Repository: Microsoft/Ironclad Branch: main Commit: 2fe4dcdc323b Files: 1364 Total size: 33.5 MB Directory structure: gitextract_3960jfld/ ├── .gitignore ├── LICENSE ├── README.md ├── SECURITY.md ├── ironclad-apps/ │ ├── .gitignore │ ├── IRONROOT.sentinel │ ├── README.md │ ├── boot/ │ │ ├── boot-cp.cmd │ │ ├── bootd.pdb │ │ └── boothosts.txt │ ├── build-tools.ps1 │ ├── def.ps1 │ ├── env.ps1 │ ├── makefile │ ├── src/ │ │ ├── Checked/ │ │ │ ├── BootLoader/ │ │ │ │ └── SingLdrPc/ │ │ │ │ ├── .gitignore │ │ │ │ ├── bl.h │ │ │ │ ├── bl.inc │ │ │ │ ├── blacpi.cpp │ │ │ │ ├── blcdrom.cpp │ │ │ │ ├── blcom.cpp │ │ │ │ ├── blentry.cpp │ │ │ │ ├── blentry16.asm │ │ │ │ ├── blfat.cpp │ │ │ │ ├── blflash.cpp │ │ │ │ ├── blkd.cpp │ │ │ │ ├── blkd1394.cpp │ │ │ │ ├── blkd1394.h │ │ │ │ ├── blkdcom.cpp │ │ │ │ ├── blmm.cpp │ │ │ │ ├── blmps.cpp │ │ │ │ ├── blpci.cpp │ │ │ │ ├── blpecoff.cpp │ │ │ │ ├── blpnp.cpp │ │ │ │ ├── blpool.cpp │ │ │ │ ├── blpxe.cpp │ │ │ │ ├── blsingularity.cpp │ │ │ │ ├── blsmap.cpp │ │ │ │ ├── blstring.cpp │ │ │ │ ├── bltrap.cpp │ │ │ │ ├── blutil.cpp │ │ │ │ ├── blvesa.cpp │ │ │ │ ├── blvideo.cpp │ │ │ │ ├── makefile │ │ │ │ ├── platform.h │ │ │ │ ├── tpm/ │ │ │ │ │ ├── aik.cpp │ │ │ │ │ └── aik.h │ │ │ │ └── x86/ │ │ │ │ ├── blcrtasm.asm │ │ │ │ ├── blidt.asm │ │ │ │ ├── blioport.asm │ │ │ │ ├── bllegacy.asm │ │ │ │ └── blutilasm.asm │ │ │ ├── Libraries/ │ │ │ │ └── DafnyCC/ │ │ │ │ ├── Base.dfy │ │ │ │ └── Seq.dfy │ │ │ └── Nucleus/ │ │ │ ├── Base/ │ │ │ │ ├── BitVectorLemmasBase.ifc.beat │ │ │ │ ├── BitVectorLemmasBase.imp.beat │ │ │ │ ├── Core.ifc.beat │ │ │ │ ├── Core.imp.beat │ │ │ │ ├── Instructions.ifc.beat │ │ │ │ ├── Instructions.imp.beat │ │ │ │ ├── IntLemmasBase.ifc.beat │ │ │ │ ├── IntLemmasBase.imp.beat │ │ │ │ ├── LogicalAddressing.ifc.beat │ │ │ │ ├── LogicalAddressing.imp.beat │ │ │ │ ├── Overflow.imp.beat │ │ │ │ ├── Partition.ifc.beat │ │ │ │ ├── Partition.imp.beat │ │ │ │ ├── Separation.ifc.beat │ │ │ │ ├── Separation.imp.beat │ │ │ │ ├── Stacks.ifc.beat │ │ │ │ ├── Stacks.imp.beat │ │ │ │ ├── Util.ifc.beat │ │ │ │ └── Util.imp.beat │ │ │ ├── Devices/ │ │ │ │ ├── BitVectorLemmasDevices.ifc.beat │ │ │ │ ├── BitVectorLemmasDevices.imp.beat │ │ │ │ ├── IntLemmasDevices.ifc.beat │ │ │ │ ├── IntLemmasDevices.imp.beat │ │ │ │ ├── IntelNIC.ifc.beat │ │ │ │ ├── IntelNIC.imp.beat │ │ │ │ ├── IoMain.ifc.beat │ │ │ │ ├── IoMain.imp.beat │ │ │ │ ├── PCI.ifc.beat │ │ │ │ └── PCI.imp.beat │ │ │ ├── GC/ │ │ │ │ ├── BitVectorLemmasGc.ifc.beat │ │ │ │ ├── BitVectorLemmasGc.imp.beat │ │ │ │ ├── IntLemmasGc.ifc.beat │ │ │ │ ├── IntLemmasGc.imp.beat │ │ │ │ ├── SimpleCollector.ifc.beat │ │ │ │ ├── SimpleCollector.imp.beat │ │ │ │ ├── SimpleCommon.ifc.beat │ │ │ │ ├── SimpleCommon.imp.beat │ │ │ │ ├── SimpleGc.ifc.beat │ │ │ │ ├── SimpleGcMemory.ifc.beat │ │ │ │ └── SimpleGcMemory.imp.beat │ │ │ └── Main/ │ │ │ ├── BitVectorLemmasMain.ifc.beat │ │ │ ├── BitVectorLemmasMain.imp.beat │ │ │ ├── Cube.ifc.beat │ │ │ ├── DafnyAssembly.ifc.beat │ │ │ ├── DafnyAssembly.imp.beat │ │ │ ├── Entry.imp.beat │ │ │ ├── IntLemmasMain.ifc.beat │ │ │ ├── IntLemmasMain.imp.beat │ │ │ ├── Main.ifc.beat │ │ │ ├── axiom.whitelist │ │ │ ├── dafny_FatNatX86_i.imp.beat │ │ │ ├── dafny_FatNatX86big_i.imp.beat │ │ │ ├── dafny_FleetNatMulLoopOpt_i.imp.beat │ │ │ ├── dafny_FleetNatMulOpt_i.imp.beat │ │ │ ├── dafny_assembly_i.imp.beat │ │ │ ├── dafny_bit_vector_lemmas_i.imp.beat │ │ │ ├── dafny_io_mem_i.imp.beat │ │ │ ├── dafny_pci_i.imp.beat │ │ │ ├── dafny_sha256opt2_i.imp.beat │ │ │ ├── dafny_sha256opt_i.imp.basm │ │ │ ├── mul_plan.txt │ │ │ ├── sha256opt2.plan │ │ │ └── sha256opt2.plan2 │ │ ├── Clients/ │ │ │ ├── Benchmark/ │ │ │ │ ├── BenchSpec.py │ │ │ │ ├── BenchmarkAnalyzer.py │ │ │ │ ├── BenchmarkDriver.py │ │ │ │ ├── BenchmarkRequestCmd/ │ │ │ │ │ ├── App.config │ │ │ │ │ ├── BenchmarkRequestCmd.csproj │ │ │ │ │ ├── GlobalSuppressions.cs │ │ │ │ │ ├── Program.cs │ │ │ │ │ └── Properties/ │ │ │ │ │ └── AssemblyInfo.cs │ │ │ │ ├── BenchmarkRequestGui/ │ │ │ │ │ ├── App.config │ │ │ │ │ ├── App.xaml │ │ │ │ │ ├── App.xaml.cs │ │ │ │ │ ├── BenchmarkRequestGui.csproj │ │ │ │ │ ├── GlobalSuppressions.cs │ │ │ │ │ ├── MainWindow.xaml │ │ │ │ │ ├── MainWindow.xaml.cs │ │ │ │ │ └── Properties/ │ │ │ │ │ ├── AssemblyInfo.cs │ │ │ │ │ ├── Resources.Designer.cs │ │ │ │ │ ├── Resources.resx │ │ │ │ │ ├── Settings.Designer.cs │ │ │ │ │ └── Settings.settings │ │ │ │ ├── Communication/ │ │ │ │ │ ├── BenchmarkList.cs │ │ │ │ │ ├── Communication.csproj │ │ │ │ │ ├── Connection.cs │ │ │ │ │ ├── GlobalSuppressions.cs │ │ │ │ │ ├── Properties/ │ │ │ │ │ │ └── AssemblyInfo.cs │ │ │ │ │ ├── Request.cs │ │ │ │ │ └── Response.cs │ │ │ │ ├── TestEcho.py │ │ │ │ └── notes │ │ │ ├── Benchmark.sln │ │ │ ├── Clients.sln │ │ │ ├── Common/ │ │ │ │ ├── Common.cs │ │ │ │ ├── Common.csproj │ │ │ │ ├── CommonParams.cs │ │ │ │ ├── GetQuote.cs │ │ │ │ ├── Profiler.cs │ │ │ │ └── Properties/ │ │ │ │ └── AssemblyInfo.cs │ │ │ ├── DiffPriv/ │ │ │ │ ├── App.config │ │ │ │ ├── DiffPriv.csproj │ │ │ │ ├── DiffPrivRequests.cs │ │ │ │ ├── DiffPrivResponses.cs │ │ │ │ ├── Parameters.cs │ │ │ │ ├── Program.cs │ │ │ │ ├── Properties/ │ │ │ │ │ └── AssemblyInfo.cs │ │ │ │ └── Rational.cs │ │ │ ├── DiffPrivSrv/ │ │ │ │ ├── App.config │ │ │ │ ├── BigRational.cs │ │ │ │ ├── DiffPrivRequest.cs │ │ │ │ ├── DiffPrivResponse.cs │ │ │ │ ├── DiffPrivSrv.csproj │ │ │ │ ├── Parameters.cs │ │ │ │ ├── Program.cs │ │ │ │ ├── Properties/ │ │ │ │ │ └── AssemblyInfo.cs │ │ │ │ └── StateMachine.cs │ │ │ ├── DotNetSHABench/ │ │ │ │ ├── App.config │ │ │ │ ├── DotNetSHABench.csproj │ │ │ │ ├── Parameters.cs │ │ │ │ ├── Program.cs │ │ │ │ └── Properties/ │ │ │ │ └── AssemblyInfo.cs │ │ │ ├── Notary/ │ │ │ │ ├── App.config │ │ │ │ ├── Notary.csproj │ │ │ │ ├── NotaryRequests.cs │ │ │ │ ├── NotaryResponses.cs │ │ │ │ ├── Parameters.cs │ │ │ │ ├── Program.cs │ │ │ │ └── Properties/ │ │ │ │ └── AssemblyInfo.cs │ │ │ ├── NotarySrv/ │ │ │ │ ├── App.config │ │ │ │ ├── NotaryRequest.cs │ │ │ │ ├── NotaryResponse.cs │ │ │ │ ├── NotarySrv.csproj │ │ │ │ ├── Parameters.cs │ │ │ │ ├── Program.cs │ │ │ │ ├── Properties/ │ │ │ │ │ └── AssemblyInfo.cs │ │ │ │ └── StateMachine.cs │ │ │ ├── PassHash/ │ │ │ │ ├── App.config │ │ │ │ ├── Parameters.cs │ │ │ │ ├── PassHash.csproj │ │ │ │ ├── PassHashRequests.cs │ │ │ │ ├── PassHashResponses.cs │ │ │ │ ├── Program.cs │ │ │ │ └── Properties/ │ │ │ │ └── AssemblyInfo.cs │ │ │ ├── PassHashSrv/ │ │ │ │ ├── App.config │ │ │ │ ├── Parameters.cs │ │ │ │ ├── PassHashRequest.cs │ │ │ │ ├── PassHashResponse.cs │ │ │ │ ├── PassHashSrv.csproj │ │ │ │ ├── Program.cs │ │ │ │ ├── Properties/ │ │ │ │ │ └── AssemblyInfo.cs │ │ │ │ └── StateMachine.cs │ │ │ ├── TrInc/ │ │ │ │ ├── App.config │ │ │ │ ├── Parameters.cs │ │ │ │ ├── Program.cs │ │ │ │ ├── Properties/ │ │ │ │ │ └── AssemblyInfo.cs │ │ │ │ ├── TrInc.csproj │ │ │ │ ├── TrIncRequests.cs │ │ │ │ └── TrIncResponses.cs │ │ │ ├── TrIncSrv/ │ │ │ │ ├── App.config │ │ │ │ ├── Parameters.cs │ │ │ │ ├── Program.cs │ │ │ │ ├── Properties/ │ │ │ │ │ └── AssemblyInfo.cs │ │ │ │ ├── StateMachine.cs │ │ │ │ ├── TrIncRequest.cs │ │ │ │ ├── TrIncResponse.cs │ │ │ │ └── TrIncSrv.csproj │ │ │ ├── UdpEchoClient/ │ │ │ │ ├── App.config │ │ │ │ ├── Program.cs │ │ │ │ ├── Properties/ │ │ │ │ │ └── AssemblyInfo.cs │ │ │ │ └── UdpEchoClient.csproj │ │ │ └── UdpEchoClient.sln │ │ ├── Dafny/ │ │ │ ├── .gitignore │ │ │ ├── Apps/ │ │ │ │ ├── .gitignore │ │ │ │ ├── AddPerf/ │ │ │ │ │ └── Main.i.dfy │ │ │ │ ├── AppLoader/ │ │ │ │ │ └── Main.i.dfy │ │ │ │ ├── BenchmarkApp/ │ │ │ │ │ └── Main.i.dfy │ │ │ │ ├── BenchmarkService/ │ │ │ │ │ ├── BenchmarkCore.i.dfy │ │ │ │ │ ├── BenchmarkList.i.dfy │ │ │ │ │ ├── Main.i.dfy │ │ │ │ │ └── Protocol.i.dfy │ │ │ │ ├── Common/ │ │ │ │ │ ├── .gitignore │ │ │ │ │ ├── CommonState.i.dfy │ │ │ │ │ └── CommonState.s.dfy │ │ │ │ ├── DafnyCCTest/ │ │ │ │ │ └── Main.i.dfy │ │ │ │ ├── DiffPriv/ │ │ │ │ │ ├── .gitignore │ │ │ │ │ ├── Database.s.dfy │ │ │ │ │ ├── DiffPriv.i.dfy │ │ │ │ │ ├── DiffPriv.s.dfy │ │ │ │ │ ├── DiffPrivPerformQuery.i.dfy │ │ │ │ │ ├── ErrorCodes.i.dfy │ │ │ │ │ ├── Main.i.dfy │ │ │ │ │ ├── Mapper.i.dfy │ │ │ │ │ ├── Mapper.s.dfy │ │ │ │ │ ├── Math.s.dfy │ │ │ │ │ ├── Noise.i.dfy │ │ │ │ │ ├── Noise.s.dfy │ │ │ │ │ ├── PacketParsing.c.dfy │ │ │ │ │ ├── PacketParsing.i.dfy │ │ │ │ │ ├── RelationalProperties.i.dfy │ │ │ │ │ ├── StateMachine.i.dfy │ │ │ │ │ ├── StateMachine.s.dfy │ │ │ │ │ ├── StateMachine2.i.dfy │ │ │ │ │ ├── SumReducer.i.dfy │ │ │ │ │ └── SumReducer.s.dfy │ │ │ │ ├── EtherTest/ │ │ │ │ │ └── EtherTest.i.dfy │ │ │ │ ├── Notary/ │ │ │ │ │ ├── .gitignore │ │ │ │ │ ├── Main.i.dfy │ │ │ │ │ ├── MainOneStep.i.dfy │ │ │ │ │ ├── Notary.i.dfy │ │ │ │ │ ├── Notary.s.dfy │ │ │ │ │ ├── PacketParsing.c.dfy │ │ │ │ │ ├── PacketParsing.i.dfy │ │ │ │ │ ├── StateMachine.i.dfy │ │ │ │ │ └── StateMachine.s.dfy │ │ │ │ ├── PassHash/ │ │ │ │ │ ├── Main.i.dfy │ │ │ │ │ ├── PacketParsing.c.dfy │ │ │ │ │ ├── PacketParsing.i.dfy │ │ │ │ │ ├── PassHash.i.dfy │ │ │ │ │ ├── PassHash.s.dfy │ │ │ │ │ └── StateMachine.s.dfy │ │ │ │ ├── TPMTest/ │ │ │ │ │ └── TPMTest.i.dfy │ │ │ │ ├── TrInc/ │ │ │ │ │ ├── .gitignore │ │ │ │ │ ├── Main.i.dfy │ │ │ │ │ ├── PacketParsing.c.dfy │ │ │ │ │ ├── PacketParsing.i.dfy │ │ │ │ │ ├── StateMachine.i.dfy │ │ │ │ │ ├── StateMachine.s.dfy │ │ │ │ │ ├── TrInc.i.dfy │ │ │ │ │ └── TrInc.s.dfy │ │ │ │ ├── UdpEchoService/ │ │ │ │ │ └── UdpEchoService.i.dfy │ │ │ │ └── apps.dfy.batch │ │ │ ├── BuildExceptions.py │ │ │ ├── Drivers/ │ │ │ │ ├── .gitignore │ │ │ │ ├── CPU/ │ │ │ │ │ ├── assembly.i.dfy │ │ │ │ │ ├── assembly.s.dfy │ │ │ │ │ └── assembly_premium.i.dfy │ │ │ │ ├── IO/ │ │ │ │ │ ├── io_mem.i.dfy │ │ │ │ │ ├── io_mem.s.dfy │ │ │ │ │ └── pci.i.dfy │ │ │ │ ├── Network/ │ │ │ │ │ ├── .gitignore │ │ │ │ │ └── Intel/ │ │ │ │ │ ├── .gitignore │ │ │ │ │ └── driver.i.dfy │ │ │ │ └── TPM/ │ │ │ │ ├── .gitignore │ │ │ │ ├── tpm-device.s.dfy │ │ │ │ ├── tpm-device.s.dfy.disabled │ │ │ │ ├── tpm-driver.i.dfy │ │ │ │ ├── tpm-wrapper-randoms.i.dfy │ │ │ │ └── tpm-wrapper.i.dfy │ │ │ └── Libraries/ │ │ │ ├── .gitignore │ │ │ ├── BigNum/ │ │ │ │ ├── .gitignore │ │ │ │ ├── BigNatAdd.i.dfy │ │ │ │ ├── BigNatBitCount.i.dfy │ │ │ │ ├── BigNatBitwise.i.dfy │ │ │ │ ├── BigNatCompare.i.dfy │ │ │ │ ├── BigNatCore.i.dfy │ │ │ │ ├── BigNatDiv.i.dfy │ │ │ │ ├── BigNatMod.i.dfy │ │ │ │ ├── BigNatMul.i.dfy │ │ │ │ ├── BigNatPartial.i.dfy │ │ │ │ ├── BigNatRandom.i.dfy │ │ │ │ ├── BigNatSub.i.dfy │ │ │ │ ├── BigNatTestLib.i.dfy │ │ │ │ ├── BigNatX86Shim.i.dfy │ │ │ │ ├── BigNum.i.dfy │ │ │ │ ├── BigNumBEAdaptor.i.dfy │ │ │ │ ├── BigRat.i.dfy │ │ │ │ └── Word32.i.dfy │ │ │ ├── Crypto/ │ │ │ │ ├── .gitignore │ │ │ │ ├── Hash/ │ │ │ │ │ ├── .gitignore │ │ │ │ │ ├── Digest.i.dfy │ │ │ │ │ ├── Digest.s.dfy │ │ │ │ │ ├── hmac_common.i.dfy │ │ │ │ │ ├── hmac_common.s.dfy │ │ │ │ │ ├── sha1.i.dfy │ │ │ │ │ ├── sha1.s.dfy │ │ │ │ │ ├── sha1_hmac.i.dfy │ │ │ │ │ ├── sha256.i.dfy │ │ │ │ │ ├── sha256.s.dfy │ │ │ │ │ ├── sha256_hmac.i.dfy │ │ │ │ │ ├── sha256common.i.dfy │ │ │ │ │ ├── sha256opt.i.dfy │ │ │ │ │ ├── sha256opt2.i.dfy │ │ │ │ │ ├── sha_common.i.dfy │ │ │ │ │ ├── sha_common.s.dfy │ │ │ │ │ ├── sha_padding.i.dfy │ │ │ │ │ └── sha_test.i.dfy │ │ │ │ ├── RSA/ │ │ │ │ │ ├── .gitignore │ │ │ │ │ ├── BlockEncoding.i.dfy │ │ │ │ │ ├── ByteSequences.i.dfy │ │ │ │ │ ├── Extended_GCD.i.dfy │ │ │ │ │ ├── KeyGen.i.dfy │ │ │ │ │ ├── KeyGen.s.dfy │ │ │ │ │ ├── KeyImpl.i.dfy │ │ │ │ │ ├── KeybitsLength.i.dfy │ │ │ │ │ ├── MillerRabin.i.dfy │ │ │ │ │ ├── MillerRabin.s.dfy │ │ │ │ │ ├── MultiplicativeInverse.i.dfy │ │ │ │ │ ├── OAEP.i.dfy │ │ │ │ │ ├── OAEP.s.dfy │ │ │ │ │ ├── PSS.s.dfy │ │ │ │ │ ├── RSA.i.dfy │ │ │ │ │ ├── RSADigestedSign.i.dfy │ │ │ │ │ ├── RSAOps.i.dfy │ │ │ │ │ ├── RSAPublicWrapper.i.dfy │ │ │ │ │ ├── RSASpec.s.dfy │ │ │ │ │ ├── RSA_Decrypt.i.dfy │ │ │ │ │ ├── division.i.dfy │ │ │ │ │ ├── rfc4251.s.dfy │ │ │ │ │ ├── rfc4251decode.i.dfy │ │ │ │ │ └── rfc4251impl.i.dfy │ │ │ │ ├── RandomNumberGen.s.dfy │ │ │ │ └── RandomTracing.s.dfy │ │ │ ├── FatNat/ │ │ │ │ ├── BigNatToFatNatAdaptor.i.dfy │ │ │ │ ├── Bitwise.i.dfy │ │ │ │ ├── CanonicalArrays.i.dfy │ │ │ │ ├── FatInt.i.dfy │ │ │ │ ├── FatNatAdd.i.dfy │ │ │ │ ├── FatNatAddLemmas.i.dfy │ │ │ │ ├── FatNatAddUnrolled.i.dfy │ │ │ │ ├── FatNatCommon.i.dfy │ │ │ │ ├── FatNatCompare.i.dfy │ │ │ │ ├── FatNatDiv.i.dfy │ │ │ │ ├── FatNatDivDefs.i.dfy │ │ │ │ ├── FatNatDivEstDiv32.i.dfy │ │ │ │ ├── FatNatDivEstTrivial.i.dfy │ │ │ │ ├── FatNatMod.i.dfy │ │ │ │ ├── FatNatModesty.i.dfy │ │ │ │ ├── FatNatMul.i.dfy │ │ │ │ ├── FatNatRandom.i.dfy │ │ │ │ ├── FatNatReciprocal.i.dfy │ │ │ │ ├── FatNatSub.i.dfy │ │ │ │ ├── FatNatX86.i.dfy │ │ │ │ ├── FatNatX86big.i.dfy │ │ │ │ ├── Transforms.i.dfy │ │ │ │ └── WordBoundHack.i.dfy │ │ │ ├── FleetNat/ │ │ │ │ ├── Bizarre.dfy │ │ │ │ ├── FleetNatAdd.i.dfy │ │ │ │ ├── FleetNatCommon.i.dfy │ │ │ │ ├── FleetNatMul.i.dfy │ │ │ │ ├── FleetNatMulLemmas.i.dfy │ │ │ │ ├── FleetNatMulLoopOpt.i.dfy │ │ │ │ ├── FleetNatMulLoopOptLemmas.i.dfy │ │ │ │ ├── FleetNatMulOpt.i.dfy │ │ │ │ ├── FleetNatSub.i.dfy │ │ │ │ └── FleetNatSubOpt.i.dfy │ │ │ ├── Math/ │ │ │ │ ├── .gitignore │ │ │ │ ├── BitwiseOperations.i.dfy │ │ │ │ ├── GCD.s.dfy │ │ │ │ ├── bit_vector_lemmas.i.dfy │ │ │ │ ├── bit_vector_lemmas_premium.i.dfy │ │ │ │ ├── div.i.dfy │ │ │ │ ├── div_boogie.i.dfy │ │ │ │ ├── div_def.i.dfy │ │ │ │ ├── div_nonlinear.i.dfy │ │ │ │ ├── evenodd.i.dfy │ │ │ │ ├── mul.i.dfy │ │ │ │ ├── mul_nonlinear.i.dfy │ │ │ │ ├── power.i.dfy │ │ │ │ ├── power.s.dfy │ │ │ │ ├── power2.i.dfy │ │ │ │ ├── power2.s.dfy │ │ │ │ ├── power2methods.i.dfy │ │ │ │ ├── round.i.dfy │ │ │ │ └── round.s.dfy │ │ │ ├── Net/ │ │ │ │ ├── .gitignore │ │ │ │ ├── IPv4.i.dfy │ │ │ │ ├── InternetChecksum.i.dfy │ │ │ │ ├── Udp.i.dfy │ │ │ │ └── ethernet.i.dfy │ │ │ ├── Util/ │ │ │ │ ├── .gitignore │ │ │ │ ├── DebugPrint.i.dfy │ │ │ │ ├── Halter.i.dfy │ │ │ │ ├── ProfileIfc.i.dfy │ │ │ │ ├── arrays.i.dfy │ │ │ │ ├── arrays_2.i.dfy │ │ │ │ ├── arrays_and_seqs.i.dfy │ │ │ │ ├── be_sequences.s.dfy │ │ │ │ ├── beseqs_simple.i.dfy │ │ │ │ ├── bytes_and_words.s.dfy │ │ │ │ ├── insecure_prng.i.dfy │ │ │ │ ├── integer_sequences.i.dfy │ │ │ │ ├── integer_sequences.s.dfy │ │ │ │ ├── integer_sequences_premium.i.dfy │ │ │ │ ├── relational.i.dfy │ │ │ │ ├── relational.s.dfy │ │ │ │ ├── repeat_digit.i.dfy │ │ │ │ ├── seq_blocking.i.dfy │ │ │ │ ├── seq_blocking.s.dfy │ │ │ │ ├── seqs_and_ints.i.dfy │ │ │ │ ├── seqs_canonical.i.dfy │ │ │ │ ├── seqs_common.i.dfy │ │ │ │ ├── seqs_reverse.i.dfy │ │ │ │ ├── seqs_simple.i.dfy │ │ │ │ ├── seqs_transforms.i.dfy │ │ │ │ └── word_bits.i.dfy │ │ │ └── base.s.dfy │ │ ├── DafnyTestDriver/ │ │ │ ├── DafnyTestDriver/ │ │ │ │ ├── App.config │ │ │ │ ├── DafnyTestDriver.csproj │ │ │ │ ├── Program.cs │ │ │ │ ├── Properties/ │ │ │ │ │ └── AssemblyInfo.cs │ │ │ │ ├── assembly.cs │ │ │ │ ├── debug.cs │ │ │ │ └── profile.cs │ │ │ └── DafnyTestDriver.sln │ │ └── Trusted/ │ │ ├── DafnySpec/ │ │ │ └── Seq.s.dfy │ │ └── Spec/ │ │ ├── AddPerf/ │ │ │ └── AppRequirements.ifc.stitch │ │ ├── AppLoader/ │ │ │ └── AppRequirements.ifc.stitch │ │ ├── AppLoaderContract.ifc.basm │ │ ├── AppLoaderContract.imp.basm │ │ ├── AssemblySpec.ifc.basm │ │ ├── AssemblySpec.imp.basm │ │ ├── Assembly_axioms.bpl │ │ ├── BaseSpec.ifc.basm │ │ ├── BaseSpec.imp.basm │ │ ├── Base_axioms.bpl │ │ ├── BenchmarkApp/ │ │ │ └── AppRequirements.ifc.stitch │ │ ├── BenchmarkService/ │ │ │ └── AppRequirements.ifc.stitch │ │ ├── BitVector_axioms.bpl │ │ ├── DafnyCCTest/ │ │ │ └── AppRequirements.ifc.stitch │ │ ├── DiffPriv/ │ │ │ └── AppRequirements.ifc.stitch │ │ ├── Entry.ifc.basm.stitch │ │ ├── ExtendedAssembly.ifc.basm │ │ ├── ExtendedAssembly.imp.basm │ │ ├── IntSpec.ifc.basm │ │ ├── IntSpec.imp.basm │ │ ├── IntSpec_axioms.bpl │ │ ├── InterruptsSpec.ifc.basm │ │ ├── InterruptsSpec.imp.basm │ │ ├── IoSpec.ifc.basm │ │ ├── IoSpec.imp.basm │ │ ├── IoTypesSpec.ifc.basm │ │ ├── IoTypesSpec.imp.basm │ │ ├── Io_axioms.bpl │ │ ├── MachineStateSpec.ifc.basm │ │ ├── MachineStateSpec.imp.basm │ │ ├── MemorySpec.ifc.basm │ │ ├── MemorySpec.imp.basm │ │ ├── Memory_axioms.bpl │ │ ├── Notary/ │ │ │ └── AppRequirements.ifc.stitch │ │ ├── NucleusInvCopying.bpl │ │ ├── Overflow.ifc.basm │ │ ├── PassHash/ │ │ │ └── AppRequirements.ifc.stitch │ │ ├── TPMTest/ │ │ │ └── AppRequirements.ifc.stitch │ │ ├── TrInc/ │ │ │ └── AppRequirements.ifc.stitch │ │ └── Word_axioms.bpl │ └── tools/ │ ├── Beat/ │ │ ├── ast.fs │ │ ├── beat.vim │ │ ├── lex.fsl │ │ ├── main.fs │ │ ├── makefile │ │ ├── makefile.fs │ │ ├── nubuild-manifest.txt │ │ ├── parse.fsy │ │ └── parse_util.fs │ ├── BoogieAsm/ │ │ ├── SymdiffMerge.cs │ │ ├── ast.fs │ │ ├── emit_bpl.fs │ │ ├── lex.fsl │ │ ├── main.fs │ │ ├── makefile │ │ ├── makefile.fs │ │ ├── nubuild-manifest.txt │ │ ├── parse.fsy │ │ └── parse_util.fs │ ├── Dafny/ │ │ ├── AbsInt.pdb │ │ ├── BVD.exe.config │ │ ├── BVD.pdb │ │ ├── Basetypes.pdb │ │ ├── Boogie.pdb │ │ ├── Boogie.suo │ │ ├── Boogie.vshost.exe.manifest │ │ ├── CodeContracts/ │ │ │ └── Dafny.Contracts.pdb │ │ ├── CodeContractsExtender.pdb │ │ ├── Concurrency.pdb │ │ ├── Core.pdb │ │ ├── Dafny.exe.config │ │ ├── Dafny.pdb │ │ ├── Dafny.vshost.exe.config │ │ ├── Dafny.vshost.exe.manifest │ │ ├── DafnyLanguageService.pdb │ │ ├── DafnyLanguageService.vsix │ │ ├── DafnyMenu.pdb │ │ ├── DafnyMenu.pkgdef │ │ ├── DafnyMenu.vsix │ │ ├── DafnyPipeline.pdb │ │ ├── DafnyPrelude.bpl │ │ ├── DafnyRuntime.cs │ │ ├── Doomed.pdb │ │ ├── ExecutionEngine.pdb │ │ ├── Graph.pdb │ │ ├── Houdini.pdb │ │ ├── Microsoft.Z3.xml │ │ ├── Model.pdb │ │ ├── ModelViewer.pdb │ │ ├── ParserHelper.pdb │ │ ├── Predication.pdb │ │ ├── PrepareBoogieZip.bat │ │ ├── PrepareDafnyZip.bat │ │ ├── Provers.SMTLib.pdb │ │ ├── README │ │ ├── VCExpr.pdb │ │ ├── VCGeneration.pdb │ │ ├── extension.vsixmanifest │ │ ├── libiz3.lib │ │ ├── z3.lib │ │ └── z3_dbg.lib │ ├── DafnyCC/ │ │ ├── .gitignore │ │ ├── Analyze.cs │ │ ├── CompileMethod.cs │ │ ├── DafnyCC.cs │ │ ├── DafnyCC.csproj │ │ ├── DafnyCC.sln │ │ ├── Makefile │ │ ├── RegAlloc.cs │ │ ├── Rtl.cs │ │ ├── blueprints/ │ │ │ ├── Analyze.bpl │ │ │ └── RegAlloc.bpl │ │ └── nubuild-manifest.txt │ ├── DafnySpec/ │ │ ├── .gitignore │ │ ├── Compile.cs │ │ ├── CompileField.cs │ │ ├── CompileFunction.cs │ │ ├── CompileMethodGhost.cs │ │ ├── DafnyPrelude.dfy │ │ ├── DafnySpec.cs │ │ ├── DafnySpec.csproj │ │ ├── DafnySpec.sln │ │ ├── DafnySpecAst/ │ │ │ ├── DafnySpecAst.cs │ │ │ ├── DafnySpecAst.csproj │ │ │ └── nubuild-manifest.txt │ │ ├── Makefile │ │ ├── ParseMain.cs │ │ ├── Parser/ │ │ │ ├── Parser.csproj │ │ │ ├── ReadMe.txt │ │ │ ├── lex.fsl │ │ │ ├── nubuild-manifest.txt │ │ │ ├── parse.fsy │ │ │ ├── parse_util.fs │ │ │ └── parser.fs │ │ ├── RtlGhost.cs │ │ ├── Util.cs │ │ └── nubuild-manifest.txt │ ├── LineCount/ │ │ ├── lex.fsl │ │ ├── main.fs │ │ ├── makefile │ │ └── parse_util.fs │ ├── NuBuild/ │ │ ├── .gitignore │ │ ├── AzureManager/ │ │ │ ├── App.config │ │ │ ├── AzureAccount.cs │ │ │ ├── AzureManager.csproj │ │ │ ├── Program.cs │ │ │ ├── Properties/ │ │ │ │ └── AssemblyInfo.cs │ │ │ └── ServiceConfiguration.cs │ │ ├── CloudExecutionEngine/ │ │ │ ├── App.config │ │ │ ├── CloudExecutionEngine.csproj │ │ │ ├── Program.cs │ │ │ └── Properties/ │ │ │ └── AssemblyInfo.cs │ │ ├── CloudExecutionWorker/ │ │ │ ├── CloudExecutionEngine.cs │ │ │ ├── CloudExecutionWorker.csproj │ │ │ ├── Properties/ │ │ │ │ └── AssemblyInfo.cs │ │ │ ├── WorkerRole.cs │ │ │ └── app.config │ │ ├── CloudQueueTool/ │ │ │ ├── App.config │ │ │ ├── CloudQueueTool.csproj │ │ │ ├── Program.cs │ │ │ └── Properties/ │ │ │ └── AssemblyInfo.cs │ │ ├── CustomDictionary.xml │ │ ├── ItemCacheTool/ │ │ │ ├── App.config │ │ │ ├── CacheState.cs │ │ │ ├── ItemCacheTool.csproj │ │ │ ├── Program.cs │ │ │ └── Properties/ │ │ │ └── AssemblyInfo.cs │ │ ├── NuBuild/ │ │ │ ├── .gitignore │ │ │ ├── AbstractId.cs │ │ │ ├── AnnotationScanner.cs │ │ │ ├── App.config │ │ │ ├── AsmRewriterVerb.cs │ │ │ ├── BackgroundWorker.cs │ │ │ ├── BasmObligationIncludes.cs │ │ │ ├── BasmTransitiveDepsVerb.cs │ │ │ ├── BatchVerifyVerb.cs │ │ │ ├── BeatExtensions.cs │ │ │ ├── BeatIncludes.cs │ │ │ ├── BeatVerb.cs │ │ │ ├── BoogieAsmDepBase.cs │ │ │ ├── BoogieAsmLinkVerb.cs │ │ │ ├── BoogieAsmVerificationObligationListVerb.cs │ │ │ ├── BoogieAsmVerifyVerb.cs │ │ │ ├── BoogieAsmWorkerBase.cs │ │ │ ├── BoogieVerb.cs │ │ │ ├── BootableAppVerb.cs │ │ │ ├── BuildEngine.cs │ │ │ ├── BuildObject.cs │ │ │ ├── BuildObjectValuePointer.cs │ │ │ ├── CachedHash.cs │ │ │ ├── CloudExecutionQueue.cs │ │ │ ├── CloudExecutionReport.cs │ │ │ ├── CloudExecutionRequest.cs │ │ │ ├── CloudExecutionWaiter.cs │ │ │ ├── CloudSubmitter.cs │ │ │ ├── ConcatContext.cs │ │ │ ├── ConcatContextVerb.cs │ │ │ ├── ContextContents.cs │ │ │ ├── ContextGeneratingVerb.cs │ │ │ ├── CustomManifestParser.cs │ │ │ ├── DafnyCCVerb.cs │ │ │ ├── DafnyCompileOneVerb.cs │ │ │ ├── DafnyExecutableDependencies.cs │ │ │ ├── DafnyExtensions.cs │ │ │ ├── DafnyIncludes.cs │ │ │ ├── DafnySpecVerb.cs │ │ │ ├── DafnyTransformBaseVerb.cs │ │ │ ├── DafnyTransitiveDepsVerb.cs │ │ │ ├── DafnyVerifyOneVerb.cs │ │ │ ├── DafnyVerifyTreeVerb.cs │ │ │ ├── DbgFileCopySpeedTest.cs │ │ │ ├── DbgHashSpeedTest.cs │ │ │ ├── DbgVerbCounter.cs │ │ │ ├── DependencyCache.cs │ │ │ ├── DependencyDisposition.cs │ │ │ ├── Disposition.cs │ │ │ ├── EntryStitcherVerb.cs │ │ │ ├── Hasher.cs │ │ │ ├── IAsmProducer.cs │ │ │ ├── IContextGeneratingVerb.cs │ │ │ ├── IHasher.cs │ │ │ ├── IIncludeFactory.cs │ │ │ ├── IIncludePathContext.cs │ │ │ ├── IItemCache.cs │ │ │ ├── IObligationsProducer.cs │ │ │ ├── IProcessInvokeAsyncVerb.cs │ │ │ ├── IProcessInvoker.cs │ │ │ ├── IRejectable.cs │ │ │ ├── IVerb.cs │ │ │ ├── IVerbWorker.cs │ │ │ ├── IVerificationResultParser.cs │ │ │ ├── IncludePathContext.cs │ │ │ ├── IronRootDirectory.cs │ │ │ ├── IroncladAppVerb.cs │ │ │ ├── IronfleetAppVerb.cs │ │ │ ├── ItemCacheCloud.cs │ │ │ ├── ItemCacheLocal.cs │ │ │ ├── ItemCacheMultiplexer.cs │ │ │ ├── Job.cs │ │ │ ├── LinkerVerb.cs │ │ │ ├── Logger.cs │ │ │ ├── MasmVerb.cs │ │ │ ├── NMakeVerb.cs │ │ │ ├── NuBuild.csproj │ │ │ ├── ObjectFailedException.cs │ │ │ ├── ObjectMissingFromCacheException.cs │ │ │ ├── ObjectNotReadyException.cs │ │ │ ├── OrderPreservingSet.cs │ │ │ ├── PathNormalizer.cs │ │ │ ├── PoundDefines.cs │ │ │ ├── Presentater.cs │ │ │ ├── Presentation.cs │ │ │ ├── PresentationBuilder.cs │ │ │ ├── ProcessInvokeAsyncWorker.cs │ │ │ ├── ProcessInvoker.cs │ │ │ ├── Program.cs │ │ │ ├── Properties/ │ │ │ │ └── AssemblyInfo.cs │ │ │ ├── Repository.cs │ │ │ ├── ResultSummaryRecord.cs │ │ │ ├── Scheduler.cs │ │ │ ├── SourceConfigurationError.cs │ │ │ ├── SourcePath.cs │ │ │ ├── SourcePathIncludeContext.cs │ │ │ ├── StaticContextVerb.cs │ │ │ ├── SymDiffBaseVerb.cs │ │ │ ├── SymDiffCombineVerb.cs │ │ │ ├── SymDiffEngine.cs │ │ │ ├── SymDiffExtractVerb.cs │ │ │ ├── SymDiffInferVerb.cs │ │ │ ├── SymDiffMergeBaseVerb.cs │ │ │ ├── SymDiffMergeConfigVerb.cs │ │ │ ├── SymDiffMergeVerb.cs │ │ │ ├── TransitiveDepsContents.cs │ │ │ ├── TransitiveDepsVerb.cs │ │ │ ├── UnverifiedSentinelVirtualContents.cs │ │ │ ├── UserError.cs │ │ │ ├── Util.cs │ │ │ ├── VSProjectParser.cs │ │ │ ├── VSSolutionParser.cs │ │ │ ├── VSSolutionVerb.cs │ │ │ ├── Verb.cs │ │ │ ├── VerbOutputsContext.cs │ │ │ ├── VerbOutputsContextVerb.cs │ │ │ ├── VerbRunner.cs │ │ │ ├── VerbSyncWorker.cs │ │ │ ├── VerbToposorter.cs │ │ │ ├── VerificationMessage.cs │ │ │ ├── VerificationObligationList.cs │ │ │ ├── VerificationRequest.cs │ │ │ ├── VerificationResult.cs │ │ │ ├── VerificationResultBoogieParser.cs │ │ │ ├── VerificationResultDafnyParser.cs │ │ │ ├── VerificationResultSummaryVerb.cs │ │ │ ├── VerificationResultVerb.cs │ │ │ ├── VirtualBuildObject.cs │ │ │ ├── VirtualContents.cs │ │ │ ├── WaitIndex.cs │ │ │ ├── WinLinkerVerb.cs │ │ │ ├── WorkingDirectory.cs │ │ │ └── XmlFiller.cs │ │ ├── NuBuild.sln │ │ ├── NuBuildExecutionService/ │ │ │ ├── .gitignore │ │ │ ├── CloudExecutionWorkerContent/ │ │ │ │ └── diagnostics.wadcfg │ │ │ ├── NuBuildExecutionService.ccproj │ │ │ ├── ServiceConfiguration.Cloud.cscfg │ │ │ ├── ServiceConfiguration.Local.cscfg │ │ │ └── ServiceDefinition.csdef │ │ ├── References/ │ │ │ ├── Microsoft.Threading.Tasks.xml │ │ │ ├── Microsoft.WindowsAzure.Common.NetFramework.xml │ │ │ ├── Microsoft.WindowsAzure.Common.xml │ │ │ ├── Microsoft.WindowsAzure.Management.Compute.xml │ │ │ ├── Microsoft.WindowsAzure.Management.Storage.xml │ │ │ └── Microsoft.WindowsAzure.Storage.xml │ │ ├── Settings.StyleCop │ │ └── makefile │ ├── NuBuild2/ │ │ ├── .gitignore │ │ ├── AzureManager/ │ │ │ ├── App.config │ │ │ ├── AzureAccount.cs │ │ │ ├── AzureManager.csproj │ │ │ ├── Program.cs │ │ │ ├── Properties/ │ │ │ │ └── AssemblyInfo.cs │ │ │ └── ServiceConfiguration.cs │ │ ├── CloudExecutionEngine/ │ │ │ ├── App.config │ │ │ ├── CloudExecutionEngine.csproj │ │ │ ├── Program.cs │ │ │ └── Properties/ │ │ │ └── AssemblyInfo.cs │ │ ├── CloudExecutionWorker/ │ │ │ ├── CloudExecutionEngine.cs │ │ │ ├── CloudExecutionWorker.csproj │ │ │ ├── Properties/ │ │ │ │ └── AssemblyInfo.cs │ │ │ ├── WorkerRole.cs │ │ │ └── app.config │ │ ├── CloudQueueTool/ │ │ │ ├── App.config │ │ │ ├── CloudQueueTool.csproj │ │ │ ├── Program.cs │ │ │ └── Properties/ │ │ │ └── AssemblyInfo.cs │ │ ├── CustomDictionary.xml │ │ ├── ItemCacheTool/ │ │ │ ├── App.config │ │ │ ├── CacheState.cs │ │ │ ├── ItemCacheTool.csproj │ │ │ ├── Program.cs │ │ │ └── Properties/ │ │ │ └── AssemblyInfo.cs │ │ ├── NuBuild/ │ │ │ ├── .gitignore │ │ │ ├── AbstractId.cs │ │ │ ├── AnnotationScanner.cs │ │ │ ├── App.config │ │ │ ├── AsmRewriterVerb.cs │ │ │ ├── BackgroundWorker.cs │ │ │ ├── BasmObligationIncludes.cs │ │ │ ├── BasmTransitiveDepsVerb.cs │ │ │ ├── BatchVerifyVerb.cs │ │ │ ├── BeatExtensions.cs │ │ │ ├── BeatIncludes.cs │ │ │ ├── BeatVerb.cs │ │ │ ├── BoogieAsmDepBase.cs │ │ │ ├── BoogieAsmLinkVerb.cs │ │ │ ├── BoogieAsmVerificationObligationListVerb.cs │ │ │ ├── BoogieAsmVerifyVerb.cs │ │ │ ├── BoogieAsmWorkerBase.cs │ │ │ ├── BoogieVerb.cs │ │ │ ├── BootableAppVerb.cs │ │ │ ├── BuildEngine.cs │ │ │ ├── BuildObject.cs │ │ │ ├── BuildObjectValuePointer.cs │ │ │ ├── CachedHash.cs │ │ │ ├── CloudExecutionQueue.cs │ │ │ ├── CloudExecutionReport.cs │ │ │ ├── CloudExecutionRequest.cs │ │ │ ├── CloudExecutionWaiter.cs │ │ │ ├── CloudSubmitter.cs │ │ │ ├── ConcatContext.cs │ │ │ ├── ConcatContextVerb.cs │ │ │ ├── ContextContents.cs │ │ │ ├── ContextGeneratingVerb.cs │ │ │ ├── CustomManifestParser.cs │ │ │ ├── DafnyCCVerb.cs │ │ │ ├── DafnyCompileOneVerb.cs │ │ │ ├── DafnyExecutableDependencies.cs │ │ │ ├── DafnyExtensions.cs │ │ │ ├── DafnyIncludes.cs │ │ │ ├── DafnySpecVerb.cs │ │ │ ├── DafnyTransformBaseVerb.cs │ │ │ ├── DafnyTransitiveDepsVerb.cs │ │ │ ├── DafnyVerifyOneVerb.cs │ │ │ ├── DafnyVerifyTreeVerb.cs │ │ │ ├── DbgFileCopySpeedTest.cs │ │ │ ├── DbgHashSpeedTest.cs │ │ │ ├── DbgVerbCounter.cs │ │ │ ├── DependencyCache.cs │ │ │ ├── DependencyDisposition.cs │ │ │ ├── Disposition.cs │ │ │ ├── EntryStitcherVerb.cs │ │ │ ├── Hasher.cs │ │ │ ├── IAsmProducer.cs │ │ │ ├── IContextGeneratingVerb.cs │ │ │ ├── IHasher.cs │ │ │ ├── IIncludeFactory.cs │ │ │ ├── IIncludePathContext.cs │ │ │ ├── IItemCache.cs │ │ │ ├── IObligationsProducer.cs │ │ │ ├── IProcessInvokeAsyncVerb.cs │ │ │ ├── IProcessInvoker.cs │ │ │ ├── IRejectable.cs │ │ │ ├── IVerb.cs │ │ │ ├── IVerbWorker.cs │ │ │ ├── IVerificationResultParser.cs │ │ │ ├── IncludePathContext.cs │ │ │ ├── IronRootDirectory.cs │ │ │ ├── IroncladAppVerb.cs │ │ │ ├── IronfleetAppVerb.cs │ │ │ ├── ItemCacheCloud.cs │ │ │ ├── ItemCacheLocal.cs │ │ │ ├── ItemCacheMultiplexer.cs │ │ │ ├── Job.cs │ │ │ ├── LinkerVerb.cs │ │ │ ├── Logger.cs │ │ │ ├── MasmVerb.cs │ │ │ ├── NMakeVerb.cs │ │ │ ├── NuBuild.csproj │ │ │ ├── ObjectFailedException.cs │ │ │ ├── ObjectMissingFromCacheException.cs │ │ │ ├── ObjectNotReadyException.cs │ │ │ ├── OrderPreservingSet.cs │ │ │ ├── PathNormalizer.cs │ │ │ ├── PoundDefines.cs │ │ │ ├── Presentater.cs │ │ │ ├── Presentation.cs │ │ │ ├── PresentationBuilder.cs │ │ │ ├── ProcessInvokeAsyncWorker.cs │ │ │ ├── ProcessInvoker.cs │ │ │ ├── Program.cs │ │ │ ├── Properties/ │ │ │ │ └── AssemblyInfo.cs │ │ │ ├── Repository.cs │ │ │ ├── ResultSummaryRecord.cs │ │ │ ├── Scheduler.cs │ │ │ ├── SourceConfigurationError.cs │ │ │ ├── SourcePath.cs │ │ │ ├── SourcePathIncludeContext.cs │ │ │ ├── StaticContextVerb.cs │ │ │ ├── SymDiffBaseVerb.cs │ │ │ ├── SymDiffCombineVerb.cs │ │ │ ├── SymDiffEngine.cs │ │ │ ├── SymDiffExtractVerb.cs │ │ │ ├── SymDiffInferVerb.cs │ │ │ ├── SymDiffMergeBaseVerb.cs │ │ │ ├── SymDiffMergeConfigVerb.cs │ │ │ ├── SymDiffMergeVerb.cs │ │ │ ├── ToDo.txt │ │ │ ├── TransitiveDepsContents.cs │ │ │ ├── TransitiveDepsVerb.cs │ │ │ ├── UnverifiedSentinelVirtualContents.cs │ │ │ ├── UserError.cs │ │ │ ├── Util.cs │ │ │ ├── VSProjectParser.cs │ │ │ ├── VSSolutionParser.cs │ │ │ ├── VSSolutionVerb.cs │ │ │ ├── Verb.cs │ │ │ ├── VerbOutputsContext.cs │ │ │ ├── VerbOutputsContextVerb.cs │ │ │ ├── VerbRunner.cs │ │ │ ├── VerbSyncWorker.cs │ │ │ ├── VerbToposorter.cs │ │ │ ├── VerificationMessage.cs │ │ │ ├── VerificationObligationList.cs │ │ │ ├── VerificationRequest.cs │ │ │ ├── VerificationResult.cs │ │ │ ├── VerificationResultBoogieParser.cs │ │ │ ├── VerificationResultDafnyParser.cs │ │ │ ├── VerificationResultSummaryVerb.cs │ │ │ ├── VerificationResultVerb.cs │ │ │ ├── VirtualBuildObject.cs │ │ │ ├── VirtualContents.cs │ │ │ ├── WaitIndex.cs │ │ │ ├── WinLinkerVerb.cs │ │ │ ├── WorkingDirectory.cs │ │ │ └── XmlFiller.cs │ │ ├── NuBuild.sln │ │ ├── NuBuildExecutionService/ │ │ │ ├── .gitignore │ │ │ ├── CloudExecutionWorkerContent/ │ │ │ │ └── diagnostics.wadcfg │ │ │ ├── NuBuildExecutionService.ccproj │ │ │ ├── ServiceConfiguration.Cloud.cscfg │ │ │ ├── ServiceConfiguration.Local.cscfg │ │ │ ├── ServiceDefinition.csdef │ │ │ └── csx/ │ │ │ └── Release/ │ │ │ └── roles/ │ │ │ └── CloudExecutionWorker/ │ │ │ └── base/ │ │ │ └── x64/ │ │ │ └── WaHostBootstrapper.exe.config │ │ ├── References/ │ │ │ ├── Microsoft.Threading.Tasks.xml │ │ │ ├── Microsoft.WindowsAzure.Common.NetFramework.xml │ │ │ ├── Microsoft.WindowsAzure.Common.xml │ │ │ ├── Microsoft.WindowsAzure.Management.Compute.xml │ │ │ ├── Microsoft.WindowsAzure.Management.Storage.xml │ │ │ └── Microsoft.WindowsAzure.Storage.xml │ │ ├── Settings.StyleCop │ │ ├── makefile │ │ ├── modules.log │ │ └── modules.result │ ├── SymDiff/ │ │ ├── AIFramework.pdb │ │ ├── AbsInt.pdb │ │ ├── Basetypes.pdb │ │ ├── CodeContractsExtender.pdb │ │ ├── Core.pdb │ │ ├── Graph.pdb │ │ ├── Model.pdb │ │ ├── ParserHelper.pdb │ │ ├── Provers.SMTLib.pdb │ │ ├── SymDiff.exe.config │ │ ├── SymDiff.pdb │ │ ├── SymDiff.vshost.exe.config │ │ ├── SymDiff.vshost.exe.manifest │ │ ├── TypedUnivBackPred2.sx │ │ ├── UnivBackPred2.smt │ │ ├── UnivBackPred2.smt2 │ │ ├── UnivBackPred2.sx │ │ ├── VCExpr.pdb │ │ └── VCGeneration.pdb │ ├── build/ │ │ └── x86_x86/ │ │ ├── cl.exe.config │ │ └── link.exe.config │ ├── fsharp/ │ │ ├── FSharp.Compiler.CodeDom.xml │ │ ├── FSharp.Core.pdb │ │ ├── FSharp.Core.xml │ │ ├── FSharp.PowerPack.Build.Tasks.pdb │ │ ├── FSharp.PowerPack.Build.Tasks.xml │ │ ├── FSharp.PowerPack.Linq.pdb │ │ ├── FSharp.PowerPack.Linq.xml │ │ ├── FSharp.PowerPack.Metadata.pdb │ │ ├── FSharp.PowerPack.Metadata.xml │ │ ├── FSharp.PowerPack.pdb │ │ └── FSharp.PowerPack.xml │ ├── scripts/ │ │ ├── .gitignore │ │ ├── binary_to_c_symbols.py │ │ ├── build-standalone-asm.py │ │ ├── build-standalone-init.sh │ │ ├── zero-obj.bz2 │ │ └── zero.asm │ └── standalone/ │ ├── .gitignore │ ├── StandAloneSupport.sln │ ├── StandAloneSupport.vcxproj │ ├── StandAloneSupport.vcxproj.filters │ └── support.cpp └── ironfleet/ ├── .gitignore ├── CODE.md ├── CONTRIBUTING.md ├── IRONROOT.sentinel ├── LICENSE ├── README.md ├── SConstruct ├── STYLE.md ├── src/ │ ├── CreateIronServiceCerts/ │ │ ├── .gitignore │ │ ├── CreateIronServiceCerts.csproj │ │ ├── CreateIronServiceCerts.sln │ │ ├── Params.cs │ │ └── Program.cs │ ├── Dafny/ │ │ ├── .gitignore │ │ ├── Distributed/ │ │ │ ├── Common/ │ │ │ │ ├── .gitignore │ │ │ │ ├── Collections/ │ │ │ │ │ ├── CountMatches.i.dfy │ │ │ │ │ ├── Maps.i.dfy │ │ │ │ │ ├── Maps2.i.dfy │ │ │ │ │ ├── Maps2.s.dfy │ │ │ │ │ ├── Multisets.s.dfy │ │ │ │ │ ├── Seqs.i.dfy │ │ │ │ │ ├── Seqs.s.dfy │ │ │ │ │ └── Sets.i.dfy │ │ │ │ ├── Framework/ │ │ │ │ │ ├── AbstractService.s.dfy │ │ │ │ │ ├── DistributedSystem.s.dfy │ │ │ │ │ ├── Environment.s.dfy │ │ │ │ │ ├── EnvironmentSynchrony.s.dfy │ │ │ │ │ ├── EnvironmentSynchronyLemmas.i.dfy │ │ │ │ │ ├── Host.s.dfy │ │ │ │ │ ├── HostQueueLemmas.i.dfy │ │ │ │ │ └── Main.s.dfy │ │ │ │ ├── Logic/ │ │ │ │ │ ├── Option.i.dfy │ │ │ │ │ └── Temporal/ │ │ │ │ │ ├── Heuristics.i.dfy │ │ │ │ │ ├── Induction.i.dfy │ │ │ │ │ ├── LeadsTo.i.dfy │ │ │ │ │ ├── Monotonicity.i.dfy │ │ │ │ │ ├── Rules.i.dfy │ │ │ │ │ ├── Sets.i.dfy │ │ │ │ │ ├── Temporal.s.dfy │ │ │ │ │ ├── Time.i.dfy │ │ │ │ │ ├── Time.s.dfy │ │ │ │ │ └── WF1.i.dfy │ │ │ │ └── Native/ │ │ │ │ ├── Io.s.dfy │ │ │ │ ├── IoFramework.cs │ │ │ │ ├── IoLemmas.i.dfy │ │ │ │ ├── IoNative.cs │ │ │ │ ├── NativeTypes.i.dfy │ │ │ │ └── NativeTypes.s.dfy │ │ │ ├── Impl/ │ │ │ │ ├── Common/ │ │ │ │ │ ├── CmdLineParser.i.dfy │ │ │ │ │ ├── GenericMarshalling.i.dfy │ │ │ │ │ ├── GenericRefinement.i.dfy │ │ │ │ │ ├── MarshallInt.i.dfy │ │ │ │ │ ├── NetClient.i.dfy │ │ │ │ │ ├── NodeIdentity.i.dfy │ │ │ │ │ ├── SeqIsUnique.i.dfy │ │ │ │ │ ├── SeqIsUniqueDef.i.dfy │ │ │ │ │ ├── UpperBound.i.dfy │ │ │ │ │ └── Util.i.dfy │ │ │ │ ├── LiveSHT/ │ │ │ │ │ ├── CmdLineParser.i.dfy │ │ │ │ │ ├── Host.i.dfy │ │ │ │ │ ├── NetSHT.i.dfy │ │ │ │ │ ├── SchedulerImpl.i.dfy │ │ │ │ │ ├── SchedulerModel.i.dfy │ │ │ │ │ └── Unsendable.i.dfy │ │ │ │ ├── Lock/ │ │ │ │ │ ├── CmdLineParser.i.dfy │ │ │ │ │ ├── Host.i.dfy │ │ │ │ │ ├── Message.i.dfy │ │ │ │ │ ├── NetLock.i.dfy │ │ │ │ │ ├── Node.i.dfy │ │ │ │ │ ├── NodeImpl.i.dfy │ │ │ │ │ └── PacketParsing.i.dfy │ │ │ │ ├── RSL/ │ │ │ │ │ ├── AcceptorModel.i.dfy │ │ │ │ │ ├── AcceptorState.i.dfy │ │ │ │ │ ├── AppInterface.i.dfy │ │ │ │ │ ├── Broadcast.i.dfy │ │ │ │ │ ├── CClockReading.i.dfy │ │ │ │ │ ├── CLastCheckpointedMap.i.dfy │ │ │ │ │ ├── CMessage.i.dfy │ │ │ │ │ ├── CMessageRefinements.i.dfy │ │ │ │ │ ├── COperationNumberSort.i.dfy │ │ │ │ │ ├── CPaxosConfiguration.i.dfy │ │ │ │ │ ├── CTypes.i.dfy │ │ │ │ │ ├── CmdLineParser.i.dfy │ │ │ │ │ ├── ConstantsState.i.dfy │ │ │ │ │ ├── ElectionModel.i.dfy │ │ │ │ │ ├── ElectionState.i.dfy │ │ │ │ │ ├── ExecutorModel.i.dfy │ │ │ │ │ ├── ExecutorState.i.dfy │ │ │ │ │ ├── Host.i.dfy │ │ │ │ │ ├── LearnerModel.i.dfy │ │ │ │ │ ├── LearnerState.i.dfy │ │ │ │ │ ├── MinCQuorumSize.i.dfy │ │ │ │ │ ├── NetRSL.i.dfy │ │ │ │ │ ├── PacketParsing.i.dfy │ │ │ │ │ ├── ParametersState.i.dfy │ │ │ │ │ ├── PaxosWorldState.i.dfy │ │ │ │ │ ├── ProposerLemmas.i.dfy │ │ │ │ │ ├── ProposerModel.i.dfy │ │ │ │ │ ├── ProposerState.i.dfy │ │ │ │ │ ├── QRelations.i.dfy │ │ │ │ │ ├── ReplicaConstantsState.i.dfy │ │ │ │ │ ├── ReplicaImplClass.i.dfy │ │ │ │ │ ├── ReplicaImplDelivery.i.dfy │ │ │ │ │ ├── ReplicaImplLemmas.i.dfy │ │ │ │ │ ├── ReplicaImplMain.i.dfy │ │ │ │ │ ├── ReplicaImplNoReceiveClock.i.dfy │ │ │ │ │ ├── ReplicaImplNoReceiveNoClock.i.dfy │ │ │ │ │ ├── ReplicaImplProcessPacketNoClock.i.dfy │ │ │ │ │ ├── ReplicaImplProcessPacketX.i.dfy │ │ │ │ │ ├── ReplicaImplReadClock.i.dfy │ │ │ │ │ ├── ReplicaModel-Part1.i.dfy │ │ │ │ │ ├── ReplicaModel-Part2.i.dfy │ │ │ │ │ ├── ReplicaModel-Part3.i.dfy │ │ │ │ │ ├── ReplicaModel-Part4.i.dfy │ │ │ │ │ ├── ReplicaModel-Part5.i.dfy │ │ │ │ │ ├── ReplicaModel.i.dfy │ │ │ │ │ ├── ReplicaState.i.dfy │ │ │ │ │ └── Unsendable.i.dfy │ │ │ │ └── SHT/ │ │ │ │ ├── AppInterface.i.dfy │ │ │ │ ├── AppInterfaceConcrete.i.dfy │ │ │ │ ├── CMessage.i.dfy │ │ │ │ ├── ConstantsState.i.dfy │ │ │ │ ├── DelegationLookup.i.dfy │ │ │ │ ├── Delegations.i.dfy │ │ │ │ ├── HostModel.i.dfy │ │ │ │ ├── HostState.i.dfy │ │ │ │ ├── PacketParsing.i.dfy │ │ │ │ ├── Parameters.i.dfy │ │ │ │ ├── SHTConcreteConfiguration.i.dfy │ │ │ │ ├── SingleDeliveryModel.i.dfy │ │ │ │ └── SingleDeliveryState.i.dfy │ │ │ ├── Protocol/ │ │ │ │ ├── Common/ │ │ │ │ │ ├── Liveness/ │ │ │ │ │ │ └── RTSchedule.i.dfy │ │ │ │ │ ├── NodeIdentity.i.dfy │ │ │ │ │ ├── NodeIdentity.s.dfy │ │ │ │ │ └── UpperBound.s.dfy │ │ │ │ ├── LiveSHT/ │ │ │ │ │ ├── LivenessProof/ │ │ │ │ │ │ ├── Acks.i.dfy │ │ │ │ │ │ ├── Actions.i.dfy │ │ │ │ │ │ ├── Assumptions.i.dfy │ │ │ │ │ │ ├── Constants.i.dfy │ │ │ │ │ │ ├── Environment.i.dfy │ │ │ │ │ │ ├── InfiniteSends.i.dfy │ │ │ │ │ │ ├── Invariants.i.dfy │ │ │ │ │ │ ├── LivenessProof.i.dfy │ │ │ │ │ │ ├── PacketReceipt.i.dfy │ │ │ │ │ │ ├── PacketSending.i.dfy │ │ │ │ │ │ ├── RefinementInvariants.i.dfy │ │ │ │ │ │ ├── RoundRobin.i.dfy │ │ │ │ │ │ └── Seqno.i.dfy │ │ │ │ │ ├── RefinementProof/ │ │ │ │ │ │ ├── Environment.i.dfy │ │ │ │ │ │ ├── EnvironmentLemmas.i.dfy │ │ │ │ │ │ ├── EnvironmentRefinement.i.dfy │ │ │ │ │ │ ├── SHT.i.dfy │ │ │ │ │ │ ├── SHTLemmas.i.dfy │ │ │ │ │ │ ├── SHTRefinement.i.dfy │ │ │ │ │ │ ├── SchedulerLemmas.i.dfy │ │ │ │ │ │ └── SchedulerRefinement.i.dfy │ │ │ │ │ └── Scheduler.i.dfy │ │ │ │ ├── Lock/ │ │ │ │ │ ├── Node.i.dfy │ │ │ │ │ ├── RefinementProof/ │ │ │ │ │ │ ├── DistributedSystem.i.dfy │ │ │ │ │ │ ├── Refinement.i.dfy │ │ │ │ │ │ └── RefinementProof.i.dfy │ │ │ │ │ └── Types.i.dfy │ │ │ │ ├── RSL/ │ │ │ │ │ ├── Acceptor.i.dfy │ │ │ │ │ ├── Broadcast.i.dfy │ │ │ │ │ ├── ClockReading.i.dfy │ │ │ │ │ ├── CommonProof/ │ │ │ │ │ │ ├── Actions.i.dfy │ │ │ │ │ │ ├── Assumptions.i.dfy │ │ │ │ │ │ ├── CanonicalizeBallot.i.dfy │ │ │ │ │ │ ├── Chosen.i.dfy │ │ │ │ │ │ ├── Constants.i.dfy │ │ │ │ │ │ ├── Environment.i.dfy │ │ │ │ │ │ ├── LearnerState.i.dfy │ │ │ │ │ │ ├── LogTruncationPoint.i.dfy │ │ │ │ │ │ ├── MaxBallot.i.dfy │ │ │ │ │ │ ├── MaxBallotISent1a.i.dfy │ │ │ │ │ │ ├── Message1b.i.dfy │ │ │ │ │ │ ├── Message2a.i.dfy │ │ │ │ │ │ ├── Message2b.i.dfy │ │ │ │ │ │ ├── PacketSending.i.dfy │ │ │ │ │ │ ├── Quorum.i.dfy │ │ │ │ │ │ ├── Received1b.i.dfy │ │ │ │ │ │ ├── ReplyCache.i.dfy │ │ │ │ │ │ └── Requests.i.dfy │ │ │ │ │ ├── Configuration.i.dfy │ │ │ │ │ ├── Constants.i.dfy │ │ │ │ │ ├── DistributedSystem.i.dfy │ │ │ │ │ ├── Election.i.dfy │ │ │ │ │ ├── Environment.i.dfy │ │ │ │ │ ├── Executor.i.dfy │ │ │ │ │ ├── Learner.i.dfy │ │ │ │ │ ├── LivenessProof/ │ │ │ │ │ │ ├── Assumptions.i.dfy │ │ │ │ │ │ ├── Catchup.i.dfy │ │ │ │ │ │ ├── Environment.i.dfy │ │ │ │ │ │ ├── EpochLength.i.dfy │ │ │ │ │ │ ├── Execution.i.dfy │ │ │ │ │ │ ├── GenericInvariants.i.dfy │ │ │ │ │ │ ├── Invariants.i.dfy │ │ │ │ │ │ ├── LivenessProof.i.dfy │ │ │ │ │ │ ├── MaxBalReflected.i.dfy │ │ │ │ │ │ ├── MaxBallot.i.dfy │ │ │ │ │ │ ├── MaxBallotISent1a.i.dfy │ │ │ │ │ │ ├── NextOp.i.dfy │ │ │ │ │ │ ├── PacketHandling.i.dfy │ │ │ │ │ │ ├── Phase1a.i.dfy │ │ │ │ │ │ ├── Phase1b.i.dfy │ │ │ │ │ │ ├── Phase1bCont.i.dfy │ │ │ │ │ │ ├── Phase2Conclusion.i.dfy │ │ │ │ │ │ ├── Phase2Invariants.i.dfy │ │ │ │ │ │ ├── Phase2Start.i.dfy │ │ │ │ │ │ ├── Phase2a.i.dfy │ │ │ │ │ │ ├── Phase2b.i.dfy │ │ │ │ │ │ ├── Phase2c.i.dfy │ │ │ │ │ │ ├── RealTime.i.dfy │ │ │ │ │ │ ├── RequestQueue.i.dfy │ │ │ │ │ │ ├── RequestsReceived.i.dfy │ │ │ │ │ │ ├── RoundRobin.i.dfy │ │ │ │ │ │ ├── Seqno.i.dfy │ │ │ │ │ │ ├── StablePeriod.i.dfy │ │ │ │ │ │ ├── StateTransfer.i.dfy │ │ │ │ │ │ ├── ViewAdvance.i.dfy │ │ │ │ │ │ ├── ViewChange.i.dfy │ │ │ │ │ │ ├── ViewPersistence.i.dfy │ │ │ │ │ │ ├── ViewPropagation.i.dfy │ │ │ │ │ │ ├── ViewPropagation2.i.dfy │ │ │ │ │ │ ├── ViewSuspicion.i.dfy │ │ │ │ │ │ └── WF1.i.dfy │ │ │ │ │ ├── Message.i.dfy │ │ │ │ │ ├── Parameters.i.dfy │ │ │ │ │ ├── Proposer.i.dfy │ │ │ │ │ ├── RefinementProof/ │ │ │ │ │ │ ├── Chosen.i.dfy │ │ │ │ │ │ ├── Execution.i.dfy │ │ │ │ │ │ ├── HandleRequestBatch.i.dfy │ │ │ │ │ │ ├── Refinement.i.dfy │ │ │ │ │ │ ├── Requests.i.dfy │ │ │ │ │ │ └── StateMachine.i.dfy │ │ │ │ │ ├── Replica.i.dfy │ │ │ │ │ ├── StateMachine.i.dfy │ │ │ │ │ └── Types.i.dfy │ │ │ │ └── SHT/ │ │ │ │ ├── Configuration.i.dfy │ │ │ │ ├── Delegations.i.dfy │ │ │ │ ├── Host.i.dfy │ │ │ │ ├── Keys.i.dfy │ │ │ │ ├── Message.i.dfy │ │ │ │ ├── Network.i.dfy │ │ │ │ ├── Parameters.i.dfy │ │ │ │ ├── RefinementProof/ │ │ │ │ │ ├── InvDefs.i.dfy │ │ │ │ │ ├── InvProof.i.dfy │ │ │ │ │ ├── Refinement.i.dfy │ │ │ │ │ ├── RefinementProof.i.dfy │ │ │ │ │ └── SHT.i.dfy │ │ │ │ ├── SingleDelivery.i.dfy │ │ │ │ └── SingleMessage.i.dfy │ │ │ ├── Services/ │ │ │ │ ├── Lock/ │ │ │ │ │ ├── .gitignore │ │ │ │ │ ├── AbstractService.s.dfy │ │ │ │ │ ├── LockDistributedSystem.i.dfy │ │ │ │ │ ├── Main.i.dfy │ │ │ │ │ └── Marshall.i.dfy │ │ │ │ ├── RSL/ │ │ │ │ │ ├── .gitignore │ │ │ │ │ ├── AbstractService.s.dfy │ │ │ │ │ ├── AppStateMachine.s.dfy │ │ │ │ │ ├── Main.i.dfy │ │ │ │ │ ├── Marshall.i.dfy │ │ │ │ │ ├── Program.cs │ │ │ │ │ └── RSLDistributedSystem.i.dfy │ │ │ │ └── SHT/ │ │ │ │ ├── .gitignore │ │ │ │ ├── AbstractService.s.dfy │ │ │ │ ├── AppInterface.i.dfy │ │ │ │ ├── AppInterface.s.dfy │ │ │ │ ├── Bytes.s.dfy │ │ │ │ ├── HT.s.dfy │ │ │ │ ├── Main.i.dfy │ │ │ │ ├── Marshall.i.dfy │ │ │ │ └── SHTDistributedSystem.i.dfy │ │ │ └── apps.dfy.batch │ │ └── Libraries/ │ │ ├── .gitignore │ │ └── Math/ │ │ ├── .gitignore │ │ ├── div.i.dfy │ │ ├── div_auto.i.dfy │ │ ├── div_auto_proofs.i.dfy │ │ ├── div_def.i.dfy │ │ ├── div_nonlinear.i.dfy │ │ ├── mod_auto.i.dfy │ │ ├── mod_auto_proofs.i.dfy │ │ ├── mul.i.dfy │ │ ├── mul_auto.i.dfy │ │ ├── mul_auto_proofs.i.dfy │ │ ├── mul_nonlinear.i.dfy │ │ ├── power.i.dfy │ │ ├── power2.i.dfy │ │ ├── power2s.i.dfy │ │ └── powers.i.dfy │ ├── IronLockServer/ │ │ ├── .gitignore │ │ ├── IronLockServer.csproj │ │ ├── IronLockServer.sln │ │ ├── Params.cs │ │ └── Program.cs │ ├── IronRSLClient/ │ │ ├── .gitignore │ │ ├── IronRSLClient.csproj │ │ ├── IronRSLClient.sln │ │ └── RSLClient.cs │ ├── IronRSLCounterClient/ │ │ ├── .gitignore │ │ ├── Client.cs │ │ ├── IronRSLCounterClient.csproj │ │ ├── IronRSLCounterClient.sln │ │ ├── Params.cs │ │ └── Program.cs │ ├── IronRSLCounterServer/ │ │ ├── .gitignore │ │ ├── IronRSLCounterServer.csproj │ │ ├── IronRSLCounterServer.sln │ │ └── Service.cs │ ├── IronRSLKVClient/ │ │ ├── .gitignore │ │ ├── Client.cs │ │ ├── IronRSLKVClient.csproj │ │ ├── IronRSLKVClient.sln │ │ ├── Params.cs │ │ └── Program.cs │ ├── IronRSLKVServer/ │ │ ├── .gitignore │ │ ├── IronRSLKVServer.csproj │ │ ├── IronRSLKVServer.sln │ │ ├── KVMessages.cs │ │ └── Service.cs │ ├── IronSHTClient/ │ │ ├── .gitignore │ │ ├── Client.cs │ │ ├── IronSHTClient.csproj │ │ ├── IronSHTClient.sln │ │ ├── Params.cs │ │ └── Program.cs │ ├── IronSHTServer/ │ │ ├── .gitignore │ │ ├── IronSHTServer.csproj │ │ ├── IronSHTServer.sln │ │ ├── Params.cs │ │ └── Program.cs │ ├── IronfleetCommon/ │ │ ├── Networking.cs │ │ ├── Profiler.cs │ │ └── Timer.cs │ ├── RedisClient/ │ │ ├── .gitignore │ │ ├── IronfleetShtClient/ │ │ │ ├── App.config │ │ │ ├── Experiment.cs │ │ │ ├── IVocabularyModule.cs │ │ │ ├── IronfleetShtClient.csproj │ │ │ ├── KeyValueStoreClient.cs │ │ │ ├── Program.cs │ │ │ ├── Properties/ │ │ │ │ └── AssemblyInfo.cs │ │ │ ├── RedisClient.cs │ │ │ ├── StrawDog.cs │ │ │ ├── Vocabulary.cs │ │ │ └── packages.config │ │ └── IronfleetShtClient.sln │ └── TestIoFramework/ │ ├── .gitignore │ ├── Params.cs │ ├── Program.cs │ ├── TestIoFramework.csproj │ └── TestIoFramework.sln └── tools/ ├── DepGraph/ │ └── parse.py └── scripts/ ├── .gitignore ├── build-summary.py ├── check-lf.ps1 ├── dafny-line-count.py ├── dafny-oneproc.py ├── dafnyBuildVsix.ps1 ├── expand-tabs-in-place ├── function_call_graph.py ├── integration-project/ │ ├── build.py │ ├── build.pyproj │ ├── build.sln │ ├── make-project.sln │ └── make-project.vcxproj ├── integration-testing.ps1 └── purge.py ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # # This file needs to exist to work-around a bug in Visual Studio 2013's Git. # # Without this file, VS doesn't read any .gitignore files in any subdirectories # of this directory, with the end result being that some should-be-ignored files # show up as "Untracked Files" in the "Team Explorer - Changes" panel. # ================================================ FILE: LICENSE ================================================ Ironclad 1.0 Copyright (c) Microsoft Corporation All rights reserved. MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # About To learn more about the Ironclad Apps project, please see the related [README](./ironclad-apps/README.md) file. To learn more about the IronFleet project, please see the related [README](./ironfleet/README.md) file. ================================================ FILE: SECURITY.md ================================================ ## Security Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. ## Reporting Security Issues **Please do not report security vulnerabilities through public GitHub issues.** Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) * Full paths of source file(s) related to the manifestation of the issue * The location of the affected source code (tag/branch/commit or direct URL) * Any special configuration required to reproduce the issue * Step-by-step instructions to reproduce the issue * Proof-of-concept or exploit code (if possible) * Impact of the issue, including how an attacker might exploit the issue This information will help us triage your report more quickly. If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. ## Preferred Languages We prefer all communications to be in English. ## Policy Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). ================================================ FILE: ironclad-apps/.gitignore ================================================ codeplex obj/ obj-*/ bin-*/ bin/ bin_tools/ obj_tools/ src/Clients/*/bin/ *-disabled nucache/ nuobj/ nutemp/ nubuild.config nubuild.cloud-credentials nubuild.log nubuild.progress Experiments/ *.csproj.user StyleCop.Cache tmp/ ================================================ FILE: ironclad-apps/IRONROOT.sentinel ================================================ This file marks the top of the Ironclad source repository. Its presence is used by the NuBuild system to orient itself to the src/, nuobj/, and nucache/ directories. ================================================ FILE: ironclad-apps/README.md ================================================ # About This directory contains experimental verified Ironclad Apps code, as described in: > [_Ironclad Apps: End-to-End Security via Automated Full-System Verification_](http://research.microsoft.com/apps/pubs/default.aspx?id=230123) > Chris Hawblitzel, Jon Howell, Jacob R. Lorch, Arjun Narayan, Bryan Parno, Danfeng Zhang, and Brian Zill. > In Proceedings of the USENIX Symposium on Operating Systems Design and Implementation (OSDI) > October 6, 2014. As a brief summary, an Ironclad App lets a user securely transmit her data to a remote machine with the guarantee that every instruction executed on that machine adheres to a formal abstract specification of the app’s behavior. This does more than eliminate implementation vulnerabilities such as buffer overflows, parsing errors, or data leaks; it tells the user exactly how the app will behave at all times. We provide these guarantees via complete, low-level software verification. We then use cryptography and secure hardware to enable secure channels from the verified software to remote users. To achieve such complete verification, we developed a set of new and modified tools, a collection of techniques and engineering disciplines, and a methodology focused on rapid development of verified systems software. We describe our methodology, formal results, and lessons we learned from building a full stack of verified software. That software includes a verified kernel; verified drivers; verified system and crypto libraries including SHA, HMAC, and RSA; and four Ironclad Apps See http://research.microsoft.com/ironclad for more details. # License The Ironclad Apps code is licensed under the MIT license included in the [LICENSE](../ironfleet/LICENSE) file. # Setup The build process currently requires Windows PowerShell, though this should be relatively simple to replace. Since the build process uses PowerShell scripts, script execution must be enabled. (For example, launch "powershell.exe -ExecutionPolicy RemoteSigned".) To build the tools from a PowerShell prompt, simply run: `.\build-tools`. This will build all of the basic tools, including NuBuild (aka IronBuild), our distributed verification and build tool. To use Dafny interactively, you'll need Visual Studio 2012 or newer, Vim, or Emacs. Each has a plugin: - For Vim, we suggest the vim-loves-dafny plugin: https://github.com/mlr-msft/vim-loves-dafny - For Emacs, we suggest the Emacs packages boogie-mode and dafny-mode: https://github.com/boogie-org/boogie-friends - For Visual Studio, open: `./tools/Dafny/DafnyLanguageService.vsix` to install the Dafny plugin with our default settings. If you're running on Windows Server, and you see an error message that says Z3 has crashed, then you may need to install the [Microsoft Visual C++ runtime](http://www.microsoft.com/en-us/download/details.aspx?id=5555). These instructions assume you're running on Windows. However, Dafny, and all of its dependencies, also run on Linux. You can obtain Dafny sources from: https://github.com/Microsoft/Dafny/ Dafny's INSTALL file contains instructions for building on Linux with Mono. Note that we have not yet tested building our build tool, NuBuild, on Linux, so your mileage may vary. # Verification To perform our definitive verifications, we use our NuBuild tool, which handles dependency tracking, caches intermediate verification results locally and in the cloud, and can utilize a cluster of cloud VMs to parallelize verification. To enable cloud features, you'll need an Azure account and an Azure storage account. Once you have an Azure storage account, put your storage account's connection string into the `bin_tools/NuBuild/Nubuild.exe.config` file. This will let you make use of the cloud cache capabilities. To use the cloud build functionality, you'll need to add your subscription Id and Certificate (base64 encoded) to `bin_tools/NuBuild/AzureManage.exe.config`, which will then let you manage a cluster of VMs to serve as workers. You can still use NuBuild without cloud support, however, by passing the `--no-cloudcache` option. In the examples below, we'll assume you're using Cygwin, but other shells (e.g., Powershell) should work as well. To verify an individual Dafny file (and all of its dependencies), run: `./bin_tools/NuBuild/NuBuild.exe --no-cloudcache -j 3 DafnyVerifyTree src/Dafny/Libraries/Math/power2.i.dfy` which uses the `-j` flag to add 3-way local parallelism. To verify a forest of Dafny files (e.g., all of the IronFleet files), run: `./bin_tools/NuBuild/NuBuild.exe --no-cloudcache -j 3 BatchDafny src/Dafny/Apps/apps.dfy.batch` to do a high-level Dafny verification. This is a useful sanity check, but it is not the definitive verification for the system. The definitive verification, which includes all of the assembly code that will be executed, is run via: `./bin_tools/NuBuild/NuBuild.exe --no-cloudcache -j 3 IroncladApp src/Dafny/Apps/DafnyCCTest/Main.i.dfy` to verify and build a very simple Ironclad App. Try pointing it at other files in: `./src/Dafny/Apps/*/Main.i.dfy` to build the other apps. To build a version that actually boots, use `BootableApp` in place of `IroncladApp`. To build a debug version that runs on Windows, use the `--windows flag` to NuBuild. This is most useful when accompanied by the `--useFramePointer` which enables more detailed profiling. # Running To run an Ironclad App, you'll need an AMD machine with SVM support and a TPM. Adjust `boot/boot-cp.cmd` to point at the executable output by the `BootableApp` verb above, and run `boot/boot-cp.cmd`, which will start a PXE boot server that your AMD machine should be configured to connect to. # Contributing See the [CONTRIBUTING](../ironfleet/CONTRIBUTING.md) file for more details. # Version History - v0.1: Initial code release on GitHub. ================================================ FILE: ironclad-apps/boot/boot-cp.cmd ================================================ @rem ////////////////////////////////////////////////////////////////////// @rem @rem Microsoft Research Singularity @rem @rem Copyright (c) Microsoft Corporation. All rights reserved. @rem @rem This script launches bootd with paths set up for the current build @rem environment. It replies to hosts specified in the file @rem %SINGULARITY_ROOT%\boothosts.txt. MAC addresses should appear one per @rem line. @rem @echo off setlocal enabledelayedexpansion enableextensions :parse if /I .%1==./1394 ( set ConnectArgs=/dhcp /c:DBG=1 shift goto :parse ) if not defined BOOT_HOSTS ( set BOOT_HOSTS=%~dp0\boothosts.txt ) if not exist "%BOOT_HOSTS%" ( echo.Could not find boot hosts file: echo. echo. %BOOT_HOSTS% echo. echo.The boot hosts file should specify a list of MAC addresses one per echo.line for bootd to respond to. If IP addresses are to be associated echo.with a MAC address then they should be comma-separated from their MAC echo.addresses, e.g. 00-01-02-03-04-05,10.0.0.1 exit /b 1 ) @rem NB using type here because of need to quote protect path to support @rem paths with spaces in. set MacArgs= for /F %%m in ('type "%BOOT_HOSTS%"') do ( set MacArgs=!MacArgs! /m:%%m ) start %~dp0\bootd.exe /dhcp %ConnectArgs% /b:pxe-loader !MacArgs! /tftp /v ..\nuobj\src\Dafny\Apps\BenchmarkService\bootable-NoVerify %* ================================================ FILE: ironclad-apps/boot/boothosts.txt ================================================ 90-e2-ba-4f-0c-5b d4-85-64-c3-19-f6 ================================================ FILE: ironclad-apps/build-tools.ps1 ================================================ . .\env.ps1 $ROOT="." . $ROOT\def.ps1 $args $NMAKE = "$(ls $BUILD\nmake.exe)" $MSBUILD="C:/Windows/Microsoft.NET/Framework/v4.0.30319/MSBuild.exe" $VSVERSION="/property:VisualStudioVersion=12.0" ensureDir("$OBJROOT") ensureDir("$BINROOT") # Cygwin make helpfully passes along an argument that NMAKE doesn't understand $Env:MAKEFLAGS = "" echo "Building NuBuild" runShell "cd tools\NuBuild; & `"$MSBUILD`" $VSVERSION NuBuild.sln" ensureDir("$OBJROOT\Checked\BootLoader\SingLdrPc") ensureDir("$OBJROOT\Checked\BootLoader\x86") ensureDir("$OBJROOT\Checked\BootLoader\tpm") echo "Building Bootloader" runShell "cd src\Checked\BootLoader\SingLdrPc; & `"$NMAKE`" /nologo OBJ=..\..\..\..\obj$BUILD_SUFFIX\Checked\BootLoader" pxe-loader ================================================ FILE: ironclad-apps/def.ps1 ================================================ $build_args = $args[0] $BUILD_SUFFIX = "$($build_args | %{"-$_"})".Replace(" ", "") $BUILD_DEFS = $($build_args | %{"-def"; $_}) $BUILD = "$ROOT\tools\build" $OBJROOT = "$ROOT\obj$BUILD_SUFFIX" $BINROOT = "$ROOT\bin$BUILD_SUFFIX" $BINTOOLS = "$ROOT\bin_tools" $SPEC = "$ROOT\src\Trusted\Spec" # By default, all the following should be true: $SYMDIFF_ENABLED = $false $BOOGIE_ENABLED = $true $DAFNYCC_INCREMENTAL_BUILD = $true # The AppLoader doesn't know any secrets, so we don't need to run SymDiff on it. if ($build_args -contains "AppLoader") { $SYMDIFF_ENABLED = $false } function list { @($args) } $boogieasm_x64_flag = "" if ($build_args.Contains("x64")) { $boogieasm_x64_flag = "-x64" } # recursively flatten all arrays into a single array function flatten($arr) { do { $c = $arr.count $arr = @($arr | %{$_}) } while ($c -ne $arr.count) ,($arr) } function run([Parameter(Mandatory=$true)]$cmd, [Parameter(ValueFromRemainingArguments=$true)]$arr) { & $cmd $(flatten $arr) if($LastExitCode) { throw "error running $cmd $(flatten $arr)" } } function runShell { powershell -command "$(flatten $args)" if($LastExitCode) { throw "error running $(flatten $args)" } } function needToBuild($out, $ins) { #Write-Host "Do I need to build $out ?" if (-not (test-path $out)) { return $true } $t = (get-item $out).LastWriteTimeUtc foreach ($f in $ins) { if (-not (test-path $f)) { throw "cannot find input file $f" } if ($t -lt (get-item $f).LastWriteTimeUtc) { return $true } #Write-Host "Checking need to build based on: $f" } return $false } function ensureDir($dir) { if (-not (test-path $dir)) { mkdir $dir } } function ensureDirForFile($path) { $dir = [System.IO.Path]::GetDirectoryName($path) if (-not (test-path $dir)) { mkdir $dir } } function _boogie_dbg([Parameter(Mandatory=$true)]$out, [Parameter(ValueFromRemainingArguments=$true)]$arr) { $arr = flatten $arr $boogieasm = "$BINTOOLS\boogieasm\boogieasm.exe" $ins = @($arr | ?{-not $_.StartsWith("/")}) + @($boogieasm) if (needToBuild $out $ins) { ensureDirForFile($out) "boogie $arr" $bpls = $arr | ?{$_.EndsWith(".bpl")} $flags = $arr | ?{-not $_.EndsWith(".bpl")} run $boogieasm $BUILD_DEFS $boogieasm_x64_flag "-verify" "-out" "$out.bpl" $bpls $time1 = Get-Date & "$ROOT\..\iron\build\boogie-new\boogie.exe" /printModel:4 /noinfer /typeEncoding:m $flags "$out.bpl" | out-file -encoding ascii "$out.err" #& "$ROOT\..\iron\build\boogie-new\boogie.exe" /mv:model.bvd /noinfer /typeEncoding:m $flags "$out.bpl" | out-file -encoding ascii "$out.err" $time2 = Get-Date cat "$out.err" if(-not (findstr /c:"verified, 0 errors" "$out.err")) {throw "error building $out"} if( (findstr /c:"inconclusive" "$out.err")) {throw "error building $out"} if( (findstr /c:"time out" "$out.err")) {throw "error building $out"} mv -force "$out.err" $out "Time: $($time2 - $time1)" "" } } function __boogie_exe($out, $flags, $arr) { $time1 = Get-Date "$ROOT\tools\Dafny\boogie.exe /noinfer /typeEncoding:m /z3opt:ARITH_RANDOM_SEED=1 $flags $out.bpl" & "$ROOT\tools\Dafny\boogie.exe" /noinfer /typeEncoding:m /z3opt:ARITH_RANDOM_SEED=1 $flags "$out.bpl" | out-file -encoding ascii "$out.err" $time2 = Get-Date cat "$out.err" if(-not (findstr /c:"verified, 0 errors" "$out.err")) {throw "error building $out"} if( (findstr /c:"inconclusive" "$out.err")) {throw "error building $out"} if( (findstr /c:"time out" "$out.err")) {throw "error building $out"} mv -force "$out.err" $out "Time: $(($time2 - $time1).TotalSeconds) $out" "" } function __boogie_sd_optional($out, $sdiff, $arr) { $arr = flatten $arr $boogieasm = "$BINTOOLS\boogieasm\boogieasm.exe" $ins = @($arr | ?{-not $_.StartsWith("/")}) + @($boogieasm) $outname = $out # Assume the file to be verified is the last in line $src = $arr[-1] $src_i = $src.replace(".bpl", "_i.bpl") # Create the potential interface file name # Check whether the Boogie files use relational logic $rel_i = $false $pub_i = $false if (Test-Path ($src_i)) { # If this is the module implementation, check the interface too $rel_i = (Select-String -CaseSensitive "[^a-zA-Z0-9_]relation\(.*\)" $src_i).Count -gt 0 $pub_i = (Select-String -CaseSensitive "[^a-zA-Z0-9_]public\(.*\)" $src_i).Count -gt 0 } $rel = (Select-String -CaseSensitive "[^a-zA-Z0-9_]relation\(.*\)" $src).Count -gt 0 $pub = (Select-String -CaseSensitive "[^a-zA-Z0-9_]public\(.*\)" $src).Count -gt 0 if ($src.EndsWith("EntryCP.bpl")) { # Special-case entry, since its interface lives in spec land $rel_i = $true } # Apply SymDiff if we find relation or public in the implementation or the interface $deduced_symdiff = $rel -or $pub -or $rel_i -or $pub_i #echo "For $src, sdiff is $sdiff and I deduced $deduced_symdiff" | out-file -append -encoding ascii sdiff.txt $sdiff = $deduced_symdiff if ($sdiff -and $SYMDIFF_ENABLED) { $outname = "$out.merged" } if (((needToBuild $outname $ins) -and $BOOGIE_ENABLED) -or ((-not $BOOGIE_ENABLED) -and (needToBuild "$outname.assume" $ins))) { ensureDirForFile($out) "boogie $arr" $bpls = $arr | ?{$_.EndsWith(".bpl")} $ba_flagnames = @("") $ba_flags = $arr | ?{$ba_flagnames -contains $_} | %{$_.Replace("/", "-")} $flags = $arr | ?{-not $_.EndsWith(".bpl")} | ?{-not ($ba_flagnames -contains $_)} $fulltime1 = Get-Date if ($sdiff) { run $boogieasm $BUILD_DEFS $boogieasm_x64_flag $ba_flags "-verify" "-symdiffok" "-out" "$out.bpl" $bpls run $boogieasm $BUILD_DEFS $boogieasm_x64_flag $ba_flags "-verify" "-symdiffms" "$out.ms.bpl" "-out" "$out.symdiff.bpl" $bpls } else { run $boogieasm $BUILD_DEFS $boogieasm_x64_flag $ba_flags "-verify" "-out" "$out.bpl" $bpls } $fulltime2 = Get-Date if ($BOOGIE_ENABLED) { __boogie_exe $out $flags $arr } else { echo $null > "$out.assume" } $fulltime3 = Get-Date if ($sdiff -and $SYMDIFF_ENABLED) { $save_dir = pwd try { $outfile = [System.IO.Path]::GetFileName($out) cd $([System.IO.Path]::GetDirectoryName($out)) cp $($outfile + ".symdiff.bpl") v1.bpl cp $($outfile + ".symdiff.bpl") v2.bpl echo "" | out-file -encoding ascii ms_symdiff_file.bpl echo "LOOPS" run "$SYMDIFF\symdiff.exe" -extractLoops v1.bpl v1_u.bpl run "$SYMDIFF\symdiff.exe" -extractLoops v2.bpl v2_u.bpl echo "INFER" run "$SYMDIFF\symdiff.exe" -inferConfig v1_u.bpl v2_u.bpl | out-file -encoding ascii v1_uv2_u.config echo "CONFIGURE" run $BINTOOLS\boogieasm\symdiffmerge.exe -config "$outfile.ms.bpl" v1_uv2_u.config | out-file -encoding ascii "$outfile.config" echo "RUN SYMDIFF" run "$SYMDIFF\symdiff.exe" -allInOne v1_u.bpl v2_u.bpl "$outfile.config" -asserts -freeContracts -usemutual -sound -dontUseHoudiniForMS -checkMutualPrecondNonTerminating echo "MERGE" run $BINTOOLS\boogieasm\symdiffmerge.exe -merge "$outfile.ms.bpl" mergedProgSingle.bpl | out-file -encoding ascii "$outfile.merged.bpl" cd $save_dir echo "RUN BOOGIE" __boogie_exe $outname $flags $arr } finally { cd $save_dir } } $fulltime4 = Get-Date $t = $(($fulltime2 - $fulltime1).TotalSeconds); $t | out-file -encoding ascii "$out.____$($t)____.time_bgasm" $t = $(($fulltime3 - $fulltime2).TotalSeconds); $t | out-file -encoding ascii "$out.____$($t)____.time_boogie" $t = $(($fulltime4 - $fulltime3).TotalSeconds); $t | out-file -encoding ascii "$out.____$($t)____.time_symdiff" } } function _boogie_sd_optional([Parameter(Mandatory=$true)]$out, [Parameter(Mandatory=$true)]$relational, [Parameter(ValueFromRemainingArguments=$true)]$arr) { __boogie_sd_optional $out $relational $arr } function _boogie([Parameter(Mandatory=$true)]$out, [Parameter(ValueFromRemainingArguments=$true)]$arr) { __boogie_sd_optional $out $false $arr } function _boogie_symdiff([Parameter(Mandatory=$true)]$out, [Parameter(ValueFromRemainingArguments=$true)]$arr) { __boogie_sd_optional $out $true $arr } function _copy([Parameter(Mandatory=$true)]$out, [Parameter(Mandatory=$true)]$in) { $ins = list $in if (needToBuild $out $ins) { ensureDirForFile($out); "copy -out $out -in $in" cat $in | out-file -encoding ascii $out } } function _copy_if_different([Parameter(Mandatory=$true)]$out, [Parameter(Mandatory=$true)]$in) { if (-not $DAFNYCC_INCREMENTAL_BUILD) { cp $in $out } elseif (-not (test-path $out)) { cp $in $out } else { $bytes_out = [System.IO.File]::ReadAllBytes((ls $out).FullName) $bytes_in = [System.IO.File]::ReadAllBytes((ls $in).FullName) if (-not ([System.Collections.StructuralComparisons]::StructuralEqualityComparer.Equals($bytes_out, $bytes_in))) { cp $in $out } } } function _cat([Parameter(Mandatory=$true)]$out, [Parameter(Mandatory=$true)][string[]]$in) { $ins = $in if (needToBuild $out $ins) { ensureDirForFile($out); "cat -out $out -in $in" cat $in | out-file -encoding ascii $out } } function _beat([Parameter(Mandatory=$true)]$out, [Parameter(Mandatory=$true)]$in, [string[]]$includes) { if ($includes -eq $null) { $includes = @() } $beat = "$BINTOOLS\beat\beat.exe" $ins = flatten (list $in $beat $includes) if (needToBuild $out $ins) { ensureDirForFile($out) $incls = @($includes | %{"-i"; $_}) "beat $BUILD_DEFS -out $out.tmp -in $in $incls" # & $beat -printAndExit $BUILD_DEFS -in $in $incls | out-file -encoding ascii "$out.ppall" # if($LastExitCode) { cat "$out.ppall"; throw "error building $out" } # & $beat -printNonghostAndExit $BUILD_DEFS -in $in $incls | out-file -encoding ascii "$out.ppwog" # if($LastExitCode) { cat "$out.ppwog"; throw "error building $out" } & $beat $BUILD_DEFS -in $in $incls | out-file -encoding ascii "$out.tmp" if($LastExitCode) { cat "$out.tmp" throw "error building $out" } mv -force "$out.tmp" $out "" } } function _dafnyspec([Parameter(Mandatory=$true)]$outdir, [Parameter(Mandatory=$true)]$outlist, [Parameter(Mandatory=$true)]$deps, [Parameter(Mandatory=$true)]$in) { $dafnyspec = "$BINTOOLS\dafnyspec\dafnyspec.exe" $ins = flatten ((list $in $dafnyspec) + @($deps)) if (needToBuild $outlist $ins) { ensureDirForFile("$outdir\dummy") "dafnyspec $in /outdir:$outdir /outlist:$outlist" & $dafnyspec $in /outdir:$outdir /outlist:$outlist if($LastExitCode) { throw "error building $out" } "" } } function _dafnycc([Parameter(Mandatory=$true)]$outdir, [Parameter(Mandatory=$true)]$outlist, [Parameter(Mandatory=$true)]$heap, [Parameter(Mandatory=$true)]$heapi, [Parameter(Mandatory=$true)]$deps, [Parameter(Mandatory=$true)]$in) { $dafnycc = "$BINTOOLS\dafnycc\dafnycc.exe" $ins = flatten ((list $in $dafnycc) + @($deps)) if ($build_args.Contains("x64")) { $x64_flag = "/x64" } if (needToBuild $heap $ins) { ensureDirForFile($heap) ensureDirForFile($heapi) ensureDirForFile("$outdir\dummy") "dafnycc $in /useFramePointer /heapfile:$heap /heapifile:$heapi /outdir:$outdir /relational /outlist:$outlist $x64_flag" & $dafnycc $in /useFramePointer /heapfile:$heap /heapifile:$heapi /outdir:$outdir /relational /outlist:$outlist $x64_flag if($LastExitCode) { throw "error building $out" } "" } } function _boogieasm([Parameter(Mandatory=$true)]$out, [Parameter(ValueFromRemainingArguments=$true)]$arr) { $boogieasm = "$BINTOOLS\boogieasm\boogieasm.exe" $arr = flatten $arr $ins = @($arr | %{"$_.bpl"}) + @($arr | %{"$($_)_i.bpl"}) + @($boogieasm) if (needToBuild $out $ins) { ensureDirForFile($out) "$boogieasm $BUILD_DEFS $boogieasm_x64_flag -link $arr | out-file -encoding ascii $out.tmp " & $boogieasm $BUILD_DEFS $boogieasm_x64_flag -link $arr | out-file -encoding ascii "$out.tmp" if($LastExitCode) { #cat "$out.tmp" | out-file -encoding ascii "$OBJROOT\$out.tmp" throw "error building $out. Check the end of $out.tmp for more details." } mv -force "$out.tmp" $out "" } } function _cdimage([Parameter(Mandatory=$true)]$inDir, [Parameter(Mandatory=$true)]$bootSector, [Parameter(Mandatory=$true)]$out, [Parameter(ValueFromRemainingArguments=$true)]$arr) { $arr = flatten $arr $ins = @(ls -r $inDir | %{$_.FullName}) + @($bootsector) if (needToBuild $out $ins) { ensureDirForFile($out) "cdimage $arr -b$bootSector $inDir $out" run $BUILD\cdimage.exe $arr "-b$bootSector" $inDir $out "" } } ================================================ FILE: ironclad-apps/env.ps1 ================================================ if ($env:SAFEOS_ROOT -eq $null) { $env:SAFEOS_ROOT = $PWD $env:PATH = $env:PATH + ";$env:SAFEOS_ROOT\tools\build" } ================================================ FILE: ironclad-apps/makefile ================================================ NUBUILD=bin_tools/NuBuild/NuBuild.exe -j $(j) all: $(NUBUILD) $(NUBUILD) DafnyVerifyTree src/Dafny/apps/apps.batch # $(NUBUILD) --html nuobj/summary.html DafnyVerifyTree src/Dafny/apps/apps.batch $(NUBUILD): make -C tools/NuBuild nuobj/test.tgz: all find nuobj -name \*.vdfy | tar --files-from=- -czf $@ #all: # tools/scripts/ironmake.py # +make -C obj #test.tgz: # tools/scripts/ironmake.py # +DAFNYTIMELIMIT=120 make -C obj test.tgz clean-dafny: find obj -name \*.res\* | xargs rm ================================================ FILE: ironclad-apps/src/Checked/BootLoader/SingLdrPc/.gitignore ================================================ tags ================================================ FILE: ironclad-apps/src/Checked/BootLoader/SingLdrPc/bl.h ================================================ //++ // // Copyright (c) Microsoft Corporation // // Module Name: // // bl.h // // Abstract: // // This module contains definitions for the boot loader. // // Environment: // // Boot loader. // //-- #pragma once #pragma warning(disable:4127) // conditional expression is constant #pragma warning(disable:4152) // function/data pointer conversion in expression #pragma warning(disable:4200) // zero-sized array in struct/union #pragma warning(disable:4201) // nameless struct/union #pragma warning(disable:4214) // bit field types other than int // // Constants for selectively enabling verbose debug output. // #define ACPI_VERBOSE 0 #define APM_VERBOSE 0 #define CDROM_VERBOSE 0 #define COM_VERBOSE 0 #define DISTRO_VERBOSE 1 #define FAT_VERBOSE 0 #define KD_VERBOSE 0 #define MM_VERBOSE 0 #define MPS_VERBOSE 0 #define PCI_VERBOSE 0 #define PECOFF_VERBOSE 1 #define PNP_VERBOSE 0 #define POOL_VERBOSE 0 #define PXE_VERBOSE 0 #define SINGULARITY_VERBOSE 0 #define SMAP_VERBOSE 0 #define DEBUG_MSG(msg) \ { \ UINT32 my_debug_cntr = 0; \ while (my_debug_cntr < 1<<31) { \ if (my_debug_cntr == 0) { \ BlRtlPrintf(msg); \ } \ my_debug_cntr += 1; \ } \ } // // Basic platform constants. // #define PAGE_SIZE 4096 #define LEGACY_MEMORY_LIMIT 0x100000 // // Compile-time assertion support. // #define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1] // // Basic integer types. // typedef char CHAR; typedef unsigned char UCHAR; typedef char INT8; typedef unsigned char UINT8; typedef short INT16; typedef unsigned short UINT16; typedef long INT32; typedef unsigned long UINT32; typedef __int64 INT64; typedef unsigned __int64 UINT64; #if defined(BOOT_X86) typedef INT32 LONG_PTR; typedef UINT32 ULONG_PTR; #elif defined (BOOT_X64) typedef INT64 LONG_PTR; typedef UINT64 ULONG_PTR; #endif // // Basic boolean type. // typedef unsigned char BOOLEAN; // // Basic pointer types. // typedef void VOID; typedef VOID * PVOID; typedef const VOID * PCVOID; typedef CHAR * PCHAR; typedef INT8 * PINT8; typedef UINT8 * PUINT8; typedef INT16 * PINT16; typedef UINT16 * PUINT16; typedef INT32 * PINT32; typedef UINT32 * PUINT32; typedef INT64 * PINT64; typedef UINT64 * PUINT64; typedef LONG_PTR * PLONG_PTR; typedef ULONG_PTR * PULONG_PTR; typedef BOOLEAN PBOOLEAN; // // Wide character types. // typedef wchar_t WCHAR; typedef WCHAR * PWCHAR; typedef const WCHAR * PCWSTR; typedef const CHAR * PCSTR; // // Structure macros. // #define FIELD_OFFSET(Type, Field) ((UINT32) (ULONG_PTR) &(((Type *) 0)->Field)) #define CONTAINING_RECORD(Address, Type, Field) ((Type *) ((ULONG_PTR) (Address) - FIELD_OFFSET(Type, Field))) #define ARRAY_SIZE(Array) (sizeof(Array) / sizeof(Array[0])) // // Macros for rounding up. // #define ROUND_UP_TO_POWER2(X, P) (((X) + ((P) - 1)) & (~((P) - 1))) #define ROUND_UP_TO_PAGES(X) ROUND_UP_TO_POWER2(X, PAGE_SIZE) // // The following macro is used to satisfy the compiler. Note that the // expressions/statements passed to this macro are not necessary for // correctness, but without them the compiler cannot compile with W4. // #define SATISFY_OVERZEALOUS_COMPILER(X) X // // Function modifiers. // #define FORCEINLINE __forceinline // // Basic constants. // #define FALSE 0 #define TRUE 1 #define NULL 0 // // va support (from vadefs.h). // typedef char *va_list; #if defined(BOOT_X86) #define _ADDRESSOF(v) ( &(v) ) #define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) ) #define _crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) ) #define _crt_va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) #define _crt_va_end(ap) ( ap = (va_list)0 ) #elif defined(BOOT_X64) extern "C" void __cdecl __va_start(va_list *, ...); #define _crt_va_start(ap, x) ( __va_start(&ap, x) ) #define _crt_va_arg(ap, t) \ ( ( sizeof(t) > sizeof(__int64) || ( sizeof(t) & (sizeof(t) - 1) ) != 0 ) \ ? **(t **)( ( ap += sizeof(__int64) ) - sizeof(__int64) ) \ : *(t *)( ( ap += sizeof(__int64) ) - sizeof(__int64) ) ) #define _crt_va_end(ap) ( ap = (va_list)0 ) #endif #define va_start _crt_va_start #define va_arg _crt_va_arg #define va_end _crt_va_end UINT32 DisablePaging( UINT32 arg ); // // Runtime assertion support. // BOOLEAN BlRtlPrintf( PCSTR Format, ... ); VOID BlRtlHaltInternal( PCSTR FileName, UINT32 LineNumber ); VOID BlRtlAssertFailed( PCSTR FileName, UINT32 LineNumber ); VOID BlRtlAssertFailedPtr( PCSTR FileName, UINT32 LineNumber, ULONG_PTR Param ); #define BlRtlHalt() BlRtlHaltInternal(__FILE__, __LINE__) #define BLASSERT(X) \ if (!(X)) { \ BlRtlAssertFailed(__FILE__, __LINE__); \ } #define BLASSERT_PTR(X, P) \ if (!(X)) { \ BlRtlAssertFailedPtr(__FILE__, __LINE__, (ULONG_PTR) (P)); \ } // // Linked list support. // typedef struct _LIST_ENTRY { struct _LIST_ENTRY *Flink; struct _LIST_ENTRY *Blink; } LIST_ENTRY, *PLIST_ENTRY; VOID BlRtlInitializeListHead( PLIST_ENTRY Head ); BOOLEAN BlRtlIsListEmpty( PLIST_ENTRY Head ); BOOLEAN BlRtlRemoveEntryList( PLIST_ENTRY Entry ); PLIST_ENTRY BlRtlRemoveHeadList( PLIST_ENTRY Head ); PLIST_ENTRY BlRtlRemoveTailList( PLIST_ENTRY Head ); VOID BlRtlInsertTailList( PLIST_ENTRY Head, PLIST_ENTRY Entry ); VOID BlRtlInsertHeadList( PLIST_ENTRY Head, PLIST_ENTRY Entry ); // // Legacy far pointer support. // typedef struct _FAR_POINTER { UINT16 Offset; UINT16 Segment; } FAR_POINTER, *PFAR_POINTER; C_ASSERT(sizeof(FAR_POINTER) == sizeof(UINT32)); VOID BlRtlConvertLinearPointerToFarPointer( PVOID LinearPointer, PFAR_POINTER FarPointer ); PVOID BlRtlConvertFarPointerToLinearPointer( PFAR_POINTER FarPointer ); // // Boot environment block. // typedef struct _BEB { UINT32 BootType; UINT32 BootDriveNumber; UINT32 FlashImage; UINT32 SmapAddr; UINT32 SmapSize; UINT32 LegacyCallAddress; UINT32 LegacyReturnAddress; UINT32 LegacyReturnCr3; UINT32 LegacyCall_OpCode; UINT32 LegacyCall_Vector; UINT32 LegacyCall_ax; UINT32 LegacyCall_bx; UINT32 LegacyCall_cx; UINT32 LegacyCall_dx; UINT32 LegacyCall_si; UINT32 LegacyCall_di; UINT32 LegacyCall_ds; UINT32 LegacyCall_es; UINT32 LegacyCall_flags; FAR_POINTER LegacyCall_FramePtr; UINT32 LegacyCall_FrameSize; FAR_POINTER LegacyCall_FuncPtr; FAR_POINTER ApEntry16; UINT32 ApEntry; FAR_POINTER ApStartupLock; } BEB, *PBEB; #define BEB_BASE ((ULONG_PTR) 0x2F000) FORCEINLINE PBEB BlGetBeb( VOID ) //++ // //Routine Description: // // This function returns a pointer to the boot environment block. // //Return Value: // // Pointer to the boot environment block. // //-- { return ((PBEB) BEB_BASE); } // // Boot sources. // #define BL_CD_BOOT 1 #define BL_FAT16_BOOT 2 #define BL_FAT32_BOOT 3 #define BL_PXE_BOOT 4 #define BL_FLASH_BOOT 5 // // Legacy call context. // typedef struct _BL_LEGACY_CALL_CONTEXT { UINT32 eax; UINT32 ebx; UINT32 ecx; UINT32 edx; UINT32 esi; UINT32 edi; UINT32 ds; UINT32 es; UINT32 eflags; } BL_LEGACY_CALL_CONTEXT, *PBL_LEGACY_CALL_CONTEXT; // // Legacy call opcodes. // #define LC_NOP 0x0000 #define LC_INTXX 0x0001 #define LC_FARCALL 0x0002 // // RFLAGS. // #define RFLAGS_CF 0x0001 // // Utility functions. // VOID BlRtlZeroMemory( PVOID Buffer, ULONG_PTR Length ); VOID BlRtlCopyMemory( PVOID Destination, PCVOID Source, ULONG_PTR Length ); BOOLEAN BlRtlCompareMemory( PCVOID Buffer1, PCVOID Buffer2, ULONG_PTR Length ); VOID BlRtlCallLegacyInterruptService( UINT8 Vector, PBL_LEGACY_CALL_CONTEXT Input, PBL_LEGACY_CALL_CONTEXT Output ); VOID BlRtlCallLegacyFunction( UINT16 CodeSegment16, UINT16 CodeOffset16, PVOID CallFrame, UINT32 CallFrameSize, PBL_LEGACY_CALL_CONTEXT Input, PBL_LEGACY_CALL_CONTEXT Output ); UINT8 BlRtlComputeChecksum8( PCVOID Buffer, UINT32 Size ); UINT32 BlGetCpuidEax( UINT32 reg ); UINT32 BlGetCpuidEbx( UINT32 reg ); UINT32 BlGetCpuidEcx( UINT32 reg ); UINT32 BlGetCpuidEdx( UINT32 reg ); // // Constants and macros for accessing the keyboard controller. // #define BL_KEYBOARD_STATUS_PORT 0x0064 #define BL_KEYBOARD_COMMAND_PORT 0x0064 #define BL_KEYBOARD_DATA_PORT 0x0060 #define BL_KEYBOARD_STATUS_INPUT_BUFFER_FULL 0x02 #define BL_KEYBOARD_COMMAND_WRITE_OUTPUT_PORT 0xD1 #define BL_KEYBOARD_COMMAND_PULSE_RESET_BIT 0xFE #define BL_KEYBOARD_COMMAND_PULSE_OUTPUT_PORT 0xFF #define BL_KEYBOARD_A20_ENABLE 0xDF #define BL_KEYBOARD_WAIT_FOR_IDLE() \ while ((BlRtlReadPort8(BL_KEYBOARD_STATUS_PORT) & BL_KEYBOARD_STATUS_INPUT_BUFFER_FULL) != 0) { \ } #define BL_KEYBOARD_WRITE_COMMAND(X) \ { \ BL_KEYBOARD_WAIT_FOR_IDLE(); \ BlRtlWritePort8(BL_KEYBOARD_COMMAND_PORT, (X)); \ BL_KEYBOARD_WAIT_FOR_IDLE(); \ } #define BL_KEYBOARD_WRITE_OUTPUT_PORT(X) \ { \ BL_KEYBOARD_WAIT_FOR_IDLE(); \ BlRtlWritePort8(BL_KEYBOARD_COMMAND_PORT, BL_KEYBOARD_COMMAND_WRITE_OUTPUT_PORT); \ BL_KEYBOARD_WAIT_FOR_IDLE(); \ BlRtlWritePort8(BL_KEYBOARD_DATA_PORT, (X)); \ BL_KEYBOARD_WAIT_FOR_IDLE(); \ } VOID BlRtlResetSystem( VOID ); VOID BlRtlShutdownSystem( VOID ); // // Drive access routines. // #pragma pack(1) typedef struct _INT13_DRIVE_PARAMETERS { UINT16 StructureSize; UINT16 InformationFlags; UINT32 NumberOfCylinders; UINT32 NumberOfHeads; UINT32 SectorsPerTrack; UINT64 TotalNumberOfSectors; UINT16 BytesPerSector; } INT13_DRIVE_PARAMETERS, *PINT13_DRIVE_PARAMETERS; C_ASSERT(sizeof(INT13_DRIVE_PARAMETERS) == 0x1A); #pragma pack() BOOLEAN BlRtlGetDriveParameters( UINT8 DriveId, PINT13_DRIVE_PARAMETERS DriveParameters ); BOOLEAN BlRtlReadDrive( UINT8 DriveId, UINT64 FirstBlock, UINT16 NumberOfBlocks, PVOID Buffer ); // // I/O port access routines. // UINT8 BlRtlReadPort8( UINT16 Port ); UINT32 BlRtlReadPort32( UINT16 Port ); VOID BlRtlWritePort8( UINT16 Port, UINT8 Value ); VOID BlRtlWritePort32( UINT16 Port, UINT32 Value ); // // String support. // CHAR BlRtlConvertCharacterToUpperCase( CHAR C ); PCSTR BlRtlFindSubstring( PCSTR String, PCSTR Substring ); BOOLEAN BlRtlParsePositiveDecimal( PCSTR String, PUINT32 Number, PUINT32 CharactersConsumed ); BOOLEAN BlRtlFormatString( PCHAR Output, UINT32 OutputSize, PCSTR Format, va_list ArgumentList ); UINT32 BlRtlStringLength( PCSTR String ); UINT32 BlRtlStringLengthW( PCWSTR String ); BOOLEAN BlRtlEqualStringN( PCSTR String1, PCSTR String2, UINT32 Count ); BOOLEAN BlRtlEqualStringI( PCSTR String1, PCSTR String2 ); // // Video support. // VOID BlVideoPrintString( PCSTR String ); BOOLEAN BlVideoPrintf( PCSTR Format, ... ); VOID BlVideoInitialize( VOID ); // // COM port support. // #define COM_MAX_PORT 4 extern const UINT16 BlComBasePort[COM_MAX_PORT + 1]; BOOLEAN BlComInitialize( UINT8 PortNumber, UINT32 BaudRate ); BOOLEAN BlComSendByte( UINT8 PortNumber, UINT8 Byte ); BOOLEAN BlComDataAvailable( UINT8 PortNumber ); UINT8 BlComReceiveByte( UINT8 PortNumber ); // // KD support. // #define KD_RETRY_COUNT 16 #define KD_PACKET_LEADER 0x30303030 #define KD_CONTROL_PACKET_LEADER 0x69696969 #define KD_PACKET_TYPE_KD_DEBUG_IO 3 #define KD_PACKET_TYPE_KD_RESEND 5 // Packet-control type #define KD_PACKET_TYPE_KD_RESET 6 // Packet-control type #define KD_API_PRINT_STRING 0x00003230 typedef struct _KD_PACKET { UINT32 PacketLeader; UINT16 PacketType; UINT16 ByteCount; UINT32 PacketId; UINT32 Checksum; } KD_PACKET, *PKD_PACKET; typedef struct _KD_PRINT_STRING { UINT32 LengthOfString; } KD_PRINT_STRING, *PKD_PRINT_STRING; typedef struct _KD_GET_STRING { UINT32 LengthOfPromptString; UINT32 LengthOfStringRead; } KD_GET_STRING, *PKD_GET_STRING; typedef struct _KD_DEBUG_IO { UINT32 ApiNumber; UINT16 ProcessorLevel; UINT16 Processor; union { KD_PRINT_STRING PrintString; KD_GET_STRING GetString; } u1; } KD_DEBUG_IO, *PKD_DEBUG_IO; extern UINT8 BlSingularityOhci1394Buffer[3 * PAGE_SIZE]; extern UINT8 BlKdComPort; extern UINT32 BlKdNextPacketId; VOID BlKdInitialize( VOID ); VOID BlKdSpin( VOID ); BOOLEAN BlKdPrintString( PCSTR String ); BOOLEAN BlKdPrintf( PCSTR Format, ... ); UINT32 BlKdComputeChecksum( PCVOID Buffer, UINT32 Length ); BOOLEAN BlKd1394Connect( VOID ); BOOLEAN BlKd1394SendPacket( UINT16 PacketType, PCVOID Header, UINT16 HeaderSize, PCVOID Data, UINT16 DataSize ); BOOLEAN BlKdComConnect( VOID ); BOOLEAN BlKdComSendPacket( UINT16 PacketType, PCVOID Header, UINT16 HeaderSize, PCVOID Data, UINT16 DataSize ); // // System memory map (SMAP) support. // #define BL_SMAP_AVAILABLE 1 #define BL_SMAP_RESERVED 2 #define BL_SMAP_ACPI_RECLAIM 3 #define BL_SMAP_ACPI_NVS 4 #define BL_SMAP_UNUSABLE 5 #define BL_SMAP_KERNEL_NONGC 6 #define BL_SMAP_KERNEL_STACK 7 typedef struct _BL_SMAP_ENTRY { UINT64 Base; UINT64 Size; UINT32 Type; UINT32 ExtendedAttributes; } BL_SMAP_ENTRY, *PBL_SMAP_ENTRY; #define BL_MAX_SMAP_ENTRIES 128 typedef struct _BL_SMAP { BL_SMAP_ENTRY Entry[BL_MAX_SMAP_ENTRIES]; UINT32 EntryCount; } BL_SMAP, *PBL_SMAP; extern BL_SMAP BlSystemMemoryMap; VOID BlSmapInitialize( VOID ); // // Pool support. // VOID BlPoolInitialize( VOID ); PVOID BlPoolAllocateBlock( UINT32 Size ); VOID BlPoolFreeBlock( PVOID P ); // // PNP BIOS support. // #pragma pack(1) typedef struct _PNP_INSTALLATION_CHECK { CHAR Signature[4]; UINT8 Version; UINT8 Length; UINT16 ControlField; UINT8 Checksum; UINT32 EventNotificationFlagAddress; UINT16 RealModeCodeOffset16; UINT16 RealModeCodeSegment16; UINT16 ProtectedModeCodeOffset16; UINT32 ProtectedModeCodeSegmentBase32; UINT32 OEMDeviceId; UINT16 RealModeDataSegment16; UINT32 ProtectedModeDataSegmentBase32; } PNP_INSTALLATION_CHECK, *PPNP_INSTALLATION_CHECK; C_ASSERT(sizeof(PNP_INSTALLATION_CHECK) == 0x21); typedef struct _PNP_SYSTEM_DEVICE_NODE { UINT16 Size; UINT8 Handle; UINT32 ProductId; UINT8 DeviceTypeCode[3]; UINT16 DeviceNodeAttributes; } PNP_SYSTEM_DEVICE_NODE, *PPNP_SYSTEM_DEVICE_NODE; typedef struct _PNP_ISA_CONFIGURATION { UINT8 Revision; UINT8 NumberOfCardSelectNumbers; UINT16 DataReadPort; UINT16 Reserved; } PNP_ISA_CONFIGURATION, *PPNP_ISA_CONFIGURATION; #pragma pack() extern PPNP_SYSTEM_DEVICE_NODE BlPnpSystemDeviceNodeList; extern UINT32 BlPnpSystemDeviceNodeListSize; extern PNP_ISA_CONFIGURATION BlPnpIsaConfiguration; VOID BlPnpInitialize( VOID ); // // PCI support. // typedef struct _PCI_INSTALLATION_CHECK { UINT32 Eax; UINT32 Ebx; UINT32 Ecx; UINT32 Edx; UINT8 HardwareCharacteristics; UINT8 MajorVersion; UINT8 MinorVersion; UINT8 LastBusNumber; UINT32 ProtectedModeEntryPoint; } PCI_INSTALLATION_CHECK, *PPCI_INSTALLATION_CHECK; extern PCI_INSTALLATION_CHECK BlPciInstallationCheck; extern UINT32 BlPciOhci1394BaseAddress; VOID BlPciInitialize( VOID ); // // ACPI support. // extern UINT32 BlAcpiNumberOfProcessors; extern PVOID BlAcpiRsdpAddress; VOID BlAcpiInitialize( VOID ); VOID BlAcpiResetSystem( VOID ); // // Segment management. // #define NULL_SELECTOR 0x0000 #define RM_VIDEO_SELECTOR 0x0008 #define RM_CODE_SELECTOR 0x0010 #define RM_DATA_SELECTOR 0x0018 #define PM_CODE_SELECTOR 0x0020 #define PM_DATA_SELECTOR 0x0028 #define LM_CODE_SELECTOR 0x0030 #define LM_DATA_SELECTOR 0x0038 #define UM_CODE_SELECTOR 0x0040 #define UM_DATA_SELECTOR 0x0048 #define PROCESSOR_SELECTOR 0x0050 #define UNUSED_SELECTOR 0x0058 #define TSS_SELECTOR 0x0060 typedef struct _CODE_SEGMENT { UINT64 Limit_15_0:16; UINT64 Base_23_0:24; UINT64 Accessed:1; UINT64 Readable:1; UINT64 Conforming:1; UINT64 Code:1; UINT64 S:1; UINT64 Dpl:2; UINT64 Present:1; UINT64 Limit_19_16:4; UINT64 Unused:1; UINT64 Long:1; UINT64 Default:1; UINT64 Granularity:1; UINT64 Base_31_24:8; } CODE_SEGMENT, *PCODE_SEGMENT; typedef struct _DATA_SEGMENT { UINT64 Limit_15_0:16; UINT64 Base_23_0:24; UINT64 Accessed:1; UINT64 Writable:1; UINT64 Expansion:1; UINT64 Code:1; UINT64 S:1; UINT64 Dpl:2; UINT64 Present:1; UINT64 Limit_19_16:4; UINT64 Unused:1; UINT64 Reserved:1; UINT64 Big:1; UINT64 Granularity:1; UINT64 Base_31_24:8; } DATA_SEGMENT, *PDATA_SEGMENT; #define SSDT_AVAILABLE_TSS 0x09 #define SSDT_BUSY_TSS 0x0B typedef struct _SYSTEM_SEGMENT { UINT64 Limit_15_0:16; UINT64 Base_23_0:24; UINT64 Type:4; UINT64 S:1; UINT64 Dpl:2; UINT64 Present:1; UINT64 Limit_19_16:4; UINT64 Unused:1; UINT64 Reserved1:2; UINT64 Granularity:1; UINT64 Base_31_24:8; #if defined(BOOT_X64) UINT64 Base_63_32:32; UINT64 Reserved2:32; #endif } SYSTEM_SEGMENT, *PSYSTEM_SEGMENT; #pragma pack(1) typedef struct _GDTR { UINT16 Limit; UINT64 Base; } GDTR, *PGDTR; C_ASSERT(sizeof(GDTR) == 10); typedef struct _IDTR { UINT16 Limit; UINT64 Base; } IDTR, *PIDTR; C_ASSERT(sizeof(IDTR) == 10); #pragma pack() extern GDTR BlMmInitialGdtr; ULONG_PTR BlMmGetCr3( VOID ); VOID BlMmSetCr3( ULONG_PTR Value ); VOID BlFakeSKINIT( ULONG_PTR Value ); VOID BlRealSKINIT( ULONG_PTR Value ); #if defined(BOOT_X86) UINT16 BlMmGetFs( VOID ); VOID BlMmSetFs( UINT16 Value ); #elif defined(BOOT_X64) UINT16 BlMmGetGs( VOID ); VOID BlMmSetGs( UINT16 Value ); #endif VOID BlMmSwitchStack( PVOID Stack, PVOID Function ); VOID BlMmGetGdtr( PGDTR Gdtr ); VOID BlMmSetGdtr( PGDTR Gdtr ); VOID BlMmInitializeCodeSegment( PCODE_SEGMENT CodeSegment ); VOID BlMmInitializeDataSegment( PDATA_SEGMENT DataSegment, UINT32 Base, UINT32 Limit ); VOID BlMmInitializeSystemSegment( PSYSTEM_SEGMENT SystemSegment, UINT32 Type, ULONG_PTR Base, UINT32 Limit ); // // Memory management. // #define PAGE_PRESENT ((UINT64) 0x01) #define PAGE_WRITEABLE ((UINT64) 0x02) #define PAGE_WRITETHROUGH ((UINT64) 0x08) #define PAGE_CACHEDISABLE ((UINT64) 0x10) #define PAGE_ACCESSED ((UINT64) 0x20) #define PAGE_2MB ((UINT64) 0x80) #define BL_MM_PHYSICAL_REGION_MIN_TYPE 0x00000001 #define BL_MM_PHYSICAL_REGION_FREE 0x00000001 #define BL_MM_PHYSICAL_REGION_BIOS 0x00000002 #define BL_MM_PHYSICAL_REGION_BOOT_LOADER 0x00000003 #define BL_MM_PHYSICAL_REGION_SMAP_RESERVED 0x00000004 #define BL_MM_PHYSICAL_REGION_DISTRO 0x00000005 #define BL_MM_PHYSICAL_REGION_KERNEL_IMAGE 0x00000006 #define BL_MM_PHYSICAL_REGION_NATIVE_PLATFORM 0x00000007 #define BL_MM_PHYSICAL_REGION_NATIVE_PROCESSOR 0x00000008 #define BL_MM_PHYSICAL_REGION_LOG_RECORD 0x00000009 #define BL_MM_PHYSICAL_REGION_LOG_TEXT 0x0000000A #define BL_MM_PHYSICAL_REGION_KERNEL_STACK 0x0000000B #define BL_MM_PHYSICAL_REGION_CONTEXT 0x0000000C #define BL_MM_PHYSICAL_REGION_TASK 0x0000000D #define BL_MM_PHYSICAL_REGION_SINGULARITY 0x0000000E #define BL_MM_PHYSICAL_REGION_BOOT_STACK 0x0000000F #define BL_MM_PHYSICAL_REGION_SINGULARITY_SMAP 0x00000010 #define BL_MM_PHYSICAL_REGION_MAX_TYPE 0x00000010 #define BL_MM_BIOS_SIZE (1024 * 1024) typedef struct _BL_MM_PHYSICAL_REGION { LIST_ENTRY Entry; UINT64 Start; UINT64 Size; UINT64 Limit; UINT32 Type; } BL_MM_PHYSICAL_REGION, *PBL_MM_PHYSICAL_REGION; extern ULONG_PTR BlMmBootCr3; VOID BlMmEnableA20Gate( VOID ); VOID BlMmInitializeSystem( VOID ); PCHAR BlMmPhysicalRegionTypeString( UINT32 Type ); UINT64 BlMmAllocatePhysicalRegion( UINT32 Size, UINT32 Type ); BOOLEAN BlMmAllocateSpecificPhysicalRegion( UINT64 Base, UINT64 Size, UINT32 Type ); BOOLEAN BlMmFindFreePhysicalRegion( PUINT64 Base, PUINT64 Size ); BOOLEAN BlMmGetNextPhysicalRegion( PVOID *Handle, PUINT64 Base, PUINT64 Size, PUINT32 Type ); VOID BlMmDumpPhysicalRegionList( VOID ); VOID BlMmMapVirtualPage( PVOID VirtualAddress, PVOID PhysicalAddress, BOOLEAN Writeable, BOOLEAN Cacheable, BOOLEAN WriteThrough ); VOID BlMmMapVirtualRange( PVOID VirtualAddress, PVOID PhysicalAddress, ULONG_PTR Size, BOOLEAN Writeable, BOOLEAN Cacheable, BOOLEAN WriteThrough ); extern PVOID BlMmExtendedBiosDataArea; // // File system support. // extern BOOLEAN (*BlFsGetFileSize)( PCSTR Path, PUINT32 FileSize ); extern BOOLEAN (*BlFsReadFile)( PCSTR Path, PVOID Buffer, UINT32 NumberOfBytes ); // // CDROM support. // VOID BlCdInitialize( UINT8 DriveId ); // // FAT support. // #define MBR_FAT32LBA 0x0C #define MBR_FAT16LBA 0x0E VOID BlFatInitialize( UINT8 DriveId, UINT8 FatType ); // // Flash support. // VOID BlFlashInitialize( PVOID SearchBegin, PVOID SearchLimit ); // // PXE support. // VOID BlPxeInitialize( VOID ); // // PE/COFF support. // VOID BlPeGetVirtualRange( PVOID Image, PVOID *VirtualBase, ULONG_PTR *VirtualSize ); VOID BlPeLoadImage( PVOID LoadBase, UINT32 ImageSize, PVOID Image, PVOID *EntryPoint, BOOLEAN isSLB ); // // RTC support. // typedef struct _BL_TIME { UINT32 Year; UINT8 Month; UINT8 Day; UINT8 Hour; UINT8 Minute; UINT8 Second; } BL_TIME, *PBL_TIME; VOID BlRtlGetCurrentTime( PBL_TIME Time ); extern BL_TIME BlStartTime; // // MPS support. // VOID BlMpsInitialize( VOID ); extern PVOID BlMpsFps; // // VESA Support. // BOOLEAN BlVesaInitialize( VOID ); extern ULONG_PTR BlVesaVideoBuffer; // // Call stack support. // #if defined(BOOT_X86) PVOID BlRtlGetEbp( VOID ); #elif defined(BOOT_X64) PVOID BlRtlGetRbp( VOID ); #endif VOID BlRtlCaptureCallStack( PVOID *FrameArray, UINT32 FrameCount ); // // Trap Support. // typedef struct _BL_TRAP_CONTEXT { #if defined(BOOT_X86) UINT32 Cr2; UINT32 Esp; UINT32 Ebp; UINT32 Edi; UINT32 Esi; UINT32 Edx; UINT32 Ecx; UINT32 Ebx; UINT32 Eax; UINT32 Num; UINT32 Err; UINT32 Eip; UINT32 Cs0; UINT32 Efl; #elif defined (BOOT_X64) UINT64 Cr2; UINT64 Rsp; UINT64 R15; UINT64 R14; UINT64 R13; UINT64 R12; UINT64 R11; UINT64 R10; UINT64 R9; UINT64 R8; UINT64 Rbp; UINT64 Rdi; UINT64 Rsi; UINT64 Rdx; UINT64 Rcx; UINT64 Rbx; UINT64 Rax; UINT64 Num; UINT64 Err; UINT64 Rip; UINT64 Cs0; UINT64 Rfl; #endif } BL_TRAP_CONTEXT, *PBL_TRAP_CONTEXT; typedef struct _IDTE { UINT16 Offset0To15; UINT16 Selector; UINT8 Flags; UINT8 Access; UINT16 Offset16To31; #if defined(BOOT_X64) UINT32 Offset32To63; UINT32 Reserved; #endif } IDTE, *PIDTE; VOID BlTrapEnable( VOID ); VOID BlTrapEnter( VOID ); VOID BlTrapFatal( UINT32 Trap, PBL_TRAP_CONTEXT Context ); VOID BlTrapSetIdtr( PIDTR Idtr ); // // Singularity bridge. // extern PWCHAR BlCommandLine; VOID BlSingularityInitialize( UINT32 NumberOfProcessors, PFAR_POINTER ApEntry16, PFAR_POINTER ApStartupLock ); VOID BlSingularityApEntry( VOID ); extern "C" void * _ReturnAddress(void); #pragma intrinsic(_ReturnAddress) ================================================ FILE: ironclad-apps/src/Checked/BootLoader/SingLdrPc/bl.inc ================================================ ;++ ; ; Copyright (c) Microsoft Corporation ; ; Module Name: ; ; bl.inc ; ; Abstract: ; ; This module contains definitions for the boot loader. ; ; Environment: ; ; Boot loader. ; ;-- ; ; Boot sources. ; CD_BOOT equ 00001h FAT16_BOOT equ 00002h FAT32_BOOT equ 00003h PXE_BOOT equ 00004h FLASH_BOOT equ 00005h ; ; Segment selectors. ; NULL_SELECTOR equ 000h RM_VIDEO_SELECTOR equ 008h RM_CODE_SELECTOR equ 010h RM_DATA_SELECTOR equ 018h PM_CODE_SELECTOR equ 020h PM_DATA_SELECTOR equ 028h LM_CODE_SELECTOR equ 030h LM_DATA_SELECTOR equ 038h UM_CODE_SELECTOR equ 040h UM_DATA_SELECTOR equ 048h PROCESSOR_SELECTOR equ 050h UNUSED_SELECTOR equ 058h TSS_SELECTOR equ 060h ; ; CR0 flags. ; CR0_PE equ 000000001h CR0_NE equ 000000020h CR0_PG equ 080000000h ; ; CR4 flags. ; CR4_PSE equ 000000010h CR4_PAE equ 000000020h CR4_PCE equ 000000100h CR4_OSFXSR equ 000000200h ; ; Initial stack pointer values. ; RM_INITIAL_SS equ 01000h RM_INITIAL_SP equ 0FFF8h PM_INITIAL_ESP equ 000020000h BL_ENTRY_SP equ 000080000h ; ; Page table addresses. ; LM_PML4T_ADDRESS equ 000021000h PM_PDPT_ADDRESS equ 000022000h PM_PDT_ADDRESS equ 000023000h ; ; Page table entry flags. ; PTE_PRESENT equ 000000001h PTE_WRITEABLE equ 000000002h PTE_ACCESSED equ 000000020h PTE_2MB equ 000000080h ; ; EFER MSR index. (Long Mode) ; EFER_MSR_INDEX equ 0C0000080h ; ; EFER flags. (Long Mode) ; EFER_LME equ 000000100h EFER_NXE equ 000000800h ; ; Image target address. ; IMAGE_ADDRESS equ 000040000h ; ; Boot environment block (BEB). ; BEB_BASE equ 00002F000h BEB_SEG16 equ 02F00h BEB_OFF16 equ 00000h BEB struct BootType dd ? BootDriveNumber dd ? FlashImage dd ? SmapAddr dd ? SmapSize dd ? LegacyCallAddress dd ? LegacyReturnAddress dd ? LegacyReturnCr3 dd ? LegacyCall_OpCode dd ? LegacyCall_Vector dd ? LegacyCall_eax dd ? LegacyCall_ebx dd ? LegacyCall_ecx dd ? LegacyCall_edx dd ? LegacyCall_esi dd ? LegacyCall_edi dd ? LegacyCall_ds dd ? LegacyCall_es dd ? LegacyCall_eflags dd ? LegacyCall_FramePtr dd ? LegacyCall_FrameSize dd ? LegacyCall_FuncPtr dd ? ApEntry16 dd ? ApEntry dd ? ApStartupLock dd ? BEB ends ; ; Trap Context ; BL_TRAP_CONTEXT struct ifdef BOOT_X86 TrapCr2 dd ? TrapEsp dd ? TrapEbp dd ? TrapEdi dd ? TrapEsi dd ? TrapEdx dd ? TrapEcx dd ? TrapEbx dd ? TrapEax dd ? TrapNum dd ? TrapErr dd ? TrapEip dd ? TrapCs0 dd ? TrapEfl dd ? endif ifdef BOOT_X64 TrapCr2 dq ? TrapRsp dq ? TrapR15 dq ? TrapR14 dq ? TrapR13 dq ? TrapR12 dq ? TrapR11 dq ? TrapR10 dq ? TrapR09 dq ? TrapR08 dq ? TrapRbp dq ? TrapRdi dq ? TrapRsi dq ? TrapRdx dq ? TrapRcx dq ? TrapRbx dq ? TrapRax dq ? TrapNum dq ? TrapErr dq ? TrapRip dq ? TrapCs0 dq ? TrapRfl dq ? endif BL_TRAP_CONTEXT ends ; ; Legacy call opcodes. ; LC_NOP equ 00000h LC_INTXX equ 00001h LC_FARCALL equ 00002h ; ; PE/COFF structures. ; ; ; typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header ; WORD e_magic; // Magic number ; WORD e_cblp; // Bytes on last page of file ; WORD e_cp; // Pages in file ; WORD e_crlc; // Relocations ; WORD e_cparhdr; // Size of header in paragraphs ; WORD e_minalloc; // Minimum extra paragraphs needed ; WORD e_maxalloc; // Maximum extra paragraphs needed ; WORD e_ss; // Initial (relative) SS value ; WORD e_sp; // Initial SP value ; WORD e_csum; // Checksum ; WORD e_ip; // Initial IP value ; WORD e_cs; // Initial (relative) CS value ; WORD e_lfarlc; // File address of relocation table ; WORD e_ovno; // Overlay number ; WORD e_res[4]; // Reserved words ; WORD e_oemid; // OEM identifier (for e_oeminfo) ; WORD e_oeminfo; // OEM information; e_oemid specific ; WORD e_res2[10]; // Reserved words ; LONG e_lfanew; // File address of new exe header ; } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; ; IDH_NT_HEADER_OFFSET equ 00000003Ch ; ; typedef struct _IMAGE_FILE_HEADER { ; WORD Machine; ; WORD NumberOfSections; ; DWORD TimeDateStamp; ; DWORD PointerToSymbolTable; ; DWORD NumberOfSymbols; ; WORD SizeOfOptionalHeader; ; WORD Characteristics; ; } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; ; IFH_NUMBER_OF_SECTIONS equ 000000002h IFH_SIZE_OF_OPTIONAL_HEADER equ 000000010h ifdef BOOT_X86 ; ; typedef struct _IMAGE_OPTIONAL_HEADER32 { ; WORD Magic; ; BYTE MajorLinkerVersion; ; BYTE MinorLinkerVersion; ; DWORD SizeOfCode; ; DWORD SizeOfInitializedData; ; DWORD SizeOfUninitializedData; ; DWORD AddressOfEntryPoint; ; DWORD BaseOfCode; ; DWORD BaseOfData; ; DWORD ImageBase; ; DWORD SectionAlignment; ; DWORD FileAlignment; ; WORD MajorOperatingSystemVersion; ; WORD MinorOperatingSystemVersion; ; WORD MajorImageVersion; ; WORD MinorImageVersion; ; WORD MajorSubsystemVersion; ; WORD MinorSubsystemVersion; ; DWORD Win32VersionValue; ; DWORD SizeOfImage; ; DWORD SizeOfHeaders; ; DWORD CheckSum; ; WORD Subsystem; ; WORD DllCharacteristics; ; DWORD SizeOfStackReserve; ; DWORD SizeOfStackCommit; ; DWORD SizeOfHeapReserve; ; DWORD SizeOfHeapCommit; ; DWORD LoaderFlags; ; DWORD NumberOfRvaAndSizes; ; IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; ; } IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32; ; IOH32_IMAGE_BASE equ 00000001Ch endif ifdef BOOT_X64 ; ; typedef struct _IMAGE_OPTIONAL_HEADER64 { ; WORD Magic; ; BYTE MajorLinkerVersion; ; BYTE MinorLinkerVersion; ; DWORD SizeOfCode; ; DWORD SizeOfInitializedData; ; DWORD SizeOfUninitializedData; ; DWORD AddressOfEntryPoint; ; DWORD BaseOfCode; ; ULONGLONG ImageBase; ; DWORD SectionAlignment; ; DWORD FileAlignment; ; WORD MajorOperatingSystemVersion; ; WORD MinorOperatingSystemVersion; ; WORD MajorImageVersion; ; WORD MinorImageVersion; ; WORD MajorSubsystemVersion; ; WORD MinorSubsystemVersion; ; DWORD Win32VersionValue; ; DWORD SizeOfImage; ; DWORD SizeOfHeaders; ; DWORD CheckSum; ; WORD Subsystem; ; WORD DllCharacteristics; ; ULONGLONG SizeOfStackReserve; ; ULONGLONG SizeOfStackCommit; ; ULONGLONG SizeOfHeapReserve; ; ULONGLONG SizeOfHeapCommit; ; DWORD LoaderFlags; ; DWORD NumberOfRvaAndSizes; ; IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; ; } IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64; ; IOH64_IMAGE_BASE equ 000000018h endif IOH_ADDRESS_OF_ENTRY_POINT equ 000000010h IOH_SIZE_OF_HEADERS equ 00000003Ch ; ; typedef struct _IMAGE_NT_HEADERS32/64 { ; DWORD Signature; ; IMAGE_FILE_HEADER FileHeader; ; IMAGE_OPTIONAL_HEADER32/64 OptionalHeader; ; } IMAGE_NT_HEADERS32/64, *PIMAGE_NT_HEADERS32/64; ; INH_SIGNATURE equ 000000000h INH_FILE_HEADER equ 000000004h INH_OPTIONAL_HEADER equ 000000018h ; ; Signatures. ; IMAGE_DOS_SIGNATURE equ 05A4Dh ; MZ IMAGE_NT_SIGNATURE equ 000004550h ; PE00 ; ; typedef struct _IMAGE_SECTION_HEADER { ; BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; ; union { ; DWORD PhysicalAddress; ; DWORD VirtualSize; ; } Misc; ; DWORD VirtualAddress; ; DWORD SizeOfRawData; ; DWORD PointerToRawData; ; DWORD PointerToRelocations; ; DWORD PointerToLinenumbers; ; WORD NumberOfRelocations; ; WORD NumberOfLinenumbers; ; DWORD Characteristics; ; } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; ; ISH_VIRTUAL_SIZE equ 000000008h ISH_VIRTUAL_ADDRESS equ 00000000Ch ISH_SIZE_OF_RAW_DATA equ 000000010h ISH_POINTER_TO_RAW_DATA equ 000000014h IMAGE_SECTION_HEADER_SIZE equ 000000028h ================================================ FILE: ironclad-apps/src/Checked/BootLoader/SingLdrPc/blacpi.cpp ================================================ //++ // // Copyright (c) Microsoft Corporation // // Module Name: // // blacpi.cpp // // Abstract: // // This module implements ACPI support for the boot loader environment. // // Environment: // // Boot loader. // //-- #include "bl.h" #pragma pack(1) // // Generic Address Structure (GAS) // #define ACPI_GAS_MEMORY 0 #define ACPI_GAS_IO 1 #define ACPI_GAS_PCI 2 #define ACPI_GAS_ACCESS_SIZE_UNDEFINED 0 #define ACPI_GAS_ACCESS_SIZE_BYTE 1 #define ACPI_GAS_ACCESS_SIZE_WORD 2 #define ACPI_GAS_ACCESS_SIZE_DWORD 3 #define ACPI_GAS_ACCESS_SIZE_QWORD 4 typedef struct _ACPI_GAS { UINT8 AddressSpaceId; UINT8 RegisterBitWidth; UINT8 RegisterBitOffset; UINT8 AccessSize; UINT64 Address; } ACPI_GAS, *PACPI_GAS; C_ASSERT(sizeof(ACPI_GAS) == 12); // // Root System Description Pointer (RSDP) // typedef struct _ACPI_RSDP { CHAR Signature[8]; UINT8 Checksum; CHAR OemId[6]; UINT8 Revision; UINT32 RsdtAddress; UINT32 Length; UINT64 XsdtAddress; UINT8 ExtendedChecksum; UINT8 Reserved[3]; } ACPI_RSDP, *PACPI_RSDP; C_ASSERT(sizeof(ACPI_RSDP) == 36); // // Root System Description Table (RSDT) // typedef struct _ACPI_RSDT { UINT8 Signature[4]; UINT32 Length; UINT8 Revision; UINT8 Checksum; UINT8 OemId[6]; UINT8 OemTableId[8]; UINT32 OemRevision; UINT32 CreatorId; UINT32 CreatorRevision; UINT32 Entry[]; } ACPI_RSDT, *PACPI_RSDT; C_ASSERT(sizeof(ACPI_RSDT) == 36); // // Multiple APIC Description Table (MADT) // typedef struct _ACPI_MADT { UINT8 Signature[4]; UINT32 Length; UINT8 Revision; UINT8 Checksum; UINT8 OemId[6]; UINT8 OemTableId[8]; UINT32 OemRevision; UINT32 CreatorId; UINT32 CreatorRevision; UINT32 LocalApicAddress; UINT32 Flags; UINT8 ApicStructures[]; } ACPI_MADT, *PACPI_MADT; C_ASSERT(sizeof(ACPI_MADT) == 44); #define ACPI_APIC_TYPE_PROCESSOR_LOCAL 0 typedef struct _ACPI_MADT_ENTRY { UINT8 Type; UINT8 Length; } ACPI_MADT_ENTRY, *PACPI_MADT_ENTRY; typedef struct _ACPI_PROCESSOR_LOCAL_APIC { UINT8 Type; UINT8 Length; UINT8 AcpiProcessorId; UINT8 ApicId; union { struct { UINT32 Enabled:1; UINT32 Reserved:31; } s1; UINT32 Flags; } u1; } ACPI_PROCESSOR_LOCAL_APIC, *PACPI_PROCESSOR_LOCAL_APIC; C_ASSERT(sizeof(ACPI_PROCESSOR_LOCAL_APIC) == 8); // //System Resource Affinity Table (SRAT) // typedef struct _ACPI_SRAT { UINT8 Signature[4]; UINT32 Length; UINT8 Revision; UINT8 Checksum; UINT8 OemId[6]; UINT8 OemTableId[8]; UINT32 OemRevision; UINT32 CreatorId; UINT32 CreatorRevision; UINT8 Reserved[12]; UINT8 SratStructures[]; } ACPI_SRAT, *PACPI_SRAT; C_ASSERT(sizeof(ACPI_SRAT) == 48); #define ACPI_SRAT_TYPE_PROC_AFFINITY_ENTRY 0 #define ACPI_SRAT_TYPE_MEM_AFFINITY_ENTRY 1 typedef ACPI_MADT_ENTRY ACPI_SRAT_ENTRY; typedef PACPI_MADT_ENTRY PACPI_SRAT_ENTRY; typedef struct _ACPI_SRAT_PROC_AFFINITY_ENTRY { UINT8 Type; UINT8 Length; UINT8 ProximityDomainLowEightBits; UINT8 ApicID; UINT32 Flags; UINT8 LocalApicEid; UINT8 ProximityDomainHighTwentyFourBits[3]; UINT32 Reserved; } ACPI_SRAT_PROC_AFFINITY_ENTRY, *PACPI_SRAT_PROC_AFFINITY_ENTRY; typedef struct _ACPI_SRAT_MEM_AFFINITY_ENTRY { UINT8 Type; UINT8 Length; UINT32 ProximityDomain; UINT8 Reserved[2]; UINT32 BaseAddressLow; UINT32 BaseAddressHigh; UINT32 LengthLow; UINT32 LengthHigh; UINT32 Reserved2; UINT32 Flags; UINT8 Reserved3[8]; } ACPI_SRAT_MEM_AFFINITY_ENTRY, *PACPI_SRAT_MEM_AFFINITY_ENTRY; // // Fixed ACPI Description Table (FADT) // #define ACPI_FADT_FLAGS_RESET_SUPPORTED 0x400 typedef struct _ACPI_FADT { UINT8 Signature[4]; UINT32 Length; UINT8 Revision; UINT8 Checksum; UINT8 OemId[6]; UINT8 OemTableId[8]; UINT32 OemRevision; UINT32 CreatorId; UINT32 CreatorRevision; UINT8 Data1[112-36]; UINT32 Flags; ACPI_GAS ResetRegister; UINT8 ResetValue; UINT8 Data2[244-129]; } ACPI_FADT, *PACPI_FADT; C_ASSERT(FIELD_OFFSET(ACPI_FADT, Flags) == 112); C_ASSERT(FIELD_OFFSET(ACPI_FADT, ResetRegister) == 116); C_ASSERT(FIELD_OFFSET(ACPI_FADT, ResetValue) == 128); C_ASSERT(sizeof(ACPI_FADT) == 244); #pragma pack() PACPI_FADT BlAcpiFadt; PACPI_MADT BlAcpiMadt; UINT32 BlAcpiNumberOfProcessors; PACPI_RSDP BlAcpiRsdp; PVOID BlAcpiRsdpAddress; PACPI_RSDT BlAcpiRsdt; PACPI_SRAT BlAcpiSrat; PACPI_RSDP BlAcpiLocateRsdp( VOID ) //++ // // Routine Description: // // This function locates the ACPI RSDP structure. // // Return Value: // // ACPI RSDP structure, if located. // NULL, otherwise. // //-- { ULONG_PTR End; PACPI_RSDP Rsdp; ULONG_PTR Start; Start = 0xE0000; End = 0x100000; while (Start < End) { Rsdp = (PACPI_RSDP) Start; if ((Rsdp->Signature[0] == 'R') && (Rsdp->Signature[1] == 'S') && (Rsdp->Signature[2] == 'D') && (Rsdp->Signature[3] == ' ') && (Rsdp->Signature[4] == 'P') && (Rsdp->Signature[5] == 'T') && (Rsdp->Signature[6] == 'R') && (Rsdp->Signature[7] == ' ') && (BlRtlComputeChecksum8(Rsdp, 20) == 0) ) { return Rsdp; } Start += 0x10; } Start = (ULONG_PTR) BlMmExtendedBiosDataArea; End = Start + 0x10000; while (Start < End) { Rsdp = (PACPI_RSDP) Start; if ((Rsdp->Signature[0] == 'R') && (Rsdp->Signature[1] == 'S') && (Rsdp->Signature[2] == 'D') && (Rsdp->Signature[3] == ' ') && (Rsdp->Signature[4] == 'P') && (Rsdp->Signature[5] == 'T') && (Rsdp->Signature[6] == 'R') && (Rsdp->Signature[7] == ' ') && (BlRtlComputeChecksum8(Rsdp, 20) == 0) ) { return Rsdp; } Start += 0x10; } return NULL; } PACPI_RSDT BlAcpiLocateRsdt( PACPI_RSDP Rsdp ) //++ // // Routine Description: // // This function locates the ACPI RSDT structure. // // Arguments: // // Rsdp - Supplies a pointer to the ACPI RSDP structure. // // Return Value: // // ACPI RSDT structure, if located. // NULL, otherwise. // //-- { PACPI_RSDT Rsdt; Rsdt = (PACPI_RSDT) (ULONG_PTR) Rsdp->RsdtAddress; if (Rsdt == NULL) { return NULL; } if ((Rsdt->Signature[0] == 'R') && (Rsdt->Signature[1] == 'S') && (Rsdt->Signature[2] == 'D') && (Rsdt->Signature[3] == 'T') && (Rsdt->Length >= sizeof(ACPI_RSDT)) && (BlRtlComputeChecksum8(Rsdt, Rsdt->Length) == 0)) { return Rsdt; } return NULL; } PACPI_MADT BlAcpiLocateMadt( PACPI_RSDT Rsdt ) //++ // // Routine Description: // // This function locates the ACPI MADT structure. // // Arguments: // // Rsdt - Supplies a pointer to the ACPI RSDT structure. // // Return Value: // // ACPI MADT structure, if located. // NULL, otherwise. // //-- { UINT32 Index; PACPI_MADT Madt; UINT32 NumberOfTables; NumberOfTables = (Rsdt->Length - FIELD_OFFSET(ACPI_RSDT, Entry)) / sizeof(Rsdt->Entry[0]); for (Index = 0; Index < NumberOfTables; Index += 1) { Madt = (PACPI_MADT) (ULONG_PTR) Rsdt->Entry[Index]; if ((Madt->Signature[0] == 'A') && (Madt->Signature[1] == 'P') && (Madt->Signature[2] == 'I') && (Madt->Signature[3] == 'C') && (Madt->Length >= sizeof(ACPI_MADT)) && (BlRtlComputeChecksum8(Madt, Madt->Length) == 0)) { return Madt; } } return NULL; } PACPI_SRAT BlAcpiLocateSrat( PACPI_RSDT Rsdt ) //++ // // Routine Description: // // This function locates the ACPI SRAT structure. // // Arguments: // // Rsdt - Supplies a pointer to the ACPI RSDT structure. // // Return Value: // // ACPI SRAT structure, if located. // NULL, otherwise. // //-- { UINT32 Index; PACPI_SRAT Srat; UINT32 NumberOfTables; NumberOfTables = (Rsdt->Length - FIELD_OFFSET(ACPI_RSDT, Entry)) / sizeof(Rsdt->Entry[0]); for (Index = 0; Index < NumberOfTables; Index += 1) { Srat = (PACPI_SRAT) (ULONG_PTR) Rsdt->Entry[Index]; if ((Srat->Signature[0] == 'S') && (Srat->Signature[1] == 'R') && (Srat->Signature[2] == 'A') && (Srat->Signature[3] == 'T') && (Srat->Length >= sizeof(ACPI_SRAT)) && (BlRtlComputeChecksum8(Srat, Srat->Length) == 0)) { #if ACPI_VERBOSE BlRtlPrintf("ACPI: Found SRAT Table\n"); #endif return Srat; } } return NULL; } VOID BlAcpiDumpSratEntries( VOID ) //++ // // Routine Description: // // This function prints out the SRAT table. //-- { PACPI_SRAT_ENTRY Entry; PCHAR Limit; PACPI_SRAT_PROC_AFFINITY_ENTRY ProcAffinityEntry; PACPI_SRAT_MEM_AFFINITY_ENTRY MemAffinityEntry; PCHAR Next; UINT32 hbits; UINT32 totalbits; if (BlAcpiSrat == NULL) { BlRtlPrintf("ACPI: No Srat??\n"); return; } #if ACPI_VERBOSE BlRtlPrintf("SRAT:\n"); #endif Next = (PCHAR) &BlAcpiSrat->SratStructures[0]; Limit = ((PCHAR) BlAcpiSrat) + BlAcpiSrat->Length; while (Next < Limit) { Entry = (PACPI_SRAT_ENTRY) Next; if ((Entry->Type == ACPI_SRAT_TYPE_PROC_AFFINITY_ENTRY) && (Entry->Length >= sizeof(ACPI_SRAT_PROC_AFFINITY_ENTRY))) { ProcAffinityEntry = (PACPI_SRAT_PROC_AFFINITY_ENTRY) Next; #if ACPI_VERBOSE BlRtlPrintf(" Processor:\n"); #endif hbits = 0; hbits += ProcAffinityEntry->ProximityDomainHighTwentyFourBits[0] << 24; hbits += ProcAffinityEntry->ProximityDomainHighTwentyFourBits[1] << 16; hbits += ProcAffinityEntry->ProximityDomainHighTwentyFourBits[2] << 8; totalbits = hbits | ProcAffinityEntry->ProximityDomainLowEightBits; #if ACPI_VERBOSE BlRtlPrintf(" HighDomain 0x%06x LowDomain 0x%02x totalbits 0x%08x\n", hbits, ProcAffinityEntry->ProximityDomainLowEightBits, totalbits); BlRtlPrintf(" ApicID: %d flags 0x%08x\n", ProcAffinityEntry->ApicID, ProcAffinityEntry->Flags); #endif } else if ((Entry->Type == ACPI_SRAT_TYPE_MEM_AFFINITY_ENTRY) && (Entry->Length >= sizeof(ACPI_SRAT_MEM_AFFINITY_ENTRY))) { MemAffinityEntry = (PACPI_SRAT_MEM_AFFINITY_ENTRY) Next; #if ACPI_VERBOSE BlRtlPrintf(" Memory:\n"); BlRtlPrintf(" BaseAddress 0x%08x.%08x .. 0x%08x.%08x", MemAffinityEntry->BaseAddressHigh, MemAffinityEntry->BaseAddressLow, MemAffinityEntry->LengthHigh, MemAffinityEntry->LengthLow); BlRtlPrintf(" Domain %d Flags 0x%08x\n", MemAffinityEntry->ProximityDomain, MemAffinityEntry->Flags); #endif } Next += Entry->Length; } } UINT32 BlAcpiGetNumberOfProcessors( VOID ) //++ // // Routine Description: // // This function returns the number of processors. // // Return Value: // // Number of processors. // //-- { PACPI_MADT_ENTRY Entry; PCHAR Limit; PACPI_PROCESSOR_LOCAL_APIC LocalApic; PCHAR Next; UINT32 NumberOfProcessors; if (BlAcpiMadt == NULL) { return 1; } Next = (PCHAR) &BlAcpiMadt->ApicStructures[0]; Limit = ((PCHAR) BlAcpiMadt) + BlAcpiMadt->Length; NumberOfProcessors = 0; while (Next < Limit) { Entry = (PACPI_MADT_ENTRY) Next; if ((Entry->Type == ACPI_APIC_TYPE_PROCESSOR_LOCAL) && (Entry->Length >= sizeof(ACPI_PROCESSOR_LOCAL_APIC))) { LocalApic = (PACPI_PROCESSOR_LOCAL_APIC) Next; if (LocalApic->u1.s1.Enabled != FALSE) { #if ACPI_VERBOSE BlRtlPrintf("ACPI: AcpiProcessorId=%u , LocalApicId=%u\n", LocalApic->AcpiProcessorId, LocalApic->ApicId); #endif NumberOfProcessors += 1; } } Next += Entry->Length; } return NumberOfProcessors; } PACPI_FADT BlAcpiLocateFadt( PACPI_RSDT Rsdt ) //++ // // Routine Description: // // This function locates the ACPI FADT structure. // // Arguments: // // Rsdt - Supplies a pointer to the ACPI RSDT structure. // // Return Value: // // ACPI FADT structure, if located. // NULL, otherwise. // //-- { PACPI_FADT Fadt; UINT32 Index; UINT32 NumberOfTables; NumberOfTables = (Rsdt->Length - FIELD_OFFSET(ACPI_RSDT, Entry)) / sizeof(Rsdt->Entry[0]); for (Index = 0; Index < NumberOfTables; Index += 1) { Fadt = (PACPI_FADT) (ULONG_PTR) Rsdt->Entry[Index]; if ((Fadt->Signature[0] == 'F') && (Fadt->Signature[1] == 'A') && (Fadt->Signature[2] == 'C') && (Fadt->Signature[3] == 'P') && (BlRtlComputeChecksum8(Fadt, Fadt->Length) == 0)) { return Fadt; } } return NULL; } VOID BlAcpiResetSystem( VOID ) //++ // // Routine Description: // // This function resets the system through the ACPI reset register. // //-- { if ((BlAcpiFadt->Revision < 2) || (BlAcpiFadt->Length < (FIELD_OFFSET(ACPI_FADT, ResetValue) + sizeof(UINT8))) || ((BlAcpiFadt->Flags & ACPI_FADT_FLAGS_RESET_SUPPORTED) == 0) ) { #if ACPI_VERBOSE BlRtlPrintf("ACPI: Reset register is not supported! [FADT v%u]\n", BlAcpiFadt->Revision); #endif return; } #if ACPI_VERBOSE BlRtlPrintf("ACPI: Reset register type is %u.\n", BlAcpiFadt->ResetRegister.AddressSpaceId); #endif switch (BlAcpiFadt->ResetRegister.AddressSpaceId) { case ACPI_GAS_IO: { BlRtlWritePort8((UINT16) BlAcpiFadt->ResetRegister.Address, BlAcpiFadt->ResetValue); break; } } } VOID BlAcpiInitialize( VOID ) //++ // // Routine Description: // // This function initializes ACPI support for the boot loader. // //-- { BlAcpiRsdp = BlAcpiLocateRsdp(); if (BlAcpiRsdp == NULL) { BlRtlPrintf("ACPI: No RSDP!\n"); BlRtlHalt(); } BlAcpiRsdpAddress = (PVOID) BlAcpiRsdp; BlAcpiRsdt = BlAcpiLocateRsdt(BlAcpiRsdp); if (BlAcpiRsdt == NULL) { BlRtlPrintf("ACPI: No RSDT!\n"); BlRtlHalt(); } BlAcpiFadt = BlAcpiLocateFadt(BlAcpiRsdt); if (BlAcpiFadt == NULL) { BlRtlPrintf("ACPI: No FADT!\n"); //BlRtlHalt(); } BlAcpiMadt = BlAcpiLocateMadt(BlAcpiRsdt); if (BlAcpiMadt == NULL) { BlAcpiNumberOfProcessors = 1; } else { BlAcpiNumberOfProcessors = BlAcpiGetNumberOfProcessors(); } if (BlAcpiNumberOfProcessors == 0) { BlRtlPrintf("ACPI: No local APIC!\n"); BlRtlHalt(); } BlAcpiSrat = BlAcpiLocateSrat(BlAcpiRsdt); if (BlAcpiSrat != NULL) { BlAcpiDumpSratEntries(); } #if ACPI_VERBOSE BlRtlPrintf("ACPI: RSDP @ %p\n" "ACPI: RSDT @ %p\n" "ACPI: FADT @ %p [Revision=%u , Length=%u]\n" "ACPI: MADT @ %p\n" "ACPI: %u processor(s)\n", BlAcpiRsdp, BlAcpiRsdt, BlAcpiFadt, BlAcpiFadt->Revision, BlAcpiFadt->Length, BlAcpiMadt, BlAcpiNumberOfProcessors); #endif // // Map APIC page uncached. // if ((BlAcpiMadt != NULL) && (BlAcpiMadt->LocalApicAddress != 0)) { #if ACPI_VERBOSE BlRtlPrintf("ACPI: APIC mapped @ %p.\n", BlAcpiMadt->LocalApicAddress); #endif BlMmMapVirtualRange((PVOID) (ULONG_PTR) BlAcpiMadt->LocalApicAddress, (PVOID) (ULONG_PTR) BlAcpiMadt->LocalApicAddress, PAGE_SIZE, TRUE, FALSE, FALSE); } } ================================================ FILE: ironclad-apps/src/Checked/BootLoader/SingLdrPc/blcdrom.cpp ================================================ //++ // // Copyright (c) Microsoft Corporation // // Module Name: // // blcdrom.cpp // // Abstract: // // This module implements CDROM support for the boot loader. // //-- #include "bl.h" #define ISO9660_LOGICAL_BLOCK_SIZE 2048 #define ISO9660_ROUND_UP_TO_LOGICAL_BLOCKS(X) (((X) + ISO9660_LOGICAL_BLOCK_SIZE - 1) & (~(ISO9660_LOGICAL_BLOCK_SIZE - 1))) #define ISO9660_VOLUME_SPACE_DATA_AREA_LBN 16 #define ISO9660_VOLUME_DESCRIPTOR_TYPE_BOOT 0x00 #define ISO9660_VOLUME_DESCRIPTOR_TYPE_PRIMARY 0x01 #define ISO9660_VOLUME_DESCRIPTOR_TYPE_SUPPLEMENTARY 0x02 #define ISO9660_VOLUME_DESCRIPTOR_TYPE_TERMINATOR 0xFF #define ISO9660_MAX_PATH 255 #pragma pack(1) typedef struct _ISO9660_LOGICAL_BLOCK { UINT8 Data[ISO9660_LOGICAL_BLOCK_SIZE]; } ISO9660_LOGICAL_BLOCK, *PISO9660_LOGICAL_BLOCK; C_ASSERT(sizeof(ISO9660_LOGICAL_BLOCK) == ISO9660_LOGICAL_BLOCK_SIZE); typedef struct _ISO9660_DIRECTORY_RECORD { UINT8 DirectoryRecordLength; UINT8 ExtendedAttributeRecordLength; UINT32 ExtentLocation; UINT32 ExtentLocation_BigEndian; UINT32 DataLength; UINT32 DataLength_BigEndian; UINT8 RecordingDateTime[7]; union { struct { UINT8 Present:1; UINT8 Directory:1; UINT8 AssociatedFile:1; UINT8 Record:1; UINT8 Protection:1; UINT8 Reserved:2; UINT8 MultiExtent:1; } s1; UINT8 FileFlags; } u1; UINT8 FileUnitSize; UINT8 InterleaveGapSize; UINT16 VolumeSequenceNumber; UINT16 VolumeSequenceNumber_BigEndian; UINT8 FileIdentifierLength; UINT8 FileIdentifier[1]; } ISO9660_DIRECTORY_RECORD, *PISO9660_DIRECTORY_RECORD; C_ASSERT(sizeof(ISO9660_DIRECTORY_RECORD) == 34); typedef struct _ISO9660_PRIMARY_VOLUME_DESCRIPTOR { UINT8 VolumeDescriptorType; UINT8 StandardIdentifier[5]; UINT8 VolumeDescriptorVersion; UINT8 Reserved1; UINT8 SystemIdentifier[32]; UINT8 VolumeIdentifier[32]; UINT8 Reserved2[8]; UINT32 VolumeSpaceSize; UINT32 VolumeSpaceSize_BigEndian; UINT8 Reserved3[32]; UINT16 VolumeSetSize; UINT16 VolumeSetSize_BigEndian; UINT16 VolumeSequenceNumber; UINT16 VolumeSequenceNumber_BigEndian; UINT16 LogicalBlockSize; UINT16 LogicalBlockSize_BigEndian; UINT32 PathTableSize; UINT32 PathTableSize_BigEndian; UINT32 PathTableLocation[2]; UINT32 PathTableLocation_BigEndian[2]; ISO9660_DIRECTORY_RECORD RootDirectory; UINT8 VolumeSetIdentifier[128]; UINT8 PublisherIdentifier[128]; UINT8 DataPreparerIdentifier[128]; UINT8 ApplicationIdentifier[128]; UINT8 CopyrightFileIdentifier[37]; UINT8 AbstractFileIdentifier[37]; UINT8 BibliographicFileIdentifier[37]; UINT8 VolumeCreationDateTime[17]; UINT8 VolumeModificationDateTime[17]; UINT8 VolumeExpirationDateTime[17]; UINT8 VolumeEffectiveDateTime[17]; UINT8 FileStructureVersion; UINT8 Reserved4; UINT8 ReservedForApplication[512]; UINT8 Reserved5[653]; } ISO9660_PRIMARY_VOLUME_DESCRIPTOR, *PISO9660_PRIMARY_VOLUME_DESCRIPTOR; C_ASSERT(sizeof(ISO9660_PRIMARY_VOLUME_DESCRIPTOR) == ISO9660_LOGICAL_BLOCK_SIZE); typedef struct _ISO9660_SUPPLEMENTARY_VOLUME_DESCRIPTOR { UINT8 VolumeDescriptorType; UINT8 StandardIdentifier[5]; UINT8 VolumeDescriptorVersion; UINT8 VolumeFlags; UINT8 SystemIdentifier[32]; UINT8 VolumeIdentifier[32]; UINT8 Reserved2[8]; UINT32 VolumeSpaceSize; UINT32 VolumeSpaceSize_BigEndian; UINT8 EscapeSequences[32]; UINT16 VolumeSetSize; UINT16 VolumeSetSize_BigEndian; UINT16 VolumeSequenceNumber; UINT16 VolumeSequenceNumber_BigEndian; UINT16 LogicalBlockSize; UINT16 LogicalBlockSize_BigEndian; UINT32 PathTableSize; UINT32 PathTableSize_BigEndian; UINT32 PathTableLocation[2]; UINT32 PathTableLocation_BigEndian[2]; ISO9660_DIRECTORY_RECORD RootDirectory; UINT8 VolumeSetIdentifier[128]; UINT8 PublisherIdentifier[128]; UINT8 DataPreparerIdentifier[128]; UINT8 ApplicationIdentifier[128]; UINT8 CopyrightFileIdentifier[37]; UINT8 AbstractFileIdentifier[37]; UINT8 BibliographicFileIdentifier[37]; UINT8 VolumeCreationDateTime[17]; UINT8 VolumeModificationDateTime[17]; UINT8 VolumeExpirationDateTime[17]; UINT8 VolumeEffectiveDateTime[17]; UINT8 FileStructureVersion; UINT8 Reserved4; UINT8 ReservedForApplication[512]; UINT8 Reserved5[653]; } ISO9660_SUPPLEMENTARY_VOLUME_DESCRIPTOR, *PISO9660_SUPPLEMENTARY_VOLUME_DESCRIPTOR; C_ASSERT(sizeof(ISO9660_SUPPLEMENTARY_VOLUME_DESCRIPTOR) == ISO9660_LOGICAL_BLOCK_SIZE); typedef struct _ISO9660_VOLUME_DESCRIPTOR { union { UINT8 VolumeDescriptorType; ISO9660_PRIMARY_VOLUME_DESCRIPTOR Primary; ISO9660_SUPPLEMENTARY_VOLUME_DESCRIPTOR Supplementary; } u1; } ISO9660_VOLUME_DESCRIPTOR, *PISO9660_VOLUME_DESCRIPTOR; C_ASSERT(sizeof(ISO9660_VOLUME_DESCRIPTOR) == ISO9660_LOGICAL_BLOCK_SIZE); #pragma pack() UINT8 BlCdDriveId; INT13_DRIVE_PARAMETERS BlCdDriveParameters; ISO9660_VOLUME_DESCRIPTOR BlCdVolumeDescriptor; ISO9660_LOGICAL_BLOCK BlCdTemporaryBlock[32]; UINT16 BlCdTemporaryBlockCount = sizeof(BlCdTemporaryBlock) / sizeof(BlCdTemporaryBlock[0]); VOID BlCdReadLogicalBlock( UINT32 LogicalBlockNumber, UINT32 NumberOfBlocks, PISO9660_LOGICAL_BLOCK LogicalBlock ) //++ // // Routine Description: // // This function reads the specified logical block. // // Arguments: // // LogicalBlockNumber - Supplies the number of the logical block to read. // // NumberOfBlocks - Supplies the number of blocks to read. // // LogicalBlock - Receives logical block data. // //-- { UINT16 ChunkSize; BOOLEAN Result; while (NumberOfBlocks > 0) { if (NumberOfBlocks < BlCdTemporaryBlockCount) { ChunkSize = (UINT16) NumberOfBlocks; } else { ChunkSize = BlCdTemporaryBlockCount; } Result = BlRtlReadDrive(BlCdDriveId, LogicalBlockNumber, ChunkSize, BlCdTemporaryBlock); if (Result == FALSE) { BlRtlPrintf("CDROM: I/O Error: DriveID=0x%02x LBN=%u Count=%u\n", BlCdDriveId, LogicalBlockNumber, ChunkSize); BlRtlHalt(); } BlRtlCopyMemory(LogicalBlock, BlCdTemporaryBlock, ChunkSize * sizeof(ISO9660_LOGICAL_BLOCK)); LogicalBlockNumber += ChunkSize; LogicalBlock += ChunkSize; NumberOfBlocks -= ChunkSize; } return; } BOOLEAN BlCdFindDirectoryRecord( PCSTR Path, PISO9660_DIRECTORY_RECORD DirectoryRecord ) //++ // // Routine Description: // // This function finds the directory record for the specified path. // // Arguments: // // Path - Supplies the path to look up. // // DirectoryRecord - Receives directory record. // // Return Value: // // TRUE, if directory record was found. // FALSE, otherwise. // //-- { PISO9660_LOGICAL_BLOCK DirectoryData; UINT32 DirectoryDataIndex; ULONG_PTR DirectoryDataLimit; UINT32 DirectoryDataExtentStart; UINT32 DirectoryDataExtentSize; PISO9660_DIRECTORY_RECORD Entry; UINT32 Index; PCSTR NextToken; PCSTR Separator; CHAR Temp[ISO9660_MAX_PATH]; CHAR Token[ISO9660_MAX_PATH]; UINT32 TokenSize; DirectoryDataExtentStart = BlCdVolumeDescriptor.u1.Supplementary.RootDirectory.ExtentLocation; DirectoryDataExtentSize = ROUND_UP_TO_POWER2(BlCdVolumeDescriptor.u1.Supplementary.RootDirectory.DataLength, ISO9660_LOGICAL_BLOCK_SIZE) / ISO9660_LOGICAL_BLOCK_SIZE; NextToken = Path; for (;;) { BLASSERT(DirectoryDataExtentStart > ISO9660_VOLUME_SPACE_DATA_AREA_LBN); BLASSERT(DirectoryDataExtentSize > 0); BLASSERT((*NextToken != 0) && (*NextToken != '/')); Separator = NextToken; while ((*Separator != '/') && (*Separator != 0)) { Separator += 1; } TokenSize = (UINT32) (Separator - NextToken); for (Index = 0; Index < TokenSize; Index += 1) { Token[Index] = BlRtlConvertCharacterToUpperCase(NextToken[Index]); } Token[TokenSize] = 0; DirectoryData = (PISO9660_LOGICAL_BLOCK) BlPoolAllocateBlock(DirectoryDataExtentSize * ISO9660_LOGICAL_BLOCK_SIZE); DirectoryDataLimit = (ULONG_PTR) DirectoryData + (DirectoryDataExtentSize * ISO9660_LOGICAL_BLOCK_SIZE); BlCdReadLogicalBlock(DirectoryDataExtentStart, DirectoryDataExtentSize, DirectoryData); Entry = NULL; for (DirectoryDataIndex = 0; (Entry == NULL) && (DirectoryDataIndex < DirectoryDataExtentSize); DirectoryDataIndex += 1) { Entry = (PISO9660_DIRECTORY_RECORD) &DirectoryData[DirectoryDataIndex]; for (;;) { if (Entry->DirectoryRecordLength == 0) { Entry = NULL; break; } if (Entry->FileIdentifierLength == (TokenSize * 2)) { for (Index = 0; Index < TokenSize; Index += 1) { Temp[Index] = BlRtlConvertCharacterToUpperCase(Entry->FileIdentifier[(Index * 2) + 1]); } if (BlRtlCompareMemory(Temp, Token, TokenSize) != FALSE) { break; } } Entry = (PISO9660_DIRECTORY_RECORD) ROUND_UP_TO_POWER2((((ULONG_PTR) Entry) + Entry->DirectoryRecordLength), 2); if ((ULONG_PTR) Entry >= DirectoryDataLimit) { Entry = NULL; break; } } } if (Entry == NULL) { BlPoolFreeBlock(DirectoryData); return FALSE; } if (*Separator == 0) { BlRtlCopyMemory(DirectoryRecord, Entry, sizeof(ISO9660_DIRECTORY_RECORD)); BlPoolFreeBlock(DirectoryData); return TRUE; } if (Entry->u1.s1.Directory == FALSE) { BlPoolFreeBlock(DirectoryData); return FALSE; } DirectoryDataExtentStart = Entry->ExtentLocation; DirectoryDataExtentSize = ROUND_UP_TO_POWER2(Entry->DataLength, ISO9660_LOGICAL_BLOCK_SIZE) / ISO9660_LOGICAL_BLOCK_SIZE; NextToken = Separator + 1; BlPoolFreeBlock(DirectoryData); } } BOOLEAN BlCdGetFileSize( PCSTR Path, PUINT32 FileSize ) //++ // // Routine Description: // // This function queries the size of the specified file. // // Arguments: // // Path - Supplies the path to the file to query. // // FileSize - Receives the size of the file. // // Return Value: // // TRUE, if the query operation was successful. // FALSE, otherwise. // //-- { ISO9660_DIRECTORY_RECORD DirectoryRecord; if (BlCdFindDirectoryRecord(Path, &DirectoryRecord) == FALSE) { BlRtlPrintf("CdGetFileSize: [%s] FAILED 1\n", Path); return FALSE; } if (DirectoryRecord.u1.s1.Directory != FALSE) { BlRtlPrintf("CdGetFileSize: [%s] FAILED 2\n", Path); return FALSE; } *FileSize = DirectoryRecord.DataLength; return TRUE; } BOOLEAN BlCdReadFile( PCSTR Path, PVOID Buffer, UINT32 NumberOfBytes ) //++ // // Routine Description: // // This function reads from the specified file. // // Arguments: // // Path - Supplies the path to the file to read. // // Buffer - Receives data. // // NumberOfBytes - Supplies the number of bytes to read. // // Return Value: // // TRUE, if the read operation was successful. // FALSE, otherwise. // //-- { ISO9660_LOGICAL_BLOCK Block; UINT32 ChunkOffset; UINT32 ChunkSize; ISO9660_DIRECTORY_RECORD DirectoryRecord; PUINT8 Next; UINT32 Offset = 0; if (BlCdFindDirectoryRecord(Path, &DirectoryRecord) == FALSE) { return FALSE; } if (DirectoryRecord.u1.s1.Directory != FALSE) { return FALSE; } if (NumberOfBytes > DirectoryRecord.DataLength) { return FALSE; } if (NumberOfBytes == 0) { return TRUE; } Next = (PUINT8) Buffer; // // Handle full-read blocks in a single step. // if (NumberOfBytes >= ISO9660_LOGICAL_BLOCK_SIZE) { ChunkSize = NumberOfBytes - (NumberOfBytes % ISO9660_LOGICAL_BLOCK_SIZE); BlCdReadLogicalBlock(DirectoryRecord.ExtentLocation, ChunkSize / ISO9660_LOGICAL_BLOCK_SIZE, (PISO9660_LOGICAL_BLOCK) Next); Next += ChunkSize; Offset += ChunkSize; NumberOfBytes -= ChunkSize; } // // Check if the ending block is a partial read. // BLASSERT(NumberOfBytes < ISO9660_LOGICAL_BLOCK_SIZE); if (NumberOfBytes > 0) { BlCdReadLogicalBlock(DirectoryRecord.ExtentLocation + (Offset / ISO9660_LOGICAL_BLOCK_SIZE), 1, &Block); BlRtlCopyMemory(Next, Block.Data, NumberOfBytes); } return TRUE; } VOID BlCdInitialize( UINT8 DriveId ) //++ // // Routine Description: // // This function initializes CDROM support. // // Arguments: // // DriveId - Supplies CDROM drive ID. // // -- { UINT32 LogicalBlockNumber; BlCdDriveId = DriveId; if (BlRtlGetDriveParameters(BlCdDriveId, &BlCdDriveParameters) == FALSE) { BlRtlPrintf("CDROM: Unable to get drive parameters!\n"); BlRtlHalt(); } if (BlCdDriveParameters.BytesPerSector != ISO9660_LOGICAL_BLOCK_SIZE) { BlRtlPrintf("CDROM: Unexpected sector size!\n"); BlRtlHalt(); } // // Locate Joliet volume descriptor. // LogicalBlockNumber = ISO9660_VOLUME_SPACE_DATA_AREA_LBN; for (;;) { BlCdReadLogicalBlock(LogicalBlockNumber, 1, (PISO9660_LOGICAL_BLOCK) &BlCdVolumeDescriptor); if ((BlCdVolumeDescriptor.u1.VolumeDescriptorType == ISO9660_VOLUME_DESCRIPTOR_TYPE_SUPPLEMENTARY) && (BlCdVolumeDescriptor.u1.Supplementary.EscapeSequences[0] == 0x25) && (BlCdVolumeDescriptor.u1.Supplementary.EscapeSequences[1] == 0x2F) && (BlCdVolumeDescriptor.u1.Supplementary.EscapeSequences[2] == 0x45)){ break; } if (BlCdVolumeDescriptor.u1.VolumeDescriptorType == ISO9660_VOLUME_DESCRIPTOR_TYPE_TERMINATOR) { BlRtlPrintf("CDROM: Unable to find Joliet volume descriptor.\n"); BlRtlHalt(); } LogicalBlockNumber += 1; } BlFsGetFileSize = BlCdGetFileSize; BlFsReadFile = BlCdReadFile; return; } ================================================ FILE: ironclad-apps/src/Checked/BootLoader/SingLdrPc/blcom.cpp ================================================ //++ // // Copyright (c) Microsoft Corporation // // Module Name: // // blcom.cpp // // Abstract: // // This module implements COM port support for the boot loader. // //-- #include "bl.h" #define COM1_ADDRESS 0x3F8 #define COM2_ADDRESS 0x2F8 #define COM3_ADDRESS 0x3E8 #define COM4_ADDRESS 0x2E8 const UINT16 BlComBasePort[COM_MAX_PORT + 1] = { 0, COM1_ADDRESS, COM2_ADDRESS, COM3_ADDRESS, COM4_ADDRESS }; #define COM_DATA_REGISTER 0x0000 #define COM_INTERRUPT_ENABLE_REGISTER 0x0001 #define COM_INTERRUPT_IDENTIFICATION_REGISTER 0x0002 #define COM_FIFO_CONTROL_REGISTER 0x0002 #define COM_LINE_CONTROL_REGISTER 0x0003 #define COM_MODEM_CONTROL_REGISTER 0x0004 #define COM_LINE_STATUS_REGISTER 0x0005 #define COM_MODEM_STATUS_REGISTER 0x0006 #define COM_SCRATCH_REGISTER 0x0007 #define COM_DIVISOR_LATCH_REGISTER_LOW 0x0000 #define COM_DIVISOR_LATCH_REGISTER_HIGH 0x0001 #define COM_CLOCK_RATE 0x1C200 #define COM_LINE_CONTROL_8BITS_1STOP 0x03 #define COM_LINE_CONTROL_DIVISOR_ACCESS 0x80 #define COM_MODEM_CONTROL_DATA_TERMINAL_READY 0x01 #define COM_MODEM_CONTROL_REQUEST_TO_SEND 0x02 #define COM_LINE_STATUS_DATA_READY 0x01 #define COM_LINE_STATUS_OVERRUN_ERROR 0x02 #define COM_LINE_STATUS_PARITY_ERROR 0x04 #define COM_LINE_STATUS_FRAMING_ERROR 0x08 #define COM_LINE_STATUS_SEND_BUFFER_EMPTY 0x20 BOOLEAN BlComInitialize( UINT8 PortNumber, UINT32 BaudRate ) //++ // // Routine Description: // // This function initializes the specified COM port. // // Arguments: // // PortNumber - Supplies the number of the port to initialize. // // BaudRate - Supplies the baud rate. // // Return Value: // // TRUE, if initialization was successful. // FALSE, otherwise. // //-- { UINT16 Base; UINT16 Divisor; UINT8 Index; UINT8 Status; BLASSERT((PortNumber >= 1) && (PortNumber <= COM_MAX_PORT)); BLASSERT(BaudRate != 0); BLASSERT(BaudRate <= COM_CLOCK_RATE); BLASSERT((COM_CLOCK_RATE % BaudRate) == 0); BLASSERT((COM_CLOCK_RATE / BaudRate) <= 0x10000); Base = BlComBasePort[PortNumber]; BlRtlWritePort8(Base + COM_LINE_CONTROL_REGISTER, 0); BlRtlWritePort8(Base + COM_INTERRUPT_ENABLE_REGISTER, 0); BlRtlWritePort8(Base + COM_MODEM_CONTROL_REGISTER, COM_MODEM_CONTROL_DATA_TERMINAL_READY | COM_MODEM_CONTROL_REQUEST_TO_SEND); Divisor = (UINT16) (COM_CLOCK_RATE / BaudRate); BlRtlWritePort8(Base + COM_LINE_CONTROL_REGISTER, COM_LINE_CONTROL_DIVISOR_ACCESS); BlRtlWritePort8(Base + COM_DIVISOR_LATCH_REGISTER_LOW, (UINT8) (Divisor & 0xFF)); BlRtlWritePort8(Base + COM_DIVISOR_LATCH_REGISTER_HIGH, (UINT8) (Divisor >> 8)); BlRtlWritePort8(Base + COM_LINE_CONTROL_REGISTER, COM_LINE_CONTROL_8BITS_1STOP); Index = 0; do { BlRtlWritePort8(Base + COM_SCRATCH_REGISTER, Index); if (BlRtlReadPort8(Base + COM_SCRATCH_REGISTER) != Index) { return FALSE; } Index += 1; } while (Index != 0); Status = BlRtlReadPort8(Base + COM_LINE_STATUS_REGISTER); if (Status == 0xFF) { return FALSE; } #if COM_VERBOSE if ((Status & COM_LINE_STATUS_OVERRUN_ERROR) != 0) { BlVideoPrintf("COM%u: Overrun error!\n", PortNumber); } if ((Status & COM_LINE_STATUS_PARITY_ERROR) != 0) { BlVideoPrintf("COM%u: Parity error!\n", PortNumber); } if ((Status & COM_LINE_STATUS_FRAMING_ERROR) != 0) { BlVideoPrintf("COM%u: Framing error!\n", PortNumber); } #endif return TRUE; } BOOLEAN BlComSendByte( UINT8 PortNumber, UINT8 Byte ) //++ // // Routine Description: // // This function sends a byte to the specified COM port. // // Arguments: // // PortNumber - Supplies the number of the port to send to. // // Byte - Supplies the byte to send. // // Return Value: // // TRUE, if data was sent. // FALSE, otherwise. // //-- { UINT16 Base; UINT8 Status; BLASSERT((PortNumber >= 1) && (PortNumber <= COM_MAX_PORT)); Base = BlComBasePort[PortNumber]; do { Status = BlRtlReadPort8(Base + COM_LINE_STATUS_REGISTER); #if COM_VERBOSE if ((Status & COM_LINE_STATUS_OVERRUN_ERROR) != 0) { BlVideoPrintf("COM%u: Overrun error!\n", PortNumber); } if ((Status & COM_LINE_STATUS_PARITY_ERROR) != 0) { BlVideoPrintf("COM%u: Parity error!\n", PortNumber); } if ((Status & COM_LINE_STATUS_FRAMING_ERROR) != 0) { BlVideoPrintf("COM%u: Framing error!\n", PortNumber); } #endif } while ((Status & COM_LINE_STATUS_SEND_BUFFER_EMPTY) == 0); BlRtlWritePort8(Base + COM_DATA_REGISTER, Byte); Status = BlRtlReadPort8(Base + COM_LINE_STATUS_REGISTER); #if COM_VERBOSE if ((Status & COM_LINE_STATUS_OVERRUN_ERROR) != 0) { BlVideoPrintf("COM%u: Overrun error!\n", PortNumber); } if ((Status & COM_LINE_STATUS_PARITY_ERROR) != 0) { BlVideoPrintf("COM%u: Parity error!\n", PortNumber); } if ((Status & COM_LINE_STATUS_FRAMING_ERROR) != 0) { BlVideoPrintf("COM%u: Framing error!\n", PortNumber); } #endif return TRUE; } BOOLEAN BlComDataAvailable( UINT8 PortNumber ) //++ // // Routine Description: // // This function checks if data is available at the specified COM port. // // Arguments: // // PortNumber - Supplies the number of the port to check. // // Return Value: // // TRUE, if data is available. // FALSE, otherwise. // //-- { UINT16 Base; UINT8 Status; BLASSERT((PortNumber >= 1) && (PortNumber <= COM_MAX_PORT)); Base = BlComBasePort[PortNumber]; Status = BlRtlReadPort8(Base + COM_LINE_STATUS_REGISTER); #if COM_VERBOSE if ((Status & COM_LINE_STATUS_OVERRUN_ERROR) != 0) { BlVideoPrintf("COM%u: Overrun error!\n", PortNumber); } if ((Status & COM_LINE_STATUS_PARITY_ERROR) != 0) { BlVideoPrintf("COM%u: Parity error!\n", PortNumber); } if ((Status & COM_LINE_STATUS_FRAMING_ERROR) != 0) { BlVideoPrintf("COM%u: Framing error!\n", PortNumber); } #endif return ((Status & COM_LINE_STATUS_DATA_READY) != 0); } UINT8 BlComReceiveByte( UINT8 PortNumber ) //++ // // Routine Description: // // This function receives a byte from the specified COM port. // // Arguments: // // PortNumber - Supplies the number of the port to receive from. // // Return Value: // // Byte received from the specified COM port. // //-- { UINT16 Base; UINT8 Byte; UINT8 Status; BLASSERT((PortNumber >= 1) && (PortNumber <= COM_MAX_PORT)); Base = BlComBasePort[PortNumber]; BlRtlReadPort8(Base + COM_MODEM_STATUS_REGISTER); do { Status = BlRtlReadPort8(Base + COM_LINE_STATUS_REGISTER); #if COM_VERBOSE if ((Status & COM_LINE_STATUS_OVERRUN_ERROR) != 0) { BlVideoPrintf("COM%u: Overrun error!\n", PortNumber); } if ((Status & COM_LINE_STATUS_PARITY_ERROR) != 0) { BlVideoPrintf("COM%u: Parity error!\n", PortNumber); } if ((Status & COM_LINE_STATUS_FRAMING_ERROR) != 0) { BlVideoPrintf("COM%u: Framing error!\n", PortNumber); } #endif } while ((Status & COM_LINE_STATUS_DATA_READY) == 0); Byte = BlRtlReadPort8(Base + COM_DATA_REGISTER); Status = BlRtlReadPort8(Base + COM_LINE_STATUS_REGISTER); #if COM_VERBOSE if ((Status & COM_LINE_STATUS_OVERRUN_ERROR) != 0) { BlVideoPrintf("COM%u: Overrun error!\n", PortNumber); } if ((Status & COM_LINE_STATUS_PARITY_ERROR) != 0) { BlVideoPrintf("COM%u: Parity error!\n", PortNumber); } if ((Status & COM_LINE_STATUS_FRAMING_ERROR) != 0) { BlVideoPrintf("COM%u: Framing error!\n", PortNumber); } #endif return Byte; } ================================================ FILE: ironclad-apps/src/Checked/BootLoader/SingLdrPc/blentry.cpp ================================================ //++ // // Copyright (c) Microsoft Corporation // // Module Name: // // blentry.cpp // // Abstract: // // This module implements the entry point for the boot loader. // //-- #include "bl.h" //#define VESA_ENABLED 1 #define BL_BOOT_STACK_SIZE 0x10000 PVOID BlBootStackLimit; PVOID BlBootStackBase; VOID BlApEntry( VOID ) //++ // // Routine Description: // // This function implements the non-legacy entry point for application processors. // //-- { BlSingularityApEntry(); BlRtlHalt(); } VOID BlInitialize( VOID ) //++ // // Routine Description: // // This function initializes the boot loader. // //-- { PBEB Beb; Beb = BlGetBeb(); // // Check boot type and perform any necessary source specific initialization. // BlRtlPrintf("Booting from "); switch (Beb->BootType) { case BL_CD_BOOT: { BlRtlPrintf("CD in drive 0x%02x.\n\n", Beb->BootDriveNumber); BlCdInitialize((UINT8) Beb->BootDriveNumber); break; } case BL_FAT16_BOOT: { BlRtlPrintf("FAT16 on drive 0x%02x.\n\n", Beb->BootDriveNumber); BlFatInitialize((UINT8) Beb->BootDriveNumber, MBR_FAT16LBA); break; } case BL_FAT32_BOOT: { BlRtlPrintf("FAT32 on drive 0x%02x.\n\n", Beb->BootDriveNumber); BlFatInitialize((UINT8) Beb->BootDriveNumber, MBR_FAT32LBA); break; } case BL_PXE_BOOT: { BlRtlPrintf("network.\n"); BlPxeInitialize(); break; } case BL_FLASH_BOOT: { BlRtlPrintf("Flash.\n"); BlFlashInitialize((PVOID)Beb->FlashImage, (PVOID)Beb->FlashImage); break; } default: { BlRtlPrintf("unknown source!\n"); BlRtlHalt(); } } // // Initialize PNP BIOS support. // if (Beb->BootType != BL_FLASH_BOOT) { BlPnpInitialize(); } // // Initialize MPS support. // BlMpsInitialize(); // // Initialize ACPI support. // if (Beb->BootType != BL_FLASH_BOOT) { BlAcpiInitialize(); } else { BlAcpiNumberOfProcessors = 1; } // // Set AP entry address. // Beb->ApEntry = (UINT32) (ULONG_PTR) BlApEntry; // // Initialize Singularity. // if (BlCommandLine == NULL) { BlCommandLine = L""; } BlSingularityInitialize(BlAcpiNumberOfProcessors, &Beb->ApEntry16, &Beb->ApStartupLock); } #if defined(BOOT_X86) #define PLATFORM_STRING "x86" #elif defined(BOOT_X64) #define PLATFORM_STRING "x64" #endif BL_TIME BlStartTime; VOID BlEntry( VOID ) //++ // // Routine Description: // // This function implements the non-legacy entry point for the boot loader. // //-- { PBEB Beb; Beb = BlGetBeb(); // // Initialize the trap table. // BlTrapEnable(); // // Initialize video. // BlVideoInitialize(); // // Print the welcome banner. // BlRtlPrintf("Singularity %s Boot Loader [%s %s]\n" "\n", PLATFORM_STRING, __DATE__, __TIME__); // // Capture boot start time. // if (Beb->BootType != BL_FLASH_BOOT) { BlRtlGetCurrentTime(&BlStartTime); } // // Initialize memory management (ring transitions must follow this call). // BlMmInitializeSystem(); // // Initialize PCI support (probe for 1394 interfaces for KD). // if (Beb->BootType != BL_FLASH_BOOT) { BlPciInitialize(); } // // Initialize KD. // BlRtlPrintf("Looking for debugger.\n"); // BlKdInitialize(); // // Print the welcome banner. // BlRtlPrintf("Boot Time: %02u/%02u/%02u %02u:%02u:%02u\n", BlStartTime.Month, BlStartTime.Day, BlStartTime.Year, BlStartTime.Hour, BlStartTime.Minute, BlStartTime.Second); // // Initialize VESA support. // #if VESA_ENABLED BlVesaInitialize(); #endif // // Allocate and switch to the boot stack. // BlBootStackLimit = (PVOID) (ULONG_PTR) BlMmAllocatePhysicalRegion(BL_BOOT_STACK_SIZE, BL_MM_PHYSICAL_REGION_BOOT_STACK); BlBootStackBase = (PVOID) ((ULONG_PTR) BlBootStackLimit + BL_BOOT_STACK_SIZE); BlMmSwitchStack(BlBootStackBase, BlInitialize); } ================================================ FILE: ironclad-apps/src/Checked/BootLoader/SingLdrPc/blentry16.asm ================================================ ;++ ; ; Copyright (c) Microsoft Corporation ; ; Module Name: ; ; blentry16.asm (x64) ; ; Abstract: ; ; This module implements the 16-bit entry point for the boot loader. ; ; Environment: ; ; Boot loader. ; ;-- .model tiny, c OPTION SCOPED include bl.inc REAL_MODE_BASE equ 07b00h VIDEO_BASE equ 0b8000h BLUE equ 01f00h RED equ 02f00h GREEN equ 04f00h .code .686p JMPF16 MACRO SEG:REQ,OFF:REQ db 0eah dw OFF dw SEG ENDM JMPF32 MACRO SEG:REQ,OFF:REQ db 0eah dd OFF dw SEG ENDM _TEXT16 segment page public use16 'CODE' org 100h ;++ ; ; VOID ; BlEntry16( ; VOID ; ) ; ; Routine Description: ; ; This function is the 16-bit entry point for the boot loader and it detects ; the type of boot to perform and calls the appropriate function. ; ;-- BlEntry16 proc ; ; Disable interrupts. ; cli mov bp, sp ;; Write a character to the screen. ;; Configure GS to point to the text-mode video console. mov ax, 0b800h mov gs, ax mov ax, GREEN + 'A' mov gs:[0], ax mov ax, GREEN + '-' mov gs:[2], ax ; ; If CS is 0x5000, then it indicates a CD or HD boot. ; mov bx, PXE_BOOT mov dx, 0 mov ax, cs cmp ax, 05000h jne boot_ready ; ; Check for CD signature on the stack. ; mov dx, word ptr [bp + 8] mov bx, CD_BOOT cmp word ptr [bp + 4], 04344h je boot_needs_fixup ; ; Check for FAT16 signature on the stack. ; mov bx, FAT16_BOOT cmp word ptr [bp + 4], 04806h je boot_needs_fixup ; ; Check for FAT32 signature on the stack. ; mov bx, FAT32_BOOT cmp word ptr [bp + 4], 04803h je boot_needs_fixup ; ; Unknown boot device ; mov ax, GREEN + 'B' mov gs:[2], ax @@: jmp @b ; ; Copy 64K from 57C0:0000 to 07C0:0000. ; boot_needs_fixup: mov ax, GREEN + 'C' mov gs:[4], ax mov ax, 057C0h mov ds, ax mov si, 0 mov ax, 007C0h mov es, ax mov di, 0 mov cx, 04000h rep movsd ; ; Continue execution at the relocated block with known segment selector. ; boot_ready: mov ax, GREEN + 'D' mov gs:[6], ax ; ; Jump to relocated code. ; JMPF16 07b0h, @f @@: ; bx = BootType ; dx = BootDriveNumber ; ; Initialize DS, ES, SS, and SP for real mode. ; mov ax, cs mov ds, ax mov es, ax mov ax, RM_INITIAL_SS mov ss, ax mov sp, RM_INITIAL_SP mov ax, GREEN + 'E' mov gs:[8], ax ; ; Initialize boot environment block (pass bx & dx). ; call BlInitializeBeb ; ; Initialize video. ; call BlInitializeVideo ; ; Load GDT. ; mov ax, GREEN + 'F' mov gs:[10], ax mov di, OFFSET BlGDTS_Limit lgdt fword ptr ds:[di] mov ax, RM_VIDEO_SELECTOR mov gs, ax mov ax, GREEN + 'G' mov gs:[12], ax ; ; Clear the real-mode segment registers. ; xor ax, ax mov ds, ax mov es, ax mov ss, ax mov fs, ax mov gs, ax ; ; Enable protected mode. ; mov eax, cr0 or eax, CR0_PE OR CR0_NE mov cr0, eax ; ; Jump far to 32-bit protected-mode code. ; JMPF16 PM_CODE_SELECTOR, LOWWORD ( REAL_MODE_BASE + OFFSET BlEntry32 ) BlEntry16 endp ;++ ; ; VOID ; BlInitializeVideo( ; VOID ; ) ; ; Routine Description: ; ; This function initializes video support for the boot loader. ; ;-- BlInitializeVideo proc mov ax, 1202h ; LINES_400_CONFIGURATION mov bx, 0301h ; SELECT_SCAN_LINE int 10h mov ax, 3h ; SET_80X25_16_COLOR_MODE mov bx, 0h ; PAGE0 int 10h mov ax, 1112h ; LOAD_8X8_CHARACTER_SET mov bx, 0h int 10h mov ax, 1003h ; Disable BLINK mode, enable background intensity. mov bx, 0h int 10h mov ax, 0200h ; Set Cursor position to 0, 0 mov bx, 0h mov dx, 0h int 10h ret BlInitializeVideo endp ;++ ; ; VOID ; BlInitializeBeb( ; bx = BootType ; dx = BootDriveNumber ; ) ; ; Routine Description: ; ; This function initializes the boot environment block. ; ;-- BlInitializeBeb proc push es push di mov di, BEB_SEG16 mov es, di mov di, BEB_OFF16 xor al, al mov cx, 4096 rep stosb mov di, BEB_OFF16 ;; See if we are booting from Flash mov si, BlFlashImage mov eax, [si] cmp eax, 0 je @f mov dword ptr es:[di].BEB.FlashImage, eax mov si, BlSmapAddr mov eax, [si] mov dword ptr es:[di].BEB.SmapAddr, eax mov si, BlSmapSize mov eax, [si] mov dword ptr es:[di].BEB.SmapSize, eax mov bx, FLASH_BOOT @@: mov word ptr es:[di].BEB.BootType, bx mov word ptr es:[di].BEB.BootDriveNumber, dx ifdef BOOT_X64 mov dword ptr es:[di].BEB.LegacyReturnCr3, LM_PML4T_ADDRESS else mov dword ptr es:[di].BEB.LegacyReturnCr3, PM_PDPT_ADDRESS endif lea ax, BlApEntry16 mov word ptr es:[di].BEB.ApEntry16, ax mov ax, cs mov word ptr es:[di].BEB.ApEntry16 + 2, ax lea ax, BlApStartupLock mov word ptr es:[di].BEB.ApStartupLock, ax mov ax, cs mov word ptr es:[di].BEB.ApStartupLock + 2, ax pop di pop es ret BlInitializeBeb endp ;++ ; ; Hardware Protection Configuration Data ; ;-- ; ; TSS. ; ALIGN 16 BlTSS: db 066h dup (0) dw 068h ; ; Global Descriptor Table (GDT). ; ALIGN 16 BlGDTStart: dq 00000000000000000h ; 00: NULL segment [NULL_SELECTOR]. dq 00000930B8000FFFFh ; 08: 000B8000[0000FFFF] Data [PM_VIDEO_SELECTOR]. dq 000009B007B00FFFFh ; 10: 00007800[0000FFFF] COde [RM_CODE_SELECTOR]. dq 0000093007B00FFFFh ; 18: 00007B00[0000FFFF] Data [RM_DATA_SELECTOR]. dq 000CF9B000000FFFFh ; 20: PM code segment [PM_CODE_SELECTOR]. dq 000CF93000000FFFFh ; 28: PM data segment [PM_DATA_SELECTOR]. dq 000209B0000000000h ; 30: LM code segment [LM_CODE_SELECTOR]. dq 00000930000000000h ; 38: LM data segment [LM_DATA_SELECTOR]. dq 00000000000000000h ; 40: PM user code segment [UM_CODE_SELECTOR]. dq 00000000000000000h ; 48: PM user data segment [UM_DATA_SELECTOR]. dq 00000000000000000h ; 50: FS/GS segment [PROCESSOR_SELECTOR]. dq 00000000000000000h ; 58: [UNUSED_SELECTOR] ; ; TSS segment. ; dw 00067h dw REAL_MODE_BASE + OFFSET BlTSS db 000h db 089h dw 00000h ifdef BOOT_X64 dq 00000000000000000h endif BlGDTLimit: ; ; Global Descriptor Table Selector (GDTS). ; ALIGN 16 ;; Padding to align address (and limit to -2) dw 00000h dw 00000h dw 00000h BlGDTS_Limit: dw offset BlGDTLimit - offset BlGDTStart BlGDTS_Address: dw REAL_MODE_BASE + OFFSET BlGDTStart dw 0 dd 0 ;++ ; ; VOID ; BlReturnToRealMode( ; VOID ; ) ; ; Routine Description: ; ; This function switches the processor back to real mode to execute a real ; mode request. ; ;-- ALIGN 16 BlReturnToRealMode proc ; ; Zero all registers. ; xor ebx, ebx xor ecx, ecx xor edx, edx xor esi, esi xor edi, edi xor esp, esp xor ebp, ebp mov ax, RM_DATA_SELECTOR mov ds, ax mov es, ax mov ss, ax mov fs, ax mov gs, ax ; ; Disable protected mode. ; mov eax, cr0 and eax, NOT (CR0_PE OR CR0_NE) mov cr0, eax ; ; Return to real mode. ; JMPF16 07b0h, OFFSET BlProcessRealModeRequest BlReturnToRealMode endp ;++ ; ; VOID ; BlLeaveLrbPmToBoot( ; VOID ; ) ; ; Routine Description: ; ; This function switches the processor back to real mode for boot. ; ;-- ALIGN 16 BlLeaveLrbPmToBoot PROC mov ax, RM_VIDEO_SELECTOR mov gs, ax ;; Write to position 0. mov ax, RED + 'T' mov gs:[12], ax ; Zero all registers. ; xor ebx, ebx xor ecx, ecx xor edx, edx xor esi, esi xor edi, edi xor esp, esp xor ebp, ebp ; ; Disable paging. ; mov eax, cr0 and eax, NOT (CR0_PG) mov cr0, eax xor eax, eax mov cr3, eax mov cr4, eax ; ; Disable long mode and return to legacy protected-mode. ; mov ecx, EFER_MSR_INDEX rdmsr and eax, NOT (EFER_LME OR EFER_NXE) wrmsr ; ; Disable protected mode. ; mov eax, cr0 and eax, NOT (CR0_PE OR CR0_NE) mov cr0, eax ; ; Return to real mode. ; JMPF16 07b0h, OFFSET @f @@: mov ax, 0b800h mov gs, ax ;; Write to position 0. mov ax, RED + 'U' mov gs:[14], ax mov ax, cs mov ds, ax mov es, ax mov ax, RM_INITIAL_SS mov ss, ax mov sp, RM_INITIAL_SP ;; Write to position 0. mov ax, RED + 'V' mov gs:[16], ax ; ; Return to real mode boot entry. ; JMPF16 07b0h, OFFSET BlEntry16 BlLeaveLrbPmToBoot endp ;++ ; ; VOID ; BlProcessRealModeRequest( ; VOID ; ) ; ; Routine Description: ; ; This function performs the requested real mode operation and returns back to ; protected mode as necessary. ; ;-- ; ; Real-mode IDTR. ; BlRealModeIdtr: dw 01000h dq 0 ; ; Protected-mode IDTR. ; BlProtModeIdtr: dw 01000h dq 0 BlProcessRealModeRequest proc ; ; Set DS, ES, SS, SP, and SI for real-mode legacy call. ; xor eax,eax mov ax, cs mov ds, ax mov ax, BEB_SEG16 mov es, ax mov ax, RM_INITIAL_SS mov ss, ax mov sp, RM_INITIAL_SP mov si, BEB_OFF16 ; ; Switch back to real-mode IDT. ; lea eax, BlRealModeIdtr lidt fword ptr ds:[eax] cmp word ptr es:[si].BEB.LegacyCall_OpCode, LC_INTXX jne @f mov cl, byte ptr es:[si].BEB.LegacyCall_Vector call BlProcessIntXx jmp BlProcessRealModeRequest_Exit @@: cmp word ptr es:[si].BEB.LegacyCall_OpCode, LC_FARCALL jne @f call BlProcessFarCall jmp BlProcessRealModeRequest_Exit @@: BlProcessRealModeRequest_Exit: ; ; Restore DS, ES, SS, and SP to their initial real-mode values. ; mov ax, cs mov ds, ax mov es, ax mov ax, RM_INITIAL_SS mov ss, ax mov sp, RM_INITIAL_SP ; ; Load GDT. ; mov di, OFFSET BlGDTS_Limit lgdt fword ptr ds:[di] ; ; Clear the real-mode segment registers. ; xor ax, ax mov ds, ax mov es, ax mov ss, ax mov fs, ax mov gs, ax ; ; Enable protected mode. ; mov eax, cr0 or eax, CR0_PE OR CR0_NE mov cr0, eax ; ; Jump far to 32-bit protected-mode code. ; JMPF16 PM_CODE_SELECTOR, LOWWORD ( REAL_MODE_BASE + OFFSET BlEnter32AfterRealModeRequest ) BlProcessRealModeRequest endp ;++ ; ; Lock to protect shared access to real-mode boot stack. ; ;-- BlApStartupLock: dd 0 Bl16End db 0deh, 0adh, 0beh, 0efh org 500h ;++ ; ; VOID ; BlApEntry16( ; VOID ; ) ; ; Routine Description: ; ; This function implements the entry point for application processors ; on a multi-processor system. ; ;-- BlApEntry16 proc ; ; Disable interrupts. ; cli ; ; Set DS to access AP startup lock. ; mov ax, 07b0h mov ds, ax ; ; Acquire AP startup lock before touching any other memory or stack. ; @@: cmp word ptr ds:[BlApStartupLock], 0 jne @b mov ax, 1 xchg word ptr ds:[BlApStartupLock], ax cmp ax, 0 jne @b ; ; Set SS & SP and switch to 16-bit entry CS. ; mov ax, RM_INITIAL_SS mov ss, ax mov sp, RM_INITIAL_SP JMPF16 07b0h, OFFSET @f @@: ; ; Initialize DS, ES, SS, and SP for real mode. ; mov ax, cs mov ds, ax mov es, ax mov ax, RM_INITIAL_SS mov ss, ax mov sp, RM_INITIAL_SP ; ; Load GDT. ; mov di, OFFSET BlGDTS_Limit lgdt fword ptr ds:[di] ; ; Clear the real-mode segment registers. ; xor ax, ax mov ds, ax mov es, ax mov ss, ax mov fs, ax mov gs, ax ; ; Enable protected mode. ; mov eax, cr0 or eax, CR0_PE OR CR0_NE mov cr0, eax ; ; Jump far to 32-bit protected-mode code. ; JMPF16 PM_CODE_SELECTOR, LOWWORD ( REAL_MODE_BASE + OFFSET BlApEntry32 ) BlApEntry16 endp ; ; ; SAVE_CONTEXT_TO_STACK macro push eax push ebx push ecx push edx push esi push edi push ds push es pushfd endm RESTORE_CONTEXT_FROM_STACK macro popfd pop es pop ds pop edi pop esi pop edx pop ecx pop ebx pop eax endm SAVE_CALL_CONTEXT_TO_STACK macro mov ax, BEB_SEG16 mov es, ax mov si, BEB_OFF16 push dword ptr es:[si].BEB.LegacyCall_eax push dword ptr es:[si].BEB.LegacyCall_ebx push dword ptr es:[si].BEB.LegacyCall_ecx push dword ptr es:[si].BEB.LegacyCall_edx push dword ptr es:[si].BEB.LegacyCall_esi push dword ptr es:[si].BEB.LegacyCall_edi push word ptr es:[si].BEB.LegacyCall_ds push word ptr es:[si].BEB.LegacyCall_es pushfd endm RESTORE_CALL_CONTEXT_FROM_STACK macro mov ax, BEB_SEG16 mov es, ax mov si, BEB_OFF16 pop dword ptr es:[si].BEB.LegacyCall_eflags pop word ptr es:[si].BEB.LegacyCall_es pop word ptr es:[si].BEB.LegacyCall_ds pop dword ptr es:[si].BEB.LegacyCall_edi pop dword ptr es:[si].BEB.LegacyCall_esi pop dword ptr es:[si].BEB.LegacyCall_edx pop dword ptr es:[si].BEB.LegacyCall_ecx pop dword ptr es:[si].BEB.LegacyCall_ebx pop dword ptr es:[si].BEB.LegacyCall_eax endm ;++ ; ; VOID ; BlProcessIntXx( ; UCHAR InterruptVector ; ) ; ; Routine Description: ; ; This function processes INT XX requests. ; ; Arguments: ; ; InterruptVector (cl) - Supplies the interrupt vector to invoke. ; ;-- BlProcessIntXx proc mov byte ptr @f, cl SAVE_CONTEXT_TO_STACK SAVE_CALL_CONTEXT_TO_STACK RESTORE_CONTEXT_FROM_STACK ; ; INT XX instruction. ; db 0CDh @@: db 000h SAVE_CONTEXT_TO_STACK RESTORE_CALL_CONTEXT_FROM_STACK RESTORE_CONTEXT_FROM_STACK ret BlProcessIntXx endp ;++ ; ; VOID ; BlProcessFarCall( ; UCHAR InterruptVector ; ) ; ; Routine Description: ; ; This function processes far call requests. ; ;-- BlProcessFarCall proc SAVE_CONTEXT_TO_STACK push bp mov bp, sp ; ; Copy the call frame to the stack. ; mov ax, BEB_SEG16 mov es, ax mov si, BEB_OFF16 mov ax, word ptr es:[si].BEB.LegacyCall_FramePtr + 2 mov ds, ax mov bx, word ptr es:[si].BEB.LegacyCall_FramePtr mov cx, word ptr es:[si].BEB.LegacyCall_FrameSize add bx, cx mov ax, cx @@: cmp ax, 0 je @f sub bx, 2 push word ptr ds:[bx] sub ax, 2 jmp @b @@: ; ; Set return address. ; push cs push @f ; ; Set call address. ; push dword ptr es:[si].BEB.LegacyCall_FuncPtr ; ; Set caller provided context. ; SAVE_CALL_CONTEXT_TO_STACK RESTORE_CONTEXT_FROM_STACK ; ; Call the specified function with a far return. ; retf @@: ; ; Copy the output context to BEB. ; SAVE_CONTEXT_TO_STACK RESTORE_CALL_CONTEXT_FROM_STACK mov sp, bp pop bp RESTORE_CONTEXT_FROM_STACK ret BlProcessFarCall endp _TEXT16 ends _TEXT32 segment page public use32 'CODE' ;++ ; ; VOID ; BlEntry32( ; VOID ; ) ; ; Routine Description: ; ; This function implements the 32-bit entry point for the boot loader. ; ;-- BlEntry32 proc ; ; Load the protected-mode segment registers. ; mov ax, PM_DATA_SELECTOR mov ds, ax mov es, ax mov ss, ax mov esp, PM_INITIAL_ESP mov ax, NULL_SELECTOR mov fs, ax mov gs, ax mov esi, VIDEO_BASE + 14 mov [esi], ax ifdef BOOT_X64 ; ; Check for long mode. ; call BlCheckLongMode cmp eax, 0 jne @f ; ; Long mode is not supported -- halt execution. ; call BlHalt @@: endif ; ; Initialize boot environment block. ; call BlRegisterExitAddress ; ; Prepare page tables. ; call BlPreparePageTables mov ax, GREEN + 'I' mov esi, VIDEO_BASE + 14 mov [esi], ax ; ; Enable PSE, PAE, performance counters, and floating point support. ; mov eax, cr4 ;or eax, CR4_PCE OR CR4_OSFXSR or eax, CR4_PSE OR CR4_PAE OR CR4_PCE OR CR4_OSFXSR mov cr4, eax ; ; Set root page table. ; ifdef BOOT_X64 mov eax, LM_PML4T_ADDRESS else mov eax, PM_PDPT_ADDRESS endif mov cr3, eax ifdef BOOT_X64 ; ; Enable long-mode and no-execute. ; mov ecx, EFER_MSR_INDEX rdmsr or eax, EFER_LME OR EFER_NXE wrmsr endif ; ; Enable paging. ; ;hlt mov eax, cr0 or eax, CR0_PG mov cr0, eax ; mov eax, cr0 ;myInfLoop: ; and eax, 080000000h; ; cmp eax, 0 ; jne myInfLoop ; ; Load PE image. ; call BlLoadImage mov bx, GREEN + 'J' mov esi, VIDEO_BASE + 16 mov [esi], bx ifdef BOOT_X64 ; ; Enter long mode. ; JMPF32 LM_CODE_SELECTOR, REAL_MODE_BASE + OFFSET @f @@: mov dx, LM_DATA_SELECTOR mov ds, dx mov es, dx mov ss, dx mov bx, GREEN + 'K' mov esi, VIDEO_BASE + 18 mov [esi], bx endif ; ; Switch to entry stack and call entry point. ; mov esp, BL_ENTRY_SP call eax BlEntry32 endp ;++ ; ; VOID ; BlEnter32AfterRealModeRequest( ; VOID ; ) ; ; Routine Description: ; ; This function returns to normal mode after a legacy mode request was handled. ; ;-- BlEnter32AfterRealModeRequest proc ; ; Load the protected-mode segment registers. ; mov ax, PM_DATA_SELECTOR mov ds, ax mov es, ax mov ss, ax mov esp, PM_INITIAL_ESP mov ax, NULL_SELECTOR mov fs, ax mov gs, ax ; ; Enable PSE, PAE, performance counters, and floating point support. ; mov eax, cr4 ;or eax, CR4_PCE OR CR4_OSFXSR or eax, CR4_PSE OR CR4_PAE OR CR4_PCE OR CR4_OSFXSR mov cr4, eax ; ; Set root page table. ; mov eax, BEB_BASE mov eax, dword ptr [eax].BEB.LegacyReturnCr3 mov cr3, eax ifdef BOOT_X64 ; ; Enable long-mode and no-execute. ; mov ecx, EFER_MSR_INDEX rdmsr or eax, EFER_LME OR EFER_NXE wrmsr endif ; ; Restore the IDT ; mov eax, OFFSET BlProtModeIdtr add eax, REAL_MODE_BASE lidt fword ptr ds:[eax] ; ; Enable paging. ; mov eax, cr0 or eax, CR0_PG mov cr0, eax ; ; Get return address from BEB. ; mov eax, BEB_BASE mov eax, dword ptr [eax].BEB.LegacyReturnAddress ifdef BOOT_X64 ; ; Enter long mode. ; JMPF32 LM_CODE_SELECTOR, REAL_MODE_BASE + OFFSET @f @@: mov edx, LM_DATA_SELECTOR mov ds, edx mov es, edx mov ss, edx endif ; ; Return to normal code. ; call eax BlEnter32AfterRealModeRequest endp ;++ ; ; VOID ; BlPreparePageTables( ; VOID ; ) ; ; Routine Description: ; ; This function prepares page tables for long mode execution. ; ;-- BlPreparePageTables proc ifdef BOOT_X64 ; ; Clear all entries for 4th level table. ; xor eax, eax mov edi, LM_PML4T_ADDRESS mov ecx, 0400h rep stosd ; ; Create a single 4th level entry. ; mov eax, LM_PML4T_ADDRESS mov dword ptr [eax], PM_PDPT_ADDRESS OR PTE_PRESENT OR PTE_WRITEABLE OR PTE_ACCESSED endif ; ; Clear all entries for 2nd and 3rd level tables. ; xor eax, eax mov edi, PM_PDPT_ADDRESS mov ecx, 0400h rep stosd xor eax, eax mov edi, PM_PDT_ADDRESS mov ecx, 0400h rep stosd ; ; Create a single 3rd level entry. ; mov eax, PM_PDPT_ADDRESS ifdef BOOT_X64 mov dword ptr [eax], PM_PDT_ADDRESS OR PTE_PRESENT OR PTE_WRITEABLE OR PTE_ACCESSED else ;;; See if these can't be the same. mov dword ptr [eax], PM_PDT_ADDRESS OR PTE_PRESENT endif ; ; Create a single 2nd level entry to identity-map the first 2MB of memory. ; mov eax, PM_PDT_ADDRESS mov dword ptr [eax], 0 OR PTE_PRESENT OR PTE_WRITEABLE OR PTE_ACCESSED OR PTE_2MB ret BlPreparePageTables endp ifdef BOOT_X64 ;++ ; ; VOID ; BlCheckLongMode( ; VOID ; ) ; ; Routine Description: ; ; This function checks if the processor supports long mode execution. ; ; Return Value: ; ; TRUE, if long mode execution is supported. ; FALSE, otherwise. ; ;-- BlCheckLongMode proc ; ; Get the largest extended function supported. ; mov eax, 080000000h cpuid ; ; If 0x80000000 is the limit, then long mode is not supported. ; cmp eax, 080000000h jbe NoLongMode ; ; Execute extended function 1 and check for long mode bit. ; mov eax, 080000001h cpuid bt edx, 29 jnc NoLongMode ; ; Return 1 to indicate presence of long mode. ; mov eax, 1 ret NoLongMode: ; ; Return 0 to indicate absense of long mode. ; mov eax, 0 ret BlCheckLongMode endp endif ;++ ; ; VOID ; BlHalt( ; VOID ; ) ; ; Routine Description: ; ; This function halts execution. ; ;-- BlHalt proc @@: jmp @b BlHalt endp ;++ ; ; VOID ; BlLeaveProtectedMode( ; VOID ; ) ; ; Routine Description: ; ; This function leaves protected mode to perform a real mode operation. ; ;-- ALIGN 16 BlLeaveProtectedMode proc ; ; Disable paging, reset root page table, and flush TLB. ; mov eax, cr0 and eax, NOT CR0_PG mov cr0, eax xor eax, eax mov cr3, eax mov cr4, eax jmp @f ALIGN 16 @@: ; ; Save the IDT. ; mov eax, OFFSET BlProtModeIdtr add eax, REAL_MODE_BASE sidt fword ptr ds:[eax] ifdef BOOT_X64 ; ; Disable long mode and return to legacy protected-mode. ; mov ecx, EFER_MSR_INDEX rdmsr and eax, NOT (EFER_LME OR EFER_NXE) wrmsr endif ; ; Return to real-mode code. ; JMPF32 RM_CODE_SELECTOR, OFFSET BlReturnToRealMode BlLeaveProtectedMode endp ;++ ; ; PVOID ; BlLoadImage( ; VOID ; ) ; ; Routine Description: ; ; This function loads the higher-level boot loader image. ; ; Return Value: ; ; Entry point address for the loaded image. ; ;-- BlLoadImage proc lea ebp, OFFSET BlImageStart add ebp, REAL_MODE_BASE ; ; Check DOS signature. ; cmp word ptr [ebp], IMAGE_DOS_SIGNATURE jne BlInvalidImage ; ; Calculate NT header address. ; mov ebx, dword ptr [ebp + IDH_NT_HEADER_OFFSET] add ebx, ebp ; ; Check NT signature. ; cmp dword ptr [ebx + INH_SIGNATURE], IMAGE_NT_SIGNATURE jne BlInvalidImage ; ; Check image base. ; ifdef BOOT_X64 cmp dword ptr [ebx + INH_OPTIONAL_HEADER + IOH64_IMAGE_BASE + 4], 0 jne BlInvalidImage cmp dword ptr [ebx + INH_OPTIONAL_HEADER + IOH64_IMAGE_BASE], IMAGE_ADDRESS else cmp dword ptr [ebx + INH_OPTIONAL_HEADER + IOH32_IMAGE_BASE], IMAGE_ADDRESS endif jne BlInvalidImage ; ; Copy headers. ; mov esi, ebp mov edi, IMAGE_ADDRESS mov ecx, dword ptr [ebx + INH_OPTIONAL_HEADER + IOH_SIZE_OF_HEADERS] rep movsb ; ; Calculate the address of first section header. ; ; SectionHeader = (PIMAGE_SECTION_HEADER) (((ULONG_PTR) &NtHeaders->OptionalHeader) + NtHeaders->FileHeader.SizeOfOptionalHeader) ; xor esi, esi mov si, word ptr [ebx + INH_FILE_HEADER + IFH_SIZE_OF_OPTIONAL_HEADER] add esi, INH_OPTIONAL_HEADER add esi, ebx xor ecx, ecx mov cx, word ptr [ebx + INH_FILE_HEADER + IFH_NUMBER_OF_SECTIONS] cmp cx, 0 jne @f call BlInvalidImage ; ; for (Index = 0; Index < NtHeaders->FileHeader.NumberOfSections; Index += 1) { ; ; BlCopySection(DosHeader, &SectionHeader[Index]); ; } ; @@: push ecx mov ecx, ebp mov edx, esi call BlCopySection pop ecx add esi, IMAGE_SECTION_HEADER_SIZE dec ecx jnz @b mov eax, dword ptr [ebx + INH_OPTIONAL_HEADER + IOH_ADDRESS_OF_ENTRY_POINT] add eax, IMAGE_ADDRESS ret BlLoadImage endp ;++ ; ; VOID ; FASTCALL ; BlCopySection( ; PIMAGE_DOS_HEADER DosHeader, ; PIMAGE_SECTION_HEADER SectionHeader ; ) ; ; Routine Description: ; ; This function copies the specified image section. ; ; Arguments: ; ; DosHeader (ecx) - Supplies a pointer to the source image to copy from. ; ; SectionHeader (edx) - Supplies a pointer to the section header describing ; the section to copy. ; ;-- BlCopySection proc ; ; Create call frame and save non-volatile registers that will be used. ; push ebp mov ebp, esp push esi push edi ; ; Calculate source and destination address for the copy operation. ; mov esi, dword ptr [edx + ISH_POINTER_TO_RAW_DATA] add esi, ecx mov edi, dword ptr [edx + ISH_VIRTUAL_ADDRESS] add edi, IMAGE_ADDRESS ; ; Save source and destination addresses -- rep stosb below will use them. ; push esi push edi ; ; Zero the entire target virtual range. ; mov eax, 0 mov ecx, dword ptr [edx + ISH_VIRTUAL_SIZE] rep stosb ; ; Restore source and destination addresses. ; pop edi pop esi ; ; BytesToCopy = min(SectionHeader->VirtualSize, SectionHeader->SizeOfRawData) ; mov ecx, dword ptr [edx + ISH_VIRTUAL_SIZE] cmp ecx, dword ptr [edx + ISH_SIZE_OF_RAW_DATA] jl @f mov ecx, dword ptr [edx + ISH_SIZE_OF_RAW_DATA] @@: ; ; Perform copy. ; rep movsb ; ; Restore used non-volatile registers, base pointer, and return. ; pop edi pop esi mov esp, ebp pop ebp ret BlCopySection endp ;++ ; ; VOID ; BlInvalidImage( ; VOID ; ) ; ; Routine Description: ; ; This function is called to halt execution if the embedded image is corrupted. ; ;-- BlInvalidImage proc call BlHalt BlInvalidImage endp ;++ ; ; VOID ; BlRegisterExitAddress( ; VOID ; ) ; ; Routine Description: ; ; This function registers the exit address in the boot environment block. ; ;-- BlRegisterExitAddress proc mov ecx, BEB_BASE lea eax, BlLeaveProtectedMode add eax, REAL_MODE_BASE mov dword ptr [ecx].BEB.LegacyCallAddress, eax ret BlRegisterExitAddress endp ;++ ; ; VOID ; BlApEntry32( ; VOID ; ) ; ; Routine Description: ; ; This function implements 32-bit entry point for application processors. ; ;-- BlApEntry32 proc ; ; Load the protected-mode segment registers. ; mov ax, PM_DATA_SELECTOR mov ds, ax mov es, ax mov ss, ax mov esp, PM_INITIAL_ESP mov ax, NULL_SELECTOR mov fs, ax mov gs, ax ; ; Enable PSE, PAE, performance counters, and floating point support. ; mov eax, cr4 or eax, CR4_PSE OR CR4_PAE OR CR4_PCE OR CR4_OSFXSR mov cr4, eax ; ; Set root page table. ; mov eax, BEB_BASE mov eax, dword ptr [eax].BEB.LegacyReturnCr3 mov cr3, eax ifdef BOOT_X64 ; ; Enable long-mode and no-execute. ; mov ecx, EFER_MSR_INDEX rdmsr or eax, EFER_LME OR EFER_NXE wrmsr endif ; ; Enable paging. ; mov eax, cr0 or eax, CR0_PG mov cr0, eax ; ; Get entry address from BEB. ; mov eax, BEB_BASE mov eax, dword ptr [eax].BEB.ApEntry ifdef BOOT_X64 ; ; Enter long mode. ; JMPF32 LM_CODE_SELECTOR, REAL_MODE_BASE + OFFSET @f @@: mov edx, LM_DATA_SELECTOR mov ds, edx mov es, edx mov ss, edx endif ; ; Switch to entry stack and call entry point. ; mov esp, BL_ENTRY_SP call eax BlApEntry32 endp ;++ ; ; VOID ; BlLeaveLrb64ToBoot( ; VOID ; ) ; ; Routine Description: ; ; This function leaves paging and protected mode to boot. ; ;-- ALIGN 16 db 'S','I','N','G' db 'L','R','B',0 db 0f8h, 0f9h, 0fah, 0fbh db 0fch, 0fdh, 0feh, 0ffh BlFlashImage: dd 0 BlSmapAddr: dd 0 BlSmapSize: dd 0 dd 0 BlLeaveLrb64ToBoot proc mov eax, BLUE + 'P' mov esi, VIDEO_BASE + 0 mov [esi], ax mov eax, BLUE + 'O' mov esi, VIDEO_BASE + 2 mov [esi], ax mov eax, BLUE + 'N' mov esi, VIDEO_BASE + 4 mov [esi], ax mov eax, BLUE + 'M' mov esi, VIDEO_BASE + 6 mov [esi], ax mov eax, BLUE + 'L' mov esi, VIDEO_BASE + 8 mov [esi], ax ; ; Prepare a known GDT. ; mov eax, BLUE + 'K' mov esi, VIDEO_BASE + 10 mov [esi], ax mov eax, BLUE + 'J' mov esi, VIDEO_BASE + 12 mov [esi], ax ; ; Load the known GDT. ; mov edi, BlGDTS_Limit add edi, REAL_MODE_BASE lgdt fword ptr ds:[edi] mov eax, RED + 'R' mov esi, VIDEO_BASE + 8 mov [esi], ax mov eax, RED + 'S' mov esi, VIDEO_BASE + 10 mov [esi], ax mov edi, REAL_MODE_BASE + offset target jmp fword ptr [edi] target: dd OFFSET BlLeaveLrbPmToBoot dw RM_CODE_SELECTOR BlLeaveLrb64ToBoot endp ; ; Align to 16-bytes before PE image is concatenated. ; ALIGN 16 BlImageStart: _TEXT32 ends end BlEntry16 ================================================ FILE: ironclad-apps/src/Checked/BootLoader/SingLdrPc/blfat.cpp ================================================ //++ // // Copyright (c) Microsoft Corporation // // Module Name: // // blfat.cpp // // Abstract: // // This module implements FAT support for the boot loader. // //-- #include "bl.h" // // MBR definitions. // #pragma pack(1) #define MBR_BOOTABLE 0x80 typedef struct _MBR_PARTITION { UINT8 Status; UINT8 FirstSectorCHS[3]; UINT8 Type; UINT8 LastSectorCHS[3]; UINT32 FirstSector; UINT32 NumberOfSectors; } MBR_PARTITION, *PMBR_PARTITION; C_ASSERT(sizeof(MBR_PARTITION) == 16); #define MBR_SIGNATURE 0xAA55 typedef struct _MBR { UINT8 BootCode[446]; MBR_PARTITION Partition[4]; UINT16 Signature; } MBR, *PMBR; C_ASSERT(sizeof(MBR) == 512); #pragma pack() // // FAT definitions. // #define FAT_SECTOR_SIZE 512 #define FAT_FIRST_DATA_CLUSTER 2 #define FAT16_CLUSTER_MASK 0xFFFF #define FAT16_LINK_TERMINATOR 0xFFFF #define FAT32_CLUSTER_MASK 0x0FFFFFFF #define FAT32_LINK_TERMINATOR 0x0FFFFFFF #pragma pack(1) typedef struct __declspec(align(FAT_SECTOR_SIZE)) _FAT_SECTOR { UINT8 Data[FAT_SECTOR_SIZE]; } FAT_SECTOR, *PFAT_SECTOR; typedef struct _FAT16_BOOT_SECTOR { UINT8 JumpInstruction[3]; UINT8 OemName[8]; UINT16 BytesPerSector; UINT8 SectorsPerCluster; UINT16 NumberOfReservedSectors; UINT8 NumberOfFATs; UINT16 NumberOfRootDirectoryEntries; UINT16 TotalSectorCount16; UINT8 Media; UINT16 SectorsPerFAT; UINT16 SectorsPerTrack; UINT16 NumberOfHeads; UINT32 NumberOfHiddenSectors; UINT32 TotalSectorCount32; UINT8 DriveNumber; UINT8 Reserved1; UINT8 ExtendedBootSignature; UINT32 VolumeSerialNumber; UINT8 VolumeLabel[11]; UINT8 FileSystemType[8]; UINT8 BootCode[448]; UINT16 Signature; } FAT16_BOOT_SECTOR, *PFAT16_BOOT_SECTOR; C_ASSERT(sizeof(FAT16_BOOT_SECTOR) == FAT_SECTOR_SIZE); typedef struct _FAT32_BOOT_SECTOR { UINT8 JumpInstruction[3]; UINT8 OemName[8]; UINT16 BytesPerSector; UINT8 SectorsPerCluster; UINT16 NumberOfReservedSectors; UINT8 NumberOfFATs; UINT16 NumberOfRootDirectoryEntries; UINT16 TotalSectorCount16; UINT8 Media; UINT16 SectorsPerFAT16; UINT16 SectorsPerTrack; UINT16 NumberOfHeads; UINT32 NumberOfHiddenSectors; UINT32 TotalSectorCount32; UINT32 SectorsPerFAT32; UINT16 Flags; UINT16 FileSystemVersion; UINT32 RootDirectoryFirstCluster; UINT16 FileSystemInfoSector; UINT16 BackupBootSector; UINT8 Reserved[12]; UINT8 DriveNumber; UINT8 Reserved1; UINT8 ExtendedBootSignature; UINT32 VolumeSerialNumber; UINT8 VolumeLabel[11]; UINT8 FileSystemType[8]; UINT8 BootCode[420]; UINT16 Signature; } FAT32_BOOT_SECTOR, *PFAT32_BOOT_SECTOR; C_ASSERT(sizeof(FAT32_BOOT_SECTOR) == FAT_SECTOR_SIZE); typedef struct _FAT_BOOT_SECTOR { union { FAT16_BOOT_SECTOR Fat16; FAT32_BOOT_SECTOR Fat32; } u1; } FAT_BOOT_SECTOR, *PFAT_BOOT_SECTOR; C_ASSERT(sizeof(FAT_BOOT_SECTOR) == FAT_SECTOR_SIZE); #define FAT_DIRECTORY_ENTRY_FREE 0xE5 #define FAT_DIRECTORY_ENTRY_LAST 0x00 #define FAT_ATTRIBUTE_READ_ONLY 0x01 #define FAT_ATTRIBUTE_HIDDEN 0x02 #define FAT_ATTRIBUTE_SYSTEM 0x04 #define FAT_ATTRIBUTE_VOLUME_ID 0x08 #define FAT_ATTRIBUTE_DIRECTORY 0x10 #define FAT_ATTRIBUTE_ARCHIVE 0x20 #define FAT_ATTRIBUTE_LONG_NAME (FAT_ATTRIBUTE_READ_ONLY | FAT_ATTRIBUTE_HIDDEN | FAT_ATTRIBUTE_SYSTEM | FAT_ATTRIBUTE_VOLUME_ID) #define FAT_ATTRIBUTE_MASK 0x3F #define FAT_LONG_NAME_TERMINATOR 0x40 #define FAT_LONG_NAME_ORDER_MASK 0x3F typedef struct _FAT_DIRECTORY_ENTRY { union { struct { UINT8 Name[11]; UINT8 Attribute; UINT8 ReservedForNT; UINT8 CreationTime[3]; UINT8 CreationDate[2]; UINT8 LastAccessDate[2]; UINT16 FirstClusterHigh; UINT8 ModificationTime[2]; UINT8 ModificationDate[2]; UINT16 FirstClusterLow; UINT32 Size; } Short; struct { UINT8 Order; WCHAR NameW1_5[5]; UINT8 Attribute; UINT8 Type; UINT8 Checksum; WCHAR NameW6_11[6]; UINT16 Zero; WCHAR NameW12_13[2]; } Long; } u1; } FAT_DIRECTORY_ENTRY, *PFAT_DIRECTORY_ENTRY; C_ASSERT(sizeof(FAT_DIRECTORY_ENTRY) == 32); #define FAT_MAX_PATH 255 typedef struct _FAT_NAME { UINT8 ShortName[13]; UINT8 LongName[FAT_MAX_PATH + 1]; } FAT_NAME, *PFAT_NAME; #pragma pack() FAT_BOOT_SECTOR BlFatBootSector; UINT32 BlFatBytesPerCluster; UINT32 BlFatDataStart; UINT8 BlFatDriveId; INT13_DRIVE_PARAMETERS BlFatDriveParameters; UINT32 BlFatLinkTerminator; MBR BlFatMbr; UINT32 BlFatNumberOfDataClusters; UINT32 BlFatNumberOfRootDirectoryEntries; UINT32 BlFatPartitionId; UINT32 BlFatPartitionStart; UINT32 BlFatPartitionSize; PFAT_DIRECTORY_ENTRY BlFatRootDirectory; UINT32 BlFatRootStart; UINT32 BlFatSectorsPerCluster; UINT32 BlFatTableStart; FAT_SECTOR BlFatTemporaryBlock[64]; UINT16 BlFatTemporaryBlockCount = sizeof(BlFatTemporaryBlock) / sizeof(BlFatTemporaryBlock[0]); UINT32 BlFatTotalSectorCount; #define FAT_IS_DATA_CLUSTER(X) (((X) >= FAT_FIRST_DATA_CLUSTER) && (((X) - FAT_FIRST_DATA_CLUSTER) < BlFatNumberOfDataClusters)) #define FAT_DATA_CLUSTER_TO_SECTOR(X) (BlFatDataStart + (((X) - 2) * BlFatSectorsPerCluster)) #define FAT_IS_TERMINATOR(X) (((UINT32) (X)) == BlFatLinkTerminator) #define BlFatHalt() BlFatHaltInternal(__LINE__) BOOLEAN (*BlFatGetNextCluster)( UINT32 Cluster, PUINT32 NextCluster ); VOID BlFatHaltInternal( UINT32 Line ) //++ // // Routine Description: // // Prints an error message and halts. // //-- { BlRtlPrintf("FAT: Error reading disk image!\n"); BlRtlHaltInternal(__FILE__, Line); } BOOLEAN BlFatReadSector( UINT32 FirstSector, UINT32 NumberOfSectors, PFAT_SECTOR Buffer ) //++ // // Routine Description: // // This function reads the specified range of sectors. // // Arguments: // // FirstSector - Supplies the first sector to read. // // NumberOfSectors - Supplies the number of sectors to read. // // Buffer - Receives data. // // Return Value: // // TRUE, if read operation was successful. // FALSE, otherwise. // //-- { UINT16 StepSize; BLASSERT_PTR(FirstSector < BlFatTotalSectorCount, FirstSector); BLASSERT(NumberOfSectors > 0); BLASSERT(FirstSector + NumberOfSectors > FirstSector); BLASSERT((FirstSector + NumberOfSectors) < BlFatTotalSectorCount); while (NumberOfSectors > 0) { if (NumberOfSectors < BlFatTemporaryBlockCount) { StepSize = (UINT16) NumberOfSectors; } else { StepSize = BlFatTemporaryBlockCount; } if (BlRtlReadDrive(BlFatDriveId, BlFatPartitionStart + FirstSector, StepSize, BlFatTemporaryBlock) == FALSE) { #if FAT_VERBOSE BlRtlPrintf("FAT: I/O error reading sector %u on drive 0x%02x!\n", BlFatPartitionStart + FirstSector, BlFatDriveId); #endif return FALSE; } BlRtlCopyMemory(Buffer, BlFatTemporaryBlock, StepSize * FAT_SECTOR_SIZE); FirstSector += StepSize; NumberOfSectors -= StepSize; Buffer += StepSize; } return TRUE; } BOOLEAN BlFatDirectoryEntryToName( PFAT_DIRECTORY_ENTRY ShortEntry, PFAT_NAME Name, PFAT_DIRECTORY_ENTRY TableStart ) //++ // // Routine Description: // // This function extracts FAT short and long names from the specified directory entry. // // Arguments: // // ShortEntry - Supplies a pointer to the short name entry. // // Name - Receives short and long names. // // TableStart - Supplies the start address for the directory table. // // Return Value: // // TRUE, if names were extracted successfully. // FALSE, otherwise. // //-- { UINT8 Character; PFAT_DIRECTORY_ENTRY Entry; UINT8 LongNameComponentIndex; UINT32 SourceIndex; UINT32 TargetIndex; if ((ShortEntry->u1.Short.Attribute & FAT_ATTRIBUTE_MASK) == FAT_ATTRIBUTE_LONG_NAME) { return FALSE; } // // Extract short name. // TargetIndex = 0; for (SourceIndex = 0; SourceIndex < 8; SourceIndex += 1) { Character = ShortEntry->u1.Short.Name[SourceIndex]; if (Character == ' ') { if (SourceIndex == 0) { return FALSE; } break; } if (Character == '.') { return FALSE; } Name->ShortName[TargetIndex] = Character; TargetIndex += 1; } if (ShortEntry->u1.Short.Name[8] != ' ') { Name->ShortName[TargetIndex] = '.'; TargetIndex += 1; for (SourceIndex = 8; SourceIndex < 11; SourceIndex += 1) { Character = ShortEntry->u1.Short.Name[SourceIndex]; if (Character == ' ') { break; } if (Character == '.') { return FALSE; } Name->ShortName[TargetIndex] = Character; TargetIndex += 1; } } Name->ShortName[TargetIndex] = 0; // // If there is a long name, extract it by walking backwards from the short entry. // Otherwise, set long name to empty string. // Name->LongName[0] = 0; Entry = ShortEntry - 1; if (Entry < TableStart) { return TRUE; } if ((Entry->u1.Short.Attribute & FAT_ATTRIBUTE_MASK) != FAT_ATTRIBUTE_LONG_NAME) { return TRUE; } LongNameComponentIndex = 1; TargetIndex = 0; for (;;) { if (TargetIndex == FAT_MAX_PATH) { return FALSE; } if (Entry < TableStart) { return FALSE; } if ((Entry->u1.Long.Order & FAT_LONG_NAME_ORDER_MASK) != LongNameComponentIndex) { return FALSE; } #define ADD_CHARACTER(C) \ \ if (TargetIndex == FAT_MAX_PATH) { \ \ return FALSE; \ } \ \ if (((C) != 0) && ((C) != 0xFFFF)) { \ \ Name->LongName[TargetIndex] = (UINT8) (C); \ TargetIndex += 1; \ } ADD_CHARACTER(Entry->u1.Long.NameW1_5[0]); ADD_CHARACTER(Entry->u1.Long.NameW1_5[1]); ADD_CHARACTER(Entry->u1.Long.NameW1_5[2]); ADD_CHARACTER(Entry->u1.Long.NameW1_5[3]); ADD_CHARACTER(Entry->u1.Long.NameW1_5[4]); ADD_CHARACTER(Entry->u1.Long.NameW6_11[0]); ADD_CHARACTER(Entry->u1.Long.NameW6_11[1]); ADD_CHARACTER(Entry->u1.Long.NameW6_11[2]); ADD_CHARACTER(Entry->u1.Long.NameW6_11[3]); ADD_CHARACTER(Entry->u1.Long.NameW6_11[4]); ADD_CHARACTER(Entry->u1.Long.NameW6_11[5]); ADD_CHARACTER(Entry->u1.Long.NameW12_13[0]); ADD_CHARACTER(Entry->u1.Long.NameW12_13[1]); #undef ADD_CHARACTER if ((Entry->u1.Long.Order & FAT_LONG_NAME_TERMINATOR)) { break; } Entry -= 1; LongNameComponentIndex += 1; } Name->LongName[TargetIndex] = 0; return TRUE; } PFAT_DIRECTORY_ENTRY BlFatFindDirectoryTableEntry( PFAT_DIRECTORY_ENTRY Table, UINT32 NumberOfEntries, PCSTR Name ) //++ // // Routine Description: // // This function finds the directory table entry matching the specified name. // // Arguments: // // Table - Supplies a pointer to the table to find in. // // NumberOfEntries - Supplies the number of entries in the table. // // Name - Supplies the name to look for. // // Return Value: // // TRUE, if a matching entry was located. // FALSE, otherwise. // //-- { PFAT_DIRECTORY_ENTRY Entry; FAT_NAME EntryName; PFAT_DIRECTORY_ENTRY Limit; BLASSERT(Name[0] != 0); Limit = Table + NumberOfEntries; for (Entry = Table; Entry != Limit; Entry += 1) { if (Entry->u1.Short.Name[0] == FAT_DIRECTORY_ENTRY_FREE) { continue; } if (Entry->u1.Short.Name[0] == FAT_DIRECTORY_ENTRY_LAST) { break; } if (Entry->u1.Short.Name[0] == '.') { continue; } if ((Entry->u1.Short.Attribute & FAT_ATTRIBUTE_MASK) == FAT_ATTRIBUTE_VOLUME_ID) { continue; } if (BlFatDirectoryEntryToName(Entry, &EntryName, Table) != FALSE) { if ((BlRtlEqualStringI(Name, (PCSTR) EntryName.ShortName) != FALSE) || (BlRtlEqualStringI(Name, (PCSTR) EntryName.LongName) != FALSE)) { return Entry; } } } return NULL; } BOOLEAN BlFatGetLengthClusterChain( UINT32 Cluster, PUINT32 Length ) //++ // // Routine Description: // // This function queries the length of the specified cluster chain. // // Arguments: // // Cluster - Supplies the index of the first cluster in the chain. // // Length - Receives the length of the chain. // // Return Value: // // TRUE, if query operation was successful. // FALSE, otherwise. // //-- { *Length = 0; do { if (FAT_IS_DATA_CLUSTER(Cluster) == FALSE) { return FALSE; } if (BlFatGetNextCluster(Cluster, &Cluster) == FALSE) { return FALSE; } *Length += 1; } while (Cluster != BlFatLinkTerminator); return TRUE; } BOOLEAN BlFatReadClusterChain( UINT32 Cluster, UINT32 BytesToRead, PVOID Buffer ) //++ // // Routine Description: // // This function reads from the specified FAT data cluster chain. // // Arguments: // // Cluster - Supplies the index of the first cluster in the chain. // // BytesToRead - Supplies number of bytes to read. // // Buffer - Receives data. // // Return Value: // // TRUE, if read operation was successful. // FALSE, otherwise. // //-- { PVOID ClusterData; PUINT8 Next; UINT32 Sector; BLASSERT_PTR(FAT_IS_DATA_CLUSTER(Cluster) != FALSE, Cluster); BLASSERT(BytesToRead > 0); Next = (PUINT8) Buffer; for (;;) { // // If the cluster number is not within the valid data range, then fail the read operation. // if (FAT_IS_DATA_CLUSTER(Cluster) == FALSE) { #if FAT_VERBOSE BlRtlPrintf("FAT: ReadClusterChain: Cluster %u is out of range!\n", Cluster); #endif return FALSE; } // // Calculate the first sector in the cluster. // Sector = FAT_DATA_CLUSTER_TO_SECTOR(Cluster); // // If remaining bytes to read is less than the cluster size, then read it using a // temporary buffer, since the caller provided buffer is not necessarily a multiple // of cluster size. // if (BytesToRead < BlFatBytesPerCluster) { ClusterData = BlPoolAllocateBlock(BlFatBytesPerCluster); if (BlFatReadSector(Sector, ROUND_UP_TO_POWER2(BytesToRead, FAT_SECTOR_SIZE) / FAT_SECTOR_SIZE, (PFAT_SECTOR) ClusterData) == FALSE) { BlPoolFreeBlock(ClusterData); return FALSE; } BlRtlCopyMemory(Next, ClusterData, BytesToRead); BlPoolFreeBlock(ClusterData); return TRUE; } // // Otherwise, read the entire cluster and advance by full cluster size. // if (BlFatReadSector(Sector, BlFatSectorsPerCluster, (PFAT_SECTOR) Next) == FALSE) { return FALSE; } BytesToRead -= BlFatBytesPerCluster; Next += BlFatBytesPerCluster; if (BytesToRead == 0) { return TRUE; } // // Get the next cluster index. // if (BlFatGetNextCluster(Cluster, &Cluster) == FALSE) { return FALSE; } } } BOOLEAN BlFatFindFileEntry( PCSTR Path, PFAT_DIRECTORY_ENTRY FileEntry ) //++ // // Routine Description: // // This function finds the entry matching the specified file path. // // Arguments: // // Path - Supplies a pointer to the path to look up. // // FileEntry - Receives the contents of the entry matching the specified path. // // Return Value: // // TRUE, if a match was found. // FALSE, otherwise. // //-- { UINT32 DirectoryCluster; UINT32 DirectoryClusterCount; UINT32 Depth; FAT_DIRECTORY_ENTRY Entry; PFAT_DIRECTORY_ENTRY Match; PCSTR Next; PFAT_DIRECTORY_ENTRY Table; UINT32 TableSize; UINT8 Token[FAT_MAX_PATH]; UINT32 TokenIndex; if ((Path[0] == 0) || (Path[0] == '/') || (BlRtlStringLength(Path) >= FAT_MAX_PATH)) { return FALSE; } Next = Path; Depth = 0; SATISFY_OVERZEALOUS_COMPILER(BlRtlZeroMemory(&Entry, sizeof(Entry))); for (;;) { if (*Next == 0) { if ((Entry.u1.Short.Attribute & FAT_ATTRIBUTE_DIRECTORY) != 0) { #if FAT_VERBOSE BlRtlPrintf("FAT: FindFileEntry: %s is a directory!\n", Path); #endif return FALSE; } *FileEntry = Entry; return TRUE; } // // If the next token is empty (i.e. back to back separators), then this is a malformed path. // if (*Next == '/') { #if FAT_VERBOSE BlRtlPrintf("FAT: FindFileEntry: %s is a malformed path!\n", Path); #endif return FALSE; } // // Extract the next token. // TokenIndex = 0; for (;;) { if (*Next == 0) { break; } if (*Next == '/') { Next += 1; break; } Token[TokenIndex] = *Next; TokenIndex += 1; Next += 1; } BLASSERT(TokenIndex > 0); Token[TokenIndex] = 0; if (Depth == 0) { Table = BlFatRootDirectory; TableSize = BlFatNumberOfRootDirectoryEntries; } else { DirectoryCluster = Entry.u1.Short.FirstClusterLow; if (BlFatGetLengthClusterChain(DirectoryCluster, &DirectoryClusterCount) == FALSE) { return FALSE; } Table = (PFAT_DIRECTORY_ENTRY) BlPoolAllocateBlock(DirectoryClusterCount * BlFatBytesPerCluster); if (BlFatReadClusterChain(DirectoryCluster, DirectoryClusterCount * BlFatBytesPerCluster, Table) == FALSE) { BlPoolFreeBlock(Table); return FALSE; } TableSize = (DirectoryClusterCount * BlFatBytesPerCluster) / sizeof(FAT_DIRECTORY_ENTRY); } // // Walk the directory table matching the previous token for an entry matching the next token. // Match = BlFatFindDirectoryTableEntry(Table, TableSize, (PCSTR) Token); if (Match == NULL) { #if FAT_VERBOSE BlRtlPrintf("FAT: FindFileEntry: Unable to find directory entry for token %s.\n", Token); #endif if (Table != BlFatRootDirectory) { BlPoolFreeBlock(Table); } return FALSE; } Entry = *Match; if (Table != BlFatRootDirectory) { BlPoolFreeBlock(Table); } Depth += 1; } } BOOLEAN BlFatGetFileSize( PCSTR Path, PUINT32 FileSize ) //++ // // Routine Description: // // This function queries the size of the specified file. // // Arguments: // // Path - Supplies the path to the file to query. // // FileSize - Receives the size of the file. // // Return Value: // // TRUE, if the query operation was successful. // FALSE, otherwise. // //-- { FAT_DIRECTORY_ENTRY Entry; if (BlFatFindFileEntry(Path, &Entry) == FALSE) { return FALSE; } *FileSize = Entry.u1.Short.Size; return TRUE; } BOOLEAN BlFatReadFile( PCSTR Path, PVOID Buffer, UINT32 NumberOfBytes ) //++ // // Routine Description: // // This function reads from the specified file. // // Arguments: // // Path - Supplies the path to the file to read. // // Buffer - Receives data. // // NumberOfBytes - Supplies the number of bytes to read. // // Return Value: // // TRUE, if the read operation was successful. // FALSE, otherwise. // //-- { FAT_DIRECTORY_ENTRY Entry; BOOLEAN Result; if (BlFatFindFileEntry(Path, &Entry) == FALSE) { return FALSE; } if (NumberOfBytes > Entry.u1.Short.Size) { return FALSE; } Result = BlFatReadClusterChain(Entry.u1.Short.FirstClusterLow, NumberOfBytes, Buffer); return Result; } BOOLEAN BlFat16GetNextCluster( UINT32 Cluster, PUINT32 NextCluster ) //++ // // Routine Description: // // This function gets the index of the cluster following the specified cluster. // // Arguments: // // Cluster - Supplies the index of the cluster. // // NextCluster - Receives the index of the next cluster. // // Return Value: // // TRUE, if query operation was successful. // FALSE, otherwise. // //-- { UINT32 Offset; UINT32 Sector; FAT_SECTOR TablePage; if (FAT_IS_DATA_CLUSTER(Cluster) == FALSE) { #if FAT_VERBOSE BlRtlPrintf("FAT: Fat16GetNextCluster: Cluster %u is out of range!\n", Cluster); #endif return FALSE; } Sector = BlFatTableStart + (Cluster / 256); Offset = Cluster % 256; if (BlFatReadSector(Sector, 1, &TablePage) == FALSE) { return FALSE; } *NextCluster = (UINT32) (((PUINT16) &TablePage)[Offset]); return TRUE; } VOID BlFat16Initialize( VOID ) //++ // // Routine Description: // // This function initializes FAT16 support. // //-- { PFAT16_BOOT_SECTOR BootSector; BootSector = &BlFatBootSector.u1.Fat16; BLASSERT(BlFatMbr.Partition[BlFatPartitionId].Type == MBR_FAT16LBA); // // Read FAT16 boot sector. // if (BlRtlReadDrive(BlFatDriveId, BlFatPartitionStart, 1, BootSector) == FALSE) { #if FAT_VERBOSE BlRtlPrintf("FAT: Error reading boot sector!\n"); #endif BlFatHalt(); } // // Extract volume geometry. // if (BootSector->BytesPerSector != FAT_SECTOR_SIZE) { #if FAT_VERBOSE BlRtlPrintf("FAT: Unsupported sector size (%u)!\n", BootSector->BytesPerSector); #endif BlFatHalt(); } BlFatSectorsPerCluster = BootSector->SectorsPerCluster; if (BlFatSectorsPerCluster == 0) { #if FAT_VERBOSE BlRtlPrintf("FAT: SectorsPerCluster == 0!\n"); #endif BlFatHalt(); } BlFatBytesPerCluster = BlFatSectorsPerCluster * FAT_SECTOR_SIZE; if (BootSector->TotalSectorCount32 > 0) { BlFatTotalSectorCount = BootSector->TotalSectorCount32; } else { BlFatTotalSectorCount = BootSector->TotalSectorCount16; } if (BlFatTotalSectorCount > BlFatPartitionSize) { #if FAT_VERBOSE BlRtlPrintf("FAT: Boot sector claims more sectors than MBR!\n"); #endif BlFatHalt(); } if (BootSector->NumberOfFATs == 0) { #if FAT_VERBOSE BlRtlPrintf("FAT: NumberOfFATs == 0!\n"); #endif BlFatHalt(); } if (BootSector->SectorsPerFAT == 0) { #if FAT_VERBOSE BlRtlPrintf("FAT: SectorsPerFAT == 0!\n"); #endif BlFatHalt(); } BlFatNumberOfRootDirectoryEntries = BootSector->NumberOfRootDirectoryEntries; if ((BlFatNumberOfRootDirectoryEntries == 0) || ((BlFatNumberOfRootDirectoryEntries % 64) != 0)) { #if FAT_VERBOSE BlRtlPrintf("FAT: Invalid number of root directory entries (%u)!\n", BlFatNumberOfRootDirectoryEntries); #endif BlFatHalt(); } BlFatTableStart = BootSector->NumberOfReservedSectors; if (BlFatTotalSectorCount < BlFatTableStart) { #if FAT_VERBOSE BlRtlPrintf("FAT: TotalSectorCount < TableStart!\n"); #endif BlFatHalt(); } BlFatRootStart = BlFatTableStart + (BootSector->NumberOfFATs * BootSector->SectorsPerFAT); if (BlFatTotalSectorCount < BlFatRootStart) { #if FAT_VERBOSE BlRtlPrintf("FAT: TotalSectorCount < RootStart!\n"); #endif BlFatHalt(); } BlFatDataStart = BlFatRootStart + (ROUND_UP_TO_POWER2(BlFatNumberOfRootDirectoryEntries * sizeof(FAT_DIRECTORY_ENTRY), FAT_SECTOR_SIZE) / FAT_SECTOR_SIZE); if (BlFatTotalSectorCount < BlFatDataStart) { #if FAT_VERBOSE BlRtlPrintf("FAT: TotalSectorCount < DataStart!\n"); #endif BlFatHalt(); } BlFatNumberOfDataClusters = (BlFatTotalSectorCount - BlFatDataStart) / BlFatSectorsPerCluster; if (BlFatNumberOfDataClusters == 0) { #if FAT_VERBOSE BlRtlPrintf("FAT: NumberOfDataClusters == 0!\n"); #endif BlFatHalt(); } BlFatLinkTerminator = FAT16_LINK_TERMINATOR; BlFatGetNextCluster = BlFat16GetNextCluster; // // Read root directory. // BlFatRootDirectory = (PFAT_DIRECTORY_ENTRY) BlPoolAllocateBlock((BlFatDataStart - BlFatRootStart) * FAT_SECTOR_SIZE); if (BlFatReadSector(BlFatRootStart, BlFatDataStart - BlFatRootStart, (PFAT_SECTOR) BlFatRootDirectory) == FALSE) { #if FAT_VERBOSE BlRtlPrintf("FAT: Error reading root directory!\n"); #endif BlFatHalt(); } BLASSERT(FAT_IS_DATA_CLUSTER(FAT16_LINK_TERMINATOR) == FALSE); return; } BOOLEAN BlFat32GetNextCluster( UINT32 Cluster, PUINT32 NextCluster ) //++ // // Routine Description: // // This function gets the index of the cluster following the specified cluster. // // Arguments: // // Cluster - Supplies the index of the cluster. // // NextCluster - Receives the index of the next cluster. // // Return Value: // // TRUE, if query operation was successful. // FALSE, otherwise. // //-- { UINT32 Offset; UINT32 Sector; FAT_SECTOR TablePage; if (FAT_IS_DATA_CLUSTER(Cluster) == FALSE) { #if FAT_VERBOSE BlRtlPrintf("FAT: Fat32GetNextCluster: Cluster %u is out of range!\n", Cluster); #endif return FALSE; } Sector = BlFatTableStart + (Cluster / 128); Offset = Cluster % 128; if (BlFatReadSector(Sector, 1, &TablePage) == FALSE) { return FALSE; } *NextCluster = ((PUINT32) &TablePage)[Offset]; return TRUE; } VOID BlFat32Initialize( VOID ) //++ // // Routine Description: // // This function initializes FAT32 support. // //-- { PFAT32_BOOT_SECTOR BootSector; UINT32 RootDirectoryChainLength; BootSector = &BlFatBootSector.u1.Fat32; BLASSERT(BlFatMbr.Partition[BlFatPartitionId].Type == MBR_FAT32LBA); // // Read FAT32 boot sector. // if (BlRtlReadDrive(BlFatDriveId, BlFatPartitionStart, 1, BootSector) == FALSE) { #if FAT_VERBOSE BlRtlPrintf("FAT: Error reading boot sector!\n"); #endif BlFatHalt(); } // // Extract volume geometry. // if (BootSector->BytesPerSector != FAT_SECTOR_SIZE) { #if FAT_VERBOSE BlRtlPrintf("FAT: Unsupported sector size (%u)!\n", BootSector->BytesPerSector); #endif BlFatHalt(); } BlFatSectorsPerCluster = BootSector->SectorsPerCluster; if (BlFatSectorsPerCluster == 0) { #if FAT_VERBOSE BlRtlPrintf("FAT: SectorsPerCluster == 0!\n"); #endif BlFatHalt(); } BlFatBytesPerCluster = BlFatSectorsPerCluster * FAT_SECTOR_SIZE; if (BootSector->TotalSectorCount32 > 0) { BlFatTotalSectorCount = BootSector->TotalSectorCount32; } else { BlFatTotalSectorCount = BootSector->TotalSectorCount16; } if (BlFatTotalSectorCount > BlFatPartitionSize) { #if FAT_VERBOSE BlRtlPrintf("FAT: Boot sector claims more sectors than MBR!\n"); #endif BlFatHalt(); } if (BootSector->NumberOfFATs == 0) { #if FAT_VERBOSE BlRtlPrintf("FAT: NumberOfFATs == 0!\n"); #endif BlFatHalt(); } if (BootSector->SectorsPerFAT32 == 0) { #if FAT_VERBOSE BlRtlPrintf("FAT: SectorsPerFAT == 0!\n"); #endif BlFatHalt(); } if (BootSector->NumberOfRootDirectoryEntries != 0) { #if FAT_VERBOSE BlRtlPrintf("FAT: BootSector->NumberOfRootDirectoryEntries != 0!\n"); #endif BlFatHalt(); } BlFatTableStart = BootSector->NumberOfReservedSectors; if (BlFatTotalSectorCount < BlFatTableStart) { #if FAT_VERBOSE BlRtlPrintf("FAT: TotalSectorCount < TableStart!\n"); #endif BlFatHalt(); } BlFatDataStart = BlFatTableStart + (BootSector->NumberOfFATs * BootSector->SectorsPerFAT32); if (BlFatTotalSectorCount < BlFatDataStart) { #if FAT_VERBOSE BlRtlPrintf("FAT: TotalSectorCount < DataStart!\n"); #endif BlFatHalt(); } BlFatNumberOfDataClusters = (BlFatTotalSectorCount - BlFatDataStart) / BlFatSectorsPerCluster; if (BlFatNumberOfDataClusters == 0) { #if FAT_VERBOSE BlRtlPrintf("FAT: NumberOfDataClusters == 0!\n"); #endif BlFatHalt(); } BlFatLinkTerminator = FAT32_LINK_TERMINATOR; BlFatGetNextCluster = BlFat32GetNextCluster; // // Read root directory. // if (BlFatGetLengthClusterChain(BootSector->RootDirectoryFirstCluster, &RootDirectoryChainLength) == FALSE) { #if FAT_VERBOSE BlRtlPrintf("FAT: Error querying chain length of root directory!\n"); #endif BlFatHalt(); } BlFatRootDirectory = (PFAT_DIRECTORY_ENTRY) BlPoolAllocateBlock(RootDirectoryChainLength * BlFatBytesPerCluster); if (BlFatReadClusterChain(BootSector->RootDirectoryFirstCluster, RootDirectoryChainLength * BlFatBytesPerCluster, BlFatRootDirectory) == FALSE) { #if FAT_VERBOSE BlRtlPrintf("FAT: Error reading root directory!\n"); #endif BlFatHalt(); } BlFatNumberOfRootDirectoryEntries = (RootDirectoryChainLength * BlFatBytesPerCluster) / sizeof(FAT_DIRECTORY_ENTRY); BLASSERT(FAT_IS_DATA_CLUSTER(FAT32_LINK_TERMINATOR) == FALSE); return; } VOID BlFatInitialize( UINT8 DriveId, UINT8 FatType ) //++ // // Routine Description: // // This function initializes FAT support. // // Arguments: // // DriveId - Supplies boot drive ID. // // FatType - Supplies the FAT type to look for. // //-- { UINT32 Index; BLASSERT((FatType == MBR_FAT16LBA) || (FatType == MBR_FAT32LBA)); if (BlRtlGetDriveParameters(DriveId, &BlFatDriveParameters) == FALSE) { BlRtlPrintf("FAT: Can't get drive info 0x%02x!\n", DriveId); BlRtlHalt(); } if (BlFatDriveParameters.BytesPerSector != FAT_SECTOR_SIZE) { BlRtlPrintf("FAT: Unexpected bytes per sector (%u)!\n", BlFatDriveParameters.BytesPerSector); BlRtlHalt(); } if (BlRtlReadDrive(DriveId, 0, 1, &BlFatMbr) == FALSE) { BlRtlPrintf("FAT: Error reading MBR!\n"); BlRtlHalt(); } if (BlFatMbr.Signature != MBR_SIGNATURE) { BlRtlPrintf("FAT: No MBR signature!\n"); } BlFatPartitionId = (UINT32) -1; for (Index = 0; Index <= 4; Index += 1) { if (FatType == BlFatMbr.Partition[Index].Type) { switch (BlFatMbr.Partition[Index].Type) { case MBR_FAT16LBA: { BlFatDriveId = DriveId; BlFatPartitionId = Index; BlFatPartitionStart = BlFatMbr.Partition[Index].FirstSector; BlFatPartitionSize = BlFatMbr.Partition[Index].NumberOfSectors; BlFat16Initialize(); break; } case MBR_FAT32LBA: { BlFatDriveId = DriveId; BlFatPartitionId = Index; BlFatPartitionStart = BlFatMbr.Partition[Index].FirstSector; BlFatPartitionSize = BlFatMbr.Partition[Index].NumberOfSectors; BlFat32Initialize(); break; } } } } if (BlFatPartitionId == (UINT32) -1) { BlRtlPrintf("FAT: No %s partitions!\n", FatType == MBR_FAT16LBA ? "FAT16" : "FAT32"); BlRtlHalt(); } BlFsGetFileSize = BlFatGetFileSize; BlFsReadFile = BlFatReadFile; return; } ================================================ FILE: ironclad-apps/src/Checked/BootLoader/SingLdrPc/blflash.cpp ================================================ //++ // // Copyright (c) Microsoft Corporation // // Module Name: // // blflash.cpp // // Abstract: // // This module implements flash support for the boot loader. // //-- #include "bl.h" struct FLASH_HEADER { UINT8 Label[18]; UINT8 HeadSize; UINT8 SpecSize; UINT32 PageSize; UINT32 MajorVersion; UINT32 MinorVersion; }; struct FLASH_FILE { UINT32 PathOffset; UINT32 DataOffset; UINT32 Size; }; static PUINT8 BlFlashBase = NULL; static FLASH_FILE * BlFlashImages = NULL; FLASH_FILE * BlFlashRecordIsValid( FLASH_FILE *Current ) //++ // // Routine Description: // // Find the next valid flash file record. // // Return Value: // // Pointer to the next valid flash file record, if the query operation was successful. // NULL, if there are no remaining valid record. // //-- { for (;; Current++) { if ((Current->DataOffset == 0xffffffff && Current->Size == 0xffffffff) || (Current->DataOffset == 0 && Current->Size == 0)) { continue; } else if (Current->DataOffset == 0xffffffff && Current->Size == 0) { return NULL; } return Current; } } FLASH_FILE * BlFlashFindFile( PCSTR Path ) //++ // // Routine Description: // // Find the flash file record matching this path name. // // Arguments: // // Path - Supplies the path to the file to query. // // Return Value: // // Pointer to the flash file record, if the query operation was successful. // NULL, otherwise. // //-- { for (FLASH_FILE *File = BlFlashImages; File != NULL; File = BlFlashRecordIsValid(File + 1)) { if (BlRtlEqualStringI(Path, (PCSTR)(BlFlashBase + File->PathOffset))) { return File; } } return NULL; } BOOLEAN BlFlashGetFileSize( PCSTR Path, PUINT32 FileSize ) //++ // // Routine Description: // // This function queries the size of the specified file. // // Arguments: // // Path - Supplies the path to the file to query. // // FileSize - Receives the size of the file. // // Return Value: // // TRUE, if the query operation was successful. // FALSE, otherwise. // //-- { FLASH_FILE * File = BlFlashFindFile(Path); if (File != NULL) { *FileSize = File->Size; return TRUE; } return FALSE; } //++ // // Routine Description: // // This function reads from the specified file. // // Arguments: // // Path - Supplies the path to the file to read. // // Buffer - Receives data. // // NumberOfBytes - Supplies the number of bytes to read. // // Return Value: // // TRUE, if the read operation was successful. // FALSE, otherwise. // //-- BOOLEAN BlFlashReadFile( PCSTR Path, PVOID Buffer, UINT32 NumberOfBytes ) { (void)Path; (void)NumberOfBytes; (void)Buffer; FLASH_FILE * File = BlFlashFindFile(Path); if (File != NULL) { BlRtlCopyMemory(Buffer, BlFlashBase + File->DataOffset, NumberOfBytes); return TRUE; } return FALSE; } VOID BlFlashInitialize( PVOID SearchBegin, PVOID SearchLimit ) { // walk through at 64KB boundaries looking for flash image. for (FLASH_HEADER * Search = (FLASH_HEADER *)SearchBegin; Search <= (FLASH_HEADER *)SearchLimit; Search = (FLASH_HEADER *)(((PUINT8)Search) + 0x10000)) { if (!BlRtlEqualStringI((PCSTR)Search->Label, "SingularityFlash!")) { continue; } if (Search->HeadSize != sizeof(FLASH_HEADER)) { continue; } if (Search->SpecSize != sizeof(FLASH_FILE)) { continue; } if (Search->MajorVersion != ~0u || Search->MinorVersion != ~0u) { BlRtlPrintf("--- Version %x.%x didn't match\n", Search->MajorVersion, Search->MinorVersion); continue; } if (Search->PageSize != 0x1000) { continue; } BlFlashBase = (PUINT8)Search; BlFlashImages = BlFlashRecordIsValid((FLASH_FILE *)(Search + 1)); break; } BlFsGetFileSize = BlFlashGetFileSize; BlFsReadFile = BlFlashReadFile; } ================================================ FILE: ironclad-apps/src/Checked/BootLoader/SingLdrPc/blkd.cpp ================================================ //++ // // Copyright (c) Microsoft Corporation // // Module Name: // // blkd.cpp // // Abstract: // // This module implements KD support for the boot loader. // //-- #include "bl.h" UINT32 BlKdNextPacketId; VOID BlKdSpin( VOID ) //++ // // Routine Description: // // Provide user feedback that we are waiting on the kernel debugger. // //-- { static UINT8 state = 0; // // Write the spinner character to the top left corner of the screen. // *((UINT16 *)(ULONG_PTR)0xb809e) = 0x2f00 + ("+-|*" [state++ & 0x3]); } UINT32 BlKdComputeChecksum( PCVOID Buffer, UINT32 Length ) //++ // // Routine Description: // // This function computes the checksum of a KD buffer. // // Arguments: // // Buffer - Supplies a pointer to the buffer. // // Length - Supplies the length of the buffer. // // Return Value: // // Checksum value for the specified buffer. // //-- { UINT32 Checksum; UINT32 Index; Checksum = 0; for (Index = 0; Index < Length; Index += 1) { Checksum += ((PCHAR)Buffer)[Index]; } return Checksum; } BOOLEAN BlKdPrintString( PCSTR String ) //++ // // Routine Description: // // This function prints the specified string to the KD. // // Arguments: // // String - Supplies a pointer to the string to print. // // Return Value: // // TRUE, if operation was successful. // FALSE, otherwise. // //-- { KD_DEBUG_IO Packet; UINT32 StringLength; StringLength = BlRtlStringLength(String); if (StringLength >= 0xFFFF) { return FALSE; } BlRtlZeroMemory(&Packet, sizeof(Packet)); Packet.ApiNumber = KD_API_PRINT_STRING; Packet.u1.PrintString.LengthOfString = StringLength; if (BlKdComPort != 0) { return BlKdComSendPacket(KD_PACKET_TYPE_KD_DEBUG_IO, &Packet, sizeof(Packet), String, (UINT16) StringLength + 1); } else if (BlPciOhci1394BaseAddress != 0) { return BlKd1394SendPacket(KD_PACKET_TYPE_KD_DEBUG_IO, &Packet, sizeof(Packet), String, (UINT16) StringLength + 1); } return FALSE; } BOOLEAN BlKdPrintf( PCSTR Format, ... ) //++ // // Routine Description: // // This function prints out a string to KD. // // Arguments: // // Format - Supplies the format string. // // ... - Supplies the input parameters. // // Return Value: // // TRUE, if operation was successful. // FALSE, otherwise. // //-- { va_list ArgumentList; CHAR Buffer[4096]; va_start(ArgumentList, Format); if (BlRtlFormatString(Buffer, sizeof(Buffer), Format, ArgumentList) == FALSE) { return FALSE; } BlKdPrintString(Buffer); return TRUE; } VOID BlKdInitialize( VOID ) //++ // // Routine Description: // // This function initializes KD support for the boot loader. // //-- { // // Try serial first. // if (BlKdComConnect() != FALSE) { #if KD_VERBOSE BlVideoPrintf("KD: Connected to COM%u\n", BlKdComPort); #endif return; } // // Try the 1394 transport next. // if (BlKd1394Connect() != FALSE) { #if KD_VERBOSE BlVideoPrintf("KD: Connected to 1394:%u\n", 0); #endif return; } return; } ================================================ FILE: ironclad-apps/src/Checked/BootLoader/SingLdrPc/blkd1394.cpp ================================================ //++ // // Copyright (c) Microsoft Corporation // // Module Name: // // blkd1394.cpp // // Abstract: // // This module implements the 1394 transport for KD. // //-- #include "bl.h" #include "blkd1394.h" #if defined(BOOT_X64) BOOLEAN BlKd1394InitHardware( UINT16 Channel, PVOID IoRegion ) { return FALSE; } BOOLEAN BlKd1394Connect( VOID ) { return FALSE; } BOOLEAN BlKd1394SendPacket( UINT16 PacketType, PCVOID Header, UINT16 HeaderSize, PCVOID Data, UINT16 DataSize) { return FALSE; } #else // !defined(BOOT_X64) #define PACKET_READY 0x00000000 // Aka STATUS_SUCCESS #define PACKET_PENDING 0x00000103 // Aka STATUS_PENDING // // Change these macros to debug the debugger transport. // #define KDDBG if (0) BlVideoPrintf #define KDDBG2 if (0) BlVideoPrintf // // These structures are accessed directly by the host using RDMA. // #define DEBUG_BUS1394_MAX_PACKET_SIZE 4000 #define DEBUG_1394_MAJOR_VERSION 0x1 #define DEBUG_1394_MINOR_VERSION 0x0 #define DEBUG_1394_CONFIG_TAG 0xBABABABA typedef struct _DEBUG_1394_SEND_PACKET { UINT32 TransferStatus; UINT32 PacketHeader[4]; UINT32 Length; UINT8 Packet[DEBUG_BUS1394_MAX_PACKET_SIZE]; UINT8 Padding[72]; } DEBUG_1394_SEND_PACKET; C_ASSERT(sizeof(DEBUG_1394_SEND_PACKET) == 4096); typedef struct _DEBUG_1394_RECEIVE_PACKET { UINT32 TransferStatus; UINT32 Length; UINT8 Packet[DEBUG_BUS1394_MAX_PACKET_SIZE]; UINT8 Padding[88]; } DEBUG_1394_RECEIVE_PACKET; C_ASSERT(sizeof(DEBUG_1394_RECEIVE_PACKET) == 4096); typedef struct _DEBUG_1394_CONFIG { UINT32 Tag; UINT16 MajorVersion; UINT16 MinorVersion; UINT32 Id; UINT32 BusPresent; UINT64 SendPacket; UINT64 ReceivePacket; } DEBUG_1394_CONFIG; C_ASSERT(sizeof(DEBUG_1394_CONFIG) == 32); typedef struct _DEBUG_1394_DATA { UINT32 CromBuffer[248]; // our config ROM - must be 1k aligned DEBUG_1394_CONFIG Config; // our config for this session DEBUG_1394_SEND_PACKET SendPacket; // our send packet (isoch packet) DEBUG_1394_RECEIVE_PACKET ReceivePacket; // our receive packet } DEBUG_1394_DATA; C_ASSERT(sizeof(DEBUG_1394_DATA) == 1024 + 4096 + 4096); // // Timing constants. // #define TIMEOUT_COUNT 100000 #define MAX_REGISTER_READS 400000 // // Static Data Structures // static DEBUG_1394_DATA * Kd1394Data = NULL; static volatile OHCI_REGISTER_MAP * KdRegisters = NULL; UINT32 BlKd1394StallExecution( UINT32 LoopCount ) //++ // // Routine Description: // // Stall for a finite time to allow hardware to respond. // // Arguments: // // LoopCount - Number of times to run the outer loop. // // Return Value: // // Ignored. // //-- { volatile UINT32 b; volatile UINT32 k; volatile UINT32 i; b = 1; for (k = 0; k < LoopCount; k++) { BlKdSpin(); for (i = 1; i < 10000; i++) { b = b * (i>>k); } } return b; } UINT32 BlKd1394ByteSwap( UINT32 Source ) //++ // // Routine Description: // // Reverse the order of byte in the UINT32. // // Arguments: // // Source - 32-bit UINT32 value. // // Return Value: // // The input value with byte pairs 0:3 and 1:2 swapped. // //-- { return (((Source) << (8 * 3)) | ((Source & 0x0000FF00) << (8 * 1)) | ((Source & 0x00FF0000) >> (8 * 1)) | ((Source) >> (8 * 3))); } UINT32 BlKd1394Crc16( UINT32 Data, UINT32 Check ) //++ // // Routine Description: // // Derive the 16-bit CRC as defined by IEEE 1212 clause 8.1.5. (ISO/IEC 13213) // First edition 1994-10-05. // // Arguments: // // Data - UINT32 data to derive CRC from. // // Check - check value. // // Return Value: // // The 16-bit CRC. // //-- { UINT32 Next = Check; INT32 Shift; for (Shift = 28; Shift >= 0; Shift -= 4) { UINT32 Sum; Sum = ((Next >> 12) ^ (Data >> Shift)) & 0xf; Next = (Next << 4) ^ (Sum << 12) ^ (Sum << 5) ^ (Sum); } return (Next & 0xFFFF); } UINT16 BlKd1394CalculateCrc( UINT32 *Quadlet, UINT32 Length ) //++ // // Routine Description: // // Calculate a CRC for the pointer to the Quadlet data. // // Arguments: // // Quadlet - Pointer to data to CRC. // // Length - Length of data to CRC. // // Return Value: // // The 16-bit CRC. // //-- { UINT32 Temp = 0; UINT32 Index; Temp = 0; for (Index = 0; Index < Length; Index++) { Temp = BlKd1394Crc16(Quadlet[Index], Temp); } return (UINT16)Temp; } BOOLEAN BlKd1394InitHardware( UINT16 Channel, PVOID IoRegion ) //++ // // Routine Description: // // Initialize the 1394 hardware and connect it to KD. // // Arguments: // // Channel - KD 1394 Channel. Default is channel 0, but can be changed if 1394 is shared. // // IoRegion - Pointer to the 1394 registers mapped into our address space. // // Return Value: // // The 16-bit CRC. // //-- { UINT32 ulVersion; UINT8 MajorVersion; HC_CONTROL_REGISTER HCControl; UINT32 retry; LINK_CONTROL_REGISTER LinkControl; NODE_ID_REGISTER NodeId; BUS_OPTIONS_REGISTER BusOptions; CONFIG_ROM_INFO ConfigRomHeader; IMMEDIATE_ENTRY CromEntry; DIRECTORY_INFO DirInfo; PHY_CONTROL_REGISTER PhyControl; UINT8 Data; volatile OHCI_REGISTER_MAP * Registers; #if KD_VERBOSE BlVideoPrintf("1394: IoRegion: %p\n", IoRegion); #endif // // Note: Kd1394Data must be in the low 32-bits of address space due to // limits on valid 1394 DMA addresses. It must also be contiguous. // It must be in the low 24-bits of address space to statisfy KD. // Kd1394Data = (DEBUG_1394_DATA *) BlSingularityOhci1394Buffer; BlRtlZeroMemory(Kd1394Data, sizeof(*Kd1394Data)); // // Get our base address. // Registers = (volatile OHCI_REGISTER_MAP *)IoRegion; // // Initialize our config info for host debugger to read. // Kd1394Data->Config.Tag = DEBUG_1394_CONFIG_TAG; Kd1394Data->Config.MajorVersion = DEBUG_1394_MAJOR_VERSION; Kd1394Data->Config.MinorVersion = DEBUG_1394_MINOR_VERSION; Kd1394Data->Config.Id = Channel; Kd1394Data->Config.BusPresent = FALSE; Kd1394Data->Config.SendPacket = (UINT64) &Kd1394Data->SendPacket; Kd1394Data->Config.ReceivePacket = (UINT64) &Kd1394Data->ReceivePacket; // // Get the transport version. // ulVersion = Registers->Version.all; MajorVersion = (UINT8)(ulVersion >> 16); // // Make sure we have a valid version. // if (MajorVersion != 1) { // INVESTIGATE #if KD_VERBOSE BlVideoPrintf("1394: MajorVersion != 1\n"); #endif return FALSE; } // // Soft reset to initialize the controller. // HCControl.all = 0; HCControl.SoftReset = TRUE; Registers->HCControlSet.all = HCControl.all; // // wait until reset completes. // retry = 1000; // ?? do { HCControl.all = Registers->HCControlSet.all; BlKd1394StallExecution(1); } while ((HCControl.SoftReset) && (--retry)); if (retry == 0) { #if KD_VERBOSE BlVideoPrintf("1394: Reset failed\n"); #endif return FALSE; } // // Enable link to phy communication. // HCControl.all = 0; HCControl.Lps = TRUE; Registers->HCControlSet.all = HCControl.all; BlKd1394StallExecution(20); // // Initialize HCControl register // Send data in little-endian order (i.e. do byte swap). // HCControl.all = 0; HCControl.NoByteSwapData = TRUE; Registers->HCControlClear.all = HCControl.all; // // Enable posted writes. // HCControl.all = 0; HCControl.PostedWriteEnable = TRUE; Registers->HCControlSet.all = HCControl.all; // // Setup the link control. // LinkControl.all = 0; LinkControl.CycleTimerEnable = TRUE; LinkControl.CycleMaster = TRUE; LinkControl.RcvPhyPkt = TRUE; LinkControl.RcvSelfId = TRUE; Registers->LinkControlClear.all = LinkControl.all; LinkControl.all = 0; LinkControl.CycleTimerEnable = TRUE; LinkControl.CycleMaster = TRUE; Registers->LinkControlSet.all = LinkControl.all; // // Set the bus number (hardcoded to 0x3FF) - ??? what about node id?? // NodeId.all = 0; NodeId.BusId = (UINT16)0x3FF; Registers->NodeId.all = NodeId.all; // // Do something with the crom... // // // 0xf0000404 - bus id register // Kd1394Data->CromBuffer[1] = 0x31333934; // // 0xf0000408 - bus options register // BusOptions.all = BlKd1394ByteSwap(Registers->BusOptions.all); BusOptions.Pmc = FALSE; BusOptions.Bmc = FALSE; BusOptions.Isc = FALSE; BusOptions.Cmc = FALSE; BusOptions.Irmc = FALSE; BusOptions.g = 1; Kd1394Data->CromBuffer[2] = BlKd1394ByteSwap(BusOptions.all); // // 0xf000040c - global unique id hi // Kd1394Data->CromBuffer[3] = Registers->GuidHi; // // 0xf0000410 - global unique id lo // Kd1394Data->CromBuffer[4] = Registers->GuidLo; // // 0xf0000400 - config ROM header - set last to calculate CRC! // ConfigRomHeader.all = 0; ConfigRomHeader.CRI_Info_Length = 4; ConfigRomHeader.CRI_CRC_Length = 4; ConfigRomHeader.CRI_CRC_Value = BlKd1394CalculateCrc(&Kd1394Data->CromBuffer[1], ConfigRomHeader.CRI_CRC_Length); Kd1394Data->CromBuffer[0] = ConfigRomHeader.all; Kd1394Data->CromBuffer[6] = 0xC083000C; // 0xf0000418 - node capabilities Kd1394Data->CromBuffer[7] = 0xF2500003; // 0xf000041C - module vendor id // // KD's state machine looks for 1c w/ 50f2, 1d w/ 02, then 1e w/ address. // Kd1394Data->CromBuffer[8] = 0xF250001C; // 0xf0000420 - extended key (for KD) Kd1394Data->CromBuffer[9] = 0x0200001D; // 0xf0000424 - debug key (for KD) // // 0xf0000428 - debug value (for KD) // CromEntry.all = (UINT32)(ULONG_PTR) &Kd1394Data->Config; CromEntry.IE_Key = 0x1E; Kd1394Data->CromBuffer[10] = BlKd1394ByteSwap(CromEntry.all); // // 0xf0000414 - root directory header - set last to calculate CRC! // DirInfo.all = 0; DirInfo.DI_Length = 5; DirInfo.DI_CRC = BlKd1394CalculateCrc(&Kd1394Data->CromBuffer[6], DirInfo.DI_Length); Kd1394Data->CromBuffer[5] = BlKd1394ByteSwap(DirInfo.all); // // Write the first few registers. // Registers->ConfigRomHeader.all = Kd1394Data->CromBuffer[0]; Registers->BusId = Kd1394Data->CromBuffer[1]; Registers->BusOptions.all = Kd1394Data->CromBuffer[2]; Registers->GuidHi = Kd1394Data->CromBuffer[3]; Registers->GuidLo = Kd1394Data->CromBuffer[4]; // // Set our crom. // Registers->ConfigRomMap = (UINT32)(ULONG_PTR) &Kd1394Data->CromBuffer; // // Disable all interrupts, we use polling for the debugger transport. // Registers->IntMaskClear.all = 0xFFFFFFFF; // // Enable the link. // HCControl.all = 0; HCControl.LinkEnable = TRUE; Registers->HCControlSet.all = HCControl.all; BlKd1394StallExecution(1000); // // Enable access filters to all nodes. // Registers->AsynchReqFilterLoSet = 0xFFFFFFFF; Registers->AsynchReqFilterHiSet = 0xFFFFFFFF; Registers->PhyReqFilterHiSet = 0xFFFFFFFF; Registers->PhyReqFilterLoSet = 0xFFFFFFFF; // // Hard reset on the bus (so KD will look for us). // PhyControl.all = 0; PhyControl.RdReg = TRUE; PhyControl.RegAddr = 1; Registers->PhyControl.all = PhyControl.all; retry = MAX_REGISTER_READS; do { PhyControl.all = Registers->PhyControl.all; } while ((!PhyControl.RdDone) && --retry); if (retry == 0) { #if KD_VERBOSE BlVideoPrintf("1394: Bus read failed.\n"); #endif return FALSE; } Data = ((UINT8)PhyControl.RdData | PHY_INITIATE_BUS_RESET); PhyControl.all = 0; PhyControl.WrReg = TRUE; PhyControl.RegAddr = 1; PhyControl.WrData = Data; Registers->PhyControl.all = PhyControl.all; retry = MAX_REGISTER_READS; do { PhyControl.all = Registers->PhyControl.all; } while (PhyControl.WrReg && --retry); if (retry == 0) { #if KD_VERBOSE BlVideoPrintf("1394: Hard reset of bus failed\n"); #endif return FALSE; } #if KD_VERBOSE BlVideoPrintf("1394: Hardware init succeeded.\n"); #endif KdRegisters = Registers; return TRUE; } VOID BlKd1394EnablePhysicalAccess( VOID ) { HC_CONTROL_REGISTER HCControl; INT_EVENT_MASK_REGISTER IntEvent; // // See if ohci1394 is being loaded... // HCControl.all = KdRegisters->HCControlSet.all; if (!HCControl.LinkEnable || !HCControl.Lps || HCControl.SoftReset) { KDDBG("1394: EnablePhysicalAccess HCControl=%08x!\n", HCControl.all); return; } // // If the bus reset interrupt is not cleared, we have to clear it... // IntEvent.all = KdRegisters->IntEventSet.all; if (IntEvent.BusReset) { KDDBG("1394: EnablePhysicalAccess IntEvent =%08x!\n", IntEvent.all); IntEvent.all = 0; IntEvent.BusReset = 1; KdRegisters->IntEventClear.all = IntEvent.all; } // // Re-enable physical access as it may be necessary. // KdRegisters->AsynchReqFilterHiSet = 0xFFFFFFFF; KdRegisters->AsynchReqFilterLoSet = 0xFFFFFFFF; KdRegisters->PhyReqFilterHiSet = 0xFFFFFFFF; KdRegisters->PhyReqFilterLoSet = 0xFFFFFFFF; return; } BOOLEAN BlKd1394SendPacket( UINT16 PacketType, PCVOID Header, UINT16 HeaderSize, PCVOID Data, UINT16 DataSize) //++ // // Routine Description: // // This routine sends a packet to the host machine that is running the kernel debugger and // waits for an ACK. // // Arguments: // // PacketType - Supplies the type of the packet to send. // // Header - Supplies a pointer to the header. // // HeaderSize - Supplies the size of the header. // // Data - Supplies a pointer to the data. // // DataSize - Supplies the size of the data. // // Return Value: // // TRUE, if send operation was successful. // FALSE, otherwise. // //-- { KD_PACKET PacketHeader; UINT32 Retries; UINT32 count; volatile UINT32 *pStatus; KDDBG2("BlKd1394SendPacket\n"); // // Abort if the hardware hasn't been initialized. // if (KdRegisters == NULL) { return FALSE; } // // Initialize the packet header. // PacketHeader.PacketLeader = KD_PACKET_LEADER; PacketHeader.ByteCount = HeaderSize + DataSize; PacketHeader.PacketType = PacketType; PacketHeader.PacketId = BlKdNextPacketId++; PacketHeader.Checksum = (BlKdComputeChecksum(Header, HeaderSize) + BlKdComputeChecksum(Data, DataSize)); // // Setup our send packet. // BlRtlZeroMemory(&Kd1394Data->SendPacket, sizeof(DEBUG_1394_SEND_PACKET)); Kd1394Data->SendPacket.Length = 0; // Redundant. // // Copy our packet header into the transmit region. // BlRtlCopyMemory(&Kd1394Data->SendPacket.PacketHeader[0], &PacketHeader, sizeof(KD_PACKET)); // // Setup our message header. // if (HeaderSize > 0) { BlRtlCopyMemory(&Kd1394Data->SendPacket.Packet[0], Header, HeaderSize); Kd1394Data->SendPacket.Length = HeaderSize; } // // Setup our message data. // if (DataSize > 0) { BlRtlCopyMemory(&Kd1394Data->SendPacket.Packet[Kd1394Data->SendPacket.Length], Data, DataSize); Kd1394Data->SendPacket.Length += DataSize; } // // Mark the packet as ready for processing by host. // Kd1394Data->SendPacket.TransferStatus = PACKET_PENDING; // // Wait for our packet to be acknowledged by the host. // for (Retries = KD_RETRY_COUNT; Retries > 0; Retries--) { KDDBG2("LOOP %d [SendPacket=%p %08x %08x %08x %02x %02x %02x %02x]\n", Retries, &Kd1394Data->SendPacket, Kd1394Data->SendPacket.TransferStatus, * (UINT32*) &Kd1394Data->SendPacket.PacketHeader, Kd1394Data->SendPacket.Length, Kd1394Data->SendPacket.Packet[0], Kd1394Data->SendPacket.Packet[1], Kd1394Data->SendPacket.Packet[2], Kd1394Data->SendPacket.Packet[3]); // // make sure our link is enabled.. // BlKd1394EnablePhysicalAccess(); pStatus = &Kd1394Data->ReceivePacket.TransferStatus; // // now sit here and poll for a response from the host machine // for (count = 0; count < TIMEOUT_COUNT; count++) { // // make sure our link is enabled.. // BlKd1394EnablePhysicalAccess(); BlKdSpin(); // // Check to see if the host has ACK'd our packet. // if (Kd1394Data->SendPacket.TransferStatus != PACKET_PENDING) { return TRUE; } // // While in this loop check if the host has submitted a new request. // If they did, ACK it, and retry. // if (*pStatus == PACKET_PENDING) { // // ACK the packet from the debugger so it will accept our packet. // *pStatus = PACKET_READY; } } } return FALSE; } BOOLEAN BlKd1394Connect( VOID ) //++ // // Routine Description: // // This function tries to connect to the KD through a COM port. // // Return Value: // // TRUE, if connection was successful. // FALSE, otherwise. // //-- { // // Abort if there is no 1394 hardware. // if (BlPciOhci1394BaseAddress == 0) { return FALSE; } // // Initialize the underlying hardware. // if (BlKd1394InitHardware(0, (PVOID)(ULONG_PTR) BlPciOhci1394BaseAddress)) { KD_DEBUG_IO Packet; // // Send a test packet to verify the debugger is attached. // BlRtlZeroMemory(&Packet, sizeof(Packet)); Packet.ApiNumber = KD_API_PRINT_STRING; Packet.u1.PrintString.LengthOfString = 0; if (BlKd1394SendPacket(KD_PACKET_TYPE_KD_DEBUG_IO, &Packet, sizeof(Packet), L"1394!\n", 7)) { return TRUE; } } BlPciOhci1394BaseAddress = 0; return FALSE; } #endif // !defined(BOOT_X64) ================================================ FILE: ironclad-apps/src/Checked/BootLoader/SingLdrPc/blkd1394.h ================================================ //++ // //Copyright (c) Microsoft Corporation // //Module Name: // // blkd1394.h // //Abstract: // // This module defines 1394 structures. // //Environment: // // Boot loader. // //-- // // Various OHCI definitions // #define PHY_INITIATE_BUS_RESET 0x40 // IBR @ Address 1 ///////////////////////////////////////////////////////// Register Structures. // typedef union _VERSION_REGISTER { struct { UINT32 Revision:8; // bits 0-7 UINT32 Reserved:8; // bits 8-15 UINT32 Version:8; // bits 16-23 UINT32 GUID_ROM:1; // bit 24 UINT32 Reserved1:7; // bits 25-31 }; UINT32 all; } VERSION_REGISTER; C_ASSERT(sizeof(VERSION_REGISTER) == 4); typedef union _VENDOR_ID_REGISTER { struct { UINT32 VendorCompanyId:24; // bits 0-23 UINT32 VendorUnique:8; // bits 24-31 }; UINT32 all; } VENDOR_ID_REGISTER; C_ASSERT(sizeof(VENDOR_ID_REGISTER) == 4); typedef union _GUID_ROM_REGISTER { struct { UINT32 Reserved0:16; // bits 0-15 UINT32 RdData:8; // bits 16-23 UINT32 Reserved1:1; // bit 24 UINT32 RdStart:1; // bit 25 UINT32 Reserved2:5; // bits 26-30 UINT32 AddrReset:1; // bits 31 }; UINT32 all; } GUID_ROM_REGISTER; C_ASSERT(sizeof(GUID_ROM_REGISTER) == 4); typedef union _AT_RETRIES_REGISTER { struct { UINT32 MaxATReqRetries:4; // bits 0-3 UINT32 MaxATRespRetries:4; // bits 4-7 UINT32 MaxPhysRespRetries:4; // bits 8-11 UINT32 Reserved:4; // bits 12-15 UINT32 CycleLimit:13; // bits 16-28 UINT32 SecondLimit:3; // bits 29-31 }; UINT32 all; } AT_RETRIES_REGISTER; C_ASSERT(sizeof(AT_RETRIES_REGISTER) == 4); typedef union _CSR_CONTROL_REGISTER { struct { UINT32 CsrSel:2; // bits 0-1 UINT32 Reserved:29; // bits 2-30 UINT32 CsrDone:1; // bit 31 }; UINT32 all; } CSR_CONTROL_REGISTER; C_ASSERT(sizeof(CSR_CONTROL_REGISTER) == 4); typedef union _CONFIG_ROM_HEADER_REGISTER { struct { UINT32 Rom_crc_value:16; // bits 0-15 UINT32 Crc_length:8; // bits 16-23 UINT32 Info_length:8; // bits 24-31 }; UINT32 all; } CONFIG_ROM_HEADER_REGISTER; C_ASSERT(sizeof(CONFIG_ROM_HEADER_REGISTER) == 4); typedef union _BUS_OPTIONS_REGISTER { struct { UINT32 Link_spd:3; // bits 0-2 UINT32 Reserved0:3; // bits 3-5 UINT32 g:2; // bits 6-7 UINT32 Reserved1:4; // bits 8-11 UINT32 Max_rec:4; // bits 12-15 UINT32 Cyc_clk_acc:8; // bits 16-23 UINT32 Reserved2:3; // bits 24-26 UINT32 Pmc:1; // bit 27 UINT32 Bmc:1; // bit 28 UINT32 Isc:1; // bit 29 UINT32 Cmc:1; // bit 30 UINT32 Irmc:1; // bit 31 }; UINT32 all; } BUS_OPTIONS_REGISTER; C_ASSERT(sizeof(BUS_OPTIONS_REGISTER) == 4); typedef union _HC_CONTROL_REGISTER { struct { UINT32 Reserved:16; // bits 0-15 UINT32 SoftReset:1; // bit 16 UINT32 LinkEnable:1; // bit 17 UINT32 PostedWriteEnable:1; // bit 18 UINT32 Lps:1; // bit 19 UINT32 Reserved2:2; // bits 20-21 UINT32 APhyEnhanceEnable:1; // bit 22 UINT32 ProgramPhyEnable:1; // bit 23 UINT32 Reserved3:6; // bits 24-29 UINT32 NoByteSwapData:1; // bit 30 UINT32 Reserved4:1; // bit 31 }; UINT32 all; } HC_CONTROL_REGISTER; C_ASSERT(sizeof(HC_CONTROL_REGISTER) == 4); typedef union _FAIRNESS_CONTROL_REGISTER { struct { UINT32 Pri_req:8; // bits 0-7 UINT32 Reserved0:24; // bits 8-31 }; UINT32 all; } FAIRNESS_CONTROL_REGISTER; C_ASSERT(sizeof(FAIRNESS_CONTROL_REGISTER) == 4); typedef union _LINK_CONTROL_REGISTER { struct { UINT32 Reserved0:4; // bits 0-3 UINT32 CycleSyncLReqEnable:1; // bit 4 UINT32 Reserved1:4; // bits 5-8 UINT32 RcvSelfId:1; // bit 9 UINT32 RcvPhyPkt:1; // bit 10 UINT32 Reserved2:9; // bits 11-19 UINT32 CycleTimerEnable:1; // bit 20 UINT32 CycleMaster:1; // bit 21 UINT32 CycleSource:1; // bit 22 UINT32 Reserved3:9; // bits 23-31 }; UINT32 all; } LINK_CONTROL_REGISTER; C_ASSERT(sizeof(LINK_CONTROL_REGISTER) == 4); typedef union _NODE_ID_REGISTER { struct { UINT32 NodeId:6; // bits 0-5 UINT32 BusId:10; // bits 6-15 UINT32 Reserved1:11; // bits 16-26 UINT32 Cps:1; // bit 27 UINT32 Reserved2:2; // bits 28-29 UINT32 Root:1; // bit 30 UINT32 IdValid:1; // bit 31 }; UINT32 all; } NODE_ID_REGISTER; C_ASSERT(sizeof(NODE_ID_REGISTER) == 4); typedef union _SELF_ID_BUFFER_REGISTER { UINT32 SelfIdBufferPointer; struct { UINT32 Reserved0:11; // bits 0-10 UINT32 SelfIdBuffer:21; // bits 11-32 }; UINT32 all; } SELF_ID_BUFFER_REGISTER; C_ASSERT(sizeof(SELF_ID_BUFFER_REGISTER) == 4); typedef union _SELF_ID_COUNT_REGISTER { struct { UINT32 Reserved0:2; // bits 0-1 UINT32 SelfIdSize:11; // bits 2-12 UINT32 Reserved1:3; // bits 13-15 UINT32 SelfIdGeneration:8; // bits 16-23 UINT32 Reserved2:7; // bits 24-30 UINT32 SelfIdError:1; // bit 31 }; UINT32 all; } SELF_ID_COUNT_REGISTER; C_ASSERT(sizeof(SELF_ID_COUNT_REGISTER) == 4); typedef union _PHY_CONTROL_REGISTER { struct { UINT32 WrData:8; // bits 0-7 UINT32 RegAddr:4; // bits 8-11 UINT32 Reserved0:2; // bits 12-13 UINT32 WrReg:1; // bit 14 UINT32 RdReg:1; // bit 15 UINT32 RdData:8; // bits 16-23 UINT32 RdAddr:4; // bits 24-27 UINT32 Reserved1:3; // bits 28-30 UINT32 RdDone:1; // bit 31 }; UINT32 all; } PHY_CONTROL_REGISTER; C_ASSERT(sizeof(PHY_CONTROL_REGISTER) == 4); typedef union _ISOCH_CYCLE_TIMER_REGISTER { struct { UINT32 CycleOffset:12; // bits 0-11 UINT32 CycleCount:13; // bits 12-24 UINT32 CycleSeconds:7; // bits 25-31 }; UINT32 all; } ISOCH_CYCLE_TIMER_REGISTER; C_ASSERT(sizeof(ISOCH_CYCLE_TIMER_REGISTER) == 4); typedef union _INT_EVENT_MASK_REGISTER { struct { UINT32 ReqTxComplete:1; // bit 0 UINT32 RspTxComplete:1; // bit 1 UINT32 ARRQ:1; // bit 2 UINT32 ARRS:1; // bit 3 UINT32 RQPkt:1; // bit 4 UINT32 RSPPkt:1; // bit 5 UINT32 IsochTx:1; // bit 6 UINT32 IsochRx:1; // bit 7 UINT32 PostedWriteErr:1; // bit 8 UINT32 LockRespErr:1; // bit 9 UINT32 Reserved0:6; // bits 10-15 UINT32 SelfIdComplete:1; // bit 16 UINT32 BusReset:1; // bit 17 UINT32 Reserved1:1; // bit 18 UINT32 Phy:1; // bit 19 UINT32 CycleSynch:1; // bit 20 UINT32 Cycle64Secs:1; // bit 21 UINT32 CycleLost:1; // bit 22 UINT32 CycleInconsistent:1; // bit 23 UINT32 UnrecoverableError:1; // bit 24 UINT32 CycleTooLong:1; // bit 25 UINT32 PhyRegRcvd:1; // bit 26 UINT32 Reserved2:3; // bits 27-29 UINT32 VendorSpecific:1; // bit 30 UINT32 MasterIntEnable:1; // bit 31 }; UINT32 all; } INT_EVENT_MASK_REGISTER; C_ASSERT(sizeof(INT_EVENT_MASK_REGISTER) == 4); typedef union _COMMAND_POINTER_REGISTER { struct { UINT32 Z:4; // bits 0-3 UINT32 DescriptorAddr:28; // bits 4-31 }; UINT32 all; } COMMAND_POINTER_REGISTER; C_ASSERT(sizeof(COMMAND_POINTER_REGISTER) == 4); typedef union _CONTEXT_CONTROL_REGISTER { struct { UINT32 EventCode:5; // bits 0-4 UINT32 Spd:3; // bits 5-7 UINT32 Reserved0:2; // bits 8-9 UINT32 Active:1; // bit 10 UINT32 Dead:1; // bit 11 UINT32 Wake:1; // bit 12 UINT32 Reserved1:2; // bits 13-14 UINT32 Run:1; // bit 15 UINT32 Reserved2:16; // bits 16-31 }; UINT32 all; } CONTEXT_CONTROL_REGISTER; C_ASSERT(sizeof(CONTEXT_CONTROL_REGISTER) == 4); typedef union _IT_CONTEXT_CONTROL_REGISTER { struct { UINT32 EventCode:5; // bits 0-4 UINT32 Spd:3; // bits 5-7 UINT32 Reserved0:2; // bits 8-9 UINT32 Active:1; // bit 10 UINT32 Dead:1; // bit 11 UINT32 Wake:1; // bit 12 UINT32 Reserved1:2; // bits 13-14 UINT32 Run:1; // bit 15 UINT32 CycleMatch:15; // bits 16-30 UINT32 CycleMatchEnable:1; // bit 31 }; UINT32 all; } IT_CONTEXT_CONTROL_REGISTER; C_ASSERT(sizeof(IT_CONTEXT_CONTROL_REGISTER) == 4); typedef union _IR_CONTEXT_CONTROL_REGISTER { struct { UINT32 EventCode:5; // bits 0-4 UINT32 Spd:3; // bits 5-7 UINT32 Reserved0:2; // bits 8-9 UINT32 Active:1; // bit 10 UINT32 Dead:1; // bit 11 UINT32 Wake:1; // bit 12 UINT32 Reserved1:2; // bits 13-14 UINT32 Run:1; // bit 15 UINT32 CycleMatch:12; // bits 16-27 UINT32 MultiChanMode:1; // bit 28 UINT32 CycleMatchEnable:1; // bit 29 UINT32 IsochHeader:1; // bit 30 UINT32 BufferFill:1; // bit 31 }; UINT32 all; } IR_CONTEXT_CONTROL_REGISTER; C_ASSERT(sizeof(IR_CONTEXT_CONTROL_REGISTER) == 4); typedef union _CONTEXT_MATCH_REGISTER { struct { UINT32 ChannelNumber:6; // bits 0-5 UINT32 Reserved:1; // bit 6 UINT32 Tag1SyncFilter:1; // bit 7 UINT32 Sync:4; // bits 8-11 UINT32 CycleMatch:13; // bits 12-24 UINT32 Reserved1:3; // bits 25-27 UINT32 Tag:4; // bit 28-31 }; UINT32 all; } CONTEXT_MATCH_REGISTER; C_ASSERT(sizeof(CONTEXT_MATCH_REGISTER) == 4); /////////////////////////////////////////////////////////////// Register Sets. // typedef struct _DMA_CONTEXT_REGISTERS { CONTEXT_CONTROL_REGISTER ContextControlSet; CONTEXT_CONTROL_REGISTER ContextControlClear; UINT32 Reserved0[1]; COMMAND_POINTER_REGISTER CommandPtr; UINT32 Reserved1[4]; } DMA_CONTEXT_REGISTERS; typedef struct _DMA_ISOCH_RCV_CONTEXT_REGISTERS { IR_CONTEXT_CONTROL_REGISTER ContextControlSet; IR_CONTEXT_CONTROL_REGISTER ContextControlClear; UINT32 Reserved0[1]; COMMAND_POINTER_REGISTER CommandPtr; CONTEXT_MATCH_REGISTER ContextMatch; UINT32 Reserved1[3]; } DMA_ISOCH_RCV_CONTEXT_REGISTERS; typedef struct _DMA_ISOCH_XMIT_CONTEXT_REGISTERS { IT_CONTEXT_CONTROL_REGISTER ContextControlSet; IT_CONTEXT_CONTROL_REGISTER ContextControlClear; UINT32 Reserved0[1]; COMMAND_POINTER_REGISTER CommandPtr; } DMA_ISOCH_XMIT_CONTEXT_REGISTERS; typedef struct _OHCI_REGISTER_MAP { VERSION_REGISTER Version; // @ 0 GUID_ROM_REGISTER GUID_ROM; // @ 4 AT_RETRIES_REGISTER ATRetries; // @ 8 UINT32 CsrData; // @ C UINT32 CsrCompare; // @ 10 CSR_CONTROL_REGISTER CsrControl; // @ 14 CONFIG_ROM_HEADER_REGISTER ConfigRomHeader; // @ 18 UINT32 BusId; // @ 1C BUS_OPTIONS_REGISTER BusOptions; // @ 20 UINT32 GuidHi; // @ 24 UINT32 GuidLo; // @ 28 UINT32 Reserved0[2]; // @ 2C UINT32 ConfigRomMap; // @ 34 UINT32 PostedWriteAddressLo; // @ 38 UINT32 PostedWriteAddressHi; // @ 3C VENDOR_ID_REGISTER VendorId; // @ 40 UINT32 Reserved1[3]; // @ 44 HC_CONTROL_REGISTER HCControlSet; // @ 50 HC_CONTROL_REGISTER HCControlClear; // @ 54 UINT32 Reserved2[3]; // @ 58 SELF_ID_BUFFER_REGISTER SelfIdBufferPtr; // @ 64 SELF_ID_COUNT_REGISTER SelfIdCount; // @ 68 UINT32 Reserved3[1]; // @ 6C UINT32 IRChannelMaskHiSet; // @ 70 UINT32 IRChannelMaskHiClear; // @ 74 UINT32 IRChannelMaskLoSet; // @ 78 UINT32 IRChannelMaskLoClear; // @ 7C INT_EVENT_MASK_REGISTER IntEventSet; // @ 80 INT_EVENT_MASK_REGISTER IntEventClear; // @ 84 INT_EVENT_MASK_REGISTER IntMaskSet; // @ 88 INT_EVENT_MASK_REGISTER IntMaskClear; // @ 8C UINT32 IsoXmitIntEventSet; // @ 90 UINT32 IsoXmitIntEventClear; // @ 94 UINT32 IsoXmitIntMaskSet; // @ 98 UINT32 IsoXmitIntMaskClear; // @ 9C UINT32 IsoRecvIntEventSet; // @ A0 UINT32 IsoRecvIntEventClear; // @ A4 UINT32 IsoRecvIntMaskSet; // @ A8 UINT32 IsoRecvIntMaskClear; // @ AC UINT32 Reserved4[11]; // @ B0 FAIRNESS_CONTROL_REGISTER FairnessControl; // @ DC LINK_CONTROL_REGISTER LinkControlSet; // @ E0 LINK_CONTROL_REGISTER LinkControlClear; // @ E4 NODE_ID_REGISTER NodeId; // @ E8 PHY_CONTROL_REGISTER PhyControl; // @ EC ISOCH_CYCLE_TIMER_REGISTER IsochCycleTimer; // @ F0 UINT32 Reserved5[3]; // @ F4 UINT32 AsynchReqFilterHiSet; // @ 100 UINT32 AsynchReqFilterHiClear; // @ 104 UINT32 AsynchReqFilterLoSet; // @ 108 UINT32 AsynchReqFilterLoClear; // @ 10C UINT32 PhyReqFilterHiSet; // @ 110 UINT32 PhyReqFilterHiClear; // @ 114 UINT32 PhyReqFilterLoSet; // @ 118 UINT32 PhyReqFilterLoClear; // @ 11C UINT32 PhysicalUpperBound; // @ 120 UINT32 Reserved6[23]; // @ 124 DMA_CONTEXT_REGISTERS AsynchContext[4]; // @ 180 // ATRsp_Context; // @ 1A0 // ARReq_Context; // @ 1C0 // ARRsp_Context; // @ 1E0 DMA_ISOCH_XMIT_CONTEXT_REGISTERS IT_Context[32]; // @ 200 DMA_ISOCH_RCV_CONTEXT_REGISTERS IR_Context[32]; // @ 400 } OHCI_REGISTER_MAP; C_ASSERT(sizeof(OHCI_REGISTER_MAP) == 2048); // // IEEE 1212 Configuration Rom header definition // typedef union _CONFIG_ROM_INFO { struct { union { UINT16 CRI_CRC_Value:16; struct { UINT8 CRI_Saved_Info_Length; UINT8 CRI_Saved_CRC_Length; } Saved; }; UINT8 CRI_CRC_Length; UINT8 CRI_Info_Length; }; UINT32 all; } CONFIG_ROM_INFO; C_ASSERT(sizeof(CONFIG_ROM_INFO) == 4); // // IEEE 1212 Immediate entry definition // typedef union _IMMEDIATE_ENTRY { struct { UINT32 IE_Value:24; UINT32 IE_Key:8; }; UINT32 all; } IMMEDIATE_ENTRY; C_ASSERT(sizeof(IMMEDIATE_ENTRY) == 4); // // IEEE 1212 Directory definition // typedef union _DIRECTORY_INFO { struct { union { UINT16 DI_CRC; UINT16 DI_Saved_Length; }; UINT16 DI_Length; }; UINT32 all; } DIRECTORY_INFO; C_ASSERT(sizeof(DIRECTORY_INFO) == 4); // ///////////////////////////////////////////////////////////////// End of File. ================================================ FILE: ironclad-apps/src/Checked/BootLoader/SingLdrPc/blkdcom.cpp ================================================ //++ // // Copyright (c) Microsoft Corporation // // Module Name: // // blkdcom.cpp // // Abstract: // // This module implements the com port transport for KD. // //-- #include "bl.h" #define KD_DELAY_LOOP 0x00010000 #define KD_INITIAL_PACKET_ID 0x80800000 #define KD_SYNC_PACKET_ID 0x00000800 #define KD_PACKET_TRAILING_BYTE 0xAA struct { KD_PACKET Header; UINT8 Data[PAGE_SIZE - sizeof(KD_PACKET)]; } BlKdStaticPacket; UINT8 BlKdComPort; BOOLEAN BlKdComReceiveByte( PUINT8 Byte ) //++ // // Routine Description: // // This function receives a byte from the KD. // // Arguments: // // Byte - Receives the byte from KD. // // Return Value: // // TRUE, if receive operation was successful. // FALSE, otherwise. // //-- { volatile UINT32 Count; if (BlKdComPort != 0) { Count = KD_DELAY_LOOP; while (Count > 0) { if (BlComDataAvailable(BlKdComPort) != FALSE) { *Byte = BlComReceiveByte(BlKdComPort); return TRUE; } Count -= 1; } #if KD_VERBOSE BlVideoPrintf("KD: Receive timeout!\n"); #endif return FALSE; } return FALSE; } BOOLEAN BlKdComSendData( PCVOID Buffer, UINT32 Length ) //++ // // Routine Description: // // This function sends data to the KD. // // Arguments: // // Buffer - Supplies a pointer to the buffer to send. // // Length - Supplies the length of the buffer to send. // // Return Value: // // TRUE, if send operation was successful. // FALSE, otherwise. // //-- { UINT32 Index; for (Index = 0; Index < Length; Index += 1) { if (BlComSendByte(BlKdComPort, ((PUINT8) Buffer)[Index]) == FALSE) { return FALSE; } } return TRUE; } BOOLEAN BlKdComReceiveData( PVOID Buffer, UINT32 Length ) //++ // // Routine Description: // // This function receives data from the KD. // // Arguments: // // Buffer - Receives data. // // Length - Supplies the length of the buffer to receive. // // Return Value: // // TRUE, if receive operation was successful. // FALSE, otherwise. // //-- { UINT32 Index; for (Index = 0; Index < Length; Index += 1) { if (BlKdComReceiveByte(&(((PUINT8) Buffer)[Index])) == FALSE) { return FALSE; } } return TRUE; } BOOLEAN BlKdComSendControlPacket( UINT16 PacketType, UINT32 PacketId ) //++ // // Routine Description: // // This function sends a control packet to the KD. // // Arguments: // // PacketType - Supplies the packet type. // // PacketId - Supplies the packet ID. // // Return Value: // // TRUE, if send operation was successful. // FALSE, otherwise. // //-- { KD_PACKET Header; BlRtlZeroMemory(&Header, sizeof(Header)); Header.PacketLeader = KD_CONTROL_PACKET_LEADER; Header.PacketType = PacketType; Header.PacketId = PacketId; if (BlKdComSendData(&Header, sizeof(Header)) == FALSE) { return FALSE; } #if KD_VERBOSE BlVideoPrintf("KD: Sent type %u control packet.\n", PacketType); #endif return TRUE; } BOOLEAN BlKdComReceivePacket( VOID ) //++ // // Routine Description: // // This function receives the next packet from the KD. // // Return Value: // // TRUE, if receive operation was successful. // FALSE, otherwise. // //-- { PKD_PACKET Header; UINT8 TrailingByte; Header = &BlKdStaticPacket.Header; Retry: for (;;) { if (BlKdComReceiveData(&Header->PacketLeader, sizeof(Header->PacketLeader)) == FALSE) { return FALSE; } if (Header->PacketLeader == KD_PACKET_LEADER) { break; } if (Header->PacketLeader == KD_CONTROL_PACKET_LEADER) { break; } } if (BlKdComReceiveData(&Header->PacketType, sizeof(Header->PacketType)) == FALSE) { return FALSE; } if (BlKdComReceiveData(&Header->ByteCount, sizeof(Header->ByteCount)) == FALSE) { return FALSE; } if (BlKdComReceiveData(&Header->PacketId, sizeof(Header->PacketId)) == FALSE) { return FALSE; } if (BlKdComReceiveData(&Header->Checksum, sizeof(Header->Checksum)) == FALSE) { return FALSE; } if (Header->ByteCount > sizeof(BlKdStaticPacket.Data)) { goto Retry; } if (Header->ByteCount > 0) { if (BlKdComReceiveData(BlKdStaticPacket.Data, Header->ByteCount) == FALSE) { return FALSE; } if (BlKdComReceiveByte(&TrailingByte) == FALSE) { return FALSE; } if (TrailingByte != KD_PACKET_TRAILING_BYTE) { goto Retry; } } #if KD_VERBOSE BlVideoPrintf("KD: Received type %u packet.\n", Header->PacketType); #endif return TRUE; } BOOLEAN BlKdComSendPacket( UINT16 PacketType, PCVOID Header, UINT16 HeaderSize, PCVOID Data, UINT16 DataSize ) //++ // // Routine Description: // // This function sends a packet to the KD. // // Arguments: // // PacketType - Supplies the type of the packet to send. // // Header - Supplies a pointer to the header. // // HeaderSize - Supplies the size of the header. // // Data - Supplies a pointer to the data. // // DataSize - Supplies the size of the data. // // Return Value: // // TRUE, if send operation was successful. // FALSE, otherwise. // //-- { UINT16 ByteCount; UINT32 Checksum; KD_PACKET Packet; BLASSERT(HeaderSize > 0); Resend: // // Calculate byte count and checksum. // ByteCount = HeaderSize; Checksum = BlKdComputeChecksum(Header, HeaderSize); if (Data != NULL) { BLASSERT(DataSize > 0); ByteCount = ByteCount + DataSize; Checksum += BlKdComputeChecksum(Data, DataSize); } // // Send packet. // Packet.PacketLeader = KD_PACKET_LEADER; Packet.PacketId = BlKdNextPacketId; Packet.PacketType = PacketType; Packet.ByteCount = ByteCount; Packet.Checksum = Checksum; if (BlKdComSendData(&Packet, sizeof(Packet)) == FALSE) { return FALSE; } if (BlKdComSendData(Header, HeaderSize) == FALSE) { return FALSE; } if (Data != NULL) { if (BlKdComSendData(Data, DataSize) == FALSE) { return FALSE; } } if (BlComSendByte(BlKdComPort, KD_PACKET_TRAILING_BYTE) == FALSE) { return FALSE; } #if KD_VERBOSE BlVideoPrintf("KD: Sent type %u packet.\n", Packet.PacketType); #endif // // Update packet ID. // BlKdNextPacketId &= (~KD_SYNC_PACKET_ID); BlKdNextPacketId ^= 1; if (BlKdComReceivePacket() != FALSE) { switch (BlKdStaticPacket.Header.PacketType) { case KD_PACKET_TYPE_KD_RESET: { #if KD_VERBOSE BlVideoPrintf("KD: Received RESET after send.\n"); #endif BlKdComSendControlPacket(KD_PACKET_TYPE_KD_RESET, 0); goto Resend; } case KD_PACKET_TYPE_KD_RESEND: { #if KD_VERBOSE BlVideoPrintf("KD: Received RESEND after send.\n"); #endif goto Resend; } } } return TRUE; } BOOLEAN BlKdComConnect( VOID ) //++ // // Routine Description: // // This function tries to connect to the KD through a COM port. // // Return Value: // // TRUE, if connection was successful. // FALSE, otherwise. // //-- { UINT8 Index; BOOLEAN Present[COM_MAX_PORT + 1]; UINT32 Retry; // // Find all COM ports on the system. // for (Index = 1; Index <= COM_MAX_PORT; Index += 1) { Present[Index] = BlComInitialize(Index, 115200); #if KD_VERBOSE BlVideoPrintf("KD: COM%u %s\n", Index, Present[Index] ? "found." : "not found."); #endif } // // Set initial packet ID. // BlKdNextPacketId = KD_INITIAL_PACKET_ID | KD_SYNC_PACKET_ID; for (Retry = 0; Retry < KD_RETRY_COUNT; Retry += 1) { for (Index = 1; Index <= COM_MAX_PORT; Index += 1) { if (Present[Index] != FALSE) { #if KD_VERBOSE BlVideoPrintf("KD: Trying COM%u ...\n", Index); #endif BlKdComPort = Index; BlKdComSendControlPacket(KD_PACKET_TYPE_KD_RESET, 0); if (BlKdComReceivePacket() != FALSE) { return TRUE; } } } } BlKdComPort = 0; return FALSE; } ================================================ FILE: ironclad-apps/src/Checked/BootLoader/SingLdrPc/blmm.cpp ================================================ //++ // // Copyright (c) Microsoft Corporation // // Module Name: // // blmm.cpp // // Abstract: // // This module implements memory management for the boot loader. // //-- #include "bl.h" LIST_ENTRY BlMmPhysicalRegionList; struct { BL_MM_PHYSICAL_REGION StaticArray[16]; LIST_ENTRY FreeList; } BlMmPhysicalRegionLookaside; GDTR BlMmInitialGdtr; ULONG_PTR BlMmLegacyCr3; ULONG_PTR BlMmBootCr3; typedef struct _BL_MM_PAGE_TABLE { UINT64 Entry[512]; } BL_MM_PAGE_TABLE, *PBL_MM_PAGE_TABLE; #if defined(BOOT_X64) __declspec(align(PAGE_SIZE)) BL_MM_PAGE_TABLE BlMmPml4Table[1]; #endif __declspec(align(PAGE_SIZE)) BL_MM_PAGE_TABLE BlMmPdpTable[1]; __declspec(align(PAGE_SIZE)) BL_MM_PAGE_TABLE BlMmPdTable[4]; __declspec(align(PAGE_SIZE)) BL_MM_PAGE_TABLE BlMmPgTable[1]; PVOID BlMmExtendedBiosDataArea; VOID BlMmCompactPhysicalRegionList( VOID ) //++ // // Routine Description: // // This function compacts the physical region list by coalescing adjacent // regions of the same type. // //-- { PBL_MM_PHYSICAL_REGION Current; PLIST_ENTRY Head; PBL_MM_PHYSICAL_REGION Next; Head = &BlMmPhysicalRegionList; if (BlRtlIsListEmpty(Head) != FALSE) { return; } Current = CONTAINING_RECORD(Head->Flink, BL_MM_PHYSICAL_REGION, Entry); for (;;) { BLASSERT(Current->Size > 0); BLASSERT(Current->Start + Current->Size == Current->Limit); BLASSERT((Current->Type >= BL_MM_PHYSICAL_REGION_MIN_TYPE) && (Current->Type <= BL_MM_PHYSICAL_REGION_MAX_TYPE)); if (Current->Entry.Flink == Head) { break; } Next = CONTAINING_RECORD(Current->Entry.Flink, BL_MM_PHYSICAL_REGION, Entry); BLASSERT(Next->Start >= Current->Limit); if ((Next->Start == Current->Limit) && (Next->Type == Current->Type)) { Current->Limit = Next->Limit; Current->Size = Current->Limit - Current->Start; BlRtlRemoveEntryList(&Next->Entry); BlRtlInsertTailList(&BlMmPhysicalRegionLookaside.FreeList, &Next->Entry); continue; } Current = Next; } } VOID BlMmInsertPhysicalRegion( PBL_MM_PHYSICAL_REGION Region ) //++ // // Routine Description: // // This function inserts a new physical region to the physical region list. // // Arguments: // // Region - Supplies a pointer to the region to insert. // //-- { PLIST_ENTRY Entry; PLIST_ENTRY Head; PBL_MM_PHYSICAL_REGION Next; Head = &BlMmPhysicalRegionList; Entry = Head->Flink; while (Entry != Head) { Next = CONTAINING_RECORD(Entry, BL_MM_PHYSICAL_REGION, Entry); if (Next->Start > Region->Start) { break; } Entry = Entry->Flink; } BlRtlInsertTailList(Entry, &Region->Entry); BlMmCompactPhysicalRegionList(); return; } VOID BlMmCreatePhysicalRegion( UINT64 Start, UINT64 Size, UINT32 Type ) //++ // // Routine Description: // // This function creates a physical region descriptor. // // Arguments: // // Start - Supplies the start address of the region. // // Size - Supplies the size of the region. // // Type - Supplies the type of the region. // //-- { PLIST_ENTRY Entry; PLIST_ENTRY Head; UINT64 Limit; PBL_MM_PHYSICAL_REGION Region; BLASSERT((Start % PAGE_SIZE) == 0); BLASSERT(Size > 0); BLASSERT((Size % PAGE_SIZE) == 0); BLASSERT(Type >= BL_MM_PHYSICAL_REGION_MIN_TYPE); BLASSERT(Type <= BL_MM_PHYSICAL_REGION_MAX_TYPE); Limit = Start + Size; BLASSERT(Limit > Start); Head = &BlMmPhysicalRegionList; Entry = Head->Flink; while (Entry != Head) { Region = CONTAINING_RECORD(Entry, BL_MM_PHYSICAL_REGION, Entry); if ((Start < Region->Limit) && (Limit > Region->Start)) { BlRtlPrintf("MM: Physical region collision!\n"); BlRtlHalt(); } Entry = Entry->Flink; } Entry = Head->Flink; while (Entry != Head) { Region = CONTAINING_RECORD(Entry, BL_MM_PHYSICAL_REGION, Entry); if (Start < Region->Start) { break; } Entry = Entry->Flink; } BLASSERT(BlRtlIsListEmpty(&BlMmPhysicalRegionLookaside.FreeList) == FALSE); Region = CONTAINING_RECORD(BlRtlRemoveHeadList(&BlMmPhysicalRegionLookaside.FreeList), BL_MM_PHYSICAL_REGION, Entry); Region->Start = Start; Region->Size = Size; Region->Limit = Limit; Region->Type = Type; BlMmInsertPhysicalRegion(Region); return; } UINT64 BlMmAllocatePhysicalRegion( UINT32 Size, UINT32 Type ) //++ // // Routine Description: // // This function allocates a physical region from the lowest available and // sufficient free region. // // Arguments: // // Size - Supplies the size of the region to allocate. // // Type - Supplies the type of the region to allocate. // // Return Value: // // The physical address of the allocated region. // //-- { PLIST_ENTRY Entry; PBL_MM_PHYSICAL_REGION FreeRegion; PLIST_ENTRY Head; PBL_MM_PHYSICAL_REGION Region; BLASSERT(Size > 0); BLASSERT(Type != BL_MM_PHYSICAL_REGION_FREE); SATISFY_OVERZEALOUS_COMPILER(Region = NULL); Size = ROUND_UP_TO_PAGES(Size); Head = &BlMmPhysicalRegionList; Entry = Head->Blink; while (Entry != Head) { Region = CONTAINING_RECORD(Entry, BL_MM_PHYSICAL_REGION, Entry); if ((Region->Type == BL_MM_PHYSICAL_REGION_FREE) && (Region->Size >= Size) && (Region->Limit < 0x100000000UI64)) { break; } Entry = Entry->Blink; } if (Entry == Head) { BlRtlPrintf("MM: Unable to allocate %x bytes!\n", Size); BlRtlHalt(); } if (Region->Size == Size) { Region->Type = Type; return Region->Start; } FreeRegion = Region; BLASSERT(BlRtlIsListEmpty(&BlMmPhysicalRegionLookaside.FreeList) == FALSE); Region = CONTAINING_RECORD(BlRtlRemoveHeadList(&BlMmPhysicalRegionLookaside.FreeList), BL_MM_PHYSICAL_REGION, Entry); Region->Start = FreeRegion->Limit - Size; FreeRegion->Limit -= Size; FreeRegion->Size -= Size; Region->Size = Size; Region->Limit = Region->Start + Region->Size; Region->Type = Type; BlRtlZeroMemory((PVOID) (ULONG_PTR) Region->Start, (ULONG_PTR) (UINT32) Region->Size); BlMmInsertPhysicalRegion(Region); return Region->Start; } BOOLEAN BlMmAllocateSpecificPhysicalRegion( UINT64 Base, UINT64 Size, UINT32 Type ) //++ // // Routine Description: // // This function allocates a specific physical region. // // Arguments: // // Base - Supplies the base physical address of the region to allocate. // // Size - Supplies the size of the region to allocate. // // Type - Supplies the type of the region to allocate. // // Return Value: // // TRUE, if allocation was successful. // FALSE, otherwise. // //-- { UINT64 End; PLIST_ENTRY Entry; PLIST_ENTRY Head; PBL_MM_PHYSICAL_REGION NextRegion; PBL_MM_PHYSICAL_REGION PreviousRegion; PBL_MM_PHYSICAL_REGION Region; UINT64 Start; BLASSERT((Base % PAGE_SIZE) == 0); BLASSERT(Size > 0); BLASSERT((Size % PAGE_SIZE) == 0); BLASSERT(Type != BL_MM_PHYSICAL_REGION_FREE); SATISFY_OVERZEALOUS_COMPILER(Region = NULL); Start = Base; End = Start + Size; Head = &BlMmPhysicalRegionList; for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink) { Region = CONTAINING_RECORD(Entry, BL_MM_PHYSICAL_REGION, Entry); if ((Start >= Region->Start) && (End <= Region->Limit)) { break; } } if (Entry == Head) { return FALSE; } if (Region->Type != BL_MM_PHYSICAL_REGION_FREE) { return FALSE; } PreviousRegion = NULL; NextRegion = NULL; if (Region->Start < Start) { BLASSERT(BlRtlIsListEmpty(&BlMmPhysicalRegionLookaside.FreeList) == FALSE); PreviousRegion = CONTAINING_RECORD(BlRtlRemoveHeadList(&BlMmPhysicalRegionLookaside.FreeList), BL_MM_PHYSICAL_REGION, Entry); PreviousRegion->Start = Region->Start; PreviousRegion->Size = Start - Region->Start; PreviousRegion->Limit = Start; PreviousRegion->Type = BL_MM_PHYSICAL_REGION_FREE; } if (Region->Limit > End) { BLASSERT(BlRtlIsListEmpty(&BlMmPhysicalRegionLookaside.FreeList) == FALSE); NextRegion = CONTAINING_RECORD(BlRtlRemoveHeadList(&BlMmPhysicalRegionLookaside.FreeList), BL_MM_PHYSICAL_REGION, Entry); NextRegion->Start = End; NextRegion->Size = Region->Limit - End; NextRegion->Limit = Region->Limit; NextRegion->Type = BL_MM_PHYSICAL_REGION_FREE; } Region->Start = Start; Region->Size = Size; Region->Limit = End; Region->Type = Type; if (PreviousRegion != NULL) { BlMmInsertPhysicalRegion(PreviousRegion); } if (NextRegion != NULL) { BlMmInsertPhysicalRegion(NextRegion); } return TRUE; } BOOLEAN BlMmFindFreePhysicalRegion( PUINT64 Base, PUINT64 Size ) //++ // // Routine Description: // // This function finds a free physical region. // // Arguments: // // Base - Receives the base address of the free region. // // Size - Receives the size of the free region. // // Return Value: // // TRUE, if a free region was found. // FALSE, otherwise. // //-- { PLIST_ENTRY Entry; PLIST_ENTRY Head; PBL_MM_PHYSICAL_REGION Region; Head = &BlMmPhysicalRegionList; for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink) { Region = CONTAINING_RECORD(Entry, BL_MM_PHYSICAL_REGION, Entry); if (Region->Type == BL_MM_PHYSICAL_REGION_FREE) { *Base = Region->Start; *Size = Region->Size; return TRUE; } } return FALSE; } BOOLEAN BlMmGetNextPhysicalRegion( PVOID *Handle, PUINT64 Base, PUINT64 Size, PUINT32 Type ) //++ // // Routine Description: // // This function is used to enumerate physical regions. // // Arguments: // // Handle - Supplies a pointer to the last handle (or NULL to start // enumeration) on entry. // Receives the next handle (if any) on exit. // // Base - Receives the base address of the next region. // // Size - Receives the size of the next region. // // Type - Receives the type of the next region. // // Return Value: // // TRUE, if there is a next region. // FALSE, otherwise. // //-- { PLIST_ENTRY Entry; PLIST_ENTRY Head; PBL_MM_PHYSICAL_REGION Region; Head = &BlMmPhysicalRegionList; if (*Handle == NULL) { Entry = Head; } else { Entry = (PLIST_ENTRY) *Handle; } Entry = Entry->Flink; if (Entry == Head) { return FALSE; } Region = CONTAINING_RECORD(Entry, BL_MM_PHYSICAL_REGION, Entry); *Handle = &Region->Entry; *Base = Region->Start; *Size = Region->Size; *Type = Region->Type; return TRUE; } PCHAR BlMmPhysicalRegionTypeString( UINT32 Type ) //++ // // Routine Description: // // This function returns the specified physical region type string. // // Arguments: // // Type - Supplies the physical region type. // // Return Value: // // String representation for the specified type. // //-- { #define CASE(X) case BL_MM_PHYSICAL_REGION_##X: return #X; switch (Type) { CASE(FREE) CASE(BIOS) CASE(BOOT_LOADER) CASE(SMAP_RESERVED) CASE(DISTRO) CASE(KERNEL_IMAGE) CASE(NATIVE_PLATFORM) CASE(NATIVE_PROCESSOR) CASE(LOG_RECORD) CASE(LOG_TEXT) CASE(KERNEL_STACK) CASE(CONTEXT) CASE(TASK) CASE(SINGULARITY) CASE(BOOT_STACK) CASE(SINGULARITY_SMAP) } #undef CASE BLASSERT(FALSE); return NULL; } VOID BlMmDumpPhysicalRegionList( VOID ) //++ // // Routine Description: // // This function dumps the list of physical regions. // //-- { PLIST_ENTRY Entry; PLIST_ENTRY Head; PBL_MM_PHYSICAL_REGION Region; BlRtlPrintf("MM: Physical Region:\n"); Head = &BlMmPhysicalRegionList; for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink) { Region = CONTAINING_RECORD(Entry, BL_MM_PHYSICAL_REGION, Entry); BlRtlPrintf("MM: %016I64x...%016I64x %s\n", Region->Start, Region->Limit, BlMmPhysicalRegionTypeString(Region->Type)); } BlRtlPrintf("\n"); return; } // // AIFIX: Switch from identity mapping to dynamic mapping. // VOID BlMmInitializePageTables( VOID ) //++ // // Routine Description: // // This function initializes boot loader page tables that identity map the first 4GB of memory. // //-- { UINT64 Index; UINT64 *Pde; UINT64 PdtBase; UINT64 *Pdpe; UINT64 PdptBase; #if defined(BOOT_X64) UINT64 *Pml4e; UINT64 Pml4tBase; #endif UINT64 *Pte; UINT64 PtBase; #if defined(BOOT_X64) Pml4tBase = (UINT64) (ULONG_PTR) BlMmPml4Table; #endif PdptBase = (UINT64) (ULONG_PTR) BlMmPdpTable; PdtBase = (UINT64) (ULONG_PTR) BlMmPdTable; PtBase = (UINT64) (ULONG_PTR) BlMmPgTable; #if defined(BOOT_X64) Pml4e = (UINT64 *) (PVOID) Pml4tBase; #endif Pdpe = (UINT64 *) (PVOID) (ULONG_PTR) PdptBase; Pde = (UINT64 *) (PVOID) (ULONG_PTR) PdtBase; Pte = (UINT64 *) (PVOID) (ULONG_PTR) PtBase; #if defined(BOOT_X64) Pml4e[0] = PdptBase | PAGE_PRESENT | PAGE_WRITEABLE | PAGE_ACCESSED; #endif for (Index = 0; Index < 4; Index += 1) { Pdpe[Index] = (PdtBase + (Index * PAGE_SIZE)) | PAGE_PRESENT; #if defined(BOOT_X64) Pdpe[Index] |= PAGE_WRITEABLE | PAGE_ACCESSED; #endif } Pde[0] = PtBase | PAGE_PRESENT | PAGE_WRITEABLE | PAGE_ACCESSED; for (Index = 1; Index < 512; Index += 1) { Pte[Index] = (Index << 12) | PAGE_PRESENT | PAGE_WRITEABLE | PAGE_ACCESSED; } for (Index = 1; Index < 2048; Index += 1) { Pde[Index] = (Index << 21) | PAGE_PRESENT | PAGE_WRITEABLE | PAGE_ACCESSED | PAGE_2MB; } #if defined(BOOT_X86) BlMmBootCr3 = (ULONG_PTR) PdptBase; #elif defined(BOOT_X64) BlMmBootCr3 = Pml4tBase; #endif BlMmSetCr3(BlMmBootCr3); BlGetBeb()->LegacyReturnCr3 = (UINT32) BlMmBootCr3; #if MM_VERBOSE BlRtlPrintf("MM: 4GB identity map [CR3=%p]\n", BlMmBootCr3); #endif return; } VOID BlMmMapVirtualPage( PVOID VirtualAddress, PVOID PhysicalAddress, BOOLEAN Writeable, BOOLEAN Cacheable, BOOLEAN WriteThrough ) //++ // // Routine Description: // // This function maps the specified virtual page. // // Arguments: // // VirtualAddress - Supplies the virtual address to map. // // PhysicalAddress - Supplies the physical address to map to. // // Writeable - Supplies whether the page is writeable. // // Cacheable - Supplies whether the page is cacheable. // // WriteThrough - Supplies whether the page is write-through. // //-- { UINT64 Entry; UINT32 Index; UINT64 LargePageAddress; PUINT64 PdBase; UINT32 PdIndex; PUINT64 PdpBase; UINT32 PdpIndex; UINT64 PhysicalPageNumber; PUINT64 PtBase; UINT32 PtIndex; ULONG_PTR VirtualPageNumber; BLASSERT((((ULONG_PTR) VirtualAddress) & 0xFFF) == 0); BLASSERT((((ULONG_PTR) PhysicalAddress) & 0xFFF) == 0); #if defined(BOOT_X64) BLASSERT((ULONG_PTR) VirtualAddress < 0x100000000UI64); #endif // // Compute virtual page number, page directory pointer, page directory, and page table indices. // VirtualPageNumber = ((ULONG_PTR) VirtualAddress) / PAGE_SIZE; PdpIndex = (UINT32) ((VirtualPageNumber >> 18) & 0x1FF); PdIndex = (UINT32) ((VirtualPageNumber >> 9) & 0x1FF); PtIndex = (UINT32) (VirtualPageNumber & 0x1FF); // // Look up page directory base address. // PdpBase = &BlMmPdpTable[0].Entry[0]; PdBase = (PUINT64) (ULONG_PTR) (PdpBase[PdpIndex] & (~(0xFFFUI64))); // // If the specified page is currently being mapped with large pages, then split it into 4K mappings. // if ((PdBase[PdIndex] & PAGE_2MB) != 0) { PtBase = (PUINT64) (ULONG_PTR) BlMmAllocatePhysicalRegion(PAGE_SIZE, BL_MM_PHYSICAL_REGION_BOOT_LOADER); LargePageAddress = (PdBase[PdIndex] & (~(0xFFFUI64))); BLASSERT(((LargePageAddress >> 12) & 0x1FF) == 0); // // Create page table entries to map the region in 4K pages. // for (Index = 0; Index < 512; Index += 1) { PtBase[Index] = (LargePageAddress + (Index * PAGE_SIZE)) | PAGE_PRESENT | PAGE_WRITEABLE | PAGE_ACCESSED; } // // Update page directory entry. // PdBase[PdIndex] = ((UINT64) (ULONG_PTR) PtBase) | PAGE_PRESENT | PAGE_WRITEABLE | PAGE_ACCESSED; // // Flush TLB. // BlMmSetCr3(BlMmBootCr3); } // // Update page mapping. // PtBase = (PUINT64) (ULONG_PTR) (PdBase[PdIndex] & (~(0xFFFUI64))); PhysicalPageNumber = ((ULONG_PTR) PhysicalAddress) >> 12; Entry = (PhysicalPageNumber << 12) | PAGE_PRESENT; if (Writeable != FALSE) { Entry |= PAGE_WRITEABLE; } if (Cacheable == FALSE) { Entry |= PAGE_CACHEDISABLE; } else if (WriteThrough != FALSE) { Entry |= PAGE_WRITETHROUGH; } PtBase[PtIndex] = Entry; // // Flush TLB. // BlMmSetCr3(BlMmBootCr3); return; } VOID BlMmMapVirtualRange( PVOID VirtualAddress, PVOID PhysicalAddress, ULONG_PTR Size, BOOLEAN Writeable, BOOLEAN Cacheable, BOOLEAN WriteThrough ) //++ // // Routine Description: // // This function maps the specified virtual range. // // Arguments: // // VirtualAddress - Supplies the virtual address to map. // // PhysicalAddress - Supplies the physical address to map to. // // Size - Supplies the size of the mapping. // // Writeable - Supplies whether the page is writeable. // // Cacheable - Supplies whether the page is cacheable. // // WriteThrough - Supplies whether the page is write-through. // //-- { ULONG_PTR PhysicalNext; ULONG_PTR VirtualLimit; ULONG_PTR VirtualNext; VirtualNext = (ULONG_PTR) VirtualAddress; VirtualLimit = VirtualNext + Size; VirtualNext &= (~((ULONG_PTR) 0xFFF)); VirtualLimit = ROUND_UP_TO_PAGES(VirtualLimit); PhysicalNext = (ULONG_PTR) PhysicalAddress; PhysicalNext &= (~((ULONG_PTR) 0xFFF)); while (VirtualNext < VirtualLimit) { BlMmMapVirtualPage((PVOID) VirtualNext, (PVOID) PhysicalNext, Writeable, Cacheable, WriteThrough); VirtualNext += PAGE_SIZE; PhysicalNext += PAGE_SIZE; } return; } VOID BlMmInitializeCodeSegment( PCODE_SEGMENT CodeSegment ) //++ // // Routine Description: // // This function initializes the specified code segment. // // Arguments: // // CodeSegment - Supplies a pointer to the code segment to initialize. // //-- { BlRtlZeroMemory(CodeSegment, sizeof(CODE_SEGMENT)); CodeSegment->Accessed = 1; CodeSegment->Readable = 1; CodeSegment->Code = 1; CodeSegment->S = 1; CodeSegment->Present = 1; CodeSegment->Long = 1; return; } VOID BlMmInitializeDataSegment( PDATA_SEGMENT DataSegment, UINT32 Base, UINT32 Limit ) //++ // // Routine Description: // // This function initializes the specified data segment. // // Arguments: // // DataSegment - Supplies a pointer to the data segment to initialize. // // Base - Supplies the base address of the data segment. // // Limit - Supplies the limit of the data segment. // //-- { BlRtlZeroMemory(DataSegment, sizeof(DATA_SEGMENT)); DataSegment->Accessed = 1; DataSegment->Writable = 1; DataSegment->S = 1; DataSegment->Present = 1; DataSegment->Big = 1; DataSegment->Base_23_0 = Base & 0xFFFFFF; DataSegment->Base_31_24 = Base >> 24; if (Limit <= 0xFFFFF) { DataSegment->Limit_15_0 = Limit & 0xFFFF; DataSegment->Limit_19_16 = (Limit >> 16) & 0xF; } else { DataSegment->Granularity = 1; DataSegment->Limit_15_0 = (Limit >> 12) & 0xFFFF; DataSegment->Limit_19_16 = (Limit >> 28) & 0xF; } return; } VOID BlMmInitializeSystemSegment( PSYSTEM_SEGMENT SystemSegment, UINT32 Type, ULONG_PTR Base, UINT32 Limit ) //++ // // Routine Description: // // This function initializes the specified system segment. // // Arguments: // // SystemSegment - Supplies a pointer to the system segment to initialize. // // Type - Supplies the type of the system segment. // // Base - Supplies the base address of the system segment. // // Limit - Supplies the limit of the system segment. // //-- { BlRtlZeroMemory(SystemSegment, sizeof(SYSTEM_SEGMENT)); SystemSegment->Type = (Type & 0xF); SystemSegment->Present = 1; SystemSegment->Base_23_0 = Base & 0xFFFFFF; SystemSegment->Base_31_24 = (Base >> 24) & 0xFF; #if defined(BOOT_X64) SystemSegment->Base_63_32 = Base >> 32; #endif if (Limit <= 0xFFFFF) { SystemSegment->Limit_15_0 = Limit & 0xFFFF; SystemSegment->Limit_19_16 = (Limit >> 16) & 0xF; } else { SystemSegment->Granularity = 1; SystemSegment->Limit_15_0 = (Limit >> 12) & 0xFFFF; SystemSegment->Limit_19_16 = (Limit >> 28) & 0xF; } return; } #if !defined(BOOT_PXE) VOID BlMmEnableA20Gate( VOID ) //++ // // Routine Description: // // This function enables A20 gate. // //-- { BL_KEYBOARD_WRITE_OUTPUT_PORT(BL_KEYBOARD_A20_ENABLE); BL_KEYBOARD_WRITE_COMMAND(BL_KEYBOARD_COMMAND_PULSE_OUTPUT_PORT); return; } #endif PVOID BlMmGetExtendedBiosDataArea( VOID ) //++ // // Routine Description: // // This function gets the address of the extended BIOS data area. // // Return Value: // // Address of the extended BIOS data area. // //-- { UINT16 Segment; Segment = *((PUINT16) (ULONG_PTR) 0x40E); return (PVOID) (((ULONG_PTR) Segment) << 4); } VOID BlMmInitializeSystem( VOID ) //++ // // Routine Description: // // This function initializes boot loader memory management. // //-- { UINT64 Delta; UINT32 Index; PBL_MM_PHYSICAL_REGION PhysicalRegion; PBL_SMAP_ENTRY SmapEntry; #if !defined(BOOT_PXE) // // Enable A20 gate. // BlMmEnableA20Gate(); #endif // // Get extended BIOS data area. // BlMmExtendedBiosDataArea = BlMmGetExtendedBiosDataArea(); // // Get legacy CR3 value; // BlMmLegacyCr3 = BlMmGetCr3(); // // Get initial GDTR. // BlMmGetGdtr(&BlMmInitialGdtr); // // Initialize memory map. // BlSmapInitialize(); // // Create physical region lookaside. // BlRtlInitializeListHead(&BlMmPhysicalRegionList); BlRtlInitializeListHead(&BlMmPhysicalRegionLookaside.FreeList); for (Index = 0; Index < (sizeof(BlMmPhysicalRegionLookaside.StaticArray) / sizeof(BlMmPhysicalRegionLookaside.StaticArray[0])); Index += 1) { BlRtlInsertTailList(&BlMmPhysicalRegionLookaside.FreeList, &BlMmPhysicalRegionLookaside.StaticArray[Index].Entry); } // // Initialize page tables. // BlMmInitializePageTables(); // // Create reserved BIOS region. // BlMmCreatePhysicalRegion(0, BL_MM_BIOS_SIZE, BL_MM_PHYSICAL_REGION_BIOS); // // Create free regions based on SMAP. // for (Index = 0; Index < BlSystemMemoryMap.EntryCount; Index += 1) { SmapEntry = &BlSystemMemoryMap.Entry[Index]; // // Don't use any memory below 1MB (BIOS area) and above 2GB (Singularity uses MSB for marking and such). // if ((SmapEntry->Type == BL_SMAP_AVAILABLE) && (SmapEntry->Base >= BL_MM_BIOS_SIZE) && (SmapEntry->Base < 0x80000000UI64) ) { if ((SmapEntry->Base % PAGE_SIZE) != 0) { Delta = PAGE_SIZE - (SmapEntry->Base % PAGE_SIZE); SmapEntry->Base += Delta; SmapEntry->Size -= Delta; } SmapEntry->Size &= (~(0xFFFUI64)); if ((SmapEntry->Base + SmapEntry->Size) > 0x80000000UI64) { SmapEntry->Size = 0x80000000UI64 - SmapEntry->Base; } if (SmapEntry->Size > 0) { BlMmCreatePhysicalRegion(SmapEntry->Base, SmapEntry->Size, BL_MM_PHYSICAL_REGION_FREE); } } } // // Initialize pool. // BlPoolInitialize(); // // Add more entries to the physical region lookaside. // for (Index = 0; Index < 256; Index += 1) { PhysicalRegion = (PBL_MM_PHYSICAL_REGION) BlPoolAllocateBlock(sizeof(BL_MM_PHYSICAL_REGION)); BlRtlInsertTailList(&BlMmPhysicalRegionLookaside.FreeList, &PhysicalRegion->Entry); } return; } ================================================ FILE: ironclad-apps/src/Checked/BootLoader/SingLdrPc/blmps.cpp ================================================ //++ // // Copyright (c) Microsoft Corporation // // Module Name: // // blmps.cpp // // Abstract: // // This module implements MPS support for the boot loader environment. // //-- #include "bl.h" // // MPS Floating Pointer Structure (FPS) // typedef struct _MPS_FPS { CHAR Signature[4]; UINT32 ConfigurationTableAddress; UINT8 Length; UINT8 Revision; UINT8 Checksum; UINT8 FeatureByte[5]; } MPS_FPS, *PMPS_FPS; C_ASSERT(sizeof(MPS_FPS) == 16); PVOID BlMpsFps; PMPS_FPS BlMpsLocateFpsInRange( ULONG_PTR Start, ULONG_PTR End ) //++ // // Routine Description: // // This function locates the MPS FPS structure in the specified range. // // Arguments: // // Start - Supplies the start address of the range to locate in. // // End - Supplies the end address of the range to locate in. // // Return Value: // // MPS FPS structure, if located. // NULL, otherwise. // //-- { PMPS_FPS Fps; Start = ROUND_UP_TO_POWER2(Start, 16); End &= ~((ULONG_PTR) 15); while (Start < End) { Fps = (PMPS_FPS) Start; if ((Fps->Signature[0] == '_') && (Fps->Signature[1] == 'M') && (Fps->Signature[2] == 'P') && (Fps->Signature[3] == '_') && (BlRtlComputeChecksum8(Fps, Fps->Length * 16) == 0)) { return Fps; } Start += 16; } return NULL; } PMPS_FPS BlMpsLocateFps( VOID ) //++ // // Routine Description: // // This function locates the MPS FPS structure. // // Return Value: // // MPS FPS structure, if located. // NULL, otherwise. // //-- { PMPS_FPS Fps; // // Look for FPS in the first KB of the EBDA first. // Fps = BlMpsLocateFpsInRange((ULONG_PTR) BlMmExtendedBiosDataArea, (ULONG_PTR) BlMmExtendedBiosDataArea + 1024); if (Fps != NULL) { return Fps; } // // Look for FPS in the 639KB - 640KB range. // Fps = BlMpsLocateFpsInRange(639 * 1024, 640 * 1024); if (Fps != NULL) { return Fps; } // // Look for FPS in the BIOS ROM range (0xF0000 - 0xFFFFF). // Fps = BlMpsLocateFpsInRange(0xF0000, 0x100000); if (Fps != NULL) { return Fps; } // // If FPS is not located, then return NULL. // return NULL; } VOID BlMpsInitialize( VOID ) //++ // // Routine Description: // // This function initializes MPS support for the boot loader. // //-- { PMPS_FPS Fps; Fps = BlMpsLocateFps(); if (Fps == NULL) { #if MPS_VERBOSE BlRtlPrintf("MPS: MPS not supported!\n"); #endif return; } #if MPS_VERBOSE BlRtlPrintf("MPS: Found version 1.%u.\n", Fps->Revision); #endif BlMpsFps = Fps; return; } ================================================ FILE: ironclad-apps/src/Checked/BootLoader/SingLdrPc/blpci.cpp ================================================ //++ // // Copyright (c) Microsoft Corporation // // Module Name: // // blpci.cpp // // Abstract: // // This module implements PCI support for the boot loader environment. // //-- #include "bl.h" #define PCI_MAX_BUSES 128 #define PCI_MAX_DEVICES 32 #define PCI_MAX_FUNCTIONS 8 #define PCI_ADDRESS_PORT 0x0CF8 #define PCI_DATA_PORT 0x0CFC #define PCI_INVALID_VENDORID 0xFFFF #define PCI_MULTI_FUNCTION 0x80 #define PCI_TYPE_MASK 0x7F #define PCI_DEVICE 0x00 #define PCI_BRIDGE 0x01 #define PCI_DEVICE_BASE_ADDRESS_COUNT 6 #define PCI_BASE_ADDRESS_MEMORY 0 #define PCI_BASE_ADDRESS_IO 1 #define PCI_BASE_ADDRESS_MEMORY_32 0 #define PCI_BASE_ADDRESS_MEMORY_32_1MB 1 #define PCI_BASE_ADDRESS_MEMORY_64 2 #define PCI_BASE_ADDRESS_SHIFT 4 #define PCI_BASE_ADDRESS_FLAGS_MASK 0xF #pragma pack(1) typedef struct _PCI_CONFIGURATION_SPACE_HEADER { UINT16 VendorId; UINT16 DeviceId; UINT16 Command; UINT16 Status; UINT8 RevisionId; UINT8 ProgrammingInterface; UINT8 SubClass; UINT8 BaseClass; UINT8 CacheLineSize; UINT8 LatencyTimer; UINT8 HeaderType; UINT8 BIST; union { struct { UINT32 BaseAddressRegister[PCI_DEVICE_BASE_ADDRESS_COUNT]; UINT32 CardBusCISPointer; UINT16 SubsystemVendorId; UINT16 SubsystemId; UINT32 ExpansionRomBaseAddress; UINT32 Reserved[2]; UINT8 InterruptLine; UINT8 InterruptPin; UINT8 MinimumGrant; UINT8 MaximumLatency; UINT8 __End; } Device; UINT8 DynamicStart; } u1; } PCI_CONFIGURATION_SPACE_HEADER, *PPCI_CONFIGURATION_SPACE_HEADER; C_ASSERT(FIELD_OFFSET(PCI_CONFIGURATION_SPACE_HEADER, u1.DynamicStart) == 0x10); C_ASSERT(FIELD_OFFSET(PCI_CONFIGURATION_SPACE_HEADER, u1.Device.__End) == 0x40); typedef struct _PCI_CONFIG_ADDRESS { union { struct { UINT32 Zero:2; UINT32 RegisterNumber:6; UINT32 FunctionNumber:3; UINT32 DeviceNumber:5; UINT32 BusNumber:8; UINT32 Reserved:7; UINT32 Enable:1; } s1; UINT32 Value; } u1; } PCI_CONFIG_ADDRESS, *PPCI_CONFIG_ADDRESS; C_ASSERT(sizeof(PCI_CONFIG_ADDRESS) == sizeof(UINT32)); typedef struct _PCI_BASE_ADDRESS { union { struct { UINT32 Type:1; } Common; struct { UINT32 Zero:1; UINT32 Type:2; UINT32 Prefetch:1; UINT32 Base:28; } Memory; struct { UINT64 Zero:1; UINT64 Type:2; UINT64 Prefetch:1; UINT64 Base:60; } Memory64; struct { UINT32 One:1; UINT32 Reserved:1; UINT32 Base:30; } Io; } u1; } PCI_BASE_ADDRESS, *PPCI_BASE_ADDRESS; C_ASSERT(sizeof(((PPCI_BASE_ADDRESS) 0)->u1.Memory) == sizeof(UINT32)); C_ASSERT(sizeof(((PPCI_BASE_ADDRESS) 0)->u1.Memory64) == sizeof(UINT64)); C_ASSERT(sizeof(((PPCI_BASE_ADDRESS) 0)->u1.Io) == sizeof(UINT32)); #pragma pack() PCI_INSTALLATION_CHECK BlPciInstallationCheck; UINT32 BlPciOhci1394BaseAddress; BOOLEAN BlPciCheckBios( PPCI_INSTALLATION_CHECK PciInstallationCheck ) //++ // // Routine Description: // // This function checks for the presence of PCI BIOS. // // Arguments: // // PciInstallationCheck - Receives PCI BIOS information. // // Return Value: // // TRUE, if PCI BIOS is present. // FALSE, otherwise. // //-- { BL_LEGACY_CALL_CONTEXT Context; // // Call PCI detection service. // BlRtlZeroMemory(&Context, sizeof(Context)); Context.eax = 0xB101; BlRtlCallLegacyInterruptService(0x1A, &Context, &Context); // // If CF is set, AH is not zero, or if the signature is not ' ICP', then // there is no PCI BIOS. // if (((Context.eflags & RFLAGS_CF) != 0) || (((Context.eax >> 8) & 0xFF) != 0) || (Context.edx != 0x20494350)) { return FALSE; } // // Populate the provided installation check structure and return success. // PciInstallationCheck->Eax = Context.eax; PciInstallationCheck->Ebx = Context.ebx; PciInstallationCheck->Ecx = Context.ecx; PciInstallationCheck->Edx = Context.edx; PciInstallationCheck->HardwareCharacteristics = (UINT8) (Context.eax & 0xFF); PciInstallationCheck->LastBusNumber = (UINT8) (Context.ecx & 0xFF); PciInstallationCheck->MajorVersion = (UINT8) ((Context.ebx >> 8) & 0xFF); PciInstallationCheck->MinorVersion = (UINT8) (Context.ebx & 0xFF); PciInstallationCheck->ProtectedModeEntryPoint = Context.edi; return TRUE; } UINT32 BlPciReadConfigurationRegister( UINT8 BusNumber, UINT8 DeviceNumber, UINT8 FunctionNumber, UINT8 RegisterNumber ) //++ // // Routine Description: // // This function reads from the specified PCI configuration register. // // Arguments: // // BusNumber - Supplies the PCI bus number. // // DeviceNumber - Supplies the PCI device number. // // FunctionNumber - Supplies the PCI function number. // // RegisterNumber - Supplies the PCI configuration register number. // // Return Value: // // The value of the configuration register. // //-- { PCI_CONFIG_ADDRESS ConfigAddress; UINT32 Value; BLASSERT(DeviceNumber < PCI_MAX_DEVICES); BLASSERT(FunctionNumber < PCI_MAX_FUNCTIONS); BLASSERT((RegisterNumber % sizeof(UINT32)) == 0); BlRtlZeroMemory(&ConfigAddress, sizeof(ConfigAddress)); ConfigAddress.u1.s1.BusNumber = BusNumber; ConfigAddress.u1.s1.DeviceNumber = DeviceNumber; ConfigAddress.u1.s1.FunctionNumber = FunctionNumber; ConfigAddress.u1.s1.RegisterNumber = RegisterNumber >> 2; ConfigAddress.u1.s1.Enable = 1; BlRtlWritePort32(PCI_ADDRESS_PORT, ConfigAddress.u1.Value); Value = BlRtlReadPort32(PCI_DATA_PORT); return Value; } VOID BlPciWriteConfigurationRegister( UINT8 BusNumber, UINT8 DeviceNumber, UINT8 FunctionNumber, UINT8 RegisterNumber, UINT32 Value ) //++ // // Routine Description: // // This function writes to the specified PCI configuration register. // // Arguments: // // BusNumber - Supplies the PCI bus number. // // DeviceNumber - Supplies the PCI device number. // // FunctionNumber - Supplies the PCI function number. // // RegisterNumber - Supplies the PCI configuration register number. // // Value - Supplies the value to write. // //-- { PCI_CONFIG_ADDRESS ConfigAddress; BLASSERT(DeviceNumber < PCI_MAX_DEVICES); BLASSERT(FunctionNumber < PCI_MAX_FUNCTIONS); BLASSERT((RegisterNumber % sizeof(UINT32)) == 0); BlRtlZeroMemory(&ConfigAddress, sizeof(ConfigAddress)); ConfigAddress.u1.s1.BusNumber = BusNumber; ConfigAddress.u1.s1.DeviceNumber = DeviceNumber; ConfigAddress.u1.s1.FunctionNumber = FunctionNumber; ConfigAddress.u1.s1.RegisterNumber = RegisterNumber >> 2; ConfigAddress.u1.s1.Enable = 1; BlRtlWritePort32(PCI_ADDRESS_PORT, ConfigAddress.u1.Value); BlRtlWritePort32(PCI_DATA_PORT, Value); return; } VOID BlPciReadConfigurationSpace( UINT8 BusNumber, UINT8 DeviceNumber, UINT8 FunctionNumber, UINT8 RegisterNumber, PVOID Buffer, UINT16 BufferSize ) //++ // // Routine Description: // // This function reads the specified PCI configuration space range. // // Arguments: // // BusNumber - Supplies the PCI bus number. // // DeviceNumber - Supplies the PCI device number. // // FunctionNumber - Supplies the PCI function number. // // RegisterNumber - Supplies the PCI configuration register number. // // Buffer - Receives configuration data. // // BufferSize - Supplies the number of bytes to read. // //-- { UINT16 Count; UINT16 Index; BLASSERT((RegisterNumber % sizeof(UINT32)) == 0); BLASSERT((BufferSize % sizeof(UINT32)) == 0); Count = BufferSize / sizeof(UINT32); for (Index = 0; Index < Count; Index += 1) { ((PUINT32) Buffer)[Index] = BlPciReadConfigurationRegister(BusNumber, DeviceNumber, FunctionNumber, (UINT8) (RegisterNumber + (Index * sizeof(UINT32)))); } return; } VOID BlPciScanDevices( VOID ) //++ // // Routine Description: // // This function scans all PCI buses on the system. // //-- { UINT64 Address; PPCI_BASE_ADDRESS BaseAddress; UINT8 BaseAddressRegister; UINT8 BusNumber; PCI_CONFIGURATION_SPACE_HEADER Config; UINT8 DeviceNumber; UINT8 FunctionNumber; UINT8 Index; UINT8 NodeType; UINT32 OldValue; UINT32 Size; for (BusNumber = 0; BusNumber <= BlPciInstallationCheck.LastBusNumber; BusNumber += 1) { for (DeviceNumber = 0; DeviceNumber < PCI_MAX_DEVICES; DeviceNumber += 1) { for (FunctionNumber = 0; FunctionNumber < PCI_MAX_FUNCTIONS; FunctionNumber += 1) { BlRtlZeroMemory(&Config, sizeof(Config)); Config.VendorId = PCI_INVALID_VENDORID; BlPciReadConfigurationSpace(BusNumber, DeviceNumber, FunctionNumber, 0, &Config, FIELD_OFFSET(PCI_CONFIGURATION_SPACE_HEADER, u1.DynamicStart)); if ((Config.VendorId == PCI_INVALID_VENDORID) || (Config.VendorId == 0)) { continue; } NodeType = Config.HeaderType & PCI_TYPE_MASK; switch (NodeType) { case PCI_DEVICE: { #if PCI_VERBOSE BlRtlPrintf("PCI: %02x:%02x:%02x: Device %04x:%04x [BC=%02x SC=%02x PI=%02x]\n", BusNumber, DeviceNumber, FunctionNumber, Config.VendorId, Config.DeviceId, Config.BaseClass, Config.SubClass, Config.ProgrammingInterface ); #endif BlPciReadConfigurationSpace(BusNumber, DeviceNumber, FunctionNumber, FIELD_OFFSET(PCI_CONFIGURATION_SPACE_HEADER, u1.DynamicStart), &Config.u1.DynamicStart, FIELD_OFFSET(PCI_CONFIGURATION_SPACE_HEADER, u1.Device.__End) - FIELD_OFFSET(PCI_CONFIGURATION_SPACE_HEADER, u1.DynamicStart)); for (Index = 0; Index < PCI_DEVICE_BASE_ADDRESS_COUNT; Index += 1) { BaseAddress = (PPCI_BASE_ADDRESS) &Config.u1.Device.BaseAddressRegister[Index]; BaseAddressRegister = (UINT8) FIELD_OFFSET(PCI_CONFIGURATION_SPACE_HEADER, u1.Device.BaseAddressRegister[Index]); Address = 0; switch (BaseAddress->u1.Common.Type) { case PCI_BASE_ADDRESS_MEMORY: { SATISFY_OVERZEALOUS_COMPILER(Size = 0); switch (BaseAddress->u1.Memory.Type) { case PCI_BASE_ADDRESS_MEMORY_32: case PCI_BASE_ADDRESS_MEMORY_32_1MB: { Address = BaseAddress->u1.Memory.Base << PCI_BASE_ADDRESS_SHIFT; OldValue = Config.u1.Device.BaseAddressRegister[Index]; BlPciWriteConfigurationRegister(BusNumber, DeviceNumber, FunctionNumber, BaseAddressRegister, (UINT32) -1); Size = BlPciReadConfigurationRegister(BusNumber, DeviceNumber, FunctionNumber, BaseAddressRegister); BlPciWriteConfigurationRegister(BusNumber, DeviceNumber, FunctionNumber, BaseAddressRegister, OldValue); Size &= ~(PCI_BASE_ADDRESS_FLAGS_MASK); Size = (~Size) + 1; break; } case PCI_BASE_ADDRESS_MEMORY_64: { Address = BaseAddress->u1.Memory64.Base << PCI_BASE_ADDRESS_SHIFT; OldValue = Config.u1.Device.BaseAddressRegister[Index]; BlPciWriteConfigurationRegister(BusNumber, DeviceNumber, FunctionNumber, BaseAddressRegister, (UINT32) -1); Size = BlPciReadConfigurationRegister(BusNumber, DeviceNumber, FunctionNumber, BaseAddressRegister); BlPciWriteConfigurationRegister(BusNumber, DeviceNumber, FunctionNumber, BaseAddressRegister, OldValue); Size &= ~(PCI_BASE_ADDRESS_FLAGS_MASK); Size = (~Size) + 1; Index += 1; break; } } if (Address != 0) { BLASSERT(Size > 0); #if PCI_VERBOSE BlRtlPrintf("PCI: %02x:%02x:%02x: IO Memory [%016I64x ... %016I64x]\n", BusNumber, DeviceNumber, FunctionNumber, Address, Address + Size - 1); #endif if ((Address >= LEGACY_MEMORY_LIMIT) && ((Address + Size) > Address) && ((Address + Size) <= 0x100000000UI64) ) { BlMmMapVirtualRange((PVOID) (ULONG_PTR) Address, (PVOID) (ULONG_PTR) Address, Size, TRUE, (BOOLEAN) BaseAddress->u1.Memory.Prefetch, FALSE); } // // Check if this memory range maps OHCI 1394 registers. // if ((Config.BaseClass == 0x0C) && (Config.SubClass == 0x00) && (Config.ProgrammingInterface == 0x10) && (BlPciOhci1394BaseAddress == 0)) { BlPciOhci1394BaseAddress = (UINT32) Address; } } break; } } } break; } case PCI_BRIDGE: { #if PCI_VERBOSE BlRtlPrintf("PCI: %02x:%02x:%02x: Bridge %04x:%04x\n", BusNumber, DeviceNumber, FunctionNumber, Config.VendorId, Config.DeviceId); #endif break; } } if ((Config.HeaderType & PCI_MULTI_FUNCTION) == 0) { break; } } } } } VOID BlPciInitialize( VOID ) //++ // // Routine Description: // // This function initializes PCI support. // //-- { if (BlPciCheckBios(&BlPciInstallationCheck) == FALSE) { BlRtlPrintf("pci: PCI BIOS not detected!\n"); BlRtlHalt(); } #if PCI_VERBOSE BlRtlPrintf("PCI: PCI BIOS detected.\n" "PCI: Version : %u.%u\n" "PCI: Last Bus Number : %u\n", BlPciInstallationCheck.MajorVersion, BlPciInstallationCheck.MinorVersion, BlPciInstallationCheck.LastBusNumber); #endif BlPciScanDevices(); return; } ================================================ FILE: ironclad-apps/src/Checked/BootLoader/SingLdrPc/blpecoff.cpp ================================================ //++ // // Copyright (c) Microsoft Corporation // // Module Name: // // blpecoff.cpp // // Abstract: // // This module implements PE / COFF support for the boot loader. // //-- #include "bl.h" #define IMAGE_DOS_SIGNATURE 0x05A4D // MZ #define IMAGE_NT_SIGNATURE 0x000004550 // PE00 typedef struct _IMAGE_DOS_HEADER { //- DOS .EXE header UINT16 e_magic; //- Magic number UINT16 e_cblp; //- Bytes on last page of file UINT16 e_cp; //- Pages in file UINT16 e_crlc; //- Relocations UINT16 e_cparhdr; //- Size of header in paragraphs UINT16 e_minalloc; //- Minimum extra paragraphs needed UINT16 e_maxalloc; //- Maximum extra paragraphs needed UINT16 e_ss; //- Initial (relative) SS value UINT16 e_sp; //- Initial SP value UINT16 e_csum; //- Checksum UINT16 e_ip; //- Initial IP value UINT16 e_cs; //- Initial (relative) CS value UINT16 e_lfarlc; //- File address of relocation table UINT16 e_ovno; //- Overlay number UINT16 e_res[4]; //- Reserved words UINT16 e_oemid; //- OEM identifier (for e_oeminfo) UINT16 e_oeminfo; //- OEM information; e_oemid specific UINT16 e_res2[10]; //- Reserved words INT32 e_lfanew; //- File address of new exe header } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; typedef struct _IMAGE_FILE_HEADER { UINT16 Machine; UINT16 NumberOfSections; UINT32 TimeDateStamp; UINT32 PointerToSymbolTable; UINT32 NumberOfSymbols; UINT16 SizeOfOptionalHeader; UINT16 Characteristics; } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; typedef struct _IMAGE_DATA_DIRECTORY { UINT32 VirtualAddress; UINT32 Size; } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; #define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 #define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 #if defined(BOOT_X86) typedef struct _IMAGE_OPTIONAL_HEADER_32 { UINT16 Magic; UINT8 MajorLinkerVersion; UINT8 MinorLinkerVersion; UINT32 SizeOfCode; UINT32 SizeOfInitializedData; UINT32 SizeOfUninitializedData; UINT32 AddressOfEntryPoint; UINT32 BaseOfCode; UINT32 BaseOfData; UINT32 ImageBase; UINT32 SectionAlignment; UINT32 FileAlignment; UINT16 MajorOperatingSystemVersion; UINT16 MinorOperatingSystemVersion; UINT16 MajorImageVersion; UINT16 MinorImageVersion; UINT16 MajorSubsystemVersion; UINT16 MinorSubsystemVersion; UINT32 Win32VersionValue; UINT32 SizeOfImage; UINT32 SizeOfHeaders; UINT32 CheckSum; UINT16 Subsystem; UINT16 DllCharacteristics; UINT32 SizeOfStackReserve; UINT32 SizeOfStackCommit; UINT32 SizeOfHeapReserve; UINT32 SizeOfHeapCommit; UINT32 LoaderFlags; UINT32 NumberOfRvaAndSizes; IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; } IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32; typedef struct _IMAGE_NT_HEADERS32 { UINT32 Signature; IMAGE_FILE_HEADER FileHeader; IMAGE_OPTIONAL_HEADER32 OptionalHeader; } IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32; typedef IMAGE_NT_HEADERS32 IMAGE_NT_HEADERS, *PIMAGE_NT_HEADERS; #elif defined(BOOT_X64) typedef struct _IMAGE_OPTIONAL_HEADER64 { UINT16 Magic; UINT8 MajorLinkerVersion; UINT8 MinorLinkerVersion; UINT32 SizeOfCode; UINT32 SizeOfInitializedData; UINT32 SizeOfUninitializedData; UINT32 AddressOfEntryPoint; UINT32 BaseOfCode; UINT64 ImageBase; UINT32 SectionAlignment; UINT32 FileAlignment; UINT16 MajorOperatingSystemVersion; UINT16 MinorOperatingSystemVersion; UINT16 MajorImageVersion; UINT16 MinorImageVersion; UINT16 MajorSubsystemVersion; UINT16 MinorSubsystemVersion; UINT32 Win32VersionValue; UINT32 SizeOfImage; UINT32 SizeOfHeaders; UINT32 CheckSum; UINT16 Subsystem; UINT16 DllCharacteristics; UINT64 SizeOfStackReserve; UINT64 SizeOfStackCommit; UINT64 SizeOfHeapReserve; UINT64 SizeOfHeapCommit; UINT32 LoaderFlags; UINT32 NumberOfRvaAndSizes; IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; } IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64; typedef struct _IMAGE_NT_HEADERS64 { UINT32 Signature; IMAGE_FILE_HEADER FileHeader; IMAGE_OPTIONAL_HEADER64 OptionalHeader; } IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64; typedef IMAGE_NT_HEADERS64 IMAGE_NT_HEADERS, *PIMAGE_NT_HEADERS; #endif #define IMAGE_SIZEOF_SHORT_NAME 8 typedef struct _IMAGE_SECTION_HEADER { UINT8 Name[IMAGE_SIZEOF_SHORT_NAME]; union { UINT32 PhysicalAddress; UINT32 VirtualSize; } Misc; UINT32 VirtualAddress; UINT32 SizeOfRawData; UINT32 PointerToRawData; UINT32 PointerToRelocations; UINT32 PointerToLinenumbers; UINT16 NumberOfRelocations; UINT16 NumberOfLinenumbers; UINT32 Characteristics; } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; typedef struct _IMAGE_BASE_RELOCATION { UINT32 VirtualAddress; UINT32 SizeOfBlock; UINT16 TypeOffset[0]; } IMAGE_BASE_RELOCATION, *PIMAGE_BASE_RELOCATION; #define IMAGE_REL_BASED_ABSOLUTE 0 #define IMAGE_REL_BASED_HIGHLOW 3 #define IMAGE_REL_BASED_DIR64 10 VOID BlPeGetVirtualRange( PVOID Image, PVOID *VirtualBase, ULONG_PTR *VirtualSize ) //-++ //- //- Routine Description: //- //- This function queries the virtual range for the specified image. //- //- Arguments: //- //- Image - Supplies a pointer to the image. //- //- VirtualBase - Receives the virtual base address of the image. //- //- VirtualSize - Receives the virtual size of the image. //- //--- { PIMAGE_DOS_HEADER DosHeader; UINT32 Index; PIMAGE_NT_HEADERS NtHeader; PIMAGE_SECTION_HEADER Section; UINT32 SectionEnd; DosHeader = (PIMAGE_DOS_HEADER) Image; if (DosHeader->e_magic != IMAGE_DOS_SIGNATURE) { BlRtlPrintf("PECOFF: Invalid image!\n"); BlRtlHalt(); } NtHeader = (PIMAGE_NT_HEADERS) ((ULONG_PTR) Image + DosHeader->e_lfanew); if (NtHeader->Signature != IMAGE_NT_SIGNATURE) { BlRtlPrintf("PECOFF: Invalid image!\n"); BlRtlHalt(); } if (NtHeader->FileHeader.NumberOfSections == 0) { BlRtlPrintf("PECOFF: Invalid image!\n"); BlRtlHalt(); } if ((NtHeader->OptionalHeader.ImageBase % PAGE_SIZE) != 0) { BlRtlPrintf("PECOFF: Invalid image!\n"); BlRtlHalt(); } *VirtualBase = (PVOID) NtHeader->OptionalHeader.ImageBase; *VirtualSize = 0; Section = (PIMAGE_SECTION_HEADER) (((ULONG_PTR) &NtHeader->OptionalHeader) + NtHeader->FileHeader.SizeOfOptionalHeader); for (Index = 0; Index < NtHeader->FileHeader.NumberOfSections; Index += 1) { SectionEnd = Section[Index].VirtualAddress + Section[Index].Misc.VirtualSize; if (SectionEnd > *VirtualSize) { *VirtualSize = SectionEnd; } } *VirtualSize = ROUND_UP_TO_PAGES(*VirtualSize); return; } VOID BlPeApplyFixupBlock( PIMAGE_BASE_RELOCATION Block, ULONG_PTR VirtualBase, ULONG_PTR RelocDiff ) //-++ //- //- Routine Description: //- //- This function applies all of the base fixups in the specified block to the image. //- //- Arguments: //- //- Block - Supplies a pointer to the base relocation fixup block. //- //- VirtualBase - Supplies the target address of the image. //- //- RelocDiff - Supplies the offset of the image target address from the base address. //- //--- { PUINT16 Reloc; PUINT16 BlockEnd; ULONG_PTR BlockBase; ULONG_PTR Target; Reloc = Block->TypeOffset; BlockEnd = (PUINT16) ( ((PUINT8) Block) + Block->SizeOfBlock); BlockBase = VirtualBase + Block->VirtualAddress; #if PECOFF_VERBOSE BlRtlPrintf("PECOFF: Reloc Block %p:\n", Block->VirtualAddress); #endif for (; Reloc < BlockEnd; Reloc++) { Target = BlockBase + (*Reloc & 0xfff); #if PECOFF_VERBOSE switch (*Reloc >> 12) { case IMAGE_REL_BASED_ABSOLUTE: { BlRtlPrintf("PECOFF: %p: abs:%x \r", (PUINT32) Target, * (PUINT32) Target); break; } case IMAGE_REL_BASED_HIGHLOW: { BlRtlPrintf("PECOFF: %p: r32:%x->%x \r", (PUINT32) Target, * (PUINT32) Target, * (PUINT32) Target + (UINT32) RelocDiff); break; } case IMAGE_REL_BASED_DIR64: { BlRtlPrintf("PECOFF: %p: r64:%lx->%lx \r", (PUINT64) Target, * (PUINT64) Target, * (PUINT64) Target + (UINT64) RelocDiff); break; } default: { BlRtlPrintf("PECOFF: %p: %x ??? \r", (PUINT32) Target, Reloc[0] >> 12); break; } } #endif switch (*Reloc >> 12) { case IMAGE_REL_BASED_ABSOLUTE: { break; } case IMAGE_REL_BASED_HIGHLOW: { * (PUINT32) Target += (UINT32) RelocDiff; break; } case IMAGE_REL_BASED_DIR64: { * (PUINT64 *) Target += (UINT64) RelocDiff; break; } default: { BlRtlPrintf("PECOFF: Illegal relocation.\n"); BlRtlHalt(); } } } } VOID BlPeLoadImage( PVOID LoadBase, UINT32 ImageSize, PVOID Image, PVOID *EntryPoint, BOOLEAN isSLB ) //-++ //- //- Routine Description: //- //- This function loads the specified image. //- //- Arguments: //- //- Image - Supplies a pointer to the image to load. //- //- EntryPoint - Receives a pointer to the entry point of the image. //- //--- { ULONG_PTR BytesToCopy; PIMAGE_DOS_HEADER DosHeader; UINT32 Index; PIMAGE_NT_HEADERS NtHeader; PIMAGE_SECTION_HEADER Section; ULONG_PTR VirtualBase; ULONG_PTR RelocDiff; VirtualBase = (ULONG_PTR) LoadBase; DosHeader = (PIMAGE_DOS_HEADER) Image; if (DosHeader->e_magic != IMAGE_DOS_SIGNATURE) { BlRtlPrintf("PECOFF: Missing MZ!\n"); BlRtlHalt(); } NtHeader = (PIMAGE_NT_HEADERS) ((ULONG_PTR) Image + DosHeader->e_lfanew); if (NtHeader->Signature != IMAGE_NT_SIGNATURE) { BlRtlPrintf("PECOFF: Missing PE!\n"); BlRtlHalt(); } if (NtHeader->FileHeader.NumberOfSections == 0) { BlRtlPrintf("PECOFF: No sections!\n"); BlRtlHalt(); } if ((NtHeader->OptionalHeader.ImageBase % PAGE_SIZE) != 0) { BlRtlPrintf("PECOFF: Not page aligned.\n"); BlRtlHalt(); } if (isSLB && ImageSize > 64*1024) { BlRtlPrintf("PECOFF: Image is too large for late launch!\n"); BlRtlHalt(); } //- Zero out the entire range of memory used by the kernel, //- to ensure a consistent measurement during late launch via SKINIT BlRtlZeroMemory((PVOID) VirtualBase, ImageSize); BlRtlCopyMemory((PVOID) VirtualBase, Image, NtHeader->OptionalHeader.SizeOfHeaders); Section = (PIMAGE_SECTION_HEADER) (((ULONG_PTR) &NtHeader->OptionalHeader) + NtHeader->FileHeader.SizeOfOptionalHeader); for (Index = 0; Index < NtHeader->FileHeader.NumberOfSections; Index += 1) { BlRtlZeroMemory((PVOID) (VirtualBase + Section[Index].VirtualAddress), Section[Index].Misc.VirtualSize); if (Section[Index].SizeOfRawData < Section[Index].Misc.VirtualSize) { BytesToCopy = Section[Index].SizeOfRawData; } else { BytesToCopy = Section[Index].Misc.VirtualSize; } BlRtlCopyMemory((PVOID) (VirtualBase + Section[Index].VirtualAddress), (PVOID) (((ULONG_PTR) Image) + Section[Index].PointerToRawData), BytesToCopy); #if PECOFF_VERBOSE { CHAR Temp[IMAGE_SIZEOF_SHORT_NAME + 1]; BlRtlCopyMemory(Temp, Section[Index].Name, IMAGE_SIZEOF_SHORT_NAME); Temp[IMAGE_SIZEOF_SHORT_NAME] = 0; BlRtlPrintf("PECOFF: %p ... %p (%p ... %p) %s\n", VirtualBase + Section[Index].VirtualAddress, VirtualBase + Section[Index].VirtualAddress + Section[Index].Misc.VirtualSize - 1, (((ULONG_PTR) Image) + Section[Index].PointerToRawData), (((ULONG_PTR) Image) + Section[Index].PointerToRawData) + BytesToCopy, Temp); } #endif } RelocDiff = VirtualBase - (ULONG_PTR)NtHeader->OptionalHeader.ImageBase; if (RelocDiff != 0) { PUINT8 RelocList; PUINT8 RelocListEnd; PIMAGE_BASE_RELOCATION Block; RelocList = (PUINT8) (VirtualBase + NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress); RelocListEnd = RelocList + NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size; #if PECOFF_VERBOSE BlRtlPrintf("PECOFF: Relocs: %p ... %p\n", RelocList, RelocListEnd); #endif while (RelocList < RelocListEnd) { Block = (PIMAGE_BASE_RELOCATION) RelocList; BlPeApplyFixupBlock(Block, VirtualBase, RelocDiff); RelocList += Block->SizeOfBlock; } } *EntryPoint = (PVOID) (VirtualBase + NtHeader->OptionalHeader.AddressOfEntryPoint); if (isSLB) { //- Prepare the secure loader image with the necessary header //- Make sure the first 32 bits of the image are [31..16] == length and [15..0] == entry point *((UINT32*)VirtualBase) = (ImageSize << 16) | (NtHeader->OptionalHeader.AddressOfEntryPoint & 0x0000FFFF); BlRtlPrintf("PECOFF: Base: %p AddressOfEntryPoint: %p ImageSize: %p\n", VirtualBase, NtHeader->OptionalHeader.AddressOfEntryPoint, ImageSize); } return; } ================================================ FILE: ironclad-apps/src/Checked/BootLoader/SingLdrPc/blpnp.cpp ================================================ //++ // // Copyright (c) Microsoft Corporation // // Module Name: // // blpnp.cpp // // Abstract: // // This module implements PNP BIOS support for the boot loader environment. // //-- #include "bl.h" // // PNP status codes. // #define PNP_STATUS_SUCCESS 0x0000 typedef UINT16 PNP_STATUS; // // PNP enumeration terminator value. // #define PNP_NO_MORE_NODES 0xFF // // PNP BIOS state. // PPNP_INSTALLATION_CHECK BlPnpBiosInformation; PPNP_SYSTEM_DEVICE_NODE BlPnpSystemDeviceNodeList; UINT32 BlPnpSystemDeviceNodeListSize; PNP_ISA_CONFIGURATION BlPnpIsaConfiguration; // // The following variables are in the global data segment to ensure that // they are located in legacy memory (i.e. in the 1st MB of memory) so // that BIOS calls can access them. // UINT16 BlPnpCallFrame[16]; UINT8 BlPnpHandle; UINT8 BlPnpNodeData[PAGE_SIZE]; UINT32 BlPnpNodeSize; UINT8 BlPnpNumberOfNodes; PNP_STATUS BlPnpGetNumberOfSystemDeviceNodes( PUINT8 NumberOfNodes, PUINT32 NodeSize, UINT16 BiosSelector ) //++ // // Routine Description: // // This function queries the number of PNP system device nodes. // // Arguments: // // NumberOfNodes - Receives the number of nodes. // // NodeSize - Receives the size of the largest node. // // BiosSelector - Supplies the selector for the PNP BIOS. // // Return Value: // // PNP BIOS status code. // //-- { BL_LEGACY_CALL_CONTEXT Context; BlPnpNumberOfNodes = 0; BlPnpNodeSize = 0; BlPnpCallFrame[0] = 0; BlRtlConvertLinearPointerToFarPointer(&BlPnpNumberOfNodes, (PFAR_POINTER) &BlPnpCallFrame[1]); BlRtlConvertLinearPointerToFarPointer(&BlPnpNodeSize, (PFAR_POINTER) &BlPnpCallFrame[3]); BlPnpCallFrame[5] = BiosSelector; BlRtlZeroMemory(&Context, sizeof(BL_LEGACY_CALL_CONTEXT)); BlRtlCallLegacyFunction(BlPnpBiosInformation->RealModeCodeSegment16, BlPnpBiosInformation->RealModeCodeOffset16, BlPnpCallFrame, 6 * sizeof(UINT16), &Context, &Context); if ((PNP_STATUS) Context.eax == PNP_STATUS_SUCCESS) { *NumberOfNodes = BlPnpNumberOfNodes; *NodeSize = BlPnpNodeSize; } return (PNP_STATUS) Context.eax; } PNP_STATUS BlPnpGetSystemDeviceNode( PUINT8 Handle, PPNP_SYSTEM_DEVICE_NODE Node, UINT32 NodeSize, UINT16 Control, UINT16 BiosSelector ) //++ // // Routine Description: // // This function queries the specified PNP system device nodes. // // Arguments: // // Handle - Supplies a pointer to the variable containing // the handle to query at entry and the next available // handle at exit. // // Node - Receives node information. // // NodeSize - Supplies the size of the node structure. // // Control - Supplies query control flags. // // BiosSelector - Supplies the selector for the PNP BIOS. // // Return Value: // // PNP BIOS status code. // //-- { BL_LEGACY_CALL_CONTEXT Context; BLASSERT(NodeSize > 0); BLASSERT(NodeSize <= sizeof(BlPnpNodeData)); BlPnpHandle = *Handle; BlPnpCallFrame[0] = 1; BlRtlConvertLinearPointerToFarPointer(&BlPnpHandle, (PFAR_POINTER) &BlPnpCallFrame[1]); BlRtlConvertLinearPointerToFarPointer(BlPnpNodeData, (PFAR_POINTER) &BlPnpCallFrame[3]); BlPnpCallFrame[5] = Control; BlPnpCallFrame[6] = BiosSelector; BlRtlZeroMemory(&Context, sizeof(BL_LEGACY_CALL_CONTEXT)); BlRtlCallLegacyFunction(BlPnpBiosInformation->RealModeCodeSegment16, BlPnpBiosInformation->RealModeCodeOffset16, BlPnpCallFrame, 7 * sizeof(UINT16), &Context, &Context); if ((PNP_STATUS) Context.eax == PNP_STATUS_SUCCESS) { *Handle = BlPnpHandle; BLASSERT(((PPNP_SYSTEM_DEVICE_NODE) BlPnpNodeData)->Size <= NodeSize); BlRtlCopyMemory(Node, BlPnpNodeData, ((PPNP_SYSTEM_DEVICE_NODE) BlPnpNodeData)->Size); } return (PNP_STATUS) Context.eax; } PNP_STATUS BlPnpGetIsaConfiguration( PPNP_ISA_CONFIGURATION IsaConfiguration, UINT16 BiosSelector ) //++ // // Routine Description: // // This function queries PNP ISA configuration. // // Arguments: // // IsaConfiguration - Receive PNP ISA configuration. // // BiosSelector - Supplies the selector for the PNP BIOS. // // Return Value: // // PNP BIOS status code. // //-- { BL_LEGACY_CALL_CONTEXT Context; BlRtlZeroMemory(IsaConfiguration, sizeof(PNP_ISA_CONFIGURATION)); IsaConfiguration->Revision = 1; BlPnpCallFrame[0] = 0x40; BlRtlConvertLinearPointerToFarPointer(IsaConfiguration, (PFAR_POINTER) &BlPnpCallFrame[1]); BlPnpCallFrame[3] = BiosSelector; BlRtlZeroMemory(&Context, sizeof(BL_LEGACY_CALL_CONTEXT)); BlRtlCallLegacyFunction(BlPnpBiosInformation->RealModeCodeSegment16, BlPnpBiosInformation->RealModeCodeOffset16, BlPnpCallFrame, 4 * sizeof(UINT16), &Context, &Context); return (PNP_STATUS) Context.eax; } PPNP_INSTALLATION_CHECK BlPnpLocateBios( VOID ) //++ // // Routine Description: // // This function locates the PNP BIOS by searching the ROM area. // // Return Value: // // PNP BIOS installation check structure, if located. // NULL, otherwise. // //-- { ULONG_PTR End; PPNP_INSTALLATION_CHECK Pnp; ULONG_PTR Start; Start = 0xF0000; End = 0x100000; while (Start != End) { Pnp = (PPNP_INSTALLATION_CHECK) Start; if ((Pnp->Signature[0] == '$') && (Pnp->Signature[1] == 'P') && (Pnp->Signature[2] == 'n') && (Pnp->Signature[3] == 'P') && (Pnp->Version == 0x10) && (Pnp->Length == 0x21) && (BlRtlComputeChecksum8(Pnp, Pnp->Length) == 0) ) { return Pnp; } Start += 16; } return NULL; } VOID BlPnpInitialize( VOID ) //++ // // Routine Description: // // This function initializes PNP BIOS support. // //-- { UINT8 Handle; PPNP_SYSTEM_DEVICE_NODE Node; UINT32 NodeListSize; UINT32 NodeSize; UINT8 NumberOfNodes; PPNP_INSTALLATION_CHECK Pnp; PNP_STATUS Result; // // Initialize empty node list. // BlPnpSystemDeviceNodeList = NULL; BlPnpSystemDeviceNodeListSize = 0; // // Locate PNP BIOS. // Pnp = BlPnpLocateBios(); if (Pnp == NULL) { #if PNP_VERBOSE BlRtlPrintf("PNP: PNP BIOS not found!\n"); #endif return; } #if PNP_VERBOSE BlRtlPrintf("PNP: PNP BIOS detected @ %p\n", Pnp); #endif BlPnpBiosInformation = Pnp; #if PNP_VERBOSE BlRtlPrintf("PNP: Real-Mode Code: %04x:%04x\n", Pnp->RealModeCodeSegment16, Pnp->RealModeCodeOffset16); BlRtlPrintf("PNP: Real-Mode Data: %04x:\n", Pnp->RealModeDataSegment16); #endif // // Build PNP system device node list. // Result = BlPnpGetNumberOfSystemDeviceNodes(&NumberOfNodes, &NodeSize, Pnp->RealModeDataSegment16); if (Result != PNP_STATUS_SUCCESS) { #if PNP_VERBOSE BlRtlPrintf("PNP: BlPnpGetNumberOfSystemDeviceNodes failed with error %04x.\n", Result); #endif return; } #if PNP_VERBOSE BlRtlPrintf("PNP: %u node(s), %u bytes in largest node.\n", NumberOfNodes, NodeSize); #endif if (NumberOfNodes == 0) { return; } Node = (PPNP_SYSTEM_DEVICE_NODE) BlPoolAllocateBlock(NodeSize); NodeListSize = 0; Handle = 0; for (;;) { BlRtlZeroMemory(Node, sizeof(*Node)); Result = BlPnpGetSystemDeviceNode(&Handle, Node, NodeSize, 1, Pnp->RealModeDataSegment16); if (Result != PNP_STATUS_SUCCESS) { #if PNP_VERBOSE BlRtlPrintf("PNP: BlPnpGetSystemDeviceNode failed with error %04x.\n", Result); #endif BlPoolFreeBlock(Node); return; } NodeListSize += Node->Size; if (Handle == PNP_NO_MORE_NODES) { break; } } BlPnpSystemDeviceNodeList = (PPNP_SYSTEM_DEVICE_NODE)BlPoolAllocateBlock(NodeListSize); BlPnpSystemDeviceNodeListSize = NodeListSize; Node = BlPnpSystemDeviceNodeList; Handle = 0; for (;;) { BlRtlZeroMemory(Node, sizeof(*Node)); Result = BlPnpGetSystemDeviceNode(&Handle, Node, NodeSize, 1, Pnp->RealModeDataSegment16); if (Result != PNP_STATUS_SUCCESS) { BlRtlPrintf("PNP: BlPnpGetSystemDeviceNode failed with error %04x.\n", Result); BlRtlHalt(); } if (Handle == PNP_NO_MORE_NODES) { break; } Node = (PPNP_SYSTEM_DEVICE_NODE) (((ULONG_PTR) Node) + Node->Size); NodeSize -= Node->Size; } #if PNP_VERBOSE BlRtlPrintf("PNP: DeviceNodeList: %p ... %p\n", BlPnpSystemDeviceNodeList, (ULONG_PTR) BlPnpSystemDeviceNodeList + BlPnpSystemDeviceNodeListSize - 1); #endif // // Query PNP ISA configuration. // BlPnpGetIsaConfiguration(&BlPnpIsaConfiguration, Pnp->RealModeDataSegment16); #if PNP_VERBOSE BlRtlPrintf("PNP: ISA Configuration:\n" "PNP: Revision : %u\n" "PNP: # of Card Select Numbers : %u\n" "PNP: Data read port : %04x\n", BlPnpIsaConfiguration.Revision, BlPnpIsaConfiguration.NumberOfCardSelectNumbers, BlPnpIsaConfiguration.DataReadPort); #endif return; } ================================================ FILE: ironclad-apps/src/Checked/BootLoader/SingLdrPc/blpool.cpp ================================================ //++ // // Copyright (c) Microsoft Corporation // // Module Name: // // blpool.cpp // // Abstract: // // This module implements pool support for the boot loader environment. // //-- #include "bl.h" #define BL_POOL_FREE 1 #define BL_POOL_BUSY 2 #define BL_POOL_GRANULARITY 256 C_ASSERT((BL_POOL_GRANULARITY & (BL_POOL_GRANULARITY - 1)) == 0); #define BL_POOL_ROUND_UP(X) ROUND_UP_TO_POWER2(X, BL_POOL_GRANULARITY) #define BL_POOL_SEGMENT_SIZE (8 * PAGE_SIZE) C_ASSERT((BL_POOL_SEGMENT_SIZE & (BL_POOL_SEGMENT_SIZE - 1)) == 0); #define BL_POOL_SEGMENT_ROUND_UP(X) ((X + (BL_POOL_SEGMENT_SIZE - 1)) & (~(BL_POOL_SEGMENT_SIZE - 1))) #if defined(BOOT_X86) #define BL_POOL_BLOCK_MAGIC1 0x01020304 #define BL_POOL_BLOCK_MAGIC2 0x05060708 #elif defined(BOOT_X64) #define BL_POOL_BLOCK_MAGIC1 0x0102030405060708UI64 #define BL_POOL_BLOCK_MAGIC2 0x090A0B0C0D0E0F10UI64 #endif typedef struct _BL_POOL_BLOCK { ULONG_PTR Magic1; LIST_ENTRY Entry; ULONG_PTR Size; ULONG_PTR State; PVOID Allocator; ULONG_PTR Pad; ULONG_PTR Magic2; } BL_POOL_BLOCK, *PBL_POOL_BLOCK; C_ASSERT((sizeof(BL_POOL_BLOCK) % 16) == 0); #if defined(BOOT_X86) #define BL_POOL_SEGMENT_MAGIC1 0xFFFEFDFC #define BL_POOL_SEGMENT_MAGIC2 0xFBFAF9F8 #elif defined(BOOT_X64) #define BL_POOL_SEGMENT_MAGIC1 0xFFFEFDFCFBFAF9F8UI64 #define BL_POOL_SEGMENT_MAGIC2 0xF7F6F5F4F3F2F1F0UI64 #endif typedef struct _BL_POOL_SEGMENT { ULONG_PTR Magic1; LIST_ENTRY Entry; ULONG_PTR Size; ULONG_PTR Start; ULONG_PTR Limit; LIST_ENTRY BlockList; ULONG_PTR Magic2; } BL_POOL_SEGMENT, *PBL_POOL_SEGMENT; LIST_ENTRY BlPoolSegmentList; VOID BlPoolInitialize( VOID ) //++ // // Routine Description: // // This function initializes boot loader pool. // //-- { BlRtlInitializeListHead(&BlPoolSegmentList); #if POOL_VERBOSE BlRtlPrintf("POOL: Segment list @ %p.\n", &BlPoolSegmentList); #endif return; } #if DEBUG VOID BlPoolDump( VOID ) //++ // // Routine Description: // // This function dumps boot loader pool. // //-- { PBL_POOL_BLOCK Block; PLIST_ENTRY BlockEntry; PLIST_ENTRY BlockHead; PBL_POOL_SEGMENT Segment; PLIST_ENTRY SegmentEntry; PLIST_ENTRY SegmentHead; BlRtlPrintf("POOL: BlDumpPool: \n"); SegmentHead = &BlPoolSegmentList; for (SegmentEntry = SegmentHead->Flink; SegmentEntry != SegmentHead; SegmentEntry = SegmentEntry->Flink) { Segment = CONTAINING_RECORD(SegmentEntry, BL_POOL_SEGMENT, Entry); BlRtlPrintf("POOL: BlDumpPool: Segment @ %p\n", Segment); BlockHead = &Segment->BlockList; for (BlockEntry = BlockHead->Flink; BlockEntry != BlockHead; BlockEntry = BlockEntry->Flink) { Block = CONTAINING_RECORD(BlockEntry, BL_POOL_BLOCK, Entry); BlRtlPrintf("POOL: BlDumpPool: Entry %p ... %p [%u]\n", Block, (ULONG_PTR) Block + Block->Size, Block->State); } } BlRtlPrintf("pool: BlDumpPool: \n"); return; } #endif VOID BlPoolVerify( VOID ) //++ // // Routine Description: // // This function verifies boot loader pool. // //-- { PBL_POOL_BLOCK Block; PLIST_ENTRY BlockEntry; PLIST_ENTRY BlockHead; PBL_POOL_BLOCK NextBlock; PBL_POOL_SEGMENT Segment; PLIST_ENTRY SegmentEntry; PLIST_ENTRY SegmentHead; SegmentHead = &BlPoolSegmentList; BLASSERT(SegmentHead->Flink->Blink == SegmentHead); BLASSERT(SegmentHead->Blink->Flink == SegmentHead); for (SegmentEntry = SegmentHead->Flink; SegmentEntry != SegmentHead; SegmentEntry = SegmentEntry->Flink) { Segment = CONTAINING_RECORD(SegmentEntry, BL_POOL_SEGMENT, Entry); BLASSERT_PTR(Segment->Magic1 == BL_POOL_SEGMENT_MAGIC1, Segment); BLASSERT_PTR(Segment->Magic2 == BL_POOL_SEGMENT_MAGIC2, Segment); BLASSERT_PTR(Segment->Entry.Flink->Blink == &Segment->Entry, Segment); BLASSERT_PTR(Segment->Entry.Blink->Flink == &Segment->Entry, Segment); BlockHead = &Segment->BlockList; for (BlockEntry = BlockHead->Flink; BlockEntry != BlockHead; BlockEntry = BlockEntry->Flink) { Block = CONTAINING_RECORD(BlockEntry, BL_POOL_BLOCK, Entry); BLASSERT_PTR(Block->Magic1 == BL_POOL_BLOCK_MAGIC1, Block); BLASSERT_PTR(Block->Magic2 == BL_POOL_BLOCK_MAGIC2, Block); BLASSERT_PTR((Block->State == BL_POOL_FREE) || ((Block->State == BL_POOL_BUSY)), Block); BLASSERT_PTR(((ULONG_PTR) Block % BL_POOL_GRANULARITY) == 0, Block); BLASSERT_PTR(Block->Size > sizeof(BL_POOL_BLOCK), Block); BLASSERT_PTR((Block->Size % BL_POOL_GRANULARITY) == 0, Block); if (Block->Entry.Flink != BlockHead) { NextBlock = CONTAINING_RECORD(Block->Entry.Flink, BL_POOL_BLOCK, Entry); BLASSERT_PTR(((ULONG_PTR) Block + Block->Size) == ((ULONG_PTR) NextBlock), Block); } BLASSERT_PTR(Block->Entry.Flink->Blink == &Block->Entry, Block); BLASSERT_PTR(Block->Entry.Blink->Flink == &Block->Entry, Block); } } return; } VOID BlPoolGrow( UINT32 Size ) //++ // // Routine Description: // // This function grows the pool. // // Arguments: // // Size - Supplies the growth size. // //-- { PBL_POOL_BLOCK Block; PBL_POOL_SEGMENT Segment; BlPoolVerify(); BLASSERT(Size > 0); Size = ROUND_UP_TO_PAGES(Size); Segment = (PBL_POOL_SEGMENT) (ULONG_PTR) BlMmAllocatePhysicalRegion(Size, BL_MM_PHYSICAL_REGION_BOOT_LOADER); BlRtlZeroMemory(Segment, Size); Segment->Magic1 = BL_POOL_SEGMENT_MAGIC1; Segment->Magic2 = BL_POOL_SEGMENT_MAGIC2; Segment->Start = (ULONG_PTR) Segment; Segment->Size = Size; Segment->Limit = Segment->Start + Segment->Size; BlRtlInitializeListHead(&Segment->BlockList); Block = (PBL_POOL_BLOCK) (BL_POOL_ROUND_UP(((ULONG_PTR) (Segment + 1)))); Block->Magic1 = BL_POOL_BLOCK_MAGIC1; Block->Magic2 = BL_POOL_BLOCK_MAGIC2; Block->Size = Segment->Limit - (ULONG_PTR) Block; Block->State = BL_POOL_FREE; Block->Allocator = NULL; BlRtlInsertTailList(&Segment->BlockList, &Block->Entry); BlRtlInsertTailList(&BlPoolSegmentList, &Segment->Entry); BlPoolVerify(); return; } PVOID BlPoolAllocateBlock( UINT32 Size ) //++ // // Routine Description: // // This function allocates from the boot loader pool. // // Arguments: // // Size - Supplies the number of bytes to allocate. // // Return Value: // // A pointer to the allocated buffer. // //-- { PBL_POOL_BLOCK Block; PLIST_ENTRY BlockEntry; PLIST_ENTRY BlockHead; UINT32 GrowthSize; PBL_POOL_BLOCK NewBlock; PBL_POOL_SEGMENT Segment; PLIST_ENTRY SegmentEntry; PLIST_ENTRY SegmentHead; BlPoolVerify(); BLASSERT(Size > 0); Size += sizeof(BL_POOL_BLOCK); Size = BL_POOL_ROUND_UP(Size); SegmentHead = &BlPoolSegmentList; for (;;) { for (SegmentEntry = SegmentHead->Flink; SegmentEntry != SegmentHead; SegmentEntry = SegmentEntry->Flink) { Segment = CONTAINING_RECORD(SegmentEntry, BL_POOL_SEGMENT, Entry); BlockHead = &Segment->BlockList; for (BlockEntry = BlockHead->Flink; BlockEntry != BlockHead; BlockEntry = BlockEntry->Flink) { Block = CONTAINING_RECORD(BlockEntry, BL_POOL_BLOCK, Entry); if ((Block->State == BL_POOL_FREE) && (Block->Size >= Size)) { if (Block->Size > Size) { NewBlock = (PBL_POOL_BLOCK) ((ULONG_PTR) Block + Size); BlRtlZeroMemory(NewBlock, sizeof(BL_POOL_BLOCK)); NewBlock->Magic1 = BL_POOL_BLOCK_MAGIC1; NewBlock->Magic2 = BL_POOL_BLOCK_MAGIC2; NewBlock->Size = Block->Size - Size; NewBlock->State = BL_POOL_FREE; NewBlock->Allocator = NULL; BlRtlInsertHeadList(&Block->Entry, &NewBlock->Entry); Block->Size = Size; } Block->State = BL_POOL_BUSY; Block->Allocator = _ReturnAddress(); BlRtlZeroMemory(Block + 1, Block->Size - sizeof(BL_POOL_BLOCK)); BlPoolVerify(); return (Block + 1); } } } GrowthSize = BL_POOL_SEGMENT_ROUND_UP(Size); BlPoolGrow(GrowthSize); } } VOID BlPoolFreeBlock( PVOID P ) //++ // // Routine Description: // // This function frees the specified pool block. // // Arguments: // // P - Supplies a pointer to the block to free. // //-- { PBL_POOL_BLOCK Block; BlPoolVerify(); BLASSERT(((ULONG_PTR) P % __alignof(BL_POOL_BLOCK)) == 0); Block = ((PBL_POOL_BLOCK) P) - 1; BLASSERT(((ULONG_PTR) Block % BL_POOL_GRANULARITY) == 0); BLASSERT(Block->State == BL_POOL_BUSY); Block->State = BL_POOL_FREE; Block->Allocator = NULL; // // AIFIX: Check for adjacent free blocks and coalesce. // BlPoolVerify(); return; } ================================================ FILE: ironclad-apps/src/Checked/BootLoader/SingLdrPc/blpxe.cpp ================================================ //++ // // Copyright (c) Microsoft Corporation // // Module Name: // // blpxe.cpp // // Abstract: // // This module implements PXE support for the boot loader. // //-- #include "bl.h" #pragma pack(1) typedef struct _IP_ADDRESS { union { UINT32 Value; UINT8 Array[4]; }; } IP_ADDRESS, *PIP_ADDRESS; #define DHCP_OPTION_CODE_PAD 0 #define DHCP_OPTION_CODE_COMMAND_LINE 8 typedef struct _DHCP_OPTION_HEADER { UINT8 Code; UINT8 Length; } DHCP_OPTION_HEADER, *PDHCP_OPTION_HEADER; #define BOOTP_REPLY_OPCODE_REPLY 2 typedef struct _BOOTP_REPLY { UINT8 OpCode; UINT8 HardwareAddressType; UINT8 HardwareAddressLength; UINT8 Hops; UINT32 TransactionId; UINT16 SecondsSinceAddressAcquisition; UINT16 Flags; IP_ADDRESS ClientIP; IP_ADDRESS YourIP; IP_ADDRESS ServerIP; IP_ADDRESS GatewayIP; UINT8 ClientMAC[16]; UINT8 ServerHostName[64]; UINT8 BootFileName[128]; UINT8 Magic[4]; UINT8 Data[1500]; } BOOTP_REPLY, *PBOOTP_REPLY; typedef struct _PXE_INSTALLATION_CHECK { UINT8 Signature[6]; UINT16 Version; UINT8 Length; UINT8 Checksum; FAR_POINTER RealModeEntry; UINT32 ProtectedModeEntry; UINT16 ProtectedModeSelector; UINT16 StackSegment; UINT16 StackSize; UINT16 BCCodeSegment; UINT16 BCCodeSize; UINT16 BCDataSegment; UINT16 BCDataSize; UINT16 UNDIDataSegment; UINT16 UNDIDataSize; UINT16 UNDICodeSegment; UINT16 UNDICOdeSize; FAR_POINTER ExtendedInformation; } PXE_INSTALLATION_CHECK, *PPXE_INSTALLATION_CHECK; C_ASSERT(sizeof(PXE_INSTALLATION_CHECK) == 0x2C); typedef struct _PXE_SEGMENT_DESCRIPTOR { UINT16 Selector; UINT32 Base; UINT16 Size; } PXE_SEGMENT_DESCRIPTOR, *PPXE_SEGMENT_DESCRIPTOR; C_ASSERT(sizeof(PXE_SEGMENT_DESCRIPTOR) == 8); typedef struct _PXE_EXTENDED_INFORMATION { UINT8 Signature[4]; UINT8 Length; UINT8 Checksum; UINT8 Version; UINT8 Reserved1; FAR_POINTER UNDIROMID; FAR_POINTER BaseROMID; FAR_POINTER Entry16; FAR_POINTER Entry32; FAR_POINTER StatusCallout; UINT8 Reserved2; UINT8 SegmentDescriptorCount; UINT16 FirstSelector; PXE_SEGMENT_DESCRIPTOR Stack; PXE_SEGMENT_DESCRIPTOR UNDIData; PXE_SEGMENT_DESCRIPTOR UNDICode; PXE_SEGMENT_DESCRIPTOR UNDICodeWrite; PXE_SEGMENT_DESCRIPTOR BCData; PXE_SEGMENT_DESCRIPTOR BCCode; PXE_SEGMENT_DESCRIPTOR BCCOdeWrite; } PXE_EXTENDED_INFORMATION, *PPXE_EXTENDED_INFORMATION; C_ASSERT(sizeof(PXE_EXTENDED_INFORMATION) == 0x58); #define PXE_STATUS_SUCCESS 0 typedef UINT16 PXE_STATUS; #define PXE_OPCODE_TFTP_READ_FILE 0x0023 #define PXE_OPCODE_TFTP_GET_FILE_SIZE 0x0025 #define PXE_OPCODE_GET_CACHED_INFO 0x0071 #define PXE_PACKET_TYPE_DHCP_ACK 2 #define PXE_PACKET_TYPE_CACHED_REPLY 3 typedef struct _PXE_GET_CACHED_INFO { PXE_STATUS Status; UINT16 PacketType; UINT16 BufferSize; FAR_POINTER Buffer; UINT16 BufferLimit; } PXE_GET_CACHED_INFO, *PPXE_GET_CACHED_INFO; typedef struct _PXE_TFTP_GET_FILE_SIZE { PXE_STATUS Status; IP_ADDRESS ServerIP; IP_ADDRESS GatewayIP; UINT8 FileName[128]; UINT32 FileSize; } PXE_TFTP_GET_FILE_SIZE, *PPXE_TFTP_GET_FILE_SIZE; #define PXE_TFTP_READ_FILE_RETRY_COUNT 5 typedef struct _PXE_TFTP_READ_FILE { PXE_STATUS Status; UINT8 FileName[128]; UINT32 BufferSize; UINT32 Buffer; IP_ADDRESS ServerIP; IP_ADDRESS GatewayIP; IP_ADDRESS MulticastIP; UINT16 ClientMulticastPort; UINT16 ServerMulticastPort; UINT16 OpenTimeout; UINT16 ReopenDelay; } PXE_TFTP_READ_FILE, *PPXE_TFTP_READ_FILE; typedef struct _PXE_API_PACKET { union { PXE_GET_CACHED_INFO GetCachedInfo; PXE_TFTP_GET_FILE_SIZE TFTPGetFileSize; PXE_TFTP_READ_FILE TFTPReadFile; } u1; } PXE_API_PACKET, *PPXE_API_PACKET; #pragma pack() PXE_API_PACKET BlPxeApiPacket; BOOTP_REPLY BlPxeBootpReply; UINT16 BlPxeCallFrame[16]; FAR_POINTER BlPxeEntry16; PPXE_EXTENDED_INFORMATION BlPxeExtendedInformation; PPXE_INSTALLATION_CHECK BlPxeInstallationCheck; VOID BlPxeCallPxeApi( UINT16 OpCode, PVOID Packet ) //++ // // Routine Description: // // This function calls the PXE API. // // Arguments: // // OpCode - Supplies the operation to perform. // // Packet - Supplies a pointer to te packet describing the operation details. // //-- { BL_LEGACY_CALL_CONTEXT Context; FAR_POINTER FarPointer; BlRtlZeroMemory(&Context, sizeof(BL_LEGACY_CALL_CONTEXT)); if (BlPxeExtendedInformation != NULL) { BlPxeCallFrame[0] = OpCode; BlRtlConvertLinearPointerToFarPointer(Packet, (PFAR_POINTER) &BlPxeCallFrame[1]); BlRtlCallLegacyFunction(BlPxeExtendedInformation->Entry16.Segment, BlPxeExtendedInformation->Entry16.Offset, BlPxeCallFrame, 3 * sizeof(UINT16), &Context, &Context); } else { BlRtlConvertLinearPointerToFarPointer(Packet, &FarPointer); Context.ebx = OpCode; Context.es = FarPointer.Segment; Context.edi = FarPointer.Offset; BlRtlCallLegacyFunction(BlPxeInstallationCheck->RealModeEntry.Segment, BlPxeInstallationCheck->RealModeEntry.Offset, NULL, 0, &Context, &Context); } return; } VOID BlPxeGetBootpReply( VOID ) //++ // // Routine Description: // // This function gets the BOOTP reply received by PXE. // //-- { PPXE_GET_CACHED_INFO GetCachedInfo; UINT32 Index; ULONG_PTR Limit; ULONG_PTR Next; PDHCP_OPTION_HEADER Option; GetCachedInfo = &BlPxeApiPacket.u1.GetCachedInfo; // // Get the discover reply packet received from the boot server. // BlRtlZeroMemory(GetCachedInfo, sizeof(PXE_GET_CACHED_INFO)); GetCachedInfo->PacketType = PXE_PACKET_TYPE_CACHED_REPLY; BlRtlConvertLinearPointerToFarPointer(&BlPxeBootpReply, &GetCachedInfo->Buffer); GetCachedInfo->BufferSize = sizeof(BlPxeBootpReply); BlPxeCallPxeApi(PXE_OPCODE_GET_CACHED_INFO, GetCachedInfo); if (GetCachedInfo->Status != PXE_STATUS_SUCCESS) { BlRtlPrintf("PXE: Get PXE_REPLY failed: 0x%04x!\n", GetCachedInfo->Status); BlRtlHalt(); } // // If the discover reply packet does not have the BOOTP reply opcode, then get the DHCP ACK packet. // if (BlPxeBootpReply.OpCode != BOOTP_REPLY_OPCODE_REPLY) { BlRtlZeroMemory(GetCachedInfo, sizeof(PXE_GET_CACHED_INFO)); GetCachedInfo->PacketType = PXE_PACKET_TYPE_DHCP_ACK; BlRtlConvertLinearPointerToFarPointer(&BlPxeBootpReply, &GetCachedInfo->Buffer); GetCachedInfo->BufferSize = sizeof(BlPxeBootpReply); BlPxeCallPxeApi(PXE_OPCODE_GET_CACHED_INFO, GetCachedInfo); if (GetCachedInfo->Status != PXE_STATUS_SUCCESS) { BlRtlPrintf("PXE: Get DHCP_ACK failed 0x%04x!\n", GetCachedInfo->Status); BlRtlHalt(); } } // // If neither discover reply packet nor the DHCP ACK packet contains the BOOTP reply opcode, then PXE boot is not possible. // if (BlPxeBootpReply.OpCode != BOOTP_REPLY_OPCODE_REPLY) { BlRtlPrintf("PXE: Invalid BOOTP_REPLY packet!\n"); BlRtlHalt(); } #if PXE_VERBOSE BlRtlPrintf("PXE: IP=%u.%u.%u.%u DHCP=%u.%u.%u.%u GATEWAY=%u.%u.%u.%u\n", BlPxeBootpReply.ClientIP.Array[0], BlPxeBootpReply.ClientIP.Array[1], BlPxeBootpReply.ClientIP.Array[2], BlPxeBootpReply.ClientIP.Array[3], BlPxeBootpReply.ServerIP.Array[0], BlPxeBootpReply.ServerIP.Array[1], BlPxeBootpReply.ServerIP.Array[2], BlPxeBootpReply.ServerIP.Array[3], BlPxeBootpReply.GatewayIP.Array[0], BlPxeBootpReply.GatewayIP.Array[1], BlPxeBootpReply.GatewayIP.Array[2], BlPxeBootpReply.GatewayIP.Array[3] ); #endif Limit = ((ULONG_PTR) &BlPxeBootpReply) + GetCachedInfo->BufferSize; Next = (ULONG_PTR) (&BlPxeBootpReply.Data); while (Next < Limit) { Option = (PDHCP_OPTION_HEADER) Next; switch (Option->Code) { case DHCP_OPTION_CODE_PAD: { Next += 1; break; } case DHCP_OPTION_CODE_COMMAND_LINE: { if (((Next + sizeof(DHCP_OPTION_HEADER)) < Limit) && ((Next + sizeof(DHCP_OPTION_HEADER) + Option->Length) < Limit)) { BlCommandLine = (PWCHAR)BlPoolAllocateBlock((Option->Length + 1) * sizeof(WCHAR)); for (Index = 0; Index < Option->Length; Index += 1) { BlCommandLine[Index] = (WCHAR) (((PCHAR) (Option + 1))[Index]); } BlCommandLine[Option->Length] = 0; #if PXE_VERBOSE BlRtlPrintf("PXE: CMD=[%s]\n", BlCommandLine); #endif } Next = Limit; break; } default: { Next += (sizeof(DHCP_OPTION_HEADER) + Option->Length); } } } return; } BOOLEAN BlPxeGetFileSize( PCSTR Path, PUINT32 FileSize ) //++ // // Routine Description: // // This function queries the size of the specified file. // // Arguments: // // Path - Supplies the path to the file to query. // // FileSize - Receives the size of the file. // // Return Value: // // TRUE, if the query operation was successful. // FALSE, otherwise. // //-- { PPXE_TFTP_GET_FILE_SIZE GetFileSize; UINT32 PathLength; GetFileSize = &BlPxeApiPacket.u1.TFTPGetFileSize; BlRtlZeroMemory(GetFileSize, sizeof(PXE_TFTP_GET_FILE_SIZE)); PathLength = BlRtlStringLength(Path); if (PathLength >= sizeof(GetFileSize->FileName)) { return FALSE; } GetFileSize->ServerIP = BlPxeBootpReply.ServerIP; GetFileSize->GatewayIP = BlPxeBootpReply.GatewayIP; BlRtlCopyMemory(GetFileSize->FileName, Path, PathLength); GetFileSize->FileName[PathLength] = 0; BlPxeCallPxeApi(PXE_OPCODE_TFTP_GET_FILE_SIZE, GetFileSize); if (GetFileSize->Status != PXE_STATUS_SUCCESS) { return FALSE; } *FileSize = GetFileSize->FileSize; return TRUE; } BOOLEAN BlPxeReadFile( PCSTR Path, PVOID Buffer, UINT32 NumberOfBytes ) //++ // // Routine Description: // // This function reads from the specified file. // // Arguments: // // Path - Supplies the path to the file to read. // // Buffer - Receives data. // // NumberOfBytes - Supplies the number of bytes to read. // // Return Value: // // TRUE, if the read operation was successful. // FALSE, otherwise. // //-- { UINT32 Index; UINT32 PathLength; PPXE_TFTP_READ_FILE ReadFile; BLASSERT((((ULONG_PTR) Buffer) + NumberOfBytes) > ((ULONG_PTR) Buffer)); BLASSERT((((ULONG_PTR) Buffer) + NumberOfBytes) <= 0xFFFFFFFF); ReadFile = &BlPxeApiPacket.u1.TFTPReadFile; PathLength = BlRtlStringLength(Path); if (PathLength >= sizeof(ReadFile->FileName)) { #if PXE_VERBOSE BlRtlPrintf("PXE: Path is too long [%s]\n", Path); #endif return FALSE; } for (Index = 0; Index < PXE_TFTP_READ_FILE_RETRY_COUNT; Index += 1) { BlRtlZeroMemory(ReadFile, sizeof(PXE_TFTP_READ_FILE)); BlRtlCopyMemory(ReadFile->FileName, Path, PathLength); ReadFile->FileName[PathLength] = 0; ReadFile->BufferSize = NumberOfBytes; ReadFile->Buffer = (UINT32) (ULONG_PTR) Buffer; ReadFile->ServerIP = BlPxeBootpReply.ServerIP; ReadFile->GatewayIP = BlPxeBootpReply.GatewayIP; BlPxeCallPxeApi(PXE_OPCODE_TFTP_READ_FILE, ReadFile); if (ReadFile->Status == PXE_STATUS_SUCCESS) { break; } #if PXE_VERBOSE BlRtlPrintf("PXE: TFTP_READ failed: 0x%04x! [%u / %u]\n", ReadFile->Status, Index + 1, PXE_TFTP_READ_FILE_RETRY_COUNT); #endif } return TRUE; } VOID BlPxeInitialize( VOID ) //++ // // Routine Description: // // This function initializes PXE support. // //-- { BL_LEGACY_CALL_CONTEXT Context; FAR_POINTER FarPointer; PPXE_INSTALLATION_CHECK InstallationCheck; ULONG_PTR Limit; ULONG_PTR Next; BlRtlZeroMemory(&Context, sizeof(Context)); Context.eax = 0x5650; BlRtlCallLegacyInterruptService(0x1A, &Context, &Context); if (((Context.eflags & RFLAGS_CF) == 0) && ((Context.eax & 0xFFFF) == 0x564E)) { FarPointer.Segment = (UINT16) Context.es; FarPointer.Offset = (UINT16) (Context.ebx & 0xFFFF); #if PXE_VERBOSE BlRtlPrintf("PXE: INT1A/5650h => [ES:BX = %04x:%04x]\n", FarPointer.Segment, FarPointer.Offset); #endif BlPxeInstallationCheck = (PPXE_INSTALLATION_CHECK) BlRtlConvertFarPointerToLinearPointer(&FarPointer); } else { Next = 0xA0000; Limit = 0x10000; BlPxeInstallationCheck = NULL; do { Next -= 16; InstallationCheck = (PPXE_INSTALLATION_CHECK) Next; if ((InstallationCheck->Length >= sizeof(PXE_INSTALLATION_CHECK)) && (InstallationCheck->Signature[0] == 'P') && (InstallationCheck->Signature[1] == 'X') && (InstallationCheck->Signature[2] == 'E') && (InstallationCheck->Signature[3] == 'N') && (InstallationCheck->Signature[4] == 'V') && (InstallationCheck->Signature[5] == '+') && (BlRtlComputeChecksum8(InstallationCheck, InstallationCheck->Length) == 0)) { BlPxeInstallationCheck = InstallationCheck; break; } } while (Next > Limit); } if (BlPxeInstallationCheck == NULL) { BlRtlPrintf("PXE: Unable to find PXE!\n"); BlRtlHalt(); } if (BlPxeInstallationCheck->Version < 0x201) { #if PXE_VERBOSE BlRtlPrintf("PXE: Using PXENV+.\n"); #endif BlPxeEntry16 = BlPxeInstallationCheck->RealModeEntry; } else { #if PXE_VERBOSE BlRtlPrintf("PXE: Using !PXE.\n"); #endif BlPxeExtendedInformation = (PPXE_EXTENDED_INFORMATION) BlRtlConvertFarPointerToLinearPointer(&BlPxeInstallationCheck->ExtendedInformation); if (!((BlPxeExtendedInformation->Length >= sizeof(PXE_EXTENDED_INFORMATION)) && (BlPxeExtendedInformation->Signature[0] == '!') && (BlPxeExtendedInformation->Signature[1] == 'P') && (BlPxeExtendedInformation->Signature[2] == 'X') && (BlPxeExtendedInformation->Signature[3] == 'E') && (BlRtlComputeChecksum8(BlPxeExtendedInformation, BlPxeExtendedInformation->Length) == 0))) { BlRtlPrintf("PXE: !PXE is invalid!\n"); BlRtlHalt(); } BlPxeEntry16 = BlPxeExtendedInformation->Entry16; } #if PXE_VERBOSE BlRtlPrintf("PXE: PXENV+ @ %p\n" "PXE: !PXE @ %p\n" "PXE: Entry16 @ %04x:%04x\n", BlPxeInstallationCheck, BlPxeExtendedInformation, BlPxeEntry16.Segment, BlPxeEntry16.Offset); #endif BlPxeGetBootpReply(); BlFsGetFileSize = BlPxeGetFileSize; BlFsReadFile = BlPxeReadFile; return; } ================================================ FILE: ironclad-apps/src/Checked/BootLoader/SingLdrPc/blsingularity.cpp ================================================ //-++ //- //- Copyright (c) Microsoft Corporation //- //- Module Name: //- //- blsingularity.cpp //- //- Abstract: //- //- This module initializes and boots Singularity. //- //-- #include "bl.h" #include "tpm/aik.h" #define SINGULARITY_DISTRO_INI_PATH "safeos/boot.ini" #define SINGULARITY_LOG_RECORD_SIZE 0x20000 #define SINGULARITY_LOG_TEXT_SIZE 0x20000 #define SINGULARITY_KERNEL_STACK_SIZE 0xC0000 //- //- Define halclass style basic definitions and macros. //- typedef ULONG_PTR PTR_TYPE; typedef LONG_PTR SPTR_TYPE; typedef ULONG_PTR UPTR_TYPE; #define OFFSETOF FIELD_OFFSET #define STATIC_ASSERT C_ASSERT //- //- Include halclasswin.h for Singularity definitions. //- #define SINGULARITY_LOADER 1 #pragma pack(1) #include "platform.h" #pragma pack() C_ASSERT(FIELD_OFFSET(Struct_Microsoft_Singularity_Isal_IX_DescriptorTable_Gdt, rc) == RM_CODE_SELECTOR); C_ASSERT(FIELD_OFFSET(Struct_Microsoft_Singularity_Isal_IX_DescriptorTable_Gdt, rd) == RM_DATA_SELECTOR); C_ASSERT(FIELD_OFFSET(Struct_Microsoft_Singularity_Isal_IX_DescriptorTable_Gdt, pc) == PM_CODE_SELECTOR); C_ASSERT(FIELD_OFFSET(Struct_Microsoft_Singularity_Isal_IX_DescriptorTable_Gdt, pd) == PM_DATA_SELECTOR); C_ASSERT(FIELD_OFFSET(Struct_Microsoft_Singularity_Isal_IX_DescriptorTable_Gdt, lc) == LM_CODE_SELECTOR); C_ASSERT(FIELD_OFFSET(Struct_Microsoft_Singularity_Isal_IX_DescriptorTable_Gdt, ld) == LM_DATA_SELECTOR); C_ASSERT(FIELD_OFFSET(Struct_Microsoft_Singularity_Isal_IX_DescriptorTable_Gdt, pp) == PROCESSOR_SELECTOR); C_ASSERT(FIELD_OFFSET(Struct_Microsoft_Singularity_Isal_IX_DescriptorTable_Gdt, tss) == TSS_SELECTOR); Class_Microsoft_Singularity_Hal_Platform *BlPlatform; Class_Microsoft_Singularity_Hal_Cpu *BlCpuArray; typedef struct _BL_DISTRO_FILE { LIST_ENTRY Entry; UINT32 Size; CHAR Path[1024]; PVOID Data; } BL_DISTRO_FILE, *PBL_DISTRO_FILE; typedef struct _BL_DISTRO { UINT32 NumberOfFiles; UINT32 TotalSize; LIST_ENTRY FileList; PVOID Data; } BL_DISTRO, PBL_DISTRO; BL_DISTRO BlDistro; PBL_DISTRO_FILE BlKernelFile; PVOID BlKernelBase; ULONG_PTR BlKernelSize; UINT32 (*BlKernelEntryPoint)( Class_Microsoft_Singularity_Hal_Platform *Platform, Class_Microsoft_Singularity_Hal_Cpu *Cpu ); PBL_SMAP BlSingularitySmap; PWCHAR BlCommandLine; Struct_Microsoft_Singularity_Io_FileImage *BlSingularityFileImageTable; UINT32 BlSingularityFileImageTableSize; // // OHCI 1394 buffer for Singularity KD. // // AIFIX: Currently, this buffer needs to be allocated in low memory, because // Singularity KD does not connect if it is allocated in high memory. // __declspec(align(PAGE_SIZE)) UINT8 BlSingularityOhci1394Buffer[3 * PAGE_SIZE]; VOID BlSingularityLoadDistro( VOID ) //++ // // Routine Description: // // This function loads the distro. // //-- { UINT32 BytesRead; UINT32 CharactersConsumed; PBL_DISTRO_FILE DistroFile; UINT32 DummySize; PLIST_ENTRY Entry; UINT32 FilesRead; PLIST_ENTRY Head; PCHAR NewLine; PCHAR Next; UINT32 Size; PCHAR Temp; PVOID BlIniFileData; UINT32 BlIniFileSize; BlDistro.NumberOfFiles = 0; BlRtlInitializeListHead(&BlDistro.FileList); //- //- Read the distro INI file. //- if (BlFsGetFileSize(SINGULARITY_DISTRO_INI_PATH, &BlIniFileSize) == FALSE) { BlRtlPrintf("BL: Unable to get INI file!\n"); BlRtlHalt(); } BlIniFileData = BlPoolAllocateBlock(BlIniFileSize + 1); if (BlFsReadFile(SINGULARITY_DISTRO_INI_PATH, BlIniFileData, BlIniFileSize) == FALSE) { BlRtlPrintf("BL: Unable to read INI file!\n"); BlRtlHalt(); } //- //- Parse INI file and build distro file list. //- NewLine = (PCHAR) BlIniFileData; for (;;) { Next = NewLine; NewLine = Next + 1; while ((*NewLine != 0) && (*NewLine != '\r') && (*NewLine != '\n')) { NewLine += 1; } if (*NewLine == 0) { break; } while ((*NewLine == '\r') || (*NewLine == '\n')) { *NewLine = 0; NewLine += 1; } Next = (PCHAR)BlRtlFindSubstring(Next, "Size="); if (Next == NULL) { continue; } Next += 5; if (BlRtlParsePositiveDecimal(Next, &Size, &CharactersConsumed) == FALSE) { ParseFailure: BlRtlPrintf("BL: Error parsing distro INI file!\n"); BlRtlHalt(); } Next = (PCHAR)BlRtlFindSubstring(Next, "Path="); if (Next == NULL) { goto ParseFailure; } Next += 5; if (*Next == 0) { goto ParseFailure; } DistroFile = (PBL_DISTRO_FILE) BlPoolAllocateBlock(sizeof(BL_DISTRO_FILE)); BLASSERT((NewLine - Next) < sizeof(DistroFile->Path)); Temp = (PCHAR)Next; while (Temp != NewLine) { if (*Temp == '\\') { *Temp = '/'; } Temp += 1; } BlRtlCopyMemory(DistroFile->Path, Next, NewLine - Next); //- //- By convention with DistroBuiderl, the first file with a size of zero is //- really the INI file, so we need to set its size. //- if (Size == 0) { Size = BlIniFileSize; } DistroFile->Size = Size; BlDistro.NumberOfFiles += 1; BlDistro.TotalSize += Size; BlRtlInsertTailList(&BlDistro.FileList, &DistroFile->Entry); } //- //- Read distro files. //- BlDistro.Data = (PVOID) BlMmAllocatePhysicalRegion(ROUND_UP_TO_PAGES(BlDistro.TotalSize), BL_MM_PHYSICAL_REGION_DISTRO); #if DISTRO_VERBOSE BlKdPrintf("DISTRO: Reading distro (%u files , %u bytes).\n", BlDistro.NumberOfFiles, BlDistro.TotalSize); #endif FilesRead = 0; BytesRead = 0; Next = (PCHAR) BlDistro.Data; Head = &BlDistro.FileList; for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink) { DistroFile = CONTAINING_RECORD(Entry, BL_DISTRO_FILE, Entry); DistroFile->Data = Next; BLASSERT(DistroFile->Path[0] == '/'); #if DISTRO_VERBOSE BlKdPrintf("DISTRO: %s [%u bytes]\n", DistroFile->Path, DistroFile->Size); #endif if (BlFsReadFile(&DistroFile->Path[1], DistroFile->Data, DistroFile->Size) == FALSE) { BlRtlPrintf("\n" "BL: Error reading %s!\n", DistroFile->Path); BlRtlHalt(); } Next += DistroFile->Size; FilesRead += 1; BytesRead += DistroFile->Size; BlVideoPrintf("\rReading distro files ... %u / %u [%u / %u]", FilesRead, BlDistro.NumberOfFiles, BytesRead, BlDistro.TotalSize); } BlVideoPrintf("\n"); //- //- If this is a network boot, then signal the PXE server to exit. //- This is the only mechanism to notify the server that the boot succeeded. //- if (BlGetBeb()->BootType == BL_PXE_BOOT) { BlFsGetFileSize("end.:", &DummySize); } //- //- Switch distro range to read-only. //- BlMmMapVirtualRange(BlDistro.Data, BlDistro.Data, BlDistro.TotalSize, FALSE, TRUE, FALSE); //- //- Build file image table. //- BlSingularityFileImageTable = (Struct_Microsoft_Singularity_Io_FileImage *) BlPoolAllocateBlock(BlDistro.NumberOfFiles * sizeof(Struct_Microsoft_Singularity_Io_FileImage)); for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink) { DistroFile = CONTAINING_RECORD(Entry, BL_DISTRO_FILE, Entry); BlSingularityFileImageTable[BlSingularityFileImageTableSize].Address = (ULONG_PTR) DistroFile->Data; BlSingularityFileImageTable[BlSingularityFileImageTableSize].Size = DistroFile->Size; BlSingularityFileImageTableSize += 1; } return; } VOID BlSingularityLoadKernelImage( VOID ) //-++ //- //- Routine Description: //- //- This function loads the kernel image. //- //--- { BLASSERT(BlRtlIsListEmpty(&BlDistro.FileList) == FALSE); //- //- Kernel is the first entry in the distro file list. //- BlKernelFile = CONTAINING_RECORD(BlDistro.FileList.Flink, BL_DISTRO_FILE, Entry); //- //- Get the virtual range for the kernel image. //- BlPeGetVirtualRange(BlKernelFile->Data, &BlKernelBase, &BlKernelSize); BLASSERT(((UINT64) BlKernelBase % PAGE_SIZE) == 0); BLASSERT((BlKernelSize % PAGE_SIZE) == 0); //- //- Allocate a physical region for the kernel image, since pages are identity mapped at boot. //- // AIFIX: This needs to be be made dynamic! // if (BlMmAllocateSpecificPhysicalRegion((UINT64) BlKernelBase, BlKernelSize, BL_MM_PHYSICAL_REGION_KERNEL_IMAGE) == FALSE) { BlMmDumpPhysicalRegionList(); BlRtlHalt(); } #if SINGULARITY_VERBOSE BlRtlPrintf("BL: Loading kernel ... [%p ... %p]\n", BlKernelBase, (ULONG_PTR) BlKernelBase + BlKernelSize - 1); #endif BlPeLoadImage(BlKernelBase, BlKernelSize, BlKernelFile->Data, (PVOID *) &BlKernelEntryPoint, TRUE); } ULONG_PTR BlSingularityLoadAppImage( VOID ) //-++ //- //- Routine Description: //- //- This function loads the kernel image. //- //--- { PBL_DISTRO_FILE BlAppFile; PVOID BlAppBase; ULONG_PTR BlAppSize; ULONG_PTR BlAppEntryPoint; BLASSERT(BlRtlIsListEmpty(&BlDistro.FileList) == FALSE); //- //- App is the second entry in the distro file list. //- BlAppFile = CONTAINING_RECORD(BlDistro.FileList.Flink->Flink, BL_DISTRO_FILE, Entry); //- //- Get the virtual range for the kernel image. //- BlPeGetVirtualRange(BlAppFile->Data, &BlAppBase, &BlAppSize); BLASSERT(((UINT64) BlAppBase % PAGE_SIZE) == 0); BLASSERT((BlAppSize % PAGE_SIZE) == 0); //- //- Allocate a physical region for the app image, since pages are identity mapped at boot. //- // AIFIX: This needs to be be made dynamic! // BlRtlPrintf("BL: Loading app... [%p ... %p]\n", BlAppBase, (ULONG_PTR) BlAppBase + BlAppSize - 1); if (BlMmAllocateSpecificPhysicalRegion((UINT64) BlAppBase, BlAppSize, BL_MM_PHYSICAL_REGION_SINGULARITY) == FALSE) { BlRtlPrintf("BL: Loading app... failed\n"); BlMmDumpPhysicalRegionList(); BlRtlHalt(); } #if SINGULARITY_VERBOSE BlRtlPrintf("BL: Loading app... [%p ... %p]\n", BlAppBase, (ULONG_PTR) BlAppBase + BlAppSize - 1); #endif BlPeLoadImage(BlAppBase, BlAppSize, BlAppFile->Data, (PVOID *) &BlAppEntryPoint, FALSE); return BlAppEntryPoint; } // // AIFIX: Fix task page definition. // #if defined(BOOT_X86) typedef Struct_Microsoft_Singularity_Isal_IX_TSS BL_TASK_SEGMENT; #elif defined(BOOT_X64) typedef Struct_Microsoft_Singularity_Isal_IX_TSS64 BL_TASK_SEGMENT; #endif typedef struct _BL_PROCESSOR { UINT32 Index; Class_Microsoft_Singularity_Hal_Cpu *Cpu; PVOID KernelStack; ULONG_PTR KernelStackSize; PVOID ContextPage; PVOID BasePage; BL_TASK_SEGMENT *TaskPage; } BL_PROCESSOR, *PBL_PROCESSOR; PBL_PROCESSOR BlProcessor; UINT32 BlProcessorCount; VOID BlSingularityInitializeProcessor( UINT32 Index ) //-++ //- //- Routine Description: //- //- This function initializes the specified processor. //- //- Arguments: //- //- Index - Supplies the index of the processor to initialize. //- //--- { Class_Microsoft_Singularity_Hal_Cpu *Processor; //- //- Initialize native processor structure. //- Processor = BlProcessor[Index].Cpu; Processor->Size = sizeof(Class_Microsoft_Singularity_Hal_Cpu); Processor->Id = Index; #if 0 Processor->ApicId = Index; #endif Processor->KernelStackLimit = (ULONG_PTR) BlProcessor[Index].KernelStack; // Processor->KernelStackBegin = Processor->KernelStackLimit + SINGULARITY_KERNEL_STACK_SIZE; Processor->KernelStackBegin = Processor->KernelStackLimit + BlProcessor[Index].KernelStackSize; Processor->CpuRecordPage = (ULONG_PTR) BlProcessor[Index].BasePage; //- //- Initialize task structure. //- BlProcessor[Index].TaskPage->io_bitmap_offset = sizeof(BL_TASK_SEGMENT); //- //- Initialize segments. //- BlRtlZeroMemory(&Processor->segments, sizeof(Processor->segments)); Processor->segments.gdtPtr.addr = (ULONG_PTR) &Processor->segments.gdt; Processor->segments.gdtPtr.limit = sizeof(Processor->segments.gdt) - 1; BlRtlCopyMemory(&Processor->segments.gdt.pc, (PVOID) (BlMmInitialGdtr.Base + PM_CODE_SELECTOR), sizeof(CODE_SEGMENT)); BlRtlCopyMemory(&Processor->segments.gdt.pd, (PVOID) (BlMmInitialGdtr.Base + PM_DATA_SELECTOR), sizeof(CODE_SEGMENT)); #if defined(BOOT_X64) BlRtlCopyMemory(&Processor->segments.gdt.lc, (PVOID) (BlMmInitialGdtr.Base + LM_CODE_SELECTOR), sizeof(CODE_SEGMENT)); BlRtlCopyMemory(&Processor->segments.gdt.ld, (PVOID) (BlMmInitialGdtr.Base + LM_DATA_SELECTOR), sizeof(CODE_SEGMENT)); #endif BlMmInitializeDataSegment((PDATA_SEGMENT) &Processor->segments.gdt.pp, (UINT32) (ULONG_PTR) BlProcessor[Index].ContextPage, PAGE_SIZE - 1); BlMmInitializeSystemSegment((PSYSTEM_SEGMENT) &Processor->segments.gdt.tss, SSDT_AVAILABLE_TSS, (ULONG_PTR) BlProcessor[Index].TaskPage, sizeof(BL_TASK_SEGMENT) - 1); return; } UINT32 BlSingularityProcessorToStart; //- Test whether SKINIT is possible on this machine UINT8 TestForSKINIT() { //- First check for max extended capabilities we're allowed to query UINT32 result = BlGetCpuidEax(0x80000000); if (result >= 0x80000001) { result = BlGetCpuidEcx(0x80000001); //- Query the SVM-related capabilities if (result & 0x00001000) { //- Check for SKINIT in the 12th bit return 1; } else { BlRtlPrintf("CPUID returned: %p\n", result); } } else { BlRtlPrintf("Result of extended query too small.\n"); } return 0; } #ifdef SMALL_LOADER UINT8 PrepTPM(ULONG_PTR SKINIT_base) { return 0; } #else // !SMALL_LOADER UINT8 PrepTPM(ULONG_PTR SKINIT_base) { UINT32 locality = 3; UINT32 SKINIT_args = 0; //- Deposit the TPM's AIK at app's base+size+0x1F000+sSize+dSize //-SKINIT_args = (UINT32)330000 + 1024*1024 + 0x1F000 + 1024 + 1024; //- Deposit the TPM's AIK at loader's base+?CodeSpace+0x1F000(for DEV)+sSize+dSize SKINIT_args = (UINT32)SKINIT_base + 193 * 1024 + 4; // +4 since app entry point is at 0 UINT32* SKINIT_args_words = (UINT32*)SKINIT_args; SKINIT_args_words[0] = sizeof(aik); BlRtlPrintf("AIK of size: %p \n", SKINIT_args_words[0]); unsigned char* arg_ptr = (unsigned char*)(SKINIT_args + 4); for (int i = 0; i < sizeof(aik); i++) { arg_ptr[i] = aik[i]; // BlRtlPrintf("%02x ", ((unsigned int)aik[i]) & 0xff); // if (((i+1)%24)==0) // { // BlRtlPrintf("\n"); // } } // BlRtlPrintf("\n"); arg_ptr += sizeof(aik); return 0; } #endif // SMALL_LOADER UINT32 BlSingularityCallKernel( UINT32 Index ) //-++ //- //- Routine Description: //- //- This function calls the kernel. //- //- Arguments: //- //- Index - Supplies the index of the current processor. //- //- Return Value: //- //- Kernel exit code. //- //--- { UINT32 ExitCode; ULONG_PTR SKINIT_base; #if SINGULARITY_VERBOSE BlRtlPrintf("\fBL: Processor[%d]: Starting Singularity ...\n", Index ); BlRtlPrintf("BL: Cpu = %p\n", BlProcessor[Index].Cpu ); BlRtlPrintf("BL: GDT =[%p...%p]\n", BlProcessor[Index].Cpu->segments.gdtPtr.addr, BlProcessor[Index].Cpu->segments.gdtPtr.addr + BlProcessor[Index].Cpu->segments.gdtPtr.limit ); BlRtlPrintf("BL: stack=[%p...%p]\n", BlProcessor[Index].Cpu->KernelStackLimit, BlProcessor[Index].Cpu->KernelStackBegin ); #endif BlMmSetGdtr((PGDTR) &BlProcessor[Index].Cpu->segments.gdtPtr.limit); #if defined(BOOT_X86) BlMmSetFs(PROCESSOR_SELECTOR); #elif defined(BOOT_X64) BlMmSetGs(PROCESSOR_SELECTOR); #endif BlMmSetCr3(BlMmBootCr3); BlRtlPrintf("BL: kernel=[%p ... %p]\n", BlKernelBase, (ULONG_PTR) BlKernelBase + BlKernelSize - 1); BlRtlPrintf("BL: entry= %p\n", BlKernelEntryPoint); //- Compute the 64K aligned address SKINIT_base = (ULONG_PTR)((UINT32)BlKernelEntryPoint) & ~(0x00010000 - 1); BlRtlPrintf("SL Base: entry= %p\n", SKINIT_base); BlRtlPrintf("SL Header: entry= %p\n", *(UINT32*)SKINIT_base); //- BlRtlPrintf("Stopping here\n"); //- while (1) {} //- Load the app too ULONG_PTR AppEntry = BlSingularityLoadAppImage(); //- Deposit the app's entry point at base+190k UINT32 app_args = (UINT32)SKINIT_base + 193 * 1024; UINT32* app_args_words = (UINT32*)app_args; app_args_words[0] = (UINT32)AppEntry; DisablePaging(42); //- Invoke SKINIT instead of calling into the kernel directly if (TestForSKINIT()) { if (PrepTPM(SKINIT_base)) { BlRtlPrintf("Prepping the TPM failed. Halting...\n"); BlRtlHalt(); } DEBUG_MSG("Executing SKINIT for real. See you on the other side!\n"); BlRealSKINIT(SKINIT_base); } else { //- Assume we're in a VM, so don't bother with the TPM DEBUG_MSG("Faking SKINIT for testing purposes.\n"); BlFakeSKINIT(SKINIT_base); } //- Should never reach here! BlRtlPrintf("Wasn't expecting to see this...\n"); ExitCode = BlKernelEntryPoint(BlPlatform, BlProcessor[Index].Cpu); BlMmSetGdtr(&BlMmInitialGdtr); BlVideoInitialize(); return ExitCode; } VOID BlSingularityEnterKernel( VOID ) //++ // // Routine Description: // // This function enters Singularity. // //-- { UINT32 ExitCode; PVOID LocalVariable; UINT32 Index; Index = BlSingularityProcessorToStart; BLASSERT(((ULONG_PTR) &LocalVariable) >= BlProcessor[Index].Cpu->KernelStackLimit); BLASSERT(((ULONG_PTR) &LocalVariable) < BlProcessor[Index].Cpu->KernelStackBegin); // // The bootstrap processor runs in a loop calling kernel entry point and performing warm boot // when the kernel returns. The application processors do not return from the kernel call and are // reinitialized with SIPIs by the kernel after a warm boot. // if (Index == 0) { for (;;) { BlMmDumpPhysicalRegionList(); ExitCode = BlSingularityCallKernel(Index); #if SINGULARITY_VERBOSE BlRtlPrintf("BL: Processor[%02x]: Kernel exited with 0x%08x.\n", Index, ExitCode); #endif BlPlatform->BootCount += 1; BlRtlZeroMemory(BlKernelBase, BlKernelSize); BlPeLoadImage(BlKernelBase, BlKernelSize, BlKernelFile->Data, (PVOID *) &BlKernelEntryPoint, FALSE); } } else { ExitCode = BlSingularityCallKernel(Index); BlRtlPrintf("BL: AP returned from kernel call!\n"); BlRtlHalt(); } return; } VOID BlSingularityExit( VOID ) //++ // // Routine Description: // // This function exits Singularity and performs the "kill action" requested by the kernel. // //-- { BlMmSetGdtr(&BlMmInitialGdtr); BlVideoInitialize(); switch (BlPlatform->KillAction) { case Class_Microsoft_Singularity_Hal_Platform_EXIT_AND_SHUTDOWN: { BlRtlPrintf("BL: Kernel requested shutdown.\n"); BlRtlShutdownSystem(); break; } case Class_Microsoft_Singularity_Hal_Platform_EXIT_AND_RESTART: { BlRtlPrintf("BL: Kernel requested restart.\n"); BlRtlResetSystem(); break; } case Class_Microsoft_Singularity_Hal_Platform_EXIT_AND_HALT: { BlRtlPrintf("BL: Kernel requested halt.\n"); BlRtlHalt(); break; } case Class_Microsoft_Singularity_Hal_Platform_EXIT_AND_WARMBOOT: { BlRtlPrintf("BL: Kernel requested warmboot.\n"); BlPlatform->BootCount += 1; BlRtlZeroMemory(BlKernelBase, BlKernelSize); BlPeLoadImage(BlKernelBase, BlKernelSize, BlKernelFile->Data, (PVOID *) &BlKernelEntryPoint, FALSE); BlSingularityProcessorToStart = 0; BlMmSwitchStack((PVOID) BlProcessor[0].Cpu->KernelStackBegin, BlSingularityEnterKernel); break; } default: { BlRtlPrintf("BL: Unrecognized kill action 0x%08x!\n", BlPlatform->KillAction); BlRtlHalt(); } } } unsigned int IsApicPresent (void) { unsigned int reg_edx = BlGetCpuidEdx(1); return ((reg_edx >> 9) & 0x1); } #define INITIAL_APIC_ID_BITS 0xFF000000 // EBX[31:24] unique APIC ID // Returns the 8-bit unique Initial APIC ID for the processor this // code is actually running on. The default value returned is 0xFF if // Hyper-Threading Technology is not supported. // Taken from intel application note Ap-485 "Intel Processor Identification and the CPUID instruction" unsigned char GetAPIC_ID (void) { unsigned int reg_ebx = BlGetCpuidEbx(1); return (unsigned char) ((reg_ebx & INITIAL_APIC_ID_BITS) >> 24); } VOID BlSingularityInitialize( UINT32 NumberOfProcessors, PFAR_POINTER ApEntry16, PFAR_POINTER ApStartupLock ) //++ // // Routine Description: // // This function initializes Singularity. // // Arguments: // // NumberOfProcessors - Supplies the number of processors on the system. // // ApEntry6 - Supplies a pointer to the 16-bit entry point for // application processors on a multi-processor system. // // ApStartupLock - Supplies a pointer to the lock used for AP startup // synchronization. // //-- { UINT64 Base; UINT32 Index; PVOID PhysicalRegionHandle; UINT64 Size; UINT32 Type; UINT8 id; UINT64 HighAddress; UINT64 TempAddress; UINT64 StackStart; UINT64 PlayStart; int i; char* p; // // Allocate processor array and set processor count. // BlProcessor = (PBL_PROCESSOR) BlPoolAllocateBlock(sizeof(BL_PROCESSOR) * NumberOfProcessors); BlProcessorCount = NumberOfProcessors; // // Load distro. // BlSingularityLoadDistro(); // // Load kernel image. // BlSingularityLoadKernelImage(); // // Allocate native platform structure. // BlPlatform = (Class_Microsoft_Singularity_Hal_Platform *) BlMmAllocatePhysicalRegion(ROUND_UP_TO_PAGES(sizeof(Class_Microsoft_Singularity_Hal_Platform)), BL_MM_PHYSICAL_REGION_NATIVE_PLATFORM); BlPlatform->Size = sizeof(Class_Microsoft_Singularity_Hal_Platform); if (IsApicPresent()) { BlPlatform->hasApic = 1; } else { BlPlatform->hasApic = 0; } // // Set offsets for per-cpu and per-thread pointers. // BlPlatform->CpuRecordPointerOffset = 0; BlPlatform->ThreadRecordPointerOffset = sizeof(PTR_TYPE); // // Set boot time. // if (BlStartTime.Year != 0) { BlPlatform->BootYear = 2000 + BlStartTime.Year; BlPlatform->BootMonth = BlStartTime.Month; BlPlatform->BootDay = BlStartTime.Day; BlPlatform->BootHour = BlStartTime.Hour; BlPlatform->BootMinute = BlStartTime.Minute; BlPlatform->BootSecond = BlStartTime.Second; } // // Set processor count. // BlPlatform->CpuRealCount = NumberOfProcessors; BlPlatform->CpuMaxCount = NumberOfProcessors; // // Set MPS floating pointer structure address. // BlPlatform->MpFloat32 = (UINT32) (ULONG_PTR) BlMpsFps; // // Set kernel range. // BlPlatform->KernelDllBase = (ULONG_PTR) BlKernelBase; BlPlatform->KernelDllFirstPage = (ULONG_PTR) BlKernelBase; BlPlatform->KernelDllSize = BlKernelSize; // // Set command line. // BlPlatform->CommandLine32 = (ULONG_PTR) BlCommandLine; BlPlatform->CommandLineCount = BlRtlStringLengthW(BlCommandLine); // // Set PNP node list address. // BlPlatform->PnpNodesAddr32 = (ULONG_PTR) BlPnpSystemDeviceNodeList; BlPlatform->PnpNodesSize32 = BlPnpSystemDeviceNodeListSize; // // Set ISA information. // BlPlatform->IsaCsns = BlPnpIsaConfiguration.NumberOfCardSelectNumbers; BlPlatform->IsaReadPort = BlPnpIsaConfiguration.DataReadPort; // // Set PCI BIOS information. // BlPlatform->PciBiosAX = BlPciInstallationCheck.Eax; BlPlatform->PciBiosBX = BlPciInstallationCheck.Ebx; BlPlatform->PciBiosCX = BlPciInstallationCheck.Ecx; BlPlatform->PciBiosEDX = BlPciInstallationCheck.Edx; // // Set VESA information. // BlPlatform->VesaBuffer = BlVesaVideoBuffer; // // Set ACPI information. // BlPlatform->AcpiRoot32 = (ULONG_PTR) BlAcpiRsdpAddress; // // Set file image table. // BlPlatform->FileImageTableBase32 = (ULONG_PTR) BlSingularityFileImageTable; BlPlatform->FileImageTableEntries = BlSingularityFileImageTableSize; // // Allocate log record and text buffers. // BlPlatform->LogRecordBuffer = (ULONG_PTR) BlMmAllocatePhysicalRegion(SINGULARITY_LOG_RECORD_SIZE, BL_MM_PHYSICAL_REGION_LOG_RECORD); BlPlatform->LogRecordSize = SINGULARITY_LOG_RECORD_SIZE; BlPlatform->LogTextBuffer = (ULONG_PTR) BlMmAllocatePhysicalRegion(SINGULARITY_LOG_TEXT_SIZE, BL_MM_PHYSICAL_REGION_LOG_TEXT); BlPlatform->LogTextSize = SINGULARITY_LOG_TEXT_SIZE; // // Set debugger settings. // if (BlKdComPort != 0) { BlPlatform->DebuggerType = Class_Microsoft_Singularity_Hal_Platform_DEBUGGER_SERIAL; BlPlatform->DebugBasePort = BlComBasePort[BlKdComPort]; } else if (BlPciOhci1394BaseAddress != 0) { BlRtlPrintf("Got 1394 debugger base address!\n"); BlPlatform->DebuggerType = Class_Microsoft_Singularity_Hal_Platform_DEBUGGER_1394; BlPlatform->Ohci1394Base = BlPciOhci1394BaseAddress; BlPlatform->Ohci1394BufferAddr32 = (ULONG_PTR) BlSingularityOhci1394Buffer; BlPlatform->Ohci1394BufferSize32 = sizeof(BlSingularityOhci1394Buffer); } else { BlRtlPrintf("Debugger OFF\n"); BlPlatform->DebuggerType = Class_Microsoft_Singularity_Hal_Platform_DEBUGGER_NONE; } BlPlatform->TwiddleSpinBase = 0xb8000; // // Set exit routine. // BlPlatform->Kill32 = (ULONG_PTR) BlSingularityExit; // // Set entry routine and startup lock address for application processors. // BlPlatform->MpEnter32 = (ULONG_PTR) BlRtlConvertFarPointerToLinearPointer(ApEntry16); BlPlatform->MpStartupLock32 = (ULONG_PTR) BlRtlConvertFarPointerToLinearPointer(ApStartupLock); // // Allocate native processor structures. // BlCpuArray = (Class_Microsoft_Singularity_Hal_Cpu *) BlMmAllocatePhysicalRegion(ROUND_UP_TO_PAGES(sizeof(Class_Microsoft_Singularity_Hal_Cpu) * NumberOfProcessors), BL_MM_PHYSICAL_REGION_NATIVE_PROCESSOR); BlPlatform->Cpus = (ULONG_PTR) BlCpuArray; // // Allocate per-processor resources upfront. // for (Index = 0; Index < NumberOfProcessors; Index += 1) { BlProcessor[Index].Index = Index; BlProcessor[Index].Cpu = &BlCpuArray[Index]; BlProcessor[Index].ContextPage = (PVOID) BlMmAllocatePhysicalRegion(2 * PAGE_SIZE, BL_MM_PHYSICAL_REGION_CONTEXT); BlProcessor[Index].BasePage = (PVOID) ((ULONG_PTR) BlProcessor[Index].ContextPage + PAGE_SIZE); BlProcessor[Index].TaskPage = (BL_TASK_SEGMENT *) BlMmAllocatePhysicalRegion(PAGE_SIZE, BL_MM_PHYSICAL_REGION_TASK); } // // Allocate kernel stack for the bootstrap processor. // StackStart = BlMmAllocatePhysicalRegion(SINGULARITY_KERNEL_STACK_SIZE, BL_MM_PHYSICAL_REGION_KERNEL_STACK); if (0 == StackStart) { BlRtlPrintf("Failed to allocate kernel stack.\n", StackStart); BlRtlHalt(); } BlRtlPrintf("Allocated kernel stack at 0x%016I64x\n", StackStart); BlProcessor[0].KernelStack = (PVOID) (StackStart); BlProcessor[0].Cpu->DomainBsp = TRUE; BlPlatform->OutgoingMessage = 0; BlPlatform->OutgoingCount = 0; BlPlatform->IncomingFree = 0; BlPlatform->IncomingFreeCount = 0; BlPlatform->IncomingMessage = 0; BlPlatform->IncomingCount = 0; BlPlatform->OutgoingFree = 0; BlPlatform->OutgoingFreeCount = 0; BlPlatform->MaxBufferLength = 0; BlProcessor[0].KernelStackSize = SINGULARITY_KERNEL_STACK_SIZE; // // Initialize the first processor structure. // BlSingularityInitializeProcessor(0); // // Allocate memory map for Singularity. // BlSingularitySmap = (PBL_SMAP) BlMmAllocatePhysicalRegion(sizeof(BL_SMAP), BL_MM_PHYSICAL_REGION_SINGULARITY_SMAP); // // Claim all remaining physical memory for Singularity. // // while (BlMmFindFreePhysicalRegion(&Base, &Size) != FALSE) { // // BlMmAllocateSpecificPhysicalRegion(Base, Size, BL_MM_PHYSICAL_REGION_SINGULARITY); // } // // Generate memory map for Singularity. // BlRtlZeroMemory(BlSingularitySmap, sizeof(BL_SMAP)); BlPlatform->PhysicalBase = (ULONG_PTR) -1; PhysicalRegionHandle = NULL; while (BlMmGetNextPhysicalRegion(&PhysicalRegionHandle, &Base, &Size, &Type) != FALSE) { if ((Type == BL_MM_PHYSICAL_REGION_SINGULARITY) || (Type == BL_MM_PHYSICAL_REGION_KERNEL_IMAGE) || (Type == BL_MM_PHYSICAL_REGION_NATIVE_PLATFORM) || (Type == BL_MM_PHYSICAL_REGION_NATIVE_PROCESSOR) || (Type == BL_MM_PHYSICAL_REGION_KERNEL_STACK) ) { if (Type == BL_MM_PHYSICAL_REGION_SINGULARITY) { BlSingularitySmap->Entry[BlSingularitySmap->EntryCount].Base = Base; BlSingularitySmap->Entry[BlSingularitySmap->EntryCount].Size = Size; BlSingularitySmap->Entry[BlSingularitySmap->EntryCount].Type = BL_SMAP_AVAILABLE; } else if (Type == BL_MM_PHYSICAL_REGION_KERNEL_IMAGE || (Type == BL_MM_PHYSICAL_REGION_NATIVE_PLATFORM) || (Type == BL_MM_PHYSICAL_REGION_NATIVE_PROCESSOR)) { BlSingularitySmap->Entry[BlSingularitySmap->EntryCount].Base = Base; BlSingularitySmap->Entry[BlSingularitySmap->EntryCount].Size = Size; BlSingularitySmap->Entry[BlSingularitySmap->EntryCount].Type = BL_SMAP_KERNEL_NONGC; } else if (Type == BL_MM_PHYSICAL_REGION_KERNEL_STACK) { BlSingularitySmap->Entry[BlSingularitySmap->EntryCount].Base = Base; BlSingularitySmap->Entry[BlSingularitySmap->EntryCount].Size = Size; BlSingularitySmap->Entry[BlSingularitySmap->EntryCount].Type = BL_SMAP_KERNEL_STACK; } else { BlRtlPrintf("UNKNOWN TYPE MEMORY??? %d\n", Type); } if (Base < BlPlatform->PhysicalBase) { BlPlatform->PhysicalBase = (ULONG_PTR) Base; } BlSingularitySmap->EntryCount += 1; } else { #if MM_VERBOSE BlRtlPrintf("Building SMAP marking type %s nongc\n", BlMmPhysicalRegionTypeString(Type)); #endif BlSingularitySmap->Entry[BlSingularitySmap->EntryCount].Base = Base; BlSingularitySmap->Entry[BlSingularitySmap->EntryCount].Size = Size; BlSingularitySmap->Entry[BlSingularitySmap->EntryCount].Type = BL_SMAP_KERNEL_NONGC; BlSingularitySmap->EntryCount += 1; } } BlPlatform->Smap32 = (ULONG_PTR) (PVOID) BlSingularitySmap->Entry; BlPlatform->SmapCount = BlSingularitySmap->EntryCount; #if MM_VERBOSE BlMmDumpPhysicalRegionList(); #endif // // Start processor 0. // BlSingularityProcessorToStart = 0; BlMmSwitchStack((PVOID) BlProcessor[0].Cpu->KernelStackBegin, BlSingularityEnterKernel); return; } VOID BlSingularityApEntry( VOID ) //++ // // Routine Description: // // This function implements the entry point for application processors. // //-- { UINT32 Index; UINT8 MyIdChar; UINT32 MyId; UINT32 MyStack; Class_Microsoft_Singularity_Hal_Cpu *Processor; // BlRtlPrintf("In Ap Entry\n"); // BlRtlPrintf("Non AP processor booting\n"); Index = BlPlatform->MpBootInfo.TargetCpu; if (Index == 0) { // BlRtlPrintf("BL: BSP entered AP code!\n"); BlRtlHalt(); } #if SINGULARITY_VERBOSE BlRtlPrintf("BL: Initializing processor %u of %u. [Max=%u]\n", Index + 1, BlPlatform->CpuRealCount, BlPlatform->CpuMaxCount); #endif BlProcessor[Index].KernelStack = (PVOID) BlPlatform->MpBootInfo.KernelStackLimit; BlProcessor[Index].Cpu->DomainBsp = FALSE; BlProcessor[Index].KernelStackSize = BlPlatform->MpBootInfo.KernelStackBegin - BlPlatform->MpBootInfo.KernelStackLimit; BlSingularityInitializeProcessor(Index); BlSingularityProcessorToStart = Index; BlMmSwitchStack((PVOID) BlProcessor[Index].Cpu->KernelStackBegin, BlSingularityEnterKernel); return; } ================================================ FILE: ironclad-apps/src/Checked/BootLoader/SingLdrPc/blsmap.cpp ================================================ //++ // // Copyright (c) Microsoft Corporation // // Module Name: // // blsmap.cpp // // Abstract: // // This module implements system memory map (SMAP) support for the boot loader. // //-- #include "bl.h" BL_SMAP BlSystemMemoryMap; #if SMAP_VERBOSE PCHAR BlSmapTypeString( UINT32 Type ) //++ // // Routine Description: // // This function returns the specified memory type string. // // Arguments: // // Type - Supplies the memory type. // // Return Value: // // Memory type string. // //-- { switch (Type) { case BL_SMAP_AVAILABLE: { return "Available"; } case BL_SMAP_RESERVED: { return "Reserved"; } case BL_SMAP_ACPI_RECLAIM: { return "ACPI Reclaim"; } case BL_SMAP_ACPI_NVS: { return "ACPI NVS"; } default: { return "*UNKNOWN*"; } } } #endif VOID BlSmapInitialize( VOID ) //++ // // Routine Description: // // This function initializes the system memory map. // //-- { UINT32 Index; PBEB Beb; Beb = BlGetBeb(); if (Beb->SmapAddr != 0) { PUINT8 pb = (PUINT8)Beb->SmapAddr; UINT32 cb = Beb->SmapSize; for (Index = 0; Index < cb / 20; Index++) { PUINT8 pn = pb + Index * 20; BlRtlCopyMemory((PVOID)&BlSystemMemoryMap.Entry[Index], (PVOID)(pb + Index * 20), 20); #if 0 BlVideoPrintf("%4d: %p %p %8x\n", Index, ((UINT64 *)(pn + 0))[0], ((UINT64 *)(pn + 8))[0], ((UINT32 *)(pn + 16))[0]); #endif } BlSystemMemoryMap.EntryCount = Index; } else { ULONG_PTR Address; BL_LEGACY_CALL_CONTEXT Context; UINT32 ContinuationValue; Index = 0; ContinuationValue = 0; for (;;) { BLASSERT(Index < (sizeof(BlSystemMemoryMap.Entry) / sizeof(BlSystemMemoryMap.Entry[0]))); BlRtlZeroMemory(&Context, sizeof(Context)); Context.eax = 0xE820; Context.edx = 0x534D4150; // 'SMAP' Context.ebx = ContinuationValue; Context.ecx = 20; Address = (ULONG_PTR) &BlSystemMemoryMap.Entry[Index]; Context.es = (UINT32) (Address >> 4); Context.edi = (UINT32) (Address & 0xF); BlRtlCallLegacyInterruptService(0x15, &Context, &Context); if (((Context.eflags & RFLAGS_CF) != 0) || (Context.eax != 0x534D4150)) { BlRtlPrintf("SMAP: INT 15/E820 failed!\n"); BlRtlHalt(); } Index += 1; ContinuationValue = Context.ebx; if (ContinuationValue == 0) { break; } } BlSystemMemoryMap.EntryCount = Index; } #if SMAP_VERBOSE BlRtlPrintf("SMAP: %u entries\n", BlSystemMemoryMap.EntryCount); for (Index = 0; Index < BlSystemMemoryMap.EntryCount; Index += 1) { BlRtlPrintf("SMAP: %016I64x ... %016I64x %s\n", BlSystemMemoryMap.Entry[Index].Base, BlSystemMemoryMap.Entry[Index].Base + BlSystemMemoryMap.Entry[Index].Size - 1, BlSmapTypeString(BlSystemMemoryMap.Entry[Index].Type)); } #endif return; } ================================================ FILE: ironclad-apps/src/Checked/BootLoader/SingLdrPc/blstring.cpp ================================================ //++ // // Copyright (c) Microsoft Corporation // // Module Name: // // blstring.cpp // // Abstract: // // This module implements string functions for the boot loader environment. // //-- #include "bl.h" #define ABS(X) (((X) < 0) ? (-(X)) : (X)) #define STRING_TOKEN_LONG 1 #define STRING_TOKEN_ULONG 2 #define STRING_TOKEN_ULONG_HEX 3 #define STRING_TOKEN_LONGLONG 4 #define STRING_TOKEN_ULONGLONG 5 #define STRING_TOKEN_ULONGLONG_HEX 6 #define STRING_TOKEN_PVOID 7 #define STRING_TOKEN_PCHAR 8 #define STRING_TOKEN_CHAR 9 CHAR BlRtlConvertCharacterToUpperCase( CHAR C ) //++ // // Routine Description: // // This function converts the specified character to upper case. // // Arguments: // // C - Supplies the character to convert. // // Return Value: // // Upper case character matching the specified character. // //-- { if ((C >= 'a') && (C <= 'z')) { return C + 'A' - 'a'; } return C; } BOOLEAN BlRtlParsePositiveDecimal( PCSTR String, PUINT32 Number, PUINT32 CharactersConsumed ) //++ // // Routine Description: // // This function parses a positive decimal value. // // Arguments: // // String - Supplies a pointer to the string to parse. // // Number - Receives the number. // // CharactersConsumed - Receives the number of characters consumed. // // // Return Value: // // TRUE, if parse was successful. // FALSE, otherwise. // //-- { UINT32 Digit; UINT32 Index; UINT32 Temp; if ((String[0] < '0') || (String[0] > '9')) { return FALSE; } Index = 0; Temp = 0; for (;;) { if ((String[Index] < '0') || (String[Index] > '9')) { *Number = Temp; *CharactersConsumed = Index; return TRUE; } Digit = String[Index] - '0'; if (((Temp * 10) + Digit) < Temp) { return FALSE; } Temp = (Temp * 10) + Digit; Index += 1; } } BOOLEAN BlRtlParseTypeSpecifier( PCSTR String, PINT32 Width, PCHAR PadCharacter, PUINT8 TokenType, PUINT32 CharactersConsumed ) //++ // // Routine Description: // // This function parses a type specifier. // // Arguments: // // String - Supplies a pointer to the string to parse. // // Width - Receives the width. // // PadCharacter - Receives the pad character. // // TokenType - Receives the token type. // // CharactersConsumed - Receives the number of characters consumed. // // // Return Value: // // TRUE, if parse was successful. // FALSE, otherwise. // //-- { UINT32 Advance; BOOLEAN WidthPresent; UINT32 Index; BOOLEAN Minus; UINT32 WidthPositiveValue; BOOLEAN Zero; SATISFY_OVERZEALOUS_COMPILER(WidthPositiveValue = 0); // // Check if type specifier character is present. // if (String[0] != '%') { return FALSE; } Index = 1; // // Check for pad modifiers. // Minus = FALSE; Zero = FALSE; for (;;) { if (String[Index] == '-') { if (Minus != FALSE) { return FALSE; } Minus = TRUE; Index += 1; } else if (String[Index] == '0') { if (Zero != FALSE) { return FALSE; } Zero = TRUE; Index += 1; } else { break; } } // // - and 0 pad modifiers are mutually exclusive. // if ((Minus != FALSE) && (Zero != FALSE)) { return FALSE; } // // If there is a width value, then parse it. // WidthPresent = ((String[Index] >= '1') && (String[Index] <= '9')); if (WidthPresent != FALSE) { if (BlRtlParsePositiveDecimal(&String[Index], &WidthPositiveValue, &Advance) == FALSE) { return FALSE; } Index += Advance; } // // Pad modifiers require width value. // if (((Minus != FALSE) || (Zero != FALSE)) && (WidthPresent == FALSE)) { return FALSE; } // // Set pad character. // if (Zero != FALSE) { *PadCharacter = '0'; } else { *PadCharacter = ' '; } // // Compute signed width value. // if (WidthPresent == FALSE) { *Width = 0; } else if (Minus == FALSE) { *Width = (INT32) WidthPositiveValue; } else { *Width = -((INT32) WidthPositiveValue); } // // Set type character. // if (BlRtlEqualStringN(&String[Index], "d", 1) != FALSE) { *TokenType = STRING_TOKEN_LONG; Index += 1; } else if (BlRtlEqualStringN(&String[Index], "u", 1) != FALSE) { *TokenType = STRING_TOKEN_ULONG; Index += 1; } else if (BlRtlEqualStringN(&String[Index], "x", 1) != FALSE) { *TokenType = STRING_TOKEN_ULONG_HEX; Index += 1; } else if (BlRtlEqualStringN(&String[Index], "I64d", 4) != FALSE) { *TokenType = STRING_TOKEN_LONGLONG; Index += 4; } else if (BlRtlEqualStringN(&String[Index], "I64u", 4) != FALSE) { *TokenType = STRING_TOKEN_ULONGLONG; Index += 4; } else if (BlRtlEqualStringN(&String[Index], "I64x", 4) != FALSE) { *TokenType = STRING_TOKEN_ULONGLONG_HEX; Index += 4; } else if (BlRtlEqualStringN(&String[Index], "p", 1) != FALSE) { *TokenType = STRING_TOKEN_PVOID; Index += 1; } else if (BlRtlEqualStringN(&String[Index], "s", 1) != FALSE) { *TokenType = STRING_TOKEN_PCHAR; Index += 1; } else if (BlRtlEqualStringN(&String[Index], "c", 1) != FALSE) { *TokenType = STRING_TOKEN_CHAR; Index += 1; } else { return FALSE; } // // Set number of characters consumed. // *CharactersConsumed = Index; return TRUE; } BOOLEAN BlRtlFormatSignedDecimalLong( PCHAR Output, UINT32 OutputSize, INT32 Value, INT32 Width, PUINT32 CharactersConsumed ) //++ // // Routine Description: // // This function formats a signed decimal long. // // Arguments: // // Output - Supplies a pointer to the output buffer. // // OutputSize - Supplies the size of the output buffer. // // Value - Supplies the value to format. // // Width - Supplies the width. // // CharactersConsumed - Receives the number of characters consumed. // // // Return Value: // // TRUE, if format was successful. // FALSE, otherwise. // //-- { UINT32 Index; UINT32 MinimumWidth; BOOLEAN Minus; UINT32 NumberWidth; UINT32 PadWidth; UINT32 Temp; // // Check if this is a negative value. // Minus = (BOOLEAN) (Value < 0); // // Compute the number of characters necessary. // Temp = ABS(Value); NumberWidth = 0; do { NumberWidth += 1; Temp = Temp / 10; } while (Temp > 0); if (Minus != FALSE) { NumberWidth += 1; } PadWidth = 0; MinimumWidth = ABS(Width); if (MinimumWidth > NumberWidth) { PadWidth = MinimumWidth - NumberWidth; } // // Check if there is sufficient space in the output buffer. // if ((NumberWidth + PadWidth) > OutputSize) { return FALSE; } Index = 0; // // If right alignment is specified, then insert any necessary pads before the number. // if (Width > 0) { while (PadWidth > 0) { Output[Index] = ' '; Index += 1; PadWidth -= 1; } } // // Insert absolute number starting with the least significant digit, going right to left. // Temp = ABS(Value); Index += NumberWidth; do { Index -= 1; Output[Index] = (CHAR) ('0' + (Temp % 10)); Temp = Temp / 10; } while (Temp > 0); // // If the number is negative, then insert the negative sign. // if (Minus != FALSE) { Index -= 1; Output[Index] = '-'; } // // If left alignment was specified, then insert any necessary pads after the number. // Index += NumberWidth; while (PadWidth > 0) { Output[Index] = ' '; Index += 1; PadWidth -= 1; } // // Set number of characters consumed in the buffer. // *CharactersConsumed = Index; return TRUE; } BOOLEAN BlRtlFormatUnsignedLong( PCHAR Output, UINT32 OutputSize, UINT32 Value, UINT8 PadCharacter, INT32 Width, UINT32 Base, PUINT32 CharactersConsumed ) //++ // // Routine Description: // // This function formats an unsigned long. // // Arguments: // // Output - Supplies a pointer to the output buffer. // // OutputSize - Supplies the size of the output buffer. // // Value - Supplies the value to format. // // PadCharacter - Supplies the pad character. // // Width - Supplies the width. // // Base - Supplies the base. // // CharactersConsumed - Receives the number of characters consumed. // // // Return Value: // // TRUE, if format was successful. // FALSE, otherwise. // //-- { UINT32 Index; UINT32 MinimumWidth; UINT32 NumberWidth; UINT32 PadWidth; UINT32 Temp; if (Base == 0) { return FALSE; } // // Compute the number of characters necessary. // Temp = Value; NumberWidth = 0; do { NumberWidth += 1; Temp = Temp / Base; } while (Temp > 0); PadWidth = 0; MinimumWidth = ABS(Width); if (MinimumWidth > NumberWidth) { PadWidth = MinimumWidth - NumberWidth; } // // Check if there is sufficient space in the output buffer. // if ((NumberWidth + PadWidth) > OutputSize) { return FALSE; } Index = 0; // // If right alignment is specified, then insert any necessary pads before the number. // if (Width > 0) { while (PadWidth > 0) { Output[Index] = PadCharacter; Index += 1; PadWidth -= 1; } } // // Insert absolute number starting with the least significant digit, going right to left. // Temp = Value; Index += NumberWidth; do { Index -= 1; switch (Base) { case 10: { Output[Index] = (CHAR) ('0' + (Temp % Base)); break; } case 16: { if ((Temp % Base) < 10) { Output[Index] = (CHAR) ('0' + (Temp % Base)); } else { Output[Index] = (CHAR) ('A' + (Temp % Base) - 10); } break; } default: { return FALSE; } } Temp = Temp / Base; } while (Temp > 0); // // If left alignment was specified, then insert any necessary pads after the number. // Index += NumberWidth; while (PadWidth > 0) { Output[Index] = PadCharacter; Index += 1; PadWidth -= 1; } // // Set number of characters consumed in the buffer. // *CharactersConsumed = Index; return TRUE; } BOOLEAN BlRtlFormatUnsignedLongLong( PCHAR Output, UINT32 OutputSize, UINT64 Value, UINT8 PadCharacter, INT32 Width, UINT32 Base, PUINT32 CharactersConsumed ) //++ // // Routine Description: // // This function formats an unsigned long long. // // Arguments: // // Output - Supplies a pointer to the output buffer. // // OutputSize - Supplies the size of the output buffer. // // Value - Supplies the value to format. // // PadCharacter - Supplies the pad character. // // Width - Supplies the width. // // Base - Supplies the base. // // CharactersConsumed - Receives the number of characters consumed. // // // Return Value: // // TRUE, if format was successful. // FALSE, otherwise. // //-- { UINT32 Index; UINT32 MinimumWidth; UINT32 NumberWidth; UINT32 PadWidth; UINT64 Temp; if (Base == 0) { return FALSE; } // // Compute the number of characters necessary. // Temp = Value; NumberWidth = 0; do { NumberWidth += 1; Temp = Temp / Base; } while (Temp > 0); PadWidth = 0; MinimumWidth = ABS(Width); if (MinimumWidth > NumberWidth) { PadWidth = MinimumWidth - NumberWidth; } // // Check if there is sufficient space in the output buffer. // if ((NumberWidth + PadWidth) > OutputSize) { return FALSE; } Index = 0; // // If right alignment is specified, then insert any necessary pads before the number. // if (Width > 0) { while (PadWidth > 0) { Output[Index] = PadCharacter; Index += 1; PadWidth -= 1; } } // // Insert absolute number starting with the least significant digit, going right to left. // Temp = Value; Index += NumberWidth; do { Index -= 1; switch (Base) { case 10: { Output[Index] = (CHAR) ('0' + (Temp % Base)); break; } case 16: { if ((Temp % Base) < 10) { Output[Index] = (CHAR) ('0' + (Temp % Base)); } else { Output[Index] = (CHAR) ('A' + (Temp % Base) - 10); } break; } default: { return FALSE; } } Temp = Temp / Base; } while (Temp > 0); // // If left alignment was specified, then insert any necessary pads after the number. // Index += NumberWidth; while (PadWidth > 0) { Output[Index] = PadCharacter; Index += 1; PadWidth -= 1; } // // Set number of characters consumed in the buffer. // *CharactersConsumed = Index; return TRUE; } UINT32 BlRtlStringLength( PCSTR String ) //++ // // Routine Description: // // This function returns the length of the specified string. // // Arguments: // // String - Supplies a pointer to the string. // // Return Value: // // Length of the string. // //-- { UINT32 Index; Index = 0; while (String[Index] != 0) { Index += 1; } return Index; } UINT32 BlRtlStringLengthW( PCWSTR String ) //++ // // Routine Description: // // This function returns the length of the specified wide string. // // Arguments: // // String - Supplies a pointer to the string. // // Return Value: // // Length of the string. // //-- { UINT32 Index; Index = 0; while (String[Index] != 0) { Index += 1; } return Index; } BOOLEAN BlRtlFormatStringToken( PCHAR Output, UINT32 OutputSize, PCSTR String, INT32 Width, PUINT32 CharactersConsumed ) //++ // // Routine Description: // // This function formats a string token. // // Arguments: // // Output - Supplies a pointer to the output buffer. // // OutputSize - Supplies the size of the output buffer. // // String - Supplies the string token. // // Width - Supplies the width. // // CharactersConsumed - Receives the number of characters consumed. // // // Return Value: // // TRUE, if format was successful. // FALSE, otherwise. // //-- { UINT32 Index; UINT32 MinimumWidth; UINT32 PadWidth; UINT32 StringIndex; UINT32 StringLength; // // Compute string length, minimum width, and pad width. // StringLength = BlRtlStringLength(String); MinimumWidth = ABS(Width); PadWidth = 0; if (MinimumWidth > StringLength) { PadWidth = MinimumWidth - StringLength; } // // Check if there is sufficient space in the output buffer. // if ((StringLength + PadWidth) > OutputSize) { return FALSE; } Index = 0; // // If right alignment is specified, then insert any necessary pads before the string. // if (Width > 0) { while (PadWidth > 0) { Output[Index] = ' '; Index += 1; PadWidth -= 1; } } // // Copy the string. // for (StringIndex = 0; StringIndex < StringLength; StringIndex += 1) { Output[Index] = String[StringIndex]; Index += 1; } // // If left alignment was specified, then insert any necessary pads after the string. // while (PadWidth > 0) { Output[Index] = ' '; Index += 1; PadWidth -= 1; } // // Set number of characters consumed in the buffer. // *CharactersConsumed = Index; return TRUE; } BOOLEAN BlRtlFormatChar( PCHAR Output, UINT32 OutputSize, CHAR Value, PUINT32 CharactersConsumed ) //++ // // Routine Description: // // This function formats a character. // // Arguments: // // Output - Supplies a pointer to the output buffer. // // OutputSize - Supplies the size of the output buffer. // // Value - Supplies the value to format. // // CharactersConsumed - Receives the number of characters consumed. // // // Return Value: // // TRUE, if format was successful. // FALSE, otherwise. // //-- { // // Check if there is sufficient space in the output buffer. // if (1 > OutputSize) { return FALSE; } Output[0] = Value; // // Set number of characters consumed in the buffer. // *CharactersConsumed = 1; return TRUE; } BOOLEAN BlRtlFormatString( PCHAR Output, UINT32 OutputSize, PCSTR Format, va_list ArgumentList ) //++ // // Routine Description: // // This function formats a string. // // Arguments: // // Output - Supplies a pointer to the output buffer. // // OutputSize - Supplies the size of the output buffer. // // Format - Supplies the format string. // // ArgumentList - Supplies the input parameters. // // Return Value: // // TRUE, if format was successful. // FALSE, otherwise. // //-- { UINT32 CharactersConsumed; UINT32 InputIndex; UINT32 OutputIndex; CHAR PadCharacter; UINT8 TokenType; INT32 Width; InputIndex = 0; OutputIndex = 0; for (;;) { if (OutputIndex == OutputSize) { return FALSE; } if (Format[InputIndex] == 0) { Output[OutputIndex] = 0; return TRUE; } if (Format[InputIndex] == '\\') { switch (Format[InputIndex + 1]) { case '\\': { Output[OutputIndex] = '\\'; OutputIndex += 1; break; } case 'r': { Output[OutputIndex] = '\r'; OutputIndex += 1; break; } case 'n': { Output[OutputIndex] = '\r'; OutputIndex += 1; break; } default: { return FALSE; } } InputIndex += 2; continue; } if (BlRtlParseTypeSpecifier(&Format[InputIndex], &Width, &PadCharacter, &TokenType, &CharactersConsumed) != FALSE) { InputIndex += CharactersConsumed; switch (TokenType) { case STRING_TOKEN_LONG: { if (BlRtlFormatSignedDecimalLong(&Output[OutputIndex], OutputSize - OutputIndex, va_arg(ArgumentList, INT32), Width, &CharactersConsumed) == FALSE) { return FALSE; } OutputIndex += CharactersConsumed; break; } case STRING_TOKEN_ULONG: { if (BlRtlFormatUnsignedLong(&Output[OutputIndex], OutputSize - OutputIndex, va_arg(ArgumentList, UINT32), PadCharacter, Width, 10, &CharactersConsumed) == FALSE) { return FALSE; } OutputIndex += CharactersConsumed; break; } case STRING_TOKEN_ULONG_HEX: { if (BlRtlFormatUnsignedLong(&Output[OutputIndex], OutputSize - OutputIndex, va_arg(ArgumentList, UINT32), PadCharacter, Width, 16, &CharactersConsumed) == FALSE) { return FALSE; } OutputIndex += CharactersConsumed; break; } case STRING_TOKEN_ULONGLONG: { if (BlRtlFormatUnsignedLongLong(&Output[OutputIndex], OutputSize - OutputIndex, va_arg(ArgumentList, UINT64), PadCharacter, Width, 10, &CharactersConsumed) == FALSE) { return FALSE; } OutputIndex += CharactersConsumed; break; } case STRING_TOKEN_ULONGLONG_HEX: { if (BlRtlFormatUnsignedLongLong(&Output[OutputIndex], OutputSize - OutputIndex, va_arg(ArgumentList, UINT64), PadCharacter, Width, 16, &CharactersConsumed) == FALSE) { return FALSE; } OutputIndex += CharactersConsumed; break; } case STRING_TOKEN_PVOID: { #if defined(BOOT_X86) if (BlRtlFormatUnsignedLong(&Output[OutputIndex], OutputSize - OutputIndex, va_arg(ArgumentList, UINT32), '0', 8, 16, &CharactersConsumed) == FALSE) { return FALSE; } #elif defined(BOOT_X64) if (BlRtlFormatUnsignedLongLong(&Output[OutputIndex], OutputSize - OutputIndex, va_arg(ArgumentList, UINT64), '0', 16, 16, &CharactersConsumed) == FALSE) { return FALSE; } #endif OutputIndex += CharactersConsumed; break; } case STRING_TOKEN_PCHAR: { if (BlRtlFormatStringToken(&Output[OutputIndex], OutputSize - OutputIndex, va_arg(ArgumentList, PCHAR), Width, &CharactersConsumed) == FALSE) { return FALSE; } OutputIndex += CharactersConsumed; break; } case STRING_TOKEN_CHAR: { if (BlRtlFormatChar(&Output[OutputIndex], OutputSize - OutputIndex, va_arg(ArgumentList, CHAR), &CharactersConsumed) == FALSE) { return FALSE; } OutputIndex += CharactersConsumed; break; } } continue; } Output[OutputIndex] = Format[InputIndex]; InputIndex += 1; OutputIndex += 1; } } BOOLEAN BlRtlPrintf( PCSTR Format, ... ) //++ // // Routine Description: // // This function implements C-style printf for the boot loader environment. // // Arguments: // // Format - Supplies the format string. // // ... - Supplies the input parameters. // // Return Value: // // TRUE, if operation was successful. // FALSE, otherwise. // //-- { va_list ArgumentList; CHAR Buffer[4096]; va_start(ArgumentList, Format); if (BlRtlFormatString(Buffer, sizeof(Buffer), Format, ArgumentList) == FALSE) { return FALSE; } BlVideoPrintString(Buffer); BlKdPrintString(Buffer); return TRUE; } BOOLEAN BlRtlEqualStringN( PCSTR String1, PCSTR String2, UINT32 Count ) //++ // // Routine Description: // // This function compares two strings. // // Arguments: // // String1 - Supplies a pointer to the first string. // // String2 - Supplies a pointer to the second string. // // Count - Number of characters to compare. // // Return Value: // // TRUE, if strings are equal. // FALSE, otherwise. // //-- { while (Count > 0) { if ((*String1 == 0) || (*String2 == 0)) { return FALSE; } if (*String1 != *String2) { return FALSE; } String1 += 1; String2 += 1; Count -= 1; } return TRUE; } BOOLEAN BlRtlEqualStringI( PCSTR String1, PCSTR String2 ) //++ // // Routine Description: // // This function compares two strings ignoring case differences. // // Arguments: // // String1 - Supplies a pointer to the first string. // // String2 - Supplies a pointer to the second string. // // Return Value: // // TRUE, if strings are equal. // FALSE, otherwise. // //-- { for (;;) { if (BlRtlConvertCharacterToUpperCase(*String1) != BlRtlConvertCharacterToUpperCase(*String2)) { return FALSE; } if (*String1 == 0) { return TRUE; } String1 += 1; String2 += 1; } } PCSTR BlRtlFindSubstring( PCSTR String, PCSTR Substring ) //++ // // Routine Description: // // This function searches for a substring. // // Arguments: // // String - Supplies a pointer to the string to search in. // // Substring - Supplies a pointer to the substring to search for. // // Return Value: // // A pointer to the first instance of the substring, if search was successful. // NULL, otherwise. // //-- { UINT32 SubstringLength; SubstringLength = BlRtlStringLength(Substring); while (*String != 0) { if (BlRtlEqualStringN(String, Substring, SubstringLength) != FALSE) { return String; } String += 1; } return NULL; } ================================================ FILE: ironclad-apps/src/Checked/BootLoader/SingLdrPc/bltrap.cpp ================================================ //++ // // Copyright (c) Microsoft Corporation // // Module Name: // // bltrap.cpp // // Abstract: // // This module implements trap capture. // //-- #include "bl.h" IDTR BlIdtr; IDTE BlIdt[32]; VOID BlTrapEnable( VOID ) //++ // { for (UINT32 i = 0; i < ARRAY_SIZE(BlIdt); i++) { UINT64 Enter = ((UINT64)BlTrapEnter) + i * 8; BlIdt[i].Offset0To15 =(UINT16)((Enter >> 0) & 0xffff); BlIdt[i].Offset16To31 = (UINT16)((Enter >> 16) & 0xffff); #if defined(BOOT_X64) BlIdt[i].Selector = LM_CODE_SELECTOR; #else BlIdt[i].Selector = PM_CODE_SELECTOR; #endif BlIdt[i].Flags = 0; BlIdt[i].Access = 0x8e; #if defined(BOOT_X64) BlIdt[i].Offset32To63 = (UINT32)((Enter >> 32) & 0xffffffff); #endif } BlIdtr.Limit = 32 * 8; BlIdtr.Base = (UINT64)BlIdt; BlTrapSetIdtr(&BlIdtr); } VOID BlTrapFatal( ULONG_PTR Trap, PBL_TRAP_CONTEXT Context ) //++ // // Routine Description: // // This function returns the specified memory type string. // // Arguments: // // Type - Supplies the memory type. // //-- { BlVideoPrintf("\n*** Fatal Trap: 0x%2x:%p [err=%p]\n", Trap, Context, Context->Err); #if defined(BOOT_X86) BlVideoPrintf(" eip=%p efl=%p cr2=%p cs=%2x num=%02x\n", Context->Eip, Context->Efl, Context->Cr2, (UINT32)Context->Cs0, (UINT32)Context->Num); BlVideoPrintf(" eax=%p ebx=%p ecx=%p edx=%p\n", Context->Eax, Context->Ebx, Context->Ecx, Context->Edx); BlVideoPrintf(" esp=%p ebp=%p esi=%p edi=%p\n", Context->Esp, Context->Ebp, Context->Esi, Context->Edi); ULONG_PTR * ebp = (ULONG_PTR *)Context->Ebp; BlVideoPrintf("\n"); BlVideoPrintf(" Frame: next return arg0 arg1 arg2 arg3\n"); for (int i = 0; i < 10; i++) { if (ebp < (ULONG_PTR*)0x10000 || ebp > (ULONG_PTR*)0x7fffffff) { BlVideoPrintf(" %8x:\n", (ULONG_PTR)ebp); break; } ULONG_PTR *end = (ULONG_PTR *)ebp[0]; if (end < ebp) { end = ebp + 6; } BlVideoPrintf(" %p: %p %p", (ULONG_PTR)ebp, ebp[0], ebp[1]); for (int i = 2; i < 6 && ebp + i < end; i++) { BlVideoPrintf(" %p", ebp[i]); } BlVideoPrintf("\n"); ebp = (ULONG_PTR *)ebp[0]; } BlVideoPrintf("\n"); ULONG_PTR * esp = (ULONG_PTR *)(Context->Esp); for (int i = 0; i < 6; i++) { BlVideoPrintf(" %p: %p %p %p %p\n", esp, esp[0], esp[1], esp[2], esp[3]); esp += 4; } BlVideoPrintf("\n"); esp = (ULONG_PTR *)(Context); for (int i = 0; i < 6; i++) { BlVideoPrintf(" %p: %p %p %p\n", esp, esp[0], esp[1], esp[2], esp[3]); esp += 4; } BlVideoPrintf("\n"); UINT8 * eip = (UINT8 *)Context->Eip; BlVideoPrintf(" %p:", eip); for (int i = 0; i < 12; i++) { BlVideoPrintf(" %02x", eip[i]); } BlVideoPrintf("\n"); #elif defined(BOOT_X64) BlVideoPrintf(" rip=%p rfl=%p cs=%2x num=%02x\n", Context->Rip, Context->Rfl, (UINT32)Context->Cs0, (UINT32)Context->Num); BlVideoPrintf(" rsp=%p rbp=%p cr2=%p\n", Context->Rsp, Context->Rbp, Context->Cr2); BlVideoPrintf(" rax=%p rbx=%p rcx=%p\n", Context->Rax, Context->Rbx, Context->Rcx); BlVideoPrintf(" rdx=%p rsi=%p rdi=%p\n", Context->Rdx, Context->Rsi, Context->Rdi); BlVideoPrintf(" r08=%p r09=%p r10=%p\n", Context->R8, Context->R9, Context->R10); BlVideoPrintf(" r11=%p r12=%p r13=%p\n", Context->R11, Context->R12, Context->R13); BlVideoPrintf(" r14=%p r15=%p\n", Context->R14, Context->R15); ULONG_PTR * rbp = (ULONG_PTR *)Context->Rbp; BlVideoPrintf("\n"); BlVideoPrintf(" Frame: next return arg0\n"); for (int i = 0; i < 10; i++) { if (rbp < (ULONG_PTR*)0x10000 || rbp > (ULONG_PTR*)0x7fffffff) { BlVideoPrintf(" %p:\n", (ULONG_PTR)rbp); break; } ULONG_PTR *end = (ULONG_PTR *)rbp[0]; if (end < rbp) { end = rbp + 3; } BlVideoPrintf(" %p: %p %p", (ULONG_PTR)rbp, rbp[0], rbp[1]); for (int i = 2; i < 3 && rbp + i < end; i++) { BlVideoPrintf(" %p", rbp[i]); } BlVideoPrintf("\n"); rbp = (ULONG_PTR *)rbp[0]; } BlVideoPrintf("\n"); ULONG_PTR * rsp = (ULONG_PTR *)(Context->Rsp); for (int i = 0; i < 6; i++) { BlVideoPrintf(" %p: %p %p %p\n", rsp, rsp[0], rsp[1], rsp[2]); rsp += 3; } BlVideoPrintf("\n"); rsp = (ULONG_PTR *)(Context); for (int i = 0; i < 6; i++) { BlVideoPrintf(" %p: %p %p %p\n", rsp, rsp[0], rsp[1], rsp[2]); rsp += 3; } BlVideoPrintf("\n"); UINT8 * rip = (UINT8 *)Context->Rip; BlVideoPrintf(" %p:", rip); for (int i = 0; i < 12; i++) { BlVideoPrintf(" %02x", rip[i]); } BlVideoPrintf("\n"); #endif for (;;); } ================================================ FILE: ironclad-apps/src/Checked/BootLoader/SingLdrPc/blutil.cpp ================================================ //++ // // Copyright (c) Microsoft Corporation // // Module Name: // // blutil.cpp // // Abstract: // // This module implements utility functions for the boot loader environment. // //-- #include "bl.h" VOID BlReturnToLegacyMode( VOID ); VOID BlRtlInitializeListHead( PLIST_ENTRY Head ) //++ // // Routine Description: // // This function initializes the specified list head. // // Arguments: // // Head - Supplies a pointer to the list head to initialize. // //-- { Head->Flink = Head->Blink = Head; } BOOLEAN BlRtlIsListEmpty( PLIST_ENTRY Head ) //++ // // Routine Description: // // This function checks if the specified list is empty. // // Arguments: // // Head - Supplies a pointer to the list head. // // Return Value: // // TRUE, if the list is empty. // FALSE, otherwise. // //-- { return (BOOLEAN) (Head->Flink == Head); } BOOLEAN BlRtlRemoveEntryList( PLIST_ENTRY Entry ) //++ // // Routine Description: // // This function removes the specified entry from the list. // // Arguments: // // Entry - Supplies a pointer to the entry to remove. // // Return Value: // // TRUE, if this was the last entry in the list. // FALSE, otherwise. // //-- { PLIST_ENTRY Blink; PLIST_ENTRY Flink; Blink = Entry->Blink; Flink = Entry->Flink; BLASSERT(Blink != Entry); BLASSERT(Flink != Entry); Blink->Flink = Flink; Flink->Blink = Blink; return (BOOLEAN) (Flink == Blink); } PLIST_ENTRY BlRtlRemoveHeadList( PLIST_ENTRY Head ) //++ // // Routine Description: // // This function removes an entry from the head of the specified list. // // Arguments: // // Head - Supplies a pointer to the list to remove from. // // Return Value: // // A pointer to the removed entry. // //-- { PLIST_ENTRY Entry; PLIST_ENTRY Flink; BLASSERT(BlRtlIsListEmpty(Head) == FALSE); Entry = Head->Flink; Flink = Entry->Flink; Head->Flink = Flink; Flink->Blink = Head; return Entry; } PLIST_ENTRY BlRtlRemoveTailList( PLIST_ENTRY Head ) //++ // // Routine Description: // // This function removes an entry from the tail of the specified list. // // Arguments: // // Head - Supplies a pointer to the list to remove from. // // Return Value: // // A pointer to the removed entry. // //-- { PLIST_ENTRY Blink; PLIST_ENTRY Entry; BLASSERT(BlRtlIsListEmpty(Head) == FALSE); Entry = Head->Blink; Blink = Entry->Blink; Head->Blink = Blink; Blink->Flink = Head; return Entry; } VOID BlRtlInsertTailList( PLIST_ENTRY Head, PLIST_ENTRY Entry ) //++ // // Routine Description: // // This function inserts the specified entry to the tail of the specified list. // // Arguments: // // Head - Supplies a pointer to the list to insert to. // // Entry - Supplies a pointer to the entry to insert. // //-- { PLIST_ENTRY Blink; Blink = Head->Blink; Entry->Flink = Head; Entry->Blink = Blink; Head->Blink = Entry; Blink->Flink = Entry; } VOID BlRtlInsertHeadList( PLIST_ENTRY Head, PLIST_ENTRY Entry ) //++ // // Routine Description: // // This function inserts the specified entry to the head of the specified list. // // Arguments: // // Head - Supplies a pointer to the list to insert to. // // Entry - Supplies a pointer to the entry to insert. // //-- { PLIST_ENTRY Flink; Flink = Head->Flink; Entry->Flink = Flink; Entry->Blink = Head; Head->Flink = Entry; Flink->Blink = Entry; } VOID BlRtlConvertLinearPointerToFarPointer( PVOID LinearPointer, PFAR_POINTER FarPointer ) //++ // // Routine Description: // // This function converts the specified linear pointer to a legacy far pointer. // // Arguments: // // LinearPointer - Supplies the linear pointer to convert. // // FarPointer - Receives the legacy far pointer. // //-- { BLASSERT((ULONG_PTR) LinearPointer < LEGACY_MEMORY_LIMIT); FarPointer->Segment = (UINT16) (((ULONG_PTR) LinearPointer) >> 4); FarPointer->Offset = (((UINT16) (ULONG_PTR) LinearPointer) & 0xF); } PVOID BlRtlConvertFarPointerToLinearPointer( PFAR_POINTER FarPointer ) //++ // // Routine Description: // // This function converts the specified legacy far pointer to a linear pointer. // // Arguments: // // FarPointer - Supplies the legacy far pointer to convert. // // Return Value: // // Linear pointer matching the specified legacy far pointer. // //-- { return (PVOID) (((ULONG_PTR) FarPointer->Segment << 4) + ((ULONG_PTR) FarPointer->Offset)); } VOID BlRtlZeroMemory( PVOID Buffer, ULONG_PTR Length ) //++ // // Routine Description: // // This function zeroes the specified buffer. // // Arguments: // // Buffer - Supplies a pointer to the buffer to zero. // // Length - Supplies the length of the buffer. // //-- { PUINT8 Limit; PUINT8 Next; Next = (PUINT8) Buffer; Limit = Next + Length; while (Next < Limit) { *Next = 0; Next += 1; } } VOID BlRtlCopyMemory( PVOID Destination, PCVOID Source, ULONG_PTR Length ) //++ // // Routine Description: // // This function copies data from the source buffer to the destination buffer. // // Arguments: // // Destination - Receives copied data. // // Source - Supplies data to copy. // // Length - Supplies the length of the data to copy. // //-- { ULONG_PTR DestinationEnd; ULONG_PTR DestinationStart; ULONG_PTR Index; ULONG_PTR SourceEnd; ULONG_PTR SourceStart; if (Length == 0) { return; } SourceStart = (ULONG_PTR) Source; SourceEnd = SourceStart + Length; DestinationStart = (ULONG_PTR) Destination; DestinationEnd = DestinationStart + Length; // // If the higher part of the source buffer intersects with the destination // buffer, then perform a reverse copy. Otherwise, perform a regular copy. // if ((SourceStart < DestinationStart) && (SourceEnd > DestinationStart)) { Index = Length; do { Index -= 1; ((PUINT8) Destination)[Index] = ((PUINT8) Source)[Index]; } while (Index > 0); } else { for (Index = 0; Index < Length; Index += 1) { ((PUINT8) Destination)[Index] = ((PUINT8) Source)[Index]; } } } BOOLEAN BlRtlCompareMemory( PCVOID Buffer1, PCVOID Buffer2, ULONG_PTR Length ) //++ // // Routine Description: // // This function compares the data in the supplied buffers. // // Arguments: // // Buffer1 - Supplies the first buffer. // // Buffer2 - Supplies the second buffer. // // Length - Supplies the number of bytes to compare. // // Return Value: // // TRUE, if buffers contain identical data. // FALSE, otherwise. // //-- { ULONG_PTR Index; for (Index = 0; Index < Length; Index += 1) { if (((PUINT8) Buffer1)[Index] != ((PUINT8) Buffer2)[Index]) { return FALSE; } } return TRUE; } VOID BlRtlMakeLegacyCall( VOID ) //++ // // Routine Description: // // This function switches back to legacy mode, makes the call // specified in the BEB, and returns back to normal mode. // //-- { // // Return to legacy mode. // BlReturnToLegacyMode(); // // Re-enable A20 gate -- this is absolutely necessary, because some // legacy calls (such as some PXE implementations) modify A20 state. // BlMmEnableA20Gate(); } VOID BlRtlCallLegacyInterruptService( UINT8 Vector, PBL_LEGACY_CALL_CONTEXT Input, PBL_LEGACY_CALL_CONTEXT Output ) //++ // // Routine Description: // // This function calls the specified legacy interrupt service. // // Arguments: // // Vector - Supplies the legacy interrupt service vector to call. // // Input - Supplies a pointer to the input context for the call. // // Output - Supplies a pointer to the output context to fill after the call. // //-- { PBEB Beb; Beb = BlGetBeb(); Beb->LegacyCall_OpCode = LC_INTXX; Beb->LegacyCall_Vector = Vector; Beb->LegacyCall_ax = Input->eax; Beb->LegacyCall_bx = Input->ebx; Beb->LegacyCall_cx = Input->ecx; Beb->LegacyCall_dx = Input->edx; Beb->LegacyCall_si = Input->esi; Beb->LegacyCall_di = Input->edi; Beb->LegacyCall_ds = Input->ds; Beb->LegacyCall_es = Input->es; BlRtlMakeLegacyCall(); Output->eax = Beb->LegacyCall_ax; Output->ebx = Beb->LegacyCall_bx; Output->ecx = Beb->LegacyCall_cx; Output->edx = Beb->LegacyCall_dx; Output->esi = Beb->LegacyCall_si; Output->edi = Beb->LegacyCall_di; Output->ds = Beb->LegacyCall_ds; Output->es = Beb->LegacyCall_es; Output->eflags = Beb->LegacyCall_flags; } VOID BlRtlCallLegacyFunction( UINT16 CodeSegment16, UINT16 CodeOffset16, PVOID CallFrame, UINT32 CallFrameSize, PBL_LEGACY_CALL_CONTEXT Input, PBL_LEGACY_CALL_CONTEXT Output ) //++ // // Routine Description: // // This function calls the specified legacy function. // // Arguments: // // CodeSegment16 - Supplies the 16-bit segment value for the function to call. // // CodeOffset16 - Supplies the 16-bit offset value for the function to call. // // CallFrame - Supplies a pointer to the call frame. // // CallFrameSize - Supplies the size of the call frame. // // Input - Supplies the input context for the call. // // Output - Receives the output context after the call. // //-- { PBEB Beb; BLASSERT((ULONG_PTR) CallFrame < LEGACY_MEMORY_LIMIT); BLASSERT(((ULONG_PTR) CallFrame + CallFrameSize) < LEGACY_MEMORY_LIMIT); Beb = BlGetBeb(); Beb->LegacyCall_OpCode = LC_FARCALL; Beb->LegacyCall_FuncPtr.Segment = CodeSegment16; Beb->LegacyCall_FuncPtr.Offset = CodeOffset16; BlRtlConvertLinearPointerToFarPointer(CallFrame, &Beb->LegacyCall_FramePtr); Beb->LegacyCall_FrameSize = CallFrameSize; Beb->LegacyCall_ax = Input->eax; Beb->LegacyCall_bx = Input->ebx; Beb->LegacyCall_cx = Input->ecx; Beb->LegacyCall_dx = Input->edx; Beb->LegacyCall_si = Input->esi; Beb->LegacyCall_di = Input->edi; Beb->LegacyCall_ds = Input->ds; Beb->LegacyCall_es = Input->es; BlRtlMakeLegacyCall(); Output->eax = Beb->LegacyCall_ax; Output->ebx = Beb->LegacyCall_bx; Output->ecx = Beb->LegacyCall_cx; Output->edx = Beb->LegacyCall_dx; Output->esi = Beb->LegacyCall_si; Output->edi = Beb->LegacyCall_di; Output->ds = Beb->LegacyCall_ds; Output->es = Beb->LegacyCall_es; Output->eflags = Beb->LegacyCall_flags; } VOID BlRtlHaltInternal( PCSTR FileName, UINT32 LineNumber ) //++ // // Routine Description: // // This function halts execution. // // Arguments: // // FileName - file associated with call site. // // LineNumber - line associated with call site. // //-- { BlRtlPrintf("BL: Halt! %s(%d)\n", FileName, LineNumber); for (;;) { ; } } VOID BlRtlAssertFailedPtr( PCSTR FileName, UINT32 LineNumber, ULONG_PTR Param ) //++ // // Routine Description: // // This function halts execution. // // Arguments: // // FileName - file associated with call site. // // LineNumber - line associated with call site. // //-- { BlRtlPrintf("BL: Assert failed! %s(%d) (%p)\n", FileName, LineNumber, Param); for (;;) { ; } } VOID BlRtlAssertFailed( PCSTR FileName, UINT32 LineNumber ) //++ // // Routine Description: // // This function halts execution. // // Arguments: // // FileName - file associated with call site. // // LineNumber - line associated with call site. // //-- { BlRtlAssertFailedPtr(FileName, LineNumber, 0); } UINT8 BlRtlComputeChecksum8( PCVOID Buffer, UINT32 Size ) //++ // // Routine Description: // // This function computes the 8-bit checksum of the specified buffer. // // Arguments: // // Buffer - Supplies a pointer to the buffer. // // Size - Supplies the size of the buffer. // // Return Value: // // 8-bit check sum of the specified buffer. // //-- { UINT8 Checksum; UINT32 Index; Checksum = 0; for (Index = 0; Index < Size; Index += 1) { Checksum = Checksum + ((PUINT8) Buffer)[Index]; } return Checksum; } BOOLEAN BlRtlGetDriveParameters( UINT8 DriveId, PINT13_DRIVE_PARAMETERS DriveParameters ) //++ // // Routine Description: // // This function gets the parameters for the specified drive. // // Arguments: // // DriveId - Supplies the ID of the drive to query. // // DriveParameters - Receives drive parameters. // // Return Value: // // TRUE, if query operation was successful. // FALSE, otherwise. // //-- { BL_LEGACY_CALL_CONTEXT Context; FAR_POINTER FarPointer; BlRtlZeroMemory(DriveParameters, sizeof(INT13_DRIVE_PARAMETERS)); DriveParameters->StructureSize = sizeof(INT13_DRIVE_PARAMETERS); BlRtlConvertLinearPointerToFarPointer(DriveParameters, &FarPointer); BlRtlZeroMemory(&Context, sizeof(Context)); Context.eax = 0x4800; Context.edx = DriveId; Context.ds = FarPointer.Segment; Context.esi = FarPointer.Offset; BlRtlCallLegacyInterruptService(0x13, &Context, &Context); if (((Context.eflags & RFLAGS_CF) != 0) || ((Context.eax & 0xFF00) != 0)) { return FALSE; } return TRUE; } #pragma pack(1) typedef struct _INT13_DISK_ADDRESS_PACKET { UINT8 PacketSize; UINT8 Reserved; UINT16 NumberOfBlocks; FAR_POINTER Buffer; UINT64 FirstBlock; } INT13_DISK_ADDRESS_PACKET, *PINT13_DISK_ADDRESS_PACKET; C_ASSERT(sizeof(INT13_DISK_ADDRESS_PACKET) == 0x10); #pragma pack() INT13_DISK_ADDRESS_PACKET BlInt13AddressPacket; BOOLEAN BlRtlReadDrive( UINT8 DriveId, UINT64 FirstBlock, UINT16 NumberOfBlocks, PVOID Buffer ) //++ // // Routine Description: // // This function reads from the specified drive region. // // Arguments: // // DriveId - Supplies the ID of the drive to read from. // // FirstBlock - Supplies the first block to read. // // NumberOfBlocks - Supplies the number of blocks to read. // // Buffer - Receives data. // // Return Value: // // TRUE, if read operation was successful. // FALSE, otherwise. // //-- { FAR_POINTER AddressPacketPointer; BL_LEGACY_CALL_CONTEXT Context; BlRtlZeroMemory(&BlInt13AddressPacket, sizeof(BlInt13AddressPacket)); BlRtlZeroMemory(&Context, sizeof(Context)); BLASSERT(((ULONG_PTR) &BlInt13AddressPacket) < LEGACY_MEMORY_LIMIT); BLASSERT((ULONG_PTR) Buffer < LEGACY_MEMORY_LIMIT); BlInt13AddressPacket.PacketSize = sizeof(BlInt13AddressPacket); BlInt13AddressPacket.FirstBlock = FirstBlock; BlInt13AddressPacket.NumberOfBlocks = NumberOfBlocks; BlRtlConvertLinearPointerToFarPointer(Buffer, &BlInt13AddressPacket.Buffer); BlRtlConvertLinearPointerToFarPointer(&BlInt13AddressPacket, &AddressPacketPointer); Context.eax = 0x4200; Context.edx = DriveId; Context.ds = AddressPacketPointer.Segment; Context.esi = AddressPacketPointer.Offset; BlRtlCallLegacyInterruptService(0x13, &Context, &Context); if (((Context.eflags & RFLAGS_CF) != 0) || ((Context.eax & 0xFF00) != 0)) { return FALSE; } return TRUE; } BOOLEAN (*BlFsGetFileSize)( PCSTR Path, PUINT32 FileSize ); BOOLEAN (*BlFsReadFile)( PCSTR Path, PVOID Buffer, UINT32 NumberOfBytes ); #define CMOS_CONTROL_REGISTER 0x0070 #define CMOS_DATA_REGISTER 0x0071 #define CMOS_SECONDS_REGISTER 0x00 #define CMOS_MINUTES_REGISTER 0x02 #define CMOS_HOURS_REGISTER 0x04 #define CMOS_DAYS_REGISTER 0x07 #define CMOS_MONTHS_REGISTER 0x08 #define CMOS_YEARS_REGISTER 0x09 #define CMOS_STATUS_REGISTER_A 0x0A #define CMOS_STATUS_REGISTER_B 0x0B #define CMOS_SHUTDOWN_REGISTER 0x0F #define CMOS_CLOCK_IN_BINARY 0x04 #define CMOS_ENABLE_PERIODIC_TIMER 0x40 #define CMOS_RATE_MASK 0x0F #define CMOS_DEFAULT_RATE 0x06 UINT8 BlCmosReadRegister( UINT8 Register ) //++ // // Routine Description: // // This function reads from the specified CMOS register. // // Arguments: // // Register - Supplies the CMOS register to read from. // // Return Value: // // Value read from the specified CMOS register. // //-- { BlRtlWritePort8(CMOS_CONTROL_REGISTER, Register); return BlRtlReadPort8(CMOS_DATA_REGISTER); } VOID BlCmosWriteRegister( UINT8 Register, UINT8 Value ) //++ // // Routine Description: // // This function writes to the specified CMOS register. // // Arguments: // // Register - Supplies the CMOS register to write to. // // Value - Supplies the value to write. // //-- { BlRtlWritePort8(CMOS_CONTROL_REGISTER, Register); BlRtlWritePort8(CMOS_DATA_REGISTER, Value); } VOID BlRtlResetSystem( VOID ) //++ // // Routine Description: // // This function resets the system. // //-- { BL_LEGACY_CALL_CONTEXT Context; UINT8 Value; // // Issue a no-op legacy operation to restore legacy context. // BlGetBeb()->LegacyCall_OpCode = LC_NOP; BlRtlMakeLegacyCall(); // // Disable periodic interrupt. // Value = BlCmosReadRegister(CMOS_STATUS_REGISTER_B); Value &= ~CMOS_ENABLE_PERIODIC_TIMER; BlCmosWriteRegister(CMOS_STATUS_REGISTER_B, Value); // // Set default rate. // Value = BlCmosReadRegister(CMOS_STATUS_REGISTER_A); Value &= ~CMOS_RATE_MASK; Value |= CMOS_DEFAULT_RATE; BlCmosWriteRegister(CMOS_STATUS_REGISTER_A, Value); // // Set reset reason. // BlCmosWriteRegister(CMOS_SHUTDOWN_REGISTER, 0); // // Try to reset using ACPI. // BlRtlPrintf("BL: Attempting reset with ACPI.\n"); BlAcpiResetSystem(); // // If the ACPI call returned, then it indicates that ACPI reset is // not supported, so try to reset with the keyboard controller. // BlRtlPrintf("BL: Attempting reset with keyboard controller.\n"); BL_KEYBOARD_WRITE_COMMAND(BL_KEYBOARD_COMMAND_PULSE_RESET_BIT); // // Issue INT19 as last resort. // BlRtlZeroMemory(&Context, sizeof(Context)); BlRtlCallLegacyInterruptService(0x19, &Context, &Context); for (;;) { } } VOID BlRtlShutdownSystem( VOID ) //++ // // Routine Description: // // This function shuts down the system. // //-- { BL_LEGACY_CALL_CONTEXT Context; UINT32 Index; // // AIFIX: Add ACPI shutdown logic here. // BlRtlPrintf("BL: Attempting system shutdown through APM.\n"); // // APM installation check. // #if APM_VERBOSE BlRtlPrintf("APM: INT15/5300h [Installation Check]\n"); #endif BlRtlZeroMemory(&Context, sizeof(Context)); Context.eax = 0x5300; BlRtlCallLegacyInterruptService(0x15, &Context, &Context); if (((Context.eflags & RFLAGS_CF) != 0) || (Context.ebx != 0x504D)) { BlRtlPrintf("APM: Not available!\n"); BlRtlHalt(); } #if APM_VERBOSE BlRtlPrintf("APM: Found APM v%u.%u.\n", (Context.eax >> 8) & 0xFF, Context.eax && 0xFF); #endif // // Connect real-mode interface. // #if APM_VERBOSE BlRtlPrintf("APM: INT15/5301h [Connect Real-Mode Interface]\n"); #endif BlRtlZeroMemory(&Context, sizeof(Context)); Context.eax = 0x5301; BlRtlCallLegacyInterruptService(0x15, &Context, &Context); if ((Context.eflags & RFLAGS_CF) != 0) { BlRtlPrintf("APM: INT15/5301h failed!\n"); BlRtlHalt(); } // // Set APM driver version. // #if APM_VERBOSE BlRtlPrintf("APM: INT15/530Eh [Set APM Driver Version]\n"); #endif BlRtlZeroMemory(&Context, sizeof(Context)); Context.eax = 0x530E; Context.ecx = 0x0102; BlRtlCallLegacyInterruptService(0x15, &Context, &Context); if ((Context.eflags & RFLAGS_CF) != 0) { BlRtlPrintf("APM: INT15/530Eh failed!\n"); BlRtlHalt(); } #if APM_VERBOSE BlRtlPrintf("APM: INT15/5307h [Shutdown]\n"); #endif // // Announce shutdown. // // Note that the lab infrastructure searches for this string // when attempting to determine if the host successfully // reached shutdown. // BlRtlPrintf("APM: Power-off via APM.\n"); // // Issue APM shutdown command. // Context.eax = 0x5307; Context.ebx = 1; Context.ecx = 3; BlRtlCallLegacyInterruptService(0x15, &Context, &Context); for (;;) { } } UINT8 BlRtlConvertBcdToBinary8( UINT8 BcdValue ) //++ // // Routine Description: // // This function converts the specified 8-bit BCD value to binary. // // Arguments: // // BcdValue - Supplies the BCD value to convert. // // Return Value: // // Binary value matching the specified BCD value. // //-- { return (((BcdValue >> 4) & 0xF) * 10) + (BcdValue & 0xF); } VOID BlRtlGetCurrentTime( PBL_TIME Time ) //++ // // Routine Description: // // This function queries the current time. // // Arguments: // // Time - Receives current time. // //-- { // // Query CMOS RTC. // Time->Year = BlCmosReadRegister(CMOS_YEARS_REGISTER); Time->Month = BlCmosReadRegister(CMOS_MONTHS_REGISTER); Time->Day = BlCmosReadRegister(CMOS_DAYS_REGISTER); Time->Hour = BlCmosReadRegister(CMOS_HOURS_REGISTER); Time->Minute = BlCmosReadRegister(CMOS_MINUTES_REGISTER); Time->Second = BlCmosReadRegister(CMOS_SECONDS_REGISTER); // // If the clock is in BCD format, then convert it to binary. // if ((BlCmosReadRegister(CMOS_STATUS_REGISTER_B) & CMOS_CLOCK_IN_BINARY) == 0) { Time->Year = BlRtlConvertBcdToBinary8((UINT8) Time->Year); Time->Month = BlRtlConvertBcdToBinary8(Time->Month); Time->Day = BlRtlConvertBcdToBinary8(Time->Day); Time->Hour = BlRtlConvertBcdToBinary8(Time->Hour); Time->Minute = BlRtlConvertBcdToBinary8(Time->Minute); Time->Second = BlRtlConvertBcdToBinary8(Time->Second); } } ================================================ FILE: ironclad-apps/src/Checked/BootLoader/SingLdrPc/blvesa.cpp ================================================ //++ // // Copyright (c) Microsoft Corporation // // Module Name: // // blvesa.cpp // // Abstract: // // This module implements VESA grahics support for the boot loader. // //-- #include "bl.h" #pragma pack(1) typedef union __declspec(align(16)) _BL_VESA_INFO { struct { UINT8 Signature[4]; UINT16 Version; FAR_POINTER Oem; // LPCHAR UINT8 Capabilities[4]; FAR_POINTER Modes; // LPUSHORT UINT16 Memory; }; UINT8 Raw[1024]; } BL_VESA_INFO, *PBL_VESA_INFO; typedef union __declspec(align(16)) _BL_VESA_MODE { struct { UINT16 Attributes; UINT8 WindowA; UINT8 WindowB; UINT16 Granularity; UINT16 Size; UINT16 WindowASegment; UINT16 WindowBSegment; FAR_POINTER WindowFuncPtr; // LPUCHAR UINT16 BytesPerLine; UINT16 XRes; UINT16 YRes; UINT8 XCharSize; UINT8 YCharSize; UINT8 Planes; UINT8 BitsPerPixel; UINT8 Banks; UINT8 MemoryModel; UINT8 BankSize; UINT8 ImagePages; UINT8 Reserved; UINT8 RedMaskSize; UINT8 RedFieldPos; UINT8 GreenMaskSize; UINT8 GreenFieldPos; UINT8 BlueMaskSize; UINT8 BlueFieldPos; UINT8 ReservedMaskSize; UINT8 ReservedFieldPos; UINT8 DirectColorInfo; // VBE 2.0 UINT32 PhysBasePtr; UINT32 Reserved1; UINT16 Reserved2; }; UINT8 Raw[1024]; } BL_VESA_MODE, *PBL_VESA_MODE; #pragma pack() BL_VESA_INFO BlVesaInfo; BL_VESA_MODE BlVesaMode; ULONG_PTR BlVesaVideoBuffer; UINT32 BlVesaInvoke( UINT32 Ax, UINT32 Bx, UINT32 Cx, PVOID Buffer ) { ULONG_PTR Address; BL_LEGACY_CALL_CONTEXT Context; BlRtlZeroMemory(&Context, sizeof(Context)); Context.eax = Ax; Context.ebx = Bx; Context.ecx = Cx; Address = (ULONG_PTR)Buffer; Context.es = (UINT32)(Address >> 4); Context.edi = (UINT32)(Address & 0xF); BlRtlCallLegacyInterruptService(0x10, &Context, &Context); return Context.eax; } BOOLEAN BlVesaInitialize( VOID ) { UINT32 Returned; PUINT16 ModeList; UINT16 Mode; ULONG_PTR Video; // // Determine if a VESA video card is enabled. // BlRtlZeroMemory(&BlVesaInfo, sizeof(BlVesaInfo)); Returned = BlVesaInvoke(0x4f00, 0, 0, &BlVesaInfo); if (Returned != 0x4f || BlVesaInfo.Signature[0] != 'V' || BlVesaInfo.Signature[1] != 'E' || BlVesaInfo.Signature[2] != 'S' || BlVesaInfo.Signature[3] != 'A' || BlVesaInfo.Version < 0x200) { BlRtlPrintf("VESA: No VESA found.\n"); return FALSE; } // // Print the VESA identification information. // BlRtlPrintf("VESA: %c%c%c%c V%x %s (%d MB)\n", BlVesaInfo.Signature[0], BlVesaInfo.Signature[1], BlVesaInfo.Signature[2], BlVesaInfo.Signature[3], BlVesaInfo.Version, (PCHAR) BlRtlConvertFarPointerToLinearPointer(&BlVesaInfo.Oem), BlVesaInfo.Memory / 16); // // Search list of modes for 1024 x 768 x 16. // ModeList = (PUINT16) BlRtlConvertFarPointerToLinearPointer((PFAR_POINTER) &BlVesaInfo.Modes); for (; *ModeList != 0xffff; ModeList++) { Mode = *ModeList; // // Query for the mode information. // BlRtlZeroMemory(&BlVesaMode, sizeof(BlVesaMode)); Returned = BlVesaInvoke(0x4f01, 0, Mode, &BlVesaMode); if (Returned != 0x4f || BlVesaMode.BitsPerPixel > 8) { BlRtlPrintf("VESA: Mode %03x: Attr=%04x, Addr=%p Res=%dx%dx%d\n", Mode, BlVesaMode.Attributes, (ULONG_PTR)BlVesaMode.PhysBasePtr, BlVesaMode.XRes, BlVesaMode.YRes, BlVesaMode.BitsPerPixel); // // See if one of the modes suport 1024 x 768 x 16 bits. // if (BlVesaMode.XRes == 1024 && BlVesaMode.YRes == 768 && BlVesaMode.BitsPerPixel == 16) { Video = (ULONG_PTR)BlVesaMode.PhysBasePtr; BlRtlZeroMemory(&BlVesaMode, sizeof(BlVesaMode)); if (Mode >= 0x100) { Returned = BlVesaInvoke(0x4f02, 0x4000 | Mode, 0, &BlVesaMode); } else { Returned = BlVesaInvoke(0x4f02, Mode, 0, &BlVesaMode); } if (Returned != 0x4f) { BlRtlPrintf(" Couldn't enable Linear Frame Buffer.\n"); continue; } BlRtlPrintf("VESA: Select 1024 x 768 x 16 @ %p\n", Video); BlVesaVideoBuffer = Video; } } } if (BlVesaVideoBuffer != 0) { PUINT16 Buffer = (PUINT16)BlVesaVideoBuffer; INT32 i = 0; for (; i < 1 * 1024; i++) { Buffer[i] = 0xf800; } for (; i < 2 * 1024; i++) { Buffer[i] = 0x07e0; } for (; i < 3 * 1024; i++) { Buffer[i] = 0x001f; } for (; i < 4 * 1024; i++) { Buffer[i] = 0xffff; } } return FALSE; } ================================================ FILE: ironclad-apps/src/Checked/BootLoader/SingLdrPc/blvideo.cpp ================================================ //++ // // Copyright (c) Microsoft Corporation // // Module Name: // // blvideo.cpp // // Abstract: // // This module implements basic video support for the boot loader. // //-- #include "bl.h" #define BL_VIDEO_ROW_COUNT 50 #define BL_VIDEO_COL_COUNT 80 #define BL_VIDEO_DEFAULT_ATTRIBUTE 0x1F00 #define BL_VIDEO_REGISTER_INDEX_PORT 0x3D4 #define BL_VIDEO_REGISTER_DATA_PORT 0x3D5 #define BL_VIDEO_REGISTER_CURSOR_LOW 0x0F #define BL_VIDEO_REGISTER_CURSOR_HIGH 0x0E #define BL_VIDEO_BASE_ADDRESS ((ULONG_PTR) 0x000B8000) PUINT16 BlVideoBuffer = (PUINT16) BL_VIDEO_BASE_ADDRESS; UINT16 BlVideoCursorPosition; UINT16 BlVideoDefaultAttribute = BL_VIDEO_DEFAULT_ATTRIBUTE; VOID BlVideoSetCursorPosition( UINT16 X, UINT16 Y ) //++ // // Routine Description: // // This function sets the cursor position. // // Arguments: // // X - Supplies the X coordinate for the cursor. // // Y - Supplies the Y coordinate for the cursor. // //-- { BlVideoCursorPosition = (Y * BL_VIDEO_COL_COUNT) + X; BlRtlWritePort8(BL_VIDEO_REGISTER_INDEX_PORT, BL_VIDEO_REGISTER_CURSOR_HIGH); BlRtlWritePort8(BL_VIDEO_REGISTER_DATA_PORT, (UINT8) (BlVideoCursorPosition >> 8)); BlRtlWritePort8(BL_VIDEO_REGISTER_INDEX_PORT, BL_VIDEO_REGISTER_CURSOR_LOW); BlRtlWritePort8(BL_VIDEO_REGISTER_DATA_PORT, (UINT8) (BlVideoCursorPosition & 0xFF)); } VOID BlVideoGetCursorPosition( PUINT16 X, PUINT16 Y ) //++ // // Routine Description: // // This function gets the cursor position. // // Arguments: // // X - Supplies a pointer to the variable that will receive the X coordinate. // // Y - Supplies a pointer to the variable that will receive the Y coordinate. // //-- { *X = BlVideoCursorPosition % BL_VIDEO_COL_COUNT; *Y = BlVideoCursorPosition / BL_VIDEO_COL_COUNT; } VOID BlVideoWriteCurrentCharacter( UINT8 Character ) //++ // // Routine Description: // // This function writes the current character (i.e. the character under the cursor). // // Arguments: // // Character - Supplies the character to write. // //-- { UINT16 X; UINT16 Y; BlVideoGetCursorPosition(&X, &Y); BlVideoBuffer[(Y * BL_VIDEO_COL_COUNT) + X] = BlVideoDefaultAttribute | Character; } VOID BlVideoScrollUpWindow( UINT8 NumberOfLines ) //++ // // Routine Description: // // This function scrolls up the specified window. // // Arguments: // // NumberOfLines - Supplies the number of lines to scroll. // //-- { UINT16 Delta; UINT16 Index; UINT16 Limit; Limit = BL_VIDEO_COL_COUNT * BL_VIDEO_ROW_COUNT; Delta = NumberOfLines * BL_VIDEO_COL_COUNT; if (Delta > Limit) { Delta = Limit; } for (Index = Delta; Index < Limit; Index += 1) { BlVideoBuffer[Index - Delta] = BlVideoBuffer[Index]; } for (Index = Limit - Delta; Index < Limit; Index += 1) { BlVideoBuffer[Index] = BlVideoDefaultAttribute | ' '; } } VOID BlVideoPrintCharacter( UINT8 Character ) //++ // // Routine Description: // // This function prints the specified character and advances the cursor. // // Arguments: // // Character - Supplies the character to print. // //-- { UINT16 X; UINT16 Y; BlVideoGetCursorPosition(&X, &Y); switch (Character) { case '\f': { X = 0; Y = 0; BlVideoInitialize(); break; } case '\r': { X = 0; break; } case '\n': { X = BL_VIDEO_COL_COUNT; break; } default: { BlVideoWriteCurrentCharacter(Character); X += 1; } } if (X == BL_VIDEO_COL_COUNT) { X = 0; Y += 1; } if (Y == BL_VIDEO_ROW_COUNT) { BlVideoScrollUpWindow(1); Y = BL_VIDEO_ROW_COUNT - 1; } BlVideoSetCursorPosition(X, Y); } VOID BlVideoPrintString( PCSTR String ) //++ // // Routine Description: // // This function prints the specified string and advances the cursor. // // Arguments: // // String - Supplies a pointer to the string to print. // //-- { PCSTR Next; Next = String; while (*Next != 0) { BlVideoPrintCharacter(*Next); Next += 1; } } BOOLEAN BlVideoPrintf( PCSTR Format, ... ) //++ // // Routine Description: // // This function prints out a string. // // Arguments: // // Format - Supplies the format string. // // ... - Supplies the input parameters. // // Return Value: // // TRUE, if operation was successful. // FALSE, otherwise. // //-- { va_list ArgumentList; CHAR Buffer[4096]; va_start(ArgumentList, Format); if (BlRtlFormatString(Buffer, sizeof(Buffer), Format, ArgumentList) == FALSE) { return FALSE; } BlVideoPrintString(Buffer); return TRUE; } VOID BlVideoInitialize( VOID ) //++ // // Routine Description: // // This function initializes video support for the boot loader. // //-- { UINT16 Index; UINT16 Limit; Limit = BL_VIDEO_COL_COUNT * BL_VIDEO_ROW_COUNT; for (Index = 0; Index < Limit; Index += 1) { BlVideoBuffer[Index] = BlVideoDefaultAttribute | ' '; } BlVideoSetCursorPosition(0, 0); } ================================================ FILE: ironclad-apps/src/Checked/BootLoader/SingLdrPc/makefile ================================================ BUILD = ..\..\..\..\tools\build AS = $(BUILD)\x86_x86\ml.exe CC = $(BUILD)\x86_x86\cl.exe LINK = $(BUILD)\x86_x86\link.exe AS16 = $(BUILD)\x86_x86\ml.exe LINK16 = $(BUILD)\x86_x86\link16.exe BLGEN = $(BUILD)\x86_x86\blgen.exe # To generate a small version, use: nmake CCFLAGS=/DSMALL_LOADER CCFLAGS = MIN_OBJS = \ $(OBJ)\x86\blcrtasm.obj \ $(OBJ)\x86\blidt.obj \ $(OBJ)\x86\blioport.obj \ $(OBJ)\x86\bllegacy.obj \ $(OBJ)\x86\blutilasm.obj \ $(OBJ)\blacpi.obj \ $(OBJ)\blcdrom.obj \ $(OBJ)\blcom.obj \ $(OBJ)\blentry.obj \ $(OBJ)\blfat.obj \ $(OBJ)\blflash.obj \ $(OBJ)\blkd.obj \ $(OBJ)\blkd1394.obj \ $(OBJ)\blkdcom.obj \ $(OBJ)\blmm.obj \ $(OBJ)\blmps.obj \ $(OBJ)\blpci.obj \ $(OBJ)\blpecoff.obj \ $(OBJ)\blpnp.obj \ $(OBJ)\blpool.obj \ $(OBJ)\blpxe.obj \ $(OBJ)\blsingularity.obj \ $(OBJ)\blsmap.obj \ $(OBJ)\blstring.obj \ $(OBJ)\bltrap.obj \ $(OBJ)\blutil.obj \ $(OBJ)\blvesa.obj \ $(OBJ)\blvideo.obj \ TPM_OBJS = \ $(OBJ)\tpm\aik.obj \ OBJS = $(MIN_OBJS) $(TPM_OBJS) all: $(OBJ)\x86 $(OBJ)\tpm $(OBJ)\pxe-loader dirs: $(OBJ)\x86 $(OBJ)\tpm pxe-loader: dirs $(OBJ)\pxe-loader $(OBJ)\x86: md $(OBJ)\x86 $(OBJ)\tpm: md $(OBJ)\tpm {x86}.asm{$(OBJ)\x86}.obj: $(AS) /nologo /c /DBOOT_X86 /I. /Fl$*.lst /Fo$*.obj $< {tpm}.cpp{$(OBJ)\tpm}.obj: $(CC) $(CCFLAGS) /nologo /c /DBOOT_X86 /GF /Gy /Gr /Zi /Od /Oy- /GS- /Gs65536 /FAsc /Fa$*.cod /Fo$*.obj /Fd$*.pdb $< .cpp{$(OBJ)}.obj: $(CC) $(CCFLAGS) /nologo /c /DBOOT_X86 /GF /Gy /Gr /Zi /Od /Oy- /GS- /Gs65536 /FAsc /Fa$*.cod /Fo$*.obj /Fd$*.pdb $< $(OBJ)\blentry16.obj: blentry16.asm bl.inc $(AS16) /nologo /DBOOT_X86 /AT /omf /c /I. /Fl$(OBJ)\blentry16.lst /Fo$(OBJ)\blentry16.obj blentry16.asm $(OBJ)\blentry16.com: $(OBJ)\blentry16.obj $(LINK16) /nologo /TINY $(OBJ)\blentry16.obj,$(OBJ)\blentry16.com,$(OBJ)\blentry16.map,,,/ONERROR:NOEXE /NOLOGO $(OBJ)\pxe-bl.exe: $(OBJS) $(LINK) /nologo /debug /out:$(OBJ)\pxe-bl.exe /pdb:$(OBJ)\pxe-bl.pdb $(OBJS) /nodefaultlib /entry:BlEntry /subsystem:native /base:0x40000 /fixed /ignore:4078 /ignore:4254 /merge:.rdata=.data /merge:.data=.text $(OBJ)\pxe-blentry16.com: $(OBJ)\blentry16.obj $(LINK16) /nologo /TINY $(OBJ)\blentry16.obj,$(OBJ)\pxe-blentry16.com,$(OBJ)\pxe-blentry16.map,,,/ONERROR:NOEXE /NOLOGO $(OBJ)\pxe-loader: $(OBJ)\pxe-bl.exe $(OBJ)\pxe-blentry16.com $(BLGEN) $(OBJ)\pxe-blentry16.com $(OBJ)\pxe-bl.exe $(OBJ)\pxe-loader clean-obj: cd $(OBJ) del *.com *.map *.lst *.obj *.cod *.pdb *.exe cd x86 del *.lst *.obj clean: cd $(OBJ) del *.com *.map *.lst *.obj *.cod *.pdb *.exe loader pxe-loader cd x86 del *.lst *.obj ================================================ FILE: ironclad-apps/src/Checked/BootLoader/SingLdrPc/platform.h ================================================ typedef __int64 Gdte; typedef unsigned char byte; typedef unsigned short ushort; typedef unsigned uint; typedef unsigned __int64 ulong; typedef ULONG_PTR UIntPtr; const int Class_Microsoft_Singularity_Hal_Platform_EXIT_AND_RESTART = 0x1fff; const int Class_Microsoft_Singularity_Hal_Platform_EXIT_AND_SHUTDOWN = 0x1ffe; const int Class_Microsoft_Singularity_Hal_Platform_EXIT_AND_WARMBOOT = 0x1ffd; const int Class_Microsoft_Singularity_Hal_Platform_EXIT_AND_HALT = 0x1ffc; const int Class_Microsoft_Singularity_Hal_Platform_DEBUGGER_NONE = 0; const int Class_Microsoft_Singularity_Hal_Platform_DEBUGGER_SERIAL = 1; const int Class_Microsoft_Singularity_Hal_Platform_DEBUGGER_1394 = 2; struct Class_Microsoft_Singularity_MpBootInfo { uint signature; UIntPtr KernelStackBegin; UIntPtr KernelStack; UIntPtr KernelStackLimit; volatile int TargetCpu; }; struct Struct_Microsoft_Singularity_Isal_IX_DescriptorTable_Gdt { Gdte nul; // Null segment Gdte pv; // 16-bit video, used in boot loader only Gdte rc; // 16-bit code, used to align with RM code in boot loader Gdte rd; // 16-bit data, used to align with RM data in boot loader Gdte pc; // 32-bit code Gdte pd; // 32-bit data Gdte lc; // 64-bit code Gdte ld; // 64-bit data Gdte uc; // User mode code - used in paging mode only Gdte ud; // User mode data - used in paging mode only Gdte pp; // Kernel mode per-processor data Gdte nn; // Unused Gdte tss; // Currently executing task segment }; struct Struct_Microsoft_Singularity_Isal_IX_Gdtp { ushort pad; ushort limit; uint addr; }; struct Struct_Microsoft_Singularity_Isal_IX_DescriptorTable { Struct_Microsoft_Singularity_Isal_IX_DescriptorTable_Gdt gdt; Struct_Microsoft_Singularity_Isal_IX_Gdtp gdtPtr; }; struct Class_Microsoft_Singularity_Hal_Cpu { int Size; int Id; UIntPtr CpuRecordPage; UIntPtr KernelStackLimit; // lower bounds of stack UIntPtr KernelStackBegin; // upper bounds of stack int DomainBsp; Struct_Microsoft_Singularity_Isal_IX_DescriptorTable segments; bool halted; }; struct Class_Microsoft_Singularity_Hal_Platform { // Size of instance; this is a versioning/consistency check int Size; uint BootYear; uint BootMonth; uint BootDay; uint BootHour; uint BootMinute; uint BootSecond; int CpuMaxCount; int CpuRealCount; int BootCount; UIntPtr Smap32; int SmapCount; UIntPtr PhysicalBase; uint*OutgoingMessage; int* OutgoingCount; uint*IncomingFree; //previously sent messages that cane be safely freed int* IncomingFreeCount; uint*IncomingMessage; //messages bound for this kernel int* IncomingCount; uint*OutgoingFree; // messages that this kernel has processed int* OutgoingFreeCount; uint MaxBufferLength; uint thisDestinationId; uint hasApic; UIntPtr BootAllocatedMemory; UIntPtr BootAllocatedMemorySize; UIntPtr CommandLine32; int CommandLineCount; int CpuRecordPointerOffset; int ThreadRecordPointerOffset; UIntPtr LogRecordBuffer; UIntPtr LogRecordSize; UIntPtr LogTextBuffer; UIntPtr LogTextSize; UIntPtr KernelDllBase; UIntPtr KernelDllSize; UIntPtr KernelDllFirstPage; // first page may be disjoint on CE UIntPtr MiniDumpBase; UIntPtr MiniDumpLimit; int DebuggerType; // protected Cpu bootCpu; uint RecSize; ushort DebugBasePort; ushort DebugSpinBase; uint TwiddleSpinBase; ulong Info32; ulong Kill32; uint KillAction; ulong DumpAddr32; ulong FileImageTableBase32; uint FileImageTableEntries; uint DumpSize32; ulong DumpRemainder; ulong DumpLimit; ulong NativeContext; ulong Cpus; ushort BiosPicMask; byte BiosWarmResetCmos; uint BiosWarmResetVector; uint Info16; ulong IdtEnter0; ulong IdtEnter1; ulong IdtEnterN; ulong IdtTarget; ulong Pdpt32; ulong KernelPdpt64; ulong Undump; uint PciBiosAX; uint PciBiosBX; uint PciBiosCX; uint PciBiosEDX; ulong AcpiRoot32; ulong PnpNodesAddr32; uint PnpNodesSize32; ulong SmbiosRoot32; ulong DmiRoot32; uint IsaCsns; ushort IsaReadPort; uint Ebda32; uint MpFloat32; ulong Ohci1394Base; ulong Ohci1394BufferAddr32; uint Ohci1394BufferSize32; ulong VesaBuffer; ulong MpEnter32; // Entry point uint MpCpuCount; // No of AP's booted uint MpStatus32; // Error indicator ulong MpStartupLock32; // Pointer to MP init lock var Class_Microsoft_Singularity_MpBootInfo MpBootInfo; // private Cpu[] processors; // private HalDevices devices; }; struct Struct_Microsoft_Singularity_Io_FileImage { UIntPtr Address; uint Size; }; struct Struct_Microsoft_Singularity_Isal_IX_TSS { ushort previous_tss; ushort pad0; uint esp0; ushort ss0; ushort pad1; uint esp1; ushort ss1; ushort pad2; uint esp2; ushort ss2; ushort pad3; uint cr3; uint eip; uint eflags; uint eax; uint ecx; uint edx; uint ebx; uint esp; uint ebp; uint esi; uint edi; ushort es; ushort pades; ushort cs; ushort padcs; ushort ss; ushort padss; ushort ds; ushort padds; ushort fs; ushort padfs; ushort gs; ushort padgs; ushort ldt; ushort padldt; ushort trap_bit; ushort io_bitmap_offset; }; ================================================ FILE: ironclad-apps/src/Checked/BootLoader/SingLdrPc/tpm/aik.cpp ================================================ char aik[559] = { 0x00, 0x28, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x86, 0x4e, 0x0d, 0x6b, 0x86, 0xf5, 0x4f, 0xbf, 0xb0, 0x78, 0x74, 0x51, 0x7a, 0x44, 0x31, 0xab, 0xe1, 0xb6, 0x01, 0x01, 0x9b, 0x26, 0x5f, 0x31, 0x24, 0x87, 0x2e, 0xb1, 0xf0, 0xff, 0x02, 0xc0, 0x11, 0x14, 0xc4, 0x7f, 0xd8, 0x9c, 0xbe, 0xae, 0xa4, 0x6d, 0x28, 0x29, 0x9c, 0xfa, 0x6b, 0x50, 0xce, 0x03, 0x67, 0x12, 0x6a, 0xc7, 0xc2, 0x77, 0xaa, 0x8d, 0x54, 0x90, 0x21, 0x99, 0x58, 0xd8, 0xbc, 0x74, 0x16, 0x82, 0x30, 0x57, 0xca, 0xa5, 0xe0, 0xcc, 0x51, 0xe9, 0xc6, 0xf3, 0x9b, 0xef, 0xe1, 0xa6, 0xe6, 0x5c, 0x37, 0x4d, 0x35, 0xb4, 0x03, 0x1d, 0x25, 0x46, 0x61, 0x64, 0xe6, 0x1f, 0x00, 0x41, 0xf5, 0xd9, 0xf8, 0x4e, 0xb1, 0x3f, 0x8f, 0xfc, 0xe2, 0x2f, 0xf3, 0x08, 0xac, 0x52, 0x1f, 0xcd, 0x76, 0xa5, 0xeb, 0xcc, 0x24, 0x9f, 0xb7, 0x8e, 0xa2, 0x97, 0x56, 0x24, 0xf4, 0x98, 0x76, 0x45, 0x90, 0x97, 0xc6, 0xf4, 0x56, 0xf9, 0xa0, 0xf4, 0x8e, 0x24, 0x95, 0x92, 0x0a, 0x1a, 0xdc, 0x58, 0x6c, 0x3c, 0x18, 0xd1, 0x30, 0xe2, 0x1d, 0xa4, 0xaa, 0xa5, 0x72, 0x92, 0xd0, 0xf6, 0x31, 0xa9, 0xa3, 0x7b, 0xdf, 0x9c, 0x97, 0x59, 0xfe, 0x48, 0x0e, 0x03, 0xde, 0xa1, 0xee, 0xc5, 0xfe, 0xfa, 0xf0, 0xda, 0x54, 0x17, 0x39, 0x0c, 0xce, 0x34, 0x17, 0xb2, 0x9f, 0x20, 0xcc, 0x32, 0x98, 0xb2, 0x18, 0xb0, 0x34, 0x66, 0x9e, 0x3f, 0x24, 0x3f, 0xdf, 0x8b, 0x97, 0xeb, 0x33, 0xe3, 0x23, 0x49, 0x8d, 0xdf, 0x25, 0x59, 0xe7, 0xff, 0xc2, 0xd3, 0x79, 0x05, 0xa0, 0xf8, 0x76, 0x42, 0x15, 0x00, 0xa0, 0xa8, 0x3b, 0x7d, 0x08, 0x44, 0xca, 0xb8, 0x19, 0xf6, 0xb8, 0x18, 0x96, 0xb5, 0x62, 0x8c, 0x5a, 0xc7, 0xdb, 0x75, 0x6c, 0x1f, 0x9f, 0x1c, 0xaf, 0xaf, 0x19, 0xce, 0x7e, 0xe1, 0x00, 0x00, 0x01, 0x00, 0x7e, 0xb1, 0x4e, 0xfe, 0x73, 0xb8, 0xe1, 0x92, 0xda, 0x68, 0xae, 0x71, 0xb7, 0xd1, 0x45, 0x68, 0x29, 0x38, 0xc0, 0xbc, 0x21, 0xd5, 0xbb, 0xb7, 0xb7, 0x23, 0x35, 0xce, 0xf5, 0xc3, 0x79, 0xf8, 0x5e, 0x63, 0x20, 0x73, 0x30, 0x72, 0xd5, 0xf0, 0x66, 0xd4, 0x24, 0x8c, 0x73, 0xef, 0xcf, 0xa7, 0xb1, 0xc2, 0x54, 0xd5, 0x8c, 0xb8, 0x0f, 0xa2, 0xf6, 0xb3, 0xbc, 0x88, 0xb4, 0x58, 0x75, 0xaf, 0x50, 0x0f, 0xc4, 0x2b, 0x96, 0x9a, 0x0e, 0xee, 0xe1, 0xa8, 0x43, 0xa3, 0x47, 0x89, 0x4a, 0xc6, 0x52, 0x11, 0xc2, 0x63, 0x7d, 0xb4, 0xf3, 0x91, 0xe3, 0x62, 0x6e, 0x35, 0xfc, 0x1f, 0x7e, 0xc7, 0x7c, 0xfd, 0x13, 0x20, 0xc5, 0x44, 0xf4, 0x1e, 0x07, 0x28, 0xa9, 0xd4, 0x7f, 0x49, 0x34, 0xf6, 0x41, 0x9c, 0xa8, 0xf8, 0x0f, 0xd8, 0x07, 0x5b, 0x52, 0x85, 0x22, 0xc3, 0x42, 0x18, 0x1d, 0x6a, 0xf0, 0x23, 0x05, 0xf0, 0x0d, 0x3f, 0x38, 0xa4, 0x96, 0x50, 0xac, 0xd5, 0x40, 0xb3, 0x49, 0x8d, 0x61, 0x2c, 0xe1, 0xd9, 0xf2, 0xca, 0x99, 0x28, 0x93, 0xca, 0x87, 0xc5, 0xdd, 0x79, 0x91, 0xbb, 0xac, 0xf0, 0x2e, 0x2a, 0x01, 0x61, 0x41, 0x40, 0x1f, 0x4f, 0x1a, 0xf7, 0x32, 0x96, 0x83, 0x08, 0x2a, 0x64, 0xf1, 0x7e, 0x72, 0x5c, 0xfb, 0xa0, 0xfa, 0x84, 0x40, 0x90, 0x59, 0xd9, 0xeb, 0x00, 0x21, 0xf9, 0xa3, 0xc7, 0x12, 0x87, 0xc5, 0xa4, 0xbf, 0xb3, 0x0f, 0x4c, 0xde, 0xc1, 0x87, 0xe6, 0xff, 0x28, 0xff, 0xa4, 0xea, 0x9b, 0x86, 0x4d, 0x31, 0x16, 0xab, 0x34, 0x5c, 0x3b, 0x05, 0x45, 0xf7, 0x06, 0x60, 0xc9, 0xaa, 0x38, 0x66, 0xb1, 0x81, 0x76, 0x3f, 0xe4, 0x22, 0x45, 0x3a, 0x9e, 0x45, 0xf0, 0xbc, 0xa6, 0x8a, 0xf8, 0x58, 0xbe, 0xc3, 0xa5, 0x9b, 0x1f, 0x2b, 0x68, 0xe2, 0xfe, }; ================================================ FILE: ironclad-apps/src/Checked/BootLoader/SingLdrPc/tpm/aik.h ================================================ #pragma once extern char aik[559]; ================================================ FILE: ironclad-apps/src/Checked/BootLoader/SingLdrPc/x86/blcrtasm.asm ================================================ ;++ ; ; Copyright (c) Microsoft Corporation ; ; Module Name: ; ; blcrt.asm ; ; Abstract: ; ; This module implements utility functions for boot loader C runtime. ; ; Environment: ; ; Boot loader. ; ;-- include bl.inc .686p .model flat .code assume ds:flat assume es:flat assume ss:flat assume fs:flat LOWORD equ [0] HIWORD equ [4] ;*** ;lldiv.asm - signed long divide routine ; ; Copyright (c) Microsoft Corporation. All rights reserved. ; ;Purpose: ; defines the signed long divide routine ; __alldiv ; ;Revision History: ; 11-29-83 DFW initial version ; 06-01-84 RN modified to use cmacros ; 10-24-87 SKS fixed off-by-1 error for dividend close to 2**32. ; 05-18-89 SKS Remove redundant "MOV SP,BP" from epilog ; 11-28-89 GJF Fixed copyright ; 11-19-93 SMK Modified to work on 64 bit integers ; 01-17-94 GJF Minor changes to build with NT's masm386. ; 07-22-94 GJF Use esp-relative addressing for args. Shortened ; conditional jumps. Also, don't use xchg to do a ; simple move between regs. ; ;******************************************************************************* ;*** ;lldiv - signed long divide ; ;Purpose: ; Does a signed long divide of the arguments. Arguments are ; not changed. ; ;Entry: ; Arguments are passed on the stack: ; 1st pushed: divisor (QWORD) ; 2nd pushed: dividend (QWORD) ; ;Exit: ; EDX:EAX contains the quotient (dividend/divisor) ; NOTE: this routine removes the parameters from the stack. ; ;Uses: ; ECX ; ;Exceptions: ; ;******************************************************************************* __alldiv PROC NEAR push edi push esi push ebx ; Set up the local stack and save the index registers. When this is done ; the stack frame will look as follows (assuming that the expression a/b will ; generate a call to lldiv(a, b)): ; ; ----------------- ; | | ; |---------------| ; | | ; |--divisor (b)--| ; | | ; |---------------| ; | | ; |--dividend (a)-| ; | | ; |---------------| ; | return addr** | ; |---------------| ; | EDI | ; |---------------| ; | ESI | ; |---------------| ; ESP---->| EBX | ; ----------------- ; DVND equ [esp + 16] ; stack address of dividend (a) DVSR equ [esp + 24] ; stack address of divisor (b) ; Determine sign of the result (edi = 0 if result is positive, non-zero ; otherwise) and make operands positive. xor edi,edi ; result sign assumed positive mov eax,HIWORD(DVND) ; hi word of a or eax,eax ; test to see if signed jge short L1 ; skip rest if a is already positive inc edi ; complement result sign flag mov edx,LOWORD(DVND) ; lo word of a neg eax ; make a positive neg edx sbb eax,0 mov HIWORD(DVND),eax ; save positive value mov LOWORD(DVND),edx L1: mov eax,HIWORD(DVSR) ; hi word of b or eax,eax ; test to see if signed jge short L2 ; skip rest if b is already positive inc edi ; complement the result sign flag mov edx,LOWORD(DVSR) ; lo word of a neg eax ; make b positive neg edx sbb eax,0 mov HIWORD(DVSR),eax ; save positive value mov LOWORD(DVSR),edx L2: ; ; Now do the divide. First look to see if the divisor is less than 4194304K. ; If so, then we can use a simple algorithm with word divides, otherwise ; things get a little more complex. ; ; NOTE - eax currently contains the high order word of DVSR ; or eax,eax ; check to see if divisor < 4194304K jnz short L3 ; nope, gotta do this the hard way mov ecx,LOWORD(DVSR) ; load divisor mov eax,HIWORD(DVND) ; load high word of dividend xor edx,edx div ecx ; eax <- high order bits of quotient mov ebx,eax ; save high bits of quotient mov eax,LOWORD(DVND) ; edx:eax <- remainder:lo word of dividend div ecx ; eax <- low order bits of quotient mov edx,ebx ; edx:eax <- quotient jmp short L4 ; set sign, restore stack and return ; ; Here we do it the hard way. Remember, eax contains the high word of DVSR ; L3: mov ebx,eax ; ebx:ecx <- divisor mov ecx,LOWORD(DVSR) mov edx,HIWORD(DVND) ; edx:eax <- dividend mov eax,LOWORD(DVND) L5: shr ebx,1 ; shift divisor right one bit rcr ecx,1 shr edx,1 ; shift dividend right one bit rcr eax,1 or ebx,ebx jnz short L5 ; loop until divisor < 4194304K div ecx ; now divide, ignore remainder mov esi,eax ; save quotient ; ; We may be off by one, so to check, we will multiply the quotient ; by the divisor and check the result against the orignal dividend ; Note that we must also check for overflow, which can occur if the ; dividend is close to 2**64 and the quotient is off by 1. ; mul dword ptr HIWORD(DVSR) ; QUOT * HIWORD(DVSR) mov ecx,eax mov eax,LOWORD(DVSR) mul esi ; QUOT * LOWORD(DVSR) add edx,ecx ; EDX:EAX = QUOT * DVSR jc short L6 ; carry means Quotient is off by 1 ; ; do long compare here between original dividend and the result of the ; multiply in edx:eax. If original is larger or equal, we are ok, otherwise ; subtract one (1) from the quotient. ; cmp edx,HIWORD(DVND) ; compare hi words of result and original ja short L6 ; if result > original, do subtract jb short L7 ; if result < original, we are ok cmp eax,LOWORD(DVND) ; hi words are equal, compare lo words jbe short L7 ; if less or equal we are ok, else subtract L6: dec esi ; subtract 1 from quotient L7: xor edx,edx ; edx:eax <- quotient mov eax,esi ; ; Just the cleanup left to do. edx:eax contains the quotient. Set the sign ; according to the save value, cleanup the stack, and return. ; L4: dec edi ; check to see if result is negative jnz short L8 ; if EDI == 0, result should be negative neg edx ; otherwise, negate the result neg eax sbb edx,0 ; ; Restore the saved registers and return. ; L8: pop ebx pop esi pop edi ret 16 __alldiv ENDP ;*** ;lldvrm.asm - signed long divide and remainder routine ; ; Copyright (c) Microsoft Corporation. All rights reserved. ; ;Purpose: ; defines the signed long divide and remainder routine ; __alldvrm ; ;Revision History: ; 10-06-98 SMK Initial version. ; ;******************************************************************************* ;*** ;lldvrm - signed long divide and remainder ; ;Purpose: ; Does a signed long divide and remainder of the arguments. Arguments are ; not changed. ; ;Entry: ; Arguments are passed on the stack: ; 1st pushed: divisor (QWORD) ; 2nd pushed: dividend (QWORD) ; ;Exit: ; EDX:EAX contains the quotient (dividend/divisor) ; EBX:ECX contains the remainder (divided % divisor) ; NOTE: this routine removes the parameters from the stack. ; ;Uses: ; ECX ; ;Exceptions: ; ;******************************************************************************* __alldvrm PROC NEAR push edi push esi push ebp ; Set up the local stack and save the index registers. When this is done ; the stack frame will look as follows (assuming that the expression a/b will ; generate a call to alldvrm(a, b)): ; ; ----------------- ; | | ; |---------------| ; | | ; |--divisor (b)--| ; | | ; |---------------| ; | | ; |--dividend (a)-| ; | | ; |---------------| ; | return addr** | ; |---------------| ; | EDI | ; |---------------| ; | ESI | ; |---------------| ; ESP---->| EBP | ; ----------------- ; DVND equ [esp + 16] ; stack address of dividend (a) DVSR equ [esp + 24] ; stack address of divisor (b) ; Determine sign of the quotient (edi = 0 if result is positive, non-zero ; otherwise) and make operands positive. ; Sign of the remainder is kept in ebp. xor edi,edi ; result sign assumed positive xor ebp,ebp ; result sign assumed positive mov eax,HIWORD(DVND) ; hi word of a or eax,eax ; test to see if signed jge short L1 ; skip rest if a is already positive inc edi ; complement result sign flag inc ebp ; complement result sign flag mov edx,LOWORD(DVND) ; lo word of a neg eax ; make a positive neg edx sbb eax,0 mov HIWORD(DVND),eax ; save positive value mov LOWORD(DVND),edx L1: mov eax,HIWORD(DVSR) ; hi word of b or eax,eax ; test to see if signed jge short L2 ; skip rest if b is already positive inc edi ; complement the result sign flag mov edx,LOWORD(DVSR) ; lo word of a neg eax ; make b positive neg edx sbb eax,0 mov HIWORD(DVSR),eax ; save positive value mov LOWORD(DVSR),edx L2: ; ; Now do the divide. First look to see if the divisor is less than 4194304K. ; If so, then we can use a simple algorithm with word divides, otherwise ; things get a little more complex. ; ; NOTE - eax currently contains the high order word of DVSR ; or eax,eax ; check to see if divisor < 4194304K jnz short L3 ; nope, gotta do this the hard way mov ecx,LOWORD(DVSR) ; load divisor mov eax,HIWORD(DVND) ; load high word of dividend xor edx,edx div ecx ; eax <- high order bits of quotient mov ebx,eax ; save high bits of quotient mov eax,LOWORD(DVND) ; edx:eax <- remainder:lo word of dividend div ecx ; eax <- low order bits of quotient mov esi,eax ; ebx:esi <- quotient ; ; Now we need to do a multiply so that we can compute the remainder. ; mov eax,ebx ; set up high word of quotient mul dword ptr LOWORD(DVSR) ; HIWORD(QUOT) * DVSR mov ecx,eax ; save the result in ecx mov eax,esi ; set up low word of quotient mul dword ptr LOWORD(DVSR) ; LOWORD(QUOT) * DVSR add edx,ecx ; EDX:EAX = QUOT * DVSR jmp short L4 ; complete remainder calculation ; ; Here we do it the hard way. Remember, eax contains the high word of DVSR ; L3: mov ebx,eax ; ebx:ecx <- divisor mov ecx,LOWORD(DVSR) mov edx,HIWORD(DVND) ; edx:eax <- dividend mov eax,LOWORD(DVND) L5: shr ebx,1 ; shift divisor right one bit rcr ecx,1 shr edx,1 ; shift dividend right one bit rcr eax,1 or ebx,ebx jnz short L5 ; loop until divisor < 4194304K div ecx ; now divide, ignore remainder mov esi,eax ; save quotient ; ; We may be off by one, so to check, we will multiply the quotient ; by the divisor and check the result against the orignal dividend ; Note that we must also check for overflow, which can occur if the ; dividend is close to 2**64 and the quotient is off by 1. ; mul dword ptr HIWORD(DVSR) ; QUOT * HIWORD(DVSR) mov ecx,eax mov eax,LOWORD(DVSR) mul esi ; QUOT * LOWORD(DVSR) add edx,ecx ; EDX:EAX = QUOT * DVSR jc short L6 ; carry means Quotient is off by 1 ; ; do long compare here between original dividend and the result of the ; multiply in edx:eax. If original is larger or equal, we are ok, otherwise ; subtract one (1) from the quotient. ; cmp edx,HIWORD(DVND) ; compare hi words of result and original ja short L6 ; if result > original, do subtract jb short L7 ; if result < original, we are ok cmp eax,LOWORD(DVND) ; hi words are equal, compare lo words jbe short L7 ; if less or equal we are ok, else subtract L6: dec esi ; subtract 1 from quotient sub eax,LOWORD(DVSR) ; subtract divisor from result sbb edx,HIWORD(DVSR) L7: xor ebx,ebx ; ebx:esi <- quotient L4: ; ; Calculate remainder by subtracting the result from the original dividend. ; Since the result is already in a register, we will do the subtract in the ; opposite direction and negate the result if necessary. ; sub eax,LOWORD(DVND) ; subtract dividend from result sbb edx,HIWORD(DVND) ; ; Now check the result sign flag to see if the result is supposed to be positive ; or negative. It is currently negated (because we subtracted in the 'wrong' ; direction), so if the sign flag is set we are done, otherwise we must negate ; the result to make it positive again. ; dec ebp ; check result sign flag jns short L9 ; result is ok, set up the quotient neg edx ; otherwise, negate the result neg eax sbb edx,0 ; ; Now we need to get the quotient into edx:eax and the remainder into ebx:ecx. ; L9: mov ecx,edx mov edx,ebx mov ebx,ecx mov ecx,eax mov eax,esi ; ; Just the cleanup left to do. edx:eax contains the quotient. Set the sign ; according to the save value, cleanup the stack, and return. ; dec edi ; check to see if result is negative jnz short L8 ; if EDI == 0, result should be negative neg edx ; otherwise, negate the result neg eax sbb edx,0 ; ; Restore the saved registers and return. ; L8: pop ebp pop esi pop edi ret 16 __alldvrm ENDP ;*** ;llmul.asm - long multiply routine ; ; Copyright (c) Microsoft Corporation. All rights reserved. ; ;Purpose: ; Defines long multiply routine ; Both signed and unsigned routines are the same, since multiply's ; work out the same in 2's complement ; creates the following routine: ; __allmul ; ;Revision History: ; 11-29-83 DFW initial version ; 06-01-84 RN modified to use cmacros ; 04-17-85 TC ignore signs since they take care of themselves ; do a fast multiply if both hiwords of arguments are 0 ; 10-10-86 MH slightly faster implementation, for 0 in upper words ; 03-20-89 SKS Remove redundant "MOV SP,BP" from epilogs ; 05-18-89 SKS Preserve BX ; 11-28-89 GJF Fixed copyright ; 11-19-93 SMK Modified to work on 64 bit integers ; 01-17-94 GJF Minor changes to build with NT's masm386. ; 07-22-94 GJF Use esp-relative addressing for args. Shortened ; conditional jump. ; ;******************************************************************************* ;*** ;llmul - long multiply routine ; ;Purpose: ; Does a long multiply (same for signed/unsigned) ; Parameters are not changed. ; ;Entry: ; Parameters are passed on the stack: ; 1st pushed: multiplier (QWORD) ; 2nd pushed: multiplicand (QWORD) ; ;Exit: ; EDX:EAX - product of multiplier and multiplicand ; NOTE: parameters are removed from the stack ; ;Uses: ; ECX ; ;Exceptions: ; ;******************************************************************************* __allmul PROC NEAR A EQU [esp + 4] ; stack address of a B EQU [esp + 12] ; stack address of b ; ; AHI, BHI : upper 32 bits of A and B ; ALO, BLO : lower 32 bits of A and B ; ; ALO * BLO ; ALO * BHI ; + BLO * AHI ; --------------------- ; mov eax,HIWORD(A) mov ecx,HIWORD(B) or ecx,eax ;test for both hiwords zero. mov ecx,LOWORD(B) jnz short hard ;both are zero, just mult ALO and BLO mov eax,LOWORD(A) mul ecx ret 16 ; callee restores the stack hard: push ebx ; must redefine A and B since esp has been altered A2 EQU [esp + 8] ; stack address of a B2 EQU [esp + 16] ; stack address of b mul ecx ;eax has AHI, ecx has BLO, so AHI * BLO mov ebx,eax ;save result mov eax,LOWORD(A2) mul dword ptr HIWORD(B2) ;ALO * BHI add ebx,eax ;ebx = ((ALO * BHI) + (AHI * BLO)) mov eax,LOWORD(A2) ;ecx = BLO mul ecx ;so edx:eax = ALO*BLO add edx,ebx ;now edx has all the LO*HI stuff pop ebx ret 16 ; callee restores the stack __allmul ENDP ;*** ;llrem.asm - signed long remainder routine ; ; Copyright (c) Microsoft Corporation. All rights reserved. ; ;Purpose: ; defines the signed long remainder routine ; __allrem ; ;Revision History: ; 11-29-83 DFW initial version ; 06-01-84 RN modified to use cmacros ; 10-23-87 SKS fixed off-by-1 error for dividend close to 2**32. ; 05-18-89 SKS Remove redundant "MOV SP,BP" from epilog ; 11-28-89 GJF Fixed copyright ; 11-19-93 SMK Modified to work on 64 bit integers ; 01-17-94 GJF Minor changes to build with NT's masm386. ; 07-22-94 GJF Use esp-relative addressing for args. Shortened ; conditional jumps. ; ;******************************************************************************* ;*** ;llrem - signed long remainder ; ;Purpose: ; Does a signed long remainder of the arguments. Arguments are ; not changed. ; ;Entry: ; Arguments are passed on the stack: ; 1st pushed: divisor (QWORD) ; 2nd pushed: dividend (QWORD) ; ;Exit: ; EDX:EAX contains the remainder (dividend%divisor) ; NOTE: this routine removes the parameters from the stack. ; ;Uses: ; ECX ; ;Exceptions: ; ;******************************************************************************* __allrem PROC NEAR push ebx push edi ; Set up the local stack and save the index registers. When this is done ; the stack frame will look as follows (assuming that the expression a%b will ; generate a call to lrem(a, b)): ; ; ----------------- ; | | ; |---------------| ; | | ; |--divisor (b)--| ; | | ; |---------------| ; | | ; |--dividend (a)-| ; | | ; |---------------| ; | return addr** | ; |---------------| ; | EBX | ; |---------------| ; ESP---->| EDI | ; ----------------- ; DVND equ [esp + 12] ; stack address of dividend (a) DVSR equ [esp + 20] ; stack address of divisor (b) ; Determine sign of the result (edi = 0 if result is positive, non-zero ; otherwise) and make operands positive. xor edi,edi ; result sign assumed positive mov eax,HIWORD(DVND) ; hi word of a or eax,eax ; test to see if signed jge short L1 ; skip rest if a is already positive inc edi ; complement result sign flag bit mov edx,LOWORD(DVND) ; lo word of a neg eax ; make a positive neg edx sbb eax,0 mov HIWORD(DVND),eax ; save positive value mov LOWORD(DVND),edx L1: mov eax,HIWORD(DVSR) ; hi word of b or eax,eax ; test to see if signed jge short L2 ; skip rest if b is already positive mov edx,LOWORD(DVSR) ; lo word of b neg eax ; make b positive neg edx sbb eax,0 mov HIWORD(DVSR),eax ; save positive value mov LOWORD(DVSR),edx L2: ; ; Now do the divide. First look to see if the divisor is less than 4194304K. ; If so, then we can use a simple algorithm with word divides, otherwise ; things get a little more complex. ; ; NOTE - eax currently contains the high order word of DVSR ; or eax,eax ; check to see if divisor < 4194304K jnz short L3 ; nope, gotta do this the hard way mov ecx,LOWORD(DVSR) ; load divisor mov eax,HIWORD(DVND) ; load high word of dividend xor edx,edx div ecx ; edx <- remainder mov eax,LOWORD(DVND) ; edx:eax <- remainder:lo word of dividend div ecx ; edx <- final remainder mov eax,edx ; edx:eax <- remainder xor edx,edx dec edi ; check result sign flag jns short L4 ; negate result, restore stack and return jmp short L8 ; result sign ok, restore stack and return ; ; Here we do it the hard way. Remember, eax contains the high word of DVSR ; L3: mov ebx,eax ; ebx:ecx <- divisor mov ecx,LOWORD(DVSR) mov edx,HIWORD(DVND) ; edx:eax <- dividend mov eax,LOWORD(DVND) L5: shr ebx,1 ; shift divisor right one bit rcr ecx,1 shr edx,1 ; shift dividend right one bit rcr eax,1 or ebx,ebx jnz short L5 ; loop until divisor < 4194304K div ecx ; now divide, ignore remainder ; ; We may be off by one, so to check, we will multiply the quotient ; by the divisor and check the result against the orignal dividend ; Note that we must also check for overflow, which can occur if the ; dividend is close to 2**64 and the quotient is off by 1. ; mov ecx,eax ; save a copy of quotient in ECX mul dword ptr HIWORD(DVSR) xchg ecx,eax ; save product, get quotient in EAX mul dword ptr LOWORD(DVSR) add edx,ecx ; EDX:EAX = QUOT * DVSR jc short L6 ; carry means Quotient is off by 1 ; ; do long compare here between original dividend and the result of the ; multiply in edx:eax. If original is larger or equal, we are ok, otherwise ; subtract the original divisor from the result. ; cmp edx,HIWORD(DVND) ; compare hi words of result and original ja short L6 ; if result > original, do subtract jb short L7 ; if result < original, we are ok cmp eax,LOWORD(DVND) ; hi words are equal, compare lo words jbe short L7 ; if less or equal we are ok, else subtract L6: sub eax,LOWORD(DVSR) ; subtract divisor from result sbb edx,HIWORD(DVSR) L7: ; ; Calculate remainder by subtracting the result from the original dividend. ; Since the result is already in a register, we will do the subtract in the ; opposite direction and negate the result if necessary. ; sub eax,LOWORD(DVND) ; subtract dividend from result sbb edx,HIWORD(DVND) ; ; Now check the result sign flag to see if the result is supposed to be positive ; or negative. It is currently negated (because we subtracted in the 'wrong' ; direction), so if the sign flag is set we are done, otherwise we must negate ; the result to make it positive again. ; dec edi ; check result sign flag jns short L8 ; result is ok, restore stack and return L4: neg edx ; otherwise, negate the result neg eax sbb edx,0 ; ; Just the cleanup left to do. edx:eax contains the quotient. ; Restore the saved registers and return. ; L8: pop edi pop ebx ret 16 __allrem ENDP ;*** ;llshl.asm - long shift left ; ; Copyright (c) Microsoft Corporation. All rights reserved. ; ;Purpose: ; define long shift left routine (signed and unsigned are same) ; __allshl ; ;Revision History: ; 11-??-83 HS initial version ; 11-30-83 DFW added medium model support ; 03-12-84 DFW broke apart; added long model support ; 06-01-84 RN modified to use cmacros ; 11-28-89 GJF Fixed copyright ; 11-19-93 SMK Modified to work on 64 bit integers ; 01-17-94 GJF Minor changes to build with NT's masm386. ; 07-08-94 GJF Faster, fatter version for NT. ; 07-13-94 GJF Further improvements from JonM. ; ;******************************************************************************* ;*** ;llshl - long shift left ; ;Purpose: ; Does a Long Shift Left (signed and unsigned are identical) ; Shifts a long left any number of bits. ; ;Entry: ; EDX:EAX - long value to be shifted ; CL - number of bits to shift by ; ;Exit: ; EDX:EAX - shifted value ; ;Uses: ; CL is destroyed. ; ;Exceptions: ; ;******************************************************************************* __allshl PROC NEAR ; ; Handle shifts of 64 or more bits (all get 0) ; cmp cl, 64 jae short RETZERO ; ; Handle shifts of between 0 and 31 bits ; cmp cl, 32 jae short MORE32 shld edx,eax,cl shl eax,cl ret ; ; Handle shifts of between 32 and 63 bits ; MORE32: mov edx,eax xor eax,eax and cl,31 shl edx,cl ret ; ; return 0 in edx:eax ; RETZERO: xor eax,eax xor edx,edx ret __allshl ENDP ;*** ;llshr.asm - long shift right ; ; Copyright (c) Microsoft Corporation. All rights reserved. ; ;Purpose: ; define signed long shift right routine ; __allshr ; ;Revision History: ; 11-??-83 HS initial version ; 11-30-83 DFW added medium model support ; 03-12-84 DFW broke apart; added long model support ; 06-01-84 RN modified to use cmacros ; 11-28-89 GJF Fixed copyright ; 11-19-93 SMK Modified to work on 64 bit integers ; 01-17-94 GJF Minor changes to build with NT's masm386. ; 07-08-94 GJF Faster, fatter version for NT. ; 07-13-94 GJF Further improvements from JonM. ; ;******************************************************************************* ;*** ;llshr - long shift right ; ;Purpose: ; Does a signed Long Shift Right ; Shifts a long right any number of bits. ; ;Entry: ; EDX:EAX - long value to be shifted ; CL - number of bits to shift by ; ;Exit: ; EDX:EAX - shifted value ; ;Uses: ; CL is destroyed. ; ;Exceptions: ; ;******************************************************************************* __allshr PROC NEAR ; ; Handle shifts of 64 bits or more (if shifting 64 bits or more, the result ; depends only on the high order bit of edx). ; cmp cl,64 jae short RETSIGN ; ; Handle shifts of between 0 and 31 bits ; cmp cl, 32 jae short MORE32 shrd eax,edx,cl sar edx,cl ret ; ; Handle shifts of between 32 and 63 bits ; MORE32: mov eax,edx sar edx,31 and cl,31 sar eax,cl ret ; ; Return double precision 0 or -1, depending on the sign of edx ; RETSIGN: sar edx,31 mov eax,edx ret __allshr ENDP ;*** ;ulldiv.asm - unsigned long divide routine ; ; Copyright (c) Microsoft Corporation. All rights reserved. ; ;Purpose: ; defines the unsigned long divide routine ; __aulldiv ; ;Revision History: ; 11-29-83 DFW initial version ; 06-01-84 RN modified to use cmacros ; 10-23-87 SKS fixed off-by-1 error for dividend close to 2**32. ; 05-18-89 SKS Remove redundant "MOV SP,BP" from epilog ; 11-28-89 GJF Fixed copyright ; 11-19-93 SMK Modified to work on 64 bit integers ; 01-17-94 GJF Minor changes to build with NT's masm386. ; 07-22-94 GJF Use esp-relative addressing for args. Shortened ; conditional jumps. Also, don't use xchg to do a ; simple move between regs. ; ;******************************************************************************* ;*** ;ulldiv - unsigned long divide ; ;Purpose: ; Does a unsigned long divide of the arguments. Arguments are ; not changed. ; ;Entry: ; Arguments are passed on the stack: ; 1st pushed: divisor (QWORD) ; 2nd pushed: dividend (QWORD) ; ;Exit: ; EDX:EAX contains the quotient (dividend/divisor) ; NOTE: this routine removes the parameters from the stack. ; ;Uses: ; ECX ; ;Exceptions: ; ;******************************************************************************* __aulldiv PROC NEAR push ebx push esi ; Set up the local stack and save the index registers. When this is done ; the stack frame will look as follows (assuming that the expression a/b will ; generate a call to uldiv(a, b)): ; ; ----------------- ; | | ; |---------------| ; | | ; |--divisor (b)--| ; | | ; |---------------| ; | | ; |--dividend (a)-| ; | | ; |---------------| ; | return addr** | ; |---------------| ; | EBX | ; |---------------| ; ESP---->| ESI | ; ----------------- ; DVND equ [esp + 12] ; stack address of dividend (a) DVSR equ [esp + 20] ; stack address of divisor (b) ; ; Now do the divide. First look to see if the divisor is less than 4194304K. ; If so, then we can use a simple algorithm with word divides, otherwise ; things get a little more complex. ; mov eax,HIWORD(DVSR) ; check to see if divisor < 4194304K or eax,eax jnz short L1 ; nope, gotta do this the hard way mov ecx,LOWORD(DVSR) ; load divisor mov eax,HIWORD(DVND) ; load high word of dividend xor edx,edx div ecx ; get high order bits of quotient mov ebx,eax ; save high bits of quotient mov eax,LOWORD(DVND) ; edx:eax <- remainder:lo word of dividend div ecx ; get low order bits of quotient mov edx,ebx ; edx:eax <- quotient hi:quotient lo jmp short L2 ; restore stack and return ; ; Here we do it the hard way. Remember, eax contains DVSRHI ; L1: mov ecx,eax ; ecx:ebx <- divisor mov ebx,LOWORD(DVSR) mov edx,HIWORD(DVND) ; edx:eax <- dividend mov eax,LOWORD(DVND) L3: shr ecx,1 ; shift divisor right one bit; hi bit <- 0 rcr ebx,1 shr edx,1 ; shift dividend right one bit; hi bit <- 0 rcr eax,1 or ecx,ecx jnz short L3 ; loop until divisor < 4194304K div ebx ; now divide, ignore remainder mov esi,eax ; save quotient ; ; We may be off by one, so to check, we will multiply the quotient ; by the divisor and check the result against the orignal dividend ; Note that we must also check for overflow, which can occur if the ; dividend is close to 2**64 and the quotient is off by 1. ; mul dword ptr HIWORD(DVSR) ; QUOT * HIWORD(DVSR) mov ecx,eax mov eax,LOWORD(DVSR) mul esi ; QUOT * LOWORD(DVSR) add edx,ecx ; EDX:EAX = QUOT * DVSR jc short L4 ; carry means Quotient is off by 1 ; ; do long compare here between original dividend and the result of the ; multiply in edx:eax. If original is larger or equal, we are ok, otherwise ; subtract one (1) from the quotient. ; cmp edx,HIWORD(DVND) ; compare hi words of result and original ja short L4 ; if result > original, do subtract jb short L5 ; if result < original, we are ok cmp eax,LOWORD(DVND) ; hi words are equal, compare lo words jbe short L5 ; if less or equal we are ok, else subtract L4: dec esi ; subtract 1 from quotient L5: xor edx,edx ; edx:eax <- quotient mov eax,esi ; ; Just the cleanup left to do. edx:eax contains the quotient. ; Restore the saved registers and return. ; L2: pop esi pop ebx ret 16 __aulldiv ENDP ;*** ;ulldvrm.asm - unsigned long divide and remainder routine ; ; Copyright (c) Microsoft Corporation. All rights reserved. ; ;Purpose: ; defines the unsigned long divide and remainder routine ; __aulldvrm ; ;Revision History: ; 10-06-98 SMK Initial version. ; ;******************************************************************************* ;*** ;ulldvrm - unsigned long divide and remainder ; ;Purpose: ; Does a unsigned long divide and remainder of the arguments. Arguments ; are not changed. ; ;Entry: ; Arguments are passed on the stack: ; 1st pushed: divisor (QWORD) ; 2nd pushed: dividend (QWORD) ; ;Exit: ; EDX:EAX contains the quotient (dividend/divisor) ; EBX:ECX contains the remainder (divided % divisor) ; NOTE: this routine removes the parameters from the stack. ; ;Uses: ; ECX ; ;Exceptions: ; ;******************************************************************************* __aulldvrm PROC NEAR push esi ; Set up the local stack and save the index registers. When this is done ; the stack frame will look as follows (assuming that the expression a/b will ; generate a call to aulldvrm(a, b)): ; ; ----------------- ; | | ; |---------------| ; | | ; |--divisor (b)--| ; | | ; |---------------| ; | | ; |--dividend (a)-| ; | | ; |---------------| ; | return addr** | ; |---------------| ; ESP---->| ESI | ; ----------------- ; DVND equ [esp + 8] ; stack address of dividend (a) DVSR equ [esp + 16] ; stack address of divisor (b) ; ; Now do the divide. First look to see if the divisor is less than 4194304K. ; If so, then we can use a simple algorithm with word divides, otherwise ; things get a little more complex. ; mov eax,HIWORD(DVSR) ; check to see if divisor < 4194304K or eax,eax jnz short L1 ; nope, gotta do this the hard way mov ecx,LOWORD(DVSR) ; load divisor mov eax,HIWORD(DVND) ; load high word of dividend xor edx,edx div ecx ; get high order bits of quotient mov ebx,eax ; save high bits of quotient mov eax,LOWORD(DVND) ; edx:eax <- remainder:lo word of dividend div ecx ; get low order bits of quotient mov esi,eax ; ebx:esi <- quotient ; ; Now we need to do a multiply so that we can compute the remainder. ; mov eax,ebx ; set up high word of quotient mul dword ptr LOWORD(DVSR) ; HIWORD(QUOT) * DVSR mov ecx,eax ; save the result in ecx mov eax,esi ; set up low word of quotient mul dword ptr LOWORD(DVSR) ; LOWORD(QUOT) * DVSR add edx,ecx ; EDX:EAX = QUOT * DVSR jmp short L2 ; complete remainder calculation ; ; Here we do it the hard way. Remember, eax contains DVSRHI ; L1: mov ecx,eax ; ecx:ebx <- divisor mov ebx,LOWORD(DVSR) mov edx,HIWORD(DVND) ; edx:eax <- dividend mov eax,LOWORD(DVND) L3: shr ecx,1 ; shift divisor right one bit; hi bit <- 0 rcr ebx,1 shr edx,1 ; shift dividend right one bit; hi bit <- 0 rcr eax,1 or ecx,ecx jnz short L3 ; loop until divisor < 4194304K div ebx ; now divide, ignore remainder mov esi,eax ; save quotient ; ; We may be off by one, so to check, we will multiply the quotient ; by the divisor and check the result against the orignal dividend ; Note that we must also check for overflow, which can occur if the ; dividend is close to 2**64 and the quotient is off by 1. ; mul dword ptr HIWORD(DVSR) ; QUOT * HIWORD(DVSR) mov ecx,eax mov eax,LOWORD(DVSR) mul esi ; QUOT * LOWORD(DVSR) add edx,ecx ; EDX:EAX = QUOT * DVSR jc short L4 ; carry means Quotient is off by 1 ; ; do long compare here between original dividend and the result of the ; multiply in edx:eax. If original is larger or equal, we are ok, otherwise ; subtract one (1) from the quotient. ; cmp edx,HIWORD(DVND) ; compare hi words of result and original ja short L4 ; if result > original, do subtract jb short L5 ; if result < original, we are ok cmp eax,LOWORD(DVND) ; hi words are equal, compare lo words jbe short L5 ; if less or equal we are ok, else subtract L4: dec esi ; subtract 1 from quotient sub eax,LOWORD(DVSR) ; subtract divisor from result sbb edx,HIWORD(DVSR) L5: xor ebx,ebx ; ebx:esi <- quotient L2: ; ; Calculate remainder by subtracting the result from the original dividend. ; Since the result is already in a register, we will do the subtract in the ; opposite direction and negate the result. ; sub eax,LOWORD(DVND) ; subtract dividend from result sbb edx,HIWORD(DVND) neg edx ; otherwise, negate the result neg eax sbb edx,0 ; ; Now we need to get the quotient into edx:eax and the remainder into ebx:ecx. ; mov ecx,edx mov edx,ebx mov ebx,ecx mov ecx,eax mov eax,esi ; ; Just the cleanup left to do. edx:eax contains the quotient. ; Restore the saved registers and return. ; pop esi ret 16 __aulldvrm ENDP ;*** ;ullrem.asm - unsigned long remainder routine ; ; Copyright (c) Microsoft Corporation. All rights reserved. ; ;Purpose: ; defines the unsigned long remainder routine ; __aullrem ; ;Revision History: ; 11-29-83 DFW initial version ; 06-01-84 RN modified to use cmacros ; 10-23-87 SKS fixed off-by-1 error for dividend close to 2**32. ; 05-18-89 SKS Remove redundant "MOV SP,BP" from epilog ; 11-28-89 GJF Fixed copyright ; 11-19-93 SMK Modified to work on 64 bit integers ; 01-17-94 GJF Minor changes to build with NT's masm386. ; 07-22-94 GJF Use esp-relative addressing for args. Shortened ; conditional jumps. ; ;******************************************************************************* ;*** ;ullrem - unsigned long remainder ; ;Purpose: ; Does a unsigned long remainder of the arguments. Arguments are ; not changed. ; ;Entry: ; Arguments are passed on the stack: ; 1st pushed: divisor (QWORD) ; 2nd pushed: dividend (QWORD) ; ;Exit: ; EDX:EAX contains the remainder (dividend%divisor) ; NOTE: this routine removes the parameters from the stack. ; ;Uses: ; ECX ; ;Exceptions: ; ;******************************************************************************* __aullrem PROC NEAR push ebx ; Set up the local stack and save the index registers. When this is done ; the stack frame will look as follows (assuming that the expression a%b will ; generate a call to ullrem(a, b)): ; ; ----------------- ; | | ; |---------------| ; | | ; |--divisor (b)--| ; | | ; |---------------| ; | | ; |--dividend (a)-| ; | | ; |---------------| ; | return addr** | ; |---------------| ; ESP---->| EBX | ; ----------------- ; DVND equ [esp + 8] ; stack address of dividend (a) DVSR equ [esp + 16] ; stack address of divisor (b) ; Now do the divide. First look to see if the divisor is less than 4194304K. ; If so, then we can use a simple algorithm with word divides, otherwise ; things get a little more complex. ; mov eax,HIWORD(DVSR) ; check to see if divisor < 4194304K or eax,eax jnz short L1 ; nope, gotta do this the hard way mov ecx,LOWORD(DVSR) ; load divisor mov eax,HIWORD(DVND) ; load high word of dividend xor edx,edx div ecx ; edx <- remainder, eax <- quotient mov eax,LOWORD(DVND) ; edx:eax <- remainder:lo word of dividend div ecx ; edx <- final remainder mov eax,edx ; edx:eax <- remainder xor edx,edx jmp short L2 ; restore stack and return ; ; Here we do it the hard way. Remember, eax contains DVSRHI ; L1: mov ecx,eax ; ecx:ebx <- divisor mov ebx,LOWORD(DVSR) mov edx,HIWORD(DVND) ; edx:eax <- dividend mov eax,LOWORD(DVND) L3: shr ecx,1 ; shift divisor right one bit; hi bit <- 0 rcr ebx,1 shr edx,1 ; shift dividend right one bit; hi bit <- 0 rcr eax,1 or ecx,ecx jnz short L3 ; loop until divisor < 4194304K div ebx ; now divide, ignore remainder ; ; We may be off by one, so to check, we will multiply the quotient ; by the divisor and check the result against the orignal dividend ; Note that we must also check for overflow, which can occur if the ; dividend is close to 2**64 and the quotient is off by 1. ; mov ecx,eax ; save a copy of quotient in ECX mul dword ptr HIWORD(DVSR) xchg ecx,eax ; put partial product in ECX, get quotient in EAX mul dword ptr LOWORD(DVSR) add edx,ecx ; EDX:EAX = QUOT * DVSR jc short L4 ; carry means Quotient is off by 1 ; ; do long compare here between original dividend and the result of the ; multiply in edx:eax. If original is larger or equal, we're ok, otherwise ; subtract the original divisor from the result. ; cmp edx,HIWORD(DVND) ; compare hi words of result and original ja short L4 ; if result > original, do subtract jb short L5 ; if result < original, we're ok cmp eax,LOWORD(DVND) ; hi words are equal, compare lo words jbe short L5 ; if less or equal we're ok, else subtract L4: sub eax,LOWORD(DVSR) ; subtract divisor from result sbb edx,HIWORD(DVSR) L5: ; ; Calculate remainder by subtracting the result from the original dividend. ; Since the result is already in a register, we will perform the subtract in ; the opposite direction and negate the result to make it positive. ; sub eax,LOWORD(DVND) ; subtract original dividend from result sbb edx,HIWORD(DVND) neg edx ; and negate it neg eax sbb edx,0 ; ; Just the cleanup left to do. dx:ax contains the remainder. ; Restore the saved registers and return. ; L2: pop ebx ret 16 __aullrem ENDP ;*** ;ullshr.asm - long shift right ; ; Copyright (c) Microsoft Corporation. All rights reserved. ; ;Purpose: ; define unsigned long shift right routine ; __aullshr ; ;Revision History: ; 11-??-83 HS initial version ; 11-30-83 DFW added medium model support ; 03-12-84 DFW broke apart; added long model support ; 06-01-84 RN modified to use cmacros ; 11-28-89 GJF Fixed copyright ; 11-19-93 SMK Modified to work on 64 bit integers ; 01-17-94 GJF Minor changes to build with NT's masm386. ; 07-08-94 GJF Faster, fatter version for NT. ; 07-13-94 GJF Further improvements from JonM. ; ;******************************************************************************* ;*** ;ullshr - long shift right ; ;Purpose: ; Does a unsigned Long Shift Right ; Shifts a long right any number of bits. ; ;Entry: ; EDX:EAX - long value to be shifted ; CL - number of bits to shift by ; ;Exit: ; EDX:EAX - shifted value ; ;Uses: ; CL is destroyed. ; ;Exceptions: ; ;******************************************************************************* __aullshr PROC NEAR ; ; Handle shifts of 64 bits or more (if shifting 64 bits or more, the result ; depends only on the high order bit of edx). ; cmp cl,64 jae short RETZERO ; ; Handle shifts of between 0 and 31 bits ; cmp cl, 32 jae short MORE32 shrd eax,edx,cl shr edx,cl ret ; ; Handle shifts of between 32 and 63 bits ; MORE32: mov eax,edx xor edx,edx and cl,31 shr eax,cl ret ; ; return 0 in edx:eax ; RETZERO: xor eax,eax xor edx,edx ret __aullshr ENDP end ================================================ FILE: ironclad-apps/src/Checked/BootLoader/SingLdrPc/x86/blidt.asm ================================================ ;++ ; ; Copyright (c) Microsoft Corporation ; ; Module Name: ; ; blidt.asm ; ; Abstract: ; ; This module implements IDT functions for the boot loader. ; ; Environment: ; ; Boot loader. ; ;-- include bl.inc .686p .model flat .code assume ds:flat assume es:flat assume ss:flat assume fs:flat extrn ?BlTrapFatal@@YIXKPAU_BL_TRAP_CONTEXT@@@Z:near ;++ ; ; VOID ; BlTrapEnter( ; VOID ; ) ; ; Routine Description: ; ; Entry point for incoming exceptions. ; ;-- align 16 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; The IDT_ENTER building macros insure that each IDT target has ;;; an offset of form BlTrapEnter + 0x10 * interrupt_number. ;;; IDT_ENTER_NOERR MACRO num:req push 77h ; No error call @f align 8 ENDM IDT_ENTER_ERR MACRO num:req call @f align 8 ENDM align 16 ?BlTrapEnter@@YIXXZ proc IDT_ENTER_NOERR 000h ; #DE Divide-by-Zero IDT_ENTER_NOERR 001h ; #DB Debug Exception IDT_ENTER_NOERR 002h ; NMI Non-Maskable-Interrupt IDT_ENTER_NOERR 003h ; #BP Breakpoint IDT_ENTER_NOERR 004h ; #OF OVerflow IDT_ENTER_NOERR 005h ; #BR Bound-Range IDT_ENTER_NOERR 006h ; #UD Invalid Opcode IDT_ENTER_NOERR 007h ; #NM Device Not Available IDT_ENTER_ERR 008h ; #DF Double Fault IDT_ENTER_NOERR 009h ; Unused (was x87 segment except) IDT_ENTER_ERR 00ah ; #TS Invalid TSS IDT_ENTER_ERR 00bh ; #NP Sgement Not Present IDT_ENTER_ERR 00ch ; #SS Stack Exception IDT_ENTER_ERR 00dh ; #GP General Protection IDT_ENTER_ERR 00eh ; #PF Page Fault IDT_ENTER_NOERR 00fh ; Reserved IDT_ENTER_NOERR 010h ; #MF x87 Math Error IDT_ENTER_ERR 011h ; #AC Alignment Check IDT_ENTER_NOERR 012h ; #MC Machine Check IDT_ENTER_NOERR 013h ; #XF SIMD Exception inum = 014h ; 014h to 020h WHILE inum LE 020h IDT_ENTER_NOERR inum inum = inum + 1 ENDM @@: push eax push ebx push ecx push edx push esi push edi push ebp mov eax, esp add eax, 48 push eax mov eax, cr2 push eax mov edx, esp mov ecx, [edx].BL_TRAP_CONTEXT.TrapNum sub ecx, ?BlTrapEnter@@YIXXZ shr ecx, 3 mov [edx].BL_TRAP_CONTEXT.TrapNum, ecx call ?BlTrapFatal@@YIXKPAU_BL_TRAP_CONTEXT@@@Z @@: jmp @b ?BlTrapEnter@@YIXXZ endp ;++ ; ; VOID ; FASTCALL ; BlTrapSetIdtr( ; PIDTR Idtr ; ) ; ; Routine Description: ; ; This function sets the IDTR register. ; ; Arguments: ; ; Idtr - Supplies the data to write to the IDTR register. ; ;-- ?BlTrapSetIdtr@@YIXPAU_IDTR@@@Z proc lidt fword ptr [ecx] ret ?BlTrapSetIdtr@@YIXPAU_IDTR@@@Z endp end ================================================ FILE: ironclad-apps/src/Checked/BootLoader/SingLdrPc/x86/blioport.asm ================================================ ;++ ; ; Copyright (c) Microsoft Corporation ; ; Module Name: ; ; blioport.asm ; ; Abstract: ; ; This module implements IO port access routines for the boot loader. ; ; Environment: ; ; Boot loader. ; ;-- include bl.inc .686p .model flat .code assume ds:flat assume es:flat assume ss:flat assume fs:flat ;++ ; ; UCHAR ; FASTCALL ; BlRtlReadPort8( ; USHORT Port ; ) ; ; Routine Description: ; ; This function reads from the specified 8-bit port. ; ; Arguments: ; ; Port - Supplies the port to read from. ; ; Return Value: ; ; Value read from the port. ; ;-- ?BlRtlReadPort8@@YIEG@Z proc mov dx, cx in al, dx ret ?BlRtlReadPort8@@YIEG@Z endp ;++ ; ; ULONG ; FASTCALL ; BlRtlReadPort32( ; USHORT Port ; ) ; ; Routine Description: ; ; This function reads from the specified 32-bit port. ; ; Arguments: ; ; Port - Supplies the port to read from. ; ; Return Value: ; ; Value read from the port. ; ;-- ?BlRtlReadPort32@@YIKG@Z proc mov dx, cx in eax, dx ret ?BlRtlReadPort32@@YIKG@Z endp ;++ ; ; VOID ; FASTCALL ; BlRtlWritePort8( ; USHORT Port, ; UCHAR Value ; ) ; ; Routine Description: ; ; This function writes to the specified 8-bit port. ; ; Arguments: ; ; Port - Supplies the port to write to. ; ; Value - Supplies the value to write. ; ;-- ?BlRtlWritePort8@@YIXGE@Z proc mov al, dl mov dx, cx out dx, al ret ?BlRtlWritePort8@@YIXGE@Z endp ;++ ; ; VOID ; FASTCALL ; BlRtlWritePort32( ; USHORT Port, ; ULONG Value ; ) ; ; Routine Description: ; ; This function writes to the specified 32-bit port. ; ; Arguments: ; ; Port - Supplies the port to write to. ; ; Value - Supplies the value to write. ; ;-- ?BlRtlWritePort32@@YIXGK@Z proc mov eax, edx mov dx, cx out dx, eax ret ?BlRtlWritePort32@@YIXGK@Z endp end ================================================ FILE: ironclad-apps/src/Checked/BootLoader/SingLdrPc/x86/bllegacy.asm ================================================ ;++ ; ; Copyright (c) Microsoft Corporation ; ; Module Name: ; ; bllegacy.asm ; ; Abstract: ; ; This module implements legacy call support. ; ; Environment: ; ; Boot loader. ; ;-- include bl.inc .686p .model flat .code assume ds:flat assume es:flat assume ss:flat assume fs:flat .code ; ; Legacy call frame. ; LegacyCallFrame struct _eax dq ? _ebx dq ? _ecx dq ? _edx dq ? _ebp dq ? _esi dq ? _edi dq ? _idtr df ? LegacyCallFrame ends BlLegacyReturnStackPointer dd 0 ;++ ; ; VOID ; FASTCALL ; BlReturnToLegacyMode( ; VOID ; ) ; ; Routine Description: ; ; This function returns to legacy mode to process a legacy request. ; ;-- ?BlReturnToLegacyMode@@YIXXZ proc ; ; Save all registers. ; sub esp, (sizeof LegacyCallFrame) mov dword ptr [esp].LegacyCallFrame._eax, eax mov dword ptr [esp].LegacyCallFrame._ebx, ebx mov dword ptr [esp].LegacyCallFrame._ecx, ecx mov dword ptr [esp].LegacyCallFrame._edx, edx mov dword ptr [esp].LegacyCallFrame._ebp, ebp mov dword ptr [esp].LegacyCallFrame._esi, esi mov dword ptr [esp].LegacyCallFrame._edi, edi ; ; Save IDTR ; sidt fword ptr [esp].LegacyCallFrame._idtr ; ; Save stack pointer. ; mov BlLegacyReturnStackPointer, esp ; ; Set return address in BEB. ; mov eax, BEB_BASE lea ecx, @f mov dword ptr [eax].BEB.LegacyReturnAddress, ecx ; ; Get legacy call stub address from BEB. ; mov ecx, dword ptr [eax].BEB.LegacyCallAddress ; ; Return to legacy mode. ; call ecx @@: ; ; Restore stack pointer. ; mov esp, BlLegacyReturnStackPointer ; ; Restore all registers. ; mov eax, dword ptr [esp].LegacyCallFrame._eax mov ebx, dword ptr [esp].LegacyCallFrame._ebx mov ecx, dword ptr [esp].LegacyCallFrame._ecx mov edx, dword ptr [esp].LegacyCallFrame._edx mov ebp, dword ptr [esp].LegacyCallFrame._ebp mov esi, dword ptr [esp].LegacyCallFrame._esi mov edi, dword ptr [esp].LegacyCallFrame._edi ; ; Restore IDT ; lidt fword ptr [esp].LegacyCallFrame._idtr add esp, (sizeof LegacyCallFrame) ret ?BlReturnToLegacyMode@@YIXXZ endp public ?BlReturnToLegacyMode@@YIXXZ end ================================================ FILE: ironclad-apps/src/Checked/BootLoader/SingLdrPc/x86/blutilasm.asm ================================================ ;++ ; ; Copyright (c) Microsoft Corporation ; ; Module Name: ; ; blutilasm.asm ; ; Abstract: ; ; This module implements utility functions for the boot loader. ; ; Environment: ; ; Boot loader. ; ;-- include bl.inc .686p .model flat .code assume ds:flat assume es:flat assume ss:flat assume fs:flat ;++ ; ; UINT ; DisablePaging( ; UINT reg ; ) ; ; Routine Description: ; This function takes one value as an argument and returns another ; that have no meaning. It was simpler to copy an existing function ; than deduce the calling/name-mangling conventions for MS C++. ; Return Value: ; ; None of interest ; ;-- ?DisablePaging@@YIKK@Z proc ; Disable paging mov eax, cr0 and eax, NOT CR0_PG mov cr0, eax ; Make sure PAE is off, in case Verve turns paging back on mov eax, cr4 and eax, NOT CR4_PAE and eax, NOT CR4_PSE mov cr4, eax ; Make sure long mode (EFER.LME) and no-execute (EFER_NXE) is off mov ecx, EFER_MSR_INDEX rdmsr and eax, NOT (EFER_LME OR EFER_NXE) wrmsr ret ?DisablePaging@@YIKK@Z endp ;++ ; ; ULONG_PTR ; FASTCALL ; BlMmGetCr3( ; VOID ; ) ; ; Routine Description: ; ; This function queries the CR3 register. ; ; Return Value: ; ; Value of the CR3 register. ; ;-- ?BlMmGetCr3@@YIKXZ proc mov eax, cr3 ret ?BlMmGetCr3@@YIKXZ endp ;++ ; ; VOID ; FASTCALL ; BlMmSetCr3( ; ULONG_PTR Value ; ) ; ; Routine Description: ; ; This function sets the CR3 register. ; ; Arguments: ; ; Value - Supplies the value to write to the CR3 register. ; ;-- ?BlMmSetCr3@@YIXK@Z proc mov cr3, ecx ret ?BlMmSetCr3@@YIXK@Z endp ;++ ; ; VOID ; FASTCALL ; BlFakeSKINIT( ; ULONG_PTR Value ; ) ; ; Routine Description: ; ; This function launches Verve as though we had invoked SKINIT ; ; Arguments: ; ; Value - Supplies the base address of the Verve image ; ;-- ?BlFakeSKINIT@@YIXK@Z proc mov esp, ecx add esp, 00010000h ; esp == base + 64K mov eax, ecx ; eax == base ; Now calculate the actual entry point, based on the SL header mov edx, [ecx] ; edx contains the SL header and edx, 0000FFFFh ; edx contains the entry point offset add ecx, edx ; ecx contains the absolute entry point addr jmp ecx ?BlFakeSKINIT@@YIXK@Z endp ;++ ; ; VOID ; FASTCALL ; BlRealSKINIT( ; ULONG_PTR Value ; ) ; ; Routine Description: ; ; This function launches Verve as via a real SKINIT ; ; Arguments: ; ; Value - Supplies the base address of the Verve image ; ;-- ?BlRealSKINIT@@YIXK@Z proc mov ebx, ecx ; ebx == base ; Enable SVM mov ecx, 0C0000080h ; Specify EFER rdmsr ; Puts value in EAX (and EDX in 64-bit mode) or eax, 000001000h ; Bit 12, SVME, is now set wrmsr ; Enable SVME ; Do it! mov eax, ebx ; Move the base addr back into EAX ; Windows doesn't know that the SKINIT opcode is 0x0f01de db 00fh db 001h db 0deh ;__emit 00fh ;__emit 001h ;__emit 0deh ?BlRealSKINIT@@YIXK@Z endp ;++ ; ; VOID ; FASTCALL ; BlMmGetGdtr( ; PGDTR Gdtr ; ) ; ; Routine Description: ; ; This function queries the GDTR register. ; ; Arguments: ; ; Gdtr - Receives the contents of the GDTR register. ; ;-- ?BlMmGetGdtr@@YIXPAU_GDTR@@@Z proc sgdt fword ptr [ecx] ret ?BlMmGetGdtr@@YIXPAU_GDTR@@@Z endp ;++ ; ; VOID ; FASTCALL ; BlMmSetGdtr( ; PGDTR Gdtr ; ) ; ; Routine Description: ; ; This function sets the GDTR register. ; ; Arguments: ; ; Gdtr - Supplies the data to write to the GDTR register. ; ;-- ?BlMmSetGdtr@@YIXPAU_GDTR@@@Z proc lgdt fword ptr [ecx] ret ?BlMmSetGdtr@@YIXPAU_GDTR@@@Z endp ;++ ; ; USHORT ; FASTCALL ; BlMmGetFs( ; VOID ; ) ; ; Routine Description: ; ; This function queries the FS register. ; ; Return Value: ; ; Value of the FS register. ; ;-- @BlMmGetFs@0 proc mov ax, fs ret @BlMmGetFs@0 endp ;++ ; ; VOID ; FASTCALL ; BlMmSetFs( ; USHORT Value ; ) ; ; Routine Description: ; ; This function sets the FS register. ; ; Arguments: ; ; Value - Supplies the value to write to the FS register. ; ;-- ?BlMmSetFs@@YIXG@Z proc mov fs, cx ret ?BlMmSetFs@@YIXG@Z endp ;++ ; ; VOID ; FASTCALL ; BlMmSwitchStack( ; PVOID Stack, ; PVOID Function ; ) ; ; Routine Description: ; ; This function switches the stack and calls the specified function. ; ; Arguments: ; ; Stack - Supplies the stack to switch to. ; ; Function - Supplies the function to call. ; ;-- ?BlMmSwitchStack@@YIXPAX0@Z proc mov esp, ecx call edx @@: jmp @b ?BlMmSwitchStack@@YIXPAX0@Z endp ;++ ; ; PVOID ; FASTCALL ; BlRtlGetEbp( ; VOID ; ) ; ; Routine Description: ; ; This function queries the value of the EBP register. ; ; Return Value: ; ; Value of the EBP register. ; ;-- ?BlRtlGetEbp@@YIPAXXZ proc mov eax, ebp ret ?BlRtlGetEbp@@YIPAXXZ endp ;++ ; ; UINT ; BlGetCpuidEax( ; UINT reg ; ) ; ; Routine Description: ; ; This function queries the CPUID. ; ; Return Value: ; ; Value of the EAX register. ; ;-- ?BlGetCpuidEax@@YIKK@Z proc mov eax, ecx cpuid ret ?BlGetCpuidEax@@YIKK@Z endp ;++ ; ; UINT ; BlGetCpuidEbx( ; UINT reg ; ) ; ; Routine Description: ; ; This function queries the CPUID. ; ; Return Value: ; ; Value of the EBX register. ; ;-- ?BlGetCpuidEbx@@YIKK@Z proc mov eax, ecx cpuid mov ebx, eax ret ?BlGetCpuidEbx@@YIKK@Z endp ;++ ; ; UINT ; BlGetCpuidEcx( ; UINT reg ; ) ; ; Routine Description: ; ; This function queries the CPUID. ; ; Return Value: ; ; Value of the ECX register. ; ;-- ?BlGetCpuidEcx@@YIKK@Z proc mov eax, ecx cpuid mov eax, ecx ret ?BlGetCpuidEcx@@YIKK@Z endp ;++ ; ; UINT ; BlGetCpuidEdx( ; UINT reg ; ) ; ; Routine Description: ; ; This function queries the CPUID. ; ; Return Value: ; ; Value of the EDX register. ; ;-- ?BlGetCpuidEdx@@YIKK@Z proc mov eax, ecx cpuid mov eax, edx ret ?BlGetCpuidEdx@@YIKK@Z endp end ================================================ FILE: ironclad-apps/src/Checked/Libraries/DafnyCC/Base.dfy ================================================ include "../../../Dafny/Libraries/base.s.dfy" static function{:imported} unroll_all(i:int):bool { true } static function{:imported} INTERNAL_add_raw(x:int, y:int):int { x + y } static function{:imported} INTERNAL_sub_raw(x:int, y:int):int { x + y } type INTERNAL_AbsMem; type INTERNAL_ArrayElems; static function{:imported} INTERNAL_array_elems(a:array):INTERNAL_ArrayElems static function{:imported} INTERNAL_array_elems_index(a:INTERNAL_ArrayElems, k:int):int static function{:imported} INTERNAL_array_elems_update(a:INTERNAL_ArrayElems, k:int, v:int):INTERNAL_ArrayElems static function{:imported} INTERNAL_array_update(a:array, k:int, v:int):INTERNAL_AbsMem ================================================ FILE: ironclad-apps/src/Checked/Libraries/DafnyCC/Seq.dfy ================================================ include "Base.dfy" include "../../../Trusted/DafnySpec/Seq.s.dfy" //- Untrusted sequence definitions ghost method Seq_Empty_ToZero() ensures Seq_Length(Seq_Empty()) == 0; { reveal_Seq_Length(){:typearg "A"}; Seq_Cons_All(); } ghost method Seq_Empty_FromZero() ensures (forall s:Seq {:trigger Seq_Length(s)}::Seq_Length(s) == 0 ==> s == Seq_Empty()); { reveal_Seq_Length(){:typearg "A"}; assert unroll_all(1); Seq_Cons_All(); } ghost method Seq_Singleton_Length() ensures (forall a:A {:trigger Seq_Length(Seq_Singleton(a))}::Seq_Length(Seq_Singleton(a)) == 1); { reveal_Seq_Length(){:typearg "A"}; reveal_Seq_Singleton(){:typearg "A"}; Seq_Cons_All(); } ghost method Seq_Index_Negative(s:Seq, k:int) ensures k < 0 ==> Seq_Index(s, k) == Seq_Dummy(); { reveal_Seq_Index(){:typearg "A"}; Seq_Cons_All(); if (s.Seq_Cons?) { Seq_Seq(s); Seq_Index_Negative(s.tl, k - 1); } } ghost method Seq_Build_LengthRec(s:Seq, a:A) ensures Seq_Length(Seq_Build(s, a)) == 1 + Seq_Length(s); { reveal_Seq_Length(){:typearg "A"}; reveal_Seq_Singleton(){:typearg "A"}; reveal_Seq_Build(){:typearg "A"}; Seq_Cons_All(); if (s.Seq_Cons?) { Seq_Seq(s); Seq_Build_LengthRec(s.tl, a); } } ghost method Seq_Build_Length() ensures (forall s:Seq, a:A {:trigger Seq_Length(Seq_Build(s, a))}::Seq_Length(Seq_Build(s, a)) == INTERNAL_add_raw(1, Seq_Length(s))); { forall s:Seq, a:A ensures Seq_Length(Seq_Build(s, a)) == 1 + Seq_Length(s); { Seq_Build_LengthRec(s, a); } } ghost method Seq_Build_IndexRec(s:Seq, k:int, a:A) ensures k == Seq_Length(s) ==> Seq_Index(Seq_Build(s, a), k) == a; ensures k != Seq_Length(s) ==> Seq_Index(Seq_Build(s, a), k) == Seq_Index(s, k); { reveal_Seq_Length(){:typearg "A"}; reveal_Seq_Singleton(){:typearg "A"}; reveal_Seq_Build(){:typearg "A"}; reveal_Seq_Index(){:typearg "A"}; Seq_Cons_All(); if (s.Seq_Cons?) { Seq_Seq(s); Seq_Build_IndexRec(s.tl, k - 1, a); } } ghost method Seq_Build_Index() ensures forall s:Seq, k:int, a:A {:trigger Seq_Index(Seq_Build(s, a), k)}:: (k == Seq_Length(s) ==> Seq_Index(Seq_Build(s, a), k) == a) && (k != Seq_Length(s) ==> Seq_Index(Seq_Build(s, a), k) == Seq_Index(s, k)); { forall s:Seq, k:int, a:A ensures (k == Seq_Length(s) ==> Seq_Index(Seq_Build(s, a), k) == a) && (k != Seq_Length(s) ==> Seq_Index(Seq_Build(s, a), k) == Seq_Index(s, k)); { Seq_Build_IndexRec(s, k, a); } } ghost method Seq_Append_LengthRec(s0:Seq, s1:Seq) ensures Seq_Length(Seq_Append(s0, s1)) == Seq_Length(s0) + Seq_Length(s1); { reveal_Seq_Length(){:typearg "A"}; reveal_Seq_Append(){:typearg "A"}; Seq_Cons_All(); if (s0.Seq_Cons?) { Seq_Seq(s0); Seq_Append_LengthRec(s0.tl, s1); } } ghost method Seq_Append_Length() ensures forall s0:Seq, s1:Seq {:trigger Seq_Length(Seq_Append(s0, s1))}:: Seq_Length(Seq_Append(s0, s1)) == INTERNAL_add_raw(Seq_Length(s0), Seq_Length(s1)); { forall s0:Seq, s1:Seq ensures Seq_Length(Seq_Append(s0, s1)) == Seq_Length(s0) + Seq_Length(s1); { Seq_Append_LengthRec(s0, s1); } } ghost method Seq_Index_Singleton() ensures forall a:A {:trigger Seq_Index(Seq_Singleton(a), 0)}::Seq_Index(Seq_Singleton(a), 0) == a; { reveal_Seq_Singleton(){:typearg "A"}; reveal_Seq_Index(){:typearg "A"}; Seq_Cons_All(); } ghost method Seq_Append_IndexRec(s0:Seq, s1:Seq, n:int) ensures n < Seq_Length(s0) ==> Seq_Index(Seq_Append(s0, s1), n) == Seq_Index(s0, n); ensures Seq_Length(s0) <= n ==> Seq_Index(Seq_Append(s0, s1), n) == Seq_Index(s1, n - Seq_Length(s0)); { reveal_Seq_Length(){:typearg "A"}; reveal_Seq_Index(){:typearg "A"}; reveal_Seq_Append(){:typearg "A"}; Seq_Cons_All(); if (s0.Seq_Cons?) { Seq_Seq(s0); Seq_Append_IndexRec(s0.tl, s1, n - 1); } if (n < 0) { Seq_Index_Negative(Seq_Append(s0, s1), n); } } ghost method Seq_Append_Index() ensures forall s0:Seq, s1:Seq, n:int {:trigger Seq_Index(Seq_Append(s0, s1), n)}:: (n < Seq_Length(s0) ==> Seq_Index(Seq_Append(s0, s1), n) == Seq_Index(s0, n)) && (Seq_Length(s0) <= n ==> Seq_Index(Seq_Append(s0, s1), n) == Seq_Index(s1, INTERNAL_sub_raw(n, Seq_Length(s0)))); { forall s0:Seq, s1:Seq, n:int ensures (n < Seq_Length(s0) ==> Seq_Index(Seq_Append(s0, s1), n) == Seq_Index(s0, n)) && (Seq_Length(s0) <= n ==> Seq_Index(Seq_Append(s0, s1), n) == Seq_Index(s1, n - Seq_Length(s0))); { Seq_Append_IndexRec(s0, s1, n); } } ghost method Seq_Update_LengthRec(s:Seq, k:int, a:A) ensures 0 <= k && k < Seq_Length(s) ==> Seq_Length(Seq_Update(s, k, a)) == Seq_Length(s); { reveal_Seq_Length(){:typearg "A"}; reveal_Seq_Update(){:typearg "A"}; Seq_Cons_All(); if (s.Seq_Cons?) { Seq_Seq(s); Seq_Update_LengthRec(s.tl, k - 1, a); } } ghost method Seq_Update_Length() ensures forall s:Seq, k:int, a:A {:trigger Seq_Length(Seq_Update(s, k, a))}:: 0 <= k && k < Seq_Length(s) ==> Seq_Length(Seq_Update(s, k, a)) == Seq_Length(s); { forall s:Seq, k:int, a:A ensures 0 <= k && k < Seq_Length(s) ==> Seq_Length(Seq_Update(s, k, a)) == Seq_Length(s); { Seq_Update_LengthRec(s, k, a); } } ghost method Seq_Index_UpdateRec(s:Seq, k:int, a:A, n:int) ensures 0 <= n && n < Seq_Length(s) ==> (k == n ==> Seq_Index(Seq_Update(s, k, a), n) == a) && (k != n ==> Seq_Index(Seq_Update(s, k, a), n) == Seq_Index(s, n)); { reveal_Seq_Length(){:typearg "A"}; reveal_Seq_Singleton(){:typearg "A"}; reveal_Seq_Build(){:typearg "A"}; reveal_Seq_Index(){:typearg "A"}; reveal_Seq_Update(){:typearg "A"}; Seq_Cons_All(); if (s.Seq_Cons?) { Seq_Seq(s); Seq_Index_UpdateRec(s.tl, k - 1, a, n - 1); } } ghost method Seq_Index_Update() ensures (forall s:Seq, k:int, a:A, n:int {:trigger Seq_Index(Seq_Update(s, k, a), n)}:: 0 <= n && n < Seq_Length(s) ==> (k == n ==> Seq_Index(Seq_Update(s, k, a), n) == a) && (k != n ==> Seq_Index(Seq_Update(s, k, a), n) == Seq_Index(s, n))); { forall s:Seq, k:int, a:A, n:int ensures 0 <= n && n < Seq_Length(s) ==> (k == n ==> Seq_Index(Seq_Update(s, k, a), n) == a) && (k != n ==> Seq_Index(Seq_Update(s, k, a), n) == Seq_Index(s, n)); { Seq_Index_UpdateRec(s, k, a, n); } } function{:private} Seq_Equal_Trigger(i:int):bool { true } ghost method Seq_Equal_EquivRec(s0:Seq, s1:Seq, n:int) requires Seq_Length(s0) == Seq_Length(s1); requires (forall i:int::Seq_Equal_Trigger(i) && n <= i < n + Seq_Length(s0) ==> Seq_Index(s0, i - n) == Seq_Index(s1, i - n)); ensures s0 == s1; { reveal_Seq_Length(){:typearg "A"}; reveal_Seq_Index(){:typearg "A"}; Seq_Empty_FromZero(); Seq_Cons_All(); if (s0.Seq_Cons? && s1.Seq_Cons?) { Seq_Seq(s0); Seq_Seq(s1); Seq_Equal_EquivRec(s0.tl, s1.tl, n + 1); assert Seq_Equal_Trigger(n); } } ghost method{:loop_lemma} Seq_Equal_Equiv() ensures (forall s0:Seq, s1:Seq {:trigger Seq_Equal(s0, s1)}::Seq_Equal(s0, s1) ==> s0 == s1); ensures (forall s0:Seq, s1:Seq {:trigger Seq_Equal(s0, s1)}:: Seq_Equal(s0, s1) <==> Seq_Length(s0) == Seq_Length(s1) && (forall i:int {:trigger Seq_Index(s0, i)}{:trigger Seq_Index(s1, i)}:: 0 <= i && i < Seq_Length(s0) ==> Seq_Index(s0, i) == Seq_Index(s1, i))); { forall s0:Seq, s1:Seq ensures Seq_Equal(s0, s1) <==> Seq_Length(s0) == Seq_Length(s1) && (forall i:int::0 <= i && i < Seq_Length(s0) ==> Seq_Index(s0, i) == Seq_Index(s1, i)); { if ( Seq_Length(s0) == Seq_Length(s1) && (forall i:int::0 <= i && i < Seq_Length(s0) ==> Seq_Index(s0, i) == Seq_Index(s1, i))) { Seq_Equal_EquivRec(s0, s1, 0); } } } ghost method Seq_Take_LengthRec(s:Seq, n:int) ensures 0 <= n ==> (n <= Seq_Length(s) ==> Seq_Length(Seq_Take(s, n)) == n) && (Seq_Length(s) < n ==> Seq_Length(Seq_Take(s, n)) == Seq_Length(s)); { reveal_Seq_Length(){:typearg "A"}; reveal_Seq_Take(){:typearg "A"}; Seq_Cons_All(); if (s.Seq_Cons?) { Seq_Seq(s); Seq_Take_LengthRec(s.tl, n - 1); } } ghost method Seq_Take_Length() ensures forall s:Seq, n:int {:trigger Seq_Length(Seq_Take(s, n))}::0 <= n ==> (n <= Seq_Length(s) ==> Seq_Length(Seq_Take(s, n)) == n) && (Seq_Length(s) < n ==> Seq_Length(Seq_Take(s, n)) == Seq_Length(s)); { forall s:Seq, n:int ensures 0 <= n ==> (n <= Seq_Length(s) ==> Seq_Length(Seq_Take(s, n)) == n) && (Seq_Length(s) < n ==> Seq_Length(Seq_Take(s, n)) == Seq_Length(s)); { Seq_Take_LengthRec(s, n); } } ghost method Seq_Take_IndexRec(s:Seq, n:int, i:int) ensures 0 <= i < n && i < Seq_Length(s) ==> Seq_Index(Seq_Take(s, n), i) == Seq_Index(s, i); { reveal_Seq_Length(){:typearg "A"}; reveal_Seq_Index(){:typearg "A"}; reveal_Seq_Take(){:typearg "A"}; Seq_Cons_All(); if (s.Seq_Cons?) { Seq_Seq(s); Seq_Take_IndexRec(s.tl, n - 1, i - 1); } } ghost method Seq_Take_Index() ensures forall s:Seq, n:int, i:int {:trigger Seq_Index(Seq_Take(s, n), i)}:: 0 <= i < n && i < Seq_Length(s) ==> Seq_Index(Seq_Take(s, n), i) == Seq_Index(s, i); { forall s:Seq, n:int, i:int ensures 0 <= i < n && i < Seq_Length(s) ==> Seq_Index(Seq_Take(s, n), i) == Seq_Index(s, i); { Seq_Take_IndexRec(s, n, i); } } ghost method Seq_Drop_LengthRec(s:Seq, n:int) ensures 0 <= n ==> (n <= Seq_Length(s) ==> Seq_Length(Seq_Drop(s, n)) == Seq_Length(s) - n) && (Seq_Length(s) < n ==> Seq_Length(Seq_Drop(s, n)) == 0); { reveal_Seq_Length(){:typearg "A"}; reveal_Seq_Drop(){:typearg "A"}; Seq_Cons_All(); if (s.Seq_Cons?) { Seq_Seq(s); Seq_Drop_LengthRec(s.tl, n - 1); } } ghost method Seq_Drop_Length() ensures (forall s:Seq, n:int {:trigger Seq_Length(Seq_Drop(s, n))}::0 <= n ==> (n <= Seq_Length(s) ==> Seq_Length(Seq_Drop(s, n)) == INTERNAL_sub_raw(Seq_Length(s), n)) && (Seq_Length(s) < n ==> Seq_Length(Seq_Drop(s, n)) == 0)); { forall s:Seq, n:int ensures 0 <= n ==> (n <= Seq_Length(s) ==> Seq_Length(Seq_Drop(s, n)) == Seq_Length(s) - n) && (Seq_Length(s) < n ==> Seq_Length(Seq_Drop(s, n)) == 0); { Seq_Drop_LengthRec(s, n); } } ghost method Seq_Drop_IndexRec(s:Seq, n:int, i:int) ensures 0 <= n && 0 <= i ==> Seq_Index(Seq_Drop(s, n), i) == Seq_Index(s, i + n); { reveal_Seq_Index(){:typearg "A"}; reveal_Seq_Drop(){:typearg "A"}; Seq_Cons_All(); if (s.Seq_Cons?) { Seq_Seq(s); Seq_Drop_IndexRec(s.tl, n - 1, i); } } ghost method Seq_Drop_Index() ensures forall s:Seq, n:int, i:int {:trigger Seq_Index(Seq_Drop(s, n), i)}:: 0 <= n && 0 <= i && i < Seq_Length(s) - n ==> Seq_Index(Seq_Drop(s, n), i) == Seq_Index(s, INTERNAL_add_raw(i, n)); { forall s:Seq, n:int, i:int ensures 0 <= n && 0 <= i && i < Seq_Length(s) - n ==> Seq_Index(Seq_Drop(s, n), i) == Seq_Index(s, i + n); { Seq_Drop_IndexRec(s, n, i); } } function{:private} Seq_FromArrayRange(a:INTERNAL_ArrayElems, j:int, k:int):Seq decreases k - j; { if j < k then Seq_Cons(INTERNAL_array_elems_index(a, j), Seq_FromArrayRange(a, j + 1, k)) else Seq_Nil() } function{:private}{:opaque} Seq_FromArrayElems(a:INTERNAL_ArrayElems, len:int):Seq { Seq_FromArrayRange(a, 0, len) } //- declared public so that old(a[..]) == a[..] is more evident across calls that don't modify a function Seq_FromArray(a:array):Seq { Seq_FromArrayElems(INTERNAL_array_elems(a), a.Length) } function{:private} Seq_FromArrayRange_INTERNAL_HEAP(heap:INTERNAL_AbsMem, a:array, j:int, k:int):Seq function{:private} Seq_FromArray_INTERNAL_HEAP(heap:INTERNAL_AbsMem, a:array):Seq ghost method Seq_FromArray_LengthRec(a:INTERNAL_ArrayElems, j:int, k:int) ensures Seq_Length(Seq_FromArrayRange(a, j, k)) == if j <= k then k - j else 0; decreases k - j; { reveal_Seq_Length(){:typearg "int"}; Seq_Cons_All(); if (j < k) { Seq_FromArray_LengthRec(a, j + 1, k); } } ghost method Seq_FromArray_Length() ensures forall INTERNAL_absMem:INTERNAL_AbsMem, a:array {:trigger Seq_Length(Seq_FromArray(a))}:: a.Length >= 0 ==> Seq_Length(Seq_FromArray(a)) == a.Length; ensures forall INTERNAL_absMem:INTERNAL_AbsMem, a:array {:trigger Seq_Length(Seq_FromArray(a))}:: Seq_Length(Seq_FromArray(a)) > 0 ==> Seq_Length(Seq_FromArray(a)) == a.Length; { reveal_Seq_FromArrayElems(); forall INTERNAL_absMem:INTERNAL_AbsMem, a:array ensures a.Length >= 0 ==> Seq_Length(Seq_FromArray(a)) == a.Length; ensures Seq_Length(Seq_FromArray(a)) > 0 ==> Seq_Length(Seq_FromArray(a)) == a.Length; { Seq_FromArray_LengthRec(INTERNAL_array_elems(a), 0, a.Length); } } ghost method Seq_FromArray_IndexRec(a:INTERNAL_ArrayElems, i:int, j:int, k:int) ensures 0 <= j <= i < k ==> Seq_Index(Seq_FromArrayRange(a, j, k), i - j) == INTERNAL_array_elems_index(a, i); decreases i - j; { reveal_Seq_Length(){:typearg "int"}; reveal_Seq_Index(){:typearg "int"}; Seq_Cons_All(); if (j < i) { Seq_FromArray_IndexRec(a, i, j + 1, k); } } ghost method Seq_FromArray_Index() ensures forall INTERNAL_absMem:INTERNAL_AbsMem, a:array, i:int {:trigger Seq_Index(Seq_FromArray(a), i)} {:trigger Seq_FromArray(a), a[i]}:: 0 <= i < Seq_Length(Seq_FromArray(a)) ==> Seq_Index(Seq_FromArray(a), i) == a[i]; { reveal_Seq_FromArrayElems(); forall INTERNAL_absMem:INTERNAL_AbsMem, a:array, i:int ensures 0 <= i < Seq_Length(Seq_FromArray(a)) ==> Seq_Index(Seq_FromArray(a), i) == a[i]; { if (0 <= i < Seq_Length(Seq_FromArray(a))) { Seq_FromArray_LengthRec(INTERNAL_array_elems(a), 0, a.Length); Seq_FromArray_IndexRec(INTERNAL_array_elems(a), i, 0, a.Length); } } } ghost method Seq_FromArray_UpdateRec(a:INTERNAL_ArrayElems, i:int, v:int, j:int, k:int) ensures 0 <= j <= i < k ==> Seq_FromArrayRange(INTERNAL_array_elems_update(a, i, v), j, k) == Seq_Update(Seq_FromArrayRange(a, j, k), i - j, v); ensures i < j <= k ==> Seq_FromArrayRange(INTERNAL_array_elems_update(a, i, v), j, k) == Seq_FromArrayRange(a, j, k); decreases k - j; { reveal_Seq_Update(){:typearg "int"}; if (j < k) { Seq_FromArray_UpdateRec(a, i, v, j + 1, k); Seq_Cons_All(); } } ghost method Seq_FromArray_Update() ensures forall INTERNAL_absMem:INTERNAL_AbsMem, a:array, i:int, v:int {:trigger Seq_FromArray_INTERNAL_HEAP(INTERNAL_array_update(a, i, v), a)}:: 0 <= i < a.Length ==> Seq_FromArray_INTERNAL_HEAP(INTERNAL_array_update(a, i, v), a) == Seq_Update(Seq_FromArray(a), i, v); { reveal_Seq_FromArrayElems(); forall INTERNAL_absMem:INTERNAL_AbsMem, a:array, i:int, v:int ensures 0 <= i < a.Length ==> Seq_FromArray_INTERNAL_HEAP(INTERNAL_array_update(a, i, v), a) == Seq_Update(Seq_FromArray(a), i, v); { if (0 <= i < a.Length) { Seq_FromArray_UpdateRec(INTERNAL_array_elems(a), i, v, 0, a.Length); } } } /* axiom (forall h: HeapType, o: ref, f: Field alpha, v: alpha, a: ref :: { Seq#FromArray(update(h, o, f, v), a) } o != a ==> Seq#FromArray(update(h, o, f, v), a) == Seq#FromArray(h, a) ); */ ghost method Seq_Append_TakeDropRec(s0:Seq, s1:Seq) ensures Seq_Take(Seq_Append(s0, s1), Seq_Length(s0)) == s0; ensures Seq_Drop(Seq_Append(s0, s1), Seq_Length(s0)) == s1; { reveal_Seq_Length(){:typearg "A"}; reveal_Seq_Append(){:typearg "A"}; reveal_Seq_Take(){:typearg "A"}; reveal_Seq_Drop(){:typearg "A"}; Seq_Cons_All(); if (s0.Seq_Cons?) { Seq_Seq(s0); Seq_Append_TakeDropRec(s0.tl, s1); } } ghost method Seq_Append_TakeDrop() ensures forall s0:Seq, s1:Seq {:trigger Seq_Append(s0, s1)}:: //- default Dafny trigger // Seq_Take(Seq_Append(s0, s1), Seq_Length(s0)) == s0 && Seq_Drop(Seq_Append(s0, s1), Seq_Length(s0)) == s1; { forall s0:Seq, s1:Seq ensures Seq_Take(Seq_Append(s0, s1), Seq_Length(s0)) == s0 && Seq_Drop(Seq_Append(s0, s1), Seq_Length(s0)) == s1; { Seq_Append_TakeDropRec(s0, s1); } } ghost method Seq_Append_TakeDrop_Restricted() ensures forall s0:Seq, s1:Seq //- [ckh] The default Dafny trigger is very liberal here, but I've seen some slow performance and timeouts, so I made it more restrictive {:trigger Seq_Take(Seq_Append(s0, s1), Seq_Length(s0))} {:trigger Seq_Drop(Seq_Append(s0, s1), Seq_Length(s0))} :: Seq_Take(Seq_Append(s0, s1), Seq_Length(s0)) == s0 && Seq_Drop(Seq_Append(s0, s1), Seq_Length(s0)) == s1; { forall s0:Seq, s1:Seq ensures Seq_Take(Seq_Append(s0, s1), Seq_Length(s0)) == s0 && Seq_Drop(Seq_Append(s0, s1), Seq_Length(s0)) == s1; { Seq_Append_TakeDropRec(s0, s1); } } ghost method Seq_Update_CommuteTake1Rec(s:Seq, i:int, a:A, n:int) ensures 0 <= i && i < n && n <= Seq_Length(s) ==> Seq_Take(Seq_Update(s, i, a), n) == Seq_Update(Seq_Take(s, n), i, a); { reveal_Seq_Length(){:typearg "A"}; reveal_Seq_Update(){:typearg "A"}; reveal_Seq_Take(){:typearg "A"}; Seq_Cons_All(); if (s.Seq_Cons?) { Seq_Seq(s); Seq_Update_CommuteTake1Rec(s.tl, i - 1, a, n - 1); } } ghost method Seq_Update_CommuteTake1() ensures forall s:Seq, i:int, a:A, n:int {:trigger Seq_Take(Seq_Update(s, i, a), n)}:: 0 <= i && i < n && n <= Seq_Length(s) ==> Seq_Take(Seq_Update(s, i, a), n) == Seq_Update(Seq_Take(s, n), i, a); { forall s:Seq, i:int, a:A, n:int ensures 0 <= i && i < n && n <= Seq_Length(s) ==> Seq_Take(Seq_Update(s, i, a), n) == Seq_Update(Seq_Take(s, n), i, a); { Seq_Update_CommuteTake1Rec(s, i, a, n); } } ghost method Seq_Update_CommuteTake2Rec(s:Seq, i:int, a:A, n:int) ensures n <= i && i < Seq_Length(s) ==> Seq_Take(Seq_Update(s, i, a), n) == Seq_Take(s, n); { reveal_Seq_Length(){:typearg "A"}; reveal_Seq_Update(){:typearg "A"}; reveal_Seq_Take(){:typearg "A"}; Seq_Cons_All(); if (s.Seq_Cons?) { Seq_Seq(s); Seq_Update_CommuteTake2Rec(s.tl, i - 1, a, n - 1); } } ghost method Seq_Update_CommuteTake2() ensures forall s:Seq, i:int, a:A, n:int {:trigger Seq_Take(Seq_Update(s, i, a), n)}:: n <= i && i < Seq_Length(s) ==> Seq_Take(Seq_Update(s, i, a), n) == Seq_Take(s, n); { forall s:Seq, i:int, a:A, n:int ensures n <= i && i < Seq_Length(s) ==> Seq_Take(Seq_Update(s, i, a), n) == Seq_Take(s, n); { Seq_Update_CommuteTake2Rec(s, i, a, n); } } ghost method Seq_Update_CommuteDrop1Rec(s:Seq, i:int, a:A, n:int) ensures 0 <= n && n < i && i <= Seq_Length(s) ==> Seq_Drop(Seq_Update(s, i, a), n) == Seq_Update(Seq_Drop(s, n), i - n, a); { reveal_Seq_Length(){:typearg "A"}; reveal_Seq_Update(){:typearg "A"}; reveal_Seq_Drop(){:typearg "A"}; Seq_Cons_All(); if (s.Seq_Cons?) { Seq_Seq(s); Seq_Update_CommuteDrop1Rec(s.tl, i - 1, a, n - 1); } } ghost method Seq_Update_CommuteDrop1() ensures forall s:Seq, i:int, a:A, n:int {:trigger Seq_Drop(Seq_Update(s, i, a), n)}:: 0 <= n && n < i && i <= Seq_Length(s) ==> Seq_Drop(Seq_Update(s, i, a), n) == Seq_Update(Seq_Drop(s, n), i - n, a); { forall s:Seq, i:int, a:A, n:int ensures 0 <= n && n < i && i <= Seq_Length(s) ==> Seq_Drop(Seq_Update(s, i, a), n) == Seq_Update(Seq_Drop(s, n), i - n, a); { Seq_Update_CommuteDrop1Rec(s, i, a, n); } } ghost method Seq_Update_CommuteDrop2Rec(s:Seq, i:int, a:A, n:int) ensures 0 <= i && i < n && n < Seq_Length(s) ==> Seq_Drop(Seq_Update(s, i, a), n) == Seq_Drop(s, n); { reveal_Seq_Length(){:typearg "A"}; reveal_Seq_Update(){:typearg "A"}; reveal_Seq_Drop(){:typearg "A"}; Seq_Cons_All(); if (s.Seq_Cons?) { Seq_Seq(s); Seq_Update_CommuteDrop2Rec(s.tl, i - 1, a, n - 1); } } ghost method Seq_Update_CommuteDrop2() ensures forall s:Seq, i:int, a:A, n:int {:trigger Seq_Drop(Seq_Update(s, i, a), n)}:: 0 <= i && i < n && n < Seq_Length(s) ==> Seq_Drop(Seq_Update(s, i, a), n) == Seq_Drop(s, n); { forall s:Seq, i:int, a:A, n:int ensures 0 <= i && i < n && n < Seq_Length(s) ==> Seq_Drop(Seq_Update(s, i, a), n) == Seq_Drop(s, n); { Seq_Update_CommuteDrop2Rec(s, i, a, n); } } ghost method Seq_Build_CommuteDropRec(s:Seq, a:A, n:int) ensures 0 <= n && n <= Seq_Length(s) ==> Seq_Drop(Seq_Build(s, a), n) == Seq_Build(Seq_Drop(s, n), a); { reveal_Seq_Length(){:typearg "A"}; reveal_Seq_Singleton(){:typearg "A"}; reveal_Seq_Build(){:typearg "A"}; reveal_Seq_Drop(){:typearg "A"}; Seq_Cons_All(); if (s.Seq_Cons?) { Seq_Seq(s); Seq_Build_CommuteDropRec(s.tl, a, n - 1); } } ghost method Seq_Build_CommuteDrop() ensures forall s:Seq, a:A, n:int {:trigger Seq_Drop(Seq_Build(s, a), n)}:: 0 <= n && n <= Seq_Length(s) ==> Seq_Drop(Seq_Build(s, a), n) == Seq_Build(Seq_Drop(s, n), a); { forall s:Seq, a:A, n:int ensures 0 <= n && n <= Seq_Length(s) ==> Seq_Drop(Seq_Build(s, a), n) == Seq_Build(Seq_Drop(s, n), a); { Seq_Build_CommuteDropRec(s, a, n); } } ghost method Seq_Take_Empty() ensures Seq_Take(Seq_Empty(), 0) == Seq_Empty(); { reveal_Seq_Take(){:typearg "A"}; } ghost method Seq_Drop_Empty() ensures Seq_Drop(Seq_Empty(), 0) == Seq_Empty(); { reveal_Seq_Drop(){:typearg "A"}; } ghost method lemma_Seq_Case(s:Seq) ensures s.Seq_Cons? <==> Seq_Length(s) > 0; ensures s.Seq_Cons? <==> !s.Seq_Nil?; { reveal_Seq_Length(){:typearg "A"}; Seq_Seq(s); } ghost method lemma_Seq_Cons(a:A, s:Seq) ensures Seq_Equal(Seq_Cons(a, s), Seq_Append(Seq_Build(Seq_Empty(), a), s)); { reveal_Seq_Length(){:typearg "A"}; reveal_Seq_Build(){:typearg "A"}; reveal_Seq_Singleton(){:typearg "A"}; reveal_Seq_Append(){:typearg "A"}; Seq_Cons_All(); Seq_Seq(Seq_Nil()); Seq_Seq(s); } ghost method lemma_Seq_Head(s:Seq) ensures Seq_Length(s) > 0 ==> s.hd == Seq_Index(s, 0); { reveal_Seq_Length(){:typearg "A"}; reveal_Seq_Index(){:typearg "A"}; } ghost method lemma_Seq_Tail(s:Seq) ensures Seq_Length(s) > 0 ==> Seq_Equal(s.tl, Seq_Drop(s, 1)); { reveal_Seq_Length(){:typearg "A"}; reveal_Seq_Drop(){:typearg "A"}; lemma_Seq_Case(s); Seq_Seq(s); } method seq_Length(s:Seq) returns(n:int) ensures n == Seq_Length(s); { reveal_Seq_Length(){:typearg "A"}; Seq_Cons_All(); n := 0; var iter := s; while (iter.Seq_Cons?) decreases Seq_Length(iter); invariant n + Seq_Length(iter) == Seq_Length(s); { Seq_Seq(iter); iter := iter.tl; n := n + 1; } } method seq_Empty() returns(s:Seq) ensures s == Seq_Empty(); { Seq_Cons_All(); s := Seq_Nil(); } method seq_Build(s:Seq, a:A) returns(r:Seq) ensures Seq_Equal(r, Seq_Build(s, a)); { lemma_Seq_Cons(a, Seq_Nil()); r := seq_Append(s, Seq_Cons(a, Seq_Nil())); } method seq_Index(s:Seq, k:int) returns(a:A) requires 0 <= k < Seq_Length(s); ensures a == Seq_Index(s, k); { Seq_Cons_All(); var iter := s; var j := k; while (j != 0) decreases j; invariant 0 <= j < Seq_Length(iter); invariant Seq_Index(iter, j) == Seq_Index(s, k); { j := j - 1; lemma_Seq_Tail(iter); iter := iter.tl; } lemma_Seq_Head(iter); a := iter.hd; } method seq_Append0(s0:Seq) returns(rev0:Seq) ensures Seq_Length(rev0) == Seq_Length(s0); ensures forall i {:trigger Seq_Index(rev0, i)}::0 <= i < Seq_Length(rev0) ==> Seq_Index(rev0, i) == Seq_Index(s0, Seq_Length(rev0) - i - 1); { rev0 := Seq_Nil(); var iter := s0; reveal_Seq_Drop(){:typearg "A"}; while (iter.Seq_Cons?) decreases Seq_Length(iter); invariant Seq_Length(rev0) + Seq_Length(iter) == Seq_Length(s0); invariant forall i::0 <= i < Seq_Length(rev0) ==> Seq_Index(rev0, i) == Seq_Index(s0, Seq_Length(rev0) - i - 1); invariant Seq_Equal(iter, Seq_Drop(s0, Seq_Length(s0) - Seq_Length(iter))); { lemma_Seq_Case(iter); lemma_Seq_Head(iter); lemma_Seq_Tail(iter); lemma_Seq_Cons(iter.hd, rev0); rev0 := Seq_Cons(iter.hd, rev0); iter := iter.tl; } lemma_Seq_Case(iter); } ghost method lemma_Seq_Length(s:Seq) ensures Seq_Length(s) >= 0; { } method{:dafnycc_no_lemmas} seq_Append(s0:Seq, s1:Seq) returns(s:Seq) ensures Seq_Equal(s, Seq_Append(s0, s1)); { assert unroll(0); assert unroll(1); lemma_Seq_Length(s0); lemma_Seq_Length(s1); var rev0 := seq_Append0(s0); s := s1; var iter := rev0; calc { Seq_Equal(s, Seq_Append(Seq_Drop(s0, Seq_Length(iter)), s1)); { Seq_Drop_LengthRec(s0, Seq_Length(iter)); } { Seq_Empty_FromZero(); } Seq_Equal(s, Seq_Append(Seq_Empty(), s1)); Seq_Equal(s, Seq_Append(Seq_Nil(), s1)); { Seq_Seq(Seq_Nil()); } { reveal_Seq_Append(){:typearg "A"}; } Seq_Equal(s, s1); { Seq_Equal_Equiv(); } true; } while (iter.Seq_Cons?) decreases Seq_Length(iter); invariant Seq_Length(s) + Seq_Length(iter) == Seq_Length(s0) + Seq_Length(s1); invariant forall i::0 <= i < Seq_Length(iter) ==> Seq_Index(iter, i) == Seq_Index(s0, Seq_Length(iter) - i - 1); invariant Seq_Equal(s, Seq_Append(Seq_Drop(s0, Seq_Length(iter)), s1)); { lemma_Seq_Case(iter); lemma_Seq_Head(iter); lemma_Seq_Tail(iter); lemma_Seq_Cons(iter.hd, s); s := Seq_Cons(iter.hd, s); iter := iter.tl; Seq_Empty_ToZero(); Seq_Empty_FromZero(); Seq_Build_Length(); Seq_Build_Index(); Seq_Append_Length(); Seq_Append_Index(); Seq_Equal_Equiv(); Seq_Drop_Length(); Seq_Drop_Index(); } calc { Seq_Equal(s, Seq_Append(Seq_Drop(s0, Seq_Length(iter)), s1)); { lemma_Seq_Length(iter); } { lemma_Seq_Case(iter); } Seq_Equal(s, Seq_Append(Seq_Drop(s0, 0), s1)); { Seq_Drop_LengthRec(s0, 0); } { Seq_Drop_Index(); } { Seq_Equal_EquivRec(s0, Seq_Drop(s0, 0), 0); } Seq_Equal(s, Seq_Append(s0, s1)); } } method seq_Update(s:Seq, k:int, a:A) returns(r:Seq) requires 0 <= k < Seq_Length(s); ensures Seq_Equal(r, Seq_Update(s, k, a)); { Seq_Cons_All(); var iter := s; var j := k; var rev0 := Seq_Nil(); while (j != 0) decreases j; invariant 0 <= j; invariant k == j + Seq_Length(rev0); invariant Seq_Length(rev0) + Seq_Length(iter) == Seq_Length(s); invariant forall i {:trigger Seq_Index(rev0, i)}::0 <= i < Seq_Length(rev0) ==> Seq_Index(rev0, i) == Seq_Index(s, Seq_Length(rev0) - i - 1); invariant Seq_Equal(iter, Seq_Drop(s, Seq_Length(s) - Seq_Length(iter))); { lemma_Seq_Head(iter); lemma_Seq_Tail(iter); lemma_Seq_Cons(iter.hd, rev0); j := j - 1; rev0 := Seq_Cons(iter.hd, rev0); iter := iter.tl; } lemma_Seq_Tail(iter); r := iter.tl; lemma_Seq_Cons(a, r); r := Seq_Cons(a, r); iter := rev0; while (iter.Seq_Cons?) decreases Seq_Length(iter); invariant Seq_Length(r) + Seq_Length(iter) == Seq_Length(s); invariant forall i {:trigger Seq_Index(iter, i)}::0 <= i < Seq_Length(iter) ==> Seq_Index(iter, i) == Seq_Index(s, Seq_Length(iter) - i - 1); invariant Seq_Equal(r, Seq_Append(Seq_Drop(Seq_Take(s, k), Seq_Length(iter)), Seq_Append(Seq_Build(Seq_Empty(), a), Seq_Drop(s, k + 1)))); { Seq_Seq(iter); lemma_Seq_Case(iter); lemma_Seq_Head(iter); lemma_Seq_Tail(iter); lemma_Seq_Cons(iter.hd, r); r := Seq_Cons(iter.hd, r); iter := iter.tl; } lemma_Seq_Case(iter); } method seq_Take(s:Seq, k:int) returns(r:Seq) requires 0 <= k <= Seq_Length(s); ensures Seq_Equal(r, Seq_Take(s, k)); { Seq_Cons_All(); var iter := s; var j := k; var rev0 := Seq_Nil(); while (j != 0) decreases j; invariant 0 <= j; invariant k == j + Seq_Length(rev0); invariant Seq_Length(rev0) + Seq_Length(iter) == Seq_Length(s); invariant forall i {:trigger Seq_Index(rev0, i)}::0 <= i < Seq_Length(rev0) ==> Seq_Index(rev0, i) == Seq_Index(s, Seq_Length(rev0) - i - 1); invariant Seq_Equal(iter, Seq_Drop(s, Seq_Length(s) - Seq_Length(iter))); { lemma_Seq_Head(iter); lemma_Seq_Tail(iter); lemma_Seq_Cons(iter.hd, rev0); j := j - 1; rev0 := Seq_Cons(iter.hd, rev0); iter := iter.tl; } iter := rev0; r := Seq_Nil(); while (iter.Seq_Cons?) decreases Seq_Length(iter); invariant Seq_Length(r) + Seq_Length(iter) == k; invariant forall i {:trigger Seq_Index(iter, i)}::0 <= i < Seq_Length(iter) ==> Seq_Index(iter, i) == Seq_Index(s, Seq_Length(iter) - i - 1); invariant Seq_Equal(r, Seq_Drop(Seq_Take(s, k), Seq_Length(iter))); { Seq_Seq(iter); lemma_Seq_Case(iter); lemma_Seq_Head(iter); lemma_Seq_Tail(iter); lemma_Seq_Cons(iter.hd, r); r := Seq_Cons(iter.hd, r); iter := iter.tl; } lemma_Seq_Case(iter); } method seq_Drop(s:Seq, k:int) returns(r:Seq) requires 0 <= k <= Seq_Length(s); ensures Seq_Equal(r, Seq_Drop(s, k)); { Seq_Cons_All(); var iter := s; var j := k; var rev0 := Seq_Nil(); while (j != 0) decreases j; invariant 0 <= j; invariant k == j + Seq_Length(rev0); invariant Seq_Length(rev0) + Seq_Length(iter) == Seq_Length(s); invariant forall i {:trigger Seq_Index(rev0, i)}::0 <= i < Seq_Length(rev0) ==> Seq_Index(rev0, i) == Seq_Index(s, Seq_Length(rev0) - i - 1); invariant Seq_Equal(iter, Seq_Drop(s, Seq_Length(s) - Seq_Length(iter))); { lemma_Seq_Head(iter); lemma_Seq_Tail(iter); lemma_Seq_Cons(iter.hd, rev0); j := j - 1; rev0 := Seq_Cons(iter.hd, rev0); iter := iter.tl; } r := iter; } method seq_TakeDrop(s:Seq, k1:int, k2:int) returns(r:Seq) requires 0 <= k1 <= k2 <= Seq_Length(s); ensures Seq_Equal(r, Seq_Drop(Seq_Take(s, k2), k1)); { r := seq_Drop(s, k1); r := seq_Take(r, k2 - k1); } method seq_Equal(s1:Seq, s2:Seq) returns(b:bool) ensures b == Seq_Equal(s1, s2); { Seq_Cons_All(); var iter1 := s1; var iter2 := s2; while (iter1.Seq_Cons? && iter2.Seq_Cons?) decreases Seq_Length(iter1); invariant Seq_Length(iter1) <= Seq_Length(s1); invariant Seq_Length(iter2) <= Seq_Length(s2); invariant Seq_Equal(Seq_Take(s1, Seq_Length(s1) - Seq_Length(iter1)), Seq_Take(s2, Seq_Length(s2) - Seq_Length(iter2))); invariant Seq_Equal(iter1, Seq_Drop(s1, Seq_Length(s1) - Seq_Length(iter1))); invariant Seq_Equal(iter2, Seq_Drop(s2, Seq_Length(s2) - Seq_Length(iter2))); { Seq_Seq(iter1); lemma_Seq_Head(iter1); lemma_Seq_Tail(iter1); lemma_Seq_Head(iter2); lemma_Seq_Tail(iter2); if (iter1.hd != iter2.hd) { b := false; return; } ghost var n1 := Seq_Length(s1) - Seq_Length(iter1); assert Seq_Equal( Seq_Append(Seq_Take(s1, n1), Seq_Singleton(Seq_Index(s1, n1))), Seq_Take(s1, n1 + 1)); ghost var n2 := Seq_Length(s2) - Seq_Length(iter2); assert Seq_Equal( Seq_Append(Seq_Take(s2, n2), Seq_Singleton(Seq_Index(s2, n2))), Seq_Take(s2, n2 + 1)); iter1 := iter1.tl; iter2 := iter2.tl; } if (iter1.Seq_Nil? && iter2.Seq_Nil?) { b := true; assert Seq_Equal(s1, Seq_Take(s1, Seq_Length(s1))); assert Seq_Equal(s2, Seq_Take(s2, Seq_Length(s2))); return; } b := false; return; } method seq_FromArray(a:array) returns (r:Seq) ensures Seq_Equal(r, Seq_FromArray(a)); { Seq_Cons_All(); r := Seq_Nil(); var j := a.Length; while (j != 0) invariant 0 <= j <= a.Length; invariant r == Seq_FromArrayRange(INTERNAL_array_elems(a), j, a.Length); { j := j - 1; r := Seq_Cons(a[j], r); } reveal_Seq_FromArrayElems(); } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Base/BitVectorLemmasBase.ifc.beat ================================================ //--private-import BaseSpec; //--private-import MemorySpec; //-- //-- //-- //-- //-- //-- Copyright (c) Microsoft Corporation. All rights reserved. //-- module interface BitVectorLemmasBase { function $_Aligned(b:bv32) returns(bool) { $and(b, 3bv32) == 0bv32 } function $_Aligned4k(b:bv32) returns (bool) { $clear_LSBs(12bv32, b) == b } function _bit_index($i:bv32) returns (bool) { $le(0bv32, $i) && $le($i, 31bv32) } function $between(lb:bv32, ub:bv32, val:bv32):bool { $le(lb, val) && $lt(val, ub) } function $get_bit ($i:bv32, $val:bv32) returns (bool) { $and($val, $shl(1bv32, $i)) != 0bv32 } function $set_bit ($i:bv32, $val:bv32) returns (bv32) { $or($val, $shl(1bv32, $i)) } function $clear_bit($i:bv32, $val:bv32) returns (bv32) { $and($val, $neg($shl(1bv32, $i))) } function $clear_LSBs ($i:bv32, $val:bv32) returns (bv32) { $and($val, $neg($sub($shl(1bv32, $i), 1bv32))) } function $select_LSBs ($i:bv32, $val:bv32) returns (bv32) { $and($val, $sub($shl(1bv32, $i), 1bv32)) } function $eq ($x:bv32, $y:bv32) returns (bool) { $le($x, $y) && $le($y, $x) } atomic ghost procedure _const_base(); ensures $sub(1bv32, 1bv32) == 0bv32; ensures $add(1bv32, 1bv32) == 2bv32; ensures $add(2bv32, 1bv32) == 3bv32; ensures $add(2bv32, 2bv32) == 4bv32; ensures $add(4bv32, 1bv32) == 5bv32; ensures $add(5bv32, 1bv32) == 6bv32; ensures $add(5bv32, 2bv32) == 7bv32; ensures $add(5bv32, 3bv32) == 8bv32; ensures $add(5bv32, 4bv32) == 9bv32; ensures $add(5bv32, 5bv32) == 10bv32; ensures $add(5bv32, 6bv32) == 11bv32; ensures $add(5bv32, 7bv32) == 12bv32; ensures $add(5bv32, 8bv32) == 13bv32; ensures $add(7bv32, 8bv32) == 15bv32; ensures $mul(4bv32, 4bv32) == 16bv32; ensures $add(10bv32, 12bv32) == 22bv32; ensures $add(16bv32, 16bv32) == 32bv32; ensures $sub(32bv32, 1bv32) == 31bv32; ensures $add(32bv32, 32bv32) == 64bv32; ensures $sub(64bv32, 1bv32) == 63bv32; ensures $mul(32bv32, 4bv32) == 128bv32; ensures $sub(128bv32, 1bv32) == 127bv32; ensures $mul(16bv32, 16bv32) == 256bv32; ensures $sub(256bv32, 1bv32) == 255bv32; ensures $add(256bv32, 256bv32) == 512bv32; ensures $sub(1024bv32, 1bv32) == 1023bv32; ensures $add(512bv32, 512bv32) == 1024bv32; ensures $mul(64bv32, 64bv32) == 4096bv32; ensures $sub(4096bv32, 1bv32) == 4095bv32; ensures $mul(1024bv32, 1024bv32) == 1048576bv32; ensures $sub(1048576bv32, 1bv32) == 1048575bv32; ensures $mul(1048575bv32, 4096bv32) == 4294963200bv32; ensures $mul(1048576bv32, 4bv32) == 4194304bv32; ensures $mul(256bv32, 256bv32) == 65536bv32; ensures $sub(65536bv32, 1bv32) == 65535bv32; ensures $mul(65536bv32, 32bv32) == 2097152bv32; ensures $sub(2097152bv32, 1bv32) == 2097151bv32; ensures $mul(65536bv32, 256bv32) == 16777216bv32; ensures $sub(16777216bv32, 1bv32) == 16777215bv32; ensures $mul(65536bv32, 512bv32) == 33554432bv32; ensures $sub(33554432bv32, 1bv32) == 33554431bv32; ensures $add(33554432bv32, 33554432bv32) == 67108864bv32; ensures $sub(67108864bv32, 1bv32) == 67108863bv32; ensures $mul(65536bv32, 65535bv32) == 4294901760bv32; ensures $add(4294901760bv32, 65535bv32) == 4294967295bv32; ensures $sub(4294967295bv32, 3bv32) == 4294967292bv32; ensures $mul(33554432bv32, 64bv32) == 2147483648bv32; atomic ghost procedure _shl_1_ge_1(); ensures (forall $x:bv32 :: $le($x, 31bv32) ==> $ge($shl(1bv32, $x), 1bv32) ); atomic ghost procedure _alignment_is_mod4_lemma(); ensures (forall $x:bv32 :: $_Aligned($x) == ($mod($x, 4bv32) == 0bv32)); atomic ghost procedure _alignment_4k_is_mod4096_lemma(); ensures (forall $x:bv32 :: $_Aligned4k($x) == ($mod($x, 4096bv32) == 0bv32)); atomic ghost procedure _alignment_dominance_lemma($ptr:bv32); ensures $ge($shl(1bv32, 12bv32), 1bv32); ensures $_Aligned4k($ptr) ==> $_Aligned($ptr); atomic ghost procedure _lower_bits_dont_matter_lemma($ptr:bv32, $orVal:bv32); requires $le(0bv32, $orVal) && $lt($orVal, 4096bv32); ensures $_Aligned4k($ptr) ==> $clear_LSBs(12bv32, $or($ptr, $orVal)) == $ptr; atomic ghost procedure _get_set_lemma(); ensures (forall $ptr:bv32, $index:bv32 :: { $get_bit($index, $set_bit($index, $ptr)) } _bit_index($index) ==> $get_bit($index, $set_bit($index, $ptr)) == true); atomic ghost procedure _clear_LSBs_lemma(); ensures (forall $ptr:bv32, $amount:bv32, $i:bv32 :: { $get_bit($i, $clear_LSBs($amount, $ptr)) } (_bit_index($amount) && _bit_index($i)) ==> if $lt($i, $amount) then $get_bit($i, $clear_LSBs($amount, $ptr)) == false else $get_bit($i, $clear_LSBs($amount, $ptr)) == $get_bit($i, $ptr) ); atomic ghost procedure _upper_bits_clear_ubound_lemma(); ensures (forall $ptr:bv32, $y:bv32 :: { $select_LSBs($y, $ptr) } ($ge(10bv32, $y) && $ge($y, 0bv32)) ==> $le($select_LSBs($y, $ptr), 1023bv32) ); atomic ghost procedure _upper_bits_clear_lbound_lemma(); ensures (forall $ptr:bv32, $y:bv32 :: { $le(0bv32, $select_LSBs($y, $ptr)) } ($ge(10bv32, $y) && $ge($y, 0bv32)) ==> $le(0bv32, $select_LSBs($y, $ptr))); atomic ghost procedure _clear_less_than_equal_lemma(); ensures (forall $ptr:bv32, $amt:bv32 :: { $le($clear_LSBs($amt, $ptr), $ptr) } _bit_index($amt) ==> $le($clear_LSBs($amt, $ptr), $ptr) ); atomic ghost procedure _clear_12_lemma(); ensures (forall $ptr:bv32 :: { $and($ptr, 4294963200bv32) } $clear_LSBs(12bv32, $ptr) == $and($ptr, 4294963200bv32) ); ensures (forall $ptr:bv32 :: { $add($clear_LSBs(12bv32, $ptr), 4096bv32) } $lt($ptr, 4294963200bv32) ==> $ge($add($clear_LSBs(12bv32, $ptr), 4096bv32), $ptr) ); ensures (forall ptr:bv32, lb:bv32, ub:bv32 :: { $between(lb, ub, $clear_LSBs(12bv32, ptr)) } $_Aligned4k(lb) && $_Aligned4k(ub) && $between(lb, ub, ptr) ==> $between(lb, ub, $clear_LSBs(12bv32, ptr)) ); ensures (forall ptr:bv32, lb:bv32, ub:bv32 :: { $between(lb, ub, $clear_LSBs(12bv32, ptr)) } $_Aligned4k(lb) && $_Aligned4k(ub) && !$between(lb, ub, ptr) ==> !$between(lb, ub, $clear_LSBs(12bv32, ptr)) ); atomic ghost procedure _clear_select_consistent_lemma(); ensures (forall $ptr:bv32, $val:bv32 :: { $clear_LSBs($val, $clear_LSBs($val, $ptr)) } { $select_LSBs($val, $select_LSBs($val, $ptr))} _bit_index($val) ==> ( $clear_LSBs($val, $clear_LSBs($val, $ptr)) == $clear_LSBs($val, $ptr)) && ($select_LSBs($val, $select_LSBs($val, $ptr)) == $select_LSBs($val, $ptr))); atomic ghost procedure _select_non_negative_lemma(); ensures (forall $ptr:bv32, $amt:bv32 :: { $le(0bv32, $select_LSBs($amt, $ptr)) } (_bit_index($amt)) ==> $le(0bv32, $select_LSBs($amt, $ptr)) ); atomic ghost procedure _select_preserves_word_lemma(); ensures (forall $ptr:bv32, $x:bv32 :: { $select_LSBs($x, $ptr) } (_bit_index($x)) ==> $le($select_LSBs($x, $ptr),$ptr)); atomic ghost procedure _and_bounds(); ensures (forall $val:bv32 :: { $and($val, 255bv32) } $le(0bv32, $and($val, 255bv32)) && $lt($and($val, 255bv32), 256bv32)); ensures (forall $val:bv32 :: { $and($val, 15bv32) } $le(0bv32, $and($val, 15bv32)) && $lt($and($val, 15bv32), 16bv32)); atomic ghost procedure _shr_decreases(); ensures (forall $ptr:bv32, $x:bv32 :: { $shr($ptr, $x) } $le($shr($ptr, $x), $ptr)); atomic ghost procedure _shr_preserves_word_lemma(); ensures (forall $ptr:bv32, $x:bv32 :: { $shr($ptr, $x) } ($ge($x, 0bv32)) ==> $le($shr($ptr, $x), $ptr)); atomic ghost procedure _or_with_3_lemma(); ensures (forall $ptr:bv32, $i:bv32:: { $get_bit($i, $or($ptr, 3bv32)) } _bit_index($i) ==> if ($eq($i, 0bv32) || $eq($i, 1bv32)) then $get_bit($i, $or($ptr, 3bv32)) == true else $get_bit($i, $or($ptr, 3bv32)) == $get_bit($i, $ptr)); atomic ghost procedure _or_with_7_lemma(); ensures (forall $ptr:bv32, $i:bv32:: { $get_bit($i, $or($ptr, 7bv32)) } _bit_index($i) ==> if ($eq($i, 0bv32) || $eq($i, 1bv32) || $eq($i, 2bv32)) then $get_bit($i, $or($ptr, 7bv32)) == true else $get_bit($i, $or($ptr, 7bv32)) == $get_bit($i, $ptr)); atomic ghost procedure _or_with_pow2_31_lemma(); ensures (forall $ptr:bv32, $i:bv32:: { $get_bit($i, $or($ptr, 2147483648bv32)) } _bit_index($i) ==> if ($eq($i, 31bv32)) then $get_bit($i, $or($ptr, 2147483648bv32)) == true else $get_bit($i, $or($ptr, 2147483648bv32)) == $get_bit($i, $ptr)); ensures (forall $ptr:bv32 :: { $or($ptr, 2147483648bv32) } $set_bit(31bv32, $ptr) == $or($ptr, 2147483648bv32)); atomic ghost procedure _pointer_pieces_lemma(); ensures (forall $ptr:bv32 :: { $mul(4096bv32, $add($mul($select_LSBs(10bv32, $shr($ptr, 22bv32)), 1024bv32), $select_LSBs(10bv32, $shr($ptr, 12bv32)))) } { $clear_LSBs(12bv32, $ptr) } $mul(4096bv32, $add($mul($select_LSBs(10bv32, $shr($ptr, 22bv32)), 1024bv32), $select_LSBs(10bv32, $shr($ptr, 12bv32)))) == $clear_LSBs(12bv32, $ptr) ); atomic ghost procedure _ptr_offsets_lemma(); ensures (forall $ptr:bv32 :: { $select_LSBs(10bv32, $shr($ptr,12bv32)) } $lt($ptr, 4096bv32) ==> $select_LSBs(10bv32, $shr($ptr, 12bv32)) == 0bv32 ); ensures (forall $ptr:bv32 :: { $select_LSBs(10bv32, $shr($ptr,22bv32)) } $lt($ptr, 4194304bv32) <==> $select_LSBs(10bv32, $shr($ptr,22bv32)) == 0bv32 ); ensures (forall $ptr:bv32 :: { $select_LSBs(10bv32, $shr($ptr,12bv32)) } $select_LSBs(10bv32, $shr($ptr, 12bv32)) != 0bv32 ==> $gt($ptr, 0bv32)); ensures (forall $ptr:bv32 :: { $select_LSBs(10bv32, $shr($ptr,12bv32)) } $ge($ptr, 4096bv32) ==> $select_LSBs(10bv32, $shr($ptr, 12bv32)) != 0bv32 || $select_LSBs(10bv32, $shr($ptr,22bv32)) != 0bv32 ); atomic ghost procedure _ptr_reconstruction_lemma(); ensures (forall ptr:bv32 :: { $or($clear_LSBs(12bv32, ptr), $select_LSBs(12bv32, ptr)) } ptr == $or($clear_LSBs(12bv32, ptr), $select_LSBs(12bv32, ptr)) ); ensures (forall ptr:bv32 :: { $or($select_LSBs(12bv32, ptr), $clear_LSBs(12bv32, ptr)) } ptr == $or($select_LSBs(12bv32, ptr), $clear_LSBs(12bv32, ptr)) ); } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Base/BitVectorLemmasBase.imp.beat ================================================ //-private-import BaseSpec; //-private-import MemorySpec; //- //- //- //- //- //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module implementation BitVectorLemmasBase { implementation _const_base() {} implementation _shl_1_ge_1() {} implementation _alignment_is_mod4_lemma() {} implementation _alignment_4k_is_mod4096_lemma() {} implementation _alignment_dominance_lemma($ptr:bv32) {} implementation _lower_bits_dont_matter_lemma($ptr:bv32, $bitPos:bv32) {} implementation _get_set_lemma() {} implementation _clear_LSBs_lemma() {} implementation _upper_bits_clear_ubound_lemma() {} implementation _upper_bits_clear_lbound_lemma() {} implementation _clear_less_than_equal_lemma() {} implementation _clear_12_lemma() {} implementation _clear_select_consistent_lemma() {} implementation _select_non_negative_lemma() {} implementation _select_preserves_word_lemma() {} implementation _and_bounds() {} implementation _shr_decreases() {} implementation _shr_preserves_word_lemma() {} implementation _or_with_3_lemma() {} implementation _or_with_7_lemma() {} implementation _or_with_pow2_31_lemma() {} implementation _pointer_pieces_lemma() {} implementation _ptr_offsets_lemma() {} implementation _ptr_reconstruction_lemma() {} } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Base/Core.ifc.beat ================================================ //-private-import BaseSpec; //-private-import MemorySpec; //-private-import IoTypesSpec; //-private-import MachineStateSpec; //-private-import AssemblySpec; //-private-import InterruptsSpec; //-private-import IoSpec; //- //- //- //-private-import Partition; //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module interface Core modifies init; { atomic ghost procedure setInit(); requires me == 0; modifies init; ensures init; function LogicalToPhysical(c:core_state, logicalAddr:int):int { LogicalToPhysicalViaSegment(c, DS, logicalAddr) } function LogicalToPhysicalSS(c:core_state, logicalAddr:int):int { LogicalToPhysicalViaSegment(c, SS, logicalAddr) } function LogicalToPhysicalViaSegment(c:core_state, segment_index:int, logicalAddr:int):int { let linearAddr:int := SegmentMap(c.seg_regs[segment_index], logicalAddr) in if paging_enabled(c) then PageMap(linearAddr, ?System, ?Write, c.caches.TLB, c.caches.TLB_activeLabel).<> else linearAddr } function DstPhysicalAddr(r:regs, c:core_state, dst:opn_mem):int { LogicalToPhysical(c, EvalPtr(r, dst)) } function DstPhysicalAddrSS(r:regs, c:core_state, dst:opn_mem):int { LogicalToPhysicalSS(c, EvalPtr(r, dst)) } function PartDstOk(r:regs, c:core_state, m:mem, dst:opn_mem):bool { MemDstOk(r, c, m, dst) && (dst is OMem ==> m.dom[DstPhysicalAddr(r, c, dst)]) } function PartDstOkSS(r:regs, c:core_state, m:mem, dst:opn_mem):bool { DstOkViaSegment(r, c, m, SS, dst) && (dst is OMem ==> m.dom[DstPhysicalAddrSS(r, c, dst)]) } atomic procedure core_Load(my r:regs, const my c:core_state, const linear m:mem, x:int, y:opn_mem) returns(my _r:regs); requires MemSrcOk(r, c, m, y); ensures _r.regs == r.regs[x := EvalMem(r, c, m, y)]; ensures _r.efl == r.efl; ensures word(_r.regs[x]); atomic procedure core_Store(const my r:regs, const my c:core_state, linear m:mem, x:opn_mem, y:opn) returns(linear _m:mem); requires PartDstOk(r, c, m, x); requires SrcOk(y); ensures _m == MemUpdate1(r, c, m, x, Eval(r, y)); ensures word(EvalMem(r, c, _m, x)); atomic procedure core_LoadStack(my r:regs, const my c:core_state, const linear m:mem, x:int, y:opn_mem) returns(my _r:regs); requires SrcOkViaSegment(r, c, m, SS, y); ensures _r.regs == r.regs[x := EvalViaSegment(r, c, m, SS, y)]; ensures _r.efl == r.efl; atomic procedure core_StoreStack(const my r:regs, const my c:core_state, linear m:mem, x:opn_mem, y:opn) returns(linear _m:mem); requires PartDstOkSS(r, c, m, x); ensures _m == StackUpdate1(r, c, m, x, Eval(r, y)); atomic procedure core_Push(my r:regs, const my c:core_state, linear m:mem, v:opn) returns(my _r:regs, linear _m:mem); requires v is OReg && v != OReg(ESP); requires SrcOk(v); requires PartDstOkSS(r, c, m, OMem(MConst(sub(r.regs[ESP], 4)))); requires word(r.regs[ESP]) && r.regs[ESP] >= 4; ensures _r.regs == r.regs[ESP := sub(r.regs[ESP], 4)]; ensures _r.efl == r.efl; ensures _m == StackUpdate1(r, c, m, OMem(MConst(sub(r.regs[ESP], 4))), Eval(r, v)); } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Base/Core.imp.beat ================================================ //-private-import BaseSpec; //-private-import MemorySpec; //-private-import IoTypesSpec; //-private-import MachineStateSpec; //-private-import AssemblySpec; //-private-import InterruptsSpec; //-private-import IoSpec; //- //- //- //-private-import Partition; //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module implementation Core { implementation setInit() { init := true; } implementation core_Load(my r:regs, const my c:core_state, const linear m:mem, x:int, y:opn_mem) returns(my _r:regs) { call _r := instr_Load(r, c, m, x, y); } implementation core_Store(const my r:regs, const my c:core_state, linear m:mem, x:opn_mem, y:opn) returns(linear _m:mem) { call _m := instr_Store(r, c, m, x, y); } implementation core_LoadStack(my r:regs, const my c:core_state, linear m:mem, x:int, y:opn_mem) returns(my _r:regs) { call _r := instr_LoadStack(r, c, m, x, y); } implementation core_StoreStack(const my r:regs, const my c:core_state, const linear m:mem, x:opn_mem, y:opn) returns(linear _m:mem) { call _m := instr_StoreStack(r, c, m, x, y); } implementation core_Push(my r:regs, const my c:core_state, linear m:mem, v:opn) returns(my _r:regs, linear _m:mem) { var dst:opn_mem := OMem(MConst(sub(r.regs[ESP], 4))); call reveal_wrap32(sub(r.regs[ESP], 4)); call reveal_WORD_HI(); {: call _r := instr_SubNoFlags(r, ESP, OConst(4)); call _m := instr_StoreStack(_r, c, m, OMem(MReg(ESP, 0)), v); :} } } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Base/Instructions.ifc.beat ================================================ module interface Instructions { instruction Mov(y:opn) returns(x:reg) { call r := instr_Mov(r, x, y); } instruction Add(x:reg, y:opn) returns(x:reg) ensures InputOutput(r, x, r.regs[x] + Eval(r, y)); { call logical_Add(inout r, x, y); } instruction AddCarry(x:reg, y:opn) returns(x:reg) ensures InputOutput(r, x, let carry:int := if Cf(r.efl) then 1 else 0 in wrap32(r.regs[x] + Eval(r, y) + carry)); { call r := instr_AddCarry(r, x, y); } instruction AddWrap(x:reg, y:opn) returns(x:reg) ensures InputOutput(r, x, wrap32(r.regs[x] + Eval(r, y))); { call r := instr_Add(r, x, y); } instruction Sub(x:reg, y:opn) returns(x:reg) ensures InputOutput(r, x, r.regs[x] - Eval(r, y)); { call logical_Sub(inout r, x, y); } instruction SubWrap(x:reg, y:opn) returns(x:reg) ensures InputOutput(r, x, wrap32(r.regs[x] - Eval(r, y))); { call r := instr_Sub(r, x, y); } instruction Mul(xLo:opn, y:opn) returns(xLo:opn, xHi:opn) { call r := instr_Mul(r, y); } instruction Mul64(xLo:opn, y:opn) returns(xLo:opn, xHi:opn) { call r := instr_Mul64(r, y); } instruction MulWrap(xLo:opn, y:opn) returns(xLo:opn, xHi:opn) { call r := instr_Mul(r, y); } instruction Div(xLo:opn, xHi:opn, y:opn) returns(xLo:opn, xHi:opn) { call r := instr_Div(r, y); } instruction Not(x:reg) returns(x:reg) { call r := instr_Not(r, x); } instruction And(x:reg, y:opn) returns(x:reg) { call r := instr_And(r, x, y); } instruction Or(x:reg, y:opn) returns(x:reg) { call r := instr_Or(r, x, y); } instruction Xor(x:reg, y:opn) returns(x:reg) { call r := instr_Xor(r, x, y); } instruction Shl(x:reg, y:opn) returns(x:reg) { call r := instr_Shl(r, x, y); } instruction Shr(x:reg, y:opn) returns(x:reg) { call r := instr_Shr(r, x, y); } instruction Rol(x:reg, y:opn) returns(x:reg) { call r := instr_Rol(r, x, y); } instruction Ror(x:reg, y:opn) returns(x:reg) { call r := instr_Ror(r, x, y); } instruction AddChecked(x:opn, y:opn) returns(x:reg) ensures InputOutput(r, x, r.regs[x] + Eval(r, y)); { call r := instr_AddChecked(r, x, y); } instruction SubChecked(x:opn, y:opn) returns(x:reg) ensures InputOutput(r, x, r.regs[x] - Eval(r, y)); { call r := instr_SubChecked(r, x, y); } instruction MulChecked(xLo:opn, y:opn) returns(xLo:opn, xHi:opn) { call r := instr_MulChecked(r, y); } instruction Cmp(x:reg, y:opn) { call r := instr_Cmp(r, x, y); } instruction Lea(y:opn_mem_of_int) returns(x:reg) { call r := instr_Lea(r, x, y); } instruction LeaUnchecked(y:opn_mem_of_int) returns(x:reg) { call r := instr_LeaUnchecked(r, x, y); } instruction LeaSignedIndex(base:reg, scale:int, index:reg, offset:opn) returns(x:reg) { call r := instr_LeaSignedIndex(r, x, base, scale, index, offset); } instruction Rdtsc() { call r := instr_Rdtsc(r); } instruction SubLoad(const linear m:mem, x:reg, y:opn_mem_of_int) returns(x:reg) ensures InputOutput(x, r.regs[x] - LogicalEval(m, r, y)); { call logical_SubLoad(inout r, core_state, m, x, y); } instruction CmpLoad(x:opn_mem_of_int, y:opn) { call logical_CmpLoad(inout r, core_state, statics, x, y); } // TODO: don't hardwire for statics instruction Load(const linear m:mem, ptr:opn_mem_of_int) returns (y:reg) { call logical_Load(inout r, core_state, m, y, ptr); } instruction Store(inout linear m:mem, ptr:opn_mem_of_int, val:opn) ensures Output(ptr, Eval(r, val)); { call logical_Store(r, core_state, inout m, ptr, val); } instruction SLoad (ptr:opn_mem_of_int) returns (y:reg) { call logical_Load(inout r, core_state, stk, y, ptr); } instruction SStore (ptr:opn_mem_of_int, val:opn) { call logical_Store(r, core_state, inout stk, ptr, val); } instruction SCmpLoad(x:opn_mem_of_int, y:opn) { call logical_CmpLoad(inout r, core_state, stk, x, y); } instruction Call() { call alignCall(r.regs[ESP]); call logical_Call(inout r, core_state, inout stk); } instruction Ret() { call logical_Ret(inout r, core_state, stk); } //instruction IRet() { call r, mem := logical_IRet(r, mem); } //instruction RoLoadU8(y:opn_mem_of_int) returns(x:opn) { call r, mem := logical_RoLoadU8(r, mem, x, y); } //instruction RoLoadS8(y:opn_mem_of_int) returns(x:opn) { call r, mem := logical_RoLoadS8(r, mem, x, y); } //instruction RoLoadU16(y:opn_mem_of_int) returns(x:opn) { call r, mem := logical_RoLoadU16(r, mem, x, y); } //instruction RoLoadS16(y:opn_mem_of_int) returns(x:opn) { call r, mem := logical_RoLoadS16(r, mem, x, y); } //instruction RoLoad32(y:opn_mem_of_int) returns(x:opn) { call r, mem := logical_RoLoad32(r, mem, x, y); } instruction ReadCR0() returns (x:opn) { call r := instr_ReadCR0(r, core_state, x); } instruction WriteCR0(x:opn) { call r, core_state := instr_WriteCR0(r, core_state, x); } //instruction WriteCR3(x:opn) { call r, mem := instr_WriteCR3(r, mem, x); } instruction VgaDebugStore16(ptr:opn_mem_of_int, val:opn) { call instr_VgaDebugStore16(r, ptr, val); } instruction VgaTextStore16(ptr:opn_mem_of_int, val:opn) { call io := instr_VgaTextStore16(r, io, ptr, val); } instruction KeyboardStatusIn8() { call r, io := instr_KeyboardStatusIn8(r, io); } instruction KeyboardDataIn8() { call r, io := instr_KeyboardDataIn8(r, io); } instruction SerialDbgConfigOut() { call instr_SerialDbgConfigOut(r); } instruction SerialDbgDataOut8() { call instr_SerialDbgDataOut8(r); } instruction SerialDbgStatusOut8() { call r := instr_SerialDbgStatusOut8(r); } //instruction SerialDbgDataIn8() { call r, io := instr_SerialDbgDataIn8(r, io, $serialState); } //instruction SerialDbgStatusIn8() { call r, io := instr_SerialDbgStatusIn8(r, io, $serialState); } //instruction SampleIn32(M:[int]int) { call r, io := instr_SampleIn32(r, io, M); } //instruction IomStore(ptr:opn_mem_of_int, val:opn) { call r, io := instr_IomStore(r, io, ptr, val); } //instruction IomRegLoad(entry:int, ptr:opn_mem_of_int) returns(val:opn) { call r, io := instr_IomRegLoad(r, io, entry, val, ptr); } //instruction IomRegStore(entry:int, ptr:opn_mem_of_int, val:opn) { call r, io := instr_IomRegStore(r, io, entry, ptr, val); } //instruction IomEnable() { call r, io := /*core :=*/ core_IomEnable(r, io); } instruction PciConfigAddrOut32(id:int, offset:int) { call io := instr_PciConfigAddrOut32(r, io, id, offset); } instruction PciConfigDataIn32(id:int, offset:int) { call r, io := instr_PciConfigDataIn32(r, io, id, offset); } instruction PciConfigDataOut32(id:int, offset:int, config0:int, config4:int, config12:int, config16:int) { call io := instr_PciConfigDataOut32(r, io, id, offset, config0, config4, config12, config16); } instruction PciMemLoad32(id:int, ptr:opn_mem_of_int) returns(val:reg) { call r, io := instr_PciMemLoad32(r, io, id, val, ptr); } instruction PciMemStore32(id:int, ptr:opn_mem_of_int, val:opn) { call io := instr_PciMemStore32(r, io, id, ptr, val); } instruction DeviceLoad(ptr:opn_mem_of_int) returns(val:reg) { call r, io := instr_DeviceLoad(r, io, val, ptr); } instruction DeviceStore(ptr:opn_mem_of_int, val:opn) { call io := instr_DeviceStore(r, io, ptr, val); } instruction DEV_PciConfigDataIn32 (linear DEV_states:DEV_StateMachines, id:int, dev_offset:int, offset:int) returns (linear _DEV_states:DEV_StateMachines) { call r, io, _DEV_states := instr_DEV_PciConfigDataIn32 (r, io, DEV_states, id, dev_offset, offset); } instruction DEV_PciConfigDataOut32(linear DEV_states:DEV_StateMachines, id:int, dev_offset:int, offset:int) returns (linear _DEV_states:DEV_StateMachines) { call io, _DEV_states := instr_DEV_PciConfigDataOut32(r, io, DEV_states, id, dev_offset, offset); } instruction IoMemAddrRead(ptr:opn_mem_of_int) returns(val:reg) { call r := instr_IoMemAddrRead(r, val, ptr); } instruction IoMemAddrWrite(ptr:opn_mem_of_int, val:opn) { call instr_IoMemAddrWrite(r, ptr, val); } //instruction IdtStore(entry:int, offset:int, handler:int, ptr:opn_mem_of_int, val:opn) { call r, state := logical_IdtStore(r, state, entry, offset, handler, ptr, val); } //instruction Lidt(ptr:opn_mem_of_int) { call r, state := logical_Lidt(r, state, ptr); } //instruction PicOut8(pic:int, offset:int, seq:int) { call r, state := logical_PicOut8(r, state, pic, offset, seq); } //instruction PitModeOut8(freq:int) { call r, state := logical_PitModeOut8(r, state, freq); } //instruction PitFreqOut8() { call r, state := logical_PitFreqOut8(r, state); } // //instruction SectionLoad(y:opn_mem_of_int) returns(x:opn) { call r := logical_SectionLoad(r, state, x, y); } //instruction SectionStore(x:opn_mem_of_int, y:opn) { call r := logical_SectionStore(r, state, x, y); } // //instruction StoreShared(linear owner:int, ptr:opn_mem_of_int, val:opn) returns(linear _owner:int) ensures Output(ptr, _Eval(regs, val)); { call r := core, _owner := logical_StoreShared(r, state, owner, ptr, val); } } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Base/Instructions.imp.beat ================================================ module implementation Instructions { } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Base/IntLemmasBase.ifc.beat ================================================ //-private-import BaseSpec; //-private-import MemorySpec; //-private-import IoTypesSpec; //-private-import MachineStateSpec; //-private-import AssemblySpec; //- //-private-import IntSpec; //-private-import BitVectorLemmasBase; //- //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module interface IntLemmasBase { function bit_index($i:int) returns (bool) { le(0, $i) && le($i, 31) } function eq($x:int, $y:int) returns (bool) { le($x, $y) && le($y, $x) } function aligned4k($ptr:int) returns (bool) { ClearLSBs(12, $ptr) == $ptr } atomic ghost procedure alignment_is_mod4_lemma(); ensures (forall $x:int :: {Aligned($x)} word($x) ==> Aligned($x) == (_mod($x, 4) == 0)); atomic ghost procedure alignment_4k_is_mod4096_lemma(); ensures (forall $x:int :: {aligned4k($x)} word($x) ==> aligned4k($x) == (_mod($x, 4096) == 0)); atomic ghost procedure alignment_dominance_lemma($ptr:int); requires word($ptr); ensures aligned4k($ptr) ==> Aligned($ptr); atomic ghost procedure lower_bits_dont_matter_lemma($ptr:int, $orVal:int); requires word($ptr); requires le(0, $orVal) && lt($orVal, 4096); ensures aligned4k($ptr) ==> ClearLSBs(12, or($ptr, $orVal)) == $ptr; atomic ghost procedure get_set_lemma(); ensures (forall $ptr:int, $index:int :: { GetBit($index, SetBit($index, $ptr)) } (word($ptr) && bit_index($index)) ==> GetBit($index, SetBit($index, $ptr)) == true); //- Explain the effect clearing the LSBs has on the bits that constitute $ptr atomic ghost procedure clear_LSBs_lemma(); ensures (forall $ptr:int, $amount:int, $i:int :: { GetBit($i, ClearLSBs($amount, $ptr)) } (bit_index($amount) && word($ptr) && bit_index($i)) ==> if lt($i, $amount) then GetBit($i, ClearLSBs($amount, $ptr)) == false else GetBit($i, ClearLSBs($amount, $ptr)) == GetBit($i, $ptr) ); atomic ghost procedure upper_bits_clear_ubound_lemma(); ensures (forall $ptr:int, $y:int :: { SelectLSBs($y, $ptr) } (word($ptr) && ge(10, $y) && ge($y, 0)) ==> le(SelectLSBs($y, $ptr), 1023) ); atomic ghost procedure upper_bits_clear_lbound_lemma(); ensures (forall $ptr:int, $y:int :: { SelectLSBs($y, $ptr) } (word($ptr) && ge(10, $y) && ge($y, 0)) ==> le(0, SelectLSBs($y, $ptr))); atomic ghost procedure clear_less_than_equal_lemma(); ensures (forall $ptr:int, $amt:int :: { le(ClearLSBs($amt, $ptr), $ptr) } (word($ptr) && bit_index($amt)) ==> le(ClearLSBs($amt, $ptr), $ptr) ); atomic ghost procedure clear_12_lemma(); ensures (forall $ptr:int :: { and($ptr, 0xFFFFF000) } word($ptr) ==> ClearLSBs(12, $ptr) == and($ptr, 0xFFFFF000)); ensures (forall $ptr:int :: { add(ClearLSBs(12, $ptr), 0x1000) } word($ptr) && lt($ptr, 0xFFFFF000) ==> ge(add(ClearLSBs(12, $ptr), 0x1000), $ptr) ); ensures (forall ptr:int, lb:int, ub:int :: { between(lb, ub, ClearLSBs(12, ptr)) } word(ptr) && word(lb) && word(ub) && aligned4k(lb) && aligned4k(ub) && between(lb, ub, ptr) ==> between(lb, ub, ClearLSBs(12, ptr)) ); ensures (forall ptr:int, lb:int, ub:int :: { between(lb, ub, ClearLSBs(12, ptr)) } word(ptr) && word(lb) && word(ub) && aligned4k(lb) && aligned4k(ub) && !between(lb, ub, ptr) ==> !between(lb, ub, ClearLSBs(12, ptr)) ); atomic ghost procedure clear_select_consistent_lemma(); ensures (forall $ptr:int, $val:int :: { ClearLSBs($val, ClearLSBs($val, $ptr)) } { SelectLSBs($val, SelectLSBs($val, $ptr))} (word($ptr) && bit_index($val)) ==> ClearLSBs($val, ClearLSBs($val, $ptr)) == ClearLSBs($val, $ptr) && SelectLSBs($val, SelectLSBs($val, $ptr)) == SelectLSBs($val, $ptr)); atomic ghost procedure select_non_negative_lemma(); ensures (forall $ptr:int, $amt:int :: { le(0, SelectLSBs($amt, $ptr)) } (word($ptr) && bit_index($amt)) ==> le(0, SelectLSBs($amt, $ptr)) ); atomic ghost procedure select_preserves_word_lemma(); ensures (forall $ptr:int, $x:int :: { word(SelectLSBs($x, $ptr)) } (word($ptr) && bit_index($x)) ==> word(SelectLSBs($x, $ptr))); atomic ghost procedure and_bounds(); ensures (forall $val:int :: { and($val, 0xff) } word($val) ==> le(0, and($val, 0xff)) && lt(and($val, 0xff), 256)); ensures (forall $val:int :: { and($val, 0xf) } word($val) ==> le(0, and($val, 0xf)) && lt(and($val, 0xf), 16)); atomic ghost procedure shr_decreases(); ensures (forall $ptr:int, $x:int :: { shr($ptr, $x) } (word($ptr) && ge($x, 0)) ==> le(shr($ptr, $x), $ptr)); atomic ghost procedure shr_preserves_word_lemma(); ensures (forall $ptr:int, $x:int :: { word(shr($ptr, $x)) } (word($ptr) && ge($x, 0)) ==> word(shr($ptr, $x))); atomic ghost procedure set_bit_preserves_word_lemma(); ensures (forall $ptr:int, $x:int :: { word(SetBit($x, $ptr)) } (word($ptr) && bit_index($x)) ==> word(SetBit($x, $ptr))); atomic ghost procedure or_with_3_lemma(); ensures (forall $ptr:int, $i:int :: { GetBit($i, or($ptr, 3)) } (word($ptr) && bit_index($i)) ==> if (eq($i, 0) || eq($i, 1)) then GetBit($i, or($ptr, 3)) == true else GetBit($i, or($ptr, 3)) == GetBit($i, $ptr)); atomic ghost procedure or_with_7_lemma(); ensures (forall $ptr:int, $i:int :: { GetBit($i, or($ptr, 7)) } (word($ptr) && bit_index($i)) ==> if (eq($i, 0) || eq($i, 1) || eq($i, 2)) then GetBit($i, or($ptr, 7)) == true else GetBit($i, or($ptr, 7)) == GetBit($i, $ptr)); atomic ghost procedure or_with_pow2_31_lemma(); ensures (forall $ptr:int, $i:int :: { GetBit($i, or($ptr, 0x80000000)) } (word($ptr) && bit_index($i)) ==> if (eq($i, 31)) then GetBit($i, or($ptr, 0x80000000)) == true else GetBit($i, or($ptr, 0x80000000)) == GetBit($i, $ptr)); ensures (forall $ptr:int :: { or($ptr, 0x80000000) } word($ptr) ==> SetBit(31, $ptr) == or($ptr, 0x80000000) ); atomic ghost procedure pointer_pieces_lemma(); ensures (forall $ptr:int :: { mul(4096, add(mul(SelectLSBs(10, shr($ptr, 22)), 1024), SelectLSBs(10, shr($ptr, 12)))) } word($ptr) ==> mul(4096, add(mul(SelectLSBs(10, shr($ptr, 22)), 1024), SelectLSBs(10, shr($ptr, 12)))) == ClearLSBs(12, $ptr) ); atomic ghost procedure ptr_offsets_lemma(); ensures (forall $ptr:int :: { PageTableOffset($ptr) } (word($ptr) && lt($ptr, 4096)) ==> PageTableOffset($ptr) == 0 ); ensures (forall $ptr:int :: { PageDirectoryOffset($ptr) } word($ptr) ==> (lt($ptr, 4194304) <==> PageDirectoryOffset($ptr) == 0) ); ensures (forall $ptr:int :: { PageTableOffset($ptr) } (word($ptr) && PageTableOffset($ptr) != 0) ==> gt($ptr, 0) ); ensures (forall $ptr:int :: { PageTableOffset($ptr) } (word($ptr) && ge($ptr, 4096)) ==> gt(PageTableOffset($ptr), 0) || gt(PageDirectoryOffset($ptr), 0) ); atomic ghost procedure ptr_reconstruction_lemma(); ensures (forall ptr:int :: { or(ClearLSBs(12, ptr), SelectLSBs(12, ptr)) } word(ptr) ==> ptr == or(ClearLSBs(12, ptr), SelectLSBs(12, ptr)) ); ensures (forall ptr:int :: { or(SelectLSBs(12, ptr), ClearLSBs(12, ptr)) } word(ptr) ==> ptr == or(SelectLSBs(12, ptr), ClearLSBs(12, ptr)) ); } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Base/IntLemmasBase.imp.beat ================================================ //-private-import BaseSpec; //-private-import MemorySpec; //-private-import IoTypesSpec; //-private-import MachineStateSpec; //-private-import AssemblySpec; //- //-private-import IntSpec; //-private-import BitVectorLemmasBase; //- //- //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module implementation IntLemmasBase { atomic ghost procedure helper() ensures (forall b1:bv32, b2:bv32::{$add(b1, b2)} word(add(I(b1), I(b2))) ==> add(I(b1), I(b2)) == I($add(b1, b2))); ensures (forall b1:bv32, b2:bv32::{$sub(b1, b2)} word(sub(I(b1), I(b2))) ==> sub(I(b1), I(b2)) == I($sub(b1, b2))); ensures (forall b1:bv32, b2:bv32::{$mul(b1, b2)} word(mul(I(b1), I(b2))) ==> mul(I(b1), I(b2)) == I($mul(b1, b2))); ensures (forall b1:bv32, b2:bv32::{$div(b1, b2)} word(_mod(I(b1), I(b2))) ==> _mod(I(b1), I(b2)) == I($mod(b1, b2))); ensures (forall b1:bv32, b2:bv32::{$mod(b1, b2)} word(_div(I(b1), I(b2))) ==> _div(I(b1), I(b2)) == I($div(b1, b2))); ensures (forall b1:bv32, b2:bv32::{$le(b1, b2)} le(I(b1), I(b2)) <==> $le(b1, b2)); ensures (forall b1:bv32, b2:bv32::{$lt(b1, b2)} lt(I(b1), I(b2)) <==> $lt(b1, b2)); ensures (forall b1:bv32, b2:bv32::{$ge(b1, b2)} ge(I(b1), I(b2)) <==> $ge(b1, b2)); ensures (forall b1:bv32, b2:bv32::{$gt(b1, b2)} gt(I(b1), I(b2)) <==> $gt(b1, b2)); ensures (forall b1:bv32, b2:bv32::{$eq(b1, b2)} eq(I(b1), I(b2)) <==> $eq(b1, b2)); ensures (forall b1:bv32, b2:bv32, b3:bv32::{$between(b1, b2, b3)} between(I(b1), I(b2), I(b3)) <==> $between(b1, b2, b3)); ensures (forall i1:int, i2:int, i3:int ::{between(i1, i2, i3)} word(i1) && word(i2) && word(i3) ==> (between(i1, i2, i3) <==> $between(B(i1), B(i2), B(i3))) ); { } //- Add atomic ghost procedure _a($b1:bv32, $b2:bv32) requires word(add(I($b1), I($b2))); ensures add(I($b1), I($b2)) == I($add($b1, $b2)); { } //- Sub atomic ghost procedure _s($b1:bv32, $b2:bv32) requires word(sub(I($b1), I($b2))); ensures sub(I($b1), I($b2)) == I($sub($b1, $b2)); { } //- Multiply atomic ghost procedure _m($b1:bv32, $b2:bv32) requires word(mul(I($b1), I($b2))); ensures mul(I($b1), I($b2)) == I($mul($b1, $b2)); { } //- Useful relations between const ints and const bitvectors atomic ghost procedure __const() ensures 0 == I(0bv32); ensures 1 == I(1bv32); ensures 2 == I(2bv32); ensures 3 == I(3bv32); ensures 4 == I(4bv32); ensures 5 == I(5bv32); ensures 6 == I(6bv32); ensures 7 == I(7bv32); ensures 8 == I(8bv32); ensures 9 == I(9bv32); ensures 10 == I(10bv32); ensures 11 == I(11bv32); ensures 12 == I(12bv32); ensures 13 == I(13bv32); ensures 15 == I(15bv32); ensures 16 == I(16bv32); ensures 22 == I(22bv32); ensures 32 == I(32bv32); ensures 31 == I(31bv32); ensures 64 == I(64bv32); ensures 63 == I(63bv32); ensures 128 == I(128bv32); ensures 127 == I(127bv32); ensures 255 == I(255bv32); ensures 256 == I(256bv32); ensures 1023 == I(1023bv32); ensures 1024 == I(1024bv32); ensures 4096 == I(4096bv32); ensures 4095 == I(4095bv32); ensures 1048576 == I(1048576bv32); // 2^20 ensures 16777215 == I(16777215bv32); ensures 33554431 == I(33554431bv32); ensures 67108863 == I(67108863bv32); ensures 2147483648 == I(2147483648bv32); ensures 0xFFFFF000 == I(4294963200bv32); ensures 4194304 == I(4194304bv32); // 2^22 = 0x0040000 { call _const_base(); call _s(1bv32, 1bv32); call _a(1bv32, 0bv32); call _a(1bv32, 1bv32); call _a(2bv32, 1bv32); call _a(2bv32, 2bv32); call _a(4bv32, 1bv32); call _a(5bv32, 1bv32); call _a(5bv32, 2bv32); call _a(5bv32, 3bv32); call _a(5bv32, 4bv32); call _a(5bv32, 5bv32); call _a(5bv32, 6bv32); call _a(5bv32, 7bv32); call _a(5bv32, 8bv32); call _a(7bv32, 8bv32); call _m(4bv32, 4bv32); call _a(10bv32, 12bv32); call _a(16bv32, 16bv32); call _s(32bv32, 1bv32); call _a(32bv32, 32bv32); call _s(64bv32, 1bv32); call _m(32bv32, 4bv32); call _s(128bv32, 1bv32); call _m(16bv32, 16bv32); call _s(256bv32, 1bv32); call _a(256bv32, 256bv32); call _a(512bv32, 512bv32); call _s(1024bv32, 1bv32); call _m(64bv32, 64bv32); call _s(4096bv32, 1bv32); call _m(256bv32, 256bv32); call _s(65536bv32, 1bv32); call _m(65536bv32, 256bv32); call _s(16777216bv32, 1bv32); call _m(65536bv32, 65535bv32); call _m(65536bv32, 512bv32); call _s(33554432bv32, 1bv32); call _a(33554432bv32, 33554432bv32); call _s(67108864bv32, 1bv32); call _m(33554432bv32, 64bv32); call _m(1024bv32, 1024bv32); call _s(1048576bv32, 1bv32); //- 0x000F FFFF call _m(1048575bv32, 4096bv32); //- 0xFFFF F000 call _m(1048576bv32, 4bv32); } atomic ghost procedure bit_helper() //- BV to Int ensures (forall i:bv32, val:bv32 :: {$get_bit(i, val)} (bit_index(I(i)) && word(I(val))) ==> GetBit(I(i), I(val)) == $get_bit(i, val)); ensures (forall i:bv32, val:bv32 :: {$set_bit(i, val)} (bit_index(I(i)) && word(I(val))) ==> SetBit(I(i), I(val)) == I($set_bit(i, val))); ensures (forall i:bv32, val:bv32 :: {$clear_bit(i, val)} (bit_index(I(i)) && word(I(val))) ==> ClearBit(I(i), I(val)) == I($clear_bit(i, val))); ensures (forall i:bv32, val:bv32 :: {$clear_LSBs(i, val)} (bit_index(I(i)) && word(I(val))) ==> ClearLSBs(I(i), I(val)) == I($clear_LSBs(i, val))); ensures (forall i:bv32, val:bv32 :: {$select_LSBs(i, val)} (bit_index(I(i)) && word(I(val))) ==> SelectLSBs(I(i), I(val)) == I($select_LSBs(i, val))); //- Int to BV ensures (forall i:int, val:int :: {GetBit(i,val)} (bit_index(i) && word(val)) ==> GetBit(i, val) == $get_bit(B(i), B(val))); ensures (forall i:int, val:int :: {SetBit(i,val)} (bit_index(i) && word(val)) ==> SetBit(i, val) == I($set_bit(B(i), B(val)))); ensures (forall i:int, val:int :: {ClearBit(i,val)} (bit_index(i) && word(val)) ==> ClearBit(i, val) == I($clear_bit(B(i), B(val)))); ensures (forall i:int, val:int :: {ClearLSBs(i,val)} (bit_index(i) && word(val)) ==> ClearLSBs(i, val) == I($clear_LSBs(B(i), B(val)))); ensures (forall i:int, val:int :: {SelectLSBs(i,val)} (bit_index(i) && word(val)) ==> SelectLSBs(i, val) == I($select_LSBs(B(i), B(val)))); ensures (forall i:bv32, val1:bv32, val2:bv32 :: { $get_bit(i, $or(val1, val2)) } (bit_index(I(i)) && word(I(val1)) && word(I(val2))) ==> GetBit(I(i), or(I(val1), I(val2))) == $get_bit(i, $or(val1, val2))); ensures (forall i:bv32, j:bv32, val:bv32 :: { $get_bit(j, $clear_LSBs(i, val)) } (bit_index(I(i)) && bit_index(I(j)) && word(I(val))) ==> GetBit(I(j), ClearLSBs(I(i), I(val))) == $get_bit(j, $clear_LSBs(i, val))); ensures (forall i:bv32, j:bv32, val:bv32 :: { $get_bit(j, $select_LSBs(i, val)) } (bit_index(I(i)) && bit_index(I(j)) && word(I(val))) ==> GetBit(I(j), SelectLSBs(I(i), I(val))) == $get_bit(j, $select_LSBs(i, val))); { call helper(); call __const(); call _shl_1_ge_1(); } implementation alignment_is_mod4_lemma() { call __const(); call _alignment_is_mod4_lemma(); } implementation alignment_4k_is_mod4096_lemma() { call __const(); call _shl_1_ge_1(); call bit_helper(); call _clear_LSBs_lemma(); call _alignment_4k_is_mod4096_lemma(); } implementation alignment_dominance_lemma($ptr:int) { call helper(); call __const(); call _alignment_dominance_lemma(B($ptr)); } // Note: Including a semicolon at the end of an implementation line (before the braces) causes BoogieAsm to freak out implementation lower_bits_dont_matter_lemma($ptr:int, $bitPos:int) { call helper(); call __const(); call _shl_1_ge_1(); call bit_helper(); call _lower_bits_dont_matter_lemma(B($ptr), B($bitPos)); } implementation get_set_lemma() { call helper(); call __const(); call bit_helper(); call _get_set_lemma(); } implementation clear_LSBs_lemma() { call helper(); call __const(); call _shl_1_ge_1(); call bit_helper(); call _clear_LSBs_lemma(); } implementation upper_bits_clear_ubound_lemma() { call __const(); call _shl_1_ge_1(); call bit_helper(); call _upper_bits_clear_ubound_lemma(); } implementation upper_bits_clear_lbound_lemma() { call __const(); call _upper_bits_clear_lbound_lemma(); } implementation clear_less_than_equal_lemma () { call __const(); call _shl_1_ge_1(); call bit_helper(); call _clear_less_than_equal_lemma(); } implementation clear_12_lemma () { call __const(); call _shl_1_ge_1(); call bit_helper(); call helper(); call _clear_12_lemma(); // assert (forall ptr:int, lb:int, ub:int :: { between(lb, ub, ClearLSBs(12, ptr)) } // word(ptr) && word(lb) && word(ub) && aligned4k(lb) && aligned4k(ub) && // le(lb, ptr) && lt(ptr, ub) ==> // le(lb, ClearLSBs(12, ptr)) ); } implementation clear_select_consistent_lemma() { call __const(); call _shl_1_ge_1(); call bit_helper(); call _clear_select_consistent_lemma(); } implementation select_non_negative_lemma() { call __const(); call _shl_1_ge_1(); call bit_helper(); call _select_non_negative_lemma(); } implementation select_preserves_word_lemma() { call __const(); call _select_preserves_word_lemma(); } implementation shr_decreases() { call helper(); call __const(); call bit_helper(); call _shr_decreases(); } implementation and_bounds() { call helper(); call __const(); call bit_helper(); call _and_bounds(); } implementation shr_preserves_word_lemma() { call __const(); call _shr_preserves_word_lemma(); } implementation set_bit_preserves_word_lemma() { call __const(); call __const(); call bit_helper(); //call _set_bit_preserves_word_lemma(); } implementation or_with_3_lemma() { call helper(); call __const(); call bit_helper(); call _or_with_3_lemma(); } implementation or_with_7_lemma() { call helper(); call __const(); call bit_helper(); call _or_with_7_lemma(); } implementation or_with_pow2_31_lemma() { call helper(); call __const(); call bit_helper(); call _or_with_pow2_31_lemma(); } implementation pointer_pieces_lemma() { call helper(); call __const(); call _shl_1_ge_1(); call bit_helper(); call _upper_bits_clear_ubound_lemma(); call _upper_bits_clear_lbound_lemma(); call _pointer_pieces_lemma(); } implementation ptr_offsets_lemma() { call helper(); call __const(); call bit_helper(); call _ptr_offsets_lemma(); } implementation ptr_reconstruction_lemma() { call helper(); call __const(); call bit_helper(); call _ptr_reconstruction_lemma(); } } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Base/LogicalAddressing.ifc.beat ================================================ //-private-import BaseSpec; //-private-import MemorySpec; //-private-import IoTypesSpec; //-private-import MachineStateSpec; //-private-import AssemblySpec; //-private-import InterruptsSpec; //-private-import IoSpec; //- //- //- //-private-import IntLemmasBase; //-private-import Partition; //-private-import Core; //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- #ifdef x64 #define IPSize 8 #else #define IPSize 4 #endif module interface LogicalAddressing { linear var ptMem:mem; const ?ptLo:int := ?memLo; const ?ptHi:int := ?ptLo + 0x402000; //- 0x402000 = ?pageDirSize + ?numPDEs * ?pageTableSize + 4096 (padding to ensure 4k aligned) const ?numPDEs:int := 1024; const ?numPTEsPerTable:int := 1024; const ?pageDirSize:int := 4096; //-?numPDEs * ?sizeofPDE; const ?pageTableSize:int := 4096; //-?numPTEsPerTable * ?sizeofPTE; const ?pageFrameSize:int := 4096; //- 4K function Aligned4k(ptr:int):bool { ClearLSBs(12, ptr) == ptr } function FlatSegmentationInv(seg_reg:SegmentRegister):bool { seg_reg.descriptor.segBase == 0 && seg_reg.descriptor.segType == ?SegmentDescriptorTypeData } function in_guard_region(ptr:int):bool { le(0, ptr) && lt(ptr, 4096) } //function PciUninitialized(io:IOState):bool //{ // (forall i:int :: {io._pci.PciConfigState[i]} io._pci.PciConfigState[i] == 0) //} function flat_page_mapping(mem:mem, base:int):bool; function only_user_accessible_pages(mem:mem, base:int, low:int, high:int):bool; procedure fixupDS() inout my r:regs, my core_state:core_state, linear mem:mem; requires !init; requires !paging_enabled(core_state); requires (forall i:int::{memAddr(i)} ?memLo <= i && i < ?memHi ==> memAddr(i)); requires ?memLo <= esp - 6*?SegmentDescriptorSize && esp <= ?memHi; requires Aligned(esp); requires (forall i:int :: { mem.dom[i] } esp - 24 <= i && i <= esp - 4 && Aligned(i) ==> mem.dom[i]); requires FlatSegmentationInv(core_state.seg_regs[SS]); // requires PciUninitialized(io); modifies mem, efl, ecx, edx, esp, core_state._gdt_regs, core_state._seg_regs; ensures FlatSegmentationInv(core_state.seg_regs[DS]); ensures FlatSegmentationInv(core_state.seg_regs[SS]); ensures !paging_enabled(core_state); ensures !init; ensures mem.dom == old(mem).dom; // ensures PciUninitialized(io); atomic ghost procedure enableLogicalAddressing(); inout my core_state:core_state, linear mem:mem; requires me == 0; requires !init; requires FlatSegmentationInv(core_state.seg_regs[DS]); requires FlatSegmentationInv(core_state.seg_regs[SS]); requires !paging_enabled(core_state); ensures logical_addressing_inv(init, ptMem, core_state); atomic ghost procedure logical_inv_is_flat(); inout my core_state:core_state; requires logical_addressing_inv(init, ptMem, core_state); ensures FlatSegmentationInv(core_state.seg_regs[DS]); ensures FlatSegmentationInv(core_state.seg_regs[SS]); ensures logical_addressing_inv(init, ptMem, core_state); function ptAddr(ptr:int):bool { between(?ptLo, ?ptHi, ptr) } function ptAddrOwned(ptMem:mem):bool { (forall addr:int :: { ptMem.dom[addr] } ptAddr(addr) ==> ptMem.dom[addr]) } const ptRoot:int := and(?memLo, 0xfffff000) + 0x1000; procedure initPageTablePartition(); inout my r:regs, my core_state:core_state, linear mem:mem; requires me == 0; requires !init; requires !paging_enabled(core_state); requires logical_addressing_inv(init, ptMem, core_state); // ensures (forall addr:int :: { $part.vars[ptOwner__id].dom[addr] } $part.vars[if ptAddr(addr) then ptOwner__id else me].dom[addr]); // ensures ptAddrOwned(ptMem); // ensures (forall i:int::{$part.vars[me].dom[i]} !ptAddr(i) ==> $part.vars[me].dom[i]); ensures logical_addressing_inv(init, ptMem, core_state); //procedure enablePaging($base:int); // inout my r:regs, my core_state:core_state, linear mem:mem; // requires me == 0; // requires !init; // requires logical_addressing_inv(init, ptMem, core_state); // requires ptAddrOwned(ptMem); // requires $base == eax; // requires $base == ptRoot; // requires word($base) && ptAddr($base) && Aligned4k($base); // // Must be enough room for all the structures // requires ptAddr($base + ?pageDirSize + ?numPDEs * ?pageTableSize-1) && // word($base + ?pageDirSize + ?numPDEs * ?pageTableSize); // requires ValidPrePagingState(core_state.cregs[CR0]); // requires FlatSegmentationInv(core_state.seg_regs[DS]); // requires FlatSegmentationInv(core_state.seg_regs[SS]); // requires (forall i:int::{memAddr(i)} ?memLo <= i && i < ?memHi ==> memAddr(i)); // requires lt(?ptHi, ?memHi); // modifies eax, ebx, ecx, edx, edi, esi, ptMem, mem; // ensures PageDirectoryBase(core_state.cregs[CR3]) == $base; // ensures flat_page_mapping(mem, core_state.cregs[CR3]); // ensures paging_enabled(core_state); // ensures logical_addressing_inv(true, ptMem, core_state); function logical_addressing_inv_priv(init:bool, core_state:core_state, ptMem:mem):bool; function logical_addressing_inv_base(init:bool, core_state:core_state, ptMem:mem):bool { logical_addressing_inv_priv(init, core_state, ptMem) } function logical_addressing_inv(init:bool, ptMem:mem, core_state:core_state):bool { logical_addressing_inv_base(init, core_state, ptMem) } function LogicalSrcOk(r:regs, core:core_state, m:mem, o:opn_mem):bool { EvalPtrOk(o) && PhysPtrOk(m, EvalPtr(r, o)) && word(EvalPtr(r, o)) && (paging_enabled(core) ==> !in_guard_region(EvalPtr(r, o))) } function LogicalDstOk(init:bool, r:regs, core:core_state, m:mem, o:opn_mem):bool { EvalPtrOk(o) && PhysPtrOk(m, EvalPtr(r, o)) && word(EvalPtr(r, o)) && (init ==> !in_guard_region(EvalPtr(r, o)) && !between(?ptLo, ?ptHi, EvalPtr(r, o))) //- Once paging is enabled, no more writing to the page tables } function LogicalEval(m:mem, r:regs, o:opn_mem):int { m.map[EvalPtr(r, o)] } function LogicalInOutUpdate(io:IOState):IOState { IOState( io._vga, io._keyboard, io._iom, io._pci, io._inCtr + 1, io._outCtr + 1 ) } //- Entirely ghost update function LogicalOutUpdate(io:IOState):IOState { IOState( io._vga, io._keyboard, io._iom, io._pci, io._inCtr, io._outCtr+1 ) } //-//////////////// Wrappers to hide paging complexity /////////////////// atomic procedure logical_Add(inout my r:regs, x:int, y:opn); requires word(r.regs[x] + Eval(r, y)); ensures r.regs == old(r.regs[x := r.regs[x] + Eval(r, y)]); ensures word(r.regs[x]); atomic procedure logical_Sub(inout my r:regs, x:int, y:opn); requires word(r.regs[x] - Eval(r, y)); ensures r.regs == old(r.regs[x := r.regs[x] - Eval(r, y)]); ensures word(r.regs[x]); atomic procedure logical_Load(inout my r:regs, const my c:core_state, const linear m:mem, x:int, y:opn_mem); requires logical_addressing_inv(init, ptMem, c); requires LogicalSrcOk(r, c, m, y); ensures r.regs == old(r.regs[x := LogicalEval(m, r, y)]); ensures r.efl == old(r).efl; ensures word(r.regs[x]); ensures logical_addressing_inv(init, ptMem, c); atomic procedure logical_Store(const my r:regs, const my c:core_state, inout linear m:mem, x:opn_mem, y:opn); requires logical_addressing_inv(init, ptMem, c); requires LogicalDstOk(init, r, c, m, x); requires SrcOk(y); ensures word(LogicalEval(m, r, x)); ensures m == old(mem_update(m, EvalPtr(r, x), Eval(r, y))); atomic procedure logical_SubLoad(inout my r:regs, const my c:core_state, const linear m:mem, x:int, y:opn_mem); requires logical_addressing_inv(init, ptMem, c); requires RegOk(x); requires LogicalSrcOk(r, c, m, y); requires word(r.regs[x] - LogicalEval(m, r, y)); ensures r.regs == old(r.regs[x := r.regs[x] - LogicalEval(m, r, y)]); atomic procedure logical_CmpLoad(inout my r:regs, const my c:core_state, const linear m:mem, x:opn_mem, y:opn); requires logical_addressing_inv(init, ptMem, c); requires LogicalSrcOk(r, c, m, x); requires SrcOk(y); ensures r.regs == old(r.regs); ensures r.efl == old(Efl_Cmp(r.efl, LogicalEval(m, r, x), Eval(r, y))); //atomic procedure logical_Cmpxchg(m:mem, core:core_state, ptr:opn_mem, val:opn) returns(_core:core_state); // requires logical_addressing_inv(init, ptMem, core_state); // requires m == $State; modifies state; // requires LogicalDstOk(init, $part, me, core, ptr); // requires SrcOk(val); // ensures word(regs[EAX]); // ensures $State == let _efl:int := Efl_Cmp(core._efl, old(regs)[EAX], LogicalEval(m, core, ptr)) in // if old(regs)[EAX] == LogicalEval(m, core, ptr) // then LogicalInsUpdate1(m, ptr, Eval(r, val), _efl) // else LogicalInsUpdate1(m, OReg(EAX), LogicalEval(m, core, ptr), _efl); // ensures logical_addressing_inv(init, ptMem, core_state); //atomic procedure logical_RoLoadU8(m:mem, core:core_state, x:opn, y:opn_mem) returns(_core:core_state); // requires logical_addressing_inv(init, ptMem, core_state); // requires m == $State; modifies state; // requires DstOk(x); // requires inRo(EvalPtr(core, y), 1); // ensures word(_Eval(regs, x)); // ensures _core == LogicalCoreUpdate1(core, x, roU8(EvalPtr(core, y)), core._efl); // ensures logical_addressing_inv(init, ptMem, core_state); // //atomic procedure logical_RoLoadS8(m:mem, core:core_state, x:opn, y:opn_mem) returns(_core:core_state); // requires logical_addressing_inv(init, ptMem, core_state); // requires m == $State; modifies state; // requires DstOk(x); // requires inRo(EvalPtr(core, y), 1); // ensures word(_Eval(regs, x)); // ensures (exists v:int:: asSigned(v) == roS8(EvalPtr(core, y)) // && _core == LogicalCoreUpdate1(core, x, v, core._efl)); // ensures logical_addressing_inv(init, ptMem, core_state); // //atomic procedure logical_RoLoadU16(m:mem, core:core_state, x:opn, y:opn_mem) returns(_core:core_state); // requires logical_addressing_inv(init, ptMem, core_state); // requires m == $State; modifies state; // requires DstOk(x); // requires inRo(EvalPtr(core, y), 2); // ensures word(_Eval(regs, x)); // ensures _core == LogicalCoreUpdate1(core, x, roU16(EvalPtr(core, y)), core._efl); // ensures logical_addressing_inv(init, ptMem, core_state); // //atomic procedure logical_RoLoadS16(m:mem, core:core_state, x:opn, y:opn_mem) returns(_core:core_state); // requires logical_addressing_inv(init, ptMem, core_state); // requires m == $State; modifies state; // requires DstOk(x); // requires inRo(EvalPtr(core, y), 2); // ensures word(_Eval(regs, x)); // ensures (exists v:int:: asSigned(v) == roS16(EvalPtr(core, y)) // && _core == LogicalCoreUpdate1(core, x, v, core._efl)); // ensures logical_addressing_inv(init, ptMem, core_state); // //atomic procedure logical_RoLoad32(m:mem, core:core_state, x:opn, y:opn_mem) returns(_core:core_state); // requires logical_addressing_inv(init, ptMem, core_state); // requires m == $State; modifies state; // requires DstOk(x); // requires inRo(EvalPtr(core, y), 4); // ensures word(_Eval(regs, x)); // ensures _core == LogicalCoreUpdate1(core, x, ro32(EvalPtr(core, y)), core._efl); // ensures logical_addressing_inv(init, ptMem, core_state); atomic procedure logical_Call(inout my r:regs, const my c:core_state, inout linear m:mem); requires logical_addressing_inv(init, ptMem, c); requires LogicalDstOk(init, r, c, m, OMem(MConst(esp - 4))); #ifdef x64 requires LogicalDstOk(init, r, c, m, OMem(MConst(esp - 8))); #endif #ifdef x64 ensures r.regs == old(r.regs[ESP := sub(r.regs[ESP], 8)])[TMP1 := m.map[esp]][TMP2 := m.map[esp + 4]]; #else ensures r.regs == old(r.regs[ESP := sub(r.regs[ESP], 4)])[TMP1 := m.map[esp]]; #endif #ifdef x64 ensures m == mem_update(mem_update(old(m), esp, m.map[esp]), esp + 4, m.map[esp + 4]); #else ensures m == mem_update(old(m), r.regs[ESP], m.map[esp]); #endif atomic procedure logical_Ret(inout my r:regs, const my c:core_state, const linear m:mem); requires logical_addressing_inv(init, ptMem, c); #ifdef x64 requires RET == ReturnToAddr64(LogicalEval(m, r, OMem(MReg(ESP, 0))), LogicalEval(m, r, OMem(MReg(ESP, 4)))); #else requires RET == ReturnToAddr32(LogicalEval(m, r, OMem(MReg(ESP, 0)))); #endif requires LogicalSrcOk(r, c, m, OMem(MReg(ESP, 0))); #ifdef x64 requires LogicalSrcOk(r, c, m, OMem(MReg(ESP, 4))); #endif ensures r.regs == old(r.regs[ESP := r.regs[ESP] + IPSize]); //atomic procedure logical_IRet(m:mem, core:core_state) returns(_core:core_state); // requires logical_addressing_inv(init, ptMem, core_state); // requires m == $State; modifies state; // requires LogicalSrcOk(core, OMem(MReg(ESP, 0))); // requires LogicalSrcOk(core, OMem(MReg(ESP, 4))); // requires LogicalSrcOk(core, OMem(MReg(ESP, 8))); // requires RET == ReturnToInterrupted( // LogicalEval(m, core, OMem(MReg(ESP, 0))), // LogicalEval(m, core, OMem(MReg(ESP, 4))), // LogicalEval(m, core, OMem(MReg(ESP, 8)))); // ensures _core == LogicalCoreUpdate1( // core, // OReg(ESP), // old(regs)[ESP]+12, // core._efl); // ensures logical_addressing_inv(init, ptMem, core_state); //atomic procedure logical_ActivateDataSelector(s:state, core:core_state, index:int, descriptor:SegmentDescriptor, srcRegister:opn, dstRegister:int) returns (_core:core_state); // requires logical_addressing_inv(init, s, ptMem, core_state); // requires s == $State; modifies state; // requires ValidSegmentSelector(Eval(r, srcRegister), index); // requires ValidGdtDescriptor(core._ext._gdt_regs, index, descriptor, s._mem); // requires descriptor.segType == ?SegmentDescriptorTypeData; // requires SegRegOk(dstRegister) && dstRegister != CS; // //ensures _core == LogicalCoreUpdate0(core, core._efl); // ensures core_state == (let c:core_state := old(core_state) in // core_state(c._cregs, c._gdt_regs, c._seg_regs[dstRegister := SegmentRegister(index, descriptor)], c._caches)); // ensures logical_addressing_inv(init, ptMem, core_state); // //atomic procedure logical_LoadGDT(s:state, core:core_state, base:int, len:int, addr:opn_mem) returns(_core:core_state); // requires logical_addressing_inv(init, s, ptMem, core_state); // requires s == $State; modifies state; // requires 0 <= len && len < 8192; // requires word(base); // requires base >= ?memLo && base + len * ?SegmentDescriptorSize <= ?memHi; // requires PhysPtrOk(EvalPtr(r, addr)) && PhysPtrOk(EvalPtr(r, addr) + 4); // requires GdtParamsWord0(base, len) == s._mem[EvalPtr(r, addr)]; // requires GdtParamsWord1(base, len) == s._mem[EvalPtr(r, addr) + 4]; // ensures core_state == (let c:core_state := old(core_state) in // core_state(c._cregs, GDT_regs(base, len), c._seg_regs, c._caches)); // //ensures logical_addressing_inv(init, ptMem, core_state); // //atomic procedure logical_ReadCR0(s:state, core:core_state, $dstReg:opn) returns(_core:core_state); // requires logical_addressing_inv(init, s, ptMem, core_state); // requires s == $State; modifies state; // requires DstOk($dstReg); // requires $dstReg is OReg; // ensures fresh_CR0_val(_Eval(regs, $dstReg)); // ensures _core == LogicalCoreUpdate1(core, $dstReg, core._ext._cregs[CR0], core._efl); // ensures word(_Eval(regs, $dstReg)); // ensures logical_addressing_inv(init, ptMem, core_state); // //atomic procedure logical_WriteCR0(s:state, core:core_state, newCR0:opn) returns(_core:core_state); // requires logical_addressing_inv(init, s, ptMem, core_state); // requires s == $State; modifies state; // requires word(Eval(r, newCR0)); // requires SrcOk(newCR0); // requires ValidPrePagingState(core._ext._cregs[CR0]); // requires (exists $x:int :: { fresh_CR0_val($x) } // (Eval(r, newCR0) == SetBit(?CR0_paging_enabled, $x)) && fresh_CR0_val($x)); // ensures core_state == (let c:core_state := old(core_state) in // core_state(c._cregs[CR0 := SetBit(?CR0_paging_enabled, c._cregs[CR0])], // c._gdt_regs, c._seg_regs, c._caches)); // ensures _core == $State._cores[me]; // //ensures logical_addressing_inv(init, ptMem, core_state); // //atomic procedure logical_HavocPagingCaches(s:state, core:core_state, c:core_state) returns(_s:state, _core:core_state); // requires logical_addressing_inv(init, s, ptMem, core_state); // requires c == core_state; // requires s == $State; modifies state; // requires paging_enabled(core) ==> // (forall $ptr:int, $dlabel:DTLB_label :: // word($ptr) ==> DTLBIsFreshWrtMemOneEntry(c._cregs[CR3], c._caches.DTLB, $dlabel, s._mem, $ptr) != <>()); // requires paging_enabled(core) ==> // (forall $ptr:int, $dlabel:DTLB_label, $label:TLB_label :: // word($ptr) ==> TLBIsFreshWrtDTLBOneEntry(c._cregs[CR3], c._caches.DTLB, $dlabel, c._caches.TLB, $label, s._mem, $ptr) != <>()); // ensures paging_enabled(core) ==> // core_state == core_state(c._cregs, c._gdt_regs, c._seg_regs, // paging_caches(_s._cores[me]._ext._caches.TLB, _s._cores[me]._ext._caches.DTLB, // c._caches.TLB_activeLabel, c._caches.DTLB_activeLabel)); // ensures paging_enabled(core) ==> // (forall $ptr:int, $dlabel:DTLB_label :: // $State._cores[me]._ext._caches.DTLB[PteNumber($ptr)][$dlabel] == c._caches.DTLB[PteNumber($ptr)][$dlabel] || // (word($ptr) ==> DTLBIsFreshWrtMemOneEntry(c._cregs[CR3], $State._cores[me]._ext._caches.DTLB, $dlabel, s._mem, $ptr).<>)); // ensures paging_enabled(core) ==> // (forall $ptr:int, $label:TLB_label, $dlabel:DTLB_label :: // $State._cores[me]._ext._caches.TLB[PageNumber($ptr)][$label] == c._caches.TLB[PageNumber($ptr)][$label] || // (word($ptr) ==> TLBIsFreshWrtDTLBOneEntry(c._cregs[CR3], c._caches.DTLB, $dlabel, // $State._cores[me]._ext._caches.TLB, $label, s._mem, $ptr).<>)); // ensures logical_addressing_inv(init, ptMem, core_state); // //atomic procedure logical_WriteCR3(s:state, core:core_state, newCR3:opn) returns(_core:core_state); // requires logical_addressing_inv(init, s, ptMem, core_state); // requires s == $State; modifies state; // requires SrcOk(newCR3); // requires ValidCR3(Eval(r, newCR3)); // requires DTLBsAreFreshWrtMem(Eval(r, newCR3), core._ext._caches.DTLB, s._mem) != <>(); // requires TLBsAreFreshWrtMem(Eval(r, newCR3), core._ext._caches.TLB, s._mem) != <>(); // ensures core_state == (let c:core_state := old(core_state) in // Everything is the same, except CR3 and the TLB and DTLB // core_state(c._cregs[CR3 := Eval(r, newCR3)], c._gdt_regs, c._seg_regs, // paging_caches(_s._cores[me]._ext._caches.TLB, _s._cores[me]._ext._caches.DTLB, // c._caches.TLB_activeLabel, c._caches.DTLB_activeLabel))); // ensures _core == $State._cores[me]; // ensures DTLBsAreFreshWrtMem(Eval(r, newCR3), $State._cores[me]._ext._caches.DTLB, s._mem) == <>(true); // ensures TLBsAreFreshWrtMem(Eval(r, newCR3), $State._cores[me]._ext._caches.TLB, s._mem) == <>(true); // //ensures logical_addressing_inv(init, ptMem, core_state); // //// Specifies the INVLPG instruction //atomic procedure logical_InvalidatePagingCaches(s:state, core:core_state, ptr:opn_mem) returns(_core:core_state); // requires logical_addressing_inv(init, s, ptMem, core_state); // requires s == $State; modifies state; // requires word(EvalPtr(r, ptr)); // requires DTLBsAreFreshWrtMem(core._ext._cregs[CR3], core._ext._caches.DTLB, s._mem) != <>(); // requires TLBsAreFreshWrtMemOneEntry(core._ext._cregs[CR3], core._ext._caches.TLB, s._mem, EvalPtr(r, ptr)) != <>(); // ensures core_state == (let c:core_state := old(core_state) in // Everything is the same, except the TLB and DTLB // core_state(c._cregs, c._gdt_regs, c._seg_regs, // paging_caches(_s._cores[me]._ext._caches.TLB, _s._cores[me]._ext._caches.DTLB, // c._caches.TLB_activeLabel, c._caches.DTLB_activeLabel))); // ensures DTLBsAreFreshWrtMem(core._ext._cregs[CR3], $State._cores[me]._ext._caches.DTLB, s._mem) == <>(true); // ensures TLBsAreFreshWrtMemOneEntry(core._ext._cregs[CR3], $State._cores[me]._ext._caches.TLB, s._mem, EvalPtr(r, ptr)) == <>(true); // ensures logical_addressing_inv(init, ptMem, core_state); // //atomic procedure logical_IdtStore(s:state, core:core_state, entry:int, offset:int, handler:int, ptr:opn_mem, val:opn) returns(_core:core_state); // requires logical_addressing_inv(init, s, ptMem, core_state); // requires s == $State; modifies state; // requires 0 <= entry && entry < ?NIdt; // requires SrcOk(val); // requires LogicalDstOk(init, $part, me, core, ptr); // requires (offset == 0 && Eval(r, val) == IdtWord0(handler)) || (offset == 4 && Eval(r, val) == IdtWord4(handler)); // requires IsHandlerForEntry(entry, handler); // requires EvalPtr(r, ptr) == ?idtLo + 8 * entry + offset; // modifies $IdtMem, $IdtMemOk; // ensures $IdtMem == old($IdtMem)[EvalPtr(r, ptr) := Eval(r, val)]; // ensures $IdtMemOk == old($IdtMemOk)[EvalPtr(r, ptr) := true]; // ensures _core == LogicalCoreUpdate0(core, core._efl); // ensures logical_addressing_inv(init, ptMem, core_state); // //atomic procedure logical_Lidt(s:state, core:core_state, ptr:opn_mem) returns(_core:core_state); // requires logical_addressing_inv(init, s, ptMem, core_state); // requires s == $State; modifies state; // requires memAddr(EvalPtr(r, ptr)) && memAddr(EvalPtr(r, ptr) + 4); // requires Aligned(EvalPtr(r, ptr)); // requires s._mem[EvalPtr(r, ptr)] == or(shl(?idtLo, 16), ?idtHi - ?idtLo - 1); // requires s._mem[EvalPtr(r, ptr) + 4] == shr(?idtLo, 16); // requires IdtMemOk($IdtMemOk); // modifies $IdtOk; // ensures $IdtOk; // ensures _core == LogicalCoreUpdate0(core, core._efl); // ensures logical_addressing_inv(init, ptMem, core_state); // //atomic procedure logical_VgaTextStore16(s:state, core:core_state, ptr:opn_mem, val:opn) returns(_core:core_state); // requires logical_addressing_inv(init, s, ptMem, core_state); // requires s == $State; modifies state; // requires SrcOk(val); // requires vgaAddr2(EvalPtr(r, ptr)); // requires left_opn_mem(ptr) == right_opn_mem(ptr); // requires left_opn(val) == right_opn(val); // requires left(s._io._inCtr) == right(s._io._inCtr); // requires left(s._io._outCtr) == right(s._io._outCtr); // ensures $State == OutUpdate(VgaUpdate(s, // VgaState( // s._io._vga.VgaEvents[s._io._vga.VgaNextEvent := VgaTextStore(EvalPtr(r, ptr), Eval(r, val))], // s._io._vga.VgaNextEvent + 1 // ))); // ensures logical_addressing_inv(init, ptMem, core_state); // //atomic procedure logical_VgaDebugStore16(s:state, core:core_state, ptr:opn_mem, val:opn) returns(_core:core_state); // requires logical_addressing_inv(init, s, ptMem, core_state); // requires s == $State; modifies state; // requires SrcOk(val); // requires vgaAddr2(EvalPtr(r, ptr)); // requires ?VgaTextLo <= EvalPtr(r, ptr) && EvalPtr(r, ptr) <= ?VgaTextLo + 158; // ensures _core == LogicalCoreUpdate0(core, core._efl); // ensures logical_addressing_inv(init, ptMem, core_state); // //atomic procedure logical_IomStore(s:state, core:core_state, ptr:opn_mem, val:opn) returns(_core:core_state); // requires logical_addressing_inv(init, s, ptMem, core_state); // requires s == $State; modifies state; // requires iomAddr(EvalPtr(r, ptr)); // requires Aligned(EvalPtr(r, ptr)); // requires word(Eval(r, val)); // requires SrcOk(val); // //requires LogicalDstOk(init, $part, me, core, ptr); // requires !s._io._iom.IomFrozen; // ensures $State == IomUpdate(s, // IomState( // s._io._iom.IomMem[EvalPtr(r, ptr) := Eval(r, val)], // s._io._iom.IomFrozen, // s._io._iom.IoMmuState, // s._io._iom.IoMmuEnabled, // s._io._iom.DevEnabled // )); // ensures logical_addressing_inv(init, ptMem, core_state); // //atomic procedure logical_IomRegLoad(s:state, core:core_state, entry:int, val:opn, ptr:opn_mem) returns(_core:core_state); // requires logical_addressing_inv(init, s, ptMem, core_state); // requires s == $State; modifies state; // requires EvalPtr(r, ptr) == ?DrhdRegs[entry] + 28 // || EvalPtr(r, ptr) == ?DrhdRegs[entry] + 0 // || EvalPtr(r, ptr) == ?DrhdRegs[entry] + 8 // || EvalPtr(r, ptr) == ?DrhdRegs[entry] + 12; // requires DstOk(val); // ensures word(_Eval(regs, val)); // ensures (exists v:int::{InsUpdate1(me, s, val, v, core._efl)} _core == LogicalCoreUpdate1(core, val, v, core._efl)); // ensures logical_addressing_inv(init, ptMem, core_state); // //atomic procedure logical_IomRegStore(s:state, core:core_state, entry:int, ptr:opn_mem, val:opn) returns(_core:core_state); // requires logical_addressing_inv(init, s, ptMem, core_state); // requires s == $State; modifies state; // requires SrcOk(val); // requires (s._io._iom.IoMmuState[entry] == 0 && EvalPtr(r, ptr) == ?DrhdRegs[entry] + 32 && IoRootTable(s._io._iom.IomMem, Eval(r, val))) // || (s._io._iom.IoMmuState[entry] == 1 && EvalPtr(r, ptr) == ?DrhdRegs[entry] + 36 && Eval(r, val) == 0) // || (s._io._iom.IoMmuState[entry] == 2 && EvalPtr(r, ptr) == ?DrhdRegs[entry] + 24 && Eval(r, val) == shl(1, 30)) // || (s._io._iom.IoMmuState[entry] == 3 && EvalPtr(r, ptr) == ?DrhdRegs[entry] + 24 && Eval(r, val) == shl(1, 31)); // ensures $State == IomUpdate(s, // IomState( // s._io._iom.IomMem, // true, // s._io._iom.IoMmuState[entry := 1 + s._io._iom.IoMmuState[entry]], // s._io._iom.IoMmuEnabled, // s._io._iom.DevEnabled // )); // ensures logical_addressing_inv(init, ptMem, core_state); // //atomic procedure logical_PciMemLoad32(s:state, core:core_state, id:int, val:opn, ptr:opn_mem) returns(_core:core_state); // requires logical_addressing_inv(init, s, ptMem, core_state); // requires s == $State; modifies state; // requires s._io._pci.PciConfigState[id] == 4; // requires PciMemAddr(id) <= EvalPtr(r, ptr) && EvalPtr(r, ptr) + 4 <= PciMemAddr(id) + PciMemSize(id); // requires DstOk(val); // requires left(s._io._inCtr) == right(s._io._inCtr); // requires left(s._io._outCtr) == right(s._io._outCtr); // requires EvalPtr(left_array(old(regs)), left_opn_mem(ptr)) == EvalPtr(right_array(old(regs)), right_opn_mem(ptr)); // Secret vals shouldn't affect addr we read on bus // ensures PciMemLoaded(id, EvalPtr(r, ptr), _Eval(regs, val)); // ensures word(_Eval(regs, val)); // ensures (exists v:int:: {InsUpdate1(me, s, val, v, core._efl)} // _core == LogicalCoreUpdate1(core, val, v, core._efl) // && word(v) // && left(v) == right(v)); // ensures state._io == LogicalInOutUpdate(s._io); // ensures logical_addressing_inv(init, ptMem, core_state); // //atomic procedure logical_PciMemStore32(s:state, core:core_state, id:int, ptr:opn_mem, src:opn) returns(_core:core_state); // requires logical_addressing_inv(init, s, ptMem, core_state); // requires s == $State; modifies state; // requires s._io._pci.PciConfigState[id] == 4; // requires PciMemAddr(id) <= EvalPtr(r, ptr) && EvalPtr(r, ptr) + 4 <= PciMemAddr(id) + PciMemSize(id); // requires word(Eval(r, src)); // requires left(s._io._inCtr) == right(s._io._inCtr); // requires left(s._io._outCtr) == right(s._io._outCtr); // requires EvalPtr(left_array(old(regs)), left_opn_mem(ptr)) == EvalPtr(right_array(old(regs)), right_opn_mem(ptr)); // Secret vals shouldn't affect addr we write on bus // requires _Eval(left_array(old(regs)), left_opn(src)) == _Eval(right_array(old(regs)), right_opn(src)); // nor the value itself // requires SrcOk(src); // ensures PciMemStored(id, EvalPtr(r, ptr), Eval(r, src)); // ensures _core == LogicalCoreUpdate0(core, core._efl); // ensures state._io == LogicalOutUpdate(s._io); // ensures logical_addressing_inv(init, ptMem, core_state); // //atomic procedure logical_DeviceLoad(s:state, core:core_state, dst:opn, ptr:opn_mem) returns(_core:core_state); // requires logical_addressing_inv(init, s, ptMem, core_state); // requires s == $State; modifies state; // //requires s._io._iom.DevEnabled; // requires ?devMemLo <= EvalPtr(r, ptr) && EvalPtr(r, ptr) + 4 <= ?devMemHi; // requires DstOk(dst); // requires left(s._io._inCtr) == right(s._io._inCtr); // requires left(s._io._outCtr) == right(s._io._outCtr); // requires EvalPtr(left_array(old(regs)), left_opn_mem(ptr)) == EvalPtr(right_array(old(regs)), right_opn_mem(ptr)); // Secret vals shouldn't affect addr we read on bus // requires dst is OReg; // ensures (exists v:int:: // Since addr we read is publicly visible, this is both an In and Out event // _core == LogicalCoreUpdate1(core, dst, v, s._cores[me]._efl) // && word(v) // && left(v) == right(v)); // ensures state._io == LogicalInOutUpdate(s._io); // ensures logical_addressing_inv(init, ptMem, core_state); // //atomic procedure logical_DeviceStore(s:state, core:core_state, ptr:opn_mem, src:opn, send_auth_word:bool, auth_word_index:int, // packet:[int]int) returns(_core:core_state); // requires logical_addressing_inv(init, s, ptMem, core_state); // requires s == $State; modifies state; // //requires s._io._iom.DevEnabled; // requires src is OReg || src is OConst; // requires ?devMemLo <= EvalPtr(r, ptr) && EvalPtr(r, ptr) + 4 <= ?devMemHi; // requires SrcOk(src); // requires left(s._io._inCtr) == right(s._io._inCtr); // requires left(s._io._outCtr) == right(s._io._outCtr); // requires left_b(send_auth_word) == right_b(send_auth_word); // requires left(auth_word_index) == right(auth_word_index); // requires EvalPtr(left_array(old(regs)), left_opn_mem(ptr)) == EvalPtr(right_array(old(regs)), right_opn_mem(ptr)); // Secret vals shouldn't affect addr we write on bus // requires !send_auth_word ==> _Eval(left_array(old(regs)), left_opn(src)) == _Eval(right_array(old(regs)), right_opn(src)); // nor the value itself // requires send_auth_word ==> // 0 <= auth_word_index && auth_word_index < ?wordsPerPacket // && app_approves_disclosure(left_array(packet), right_array(packet), ?wordsPerPacket) // && left_array (packet)[left (auth_word_index)] == _Eval( left_array(old(regs)), left_opn (src)) // && right_array(packet)[right(auth_word_index)] == _Eval(right_array(old(regs)), right_opn(src)); // ensures _core == LogicalCoreUpdate0(core, core._efl); // ensures state._io == LogicalOutUpdate(s._io); // ensures logical_addressing_inv(init, ptMem, core_state); // //atomic procedure logical_StoreShared(s:state, core:core_state, linear owner:int, x:opn_mem, y:opn) returns(_core:core_state, linear _owner:int); // requires logical_addressing_inv(init, s, ptMem, core_state); // requires s == $State; // requires LogicalDstOk(init, $part, owner, core, x); // requires SrcOk(y); // modifies state, efl, $part; // ensures logical_addressing_inv(init, ptMem, core_state); // ensures _owner == owner; // ensures _core == core; // ensures $part == LogicalPartUpdate1(old($part), owner, core, x, Eval(r, y)); // ensures word(LogicalEval($State, _core, x)); // //atomic procedure logical_CmpxchgShared(s:state, core:core_state, linear owner:int, ptr:opn_mem, val:opn) returns(_core:core_state, linear _owner:int); // requires logical_addressing_inv(init, s, ptMem, core_state); // requires s == $State; // requires LogicalDstOk(init, $part, owner, core, ptr); // requires SrcOk(val); // modifies state, efl, $part; // ensures logical_addressing_inv(init, ptMem, core_state); // ensures word(regs[EAX]); // ensures let _efl:int := Efl_Cmp(core._efl, old(regs)[EAX], LogicalEval(s, core, ptr)) in // if old(regs)[EAX] == LogicalEval(s, core, ptr) // then _core == LogicalCoreUpdate1(core, ptr, Eval(r, val), _efl) // && $part == LogicalPartUpdate1(old($part), owner, core, ptr, Eval(r, val)) // else _core == LogicalCoreUpdate1(core, OReg(EAX), LogicalEval(s, core, ptr), _efl) // && $part == LogicalPartUpdate1(old($part), owner, core, OReg(EAX), LogicalEval(s, core, ptr)); } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Base/LogicalAddressing.imp.beat ================================================ //-private-import BaseSpec; //-private-import MemorySpec; //-private-import IoTypesSpec; //-private-import MachineStateSpec; //-private-import AssemblySpec; //-private-import InterruptsSpec; //-private-import IoSpec; //- //- //- //- //-private-import IntLemmasBase; //-private-import Partition; //-private-import Core; //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module implementation LogicalAddressing { //-//////////////// Basic function definitions /////////////////// function implementation flat_page_mapping(mem:mem, base:int):bool { (forall ptr:int :: {PDEaddr(base, ptr)} {LoadPhysical(mem, PDEaddr(base, ptr))} word(ptr) ==> LoadPhysical(mem, PDEaddr(base, ptr)) != <>() && WordToPageEntry(LoadPhysical(mem, PDEaddr(base, ptr)).<>) != <>()) && (forall ptr:int :: {WordToPageEntry(LoadPhysical(mem, PDEaddr(base, ptr)).<>).<>} (word(ptr) && !in_guard_region(ptr)) ==> let pde:PageEntry := WordToPageEntry(LoadPhysical(mem, PDEaddr(base, ptr)).<>).<> in pde.present == ?Present && pde.write == ?Write) && (forall ptr:int :: {WordToPageEntry(LoadPhysical(mem, PDEaddr(base, ptr)).<>).<>} word(ptr) ==> let pde:PageEntry := WordToPageEntry(LoadPhysical(mem,PDEaddr(base, ptr)).<>).<> in LoadPhysical(mem, PTEaddr(pde, ptr)) != <>() && WordToPageEntry(LoadPhysical(mem, PTEaddr(pde, ptr)).<>) != <>()) && (forall ptr:int :: {WordToPageEntry(LoadPhysical(mem, PDEaddr(base, ptr)).<>).<>} (word(ptr) && !in_guard_region(ptr) ==> let pde:PageEntry := WordToPageEntry(LoadPhysical(mem, PDEaddr(base, ptr)).<>).<> in let pte:PageEntry := WordToPageEntry(LoadPhysical(mem, PTEaddr(pde, ptr)).<>).<> in pte.base == ClearLSBs(12, ptr) && pte.present == ?Present && pte.write == ?Write )) && (forall ptr:int :: {WordToPageEntry(LoadPhysical(mem, PDEaddr(base, ptr)).<>).<>} (word(ptr) && in_guard_region(ptr)) ==> let pde:PageEntry := WordToPageEntry(LoadPhysical(mem, PDEaddr(base, ptr)).<>).<> in let pte:PageEntry := WordToPageEntry(LoadPhysical(mem,PTEaddr(pde, ptr)).<>).<> in pte.present == ?Absent) && (forall ptr:int, TLB:[int][TLB_label]PageEntry, cacheLabel:TLB_label :: {PageMap(ptr, ?System, ?Write, TLB, cacheLabel).<>} (TLBsAreFreshWrtMem(base, TLB, mem) == <>(true) && PageMap(ptr, ?System, ?Write, TLB, cacheLabel) != <>() && word(ptr)) ==> PageMap(ptr, ?System, ?Write, TLB, cacheLabel).<> == ptr) && (forall ptr:int, TLB:[int][TLB_label]PageEntry, cacheLabel:TLB_label :: {PageMap(ptr, ?System, ?Read, TLB, cacheLabel).<>} (TLBsAreFreshWrtMem(base, TLB, mem) == <>(true) && PageMap(ptr, ?System, ?Read, TLB, cacheLabel) != <>() && word(ptr)) ==> PageMap(ptr, ?System, ?Read, TLB, cacheLabel).<> == ptr) } function in_user_region(ptr:int, low:int, high:int):bool { between(low, high, ptr) } function implementation only_user_accessible_pages(mem:mem, base:int, low:int, high:int):bool { (forall ptr:int :: {WordToPageEntry(mem[PDEaddr(base, ptr)]).<>} let pde:PageEntry := WordToPageEntry(mem[PDEaddr(base, ptr)]).<> in let pte:PageEntry := WordToPageEntry(mem[PTEaddr(pde, ptr)]).<> in word(ptr) && in_user_region(ptr, low, high) ==> pte.user == ?User) && (forall ptr:int :: {WordToPageEntry(mem[PDEaddr(base, ptr)]).<>} let pde:PageEntry := WordToPageEntry(mem[PDEaddr(base, ptr)]).<> in let pte:PageEntry := WordToPageEntry(mem[PTEaddr(pde, ptr)]).<> in word(ptr) && !in_user_region(ptr, low, high) && !in_guard_region(ptr) ==> pte.user == ?System) } //- Ensures all page table structures lie in the [?ptLo, ?ptHi) region, where they'll be safe function page_tables_correctly_situated(mem:mem, cr3:int):bool { (forall ptr:int :: { PDEaddr(cr3, ptr) } word(ptr) ==> between(?ptLo, ?ptHi, PDEaddr(cr3, ptr))) && (forall ptr:int :: { WordToPageEntry(LoadPhysical(mem,PDEaddr(cr3, ptr)).<>).<> } word(ptr) ==> let pde:PageEntry := WordToPageEntry(LoadPhysical(mem,PDEaddr(cr3, ptr)).<>).<> in between(?ptLo, ?ptHi, PTEaddr(pde, ptr))) } function LA(init:bool, core_state:core_state, ptMem:mem):bool { LA_priv(init, core_state, ptMem) } function LA_priv(init:bool, core_state:core_state, ptMem:mem):bool { true } //- Per-core invariant function logical_addressing_inv_core(init:bool, core_state:core_state, ptMem:mem):bool { FlatSegmentationInv(core_state.seg_regs[SS]) && FlatSegmentationInv(core_state.seg_regs[DS]) && (paging_enabled(core_state) ==> init && core_state.cregs[CR3] == ptRoot && DTLBsAreFreshWrtMem(core_state.cregs[CR3], core_state.caches.DTLB, ptMem) == <>(true) && TLBsAreFreshWrtMem(core_state.cregs[CR3], core_state.caches.TLB, ptMem) == <>(true) ) } //- Invariant across all cores function logical_addressing_inv_shared(init:bool, cr3:int, ptMem:mem):bool { init ==> ptAddrOwned(ptMem) && flat_page_mapping(ptMem, cr3) && page_tables_correctly_situated(ptMem, cr3) && (forall dtlb:[int][DTLB_label]PageEntry:: DTLBsAreFreshWrtMem(cr3, dtlb, ptMem) != <>()) && (forall tlb:[int][ TLB_label]PageEntry:: TLBsAreFreshWrtMem(cr3, tlb, ptMem) != <>()) } function implementation { LA_priv(init, core_state, ptMem) } logical_addressing_inv_priv(init:bool, core_state:core_state, ptMem:mem): bool { logical_addressing_inv_core(init, core_state, ptMem) && logical_addressing_inv_shared(init, ptRoot, ptMem) } implementation enableLogicalAddressing() { assert(LA(init, core_state, ptMem)); } implementation logical_inv_is_flat() { assert(LA(init, core_state, ptMem)); } function flat_PTE_index($ptr:int) returns (int) { add(mul(PageDirectoryOffset($ptr), 1024), PageTableOffset($ptr)) } // REVIEW: Merge PDE_index_to_addr with PTE_index_to_addr? function PDE_index_to_addr($base:int, $page_dir_index:int) returns (int) { add($base, mul(?sizeofPDE, $page_dir_index)) } function PTE_index_to_addr($base:int, $pte_index:int) returns (int) { add($base, mul(?sizeofPTE, $pte_index)) } function page_table_index_to_addr($page_tables_base:int, $page_table_index:int) returns (int) { add($page_tables_base, mul(?pageTableSize, $page_table_index)) } const ?totalPTEs:int := 0x100000; //-?numPTEsPerTable * ?numPDEs; function constants_correct() returns (bool) { ?totalPTEs == ?numPTEsPerTable * ?numPDEs && ?pageDirSize == ?numPDEs * ?sizeofPDE && ?pageTableSize == ?numPTEsPerTable * ?sizeofPTE } //-//////////////// Wrappers to hide paging complexity /////////////////// atomic ghost procedure logical_abstraction_lemma() // ensures (forall p:partition, owner:int, dst:opn_mem, s:state, core:core_state :: { logical_addressing_inv_base(init, s, ptMem), LogicalDstOk(p, owner, regs, core, dst) } // LA(me, init, s, ptMem) && core == s._cores[me] && logical_addressing_inv_base(init, s, ptMem) && LogicalDstOk(p, owner, regs, core, dst) ==> PartDstOk(regs, core, p, owner, s, dst)); // ensures (forall src:opn_mem, s:state :: { _MemSrcOk(regs, core_state, s, src) } // LA(me, init, s, ptMem) && logical_addressing_inv_base(init, s, ptMem) && LogicalSrcOk(regs, core_state, src) ==> _MemSrcOk(regs, core_state, s, src)); // ensures (forall o:opn_mem, s:state, core:core_state :: { LogicalEval(s, regs, o), LogicalSrcOk(regs, core, o) } // LA(me, init, s, ptMem) && core == s._cores[me] && logical_addressing_inv_base(init, s, ptMem) && LogicalSrcOk(regs, core, o) ==> LogicalEval(s, regs, o) == _EvalMem(regs, core_state, s, o)); // ensures (forall p:partition, owner:int, o:opn_mem, s:state, core:core_state :: { LogicalEval(s, regs, o), LogicalDstOk(p, owner, regs, core, o) } // LA(me, init, s, ptMem) && core == s._cores[me] && logical_addressing_inv_base(init, s, ptMem) && LogicalDstOk(p, owner, regs, core, o) ==> LogicalEval(s, regs, o) == _EvalMem(regs, core_state, s, o)); // ensures (forall s:state, _efl:int :: { logical_addressing_inv_base(init, s, ptMem) } // LA(me, init, s, ptMem) && LA(me, init, s, ptMem) && logical_addressing_inv_base(init, s, ptMem) ==> // logical_addressing_inv_base(init, s, ptMem) ); // ensures (forall dst:opn_mem, val:int, s:state, _efl:int :: // { MemUpdate1(regs, core_state, s, dst, val) } // LA(me, init, s, ptMem) // && logical_addressing_inv_base(init, s, ptMem) // && LogicalDstOk(init, $part, me, regs, core_state, dst) // // && LA(me, init, LogicalInsUpdate1(s, dst, val, _efl)) // && LA(me, init, MemUpdate1(regs, core_state, s, dst, val), ptMem) ==> // logical_addressing_inv_base(init, MemUpdate1(regs, core_state, s, dst, val), ptMem) // //&& s._cores[me] == MemUpdate1(regs, core_state, s, dst, val)._cores[me] // && LogicalPartUpdate1($part, me, regs, dst, val) == PartUpdate1($part, me, regs, core_state, dst, val) // && (word(_EvalMem(regs, core_state, MemUpdate1(regs, core_state, s, dst, val), dst)) ==> // word(LogicalEval(MemUpdate1(regs, core_state, s, dst, val), MemUpdate1(regs, core_state, s, dst, val)._cores[me], dst)))); { } implementation logical_Add(inout my r:regs, x:int, y:opn) { call r := instr_Add(r, x, y); call reveal_WORD_HI(); call reveal_wrap32(old(r.regs[x] + Eval(r, y))); var dummy:regs := old(r); } implementation logical_Sub(inout my r:regs, x:int, y:opn) { call r := instr_Sub(r, x, y); call reveal_WORD_HI(); call reveal_wrap32(old(r.regs[x] - Eval(r, y))); } ////implementation logical_Cmpxchg(m:mem, core:core_state, ptr:opn_mem, val:opn) returns(_core:core_state) { call logical_abstraction_lemma(); call core_Cmpxchg(m, ptr, val); _core := $State._cores[me]; } //implementation logical_RoLoadU8(m:mem, core:core_state, x:opn, y:opn_mem) returns(_core:core_state) { call logical_abstraction_lemma(); call core_RoLoadU8(m, x, y); _core := $State._cores[me]; } //implementation logical_RoLoadS8(m:mem, core:core_state, x:opn, y:opn_mem) returns(_core:core_state) { call logical_abstraction_lemma(); call core_RoLoadS8(m, x, y); _core := $State._cores[me]; } //implementation logical_RoLoadU16(m:mem, core:core_state, x:opn, y:opn_mem) returns(_core:core_state) { call logical_abstraction_lemma(); call core_RoLoadU16(m, x, y); _core := $State._cores[me]; } //implementation logical_RoLoadS16(m:mem, core:core_state, x:opn, y:opn_mem) returns(_core:core_state) { call logical_abstraction_lemma(); call core_RoLoadS16(m, x, y); _core := $State._cores[me]; } //implementation logical_RoLoad32(m:mem, core:core_state, x:opn, y:opn_mem) returns(_core:core_state) { call logical_abstraction_lemma(); call core_RoLoad32(m, x, y); _core := $State._cores[me]; } implementation logical_Load(inout my r:regs, const my c:core_state, const linear m:mem, x:int, y:opn_mem) { assert LA(init, c, ptMem); call r := instr_Load(r, c, m, x, y); } implementation logical_Store(const my r:regs, const my c:core_state, inout linear m:mem, x:opn_mem, y:opn) { assert LA(init, c, ptMem); call m := instr_Store(r, c, m, x, y); assert LA(init, c, ptMem); } implementation logical_SubLoad(inout my r:regs, const my c:core_state, const linear m:mem, x:int, y:opn_mem) { assert LA(init, c, ptMem); {: call r := instr_Load(r, c, m, TMP1, y); call r := instr_Sub(r, x, OReg(TMP1)); :} call reveal_WORD_HI(); call reveal_wrap32(old(r.regs[x] - LogicalEval(m, r, y))); call r := instr_DropTempRegs(r, old(r).regs[x := r.regs[x]]); } implementation logical_CmpLoad(inout my r:regs, const my c:core_state, const linear m:mem, x:opn_mem, y:opn) { assert LA(init, c, ptMem); {: call r := instr_Load(r, c, m, TMP1, x); call r := instr_Cmp(r, TMP1, y); :} call r := instr_DropTempRegs(r, old(r.regs)); } implementation logical_Call(inout my r:regs, const my c:core_state, inout linear m:mem) { assert LA(init, c, ptMem); call reveal_wrap32(esp - 4); call reveal_WORD_HI(); call memAddrBounds(esp - 4); #ifdef x64 call reveal_wrap32(esp - 8); call memAddrBounds(esp - 8); #endif assert LA(init, c, ptMem); {: call r := instr_SubNoFlags(r, ESP, OConst(IPSize)); #ifdef x64 call r := instr_MovNextEip64(r, TMP1, TMP2); #else call r := instr_MovNextEip32(r, TMP1); #endif call m := instr_StoreStack(r, c, m, OMem(MReg(ESP, 0)), OReg(TMP1)); #ifdef x64 call m := instr_StoreStack(r, c, m, OMem(MReg(ESP, 4)), OReg(TMP2)); #endif :} assert LA(init, c, ptMem); // call _r := instr_DropTempRegs(_r, r.regs[ESP := _r.regs[ESP]]); } implementation logical_Ret(inout my r:regs, const my c:core_state, const linear m:mem) { assert LA(init, c, ptMem); call reveal_wrap32(esp + 4); #ifdef x64 call reveal_wrap32(esp + 8); #endif call reveal_WORD_HI(); call memDomIsMemAddr(m, esp); #ifdef x64 call memDomIsMemAddr(m, esp + 4); #endif call memAddrBounds(esp); #ifdef x64 call memAddrBounds(esp + 4); #endif assert LA(init, c, ptMem); {: call r := instr_LoadStack(r, c, m, TMP1, OMem(MReg(ESP, 0))); #ifdef x64 call r := instr_LoadStack(r, c, m, TMP2, OMem(MReg(ESP, 4))); #endif call r := instr_AddNoFlags(r, ESP, OConst(IPSize)); call instr_Ret(r); call r := instr_DropTempRegs(r, old(r).regs[ESP := r.regs[ESP]]); :} assert LA(init, c, ptMem); } //implementation logical_IRet(m:mem, core:core_state) returns(_core:core_state) { call logical_abstraction_lemma(); call core_IRet(m); _core := $State._cores[me]; } //implementation logical_LoadGDT(s:state, core:core_state, base:int, len:int, addr:opn_mem) returns(_core:core_state) { call logical_abstraction_lemma(); call core_LoadGDT(s, base, len, addr); _core := $State._cores[me]; } //implementation logical_ReadCR0(s:state, core:core_state, $dstReg:opn) returns(_core:core_state) { call logical_abstraction_lemma(); call core_ReadCR0(s, $dstReg); _core := $State._cores[me]; } //implementation logical_WriteCR0(s:state, core:core_state, newCR0:opn) returns(_core:core_state) { call logical_abstraction_lemma(); call core_WriteCR0(s, newCR0); _core := $State._cores[me]; } //implementation logical_WriteCR3(s:state, core:core_state, newCR3:opn) returns(_core:core_state) { call logical_abstraction_lemma(); call core_WriteCR3(s, newCR3); _core := $State._cores[me]; } //implementation logical_InvalidatePagingCaches(s:state, core:core_state, ptr:opn_mem) returns(_core:core_state) { // assert(LA(me, init, s)); //// assert(forall $ptr:int :: { WordToPageEntry(LoadPhysical(s._mem,PDEaddr(core_state._cregs[CR3], $ptr)).<>) } //// paging_enabled(s._cores[me]) && word($ptr) ==> //// WordToPageEntry(LoadPhysical(s._mem,PDEaddr(core_state._cregs[CR3], $ptr)).<>) != <>() ); //// // // call logical_abstraction_lemma(); call core_InvalidatePagingCaches(s, ptr); // // assert (forall ptr:int :: word(ptr) ==> mem.map[ptr] == s._mem[ptr]); // // assert(LA(me, init, s)); // assert(LA(me, init, $State)); // // assert(forall $ptr:int :: { LoadPhysical(mem.map,PDEaddr($State._cores[me]._ext._cregs[CR3], $ptr)) } // word($ptr) ==> LoadPhysical(s._mem,PDEaddr(core_state._cregs[CR3], $ptr)) == // LoadPhysical(mem.map,PDEaddr($State._cores[me]._ext._cregs[CR3], $ptr)) ); // // assert(forall $ptr:int :: { WordToPageEntry(LoadPhysical(mem.map,PDEaddr($State._cores[me]._ext._cregs[CR3], $ptr)).<>) } // word($ptr) ==> WordToPageEntry(LoadPhysical(s._mem,PDEaddr(core_state._cregs[CR3], $ptr)).<>) == // WordToPageEntry(LoadPhysical(mem.map,PDEaddr($State._cores[me]._ext._cregs[CR3], $ptr)).<>) ); // // assert(forall $ptr:int :: { LoadPhysical(mem.map,PDEaddr($State._cores[me]._ext._cregs[CR3], $ptr)) } // paging_enabled(core_state) && word($ptr) ==> // LoadPhysical(mem.map,PDEaddr($State._cores[me]._ext._cregs[CR3], $ptr)) != <>() ); // // assert(forall $ptr:int :: { WordToPageEntry(LoadPhysical(s._mem,PDEaddr(core_state._cregs[CR3], $ptr)).<>) } // paging_enabled(s._cores[me]) && word($ptr) ==> // WordToPageEntry(LoadPhysical(s._mem,PDEaddr(core_state._cregs[CR3], $ptr)).<>) != <>() ); // // assert(forall $ptr:int :: { WordToPageEntry(LoadPhysical(mem.map,PDEaddr($State._cores[me]._ext._cregs[CR3], $ptr)).<>) } // paging_enabled(core_state) && word($ptr) ==> // WordToPageEntry(LoadPhysical(mem.map,PDEaddr($State._cores[me]._ext._cregs[CR3], $ptr)).<>) != <>() ); // // assert(forall $ptr:int :: // { WordToPageEntry(LoadPhysical(s._mem, PDEaddr(core_state._cregs[CR3], $ptr)).<>).<> } // (word($ptr) && paging_enabled(s._cores[me]) && !in_guard_region($ptr)) ==> // let $pde:PageEntry := WordToPageEntry(LoadPhysical(s._mem,PDEaddr(core_state._cregs[CR3], $ptr)).<>).<> in // $pde.present == ?Present && $pde.write == ?Write); // // assert(forall $ptr:int :: // { WordToPageEntry(LoadPhysical(mem.map, PDEaddr($State._cores[me]._ext._cregs[CR3], $ptr)).<>).<> } // (word($ptr) && paging_enabled(core_state) && !in_guard_region($ptr)) ==> // let $pde:PageEntry := WordToPageEntry(LoadPhysical(mem.map,PDEaddr($State._cores[me]._ext._cregs[CR3], $ptr)).<>).<> in // $pde.present == ?Present && $pde.write == ?Write); // // assert(forall $ptr:int :: // { WordToPageEntry(LoadPhysical(mem.map,PDEaddr($State._cores[me]._ext._cregs[CR3], $ptr)).<>).<> } // word($ptr)&& paging_enabled(core_state) ==> // let $pde:PageEntry := WordToPageEntry(LoadPhysical(mem.map,PDEaddr($State._cores[me]._ext._cregs[CR3], $ptr)).<>).<> in // LoadPhysical(mem.map, PTEaddr($pde, $ptr)) != <>()); // // assert (paging_enabled(core_state) ==> flat_page_mapping(mem.map, $State._cores[me]._ext._cregs[CR3])); // assert (paging_enabled(core_state) ==> page_tables_correctly_situated(mem.map, $State._cores[me]._ext._cregs[CR3])); // assert (paging_enabled(core_state) ==> DTLBsAreFreshWrtMem($State._cores[me]._ext._cregs[CR3], $State._cores[me]._ext._caches.DTLB, mem.map) == <>(true)); // assert (paging_enabled(core_state) ==> TLBsAreFreshWrtMem($State._cores[me]._ext._cregs[CR3], $State._cores[me]._ext._caches.TLB, mem.map) == <>(true)); //// assert (logical_addressing_inv(init) ); //} // //implementation logical_IdtStore(s:state, core:core_state, entry:int, offset:int, handler:int, ptr:opn_mem, val:opn) returns(_core:core_state) { call logical_abstraction_lemma(); call core_IdtStore(s, entry, offset, handler, ptr, val); _core := $State._cores[me]; } //implementation logical_Lidt(s:state, core:core_state, ptr:opn_mem) returns(_core:core_state) { call logical_abstraction_lemma(); call core_Lidt(s, ptr); _core := $State._cores[me]; } //implementation logical_VgaTextStore16(s:state, core:core_state, ptr:opn_mem, val:opn) returns(_core:core_state) { call logical_abstraction_lemma(); call core_VgaTextStore16(s, ptr, val); _core := $State._cores[me]; } //implementation logical_VgaDebugStore16(s:state, core:core_state, ptr:opn_mem, val:opn) returns(_core:core_state) { call logical_abstraction_lemma(); call core_VgaDebugStore16(s, ptr, val); _core := $State._cores[me]; } //implementation logical_IomStore(s:state, core:core_state, ptr:opn_mem, val:opn) returns(_core:core_state) { call logical_abstraction_lemma(); call core_IomStore(s, ptr, val); _core := $State._cores[me]; } //implementation logical_IomRegLoad(s:state, core:core_state, entry:int, val:opn, ptr:opn_mem) returns(_core:core_state) { call logical_abstraction_lemma(); call core_IomRegLoad(s, entry, val, ptr); _core := $State._cores[me]; } //implementation logical_IomRegStore(s:state, core:core_state, entry:int, ptr:opn_mem, val:opn) returns(_core:core_state) { call logical_abstraction_lemma(); call core_IomRegStore(s, entry, ptr, val); _core := $State._cores[me]; } //implementation logical_PciMemLoad32(s:state, core:core_state, id:int, val:opn, ptr:opn_mem) returns(_core:core_state) { call logical_abstraction_lemma(); call core_PciMemLoad32(s, id, val, ptr); _core := $State._cores[me]; } //implementation logical_PciMemStore32(s:state, core:core_state, id:int, ptr:opn_mem, val:opn) returns(_core:core_state) { call logical_abstraction_lemma(); call core_PciMemStore32(s, id, ptr, val); _core := $State._cores[me]; } //implementation logical_DeviceLoad(s:state, core:core_state, dst:opn, ptr:opn_mem) returns(_core:core_state) { call logical_abstraction_lemma(); call core_DeviceLoad(s, dst, ptr); _core := $State._cores[me]; } //implementation logical_DeviceStore(s:state, core:core_state, ptr:opn_mem, src:opn, send_auth_word:bool, auth_word_index:int, packet:[int]int) returns(_core:core_state) { call logical_abstraction_lemma(); call core_DeviceStore(s, ptr, src, send_auth_word, auth_word_index, packet); _core := $State._cores[me]; } // //implementation logical_StoreShared(s:state, core:core_state, linear owner:int, x:opn_mem, y:opn) returns(_core:core_state, linear _owner:int) //{ // call logical_abstraction_lemma(); // call _owner := core_StoreShared($State, owner, x, y); // _core := $State._cores[me]; //} // //implementation logical_CmpxchgShared(s:state, core:core_state, linear owner:int, ptr:opn_mem, val:opn) returns(_core:core_state, linear _owner:int) //{ // call logical_abstraction_lemma(); // assert LA(init, core_state, ptMem); // call _owner := core_CmpxchgShared($State, owner, ptr, val); // _core := $State._cores[me]; // assert LA(init, core_state, ptMem); //} //-//////////////// Actual paging-related work /////////////////// implementation initPageTablePartition() { } atomic ghost procedure espAligned(sp:int) requires Aligned(sp); ensures Aligned(sp - 4) && Aligned(sp - 8) && Aligned(sp - 12) && Aligned(sp - 16); ensures Aligned(sp - 20) && Aligned(sp - 24); { assert TV(sp) && TO(0-1) && TO(0-2) && TO(0-3) && TO(0-4) && TO(0-5) && TO(0-6) && TO(0-7); } implementation fixupDS() { call espAligned(esp); //- Save a copy of the base address for later call r := instr_Mov(r, EDX, OReg(EAX)); //-/////////////////////////////////////////////////// //- Build up a small GDT in reverse order via PUSH //-////////////////////////////////////////////////// //- "topmost" entry is a flat descriptor starting at 0. var goalSeg:SegmentDescriptor := SegmentDescriptor(0, ?SegmentDescriptorTypeData); //- The following implements SegmentDescriptorWord1() call r := instr_Mov(r, EAX, OConst(0)); assert r.regs[EAX] == 0; call r := instr_And(r, EAX, OConst(0x00ff0000)); call r := instr_Shr(r, EAX, OConst(16)); call r := instr_Mov(r, ECX, OConst(0xCF90)); call r := instr_Or (r, ECX, OConst(2)); call r := instr_Shl(r, ECX, OConst(8)); call r := instr_Or (r, EAX, OReg(ECX)); call r := instr_Mov(r, ECX, OReg(EAX)); call r := instr_Mov(r, EAX, OConst(0)); call r := instr_And(r, EAX, OConst(0xff000000)); call r := instr_Or (r, EAX, OReg(ECX)); assert r.regs[EAX] == SegmentDescriptorWord1(goalSeg); call r, mem := core_Push(r, core_state, mem, OReg(EAX)); //- Now do SegmentDescriptorWord0() call r := instr_Mov(r, EAX, OConst(0)); call r := instr_Shl(r, EAX, OConst(16)); call r := instr_Or (r, EAX, OConst(0xffff)); assert r.regs[EAX] == SegmentDescriptorWord0(goalSeg); call r, mem := core_Push(r, core_state, mem, OReg(EAX)); //- We don't care about the next two entries in the GDT, so set them to all 0 call r := instr_Mov(r, EAX, OConst(0)); call r, mem := core_Push(r, core_state, mem, OReg(EAX)); call r, mem := core_Push(r, core_state, mem, OReg(EAX)); //- Save the value in ESP, so we can build the GDT descriptor pointing to it var $base:int := r.regs[ESP]; call r := instr_Mov(r, EAX, OReg(ESP)); call r := instr_Mov(r, ECX, OReg(ESP)); //- GdtParamsWord1 call r := instr_Shr(r, EAX, OConst(16)); assert r.regs[EAX] == GdtParamsWord1($base, 2); call r, mem := core_Push(r, core_state, mem, OReg(EAX)); //- GdtParamsWord0 call r := instr_Shl(r, ECX, OConst(16)); call r := instr_Mov(r, EAX, OConst(16)); call r := instr_Or (r, ECX, OReg(EAX)); call r := instr_Mov(r, EAX, OReg(ECX)); assert r.regs[EAX] == GdtParamsWord0($base, 2); call r, mem := core_Push(r, core_state, mem, OReg(EAX)); //- Load it up! call core_state := instr_LoadGDT(r, core_state, mem, $base, 2, OMem(MReg(ESP, 0))); //- Fix up DS call r := instr_Mov(r, EAX, OConst(1)); call r := instr_Shl(r, EAX, OConst(3)); call core_state := instr_ActivateDataSelector(r, core_state, mem, 1, goalSeg, EAX, DS); //- Restore the original value of the base address call r := instr_Mov(r, EAX, OReg(EDX)); } procedure logicalAddressingInvNotEnabledLemma(p1:mem, p2:mem) inout my core_state:core_state; requires !paging_enabled(core_state); requires !init; requires logical_addressing_inv_base(init, core_state, p1); ensures logical_addressing_inv_base(init, core_state, p2); { assert LA(init, core_state, p1); assert LA(init, core_state, p2); } /* // Build a set of PDEs and PTEs describing a linear address space. // Uses memory starting at $base (in eax) for the paging structures. // Sets memory addresses in [ebx, esi) as user accessible. All others are system only // Returns (via eax) the appropriate value for CR3 procedure buildLinearPageTables($requested_base@eax, $user_low@ebx, $user_high@esi) inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem; requires !paging_enabled(core_state); requires !init; requires ptAddrOwned(ptMem); requires word($requested_base) && ptAddr($requested_base) && aligned4k($requested_base); requires word($user_low) && aligned4k($user_low) && !in_guard_region($user_low); requires word($user_high) && aligned4k($user_high) && !in_guard_region($user_high); requires le($user_low, $user_high); // Must be enough room for all the structures requires ptAddr($requested_base + ?pageDirSize + ?numPDEs * ?pageTableSize - 1) && word($requested_base + ?pageDirSize + ?numPDEs * ?pageTableSize); requires lt(?ptHi, ?memHi); requires logical_addressing_inv(init, ptMem, core_state); requires (forall i:int::{memAddr(i)} ?memLo <= i && i < ?memHi ==> memAddr(i)); modifies mem, efl, eax, ecx, edx, edi, ptOwner__id, $part; ensures ValidCR3(eax) && PageDirectoryBase(eax) == old(eax); ensures only_user_accessible_pages($part.vars[ptOwner__id].map, eax, old(ebx), old(esi)); ensures logical_addressing_inv(init, ptMem, core); ensures logical_addressing_inv_shared(true, $requested_base, $part.vars[ptOwner__id]); ensures $part.vars[me].dom == old($part).vars[me].dom; ensures eax == old(eax); { var $base:int := $requested_base; // Save the base value as a ghost, to free up eax var PartMem:[int]int := $part.vars[ptOwner__id].map; var $cur_addr @ eax; var $cur_base @ ecx; var $page_entry @ edi; assert(constants_correct()); call $cur_base := Lea(eax + ?pageDirSize); // First page table starts after all of the PDEs we build assert ($cur_base == $base + ?pageDirSize); call alignment_4k_is_mod4096_lemma(); assert (aligned4k($cur_base)); call clear_LSBs_lemma(); assert(WordToPageEntry($cur_base) != <>()); assert($cur_base != 0); call alignment_dominance_lemma($cur_addr); assert(Aligned($cur_addr)); call or_with_7_lemma(); // Create the PDEs var $iter @ edx := 0; var $pte_start:int := $base + ?pageDirSize; while ($iter < ?numPDEs) invariant LogicalDstOk(init, ptMem, regs, core_state, mem, OMem(MConst($cur_addr))); //invariant memAddrMain($cur_addr) && Aligned($cur_addr); invariant $cur_addr == $base + ?sizeofPDE*$iter; invariant $cur_base == $base + ?pageDirSize + ?pageTableSize*$iter; invariant aligned4k($cur_base); invariant !init; invariant !paging_enabled(core_state); invariant (forall $i:int :: {WordToPageEntry(PartMem[PDE_index_to_addr($base, $i)])} (le(0, $i) && lt($i, $iter)) ==> WordToPageEntry(PartMem[PDE_index_to_addr($base, $i)]) != <>()); invariant (forall $i:int :: { PartMem[PDE_index_to_addr($base, $i)] } (le(0, $i) && lt($i, $iter)) ==> word(PartMem[PDE_index_to_addr($base, $i)]) ); invariant (forall $ptr:int :: { WordToPageEntry(PartMem[PDEaddr($base, $ptr)]) } (le(0, PageDirectoryOffset($ptr)) && lt(PageDirectoryOffset($ptr), $iter)) ==> WordToPageEntry(PartMem[PDEaddr($base, $ptr)]) != <>() ); invariant (forall $ptr:int :: { WordToPageEntry(PartMem[PDEaddr($base, $ptr)]) } (le(0, PageDirectoryOffset($ptr)) && lt(PageDirectoryOffset($ptr), $iter)) ==> WordToPageEntry(PartMem[PDEaddr($base, $ptr)]).<>.base == page_table_index_to_addr($pte_start, PageDirectoryOffset($ptr)) ); // invariant (forall $ptr:int :: { WordToPageEntry(PartMem[PDEaddr($base, $ptr)]) } // (le(0, PageDirectoryOffset($ptr)) && lt(PageDirectoryOffset($ptr), $iter)) ==> // WordToPageEntry(PartMem[PDEaddr($base, $ptr)]).<>.base == page_table_index_to_addr($pte_start, PageDirectoryOffset($ptr)) ); invariant (forall $ptr:int :: { WordToPageEntry(PartMem[PDEaddr($base, $ptr)]).<> } le(0, PageDirectoryOffset($ptr)) && lt(PageDirectoryOffset($ptr), $iter) ==> let $pde:PageEntry := WordToPageEntry(PartMem[PDEaddr($base, $ptr)]).<> in $pde.present == ?Present && $pde.write == ?Write && $pde.base == page_table_index_to_addr($pte_start, PageDirectoryOffset($ptr)) ); invariant word($iter); invariant ($iter <= ?numPDEs); invariant logical_addressing_inv(init, ptMem, core_state); invariant (forall addr:int :: { $part.vars[ptOwner__id].dom[addr] } ptAddr(addr) ==> $part.vars[ptOwner__id].dom[addr]); invariant $part.vars[me].dom == old($part).vars[me].dom; invariant ebx == $user_low; invariant esi == $user_high; invariant PartMem == $part.vars[ptOwner__id].map; invariant ptAddrOwned(ptMem); { //var oldPartMem:[int]int := PartMem; $page_entry := $cur_base; //assert(DsInvFlatSegmentation($State._cores[me]._seg_regs[DS])); call $page_entry := Or($page_entry, 7); // Set User, Write, and Present flags //assert(logical_addressing_inv_priv($State, $part.vars[ptOwner__id])); linear var tmp:int; call tmp := new_linear_int(); linear var tmpPtOwner__id:int := ptOwner__id; ptOwner__id := tmp; call logicalAddressingInvNotEnabledLemma($part, tmpPtOwner__id, ptMem); call tmpPtOwner__id := StoreShared(tmpPtOwner__id, $cur_addr, $page_entry); call logicalAddressingInvNotEnabledLemma($part, ptOwner__id, $part, tmpPtOwner__id); ptOwner__id := tmpPtOwner__id; PartMem := $part.vars[ptOwner__id].map; //assert(PartMem == oldPartMem[$cur_addr := $page_entry]); call lower_bits_dont_matter_lemma($cur_base, 7); // Helps prove invariant about <>.base $cur_addr := $cur_addr + ?sizeofPDE; $cur_base := $cur_base + ?pageTableSize; assert(aligned4k($cur_base)); $iter := $iter + 1; call alignment_is_mod4_lemma(); assert(Aligned($cur_addr)); assert($iter <= ?numPDEs); } var $pde_mem:[int]int := PartMem; call select_non_negative_lemma(); call shr_preserves_word_lemma(); call select_preserves_word_lemma(); call upper_bits_clear_ubound_lemma(); call upper_bits_clear_lbound_lemma(); call pointer_pieces_lemma(); call ptr_offsets_lemma(); call or_with_3_lemma(); call clear_12_lemma(); // Create the PTEs assert($cur_addr == $base + ?pageDirSize); $cur_base := 0; // First page frame is the bottom of memory $iter := 0; call alignment_is_mod4_lemma(); while ($iter < ?totalPTEs) invariant !init; invariant logical_addressing_inv(init, ptMem, core_state); invariant (forall addr:int :: { $part.vars[ptOwner__id].dom[addr] } ptAddr(addr) ==> $part.vars[ptOwner__id].dom[addr]); invariant memAddrMain($cur_addr) && Aligned($cur_addr); invariant $cur_addr == $base + ?pageDirSize + ?sizeofPTE*$iter; invariant $iter == ?totalPTEs || $cur_base == ?pageFrameSize*$iter; invariant aligned4k($cur_base); // Insist that this while loop doesn't destroy memory-related properties of the PDEs' while loop invariant (forall $ptr:int :: { lt($ptr, add($base, ?pageDirSize)) } (word($ptr) && lt($ptr, add($base, ?pageDirSize))) ==> PartMem[$ptr] == $pde_mem[$ptr] ); // Now, establish some properties of the PTEs invariant (forall $i:int :: { WordToPageEntry(PartMem[PTE_index_to_addr($pte_start, $i)]) } (le(0, $i) && lt($i, $iter)) ==> WordToPageEntry(PartMem[PTE_index_to_addr($pte_start, $i)]) != <>()); invariant (forall $ptr:int :: { le(0, flat_PTE_index($ptr)) } { lt(flat_PTE_index($ptr), $iter) } (word($ptr) && le(0, flat_PTE_index($ptr)) && lt(flat_PTE_index($ptr), $iter)) ==> le(0, PageDirectoryOffset($ptr)) && lt(PageDirectoryOffset($ptr), $iter) ); invariant (forall $ptr:int, $pde:PageEntry :: { WordToPageEntry(PartMem[PTEaddr($pde, $ptr)]) } (word($ptr) && le(0, flat_PTE_index($ptr)) && lt(flat_PTE_index($ptr), $iter) && $pde == WordToPageEntry(PartMem[PDEaddr($base, $ptr)]).<> && $pde.base == page_table_index_to_addr($pte_start, PageDirectoryOffset($ptr)) ) ==> WordToPageEntry(PartMem[PTEaddr($pde, $ptr)]) != <>() ); // Next two invariants help us prove some properties of the page tables we create invariant (forall $i:int :: { WordToPageEntry(PartMem[add($pte_start, mul(?sizeofPTE,$i))]).<>.base} (le(0, $i) && lt($i, $iter)) ==> WordToPageEntry(PartMem[add($pte_start, mul(?sizeofPTE,$i))]).<>.base == mul(?pageFrameSize,$i)); invariant (forall $ptr:int :: { WordToPageEntry(PartMem[PDEaddr($base, $ptr)]).<>.base } { page_table_index_to_addr($pte_start, PageDirectoryOffset($ptr))} word($ptr) ==> WordToPageEntry(PartMem[PDEaddr($base, $ptr)]).<>.base == page_table_index_to_addr($pte_start, PageDirectoryOffset($ptr)) ); invariant (forall $ptr:int, $pde:PageEntry :: { WordToPageEntry(PartMem[PTEaddr($pde, $ptr)]).<>.base } (word($ptr) && le(0, flat_PTE_index($ptr)) && lt(flat_PTE_index($ptr), $iter) && $pde == WordToPageEntry(PartMem[PDEaddr($base, $ptr)]).<> ) ==> $pde.base == page_table_index_to_addr($pte_start, PageDirectoryOffset($ptr)) ); invariant (forall $ptr:int, $pde:PageEntry :: { WordToPageEntry(PartMem[PTEaddr($pde, $ptr)]) } (word($ptr) && le(0, flat_PTE_index($ptr)) && lt(flat_PTE_index($ptr), $iter) && $pde == WordToPageEntry(PartMem[PDEaddr($base, $ptr)]).<> ) ==> WordToPageEntry(PartMem[PTEaddr($pde, $ptr)]).<>.base == mul(?pageFrameSize, flat_PTE_index($ptr)) ); invariant (forall $ptr:int, $pde:PageEntry :: { WordToPageEntry(PartMem[PTEaddr($pde, $ptr)]).<>.base } (word($ptr) && le(0, flat_PTE_index($ptr)) && lt(flat_PTE_index($ptr), $iter) && $pde == WordToPageEntry(PartMem[PDEaddr($base, $ptr)]).<> ) ==> WordToPageEntry(PartMem[PTEaddr($pde, $ptr)]).<>.base == ClearLSBs(12, $ptr) ); invariant (forall $ptr:int, $pde:PageEntry :: { WordToPageEntry(PartMem[PTEaddr($pde, $ptr)]).<> } (word($ptr) && !in_guard_region($ptr) && le(0, flat_PTE_index($ptr)) && lt(flat_PTE_index($ptr), $iter) && $pde == WordToPageEntry(PartMem[PDEaddr($base, $ptr)]).<> ) ==> WordToPageEntry(PartMem[PTEaddr($pde, $ptr)]).<>.present == ?Present && ((in_user_region($ptr, $user_low, $user_high) ==> WordToPageEntry(PartMem[PTEaddr($pde, $ptr)]).<>.user == ?User) && (!in_user_region($ptr, $user_low, $user_high) ==> WordToPageEntry(PartMem[PTEaddr($pde, $ptr)]).<>.user == ?System)) && WordToPageEntry(PartMem[PTEaddr($pde, $ptr)]).<>.write == ?Write ); invariant (forall $ptr:int, $pde:PageEntry :: { WordToPageEntry(PartMem[PTEaddr($pde, $ptr)]).<> } (word($ptr) && in_guard_region($ptr) && le(0, flat_PTE_index($ptr)) && lt(flat_PTE_index($ptr), $iter) && $pde == WordToPageEntry(PartMem[PDEaddr($base, $ptr)]).<> ) ==> WordToPageEntry(PartMem[PTEaddr($pde, $ptr)]).<>.present == ?Absent ); invariant word($iter); invariant $iter <= ?totalPTEs; invariant ebx == $user_low; invariant esi == $user_high; invariant PartMem == $part.vars[ptOwner__id].map; invariant ptAddrOwned(ptMem); invariant $part.vars[me].dom == old($part).vars[me].dom; { //var oldPartMem:[int]int := PartMem; //assert(PartMem == $part.vars[ptOwner__id].map); $page_entry := $cur_base; if ($iter != 0) { if ($user_low <= $cur_base) { if ($cur_base < $user_high) { assert(in_user_region($cur_base, $user_low, $user_high)); call $page_entry := Or($page_entry, 7); // Set User, Write, Present flags assert(WordToPageEntry($page_entry).<>.user == ?User); } else { assert(!in_user_region($cur_base, $user_low, $user_high)); call $page_entry := Or($page_entry, 3); // Set Write, Present flags assert(WordToPageEntry($page_entry).<>.user == ?System); } } else { assert(!in_user_region($cur_base, $user_low, $user_high)); call $page_entry := Or($page_entry, 3); // Set User, Write, Present flags assert(WordToPageEntry($page_entry).<>.user == ?System); } } linear var tmp:int; call tmp := new_linear_int(); linear var tmpPtOwner__id:int := ptOwner__id; ptOwner__id := tmp; call logicalAddressingInvNotEnabledLemma($part, tmpPtOwner__id, ptMem); call tmpPtOwner__id := StoreShared(tmpPtOwner__id, $cur_addr, $page_entry); call logicalAddressingInvNotEnabledLemma($part, ptOwner__id, $part, tmpPtOwner__id); ptOwner__id := tmpPtOwner__id; PartMem := $part.vars[ptOwner__id].map; //assert(PartMem == oldPartMem[$cur_addr := $page_entry]); call lower_bits_dont_matter_lemma($cur_base, 3); // Helps prove invariant about <>.base call lower_bits_dont_matter_lemma($cur_base, 7); // Helps prove invariant about <>.base $cur_addr := $cur_addr + ?sizeofPTE; assert(word($cur_base)); $iter := $iter + 1; if ($cur_base != 0xFFFFF000) { $cur_base := $cur_base + ?pageFrameSize; } } assert($cur_addr == $base + ?pageDirSize + ?sizeofPTE*?totalPTEs); call $cur_addr := Sub($cur_addr, 0x401000); assert($cur_addr == $base); // Prove that CR3 is correct // Prove that DTLBsAreFreshWrtMem(eax, $DTLB, PartMem) != <>() call shr_preserves_word_lemma(); call upper_bits_clear_ubound_lemma(); call upper_bits_clear_lbound_lemma(); call alignment_is_mod4_lemma(); // Prove that TLBsAreFreshWrtMem(eax, $TLB, PartMem) != <>(); // Step 1: Prove the PDE addrs are sane assert( (forall $ptr:int :: { LoadPhysical(PartMem, PDEaddr(eax, $ptr)) } word($ptr) ==> LoadPhysical(PartMem, PDEaddr(eax, $ptr)) != <>() ) ); // Step 2: Prove that PDEs in memory are sane (this gets us past the prereqs for TLBIsFreshWrtMemOneEntry) assert( (forall $ptr:int :: { PDE_index_to_addr(PageDirectoryBase(eax), PageDirectoryOffset($ptr)) } word($ptr) ==> lt(PDE_index_to_addr(PageDirectoryBase(eax), PageDirectoryOffset($ptr)), add($base, ?pageDirSize)) ) ); assert( (forall $ptr:int, $p2:int :: { lt($p2, add($base, ?pageDirSize)), add(PageDirectoryBase(eax), mul(?sizeofPDE, PageDirectoryOffset($ptr))) } (word($ptr) && word($p2) && $p2 == PDE_index_to_addr(PageDirectoryBase(eax), PageDirectoryOffset($ptr))) ==> lt($p2, add($base, ?pageDirSize)) ) ); assert( (forall $ptr:int,$p2:int :: { PDE_index_to_addr(PageDirectoryBase(eax), PageDirectoryOffset($ptr)), WordToPageEntry(PartMem[$p2]) } (word($ptr) && word($p2) && $p2 == PDE_index_to_addr(PageDirectoryBase(eax), PageDirectoryOffset($ptr))) ==> lt($p2, add($base, ?pageDirSize)) && WordToPageEntry(PartMem[$p2]) != <>() ) ); assert( (forall $ptr:int :: { PDE_index_to_addr(PageDirectoryBase(eax), PageDirectoryOffset($ptr)) } { PDEaddr(eax, $ptr) } word($ptr) ==> (PDEaddr(eax, $ptr) == PDE_index_to_addr(PageDirectoryBase(eax), PageDirectoryOffset($ptr))) ) ); assert( (forall $ptr:int :: { WordToPageEntry(LoadPhysical(PartMem, PDEaddr(eax, $ptr)).<>) } word($ptr) ==> WordToPageEntry(LoadPhysical(PartMem, PDEaddr(eax, $ptr)).<>) != <>() ) ); // Step 3: Prove that the PTEaddrs formed via the PDEs are sane call clear_select_consistent_lemma(); assert( (forall $ptr:int, $pde:PageEntry :: { LoadPhysical(PartMem, PTEaddr($pde, $ptr)) } (word($ptr) && $pde == WordToPageEntry(LoadPhysical(PartMem, PDEaddr(eax, $ptr)).<>).<>) ==> LoadPhysical(PartMem, PTEaddr($pde, $ptr)) != <>() )); // Step 4: Prove that the PTEs are all sane assert( (forall $ptr:int, $pde:PageEntry :: { WordToPageEntry(PartMem[PDE_index_to_addr($base, PageDirectoryOffset($ptr))]).<>, le($pte_start, $pde.base) } (word($ptr) && $pde == WordToPageEntry(PartMem[PDE_index_to_addr($base, PageDirectoryOffset($ptr))]).<> ) ==> le($pte_start, $pde.base) && lt($pde.base, PTE_index_to_addr($pte_start, ?totalPTEs)) ) ); // Prove that we build a flat page table assert( forall $ptr:int :: { lt(flat_PTE_index($ptr), ?totalPTEs) } word($ptr) ==> le(0, flat_PTE_index($ptr)) && lt(flat_PTE_index($ptr), ?totalPTEs) ); call ptr_reconstruction_lemma(); } implementation enablePaging($base:int) { ebx := eax; esi := eax; call esi := Add(esi, 4096); // Create a 1-page user region here. REVIEW: We don't actually want the user to write data here! call alignment_4k_is_mod4096_lemma(); call buildLinearPageTables(); // Expects base in eax. Returns the new value for CR3 in eax var $newCR3 @ eax; assert(page_tables_correctly_situated($part.vars[ptOwner__id].map, eax)); call WriteCR3($newCR3); assert(LA(init, core_state, ptMem)); call ecx := ReadCR0(); assert(word(ecx)); call ecx := Or(ecx, 0x80000000); call or_with_pow2_31_lemma(); call WriteCR0(ecx); call get_set_lemma(); call set_bit_preserves_word_lemma(); assert(LA(me, true, $State, ptMem)); } */ } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Base/Overflow.imp.beat ================================================ //-private-import BaseSpec; //-private-import MemorySpec; //-private-import IoTypesSpec; //-private-import MachineStateSpec; //-private-import AssemblySpec; //-private-import InterruptsSpec; //-private-import IoSpec; //- //- //- //-private-import Partition; //-private-import Core; //-private-import LogicalAddressing; //-private-import Stacks; //-private-import Instructions; //-private-import Separation; //-private-import Util; //- //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module implementation Overflow { #ifdef UNVERIFIED_PRINTSTACKTRACE procedure PrintStackTrace(my r_in:regs) returns (r_out:regs) { my var r:regs := r_in; var m:mem; var core_state:core_state; call serialDbgNewlineOut(); call serialDbgMarkOut(); //edi := esp; call r:= instr_Mov(r, ECX, OConst(0x45)); call serialDbgDataOut8(); call r:= instr_Mov(r, ECX, OConst(0x44)); call serialDbgDataOut8(); call r:= instr_Mov(r, ECX, OConst(0x49)); call serialDbgDataOut8(); call r:= instr_Mov(r, ECX, OConst(0x20)); call serialDbgDataOut8(); call r:= instr_Mov(r, ESI, OReg(EDI)); call serialDbgWordOut(); call r:= instr_Mov(r, EDI, OReg(ESP)); call r:= instr_Mov(r, EBP, OConst(0)); while (ebp <= 400) { //- print address call r:= instr_Mov(r, ESI, OReg(EDI)); call serialDbgWordOut(); call r:= instr_Mov(r, ECX, OConst(32)); call serialDbgDataOut8(); //- print value call r:= instr_Load(r, core_state, m, ESI, OMem(MReg(EDI,0))); call serialDbgWordOut(); call serialDbgNewlineOut(); call r:= instr_Add(r, EDI, OConst(4)); call r:= instr_Add(r, EBP, OConst(1)); } print_stack_trace_loop: goto print_stack_trace_loop; } #endif //- UNVERIFIED_PRINTSTACKTRACE implementation Overflow(my r:regs, my c:core_state) { my var _r:regs; my var m:mem; call _r := instr_Mov(r, EAX, OConst(0x41526374)); call _r := instr_Mov(_r, EDX, OConst(0xb8000)); call instr_VgaDebugStore16(_r, OMem(MReg(EDX, 0)), OReg(EAX)); #ifdef UNVERIFIED_PRINTSTACKTRACE call _r:=PrintStackTrace(_r); #endif //- UNVERIFIED_PRINTSTACKTRACE // TODO: // call instr_Mov(EAX, OConst(0x55551001)); // call debugBreak(); overflow_loop: goto overflow_loop; } } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Base/Partition.ifc.beat ================================================ //-private-import BaseSpec; //-private-import MemorySpec; //-private-import IoTypesSpec; //-private-import MachineStateSpec; //-private-import AssemblySpec; //-private-import InterruptsSpec; //-private-import IoSpec; //- //- //- //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module interface Partition { } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Base/Partition.imp.beat ================================================ //-private-import BaseSpec; //-private-import MemorySpec; //-private-import IoTypesSpec; //-private-import MachineStateSpec; //-private-import AssemblySpec; //-private-import InterruptsSpec; //-private-import IoSpec; //- //- //- //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module implementation Partition { } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Base/Separation.ifc.beat ================================================ //-private-import BaseSpec; //-private-import MemorySpec; //-private-import IoTypesSpec; //-private-import MachineStateSpec; //-private-import AssemblySpec; //-private-import InterruptsSpec; //-private-import IoSpec; //- //- //- //-private-import Partition; //-private-import Core; //-private-import Util; //-private-import LogicalAddressing; //-private-import Stacks; //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module interface Separation { //- Memory layout: //- sMem: Nucleus private stack //- dMem: Nucleus private data //- argsMem: (Untrusted) Arguments from the bootloader //- pciMem: Memory-mapped PCI device info //- tMem[]: Thread control blocks //- fMem[]: Managed code stacks //- gcMem: GC memory (heap + auxiliary data) #define $DECL__MemVars me:int, init:bool, statics:mem, mems:mems #define $DECL_Mem_Vars me:int, init:bool, stk:mem, statics:mem, core_state:core_state, ptMem:mem, mems:mems #define $__MemVars init, statics, mems #define $_MemVars init, stk, statics, core_state, ptMem, mems #define $Mem_Vars me, $_MemVars #define DECL_IoVars io:IOState #define $IoVars io #ifdef AppLoader const ?CodeSpace:int := 0x10000; // 64 KB #else const ?CodeSpace:int := 0x100000; // 1 MB #endif //-/////////////////////////////////////////////// //- If you change any of the consts below, //- be sure to update stackGcOffset in: //- GC\SimpleCollector_i.beat //- DafnyCC/RegAlloc.cs //- If your change affects argLo, you also need //- to change the offset SKINIT_args in the bootloader //- in Trusted\Bootloader\blsingularity.cpp. //-/////////////////////////////////////////////// //- Reserve fixed amount of space for all but gcMem: const ?SSize:int := 4096; //- Must be the same as ?FSize! const ?DSize:int := 1024; const ?ArgSize:int := 1024; const ?PciSize:int := 1024; //- 8 * 65536; const ?ExtraSize:int := 0xF400; //- Extra buffer space we can distribute if needed const ?AppCodeOffset:int := 0x30000; const ?AppCodeSpace:int := 0x100000; //-1024*1024; const ?TSize:int := 0; //- 256; const ?FSize:int := 4096; //- Must be the same as ?SSize! //- Rest of memory devoted to gcMem //const ?sLo:int := 0x32F000; // ?memLo // ?ptHi; const ?sLo:int := ?CodeBase + ?CodeSpace + 0x1F000; //- Allow 124KB for DEV const ?sHi:int := ?sLo + ?SSize; const ?dLo:int := ?sHi; const ?dHi:int := ?dLo + ?DSize; const ?argLo:int := ?dHi; const ?argHi:int := ?argLo + ?ArgSize; const ?pciLo:int := ?argHi; const ?pciHi:int := ?pciLo + ?PciSize; const ?extraLo:int := ?pciHi; const ?extraHi:int := ?extraLo + ?ExtraSize; const ?appCodeLo:int := ?extraHi; const ?appCodeHi:int := ?appCodeLo + ?AppCodeSpace; const ?tLo:int := ?appCodeHi; const ?tHi:int := ?tLo + ?NumStacks * ?TSize; const ?fLo:int := ?tHi; const ?fHi:int := ?fLo + ?NumStacks * ?FSize; //- valid gc-controlled addresses (must be disjoint from null values) //- warning: because of interior pointers, ?gcHi must be a 32-bit word //- (it can equal 2^32 - 1, but not 2^32) const ?gcLo:int := ?fHi; const ?gcHi:int := ?memHi; function gcAddr(i:int):bool {?gcLo <= i && i < ?gcHi} function gcAddrEx(i:int):bool {?gcLo <= i && i <= ?gcHi} function isStack(s:int):bool {0 <= s && s < ?NumStacks} //function ptAddr(i:int):bool { ?ptLo <= i && i < ?ptHi } function ptAddrEx(i:int):bool { ?ptLo <= i && i <= ?ptHi } function sAddr(i:int):bool {?sLo <= i && i < ?sHi} function sAddrEx(i:int):bool {?sLo <= i && i <= ?sHi} function dAddr(i:int):bool {?dLo <= i && i < ?dHi} function dAddrEx(i:int):bool {?dLo <= i && i <= ?dHi} function argAddr(i:int):bool {?argLo <= i && i < ?argHi} function argAddrEx(i:int):bool {?argLo <= i && i <= ?argHi} function appCodeAddr(i:int):bool {?appCodeLo <= i && i < ?appCodeHi} function appCodeAddrEx(i:int):bool {?appCodeLo <= i && i <= ?appCodeHi} function pciAddr(i:int):bool {?pciLo <= i && i < ?pciHi} function pciAddrEx(i:int):bool {?pciLo <= i && i <= ?pciHi} function extraAddr(i:int):bool {?extraLo <= i && i < ?extraHi} function extraAddrEx(i:int):bool {?extraLo <= i && i <= ?extraHi} function fAddr(s:int, i:int):bool {isStack(s) && ?fLo + s * ?FSize <= i && i < ?fLo + s * ?FSize + ?FSize} function fAddrEx(s:int, i:int):bool {isStack(s) && ?fLo + s * ?FSize <= i && i <= ?fLo + s * ?FSize + ?FSize} function tAddr(s:int, i:int):bool {isStack(s) && ?tLo + s * ?TSize <= i && i < ?tLo + s * ?TSize + ?TSize} function tAddrEx(s:int, i:int):bool {isStack(s) && ?tLo + s * ?TSize <= i && i <= ?tLo + s * ?TSize + ?TSize} #ifdef AppLoader function DEVAddr(i:int):bool {?DEVLo <= i && i < ?CodeBase + 64*1024 + 124*1024} #else function DEVAddr(i:int):bool { ?memLo <= i && i < ?CodeBase + 0x101000 } //function DEVAddr(i:int):bool { false } #endif type mems = linear mems( linear dat:mem, //- nucleus private data linear arg:mem, //- bootloader-supplied arguments //linear appCode:mem, // code for the real application linear pci:mem, //- PCI-related data linear gc:mem, //- garbage-collected heap linear frm:mem, //- garbage-collected stack frames frms:[int][int]int, linear tcb:mem, //- thread control blocks tcbs:[int][int]int); function memsInv(this:mems):bool { (forall i:int::{memAddr(i)} memAddrMain(i) ==> memAddr(i)) && (forall i:int::{dat.dom[i]} dat.dom[i] <==> dAddr(i)) && (forall i:int::{arg.dom[i]} arg.dom[i] <==> argAddr(i)) //&& (forall i:int::{appCode.dom[i]} appCode.dom[i] <==> appCodeAddr(i)) && (forall i:int::{pci.dom[i]} pci.dom[i] <==> pciAddr(i)) && (forall i:int::{gc.dom[i]} gc.dom[i] <==> gcAddr(i)) && (forall i:int::{frm.dom[i]} frm.dom[i] <==> ?fLo <= i && i < ?fHi) && (forall i:int::{tcb.dom[i]} tcb.dom[i] <==> ?tLo <= i && i < ?tHi) && (forall s:int, i:int::{frms[s][i]} fAddr(s, i) ==> frms[s][i] == frm[i]) && (forall s:int, i:int::{tcbs[s][i]} tAddr(s, i) ==> tcbs[s][i] == tcb[i]) } #define $dMem mems.dat #define $argMem mems.arg //#define $appCodeMem mems.appCode #define $pciMem mems.pci #define $gcMem mems.gc #define $fMems mems.frms #define $tMems mems.tcbs var CodeBase @ statics; var CodeSpace @ statics; var StackCheck @ statics; var SLo @ statics; var DLo @ statics; var ArgLo @ statics; var AppCodeLo @ statics; var PciLo @ statics; var TLo @ statics; var FLo @ statics; var GcLo @ statics; var GcHi @ statics; var DmaAddr @ statics; function MemSepInv(dummy:bool):bool; function{:opaque} MemInvDetails(statics:mem, mems:mems):bool { MemSepInv(true) && (forall i:int::{memAddr(i)}{statics.dom[i]} (memAddr(i) ==> statics.dom[i] || sAddr(i) || mems.dat.dom[i] || mems.arg.dom[i] || appCodeAddr(i) || mems.pci.dom[i] || mems.gc.dom[i] || mems.frm.dom[i] || mems.tcb.dom[i] || DEVAddr(i) || extraAddr(i))) // (memAddr(i) ==> statics.dom[i] || sAddr(i) || mems.dat.dom[i] || mems.arg.dom[i] || mems.appCode.dom[i] || mems.pci.dom[i] || mems.gc.dom[i] || mems.frm.dom[i] || mems.tcb.dom[i] || DEVAddr(i))) && memsInv(mems) && statics.dom[&CodeBase] && statics.dom[&CodeSpace] && statics.dom[&StackCheck] && statics.dom[&SLo] && statics.dom[&DLo] && statics.dom[&ArgLo] && statics.dom[&AppCodeLo] && statics.dom[&PciLo] && statics.dom[&TLo] && statics.dom[&FLo] && statics.dom[&GcLo] && statics.dom[&GcHi] && statics.dom[&DmaAddr] && ?gcLo <= ?gcHi && Aligned(?sLo) && Aligned(?dLo) && Aligned(?argLo) && Aligned(?appCodeLo) && Aligned(?pciLo) && Aligned(?tLo) && Aligned(?fLo) && Aligned(?gcLo) && Aligned(?gcHi) && CodeBase == ?CodeBase && CodeSpace == ?CodeSpace && SLo == ?sLo && DLo == ?dLo && ArgLo == ?argLo && AppCodeLo == ?appCodeLo && PciLo == ?pciLo && TLo == ?tLo && FLo == ?fLo && GcLo == ?gcLo && GcHi == ?gcHi } function MemInvLocal($DECL_Mem_Vars):bool { MemInvDetails(statics, mems) && (forall i:int::{memAddr(i)}{stk.dom[i]} stk.dom[i] == sAddr(i)) // && (forall i:int::{memAddr(i)}{mems.appCode.dom[i]} mems.appCode.dom[i] == appCodeAddr(i)) } function MemInv($DECL_Mem_Vars):bool { MemInvLocal($Mem_Vars) && logical_addressing_inv(init, ptMem, core_state) && !paging_enabled(core_state) // until we have enough memory to enable paging && !init // TODO: remove this restriction #ifdef AppLoader && ?CodeBase == 0x300000 #else && ?CodeBase == 0x340000 #endif } // TODO: get Beat to generate these when importing Boogie files: function IOState_update___pci(io:IOState, x:PciState):IOState { IOState(io._vga, io._keyboard, io._iom, x, io._inCtr, io._outCtr) } function PciState_update__PciConfigState(pci:PciState, x:[int]int):PciState { PciState(pci.PciConfigId, pci.PciConfigOffset, x) } //function FDom(s:int):[int]bool { (lambda i:int::fAddr(s, i)) } //function TDom(s:int):[int]bool { (lambda i:int::tAddr(s, i)) } procedure initSeparation(linear mem:mem) returns(linear stk:mem, linear statics:mem, linear mems:mems, linear appCode:mem); inout my r:regs, my core_state:core_state; requires !init; requires Aligned(?sLo); requires Aligned(?memHi); requires ?memLo <= ?sLo; requires ?sLo <= ?memHi; requires ebp == ?CodeBase; requires ebx == ?CodeSpace; requires ecx == ?sLo; requires edx == ?memHi; #ifdef AppLoader requires ?CodeBase == 0x300000; #else requires ?CodeBase == 0x340000; #endif requires (forall ptr:int :: !memAddrMain(ptr) ==> !DEVAddr(ptr)); requires (forall i:int::{memAddr(i)} ?memLo <= i && i < ?memHi ==> memAddr(i)); requires logical_addressing_inv(init, ptMem, core_state); requires (forall i:int::{memAddr(i)}{mem.dom[i]} TV(i) ==> (memAddr(i) && !DEVAddr(i) ==> mem.dom[i])); requires !paging_enabled(core_state); requires !init; modifies efl, eax, ecx, edx, esp; ensures MemInv($Mem_Vars); ensures (forall i:int::{appCodeAddr(i)}{appCode.dom[i]} appCode.dom[i] == appCodeAddr(i)); ensures esp == old(esp); //- Reserve n bytes of stack space //- make sure both words in RIP are aligned for x64 function SMemRequire(n:int, sMem:mem, $esp:int) returns(bool) { Aligned($esp) #ifdef x64 && Aligned($esp + 4) #endif && ?sLo + n <= $esp && $esp <= ?sHi } //- Reserve n bytes of stack space, require m bytes for locals function SMemRequireInline(n:int, m:int, sMem:mem, $esp:int) returns(bool) { Aligned($esp) #ifdef x64 && Aligned($esp + 4) #endif && Aligned($esp + m) && ?sLo + n <= $esp && $esp + m <= ?sHi } //- Reserve n bytes of stack space, and require return address on stack //- Make sure both words in RIP are mapped in memory for x64 function SMemRequireRA(n:int, sMem:mem, $esp:int, $RET:ReturnTo) returns(bool) { SMemRequire(n, sMem, $esp) #ifdef x64 && ?sLo + n <= $esp && $esp <= ?sHi - 8 && ReturnToAddr64(sMem[$esp], sMem[$esp + 4]) == $RET #else && ?sLo + n <= $esp && $esp <= ?sHi - 4 && ReturnToAddr32(sMem[$esp]) == $RET #endif } //- Stack contents not altered function SMemInv(sMem:mem, oldSMem:mem, $esp:int, oldEsp:int) returns(bool) { $esp == oldEsp && (forall i:int::{sMem[i]} $esp <= i ==> sMem[i] == oldSMem[i]) } //- Stack contents not altered function SMemEnsure(sMem:mem, oldSMem:mem, $esp:int, oldEsp:int) returns(bool) { $esp == oldEsp + IPSize && (forall i:int::{sMem[i]} $esp <= i ==> sMem[i] == oldSMem[i]) } atomic ghost procedure alignCall(sp:int) requires Aligned(sp); ensures Aligned(sp - 4); #ifdef x64 ensures Aligned(sp - 8); #endif } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Base/Separation.imp.beat ================================================ //-private-import BaseSpec; //-private-import MemorySpec; //-private-import IoTypesSpec; //-private-import MachineStateSpec; //-private-import AssemblySpec; //-private-import InterruptsSpec; //-private-import IoSpec; //- //- //- //-private-import Partition; //-private-import Core; //-private-import Util; //-private-import LogicalAddressing; //-private-import Stacks; //-private-import Instructions; //- //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module implementation Separation { function implementation MemSepInv(dummy:bool):bool { true && (forall i:int::{memAddr(i)} memAddrMain(i) ==> memAddr(i)) } function idiv(x:int, y:int):int { x div y } implementation initSeparation(linear mem_in:mem) returns(linear stk:mem, linear statics:mem, linear mems:mems, linear appCode:mem) { linear var mem:mem := mem_in; call reveal_MemInvDetails(); // call eax := AddChecked(eax, 0x190000); //call eax := AddChecked(eax, 8192); eax := edx; assert eax >= ecx; call eax := Sub(eax, ecx); if (eax <= 0x132000) { eax := 0x55550011; call debugBreak(); } linear var dat:mem; linear var arg:mem; //linear var appCode:mem; linear var pci:mem; linear var gc:mem; linear var frm:mem; linear var tcb:mem; call stk := memEmpty(); call dat := memEmpty(); call arg := memEmpty(); call appCode := memEmpty(); call pci := memEmpty(); call gc := memEmpty(); call frm := memEmpty(); call tcb := memEmpty(); call mem, stk := memTransfer(mem, stk, (lambda i:int::sAddr(i))); call mem, dat := memTransfer(mem, dat, (lambda i:int::dAddr(i))); call mem, arg := memTransfer(mem, arg, (lambda i:int::argAddr(i))); call mem, pci := memTransfer(mem, pci, (lambda i:int::pciAddr(i))); call mem, appCode := memTransfer(mem, appCode, (lambda i:int::appCodeAddr(i))); call mem, gc := memTransfer(mem, gc, (lambda i:int::gcAddr(i))); call mem, frm := memTransfer(mem, frm, (lambda i:int::?fLo <= i && i < ?fHi)); call mem, tcb := memTransfer(mem, tcb, (lambda i:int::?tLo <= i && i < ?tHi)); var frms:[int][int]int := (lambda s:int::(lambda i:int::frm[i])); var tcbs:[int][int]int := (lambda s:int::(lambda i:int::tcb[i])); //let mems := mems(dat, arg, appCode, pci, gc, frm, frms, tcb, tcbs); let mems := mems(dat, arg, pci, gc, frm, frms, tcb, tcbs); statics := mem; CodeBase := ebp; CodeSpace := ebx; SLo := ecx; assert TV(ecx) && TO(1024); call ecx := Add(ecx, 4096); DLo := ecx; assert TV(ecx) && TO(256); call ecx := Add(ecx, 1024); ArgLo := ecx; assert TV(ecx) && TO(256); call ecx := Add(ecx, 1024); PciLo := ecx; assert TV(ecx) && TO(256); call ecx := Add(ecx, 1024); assert ?extraLo == ecx; assert TV(ecx) && TO(0x3D00); call ecx := Add(ecx, 0xF400); assert ?extraHi == ecx; AppCodeLo := ecx; assert TV(ecx) && TO(0x40000); call ecx := Add(ecx, 0x100000); TLo := ecx; assert TV(ecx) && TO(4096); FLo := ecx; assert TV(ecx) && TO(273920); call ecx := Add(ecx, 4096); GcLo := ecx; GcHi := edx; assert SLo == ?sLo; assert DLo == ?dLo; assert ArgLo == ?argLo; assert AppCodeLo == ?appCodeLo; assert PciLo == ?pciLo; assert TLo == ?tLo; assert FLo == ?fLo; assert GcLo == ?gcLo; assert GcHi == ?gcHi; assert ?fLo - ?sLo == 0x111000; //-stackGcOffset; } implementation alignCall(sp:int) requires Aligned(sp); ensures Aligned(sp - 4); ensures Aligned(sp - 8); { #ifdef x64 assert TV(sp) && TV(sp-4) && TO(0 - 1); #else assert TV(sp) && TO(0 - 1); #endif } } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Base/Stacks.ifc.beat ================================================ //-private-import BaseSpec; //-private-import MemorySpec; //-private-import IoTypesSpec; //-private-import MachineStateSpec; //-private-import AssemblySpec; //-private-import InterruptsSpec; //-private-import IoSpec; //- //- //- //-private-import Partition; //-private-import Core; //-private-import Util; //-private-import LogicalAddressing; //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module interface Stacks //import Util; { //-//////////////////////////////////////////////////////////////////////////// //- STACKS //-//////////////////////////////////////////////////////////////////////////// //- Stack identifiers are numbered 0, 1, 2, ..., ?NumStacks - 1 const ?NumStacks:int := 1; //- 64; const ?InitialStack:int := 0; const ?InterruptStack:int := 0; //var $S:int; // current stack id const $S:int := 0; // Each managed stack $s grows from StackHi($s) down to StackLo($s) // (see Gc_i.beat) // Managed code can only write to the stack from an address StackLo($s) <= i < StackHi($s). // --> This includes writes caused by calls and interrupts! // A call consumes 4 bytes of stack space. // An interrupt can consume as much as ?InterruptReserve bytes of stack space. // Thus, the managed code should never allow esp < StackLo($s) + ?InterruptReserve // when interrupts are enabled or when traps (e.g. null pointer or divide-by-zero traps) // are possible. // The managed code can enforce this with run-time checks against StackCheck: // If StackCheck <= esp, then there at least ?StackReserve + ?InterruptReserve // bytes are available below esp. // When managed code calls the Nucleus, it must guarantee that // StackLo($s) <= esp // holds after the call instruction. // (So before the call, StackLo($s) + 4 <= esp.) // When the Nucleus returns to native code, it restores the esp before the call. const ?InterruptReserve:int := 16; const ?StackReserve:int := 4096; // var StackCheck:int; // in Separation module //- Each stack can be in one of four states: //- - empty //- - running //- - yielded(ebp, esp, eip) //- - interrupted(eax, ebx, ecx, edx, esi, edi, ebp, esp, eip, cs, eflags) //- The arguments to yielded and interrupted are the registers that must //- be restored to resume the thread. (For example, to restore yielded(b, s, i), //- one might set ebp == b, esp == s - 4, $Mem[esp] == i, and then invoke "ret"). type StackState; readonly var $StackState:[int]StackState; const StackEmpty:StackState; const StackRunning:StackState; function StackYielded($ebp:int, $esp:int, $eip:int) returns(StackState); function StackInterrupted($eax:int, $ebx:int, $ecx:int, $edx:int, $esi:int, $edi:int, $ebp:int, $esp:int, $eip:int, $cs:int, $efl:int) returns(StackState); //- The four stack states are distinct: const ?STACK_EMPTY:int := 0; const ?STACK_RUNNING:int := 1; const ?STACK_YIELDED:int := 2; const ?STACK_INTERRUPTED:int := 3; function StackStateTag(state:StackState) returns(int); function IsStackStateTag(tag:int) returns(bool) { 0 <= tag && tag <= 3 } function IsStackStateTagFor(tag:int, state:StackState) returns(bool) { IsStackStateTag(tag) && tag == StackStateTag(state) } //- To switch to an StackEmpty stack $s, the stack memory must contain one word: //- StackHi($s) - 8: managedEntryPoint //- Execution begins by returning to the managedEntryPoint. This entry point //- should never return. (This is enforced by the TAL checker.) const ?KernelEntryPoint:int := 0xdeadbeef; /*TODO: atomic ghost*/ procedure stacksProofs(); inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState; requires logical_addressing_inv(init, ptMem, core_state); ensures logical_addressing_inv(init, ptMem, core_state); ensures (StackStateTag(StackEmpty) == ?STACK_EMPTY); ensures (StackStateTag(StackRunning) == ?STACK_RUNNING); ensures (forall $ebp:int, $esp:int, $eip:int::{StackYielded($ebp, $esp, $eip)} StackStateTag(StackYielded($ebp, $esp, $eip)) == ?STACK_YIELDED); ensures (forall $eax:int, $ebx:int, $ecx:int, $edx:int, $esi:int, $edi:int, $ebp:int, $esp:int, $eip:int, $cs:int, $efl:int:: {StackInterrupted($eax, $ebx, $ecx, $edx, $esi, $edi, $ebp, $esp, $eip, $cs, $efl)} StackStateTag(StackInterrupted($eax, $ebx, $ecx, $edx, $esi, $edi, $ebp, $esp, $eip, $cs, $efl)) == ?STACK_INTERRUPTED); ensures (forall $ebp1:int, $esp1:int, $eip1:int, $ebp2:int, $esp2:int, $eip2:int ::{StackYielded($ebp1, $esp1, $eip1), StackYielded($ebp2, $esp2, $eip2)} StackYielded($ebp1, $esp1, $eip1) == StackYielded($ebp2, $esp2, $eip2) ==> $ebp1 == $ebp2 && $esp1 == $esp2 && $eip1 == $eip2); ensures (forall $eax1:int, $ebx1:int, $ecx1:int, $edx1:int, $esi1:int, $edi1:int, $ebp1:int, $esp1:int, $eip1:int, $cs1:int, $efl1:int, $eax2:int, $ebx2:int, $ecx2:int, $edx2:int, $esi2:int, $edi2:int, $ebp2:int, $esp2:int, $eip2:int, $cs2:int, $efl2:int ::{StackInterrupted($eax1, $ebx1, $ecx1, $edx1, $esi1, $edi1, $ebp1, $esp1, $eip1, $cs1, $efl1), StackInterrupted($eax2, $ebx2, $ecx2, $edx2, $esi2, $edi2, $ebp2, $esp2, $eip2, $cs2, $efl2)} StackInterrupted($eax1, $ebx1, $ecx1, $edx1, $esi1, $edi1, $ebp1, $esp1, $eip1, $cs1, $efl1) == StackInterrupted($eax2, $ebx2, $ecx2, $edx2, $esi2, $edi2, $ebp2, $esp2, $eip2, $cs2, $efl2) ==> $eax1 == $eax2 && $ebx1 == $ebx2 && $ecx1 == $ecx2 && $edx1 == $edx2 && $esi1 == $esi2 && $edi1 == $edi2 && $ebp1 == $ebp2 && $esp1 == $esp2 && $eip1 == $eip2 && $cs1 == $cs2 && $efl1 == $efl2); ensures word(?KernelEntryPoint); } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Base/Stacks.imp.beat ================================================ //-private-import BaseSpec; //-private-import MemorySpec; //-private-import IoTypesSpec; //-private-import MachineStateSpec; //-private-import AssemblySpec; //-private-import InterruptsSpec; //-private-import IoSpec; //- //- //- //-private-import Partition; //-private-import Core; //-private-import Util; //-private-import LogicalAddressing; //- //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module implementation Stacks { implementation stacksProofs() { // TODO infloop: invariant logical_addressing_inv(init, ptMem, core_state); goto infloop; } } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Base/Util.ifc.beat ================================================ //-private-import BaseSpec; //-private-import MemorySpec; //-private-import IoTypesSpec; //-private-import MachineStateSpec; //-private-import AssemblySpec; //-private-import InterruptsSpec; //-private-import IoSpec; //- //- //- //-private-import Partition; //-private-import Core; //-private-import LogicalAddressing; //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module interface Util { //- Write hex digit (ecx & 15) to screen offset edx procedure writeHexDigit(); inout my r:regs, my core_state:core_state; requires logical_addressing_inv(init, ptMem, core_state); requires 0 <= edx && edx <= 160 - 2; modifies efl, ecx; ensures logical_addressing_inv(init, ptMem, core_state); //- Write value eax to screen offset edx procedure writeHex(); inout my r:regs, my core_state:core_state; requires logical_addressing_inv(init, ptMem, core_state); requires 0 <= edx && edx <= 160 - 16; modifies efl, eax, ecx, edx; ensures logical_addressing_inv(init, ptMem, core_state); //- Write hex digit (ecx & 15) to screen offset edx procedure writeHexDigitIllogical(); inout my r:regs, my core_state:core_state; requires 0 <= edx && edx <= 160 - 2; modifies efl, ecx; //- Write value eax to screen offset edx procedure writeHexIllogical(); inout my r:regs, my core_state:core_state; requires 0 <= edx && edx <= 160 - 16; modifies efl, eax, ecx, edx; procedure debugBreak(); inout my r:regs, my core_state:core_state; modifies efl, eax, ecx, edx; ensures false; procedure DebugBreak(); inout my r:regs, my core_state:core_state, linear stk:mem; modifies efl, eax, ecx, edx, esp; ensures false; procedure initializeSerialPort(); inout my r:regs, my core_state:core_state; modifies efl, eax, edx; ensures serialPortConfigged(); //- Pass in a word via esi procedure serialDbgWordOut(); inout my r:regs, my core_state:core_state; requires serialPortConfigged(); modifies efl, eax, ebx, ecx, edx; procedure serialDbgNewlineOut(); inout my r:regs, my core_state:core_state; requires serialPortConfigged(); modifies efl, eax, ecx, edx; //- Print ^ followed by a newline, for situations where you don't want to touch ebx procedure serialDbgMarkOut(); inout my r:regs, my core_state:core_state; requires serialPortConfigged(); modifies efl, eax, ecx, edx; //- Pass in a byte via ebx procedure serialDbgByteOut(); inout my r:regs, my core_state:core_state; requires serialPortConfigged(); modifies efl, eax, ecx, edx; //- Pass in a raw byte via ecx procedure serialDbgDataOut8(); inout my r:regs, my core_state:core_state; requires serialPortConfigged(); modifies efl, eax, edx; //procedure serialDbgDataIn8(); // inout core:state_core; // requires serialPortConfigged(); // requires logical_addressing_inv(me, init, $State, $part, ptOwner__id, core); // requires $serialState.Mode.DLAB == false; // modifies $State, $serialState.In, $Eip, $Efl, eax, edx; // modifies $part; //// ensures $part.vars[me] == old($part).vars[me]; // ensures logical_addressing_inv(me, init, $State, $part, ptOwner__id, core); // ensures $serialState.In.Events[$serialState.In.Done] == and (eax, 255); // ensures $serialState.In.Done == old($serialState).In.Done + 1; } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Base/Util.imp.beat ================================================ //-private-import BaseSpec; //-private-import MemorySpec; //-private-import IoTypesSpec; //-private-import MachineStateSpec; //-private-import AssemblySpec; //-private-import InterruptsSpec; //-private-import IoSpec; //- //- //- //- //-private-import Partition; //-private-import Core; //-private-import IntLemmasBase; //-private-import LogicalAddressing; //-private-import Instructions; //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module implementation Util { //- Write hex digit (ecx & 15) to screen offset edx implementation writeHexDigit() { ecx := eax; call ecx := And(ecx, 15); if (ecx < 10) { ecx := ecx + 0x0c30; } else { call ecx := AddChecked(ecx, 0x0c37); } call VgaDebugStore16(edx + 0xb8000, ecx); } //- Write value eax to screen offset edx implementation writeHex() { edx := edx + 14; call writeHexDigit(); edx := edx - 2; call eax := Shr(eax, 4); call writeHexDigit(); edx := edx - 2; call eax := Shr(eax, 4); call writeHexDigit(); edx := edx - 2; call eax := Shr(eax, 4); call writeHexDigit(); edx := edx - 2; call eax := Shr(eax, 4); call writeHexDigit(); edx := edx - 2; call eax := Shr(eax, 4); call writeHexDigit(); edx := edx - 2; call eax := Shr(eax, 4); call writeHexDigit(); edx := edx - 2; call eax := Shr(eax, 4); call writeHexDigit(); } implementation debugBreak() { edx := 2; call writeHexIllogical(); edx := 0xb8000; eax := 0; loop: invariant edx == 0xb8000; //invariant logical_addressing_inv(init, ptMem, core_state); //- Loop so we don't write to the screen too quickly (overwhelms card on phys machine?) ecx := 0; while (ecx <= 0x100000) invariant edx == 0xb8000; //invariant logical_addressing_inv(init, ptMem, core_state); invariant 0 <= ecx && ecx <= 0x100001; { ecx := ecx + 1; } //- Write to the screen to show we're still live call eax := LeaUnchecked(eax + 1); call VgaDebugStore16(edx, eax); goto loop; } implementation DebugBreak() { call debugBreak(); return; } //- Write hex digit (ecx & 15) to screen offset edx implementation writeHexDigitIllogical() { ecx := eax; call ecx := And(ecx, 15); if (ecx < 10) { ecx := ecx + 0x0c30; } else { call ecx := AddChecked(ecx, 0x0c37); } call VgaDebugStore16(edx + 0xb8000, ecx); } //- Write value eax to screen offset edx implementation writeHexIllogical() { edx := edx + 14; call writeHexDigitIllogical(); edx := edx - 2; call eax := Shr(eax, 4); call writeHexDigitIllogical(); edx := edx - 2; call eax := Shr(eax, 4); call writeHexDigitIllogical(); edx := edx - 2; call eax := Shr(eax, 4); call writeHexDigitIllogical(); edx := edx - 2; call eax := Shr(eax, 4); call writeHexDigitIllogical(); edx := edx - 2; call eax := Shr(eax, 4); call writeHexDigitIllogical(); edx := edx - 2; call eax := Shr(eax, 4); call writeHexDigitIllogical(); edx := edx - 2; call eax := Shr(eax, 4); call writeHexDigitIllogical(); } implementation initializeSerialPort() returns ( ) { //- enable DLAB and set baudrate 115200 edx := 0x3fb; eax := 0x80; call SerialDbgConfigOut(); edx := 0x3f8; eax := 0x01; call SerialDbgConfigOut(); edx := 0x3f9; eax := 0x00; call SerialDbgConfigOut(); //- disable DLAB and set 8N1 edx := 0x3fb; eax := 0x03; call SerialDbgConfigOut(); //- reset IRQ register edx := 0x3f9; eax := 0x00; call SerialDbgConfigOut(); //- enable fifo, flush buffer, enable fifo edx := 0x3fa; eax := 0x01; call SerialDbgConfigOut(); edx := 0x3fa; eax := 0x07; call SerialDbgConfigOut(); edx := 0x3fa; eax := 0x01; call SerialDbgConfigOut(); //- set RTS,DTR edx := 0x3fc; eax := 0x03; call SerialDbgConfigOut(); } implementation serialDbgWordOut() { //- Writes out esi, 8 bits at a time ebx := esi; call ebx := Shr(ebx, 24); call serialDbgByteOut(); ebx := esi; call ebx := Shr(ebx, 16); call serialDbgByteOut(); ebx := esi; call ebx := Shr(ebx, 8); call serialDbgByteOut(); ebx := esi; call serialDbgByteOut(); } implementation serialDbgNewlineOut() { //- Write a carriage return ecx := 13; call serialDbgDataOut8(); //- Write out a newline ecx := 10; call serialDbgDataOut8(); } implementation serialDbgMarkOut() { //- Write a caret with a carriage return ecx := 94; call serialDbgDataOut8(); call serialDbgNewlineOut(); } implementation serialDbgByteOut() { //- Truncate to byte size ecx := ebx; call ecx := And(ecx, 0xff); //- Convert top nibble to hex call ecx := Shr(ecx, 4); call and_bounds(); call shr_decreases(); if (ecx <= 9) { ecx := ecx + 48; //- ecx += '0' } else { ecx := ecx - 0xa; ecx := ecx + 97; //- ecx += 'a' } call serialDbgDataOut8(); //- Convert lower nibble to hex ecx := ebx; call ecx := And(ecx, 0xf); if (ecx <= 9) { ecx := ecx + 48; //- ecx += '0' } else { ecx := ecx - 0xa; ecx := ecx + 97; //- ecx += 'a' } call serialDbgDataOut8(); } implementation serialDbgDataOut8() { //- Loop until serial port is ready waitForSerialPort: invariant ecx == old(ecx); edx := 0x3fd; call SerialDbgStatusOut8(); call eax := And(eax, 0x20); if (eax == 0) { goto waitForSerialPort; } //- Write out the value in ecx edx := 0x3f8; eax := ecx; call SerialDbgDataOut8(); } //implementation serialDbgDataIn8() //{ // // Loop until serial port is ready //waitForSerialPort: // invariant logical_addressing_inv(me, init, $State, $part, ptOwner__id, core); // //invariant $part.vars[me] == old($part).vars[me]; // invariant $serialState.Mode.DLAB == false; // invariant $serialState.In.Done == old($serialState).In.Done; // // edx := 0x3fd; // call SerialDbgStatusIn8(); // call eax := And(eax, 0x1); // if (eax == 0) // { // goto waitForSerialPort; // } // // Read in the value in eax // edx := 0x3f8; // call SerialDbgDataIn8(); //} } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Devices/BitVectorLemmasDevices.ifc.beat ================================================ //-private-import BaseSpec; //-private-import MemorySpec; //- //- //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module interface BitVectorLemmasDevices { atomic ghost procedure _constDevices(); ensures $sub(1bv32, 1bv32) == 0bv32; ensures $sub(1bv32, 0bv32) == 1bv32; ensures $add(1bv32, 1bv32) == 2bv32; ensures $add(2bv32, 1bv32) == 3bv32; ensures $add(2bv32, 2bv32) == 4bv32; ensures $add(3bv32, 4bv32) == 7bv32; ensures $add(4bv32, 4bv32) == 8bv32; ensures $add(8bv32, 8bv32) == 16bv32; ensures $add(16bv32,16bv32) == 32bv32; atomic ghost procedure _lemma_and7_implies_mod_4(); ensures (forall x:bv32 :: $and(x, 7bv32) == 0bv32 ==> $mod(x, 4bv32) == 0bv32); atomic ghost procedure _lemma_shl_1(); ensures (forall amt:bv32 :: $le(0bv32, amt) && $lt(amt, 32bv32) ==> $gt($shl(1bv32, amt), 0bv32)); } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Devices/BitVectorLemmasDevices.imp.beat ================================================ //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- //-private-import BaseSpec; //-private-import MemorySpec; //- //-private-import BitVectorLemmasGc; //- //- //- //- module implementation BitVectorLemmasDevices { implementation _constDevices() {} implementation _lemma_and7_implies_mod_4() {} implementation _lemma_shl_1() {} } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Devices/IntLemmasDevices.ifc.beat ================================================ //-private-import BaseSpec; //-private-import MemorySpec; //-private-import IntSpec; //-private-import IoTypesSpec; //-private-import MachineStateSpec; //-private-import AssemblySpec; //-private-import BitVectorLemmasDevices; //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module interface IntLemmasDevices { atomic ghost procedure lemma_and7_implies_mod_4(); ensures (forall x:int :: word(x) ==> and(x, 7) == 0 ==> _mod(x, 4) == 0); atomic ghost procedure lemma_shl_1(); ensures (forall amt:int :: le(0, amt) && lt(amt, 32) ==> gt(shl(1, amt), 0)); } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Devices/IntLemmasDevices.imp.beat ================================================ //-private-import BaseSpec; //-private-import MemorySpec; //-private-import IntSpec; //-private-import BitVectorLemmasDevices; //- //- //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module implementation IntLemmasDevices { atomic ghost procedure _a($b1:bv32, $b2:bv32) requires word(add(I($b1), I($b2))); ensures add(I($b1), I($b2)) == I($add($b1, $b2)); { } atomic ghost procedure _s($b1:bv32, $b2:bv32) requires word(sub(I($b1), I($b2))); ensures sub(I($b1), I($b2)) == I($sub($b1, $b2)); { } atomic ghost procedure __constDevices() ensures 0 == I(0bv32); ensures 1 == I(1bv32); ensures 4 == I(4bv32); ensures 7 == I(7bv32); ensures 32 == I(32bv32); { call _constDevices(); call _s(1bv32, 1bv32); call _s(1bv32, 0bv32); call _a(1bv32, 1bv32); call _a(2bv32, 2bv32); call _a(2bv32, 1bv32); call _a(3bv32, 4bv32); call _a(4bv32, 4bv32); call _a(8bv32, 8bv32); call _a(16bv32, 16bv32); } implementation lemma_and7_implies_mod_4() { call __constDevices(); call _lemma_and7_implies_mod_4(); } implementation lemma_shl_1() { call __constDevices(); call _lemma_shl_1(); } } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Devices/IntelNIC.ifc.beat ================================================ //- Untrusted spec for interacting with the network card //- Implementation of the verified network driver //- //-private-import BaseSpec; //-private-import MemorySpec; //-private-import IoTypesSpec; //-private-import MachineStateSpec; //-private-import AssemblySpec; //-private-import InterruptsSpec; //-private-import IoSpec; //- //- //- //- //- //-private-import Core; //-private-import LogicalAddressing; //-private-import Overflow; //-private-import Util; //-private-import Stacks; //-private-import Partition; //-private-import Instructions; //-private-import Separation; //-private-import IntLemmasBase; //-private-import IntLemmasGc; //-private-import SimpleGcMemory; //-private-import SimpleCommon; //-private-import SimpleCollector; //-private-import IntLemmasDevices; //-private-import PCI; module interface IntelNIC { const ?intel_NIC_device_vendor_id:int := 0x107c8086; procedure map_network_card(); inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars; inout $absMem:[int][int]int, $toAbs:[int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout; requires NucleusInv(objLayouts, $S, $toAbs, $absMem, GcVars, $Mem_Vars, $stacksFrames, $IoVars); requires public(io._inCtr); requires public(io._outCtr); modifies io, efl, eax, ebx, ecx, edx, esi, edi, ebp, $pciMem; ensures NucleusInv(objLayouts, $S, $toAbs, $absMem, GcVars, $Mem_Vars, $stacksFrames, $IoVars); ensures PciConfigReadResult(ecx, 0, ?intel_NIC_device_vendor_id); ensures IsValidPciId(ecx); ensures eax == PciMemSize(ecx); ensures ebx == PciMemAddr(ecx); ensures word(PciMemAddr(ecx) + PciMemSize(ecx)); ensures io._pci.PciConfigState[ecx] == 4; ensures public(eax); ensures public(ebx); ensures public(ecx); ensures public(io._inCtr); ensures public(io._outCtr); } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Devices/IntelNIC.imp.beat ================================================ //- Implementation of the verified network driver //- //-private-import BaseSpec; //-private-import MemorySpec; //-private-import IoTypesSpec; //-private-import MachineStateSpec; //-private-import AssemblySpec; //-private-import InterruptsSpec; //-private-import IoSpec; //- //- //- //- //- //-private-import Core; //-private-import LogicalAddressing; //-private-import Overflow; //-private-import Util; //-private-import Stacks; //-private-import Partition; //-private-import Instructions; //-private-import Separation; //-private-import IntLemmasBase; //-private-import IntLemmasGc; //-private-import SimpleGcMemory; //-private-import SimpleCommon; //-private-import SimpleCollector; //-private-import IntLemmasDevices; //-private-import PCI; //- //- //- module implementation IntelNIC { implementation map_network_card() { call reveal_MemInvDetails(); ebp := 0x107c8086; call /* eax := */ pciFindDeviceVendor(?intel_NIC_device_vendor_id); ecx := eax; call eax := And(eax, 7); if (eax > 0) { eax := 0x55550070; call debugBreak(); } edi := PciLo; edx := PciLo; call edx := Add(edx, 1024); //- == ?pciHi call lemma_and7_implies_mod_4(); call pciMemMap(?pciLo, ?pciHi, ecx); //- Make sure the mapping fits into memory edx := ebx; call edx := AddWrap(edx, eax); if (edx <= ebx) { //- We wrapped around, so addr+size is off the end of memory eax := 0x55550071; call debugBreak(); } call reveal_WORD_HI(); assert ebx == PciMemAddr(ecx); assert eax == PciMemSize(ecx); call reveal_wrap32(ebx + eax); assert word(PciMemAddr(ecx) + PciMemSize(ecx)); } } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Devices/IoMain.ifc.beat ================================================ //-private-import BaseSpec; //-private-import MemorySpec; //-private-import IoTypesSpec; //-private-import MachineStateSpec; //-private-import AssemblySpec; //-private-import InterruptsSpec; //-private-import IoSpec; //- //- //- //- //- //-private-import Core; //-private-import LogicalAddressing; //-private-import Overflow; //-private-import Util; //-private-import Stacks; //-private-import Partition; //-private-import Instructions; //-private-import Separation; //-private-import IntLemmasBase; //-private-import IntLemmasGc; //-private-import SimpleGcMemory; //-private-import SimpleCommon; //-private-import SimpleCollector; //- //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module interface IoMain { const ?BYTE_VECTOR_VTABLE:int := 0; atomic ghost procedure espAligned(); inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState; requires Aligned(esp); ensures Aligned(esp - 4) && Aligned(esp - 8) && Aligned(esp - 12) && Aligned(esp - 16); ensures Aligned(esp - 20) && Aligned(esp - 24) && Aligned(esp - 28) && Aligned(esp - 32); ensures Aligned(esp - 36) && Aligned(esp - 40) && Aligned(esp - 44) && Aligned(esp - 48); ensures Aligned(esp - 52) && Aligned(esp - 56) && Aligned(esp - 60) && Aligned(esp - 64); atomic ghost procedure espAlignedInline(); inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState; requires Aligned(esp); ensures Aligned(esp + 4) && Aligned(esp + 8) && Aligned(esp + 12) && Aligned(esp + 16); ensures Aligned(esp + 20) && Aligned(esp + 24) && Aligned(esp + 28) && Aligned(esp + 32); ensures Aligned(esp + 36) && Aligned(esp + 40) && Aligned(esp + 44) && Aligned(esp + 48); ensures Aligned(esp + 52) && Aligned(esp + 56) && Aligned(esp + 60) && Aligned(esp + 64); //procedure startTimer(); // inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState; // requires word(ecx); // requires logical_addressing_inv(init, ptMem, core_state); // modifies state, efl, eax, $TimerSeq, $TimerFreq; // ensures TimerOk($TimerSeq) && $TimerFreq == old(ecx); // ensures logical_addressing_inv(init, ptMem, core_state); function PciUninitialized(io:IOState) returns (bool) { (forall i:int :: {io._pci.PciConfigState[i]} 0 <= i && i < 65536 ==> (io._pci.PciConfigState[i] == 0)) } procedure initIoInv(); inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars; inout $absMem:[int][int]int, $toAbs:[int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout; // inout iovars:ioVars; requires ?devMemHi - ?devMemLo > 0x204004; // requires ?memHi == ?devMemLo; // requires ?memHi == ?memLo + 0x7400; requires ?devMemLo mod 0x10000 == 0; // 64K aligned requires ecx == ?pciLo; requires edx == ?pciHi; requires (?pciHi - ?pciLo) mod 16 == 0; requires Aligned(?pciLo); requires serialPortConfigged(); requires PciUninitialized(io); // requires (forall i:int :: {io._pci.PciConfigState[i]} // 0 <= i && i < 65536 ==> (io._pci.PciConfigState[i] == 0)); //requires MemInv($Mem_Vars); requires MemInv($Mem_Vars) && commonVarsInv($commonVars, statics); //requires logical_addressing_inv(init, ptMem, core_state); // Included in MemInv modifies efl, eax, ecx, $pciMem; ensures IoInv($IoVars, $pciMem); //ensures MemInv($Mem_Vars); ensures MemInv($Mem_Vars) && commonVarsInv($commonVars, statics); //ensures logical_addressing_inv(init, ptMem, core); // Included in MemInv procedure checkIoFresh(); inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars; inout $absMem:[int][int]int, $toAbs:[int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout; requires ecx == ?pciLo; requires edx == ?pciHi; requires (?pciHi - ?pciLo) mod 16 == 0; requires Aligned(?pciLo); requires IoInv($IoVars, $pciMem); requires MemInv($Mem_Vars) && commonVarsInv($commonVars, statics); modifies efl, eax, ecx, $pciMem; ensures IoInv($IoVars, $pciMem); ensures MemInv($Mem_Vars) && commonVarsInv($commonVars, statics); ensures (forall i:int :: {io._pci.PciConfigState[i]} 0 <= i && i < 65536 ==> (io._pci.PciConfigState[i] == 0)); procedure initDEV(linear dev_states:DEV_StateMachines, linear dev_mem:mem) returns (linear new_mem:mem) inout my r:regs, my core_state:core_state, linear io:IOState; requires !init; requires ?CodeBase == 0x300000; requires (forall i:int :: {dev_states.states[i]} dev_states.states[i] is Init); requires (forall i:int :: {dev_mem.dom[i]} dev_mem.dom[i] <==> (?DEVLo <= i && i < ?DEVHi)); requires PciUninitialized(io); requires logical_addressing_inv(init, ptMem, core_state); requires public(io._inCtr); requires public(io._outCtr); modifies io, efl, eax, ebx, ecx, edx, esi, edi, ebp; ensures (forall i:int ::{ new_mem.dom[i] }{TV(i)} TV(i) ==> (new_mem.dom[i] <==> ?CodeBase + 64*1024 + 124*1024 <= i && i < 128*1024*1024)); ensures PciUninitialized(io); ensures logical_addressing_inv(init, ptMem, core_state); ensures public(io._inCtr); ensures public(io._outCtr); //procedure SetupIoTables(); // requires word(?iomLo) && word(?iomHi) && word(?dmaHi); // requires ecx == ?iomLo; // requires ?dmaLo == ?iomHi; // requires Aligned(?dmaLo); // requires !$IomFrozen; // requires MemInv($Mem_Vars); // requires SMemRequireRA(132, stk, esp, RET); // modifies eax, ebx, ecx, edx, esi, edi, ebp, esp, $Mem, stk; // modifies $IomMem; // ensures IoRootTable($IomMem, eax); // ensures $IomMem[?dmaLo - 8] == ?BYTE_VECTOR_VTABLE; // ensures $IomMem[?dmaLo - 4] == ?dmaHi - ?dmaLo; // ensures MemInv($Mem_Vars); // ensures SMemEnsure(stk, old(stk), esp, old(esp)); function CleanIoMmuState(io:IOState):bool { (forall i:int::{io._iom.IoMmuState[i]} io._iom.IoMmuState[i] == 0) } //procedure StartIoMmu(); // inout mems:mems; // inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState; // requires IoRootTable(io._iom.IomMem, ebx); // requires !io._iom.IoMmuEnabled; // requires ebp == ?dmaLo && word(ebp); // requires io._iom.IomMem[?dmaLo - 8] == ?BYTE_VECTOR_VTABLE; // requires io._iom.IomMem[?dmaLo - 4] == ?dmaHi - ?dmaLo; // requires CleanIoMmuState(state); // requires MemInv($Mem_Vars); // requires SMemRequireRA(132, stk, esp, RET); // modifies eax, ebx, ecx, edx, esi, edi, ebp, esp, $Mem, stk; // modifies io._iom.IoMmuState, io._iom.IomFrozen, io._iom.IoMmuEnabled; // modifies DmaAddr; // ensures ((DmaAddr == 0 && !io._iom.IoMmuEnabled) // || (DmaAddr == ?dmaLo && io._iom.IoMmuEnabled)); // ensures MemInv($Mem_Vars); // ensures SMemEnsure(stk, old(stk), esp, old(esp)); // //// Pass in a word via esi //procedure Proc_SerialDbgWordOut(); // inout core:state_core, my_part:partition, $mem:mems; // requires MemInv(me,init,$State,core,ptOwner__id,($State._mem),$part,my_part,$mem__id,$sepVars__id,$mem,$sepVars); // requires SMemRequireRA(0, mems__stk($mem), (core._regs)[ESP], RET); // //requires logical_addressing_inv(me, init, $State, $part, ptOwner__id, core); // requires $serialState.Mode.DLAB == false; // modifies $State, $serialState.Out, $Eip, $Efl, eax, ebx, ecx, edx; // modifies $part; // ensures (core._regs)[ESP] == old((core._regs)[ESP])+4; // ensures $part.vars[me] == old($part).vars[me]; // ensures logical_addressing_inv(me, init, $State, $part, ptOwner__id, core); // ensures $serialState.Mode.DLAB == false; // ensures MemInv(me,init,$State,core,ptOwner__id,($State._mem),$part,my_part,$mem__id,$sepVars__id,$mem,$sepVars); // ensures SMemEnsure(mems__stk($mem), old(mems__stk($mem)), (core._regs)[ESP], old((core._regs)[ESP])); // //procedure Proc_SerialDbgNewlineOut(); // inout core:state_core, my_part:partition, $mem:mems; // requires MemInv(me,init,$State,core,ptOwner__id,($State._mem),$part,my_part,$mem__id,$sepVars__id,$mem,$sepVars); // requires SMemRequireRA(0, mems__stk($mem), (core._regs)[ESP], RET); // //requires logical_addressing_inv(me, init, $State, $part, ptOwner__id, core); // requires $serialState.Mode.DLAB == false; // modifies $State, $serialState.Out, $Eip, $Efl, eax, ecx, edx; // modifies $part; // ensures (core._regs)[ESP] == old((core._regs)[ESP])+4; // ensures $part.vars[me] == old($part).vars[me]; // ensures logical_addressing_inv(me, init, $State, $part, ptOwner__id, core); // ensures $serialState.Mode.DLAB == false; // ensures MemInv(me,init,$State,core,ptOwner__id,($State._mem),$part,my_part,$mem__id,$sepVars__id,$mem,$sepVars); // ensures SMemEnsure(mems__stk($mem), old(mems__stk($mem)), (core._regs)[ESP], old((core._regs)[ESP])); // //// Dafny interface //const stack_size__DafnyCC__Proc_serialPortIn:int := 0; //procedure Proc_serialPortIn() returns ($ghost_out:int); // inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems; // requires MemInv(me,init,state,core_state,(mem.map),mems); // requires SMemRequireRA(stack_size__DafnyCC__Proc_serialPortIn, mems__stk(mems), esp, RET); // requires $serialState.Mode.DLAB == false; // modifies state, efl, $serialState.In, mems; // ensures esp == old(esp)+4; // ensures $serialState.In.Events[$serialState.In.Done] == and ($ghost_out, 255); // ensures $serialState.In.Done == old($serialState).In.Done + 1; // ensures MemInv(me,init,state,core_state,(mem.map),mems); // ensures SMemEnsure(mems__stk(mems), old(mems__stk(mems)), esp, old(esp)); // ensures eax == $ghost_out; // //// Dafny interface //const stack_size__DafnyCC__Proc_serialPortOut:int := 0; //procedure Proc_serialPortOut($ghost_in:int); // inout core:state_core, my_part:partition, $mem:mems; // requires MemInv(me,init,$State,core,ptOwner__id,($State._mem),$part,my_part,$mem__id,$sepVars__id,$mem,$sepVars); // requires SMemRequireRA(stack_size__DafnyCC__Proc_serialPortOut, mems__stk($mem), (core._regs)[ESP], RET); // requires $serialState.Mode.DLAB == false; // modifies $State, $part, core, my_part, $mem, $serialState.Out; // requires $ghost_in == core._regs[ECX]; // ensures (core._regs)[ESP] == old((core._regs)[ESP])+4; // ensures $serialState.Out.Events[$serialState.Out.Done] == and ($ghost_in, 255); // ensures $serialState.Out.Done == old($serialState).Out.Done + 1; // ensures MemInv(me,init,$State,core,ptOwner__id,($State._mem),$part,my_part,$mem__id,$sepVars__id,$mem,$sepVars); // ensures SMemEnsure(mems__stk($mem), old(mems__stk($mem)), (core._regs)[ESP], old((core._regs)[ESP])); // // //function ONE_ONE_MAP (M:[int]int) : bool //{ // (forall x:int, y:int :: (word(x) && word(y)) ==> M[x] == M[y] ==> x == y) //} // //const stack_size__DafnyCC__Proc_Hash:int := 0; // //procedure Proc_Hash(pwd:int, salt:int, key:int) returns (r:int); // inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems; // requires MemInv(me,init,state,core_state,(mem.map),mems); // requires SMemRequireRA(stack_size__DafnyCC__Proc_sample, mems__stk(mems), esp, RET); // requires ecx == pwd; // requires edx == salt; // requires ebx == key; // modifies state, efl, mems, $global_sample_index, $ghost_Hashed; // ensures RdmOracle(Triple(pwd, salt, key), r, old($ghost_Hashed), $ghost_Hashed, old($global_sample_index), $randomSource); // ensures $global_sample_index == old($global_sample_index)+1; // ensures esp == old(esp)+4; // ensures MemInv(me,init,state,core_state,(mem.map),mems); // ensures SMemEnsure(mems__stk(mems), old(mems__stk(mems)), esp, old(esp)); // ensures eax == r; // //procedure proc_SampleLemma(p:int, M:[int]int); // ensures (forall x:int :: M[x] == xor(x,p)); // //procedure proc_SampleLemmaID(M:[int]int); // ensures (forall x:int :: M[x] == x); // //function RdmOracle (tri:Tri, ret:int, MOld:Map, M:Map, index:int, randomSource:[int]int) : bool //{ // (MOld.Domain[tri] == true ==> M == MOld && M.Range[tri] == ret) // && (MOld.Domain[tri] == false ==> randomSource[index] == ret && M.Range == MOld.Range[tri := ret] && M.Domain == MOld.Domain[tri := true]) //} // // //const stack_size__DafnyCC__Proc_sample:int := 0; // //procedure Proc_sample(M:[int]int) returns ($ghost_out:int); // inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems; // requires MemInv(me,init,state,core_state,(mem.map),mems); // requires SMemRequireRA(stack_size__DafnyCC__Proc_sample, mems__stk(mems), esp, RET); // requires OneOneMap(M); // modifies state, efl, mems, $global_sample_index; // ensures esp == old(esp)+4; // ensures MemInv(me,init,state,core_state,(mem.map),mems); // ensures SMemEnsure(mems__stk(mems), old(mems__stk(mems)), esp, old(esp)); // //ensures (exists eax:int :: // // $State == InsUpdate1(me, s, OReg(EAX), eax, s._cores[me]._efl) // // && SampleCall ($randomSource, old($global_sample_index), $global_sample_index, and(eax, 255))); // ensures $randomSource[old($global_sample_index)] == $ghost_out; // ensures old($global_sample_index) + 1 == $global_sample_index; // ensures eax == $ghost_out; function max(x:int, y:int):int { if (x<=y) then y else x } } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Devices/IoMain.imp.beat ================================================ //-private-import BaseSpec; //-private-import MemorySpec; //-private-import IoTypesSpec; //-private-import MachineStateSpec; //-private-import AssemblySpec; //-private-import InterruptsSpec; //-private-import IoSpec; //- //- //- //- //- //-private-import Core; //-private-import LogicalAddressing; //-private-import Overflow; //-private-import Util; //-private-import Stacks; //-private-import Partition; //-private-import Instructions; //-private-import Separation; //-private-import IntLemmasBase; //-private-import IntLemmasGc; //-private-import SimpleGcMemory; //-private-import SimpleCommon; //-private-import SimpleCollector; //-private-import IntLemmasDevices; //-private-import PCI; //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- //- module implementation IoMain { implementation espAligned() { assert TV(esp) && TO(0-1) && TO(0-2) && TO(0-3) && TO(0-4) && TO(0-5) && TO(0-6) && TO(0-7) && TO(0-8) && TO(0-9) && TO(0-10) && TO(0-11) && TO(0-12) && TO(0-13) && TO(0-14) && TO(0-15) && TO(0-16); } implementation espAlignedInline() { assert TV(esp) && TO(1) && TO(2) && TO(3) && TO(4) && TO(5) && TO(6) && TO(7) && TO(8) && TO(9) && TO(10) && TO(11) && TO(12) && TO(13) && TO(14) && TO(15) && TO(16); } //implementation startTimer() //{ // eax := 48; // call PitModeOut8(ecx); // eax := ecx; // call PitFreqOut8(); // call eax := Shr(eax, 8); // call PitFreqOut8(); //} implementation initIoInv() { call reveal_MemInvDetails(); ecx := ecx; var i:int := 0; while(ecx < edx) invariant 0 <= i && i <= (?pciHi - ?pciLo) div 16; invariant ecx == ?pciLo + 16*i; invariant ?pciLo <= ecx && ecx <= ?pciHi; invariant (forall addr:int, j:int::{mems.pci[addr],TV(j)} TV(j) && 0 <= j && j < i && addr == ?pciLo + 16*j && addr <= ?pciHi - 16 ==> mems.pci[addr] == 0xffffffff); invariant (forall j:int :: {TV(j)} TV(j) && 0 <= j && j < i ==> mems.pci[?pciLo + 16*j] == 0xffffffff); invariant (forall i:int :: {io._pci.PciConfigState[i]} 0 <= i && i < 65536 ==> (io._pci.PciConfigState[i] == 0)); //invariant MemInv($Mem_Vars); invariant MemInv($Mem_Vars) && commonVarsInv($commonVars, statics); { assert Aligned(?pciLo) && TV(?pciLo) && TO(4*i); call Store(inout mems.pci, ecx, 0xffffffff); assert mems.pci[ecx] == 0xffffffff; assert mems.pci[?pciLo + 16*i] == 0xffffffff; ecx := ecx + 16; i := i + 1; } call reveal_IoInv(); } implementation checkIoFresh() { call reveal_MemInvDetails(); var i:int := 0; while(ecx < edx) invariant 0 <= i && i <= (?pciHi - ?pciLo) div 16; invariant ecx == ?pciLo + 16*i; invariant ?pciLo <= ecx && ecx <= ?pciHi; invariant (forall addr:int, j:int::{mems.pci[addr],TV(j)} TV(j) ==> (0 <= j && j < i && addr == ?pciLo + 16*j && addr <= ?pciHi - 16 ==> mems.pci[addr] == 0xffffffff)); // invariant (forall j:int :: {io._pci.PciConfigState[j]} // 0 <= j && j < i ==> (io._pci.PciConfigState[j] == 0)); invariant MemInv($Mem_Vars) && commonVarsInv($commonVars, statics); invariant IoInv($IoVars, mems.pci); { assert Aligned(?pciLo) && TV(?pciLo) && TO(4*i); call eax := Load(mems.pci, ecx); if (eax != 0xffffffff) { eax := 0x555500b1; call debugBreak(); } call reveal_IoInv(); ecx := ecx + 16; i := i + 1; } call reveal_IoInv(); } //procedure setupIoTablesHelper1(tableBase@esi, dmaAlignedLo@ebx) // requires logical_addressing_inv(init, ptMem, core_state); // requires word(?iomLo) && word(?iomHi) && word(?dmaHi); // requires ?dmaLo == ?iomHi; // requires and(dmaAlignedLo, 4095) == 0; // requires ?dmaLo <= dmaAlignedLo && dmaAlignedLo + 0x200000 + 4096 <= ?dmaHi; // requires Aligned(tableBase); // requires ?iomLo <= tableBase && tableBase + 32768 <= ?iomHi; // requires and(tableBase + 0x0000, 4095) == 0; // requires and(tableBase + 0x1000, 4095) == 0; // requires and(tableBase + 0x2000, 4095) == 0; // requires and(tableBase + 0x3000, 4095) == 0; // requires !$IomFrozen; // modifies eax, ebx, ecx, edx, edi, ebp; // modifies $IomMem; // ensures IoPageTable($IomMem, tableBase); // ensures (forall i:int::{TV(i)} TV(i) && 0 <= i && i < 512 ==> // ($IomMem[tableBase + 0x1000 + 8 * i] == 0 || $IomMem[tableBase + 0x1000 + 8 * i] == tableBase + 3) // && $IomMem[tableBase + 0x1000 + 8 * i + 4] == 0); // ensures (forall i:int::{TV(i)} TV(i) && 0 <= i && i < 512 ==> // $IomMem[tableBase + 0x2000 + 8 * i] == 0 // && $IomMem[tableBase + 0x2000 + 8 * i + 4] == 0); // ensures (forall i:int::{TV(i)} TV(i) && 0 <= i && i < 512 ==> // $IomMem[tableBase + 0x3000 + 8 * i] == 0 // && $IomMem[tableBase + 0x3000 + 8 * i + 4] == 0); //{ // var ptr@edi := tableBase; // var end@ebp := ptr; end := end + 4096; // var pagePtr@edx := dmaAlignedLo; // var $entry:int := 0; // while (ptr < end) // invariant Aligned(ptr) && TV(ptr) && TO(1) && TO(2); // invariant dmaAlignedLo == old(dmaAlignedLo); // invariant end == old(tableBase) + 4096; // invariant tableBase == old(tableBase); // invariant pagePtr == dmaAlignedLo + $entry * 4096; // invariant and(pagePtr, 4095) == 0; // invariant ptr == tableBase + 8 * $entry; // invariant 0 <= $entry && $entry <= 512; // invariant (forall i:int::{TV(i)} TV(i) && 0 <= i && i < $entry ==> // IoPageTableEntry($IomMem[tableBase + 8 * i], $IomMem[tableBase + 8 * i + 4])); // invariant (forall i:int::{TV(i)} TV(i) && 0 <= i && i < $entry ==> // $IomMem[tableBase + 0x1000 + 8 * i] == 0 && $IomMem[tableBase + 0x1000 + 8 * i + 4] == 0); // invariant (forall i:int::{TV(i)} TV(i) && 0 <= i && i < $entry ==> // $IomMem[tableBase + 0x2000 + 8 * i] == 0 && $IomMem[tableBase + 0x2000 + 8 * i + 4] == 0); // invariant (forall i:int::{TV(i)} TV(i) && 0 <= i && i < $entry ==> // $IomMem[tableBase + 0x3000 + 8 * i] == 0 && $IomMem[tableBase + 0x3000 + 8 * i + 4] == 0); // invariant logical_addressing_inv(init, ptMem, core_state); // { // assert TO(1024) && TO(1025) && TO(2048) && TO(2049) && TO(3072) && TO(3073); // ecx := pagePtr; ecx := ecx + 3; // assert (memAddr(ptr)); // assert(Aligned(ptr)); // //assert (LogicalDstOk($State, OMem(MReg(EDI,0)))); // call IomStore(ptr + 0, ecx); // call IomStore(ptr + 4, 0); // call IomStore(ptr + 0x1000, 0); // call IomStore(ptr + 0x1004, 0); // call IomStore(ptr + 0x2000, 0); // call IomStore(ptr + 0x2004, 0); // call IomStore(ptr + 0x3000, 0); // call IomStore(ptr + 0x3004, 0); // $entry := $entry + 1; // ptr := ptr + 8; // call __add4kAligned(pagePtr); // pagePtr := pagePtr + 4096; // } // // ecx := dmaAlignedLo; // call ecx := Shr(ecx, 21); // if (ecx >= 512) // { // eax := 0x5555006e; // dma zone is beyond first 1GB // call debugBreak(); // } // assert TV(ecx) && TO(2 * ecx + 1024); // edx := tableBase; edx := edx + 3; // call IomStore(tableBase + 8 * ecx + 0x1000, edx); // //} //procedure setupIoTablesHelper2(tableBase@esi) // requires logical_addressing_inv(init, ptMem, core_state); // requires word(?iomLo) && word(?iomHi); // requires Aligned(?dmaLo); // requires ?dmaLo == ?iomHi; // requires ecx == ?dmaLo; // requires IoPageTable($IomMem, tableBase); // requires (forall i:int::{TV(i)} TV(i) && 0 <= i && i < 512 ==> // ($IomMem[tableBase + 0x1000 + 8 * i] == 0 || $IomMem[tableBase + 0x1000 + 8 * i] == tableBase + 3) // && $IomMem[tableBase + 0x1000 + 8 * i + 4] == 0); // requires (forall i:int::{TV(i)} TV(i) && 0 <= i && i < 512 ==> // $IomMem[tableBase + 0x2000 + 8 * i] == 0 // && $IomMem[tableBase + 0x2000 + 8 * i + 4] == 0); // requires (forall i:int::{TV(i)} TV(i) && 0 <= i && i < 512 ==> // $IomMem[tableBase + 0x3000 + 8 * i] == 0 // && $IomMem[tableBase + 0x3000 + 8 * i + 4] == 0); // requires Aligned(tableBase); // requires Aligned(tableBase + 0x4000); // requires ?iomLo <= tableBase && tableBase + 32768 <= ?iomHi; // requires and(tableBase + 0x1000, 4095) == 0; // requires and(tableBase + 0x2000, 4095) == 0; // requires and(tableBase + 0x3000, 4095) == 0; // requires and(tableBase + 0x4000, 4095) == 0; // requires and(tableBase + 0x5000, 4095) == 0; // requires !$IomFrozen; // modifies eax, ebx, ecx, edx, edi, ebp; // modifies $IomMem; // ensures IoPageTable($IomMem, tableBase); // ensures $IomMem[tableBase + 0x2000] == tableBase + 0x1000 + 3; // ensures $IomMem[tableBase + 0x2004] == 0; // ensures $IomMem[tableBase + 0x3000] == tableBase + 0x2000 + 3; // ensures $IomMem[tableBase + 0x3004] == 0; // ensures (forall i:int::{TV(i)} TV(i) && 0 <= i && i < 512 ==> // ($IomMem[tableBase + 0x1000 + 8 * i] == 0 || $IomMem[tableBase + 0x1000 + 8 * i] == tableBase + 3) // && $IomMem[tableBase + 0x1000 + 8 * i + 4] == 0); // ensures (forall i:int::{TV(i)} TV(i) && 1 <= i && i < 512 ==> // $IomMem[tableBase + 0x2000 + 8 * i] == 0 // && $IomMem[tableBase + 0x2000 + 8 * i + 4] == 0); // ensures (forall i:int::{TV(i)} TV(i) && 1 <= i && i < 512 ==> // $IomMem[tableBase + 0x3000 + 8 * i] == 0 // && $IomMem[tableBase + 0x3000 + 8 * i + 4] == 0); // ensures (forall i:int::{TV(i)} TV(i) && 0 <= i && i < 256 ==> // $IomMem[tableBase + 0x4000 + 16 * i + 0] == tableBase + 0x3000 + 3 // && $IomMem[tableBase + 0x4000 + 16 * i + 4] == 0 // && $IomMem[tableBase + 0x4000 + 16 * i + 8] == 258 // && $IomMem[tableBase + 0x4000 + 16 * i + 12] == 0); // ensures (forall i:int::{TV(i)} TV(i) && 0 <= i && i < 256 ==> // $IomMem[tableBase + 0x5000 + 16 * i + 0] == tableBase + 0x4000 + 1 // && $IomMem[tableBase + 0x5000 + 16 * i + 4] == 0 // && $IomMem[tableBase + 0x5000 + 16 * i + 8] == 0 // && $IomMem[tableBase + 0x5000 + 16 * i + 12] == 0); // ensures $IomMem[?dmaLo - 8] == ?BYTE_VECTOR_VTABLE; // ensures $IomMem[?dmaLo - 4] == ?dmaHi - ?dmaLo; //{ // var dmaLo@ebx := ecx; // // var $entry:int := 0; // var ptr@edi := tableBase; ptr := ptr + 0x4000; // var end@ebp := ptr; end := end + 4096; // ecx := tableBase; ecx := ecx + 0x3003; // edx := tableBase; edx := edx + 0x4001; // while (ptr < end) // invariant Aligned(ptr) && TV(ptr) && TO(1) && TO(2) && TO(3) && TO(4); // invariant tableBase == old(tableBase); // invariant dmaLo == ?dmaLo; // invariant ecx == tableBase + 0x3003; // invariant edx == tableBase + 0x4001; // invariant ptr == tableBase + 0x4000 + 16 * $entry; // invariant end == tableBase + 0x4000 + 4096; // invariant 0 <= $entry && $entry <= 256; // invariant IoPageTable($IomMem, tableBase); // invariant (forall i:int::{TV(i)} TV(i) && 0 <= i && i < 512 ==> // ($IomMem[tableBase + 0x1000 + 8 * i] == 0 || $IomMem[tableBase + 4096 + 8 * i] == tableBase + 3) // && $IomMem[tableBase + 0x1000 + 8 * i + 4] == 0); // invariant (forall i:int::{TV(i)} TV(i) && 0 <= i && i < 512 ==> // $IomMem[tableBase + 0x2000 + 8 * i] == 0 // && $IomMem[tableBase + 0x2000 + 8 * i + 4] == 0); // invariant (forall i:int::{TV(i)} TV(i) && 0 <= i && i < 512 ==> // $IomMem[tableBase + 0x3000 + 8 * i] == 0 // && $IomMem[tableBase + 0x3000 + 8 * i + 4] == 0); // invariant (forall i:int::{TV(i)} TV(i) && 0 <= i && i < $entry ==> // $IomMem[tableBase + 0x4000 + 16 * i + 0] == tableBase + 0x3000 + 3 // && $IomMem[tableBase + 0x4000 + 16 * i + 4] == 0 // && $IomMem[tableBase + 0x4000 + 16 * i + 8] == 258 // && $IomMem[tableBase + 0x4000 + 16 * i + 12] == 0); // invariant (forall i:int::{TV(i)} TV(i) && 0 <= i && i < $entry ==> // $IomMem[tableBase + 0x5000 + 16 * i + 0] == tableBase + 0x4000 + 1 // && $IomMem[tableBase + 0x5000 + 16 * i + 4] == 0 // && $IomMem[tableBase + 0x5000 + 16 * i + 8] == 0 // && $IomMem[tableBase + 0x5000 + 16 * i + 12] == 0); // { // call IomStore(ptr + 0, ecx); // call IomStore(ptr + 4, 0); // call IomStore(ptr + 8, 258); // call IomStore(ptr + 0xc, 0); // assert TO(1024) && TO(1025) && TO(1026) && TO(1027); // call IomStore(ptr + 0x1000, edx); // call IomStore(ptr + 0x1004, 0); // call IomStore(ptr + 0x1008, 0); // call IomStore(ptr + 0x100c, 0); // $entry := $entry + 1; // ptr := ptr + 16; // } // // assert TV(tableBase); // assert TV(0) && TO(2048) && TO(3072); // edx := tableBase; edx := edx + 0x1003; // call IomStore(tableBase + 0x2000, edx); // edx := tableBase; edx := edx + 0x2003; // call IomStore(tableBase + 0x3000, edx); // // edx := dmaLo; // call edx := AddChecked(edx, 0x1200000); // var dmaHi@ebp := edx; // // assert TV(?dmaLo) && TO(0 - 1) && TO(0 - 2); // ecx := dmaLo; ecx := ecx - 8; // edx := ?BYTE_VECTOR_VTABLE; // call IomStore(ecx, edx); // edx := dmaHi; edx := edx - dmaLo; // call IomStore(ecx + 4, edx); //} // //procedure setupIoTablesHelper3(tableBase@esi) // requires and(tableBase + 0x5000, 4095) == 0; // requires IoContextTable($IomMem, tableBase + 0x4000); // requires (forall i:int::{TV(i)} TV(i) && 0 <= i && i < 256 ==> // $IomMem[tableBase + 0x5000 + 16 * i + 0] == tableBase + 0x4000 + 1 // && $IomMem[tableBase + 0x5000 + 16 * i + 4] == 0 // && $IomMem[tableBase + 0x5000 + 16 * i + 8] == 0 // && $IomMem[tableBase + 0x5000 + 16 * i + 12] == 0); // ensures IoRootTable($IomMem, tableBase + 0x5000); //{ //} // //implementation SetupIoTables() //{ // call espAligned(); // call esp := Sub(esp, 4); // eax := ecx; eax := eax + 65536; // var dmaLo @ stk[esp + 0] := eax; // // ecx := ecx + 4096; // var tableBase@esi := ecx; tableBase := tableBase + 4096; // call __is4kAligned(ecx); // call __add4kAligned(ecx - and(ecx, 4095) + 0x0000); // call __add4kAligned(ecx - and(ecx, 4095) + 0x1000); // call __add4kAligned(ecx - and(ecx, 4095) + 0x2000); // call __add4kAligned(ecx - and(ecx, 4095) + 0x3000); // call __add4kAligned(ecx - and(ecx, 4095) + 0x4000); // call __add4kAligned(ecx - and(ecx, 4095) + 0x5000); // call ecx := And(ecx, 4095); // tableBase := tableBase - ecx; // assert TV(tableBase); // // ecx := dmaLo; ecx := ecx + 0x200000; // var dmaAlignedLo@ebx := ecx; dmaAlignedLo := dmaAlignedLo + 0x200000; // call __is2m4kAligned(ecx); // call ecx := And(ecx, 0x1fffff); // dmaAlignedLo := dmaAlignedLo - ecx; // // call setupIoTablesHelper1(); // // ecx := dmaLo; // call setupIoTablesHelper2(); // // call setupIoTablesHelper3(); // // eax := tableBase; eax := eax + 0x5000; // call esp := Add(esp, 4); // Return; //} //procedure setIoMmuRegs($entry:int, _regs@esi) // inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState; // inout mems:mems; // requires MemInv($Mem_Vars); // requires _regs == ?DrhdRegs[$entry]; // requires IoRootTable(io._iom.IomMem, ebx); // requires io._iom.IoMmuState[$entry] == 0; // modifies eax, ecx, edx, esi, ebp; // modifies io._iom.IoMmuState; // modifies io._iom.IoFrozen; // modifies io._iom.IomFrozen; // modifies mem; // ensures io._iom.IoMmuState[$entry] == 4; // ensures (forall i:int::{io._iom.IoMmuState[i]} i != $entry ==> io._iom.IoMmuState[i] == old($State)._io._iom.IoMmuState[i]); // ensures MemInv($Mem_Vars); //{ // call IomRegStore($entry, _regs + 32, ebx); // call IomRegStore($entry, _regs + 36, 0); // // eax := 1; // call eax := Shl(eax, 30); // call IomRegStore($entry, _regs + 24, eax); // // eax := 1; // call eax := Shl(eax, 31); // call IomRegStore($entry, _regs + 24, eax); // //// edx := 0; //// call eax := IomRegLoad($entry, _regs + 28); //// call writeHex(); //} // //procedure ReadDmar(ptr@edi) // inout mems:mems; // inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState; // requires ?DmarExists; // requires ptr == ?DmarPtr; // requires IoRootTable(io._iom.IomMem, ebx); // requires io._iom.IomMem[?dmaLo - 8] == ?BYTE_VECTOR_VTABLE; // requires io._iom.IomMem[?dmaLo - 4] == ?dmaHi - ?dmaLo; // requires CleanIoMmuState($State); // requires MemInv($Mem_Vars); // requires SMemRequireRA(116, stk, esp, RET); // modifies eax, ebx, ecx, edx, esi, edi, ebp, esp, $Mem, stk; // modifies io._iom.IoMmuState, io._iom.IomFrozen, io._iom.IoMmuEnabled; // ensures io._iom.IoMmuEnabled; // ensures MemInv($Mem_Vars); // ensures SMemEnsure(stk, old(stk), esp, old(esp)); //{ // call espAligned(); // call esp := Sub(esp, 8); // assert(((state._io)._vga)==((old($State)._io)._vga)); // call ecx := RoLoad32(ptr + 4); // assert(((state._io)._vga)==((old($State)._io)._vga)); // eax := ptr; eax := eax + ecx; // var end @ stk[esp + 0] := eax; // // var $entry:int := 0; // ptr := ptr + 48; // while (ptr < end) // invariant TV($entry); // invariant IoRootTable(io._iom.IomMem, ebx); // invariant ?DmarPtr + 48 <= ptr && ptr <= ?DmarPtr + ?DmarLen; // invariant MaybeDrhd(ptr, $entry); // invariant (forall i:int::{io._iom.IoMmuState[i]} i >= $entry ==> io._iom.IoMmuState[i] == 0); // invariant (forall i:int::{io._iom.IoMmuState[i]} 0 <= i && i < $entry ==> io._iom.IoMmuState[i] == 4); // invariant MemInv($Mem_Vars); // invariant SMemInv(stk, old(stk), esp + 8, old(esp)); // { // var typ@edx; // var len@ecx; // call typ := RoLoadU16(ptr + 0); // call len := RoLoadU16(ptr + 2); // if (typ != 0) // { // call drhdEnd(ptr, $entry); // goto done; // } // call drhdExists(ptr, $entry); // call eax := RoLoad32(ptr + 12); // if (eax != 0) // { // eax := 0x55550066; // call debugBreak(); // } // call esi := RoLoad32(ptr + 8); // // var saveEcx @ stk[esp + 4] := ecx; // assert(MemInv($Mem_Vars)); // call setIoMmuRegs($entry); // ecx := saveEcx; // // $entry := $entry + 1; // ptr := ptr + len; // } // call drhdEnd(ptr, $entry); // // done: // // TODO // infloop: // invariant logical_addressing_inv(init, ptMem, core_state); // goto infloop; // call IomEnable(); // call esp := Add(esp, 8); // Return; //} // //procedure ReadRsdt(ptr@esi) // inout mems:mems; // inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState; // requires ?RsdpExists; // requires !io._iom.IoMmuEnabled; // requires ptr == ?RsdtPtr; // requires ebp == ?dmaLo && word(ebp); // requires IoRootTable(io._iom.IomMem, ebx); // requires io._iom.IomMem[?dmaLo - 8] == ?BYTE_VECTOR_VTABLE; // requires io._iom.IomMem[?dmaLo - 4] == ?dmaHi - ?dmaLo; // requires CleanIoMmuState($State); // requires MemInv($Mem_Vars); // requires SMemRequireRA(124, stk, esp, RET); // modifies eax, ebx, ecx, edx, esi, edi, ebp, esp, $Mem, stk; // modifies io._iom.IoMmuState, io._iom.IomFrozen, io._iom.IoMmuEnabled; // modifies DmaAddr; // ensures ((DmaAddr == 0 && !io._iom.IoMmuEnabled) // || (DmaAddr == ?dmaLo && io._iom.IoMmuEnabled)); // ensures MemInv($Mem_Vars); // ensures SMemEnsure(stk, old(stk), esp, old(esp)); //{ // call espAligned(); // call esp := Sub(esp, 4); // var dmaLo @ stk[esp + 0] := ebp; // // call ecx := RoLoad32(ptr + 4); // var end@ebp := ptr; end := end + ecx; // // var $entry:int := 0; // ptr := ptr + 36; // while (ptr < end) // invariant IoRootTable(io._iom.IomMem, ebx); // invariant end == ?RsdtPtr + ro32(?RsdtPtr + 4); // invariant TV($entry); // invariant ptr == ?RsdtPtr + 36 + 4 * $entry; // invariant 0 <= $entry && $entry <= ?RsdtCount; // invariant (forall j:int::{TV(j)} TV(j) && 0 <= j && j < $entry // ==> !MatchesDmar(ro32(?RsdtPtr + 36 + 4 * j))); // invariant MemInv($Mem_Vars); // invariant SMemInv(stk, old(stk), esp + 4, old(esp)); // invariant CleanIoMmuState($State); // invariant !io._iom.IoMmuEnabled; // { // call ecx := RoLoad32(ptr + 0); // call edx := RoLoad32(ecx + 0); // if (edx == 0x52414d44) // { // // Found a DMAR entry. Good. // var $dmarEntry:int := $entry; // var dmarPtr@edi := ecx; // var $dmarPtr:int := dmarPtr; // assert MatchesDmar(dmarPtr); // $entry := $entry + 1; // ptr := ptr + 4; // while (ptr < end) // invariant IoRootTable(io._iom.IomMem, ebx); // invariant end == ?RsdtPtr + ro32(?RsdtPtr + 4); // invariant dmarPtr == $dmarPtr; // invariant TV($entry); // invariant ptr == ?RsdtPtr + 36 + 4 * $entry; // invariant 0 <= $entry && $entry <= ?RsdtCount; // invariant (forall j:int::{TV(j)} TV(j) && 0 <= j && j < $entry && j != $dmarEntry // ==> !MatchesDmar(ro32(?RsdtPtr + 36 + 4 * j))); // invariant MemInv($Mem_Vars); // invariant SMemInv(stk, old(stk), esp + 4, old(esp)); // invariant CleanIoMmuState($State); // invariant !io._iom.IoMmuEnabled; // { // call ecx := RoLoad32(ptr + 0); // call edx := RoLoad32(ecx + 0); // if (edx == 0x52414d44) // { // // Found another DMAR entry. Bad. // DmaAddr := 0; // assert(!io._iom.IoMmuEnabled); // goto done; // } // $entry := $entry + 1; // ptr := ptr + 4; // } // call dmarExists(dmarPtr, $dmarEntry); // call ReadDmar(); // eax := dmaLo; // DmaAddr := eax; // goto done; // } // $entry := $entry + 1; // ptr := ptr + 4; // } // DmaAddr := 0; // // done: // call esp := Add(esp, 4); // Return; //} // //implementation StartIoMmu() //{ // call espAligned(); // call esp := Sub(esp, 4); // var dmaLo @ stk[esp + 0] := ebp; // var $entry:int := 0; // var ptr@esi := ?RoBiosLo; // while (ptr < 0xffff0) // ?RoBiosHi - 16 // invariant IoRootTable(io._iom.IomMem, ebx); // invariant TV($entry); // invariant ptr == ?RoBiosLo + 16 * $entry; // invariant ?RoBiosLo <= ptr && ptr <= ?RoBiosHi - 16; // invariant (forall j:int::{TV(j)} TV(j) && j < $entry && inBiosRo(?RoBiosLo + 16 * j) // ==> !MatchesRsdp(?RoBiosLo + 16 * j)); // invariant MemInv($Mem_Vars); // invariant SMemInv(stk, old(stk), esp + 4, old(esp)); // invariant CleanIoMmuState($State); // invariant !io._iom.IoMmuEnabled; // { // call ecx := RoLoad32(ptr + 0); // call edx := RoLoad32(ptr + 4); // // if (ecx == 0x20445352) // { // if (edx == 0x20525450) // { // var ptr2@edi := ptr; // var sum@ebp := 0; // var ptr_20@edx := ptr; ptr_20 := ptr_20 + 20; // while (ptr2 < ptr_20) // invariant IoRootTable(io._iom.IomMem, ebx); // invariant TV(ptr) && TV(ptr2); // invariant ptr == ?RoBiosLo + 16 * $entry; // invariant ptr_20 == ptr + 20; // invariant ptr <= ptr2 && ptr2 <= ptr + 20; // invariant sum == ByteSum(ptr, ptr2); // invariant MemInv($Mem_Vars); // invariant SMemInv(stk, old(stk), esp + 4, old(esp)); // invariant CleanIoMmuState($State); // invariant !io._iom.IoMmuEnabled; // { // call eax := RoLoadU8(ptr2); // call sum := AddChecked(sum, eax); // ptr2 := ptr2 + 1; // } // // call sum := And(sum, 0xff); // if (sum == 0) // { // call rsdpExists(ptr, $entry); // call ptr := RoLoad32(ptr + 16); // ebp := dmaLo; // call ReadRsdt(); // goto done; // } // } // } // // $entry := $entry + 1; // ptr := ptr + 16; // } // DmaAddr := 0; // // done: // call esp := Add(esp, 4); // Return; //} // // //implementation Proc_SerialDbgWordOut() //{ // assert TV((core._regs)[ESP]); // call core := logical_Sub($State, core, OReg(ESP), OConst(0)); // call serialDbgWordOut(); // call core := logical_Add($State, core, OReg(ESP), OConst(0)); // Return; //} // //implementation Proc_SerialDbgNewlineOut() //{ // assert TV((core._regs)[ESP]); //// call core := logical_Sub($State, core, OReg(ESP), OConst(0)); // call serialDbgNewlineOut(); //// call core := logical_Add($State, core, OReg(ESP), OConst(0)); // Return; //} // //implementation Proc_serialPortOut($ghost_in:int) //{ // assert TV(esp); //// call core := logical_Sub($State, core, OReg(ESP), OConst(0)); // call serialDbgDataOut8( ); //// call core := logical_Add($State, core, OReg(ESP), OConst(0)); // Return; //} // //implementation Proc_serialPortIn() returns ($ghost_out:int) //{ // assert TV(esp); //// call core := logical_Sub($State, core, OReg(ESP), OConst(0)); // call serialDbgDataIn8(); // $ghost_out := eax; //// call core := logical_Add($State, core, OReg(ESP), OConst(0)); // Return; //} // //implementation Proc_sample(M:[int]int) returns ($ghost_out:int) //{ // assert TV(esp); //// call core := logical_Sub($State, core, OReg(ESP), OConst(0)); // call SampleIn32(M); // $ghost_out := eax; //// call core := logical_Add($State, core, OReg(ESP), OConst(0)); // Return; //} procedure prepDEVmemOnes(inout linear dev_mem:mem) inout my r:regs, my core_state:core_state; requires !init; requires ?CodeBase == 0x300000; requires (forall i:int :: {dev_mem.dom[i]} dev_mem.dom[i] <==> (?DEVLo <= i && i < ?DEVHi)); requires logical_addressing_inv(init, ptMem, core_state); modifies efl, eax, ebx, ecx, edx, esi, edi; ensures (forall i:int :: PhysPtrOk(dev_mem, i) && ?DEVLo + 96 <= i ==> dev_mem.map[i] == 0xFFFFFFFF); ensures (forall i:int :: {dev_mem.dom[i]} dev_mem.dom[i] <==> (?DEVLo <= i && i < ?DEVHi)); ensures (forall i:int :: i < ?DEVLo + 96 ==> dev_mem.map[i] == old(dev_mem.map[i])); ensures logical_addressing_inv(init, ptMem, core_state); { ebx := 0x30F060; call reveal_Aligned(ebx); assert Aligned(ebx); assert ?DEVLo == 0x300000+60*1024; var i:int := 0; while (ebx < 0x310000) invariant 0 <= i; invariant ebx == ?DEVLo + 96 + 4*i; invariant (forall j:int :: {dev_mem.dom[j]} dev_mem.dom[j] <==> (?DEVLo <= j && j < ?DEVHi)); invariant ebx < ?DEVHi ==> PhysPtrOk(dev_mem, ebx); invariant (forall j:int :: ?DEVLo + 96 <= j && j < ebx && Aligned(j) ==> dev_mem.map[j] == 0xFFFFFFFF); invariant (forall j:int :: j < ?DEVLo + 96 ==> dev_mem.map[j] == old(dev_mem.map[j])); { assert EvalPtrOk(OMem(MReg(EBX, 0))); assert PhysPtrOk(dev_mem, EvalPtr(r, OMem(MReg(EBX, 0)))); assert word(EvalPtr(r, OMem(MReg(EBX, 0)))); call Store(inout dev_mem, ebx, 0xFFFFFFFF); call __notAligned(ebx); ebx := ebx + 4; i := i + 1; assert TV(0x30F060) && TO(i); } } procedure prepDEVmemZeroes(inout linear dev_mem:mem) inout my r:regs, my core_state:core_state; requires !init; requires ?CodeBase == 0x300000; requires (forall i:int :: {dev_mem.dom[i]} dev_mem.dom[i] <==> (?DEVLo <= i && i < ?DEVHi)); requires logical_addressing_inv(init, ptMem, core_state); modifies efl, eax, ebx, ecx, edx, esi, edi; ensures (forall i:int :: PhysPtrOk(dev_mem, i) && ?DEVLo <= i && i < ?DEVLo + 96 ==> dev_mem.map[i] == 0); ensures (forall i:int :: {dev_mem.dom[i]} dev_mem.dom[i] <==> (?DEVLo <= i && i < ?DEVHi)); ensures logical_addressing_inv(init, ptMem, core_state); { ebx := 0x30F000; call reveal_Aligned(ebx); assert Aligned(ebx); var i:int := 0; while (ebx < 0x30F060) invariant 0 <= i; invariant ebx == ?DEVLo + 4*i; invariant (forall j:int :: {dev_mem.dom[j]} dev_mem.dom[j] <==> (?DEVLo <= j && j < ?DEVHi)); invariant ebx < ?DEVLo + 96 ==> PhysPtrOk(dev_mem, ebx); invariant (forall j:int :: ?DEVLo <= j && j < ebx && Aligned(j) ==> dev_mem.map[j] == 0); { call Store(inout dev_mem, ebx, 0); call __notAligned(ebx); ebx := ebx + 4; i := i + 1; assert TV(0x30F000) && TO(i); } } procedure prepDEVmem(inout linear dev_mem:mem) inout my r:regs, my core_state:core_state; requires !init; requires ?CodeBase == 0x300000; requires (forall i:int :: {dev_mem.dom[i]} dev_mem.dom[i] <==> (?DEVLo <= i && i < ?DEVHi)); requires logical_addressing_inv(init, ptMem, core_state); modifies efl, eax, ebx, ecx, edx, esi, edi; ensures ValidDEV(dev_mem); ensures logical_addressing_inv(init, ptMem, core_state); { call prepDEVmemZeroes(inout dev_mem); call prepDEVmemOnes(inout dev_mem); } procedure pciConfigAddr($id:int, $offset:int) inout my r:regs, my core_state:core_state, linear io:IOState; requires ecx == $id; requires edx == $offset; requires IsValidPciId($id); requires IsValidPciOffset($offset); requires PciUninitialized(io); requires logical_addressing_inv(init, ptMem, core_state); requires public($id); requires public($offset); requires public(io._inCtr); requires public(io._outCtr); modifies io, efl, eax, edx; ensures io._pci.PciConfigId == $id; ensures io._pci.PciConfigOffset == $offset; ensures edx == 0xcfc; ensures PciUninitialized(io); ensures logical_addressing_inv(init, ptMem, core_state); ensures public(io._inCtr); ensures public(io._outCtr); { call reveal_IoInv(); eax := ecx; call eax := Shl(eax, 8); call eax := Or(eax, edx); edx := 0x7fffffff; call edx := AddChecked(edx, 1); call eax := Or(eax, edx); edx := 0xcf8; call PciConfigAddrOut32($id, $offset); edx := 0xcfc; call reveal_IoInv(); } procedure findDEVCapability(id:int) inout my r:regs, my core_state:core_state, linear io:IOState; requires ecx == id; requires IsValidPciId(id); requires PciUninitialized(io); requires PciDeviceAtId(id); requires logical_addressing_inv(init, ptMem, core_state); requires public(id); requires public(io._inCtr); requires public(io._outCtr); modifies io, efl, eax, ebx, ecx, edx, ebp, edi, esi; ensures esi == 1 ==> !Is_DEV_PCI_config(id); ensures esi == 2 ==> DEV_PciCapabilityAt(id, edx) && IsValidPciOffset(edx); ensures esi == 1 || esi == 2; ensures ecx == id; ensures PciUninitialized(io); ensures logical_addressing_inv(init, ptMem, core_state); ensures public(esi); ensures public(ecx); ensures public(edx); ensures public(io._inCtr); ensures public(io._outCtr); { //- Does this device support capability lists? //- Check bit 4 in the device status register (which is bit 20 in the combined device control and status registers). //- The combined device control/status registers take up 32 bits starting at 0x04 into the device configuration space. edx := 0x4; var offset:int := 0x4; call pciConfigAddr(id, offset); call /* eax := */ PciConfigDataIn32(id, offset); call reveal_IoInv(); var tmp:int := eax; ebx := 1; call ebx := Shl(ebx, 20); call eax := And(eax, ebx); assert (eax != 0) == GetBit(20, tmp); if (eax == 0) { assert !PciSupportsCapabilityList(id); esi := 1; } else { assert PciSupportsCapabilityList(id); //- Obtain the initial capabilities pointer edx := 0x34; offset := 0x34; call pciConfigAddr(id, offset); call /* eax := */ PciConfigDataIn32(id, offset); call reveal_IoInv(); assert PciConfigReadResult(id, offset, eax); var tmp:int := eax; call lemma_shl_1(); ebx := 1; call ebx := Shl(ebx, 8); call ebx := Sub(ebx, 1); call eax := And(eax, ebx); ebp := eax; //- cap ptr assert ebp == SelectLSBs(8, tmp); var cap_index:int := 0; assert PciCapabilityPtr(id, cap_index) == ebp; var done @ esi := 0; while (done == 0) invariant cap_index >= 0; invariant done == 0 ==> ebp == PciCapabilityPtr(id, cap_index); invariant (forall other_cap_index:int :: 0 <= other_cap_index && other_cap_index < cap_index ==> PciCapabilityID(id, other_cap_index) != 0x0f); invariant IsValidPciOffset(offset); invariant done == 0 ==> IsValidPciOffset(ebp); invariant done == 1 ==> !Is_DEV_PCI_config(id); invariant done == 2 ==> DEV_PciCapabilityAt(id, offset) && edx == offset && IsValidPciOffset(edx); invariant done == 0 || done == 1 || done == 2; //- Boilerplate invariant ecx == id; invariant IsValidPciId(id); invariant PciSupportsCapabilityList(id); invariant PciUninitialized(io); invariant logical_addressing_inv(init, ptMem, core_state); invariant public(done); invariant public(cap_index); invariant public(ebp); invariant public(id); invariant public(edx); invariant public(io._inCtr); invariant public(io._outCtr); { if (ebp == 0) { call cap_list_termination(id, cap_index); assert (forall other_cap_index:int :: 0 <= other_cap_index ==> PciCapabilityID(id, other_cap_index) != 0x0f); assert !Is_DEV_PCI_config(id); done := 1; } else { //- Read at the offset in the cap ptr edx := ebp; offset := ebp; call pciConfigAddr(id, offset); call /* eax := */ PciConfigDataIn32(id, offset); call reveal_IoInv(); assert PciConfigReadResult(id, offset, eax); edx := ebp; assert edx == offset; //- Check whether it's a DEV capability ID ebp := eax; ebx := 1; call ebx := Shl(ebx, 8); call ebx := Sub(ebx, 1); call ebp := And(ebp, ebx); //- Cap ID assert PciCapabilityID(id, cap_index) == ebp; if (ebp == 0x0f) { //- Found the DEV assert TV(cap_index); assert DEV_PciCapabilityAt(id, offset); done := 2; } else { //- Extract the next pointer ebp := eax; ebx := 1; call ebx := Shl(ebx, 16); call ebx := Sub(ebx, 1); call ebp := And(ebp, ebx); assert ebp == SelectLSBs(16, eax); call ebp := Shr(ebp, 8); //- Next ptr assert PciCapabilityPtr(id, cap_index+1) == ebp; cap_index := cap_index+1; } } } } } procedure prep_DEV_Op(id:int, dev_offset:int) inout my r:regs, my core_state:core_state, linear io:IOState; requires ecx == id; requires edx == dev_offset; requires IsValidPciId(id); requires DEV_PciCapabilityAt(id, dev_offset); requires IsValidPciOffset(dev_offset+4); requires PciUninitialized(io); requires logical_addressing_inv(init, ptMem, core_state); requires public(id); requires public(dev_offset); requires public(io._inCtr); requires public(io._outCtr); modifies io, efl, eax, edx; ensures DEV_Op(id, dev_offset, dev_offset+4); ensures io._pci.PciConfigId == id; ensures io._pci.PciConfigOffset == dev_offset + 4; ensures PciUninitialized(io); ensures logical_addressing_inv(init, ptMem, core_state); ensures public(io._inCtr); ensures public(io._outCtr); { call edx := Add(edx, 4); call pciConfigAddr(id, edx); } procedure prep_DEV_Data(id:int, dev_offset:int) inout my r:regs, my core_state:core_state, linear io:IOState; requires ecx == id; requires edx == dev_offset; requires IsValidPciId(id); requires DEV_PciCapabilityAt(id, dev_offset); requires IsValidPciOffset(dev_offset+8); requires PciUninitialized(io); requires logical_addressing_inv(init, ptMem, core_state); requires public(id); requires public(dev_offset); requires public(io._inCtr); requires public(io._outCtr); modifies io, efl, eax, edx; ensures DEV_Data(id, dev_offset, dev_offset+8); ensures io._pci.PciConfigId == id; ensures io._pci.PciConfigOffset == dev_offset + 8; ensures PciUninitialized(io); ensures logical_addressing_inv(init, ptMem, core_state); ensures public(io._inCtr); ensures public(io._outCtr); { call edx := Add(edx, 8); call pciConfigAddr(id, edx); } procedure walkThroughDevStateMachine(inout linear dev_states:DEV_StateMachines, id:int, dev_offset:int) inout my r:regs, my core_state:core_state, linear io:IOState; requires ecx == id; requires edx == dev_offset; requires ?CodeBase == 0x300000; requires dev_states.states[id] is MemApproved; requires IsValidPciId(id); requires IsValidPciOffset(dev_offset); requires DEV_PciCapabilityAt(id, edx); requires PciUninitialized(io); requires logical_addressing_inv(init, ptMem, core_state); requires public(id); requires public(dev_offset); requires public(io._inCtr); requires public(io._outCtr); modifies io, efl, eax, ebx, edx, ebp, edi, esi; // ensures dev_states == States(old(dev_states).states[id := Complete()]); ensures (forall other_id:int :: other_id != id ==> dev_states.states[other_id] == old(dev_states).states[other_id]); ensures dev_states.states[id] is Complete; ensures logical_addressing_inv(init, ptMem, core_state); ensures PciUninitialized(io); ensures public(io._inCtr); ensures public(io._outCtr); { ebp := edx; //- Make sure there's enough room for the DEV registers edx := edx + 8; if (edx >= 256) { eax := 0x5555006f; //- Badly placed DEV offset call debugBreak(); } assert IsValidPciOffset(dev_offset + 4); assert IsValidPciOffset(dev_offset + 8); edx := ebp; call prep_DEV_Op(id, dev_offset); eax := 0; edx := 0xcfc; call dev_states := DEV_PciConfigDataOut32(dev_states, id, dev_offset, dev_offset+4); assert dev_states.states[id] is SetOpBaseLo; call reveal_IoInv(); edx := ebp; call prep_DEV_Data(id, dev_offset); eax := 0x30F001; edx := 0xcfc; call dev_states := DEV_PciConfigDataOut32(dev_states, id, dev_offset, dev_offset+8); assert dev_states.states[id] is SetDataBaseLo; edx := ebp; call prep_DEV_Op(id, dev_offset); eax := 0x100; edx := 0xcfc; call dev_states := DEV_PciConfigDataOut32(dev_states, id, dev_offset, dev_offset+4); assert dev_states.states[id] is SetOpBaseHi; edx := ebp; call prep_DEV_Data(id, dev_offset); eax := 0; edx := 0xcfc; call dev_states := DEV_PciConfigDataOut32(dev_states, id, dev_offset, dev_offset+8); assert dev_states.states[id] is SetDataBaseHi; edx := ebp; call prep_DEV_Op(id, dev_offset); eax := 0x300; edx := 0xcfc; call dev_states := DEV_PciConfigDataOut32(dev_states, id, dev_offset, dev_offset+4); assert dev_states.states[id] is SetOpCap; edx := ebp; call prep_DEV_Data(id, dev_offset); edx := 0xcfc; call dev_states := DEV_PciConfigDataIn32(dev_states, id, dev_offset, dev_offset+8); assert dev_states.states[id] is GotDataCap; call eax := Shr(eax, 16); ebx := 1; call ebx := Shl(ebx, 8); call lemma_shl_1(); ebx := ebx - 1; call eax := And(eax, ebx); assert eax == num_DEV_map_regs(id); call upper_bits_clear_ubound_lemma(); assert eax <= 1023; ebx := 0; esi := eax; assert esi == num_DEV_map_regs(id); while (ebx < esi) invariant esi == num_DEV_map_regs(id) && 0 <= num_DEV_map_regs(id) && num_DEV_map_regs(id) <= 1023; invariant 0 <= ebx && ebx <= num_DEV_map_regs(id); invariant ebx == 0 ==> dev_states.states[id] is GotDataCap; invariant ebx > 0 ==> dev_states.states[id] is SetDataMap && dev_states.states[id].d_map_index == ebx - 1; invariant ebp == dev_offset; invariant (forall other_id:int :: other_id != id ==> dev_states.states[other_id] == old(dev_states.states[other_id])); invariant PciUninitialized(io); invariant logical_addressing_inv(init, ptMem, core_state); invariant public(id); invariant public(dev_offset); invariant public(ebx); invariant public(esi); invariant public(io._inCtr); invariant public(io._outCtr); { edx := ebp; call prep_DEV_Op(id, dev_offset); eax := 0x200; eax := eax + ebx; edx := 0xcfc; call dev_states := DEV_PciConfigDataOut32(dev_states, id, dev_offset, dev_offset+4); assert dev_states.states[id] is SetOpMap; call reveal_IoInv(); edx := ebp; call prep_DEV_Data(id, dev_offset); eax := 0; edx := 0xcfc; call dev_states := DEV_PciConfigDataOut32(dev_states, id, dev_offset, dev_offset+8); assert dev_states.states[id] is SetDataMap && dev_states.states[id].d_map_index == ebx; ebx := ebx + 1; } edx := ebp; call prep_DEV_Op(id, dev_offset); eax := 0x400; edx := 0xcfc; call dev_states := DEV_PciConfigDataOut32(dev_states, id, dev_offset, dev_offset+4); assert dev_states.states[id] is SetOpCtrl; edx := ebp; call prep_DEV_Data(id, dev_offset); eax := 0x31; edx := 0xcfc; call dev_states := DEV_PciConfigDataOut32(dev_states, id, dev_offset, dev_offset+8); assert dev_states.states[id] is SetDataCtrl; //- Loop until the cache invalidation completes ebx := 0; while (ebx == 0) invariant ebx == 0 ==> dev_states.states[id] is SetDataCtrl; invariant ebx == 1 ==> dev_states.states[id] is Complete; invariant ebx == 0 || ebx == 1; invariant ebp == dev_offset; invariant (forall other_id:int :: other_id != id ==> dev_states.states[other_id] == old(dev_states.states[other_id])); invariant PciUninitialized(io); invariant logical_addressing_inv(init, ptMem, core_state); invariant public(id); invariant public(dev_offset); invariant public(ebx); invariant public(io._inCtr); invariant public(io._outCtr); { edx := ebp; call prep_DEV_Data(id, dev_offset); edx := 0xcfc; call dev_states := DEV_PciConfigDataIn32(dev_states, id, dev_offset, dev_offset+8); call reveal_IoInv(); var eax_val:int := eax; ebx := 1; call ebx := Shl(ebx, 4); call eax := And(eax, ebx); assert (eax != 0) == GetBit(4, eax_val); if (eax == 0) { ebx := 1; } else { ebx := 0; } } } procedure pciEnumeration(inout linear dev_states:DEV_StateMachines) inout my r:regs, my core_state:core_state, linear io:IOState; requires (forall i:int :: dev_states.states[i] is MemApproved); requires ?CodeBase == 0x300000; requires PciUninitialized(io); requires logical_addressing_inv(init, ptMem, core_state); requires public(io._inCtr); requires public(io._outCtr); modifies io, efl, eax, ebx, ecx, edx, ebp, edi, esi; ensures (forall i:int ::{ dev_states.states[i] } IsValidPciId(i) ==> (Is_DEV_PCI_config(i) ==> dev_states.states[i] is Complete)); ensures logical_addressing_inv(init, ptMem, core_state); ensures PciUninitialized(io); ensures public(io._inCtr); ensures public(io._outCtr); { var pci_id @ ecx := 0; while (pci_id < 65536) invariant 0 <= pci_id && pci_id <= 65536; invariant (forall id:int :: pci_id <= id ==> dev_states.states[id] is MemApproved); invariant (forall id:int :: 0 <= id && id < pci_id ==> (Is_DEV_PCI_config(id) && dev_states.states[id] is Complete) || !Is_DEV_PCI_config(id)); invariant PciUninitialized(io); invariant logical_addressing_inv(init, ptMem, core_state); invariant public(pci_id); invariant public(io._inCtr); invariant public(io._outCtr); { //- Check whether there is a device present at all edx := 0; call pciConfigAddr(pci_id, 0); call /* eax := */ PciConfigDataIn32(pci_id, 0); if (eax == 0xFFFFFFFF) { call non_existent_devices(pci_id); assert !Is_DEV_PCI_config(pci_id); } else { call findDEVCapability(ecx); if (esi == 2) { assert DEV_PciCapabilityAt(pci_id, edx); assert TV(edx) ==> Is_DEV_PCI_config(pci_id); var offset:int := edx; call walkThroughDevStateMachine(inout dev_states, pci_id, offset); assert TV(offset) && Is_DEV_PCI_config(pci_id); assert dev_states.states[pci_id] == Complete(); } else { assert !Is_DEV_PCI_config(pci_id); } } pci_id := pci_id + 1; } } implementation initDEV(linear dev_states:DEV_StateMachines, linear dev_mem:mem) returns (linear new_mem:mem) // inout my r:regs, my core_state:core_state, linear io:IOState; // requires !init; // requires ?CodeBase == 0x300000; // requires (forall i:int :: {dev_states.states[i]} dev_states.states[i] is Init); // requires (forall i:int :: {dev_mem.dom[i]} dev_mem.dom[i] <==> (Aligned(i) && ?DEVLo <= i && i < ?DEVHi)); // requires logical_addressing_inv(init, ptMem, core_state); // modifies io, efl, eax, ebx, ecx, edx, esi, edi, ebp; // ensures (forall i:int ::{ new_mem.dom[i] } new_mem.dom[i] <==> Aligned(i) && ?CodeBase + 64*1024 + 124*1024 <= i && i < 128*1024*1024); // ensures logical_addressing_inv(init, ptMem, core_state); { linear var dmem:mem := dev_mem; call prepDEVmem(inout dmem); linear var dstates:DEV_StateMachines := dev_states; call dstates := begin_DEV_enablement(dstates, dmem); assert (forall i:int :: {dstates.states[i]} dstates.states[i] is MemApproved); call pciEnumeration(inout dstates); call new_mem := complete_DEV_enablement(dstates); assert (forall i:int ::{ new_mem.dom[i] }{TV(i)} TV(i) ==> (new_mem.dom[i] <==> ?CodeBase + 64*1024 <= i && i < 128*1024*1024)); //- Top=base+64K DEV covers 128MB total //- Set the rest of the DEV, covering the rest of memory, to 0 to enable device accesses ebx := 0x310000; //- codeBase + 64K call reveal_Aligned(ebx); assert Aligned(ebx); var i:int := 0; while (ebx < 0x32F000) //- codeBase + 64K + 124K invariant 0 <= i && i <= 0x7c00; invariant ebx == 0x310000 + 4*i; invariant Aligned(ebx); invariant (forall j:int :: {new_mem.dom[j]}{TV(j)} TV(j) ==> (new_mem.dom[j] <==> (?CodeBase + 64*1024 <= j && j < 128*1024*1024))); invariant !init; invariant logical_addressing_inv(init, ptMem, core_state); { assert Aligned(ebx); assert EvalPtrOk(OMem(MReg(EBX, 0))); assert PhysPtrOk(new_mem, EvalPtr(r, OMem(MReg(EBX, 0)))); assert word(EvalPtr(r, OMem(MReg(EBX, 0)))); call Store(inout new_mem, ebx, 0); call __notAligned(ebx); ebx := ebx + 4; i := i + 1; assert TV(0x310000) && TO(i); } // assert (forall j:int :: {new_mem.dom[j]}{TV(j)} TV(j) ==> (new_mem.dom[j] <==> (Aligned(j) && ?CodeBase + 64*1024 <= j && j < 128*1024*1024))); // call reveal_Aligned(0x32F000); // assert Aligned(0x32F000); // assert TV(0x32F000) ==> new_mem.dom[0x32F000]; //- Drop the DEV from new mem, so the rest of the implementation doesn't trample on it linear var extra_dev_mem:mem; call extra_dev_mem := memEmpty(); call new_mem, extra_dev_mem := memTransfer(new_mem, extra_dev_mem, (lambda j:int:: 0x310000 <= j && j < 0x32F000)); // // assert !(lambda j:int:: Aligned(j) && 0x310000 <= j && j < 0x32F000)[0x32F000]; // // call reveal_Aligned(0x32F000); // assert Aligned(0x32F000); // //assert TV(0x32F000) ==> extra_dev_mem.dom[0x32F000]; // assert TV(0x32F000) ==> new_mem.dom[0x32F000]; // assert ?CodeBase + 64*1024 + 124*1024 == 0x32F000; // assert (forall i:int ::{ new_mem.dom[i] }{TV(i)} TV(i) ==> (new_mem.dom[i] ==> Aligned(i) && ?CodeBase + 64*1024 + 124*1024 <= i && i < 128*1024*1024)); // assert (forall i:int ::{ new_mem.dom[i] }{TV(i)} TV(i) ==> (Aligned(i) && ?CodeBase + 64*1024 + 124*1024 <= i && i < 128*1024*1024 ==> new_mem.dom[i])); // assert (forall j:int ::{ new_mem.dom[j] }{TV(j)} TV(j) ==> (new_mem.dom[j] <==> Aligned(j) && ?CodeBase + 64*1024 + 124*1024 <= j && j < 128*1024*1024)); } } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Devices/PCI.ifc.beat ================================================ //-private-import BaseSpec; //-private-import MemorySpec; //-private-import IoTypesSpec; //-private-import MachineStateSpec; //-private-import AssemblySpec; //-private-import InterruptsSpec; //-private-import IoSpec; //-private-import Core; //-private-import LogicalAddressing; //-private-import Overflow; //-private-import Util; //-private-import Stacks; //-private-import Partition; //-private-import Instructions; //-private-import Separation; //-private-import IntLemmasBase; //-private-import IntLemmasGc; //-private-import SimpleGcMemory; //-private-import SimpleCommon; //-private-import SimpleCollector; //- module interface PCI { //procedure pciConfigRead32($id:int, $offset:int) // inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars; // inout $absMem:[int][int]int, $toAbs:[int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout; // requires ecx == $id; // requires edx == $offset; // requires 0 <= $id && $id < 65536; // requires 0 <= $offset && $offset < 256; // requires $id mod 4 == 0 && $offset mod 4 == 0; //// requires SMemRequireRA(4, stk, esp, RET); //// requires RET == ReturnToAddr($Mem[esp]); // requires logical_addressing_inv(init, ptMem, core_state); // requires NucleusInv(objLayouts, $S, $toAbs, $absMem, GcVars, $Mem_Vars, $stacksFrames, $IoVars); // modifies state, efl, eax, ecx, edx; //// ensures SMemEnsure(stk, old(stk), esp, old(esp)); // ensures PciConfigReadResult(old(ecx), old(edx), eax); // ensures logical_addressing_inv(init, ptMem, core_state); // ensures NucleusInv(objLayouts, $S, $toAbs, $absMem, GcVars, $Mem_Vars, $stacksFrames, $IoVars); //- Does PCI enumeration to find a device with the specified Device & Vendor ID or dies trying //- if no such device is present procedure pciFindDeviceVendor(device_vendor_id:int); inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars; inout $absMem:[int][int]int, $toAbs:[int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout; requires ebp == device_vendor_id; requires word(device_vendor_id); requires NucleusInv(objLayouts, $S, $toAbs, $absMem, GcVars, $Mem_Vars, $stacksFrames, $IoVars); requires public(device_vendor_id); requires public(io._inCtr); requires public(io._outCtr); modifies io, efl, eax, ebx, ecx, edx, esi, edi; ensures IsValidPciId(eax); ensures PciConfigReadResult(eax, 0, device_vendor_id); ensures NucleusInv(objLayouts, $S, $toAbs, $absMem, GcVars, $Mem_Vars, $stacksFrames, $IoVars); ensures public(eax); ensures public(io._inCtr); ensures public(io._outCtr); //- Maps a PCI device into memory space or dies trying (if you've allocated too many PCI devices) procedure pciMemMap(pLo:int, pHi:int, $id:int); inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars; inout $absMem:[int][int]int, $toAbs:[int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout; requires ecx == $id; requires IsValidPciId($id); requires $id mod 4 == 0; requires and($id, 7) == 0; requires (exists ret:int :: PciConfigReadResult($id, 0, ret) && ret != 0xffff); requires edi == pLo && pLo == ?pciLo; requires edx == pHi && pHi == ?pciHi; requires (?pciHi - ?pciLo) mod 16 == 0; //requires SMemRequireInline(28, 0, stk, esp); requires logical_addressing_inv(init, ptMem, core_state); requires NucleusInv(objLayouts, $S, $toAbs, $absMem, GcVars, $Mem_Vars, $stacksFrames, $IoVars); requires public($id); requires public(pLo); requires public(pHi); requires public(io._inCtr); requires public(io._outCtr); modifies io, efl, eax, ebx, ecx, edx, esi, edi, ebp, $pciMem; ensures eax == PciMemSize($id); ensures ebx == PciMemAddr($id); ensures ecx == $id; ensures word(PciMemAddr($id)); ensures word(PciMemSize($id)); ensures io._pci.PciConfigState[$id] == 4; ensures logical_addressing_inv(init, ptMem, core_state); ensures NucleusInv(objLayouts, $S, $toAbs, $absMem, GcVars, $Mem_Vars, $stacksFrames, $IoVars); ensures public(eax); ensures public(ebx); ensures public(ecx); ensures public(io._inCtr); ensures public(io._outCtr); //- Searches our table of existing PCI mappings for the ID provided //- Returns the mapping's address (ebx) and size (eax), if found. //- Else sets ecx to 0 and returns a suggested slot (eax) for the new mapping procedure lookupMapping(id:int, pLo:int, pHi:int) inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars; inout $absMem:[int][int]int, $toAbs:[int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout; //inout iovars:ioVars; requires IsValidPciId(id); requires esi == id; requires edi == pLo && pLo == ?pciLo; requires edx == pHi && pHi == ?pciHi; requires (?pciHi - ?pciLo) mod 16 == 0; requires Aligned(?pciLo); requires logical_addressing_inv(init, ptMem, core_state); requires NucleusInv(objLayouts, $S, $toAbs, $absMem, GcVars, $Mem_Vars, $stacksFrames, $IoVars); requires public(id); requires public(pLo); requires public(pHi); requires public(io._inCtr); requires public(io._outCtr); modifies efl, eax, ebx, ecx, edi, ebp; modifies mems.pci; ensures mems == old(mems); ensures ecx == 1 ==> eax == PciMemSize(id) && ebx == PciMemAddr(id) && word(PciMemSize(id)) && word(PciMemAddr(id)) && io._pci.PciConfigState[id] == 4; ensures ecx == 0 ==> io._pci.PciConfigState[id] == 0; ensures ecx == 0 ==> ?pciLo <= ebx && ebx < ?pciHi && Aligned(ebx) && !IsValidPciId($pciMem[ebx]) && (exists j:int :: TV(j) && 0 <= j && ebx == ?pciLo + 16*j); // ensures ecx == 0 ==> ?pciLo <= ebx && ebx < ?pciHi && Aligned(ebx) && !IsValidPciId($pciMem[ebx]) && // (exists j:int :: TV(j) && 0 <= j && ebx == ?pciLo + 16*j); ensures ecx == 0 || ecx == 1; ensures logical_addressing_inv(init, ptMem, core_state); ensures NucleusInv(objLayouts, $S, $toAbs, $absMem, GcVars, $Mem_Vars, $stacksFrames, $IoVars); //ensures public(eax); //ensures public(ebx); //ensures public(ecx); ensures public(io._inCtr); ensures public(io._outCtr); //// internal extern static byte[] PciDmaBuffer(); //procedure PciDmaBuffer(); // requires RET == ReturnToAddr($Mem[esp]); // requires isStack($S) && SpRequire($S, esp, 4); // requires NucleusInv($S, $StackState, $toAbs, $AbsMem, GcVars, $Mem_Vars, $StacksFrames, $IoVars); // modifies state, efl, eax, edx, esp; // ensures esp == old(esp) + 4; // ensures $IoMmuEnabled ==> eax == ?dmaLo - 8; // ensures !$IoMmuEnabled ==> eax == 0; // //// internal extern static uint PciDmaPhysicalAddr(); //procedure PciDmaPhysicalAddr(); // requires RET == ReturnToAddr($Mem[esp]); // requires isStack($S) && SpRequire($S, esp, 4); // requires NucleusInv($S, $StackState, $toAbs, $AbsMem, GcVars, $Mem_Vars, $StacksFrames, $IoVars); // modifies state, efl, eax, edx, esp; // ensures esp == old(esp) + 4; // ensures $IoMmuEnabled ==> eax == ?dmaLo; // ensures !$IoMmuEnabled ==> eax == 0; // //// internal extern static uint PciMemRead32(uint id, uint offset); //procedure PciMemRead32($id:int, $offset:int); // inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState; // inout mems:mems; // requires word(eax) && word(ebx) && word(ecx) && word(edx) && word(esi) && word(edi) && word(ebp); // requires ecx == $id; // requires edx == $offset; // requires RET == ReturnToAddr($Mem[esp]); // requires isStack($S) && SpRequire($S, esp, 4); // requires NucleusInv($S, $StackState, $toAbs, $AbsMem, GcVars, $Mem_Vars, $StacksFrames, $IoVars); // modifies state, efl, eax, ebx, ecx, edx, esi, edi, esp; // not ebp // ensures esp == old(esp) + 4; // ensures PciMemLoaded($id, PciMemAddr($id) + $offset, eax); // //// internal extern static void PciMemWrite32(uint id, uint offset, uint val); //procedure PciMemWrite32($id:int, $offset:int, $val:int); // inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState; // inout mems:mems; // requires word(eax) && word(ebx) && word(ecx) && word(edx) && word(esi) && word(edi) && word(ebp); // requires ecx == $id; // requires edx == $offset; // requires $StacksFrames[$S].Slices[esp + 4] == $StacksFrames[$S].Count && $fMems[$S][esp + 4] == $val; // requires RET == ReturnToAddr($Mem[esp]); // requires isStack($S) && SpRequire($S, esp, 8); // requires NucleusInv($S, $StackState, $toAbs, $AbsMem, GcVars, $Mem_Vars, $StacksFrames, $IoVars); // modifies state, efl, eax, ebx, ecx, edx, esi, edi, esp; // not ebp // ensures esp == old(esp) + 4; // ensures PciMemStored($id, PciMemAddr($id) + $offset, $val); } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Devices/PCI.imp.beat ================================================ //-private-import BaseSpec; //-private-import MemorySpec; //-private-import IoTypesSpec; //-private-import MachineStateSpec; //-private-import AssemblySpec; //-private-import InterruptsSpec; //-private-import IoSpec; //- //- //- //- //- //-private-import Core; //-private-import LogicalAddressing; //-private-import Overflow; //-private-import Util; //-private-import Stacks; //-private-import Partition; //-private-import Instructions; //-private-import Separation; //-private-import IntLemmasBase; //-private-import IntLemmasGc; //-private-import SimpleGcMemory; //-private-import SimpleCommon; //-private-import SimpleCollector; //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- //- Functions to interact with the PCI bus and its devices //- module implementation PCI { procedure pciConfigAddr($id:int, $offset:int) inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars; inout $absMem:[int][int]int, $toAbs:[int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout; requires IsValidPciId($id); requires IsValidPciOffset($offset); requires ecx == $id; requires edx == $offset; requires logical_addressing_inv(init, ptMem, core_state); requires MemInv($Mem_Vars); requires public($id); requires public($offset); requires public(io._inCtr); requires public(io._outCtr); // requires NucleusInv(objLayouts, $S, $toAbs, $absMem, GcVars, $Mem_Vars, $stacksFrames, $IoVars); modifies io, efl, eax, edx; ensures io._pci.PciConfigId == $id; ensures io._pci.PciConfigOffset == $offset; ensures edx == 0xcfc; //- The following is the strongest we can say (can't say IoInv), because we use pciConfigAddr when IoInv isn't true //- Hence we can't require it, and thus can't ensure it ensures (forall i:int::{io._pci.PciConfigState[i]} 0 <= i && i < 65536 ==> (io._pci.PciConfigState[i] == old(io)._pci.PciConfigState[i])); ensures (forall addr:int :: ?pciLo <= addr && addr < ?pciHi ==> $pciMem[addr] == old($pciMem[addr])); ensures logical_addressing_inv(init, ptMem, core_state); ensures MemInv($Mem_Vars); ensures public(io._inCtr); ensures public(io._outCtr); // ensures NucleusInv(objLayouts, $S, $toAbs, $absMem, GcVars, $Mem_Vars, $stacksFrames, $IoVars); { call reveal_IoInv(); eax := ecx; call eax := Shl(eax, 8); call eax := Or(eax, edx); edx := 0x7fffffff; call edx := AddChecked(edx, 1); call eax := Or(eax, edx); edx := 0xcf8; //assert IoInv_Transparent($IoVars, $pciMem); call PciConfigAddrOut32($id, $offset); //assert IoInv_Transparent($IoVars, $pciMem); edx := 0xcfc; //assert IoInv_Transparent($IoVars, $pciMem); call reveal_IoInv(); //assert IoInv($IoVars, $pciMem); } // Searches our table of existing PCI mappings for the ID provided // Returns the mapping's address (ebx) and size (eax), if found. // Else sets ecx to 0 and returns a suggested slot (eax) for the new mapping //procedure lookupMapping(id:int, pLo:int, pHi:int) // inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars; // inout $absMem:[int][int]int, $toAbs:[int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout; // //inout iovars:ioVars; // requires IsValidPciId(id); // requires esi == id; // requires edi == pLo && pLo == ?pciLo; // requires edx == pHi && pHi == ?pciHi; // requires (?pciHi - ?pciLo) mod 16 == 0; // requires Aligned(?pciLo); // requires logical_addressing_inv(init, ptMem, core_state); // requires NucleusInv(objLayouts, $S, $toAbs, $absMem, GcVars, $Mem_Vars, $stacksFrames, $IoVars); // modifies state, efl, eax, ebx, ecx, edi, ebp; // ensures ecx == 1 ==> eax == PciMemSize(id) && ebx == PciMemAddr(id) // && io._pci.PciConfigState[id] == 4; // ensures ecx == 0 ==> io._pci.PciConfigState[id] == 0; // ensures ecx == 0 ==> ?pciLo <= ebx && ebx < ?pciHi && Aligned(ebx) && !IsValidPciId($pciMem[ebx]) && // (exists j:int :: TV(j) && 0 <= j && ebx == ?pciLo + 16*j); //// ensures ecx == 0 ==> ?pciLo <= ebx && ebx < ?pciHi && Aligned(ebx) && !IsValidPciId($pciMem[ebx]) && //// (exists j:int :: TV(j) && 0 <= j && ebx == ?pciLo + 16*j); // ensures ecx == 0 || ecx == 1; // ensures logical_addressing_inv(init, ptMem, core); // ensures NucleusInv(objLayouts, $S, $toAbs, $absMem, GcVars, $Mem_Vars, $stacksFrames, $IoVars); implementation lookupMapping(id:int, pLo:int, pHi:int) { call reveal_MemInvDetails(); var i:int := 0; ecx := 0; ebx := PciLo; //- If we don't find an empty slot, default to overwriting the first one assert TV(0); call reveal_IoInv(); assert TV(0); assert (exists j:int :: {TV(j)} ebx == ?pciLo + 16*j); while(edi < edx) invariant mems == old(mems); invariant edi == ?pciLo + 16*i; invariant ?pciLo <= edi && edi <= ?pciHi; invariant esi == id; invariant IsValidPciId(id); invariant ecx == 1 || ecx == 0; invariant ecx == 1 ==> eax == PciMemSize(id) && ebx == PciMemAddr(id) && word(PciMemSize(id)) && word(PciMemAddr(id)) && io._pci.PciConfigState[id] == 4; invariant ecx == 0 ==> ?pciLo <= ebx && ebx < ?pciHi && Aligned(ebx) && (exists j:int :: TV(j) && 0 <= j && ebx == ?pciLo + 16*j); invariant ecx == 0 ==> (forall j:int :: {TV(j)} TV(j) && 0 <= j && j < i ==> mems.pci[?pciLo + 16*j] != id); invariant ecx == 0 ==> (forall addr:int, j:int::{$pciMem[addr],TV(j)} TV(j) && 0 <= j && addr == ?pciLo + 16*j && ?pciLo <= addr && addr < edi ==> $pciMem[addr] != id); invariant logical_addressing_inv(init, ptMem, core_state); invariant NucleusInv(objLayouts, $S, $toAbs, $absMem, GcVars, $Mem_Vars, $stacksFrames, $IoVars); //invariant public(eax); //invariant public(ebx); //invariant public(ecx); invariant public(edx); invariant public(edi); invariant public(esi); invariant public(io._inCtr); invariant public(io._outCtr); { call reveal_IoInv(); assert Aligned(?pciLo) && TV(?pciLo) && TO(4*i); call ebp := Load($pciMem, edi); if (ebp == esi) { ecx := 1; assert TV(edi) && TO(1) && TO(2); call ebx := Load($pciMem, edi + 4); call eax := Load($pciMem, edi + 8); assert TV(i); assert ebx == PciMemAddr(id); assert eax == PciMemSize(id); } if (ebp == 0xffffffff) { if (ecx != 1) { //- Only save a slot if we haven't already found it //- Save an empty slot we can use if we don't find the mapping ebx := edi; assert ebx == ?pciLo + 16*i; assert TV(i) && (exists j:int :: ebx == ?pciLo + 16*j); assert Aligned(?pciLo) && TV(?pciLo) && TO(4*i); assert ?pciLo <= ebx && ebx < ?pciHi; } } edi := edi + 16; i := i + 1; } if (ecx == 0) { call ebp := Load($pciMem, ebx); // TODO: Turn this into a static check based on ghost counter of # of mapped PCI devices if (ebp < 65536) { //- ebx is pointed at a valid PCI id -- die instead of clobbering it eax := 0x5555002f; call debugBreak(); } } // assert ecx == 0 ==> $pciMem[ebx] >= 65536; // assert ecx == 0 ==> !IsValidPciId($pciMem[ebx]); // assert ecx == 0 ==> ?pciLo <= ebx && ebx < ?pciHi && Aligned(ebx) && !IsValidPciId($pciMem[ebx]); // assert ecx == 0 ==> (exists j:int :: {TV(j)} TV(j) && 0 <= j && ebx == ?pciLo + 16*j); // assert ecx == 0 ==> ?pciLo <= ebx && ebx < ?pciHi && Aligned(ebx) && !IsValidPciId($pciMem[ebx]) && // (exists j:int :: TV(j) && 0 <= j && ebx == ?pciLo + 16*j); // assert ecx == 0 ==> ?pciLo <= ebx && ebx < ?pciHi && // (exists j:int :: ebx == ?pciLo + 16*j && TV(?pciLo) && TO(4*j) && Aligned(ebx)); // assert ecx == 0 ==> (exists j:int :: ebx == ?pciLo + 16*j); // assert Aligned(?pciLo) && TV(?pciLo); // && TO(4*j); // assert Aligned(ebx); call reveal_IoInv(); } //procedure stack_test($id:int) // inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars; // inout $absMem:[int][int]int, $toAbs:[int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout; // requires ecx == $id; // requires 0 <= $id && $id < 65536; // requires $id mod 4 == 0; // requires (exists ret:int :: PciConfigReadResult($id, 0, ret) && ret != 0xffff); // //requires SMemRequire(28, stk, esp); // requires SMemRequireInline(28, 8, stk, esp); // requires logical_addressing_inv(init, ptMem, core_state); // requires NucleusInv(objLayouts, $S, $toAbs, $absMem, GcVars, $Mem_Vars, $stacksFrames, $IoVars); // modifies state, efl, eax, ebx, ecx, edx, esi, edi; // modifies mems; // ensures logical_addressing_inv(init, ptMem, core_state); // ensures NucleusInv(objLayouts, $S, $toAbs, $absMem, GcVars, $Mem_Vars, $stacksFrames, $IoVars); //{ // var temp @ stk[esp + 0] := ecx; // assert TV(esp) && TO(1); // var temp2 @ stk[esp + 4] := ecx; // //} // ecx = id // edx = offset //implementation pciConfigRead32($id:int, $offset:int) //{ // eax := edx; // call eax := And(eax, 3); // if (eax != 0) // { // eax := 0x55550026; // call debugBreak(); // } // assert (0 <= $id && $id < 65536); // call pciConfigAddr($id, $offset); // call /*eax :=*/ PciConfigDataIn32($id, $offset); //} //procedure pciConfigDataIn32(id:int, offset:int) // inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars; // inout $absMem:[int][int]int, $toAbs:[int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout; // requires IsValidPciId(id); // requires IsValidPciOffset(offset); // requires id == io._pci.PciConfigId; // requires offset == io._pci.PciConfigOffset; // requires old(regs)[EDX] == 0xcfc; // requires NucleusInv(objLayouts, $S, $toAbs, $absMem, GcVars, $Mem_Vars, $stacksFrames, $IoVars); // //requires IoInv($IoVars, $pciMem); // requires logical_addressing_inv(init, ptMem, core_state); // modifies state, efl, eax, edx; // ensures (exists eax_val:int :: // $State._cores[me] == LogicalCoreUpdate1(old($State._cores[me]), OReg(EAX), eax, core._efl) // && PciConfigReadResult(id, offset, eax_val) // && (old($State)._io._pci.PciConfigState[id] == 0 && offset == 16 && and(eax_val, 15) == 0 ==> PciMemAddr(id) == eax_val) // && (old($State)._io._pci.PciConfigState[id] == 2 && offset == 16 ==> PciMemSize(id) == 1 + neg(eax_val)) // && word(eax_val)); // //ensures IoInv($IoVars, $pciMem); // ensures logical_addressing_inv(init, ptMem, core_state); // ensures NucleusInv(objLayouts, $S, $toAbs, $absMem, GcVars, $Mem_Vars, $stacksFrames, $IoVars); //{ // call reveal_IoInv(); // assert (forall i:int::{io._pci.PciConfigState[i]} 0 <= i && i < 65536 ==> (io._pci.PciConfigState[i] == 0)); // call /*eax :=*/ PciConfigDataIn32(id, offset); // assert state._io == old(state._io); // assert (forall i:int::{io._pci.PciConfigState[i]} 0 <= i && i < 65536 ==> (io._pci.PciConfigState[i] == 0)); // call reveal_IoInv(); // assert &&& &&& IoInv_Transparent($IoVars, $pciMem); //} implementation pciFindDeviceVendor(device_vendor_id:int) { //var found @ edi; var pci_id @ esi; //- Walk through the PCI device space looking for a match var matching_id @ ebx := 65536; pci_id := 0; while (pci_id < 65536) invariant device_vendor_id == ebp; invariant 0 <= pci_id && pci_id <= 65536; invariant matching_id != 65536 ==> IsValidPciId(matching_id); invariant matching_id != 65536 ==> PciConfigReadResult(matching_id, 0, device_vendor_id); invariant NucleusInv(objLayouts, $S, $toAbs, $absMem, GcVars, $Mem_Vars, $stacksFrames, $IoVars); invariant public(pci_id); invariant public(matching_id); invariant public(ebp); invariant public(io._inCtr); invariant public(io._outCtr); { call reveal_IoInv(); ecx := pci_id; edx := 0; call pciConfigAddr(pci_id, 0); call /* eax := */ PciConfigDataIn32(pci_id, 0); call reveal_IoInv(); if (eax == ebp) { matching_id := pci_id; } pci_id := pci_id + 1; } if (matching_id == 65536) { //- We didn't actually find it :( eax := 0x55550020; call debugBreak(); } eax := matching_id; } implementation pciMemMap(pLo:int, pHi:int, $id:int) { call reveal_MemInvDetails(); call reveal_IoInv(); eax := ecx; //- Check whether we've already mapped this device esi := ecx; call lookupMapping($id, pLo, pHi); if (ecx == 1) { //- Found a previous mapping -- panic! eax := 0x55550051; call debugBreak(); // // Found a previous mapping! Our work here is done // ecx := esi; } else { var emptySlot@ebx; // Save the slot that lookupMapping found for us assert ecx == 0; assert ?pciLo <= ebx && ebx < ?pciHi && Aligned(ebx) && (exists j:int :: 0 <= j && ebx == ?pciLo + 16*j); // assert ?pciLo <= ebx && ebx < ?pciHi && Aligned(ebx) && !IsValidPciId($pciMem[ebx]) && // (exists j:int :: 0 <= j && ebx == ?pciLo + 16*j); assert (exists j:int :: {TV(j)} TV(j) && 0 <= j && ebx == ?pciLo + 16*j); assert (exists j:int :: 0 <= j && ebx == ?pciLo + 16*j); //- Device and Vendor ID edx := 0; ecx := esi; call reveal_IoInv(); assert IoInv_Transparent($IoVars, $pciMem); call pciConfigAddr($id, 0); assert IoInv_Transparent($IoVars, $pciMem); call /*eax :=*/ PciConfigDataIn32($id, 0); var dev_vendor_id:int := eax; call eax := And(eax, 65535); if (eax == 65535) { eax := 0x55550021; call debugBreak(); } //- Status and Command registers edx := 4; call pciConfigAddr($id, 4); call /*eax :=*/ PciConfigDataIn32($id, 4); var status_cmd @ ebp := eax; assert IoInv_Transparent($IoVars, $pciMem); //- BIST || Header Type || LatencyTimer || CacheLineSize edx := 12; call pciConfigAddr($id, 12); call /*eax :=*/ PciConfigDataIn32($id, 12); var header @ esi := eax; //- Grab the first base address register (BAR) edx := 16; call pciConfigAddr($id, 16); call /*eax :=*/ PciConfigDataIn32($id, 16); var bar @ edi := eax; //- Check HeaderType is Type 0 (normal PCI, not a bridge or a CardBus) eax := header; var ghost_header:int := header; //- Save a ghost copy, so we can reuse esi call eax := Shr(eax, 16); call eax := And(eax, 0xff); if (eax != 0) { eax := 0x55550022; call debugBreak(); } assert IoInv_Transparent($IoVars, $pciMem); //- Check MemoryAddress type (lower three bits must be 0 for memory-mapped BAR) eax := bar; call eax := And(eax, 15); if (eax != 0) { eax := 0x55550023; call debugBreak(); } //- Make sure the address is in a sane location if (bar < 0xC0000000) { eax := 0x55550024; call debugBreak(); } //- Walkthrough PCI memory mapping state machine call reveal_IoInv(); assert IoInv_Transparent($IoVars, $pciMem); //- State 0 - Disable memory mapping edx := 4; call pciConfigAddr($id, 4); esi := 0xfffffffd; eax := status_cmd; call reveal_IoInv(); call eax := And(eax, esi); call PciConfigDataOut32($id, 4, dev_vendor_id, status_cmd, ghost_header, bar); //- State 1 - Ask the device what size it wants edx := 16; call pciConfigAddr($id, 16); eax := 0xffffffff; call PciConfigDataOut32($id, 16, dev_vendor_id, status_cmd, ghost_header, bar); edx := 16; call pciConfigAddr($id, 16); call /*eax :=*/ PciConfigDataIn32($id, 16); //- Calculate the size requested as (~eax)+1 call eax := Not(eax); call eax := AddChecked(eax, 1); assert (eax == PciMemSize($id)); var sizeBits @ esi := eax; //- Make sure we're not going to clobber the TPM call eax := AddChecked(eax, bar); if (eax >= 0xFED40000) { eax := bar; if (eax < 0xFED45000) { eax := 0x55550025; call debugBreak(); } } //- State 2 - Restore the previous address edx := 16; call pciConfigAddr($id, 16); eax := bar; call PciConfigDataOut32($id, 16, dev_vendor_id, status_cmd, ghost_header, bar); //- State 3 - Turn memory mapping back on edx := 4; call pciConfigAddr($id, 4); eax := status_cmd; call eax := Or(eax, 2); call PciConfigDataOut32($id, 4, dev_vendor_id, status_cmd, ghost_header, bar); //- State 4 - Store and return the results assert Aligned(emptySlot) && TV(emptySlot) && TO(1) && TO(2); call Store(inout mems.pci, emptySlot, ecx); call Store(inout mems.pci, emptySlot + 4, bar); call Store(inout mems.pci, emptySlot + 8, sizeBits); call reveal_IoInv(); // assert PciMemAddr($id) == bar; // assert PciMemSize($id) == sizeBits; // assert SafePciMemRegion(bar, sizeBits); // assert io._pci.PciConfigState[$id] == 4; // assert $pciMem[emptySlot] == $id; // assert $pciMem[emptySlot+4] == PciMemAddr($pciMem[emptySlot]); // assert $pciMem[emptySlot+8] == PciMemSize($pciMem[emptySlot]); // assert (forall addr:int, j:int::{$pciMem[addr],TV(j)} TV(j) && 0 <= j && // addr == ?pciLo + 16*j && addr <= ?pciHi - 16 ==> // (IsValidPciId($pciMem[addr]) ==> // $pciMem[addr + 4] == PciMemAddr($pciMem[addr]) // && $pciMem[addr + 8] == PciMemSize($pciMem[addr]) // && SafePciMemRegion(PciMemAddr($pciMem[addr]), PciMemSize($pciMem[addr])) // && io._pci.PciConfigState[$pciMem[addr]] == 4 )) ; // assert ?pciLo <= ebx && ebx <= ?pciHi - 16; // assert (exists j:int :: {TV(j)} TV(j) && 0 <= j && ebx == ?pciLo + 16*j); // assert (exists j:int :: {TV(j)} TV(j) && 0 <= j && ebx == ?pciLo + 16*j && ebx <= ?pciHi - 16); // assert (exists j:int :: {TV(j)} TV(j) && 0 <= j && ebx == ?pciLo + 16*j && ebx <= ?pciHi - 16 && $pciMem[ebx]==$id && true); assert (exists j:int :: {TV(j)} TV(j) && 0 <= j && ebx == ?pciLo + 16*j && ebx <= ?pciHi - 16 && $pciMem[ebx]==$id && TV(j)); // assert $pciMem[ebx] == $id; // assert (forall addr:int, j:int::{$pciMem[addr],TV(j)} TV(j) && 0 <= j // && addr == ?pciLo + 16*j && addr <= ?pciHi - 16 // ==> $pciMem[addr] != $id); // assert (exists j:int:: {TV(j)} (0 <= j // && ebx == ?pciLo + 16*j && ebx <= ?pciHi - 16 // && $pciMem[ebx] == $id && TV(j))); // assert (exists j:int::{TV(j)} (0 <= j // && ebx == ?pciLo + 16*j && ebx <= ?pciHi - 16 // && $pciMem[ebx] == $id)); // assert (exists addr:int, j:int::{$pciMem[addr],TV(j)} (TV(j) && 0 <= j // && addr == ?pciLo + 16*j && addr <= ?pciHi - 16 // && $pciMem[addr] == $id)); // assert (exists addr:int, j:int::{$pciMem[addr],TV(j)} !(TV(j) && 0 <= j // && addr == ?pciLo + 16*j && addr <= ?pciHi - 16 // ==> $pciMem[addr] != $id)); // assert !(forall addr:int, j:int::{$pciMem[addr],TV(j)} TV(j) && 0 <= j // && addr == ?pciLo + 16*j && addr <= ?pciHi - 16 // ==> $pciMem[addr] != $id); // // assert(forall i:int::{io._pci.PciConfigState[i]} // 0 <= i && i < 65536 && i == $id && // (forall addr:int, j:int::{$pciMem[addr],TV(j)} TV(j) && 0 <= j // && addr == ?pciLo + 16*j && addr <= ?pciHi - 16 // ==> $pciMem[addr] != i) // ==> io._pci.PciConfigState[i] == 0); // // assert (forall addr:int, j:int::{$pciMem[addr],TV(j)} TV(j) && 0 <= j // && addr == ?pciLo + 16*j && addr <= ?pciHi - 16 && addr != ebx // ==> $pciMem[addr] == old($pciMem[addr])); // // assert(forall i:int::{io._pci.PciConfigState[i]} // 0 <= i && i < 65536 && i != $id // ==> io._pci.PciConfigState[i] == old(io._pci.PciConfigState[i])); // // assert old(IoInv_Transparent($IoVars, $pciMem)); // // assert(forall i:int::{old(io._pci.PciConfigState[i])} // 0 <= i && i < 65536 && i != $id && // (forall addr:int, j:int::{old($pciMem[addr]),TV(j)} TV(j) && 0 <= j // && addr == ?pciLo + 16*j && addr <= ?pciHi - 16 // ==> old($pciMem[addr]) != i) // ==> old(io._pci.PciConfigState[i]) == 0); // // assert(forall i:int::{io._pci.PciConfigState[i]} // 0 <= i && i < 65536 && i != $id && // (forall addr:int, j:int::{old($pciMem[addr]),TV(j)} TV(j) && 0 <= j // && addr == ?pciLo + 16*j && addr <= ?pciHi - 16 // ==> old($pciMem[addr]) != i) // ==> io._pci.PciConfigState[i] == 0); // // assert(forall i:int, addr:int, j:int::{io._pci.PciConfigState[i],TV(j),$pciMem[addr]} // TV(j) && 0 <= j && // 0 <= i && i < 65536 && i != $id // && addr == ?pciLo + 16*j && addr <= ?pciHi - 16 && addr != ebx // ==> // (old($pciMem[addr]) == i ==> $pciMem[addr] == i) // ); // assert(forall i:int, addr:int, j:int::{TV(i),TV(j),$pciMem[addr]} // IsValidOtherId(i, $id) && // InTableAt(i, j, old($pciMem), ebx) ==> InTableAt(i, j, $pciMem, ebx) // // && TV(j) && 0 <= j // && addr == ?pciLo + 16*j && addr <= ?pciHi - 16 && addr != ebx // ==> // (old($pciMem[addr]) == i ==> $pciMem[addr] == i) // ); // assert(forall i:int, addr:int, j:int::{TV(i),TV(j),$pciMem[addr]} // 0 <= i && i < 65536 && i != $id // && TV(j) && 0 <= j // && addr == ?pciLo + 16*j && addr <= ?pciHi - 16 && addr != ebx // ==> // (old($pciMem[addr]) == i ==> $pciMem[addr] == i) // ); // // assert(forall i:int:: // 0 <= i && i < 65536 && i != $id && TV(i) ==> // (forall addr:int, j:int:: TV(i) && TV(j) && 0 <= j // && addr == ?pciLo + 16*j && addr <= ?pciHi - 16 && addr != ebx // ==> // (old($pciMem[addr]) == i ==> $pciMem[addr] == i) // )); // assert(forall i:int::{io._pci.PciConfigState[i]} 0 <= i && i < 65536 && i != $id ==> (forall addr:int, j:int::TV(j) && 0 <= j && addr == ?pciLo + 16*j && addr <= ?pciHi - 16 && addr != ebx ==> (old($pciMem[addr]) == i ==> $pciMem[addr] == i) )); // assert(forall i:int::{io._pci.PciConfigState[i]} // 0 <= i && i < 65536 && i != $id ==> // (exists addr:int, j:int::TV(j) && TO(j) && 0 <= j // && addr == ?pciLo + 16*j && addr <= ?pciHi - 16 && addr != ebx // ==> (old($pciMem[addr]) == i) ==> $pciMem[addr] == i)); // // assert(forall i:int::{io._pci.PciConfigState[i]} // 0 <= i && i < 65536 && i != $id && // (exists addr:int, j:int::TV(j) && TO(j) && 0 <= j // && addr == ?pciLo + 16*j && addr <= ?pciHi - 16 && addr != ebx // && old($pciMem[addr]) == i) // ==> // (exists addr:int, j:int::{TO(j),$pciMem[addr]} TV(j) && 0 <= j // && addr == ?pciLo + 16*j && addr <= ?pciHi - 16 && addr != ebx // && $pciMem[addr] == i) ); // // assert(forall i:int::{io._pci.PciConfigState[i]} // 0 <= i && i < 65536 && i != $id && // (exists addr:int, j:int::TV(j) && TO(j) && 0 <= j // && addr == ?pciLo + 16*j && addr <= ?pciHi - 16 // && old($pciMem[addr]) == i) // ==> // (exists addr:int, j:int::{TO(j),$pciMem[addr]} TV(j) && 0 <= j // && addr == ?pciLo + 16*j && addr <= ?pciHi - 16 // && $pciMem[addr] == i) ); // assert(forall i:int::{io._pci.PciConfigState[i]} // 0 <= i && i < 65536 && i != $id && // (forall addr:int, j:int::{$pciMem[addr],TV(j)} TV(j) && 0 <= j // && addr == ?pciLo + 16*j && addr <= ?pciHi - 16 // ==> $pciMem[addr] != i) // ==> io._pci.PciConfigState[i] == 0); // // assert(forall i:int::{io._pci.PciConfigState[i]} // 0 <= i && i < 65536 && // (forall addr:int, j:int::{$pciMem[addr],TV(j)} TV(j) && 0 <= j // && addr == ?pciLo + 16*j && addr <= ?pciHi - 16 // ==> $pciMem[addr] != i) // ==> io._pci.PciConfigState[i] == 0); // // // assert IoInv_Transparent($IoVars, $pciMem); // assert &&& &&& &&& NucleusInv(objLayouts, $S, $toAbs, $absMem, GcVars, $Mem_Vars, $stacksFrames, $IoVars); eax := sizeBits; ebx := bar; } } //implementation PciDmaBuffer() //{ // call revealInv1($S, $StackState); // call reveal_IoInv(); // eax := DmaAddr; // if (eax != 0) // { // eax := eax - 8; // } // return; //} // //implementation PciDmaPhysicalAddr() //{ // call revealInv1($S, $StackState); // call reveal_IoInv(); // eax := DmaAddr; // return; //} // //implementation PciMemRead32($id:int, $offset:int) //{ // call revealInv1($S, $StackState); // call reveal_IoInv(); // call fLoad($S, esp); // tie mem into fmem // assert TV($id) && TV(?pciLo) && TO(2 * ecx) && TO(2 * ecx + 1); // // eax := DmaAddr; // if (eax == 0) // { // // IO-MMU not enabled // eax := 0x5555002a; // call debugBreak(); // } // // if (ecx >= 65536) // { // eax := 0x55550027; // call debugBreak(); // } // // ebx := PciLo; // call esi := Load(mems.pci, ebx + 8 * ecx); // if (esi == 0) // { // // $id not yet set up by PciMemSetup // eax := 0x55550028; // call debugBreak(); // } // // call edi := Load(mems.pci, ebx + 8 * ecx + 4); // // eax := edx; // call eax := AddChecked(eax, 4); // if (eax > edi) // { // // $offset out of bounds // eax := 0x55550029; // call debugBreak(); // } // // call eax := PciMemLoad32($id, esi + 1 * edx); // // call fLoad($S, esp); // tie fmem back to mem // return; //} // //implementation PciMemWrite32($id:int, $offset:int, $val:int) //{ // call revealInv1($S, $StackState); // call reveal_IoInv(); // call fLoad($S, esp); // tie mem to fmem // assert TV($id) && TV(?pciLo) && TO(2 * ecx) && TO(2 * ecx + 1); // // assert TO(1) && TV(esp); // call eax := Load(mems.frm/*[$S]*/, esp + 4); // // eax := DmaAddr; // if (eax == 0) // { // // IO-MMU not enabled // eax := 0x5555002b; // call debugBreak(); // } // // if (ecx >= 65536) // { // eax := 0x5555002c; // call debugBreak(); // } // // ebx := PciLo; // call esi := Load(mems.pci, ebx + 8 * ecx); // if (esi == 0) // { // // $id not yet set up by PciMemSetup // eax := 0x5555002d; // call debugBreak(); // } // // call edi := Load(mems.pci, ebx + 8 * ecx + 4); // // eax := edx; // call eax := AddChecked(eax, 4); // if (eax > edi) // { // // $offset out of bounds // eax := 0x5555002e; // call debugBreak(); // } // // call eax := Load(mems.frm/*[$S]*/, esp + 4); // call PciMemStore32($id, esi + 1 * edx, eax); // // call fLoad($S, esp); // tie fmem back to mem // return; //} } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/GC/BitVectorLemmasGc.ifc.beat ================================================ //-private-import BaseSpec; //-private-import MemorySpec; //- //- //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module interface BitVectorLemmasGc { function $Aligned(b:bv32) returns(bool) { $and(b, 3bv32) == 0bv32 } function $bbvec4(a:[int]int, off:int, aBase:int, bb:[int]int, i0:int, i1:int, i2:int, g1:int, g2:int) returns(bool) { (forall i:int::{TV(i)} TV(i) && word(i - i0) && i1 <= i && i < i2 && $Aligned(B(i - i0)) ==> between(g1, g2, g1 + 4 * I($shr(B(i - i0), 7bv32))) && (a[aBase + (i - i0)] == off <==> 0bv32 == $and(B(bb[g1 + 4 * I($shr(B(i - i0), 7bv32))]), $shl(1bv32, $and($shr(B(i - i0), 2bv32), 31bv32))))) } function $bb2vec4(a:[int]int, aBase:int, bb:[int]int, i0:int, i1:int, i2:int, g1:int, g2:int) returns(bool) { (forall i:int::{TV(i)} TV(i) && word(i - i0) && i1 <= i && i < i2 && $Aligned(B(i - i0)) ==> between(g1, g2, g1 + 4 * I($shr(B(i - i0), 6bv32))) && (B(a[aBase + (i - i0)]) == $and( $shr(B(bb[g1 + 4 * I($shr(B(i - i0), 6bv32))]), $and($shr(B(i - i0), 1bv32), 31bv32)), 3bv32 ))) } atomic ghost procedure _aligned($x:bv32); ensures $Aligned($mul(4bv32, $x)); atomic ghost procedure _zeroAligned(); ensures $Aligned(0bv32); atomic ghost procedure _andAligned($x:bv32); ensures $and($x, 3bv32) == 0bv32 <==> $Aligned($x); atomic ghost procedure _addAligned($x:bv32, $y:bv32); ensures $Aligned($x) ==> ($Aligned($y) <==> $Aligned($add($x, $y))); atomic ghost procedure _subAligned($x:bv32, $y:bv32); ensures $Aligned($x) ==> ($Aligned($y) <==> $Aligned($sub($x, $y))); atomic ghost procedure _notAligned($b:bv32); requires $Aligned($b); ensures !$Aligned($add($b, 1bv32)); ensures !$Aligned($add($b, 2bv32)); ensures !$Aligned($add($b, 3bv32)); ensures $le($b, 4294967292bv32); atomic ghost procedure _is4kAligned($x:bv32); ensures $and($sub($x, $and($x, 4095bv32)), 4095bv32) == 0bv32; ensures $le(0bv32, $and($x, 4095bv32)) && $le($and($x, 4095bv32), 4095bv32); atomic ghost procedure _add4kAligned($x:bv32); requires $and($x, 4095bv32) == 0bv32; ensures $and($add($x, 4096bv32), 4095bv32) == 0bv32; ensures $Aligned($x); atomic ghost procedure _is2m4kAligned($x:bv32); ensures $and($sub($add($x, 2097152bv32), $and($x, 2097151bv32)), 4095bv32) == 0bv32; ensures $le(0bv32, $and($x, 2097151bv32)) && $le($and($x, 2097151bv32), 2097151bv32); atomic ghost procedure _initialize($unitSize:bv32); requires $le($unitSize, 16777215bv32); ensures $shr(0bv32, 7bv32) == 0bv32; ensures $shr($mul(128bv32, $unitSize), 7bv32) == $unitSize; ensures $shr($mul(256bv32, $unitSize), 7bv32) == $add($unitSize, $unitSize); atomic ghost procedure _bb4Zero($a:[int]int, $off:int, $aBase:int, $bb:[int]int, $i0:int, $i1:int, $i2:int, $g1:int, $g2:int, $idx:int); requires (forall i:int::{TV(i)} TV(i) && $i1 <= i && i < $i2 + 128 ==> $a[$aBase + (i - $i0)] == $off); requires $bbvec4($a, $off, $aBase, $bb, $i0, $i1, $i2, $g1, $g2); requires $Aligned(B($idx)) && $Aligned(B($g1)); requires B($i2 - $i0) == $mul(32bv32, $sub(B($idx), B($g1))); requires $i1 == $i0; requires $le($shr(B($i2 - $i0), 7bv32), 33554431bv32) && $mul(128bv32, $shr(B($i2 - $i0), 7bv32)) == B($i2 - $i0) ==> $idx - $g1 == 4 * I($shr(B($i2 - $i0), 7bv32)); requires (forall i:int::{TV(i)} TV(i) && $i2 <= i && i < $i2 + 128 ==> $le(B($i2 - $i0), B(i - $i0)) && $le(B(i - $i0), $add(B($i2 - $i0), 127bv32))); requires between($g1, $g2, $idx); requires B(0) == 0bv32; ensures $bbvec4($a, $off, $aBase, $bb[$idx := 0], $i0, $i1, $i2 + 128, $g1, $g2); atomic ghost procedure _bb4GetBit($i0:int, $k:int); ensures $le($and($shr(B($k - $i0), 2bv32), 31bv32), 31bv32); atomic ghost procedure _bb4SetBit($a:[int]int, $on:int, $off:int, $aBase:int, $bb:[int]int, $i0:int, $i1:int, $i2:int, $k:int, $idx:int, $bbb:int, $ret:[int]int, $g1:int, $g2:int); requires $bbvec4($a, $off, $aBase, $bb, $i0, $i1, $i2, $g1, $g2); requires TV($k) && word($k - $i0) && $i1 <= $k && $k < $i2 && $Aligned(B($k - $i0)); requires $on != $off; requires $idx == $g1 + 4 * I($shr(B($k - $i0), 7bv32)); requires B($bbb) == $or(B($bb[$idx]), $shl(1bv32, $and($shr(B($k - $i0), 2bv32), 31bv32))); requires $ret == $bb[$idx := $bbb]; ensures $bbvec4($a[$aBase + ($k - $i0) := $on], $off, $aBase, $ret, $i0, $i1, $i2, $g1, $g2); ensures between($g1, $g2, $idx); ensures $le($and($shr(B($k - $i0), 2bv32), 31bv32), 31bv32); atomic ghost procedure _bb4Zero2($a:[int]int, $aBase:int, $bb:[int]int, $i0:int, $i1:int, $i2:int, $g1:int, $g2:int, $idx:int); requires (forall i:int::{TV(i)} TV(i) && $i1 <= i && i < $i2 + 64 ==> $a[$aBase + (i - $i0)] == 0); requires $bb2vec4($a, $aBase, $bb, $i0, $i1, $i2, $g1, $g2); requires $Aligned(B($idx)) && $Aligned(B($g1)); requires B($i2 - $i0) == $mul(16bv32, $sub(B($idx), B($g1))); requires $i1 == $i0; requires $le($shr(B($i2 - $i0), 6bv32), 67108863bv32) && $mul(64bv32, $shr(B($i2 - $i0), 6bv32)) == B($i2 - $i0) ==> $idx - $g1 == 4 * I($shr(B($i2 - $i0), 6bv32)); requires (forall i:int::{TV(i)} TV(i) && $i2 <= i && i < $i2 + 64 ==> $le(B($i2 - $i0), B(i - $i0)) && $le(B(i - $i0), $add(B($i2 - $i0), 63bv32))); requires between($g1, $g2, $idx); requires B(0) == 0bv32; ensures $bb2vec4($a, $aBase, $bb[$idx := 0], $i0, $i1, $i2 + 64, $g1, $g2); atomic ghost procedure _bb4Get2Bit($i0:int, $k:int); ensures $le($and($shr(B($k - $i0), 1bv32), 31bv32), 31bv32); atomic ghost procedure _bb4Set2Bit($a:[int]int, $val:int, $aBase:int, $bb:[int]int, $i0:int, $i1:int, $i2:int, $k:int, $idx:int, $bbb:int, $_bbb:int, $ret:[int]int, $g1:int, $g2:int); requires $bb2vec4($a, $aBase, $bb, $i0, $i1, $i2, $g1, $g2); requires TV($k) && word($k - $i0) && $i1 <= $k && $k < $i2 && $Aligned(B($k - $i0)); requires $idx == $g1 + 4 * I($shr(B($k - $i0), 6bv32)); requires $le(B($val), 3bv32); requires B($bbb) == $and(B($bb[$idx]), $neg($shl(3bv32, $and($shr(B($k - $i0), 1bv32), 31bv32)))); requires B($_bbb) == $or(B($bbb), $shl(B($val), $and($shr(B($k - $i0), 1bv32), 31bv32))); requires $ret == $bb[$idx := $_bbb]; ensures $bb2vec4($a[$aBase + ($k - $i0) := $val], $aBase, $ret, $i0, $i1, $i2, $g1, $g2); ensures between($g1, $g2, $idx); ensures $le($and($shr(B($k - $i0), 1bv32), 31bv32), 31bv32); atomic ghost procedure _const_gc(); ensures $sub(1bv32, 1bv32) == 0bv32; ensures $add(1bv32, 1bv32) == 2bv32; ensures $add(2bv32, 1bv32) == 3bv32; ensures $add(2bv32, 2bv32) == 4bv32; ensures $add(4bv32, 1bv32) == 5bv32; ensures $add(5bv32, 1bv32) == 6bv32; ensures $add(5bv32, 2bv32) == 7bv32; ensures $mul(4bv32, 4bv32) == 16bv32; ensures $add(16bv32, 16bv32) == 32bv32; ensures $sub(32bv32, 1bv32) == 31bv32; ensures $add(32bv32, 32bv32) == 64bv32; ensures $sub(64bv32, 1bv32) == 63bv32; ensures $mul(32bv32, 4bv32) == 128bv32; ensures $sub(128bv32, 1bv32) == 127bv32; ensures $mul(16bv32, 16bv32) == 256bv32; ensures $add(256bv32, 256bv32) == 512bv32; ensures $mul(64bv32, 64bv32) == 4096bv32; ensures $sub(4096bv32, 1bv32) == 4095bv32; ensures $mul(256bv32, 256bv32) == 65536bv32; ensures $sub(65536bv32, 1bv32) == 65535bv32; ensures $mul(65536bv32, 32bv32) == 2097152bv32; ensures $sub(2097152bv32, 1bv32) == 2097151bv32; ensures $mul(65536bv32, 256bv32) == 16777216bv32; ensures $sub(16777216bv32, 1bv32) == 16777215bv32; ensures $mul(65536bv32, 512bv32) == 33554432bv32; ensures $sub(33554432bv32, 1bv32) == 33554431bv32; ensures $add(33554432bv32, 33554432bv32) == 67108864bv32; ensures $sub(67108864bv32, 1bv32) == 67108863bv32; ensures $mul(65536bv32, 65535bv32) == 4294901760bv32; ensures $add(4294901760bv32, 65535bv32) == 4294967295bv32; ensures $sub(4294967295bv32, 3bv32) == 4294967292bv32; } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/GC/BitVectorLemmasGc.imp.beat ================================================ //-private-import BaseSpec; //-private-import MemorySpec; //- //- //- //- //- //- // TODO change to timeLimitMultiplier. I only needed this flag because I was diddling with a 5-sec timeout in NuBuild. //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module implementation BitVectorLemmasGc { //- This file contains proofs of the declarations in VerifiedBitVectorsBuiltin.bpl. //- Many proofs are totally automatic, so that the implementations below have //- empty bodies. Other proofs require assertions to guide the prover. //- Verification requires the "/bv:z" option to enable Z3 support of bit vectors // Imports: // - TrustedBitVectorsBuiltin.bpl // Exports: // - VerifiedBitVectorsBuiltin.bpl // \Spec#\bin\Boogie.exe /bv:z /noinfer TrustedBitVectorsBuiltin.bpl VerifiedBitVectorsBuiltin.bpl VerifiedBitVectorsBuiltinImpl.bpl implementation _aligned($x:bv32) { } implementation _zeroAligned() { } implementation _andAligned($x:bv32) { } implementation _addAligned($x:bv32, $y:bv32) { } implementation _subAligned($x:bv32, $y:bv32) { } implementation _notAligned($b:bv32) { } implementation _is4kAligned($x:bv32) { } implementation _is2m4kAligned($x:bv32) { } implementation _add4kAligned($x:bv32) { } implementation _initialize($unitSize:bv32) { } implementation _bb4Zero($a:[int]int, $off:int, $aBase:int, $bb:[int]int, $i0:int, $i1:int, $i2:int, $g1:int, $g2:int, $idx:int) { assert $mul(128bv32, $shr(B($i2 - $i0), 7bv32)) == B($i2 - $i0); assert $idx - $g1 == 4 * I($shr(B($i2 - $i0), 7bv32)); assert (forall i:int::{TV(i)} TV(i) && $i2 <= i && i < $i2 + 128 ==> $shr(B(i - $i0), 7bv32) == $shr(B($i2 - $i0), 7bv32)); } implementation _bb4GetBit($i0:int, $k:int) { } implementation _bb4SetBit($a:[int]int, $on:int, $off:int, $aBase:int, $bb:[int]int, $i0:int, $i1:int, $i2:int, $k:int, $idx:int, $bbb:int, $ret:[int]int, $g1:int, $g2:int) { } implementation _bb4Zero2($a:[int]int, $aBase:int, $bb:[int]int, $i0:int, $i1:int, $i2:int, $g1:int, $g2:int, $idx:int) { assert $mul(64bv32, $shr(B($i2 - $i0), 6bv32)) == B($i2 - $i0); assert $idx - $g1 == 4 * I($shr(B($i2 - $i0), 6bv32)); assert (forall i:int::{TV(i)} TV(i) && $i2 <= i && i < $i2 + 64 ==> $shr(B(i - $i0), 6bv32) == $shr(B($i2 - $i0), 6bv32)); assert {:split_here} true; } implementation _bb4Get2Bit($i0:int, $k:int) { } implementation _bb4Set2Bit($a:[int]int, $val:int, $aBase:int, $bb:[int]int, $i0:int, $i1:int, $i2:int, $k:int, $idx:int, $bbb:int, $_bbb:int, $ret:[int]int, $g1:int, $g2:int) { } implementation _const_gc() { } } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/GC/IntLemmasGc.ifc.beat ================================================ //-private-import BaseSpec; //-private-import MemorySpec; //-private-import IntSpec; //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module interface IntLemmasGc { function BitIndex(i0:int, i:int) returns(int); function BitZero(x:int, i0:int, i:int) returns(bool); function ColorIndex(i0:int, i:int) returns(int); function ColorGet(x:int, i0:int, i:int) returns(int); function bbvec4(a:[int]int, off:int, aBase:int, bb:[int]int, i0:int, i1:int, i2:int, g1:int, g2:int) returns(bool) { (forall i:int::{TV(i)} TV(i) && i1 <= i && i < i2 && Aligned(i - i0) ==> between(g1, g2, g1 + BitIndex(i0, i)) && (a[aBase + (i - i0)] == off <==> BitZero(bb[g1 + BitIndex(i0, i)], i0, i)) ) } function bb2vec4(a:[int]int, aBase:int, bb:[int]int, i0:int, i1:int, i2:int, g1:int, g2:int) returns(bool) { (forall i:int::{TV(i)} TV(i) && word(i - i0) && i1 <= i && i < i2 && Aligned(i - i0) ==> between(g1, g2, g1 + ColorIndex(i0, i)) && (a[aBase + (i - i0)] == ColorGet(bb[g1 + ColorIndex(i0, i)], i0, i)) ) } atomic ghost procedure __zeroAligned(); ensures Aligned(0); atomic ghost procedure __andAligned($x:int); ensures word($x) ==> (and($x, 3) == 0 <==> Aligned($x)); atomic ghost procedure __addAligned($x:int, $y:int); ensures word($x) && word($y) && word(add($x, $y)) && Aligned($x) ==> (Aligned($y) <==> Aligned(add($x, $y))); atomic ghost procedure __subAligned($x:int, $y:int); ensures word($x) && word($y) && word(sub($x, $y)) && Aligned($x) ==> (Aligned($y) <==> Aligned(sub($x, $y))); atomic ghost procedure __notAligned($i:int); requires Aligned($i); requires word($i); ensures !Aligned(add($i, 1)); ensures !Aligned(add($i, 2)); ensures !Aligned(add($i, 3)); ensures word(add($i, 1)); ensures word(add($i, 2)); ensures word(add($i, 3)); atomic ghost procedure __is4kAligned($x:int); requires word($x) && word(sub($x, 4096)); ensures and(sub($x, and($x, 4095)), 4095) == 0; ensures le(0, and($x, 4095)) && le(and($x, 4095), 4095); atomic ghost procedure __add4kAligned($x:int); requires and($x, 4095) == 0; requires word($x) && word(add($x, 4096)); ensures and(add($x, 4096), 4095) == 0; ensures Aligned($x); atomic ghost procedure __is2m4kAligned($x:int); requires word($x) && word($x - 2097152) && word($x + 2097152); ensures and(sub(add($x, 2097152), and($x, 2097151)), 4095) == 0; ensures le(0, and($x, 2097151)) && le(and($x, 2097151), 2097151); atomic ghost procedure __initialize($unitSize:int, $heapLo:int); requires word(mul($unitSize, 256)); ensures BitIndex($heapLo, $heapLo) == 0; ensures BitIndex($heapLo, add($heapLo, mul(128, $unitSize))) == mul(4, $unitSize); ensures BitIndex($heapLo, add($heapLo, mul(256, $unitSize))) == mul(8, $unitSize); atomic ghost procedure __bb4Zero($a:[int]int, $off:int, $aBase:int, $bb:[int]int, $i0:int, $i1:int, $i2:int, $g1:int, $g2:int, $idx:int); requires (forall $i:int::{TV($i)} TV($i) && $i1 <= $i && $i < $i2 + 128 ==> $a[$aBase + ($i - $i0)] == $off); requires bbvec4($a, $off, $aBase, $bb, $i0, $i1, $i2, $g1, $g2); requires word($i1 - $i0) && word($i2 - $i0) && word($i2 - $i1) && word($i2 + 128 - $i0); requires word($idx) && word($g1); requires Aligned($idx) && Aligned($g1); requires $i2 - $i1 == mul(32, sub($idx, $g1)); requires $i1 == $i0; requires between($g1, $g2, $idx); ensures bbvec4($a, $off, $aBase, $bb[$idx := 0], $i0, $i1, $i2 + 128, $g1, $g2); atomic ghost procedure __bb4GetBit($a:[int]int, $off:int, $aBase:int, $bb:[int]int, $i0:int, $i1:int, $i2:int, $k:int, $idx:int, $bbb:int, $g1:int, $g2:int); requires bbvec4($a, $off, $aBase, $bb, $i0, $i1, $i2, $g1, $g2); requires TV($k) && word($k - $i0) && $i1 <= $k && $k < $i2 && Aligned($k - $i0); requires $idx == $g1 + 4 * shr($k - $i0, 7); requires $bbb == and($bb[$idx], shl(1, and(shr($k - $i0, 2), 31))); requires word($i1 - $i0) && word($i2 - $i0); ensures between($g1, $g2, $idx); ensures le(and(shr($k - $i0, 2), 31), 31); ensures $bbb == 0 <==> $a[$aBase + ($k - $i0)] == $off; atomic ghost procedure __bb4SetBit($a:[int]int, $on:int, $off:int, $aBase:int, $bb:[int]int, $i0:int, $i1:int, $i2:int, $k:int, $idx:int, $bbb:int, $ret:[int]int, $g1:int, $g2:int); requires bbvec4($a, $off, $aBase, $bb, $i0, $i1, $i2, $g1, $g2); requires TV($k) && word($k - $i0) && $i1 <= $k && $k < $i2 && Aligned($k - $i0); requires $on != $off; requires $idx == $g1 + 4 * shr($k - $i0, 7); requires $bbb == or($bb[$idx], shl(1, and(shr($k - $i0, 2), 31))); requires $ret == $bb[$idx := $bbb]; requires word($i1 - $i0) && word($i2 - $i0); ensures bbvec4($a[$aBase + ($k - $i0) := $on], $off, $aBase, $ret, $i0, $i1, $i2, $g1, $g2); ensures between($g1, $g2, $idx); ensures le(and(shr($k - $i0, 2), 31), 31); ensures 4 * shr($k - $i0, 7) == BitIndex($i0, $k); atomic ghost procedure __bb4Zero2($a:[int]int, $aBase:int, $bb:[int]int, $i0:int, $i1:int, $i2:int, $g1:int, $g2:int, $idx:int); requires (forall $i:int::{TV($i)} TV($i) && $i1 <= $i && $i < $i2 + 64 ==> $a[$aBase + ($i - $i0)] == 0); requires bb2vec4($a, $aBase, $bb, $i0, $i1, $i2, $g1, $g2); requires word($i1 - $i0) && word($i2 - $i0) && word($i2 - $i1) && word($i2 + 64 - $i0); requires word($idx) && word($g1); requires Aligned($idx) && Aligned($g1); requires $i2 - $i1 == mul(16, sub($idx, $g1)); requires $i1 == $i0; requires between($g1, $g2, $idx); ensures bb2vec4($a, $aBase, $bb[$idx := 0], $i0, $i1, $i2 + 64, $g1, $g2); atomic ghost procedure __bb4Get2Bit($a:[int]int, $aBase:int, $bb:[int]int, $i0:int, $i1:int, $i2:int, $k:int, $idx:int, $bbb:int, $g1:int, $g2:int); requires bb2vec4($a, $aBase, $bb, $i0, $i1, $i2, $g1, $g2); requires TV($k) && word($k - $i0) && $i1 <= $k && $k < $i2 && Aligned($k - $i0); requires $idx == $g1 + 4 * shr($k - $i0, 6); requires $bbb == and(shr($bb[$idx], and(shr($k - $i0, 1), 31)), 3); ensures $a[$aBase + ($k - $i0)] == $bbb; ensures between($g1, $g2, $idx); ensures le(and(shr($k - $i0, 1), 31), 31); atomic ghost procedure __bb4Set2Bit($a:[int]int, $val:int, $aBase:int, $bb:[int]int, $i0:int, $i1:int, $i2:int, $k:int, $idx:int, $bbb:int, $_bbb:int, $ret:[int]int, $g1:int, $g2:int); requires bb2vec4($a, $aBase, $bb, $i0, $i1, $i2, $g1, $g2); requires TV($k) && word($k - $i0) && $i1 <= $k && $k < $i2 && Aligned($k - $i0); requires $idx == $g1 + 4 * shr($k - $i0, 6); requires le(0, $val) && le($val, 3); requires $bbb == and($bb[$idx], neg(shl(3, and(shr($k - $i0, 1), 31)))); requires $_bbb == or($bbb, shl($val, and(shr($k - $i0, 1), 31))); requires $ret == $bb[$idx := $_bbb]; ensures bb2vec4($a[$aBase + ($k - $i0) := $val], $aBase, $ret, $i0, $i1, $i2, $g1, $g2); ensures between($g1, $g2, $idx); ensures le(and(shr($k - $i0, 1), 31), 31); ensures 4 * shr($k - $i0, 6) == ColorIndex($i0, $k); } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/GC/IntLemmasGc.imp.beat ================================================ //-private-import BaseSpec; //-private-import MemorySpec; //-private-import IntSpec; //-private-import BitVectorLemmasGc; //- //- //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module implementation IntLemmasGc { function implementation BitIndex(i0:int, i:int):int { 4 * shr(i - i0, 7) } function implementation BitZero(x:int, i0:int, i:int):bool { 0 == and(x, shl(1, and(shr(i - i0, 2), 31))) } function implementation ColorIndex(i0:int, i:int):int { 4 * shr(i - i0, 6) } function implementation ColorGet(x:int, i0:int, i:int):int { and(shr(x, and(shr(i - i0, 1), 31)), 3) } atomic ghost procedure _a($b1:bv32, $b2:bv32) requires word(add(I($b1), I($b2))); ensures add(I($b1), I($b2)) == I($add($b1, $b2)); { } atomic ghost procedure _s($b1:bv32, $b2:bv32) requires word(sub(I($b1), I($b2))); ensures sub(I($b1), I($b2)) == I($sub($b1, $b2)); { } atomic ghost procedure _m($b1:bv32, $b2:bv32) requires word(mul(I($b1), I($b2))); ensures mul(I($b1), I($b2)) == I($mul($b1, $b2)); { } atomic ghost procedure __const() ensures 0 == I(0bv32); ensures 2 == I(2bv32); ensures 3 == I(3bv32); ensures 4 == I(4bv32); ensures 5 == I(5bv32); ensures 6 == I(6bv32); ensures 7 == I(7bv32); ensures 16 == I(16bv32); ensures 32 == I(32bv32); ensures 31 == I(31bv32); ensures 64 == I(64bv32); ensures 63 == I(63bv32); ensures 128 == I(128bv32); ensures 127 == I(127bv32); ensures 256 == I(256bv32); ensures 16777215 == I(16777215bv32); ensures 33554431 == I(33554431bv32); ensures 67108863 == I(67108863bv32); { call _const_gc(); call _s(1bv32, 1bv32); call _a(1bv32, 1bv32); call _a(2bv32, 1bv32); call _a(2bv32, 2bv32); call _a(4bv32, 1bv32); call _a(5bv32, 1bv32); call _a(5bv32, 2bv32); call _m(4bv32, 4bv32); call _a(16bv32, 16bv32); call _s(32bv32, 1bv32); call _a(32bv32, 32bv32); call _s(64bv32, 1bv32); call _m(32bv32, 4bv32); call _s(128bv32, 1bv32); call _m(16bv32, 16bv32); call _a(256bv32, 256bv32); call _m(256bv32, 256bv32); call _s(65536bv32, 1bv32); call _m(65536bv32, 256bv32); call _s(16777216bv32, 1bv32); call _m(65536bv32, 65535bv32); call _m(65536bv32, 512bv32); call _s(33554432bv32, 1bv32); call _a(33554432bv32, 33554432bv32); call _s(67108864bv32, 1bv32); } atomic ghost procedure __const2() ensures 65535 == I(65535bv32); ensures 65536 == I(65536bv32); ensures add(add(2147483647, 2147483647), 1) == I(4294967295bv32); ensures sub(add(2147483647, 2147483647), 2) == I(4294967292bv32); { call __const(); call _const_gc(); call _m(256bv32, 256bv32); call _s(65536bv32, 1bv32); call _m(65536bv32, 65535bv32); call _a(4294901760bv32, 65535bv32); call _s(4294967295bv32, 3bv32); } atomic ghost procedure __const3() ensures 4096 == I(4096bv32); ensures 4095 == I(4095bv32); { call __const(); call _const_gc(); call _m(64bv32, 64bv32); call _s(4096bv32, 1bv32); } atomic ghost procedure __const4() ensures 2097152 == I(2097152bv32); ensures 2097151 == I(2097151bv32); { call __const(); call _const_gc(); call _m(256bv32, 256bv32); call _m(65536bv32, 32bv32); call _s(2097152bv32, 1bv32); } implementation __zeroAligned() { call __const(); call _zeroAligned(); } implementation __andAligned($x:int) { call __const(); call _andAligned(B($x)); } implementation __addAligned($x:int, $y:int) { call __const(); call _addAligned(B($x), B($y)); } implementation __subAligned($x:int, $y:int) { call __const(); call _subAligned(B($x), B($y)); } implementation __notAligned($i:int) { call __const(); call __const2(); call _notAligned(B($i)); assert le($i, 4294967292); } implementation __is4kAligned($x:int) { call __const(); call __const3(); call _is4kAligned(B($x)); assert le(and($x, 4095), 4095); } implementation __is2m4kAligned($x:int) { call __const(); call __const3(); call __const4(); call _is2m4kAligned(B($x)); assert le(and($x, 2097151), 2097151); } implementation __add4kAligned($x:int) { call __const(); call __const3(); call _add4kAligned(B($x)); } atomic ghost procedure helper() ensures (forall b1:bv32, b2:bv32::{$add(b1, b2)} word(add(I(b1), I(b2))) ==> add(I(b1), I(b2)) == I($add(b1, b2))); ensures (forall b1:bv32, b2:bv32::{$sub(b1, b2)} word(sub(I(b1), I(b2))) ==> sub(I(b1), I(b2)) == I($sub(b1, b2))); ensures (forall b1:bv32, b2:bv32::{$mul(b1, b2)} word(mul(I(b1), I(b2))) ==> mul(I(b1), I(b2)) == I($mul(b1, b2))); ensures (forall b1:bv32, b2:bv32::{$le(b1, b2)} le(I(b1), I(b2)) <==> $le(b1, b2)); { } implementation __initialize($unitSize:int, $heapLo:int) { call __const(); call helper(); call _initialize(B($unitSize)); } implementation __bb4Zero($a:[int]int, $off:int, $aBase:int, $bb:[int]int, $i0:int, $i1:int, $i2:int, $g1:int, $g2:int, $idx:int) { call __const(); call helper(); call _bb4Zero($a, $off, $aBase, $bb, $i0, $i1, $i2, $g1, $g2, $idx); } implementation __bb4GetBit($a:[int]int, $off:int, $aBase:int, $bb:[int]int, $i0:int, $i1:int, $i2:int, $k:int, $idx:int, $bbb:int, $g1:int, $g2:int) { call __const(); call _bb4GetBit($i0, $k); } implementation __bb4SetBit($a:[int]int, $on:int, $off:int, $aBase:int, $bb:[int]int, $i0:int, $i1:int, $i2:int, $k:int, $idx:int, $bbb:int, $ret:[int]int, $g1:int, $g2:int) { call __const(); call _bb4SetBit($a, $on, $off, $aBase, $bb, $i0, $i1, $i2, $k, $idx, $bbb, $ret, $g1, $g2); } implementation __bb4Zero2($a:[int]int, $aBase:int, $bb:[int]int, $i0:int, $i1:int, $i2:int, $g1:int, $g2:int, $idx:int) { call __const(); call helper(); call _bb4Zero2($a, $aBase, $bb, $i0, $i1, $i2, $g1, $g2, $idx); } implementation __bb4Get2Bit($a:[int]int, $aBase:int, $bb:[int]int, $i0:int, $i1:int, $i2:int, $k:int, $idx:int, $bbb:int, $g1:int, $g2:int) { call __const(); call _bb4Get2Bit($i0, $k); } implementation __bb4Set2Bit($a:[int]int, $val:int, $aBase:int, $bb:[int]int, $i0:int, $i1:int, $i2:int, $k:int, $idx:int, $bbb:int, $_bbb:int, $ret:[int]int, $g1:int, $g2:int) { call __const(); call helper(); call _bb4Set2Bit($a, $val, $aBase, $bb, $i0, $i1, $i2, $k, $idx, $bbb, $_bbb, $ret, $g1, $g2); } } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/GC/SimpleCollector.ifc.beat ================================================ //-private-import BaseSpec; //-private-import MemorySpec; //-private-import IoTypesSpec; //-private-import MachineStateSpec; //-private-import AssemblySpec; //-private-import InterruptsSpec; //-private-import IoSpec; //- //- //- //- //-private-import Core; //-private-import LogicalAddressing; //-private-import Overflow; //-private-import Util; //-private-import Stacks; //-private-import Partition; //-private-import Instructions; //-private-import Separation; //-private-import IntLemmasGc; //-private-import SimpleGcMemory; //-private-import SimpleCommon; //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module interface SimpleCollector { const ?GcCollector:int := 30; //- Verified copying garbage collector // Includes Spec/NucleusInvCopying_i.beat // Includes Spec/Gc_i.bpl //var $freshAbs:int; //- The allocation bitmap ranges from ?gcLo..HeapLo //- The spaces (from and to) range from HeapLo..?gcHi var HeapLo @ statics; //- Fromspace ranges from Fi to Fl, where Fk..Fl is empty //- Tospace ranges from Ti to Tl, where Tk..Tl is empty var Fi @ statics; var Fk @ statics; var Fl @ statics; var Ti @ statics; var Tj @ statics; var Tk @ statics; var Tl @ statics; //- Bitmaps for fromspace and tospace: var BF @ statics; var BT @ statics; type gcVars = gcVars(freshAbs:int); function gcVarsInv(x:gcVars, m:mem):bool; #define $freshAbs $gcVars.freshAbs #define DECL_GcVars $commonVars:commonVars, $gcVars:gcVars #define GcVars $commonVars, $gcVars #define DECL_AllGcVars DECL_GcVars, $Time:Time #define AllGcVars GcVars, $Time const no_owners:[int]int := (lambda i:int::0); const empty_mem:mem := mem((lambda i:int::0), (lambda i:int::false)); function submems(gc:mem, frm:mem, frms:[int][int]int):mems { mems(empty_mem, empty_mem, empty_mem, gc, frm, frms, empty_mem, (lambda s:int::(lambda i:int::0))) } function _NucleusInv(objLayouts:[int]ObjLayout, $S:int, $toAbs:[int]int, $absMem:[int][int]int, DECL_GcVars, $DECL__MemVars, $stacksFrames:[int]Frames) returns(bool); function NucleusInv(objLayouts:[int]ObjLayout, $S:int, $toAbs:[int]int, $absMem:[int][int]int, DECL_GcVars, $DECL_Mem_Vars, $stacksFrames:[int]Frames, DECL_IoVars) returns(bool) { _NucleusInv(objLayouts, $S, $toAbs, $absMem, GcVars, me, init, statics, submems(mems.gc, mems.frm, mems.frms), $stacksFrames) && IoInv($IoVars, $pciMem) && MemInv($Mem_Vars) } atomic ghost procedure proc_RevealAbssValue(); ensures (forall objLayouts:[int]ObjLayout, $S:int, $toAbs:[int]int, $absMem:[int][int]int, DECL_GcVars, $DECL_Mem_Vars, $stacksFrames:[int]Frames, DECL_IoVars :: NucleusInv(objLayouts, $S, $toAbs, $absMem, GcVars, $Mem_Vars, $stacksFrames, $IoVars) ==> (forall i:int:: StackLo(0) <= i && i < StackHi(0) && Aligned(i) ==> Value(objLayouts, true, $toAbs, $fMems[0][i], $stacksFrames[0].Abss[i]) ) && // Chris tried to write a cleverer trigger than Wellformed's Nuclear Triggerbomb, // but it didn't actually trigger, so we gave up. // (forall i1:int, i2:int::{$stacksFrames[0].Abss[i1], $stacksFrames[0].Abss[i2]} // gcAddr(i1) && gcAddr(i2) && i1 != i2 && $toAbs[i1] != NO_ABS && $toAbs[i2] != NO_ABS // ==> $toAbs[i1] != $toAbs[i2]) WellFormed($toAbs) ); procedure InitializeGc(); inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars; inout $absMem:[int][int]int, $toAbs:[int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout; requires word(ebp); requires SMemRequireRA(112, stk, esp, RET); requires MemInv($Mem_Vars) && commonVarsInv($commonVars, statics); requires IoInv($IoVars, $pciMem); requires (forall i:int::{statics.dom[i]} memAddr(i) && !memAddrMain(i) ==> statics.dom[i]); // requires CurrentStack == $S; // requires (forall $s:int::{TStk($s)} TStk($s) ==> isStack($s) ==> IsEmpty($StackState[$s])); // requires (forall $s:int::{TStk($s)} TStk($s) ==> isStack($s) ==> StackTag($s, $tMems) == ?STACK_EMPTY); requires (forall i:int::{TV(i)} TV(i) ==> $toAbs[i] == NO_ABS); requires (forall $s:int::{TStk($s)} TStk($s) ==> isStack($s) ==> (forall i:int::{TV(i)} TV(i) ==> StackLo($s) <= i && i < StackHi($s) && Aligned(i) ==> $stacksFrames[$s].Abss[i] == 0)); modifies stk, efl, eax, ebx, ecx, edx, esi, edi, ebp, esp; modifies $commonVars, $gcVars, $Time, mems; modifies HeapLo, Fi, Fk, Fl, Ti, Tj, Tk, Tl, BF, BT; ensures SMemEnsure(stk, old(stk), esp, old(esp)); ensures MemInv($Mem_Vars) && commonVarsInv($commonVars, statics); ensures NucleusInv(objLayouts, $S, $toAbs, $absMem, GcVars, $Mem_Vars, $stacksFrames, $IoVars); ensures WellFormed($toAbs); ensures ebp == old(ebp); ghost procedure revealInv1($s:int, $_stackState:[int]StackState); inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars; inout $absMem:[int][int]int, $toAbs:[int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout; requires isStack($s); requires NucleusInv(objLayouts, $S, $toAbs, $absMem, GcVars, $Mem_Vars, $stacksFrames, $IoVars); ensures MemInv($Mem_Vars) && commonVarsInv($commonVars, statics); ensures IoInv($IoVars, $pciMem); ghost procedure updateInv1($oldPciConfigState:[int]int, $oldmem:mems); inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars; inout $absMem:[int][int]int, $toAbs:[int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout; requires NucleusInv(objLayouts, $S, $toAbs, $absMem, GcVars, me, init, stk, statics, core_state, ptMem, $oldmem, $stacksFrames, io.(_pci := io._pci.(PciConfigState := $oldPciConfigState))); requires MemInv($Mem_Vars); requires IoInv($IoVars, $pciMem); requires mems.dat == $oldmem.dat; requires mems.gc == $oldmem.gc; requires mems.frm == $oldmem.frm; requires mems.tcb == $oldmem.tcb; ensures NucleusInv(objLayouts, $S, $toAbs, $absMem, GcVars, $Mem_Vars, $stacksFrames, $IoVars); //- Call the garbage collector. // REVIEW: most system calls will share these preconditions and postconditions, so we should define some more abbreviations procedure GarbageCollect(); inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars; inout $absMem:[int][int]int, $toAbs:[int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout; requires word(ebp); requires NucleusInv(objLayouts, $S, $toAbs, $absMem, GcVars, $Mem_Vars, $stacksFrames, $IoVars); requires SMemRequireRA(212, stk, esp, RET); modifies $r1, $r2, $gcMem, $toAbs, $gcSlice, mems.frm, $fMems, $Time; modifies Ti, Tj, Tk, Tl, Fi, Fk, Fl, BF, BT; modifies efl, eax, ebx, ecx, edx, esi, edi, ebp, esp, stk; //- postcondition same as precondition, plus reached: ensures NucleusInv(objLayouts, $S, $toAbs, $absMem, GcVars, $Mem_Vars, $stacksFrames, $IoVars); ensures (forall i:int::{TV(i)} TV(i) ==> Fi <= i && i < Fk && $toAbs[i] != NO_ABS ==> reached($toAbs[i], $Time)); ensures ebp == old(ebp); ensures SMemEnsure(stk, old(stk), esp, old(esp)); atomic procedure gcFieldProperties(ptr:int, fld:int); inout my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars; inout $absMem:[int][int]int, $toAbs:[int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout; requires isStack($S); requires NucleusInv(objLayouts, $S, $toAbs, $absMem, GcVars, $Mem_Vars, $stacksFrames, $IoVars); requires Pointer($toAbs, ptr, $toAbs[ptr]); requires 0 <= fld && fld < numFields(objLayouts, $toAbs[ptr]); ensures word(ptr + 4 * fld); atomic procedure gcLoadField(x:int, y:opn_mem, ptr:int, fld:int); inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars; inout $absMem:[int][int]int, $toAbs:[int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout; requires isStack($S); requires NucleusInv(objLayouts, $S, $toAbs, $absMem, GcVars, $Mem_Vars, $stacksFrames, $IoVars); requires Pointer($toAbs, ptr, $toAbs[ptr]); requires 0 <= fld && fld < numFields(objLayouts, $toAbs[ptr]); requires EvalPtrOk(y); requires EvalPtr(r, y) == ptr + 4 * fld; modifies r, mems; ensures mems == old(mems); ensures r.regs == old(r).regs[x := r.regs[x]]; ensures r.efl == old(r).efl; ensures word(r.regs[x]); ensures Value(objLayouts, VFieldPtr(objLayouts, $toAbs[ptr], fld), $toAbs, r.regs[x], $absMem[$toAbs[ptr]][fld]); atomic procedure gcStoreField(x:opn_mem, y:opn, ptr:int, fld:int, abs:int); inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars; inout $absMem:[int][int]int, $toAbs:[int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout; requires isStack($S); requires NucleusInv(objLayouts, $S, $toAbs, $absMem, GcVars, me, init, stk, statics, core_state, ptMem, mems, $stacksFrames, $IoVars); requires Pointer($toAbs, ptr, $toAbs[ptr]); requires 0 <= fld && fld < numFields(objLayouts, $toAbs[ptr]); requires !isReadonlyField(0, fld); requires Value(objLayouts, VFieldPtr(objLayouts, $toAbs[ptr], fld), $toAbs, Eval(r, y), abs); requires EvalPtrOk(x); requires EvalPtr(r, x) == ptr + 4 * fld; requires SrcOk(y); modifies mems.gc, $absMem; ensures NucleusInv(objLayouts, $S, $toAbs, $absMem, GcVars, me, init, stk, statics, core_state, ptMem, mems, $stacksFrames, $IoVars); ensures $absMem == old($absMem[$toAbs[ptr] := $absMem[$toAbs[ptr]][fld := abs]]); atomic procedure gcLoadStack(x:int, y:opn_mem, ptr:int); inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars; inout $absMem:[int][int]int, $toAbs:[int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout; requires isStack($S); requires NucleusInv(objLayouts, $S, $toAbs, $absMem, GcVars, $Mem_Vars, $stacksFrames, $IoVars); requires StackLo($S) <= ptr && ptr < StackHi($S); requires Aligned(ptr); requires EvalPtrOk(y); requires EvalPtr(r, y) == ptr; modifies r, mems; ensures mems == old(mems); ensures r.regs == old(r).regs[x := r.regs[x]]; ensures word(r.regs[x]); ensures Value(objLayouts, true, $toAbs, r.regs[x], $stacksFrames[$S].Abss[ptr]); atomic procedure gcStoreStack(x:opn_mem, y:opn, ptr:int, abs:int); inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars; inout $absMem:[int][int]int, $toAbs:[int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout; requires isStack($S); requires NucleusInv(objLayouts, $S, $toAbs, $absMem, GcVars, me, init, stk, statics, core_state, ptMem, mems, $stacksFrames, $IoVars); requires StackLo($S) <= ptr && ptr < StackHi($S); requires Aligned(ptr); requires Value(objLayouts, true, $toAbs, Eval(r, y), abs); requires EvalPtrOk(x); requires EvalPtr(r, x) == ptr; requires SrcOk(y); modifies mems.frm, mems.frms, $stacksFrames; ensures NucleusInv(objLayouts, $S, $toAbs, $absMem, GcVars, me, init, stk, statics, core_state, ptMem, mems, $stacksFrames, $IoVars); ensures $stacksFrames == old($stacksFrames[$S := Frames($stacksFrames[$S].Abss[ptr := abs])]); procedure AllocObject($abs:int, $numWords:int, $numPrimitiveWords:int); inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars; inout $absMem:[int][int]int, $toAbs:[int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout; requires word(ebp); //- GC invariant: requires isStack($S); // && $StackState[$S] == StackRunning; requires NucleusInv(objLayouts, $S, $toAbs, $absMem, GcVars, $Mem_Vars, $stacksFrames, $IoVars); //requires SMemRequireRA(224, stk, esp, RET); requires SMemRequireRA(228, stk, esp, RET); #ifdef x64 requires ReturnToAddr64(stk[esp], stk[esp+4]) == RET; #else requires ReturnToAddr32(stk[esp]) == RET; #endif //- requirements on mutator root layout: requires ScanStackInv($S, $fMems[$S], $stacksFrames, stk[esp], esp, ebp); //- requirements on vtable and layout: requires stk[esp + (4 + IPSize)] == $numWords * 4; requires stk[esp + (8 + IPSize)] == $numPrimitiveWords * 4; requires sAddr(esp + (8 + IPSize)); requires word($numWords * 4); //- require a fresh, empty abstract node: requires $abs != NO_ABS; requires objLayouts[$abs] == NoObjLayout(); requires 2 <= $numPrimitiveWords && $numPrimitiveWords <= $numWords; requires (forall i:int::{TV(i)} TV(i) ==> gcAddr(i) ==> $toAbs[i] != $abs); modifies stk, efl, eax, ebx, ecx, edx, esi, edi, ebp, esp; modifies $absMem, $toAbs, objLayouts; modifies $commonVars, $gcVars, $Time, mems; modifies HeapLo, Fi, Fk, Fl, Ti, Tj, Tk, Tl, BF, BT; ensures SMemEnsureGcF(4, stk, old(stk), esp, old(esp), $stacksFrames, old($stacksFrames)); ensures StackInv($stacksFrames[$S]); ensures NucleusInv(objLayouts, $S, $toAbs, $absMem, GcVars, $Mem_Vars, $stacksFrames, $IoVars); ensures $absMem == old($absMem)[$abs := $absMem[$abs]]; ensures (forall j:int::{TO(j)} $absMem[$abs][j] == if j == 0 then $numPrimitiveWords * 4 else if j == 1 then $numWords * 4 else NULL); // ensures $toAbs == old($toAbs)[eax - 4 := $abs]; // ensures $toAbs[stk[esp] - 4] == $abs; ensures objLayouts == old(objLayouts)[$abs := ObjLayout($numWords, $numPrimitiveWords)]; ensures Pointer($toAbs, stk[esp] - 4, $abs); ensures gcAddrEx(stk[esp]); ensures WellFormed($toAbs); ensures ebp == old(ebp); ensures esp == old(esp) + IPSize; //- note: keep stackGcOffset up to date if ?fLo or ?sLo change; see assertion in Entry.beat //- note: keep stackGcOffset in sync with DafnyCC/RegAlloc.cs, RegAlloc.stackGcOffset const stackGcOffset:int := 0x111000; //- assert ?fLo - ?sLo == stackGcOffset; function frameGet(stacksFrames:[int]Frames, i:int):int { stacksFrames[0].Abss[i] } //- Reserve n bytes of stack space, argRet bytes of argument/return space, and require return address on stack function SMemRequireGcRA(n:int, argRet:int, sMem:mem, $esp:int, $RET:ReturnTo) returns(bool) { SMemRequire(n, sMem, $esp) #ifdef x64 && ?sLo + n <= $esp && $esp + argRet <= ?sHi - 8 && ReturnToAddr64(sMem[$esp], sMem[$esp + 4]) == $RET #else && ?sLo + n <= $esp && $esp + argRet <= ?sHi - 4 && ReturnToAddr32(sMem[$esp]) == $RET #endif } //- Stack contents not altered function SMemInvGc(argRet:int, sMem:mem, oldSMem:mem, $esp:int, oldEsp:int, sAbs:[int]int, oldSAbs:[int]int):bool { $esp == oldEsp && sMem[$esp] == oldSMem[$esp] #ifdef x64 && sMem[$esp + 4] == oldSMem[$esp + 4] #endif && (forall i:int::{sMem[i]} $esp + argRet <= i ==> sMem[i] == oldSMem[i]) && (forall i:int::{sAbs[i]} $esp + argRet + stackGcOffset <= i ==> sAbs[i] == oldSAbs[i]) } function SMemInvGcF(argRet:int, sMem:mem, oldSMem:mem, $esp:int, oldEsp:int, stacksFrames:[int]Frames, oldStacksFrames:[int]Frames):bool { SMemInvGc(argRet, sMem, oldSMem, $esp, oldEsp, stacksFrames[$S].Abss, oldStacksFrames[$S].Abss) } //- Stack contents not altered function SMemEnsureGc(argRet:int, sMem:mem, oldSMem:mem, $esp:int, oldEsp:int, sAbs:[int]int, oldSAbs:[int]int):bool { $esp == oldEsp + IPSize && (forall i:int::{sMem[i]} $esp + argRet <= i ==> sMem[i] == oldSMem[i]) && (forall i:int::{sAbs[i]} $esp + argRet + stackGcOffset <= i ==> sAbs[i] == oldSAbs[i]) } function SMemEnsureGcF(argRet:int, sMem:mem, oldSMem:mem, $esp:int, oldEsp:int, stacksFrames:[int]Frames, oldStacksFrames:[int]Frames):bool { SMemEnsureGc(argRet, sMem, oldSMem, $esp, oldEsp, stacksFrames[$S].Abss, oldStacksFrames[$S].Abss) } function AbsExtend(toAbs:[int]int, oldToAbs:[int]int, objLayouts:[int]ObjLayout, oldObjLayouts:[int]ObjLayout):bool { (forall i:int:: {objLayouts[i]} //{oldObjLayouts[i]} // commented out to slightly improve performance oldObjLayouts[i] != NoObjLayout() ==> oldObjLayouts[i] == objLayouts[i]) } } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/GC/SimpleCollector.imp.beat ================================================ //-private-import BaseSpec; //-private-import MemorySpec; //-private-import IoTypesSpec; //-private-import MachineStateSpec; //-private-import AssemblySpec; //-private-import InterruptsSpec; //-private-import IoSpec; //- //- //- //- //-private-import Core; //-private-import LogicalAddressing; //-private-import Overflow; //-private-import Util; //-private-import Stacks; //-private-import Partition; //-private-import Instructions; //-private-import Separation; //-private-import IntLemmasGc; //-private-import SimpleGcMemory; //-private-import SimpleCommon; //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module implementation SimpleCollector { function implementation gcVarsInv(x:gcVars, m:mem):bool { true && m.dom[&HeapLo] && m.dom[&Fi] && m.dom[&Fk] && m.dom[&Fl] && m.dom[&Ti] && m.dom[&Tj] && m.dom[&Tk] && m.dom[&Tl] && m.dom[&BF] && m.dom[&BT] } //-//////////////////////////////////////////////////////////////////////////// //- COPYING COLLECTOR //-//////////////////////////////////////////////////////////////////////////// function IsFwdPtr(i:int) returns(bool) { i == 0 } function ObjectSpc(objLayouts:[int]ObjLayout, i1:int, i2:int, r:[int]int) returns (bool) { (forall i:int::{TV(i)} TV(i) ==> i1 <= i && i < i2 && r[i] != NO_ABS ==> i + 4 * numFields(objLayouts, r[i]) <= i2 && (forall ii:int::{TV(ii)} TV(ii) ==> i < ii && ii < i + 4 * numFields(objLayouts, r[i]) ==> r[ii] == NO_ABS)) } function ObjectSeq(objLayouts:[int]ObjLayout, i1:int, i2:int, r:[int]int) returns (bool) { (i1 == i2 || r[i1] != NO_ABS) && (forall i:int::{TV(i)} TV(i) ==> i1 <= i && i < i2 && r[i] != NO_ABS ==> (forall ii:int::{TV(ii)} TV(ii) ==> i < ii && ii < i + 4 * numFields(objLayouts, r[i]) ==> r[ii] == NO_ABS) && (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < numFields(objLayouts, r[i]) ==> gcAddr(i + 4 * j)) // REVIEW: necessary? && ( (i + 4 * numFields(objLayouts, r[i]) == i2) || (i + 4 * numFields(objLayouts, r[i]) < i2 && r[i + 4 * numFields(objLayouts, r[i])] != NO_ABS))) } function EmptySeq(i1:int, i2:int, r:[int]int, $toAbs:[int]int) returns (bool) { (forall i:int::{TV(i)} TV(i) ==> i1 <= i && i < i2 ==> gcAddr(i) && r[i] == NO_ABS && $toAbs[i] == NO_ABS) // REVIEW: gcAddr necessary? } //- invariant: //- note: typically, Tj = _tj and Tk = _tk function CopyGcInv(objLayouts:[int]ObjLayout, _tj:int, $Tk:int, _tk:int, $Time:Time, r1Live:bool, $toAbs:[int]int, $absMem:[int][int]int, $DECL__MemVars, $commonVars:commonVars, $gcVars:gcVars ):bool { ?gcLo <= HeapLo && HeapLo <= ?gcHi && ((Fi == HeapLo && Ti == Fl && BF == ?gcLo) || (Ti == HeapLo && Fi == Tl && BT == ?gcLo)) && Fi <= Fk && Fk <= Fl && Fl <= ?gcHi && Ti <= Tj && Tj <= _tj && _tj <= $Tk && $Tk <= _tk && _tk <= Tl && Tl <= ?gcHi && Aligned(Fi) && Aligned(Fk) && Aligned(Ti) && Aligned(Tj) && Aligned($Tk) && WellFormed($toAbs) && ObjectSpc(objLayouts, Fi, Fk, $r1) && EmptySeq( Fk, Fl, $r1, $toAbs) && ObjectSpc(objLayouts, Ti, Tj, $r2) && ObjectSeq(objLayouts, _tj, $Tk, $r2) && EmptySeq( _tk, Tl, $r2, $toAbs) && (forall i:int::{TV(i)} TV(i) ==> gcAddr(i) ==> $toAbs[i] == NO_ABS || $toAbs[i] != $freshAbs) && (forall i:int::{TV(i)} TV(i) ==> gcAddr(i) ==> $r1[i] != NO_ABS && r1Live ==> Fi <= i && i < Fk) && (forall i:int::{TV(i)} TV(i) ==> gcAddr(i) ==> $r2[i] != NO_ABS ==> Ti <= i && i < _tk) && (forall i:int::{TV(i)} TV(i) ==> Fi <= i && i < Fk && $r1[i] != NO_ABS ==> ( IsFwdPtr($gcMem[i]) <==> $toAbs[i] == NO_ABS) && ( IsFwdPtr($gcMem[i]) ==> Pointer($r2, $gcMem[i + 4] - 4, $r1[i]) && AlignedHeapAddr(i + 4) && gcAddrEx($gcMem[i + 4])) && (!IsFwdPtr($gcMem[i]) ==> $toAbs[i] == $r1[i]) && (!IsFwdPtr($gcMem[i]) ==> r1Live ==> ObjInv(objLayouts, i, $r1, $r1, $toAbs, $absMem, $gcMem, $gcSlice)) && (r1Live ==> $gcSlice[i] == i && $gcSlice[i + 4] == i) && i + 4 < Fk // REVIEW: hack? && Aligned(i) // REVIEW: redundant? ) && (forall i:int::{TV(i)} TV(i) ==> Fi <= i && i < Fl && $toAbs[i] != NO_ABS ==> $r1[i] != NO_ABS && $r1[i] != NO_ABS) && (forall i:int::{TV(i)} TV(i) ==> Ti <= i && i < Tl && $toAbs[i] != NO_ABS ==> $r2[i] != NO_ABS && $r2[i] != NO_ABS) && (forall i:int::{TV(i)} TV(i) ==> Ti <= i && i < Tj && $r2[i] != NO_ABS ==> $toAbs[i] != NO_ABS && $toAbs[i] == $r2[i] && reached($toAbs[i], $Time) && ObjInv(objLayouts, i, $r2, $r2, $toAbs, $absMem, $gcMem, $gcSlice) && !IsFwdPtr($gcMem[i]) ) && (Tj != _tj ==> (forall j:int::{TO(j)} TO(j) ==> 0 <= j && Tj + 4 * j < _tj ==> gcAddr(Tj + 4 * j) && $gcSlice[Tj + 4 * j] == Tj)) // REVIEW: gcAddr necessary? && (forall i:int::{TV(i)} TV(i) ==> Tj < i && i < _tj ==> $r2[i] == NO_ABS) && (forall i:int::{TV(i)} TV(i) ==> _tj <= i && i < $Tk && $r2[i] != NO_ABS ==> $toAbs[i] != NO_ABS && $toAbs[i] == $r2[i] && reached($toAbs[i], $Time) && ObjInv(objLayouts, i, $r2, $r1, $toAbs, $absMem, $gcMem, $gcSlice) && !IsFwdPtr($gcMem[i]) ) && commonVarsInv($commonVars, statics) && gcVarsInv($gcVars, statics) } function __NucleusInv(objLayouts:[int]ObjLayout, $toAbs:[int]int, $absMem:[int][int]int, DECL_GcVars, $DECL__MemVars, $stacksFrames:[int]Frames) returns(bool) { ?gcLo <= HeapLo && HeapLo <= ?gcHi && ((Fi == HeapLo && Ti == Fl && BF == ?gcLo) || (Ti == HeapLo && Fi == Tl && BT == ?gcLo)) && Fi <= Fk && Fk <= Fl && Fl <= ?gcHi && Ti <= Tj && Tj <= Tk && Tk <= Tl && Tl <= ?gcHi && Aligned(Fi) && Aligned(Fk) && Aligned(Ti) && Aligned(Tj) && Aligned(Tk) && WellFormed($toAbs) && ObjectSpc(objLayouts, Fi, Fk, $toAbs) && EmptySeq( Fk, Fl, $toAbs, $toAbs) && EmptySeq( Ti, Tl, $toAbs, $toAbs) && (forall i:int::{TV(i)} TV(i) ==> gcAddr(i) ==> $toAbs[i] == NO_ABS || $toAbs[i] != $freshAbs) && (forall i:int::{TV(i)} TV(i) ==> gcAddr(i) ==> ($toAbs[i] != NO_ABS ==> Fi <= i && i < Fk)) && (forall i:int::{TV(i)} TV(i) ==> Fi <= i && i < Fk && $toAbs[i] != NO_ABS ==> $toAbs[i] != NO_ABS && ObjInv(objLayouts, i, $toAbs, $toAbs, $toAbs, $absMem, $gcMem, $gcSlice) && !IsFwdPtr($gcMem[i]) ) && (forall i:int::{TV(i)} TV(i) ==> Fi <= i && i < Fl && $toAbs[i] != NO_ABS ==> $toAbs[i] != NO_ABS) && (forall i:int::{TV(i)} TV(i) ==> Ti <= i && i < Tl && $toAbs[i] != NO_ABS ==> false) && commonVarsInv($commonVars, statics) && gcVarsInv($gcVars, statics) } // REVIEW: this should be shared between collectors function _StateInv(objLayouts:[int]ObjLayout, $s:int, $toAbs:[int]int, $DECL__MemVars, $stacksFrames:[int]Frames) returns(bool) { MutatorStackInv(objLayouts, $s, $toAbs, $stacksFrames[$s], $fMems[$s]) && ScanStackInv($s, $fMems[$s], $stacksFrames, StackRA($s, $tMems, $fMems), StackEsp($s, $tMems), StackEbp($s, $tMems)) } function implementation _NucleusInv(objLayouts:[int]ObjLayout, $S:int, $toAbs:[int]int, $absMem:[int][int]int, DECL_GcVars, $DECL__MemVars, $stacksFrames:[int]Frames) returns(bool) { __NucleusInv(objLayouts, $toAbs, $absMem, GcVars, me, $__MemVars, $stacksFrames) && (forall $s:int::{TStk($s)} TStk($s) ==> isStack($s) ==> _StateInv(objLayouts, $s, $toAbs, me, $__MemVars, $stacksFrames)) } implementation proc_RevealAbssValue() { assert TStk(0); assert (forall objLayouts:[int]ObjLayout, $S:int, $toAbs:[int]int, $absMem:[int][int]int, DECL_GcVars, $DECL_Mem_Vars, $stacksFrames:[int]Frames, DECL_IoVars :: NucleusInv(objLayouts, $S, $toAbs, $absMem, GcVars, $Mem_Vars, $stacksFrames, $IoVars) ==> (forall i:int:: TV(i) ==> StackLo(0) <= i && i < StackHi(0) && Aligned(i) ==> Value(objLayouts, true, $toAbs, $fMems[0][i], $stacksFrames[0].Abss[i]) ) ); } atomic ghost procedure espAligned() inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState; requires Aligned(esp); ensures Aligned(esp - 4) && Aligned(esp - 8) && Aligned(esp - 12) && Aligned(esp - 16); ensures Aligned(esp - 20) && Aligned(esp - 24) && Aligned(esp - 28) && Aligned(esp - 32); ensures Aligned(esp - 36) && Aligned(esp - 40) && Aligned(esp - 44) && Aligned(esp - 48); ensures Aligned(esp - 52) && Aligned(esp - 56) && Aligned(esp - 60) && Aligned(esp - 64); { assert TV(esp) && TO(0-1) && TO(0-2) && TO(0-3) && TO(0-4) && TO(0-5) && TO(0-6) && TO(0-7) && TO(0-8) && TO(0-9) && TO(0-10) && TO(0-11) && TO(0-12) && TO(0-13) && TO(0-14) && TO(0-15) && TO(0-16); } atomic ghost procedure espAlignedInline() inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState; requires Aligned(esp); ensures Aligned(esp + 4) && Aligned(esp + 8) && Aligned(esp + 12) && Aligned(esp + 16); ensures Aligned(esp + 20) && Aligned(esp + 24) && Aligned(esp + 28) && Aligned(esp + 32); ensures Aligned(esp + 36) && Aligned(esp + 40) && Aligned(esp + 44) && Aligned(esp + 48); ensures Aligned(esp + 52) && Aligned(esp + 56) && Aligned(esp + 60) && Aligned(esp + 64); { assert TV(esp) && TO(1) && TO(2) && TO(3) && TO(4) && TO(5) && TO(6) && TO(7) && TO(8) && TO(9) && TO(10) && TO(11) && TO(12) && TO(13) && TO(14) && TO(15) && TO(16); } procedure copyWord($ptr:int, $_tj:int, $ret:int, $ind:int, $s:int) inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars; inout $absMem:[int][int]int, $toAbs:[int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout; requires ecx == $ptr && esi == $ret && edx == 4 * $ind; requires Pointer($r1, $ptr, $r1[$ptr]) && TV($ptr); requires !IsFwdPtr($gcMem[$ptr]); requires $_tj <= Tk; requires $s == 4 * numFields(objLayouts, $r1[$ptr]); requires Tk == $ret + $s; requires Tk <= Tl; requires TO($ind) && 0 <= $ind && $ind < numFields(objLayouts, $r1[$ptr]); requires CopyGcInv(objLayouts, $_tj, $ret, Tk, $Time, true, $toAbs, $absMem, me, $__MemVars, $commonVars, $gcVars); requires MemInv($Mem_Vars); requires (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < $ind ==> gcAddr($ret + 4 * j) && $gcSlice[$ret + 4 * j] == $ret); // REVIEW: gcAddr necessary? requires EmptySeq($ret + 4 * $ind, Tk, $r2, $toAbs); requires (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < $ind ==> Value(objLayouts, VFieldPtr(objLayouts, $r1[$ptr], j), $r1, $gcMem[$ret + 4 * j], $absMem[$toAbs[$ptr]][j])); requires (forall i:int::{TV(i)} TV(i) ==> $ret < i && i < $ret + 4 * $ind ==> $r2[i] == NO_ABS); requires $r2[$ret] == NO_ABS; modifies $gcMem, $gcSlice; modifies efl, eax; ensures CopyGcInv(objLayouts, $_tj, $ret, Tk, $Time, true, $toAbs, $absMem, me, $__MemVars, $commonVars, $gcVars); ensures MemInv($Mem_Vars); ensures (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < $ind + 1 ==> gcAddr($ret + 4 * j) && $gcSlice[$ret + 4 * j] == $ret); // REVIEW: gcAddr necessary? ensures (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < $ind + 1 ==> Value(objLayouts, VFieldPtr(objLayouts, $r1[$ptr], j), $r1, $gcMem[$ret + 4 * j], $absMem[$toAbs[$ptr]][j])); ensures (forall j:int::{TO(j)} TO(j) ==> 0 <= j && Tj + 4 * j < $_tj ==> $gcMem[Tj + 4 * j] == old($gcMem)[Tj + 4 * j] && $gcSlice[Tj + 4 * j] == old($gcSlice[Tj + 4 * j])); ensures RExtend(old($r2), $r2); ensures $Time == old($Time); { call reveal_MemInvDetails(); assert TO(numFields(objLayouts, $r1[$ptr])); assert TV($ret); call eax := Load(mems.gc, ecx + edx); assert TV($ret + 4 * $ind); $gcSlice[$ret + 4 * $ind] := $ret; call Store(inout mems.gc, esi + edx, eax); assert TO(1); } procedure CopyAndForward($ptr:int, $_tj:int) inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars; inout $absMem:[int][int]int, $toAbs:[int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout; requires ecx == $ptr; requires CopyGcInv(objLayouts, $_tj, Tk, Tk, $Time, true, $toAbs, $absMem, me, $__MemVars, $commonVars, $gcVars); requires MemInv($Mem_Vars); requires Pointer($r1, $ptr, $r1[$ptr]) && TV($ptr); requires !IsFwdPtr($gcMem[$ptr]); requires $_tj <= Tk; requires reached($toAbs[$ptr], $Time); requires SMemRequireRA(100, stk, esp, RET); modifies $r2, $gcMem, $toAbs, Tk, $gcSlice; modifies efl, eax, ebx, ecx, edx, esi, esp; modifies stk; ensures CopyGcInv(objLayouts, $_tj, Tk, Tk, $Time, true, $toAbs, $absMem, me, $__MemVars, $commonVars, $gcVars); ensures MemInv($Mem_Vars); ensures RExtend(old($r2), $r2); ensures Pointer($r2, eax, $r1[$ptr]); ensures Tj == old(Tj); ensures Tk >= old(Tk); ensures old($toAbs)[Tj] != NO_ABS ==> $toAbs[Tj] != NO_ABS && $toAbs[Tj] == old($toAbs)[Tj]; ensures (forall j:int::{TO(j)} TO(j) ==> 0 <= j && Tj + 4 * j < $_tj ==> $gcMem[Tj + 4 * j] == old($gcMem)[Tj + 4 * j] && $gcSlice[Tj + 4 * j] == old($gcSlice[Tj + 4 * j])); ensures Ti <= eax && eax < Tk && gcAddrEx(eax + 4); ensures SMemEnsure(stk, old(stk), esp, old(esp)); ensures $Time == old($Time); { call reveal_MemInvDetails(); call ebx := Load(mems.gc, ecx + 4); assert TV($ptr); assert TO(0) && TO(1); assert TO(numFields(objLayouts, $r1[$ptr])); eax := Tk; esi := eax; call eax := AddChecked(eax, ebx); Tk := eax; assert TV(esi); eax := Tl; if (Tk <= eax) { goto skip1; } // out of memory eax := 0x55550031; call DebugBreak(); skip1: var ind:int := 0; edx := 0; // while (edx < ebx) loop: invariant 4 * ind == edx; invariant 4 * numFields(objLayouts, $r1[$ptr]) == ebx; invariant esi == old(Tk); invariant ecx == $ptr; invariant Tk == esi + ebx; invariant TO(ind) && 0 <= ind && ind <= numFields(objLayouts, $r1[$ptr]); invariant CopyGcInv(objLayouts, $_tj, esi, Tk, $Time, true, $toAbs, $absMem, me, $__MemVars, $commonVars, $gcVars); invariant MemInv($Mem_Vars); invariant RExtend(old($r2), $r2); invariant (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < ind ==> gcAddr(esi + 4 * j) && $gcSlice[esi + 4 * j] == esi); // REVIEW: gcAddr necessary? invariant EmptySeq(esi + 4 * ind, Tk, $r2, $toAbs); invariant (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < ind ==> Value(objLayouts, VFieldPtr(objLayouts, $r1[$ptr], j), $r1, $gcMem[esi + 4 * j], $absMem[$toAbs[$ptr]][j])); invariant (forall i:int::{TV(i)} TV(i) ==> esi < i && i < esi + 4 * ind ==> $r2[i] == NO_ABS); invariant (forall j:int::{TO(j)} TO(j) ==> 0 <= j && Tj + 4 * j < $_tj ==> $gcMem[Tj + 4 * j] == old($gcMem)[Tj + 4 * j] && $gcSlice[Tj + 4 * j] == old($gcSlice[Tj + 4 * j])); invariant $r2[esi] == NO_ABS; invariant SMemInv(stk, old(stk), esp, old(esp)); invariant $Time == old($Time); if (edx >= ebx) { goto loopEnd; } call copyWord($ptr, $_tj, esi, ind, ebx); ind := ind + 1; call edx := Add(edx, 4); goto loop; loopEnd: // Set forwarding pointer call eax := Lea(esi + 4); call Store(inout mems.gc, ecx + 0, 0); call Store(inout mems.gc, ecx + 4, eax); eax := esi; $r2[eax] := $r1[$ptr]; $toAbs[eax] := $toAbs[$ptr]; $toAbs[$ptr] := NO_ABS; assert TO(0) && TO(1); assert TV(eax - Ti); Return; } procedure forwardFromspacePtr($ptr:int, $abs:int, $_tj:int) inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars; inout $absMem:[int][int]int, $toAbs:[int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout; requires ecx == $ptr; requires CopyGcInv(objLayouts, $_tj, Tk, Tk, $Time, true, $toAbs, $absMem, me, $__MemVars, $commonVars, $gcVars); requires MemInv($Mem_Vars); requires word($ptr); requires Pointer($r1, $ptr - 4, $abs); requires $_tj <= Tk; requires IsFwdPtr($gcMem[$ptr - 4]) || reached($toAbs[$ptr - 4], $Time); requires SMemRequire(108, stk, esp); modifies $r2, $gcMem, $toAbs, Tk, $gcSlice; modifies efl, eax, ebx, ecx, edx, esi, esp; modifies stk; ensures CopyGcInv(objLayouts, $_tj, Tk, Tk, $Time, true, $toAbs, $absMem, me, $__MemVars, $commonVars, $gcVars); ensures MemInv($Mem_Vars); ensures RExtend(old($r2), $r2); ensures Pointer($r2, eax - 4, $abs); ensures Tj == old(Tj); ensures Tk >= old(Tk); ensures old($toAbs)[Tj] != NO_ABS ==> $toAbs[Tj] != NO_ABS && $toAbs[Tj] == old($toAbs)[Tj]; ensures (forall j:int::{TO(j)} TO(j) ==> 0 <= j && Tj + 4 * j < $_tj ==> $gcMem[Tj + 4 * j] == old($gcMem)[Tj + 4 * j] && $gcSlice[Tj + 4 * j] == old($gcSlice[Tj + 4 * j])); ensures Ti <= eax - 4 && eax - 4 < Tk; ensures gcAddrEx(eax); ensures SMemInv(stk, old(stk), esp, old(esp)); ensures $Time == old($Time); { call reveal_MemInvDetails(); assert TV($ptr - 4); call ecx := Sub(ecx, 4); call eax := Load(mems.gc, ecx); if (eax != 0) { goto skip; } call eax := Load(mems.gc, ecx + 4); goto done; skip: call CopyAndForward($ptr - 4, $_tj); call eax := Add(eax, 4); done: assert TV(eax - 4); } procedure scanObject() inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars; inout $absMem:[int][int]int, $toAbs:[int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout; requires CopyGcInv(objLayouts, Tj, Tk, Tk, $Time, true, $toAbs, $absMem, me, $__MemVars, $commonVars, $gcVars); requires MemInv($Mem_Vars); requires Tj < Tk; requires TV(Tj); requires SMemRequireInline(108, 24, stk, esp); modifies $r2, $gcMem, $toAbs, Tj, Tk, $gcSlice; modifies efl, eax, ebx, ecx, edx, esi, edi, ebp, esp, stk; ensures CopyGcInv(objLayouts, Tj, Tk, Tk, $Time, true, $toAbs, $absMem, me, $__MemVars, $commonVars, $gcVars); ensures MemInv($Mem_Vars); ensures RExtend(old($r2), $r2); ensures SMemInv(stk, old(stk), esp + 24, old(esp) + 24); ensures $Time == old($Time); { call reveal_MemInvDetails(); var $ind:int; var $tj:int := Tj; call espAlignedInline(); assert TO(0); assert TO(1); assert TO(numFields(objLayouts, $r2[Tj])); ebx := Tj; call edi := Load(mems.gc, ebx + 0); //- sizePrimitives call ebp := Load(mems.gc, ebx + 4); //- size $ind := numPrimitiveFields(objLayouts, $r2[$tj]); call edi := Add(edi, ebx); call ebp := Add(ebp, ebx); //while (edi < ebp) loop: invariant $tj == Tj; invariant edi == $tj + 4 * $ind; invariant ebp == $tj + 4 * numFields(objLayouts, $r2[$tj]); invariant TO($ind) && numPrimitiveFields(objLayouts, $r2[$tj]) <= $ind && $ind <= numFields(objLayouts, $r2[$tj]); invariant Pointer($r2, $tj, $r2[$tj]); invariant CopyGcInv(objLayouts, $tj + 4 * numFields(objLayouts, $r2[$tj]), Tk, Tk, $Time, true, $toAbs, $absMem, me, $__MemVars, $commonVars, $gcVars); invariant MemInv($Mem_Vars); invariant RExtend(old($r2), $r2); invariant ObjInvPartial(objLayouts, $tj, 0, $ind, $r2, $r2, $toAbs, $absMem, $gcMem, $gcSlice); invariant ObjInvPartial(objLayouts, $tj, $ind, numFields(objLayouts, $r2[$tj]), $r2, $r1, $toAbs, $absMem, $gcMem, $gcSlice); invariant $toAbs[$tj] != NO_ABS && $toAbs[$tj] == $r2[$tj]; invariant SMemInv(stk, old(stk), esp + 24, old(esp) + 24); invariant $Time == old($Time); invariant TO(0) && TO(1) && TO(2); if (edi >= ebp) { goto loopEnd; } call ecx := Load(mems.gc, edi); //if (gcAddrEx(ecx)) if (ecx < GcLo) { goto skip1; } if (ecx > GcHi) { goto skip1; } assert TV(ecx - 4); call reach($toAbs[Tj], $ind, $Time); call forwardFromspacePtr(ecx, $absMem[$toAbs[Tj]][$ind], ebp); call Store(inout mems.gc, edi, eax); skip1: $ind := $ind + 1; call edi := Add(edi, 4); goto loop; loopEnd: Tj := ebp; } procedure ScanObjects() inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars; inout $absMem:[int][int]int, $toAbs:[int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout; requires CopyGcInv(objLayouts, Tj, Tk, Tk, $Time, true, $toAbs, $absMem, me, $__MemVars, $commonVars, $gcVars); requires MemInv($Mem_Vars); requires SMemRequireRA(132, stk, esp, RET); modifies $r2, $gcMem, $toAbs, Tj, Tk, $gcSlice; modifies efl, eax, ebx, ecx, edx, esi, edi, ebp, esp, stk; ensures CopyGcInv(objLayouts, Tj, Tk, Tk, $Time, true, $toAbs, $absMem, me, $__MemVars, $commonVars, $gcVars); ensures MemInv($Mem_Vars); ensures RExtend(old($r2), $r2); ensures Tj == Tk; ensures SMemEnsure(stk, old(stk), esp, old(esp)); ensures $Time == old($Time); { call espAligned(); call esp := Sub(esp, 24); entry: loop: invariant CopyGcInv(objLayouts, Tj, Tk, Tk, $Time, true, $toAbs, $absMem, me, $__MemVars, $commonVars, $gcVars); invariant MemInv($Mem_Vars); invariant RExtend(old($r2), $r2); invariant SMemInv(stk, old(stk), esp + 24, old(esp)); invariant $Time == old($Time); eax := Tk; if (Tj >= eax) { goto exit; } call scanObject(); goto loop; exit: call esp := Add(esp, 24); Return; } procedure ScanStack($s:int, $ra:int, $nextFp:int) inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars; inout $absMem:[int][int]int, $toAbs:[int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout; requires edi == StackLo($s); requires Aligned(edi); requires isStack($s); // requires ecx == $ra && word($ra); // requires edx == $nextFp && word($nextFp); requires GcStackInv(objLayouts, $s, $r1, $stacksFrames[$s], $fMems[$s]); requires CopyGcInv(objLayouts, Tj, Tk, Tk, $Time, true, $toAbs, $absMem, me, $__MemVars, $commonVars, $gcVars); requires MemInv($Mem_Vars); requires SMemRequireRA(172, stk, esp, RET); modifies $r2, $gcMem, $toAbs, Tk, $gcSlice, mems.frm, $fMems; modifies efl, eax, ebx, ecx, edx, esi, edi, ebp, esp, stk; ensures edi == StackHi($s); ensures Aligned(edi); ensures GcStackInv(objLayouts, $s, $r2, $stacksFrames[$s], $fMems[$s]); ensures CopyGcInv(objLayouts, Tj, Tk, Tk, $Time, true, $toAbs, $absMem, me, $__MemVars, $commonVars, $gcVars); ensures MemInv($Mem_Vars); ensures RExtend(old($r2), $r2); ensures (forall $ss:int::{TStk($ss)} TStk($ss) ==> $ss != $s ==> $fMems[$ss] == old($fMems)[$ss]); ensures SMemEnsure(stk, old(stk), esp, old(esp)); ensures $Time == old($Time); { call reveal_MemInvDetails(); call espAligned(); call esp := Sub(esp, 8); var save1 @ stk[esp + 0]; var save2 @ stk[esp + 4]; var $ind:int := 0; call ebp := Lea(edi + ?FSize); //while (edi < ebp) loop: invariant 0 <= $ind && $ind <= ?fWords; invariant edi == StackLo($s) + 4 * $ind; invariant ebp == StackHi($s); invariant Aligned(edi); invariant CopyGcInv(objLayouts, Tj, Tk, Tk, $Time, true, $toAbs, $absMem, me, $__MemVars, $commonVars, $gcVars); invariant MemInv($Mem_Vars); invariant RExtend(old($r2), $r2); invariant (forall i:int::{TV(i)} TV(i) ==> edi <= i && i < StackHi($s) && Aligned(i) ==> Value(objLayouts, true, $r1, $fMems[$s][i], $stacksFrames[$s].Abss[i])); invariant (forall i:int::{TV(i)} TV(i) ==> StackLo($s) <= i && i < edi && Aligned(i) ==> Value(objLayouts, true, $r2, $fMems[$s][i], $stacksFrames[$s].Abss[i])); invariant SMemInv(stk, old(stk), esp + 8, old(esp)); invariant (forall $ss:int::{TStk($ss)} TStk($ss) ==> $ss != $s ==> $fMems[$ss] == old($fMems)[$ss]); invariant $Time == old($Time); invariant TO($ind) && TV(edi); if (edi >= ebp) { goto loopEnd; } call ecx := Load(mems.frm/*[$s]*/, edi); assert TV(ecx - 4); //if (gcAddrEx(ecx)) if (ecx < GcLo) { goto skip1; } if (ecx > GcHi) { goto skip1; } call reachStackRoot($s, edi, $Time); save1 := edi; save2 := ebp; call forwardFromspacePtr(ecx, $stacksFrames[$s].Abss[edi], Tj); edi := save1; ebp := save2; $fMems[$s][edi] := eax; call Store(inout mems.frm/*[$s]*/, edi, eax); skip1: assert TV(edi) && TO(1); $ind := $ind + 1; call __notAligned(edi); call edi := Add(edi, 4); goto loop; loopEnd: call esp := Add(esp, 8); Return; } procedure ScanStacks() inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars; inout $absMem:[int][int]int, $toAbs:[int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout; requires CopyGcInv(objLayouts, Tj, Tk, Tk, $Time, true, $toAbs, $absMem, me, $__MemVars, $commonVars, $gcVars); requires MemInv($Mem_Vars); //requires SMemRequireRA(188, stk, esp, RET); requires SMemRequireRA(192, stk, esp, RET); requires (forall $s:int::{TStk($s)} TStk($s) ==> isStack($s) ==> _StateInv(objLayouts, $s, $r1, me, $__MemVars, $stacksFrames)); modifies $r2, $gcMem, $toAbs, Tk, $gcSlice, mems.frm, $fMems; modifies efl, eax, ebx, ecx, edx, esi, edi, ebp, esp, stk; ensures CopyGcInv(objLayouts, Tj, Tk, Tk, $Time, true, $toAbs, $absMem, me, $__MemVars, $commonVars, $gcVars); ensures MemInv($Mem_Vars); ensures RExtend(old($r2), $r2); ensures SMemEnsure(stk, old(stk), esp, old(esp)); ensures (forall $s:int::{TStk($s)} TStk($s) ==> isStack($s) ==> _StateInv(objLayouts, $s, $r2, me, $__MemVars, $stacksFrames)); ensures $Time == old($Time); { call reveal_MemInvDetails(); call espAligned(); call esp := Sub(esp, 12); var s @ stk[esp + 0] := 0; edi := FLo; while (s < ?NumStacks) invariant 0 <= s && TStk(s); invariant CopyGcInv(objLayouts, Tj, Tk, Tk, $Time, true, $toAbs, $absMem, me, $__MemVars, $commonVars, $gcVars); invariant MemInv($Mem_Vars); invariant RExtend(old($r2), $r2); invariant SMemInv(stk, old(stk), esp + 12, old(esp)); invariant (forall $s:int::{TStk($s)} TStk($s) ==> isStack($s) && s <= $s ==> _StateInv(objLayouts, $s, $r1, me, $__MemVars, $stacksFrames)); invariant (forall $s:int::{TStk($s)} TStk($s) ==> isStack($s) && s > $s ==> _StateInv(objLayouts, $s, $r2, me, $__MemVars, $stacksFrames)); invariant $Time == old($Time); invariant edi == StackLo(s); invariant Aligned(edi); { assert TStk($S) && TV(?sLo) && TO(512 + 65536 * 2 + 64 * s) && TO(512 + 65536 * 2 + 64 * s + 1) && TO(512 + 65536 * 2 + 64 * s + 2); call ScanStack(s, StackRA(s, $tMems, $fMems), StackEbp(s, $tMems)); eax := s; call eax := Add(eax, 1); s := eax; } call esp := Add(esp, 12); Return; } procedure __garbageCollect() inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars; inout $absMem:[int][int]int, $toAbs:[int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout; requires word(ebp); requires _NucleusInv(objLayouts, $S, $toAbs, $absMem, GcVars, me, $__MemVars, $stacksFrames); requires MemInv($Mem_Vars); //requires SMemRequireInline(196, 4, stk, esp); requires SMemRequireInline(200, 4, stk, esp); requires IoInv($IoVars, $pciMem); modifies $r1, $r2, $gcMem, $toAbs, $gcSlice, mems.frm, $fMems, $Time; modifies Ti, Tj, Tk, Tl, Fi, Fk, Fl, BF, BT; modifies efl, eax, ebx, ecx, edx, esi, edi, ebp, esp, stk; // postcondition same as precondition, plus reached: ensures NucleusInv(objLayouts, $S, $toAbs, $absMem, GcVars, $Mem_Vars, $stacksFrames, $IoVars); ensures (forall i:int::{TV(i)} TV(i) ==> Fi <= i && i < Fk && $toAbs[i] != NO_ABS ==> reached($toAbs[i], $Time)); ensures ebp == old(ebp); ensures SMemInv(stk, old(stk), esp + 4, old(esp) + 4); { call reveal_MemInvDetails(); call espAlignedInline(); var saveEbp @ stk[esp + 0] := ebp; call newTime(); $r1 := $toAbs; $r2 := (lambda i:int::NO_ABS); eax := Ti; Tj := eax; Tk := eax; eax := BT; ebx := Fi; if (ebx != HeapLo) { goto skip1; } ebx := HeapLo; goto skip2; skip1: ebx := BF; skip2: call ScanStacks(); call ScanObjects(); $toAbs := $r2; eax := Fi; ebx := Ti; Fi := ebx; Ti := eax; eax := Fl; ebx := Tl; Fl := ebx; Tl := eax; eax := Tk; Fk := eax; eax := Ti; Tk := eax; Tj := eax; eax := BF; ebx := BT; BF := ebx; BT := eax; ebp := saveEbp; } implementation GarbageCollect() { call espAligned(); call esp := Sub(esp, 12); call __garbageCollect(); call esp := Add(esp, 12); Return; } procedure doAllocCopyingWord($ret:int, $ind:int) inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars; inout $absMem:[int][int]int, $toAbs:[int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout; requires esi == $ret + 4 * $ind; requires TO($ind) && $ind >= 0; requires Aligned($ret) && Fk <= $ret && $ret + 4 * $ind + 4 <= Fl; requires __NucleusInv(objLayouts, $toAbs, $absMem, GcVars, me, $__MemVars, $stacksFrames); requires MemInv($Mem_Vars); requires (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < $ind ==> $gcSlice[$ret + 4 * j] == $ret); requires (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < $ind ==> gcAddr($ret + 4 * j)); // REVIEW: necessary? requires (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < $ind ==> $gcMem[$ret + 4 * j] == NULL); modifies efl, $gcMem, $gcSlice; ensures __NucleusInv(objLayouts, $toAbs, $absMem, GcVars, me, $__MemVars, $stacksFrames); ensures MemInv($Mem_Vars); ensures (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < $ind + 1 ==> $gcSlice[$ret + 4 * j] == $ret); ensures (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < $ind + 1 ==> gcAddr($ret + 4 * j)); // REVIEW: necessary? ensures (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < $ind + 1 ==> $gcMem[$ret + 4 * j] == NULL); ensures $Time == old($Time); { call reveal_MemInvDetails(); assert TV($ret); assert TV($ret + 4 * $ind);// && TV($ret + 4 * $ind + 1) && TV($ret + 4 * $ind + 2) && TV($ret + 4 * $ind + 3); $gcSlice[$ret + 4 * $ind] := $ret; call Store(inout mems.gc, esi, 0); } procedure doAllocCopyingWords($ret:int, $size:int, $nf:int) inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars; inout $absMem:[int][int]int, $toAbs:[int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout; requires eax == $ret; requires ebx == $ret + $size; requires $size == $nf * 4; requires $nf >= 0; requires __NucleusInv(objLayouts, $toAbs, $absMem, GcVars, me, $__MemVars, $stacksFrames); requires MemInv($Mem_Vars); requires Aligned($ret) && Fk <= $ret && $ret + $size <= Fl; modifies $gcMem, $gcSlice; modifies efl, esi; ensures __NucleusInv(objLayouts, $toAbs, $absMem, GcVars, me, $__MemVars, $stacksFrames); ensures MemInv($Mem_Vars); ensures (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < $nf ==> $gcSlice[$ret + 4 * j] == $ret); ensures (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < $nf ==> gcAddr($ret + 4 * j)); // REVIEW: necessary? ensures (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < $nf ==> $gcMem[$ret + 4 * j] == NULL); ensures ebp == old(ebp); ensures $Time == old($Time); { call reveal_MemInvDetails(); var $ind:int; $ind := 0; esi := eax; //while (4 * $ind < $size) if (esi >= ebx) { goto loopEnd; } loop: invariant 4 * $ind < $size; invariant esi == $ret + 4 * $ind; invariant TO($ind) && $ind >= 0; invariant __NucleusInv(objLayouts, $toAbs, $absMem, GcVars, me, $__MemVars, $stacksFrames); invariant MemInv($Mem_Vars); invariant (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < $ind ==> $gcSlice[$ret + 4 * j] == $ret); invariant (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < $ind ==> gcAddr($ret + 4 * j)); // REVIEW: necessary? invariant (forall j:int::{TO(j)} TO(j) ==> 0 <= j && j < $ind ==> $gcMem[$ret + 4 * j] == NULL); invariant $Time == old($Time); call doAllocCopyingWord($ret, $ind); $ind := $ind + 1; call esi := Add(esi, 4); if (esi < ebx) { goto loop; } loopEnd: } procedure doAllocObjectCopying($nextFp:int, $abs:int, $size:int, $sizePrimitives:int) inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars; inout $absMem:[int][int]int, $toAbs:[int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout; requires ebx == Fk + $size; requires ecx == $size; requires edx == $sizePrimitives; requires Fk + 4 * numFields(objLayouts, $abs) <= Fl; requires !VFieldPtr(objLayouts, $abs, 0); requires !VFieldPtr(objLayouts, $abs, 1); requires 2 <= numFields(objLayouts, $abs); requires $size == 4 * numFields(objLayouts, $abs); requires ObjSize(objLayouts, $abs, $size, $absMem[$abs][0]); requires _NucleusInv(objLayouts, $S, $toAbs, $absMem, GcVars, me, $__MemVars, $stacksFrames); requires MemInv($Mem_Vars); //- requirements on vtable and layout: requires word($size); requires VTable(objLayouts, $abs, $size); requires ObjSize(objLayouts, $abs, $size, $sizePrimitives); //- require a fresh, empty abstract node: requires $abs != NO_ABS; requires (forall i:int::{TV(i)} TV(i) ==> gcAddr(i) ==> $toAbs[i] != $abs); requires $absMem[$abs][0] == $sizePrimitives; requires $absMem[$abs][1] == $size; requires (forall j:int::{TO(j)} TO(j) ==> 2 <= j && j < numFields(objLayouts, $abs) ==> $absMem[$abs][j] == NULL); requires IoInv($IoVars, $pciMem); modifies $gcMem, $toAbs, $gcSlice, Fk, $freshAbs; modifies efl, eax, ebx, ecx, edx, esi, edi, ebp; ensures NucleusInv(objLayouts, $S, $toAbs, $absMem, GcVars, $Mem_Vars, $stacksFrames, $IoVars); ensures old($toAbs)[eax - 4] == NO_ABS; ensures $toAbs == old($toAbs)[eax - 4 := $abs]; ensures Pointer($toAbs, eax - 4, $abs); ensures eax == old(Fk) + 4; ensures ebp == old(ebp); { call reveal_MemInvDetails(); eax := Fk; assert TV(eax + 0) && TV(eax + 4); assert TO(0) && TO(1) && TO(2); assert TO(numFields(objLayouts, $abs)); call doAllocCopyingWords(eax, $size, numFields(objLayouts, $abs)); call Store(inout mems.gc, eax + 0, edx); call Store(inout mems.gc, eax + 4, ecx); assert TV(Fk - Fi); $toAbs[eax] := $abs; assert TV(Fk); assert TO(numFields(objLayouts, $abs)); Fk := ebx; call eax := Add(eax, 4); assert TV(eax + 4); assert TO(0); $freshAbs := NO_ABS; } implementation InitializeGc() { call reveal_MemInvDetails(); call espAligned(); call esp := Sub(esp, 8); var save @ stk[esp + 0] := ebp; var unitSize @ stk[esp + 4]; ecx := FLo; eax := 0; loop1: invariant 0 <= eax && eax <= ?NumStacks; invariant ecx == StackLo(eax); invariant Aligned(ecx); invariant (forall $s:int::{TStk($s)} TStk($s) ==> 0 <= $s && $s < eax ==> (forall i:int::{TV(i)} TV(i) ==> StackLo($s) <= i && i < StackHi($s) && Aligned(i) ==> $fMems[$s][i] == 0)); invariant logical_addressing_inv(init, ptMem, core_state); invariant SMemInv(stk, old(stk), esp + 8, old(esp)); invariant MemInv($Mem_Vars) && commonVarsInv($commonVars, statics); invariant stk[esp + 0] == old(ebp); invariant IoInv($IoVars, $pciMem); if (eax >= ?NumStacks) { goto end1; } // for 0 <= $ind < ?fWords ebx := 0; var $ind:int := 0; loop2: invariant 0 <= eax && eax < ?NumStacks; invariant 0 <= $ind && $ind <= ?fWords; invariant ebx == 4 * $ind; invariant ecx == StackLo(eax) + 4 * $ind; invariant Aligned(ecx); invariant (forall $s:int::{TStk($s)} TStk($s) ==> 0 <= $s && $s <= eax ==> (forall i:int::{TV(i)} TV(i) ==> Aligned(i) && StackLo(eax) <= i && (i < (if $s < eax then StackHi(eax) else ecx)) ==> $fMems[$s][i] == 0)); invariant logical_addressing_inv(init, ptMem, core_state); invariant SMemInv(stk, old(stk), esp + 8, old(esp)); invariant MemInv($Mem_Vars) && commonVarsInv($commonVars, statics); invariant stk[esp + 0] == old(ebp); invariant IoInv($IoVars, $pciMem); assert ?fWords == 1024; if (ebx >= ?FSize) { goto end2; } $fMems[eax][ecx] := 0; call Store(inout mems.frm/*[eax]*/, ecx, 0); assert TV(ecx) && TO(1); $ind := $ind + 1; call __notAligned(ecx); ebx := ebx + 4; ecx := ecx + 4; goto loop2; end2: eax := eax + 1; goto loop1; end1: //- Compute gcMem size, in bytes and words esi := GcHi; call esi := SubLoad(statics, esi, GcLo); edi := esi; //- Break into 256-byte units. Let ebp be the number of units. edx := 0; eax := edi; ebx := 256; call eax, edx := Div(eax, edx, ebx); ebp := eax; unitSize := ebp; assert 256 * unitSize <= (?gcHi - ?gcLo); //- Divide heap into ?gcLo = ebx <--128--> ecx <--128--> ?gcHi edx := 0; call ebp := Lea(edx + 4 * ebp); eax := GcLo; BF := eax; BT := eax; ebx := eax; call ebp := Lea(edx + 4 * ebp); call ecx := Lea(ebx + 8 * ebp); call edx := Lea(ecx + 8 * ebp); HeapLo := ebx; Fi := ebx; Fk := ebx; Fl := ecx; Ti := ecx; Tj := ecx; Tk := ecx; Tl := edx; call __initialize(unitSize, HeapLo); assert TV(?gcLo); assert TV(HeapLo); assert TO(0); assert TO(unitSize); assert TO(2 * unitSize); assert TO(32 * unitSize); eax := GcLo; esi := unitSize; call ebx := Lea(eax + 4 * esi); $freshAbs := NO_ABS; ebp := save; call esp := Add(esp, 8); Return; } implementation revealInv1($s:int, $_stackState:[int]StackState) { assert TStk($s); } implementation updateInv1($oldPciConfigState:[int]int, $oldmem:mems) { call reveal_MemInvDetails(); } implementation gcFieldProperties(ptr:int, fld:int) { call reveal_MemInvDetails(); assert TV(ptr) && TO(fld); } implementation gcLoadField(x:int, y:opn_mem, ptr:int, fld:int) { call reveal_MemInvDetails(); assert TV(ptr) && TO(fld); call logical_Load(inout r, core_state, mems.gc, x, y); } implementation gcStoreField(x:opn_mem, y:opn, ptr:int, fld:int, abs:int) { call reveal_MemInvDetails(); assert TVL($toAbs[ptr]); assert TV(Eval(r, y)) && TV(ptr); assert TO(fld); call logical_Store(r, core_state, inout mems.gc, x, y); $absMem := $absMem[$toAbs[ptr] := $absMem[$toAbs[ptr]][fld := abs]]; } implementation gcLoadStack(x:int, y:opn_mem, ptr:int) { call reveal_MemInvDetails(); assert TStk($S) && TV(ptr); call logical_Load(inout r, core_state, mems.frm, x, y); } implementation gcStoreStack(x:opn_mem, y:opn, ptr:int, abs:int) { call reveal_MemInvDetails(); assert TStk($S) && TV(ptr); call logical_Store(r, core_state, inout mems.frm, x, y); $fMems[$S][ptr] := Eval(r, y); $stacksFrames := $stacksFrames[$S := Frames($stacksFrames[$S].Abss[ptr := abs])]; } implementation AllocObject($abs:int, $numWords:int, $numPrimitiveWords:int) { assert TV(esp) && TO(0) && TO(1) && TO(2) && TO(3); #ifdef x64 assert TO(4); #endif #ifdef x64 call ecx := Load(stk, esp + 12); call edx := Load(stk, esp + 16); #else call ecx := Load(stk, esp + 8); call edx := Load(stk, esp + 12); #endif $freshAbs := $abs; objLayouts[$abs] := ObjLayout($numWords, $numPrimitiveWords); $absMem[$abs] := (lambda i:int::if i == 0 then $numPrimitiveWords * 4 else if i == 1 then $numWords * 4 else NULL); ebx := Fk; call ebx := AddChecked(ebx, ecx); //if (!(Fk + size <= Fl)) if (ebx <= Fl) { goto skip1; } call GarbageCollect(); //- try one more time #ifdef x64 call ecx := Load(stk, esp + 12); call edx := Load(stk, esp + 16); #else call ecx := Load(stk, esp + 8); call edx := Load(stk, esp + 12); #endif ebx := Fk; call ebx := AddChecked(ebx, ecx); if (ebx <= Fl) { goto skip1; } eax := 0x5555feed; // out of memory call debugBreak(); skip1: call doAllocObjectCopying(ebp, $abs, $numWords * 4, $numPrimitiveWords * 4); #ifdef x64 call Store(inout stk, esp + 8, eax); #else call Store(inout stk, esp + 4, eax); #endif Return; } } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/GC/SimpleCommon.ifc.beat ================================================ //-private-import BaseSpec; //-private-import MemorySpec; //-private-import IoTypesSpec; //-private-import MachineStateSpec; //-private-import AssemblySpec; //-private-import InterruptsSpec; //-private-import IoSpec; //- //- //- //- //-private-import Core; //-private-import LogicalAddressing; //-private-import Overflow; //-private-import Util; //-private-import Stacks; //-private-import Partition; //-private-import Instructions; //-private-import Separation; //-private-import IntLemmasGc; //-private-import SimpleGcMemory; //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module interface SimpleCommon { const ?GcCommon:int := 20; //- Common definitions and procedures shared between garbage collectors. //- This file is included by the garbage collectors. // Imports: // - Trusted_i.bpl // - VerifiedBitVectors_i.bpl /***************************************************************************** ****************************************************************************** **** VERIFIED ****************************************************************************** *****************************************************************************/ function AlignedHeapAddr(i:int):bool { gcAddr(i) && Aligned(i) } //-//////////////////////////////////////////////////////////////////////////// //- LOCAL REASONING //-//////////////////////////////////////////////////////////////////////////// //- As a region evolves, it adds new mappings, but each mapping is //- permanent: RExtend ensures that new mappings do not overwrite old mappings. function RExtend(rOld:[int]int, rNew:[int]int):bool { (forall i:int::{rOld[i]}{rNew[i]} rOld[i] != NO_ABS ==> rOld[i] == rNew[i]) } function AbsMapped(val:int, rev:[int]int, abs:int):bool { abs != NO_ABS && abs == rev[val] } // Both the mark-sweep and copying collectors only have two regions at // any given time. //var $r1:[int]int; //var $r2:[int]int; //-//////////////////////////////////////////////////////////////////////////// //- STACKS //-//////////////////////////////////////////////////////////////////////////// // TODO: clean up, move to right file function{:expand true} TStk($s:int) returns(bool) { true } // TODO: expand false //var $stackState:[int]StackState; var CurrentStack @ statics; type commonVars = commonVars(r1:[int]int, r2:[int]int, stackState:[int]StackState, gcSlice:[int]int); function commonVarsInv(x:commonVars, m:mem):bool { m.dom[&CurrentStack] } #define $r1 $commonVars.r1 #define $r2 $commonVars.r2 #define $stackState $commonVars.stackState #define $gcSlice $commonVars.gcSlice atomic procedure initCommon(); inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $toAbs:[int]int; requires (forall i:int::{statics.dom[i]} memAddr(i) && !memAddrMain(i) ==> statics.dom[i]); modifies $commonVars; ensures commonVarsInv($commonVars, statics); function StackTag(s:int, tMems:[int][int]int) returns(int) { tMems[s][?tLo + s * ?TSize + 0] } function StackEsp(s:int, tMems:[int][int]int) returns(int) { tMems[s][?tLo + s * ?TSize + 4] } function StackEbp(s:int, tMems:[int][int]int) returns(int) { tMems[s][?tLo + s * ?TSize + 8] } function StackEax(s:int, tMems:[int][int]int) returns(int) { tMems[s][?tLo + s * ?TSize + 12] } function StackEbx(s:int, tMems:[int][int]int) returns(int) { tMems[s][?tLo + s * ?TSize + 16] } function StackEcx(s:int, tMems:[int][int]int) returns(int) { tMems[s][?tLo + s * ?TSize + 20] } function StackEdx(s:int, tMems:[int][int]int) returns(int) { tMems[s][?tLo + s * ?TSize + 24] } function StackEsi(s:int, tMems:[int][int]int) returns(int) { tMems[s][?tLo + s * ?TSize + 28] } function StackEdi(s:int, tMems:[int][int]int) returns(int) { tMems[s][?tLo + s * ?TSize + 32] } function StackRA(s:int, tMems:[int][int]int, fMems:[int][int]int) returns(int) { fMems[s][StackEsp(s, tMems)] } function StackCS(s:int, tMems:[int][int]int, fMems:[int][int]int) returns(int) { fMems[s][StackEsp(s, tMems) + 4] } function StackEfl(s:int, tMems:[int][int]int, fMems:[int][int]int) returns(int) { fMems[s][StackEsp(s, tMems) + 8] } function IsEmpty($state:StackState) returns(bool) { StackStateTag($state) == ?STACK_EMPTY } function IsYielded($state:StackState) returns(bool) { StackStateTag($state) == ?STACK_YIELDED } function IsInterrupted($state:StackState) returns(bool) { StackStateTag($state) == ?STACK_INTERRUPTED } function MutatorStackInv(objLayouts:[int]ObjLayout, $s:int, r:[int]int, $Frames:Frames, $fMem:[int]int) returns(bool) { (forall i:int::{TV(i)} TV(i) ==> StackLo($s) <= i && i < StackHi($s) && Aligned(i) ==> Value(objLayouts, true, r, $fMem[i], $Frames.Abss[i]) ) } function GcStackInv(objLayouts:[int]ObjLayout, $s:int, r:[int]int, $Frames:Frames, $fMem:[int]int) returns(bool) { StackInv($Frames) && MutatorStackInv(objLayouts, $s, r, $Frames, $fMem) } //-//////////////////////////////////////////////////////////////////////////// //- OBJECTS //-//////////////////////////////////////////////////////////////////////////// //- Each object occupies a "slice" of the heap. If an object occupies //- addresses i + 0 ... i + m, then slice[i + 0] == i && ... && slice[i + m] == i. //- This helps distinguish addresses that belong to different objects. //var $gcSlice:[int]int; // REVIEW: cut $toAbs here? function ObjInvBase(objLayouts:[int]ObjLayout, i:int, rs:[int]int, $toAbs:[int]int, $absMem:[int][int]int, gcMem:mem, gcSlice:[int]int):bool { gcAddr(i) && rs[i] != NO_ABS ==> Aligned(i) && AlignedHeapAddr(i + 4) // REVIEW: this is convenient, but is it necessary? && VTable(objLayouts, rs[i], $absMem[rs[i]][1]) && !VFieldPtr(objLayouts, rs[i], 1) // REVIEW: necessary? && numFields(objLayouts, rs[i]) >= 2 // REVIEW: necessary? && ObjSize(objLayouts, rs[i], $absMem[rs[i]][1], $absMem[rs[i]][0]) && gcSlice[i] == i && gcSlice[i + 4] == i // REVIEW: this is convenient, but is it necessary? } function ObjInvField(objLayouts:[int]ObjLayout, i:int, j:int, rs:[int]int, rt:[int]int, $toAbs:[int]int, $absMem:[int][int]int, gcMem:mem, gcSlice:[int]int):bool { gcAddr(i) && rs[i] != NO_ABS ==> gcAddr(i + 4 * j) // REVIEW: necessary? && gcSlice[i + 4 * j] == i && Value(objLayouts, VFieldPtr(objLayouts, rs[i], j), rt, gcMem[i + 4 * j], $absMem[$toAbs[i]][j]) } function ObjInvPartial(objLayouts:[int]ObjLayout, i:int, j1:int, j2:int, rs:[int]int, rt:[int]int, $toAbs:[int]int, $absMem:[int][int]int, gcMem:mem, gcSlice:[int]int):bool { ObjInvBase(objLayouts, i, rs, $toAbs, $absMem, gcMem, gcSlice) && (forall j:int::{TO(j)} TO(j) ==> j1 <= j && j < j2 ==> ObjInvField(objLayouts, i, j, rs, rt, $toAbs, $absMem, gcMem, gcSlice)) } function ObjInv(objLayouts:[int]ObjLayout, i:int, rs:[int]int, rt:[int]int, $toAbs:[int]int, $absMem:[int][int]int, gcMem:mem, gcSlice:[int]int) returns (bool) { ObjInvPartial(objLayouts, i, 0, numFields(objLayouts, rs[i]), rs, rt, $toAbs, $absMem, gcMem, gcSlice) } //-//////////////////////////////////////////////////////////////////////////// //- STATE //-//////////////////////////////////////////////////////////////////////////// function IoInv(DECL_IoVars, pciMem:mem):bool; // { true } //function IoInv_Transparent(DECL_IoVars, pciMem:mem):bool //{ //true //} function IoInv_Transparent(DECL_IoVars, pciMem:mem):bool { //- Serial port has been initialized serialPortConfigged() //- We have enough device memory for the network driver && ?devMemHi - ?devMemLo > 0x204004 // && ?memHi == ?devMemLo // && ?memHi == ?memLo + 0x7400 && ?devMemLo mod 0x10000 == 0 && //- We properly maintain records of previously mapped devices //- as tuples of (id, addr, size) in the pciLo to pciHi region //- We use 16, so that it divides the size (1024) of PCI memory nicely (forall addr:int, j:int::{pciMem[addr],TV(j)} TV(j) && 0 <= j && addr == ?pciLo + 16*j && addr <= ?pciHi - 16 ==> // pciMem[addr] == 0xffffffff) // //(IsValidPciId(pciMem[addr]) ==> false )) (IsValidPciId(pciMem[addr]) ==> pciMem[addr + 4] == PciMemAddr(pciMem[addr]) && pciMem[addr + 8] == PciMemSize(pciMem[addr]) && word(PciMemAddr(pciMem[addr])) && word(PciMemSize(pciMem[addr])) && SafePciMemRegion(PciMemAddr(pciMem[addr]), PciMemSize(pciMem[addr])) && io._pci.PciConfigState[pciMem[addr]] == 4 )) && (forall i:int::{io._pci.PciConfigState[i]} 0 <= i && i < 65536 && (forall addr:int, j:int::{pciMem[addr],TV(j)} TV(j) && 0 <= j && addr == ?pciLo + 16*j && addr <= ?pciHi - 16 ==> pciMem[addr] != i) ==> io._pci.PciConfigState[i] == 0) // !(exists j:int :: {TV(j)} TV(j) && pciMem[?pciLo + 16*j] == i) // ==> io._pci.PciConfigState[i] == 0) // (forall i:int::{io._pci.PciConfigState[i]} // 0 <= i && i < 65536 ==> // io._pci.PciConfigState[i] == 0 //// || io._pci.PciConfigState[i] == 4) ////// (forall i:int::{TV(i)} TV(i) ==> ////// 0 <= i && i < 65536 ==> ////// (io._pci.PciConfigState[i] == 0)) // || (exists j:int :: {TV(j)} TV(j) && // pciMem[?pciLo + 12*j] == i && // pciMem[?pciLo + 12*j + 4] == PciMemAddr(i) && // pciMem[?pciLo + 12*j + 8] == PciMemSize(i) && // SafePciMemRegion(PciMemAddr(i), PciMemSize(i)) && // io._pci.PciConfigState[i] == 4 )) //// ) // ((DmaAddr == 0 && !io._iom.IoMmuEnabled) || (DmaAddr == ?dmaLo && io._iom.IoMmuEnabled)) // && ?dmaLo > 8 && word(?dmaLo - 8) // && (forall i:int::{TV(i)} TV(i) ==> // 0 <= i && i < 65536 ==> // (pciMem[?pciLo + 8 * i] == 0 && io._pci.PciConfigState[i] == 0) // || (pciMem[?pciLo + 8 * i] != 0 && io._pci.PciConfigState[i] == 4 // && PciMemAddr(i) == pciMem[?pciLo + 8 * i] // && PciMemSize(i) == pciMem[?pciLo + 8 * i + 4])) } atomic ghost procedure reveal_IoInv(); ensures (forall io:IOState, pciMem:mem::{IoInv(io, pciMem)} IoInv(io, pciMem) <==> IoInv_Transparent(io, pciMem)); } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/GC/SimpleCommon.imp.beat ================================================ //-private-import BaseSpec; //-private-import MemorySpec; //-private-import IoTypesSpec; //-private-import MachineStateSpec; //-private-import AssemblySpec; //-private-import InterruptsSpec; //-private-import IoSpec; //- //- //- //- //-private-import Core; //-private-import LogicalAddressing; //-private-import Overflow; //-private-import Util; //-private-import Stacks; //-private-import Partition; //-private-import Instructions; //-private-import Separation; //-private-import IntLemmasGc; //-private-import SimpleGcMemory; //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module implementation SimpleCommon { implementation initCommon() { } function implementation IoInv(DECL_IoVars, pciMem:mem):bool { IoInv_Transparent(io, pciMem) } implementation reveal_IoInv() {} } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/GC/SimpleGc.ifc.beat ================================================ //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- ================================================ FILE: ironclad-apps/src/Checked/Nucleus/GC/SimpleGcMemory.ifc.beat ================================================ //-private-import BaseSpec; //-private-import MemorySpec; //-private-import IoTypesSpec; //-private-import MachineStateSpec; //-private-import AssemblySpec; //-private-import InterruptsSpec; //-private-import IoSpec; //- //- //- //- //-private-import Core; //-private-import LogicalAddressing; //-private-import Overflow; //-private-import Util; //-private-import Stacks; //-private-import Partition; //-private-import Instructions; //-private-import Separation; //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module interface GcMemory { //-//////////////////////////////////////////////////////////////////////////// //- ABSTRACT NODES //-//////////////////////////////////////////////////////////////////////////// //- The mutator controls an abstract graph consisting of abstract nodes, //- which contain abstract values. These abstract values may be //- abstract primitive values or abstract edges pointing to abstract nodes. //- Abstract values are represented by integers. For any integer A, //- we may interpret A as an abstract primitive value or an abstract pointer: //- - the abstract primitive value A represents the concrete integer A //- - the abstract pointer A may be one of the following: //- - NO_ABS, representing no value (used for partial maps) //- - any other value, representing a node in the abstract graph //- Any primitive value A will satisfy word(A). To avoid confusion //- between abstract primitive and abstract pointer values, the //- mutator should choose abstract pointer values A such that !word(A). const NO_ABS:int := 0 - 1; //- the value "none" //- Each abstract object node A has some number of fields, //- which is chosen when A is allocated, and never changes afterwards. type ObjLayout = ObjLayout(numFields:int, numPrimitiveFields:int) | NoObjLayout(); function numFields(objLayouts:[int]ObjLayout, abs:int) returns (int) { objLayouts[abs].numFields } function numPrimitiveFields(objLayouts:[int]ObjLayout, abs:int) returns (int) { objLayouts[abs].numPrimitiveFields } // $absMem represents of the abstract graph's edges: for abstract node A // and field j, $absMem[A][j] is the abstract node pointed to by A's field j. //var $absMem:[int][int]int; //-//////////////////////////////////////////////////////////////////////////// //- POINTERS AND VALUES //-//////////////////////////////////////////////////////////////////////////// function Pointer(rev:[int]int, ptr:int, abs:int) returns (bool) { gcAddr(ptr) && Aligned(ptr) && abs != NO_ABS && rev[ptr] == abs //- AbsMapped(ptr,rev,abs) } //- An interior pointer ("interiorPtr") points to an actual //- object address ("ptr") plus some offset ("offset"): //- !nullAddr(interiorPtr) ==> interiorPtr == ptr + offset && 0 <= offset && offset <= 4 * numFields(objLayouts, $toAbs[ptr - 4]) - 4; function InteriorValue(objLayouts:[int]ObjLayout, isPtr:bool, rev:[int]int, val:int, abs:int, offset:int) returns (bool) { (isPtr && word(val) && gcAddrEx(val) && Pointer(rev, val - 4 - offset, abs) && !word(abs) && 0 <= offset && offset <= 4 * numFields(objLayouts, abs) - 4) || (isPtr && word(val) && !gcAddrEx(val) && abs == val) || (!isPtr && word(val) && abs == val) } function Value(objLayouts:[int]ObjLayout, isPtr:bool, rev:[int]int, val:int, abs:int) returns (bool) { InteriorValue(objLayouts, isPtr, rev, val, abs, 0) } //-//////////////////////////////////////////////////////////////////////////// //- ABSTRACT AND CONCRETE GRAPHS //-//////////////////////////////////////////////////////////////////////////// //- Each integer i is considered a concrete node. //- The memory manager controls concrete nodes in memory. //- - Each abstract object node is either mapped to one concrete node or is unmapped //- - Each concrete node is either mapped to one abstract object node or is unmapped //- - If abstract object node A is mapped to concrete node C, then C is mapped to A //- Let the notation C<-->A indicate that A is mapped to C and C is mapped to A. //- Let the notation C-->none indicate that C is unmapped. //- Let the notation A-->none indicate that A is unmapped. //- The variable $toAbs maps concrete nodes to abstract nodes, and thereby //- exactly describes all C<-->A and C-->none. The A-->none mappings are //- implied; if there is no C such that C<-->A, then A-->none. //-var $toAbs:[int]int; // maps a concrete node C to an abstract node A or to "none" //- WellFormed($toAbs) ensures that if C1 != C2 and $toAbs[C1] != NO_ABS //- and $toAbs[C2] != NO_ABS then $toAbs[C1] != $toAbs[C2]. function WellFormed($toAbs:[int]int) returns(bool) { (forall i1:int, i2:int::{TV(i1), TV(i2)} TV(i1) && TV(i2) && gcAddr(i1) && gcAddr(i2) && i1 != i2 && $toAbs[i1] != NO_ABS && $toAbs[i2] != NO_ABS ==> $toAbs[i1] != $toAbs[i2]) } //-//////////////////////////////////////////////////////////////////////////// //- TRIGGERS //-//////////////////////////////////////////////////////////////////////////// //- TSlot is a trigger for slots in sparse tags function{:expand false} TSlot(slot:int) returns (bool) { true } //- TT is a trigger for tables function{:expand false} TT(table:int) returns (bool) { true } //-//////////////////////////////////////////////////////////////////////////// //- MUTATOR INTERFACE //-//////////////////////////////////////////////////////////////////////////// function isReadonlyField(t:int, j:int) returns(bool) { 0 <= j && j < 2 } //- true ==> field j is pointer //- false ==> field j is primitive function VFieldPtr(objLayouts:[int]ObjLayout, abs:int, f:int) returns(bool) { !(0 <= f && f < objLayouts[abs].numPrimitiveFields) } function{:expand false} TVT(abs:int, vt:int) returns(bool) { true } function VTable(objLayouts:[int]ObjLayout, abs:int, vt:int) returns(bool) { !VFieldPtr(objLayouts, abs, 0) // REVIEW: is this redundant? && !VFieldPtr(objLayouts, abs, 1) // REVIEW: is this redundant? && (forall j:int::{TO(j)} TO(j) ==> (0 <= j && j < numPrimitiveFields(objLayouts, abs) <==> !VFieldPtr(objLayouts, abs, j))) } function pad(i:int) returns(int) { and(i + 3, neg(3)) } function{:expand false} TVL(abs:int) returns(bool) { true } function ObjSize(objLayouts:[int]ObjLayout, abs:int, size:int, sizePrimitives:int) returns(bool) { 2 <= numPrimitiveFields(objLayouts, abs) && numPrimitiveFields(objLayouts, abs) <= numFields(objLayouts, abs) && 4 * numFields(objLayouts, abs) == size && 4 * numPrimitiveFields(objLayouts, abs) == sizePrimitives } type Frames=Frames(Abss:[int]int); //var $stacksFrames:[int]Frames; function{:expand false} TVS(s:int, j:int) returns(bool) { true } function{:expand false} TVFT(f:int) returns(bool) { true } function StackInv($frames:Frames) returns(bool) { true } //- Each managed stack $s grows from StackHi($s) down to StackLo($s) function StackHi($s:int):int { ?fLo + $s * ?FSize + ?FSize } function StackLo($s:int):int { ?fLo + $s * ?FSize } const ?fWords:int := ?FSize div 4; //- Requirement on entry to Nucleus from managed call: //- Since interrupts are disabled when calling the Nucleus, we do not //- require ?InterruptReserve be reserved between StackLo and esp. function SpRequire($s:int, sp:int, n:int) returns(bool) { StackLo($s) <= sp && sp + n <= StackHi($s) && Aligned(sp) } function StackCheckInv($s:int, $StackCheck:int) returns(bool) { StackLo($s) + ?StackReserve + ?InterruptReserve <= $StackCheck && $StackCheck <= StackHi($s) } function ScanStackInv($S:int, $Mem:[int]int, $stacksFrames:[int]Frames, $ra:int, $esp:int, $ebp:int) returns(bool) { StackInv($stacksFrames[$S]) } //-//////////////////////////////////////////////////////////////////////////// //- REACHABILITY //-//////////////////////////////////////////////////////////////////////////// //- Extra internal sanity checking for GC: check that any uncollected objects //- were actually reached during the collection. type Time; readonly var $Time:Time; //- reached(A,T) means that the GC has reached abstract node A at some time //- after the initial time T. Initially (at time T), the mutator will //- say that reached(root, T). After that, the GC calls the "reach" //- ghost procedure to generate reached(A, T) for other A. function reached(a:int, t:Time) returns (bool); atomic ghost procedure newTime(); modifies $Time; atomic ghost procedure reachStackRoot($s:int, $ptr:int, $t:Time); inout $absMem:[int][int]int, $toAbs:[int]int, $stacksFrames:[int]Frames; requires StackLo($s) <= $ptr && $ptr < StackHi($s); requires Aligned($ptr); ensures reached($stacksFrames[$s].Abss[$ptr], $t); //- If we've reached A, and A points to A', then reach A'. atomic ghost procedure reach($a:int, $j:int, $t:Time); inout $absMem:[int][int]int, $toAbs:[int]int, $stacksFrames:[int]Frames; requires reached($a, $t); requires $absMem[$a][$j] != NO_ABS; ensures reached($absMem[$a][$j], $t); } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/GC/SimpleGcMemory.imp.beat ================================================ //-private-import BaseSpec; //-private-import MemorySpec; //-private-import IoTypesSpec; //-private-import MachineStateSpec; //-private-import AssemblySpec; //-private-import InterruptsSpec; //-private-import IoSpec; //- //- //- //- //-private-import Core; //-private-import LogicalAddressing; //-private-import Overflow; //-private-import Util; //-private-import Stacks; //-private-import Partition; //-private-import Instructions; //-private-import Separation; //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module implementation GcMemory { function implementation reached(a:int, t:Time):bool { true } implementation newTime() {} implementation reachStackRoot($s:int, $j:int, $t:Time) {} implementation reach($a:int, $j:int, $t:Time) {} } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Main/BitVectorLemmasMain.ifc.beat ================================================ //-private-import BaseSpec; //-private-import MemorySpec; //- //- //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module interface BitVectorLemmasMain { atomic ghost procedure _const(); ensures $sub(1bv32, 1bv32) == 0bv32; ensures $add(1bv32, 1bv32) == 2bv32; ensures $mul(2bv32, 2bv32) == 4bv32; ensures $mul(4bv32, 4bv32) == 16bv32; ensures $add(16bv32, 16bv32) == 32bv32; ensures $add(32bv32, 32bv32) == 64bv32; ensures $mul(16bv32, 16bv32) == 256bv32; ensures $sub(256bv32, 1bv32) == 255bv32; ensures $mul(256bv32, 256bv32) == 65536bv32; ensures $sub(65536bv32, 1bv32) == 65535bv32; atomic ghost procedure _proc_XorLemmas(); ensures (forall x:bv32::$xor(x, x) == 0bv32); ensures (forall x:bv32::$xor(x, 0bv32) == x); ensures (forall x:bv32, y:bv32::$xor(x, y) == $xor(y, x)); ensures (forall x:bv32, y:bv32, z:bv32:: $xor(x, $xor(y,z)) == $xor(y, $xor(x,z))); ensures (forall x:bv32, y:bv32, z:bv32:: ($xor(x,z) == $xor(y,z)) ==> (x == y)); atomic ghost procedure _lemma_and_with_ff(x:bv32); ensures $le(0bv32, $and(x, 255bv32)) && $lt($and(x, 255bv32), 256bv32); atomic ghost procedure _lemma_and_with_ffff(x:bv32); ensures $le(0bv32, $and(x, 65535bv32)) && $lt($and(x, 65535bv32), 65536bv32); atomic ghost procedure _lemma_and_with_32_64(x:bv32); ensures $gt($and(x, 32bv32), 0bv32) ==> $mod($div($div($div($div($div(x, 2bv32), 2bv32), 2bv32), 2bv32), 2bv32), 2bv32) != 0bv32; //int_bit(x, 5) == 1; ensures $gt($and(x, 64bv32), 0bv32) ==> $mod($div($div($div($div($div($div(x, 2bv32), 2bv32), 2bv32), 2bv32), 2bv32), 2bv32), 2bv32) != 0bv32; //int_bit(x, 6) == 1; atomic ghost procedure _lemma_xor_bytes(x:bv32, y:bv32); requires $le(0bv32, x); requires $lt(x, 256bv32); requires $le(0bv32, y); requires $lt(y, 256bv32); ensures $le(0bv32, $xor(x, y)); ensures $lt($xor(x, y), 256bv32); } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Main/BitVectorLemmasMain.imp.beat ================================================ //-private-import BaseSpec; //-private-import MemorySpec; //- //- //- //- //- //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module implementation BitVectorLemmasMain { implementation _const() {} implementation _proc_XorLemmas() {} implementation _lemma_and_with_ff(x:bv32) {} implementation _lemma_and_with_ffff(x:bv32) {} implementation _lemma_and_with_32_64(x:bv32) {} implementation _lemma_xor_bytes(x:bv32, y:bv32) { } } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Main/Cube.ifc.beat ================================================ //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module interface Cube { type Tri = Triple(Pwd:int, Salt:int, Key:int); type Map = MapCons(Domain:[Tri]bool, Range:[Tri]int); var $ghost_Hashed:Map; const stack_size__DafnyCC__Proc_Cube:int := 256 + 64; procedure Proc_Cube(core_old:core_state, my_part__DafnyCC__old:partition, my__DafnyCC__mem_old:mems, $commonVars_old:commonVars, $gcVars_old:gcVars, $toAbs_old:[int]int, $absMem_old:[int][int]int, $stacksFrames_old:[int]Frames, objLayouts_old:[int]ObjLayout, heap_old:Heap, $ghost_N:int) returns(core:core_state, my_part:partition, my__DafnyCC__mem:mems, $commonVars:commonVars, $gcVars:gcVars, $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap, $ghost_c:int); requires MemInv(me,init,$State,core_old,ptOwner__id,(mem.map),$part,my_part__DafnyCC__old,$mem__id,$sepVars__id,my__DafnyCC__mem_old,$sepVars); requires NucleusInv(objLayouts_old,$S,$toAbs_old,$absMem_old,$commonVars__id,$gcVars__id,$ioVars__id,$commonVars_old,$gcVars_old,me,init,$State,core_old,ptOwner__id,(mem.map),$part,my_part__DafnyCC__old,$mem__id,$sepVars__id,my__DafnyCC__mem_old,$sepVars,$stacksFrames_old,state._io,$ioVars); requires SMemRequireGcRA(stack_size__DafnyCC__Proc_Cube, 8, mems__stk(my__DafnyCC__mem_old), (core_old._regs)[ESP], RET); requires HeapInv($absMem_old, objLayouts_old, heap_old); // requires $serialState.Mode.DLAB == false; // requires (core_old._regs)[ECX] == $ghost_N; requires sMemGet(mems__stk(my__DafnyCC__mem_old), core_old._regs[ESP] + 8) == $ghost_N; requires 0 <= $ghost_N; modifies state, efl, $part, $sepVars, $Time; //, $global_sample_index, $ghost_Hashed; ensures core._regs[ESP] == old(core_old._regs[ESP]) + 4; // ensures $serialState.Mode == old($serialState.Mode); ensures MemInv(me,init,state,core_state,ptOwner__id,(mem.map),$part,my_part,$mem__id,$sepVars__id,my__DafnyCC__mem,$sepVars); ensures NucleusInv(objLayouts,$S,$toAbs,$absMem,$commonVars__id,$gcVars__id,$ioVars__id,$commonVars,$gcVars,me,init,$State,core,ptOwner__id,(mem.map),$part,my_part,$mem__id,$sepVars__id,my__DafnyCC__mem,$sepVars,$stacksFrames,state._io,$ioVars); ensures SMemEnsureGcF(8, mems__stk(my__DafnyCC__mem), old(mems__stk(my__DafnyCC__mem_old)), esp, old((core_old._regs)[ESP]), $stacksFrames, $stacksFrames_old); ensures HeapInv($absMem, objLayouts, heap); ensures AbsExtend($toAbs, $toAbs_old, objLayouts, objLayouts_old); ensures $ghost_c == (($ghost_N * $ghost_N) * $ghost_N); // ensures eax == $ghost_c; ensures sMemGet(mems__stk(my__DafnyCC__mem), core_old._regs[ESP] + 4) == $ghost_c; //const stack_size__DafnyCC__Proc_XorIdentity:int := 0 + 0; // //procedure Proc_XorIdentity(core_old:core_state, my_part__DafnyCC__old:partition, my__DafnyCC__mem_old:mems, $ghost_a:int) returns(core:core_state, my_part:partition, my__DafnyCC__mem:mems, $ghost_r:int); // requires MemInv(me,init,$State,core_old,ptOwner__id,(mem.map),$part,my_part__DafnyCC__old,$mem__id,$sepVars__id,my__DafnyCC__mem_old,$sepVars); // requires SMemRequireRA(stack_size__DafnyCC__Proc_XorIdentity, mems__stk(my__DafnyCC__mem_old), (core_old._regs)[ESP], RET); //// requires $serialState.Mode.DLAB == false; // requires (core_old._regs)[ECX] == $ghost_a; // requires word($ghost_a); // modifies state, efl, $part, $serialState; //, $global_sample_index, $ghost_Hashed; // ensures esp == old((core_old._regs)[ESP])+4; // ensures $serialState.Mode == old($serialState.Mode); // ensures MemInv(me,init,state,core_state,ptOwner__id,(mem.map),$part,my_part,$mem__id,$sepVars__id,my__DafnyCC__mem,$sepVars); // ensures SMemEnsure(mems__stk(my__DafnyCC__mem), old(mems__stk(my__DafnyCC__mem_old)), esp, old((core_old._regs)[ESP])); // ensures $ghost_r == $ghost_a; // ensures eax == $ghost_r; } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Main/DafnyAssembly.ifc.beat ================================================ //-private-import BaseSpec; //-private-import MemorySpec; //-private-import IoTypesSpec; //-private-import MachineStateSpec; //-private-import AssemblySpec; //-private-import InterruptsSpec; //-private-import IoSpec; //- //- //- //- //- //-private-import Core; //-private-import LogicalAddressing; //-private-import Overflow; //-private-import Util; //-private-import Stacks; //-private-import Partition; //-private-import Instructions; //-private-import Separation; //-private-import IntLemmasBase; //-private-import IntLemmasGc; //-private-import SimpleGcMemory; //-private-import SimpleCommon; //-private-import SimpleCollector; //-private-import IoMain; //-private-import IntLemmasMain; //-private-basmonly-import Trusted; //-private-basmonly-import Checked; //-private-import Heap; //-private-import Seq; //-private-import dafny_DafnyPrelude; module interface DafnyAssembly { //- Connect Dafny's word32() to Boogie's word() function fun_word32($ghost_x:int):bool { word($ghost_x) } function fun_mod0x100000000($ghost_x:int):int { $ghost_x mod 0x100000000 } function fun_asm__Add($ghost_x:int, $ghost_y:int):int { fun_mod0x100000000(INTERNAL_add_boogie($ghost_x, $ghost_y)) } function fun_asm__Sub($ghost_x:int, $ghost_y:int):int { fun_mod0x100000000(INTERNAL_sub_boogie($ghost_x, $ghost_y)) } function fun_asm__Mul($ghost_x:int, $ghost_y:int):int { fun_mod0x100000000(fun_INTERNAL__mul($ghost_x, $ghost_y)) } function fun_asm__Div($ghost_x:int, $ghost_y:int):int { fun_mod0x100000000(fun_INTERNAL__div($ghost_x, $ghost_y)) } function fun_asm__Mod($ghost_x:int, $ghost_y:int):int { fun_INTERNAL__mod($ghost_x, $ghost_y) } function fun_asm__LeftShift($ghost_x:int, $ghost_y:int):int { shl($ghost_x, $ghost_y) } function fun_asm__RightShift($ghost_x:int, $ghost_y:int):int { shr($ghost_x, $ghost_y) } function fun_asm__RotateLeft($ghost_x:int, $ghost_y:int):int { rol($ghost_x, $ghost_y) } function fun_asm__RotateRight($ghost_x:int, $ghost_y:int):int { ror($ghost_x, $ghost_y) } function fun_asm__BitwiseNot($ghost_x:int):int { neg($ghost_x) } function fun_asm__BitwiseAnd($ghost_x:int, $ghost_y:int):int { and($ghost_x, $ghost_y) } function fun_asm__BitwiseOr($ghost_x:int, $ghost_y:int):int { or($ghost_x, $ghost_y) } function fun_asm__BitwiseXor($ghost_x:int, $ghost_y:int):int { xor($ghost_x, $ghost_y) } function fun_IntBit($ghost_index:int, $ghost_val:int):bool { int_bit($ghost_val, 31 - $ghost_index) //- IntBit is big endian, int_bit is little endian } function trigger_fun_asm__Add($ghost_x:int, $ghost_y:int):bool { true } atomic ghost procedure lemma_fun_ensures_fun_asm__Add(); ensures (forall $ghost_x:int, $ghost_y:int::{fun_asm__Add($ghost_x, $ghost_y)}{trigger_fun_asm__Add($ghost_x, $ghost_y)}trigger_fun_asm__Add($ghost_x, $ghost_y) ==> (true && (fun_word32($ghost_x)) && (fun_word32($ghost_y))) ==> (true && (fun_word32(fun_asm__Add($ghost_x, $ghost_y))) && ((fun_asm__Add($ghost_x, $ghost_y)) == (fun_mod0x100000000(INTERNAL_add_boogie($ghost_x, $ghost_y)))))); atomic procedure proc_asm__Add(my r_old:regs, $ghost_x:int, $ghost_y:int, $opn_x:int, $opn_y:opn) returns(my r:regs, $ghost___result:int); requires $ghost_x == r_old.regs[$opn_x]; requires $ghost_y == Eval(r_old, $opn_y); requires fun_word32($ghost_x); requires fun_word32($ghost_y); ensures $ghost___result == (fun_asm__Add($ghost_x, $ghost_y)); ensures fun_word32(fun_asm__Add($ghost_x, $ghost_y)); ensures (fun_asm__Add($ghost_x, $ghost_y)) == (fun_mod0x100000000(INTERNAL_add_boogie($ghost_x, $ghost_y))); ensures r.regs == r_old.regs[$opn_x := $ghost___result]; function trigger_fun_asm__Sub($ghost_x:int, $ghost_y:int):bool { true } atomic ghost procedure lemma_fun_ensures_fun_asm__Sub(); ensures (forall $ghost_x:int, $ghost_y:int::{fun_asm__Sub($ghost_x, $ghost_y)}{trigger_fun_asm__Sub($ghost_x, $ghost_y)}trigger_fun_asm__Sub($ghost_x, $ghost_y) ==> (true && (fun_word32($ghost_x)) && (fun_word32($ghost_y))) ==> (true && (fun_word32(fun_asm__Sub($ghost_x, $ghost_y))) && ((fun_asm__Sub($ghost_x, $ghost_y)) == (fun_mod0x100000000(INTERNAL_sub_boogie($ghost_x, $ghost_y)))))); atomic procedure proc_asm__Sub(my r_old:regs, $ghost_x:int, $ghost_y:int, $opn_x:int, $opn_y:opn) returns(my r:regs, $ghost___result:int); requires $ghost_x == r_old.regs[$opn_x]; requires $ghost_y == Eval(r_old, $opn_y); requires fun_word32($ghost_x); requires fun_word32($ghost_y); ensures $ghost___result == (fun_asm__Sub($ghost_x, $ghost_y)); ensures fun_word32(fun_asm__Sub($ghost_x, $ghost_y)); ensures (fun_asm__Sub($ghost_x, $ghost_y)) == (fun_mod0x100000000(INTERNAL_sub_boogie($ghost_x, $ghost_y))); ensures r.regs == r_old.regs[$opn_x := $ghost___result]; function trigger_fun_asm__Mul($ghost_x:int, $ghost_y:int):bool { true } atomic ghost procedure lemma_fun_ensures_fun_asm__Mul(); ensures (forall $ghost_x:int, $ghost_y:int::{fun_asm__Mul($ghost_x, $ghost_y)}{trigger_fun_asm__Mul($ghost_x, $ghost_y)}trigger_fun_asm__Mul($ghost_x, $ghost_y) ==> (true && (fun_word32($ghost_x)) && (fun_word32($ghost_y))) ==> (true && (fun_word32(fun_asm__Mul($ghost_x, $ghost_y))) && ((fun_asm__Mul($ghost_x, $ghost_y)) == (fun_mod0x100000000(fun_INTERNAL__mul($ghost_x, $ghost_y)))))); const stack_size__DafnyCC__Proc_asm__Mul:int := 0 + 0; procedure Proc_asm__Mul(my r_old:regs, const my core_state:core_state, linear stk_old:mem, linear statics_old:mem, linear io_old:IOState, linear mems_old:mems, $commonVars_old:commonVars, $gcVars_old:gcVars, $toAbs_old:[int]int, $absMem_old:[int][int]int, $stacksFrames_old:[int]Frames, objLayouts_old:[int]ObjLayout, heap_old:Heap, $ghost_x:int, $ghost_y:int) returns(my r:regs, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars, $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap, $ghost___result:int); requires MemInv(me,init,stk_old,statics_old,core_state,ptMem,mems_old); requires NucleusInv(objLayouts_old,$S,$toAbs_old,$absMem_old,$commonVars_old,$gcVars_old,me,init,stk_old,statics_old,core_state,ptMem,mems_old,$stacksFrames_old,io_old); requires SMemRequireGcRA(stack_size__DafnyCC__Proc_asm__Mul, 16, stk_old, r_old.regs[ESP], RET); requires HeapInv($absMem_old, objLayouts_old, heap_old); requires (($ghost_x) == (stk_old.map[r_old.regs[ESP] + (4 + IPSize)])); requires (($ghost_y) == (stk_old.map[r_old.regs[ESP] + (8 + IPSize)])); requires fun_word32($ghost_x); requires fun_word32($ghost_y); modifies $Time; ensures r.regs[ESP] == old(r_old.regs[ESP]) + IPSize; ensures MemInv(me,init,stk,statics,core_state,ptMem,mems); ensures NucleusInv(objLayouts,$S,$toAbs,$absMem,$commonVars,$gcVars,me,init,stk,statics,core_state,ptMem,mems,$stacksFrames,io); ensures SMemEnsureGcF(16, stk, old(stk_old), r.regs[ESP], old(r_old.regs[ESP]), $stacksFrames, $stacksFrames_old); ensures HeapInv($absMem, objLayouts, heap); ensures AbsExtend($toAbs, $toAbs_old, objLayouts, objLayouts_old); ensures io._inCtr == io_old._inCtr && io._outCtr == io_old._outCtr; ensures (forall i:int::{$absMem[i]}{heap.absData[i]} heap_old.absData[i] is AbsNone || (heap.absData[i] == heap_old.absData[i] && ($absMem[i] == $absMem_old[i]))); ensures $ghost___result == (fun_asm__Mul($ghost_x, $ghost_y)); ensures fun_word32(fun_asm__Mul($ghost_x, $ghost_y)); ensures (fun_asm__Mul($ghost_x, $ghost_y)) == (fun_mod0x100000000(fun_INTERNAL__mul($ghost_x, $ghost_y))); ensures (($ghost___result) == (stk.map[r_old.regs[ESP] + IPSize])); atomic procedure proc_asm__Mul64(my r_old:regs, $ghost_x:int, $ghost_y:int, $opn_hi:int, $opn_x:int, $opn_y:opn) returns(my r:regs, $ghost_hi:int, $ghost_lo:int); requires $opn_hi == EDX; requires $opn_x == EAX; requires $opn_y != OReg(EDX) && $opn_y != OReg(EAX); requires $ghost_x == r_old.regs[$opn_x]; requires $ghost_y == Eval(r_old, $opn_y); requires fun_word32($ghost_x); requires fun_word32($ghost_y); ensures fun_word32($ghost_hi); ensures fun_word32($ghost_lo); ensures $ghost_lo == (fun_mod0x100000000(fun_INTERNAL__mul($ghost_x, $ghost_y))); ensures $ghost_hi == (fun_INTERNAL__div(fun_INTERNAL__mul($ghost_x, $ghost_y), 4294967296)); ensures r.regs == r_old.regs[$opn_hi := $ghost_hi][$opn_x := $ghost_lo]; function trigger_fun_asm__Div($ghost_x:int, $ghost_y:int):bool { true } atomic ghost procedure lemma_fun_ensures_fun_asm__Div(); ensures (forall $ghost_x:int, $ghost_y:int::{fun_asm__Div($ghost_x, $ghost_y)}{trigger_fun_asm__Div($ghost_x, $ghost_y)}trigger_fun_asm__Div($ghost_x, $ghost_y) ==> (true && (fun_word32($ghost_x)) && (fun_word32($ghost_y)) && (INTERNAL_gt_boogie($ghost_y, 0))) ==> (true && (fun_word32(fun_asm__Div($ghost_x, $ghost_y))) && ((fun_asm__Div($ghost_x, $ghost_y)) == (fun_mod0x100000000(fun_INTERNAL__div($ghost_x, $ghost_y)))))); const stack_size__DafnyCC__Proc_asm__Div:int := 0 + 0; procedure Proc_asm__Div(my r_old:regs, const my core_state:core_state, linear stk_old:mem, linear statics_old:mem, linear io_old:IOState, linear mems_old:mems, $commonVars_old:commonVars, $gcVars_old:gcVars, $toAbs_old:[int]int, $absMem_old:[int][int]int, $stacksFrames_old:[int]Frames, objLayouts_old:[int]ObjLayout, heap_old:Heap, $ghost_x:int, $ghost_y:int) returns(my r:regs, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars, $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap, $ghost___result:int); requires MemInv(me,init,stk_old,statics_old,core_state,ptMem,mems_old); requires NucleusInv(objLayouts_old,$S,$toAbs_old,$absMem_old,$commonVars_old,$gcVars_old,me,init,stk_old,statics_old,core_state,ptMem,mems_old,$stacksFrames_old,io_old); requires SMemRequireGcRA(stack_size__DafnyCC__Proc_asm__Div, 16, stk_old, r_old.regs[ESP], RET); requires HeapInv($absMem_old, objLayouts_old, heap_old); requires (($ghost_x) == (stk_old.map[r_old.regs[ESP] + (4 + IPSize)])); requires (($ghost_y) == (stk_old.map[r_old.regs[ESP] + (8 + IPSize)])); requires fun_word32($ghost_x); requires fun_word32($ghost_y); requires INTERNAL_gt_boogie($ghost_y, 0); modifies $Time; ensures r.regs[ESP] == old(r_old.regs[ESP]) + IPSize; ensures MemInv(me,init,stk,statics,core_state,ptMem,mems); ensures NucleusInv(objLayouts,$S,$toAbs,$absMem,$commonVars,$gcVars,me,init,stk,statics,core_state,ptMem,mems,$stacksFrames,io); ensures SMemEnsureGcF(12, stk, old(stk_old), r.regs[ESP], old(r_old.regs[ESP]), $stacksFrames, $stacksFrames_old); ensures HeapInv($absMem, objLayouts, heap); ensures AbsExtend($toAbs, $toAbs_old, objLayouts, objLayouts_old); ensures (forall i:int::{$absMem[i]}{heap.absData[i]} heap_old.absData[i] is AbsNone || (heap.absData[i] == heap_old.absData[i] && ($absMem[i] == $absMem_old[i]))); ensures io._inCtr == io_old._inCtr && io._outCtr == io_old._outCtr; ensures $ghost___result == (fun_asm__Div($ghost_x, $ghost_y)); ensures fun_word32(fun_asm__Div($ghost_x, $ghost_y)); ensures (fun_asm__Div($ghost_x, $ghost_y)) == (fun_mod0x100000000(fun_INTERNAL__div($ghost_x, $ghost_y))); ensures (($ghost___result) == (stk.map[r_old.regs[ESP] + IPSize])); function trigger_fun_asm__Mod($ghost_x:int, $ghost_y:int):bool { true } atomic ghost procedure lemma_fun_ensures_fun_asm__Mod(); ensures (forall $ghost_x:int, $ghost_y:int::{fun_asm__Mod($ghost_x, $ghost_y)}{trigger_fun_asm__Mod($ghost_x, $ghost_y)}trigger_fun_asm__Mod($ghost_x, $ghost_y) ==> (true && (fun_word32($ghost_x)) && (fun_word32($ghost_y)) && (INTERNAL_gt_boogie($ghost_y, 0))) ==> (true && (fun_word32(fun_asm__Mod($ghost_x, $ghost_y))) && ((fun_asm__Mod($ghost_x, $ghost_y)) == (fun_INTERNAL__mod($ghost_x, $ghost_y))))); const stack_size__DafnyCC__Proc_asm__Mod:int := 0 + 0; procedure Proc_asm__Mod(my r_old:regs, const my core_state:core_state, linear stk_old:mem, linear statics_old:mem, linear io_old:IOState, linear mems_old:mems, $commonVars_old:commonVars, $gcVars_old:gcVars, $toAbs_old:[int]int, $absMem_old:[int][int]int, $stacksFrames_old:[int]Frames, objLayouts_old:[int]ObjLayout, heap_old:Heap, $ghost_x:int, $ghost_y:int) returns(my r:regs, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars, $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap, $ghost___result:int); requires MemInv(me,init,stk_old,statics_old,core_state,ptMem,mems_old); requires NucleusInv(objLayouts_old,$S,$toAbs_old,$absMem_old,$commonVars_old,$gcVars_old,me,init,stk_old,statics_old,core_state,ptMem,mems_old,$stacksFrames_old,io_old); requires SMemRequireGcRA(stack_size__DafnyCC__Proc_asm__Mod, 16, stk_old, r_old.regs[ESP], RET); requires HeapInv($absMem_old, objLayouts_old, heap_old); requires (($ghost_x) == (stk_old.map[r_old.regs[ESP] + (4 + IPSize)])); requires (($ghost_y) == (stk_old.map[r_old.regs[ESP] + (8 + IPSize)])); requires fun_word32($ghost_x); requires fun_word32($ghost_y); requires INTERNAL_gt_boogie($ghost_y, 0); modifies $Time; ensures r.regs[ESP] == old(r_old.regs[ESP]) + IPSize; ensures MemInv(me,init,stk,statics,core_state,ptMem,mems); ensures NucleusInv(objLayouts,$S,$toAbs,$absMem,$commonVars,$gcVars,me,init,stk,statics,core_state,ptMem,mems,$stacksFrames,io); ensures SMemEnsureGcF(16, stk, old(stk_old), r.regs[ESP], old(r_old.regs[ESP]), $stacksFrames, $stacksFrames_old); ensures HeapInv($absMem, objLayouts, heap); ensures AbsExtend($toAbs, $toAbs_old, objLayouts, objLayouts_old); ensures (forall i:int::{$absMem[i]}{heap.absData[i]} heap_old.absData[i] is AbsNone || (heap.absData[i] == heap_old.absData[i] && ($absMem[i] == $absMem_old[i]))); ensures io._inCtr == io_old._inCtr && io._outCtr == io_old._outCtr; ensures $ghost___result == (fun_asm__Mod($ghost_x, $ghost_y)); ensures fun_word32(fun_asm__Mod($ghost_x, $ghost_y)); ensures (fun_asm__Mod($ghost_x, $ghost_y)) == (fun_INTERNAL__mod($ghost_x, $ghost_y)); ensures (($ghost___result) == (stk.map[r_old.regs[ESP] + IPSize])); function trigger_fun_asm__LeftShift($ghost_x:int, $ghost_amount:int):bool { true } atomic ghost procedure lemma_fun_ensures_fun_asm__LeftShift(); ensures (forall $ghost_x:int, $ghost_amount:int::{fun_asm__LeftShift($ghost_x, $ghost_amount)}{trigger_fun_asm__LeftShift($ghost_x, $ghost_amount)}trigger_fun_asm__LeftShift($ghost_x, $ghost_amount) ==> (true && (fun_word32($ghost_x)) && ((INTERNAL_le_boogie(0, $ghost_amount)) && (INTERNAL_lt_boogie($ghost_amount, 32)))) ==> (true && (fun_word32(fun_asm__LeftShift($ghost_x, $ghost_amount))) && ((forall $ghost__0_i:int :: {fun_IntBit($ghost__0_i, fun_asm__LeftShift($ghost_x, $ghost_amount))} ((INTERNAL_le_boogie(INTERNAL_sub_boogie(32, $ghost_amount), $ghost__0_i)) && (INTERNAL_lt_boogie($ghost__0_i, 32))) ==> ((fun_IntBit($ghost__0_i, fun_asm__LeftShift($ghost_x, $ghost_amount))) == (false)))) && ((forall $ghost__1_i:int :: {fun_IntBit($ghost__1_i, fun_asm__LeftShift($ghost_x, $ghost_amount))} ((INTERNAL_le_boogie(0, $ghost__1_i)) && (INTERNAL_lt_boogie($ghost__1_i, INTERNAL_sub_boogie(32, $ghost_amount)))) ==> ((fun_IntBit($ghost__1_i, fun_asm__LeftShift($ghost_x, $ghost_amount))) == (fun_IntBit(INTERNAL_add_boogie($ghost__1_i, $ghost_amount), $ghost_x))))))); atomic procedure proc_asm__LeftShift(my r_old:regs, $ghost_x:int, $ghost_amount:int, $opn_x:int, $opn_amount:opn) returns(my r:regs, $ghost___result:int); requires $ghost_x == r_old.regs[$opn_x]; requires $ghost_amount == Eval(r_old, $opn_amount); requires fun_word32($ghost_x); requires (INTERNAL_le_boogie(0, $ghost_amount)) && (INTERNAL_lt_boogie($ghost_amount, 32)); ensures $ghost___result == (fun_asm__LeftShift($ghost_x, $ghost_amount)); ensures fun_word32(fun_asm__LeftShift($ghost_x, $ghost_amount)); ensures (forall $ghost__0_i:int :: {fun_IntBit($ghost__0_i, fun_asm__LeftShift($ghost_x, $ghost_amount))} ((INTERNAL_le_boogie(INTERNAL_sub_boogie(32, $ghost_amount), $ghost__0_i)) && (INTERNAL_lt_boogie($ghost__0_i, 32))) ==> ((fun_IntBit($ghost__0_i, fun_asm__LeftShift($ghost_x, $ghost_amount))) == (false))); ensures (forall $ghost__1_i:int :: {fun_IntBit($ghost__1_i, fun_asm__LeftShift($ghost_x, $ghost_amount))} ((INTERNAL_le_boogie(0, $ghost__1_i)) && (INTERNAL_lt_boogie($ghost__1_i, INTERNAL_sub_boogie(32, $ghost_amount)))) ==> ((fun_IntBit($ghost__1_i, fun_asm__LeftShift($ghost_x, $ghost_amount))) == (fun_IntBit(INTERNAL_add_boogie($ghost__1_i, $ghost_amount), $ghost_x)))); ensures r.regs == r_old.regs[$opn_x := $ghost___result]; function trigger_fun_asm__RightShift($ghost_x:int, $ghost_amount:int):bool { true } atomic ghost procedure lemma_fun_ensures_fun_asm__RightShift(); ensures (forall $ghost_x:int, $ghost_amount:int::{fun_asm__RightShift($ghost_x, $ghost_amount)}{trigger_fun_asm__RightShift($ghost_x, $ghost_amount)}trigger_fun_asm__RightShift($ghost_x, $ghost_amount) ==> (true && (fun_word32($ghost_x)) && ((INTERNAL_le_boogie(0, $ghost_amount)) && (INTERNAL_lt_boogie($ghost_amount, 32)))) ==> (true && (fun_word32(fun_asm__RightShift($ghost_x, $ghost_amount))) && ((forall $ghost__0_i:int :: {fun_IntBit($ghost__0_i, fun_asm__RightShift($ghost_x, $ghost_amount))} ((INTERNAL_le_boogie(0, $ghost__0_i)) && (INTERNAL_lt_boogie($ghost__0_i, $ghost_amount))) ==> ((fun_IntBit($ghost__0_i, fun_asm__RightShift($ghost_x, $ghost_amount))) == (false)))) && ((forall $ghost__1_i:int :: {fun_IntBit($ghost__1_i, fun_asm__RightShift($ghost_x, $ghost_amount))} ((INTERNAL_le_boogie($ghost_amount, $ghost__1_i)) && (INTERNAL_lt_boogie($ghost__1_i, 32))) ==> ((fun_IntBit($ghost__1_i, fun_asm__RightShift($ghost_x, $ghost_amount))) == (fun_IntBit(INTERNAL_sub_boogie($ghost__1_i, $ghost_amount), $ghost_x))))))); atomic procedure proc_asm__RightShift(my r_old:regs, $ghost_x:int, $ghost_amount:int, $opn_x:int, $opn_amount:opn) returns(my r:regs, $ghost___result:int); requires $ghost_x == r_old.regs[$opn_x]; requires $ghost_amount == Eval(r_old, $opn_amount); requires fun_word32($ghost_x); requires (INTERNAL_le_boogie(0, $ghost_amount)) && (INTERNAL_lt_boogie($ghost_amount, 32)); ensures $ghost___result == (fun_asm__RightShift($ghost_x, $ghost_amount)); ensures fun_word32(fun_asm__RightShift($ghost_x, $ghost_amount)); ensures (forall $ghost__0_i:int :: {fun_IntBit($ghost__0_i, fun_asm__RightShift($ghost_x, $ghost_amount))} ((INTERNAL_le_boogie(0, $ghost__0_i)) && (INTERNAL_lt_boogie($ghost__0_i, $ghost_amount))) ==> ((fun_IntBit($ghost__0_i, fun_asm__RightShift($ghost_x, $ghost_amount))) == (false))); ensures (forall $ghost__1_i:int :: {fun_IntBit($ghost__1_i, fun_asm__RightShift($ghost_x, $ghost_amount))} ((INTERNAL_le_boogie($ghost_amount, $ghost__1_i)) && (INTERNAL_lt_boogie($ghost__1_i, 32))) ==> ((fun_IntBit($ghost__1_i, fun_asm__RightShift($ghost_x, $ghost_amount))) == (fun_IntBit(INTERNAL_sub_boogie($ghost__1_i, $ghost_amount), $ghost_x)))); ensures r.regs == r_old.regs[$opn_x := $ghost___result]; function trigger_fun_asm__RotateLeft($ghost_x:int, $ghost_amount:int):bool { true } atomic ghost procedure lemma_fun_ensures_fun_asm__RotateLeft(); ensures (forall $ghost_x:int, $ghost_amount:int::{fun_asm__RotateLeft($ghost_x, $ghost_amount)}{trigger_fun_asm__RotateLeft($ghost_x, $ghost_amount)}trigger_fun_asm__RotateLeft($ghost_x, $ghost_amount) ==> (true && (fun_word32($ghost_x)) && ((INTERNAL_le_boogie(0, $ghost_amount)) && (INTERNAL_lt_boogie($ghost_amount, 32)))) ==> (true && (fun_word32(fun_asm__RotateLeft($ghost_x, $ghost_amount))) && ((forall $ghost__0_i:int :: {fun_IntBit($ghost__0_i, fun_asm__RotateLeft($ghost_x, $ghost_amount))} ((INTERNAL_le_boogie(0, $ghost__0_i)) && (INTERNAL_lt_boogie($ghost__0_i, INTERNAL_sub_boogie(32, $ghost_amount)))) ==> ((fun_IntBit($ghost__0_i, fun_asm__RotateLeft($ghost_x, $ghost_amount))) == (fun_IntBit(INTERNAL_add_boogie($ghost__0_i, $ghost_amount), $ghost_x))))) && ((forall $ghost__1_i:int :: {fun_IntBit($ghost__1_i, fun_asm__RotateLeft($ghost_x, $ghost_amount))} ((INTERNAL_le_boogie(INTERNAL_sub_boogie(32, $ghost_amount), $ghost__1_i)) && (INTERNAL_lt_boogie($ghost__1_i, 32))) ==> ((fun_IntBit($ghost__1_i, fun_asm__RotateLeft($ghost_x, $ghost_amount))) == (fun_IntBit(INTERNAL_sub_boogie($ghost__1_i, INTERNAL_sub_boogie(32, $ghost_amount)), $ghost_x))))))); atomic procedure proc_asm__RotateLeft(my r_old:regs, $ghost_x:int, $ghost_amount:int, $opn_x:int, $opn_amount:opn) returns(my r:regs, $ghost___result:int); requires $ghost_x == r_old.regs[$opn_x]; requires $ghost_amount == Eval(r_old, $opn_amount); requires fun_word32($ghost_x); requires (INTERNAL_le_boogie(0, $ghost_amount)) && (INTERNAL_lt_boogie($ghost_amount, 32)); ensures $ghost___result == (fun_asm__RotateLeft($ghost_x, $ghost_amount)); ensures fun_word32(fun_asm__RotateLeft($ghost_x, $ghost_amount)); ensures (forall $ghost__0_i:int :: {fun_IntBit($ghost__0_i, fun_asm__RotateLeft($ghost_x, $ghost_amount))} ((INTERNAL_le_boogie(0, $ghost__0_i)) && (INTERNAL_lt_boogie($ghost__0_i, INTERNAL_sub_boogie(32, $ghost_amount)))) ==> ((fun_IntBit($ghost__0_i, fun_asm__RotateLeft($ghost_x, $ghost_amount))) == (fun_IntBit(INTERNAL_add_boogie($ghost__0_i, $ghost_amount), $ghost_x)))); ensures (forall $ghost__1_i:int :: {fun_IntBit($ghost__1_i, fun_asm__RotateLeft($ghost_x, $ghost_amount))} ((INTERNAL_le_boogie(INTERNAL_sub_boogie(32, $ghost_amount), $ghost__1_i)) && (INTERNAL_lt_boogie($ghost__1_i, 32))) ==> ((fun_IntBit($ghost__1_i, fun_asm__RotateLeft($ghost_x, $ghost_amount))) == (fun_IntBit(INTERNAL_sub_boogie($ghost__1_i, INTERNAL_sub_boogie(32, $ghost_amount)), $ghost_x)))); ensures r.regs == r_old.regs[$opn_x := $ghost___result]; function trigger_fun_asm__RotateRight($ghost_x:int, $ghost_amount:int):bool { true } atomic ghost procedure lemma_fun_ensures_fun_asm__RotateRight(); ensures (forall $ghost_x:int, $ghost_amount:int::{fun_asm__RotateRight($ghost_x, $ghost_amount)}{trigger_fun_asm__RotateRight($ghost_x, $ghost_amount)}trigger_fun_asm__RotateRight($ghost_x, $ghost_amount) ==> (true && (fun_word32($ghost_x)) && ((INTERNAL_le_boogie(0, $ghost_amount)) && (INTERNAL_lt_boogie($ghost_amount, 32)))) ==> (true && (fun_word32(fun_asm__RotateRight($ghost_x, $ghost_amount))) && ((forall $ghost__0_i:int :: {fun_IntBit($ghost__0_i, fun_asm__RotateRight($ghost_x, $ghost_amount))} ((INTERNAL_le_boogie(0, $ghost__0_i)) && (INTERNAL_lt_boogie($ghost__0_i, $ghost_amount))) ==> ((fun_IntBit($ghost__0_i, fun_asm__RotateRight($ghost_x, $ghost_amount))) == (fun_IntBit(INTERNAL_add_boogie(INTERNAL_sub_boogie(32, $ghost_amount), $ghost__0_i), $ghost_x))))) && ((forall $ghost__1_i:int :: {fun_IntBit($ghost__1_i, fun_asm__RotateRight($ghost_x, $ghost_amount))} ((INTERNAL_le_boogie($ghost_amount, $ghost__1_i)) && (INTERNAL_lt_boogie($ghost__1_i, 32))) ==> ((fun_IntBit($ghost__1_i, fun_asm__RotateRight($ghost_x, $ghost_amount))) == (fun_IntBit(INTERNAL_sub_boogie($ghost__1_i, $ghost_amount), $ghost_x))))))); atomic procedure proc_asm__RotateRight(my r_old:regs, $ghost_x:int, $ghost_amount:int, $opn_x:int, $opn_amount:opn) returns(my r:regs, $ghost___result:int); requires $ghost_x == r_old.regs[$opn_x]; requires $ghost_amount == Eval(r_old, $opn_amount); requires fun_word32($ghost_x); requires (INTERNAL_le_boogie(0, $ghost_amount)) && (INTERNAL_lt_boogie($ghost_amount, 32)); ensures $ghost___result == (fun_asm__RotateRight($ghost_x, $ghost_amount)); ensures fun_word32(fun_asm__RotateRight($ghost_x, $ghost_amount)); ensures (forall $ghost__0_i:int :: {fun_IntBit($ghost__0_i, fun_asm__RotateRight($ghost_x, $ghost_amount))} ((INTERNAL_le_boogie(0, $ghost__0_i)) && (INTERNAL_lt_boogie($ghost__0_i, $ghost_amount))) ==> ((fun_IntBit($ghost__0_i, fun_asm__RotateRight($ghost_x, $ghost_amount))) == (fun_IntBit(INTERNAL_add_boogie(INTERNAL_sub_boogie(32, $ghost_amount), $ghost__0_i), $ghost_x)))); ensures (forall $ghost__1_i:int :: {fun_IntBit($ghost__1_i, fun_asm__RotateRight($ghost_x, $ghost_amount))} ((INTERNAL_le_boogie($ghost_amount, $ghost__1_i)) && (INTERNAL_lt_boogie($ghost__1_i, 32))) ==> ((fun_IntBit($ghost__1_i, fun_asm__RotateRight($ghost_x, $ghost_amount))) == (fun_IntBit(INTERNAL_sub_boogie($ghost__1_i, $ghost_amount), $ghost_x)))); ensures r.regs == r_old.regs[$opn_x := $ghost___result]; function trigger_fun_asm__BitwiseNot($ghost_x:int):bool { true } atomic ghost procedure lemma_fun_ensures_fun_asm__BitwiseNot(); ensures (forall $ghost_x:int::{fun_asm__BitwiseNot($ghost_x)}{trigger_fun_asm__BitwiseNot($ghost_x)}trigger_fun_asm__BitwiseNot($ghost_x) ==> (true && (fun_word32($ghost_x))) ==> (true && (fun_word32(fun_asm__BitwiseNot($ghost_x))) && ((forall $ghost__0_i:int :: {fun_IntBit($ghost__0_i, fun_asm__BitwiseNot($ghost_x))} ((INTERNAL_le_boogie(0, $ghost__0_i)) && (INTERNAL_lt_boogie($ghost__0_i, 32))) ==> ((fun_IntBit($ghost__0_i, fun_asm__BitwiseNot($ghost_x))) == ((!(fun_IntBit($ghost__0_i, $ghost_x))))))))); atomic procedure proc_asm__BitwiseNot(my r_old:regs, $ghost_x:int, $opn_x:int) returns(my r:regs, $ghost___result:int); requires $ghost_x == r_old.regs[$opn_x]; requires fun_word32($ghost_x); ensures $ghost___result == (fun_asm__BitwiseNot($ghost_x)); ensures fun_word32(fun_asm__BitwiseNot($ghost_x)); ensures (forall $ghost__0_i:int :: {fun_IntBit($ghost__0_i, fun_asm__BitwiseNot($ghost_x))} ((INTERNAL_le_boogie(0, $ghost__0_i)) && (INTERNAL_lt_boogie($ghost__0_i, 32))) ==> ((fun_IntBit($ghost__0_i, fun_asm__BitwiseNot($ghost_x))) == ((!(fun_IntBit($ghost__0_i, $ghost_x)))))); ensures r.regs == r_old.regs[$opn_x := $ghost___result]; function trigger_fun_asm__BitwiseAnd($ghost_x:int, $ghost_y:int):bool { true } atomic ghost procedure lemma_fun_ensures_fun_asm__BitwiseAnd(); ensures (forall $ghost_x:int, $ghost_y:int::{fun_asm__BitwiseAnd($ghost_x, $ghost_y)}{trigger_fun_asm__BitwiseAnd($ghost_x, $ghost_y)}trigger_fun_asm__BitwiseAnd($ghost_x, $ghost_y) ==> (true && (fun_word32($ghost_x)) && (fun_word32($ghost_y))) ==> (true && (fun_word32(fun_asm__BitwiseAnd($ghost_x, $ghost_y))) && ((forall $ghost__0_i:int :: {fun_IntBit($ghost__0_i, fun_asm__BitwiseAnd($ghost_x, $ghost_y))} ((INTERNAL_le_boogie(0, $ghost__0_i)) && (INTERNAL_lt_boogie($ghost__0_i, 32))) ==> ((fun_IntBit($ghost__0_i, fun_asm__BitwiseAnd($ghost_x, $ghost_y))) == ((fun_IntBit($ghost__0_i, $ghost_x)) && (fun_IntBit($ghost__0_i, $ghost_y)))))))); atomic procedure proc_asm__BitwiseAnd(my r_old:regs, $ghost_x:int, $ghost_y:int, $opn_x:int, $opn_y:opn) returns(my r:regs, $ghost___result:int); requires $ghost_x == r_old.regs[$opn_x]; requires $ghost_y == Eval(r_old, $opn_y); requires fun_word32($ghost_x); requires fun_word32($ghost_y); ensures $ghost___result == (fun_asm__BitwiseAnd($ghost_x, $ghost_y)); ensures fun_word32(fun_asm__BitwiseAnd($ghost_x, $ghost_y)); ensures (forall $ghost__0_i:int :: {fun_IntBit($ghost__0_i, fun_asm__BitwiseAnd($ghost_x, $ghost_y))} ((INTERNAL_le_boogie(0, $ghost__0_i)) && (INTERNAL_lt_boogie($ghost__0_i, 32))) ==> ((fun_IntBit($ghost__0_i, fun_asm__BitwiseAnd($ghost_x, $ghost_y))) == ((fun_IntBit($ghost__0_i, $ghost_x)) && (fun_IntBit($ghost__0_i, $ghost_y))))); ensures r.regs == r_old.regs[$opn_x := $ghost___result]; function trigger_fun_asm__BitwiseOr($ghost_x:int, $ghost_y:int):bool { true } atomic ghost procedure lemma_fun_ensures_fun_asm__BitwiseOr(); ensures (forall $ghost_x:int, $ghost_y:int::{fun_asm__BitwiseOr($ghost_x, $ghost_y)}{trigger_fun_asm__BitwiseOr($ghost_x, $ghost_y)}trigger_fun_asm__BitwiseOr($ghost_x, $ghost_y) ==> (true && (fun_word32($ghost_x)) && (fun_word32($ghost_y))) ==> (true && (fun_word32(fun_asm__BitwiseOr($ghost_x, $ghost_y))) && ((forall $ghost__0_i:int :: {fun_IntBit($ghost__0_i, fun_asm__BitwiseOr($ghost_x, $ghost_y))} ((INTERNAL_le_boogie(0, $ghost__0_i)) && (INTERNAL_lt_boogie($ghost__0_i, 32))) ==> ((fun_IntBit($ghost__0_i, fun_asm__BitwiseOr($ghost_x, $ghost_y))) == ((fun_IntBit($ghost__0_i, $ghost_x)) || (fun_IntBit($ghost__0_i, $ghost_y)))))))); atomic procedure proc_asm__BitwiseOr(my r_old:regs, $ghost_x:int, $ghost_y:int, $opn_x:int, $opn_y:opn) returns(my r:regs, $ghost___result:int); requires $ghost_x == r_old.regs[$opn_x]; requires $ghost_y == Eval(r_old, $opn_y); requires fun_word32($ghost_x); requires fun_word32($ghost_y); ensures $ghost___result == (fun_asm__BitwiseOr($ghost_x, $ghost_y)); ensures fun_word32(fun_asm__BitwiseOr($ghost_x, $ghost_y)); ensures (forall $ghost__0_i:int :: {fun_IntBit($ghost__0_i, fun_asm__BitwiseOr($ghost_x, $ghost_y))} ((INTERNAL_le_boogie(0, $ghost__0_i)) && (INTERNAL_lt_boogie($ghost__0_i, 32))) ==> ((fun_IntBit($ghost__0_i, fun_asm__BitwiseOr($ghost_x, $ghost_y))) == ((fun_IntBit($ghost__0_i, $ghost_x)) || (fun_IntBit($ghost__0_i, $ghost_y))))); ensures r.regs == r_old.regs[$opn_x := $ghost___result]; function trigger_fun_asm__BitwiseXor($ghost_x:int, $ghost_y:int):bool { true } atomic ghost procedure lemma_fun_ensures_fun_asm__BitwiseXor(); ensures (forall $ghost_x:int, $ghost_y:int::{fun_asm__BitwiseXor($ghost_x, $ghost_y)}{trigger_fun_asm__BitwiseXor($ghost_x, $ghost_y)}trigger_fun_asm__BitwiseXor($ghost_x, $ghost_y) ==> (true && (fun_word32($ghost_x)) && (fun_word32($ghost_y))) ==> (true && (fun_word32(fun_asm__BitwiseXor($ghost_x, $ghost_y))) && ((forall $ghost__0_i:int :: {fun_IntBit($ghost__0_i, fun_asm__BitwiseXor($ghost_x, $ghost_y))} ((INTERNAL_le_boogie(0, $ghost__0_i)) && (INTERNAL_lt_boogie($ghost__0_i, 32))) ==> ((fun_IntBit($ghost__0_i, fun_asm__BitwiseXor($ghost_x, $ghost_y))) == ((fun_IntBit($ghost__0_i, $ghost_x)) != (fun_IntBit($ghost__0_i, $ghost_y)))))))); atomic procedure proc_asm__BitwiseXor(my r_old:regs, $ghost_x:int, $ghost_y:int, $opn_x:int, $opn_y:opn) returns(my r:regs, $ghost___result:int); requires $ghost_x == r_old.regs[$opn_x]; requires $ghost_y == Eval(r_old, $opn_y); requires fun_word32($ghost_x); requires fun_word32($ghost_y); ensures $ghost___result == (fun_asm__BitwiseXor($ghost_x, $ghost_y)); ensures fun_word32(fun_asm__BitwiseXor($ghost_x, $ghost_y)); ensures (forall $ghost__0_i:int :: {fun_IntBit($ghost__0_i, fun_asm__BitwiseXor($ghost_x, $ghost_y))} ((INTERNAL_le_boogie(0, $ghost__0_i)) && (INTERNAL_lt_boogie($ghost__0_i, 32))) ==> ((fun_IntBit($ghost__0_i, fun_asm__BitwiseXor($ghost_x, $ghost_y))) == ((fun_IntBit($ghost__0_i, $ghost_x)) != (fun_IntBit($ghost__0_i, $ghost_y))))); ensures r.regs == r_old.regs[$opn_x := $ghost___result]; } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Main/DafnyAssembly.imp.beat ================================================ //-private-import BaseSpec; //-private-import MemorySpec; //-private-import IoTypesSpec; //-private-import MachineStateSpec; //-private-import AssemblySpec; //-private-import InterruptsSpec; //-private-import IoSpec; //- //- //- //- //- //-private-import Core; //-private-import LogicalAddressing; //-private-import Overflow; //-private-import Util; //-private-import Stacks; //-private-import Partition; //-private-import Instructions; //-private-import Separation; //-private-import IntLemmasBase; //-private-import IntLemmasGc; //-private-import SimpleGcMemory; //-private-import SimpleCommon; //-private-import SimpleCollector; //-private-import IoMain; //-private-import IntLemmasMain; //-private-basmonly-import Trusted; //-private-basmonly-import Checked; //-private-import Heap; //-private-import Seq; //-private-import dafny_DafnyPrelude; module implementation DafnyAssembly { implementation lemma_fun_ensures_fun_asm__Add() {} implementation lemma_fun_ensures_fun_asm__Sub() {} implementation lemma_fun_ensures_fun_asm__Mul() {} implementation lemma_fun_ensures_fun_asm__Div() {} implementation lemma_fun_ensures_fun_asm__Mod() {} implementation lemma_fun_ensures_fun_asm__LeftShift() { forall $ghost_x:int, $ghost_amount:int::{fun_asm__LeftShift($ghost_x, $ghost_amount)}{trigger_fun_asm__LeftShift($ghost_x, $ghost_amount)}trigger_fun_asm__LeftShift($ghost_x, $ghost_amount) ==> (true && (fun_word32($ghost_x)) && ((INTERNAL_le_boogie(0, $ghost_amount)) && (INTERNAL_lt_boogie($ghost_amount, 32)))) ==> (true && (fun_word32(fun_asm__LeftShift($ghost_x, $ghost_amount))) && ((forall $ghost_i:int :: {fun_IntBit($ghost_i, fun_asm__LeftShift($ghost_x, $ghost_amount))} ((INTERNAL_le_boogie(32 - $ghost_amount, $ghost_i)) && (INTERNAL_lt_boogie($ghost_i, 32))) ==> ((fun_IntBit($ghost_i, fun_asm__LeftShift($ghost_x, $ghost_amount))) == (false)))) && ((forall $ghost_i:int :: {fun_IntBit($ghost_i, fun_asm__LeftShift($ghost_x, $ghost_amount))} ((INTERNAL_le_boogie(0, $ghost_i)) && (INTERNAL_lt_boogie($ghost_i, 32 - $ghost_amount))) ==> ((fun_IntBit($ghost_i, fun_asm__LeftShift($ghost_x, $ghost_amount))) == (fun_IntBit($ghost_i + $ghost_amount, $ghost_x)))))) { call axiom_shl($ghost_x, $ghost_amount); call reveal_WORD_HI(); } } implementation lemma_fun_ensures_fun_asm__RightShift() { forall $ghost_x:int, $ghost_amount:int::{fun_asm__RightShift($ghost_x, $ghost_amount)}{trigger_fun_asm__RightShift($ghost_x, $ghost_amount)}trigger_fun_asm__RightShift($ghost_x, $ghost_amount) ==> (true && (fun_word32($ghost_x)) && ((INTERNAL_le_boogie(0, $ghost_amount)) && (INTERNAL_lt_boogie($ghost_amount, 32)))) ==> (true && (fun_word32(fun_asm__RightShift($ghost_x, $ghost_amount))) && ((forall $ghost_i:int :: {fun_IntBit($ghost_i, fun_asm__RightShift($ghost_x, $ghost_amount))} ((INTERNAL_le_boogie(0, $ghost_i)) && (INTERNAL_lt_boogie($ghost_i, $ghost_amount))) ==> ((fun_IntBit($ghost_i, fun_asm__RightShift($ghost_x, $ghost_amount))) == (false)))) && ((forall $ghost_i:int :: {fun_IntBit($ghost_i, fun_asm__RightShift($ghost_x, $ghost_amount))} ((INTERNAL_le_boogie($ghost_amount, $ghost_i)) && (INTERNAL_lt_boogie($ghost_i, 32))) ==> ((fun_IntBit($ghost_i, fun_asm__RightShift($ghost_x, $ghost_amount))) == (fun_IntBit($ghost_i - $ghost_amount, $ghost_x)))))) { call axiom_shr($ghost_x, $ghost_amount); call reveal_WORD_HI(); } } implementation lemma_fun_ensures_fun_asm__RotateLeft() { forall $ghost_x:int, $ghost_amount:int::{fun_asm__RotateLeft($ghost_x, $ghost_amount)}{trigger_fun_asm__RotateLeft($ghost_x, $ghost_amount)}trigger_fun_asm__RotateLeft($ghost_x, $ghost_amount) ==> (true && (fun_word32($ghost_x)) && ((INTERNAL_le_boogie(0, $ghost_amount)) && (INTERNAL_lt_boogie($ghost_amount, 32)))) ==> (true && (fun_word32(fun_asm__RotateLeft($ghost_x, $ghost_amount))) && ((forall $ghost_i:int :: {fun_IntBit($ghost_i, fun_asm__RotateLeft($ghost_x, $ghost_amount))} ((INTERNAL_le_boogie(0, $ghost_i)) && (INTERNAL_lt_boogie($ghost_i, 32 - $ghost_amount))) ==> ((fun_IntBit($ghost_i, fun_asm__RotateLeft($ghost_x, $ghost_amount))) == (fun_IntBit($ghost_i + $ghost_amount, $ghost_x))))) && ((forall $ghost_i:int :: {fun_IntBit($ghost_i, fun_asm__RotateLeft($ghost_x, $ghost_amount))} ((INTERNAL_le_boogie(32 - $ghost_amount, $ghost_i)) && (INTERNAL_lt_boogie($ghost_i, 32))) ==> ((fun_IntBit($ghost_i, fun_asm__RotateLeft($ghost_x, $ghost_amount))) == (fun_IntBit($ghost_i - (32 - $ghost_amount), $ghost_x)))))) { call axiom_rol($ghost_x, $ghost_amount); call reveal_WORD_HI(); } } implementation lemma_fun_ensures_fun_asm__RotateRight() { forall $ghost_x:int, $ghost_amount:int::{fun_asm__RotateRight($ghost_x, $ghost_amount)}{trigger_fun_asm__RotateRight($ghost_x, $ghost_amount)}trigger_fun_asm__RotateRight($ghost_x, $ghost_amount) ==> (true && (fun_word32($ghost_x)) && ((INTERNAL_le_boogie(0, $ghost_amount)) && (INTERNAL_lt_boogie($ghost_amount, 32)))) ==> (true && (fun_word32(fun_asm__RotateRight($ghost_x, $ghost_amount))) && ((forall $ghost_i:int :: {fun_IntBit($ghost_i, fun_asm__RotateRight($ghost_x, $ghost_amount))} ((INTERNAL_le_boogie(0, $ghost_i)) && (INTERNAL_lt_boogie($ghost_i, $ghost_amount))) ==> ((fun_IntBit($ghost_i, fun_asm__RotateRight($ghost_x, $ghost_amount))) == (fun_IntBit((32 - $ghost_amount) + $ghost_i, $ghost_x))))) && ((forall $ghost_i:int :: {fun_IntBit($ghost_i, fun_asm__RotateRight($ghost_x, $ghost_amount))} ((INTERNAL_le_boogie($ghost_amount, $ghost_i)) && (INTERNAL_lt_boogie($ghost_i, 32))) ==> ((fun_IntBit($ghost_i, fun_asm__RotateRight($ghost_x, $ghost_amount))) == (fun_IntBit($ghost_i - $ghost_amount, $ghost_x)))))) { call axiom_ror($ghost_x, $ghost_amount); call reveal_WORD_HI(); } } implementation lemma_fun_ensures_fun_asm__BitwiseNot() { forall $ghost_x:int::{fun_asm__BitwiseNot($ghost_x)} (true && (fun_word32($ghost_x))) ==> (true && (fun_word32(fun_asm__BitwiseNot($ghost_x))) && ((forall $ghost_i:int :: {fun_IntBit($ghost_i, fun_asm__BitwiseNot($ghost_x))} ((INTERNAL_le_boogie(0, $ghost_i)) && (INTERNAL_lt_boogie($ghost_i, 32))) ==> ((fun_IntBit($ghost_i, fun_asm__BitwiseNot($ghost_x))) == ((!(fun_IntBit($ghost_i, $ghost_x)))))))) { call axiom_neg($ghost_x); call reveal_WORD_HI(); } } implementation lemma_fun_ensures_fun_asm__BitwiseAnd() { forall $ghost_x:int, $ghost_y:int::{fun_asm__BitwiseAnd($ghost_x, $ghost_y)} (true && (fun_word32($ghost_x)) && (fun_word32($ghost_y))) ==> (true && (fun_word32(fun_asm__BitwiseAnd($ghost_x, $ghost_y))) && ((forall $ghost_i:int :: {fun_IntBit($ghost_i, fun_asm__BitwiseAnd($ghost_x, $ghost_y))} ((INTERNAL_le_boogie(0, $ghost_i)) && (INTERNAL_lt_boogie($ghost_i, 32))) ==> ((fun_IntBit($ghost_i, fun_asm__BitwiseAnd($ghost_x, $ghost_y))) == ((fun_IntBit($ghost_i, $ghost_x)) && (fun_IntBit($ghost_i, $ghost_y))))))) { call axiom_and($ghost_x, $ghost_y); call reveal_WORD_HI(); } } implementation lemma_fun_ensures_fun_asm__BitwiseOr() { forall $ghost_x:int, $ghost_y:int::{fun_asm__BitwiseOr($ghost_x, $ghost_y)} (true && (fun_word32($ghost_x)) && (fun_word32($ghost_y))) ==> (true && (fun_word32(fun_asm__BitwiseOr($ghost_x, $ghost_y))) && ((forall $ghost_i:int :: {fun_IntBit($ghost_i, fun_asm__BitwiseOr($ghost_x, $ghost_y))} ((INTERNAL_le_boogie(0, $ghost_i)) && (INTERNAL_lt_boogie($ghost_i, 32))) ==> ((fun_IntBit($ghost_i, fun_asm__BitwiseOr($ghost_x, $ghost_y))) == ((fun_IntBit($ghost_i, $ghost_x)) || (fun_IntBit($ghost_i, $ghost_y))))))) { call axiom_or($ghost_x, $ghost_y); call reveal_WORD_HI(); } } implementation lemma_fun_ensures_fun_asm__BitwiseXor() { forall $ghost_x:int, $ghost_y:int::{fun_asm__BitwiseXor($ghost_x, $ghost_y)} (true && (fun_word32($ghost_x)) && (fun_word32($ghost_y))) ==> (true && (fun_word32(fun_asm__BitwiseXor($ghost_x, $ghost_y))) && ((forall $ghost_i:int :: {fun_IntBit($ghost_i, fun_asm__BitwiseXor($ghost_x, $ghost_y))} ((INTERNAL_le_boogie(0, $ghost_i)) && (INTERNAL_lt_boogie($ghost_i, 32))) ==> ((fun_IntBit($ghost_i, fun_asm__BitwiseXor($ghost_x, $ghost_y))) == ((fun_IntBit($ghost_i, $ghost_x)) != (fun_IntBit($ghost_i, $ghost_y))))))) { call axiom_xor($ghost_x, $ghost_y); call reveal_WORD_HI(); } } implementation proc_asm__Add(my r_old:regs, $ghost_x:int, $ghost_y:int, $opn_x:int, $opn_y:opn) returns(my r:regs, $ghost___result:int) { r := r_old; call reveal_WORD_HI(); call reveal_wrap32($ghost_x + $ghost_y); call r := instr_Add(r, $opn_x, $opn_y); $ghost___result := fun_asm__Add($ghost_x, $ghost_y); } implementation proc_asm__Sub(my r_old:regs, $ghost_x:int, $ghost_y:int, $opn_x:int, $opn_y:opn) returns(my r:regs, $ghost___result:int) { r := r_old; call reveal_WORD_HI(); call reveal_wrap32($ghost_x - $ghost_y); call r := instr_Sub(r, $opn_x, $opn_y); $ghost___result := fun_asm__Sub($ghost_x, $ghost_y); } implementation Proc_asm__Mul(my r_old:regs, const my core_state:core_state, linear stk_old:mem, linear statics_old:mem, linear io_old:IOState, linear mems_old:mems, $commonVars_old:commonVars, $gcVars_old:gcVars, $toAbs_old:[int]int, $absMem_old:[int][int]int, $stacksFrames_old:[int]Frames, objLayouts_old:[int]ObjLayout, heap_old:Heap, $ghost_x:int, $ghost_y:int) returns(my r:regs, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars, $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap, $ghost___result:int) { r := r_old; stk := stk_old; statics := statics_old; io := io_old; mems := mems_old; $commonVars := $commonVars_old; $gcVars := $gcVars_old; $toAbs := $toAbs_old; $absMem := $absMem_old; $stacksFrames := $stacksFrames_old; objLayouts := objLayouts_old; heap := heap_old; assert TV(esp) && TO(0) && TO(1) && TO(2) && TO(3) && TO(4); #ifdef x64 call eax := Load(stk, esp + 12); call ebx := Load(stk, esp + 16); #else call eax := Load(stk, esp + 8); call ebx := Load(stk, esp + 12); #endif call reveal_WORD_HI(); call reveal_wrap32(eax * ebx); call eax, edx := MulWrap(eax, ebx); assert TVM($ghost_x, $ghost_y); #ifdef x64 call Store(inout stk, esp + 8, eax); #else call Store(inout stk, esp + 4, eax); #endif $ghost___result := fun_asm__Mul($ghost_x, $ghost_y); Return; } implementation proc_asm__Mul64(my r_old:regs, $ghost_x:int, $ghost_y:int, $opn_hi:int, $opn_x:int, $opn_y:opn) returns(my r:regs, $ghost_hi:int, $ghost_lo:int) { r := r_old; call r := instr_Mul64(r, $opn_y); assert TVM($ghost_x, $ghost_y); assert TVD($ghost_x * $ghost_y, 0x100000000); $ghost_lo := (fun_mod0x100000000($ghost_x * $ghost_y)); $ghost_hi := ($ghost_x * $ghost_y) div 0x100000000; forall :: $ghost_hi == Div(Mult($ghost_x, $ghost_y), 4294967296) && $ghost_lo == wrap32(Mult($ghost_x, $ghost_y)) { call reveal_wrap32(Mult($ghost_x, $ghost_y)); } } implementation Proc_asm__Div(my r_old:regs, const my core_state:core_state, linear stk_old:mem, linear statics_old:mem, linear io_old:IOState, linear mems_old:mems, $commonVars_old:commonVars, $gcVars_old:gcVars, $toAbs_old:[int]int, $absMem_old:[int][int]int, $stacksFrames_old:[int]Frames, objLayouts_old:[int]ObjLayout, heap_old:Heap, $ghost_x:int, $ghost_y:int) returns(my r:regs, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars, $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap, $ghost___result:int) { r := r_old; stk := stk_old; statics := statics_old; io := io_old; mems := mems_old; $commonVars := $commonVars_old; $gcVars := $gcVars_old; $toAbs := $toAbs_old; $absMem := $absMem_old; $stacksFrames := $stacksFrames_old; objLayouts := objLayouts_old; heap := heap_old; assert TV(esp) && TO(0) && TO(1) && TO(2) && TO(3) && TO(4); #ifdef x64 call eax := Load(stk, esp + 12); call ebx := Load(stk, esp + 16); #else call eax := Load(stk, esp + 8); call ebx := Load(stk, esp + 12); #endif call edx := Mov(0); call reveal_WORD_HI(); call reveal_wrap32(eax div ebx); call eax, edx := Div(eax, edx, ebx); #ifdef x64 call Store(inout stk, esp + 8, eax); #else call Store(inout stk, esp + 4, eax); #endif $ghost___result := fun_asm__Div($ghost_x, $ghost_y); Return; } implementation Proc_asm__Mod(my r_old:regs, const my core_state:core_state, linear stk_old:mem, linear statics_old:mem, linear io_old:IOState, linear mems_old:mems, $commonVars_old:commonVars, $gcVars_old:gcVars, $toAbs_old:[int]int, $absMem_old:[int][int]int, $stacksFrames_old:[int]Frames, objLayouts_old:[int]ObjLayout, heap_old:Heap, $ghost_x:int, $ghost_y:int) returns(my r:regs, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars, $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap, $ghost___result:int) { r := r_old; stk := stk_old; statics := statics_old; io := io_old; mems := mems_old; $commonVars := $commonVars_old; $gcVars := $gcVars_old; $toAbs := $toAbs_old; $absMem := $absMem_old; $stacksFrames := $stacksFrames_old; objLayouts := objLayouts_old; heap := heap_old; assert TV(esp) && TO(0) && TO(1) && TO(2) && TO(3) && TO(4); #ifdef x64 call eax := Load(stk, esp + 12); call ebx := Load(stk, esp + 16); #else call eax := Load(stk, esp + 8); call ebx := Load(stk, esp + 12); #endif call edx := Mov(0); call reveal_WORD_HI(); call reveal_wrap32(eax div ebx); call eax, edx := Div(eax, edx, ebx); #ifdef x64 call Store(inout stk, esp + 8, edx); #else call Store(inout stk, esp + 4, edx); #endif $ghost___result := fun_asm__Mod($ghost_x, $ghost_y); Return; } implementation proc_asm__LeftShift(my r_old:regs, $ghost_x:int, $ghost_amount:int, $opn_x:int, $opn_amount:opn) returns(my r:regs, $ghost___result:int) { r := r_old; call r := instr_Shl(r, $opn_x, $opn_amount); $ghost___result := fun_asm__LeftShift($ghost_x, $ghost_amount); call lemma_fun_ensures_fun_asm__LeftShift(); } implementation proc_asm__RightShift(my r_old:regs, $ghost_x:int, $ghost_amount:int, $opn_x:int, $opn_amount:opn) returns(my r:regs, $ghost___result:int) { r := r_old; call r := instr_Shr(r, $opn_x, $opn_amount); $ghost___result := fun_asm__RightShift($ghost_x, $ghost_amount); call lemma_fun_ensures_fun_asm__RightShift(); } implementation proc_asm__RotateLeft(my r_old:regs, $ghost_x:int, $ghost_amount:int, $opn_x:int, $opn_amount:opn) returns(my r:regs, $ghost___result:int) { r := r_old; call r := instr_Rol(r, $opn_x, $opn_amount); $ghost___result := fun_asm__RotateLeft($ghost_x, $ghost_amount); call lemma_fun_ensures_fun_asm__RotateLeft(); } implementation proc_asm__RotateRight(my r_old:regs, $ghost_x:int, $ghost_amount:int, $opn_x:int, $opn_amount:opn) returns(my r:regs, $ghost___result:int) { r := r_old; call r := instr_Ror(r, $opn_x, $opn_amount); $ghost___result := fun_asm__RotateRight($ghost_x, $ghost_amount); call lemma_fun_ensures_fun_asm__RotateRight(); } implementation proc_asm__BitwiseNot(my r_old:regs, $ghost_x:int, $opn_x:int) returns(my r:regs, $ghost___result:int) { r := r_old; call r := instr_Not(r, $opn_x); $ghost___result := fun_asm__BitwiseNot($ghost_x); call lemma_fun_ensures_fun_asm__BitwiseNot(); } implementation proc_asm__BitwiseAnd(my r_old:regs, $ghost_x:int, $ghost_y:int, $opn_x:int, $opn_y:opn) returns(my r:regs, $ghost___result:int) { r := r_old; call r := instr_And(r, $opn_x, $opn_y); $ghost___result := fun_asm__BitwiseAnd($ghost_x, $ghost_y); call lemma_fun_ensures_fun_asm__BitwiseAnd(); } implementation proc_asm__BitwiseOr(my r_old:regs, $ghost_x:int, $ghost_y:int, $opn_x:int, $opn_y:opn) returns(my r:regs, $ghost___result:int) { r := r_old; call r := instr_Or(r, $opn_x, $opn_y); $ghost___result := fun_asm__BitwiseOr($ghost_x, $ghost_y); call lemma_fun_ensures_fun_asm__BitwiseOr(); } implementation proc_asm__BitwiseXor(my r_old:regs, $ghost_x:int, $ghost_y:int, $opn_x:int, $opn_y:opn) returns(my r:regs, $ghost___result:int) { r := r_old; call r := instr_Xor(r, $opn_x, $opn_y); $ghost___result := fun_asm__BitwiseXor($ghost_x, $ghost_y); call lemma_fun_ensures_fun_asm__BitwiseXor(); } } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Main/Entry.imp.beat ================================================ // Uh-oh: it looks like whether we need Symdiff in Main depends // on what app we're compiling! DafnyCCTest (nee Cube) didn't need it. // I guess as long as it's always *allowed*, we'll just pay for it // too often. // jonh: deleting all these import rules; we'll pick the correct // set up from dafny_Main_i via HorribleEntryStitcher. // Except we definitely need to add this one in: //private-import dafny_Main_i; // And we need annotations, which Horrible isn't transferring: //- //- //- //- //- //- //-private-disabled BaseSpec; //-private-disabled MemorySpec; //-private-disabled IoTypesSpec; //-private-disabled MachineStateSpec; //-private-disabled AssemblySpec; //-private-disabled InterruptsSpec; //-private-disabled IoSpec; //-private-disabled Core; //-private-disabled LogicalAddressing; //-private-disabled Overflow; //-private-disabled Stacks; //-private-disabled Partition; //-private-disabled Instructions; //-private-disabled Util; //-private-disabled Separation; //-private-disabled IntLemmasBase; //-private-disabled IntLemmasGc; //-private-disabled SimpleGcMemory; //-private-disabled SimpleCommon; //-private-disabled SimpleCollector; //-private-disabled IoMain; //-private-disabled IntLemmasMain; //-private-basmonly-disabled Trusted; //-private-basmonly-disabled Checked; //-private-disabled Heap; //-private-disabled Seq; //-private-disabled dafny_DafnyPrelude; //-private-disabled DafnyAssembly; //-private-disabled dafny_relational_s; //-private-disabled dafny_base_s; //-private-disabled dafny_power2_s; //-private-disabled dafny_mul_i; //-private-disabled dafny_assembly_i; //-private-disabled dafny_bit_vector_lemmas_i; //-private-import AppLoaderContract; //-private-import ExtendedAssembly; //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- //- Entry points from the outside world (e.g. from boot loader, interrupts, TAL code, etc.) module implementation Entry { #ifdef AppLoader implementation LoaderEntryPoint( my r_in:regs, my core_state_in:core_state, linear initState_in:InitStateMachine, linear mem_in:mem, linear io_in:IOState, linear dev_states_in:DEV_StateMachines, $sl_len:int, $cpu_info:int) #else implementation AppEntryPoint( my r_in:regs, my core_state_in:core_state, linear initState_in:InitStateMachine, linear mem_in:mem, linear code_mem:mem, linear io_in:IOState, app_entry:int, app_code_base:int, code_word_seq:Seq___int ) #endif { call reveal_MemInvDetails(); assert ?fLo - ?sLo == stackGcOffset; my var r:regs := r_in; my var core_state:core_state := core_state_in; linear var initState:InitStateMachine := initState_in; linear var mem:mem := mem_in; linear var stk:mem; linear var statics:mem; linear var static_mem:mem; linear var io:IOState := io_in; #ifdef AppLoader ecx := 0x300000; #else ecx := 0x340000; #endif if (eax != ecx) { //- We were loaded at the wrong address! eax := 0x55550001; call debugBreak(); } call initState, static_mem := enableStatics(initState); assert ?memLo <= esp - 6*?SegmentDescriptorSize; assert esp <= ?memHi; // assert esp == 0x310000; // call reveal_Aligned(0x310000); assert TV(?CodeBase) && TO(123*1024*256) && TO(0x4000); assert Aligned(esp); #ifdef AppLoader //- Other apps require the loader to take care of this call fixupDS(); #endif call enableLogicalAddressing(); // edx := 300; // eax := 0x112233; // call writeHex(); // //dummyLoop: // goto dummyLoop; #ifdef AppLoader linear var new_mem:mem; linear var dev_mem:mem; //- Initialize additional DEV protection, so we have more protected memory to work with call dev_mem := memEmpty(); call mem, dev_mem := memTransfer(mem, dev_mem, (lambda i:int :: ?DEVLo <= i && i < ?DEVHi)); assert (forall i:int :: {dev_mem.dom[i]} TV(i) ==> (dev_mem.dom[i] <==> (?DEVLo <= i && i < ?DEVHi))); linear var dev_states:DEV_StateMachines := dev_states_in; call new_mem := initDEV(dev_states, dev_mem); //- Merge the statics, the large swath of DEV-protected mem, and our original mem call static_mem, mem := memTransfer(static_mem, mem, (lambda i:int :: static_mem.dom[i])); call new_mem, mem := memTransfer(new_mem, mem, (lambda i:int :: new_mem.dom[i])); #else //- Merge the statics and our original mem call static_mem, mem := memTransfer(static_mem, mem, (lambda i:int :: static_mem.dom[i])); #endif //- Initialize separation module linear var mems:mems; linear var appCodeMem:mem; #ifdef AppLoader ebx := 0x10000; ecx := 0x300000; #else ebx := 0x100000; ecx := 0x340000; #endif assert ebx == ?CodeSpace; assert ecx == ?CodeBase; ebp := ecx; ecx := ecx + ebx; ecx := ecx + 0x1F000; edx := 0x08000000; assert ecx == ?sLo; call reveal_Aligned(?sLo); call stk, statics, mems, appCodeMem := initSeparation(mem); //- Switch to nucleus stack esp := DLo; call espAligned(); call esp := Sub(esp, 16); //- Initialize GC var $absMem:[int][int]int := (lambda i:int::(lambda j:int::0)); var $toAbs:[int]int := (lambda i:int::NO_ABS); var $stacksFrames:[int]Frames := (lambda i:int::Frames((lambda j:int::0))); var objLayouts:[int]ObjLayout := (lambda i:int::NoObjLayout()); var heap:Heap; var _mem:[int]int; var _val:int; call heap := initHeap($absMem, objLayouts); ebp := 0; call initCommon(); //- Initialize IO-related invariants call initializeSerialPort(); #ifdef AppLoader esi := 0xdd00001; call serialDbgWordOut(); call serialDbgNewlineOut(); #else esi := 0xaa00001; call serialDbgWordOut(); call serialDbgNewlineOut(); #endif #ifdef AppLoader ebx := 0x32F000; #else ebx := 0x45F000; #endif assert ebx == ?sLo; ebx := ebx + 4096; //- Skip the stack assert ebx == ?sHi; ebx := ebx + 1024; //- Skip the data assert ebx == ?dHi; ebx := ebx + 1024; //- Args assert ebx == ?argHi; ecx := ebx; edx := ecx; edx := edx + 1024; assert ecx == ?pciLo; assert edx == ?pciHi; call initIoInv(); call InitializeGc(); #ifdef AppLoader //- Call the Loader's Main Dafny procedure which needs more arguments than usual //- Build an array containing the words of the app code call alignCall(r.regs[ESP]); var code_words:ArrayOfInt; {: call := logical_Call(inout r, core_state, inout stk); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, code_words := Proc_ArrayAlloc(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, appCodeMem); :} //assert SMemInvGcF(16, stk, old(stk_old), r.regs[ESP] + 12, old(r_old.regs[ESP]), $stacksFrames, $stacksFrames_old); #ifdef AppLoader esi := 0xdd00010; call serialDbgWordOut(); call serialDbgNewlineOut(); #endif assert (forall j:int :: 0 <= j && j < Arr_Length(code_words) ==> fun_INTERNAL__array__elems__index($absMem[code_words.arrAbs], j) == appCodeMem.map[0x340000 + j*4]); assert (Arr_Length(code_words) == 256*1024); call proc_Seq__FromArray__Length(); assert (fun_Seq__Length___int(fun_Seq__FromArray($absMem, code_words)) == 256*1024); call proc_Seq__FromArray__Index(); assert (forall j:int :: 0 <= j && j < 256*1024 ==> fun_Seq__Index___int(fun_Seq__FromArray($absMem, code_words), j) == fun_INTERNAL__array__elems__index($absMem[code_words.arrAbs], j)); assert (forall j:int :: 0 <= j && j < 256*1024 ==> fun_Seq__Index___int(fun_Seq__FromArray($absMem, code_words), j) == appCodeMem.map[0x340000 + j*4]); //- We expect the code to be here ecx := 0x340000; assert ecx == ?appCodeLo; call reveal_MemInvDetails(); //- Shows that ?appCodeLo is sane var code_start:int := ecx; call Store(inout stk, esp + 4, ecx); //- First arg from the boot loader is the entry of the app code ecx := 0x330400; //-0x32F800; //0x316800; assert ecx == ?argLo; call reveal_MemInvDetails(); //- Shows that ArgLo is sane call ecx := Load($argMem, ecx); var entry_point:int := ecx; call Store(inout stk, esp + 8, ecx); // pop return value #0 at index 0 into destination code_words isPtr = True // regalloc_stack_load:: EAX := OMem(MReg(ESP, 1052672)) // var = code_words 1437 // call r, mems := heapLoadStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, ECX, OMem(MReg(ESP, 0x101000)), EvalPtr(r, OMem(MReg(ESP, 0x101000)))); // var code_words:int := frameGet($stacksFrames, EvalPtr(r, OMem(MReg(ESP, 0x101000)))); // call Store(inout stk, esp + 12, ecx); call reveal_WORD_HI(); var $result:int; call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $result := Proc_Main(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, code_start, entry_point, code_words); call eax := Load(stk, esp); assert eax == entry_point; edi := eax; //- Save eax == entry_point #ifdef AppLoader esi := 0xdd00100; call serialDbgWordOut(); call serialDbgNewlineOut(); #endif eax := edi; //- Restore eax == entry_point assert eax == entry_point; ebx := 0x32F000; ebx := ebx + 4096; ebx := ebx + 1024; ebx := ebx + 1024; ecx := ebx; edx := ecx; edx := edx + 1024; assert ecx == ?pciLo; assert edx == ?pciHi; ebx := eax; call checkIoFresh(); eax := ebx; assert eax == entry_point; ecx := eax; eax := 0x340000; ebx := ecx; call reveal_Aligned(eax); if (ebx < eax) { eax := 0x555500a1; call debugBreak(); //- App entry is below start of app code } ebx := eax; ebx := ebx + 0x100000; assert ebx == code_start + 0x100000; if (ecx >= ebx) { eax := 0x555500a2; call debugBreak(); //- App entry is beyond end of app code } ebx := ecx; assert eax == code_start; assert ebx == entry_point; // assert code_start <= entry_point; // assert entry_point < code_start + 0x100000; assert code_start <= entry_point && entry_point < code_start + 0x100000; // assert ?CodeBase == 0x300000; // assert ?memLo == ?CodeBase + 58*1024; // assert code_start == 0x32FC00; // assert ?memLo < code_start; // assert ?memLo < code_start + 0x100000; // assert ?memHi >= code_start + 120*1024*1024; ecx := eax; ecx := ecx + 0x7B00000; esp := ecx; assert code_start == ?appCodeLo; assert ?gcLo == code_start + 0x101000; //assert ?gcHi == code_start + 123*1024*1024; linear var dat:mem; linear var arg:mem; linear var pci:mem; linear var gc:mem; linear var frm:mem; var frms:[int][int]int; linear var tcb:mem; var tcbs:[int][int]int; let mems(dat, arg, pci, gc, frm, frms, tcb, tcbs) := mems; linear var app_mem:mem; call app_mem := memEmpty(); call gc, app_mem := memTransfer(gc, app_mem, (lambda i:int :: code_start + 0x101000 <= i && i < 0x08000000)); call logical_inv_is_flat(); assert core_state.seg_regs[SS].descriptor.segBase == 0 && core_state.seg_regs[SS].descriptor.segType == ?SegmentDescriptorTypeData; assert core_state.seg_regs[DS].descriptor.segBase == 0 && core_state.seg_regs[DS].descriptor.segType == ?SegmentDescriptorTypeData; call proc_Seq__FromArray__Index(); assert (forall j:int :: 0 <= j && j < 256*1024 ==> fun_Seq__Index___int(fun_Seq__FromArray($absMem, code_words), j) == appCodeMem.map[code_start + j*4]); //assert (forall i:int:: code_start + 0x100800 <= i && i < code_start + 123*1024*1024 <==> gc.dom[i]); edi := eax; //- Save EAX ebp := ebx; //- Save EBX #ifdef AppLoader esi := 0xdd0f000; call serialDbgWordOut(); call serialDbgNewlineOut(); #endif eax := edi; //- restore ebx := ebp; //- restore //- Transfer all of the bootloader args from our arg region to the app's ecx := 0x330400; assert ecx == ?argLo; call reveal_MemInvDetails(); //- Shows that ArgLo is sane // call ecx := Load($argMem, ecx); edx := ecx; edx := edx + 1024; assert edx == ?argHi; edi := 0x340000; edi := edi + 0x100000; edi := edi + 0x1F000; //- App's ?sLo edi := edi + 4096; //- App's dLo edi := edi + 1024; //- App's dHi/argLo var ctr:int := 0; call reveal_Aligned(0x330400); call reveal_Aligned(0x340000 + 0x100000 + 0x1F000 + 4096 + 1024); assert EvalPtrOk(OMem(MReg(EDI, 0))); assert Aligned(EvalPtr(r, OMem(MReg(EDI, 0)))); assert PhysPtrOk(app_mem, EvalPtr(r, OMem(MReg(EDI, 0)))); assert word(EvalPtr(r, OMem(MReg(EDI, 0)))); while (ecx < edx) invariant edx == ?argHi; invariant 0 <= ctr && ctr <= 256; invariant ecx == ?argLo + ctr * 4; invariant edi == 0x340000 + 0x100000 + 0x1F000 + 4096 + 1024 + ctr * 4; invariant ?argLo <= ecx && ecx <= ?argHi; invariant ?gcLo <= edi && edi < ?gcHi; invariant ecx < edx ==> LogicalSrcOk(r, core_state, arg, OMem(MReg(ECX, 0))); invariant !init; invariant (forall j:int :: app_mem.dom[j] == (code_start + 0x101000 <= j && j < 0x08000000)); invariant ecx < edx ==> LogicalDstOk(init, r, core_state, app_mem, OMem(MReg(EDI, 0))); invariant eax == code_start; invariant ebx == entry_point; invariant public(ctr); invariant public(io._inCtr); invariant public(io._outCtr); { assert TV(?argLo) && TO(ctr); assert TV(0x340000 + 0x100000 + 0x1F000 + 4096 + 1024) && TO(ctr); call ebp := Load(arg, ecx); call Store(inout app_mem, edi, ebp); ecx := ecx + 4; edi := edi + 4; ctr := ctr + 1; assert TV(?argLo) && TO(ctr); assert TV(0x340000 + 0x100000 + 0x1F000 + 4096 + 1024) && TO(ctr); assert EvalPtrOk(OMem(MReg(EDI, 0))); assert Aligned(EvalPtr(r, OMem(MReg(EDI, 0)))); assert PhysPtrOk(app_mem, EvalPtr(r, OMem(MReg(EDI, 0)))); assert word(EvalPtr(r, OMem(MReg(EDI, 0)))); } assert eax == code_start; assert ebx == entry_point; //- Readjust esp ecx := eax; ecx := ecx + 0x7B00000; esp := ecx; call instr_Launch(r, core_state, initState, app_mem, appCodeMem, io, entry_point, code_start, fun_Seq__FromArray($absMem, code_words)) ; #else #ifndef AppLoader esi := 0xaa00100; call serialDbgWordOut(); call serialDbgNewlineOut(); #endif //- Call the Main Dafny procedure with contains all of the app logic var $result:int; ecx := 5; call Store(inout stk, esp + 4, ecx); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $result := Proc_Main(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap); call eax := Load(stk, esp); edx := 140; call writeHex(); #ifndef AppLoader esi := 0xaa01000; call serialDbgWordOut(); call serialDbgNewlineOut(); #endif ebp := 0; call GarbageCollect(); #endif myInfLoop: invariant logical_addressing_inv(init, ptMem, core_state); // eax := 0x12345678; // edx := 140; // call writeHex(); goto myInfLoop; ////Can no longer turn on paging, since we don't have enough space! // // // Test out paging ************** // // // Check that there's enough rooom for page tables // // 0x402000 = ?pageDirSize + ?numPDEs * ?pageTableSize + 4096 (padding to ensure 4k aligned) // eax := ecx; // call eax := AddChecked(eax, 0x402000); // if (eax >= edx) { // call debugBreak(); // } // // // Adjust to ensure we're 4k aligned // eax := ecx; // call eax := And(eax, 0xFFFFF000); // call clear_12_lemma(); // assert(eax == ClearLSBs(12, ecx)); // call clear_select_consistent_lemma(); // assert(Aligned4k(eax)); // assert(aligned4k(eax)); // call clear_less_than_equal_lemma(); // assert(le(eax, ecx)); // call eax := Add(eax, 0x1000); // assert(eax == add(ClearLSBs(12, ecx), 0x1000)); // call alignment_4k_is_mod4096_lemma(); // // // eax points to the address at which we want to build all of our page tables // assert aligned4k(eax); // call enablePaging(eax); // // call setInit(); //// // Try writing to the guard region //// eax := 4095; //// call ecx := RoLoad32(eax); // call initializeSerialPort(); //serialInfLoop: // ecx := 0x4a; // call serialDbgDataOut8(); // goto serialInfLoop; eax := 0; edx := 0; ebx := 0; edi := 0; ebp := 0; edx := 0; call writeHex(); //ecx := 10; //call core, mems, $r := Proc_pad_one_block(core, mems, 10); //call core, mems := Proc_one_time_pad(core, mems); pagingTestLoop: invariant logical_addressing_inv(init, ptMem, core_state); invariant init; eax := 0x98765432; edx := 20; call writeHex(); goto pagingTestLoop; // End paging test *************** // var idtLo @ stk[esp + 0] := ebx; // // // Set up interrupt table // var entry@edi := 0; // var ptr@esi := idtLo; // while (entry < 256) // invariant entry >= 0 && TV(entry); // invariant ptr == idtLo + 8 * entry; // invariant (forall i:int::{TV(i)} TV(i) ==> 0 <= i && i < entry ==> // $IdtMemOk[?idtLo + 8 * i] && $IdtMemOk[?idtLo + 8 * i + 4]); // invariant MemInv($Mem_Vars); // invariant esp == DLo - 12; // { // var handler @ stk[esp + 4]; //// //// if (entry == 0) { handler := ?FaultHandler; } //// else {if(entry == 3) { handler := ?FaultHandler; } //// else {if(entry == 4) { handler := ?FaultHandler; } //// else {if(entry == 13) { handler := ?ErrorHandler; } //// else {if(entry == 14) { handler := ?ErrorHandler; } //// else {if(entry < 32) { handler := ?FatalHandler; } //// else { handler := ?InterruptHandler; }}}}}} //// // handler := ?FatalHandler; // // edx := handler; // call edx := And(edx, 0x0000ffff); // ecx := 0x20; // call ecx := Shl(ecx, 16); // call ecx := Or(ecx, edx); // assert ecx == or(shl(?CodeSegmentSelector, 16), and(handler, ?Mask16Lo)); // call IdtStore(entry, 0, handler, ptr, ecx); // // ecx := handler; // edx := 0xffff0000; // call ecx := And(ecx, edx); // call ecx := Or(ecx, 0x8e00); // call IdtStore(entry, 4, handler, ptr + 4, ecx); // // ptr := ptr + 8; // entry := entry + 1; // } // // // Set IDT register // ecx := idtLo; // edi := DLo; // call ecx := Shl(ecx, 16); // call ecx := Or(ecx, 2047); // call Store(mems.dat[edi], ecx); // ecx := idtLo; // call ecx := Shr(ecx, 16); // assert TV(DLo) && TO(1); // call Store(mems.dat[edi + 4], ecx); // call Lidt(edi); // // // Set up PIC // eax := 0x11; edx := 0x20; call PicOut8(0, 0, 0); // eax := 0x11; edx := 0xa0; call PicOut8(1, 0, 0); // eax := 0x70; edx := 0x21; call PicOut8(0, 1, 1); // eax := 0x78; edx := 0xa1; call PicOut8(1, 1, 1); // eax := 0x04; edx := 0x21; call PicOut8(0, 1, 2); // eax := 0x02; edx := 0xa1; call PicOut8(1, 1, 2); // eax := 0x01; edx := 0x21; call PicOut8(0, 1, 3); // eax := 0x01; edx := 0xa1; call PicOut8(1, 1, 3); // eax := 0xfe; edx := 0x21; call PicOut8(0, 1, 4); // eax := 0xff; edx := 0xa1; call PicOut8(1, 1, 4); // eax := 0x20; edx := 0x20; call PicOut8(0, 0, 5); // eax := 0x20; edx := 0xa0; call PicOut8(1, 0, 5); // // // Set up PCI table // entry := 0; // ptr := PciLo; // while (entry < 65536) // invariant 0 <= entry && entry <= 65536; // invariant ptr == PciLo + 8 * entry; // invariant (forall i:int::{TV(i)} TV(i) ==> 0 <= i && i < entry ==> // $pciMem[PciLo + 8 * i] == 0 && $PciConfigState[i] == 0); // invariant MemInv($Mem_Vars); // invariant esp == DLo - 12; // { // assert TV(PciLo) && TO(entry * 2); // call Store(mems.pci[ptr], 0); // entry := entry + 1; // ptr := ptr + 8; // } // call reveal_IoInv(); // // // Set up IO-MMU tables // assert TV(?memLo) && TO(0 - 18 * 256 * 1024); // ecx := idtLo; ecx := ecx + 2048; // call SetupIoTables(); // ebx := eax; // // // Set up IO-MMU // ebp := idtLo; ebp := ebp + 0x10800; // call StartIoMmu(); // // // Set initial timer // ecx : = 0; // call startTimer(); // // // Set state of all managed stacks to empty // var s @ stk[esp + 8] := 0; // ecx := TLo; // while (s < ?NumStacks) // invariant s >= 0; // invariant ecx == ?tLo + s * ?TSize; // invariant Aligned(ecx); // invariant (forall $s:int::{TStk($s)} TStk($s) ==> $s < s ==> isStack($s) ==> StackTag($s, $tMems) == ?STACK_EMPTY); // invariant MemInv($Mem_Vars); // invariant esp == DLo - 12; // invariant IoInv($IoVars, $pciMem); // { // assert TV(ecx) && TO(2) && TO(64); // call Store(mems.tcb[s][ecx], ?STACK_EMPTY); // ecx := ecx + ?TSize; // call s := Add(s, 1); // } // // esi := 0; // infloop: // edx := 140; // call esi := LeaUnchecked(esi + 1); // eax := esi; // call writeHex(); // goto infloop; // // // Initialize GC // call initCommon(); // CurrentStack := ?InitialStack; // ebp := 0; // // // assert $S == ?InitialStack; // // assert (forall $s:int::{$StackState[$s]} 0 <= $s && $s < ?NumStacks ==> StackStateTag($StackState[$s]) == ?STACK_EMPTY); // // assert (forall i:int::{TV(i)} $toAbs[i] == NO_ABS); // call InitializeGc(); // // // Switch to initial managed stack // eax := FLo; eax := eax + ?StackReserve; eax := eax + ?InterruptReserve; // StackCheck := eax; // assert FLo == ?fLo; // esp := FLo; esp := esp + ?FSize; esp := esp - 8; // assert TV(FLo) && TO(4094) && TO(4095); // edi := TLo; // assert TV(TLo) && TO(2); // // ecx := ?KernelEntryPoint; // call setStackRunning1(0); // ebp := 0; // // return; //*/ edx := 140; call writeHex(); eax := 0x55550001; call debugBreak(); // not reached return; } //procedure BuildCodeWordArray(); // inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars; // inout $absMem:[int][int]int, $toAbs:[int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout; // requires NucleusInv(objLayouts, $S, $toAbs, $absMem, GcVars, $Mem_Vars, $stacksFrames, $IoVars); // requires SMemRequireRA(212, stk, esp, RET); // modifies efl, eax, ebx, ecx, esp, stk; // // postcondition same as precondition, plus reached: // ensures NucleusInv(objLayouts, $S, $toAbs, $absMem, GcVars, $Mem_Vars, $stacksFrames, $IoVars); // ensures SMemEnsure(stk, old(stk), esp, old(esp)); //{ // // //} #ifdef AppLoader const stack_size__DafnyCC__Proc_ArrayAlloc:int := 4 + max(stack_size__DafnyCC__Proc_AllocArrayOfInt + 4, 0); procedure Proc_ArrayAlloc(my r_old:regs, const my core_state:core_state, linear stk_old:mem, linear statics_old:mem, linear io_old:IOState, linear mems_old:mems, $commonVars_old:commonVars, $gcVars_old:gcVars, $toAbs_old:[int]int, $absMem_old:[int][int]int, $stacksFrames_old:[int]Frames, objLayouts_old:[int]ObjLayout, heap_old:Heap, const linear appCodeMem:mem) returns(my r:regs, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars, $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap, $ghost_arr:ArrayOfInt); requires MemInv(me,init,stk_old,statics_old,core_state,ptMem,mems_old); requires (forall i:int::{appCodeAddr(i)}{appCodeMem.dom[i]} appCodeMem.dom[i] == appCodeAddr(i)); requires NucleusInv(objLayouts_old,$S,$toAbs_old,$absMem_old,$commonVars_old,$gcVars_old,me,init,stk_old,statics_old,core_state,ptMem,mems_old,$stacksFrames_old,io_old); requires SMemRequireGcRA(stack_size__DafnyCC__Proc_ArrayAlloc, 4, stk_old, r_old.regs[ESP], RET); requires HeapInv($absMem_old, objLayouts_old, heap_old); modifies $Time; ensures r.regs[ESP] == old(r_old.regs[ESP]) + 4; ensures MemInv(me,init,stk,statics,core_state,ptMem,mems); ensures NucleusInv(objLayouts,$S,$toAbs,$absMem,$commonVars,$gcVars,me,init,stk,statics,core_state,ptMem,mems,$stacksFrames,io); ensures SMemEnsureGcF(4, stk, old(stk_old), r.regs[ESP], old(r_old.regs[ESP]), $stacksFrames, $stacksFrames_old); ensures HeapInv($absMem, objLayouts, heap); ensures AbsExtend($toAbs, $toAbs_old, objLayouts, objLayouts_old); ensures (forall i:int::{$absMem[i]}{heap.absData[i]} heap_old.absData[i] is AbsNone || (heap.absData[i] == heap_old.absData[i] && ($absMem[i] == $absMem_old[i]))); ensures io._inCtr == io_old._inCtr && io._outCtr == io_old._outCtr; ensures (heap_old.absData[$ghost_arr.arrAbs] is AbsNone); ensures $ghost_arr != (ArrayOfInt(0 - 1, NO_ABS)); ensures ((Arr_Length($ghost_arr))) == 262144; ensures (forall j:int :: 0 <= j && j < Arr_Length($ghost_arr) ==> fun_INTERNAL__array__elems__index($absMem[$ghost_arr.arrAbs], j) == appCodeMem.map[0x340000 + j*4]); ensures fun_IsWordSeq(fun_Seq__FromArray($absMem, $ghost_arr)); ensures StackAbsSlot(heap, $stacksFrames, r_old.regs[ESP] + 4 + stackGcOffset) == Abs_ArrayOfInt($ghost_arr); ensures frameGet($stacksFrames, r_old.regs[ESP] + 4 + stackGcOffset) == $ghost_arr.arrAbs; { var $absMem_tmp:[int][int]int; var objLayouts_tmp:[int]ObjLayout; var heap_tmp:Heap; var obj_tmp:int; var val_tmp:int; var $ghost__temp__0:int; var $ghost_i:int; var $ghost_arr__abs:int; assert fun_unroll(0); assert fun_unroll(1); call proc_Seq__FromArray__Length(); r := r_old; stk := stk_old; statics := statics_old; io := io_old; mems := mems_old; $commonVars := $commonVars_old; $gcVars := $gcVars_old; $toAbs := $toAbs_old; $absMem := $absMem_old; $stacksFrames := $stacksFrames_old; objLayouts := objLayouts_old; heap := heap_old; assert TV(r.regs[ESP]); assert TO(0 - 1); assert TO(263168 - 1); assert TO(0); assert TO(263168); assert TO(1); assert TO(263169); assert TO(0x443FF); assert TO(0x44400); assert TO(0x44401); assert TO(0x44402); call logical_Sub(inout r, ESP, OConst(4)); // ###LINE: D:\home\git\IroncladApps\iron\src\Dafny\Apps\Loader\Loader.i.dfy: 40 // ###LINE: D:\home\git\IroncladApps\iron\src\Dafny\Apps\Loader\Loader.i.dfy: 40 // move:: $ghost__temp__0 := 262144 // isPtr = False call r := instr_Mov(r, EAX, OConst(262144)); $ghost__temp__0 := r.regs[EAX]; // push argument #0 at index 0 isPtr = False argument = $ghost__temp__0 // regalloc_stack_store:: OMem(MReg(ESP, 0)) := EAX // var = $ghost__temp__0 call logical_Store(r, core_state, inout stk, OMem(MReg(ESP, 0)), OReg(EAX)); // call:: $ghost_arr := Proc_AllocArrayOfInt($ghost__temp__0) // isGhost = False call alignCall(r.regs[ESP]); {: call logical_Call(inout r, core_state, inout stk); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_arr := Proc_AllocArrayOfInt(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost__temp__0); :} assert SMemInvGcF(8, stk, old(stk_old), r.regs[ESP] + 4, old(r_old.regs[ESP]), $stacksFrames, $stacksFrames_old); // pop return value #0 at index 0 into destination $ghost_arr isPtr = True // regalloc_stack_load:: EAX := OMem(MReg(ESP, 0x101000)) // var = $ghost_arr 1437 call r, mems := heapLoadStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, EAX, OMem(MReg(ESP, 0x111000)), EvalPtr(r, OMem(MReg(ESP, 0x111000)))); $ghost_arr__abs := frameGet($stacksFrames, EvalPtr(r, OMem(MReg(ESP, 0x111000)))); // ###LINE: D:\home\git\IroncladApps\iron\src\Dafny\Apps\Loader\Loader.i.dfy: 41 // ###LINE: D:\home\git\IroncladApps\iron\src\Dafny\Apps\Loader\Loader.i.dfy: 41 // ###LINE: D:\home\git\IroncladApps\iron\src\Dafny\Apps\Loader\Loader.i.dfy: 41 // ###LINE: D:\home\git\IroncladApps\iron\src\Dafny\Apps\Loader\Loader.i.dfy: 41 // move:: $ghost_i := 0 // isPtr = False call r := instr_Mov(r, ECX, OConst(0)); $ghost_i := r.regs[ECX]; // ###LINE: D:\home\git\IroncladApps\iron\src\Dafny\Apps\Loader\Loader.i.dfy: 42 // jump_to_label:: L2 condition = goto L2; // label:: L1 // isLoop = False L1: // ###LINE: D:\home\git\IroncladApps\iron\src\Dafny\Apps\Loader\Loader.i.dfy: 45 // ###LINE: D:\home\git\IroncladApps\iron\src\Dafny\Apps\Loader\Loader.i.dfy: 46 // ###LINE: D:\home\git\IroncladApps\iron\src\Dafny\Apps\Loader\Loader.i.dfy: 46 // storeArrayElement // New code: var foo:int := eax; var bar:int := ecx; ebp := eax; // Save the contents of eax esi := ecx; // Save the contents of ecx ebx := ecx; ecx := 0x340000; eax := ebx; assert eax == $ghost_i; edi := 4; call eax,edx := Mul(eax, edi); assert TVM($ghost_i, 4); call reveal_wrap32($ghost_i*4); assert eax == $ghost_i*4; call reveal_WORD_HI(); ecx := ecx + eax; call reveal_MemInvDetails(); // Shows that ecx is sane call reveal_Aligned(0x340000); assert TV(0x340000) && TO(ebx); call ecx := Load(appCodeMem, ecx); edi := ecx; // Save the value we loaded eax := ebp; // Restore eax ecx := esi; // Restore ecx assert foo == eax; assert bar == ecx; // End new code call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MIndex(EAX, 4, ECX, 8)), OReg(EDI), $ghost_i, appCodeMem.map[0x340000+$ghost_i*4], $ghost_arr__abs, r.regs[EAX]); // ###LINE: D:\home\git\IroncladApps\iron\src\Dafny\Apps\Loader\Loader.i.dfy: 47 // ###LINE: D:\home\git\IroncladApps\iron\src\Dafny\Apps\Loader\Loader.i.dfy: 47 // binary_assignment:: $ghost_i := instr_AddChecked($ghost_i, ) call r := instr_AddChecked(r, ECX, OConst(1)); $ghost_i := r.regs[ECX]; call proc_lemma__2toX(); call proc_lemma__word32(edi); call reveal_WORD_HI(); // label:: L2 // isLoop = True L2: invariant MemInv(me,init,stk,statics,core_state,ptMem,mems); invariant NucleusInv(objLayouts,$S,$toAbs,$absMem,$commonVars,$gcVars,me,init,stk,statics,core_state,ptMem,mems,$stacksFrames,io); invariant SMemInvGcF(8, stk, old(stk_old), r.regs[ESP] + 4, old(r_old.regs[ESP]), $stacksFrames, $stacksFrames_old); invariant HeapInv($absMem, objLayouts, heap); invariant AbsExtend($toAbs, $toAbs_old, objLayouts, objLayouts_old); invariant (forall i:int::{$absMem[i]}{heap.absData[i]} heap_old.absData[i] is AbsNone || (heap.absData[i] == heap_old.absData[i] && ($absMem[i] == $absMem_old[i]))); invariant io._inCtr == io_old._inCtr && io._outCtr == io_old._outCtr; // loop invariants invariant $ghost_i == (r.regs[ECX]); invariant HeapAbsData(heap, $ghost_arr__abs) == Abs_ArrayOfInt($ghost_arr); invariant HeapValue(objLayouts, true, $toAbs, r.regs[EAX], $ghost_arr__abs); invariant $ghost_arr__abs == $ghost_arr.arrAbs; invariant 0 <= $ghost_i && $ghost_i <= 262144; invariant (forall j:int :: 0 <= j && j < $ghost_i ==> fun_INTERNAL__array__elems__index($absMem[$ghost_arr.arrAbs], j) == appCodeMem.map[0x340000 + j*4]); invariant (forall j:int :: 0 <= j && j < $ghost_i ==> fun_word32(fun_INTERNAL__array__elems__index($absMem[$ghost_arr.arrAbs], j))); //invariant (forall j:int :: 0 <= j && j < $ghost_i ==> word(fun_INTERNAL__array__elems__index($absMem[$ghost_arr.arrAbs], j))); assert !false; call proc_Seq__Equal__Equiv___int(); call proc_Seq__Equal__Equiv___Seq___int(); call proc_Seq__Equal__Equiv___atoe_Type(); call proc_Seq__Equal__Equiv___Seq___atoe_Type(); call proc_Seq__Equal__Equiv___bool(); // jump_to_label:: L1 condition = $ghost_i < 262144 if (ecx < 0x40000) { goto L1; } // label:: L3 // isLoop = False L3: // regalloc_stack_store:: OMem(MReg(ESP, 4104)) := EAX // var = $ghost_arr call mems, $stacksFrames := heapStoreStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, OMem(MReg(ESP, 0x111008)), OReg(EAX), EvalPtr(r, OMem(MReg(ESP, 0x111008))), $ghost_arr__abs); call logical_Add(inout r, ESP, OConst(4)); call proc_Seq__FromArray__Index(); call proc_lemma__word32__Word32(); assert (forall j:int :: 0 <= j && j < 262144 ==> word(fun_INTERNAL__array__elems__index($absMem[$ghost_arr.arrAbs], j))); assert (forall j:int :: 0 <= j && j < 262144 ==> fun_Word32(fun_INTERNAL__array__elems__index($absMem[$ghost_arr.arrAbs], j))); // return {: call logical_Ret(inout r, core_state, stk); return; :} } #endif //implementation FaultHandler($_stackState:[int]StackState, $ebp:int, $esp:int, $eip:int) //{ // var $__stackState:[int]StackState := $StackState[$S := StackEmpty]; // call revealInv1($S, $StackState); // // eax := CurrentStack; // edx := ?TSize; // call eax, edx := Mul(eax, edx); // call eax := Add(eax, TLo); // assert TV(TLo) && TO(64 * $S); // // call setStackEmpty($S); // call revealInv1(?InterruptStack, $__stackState); // // ecx := FLo; // call ecx := Add(ecx, ?StackReserve); // call ecx := Add(ecx, ?InterruptReserve); // StackCheck := ecx; // // ecx := 0; // edi := TLo; // call ebx := Load(mems.tcb[?InterruptStack][edi]); // if (ebx != ?STACK_YIELDED) // { // // Fatal error: interrupt stack not ready to receive interrupt // eax := 0x55550004; // call debugBreak(); // } // // call setStackRunning3(?InterruptStack, $__stackState, $ebp, $esp, $eip); // return; //} // //implementation ErrorHandler($_stackState:[int]StackState, $ebp:int, $esp:int, $eip:int) //{ // var $__stackState:[int]StackState := $StackState[$S := StackEmpty]; // call revealInv1($S, $StackState); // // eax := CurrentStack; // edx := ?TSize; // call eax, edx := Mul(eax, edx); // call eax := Add(eax, TLo); // assert TV(TLo) && TO(64 * $S); // // call setStackEmpty($S); // call revealInv1(?InterruptStack, $__stackState); // // ecx := FLo; // call ecx := Add(ecx, ?StackReserve); // call ecx := Add(ecx, ?InterruptReserve); // StackCheck := ecx; // // ecx := 0; // edi := TLo; // call ebx := Load(mems.tcb[?InterruptStack][edi]); // if (ebx != ?STACK_YIELDED) // { // // Fatal error: interrupt stack not ready to receive interrupt // eax := 0x55550005; // call debugBreak(); // } // // call setStackRunning3(?InterruptStack, $__stackState, $ebp, $esp, $eip); // return; //} // //implementation InterruptHandler($_stackState:[int]StackState, $ebp:int, $esp:int, $eip:int) //{ // var $__stackState:[int]StackState := // $StackState[$S := StackInterrupted(eax, ebx, ecx, edx, esi, edi, ebp, esp + 12, $Mem[esp], $Mem[esp + 4], $Mem[esp + 8])]; // call stacksProofs(); // call setStackInterrupted(); // call revealInv1(?InterruptStack, $__stackState); // // ecx := FLo; // call ecx := Add(ecx, ?StackReserve); // call ecx := Add(ecx, ?InterruptReserve); // StackCheck := ecx; // // ecx := 0; // edi := TLo; // call ebx := Load(mems.tcb[?InterruptStack][edi]); // if (ebx != ?STACK_YIELDED) // { // // Fatal error: interrupt stack not ready to receive interrupt // eax := 0x55550006; // call debugBreak(); // } // // call setStackRunning3(?InterruptStack, $__stackState, $ebp, $esp, $eip); // return; //} //implementation Throw($_stackState:[int]StackState, $ebp:int, $esp:int, $eip:int) //{ // var $__stackState:[int]StackState := $StackState[$S := StackEmpty]; // call revealInv1($S, $StackState); // // eax := CurrentStack; // edx := ?TSize; // call eax, edx := Mul(eax, edx); // call eax := Add(eax, TLo); // assert TV(TLo) && TO(64 * $S); // // //assert&&& &&&(NucleusInv(objLayouts, $S, $StackState, $toAbs, $AbsMem, GcVars, $Mem_Vars, $FrameVars, $IoVars)); // call setStackEmpty($S); // call revealInv1(?InterruptStack, $__stackState); // // eax := FLo; // call eax := Add(eax, ?StackReserve); // call eax := Add(eax, ?InterruptReserve); // call setStackCheck($__stackState); // // ecx := 0; // edi := TLo; // call ebx := Load(mems.tcb[?InterruptStack][edi]); // if (ebx != ?STACK_YIELDED) // { // // Fatal error: interrupt stack not ready to receive interrupt // eax := 0x55550003; // call debugBreak(); // } // // call stacksProofs(); // call setStackRunning3(?InterruptStack, $__stackState, $ebp, $esp, $eip); // return; //} //implementation FatalHandler() //{ // eax := 0x55550007; // call debugBreak(); // return; //} //implementation GetStackState($s:int) //{ // if (ecx >= ?NumStacks) // { // eax := 0x55550009; // call debugBreak(); // } // call revealInv1($s, $StackState); // // // Get $s state // eax := ecx; // edx := ?TSize; // call eax, edx := Mul(eax, edx); // call eax := Add(eax, TLo); // assert TV(TLo) && TO(64 * $s); // call eax := Load(mems.tcb[$s][eax]); // return; //} // //implementation ResetStack($s:int) //{ // call stacksProofs(); // if (ecx >= ?NumStacks) // { // eax := 0x55550009; // call debugBreak(); // } // call revealInv1($s, $StackState); // // // Get $s state // eax := ecx; // edx := ?TSize; // call eax, edx := Mul(eax, edx); // call eax := Add(eax, TLo); // assert TV(TLo) && TO(64 * $s); // call ebx := Load(mems.tcb[$s][eax]); // // if (ebx == ?STACK_RUNNING) // { // // Can't reset our own stack // eax := 0x5555000a; // call debugBreak(); // } // // call setStackEmpty($s); // return; //} // // //implementation YieldTo($s:int, $_stackState:[int]StackState, // $eax:int, $ebx:int, $ecx:int, $edx:int, $esi:int, $edi:int, $ebp:int, $esp:int, // $eip:int, $cs:int, $efl:int) //{ // call stacksProofs(); // if (ecx >= ?NumStacks) // { // eax := 0x55550008; // call debugBreak(); // } // // var $__stackState:[int]StackState := $StackState[$S := StackYielded(ebp, esp + 4, $Mem[esp])]; // call revealInv1($s, $StackState); // // // Set stack check limit // eax := ecx; // edx := ?FSize; // call eax, edx := Mul(eax, edx); // call eax := Add(eax, FLo); // call eax := Add(eax, ?StackReserve); // call eax := Add(eax, ?InterruptReserve); // call setStackCheck($StackState); // // // Get $s state // eax := ecx; // edx := ?TSize; // call eax, edx := Mul(eax, edx); // call eax := Add(eax, TLo); // assert TV(TLo) && TO(64 * $s); // call ebx := Load(mems.tcb[$s][eax]); // edi := eax; // // // Prepare to set $S state if necessary // eax := CurrentStack; // edx := ?TSize; // call eax, edx := Mul(eax, edx); // call eax := Add(eax, TLo); // assert TV(TLo) && TO(64 * $S); // // if (ebx == ?STACK_YIELDED) // { // call setStackYielded(); // call setStackRunning3($s, $__stackState, $ebp, $esp, $eip); // return; // } // else {if(ebx == ?STACK_INTERRUPTED) // { // call setStackYielded(); // call setStackRunning4($s, $__stackState, $eax, $ebx, $ecx, $edx, $esi, $edi, $ebp, $esp, $eip, $cs, $efl); // ireturn; // } // else {if(ebx == ?STACK_EMPTY) // { // call setStackYielded(); // // eax := ecx; // edx := ?FSize; // call eax, edx := Mul(eax, edx); // call eax := Add(eax, FLo); // assert TV(FLo) && TO($s * 4096 + 4094) && TO($s * 4096 + 4095); // call esp := Lea(eax + 16376); // eax := ?KernelEntryPoint; // call setStackRunning2($s, $__stackState); // ebp := 0; // return; // }}} // // ebx == ?STACK_RUNNING // return; //} // //implementation VgaTextWrite() //{ // if (ecx < 4000) // { // call VgaTextStore16(ecx + 1 * ecx + 0xb8000, edx); // } // return; //} // //implementation TryReadKeyboard() //{ // call /*eax := */ KeyboardStatusIn8(); // call eax := And(eax, 1); // if (eax != 0) { goto skip; } // call eax:=Mov(256); // return; // skip: // call /*eax := */ KeyboardDataIn8(); // call eax := And(eax, 255); // return; //} // //implementation StartTimer() //{ // call startTimer(); // return; //} // //implementation SendEoi() //{ // var $seq0:int := $PicSeq[0] + 1; // var $seq1:int := $PicSeq[1] + 1; // eax := 0x20; edx := 0x20; call PicOut8(0, 0, $seq0); // eax := 0x20; edx := 0xa0; call PicOut8(1, 0, $seq1); // return; //} //implementation CycleCounter() //{ // call Rdtsc(); // return; //} // //implementation DebugPrintHex() //{ // if (ecx >= 72) // { // eax := 0x5555000b; // call debugBreak(); // } // eax := edx; // call edx := Lea(ecx + ecx); // call writeHex(); // return; //} } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Main/IntLemmasMain.ifc.beat ================================================ //-private-import BaseSpec; //-private-import MemorySpec; //-private-import IntSpec; //-private-import BitVectorLemmasMain; //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module interface IntLemmasMain { atomic ghost procedure proc_XorLemmas(); ensures (forall x:int::xor(x, x) == 0); ensures (forall x:int::word(x) ==> xor(x, 0) == x); ensures (forall x:int, y:int::xor(x, y) == xor(y, x)); ensures (forall x:int, y:int, z:int:: xor(x, xor(y,z)) == xor(y, xor(x,z))); ensures (forall x:int, y:int, z:int :: (word(x) && word(y) && word(z)) ==> (xor(x,z) == xor(y,z)) ==> (x == y)); atomic ghost procedure lemma_and_with_ff(x:int); requires word(x); ensures le(0, and(x, 0xff)) && lt(and(x, 0xff), 0x100); atomic ghost procedure lemma_and_with_ffff(x:int); requires word(x); ensures le(0, and(x, 0xffff)) && lt(and(x, 0xffff), 0x10000); atomic ghost procedure lemma_and_with_32_64(x:int); requires word(x); ensures gt(and(x, 32), 0) ==> int_bit(x, 5); ensures gt(and(x, 64), 0) ==> int_bit(x, 6); atomic ghost procedure lemma_xor_bytes(x:int, y:int); requires le(0, x) && lt(x, 256); requires le(0, y) && lt(y, 256); ensures le(0, xor(x, y)) && lt(xor(x, y), 256); } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Main/IntLemmasMain.imp.beat ================================================ //-private-import BaseSpec; //-private-import MemorySpec; //-private-import IntSpec; //-private-import BitVectorLemmasMain; //- //- //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module implementation IntLemmasMain { atomic ghost procedure _a($b1:bv32, $b2:bv32) requires word(add(I($b1), I($b2))); ensures add(I($b1), I($b2)) == I($add($b1, $b2)); { } atomic ghost procedure _s($b1:bv32, $b2:bv32) requires word(sub(I($b1), I($b2))); ensures sub(I($b1), I($b2)) == I($sub($b1, $b2)); { } atomic ghost procedure _m($b1:bv32, $b2:bv32) requires word(mul(I($b1), I($b2))); ensures mul(I($b1), I($b2)) == I($mul($b1, $b2)); { } atomic ghost procedure __const() ensures 0 == I(0bv32); ensures 2 == I(2bv32); ensures 4 == I(4bv32); ensures 16 == I(16bv32); ensures 32 == I(32bv32); ensures 64 == I(64bv32); ensures 255 == I(255bv32); ensures 256 == I(256bv32); ensures 0x10000 == I(65536bv32); ensures 0xffff == I(65535bv32); { call _const(); call _s(1bv32, 1bv32); call _a(1bv32, 1bv32); call _m(2bv32, 2bv32); call _m(4bv32, 4bv32); call _a(16bv32, 16bv32); call _a(32bv32, 32bv32); call _m(16bv32, 16bv32); call _m(256bv32, 256bv32); call _s(256bv32, 1bv32); call _s(65536bv32, 1bv32); } implementation proc_XorLemmas() { call __const(); call _proc_XorLemmas(); } implementation lemma_and_with_ff(x:int) { call __const(); call _lemma_and_with_ff(B(x)); } implementation lemma_and_with_ffff(x:int) { call __const(); call _lemma_and_with_ffff(B(x)); } implementation lemma_and_with_32_64(x:int) { call __const(); call _lemma_and_with_32_64(B(x)); call reveal_int_bit(x, 5); call reveal_int_bit(x div 2, 4); call reveal_int_bit((x div 2) div 2, 3); call reveal_int_bit(((x div 2) div 2) div 2, 2); call reveal_int_bit((((x div 2) div 2) div 2) div 2, 1); call reveal_int_bit(((((x div 2) div 2) div 2) div 2) div 2, 0); assert gt(and(x, 32), 0) ==> _mod(_div(_div(_div(_div(_div(x, 2), 2), 2), 2), 2), 2) != 0; //int_bit(x, 5) == 1; call reveal_int_bit(x, 6); call reveal_int_bit(x div 2, 5); call reveal_int_bit((x div 2) div 2, 4); call reveal_int_bit(((x div 2) div 2) div 2, 3); call reveal_int_bit((((x div 2) div 2) div 2) div 2, 2); call reveal_int_bit(((((x div 2) div 2) div 2) div 2) div 2, 1); call reveal_int_bit((((((x div 2) div 2) div 2) div 2) div 2) div 2, 0); assert gt(and(x, 64), 0) ==> _mod(_div(_div(_div(_div(_div(_div(x, 2), 2), 2), 2), 2), 2), 2) != 0; //int_bit(x, 6) == 1; } implementation lemma_xor_bytes(x:int, y:int) { call __const(); assert le(0, x) && lt(x, 256); assert le(0, y) && lt(y, 256); call _lemma_xor_bytes(B(x), B(y)); } } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Main/Main.ifc.beat ================================================ //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- //-private-import BaseSpec; //-private-import MemorySpec; //-private-import IoTypesSpec; //-private-import MachineStateSpec; //-private-import AssemblySpec; //-private-import InterruptsSpec; //-private-import IoSpec; //- //- //- //- //- //-private-import Core; //-private-import LogicalAddressing; //-private-import Overflow; //-private-import Util; //-private-import Stacks; //-private-import Partition; //-private-import Separation; //-private-import IntLemmasBase; //-private-import IntLemmasGc; //-private-import SimpleGcMemory; //-private-import SimpleCommon; //-private-import SimpleCollector; //-private-import IoMain; //-private-import IntLemmasMain; //-private-basmonly-import Trusted; //-private-basmonly-import Checked; //-private-import Heap; //-private-import Seq; //-private-import dafny_DafnyPrelude; //-private-import DafnyAssembly; //-private-import dafny_relational_s; //-private-import dafny_base_s; //-private-import dafny_power2_s; //-disallowd-xrivate-import dafny_mul_i; //-disallowd-xrivate-import dafny_assembly_i; //-disallowd-xrivate-import dafny_bit_vector_lemmas_i; //-disallowd-xrivate-import dafny_Main_i; //-private-import AppLoaderContract; //-private-import ExtendedAssembly; module interface Entry { var $commonVars:commonVars; var $gcVars:gcVars; // //// TODO: better dispatcher //procedure Throw($_stackState:[int]StackState, $ebp:int, $esp:int, $eip:int); // inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState; // inout mems:mems; // requires word(eax) && word(ebx) && word(ecx) && word(edx) && word(esi) && word(edi) && word(ebp) && word(esp); // requires isStack($S) && $StackState[$S] == StackRunning; // requires NucleusInv($S, $StackState, $toAbs, $AbsMem, GcVars, $Mem_Vars, $StacksFrames, $IoVars); // requires SpRequire($S, esp, 4); // requires $_stackState == $StackState[$S := StackEmpty][?InterruptStack := StackRunning]; // requires (StackStateTag($StackState[?InterruptStack]) == ?STACK_YIELDED ==> // RET == ReturnToAddr($eip) // && $StackState[?InterruptStack] == StackYielded($ebp, $esp, $eip)); // modifies state, efl, eax, ebx, ecx, edx, esi, edi, ebp, esp; // modifies AllGcVars, $_MemVars; // modifies StackCheck; // ensures StackCheckInv(?InterruptStack, StackCheck); // ensures (StackStateTag($StackState[?InterruptStack]) == ?STACK_YIELDED ==> // NucleusInv(?InterruptStack, $_stackState, $toAbs, $AbsMem, GcVars, $Mem_Vars, $StacksFrames, $IoVars) // && ebp == $ebp // && esp == $esp); // //procedure GetStackState($s:int); // inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState; // inout mems:mems; // requires word(ecx); // requires isStack($S) && $StackState[$S] == StackRunning; // requires ecx == $s; // requires NucleusInv($S, $StackState, $toAbs, $AbsMem, GcVars, $Mem_Vars, $StacksFrames, $IoVars); // requires ReturnToAddr($Mem[esp]) == RET; // requires SpRequire($S, esp, 4); // modifies state, efl, eax, ecx, edx, esp; // ensures NucleusInv($S, $StackState, $toAbs, $AbsMem, GcVars, $Mem_Vars, $StacksFrames, $IoVars); // ensures eax == StackStateTag($StackState[$s]); // ensures ebp == old(ebp); // ensures esp == old(esp) + 4; // //procedure ResetStack($s:int); // inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState; // inout mems:mems; // requires word(ecx); // requires isStack($S) && $StackState[$S] == StackRunning; // requires ecx == $s; // requires NucleusInv($S, $StackState, $toAbs, $AbsMem, GcVars, $Mem_Vars, $StacksFrames, $IoVars); // requires ScanStackInv($S, $Mem, $StacksFrames, $Mem[esp], esp, ebp); // requires $StackState[$s] != StackRunning ==> ReturnToAddr($Mem[esp]) == RET; // requires SpRequire($S, esp, 4); // modifies state, efl, eax, ebx, ecx, edx, esi, edi, ebp, esp; // modifies AllGcVars, $_MemVars; // ensures NucleusInv($S, $StackState[$s := StackEmpty], $toAbs, $AbsMem, GcVars, $Mem_Vars, $StacksFrames, $IoVars); // ensures ebp == old(ebp); // ensures esp == old(esp) + 4; // //// extern static void YieldTo(uint stackId); //// Switch to a stack $s. //// - $s may be empty, yielded, interrupted, or the current running stack. //// Change the state of $S to yielded, then change the state of $s to running. //procedure YieldTo($s:int, $_stackState:[int]StackState, // $eax:int, $ebx:int, $ecx:int, $edx:int, $esi:int, $edi:int, $ebp:int, $esp:int, // $eip:int, $cs:int, $efl:int); // inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState; // inout mems:mems; // requires ecx == $s; // requires word(eax) && word(ebx) && word(ecx) && word(edx) && word(esi) && word(edi) && word(ebp); // requires isStack($S) && $StackState[$S] == StackRunning; // requires NucleusInv($S, $StackState, $toAbs, $AbsMem, GcVars, $Mem_Vars, $StacksFrames, $IoVars); // requires ScanStackInv($S, $Mem, $StacksFrames, $Mem[esp], esp, ebp); // requires SpRequire($S, esp, 4); // requires $_stackState == $StackState[$S := StackYielded(ebp, esp + 4, $Mem[esp])][$s := StackRunning]; // requires ($StackState[$s] == StackRunning && $s == $S && RET == ReturnToAddr($Mem[esp])) // || ($StackState[$s] == StackYielded($ebp, $esp, $eip) && RET == ReturnToAddr($eip)) // || ($StackState[$s] == StackInterrupted($eax, $ebx, $ecx, $edx, $esi, $edi, $ebp, $esp, $eip, $cs, $efl) // && RET == ReturnToInterrupted($eip, $cs, $efl)) // || ($StackState[$s] == StackEmpty && RET == ReturnToAddr(?KernelEntryPoint) // && $StacksFrames[$s].Count == 0); // // modifies state, efl, eax, ebx, ecx, edx, esi, edi, ebp, esp; // modifies AllGcVars, $_MemVars; // modifies StackCheck; // // ensures StackCheckInv($s, StackCheck); // ensures ($StackState[$s] == StackRunning ==> // NucleusInv($s, $StackState, $toAbs, $AbsMem, GcVars, $Mem_Vars, $StacksFrames, $IoVars) // && ebp == old(ebp) // && esp == old(esp) + 4); // ensures ($StackState[$s] == StackYielded($ebp, $esp, $eip) ==> // NucleusInv($s, $_stackState, $toAbs, $AbsMem, GcVars, $Mem_Vars, $StacksFrames, $IoVars) // && ebp == $ebp // && esp == $esp); // ensures ($StackState[$s] == StackInterrupted($eax, $ebx, $ecx, $edx, $esi, $edi, $ebp, $esp, $eip, $cs, $efl) ==> // NucleusInv($s, $_stackState, $toAbs, $AbsMem, GcVars, $Mem_Vars, $StacksFrames, $IoVars) // && ebp == $ebp // && esp == $esp // && eax == $eax && ebx == $ebx && ecx == $ecx && edx == $edx && esi == $esi && edi == $edi); // ensures ($StackState[$s] == StackEmpty ==> // NucleusInv($s, $_stackState, $toAbs, $AbsMem, GcVars, $Mem_Vars, $StacksFrames, $IoVars) // && esp == StackHi($s) - 4 // && ebp == 0 // end of frame pointer linked list // ); //*/ ///* //// extern static void VgaTextWrite(uint screenOffset, uint hexMessage); //procedure VgaTextWrite(); // requires word(eax) && word(ebx) && word(ecx) && word(edx) && word(esi) && word(edi) && word(ebp); // requires RET == ReturnToAddr($Mem[esp]); // requires SpRequire($S, esp, 4); // modifies state, efl, esp; // modifies $VgaNextEvent, $VgaEvents; // ensures ecx < 4000 ==> // $VgaNextEvent == old($VgaNextEvent) + 1 // && $VgaEvents == old($VgaEvents)[old($VgaNextEvent) := VgaTextStore(?VgaTextLo + 2 * ecx, edx)]; // ensures esp == old(esp) + 4; // //// extern static uint TryReadKeyboard(); //procedure TryReadKeyboard(); // requires word(eax) && word(ebx) && word(ecx) && word(edx) && word(esi) && word(edi) && word(ebp); // requires RET == ReturnToAddr($Mem[esp]); // requires SpRequire($S, esp, 4); // modifies state, efl, eax, esp; // modifies $KeyboardAvailable, $KeyboardDone; // ensures $KeyboardAvailable == old($KeyboardDone) ==> eax == 256; // ensures $KeyboardAvailable > old($KeyboardDone) ==> eax == $KeyboardEvents[old($KeyboardDone)]; // ensures esp == old(esp) + 4; // //// extern static uint StartTimer(uint freq); //procedure StartTimer(); // inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState, mems:mems; // requires word(eax) && word(ebx) && word(ecx) && word(edx) && word(esi) && word(edi) && word(ebp); // requires RET == ReturnToAddr($Mem[esp]); // requires SpRequire($S, esp, 4); // modifies state, efl, eax, esp; // modifies $TimerSeq, $TimerFreq; // ensures TimerOk($TimerSeq) && $TimerFreq == old(ecx); // ensures esp == old(esp) + 4; // //// extern static void SendEoi(); //procedure SendEoi(); // inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState, mems:mems; // requires word(eax) && word(ebx) && word(ecx) && word(edx) && word(esi) && word(edi) && word(ebp); // requires RET == ReturnToAddr($Mem[esp]); // requires SpRequire($S, esp, 4); // requires PicOk($PicSeq); // modifies state, efl, eax, edx, esp; // modifies $PicSeq; // ensures $PicSeq[0] == old($PicSeq[0]) + 1; // ensures $PicSeq[1] == old($PicSeq[1]) + 1; // ensures esp == old(esp) + 4; // //// extern static long Rdtsc(); //procedure CycleCounter(); // inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState, mems:mems; // requires RET == ReturnToAddr($Mem[esp]); // requires SpRequire($S, esp, 4); // modifies state, efl, eax, edx, esp; // ensures esp == old(esp) + 4; // //// extern static void DebugPrintHex(uint screenOffset, uint hexMessage); //procedure DebugPrintHex(); // inout my r:regs, my core_state:core_state, linear stk:mem, linear statics:mem, linear io:IOState, mems:mems; // requires word(eax) && word(ebx) && word(ecx) && word(edx) && word(esi) && word(edi) && word(ebp); // requires RET == ReturnToAddr($Mem[esp]); // requires SpRequire($S, esp, 4); // modifies state, efl, eax, ebx, ecx, edx, esi, edi, esp; // not ebp // ensures esp == old(esp) + 4; // } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Main/axiom.whitelist ================================================ axiom (forall f: int, x: int, y: int :: { v2_u.Je(v2_u.Efl_Cmp(f, x, y)) } v2_u.Je(v2_u.Efl_Cmp(f, x, y)) <==> x == y); axiom (forall f: int, x: int, y: int :: { v2_u.Jne(v2_u.Efl_Cmp(f, x, y)) } v2_u.Jne(v2_u.Efl_Cmp(f, x, y)) <==> x != y); axiom (forall f: int, x: int, y: int :: { v2_u.Jbe(v2_u.Efl_Cmp(f, x, y)) } v2_u.Jbe(v2_u.Efl_Cmp(f, x, y)) <==> x <= y); axiom (forall f: int, x: int, y: int :: { v2_u.Jb(v2_u.Efl_Cmp(f, x, y)) } v2_u.Jb(v2_u.Efl_Cmp(f, x, y)) <==> x < y); axiom (forall f: int, x: int, y: int :: { v2_u.Jae(v2_u.Efl_Cmp(f, x, y)) } v2_u.Jae(v2_u.Efl_Cmp(f, x, y)) <==> x >= y); axiom (forall f: int, x: int, y: int :: { v2_u.Ja(v2_u.Efl_Cmp(f, x, y)) } v2_u.Ja(v2_u.Efl_Cmp(f, x, y)) <==> x > y); axiom (forall i1: int, i2: int :: {:expand false} { v2_u.add(i1, i2): int } v2_u.add(i1, i2): int == i1 + i2); axiom (forall i1: int, i2: int :: {:expand false} { v2_u.sub(i1, i2): int } v2_u.sub(i1, i2): int == i1 - i2); axiom (forall i1: int, i2: int :: {:expand false} { v2_u.mul(i1, i2): int } v2_u.mul(i1, i2): int == i1 * i2); axiom (forall i1: int, i2: int :: {:expand false} { v2_u._div(i1, i2): int } v2_u._div(i1, i2): int == i1 div i2); axiom (forall i1: int, i2: int :: {:expand false} { v2_u._mod(i1, i2): int } v2_u._mod(i1, i2): int == i1 mod i2); axiom (forall i1: int, i2: int :: {:expand false} { v2_u.le(i1, i2): bool } v2_u.le(i1, i2): bool <==> i1 <= i2); axiom (forall i1: int, i2: int :: {:expand false} { v2_u.lt(i1, i2): bool } v2_u.lt(i1, i2): bool <==> i1 < i2); axiom (forall i1: int, i2: int :: {:expand false} { v2_u.ge(i1, i2): bool } v2_u.ge(i1, i2): bool <==> i1 >= i2); axiom (forall i1: int, i2: int :: {:expand false} { v2_u.gt(i1, i2): bool } v2_u.gt(i1, i2): bool <==> i1 > i2); axiom v2_u.EAX == 0; axiom v2_u.ECX == 1; axiom v2_u.EDX == 2; axiom v2_u.EBX == 3; axiom v2_u.ESI == 4; axiom v2_u.EDI == 5; axiom v2_u.EBP == 6; axiom v2_u.ESP == 7; axiom v2_u.TMP1 == 0 - 1; axiom v2_u.TMP2 == 0 - 2; axiom (forall r: int :: { v2_u.RegOk(r): bool } v2_u.RegOk(r): bool <==> v2_u.EAX <= r && r <= v2_u.ESP); axiom (forall x: mem_opn :: { v2_u.._mconst(x): int } v2_u.._mconst(x): int == _mconst#MConst(x)); axiom (forall x: mem_opn :: { v2_u.._mreg(x): int } v2_u.._mreg(x): int == _mreg#MReg(x)); axiom (forall x: mem_opn :: { v2_u.._moffset(x): int } v2_u.._moffset(x): int == _moffset#MReg(x)); axiom (forall x: mem_opn :: { v2_u.._mbase(x): int } v2_u.._mbase(x): int == _mbase#MIndex(x)); axiom (forall x: mem_opn :: { v2_u.._mscale(x): int } v2_u.._mscale(x): int == _mscale#MIndex(x)); axiom (forall x: mem_opn :: { v2_u.._mindex(x): int } v2_u.._mindex(x): int == _mindex#MIndex(x)); axiom (forall x: mem_opn :: { v2_u.._moff(x): int } v2_u.._moff(x): int == _moff#MIndex(x)); axiom (forall x: opn :: { v2_u.._const(x): int } v2_u.._const(x): int == _const#OConst(x)); axiom (forall x: opn :: { v2_u.._reg(x): int } v2_u.._reg(x): int == _reg#OReg(x)); axiom (forall x: opn_mem :: { v2_u.._ptr(x): mem_opn } v2_u.._ptr(x): mem_opn == _ptr#OMem(x)); axiom (forall x: mem :: { v2_u..map(x): [int]int } v2_u..map(x): [int]int == map#mem(x)); axiom (forall x: mem :: { v2_u..dom(x): [int]bool } v2_u..dom(x): [int]bool == dom#mem(x)); axiom (forall mem: mem, ptr: int, val: int :: { v2_u.mem_update(mem, ptr, val): mem } v2_u.mem_update(mem, ptr, val): mem == mem(v2_u..map(mem)[ptr := val], v2_u..dom(mem))); axiom (forall x: regs :: { v2_u.._regs(x): [int]int } v2_u.._regs(x): [int]int == _regs#regs(x)); axiom (forall x: regs :: { v2_u.._efl(x): int } v2_u.._efl(x): int == _efl#regs(x)); axiom (forall r: regs :: { v2_u..regs(r): [int]int } v2_u..regs(r): [int]int == v2_u.._regs(r)); axiom (forall r: regs :: { v2_u..efl(r): int } v2_u..efl(r): int == v2_u.._efl(r)); axiom (forall r: regs, m: mem_opn :: { v2_u.EvalMemOpn(r, m): int } v2_u.EvalMemOpn(r, m): int == (if is#MConst(m) then v2_u.._mconst(m) else (if is#MReg(m) then v2_u..regs(r)[v2_u.._mreg(m)] + v2_u.._moffset(m) else v2_u..regs(r)[v2_u.._mbase(m)] + v2_u.._mscale(m) * v2_u..regs(r)[v2_u.._mindex(m)] + v2_u.._moff(m)))); axiom (forall m: mem_opn :: { v2_u.EvalMemOpnOk(m): bool } v2_u.EvalMemOpnOk(m): bool <==> (if is#MConst(m) then true else (if is#MReg(m) then v2_u.RegOk(v2_u.._mreg(m)) else v2_u.RegOk(v2_u.._mbase(m)) && v2_u.RegOk(v2_u.._mindex(m))))); axiom (forall r: regs, o: opn :: { v2_u.Eval(r, o): int } v2_u.Eval(r, o): int == (if is#OConst(o) then v2_u.._const(o) else v2_u..regs(r)[v2_u.._reg(o)])); axiom (forall r: regs, o: opn_mem :: { v2_u.EvalPtr(r, o): int } v2_u.EvalPtr(r, o): int == v2_u.EvalMemOpn(r, v2_u.._ptr(o))); axiom (forall o: opn_mem :: { v2_u.EvalPtrOk(o): bool } v2_u.EvalPtrOk(o): bool <==> v2_u.EvalMemOpnOk(v2_u.._ptr(o))); axiom (forall o: opn :: { v2_u.SrcOk(o): bool } v2_u.SrcOk(o): bool <==> (if is#OConst(o) then v2_u.word(v2_u.._const(o)) else v2_u.RegOk(v2_u.._reg(o)))); axiom (forall o: opn :: { v2_u.DstOk(o): bool } v2_u.DstOk(o): bool <==> is#OReg(o) && v2_u.RegOk(v2_u.._reg(o))); axiom (forall r: regs, c: core_state, m: mem, o: opn_mem :: { v2_u.MemSrcOk(r, c, m, o): bool } v2_u.MemSrcOk(r, c, m, o): bool <==> v2_u.SrcOkViaSegment(r, c, m, v2_u.DS, o)); axiom (forall r: regs, c: core_state, m: mem, o: opn_mem :: { v2_u.MemDstOk(r, c, m, o): bool } v2_u.MemDstOk(r, c, m, o): bool <==> v2_u.DstOkViaSegment(r, c, m, v2_u.DS, o)); axiom (forall r__BEAT: regs, core__BEAT: core_state, m__BEAT: mem, o__BEAT: opn_mem :: { v2_u.LogicalSrcOk(r__BEAT, core__BEAT, m__BEAT, o__BEAT): bool } v2_u.LogicalSrcOk(r__BEAT, core__BEAT, m__BEAT, o__BEAT): bool <==> v2_u.EvalPtrOk(o__BEAT) && v2_u.PhysPtrOk(m__BEAT, v2_u.EvalPtr(r__BEAT, o__BEAT)) && v2_u.word(v2_u.EvalPtr(r__BEAT, o__BEAT)) && (v2_u.paging_enabled(core__BEAT) ==> !v2_u.in_guard_region(v2_u.EvalPtr(r__BEAT, o__BEAT)))); axiom (forall init__BEAT: bool, r__BEAT: regs, core__BEAT: core_state, m__BEAT: mem, o__BEAT: opn_mem :: { v2_u.LogicalDstOk(init__BEAT, r__BEAT, core__BEAT, m__BEAT, o__BEAT): bool } v2_u.LogicalDstOk(init__BEAT, r__BEAT, core__BEAT, m__BEAT, o__BEAT): bool <==> v2_u.EvalPtrOk(o__BEAT) && v2_u.PhysPtrOk(m__BEAT, v2_u.EvalPtr(r__BEAT, o__BEAT)) && v2_u.word(v2_u.EvalPtr(r__BEAT, o__BEAT)) && (init__BEAT ==> !v2_u.in_guard_region(v2_u.EvalPtr(r__BEAT, o__BEAT)) && !v2_u.between(v2_u.?ptLo, v2_u.?ptHi, v2_u.EvalPtr(r__BEAT, o__BEAT)))); axiom (forall m__BEAT: mem, r__BEAT: regs, o__BEAT: opn_mem :: { v2_u.LogicalEval(m__BEAT, r__BEAT, o__BEAT): int } v2_u.LogicalEval(m__BEAT, r__BEAT, o__BEAT): int == map#mem(m__BEAT)[v2_u.EvalPtr(r__BEAT, o__BEAT)]); axiom (forall stacksFrames__BEAT: [int]Frames, i__BEAT: int :: { v2_u.frameGet(stacksFrames__BEAT, i__BEAT): int } v2_u.frameGet(stacksFrames__BEAT, i__BEAT): int == Abss#Frames(stacksFrames__BEAT[0])[i__BEAT]); axiom (forall n__BEAT: int, argRet__BEAT: int, sMem__BEAT: mem, $esp__BEAT: int, $RET__BEAT: ReturnTo :: { v2_u.SMemRequireGcRA(n__BEAT, argRet__BEAT, sMem__BEAT, $esp__BEAT, $RET__BEAT): bool } v2_u.SMemRequireGcRA(n__BEAT, argRet__BEAT, sMem__BEAT, $esp__BEAT, $RET__BEAT): bool <==> v2_u.SMemRequire(n__BEAT, sMem__BEAT, $esp__BEAT) && v2_u.?sLo + n__BEAT <= $esp__BEAT && $esp__BEAT + argRet__BEAT <= v2_u.?sHi - 4 && v2_u.ReturnToAddr(map#mem(sMem__BEAT)[$esp__BEAT]) == $RET__BEAT); axiom (forall argRet__BEAT: int, sMem__BEAT: mem, oldSMem__BEAT: mem, $esp__BEAT: int, oldEsp__BEAT: int, sAbs__BEAT: [int]int, oldSAbs__BEAT: [int]int :: { v2_u.SMemInvGc(argRet__BEAT, sMem__BEAT, oldSMem__BEAT, $esp__BEAT, oldEsp__BEAT, sAbs__BEAT, oldSAbs__BEAT): bool } v2_u.SMemInvGc(argRet__BEAT, sMem__BEAT, oldSMem__BEAT, $esp__BEAT, oldEsp__BEAT, sAbs__BEAT, oldSAbs__BEAT): bool <==> $esp__BEAT == oldEsp__BEAT && map#mem(sMem__BEAT)[$esp__BEAT] == map#mem(oldSMem__BEAT)[$esp__BEAT] && (forall i__BEAT__BEAT: int :: { map#mem(sMem__BEAT)[i__BEAT__BEAT] } $esp__BEAT + argRet__BEAT <= i__BEAT__BEAT ==> map#mem(sMem__BEAT)[i__BEAT__BEAT] == map#mem(oldSMem__BEAT)[i__BEAT__BEAT]) && (forall i__BEAT__BEAT: int :: { sAbs__BEAT[i__BEAT__BEAT] } $esp__BEAT + argRet__BEAT + v2_u.stackGcOffset <= i__BEAT__BEAT ==> sAbs__BEAT[i__BEAT__BEAT] == oldSAbs__BEAT[i__BEAT__BEAT])); axiom (forall argRet__BEAT: int, sMem__BEAT: mem, oldSMem__BEAT: mem, $esp__BEAT: int, oldEsp__BEAT: int, stacksFrames__BEAT: [int]Frames, oldStacksFrames__BEAT: [int]Frames :: { v2_u.SMemInvGcF(argRet__BEAT, sMem__BEAT, oldSMem__BEAT, $esp__BEAT, oldEsp__BEAT, stacksFrames__BEAT, oldStacksFrames__BEAT): bool } v2_u.SMemInvGcF(argRet__BEAT, sMem__BEAT, oldSMem__BEAT, $esp__BEAT, oldEsp__BEAT, stacksFrames__BEAT, oldStacksFrames__BEAT): bool <==> v2_u.SMemInvGc(argRet__BEAT, sMem__BEAT, oldSMem__BEAT, $esp__BEAT, oldEsp__BEAT, Abss#Frames(stacksFrames__BEAT[v2_u.$S]), Abss#Frames(oldStacksFrames__BEAT[v2_u.$S]))); axiom (forall argRet__BEAT: int, sMem__BEAT: mem, oldSMem__BEAT: mem, $esp__BEAT: int, oldEsp__BEAT: int, sAbs__BEAT: [int]int, oldSAbs__BEAT: [int]int :: { v2_u.SMemEnsureGc(argRet__BEAT, sMem__BEAT, oldSMem__BEAT, $esp__BEAT, oldEsp__BEAT, sAbs__BEAT, oldSAbs__BEAT): bool } v2_u.SMemEnsureGc(argRet__BEAT, sMem__BEAT, oldSMem__BEAT, $esp__BEAT, oldEsp__BEAT, sAbs__BEAT, oldSAbs__BEAT): bool <==> $esp__BEAT == oldEsp__BEAT + 4 && (forall i__BEAT__BEAT: int :: { map#mem(sMem__BEAT)[i__BEAT__BEAT] } $esp__BEAT + argRet__BEAT <= i__BEAT__BEAT ==> map#mem(sMem__BEAT)[i__BEAT__BEAT] == map#mem(oldSMem__BEAT)[i__BEAT__BEAT]) && (forall i__BEAT__BEAT: int :: { sAbs__BEAT[i__BEAT__BEAT] } $esp__BEAT + argRet__BEAT + v2_u.stackGcOffset <= i__BEAT__BEAT ==> sAbs__BEAT[i__BEAT__BEAT] == oldSAbs__BEAT[i__BEAT__BEAT])); axiom (forall argRet__BEAT: int, sMem__BEAT: mem, oldSMem__BEAT: mem, $esp__BEAT: int, oldEsp__BEAT: int, stacksFrames__BEAT: [int]Frames, oldStacksFrames__BEAT: [int]Frames :: { v2_u.SMemEnsureGcF(argRet__BEAT, sMem__BEAT, oldSMem__BEAT, $esp__BEAT, oldEsp__BEAT, stacksFrames__BEAT, oldStacksFrames__BEAT): bool } v2_u.SMemEnsureGcF(argRet__BEAT, sMem__BEAT, oldSMem__BEAT, $esp__BEAT, oldEsp__BEAT, stacksFrames__BEAT, oldStacksFrames__BEAT): bool <==> v2_u.SMemEnsureGc(argRet__BEAT, sMem__BEAT, oldSMem__BEAT, $esp__BEAT, oldEsp__BEAT, Abss#Frames(stacksFrames__BEAT[v2_u.$S]), Abss#Frames(oldStacksFrames__BEAT[v2_u.$S]))); ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Main/dafny_FatNatX86_i.imp.beat ================================================ //-private-import BaseSpec; //-private-import MemorySpec; //-private-import IoTypesSpec; //-private-import MachineStateSpec; //-private-import AssemblySpec; //-private-import InterruptsSpec; //-private-import IoSpec; //-private-import Overflow; //-private-import Core; //-private-import LogicalAddressing; //-private-import Util; //-private-import Stacks; //-private-import Partition; //-private-import Instructions; //-private-import Separation; //-private-import IntLemmasGc; //-private-import SimpleGcMemory; //-private-import SimpleCommon; //-private-import SimpleCollector; //-private-import IntLemmasMain; //-private-import IntLemmasBase; //-private-import IoMain; //-private-basmonly-import Trusted; //-private-basmonly-import Checked; //-private-import Heap; //-private-import Seq; //-private-import dafny_DafnyPrelude; //-private-import DafnyAssembly; //-private-import dafny_base_s; //-private-import dafny_power2_s; //-private-import dafny_bytes_and_words_s; //-private-import dafny_be_sequences_s; //-private-import dafny_integer_sequences_s; //-private-import dafny_seqs_simple_i; //-private-import dafny_power_s; //-private-import dafny_mul_nonlinear_i; //-private-import dafny_mul_i; //-private-import dafny_power_i; //-private-import dafny_div_def_i; //-private-import dafny_div_boogie_i; //-private-import dafny_div_nonlinear_i; //-private-import dafny_div_i; //-private-import dafny_repeat_digit_i; //-private-import dafny_assembly_s; //-private-import dafny_power2_i; //-private-import dafny_seqs_and_ints_i; //-private-import dafny_seqs_common_i; //-private-import dafny_Word32_i; //-private-import dafny_relational_s; //-private-import dafny_assembly_i; //-private-import dafny_arrays_i; //-private-import dafny_seqs_transforms_i; //-private-import dafny_seqs_reverse_i; //-private-import dafny_integer_sequences_i; //-private-import dafny_integer_sequences_premium_i; //-private-import dafny_assembly_premium_i; //-private-import dafny_BigNatX86Shim_i; //-private-import dafny_seqs_canonical_i; //-private-import dafny_CanonicalArrays_i; //-private-import dafny_FatNatCommon_i; //- //- //- //- //- module implementation dafny_FatNatX86_i { procedure arrayAdd(my r_old:regs, const my core_state:core_state, linear stk_old:mem, linear statics_old:mem, linear io_old:IOState, linear mems_old:mems, $commonVars_old:commonVars, $gcVars_old:gcVars, $toAbs_old:[int]int, $absMem_old:[int][int]int, $stacksFrames_old:[int]Frames, objLayouts_old:[int]ObjLayout, heap_old:Heap, $ghost_a:ArrayOfInt, $ghost_b:ArrayOfInt, $ghost_s:ArrayOfInt, a_opn:opn_mem, $ghost_a__abs:int, a_base:int, a_offset:int, b_opn:opn_mem, $ghost_b__abs:int, b_base:int, b_offset:int, s_opn:opn_mem, $ghost_s__abs:int, s_base:int, s_offset:int, $ghost_si:int, index_offset:int, old_carries:Seq___int, old_carry:int) returns(my r:regs, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars, $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap, new_carry:int, new_carries:Seq___int) requires MemInv(me,init,stk_old,statics_old,core_state,ptMem,mems_old); requires NucleusInv(objLayouts_old,$S,$toAbs_old,$absMem_old,$commonVars_old,$gcVars_old,me,init,stk_old,statics_old,core_state,ptMem,mems_old,$stacksFrames_old,io_old); requires HeapInv($absMem_old, objLayouts_old, heap_old); requires $ghost_a != (ArrayOfInt(0 - 1, NO_ABS)); requires fun_IsWordSeq(fun_Seq__FromArray($absMem_old, $ghost_a)); requires $ghost_b != (ArrayOfInt(0 - 1, NO_ABS)); requires fun_IsWordSeq(fun_Seq__FromArray($absMem_old, $ghost_b)); requires $ghost_s != (ArrayOfInt(0 - 1, NO_ABS)); requires $ghost_b != $ghost_s; requires $ghost_a != $ghost_s; requires $ghost_a__abs != $ghost_s__abs; requires $ghost_b__abs != $ghost_s__abs; requires s_offset == Arr_Length($ghost_s) - 1 - $ghost_si + index_offset; requires old_carry == if (Cf(r_old.efl)) then 1 else 0; requires $ghost_a.arrAbs == $ghost_a__abs; requires HeapAbsData(heap_old, $ghost_a__abs) is Abs_ArrayOfInt; requires 0 <= a_offset && a_offset < HeapAbsData(heap_old, $ghost_a__abs).arr.arrCount; requires HeapValue(objLayouts_old, true, $toAbs_old, a_base, $ghost_a__abs); requires EvalPtrOk(a_opn); requires EvalPtr(r_old, a_opn) == a_base + 4 * (2 + a_offset); requires a_opn._ptr is MReg && a_opn._ptr._mreg == EAX; requires $ghost_b.arrAbs == $ghost_b__abs; requires HeapAbsData(heap_old, $ghost_b__abs) is Abs_ArrayOfInt; requires 0 <= b_offset && b_offset < HeapAbsData(heap_old, $ghost_b__abs).arr.arrCount; requires HeapValue(objLayouts_old, true, $toAbs_old, b_base, $ghost_b__abs); requires EvalPtrOk(b_opn); requires EvalPtr(r_old, b_opn) == b_base + 4 * (2 + b_offset); requires b_opn._ptr is MReg && b_opn._ptr._mreg == EBX; requires $ghost_s.arrAbs == $ghost_s__abs; requires HeapAbsData(heap_old, $ghost_s__abs) is Abs_ArrayOfInt; requires 0 <= s_offset && s_offset < HeapAbsData(heap_old, $ghost_s__abs).arr.arrCount; requires HeapValue(objLayouts_old, true, $toAbs_old, s_base, $ghost_s__abs); requires EvalPtrOk(s_opn); requires EvalPtr(r_old, s_opn) == s_base + 4 * (2 + s_offset); requires s_opn._ptr is MReg && s_opn._ptr._mreg == ECX; modifies $Time; ensures stk == stk_old; ensures $stacksFrames == $stacksFrames_old; ensures (forall i:int::{$stacksFrames[$S].Abss[i]} i != EvalPtr(r_old, s_opn) ==> $stacksFrames[$S].Abss[i] == $stacksFrames_old[$S].Abss[i]); ensures MemInv(me,init,stk,statics,core_state,ptMem,mems); ensures NucleusInv(objLayouts,$S,$toAbs,$absMem,$commonVars,$gcVars,me,init,stk,statics,core_state,ptMem,mems,$stacksFrames,io); ensures HeapInv($absMem, objLayouts, heap); ensures AbsExtend($toAbs, $toAbs_old, objLayouts, objLayouts_old); ensures (forall i:int::{$absMem[i]}{heap.absData[i]} heap_old.absData[i] is AbsNone || (heap.absData[i] == heap_old.absData[i] && ($absMem[i] == $absMem_old[i] || i == (($ghost_s).arrAbs)))); ensures io._inCtr == io_old._inCtr && io._outCtr == io_old._outCtr; //- Only havocs edi, ebp ensures r.regs[EAX] == r_old.regs[EAX]; ensures r.regs[EBX] == r_old.regs[EBX]; ensures r.regs[ECX] == r_old.regs[ECX]; ensures r.regs[EDX] == r_old.regs[EDX]; ensures r.regs[ESI] == r_old.regs[ESI]; ensures r.regs[ESP] == r_old.regs[ESP]; ensures HeapValue(objLayouts, true, $toAbs, a_base, $ghost_a__abs); ensures HeapValue(objLayouts, true, $toAbs, b_base, $ghost_b__abs); ensures HeapValue(objLayouts, true, $toAbs, s_base, $ghost_s__abs); ensures new_carry == if (Cf(r.efl)) then 1 else 0; ensures new_carry == if ((fun_INTERNAL__array__elems__index($absMem[$ghost_a__abs], a_offset) + fun_INTERNAL__array__elems__index($absMem[$ghost_b__abs], b_offset) + old_carry) >= WORD_HI) then 1 else 0; ensures fun_INTERNAL__array__elems__index($absMem[$ghost_s__abs], s_offset) == fun_mod0x100000000(fun_INTERNAL__array__elems__index($absMem[$ghost_a__abs], a_offset) + fun_INTERNAL__array__elems__index($absMem[$ghost_b__abs], b_offset) + old_carry); //- Arrays A and B are unmodified ensures (forall j:int :: { fun_INTERNAL__array__elems__index($absMem[$ghost_a.arrAbs], j) } (((INTERNAL_le_boogie(0, j)) && (INTERNAL_lt_boogie(j, (Arr_Length($ghost_a)))))) ==> ((fun_INTERNAL__array__elems__index($absMem[$ghost_a.arrAbs], j)) == (old(fun_INTERNAL__array__elems__index($absMem_old[$ghost_a.arrAbs], j))))); ensures (forall j:int :: { fun_INTERNAL__array__elems__index($absMem[$ghost_b.arrAbs], j) } (((INTERNAL_le_boogie(0, j)) && (INTERNAL_lt_boogie(j, (Arr_Length($ghost_b)))))) ==> ((fun_INTERNAL__array__elems__index($absMem[$ghost_b.arrAbs], j)) == (old(fun_INTERNAL__array__elems__index($absMem_old[$ghost_b.arrAbs], j))))); //- Array S is unmodified except for the one entry we touch ensures (forall j:int :: { fun_INTERNAL__array__elems__index($absMem[$ghost_s.arrAbs], j) } (((INTERNAL_le_boogie(0, j)) && (INTERNAL_lt_boogie(j, (Arr_Length($ghost_s))))) && j != s_offset) ==> ((fun_INTERNAL__array__elems__index($absMem[$ghost_s.arrAbs], j)) == (old(fun_INTERNAL__array__elems__index($absMem_old[$ghost_s.arrAbs], j))))); ensures fun_Seq__Length___int(new_carries) == fun_Seq__Length___int(old_carries) + 1; ensures (forall i:int :: 0 <= i && i < fun_Seq__Length___int(old_carries) ==> fun_Seq__Index___int(new_carries, i) == fun_Seq__Index___int(old_carries, i)); ensures fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - 1) == new_carry; { //- Boilerplate variable propagation r := r_old; stk := stk_old; statics := statics_old; io := io_old; mems := mems_old; $commonVars := $commonVars_old; $gcVars := $gcVars_old; $toAbs := $toAbs_old; $absMem := $absMem_old; $stacksFrames := $stacksFrames_old; objLayouts := objLayouts_old; heap := heap_old; //- Teach Beat about Dafny sequence operations call proc_Seq__Empty__ToZero___int(); call proc_Seq__Empty__FromZero___int(); call proc_Seq__Singleton__Length___int(); call proc_Seq__Build__Length___int(); call proc_Seq__Build__Index___int(); call proc_Seq__Append__Length___int(); call proc_Seq__Index__Singleton___int(); call proc_Seq__Append__Index___int(); call proc_Seq__Update__Length___int(); call proc_Seq__Index__Update___int(); call proc_Seq__Equal__Equiv___int(); call proc_Seq__Take__Length___int(); call proc_Seq__Take__Index___int(); call proc_Seq__Drop__Length___int(); call proc_Seq__Drop__Index___int(); call proc_Seq__Append__TakeDrop___int(); call proc_Seq__Update__CommuteTake1___int(); call proc_Seq__Update__CommuteTake2___int(); call proc_Seq__Update__CommuteDrop1___int(); call proc_Seq__Update__CommuteDrop2___int(); call proc_Seq__Build__CommuteDrop___int(); call proc_Seq__Take__Empty___int(); call proc_Seq__Drop__Empty___int(); call proc_lemma__2toX(); call r, mems := loadArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, EDI, a_opn, a_offset, $ghost_a__abs, a_base); //- edi <- a[aii+1] call r, mems := loadArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, EBP, b_opn, b_offset, $ghost_b__abs, b_base); //- ebp <- b[bii+1] var old_edi:int := edi; var next_efl:int := r.efl; call edi := AddCarry(edi, ebp); //- edi == a[aii+index_offset] + b[bii+index_offset] + carry call reveal_wrap32(old_edi + ebp + old_carry); new_carry := if (old_edi + ebp + old_carry >= WORD_HI) then 1 else 0; new_carries := fun_Seq__Append___int(old_carries, fun_Seq__Build___int(fun_Seq__Empty___int(), new_carry)); //- Write the result in edi back to s[sii+index_offset] call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, s_opn, OReg(EDI), s_offset, edi, $ghost_s__abs, s_base); call reveal_wrap32(fun_INTERNAL__array__elems__index($absMem[$ghost_a__abs], a_offset) + fun_INTERNAL__array__elems__index($absMem[$ghost_b__abs], b_offset) + old_carry); call reveal_WORD_HI(); } procedure arrayAdd4(my r_old:regs, const my core_state:core_state, linear stk_old:mem, linear statics_old:mem, linear io_old:IOState, linear mems_old:mems, $commonVars_old:commonVars, $gcVars_old:gcVars, $toAbs_old:[int]int, $absMem_old:[int][int]int, $stacksFrames_old:[int]Frames, objLayouts_old:[int]ObjLayout, heap_old:Heap, $ghost_a:ArrayOfInt, $ghost_b:ArrayOfInt, $ghost_s:ArrayOfInt, a_opn1:opn_mem, a_opn2:opn_mem, a_opn3:opn_mem, a_opn4:opn_mem,$ghost_a__abs:int, a_base:int, a_offset1:int, a_offset2:int, a_offset3:int, a_offset4:int, b_opn1:opn_mem, b_opn2:opn_mem, b_opn3:opn_mem, b_opn4:opn_mem, $ghost_b__abs:int, b_base:int, b_offset1:int, b_offset2:int, b_offset3:int, b_offset4:int, s_opn1:opn_mem, s_opn2:opn_mem, s_opn3:opn_mem, s_opn4:opn_mem, $ghost_s__abs:int, s_base:int, s_offset1:int, s_offset2:int, s_offset3:int, s_offset4:int, $ghost_si:int, index_offset1:int, index_offset2:int, index_offset3:int, index_offset4:int, old_carries:Seq___int, old_carry:int) returns(my r:regs, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars, $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap, new_carry:int, new_carries:Seq___int) requires MemInv(me,init,stk_old,statics_old,core_state,ptMem,mems_old); requires NucleusInv(objLayouts_old,$S,$toAbs_old,$absMem_old,$commonVars_old,$gcVars_old,me,init,stk_old,statics_old,core_state,ptMem,mems_old,$stacksFrames_old,io_old); requires HeapInv($absMem_old, objLayouts_old, heap_old); requires $ghost_a != (ArrayOfInt(0 - 1, NO_ABS)); requires fun_IsWordSeq(fun_Seq__FromArray($absMem_old, $ghost_a)); requires $ghost_b != (ArrayOfInt(0 - 1, NO_ABS)); requires fun_IsWordSeq(fun_Seq__FromArray($absMem_old, $ghost_b)); requires $ghost_s != (ArrayOfInt(0 - 1, NO_ABS)); requires $ghost_b != $ghost_s; requires $ghost_a != $ghost_s; requires $ghost_a__abs != $ghost_s__abs; requires $ghost_b__abs != $ghost_s__abs; requires s_offset1 == Arr_Length($ghost_s) - 1 - $ghost_si + index_offset1; requires s_offset2 == Arr_Length($ghost_s) - 1 - $ghost_si + index_offset2; requires s_offset3 == Arr_Length($ghost_s) - 1 - $ghost_si + index_offset3; requires s_offset4 == Arr_Length($ghost_s) - 1 - $ghost_si + index_offset4; requires old_carry == if (Cf(r_old.efl)) then 1 else 0; requires $ghost_a.arrAbs == $ghost_a__abs; requires HeapAbsData(heap_old, $ghost_a__abs) is Abs_ArrayOfInt; requires 0 <= a_offset1 && a_offset1 < HeapAbsData(heap_old, $ghost_a__abs).arr.arrCount; requires 0 <= a_offset2 && a_offset2 < HeapAbsData(heap_old, $ghost_a__abs).arr.arrCount; requires 0 <= a_offset3 && a_offset3 < HeapAbsData(heap_old, $ghost_a__abs).arr.arrCount; requires 0 <= a_offset4 && a_offset4 < HeapAbsData(heap_old, $ghost_a__abs).arr.arrCount; requires HeapValue(objLayouts_old, true, $toAbs_old, a_base, $ghost_a__abs); requires EvalPtrOk(a_opn1); requires EvalPtrOk(a_opn2); requires EvalPtrOk(a_opn3); requires EvalPtrOk(a_opn4); requires EvalPtr(r_old, a_opn1) == a_base + 4 * (2 + a_offset1); requires EvalPtr(r_old, a_opn2) == a_base + 4 * (2 + a_offset2); requires EvalPtr(r_old, a_opn3) == a_base + 4 * (2 + a_offset3); requires EvalPtr(r_old, a_opn4) == a_base + 4 * (2 + a_offset4); requires a_offset1 == a_offset2 + 1 && a_offset2 == a_offset3 + 1 && a_offset3 == a_offset4 + 1; requires a_opn1._ptr is MReg && a_opn1._ptr._mreg == EAX; requires a_opn2._ptr is MReg && a_opn2._ptr._mreg == EAX; requires a_opn3._ptr is MReg && a_opn3._ptr._mreg == EAX; requires a_opn4._ptr is MReg && a_opn4._ptr._mreg == EAX; requires $ghost_b.arrAbs == $ghost_b__abs; requires HeapAbsData(heap_old, $ghost_b__abs) is Abs_ArrayOfInt; requires 0 <= b_offset1 && b_offset1 < HeapAbsData(heap_old, $ghost_b__abs).arr.arrCount; requires 0 <= b_offset2 && b_offset2 < HeapAbsData(heap_old, $ghost_b__abs).arr.arrCount; requires 0 <= b_offset3 && b_offset3 < HeapAbsData(heap_old, $ghost_b__abs).arr.arrCount; requires 0 <= b_offset4 && b_offset4 < HeapAbsData(heap_old, $ghost_b__abs).arr.arrCount; requires HeapValue(objLayouts_old, true, $toAbs_old, b_base, $ghost_b__abs); requires EvalPtrOk(b_opn1); requires EvalPtrOk(b_opn2); requires EvalPtrOk(b_opn3); requires EvalPtrOk(b_opn4); requires EvalPtr(r_old, b_opn1) == b_base + 4 * (2 + b_offset1); requires EvalPtr(r_old, b_opn2) == b_base + 4 * (2 + b_offset2); requires EvalPtr(r_old, b_opn3) == b_base + 4 * (2 + b_offset3); requires EvalPtr(r_old, b_opn4) == b_base + 4 * (2 + b_offset4); requires b_offset1 == b_offset2 + 1 && b_offset2 == b_offset3 + 1 && b_offset3 == b_offset4 + 1; requires b_opn1._ptr is MReg && b_opn1._ptr._mreg == EBX; requires b_opn2._ptr is MReg && b_opn2._ptr._mreg == EBX; requires b_opn3._ptr is MReg && b_opn3._ptr._mreg == EBX; requires b_opn4._ptr is MReg && b_opn4._ptr._mreg == EBX; requires $ghost_s.arrAbs == $ghost_s__abs; requires HeapAbsData(heap_old, $ghost_s__abs) is Abs_ArrayOfInt; requires 0 <= s_offset1 && s_offset1 < HeapAbsData(heap_old, $ghost_s__abs).arr.arrCount; requires 0 <= s_offset2 && s_offset2 < HeapAbsData(heap_old, $ghost_s__abs).arr.arrCount; requires 0 <= s_offset3 && s_offset3 < HeapAbsData(heap_old, $ghost_s__abs).arr.arrCount; requires 0 <= s_offset4 && s_offset4 < HeapAbsData(heap_old, $ghost_s__abs).arr.arrCount; requires INTERNAL_lt_boogie(s_offset1, (Arr_Length($ghost_s))); requires INTERNAL_lt_boogie(s_offset2, (Arr_Length($ghost_s))); requires INTERNAL_lt_boogie(s_offset3, (Arr_Length($ghost_s))); requires INTERNAL_lt_boogie(s_offset4, (Arr_Length($ghost_s))); requires HeapValue(objLayouts_old, true, $toAbs_old, s_base, $ghost_s__abs); requires EvalPtrOk(s_opn1); requires EvalPtrOk(s_opn2); requires EvalPtrOk(s_opn3); requires EvalPtrOk(s_opn4); requires EvalPtr(r_old, s_opn1) == s_base + 4 * (2 + s_offset1); requires EvalPtr(r_old, s_opn2) == s_base + 4 * (2 + s_offset2); requires EvalPtr(r_old, s_opn3) == s_base + 4 * (2 + s_offset3); requires EvalPtr(r_old, s_opn4) == s_base + 4 * (2 + s_offset4); requires s_offset1 == s_offset2 + 1 && s_offset2 == s_offset3 + 1 && s_offset3 == s_offset4 + 1; requires s_opn1._ptr is MReg && s_opn1._ptr._mreg == ECX; requires s_opn2._ptr is MReg && s_opn2._ptr._mreg == ECX; requires s_opn3._ptr is MReg && s_opn3._ptr._mreg == ECX; requires s_opn4._ptr is MReg && s_opn4._ptr._mreg == ECX; requires fun_Seq__Length___int(old_carries) > 0; requires fun_Seq__Index___int(old_carries, fun_Seq__Length___int(old_carries) - 1) == old_carry; modifies $Time; ensures stk == stk_old; ensures $stacksFrames == $stacksFrames_old; ensures (forall i:int::{$stacksFrames[$S].Abss[i]} i != EvalPtr(r_old, s_opn1) && i != EvalPtr(r_old, s_opn2) && i != EvalPtr(r_old, s_opn3) && i != EvalPtr(r_old, s_opn4) ==> $stacksFrames[$S].Abss[i] == $stacksFrames_old[$S].Abss[i]); ensures MemInv(me,init,stk,statics,core_state,ptMem,mems); ensures NucleusInv(objLayouts,$S,$toAbs,$absMem,$commonVars,$gcVars,me,init,stk,statics,core_state,ptMem,mems,$stacksFrames,io); ensures HeapInv($absMem, objLayouts, heap); ensures AbsExtend($toAbs, $toAbs_old, objLayouts, objLayouts_old); ensures (forall i:int::{$absMem[i]}{heap.absData[i]} heap_old.absData[i] is AbsNone || (heap.absData[i] == heap_old.absData[i] && ($absMem[i] == $absMem_old[i] || i == (($ghost_s).arrAbs)))); ensures io._inCtr == io_old._inCtr && io._outCtr == io_old._outCtr; //- Only havocs edi, ebp ensures r.regs[EAX] == r_old.regs[EAX]; ensures r.regs[EBX] == r_old.regs[EBX]; ensures r.regs[ECX] == r_old.regs[ECX]; ensures r.regs[EDX] == r_old.regs[EDX]; ensures r.regs[ESI] == r_old.regs[ESI]; ensures r.regs[ESP] == r_old.regs[ESP]; ensures HeapValue(objLayouts, true, $toAbs, a_base, $ghost_a__abs); ensures HeapValue(objLayouts, true, $toAbs, b_base, $ghost_b__abs); ensures HeapValue(objLayouts, true, $toAbs, s_base, $ghost_s__abs); ensures new_carry == if (Cf(r.efl)) then 1 else 0; ensures new_carry == if ((fun_INTERNAL__array__elems__index($absMem[$ghost_a__abs], a_offset4) + fun_INTERNAL__array__elems__index($absMem[$ghost_b__abs], b_offset4) + fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - 2)) >= WORD_HI) then 1 else 0; //if ((fun_INTERNAL__array__elems__index($absMem[$ghost_a__abs], a_offset4) + fun_INTERNAL__array__elems__index($absMem[$ghost_b__abs], b_offset4) + old_carry) >= WORD_HI) then 1 else 0; ensures fun_INTERNAL__array__elems__index($absMem[$ghost_s__abs], s_offset1) == fun_mod0x100000000(fun_INTERNAL__array__elems__index($absMem[$ghost_a__abs], a_offset1) + fun_INTERNAL__array__elems__index($absMem[$ghost_b__abs], b_offset1) + old_carry); ensures fun_INTERNAL__array__elems__index($absMem[$ghost_s__abs], s_offset2) == fun_mod0x100000000(fun_INTERNAL__array__elems__index($absMem[$ghost_a__abs], a_offset2) + fun_INTERNAL__array__elems__index($absMem[$ghost_b__abs], b_offset2) + fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - 4)); ensures fun_INTERNAL__array__elems__index($absMem[$ghost_s__abs], s_offset3) == fun_mod0x100000000(fun_INTERNAL__array__elems__index($absMem[$ghost_a__abs], a_offset3) + fun_INTERNAL__array__elems__index($absMem[$ghost_b__abs], b_offset3) + fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - 3)); ensures fun_INTERNAL__array__elems__index($absMem[$ghost_s__abs], s_offset4) == fun_mod0x100000000(fun_INTERNAL__array__elems__index($absMem[$ghost_a__abs], a_offset4) + fun_INTERNAL__array__elems__index($absMem[$ghost_b__abs], b_offset4) + fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - 2)); //- Arrays A and B are unmodified ensures (forall j:int :: { fun_INTERNAL__array__elems__index($absMem[$ghost_a.arrAbs], j) } (((INTERNAL_le_boogie(0, j)) && (INTERNAL_lt_boogie(j, (Arr_Length($ghost_a)))))) ==> ((fun_INTERNAL__array__elems__index($absMem[$ghost_a.arrAbs], j)) == (old(fun_INTERNAL__array__elems__index($absMem_old[$ghost_a.arrAbs], j))))); ensures (forall j:int :: { fun_INTERNAL__array__elems__index($absMem[$ghost_b.arrAbs], j) } (((INTERNAL_le_boogie(0, j)) && (INTERNAL_lt_boogie(j, (Arr_Length($ghost_b)))))) ==> ((fun_INTERNAL__array__elems__index($absMem[$ghost_b.arrAbs], j)) == (old(fun_INTERNAL__array__elems__index($absMem_old[$ghost_b.arrAbs], j))))); //- Array S is unmodified except for the four entries we touch ensures (forall j:int :: { fun_INTERNAL__array__elems__index($absMem[$ghost_s.arrAbs], j) } (((INTERNAL_le_boogie(0, j)) && (INTERNAL_lt_boogie(j, (Arr_Length($ghost_s))))) && j != s_offset1 && j != s_offset2 && j != s_offset3 && j != s_offset4) ==> ((fun_INTERNAL__array__elems__index($absMem[$ghost_s.arrAbs], j)) == (old(fun_INTERNAL__array__elems__index($absMem_old[$ghost_s.arrAbs], j))))); ensures fun_Seq__Length___int(new_carries) == fun_Seq__Length___int(old_carries) + 4; ensures (forall i:int :: 0 <= i && i < fun_Seq__Length___int(old_carries) ==> fun_Seq__Index___int(new_carries, i) == fun_Seq__Index___int(old_carries, i)); ensures fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - 4) == if ((fun_INTERNAL__array__elems__index($absMem[$ghost_a__abs], a_offset1) + fun_INTERNAL__array__elems__index($absMem[$ghost_b__abs], b_offset1) + old_carry) >= WORD_HI) then 1 else 0; ensures fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - 3) == if ((fun_INTERNAL__array__elems__index($absMem[$ghost_a__abs], a_offset2) + fun_INTERNAL__array__elems__index($absMem[$ghost_b__abs], b_offset2) + fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - 4)) >= WORD_HI) then 1 else 0; ensures fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - 2) == if ((fun_INTERNAL__array__elems__index($absMem[$ghost_a__abs], a_offset3) + fun_INTERNAL__array__elems__index($absMem[$ghost_b__abs], b_offset3) + fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - 3)) >= WORD_HI) then 1 else 0; ensures fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - 1) == new_carry; ensures (forall i:int :: TV(i) && 1 <= i && i <= 4 ==> fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - i) == if ((fun_INTERNAL__array__elems__index($absMem[$ghost_a__abs], a_offset4 + i - 1) + fun_INTERNAL__array__elems__index($absMem[$ghost_b__abs], b_offset4 + i - 1) + fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - (i+1))) >= WORD_HI) then 1 else 0); { var $ghost_carries:Seq___int; var carry1:int; var carry2:int; var carry3:int; //- Boilerplate variable propagation r := r_old; stk := stk_old; statics := statics_old; io := io_old; mems := mems_old; $commonVars := $commonVars_old; $gcVars := $gcVars_old; $toAbs := $toAbs_old; $absMem := $absMem_old; $stacksFrames := $stacksFrames_old; objLayouts := objLayouts_old; heap := heap_old; //- Teach Beat about Dafny sequence operations call proc_Seq__Empty__ToZero___int(); call proc_Seq__Empty__FromZero___int(); call proc_Seq__Singleton__Length___int(); call proc_Seq__Build__Length___int(); call proc_Seq__Build__Index___int(); call proc_Seq__Append__Length___int(); call proc_Seq__Index__Singleton___int(); call proc_Seq__Append__Index___int(); call proc_Seq__Update__Length___int(); call proc_Seq__Index__Update___int(); call proc_Seq__Equal__Equiv___int(); call proc_Seq__Take__Length___int(); call proc_Seq__Take__Index___int(); call proc_Seq__Drop__Length___int(); call proc_Seq__Drop__Index___int(); call proc_Seq__Append__TakeDrop___int(); call proc_Seq__Update__CommuteTake1___int(); call proc_Seq__Update__CommuteTake2___int(); call proc_Seq__Update__CommuteDrop1___int(); call proc_Seq__Update__CommuteDrop2___int(); call proc_Seq__Build__CommuteDrop___int(); call proc_Seq__Take__Empty___int(); call proc_Seq__Drop__Empty___int(); call proc_lemma__2toX(); $ghost_carries := old_carries; call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry1, $ghost_carries := arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_a, $ghost_b, $ghost_s, a_opn1, $ghost_a__abs, a_base, a_offset1, b_opn1, $ghost_b__abs, b_base, b_offset1, s_opn1, $ghost_s__abs, s_base, s_offset1, $ghost_si, index_offset1, $ghost_carries, old_carry); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry2, $ghost_carries := arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_a, $ghost_b, $ghost_s, a_opn2, $ghost_a__abs, a_base, a_offset2, b_opn2, $ghost_b__abs, b_base, b_offset2, s_opn2, $ghost_s__abs, s_base, s_offset2, $ghost_si, index_offset2, $ghost_carries, carry1); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry3, $ghost_carries := arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_a, $ghost_b, $ghost_s, a_opn3, $ghost_a__abs, a_base, a_offset3, b_opn3, $ghost_b__abs, b_base, b_offset3, s_opn3, $ghost_s__abs, s_base, s_offset3, $ghost_si, index_offset3, $ghost_carries, carry2); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, new_carry, $ghost_carries := arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_a, $ghost_b, $ghost_s, a_opn4, $ghost_a__abs, a_base, a_offset4, b_opn4, $ghost_b__abs, b_base, b_offset4, s_opn4, $ghost_s__abs, s_base, s_offset4, $ghost_si, index_offset4, $ghost_carries, carry3); new_carries := $ghost_carries; } implementation Proc_Add32__unrolled__8(my r_old:regs, const my core_state:core_state, linear stk_old:mem, linear statics_old:mem, linear io_old:IOState, linear mems_old:mems, $commonVars_old:commonVars, $gcVars_old:gcVars, $toAbs_old:[int]int, $absMem_old:[int][int]int, $stacksFrames_old:[int]Frames, objLayouts_old:[int]ObjLayout, heap_old:Heap, $ghost_a:ArrayOfInt, $ghost_ai:int, $ghost_b:ArrayOfInt, $ghost_bi:int, $ghost_s:ArrayOfInt, $ghost_si:int, $ghost_c_in:int) returns(my r:regs, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars, $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap, $ghost_c_out:int, $ghost_carries:Seq___int) { var $ghost_a__abs:int; var $ghost_b__abs:int; var $ghost_s__abs:int; var gcStackOffset:int; //- Boilerplate variable propagation r := r_old; stk := stk_old; statics := statics_old; io := io_old; mems := mems_old; $commonVars := $commonVars_old; $gcVars := $gcVars_old; $toAbs := $toAbs_old; $absMem := $absMem_old; $stacksFrames := $stacksFrames_old; objLayouts := objLayouts_old; heap := heap_old; //- Teach Beat about Dafny sequence operations call proc_Seq__Empty__ToZero___int(); call proc_Seq__Empty__FromZero___int(); call proc_Seq__Singleton__Length___int(); call proc_Seq__Build__Length___int(); call proc_Seq__Build__Index___int(); call proc_Seq__Append__Length___int(); call proc_Seq__Index__Singleton___int(); call proc_Seq__Append__Index___int(); call proc_Seq__Update__Length___int(); call proc_Seq__Index__Update___int(); call proc_Seq__Equal__Equiv___int(); call proc_Seq__Take__Length___int(); call proc_Seq__Take__Index___int(); call proc_Seq__Drop__Length___int(); call proc_Seq__Drop__Index___int(); call proc_Seq__Append__TakeDrop___int(); //- call proc_Seq__Append__TakeDrop__Restricted___int(); call proc_Seq__Update__CommuteTake1___int(); call proc_Seq__Update__CommuteTake2___int(); call proc_Seq__Update__CommuteDrop1___int(); call proc_Seq__Update__CommuteDrop2___int(); call proc_Seq__Build__CommuteDrop___int(); call proc_Seq__Take__Empty___int(); call proc_Seq__Drop__Empty___int(); gcStackOffset := 0x111000; call proc_lemma__2toX(); assert Aligned(esp); //- Prove that we can load arguments from the stack (b/c accesses are aligned) assert TV(esp) && TO(0) && TO(1) && TO(2) && TO(3) && TO(4) && TO(5); //- Prove that we can load arguments from the GC stack (b/c accesses are aligned) assert TO(0x44401) && TO(0x44402) && TO(0x44403); //- (gcStackOffset + {4,8,12}) / 4 //- Load pointer to array a into edx call r, mems := heapLoadStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, EDX, OMem(MReg(ESP, 0x111004)), EvalPtr(r, OMem(MReg(ESP, 0x111004)))); //- 0x111004 = gcStackOffset + 4 var a_base:int; a_base := edx; $ghost_a__abs := frameGet($stacksFrames, EvalPtr(r, OMem(MReg(ESP, gcStackOffset + 4)))); //- Load its length into eax call r, mems := loadArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, EAX, OMem(MReg(EDX, 4)), 0 - 1, $ghost_a__abs, r.regs[EDX]); //- Adjust to the "beginning" of the values we care about eax := eax - 1; call edi := Load(stk, esp + 8); //- grab ai eax := eax - edi; var aii:int := eax; assert aii == Arr_Length($ghost_a) - 1 - $ghost_ai; //- Convert aii into a memory pointer call arrayElementProperties(core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, aii, $ghost_a__abs, edx); //- Proves we're within bounds for the Lea calculation call eax := Lea(edx + 4 * eax + 8); var aii_ptr @ eax; //- Load pointer to array b into edx call r, mems := heapLoadStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, EDX, OMem(MReg(ESP, 0x111008)), EvalPtr(r, OMem(MReg(ESP, 0x111008)))); //- 0x111008 = gcStackOffset + 8 var b_base:int; b_base := edx; $ghost_b__abs := frameGet($stacksFrames, EvalPtr(r, OMem(MReg(ESP, gcStackOffset + 8)))); //- Load its length into ebx call r, mems := loadArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, EBX, OMem(MReg(EDX, 4)), 0 - 1, $ghost_b__abs, r.regs[EDX]); //- Adjust to the "beginning" of the values we care about ebx := ebx - 1; call edi := Load(stk, esp + 12); //- grab bi ebx := ebx - edi; var bii:int := ebx; assert bii == Arr_Length($ghost_b) - 1 - $ghost_bi; //- Convert aii into a memory pointer call arrayElementProperties(core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, bii, $ghost_b__abs, edx); //- Proves we're within bounds for the Lea calculation call ebx := Lea(edx + 4 * ebx + 8); var bii_ptr @ ebx; //- Load pointer to array s into edx call r, mems := heapLoadStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, EDX, OMem(MReg(ESP, 0x11100c)), EvalPtr(r, OMem(MReg(ESP, 0x11100c)))); //- 0x11100c == gcStackOffset + 12 var s_base:int; s_base := edx; $ghost_s__abs := frameGet($stacksFrames, EvalPtr(r, OMem(MReg(ESP, gcStackOffset + 12)))); //- Load its length into ecx call r, mems := loadArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, ECX, OMem(MReg(EDX, 4)), 0 - 1, $ghost_s__abs, r.regs[EDX]); //- Adjust to the "beginning" of the values we care about ecx := ecx - 1; call edi := Load(stk, esp + 16); //- grab si ecx := ecx - edi; var sii:int := ecx; assert sii == Arr_Length($ghost_s) - 1 - $ghost_si; //- Convert sii into a memory pointer call arrayElementProperties(core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, sii, $ghost_s__abs, edx); //- Proves we're within bounds for the Lea calculation call ecx := Lea(edx + 4 * ecx + 8); var sii_ptr @ ecx; //-///////////// Start computing ////////////////////////// //- First, "load" c_in into CF via a sneaky addition call edi := Load(stk, esp + 20); //- grab c_in assert edi == $ghost_c_in; call r := instr_Add(r, EDI, OConst(0xffffffff)); assert Cf(r.efl) == ($ghost_c_in == 1); //- Build the carries sequence $ghost_carries := fun_Seq__Build___int(fun_Seq__Empty___int(), $ghost_c_in); var carry:int; call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := arrayAdd4(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_a, $ghost_b, $ghost_s, OMem(MReg(EAX, 0)), OMem(MReg(EAX, (-4))), OMem(MReg(EAX, (-8))), OMem(MReg(EAX, (-12))), $ghost_a__abs, a_base, aii-0, aii-1, aii-2, aii-3, OMem(MReg(EBX, 0)), OMem(MReg(EBX, (-4))), OMem(MReg(EBX, (-8))), OMem(MReg(EBX, (-12))), $ghost_b__abs, b_base, bii-0, bii-1, bii-2, bii-3, OMem(MReg(ECX, 0)), OMem(MReg(ECX, (-4))), OMem(MReg(ECX, (-8))), OMem(MReg(ECX, (-12))), $ghost_s__abs, s_base, sii-0, sii-1, sii-2, sii-3, $ghost_si, 0, (-1), (-2), (-3), $ghost_carries, $ghost_c_in); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := arrayAdd4(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_a, $ghost_b, $ghost_s, OMem(MReg(EAX, (-16))), OMem(MReg(EAX, (-20))), OMem(MReg(EAX, (-24))), OMem(MReg(EAX, (-28))), $ghost_a__abs, a_base, aii-4, aii-5, aii-6, aii-7, OMem(MReg(EBX, (-16))), OMem(MReg(EBX, (-20))), OMem(MReg(EBX, (-24))), OMem(MReg(EBX, (-28))), $ghost_b__abs, b_base, bii-4, bii-5, bii-6, bii-7, OMem(MReg(ECX, (-16))), OMem(MReg(ECX, (-20))), OMem(MReg(ECX, (-24))), OMem(MReg(ECX, (-28))), $ghost_s__abs, s_base, sii-4, sii-5, sii-6, sii-7, $ghost_si, (-4), (-5), (-6), (-7), $ghost_carries, carry); //- Extract the final carry bit from EFL eax := 0; call r := instr_GetCf(r, EAX); assert Aligned(esp); assert Aligned(esp + 4); call Store(inout stk, esp + 4, eax); $ghost_c_out := carry; assert $ghost_a.arrAbs != $ghost_s.arrAbs; Return; } //implementation Proc_Add32__unrolled__8(my r_old:regs, const my core_state:core_state, linear stk_old:mem, linear statics_old:mem, linear io_old:IOState, linear mems_old:mems, $commonVars_old:commonVars, $gcVars_old:gcVars, $toAbs_old:[int]int, $absMem_old:[int][int]int, $stacksFrames_old:[int]Frames, objLayouts_old:[int]ObjLayout, heap_old:Heap, $ghost_a:ArrayOfInt, $ghost_ai:int, $ghost_b:ArrayOfInt, $ghost_bi:int, $ghost_s:ArrayOfInt, $ghost_si:int, $ghost_c_in:int) returns(my r:regs, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars, $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap, $ghost_c_out:int, $ghost_carries:Seq___int) //{ // var $ghost_a__abs:int; // var $ghost_b__abs:int; // var $ghost_s__abs:int; // var gcStackOffset:int; // // // Boilerplate variable propagation // r := r_old; // stk := stk_old; // statics := statics_old; // io := io_old; // mems := mems_old; // $commonVars := $commonVars_old; // $gcVars := $gcVars_old; // $toAbs := $toAbs_old; // $absMem := $absMem_old; // $stacksFrames := $stacksFrames_old; // objLayouts := objLayouts_old; // heap := heap_old; // // // Teach Beat about Dafny sequence operations // call proc_Seq__Empty__ToZero___int(); // call proc_Seq__Empty__FromZero___int(); // call proc_Seq__Singleton__Length___int(); // call proc_Seq__Build__Length___int(); // call proc_Seq__Build__Index___int(); // call proc_Seq__Append__Length___int(); // call proc_Seq__Index__Singleton___int(); // call proc_Seq__Append__Index___int(); // call proc_Seq__Update__Length___int(); // call proc_Seq__Index__Update___int(); // call proc_Seq__Equal__Equiv___int(); // call proc_Seq__Take__Length___int(); // call proc_Seq__Take__Index___int(); // call proc_Seq__Drop__Length___int(); // call proc_Seq__Drop__Index___int(); // call proc_Seq__Append__TakeDrop___int(); // // call proc_Seq__Append__TakeDrop__Restricted___int(); // call proc_Seq__Update__CommuteTake1___int(); // call proc_Seq__Update__CommuteTake2___int(); // call proc_Seq__Update__CommuteDrop1___int(); // call proc_Seq__Update__CommuteDrop2___int(); // call proc_Seq__Build__CommuteDrop___int(); // call proc_Seq__Take__Empty___int(); // call proc_Seq__Drop__Empty___int(); // // gcStackOffset := 0x111000; // // call proc_lemma__2toX(); // // assert Aligned(esp); // // Prove that we can load arguments from the stack (b/c accesses are aligned) // assert TV(esp) && TO(0) && TO(1) && TO(2) && TO(3) && TO(4) && TO(5); // // // Prove that we can load arguments from the GC stack (b/c accesses are aligned) // assert TO(0x44401) && TO(0x44402) && TO(0x44403); // (gcStackOffset + {4,8,12}) / 4 // // // Load pointer to array a into edx // call r, mems := heapLoadStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, EDX, OMem(MReg(ESP, 0x111004)), EvalPtr(r, OMem(MReg(ESP, 0x111004)))); // 0x111004 = gcStackOffset + 4 // var a_base:int; // a_base := edx; // $ghost_a__abs := frameGet($stacksFrames, EvalPtr(r, OMem(MReg(ESP, gcStackOffset + 4)))); // // // Load its length into eax // call r, mems := loadArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, EAX, OMem(MReg(EDX, 4)), 0 - 1, $ghost_a__abs, r.regs[EDX]); // // // Adjust to the "beginning" of the values we care about // eax := eax - 1; // call edi := Load(stk, esp + 8); // grab ai // eax := eax - edi; // var aii:int := eax; // assert aii == Arr_Length($ghost_a) - 1 - $ghost_ai; // // // Convert aii into a memory pointer // call arrayElementProperties(core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, aii, $ghost_a__abs, edx); // Proves we're within bounds for the Lea calculation // call eax := Lea(edx + 4 * eax + 8); // var aii_ptr @ eax; // // // Load pointer to array b into edx // call r, mems := heapLoadStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, EDX, OMem(MReg(ESP, 0x111008)), EvalPtr(r, OMem(MReg(ESP, 0x111008)))); // 0x111008 = gcStackOffset + 8 // var b_base:int; // b_base := edx; // $ghost_b__abs := frameGet($stacksFrames, EvalPtr(r, OMem(MReg(ESP, gcStackOffset + 8)))); // // // Load its length into ebx // call r, mems := loadArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, EBX, OMem(MReg(EDX, 4)), 0 - 1, $ghost_b__abs, r.regs[EDX]); // // // Adjust to the "beginning" of the values we care about // ebx := ebx - 1; // call edi := Load(stk, esp + 12); // grab bi // ebx := ebx - edi; // var bii:int := ebx; // assert bii == Arr_Length($ghost_b) - 1 - $ghost_bi; // // // Convert aii into a memory pointer // call arrayElementProperties(core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, bii, $ghost_b__abs, edx); // Proves we're within bounds for the Lea calculation // call ebx := Lea(edx + 4 * ebx + 8); // var bii_ptr @ ebx; // // // Load pointer to array s into edx // call r, mems := heapLoadStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, EDX, OMem(MReg(ESP, 0x11100c)), EvalPtr(r, OMem(MReg(ESP, 0x11100c)))); // 0x11100c == gcStackOffset + 12 // var s_base:int; // s_base := edx; // $ghost_s__abs := frameGet($stacksFrames, EvalPtr(r, OMem(MReg(ESP, gcStackOffset + 12)))); // // // Load its length into ecx // call r, mems := loadArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, ECX, OMem(MReg(EDX, 4)), 0 - 1, $ghost_s__abs, r.regs[EDX]); // // // Adjust to the "beginning" of the values we care about // ecx := ecx - 1; // call edi := Load(stk, esp + 16); // grab si // ecx := ecx - edi; // var sii:int := ecx; // assert sii == Arr_Length($ghost_s) - 1 - $ghost_si; // // // Convert sii into a memory pointer // call arrayElementProperties(core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, sii, $ghost_s__abs, edx); // Proves we're within bounds for the Lea calculation // call ecx := Lea(edx + 4 * ecx + 8); // var sii_ptr @ ecx; // // /////////////// Start computing ////////////////////////// // // // First, "load" c_in into CF via a sneaky addition // call edi := Load(stk, esp + 20); // grab c_in // assert edi == $ghost_c_in; // call r := instr_Add(r, EDI, OConst(0xffffffff)); // assert Cf(r.efl) == ($ghost_c_in == 1); // // // Build the carries sequence // $ghost_carries := fun_Seq__Build___int(fun_Seq__Empty___int(), $ghost_c_in); // // var carry:int; // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, 0)), $ghost_a__abs, a_base, aii-0, // OMem(MReg(EBX, 0)), $ghost_b__abs, b_base, bii-0, // OMem(MReg(ECX, 0)), $ghost_s__abs, s_base, sii-0, // $ghost_si, 0, $ghost_carries, $ghost_c_in); // // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-4))), $ghost_a__abs, a_base, aii-1, // OMem(MReg(EBX, (-4))), $ghost_b__abs, b_base, bii-1, // OMem(MReg(ECX, (-4))), $ghost_s__abs, s_base, sii-1, // $ghost_si, (-1), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-8))), $ghost_a__abs, a_base, aii-2, // OMem(MReg(EBX, (-8))), $ghost_b__abs, b_base, bii-2, // OMem(MReg(ECX, (-8))), $ghost_s__abs, s_base, sii-2, // $ghost_si, (-2), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-12))), $ghost_a__abs, a_base, aii-3, // OMem(MReg(EBX, (-12))), $ghost_b__abs, b_base, bii-3, // OMem(MReg(ECX, (-12))), $ghost_s__abs, s_base, sii-3, // $ghost_si, (-3), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-16))), $ghost_a__abs, a_base, aii-4, // OMem(MReg(EBX, (-16))), $ghost_b__abs, b_base, bii-4, // OMem(MReg(ECX, (-16))), $ghost_s__abs, s_base, sii-4, // $ghost_si, (-4), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-20))), $ghost_a__abs, a_base, aii-5, // OMem(MReg(EBX, (-20))), $ghost_b__abs, b_base, bii-5, // OMem(MReg(ECX, (-20))), $ghost_s__abs, s_base, sii-5, // $ghost_si, (-5), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-24))), $ghost_a__abs, a_base, aii-6, // OMem(MReg(EBX, (-24))), $ghost_b__abs, b_base, bii-6, // OMem(MReg(ECX, (-24))), $ghost_s__abs, s_base, sii-6, // $ghost_si, (-6), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-28))), $ghost_a__abs, a_base, aii-7, // OMem(MReg(EBX, (-28))), $ghost_b__abs, b_base, bii-7, // OMem(MReg(ECX, (-28))), $ghost_s__abs, s_base, sii-7, // $ghost_si, (-7), $ghost_carries, carry); // // // Extract the final carry bit from EFL // eax := 0; // call r := instr_GetCf(r, EAX); // assert Aligned(esp); // assert Aligned(esp + 4); // call Store(inout stk, esp + 4, eax); // $ghost_c_out := carry; // // assert $ghost_a.arrAbs != $ghost_s.arrAbs; // // Return; //} implementation Proc_Add32__unrolled__16(my r_old:regs, const my core_state:core_state, linear stk_old:mem, linear statics_old:mem, linear io_old:IOState, linear mems_old:mems, $commonVars_old:commonVars, $gcVars_old:gcVars, $toAbs_old:[int]int, $absMem_old:[int][int]int, $stacksFrames_old:[int]Frames, objLayouts_old:[int]ObjLayout, heap_old:Heap, $ghost_a:ArrayOfInt, $ghost_ai:int, $ghost_b:ArrayOfInt, $ghost_bi:int, $ghost_s:ArrayOfInt, $ghost_si:int, $ghost_c_in:int) returns(my r:regs, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars, $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap, $ghost_c_out:int, $ghost_carries:Seq___int) { var $ghost_a__abs:int; var $ghost_b__abs:int; var $ghost_s__abs:int; var gcStackOffset:int; //- Boilerplate variable propagation r := r_old; stk := stk_old; statics := statics_old; io := io_old; mems := mems_old; $commonVars := $commonVars_old; $gcVars := $gcVars_old; $toAbs := $toAbs_old; $absMem := $absMem_old; $stacksFrames := $stacksFrames_old; objLayouts := objLayouts_old; heap := heap_old; //- Teach Beat about Dafny sequence operations call proc_Seq__Empty__ToZero___int(); call proc_Seq__Empty__FromZero___int(); call proc_Seq__Singleton__Length___int(); call proc_Seq__Build__Length___int(); call proc_Seq__Build__Index___int(); call proc_Seq__Append__Length___int(); call proc_Seq__Index__Singleton___int(); call proc_Seq__Append__Index___int(); call proc_Seq__Update__Length___int(); call proc_Seq__Index__Update___int(); call proc_Seq__Equal__Equiv___int(); call proc_Seq__Take__Length___int(); call proc_Seq__Take__Index___int(); call proc_Seq__Drop__Length___int(); call proc_Seq__Drop__Index___int(); call proc_Seq__Append__TakeDrop___int(); //- call proc_Seq__Append__TakeDrop__Restricted___int(); call proc_Seq__Update__CommuteTake1___int(); call proc_Seq__Update__CommuteTake2___int(); call proc_Seq__Update__CommuteDrop1___int(); call proc_Seq__Update__CommuteDrop2___int(); call proc_Seq__Build__CommuteDrop___int(); call proc_Seq__Take__Empty___int(); call proc_Seq__Drop__Empty___int(); gcStackOffset := 0x111000; call proc_lemma__2toX(); assert Aligned(esp); //- Prove that we can load arguments from the stack (b/c accesses are aligned) assert TV(esp) && TO(0) && TO(1) && TO(2) && TO(3) && TO(4) && TO(5); //- Prove that we can load arguments from the GC stack (b/c accesses are aligned) assert TO(0x44401) && TO(0x44402) && TO(0x44403); //- (gcStackOffset + {4,8,12}) / 4 //- Load pointer to array a into edx call r, mems := heapLoadStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, EDX, OMem(MReg(ESP, 0x111004)), EvalPtr(r, OMem(MReg(ESP, 0x111004)))); //- 0x111004 = gcStackOffset + 4 var a_base:int; a_base := edx; $ghost_a__abs := frameGet($stacksFrames, EvalPtr(r, OMem(MReg(ESP, gcStackOffset + 4)))); //- Load its length into eax call r, mems := loadArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, EAX, OMem(MReg(EDX, 4)), 0 - 1, $ghost_a__abs, r.regs[EDX]); //- Adjust to the "beginning" of the values we care about eax := eax - 1; call edi := Load(stk, esp + 8); //- grab ai eax := eax - edi; var aii:int := eax; assert aii == Arr_Length($ghost_a) - 1 - $ghost_ai; //- Convert aii into a memory pointer call arrayElementProperties(core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, aii, $ghost_a__abs, edx); //- Proves we're within bounds for the Lea calculation call eax := Lea(edx + 4 * eax + 8); var aii_ptr @ eax; //- Load pointer to array b into edx call r, mems := heapLoadStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, EDX, OMem(MReg(ESP, 0x111008)), EvalPtr(r, OMem(MReg(ESP, 0x111008)))); //- 0x111008 = gcStackOffset + 8 var b_base:int; b_base := edx; $ghost_b__abs := frameGet($stacksFrames, EvalPtr(r, OMem(MReg(ESP, gcStackOffset + 8)))); //- Load its length into ebx call r, mems := loadArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, EBX, OMem(MReg(EDX, 4)), 0 - 1, $ghost_b__abs, r.regs[EDX]); //- Adjust to the "beginning" of the values we care about ebx := ebx - 1; call edi := Load(stk, esp + 12); //- grab bi ebx := ebx - edi; var bii:int := ebx; assert bii == Arr_Length($ghost_b) - 1 - $ghost_bi; //- Convert aii into a memory pointer call arrayElementProperties(core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, bii, $ghost_b__abs, edx); //- Proves we're within bounds for the Lea calculation call ebx := Lea(edx + 4 * ebx + 8); var bii_ptr @ ebx; //- Load pointer to array s into edx call r, mems := heapLoadStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, EDX, OMem(MReg(ESP, 0x11100c)), EvalPtr(r, OMem(MReg(ESP, 0x11100c)))); //- 0x11100c == gcStackOffset + 12 var s_base:int; s_base := edx; $ghost_s__abs := frameGet($stacksFrames, EvalPtr(r, OMem(MReg(ESP, gcStackOffset + 12)))); //- Load its length into ecx call r, mems := loadArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, ECX, OMem(MReg(EDX, 4)), 0 - 1, $ghost_s__abs, r.regs[EDX]); //- Adjust to the "beginning" of the values we care about ecx := ecx - 1; call edi := Load(stk, esp + 16); //- grab si ecx := ecx - edi; var sii:int := ecx; assert sii == Arr_Length($ghost_s) - 1 - $ghost_si; //- Convert sii into a memory pointer call arrayElementProperties(core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, sii, $ghost_s__abs, edx); //- Proves we're within bounds for the Lea calculation call ecx := Lea(edx + 4 * ecx + 8); var sii_ptr @ ecx; //-///////////// Start computing ////////////////////////// //- First, "load" c_in into CF via a sneaky addition call edi := Load(stk, esp + 20); //- grab c_in assert edi == $ghost_c_in; call r := instr_Add(r, EDI, OConst(0xffffffff)); assert Cf(r.efl) == ($ghost_c_in == 1); //- Build the carries sequence $ghost_carries := fun_Seq__Build___int(fun_Seq__Empty___int(), $ghost_c_in); var carry:int; call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := arrayAdd4(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_a, $ghost_b, $ghost_s, OMem(MReg(EAX, 0)), OMem(MReg(EAX, (-4))), OMem(MReg(EAX, (-8))), OMem(MReg(EAX, (-12))), $ghost_a__abs, a_base, aii-0, aii-1, aii-2, aii-3, OMem(MReg(EBX, 0)), OMem(MReg(EBX, (-4))), OMem(MReg(EBX, (-8))), OMem(MReg(EBX, (-12))), $ghost_b__abs, b_base, bii-0, bii-1, bii-2, bii-3, OMem(MReg(ECX, 0)), OMem(MReg(ECX, (-4))), OMem(MReg(ECX, (-8))), OMem(MReg(ECX, (-12))), $ghost_s__abs, s_base, sii-0, sii-1, sii-2, sii-3, $ghost_si, 0, (-1), (-2), (-3), $ghost_carries, $ghost_c_in); assert (forall $ghost__1_i:int :: {fun_INTERNAL__array__elems__index($absMem[$ghost_a.arrAbs], (fun_FatNatAddIndex((Arr_Length($ghost_a)), $ghost_ai, $ghost__1_i)))} ((INTERNAL_le_boogie(0, $ghost__1_i)) && (INTERNAL_lt_boogie($ghost__1_i, 4))) ==> ((fun_Seq__Index___int($ghost_carries, INTERNAL_add_boogie($ghost__1_i, 1))) == ((if (INTERNAL_ge_boogie(INTERNAL_add_boogie(INTERNAL_add_boogie(fun_INTERNAL__array__elems__index($absMem[$ghost_a.arrAbs], (fun_FatNatAddIndex((Arr_Length($ghost_a)), $ghost_ai, $ghost__1_i))), fun_INTERNAL__array__elems__index($absMem[$ghost_b.arrAbs], (fun_FatNatAddIndex((Arr_Length($ghost_b)), $ghost_bi, $ghost__1_i)))), fun_Seq__Index___int($ghost_carries, $ghost__1_i)), 4294967296)) then (1) else (0))))); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := arrayAdd4(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_a, $ghost_b, $ghost_s, OMem(MReg(EAX, (-16))), OMem(MReg(EAX, (-20))), OMem(MReg(EAX, (-24))), OMem(MReg(EAX, (-28))), $ghost_a__abs, a_base, aii-4, aii-5, aii-6, aii-7, OMem(MReg(EBX, (-16))), OMem(MReg(EBX, (-20))), OMem(MReg(EBX, (-24))), OMem(MReg(EBX, (-28))), $ghost_b__abs, b_base, bii-4, bii-5, bii-6, bii-7, OMem(MReg(ECX, (-16))), OMem(MReg(ECX, (-20))), OMem(MReg(ECX, (-24))), OMem(MReg(ECX, (-28))), $ghost_s__abs, s_base, sii-4, sii-5, sii-6, sii-7, $ghost_si, (-4), (-5), (-6), (-7), $ghost_carries, carry); assert (forall $ghost__1_i:int :: {fun_INTERNAL__array__elems__index($absMem[$ghost_a.arrAbs], (fun_FatNatAddIndex((Arr_Length($ghost_a)), $ghost_ai, $ghost__1_i)))} ((INTERNAL_le_boogie(0, $ghost__1_i)) && (INTERNAL_lt_boogie($ghost__1_i, 8))) ==> ((fun_Seq__Index___int($ghost_carries, INTERNAL_add_boogie($ghost__1_i, 1))) == ((if (INTERNAL_ge_boogie(INTERNAL_add_boogie(INTERNAL_add_boogie(fun_INTERNAL__array__elems__index($absMem[$ghost_a.arrAbs], (fun_FatNatAddIndex((Arr_Length($ghost_a)), $ghost_ai, $ghost__1_i))), fun_INTERNAL__array__elems__index($absMem[$ghost_b.arrAbs], (fun_FatNatAddIndex((Arr_Length($ghost_b)), $ghost_bi, $ghost__1_i)))), fun_Seq__Index___int($ghost_carries, $ghost__1_i)), 4294967296)) then (1) else (0))))); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := arrayAdd4(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_a, $ghost_b, $ghost_s, OMem(MReg(EAX, (-32))), OMem(MReg(EAX, (-36))), OMem(MReg(EAX, (-40))), OMem(MReg(EAX, (-44))), $ghost_a__abs, a_base, aii-8, aii-9, aii-10, aii-11, OMem(MReg(EBX, (-32))), OMem(MReg(EBX, (-36))), OMem(MReg(EBX, (-40))), OMem(MReg(EBX, (-44))), $ghost_b__abs, b_base, bii-8, bii-9, bii-10, bii-11, OMem(MReg(ECX, (-32))), OMem(MReg(ECX, (-36))), OMem(MReg(ECX, (-40))), OMem(MReg(ECX, (-44))), $ghost_s__abs, s_base, sii-8, sii-9, sii-10, sii-11, $ghost_si, (-8), (-9), (-10), (-11), $ghost_carries, carry); assert (forall $ghost__1_i:int :: {fun_INTERNAL__array__elems__index($absMem[$ghost_a.arrAbs], (fun_FatNatAddIndex((Arr_Length($ghost_a)), $ghost_ai, $ghost__1_i)))} ((INTERNAL_le_boogie(0, $ghost__1_i)) && (INTERNAL_lt_boogie($ghost__1_i, 12))) ==> ((fun_Seq__Index___int($ghost_carries, INTERNAL_add_boogie($ghost__1_i, 1))) == ((if (INTERNAL_ge_boogie(INTERNAL_add_boogie(INTERNAL_add_boogie(fun_INTERNAL__array__elems__index($absMem[$ghost_a.arrAbs], (fun_FatNatAddIndex((Arr_Length($ghost_a)), $ghost_ai, $ghost__1_i))), fun_INTERNAL__array__elems__index($absMem[$ghost_b.arrAbs], (fun_FatNatAddIndex((Arr_Length($ghost_b)), $ghost_bi, $ghost__1_i)))), fun_Seq__Index___int($ghost_carries, $ghost__1_i)), 4294967296)) then (1) else (0))))); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := arrayAdd4(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_a, $ghost_b, $ghost_s, OMem(MReg(EAX, (-48))), OMem(MReg(EAX, (-52))), OMem(MReg(EAX, (-56))), OMem(MReg(EAX, (-60))), $ghost_a__abs, a_base, aii-12, aii-13, aii-14, aii-15, OMem(MReg(EBX, (-48))), OMem(MReg(EBX, (-52))), OMem(MReg(EBX, (-56))), OMem(MReg(EBX, (-60))), $ghost_b__abs, b_base, bii-12, bii-13, bii-14, bii-15, OMem(MReg(ECX, (-48))), OMem(MReg(ECX, (-52))), OMem(MReg(ECX, (-56))), OMem(MReg(ECX, (-60))), $ghost_s__abs, s_base, sii-12, sii-13, sii-14, sii-15, $ghost_si, (-12), (-13), (-14), (-15), $ghost_carries, carry); // assert (forall $ghost__1_i:int :: {fun_INTERNAL__array__elems__index($absMem[$ghost_a.arrAbs], (fun_FatNatAddIndex((Arr_Length($ghost_a)), $ghost_ai, $ghost__1_i)))} ((INTERNAL_le_boogie(0, $ghost__1_i)) && (INTERNAL_lt_boogie($ghost__1_i, 16))) ==> ((fun_Seq__Index___int($ghost_carries, INTERNAL_add_boogie($ghost__1_i, 1))) == ((if (INTERNAL_ge_boogie(INTERNAL_add_boogie(INTERNAL_add_boogie(fun_INTERNAL__array__elems__index($absMem[$ghost_a.arrAbs], (fun_FatNatAddIndex((Arr_Length($ghost_a)), $ghost_ai, $ghost__1_i))), fun_INTERNAL__array__elems__index($absMem[$ghost_b.arrAbs], (fun_FatNatAddIndex((Arr_Length($ghost_b)), $ghost_bi, $ghost__1_i)))), fun_Seq__Index___int($ghost_carries, $ghost__1_i)), 4294967296)) then (1) else (0))))); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, 0)), $ghost_a__abs, a_base, aii-0, // OMem(MReg(EBX, 0)), $ghost_b__abs, b_base, bii-0, // OMem(MReg(ECX, 0)), $ghost_s__abs, s_base, sii-0, // $ghost_si, 0, $ghost_carries, $ghost_c_in); // // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-4))), $ghost_a__abs, a_base, aii-1, // OMem(MReg(EBX, (-4))), $ghost_b__abs, b_base, bii-1, // OMem(MReg(ECX, (-4))), $ghost_s__abs, s_base, sii-1, // $ghost_si, (-1), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-8))), $ghost_a__abs, a_base, aii-2, // OMem(MReg(EBX, (-8))), $ghost_b__abs, b_base, bii-2, // OMem(MReg(ECX, (-8))), $ghost_s__abs, s_base, sii-2, // $ghost_si, (-2), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-12))), $ghost_a__abs, a_base, aii-3, // OMem(MReg(EBX, (-12))), $ghost_b__abs, b_base, bii-3, // OMem(MReg(ECX, (-12))), $ghost_s__abs, s_base, sii-3, // $ghost_si, (-3), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-16))), $ghost_a__abs, a_base, aii-4, // OMem(MReg(EBX, (-16))), $ghost_b__abs, b_base, bii-4, // OMem(MReg(ECX, (-16))), $ghost_s__abs, s_base, sii-4, // $ghost_si, (-4), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-20))), $ghost_a__abs, a_base, aii-5, // OMem(MReg(EBX, (-20))), $ghost_b__abs, b_base, bii-5, // OMem(MReg(ECX, (-20))), $ghost_s__abs, s_base, sii-5, // $ghost_si, (-5), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-24))), $ghost_a__abs, a_base, aii-6, // OMem(MReg(EBX, (-24))), $ghost_b__abs, b_base, bii-6, // OMem(MReg(ECX, (-24))), $ghost_s__abs, s_base, sii-6, // $ghost_si, (-6), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-28))), $ghost_a__abs, a_base, aii-7, // OMem(MReg(EBX, (-28))), $ghost_b__abs, b_base, bii-7, // OMem(MReg(ECX, (-28))), $ghost_s__abs, s_base, sii-7, // $ghost_si, (-7), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-32))), $ghost_a__abs, a_base, aii-8, // OMem(MReg(EBX, (-32))), $ghost_b__abs, b_base, bii-8, // OMem(MReg(ECX, (-32))), $ghost_s__abs, s_base, sii-8, // $ghost_si, (-8), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-36))), $ghost_a__abs, a_base, aii-9, // OMem(MReg(EBX, (-36))), $ghost_b__abs, b_base, bii-9, // OMem(MReg(ECX, (-36))), $ghost_s__abs, s_base, sii-9, // $ghost_si, (-9), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-40))), $ghost_a__abs, a_base, aii-10, // OMem(MReg(EBX, (-40))), $ghost_b__abs, b_base, bii-10, // OMem(MReg(ECX, (-40))), $ghost_s__abs, s_base, sii-10, // $ghost_si, (-10), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-44))), $ghost_a__abs, a_base, aii-11, // OMem(MReg(EBX, (-44))), $ghost_b__abs, b_base, bii-11, // OMem(MReg(ECX, (-44))), $ghost_s__abs, s_base, sii-11, // $ghost_si, (-11), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-48))), $ghost_a__abs, a_base, aii-12, // OMem(MReg(EBX, (-48))), $ghost_b__abs, b_base, bii-12, // OMem(MReg(ECX, (-48))), $ghost_s__abs, s_base, sii-12, // $ghost_si, (-12), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-52))), $ghost_a__abs, a_base, aii-13, // OMem(MReg(EBX, (-52))), $ghost_b__abs, b_base, bii-13, // OMem(MReg(ECX, (-52))), $ghost_s__abs, s_base, sii-13, // $ghost_si, (-13), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-56))), $ghost_a__abs, a_base, aii-14, // OMem(MReg(EBX, (-56))), $ghost_b__abs, b_base, bii-14, // OMem(MReg(ECX, (-56))), $ghost_s__abs, s_base, sii-14, // $ghost_si, (-14), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-60))), $ghost_a__abs, a_base, aii-15, // OMem(MReg(EBX, (-60))), $ghost_b__abs, b_base, bii-15, // OMem(MReg(ECX, (-60))), $ghost_s__abs, s_base, sii-15, // $ghost_si, (-15), $ghost_carries, carry); //- Extract the final carry bit from EFL eax := 0; call r := instr_GetCf(r, EAX); assert Aligned(esp); assert Aligned(esp + 4); call Store(inout stk, esp + 4, eax); $ghost_c_out := carry; assert $ghost_a.arrAbs != $ghost_s.arrAbs; Return; } //implementation Proc_Add32__unrolled__32(my r_old:regs, const my core_state:core_state, linear stk_old:mem, linear statics_old:mem, linear io_old:IOState, linear mems_old:mems, $commonVars_old:commonVars, $gcVars_old:gcVars, $toAbs_old:[int]int, $absMem_old:[int][int]int, $stacksFrames_old:[int]Frames, objLayouts_old:[int]ObjLayout, heap_old:Heap, $ghost_a:ArrayOfInt, $ghost_ai:int, $ghost_b:ArrayOfInt, $ghost_bi:int, $ghost_s:ArrayOfInt, $ghost_si:int, $ghost_c_in:int) returns(my r:regs, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars, $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap, $ghost_c_out:int, $ghost_carries:Seq___int) //{ // var $ghost_a__abs:int; // var $ghost_b__abs:int; // var $ghost_s__abs:int; // var gcStackOffset:int; // // // Boilerplate variable propagation // r := r_old; // stk := stk_old; // statics := statics_old; // io := io_old; // mems := mems_old; // $commonVars := $commonVars_old; // $gcVars := $gcVars_old; // $toAbs := $toAbs_old; // $absMem := $absMem_old; // $stacksFrames := $stacksFrames_old; // objLayouts := objLayouts_old; // heap := heap_old; // // // Teach Beat about Dafny sequence operations // call proc_Seq__Empty__ToZero___int(); // call proc_Seq__Empty__FromZero___int(); // call proc_Seq__Singleton__Length___int(); // call proc_Seq__Build__Length___int(); // call proc_Seq__Build__Index___int(); // call proc_Seq__Append__Length___int(); // call proc_Seq__Index__Singleton___int(); // call proc_Seq__Append__Index___int(); // call proc_Seq__Update__Length___int(); // call proc_Seq__Index__Update___int(); // call proc_Seq__Equal__Equiv___int(); // call proc_Seq__Take__Length___int(); // call proc_Seq__Take__Index___int(); // call proc_Seq__Drop__Length___int(); // call proc_Seq__Drop__Index___int(); // call proc_Seq__Append__TakeDrop___int(); // // call proc_Seq__Append__TakeDrop__Restricted___int(); // call proc_Seq__Update__CommuteTake1___int(); // call proc_Seq__Update__CommuteTake2___int(); // call proc_Seq__Update__CommuteDrop1___int(); // call proc_Seq__Update__CommuteDrop2___int(); // call proc_Seq__Build__CommuteDrop___int(); // call proc_Seq__Take__Empty___int(); // call proc_Seq__Drop__Empty___int(); // // assert false; // // gcStackOffset := 0x111000; // // call proc_lemma__2toX(); // // assert Aligned(esp); // // Prove that we can load arguments from the stack (b/c accesses are aligned) // assert TV(esp) && TO(0) && TO(1) && TO(2) && TO(3) && TO(4) && TO(5); // // // Prove that we can load arguments from the GC stack (b/c accesses are aligned) // assert TO(0x44401) && TO(0x44402) && TO(0x44403); // (gcStackOffset + {4,8,12}) / 4 // // // Load pointer to array a into edx // call r, mems := heapLoadStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, EDX, OMem(MReg(ESP, 0x111004)), EvalPtr(r, OMem(MReg(ESP, 0x111004)))); // 0x111004 = gcStackOffset + 4 // var a_base:int; // a_base := edx; // $ghost_a__abs := frameGet($stacksFrames, EvalPtr(r, OMem(MReg(ESP, gcStackOffset + 4)))); // // // Load its length into eax // call r, mems := loadArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, EAX, OMem(MReg(EDX, 4)), 0 - 1, $ghost_a__abs, r.regs[EDX]); // // // Adjust to the "beginning" of the values we care about // eax := eax - 1; // call edi := Load(stk, esp + 8); // grab ai // eax := eax - edi; // var aii:int := eax; // assert aii == Arr_Length($ghost_a) - 1 - $ghost_ai; // // // Convert aii into a memory pointer // call arrayElementProperties(core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, aii, $ghost_a__abs, edx); // Proves we're within bounds for the Lea calculation // call eax := Lea(edx + 4 * eax + 8); // var aii_ptr @ eax; // // // Load pointer to array b into edx // call r, mems := heapLoadStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, EDX, OMem(MReg(ESP, 0x111008)), EvalPtr(r, OMem(MReg(ESP, 0x111008)))); // 0x111008 = gcStackOffset + 8 // var b_base:int; // b_base := edx; // $ghost_b__abs := frameGet($stacksFrames, EvalPtr(r, OMem(MReg(ESP, gcStackOffset + 8)))); // // // Load its length into ebx // call r, mems := loadArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, EBX, OMem(MReg(EDX, 4)), 0 - 1, $ghost_b__abs, r.regs[EDX]); // // // Adjust to the "beginning" of the values we care about // ebx := ebx - 1; // call edi := Load(stk, esp + 12); // grab bi // ebx := ebx - edi; // var bii:int := ebx; // assert bii == Arr_Length($ghost_b) - 1 - $ghost_bi; // // // Convert aii into a memory pointer // call arrayElementProperties(core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, bii, $ghost_b__abs, edx); // Proves we're within bounds for the Lea calculation // call ebx := Lea(edx + 4 * ebx + 8); // var bii_ptr @ ebx; // // // Load pointer to array s into edx // call r, mems := heapLoadStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, EDX, OMem(MReg(ESP, 0x11100c)), EvalPtr(r, OMem(MReg(ESP, 0x11100c)))); // 0x11100c == gcStackOffset + 12 // var s_base:int; // s_base := edx; // $ghost_s__abs := frameGet($stacksFrames, EvalPtr(r, OMem(MReg(ESP, gcStackOffset + 12)))); // // // Load its length into ecx // call r, mems := loadArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, ECX, OMem(MReg(EDX, 4)), 0 - 1, $ghost_s__abs, r.regs[EDX]); // // // Adjust to the "beginning" of the values we care about // ecx := ecx - 1; // call edi := Load(stk, esp + 16); // grab si // ecx := ecx - edi; // var sii:int := ecx; // assert sii == Arr_Length($ghost_s) - 1 - $ghost_si; // // // Convert sii into a memory pointer // call arrayElementProperties(core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, sii, $ghost_s__abs, edx); // Proves we're within bounds for the Lea calculation // call ecx := Lea(edx + 4 * ecx + 8); // var sii_ptr @ ecx; // // /////////////// Start computing ////////////////////////// // // // First, "load" c_in into CF via a sneaky addition // call edi := Load(stk, esp + 20); // grab c_in // assert edi == $ghost_c_in; // call r := instr_Add(r, EDI, OConst(0xffffffff)); // assert Cf(r.efl) == ($ghost_c_in == 1); // // // Build the carries sequence // $ghost_carries := fun_Seq__Build___int(fun_Seq__Empty___int(), $ghost_c_in); // // var carry:int; // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, 0)), $ghost_a__abs, a_base, aii-0, // OMem(MReg(EBX, 0)), $ghost_b__abs, b_base, bii-0, // OMem(MReg(ECX, 0)), $ghost_s__abs, s_base, sii-0, // $ghost_si, 0, $ghost_carries, $ghost_c_in); // // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-4))), $ghost_a__abs, a_base, aii-1, // OMem(MReg(EBX, (-4))), $ghost_b__abs, b_base, bii-1, // OMem(MReg(ECX, (-4))), $ghost_s__abs, s_base, sii-1, // $ghost_si, (-1), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-8))), $ghost_a__abs, a_base, aii-2, // OMem(MReg(EBX, (-8))), $ghost_b__abs, b_base, bii-2, // OMem(MReg(ECX, (-8))), $ghost_s__abs, s_base, sii-2, // $ghost_si, (-2), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-12))), $ghost_a__abs, a_base, aii-3, // OMem(MReg(EBX, (-12))), $ghost_b__abs, b_base, bii-3, // OMem(MReg(ECX, (-12))), $ghost_s__abs, s_base, sii-3, // $ghost_si, (-3), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-16))), $ghost_a__abs, a_base, aii-4, // OMem(MReg(EBX, (-16))), $ghost_b__abs, b_base, bii-4, // OMem(MReg(ECX, (-16))), $ghost_s__abs, s_base, sii-4, // $ghost_si, (-4), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-20))), $ghost_a__abs, a_base, aii-5, // OMem(MReg(EBX, (-20))), $ghost_b__abs, b_base, bii-5, // OMem(MReg(ECX, (-20))), $ghost_s__abs, s_base, sii-5, // $ghost_si, (-5), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-24))), $ghost_a__abs, a_base, aii-6, // OMem(MReg(EBX, (-24))), $ghost_b__abs, b_base, bii-6, // OMem(MReg(ECX, (-24))), $ghost_s__abs, s_base, sii-6, // $ghost_si, (-6), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-28))), $ghost_a__abs, a_base, aii-7, // OMem(MReg(EBX, (-28))), $ghost_b__abs, b_base, bii-7, // OMem(MReg(ECX, (-28))), $ghost_s__abs, s_base, sii-7, // $ghost_si, (-7), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-32))), $ghost_a__abs, a_base, aii-8, // OMem(MReg(EBX, (-32))), $ghost_b__abs, b_base, bii-8, // OMem(MReg(ECX, (-32))), $ghost_s__abs, s_base, sii-8, // $ghost_si, (-8), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-36))), $ghost_a__abs, a_base, aii-9, // OMem(MReg(EBX, (-36))), $ghost_b__abs, b_base, bii-9, // OMem(MReg(ECX, (-36))), $ghost_s__abs, s_base, sii-9, // $ghost_si, (-9), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-40))), $ghost_a__abs, a_base, aii-10, // OMem(MReg(EBX, (-40))), $ghost_b__abs, b_base, bii-10, // OMem(MReg(ECX, (-40))), $ghost_s__abs, s_base, sii-10, // $ghost_si, (-10), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-44))), $ghost_a__abs, a_base, aii-11, // OMem(MReg(EBX, (-44))), $ghost_b__abs, b_base, bii-11, // OMem(MReg(ECX, (-44))), $ghost_s__abs, s_base, sii-11, // $ghost_si, (-11), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-48))), $ghost_a__abs, a_base, aii-12, // OMem(MReg(EBX, (-48))), $ghost_b__abs, b_base, bii-12, // OMem(MReg(ECX, (-48))), $ghost_s__abs, s_base, sii-12, // $ghost_si, (-12), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-52))), $ghost_a__abs, a_base, aii-13, // OMem(MReg(EBX, (-52))), $ghost_b__abs, b_base, bii-13, // OMem(MReg(ECX, (-52))), $ghost_s__abs, s_base, sii-13, // $ghost_si, (-13), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-56))), $ghost_a__abs, a_base, aii-14, // OMem(MReg(EBX, (-56))), $ghost_b__abs, b_base, bii-14, // OMem(MReg(ECX, (-56))), $ghost_s__abs, s_base, sii-14, // $ghost_si, (-14), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-60))), $ghost_a__abs, a_base, aii-15, // OMem(MReg(EBX, (-60))), $ghost_b__abs, b_base, bii-15, // OMem(MReg(ECX, (-60))), $ghost_s__abs, s_base, sii-15, // $ghost_si, (-15), $ghost_carries, carry); // // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-64))), $ghost_a__abs, a_base, aii-16, // OMem(MReg(EBX, (-64))), $ghost_b__abs, b_base, bii-16, // OMem(MReg(ECX, (-64))), $ghost_s__abs, s_base, sii-16, // $ghost_si, (-16), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-68))), $ghost_a__abs, a_base, aii-17, // OMem(MReg(EBX, (-68))), $ghost_b__abs, b_base, bii-17, // OMem(MReg(ECX, (-68))), $ghost_s__abs, s_base, sii-17, // $ghost_si, (-17), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-72))), $ghost_a__abs, a_base, aii-18, // OMem(MReg(EBX, (-72))), $ghost_b__abs, b_base, bii-18, // OMem(MReg(ECX, (-72))), $ghost_s__abs, s_base, sii-18, // $ghost_si, (-18), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-76))), $ghost_a__abs, a_base, aii-19, // OMem(MReg(EBX, (-76))), $ghost_b__abs, b_base, bii-19, // OMem(MReg(ECX, (-76))), $ghost_s__abs, s_base, sii-19, // $ghost_si, (-19), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-80))), $ghost_a__abs, a_base, aii-20, // OMem(MReg(EBX, (-80))), $ghost_b__abs, b_base, bii-20, // OMem(MReg(ECX, (-80))), $ghost_s__abs, s_base, sii-20, // $ghost_si, (-20), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-84))), $ghost_a__abs, a_base, aii-21, // OMem(MReg(EBX, (-84))), $ghost_b__abs, b_base, bii-21, // OMem(MReg(ECX, (-84))), $ghost_s__abs, s_base, sii-21, // $ghost_si, (-21), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-88))), $ghost_a__abs, a_base, aii-22, // OMem(MReg(EBX, (-88))), $ghost_b__abs, b_base, bii-22, // OMem(MReg(ECX, (-88))), $ghost_s__abs, s_base, sii-22, // $ghost_si, (-22), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-92))), $ghost_a__abs, a_base, aii-23, // OMem(MReg(EBX, (-92))), $ghost_b__abs, b_base, bii-23, // OMem(MReg(ECX, (-92))), $ghost_s__abs, s_base, sii-23, // $ghost_si, (-23), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-96))), $ghost_a__abs, a_base, aii-24, // OMem(MReg(EBX, (-96))), $ghost_b__abs, b_base, bii-24, // OMem(MReg(ECX, (-96))), $ghost_s__abs, s_base, sii-24, // $ghost_si, (-24), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-100))), $ghost_a__abs, a_base, aii-25, // OMem(MReg(EBX, (-100))), $ghost_b__abs, b_base, bii-25, // OMem(MReg(ECX, (-100))), $ghost_s__abs, s_base, sii-25, // $ghost_si, (-25), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-104))), $ghost_a__abs, a_base, aii-26, // OMem(MReg(EBX, (-104))), $ghost_b__abs, b_base, bii-26, // OMem(MReg(ECX, (-104))), $ghost_s__abs, s_base, sii-26, // $ghost_si, (-26), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-108))), $ghost_a__abs, a_base, aii-27, // OMem(MReg(EBX, (-108))), $ghost_b__abs, b_base, bii-27, // OMem(MReg(ECX, (-108))), $ghost_s__abs, s_base, sii-27, // $ghost_si, (-27), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-112))), $ghost_a__abs, a_base, aii-28, // OMem(MReg(EBX, (-112))), $ghost_b__abs, b_base, bii-28, // OMem(MReg(ECX, (-112))), $ghost_s__abs, s_base, sii-28, // $ghost_si, (-28), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-116))), $ghost_a__abs, a_base, aii-29, // OMem(MReg(EBX, (-116))), $ghost_b__abs, b_base, bii-29, // OMem(MReg(ECX, (-116))), $ghost_s__abs, s_base, sii-29, // $ghost_si, (-29), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-120))), $ghost_a__abs, a_base, aii-30, // OMem(MReg(EBX, (-120))), $ghost_b__abs, b_base, bii-30, // OMem(MReg(ECX, (-120))), $ghost_s__abs, s_base, sii-30, // $ghost_si, (-30), $ghost_carries, carry); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-124))), $ghost_a__abs, a_base, aii-31, // OMem(MReg(EBX, (-124))), $ghost_b__abs, b_base, bii-31, // OMem(MReg(ECX, (-124))), $ghost_s__abs, s_base, sii-31, // $ghost_si, (-31), $ghost_carries, carry); // // // // // Extract the final carry bit from EFL // eax := 0; // call r := instr_GetCf(r, EAX); // assert Aligned(esp); // assert Aligned(esp + 4); // call Store(inout stk, esp + 4, eax); // $ghost_c_out := carry; // // assert $ghost_a.arrAbs != $ghost_s.arrAbs; // // Return; //} } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Main/dafny_FatNatX86big_i.imp.beat ================================================ //-private-import BaseSpec; //-private-import MemorySpec; //-private-import IoTypesSpec; //-private-import MachineStateSpec; //-private-import AssemblySpec; //-private-import InterruptsSpec; //-private-import IoSpec; //-private-import Overflow; //-private-import Core; //-private-import LogicalAddressing; //-private-import Util; //-private-import Stacks; //-private-import Partition; //-private-import Instructions; //-private-import Separation; //-private-import IntLemmasGc; //-private-import SimpleGcMemory; //-private-import SimpleCommon; //-private-import SimpleCollector; //-private-import IntLemmasMain; //-private-import IntLemmasBase; //-private-import IoMain; //-private-basmonly-import Trusted; //-private-basmonly-import Checked; //-private-import Heap; //-private-import Seq; //-private-import dafny_DafnyPrelude; //-private-import DafnyAssembly; //-private-import dafny_base_s; //-private-import dafny_power2_s; //-private-import dafny_bytes_and_words_s; //-private-import dafny_be_sequences_s; //-private-import dafny_integer_sequences_s; //-private-import dafny_seqs_simple_i; //-private-import dafny_power_s; //-private-import dafny_mul_nonlinear_i; //-private-import dafny_mul_i; //-private-import dafny_power_i; //-private-import dafny_div_def_i; //-private-import dafny_div_boogie_i; //-private-import dafny_div_nonlinear_i; //-private-import dafny_div_i; //-private-import dafny_repeat_digit_i; //-private-import dafny_assembly_s; //-private-import dafny_power2_i; //-private-import dafny_seqs_and_ints_i; //-private-import dafny_seqs_common_i; //-private-import dafny_Word32_i; //-private-import dafny_relational_s; //-private-import dafny_assembly_i; //-private-import dafny_arrays_i; //-private-import dafny_seqs_transforms_i; //-private-import dafny_seqs_reverse_i; //-private-import dafny_integer_sequences_i; //-private-import dafny_integer_sequences_premium_i; //-private-import dafny_assembly_premium_i; //-private-import dafny_BigNatX86Shim_i; //-private-import dafny_seqs_canonical_i; //-private-import dafny_CanonicalArrays_i; //-private-import dafny_FatNatCommon_i; //- //- //- //- //- module implementation dafny_FatNatX86big_i { procedure arrayAdd(my r_old:regs, const my core_state:core_state, linear stk_old:mem, linear statics_old:mem, linear io_old:IOState, linear mems_old:mems, $commonVars_old:commonVars, $gcVars_old:gcVars, $toAbs_old:[int]int, $absMem_old:[int][int]int, $stacksFrames_old:[int]Frames, objLayouts_old:[int]ObjLayout, heap_old:Heap, $ghost_a:ArrayOfInt, $ghost_b:ArrayOfInt, $ghost_s:ArrayOfInt, a_opn:opn_mem, $ghost_a__abs:int, a_base:int, a_offset:int, b_opn:opn_mem, $ghost_b__abs:int, b_base:int, b_offset:int, s_opn:opn_mem, $ghost_s__abs:int, s_base:int, s_offset:int, $ghost_si:int, index_offset:int, old_carries:Seq___int, old_carry:int) returns(my r:regs, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars, $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap, new_carry:int, new_carries:Seq___int) requires MemInv(me,init,stk_old,statics_old,core_state,ptMem,mems_old); requires NucleusInv(objLayouts_old,$S,$toAbs_old,$absMem_old,$commonVars_old,$gcVars_old,me,init,stk_old,statics_old,core_state,ptMem,mems_old,$stacksFrames_old,io_old); requires HeapInv($absMem_old, objLayouts_old, heap_old); requires $ghost_a != (ArrayOfInt(0 - 1, NO_ABS)); requires fun_IsWordSeq(fun_Seq__FromArray($absMem_old, $ghost_a)); requires $ghost_b != (ArrayOfInt(0 - 1, NO_ABS)); requires fun_IsWordSeq(fun_Seq__FromArray($absMem_old, $ghost_b)); requires $ghost_s != (ArrayOfInt(0 - 1, NO_ABS)); requires $ghost_b != $ghost_s; requires $ghost_a != $ghost_s; requires $ghost_a__abs != $ghost_s__abs; requires $ghost_b__abs != $ghost_s__abs; requires s_offset == Arr_Length($ghost_s) - 1 - $ghost_si + index_offset; requires old_carry == if (Cf(r_old.efl)) then 1 else 0; requires $ghost_a.arrAbs == $ghost_a__abs; requires HeapAbsData(heap_old, $ghost_a__abs) is Abs_ArrayOfInt; requires 0 <= a_offset && a_offset < HeapAbsData(heap_old, $ghost_a__abs).arr.arrCount; requires HeapValue(objLayouts_old, true, $toAbs_old, a_base, $ghost_a__abs); requires EvalPtrOk(a_opn); requires EvalPtr(r_old, a_opn) == a_base + 4 * (2 + a_offset); requires a_opn._ptr is MReg && a_opn._ptr._mreg == EAX; requires $ghost_b.arrAbs == $ghost_b__abs; requires HeapAbsData(heap_old, $ghost_b__abs) is Abs_ArrayOfInt; requires 0 <= b_offset && b_offset < HeapAbsData(heap_old, $ghost_b__abs).arr.arrCount; requires HeapValue(objLayouts_old, true, $toAbs_old, b_base, $ghost_b__abs); requires EvalPtrOk(b_opn); requires EvalPtr(r_old, b_opn) == b_base + 4 * (2 + b_offset); requires b_opn._ptr is MReg && b_opn._ptr._mreg == EBX; requires $ghost_s.arrAbs == $ghost_s__abs; requires HeapAbsData(heap_old, $ghost_s__abs) is Abs_ArrayOfInt; requires 0 <= s_offset && s_offset < HeapAbsData(heap_old, $ghost_s__abs).arr.arrCount; requires HeapValue(objLayouts_old, true, $toAbs_old, s_base, $ghost_s__abs); requires EvalPtrOk(s_opn); requires EvalPtr(r_old, s_opn) == s_base + 4 * (2 + s_offset); requires s_opn._ptr is MReg && s_opn._ptr._mreg == ECX; modifies $Time; ensures stk == stk_old; ensures $stacksFrames == $stacksFrames_old; ensures (forall i:int::{$stacksFrames[$S].Abss[i]} i != EvalPtr(r_old, s_opn) ==> $stacksFrames[$S].Abss[i] == $stacksFrames_old[$S].Abss[i]); ensures MemInv(me,init,stk,statics,core_state,ptMem,mems); ensures NucleusInv(objLayouts,$S,$toAbs,$absMem,$commonVars,$gcVars,me,init,stk,statics,core_state,ptMem,mems,$stacksFrames,io); ensures HeapInv($absMem, objLayouts, heap); ensures AbsExtend($toAbs, $toAbs_old, objLayouts, objLayouts_old); ensures (forall i:int::{$absMem[i]}{heap.absData[i]} heap_old.absData[i] is AbsNone || (heap.absData[i] == heap_old.absData[i] && ($absMem[i] == $absMem_old[i] || i == (($ghost_s).arrAbs)))); ensures io._inCtr == io_old._inCtr && io._outCtr == io_old._outCtr; //- Only havocs edi, ebp ensures r.regs[EAX] == r_old.regs[EAX]; ensures r.regs[EBX] == r_old.regs[EBX]; ensures r.regs[ECX] == r_old.regs[ECX]; ensures r.regs[EDX] == r_old.regs[EDX]; ensures r.regs[ESI] == r_old.regs[ESI]; ensures r.regs[ESP] == r_old.regs[ESP]; ensures HeapValue(objLayouts, true, $toAbs, a_base, $ghost_a__abs); ensures HeapValue(objLayouts, true, $toAbs, b_base, $ghost_b__abs); ensures HeapValue(objLayouts, true, $toAbs, s_base, $ghost_s__abs); ensures new_carry == if (Cf(r.efl)) then 1 else 0; ensures new_carry == if ((fun_INTERNAL__array__elems__index($absMem[$ghost_a__abs], a_offset) + fun_INTERNAL__array__elems__index($absMem[$ghost_b__abs], b_offset) + old_carry) >= WORD_HI) then 1 else 0; ensures fun_INTERNAL__array__elems__index($absMem[$ghost_s__abs], s_offset) == fun_mod0x100000000(fun_INTERNAL__array__elems__index($absMem[$ghost_a__abs], a_offset) + fun_INTERNAL__array__elems__index($absMem[$ghost_b__abs], b_offset) + old_carry); //- Arrays A and B are unmodified ensures (forall j:int :: { fun_INTERNAL__array__elems__index($absMem[$ghost_a.arrAbs], j) } (((INTERNAL_le_boogie(0, j)) && (INTERNAL_lt_boogie(j, (Arr_Length($ghost_a)))))) ==> ((fun_INTERNAL__array__elems__index($absMem[$ghost_a.arrAbs], j)) == (old(fun_INTERNAL__array__elems__index($absMem_old[$ghost_a.arrAbs], j))))); ensures (forall j:int :: { fun_INTERNAL__array__elems__index($absMem[$ghost_b.arrAbs], j) } (((INTERNAL_le_boogie(0, j)) && (INTERNAL_lt_boogie(j, (Arr_Length($ghost_b)))))) ==> ((fun_INTERNAL__array__elems__index($absMem[$ghost_b.arrAbs], j)) == (old(fun_INTERNAL__array__elems__index($absMem_old[$ghost_b.arrAbs], j))))); //- Array S is unmodified except for the one entry we touch ensures (forall j:int :: { fun_INTERNAL__array__elems__index($absMem[$ghost_s.arrAbs], j) } (((INTERNAL_le_boogie(0, j)) && (INTERNAL_lt_boogie(j, (Arr_Length($ghost_s))))) && j != s_offset) ==> ((fun_INTERNAL__array__elems__index($absMem[$ghost_s.arrAbs], j)) == (old(fun_INTERNAL__array__elems__index($absMem_old[$ghost_s.arrAbs], j))))); ensures fun_Seq__Length___int(new_carries) == fun_Seq__Length___int(old_carries) + 1; ensures (forall i:int :: 0 <= i && i < fun_Seq__Length___int(old_carries) ==> fun_Seq__Index___int(new_carries, i) == fun_Seq__Index___int(old_carries, i)); ensures fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - 1) == new_carry; { //- Boilerplate variable propagation r := r_old; stk := stk_old; statics := statics_old; io := io_old; mems := mems_old; $commonVars := $commonVars_old; $gcVars := $gcVars_old; $toAbs := $toAbs_old; $absMem := $absMem_old; $stacksFrames := $stacksFrames_old; objLayouts := objLayouts_old; heap := heap_old; //- Teach Beat about Dafny sequence operations call proc_Seq__Empty__ToZero___int(); call proc_Seq__Empty__FromZero___int(); call proc_Seq__Singleton__Length___int(); call proc_Seq__Build__Length___int(); call proc_Seq__Build__Index___int(); call proc_Seq__Append__Length___int(); call proc_Seq__Index__Singleton___int(); call proc_Seq__Append__Index___int(); call proc_Seq__Update__Length___int(); call proc_Seq__Index__Update___int(); call proc_Seq__Equal__Equiv___int(); call proc_Seq__Take__Length___int(); call proc_Seq__Take__Index___int(); call proc_Seq__Drop__Length___int(); call proc_Seq__Drop__Index___int(); call proc_Seq__Append__TakeDrop___int(); call proc_Seq__Update__CommuteTake1___int(); call proc_Seq__Update__CommuteTake2___int(); call proc_Seq__Update__CommuteDrop1___int(); call proc_Seq__Update__CommuteDrop2___int(); call proc_Seq__Build__CommuteDrop___int(); call proc_Seq__Take__Empty___int(); call proc_Seq__Drop__Empty___int(); call proc_lemma__2toX(); call r, mems := loadArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, EDI, a_opn, a_offset, $ghost_a__abs, a_base); //- edi <- a[aii+1] call r, mems := loadArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, EBP, b_opn, b_offset, $ghost_b__abs, b_base); //- ebp <- b[bii+1] var old_edi:int := edi; var next_efl:int := r.efl; call edi := AddCarry(edi, ebp); //- edi == a[aii+index_offset] + b[bii+index_offset] + carry call reveal_wrap32(old_edi + ebp + old_carry); new_carry := if (old_edi + ebp + old_carry >= WORD_HI) then 1 else 0; new_carries := fun_Seq__Append___int(old_carries, fun_Seq__Build___int(fun_Seq__Empty___int(), new_carry)); //- Write the result in edi back to s[sii+index_offset] call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, s_opn, OReg(EDI), s_offset, edi, $ghost_s__abs, s_base); call reveal_wrap32(fun_INTERNAL__array__elems__index($absMem[$ghost_a__abs], a_offset) + fun_INTERNAL__array__elems__index($absMem[$ghost_b__abs], b_offset) + old_carry); call reveal_WORD_HI(); } procedure arrayAdd4(my r_old:regs, const my core_state:core_state, linear stk_old:mem, linear statics_old:mem, linear io_old:IOState, linear mems_old:mems, $commonVars_old:commonVars, $gcVars_old:gcVars, $toAbs_old:[int]int, $absMem_old:[int][int]int, $stacksFrames_old:[int]Frames, objLayouts_old:[int]ObjLayout, heap_old:Heap, $ghost_a:ArrayOfInt, $ghost_b:ArrayOfInt, $ghost_s:ArrayOfInt, a_opn1:opn_mem, a_opn2:opn_mem, a_opn3:opn_mem, a_opn4:opn_mem,$ghost_a__abs:int, a_base:int, a_offset1:int, a_offset2:int, a_offset3:int, a_offset4:int, b_opn1:opn_mem, b_opn2:opn_mem, b_opn3:opn_mem, b_opn4:opn_mem, $ghost_b__abs:int, b_base:int, b_offset1:int, b_offset2:int, b_offset3:int, b_offset4:int, s_opn1:opn_mem, s_opn2:opn_mem, s_opn3:opn_mem, s_opn4:opn_mem, $ghost_s__abs:int, s_base:int, s_offset1:int, s_offset2:int, s_offset3:int, s_offset4:int, $ghost_si:int, index_offset1:int, index_offset2:int, index_offset3:int, index_offset4:int, old_carries:Seq___int, old_carry:int) returns(my r:regs, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars, $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap, new_carry:int, new_carries:Seq___int) requires MemInv(me,init,stk_old,statics_old,core_state,ptMem,mems_old); requires NucleusInv(objLayouts_old,$S,$toAbs_old,$absMem_old,$commonVars_old,$gcVars_old,me,init,stk_old,statics_old,core_state,ptMem,mems_old,$stacksFrames_old,io_old); requires HeapInv($absMem_old, objLayouts_old, heap_old); requires $ghost_a != (ArrayOfInt(0 - 1, NO_ABS)); requires fun_IsWordSeq(fun_Seq__FromArray($absMem_old, $ghost_a)); requires $ghost_b != (ArrayOfInt(0 - 1, NO_ABS)); requires fun_IsWordSeq(fun_Seq__FromArray($absMem_old, $ghost_b)); requires $ghost_s != (ArrayOfInt(0 - 1, NO_ABS)); requires $ghost_b != $ghost_s; requires $ghost_a != $ghost_s; requires $ghost_a__abs != $ghost_s__abs; requires $ghost_b__abs != $ghost_s__abs; requires s_offset1 == Arr_Length($ghost_s) - 1 - $ghost_si + index_offset1; requires s_offset2 == Arr_Length($ghost_s) - 1 - $ghost_si + index_offset2; requires s_offset3 == Arr_Length($ghost_s) - 1 - $ghost_si + index_offset3; requires s_offset4 == Arr_Length($ghost_s) - 1 - $ghost_si + index_offset4; requires old_carry == if (Cf(r_old.efl)) then 1 else 0; requires $ghost_a.arrAbs == $ghost_a__abs; requires HeapAbsData(heap_old, $ghost_a__abs) is Abs_ArrayOfInt; requires 0 <= a_offset1 && a_offset1 < HeapAbsData(heap_old, $ghost_a__abs).arr.arrCount; requires 0 <= a_offset2 && a_offset2 < HeapAbsData(heap_old, $ghost_a__abs).arr.arrCount; requires 0 <= a_offset3 && a_offset3 < HeapAbsData(heap_old, $ghost_a__abs).arr.arrCount; requires 0 <= a_offset4 && a_offset4 < HeapAbsData(heap_old, $ghost_a__abs).arr.arrCount; requires HeapValue(objLayouts_old, true, $toAbs_old, a_base, $ghost_a__abs); requires EvalPtrOk(a_opn1); requires EvalPtrOk(a_opn2); requires EvalPtrOk(a_opn3); requires EvalPtrOk(a_opn4); requires EvalPtr(r_old, a_opn1) == a_base + 4 * (2 + a_offset1); requires EvalPtr(r_old, a_opn2) == a_base + 4 * (2 + a_offset2); requires EvalPtr(r_old, a_opn3) == a_base + 4 * (2 + a_offset3); requires EvalPtr(r_old, a_opn4) == a_base + 4 * (2 + a_offset4); requires a_offset1 == a_offset2 + 1 && a_offset2 == a_offset3 + 1 && a_offset3 == a_offset4 + 1; requires a_opn1._ptr is MReg && a_opn1._ptr._mreg == EAX; requires a_opn2._ptr is MReg && a_opn2._ptr._mreg == EAX; requires a_opn3._ptr is MReg && a_opn3._ptr._mreg == EAX; requires a_opn4._ptr is MReg && a_opn4._ptr._mreg == EAX; requires $ghost_b.arrAbs == $ghost_b__abs; requires HeapAbsData(heap_old, $ghost_b__abs) is Abs_ArrayOfInt; requires 0 <= b_offset1 && b_offset1 < HeapAbsData(heap_old, $ghost_b__abs).arr.arrCount; requires 0 <= b_offset2 && b_offset2 < HeapAbsData(heap_old, $ghost_b__abs).arr.arrCount; requires 0 <= b_offset3 && b_offset3 < HeapAbsData(heap_old, $ghost_b__abs).arr.arrCount; requires 0 <= b_offset4 && b_offset4 < HeapAbsData(heap_old, $ghost_b__abs).arr.arrCount; requires HeapValue(objLayouts_old, true, $toAbs_old, b_base, $ghost_b__abs); requires EvalPtrOk(b_opn1); requires EvalPtrOk(b_opn2); requires EvalPtrOk(b_opn3); requires EvalPtrOk(b_opn4); requires EvalPtr(r_old, b_opn1) == b_base + 4 * (2 + b_offset1); requires EvalPtr(r_old, b_opn2) == b_base + 4 * (2 + b_offset2); requires EvalPtr(r_old, b_opn3) == b_base + 4 * (2 + b_offset3); requires EvalPtr(r_old, b_opn4) == b_base + 4 * (2 + b_offset4); requires b_offset1 == b_offset2 + 1 && b_offset2 == b_offset3 + 1 && b_offset3 == b_offset4 + 1; requires b_opn1._ptr is MReg && b_opn1._ptr._mreg == EBX; requires b_opn2._ptr is MReg && b_opn2._ptr._mreg == EBX; requires b_opn3._ptr is MReg && b_opn3._ptr._mreg == EBX; requires b_opn4._ptr is MReg && b_opn4._ptr._mreg == EBX; requires $ghost_s.arrAbs == $ghost_s__abs; requires HeapAbsData(heap_old, $ghost_s__abs) is Abs_ArrayOfInt; requires 0 <= s_offset1 && s_offset1 < HeapAbsData(heap_old, $ghost_s__abs).arr.arrCount; requires 0 <= s_offset2 && s_offset2 < HeapAbsData(heap_old, $ghost_s__abs).arr.arrCount; requires 0 <= s_offset3 && s_offset3 < HeapAbsData(heap_old, $ghost_s__abs).arr.arrCount; requires 0 <= s_offset4 && s_offset4 < HeapAbsData(heap_old, $ghost_s__abs).arr.arrCount; requires INTERNAL_lt_boogie(s_offset1, (Arr_Length($ghost_s))); requires INTERNAL_lt_boogie(s_offset2, (Arr_Length($ghost_s))); requires INTERNAL_lt_boogie(s_offset3, (Arr_Length($ghost_s))); requires INTERNAL_lt_boogie(s_offset4, (Arr_Length($ghost_s))); requires HeapValue(objLayouts_old, true, $toAbs_old, s_base, $ghost_s__abs); requires EvalPtrOk(s_opn1); requires EvalPtrOk(s_opn2); requires EvalPtrOk(s_opn3); requires EvalPtrOk(s_opn4); requires EvalPtr(r_old, s_opn1) == s_base + 4 * (2 + s_offset1); requires EvalPtr(r_old, s_opn2) == s_base + 4 * (2 + s_offset2); requires EvalPtr(r_old, s_opn3) == s_base + 4 * (2 + s_offset3); requires EvalPtr(r_old, s_opn4) == s_base + 4 * (2 + s_offset4); requires s_offset1 == s_offset2 + 1 && s_offset2 == s_offset3 + 1 && s_offset3 == s_offset4 + 1; requires s_opn1._ptr is MReg && s_opn1._ptr._mreg == ECX; requires s_opn2._ptr is MReg && s_opn2._ptr._mreg == ECX; requires s_opn3._ptr is MReg && s_opn3._ptr._mreg == ECX; requires s_opn4._ptr is MReg && s_opn4._ptr._mreg == ECX; requires fun_Seq__Length___int(old_carries) > 0; requires fun_Seq__Index___int(old_carries, fun_Seq__Length___int(old_carries) - 1) == old_carry; modifies $Time; ensures stk == stk_old; ensures $stacksFrames == $stacksFrames_old; ensures (forall i:int::{$stacksFrames[$S].Abss[i]} i != EvalPtr(r_old, s_opn1) && i != EvalPtr(r_old, s_opn2) && i != EvalPtr(r_old, s_opn3) && i != EvalPtr(r_old, s_opn4) ==> $stacksFrames[$S].Abss[i] == $stacksFrames_old[$S].Abss[i]); ensures MemInv(me,init,stk,statics,core_state,ptMem,mems); ensures NucleusInv(objLayouts,$S,$toAbs,$absMem,$commonVars,$gcVars,me,init,stk,statics,core_state,ptMem,mems,$stacksFrames,io); ensures HeapInv($absMem, objLayouts, heap); ensures AbsExtend($toAbs, $toAbs_old, objLayouts, objLayouts_old); ensures (forall i:int::{$absMem[i]}{heap.absData[i]} heap_old.absData[i] is AbsNone || (heap.absData[i] == heap_old.absData[i] && ($absMem[i] == $absMem_old[i] || i == (($ghost_s).arrAbs)))); ensures io._inCtr == io_old._inCtr && io._outCtr == io_old._outCtr; //- Only havocs edi, ebp ensures r.regs[EAX] == r_old.regs[EAX]; ensures r.regs[EBX] == r_old.regs[EBX]; ensures r.regs[ECX] == r_old.regs[ECX]; ensures r.regs[EDX] == r_old.regs[EDX]; ensures r.regs[ESI] == r_old.regs[ESI]; ensures r.regs[ESP] == r_old.regs[ESP]; ensures HeapValue(objLayouts, true, $toAbs, a_base, $ghost_a__abs); ensures HeapValue(objLayouts, true, $toAbs, b_base, $ghost_b__abs); ensures HeapValue(objLayouts, true, $toAbs, s_base, $ghost_s__abs); ensures new_carry == if (Cf(r.efl)) then 1 else 0; ensures new_carry == if ((fun_INTERNAL__array__elems__index($absMem[$ghost_a__abs], a_offset4) + fun_INTERNAL__array__elems__index($absMem[$ghost_b__abs], b_offset4) + fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - 2)) >= WORD_HI) then 1 else 0; //if ((fun_INTERNAL__array__elems__index($absMem[$ghost_a__abs], a_offset4) + fun_INTERNAL__array__elems__index($absMem[$ghost_b__abs], b_offset4) + old_carry) >= WORD_HI) then 1 else 0; ensures fun_INTERNAL__array__elems__index($absMem[$ghost_s__abs], s_offset1) == fun_mod0x100000000(fun_INTERNAL__array__elems__index($absMem[$ghost_a__abs], a_offset1) + fun_INTERNAL__array__elems__index($absMem[$ghost_b__abs], b_offset1) + old_carry); ensures fun_INTERNAL__array__elems__index($absMem[$ghost_s__abs], s_offset2) == fun_mod0x100000000(fun_INTERNAL__array__elems__index($absMem[$ghost_a__abs], a_offset2) + fun_INTERNAL__array__elems__index($absMem[$ghost_b__abs], b_offset2) + fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - 4)); ensures fun_INTERNAL__array__elems__index($absMem[$ghost_s__abs], s_offset3) == fun_mod0x100000000(fun_INTERNAL__array__elems__index($absMem[$ghost_a__abs], a_offset3) + fun_INTERNAL__array__elems__index($absMem[$ghost_b__abs], b_offset3) + fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - 3)); ensures fun_INTERNAL__array__elems__index($absMem[$ghost_s__abs], s_offset4) == fun_mod0x100000000(fun_INTERNAL__array__elems__index($absMem[$ghost_a__abs], a_offset4) + fun_INTERNAL__array__elems__index($absMem[$ghost_b__abs], b_offset4) + fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - 2)); //- Arrays A and B are unmodified ensures (forall j:int :: { fun_INTERNAL__array__elems__index($absMem[$ghost_a.arrAbs], j) } (((INTERNAL_le_boogie(0, j)) && (INTERNAL_lt_boogie(j, (Arr_Length($ghost_a)))))) ==> ((fun_INTERNAL__array__elems__index($absMem[$ghost_a.arrAbs], j)) == (old(fun_INTERNAL__array__elems__index($absMem_old[$ghost_a.arrAbs], j))))); ensures (forall j:int :: { fun_INTERNAL__array__elems__index($absMem[$ghost_b.arrAbs], j) } (((INTERNAL_le_boogie(0, j)) && (INTERNAL_lt_boogie(j, (Arr_Length($ghost_b)))))) ==> ((fun_INTERNAL__array__elems__index($absMem[$ghost_b.arrAbs], j)) == (old(fun_INTERNAL__array__elems__index($absMem_old[$ghost_b.arrAbs], j))))); //- Array S is unmodified except for the four entries we touch ensures (forall j:int :: { fun_INTERNAL__array__elems__index($absMem[$ghost_s.arrAbs], j) } (((INTERNAL_le_boogie(0, j)) && (INTERNAL_lt_boogie(j, (Arr_Length($ghost_s))))) && j != s_offset1 && j != s_offset2 && j != s_offset3 && j != s_offset4) ==> ((fun_INTERNAL__array__elems__index($absMem[$ghost_s.arrAbs], j)) == (old(fun_INTERNAL__array__elems__index($absMem_old[$ghost_s.arrAbs], j))))); ensures fun_Seq__Length___int(new_carries) == fun_Seq__Length___int(old_carries) + 4; ensures (forall i:int :: 0 <= i && i < fun_Seq__Length___int(old_carries) ==> fun_Seq__Index___int(new_carries, i) == fun_Seq__Index___int(old_carries, i)); ensures fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - 4) == if ((fun_INTERNAL__array__elems__index($absMem[$ghost_a__abs], a_offset1) + fun_INTERNAL__array__elems__index($absMem[$ghost_b__abs], b_offset1) + old_carry) >= WORD_HI) then 1 else 0; ensures fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - 3) == if ((fun_INTERNAL__array__elems__index($absMem[$ghost_a__abs], a_offset2) + fun_INTERNAL__array__elems__index($absMem[$ghost_b__abs], b_offset2) + fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - 4)) >= WORD_HI) then 1 else 0; ensures fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - 2) == if ((fun_INTERNAL__array__elems__index($absMem[$ghost_a__abs], a_offset3) + fun_INTERNAL__array__elems__index($absMem[$ghost_b__abs], b_offset3) + fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - 3)) >= WORD_HI) then 1 else 0; ensures fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - 1) == new_carry; ensures (forall i:int :: TV(i) && 1 <= i && i <= 4 ==> fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - i) == if ((fun_INTERNAL__array__elems__index($absMem[$ghost_a__abs], a_offset4 + i - 1) + fun_INTERNAL__array__elems__index($absMem[$ghost_b__abs], b_offset4 + i - 1) + fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - (i+1))) >= WORD_HI) then 1 else 0); { var $ghost_carries:Seq___int; var carry1:int; var carry2:int; var carry3:int; //- Boilerplate variable propagation r := r_old; stk := stk_old; statics := statics_old; io := io_old; mems := mems_old; $commonVars := $commonVars_old; $gcVars := $gcVars_old; $toAbs := $toAbs_old; $absMem := $absMem_old; $stacksFrames := $stacksFrames_old; objLayouts := objLayouts_old; heap := heap_old; //- Teach Beat about Dafny sequence operations call proc_Seq__Empty__ToZero___int(); call proc_Seq__Empty__FromZero___int(); call proc_Seq__Singleton__Length___int(); call proc_Seq__Build__Length___int(); call proc_Seq__Build__Index___int(); call proc_Seq__Append__Length___int(); call proc_Seq__Index__Singleton___int(); call proc_Seq__Append__Index___int(); call proc_Seq__Update__Length___int(); call proc_Seq__Index__Update___int(); call proc_Seq__Equal__Equiv___int(); call proc_Seq__Take__Length___int(); call proc_Seq__Take__Index___int(); call proc_Seq__Drop__Length___int(); call proc_Seq__Drop__Index___int(); call proc_Seq__Append__TakeDrop___int(); call proc_Seq__Update__CommuteTake1___int(); call proc_Seq__Update__CommuteTake2___int(); call proc_Seq__Update__CommuteDrop1___int(); call proc_Seq__Update__CommuteDrop2___int(); call proc_Seq__Build__CommuteDrop___int(); call proc_Seq__Take__Empty___int(); call proc_Seq__Drop__Empty___int(); call proc_lemma__2toX(); $ghost_carries := old_carries; call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry1, $ghost_carries := arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_a, $ghost_b, $ghost_s, a_opn1, $ghost_a__abs, a_base, a_offset1, b_opn1, $ghost_b__abs, b_base, b_offset1, s_opn1, $ghost_s__abs, s_base, s_offset1, $ghost_si, index_offset1, $ghost_carries, old_carry); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry2, $ghost_carries := arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_a, $ghost_b, $ghost_s, a_opn2, $ghost_a__abs, a_base, a_offset2, b_opn2, $ghost_b__abs, b_base, b_offset2, s_opn2, $ghost_s__abs, s_base, s_offset2, $ghost_si, index_offset2, $ghost_carries, carry1); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry3, $ghost_carries := arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_a, $ghost_b, $ghost_s, a_opn3, $ghost_a__abs, a_base, a_offset3, b_opn3, $ghost_b__abs, b_base, b_offset3, s_opn3, $ghost_s__abs, s_base, s_offset3, $ghost_si, index_offset3, $ghost_carries, carry2); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, new_carry, $ghost_carries := arrayAdd(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_a, $ghost_b, $ghost_s, a_opn4, $ghost_a__abs, a_base, a_offset4, b_opn4, $ghost_b__abs, b_base, b_offset4, s_opn4, $ghost_s__abs, s_base, s_offset4, $ghost_si, index_offset4, $ghost_carries, carry3); new_carries := $ghost_carries; } procedure arrayAdd8(my r_old:regs, const my core_state:core_state, linear stk_old:mem, linear statics_old:mem, linear io_old:IOState, linear mems_old:mems, $commonVars_old:commonVars, $gcVars_old:gcVars, $toAbs_old:[int]int, $absMem_old:[int][int]int, $stacksFrames_old:[int]Frames, objLayouts_old:[int]ObjLayout, heap_old:Heap, $ghost_a:ArrayOfInt, $ghost_b:ArrayOfInt, $ghost_s:ArrayOfInt, a_opn1:opn_mem, a_opn2:opn_mem, a_opn3:opn_mem, a_opn4:opn_mem,a_opn5:opn_mem,a_opn6:opn_mem,a_opn7:opn_mem,a_opn8:opn_mem,$ghost_a__abs:int, a_base:int, a_offset1:int, a_offset2:int, a_offset3:int, a_offset4:int, a_offset5:int, a_offset6:int, a_offset7:int, a_offset8:int, b_opn1:opn_mem, b_opn2:opn_mem, b_opn3:opn_mem, b_opn4:opn_mem,b_opn5:opn_mem,b_opn6:opn_mem,b_opn7:opn_mem,b_opn8:opn_mem, $ghost_b__abs:int, b_base:int, b_offset1:int, b_offset2:int, b_offset3:int, b_offset4:int, b_offset5:int, b_offset6:int, b_offset7:int, b_offset8:int, s_opn1:opn_mem, s_opn2:opn_mem, s_opn3:opn_mem, s_opn4:opn_mem, s_opn5:opn_mem, s_opn6:opn_mem, s_opn7:opn_mem, s_opn8:opn_mem, $ghost_s__abs:int, s_base:int, s_offset1:int, s_offset2:int, s_offset3:int, s_offset4:int, s_offset5:int, s_offset6:int, s_offset7:int, s_offset8:int, $ghost_si:int, index_offset1:int, index_offset2:int, index_offset3:int, index_offset4:int, index_offset5:int, index_offset6:int, index_offset7:int, index_offset8:int, old_carries:Seq___int, old_carry:int) returns(my r:regs, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars, $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap, new_carry:int, new_carries:Seq___int) requires MemInv(me,init,stk_old,statics_old,core_state,ptMem,mems_old); requires NucleusInv(objLayouts_old,$S,$toAbs_old,$absMem_old,$commonVars_old,$gcVars_old,me,init,stk_old,statics_old,core_state,ptMem,mems_old,$stacksFrames_old,io_old); requires HeapInv($absMem_old, objLayouts_old, heap_old); requires $ghost_a != (ArrayOfInt(0 - 1, NO_ABS)); requires fun_IsWordSeq(fun_Seq__FromArray($absMem_old, $ghost_a)); requires $ghost_b != (ArrayOfInt(0 - 1, NO_ABS)); requires fun_IsWordSeq(fun_Seq__FromArray($absMem_old, $ghost_b)); requires $ghost_s != (ArrayOfInt(0 - 1, NO_ABS)); requires $ghost_b != $ghost_s; requires $ghost_a != $ghost_s; requires $ghost_a__abs != $ghost_s__abs; requires $ghost_b__abs != $ghost_s__abs; requires s_offset1 == Arr_Length($ghost_s) - 1 - $ghost_si + index_offset1; requires s_offset2 == Arr_Length($ghost_s) - 1 - $ghost_si + index_offset2; requires s_offset3 == Arr_Length($ghost_s) - 1 - $ghost_si + index_offset3; requires s_offset4 == Arr_Length($ghost_s) - 1 - $ghost_si + index_offset4; requires s_offset5 == Arr_Length($ghost_s) - 1 - $ghost_si + index_offset5; requires s_offset6 == Arr_Length($ghost_s) - 1 - $ghost_si + index_offset6; requires s_offset7 == Arr_Length($ghost_s) - 1 - $ghost_si + index_offset7; requires s_offset8 == Arr_Length($ghost_s) - 1 - $ghost_si + index_offset8; requires old_carry == if (Cf(r_old.efl)) then 1 else 0; requires $ghost_a.arrAbs == $ghost_a__abs; requires HeapAbsData(heap_old, $ghost_a__abs) is Abs_ArrayOfInt; requires 0 <= a_offset1 && a_offset1 < HeapAbsData(heap_old, $ghost_a__abs).arr.arrCount; requires 0 <= a_offset2 && a_offset2 < HeapAbsData(heap_old, $ghost_a__abs).arr.arrCount; requires 0 <= a_offset3 && a_offset3 < HeapAbsData(heap_old, $ghost_a__abs).arr.arrCount; requires 0 <= a_offset4 && a_offset4 < HeapAbsData(heap_old, $ghost_a__abs).arr.arrCount; requires 0 <= a_offset5 && a_offset5 < HeapAbsData(heap_old, $ghost_a__abs).arr.arrCount; requires 0 <= a_offset6 && a_offset6 < HeapAbsData(heap_old, $ghost_a__abs).arr.arrCount; requires 0 <= a_offset7 && a_offset7 < HeapAbsData(heap_old, $ghost_a__abs).arr.arrCount; requires 0 <= a_offset8 && a_offset8 < HeapAbsData(heap_old, $ghost_a__abs).arr.arrCount; requires HeapValue(objLayouts_old, true, $toAbs_old, a_base, $ghost_a__abs); requires EvalPtrOk(a_opn1); requires EvalPtrOk(a_opn2); requires EvalPtrOk(a_opn3); requires EvalPtrOk(a_opn4); requires EvalPtrOk(a_opn5); requires EvalPtrOk(a_opn6); requires EvalPtrOk(a_opn7); requires EvalPtrOk(a_opn8); requires EvalPtr(r_old, a_opn1) == a_base + 4 * (2 + a_offset1); requires EvalPtr(r_old, a_opn2) == a_base + 4 * (2 + a_offset2); requires EvalPtr(r_old, a_opn3) == a_base + 4 * (2 + a_offset3); requires EvalPtr(r_old, a_opn4) == a_base + 4 * (2 + a_offset4); requires EvalPtr(r_old, a_opn5) == a_base + 4 * (2 + a_offset5); requires EvalPtr(r_old, a_opn6) == a_base + 4 * (2 + a_offset6); requires EvalPtr(r_old, a_opn7) == a_base + 4 * (2 + a_offset7); requires EvalPtr(r_old, a_opn8) == a_base + 4 * (2 + a_offset8); requires a_offset1 == a_offset2 + 1 && a_offset2 == a_offset3 + 1 && a_offset3 == a_offset4 + 1; requires a_offset4 == a_offset5 + 1 && a_offset5 == a_offset6 + 1 && a_offset6 == a_offset7 + 1 && a_offset7 == a_offset8 + 1; requires a_opn1._ptr is MReg && a_opn1._ptr._mreg == EAX; requires a_opn2._ptr is MReg && a_opn2._ptr._mreg == EAX; requires a_opn3._ptr is MReg && a_opn3._ptr._mreg == EAX; requires a_opn4._ptr is MReg && a_opn4._ptr._mreg == EAX; requires a_opn5._ptr is MReg && a_opn5._ptr._mreg == EAX; requires a_opn6._ptr is MReg && a_opn6._ptr._mreg == EAX; requires a_opn7._ptr is MReg && a_opn7._ptr._mreg == EAX; requires a_opn8._ptr is MReg && a_opn8._ptr._mreg == EAX; requires $ghost_b.arrAbs == $ghost_b__abs; requires HeapAbsData(heap_old, $ghost_b__abs) is Abs_ArrayOfInt; requires 0 <= b_offset1 && b_offset1 < HeapAbsData(heap_old, $ghost_b__abs).arr.arrCount; requires 0 <= b_offset2 && b_offset2 < HeapAbsData(heap_old, $ghost_b__abs).arr.arrCount; requires 0 <= b_offset3 && b_offset3 < HeapAbsData(heap_old, $ghost_b__abs).arr.arrCount; requires 0 <= b_offset4 && b_offset4 < HeapAbsData(heap_old, $ghost_b__abs).arr.arrCount; requires 0 <= b_offset5 && b_offset5 < HeapAbsData(heap_old, $ghost_b__abs).arr.arrCount; requires 0 <= b_offset6 && b_offset6 < HeapAbsData(heap_old, $ghost_b__abs).arr.arrCount; requires 0 <= b_offset7 && b_offset7 < HeapAbsData(heap_old, $ghost_b__abs).arr.arrCount; requires 0 <= b_offset8 && b_offset8 < HeapAbsData(heap_old, $ghost_b__abs).arr.arrCount; requires HeapValue(objLayouts_old, true, $toAbs_old, b_base, $ghost_b__abs); requires EvalPtrOk(b_opn1); requires EvalPtrOk(b_opn2); requires EvalPtrOk(b_opn3); requires EvalPtrOk(b_opn4); requires EvalPtrOk(b_opn5); requires EvalPtrOk(b_opn6); requires EvalPtrOk(b_opn7); requires EvalPtrOk(b_opn8); requires EvalPtr(r_old, b_opn1) == b_base + 4 * (2 + b_offset1); requires EvalPtr(r_old, b_opn2) == b_base + 4 * (2 + b_offset2); requires EvalPtr(r_old, b_opn3) == b_base + 4 * (2 + b_offset3); requires EvalPtr(r_old, b_opn4) == b_base + 4 * (2 + b_offset4); requires EvalPtr(r_old, b_opn5) == b_base + 4 * (2 + b_offset5); requires EvalPtr(r_old, b_opn6) == b_base + 4 * (2 + b_offset6); requires EvalPtr(r_old, b_opn7) == b_base + 4 * (2 + b_offset7); requires EvalPtr(r_old, b_opn8) == b_base + 4 * (2 + b_offset8); requires b_offset1 == b_offset2 + 1 && b_offset2 == b_offset3 + 1 && b_offset3 == b_offset4 + 1; requires b_offset4 == b_offset5 + 1 && b_offset5 == b_offset6 + 1 && b_offset6 == b_offset7 + 1 && b_offset7 == b_offset8 + 1; requires b_opn1._ptr is MReg && b_opn1._ptr._mreg == EBX; requires b_opn2._ptr is MReg && b_opn2._ptr._mreg == EBX; requires b_opn3._ptr is MReg && b_opn3._ptr._mreg == EBX; requires b_opn4._ptr is MReg && b_opn4._ptr._mreg == EBX; requires b_opn5._ptr is MReg && b_opn5._ptr._mreg == EBX; requires b_opn6._ptr is MReg && b_opn6._ptr._mreg == EBX; requires b_opn7._ptr is MReg && b_opn7._ptr._mreg == EBX; requires b_opn8._ptr is MReg && b_opn8._ptr._mreg == EBX; requires $ghost_s.arrAbs == $ghost_s__abs; requires HeapAbsData(heap_old, $ghost_s__abs) is Abs_ArrayOfInt; requires 0 <= s_offset1 && s_offset1 < HeapAbsData(heap_old, $ghost_s__abs).arr.arrCount; requires 0 <= s_offset2 && s_offset2 < HeapAbsData(heap_old, $ghost_s__abs).arr.arrCount; requires 0 <= s_offset3 && s_offset3 < HeapAbsData(heap_old, $ghost_s__abs).arr.arrCount; requires 0 <= s_offset4 && s_offset4 < HeapAbsData(heap_old, $ghost_s__abs).arr.arrCount; requires 0 <= s_offset5 && s_offset5 < HeapAbsData(heap_old, $ghost_s__abs).arr.arrCount; requires 0 <= s_offset6 && s_offset6 < HeapAbsData(heap_old, $ghost_s__abs).arr.arrCount; requires 0 <= s_offset7 && s_offset7 < HeapAbsData(heap_old, $ghost_s__abs).arr.arrCount; requires 0 <= s_offset8 && s_offset8 < HeapAbsData(heap_old, $ghost_s__abs).arr.arrCount; requires INTERNAL_lt_boogie(s_offset1, (Arr_Length($ghost_s))); requires INTERNAL_lt_boogie(s_offset2, (Arr_Length($ghost_s))); requires INTERNAL_lt_boogie(s_offset3, (Arr_Length($ghost_s))); requires INTERNAL_lt_boogie(s_offset4, (Arr_Length($ghost_s))); requires INTERNAL_lt_boogie(s_offset5, (Arr_Length($ghost_s))); requires INTERNAL_lt_boogie(s_offset6, (Arr_Length($ghost_s))); requires INTERNAL_lt_boogie(s_offset7, (Arr_Length($ghost_s))); requires INTERNAL_lt_boogie(s_offset8, (Arr_Length($ghost_s))); requires HeapValue(objLayouts_old, true, $toAbs_old, s_base, $ghost_s__abs); requires EvalPtrOk(s_opn1); requires EvalPtrOk(s_opn2); requires EvalPtrOk(s_opn3); requires EvalPtrOk(s_opn4); requires EvalPtrOk(s_opn5); requires EvalPtrOk(s_opn6); requires EvalPtrOk(s_opn7); requires EvalPtrOk(s_opn8); requires EvalPtr(r_old, s_opn1) == s_base + 4 * (2 + s_offset1); requires EvalPtr(r_old, s_opn2) == s_base + 4 * (2 + s_offset2); requires EvalPtr(r_old, s_opn3) == s_base + 4 * (2 + s_offset3); requires EvalPtr(r_old, s_opn4) == s_base + 4 * (2 + s_offset4); requires EvalPtr(r_old, s_opn5) == s_base + 4 * (2 + s_offset5); requires EvalPtr(r_old, s_opn6) == s_base + 4 * (2 + s_offset6); requires EvalPtr(r_old, s_opn7) == s_base + 4 * (2 + s_offset7); requires EvalPtr(r_old, s_opn8) == s_base + 4 * (2 + s_offset8); requires s_offset1 == s_offset2 + 1 && s_offset2 == s_offset3 + 1 && s_offset3 == s_offset4 + 1; requires s_offset4 == s_offset5 + 1 && s_offset5 == s_offset6 + 1 && s_offset6 == s_offset7 + 1 && s_offset7 == s_offset8 + 1; requires s_opn1._ptr is MReg && s_opn1._ptr._mreg == ECX; requires s_opn2._ptr is MReg && s_opn2._ptr._mreg == ECX; requires s_opn3._ptr is MReg && s_opn3._ptr._mreg == ECX; requires s_opn4._ptr is MReg && s_opn4._ptr._mreg == ECX; requires s_opn5._ptr is MReg && s_opn5._ptr._mreg == ECX; requires s_opn6._ptr is MReg && s_opn6._ptr._mreg == ECX; requires s_opn7._ptr is MReg && s_opn7._ptr._mreg == ECX; requires s_opn8._ptr is MReg && s_opn8._ptr._mreg == ECX; requires fun_Seq__Length___int(old_carries) > 0; requires fun_Seq__Index___int(old_carries, fun_Seq__Length___int(old_carries) - 1) == old_carry; modifies $Time; ensures stk == stk_old; ensures $stacksFrames == $stacksFrames_old; ensures (forall i:int::{$stacksFrames[$S].Abss[i]} i != EvalPtr(r_old, s_opn1) && i != EvalPtr(r_old, s_opn2) && i != EvalPtr(r_old, s_opn3) && i != EvalPtr(r_old, s_opn4) && i != EvalPtr(r_old, s_opn5) && i != EvalPtr(r_old, s_opn6) && i != EvalPtr(r_old, s_opn7) && i != EvalPtr(r_old, s_opn8) ==> $stacksFrames[$S].Abss[i] == $stacksFrames_old[$S].Abss[i]); ensures MemInv(me,init,stk,statics,core_state,ptMem,mems); ensures NucleusInv(objLayouts,$S,$toAbs,$absMem,$commonVars,$gcVars,me,init,stk,statics,core_state,ptMem,mems,$stacksFrames,io); ensures HeapInv($absMem, objLayouts, heap); ensures AbsExtend($toAbs, $toAbs_old, objLayouts, objLayouts_old); ensures (forall i:int::{$absMem[i]}{heap.absData[i]} heap_old.absData[i] is AbsNone || (heap.absData[i] == heap_old.absData[i] && ($absMem[i] == $absMem_old[i] || i == (($ghost_s).arrAbs)))); ensures io._inCtr == io_old._inCtr && io._outCtr == io_old._outCtr; //- Only havocs edi, ebp ensures r.regs[EAX] == r_old.regs[EAX]; ensures r.regs[EBX] == r_old.regs[EBX]; ensures r.regs[ECX] == r_old.regs[ECX]; ensures r.regs[EDX] == r_old.regs[EDX]; ensures r.regs[ESI] == r_old.regs[ESI]; ensures r.regs[ESP] == r_old.regs[ESP]; ensures HeapValue(objLayouts, true, $toAbs, a_base, $ghost_a__abs); ensures HeapValue(objLayouts, true, $toAbs, b_base, $ghost_b__abs); ensures HeapValue(objLayouts, true, $toAbs, s_base, $ghost_s__abs); ensures new_carry == if (Cf(r.efl)) then 1 else 0; ensures new_carry == if ((fun_INTERNAL__array__elems__index($absMem[$ghost_a__abs], a_offset8) + fun_INTERNAL__array__elems__index($absMem[$ghost_b__abs], b_offset8) + fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - 2)) >= WORD_HI) then 1 else 0; ensures fun_INTERNAL__array__elems__index($absMem[$ghost_s__abs], s_offset1) == fun_mod0x100000000(fun_INTERNAL__array__elems__index($absMem[$ghost_a__abs], a_offset1) + fun_INTERNAL__array__elems__index($absMem[$ghost_b__abs], b_offset1) + old_carry); ensures fun_INTERNAL__array__elems__index($absMem[$ghost_s__abs], s_offset2) == fun_mod0x100000000(fun_INTERNAL__array__elems__index($absMem[$ghost_a__abs], a_offset2) + fun_INTERNAL__array__elems__index($absMem[$ghost_b__abs], b_offset2) + fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - 8)); ensures fun_INTERNAL__array__elems__index($absMem[$ghost_s__abs], s_offset3) == fun_mod0x100000000(fun_INTERNAL__array__elems__index($absMem[$ghost_a__abs], a_offset3) + fun_INTERNAL__array__elems__index($absMem[$ghost_b__abs], b_offset3) + fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - 7)); ensures fun_INTERNAL__array__elems__index($absMem[$ghost_s__abs], s_offset4) == fun_mod0x100000000(fun_INTERNAL__array__elems__index($absMem[$ghost_a__abs], a_offset4) + fun_INTERNAL__array__elems__index($absMem[$ghost_b__abs], b_offset4) + fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - 6)); ensures fun_INTERNAL__array__elems__index($absMem[$ghost_s__abs], s_offset5) == fun_mod0x100000000(fun_INTERNAL__array__elems__index($absMem[$ghost_a__abs], a_offset5) + fun_INTERNAL__array__elems__index($absMem[$ghost_b__abs], b_offset5) + fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - 5)); ensures fun_INTERNAL__array__elems__index($absMem[$ghost_s__abs], s_offset6) == fun_mod0x100000000(fun_INTERNAL__array__elems__index($absMem[$ghost_a__abs], a_offset6) + fun_INTERNAL__array__elems__index($absMem[$ghost_b__abs], b_offset6) + fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - 4)); ensures fun_INTERNAL__array__elems__index($absMem[$ghost_s__abs], s_offset7) == fun_mod0x100000000(fun_INTERNAL__array__elems__index($absMem[$ghost_a__abs], a_offset7) + fun_INTERNAL__array__elems__index($absMem[$ghost_b__abs], b_offset7) + fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - 3)); ensures fun_INTERNAL__array__elems__index($absMem[$ghost_s__abs], s_offset8) == fun_mod0x100000000(fun_INTERNAL__array__elems__index($absMem[$ghost_a__abs], a_offset8) + fun_INTERNAL__array__elems__index($absMem[$ghost_b__abs], b_offset8) + fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - 2)); //- Arrays A and B are unmodified ensures (forall j:int :: { fun_INTERNAL__array__elems__index($absMem[$ghost_a.arrAbs], j) } (((INTERNAL_le_boogie(0, j)) && (INTERNAL_lt_boogie(j, (Arr_Length($ghost_a)))))) ==> ((fun_INTERNAL__array__elems__index($absMem[$ghost_a.arrAbs], j)) == (old(fun_INTERNAL__array__elems__index($absMem_old[$ghost_a.arrAbs], j))))); ensures (forall j:int :: { fun_INTERNAL__array__elems__index($absMem[$ghost_b.arrAbs], j) } (((INTERNAL_le_boogie(0, j)) && (INTERNAL_lt_boogie(j, (Arr_Length($ghost_b)))))) ==> ((fun_INTERNAL__array__elems__index($absMem[$ghost_b.arrAbs], j)) == (old(fun_INTERNAL__array__elems__index($absMem_old[$ghost_b.arrAbs], j))))); //- Array S is unmodified except for the four entries we touch ensures (forall j:int :: { fun_INTERNAL__array__elems__index($absMem[$ghost_s.arrAbs], j) } (((INTERNAL_le_boogie(0, j)) && (INTERNAL_lt_boogie(j, (Arr_Length($ghost_s))))) && j != s_offset1 && j != s_offset2 && j != s_offset3 && j != s_offset4 && j != s_offset5 && j != s_offset6 && j != s_offset7 && j != s_offset8) ==> ((fun_INTERNAL__array__elems__index($absMem[$ghost_s.arrAbs], j)) == (old(fun_INTERNAL__array__elems__index($absMem_old[$ghost_s.arrAbs], j))))); ensures fun_Seq__Length___int(new_carries) == fun_Seq__Length___int(old_carries) + 8; ensures (forall i:int :: 0 <= i && i < fun_Seq__Length___int(old_carries) ==> fun_Seq__Index___int(new_carries, i) == fun_Seq__Index___int(old_carries, i)); ensures fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - 8) == if ((fun_INTERNAL__array__elems__index($absMem[$ghost_a__abs], a_offset1) + fun_INTERNAL__array__elems__index($absMem[$ghost_b__abs], b_offset1) + old_carry) >= WORD_HI) then 1 else 0; ensures fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - 7) == if ((fun_INTERNAL__array__elems__index($absMem[$ghost_a__abs], a_offset2) + fun_INTERNAL__array__elems__index($absMem[$ghost_b__abs], b_offset2) + fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - 8)) >= WORD_HI) then 1 else 0; ensures fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - 6) == if ((fun_INTERNAL__array__elems__index($absMem[$ghost_a__abs], a_offset3) + fun_INTERNAL__array__elems__index($absMem[$ghost_b__abs], b_offset3) + fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - 7)) >= WORD_HI) then 1 else 0; ensures fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - 5) == if ((fun_INTERNAL__array__elems__index($absMem[$ghost_a__abs], a_offset4) + fun_INTERNAL__array__elems__index($absMem[$ghost_b__abs], b_offset4) + fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - 6)) >= WORD_HI) then 1 else 0; ensures fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - 4) == if ((fun_INTERNAL__array__elems__index($absMem[$ghost_a__abs], a_offset5) + fun_INTERNAL__array__elems__index($absMem[$ghost_b__abs], b_offset5) + fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - 5)) >= WORD_HI) then 1 else 0; ensures fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - 3) == if ((fun_INTERNAL__array__elems__index($absMem[$ghost_a__abs], a_offset6) + fun_INTERNAL__array__elems__index($absMem[$ghost_b__abs], b_offset6) + fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - 4)) >= WORD_HI) then 1 else 0; ensures fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - 2) == if ((fun_INTERNAL__array__elems__index($absMem[$ghost_a__abs], a_offset7) + fun_INTERNAL__array__elems__index($absMem[$ghost_b__abs], b_offset7) + fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - 3)) >= WORD_HI) then 1 else 0; ensures fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - 1) == new_carry; ensures (forall i:int :: TV(i) && 1 <= i && i <= 8 ==> fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - i) == if ((fun_INTERNAL__array__elems__index($absMem[$ghost_a__abs], a_offset8 + i - 1) + fun_INTERNAL__array__elems__index($absMem[$ghost_b__abs], b_offset8 + i - 1) + fun_Seq__Index___int(new_carries, fun_Seq__Length___int(new_carries) - (i+1))) >= WORD_HI) then 1 else 0); { var $ghost_carries:Seq___int; var carry1:int; var carry2:int; var carry3:int; //- Boilerplate variable propagation r := r_old; stk := stk_old; statics := statics_old; io := io_old; mems := mems_old; $commonVars := $commonVars_old; $gcVars := $gcVars_old; $toAbs := $toAbs_old; $absMem := $absMem_old; $stacksFrames := $stacksFrames_old; objLayouts := objLayouts_old; heap := heap_old; //- Teach Beat about Dafny sequence operations call proc_Seq__Empty__ToZero___int(); call proc_Seq__Empty__FromZero___int(); call proc_Seq__Singleton__Length___int(); call proc_Seq__Build__Length___int(); call proc_Seq__Build__Index___int(); call proc_Seq__Append__Length___int(); call proc_Seq__Index__Singleton___int(); call proc_Seq__Append__Index___int(); call proc_Seq__Update__Length___int(); call proc_Seq__Index__Update___int(); call proc_Seq__Equal__Equiv___int(); call proc_Seq__Take__Length___int(); call proc_Seq__Take__Index___int(); call proc_Seq__Drop__Length___int(); call proc_Seq__Drop__Index___int(); call proc_Seq__Append__TakeDrop___int(); call proc_Seq__Update__CommuteTake1___int(); call proc_Seq__Update__CommuteTake2___int(); call proc_Seq__Update__CommuteDrop1___int(); call proc_Seq__Update__CommuteDrop2___int(); call proc_Seq__Build__CommuteDrop___int(); call proc_Seq__Take__Empty___int(); call proc_Seq__Drop__Empty___int(); call proc_lemma__2toX(); $ghost_carries := old_carries; call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry1, $ghost_carries := arrayAdd4(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_a, $ghost_b, $ghost_s, a_opn1,a_opn2,a_opn3,a_opn4, $ghost_a__abs, a_base, a_offset1,a_offset2,a_offset3,a_offset4, b_opn1,b_opn2,b_opn3,b_opn4, $ghost_b__abs, b_base, b_offset1,b_offset2,b_offset3,b_offset4, s_opn1,s_opn2,s_opn3,s_opn4, $ghost_s__abs, s_base, s_offset1, s_offset2, s_offset3, s_offset4, $ghost_si, index_offset1, index_offset2, index_offset3, index_offset4, $ghost_carries, old_carry); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, new_carry, $ghost_carries := arrayAdd4(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_a, $ghost_b, $ghost_s, a_opn5,a_opn6,a_opn7,a_opn8, $ghost_a__abs, a_base, a_offset5,a_offset6,a_offset7,a_offset8, b_opn5,b_opn6,b_opn7,b_opn8, $ghost_b__abs, b_base, b_offset5,b_offset6,b_offset7,b_offset8, s_opn5,s_opn6,s_opn7,s_opn8, $ghost_s__abs, s_base, s_offset5, s_offset6, s_offset7, s_offset8, $ghost_si, index_offset5, index_offset6, index_offset7, index_offset8, $ghost_carries, carry1); new_carries := $ghost_carries; } //implementation Proc_Add32__unrolled__32(my r_old:regs, const my core_state:core_state, linear stk_old:mem, linear statics_old:mem, linear io_old:IOState, linear mems_old:mems, $commonVars_old:commonVars, $gcVars_old:gcVars, $toAbs_old:[int]int, $absMem_old:[int][int]int, $stacksFrames_old:[int]Frames, objLayouts_old:[int]ObjLayout, heap_old:Heap, $ghost_a:ArrayOfInt, $ghost_ai:int, $ghost_b:ArrayOfInt, $ghost_bi:int, $ghost_s:ArrayOfInt, $ghost_si:int, $ghost_c_in:int) returns(my r:regs, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars, $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap, $ghost_c_out:int, $ghost_carries:Seq___int) //{ // var $ghost_a__abs:int; // var $ghost_b__abs:int; // var $ghost_s__abs:int; // var gcStackOffset:int; // // // Boilerplate variable propagation // r := r_old; // stk := stk_old; // statics := statics_old; // io := io_old; // mems := mems_old; // $commonVars := $commonVars_old; // $gcVars := $gcVars_old; // $toAbs := $toAbs_old; // $absMem := $absMem_old; // $stacksFrames := $stacksFrames_old; // objLayouts := objLayouts_old; // heap := heap_old; // // // Teach Beat about Dafny sequence operations // call proc_Seq__Empty__ToZero___int(); // call proc_Seq__Empty__FromZero___int(); // call proc_Seq__Singleton__Length___int(); // call proc_Seq__Build__Length___int(); // call proc_Seq__Build__Index___int(); // call proc_Seq__Append__Length___int(); // call proc_Seq__Index__Singleton___int(); // call proc_Seq__Append__Index___int(); // call proc_Seq__Update__Length___int(); // call proc_Seq__Index__Update___int(); // call proc_Seq__Equal__Equiv___int(); // call proc_Seq__Take__Length___int(); // call proc_Seq__Take__Index___int(); // call proc_Seq__Drop__Length___int(); // call proc_Seq__Drop__Index___int(); // call proc_Seq__Append__TakeDrop___int(); // // call proc_Seq__Append__TakeDrop__Restricted___int(); // call proc_Seq__Update__CommuteTake1___int(); // call proc_Seq__Update__CommuteTake2___int(); // call proc_Seq__Update__CommuteDrop1___int(); // call proc_Seq__Update__CommuteDrop2___int(); // call proc_Seq__Build__CommuteDrop___int(); // call proc_Seq__Take__Empty___int(); // call proc_Seq__Drop__Empty___int(); // // gcStackOffset := 0x111000; // // call proc_lemma__2toX(); // // assert Aligned(esp); // // Prove that we can load arguments from the stack (b/c accesses are aligned) // assert TV(esp) && TO(0) && TO(1) && TO(2) && TO(3) && TO(4) && TO(5); // // // Prove that we can load arguments from the GC stack (b/c accesses are aligned) // assert TO(0x44401) && TO(0x44402) && TO(0x44403); // (gcStackOffset + {4,8,12}) / 4 // // // Load pointer to array a into edx // call r, mems := heapLoadStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, EDX, OMem(MReg(ESP, 0x111004)), EvalPtr(r, OMem(MReg(ESP, 0x111004)))); // 0x111004 = gcStackOffset + 4 // var a_base:int; // a_base := edx; // $ghost_a__abs := frameGet($stacksFrames, EvalPtr(r, OMem(MReg(ESP, gcStackOffset + 4)))); // // // Load its length into eax // call r, mems := loadArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, EAX, OMem(MReg(EDX, 4)), 0 - 1, $ghost_a__abs, r.regs[EDX]); // // // Adjust to the "beginning" of the values we care about // eax := eax - 1; // call edi := Load(stk, esp + 8); // grab ai // eax := eax - edi; // var aii:int := eax; // assert aii == Arr_Length($ghost_a) - 1 - $ghost_ai; // // // Convert aii into a memory pointer // call arrayElementProperties(core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, aii, $ghost_a__abs, edx); // Proves we're within bounds for the Lea calculation // call eax := Lea(edx + 4 * eax + 8); // var aii_ptr @ eax; // // // Load pointer to array b into edx // call r, mems := heapLoadStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, EDX, OMem(MReg(ESP, 0x111008)), EvalPtr(r, OMem(MReg(ESP, 0x111008)))); // 0x111008 = gcStackOffset + 8 // var b_base:int; // b_base := edx; // $ghost_b__abs := frameGet($stacksFrames, EvalPtr(r, OMem(MReg(ESP, gcStackOffset + 8)))); // // // Load its length into ebx // call r, mems := loadArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, EBX, OMem(MReg(EDX, 4)), 0 - 1, $ghost_b__abs, r.regs[EDX]); // // // Adjust to the "beginning" of the values we care about // ebx := ebx - 1; // call edi := Load(stk, esp + 12); // grab bi // ebx := ebx - edi; // var bii:int := ebx; // assert bii == Arr_Length($ghost_b) - 1 - $ghost_bi; // // // Convert aii into a memory pointer // call arrayElementProperties(core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, bii, $ghost_b__abs, edx); // Proves we're within bounds for the Lea calculation // call ebx := Lea(edx + 4 * ebx + 8); // var bii_ptr @ ebx; // // // Load pointer to array s into edx // call r, mems := heapLoadStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, EDX, OMem(MReg(ESP, 0x11100c)), EvalPtr(r, OMem(MReg(ESP, 0x11100c)))); // 0x11100c == gcStackOffset + 12 // var s_base:int; // s_base := edx; // $ghost_s__abs := frameGet($stacksFrames, EvalPtr(r, OMem(MReg(ESP, gcStackOffset + 12)))); // // // Load its length into ecx // call r, mems := loadArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, ECX, OMem(MReg(EDX, 4)), 0 - 1, $ghost_s__abs, r.regs[EDX]); // // // Adjust to the "beginning" of the values we care about // ecx := ecx - 1; // call edi := Load(stk, esp + 16); // grab si // ecx := ecx - edi; // var sii:int := ecx; // assert sii == Arr_Length($ghost_s) - 1 - $ghost_si; // // // Convert sii into a memory pointer // call arrayElementProperties(core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, sii, $ghost_s__abs, edx); // Proves we're within bounds for the Lea calculation // call ecx := Lea(edx + 4 * ecx + 8); // var sii_ptr @ ecx; // // /////////////// Start computing ////////////////////////// // // // First, "load" c_in into CF via a sneaky addition // call edi := Load(stk, esp + 20); // grab c_in // assert edi == $ghost_c_in; // call r := instr_Add(r, EDI, OConst(0xffffffff)); // assert Cf(r.efl) == ($ghost_c_in == 1); // // // Build the carries sequence // $ghost_carries := fun_Seq__Build___int(fun_Seq__Empty___int(), $ghost_c_in); // // var carry:int; // // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd8(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, 0)), OMem(MReg(EAX, (-4))), OMem(MReg(EAX, (-8))), OMem(MReg(EAX, (-12))), // OMem(MReg(EAX, (-16))), OMem(MReg(EAX, (-20))), OMem(MReg(EAX, (-24))), OMem(MReg(EAX, (-28))), // $ghost_a__abs, a_base, // aii-0, aii-1, aii-2, aii-3, // aii-4, aii-5, aii-6, aii-7, // OMem(MReg(EBX, 0)), OMem(MReg(EBX, (-4))), OMem(MReg(EBX, (-8))), OMem(MReg(EBX, (-12))), // OMem(MReg(EBX, (-16))), OMem(MReg(EBX, (-20))), OMem(MReg(EBX, (-24))), OMem(MReg(EBX, (-28))), // $ghost_b__abs, b_base, // bii-0, bii-1, bii-2, bii-3, // bii-4, bii-5, bii-6, bii-7, // OMem(MReg(ECX, 0)), OMem(MReg(ECX, (-4))), OMem(MReg(ECX, (-8))), OMem(MReg(ECX, (-12))), // OMem(MReg(ECX, (-16))), OMem(MReg(ECX, (-20))), OMem(MReg(ECX, (-24))), OMem(MReg(ECX, (-28))), // $ghost_s__abs, s_base, // sii-0, sii-1, sii-2, sii-3, // sii-4, sii-5, sii-6, sii-7, // $ghost_si, 0, (-1), (-2), (-3), (-4), (-5), (-6), (-7), $ghost_carries, $ghost_c_in); // // assert (forall $ghost__1_i:int :: {fun_INTERNAL__array__elems__index($absMem[$ghost_a.arrAbs], (fun_FatNatAddIndex((Arr_Length($ghost_a)), $ghost_ai, $ghost__1_i)))} TV($ghost__1_i) ==> ((INTERNAL_le_boogie(0, $ghost__1_i)) && (INTERNAL_lt_boogie($ghost__1_i, 8))) ==> ((fun_Seq__Index___int($ghost_carries, INTERNAL_add_boogie($ghost__1_i, 1))) == ((if (INTERNAL_ge_boogie(INTERNAL_add_boogie(INTERNAL_add_boogie(fun_INTERNAL__array__elems__index($absMem[$ghost_a.arrAbs], (fun_FatNatAddIndex((Arr_Length($ghost_a)), $ghost_ai, $ghost__1_i))), fun_INTERNAL__array__elems__index($absMem[$ghost_b.arrAbs], (fun_FatNatAddIndex((Arr_Length($ghost_b)), $ghost_bi, $ghost__1_i)))), fun_Seq__Index___int($ghost_carries, $ghost__1_i)), 4294967296)) then (1) else (0))))); // // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd8(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-32))), OMem(MReg(EAX, (-36))), OMem(MReg(EAX, (-40))), OMem(MReg(EAX, (-44))), // OMem(MReg(EAX, (-48))), OMem(MReg(EAX, (-52))), OMem(MReg(EAX, (-56))), OMem(MReg(EAX, (-60))), // $ghost_a__abs, a_base, // aii-8, aii-9, aii-10, aii-11, // aii-12, aii-13, aii-14, aii-15, // OMem(MReg(EBX, (-32))), OMem(MReg(EBX, (-36))), OMem(MReg(EBX, (-40))), OMem(MReg(EBX, (-44))), // OMem(MReg(EBX, (-48))), OMem(MReg(EBX, (-52))), OMem(MReg(EBX, (-56))), OMem(MReg(EBX, (-60))), // $ghost_b__abs, b_base, // bii-8, bii-9, bii-10, bii-11, // bii-12, bii-13, bii-14, bii-15, // OMem(MReg(ECX, (-32))), OMem(MReg(ECX, (-36))), OMem(MReg(ECX, (-40))), OMem(MReg(ECX, (-44))), // OMem(MReg(ECX, (-48))), OMem(MReg(ECX, (-52))), OMem(MReg(ECX, (-56))), OMem(MReg(ECX, (-60))), // $ghost_s__abs, s_base, // sii-8, sii-9, sii-10, sii-11, // sii-12, sii-13, sii-14, sii-15, // $ghost_si, (-8), (-9), (-10), (-11), (-12), (-13), (-14), (-15), $ghost_carries, carry); // // assert (forall $ghost__1_i:int :: {fun_INTERNAL__array__elems__index($absMem[$ghost_a.arrAbs], (fun_FatNatAddIndex((Arr_Length($ghost_a)), $ghost_ai, $ghost__1_i)))} TV($ghost__1_i) ==> ((INTERNAL_le_boogie(0, $ghost__1_i)) && (INTERNAL_lt_boogie($ghost__1_i, 16))) ==> ((fun_Seq__Index___int($ghost_carries, INTERNAL_add_boogie($ghost__1_i, 1))) == ((if (INTERNAL_ge_boogie(INTERNAL_add_boogie(INTERNAL_add_boogie(fun_INTERNAL__array__elems__index($absMem[$ghost_a.arrAbs], (fun_FatNatAddIndex((Arr_Length($ghost_a)), $ghost_ai, $ghost__1_i))), fun_INTERNAL__array__elems__index($absMem[$ghost_b.arrAbs], (fun_FatNatAddIndex((Arr_Length($ghost_b)), $ghost_bi, $ghost__1_i)))), fun_Seq__Index___int($ghost_carries, $ghost__1_i)), 4294967296)) then (1) else (0))))); // // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd8(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-64))), OMem(MReg(EAX, (-68))), OMem(MReg(EAX, (-72))), OMem(MReg(EAX, (-76))), // OMem(MReg(EAX, (-80))), OMem(MReg(EAX, (-84))), OMem(MReg(EAX, (-88))), OMem(MReg(EAX, (-92))), // $ghost_a__abs, a_base, // aii-16, aii-17, aii-18, aii-19, // aii-20, aii-21, aii-22, aii-23, // OMem(MReg(EBX, (-64))), OMem(MReg(EBX, (-68))), OMem(MReg(EBX, (-72))), OMem(MReg(EBX, (-76))), // OMem(MReg(EBX, (-80))), OMem(MReg(EBX, (-84))), OMem(MReg(EBX, (-88))), OMem(MReg(EBX, (-92))), // $ghost_b__abs, b_base, // bii-16, bii-17, bii-18, bii-19, // bii-20, bii-21, bii-22, bii-23, // OMem(MReg(ECX, (-64))), OMem(MReg(ECX, (-68))), OMem(MReg(ECX, (-72))), OMem(MReg(ECX, (-76))), // OMem(MReg(ECX, (-80))), OMem(MReg(ECX, (-84))), OMem(MReg(ECX, (-88))), OMem(MReg(ECX, (-92))), // $ghost_s__abs, s_base, // sii-16, sii-17, sii-18, sii-19, // sii-20, sii-21, sii-22, sii-23, // $ghost_si, (-16), (-17), (-18), (-19), (-20), (-21), (-22), (-23), $ghost_carries, carry); // // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd8(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-96))), OMem(MReg(EAX, (-100))), OMem(MReg(EAX, (-104))), OMem(MReg(EAX, (-108))), // OMem(MReg(EAX, (-112))), OMem(MReg(EAX, (-116))), OMem(MReg(EAX, (-120))), OMem(MReg(EAX, (-124))), // $ghost_a__abs, a_base, // aii-24, aii-25, aii-26, aii-27, // aii-28, aii-29, aii-30, aii-31, // OMem(MReg(EBX, (-96))), OMem(MReg(EBX, (-100))), OMem(MReg(EBX, (-104))), OMem(MReg(EBX, (-108))), // OMem(MReg(EBX, (-112))), OMem(MReg(EBX, (-116))), OMem(MReg(EBX, (-120))), OMem(MReg(EBX, (-124))), // $ghost_b__abs, b_base, // bii-24, bii-25, bii-26, bii-27, // bii-28, bii-29, bii-30, bii-31, // OMem(MReg(ECX, (-96))), OMem(MReg(ECX, (-100))), OMem(MReg(ECX, (-104))), OMem(MReg(ECX, (-108))), // OMem(MReg(ECX, (-112))), OMem(MReg(ECX, (-116))), OMem(MReg(ECX, (-120))), OMem(MReg(ECX, (-124))), // $ghost_s__abs, s_base, // sii-24, sii-25, sii-26, sii-27, // sii-28, sii-29, sii-30, sii-31, // $ghost_si, (-24), (-25), (-26), (-27), (-28), (-29), (-30), (-31), $ghost_carries, carry); // // assert (forall $ghost__1_i:int :: {fun_INTERNAL__array__elems__index($absMem[$ghost_a.arrAbs], (fun_FatNatAddIndex((Arr_Length($ghost_a)), $ghost_ai, $ghost__1_i)))} TV($ghost__1_i) ==> ((INTERNAL_le_boogie(0, $ghost__1_i)) && (INTERNAL_lt_boogie($ghost__1_i, 32))) ==> ((fun_Seq__Index___int($ghost_carries, INTERNAL_add_boogie($ghost__1_i, 1))) == ((if (INTERNAL_ge_boogie(INTERNAL_add_boogie(INTERNAL_add_boogie(fun_INTERNAL__array__elems__index($absMem[$ghost_a.arrAbs], (fun_FatNatAddIndex((Arr_Length($ghost_a)), $ghost_ai, $ghost__1_i))), fun_INTERNAL__array__elems__index($absMem[$ghost_b.arrAbs], (fun_FatNatAddIndex((Arr_Length($ghost_b)), $ghost_bi, $ghost__1_i)))), fun_Seq__Index___int($ghost_carries, $ghost__1_i)), 4294967296)) then (1) else (0))))); // ///* // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd4(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, 0)), OMem(MReg(EAX, (-4))), OMem(MReg(EAX, (-8))), OMem(MReg(EAX, (-12))), // $ghost_a__abs, a_base, // aii-0, aii-1, aii-2, aii-3, // OMem(MReg(EBX, 0)), OMem(MReg(EBX, (-4))), OMem(MReg(EBX, (-8))), OMem(MReg(EBX, (-12))), // $ghost_b__abs, b_base, // bii-0, bii-1, bii-2, bii-3, // OMem(MReg(ECX, 0)), OMem(MReg(ECX, (-4))), OMem(MReg(ECX, (-8))), OMem(MReg(ECX, (-12))), // $ghost_s__abs, s_base, // sii-0, sii-1, sii-2, sii-3, // $ghost_si, 0, (-1), (-2), (-3), $ghost_carries, $ghost_c_in); // // assert (forall $ghost__1_i:int :: {fun_INTERNAL__array__elems__index($absMem[$ghost_a.arrAbs], (fun_FatNatAddIndex((Arr_Length($ghost_a)), $ghost_ai, $ghost__1_i)))} ((INTERNAL_le_boogie(0, $ghost__1_i)) && (INTERNAL_lt_boogie($ghost__1_i, 4))) ==> ((fun_Seq__Index___int($ghost_carries, INTERNAL_add_boogie($ghost__1_i, 1))) == ((if (INTERNAL_ge_boogie(INTERNAL_add_boogie(INTERNAL_add_boogie(fun_INTERNAL__array__elems__index($absMem[$ghost_a.arrAbs], (fun_FatNatAddIndex((Arr_Length($ghost_a)), $ghost_ai, $ghost__1_i))), fun_INTERNAL__array__elems__index($absMem[$ghost_b.arrAbs], (fun_FatNatAddIndex((Arr_Length($ghost_b)), $ghost_bi, $ghost__1_i)))), fun_Seq__Index___int($ghost_carries, $ghost__1_i)), 4294967296)) then (1) else (0))))); // // // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd4(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-16))), OMem(MReg(EAX, (-20))), OMem(MReg(EAX, (-24))), OMem(MReg(EAX, (-28))), // $ghost_a__abs, a_base, // aii-4, aii-5, aii-6, aii-7, // OMem(MReg(EBX, (-16))), OMem(MReg(EBX, (-20))), OMem(MReg(EBX, (-24))), OMem(MReg(EBX, (-28))), // $ghost_b__abs, b_base, // bii-4, bii-5, bii-6, bii-7, // OMem(MReg(ECX, (-16))), OMem(MReg(ECX, (-20))), OMem(MReg(ECX, (-24))), OMem(MReg(ECX, (-28))), // $ghost_s__abs, s_base, // sii-4, sii-5, sii-6, sii-7, // $ghost_si, (-4), (-5), (-6), (-7), $ghost_carries, carry); // // assert (forall $ghost__1_i:int :: {fun_INTERNAL__array__elems__index($absMem[$ghost_a.arrAbs], (fun_FatNatAddIndex((Arr_Length($ghost_a)), $ghost_ai, $ghost__1_i)))} ((INTERNAL_le_boogie(0, $ghost__1_i)) && (INTERNAL_lt_boogie($ghost__1_i, 8))) ==> ((fun_Seq__Index___int($ghost_carries, INTERNAL_add_boogie($ghost__1_i, 1))) == ((if (INTERNAL_ge_boogie(INTERNAL_add_boogie(INTERNAL_add_boogie(fun_INTERNAL__array__elems__index($absMem[$ghost_a.arrAbs], (fun_FatNatAddIndex((Arr_Length($ghost_a)), $ghost_ai, $ghost__1_i))), fun_INTERNAL__array__elems__index($absMem[$ghost_b.arrAbs], (fun_FatNatAddIndex((Arr_Length($ghost_b)), $ghost_bi, $ghost__1_i)))), fun_Seq__Index___int($ghost_carries, $ghost__1_i)), 4294967296)) then (1) else (0))))); // // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd4(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-32))), OMem(MReg(EAX, (-36))), OMem(MReg(EAX, (-40))), OMem(MReg(EAX, (-44))), // $ghost_a__abs, a_base, // aii-8, aii-9, aii-10, aii-11, // OMem(MReg(EBX, (-32))), OMem(MReg(EBX, (-36))), OMem(MReg(EBX, (-40))), OMem(MReg(EBX, (-44))), // $ghost_b__abs, b_base, // bii-8, bii-9, bii-10, bii-11, // OMem(MReg(ECX, (-32))), OMem(MReg(ECX, (-36))), OMem(MReg(ECX, (-40))), OMem(MReg(ECX, (-44))), // $ghost_s__abs, s_base, // sii-8, sii-9, sii-10, sii-11, // $ghost_si, (-8), (-9), (-10), (-11), $ghost_carries, carry); // // assert (forall $ghost__1_i:int :: {fun_INTERNAL__array__elems__index($absMem[$ghost_a.arrAbs], (fun_FatNatAddIndex((Arr_Length($ghost_a)), $ghost_ai, $ghost__1_i)))} ((INTERNAL_le_boogie(0, $ghost__1_i)) && (INTERNAL_lt_boogie($ghost__1_i, 12))) ==> ((fun_Seq__Index___int($ghost_carries, INTERNAL_add_boogie($ghost__1_i, 1))) == ((if (INTERNAL_ge_boogie(INTERNAL_add_boogie(INTERNAL_add_boogie(fun_INTERNAL__array__elems__index($absMem[$ghost_a.arrAbs], (fun_FatNatAddIndex((Arr_Length($ghost_a)), $ghost_ai, $ghost__1_i))), fun_INTERNAL__array__elems__index($absMem[$ghost_b.arrAbs], (fun_FatNatAddIndex((Arr_Length($ghost_b)), $ghost_bi, $ghost__1_i)))), fun_Seq__Index___int($ghost_carries, $ghost__1_i)), 4294967296)) then (1) else (0))))); // // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd4(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-48))), OMem(MReg(EAX, (-52))), OMem(MReg(EAX, (-56))), OMem(MReg(EAX, (-60))), // $ghost_a__abs, a_base, // aii-12, aii-13, aii-14, aii-15, // OMem(MReg(EBX, (-48))), OMem(MReg(EBX, (-52))), OMem(MReg(EBX, (-56))), OMem(MReg(EBX, (-60))), // $ghost_b__abs, b_base, // bii-12, bii-13, bii-14, bii-15, // OMem(MReg(ECX, (-48))), OMem(MReg(ECX, (-52))), OMem(MReg(ECX, (-56))), OMem(MReg(ECX, (-60))), // $ghost_s__abs, s_base, // sii-12, sii-13, sii-14, sii-15, // $ghost_si, (-12), (-13), (-14), (-15), $ghost_carries, carry); // // assert (forall $ghost__1_i:int :: {fun_INTERNAL__array__elems__index($absMem[$ghost_a.arrAbs], (fun_FatNatAddIndex((Arr_Length($ghost_a)), $ghost_ai, $ghost__1_i)))} ((INTERNAL_le_boogie(0, $ghost__1_i)) && (INTERNAL_lt_boogie($ghost__1_i, 16))) ==> ((fun_Seq__Index___int($ghost_carries, INTERNAL_add_boogie($ghost__1_i, 1))) == ((if (INTERNAL_ge_boogie(INTERNAL_add_boogie(INTERNAL_add_boogie(fun_INTERNAL__array__elems__index($absMem[$ghost_a.arrAbs], (fun_FatNatAddIndex((Arr_Length($ghost_a)), $ghost_ai, $ghost__1_i))), fun_INTERNAL__array__elems__index($absMem[$ghost_b.arrAbs], (fun_FatNatAddIndex((Arr_Length($ghost_b)), $ghost_bi, $ghost__1_i)))), fun_Seq__Index___int($ghost_carries, $ghost__1_i)), 4294967296)) then (1) else (0))))); // // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd4(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-64))), OMem(MReg(EAX, (-68))), OMem(MReg(EAX, (-72))), OMem(MReg(EAX, (-76))), // $ghost_a__abs, a_base, // aii-16, aii-17, aii-18, aii-19, // OMem(MReg(EBX, (-64))), OMem(MReg(EBX, (-68))), OMem(MReg(EBX, (-72))), OMem(MReg(EBX, (-76))), // $ghost_b__abs, b_base, // bii-16, bii-17, bii-18, bii-19, // OMem(MReg(ECX, (-64))), OMem(MReg(ECX, (-68))), OMem(MReg(ECX, (-72))), OMem(MReg(ECX, (-76))), // $ghost_s__abs, s_base, // sii-16, sii-17, sii-18, sii-19, // $ghost_si, (-16), (-17), (-18), (-19), $ghost_carries, carry); // // assert (forall $ghost__1_i:int :: {fun_INTERNAL__array__elems__index($absMem[$ghost_a.arrAbs], (fun_FatNatAddIndex((Arr_Length($ghost_a)), $ghost_ai, $ghost__1_i)))} ((INTERNAL_le_boogie(0, $ghost__1_i)) && (INTERNAL_lt_boogie($ghost__1_i, 20))) ==> ((fun_Seq__Index___int($ghost_carries, INTERNAL_add_boogie($ghost__1_i, 1))) == ((if (INTERNAL_ge_boogie(INTERNAL_add_boogie(INTERNAL_add_boogie(fun_INTERNAL__array__elems__index($absMem[$ghost_a.arrAbs], (fun_FatNatAddIndex((Arr_Length($ghost_a)), $ghost_ai, $ghost__1_i))), fun_INTERNAL__array__elems__index($absMem[$ghost_b.arrAbs], (fun_FatNatAddIndex((Arr_Length($ghost_b)), $ghost_bi, $ghost__1_i)))), fun_Seq__Index___int($ghost_carries, $ghost__1_i)), 4294967296)) then (1) else (0))))); // // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd4(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-80))), OMem(MReg(EAX, (-84))), OMem(MReg(EAX, (-88))), OMem(MReg(EAX, (-92))), // $ghost_a__abs, a_base, // aii-20, aii-21, aii-22, aii-23, // OMem(MReg(EBX, (-80))), OMem(MReg(EBX, (-84))), OMem(MReg(EBX, (-88))), OMem(MReg(EBX, (-92))), // $ghost_b__abs, b_base, // bii-20, bii-21, bii-22, bii-23, // OMem(MReg(ECX, (-80))), OMem(MReg(ECX, (-84))), OMem(MReg(ECX, (-88))), OMem(MReg(ECX, (-92))), // $ghost_s__abs, s_base, // sii-20, sii-21, sii-22, sii-23, // $ghost_si, (-20), (-21), (-22), (-23), $ghost_carries, carry); // // assert (forall $ghost__1_i:int :: {fun_INTERNAL__array__elems__index($absMem[$ghost_a.arrAbs], (fun_FatNatAddIndex((Arr_Length($ghost_a)), $ghost_ai, $ghost__1_i)))} ((INTERNAL_le_boogie(0, $ghost__1_i)) && (INTERNAL_lt_boogie($ghost__1_i, 24))) ==> ((fun_Seq__Index___int($ghost_carries, INTERNAL_add_boogie($ghost__1_i, 1))) == ((if (INTERNAL_ge_boogie(INTERNAL_add_boogie(INTERNAL_add_boogie(fun_INTERNAL__array__elems__index($absMem[$ghost_a.arrAbs], (fun_FatNatAddIndex((Arr_Length($ghost_a)), $ghost_ai, $ghost__1_i))), fun_INTERNAL__array__elems__index($absMem[$ghost_b.arrAbs], (fun_FatNatAddIndex((Arr_Length($ghost_b)), $ghost_bi, $ghost__1_i)))), fun_Seq__Index___int($ghost_carries, $ghost__1_i)), 4294967296)) then (1) else (0))))); // // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd4(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-96))), OMem(MReg(EAX, (-100))), OMem(MReg(EAX, (-104))), OMem(MReg(EAX, (-108))), // $ghost_a__abs, a_base, // aii-24, aii-25, aii-26, aii-27, // OMem(MReg(EBX, (-96))), OMem(MReg(EBX, (-100))), OMem(MReg(EBX, (-104))), OMem(MReg(EBX, (-108))), // $ghost_b__abs, b_base, // bii-24, bii-25, bii-26, bii-27, // OMem(MReg(ECX, (-96))), OMem(MReg(ECX, (-100))), OMem(MReg(ECX, (-104))), OMem(MReg(ECX, (-108))), // $ghost_s__abs, s_base, // sii-24, sii-25, sii-26, sii-27, // $ghost_si, (-24), (-25), (-26), (-27), $ghost_carries, carry); // // assert (forall $ghost__1_i:int :: {fun_INTERNAL__array__elems__index($absMem[$ghost_a.arrAbs], (fun_FatNatAddIndex((Arr_Length($ghost_a)), $ghost_ai, $ghost__1_i)))} ((INTERNAL_le_boogie(0, $ghost__1_i)) && (INTERNAL_lt_boogie($ghost__1_i, 28))) ==> ((fun_Seq__Index___int($ghost_carries, INTERNAL_add_boogie($ghost__1_i, 1))) == ((if (INTERNAL_ge_boogie(INTERNAL_add_boogie(INTERNAL_add_boogie(fun_INTERNAL__array__elems__index($absMem[$ghost_a.arrAbs], (fun_FatNatAddIndex((Arr_Length($ghost_a)), $ghost_ai, $ghost__1_i))), fun_INTERNAL__array__elems__index($absMem[$ghost_b.arrAbs], (fun_FatNatAddIndex((Arr_Length($ghost_b)), $ghost_bi, $ghost__1_i)))), fun_Seq__Index___int($ghost_carries, $ghost__1_i)), 4294967296)) then (1) else (0))))); // // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, carry, $ghost_carries := // arrayAdd4(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, // $ghost_a, $ghost_b, $ghost_s, // OMem(MReg(EAX, (-112))), OMem(MReg(EAX, (-116))), OMem(MReg(EAX, (-120))), OMem(MReg(EAX, (-124))), // $ghost_a__abs, a_base, // aii-28, aii-29, aii-30, aii-31, // OMem(MReg(EBX, (-112))), OMem(MReg(EBX, (-116))), OMem(MReg(EBX, (-120))), OMem(MReg(EBX, (-124))), // $ghost_b__abs, b_base, // bii-28, bii-29, bii-30, bii-31, // OMem(MReg(ECX, (-112))), OMem(MReg(ECX, (-116))), OMem(MReg(ECX, (-120))), OMem(MReg(ECX, (-124))), // $ghost_s__abs, s_base, // sii-28, sii-29, sii-30, sii-31, // $ghost_si, (-28), (-29), (-30), (-31), $ghost_carries, carry); // // assert (forall $ghost__1_i:int :: {fun_INTERNAL__array__elems__index($absMem[$ghost_a.arrAbs], (fun_FatNatAddIndex((Arr_Length($ghost_a)), $ghost_ai, $ghost__1_i)))} ((INTERNAL_le_boogie(0, $ghost__1_i)) && (INTERNAL_lt_boogie($ghost__1_i, 32))) ==> ((fun_Seq__Index___int($ghost_carries, INTERNAL_add_boogie($ghost__1_i, 1))) == ((if (INTERNAL_ge_boogie(INTERNAL_add_boogie(INTERNAL_add_boogie(fun_INTERNAL__array__elems__index($absMem[$ghost_a.arrAbs], (fun_FatNatAddIndex((Arr_Length($ghost_a)), $ghost_ai, $ghost__1_i))), fun_INTERNAL__array__elems__index($absMem[$ghost_b.arrAbs], (fun_FatNatAddIndex((Arr_Length($ghost_b)), $ghost_bi, $ghost__1_i)))), fun_Seq__Index___int($ghost_carries, $ghost__1_i)), 4294967296)) then (1) else (0))))); //*/ // // Extract the final carry bit from EFL // eax := 0; // call r := instr_GetCf(r, EAX); // assert Aligned(esp); // assert Aligned(esp + 4); // call Store(inout stk, esp + 4, eax); // $ghost_c_out := carry; // // assert $ghost_a.arrAbs != $ghost_s.arrAbs; // // Return; //} } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Main/dafny_FleetNatMulLoopOpt_i.imp.beat ================================================ //-private-import BaseSpec; //-private-import MemorySpec; //-private-import IoTypesSpec; //-private-import MachineStateSpec; //-private-import AssemblySpec; //-private-import InterruptsSpec; //-private-import IoSpec; //-private-import Overflow; //-private-import Core; //-private-import LogicalAddressing; //-private-import Util; //-private-import Stacks; //-private-import Partition; //-private-import Instructions; //-private-import Separation; //-private-import IntLemmasGc; //-private-import SimpleGcMemory; //-private-import SimpleCommon; //-private-import SimpleCollector; //-private-import IntLemmasMain; //-private-import IntLemmasBase; //-private-import IoMain; //-private-basmonly-import Trusted; //-private-basmonly-import Checked; //-private-import Heap; //-private-import Seq; //-private-import dafny_DafnyPrelude; //-private-import DafnyAssembly; //-private-import dafny_base_s; //-private-import dafny_power2_s; //-private-import dafny_bytes_and_words_s; //-private-import dafny_be_sequences_s; //-private-import dafny_integer_sequences_s; //-private-import dafny_seqs_simple_i; //-private-import dafny_power_s; //-private-import dafny_mul_nonlinear_i; //-private-import dafny_mul_i; //-private-import dafny_power_i; //-private-import dafny_div_def_i; //-private-import dafny_div_boogie_i; //-private-import dafny_div_nonlinear_i; //-private-import dafny_div_i; //-private-import dafny_repeat_digit_i; //-private-import dafny_assembly_s; //-private-import dafny_power2_i; //-private-import dafny_seqs_and_ints_i; //-private-import dafny_seqs_common_i; //-private-import dafny_Word32_i; //-private-import dafny_relational_s; //-private-import dafny_assembly_i; //-private-import dafny_arrays_i; //-private-import dafny_seqs_transforms_i; //-private-import dafny_seqs_reverse_i; //-private-import dafny_integer_sequences_i; //-private-import dafny_integer_sequences_premium_i; //-private-import dafny_assembly_premium_i; //-private-import dafny_BigNatX86Shim_i; //-private-import dafny_seqs_canonical_i; //-private-import dafny_CanonicalArrays_i; //-private-import dafny_FatNatCommon_i; //-private-import dafny_FleetNatCommon_i; //-private-import dafny_FleetNatAdd_i; //-private-import dafny_FleetNatMulLemmas_i; //-private-import dafny_FleetNatMulOpt_i; //-private-import dafny_FleetNatMulLoopOptLemmas_i; //- //- //- //- //- module implementation dafny_FleetNatMulLoopOpt_i { implementation Proc_FleetNatMul__one__loop__opt(my r_old:regs, const my core_state:core_state, linear stk_old:mem, linear statics_old:mem, linear io_old:IOState, linear mems_old:mems, $commonVars_old:commonVars, $gcVars_old:gcVars, $toAbs_old:[int]int, $absMem_old:[int][int]int, $stacksFrames_old:[int]Frames, objLayouts_old:[int]ObjLayout, heap_old:Heap, $ghost_c:ArrayOfInt, $ghost_bi:int, $ghost_a:ArrayOfInt, $ghost_adigits:int, $ghost_bv:int) returns(my r:regs, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars, $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap, $ghost_carry:int) { //- Standard boilerplate var $absMem_tmp:[int][int]int; var objLayouts_tmp:[int]ObjLayout; var heap_tmp:Heap; var obj_tmp:int; var val_tmp:int; var mod0:int; var $ghost_pv:int; var $ghost_oldcs:Seq___int; var $ghost_alenm1:int; var $ghost__temp__0:int; var $ghost_clenm1:int; var $ghost__temp__1:int; var $ghost_j:int; var $ghost_lastj:int; var $ghost_lastcarry:int; var $ghost_lastcs:Seq___int; var $ghost_asq:Seq___int; var $ghost_ci:int; var $ghost__temp__5:int; var $ghost__temp__6:int; var $ghost_ai:int; var $ghost_aj:int; var $ghost_lastcj:int; var $ghost_newcj:int; var $ghost_c__abs:int; var $ghost_a__abs:int; var a_base:int; var c_base:int; var old_esi:int; var old_edi:int; var $ghost_mhi:int; var $ghost_mlo:int; var $ghost__temp__0:int; var $ghost_add1:int; var $ghost_carry1:int; var $ghost_carry2:int; var $ghost_add3:int; var $ghost_carry3:int; var $ghost_carry4:int; var tmp:int; assert fun_unroll(0); assert fun_unroll(1); call lemma_unroll_rec_fun____HASH_Seq__Length__FULL___int(); call lemma_unroll_fun____HASH_Seq__Length__FULL___int(); call lemma_fun_ensures_fun_Seq__Length___int(); call lemma_unroll_rec_fun____HASH_Seq__Build__FULL___int(); call lemma_unroll_fun____HASH_Seq__Build__FULL___int(); call lemma_unroll_rec_fun____HASH_Seq__Index__FULL___int(); call lemma_unroll_fun____HASH_Seq__Index__FULL___int(); call lemma_unroll_rec_fun____HASH_Seq__Append__FULL___int(); call lemma_unroll_fun____HASH_Seq__Append__FULL___int(); call lemma_unroll_rec_fun____HASH_Seq__Update__FULL___int(); call lemma_unroll_fun____HASH_Seq__Update__FULL___int(); call lemma_unroll_rec_fun____HASH_Seq__Take__FULL___int(); call lemma_unroll_fun____HASH_Seq__Take__FULL___int(); call lemma_unroll_rec_fun____HASH_Seq__Drop__FULL___int(); call lemma_unroll_fun____HASH_Seq__Drop__FULL___int(); call proc_Seq__Empty__ToZero___int(); call proc_Seq__Empty__FromZero___int(); call proc_Seq__Singleton__Length___int(); call proc_Seq__Build__Length___int(); call proc_Seq__Build__Index___int(); call proc_Seq__Append__Length___int(); call proc_Seq__Index__Singleton___int(); call proc_Seq__Append__Index___int(); call proc_Seq__Update__Length___int(); call proc_Seq__Index__Update___int(); call proc_Seq__Equal__Equiv___int(); call proc_Seq__Take__Length___int(); call proc_Seq__Take__Index___int(); call proc_Seq__Drop__Length___int(); call proc_Seq__Drop__Index___int(); call proc_Seq__Append__TakeDrop___int(); call proc_Seq__Update__CommuteTake1___int(); call proc_Seq__Update__CommuteTake2___int(); call proc_Seq__Update__CommuteDrop1___int(); call proc_Seq__Update__CommuteDrop2___int(); call proc_Seq__Build__CommuteDrop___int(); call proc_Seq__Take__Empty___int(); call proc_Seq__Drop__Empty___int(); call lemma_unroll_fun_Seq__FromArrayRange(); call proc_Seq__FromArray__Length(); call proc_Seq__FromArray__Index(); call proc_Seq__FromArray__Update(); call lemma_unroll_rec_fun____HASH_power2__FULL(); call lemma_unroll_fun____HASH_power2__FULL(); call lemma_fun_ensures_fun_power2(); call lemma_unroll_rec_fun____HASH_BEDigitSeqToInt__private__FULL(); call lemma_unroll_fun____HASH_BEDigitSeqToInt__private__FULL(); call lemma_unroll_rec_fun____HASH_BEIntToDigitSeq__private__FULL(); call lemma_unroll_fun____HASH_BEIntToDigitSeq__private__FULL(); call lemma_unroll_rec_fun_RepeatDigit(); call lemma_unroll_fun_RepeatDigit(); call lemma_unroll_rec_fun____HASH_Reverse__FULL(); call lemma_unroll_fun____HASH_Reverse__FULL(); call lemma_unroll_rec_fun____HASH_power__FULL(); call lemma_unroll_fun____HASH_power__FULL(); call lemma_unroll_rec_fun_mul__pos(); call lemma_unroll_fun_mul__pos(); call lemma_unroll_rec_fun_my__div__pos(); call lemma_unroll_fun_my__div__pos(); call lemma_unroll_rec_fun_my__mod__recursive(); call lemma_unroll_fun_my__mod__recursive(); call lemma_fun_ensures_fun_RepeatDigit__premium(); call lemma_unroll_rec_fun____HASH_SequenceOfZeros__FULL(); call lemma_unroll_fun____HASH_SequenceOfZeros__FULL(); call lemma_fun_ensures_fun_SequenceOfZeros(); call lemma_fun_ensures_fun_BitwiseAnd(); call lemma_fun_ensures_fun_BitwiseOr(); call lemma_fun_ensures_fun_BitwiseNot(); call lemma_fun_ensures_fun_BitwiseXor(); call lemma_fun_ensures_fun_RotateRight(); call lemma_fun_ensures_fun_RotateLeft(); call lemma_fun_ensures_fun_RightShift(); call lemma_fun_ensures_fun_LeftShift(); call lemma_fun_ensures_fun_Add32(); call lemma_fun_ensures_fun_Sub32(); call lemma_fun_ensures_fun_Mul32(); call lemma_fun_ensures_fun_Div32(); call lemma_fun_ensures_fun_Mod32(); call lemma_unroll_rec_fun____HASH_NatNumBits__FULL(); call lemma_unroll_fun____HASH_NatNumBits__FULL(); call lemma_fun_ensures_fun_NatNumBits(); call lemma_fun_ensures_fun_asm__Add(); call lemma_fun_ensures_fun_asm__Sub(); call lemma_fun_ensures_fun_asm__Mul(); call lemma_fun_ensures_fun_asm__Div(); call lemma_fun_ensures_fun_asm__Mod(); call lemma_fun_ensures_fun_asm__LeftShift(); call lemma_fun_ensures_fun_asm__RightShift(); call lemma_fun_ensures_fun_asm__RotateLeft(); call lemma_fun_ensures_fun_asm__RotateRight(); call lemma_fun_ensures_fun_asm__BitwiseNot(); call lemma_fun_ensures_fun_asm__BitwiseAnd(); call lemma_fun_ensures_fun_asm__BitwiseOr(); call lemma_fun_ensures_fun_asm__BitwiseXor(); call lemma_unroll_rec_fun____HASH_LEDigitSeqToInt__private__FULL(); call lemma_unroll_fun____HASH_LEDigitSeqToInt__private__FULL(); call lemma_fun_ensures_fun_BEDigitSeqToInt__premium(); call lemma_fun_ensures_fun_BEWordSeqToInt__premium(); call lemma_fun_ensures_fun_BEIntToDigitSeq__premium(); call lemma_fun_ensures_fun_BEIntToByteSeq__premium(); call lemma_fun_ensures_fun_BEWordToFourBytes__premium(); call lemma_fun_ensures_fun_BEWordToBitSeq__premium(); call lemma_fun_ensures_fun_BEWordSeqToBitSeq__premium(); call lemma_fun_ensures_fun_BEByteSeqToBitSeq__premium(); call lemma_fun_ensures_fun_BEWordSeqToByteSeq__premium(); call lemma_fun_ensures_fun_Asm__Add(); call lemma_fun_ensures_fun_Asm__Sub(); call lemma_fun_ensures_fun_Asm__Mul(); call lemma_fun_ensures_fun_Asm__Div(); call lemma_fun_ensures_fun_Asm__Mod(); call lemma_fun_ensures_fun_Asm__LeftShift(); call lemma_fun_ensures_fun_Asm__RightShift(); call lemma_fun_ensures_fun_Asm__RotateLeft(); call lemma_fun_ensures_fun_Asm__RotateRight(); call lemma_fun_ensures_fun_Asm__BitwiseNot(); call lemma_fun_ensures_fun_Asm__BitwiseAnd(); call lemma_fun_ensures_fun_Asm__BitwiseOr(); call lemma_fun_ensures_fun_Asm__BitwiseXor(); call lemma_unroll_rec_fun____HASH_Seq__Length__FULL___Seq___int(); call lemma_unroll_fun____HASH_Seq__Length__FULL___Seq___int(); call lemma_fun_ensures_fun_Seq__Length___Seq___int(); call lemma_unroll_rec_fun____HASH_Seq__Build__FULL___Seq___int(); call lemma_unroll_fun____HASH_Seq__Build__FULL___Seq___int(); call lemma_unroll_rec_fun____HASH_Seq__Index__FULL___Seq___int(); call lemma_unroll_fun____HASH_Seq__Index__FULL___Seq___int(); call lemma_unroll_rec_fun____HASH_Seq__Append__FULL___Seq___int(); call lemma_unroll_fun____HASH_Seq__Append__FULL___Seq___int(); call lemma_unroll_rec_fun____HASH_Seq__Update__FULL___Seq___int(); call lemma_unroll_fun____HASH_Seq__Update__FULL___Seq___int(); call lemma_unroll_rec_fun____HASH_Seq__Take__FULL___Seq___int(); call lemma_unroll_fun____HASH_Seq__Take__FULL___Seq___int(); call lemma_unroll_rec_fun____HASH_Seq__Drop__FULL___Seq___int(); call lemma_unroll_fun____HASH_Seq__Drop__FULL___Seq___int(); call proc_Seq__Empty__ToZero___Seq___int(); call proc_Seq__Empty__FromZero___Seq___int(); call proc_Seq__Singleton__Length___Seq___int(); call proc_Seq__Build__Length___Seq___int(); call proc_Seq__Build__Index___Seq___int(); call proc_Seq__Append__Length___Seq___int(); call proc_Seq__Index__Singleton___Seq___int(); call proc_Seq__Append__Index___Seq___int(); call proc_Seq__Update__Length___Seq___int(); call proc_Seq__Index__Update___Seq___int(); call proc_Seq__Equal__Equiv___Seq___int(); call proc_Seq__Take__Length___Seq___int(); call proc_Seq__Take__Index___Seq___int(); call proc_Seq__Drop__Length___Seq___int(); call proc_Seq__Drop__Index___Seq___int(); call proc_Seq__Append__TakeDrop___Seq___int(); call proc_Seq__Update__CommuteTake1___Seq___int(); call proc_Seq__Update__CommuteTake2___Seq___int(); call proc_Seq__Update__CommuteDrop1___Seq___int(); call proc_Seq__Update__CommuteDrop2___Seq___int(); call proc_Seq__Build__CommuteDrop___Seq___int(); call proc_Seq__Take__Empty___Seq___int(); call proc_Seq__Drop__Empty___Seq___int(); call lemma_fun_ensures_fun_Width(); call lemma_unroll_rec_fun_CanonicalizeSeq__def(); call lemma_unroll_fun_CanonicalizeSeq__def(); call lemma_fun_ensures_fun_CanonicalizeSeq(); call lemma_fun_ensures_fun_IsZeroValue(); call lemma_fun_ensures_fun_SelectDigits(); call lemma_unroll_rec_fun____HASH_MaxLen__def__FULL(); call lemma_unroll_fun____HASH_MaxLen__def__FULL(); call lemma_fun_ensures_fun_MaxLen(); call lemma_fun_ensures_fun_MaxLen3(); call lemma_fun_ensures_fun_ArrayDigitAt(); call lemma_fun_ensures_fun_ArrayDigitAt__add(); call lemma_fun_ensures_fun_ArrayDigitAt__sub(); call lemma_fun_ensures_fun_ArrayDigitAt__cmp(); call lemma_fun_ensures_fun_ArrayDigitAt__mul(); call lemma_fun_ensures_fun_J(); r := r_old; stk := stk_old; statics := statics_old; io := io_old; mems := mems_old; $commonVars := $commonVars_old; $gcVars := $gcVars_old; $toAbs := $toAbs_old; $absMem := $absMem_old; $stacksFrames := $stacksFrames_old; objLayouts := objLayouts_old; heap := heap_old; $ghost_c__abs := frameGet($stacksFrames, r_old.regs[ESP] + 4 + stackGcOffset); $ghost_a__abs := frameGet($stacksFrames, r_old.regs[ESP] + 8 + stackGcOffset); mod0 := ($ghost_c).arrAbs; assert TV(r.regs[ESP]); assert TO(0 - 1); assert TO(279552 - 1); assert TO(0 - 2); assert TO(279552 - 2); assert TO(0 - 3); assert TO(279552 - 3); assert TO(0 - 4); assert TO(279552 - 4); assert TO(0 - 5); assert TO(279552 - 5); assert TO(0 - 6); assert TO(279552 - 6); assert TO(0 - 7); assert TO(279552 - 7); assert TO(0 - 8); assert TO(279552 - 8); assert TO(0 - 9); assert TO(279552 - 9); assert TO(0 - 10); assert TO(279552 - 10); assert TO(0 - 11); assert TO(279552 - 11); assert TO(0 - 12); assert TO(279552 - 12); assert TO(0); assert TO(279552); assert TO(1); assert TO(279553); assert TO(2); assert TO(279554); assert TO(3); assert TO(279555); assert TO(4); assert TO(279556); assert $ghost_adigits > 0; assert Arr_Length($ghost_a) - $ghost_adigits >= 0; assert Arr_Length($ghost_a) - $ghost_adigits < Arr_Length($ghost_a); $ghost_pv := fun_power2(32); call proc_lemma__2toX(); $ghost_oldcs := fun_Seq__FromArray($absMem, $ghost_c); //- Load array a ptr into edi call r, mems := heapLoadStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, EDI, OMem(MReg(ESP, 0x111008)), EvalPtr(r, OMem(MReg(ESP, 0x111008)))); a_base := edi; $ghost_a__abs := frameGet($stacksFrames, EvalPtr(r, OMem(MReg(ESP, 0x111008)))); //- Load a's length into eax call r, mems := loadArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, EAX, OMem(MReg(EDI, 4)), (0 - 1), $ghost_a__abs, r.regs[EDI]); assert eax == Arr_Length($ghost_a); //- Save a copy for use in bound calculation ecx := eax; call r := instr_Sub(r, EAX, OConst(1)); $ghost_alenm1 := eax; //- == alenm1 call reveal_wrap32(Arr_Length($ghost_a) - 1); assert $ghost_alenm1 == Arr_Length($ghost_a) - 1; //- Load array c ptr into esi call r, mems := heapLoadStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, ESI, OMem(MReg(ESP, 0x111004)), EvalPtr(r, OMem(MReg(ESP, 0x111004)))); c_base := esi; $ghost_c__abs := frameGet($stacksFrames, EvalPtr(r, OMem(MReg(ESP, 0x111004)))); //- Load c's length into ebx call r, mems := loadArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, EBX, OMem(MReg(ESI, 4)), (0 - 1), $ghost_c__abs, r.regs[ESI]); call r := instr_Sub(r, EBX, OConst(1)); call reveal_wrap32(Arr_Length($ghost_c) - 1); $ghost_clenm1 := ebx; //- == clenm1 //- Grab bi from the stack call ebp := Load(stk, esp + 8); //- Adjust clenm1 by bi call r := instr_Sub(r, EBX, OReg(EBP)); call reveal_wrap32(Arr_Length($ghost_c) - 1 - $ghost_bi); assert ebx == Arr_Length($ghost_c) - 1 - $ghost_bi; //- Now create ptrs directly into the correct location in a and c respectively call arrayElementProperties(core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_alenm1, $ghost_a__abs, edi); //- Proves we're within bounds for the Lea calculation edx := edi; //- Save a copy to use for the loop bound call edi := Lea(edi + 4 * eax + 8); call arrayElementProperties(core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_clenm1 - $ghost_bi, $ghost_c__abs, esi); //- Proves we're within bounds for the Lea calculation call esi := Lea(esi + 4 * ebx + 8); //- Establish partial sum invariant call proc_lemma__BEWordSeqToInt__SelectDigitRange__empty(fun_Seq__FromArray($absMem, $ghost_a)); //- Grab adigits call ebp := Load(stk, esp + 12); //- Compute the loop bound //- (take the a_ptr which is a.base + 8 + 4 * (a.Length - 1) and subtract 4*(adigits) //- which is a.Length - 1 - adigits assert ecx == Arr_Length($ghost_a); call r := instr_Sub(r, ECX, OReg(EBP)); call reveal_wrap32(Arr_Length($ghost_a) - $ghost_adigits); assert $ghost_adigits > 0; assert ecx == Arr_Length($ghost_a) - $ghost_adigits; assert 0 <= ecx; assert ecx < Arr_Length($ghost_a); call arrayElementProperties(core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, Arr_Length($ghost_a) - $ghost_adigits, $ghost_a__abs, edx); //- Proves we're within bounds for the Lea calculation call edx := Lea(edx + 4 * ecx + 8); ebx := edx; //- Ebx is now the appropriate loop bound assert ebx == a_base + 4 * (Arr_Length($ghost_a) - $ghost_adigits) + 8; //- Grab bv for multiplication purposes call ebp := Load(stk, esp + 16); //- Initialize ecx for use as the current/last carry value ecx := 0; $ghost_carry := ecx; $ghost_j := 0; assert {:split_here} true; while (edi >= ebx) invariant MemInv(me,init,stk,statics,core_state,ptMem,mems); invariant NucleusInv(objLayouts,$S,$toAbs,$absMem,$commonVars,$gcVars,me,init,stk,statics,core_state,ptMem,mems,$stacksFrames,io); invariant SMemInvGcF(20, stk, old(stk_old), r.regs[ESP], old(r_old.regs[ESP]), $stacksFrames, $stacksFrames_old); invariant HeapInv($absMem, objLayouts, heap); invariant AbsExtend($toAbs, $toAbs_old, objLayouts, objLayouts_old); invariant (forall i:int::{$absMem[i]}{heap.absData[i]} heap_old.absData[i] is AbsNone || (heap.absData[i] == heap_old.absData[i] && ($absMem[i] == $absMem_old[i] || i == (($ghost_c).arrAbs)))); invariant io._inCtr == io_old._inCtr && io._outCtr == io_old._outCtr; //- loop invariants invariant $ghost_carry == ecx; invariant $ghost_bv == ebp; invariant HeapAbsData(heap, $ghost_a__abs) == Abs_ArrayOfInt($ghost_a); invariant HeapValue(objLayouts, true, $toAbs, a_base, $ghost_a__abs); invariant $ghost_a__abs == $ghost_a.arrAbs; invariant HeapAbsData(heap, $ghost_c__abs) == Abs_ArrayOfInt($ghost_c); invariant HeapValue(objLayouts, true, $toAbs, c_base, $ghost_c__abs); invariant $ghost_c__abs == $ghost_c.arrAbs; invariant $ghost_bi >= 0; invariant (INTERNAL_le_boogie(0, $ghost_j)) && (INTERNAL_le_boogie($ghost_j, $ghost_adigits)); invariant edi == a_base + 4 * (Arr_Length($ghost_a) - 1 - $ghost_j) + 8; invariant ebx == a_base + 4 * (Arr_Length($ghost_a) - $ghost_adigits) + 8; invariant esi == c_base + 4 * (Arr_Length($ghost_c) - 1 - ($ghost_j + $ghost_bi)) + 8; invariant fun_IsDigitSeq($ghost_pv, fun_Seq__FromArray($absMem, $ghost_c)); invariant (INTERNAL_le_boogie(0, $ghost_carry)) && (INTERNAL_lt_boogie($ghost_carry, $ghost_pv)); invariant (INTERNAL_add_boogie(fun_BEWordSeqToInt(fun_Seq__FromArray($absMem, $ghost_c)), fun_INTERNAL__mul($ghost_carry, fun_power($ghost_pv, INTERNAL_add_boogie($ghost_j, $ghost_bi))))) == (INTERNAL_add_boogie(fun_BEWordSeqToInt($ghost_oldcs), fun_INTERNAL__mul(fun_INTERNAL__mul(fun_BEWordSeqToInt(fun_SelectDigitRange(fun_Seq__FromArray($absMem, $ghost_a), $ghost_j, 0)), $ghost_bv), fun_power($ghost_pv, $ghost_bi)))); invariant (forall $ghost__0_k:int :: ((INTERNAL_le_boogie(0, $ghost__0_k)) && (INTERNAL_lt_boogie($ghost__0_k, INTERNAL_sub_boogie(INTERNAL_sub_boogie((Arr_Length($ghost_c)), 1), INTERNAL_add_boogie($ghost_j, $ghost_bi))))) ==> ((fun_INTERNAL__array__elems__index($absMem[$ghost_c.arrAbs], ($ghost__0_k))) == (old(fun_INTERNAL__array__elems__index($absMem_old[$ghost_c.arrAbs], ($ghost__0_k)))))); { call proc_lemma__mod__properties(); call proc_lemma__2toX(); call proc_lemma__word32__Word32(); call reveal_WORD_HI(); $ghost_lastj := $ghost_j; $ghost_lastcarry := $ghost_carry; $ghost_lastcs := fun_Seq__FromArray($absMem, $ghost_c); $ghost_asq := fun_Seq__FromArray($absMem, $ghost_a); $ghost_ci := Arr_Length($ghost_c) - 1 - ($ghost_j + $ghost_bi); $ghost_ai := Arr_Length($ghost_a) - 1 - $ghost_j; //- eax := a[ai]; call r, mems := loadArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, EAX, OMem(MReg(EDI, 0)), $ghost_ai, $ghost_a__abs, a_base); $ghost_aj := eax; call edx, eax := Mul64(eax, ebp); $ghost_mhi := edx; $ghost_mlo := eax; call reveal_wrap32($ghost_aj * $ghost_bv); assert TVM($ghost_aj, $ghost_bv); assert TVD($ghost_aj * $ghost_bv, 0x100000000); call proc_lemma__asm__Mul64($ghost_aj, $ghost_bv, $ghost_mhi, $ghost_mlo); //- add1 (needs to be a direct call to instr_Add to bypass overflow check in logical add call r := instr_Add(r, EAX, OReg(ECX)); //- eax == mlo + lastcarry $ghost_add1 := eax; call reveal_wrap32($ghost_mlo + $ghost_lastcarry); $ghost_carry1 := if $ghost_add1 < $ghost_lastcarry then 1 else 0; assert if Cf(r.efl) then $ghost_carry1 == 1 else $ghost_carry1 == 0; call proc_lemma__asm__Add__properties($ghost_mlo, $ghost_lastcarry, $ghost_add1, $ghost_carry1); //- Add the carry bit to mhi call r := instr_AddCarry(r, EDX, OConst(0)); call reveal_wrap32($ghost_mhi + $ghost_carry1); assert edx == $ghost_mhi + $ghost_carry1; assert !Cf(r.efl); //- Load c into ecx, clobbering the no-longer-needed lastcarry //- ecx := c[ci]; call r, mems := loadArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, ECX, OMem(MReg(ESI, 0)), $ghost_ci, $ghost_c__abs, c_base); $ghost_lastcj := ecx; assert eax == wrap32($ghost_mlo + $ghost_lastcarry); call eax := AddCarry(eax, ecx); //- eax == mlo + lastcarry + lastcj $ghost_newcj := eax; $ghost_carry2 := if (wrap32($ghost_mlo + $ghost_lastcarry) + $ghost_lastcj) >= 0x100000000 then 1 else 0; assert $ghost_newcj == wrap32(wrap32($ghost_mlo + $ghost_lastcarry) + $ghost_lastcj); //- Write back the new values of c call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(ESI, 0)), OReg(EAX), $ghost_ci, eax, $ghost_c__abs, c_base); //- Add the carry bit to mhi call r := instr_AddCarry(r, EDX, OConst(0)); assert edx == wrap32($ghost_mhi + $ghost_carry1 + $ghost_carry2); $ghost_carry := edx; ecx := edx; assert $ghost_carry2 == if (wrap32($ghost_mlo + $ghost_lastcarry) + $ghost_lastcj) >= 0x100000000 then 1 else 0; call reveal_wrap32($ghost_mlo + $ghost_lastcarry); assert $ghost_carry2 == if (($ghost_mlo + $ghost_lastcarry) mod 0x100000000 + $ghost_lastcj) >= 0x100000000 then 1 else 0; call reveal_wrap32(($ghost_mlo + $ghost_lastcarry) mod 0x100000000 + $ghost_lastcj); call reveal_wrap32($ghost_mhi + $ghost_carry1 + $ghost_carry2); //- Update pointers and counters $ghost_j := $ghost_j + 1; old_edi := edi; call r := instr_Sub(r, EDI, OConst(4)); call reveal_wrap32(old_edi - 4); assert edi == old_edi - 4; old_esi := esi; call r := instr_Sub(r, ESI, OConst(4)); call reveal_wrap32(old_esi - 4); assert esi == old_esi - 4; call proc_lemma__FleetNatMul__one__element($ghost_pv, $ghost_newcj, $ghost_carry, $ghost_aj, $ghost_bv, $ghost_lastcj, $ghost_lastcarry, $ghost_mlo, $ghost_mhi, $ghost_add1, $ghost_carry1, $ghost_carry2); assert {:split_here} true; call proc_lemma__FleetNatMul__one__partial__sum__induction($ghost_pv, $ghost_oldcs, $ghost_lastcs, fun_Seq__FromArray($absMem, $ghost_c), fun_Seq__FromArray($absMem, $ghost_a), $ghost_adigits, $ghost_bi, $ghost_bv, $ghost_j, $ghost_lastj, $ghost_carry, $ghost_lastcarry, $ghost_lastcj, $ghost_newcj); } assert $ghost_j == $ghost_adigits; //- Store the final carrry back on the stack call logical_Store(r, core_state, inout stk, OMem(MReg(ESP, 4)), OReg(ECX)); Return; } } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Main/dafny_FleetNatMulOpt_i.imp.beat ================================================ //-private-import BaseSpec; //-private-import MemorySpec; //-private-import IoTypesSpec; //-private-import MachineStateSpec; //-private-import AssemblySpec; //-private-import InterruptsSpec; //-private-import IoSpec; //-private-import Overflow; //-private-import Core; //-private-import LogicalAddressing; //-private-import Util; //-private-import Stacks; //-private-import Partition; //-private-import Instructions; //-private-import Separation; //-private-import IntLemmasGc; //-private-import SimpleGcMemory; //-private-import SimpleCommon; //-private-import SimpleCollector; //-private-import IntLemmasMain; //-private-import IntLemmasBase; //-private-import IoMain; //-private-basmonly-import Trusted; //-private-basmonly-import Checked; //-private-import Heap; //-private-import Seq; //-private-import dafny_DafnyPrelude; //-private-import DafnyAssembly; //-private-import dafny_base_s; //-private-import dafny_power2_s; //-private-import dafny_bytes_and_words_s; //-private-import dafny_be_sequences_s; //-private-import dafny_integer_sequences_s; //-private-import dafny_seqs_simple_i; //-private-import dafny_power_s; //-private-import dafny_mul_nonlinear_i; //-private-import dafny_mul_i; //-private-import dafny_power_i; //-private-import dafny_div_def_i; //-private-import dafny_div_boogie_i; //-private-import dafny_div_nonlinear_i; //-private-import dafny_div_i; //-private-import dafny_repeat_digit_i; //-private-import dafny_assembly_s; //-private-import dafny_power2_i; //-private-import dafny_seqs_and_ints_i; //-private-import dafny_seqs_common_i; //-private-import dafny_Word32_i; //-private-import dafny_relational_s; //-private-import dafny_assembly_i; //-private-import dafny_arrays_i; //-private-import dafny_seqs_transforms_i; //-private-import dafny_seqs_reverse_i; //-private-import dafny_integer_sequences_i; //-private-import dafny_integer_sequences_premium_i; //-private-import dafny_assembly_premium_i; //-private-import dafny_BigNatX86Shim_i; //-private-import dafny_seqs_canonical_i; //-private-import dafny_CanonicalArrays_i; //-private-import dafny_FatNatCommon_i; //-private-import dafny_FleetNatCommon_i; //-private-import dafny_FleetNatAdd_i; //-private-import dafny_FleetNatMulLemmas_i; //- //- //- //- //- module implementation dafny_FleetNatMulOpt_i { implementation Proc_FleetNatMulMathOpt(my r_old:regs, const my core_state:core_state, linear stk_old:mem, linear statics_old:mem, linear io_old:IOState, linear mems_old:mems, $commonVars_old:commonVars, $gcVars_old:gcVars, $toAbs_old:[int]int, $absMem_old:[int][int]int, $stacksFrames_old:[int]Frames, objLayouts_old:[int]ObjLayout, heap_old:Heap, $ghost_aj:int, $ghost_bv:int, $ghost_lastcj:int, $ghost_lastcarry:int) returns(my r:regs, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars, $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap, $ghost_newcj:int, $ghost_newcarry:int) { //- Lots of boilerplate var $absMem_tmp:[int][int]int; var objLayouts_tmp:[int]ObjLayout; var heap_tmp:Heap; var obj_tmp:int; var val_tmp:int; var $ghost_mhi:int; var $ghost_mlo:int; var $ghost__temp__0:int; var $ghost_add1:int; var $ghost_carry1:int; var $ghost_carry2:int; var $ghost_add3:int; var $ghost_carry3:int; var $ghost_carry4:int; var tmp:int; assert fun_unroll(0); assert fun_unroll(1); call lemma_unroll_rec_fun____HASH_Seq__Length__FULL___int(); call lemma_unroll_fun____HASH_Seq__Length__FULL___int(); call lemma_fun_ensures_fun_Seq__Length___int(); call lemma_unroll_rec_fun____HASH_Seq__Build__FULL___int(); call lemma_unroll_fun____HASH_Seq__Build__FULL___int(); call lemma_unroll_rec_fun____HASH_Seq__Index__FULL___int(); call lemma_unroll_fun____HASH_Seq__Index__FULL___int(); call lemma_unroll_rec_fun____HASH_Seq__Append__FULL___int(); call lemma_unroll_fun____HASH_Seq__Append__FULL___int(); call lemma_unroll_rec_fun____HASH_Seq__Update__FULL___int(); call lemma_unroll_fun____HASH_Seq__Update__FULL___int(); call lemma_unroll_rec_fun____HASH_Seq__Take__FULL___int(); call lemma_unroll_fun____HASH_Seq__Take__FULL___int(); call lemma_unroll_rec_fun____HASH_Seq__Drop__FULL___int(); call lemma_unroll_fun____HASH_Seq__Drop__FULL___int(); call proc_Seq__Empty__ToZero___int(); call proc_Seq__Empty__FromZero___int(); call proc_Seq__Singleton__Length___int(); call proc_Seq__Build__Length___int(); call proc_Seq__Build__Index___int(); call proc_Seq__Append__Length___int(); call proc_Seq__Index__Singleton___int(); call proc_Seq__Append__Index___int(); call proc_Seq__Update__Length___int(); call proc_Seq__Index__Update___int(); call proc_Seq__Equal__Equiv___int(); call proc_Seq__Take__Length___int(); call proc_Seq__Take__Index___int(); call proc_Seq__Drop__Length___int(); call proc_Seq__Drop__Index___int(); call proc_Seq__Append__TakeDrop___int(); call proc_Seq__Update__CommuteTake1___int(); call proc_Seq__Update__CommuteTake2___int(); call proc_Seq__Update__CommuteDrop1___int(); call proc_Seq__Update__CommuteDrop2___int(); call proc_Seq__Build__CommuteDrop___int(); call proc_Seq__Take__Empty___int(); call proc_Seq__Drop__Empty___int(); call lemma_unroll_fun_Seq__FromArrayRange(); call proc_Seq__FromArray__Length(); call proc_Seq__FromArray__Index(); call proc_Seq__FromArray__Update(); call lemma_unroll_rec_fun____HASH_power2__FULL(); call lemma_unroll_fun____HASH_power2__FULL(); call lemma_fun_ensures_fun_power2(); call lemma_unroll_rec_fun____HASH_BEDigitSeqToInt__private__FULL(); call lemma_unroll_fun____HASH_BEDigitSeqToInt__private__FULL(); call lemma_unroll_rec_fun____HASH_BEIntToDigitSeq__private__FULL(); call lemma_unroll_fun____HASH_BEIntToDigitSeq__private__FULL(); call lemma_unroll_rec_fun_RepeatDigit(); call lemma_unroll_fun_RepeatDigit(); call lemma_unroll_rec_fun____HASH_Reverse__FULL(); call lemma_unroll_fun____HASH_Reverse__FULL(); call lemma_unroll_rec_fun____HASH_power__FULL(); call lemma_unroll_fun____HASH_power__FULL(); call lemma_unroll_rec_fun_mul__pos(); call lemma_unroll_fun_mul__pos(); call lemma_unroll_rec_fun____HASH_Seq__Length__FULL___bool(); call lemma_unroll_fun____HASH_Seq__Length__FULL___bool(); call lemma_fun_ensures_fun_Seq__Length___bool(); call lemma_unroll_rec_fun____HASH_Seq__Build__FULL___bool(); call lemma_unroll_fun____HASH_Seq__Build__FULL___bool(); call lemma_unroll_rec_fun____HASH_Seq__Index__FULL___bool(); call lemma_unroll_fun____HASH_Seq__Index__FULL___bool(); call lemma_unroll_rec_fun____HASH_Seq__Append__FULL___bool(); call lemma_unroll_fun____HASH_Seq__Append__FULL___bool(); call lemma_unroll_rec_fun____HASH_Seq__Update__FULL___bool(); call lemma_unroll_fun____HASH_Seq__Update__FULL___bool(); call lemma_unroll_rec_fun____HASH_Seq__Take__FULL___bool(); call lemma_unroll_fun____HASH_Seq__Take__FULL___bool(); call lemma_unroll_rec_fun____HASH_Seq__Drop__FULL___bool(); call lemma_unroll_fun____HASH_Seq__Drop__FULL___bool(); call proc_Seq__Empty__ToZero___bool(); call proc_Seq__Empty__FromZero___bool(); call proc_Seq__Singleton__Length___bool(); call proc_Seq__Build__Length___bool(); call proc_Seq__Build__Index___bool(); call proc_Seq__Append__Length___bool(); call proc_Seq__Index__Singleton___bool(); call proc_Seq__Append__Index___bool(); call proc_Seq__Update__Length___bool(); call proc_Seq__Index__Update___bool(); call proc_Seq__Equal__Equiv___bool(); call proc_Seq__Take__Length___bool(); call proc_Seq__Take__Index___bool(); call proc_Seq__Drop__Length___bool(); call proc_Seq__Drop__Index___bool(); call proc_Seq__Append__TakeDrop___bool(); call proc_Seq__Update__CommuteTake1___bool(); call proc_Seq__Update__CommuteTake2___bool(); call proc_Seq__Update__CommuteDrop1___bool(); call proc_Seq__Update__CommuteDrop2___bool(); call proc_Seq__Build__CommuteDrop___bool(); call proc_Seq__Take__Empty___bool(); call proc_Seq__Drop__Empty___bool(); call lemma_unroll_rec_fun_my__div__pos(); call lemma_unroll_fun_my__div__pos(); call lemma_unroll_rec_fun_my__mod__recursive(); call lemma_unroll_fun_my__mod__recursive(); call lemma_fun_ensures_fun_RepeatDigit__premium(); call lemma_unroll_rec_fun____HASH_SequenceOfZeros__FULL(); call lemma_unroll_fun____HASH_SequenceOfZeros__FULL(); call lemma_fun_ensures_fun_SequenceOfZeros(); call lemma_fun_ensures_fun_BitwiseAnd(); call lemma_fun_ensures_fun_BitwiseOr(); call lemma_fun_ensures_fun_BitwiseNot(); call lemma_fun_ensures_fun_BitwiseXor(); call lemma_fun_ensures_fun_RotateRight(); call lemma_fun_ensures_fun_RotateLeft(); call lemma_fun_ensures_fun_RightShift(); call lemma_fun_ensures_fun_LeftShift(); call lemma_fun_ensures_fun_Add32(); call lemma_fun_ensures_fun_Sub32(); call lemma_fun_ensures_fun_Mul32(); call lemma_fun_ensures_fun_Div32(); call lemma_fun_ensures_fun_Mod32(); call lemma_unroll_rec_fun____HASH_NatNumBits__FULL(); call lemma_unroll_fun____HASH_NatNumBits__FULL(); call lemma_fun_ensures_fun_NatNumBits(); call lemma_fun_ensures_fun_asm__Add(); call lemma_fun_ensures_fun_asm__Sub(); call lemma_fun_ensures_fun_asm__Mul(); call lemma_fun_ensures_fun_asm__Div(); call lemma_fun_ensures_fun_asm__Mod(); call lemma_fun_ensures_fun_asm__LeftShift(); call lemma_fun_ensures_fun_asm__RightShift(); call lemma_fun_ensures_fun_asm__RotateLeft(); call lemma_fun_ensures_fun_asm__RotateRight(); call lemma_fun_ensures_fun_asm__BitwiseNot(); call lemma_fun_ensures_fun_asm__BitwiseAnd(); call lemma_fun_ensures_fun_asm__BitwiseOr(); call lemma_fun_ensures_fun_asm__BitwiseXor(); call lemma_unroll_rec_fun____HASH_LEDigitSeqToInt__private__FULL(); call lemma_unroll_fun____HASH_LEDigitSeqToInt__private__FULL(); call lemma_fun_ensures_fun_BEDigitSeqToInt__premium(); call lemma_fun_ensures_fun_BEWordSeqToInt__premium(); call lemma_fun_ensures_fun_BEIntToDigitSeq__premium(); call lemma_fun_ensures_fun_BEIntToByteSeq__premium(); call lemma_fun_ensures_fun_BEWordToFourBytes__premium(); call lemma_fun_ensures_fun_BEWordToBitSeq__premium(); call lemma_fun_ensures_fun_BEWordSeqToBitSeq__premium(); call lemma_fun_ensures_fun_BEByteSeqToBitSeq__premium(); call lemma_fun_ensures_fun_BEWordSeqToByteSeq__premium(); call lemma_fun_ensures_fun_Asm__Add(); call lemma_fun_ensures_fun_Asm__Sub(); call lemma_fun_ensures_fun_Asm__Mul(); call lemma_fun_ensures_fun_Asm__Div(); call lemma_fun_ensures_fun_Asm__Mod(); call lemma_fun_ensures_fun_Asm__LeftShift(); call lemma_fun_ensures_fun_Asm__RightShift(); call lemma_fun_ensures_fun_Asm__RotateLeft(); call lemma_fun_ensures_fun_Asm__RotateRight(); call lemma_fun_ensures_fun_Asm__BitwiseNot(); call lemma_fun_ensures_fun_Asm__BitwiseAnd(); call lemma_fun_ensures_fun_Asm__BitwiseOr(); call lemma_fun_ensures_fun_Asm__BitwiseXor(); call lemma_unroll_rec_fun____HASH_Seq__Length__FULL___Seq___int(); call lemma_unroll_fun____HASH_Seq__Length__FULL___Seq___int(); call lemma_fun_ensures_fun_Seq__Length___Seq___int(); call lemma_unroll_rec_fun____HASH_Seq__Build__FULL___Seq___int(); call lemma_unroll_fun____HASH_Seq__Build__FULL___Seq___int(); call lemma_unroll_rec_fun____HASH_Seq__Index__FULL___Seq___int(); call lemma_unroll_fun____HASH_Seq__Index__FULL___Seq___int(); call lemma_unroll_rec_fun____HASH_Seq__Append__FULL___Seq___int(); call lemma_unroll_fun____HASH_Seq__Append__FULL___Seq___int(); call lemma_unroll_rec_fun____HASH_Seq__Update__FULL___Seq___int(); call lemma_unroll_fun____HASH_Seq__Update__FULL___Seq___int(); call lemma_unroll_rec_fun____HASH_Seq__Take__FULL___Seq___int(); call lemma_unroll_fun____HASH_Seq__Take__FULL___Seq___int(); call lemma_unroll_rec_fun____HASH_Seq__Drop__FULL___Seq___int(); call lemma_unroll_fun____HASH_Seq__Drop__FULL___Seq___int(); call proc_Seq__Empty__ToZero___Seq___int(); call proc_Seq__Empty__FromZero___Seq___int(); call proc_Seq__Singleton__Length___Seq___int(); call proc_Seq__Build__Length___Seq___int(); call proc_Seq__Build__Index___Seq___int(); call proc_Seq__Append__Length___Seq___int(); call proc_Seq__Index__Singleton___Seq___int(); call proc_Seq__Append__Index___Seq___int(); call proc_Seq__Update__Length___Seq___int(); call proc_Seq__Index__Update___Seq___int(); call proc_Seq__Equal__Equiv___Seq___int(); call proc_Seq__Take__Length___Seq___int(); call proc_Seq__Take__Index___Seq___int(); call proc_Seq__Drop__Length___Seq___int(); call proc_Seq__Drop__Index___Seq___int(); call proc_Seq__Append__TakeDrop___Seq___int(); call proc_Seq__Update__CommuteTake1___Seq___int(); call proc_Seq__Update__CommuteTake2___Seq___int(); call proc_Seq__Update__CommuteDrop1___Seq___int(); call proc_Seq__Update__CommuteDrop2___Seq___int(); call proc_Seq__Build__CommuteDrop___Seq___int(); call proc_Seq__Take__Empty___Seq___int(); call proc_Seq__Drop__Empty___Seq___int(); // call lemma_unroll_rec_fun____HASH_Seq__Length__FULL___atoe_Type(); // call lemma_unroll_fun____HASH_Seq__Length__FULL___atoe_Type(); // call lemma_fun_ensures_fun_Seq__Length___atoe_Type(); // call lemma_unroll_rec_fun____HASH_Seq__Build__FULL___atoe_Type(); // call lemma_unroll_fun____HASH_Seq__Build__FULL___atoe_Type(); // call lemma_unroll_rec_fun____HASH_Seq__Index__FULL___atoe_Type(); // call lemma_unroll_fun____HASH_Seq__Index__FULL___atoe_Type(); // call lemma_unroll_rec_fun____HASH_Seq__Append__FULL___atoe_Type(); // call lemma_unroll_fun____HASH_Seq__Append__FULL___atoe_Type(); // call lemma_unroll_rec_fun____HASH_Seq__Update__FULL___atoe_Type(); // call lemma_unroll_fun____HASH_Seq__Update__FULL___atoe_Type(); // call lemma_unroll_rec_fun____HASH_Seq__Take__FULL___atoe_Type(); // call lemma_unroll_fun____HASH_Seq__Take__FULL___atoe_Type(); // call lemma_unroll_rec_fun____HASH_Seq__Drop__FULL___atoe_Type(); // call lemma_unroll_fun____HASH_Seq__Drop__FULL___atoe_Type(); // call proc_Seq__Empty__ToZero___atoe_Type(); // call proc_Seq__Empty__FromZero___atoe_Type(); // call proc_Seq__Singleton__Length___atoe_Type(); // call proc_Seq__Build__Length___atoe_Type(); // call proc_Seq__Build__Index___atoe_Type(); // call proc_Seq__Append__Length___atoe_Type(); // call proc_Seq__Index__Singleton___atoe_Type(); // call proc_Seq__Append__Index___atoe_Type(); // call proc_Seq__Update__Length___atoe_Type(); // call proc_Seq__Index__Update___atoe_Type(); // call proc_Seq__Equal__Equiv___atoe_Type(); // call proc_Seq__Take__Length___atoe_Type(); // call proc_Seq__Take__Index___atoe_Type(); // call proc_Seq__Drop__Length___atoe_Type(); // call proc_Seq__Drop__Index___atoe_Type(); // call proc_Seq__Append__TakeDrop___atoe_Type(); // call proc_Seq__Update__CommuteTake1___atoe_Type(); // call proc_Seq__Update__CommuteTake2___atoe_Type(); // call proc_Seq__Update__CommuteDrop1___atoe_Type(); // call proc_Seq__Update__CommuteDrop2___atoe_Type(); // call proc_Seq__Build__CommuteDrop___atoe_Type(); // call proc_Seq__Take__Empty___atoe_Type(); // call proc_Seq__Drop__Empty___atoe_Type(); // call lemma_unroll_rec_fun____HASH_Seq__Length__FULL___Seq___atoe_Type(); // call lemma_unroll_fun____HASH_Seq__Length__FULL___Seq___atoe_Type(); // call lemma_fun_ensures_fun_Seq__Length___Seq___atoe_Type(); // call lemma_unroll_rec_fun____HASH_Seq__Build__FULL___Seq___atoe_Type(); // call lemma_unroll_fun____HASH_Seq__Build__FULL___Seq___atoe_Type(); // call lemma_unroll_rec_fun____HASH_Seq__Index__FULL___Seq___atoe_Type(); // call lemma_unroll_fun____HASH_Seq__Index__FULL___Seq___atoe_Type(); // call lemma_unroll_rec_fun____HASH_Seq__Append__FULL___Seq___atoe_Type(); // call lemma_unroll_fun____HASH_Seq__Append__FULL___Seq___atoe_Type(); // call lemma_unroll_rec_fun____HASH_Seq__Update__FULL___Seq___atoe_Type(); // call lemma_unroll_fun____HASH_Seq__Update__FULL___Seq___atoe_Type(); // call lemma_unroll_rec_fun____HASH_Seq__Take__FULL___Seq___atoe_Type(); // call lemma_unroll_fun____HASH_Seq__Take__FULL___Seq___atoe_Type(); // call lemma_unroll_rec_fun____HASH_Seq__Drop__FULL___Seq___atoe_Type(); // call lemma_unroll_fun____HASH_Seq__Drop__FULL___Seq___atoe_Type(); // call proc_Seq__Empty__ToZero___Seq___atoe_Type(); // call proc_Seq__Empty__FromZero___Seq___atoe_Type(); // call proc_Seq__Singleton__Length___Seq___atoe_Type(); // call proc_Seq__Build__Length___Seq___atoe_Type(); // call proc_Seq__Build__Index___Seq___atoe_Type(); // call proc_Seq__Append__Length___Seq___atoe_Type(); // call proc_Seq__Index__Singleton___Seq___atoe_Type(); // call proc_Seq__Append__Index___Seq___atoe_Type(); // call proc_Seq__Update__Length___Seq___atoe_Type(); // call proc_Seq__Index__Update___Seq___atoe_Type(); // call proc_Seq__Equal__Equiv___Seq___atoe_Type(); // call proc_Seq__Take__Length___Seq___atoe_Type(); // call proc_Seq__Take__Index___Seq___atoe_Type(); // call proc_Seq__Drop__Length___Seq___atoe_Type(); // call proc_Seq__Drop__Index___Seq___atoe_Type(); // call proc_Seq__Append__TakeDrop___Seq___atoe_Type(); // call proc_Seq__Update__CommuteTake1___Seq___atoe_Type(); // call proc_Seq__Update__CommuteTake2___Seq___atoe_Type(); // call proc_Seq__Update__CommuteDrop1___Seq___atoe_Type(); // call proc_Seq__Update__CommuteDrop2___Seq___atoe_Type(); // call proc_Seq__Build__CommuteDrop___Seq___atoe_Type(); // call proc_Seq__Take__Empty___Seq___atoe_Type(); // call proc_Seq__Drop__Empty___Seq___atoe_Type(); // call lemma_unroll_rec_fun____HASH_Seq__Length__FULL___atoh_Type(); // call lemma_unroll_fun____HASH_Seq__Length__FULL___atoh_Type(); // call lemma_fun_ensures_fun_Seq__Length___atoh_Type(); // call lemma_unroll_rec_fun____HASH_Seq__Build__FULL___atoh_Type(); // call lemma_unroll_fun____HASH_Seq__Build__FULL___atoh_Type(); // call lemma_unroll_rec_fun____HASH_Seq__Index__FULL___atoh_Type(); // call lemma_unroll_fun____HASH_Seq__Index__FULL___atoh_Type(); // call lemma_unroll_rec_fun____HASH_Seq__Append__FULL___atoh_Type(); // call lemma_unroll_fun____HASH_Seq__Append__FULL___atoh_Type(); // call lemma_unroll_rec_fun____HASH_Seq__Update__FULL___atoh_Type(); // call lemma_unroll_fun____HASH_Seq__Update__FULL___atoh_Type(); // call lemma_unroll_rec_fun____HASH_Seq__Take__FULL___atoh_Type(); // call lemma_unroll_fun____HASH_Seq__Take__FULL___atoh_Type(); // call lemma_unroll_rec_fun____HASH_Seq__Drop__FULL___atoh_Type(); // call lemma_unroll_fun____HASH_Seq__Drop__FULL___atoh_Type(); // call proc_Seq__Empty__ToZero___atoh_Type(); // call proc_Seq__Empty__FromZero___atoh_Type(); // call proc_Seq__Singleton__Length___atoh_Type(); // call proc_Seq__Build__Length___atoh_Type(); // call proc_Seq__Build__Index___atoh_Type(); // call proc_Seq__Append__Length___atoh_Type(); // call proc_Seq__Index__Singleton___atoh_Type(); // call proc_Seq__Append__Index___atoh_Type(); // call proc_Seq__Update__Length___atoh_Type(); // call proc_Seq__Index__Update___atoh_Type(); // call proc_Seq__Equal__Equiv___atoh_Type(); // call proc_Seq__Take__Length___atoh_Type(); // call proc_Seq__Take__Index___atoh_Type(); // call proc_Seq__Drop__Length___atoh_Type(); // call proc_Seq__Drop__Index___atoh_Type(); // call proc_Seq__Append__TakeDrop___atoh_Type(); // call proc_Seq__Update__CommuteTake1___atoh_Type(); // call proc_Seq__Update__CommuteTake2___atoh_Type(); // call proc_Seq__Update__CommuteDrop1___atoh_Type(); // call proc_Seq__Update__CommuteDrop2___atoh_Type(); // call proc_Seq__Build__CommuteDrop___atoh_Type(); // call proc_Seq__Take__Empty___atoh_Type(); // call proc_Seq__Drop__Empty___atoh_Type(); // call lemma_unroll_rec_fun____HASH_Seq__Length__FULL___Seq___atoh_Type(); // call lemma_unroll_fun____HASH_Seq__Length__FULL___Seq___atoh_Type(); // call lemma_fun_ensures_fun_Seq__Length___Seq___atoh_Type(); // call lemma_unroll_rec_fun____HASH_Seq__Build__FULL___Seq___atoh_Type(); // call lemma_unroll_fun____HASH_Seq__Build__FULL___Seq___atoh_Type(); // call lemma_unroll_rec_fun____HASH_Seq__Index__FULL___Seq___atoh_Type(); // call lemma_unroll_fun____HASH_Seq__Index__FULL___Seq___atoh_Type(); // call lemma_unroll_rec_fun____HASH_Seq__Append__FULL___Seq___atoh_Type(); // call lemma_unroll_fun____HASH_Seq__Append__FULL___Seq___atoh_Type(); // call lemma_unroll_rec_fun____HASH_Seq__Update__FULL___Seq___atoh_Type(); // call lemma_unroll_fun____HASH_Seq__Update__FULL___Seq___atoh_Type(); // call lemma_unroll_rec_fun____HASH_Seq__Take__FULL___Seq___atoh_Type(); // call lemma_unroll_fun____HASH_Seq__Take__FULL___Seq___atoh_Type(); // call lemma_unroll_rec_fun____HASH_Seq__Drop__FULL___Seq___atoh_Type(); // call lemma_unroll_fun____HASH_Seq__Drop__FULL___Seq___atoh_Type(); // call proc_Seq__Empty__ToZero___Seq___atoh_Type(); // call proc_Seq__Empty__FromZero___Seq___atoh_Type(); // call proc_Seq__Singleton__Length___Seq___atoh_Type(); // call proc_Seq__Build__Length___Seq___atoh_Type(); // call proc_Seq__Build__Index___Seq___atoh_Type(); // call proc_Seq__Append__Length___Seq___atoh_Type(); // call proc_Seq__Index__Singleton___Seq___atoh_Type(); // call proc_Seq__Append__Index___Seq___atoh_Type(); // call proc_Seq__Update__Length___Seq___atoh_Type(); // call proc_Seq__Index__Update___Seq___atoh_Type(); // call proc_Seq__Equal__Equiv___Seq___atoh_Type(); // call proc_Seq__Take__Length___Seq___atoh_Type(); // call proc_Seq__Take__Index___Seq___atoh_Type(); // call proc_Seq__Drop__Length___Seq___atoh_Type(); // call proc_Seq__Drop__Index___Seq___atoh_Type(); // call proc_Seq__Append__TakeDrop___Seq___atoh_Type(); // call proc_Seq__Update__CommuteTake1___Seq___atoh_Type(); // call proc_Seq__Update__CommuteTake2___Seq___atoh_Type(); // call proc_Seq__Update__CommuteDrop1___Seq___atoh_Type(); // call proc_Seq__Update__CommuteDrop2___Seq___atoh_Type(); // call proc_Seq__Build__CommuteDrop___Seq___atoh_Type(); // call proc_Seq__Take__Empty___Seq___atoh_Type(); // call proc_Seq__Drop__Empty___Seq___atoh_Type(); // call lemma_unroll_rec_fun____HASH_Seq__Length__FULL___CandidateSeedWorksheetRow(); // call lemma_unroll_fun____HASH_Seq__Length__FULL___CandidateSeedWorksheetRow(); // call lemma_fun_ensures_fun_Seq__Length___CandidateSeedWorksheetRow(); // call lemma_unroll_rec_fun____HASH_Seq__Build__FULL___CandidateSeedWorksheetRow(); // call lemma_unroll_fun____HASH_Seq__Build__FULL___CandidateSeedWorksheetRow(); // call lemma_unroll_rec_fun____HASH_Seq__Index__FULL___CandidateSeedWorksheetRow(); // call lemma_unroll_fun____HASH_Seq__Index__FULL___CandidateSeedWorksheetRow(); // call lemma_unroll_rec_fun____HASH_Seq__Append__FULL___CandidateSeedWorksheetRow(); // call lemma_unroll_fun____HASH_Seq__Append__FULL___CandidateSeedWorksheetRow(); // call lemma_unroll_rec_fun____HASH_Seq__Update__FULL___CandidateSeedWorksheetRow(); // call lemma_unroll_fun____HASH_Seq__Update__FULL___CandidateSeedWorksheetRow(); // call lemma_unroll_rec_fun____HASH_Seq__Take__FULL___CandidateSeedWorksheetRow(); // call lemma_unroll_fun____HASH_Seq__Take__FULL___CandidateSeedWorksheetRow(); // call lemma_unroll_rec_fun____HASH_Seq__Drop__FULL___CandidateSeedWorksheetRow(); // call lemma_unroll_fun____HASH_Seq__Drop__FULL___CandidateSeedWorksheetRow(); // call proc_Seq__Empty__ToZero___CandidateSeedWorksheetRow(); // call proc_Seq__Empty__FromZero___CandidateSeedWorksheetRow(); // call proc_Seq__Singleton__Length___CandidateSeedWorksheetRow(); // call proc_Seq__Build__Length___CandidateSeedWorksheetRow(); // call proc_Seq__Build__Index___CandidateSeedWorksheetRow(); // call proc_Seq__Append__Length___CandidateSeedWorksheetRow(); // call proc_Seq__Index__Singleton___CandidateSeedWorksheetRow(); // call proc_Seq__Append__Index___CandidateSeedWorksheetRow(); // call proc_Seq__Update__Length___CandidateSeedWorksheetRow(); // call proc_Seq__Index__Update___CandidateSeedWorksheetRow(); // call proc_Seq__Equal__Equiv___CandidateSeedWorksheetRow(); // call proc_Seq__Take__Length___CandidateSeedWorksheetRow(); // call proc_Seq__Take__Index___CandidateSeedWorksheetRow(); // call proc_Seq__Drop__Length___CandidateSeedWorksheetRow(); // call proc_Seq__Drop__Index___CandidateSeedWorksheetRow(); // call proc_Seq__Append__TakeDrop___CandidateSeedWorksheetRow(); // call proc_Seq__Update__CommuteTake1___CandidateSeedWorksheetRow(); // call proc_Seq__Update__CommuteTake2___CandidateSeedWorksheetRow(); // call proc_Seq__Update__CommuteDrop1___CandidateSeedWorksheetRow(); // call proc_Seq__Update__CommuteDrop2___CandidateSeedWorksheetRow(); // call proc_Seq__Build__CommuteDrop___CandidateSeedWorksheetRow(); // call proc_Seq__Take__Empty___CandidateSeedWorksheetRow(); // call proc_Seq__Drop__Empty___CandidateSeedWorksheetRow(); // call lemma_unroll_rec_fun____HASH_Seq__Length__FULL___CandidateSeedWorksheet(); // call lemma_unroll_fun____HASH_Seq__Length__FULL___CandidateSeedWorksheet(); // call lemma_fun_ensures_fun_Seq__Length___CandidateSeedWorksheet(); // call lemma_unroll_rec_fun____HASH_Seq__Build__FULL___CandidateSeedWorksheet(); // call lemma_unroll_fun____HASH_Seq__Build__FULL___CandidateSeedWorksheet(); // call lemma_unroll_rec_fun____HASH_Seq__Index__FULL___CandidateSeedWorksheet(); // call lemma_unroll_fun____HASH_Seq__Index__FULL___CandidateSeedWorksheet(); // call lemma_unroll_rec_fun____HASH_Seq__Append__FULL___CandidateSeedWorksheet(); // call lemma_unroll_fun____HASH_Seq__Append__FULL___CandidateSeedWorksheet(); // call lemma_unroll_rec_fun____HASH_Seq__Update__FULL___CandidateSeedWorksheet(); // call lemma_unroll_fun____HASH_Seq__Update__FULL___CandidateSeedWorksheet(); // call lemma_unroll_rec_fun____HASH_Seq__Take__FULL___CandidateSeedWorksheet(); // call lemma_unroll_fun____HASH_Seq__Take__FULL___CandidateSeedWorksheet(); // call lemma_unroll_rec_fun____HASH_Seq__Drop__FULL___CandidateSeedWorksheet(); // call lemma_unroll_fun____HASH_Seq__Drop__FULL___CandidateSeedWorksheet(); // call proc_Seq__Empty__ToZero___CandidateSeedWorksheet(); // call proc_Seq__Empty__FromZero___CandidateSeedWorksheet(); // call proc_Seq__Singleton__Length___CandidateSeedWorksheet(); // call proc_Seq__Build__Length___CandidateSeedWorksheet(); // call proc_Seq__Build__Index___CandidateSeedWorksheet(); // call proc_Seq__Append__Length___CandidateSeedWorksheet(); // call proc_Seq__Index__Singleton___CandidateSeedWorksheet(); // call proc_Seq__Append__Index___CandidateSeedWorksheet(); // call proc_Seq__Update__Length___CandidateSeedWorksheet(); // call proc_Seq__Index__Update___CandidateSeedWorksheet(); // call proc_Seq__Equal__Equiv___CandidateSeedWorksheet(); // call proc_Seq__Take__Length___CandidateSeedWorksheet(); // call proc_Seq__Take__Index___CandidateSeedWorksheet(); // call proc_Seq__Drop__Length___CandidateSeedWorksheet(); // call proc_Seq__Drop__Index___CandidateSeedWorksheet(); // call proc_Seq__Append__TakeDrop___CandidateSeedWorksheet(); // call proc_Seq__Update__CommuteTake1___CandidateSeedWorksheet(); // call proc_Seq__Update__CommuteTake2___CandidateSeedWorksheet(); // call proc_Seq__Update__CommuteDrop1___CandidateSeedWorksheet(); // call proc_Seq__Update__CommuteDrop2___CandidateSeedWorksheet(); // call proc_Seq__Build__CommuteDrop___CandidateSeedWorksheet(); // call proc_Seq__Take__Empty___CandidateSeedWorksheet(); // call proc_Seq__Drop__Empty___CandidateSeedWorksheet(); // call lemma_unroll_rec_fun____HASH_Seq__Length__FULL___MRProbe(); // call lemma_unroll_fun____HASH_Seq__Length__FULL___MRProbe(); // call lemma_fun_ensures_fun_Seq__Length___MRProbe(); // call lemma_unroll_rec_fun____HASH_Seq__Build__FULL___MRProbe(); // call lemma_unroll_fun____HASH_Seq__Build__FULL___MRProbe(); // call lemma_unroll_rec_fun____HASH_Seq__Index__FULL___MRProbe(); // call lemma_unroll_fun____HASH_Seq__Index__FULL___MRProbe(); // call lemma_unroll_rec_fun____HASH_Seq__Append__FULL___MRProbe(); // call lemma_unroll_fun____HASH_Seq__Append__FULL___MRProbe(); // call lemma_unroll_rec_fun____HASH_Seq__Update__FULL___MRProbe(); // call lemma_unroll_fun____HASH_Seq__Update__FULL___MRProbe(); // call lemma_unroll_rec_fun____HASH_Seq__Take__FULL___MRProbe(); // call lemma_unroll_fun____HASH_Seq__Take__FULL___MRProbe(); // call lemma_unroll_rec_fun____HASH_Seq__Drop__FULL___MRProbe(); // call lemma_unroll_fun____HASH_Seq__Drop__FULL___MRProbe(); // call proc_Seq__Empty__ToZero___MRProbe(); // call proc_Seq__Empty__FromZero___MRProbe(); // call proc_Seq__Singleton__Length___MRProbe(); // call proc_Seq__Build__Length___MRProbe(); // call proc_Seq__Build__Index___MRProbe(); // call proc_Seq__Append__Length___MRProbe(); // call proc_Seq__Index__Singleton___MRProbe(); // call proc_Seq__Append__Index___MRProbe(); // call proc_Seq__Update__Length___MRProbe(); // call proc_Seq__Index__Update___MRProbe(); // call proc_Seq__Equal__Equiv___MRProbe(); // call proc_Seq__Take__Length___MRProbe(); // call proc_Seq__Take__Index___MRProbe(); // call proc_Seq__Drop__Length___MRProbe(); // call proc_Seq__Drop__Index___MRProbe(); // call proc_Seq__Append__TakeDrop___MRProbe(); // call proc_Seq__Update__CommuteTake1___MRProbe(); // call proc_Seq__Update__CommuteTake2___MRProbe(); // call proc_Seq__Update__CommuteDrop1___MRProbe(); // call proc_Seq__Update__CommuteDrop2___MRProbe(); // call proc_Seq__Build__CommuteDrop___MRProbe(); // call proc_Seq__Take__Empty___MRProbe(); // call proc_Seq__Drop__Empty___MRProbe(); // call lemma_unroll_rec_fun____HASH_Seq__Length__FULL___SelectRandomRequest(); // call lemma_unroll_fun____HASH_Seq__Length__FULL___SelectRandomRequest(); // call lemma_fun_ensures_fun_Seq__Length___SelectRandomRequest(); // call lemma_unroll_rec_fun____HASH_Seq__Build__FULL___SelectRandomRequest(); // call lemma_unroll_fun____HASH_Seq__Build__FULL___SelectRandomRequest(); // call lemma_unroll_rec_fun____HASH_Seq__Index__FULL___SelectRandomRequest(); // call lemma_unroll_fun____HASH_Seq__Index__FULL___SelectRandomRequest(); // call lemma_unroll_rec_fun____HASH_Seq__Append__FULL___SelectRandomRequest(); // call lemma_unroll_fun____HASH_Seq__Append__FULL___SelectRandomRequest(); // call lemma_unroll_rec_fun____HASH_Seq__Update__FULL___SelectRandomRequest(); // call lemma_unroll_fun____HASH_Seq__Update__FULL___SelectRandomRequest(); // call lemma_unroll_rec_fun____HASH_Seq__Take__FULL___SelectRandomRequest(); // call lemma_unroll_fun____HASH_Seq__Take__FULL___SelectRandomRequest(); // call lemma_unroll_rec_fun____HASH_Seq__Drop__FULL___SelectRandomRequest(); // call lemma_unroll_fun____HASH_Seq__Drop__FULL___SelectRandomRequest(); // call proc_Seq__Empty__ToZero___SelectRandomRequest(); // call proc_Seq__Empty__FromZero___SelectRandomRequest(); // call proc_Seq__Singleton__Length___SelectRandomRequest(); // call proc_Seq__Build__Length___SelectRandomRequest(); // call proc_Seq__Build__Index___SelectRandomRequest(); // call proc_Seq__Append__Length___SelectRandomRequest(); // call proc_Seq__Index__Singleton___SelectRandomRequest(); // call proc_Seq__Append__Index___SelectRandomRequest(); // call proc_Seq__Update__Length___SelectRandomRequest(); // call proc_Seq__Index__Update___SelectRandomRequest(); // call proc_Seq__Equal__Equiv___SelectRandomRequest(); // call proc_Seq__Take__Length___SelectRandomRequest(); // call proc_Seq__Take__Index___SelectRandomRequest(); // call proc_Seq__Drop__Length___SelectRandomRequest(); // call proc_Seq__Drop__Index___SelectRandomRequest(); // call proc_Seq__Append__TakeDrop___SelectRandomRequest(); // call proc_Seq__Update__CommuteTake1___SelectRandomRequest(); // call proc_Seq__Update__CommuteTake2___SelectRandomRequest(); // call proc_Seq__Update__CommuteDrop1___SelectRandomRequest(); // call proc_Seq__Update__CommuteDrop2___SelectRandomRequest(); // call proc_Seq__Build__CommuteDrop___SelectRandomRequest(); // call proc_Seq__Take__Empty___SelectRandomRequest(); // call proc_Seq__Drop__Empty___SelectRandomRequest(); // call lemma_unroll_rec_fun____HASH_Seq__Length__FULL___PrimeGenerationWorksheetRow(); // call lemma_unroll_fun____HASH_Seq__Length__FULL___PrimeGenerationWorksheetRow(); // call lemma_fun_ensures_fun_Seq__Length___PrimeGenerationWorksheetRow(); // call lemma_unroll_rec_fun____HASH_Seq__Build__FULL___PrimeGenerationWorksheetRow(); // call lemma_unroll_fun____HASH_Seq__Build__FULL___PrimeGenerationWorksheetRow(); // call lemma_unroll_rec_fun____HASH_Seq__Index__FULL___PrimeGenerationWorksheetRow(); // call lemma_unroll_fun____HASH_Seq__Index__FULL___PrimeGenerationWorksheetRow(); // call lemma_unroll_rec_fun____HASH_Seq__Append__FULL___PrimeGenerationWorksheetRow(); // call lemma_unroll_fun____HASH_Seq__Append__FULL___PrimeGenerationWorksheetRow(); // call lemma_unroll_rec_fun____HASH_Seq__Update__FULL___PrimeGenerationWorksheetRow(); // call lemma_unroll_fun____HASH_Seq__Update__FULL___PrimeGenerationWorksheetRow(); // call lemma_unroll_rec_fun____HASH_Seq__Take__FULL___PrimeGenerationWorksheetRow(); // call lemma_unroll_fun____HASH_Seq__Take__FULL___PrimeGenerationWorksheetRow(); // call lemma_unroll_rec_fun____HASH_Seq__Drop__FULL___PrimeGenerationWorksheetRow(); // call lemma_unroll_fun____HASH_Seq__Drop__FULL___PrimeGenerationWorksheetRow(); // call proc_Seq__Empty__ToZero___PrimeGenerationWorksheetRow(); // call proc_Seq__Empty__FromZero___PrimeGenerationWorksheetRow(); // call proc_Seq__Singleton__Length___PrimeGenerationWorksheetRow(); // call proc_Seq__Build__Length___PrimeGenerationWorksheetRow(); // call proc_Seq__Build__Index___PrimeGenerationWorksheetRow(); // call proc_Seq__Append__Length___PrimeGenerationWorksheetRow(); // call proc_Seq__Index__Singleton___PrimeGenerationWorksheetRow(); // call proc_Seq__Append__Index___PrimeGenerationWorksheetRow(); // call proc_Seq__Update__Length___PrimeGenerationWorksheetRow(); // call proc_Seq__Index__Update___PrimeGenerationWorksheetRow(); // call proc_Seq__Equal__Equiv___PrimeGenerationWorksheetRow(); // call proc_Seq__Take__Length___PrimeGenerationWorksheetRow(); // call proc_Seq__Take__Index___PrimeGenerationWorksheetRow(); // call proc_Seq__Drop__Length___PrimeGenerationWorksheetRow(); // call proc_Seq__Drop__Index___PrimeGenerationWorksheetRow(); // call proc_Seq__Append__TakeDrop___PrimeGenerationWorksheetRow(); // call proc_Seq__Update__CommuteTake1___PrimeGenerationWorksheetRow(); // call proc_Seq__Update__CommuteTake2___PrimeGenerationWorksheetRow(); // call proc_Seq__Update__CommuteDrop1___PrimeGenerationWorksheetRow(); // call proc_Seq__Update__CommuteDrop2___PrimeGenerationWorksheetRow(); // call proc_Seq__Build__CommuteDrop___PrimeGenerationWorksheetRow(); // call proc_Seq__Take__Empty___PrimeGenerationWorksheetRow(); // call proc_Seq__Drop__Empty___PrimeGenerationWorksheetRow(); // call lemma_unroll_rec_fun____HASH_Seq__Length__FULL___RSAKeyGenerationWorksheetRow(); // call lemma_unroll_fun____HASH_Seq__Length__FULL___RSAKeyGenerationWorksheetRow(); // call lemma_fun_ensures_fun_Seq__Length___RSAKeyGenerationWorksheetRow(); // call lemma_unroll_rec_fun____HASH_Seq__Build__FULL___RSAKeyGenerationWorksheetRow(); // call lemma_unroll_fun____HASH_Seq__Build__FULL___RSAKeyGenerationWorksheetRow(); // call lemma_unroll_rec_fun____HASH_Seq__Index__FULL___RSAKeyGenerationWorksheetRow(); // call lemma_unroll_fun____HASH_Seq__Index__FULL___RSAKeyGenerationWorksheetRow(); // call lemma_unroll_rec_fun____HASH_Seq__Append__FULL___RSAKeyGenerationWorksheetRow(); // call lemma_unroll_fun____HASH_Seq__Append__FULL___RSAKeyGenerationWorksheetRow(); // call lemma_unroll_rec_fun____HASH_Seq__Update__FULL___RSAKeyGenerationWorksheetRow(); // call lemma_unroll_fun____HASH_Seq__Update__FULL___RSAKeyGenerationWorksheetRow(); // call lemma_unroll_rec_fun____HASH_Seq__Take__FULL___RSAKeyGenerationWorksheetRow(); // call lemma_unroll_fun____HASH_Seq__Take__FULL___RSAKeyGenerationWorksheetRow(); // call lemma_unroll_rec_fun____HASH_Seq__Drop__FULL___RSAKeyGenerationWorksheetRow(); // call lemma_unroll_fun____HASH_Seq__Drop__FULL___RSAKeyGenerationWorksheetRow(); // call proc_Seq__Empty__ToZero___RSAKeyGenerationWorksheetRow(); // call proc_Seq__Empty__FromZero___RSAKeyGenerationWorksheetRow(); // call proc_Seq__Singleton__Length___RSAKeyGenerationWorksheetRow(); // call proc_Seq__Build__Length___RSAKeyGenerationWorksheetRow(); // call proc_Seq__Build__Index___RSAKeyGenerationWorksheetRow(); // call proc_Seq__Append__Length___RSAKeyGenerationWorksheetRow(); // call proc_Seq__Index__Singleton___RSAKeyGenerationWorksheetRow(); // call proc_Seq__Append__Index___RSAKeyGenerationWorksheetRow(); // call proc_Seq__Update__Length___RSAKeyGenerationWorksheetRow(); // call proc_Seq__Index__Update___RSAKeyGenerationWorksheetRow(); // call proc_Seq__Equal__Equiv___RSAKeyGenerationWorksheetRow(); // call proc_Seq__Take__Length___RSAKeyGenerationWorksheetRow(); // call proc_Seq__Take__Index___RSAKeyGenerationWorksheetRow(); // call proc_Seq__Drop__Length___RSAKeyGenerationWorksheetRow(); // call proc_Seq__Drop__Index___RSAKeyGenerationWorksheetRow(); // call proc_Seq__Append__TakeDrop___RSAKeyGenerationWorksheetRow(); // call proc_Seq__Update__CommuteTake1___RSAKeyGenerationWorksheetRow(); // call proc_Seq__Update__CommuteTake2___RSAKeyGenerationWorksheetRow(); // call proc_Seq__Update__CommuteDrop1___RSAKeyGenerationWorksheetRow(); // call proc_Seq__Update__CommuteDrop2___RSAKeyGenerationWorksheetRow(); // call proc_Seq__Build__CommuteDrop___RSAKeyGenerationWorksheetRow(); // call proc_Seq__Take__Empty___RSAKeyGenerationWorksheetRow(); // call proc_Seq__Drop__Empty___RSAKeyGenerationWorksheetRow(); // call lemma_fun_ensures_fun_Width(); // call lemma_unroll_rec_fun____HASH_Seq__Length__FULL___sub_Problem(); // call lemma_unroll_fun____HASH_Seq__Length__FULL___sub_Problem(); // call lemma_fun_ensures_fun_Seq__Length___sub_Problem(); // call lemma_unroll_rec_fun____HASH_Seq__Build__FULL___sub_Problem(); // call lemma_unroll_fun____HASH_Seq__Build__FULL___sub_Problem(); // call lemma_unroll_rec_fun____HASH_Seq__Index__FULL___sub_Problem(); // call lemma_unroll_fun____HASH_Seq__Index__FULL___sub_Problem(); // call lemma_unroll_rec_fun____HASH_Seq__Append__FULL___sub_Problem(); // call lemma_unroll_fun____HASH_Seq__Append__FULL___sub_Problem(); // call lemma_unroll_rec_fun____HASH_Seq__Update__FULL___sub_Problem(); // call lemma_unroll_fun____HASH_Seq__Update__FULL___sub_Problem(); // call lemma_unroll_rec_fun____HASH_Seq__Take__FULL___sub_Problem(); // call lemma_unroll_fun____HASH_Seq__Take__FULL___sub_Problem(); // call lemma_unroll_rec_fun____HASH_Seq__Drop__FULL___sub_Problem(); // call lemma_unroll_fun____HASH_Seq__Drop__FULL___sub_Problem(); // call proc_Seq__Empty__ToZero___sub_Problem(); // call proc_Seq__Empty__FromZero___sub_Problem(); // call proc_Seq__Singleton__Length___sub_Problem(); // call proc_Seq__Build__Length___sub_Problem(); // call proc_Seq__Build__Index___sub_Problem(); // call proc_Seq__Append__Length___sub_Problem(); // call proc_Seq__Index__Singleton___sub_Problem(); // call proc_Seq__Append__Index___sub_Problem(); // call proc_Seq__Update__Length___sub_Problem(); // call proc_Seq__Index__Update___sub_Problem(); // call proc_Seq__Equal__Equiv___sub_Problem(); // call proc_Seq__Take__Length___sub_Problem(); // call proc_Seq__Take__Index___sub_Problem(); // call proc_Seq__Drop__Length___sub_Problem(); // call proc_Seq__Drop__Index___sub_Problem(); // call proc_Seq__Append__TakeDrop___sub_Problem(); // call proc_Seq__Update__CommuteTake1___sub_Problem(); // call proc_Seq__Update__CommuteTake2___sub_Problem(); // call proc_Seq__Update__CommuteDrop1___sub_Problem(); // call proc_Seq__Update__CommuteDrop2___sub_Problem(); // call proc_Seq__Build__CommuteDrop___sub_Problem(); // call proc_Seq__Take__Empty___sub_Problem(); // call proc_Seq__Drop__Empty___sub_Problem(); // call lemma_unroll_rec_fun____HASH_Seq__Length__FULL___BigNat(); // call lemma_unroll_fun____HASH_Seq__Length__FULL___BigNat(); // call lemma_fun_ensures_fun_Seq__Length___BigNat(); // call lemma_unroll_rec_fun____HASH_Seq__Build__FULL___BigNat(); // call lemma_unroll_fun____HASH_Seq__Build__FULL___BigNat(); // call lemma_unroll_rec_fun____HASH_Seq__Index__FULL___BigNat(); // call lemma_unroll_fun____HASH_Seq__Index__FULL___BigNat(); // call lemma_unroll_rec_fun____HASH_Seq__Append__FULL___BigNat(); // call lemma_unroll_fun____HASH_Seq__Append__FULL___BigNat(); // call lemma_unroll_rec_fun____HASH_Seq__Update__FULL___BigNat(); // call lemma_unroll_fun____HASH_Seq__Update__FULL___BigNat(); // call lemma_unroll_rec_fun____HASH_Seq__Take__FULL___BigNat(); // call lemma_unroll_fun____HASH_Seq__Take__FULL___BigNat(); // call lemma_unroll_rec_fun____HASH_Seq__Drop__FULL___BigNat(); // call lemma_unroll_fun____HASH_Seq__Drop__FULL___BigNat(); // call proc_Seq__Empty__ToZero___BigNat(); // call proc_Seq__Empty__FromZero___BigNat(); // call proc_Seq__Singleton__Length___BigNat(); // call proc_Seq__Build__Length___BigNat(); // call proc_Seq__Build__Index___BigNat(); // call proc_Seq__Append__Length___BigNat(); // call proc_Seq__Index__Singleton___BigNat(); // call proc_Seq__Append__Index___BigNat(); // call proc_Seq__Update__Length___BigNat(); // call proc_Seq__Index__Update___BigNat(); // call proc_Seq__Equal__Equiv___BigNat(); // call proc_Seq__Take__Length___BigNat(); // call proc_Seq__Take__Index___BigNat(); // call proc_Seq__Drop__Length___BigNat(); // call proc_Seq__Drop__Index___BigNat(); // call proc_Seq__Append__TakeDrop___BigNat(); // call proc_Seq__Update__CommuteTake1___BigNat(); // call proc_Seq__Update__CommuteTake2___BigNat(); // call proc_Seq__Update__CommuteDrop1___BigNat(); // call proc_Seq__Update__CommuteDrop2___BigNat(); // call proc_Seq__Build__CommuteDrop___BigNat(); // call proc_Seq__Take__Empty___BigNat(); // call proc_Seq__Drop__Empty___BigNat(); // call lemma_unroll_rec_fun____HASH_Seq__Length__FULL___Problem(); // call lemma_unroll_fun____HASH_Seq__Length__FULL___Problem(); // call lemma_fun_ensures_fun_Seq__Length___Problem(); // call lemma_unroll_rec_fun____HASH_Seq__Build__FULL___Problem(); // call lemma_unroll_fun____HASH_Seq__Build__FULL___Problem(); // call lemma_unroll_rec_fun____HASH_Seq__Index__FULL___Problem(); // call lemma_unroll_fun____HASH_Seq__Index__FULL___Problem(); // call lemma_unroll_rec_fun____HASH_Seq__Append__FULL___Problem(); // call lemma_unroll_fun____HASH_Seq__Append__FULL___Problem(); // call lemma_unroll_rec_fun____HASH_Seq__Update__FULL___Problem(); // call lemma_unroll_fun____HASH_Seq__Update__FULL___Problem(); // call lemma_unroll_rec_fun____HASH_Seq__Take__FULL___Problem(); // call lemma_unroll_fun____HASH_Seq__Take__FULL___Problem(); // call lemma_unroll_rec_fun____HASH_Seq__Drop__FULL___Problem(); // call lemma_unroll_fun____HASH_Seq__Drop__FULL___Problem(); // call proc_Seq__Empty__ToZero___Problem(); // call proc_Seq__Empty__FromZero___Problem(); // call proc_Seq__Singleton__Length___Problem(); // call proc_Seq__Build__Length___Problem(); // call proc_Seq__Build__Index___Problem(); // call proc_Seq__Append__Length___Problem(); // call proc_Seq__Index__Singleton___Problem(); // call proc_Seq__Append__Index___Problem(); // call proc_Seq__Update__Length___Problem(); // call proc_Seq__Index__Update___Problem(); // call proc_Seq__Equal__Equiv___Problem(); // call proc_Seq__Take__Length___Problem(); // call proc_Seq__Take__Index___Problem(); // call proc_Seq__Drop__Length___Problem(); // call proc_Seq__Drop__Index___Problem(); // call proc_Seq__Append__TakeDrop___Problem(); // call proc_Seq__Update__CommuteTake1___Problem(); // call proc_Seq__Update__CommuteTake2___Problem(); // call proc_Seq__Update__CommuteDrop1___Problem(); // call proc_Seq__Update__CommuteDrop2___Problem(); // call proc_Seq__Build__CommuteDrop___Problem(); // call proc_Seq__Take__Empty___Problem(); // call proc_Seq__Drop__Empty___Problem(); // call lemma_unroll_rec_fun_CanonicalizeSeq__def(); // call lemma_unroll_fun_CanonicalizeSeq__def(); // call lemma_fun_ensures_fun_CanonicalizeSeq(); // call lemma_fun_ensures_fun_IsZeroValue(); // call lemma_fun_ensures_fun_SelectDigits(); // call lemma_unroll_rec_fun____HASH_MaxLen__def__FULL(); // call lemma_unroll_fun____HASH_MaxLen__def__FULL(); // call lemma_fun_ensures_fun_MaxLen(); // call lemma_fun_ensures_fun_MaxLen3(); // call lemma_fun_ensures_fun_ArrayDigitAt(); // call lemma_fun_ensures_fun_ArrayDigitAt__add(); // call lemma_fun_ensures_fun_ArrayDigitAt__sub(); // call lemma_fun_ensures_fun_ArrayDigitAt__cmp(); // call lemma_fun_ensures_fun_ArrayDigitAt__mul(); // call lemma_fun_ensures_fun_J(); // call lemma_unroll_rec_fun____HASH_Seq__Length__FULL___MulRow(); // call lemma_unroll_fun____HASH_Seq__Length__FULL___MulRow(); // call lemma_fun_ensures_fun_Seq__Length___MulRow(); // call lemma_unroll_rec_fun____HASH_Seq__Build__FULL___MulRow(); // call lemma_unroll_fun____HASH_Seq__Build__FULL___MulRow(); // call lemma_unroll_rec_fun____HASH_Seq__Index__FULL___MulRow(); // call lemma_unroll_fun____HASH_Seq__Index__FULL___MulRow(); // call lemma_unroll_rec_fun____HASH_Seq__Append__FULL___MulRow(); // call lemma_unroll_fun____HASH_Seq__Append__FULL___MulRow(); // call lemma_unroll_rec_fun____HASH_Seq__Update__FULL___MulRow(); // call lemma_unroll_fun____HASH_Seq__Update__FULL___MulRow(); // call lemma_unroll_rec_fun____HASH_Seq__Take__FULL___MulRow(); // call lemma_unroll_fun____HASH_Seq__Take__FULL___MulRow(); // call lemma_unroll_rec_fun____HASH_Seq__Drop__FULL___MulRow(); // call lemma_unroll_fun____HASH_Seq__Drop__FULL___MulRow(); // call proc_Seq__Empty__ToZero___MulRow(); // call proc_Seq__Empty__FromZero___MulRow(); // call proc_Seq__Singleton__Length___MulRow(); // call proc_Seq__Build__Length___MulRow(); // call proc_Seq__Build__Index___MulRow(); // call proc_Seq__Append__Length___MulRow(); // call proc_Seq__Index__Singleton___MulRow(); // call proc_Seq__Append__Index___MulRow(); // call proc_Seq__Update__Length___MulRow(); // call proc_Seq__Index__Update___MulRow(); // call proc_Seq__Equal__Equiv___MulRow(); // call proc_Seq__Take__Length___MulRow(); // call proc_Seq__Take__Index___MulRow(); // call proc_Seq__Drop__Length___MulRow(); // call proc_Seq__Drop__Index___MulRow(); // call proc_Seq__Append__TakeDrop___MulRow(); // call proc_Seq__Update__CommuteTake1___MulRow(); // call proc_Seq__Update__CommuteTake2___MulRow(); // call proc_Seq__Update__CommuteDrop1___MulRow(); // call proc_Seq__Update__CommuteDrop2___MulRow(); // call proc_Seq__Build__CommuteDrop___MulRow(); // call proc_Seq__Take__Empty___MulRow(); // call proc_Seq__Drop__Empty___MulRow(); //- Standard variable propagation r := r_old; stk := stk_old; statics := statics_old; io := io_old; mems := mems_old; $commonVars := $commonVars_old; $gcVars := $gcVars_old; $toAbs := $toAbs_old; $absMem := $absMem_old; $stacksFrames := $stacksFrames_old; objLayouts := objLayouts_old; heap := heap_old; //- Alignment triggers assert TV(r.regs[ESP]); assert TO(0 - 1); assert TO(279552 - 1); assert TO(0); assert TO(279552); assert TO(1); assert TO(279553); assert TO(2); assert TO(279554); assert TO(3); assert TO(279555); assert TO(4); assert TO(279556); assert TO(5); assert TO(279557); assert TO(6); assert TO(279558); call proc_lemma__mod__properties(); call proc_lemma__2toX(); call proc_lemma__word32__Word32(); call reveal_WORD_HI(); call eax := Load(stk, esp + 12); //- grab aj assert eax == $ghost_aj; call edx := Load(stk, esp + 16); //- grab bv assert edx == $ghost_bv; call edx, eax := Mul64(eax, edx); $ghost_mhi := edx; $ghost_mlo := eax; call reveal_wrap32($ghost_aj * $ghost_bv); assert TVM($ghost_aj, $ghost_bv); assert TVD($ghost_aj * $ghost_bv, 0x100000000); call proc_lemma__asm__Mul64($ghost_aj, $ghost_bv, $ghost_mhi, $ghost_mlo); call ebx := Load(stk, esp + 24); //- grab last carry assert ebx == $ghost_lastcarry; //- add1 (needs to be a direct call to instr_Add to bypass overflow check in logical add call r := instr_Add(r, EAX, OReg(EBX)); //- eax == mlo + lastcarry $ghost_add1 := eax; call reveal_wrap32($ghost_mlo + $ghost_lastcarry); $ghost_carry1 := if $ghost_add1 < $ghost_lastcarry then 1 else 0; assert if Cf(r.efl) then $ghost_carry1 == 1 else $ghost_carry1 == 0; call proc_lemma__asm__Add__properties($ghost_mlo, $ghost_lastcarry, $ghost_add1, $ghost_carry1); //- Add the carry bit to mhi call r := instr_AddCarry(r, EDX, OConst(0)); call reveal_wrap32($ghost_mhi + $ghost_carry1); assert edx == $ghost_mhi + $ghost_carry1; assert !Cf(r.efl); call ebx := Load(stk, esp + 20); //- grab last cj assert eax == wrap32($ghost_mlo + $ghost_lastcarry); assert ebx == $ghost_lastcj; call eax := AddCarry(eax, ebx); //- eax == mlo + lastcarry + lastcj $ghost_newcj := eax; $ghost_carry2 := if (wrap32($ghost_mlo + $ghost_lastcarry) + $ghost_lastcj) >= 0x100000000 then 1 else 0; assert $ghost_newcj == wrap32(wrap32($ghost_mlo + $ghost_lastcarry) + $ghost_lastcj); //- Add the carry bit to mhi call r := instr_AddCarry(r, EDX, OConst(0)); //-call reveal_wrap32($ghost_mhi + $ghost_carry1 + $ghost_carry2); //-assert edx == $ghost_mhi + $ghost_carry1 + $ghost_carry2; assert edx == wrap32($ghost_mhi + $ghost_carry1 + $ghost_carry2); //- Write back the results $ghost_newcj := eax; $ghost_newcarry := edx; call Store(inout stk, esp+4, eax); call Store(inout stk, esp+8, edx); // call proc_lemma__FleetNatMul__one__element__properties(4294967296, $ghost_aj, $ghost_bv, $ghost_mhi, $ghost_mlo, $ghost_lastcarry, $ghost_add1, $ghost_carry1, $ghost_lastcj, $ghost_newcj, $ghost_carry2, $ghost_add3, $ghost_carry3, $ghost_newcarry, $ghost_carry4); assert $ghost_carry2 == if (wrap32($ghost_mlo + $ghost_lastcarry) + $ghost_lastcj) >= 0x100000000 then 1 else 0; call reveal_wrap32($ghost_mlo + $ghost_lastcarry); assert $ghost_carry2 == if (($ghost_mlo + $ghost_lastcarry) mod 0x100000000 + $ghost_lastcj) >= 0x100000000 then 1 else 0; assert $ghost_newcj == wrap32(wrap32($ghost_mlo + $ghost_lastcarry) + $ghost_lastcj); assert $ghost_newcj == wrap32(($ghost_mlo + $ghost_lastcarry) mod 0x100000000 + $ghost_lastcj); call reveal_wrap32(($ghost_mlo + $ghost_lastcarry) mod 0x100000000 + $ghost_lastcj); assert $ghost_newcj == (($ghost_mlo + $ghost_lastcarry) mod 0x100000000+ $ghost_lastcj) mod 0x100000000; assert $ghost_newcarry == wrap32($ghost_mhi + $ghost_carry1 + $ghost_carry2); call reveal_wrap32($ghost_mhi + $ghost_carry1 + $ghost_carry2); assert $ghost_newcarry == ($ghost_mhi + $ghost_carry1 + $ghost_carry2) mod 0x100000000; assert {:split_here} true; Return; } } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Main/dafny_assembly_i.imp.beat ================================================ //- //-private-import BaseSpec; //-private-import MemorySpec; //-private-import IoTypesSpec; //-private-import MachineStateSpec; //-private-import AssemblySpec; //-private-import InterruptsSpec; //-private-import IoSpec; //- //- //- //- //- //-private-import Core; //-private-import LogicalAddressing; //-private-import Overflow; //-private-import Util; //-private-import Stacks; //-private-import Partition; //-private-import Instructions; //-private-import Separation; //-private-import IntLemmasBase; //-private-import IntLemmasGc; //-private-import SimpleGcMemory; //-private-import SimpleCommon; //-private-import SimpleCollector; //-private-import IoMain; //-private-import IntLemmasMain; //-private-basmonly-import Trusted; //-private-basmonly-import Checked; //-private-import Heap; //-private-import Seq; //-private-import dafny_DafnyPrelude; //-private-import DafnyAssembly; //-private-import dafny_base_s; //-private-import dafny_relational_s; //- //- //- module implementation dafny_assembly_i { implementation proc_lemma__word32($ghost_x:int) returns() { call reveal_WORD_HI(); } //function implementation fun_IntBit($ghost_index:int, $ghost_n:int):bool //{ // int_bit($ghost_n, 31 - $ghost_index) // IntBit is big endian, int_bit is little endian //} implementation proc_lemma__IntBit($ghost_index:int, $ghost_val:int) returns() { call reveal_int_bit($ghost_val, 31 - $ghost_index); } implementation proc_lemma__mod0x100000000($ghost_x:int) returns() { } implementation proc_method__Mul(my r_old:regs, $ghost_x:int, $ghost_y:int, $opn_hi:int, $opn_x:int, $opn_y:opn) returns(my r:regs, $ghost_hi:int, $ghost_r:int) { r := r_old; call r := instr_MulChecked(r, $opn_y); assert TVM($ghost_x, $ghost_y); $ghost_r := r.regs[EAX]; $ghost_hi := r.regs[EDX]; } implementation proc_method__DivMod(my r_old:regs, $ghost_zero:int, $ghost_x:int, $ghost_y:int, $opn_zero:int, $opn_x:int, $opn_y:opn) returns(my r:regs, $ghost_m:int, $ghost_d:int) { r := r_old; call r := instr_Div(r, $opn_y); $ghost_d := r.regs[EAX]; $ghost_m := r.regs[EDX]; } implementation Proc_asm__Rdtsc(my r_old:regs, const my core_state:core_state, linear stk_old:mem, linear statics_old:mem, linear io_old:IOState, linear mems_old:mems, $commonVars_old:commonVars, $gcVars_old:gcVars, $toAbs_old:[int]int, $absMem_old:[int][int]int, $stacksFrames_old:[int]Frames, objLayouts_old:[int]ObjLayout, heap_old:Heap) returns(my r:regs, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars, $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap, $ghost_high:int, $ghost_low:int) { r := r_old; stk := stk_old; statics := statics_old; io := io_old; mems := mems_old; $commonVars := $commonVars_old; $gcVars := $gcVars_old; $toAbs := $toAbs_old; $absMem := $absMem_old; $stacksFrames := $stacksFrames_old; objLayouts := objLayouts_old; heap := heap_old; assert TV(esp) && TO(0) && TO(1) && TO(2) && TO(3); call Rdtsc(); call Store(inout stk, esp + IPSize, edx); call Store(inout stk, esp + (4 + IPSize), eax); $ghost_high := edx; $ghost_low := eax; Return; } implementation Proc_asm__declassify__result(my r_old:regs, const my core_state:core_state, linear stk_old:mem, linear statics_old:mem, linear io_old:IOState, linear mems_old:mems, $commonVars_old:commonVars, $gcVars_old:gcVars, $toAbs_old:[int]int, $absMem_old:[int][int]int, $stacksFrames_old:[int]Frames, objLayouts_old:[int]ObjLayout, heap_old:Heap, $ghost_concrete:int, $ghost_result:int) returns(my r:regs, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars, $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap, $ghost_pub_result:int) { r := r_old; stk := stk_old; statics := statics_old; io := io_old; mems := mems_old; $commonVars := $commonVars_old; $gcVars := $gcVars_old; $toAbs := $toAbs_old; $absMem := $absMem_old; $stacksFrames := $stacksFrames_old; objLayouts := objLayouts_old; heap := heap_old; assert TV(esp) && TO(0) && TO(1) && TO(2) && TO(3) && TO(4); call eax := Load(stk, esp + (4 + IPSize)); // Grab the concrete value off the stack assert eax == $ghost_concrete; call r := declassify(r, EAX, $ghost_result); assert eax == $ghost_result; call Store(inout stk, esp + IPSize, eax); $ghost_pub_result := eax; Return; } implementation Proc_GetBootloaderArgWord(my r_old:regs, const my core_state:core_state, linear stk_old:mem, linear statics_old:mem, linear io_old:IOState, linear mems_old:mems, $commonVars_old:commonVars, $gcVars_old:gcVars, $toAbs_old:[int]int, $absMem_old:[int][int]int, $stacksFrames_old:[int]Frames, objLayouts_old:[int]ObjLayout, heap_old:Heap, $ghost_index:int) returns(my r:regs, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars, $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap, $ghost_word:int) { r := r_old; stk := stk_old; statics := statics_old; io := io_old; mems := mems_old; $commonVars := $commonVars_old; $gcVars := $gcVars_old; $toAbs := $toAbs_old; $absMem := $absMem_old; $stacksFrames := $stacksFrames_old; objLayouts := objLayouts_old; heap := heap_old; assert TV(esp) && TO(0) && TO(1) && TO(2) && TO(3); call eax := Load(stk, esp + (4 + IPSize)); assert eax == $ghost_index; ebx := 4; call eax,edx := Mul(eax, ebx); //- Convert to bytes assert eax == wrap32(Mult($ghost_index, 4)); //- Prove that we can convert this into eax == $ghost_index * 4 assert TVM($ghost_index, 4); //- Reveals Mult call reveal_wrap32($ghost_index * 4); call reveal_WORD_HI(); assert eax == $ghost_index * 4; call reveal_MemInvDetails(); //- Shows that ArgLo is sane ebx := ArgLo; call ebx := AddChecked(ebx, eax); assert Aligned(ArgLo); assert TV(ArgLo) && TO($ghost_index); //- Show that ebx is Aligned call edx := Load(mems.arg, ebx); //call edx := Load(arg, ebx); call Store(inout stk, esp + IPSize, edx); $ghost_word := edx; Return; } } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Main/dafny_bit_vector_lemmas_i.imp.beat ================================================ //-private-import BaseSpec; //-private-import MemorySpec; //-private-import IoTypesSpec; //-private-import MachineStateSpec; //-private-import AssemblySpec; //-private-import InterruptsSpec; //-private-import IoSpec; //- //- //- //- //- //-private-import Core; //-private-import LogicalAddressing; //-private-import Overflow; //-private-import Util; //-private-import Stacks; //-private-import Partition; //-private-import Separation; //-private-import IntLemmasBase; //-private-import IntLemmasGc; //-private-import SimpleGcMemory; //-private-import SimpleCommon; //-private-import SimpleCollector; //-private-import IoMain; //-private-import IntLemmasMain; //-private-basmonly-import Trusted; //-private-basmonly-import Checked; //-private-import Heap; //-private-import Seq; //-private-import dafny_DafnyPrelude; //-private-import DafnyAssembly; //-private-import dafny_base_s; //-private-import dafny_relational_s; //-private-import dafny_assembly_i; //- //- //- module implementation dafny_bit_vector_lemmas_i { implementation proc_lemma__and__with__ff($ghost_x:int) returns() { call lemma_and_with_ff($ghost_x); } implementation proc_lemma__and__with__ffff($ghost_x:int) returns() { call lemma_and_with_ffff($ghost_x); } implementation proc_lemma__xor__bytes(x:int, y:int) { call lemma_xor_bytes(x, y); } implementation proc_lemma__and__with__32__64(x:int) { call lemma_and_with_32_64(x); } } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Main/dafny_io_mem_i.imp.beat ================================================ //- //-private-import BaseSpec; //-private-import MemorySpec; //-private-import IoTypesSpec; //-private-import MachineStateSpec; //-private-import AssemblySpec; //-private-import InterruptsSpec; //-private-import IoSpec; //- //- //- //- //- //-private-import Core; //-private-import LogicalAddressing; //-private-import Overflow; //-private-import Util; //-private-import Stacks; //-private-import Partition; //-private-import Instructions; //-private-import Separation; //-private-import IntLemmasBase; //-private-import IntLemmasGc; //-private-import SimpleGcMemory; //-private-import SimpleCommon; //-private-import SimpleCollector; //-private-import IoMain; //-private-import IntLemmasMain; //-private-basmonly-import Trusted; //-private-basmonly-import Checked; //-private-import Heap; //-private-import Seq; //-private-import dafny_DafnyPrelude; //-private-import DafnyAssembly; //-private-import dafny_io_mem_s; //- //- //- module implementation dafny_io_mem_i { implementation Proc_IoMemAddrRead(my r_old:regs, const my core_state:core_state, linear stk_old:mem, linear statics_old:mem, linear io_old:IOState, linear mems_old:mems, $commonVars_old:commonVars, $gcVars_old:gcVars, $toAbs_old:[int]int, $absMem_old:[int][int]int, $stacksFrames_old:[int]Frames, objLayouts_old:[int]ObjLayout, heap_old:Heap, $ghost_r_addr:int) returns(my r:regs, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars, $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap, $ghost_r_val:int) { var $absMem_tmp:[int][int]int; var objLayouts_tmp:[int]ObjLayout; var heap_tmp:Heap; var obj_tmp:int; var val_tmp:int; var mem_tmp:[int]int; assert fun_unroll(0); assert fun_unroll(1); r := r_old; stk := stk_old; statics := statics_old; io := io_old; mems := mems_old; $commonVars := $commonVars_old; $gcVars := $gcVars_old; $toAbs := $toAbs_old; $absMem := $absMem_old; $stacksFrames := $stacksFrames_old; objLayouts := objLayouts_old; heap := heap_old; assert TV(esp); assert TO(0); assert TO(768); assert TO(1); assert TO(769); assert TO(2); assert TO(770); //- Read arguments off the stack call edx := Load(stk, esp + 8); //- r_addr call ecx := IoMemAddrRead(edx); call Store(inout stk, esp + 4, ecx); $ghost_r_val := ecx; //- dummy method body for axiom Return; } implementation Proc_IoMemAddrWrite(my r_old:regs, const my core_state:core_state, linear stk_old:mem, linear statics_old:mem, linear io_old:IOState, linear mems_old:mems, $commonVars_old:commonVars, $gcVars_old:gcVars, $toAbs_old:[int]int, $absMem_old:[int][int]int, $stacksFrames_old:[int]Frames, objLayouts_old:[int]ObjLayout, heap_old:Heap, $ghost_w_addr:int, $ghost_w_val:int) returns(my r:regs, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars, $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap) { var $absMem_tmp:[int][int]int; var objLayouts_tmp:[int]ObjLayout; var heap_tmp:Heap; var obj_tmp:int; var val_tmp:int; var mem_tmp:[int]int; assert fun_unroll(0); assert fun_unroll(1); r := r_old; stk := stk_old; statics := statics_old; io := io_old; mems := mems_old; $commonVars := $commonVars_old; $gcVars := $gcVars_old; $toAbs := $toAbs_old; $absMem := $absMem_old; $stacksFrames := $stacksFrames_old; objLayouts := objLayouts_old; heap := heap_old; assert TV(esp); assert TO(0); assert TO(768); assert TO(1); assert TO(769); assert TO(2); assert TO(770); //- Read arguments off the stack call ebx := Load(stk, esp + 4); //- w_addr call edx := Load(stk, esp + 8); //- w_val call IoMemAddrWrite(ebx, edx); //- dummy method body for axiom Return; } } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Main/dafny_pci_i.imp.beat ================================================ //- //-private-import BaseSpec; //-private-import MemorySpec; //-private-import IoTypesSpec; //-private-import MachineStateSpec; //-private-import AssemblySpec; //-private-import InterruptsSpec; //-private-import IoSpec; //- //- //- //- //- //-private-import Core; //-private-import LogicalAddressing; //-private-import Overflow; //-private-import Util; //-private-import Stacks; //-private-import Partition; //-private-import Instructions; //-private-import Separation; //-private-import IntLemmasBase; //-private-import IntLemmasGc; //-private-import SimpleGcMemory; //-private-import SimpleCommon; //-private-import SimpleCollector; //-private-import IoMain; //-private-import IntLemmasMain; //-private-basmonly-import Trusted; //-private-basmonly-import Checked; //-private-import Heap; //-private-import Seq; //-private-import dafny_DafnyPrelude; //-private-import DafnyAssembly; //-private-import PCI; //-private-import IntelNIC; //-private-import dafny_relational_s; //-private-import dafny_base_s; //-private-import dafny_power2_s; //-private-import dafny_bytes_and_words_s; //- //- //- module implementation dafny_pci_i { implementation proc_reveal__mod4() { forall $ghost_n:int::fun_mod4($ghost_n) == fun____HASH_mod4__FULL($ghost_n) { assert unhide_fun_mod4($ghost_n); } } implementation proc_reveal__mod16() { forall $ghost_n:int::fun_mod16($ghost_n) == fun____HASH_mod16__FULL($ghost_n) { assert unhide_fun_mod16($ghost_n); } } implementation proc_reveal__mod128() { forall $ghost_n:int::fun_mod128($ghost_n) == fun____HASH_mod128__FULL($ghost_n) { assert unhide_fun_mod128($ghost_n); } } implementation proc_reveal__div16() { forall $ghost_n:int::fun_div16($ghost_n) == fun____HASH_div16__FULL($ghost_n) { assert unhide_fun_div16($ghost_n); } } function implementation fun_IsValidPciId($ghost_id:int):bool { IsValidPciId($ghost_id) } function implementation fun_PciMemAddr($ghost_id:int):int { PciMemAddr($ghost_id) } function implementation fun_PciMemSize($ghost_id:int):int { PciMemSize($ghost_id) } function implementation fun_DeviceMemAddr():int { ?devMemLo } function implementation fun_DeviceMemSize():int { ?devMemHi - ?devMemLo } implementation Proc_NetworkPciMemSetup(my r_old:regs, const my core_state:core_state, linear stk_old:mem, linear statics_old:mem, linear io_old:IOState, linear mems_old:mems, $commonVars_old:commonVars, $gcVars_old:gcVars, $toAbs_old:[int]int, $absMem_old:[int][int]int, $stacksFrames_old:[int]Frames, objLayouts_old:[int]ObjLayout, heap_old:Heap) returns(my r:regs, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars, $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap, $ghost_id:int, $ghost_size:int, $ghost_addr:int, $ghost_device_mem_addr:int) { var $absMem_tmp:[int][int]int; var objLayouts_tmp:[int]ObjLayout; var heap_tmp:Heap; var obj_tmp:int; var val_tmp:int; var mem_tmp:[int]int; assert fun_unroll(0); assert fun_unroll(1); r := r_old; stk := stk_old; statics := statics_old; io := io_old; mems := mems_old; $commonVars := $commonVars_old; $gcVars := $gcVars_old; $toAbs := $toAbs_old; $absMem := $absMem_old; $stacksFrames := $stacksFrames_old; objLayouts := objLayouts_old; heap := heap_old; assert TV(esp); assert TO(0); assert TO(768); assert TO(1); assert TO(769); assert TO(2); assert TO(770); assert TO(3); assert TO(771); assert TO(4); assert TO(772); call map_network_card(); edx := eax; call Store(inout stk, esp + 4, ecx); $ghost_id := ecx; call Store(inout stk, esp + 8, edx); $ghost_size := edx; call Store(inout stk, esp + 12, ebx); $ghost_addr := ebx; call reveal_IoInv(); assert IoInv_Transparent($IoVars, $pciMem); call reveal_WORD_HI(); call proc_lemma__power2__32(); // edx := SLo; // == ?memLo // assert edx == ?memLo; // assert ?memHi == ?devMemLo; // assert ?memHi == ?memLo + 0x7400; // //// assert ?devMemHi - ?devMemLo > 0x204004; //// assert ?devMemLo >= 0; //// assert word(edx); //// assert word(?devMemHi); //// assert word(?devMemLo); // // call edx := Add(edx, 0x7400); // == ?memHi == ?devMemLo // // assert edx == ?devMemLo; edx := 0x08000000; call Store(inout stk, esp + 16, edx); $ghost_device_mem_addr := edx; assert ?devMemLo mod 0x10000 == 0; call proc_reveal__mod16(); // Need to reveal it, so we can prove it's true // dummy method body for axiom Return; } implementation Proc_PciMemStore(my r_old:regs, const my core_state:core_state, linear stk_old:mem, linear statics_old:mem, linear io_old:IOState, linear mems_old:mems, $commonVars_old:commonVars, $gcVars_old:gcVars, $toAbs_old:[int]int, $absMem_old:[int][int]int, $stacksFrames_old:[int]Frames, objLayouts_old:[int]ObjLayout, heap_old:Heap, $ghost_id:int, $ghost_dst:int, $ghost_val:int) returns(my r:regs, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars, $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap) { call reveal_MemInvDetails(); var $absMem_tmp:[int][int]int; var objLayouts_tmp:[int]ObjLayout; var heap_tmp:Heap; var obj_tmp:int; var val_tmp:int; var mem_tmp:[int]int; assert fun_unroll(0); assert fun_unroll(1); r := r_old; stk := stk_old; statics := statics_old; io := io_old; mems := mems_old; $commonVars := $commonVars_old; $gcVars := $gcVars_old; $toAbs := $toAbs_old; $absMem := $absMem_old; $stacksFrames := $stacksFrames_old; objLayouts := objLayouts_old; heap := heap_old; assert TV(esp); assert TO(0); assert TO(768); assert TO(1); assert TO(769); assert TO(2); assert TO(770); assert TO(3); assert TO(771); //- Read arguments off the stack call ebx := Load(stk, esp + 4); //- id call ecx := Load(stk, esp + 8); //- dst call edx := Load(stk, esp + 12); //- val //- Setup args to lookupMapping to ensure we've configured this device esi := ebx; edi := PciLo; edx := edi; call edx := Add(edx, 1024); //- == ?pciHi call lookupMapping(ebx, edi, edx); if (ecx != 1) { //- Failed to find the mapping! eax := 0x55550050; call debugBreak(); } //- Re-read arguments off the stack call ebx := Load(stk, esp + 4); //- id call ecx := Load(stk, esp + 8); //- dst call edx := Load(stk, esp + 12); //- val call reveal_IoInv(); assert IoInv_Transparent($IoVars, $pciMem); call PciMemStore32(ebx, ecx, edx); call reveal_IoInv(); // assert $pciMem == old($pciMem); // assert io._pci == old(io._pci); // assert IoInv_Transparent($IoVars, $pciMem); // assert &&& &&& (forall addr:int, j:int::{$pciMem[addr],TV(j)} TV(j) && 0 <= j && // addr == ?pciLo + 16*j && addr <= ?pciHi - 16 ==> // (IsValidPciId($pciMem[addr]) ==> // $pciMem[addr + 4] == PciMemAddr($pciMem[addr]) // && $pciMem[addr + 8] == PciMemSize($pciMem[addr]) // && SafePciMemRegion(PciMemAddr($pciMem[addr]), PciMemSize($pciMem[addr])) // && io._pci.PciConfigState[$pciMem[addr]] == 4 )); // assert &&& &&& IoInv_Transparent($IoVars, $pciMem); // assert &&& &&& NucleusInv(objLayouts,$S,$toAbs,$absMem,$commonVars__id,$gcVars__id,$ioVars__id,$commonVars,$gcVars,me,init,$State,core,ptOwner__id,(mem.map),$part,my_part,$mem__id,$sepVars__id,mems,$sepVars,$stacksFrames,state._io,$ioVars); // dummy method body for axiom Return; } implementation Proc_PciMemLoad(my r_old:regs, const my core_state:core_state, linear stk_old:mem, linear statics_old:mem, linear io_old:IOState, linear mems_old:mems, $commonVars_old:commonVars, $gcVars_old:gcVars, $toAbs_old:[int]int, $absMem_old:[int][int]int, $stacksFrames_old:[int]Frames, objLayouts_old:[int]ObjLayout, heap_old:Heap, $ghost_id:int, $ghost_src:int) returns(my r:regs, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars, $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap, $ghost_val:int) { call reveal_MemInvDetails(); var $absMem_tmp:[int][int]int; var objLayouts_tmp:[int]ObjLayout; var heap_tmp:Heap; var obj_tmp:int; var val_tmp:int; var mem_tmp:[int]int; assert fun_unroll(0); assert fun_unroll(1); r := r_old; stk := stk_old; statics := statics_old; io := io_old; mems := mems_old; $commonVars := $commonVars_old; $gcVars := $gcVars_old; $toAbs := $toAbs_old; $absMem := $absMem_old; $stacksFrames := $stacksFrames_old; objLayouts := objLayouts_old; heap := heap_old; assert TV(esp); assert TO(0); assert TO(768); assert TO(1); assert TO(769); assert TO(2); assert TO(770); assert TO(3); assert TO(771); call ecx := Load(stk, esp + 8); //- id call edx := Load(stk, esp + 12); //- src //- Setup args to lookupMapping to ensure we've configured this device esi := ecx; edi := PciLo; edx := edi; call edx := Add(edx, 1024); //- == ?pciHi call lookupMapping(ecx, edi, edx); if (ecx != 1) { //- Failed to find the mapping! eax := 0x55550051; call debugBreak(); } //- Re-read arguments off the stack call ecx := Load(stk, esp + 8); //- id call edx := Load(stk, esp + 12); //- src call reveal_IoInv(); assert IoInv_Transparent($IoVars, $pciMem); call ebx := PciMemLoad32(ecx, edx); assert word(ebx); call reveal_IoInv(); //- Store the return val call Store(inout stk, esp + 4, ebx); $ghost_val := ebx; assert word(ebx); call reveal_WORD_HI(); call proc_lemma__power2__32(); // dummy method body for axiom Return; } implementation proc_DeviceMemStore(my r_old:regs, linear io_old:IOState, objLayouts:[int]ObjLayout, $S:int, $toAbs:[int]int, $absMem:[int][int]int, $commonVars:commonVars, $gcVars:gcVars, init:bool, stk:mem, statics:mem, core_state:core_state, ptMem:mem, mems:mems, $stacksFrames:[int]Frames, $ghost_dst:int, $ghost_val:int, $opn_dst:opn_mem, $opn_val:opn) returns(my r:regs, linear io:IOState) { r := r_old; io := io_old; call reveal_IoInv(); assert IoInv_Transparent($IoVars, $pciMem); call io := instr_DeviceStore(r, io, $opn_dst, $opn_val); call reveal_IoInv(); } implementation proc_DeviceMemLoad(my r_old:regs, linear io_old:IOState, objLayouts:[int]ObjLayout, $S:int, $toAbs:[int]int, $absMem:[int][int]int, $commonVars:commonVars, $gcVars:gcVars, init:bool, stk:mem, statics:mem, core_state:core_state, ptMem:mem, mems:mems, $stacksFrames:[int]Frames, $ghost_src:int, $opn_src:opn_mem, $opn_val:int) returns(my r:regs, linear io:IOState, $ghost_val:int) { r := r_old; io := io_old; call reveal_IoInv(); assert IoInv_Transparent($IoVars, $pciMem); call r, io := instr_DeviceLoad(r, io, $opn_val, $opn_src); call reveal_IoInv(); call reveal_WORD_HI(); call proc_lemma__power2__32(); $ghost_val := r.regs[$opn_val]; } //implementation Proc_little__endian__bytes__to__word(my r_old:regs, const my core_state:core_state, linear stk_old:mem, linear statics_old:mem, linear io_old:IOState, linear mems_old:mems, $commonVars_old:commonVars, $gcVars_old:gcVars, $toAbs_old:[int]int, $absMem_old:[int][int]int, $stacksFrames_old:[int]Frames, objLayouts_old:[int]ObjLayout, heap_old:Heap, $ghost_bytes:Seq___int) returns(my r:regs, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars, $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap, $ghost_w:int) //{ // var $absMem_tmp:[int][int]int; // var objLayouts_tmp:[int]ObjLayout; // var heap_tmp:Heap; // var obj_tmp:int; // var val_tmp:int; // var mem_tmp:[int]int; // var $ghost_bytes__abs:int; // assert fun_unroll(0); // assert fun_unroll(1); // call lemma_fun_ensures_fun_asm__Add(); // call lemma_fun_ensures_fun_asm__Sub(); // call lemma_fun_ensures_fun_asm__Mul(); // call lemma_fun_ensures_fun_asm__Div(); // call lemma_fun_ensures_fun_asm__Mod(); // call lemma_fun_ensures_fun_asm__LeftShift(); // call lemma_fun_ensures_fun_asm__RightShift(); // call lemma_fun_ensures_fun_asm__RotateLeft(); // call lemma_fun_ensures_fun_asm__RotateRight(); // call lemma_fun_ensures_fun_asm__BitwiseNot(); // call lemma_fun_ensures_fun_asm__BitwiseAnd(); // call lemma_fun_ensures_fun_asm__BitwiseOr(); // call lemma_fun_ensures_fun_asm__BitwiseXor(); // call lemma_unroll_fun_INTERNAL__mul__pos(); // call lemma_unroll_fun_INTERNAL__mod__recursive(); // call lemma_unroll_fun_INTERNAL__div__pos(); // call lemma_unroll_fun_Seq__Length__FULL___int(); // call lemma_fun_ensures_fun_Seq__Length___int(); // call lemma_unroll_fun_Seq__Build__FULL___int(); // call lemma_unroll_fun_Seq__Index__FULL___int(); // call lemma_unroll_fun_Seq__Append__FULL___int(); // call lemma_unroll_fun_Seq__Update__FULL___int(); // call lemma_unroll_fun_Seq__Take__FULL___int(); // call lemma_unroll_fun_Seq__Drop__FULL___int(); // call proc_Seq__Empty__ToZero___int(); // call proc_Seq__Empty__FromZero___int(); // call proc_Seq__Singleton__Length___int(); // call proc_Seq__Build__Length___int(); // call proc_Seq__Build__Index___int(); // call proc_Seq__Append__Length___int(); // call proc_Seq__Index__Singleton___int(); // call proc_Seq__Append__Index___int(); // call proc_Seq__Update__Length___int(); // call proc_Seq__Index__Update___int(); // call proc_Seq__Equal__Equiv___int(); // call proc_Seq__Take__Length___int(); // call proc_Seq__Take__Index___int(); // call proc_Seq__Drop__Length___int(); // call proc_Seq__Drop__Index___int(); // call proc_Seq__Append__TakeDrop___int(); // call proc_Seq__Update__CommuteTake1___int(); // call proc_Seq__Update__CommuteTake2___int(); // call proc_Seq__Update__CommuteDrop1___int(); // call proc_Seq__Update__CommuteDrop2___int(); // call proc_Seq__Build__CommuteDrop___int(); // call proc_Seq__Take__Empty___int(); // call proc_Seq__Drop__Empty___int(); // call lemma_unroll_fun_Seq__FromArrayRange(); // call proc_Seq__FromArray__Length(); // call proc_Seq__FromArray__Index(); // call proc_Seq__FromArray__Update(); // call lemma_unroll_fun_power2__FULL(); // call lemma_fun_ensures_fun_power2(); // call lemma_unroll_fun_BEDigitSeq__IntValue__FULL(); // call lemma_unroll_fun_Seq__Length__FULL___bool(); // call lemma_fun_ensures_fun_Seq__Length___bool(); // call lemma_unroll_fun_Seq__Build__FULL___bool(); // call lemma_unroll_fun_Seq__Index__FULL___bool(); // call lemma_unroll_fun_Seq__Append__FULL___bool(); // call lemma_unroll_fun_Seq__Update__FULL___bool(); // call lemma_unroll_fun_Seq__Take__FULL___bool(); // call lemma_unroll_fun_Seq__Drop__FULL___bool(); // call proc_Seq__Empty__ToZero___bool(); // call proc_Seq__Empty__FromZero___bool(); // call proc_Seq__Singleton__Length___bool(); // call proc_Seq__Build__Length___bool(); // call proc_Seq__Build__Index___bool(); // call proc_Seq__Append__Length___bool(); // call proc_Seq__Index__Singleton___bool(); // call proc_Seq__Append__Index___bool(); // call proc_Seq__Update__Length___bool(); // call proc_Seq__Index__Update___bool(); // call proc_Seq__Equal__Equiv___bool(); // call proc_Seq__Take__Length___bool(); // call proc_Seq__Take__Index___bool(); // call proc_Seq__Drop__Length___bool(); // call proc_Seq__Drop__Index___bool(); // call proc_Seq__Append__TakeDrop___bool(); // call proc_Seq__Update__CommuteTake1___bool(); // call proc_Seq__Update__CommuteTake2___bool(); // call proc_Seq__Update__CommuteDrop1___bool(); // call proc_Seq__Update__CommuteDrop2___bool(); // call proc_Seq__Build__CommuteDrop___bool(); // call proc_Seq__Take__Empty___bool(); // call proc_Seq__Drop__Empty___bool(); // call lemma_unroll_fun_SeqToInt__FULL(); // call lemma_fun_ensures_fun_SeqToInt(); // call lemma_unroll_fun_IntToSeq__FULL(); // call lemma_fun_ensures_fun_IntToSeq(); // call lemma_fun_ensures_fun_WordToSeq(); // call lemma_fun_ensures_fun_word__to__bytes(); // call lemma_unroll_fun_WordSeqToByteSeq__FULL(); // call lemma_fun_ensures_fun_WordSeqToByteSeq(); // call lemma_fun_ensures_fun_ByteSeqToWordSeq(); // call lemma_unroll_fun_WordSeqToBits__FULL(); // call lemma_fun_ensures_fun_WordSeqToBits(); // call lemma_unroll_fun_WordSeqToNBits__FULL(); // call lemma_fun_ensures_fun_WordSeqToNBits(); // call lemma_fun_ensures_fun_ArrayToBitSequence(); // call lemma_unroll_fun_SequenceOfFalses__FULL(); // call lemma_fun_ensures_fun_SequenceOfFalses(); // call lemma_unroll_fun_ByteToBoolSeqInner__FULL(); // call lemma_fun_ensures_fun_ByteToBoolSeqInner(); // call lemma_fun_ensures_fun_ByteToBoolSeq(); // call lemma_unroll_fun_ByteSeqToBoolSeq__FULL(); // call lemma_fun_ensures_fun_ByteSeqToBoolSeq(); // call lemma_fun_ensures_fun_AddInstruction(); // call lemma_fun_ensures_fun_SubInstruction(); // call lemma_fun_ensures_fun_LeftShiftInstruction(); // call lemma_fun_ensures_fun_RightShiftInstruction(); // call lemma_fun_ensures_fun_RotateRightInstruction(); // call lemma_fun_ensures_fun_RotateLeftInstruction(); // call lemma_fun_ensures_fun_BitwiseNotInstruction(); // call lemma_fun_ensures_fun_BitwiseAndInstruction(); // call lemma_fun_ensures_fun_BitwiseOrInstruction(); // call lemma_fun_ensures_fun_BitwiseXorInstruction(); // call lemma_unroll_fun_power__FULL(); // r := r_old; // stk := stk_old; // statics := statics_old; // io := io_old; // mems := mems_old; // $commonVars := $commonVars_old; // $gcVars := $gcVars_old; // $toAbs := $toAbs_old; // $absMem := $absMem_old; // $stacksFrames := $stacksFrames_old; // objLayouts := objLayouts_old; // heap := heap_old; // $ghost_bytes__abs := frameGet($stacksFrames, (core_old._regs)[ESP] + 4 + stackGcOffset); // assert TV(esp); // assert TO(0); // assert TO(768); // assert TO(1); // assert TO(769); // // // dummy method body for axiom // Return; //} implementation Proc_debug__print(my r_old:regs, const my core_state:core_state, linear stk_old:mem, linear statics_old:mem, linear io_old:IOState, linear mems_old:mems, $commonVars_old:commonVars, $gcVars_old:gcVars, $toAbs_old:[int]int, $absMem_old:[int][int]int, $stacksFrames_old:[int]Frames, objLayouts_old:[int]ObjLayout, heap_old:Heap, $ghost_loc:int, $ghost_val:int) returns(my r:regs, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars, $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap) { var $absMem_tmp:[int][int]int; var objLayouts_tmp:[int]ObjLayout; var heap_tmp:Heap; var obj_tmp:int; var val_tmp:int; var mem_tmp:[int]int; assert fun_unroll(0); assert fun_unroll(1); r := r_old; stk := stk_old; statics := statics_old; io := io_old; mems:= mems_old; $commonVars := $commonVars_old; $gcVars := $gcVars_old; $toAbs := $toAbs_old; $absMem := $absMem_old; $stacksFrames := $stacksFrames_old; objLayouts := objLayouts_old; heap := heap_old; assert TV(esp); assert TO(0); assert TO(768); assert TO(1); assert TO(769); assert TO(2); assert TO(770); //- Read arguments off the stack call ebx := Load(stk, esp + 4); //- loc call ecx := Load(stk, esp + 8); //- val ebp := ecx; //- Save a copy //- Assuming for now that loc (in ebx) is only 8 bits call reveal_IoInv(); //- Prove that serial port has been configured call serialDbgByteOut(); //- Write out a space ecx := 32; call serialDbgDataOut8(); //- Write out val esi := ebp; call serialDbgWordOut(); call serialDbgNewlineOut(); //- call Proc_SerialDbgWordOut(); //- call Proc_SerialDbgNewlineOut(); //- Re-read arguments off the stack call ebx := Load(stk, esp + 4); //- loc call ecx := Load(stk, esp + 8); //- val //- Write to the screen eax := ecx; edx := ebx; call writeHex(); Return; } } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Main/dafny_sha256opt2_i.imp.beat ================================================ //-private-import BaseSpec; //-private-import MemorySpec; //-private-import IoTypesSpec; //-private-import MachineStateSpec; //-private-import AssemblySpec; //-private-import InterruptsSpec; //-private-import IoSpec; //-private-import Overflow; //-private-import Core; //-private-import LogicalAddressing; //-private-import Util; //-private-import Stacks; //-private-import Partition; //-private-import Instructions; //-private-import Separation; //-private-import IntLemmasGc; //-private-import SimpleGcMemory; //-private-import SimpleCommon; //-private-import SimpleCollector; //-private-import IntLemmasMain; //-private-import IntLemmasBase; //-private-import IoMain; //-private-basmonly-import Trusted; //-private-basmonly-import Checked; //-private-import Heap; //-private-import Seq; //-private-import dafny_DafnyPrelude; //-private-import DafnyAssembly; //-private-import dafny_base_s; //-private-import dafny_power2_s; //-private-import dafny_bytes_and_words_s; //-private-import dafny_be_sequences_s; //-private-import dafny_assembly_s; //-private-import dafny_integer_sequences_s; //-private-import dafny_seq_blocking_s; //-private-import dafny_sha_common_s; //-private-import dafny_hmac_common_s; //-private-import dafny_sha256_s; //-private-import dafny_seqs_simple_i; //-private-import dafny_power_s; //-private-import dafny_mul_nonlinear_i; //-private-import dafny_mul_i; //-private-import dafny_power_i; //-private-import dafny_div_def_i; //-private-import dafny_div_boogie_i; //-private-import dafny_div_nonlinear_i; //-private-import dafny_div_i; //-private-import dafny_repeat_digit_i; //-private-import dafny_power2_i; //-private-import dafny_seqs_and_ints_i; //-private-import dafny_relational_s; //-private-import dafny_assembly_i; //-private-import dafny_arrays_i; //-private-import dafny_seqs_transforms_i; //-private-import dafny_seqs_reverse_i; //-private-import dafny_integer_sequences_i; //-private-import dafny_integer_sequences_premium_i; //-private-import dafny_assembly_premium_i; //-private-import dafny_bit_vector_lemmas_i; //-private-import dafny_bit_vector_lemmas_premium_i; //-private-import dafny_word_bits_i; //-private-import dafny_arrays_and_seqs_i; //-private-import dafny_round_s; //-private-import dafny_round_i; //-private-import dafny_seq_blocking_i; //-private-import dafny_sha_common_i; //-private-import dafny_sha_padding_i; //-private-import dafny_sha256common_i; //-private-import dafny_sha256opt_i; //- //- //- //- //- module implementation dafny_sha256opt2_i { procedure proc_ComputeOneStep__SHA256__optimized_A(my r_old:regs, const my core_state:core_state, linear stk_old:mem, linear statics_old:mem, linear io_old:IOState, linear mems_old:mems, $commonVars_old:commonVars, $gcVars_old:gcVars, $toAbs_old:[int]int, $absMem_old:[int][int]int, $stacksFrames_old:[int]Frames, objLayouts_old:[int]ObjLayout, heap_old:Heap, $ghost_M:ArrayOfInt, $ghost_words:int, $ghost_H:ArrayOfInt, $ghost_W:ArrayOfInt, $ghost_atoh:atoh_Type, $ghost_num_blocks:int, $ghost_a:int, $ghost_b:int, $ghost_c:int, $ghost_d:int, $ghost_e:int, $ghost_f:int, $ghost_g:int, $ghost_h:int, $ghost_z:SHA256Trace, $ghost_currentBlock:int, $ghost_currentStep:int, K:opn, Wopn:opn_mem, W_base:int, $ghost_W__abs:int) returns(my r:regs, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars, $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap, $ghost_a_next:int, $ghost_b_next:int, $ghost_c_next:int, $ghost_d_next:int, $ghost_e_next:int, $ghost_f_next:int, $ghost_g_next:int, $ghost_h_next:int, $ghost_next_atoh:atoh_Type, $ghost_next_z:SHA256Trace) requires MemInv(me,init,stk_old,statics_old,core_state,ptMem,mems_old); requires NucleusInv(objLayouts_old,$S,$toAbs_old,$absMem_old,$commonVars_old,$gcVars_old,me,init,stk_old,statics_old,core_state,ptMem,mems_old,$stacksFrames_old,io_old); //requires SMemRequireGcRA(stack_size__DafnyCC__Proc_ComputeOneStep__SHA256__optimized, 84, stk_old, r_old.regs[ESP], RET); requires SMemRequireGcRA(0, 76, stk_old, r_old.regs[ESP], RET); // requires SMemRequire(stack_size__DafnyCC__Proc_ComputeOneStep__SHA256__optimized, stk_old, r_old.regs[ESP]); // requires ?sLo + stack_size__DafnyCC__Proc_ComputeOneStep__SHA256__optimized <= r_old.regs[ESP]; requires HeapInv($absMem_old, objLayouts_old, heap_old); requires (($ghost_words) == (stk_old.map[r_old.regs[ESP] + 36])); requires (($ghost_num_blocks) == (stk_old.map[r_old.regs[ESP] + 40])); //requires (($ghost_a) == (stk_old.map[r_old.regs[ESP] + 44])); requires $ghost_a == r_old.regs[EBP]; requires (($ghost_b) == (stk_old.map[r_old.regs[ESP] + 48])); requires (($ghost_c) == (stk_old.map[r_old.regs[ESP] + 52])); requires (($ghost_d) == (stk_old.map[r_old.regs[ESP] + 56])); requires (($ghost_e) == (stk_old.map[r_old.regs[ESP] + 60])); requires (($ghost_f) == (stk_old.map[r_old.regs[ESP] + 64])); requires (($ghost_g) == (stk_old.map[r_old.regs[ESP] + 68])); requires (($ghost_h) == (stk_old.map[r_old.regs[ESP] + 72])); //requires (($ghost_currentBlock) == (stk_old.map[r_old.regs[ESP] + 76])); //requires (($ghost_currentStep) == (stk_old.map[r_old.regs[ESP] + 80])); requires EvalPtrOk(Wopn); requires EvalPtr(r_old, Wopn) == W_base + 4 * (2 + $ghost_currentStep); requires Wopn._ptr is MReg && Wopn._ptr._mreg == ESI; requires $ghost_W.arrAbs == $ghost_W__abs; requires HeapAbsData(heap_old, $ghost_W__abs) is Abs_ArrayOfInt; requires 0 <= $ghost_currentStep && $ghost_currentStep < HeapAbsData(heap_old, $ghost_W__abs).arr.arrCount; requires HeapValue(objLayouts_old, true, $toAbs_old, W_base, $ghost_W__abs); requires StackAbsSlot(heap_old, $stacksFrames_old, r_old.regs[ESP] + 4 + stackGcOffset) == Abs_ArrayOfInt($ghost_M); requires frameGet($stacksFrames_old, r_old.regs[ESP] + 4 + stackGcOffset) == $ghost_M.arrAbs; requires StackAbsSlot(heap_old, $stacksFrames_old, r_old.regs[ESP] + 8 + stackGcOffset) == Abs_ArrayOfInt($ghost_H); requires frameGet($stacksFrames_old, r_old.regs[ESP] + 8 + stackGcOffset) == $ghost_H.arrAbs; requires StackAbsSlot(heap_old, $stacksFrames_old, r_old.regs[ESP] + 12 + stackGcOffset) == Abs_ArrayOfInt($ghost_W); requires frameGet($stacksFrames_old, r_old.regs[ESP] + 12 + stackGcOffset) == $ghost_W.arrAbs; requires $ghost_H != (ArrayOfInt(0 - 1, NO_ABS)); requires $ghost_W != (ArrayOfInt(0 - 1, NO_ABS)); requires $ghost_M != (ArrayOfInt(0 - 1, NO_ABS)); requires $ghost_atoh == (atoh_c($ghost_a, $ghost_b, $ghost_c, $ghost_d, $ghost_e, $ghost_f, $ghost_g, $ghost_h)); requires (INTERNAL_le_boogie(0, $ghost_words)) && (INTERNAL_le_boogie($ghost_words, (Arr_Length($ghost_M)))); requires (INTERNAL_le_boogie(0, $ghost_currentBlock)) && (INTERNAL_lt_boogie($ghost_currentBlock, fun_Seq__Length___Seq___int((M#SHA256Trace_c($ghost_z))))); requires (INTERNAL_le_boogie(0, $ghost_currentStep)) && (INTERNAL_le_boogie($ghost_currentStep, 63)); requires K is OConst && K._const == fun_K__SHA256($ghost_currentStep); requires fun_IsSHA256ReadyForStep($ghost_z, fun_SHA256__vars__to__state($absMem_old, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_atoh, $ghost_num_blocks), $ghost_currentBlock, $ghost_currentStep); modifies $Time; ensures r.regs[ESP] == old(r_old.regs[ESP]); ensures MemInv(me,init,stk,statics,core_state,ptMem,mems); ensures NucleusInv(objLayouts,$S,$toAbs,$absMem,$commonVars,$gcVars,me,init,stk,statics,core_state,ptMem,mems,$stacksFrames,io); //ensures SMemEnsureGcF(84, stk, old(stk_old), r.regs[ESP], old(r_old.regs[ESP]), $stacksFrames, $stacksFrames_old); ensures r.regs[ESP] == old(r_old.regs[ESP]); ensures r.regs[ESI] == old(r_old.regs[ESI]); ensures stk[r.regs[ESP]] == old(stk_old)[r.regs[ESP]]; ensures (forall i:int::{stk[i]} r.regs[ESP] + 76 <= i ==> stk[i] == old(stk_old)[i]); ensures (forall i:int::{$stacksFrames[$S].Abss[i]} r.regs[ESP] + 76 + stackGcOffset <= i ==> $stacksFrames[$S].Abss[i] == $stacksFrames_old[$S].Abss[i]); ensures HeapInv($absMem, objLayouts, heap); ensures AbsExtend($toAbs, $toAbs_old, objLayouts, objLayouts_old); ensures (forall i:int::{$absMem[i]}{heap.absData[i]} heap_old.absData[i] is AbsNone || (heap.absData[i] == heap_old.absData[i] && ($absMem[i] == $absMem_old[i]))); ensures io._inCtr == io_old._inCtr && io._outCtr == io_old._outCtr; ensures fun_IsSHA256ReadyForStep($ghost_next_z, fun_SHA256__vars__to__state($absMem, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_next_atoh, $ghost_num_blocks), $ghost_currentBlock, INTERNAL_add_boogie($ghost_currentStep, 1)); ensures fun_Seq__Equal___int(fun_Seq__FromArray($absMem, $ghost_H), old(fun_Seq__FromArray($absMem_old, $ghost_H))); ensures fun_Seq__Equal___int(fun_Seq__FromArray($absMem, $ghost_M), old(fun_Seq__FromArray($absMem_old, $ghost_M))); ensures fun_Seq__Equal___int(fun_Seq__FromArray($absMem, $ghost_W), old(fun_Seq__FromArray($absMem_old, $ghost_W))); ensures $ghost_next_atoh == (atoh_c($ghost_a_next, $ghost_b_next, $ghost_c_next, $ghost_d_next, $ghost_e_next, $ghost_f_next, $ghost_g_next, $ghost_h_next)); //ensures (($ghost_a_next) == (stk.map[r_old.regs[ESP] + 4])); ensures $ghost_a_next == r.regs[EBP]; ensures (($ghost_b_next) == (stk.map[r_old.regs[ESP] + 8])); ensures (($ghost_c_next) == (stk.map[r_old.regs[ESP] + 12])); ensures (($ghost_d_next) == (stk.map[r_old.regs[ESP] + 16])); ensures (($ghost_e_next) == (stk.map[r_old.regs[ESP] + 20])); ensures (($ghost_f_next) == (stk.map[r_old.regs[ESP] + 24])); ensures (($ghost_g_next) == (stk.map[r_old.regs[ESP] + 28])); ensures (($ghost_h_next) == (stk.map[r_old.regs[ESP] + 32])); //- Preserve calling requirements ensures (($ghost_words) == (stk.map[r.regs[ESP] + 36])); ensures (($ghost_num_blocks) == (stk.map[r.regs[ESP] + 40])); ensures HeapValue(objLayouts, true, $toAbs, W_base, $ghost_W__abs); ensures StackAbsSlot(heap, $stacksFrames, r.regs[ESP] + 4 + stackGcOffset) == Abs_ArrayOfInt($ghost_M); ensures frameGet($stacksFrames, r.regs[ESP] + 4 + stackGcOffset) == $ghost_M.arrAbs; ensures StackAbsSlot(heap, $stacksFrames, r.regs[ESP] + 8 + stackGcOffset) == Abs_ArrayOfInt($ghost_H); ensures frameGet($stacksFrames, r.regs[ESP] + 8 + stackGcOffset) == $ghost_H.arrAbs; ensures StackAbsSlot(heap, $stacksFrames, r.regs[ESP] + 12 + stackGcOffset) == Abs_ArrayOfInt($ghost_W); ensures frameGet($stacksFrames, r.regs[ESP] + 12 + stackGcOffset) == $ghost_W.arrAbs; { var t:opn_mem; var $result:int; var $result2:int; //- Lots of boilerplate follows var $absMem_tmp:[int][int]int; var objLayouts_tmp:[int]ObjLayout; var heap_tmp:Heap; var obj_tmp:int; var val_tmp:int; var $ghost_s:SHA256_state; var $ghost_bsig0:int; var $ghost__temp__0:int; var $ghost__temp__1:int; var $ghost__temp__2:int; var $ghost__temp__3:int; var $ghost_bsig1:int; var $ghost__temp__4:int; var $ghost__temp__5:int; var $ghost__temp__6:int; var $ghost__temp__7:int; var $ghost_my_ch:int; var $ghost__temp__8:int; var $ghost__temp__9:int; var $ghost__temp__10:int; var $ghost_my_maj:int; var $ghost__temp__11:int; var $ghost__temp__12:int; var $ghost__temp__13:int; var $ghost__temp__14:int; var $ghost_T1:int; var $ghost__temp__15:int; var $ghost__temp__16:int; var $ghost__temp__17:int; var $ghost__temp__18:int; var $ghost__temp__19:int; var $ghost_T2:int; var $ghost_next_s:SHA256_state; var $ghost_M__abs:int; var $ghost_H__abs:int; assert fun_unroll(0); assert fun_unroll(1); call lemma_unroll_rec_fun____HASH_Seq__Length__FULL___int(); call lemma_unroll_fun____HASH_Seq__Length__FULL___int(); call lemma_fun_ensures_fun_Seq__Length___int(); call lemma_unroll_rec_fun____HASH_Seq__Build__FULL___int(); call lemma_unroll_fun____HASH_Seq__Build__FULL___int(); call lemma_unroll_rec_fun____HASH_Seq__Index__FULL___int(); call lemma_unroll_fun____HASH_Seq__Index__FULL___int(); call lemma_unroll_rec_fun____HASH_Seq__Append__FULL___int(); call lemma_unroll_fun____HASH_Seq__Append__FULL___int(); call lemma_unroll_rec_fun____HASH_Seq__Update__FULL___int(); call lemma_unroll_fun____HASH_Seq__Update__FULL___int(); call lemma_unroll_rec_fun____HASH_Seq__Take__FULL___int(); call lemma_unroll_fun____HASH_Seq__Take__FULL___int(); call lemma_unroll_rec_fun____HASH_Seq__Drop__FULL___int(); call lemma_unroll_fun____HASH_Seq__Drop__FULL___int(); call proc_Seq__Empty__ToZero___int(); call proc_Seq__Empty__FromZero___int(); call proc_Seq__Singleton__Length___int(); call proc_Seq__Build__Length___int(); call proc_Seq__Build__Index___int(); call proc_Seq__Append__Length___int(); call proc_Seq__Index__Singleton___int(); call proc_Seq__Append__Index___int(); call proc_Seq__Update__Length___int(); call proc_Seq__Index__Update___int(); call proc_Seq__Equal__Equiv___int(); call proc_Seq__Take__Length___int(); call proc_Seq__Take__Index___int(); call proc_Seq__Drop__Length___int(); call proc_Seq__Drop__Index___int(); call proc_Seq__Append__TakeDrop__Restricted___int(); call proc_Seq__Update__CommuteTake1___int(); call proc_Seq__Update__CommuteTake2___int(); call proc_Seq__Update__CommuteDrop1___int(); call proc_Seq__Update__CommuteDrop2___int(); call proc_Seq__Build__CommuteDrop___int(); call proc_Seq__Take__Empty___int(); call proc_Seq__Drop__Empty___int(); call lemma_unroll_fun_Seq__FromArrayRange(); call proc_Seq__FromArray__Length(); call proc_Seq__FromArray__Index(); call proc_Seq__FromArray__Update(); call lemma_unroll_rec_fun____HASH_power2__FULL(); call lemma_unroll_fun____HASH_power2__FULL(); call lemma_fun_ensures_fun_power2(); call lemma_unroll_rec_fun____HASH_BEDigitSeqToInt__private__FULL(); call lemma_unroll_fun____HASH_BEDigitSeqToInt__private__FULL(); call lemma_unroll_rec_fun____HASH_BEIntToDigitSeq__private__FULL(); call lemma_unroll_fun____HASH_BEIntToDigitSeq__private__FULL(); call lemma_unroll_rec_fun_RepeatDigit(); call lemma_unroll_fun_RepeatDigit(); call lemma_unroll_rec_fun____HASH_Reverse__FULL(); call lemma_unroll_fun____HASH_Reverse__FULL(); call lemma_unroll_rec_fun____HASH_power__FULL(); call lemma_unroll_fun____HASH_power__FULL(); call lemma_unroll_rec_fun_mul__pos(); call lemma_unroll_fun_mul__pos(); call lemma_unroll_rec_fun____HASH_Seq__Length__FULL___bool(); call lemma_unroll_fun____HASH_Seq__Length__FULL___bool(); call lemma_fun_ensures_fun_Seq__Length___bool(); call lemma_unroll_rec_fun____HASH_Seq__Build__FULL___bool(); call lemma_unroll_fun____HASH_Seq__Build__FULL___bool(); call lemma_unroll_rec_fun____HASH_Seq__Index__FULL___bool(); call lemma_unroll_fun____HASH_Seq__Index__FULL___bool(); call lemma_unroll_rec_fun____HASH_Seq__Append__FULL___bool(); call lemma_unroll_fun____HASH_Seq__Append__FULL___bool(); call lemma_unroll_rec_fun____HASH_Seq__Update__FULL___bool(); call lemma_unroll_fun____HASH_Seq__Update__FULL___bool(); call lemma_unroll_rec_fun____HASH_Seq__Take__FULL___bool(); call lemma_unroll_fun____HASH_Seq__Take__FULL___bool(); call lemma_unroll_rec_fun____HASH_Seq__Drop__FULL___bool(); call lemma_unroll_fun____HASH_Seq__Drop__FULL___bool(); call proc_Seq__Empty__ToZero___bool(); call proc_Seq__Empty__FromZero___bool(); call proc_Seq__Singleton__Length___bool(); call proc_Seq__Build__Length___bool(); call proc_Seq__Build__Index___bool(); call proc_Seq__Append__Length___bool(); call proc_Seq__Index__Singleton___bool(); call proc_Seq__Append__Index___bool(); call proc_Seq__Update__Length___bool(); call proc_Seq__Index__Update___bool(); call proc_Seq__Equal__Equiv___bool(); call proc_Seq__Take__Length___bool(); call proc_Seq__Take__Index___bool(); call proc_Seq__Drop__Length___bool(); call proc_Seq__Drop__Index___bool(); call proc_Seq__Append__TakeDrop__Restricted___bool(); call proc_Seq__Update__CommuteTake1___bool(); call proc_Seq__Update__CommuteTake2___bool(); call proc_Seq__Update__CommuteDrop1___bool(); call proc_Seq__Update__CommuteDrop2___bool(); call proc_Seq__Build__CommuteDrop___bool(); call proc_Seq__Take__Empty___bool(); call proc_Seq__Drop__Empty___bool(); call lemma_unroll_rec_fun_my__div__pos(); call lemma_unroll_fun_my__div__pos(); call lemma_unroll_rec_fun_my__mod__recursive(); call lemma_unroll_fun_my__mod__recursive(); call lemma_fun_ensures_fun_RepeatDigit__premium(); call lemma_unroll_rec_fun____HASH_SequenceOfZeros__FULL(); call lemma_unroll_fun____HASH_SequenceOfZeros__FULL(); call lemma_fun_ensures_fun_SequenceOfZeros(); call lemma_fun_ensures_fun_BitwiseAnd(); call lemma_fun_ensures_fun_BitwiseOr(); call lemma_fun_ensures_fun_BitwiseNot(); call lemma_fun_ensures_fun_BitwiseXor(); call lemma_fun_ensures_fun_RotateRight(); call lemma_fun_ensures_fun_RotateLeft(); call lemma_fun_ensures_fun_RightShift(); call lemma_fun_ensures_fun_LeftShift(); call lemma_fun_ensures_fun_Add32(); call lemma_fun_ensures_fun_Sub32(); call lemma_fun_ensures_fun_Mul32(); call lemma_fun_ensures_fun_Div32(); call lemma_fun_ensures_fun_Mod32(); call lemma_unroll_rec_fun____HASH_NatNumBits__FULL(); call lemma_unroll_fun____HASH_NatNumBits__FULL(); call lemma_fun_ensures_fun_NatNumBits(); call lemma_fun_ensures_fun_asm__Add(); call lemma_fun_ensures_fun_asm__Sub(); call lemma_fun_ensures_fun_asm__Mul(); call lemma_fun_ensures_fun_asm__Div(); call lemma_fun_ensures_fun_asm__Mod(); call lemma_fun_ensures_fun_asm__LeftShift(); call lemma_fun_ensures_fun_asm__RightShift(); call lemma_fun_ensures_fun_asm__RotateLeft(); call lemma_fun_ensures_fun_asm__RotateRight(); call lemma_fun_ensures_fun_asm__BitwiseNot(); call lemma_fun_ensures_fun_asm__BitwiseAnd(); call lemma_fun_ensures_fun_asm__BitwiseOr(); call lemma_fun_ensures_fun_asm__BitwiseXor(); call lemma_unroll_rec_fun____HASH_LEDigitSeqToInt__private__FULL(); call lemma_unroll_fun____HASH_LEDigitSeqToInt__private__FULL(); call lemma_fun_ensures_fun_BEDigitSeqToInt__premium(); call lemma_fun_ensures_fun_BEWordSeqToInt__premium(); call lemma_fun_ensures_fun_BEIntToDigitSeq__premium(); call lemma_fun_ensures_fun_BEIntToByteSeq__premium(); call lemma_fun_ensures_fun_BEWordToFourBytes__premium(); call lemma_fun_ensures_fun_BEWordToBitSeq__premium(); call lemma_fun_ensures_fun_BEWordSeqToBitSeq__premium(); call lemma_fun_ensures_fun_BEByteSeqToBitSeq__premium(); call lemma_fun_ensures_fun_BEWordSeqToByteSeq__premium(); call lemma_fun_ensures_fun_Asm__Add(); call lemma_fun_ensures_fun_Asm__Sub(); call lemma_fun_ensures_fun_Asm__Mul(); call lemma_fun_ensures_fun_Asm__Div(); call lemma_fun_ensures_fun_Asm__Mod(); call lemma_fun_ensures_fun_Asm__LeftShift(); call lemma_fun_ensures_fun_Asm__RightShift(); call lemma_fun_ensures_fun_Asm__RotateLeft(); call lemma_fun_ensures_fun_Asm__RotateRight(); call lemma_fun_ensures_fun_Asm__BitwiseNot(); call lemma_fun_ensures_fun_Asm__BitwiseAnd(); call lemma_fun_ensures_fun_Asm__BitwiseOr(); call lemma_fun_ensures_fun_Asm__BitwiseXor(); call lemma_fun_ensures_fun_ComputePower2(); call lemma_fun_ensures_fun_ComputePower2Minus1__mostly(); call lemma_fun_ensures_fun_ComputePower2Minus1(); call lemma_fun_ensures_fun_GetWordBit(); call lemma_unroll_rec_fun____HASH_Seq__Length__FULL___Seq___int(); call lemma_unroll_fun____HASH_Seq__Length__FULL___Seq___int(); call lemma_fun_ensures_fun_Seq__Length___Seq___int(); call lemma_unroll_rec_fun____HASH_Seq__Build__FULL___Seq___int(); call lemma_unroll_fun____HASH_Seq__Build__FULL___Seq___int(); call lemma_unroll_rec_fun____HASH_Seq__Index__FULL___Seq___int(); call lemma_unroll_fun____HASH_Seq__Index__FULL___Seq___int(); call lemma_unroll_rec_fun____HASH_Seq__Append__FULL___Seq___int(); call lemma_unroll_fun____HASH_Seq__Append__FULL___Seq___int(); call lemma_unroll_rec_fun____HASH_Seq__Update__FULL___Seq___int(); call lemma_unroll_fun____HASH_Seq__Update__FULL___Seq___int(); call lemma_unroll_rec_fun____HASH_Seq__Take__FULL___Seq___int(); call lemma_unroll_fun____HASH_Seq__Take__FULL___Seq___int(); call lemma_unroll_rec_fun____HASH_Seq__Drop__FULL___Seq___int(); call lemma_unroll_fun____HASH_Seq__Drop__FULL___Seq___int(); call proc_Seq__Empty__ToZero___Seq___int(); call proc_Seq__Empty__FromZero___Seq___int(); call proc_Seq__Singleton__Length___Seq___int(); call proc_Seq__Build__Length___Seq___int(); call proc_Seq__Build__Index___Seq___int(); call proc_Seq__Append__Length___Seq___int(); call proc_Seq__Index__Singleton___Seq___int(); call proc_Seq__Append__Index___Seq___int(); call proc_Seq__Update__Length___Seq___int(); call proc_Seq__Index__Update___Seq___int(); call proc_Seq__Equal__Equiv___Seq___int(); call proc_Seq__Take__Length___Seq___int(); call proc_Seq__Take__Index___Seq___int(); call proc_Seq__Drop__Length___Seq___int(); call proc_Seq__Drop__Index___Seq___int(); call proc_Seq__Append__TakeDrop__Restricted___Seq___int(); call proc_Seq__Update__CommuteTake1___Seq___int(); call proc_Seq__Update__CommuteTake2___Seq___int(); call proc_Seq__Update__CommuteDrop1___Seq___int(); call proc_Seq__Update__CommuteDrop2___Seq___int(); call proc_Seq__Build__CommuteDrop___Seq___int(); call proc_Seq__Take__Empty___Seq___int(); call proc_Seq__Drop__Empty___Seq___int(); call lemma_unroll_rec_fun____HASH_BreakIntoBlocks__FULL(); call lemma_unroll_fun____HASH_BreakIntoBlocks__FULL(); call lemma_fun_ensures_fun____HASH_Ch__FULL(); call lemma_fun_ensures_fun_Ch(); call lemma_fun_ensures_fun____HASH_Maj__FULL(); call lemma_fun_ensures_fun_Maj(); call lemma_fun_ensures_fun____HASH_Parity__FULL(); call lemma_fun_ensures_fun_Parity(); call lemma_fun_ensures_fun____HASH_ft__FULL(); call lemma_fun_ensures_fun_ft(); call lemma_fun_ensures_fun____HASH_BSIG0__FULL(); call lemma_fun_ensures_fun_BSIG0(); call lemma_fun_ensures_fun____HASH_BSIG1__FULL(); call lemma_fun_ensures_fun_BSIG1(); call lemma_fun_ensures_fun____HASH_SSIG0__FULL(); call lemma_fun_ensures_fun_SSIG0(); call lemma_fun_ensures_fun____HASH_SSIG1__FULL(); call lemma_fun_ensures_fun_SSIG1(); call lemma_fun_ensures_fun____HASH_NumPaddingZeroes__FULL(); call lemma_fun_ensures_fun_NumPaddingZeroes(); call lemma_unroll_rec_fun____HASH_SeqXor__FULL(); call lemma_unroll_fun____HASH_SeqXor__FULL(); call lemma_unroll_rec_fun____HASH_ConstPad__FULL(); call lemma_unroll_fun____HASH_ConstPad__FULL(); call lemma_fun_ensures_fun____HASH_GetArrayBit__FULL(); call lemma_fun_ensures_fun_GetArrayBit(); call lemma_fun_ensures_fun_DivideRoundingUp__premium(); call lemma_fun_ensures_fun_RoundUpToMultiple__premium(); call lemma_fun_ensures_fun_PadSequenceToMultiple__premium(); call lemma_fun_ensures_fun_PadAndBreakIntoBlocks__premium(); call lemma_fun_ensures_fun_Ch__impl(); call lemma_fun_ensures_fun_Maj__impl(); call lemma_fun_ensures_fun_Parity__impl(); call lemma_fun_ensures_fun_ft__impl(); call lemma_fun_ensures_fun_BSIG0__impl(); call lemma_fun_ensures_fun_BSIG1__impl(); call lemma_fun_ensures_fun_SSIG0__impl(); call lemma_fun_ensures_fun_SSIG1__impl(); call lemma_fun_ensures_fun_PadMessageForSHA__premium(); call lemma_fun_ensures_fun____HASH_GetArrayBitOpaque__FULL(); call lemma_fun_ensures_fun_GetArrayBitOpaque(); call lemma_fun_ensures_fun____HASH_K__SHA256__FULL(); call lemma_fun_ensures_fun_K__SHA256(); call lemma_fun_ensures_fun____HASH_InitialH__SHA256__FULL(); call lemma_fun_ensures_fun_InitialH__SHA256(); call lemma_unroll_rec_fun____HASH_Seq__Length__FULL___atoh_Type(); call lemma_unroll_fun____HASH_Seq__Length__FULL___atoh_Type(); call lemma_fun_ensures_fun_Seq__Length___atoh_Type(); call lemma_unroll_rec_fun____HASH_Seq__Build__FULL___atoh_Type(); call lemma_unroll_fun____HASH_Seq__Build__FULL___atoh_Type(); call lemma_unroll_rec_fun____HASH_Seq__Index__FULL___atoh_Type(); call lemma_unroll_fun____HASH_Seq__Index__FULL___atoh_Type(); call lemma_unroll_rec_fun____HASH_Seq__Append__FULL___atoh_Type(); call lemma_unroll_fun____HASH_Seq__Append__FULL___atoh_Type(); call lemma_unroll_rec_fun____HASH_Seq__Update__FULL___atoh_Type(); call lemma_unroll_fun____HASH_Seq__Update__FULL___atoh_Type(); call lemma_unroll_rec_fun____HASH_Seq__Take__FULL___atoh_Type(); call lemma_unroll_fun____HASH_Seq__Take__FULL___atoh_Type(); call lemma_unroll_rec_fun____HASH_Seq__Drop__FULL___atoh_Type(); call lemma_unroll_fun____HASH_Seq__Drop__FULL___atoh_Type(); call proc_Seq__Empty__ToZero___atoh_Type(); call proc_Seq__Empty__FromZero___atoh_Type(); call proc_Seq__Singleton__Length___atoh_Type(); call proc_Seq__Build__Length___atoh_Type(); call proc_Seq__Build__Index___atoh_Type(); call proc_Seq__Append__Length___atoh_Type(); call proc_Seq__Index__Singleton___atoh_Type(); call proc_Seq__Append__Index___atoh_Type(); call proc_Seq__Update__Length___atoh_Type(); call proc_Seq__Index__Update___atoh_Type(); call proc_Seq__Equal__Equiv___atoh_Type(); call proc_Seq__Take__Length___atoh_Type(); call proc_Seq__Take__Index___atoh_Type(); call proc_Seq__Drop__Length___atoh_Type(); call proc_Seq__Drop__Index___atoh_Type(); call proc_Seq__Append__TakeDrop__Restricted___atoh_Type(); call proc_Seq__Update__CommuteTake1___atoh_Type(); call proc_Seq__Update__CommuteTake2___atoh_Type(); call proc_Seq__Update__CommuteDrop1___atoh_Type(); call proc_Seq__Update__CommuteDrop2___atoh_Type(); call proc_Seq__Build__CommuteDrop___atoh_Type(); call proc_Seq__Take__Empty___atoh_Type(); call proc_Seq__Drop__Empty___atoh_Type(); call lemma_unroll_rec_fun____HASH_Seq__Length__FULL___Seq___atoh_Type(); call lemma_unroll_fun____HASH_Seq__Length__FULL___Seq___atoh_Type(); call lemma_fun_ensures_fun_Seq__Length___Seq___atoh_Type(); call lemma_unroll_rec_fun____HASH_Seq__Build__FULL___Seq___atoh_Type(); call lemma_unroll_fun____HASH_Seq__Build__FULL___Seq___atoh_Type(); call lemma_unroll_rec_fun____HASH_Seq__Index__FULL___Seq___atoh_Type(); call lemma_unroll_fun____HASH_Seq__Index__FULL___Seq___atoh_Type(); call lemma_unroll_rec_fun____HASH_Seq__Append__FULL___Seq___atoh_Type(); call lemma_unroll_fun____HASH_Seq__Append__FULL___Seq___atoh_Type(); call lemma_unroll_rec_fun____HASH_Seq__Update__FULL___Seq___atoh_Type(); call lemma_unroll_fun____HASH_Seq__Update__FULL___Seq___atoh_Type(); call lemma_unroll_rec_fun____HASH_Seq__Take__FULL___Seq___atoh_Type(); call lemma_unroll_fun____HASH_Seq__Take__FULL___Seq___atoh_Type(); call lemma_unroll_rec_fun____HASH_Seq__Drop__FULL___Seq___atoh_Type(); call lemma_unroll_fun____HASH_Seq__Drop__FULL___Seq___atoh_Type(); call proc_Seq__Empty__ToZero___Seq___atoh_Type(); call proc_Seq__Empty__FromZero___Seq___atoh_Type(); call proc_Seq__Singleton__Length___Seq___atoh_Type(); call proc_Seq__Build__Length___Seq___atoh_Type(); call proc_Seq__Build__Index___Seq___atoh_Type(); call proc_Seq__Append__Length___Seq___atoh_Type(); call proc_Seq__Index__Singleton___Seq___atoh_Type(); call proc_Seq__Append__Index___Seq___atoh_Type(); call proc_Seq__Update__Length___Seq___atoh_Type(); call proc_Seq__Index__Update___Seq___atoh_Type(); call proc_Seq__Equal__Equiv___Seq___atoh_Type(); call proc_Seq__Take__Length___Seq___atoh_Type(); call proc_Seq__Take__Index___Seq___atoh_Type(); call proc_Seq__Drop__Length___Seq___atoh_Type(); call proc_Seq__Drop__Index___Seq___atoh_Type(); call proc_Seq__Append__TakeDrop__Restricted___Seq___atoh_Type(); call proc_Seq__Update__CommuteTake1___Seq___atoh_Type(); call proc_Seq__Update__CommuteTake2___Seq___atoh_Type(); call proc_Seq__Update__CommuteDrop1___Seq___atoh_Type(); call proc_Seq__Update__CommuteDrop2___Seq___atoh_Type(); call proc_Seq__Build__CommuteDrop___Seq___atoh_Type(); call proc_Seq__Take__Empty___Seq___atoh_Type(); call proc_Seq__Drop__Empty___Seq___atoh_Type(); call lemma_fun_ensures_fun_SHA256(); r := r_old; stk := stk_old; statics := statics_old; io := io_old; mems := mems_old; $commonVars := $commonVars_old; $gcVars := $gcVars_old; $toAbs := $toAbs_old; $absMem := $absMem_old; $stacksFrames := $stacksFrames_old; objLayouts := objLayouts_old; heap := heap_old; $ghost_M__abs := frameGet($stacksFrames, r_old.regs[ESP] + 4 + stackGcOffset); $ghost_H__abs := frameGet($stacksFrames, r_old.regs[ESP] + 8 + stackGcOffset); assert TV(r.regs[ESP]); assert TO(0 - 1); assert TO(279552 - 1); assert TO(0 - 2); assert TO(279552 - 2); assert TO(0); assert TO(279552); assert TO(1); assert TO(279553); assert TO(2); assert TO(279554); assert TO(3); assert TO(279555); assert TO(4); assert TO(279556); assert TO(5); assert TO(279557); assert TO(6); assert TO(279558); assert TO(7); assert TO(279559); assert TO(8); assert TO(279560); assert TO(9); assert TO(279561); assert TO(10); assert TO(279562); assert TO(11); assert TO(279563); assert TO(12); assert TO(279564); assert TO(13); assert TO(279565); assert TO(14); assert TO(279566); assert TO(15); assert TO(279567); assert TO(16); assert TO(279568); assert TO(17); assert TO(279569); assert TO(18); assert TO(279570); assert TO(19); assert TO(279571); assert TO(20); assert TO(279572); assert TO(21); call proc_lemma__2toX(); call proc_lemma__word32__Word32(); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt2.i.dfy: 38 $ghost_s := fun_SHA256__vars__to__state($absMem, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_atoh, $ghost_num_blocks); // assert Aligned(esp); // // Prove that we can load arguments from the stack (b/c accesses are aligned) // assert TV(esp) && TO(0) && TO(1) && TO(2) && TO(3) && TO(4) && TO(5); // // // Prove that we can load arguments from the GC stack (b/c accesses are aligned) // assert TO(0x44401) && TO(0x44402) && TO(0x44403); // (gcStackOffset + {4,8,12}) / 4 // Calculate my_maj //t := OMem(MReg(ESP, 44)); //assert EvalPtrOk(t); //assert stk.dom[EvalPtr(r, t)]; //assert Aligned(EvalPtr(r, t)); //assert PhysPtrOk(stk, EvalPtr(r, t)); //assert word(EvalPtr(r, t)); // //call eax := Load(stk, esp + 44); // grab a //assert eax == $ghost_a; assert ebp == $ghost_a; call logical_Store(r, core_state, inout stk, OMem(MReg(ESP, 8)), OReg(EBP)); // b_next <- a call ebx := Load(stk, esp + 48); // grab b assert ebx == $ghost_b; call logical_Store(r, core_state, inout stk, OMem(MReg(ESP, 12)), OReg(EBX)); // c_next <- b call ecx := Load(stk, esp + 52); // grab c assert ecx == $ghost_c; call logical_Store(r, core_state, inout stk, OMem(MReg(ESP, 16)), OReg(ECX)); // d_next <- c edx := ebx; // Store a copy of b call r, $result := proc_Asm__BitwiseAnd(r, $ghost_b, $ghost_a, EBX, OReg(EBP)); call proc_lemma__bitwise__and__commutative($ghost_b, $ghost_a); assert fun_Asm__BitwiseAnd($ghost_b, $ghost_a) == fun_Asm__BitwiseAnd($ghost_a, $ghost_b); call r, $result := proc_Asm__BitwiseAnd(r, $ghost_b, $ghost_c, EDX, OReg(ECX)); call r, $result := proc_Asm__BitwiseAnd(r, $ghost_c, $ghost_a, ECX, OReg(EBP)); call proc_lemma__bitwise__and__commutative($ghost_c, $ghost_a); assert fun_Asm__BitwiseAnd($ghost_c, $ghost_a) == fun_Asm__BitwiseAnd($ghost_a, $ghost_c); call r, $result := proc_Asm__BitwiseXor(r, fun_Asm__BitwiseAnd($ghost_b, $ghost_a), fun_Asm__BitwiseAnd($ghost_c, $ghost_a), EBX, OReg(ECX)); call r, $ghost_my_maj := proc_Asm__BitwiseXor(r, $result, fun_Asm__BitwiseAnd($ghost_b, $ghost_c), EBX, OReg(EDX)); forall::($ghost_my_maj == (fun_Maj($ghost_a, $ghost_b, $ghost_c))) { call proc_reveal__Maj(); } // At this point, ebp == a, ebx == my_maj assert ebp == $ghost_a; assert ebx == fun_Maj($ghost_a, $ghost_b, $ghost_c); // Calculate bsig0 ecx := ebp; edx := ebp; call r, $result := proc_Asm__RotateRight(r, $ghost_a, 2, EBP, OConst(2)); call r, $result := proc_Asm__RotateRight(r, $ghost_a, 13, ECX, OConst(13)); call r, $result := proc_Asm__BitwiseXor(r, fun_Asm__RotateRight($ghost_a, 2), fun_Asm__RotateRight($ghost_a, 13), EBP, OReg(ECX)); call r, $result2 := proc_Asm__RotateRight(r, $ghost_a, 22, EDX, OConst(22)); call r, $ghost_bsig0 := proc_Asm__BitwiseXor(r, $result, fun_Asm__RotateRight($ghost_a, 22), EBP, OReg(EDX)); forall::($ghost_bsig0 == (fun_BSIG0($ghost_a))) { call proc_reveal__BSIG0(); } assert ebp == fun_BSIG0($ghost_a); call r, $ghost_T2 := proc_Asm__Add(r, $ghost_bsig0, $ghost_my_maj, EBP, OReg(EBX)); assert ebp == $ghost_T2; //- Calculate my_ch call ebx := Load(stk, esp + 60); //- grab e assert ebx == $ghost_e; call logical_Store(r, core_state, inout stk, OMem(MReg(ESP, 24)), OReg(EBX)); //- f_next <- e edx := ebx; call r, $result := proc_Asm__BitwiseNot(r, $ghost_e, EDX); call ecx := Load(stk, esp + 68); //- grab g assert ecx == $ghost_g; call logical_Store(r, core_state, inout stk, OMem(MReg(ESP, 32)), OReg(ECX)); //- h_next <- g call r, $result := proc_Asm__BitwiseAnd(r, $result, $ghost_g, EDX, OReg(ECX)); //- !e & g assert edx == fun_Asm__BitwiseAnd(fun_Asm__BitwiseNot($ghost_e), $ghost_g); call ecx := Load(stk, esp + 64); //- grab f assert ecx == $ghost_f; call logical_Store(r, core_state, inout stk, OMem(MReg(ESP, 28)), OReg(ECX)); //- g_next <- f call r, $result2 := proc_Asm__BitwiseAnd(r, $ghost_f, $ghost_e, ECX, OReg(EBX)); call proc_lemma__bitwise__and__commutative($ghost_f, $ghost_e); assert fun_Asm__BitwiseAnd($ghost_f, $ghost_e) == fun_Asm__BitwiseAnd($ghost_e, $ghost_f); call r, $ghost_my_ch := proc_Asm__BitwiseXor(r, $result2, $result, ECX, OReg(EDX)); forall::($ghost_my_ch == (fun_Ch($ghost_e, $ghost_f, $ghost_g))) { call proc_reveal__Ch(); } //- Summary: assert ebp == $ghost_T2; assert ebx == $ghost_e; assert ecx == fun_Ch($ghost_e, $ghost_f, $ghost_g); //- Calculate bsig1 edx := ebx; edi := ebx; call r, $result := proc_Asm__RotateRight(r, $ghost_e, 6, EDX, OConst(6)); call r, $result2 := proc_Asm__RotateRight(r, $ghost_e, 11, EDI, OConst(11)); call r, $result := proc_Asm__BitwiseXor(r, $result, $result2, EDX, OReg(EDI)); call r, $result2 := proc_Asm__RotateRight(r, $ghost_e, 25, EBX, OConst(25)); call r, $ghost_bsig1 := proc_Asm__BitwiseXor(r, $result, $result2, EDX, OReg(EBX)); forall::($ghost_bsig1 == (fun_BSIG1($ghost_e))) { call proc_reveal__BSIG1(); } //- Summary: assert ebp == $ghost_T2; assert ecx == fun_Ch($ghost_e, $ghost_f, $ghost_g); assert edx == fun_BSIG1($ghost_e); call ebx := Load(stk, esp + 72); //- grab h assert ebx == $ghost_h; call r, $result := proc_Asm__Add(r, $ghost_h, fun_BSIG1($ghost_e), EBX, OReg(EDX)); call r, $result := proc_Asm__Add(r, $result, fun_Ch($ghost_e, $ghost_f, $ghost_g), EBX, OReg(ECX)); call r, $result := proc_Asm__Add(r, $result, Eval(r,K), EBX, K); assert Eval(r,K) == fun_K__SHA256($ghost_currentStep); //- Load the value we want from W call r, mems := loadArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, EDX, Wopn, $ghost_currentStep, $ghost_W__abs, W_base); $ghost__temp__19 := r.regs[EDX]; call r, $ghost_T1 := proc_Asm__Add(r, $result, edx, EBX, OReg(EDX)); assert ebp == $ghost_T2; assert ebx == $ghost_T1; call r, $result := proc_Asm__Add(r, ebp, ebx, EBP, OReg(EBX)); //- a_next <- T2 + T1 assert ebp == fun_Asm__Add($ghost_T1, $ghost_T2); //call logical_Store(r, core_state, inout stk, OMem(MReg(ESP, 4)), OReg(EAX)); call eax := Load(stk, esp + 56); //- grab d assert eax == $ghost_d; call r, $result := proc_Asm__Add(r, eax, ebx, EAX, OReg(EBX)); //- e_next <- d + T1 assert eax == fun_Asm__Add((d#atoh_c($ghost_atoh)), $ghost_T1); call logical_Store(r, core_state, inout stk, OMem(MReg(ESP, 20)), OReg(EAX)); //- Ghost proofs of correctness // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt2.i.dfy: 68 $ghost_next_atoh := atoh_c(fun_Asm__Add($ghost_T1, $ghost_T2), (a#atoh_c($ghost_atoh)), (b#atoh_c($ghost_atoh)), (c#atoh_c($ghost_atoh)), fun_Asm__Add((d#atoh_c($ghost_atoh)), $ghost_T1), (e#atoh_c($ghost_atoh)), (f#atoh_c($ghost_atoh)), (g#atoh_c($ghost_atoh))); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt2.i.dfy: 69 $ghost_next_z := SHA256Trace_c((M#SHA256Trace_c($ghost_z)), (H#SHA256Trace_c($ghost_z)), (W#SHA256Trace_c($ghost_z)), fun_Seq__Append___Seq___atoh_Type(fun_Seq__Take___Seq___atoh_Type((atoh#SHA256Trace_c($ghost_z)), $ghost_currentBlock), fun_Seq__Build___Seq___atoh_Type(fun_Seq__Empty___Seq___atoh_Type(), fun_Seq__Append___atoh_Type(fun_Seq__Index___Seq___atoh_Type((atoh#SHA256Trace_c($ghost_z)), $ghost_currentBlock), fun_Seq__Build___atoh_Type(fun_Seq__Empty___atoh_Type(), $ghost_next_atoh))))); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt2.i.dfy: 70 $ghost_next_s := fun_SHA256__vars__to__state($absMem, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_next_atoh, $ghost_num_blocks); // assert fun_AreSHA256TraceAndStateOK($ghost_z, $ghost_s); // assert fun_Seq__Length___Seq___int((H#SHA256Trace_c($ghost_z))) == INTERNAL_add_boogie($ghost_currentBlock, 1); // assert fun_Seq__Length___Seq___int((W#SHA256Trace_c($ghost_z))) == INTERNAL_add_boogie($ghost_currentBlock, 1); // assert fun_Seq__Length___Seq___atoh_Type(atoh#SHA256Trace_c($ghost_z)) == INTERNAL_add_boogie($ghost_currentBlock, 1); // assert (forall $ghost__1_blk:int :: // (INTERNAL_le_boogie(0, $ghost__1_blk) && INTERNAL_lt_boogie($ghost__1_blk, $ghost_currentBlock)) ==> // (fun_IsAToHWordSeqOfLen(fun_Seq__Index___Seq___atoh_Type(atoh#SHA256Trace_c($ghost_z), $ghost__1_blk), 65))); // assert fun_IsAToHWordSeqOfLen(fun_Seq__Index___Seq___atoh_Type(atoh#SHA256Trace_c($ghost_z), $ghost_currentBlock), INTERNAL_add_boogie($ghost_currentStep, 1)); // assert fun_Seq__Equal___int(H#SHA256_state_c($ghost_s), fun_Seq__Index___Seq___int(H#SHA256Trace_c($ghost_z), $ghost_currentBlock)); // assert fun_Seq__Equal___int(W#SHA256_state_c($ghost_s), fun_Seq__Index___Seq___int(W#SHA256Trace_c($ghost_z), $ghost_currentBlock)); // assert atoh#SHA256_state_c($ghost_s) == fun_Seq__Index___atoh_Type(fun_Seq__Index___Seq___atoh_Type(atoh#SHA256Trace_c($ghost_z), $ghost_currentBlock), $ghost_currentStep); assert fun_IsSHA256ReadyForStep($ghost_z, $ghost_s, $ghost_currentBlock, $ghost_currentStep); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt2.i.dfy: 72 // call:: := proc_lemma__SHA256TransitionOKAfterSettingAtoH($ghost_z, $ghost_s, $ghost_next_z, $ghost_next_s, $ghost_currentBlock, $ghost_currentStep) // isGhost = True call proc_lemma__SHA256TransitionOKAfterSettingAtoH($ghost_z, $ghost_s, $ghost_next_z, $ghost_next_s, $ghost_currentBlock, $ghost_currentStep); //- Update ghost outputs $ghost_a_next := fun_Asm__Add($ghost_T1, $ghost_T2); $ghost_b_next := a#atoh_c($ghost_atoh); $ghost_c_next := b#atoh_c($ghost_atoh); $ghost_d_next := c#atoh_c($ghost_atoh); $ghost_e_next := fun_Asm__Add((d#atoh_c($ghost_atoh)), $ghost_T1); $ghost_f_next := e#atoh_c($ghost_atoh); $ghost_g_next := f#atoh_c($ghost_atoh); $ghost_h_next := g#atoh_c($ghost_atoh); //Return; } procedure proc_ComputeOneStep__SHA256__optimized_B(my r_old:regs, const my core_state:core_state, linear stk_old:mem, linear statics_old:mem, linear io_old:IOState, linear mems_old:mems, $commonVars_old:commonVars, $gcVars_old:gcVars, $toAbs_old:[int]int, $absMem_old:[int][int]int, $stacksFrames_old:[int]Frames, objLayouts_old:[int]ObjLayout, heap_old:Heap, $ghost_M:ArrayOfInt, $ghost_words:int, $ghost_H:ArrayOfInt, $ghost_W:ArrayOfInt, $ghost_atoh:atoh_Type, $ghost_num_blocks:int, $ghost_a:int, $ghost_b:int, $ghost_c:int, $ghost_d:int, $ghost_e:int, $ghost_f:int, $ghost_g:int, $ghost_h:int, $ghost_z:SHA256Trace, $ghost_currentBlock:int, $ghost_currentStep:int, K:opn, Wopn:opn_mem, W_base:int, $ghost_W__abs:int) returns(my r:regs, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars, $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap, $ghost_a_next:int, $ghost_b_next:int, $ghost_c_next:int, $ghost_d_next:int, $ghost_e_next:int, $ghost_f_next:int, $ghost_g_next:int, $ghost_h_next:int, $ghost_next_atoh:atoh_Type, $ghost_next_z:SHA256Trace) requires MemInv(me,init,stk_old,statics_old,core_state,ptMem,mems_old); requires NucleusInv(objLayouts_old,$S,$toAbs_old,$absMem_old,$commonVars_old,$gcVars_old,me,init,stk_old,statics_old,core_state,ptMem,mems_old,$stacksFrames_old,io_old); //requires SMemRequireGcRA(stack_size__DafnyCC__Proc_ComputeOneStep__SHA256__optimized, 84, stk_old, r_old.regs[ESP], RET); requires SMemRequireGcRA(0, 76, stk_old, r_old.regs[ESP], RET); // requires SMemRequire(stack_size__DafnyCC__Proc_ComputeOneStep__SHA256__optimized, stk_old, r_old.regs[ESP]); // requires ?sLo + stack_size__DafnyCC__Proc_ComputeOneStep__SHA256__optimized <= r_old.regs[ESP]; requires HeapInv($absMem_old, objLayouts_old, heap_old); requires (($ghost_words) == (stk_old.map[r_old.regs[ESP] + 36])); requires (($ghost_num_blocks) == (stk_old.map[r_old.regs[ESP] + 40])); //requires (($ghost_a) == (stk_old.map[r_old.regs[ESP] + 44])); requires $ghost_a == r_old.regs[EBP]; requires (($ghost_b) == (stk_old.map[r_old.regs[ESP] + 8])); requires (($ghost_c) == (stk_old.map[r_old.regs[ESP] + 12])); requires (($ghost_d) == (stk_old.map[r_old.regs[ESP] + 16])); requires (($ghost_e) == (stk_old.map[r_old.regs[ESP] + 20])); requires (($ghost_f) == (stk_old.map[r_old.regs[ESP] + 24])); requires (($ghost_g) == (stk_old.map[r_old.regs[ESP] + 28])); requires (($ghost_h) == (stk_old.map[r_old.regs[ESP] + 32])); //requires (($ghost_currentBlock) == (stk_old.map[r_old.regs[ESP] + 76])); //requires (($ghost_currentStep) == (stk_old.map[r_old.regs[ESP] + 80])); requires EvalPtrOk(Wopn); requires EvalPtr(r_old, Wopn) == W_base + 4 * (2 + $ghost_currentStep); requires Wopn._ptr is MReg && Wopn._ptr._mreg == ESI; requires $ghost_W.arrAbs == $ghost_W__abs; requires HeapAbsData(heap_old, $ghost_W__abs) is Abs_ArrayOfInt; requires 0 <= $ghost_currentStep && $ghost_currentStep < HeapAbsData(heap_old, $ghost_W__abs).arr.arrCount; requires HeapValue(objLayouts_old, true, $toAbs_old, W_base, $ghost_W__abs); requires StackAbsSlot(heap_old, $stacksFrames_old, r_old.regs[ESP] + 4 + stackGcOffset) == Abs_ArrayOfInt($ghost_M); requires frameGet($stacksFrames_old, r_old.regs[ESP] + 4 + stackGcOffset) == $ghost_M.arrAbs; requires StackAbsSlot(heap_old, $stacksFrames_old, r_old.regs[ESP] + 8 + stackGcOffset) == Abs_ArrayOfInt($ghost_H); requires frameGet($stacksFrames_old, r_old.regs[ESP] + 8 + stackGcOffset) == $ghost_H.arrAbs; requires StackAbsSlot(heap_old, $stacksFrames_old, r_old.regs[ESP] + 12 + stackGcOffset) == Abs_ArrayOfInt($ghost_W); requires frameGet($stacksFrames_old, r_old.regs[ESP] + 12 + stackGcOffset) == $ghost_W.arrAbs; requires $ghost_H != (ArrayOfInt(0 - 1, NO_ABS)); requires $ghost_W != (ArrayOfInt(0 - 1, NO_ABS)); requires $ghost_M != (ArrayOfInt(0 - 1, NO_ABS)); requires $ghost_atoh == (atoh_c($ghost_a, $ghost_b, $ghost_c, $ghost_d, $ghost_e, $ghost_f, $ghost_g, $ghost_h)); requires (INTERNAL_le_boogie(0, $ghost_words)) && (INTERNAL_le_boogie($ghost_words, (Arr_Length($ghost_M)))); requires (INTERNAL_le_boogie(0, $ghost_currentBlock)) && (INTERNAL_lt_boogie($ghost_currentBlock, fun_Seq__Length___Seq___int((M#SHA256Trace_c($ghost_z))))); requires (INTERNAL_le_boogie(0, $ghost_currentStep)) && (INTERNAL_le_boogie($ghost_currentStep, 63)); requires K is OConst && K._const == fun_K__SHA256($ghost_currentStep); requires fun_IsSHA256ReadyForStep($ghost_z, fun_SHA256__vars__to__state($absMem_old, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_atoh, $ghost_num_blocks), $ghost_currentBlock, $ghost_currentStep); modifies $Time; ensures r.regs[ESP] == old(r_old.regs[ESP]); ensures MemInv(me,init,stk,statics,core_state,ptMem,mems); ensures NucleusInv(objLayouts,$S,$toAbs,$absMem,$commonVars,$gcVars,me,init,stk,statics,core_state,ptMem,mems,$stacksFrames,io); //ensures SMemEnsureGcF(84, stk, old(stk_old), r.regs[ESP], old(r_old.regs[ESP]), $stacksFrames, $stacksFrames_old); ensures r.regs[ESP] == old(r_old.regs[ESP]); ensures r.regs[ESI] == old(r_old.regs[ESI]); ensures stk[r.regs[ESP]] == old(stk_old)[r.regs[ESP]]; ensures (forall i:int::{stk[i]} r.regs[ESP] + 76 <= i ==> stk[i] == old(stk_old)[i]); ensures (forall i:int::{$stacksFrames[$S].Abss[i]} r.regs[ESP] + 76 + stackGcOffset <= i ==> $stacksFrames[$S].Abss[i] == $stacksFrames_old[$S].Abss[i]); ensures HeapInv($absMem, objLayouts, heap); ensures AbsExtend($toAbs, $toAbs_old, objLayouts, objLayouts_old); ensures (forall i:int::{$absMem[i]}{heap.absData[i]} heap_old.absData[i] is AbsNone || (heap.absData[i] == heap_old.absData[i] && ($absMem[i] == $absMem_old[i]))); ensures io._inCtr == io_old._inCtr && io._outCtr == io_old._outCtr; ensures fun_IsSHA256ReadyForStep($ghost_next_z, fun_SHA256__vars__to__state($absMem, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_next_atoh, $ghost_num_blocks), $ghost_currentBlock, INTERNAL_add_boogie($ghost_currentStep, 1)); ensures fun_Seq__Equal___int(fun_Seq__FromArray($absMem, $ghost_H), old(fun_Seq__FromArray($absMem_old, $ghost_H))); ensures fun_Seq__Equal___int(fun_Seq__FromArray($absMem, $ghost_M), old(fun_Seq__FromArray($absMem_old, $ghost_M))); ensures fun_Seq__Equal___int(fun_Seq__FromArray($absMem, $ghost_W), old(fun_Seq__FromArray($absMem_old, $ghost_W))); ensures $ghost_next_atoh == (atoh_c($ghost_a_next, $ghost_b_next, $ghost_c_next, $ghost_d_next, $ghost_e_next, $ghost_f_next, $ghost_g_next, $ghost_h_next)); //ensures (($ghost_a_next) == (stk.map[r_old.regs[ESP] + 4])); ensures $ghost_a_next == r.regs[EBP]; ensures (($ghost_b_next) == (stk.map[r_old.regs[ESP] + 48])); ensures (($ghost_c_next) == (stk.map[r_old.regs[ESP] + 52])); ensures (($ghost_d_next) == (stk.map[r_old.regs[ESP] + 56])); ensures (($ghost_e_next) == (stk.map[r_old.regs[ESP] + 60])); ensures (($ghost_f_next) == (stk.map[r_old.regs[ESP] + 64])); ensures (($ghost_g_next) == (stk.map[r_old.regs[ESP] + 68])); ensures (($ghost_h_next) == (stk.map[r_old.regs[ESP] + 72])); //- Preserve calling requirements ensures (($ghost_words) == (stk.map[r.regs[ESP] + 36])); ensures (($ghost_num_blocks) == (stk.map[r.regs[ESP] + 40])); ensures HeapValue(objLayouts, true, $toAbs, W_base, $ghost_W__abs); ensures StackAbsSlot(heap, $stacksFrames, r.regs[ESP] + 4 + stackGcOffset) == Abs_ArrayOfInt($ghost_M); ensures frameGet($stacksFrames, r.regs[ESP] + 4 + stackGcOffset) == $ghost_M.arrAbs; ensures StackAbsSlot(heap, $stacksFrames, r.regs[ESP] + 8 + stackGcOffset) == Abs_ArrayOfInt($ghost_H); ensures frameGet($stacksFrames, r.regs[ESP] + 8 + stackGcOffset) == $ghost_H.arrAbs; ensures StackAbsSlot(heap, $stacksFrames, r.regs[ESP] + 12 + stackGcOffset) == Abs_ArrayOfInt($ghost_W); ensures frameGet($stacksFrames, r.regs[ESP] + 12 + stackGcOffset) == $ghost_W.arrAbs; { var t:opn_mem; var $result:int; var $result2:int; // Lots of boilerplate follows var $absMem_tmp:[int][int]int; var objLayouts_tmp:[int]ObjLayout; var heap_tmp:Heap; var obj_tmp:int; var val_tmp:int; var $ghost_s:SHA256_state; var $ghost_bsig0:int; var $ghost__temp__0:int; var $ghost__temp__1:int; var $ghost__temp__2:int; var $ghost__temp__3:int; var $ghost_bsig1:int; var $ghost__temp__4:int; var $ghost__temp__5:int; var $ghost__temp__6:int; var $ghost__temp__7:int; var $ghost_my_ch:int; var $ghost__temp__8:int; var $ghost__temp__9:int; var $ghost__temp__10:int; var $ghost_my_maj:int; var $ghost__temp__11:int; var $ghost__temp__12:int; var $ghost__temp__13:int; var $ghost__temp__14:int; var $ghost_T1:int; var $ghost__temp__15:int; var $ghost__temp__16:int; var $ghost__temp__17:int; var $ghost__temp__18:int; var $ghost__temp__19:int; var $ghost_T2:int; var $ghost_next_s:SHA256_state; var $ghost_M__abs:int; var $ghost_H__abs:int; assert fun_unroll(0); assert fun_unroll(1); call lemma_unroll_rec_fun____HASH_Seq__Length__FULL___int(); call lemma_unroll_fun____HASH_Seq__Length__FULL___int(); call lemma_fun_ensures_fun_Seq__Length___int(); call lemma_unroll_rec_fun____HASH_Seq__Build__FULL___int(); call lemma_unroll_fun____HASH_Seq__Build__FULL___int(); call lemma_unroll_rec_fun____HASH_Seq__Index__FULL___int(); call lemma_unroll_fun____HASH_Seq__Index__FULL___int(); call lemma_unroll_rec_fun____HASH_Seq__Append__FULL___int(); call lemma_unroll_fun____HASH_Seq__Append__FULL___int(); call lemma_unroll_rec_fun____HASH_Seq__Update__FULL___int(); call lemma_unroll_fun____HASH_Seq__Update__FULL___int(); call lemma_unroll_rec_fun____HASH_Seq__Take__FULL___int(); call lemma_unroll_fun____HASH_Seq__Take__FULL___int(); call lemma_unroll_rec_fun____HASH_Seq__Drop__FULL___int(); call lemma_unroll_fun____HASH_Seq__Drop__FULL___int(); call proc_Seq__Empty__ToZero___int(); call proc_Seq__Empty__FromZero___int(); call proc_Seq__Singleton__Length___int(); call proc_Seq__Build__Length___int(); call proc_Seq__Build__Index___int(); call proc_Seq__Append__Length___int(); call proc_Seq__Index__Singleton___int(); call proc_Seq__Append__Index___int(); call proc_Seq__Update__Length___int(); call proc_Seq__Index__Update___int(); call proc_Seq__Equal__Equiv___int(); call proc_Seq__Take__Length___int(); call proc_Seq__Take__Index___int(); call proc_Seq__Drop__Length___int(); call proc_Seq__Drop__Index___int(); call proc_Seq__Append__TakeDrop__Restricted___int(); call proc_Seq__Update__CommuteTake1___int(); call proc_Seq__Update__CommuteTake2___int(); call proc_Seq__Update__CommuteDrop1___int(); call proc_Seq__Update__CommuteDrop2___int(); call proc_Seq__Build__CommuteDrop___int(); call proc_Seq__Take__Empty___int(); call proc_Seq__Drop__Empty___int(); call lemma_unroll_fun_Seq__FromArrayRange(); call proc_Seq__FromArray__Length(); call proc_Seq__FromArray__Index(); call proc_Seq__FromArray__Update(); call lemma_unroll_rec_fun____HASH_power2__FULL(); call lemma_unroll_fun____HASH_power2__FULL(); call lemma_fun_ensures_fun_power2(); call lemma_unroll_rec_fun____HASH_BEDigitSeqToInt__private__FULL(); call lemma_unroll_fun____HASH_BEDigitSeqToInt__private__FULL(); call lemma_unroll_rec_fun____HASH_BEIntToDigitSeq__private__FULL(); call lemma_unroll_fun____HASH_BEIntToDigitSeq__private__FULL(); call lemma_unroll_rec_fun_RepeatDigit(); call lemma_unroll_fun_RepeatDigit(); call lemma_unroll_rec_fun____HASH_Reverse__FULL(); call lemma_unroll_fun____HASH_Reverse__FULL(); call lemma_unroll_rec_fun____HASH_power__FULL(); call lemma_unroll_fun____HASH_power__FULL(); call lemma_unroll_rec_fun_mul__pos(); call lemma_unroll_fun_mul__pos(); call lemma_unroll_rec_fun____HASH_Seq__Length__FULL___bool(); call lemma_unroll_fun____HASH_Seq__Length__FULL___bool(); call lemma_fun_ensures_fun_Seq__Length___bool(); call lemma_unroll_rec_fun____HASH_Seq__Build__FULL___bool(); call lemma_unroll_fun____HASH_Seq__Build__FULL___bool(); call lemma_unroll_rec_fun____HASH_Seq__Index__FULL___bool(); call lemma_unroll_fun____HASH_Seq__Index__FULL___bool(); call lemma_unroll_rec_fun____HASH_Seq__Append__FULL___bool(); call lemma_unroll_fun____HASH_Seq__Append__FULL___bool(); call lemma_unroll_rec_fun____HASH_Seq__Update__FULL___bool(); call lemma_unroll_fun____HASH_Seq__Update__FULL___bool(); call lemma_unroll_rec_fun____HASH_Seq__Take__FULL___bool(); call lemma_unroll_fun____HASH_Seq__Take__FULL___bool(); call lemma_unroll_rec_fun____HASH_Seq__Drop__FULL___bool(); call lemma_unroll_fun____HASH_Seq__Drop__FULL___bool(); call proc_Seq__Empty__ToZero___bool(); call proc_Seq__Empty__FromZero___bool(); call proc_Seq__Singleton__Length___bool(); call proc_Seq__Build__Length___bool(); call proc_Seq__Build__Index___bool(); call proc_Seq__Append__Length___bool(); call proc_Seq__Index__Singleton___bool(); call proc_Seq__Append__Index___bool(); call proc_Seq__Update__Length___bool(); call proc_Seq__Index__Update___bool(); call proc_Seq__Equal__Equiv___bool(); call proc_Seq__Take__Length___bool(); call proc_Seq__Take__Index___bool(); call proc_Seq__Drop__Length___bool(); call proc_Seq__Drop__Index___bool(); call proc_Seq__Append__TakeDrop__Restricted___bool(); call proc_Seq__Update__CommuteTake1___bool(); call proc_Seq__Update__CommuteTake2___bool(); call proc_Seq__Update__CommuteDrop1___bool(); call proc_Seq__Update__CommuteDrop2___bool(); call proc_Seq__Build__CommuteDrop___bool(); call proc_Seq__Take__Empty___bool(); call proc_Seq__Drop__Empty___bool(); call lemma_unroll_rec_fun_my__div__pos(); call lemma_unroll_fun_my__div__pos(); call lemma_unroll_rec_fun_my__mod__recursive(); call lemma_unroll_fun_my__mod__recursive(); call lemma_fun_ensures_fun_RepeatDigit__premium(); call lemma_unroll_rec_fun____HASH_SequenceOfZeros__FULL(); call lemma_unroll_fun____HASH_SequenceOfZeros__FULL(); call lemma_fun_ensures_fun_SequenceOfZeros(); call lemma_fun_ensures_fun_BitwiseAnd(); call lemma_fun_ensures_fun_BitwiseOr(); call lemma_fun_ensures_fun_BitwiseNot(); call lemma_fun_ensures_fun_BitwiseXor(); call lemma_fun_ensures_fun_RotateRight(); call lemma_fun_ensures_fun_RotateLeft(); call lemma_fun_ensures_fun_RightShift(); call lemma_fun_ensures_fun_LeftShift(); call lemma_fun_ensures_fun_Add32(); call lemma_fun_ensures_fun_Sub32(); call lemma_fun_ensures_fun_Mul32(); call lemma_fun_ensures_fun_Div32(); call lemma_fun_ensures_fun_Mod32(); call lemma_unroll_rec_fun____HASH_NatNumBits__FULL(); call lemma_unroll_fun____HASH_NatNumBits__FULL(); call lemma_fun_ensures_fun_NatNumBits(); call lemma_fun_ensures_fun_asm__Add(); call lemma_fun_ensures_fun_asm__Sub(); call lemma_fun_ensures_fun_asm__Mul(); call lemma_fun_ensures_fun_asm__Div(); call lemma_fun_ensures_fun_asm__Mod(); call lemma_fun_ensures_fun_asm__LeftShift(); call lemma_fun_ensures_fun_asm__RightShift(); call lemma_fun_ensures_fun_asm__RotateLeft(); call lemma_fun_ensures_fun_asm__RotateRight(); call lemma_fun_ensures_fun_asm__BitwiseNot(); call lemma_fun_ensures_fun_asm__BitwiseAnd(); call lemma_fun_ensures_fun_asm__BitwiseOr(); call lemma_fun_ensures_fun_asm__BitwiseXor(); call lemma_unroll_rec_fun____HASH_LEDigitSeqToInt__private__FULL(); call lemma_unroll_fun____HASH_LEDigitSeqToInt__private__FULL(); call lemma_fun_ensures_fun_BEDigitSeqToInt__premium(); call lemma_fun_ensures_fun_BEWordSeqToInt__premium(); call lemma_fun_ensures_fun_BEIntToDigitSeq__premium(); call lemma_fun_ensures_fun_BEIntToByteSeq__premium(); call lemma_fun_ensures_fun_BEWordToFourBytes__premium(); call lemma_fun_ensures_fun_BEWordToBitSeq__premium(); call lemma_fun_ensures_fun_BEWordSeqToBitSeq__premium(); call lemma_fun_ensures_fun_BEByteSeqToBitSeq__premium(); call lemma_fun_ensures_fun_BEWordSeqToByteSeq__premium(); call lemma_fun_ensures_fun_Asm__Add(); call lemma_fun_ensures_fun_Asm__Sub(); call lemma_fun_ensures_fun_Asm__Mul(); call lemma_fun_ensures_fun_Asm__Div(); call lemma_fun_ensures_fun_Asm__Mod(); call lemma_fun_ensures_fun_Asm__LeftShift(); call lemma_fun_ensures_fun_Asm__RightShift(); call lemma_fun_ensures_fun_Asm__RotateLeft(); call lemma_fun_ensures_fun_Asm__RotateRight(); call lemma_fun_ensures_fun_Asm__BitwiseNot(); call lemma_fun_ensures_fun_Asm__BitwiseAnd(); call lemma_fun_ensures_fun_Asm__BitwiseOr(); call lemma_fun_ensures_fun_Asm__BitwiseXor(); call lemma_fun_ensures_fun_ComputePower2(); call lemma_fun_ensures_fun_ComputePower2Minus1__mostly(); call lemma_fun_ensures_fun_ComputePower2Minus1(); call lemma_fun_ensures_fun_GetWordBit(); call lemma_unroll_rec_fun____HASH_Seq__Length__FULL___Seq___int(); call lemma_unroll_fun____HASH_Seq__Length__FULL___Seq___int(); call lemma_fun_ensures_fun_Seq__Length___Seq___int(); call lemma_unroll_rec_fun____HASH_Seq__Build__FULL___Seq___int(); call lemma_unroll_fun____HASH_Seq__Build__FULL___Seq___int(); call lemma_unroll_rec_fun____HASH_Seq__Index__FULL___Seq___int(); call lemma_unroll_fun____HASH_Seq__Index__FULL___Seq___int(); call lemma_unroll_rec_fun____HASH_Seq__Append__FULL___Seq___int(); call lemma_unroll_fun____HASH_Seq__Append__FULL___Seq___int(); call lemma_unroll_rec_fun____HASH_Seq__Update__FULL___Seq___int(); call lemma_unroll_fun____HASH_Seq__Update__FULL___Seq___int(); call lemma_unroll_rec_fun____HASH_Seq__Take__FULL___Seq___int(); call lemma_unroll_fun____HASH_Seq__Take__FULL___Seq___int(); call lemma_unroll_rec_fun____HASH_Seq__Drop__FULL___Seq___int(); call lemma_unroll_fun____HASH_Seq__Drop__FULL___Seq___int(); call proc_Seq__Empty__ToZero___Seq___int(); call proc_Seq__Empty__FromZero___Seq___int(); call proc_Seq__Singleton__Length___Seq___int(); call proc_Seq__Build__Length___Seq___int(); call proc_Seq__Build__Index___Seq___int(); call proc_Seq__Append__Length___Seq___int(); call proc_Seq__Index__Singleton___Seq___int(); call proc_Seq__Append__Index___Seq___int(); call proc_Seq__Update__Length___Seq___int(); call proc_Seq__Index__Update___Seq___int(); call proc_Seq__Equal__Equiv___Seq___int(); call proc_Seq__Take__Length___Seq___int(); call proc_Seq__Take__Index___Seq___int(); call proc_Seq__Drop__Length___Seq___int(); call proc_Seq__Drop__Index___Seq___int(); call proc_Seq__Append__TakeDrop__Restricted___Seq___int(); call proc_Seq__Update__CommuteTake1___Seq___int(); call proc_Seq__Update__CommuteTake2___Seq___int(); call proc_Seq__Update__CommuteDrop1___Seq___int(); call proc_Seq__Update__CommuteDrop2___Seq___int(); call proc_Seq__Build__CommuteDrop___Seq___int(); call proc_Seq__Take__Empty___Seq___int(); call proc_Seq__Drop__Empty___Seq___int(); call lemma_unroll_rec_fun____HASH_BreakIntoBlocks__FULL(); call lemma_unroll_fun____HASH_BreakIntoBlocks__FULL(); call lemma_fun_ensures_fun____HASH_Ch__FULL(); call lemma_fun_ensures_fun_Ch(); call lemma_fun_ensures_fun____HASH_Maj__FULL(); call lemma_fun_ensures_fun_Maj(); call lemma_fun_ensures_fun____HASH_Parity__FULL(); call lemma_fun_ensures_fun_Parity(); call lemma_fun_ensures_fun____HASH_ft__FULL(); call lemma_fun_ensures_fun_ft(); call lemma_fun_ensures_fun____HASH_BSIG0__FULL(); call lemma_fun_ensures_fun_BSIG0(); call lemma_fun_ensures_fun____HASH_BSIG1__FULL(); call lemma_fun_ensures_fun_BSIG1(); call lemma_fun_ensures_fun____HASH_SSIG0__FULL(); call lemma_fun_ensures_fun_SSIG0(); call lemma_fun_ensures_fun____HASH_SSIG1__FULL(); call lemma_fun_ensures_fun_SSIG1(); call lemma_fun_ensures_fun____HASH_NumPaddingZeroes__FULL(); call lemma_fun_ensures_fun_NumPaddingZeroes(); call lemma_unroll_rec_fun____HASH_SeqXor__FULL(); call lemma_unroll_fun____HASH_SeqXor__FULL(); call lemma_unroll_rec_fun____HASH_ConstPad__FULL(); call lemma_unroll_fun____HASH_ConstPad__FULL(); call lemma_fun_ensures_fun____HASH_GetArrayBit__FULL(); call lemma_fun_ensures_fun_GetArrayBit(); call lemma_fun_ensures_fun_DivideRoundingUp__premium(); call lemma_fun_ensures_fun_RoundUpToMultiple__premium(); call lemma_fun_ensures_fun_PadSequenceToMultiple__premium(); call lemma_fun_ensures_fun_PadAndBreakIntoBlocks__premium(); call lemma_fun_ensures_fun_Ch__impl(); call lemma_fun_ensures_fun_Maj__impl(); call lemma_fun_ensures_fun_Parity__impl(); call lemma_fun_ensures_fun_ft__impl(); call lemma_fun_ensures_fun_BSIG0__impl(); call lemma_fun_ensures_fun_BSIG1__impl(); call lemma_fun_ensures_fun_SSIG0__impl(); call lemma_fun_ensures_fun_SSIG1__impl(); call lemma_fun_ensures_fun_PadMessageForSHA__premium(); call lemma_fun_ensures_fun____HASH_GetArrayBitOpaque__FULL(); call lemma_fun_ensures_fun_GetArrayBitOpaque(); call lemma_fun_ensures_fun____HASH_K__SHA256__FULL(); call lemma_fun_ensures_fun_K__SHA256(); call lemma_fun_ensures_fun____HASH_InitialH__SHA256__FULL(); call lemma_fun_ensures_fun_InitialH__SHA256(); call lemma_unroll_rec_fun____HASH_Seq__Length__FULL___atoh_Type(); call lemma_unroll_fun____HASH_Seq__Length__FULL___atoh_Type(); call lemma_fun_ensures_fun_Seq__Length___atoh_Type(); call lemma_unroll_rec_fun____HASH_Seq__Build__FULL___atoh_Type(); call lemma_unroll_fun____HASH_Seq__Build__FULL___atoh_Type(); call lemma_unroll_rec_fun____HASH_Seq__Index__FULL___atoh_Type(); call lemma_unroll_fun____HASH_Seq__Index__FULL___atoh_Type(); call lemma_unroll_rec_fun____HASH_Seq__Append__FULL___atoh_Type(); call lemma_unroll_fun____HASH_Seq__Append__FULL___atoh_Type(); call lemma_unroll_rec_fun____HASH_Seq__Update__FULL___atoh_Type(); call lemma_unroll_fun____HASH_Seq__Update__FULL___atoh_Type(); call lemma_unroll_rec_fun____HASH_Seq__Take__FULL___atoh_Type(); call lemma_unroll_fun____HASH_Seq__Take__FULL___atoh_Type(); call lemma_unroll_rec_fun____HASH_Seq__Drop__FULL___atoh_Type(); call lemma_unroll_fun____HASH_Seq__Drop__FULL___atoh_Type(); call proc_Seq__Empty__ToZero___atoh_Type(); call proc_Seq__Empty__FromZero___atoh_Type(); call proc_Seq__Singleton__Length___atoh_Type(); call proc_Seq__Build__Length___atoh_Type(); call proc_Seq__Build__Index___atoh_Type(); call proc_Seq__Append__Length___atoh_Type(); call proc_Seq__Index__Singleton___atoh_Type(); call proc_Seq__Append__Index___atoh_Type(); call proc_Seq__Update__Length___atoh_Type(); call proc_Seq__Index__Update___atoh_Type(); call proc_Seq__Equal__Equiv___atoh_Type(); call proc_Seq__Take__Length___atoh_Type(); call proc_Seq__Take__Index___atoh_Type(); call proc_Seq__Drop__Length___atoh_Type(); call proc_Seq__Drop__Index___atoh_Type(); call proc_Seq__Append__TakeDrop__Restricted___atoh_Type(); call proc_Seq__Update__CommuteTake1___atoh_Type(); call proc_Seq__Update__CommuteTake2___atoh_Type(); call proc_Seq__Update__CommuteDrop1___atoh_Type(); call proc_Seq__Update__CommuteDrop2___atoh_Type(); call proc_Seq__Build__CommuteDrop___atoh_Type(); call proc_Seq__Take__Empty___atoh_Type(); call proc_Seq__Drop__Empty___atoh_Type(); call lemma_unroll_rec_fun____HASH_Seq__Length__FULL___Seq___atoh_Type(); call lemma_unroll_fun____HASH_Seq__Length__FULL___Seq___atoh_Type(); call lemma_fun_ensures_fun_Seq__Length___Seq___atoh_Type(); call lemma_unroll_rec_fun____HASH_Seq__Build__FULL___Seq___atoh_Type(); call lemma_unroll_fun____HASH_Seq__Build__FULL___Seq___atoh_Type(); call lemma_unroll_rec_fun____HASH_Seq__Index__FULL___Seq___atoh_Type(); call lemma_unroll_fun____HASH_Seq__Index__FULL___Seq___atoh_Type(); call lemma_unroll_rec_fun____HASH_Seq__Append__FULL___Seq___atoh_Type(); call lemma_unroll_fun____HASH_Seq__Append__FULL___Seq___atoh_Type(); call lemma_unroll_rec_fun____HASH_Seq__Update__FULL___Seq___atoh_Type(); call lemma_unroll_fun____HASH_Seq__Update__FULL___Seq___atoh_Type(); call lemma_unroll_rec_fun____HASH_Seq__Take__FULL___Seq___atoh_Type(); call lemma_unroll_fun____HASH_Seq__Take__FULL___Seq___atoh_Type(); call lemma_unroll_rec_fun____HASH_Seq__Drop__FULL___Seq___atoh_Type(); call lemma_unroll_fun____HASH_Seq__Drop__FULL___Seq___atoh_Type(); call proc_Seq__Empty__ToZero___Seq___atoh_Type(); call proc_Seq__Empty__FromZero___Seq___atoh_Type(); call proc_Seq__Singleton__Length___Seq___atoh_Type(); call proc_Seq__Build__Length___Seq___atoh_Type(); call proc_Seq__Build__Index___Seq___atoh_Type(); call proc_Seq__Append__Length___Seq___atoh_Type(); call proc_Seq__Index__Singleton___Seq___atoh_Type(); call proc_Seq__Append__Index___Seq___atoh_Type(); call proc_Seq__Update__Length___Seq___atoh_Type(); call proc_Seq__Index__Update___Seq___atoh_Type(); call proc_Seq__Equal__Equiv___Seq___atoh_Type(); call proc_Seq__Take__Length___Seq___atoh_Type(); call proc_Seq__Take__Index___Seq___atoh_Type(); call proc_Seq__Drop__Length___Seq___atoh_Type(); call proc_Seq__Drop__Index___Seq___atoh_Type(); call proc_Seq__Append__TakeDrop__Restricted___Seq___atoh_Type(); call proc_Seq__Update__CommuteTake1___Seq___atoh_Type(); call proc_Seq__Update__CommuteTake2___Seq___atoh_Type(); call proc_Seq__Update__CommuteDrop1___Seq___atoh_Type(); call proc_Seq__Update__CommuteDrop2___Seq___atoh_Type(); call proc_Seq__Build__CommuteDrop___Seq___atoh_Type(); call proc_Seq__Take__Empty___Seq___atoh_Type(); call proc_Seq__Drop__Empty___Seq___atoh_Type(); call lemma_fun_ensures_fun_SHA256(); r := r_old; stk := stk_old; statics := statics_old; io := io_old; mems := mems_old; $commonVars := $commonVars_old; $gcVars := $gcVars_old; $toAbs := $toAbs_old; $absMem := $absMem_old; $stacksFrames := $stacksFrames_old; objLayouts := objLayouts_old; heap := heap_old; $ghost_M__abs := frameGet($stacksFrames, r_old.regs[ESP] + 4 + stackGcOffset); $ghost_H__abs := frameGet($stacksFrames, r_old.regs[ESP] + 8 + stackGcOffset); assert TV(r.regs[ESP]); assert TO(0 - 1); assert TO(279552 - 1); assert TO(0 - 2); assert TO(279552 - 2); assert TO(0); assert TO(279552); assert TO(1); assert TO(279553); assert TO(2); assert TO(279554); assert TO(3); assert TO(279555); assert TO(4); assert TO(279556); assert TO(5); assert TO(279557); assert TO(6); assert TO(279558); assert TO(7); assert TO(279559); assert TO(8); assert TO(279560); assert TO(9); assert TO(279561); assert TO(10); assert TO(279562); assert TO(11); assert TO(279563); assert TO(12); assert TO(279564); assert TO(13); assert TO(279565); assert TO(14); assert TO(279566); assert TO(15); assert TO(279567); assert TO(16); assert TO(279568); assert TO(17); assert TO(279569); assert TO(18); assert TO(279570); assert TO(19); assert TO(279571); assert TO(20); assert TO(279572); assert TO(21); call proc_lemma__2toX(); call proc_lemma__word32__Word32(); call reveal_WORD_HI(); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt2.i.dfy: 38 $ghost_s := fun_SHA256__vars__to__state($absMem, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_atoh, $ghost_num_blocks); // assert Aligned(esp); // // Prove that we can load arguments from the stack (b/c accesses are aligned) // assert TV(esp) && TO(0) && TO(1) && TO(2) && TO(3) && TO(4) && TO(5); // // // Prove that we can load arguments from the GC stack (b/c accesses are aligned) // assert TO(0x44401) && TO(0x44402) && TO(0x44403); // (gcStackOffset + {4,8,12}) / 4 //- Calculate my_maj //t := OMem(MReg(ESP, 44)); //assert EvalPtrOk(t); //assert stk.dom[EvalPtr(r, t)]; //assert Aligned(EvalPtr(r, t)); //assert PhysPtrOk(stk, EvalPtr(r, t)); //assert word(EvalPtr(r, t)); // //call eax := Load(stk, esp + 44); // grab a //assert eax == $ghost_a; assert ebp == $ghost_a; call logical_Store(r, core_state, inout stk, OMem(MReg(ESP, 48)), OReg(EBP)); //- b_next <- a call ebx := Load(stk, esp + 8); //- grab b assert ebx == $ghost_b; call logical_Store(r, core_state, inout stk, OMem(MReg(ESP, 52)), OReg(EBX)); //- c_next <- b call ecx := Load(stk, esp + 12); //- grab c assert ecx == $ghost_c; call logical_Store(r, core_state, inout stk, OMem(MReg(ESP, 56)), OReg(ECX)); //- d_next <- c edx := ebx; //- Store a copy of b call r, $result := proc_Asm__BitwiseAnd(r, $ghost_b, $ghost_a, EBX, OReg(EBP)); call proc_lemma__bitwise__and__commutative($ghost_b, $ghost_a); assert fun_Asm__BitwiseAnd($ghost_b, $ghost_a) == fun_Asm__BitwiseAnd($ghost_a, $ghost_b); call r, $result := proc_Asm__BitwiseAnd(r, $ghost_b, $ghost_c, EDX, OReg(ECX)); call r, $result := proc_Asm__BitwiseAnd(r, $ghost_c, $ghost_a, ECX, OReg(EBP)); call proc_lemma__bitwise__and__commutative($ghost_c, $ghost_a); assert fun_Asm__BitwiseAnd($ghost_c, $ghost_a) == fun_Asm__BitwiseAnd($ghost_a, $ghost_c); call r, $result := proc_Asm__BitwiseXor(r, fun_Asm__BitwiseAnd($ghost_b, $ghost_a), fun_Asm__BitwiseAnd($ghost_c, $ghost_a), EBX, OReg(ECX)); call r, $ghost_my_maj := proc_Asm__BitwiseXor(r, $result, fun_Asm__BitwiseAnd($ghost_b, $ghost_c), EBX, OReg(EDX)); forall::($ghost_my_maj == (fun_Maj($ghost_a, $ghost_b, $ghost_c))) { call proc_reveal__Maj(); } //- At this point, ebp == a, ebx == my_maj assert ebp == $ghost_a; assert ebx == fun_Maj($ghost_a, $ghost_b, $ghost_c); //- Calculate bsig0 ecx := ebp; edx := ebp; call r, $result := proc_Asm__RotateRight(r, $ghost_a, 2, EBP, OConst(2)); call r, $result := proc_Asm__RotateRight(r, $ghost_a, 13, ECX, OConst(13)); call r, $result := proc_Asm__BitwiseXor(r, fun_Asm__RotateRight($ghost_a, 2), fun_Asm__RotateRight($ghost_a, 13), EBP, OReg(ECX)); call r, $result2 := proc_Asm__RotateRight(r, $ghost_a, 22, EDX, OConst(22)); call r, $ghost_bsig0 := proc_Asm__BitwiseXor(r, $result, fun_Asm__RotateRight($ghost_a, 22), EBP, OReg(EDX)); forall::($ghost_bsig0 == (fun_BSIG0($ghost_a))) { call proc_reveal__BSIG0(); } assert ebp == fun_BSIG0($ghost_a); call r, $ghost_T2 := proc_Asm__Add(r, $ghost_bsig0, $ghost_my_maj, EBP, OReg(EBX)); assert ebp == $ghost_T2; //- Calculate my_ch call ebx := Load(stk, esp + 20); //- grab e assert ebx == $ghost_e; call logical_Store(r, core_state, inout stk, OMem(MReg(ESP, 64)), OReg(EBX)); //- f_next <- e edx := ebx; call r, $result := proc_Asm__BitwiseNot(r, $ghost_e, EDX); call ecx := Load(stk, esp + 28); //- grab g assert ecx == $ghost_g; call logical_Store(r, core_state, inout stk, OMem(MReg(ESP, 72)), OReg(ECX)); //- h_next <- g call r, $result := proc_Asm__BitwiseAnd(r, $result, $ghost_g, EDX, OReg(ECX)); //- !e & g assert edx == fun_Asm__BitwiseAnd(fun_Asm__BitwiseNot($ghost_e), $ghost_g); call ecx := Load(stk, esp + 24); //- grab f assert ecx == $ghost_f; call logical_Store(r, core_state, inout stk, OMem(MReg(ESP, 68)), OReg(ECX)); //- g_next <- f call r, $result2 := proc_Asm__BitwiseAnd(r, $ghost_f, $ghost_e, ECX, OReg(EBX)); call proc_lemma__bitwise__and__commutative($ghost_f, $ghost_e); assert fun_Asm__BitwiseAnd($ghost_f, $ghost_e) == fun_Asm__BitwiseAnd($ghost_e, $ghost_f); call r, $ghost_my_ch := proc_Asm__BitwiseXor(r, $result2, $result, ECX, OReg(EDX)); forall::($ghost_my_ch == (fun_Ch($ghost_e, $ghost_f, $ghost_g))) { call proc_reveal__Ch(); } //- Summary: assert ebp == $ghost_T2; assert ebx == $ghost_e; assert ecx == fun_Ch($ghost_e, $ghost_f, $ghost_g); //- Calculate bsig1 edx := ebx; edi := ebx; call r, $result := proc_Asm__RotateRight(r, $ghost_e, 6, EDX, OConst(6)); call r, $result2 := proc_Asm__RotateRight(r, $ghost_e, 11, EDI, OConst(11)); call r, $result := proc_Asm__BitwiseXor(r, $result, $result2, EDX, OReg(EDI)); call r, $result2 := proc_Asm__RotateRight(r, $ghost_e, 25, EBX, OConst(25)); call r, $ghost_bsig1 := proc_Asm__BitwiseXor(r, $result, $result2, EDX, OReg(EBX)); forall::($ghost_bsig1 == (fun_BSIG1($ghost_e))) { call proc_reveal__BSIG1(); } //- Summary: assert ebp == $ghost_T2; assert ecx == fun_Ch($ghost_e, $ghost_f, $ghost_g); assert edx == fun_BSIG1($ghost_e); call ebx := Load(stk, esp + 32); //- grab h assert ebx == $ghost_h; call r, $result := proc_Asm__Add(r, $ghost_h, fun_BSIG1($ghost_e), EBX, OReg(EDX)); call r, $result := proc_Asm__Add(r, $result, fun_Ch($ghost_e, $ghost_f, $ghost_g), EBX, OReg(ECX)); call r, $result := proc_Asm__Add(r, $result, Eval(r,K), EBX, K); assert Eval(r,K) == fun_K__SHA256($ghost_currentStep); //- Load the value we want from W call r, mems := loadArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, EDX, Wopn, $ghost_currentStep, $ghost_W__abs, W_base); $ghost__temp__19 := r.regs[EDX]; call r, $ghost_T1 := proc_Asm__Add(r, $result, edx, EBX, OReg(EDX)); assert ebp == $ghost_T2; assert ebx == $ghost_T1; call r, $result := proc_Asm__Add(r, ebp, ebx, EBP, OReg(EBX)); //- a_next <- T2 + T1 assert ebp == fun_Asm__Add($ghost_T1, $ghost_T2); //call logical_Store(r, core_state, inout stk, OMem(MReg(ESP, 4)), OReg(EAX)); call eax := Load(stk, esp + 16); //- grab d assert eax == $ghost_d; call r, $result := proc_Asm__Add(r, eax, ebx, EAX, OReg(EBX)); //- e_next <- d + T1 assert eax == fun_Asm__Add((d#atoh_c($ghost_atoh)), $ghost_T1); call logical_Store(r, core_state, inout stk, OMem(MReg(ESP, 60)), OReg(EAX)); //- Ghost proofs of correctness // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt2.i.dfy: 68 $ghost_next_atoh := atoh_c(fun_Asm__Add($ghost_T1, $ghost_T2), (a#atoh_c($ghost_atoh)), (b#atoh_c($ghost_atoh)), (c#atoh_c($ghost_atoh)), fun_Asm__Add((d#atoh_c($ghost_atoh)), $ghost_T1), (e#atoh_c($ghost_atoh)), (f#atoh_c($ghost_atoh)), (g#atoh_c($ghost_atoh))); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt2.i.dfy: 69 $ghost_next_z := SHA256Trace_c((M#SHA256Trace_c($ghost_z)), (H#SHA256Trace_c($ghost_z)), (W#SHA256Trace_c($ghost_z)), fun_Seq__Append___Seq___atoh_Type(fun_Seq__Take___Seq___atoh_Type((atoh#SHA256Trace_c($ghost_z)), $ghost_currentBlock), fun_Seq__Build___Seq___atoh_Type(fun_Seq__Empty___Seq___atoh_Type(), fun_Seq__Append___atoh_Type(fun_Seq__Index___Seq___atoh_Type((atoh#SHA256Trace_c($ghost_z)), $ghost_currentBlock), fun_Seq__Build___atoh_Type(fun_Seq__Empty___atoh_Type(), $ghost_next_atoh))))); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt2.i.dfy: 70 $ghost_next_s := fun_SHA256__vars__to__state($absMem, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_next_atoh, $ghost_num_blocks); // assert fun_AreSHA256TraceAndStateOK($ghost_z, $ghost_s); // assert fun_Seq__Length___Seq___int((H#SHA256Trace_c($ghost_z))) == INTERNAL_add_boogie($ghost_currentBlock, 1); // assert fun_Seq__Length___Seq___int((W#SHA256Trace_c($ghost_z))) == INTERNAL_add_boogie($ghost_currentBlock, 1); // assert fun_Seq__Length___Seq___atoh_Type(atoh#SHA256Trace_c($ghost_z)) == INTERNAL_add_boogie($ghost_currentBlock, 1); // assert (forall $ghost__1_blk:int :: // (INTERNAL_le_boogie(0, $ghost__1_blk) && INTERNAL_lt_boogie($ghost__1_blk, $ghost_currentBlock)) ==> // (fun_IsAToHWordSeqOfLen(fun_Seq__Index___Seq___atoh_Type(atoh#SHA256Trace_c($ghost_z), $ghost__1_blk), 65))); // assert fun_IsAToHWordSeqOfLen(fun_Seq__Index___Seq___atoh_Type(atoh#SHA256Trace_c($ghost_z), $ghost_currentBlock), INTERNAL_add_boogie($ghost_currentStep, 1)); // assert fun_Seq__Equal___int(H#SHA256_state_c($ghost_s), fun_Seq__Index___Seq___int(H#SHA256Trace_c($ghost_z), $ghost_currentBlock)); // assert fun_Seq__Equal___int(W#SHA256_state_c($ghost_s), fun_Seq__Index___Seq___int(W#SHA256Trace_c($ghost_z), $ghost_currentBlock)); // assert atoh#SHA256_state_c($ghost_s) == fun_Seq__Index___atoh_Type(fun_Seq__Index___Seq___atoh_Type(atoh#SHA256Trace_c($ghost_z), $ghost_currentBlock), $ghost_currentStep); assert fun_IsSHA256ReadyForStep($ghost_z, $ghost_s, $ghost_currentBlock, $ghost_currentStep); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt2.i.dfy: 72 // call:: := proc_lemma__SHA256TransitionOKAfterSettingAtoH($ghost_z, $ghost_s, $ghost_next_z, $ghost_next_s, $ghost_currentBlock, $ghost_currentStep) // isGhost = True call proc_lemma__SHA256TransitionOKAfterSettingAtoH($ghost_z, $ghost_s, $ghost_next_z, $ghost_next_s, $ghost_currentBlock, $ghost_currentStep); //- Update ghost outputs $ghost_a_next := fun_Asm__Add($ghost_T1, $ghost_T2); $ghost_b_next := a#atoh_c($ghost_atoh); $ghost_c_next := b#atoh_c($ghost_atoh); $ghost_d_next := c#atoh_c($ghost_atoh); $ghost_e_next := fun_Asm__Add((d#atoh_c($ghost_atoh)), $ghost_T1); $ghost_f_next := e#atoh_c($ghost_atoh); $ghost_g_next := f#atoh_c($ghost_atoh); $ghost_h_next := g#atoh_c($ghost_atoh); //Return; } implementation Proc_ComputeSHA256__optimized__loop(my r_old:regs, const my core_state:core_state, linear stk_old:mem, linear statics_old:mem, linear io_old:IOState, linear mems_old:mems, $commonVars_old:commonVars, $gcVars_old:gcVars, $toAbs_old:[int]int, $absMem_old:[int][int]int, $stacksFrames_old:[int]Frames, objLayouts_old:[int]ObjLayout, heap_old:Heap, $ghost_M:ArrayOfInt, $ghost_words:int, $ghost_H:ArrayOfInt, $ghost_W:ArrayOfInt, $ghost_atoh:atoh_Type, $ghost_num_blocks:int, $ghost_a:int, $ghost_b:int, $ghost_c:int, $ghost_d:int, $ghost_e:int, $ghost_f:int, $ghost_g:int, $ghost_h:int, $ghost_z:SHA256Trace, $ghost_currentBlock:int) returns(my r:regs, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars, $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap, $ghost_a_final:int, $ghost_b_final:int, $ghost_c_final:int, $ghost_d_final:int, $ghost_e_final:int, $ghost_f_final:int, $ghost_g_final:int, $ghost_h_final:int, $ghost_final_atoh:atoh_Type, $ghost_final_z:SHA256Trace); { var $ghost_M__abs:int; var $ghost_H__abs:int; var $ghost_W__abs:int; var $ghost_local_a:int; var $ghost_local_b:int; var $ghost_local_c:int; var $ghost_local_d:int; var $ghost_local_e:int; var $ghost_local_f:int; var $ghost_local_g:int; var $ghost_local_h:int; var W_base:int; var $ghost_current_atoh:atoh_Type; var $ghost_current_z:SHA256Trace; //- Boilerplate variable propagation r := r_old; stk := stk_old; statics := statics_old; io := io_old; mems := mems_old; $commonVars := $commonVars_old; $gcVars := $gcVars_old; $toAbs := $toAbs_old; $absMem := $absMem_old; $stacksFrames := $stacksFrames_old; objLayouts := objLayouts_old; heap := heap_old; $ghost_M__abs := frameGet($stacksFrames, r_old.regs[ESP] + 4 + stackGcOffset); $ghost_H__abs := frameGet($stacksFrames, r_old.regs[ESP] + 8 + stackGcOffset); $ghost_W__abs := frameGet($stacksFrames, r_old.regs[ESP] + 12 + stackGcOffset); assert fun_unroll(0); assert fun_unroll(1); //- Functions we might want call lemma_fun_ensures_fun____HASH_K__SHA256__FULL(); call lemma_fun_ensures_fun_K__SHA256(); //- Alignment assert TV(r.regs[ESP]); assert TO(0 - 1); assert TO(279552 - 1); assert TO(0 - 2); assert TO(279552 - 2); assert TO(0); assert TO(279552); assert TO(1); assert TO(279553); assert TO(2); assert TO(279554); assert TO(3); assert TO(279555); assert TO(4); assert TO(279556); assert TO(5); assert TO(279557); assert TO(6); assert TO(279558); assert TO(7); assert TO(279559); assert TO(8); assert TO(279560); assert TO(9); assert TO(279561); assert TO(10); assert TO(279562); assert TO(11); assert TO(279563); assert TO(12); assert TO(279564); assert TO(13); assert TO(279565); assert TO(14); assert TO(279566); assert TO(15); assert TO(279567); assert TO(16); assert TO(279568); assert TO(17); assert TO(279569); assert TO(18); assert TO(279570); assert TO(19); assert TO(279571); assert TO(20); assert TO(279572); assert TO(21); //- Load the first a into ebp, where's compute expects it call ebp := Load(stk, esp + 44); //- grab a assert ebp == $ghost_a; //- Initialize local ghost variables $ghost_local_a:=$ghost_a; $ghost_local_b:=$ghost_b; $ghost_local_c:=$ghost_c; $ghost_local_d:=$ghost_d; $ghost_local_e:=$ghost_e; $ghost_local_f:=$ghost_f; $ghost_local_g:=$ghost_g; $ghost_local_h:=$ghost_h; $ghost_current_atoh := $ghost_atoh; $ghost_current_z := $ghost_z; //- Load W base into ESI call r, mems := heapLoadStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, ESI, OMem(MReg(ESP, 0x11100C)), EvalPtr(r, OMem(MReg(ESP, 0x11100C)))); W_base := esi; call arrayElementProperties(core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, 0, $ghost_W__abs, esi); //- Proves we're within bounds for the addition below esi := esi + 8; //- Skip past the header to reach the data we care about //assert OMem(MReg(ESI,0)) == esi + 4 * (2 + 0); call proc_reveal__K__SHA256(); assert 0x428a2f98 == fun_K__SHA256(0); assert 0x71374491 == fun_K__SHA256(1); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_A(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 0, OConst(0x428a2f98), OMem(MReg(ESI,0)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_B(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 1, OConst(0x71374491), OMem(MReg(ESI,4)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_A(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 2, OConst(0xb5c0fbcf), OMem(MReg(ESI,8)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_B(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 3, OConst(0xe9b5dba5), OMem(MReg(ESI,12)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_A(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 4, OConst(0x3956c25b), OMem(MReg(ESI,16)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_B(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 5, OConst(0x59f111f1), OMem(MReg(ESI,20)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_A(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 6, OConst(0x923f82a4), OMem(MReg(ESI,24)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_B(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 7, OConst(0xab1c5ed5), OMem(MReg(ESI,28)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_A(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 8, OConst(0xd807aa98), OMem(MReg(ESI,32)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_B(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 9, OConst(0x12835b01), OMem(MReg(ESI,36)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_A(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 10, OConst(0x243185be), OMem(MReg(ESI,40)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_B(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 11, OConst(0x550c7dc3), OMem(MReg(ESI,44)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_A(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 12, OConst(0x72be5d74), OMem(MReg(ESI,48)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_B(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 13, OConst(0x80deb1fe), OMem(MReg(ESI,52)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_A(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 14, OConst(0x9bdc06a7), OMem(MReg(ESI,56)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_B(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 15, OConst(0xc19bf174), OMem(MReg(ESI,60)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_A(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 16, OConst(0xe49b69c1), OMem(MReg(ESI,64)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_B(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 17, OConst(0xefbe4786), OMem(MReg(ESI,68)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_A(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 18, OConst(0x0fc19dc6), OMem(MReg(ESI,72)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_B(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 19, OConst(0x240ca1cc), OMem(MReg(ESI,76)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_A(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 20, OConst(0x2de92c6f), OMem(MReg(ESI,80)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_B(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 21, OConst(0x4a7484aa), OMem(MReg(ESI,84)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_A(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 22, OConst(0x5cb0a9dc), OMem(MReg(ESI,88)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_B(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 23, OConst(0x76f988da), OMem(MReg(ESI,92)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_A(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 24, OConst(0x983e5152), OMem(MReg(ESI,96)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_B(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 25, OConst(0xa831c66d), OMem(MReg(ESI,100)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_A(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 26, OConst(0xb00327c8), OMem(MReg(ESI,104)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_B(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 27, OConst(0xbf597fc7), OMem(MReg(ESI,108)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_A(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 28, OConst(0xc6e00bf3), OMem(MReg(ESI,112)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_B(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 29, OConst(0xd5a79147), OMem(MReg(ESI,116)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_A(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 30, OConst(0x06ca6351), OMem(MReg(ESI,120)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_B(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 31, OConst(0x14292967), OMem(MReg(ESI,124)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_A(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 32, OConst(0x27b70a85), OMem(MReg(ESI,128)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_B(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 33, OConst(0x2e1b2138), OMem(MReg(ESI,132)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_A(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 34, OConst(0x4d2c6dfc), OMem(MReg(ESI,136)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_B(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 35, OConst(0x53380d13), OMem(MReg(ESI,140)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_A(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 36, OConst(0x650a7354), OMem(MReg(ESI,144)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_B(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 37, OConst(0x766a0abb), OMem(MReg(ESI,148)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_A(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 38, OConst(0x81c2c92e), OMem(MReg(ESI,152)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_B(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 39, OConst(0x92722c85), OMem(MReg(ESI,156)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_A(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 40, OConst(0xa2bfe8a1), OMem(MReg(ESI,160)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_B(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 41, OConst(0xa81a664b), OMem(MReg(ESI,164)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_A(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 42, OConst(0xc24b8b70), OMem(MReg(ESI,168)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_B(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 43, OConst(0xc76c51a3), OMem(MReg(ESI,172)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_A(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 44, OConst(0xd192e819), OMem(MReg(ESI,176)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_B(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 45, OConst(0xd6990624), OMem(MReg(ESI,180)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_A(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 46, OConst(0xf40e3585), OMem(MReg(ESI,184)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_B(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 47, OConst(0x106aa070), OMem(MReg(ESI,188)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_A(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 48, OConst(0x19a4c116), OMem(MReg(ESI,192)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_B(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 49, OConst(0x1e376c08), OMem(MReg(ESI,196)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_A(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 50, OConst(0x2748774c), OMem(MReg(ESI,200)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_B(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 51, OConst(0x34b0bcb5), OMem(MReg(ESI,204)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_A(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 52, OConst(0x391c0cb3), OMem(MReg(ESI,208)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_B(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 53, OConst(0x4ed8aa4a), OMem(MReg(ESI,212)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_A(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 54, OConst(0x5b9cca4f), OMem(MReg(ESI,216)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_B(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 55, OConst(0x682e6ff3), OMem(MReg(ESI,220)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_A(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 56, OConst(0x748f82ee), OMem(MReg(ESI,224)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_B(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 57, OConst(0x78a5636f), OMem(MReg(ESI,228)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_A(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 58, OConst(0x84c87814), OMem(MReg(ESI,232)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_B(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 59, OConst(0x8cc70208), OMem(MReg(ESI,236)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_A(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 60, OConst(0x90befffa), OMem(MReg(ESI,240)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_B(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 61, OConst(0xa4506ceb), OMem(MReg(ESI,244)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_A(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 62, OConst(0xbef9a3f7), OMem(MReg(ESI,248)), W_base, $ghost_W__abs); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_atoh, $ghost_current_z := proc_ComputeOneStep__SHA256__optimized_B(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_current_atoh, $ghost_num_blocks, $ghost_local_a, $ghost_local_b, $ghost_local_c, $ghost_local_d, $ghost_local_e, $ghost_local_f, $ghost_local_g, $ghost_local_h, $ghost_current_z, $ghost_currentBlock, 63, OConst(0xc67178f2), OMem(MReg(ESI,252)), W_base, $ghost_W__abs); //- Move the returned arguments to the right location on the stack call logical_Store(r, core_state, inout stk, OMem(MReg(ESP, 4)), OReg(EBP)); //- a_final call ebx := Load(stk, esp + 48); //- grab b assert ebx == $ghost_local_b; call logical_Store(r, core_state, inout stk, OMem(MReg(ESP, 8)), OReg(EBX)); //- b_final call ebx := Load(stk, esp + 52); //- grab c assert ebx == $ghost_local_c; call logical_Store(r, core_state, inout stk, OMem(MReg(ESP, 12)), OReg(EBX)); //- c_final call ebx := Load(stk, esp + 56); //- grab d assert ebx == $ghost_local_d; call logical_Store(r, core_state, inout stk, OMem(MReg(ESP, 16)), OReg(EBX)); //- d_final call ebx := Load(stk, esp + 60); //- grab e assert ebx == $ghost_local_e; call logical_Store(r, core_state, inout stk, OMem(MReg(ESP, 20)), OReg(EBX)); //- e_final call ebx := Load(stk, esp + 64); //- grab f assert ebx == $ghost_local_f; call logical_Store(r, core_state, inout stk, OMem(MReg(ESP, 24)), OReg(EBX)); //- f_final call ebx := Load(stk, esp + 68); //- grab g assert ebx == $ghost_local_g; call logical_Store(r, core_state, inout stk, OMem(MReg(ESP, 28)), OReg(EBX)); //- g_final call ebx := Load(stk, esp + 72); //- grab h assert ebx == $ghost_local_h; call logical_Store(r, core_state, inout stk, OMem(MReg(ESP, 32)), OReg(EBX)); //- h_final // // From: // ensures $ghost_a_next == r.regs[EBP]; // ensures (($ghost_b_next) == (stk.map[r_old.regs[ESP] + 48])); // ensures (($ghost_c_next) == (stk.map[r_old.regs[ESP] + 52])); // ensures (($ghost_d_next) == (stk.map[r_old.regs[ESP] + 56])); // ensures (($ghost_e_next) == (stk.map[r_old.regs[ESP] + 60])); // ensures (($ghost_f_next) == (stk.map[r_old.regs[ESP] + 64])); // ensures (($ghost_g_next) == (stk.map[r_old.regs[ESP] + 68])); // ensures (($ghost_h_next) == (stk.map[r_old.regs[ESP] + 72])); // // // To: // ensures (($ghost_a_final) == (stk.map[r_old.regs[ESP] + 4])); // ensures (($ghost_b_final) == (stk.map[r_old.regs[ESP] + 8])); // ensures (($ghost_c_final) == (stk.map[r_old.regs[ESP] + 12])); // ensures (($ghost_d_final) == (stk.map[r_old.regs[ESP] + 16])); // ensures (($ghost_e_final) == (stk.map[r_old.regs[ESP] + 20])); // ensures (($ghost_f_final) == (stk.map[r_old.regs[ESP] + 24])); // ensures (($ghost_g_final) == (stk.map[r_old.regs[ESP] + 28])); // ensures (($ghost_h_final) == (stk.map[r_old.regs[ESP] + 32])); $ghost_a_final := $ghost_local_a; $ghost_b_final := $ghost_local_b; $ghost_c_final := $ghost_local_c; $ghost_d_final := $ghost_local_d; $ghost_e_final := $ghost_local_e; $ghost_f_final := $ghost_local_f; $ghost_g_final := $ghost_local_g; $ghost_h_final := $ghost_local_h; $ghost_final_atoh := $ghost_current_atoh; $ghost_final_z := $ghost_current_z; Return; } implementation Proc_ComputeWsForBlockStep1__SHA256__optimized(my r_old:regs, const my core_state:core_state, linear stk_old:mem, linear statics_old:mem, linear io_old:IOState, linear mems_old:mems, $commonVars_old:commonVars, $gcVars_old:gcVars, $toAbs_old:[int]int, $absMem_old:[int][int]int, $stacksFrames_old:[int]Frames, objLayouts_old:[int]ObjLayout, heap_old:Heap, $ghost_M:ArrayOfInt, $ghost_words:int, $ghost_H:ArrayOfInt, $ghost_W:ArrayOfInt, $ghost_atoh:atoh_Type, $ghost_num_blocks:int, $ghost_z:SHA256Trace, $ghost_currentBlock:int) returns(my r:regs, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars, $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap) { // Lots of boilerplate var $absMem_tmp:[int][int]int; var objLayouts_tmp:[int]ObjLayout; var heap_tmp:Heap; var obj_tmp:int; var val_tmp:int; var mod0:int; var $ghost_s:SHA256_state; var $ghost_t:int; var $ghost_m_index:int; var $ghost__temp__0:int; var $ghost__temp__1:int; var $ghost__temp__5:int; var $ghost_M__abs:int; var $ghost_H__abs:int; var $ghost_W__abs:int; var W_base:int; var M_base:int; assert fun_unroll(0); assert fun_unroll(1); call lemma_unroll_rec_fun____HASH_Seq__Length__FULL___int(); call lemma_unroll_fun____HASH_Seq__Length__FULL___int(); call lemma_fun_ensures_fun_Seq__Length___int(); call lemma_unroll_rec_fun____HASH_Seq__Build__FULL___int(); call lemma_unroll_fun____HASH_Seq__Build__FULL___int(); call lemma_unroll_rec_fun____HASH_Seq__Index__FULL___int(); call lemma_unroll_fun____HASH_Seq__Index__FULL___int(); call lemma_unroll_rec_fun____HASH_Seq__Append__FULL___int(); call lemma_unroll_fun____HASH_Seq__Append__FULL___int(); call lemma_unroll_rec_fun____HASH_Seq__Update__FULL___int(); call lemma_unroll_fun____HASH_Seq__Update__FULL___int(); call lemma_unroll_rec_fun____HASH_Seq__Take__FULL___int(); call lemma_unroll_fun____HASH_Seq__Take__FULL___int(); call lemma_unroll_rec_fun____HASH_Seq__Drop__FULL___int(); call lemma_unroll_fun____HASH_Seq__Drop__FULL___int(); call proc_Seq__Empty__ToZero___int(); call proc_Seq__Empty__FromZero___int(); call proc_Seq__Singleton__Length___int(); call proc_Seq__Build__Length___int(); call proc_Seq__Build__Index___int(); call proc_Seq__Append__Length___int(); call proc_Seq__Index__Singleton___int(); call proc_Seq__Append__Index___int(); call proc_Seq__Update__Length___int(); call proc_Seq__Index__Update___int(); call proc_Seq__Equal__Equiv___int(); call proc_Seq__Take__Length___int(); call proc_Seq__Take__Index___int(); call proc_Seq__Drop__Length___int(); call proc_Seq__Drop__Index___int(); call proc_Seq__Append__TakeDrop___int(); call proc_Seq__Update__CommuteTake1___int(); call proc_Seq__Update__CommuteTake2___int(); call proc_Seq__Update__CommuteDrop1___int(); call proc_Seq__Update__CommuteDrop2___int(); call proc_Seq__Build__CommuteDrop___int(); call proc_Seq__Take__Empty___int(); call proc_Seq__Drop__Empty___int(); call lemma_unroll_fun_Seq__FromArrayRange(); call proc_Seq__FromArray__Length(); call proc_Seq__FromArray__Index(); call proc_Seq__FromArray__Update(); call lemma_unroll_rec_fun____HASH_power2__FULL(); call lemma_unroll_fun____HASH_power2__FULL(); call lemma_fun_ensures_fun_power2(); call lemma_unroll_rec_fun____HASH_BEDigitSeqToInt__private__FULL(); call lemma_unroll_fun____HASH_BEDigitSeqToInt__private__FULL(); call lemma_unroll_rec_fun____HASH_BEIntToDigitSeq__private__FULL(); call lemma_unroll_fun____HASH_BEIntToDigitSeq__private__FULL(); call lemma_unroll_rec_fun_RepeatDigit(); call lemma_unroll_fun_RepeatDigit(); call lemma_unroll_rec_fun____HASH_Reverse__FULL(); call lemma_unroll_fun____HASH_Reverse__FULL(); call lemma_unroll_rec_fun____HASH_power__FULL(); call lemma_unroll_fun____HASH_power__FULL(); call lemma_unroll_rec_fun_mul__pos(); call lemma_unroll_fun_mul__pos(); call lemma_unroll_rec_fun____HASH_Seq__Length__FULL___bool(); call lemma_unroll_fun____HASH_Seq__Length__FULL___bool(); call lemma_fun_ensures_fun_Seq__Length___bool(); call lemma_unroll_rec_fun____HASH_Seq__Build__FULL___bool(); call lemma_unroll_fun____HASH_Seq__Build__FULL___bool(); call lemma_unroll_rec_fun____HASH_Seq__Index__FULL___bool(); call lemma_unroll_fun____HASH_Seq__Index__FULL___bool(); call lemma_unroll_rec_fun____HASH_Seq__Append__FULL___bool(); call lemma_unroll_fun____HASH_Seq__Append__FULL___bool(); call lemma_unroll_rec_fun____HASH_Seq__Update__FULL___bool(); call lemma_unroll_fun____HASH_Seq__Update__FULL___bool(); call lemma_unroll_rec_fun____HASH_Seq__Take__FULL___bool(); call lemma_unroll_fun____HASH_Seq__Take__FULL___bool(); call lemma_unroll_rec_fun____HASH_Seq__Drop__FULL___bool(); call lemma_unroll_fun____HASH_Seq__Drop__FULL___bool(); call proc_Seq__Empty__ToZero___bool(); call proc_Seq__Empty__FromZero___bool(); call proc_Seq__Singleton__Length___bool(); call proc_Seq__Build__Length___bool(); call proc_Seq__Build__Index___bool(); call proc_Seq__Append__Length___bool(); call proc_Seq__Index__Singleton___bool(); call proc_Seq__Append__Index___bool(); call proc_Seq__Update__Length___bool(); call proc_Seq__Index__Update___bool(); call proc_Seq__Equal__Equiv___bool(); call proc_Seq__Take__Length___bool(); call proc_Seq__Take__Index___bool(); call proc_Seq__Drop__Length___bool(); call proc_Seq__Drop__Index___bool(); call proc_Seq__Append__TakeDrop___bool(); call proc_Seq__Update__CommuteTake1___bool(); call proc_Seq__Update__CommuteTake2___bool(); call proc_Seq__Update__CommuteDrop1___bool(); call proc_Seq__Update__CommuteDrop2___bool(); call proc_Seq__Build__CommuteDrop___bool(); call proc_Seq__Take__Empty___bool(); call proc_Seq__Drop__Empty___bool(); call lemma_unroll_rec_fun_my__div__pos(); call lemma_unroll_fun_my__div__pos(); call lemma_unroll_rec_fun_my__mod__recursive(); call lemma_unroll_fun_my__mod__recursive(); call lemma_fun_ensures_fun_RepeatDigit__premium(); call lemma_unroll_rec_fun____HASH_SequenceOfZeros__FULL(); call lemma_unroll_fun____HASH_SequenceOfZeros__FULL(); call lemma_fun_ensures_fun_SequenceOfZeros(); call lemma_fun_ensures_fun_BitwiseAnd(); call lemma_fun_ensures_fun_BitwiseOr(); call lemma_fun_ensures_fun_BitwiseNot(); call lemma_fun_ensures_fun_BitwiseXor(); call lemma_fun_ensures_fun_RotateRight(); call lemma_fun_ensures_fun_RotateLeft(); call lemma_fun_ensures_fun_RightShift(); call lemma_fun_ensures_fun_LeftShift(); call lemma_fun_ensures_fun_Add32(); call lemma_fun_ensures_fun_Sub32(); call lemma_fun_ensures_fun_Mul32(); call lemma_fun_ensures_fun_Div32(); call lemma_fun_ensures_fun_Mod32(); call lemma_unroll_rec_fun____HASH_NatNumBits__FULL(); call lemma_unroll_fun____HASH_NatNumBits__FULL(); call lemma_fun_ensures_fun_NatNumBits(); call lemma_fun_ensures_fun_asm__Add(); call lemma_fun_ensures_fun_asm__Sub(); call lemma_fun_ensures_fun_asm__Mul(); call lemma_fun_ensures_fun_asm__Div(); call lemma_fun_ensures_fun_asm__Mod(); call lemma_fun_ensures_fun_asm__LeftShift(); call lemma_fun_ensures_fun_asm__RightShift(); call lemma_fun_ensures_fun_asm__RotateLeft(); call lemma_fun_ensures_fun_asm__RotateRight(); call lemma_fun_ensures_fun_asm__BitwiseNot(); call lemma_fun_ensures_fun_asm__BitwiseAnd(); call lemma_fun_ensures_fun_asm__BitwiseOr(); call lemma_fun_ensures_fun_asm__BitwiseXor(); call lemma_unroll_rec_fun____HASH_LEDigitSeqToInt__private__FULL(); call lemma_unroll_fun____HASH_LEDigitSeqToInt__private__FULL(); call lemma_fun_ensures_fun_BEDigitSeqToInt__premium(); call lemma_fun_ensures_fun_BEWordSeqToInt__premium(); call lemma_fun_ensures_fun_BEIntToDigitSeq__premium(); call lemma_fun_ensures_fun_BEIntToByteSeq__premium(); call lemma_fun_ensures_fun_BEWordToFourBytes__premium(); call lemma_fun_ensures_fun_BEWordToBitSeq__premium(); call lemma_fun_ensures_fun_BEWordSeqToBitSeq__premium(); call lemma_fun_ensures_fun_BEByteSeqToBitSeq__premium(); call lemma_fun_ensures_fun_BEWordSeqToByteSeq__premium(); call lemma_fun_ensures_fun_Asm__Add(); call lemma_fun_ensures_fun_Asm__Sub(); call lemma_fun_ensures_fun_Asm__Mul(); call lemma_fun_ensures_fun_Asm__Div(); call lemma_fun_ensures_fun_Asm__Mod(); call lemma_fun_ensures_fun_Asm__LeftShift(); call lemma_fun_ensures_fun_Asm__RightShift(); call lemma_fun_ensures_fun_Asm__RotateLeft(); call lemma_fun_ensures_fun_Asm__RotateRight(); call lemma_fun_ensures_fun_Asm__BitwiseNot(); call lemma_fun_ensures_fun_Asm__BitwiseAnd(); call lemma_fun_ensures_fun_Asm__BitwiseOr(); call lemma_fun_ensures_fun_Asm__BitwiseXor(); call lemma_fun_ensures_fun_ComputePower2(); call lemma_fun_ensures_fun_ComputePower2Minus1__mostly(); call lemma_fun_ensures_fun_ComputePower2Minus1(); call lemma_fun_ensures_fun_GetWordBit(); call lemma_unroll_rec_fun____HASH_Seq__Length__FULL___Seq___int(); call lemma_unroll_fun____HASH_Seq__Length__FULL___Seq___int(); call lemma_fun_ensures_fun_Seq__Length___Seq___int(); call lemma_unroll_rec_fun____HASH_Seq__Build__FULL___Seq___int(); call lemma_unroll_fun____HASH_Seq__Build__FULL___Seq___int(); call lemma_unroll_rec_fun____HASH_Seq__Index__FULL___Seq___int(); call lemma_unroll_fun____HASH_Seq__Index__FULL___Seq___int(); call lemma_unroll_rec_fun____HASH_Seq__Append__FULL___Seq___int(); call lemma_unroll_fun____HASH_Seq__Append__FULL___Seq___int(); call lemma_unroll_rec_fun____HASH_Seq__Update__FULL___Seq___int(); call lemma_unroll_fun____HASH_Seq__Update__FULL___Seq___int(); call lemma_unroll_rec_fun____HASH_Seq__Take__FULL___Seq___int(); call lemma_unroll_fun____HASH_Seq__Take__FULL___Seq___int(); call lemma_unroll_rec_fun____HASH_Seq__Drop__FULL___Seq___int(); call lemma_unroll_fun____HASH_Seq__Drop__FULL___Seq___int(); call proc_Seq__Empty__ToZero___Seq___int(); call proc_Seq__Empty__FromZero___Seq___int(); call proc_Seq__Singleton__Length___Seq___int(); call proc_Seq__Build__Length___Seq___int(); call proc_Seq__Build__Index___Seq___int(); call proc_Seq__Append__Length___Seq___int(); call proc_Seq__Index__Singleton___Seq___int(); call proc_Seq__Append__Index___Seq___int(); call proc_Seq__Update__Length___Seq___int(); call proc_Seq__Index__Update___Seq___int(); call proc_Seq__Equal__Equiv___Seq___int(); call proc_Seq__Take__Length___Seq___int(); call proc_Seq__Take__Index___Seq___int(); call proc_Seq__Drop__Length___Seq___int(); call proc_Seq__Drop__Index___Seq___int(); call proc_Seq__Append__TakeDrop___Seq___int(); call proc_Seq__Update__CommuteTake1___Seq___int(); call proc_Seq__Update__CommuteTake2___Seq___int(); call proc_Seq__Update__CommuteDrop1___Seq___int(); call proc_Seq__Update__CommuteDrop2___Seq___int(); call proc_Seq__Build__CommuteDrop___Seq___int(); call proc_Seq__Take__Empty___Seq___int(); call proc_Seq__Drop__Empty___Seq___int(); call lemma_unroll_rec_fun____HASH_BreakIntoBlocks__FULL(); call lemma_unroll_fun____HASH_BreakIntoBlocks__FULL(); call lemma_fun_ensures_fun____HASH_Ch__FULL(); call lemma_fun_ensures_fun_Ch(); call lemma_fun_ensures_fun____HASH_Maj__FULL(); call lemma_fun_ensures_fun_Maj(); call lemma_fun_ensures_fun____HASH_Parity__FULL(); call lemma_fun_ensures_fun_Parity(); call lemma_fun_ensures_fun____HASH_ft__FULL(); call lemma_fun_ensures_fun_ft(); call lemma_fun_ensures_fun____HASH_BSIG0__FULL(); call lemma_fun_ensures_fun_BSIG0(); call lemma_fun_ensures_fun____HASH_BSIG1__FULL(); call lemma_fun_ensures_fun_BSIG1(); call lemma_fun_ensures_fun____HASH_SSIG0__FULL(); call lemma_fun_ensures_fun_SSIG0(); call lemma_fun_ensures_fun____HASH_SSIG1__FULL(); call lemma_fun_ensures_fun_SSIG1(); call lemma_fun_ensures_fun____HASH_NumPaddingZeroes__FULL(); call lemma_fun_ensures_fun_NumPaddingZeroes(); call lemma_unroll_rec_fun____HASH_SeqXor__FULL(); call lemma_unroll_fun____HASH_SeqXor__FULL(); call lemma_unroll_rec_fun____HASH_ConstPad__FULL(); call lemma_unroll_fun____HASH_ConstPad__FULL(); call lemma_unroll_rec_fun____HASH_Seq__Length__FULL___atoe_Type(); call lemma_unroll_fun____HASH_Seq__Length__FULL___atoe_Type(); call lemma_fun_ensures_fun_Seq__Length___atoe_Type(); call lemma_unroll_rec_fun____HASH_Seq__Build__FULL___atoe_Type(); call lemma_unroll_fun____HASH_Seq__Build__FULL___atoe_Type(); call lemma_unroll_rec_fun____HASH_Seq__Index__FULL___atoe_Type(); call lemma_unroll_fun____HASH_Seq__Index__FULL___atoe_Type(); call lemma_unroll_rec_fun____HASH_Seq__Append__FULL___atoe_Type(); call lemma_unroll_fun____HASH_Seq__Append__FULL___atoe_Type(); call lemma_unroll_rec_fun____HASH_Seq__Update__FULL___atoe_Type(); call lemma_unroll_fun____HASH_Seq__Update__FULL___atoe_Type(); call lemma_unroll_rec_fun____HASH_Seq__Take__FULL___atoe_Type(); call lemma_unroll_fun____HASH_Seq__Take__FULL___atoe_Type(); call lemma_unroll_rec_fun____HASH_Seq__Drop__FULL___atoe_Type(); call lemma_unroll_fun____HASH_Seq__Drop__FULL___atoe_Type(); call proc_Seq__Empty__ToZero___atoe_Type(); call proc_Seq__Empty__FromZero___atoe_Type(); call proc_Seq__Singleton__Length___atoe_Type(); call proc_Seq__Build__Length___atoe_Type(); call proc_Seq__Build__Index___atoe_Type(); call proc_Seq__Append__Length___atoe_Type(); call proc_Seq__Index__Singleton___atoe_Type(); call proc_Seq__Append__Index___atoe_Type(); call proc_Seq__Update__Length___atoe_Type(); call proc_Seq__Index__Update___atoe_Type(); call proc_Seq__Equal__Equiv___atoe_Type(); call proc_Seq__Take__Length___atoe_Type(); call proc_Seq__Take__Index___atoe_Type(); call proc_Seq__Drop__Length___atoe_Type(); call proc_Seq__Drop__Index___atoe_Type(); call proc_Seq__Append__TakeDrop___atoe_Type(); call proc_Seq__Update__CommuteTake1___atoe_Type(); call proc_Seq__Update__CommuteTake2___atoe_Type(); call proc_Seq__Update__CommuteDrop1___atoe_Type(); call proc_Seq__Update__CommuteDrop2___atoe_Type(); call proc_Seq__Build__CommuteDrop___atoe_Type(); call proc_Seq__Take__Empty___atoe_Type(); call proc_Seq__Drop__Empty___atoe_Type(); call lemma_unroll_rec_fun____HASH_Seq__Length__FULL___Seq___atoe_Type(); call lemma_unroll_fun____HASH_Seq__Length__FULL___Seq___atoe_Type(); call lemma_fun_ensures_fun_Seq__Length___Seq___atoe_Type(); call lemma_unroll_rec_fun____HASH_Seq__Build__FULL___Seq___atoe_Type(); call lemma_unroll_fun____HASH_Seq__Build__FULL___Seq___atoe_Type(); call lemma_unroll_rec_fun____HASH_Seq__Index__FULL___Seq___atoe_Type(); call lemma_unroll_fun____HASH_Seq__Index__FULL___Seq___atoe_Type(); call lemma_unroll_rec_fun____HASH_Seq__Append__FULL___Seq___atoe_Type(); call lemma_unroll_fun____HASH_Seq__Append__FULL___Seq___atoe_Type(); call lemma_unroll_rec_fun____HASH_Seq__Update__FULL___Seq___atoe_Type(); call lemma_unroll_fun____HASH_Seq__Update__FULL___Seq___atoe_Type(); call lemma_unroll_rec_fun____HASH_Seq__Take__FULL___Seq___atoe_Type(); call lemma_unroll_fun____HASH_Seq__Take__FULL___Seq___atoe_Type(); call lemma_unroll_rec_fun____HASH_Seq__Drop__FULL___Seq___atoe_Type(); call lemma_unroll_fun____HASH_Seq__Drop__FULL___Seq___atoe_Type(); call proc_Seq__Empty__ToZero___Seq___atoe_Type(); call proc_Seq__Empty__FromZero___Seq___atoe_Type(); call proc_Seq__Singleton__Length___Seq___atoe_Type(); call proc_Seq__Build__Length___Seq___atoe_Type(); call proc_Seq__Build__Index___Seq___atoe_Type(); call proc_Seq__Append__Length___Seq___atoe_Type(); call proc_Seq__Index__Singleton___Seq___atoe_Type(); call proc_Seq__Append__Index___Seq___atoe_Type(); call proc_Seq__Update__Length___Seq___atoe_Type(); call proc_Seq__Index__Update___Seq___atoe_Type(); call proc_Seq__Equal__Equiv___Seq___atoe_Type(); call proc_Seq__Take__Length___Seq___atoe_Type(); call proc_Seq__Take__Index___Seq___atoe_Type(); call proc_Seq__Drop__Length___Seq___atoe_Type(); call proc_Seq__Drop__Index___Seq___atoe_Type(); call proc_Seq__Append__TakeDrop___Seq___atoe_Type(); call proc_Seq__Update__CommuteTake1___Seq___atoe_Type(); call proc_Seq__Update__CommuteTake2___Seq___atoe_Type(); call proc_Seq__Update__CommuteDrop1___Seq___atoe_Type(); call proc_Seq__Update__CommuteDrop2___Seq___atoe_Type(); call proc_Seq__Build__CommuteDrop___Seq___atoe_Type(); call proc_Seq__Take__Empty___Seq___atoe_Type(); call proc_Seq__Drop__Empty___Seq___atoe_Type(); call lemma_fun_ensures_fun____HASH_GetArrayBit__FULL(); call lemma_fun_ensures_fun_GetArrayBit(); call lemma_fun_ensures_fun_DivideRoundingUp__premium(); call lemma_fun_ensures_fun_RoundUpToMultiple__premium(); call lemma_fun_ensures_fun_PadSequenceToMultiple__premium(); call lemma_fun_ensures_fun_PadAndBreakIntoBlocks__premium(); call lemma_fun_ensures_fun_Ch__impl(); call lemma_fun_ensures_fun_Maj__impl(); call lemma_fun_ensures_fun_Parity__impl(); call lemma_fun_ensures_fun_ft__impl(); call lemma_fun_ensures_fun_BSIG0__impl(); call lemma_fun_ensures_fun_BSIG1__impl(); call lemma_fun_ensures_fun_SSIG0__impl(); call lemma_fun_ensures_fun_SSIG1__impl(); call lemma_fun_ensures_fun_PadMessageForSHA__premium(); call lemma_fun_ensures_fun____HASH_GetArrayBitOpaque__FULL(); call lemma_fun_ensures_fun_GetArrayBitOpaque(); call lemma_fun_ensures_fun____HASH_K__SHA256__FULL(); call lemma_fun_ensures_fun_K__SHA256(); call lemma_fun_ensures_fun____HASH_InitialH__SHA256__FULL(); call lemma_fun_ensures_fun_InitialH__SHA256(); call lemma_unroll_rec_fun____HASH_Seq__Length__FULL___atoh_Type(); call lemma_unroll_fun____HASH_Seq__Length__FULL___atoh_Type(); call lemma_fun_ensures_fun_Seq__Length___atoh_Type(); call lemma_unroll_rec_fun____HASH_Seq__Build__FULL___atoh_Type(); call lemma_unroll_fun____HASH_Seq__Build__FULL___atoh_Type(); call lemma_unroll_rec_fun____HASH_Seq__Index__FULL___atoh_Type(); call lemma_unroll_fun____HASH_Seq__Index__FULL___atoh_Type(); call lemma_unroll_rec_fun____HASH_Seq__Append__FULL___atoh_Type(); call lemma_unroll_fun____HASH_Seq__Append__FULL___atoh_Type(); call lemma_unroll_rec_fun____HASH_Seq__Update__FULL___atoh_Type(); call lemma_unroll_fun____HASH_Seq__Update__FULL___atoh_Type(); call lemma_unroll_rec_fun____HASH_Seq__Take__FULL___atoh_Type(); call lemma_unroll_fun____HASH_Seq__Take__FULL___atoh_Type(); call lemma_unroll_rec_fun____HASH_Seq__Drop__FULL___atoh_Type(); call lemma_unroll_fun____HASH_Seq__Drop__FULL___atoh_Type(); call proc_Seq__Empty__ToZero___atoh_Type(); call proc_Seq__Empty__FromZero___atoh_Type(); call proc_Seq__Singleton__Length___atoh_Type(); call proc_Seq__Build__Length___atoh_Type(); call proc_Seq__Build__Index___atoh_Type(); call proc_Seq__Append__Length___atoh_Type(); call proc_Seq__Index__Singleton___atoh_Type(); call proc_Seq__Append__Index___atoh_Type(); call proc_Seq__Update__Length___atoh_Type(); call proc_Seq__Index__Update___atoh_Type(); call proc_Seq__Equal__Equiv___atoh_Type(); call proc_Seq__Take__Length___atoh_Type(); call proc_Seq__Take__Index___atoh_Type(); call proc_Seq__Drop__Length___atoh_Type(); call proc_Seq__Drop__Index___atoh_Type(); call proc_Seq__Append__TakeDrop___atoh_Type(); call proc_Seq__Update__CommuteTake1___atoh_Type(); call proc_Seq__Update__CommuteTake2___atoh_Type(); call proc_Seq__Update__CommuteDrop1___atoh_Type(); call proc_Seq__Update__CommuteDrop2___atoh_Type(); call proc_Seq__Build__CommuteDrop___atoh_Type(); call proc_Seq__Take__Empty___atoh_Type(); call proc_Seq__Drop__Empty___atoh_Type(); call lemma_unroll_rec_fun____HASH_Seq__Length__FULL___Seq___atoh_Type(); call lemma_unroll_fun____HASH_Seq__Length__FULL___Seq___atoh_Type(); call lemma_fun_ensures_fun_Seq__Length___Seq___atoh_Type(); call lemma_unroll_rec_fun____HASH_Seq__Build__FULL___Seq___atoh_Type(); call lemma_unroll_fun____HASH_Seq__Build__FULL___Seq___atoh_Type(); call lemma_unroll_rec_fun____HASH_Seq__Index__FULL___Seq___atoh_Type(); call lemma_unroll_fun____HASH_Seq__Index__FULL___Seq___atoh_Type(); call lemma_unroll_rec_fun____HASH_Seq__Append__FULL___Seq___atoh_Type(); call lemma_unroll_fun____HASH_Seq__Append__FULL___Seq___atoh_Type(); call lemma_unroll_rec_fun____HASH_Seq__Update__FULL___Seq___atoh_Type(); call lemma_unroll_fun____HASH_Seq__Update__FULL___Seq___atoh_Type(); call lemma_unroll_rec_fun____HASH_Seq__Take__FULL___Seq___atoh_Type(); call lemma_unroll_fun____HASH_Seq__Take__FULL___Seq___atoh_Type(); call lemma_unroll_rec_fun____HASH_Seq__Drop__FULL___Seq___atoh_Type(); call lemma_unroll_fun____HASH_Seq__Drop__FULL___Seq___atoh_Type(); call proc_Seq__Empty__ToZero___Seq___atoh_Type(); call proc_Seq__Empty__FromZero___Seq___atoh_Type(); call proc_Seq__Singleton__Length___Seq___atoh_Type(); call proc_Seq__Build__Length___Seq___atoh_Type(); call proc_Seq__Build__Index___Seq___atoh_Type(); call proc_Seq__Append__Length___Seq___atoh_Type(); call proc_Seq__Index__Singleton___Seq___atoh_Type(); call proc_Seq__Append__Index___Seq___atoh_Type(); call proc_Seq__Update__Length___Seq___atoh_Type(); call proc_Seq__Index__Update___Seq___atoh_Type(); call proc_Seq__Equal__Equiv___Seq___atoh_Type(); call proc_Seq__Take__Length___Seq___atoh_Type(); call proc_Seq__Take__Index___Seq___atoh_Type(); call proc_Seq__Drop__Length___Seq___atoh_Type(); call proc_Seq__Drop__Index___Seq___atoh_Type(); call proc_Seq__Append__TakeDrop___Seq___atoh_Type(); call proc_Seq__Update__CommuteTake1___Seq___atoh_Type(); call proc_Seq__Update__CommuteTake2___Seq___atoh_Type(); call proc_Seq__Update__CommuteDrop1___Seq___atoh_Type(); call proc_Seq__Update__CommuteDrop2___Seq___atoh_Type(); call proc_Seq__Build__CommuteDrop___Seq___atoh_Type(); call proc_Seq__Take__Empty___Seq___atoh_Type(); call proc_Seq__Drop__Empty___Seq___atoh_Type(); call lemma_fun_ensures_fun_SHA256(); //call lemma_fun_ensures_fun_ConvertAtoHToSeq__premium(); r := r_old; stk := stk_old; statics := statics_old; io := io_old; mems := mems_old; $commonVars := $commonVars_old; $gcVars := $gcVars_old; $toAbs := $toAbs_old; $absMem := $absMem_old; $stacksFrames := $stacksFrames_old; objLayouts := objLayouts_old; heap := heap_old; $ghost_M__abs := frameGet($stacksFrames, r_old.regs[ESP] + 4 + stackGcOffset); $ghost_H__abs := frameGet($stacksFrames, r_old.regs[ESP] + 8 + stackGcOffset); $ghost_W__abs := frameGet($stacksFrames, r_old.regs[ESP] + 12 + stackGcOffset); mod0 := ($ghost_W).arrAbs; assert TV(r.regs[ESP]); assert TO(0 - 1); assert TO(279552 - 1); assert TO(0 - 2); assert TO(279552 - 2); assert TO(0 - 3); assert TO(279552 - 3); assert TO(0 - 4); assert TO(279552 - 4); assert TO(0); assert TO(279552); assert TO(1); assert TO(279553); assert TO(2); assert TO(279554); assert TO(3); assert TO(279555); call proc_reveal__Mul16(); call proc_lemma__word32__Word32(); call proc_lemma__2toX(); $ghost_s := fun_SHA256__vars__to__state($absMem, $ghost_M, $ghost_words, $ghost_H, $ghost_W, $ghost_atoh, $ghost_num_blocks); //- Load currentBlock call eax := Load(stk, esp+12); assert eax == $ghost_currentBlock; edx := 16; call edx,eax := Mul(eax, edx); //- Skip $currentBlock number of blocks, each 16 values //- Load W base into ESI call r, mems := heapLoadStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, ESI, OMem(MReg(ESP, 0x11100C)), EvalPtr(r, OMem(MReg(ESP, 0x11100C)))); W_base := esi; call arrayElementProperties(core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, 0, $ghost_W__abs, esi); //- Proves we're within bounds for the addition below esi := esi + 8; //- Skip past the header to reach the data we care about //- Calc statements imported from DafnyCC output assert 0 <= $ghost_currentBlock * 16; assert 0 <= $ghost_currentBlock * 16 + 15; assert $ghost_currentBlock*16 < $ghost_words; assert $ghost_currentBlock*16 + 15 < $ghost_words; //- Load M base into EDI call r, mems := heapLoadStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, EDI, OMem(MReg(ESP, 0x111004)), EvalPtr(r, OMem(MReg(ESP, 0x111004)))); M_base := edi; //-assert Aligned(edi); call arrayElementProperties(core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_currentBlock*16 + 0, $ghost_M__abs, edi); //- Proves we're within bounds for the lea below assert word($ghost_currentBlock * 16); assert eax == wrap32(Mult($ghost_currentBlock, 16)); assert TVM($ghost_currentBlock, 16); assert eax == wrap32($ghost_currentBlock * 16); call reveal_wrap32($ghost_currentBlock * 16); assert eax == ($ghost_currentBlock * 16) mod WORD_HI; assert 0 <= 16 * $ghost_currentBlock; assert 16 * $ghost_currentBlock < 0x100000000; call reveal_WORD_HI(); assert eax == 16 * $ghost_currentBlock; assert word(edi + 4 * (2 + $ghost_currentBlock*16)); call eax := Lea(edi + 4 * eax + 8); //- Convert eax into a pointer into M (index = 4*16*currentBlock, +8 to skip array header) assert TV(edi) && TO(16) && TO(18) && TO(2); //- Load the value we want from M into ebx call r, mems := loadArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, EBX, OMem(MReg(EAX, 0)), $ghost_currentBlock*16 + 0, $ghost_M__abs, M_base); //- Copy it to W call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(ESI, 0)), OReg(EBX), 0, ebx, $ghost_W__abs, W_base); //- Calc statement imported from DafnyCC output $ghost_t := 0; forall::((fun_INTERNAL__array__elems__index($absMem[$ghost_W.arrAbs], ($ghost_t))) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks(fun_Seq__Take___int(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words), 16), $ghost_currentBlock), $ghost_t))) { call proc_Lemma__BlockedSequencePrefixContainsElement(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words, 16, $ghost_currentBlock, $ghost_t); } forall::((fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks(fun_Seq__Take___int(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words), 16), $ghost_currentBlock), $ghost_t)) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks((M#SHA256_state_c($ghost_s)), 16), $ghost_currentBlock), $ghost_t))) { } forall::((fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks((M#SHA256_state_c($ghost_s)), 16), $ghost_currentBlock), $ghost_t)) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int((M#SHA256Trace_c($ghost_z)), $ghost_currentBlock), $ghost_t))) { } assert fun_INTERNAL__array__elems__index($absMem[$ghost_W.arrAbs], $ghost_t) == fun_Seq__Index___int(fun_Seq__Index___Seq___int((M#SHA256Trace_c($ghost_z)), $ghost_currentBlock), $ghost_t); //- Load the value we want from M into ebx call r, mems := loadArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, EBX, OMem(MReg(EAX, 4)), $ghost_currentBlock*16 + 1, $ghost_M__abs, M_base); //- Copy it to W call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(ESI, 4)), OReg(EBX), 1, ebx, $ghost_W__abs, W_base); //- Calc statement imported from DafnyCC output $ghost_t := 1; forall::((fun_INTERNAL__array__elems__index($absMem[$ghost_W.arrAbs], ($ghost_t))) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks(fun_Seq__Take___int(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words), 16), $ghost_currentBlock), $ghost_t))) { call proc_Lemma__BlockedSequencePrefixContainsElement(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words, 16, $ghost_currentBlock, $ghost_t); } forall::((fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks(fun_Seq__Take___int(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words), 16), $ghost_currentBlock), $ghost_t)) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks((M#SHA256_state_c($ghost_s)), 16), $ghost_currentBlock), $ghost_t))) { } forall::((fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks((M#SHA256_state_c($ghost_s)), 16), $ghost_currentBlock), $ghost_t)) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int((M#SHA256Trace_c($ghost_z)), $ghost_currentBlock), $ghost_t))) { } assert fun_INTERNAL__array__elems__index($absMem[$ghost_W.arrAbs], $ghost_t) == fun_Seq__Index___int(fun_Seq__Index___Seq___int((M#SHA256Trace_c($ghost_z)), $ghost_currentBlock), $ghost_t); //- Load the value we want from M into ebx call r, mems := loadArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, EBX, OMem(MReg(EAX, 8)), $ghost_currentBlock*16 + 2, $ghost_M__abs, M_base); //- Copy it to W call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(ESI, 8)), OReg(EBX), 2, ebx, $ghost_W__abs, W_base); //- Calc statement imported from DafnyCC output $ghost_t := 2; forall::((fun_INTERNAL__array__elems__index($absMem[$ghost_W.arrAbs], ($ghost_t))) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks(fun_Seq__Take___int(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words), 16), $ghost_currentBlock), $ghost_t))) { call proc_Lemma__BlockedSequencePrefixContainsElement(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words, 16, $ghost_currentBlock, $ghost_t); } forall::((fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks(fun_Seq__Take___int(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words), 16), $ghost_currentBlock), $ghost_t)) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks((M#SHA256_state_c($ghost_s)), 16), $ghost_currentBlock), $ghost_t))) { } forall::((fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks((M#SHA256_state_c($ghost_s)), 16), $ghost_currentBlock), $ghost_t)) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int((M#SHA256Trace_c($ghost_z)), $ghost_currentBlock), $ghost_t))) { } //- Load the value we want from M into ebx call r, mems := loadArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, EBX, OMem(MReg(EAX, 12)), $ghost_currentBlock*16 + 3, $ghost_M__abs, M_base); //- Copy it to W call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(ESI, 12)), OReg(EBX), 3, ebx, $ghost_W__abs, W_base); //- Calc statement imported from DafnyCC output $ghost_t := 3; forall::((fun_INTERNAL__array__elems__index($absMem[$ghost_W.arrAbs], ($ghost_t))) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks(fun_Seq__Take___int(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words), 16), $ghost_currentBlock), $ghost_t))) { call proc_Lemma__BlockedSequencePrefixContainsElement(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words, 16, $ghost_currentBlock, $ghost_t); } forall::((fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks(fun_Seq__Take___int(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words), 16), $ghost_currentBlock), $ghost_t)) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks((M#SHA256_state_c($ghost_s)), 16), $ghost_currentBlock), $ghost_t))) { } forall::((fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks((M#SHA256_state_c($ghost_s)), 16), $ghost_currentBlock), $ghost_t)) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int((M#SHA256Trace_c($ghost_z)), $ghost_currentBlock), $ghost_t))) { } //- Load the value we want from M into ebx call r, mems := loadArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, EBX, OMem(MReg(EAX, 16)), $ghost_currentBlock*16 + 4, $ghost_M__abs, M_base); //- Copy it to W call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(ESI, 16)), OReg(EBX), 4, ebx, $ghost_W__abs, W_base); //- Calc statement imported from DafnyCC output $ghost_t := 4; forall::((fun_INTERNAL__array__elems__index($absMem[$ghost_W.arrAbs], ($ghost_t))) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks(fun_Seq__Take___int(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words), 16), $ghost_currentBlock), $ghost_t))) { call proc_Lemma__BlockedSequencePrefixContainsElement(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words, 16, $ghost_currentBlock, $ghost_t); } forall::((fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks(fun_Seq__Take___int(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words), 16), $ghost_currentBlock), $ghost_t)) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks((M#SHA256_state_c($ghost_s)), 16), $ghost_currentBlock), $ghost_t))) { } forall::((fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks((M#SHA256_state_c($ghost_s)), 16), $ghost_currentBlock), $ghost_t)) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int((M#SHA256Trace_c($ghost_z)), $ghost_currentBlock), $ghost_t))) { } //- Load the value we want from M into ebx call r, mems := loadArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, EBX, OMem(MReg(EAX, 20)), $ghost_currentBlock*16 + 5, $ghost_M__abs, M_base); //- Copy it to W call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(ESI, 20)), OReg(EBX), 5, ebx, $ghost_W__abs, W_base); //- Calc statement imported from DafnyCC output $ghost_t := 5; forall::((fun_INTERNAL__array__elems__index($absMem[$ghost_W.arrAbs], ($ghost_t))) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks(fun_Seq__Take___int(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words), 16), $ghost_currentBlock), $ghost_t))) { call proc_Lemma__BlockedSequencePrefixContainsElement(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words, 16, $ghost_currentBlock, $ghost_t); } forall::((fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks(fun_Seq__Take___int(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words), 16), $ghost_currentBlock), $ghost_t)) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks((M#SHA256_state_c($ghost_s)), 16), $ghost_currentBlock), $ghost_t))) { } forall::((fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks((M#SHA256_state_c($ghost_s)), 16), $ghost_currentBlock), $ghost_t)) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int((M#SHA256Trace_c($ghost_z)), $ghost_currentBlock), $ghost_t))) { } //- Load the value we want from M into ebx call r, mems := loadArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, EBX, OMem(MReg(EAX, 24)), $ghost_currentBlock*16 + 6, $ghost_M__abs, M_base); //- Copy it to W call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(ESI, 24)), OReg(EBX), 6, ebx, $ghost_W__abs, W_base); //- Calc statement imported from DafnyCC output $ghost_t := 6; forall::((fun_INTERNAL__array__elems__index($absMem[$ghost_W.arrAbs], ($ghost_t))) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks(fun_Seq__Take___int(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words), 16), $ghost_currentBlock), $ghost_t))) { call proc_Lemma__BlockedSequencePrefixContainsElement(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words, 16, $ghost_currentBlock, $ghost_t); } forall::((fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks(fun_Seq__Take___int(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words), 16), $ghost_currentBlock), $ghost_t)) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks((M#SHA256_state_c($ghost_s)), 16), $ghost_currentBlock), $ghost_t))) { } forall::((fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks((M#SHA256_state_c($ghost_s)), 16), $ghost_currentBlock), $ghost_t)) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int((M#SHA256Trace_c($ghost_z)), $ghost_currentBlock), $ghost_t))) { } //- Load the value we want from M into ebx call r, mems := loadArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, EBX, OMem(MReg(EAX, 28)), $ghost_currentBlock*16 + 7, $ghost_M__abs, M_base); //- Copy it to W call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(ESI, 28)), OReg(EBX), 7, ebx, $ghost_W__abs, W_base); //- Calc statement imported from DafnyCC output $ghost_t := 7; forall::((fun_INTERNAL__array__elems__index($absMem[$ghost_W.arrAbs], ($ghost_t))) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks(fun_Seq__Take___int(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words), 16), $ghost_currentBlock), $ghost_t))) { call proc_Lemma__BlockedSequencePrefixContainsElement(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words, 16, $ghost_currentBlock, $ghost_t); } forall::((fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks(fun_Seq__Take___int(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words), 16), $ghost_currentBlock), $ghost_t)) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks((M#SHA256_state_c($ghost_s)), 16), $ghost_currentBlock), $ghost_t))) { } forall::((fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks((M#SHA256_state_c($ghost_s)), 16), $ghost_currentBlock), $ghost_t)) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int((M#SHA256Trace_c($ghost_z)), $ghost_currentBlock), $ghost_t))) { } //- Load the value we want from M into ebx call r, mems := loadArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, EBX, OMem(MReg(EAX, 32)), $ghost_currentBlock*16 + 8, $ghost_M__abs, M_base); //- Copy it to W call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(ESI, 32)), OReg(EBX), 8, ebx, $ghost_W__abs, W_base); //- Calc statement imported from DafnyCC output $ghost_t := 8; forall::((fun_INTERNAL__array__elems__index($absMem[$ghost_W.arrAbs], ($ghost_t))) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks(fun_Seq__Take___int(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words), 16), $ghost_currentBlock), $ghost_t))) { call proc_Lemma__BlockedSequencePrefixContainsElement(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words, 16, $ghost_currentBlock, $ghost_t); } forall::((fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks(fun_Seq__Take___int(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words), 16), $ghost_currentBlock), $ghost_t)) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks((M#SHA256_state_c($ghost_s)), 16), $ghost_currentBlock), $ghost_t))) { } forall::((fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks((M#SHA256_state_c($ghost_s)), 16), $ghost_currentBlock), $ghost_t)) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int((M#SHA256Trace_c($ghost_z)), $ghost_currentBlock), $ghost_t))) { } //- Load the value we want from M into ebx call r, mems := loadArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, EBX, OMem(MReg(EAX, 36)), $ghost_currentBlock*16 + 9, $ghost_M__abs, M_base); //- Copy it to W call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(ESI, 36)), OReg(EBX), 9, ebx, $ghost_W__abs, W_base); //- Calc statement imported from DafnyCC output $ghost_t := 9; forall::((fun_INTERNAL__array__elems__index($absMem[$ghost_W.arrAbs], ($ghost_t))) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks(fun_Seq__Take___int(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words), 16), $ghost_currentBlock), $ghost_t))) { call proc_Lemma__BlockedSequencePrefixContainsElement(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words, 16, $ghost_currentBlock, $ghost_t); } forall::((fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks(fun_Seq__Take___int(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words), 16), $ghost_currentBlock), $ghost_t)) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks((M#SHA256_state_c($ghost_s)), 16), $ghost_currentBlock), $ghost_t))) { } forall::((fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks((M#SHA256_state_c($ghost_s)), 16), $ghost_currentBlock), $ghost_t)) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int((M#SHA256Trace_c($ghost_z)), $ghost_currentBlock), $ghost_t))) { } //- Load the value we want from M into ebx call r, mems := loadArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, EBX, OMem(MReg(EAX, 40)), $ghost_currentBlock*16 + 10, $ghost_M__abs, M_base); //- Copy it to W call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(ESI, 40)), OReg(EBX), 10, ebx, $ghost_W__abs, W_base); //- Calc statement imported from DafnyCC output $ghost_t := 10; forall::((fun_INTERNAL__array__elems__index($absMem[$ghost_W.arrAbs], ($ghost_t))) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks(fun_Seq__Take___int(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words), 16), $ghost_currentBlock), $ghost_t))) { call proc_Lemma__BlockedSequencePrefixContainsElement(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words, 16, $ghost_currentBlock, $ghost_t); } forall::((fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks(fun_Seq__Take___int(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words), 16), $ghost_currentBlock), $ghost_t)) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks((M#SHA256_state_c($ghost_s)), 16), $ghost_currentBlock), $ghost_t))) { } forall::((fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks((M#SHA256_state_c($ghost_s)), 16), $ghost_currentBlock), $ghost_t)) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int((M#SHA256Trace_c($ghost_z)), $ghost_currentBlock), $ghost_t))) { } //- Load the value we want from M into ebx call r, mems := loadArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, EBX, OMem(MReg(EAX, 44)), $ghost_currentBlock*16 + 11, $ghost_M__abs, M_base); //- Copy it to W call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(ESI, 44)), OReg(EBX), 11, ebx, $ghost_W__abs, W_base); //- Calc statement imported from DafnyCC output $ghost_t := 11; forall::((fun_INTERNAL__array__elems__index($absMem[$ghost_W.arrAbs], ($ghost_t))) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks(fun_Seq__Take___int(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words), 16), $ghost_currentBlock), $ghost_t))) { call proc_Lemma__BlockedSequencePrefixContainsElement(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words, 16, $ghost_currentBlock, $ghost_t); } forall::((fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks(fun_Seq__Take___int(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words), 16), $ghost_currentBlock), $ghost_t)) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks((M#SHA256_state_c($ghost_s)), 16), $ghost_currentBlock), $ghost_t))) { } forall::((fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks((M#SHA256_state_c($ghost_s)), 16), $ghost_currentBlock), $ghost_t)) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int((M#SHA256Trace_c($ghost_z)), $ghost_currentBlock), $ghost_t))) { } //- Load the value we want from M into ebx call r, mems := loadArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, EBX, OMem(MReg(EAX, 48)), $ghost_currentBlock*16 + 12, $ghost_M__abs, M_base); //- Copy it to W call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(ESI, 48)), OReg(EBX), 12, ebx, $ghost_W__abs, W_base); //- Calc statement imported from DafnyCC output $ghost_t := 12; forall::((fun_INTERNAL__array__elems__index($absMem[$ghost_W.arrAbs], ($ghost_t))) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks(fun_Seq__Take___int(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words), 16), $ghost_currentBlock), $ghost_t))) { call proc_Lemma__BlockedSequencePrefixContainsElement(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words, 16, $ghost_currentBlock, $ghost_t); } forall::((fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks(fun_Seq__Take___int(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words), 16), $ghost_currentBlock), $ghost_t)) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks((M#SHA256_state_c($ghost_s)), 16), $ghost_currentBlock), $ghost_t))) { } forall::((fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks((M#SHA256_state_c($ghost_s)), 16), $ghost_currentBlock), $ghost_t)) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int((M#SHA256Trace_c($ghost_z)), $ghost_currentBlock), $ghost_t))) { } //- Load the value we want from M into ebx call r, mems := loadArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, EBX, OMem(MReg(EAX, 52)), $ghost_currentBlock*16 + 13, $ghost_M__abs, M_base); //- Copy it to W call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(ESI, 52)), OReg(EBX), 13, ebx, $ghost_W__abs, W_base); //- Calc statement imported from DafnyCC output $ghost_t := 13; forall::((fun_INTERNAL__array__elems__index($absMem[$ghost_W.arrAbs], ($ghost_t))) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks(fun_Seq__Take___int(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words), 16), $ghost_currentBlock), $ghost_t))) { call proc_Lemma__BlockedSequencePrefixContainsElement(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words, 16, $ghost_currentBlock, $ghost_t); } forall::((fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks(fun_Seq__Take___int(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words), 16), $ghost_currentBlock), $ghost_t)) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks((M#SHA256_state_c($ghost_s)), 16), $ghost_currentBlock), $ghost_t))) { } forall::((fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks((M#SHA256_state_c($ghost_s)), 16), $ghost_currentBlock), $ghost_t)) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int((M#SHA256Trace_c($ghost_z)), $ghost_currentBlock), $ghost_t))) { } //- Load the value we want from M into ebx call r, mems := loadArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, EBX, OMem(MReg(EAX, 56)), $ghost_currentBlock*16 + 14, $ghost_M__abs, M_base); //- Copy it to W call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(ESI, 56)), OReg(EBX), 14, ebx, $ghost_W__abs, W_base); //- Calc statement imported from DafnyCC output $ghost_t := 14; forall::((fun_INTERNAL__array__elems__index($absMem[$ghost_W.arrAbs], ($ghost_t))) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks(fun_Seq__Take___int(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words), 16), $ghost_currentBlock), $ghost_t))) { call proc_Lemma__BlockedSequencePrefixContainsElement(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words, 16, $ghost_currentBlock, $ghost_t); } forall::((fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks(fun_Seq__Take___int(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words), 16), $ghost_currentBlock), $ghost_t)) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks((M#SHA256_state_c($ghost_s)), 16), $ghost_currentBlock), $ghost_t))) { } forall::((fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks((M#SHA256_state_c($ghost_s)), 16), $ghost_currentBlock), $ghost_t)) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int((M#SHA256Trace_c($ghost_z)), $ghost_currentBlock), $ghost_t))) { } //- Load the value we want from M into ebx call r, mems := loadArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, EBX, OMem(MReg(EAX, 60)), $ghost_currentBlock*16 + 15, $ghost_M__abs, M_base); //- Copy it to W call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(ESI, 60)), OReg(EBX), 15, ebx, $ghost_W__abs, W_base); //- Calc statement imported from DafnyCC output $ghost_t := 15; forall::((fun_INTERNAL__array__elems__index($absMem[$ghost_W.arrAbs], ($ghost_t))) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks(fun_Seq__Take___int(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words), 16), $ghost_currentBlock), $ghost_t))) { call proc_Lemma__BlockedSequencePrefixContainsElement(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words, 16, $ghost_currentBlock, $ghost_t); } forall::((fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks(fun_Seq__Take___int(fun_Seq__FromArray($absMem, $ghost_M), $ghost_words), 16), $ghost_currentBlock), $ghost_t)) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks((M#SHA256_state_c($ghost_s)), 16), $ghost_currentBlock), $ghost_t))) { } forall::((fun_Seq__Index___int(fun_Seq__Index___Seq___int(fun_BreakIntoBlocks((M#SHA256_state_c($ghost_s)), 16), $ghost_currentBlock), $ghost_t)) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int((M#SHA256Trace_c($ghost_z)), $ghost_currentBlock), $ghost_t))) { } Return; } } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Main/dafny_sha256opt_i.imp.basm ================================================ //-private-import BaseSpec; //-private-import MemorySpec; //-private-import IoTypesSpec; //-private-import MachineStateSpec; //-private-import AssemblySpec; //-private-import InterruptsSpec; //-private-import IoSpec; //-private-import Core; //-private-import LogicalAddressing; //-private-import Overflow; //-private-import Util; //-private-import Stacks; //-private-import Partition; //-private-import Instructions; //-private-import Separation; //-private-import IntLemmasBase; //-private-import IntLemmasGc; //-private-import SimpleGcMemory; //-private-import SimpleCommon; //-private-import SimpleCollector; //-private-import IoMain; //-private-import IntLemmasMain; //-private-basmonly-import Trusted; //-private-basmonly-import Checked; //-private-import Heap; //-private-import Seq; //-private-import dafny_DafnyPrelude; //-private-import DafnyAssembly; //-private-import dafny_base_s; //-private-import dafny_power2_s; //-private-import dafny_bytes_and_words_s; //-private-import dafny_be_sequences_s; //-private-import dafny_assembly_s; //-private-import dafny_integer_sequences_s; //-private-import dafny_seq_blocking_s; //-private-import dafny_sha_common_s; //-private-import dafny_hmac_common_s; //-private-import dafny_sha256_s; //-private-import dafny_seqs_simple_i; //-private-import dafny_power_s; //-private-import dafny_mul_i; //-private-import dafny_mul_nonlinear_i; //-private-import dafny_power_i; //-private-import dafny_div_def_i; //-private-import dafny_div_boogie_i; //-private-import dafny_div_nonlinear_i; //-private-import dafny_div_i; //-private-import dafny_repeat_digit_i; //-private-import dafny_power2_i; //-private-import dafny_seqs_and_ints_i; //-private-import dafny_relational_s; //-private-import dafny_assembly_i; //-private-import dafny_arrays_i; //-private-import dafny_seqs_transforms_i; //-private-import dafny_seqs_reverse_i; //-private-import dafny_integer_sequences_i; //-private-import dafny_integer_sequences_premium_i; //-private-import dafny_assembly_premium_i; //-private-import dafny_bit_vector_lemmas_i; //-private-import dafny_bit_vector_lemmas_premium_i; //-private-import dafny_word_bits_i; //-private-import dafny_arrays_and_seqs_i; //-private-import dafny_round_s; //-private-import dafny_round_i; //-private-import dafny_seq_blocking_i; //-private-import dafny_sha_common_i; //-private-import dafny_sha256common_i; //-private-import dafny_sha_padding_i; //- //- //- //- //- module implementation dafny_sha256opt_i { implementation Proc_InitK__SHA256__0__to__10(my r_old:regs, const my core_state:core_state, linear stk_old:mem, linear statics_old:mem, linear io_old:IOState, linear mems_old:mems, $commonVars_old:commonVars, $gcVars_old:gcVars, $toAbs_old:[int]int, $absMem_old:[int][int]int, $stacksFrames_old:[int]Frames, objLayouts_old:[int]ObjLayout, heap_old:Heap, $ghost_Ks:ArrayOfInt) returns(my r:regs, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars, $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap) { var $absMem_tmp:[int][int]int; var objLayouts_tmp:[int]ObjLayout; var heap_tmp:Heap; var obj_tmp:int; var val_tmp:int; var mod0:int; var $ghost_Ks__abs:int; assert fun_unroll(0); assert fun_unroll(1); r := r_old; stk := stk_old; statics := statics_old; io := io_old; mems := mems_old; $commonVars := $commonVars_old; $gcVars := $gcVars_old; $toAbs := $toAbs_old; $absMem := $absMem_old; $stacksFrames := $stacksFrames_old; objLayouts := objLayouts_old; heap := heap_old; $ghost_Ks__abs := frameGet($stacksFrames, r_old.regs[ESP] + 4 + stackGcOffset); mod0 := ($ghost_Ks).arrAbs; assert TV(r.regs[ESP]); assert TO(0); assert TO(263168); assert TO(1); assert TO(263169); assert TO(0x44400); assert TO(0x44401); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 116 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 116 // regalloc_stack_load:: EAX := OMem(MReg(ESP, 1052676)) // var = $ghost_Ks 577 call r, mems := heapLoadStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, EAX, OMem(MReg(ESP, 0x111004)), EvalPtr(r, OMem(MReg(ESP, 0x111004)))); // 0x111004 = stackGcOffset+4 $ghost_Ks__abs := frameGet($stacksFrames, EvalPtr(r, OMem(MReg(ESP, stackGcOffset+4)))); // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 8)), OConst(1116352408), 0, 1116352408, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 117 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 117 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 12)), OConst(1899447441), 1, 1899447441, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 118 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 118 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 16)), OConst(3049323471), 2, 3049323471, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 119 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 119 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 20)), OConst(3921009573), 3, 3921009573, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 120 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 120 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 24)), OConst(961987163), 4, 961987163, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 121 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 121 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 28)), OConst(1508970993), 5, 1508970993, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 122 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 122 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 32)), OConst(2453635748), 6, 2453635748, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 123 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 123 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 36)), OConst(2870763221), 7, 2870763221, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 124 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 124 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 40)), OConst(3624381080), 8, 3624381080, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 125 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 125 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 44)), OConst(310598401), 9, 310598401, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 126 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 126 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 48)), OConst(607225278), 10, 607225278, $ghost_Ks__abs, r.regs[EAX]); // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 52)), OConst(1426881987), 11, 1426881987, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 137 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 137 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 56)), OConst(1925078388), 12, 1925078388, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 138 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 138 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 60)), OConst(2162078206), 13, 2162078206, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 139 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 139 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 64)), OConst(2614888103), 14, 2614888103, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 140 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 140 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 68)), OConst(3248222580), 15, 3248222580, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 141 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 141 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 72)), OConst(3835390401), 16, 3835390401, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 142 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 142 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 76)), OConst(4022224774), 17, 4022224774, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 143 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 143 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 80)), OConst(264347078), 18, 264347078, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 144 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 144 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 84)), OConst(604807628), 19, 604807628, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 145 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 145 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 88)), OConst(770255983), 20, 770255983, $ghost_Ks__abs, r.regs[EAX]); // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 92)), OConst(1249150122), 21, 1249150122, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 156 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 156 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 96)), OConst(1555081692), 22, 1555081692, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 157 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 157 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 100)), OConst(1996064986), 23, 1996064986, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 158 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 158 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 104)), OConst(2554220882), 24, 2554220882, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 159 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 159 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 108)), OConst(2821834349), 25, 2821834349, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 160 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 160 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 112)), OConst(2952996808), 26, 2952996808, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 161 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 161 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 116)), OConst(3210313671), 27, 3210313671, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 162 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 162 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 120)), OConst(3336571891), 28, 3336571891, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 163 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 163 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 124)), OConst(3584528711), 29, 3584528711, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 164 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 164 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 128)), OConst(113926993), 30, 113926993, $ghost_Ks__abs, r.regs[EAX]); // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 132)), OConst(338241895), 31, 338241895, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 175 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 175 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 136)), OConst(666307205), 32, 666307205, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 176 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 176 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 140)), OConst(773529912), 33, 773529912, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 177 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 177 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 144)), OConst(1294757372), 34, 1294757372, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 178 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 178 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 148)), OConst(1396182291), 35, 1396182291, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 179 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 179 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 152)), OConst(1695183700), 36, 1695183700, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 180 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 180 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 156)), OConst(1986661051), 37, 1986661051, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 181 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 181 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 160)), OConst(2177026350), 38, 2177026350, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 182 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 182 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 164)), OConst(2456956037), 39, 2456956037, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 183 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 183 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 168)), OConst(2730485921), 40, 2730485921, $ghost_Ks__abs, r.regs[EAX]); // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 172)), OConst(2820302411), 41, 2820302411, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 194 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 194 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 176)), OConst(3259730800), 42, 3259730800, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 195 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 195 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 180)), OConst(3345764771), 43, 3345764771, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 196 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 196 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 184)), OConst(3516065817), 44, 3516065817, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 197 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 197 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 188)), OConst(3600352804), 45, 3600352804, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 198 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 198 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 192)), OConst(4094571909), 46, 4094571909, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 199 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 199 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 196)), OConst(275423344), 47, 275423344, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 200 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 200 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 200)), OConst(430227734), 48, 430227734, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 201 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 201 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 204)), OConst(506948616), 49, 506948616, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 202 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 202 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 208)), OConst(659060556), 50, 659060556, $ghost_Ks__abs, r.regs[EAX]); // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 212)), OConst(883997877), 51, 883997877, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 213 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 213 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 216)), OConst(958139571), 52, 958139571, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 214 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 214 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 220)), OConst(1322822218), 53, 1322822218, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 215 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 215 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 224)), OConst(1537002063), 54, 1537002063, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 216 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 216 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 228)), OConst(1747873779), 55, 1747873779, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 217 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 217 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 232)), OConst(1955562222), 56, 1955562222, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 218 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 218 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 236)), OConst(2024104815), 57, 2024104815, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 219 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 219 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 240)), OConst(2227730452), 58, 2227730452, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 220 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 220 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 244)), OConst(2361852424), 59, 2361852424, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 221 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 221 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 248)), OConst(2428436474), 60, 2428436474, $ghost_Ks__abs, r.regs[EAX]); // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 252)), OConst(2756734187), 61, 2756734187, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 232 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 232 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 256)), OConst(3204031479), 62, 3204031479, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 233 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 233 // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MReg(EAX, 260)), OConst(3329325298), 63, 3329325298, $ghost_Ks__abs, r.regs[EAX]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 127 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 127 // call:: := proc_reveal__K__SHA256() // isGhost = True call proc_reveal__K__SHA256(); assert !false; // return {: call r := logical_Ret(r, core_state, stk); return; :} } implementation Proc_InitK__SHA256(my r_old:regs, const my core_state:core_state, linear stk_old:mem, linear statics_old:mem, linear io_old:IOState, linear mems_old:mems, $commonVars_old:commonVars, $gcVars_old:gcVars, $toAbs_old:[int]int, $absMem_old:[int][int]int, $stacksFrames_old:[int]Frames, objLayouts_old:[int]ObjLayout, heap_old:Heap, $ghost_Ks:ArrayOfInt) returns(my r:regs, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars, $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap) { var $absMem_tmp:[int][int]int; var objLayouts_tmp:[int]ObjLayout; var heap_tmp:Heap; var obj_tmp:int; var val_tmp:int; var mod0:int; var $ghost_Ks__abs:int; assert fun_unroll(0); assert fun_unroll(1); r := r_old; stk := stk_old; statics := statics_old; io := io_old; mems := mems_old; $commonVars := $commonVars_old; $gcVars := $gcVars_old; $toAbs := $toAbs_old; $absMem := $absMem_old; $stacksFrames := $stacksFrames_old; objLayouts := objLayouts_old; heap := heap_old; $ghost_Ks__abs := frameGet($stacksFrames, r_old.regs[ESP] + 4 + stackGcOffset); mod0 := ($ghost_Ks).arrAbs; assert TV(r.regs[ESP]); assert TO(0 - 1); assert TO(263168 - 1); assert TO(0); assert TO(0x44400 - 1); assert TO(0x44400); assert TO(1); assert TO(263169); assert TO(279553); call r := logical_Sub(r, ESP, OConst(4)); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 101 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 101 // regalloc_stack_load:: EAX := OMem(MReg(ESP, 0x111008)) // var = $ghost_Ks 584 call r, mems := heapLoadStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, EAX, OMem(MReg(ESP, 0x111008)), EvalPtr(r, OMem(MReg(ESP, 0x111008)))); // 0x111008 = 8 + stackGcOffset //call r, mems := heapLoadStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, EAX, OMem(MReg(ESP, 0x111008)), EvalPtr(r, OMem(MReg(ESP, 0x111008)))); $ghost_Ks__abs := frameGet($stacksFrames, EvalPtr(r, OMem(MReg(ESP, 8 + stackGcOffset)))); // push argument #0 at index 0 isPtr = True argument = $ghost_Ks // regalloc_stack_store:: OMem(MReg(ESP, 1052672)) := EAX // var = $ghost_Ks call mems, $stacksFrames := heapStoreStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, OMem(MReg(ESP, 0x111000)), OReg(EAX), EvalPtr(r, OMem(MReg(ESP, 0x111000))), $ghost_Ks__abs); // 0x111000 = stackGcOffset // regalloc_stack_store:: OMem(MReg(ESP, 1052680)) := EAX // var = $ghost_Ks call mems, $stacksFrames := heapStoreStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, OMem(MReg(ESP, 0x111008)), OReg(EAX), EvalPtr(r, OMem(MReg(ESP, 0x111008))), $ghost_Ks__abs); // 0x111008 = 8 + stackGcOffset // call:: := Proc_InitK__SHA256__0__to__10($ghost_Ks) // isGhost = False call alignCall(r.regs[ESP]); {: call r, stk := logical_Call(r, core_state, stk); call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap := Proc_InitK__SHA256__0__to__10(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_Ks); :} assert SMemInvGcF(8, stk, old(stk_old), r.regs[ESP] + 4, old(r_old.regs[ESP]), $stacksFrames, $stacksFrames_old); assert !false; // // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 102 // // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 102 // // regalloc_stack_load:: EAX := OMem(MReg(ESP, 1052680)) // var = $ghost_Ks 585 // call r, mems := heapLoadStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, EAX, OMem(MReg(ESP, 1052680)), EvalPtr(r, OMem(MReg(ESP, 1052680)))); // $ghost_Ks__abs := frameGet($stacksFrames, EvalPtr(r, OMem(MReg(ESP, 1052680)))); // // // push argument #0 at index 0 isPtr = True argument = $ghost_Ks // // regalloc_stack_store:: OMem(MReg(ESP, 1052672)) := EAX // var = $ghost_Ks // call mems, $stacksFrames := heapStoreStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, OMem(MReg(ESP, 1052672)), OReg(EAX), EvalPtr(r, OMem(MReg(ESP, 1052672))), $ghost_Ks__abs); // // // regalloc_stack_store:: OMem(MReg(ESP, 1052680)) := EAX // var = $ghost_Ks // call mems, $stacksFrames := heapStoreStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, OMem(MReg(ESP, 1052680)), OReg(EAX), EvalPtr(r, OMem(MReg(ESP, 1052680))), $ghost_Ks__abs); // // // call:: := Proc_InitK__SHA256__11__to__20($ghost_Ks) // isGhost = False // call alignCall(r.regs[ESP]); // {: call r, stk := logical_Call(r, core_state, stk); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap := Proc_InitK__SHA256__11__to__20(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_Ks); :} // assert SMemInvGcF(8, stk, old(stk_old), r.regs[ESP] + 4, old(r_old.regs[ESP]), $stacksFrames, $stacksFrames_old); // assert !false; // // // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 103 // // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 103 // // regalloc_stack_load:: EAX := OMem(MReg(ESP, 1052680)) // var = $ghost_Ks 586 // call r, mems := heapLoadStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, EAX, OMem(MReg(ESP, 1052680)), EvalPtr(r, OMem(MReg(ESP, 1052680)))); // $ghost_Ks__abs := frameGet($stacksFrames, EvalPtr(r, OMem(MReg(ESP, 1052680)))); // // // push argument #0 at index 0 isPtr = True argument = $ghost_Ks // // regalloc_stack_store:: OMem(MReg(ESP, 1052672)) := EAX // var = $ghost_Ks // call mems, $stacksFrames := heapStoreStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, OMem(MReg(ESP, 1052672)), OReg(EAX), EvalPtr(r, OMem(MReg(ESP, 1052672))), $ghost_Ks__abs); // // // regalloc_stack_store:: OMem(MReg(ESP, 1052680)) := EAX // var = $ghost_Ks // call mems, $stacksFrames := heapStoreStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, OMem(MReg(ESP, 1052680)), OReg(EAX), EvalPtr(r, OMem(MReg(ESP, 1052680))), $ghost_Ks__abs); // // // call:: := Proc_InitK__SHA256__21__to__30($ghost_Ks) // isGhost = False // call alignCall(r.regs[ESP]); // {: call r, stk := logical_Call(r, core_state, stk); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap := Proc_InitK__SHA256__21__to__30(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_Ks); :} // assert SMemInvGcF(8, stk, old(stk_old), r.regs[ESP] + 4, old(r_old.regs[ESP]), $stacksFrames, $stacksFrames_old); // assert !false; // // // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 104 // // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 104 // // regalloc_stack_load:: EAX := OMem(MReg(ESP, 1052680)) // var = $ghost_Ks 587 // call r, mems := heapLoadStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, EAX, OMem(MReg(ESP, 1052680)), EvalPtr(r, OMem(MReg(ESP, 1052680)))); // $ghost_Ks__abs := frameGet($stacksFrames, EvalPtr(r, OMem(MReg(ESP, 1052680)))); // // // push argument #0 at index 0 isPtr = True argument = $ghost_Ks // // regalloc_stack_store:: OMem(MReg(ESP, 1052672)) := EAX // var = $ghost_Ks // call mems, $stacksFrames := heapStoreStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, OMem(MReg(ESP, 1052672)), OReg(EAX), EvalPtr(r, OMem(MReg(ESP, 1052672))), $ghost_Ks__abs); // // // regalloc_stack_store:: OMem(MReg(ESP, 1052680)) := EAX // var = $ghost_Ks // call mems, $stacksFrames := heapStoreStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, OMem(MReg(ESP, 1052680)), OReg(EAX), EvalPtr(r, OMem(MReg(ESP, 1052680))), $ghost_Ks__abs); // // // call:: := Proc_InitK__SHA256__31__to__40($ghost_Ks) // isGhost = False // call alignCall(r.regs[ESP]); // {: call r, stk := logical_Call(r, core_state, stk); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap := Proc_InitK__SHA256__31__to__40(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_Ks); :} // assert SMemInvGcF(8, stk, old(stk_old), r.regs[ESP] + 4, old(r_old.regs[ESP]), $stacksFrames, $stacksFrames_old); // assert !false; // // // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 105 // // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 105 // // regalloc_stack_load:: EAX := OMem(MReg(ESP, 1052680)) // var = $ghost_Ks 588 // call r, mems := heapLoadStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, EAX, OMem(MReg(ESP, 1052680)), EvalPtr(r, OMem(MReg(ESP, 1052680)))); // $ghost_Ks__abs := frameGet($stacksFrames, EvalPtr(r, OMem(MReg(ESP, 1052680)))); // // // push argument #0 at index 0 isPtr = True argument = $ghost_Ks // // regalloc_stack_store:: OMem(MReg(ESP, 1052672)) := EAX // var = $ghost_Ks // call mems, $stacksFrames := heapStoreStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, OMem(MReg(ESP, 1052672)), OReg(EAX), EvalPtr(r, OMem(MReg(ESP, 1052672))), $ghost_Ks__abs); // // // regalloc_stack_store:: OMem(MReg(ESP, 1052680)) := EAX // var = $ghost_Ks // call mems, $stacksFrames := heapStoreStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, OMem(MReg(ESP, 1052680)), OReg(EAX), EvalPtr(r, OMem(MReg(ESP, 1052680))), $ghost_Ks__abs); // // // call:: := Proc_InitK__SHA256__41__to__50($ghost_Ks) // isGhost = False // call alignCall(r.regs[ESP]); // {: call r, stk := logical_Call(r, core_state, stk); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap := Proc_InitK__SHA256__41__to__50(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_Ks); :} // assert SMemInvGcF(8, stk, old(stk_old), r.regs[ESP] + 4, old(r_old.regs[ESP]), $stacksFrames, $stacksFrames_old); // assert !false; // // // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 106 // // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 106 // // regalloc_stack_load:: EAX := OMem(MReg(ESP, 1052680)) // var = $ghost_Ks 589 // call r, mems := heapLoadStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, EAX, OMem(MReg(ESP, 1052680)), EvalPtr(r, OMem(MReg(ESP, 1052680)))); // $ghost_Ks__abs := frameGet($stacksFrames, EvalPtr(r, OMem(MReg(ESP, 1052680)))); // // // push argument #0 at index 0 isPtr = True argument = $ghost_Ks // // regalloc_stack_store:: OMem(MReg(ESP, 1052672)) := EAX // var = $ghost_Ks // call mems, $stacksFrames := heapStoreStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, OMem(MReg(ESP, 1052672)), OReg(EAX), EvalPtr(r, OMem(MReg(ESP, 1052672))), $ghost_Ks__abs); // // // regalloc_stack_store:: OMem(MReg(ESP, 1052680)) := EAX // var = $ghost_Ks // call mems, $stacksFrames := heapStoreStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, OMem(MReg(ESP, 1052680)), OReg(EAX), EvalPtr(r, OMem(MReg(ESP, 1052680))), $ghost_Ks__abs); // // // call:: := Proc_InitK__SHA256__51__to__60($ghost_Ks) // isGhost = False // call alignCall(r.regs[ESP]); // {: call r, stk := logical_Call(r, core_state, stk); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap := Proc_InitK__SHA256__51__to__60(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_Ks); :} // assert SMemInvGcF(8, stk, old(stk_old), r.regs[ESP] + 4, old(r_old.regs[ESP]), $stacksFrames, $stacksFrames_old); // assert !false; // // // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 107 // // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 107 // // regalloc_stack_load:: EAX := OMem(MReg(ESP, 1052680)) // var = $ghost_Ks 590 // call r, mems := heapLoadStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, EAX, OMem(MReg(ESP, 1052680)), EvalPtr(r, OMem(MReg(ESP, 1052680)))); // $ghost_Ks__abs := frameGet($stacksFrames, EvalPtr(r, OMem(MReg(ESP, 1052680)))); // // // push argument #0 at index 0 isPtr = True argument = $ghost_Ks // // regalloc_stack_store:: OMem(MReg(ESP, 1052672)) := EAX // var = $ghost_Ks // call mems, $stacksFrames := heapStoreStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, OMem(MReg(ESP, 1052672)), OReg(EAX), EvalPtr(r, OMem(MReg(ESP, 1052672))), $ghost_Ks__abs); // // // call:: := Proc_InitK__SHA256__61__to__63($ghost_Ks) // isGhost = False // call alignCall(r.regs[ESP]); // {: call r, stk := logical_Call(r, core_state, stk); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap := Proc_InitK__SHA256__61__to__63(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost_Ks); :} // assert SMemInvGcF(8, stk, old(stk_old), r.regs[ESP] + 4, old(r_old.regs[ESP]), $stacksFrames, $stacksFrames_old); // assert !false; call r := logical_Add(r, ESP, OConst(4)); // return {: call r := logical_Ret(r, core_state, stk); return; :} } implementation Proc_ComputeWsForBlockStep2__SHA256(my r_old:regs, const my core_state:core_state, linear stk_old:mem, linear statics_old:mem, linear io_old:IOState, linear mems_old:mems, $commonVars_old:commonVars, $gcVars_old:gcVars, $toAbs_old:[int]int, $absMem_old:[int][int]int, $stacksFrames_old:[int]Frames, objLayouts_old:[int]ObjLayout, heap_old:Heap, $ghost_M:ArrayOfInt, $ghost_words:int, $ghost_H:ArrayOfInt, $ghost_W:ArrayOfInt, $ghost_atoh:atoh_Type, $ghost_num_blocks:int, $ghost_z:SHA256Trace, $ghost_currentBlock:int) returns(my r:regs, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars, $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap) { var $absMem_tmp:[int][int]int; var objLayouts_tmp:[int]ObjLayout; var heap_tmp:Heap; var obj_tmp:int; var val_tmp:int; var mod0:int; var $ghost_t:int; var $ghost__temp__3:int; var $ghost__temp__4:int; var $ghost__temp__5:int; var $ghost__temp__6:int; var $ghost__temp__7:int; var $ghost__temp__8:int; var $ghost__temp__9:int; var $ghost__temp__10:int; var $ghost__temp__11:int; var $ghost__temp__12:int; var $ghost__temp__13:int; var $ghost__temp__14:int; var $ghost__temp__15:int; var $ghost_M__abs:int; var $ghost_H__abs:int; var $ghost_W__abs:int; var $ghost_atoh__abs:int; var $ghost_x:int; var curW:int; assert fun_unroll(0); assert fun_unroll(1); r := r_old; stk := stk_old; statics := statics_old; io := io_old; mems := mems_old; $commonVars := $commonVars_old; $gcVars := $gcVars_old; $toAbs := $toAbs_old; $absMem := $absMem_old; $stacksFrames := $stacksFrames_old; objLayouts := objLayouts_old; heap := heap_old; $ghost_M__abs := frameGet($stacksFrames, r_old.regs[ESP] + 4 + stackGcOffset); $ghost_H__abs := frameGet($stacksFrames, r_old.regs[ESP] + 8 + stackGcOffset); $ghost_W__abs := frameGet($stacksFrames, r_old.regs[ESP] + 12 + stackGcOffset); $ghost_atoh__abs := frameGet($stacksFrames, r_old.regs[ESP] + 20 + stackGcOffset); mod0 := ($ghost_W).arrAbs; assert TV(r.regs[ESP]); assert TO(0 - 1); assert TO(263168 - 1); assert TO(0 - 2); assert TO(263168 - 2); assert TO(0 - 3); assert TO(263168 - 3); assert TO(0 - 4); assert TO(263168 - 4); assert TO(0 - 5); assert TO(263168 - 5); assert TO(0); assert TO(263168); assert TO(1); assert TO(263169); assert TO(2); assert TO(263170); assert TO(3); assert TO(263171); assert TO(4); assert TO(263172); assert TO(5); assert TO(263173); assert TO(0x44400); assert TO(0x44403); assert TO(0x44404); assert TO(0x44405); assert TO(0x44408); call r := logical_Sub(r, ESP, OConst(20)); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 807 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 807 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 807 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 807 // move:: $ghost_t := 16 // isPtr = False call r := instr_Mov(r, EBP, OConst(16)); $ghost_t := r.regs[EBP]; // regalloc_stack_load:: ESI := OMem(MReg(ESP, 0x111032)) // var = $ghost_W 604 call r, mems := heapLoadStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, ESI, OMem(MReg(ESP, 0x111020)), EvalPtr(r, OMem(MReg(ESP, 0x111020)))); // 0x111020 = stackGcOffset + 32 $ghost_W__abs := frameGet($stacksFrames, EvalPtr(r, OMem(MReg(ESP, stackGcOffset + 32)))); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 808 // jump_to_label:: L1 condition = goto L1; // label:: L0 // isLoop = False L0: // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 814 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 815 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 815 // move:: $ghost__temp__8 := $ghost_t // isPtr = False call r := instr_Mov(r, ECX, OReg(EBP)); $ghost__temp__8 := r.regs[ECX]; // binary_assignment:: $ghost__temp__8 := instr_SubChecked($ghost__temp__8, ) call r := instr_SubChecked(r, ECX, OConst(2)); $ghost__temp__8 := r.regs[ECX]; //assert HeapValue(objLayouts, true, $toAbs, r.regs[ESI], $ghost_W__abs); // loadArrayElement call r, mems := loadArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, EDX, OMem(MIndex(ESI, 4, ECX, 8)), $ghost__temp__8, $ghost_W__abs, r.regs[ESI]); $ghost__temp__7 := r.regs[EDX]; //- Have: //- eax == t //- ecx == t - 2 //- edx == W[t-2] //- ebx := edx; //- call ebx := Ror(ebx, 17); //- ecx := edx; //- call ecx := Ror(ecx, 19); //- call ebx := Xor(ebx, ecx); curW := Eval(r, OReg(EDX)); call r := instr_Mov(r, EBX, OReg(EDX)); call r, $ghost__temp__3 := proc_Asm__RotateRight(r, $ghost__temp__7, 17, EBX, OConst(17)); call r := instr_Mov(r, ECX, OReg(EDX)); call r, $ghost__temp__6 := proc_Asm__RotateRight(r, $ghost__temp__7, 19, ECX, OConst(19)); call r, $ghost__temp__3 := proc_Asm__BitwiseXor(r, $ghost__temp__3, $ghost__temp__6, EBX, OReg(ECX)); //- Save a move by squashing edx, which we don't need any more // call edx := Shr(edx, 10); // call ebx := Xor(ebx, edx); call r, $ghost__temp__4 := proc_Asm__RightShift(r, $ghost__temp__7, 10, EDX, OConst(10)); call r, $ghost__temp__3 := proc_Asm__BitwiseXor(r, $ghost__temp__3, $ghost__temp__4, EBX, OReg(EDX)); call proc_reveal__SSIG1(); assert Eval(r, OReg(EBX)) == fun_SSIG1(curW); //- EAX == t //- EBX == result == SSIG(edx) //- edx := eax; //- eax := ebx; //- $ghost__temp__6 := eax; call r := instr_Mov(r, EAX, OReg(EBX)); $ghost__temp__6 := Eval(r, OReg(EAX)); //- Need: //- eax == SSIG1(edx) //- edx == t //- $ghost__temp__6 == eax? // // push argument #0 at index 1 isPtr = False argument = $ghost__temp__7 // // regalloc_stack_store:: OMem(MReg(ESP, 4)) := EDX // var = $ghost__temp__7 // call stk := logical_Store(r, core_state, stk, OMem(MReg(ESP, 4)), OReg(EDX)); // // // regalloc_stack_store:: OMem(MReg(ESP, 12)) := EAX // var = $ghost_t // call stk := logical_Store(r, core_state, stk, OMem(MReg(ESP, 12)), OReg(EAX)); // // // regalloc_stack_store:: OMem(MReg(ESP, 1052704)) := EBX // var = $ghost_W // call mems, $stacksFrames := heapStoreStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, OMem(MReg(ESP, 1052704)), OReg(EBX), EvalPtr(r, OMem(MReg(ESP, 1052704))), $ghost_W__abs); // // // call:: $ghost__temp__6 := Proc_SSIG1__impl($ghost__temp__7) // isGhost = False // call alignCall(r.regs[ESP]); // {: call r, stk := logical_Call(r, core_state, stk); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost__temp__6 := Proc_SSIG1__impl(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost__temp__7); :} // assert SMemInvGcF(24, stk, old(stk_old), r.regs[ESP] + 20, old(r_old.regs[ESP]), $stacksFrames, $stacksFrames_old); // // // pop return value #0 at index 0 into destination $ghost__temp__6 isPtr = False // $ghost__temp__6 := stk.map[r.regs[ESP] + 0]; // // // regalloc_stack_load:: EAX := OMem(MReg(ESP, 0)) // var = $ghost__temp__6 605 // call r := logical_Load(r, core_state, stk, EAX, OMem(MReg(ESP, 0))); // assert !false; // // // regalloc_stack_load:: EDX := OMem(MReg(ESP, 12)) // var = $ghost_t 606 // call r := logical_Load(r, core_state, stk, EDX, OMem(MReg(ESP, 12))); // move:: $ghost__temp__10 := $ghost_t // isPtr = False call r := instr_Mov(r, ECX, OReg(EBP)); $ghost__temp__10 := r.regs[ECX]; // binary_assignment:: $ghost__temp__10 := instr_SubChecked($ghost__temp__10, ) call r := instr_SubChecked(r, ECX, OConst(7)); $ghost__temp__10 := r.regs[ECX]; // // regalloc_stack_load:: ESI := OMem(MReg(ESP, 1052704)) // var = $ghost_W 607 // call r, mems := heapLoadStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, ESI, OMem(MReg(ESP, 1052704)), EvalPtr(r, OMem(MReg(ESP, 1052704)))); // $ghost_W__abs := frameGet($stacksFrames, EvalPtr(r, OMem(MReg(ESP, 1052704)))); // loadArrayElement call r, mems := loadArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, EBX, OMem(MIndex(ESI, 4, ECX, 8)), $ghost__temp__10, $ghost_W__abs, r.regs[ESI]); $ghost__temp__9 := r.regs[EBX]; // binary_assignment:: $ghost__temp__5 := proc_Asm__Add($ghost__temp__6, ) call r, $ghost__temp__5 := proc_Asm__Add(r, fun_SSIG1__impl(fun_INTERNAL__array__elems__index($absMem[$ghost_W.arrAbs], (INTERNAL_sub_boogie($ghost_t, 2)))), fun_INTERNAL__array__elems__index($absMem[$ghost_W.arrAbs], (INTERNAL_sub_boogie($ghost_t, 7))), EAX, OReg(EBX)); $ghost__temp__6 := r.regs[EAX]; // move:: $ghost__temp__5 := $ghost__temp__6 // isPtr = False call r := instr_Mov(r, ECX, OReg(EAX)); $ghost__temp__5 := r.regs[ECX]; assert !false; // move:: $ghost__temp__13 := $ghost_t // isPtr = False call r := instr_Mov(r, EAX, OReg(EBP)); $ghost__temp__13 := r.regs[EAX]; // binary_assignment:: $ghost__temp__13 := instr_SubChecked($ghost__temp__13, ) call r := instr_SubChecked(r, EAX, OConst(15)); $ghost__temp__13 := r.regs[EAX]; // loadArrayElement call r, mems := loadArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, EBX, OMem(MIndex(ESI, 4, EAX, 8)), $ghost__temp__13, $ghost_W__abs, r.regs[ESI]); $ghost__temp__12 := r.regs[EBX]; // Arg is EBX // Saves ECX, EDX curW := Eval(r, OReg(EBX)); call r := instr_Mov(r, EAX, OReg(EBX)); // binary_assignment:: $ghost__temp__11 := proc_Asm__RotateRight($ghost__temp__1, ) $ghost_x := Eval(r, OReg(EAX)); call r, $ghost__temp__11 := proc_Asm__RotateRight(r, $ghost_x, 7, EAX, OConst(7)); $ghost__temp__11 := r.regs[EAX]; assert !false; // move:: $ghost__temp__3 := $ghost_x // isPtr = False call r := instr_Mov(r, EDI, OReg(EBX)); $ghost__temp__3 := r.regs[EDI]; // binary_assignment:: $ghost__temp__3 := proc_Asm__RotateRight($ghost__temp__2, ) call r, $ghost__temp__3 := proc_Asm__RotateRight(r, $ghost_x, 18, EDI, OConst(18)); $ghost__temp__3 := r.regs[EDI]; assert !false; // binary_assignment:: $ghost__temp__12 := proc_Asm__BitwiseXor($ghost__temp__1, ) call r, $ghost__temp__12 := proc_Asm__BitwiseXor(r, fun_Asm__RotateRight($ghost_x, 7), fun_Asm__RotateRight($ghost_x, 18), EAX, OReg(EDI)); $ghost__temp__11 := r.regs[EAX]; // // move:: $ghost__temp__12 := $ghost__temp__11 // isPtr = False // call r := instr_Mov(r, EDI, OReg(EAX)); // $ghost__temp__12 := r.regs[EDI]; // assert !false; // // move:: $ghost__temp__3 := $ghost_x // isPtr = False // call r := instr_Mov(r, EAX, OReg(EBX)); // $ghost__temp__3 := r.regs[EAX]; // binary_assignment:: $ghost__temp__3 := proc_Asm__RightShift($ghost__temp__3, ) call r, $ghost__temp__3 := proc_Asm__RightShift(r, $ghost_x, 3, EBX, OConst(3)); $ghost__temp__3 := r.regs[EBX]; assert !false; // binary_assignment:: $ghost___result := proc_Asm__BitwiseXor($ghost__temp__12, ) call r, $ghost__temp__11 := proc_Asm__BitwiseXor(r, fun_Asm__BitwiseXor(fun_Asm__RotateRight($ghost_x, 7), fun_Asm__RotateRight($ghost_x, 18)), fun_Asm__RightShift($ghost_x, 3), EAX, OReg(EBX)); $ghost__temp__12 := r.regs[EAX]; call proc_reveal__SSIG0(); assert Eval(r, OReg(EAX)) == fun_SSIG0(curW); // call r := instr_Mov(r, EAX, OReg(EDI)); // // push argument #0 at index 1 isPtr = False argument = $ghost__temp__12 // // regalloc_stack_store:: OMem(MReg(ESP, 4)) := EBX // var = $ghost__temp__12 // call stk := logical_Store(r, core_state, stk, OMem(MReg(ESP, 4)), OReg(EBX)); // // // regalloc_stack_store:: OMem(MReg(ESP, 16)) := ECX // var = $ghost__temp__5 // call stk := logical_Store(r, core_state, stk, OMem(MReg(ESP, 16)), OReg(ECX)); // // // regalloc_stack_store:: OMem(MReg(ESP, 12)) := EDX // var = $ghost_t // call stk := logical_Store(r, core_state, stk, OMem(MReg(ESP, 12)), OReg(EDX)); // // // regalloc_stack_store:: OMem(MReg(ESP, 1052704)) := ESI // var = $ghost_W // call mems, $stacksFrames := heapStoreStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, OMem(MReg(ESP, 1052704)), OReg(ESI), EvalPtr(r, OMem(MReg(ESP, 1052704))), $ghost_W__abs); // // // call:: $ghost__temp__11 := Proc_SSIG0__impl($ghost__temp__12) // isGhost = False // call alignCall(r.regs[ESP]); // {: call r, stk := logical_Call(r, core_state, stk); // call r, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost__temp__11 := Proc_SSIG0__impl(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, $ghost__temp__12); :} // assert SMemInvGcF(24, stk, old(stk_old), r.regs[ESP] + 20, old(r_old.regs[ESP]), $stacksFrames, $stacksFrames_old); // // // pop return value #0 at index 0 into destination $ghost__temp__11 isPtr = False // $ghost__temp__11 := stk.map[r.regs[ESP] + 0]; // // // regalloc_stack_load:: EAX := OMem(MReg(ESP, 0)) // var = $ghost__temp__11 608 // call r := logical_Load(r, core_state, stk, EAX, OMem(MReg(ESP, 0))); // assert !false; // // // regalloc_stack_load:: ECX := OMem(MReg(ESP, 16)) // var = $ghost__temp__5 609 // call r := logical_Load(r, core_state, stk, ECX, OMem(MReg(ESP, 16))); call proc_reveal__SSIG0(); // Result == EAX // need ECX == old(ECX) // need EDX == old(EDX) // binary_assignment:: $ghost__temp__4 := proc_Asm__Add($ghost__temp__5, ) call r, $ghost__temp__4 := proc_Asm__Add(r, fun_Asm__Add(fun_SSIG1__impl(fun_INTERNAL__array__elems__index($absMem[$ghost_W.arrAbs], (INTERNAL_sub_boogie($ghost_t, 2)))), fun_INTERNAL__array__elems__index($absMem[$ghost_W.arrAbs], (INTERNAL_sub_boogie($ghost_t, 7)))), fun_SSIG0__impl(fun_INTERNAL__array__elems__index($absMem[$ghost_W.arrAbs], (INTERNAL_sub_boogie($ghost_t, 15)))), ECX, OReg(EAX)); $ghost__temp__5 := r.regs[ECX]; // move:: $ghost__temp__4 := $ghost__temp__5 // isPtr = False call r := instr_Mov(r, EAX, OReg(ECX)); $ghost__temp__4 := r.regs[EAX]; assert !false; // // regalloc_stack_load:: EDX := OMem(MReg(ESP, 12)) // var = $ghost_t 610 // call r := logical_Load(r, core_state, stk, EDX, OMem(MReg(ESP, 12))); // move:: $ghost__temp__15 := $ghost_t // isPtr = False call r := instr_Mov(r, ECX, OReg(EBP)); $ghost__temp__15 := r.regs[ECX]; // binary_assignment:: $ghost__temp__15 := instr_SubChecked($ghost__temp__15, ) call r := instr_SubChecked(r, ECX, OConst(16)); $ghost__temp__15 := r.regs[ECX]; // regalloc_stack_load:: ESI := OMem(MReg(ESP, 1052704)) // var = $ghost_W 611 // call r, mems := heapLoadStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, ESI, OMem(MReg(ESP, 1052704)), EvalPtr(r, OMem(MReg(ESP, 1052704)))); // $ghost_W__abs := frameGet($stacksFrames, EvalPtr(r, OMem(MReg(ESP, 1052704)))); // loadArrayElement call r, mems := loadArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, EBX, OMem(MIndex(ESI, 4, ECX, 8)), $ghost__temp__15, $ghost_W__abs, r.regs[ESI]); $ghost__temp__14 := r.regs[EBX]; // binary_assignment:: $ghost__temp__3 := proc_Asm__Add($ghost__temp__4, ) call r, $ghost__temp__3 := proc_Asm__Add(r, fun_Asm__Add(fun_Asm__Add(fun_SSIG1__impl(fun_INTERNAL__array__elems__index($absMem[$ghost_W.arrAbs], (INTERNAL_sub_boogie($ghost_t, 2)))), fun_INTERNAL__array__elems__index($absMem[$ghost_W.arrAbs], (INTERNAL_sub_boogie($ghost_t, 7)))), fun_SSIG0__impl(fun_INTERNAL__array__elems__index($absMem[$ghost_W.arrAbs], (INTERNAL_sub_boogie($ghost_t, 15))))), fun_INTERNAL__array__elems__index($absMem[$ghost_W.arrAbs], (INTERNAL_sub_boogie($ghost_t, 16))), EAX, OReg(EBX)); $ghost__temp__4 := r.regs[EAX]; // move:: $ghost__temp__3 := $ghost__temp__4 // isPtr = False call r := instr_Mov(r, ECX, OReg(EAX)); $ghost__temp__3 := r.regs[ECX]; assert !false; // storeArrayElement call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, OMem(MIndex(ESI, 4, EBP, 8)), OReg(ECX), $ghost_t, $ghost__temp__3, $ghost_W__abs, r.regs[ESI]); // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 816 // ###LINE: C:\home\git\IroncladApps\iron\src\Dafny\Libraries\Crypto\Hash\sha256opt.i.dfy: 816 // binary_assignment:: $ghost_t := instr_AddChecked($ghost_t, ) call r := instr_AddChecked(r, EBP, OConst(1)); $ghost_t := r.regs[EBP]; // // regalloc_move:: EAX := EDX // call r := instr_Mov(r, EAX, OReg(EDX)); // regalloc_stack_store:: OMem(MReg(ESP, 1052704)) := ESI // var = $ghost_W // call mems, $stacksFrames := heapStoreStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, OMem(MReg(ESP, 1052704)), OReg(ESI), EvalPtr(r, OMem(MReg(ESP, 1052704))), $ghost_W__abs); // // label:: L1 // isLoop = True L1: invariant MemInv(me,init,stk,statics,core_state,ptMem,mems); invariant NucleusInv(objLayouts,$S,$toAbs,$absMem,$commonVars,$gcVars,me,init,stk,statics,core_state,ptMem,mems,$stacksFrames,io); invariant SMemInvGcF(24, stk, old(stk_old), r.regs[ESP] + 20, old(r_old.regs[ESP]), $stacksFrames, $stacksFrames_old); invariant HeapInv($absMem, objLayouts, heap); invariant AbsExtend($toAbs, $toAbs_old, objLayouts, objLayouts_old); invariant (forall i:int::{$absMem[i]}{heap.absData[i]} heap_old.absData[i] is AbsNone || (heap.absData[i] == heap_old.absData[i] && ($absMem[i] == $absMem_old[i] || i == (($ghost_W).arrAbs)))); invariant io._inCtr == io_old._inCtr && io._outCtr == io_old._outCtr; // loop invariants invariant HeapValue(objLayouts, true, $toAbs, r.regs[ESI], $ghost_W__abs); invariant $ghost_t == (r.regs[EBP]); invariant StackAbsSlot(heap, $stacksFrames, EvalPtr(r, OMem(MReg(ESP, stackGcOffset+32)))) == Abs_ArrayOfInt($ghost_W); invariant frameGet($stacksFrames, EvalPtr(r, OMem(MReg(ESP, stackGcOffset+32)))) == $ghost_W.arrAbs; invariant (INTERNAL_le_boogie(16, $ghost_t)) && (INTERNAL_le_boogie($ghost_t, 64)); invariant (forall $ghost__0_step:int :: ((INTERNAL_le_boogie(0, $ghost__0_step)) && (INTERNAL_lt_boogie($ghost__0_step, $ghost_t))) ==> (fun_Word32(fun_INTERNAL__array__elems__index($absMem[$ghost_W.arrAbs], ($ghost__0_step))))); invariant (forall $ghost__1_step:int :: {fun_TStep($ghost__1_step)} ((fun_TStep($ghost__1_step)) && ((INTERNAL_le_boogie(0, $ghost__1_step)) && (INTERNAL_lt_boogie($ghost__1_step, 16)))) ==> ((fun_INTERNAL__array__elems__index($absMem[$ghost_W.arrAbs], ($ghost__1_step))) == (fun_Seq__Index___int(fun_Seq__Index___Seq___int((M#SHA256Trace_c($ghost_z)), $ghost_currentBlock), $ghost__1_step)))); invariant (forall $ghost__2_step:int :: {fun_TStep($ghost__2_step)} ((fun_TStep($ghost__2_step)) && ((INTERNAL_le_boogie(16, $ghost__2_step)) && (INTERNAL_lt_boogie($ghost__2_step, $ghost_t)))) ==> ((fun_INTERNAL__array__elems__index($absMem[$ghost_W.arrAbs], ($ghost__2_step))) == (fun_Asm__Add(fun_Asm__Add(fun_Asm__Add(fun_SSIG1(fun_INTERNAL__array__elems__index($absMem[$ghost_W.arrAbs], (INTERNAL_sub_boogie($ghost__2_step, 2)))), fun_INTERNAL__array__elems__index($absMem[$ghost_W.arrAbs], (INTERNAL_sub_boogie($ghost__2_step, 7)))), fun_SSIG0(fun_INTERNAL__array__elems__index($absMem[$ghost_W.arrAbs], (INTERNAL_sub_boogie($ghost__2_step, 15))))), fun_INTERNAL__array__elems__index($absMem[$ghost_W.arrAbs], (INTERNAL_sub_boogie($ghost__2_step, 16))))))); assert !false; call proc_Seq__Equal__Equiv___int(); call proc_Seq__Equal__Equiv___Seq___int(); call proc_Seq__Equal__Equiv___atoh_Type(); call proc_Seq__Equal__Equiv___Seq___atoh_Type(); call proc_Seq__Equal__Equiv___bool(); // jump_to_label:: L0 condition = $ghost_t < 64 call r := instr_Cmp(r, EBP, OConst(64)); if (Jb(r.efl)) { goto L0; } // label:: L2 // isLoop = False L2: call r := logical_Add(r, ESP, OConst(20)); // return {: call r := logical_Ret(r, core_state, stk); return; :} } } ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Main/mul_plan.txt ================================================ MulOpt: mhi, mlo := Mul64(aj, bv) edx, eax add1 := Add(mlo, lastcarry) mhi := AddCarry(mhi,0) newcj := AddCarry(add1, lastcj) mhi := AddCarry(mhi,0) // == newcarry Suppose on input: eax == aj ebx == lastcarry ecx == lastcj edx == bv Then we have: edx, eax := Mul64(eax, edx); eax(mlo) := eax + ebx (lastcarry) edx(mhi) := AddCarry(edx, 0); ecx(newcj) := AddCarry(ecx, eax(add1)); edx(newcarry) := AddCarry(edx, 0); Ensures: ecx == newcj // Written out to memory edx == newcarry // Need to move this to ebx for next call :-/ Loop Plan: Need to hold pointer to a: Starts at a.Length-1-0. Then we sub 1 per iteration. Last iter is a.Length-1-(adigits-1) = a.Length - adigits Need to hold pointer to c: Starts at c.Length-1-(0+bi). Then we sub 1 per iteration Need to hold loop bound: aptr >= a.Length - adigits --------------- This requires 3 registers To hold the bv value in CPU, we need a 4th register Have to hold the value from a array and c array => 2 more registers Have to hold the previous carry => 1 more register And Mul64 is going to clobber eax and edx - Okay to clobber the value in aj (eax), but what can we clobber in edx? Plan: Setup the array pointers. (edi, esi) Compute the loop bound (ebx) Load bv (ebp) lastcarry (ecx) := 0 ----> That only leaves eax, edx available! in the loop: Load from a into eax (aj) edx, eax := Mul64(eax, ebp) eax(mlo) := eax + ecx (lastcarry) // ecx now free edx(mhi) := AddCarry(edx, 0); Load from c into ecx (lastcj) ecx(newcj) := AddCarry(ecx, eax(add1)); Store ecx back into c edx(newcarry) := AddCarry(edx, 0); ecx := edx; // Move newcarry out of the way for the next loop subtract 4 from a ptr (edi) and c ptr (esi) ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Main/sha256opt2.plan ================================================ eax, ebx, ecx, edx, edi, esi, ebp NOTES/TODO: - For each variable that needs to be propagated, I should write it to the correct location on the stack for the next round immediately after reading it. That way, I don't need to hold onto it any longer than necessary - If we do that with b and c, we may be able to save a register ------------------------------------------------------------------- - The block below requires 3 registers, if we want to keep a alive ------------------------------------------------------------------- r1 <- Load a Store r1 r2 <- r1 r3 <- r1 r2 <- RotateRight(r2, 2) r3 <- RotateRight(r3, 13) r2 <- r2 xor r3 r3 <- r1 r3 <- RotateRight(r3, 22) r2 <- r2 xor r3 // == bsig0 ------------------------------------- After above block: Live: r1 == a r2 == bsig0 ------------------------------------- Assuming r1 holds a: r3 <- Load b Store r3 r4 <- r1 r1 <- And(r1, r3) // a & b r3 <- Load c Store r3 r4 <- And(r4, r3) // a & c Need to hold: bsig0, a, b, and (a & b), since we need to combine c with a and with b - Do this before we calculate bsig0? r4 <- Load c Store r4 r5 <- r1 r5 <- r1 and r3 == a & b r6 <- r1 r6 <- r1 and r4 == a & c r5 <- r5 xor r6 r6 <- r3 r6 <- r6 and r4 == b & c r5 <- r5 xor r6 ------------------------------------- After above block: Live: r1 == a r2 == bsig0 r3 == b r4 == c r5 == my_maj ------------------------------------- r2 <- Add(r2, r5) // T2 ------------------------------------- After above block: Live: r1 == a r2 == T2 r3 == b r4 == c ------------------------------------- After this point, we don't need a, b, or c any more, so write them back to the stack Store r1 Store r3 Store r4 ------------------------------------- After above block: Live: r2 == T2 ------------------------------------- // Calculate bsig1 r1 <- Load e r3 <- r1 r4 <- r1 r3 <- RotateRight(r3, 6) r4 <- RotateRight(r4, 11) r3 <- r3 xor r4 r4 <- r1 r4 <- RotateRight(r4, 25) r3 <- r3 xor r4 // == bsig1 ------------------------------------- After above block: Live: r1 == e r2 == T2 r3 == bsig1 ------------------------------------- // Calculate my_ch // Assume e is already stored r4 <- r1 r5 <- Load f Store r5 r4 <- r4 and r5 r1 <- not r1 r5 <- Load g Store r5 r1 <- r1 and r5 r4 <- r4 xor r1 // my_ch ------------------------------------- After above block: Live: r2 == T2 r3 == bsig1 r4 == my_ch ------------------------------------- // Calculate T1 r1 <- Load h r1 <- Add(r1, r3) // Frees up r3 r1 <- Add(r1, r4) // Frees up r4 // Do some of this sooner? r1 <- Add(r1, Kconst) r3 <- Load(Wregister, currentStepConst) r1 <- Add(r1, r3) // T1 ------------------------------------- After above block: Live: r1 == T1 r2 == T2 ------------------------------------- r2 <- r2 + r1 // May need a commutativity proof? Store r2 // T1 + T2 == a_next r2 <- Load d r1 <- r1 + r2 // May need a commutativity proof? Store r1 as e_next // Uses a // var bsig0 := Asm_BitwiseXor(Asm_BitwiseXor(Asm_RotateRight(a, 2), Asm_RotateRight(a, 13)), Asm_RotateRight(a, 22)); // Uses e // var bsig1 := Asm_BitwiseXor(Asm_BitwiseXor(Asm_RotateRight(e, 6), Asm_RotateRight(e, 11)), Asm_RotateRight(e, 25)); // Uses e, f, g // var my_ch := Asm_BitwiseXor(Asm_BitwiseAnd(e, f), Asm_BitwiseAnd(Asm_BitwiseNot(e), g)); // Uses a, b, c // var my_maj := Asm_BitwiseXor(Asm_BitwiseXor(Asm_BitwiseAnd(a, b), Asm_BitwiseAnd(a, c)), Asm_BitwiseAnd(b, c)); // Uses h // var T1 := Asm_Add(Asm_Add(Asm_Add(Asm_Add(h, bsig1), my_ch), Ks[currentStep]), W[currentStep]); // var T2 := Asm_Add(bsig0, my_maj); // Uses d a_next, b_next, c_next, d_next, e_next, f_next, g_next, h_next := Asm_Add(T1, T2), a, b, c, Asm_Add(d, T1), e, f, g; ================================================ FILE: ironclad-apps/src/Checked/Nucleus/Main/sha256opt2.plan2 ================================================ We need to use 5 registers out of the following 7: eax, ebx, ecx, edx, edi, esi, ebp r1, r2, r3, r4, r5 Initially, we can use the extra to point to Ks and W Eventually, we should hard-code the Ks, giving us an extra register - Use it to keep one state var? Not sure it matters which. ---------------------------------------------------------- Start with my_maj. Uses 4 registers. Preserves a in r1 ---------------------------------------------------------- r1 <- Load a Store r1 r2 <- Load b Store r2 r3 <- Load c Store r3 r4 <- r2 r2 <- And(r2, r1) // b & a // Need commutativity r4 <- And(r4, r3) // b & c r3 <- And(r3, r1) // c & a // Need commutativity r2 <- Xor(r2, r3) r2 <- Xor(r2, r4) // my_maj ------------------------------------- After above block, live: r1 == a r2 == my_maj ------------------------------------- // Calculate bsig0 r3 <- r1 r4 <- r1 r1 <- RotateRight(r1, 2) r3 <- RotateRight(r3, 13) r1 <- r1 xor r3 r4 <- RotateRight(r4, 22) r1 <- r1 xor r4 // == bsig0 r1 <- Add(r1, r2) // == T2 ------------------------------------- After above block, live: r1 == T2 ------------------------------------- // Calculate my_ch r2 <- Load e Store e r4 <- r2 r4 <- not r4 r3 <- Load g Store r3 r4 <- And(r4, r3) // !e & g r3 <- Load f Store r3 r3 <- And(r3, r2) // f & e // Need commutativity r3 <- Xor(r3, r4) // my_ch // Need commutativity ------------------------------------- After above block, live: r1 == T2 r2 == e r3 == my_ch ------------------------------------- // Calculate bsig1 r4 <- r2 r5 <- r2 r4 <- RotateRight(r4, 6) r5 <- RotateRight(r5, 11) r4 <- r4 xor r5 r2 <- RotateRight(r2, 25) r4 <- r4 xor r2 // == bsig1 ------------------------------------- After above block, live: r1 == T2 r3 == my_ch r4 == bsig1 ------------------------------------- // Calculate T1 r2 <- Load h r2 <- Add(r2, r4) // Frees r4 r2 <- Add(r2, r3) // Frees r3 r2 <- Add(r2, Kconst) r3 <- Load(Wregister, currentStepConst) r2 <- Add(r2, r3) // T1 ------------------------------------- After above block, live: r1 == T2 r2 == T1 ------------------------------------- r1 <- r1 + r2 // T2 + T1 == a_next // May need a commutivity proof Store r1 r1 <- Load d r1 <- r1 + r2 // d + T1 Store r1 as e_next // Uses a // var bsig0 := Asm_BitwiseXor(Asm_BitwiseXor(Asm_RotateRight(a, 2), Asm_RotateRight(a, 13)), Asm_RotateRight(a, 22)); // Uses e // var bsig1 := Asm_BitwiseXor(Asm_BitwiseXor(Asm_RotateRight(e, 6), Asm_RotateRight(e, 11)), Asm_RotateRight(e, 25)); // Uses e, f, g // var my_ch := Asm_BitwiseXor(Asm_BitwiseAnd(e, f), Asm_BitwiseAnd(Asm_BitwiseNot(e), g)); // Uses a, b, c // var my_maj := Asm_BitwiseXor(Asm_BitwiseXor(Asm_BitwiseAnd(a, b), Asm_BitwiseAnd(a, c)), Asm_BitwiseAnd(b, c)); // Uses h //var T1 := Asm_Add(Asm_Add(Asm_Add(Asm_Add(h, bsig1), my_ch), Ks[currentStep]), W[currentStep]); //var T2 := Asm_Add(bsig0, my_maj); // Uses d a_next, b_next, c_next, d_next, e_next, f_next, g_next, h_next := Asm_Add(T1, T2), a, b, c, Asm_Add(d, T1), e, f, g; ================================================ FILE: ironclad-apps/src/Clients/Benchmark/BenchSpec.py ================================================ SUT_IP="157.54.148.142" # Converted (manually) from BenchmarkList.i.dfy BenchmarkList = { "Nothing" : 0, "Sha1" : 1, "Sha256" : 2, "RsaKeyGen" : 3, "RsaEncrypt" : 4, "RsaDecrypt" : 5, "RsaDigestedSign" : 6, "RsaDigestedVerify" : 7, "TpmExtractRandom" : 8, "ByteSeqToWordSeq" : 9, "WordSeqToByteSeq" : 10, #"Sha1Raw" : 11, #"Sha256Raw" : 12, "DuplicateArray" : 13, "Max" : 14, } class BenchSpec(): def __init__(self, benchmark, iterations, key_length, message_length, use_words=False, use_original=False, annotation="", elapsed_time=None): self.benchmark = benchmark self.iterations = iterations self.key_length = key_length self.message_length = message_length self.use_words = use_words self.use_original = use_original self.annotation = annotation self.elapsed_time = elapsed_time def tuple(self): return (self.benchmark, self.iterations, self.key_length, self.message_length, self.use_words, self.use_original, self.annotation, self.elapsed_time) def __repr__(self): return "BenchSpec"+str(self.tuple())+"," def spec_tuple(self): return (self.benchmark, self.iterations, self.key_length, self.message_length, self.use_words, self.use_original, self.annotation) def compatible(self, other): return self.spec_tuple() == other.spec_tuple() ================================================ FILE: ironclad-apps/src/Clients/Benchmark/BenchmarkAnalyzer.py ================================================ #!/usr/bin/python import re from numpy import * from BenchSpec import BenchSpec data = [ #BenchSpec('RsaKeyGen', 1, 1024, '', 194.5417), #BenchSpec('RsaKeyGen', 1, 1024, '', 277.6209), #BenchSpec('RsaKeyGen', 1, 1024, '', 479.9764), #BenchSpec('RsaKeyGen', 1, 1024, '', 410.7493), #BenchSpec('RsaKeyGen', 1, 1024, '', 995.0421), #BenchSpec('RsaKeyGen', 1, 1024, '', 185.5208), #BenchSpec('RsaKeyGen', 1, 1024, '', 271.9875), #BenchSpec('RsaKeyGen', 1, 1024, '', 214.8805), #BenchSpec('RsaKeyGen', 1, 1024, '', 243.2842), #BenchSpec('RsaKeyGen', 1, 1024, '', 471.1768), # ## Before Canonicalizing #BenchSpec('RsaKeyGen', 1, 512, '', 16.77731), #BenchSpec('RsaKeyGen', 1, 512, '', 29.44297), #BenchSpec('RsaKeyGen', 1, 512, '', 25.03836), #BenchSpec('RsaKeyGen', 1, 512, '', 13.80892), #BenchSpec('RsaKeyGen', 1, 512, '', 7.543423), #BenchSpec('RsaKeyGen', 1, 512, '', 20.06039), #BenchSpec('RsaKeyGen', 1, 512, '', 73.0106), #BenchSpec('RsaKeyGen', 1, 512, '', 17.2482), #BenchSpec('RsaKeyGen', 1, 512, '', 23.70473), #BenchSpec('RsaKeyGen', 1, 512, '', 26.22202), # ## After Canonicalizing #BenchSpec('RsaKeyGen', 1, 512, '', 25.52086), #BenchSpec('RsaKeyGen', 1, 512, '', 40.67058), #BenchSpec('RsaKeyGen', 1, 512, '', 12.83777), #BenchSpec('RsaKeyGen', 1, 512, '', 11.71982), #BenchSpec('RsaKeyGen', 1, 512, '', 31.66075), #BenchSpec('RsaKeyGen', 1, 512, '', 17.82285), #BenchSpec('RsaKeyGen', 1, 512, '', 9.800225), #BenchSpec('RsaKeyGen', 1, 512, '', 8.215545), #BenchSpec('RsaKeyGen', 1, 512, '', 11.95486), #BenchSpec('RsaKeyGen', 1, 512, '', 6.170479), # #BenchSpec('RsaDecrypt', 8, 32, '', 3.906329), #BenchSpec('RsaDecrypt', 8, 32, '', 3.906904), #BenchSpec('RsaDecrypt', 8, 32, '', 3.907146), #BenchSpec('RsaDecrypt', 8, 32, '', 3.907072), #BenchSpec('RsaDecrypt', 8, 32, '', 3.906528), #BenchSpec('RsaDecrypt', 8, 32, '', 3.906117), #BenchSpec('RsaDecrypt', 8, 32, '', 3.904497), #BenchSpec('RsaDecrypt', 8, 32, '', 3.904088), #BenchSpec('RsaDecrypt', 8, 32, '', 3.907179), #BenchSpec('RsaDecrypt', 8, 32, '', 3.906088), # #BenchSpec('RsaEncrypt', 8, 32, '', 0.9219429), #BenchSpec('RsaEncrypt', 8, 32, '', 0.9286233), #BenchSpec('RsaEncrypt', 8, 32, '', 0.9285086), #BenchSpec('RsaEncrypt', 8, 32, '', 0.9285977), #BenchSpec('RsaEncrypt', 8, 32, '', 0.9280463), #BenchSpec('RsaEncrypt', 8, 32, '', 0.927805), #BenchSpec('RsaEncrypt', 8, 32, '', 0.9287491), #BenchSpec('RsaEncrypt', 8, 32, '', 0.9285343), #BenchSpec('RsaEncrypt', 8, 32, '', 0.9285265), #BenchSpec('RsaEncrypt', 8, 32, '', 0.9286342), # #BenchSpec('RsaKeyGen', 1, 1024, '', 327.0056), #BenchSpec('RsaDecrypt', 8, 64, '', 49.4005), #BenchSpec('RsaEncrypt', 8, 64, '', 2.30449), #BenchSpec('RsaDecrypt', 8, 64, '', 49.41412), #BenchSpec('RsaEncrypt', 8, 64, '', 2.304769), #BenchSpec('RsaDecrypt', 8, 64, '', 49.40992), #BenchSpec('RsaEncrypt', 8, 64, '', 2.304908), #BenchSpec('RsaDecrypt', 8, 64, '', 49.4192), #BenchSpec('RsaEncrypt', 8, 64, '', 2.305215), #BenchSpec('RsaDecrypt', 8, 64, '', 49.41233), #BenchSpec('RsaEncrypt', 8, 64, '', 2.304783), #BenchSpec('RsaDecrypt', 8, 64, '', 49.41201), #BenchSpec('RsaEncrypt', 8, 64, '', 2.304904), #BenchSpec('RsaDecrypt', 8, 64, '', 49.40812), #BenchSpec('RsaEncrypt', 8, 64, '', 2.306457), #BenchSpec('RsaDecrypt', 8, 64, '', 49.4155), #BenchSpec('RsaEncrypt', 8, 64, '', 2.305282), #BenchSpec('RsaDecrypt', 8, 64, '', 49.41673), #BenchSpec('RsaEncrypt', 8, 64, '', 2.304551), #BenchSpec('RsaDecrypt', 8, 64, '', 49.41605), #BenchSpec('RsaEncrypt', 8, 64, '', 2.304723), # ## After Add32_unrolled_8 optimization, setting MR to 8. #BenchSpec('RsaKeyGen-u', 4, 512, '', 80.74383), #BenchSpec('RsaKeyGen-u', 4, 512, '', 73.37518), #BenchSpec('RsaKeyGen-u', 4, 512, '', 58.45101), #BenchSpec('RsaKeyGen-u', 4, 512, '', 60.88408), #BenchSpec('RsaKeyGen-u', 4, 512, '', 64.99814), #BenchSpec('RsaKeyGen-u', 4, 512, '', 48.6908), #BenchSpec('RsaKeyGen-u', 4, 512, '', 35.17658), #BenchSpec('RsaKeyGen-u', 4, 512, '', 70.93044), #BenchSpec('RsaKeyGen-u', 4, 512, '', 88.05916), #BenchSpec('RsaKeyGen-u', 4, 1024, '', 592.9341), #BenchSpec('RsaKeyGen-u', 4, 1024, '', 1156.92), # #BenchSpec('RsaKeyGen-v', 4, 512, '', 203.6944), #BenchSpec('RsaKeyGen-v', 4, 512, '', 142.6029), #BenchSpec('RsaKeyGen-v', 4, 512, '', 328.2928), #BenchSpec('RsaKeyGen-v', 4, 512, '', 186.0192), #BenchSpec('RsaKeyGen-v', 4, 512, '', 178.2307), #BenchSpec('RsaKeyGen-v', 4, 512, '', 188.0875), #BenchSpec('RsaKeyGen-v', 4, 512, '', 181.3387), #BenchSpec('RsaKeyGen-v', 4, 512, '', 144.2986), #BenchSpec('RsaKeyGen-v', 4, 512, '', 306.3781), #BenchSpec('RsaKeyGen-v', 4, 512, '', 94.22977), #BenchSpec('RsaKeyGen-v', 4, 512, '', 208.8214), # #BenchSpec('RsaDecrypt-v', 8, 32, '', 8.302419), #BenchSpec('RsaEncrypt-v', 8, 32, '', 0.9127128), #BenchSpec('RsaDecrypt-v', 8, 32, '', 8.301742), #BenchSpec('RsaEncrypt-v', 8, 32, '', 0.9122038), #BenchSpec('RsaDecrypt-v', 8, 32, '', 8.302255), #BenchSpec('RsaEncrypt-v', 8, 32, '', 0.9126821), #BenchSpec('RsaDecrypt-v', 8, 32, '', 8.301459), #BenchSpec('RsaEncrypt-v', 8, 32, '', 0.9123324), #BenchSpec('RsaDecrypt-v', 8, 32, '', 8.301554), #BenchSpec('RsaEncrypt-v', 8, 32, '', 0.9124045), #BenchSpec('RsaDecrypt-v', 8, 32, '', 8.301258), #BenchSpec('RsaEncrypt-v', 8, 32, '', 0.9122229), #BenchSpec('RsaDecrypt-v', 8, 32, '', 8.302022), #BenchSpec('RsaEncrypt-v', 8, 32, '', 0.9121833), #BenchSpec('RsaDecrypt-v', 8, 32, '', 8.301646), #BenchSpec('RsaEncrypt-v', 8, 32, '', 0.912534), #BenchSpec('RsaDecrypt-v', 8, 32, '', 8.302246), #BenchSpec('RsaEncrypt-v', 8, 32, '', 0.9125597), #BenchSpec('RsaDecrypt-v', 8, 32, '', 8.301321), #BenchSpec('RsaEncrypt-v', 8, 32, '', 0.9054516), # #BenchSpec('RsaKeyGen-v', 1, 512, '', 36.56007), #BenchSpec('RsaDecrypt-v', 8, 32, 'key_size_bits=512', 8.084312), #BenchSpec('RsaEncrypt-v', 8, 32, 'key_size_bits=512', 0.9064715), #BenchSpec('RsaDecrypt-v', 8, 32, 'key_size_bits=512', 8.084259), #BenchSpec('RsaEncrypt-v', 8, 32, 'key_size_bits=512', 0.9062216), #BenchSpec('RsaDecrypt-v', 8, 32, 'key_size_bits=512', 8.084807), #BenchSpec('RsaEncrypt-v', 8, 32, 'key_size_bits=512', 0.9061556), #BenchSpec('RsaDecrypt-v', 8, 32, 'key_size_bits=512', 8.084284), #BenchSpec('RsaEncrypt-v', 8, 32, 'key_size_bits=512', 0.906733), #BenchSpec('RsaDecrypt-v', 8, 32, 'key_size_bits=512', 8.084139), #BenchSpec('RsaEncrypt-v', 8, 32, 'key_size_bits=512', 0.9060693), #BenchSpec('RsaDecrypt-v', 8, 32, 'key_size_bits=512', 8.084414), #BenchSpec('RsaEncrypt-v', 8, 32, 'key_size_bits=512', 0.9062116), #BenchSpec('RsaDecrypt-v', 8, 32, 'key_size_bits=512', 8.084597), #BenchSpec('RsaEncrypt-v', 8, 32, 'key_size_bits=512', 0.9064325), #BenchSpec('RsaDecrypt-v', 8, 32, 'key_size_bits=512', 8.084273), #BenchSpec('RsaEncrypt-v', 8, 32, 'key_size_bits=512', 0.8996112), #BenchSpec('RsaDecrypt-v', 8, 32, 'key_size_bits=512', 8.084738), #BenchSpec('RsaEncrypt-v', 8, 32, 'key_size_bits=512', 0.9063217), #BenchSpec('RsaDecrypt-v', 8, 32, 'key_size_bits=512', 8.0843), #BenchSpec('RsaEncrypt-v', 8, 32, 'key_size_bits=512', 0.9063667), # After enabling reciprocal estimator and fleetnatmul together (b3b8b0595701d467d8d7d432d673a8af9c3afb5f) #BenchSpec('RsaKeyGen', 1, 1024, 0, False, False, '', 12.13395), #BenchSpec('RsaDecrypt', 8, 1024, 64, False, False, 'key_size_bits=1024', 0.7093437), #BenchSpec('RsaEncrypt', 8, 1024, 64, False, False, 'key_size_bits=1024', 0.2144841), #BenchSpec('RsaDecrypt', 8, 1024, 64, False, False, 'key_size_bits=1024', 0.7089711), #BenchSpec('RsaEncrypt', 8, 1024, 64, False, False, 'key_size_bits=1024', 0.2206407), #BenchSpec('RsaDecrypt', 8, 1024, 64, False, False, 'key_size_bits=1024', 0.7149615), #BenchSpec('RsaEncrypt', 8, 1024, 64, False, False, 'key_size_bits=1024', 0.2142338), #BenchSpec('RsaDecrypt', 8, 1024, 64, False, False, 'key_size_bits=1024', 0.7045), #BenchSpec('RsaEncrypt', 8, 1024, 64, False, False, 'key_size_bits=1024', 0.2206872) # After enabling optimized assembly code for mul inner loop (725911c92ba3c3b54d9332c24fc50a26c8b2bdfe) BenchSpec('RsaKeyGen', 1, 1024, 0, False, False, '', 27.34745), BenchSpec('RsaDecrypt', 8, 1024, 64, False, False, 'key_size_bits=1024', 0.1813447), BenchSpec('RsaEncrypt', 8, 1024, 64, False, False, 'key_size_bits=1024', 0.2059516), BenchSpec('RsaDecrypt', 8, 1024, 64, False, False, 'key_size_bits=1024', 0.18114), BenchSpec('RsaEncrypt', 8, 1024, 64, False, False, 'key_size_bits=1024', 0.2123457), BenchSpec('RsaDecrypt', 8, 1024, 64, False, False, 'key_size_bits=1024', 0.1819137), BenchSpec('RsaEncrypt', 8, 1024, 64, False, False, 'key_size_bits=1024', 0.2059879), BenchSpec('RsaDecrypt', 8, 1024, 64, False, False, 'key_size_bits=1024', 0.1821488), BenchSpec('RsaEncrypt', 8, 1024, 64, False, False, 'key_size_bits=1024', 0.2059782), BenchSpec('RsaDecrypt', 8, 1024, 64, False, False, 'key_size_bits=1024', 0.1858502), BenchSpec('RsaEncrypt', 8, 1024, 64, False, False, 'key_size_bits=1024', 0.212652), BenchSpec('RsaDecrypt', 8, 1024, 64, False, False, 'key_size_bits=1024', 0.1829405), BenchSpec('RsaEncrypt', 8, 1024, 64, False, False, 'key_size_bits=1024', 0.2059838), BenchSpec('RsaDecrypt', 8, 1024, 64, False, False, 'key_size_bits=1024', 0.1820654), BenchSpec('RsaEncrypt', 8, 1024, 64, False, False, 'key_size_bits=1024', 0.2126007), BenchSpec('RsaDecrypt', 8, 1024, 64, False, False, 'key_size_bits=1024', 0.1808525), BenchSpec('RsaEncrypt', 8, 1024, 64, False, False, 'key_size_bits=1024', 0.2060691), BenchSpec('RsaDecrypt', 8, 1024, 64, False, False, 'key_size_bits=1024', 0.1799968), BenchSpec('RsaEncrypt', 8, 1024, 64, False, False, 'key_size_bits=1024', 0.2058071), BenchSpec('RsaDecrypt', 8, 1024, 64, False, False, 'key_size_bits=1024', 0.1813919), BenchSpec('RsaEncrypt', 8, 1024, 64, False, False, 'key_size_bits=1024', 0.2059153), ] def parse_openssl(label, text): data = [] # mo = re.compile("-DOPENSSL_(IA32_\S*)", re.MULTILINE).search(text) # config = mo.groups(0)[0] reob = re.compile("Doing (.*) for .*s on (.*) size blocks: (\S*) .*in (.*)s") for line in text.split("\n"): line = line.strip() mo = reob.search(line) if (mo!=None): benchmark,block_size,iterations,elapsed_time = mo.groups(0) data += [BenchSpec( "%s-%s" % (benchmark.capitalize(), label), int(iterations), int(block_size), float(elapsed_time))] return data data += parse_openssl("openssl-101g-noasm", """ jonh@bilbao:~/openssl-1.0.1g$ ./apps/openssl speed sha1 sha256 WARNING: can't open config file: /usr/local/ssl/openssl.cnf Doing sha1 for 3s on 16 size blocks: 2710384 sha1's in 3.00s Doing sha1 for 3s on 64 size blocks: 2021935 sha1's in 3.00s Doing sha1 for 3s on 256 size blocks: 1142245 sha1's in 3.00s Doing sha1 for 3s on 1024 size blocks: 417454 sha1's in 3.00s Doing sha1 for 3s on 8192 size blocks: 60375 sha1's in 3.00s Doing sha256 for 3s on 16 size blocks: 3497661 sha256's in 3.00s Doing sha256 for 3s on 64 size blocks: 2048970 sha256's in 3.00s Doing sha256 for 3s on 256 size blocks: 908001 sha256's in 3.00s Doing sha256 for 3s on 1024 size blocks: 282259 sha256's in 2.99s Doing sha256 for 3s on 8192 size blocks: 37976 sha256's in 3.00s OpenSSL 1.0.1g 7 Apr 2014 built on: Fri Apr 25 17:21:07 PDT 2014 options:bn(64,32) rc4(idx,int) des(ptr,risc1,16,long) aes(partial) idea(int) blowfish(idx) compiler: gcc -DOPENSSL_THREADS -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -DL_ENDIAN -DTERMIO -O3 -fomit-frame-pointer -Wall The 'numbers' are in 1000s of bytes per second processed. type 16 bytes 64 bytes 256 bytes 1024 bytes 8192 bytes sha1 14455.38k 43134.61k 97471.57k 142490.97k 164864.00k sha256 18654.19k 43711.36k 77482.75k 96666.63k 103699.80k """) data += parse_openssl("openssl-101g-sse2", """ jonh@bilbao:~/openssl-1.0.1g-sse2$ ./apps/openssl speed sha1 sha256 WARNING: can't open config file: /usr/local/ssl/openssl.cnf Doing sha1 for 3s on 16 size blocks: 4441307 sha1's in 3.00s Doing sha1 for 3s on 64 size blocks: 3619553 sha1's in 3.00s Doing sha1 for 3s on 256 size blocks: 2350814 sha1's in 3.00s Doing sha1 for 3s on 1024 size blocks: 977702 sha1's in 3.00s Doing sha1 for 3s on 8192 size blocks: 152203 sha1's in 3.00s Doing sha256 for 3s on 16 size blocks: 5747552 sha256's in 2.99s Doing sha256 for 3s on 64 size blocks: 3207098 sha256's in 3.00s Doing sha256 for 3s on 256 size blocks: 1355615 sha256's in 3.00s Doing sha256 for 3s on 1024 size blocks: 413892 sha256's in 3.00s Doing sha256 for 3s on 8192 size blocks: 55292 sha256's in 3.00s OpenSSL 1.0.1g 7 Apr 2014 built on: Fri Apr 25 17:32:19 PDT 2014 options:bn(64,32) rc4(8x,mmx) des(ptr,risc1,16,long) aes(partial) idea(int) blowfish(idx) compiler: gcc -DOPENSSL_THREADS -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -Wa,--noexecstack -DL_ENDIAN -DTERMIO -O3 -fomit-frame-pointer -Wall -DOPENSSL_BN_ASM_PART_WORDS -DOPENSSL_IA32_SSE2 -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_GF2m -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DMD5_ASM -DRMD160_ASM -DAES_ASM -DVPAES_ASM -DWHIRLPOOL_ASM -DGHASH_ASM The 'numbers' are in 1000s of bytes per second processed. type 16 bytes 64 bytes 256 bytes 1024 bytes 8192 bytes sha1 23686.97k 77217.13k 200602.79k 333722.28k 415615.66k sha256 30756.13k 68418.09k 115679.15k 141275.14k 150984.02k """) data += parse_openssl("polarssl-1.3.6-O2", """ jonh@bilbao:~/polarssl-speedtest$ ./polarssl-speedtest Doing sha1 for awhiles on 16 size blocks: 6000000 sha1's in 2.847s Doing sha1 for awhiles on 64 size blocks: 3500000 sha1's in 2.944s Doing sha1 for awhiles on 256 size blocks: 2000000 sha1's in 3.944s Doing sha1 for awhiles on 1024 size blocks: 500000 sha1's in 3.238s Doing sha1 for awhiles on 8192 size blocks: 70000 sha1's in 3.409s Doing sha256 for awhiles on 16 size blocks: 6000000 sha256's in 3.188s Doing sha256 for awhiles on 64 size blocks: 3500000 sha256's in 3.329s Doing sha256 for awhiles on 256 size blocks: 1500000 sha256's in 3.333s Doing sha256 for awhiles on 1024 size blocks: 400000 sha256's in 2.933s Doing sha256 for awhiles on 8192 size blocks: 50000 sha256's in 2.748s """) benchmarks = list(set(map(lambda b: b.benchmark, data))) benchmarks.sort() def Mean(benchmark, points): A = array(points) X = A[:,0] Y = A[:,1] print "%s @ x=%s" % (benchmark, X[0]) print " mean %f std %f (%.0f%%)" % ( mean(Y), std(Y), 100.0*std(Y)/mean(Y)) def Means(benchmark, points): A = array(points) X = A[:,0] Y = A[:,1] xs = list(set(X)) xs.sort() for x in xs: subpoints = filter(lambda p: p[0]==x, points) Mean(benchmark, subpoints) def LinearRegression(benchmark, points): A = array(points) X = A[:,0] Y = A[:,1] X1 = array([ X, ones(len(X)) ]) w = linalg.lstsq(X1.T,Y)[0] print benchmark print " %f ns s/B b=%f ns" % (w[0]*1e9, w[1]*1e9) #print w for benchmark in benchmarks: print "==>",benchmark points = map(lambda b: (b.message_length, b.elapsed_time/b.iterations), filter(lambda b: b.benchmark==benchmark, data)) if (benchmark.startswith("Sha")): LinearRegression(benchmark, points) else: Means(benchmark, points) ================================================ FILE: ironclad-apps/src/Clients/Benchmark/BenchmarkDriver.py ================================================ #!/usr/bin/python import subprocess import re from BenchSpec import * class HelpfulRE: def __init__(self, pattern): self.pattern = pattern self.reob = re.compile(pattern, re.MULTILINE) class BenchmarkDriver: def __init__(self): self.re_elapsed_time = HelpfulRE("^Elapsed Time.*: (.*)$") self.suite3() def regrab(self, text, re): mo = re.reob.search(text) if (mo==None): print text raise Exception("Failed to find %s" % re.pattern) return mo.groups(0)[0] def execute_test(self, spec): test_id = BenchmarkList[spec.benchmark] cmd = ["./BenchmarkRequestCmd/bin/Debug/BenchmarkRequestCmd.exe", SUT_IP, str(test_id), str(spec.iterations), str(spec.key_length), str(spec.message_length), str(1 if spec.use_words else 0), str(1 if spec.use_original else 0)] print "sending: %s" % (" ".join(cmd)) stdout_text = subprocess.check_output(cmd) result = self.parse_reply(stdout_text, spec.annotation) spec.elapsed_time = result print "spec :",spec def parse_reply(self, text, annotation): text = text.replace("\r", "") return float(self.regrab(text, self.re_elapsed_time)) def suite0(self): #for bench in ["Sha1", "Sha256","ByteSeqToWordSeq", "WordSeqToByteSeq"]: for bench in ["Sha256" ]: for block_size in [32768]: iterations=32768 self.execute_test(BenchSpec(bench, iterations, 0, block_size)) for reps in range(20): self.execute_test(BenchSpec("TpmExtractRandom", 1024, 1024)) def suite1(self): for loops in range(10): for block_size in (512,): self.execute_test(BenchSpec("RsaKeyGen", 4, block_size)) def suite2(self): for reps in range(20): self.execute_test(BenchSpec("TpmExtractRandom", 16, 1024)) def suite3(self): #for block_size in (32,64,128,256,512,1024,2048): #self.execute_test(BenchSpec("RsaKeyGen", 1, block_size)) # valid combinations: 512/32, 1024/64 # block_size := greatest power of two less than or equal to key_size_bits/8-12. key_size_bits = 1024 block_size_bytes = 64 # create a key to encrypt against. self.execute_test(BenchSpec("RsaKeyGen", 1, key_size_bits, 0)) for i in range(10): self.execute_test(BenchSpec("RsaDecrypt", 8, key_size_bits, block_size_bytes, annotation="key_size_bits=%s"%key_size_bits)) self.execute_test(BenchSpec("RsaEncrypt", 8, key_size_bits, block_size_bytes, annotation="key_size_bits=%s"%key_size_bits)) BenchmarkDriver() ================================================ FILE: ironclad-apps/src/Clients/Benchmark/BenchmarkRequestCmd/App.config ================================================ ================================================ FILE: ironclad-apps/src/Clients/Benchmark/BenchmarkRequestCmd/BenchmarkRequestCmd.csproj ================================================  Debug AnyCPU {AE099A52-1DB3-415A-AD29-2445711E7C1F} Exe Properties Ironclad.Benchmark BenchmarkRequestCmd v4.0 512 AnyCPU true full false bin\Debug\ DEBUG;TRACE prompt 4 AllRules.ruleset AnyCPU pdbonly true bin\Release\ TRACE prompt 4 {04c9f161-f1e7-4eee-b99e-417ce01a954b} Communication ================================================ FILE: ironclad-apps/src/Clients/Benchmark/BenchmarkRequestCmd/Program.cs ================================================ //-- //-- namespace Ironclad.Benchmark { using System; using Ironclad.Benchmark.Communication; / / / public static class Program { / / / private const ulong CpuSpeed = 2992273000; / / / / private static void Main(string[] args) { if (args.Length == 7) { using (Connection connection = new Connection(args[0])) { Request request = new Request(); UInt32 useWordsInt, useOriginalInt; if (byte.TryParse(args[1], out request.benchmark) && UInt32.TryParse(args[2], out request.iterations) && UInt32.TryParse(args[3], out request.keyLengthInBits) && UInt32.TryParse(args[4], out request.messageLengthInBits) && UInt32.TryParse(args[5], out useWordsInt) && UInt32.TryParse(args[6], out useOriginalInt)) { request.useWords = (useWordsInt != 0); request.useOriginal = (useOriginalInt != 0); } else { Usage(); } request.SendOnConnection(connection); Console.WriteLine("Request sent."); Response response = new Response(connection); if (response.Error != 0) { Console.WriteLine("Server returned error code 0x{0:x} ({0:d})", response.Error); } else { Console.WriteLine("Response received."); Console.WriteLine(); Console.WriteLine("Benchmark: {0:G}", response.Benchmark.ToString()); Console.WriteLine("Iterations performed: 0x{0:x}, ({0:d})", response.Iterations); Console.WriteLine("Key bits: 0x{0:x}, ({0:d})", response.keyLengthInBits); Console.WriteLine("Message length in bits: 0x{0:x}, ({0:d})", response.messageLengthInBits); Console.WriteLine("Use words: {0}", response.useWords); Console.WriteLine("Use original: {0}", response.useOriginal); Console.WriteLine("Begin Counter: 0x{0:x16}, ({0:d})", response.BeginCounter); Console.WriteLine("End Counter: 0x{0:x16}, ({0:d})", response.EndCounter); Console.WriteLine("Elapsed Counter: 0x{0:x16}, ({0:d})", response.ElapsedCounter); Console.WriteLine("Elapsed Time (in seconds, assuming a {0} Hertz CPU): {1}", Program.CpuSpeed, response.CalculateElapsedTime(Program.CpuSpeed)); } } } else { Usage(); } } / / / private static void Usage() { Console.WriteLine("Usage: BenchmarkRequestCmd "); Environment.Exit(1); } } } ================================================ FILE: ironclad-apps/src/Clients/Benchmark/BenchmarkRequestCmd/Properties/AssemblyInfo.cs ================================================ //-- //-- using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; [assembly: AssemblyTitle("BenchmarkRequestCmd")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("BenchmarkRequestCmd")] [assembly: AssemblyCopyright("Copyright © 2014")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] [assembly: Guid("de8c4517-c0ee-4905-a1bc-bc8aff0a0df7")] // // [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: ironclad-apps/src/Clients/Benchmark/BenchmarkRequestGui/App.config ================================================ ================================================ FILE: ironclad-apps/src/Clients/Benchmark/BenchmarkRequestGui/App.xaml ================================================  ================================================ FILE: ironclad-apps/src/Clients/Benchmark/BenchmarkRequestGui/App.xaml.cs ================================================ namespace BenchmarkRequestGui { using System; using System.Collections.Generic; using System.Configuration; using System.Data; using System.Linq; using System.Threading.Tasks; using System.Windows; / / / public partial class App : Application { } } ================================================ FILE: ironclad-apps/src/Clients/Benchmark/BenchmarkRequestGui/BenchmarkRequestGui.csproj ================================================  Debug AnyCPU {F6488513-9D8E-4064-BE53-F82606704ECA} WinExe Properties Ironclad.Benchmark BenchmarkRequestGui v4.0 512 {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 4 AnyCPU true full false bin\Debug\ DEBUG;TRACE prompt 4 AllRules.ruleset AnyCPU pdbonly true bin\Release\ TRACE prompt 4 4.0 MSBuild:Compile Designer MSBuild:Compile Designer App.xaml Code MainWindow.xaml Code Code True True Resources.resx True Settings.settings True ResXFileCodeGenerator Resources.Designer.cs SettingsSingleFileGenerator Settings.Designer.cs ================================================ FILE: ironclad-apps/src/Clients/Benchmark/BenchmarkRequestGui/MainWindow.xaml ================================================  ================================================ FILE: ironclad-apps/src/Clients/Benchmark/BenchmarkRequestGui/MainWindow.xaml.cs ================================================ namespace BenchmarkRequestGui { using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; / / / public partial class MainWindow : Window { public MainWindow() { this.InitializeComponent(); } } } ================================================ FILE: ironclad-apps/src/Clients/Benchmark/BenchmarkRequestGui/Properties/AssemblyInfo.cs ================================================ //-- //-- using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Windows; [assembly: AssemblyTitle("BenchmarkRequestGui")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("BenchmarkRequestGui")] [assembly: AssemblyCopyright("Copyright © 2014")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] // [assembly: ThemeInfo( ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly )] // // [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: ironclad-apps/src/Clients/Benchmark/BenchmarkRequestGui/Properties/Resources.Designer.cs ================================================ //------------------------------------------------------------------------------ // //------------------------------------------------------------------------------ namespace Ironclad.Benchmark.Properties { using System; / / / [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { private static global::System.Resources.ResourceManager resourceMan; private static global::System.Globalization.CultureInfo resourceCulture; [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] internal Resources() { } / / / [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] internal static global::System.Resources.ResourceManager ResourceManager { get { if (object.ReferenceEquals(resourceMan, null)) { global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Ironclad.Benchmark.Properties.Resources", typeof(Resources).Assembly); resourceMan = temp; } return resourceMan; } } / / / / [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] internal static global::System.Globalization.CultureInfo Culture { get { return resourceCulture; } set { resourceCulture = value; } } } } ================================================ FILE: ironclad-apps/src/Clients/Benchmark/BenchmarkRequestGui/Properties/Resources.resx ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 ================================================ FILE: ironclad-apps/src/Clients/Benchmark/BenchmarkRequestGui/Properties/Settings.Designer.cs ================================================ //------------------------------------------------------------------------------ // //------------------------------------------------------------------------------ namespace Ironclad.Benchmark.Properties { [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "12.0.0.0")] internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); public static Settings Default { get { return defaultInstance; } } } } ================================================ FILE: ironclad-apps/src/Clients/Benchmark/BenchmarkRequestGui/Properties/Settings.settings ================================================  ================================================ FILE: ironclad-apps/src/Clients/Benchmark/Communication/BenchmarkList.cs ================================================ //-- //-- namespace Ironclad.Benchmark.Communication { using System; / / / / / / / / public enum Benchmark { / / / Nothing = 0, / / / Sha1 = 1, / / / Sha256 = 2, / / / RsaKeyGen = 3, / / / RsaEncrypt = 4, / / / RsaDecrypt = 5, / / / RsaDigestedSign = 6, / / / RsaDigestedVerify = 7, / / / TpmExtractRandom = 8, / / / ByteSeqToWordSeq = 9, / / / WordSeqToByteSeq = 10, DuplicateArray = 13, / / / Max = 14, } } ================================================ FILE: ironclad-apps/src/Clients/Benchmark/Communication/Communication.csproj ================================================  Debug AnyCPU {04C9F161-F1E7-4EEE-B99E-417CE01A954B} Library Properties Ironclad.Benchmark.Communication Communication v4.0 512 true full false bin\Debug\ DEBUG;TRACE prompt 4 AllRules.ruleset pdbonly true bin\Release\ TRACE prompt 4 ================================================ FILE: ironclad-apps/src/Clients/Benchmark/Communication/Connection.cs ================================================ //-- //-- namespace Ironclad.Benchmark.Communication { using System; using System.Net; using System.Net.Sockets; using System.Text; / / / public class Connection : IDisposable { / / / private Socket socket; / / / private bool disposed = false; / / / / public Connection(string serverName) { this.socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); this.socket.Connect(serverName, 77); } / / / internal Socket Socket { get { return this.socket; } } / / / public void Dispose() { this.Dispose(true); GC.SuppressFinalize(this); } / / / / protected virtual void Dispose(bool disposing) { if (!this.disposed) { if (disposing) { this.socket.Dispose(); } this.disposed = true; } } } } ================================================ FILE: ironclad-apps/src/Clients/Benchmark/Communication/Properties/AssemblyInfo.cs ================================================ //-- //-- using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; [assembly: AssemblyTitle("Communication")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Communication")] [assembly: AssemblyCopyright("Copyright © 2014")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] [assembly: Guid("7aeeec60-c831-42a2-b90e-0cdb988ee4cc")] // // [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: ironclad-apps/src/Clients/Benchmark/Communication/Request.cs ================================================ //-- //-- namespace Ironclad.Benchmark.Communication { using System; using System.Net; using System.Net.Sockets; / / / public class Request { / / / public byte benchmark; / / / public UInt32 iterations; / / / public UInt32 keyLengthInBits; / / / public bool useWords; / / / public bool useOriginal; / / / public UInt32 messageLengthInBits; / / / public Request() { this.benchmark = 0; this.iterations = 0; this.keyLengthInBits = 0; this.useWords = false; this.useOriginal = false; this.messageLengthInBits = 0; } / / / public Benchmark Benchmark { get { return (Benchmark)this.benchmark; } set { this.benchmark = (byte)value; } } / / / / / public int SendOnConnection(Connection connection) { if (connection == null) { return 0; } byte[] buffer = new byte[15]; buffer[0] = this.benchmark; byte[] iterationsEncoded = Request.EncodeBEWord(this.iterations); iterationsEncoded.CopyTo(buffer, 1); byte[] keyLengthEncoded = Request.EncodeBEWord(this.keyLengthInBits); keyLengthEncoded.CopyTo(buffer, 5); byte[] messageLengthEncoded = Request.EncodeBEWord(this.messageLengthInBits); messageLengthEncoded.CopyTo(buffer, 9); buffer[13] = (byte)(this.useWords ? 1 : 0); buffer[14] = (byte)(this.useOriginal ? 1 : 0); return connection.Socket.Send(buffer); } private static byte[] EncodeBEWord(UInt32 value) { byte[] encoding = BitConverter.GetBytes(value); Array.Reverse(encoding); return encoding; } } } ================================================ FILE: ironclad-apps/src/Clients/Benchmark/Communication/Response.cs ================================================ using System.Linq; //-- //-- namespace Ironclad.Benchmark.Communication { using System; using System.Net; using System.Net.Sockets; / / / public class Response { / / / private byte error; / / / private Benchmark benchmark; / / / private UInt32 iterations; / / / public UInt32 keyLengthInBits; / / / public UInt32 messageLengthInBits; / / / public bool useWords; / / / public bool useOriginal; / / / private UInt64 beginCounter; / / / private UInt64 endCounter; / / / / public Response(Connection connection) { this.benchmark = Benchmark.Nothing; this.iterations = 0; this.keyLengthInBits = 0; this.messageLengthInBits = 0; this.useWords = false; this.useOriginal = false; if (connection == null) { this.error = 1; return; } byte[] buffer = new byte[1500]; int got = connection.Socket.Receive(buffer); if (got < 20) { this.error = 1; return; } #if false Console.WriteLine(); for (int loop = 0; loop < 20; loop++) { Console.Write("{0:x2} ", buffer[loop]); } Console.WriteLine(); #endif this.error = buffer[0]; if ((Benchmark)buffer[1] < Benchmark.Max) { this.benchmark = (Benchmark)buffer[1]; } else { this.error = 2; return; } this.iterations = Response.ExtractBEWord(buffer, 2); this.keyLengthInBits = Response.ExtractBEWord(buffer, 6); this.messageLengthInBits = Response.ExtractBEWord(buffer, 10); this.useWords = (buffer[14] != 0); this.useOriginal = (buffer[15] != 0); if (BitConverter.IsLittleEndian) { byte[] temp = ReverseByteOrder(buffer, 16, 8); this.beginCounter = BitConverter.ToUInt64(temp, 0); temp = ReverseByteOrder(buffer, 24, 8); this.endCounter = BitConverter.ToUInt64(temp, 0); } else { this.beginCounter = BitConverter.ToUInt64(buffer, 16); this.endCounter = BitConverter.ToUInt64(buffer, 24); } } / / / public byte Error { get { return this.error; } } / / / public Benchmark Benchmark { get { return this.benchmark; } } / / / public UInt32 Iterations { get { return this.iterations; } } / / / public UInt64 BeginCounter { get { return this.beginCounter; } } / / / public UInt64 EndCounter { get { return this.endCounter; } } / / / public UInt64 ElapsedCounter { get { return this.endCounter - this.beginCounter; } } / / / / / public float CalculateElapsedTime(UInt64 clockSpeedInHertz) { return (float)this.ElapsedCounter / (float)clockSpeedInHertz; } / / / / / / / private static byte[] ReverseByteOrder(byte[] input, int offset, int length) { byte[] output = new byte[length]; for (int index = 0; index < length; index++) { output[index] = input[offset + length - 1 - index]; } return output; } private static UInt32 ExtractBEWord(byte[] byteArray, int offset) { byte[] extractedBytes = byteArray.Skip(offset).Take(4).ToArray(); Array.Reverse(extractedBytes); return BitConverter.ToUInt32(extractedBytes, 0); } } } ================================================ FILE: ironclad-apps/src/Clients/Benchmark/TestEcho.py ================================================ #!/usr/bin/python import socket from BenchSpec import * UDP_PORT = 7 MESSAGE = "Hello, ironclad!" sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.sendto(MESSAGE, (SUT_IP, UDP_PORT)) print sock.recv(1024) ================================================ FILE: ironclad-apps/src/Clients/Benchmark/notes ================================================ 2014.04.25 values: Sha256 [ 2.68974487e-05 -7.74454427e-03] Sha1 [ 2.66306843e-05 -7.70144164e-03] ByteSeqToWordSeq [ 2.07652270e-05 -5.97859852e-03] WordSeqToByteSeq [ 4.18720193e-05 -1.29082713e-02] Y-intercepts are negative, likely nonsense stemming from larger block sizes running with fewer repetitions. slopes are 26-42us/byte. When arp rots: netsh interface ipv4 add neighbors "Ethernet 2" 10.10.10.20 00-1b-21-31-8e-d9 serial debug: /cygdrive/c/Program\ Files\ \(x86\)/raw/plink.exe -sercfg 115200,8,n,1 -serial com3 ================================================ FILE: ironclad-apps/src/Clients/Benchmark.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0.30110.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Communication", "Benchmark\Communication\Communication.csproj", "{04C9F161-F1E7-4EEE-B99E-417CE01A954B}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BenchmarkRequestCmd", "Benchmark\BenchmarkRequestCmd\BenchmarkRequestCmd.csproj", "{AE099A52-1DB3-415A-AD29-2445711E7C1F}" ProjectSection(ProjectDependencies) = postProject {04C9F161-F1E7-4EEE-B99E-417CE01A954B} = {04C9F161-F1E7-4EEE-B99E-417CE01A954B} EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BenchmarkRequestGui", "Benchmark\BenchmarkRequestGui\BenchmarkRequestGui.csproj", "{F6488513-9D8E-4064-BE53-F82606704ECA}" ProjectSection(ProjectDependencies) = postProject {04C9F161-F1E7-4EEE-B99E-417CE01A954B} = {04C9F161-F1E7-4EEE-B99E-417CE01A954B} EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {04C9F161-F1E7-4EEE-B99E-417CE01A954B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {04C9F161-F1E7-4EEE-B99E-417CE01A954B}.Debug|Any CPU.Build.0 = Debug|Any CPU {04C9F161-F1E7-4EEE-B99E-417CE01A954B}.Release|Any CPU.ActiveCfg = Release|Any CPU {04C9F161-F1E7-4EEE-B99E-417CE01A954B}.Release|Any CPU.Build.0 = Release|Any CPU {AE099A52-1DB3-415A-AD29-2445711E7C1F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {AE099A52-1DB3-415A-AD29-2445711E7C1F}.Debug|Any CPU.Build.0 = Debug|Any CPU {AE099A52-1DB3-415A-AD29-2445711E7C1F}.Release|Any CPU.ActiveCfg = Release|Any CPU {AE099A52-1DB3-415A-AD29-2445711E7C1F}.Release|Any CPU.Build.0 = Release|Any CPU {F6488513-9D8E-4064-BE53-F82606704ECA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F6488513-9D8E-4064-BE53-F82606704ECA}.Debug|Any CPU.Build.0 = Debug|Any CPU {F6488513-9D8E-4064-BE53-F82606704ECA}.Release|Any CPU.ActiveCfg = Release|Any CPU {F6488513-9D8E-4064-BE53-F82606704ECA}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: ironclad-apps/src/Clients/Clients.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2012 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Notary", "Notary\Notary.csproj", "{482B3A42-D9E8-4D48-9E44-27392205EDB0}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common", "Common\Common.csproj", "{5E394D90-C3D6-41A1-A6B4-715E43E54D7C}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TrInc", "TrInc\TrInc.csproj", "{EC3E5C90-B0FD-44CE-883C-1BA3FC896C02}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PassHash", "PassHash\PassHash.csproj", "{92AFE843-D88C-4A62-8159-B8C5EEDB5171}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DiffPriv", "DiffPriv\DiffPriv.csproj", "{9F8B6096-C335-433E-B00F-092D5CDF0CE1}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetSHABench", "DotNetSHABench\DotNetSHABench.csproj", "{4494E273-A2EF-4799-8D7E-C893C31D1362}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PassHashSrv", "PassHashSrv\PassHashSrv.csproj", "{49E13550-3EC8-4FCC-AE5D-CBD278A33B20}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NotarySrv", "NotarySrv\NotarySrv.csproj", "{9D47885D-EC02-4454-8D4C-B6BA048F7AF5}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TrIncSrv", "TrIncSrv\TrIncSrv.csproj", "{B99001E4-00B2-4A1B-A1D6-8B4773C0F5FB}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DiffPrivSrv", "DiffPrivSrv\DiffPrivSrv.csproj", "{29139FBF-8F54-41A3-B135-F9AFCA3714C1}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {482B3A42-D9E8-4D48-9E44-27392205EDB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {482B3A42-D9E8-4D48-9E44-27392205EDB0}.Debug|Any CPU.Build.0 = Debug|Any CPU {482B3A42-D9E8-4D48-9E44-27392205EDB0}.Release|Any CPU.ActiveCfg = Release|Any CPU {482B3A42-D9E8-4D48-9E44-27392205EDB0}.Release|Any CPU.Build.0 = Release|Any CPU {5E394D90-C3D6-41A1-A6B4-715E43E54D7C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5E394D90-C3D6-41A1-A6B4-715E43E54D7C}.Debug|Any CPU.Build.0 = Debug|Any CPU {5E394D90-C3D6-41A1-A6B4-715E43E54D7C}.Release|Any CPU.ActiveCfg = Release|Any CPU {5E394D90-C3D6-41A1-A6B4-715E43E54D7C}.Release|Any CPU.Build.0 = Release|Any CPU {EC3E5C90-B0FD-44CE-883C-1BA3FC896C02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {EC3E5C90-B0FD-44CE-883C-1BA3FC896C02}.Debug|Any CPU.Build.0 = Debug|Any CPU {EC3E5C90-B0FD-44CE-883C-1BA3FC896C02}.Release|Any CPU.ActiveCfg = Release|Any CPU {EC3E5C90-B0FD-44CE-883C-1BA3FC896C02}.Release|Any CPU.Build.0 = Release|Any CPU {92AFE843-D88C-4A62-8159-B8C5EEDB5171}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {92AFE843-D88C-4A62-8159-B8C5EEDB5171}.Debug|Any CPU.Build.0 = Debug|Any CPU {92AFE843-D88C-4A62-8159-B8C5EEDB5171}.Release|Any CPU.ActiveCfg = Release|Any CPU {92AFE843-D88C-4A62-8159-B8C5EEDB5171}.Release|Any CPU.Build.0 = Release|Any CPU {9F8B6096-C335-433E-B00F-092D5CDF0CE1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9F8B6096-C335-433E-B00F-092D5CDF0CE1}.Debug|Any CPU.Build.0 = Debug|Any CPU {9F8B6096-C335-433E-B00F-092D5CDF0CE1}.Release|Any CPU.ActiveCfg = Release|Any CPU {9F8B6096-C335-433E-B00F-092D5CDF0CE1}.Release|Any CPU.Build.0 = Release|Any CPU {4494E273-A2EF-4799-8D7E-C893C31D1362}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4494E273-A2EF-4799-8D7E-C893C31D1362}.Debug|Any CPU.Build.0 = Debug|Any CPU {4494E273-A2EF-4799-8D7E-C893C31D1362}.Release|Any CPU.ActiveCfg = Release|Any CPU {4494E273-A2EF-4799-8D7E-C893C31D1362}.Release|Any CPU.Build.0 = Release|Any CPU {49E13550-3EC8-4FCC-AE5D-CBD278A33B20}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {49E13550-3EC8-4FCC-AE5D-CBD278A33B20}.Debug|Any CPU.Build.0 = Debug|Any CPU {49E13550-3EC8-4FCC-AE5D-CBD278A33B20}.Release|Any CPU.ActiveCfg = Release|Any CPU {49E13550-3EC8-4FCC-AE5D-CBD278A33B20}.Release|Any CPU.Build.0 = Release|Any CPU {9D47885D-EC02-4454-8D4C-B6BA048F7AF5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9D47885D-EC02-4454-8D4C-B6BA048F7AF5}.Debug|Any CPU.Build.0 = Debug|Any CPU {9D47885D-EC02-4454-8D4C-B6BA048F7AF5}.Release|Any CPU.ActiveCfg = Release|Any CPU {9D47885D-EC02-4454-8D4C-B6BA048F7AF5}.Release|Any CPU.Build.0 = Release|Any CPU {B99001E4-00B2-4A1B-A1D6-8B4773C0F5FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B99001E4-00B2-4A1B-A1D6-8B4773C0F5FB}.Debug|Any CPU.Build.0 = Debug|Any CPU {B99001E4-00B2-4A1B-A1D6-8B4773C0F5FB}.Release|Any CPU.ActiveCfg = Release|Any CPU {B99001E4-00B2-4A1B-A1D6-8B4773C0F5FB}.Release|Any CPU.Build.0 = Release|Any CPU {29139FBF-8F54-41A3-B135-F9AFCA3714C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {29139FBF-8F54-41A3-B135-F9AFCA3714C1}.Debug|Any CPU.Build.0 = Debug|Any CPU {29139FBF-8F54-41A3-B135-F9AFCA3714C1}.Release|Any CPU.ActiveCfg = Release|Any CPU {29139FBF-8F54-41A3-B135-F9AFCA3714C1}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: ironclad-apps/src/Clients/Common/Common.cs ================================================ using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Net; using System.Net.Sockets; using System.Numerics; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; namespace Common { public class ErrorCodeException : Exception { private UInt32 error_code; public ErrorCodeException(UInt32 i_error_code) { error_code = i_error_code; } public override string ToString() { return string.Format("Error code {0}", error_code); } } public class InvalidRequest { public InvalidRequest() { } } public class InvalidResponse { public InvalidResponse() { } public static byte[] Encode() { byte[] response = new byte[1]; response[0] = 0; return response; } } public class CommonRoutines { public static UInt32 ExtractBEWord(byte[] byteArray, int offset) { byte[] extractedBytes = byteArray.Skip(offset).Take(4).ToArray(); Array.Reverse(extractedBytes); return BitConverter.ToUInt32(extractedBytes, 0); } public static byte[] EncodeBEWord(UInt32 value) { byte[] encoding = BitConverter.GetBytes(value); Array.Reverse(encoding); return encoding; } public static byte[] EncodeMPInt(UInt32 value) { Stack encoding = new Stack(); while (value > 0) { encoding.Push((byte)(value % 256)); value = value / 256; } if (encoding.Count != 0 && encoding.Peek() >= 128) { encoding.Push((byte) 0); } byte[] length_encoded = EncodeBEWord((uint)encoding.Count); byte[] encoding_bytes = encoding.ToArray(); return CombineByteArrays(length_encoded, encoding_bytes); } public static byte[] EncodeMPBigInteger(BigInteger value) { byte[] rawEncoding = value.ToByteArray(); Array.Reverse(rawEncoding); byte[] lengthEncoded = EncodeBEWord((uint)rawEncoding.Length); return CombineByteArrays(lengthEncoded, rawEncoding); } public static UInt32 DecodeShortMPInt(byte[] byteArray, ref int offset) { if (byteArray.Length < offset + 4) { throw new Exception("Byte array too short to decode the length of an MPInt from"); } int value_length = (int)ExtractBEWord(byteArray, offset); if (byteArray.Length < offset + 4 + value_length) { throw new Exception("Byte array too short to decode an MPInt from"); } byte[] value_encoded = byteArray.Skip(offset + 4).Take(value_length).ToArray(); UInt32 value = 0; for (int pos = 0; pos < value_encoded.Length; ++pos) { value = value * 256 + value_encoded[pos]; } offset = offset + 4 + value_length; return value; } public static BigInteger DecodeMPBigInteger(byte[] byteArray, ref int offset) { if (byteArray.Length < offset + 4) { return new BigInteger(-1); } int value_length = (int)ExtractBEWord(byteArray, offset); if (byteArray.Length < offset + 4 + value_length) { return new BigInteger(-1); } byte[] value_encoded = byteArray.Skip(offset + 4).Take(value_length).ToArray(); Array.Reverse(value_encoded); offset = offset + 4 + value_length; return new BigInteger(value_encoded); } public static byte[] StripProtectiveZero(byte[] mpi) { if (0 < mpi[0] && mpi[0] < 128) { return mpi; } else { return mpi.Skip(1).ToArray(); } } public static RSACryptoServiceProvider DecodePublicKey(byte[] encoded_public_key) { int header_length = (int)ExtractBEWord(encoded_public_key, 0); if (header_length != 7) { Console.WriteLine("Header of encoded public key has invalid length {0} != 7", header_length); throw new Exception("Header of encoded public key has invalid length"); } System.Text.UTF8Encoding encoder = new System.Text.UTF8Encoding(); string header = encoder.GetString(encoded_public_key.Skip(4).Take(header_length).ToArray()); if (header != "ssh-rsa") { Console.WriteLine("Header of encoded public key is {0}, not ssh-rsa", header); throw new Exception("Header of encoded public key is not ssh-rsa"); } int exponent_length = (int)ExtractBEWord(encoded_public_key, 4 + header_length); if (encoded_public_key.Length < 4 + header_length + 4 + exponent_length + 4) { Console.WriteLine("Encoded public key not long enough to hold exponent of length {0}", exponent_length); throw new Exception("Encoded public key not long enough to hold exponent"); } byte[] exponent = encoded_public_key.Skip(4 + header_length + 4).Take(exponent_length).ToArray(); int modulus_length = (int)ExtractBEWord(encoded_public_key, 4 + header_length + 4 + exponent_length); if (encoded_public_key.Length < 4 + header_length + 4 + exponent_length + 4 + modulus_length) { Console.WriteLine("Encoded public key not long enough to hold modulus of length {0}", modulus_length); throw new Exception("Encoded public key not long enough to hold modulus"); } byte[] modulus = encoded_public_key.Skip(4 + header_length + 4 + exponent_length + 4).Take(modulus_length).ToArray(); modulus = StripProtectiveZero(modulus); RSACryptoServiceProvider provider = new RSACryptoServiceProvider(); RSAParameters info = new RSAParameters(); info.Exponent = exponent; info.Modulus = modulus; try { provider.ImportParameters(info); } catch { if (CommonParams.ignoreKey) { return null; } else { throw; } } return provider; } public static byte[] ParseFakeReply(string pastedhex) { string[] hexwords = pastedhex.Split(' '); int offset = 0x2a; byte[] output = new byte[hexwords.Length-offset]; for (int i = offset; i < hexwords.Length; i++) { output[i-offset] = Convert.ToByte(hexwords[i], 16); } return output; } static public void WriteHexArray(StreamWriter sw, byte[] bytes, string label) { sw.WriteLine(" var "+label+" = ["); for (int i=0; i a.Length)]; int offset = 0; foreach (byte[] array in arrays) { System.Buffer.BlockCopy(array, 0, rv, offset, array.Length); offset += array.Length; } return rv; } public static byte[] mpint_encode(byte[] raw) { int i; for (i = 0; i < raw.Length-1; i++) { if (raw[i] != 0) { break; } } raw = raw.Skip(i).ToArray(); if (raw[0]>=0x80) { byte[] zero = new byte[1]; zero[0] = 0; raw = CombineByteArrays(zero, raw); } byte[] length = EncodeBEWord((UInt32)raw.Length); return CombineByteArrays(length, raw); } public static byte[] EncodePublicKey (RSACryptoServiceProvider key_pair) { RSAParameters rsa_params = key_pair.ExportParameters(false); byte[] header = new System.Text.UTF8Encoding().GetBytes("ssh-rsa"); byte[] header_length = EncodeBEWord((UInt32)header.Length); byte[] exponent_encoded = mpint_encode(rsa_params.Exponent); byte[] modulus_encoded = mpint_encode(rsa_params.Modulus); return CombineByteArrays(header_length, header, exponent_encoded, modulus_encoded); } public static UInt32[] BEByteSeqToWordSeq(byte[] bytes) { int num_words = bytes.Length / 4; UInt32[] words = new UInt32[num_words]; for (int i = 0; i < num_words; ++i) { words[i] = ((UInt32)bytes[i * 4] << 24) + ((UInt32)bytes[i * 4 + 1] << 16) + ((UInt32)bytes[i * 4 + 2] << 8) + (UInt32)bytes[i * 4 + 3]; } return words; } public static IPEndPoint GetIPEndPoint(string hostname, int port) { IPHostEntry hostEntry = Dns.GetHostEntry(hostname); foreach (IPAddress addr in hostEntry.AddressList) { if (addr.AddressFamily == AddressFamily.InterNetwork) { IPEndPoint ep = new IPEndPoint(addr, port); return ep; } } Console.Error.WriteLine("Could not find address for host name {0}", CommonParams.hostname); throw new Exception("Could not find address for host name"); } public static UdpClient StartClient() { IPEndPoint serverEp = new IPEndPoint(IPAddress.Parse(CommonParams.hostname), CommonParams.port); UdpClient client = new UdpClient(); client.Connect(serverEp); return client; } public static UdpClient StartServer() { IPEndPoint ep = new IPEndPoint(IPAddress.Parse(CommonParams.hostname), CommonParams.port); UdpClient server = new UdpClient(ep); return server; } } } ================================================ FILE: ironclad-apps/src/Clients/Common/Common.csproj ================================================  Debug AnyCPU {5E394D90-C3D6-41A1-A6B4-715E43E54D7C} Library Properties Common Common v4.5 512 true full false bin\Debug\ DEBUG;TRACE prompt 4 pdbonly true bin\Release\ TRACE prompt 4 ================================================ FILE: ironclad-apps/src/Clients/Common/CommonParams.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Common { public class CommonParams { public static string hostname = "localhost"; public static int port = 1983; public static int numberOfRuns = 105; public static bool ignoreKey = false; public static string loaderHash = "6768033E216468247BD031A0A2D9876D79818F8F"; public static string appHash = ""; public static int serverKeyBits = 2048; public static bool printValues = true; public static void Print() { Console.Error.WriteLine("hostname\t{0}", hostname); Console.Error.WriteLine("port\t{0}", port); Console.Error.WriteLine("numberOfRuns\t{0}", numberOfRuns); Console.Error.WriteLine("ignoreKey\t{0}", ignoreKey); Console.Error.WriteLine("loaderHash\t{0}", loaderHash); Console.Error.WriteLine("appHash\t{0}", appHash); Console.Error.WriteLine("serverKeyBits\t{0}", serverKeyBits); Console.Error.WriteLine("printValues\t{0}", printValues); } public static void PrintUsage() { Console.Out.WriteLine(" hostname = host name of the TrInc service"); Console.Out.WriteLine(" port = port that the TrInc service listens to"); Console.Out.WriteLine(" numberOfRuns = number of times to run each benchmark"); Console.Out.WriteLine(" ignoreKey = 1 means ignore the public key and don't do any checking using it"); Console.Out.WriteLine(" loaderHash = hex value of SHA-1 of loader, e.g., 01EF..23CD"); Console.Out.WriteLine(" appHash = hex value of SHA-1 of app, e.g., 01EF..23CD"); Console.Out.WriteLine(" serverKeyBits = number of bits for server key"); Console.Out.WriteLine(" printValues = 1 means print all profile values, 0 means just print aggregates"); } public static bool ApplyArgument (string parameter, string value) { if (String.Compare(parameter, "hostname", StringComparison.OrdinalIgnoreCase) == 0) { CommonParams.hostname = value; return true; } if (String.Compare(parameter, "port", StringComparison.OrdinalIgnoreCase) == 0) { CommonParams.port = Convert.ToInt32(value); return true; } if (String.Compare(parameter, "numberOfRuns", StringComparison.OrdinalIgnoreCase) == 0) { CommonParams.numberOfRuns = Convert.ToInt32(value); return true; } if (String.Compare(parameter, "ignoreKey", StringComparison.OrdinalIgnoreCase) == 0) { CommonParams.ignoreKey = (Convert.ToInt32(value) != 0); return true; } if (String.Compare(parameter, "loaderHash", StringComparison.OrdinalIgnoreCase) == 0) { CommonParams.loaderHash = value; return true; } if (String.Compare(parameter, "appHash", StringComparison.OrdinalIgnoreCase) == 0) { CommonParams.appHash = value; return true; } if (String.Compare(parameter, "serverKeyBits", StringComparison.OrdinalIgnoreCase) == 0) { CommonParams.serverKeyBits = Convert.ToInt32(value); return true; } if (String.Compare(parameter, "printValues", StringComparison.OrdinalIgnoreCase) == 0) { CommonParams.printValues = (Convert.ToInt32(value) != 0); return true; } return false; } } } ================================================ FILE: ironclad-apps/src/Clients/Common/GetQuote.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; namespace Common { public class GetQuoteRequest { private byte[] nonce; public GetQuoteRequest() { Random rng = new Random(); nonce = new byte[20]; rng.NextBytes(nonce); } public GetQuoteRequest(byte[] i_nonce) { nonce = i_nonce; } public byte[] GetPacket() { Random rng = new Random(); byte[] packet = new byte[21]; packet[0] = 1; nonce.CopyTo(packet, 1); return packet; } public static object ParseRequest (byte[] packet) { if (packet.Length < 21) { Console.Error.WriteLine("Received get-quote request with fewer than 21 bytes"); return new InvalidRequest(); } byte[] nonce = packet.Skip(1).Take(20).ToArray(); return new GetQuoteRequest(nonce); } } public class GetQuoteResponse { private UInt32 error_code; private RSACryptoServiceProvider public_key; private byte[] pcr_info; private byte[] sig; public RSACryptoServiceProvider PublicKey { get { return public_key; } } public GetQuoteResponse(byte[] packet) { if (packet.Length < 17) { throw new Exception("Invalid GetQuoteResponse packet -- length < 17"); } if (packet[0] != 1) { throw new Exception("First byte of GetQuoteResponse is not 1"); } error_code = CommonRoutines.ExtractBEWord(packet, 1); if (error_code != 0) { throw new ErrorCodeException(error_code); } int encoded_public_key_length = (int)CommonRoutines.ExtractBEWord(packet, 5); int pcr_info_bytes_length = (int)CommonRoutines.ExtractBEWord(packet, 9); int sig_bytes_length = (int)CommonRoutines.ExtractBEWord(packet, 13); if (packet.Length < 17 + encoded_public_key_length + pcr_info_bytes_length + sig_bytes_length) { throw new Exception("Invalid GetQuoteResponse packet -- length not big enough"); } byte[] encoded_public_key = packet.Skip(17).Take(encoded_public_key_length).ToArray(); pcr_info = packet.Skip(17 + encoded_public_key_length).Take(pcr_info_bytes_length).ToArray(); sig = packet.Skip(17 + encoded_public_key_length + pcr_info_bytes_length).Take(sig_bytes_length).ToArray(); CheckPCRInfo(pcr_info, encoded_public_key); public_key = CommonRoutines.DecodePublicKey(encoded_public_key); } public GetQuoteResponse (UInt32 i_error_code, RSACryptoServiceProvider i_public_key) { error_code = i_error_code; public_key = i_public_key; pcr_info = new byte[25]; pcr_info[0] = 0; pcr_info[1] = 3; pcr_info[2] = 0; pcr_info[3] = 0; pcr_info[4] = 14; if (CommonParams.loaderHash.Length == 40 && CommonParams.appHash.Length == 40) { SHA1Managed hasher = new SHA1Managed(); byte[] encoded_public_key = CommonRoutines.EncodePublicKey(public_key); byte[] pcr17 = GetExpectedPCR17(); byte[] pcr18 = GetZeroPCR(); byte[] pcr19 = GetExpectedPCR19(hasher, encoded_public_key); byte[] tpm_pcr_composite = CommonRoutines.CombineByteArrays(pcr_info.Take(5).ToArray(), BitConverter.GetBytes((UInt32)60), pcr17, pcr18, pcr19); byte[] h1 = hasher.ComputeHash(tpm_pcr_composite); Array.Copy(h1, 0, pcr_info, 5, 20); } sig = new byte[1]; sig[0] = 0; } public override string ToString() { return string.Format("GetQuoteResponse(error_code={0}, public_key={1}, pcr_info={2}, sig={3})", error_code, public_key, pcr_info, sig); } private byte[] GetZeroPCR() { byte[] values = new byte[20]; for (int i = 0; i < 20; ++i) { values[i] = 0; } return values; } private byte[] ExtendPCR(SHA1Managed hasher, byte[] currentValue, byte[] valueToExtendBy) { return hasher.ComputeHash(CommonRoutines.CombineByteArrays(currentValue, valueToExtendBy)); } private byte[] ConvertHexStringToByteArray(string hex) { int num_bytes = hex.Length / 2; byte[] arr = new byte[num_bytes]; for (int i = 0; i < num_bytes; ++i) { arr[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16); } return arr; } private byte[] GetExpectedPCR17() { return ConvertHexStringToByteArray(CommonParams.loaderHash); } private byte[] GetExpectedPCR19(SHA1Managed hasher, byte[] encoded_public_key) { byte[] pcr = GetZeroPCR(); pcr = ExtendPCR(hasher, pcr, ConvertHexStringToByteArray(CommonParams.appHash)); pcr = ExtendPCR(hasher, pcr, hasher.ComputeHash(encoded_public_key)); return pcr; } private void CheckPCRInfo(byte[] pcr_info, byte[] encoded_public_key) { if (pcr_info[0] != 0 || pcr_info[1] != 3 || pcr_info[2] != 0 || pcr_info[3] != 0 || pcr_info[4] != 14) { throw new Exception("Invalid PCR selection in PCR info"); } if (CommonParams.loaderHash.Length != 40 || CommonParams.appHash.Length != 40) { Console.Error.WriteLine("Skipping TPM composite hash check because loader hash and app hash weren't supplied"); return; } SHA1Managed hasher = new SHA1Managed(); byte[] pcr17 = GetExpectedPCR17(); byte[] pcr18 = GetZeroPCR(); byte[] pcr19 = GetExpectedPCR19(hasher, encoded_public_key); byte[] tpm_pcr_composite = CommonRoutines.CombineByteArrays(pcr_info.Take(5).ToArray(), BitConverter.GetBytes((UInt32)60), pcr17, pcr18, pcr19); byte[] h1 = hasher.ComputeHash(tpm_pcr_composite); byte[] received_h1 = pcr_info.Skip(5).Take(20).ToArray(); if (!h1.SequenceEqual(received_h1)) { throw new Exception("Composite hash in received PCR info not what was expected"); } } public byte[] Encode () { byte[] header = new byte[1]; header[0] = 1; byte[] error_code = CommonRoutines.EncodeBEWord(0); byte[] encoded_public_key = CommonRoutines.EncodePublicKey(public_key); byte[] encoded_public_key_length = CommonRoutines.EncodeBEWord((uint)encoded_public_key.Length); byte[] pcr_info_length = CommonRoutines.EncodeBEWord((uint)pcr_info.Length); byte[] sig_length = CommonRoutines.EncodeBEWord((uint)sig.Length); return CommonRoutines.CombineByteArrays(header, error_code, encoded_public_key_length, pcr_info_length, sig_length, encoded_public_key, pcr_info, sig); } } } ================================================ FILE: ironclad-apps/src/Clients/Common/Profiler.cs ================================================ using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Web.UI.DataVisualization.Charting; namespace Common { public class Aggregator { private static Chart chart; private string name; private bool times; private long total; private int count; private double sumsq; public static void Initialize() { chart = new Chart(); } public Aggregator(string i_name, bool i_times) { name = i_name; times = i_times; total = 0; count = 0; sumsq = 0; } public void AddValue(long value) { if (CommonParams.printValues) { Console.WriteLine("{0}\t{1}", name, value * 1.0 / Stopwatch.Frequency); } total += value; count++; sumsq += (value * 1.0 * value); } public void AddTime(Stopwatch s) { AddValue(s.ElapsedTicks); } public override string ToString() { if (count < 1) { return name + ": "; } if (times) { double total_sec = total * 1.0 / Stopwatch.Frequency; if (count == 1) { return name + ": " + total_sec.ToString(); } double average_sec = total_sec / count; double sumsq_sec = sumsq / Stopwatch.Frequency / Stopwatch.Frequency; double variance = (sumsq_sec - total_sec * total_sec / count) / (count - 1); double stdev = Math.Sqrt(variance); double conf95 = stdev * chart.DataManipulator.Statistics.InverseTDistribution(0.05, count-1) / Math.Sqrt(count); return string.Format("{0}: avg_sec {1} conf95plusorminus {2} stdev {3}", name, average_sec, conf95, stdev); } else { if (count == 1) { return total.ToString(); } double average = total * 1.0 / count; double variance = (sumsq - (total * 1.0 * total) / count) / (count - 1); double stdev = Math.Sqrt(variance); double conf95 = stdev * chart.DataManipulator.Statistics.InverseTDistribution(0.05, count-1) / Math.Sqrt(count); return string.Format("{0}: avg {1} conf95plusorminus {2} stdev {3}", name, average, conf95, stdev); } } } public class Profiler { static Dictionary aggregators; public static void Initialize() { aggregators = new Dictionary(); Aggregator.Initialize(); } public static void Record(string name, long value) { if (!aggregators.ContainsKey(name)) { aggregators[name] = new Aggregator(name, false); } aggregators[name].AddValue(value); } public static void Record(string name, Stopwatch stopwatch) { if (!aggregators.ContainsKey(name)) { aggregators[name] = new Aggregator(name, true); } aggregators[name].AddValue(stopwatch.ElapsedTicks); } public static void Print() { foreach (KeyValuePair entry in aggregators) { Console.WriteLine(entry.Value.ToString()); } } } } ================================================ FILE: ironclad-apps/src/Clients/Common/Properties/AssemblyInfo.cs ================================================ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; [assembly: AssemblyTitle("Common")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Common")] [assembly: AssemblyCopyright("Copyright © 2014")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] [assembly: Guid("50f794c5-efb1-4501-9fdb-81ece815247d")] // // [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: ironclad-apps/src/Clients/DiffPriv/App.config ================================================  ================================================ FILE: ironclad-apps/src/Clients/DiffPriv/DiffPriv.csproj ================================================  Debug AnyCPU {9F8B6096-C335-433E-B00F-092D5CDF0CE1} Exe Properties DiffPriv DiffPriv v4.5 512 AnyCPU true full false bin\Debug\ DEBUG;TRACE prompt 4 AnyCPU pdbonly true bin\Release\ TRACE prompt 4 {5e394d90-c3d6-41a1-a6b4-715e43e54d7c} Common ================================================ FILE: ironclad-apps/src/Clients/DiffPriv/DiffPrivRequests.cs ================================================ using Common; using System; using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; namespace DiffPriv { public class InitializeDBRequest { private Rational budget; public InitializeDBRequest(Rational i_budget) { budget = i_budget; } public byte[] GetPacket() { byte[] header = new byte[1]; header[0] = 2; byte[] encoded_budget_num = CommonRoutines.EncodeBEWord(budget.num); byte[] encoded_budget_den = CommonRoutines.EncodeBEWord(budget.den); return CommonRoutines.CombineByteArrays(header, encoded_budget_num, encoded_budget_den); } } public class AddRowRequest { private UInt32[] values; private Rational max_budget; private byte[] nonce; public AddRowRequest(UInt32[] i_values, Rational i_max_budget, Random rng) { values = i_values; max_budget = i_max_budget; nonce = new byte[Parameters.nonceBytes]; rng.NextBytes(nonce); } public byte[] GetPacket(RSACryptoServiceProvider ironclad_public_key) { byte[] header = new byte[1]; header[0] = 3; byte[] row_nonce_size_encoded = CommonRoutines.EncodeBEWord((UInt32)nonce.Length); byte[] row_data_size_encoded = CommonRoutines.EncodeBEWord((UInt32)values.Length * 4); byte[] max_budget_num_encoded = CommonRoutines.EncodeBEWord(max_budget.num); byte[] max_budget_den_encoded = CommonRoutines.EncodeBEWord(max_budget.den); byte[] row_encoded = new byte[values.Length*4]; for (int i = 0; i < values.Length; ++i) { byte[] value_encoded = CommonRoutines.EncodeBEWord(values[i]); value_encoded.CopyTo(row_encoded, i * 4); } byte[] plaintext = CommonRoutines.CombineByteArrays( row_nonce_size_encoded, row_data_size_encoded, max_budget_num_encoded, max_budget_den_encoded, nonce, row_encoded); byte[] encrypted = ironclad_public_key.Encrypt(plaintext, false); return CommonRoutines.CombineByteArrays(header, encrypted); } } public class QueryRequest { private UInt32 row_min; private UInt32 row_max; private UInt32 answer_units; private UInt32 answer_min; private UInt32 answer_max; private Rational alpha; private Rational beta; private UInt32[] program; public QueryRequest(UInt32 i_row_min, UInt32 i_row_max, UInt32 i_answer_units, UInt32 i_answer_min, UInt32 i_answer_max, Rational i_alpha, Rational i_beta, UInt32[] i_program) { row_min = i_row_min; row_max = i_row_max; answer_units = i_answer_units; answer_min = i_answer_min; answer_max = i_answer_max; alpha = i_alpha; beta = i_beta; program = i_program; } public byte[] GetPacket() { byte[] header = new byte[1]; header[0] = 4; byte[] program_size_encoded = CommonRoutines.EncodeBEWord((UInt32)program.Length * 4); byte[] row_min_encoded = CommonRoutines.EncodeBEWord(row_min); byte[] row_max_encoded = CommonRoutines.EncodeBEWord(row_max); byte[] answer_units_encoded = CommonRoutines.EncodeBEWord(answer_units); byte[] answer_min_encoded = CommonRoutines.EncodeBEWord(answer_min); byte[] answer_max_encoded = CommonRoutines.EncodeBEWord(answer_max); byte[] alpha_num_encoded = CommonRoutines.EncodeBEWord(alpha.num); byte[] alpha_den_encoded = CommonRoutines.EncodeBEWord(alpha.den); byte[] beta_num_encoded = CommonRoutines.EncodeBEWord(beta.num); byte[] beta_den_encoded = CommonRoutines.EncodeBEWord(beta.den); byte[] program_encoded = new byte[program.Length*4]; for (int i = 0; i < program.Length; ++i) { byte[] instruction_encoded = CommonRoutines.EncodeBEWord(program[i]); instruction_encoded.CopyTo(program_encoded, i * 4); } return CommonRoutines.CombineByteArrays(header, program_size_encoded, row_min_encoded, row_max_encoded, answer_units_encoded, answer_min_encoded, answer_max_encoded, alpha_num_encoded, alpha_den_encoded, beta_num_encoded, beta_den_encoded, program_encoded); } } } ================================================ FILE: ironclad-apps/src/Clients/DiffPriv/DiffPrivResponses.cs ================================================ using Common; using System; using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; namespace DiffPriv { class InitializeDBResponse { private UInt32 error_code; public UInt32 ErrorCode { get { return error_code; } } public InitializeDBResponse(byte[] packet) { if (packet.Length < 5) { throw new Exception("Invalid InitializeDBResponse packet -- length < 5"); } if (packet[0] != 2) { throw new Exception("First byte of InitializeDBResponse packet is not 2"); } error_code = CommonRoutines.ExtractBEWord(packet, 1); if (error_code != 0) { throw new ErrorCodeException(error_code); } } public override string ToString() { return string.Format("InitializeDBResponse(error_code={0})", error_code); } } class AddRowResponse { public AddRowResponse(byte[] packet) { if (packet.Length < 1) { throw new Exception("Invalid AddRowResponse packet -- length < 5"); } if (packet[0] != 3) { throw new Exception("First byte of AddRowResponse packet is not 3"); } } public override string ToString() { return string.Format("AddRowResponse()"); } } class QueryResponse { private UInt32 error_code; private UInt32 response_value; public UInt32 ErrorCode { get { return error_code; } } public UInt32 ResponseValue { get { return response_value; } } public QueryResponse(byte[] packet) { if (packet.Length < 9) { throw new Exception("Invalid QueryResponse packet -- length < 9"); } if (packet[0] != 4) { throw new Exception("First byte of QueryResponse packet is not 4"); } error_code = CommonRoutines.ExtractBEWord(packet, 1); if (error_code != 0) { throw new ErrorCodeException(error_code); } response_value = CommonRoutines.ExtractBEWord(packet, 5); } public override string ToString() { return string.Format("QueryResponse(error_code={0})", error_code); } } } ================================================ FILE: ironclad-apps/src/Clients/DiffPriv/Parameters.cs ================================================ using Common; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DiffPriv { class InvalidParameterException : Exception { public string contents; public InvalidParameterException(string i_contents) { contents = i_contents; } } public class Parameters { public static int numColumns = 4; public static int maxColumnValue = 2048; public static int numRows = 105; public static int numQueries = 105; public static int nonceBytes = 20; public static void Print() { CommonParams.Print(); Console.Error.WriteLine("numColumns\t{0}", numColumns); Console.Error.WriteLine("maxColumnValue\t{0}", maxColumnValue); Console.Error.WriteLine("numRows\t{0}", numRows); Console.Error.WriteLine("numQueries\t{0}", numQueries); Console.Error.WriteLine("nonceBytes\t{0}", nonceBytes); } public static void PrintUsage() { Console.Out.WriteLine("Usage: DiffPriv.exe [filename or param=value]... where filename contains"); Console.Out.WriteLine(" lines of the form param=value and param must be one of the following."); Console.Out.WriteLine(); CommonParams.PrintUsage(); Console.Out.WriteLine(" numColumns = number of columns in each row"); Console.Out.WriteLine(" maxColumnValue = maximum value in each column"); Console.Out.WriteLine(" numRows = number of rows to add"); Console.Out.WriteLine(" numQueries = number of queries to run"); Console.Out.WriteLine(" nonceBytes = number of bytes to use in each row nonce"); } public static void ApplyArguments (string[] args) { try { foreach (string arg in args) { ApplyArgument(arg); } } catch (InvalidParameterException e) { Console.Out.WriteLine(e.contents); Parameters.PrintUsage(); Environment.Exit(-1); } } public static void ApplyArgument (string arg) { char[] splitter = {'='}; string[] sp = arg.ToLower().Split(splitter); if (sp.Length == 1) { ApplyArgumentsInFile(arg); return; } else if (sp.Length != 2) { throw new InvalidParameterException("Invalid command-line argument " + arg); } string parameter = sp[0]; string value = sp[1]; if (CommonParams.ApplyArgument(parameter, value)) { return; } if (String.Compare(parameter, "numColumns", StringComparison.OrdinalIgnoreCase) == 0) { Parameters.numColumns = Convert.ToInt32(value); return; } if (String.Compare(parameter, "maxColumnValue", StringComparison.OrdinalIgnoreCase) == 0) { Parameters.maxColumnValue = Convert.ToInt32(value); return; } if (String.Compare(parameter, "numRows", StringComparison.OrdinalIgnoreCase) == 0) { Parameters.numRows = Convert.ToInt32(value); return; } if (String.Compare(parameter, "numQueries", StringComparison.OrdinalIgnoreCase) == 0) { Parameters.numQueries = Convert.ToInt32(value); return; } if (String.Compare(parameter, "nonceBytes", StringComparison.OrdinalIgnoreCase) == 0) { Parameters.nonceBytes = Convert.ToInt32(value); return; } throw new InvalidParameterException("Invalid command-line parameter " + parameter); } public static void ApplyArgumentsInFile(string filename) { string[] args = File.ReadAllLines(filename); foreach (string arg in args) { ApplyArgument(arg); } } } } ================================================ FILE: ironclad-apps/src/Clients/DiffPriv/Program.cs ================================================ using Common; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Net; using System.Net.Sockets; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; namespace DiffPriv { class Program { static void InitializeDB(UdpClient client, Rational budget) { InitializeDBRequest initializeDBRequest = new InitializeDBRequest(budget); byte[] request = initializeDBRequest.GetPacket(); byte[] response = CommonRoutines.SendRequest(client, request, "InitializeDB"); InitializeDBResponse initializeDBResponse = new InitializeDBResponse(response); } static UInt32[] GetRandomRow(Random rng) { UInt32[] row = new UInt32[Parameters.numColumns]; for (int col = 0; col < Parameters.numColumns; ++col) { row[col] = (UInt32)rng.Next(Parameters.maxColumnValue); } return row; } static void AddRow(UdpClient client, Rational max_budget, UInt32[] values, RSACryptoServiceProvider ironclad_public_key, Random rng) { AddRowRequest addRowRequest = new AddRowRequest(values, max_budget, rng); byte[] request = addRowRequest.GetPacket(ironclad_public_key); byte[] response = CommonRoutines.SendRequest(client, request, "AddRow"); AddRowResponse addRowResponse = new AddRowResponse(response); } static void PerformQuery(UdpClient client, UInt32 row_min, UInt32 row_max, UInt32 answer_units, UInt32 answer_min, UInt32 answer_max, Rational alpha, Rational beta, UInt32[] program) { QueryRequest queryRequest = new QueryRequest(row_min, row_max, answer_units, answer_min, answer_max, alpha, beta, program); byte[] request = queryRequest.GetPacket(); byte[] response = CommonRoutines.SendRequest(client, request, "Query"); QueryResponse queryResponse = new QueryResponse(response); Console.Error.WriteLine("Noised answer received was {0}", queryResponse.ResponseValue); } static UInt32[] MakeProgram() { UInt32[] program = new UInt32[Parameters.numColumns * 5 - 1]; int pos = 0; for (UInt32 col = 0; col < Parameters.numColumns; ++col) { program[pos++] = col; program[pos++] = 2000000001; if (col > 0) { program[pos++] = 2000000003; program[pos++] = (UInt32)Parameters.maxColumnValue; program[pos++] = 2000000007; } } program[pos++] = (UInt32)(Parameters.maxColumnValue / 2); program[pos++] = 2000000009; Debug.Assert(pos == program.Length); return program; } static void Main(string[] args) { Parameters.ApplyArguments(args); Profiler.Initialize(); UdpClient client = CommonRoutines.StartClient(); Console.Error.WriteLine("Getting Ironclad public key"); RSACryptoServiceProvider ironclad_public_key = CommonRoutines.GetIroncladPublicKey(client); UInt32 row_min = 0; UInt32 row_max = 1; UInt32 answer_units = 1; UInt32 answer_min = 0; UInt32 answer_max = (UInt32)Parameters.numRows; Rational alpha = new Rational(1009, 1000); Rational beta = new Rational(101, 100); UInt32[] program = MakeProgram(); Rational budget = new Rational((UInt32) Math.Ceiling(Math.Pow(beta.Value, Parameters.numQueries * 3))); Console.Error.WriteLine("Initializing database"); for (UInt32 run_number = 0; run_number < CommonParams.numberOfRuns; ++run_number) { InitializeDB(client, budget); } Random rng = new Random(); for (UInt32 row_number = 0; row_number < Parameters.numRows; ++row_number) { Console.Error.WriteLine("Adding row {0}", row_number + 1); UInt32[] row = GetRandomRow(rng); AddRow(client, budget, row, ironclad_public_key, rng); } Console.Error.WriteLine("Performing queries"); for (UInt32 query_number = 0; query_number < Parameters.numQueries; ++query_number) { Console.Error.WriteLine("Performing query {0}", query_number + 1); PerformQuery(client, row_min, row_max, answer_units, answer_min, answer_max, alpha, beta, program); } Profiler.Print(); } } } ================================================ FILE: ironclad-apps/src/Clients/DiffPriv/Properties/AssemblyInfo.cs ================================================ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; [assembly: AssemblyTitle("DiffPriv")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("DiffPriv")] [assembly: AssemblyCopyright("Copyright © 2014")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] [assembly: Guid("5cb0f60c-30fc-40f1-8445-be38e3ffa50e")] // // [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: ironclad-apps/src/Clients/DiffPriv/Rational.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DiffPriv { public class Rational { public UInt32 num; public UInt32 den; public Rational(UInt32 i_num, UInt32 i_den) { num = i_num; den = i_den; } public Rational(UInt32 value) { num = value; den = 1; } public double Value { get { return num * 1.0 / den; } } } } ================================================ FILE: ironclad-apps/src/Clients/DiffPrivSrv/App.config ================================================  ================================================ FILE: ironclad-apps/src/Clients/DiffPrivSrv/BigRational.cs ================================================ using System; using System.Collections.Generic; using System.Numerics; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DiffPrivSrv { class BigRational { private BigInteger numerator; private BigInteger denominator; public BigRational(BigInteger i_numerator, BigInteger i_denominator) { numerator = i_numerator; denominator = i_denominator; } public BigRational(int i_numerator, int i_denominator) { numerator = new BigInteger(i_numerator); denominator = new BigInteger(i_denominator); } public BigRational(int value) { numerator = new BigInteger(value); denominator = new BigInteger(1); } public BigRational(BigInteger value) { numerator = value; denominator = new BigInteger(1); } public bool IsNegative() { return (numerator < 0 && denominator > 0) || (numerator > 0 && denominator < 0); } public bool IsZero() { return numerator == 0; } public bool IsPositive() { return (numerator > 0 && denominator > 0) || (numerator < 0 && denominator < 0); } public static BigRational operator +(BigRational r1, BigRational r2) { return new BigRational(r1.numerator * r2.denominator + r2.numerator * r1.denominator, r1.denominator * r2.denominator); } public static BigRational operator -(BigRational r1, BigRational r2) { return new BigRational(r1.numerator * r2.denominator - r2.numerator * r1.denominator, r1.denominator * r2.denominator); } public static BigRational operator *(BigRational r1, BigRational r2) { return new BigRational(r1.numerator * r2.numerator, r1.denominator * r2.denominator); } public static BigRational operator /(BigRational r1, BigRational r2) { return new BigRational(r1.numerator * r2.denominator, r1.denominator * r2.numerator); } public static bool operator <(BigRational r1, BigRational r2) { return (r1 - r2).IsNegative(); } public static bool operator >(BigRational r1, BigRational r2) { return (r1 - r2).IsPositive(); } public static bool operator ==(BigRational r1, BigRational r2) { return (r1 - r2).IsZero(); } public static bool operator !=(BigRational r1, BigRational r2) { return !(r1 - r2).IsZero(); } public static bool operator <=(BigRational r1, BigRational r2) { return !(r1 - r2).IsPositive(); } public static bool operator >=(BigRational r1, BigRational r2) { return !(r1 - r2).IsNegative(); } public override bool Equals(object obj) { return obj is BigRational && this == (BigRational)obj; } public override int GetHashCode() { return 0; } public static BigRational Power(BigRational x, UInt32 e) { BigRational x_to_e = new BigRational(1); while (e > 0) { x_to_e *= x; e -= 1; } return x_to_e; } } } ================================================ FILE: ironclad-apps/src/Clients/DiffPrivSrv/DiffPrivRequest.cs ================================================ using Common; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; namespace DiffPrivSrv { public class DiffPrivRequest { public DiffPrivRequest() { } public static object ParseRequest (byte[] request) { if (request.Length < 1) { Console.Error.WriteLine("Received request with no bytes"); return new Common.InvalidRequest(); } if (request[0] == 1) { return Common.GetQuoteRequest.ParseRequest(request); } if (request[0] == 2) { return InitializeDBRequest.ParseRequest(request); } if (request[0] == 3) { return AddRowRequest.ParseRequest(request); } if (request[0] == 4) { return QueryRequest.ParseRequest(request); } Console.Error.WriteLine("Received request with invalid type"); return new Common.InvalidRequest(); } } public class InitializeDBRequest { public UInt32 budget_num; public UInt32 budget_den; public InitializeDBRequest(UInt32 i_budget_num, UInt32 i_budget_den) { budget_num = i_budget_num; budget_den = i_budget_den; } public static object ParseRequest (byte[] request) { if (request.Length < 9) { Console.Error.WriteLine("Received initialize-DB request with fewer than 9 bytes"); return new Common.InvalidRequest(); } UInt32 budget_num = CommonRoutines.ExtractBEWord(request, 1); UInt32 budget_den = CommonRoutines.ExtractBEWord(request, 5); return new InitializeDBRequest(budget_num, budget_den); } } public class AddRowRequest { public byte[] ciphertext; public AddRowRequest(byte[] i_ciphertext) { ciphertext = i_ciphertext; } public static object ParseRequest (byte[] request) { if (request.Length < 2 || (request.Length-1) % 4 != 0) { Console.Error.WriteLine("Received add-row request with invalid number of bytes {0}", request.Length); return new Common.InvalidRequest(); } byte[] ciphertext = request.Skip(1).ToArray(); return new AddRowRequest(ciphertext); } } public class QueryRequest { public UInt32 row_min; public UInt32 row_max; public UInt32 answer_units; public UInt32 answer_min; public UInt32 answer_max; public UInt32 alpha_num; public UInt32 alpha_den; public UInt32 beta_num; public UInt32 beta_den; public byte[] program_encoding; public QueryRequest(UInt32 i_row_min, UInt32 i_row_max, UInt32 i_answer_units, UInt32 i_answer_min, UInt32 i_answer_max, UInt32 i_alpha_num, UInt32 i_alpha_den, UInt32 i_beta_num, UInt32 i_beta_den, byte[] i_program_encoding) { row_min = i_row_min; row_max = i_row_max; answer_units = i_answer_units; answer_min = i_answer_min; answer_max = i_answer_max; alpha_num = i_alpha_num; alpha_den = i_alpha_den; beta_num = i_beta_num; beta_den = i_beta_den; program_encoding = i_program_encoding; } public static object ParseRequest (byte[] request) { if (request.Length < 41) { Console.Error.WriteLine("Received query request with fewer than 41 bytes"); return new Common.InvalidRequest(); } int program_size = (int)CommonRoutines.ExtractBEWord(request, 1); if (request.Length < 41 + program_size) { Console.Error.WriteLine("Received query request without enough bytes to fit program"); return new Common.InvalidRequest(); } if (program_size % 4 != 0) { Console.Error.WriteLine("Received query request with program not consisting of an integer number of words"); return new Common.InvalidRequest(); } UInt32 row_min = CommonRoutines.ExtractBEWord(request, 5); UInt32 row_max = CommonRoutines.ExtractBEWord(request, 9); UInt32 answer_units = CommonRoutines.ExtractBEWord(request, 13); UInt32 answer_min = CommonRoutines.ExtractBEWord(request, 17); UInt32 answer_max = CommonRoutines.ExtractBEWord(request, 21); UInt32 alpha_num = CommonRoutines.ExtractBEWord(request, 25); UInt32 alpha_den = CommonRoutines.ExtractBEWord(request, 29); UInt32 beta_num = CommonRoutines.ExtractBEWord(request, 33); UInt32 beta_den = CommonRoutines.ExtractBEWord(request, 37); byte[] program_encoding = request.Skip(41).ToArray(); return new QueryRequest(row_min, row_max, answer_units, answer_min, answer_max, alpha_num, alpha_den, beta_num, beta_den, program_encoding); } } } ================================================ FILE: ironclad-apps/src/Clients/DiffPrivSrv/DiffPrivResponse.cs ================================================ using Common; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DiffPrivSrv { class DiffPrivSrvResponse { public static byte[] EncodeInitializeDBResponse (UInt32 error_code) { byte[] header = new byte[1]; header[0] = 2; byte[] error_code_encoded = CommonRoutines.EncodeBEWord(error_code); return CommonRoutines.CombineByteArrays(header, error_code_encoded); } public static byte[] EncodeAddRowResponse () { byte[] header = new byte[1]; header[0] = 3; return header; } public static byte[] EncodeQueryResponse (UInt32 error_code, UInt32 response_value) { byte[] header = new byte[1]; header[0] = 4; byte[] error_code_encoded = CommonRoutines.EncodeBEWord(error_code); byte[] response_value_encoded = CommonRoutines.EncodeBEWord((uint)response_value); return CommonRoutines.CombineByteArrays(header, error_code_encoded, response_value_encoded); } } } ================================================ FILE: ironclad-apps/src/Clients/DiffPrivSrv/DiffPrivSrv.csproj ================================================  Debug AnyCPU {29139FBF-8F54-41A3-B135-F9AFCA3714C1} Exe Properties DiffPrivSrv DiffPrivSrv v4.5 512 AnyCPU true full false bin\Debug\ DEBUG;TRACE prompt 4 AnyCPU pdbonly true bin\Release\ TRACE prompt 4 {5e394d90-c3d6-41a1-a6b4-715e43e54d7c} Common ================================================ FILE: ironclad-apps/src/Clients/DiffPrivSrv/Parameters.cs ================================================ using Common; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; namespace DiffPrivSrv { class InvalidParameterException : Exception { public string contents; public InvalidParameterException(string i_contents) { contents = i_contents; } } public class Parameters { public static void Print() { CommonParams.Print(); } public static void PrintUsage() { Console.Out.WriteLine("Usage: DiffPrivSrv.exe [filename or param=value]... where filename contains"); Console.Out.WriteLine(" lines of the form param=value and param must be one of the following."); Console.Out.WriteLine(); CommonParams.PrintUsage(); } public static void ApplyArguments (string[] args) { try { foreach (string arg in args) { ApplyArgument(arg); } } catch (InvalidParameterException e) { Console.Out.WriteLine(e.contents); Parameters.PrintUsage(); Environment.Exit(-1); } } public static void ApplyArgument (string arg) { char[] splitter = {'='}; string[] sp = arg.ToLower().Split(splitter); if (sp.Length == 1) { ApplyArgumentsInFile(arg); return; } else if (sp.Length != 2) { throw new InvalidParameterException("Invalid command-line argument " + arg); } string parameter = sp[0]; string value = sp[1]; if (CommonParams.ApplyArgument(parameter, value)) { return; } throw new InvalidParameterException("Invalid command-line parameter " + parameter); } public static void ApplyArgumentsInFile(string filename) { string[] args = File.ReadAllLines(filename); foreach (string arg in args) { ApplyArgument(arg); } } } } ================================================ FILE: ironclad-apps/src/Clients/DiffPrivSrv/Program.cs ================================================ using Common; using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; namespace DiffPrivSrv { class Program { static byte[] HandleRequest(byte[] request) { return new byte[0]; } static void Main(string[] args) { Parameters.ApplyArguments(args); UdpClient server = CommonRoutines.StartServer(); StateMachine stateMachine = new StateMachine(); IPEndPoint client = new IPEndPoint(IPAddress.Any, 0); while (true) { byte[] request = server.Receive(ref client); byte[] response = stateMachine.HandleRequest(request); server.Send(response, response.Length, client); } } } } ================================================ FILE: ironclad-apps/src/Clients/DiffPrivSrv/Properties/AssemblyInfo.cs ================================================ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; [assembly: AssemblyTitle("DiffPrivSrv")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("DiffPrivSrv")] [assembly: AssemblyCopyright("Copyright © 2014")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] [assembly: Guid("889d7ec6-ade0-45ed-897a-b73a6dc8d276")] // // [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: ironclad-apps/src/Clients/DiffPrivSrv/StateMachine.cs ================================================ using Common; using System; using System.Collections.Generic; using System.Linq; using System.Numerics; using System.Security.Cryptography; using System.Text; namespace DiffPrivSrv { class DiffPrivRow { public byte[] nonce; public UInt32[] data; public DiffPrivRow(byte[] i_nonce, UInt32[] i_data) { nonce = i_nonce; data = i_data; } } abstract class Operation { public Operation() { } public static Operation ConvertWordToOperation(UInt32 w) { if (w == 2000000001) { return new OperationColumn(); } if (w == 2000000002) { return new OperationIf(); } if (w == 2000000003) { return new OperationAdd(); } if (w == 2000000004) { return new OperationSub(); } if (w == 2000000005) { return new OperationMul(); } if (w == 2000000006) { return new OperationDiv(); } if (w == 2000000007) { return new OperationMod(); } if (w == 2000000008) { return new OperationGt(); } if (w == 2000000009) { return new OperationLt(); } if (w == 2000000010) { return new OperationEq(); } if (w == 2000000011) { return new OperationGe(); } if (w == 2000000012) { return new OperationLe(); } return new OperationPush(w); } public abstract int StackSizeChange(); public abstract void Apply(Stack stack, UInt32[] data); } class OperationColumn : Operation { public OperationColumn() { } public override int StackSizeChange() { return 0; } public override void Apply(Stack stack, UInt32[] data) { UInt32 column = stack.Pop(); UInt32 value = (column >= 0 && column < data.Length ? data[column] : 0); stack.Push(value); } } class OperationIf : Operation { public OperationIf() { } public override int StackSizeChange() { return -2; } public override void Apply(Stack stack, UInt32[] data) { UInt32 false_value = stack.Pop(); UInt32 true_value = stack.Pop(); UInt32 condition = stack.Pop(); UInt32 value = (condition != 0 ? true_value : false_value); stack.Push(value); } } class OperationAdd : Operation { public OperationAdd() { } public override int StackSizeChange() { return -1; } public override void Apply(Stack stack, UInt32[] data) { UInt32 value2 = stack.Pop(); UInt32 value1 = stack.Pop(); UInt32 value = value1 + value2; stack.Push(value); } } class OperationSub : Operation { public OperationSub() { } public override int StackSizeChange() { return -1; } public override void Apply(Stack stack, UInt32[] data) { UInt32 value2 = stack.Pop(); UInt32 value1 = stack.Pop(); UInt32 value = value1 - value2; stack.Push(value); } } class OperationMul : Operation { public OperationMul() { } public override int StackSizeChange() { return -1; } public override void Apply(Stack stack, UInt32[] data) { UInt32 value2 = stack.Pop(); UInt32 value1 = stack.Pop(); UInt32 value = value1 * value2; stack.Push(value); } } class OperationDiv : Operation { public OperationDiv() { } public override int StackSizeChange() { return -1; } public override void Apply(Stack stack, UInt32[] data) { UInt32 value2 = stack.Pop(); UInt32 value1 = stack.Pop(); UInt32 value = (value2 != 0 ? value1 / value2 : 0); stack.Push(value); } } class OperationMod : Operation { public OperationMod() { } public override int StackSizeChange() { return -1; } public override void Apply(Stack stack, UInt32[] data) { UInt32 value2 = stack.Pop(); UInt32 value1 = stack.Pop(); UInt32 value = (value2 != 0 ? value1 % value2 : 0); stack.Push(value); } } class OperationGt : Operation { public OperationGt() { } public override int StackSizeChange() { return -1; } public override void Apply(Stack stack, UInt32[] data) { UInt32 value2 = stack.Pop(); UInt32 value1 = stack.Pop(); UInt32 value = (UInt32)(value1 > value2 ? 1 : 0); stack.Push(value); } } class OperationLt : Operation { public OperationLt() { } public override int StackSizeChange() { return -1; } public override void Apply(Stack stack, UInt32[] data) { UInt32 value2 = stack.Pop(); UInt32 value1 = stack.Pop(); UInt32 value = (UInt32)(value1 < value2 ? 1 : 0); stack.Push(value); } } class OperationEq : Operation { public OperationEq() { } public override int StackSizeChange() { return -1; } public override void Apply(Stack stack, UInt32[] data) { UInt32 value2 = stack.Pop(); UInt32 value1 = stack.Pop(); UInt32 value = (UInt32)(value1 == value2 ? 1 : 0); stack.Push(value); } } class OperationGe : Operation { public OperationGe() { } public override int StackSizeChange() { return -1; } public override void Apply(Stack stack, UInt32[] data) { UInt32 value2 = stack.Pop(); UInt32 value1 = stack.Pop(); UInt32 value = (UInt32)(value1 >= value2 ? 1 : 0); stack.Push(value); } } class OperationLe : Operation { public OperationLe() { } public override int StackSizeChange() { return -1; } public override void Apply(Stack stack, UInt32[] data) { UInt32 value2 = stack.Pop(); UInt32 value1 = stack.Pop(); UInt32 value = (UInt32)(value1 <= value2 ? 1 : 0); stack.Push(value); } } class OperationPush : Operation { public UInt32 value; public OperationPush(UInt32 i_value) { value = i_value; } public override int StackSizeChange() { return 1; } public override void Apply(Stack stack, UInt32[] data) { stack.Push(value); } } public class MapperProgram { private Operation[] operations; public MapperProgram(UInt32[] program_encoding) { operations = new Operation[program_encoding.Length]; for (int i = 0; i < program_encoding.Length; ++i) { operations[i] = Operation.ConvertWordToOperation(program_encoding[i]); } } public bool IsValid() { int stack_size = 0; foreach (Operation operation in operations) { stack_size += operation.StackSizeChange(); if (stack_size < 1) { return false; } } return (stack_size == 1); } public UInt32 Run(UInt32[] data) { Stack stack = new Stack(); foreach (Operation operation in operations) { operation.Apply(stack, data); } return stack.Pop(); } } public class StateMachine { private RSACryptoServiceProvider key_pair; private List rows; private BigRational budget; private int rows_received; private Random rng; public StateMachine() { key_pair = new RSACryptoServiceProvider(CommonParams.serverKeyBits); rows = new List(); budget = new BigRational(1); rows_received = 0; rng = new Random(); } public byte[] HandleRequest(byte[] requestBytes) { object request = DiffPrivRequest.ParseRequest(requestBytes); if (request is Common.GetQuoteRequest) { GetQuoteResponse getQuoteResponse = new GetQuoteResponse(0, key_pair); return getQuoteResponse.Encode(); } if (request is InitializeDBRequest) { InitializeDBRequest r = (InitializeDBRequest)request; if (rows_received != 0) { Console.Error.WriteLine("Received request to initialize DB after receiving rows"); return DiffPrivSrvResponse.EncodeInitializeDBResponse(18); } if (r.budget_num < r.budget_den) { Console.Error.WriteLine("Received request to initialize DB with budget < 1"); return DiffPrivSrvResponse.EncodeInitializeDBResponse(16); } budget = new BigRational(r.budget_num, r.budget_den); rows.Clear(); return DiffPrivSrvResponse.EncodeInitializeDBResponse(0); } if (request is AddRowRequest) { byte[] ciphertext = ((AddRowRequest)request).ciphertext; byte[] plaintext; try { plaintext = key_pair.Decrypt(ciphertext, false); } catch { Console.Error.WriteLine("Received undecryptable add-row request"); return DiffPrivSrvResponse.EncodeAddRowResponse(); } HandleAddRowRequest(plaintext); return DiffPrivSrvResponse.EncodeAddRowResponse(); } if (request is QueryRequest) { QueryRequest r = (QueryRequest)request; return HandleQueryRequest(r); } return InvalidResponse.Encode(); } public void HandleAddRowRequest(byte[] plaintext) { if (plaintext.Length < 16) { Console.Error.WriteLine("Received add-row request with < 16 bytes, with length {0}", plaintext.Length); return; } int row_nonce_size = (int)CommonRoutines.ExtractBEWord(plaintext, 0); int row_data_size = (int)CommonRoutines.ExtractBEWord(plaintext, 4); if (plaintext.Length < 16 + row_nonce_size + row_data_size) { Console.Error.WriteLine("Received too-small add-row request, with length {0}", plaintext.Length); return; } UInt32 max_budget_num = CommonRoutines.ExtractBEWord(plaintext, 8); UInt32 max_budget_den = CommonRoutines.ExtractBEWord(plaintext, 12); byte[] row_nonce = plaintext.Skip(16).Take(row_nonce_size).ToArray(); byte[] row_data = plaintext.Skip(16 + row_nonce_size).Take(row_data_size).ToArray(); UInt32[] row_words = CommonRoutines.BEByteSeqToWordSeq(row_data); if (max_budget_den == 0) { Console.Error.WriteLine("Received add-row request with 0 budget denominator"); return; } BigRational max_budget = new BigRational(max_budget_num, max_budget_den); if (budget > max_budget) { Console.Error.WriteLine("Received add-row request with too restrictive a budget requirement"); return; } foreach (DiffPrivRow row in rows) { if (row.nonce.SequenceEqual(row_nonce)) { Console.Error.WriteLine("Received add-row request with duplicate nonce, so not adding it"); return; } } rows.Add(new DiffPrivRow(row_nonce, row_words)); } private static bool FindHigherPowerOfTwo (BigRational r, out UInt32 x) { x = 0; BigRational two = new BigRational(2); BigRational two_to_x = new BigRational(1); while (x < 0xFFFFFFFF) { if (two_to_x >= r) { return true; } ++x; two_to_x *= two; } return two_to_x >= r; } private static UInt32 DivideRoundingUp (UInt32 a, UInt32 b) { return (a + b - 1) / b; } private static UInt32 RoundUpToMultiple (UInt32 a, UInt32 b) { UInt32 m = a % b; if (m == 0) { return a; } else { return a + (b - m); } } private static UInt32 FindHighestPowerLeThreshold (BigRational alpha, BigRational threshold, UInt32 max_power) { UInt32 e = 0; BigRational alpha_to_e = new BigRational(1); while (e < max_power) { alpha_to_e = alpha_to_e * alpha; if (alpha_to_e > threshold) { return e; } ++e; } return max_power; } private static UInt32 ClipWord32 (UInt32 x, UInt32 min_x, UInt32 max_x) { if (x <= min_x) { return min_x; } if (x >= max_x) { return max_x; } return x; } private static UInt32 SaturatingAdd (UInt32 x, UInt32 y) { if (x + y < x) { return 0xFFFFFFFF; } else { return x + y; } } private UInt32 ComputeSum (MapperProgram program, UInt32 row_min, UInt32 row_max, UInt32 answer_units, UInt32 answer_min, UInt32 answer_max) { UInt32 clipped_scaled_sum = 0; UInt32 total_remainder = 0; foreach (DiffPrivRow row in rows) { UInt32 row_value = program.Run(row.data); UInt32 clipped_value = ClipWord32(row_value, row_min, row_max); UInt32 scaled_value = clipped_value / answer_units; UInt32 scaling_remainder = clipped_value % answer_units; clipped_scaled_sum = SaturatingAdd(clipped_scaled_sum, scaled_value); total_remainder = total_remainder + scaling_remainder; if (total_remainder >= answer_units) { clipped_scaled_sum = SaturatingAdd(clipped_scaled_sum, 1); total_remainder -= answer_units; } } UInt32 extra = (UInt32)(total_remainder * 2 >= answer_units ? 1 : 0); clipped_scaled_sum = SaturatingAdd(clipped_scaled_sum, extra); return ClipWord32(clipped_scaled_sum, answer_min, answer_max); } private UInt32 AddNoise (UInt32 answer, UInt32 absolute_noise, bool negate_noise) { if (negate_noise) { if (answer < absolute_noise) { return 0; } else { return answer - absolute_noise; } } else { return SaturatingAdd(answer, absolute_noise); } } public byte[] HandleQueryRequest(QueryRequest request) { if (request.row_min > request.row_max) { Console.Error.WriteLine("Row value range empty"); return DiffPrivSrvResponse.EncodeQueryResponse(1, 0); } if (request.answer_min > request.answer_max) { Console.Error.WriteLine("Answer range empty"); return DiffPrivSrvResponse.EncodeQueryResponse(2, 0); } if (request.answer_units <= 0) { Console.Error.WriteLine("Answer units not positive"); return DiffPrivSrvResponse.EncodeQueryResponse(3, 0); } if (request.alpha_num <= request.alpha_den) { Console.Error.WriteLine("Alpha not greater than 1"); return DiffPrivSrvResponse.EncodeQueryResponse(6, 0); } if (request.beta_num <= request.beta_den) { Console.Error.WriteLine("Beta not greater than 1"); return DiffPrivSrvResponse.EncodeQueryResponse(13, 0); } UInt32[] program_words = CommonRoutines.BEByteSeqToWordSeq(request.program_encoding); MapperProgram program = new MapperProgram(program_words); if (!program.IsValid()) { Console.Error.WriteLine("Invalid program provided for query"); return DiffPrivSrvResponse.EncodeQueryResponse(4, 0); } if (request.answer_units >= 0x80000000) { Console.Error.WriteLine("Answer granularity too high"); return DiffPrivSrvResponse.EncodeQueryResponse(17, 0); } BigRational alpha = new BigRational(request.alpha_num, request.alpha_den); BigRational beta = new BigRational(request.beta_num, request.beta_den); UInt32 delta = DivideRoundingUp(request.row_max - request.row_min, request.answer_units); UInt32 B = request.answer_max - request.answer_min; if (B <= 0) { Console.Error.WriteLine("Answer range empty"); return DiffPrivSrvResponse.EncodeQueryResponse(5, 0); } if (alpha <= new BigRational(1)) { return DiffPrivSrvResponse.EncodeQueryResponse(6, 0); } BigRational alpha_to_delta = BigRational.Power(alpha, delta); if (beta <= alpha_to_delta) { Console.Error.WriteLine("Beta not greater than alpha to the power of delta"); return DiffPrivSrvResponse.EncodeQueryResponse(7, 0); } if (beta > budget) { Console.Error.WriteLine("Not enough budget for request"); return DiffPrivSrvResponse.EncodeQueryResponse(11, 0); } BigRational one = new BigRational(1); BigRational two = new BigRational(2); BigRational min_alpha_minus_1_and_2 = alpha - one; if (min_alpha_minus_1_and_2 > two) { min_alpha_minus_1_and_2 = two; } BigRational noiseEntropyPart1 = (alpha + one) * (beta + one) / ((beta - alpha_to_delta) * min_alpha_minus_1_and_2); UInt32 r1; if (!FindHigherPowerOfTwo(noiseEntropyPart1, out r1) || r1 >= 0xFFFFFFE0) { Console.Error.WriteLine("Requires too many bits of randomness due to noise entropy part 1"); return DiffPrivSrvResponse.EncodeQueryResponse(8, 0); } UInt32 log_alpha; if (!FindHigherPowerOfTwo(alpha, out log_alpha) || log_alpha > 0xFFFFFFFFUL / B) { Console.Error.WriteLine("Requires too many bits of randomness due to alpha"); return DiffPrivSrvResponse.EncodeQueryResponse(8, 0); } UInt32 r2 = log_alpha * (B-1); if (r2 >= 0xFFFFFFC8 - r1) { Console.Error.WriteLine("Requires too many bits of randomness due to r2"); return DiffPrivSrvResponse.EncodeQueryResponse(8, 0); } UInt32 r = RoundUpToMultiple(r1 + r2 + 7, 8); UInt32 num_randoms_needed = RoundUpToMultiple(r / 8, 4) + 1; bool negate_noise = (rng.Next() % 2 == 0); byte[] randoms = new byte[num_randoms_needed]; rng.NextBytes(randoms); randoms[num_randoms_needed - 1] = 0; BigInteger U = new BigInteger(randoms); BigRational one_half = new BigRational(1, 2); BigRational numerator = new BigRational(U) + one_half; BigRational denominator = BigRational.Power(two, (num_randoms_needed - 1) * 8); BigRational u = numerator / denominator; BigRational threshold = (two * alpha) / (u * (alpha + one)); UInt32 absolute_noise = FindHighestPowerLeThreshold(alpha, threshold, B); UInt32 answer = ComputeSum(program, request.row_min, request.row_max, request.answer_units, request.answer_min, request.answer_max); UInt32 noised_answer = AddNoise(answer, absolute_noise, negate_noise); UInt32 response = ClipWord32(noised_answer, request.answer_min, request.answer_max); budget = budget / beta; return DiffPrivSrvResponse.EncodeQueryResponse(0, response); } } } ================================================ FILE: ironclad-apps/src/Clients/DotNetSHABench/App.config ================================================  ================================================ FILE: ironclad-apps/src/Clients/DotNetSHABench/DotNetSHABench.csproj ================================================  Debug AnyCPU {4494E273-A2EF-4799-8D7E-C893C31D1362} Exe Properties DotNetSHABench DotNetSHABench v4.5 512 AnyCPU true full false bin\Debug\ DEBUG;TRACE prompt 4 AnyCPU pdbonly true bin\Release\ TRACE prompt 4 {5e394d90-c3d6-41a1-a6b4-715e43e54d7c} Common ================================================ FILE: ironclad-apps/src/Clients/DotNetSHABench/Parameters.cs ================================================ using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DotNetSHABench { class InvalidParameterException : Exception { public string contents; public InvalidParameterException(string i_contents) { contents = i_contents; } } public class Parameters { public static int messageSize = 2048; public static int numberOfRuns = 100; public static void Print() { Console.Error.WriteLine("messageSize\t{0}", messageSize); Console.Error.WriteLine("numberOfRuns\t{0}", numberOfRuns); } public static void PrintUsage() { Console.Out.WriteLine("Usage: DotNetSHABench.exe [filename or param=value]... where filename contains"); Console.Out.WriteLine(" lines of the form param=value and param must be one of the following."); Console.Out.WriteLine(); Console.Out.WriteLine(" messageSize = message size, in bytes"); Console.Out.WriteLine(" numberOfRuns = number of times to advance counter"); } public static void ApplyArguments (string[] args) { try { foreach (string arg in args) { ApplyArgument(arg); } } catch (InvalidParameterException e) { Console.Out.WriteLine(e.contents); Parameters.PrintUsage(); Environment.Exit(-1); } } public static void ApplyArgument (string arg) { char[] splitter = {'='}; string[] sp = arg.ToLower().Split(splitter); if (sp.Length == 1) { ApplyArgumentsInFile(arg); return; } else if (sp.Length != 2) { throw new InvalidParameterException("Invalid command-line argument " + arg); } string parameter = sp[0]; string value = sp[1]; if (String.Compare(parameter, "messageSize", StringComparison.OrdinalIgnoreCase) == 0) { Parameters.messageSize = Convert.ToInt32(value); } else if (String.Compare(parameter, "numberOfRuns", StringComparison.OrdinalIgnoreCase) == 0) { Parameters.numberOfRuns = Convert.ToInt32(value); } else { throw new InvalidParameterException("Invalid command-line parameter " + parameter); } } public static void ApplyArgumentsInFile(string filename) { string[] args = File.ReadAllLines(filename); foreach (string arg in args) { ApplyArgument(arg); } } } } ================================================ FILE: ironclad-apps/src/Clients/DotNetSHABench/Program.cs ================================================ using Common; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; namespace DotNetSHABench { class Program { static void TestSHA (int message_size, int num_runs) { string profileID = string.Format("SHA256-{0}Bytes", message_size); SHA256Managed hasher = new SHA256Managed(); byte[] message = new byte[message_size]; Random rng = new Random(); Stopwatch stopwatch = new Stopwatch(); for (int run_number = 0; run_number < Parameters.numberOfRuns; ++run_number) { rng.NextBytes(message); stopwatch.Restart(); byte[] hash = hasher.ComputeHash(message); stopwatch.Stop(); Profiler.Record(profileID, stopwatch); } } static void DoAllTests() { Stopwatch stopwatch = new Stopwatch(); int run_number = 0; SHA1Managed sha1_hasher = new SHA1Managed(); SHA256Managed sha256_hasher = new SHA256Managed(); byte[] msg32 = new byte[32]; byte[] msg256 = new byte[256]; byte[] msg8192 = new byte[8192]; Random rng = new Random(); rng.NextBytes(msg32); rng.NextBytes(msg256); rng.NextBytes(msg8192); double usec_per_op; double msec_per_op; double nsec_per_byte; byte[] hash; byte[] encrypted = null; byte[] decrypted; RSACryptoServiceProvider key_pair = null; RSAParameters p; stopwatch.Restart(); for (run_number = 0; run_number < Parameters.numberOfRuns; ++run_number) { key_pair = new RSACryptoServiceProvider(1024); p = key_pair.ExportParameters(true); } stopwatch.Stop(); msec_per_op = stopwatch.ElapsedTicks * 1000.0 / Stopwatch.Frequency / Parameters.numberOfRuns; Console.WriteLine("RSA KeyGen\t1024b\t{0} ms/op", msec_per_op); stopwatch.Restart(); for (run_number = 0; run_number < Parameters.numberOfRuns; ++run_number) { encrypted = key_pair.Encrypt(msg32, false); } stopwatch.Stop(); usec_per_op = stopwatch.ElapsedTicks * 1000000.0 / Stopwatch.Frequency / Parameters.numberOfRuns; Console.WriteLine("RSA Public\t1024b\t{0} us/op", usec_per_op); stopwatch.Restart(); for (run_number = 0; run_number < Parameters.numberOfRuns; ++run_number) { decrypted = key_pair.Decrypt(encrypted, false); } stopwatch.Stop(); usec_per_op = stopwatch.ElapsedTicks * 1000000.0 / Stopwatch.Frequency / Parameters.numberOfRuns; Console.WriteLine("RSA Private\t1024b\t{0} us/op", usec_per_op); /* stopwatch.Restart(); for (run_number = 0; run_number < Parameters.numberOfRuns; ++run_number) { hash = sha1_hasher.ComputeHash(msg256); } stopwatch.Stop(); usec_per_op = stopwatch.ElapsedTicks * 1000000.0 / Stopwatch.Frequency / Parameters.numberOfRuns; nsec_per_byte = usec_per_op * 1000.0 / 256; Console.WriteLine("SHA-1\t256B\t{0} us/op\t{1} ns/B", usec_per_op, nsec_per_byte); stopwatch.Restart(); for (run_number = 0; run_number < Parameters.numberOfRuns; ++run_number) { hash = sha1_hasher.ComputeHash(msg8192); } stopwatch.Stop(); usec_per_op = stopwatch.ElapsedTicks * 1000000.0 / Stopwatch.Frequency / Parameters.numberOfRuns; nsec_per_byte = usec_per_op * 1000.0 / 8192; Console.WriteLine("SHA-1\t8192B\t{0} us/op\t{1} ns/B", usec_per_op, nsec_per_byte); */ stopwatch.Restart(); for (run_number = 0; run_number < Parameters.numberOfRuns; ++run_number) { hash = sha256_hasher.ComputeHash(msg256); } stopwatch.Stop(); usec_per_op = stopwatch.ElapsedTicks * 1000000.0 / Stopwatch.Frequency / Parameters.numberOfRuns; nsec_per_byte = usec_per_op * 1000.0 / 256; Console.WriteLine("SHA-256\t256B\t{0} us/op\t{1} ns/B", usec_per_op, nsec_per_byte); stopwatch.Restart(); for (run_number = 0; run_number < Parameters.numberOfRuns; ++run_number) { hash = sha1_hasher.ComputeHash(msg8192); } stopwatch.Stop(); usec_per_op = stopwatch.ElapsedTicks * 1000000.0 / Stopwatch.Frequency / Parameters.numberOfRuns; nsec_per_byte = usec_per_op * 1000.0 / 8192; Console.WriteLine("SHA-256\t8192B\t{0} us/op\t{1} ns/B", usec_per_op, nsec_per_byte); } static void Main(string[] args) { Parameters.ApplyArguments(args); DoAllTests(); /* Profiler.Initialize(); TestSHA(Parameters.messageSize, Parameters.numberOfRuns); Profiler.Print(); */ } } } ================================================ FILE: ironclad-apps/src/Clients/DotNetSHABench/Properties/AssemblyInfo.cs ================================================ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; [assembly: AssemblyTitle("DotNetSHABench")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("DotNetSHABench")] [assembly: AssemblyCopyright("Copyright © 2014")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] [assembly: Guid("5642cbcd-359b-42a5-9469-0af61eca1e2d")] // // [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: ironclad-apps/src/Clients/Notary/App.config ================================================  ================================================ FILE: ironclad-apps/src/Clients/Notary/Notary.csproj ================================================  Debug AnyCPU {482B3A42-D9E8-4D48-9E44-27392205EDB0} Exe Properties Notary Notary v4.5 512 AnyCPU true full false bin\Debug\ DEBUG;TRACE prompt 4 AnyCPU pdbonly true bin\Release\ TRACE prompt 4 {5e394d90-c3d6-41a1-a6b4-715e43e54d7c} Common ================================================ FILE: ironclad-apps/src/Clients/Notary/NotaryRequests.cs ================================================ using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; namespace Notary { public class AdvanceCounterRequest { private byte[] message; public AdvanceCounterRequest(byte[] i_message) { message = i_message; } public byte[] GetPacket() { Debug.Assert(message.Length < 256); byte[] packet = new byte[2 + message.Length]; packet[0] = 2; packet[1] = (byte)message.Length; message.CopyTo(packet, 2); return packet; } } } ================================================ FILE: ironclad-apps/src/Clients/Notary/NotaryResponses.cs ================================================ using Common; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Net.Sockets; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; namespace Notary { class AdvanceCounterResponse { private UInt32 error_code; private UInt32 new_counter_value; private byte[] message; public UInt32 ErrorCode { get { return error_code; } } public UInt32 NewCounterValue { get { return new_counter_value; } } public byte[] Message { get { return message; } } public AdvanceCounterResponse(byte[] packet, RSACryptoServiceProvider ironclad_public_key) { if (packet.Length < 13) { throw new Exception("Invalid AdvanceCounterResponsePacket -- length < 13"); } if (packet[0] != 2) { throw new Exception("First byte of AdvanceCounterResponse is not 2"); } error_code = CommonRoutines.ExtractBEWord(packet, 1); if (error_code != 0) { throw new ErrorCodeException(error_code); } int notary_statement_length = (int)CommonRoutines.ExtractBEWord(packet, 5); int notary_attestation_length = (int)CommonRoutines.ExtractBEWord(packet, 9); byte[] notary_statement = packet.Skip(13).Take(notary_statement_length).ToArray(); byte[] notary_attestation = packet.Skip(13 + notary_statement_length).Take(notary_attestation_length).ToArray(); if (notary_statement.Length < 1) { throw new Exception("Notary statement too short"); } if (notary_statement[0] != 34) { throw new Exception("Notary statement does not start with magic byte 34"); } int offset = 1; new_counter_value = CommonRoutines.DecodeShortMPInt(notary_statement, ref offset); message = notary_statement.Skip(offset).ToArray(); if (!CommonParams.ignoreKey && !ironclad_public_key.VerifyData(notary_statement, CryptoConfig.MapNameToOID("SHA256"), notary_attestation)) { throw new Exception("Could not verify signature of notary statement"); } } public override string ToString() { return string.Format("AdvanceCounterResponse(error_code={0}", error_code); } } } ================================================ FILE: ironclad-apps/src/Clients/Notary/Parameters.cs ================================================ using Common; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; namespace Notary { class InvalidParameterException : Exception { public string contents; public InvalidParameterException(string i_contents) { contents = i_contents; } } public class Parameters { public static int messageLength = 32; public static void Print() { CommonParams.Print(); Console.Error.WriteLine("messageLength\t{0}", messageLength); } public static void PrintUsage() { Console.Out.WriteLine("Usage: Notary.exe [filename or param=value]... where filename contains"); Console.Out.WriteLine(" lines of the form param=value and param must be one of the following."); Console.Out.WriteLine(); CommonParams.PrintUsage(); Console.Out.WriteLine(" messageLength = length of message to notarize"); } public static void ApplyArguments (string[] args) { try { foreach (string arg in args) { ApplyArgument(arg); } } catch (InvalidParameterException e) { Console.Out.WriteLine(e.contents); Parameters.PrintUsage(); Environment.Exit(-1); } } public static void ApplyArgument (string arg) { char[] splitter = {'='}; string[] sp = arg.ToLower().Split(splitter); if (sp.Length == 1) { ApplyArgumentsInFile(arg); return; } else if (sp.Length != 2) { throw new InvalidParameterException("Invalid command-line argument " + arg); } string parameter = sp[0]; string value = sp[1]; if (CommonParams.ApplyArgument(parameter, value)) { return; } if (String.Compare(parameter, "messageLength", StringComparison.OrdinalIgnoreCase) == 0) { Parameters.messageLength = Convert.ToInt32(value); return; } throw new InvalidParameterException("Invalid command-line parameter " + parameter); } public static void ApplyArgumentsInFile(string filename) { string[] args = File.ReadAllLines(filename); foreach (string arg in args) { ApplyArgument(arg); } } } } ================================================ FILE: ironclad-apps/src/Clients/Notary/Program.cs ================================================ using Common; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Net; using System.Net.Sockets; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; using System.IO; namespace Notary { class Program { static void AdvanceCounter(UdpClient client, RSACryptoServiceProvider ironclad_public_key, byte[] message, bool new_counter_value_known, ref UInt32 new_counter_value) { AdvanceCounterRequest advanceCounterRequest = new AdvanceCounterRequest(message); byte[] request = advanceCounterRequest.GetPacket(); byte[] response = CommonRoutines.SendRequest(client, request, "AdvanceCounter"); AdvanceCounterResponse advanceCounterResponse = new AdvanceCounterResponse(response, ironclad_public_key); if (new_counter_value_known && advanceCounterResponse.NewCounterValue != new_counter_value) { throw new Exception("New counter value in AdvanceCounterResponse did not match expected counter value"); } new_counter_value = advanceCounterResponse.NewCounterValue; if (!advanceCounterResponse.Message.SequenceEqual(message)) { throw new Exception("Message in AdvanceCounterResponse did not match expected message"); } } static void TestStuff() { CommonRoutines.SquirtBakedKey(); byte[] getQuoteResponseBytes = CommonRoutines.ParseFakeReply("68 05 CA 1A 1D 69 00 1B 21 31 8E D9 08 00 45 00 01 80 00 00 00 00 80 11 11 3C 0A 0A 0A 14 0A 0A 0A 0A 07 BF F4 96 01 6C 3F C7 01 00 00 00 00 00 00 00 57 00 00 01 00 00 00 00 07 73 73 68 2D 72 73 61 00 00 00 03 01 00 01 00 00 00 41 00 A9 52 43 21 04 37 54 10 11 92 9F 70 A8 D3 3B 4A 44 F3 62 C3 47 89 78 93 3E 38 D8 B8 FF 33 32 3F F8 8D 03 3B B0 D7 81 47 1A 79 75 A6 6F 38 57 D9 E7 82 9D 8D 51 7F 40 BA 50 4E 22 B5 95 95 13 B5 2A 5F C5 F6 6C F3 73 85 94 D2 72 4F A3 D9 C1 8E A9 09 7B 32 2F 38 14 FD 50 22 D1 FE B1 0B 16 CD 0B 5E D7 1B 5A CF 34 14 04 4D 49 91 25 44 A3 4C 4B 3E 01 B4 14 4F 33 FA D3 9B 84 A4 4A 23 7F 13 10 0E D4 FB EC 74 53 FD 52 62 95 8A AF D6 FC B6 DB 5B 07 43 3E 70 12 5E 71 9B 15 EB 82 81 60 01 0E A2 87 A0 86 12 E0 71 17 4E 2C 4F 4C 0E 29 57 D5 F2 73 8E 52 72 14 96 CD 19 17 60 AC D2 4C 02 5D EE D5 A7 D0 D4 14 F4 FE B0 71 8A 08 C7 86 94 0E B9 7F E9 ED E2 5C 97 30 C2 6C E0 72 2A CF EE BE 52 D1 32 48 75 00 0D 3C DA ED AA 5D 35 DC 0B B4 40 8D DB 65 F7 C1 56 54 D9 44 85 D1 1E 34 D1 17 A5 A9 41 9E 68 CD 0E 4C E1 BF 30 65 E3 0E 95 A2 46 EF A5 23 B5 5E 68 EA 1D 08 8A 12 19 57 05 34 B8 2E 71 DA 67 84 55 BB 74 92 D4 F3 B9 61 BE 56 8E D8 65 33 82 3E 7E 69 AF F1 92 59 CD 47 3F"); GetQuoteResponse gr = new GetQuoteResponse(getQuoteResponseBytes); byte[] advanceCounterResponseBytes = CommonRoutines.ParseFakeReply("68 05 CA 1A 1D 69 00 1B 21 31 8E D9 08 00 45 00 00 70 00 00 00 00 80 11 12 4C 0A 0A 0A 14 0A 0A 0A 0A 07 BF F4 96 00 5C B6 A7 02 00 00 00 00 00 00 00 07 00 00 00 40 22 00 00 00 01 01 64 03 FC D3 33 B6 D2 25 38 08 7E FD 31 E6 64 D5 A9 C0 5D 26 E1 2E 4C 97 8D AC D5 EA 6D 50 5A C6 EF 98 62 DC 4B 54 AF 32 96 E3 5D EF 96 D3 B6 83 D3 80 8F 68 EE 8F 3E 9F 7C 9C B2 EB 50 EF F4 52 3B"); AdvanceCounterResponse a = new AdvanceCounterResponse(advanceCounterResponseBytes, gr.PublicKey); while (true) { } } static void Main(string[] args) { Parameters.ApplyArguments(args); Profiler.Initialize(); UdpClient client = CommonRoutines.StartClient(); Console.Error.WriteLine("Getting Ironclad public key"); RSACryptoServiceProvider ironclad_public_key = CommonRoutines.GetIroncladPublicKey(client); /* for (UInt32 run_number = 1; run_number < CommonParams.numberOfRuns; ++run_number) { GetQuoteRequest getQuoteRequest = new GetQuoteRequest(); byte[] request = getQuoteRequest.GetPacket(); byte[] response = CommonRoutines.SendRequest(client, request, "GetIroncladPublicKey"); } */ byte[] message = new byte[Parameters.messageLength]; Random rng = new Random(); UInt32 last_counter_value = 0; for (UInt32 run_number = 0; run_number < CommonParams.numberOfRuns; ++run_number) { Console.Error.WriteLine("Performing run {0}", run_number + 1); rng.NextBytes(message); if (run_number == 0) { AdvanceCounter(client, ironclad_public_key, message, false, ref last_counter_value); } else { last_counter_value++; AdvanceCounter(client, ironclad_public_key, message, true, ref last_counter_value); } } Profiler.Print(); } } } ================================================ FILE: ironclad-apps/src/Clients/Notary/Properties/AssemblyInfo.cs ================================================ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; [assembly: AssemblyTitle("Notary")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Notary")] [assembly: AssemblyCopyright("Copyright © 2014")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] [assembly: Guid("afd3163e-a9ef-44a6-8dd6-70ecea95636c")] // // [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: ironclad-apps/src/Clients/NotarySrv/App.config ================================================  ================================================ FILE: ironclad-apps/src/Clients/NotarySrv/NotaryRequest.cs ================================================ using Common; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; namespace NotarySrv { public class NotaryRequest { public NotaryRequest() { } public static object ParseRequest (byte[] request) { if (request.Length < 1) { Console.Error.WriteLine("Received request with no bytes"); return new Common.InvalidRequest(); } if (request[0] == 1) { return Common.GetQuoteRequest.ParseRequest(request); } if (request[0] == 2) { return AdvanceCounterRequest.ParseRequest(request); } Console.Error.WriteLine("Received request with invalid type"); return new Common.InvalidRequest(); } } public class AdvanceCounterRequest { public byte[] message; public AdvanceCounterRequest(byte[] i_message) { message = i_message; } public static object ParseRequest (byte[] request) { if (request.Length < 2) { Console.Error.WriteLine("Received advance-counter request with fewer than 2 bytes"); return new Common.InvalidRequest(); } int messageLength = (int)request[1]; if (request.Length < 2 + messageLength) { Console.Error.WriteLine("Received advance-counter request without enough bytes to encode message"); return new Common.InvalidRequest(); } byte[] message = request.Skip(2).Take(messageLength).ToArray(); return new AdvanceCounterRequest(message); } } } ================================================ FILE: ironclad-apps/src/Clients/NotarySrv/NotaryResponse.cs ================================================ using Common; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace NotarySrv { class NotarySrvResponse { public static byte[] EncodeAdvanceCounterResponse (UInt32 error_code, byte[] notary_statement, byte[] notary_attestation) { byte[] header = new byte[1]; header[0] = 2; byte[] error_code_encoded = CommonRoutines.EncodeBEWord(error_code); byte[] notary_statement_length = CommonRoutines.EncodeBEWord((uint)notary_statement.Length); byte[] notary_attestation_length = CommonRoutines.EncodeBEWord((uint)notary_attestation.Length); return CommonRoutines.CombineByteArrays(header, error_code_encoded, notary_statement_length, notary_attestation_length, notary_statement, notary_attestation); } } } ================================================ FILE: ironclad-apps/src/Clients/NotarySrv/NotarySrv.csproj ================================================  Debug AnyCPU {9D47885D-EC02-4454-8D4C-B6BA048F7AF5} Exe Properties NotarySrv NotarySrv v4.5 512 AnyCPU true full false bin\Debug\ DEBUG;TRACE prompt 4 AnyCPU pdbonly true bin\Release\ TRACE prompt 4 {5e394d90-c3d6-41a1-a6b4-715e43e54d7c} Common ================================================ FILE: ironclad-apps/src/Clients/NotarySrv/Parameters.cs ================================================ using Common; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; namespace NotarySrv { class InvalidParameterException : Exception { public string contents; public InvalidParameterException(string i_contents) { contents = i_contents; } } public class Parameters { public static void Print() { CommonParams.Print(); } public static void PrintUsage() { Console.Out.WriteLine("Usage: NotarySrv.exe [filename or param=value]... where filename contains"); Console.Out.WriteLine(" lines of the form param=value and param must be one of the following."); Console.Out.WriteLine(); CommonParams.PrintUsage(); } public static void ApplyArguments (string[] args) { try { foreach (string arg in args) { ApplyArgument(arg); } } catch (InvalidParameterException e) { Console.Out.WriteLine(e.contents); Parameters.PrintUsage(); Environment.Exit(-1); } } public static void ApplyArgument (string arg) { char[] splitter = {'='}; string[] sp = arg.ToLower().Split(splitter); if (sp.Length == 1) { ApplyArgumentsInFile(arg); return; } else if (sp.Length != 2) { throw new InvalidParameterException("Invalid command-line argument " + arg); } string parameter = sp[0]; string value = sp[1]; if (CommonParams.ApplyArgument(parameter, value)) { return; } throw new InvalidParameterException("Invalid command-line parameter " + parameter); } public static void ApplyArgumentsInFile(string filename) { string[] args = File.ReadAllLines(filename); foreach (string arg in args) { ApplyArgument(arg); } } } } ================================================ FILE: ironclad-apps/src/Clients/NotarySrv/Program.cs ================================================ using Common; using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; namespace NotarySrv { class Program { static byte[] HandleRequest(byte[] request) { return new byte[0]; } static void Main(string[] args) { Parameters.ApplyArguments(args); UdpClient server = CommonRoutines.StartServer(); StateMachine stateMachine = new StateMachine(); IPEndPoint client = new IPEndPoint(IPAddress.Any, 0); while (true) { byte[] request = server.Receive(ref client); byte[] response = stateMachine.HandleRequest(request); server.Send(response, response.Length, client); } } } } ================================================ FILE: ironclad-apps/src/Clients/NotarySrv/Properties/AssemblyInfo.cs ================================================ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; [assembly: AssemblyTitle("NotarySrv")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("NotarySrv")] [assembly: AssemblyCopyright("Copyright © 2014")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] [assembly: Guid("5491bcbe-7d26-4b1b-a159-57de21b02c0f")] // // [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: ironclad-apps/src/Clients/NotarySrv/StateMachine.cs ================================================ using Common; using System; using System.Collections.Generic; using System.Linq; using System.Numerics; using System.Security.Cryptography; using System.Text; namespace NotarySrv { class StateMachine { private RSACryptoServiceProvider key_pair; private BigInteger counter; public StateMachine() { key_pair = new RSACryptoServiceProvider(CommonParams.serverKeyBits); counter = new BigInteger(0); } public byte[] HandleRequest(byte[] requestBytes) { object request = NotaryRequest.ParseRequest(requestBytes); if (request is Common.GetQuoteRequest) { GetQuoteResponse getQuoteResponse = new GetQuoteResponse(0, key_pair); return getQuoteResponse.Encode(); } if (request is AdvanceCounterRequest) { AdvanceCounterRequest r = (AdvanceCounterRequest)request; counter = counter + 1; byte[] header = new byte[1]; header[0] = 34; byte[] new_counter_value_encoding = CommonRoutines.EncodeMPBigInteger(counter); byte[] notary_statement = CommonRoutines.CombineByteArrays(header, new_counter_value_encoding, r.message); byte[] notary_attestation = key_pair.SignData(notary_statement, CryptoConfig.MapNameToOID("SHA256")); return NotarySrvResponse.EncodeAdvanceCounterResponse(0, notary_statement, notary_attestation); } return InvalidResponse.Encode(); } } } ================================================ FILE: ironclad-apps/src/Clients/PassHash/App.config ================================================  ================================================ FILE: ironclad-apps/src/Clients/PassHash/Parameters.cs ================================================ using Common; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; namespace PassHash { class InvalidParameterException : Exception { public string contents; public InvalidParameterException(string i_contents) { contents = i_contents; } } public class Parameters { public static int passwordLength = 12; public static int saltLength = 16; public static void Print() { CommonParams.Print(); Console.Error.WriteLine("passwordLength\t{0}", passwordLength); Console.Error.WriteLine("saltLength\t{0}", saltLength); } public static void PrintUsage() { Console.Out.WriteLine("Usage: PassHash.exe [filename or param=value]... where filename contains"); Console.Out.WriteLine(" lines of the form param=value and param must be one of the following."); Console.Out.WriteLine(); CommonParams.PrintUsage(); Console.Out.WriteLine(" passwordLength = length of password to use"); Console.Out.WriteLine(" saltLength = length of salt to use"); } public static void ApplyArguments (string[] args) { try { foreach (string arg in args) { ApplyArgument(arg); } } catch (InvalidParameterException e) { Console.Out.WriteLine(e.contents); Parameters.PrintUsage(); Environment.Exit(-1); } } public static void ApplyArgument (string arg) { char[] splitter = {'='}; string[] sp = arg.ToLower().Split(splitter); if (sp.Length == 1) { ApplyArgumentsInFile(arg); return; } else if (sp.Length != 2) { throw new InvalidParameterException("Invalid command-line argument " + arg); } string parameter = sp[0]; string value = sp[1]; if (CommonParams.ApplyArgument(parameter, value)) { return; } if (String.Compare(parameter, "passwordLength", StringComparison.OrdinalIgnoreCase) == 0) { Parameters.passwordLength = Convert.ToInt32(value); return; } if (String.Compare(parameter, "saltLength", StringComparison.OrdinalIgnoreCase) == 0) { Parameters.saltLength = Convert.ToInt32(value); return; } throw new InvalidParameterException("Invalid command-line parameter " + parameter); } public static void ApplyArgumentsInFile(string filename) { string[] args = File.ReadAllLines(filename); foreach (string arg in args) { ApplyArgument(arg); } } } } ================================================ FILE: ironclad-apps/src/Clients/PassHash/PassHash.csproj ================================================  Debug AnyCPU {92AFE843-D88C-4A62-8159-B8C5EEDB5171} Exe Properties PassHash PassHash v4.5 512 AnyCPU true full false bin\Debug\ DEBUG;TRACE prompt 4 AnyCPU pdbonly true bin\Release\ TRACE prompt 4 {5e394d90-c3d6-41a1-a6b4-715e43e54d7c} Common ================================================ FILE: ironclad-apps/src/Clients/PassHash/PassHashRequests.cs ================================================ using Common; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace PassHash { public class PerformHashRequest { private byte[] message; private byte[] salt; public PerformHashRequest(byte[] i_message, byte[] i_salt) { message = i_message; salt = i_salt; } public byte[] GetPacket() { byte[] header = new byte[1]; header[0] = 1; byte[] message_length_encoded = CommonRoutines.EncodeBEWord((UInt32)message.Length); byte[] salt_length_encoded = CommonRoutines.EncodeBEWord((UInt32)salt.Length); return CommonRoutines.CombineByteArrays(header, message_length_encoded, salt_length_encoded, message, salt); } } } ================================================ FILE: ironclad-apps/src/Clients/PassHash/PassHashResponses.cs ================================================ using Common; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace PassHash { class PerformHashResponse { private UInt32 error_code; private byte[] hash; public UInt32 ErrorCode { get { return error_code; } } public PerformHashResponse(byte[] packet) { if (packet.Length < 37) { throw new Exception("Invalid PerformHashResponsePacket -- length < 37"); } if (packet[0] != 1) { throw new Exception("First byte of PerformHashResponse is not 1"); } error_code = CommonRoutines.ExtractBEWord(packet, 1); if (error_code != 0) { throw new ErrorCodeException(error_code); } hash = packet.Skip(5).Take(32).ToArray(); } public override string ToString() { return string.Format("PerformHashResponse(error_code={0}", error_code); } } } ================================================ FILE: ironclad-apps/src/Clients/PassHash/Program.cs ================================================ using Common; using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; namespace PassHash { class Program { static void PerformHash(UdpClient client, byte[] password, byte[] salt) { PerformHashRequest performHashRequest = new PerformHashRequest(password, salt); byte[] request = performHashRequest.GetPacket(); byte[] response = CommonRoutines.SendRequest(client, request, "PerformHash"); PerformHashResponse performHashResponse = new PerformHashResponse(response); } static void Main(string[] args) { Parameters.ApplyArguments(args); Profiler.Initialize(); UdpClient client = CommonRoutines.StartClient(); byte[] password = new byte[Parameters.passwordLength]; byte[] salt = new byte[Parameters.saltLength]; Random rng = new Random(); for (UInt32 run_number = 0; run_number < CommonParams.numberOfRuns; ++run_number) { Console.Error.WriteLine("Performing run {0}", run_number + 1); rng.NextBytes(password); rng.NextBytes(salt); PerformHash(client, password, salt); } Profiler.Print(); } } } ================================================ FILE: ironclad-apps/src/Clients/PassHash/Properties/AssemblyInfo.cs ================================================ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; [assembly: AssemblyTitle("PassHash")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("PassHash")] [assembly: AssemblyCopyright("Copyright © 2014")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] [assembly: Guid("2e4bc7a9-7cd9-4eb1-bfb4-2be444a47b3c")] // // [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: ironclad-apps/src/Clients/PassHashSrv/App.config ================================================  ================================================ FILE: ironclad-apps/src/Clients/PassHashSrv/Parameters.cs ================================================ using Common; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; namespace PassHashSrv { class InvalidParameterException : Exception { public string contents; public InvalidParameterException(string i_contents) { contents = i_contents; } } public class Parameters { public static int secretLength = 32; public static void Print() { CommonParams.Print(); Console.Error.WriteLine("secretLength\t{0}", secretLength); } public static void PrintUsage() { Console.Out.WriteLine("Usage: PassHashSrv.exe [filename or param=value]... where filename contains"); Console.Out.WriteLine(" lines of the form param=value and param must be one of the following."); Console.Out.WriteLine(); CommonParams.PrintUsage(); Console.Out.WriteLine(" secretLength = length of secret to use"); } public static void ApplyArguments (string[] args) { try { foreach (string arg in args) { ApplyArgument(arg); } } catch (InvalidParameterException e) { Console.Out.WriteLine(e.contents); Parameters.PrintUsage(); Environment.Exit(-1); } } public static void ApplyArgument (string arg) { char[] splitter = {'='}; string[] sp = arg.ToLower().Split(splitter); if (sp.Length == 1) { ApplyArgumentsInFile(arg); return; } else if (sp.Length != 2) { throw new InvalidParameterException("Invalid command-line argument " + arg); } string parameter = sp[0]; string value = sp[1]; if (CommonParams.ApplyArgument(parameter, value)) { return; } if (String.Compare(parameter, "secretLength", StringComparison.OrdinalIgnoreCase) == 0) { Parameters.secretLength = Convert.ToInt32(value); return; } throw new InvalidParameterException("Invalid command-line parameter " + parameter); } public static void ApplyArgumentsInFile(string filename) { string[] args = File.ReadAllLines(filename); foreach (string arg in args) { ApplyArgument(arg); } } } } ================================================ FILE: ironclad-apps/src/Clients/PassHashSrv/PassHashRequest.cs ================================================ using Common; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; namespace PassHashSrv { public class PassHashRequest { public PassHashRequest() { } public static PassHashRequest ParseRequest (byte[] request) { if (request.Length < 1) { Console.Error.WriteLine("Received request with no bytes"); return new InvalidRequest(); } if (request[0] == 1) { return PerformHashRequest.ParsePassHashRequest(request); } Console.Error.WriteLine("Received request with invalid type"); return new InvalidRequest(); } } public class InvalidRequest : PassHashRequest { public InvalidRequest() { } } public class PerformHashRequest : PassHashRequest { public byte[] message; public byte[] salt; public PerformHashRequest(byte[] i_message, byte[] i_salt) { message = i_message; salt = i_salt; } public static PassHashRequest ParsePassHashRequest (byte[] request) { if (request.Length < 9) { Console.Error.WriteLine("Received perform-hash request with fewer than 9 bytes"); return new InvalidRequest(); } int messageLength = (int)CommonRoutines.ExtractBEWord(request, 1); int saltLength = (int)CommonRoutines.ExtractBEWord(request, 5); if (request.Length < 9 + messageLength + saltLength) { Console.Error.WriteLine("Received perform-hash request without enough bytes to encode message and salt"); return new InvalidRequest(); } byte[] message = request.Skip(9).Take(messageLength).ToArray(); byte[] salt = request.Skip(9 + messageLength).Take(saltLength).ToArray(); return new PerformHashRequest(message, salt); } } } ================================================ FILE: ironclad-apps/src/Clients/PassHashSrv/PassHashResponse.cs ================================================ using Common; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace PassHashSrv { class PassHashResponse { public static byte[] EncodePerformHashResponse (UInt32 errorCode, byte[] hash) { if (hash.Length != 32) { throw new Exception("Tried to encode hash not of length 32 bytes"); } byte[] response = new byte[37]; response[0] = 1; byte[] encodedErrorCode = CommonRoutines.EncodeBEWord(errorCode); Array.Copy(encodedErrorCode, 0, response, 1, 4); Array.Copy(hash, 0, response, 5, 32); return response; } } } ================================================ FILE: ironclad-apps/src/Clients/PassHashSrv/PassHashSrv.csproj ================================================  Debug AnyCPU {49E13550-3EC8-4FCC-AE5D-CBD278A33B20} Exe Properties PassHashSrv PassHashSrv v4.5 512 AnyCPU true full false bin\Debug\ DEBUG;TRACE prompt 4 AnyCPU pdbonly true bin\Release\ TRACE prompt 4 {5e394d90-c3d6-41a1-a6b4-715e43e54d7c} Common ================================================ FILE: ironclad-apps/src/Clients/PassHashSrv/Program.cs ================================================ using Common; using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; namespace PassHashSrv { class Program { static byte[] HandleRequest(byte[] request) { return new byte[0]; } static void Main(string[] args) { Parameters.ApplyArguments(args); UdpClient server = CommonRoutines.StartServer(); StateMachine stateMachine = new StateMachine(); IPEndPoint client = new IPEndPoint(IPAddress.Any, 0); while (true) { byte[] request = server.Receive(ref client); byte[] response = stateMachine.HandleRequest(request); server.Send(response, response.Length, client); } } } } ================================================ FILE: ironclad-apps/src/Clients/PassHashSrv/Properties/AssemblyInfo.cs ================================================ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; [assembly: AssemblyTitle("PassHashSrv")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("PassHashSrv")] [assembly: AssemblyCopyright("Copyright © 2014")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] [assembly: Guid("71784f06-0d20-461f-a4bb-4beb266e8e50")] // // [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: ironclad-apps/src/Clients/PassHashSrv/StateMachine.cs ================================================ using Common; using System; using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; using System.Text; namespace PassHashSrv { class StateMachine { private byte[] secret; private SHA256 hasher; public StateMachine() { secret = new byte[Parameters.secretLength]; Random rng = new Random(); rng.NextBytes(secret); hasher = new SHA256Managed(); } public byte[] HandleRequest(byte[] requestBytes) { PassHashRequest request = PassHashRequest.ParseRequest(requestBytes); if (request is PerformHashRequest) { PerformHashRequest performHashRequest = (PerformHashRequest)request; byte[] message = performHashRequest.message; byte[] salt = performHashRequest.salt; byte[] mashup = CommonRoutines.CombineByteArrays(secret, salt, message); byte[] hash = hasher.ComputeHash(mashup); return PassHashResponse.EncodePerformHashResponse(0, hash); } else { return Common.InvalidResponse.Encode(); } } } } ================================================ FILE: ironclad-apps/src/Clients/TrInc/App.config ================================================  ================================================ FILE: ironclad-apps/src/Clients/TrInc/Parameters.cs ================================================ using Common; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; namespace TrInc { class InvalidParameterException : Exception { public string contents; public InvalidParameterException(string i_contents) { contents = i_contents; } } public class Parameters { public static int messageLength = 32; public static int publicKeyBits = 2048; public static void Print() { CommonParams.Print(); Console.Error.WriteLine("messageLength\t{0}", messageLength); Console.Error.WriteLine("publicKeyBits\t{0}", publicKeyBits); } public static void PrintUsage() { Console.Out.WriteLine("Usage: TrInc.exe [filename or param=value]... where filename contains"); Console.Out.WriteLine(" lines of the form param=value and param must be one of the following."); Console.Out.WriteLine(); CommonParams.PrintUsage(); Console.Out.WriteLine(" messageLength = length of message to attest"); Console.Out.WriteLine(" publicKeyBits = bits in our counter's public key"); } public static void ApplyArguments (string[] args) { try { foreach (string arg in args) { ApplyArgument(arg); } } catch (InvalidParameterException e) { Console.Out.WriteLine(e.contents); Parameters.PrintUsage(); Environment.Exit(-1); } } public static void ApplyArgument (string arg) { char[] splitter = {'='}; string[] sp = arg.ToLower().Split(splitter); if (sp.Length == 1) { ApplyArgumentsInFile(arg); return; } else if (sp.Length != 2) { throw new InvalidParameterException("Invalid command-line argument " + arg); } string parameter = sp[0]; string value = sp[1]; if (CommonParams.ApplyArgument(parameter, value)) { return; } if (String.Compare(parameter, "messageLength", StringComparison.OrdinalIgnoreCase) == 0) { Parameters.messageLength = Convert.ToInt32(value); return; } if (String.Compare(parameter, "publicKeyBits", StringComparison.OrdinalIgnoreCase) == 0) { Parameters.publicKeyBits = Convert.ToInt32(value); return; } if (String.Compare(parameter, "numberOfRuns", StringComparison.OrdinalIgnoreCase) == 0) { CommonParams.numberOfRuns = Convert.ToInt32(value); return; } if (String.Compare(parameter, "ignoreKey", StringComparison.OrdinalIgnoreCase) == 0) { CommonParams.ignoreKey = Convert.ToInt32(value) != 0; return; } throw new InvalidParameterException("Invalid command-line parameter " + parameter); } public static void ApplyArgumentsInFile(string filename) { string[] args = File.ReadAllLines(filename); foreach (string arg in args) { ApplyArgument(arg); } } } } ================================================ FILE: ironclad-apps/src/Clients/TrInc/Program.cs ================================================ using Common; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Net.Sockets; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; namespace TrInc { class Program { static RSACryptoServiceProvider CreateNewCounter(UdpClient client, bool counter_index_known, ref UInt32 counter_index) { CreateCounterRequest createCounterRequest = new CreateCounterRequest(Parameters.publicKeyBits); byte[] request = createCounterRequest.GetPacket(); byte[] response = CommonRoutines.SendRequest(client, request, "CreateNewCounter"); CreateCounterResponse createCounterResponse = new CreateCounterResponse(response); if (counter_index_known && createCounterResponse.CounterIndex != counter_index) { throw new Exception("New counter index in CreateNewCounterResponse did not match expected counter index"); } counter_index = createCounterResponse.CounterIndex; return createCounterRequest.KeyPair; } static void AdvanceCounter(UdpClient client, RSACryptoServiceProvider ironclad_public_key, RSACryptoServiceProvider counter_key_pair, SHA256Managed hasher, UInt32 counter_index, byte[] message, UInt32 old_counter_value, UInt32 new_counter_value) { AdvanceCounterRequest advanceCounterRequest = new AdvanceCounterRequest(counter_index, new_counter_value, message, counter_key_pair); byte[] request = advanceCounterRequest.GetPacket(hasher); byte[] response = CommonRoutines.SendRequest(client, request, "AdvanceCounter"); AdvanceCounterResponse advanceCounterResponse = new AdvanceCounterResponse(response, ironclad_public_key); if (advanceCounterResponse.OldCounterValue != old_counter_value) { throw new Exception("AdvanceCounter statement had wrong old counter value"); } if (advanceCounterResponse.NewCounterValue != new_counter_value) { throw new Exception("AdvanceCounter statement had wrong new counter value"); } if (!advanceCounterResponse.Message.SequenceEqual(message)) { throw new Exception("AdvanceCounter statement had wrong message"); } } static void Main(string[] args) { Parameters.ApplyArguments(args); Profiler.Initialize(); UdpClient client = CommonRoutines.StartClient(); Console.Error.WriteLine("Getting Ironclad public key"); RSACryptoServiceProvider ironclad_public_key = CommonRoutines.GetIroncladPublicKey(client); Console.Error.WriteLine("Creating TrInc counter for advancing runs"); UInt32 counter_index = 0; RSACryptoServiceProvider counter_key_pair = CreateNewCounter(client, false, ref counter_index); Console.Error.WriteLine("Advancing counter {0}", counter_index); byte[] message = new byte[Parameters.messageLength]; Random rng = new Random(); SHA256Managed hasher = new SHA256Managed(); for (UInt32 counter_value = 0; counter_value < CommonParams.numberOfRuns; ++counter_value) { Console.Error.WriteLine("Performing advance-counter run {0}", counter_value + 1); rng.NextBytes(message); AdvanceCounter(client, ironclad_public_key, counter_key_pair, hasher, counter_index, message, counter_value, counter_value + 1); } Console.Error.WriteLine("Creating new counters"); for (UInt32 run_number = 0; run_number < CommonParams.numberOfRuns; ++run_number) { Console.Error.WriteLine("Performing create-counter run {0}", run_number + 1); ++counter_index; RSACryptoServiceProvider new_counter_key_pair = CreateNewCounter(client, true, ref counter_index); } Profiler.Print(); } } } ================================================ FILE: ironclad-apps/src/Clients/TrInc/Properties/AssemblyInfo.cs ================================================ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; [assembly: AssemblyTitle("TrInc")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("TrInc")] [assembly: AssemblyCopyright("Copyright © 2014")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] [assembly: Guid("9dfc9946-9439-416d-85dc-ef059cf7f824")] // // [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: ironclad-apps/src/Clients/TrInc/TrInc.csproj ================================================  Debug AnyCPU {EC3E5C90-B0FD-44CE-883C-1BA3FC896C02} Exe Properties TrInc TrInc v4.5 512 AnyCPU true full false bin\Debug\ DEBUG;TRACE prompt 4 AnyCPU pdbonly true bin\Release\ TRACE prompt 4 {5e394d90-c3d6-41a1-a6b4-715e43e54d7c} Common ================================================ FILE: ironclad-apps/src/Clients/TrInc/TrIncRequests.cs ================================================ using Common; using System; using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; namespace TrInc { public class CreateCounterRequest { private int key_size; private RSACryptoServiceProvider key_pair; public RSACryptoServiceProvider KeyPair { get { return key_pair; } } public CreateCounterRequest(int i_key_size) { key_size = i_key_size; key_pair = new RSACryptoServiceProvider(key_size); } public byte[] GetPacket() { byte[] header = new byte[1]; header[0] = 2; byte[] encoded_public_key = CommonRoutines.EncodePublicKey(key_pair); byte[] encoded_public_key_length = CommonRoutines.EncodeBEWord((UInt32)encoded_public_key.Length); return CommonRoutines.CombineByteArrays(header, encoded_public_key_length, encoded_public_key); } } public class AdvanceCounterRequest { private UInt32 counter_index; private UInt32 new_counter_value; private byte[] message; private RSACryptoServiceProvider key_pair; public AdvanceCounterRequest(UInt32 i_counter_index, UInt32 i_new_counter_value, byte[] i_message, RSACryptoServiceProvider i_key_pair) { counter_index = i_counter_index; new_counter_value = i_new_counter_value; message = i_message; key_pair = i_key_pair; } public byte[] GetPacket(SHA256Managed hasher) { byte[] header = new byte[1]; header[0] = 3; byte[] counter_index_encoded = CommonRoutines.EncodeBEWord(counter_index); byte[] new_counter_value_encoded = CommonRoutines.EncodeMPInt(new_counter_value); byte[] new_counter_value_length_encoded = CommonRoutines.EncodeBEWord((UInt32)new_counter_value_encoded.Length); byte[] message_length_encoded = CommonRoutines.EncodeBEWord((UInt32) message.Length); byte[] request = CommonRoutines.CombineByteArrays(new_counter_value_encoded, message); byte[] request_attestation = key_pair.SignData(request, CryptoConfig.MapNameToOID("SHA256")); byte[] request_attestation_length_encoded = CommonRoutines.EncodeBEWord((UInt32)request_attestation.Length); return CommonRoutines.CombineByteArrays(header, counter_index_encoded, new_counter_value_length_encoded, message_length_encoded, request_attestation_length_encoded, new_counter_value_encoded, message, request_attestation); } } } ================================================ FILE: ironclad-apps/src/Clients/TrInc/TrIncResponses.cs ================================================ using Common; using System; using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; namespace TrInc { class CreateCounterResponse { private UInt32 error_code; private UInt32 counter_index; public UInt32 CounterIndex { get { return counter_index; } } public UInt32 ErrorCode { get { return error_code; } } public CreateCounterResponse(byte[] packet) { if (packet.Length < 9) { throw new Exception("Invalid CreateCounterResponsePacket -- length < 9"); } if (packet[0] != 2) { throw new Exception("First byte of CreateCounterResponse is not 2"); } error_code = CommonRoutines.ExtractBEWord(packet, 1); if (error_code != 0) { throw new ErrorCodeException(error_code); } counter_index = CommonRoutines.ExtractBEWord(packet, 5); } public override string ToString() { return string.Format("CreateCounterResponse(error_code={0}, counter_index={1})", error_code, counter_index); } } class AdvanceCounterResponse { private UInt32 error_code; private UInt32 counter_index; private UInt32 old_counter_value; private UInt32 new_counter_value; private byte[] message; public UInt32 ErrorCode { get { return error_code; } } public UInt32 CounterIndex { get { return counter_index; } } public UInt32 OldCounterValue { get { return old_counter_value; } } public UInt32 NewCounterValue { get { return new_counter_value; } } public byte[] Message { get { return message; } } public AdvanceCounterResponse(byte[] packet, RSACryptoServiceProvider ironclad_public_key) { if (packet.Length < 13) { throw new Exception("Invalid AdvanceCounterResponsePacket -- length < 13"); } if (packet[0] != 3) { throw new Exception("First byte of AdvanceCounterResponse is not 3"); } error_code = CommonRoutines.ExtractBEWord(packet, 1); if (error_code != 0) { throw new ErrorCodeException(error_code); } int trinc_statement_length = (int)CommonRoutines.ExtractBEWord(packet, 5); int trinc_attestation_length = (int)CommonRoutines.ExtractBEWord(packet, 9); byte[] trinc_statement = packet.Skip(13).Take(trinc_statement_length).ToArray(); byte[] trinc_attestation = packet.Skip(13 + trinc_statement_length).Take(trinc_attestation_length).ToArray(); if (trinc_statement.Length < 1) { throw new Exception("TrInc statement too short"); } if (trinc_statement[0] != 34) { throw new Exception("TrInc statement does not start with magic byte 34"); } counter_index = CommonRoutines.ExtractBEWord(trinc_statement, 1); int offset = 5; old_counter_value = CommonRoutines.DecodeShortMPInt(trinc_statement, ref offset); new_counter_value = CommonRoutines.DecodeShortMPInt(trinc_statement, ref offset); message = trinc_statement.Skip(offset).ToArray(); if (!CommonParams.ignoreKey && !ironclad_public_key.VerifyData(trinc_statement, CryptoConfig.MapNameToOID("SHA256"), trinc_attestation)) { throw new Exception("Could not verify signature of TrInc statement"); } } public override string ToString() { return string.Format("AdvanceCounterResponse(error_code={0}", error_code); } } } ================================================ FILE: ironclad-apps/src/Clients/TrIncSrv/App.config ================================================  ================================================ FILE: ironclad-apps/src/Clients/TrIncSrv/Parameters.cs ================================================ using Common; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; namespace TrIncSrv { class InvalidParameterException : Exception { public string contents; public InvalidParameterException(string i_contents) { contents = i_contents; } } public class Parameters { public static void Print() { CommonParams.Print(); } public static void PrintUsage() { Console.Out.WriteLine("Usage: TrIncSrv.exe [filename or param=value]... where filename contains"); Console.Out.WriteLine(" lines of the form param=value and param must be one of the following."); Console.Out.WriteLine(); CommonParams.PrintUsage(); } public static void ApplyArguments (string[] args) { try { foreach (string arg in args) { ApplyArgument(arg); } } catch (InvalidParameterException e) { Console.Out.WriteLine(e.contents); Parameters.PrintUsage(); Environment.Exit(-1); } } public static void ApplyArgument (string arg) { char[] splitter = {'='}; string[] sp = arg.ToLower().Split(splitter); if (sp.Length == 1) { ApplyArgumentsInFile(arg); return; } else if (sp.Length != 2) { throw new InvalidParameterException("Invalid command-line argument " + arg); } string parameter = sp[0]; string value = sp[1]; if (CommonParams.ApplyArgument(parameter, value)) { return; } throw new InvalidParameterException("Invalid command-line parameter " + parameter); } public static void ApplyArgumentsInFile(string filename) { string[] args = File.ReadAllLines(filename); foreach (string arg in args) { ApplyArgument(arg); } } } } ================================================ FILE: ironclad-apps/src/Clients/TrIncSrv/Program.cs ================================================ using Common; using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; namespace TrIncSrv { class Program { static byte[] HandleRequest(byte[] request) { return new byte[0]; } static void Main(string[] args) { Parameters.ApplyArguments(args); UdpClient server = CommonRoutines.StartServer(); StateMachine stateMachine = new StateMachine(); IPEndPoint client = new IPEndPoint(IPAddress.Any, 0); while (true) { byte[] request = server.Receive(ref client); byte[] response = stateMachine.HandleRequest(request); server.Send(response, response.Length, client); } } } } ================================================ FILE: ironclad-apps/src/Clients/TrIncSrv/Properties/AssemblyInfo.cs ================================================ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; [assembly: AssemblyTitle("TrIncSrv")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("TrIncSrv")] [assembly: AssemblyCopyright("Copyright © 2014")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] [assembly: Guid("8abf08df-e907-4fcc-a116-745c4a62caa6")] // // [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: ironclad-apps/src/Clients/TrIncSrv/StateMachine.cs ================================================ using Common; using System; using System.Collections.Generic; using System.Linq; using System.Numerics; using System.Security.Cryptography; using System.Text; namespace TrIncSrv { class TrIncCounter { private RSACryptoServiceProvider public_key; private BigInteger counter; public RSACryptoServiceProvider PublicKey { get { return public_key; } } public BigInteger Value { get { return counter; } set { counter = value; } } public TrIncCounter(RSACryptoServiceProvider i_public_key) { public_key = i_public_key; counter = new BigInteger(0); } } class StateMachine { private RSACryptoServiceProvider key_pair; private List counters; private SHA256Managed hasher; public StateMachine() { key_pair = new RSACryptoServiceProvider(CommonParams.serverKeyBits); counters = new List(); hasher = new SHA256Managed(); } public byte[] HandleRequest(byte[] requestBytes) { object request = TrIncRequest.ParseRequest(requestBytes); if (request is Common.GetQuoteRequest) { GetQuoteResponse getQuoteResponse = new GetQuoteResponse(0, key_pair); return getQuoteResponse.Encode(); } if (request is CreateCounterRequest) { CreateCounterRequest r = (CreateCounterRequest)request; RSACryptoServiceProvider public_key = CommonRoutines.DecodePublicKey(r.public_key); if (public_key == null) { return TrIncSrvResponse.EncodeCreateCounterResponse(3, 0); } TrIncCounter counter = new TrIncCounter(public_key); counters.Add(counter); UInt32 counter_index = (UInt32)(counters.Count - 1); return TrIncSrvResponse.EncodeCreateCounterResponse(0, counter_index); } if (request is AdvanceCounterRequest) { AdvanceCounterRequest r = (AdvanceCounterRequest)request; if (r.counter_index < 0 || r.counter_index >= counters.Count) { Console.Error.WriteLine("Received request for invalid counter index {0}", r.counter_index); return TrIncSrvResponse.EncodeAdvanceCounterResponse(1, new byte[0], new byte[0]); } TrIncCounter counter = counters[(int)r.counter_index]; byte[] req = CommonRoutines.CombineByteArrays(r.new_counter_value, r.message); if (!counter.PublicKey.VerifyData(req, CryptoConfig.MapNameToOID("SHA256"), r.request_attestation)) { Console.Error.WriteLine("Received invalid request attestation"); return TrIncSrvResponse.EncodeAdvanceCounterResponse(5, new byte[0], new byte[0]); } int offset = 0; BigInteger new_counter_value = CommonRoutines.DecodeMPBigInteger(r.new_counter_value, ref offset); if (new_counter_value < 0 || offset != r.new_counter_value.Length) { Console.Error.WriteLine("Received invalid new counter value encoding"); return TrIncSrvResponse.EncodeAdvanceCounterResponse(6, new byte[0], new byte[0]); } if (new_counter_value < counter.Value) { Console.Error.WriteLine("New counter value requested {0} is smaller than current counter value {1}", new_counter_value, counter.Value); return TrIncSrvResponse.EncodeAdvanceCounterResponse(7, new byte[0], new byte[0]); } BigInteger old_counter_value = counter.Value; counter.Value = new_counter_value; byte[] header = new byte[1]; header[0] = 34; byte[] counter_index_encoding = CommonRoutines.EncodeBEWord(r.counter_index); byte[] old_counter_value_encoding = CommonRoutines.EncodeMPBigInteger(old_counter_value); byte[] new_counter_value_encoding = CommonRoutines.EncodeMPBigInteger(new_counter_value); byte[] trinc_statement = CommonRoutines.CombineByteArrays(header, counter_index_encoding, old_counter_value_encoding, new_counter_value_encoding, r.message); byte[] trinc_attestation = key_pair.SignData(trinc_statement, CryptoConfig.MapNameToOID("SHA256")); return TrIncSrvResponse.EncodeAdvanceCounterResponse(0, trinc_statement, trinc_attestation); } return InvalidResponse.Encode(); } } } ================================================ FILE: ironclad-apps/src/Clients/TrIncSrv/TrIncRequest.cs ================================================ using Common; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; namespace TrIncSrv { public class TrIncRequest { public TrIncRequest() { } public static object ParseRequest (byte[] request) { if (request.Length < 1) { Console.Error.WriteLine("Received request with no bytes"); return new Common.InvalidRequest(); } if (request[0] == 1) { return Common.GetQuoteRequest.ParseRequest(request); } if (request[0] == 2) { return CreateCounterRequest.ParseRequest(request); } if (request[0] == 3) { return AdvanceCounterRequest.ParseRequest(request); } Console.Error.WriteLine("Received request with invalid type"); return new Common.InvalidRequest(); } } public class CreateCounterRequest { public byte[] public_key; public CreateCounterRequest(byte[] i_public_key) { public_key = i_public_key; } public static object ParseRequest (byte[] request) { if (request.Length < 5) { Console.Error.WriteLine("Received create-counter request with fewer than 5 bytes"); return new Common.InvalidRequest(); } int public_key_length = (int)CommonRoutines.ExtractBEWord(request, 1); if (request.Length < 5 + public_key_length) { Console.Error.WriteLine("Received create-counter request without enough bytes to encode public key"); return new Common.InvalidRequest(); } byte[] public_key = request.Skip(5).Take(public_key_length).ToArray(); return new CreateCounterRequest(public_key); } } public class AdvanceCounterRequest { public UInt32 counter_index; public byte[] new_counter_value; public byte[] message; public byte[] request_attestation; public AdvanceCounterRequest(UInt32 i_counter_index, byte[] i_new_counter_value, byte[] i_message, byte[] i_request_attestation) { counter_index = i_counter_index; new_counter_value = i_new_counter_value; message = i_message; request_attestation = i_request_attestation; } public static object ParseRequest (byte[] request) { if (request.Length < 17) { Console.Error.WriteLine("Received advance-counter request with fewer than 17 bytes"); return new Common.InvalidRequest(); } UInt32 counter_index = CommonRoutines.ExtractBEWord(request, 1); int new_counter_len = (int)CommonRoutines.ExtractBEWord(request, 5); int message_len = (int)CommonRoutines.ExtractBEWord(request, 9); int request_attestation_len = (int)CommonRoutines.ExtractBEWord(request, 13); if (request.Length < 17 + new_counter_len + message_len + request_attestation_len) { Console.Error.WriteLine("Received advance-counter request without enough bytes to encode all fields"); return new Common.InvalidRequest(); } byte[] new_counter_value = request.Skip(17).Take(new_counter_len).ToArray(); byte[] message = request.Skip(17 + new_counter_len).Take(message_len).ToArray(); byte[] request_attestation = request.Skip(17 + new_counter_len + message_len).Take(request_attestation_len).ToArray(); return new AdvanceCounterRequest(counter_index, new_counter_value, message, request_attestation); } } } ================================================ FILE: ironclad-apps/src/Clients/TrIncSrv/TrIncResponse.cs ================================================ using Common; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace TrIncSrv { class TrIncSrvResponse { public static byte[] EncodeCreateCounterResponse (UInt32 error_code, UInt32 counter_index) { byte[] header = new byte[1]; header[0] = 2; byte[] error_code_encoded = CommonRoutines.EncodeBEWord(error_code); byte[] counter_index_encoded = CommonRoutines.EncodeBEWord((uint)counter_index); return CommonRoutines.CombineByteArrays(header, error_code_encoded, counter_index_encoded); } public static byte[] EncodeAdvanceCounterResponse (UInt32 error_code, byte[] trinc_statement, byte[] trinc_attestation) { byte[] header = new byte[1]; header[0] = 3; byte[] error_code_encoded = CommonRoutines.EncodeBEWord(error_code); byte[] trinc_statement_length = CommonRoutines.EncodeBEWord((uint)trinc_statement.Length); byte[] trinc_attestation_length = CommonRoutines.EncodeBEWord((uint)trinc_attestation.Length); return CommonRoutines.CombineByteArrays(header, error_code_encoded, trinc_statement_length, trinc_attestation_length, trinc_statement, trinc_attestation); } } } ================================================ FILE: ironclad-apps/src/Clients/TrIncSrv/TrIncSrv.csproj ================================================  Debug AnyCPU {B99001E4-00B2-4A1B-A1D6-8B4773C0F5FB} Exe Properties TrIncSrv TrIncSrv v4.5 512 AnyCPU true full false bin\Debug\ DEBUG;TRACE prompt 4 AnyCPU pdbonly true bin\Release\ TRACE prompt 4 {5e394d90-c3d6-41a1-a6b4-715e43e54d7c} Common ================================================ FILE: ironclad-apps/src/Clients/UdpEchoClient/App.config ================================================ ================================================ FILE: ironclad-apps/src/Clients/UdpEchoClient/Program.cs ================================================ using System; using System.Net; using System.Net.Sockets; using System.Text; namespace UdpEchoClient { class Program { static void Main(string[] Args) { UdpClient Client = null; ASCIIEncoding asciiEncoding = new ASCIIEncoding(); if (Args.Length > 0) { Client = new UdpClient(Args[0], 7); if (Args.Length == 1) { String Line = null; IPEndPoint RemoteEndpoint = null; do { Console.Write("Send: "); Line = Console.ReadLine(); if (Line != null) { byte[] Data = asciiEncoding.GetBytes(Line); Client.Send(Data, Data.Length); Data = Client.Receive(ref RemoteEndpoint); Console.WriteLine("Received: " + asciiEncoding.GetString(Data)); } } while (Line != null); } else if (Args.Length == 2) { byte[] Data = asciiEncoding.GetBytes(Args[1]); Client.Send(Data, Data.Length); } else { Usage(); } } else { Usage(); } } static void Usage() { Console.WriteLine("Usage: UdpEchoClient []"); } } } ================================================ FILE: ironclad-apps/src/Clients/UdpEchoClient/Properties/AssemblyInfo.cs ================================================ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; [assembly: AssemblyTitle("UdpEchoClient")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("UdpEchoClient")] [assembly: AssemblyCopyright("Copyright © 2014")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] [assembly: Guid("31275927-e376-4e31-ba3f-9c027b40dc70")] // // [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: ironclad-apps/src/Clients/UdpEchoClient/UdpEchoClient.csproj ================================================  Debug AnyCPU {FA18D21B-EB2B-4ACE-B4A7-BC77D3836077} Exe Properties UdpEchoClient UdpEchoClient v4.0 512 AnyCPU true full false bin\Debug\ DEBUG;TRACE prompt 4 AnyCPU pdbonly true bin\Release\ TRACE prompt 4 true bin\x86\Debug\ DEBUG;TRACE full x86 prompt MinimumRecommendedRules.ruleset true bin\x86\Release\ TRACE true pdbonly x86 prompt MinimumRecommendedRules.ruleset true ================================================ FILE: ironclad-apps/src/Clients/UdpEchoClient.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0.30110.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UdpEchoClient", "UdpEchoClient\UdpEchoClient.csproj", "{FA18D21B-EB2B-4ACE-B4A7-BC77D3836077}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {FA18D21B-EB2B-4ACE-B4A7-BC77D3836077}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {FA18D21B-EB2B-4ACE-B4A7-BC77D3836077}.Debug|Any CPU.Build.0 = Debug|Any CPU {FA18D21B-EB2B-4ACE-B4A7-BC77D3836077}.Debug|x86.ActiveCfg = Debug|x86 {FA18D21B-EB2B-4ACE-B4A7-BC77D3836077}.Debug|x86.Build.0 = Debug|x86 {FA18D21B-EB2B-4ACE-B4A7-BC77D3836077}.Release|Any CPU.ActiveCfg = Release|Any CPU {FA18D21B-EB2B-4ACE-B4A7-BC77D3836077}.Release|Any CPU.Build.0 = Release|Any CPU {FA18D21B-EB2B-4ACE-B4A7-BC77D3836077}.Release|x86.ActiveCfg = Release|x86 {FA18D21B-EB2B-4ACE-B4A7-BC77D3836077}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: ironclad-apps/src/Dafny/.gitignore ================================================ *.bpl *.log ================================================ FILE: ironclad-apps/src/Dafny/Apps/.gitignore ================================================ *.bpl *.log ================================================ FILE: ironclad-apps/src/Dafny/Apps/AddPerf/Main.i.dfy ================================================ include "../../Libraries/Util/insecure_prng.i.dfy" include "../../Libraries/FleetNat/FleetNatAdd.i.dfy" include "../../Libraries/FleetNat/FleetNatMul.i.dfy" include "../../Libraries/FatNat/FatNatMod.i.dfy" include "../../Drivers/IO/pci.i.dfy" //- //- A wrapper utility for benchmarking various parts of the system. //- method print_array(alabel:int, a:array) requires 0 <= alabel < 120; requires a != null; requires IsDigitSeq(power2(32), a[..]); { var i := 0; while (i < a.Length) invariant 0 <= i <= a.Length; invariant IsDigitSeq(power2(32), a[..i]); { debug_print(alabel, a[i]); i := i+1; } } method repeat_array(v:int, l:nat) returns (a:array) requires 0<=v a[i]==v; ensures IsDigitSeq(power2(32), a[..]); ensures 0 v <=BEWordSeqToInt(a[..]); { a := new int[l]; var j := 0; while (j < l) invariant 0<=j<=l; invariant forall i :: 0<=i a[i]==v; { a[j] := v; j := j + 1; } if (0) //- ensures fresh(arr); //- ensures arr != null; //- ensures arr.Length == 0x40000; //- ensures forall j :: 0 <= j < arr.Length ==> arr[j] == j; //- ensures IsWordSeq(arr[..]); //-{ //- arr := new int[0x40000]; //- var i := 0; //- while (i < 0x40000) //- invariant 0 <= i <= 0x40000; //- invariant forall j :: 0 <= j < i ==> arr[j] == j; //- invariant forall j :: 0 <= j < i ==> Word32(arr[j]); //- { //- arr[i] := i; //- i := i + 1; //- lemma_2toX(); //- } //-} method PrependArray(first:int, second:int, rest:array) returns (unified:array) requires Word32(first) && Word32(second); requires rest != null; requires IsWordSeq(rest[..]); ensures fresh(unified); ensures unified != null; ensures IsWordSeqOfLen(unified[..], 2 + rest.Length); ensures unified[..] == [first, second] + rest[..]; { unified := new int[2 + rest.Length]; unified[0] := first; unified[1] := second; var i := 0; while (i < rest.Length) invariant 0 <= i <= rest.Length; invariant unified[..i+2] == [first, second] + rest[..i]; { unified[i+2] := rest[i]; assert unified[..i+3] == unified[..i+2] + [unified[i+2]]; //- dafnycc assert rest[..i+1] == rest[..i] + [rest[i]]; //- dafnycc i := i + 1; } calc { unified[..]; unified[..rest.Length+2]; [first, second] + rest[..rest.Length]; [first, second] + rest[..]; } } method hash_code_region(code_start:int, entry_point:int, code_words:array) returns (hash_bytes:seq) requires Word32(code_start) && Word32(entry_point); requires code_words != null; requires code_words.Length == 0x40000; requires IsWordSeq(code_words[..]); ensures var hash_input := BEWordSeqToBitSeq_premium([code_start, entry_point] + code_words[..]); |hash_input| < power2(64) && IsBitSeq(hash_input) && hash_bytes == BEWordSeqToByteSeq_premium(SHA1(hash_input)); { lemma_2toX(); ghost var sha_input_words := [code_start, entry_point] + code_words[..]; var unified_input := PrependArray(code_start, entry_point, code_words); assert unified_input[..] == [code_start, entry_point] + code_words[..]; assert |unified_input[..]| == 0x40002; assert |BEWordSeqToBitSeq_premium([code_start, entry_point] + code_words[..])| == 32*0x40002; assert |BEWordSeqToBitSeq_premium([code_start, entry_point] + code_words[..])| < power2(64); var unified_input_bytes := new int[unified_input.Length*4]; BEWordArrayToByteArray(unified_input, unified_input_bytes); var hash_arr := SHA1_impl_Bytes_arrays(unified_input_bytes); assert hash_arr[..] == SHA1(BEByteSeqToBitSeq_premium(unified_input_bytes[..])); var hash_seq := hash_arr[..]; hash_bytes := BEWordSeqToByteSeq_impl(hash_seq); lemma_BEByteSeqToBitSeq_BEWordSeqToByteSeq([code_start, entry_point] + code_words[..]); } method Main (code_start:int, entry_point:int, code_words:array) returns (result:int) requires word32(code_start) && word32(entry_point); requires code_words != null; requires code_words.Length == 0x40000; requires IsWordSeq(code_words[..]); requires TPM_valid(TPM); requires TPM.PCR_19 == []; requires IoMemPerm.Null?; requires TPM_satisfies_integrity_policy(TPM); modifies this`TPM; modifies this`IoMemPerm; ensures Word32(code_start) && Word32(entry_point); ensures var hash_input := BEWordSeqToBitSeq([code_start, entry_point] + code_words[..]); |hash_input| < power2(64) && IsBitSeq(hash_input) && TPM.PCR_19 == [BEWordSeqToByteSeq(SHA1(hash_input))]; ensures result == entry_point; { establish_locality(); lemma_2toX(); lemma_word32_Word32(); assert word32(code_start) ==> Word32(code_start); assert word32(entry_point) ==> Word32(entry_point); var hash_bytes := hash_code_region(code_start, entry_point, code_words); var success := extend_PCR(hash_bytes); if (!success) { //- Can't guarantee anything about PCR 19 at this point while true decreases *; { debug_print(0, 0x44440021); } } //- calc { //- TPM.PCR_19; //- [hash_bytes]; //- [BEWordSeqToByteSeq(hash_seq)]; //- [BEWordSeqToByteSeq(SHA1(BEByteSeqToBitSeq_premium(unified_input_bytes[..])))]; //- [BEWordSeqToByteSeq(SHA1(BEByteSeqToBitSeq_premium(BEWordSeqToByteSeq(sha_input_words))))]; //- [BEWordSeqToByteSeq(SHA1(BEByteSeqToBitSeq_premium(BEWordSeqToByteSeq_premium([code_start, entry_point] + code_words[..]))))]; //- } lemma_BEByteSeqToBitSeq_BEWordSeqToByteSeq([code_start, entry_point] + code_words[..]); return entry_point; } ================================================ FILE: ironclad-apps/src/Dafny/Apps/BenchmarkApp/Main.i.dfy ================================================ //- include "../BenchmarkService/BenchmarkList.i.dfy" include "../BenchmarkService/BenchmarkCore.i.dfy" include "../../Libraries/Util/insecure_prng.i.dfy" include "../../Libraries/Crypto/Hash/sha256opt2.i.dfy" //- //- A wrapper utility for benchmarking various parts of the system. //- method print_array(alabel:int, a:array) requires 0 <= alabel < 120; requires a != null; requires IsDigitSeq(power2(32), a[..]); { var i := 0; while (i < a.Length) invariant 0 <= i <= a.Length; invariant IsDigitSeq(power2(32), a[..i]); { debug_print(alabel, a[i]); i := i+1; } } method print_state(state:BenchmarkState) requires WellformedBenchmarkState(state); { if state.FatNatAddState? { var b_ref := state.b; reveal_WellformedBenchmarkState(); print_array(0xa, state.a); reveal_WellformedBenchmarkState(); print_array(0xb, state.b); } } //- //- Main benchmark app entry point. //- method Main() returns (Result:int) ensures public(true); requires TPM_valid(TPM); requires TPM_satisfies_integrity_policy(TPM); requires IoMemPerm.Null?; modifies this`TPM; modifies this`IoMemPerm; { lemma_2toX(); Result := 0; var rand := insecure_get_random(42); var dummy_array := new int[1]; //- //- TPM initialization. //- //- [jonh] comment next line out to build C# version establish_locality(); //-var bms := BenchmarkState_c(KeyPairOptAbsent()); ResetTally(); var benchmark := BenchmarkSha256(); //-var benchmark := BenchmarkFatAdd(); var valid,state := prepare_state(benchmark, 512, true, false, 8192*8); if valid { var BeginHigh, BeginLow, EndHigh, EndLow, TestResult, state' := TimeIt(benchmark, 100000, state, dummy_array); //-print_state(state'); debug_print(0x89, BeginHigh); debug_print(0x89, BeginLow); debug_print(0x89, EndHigh); debug_print(0x89, EndLow); DisplayTally(); } else { debug_print(0x66, 0x666666); } } ================================================ FILE: ironclad-apps/src/Dafny/Apps/BenchmarkService/BenchmarkCore.i.dfy ================================================ include "../../Drivers/CPU/assembly_premium.i.dfy" include "../../Libraries/Util/integer_sequences.i.dfy" include "../../Libraries/Util/word_bits.i.dfy" include "../../Libraries/Crypto/Hash/sha1.i.dfy" include "../../Libraries/Crypto/Hash/sha256.i.dfy" include "../../Libraries/Crypto/RSA/RSA.i.dfy" include "../../Libraries/Crypto/RSA/RSAOps.i.dfy" include "../../Libraries/Crypto/RSA/RSA_Decrypt.i.dfy" include "BenchmarkList.i.dfy" include "../../Libraries/BigNum/BigNatTestLib.i.dfy" include "../../Libraries/Crypto/RSA/RSAPublicWrapper.i.dfy" //- //- Core utilities for benchmarking various parts of the system. //- datatype BenchmarkState = NopState() | RsaState(keypair:RSAKeyPairImpl, text:seq) | RsaKeyGenState(num_key_bits:int) | FatNatAddState(a:array, b:array) | ShaState(arr_is_words:bool, arr:array, use_original:bool) predicate {:opaque} {:heap} WellformedBenchmarkState(state:BenchmarkState) reads if state.FatNatAddState? then state.a else null; reads if state.FatNatAddState? then state.b else null; reads if state.ShaState? then state.arr else null; { if state.RsaState? then WellformedRSAKeyPairImpl(state.keypair) && IsByteSeq(state.text) && 0 < |state.text| <= state.keypair.pub.size - 11 else if state.RsaKeyGenState? then 20 < state.num_key_bits < power2(28) else if state.FatNatAddState? then state.a != null && state.b != null && IsDigitSeq(power2(32), state.a[..]) && IsDigitSeq(power2(32), state.b[..]) else if state.ShaState? then state.arr != null && if state.arr_is_words then ( Word32(state.arr.Length*32) && state.arr.Length*32 < power2(64) && IsWordSeq(state.arr[..])) else ( Word32(state.arr.Length*8) && state.arr.Length*8 < power2(64) && IsByteSeq(state.arr[..])) else true } predicate {:opaque} CorrectBenchmarkState(state:BenchmarkState, Benchmark:int) { if Benchmark == BenchmarkFatAdd() || Benchmark == BenchmarkFatAddSlowly() then state.FatNatAddState? else if Benchmark == BenchmarkSha256() then state.ShaState? else if Benchmark == BenchmarkRsaEncrypt() || Benchmark == BenchmarkRsaDecrypt() then state.RsaState? else if Benchmark == BenchmarkRsaKeyGen() then state.RsaKeyGenState? else true } method ZeroArray(arr:array) requires arr != null; modifies arr; ensures IsByteSeq(arr[..]); { var i := 0; while (i < arr.Length) invariant 0 <= i <= arr.Length; invariant IsByteSeq(arr[..i]); { arr[i] := 0; assert arr[..i+1] == arr[..i] + [arr[i]]; //- dafnycc i := i + 1; } assert arr[..] == arr[..arr.Length]; } method make_array(val:int, len:int) returns (a:array) requires 0 <= val < power2(32); requires len > 0; ensures a != null; ensures fresh(a); ensures a.Length == len; ensures forall i:int :: 0 <= i < len ==> a[i] == val; { a := new int[len]; var i := 0; while (i < a.Length) invariant 0 <= i <= a.Length; //-invariant IsDigitSeq(power2(32), a[..i]); invariant forall j:int :: 0 <= j < i ==> a[j] == val; { lemma_2toX(); a[i] := val; assert a[..i+1] == a[..i] + [a[i]]; //- this line added for DafnyCC's sake i := i + 1; } //-assert IsDigitSeq(power2(32), a[0..a.Length]); assert a[..] == a[0..a.Length]; //-assert IsDigitSeq(power2(32), a[..]); } method mkFatNatAddState() returns (state:BenchmarkState) ensures state.FatNatAddState?; ensures state.a != null && state.b != null; ensures fresh(state.a) && fresh(state.b); ensures IsDigitSeq(power2(32), state.a[..]) && IsDigitSeq(power2(32), state.b[..]); ensures WellformedBenchmarkState(state); { lemma_2toX(); var a := make_array(42,32); var b := make_array(12,32); state := FatNatAddState(a, b); reveal_WellformedBenchmarkState(); } method mkShaState(use_words:bool,use_original:bool, len_bits:int) returns (valid:bool, state:BenchmarkState) ensures valid ==> state.ShaState?; ensures valid ==> WellformedBenchmarkState(state); { lemma_2toX(); valid := true; if len_bits <= 0 || len_bits > 0x1000000 || len_bits / 32 <= 0 || len_bits / 8 <= 0 { return false, NopState(); } var a; if (use_words) { var len_words := len_bits / 32; a := make_array(42,len_words); } else { var len_bytes := len_bits / 8; a := make_array(42,len_bytes); } state := ShaState(use_words, a, use_original); reveal_WellformedBenchmarkState(); } method mkRsaState(num_key_bits:int) returns (state:BenchmarkState) requires 100 < num_key_bits < 0x10000; requires TPM_ready(); modifies this`TPM; modifies this`IoMemPerm; ensures state.RsaState?; ensures WellformedBenchmarkState(state); ensures TPM_ready(); { lemma_2toX(); var TestKeyPair:RSAKeyPairImpl; calc { 0x10000; < { lemma_2toX32(); } power2(28); } TestKeyPair := RSAKeyGen(num_key_bits); var s := RepeatDigit_impl(42, TestKeyPair.pub.size - 11); state := RsaState(TestKeyPair, s); reveal_WellformedBenchmarkState(); } method prepare_state(Benchmark:int, num_key_bits:int, use_words:bool, use_original:bool, len_bits:int) returns (valid:bool,state:BenchmarkState) //-requires IsByte(Benchmark); //-requires 100 < num_key_bits < 0x10000; requires TPM_ready(); modifies this`TPM; modifies this`IoMemPerm; ensures valid ==> WellformedBenchmarkState(state); ensures valid ==> CorrectBenchmarkState(state, Benchmark); ensures TPM_ready(); { state := NopState(); valid := true; if Benchmark == BenchmarkFatAdd() || Benchmark == BenchmarkFatAddSlowly() { state := mkFatNatAddState(); } else if Benchmark == BenchmarkRsaEncrypt() || Benchmark == BenchmarkRsaDecrypt() { if 100 < num_key_bits < 0x10000 { state := mkRsaState(num_key_bits); } else { valid := false; state := NopState(); } } else if Benchmark == BenchmarkRsaKeyGen() { if 100 < num_key_bits < 0x10000 { calc { 0x10000; < { lemma_2toX32(); } power2(28); } state := RsaKeyGenState(num_key_bits); } else { valid := false; state := NopState(); } } else if Benchmark == BenchmarkSha256() { valid,state := mkShaState(use_words, use_original, len_bits); } reveal_WellformedBenchmarkState(); reveal_CorrectBenchmarkState(); } method BenchmarkOp(Benchmark:int, state:BenchmarkState) returns (TestResult:seq,state':BenchmarkState) requires TPM_ready(); requires WellformedBenchmarkState(state); requires CorrectBenchmarkState(state, Benchmark); modifies this`TPM; modifies this`IoMemPerm; ensures TPM_ready(); ensures WellformedBenchmarkState(state'); ensures CorrectBenchmarkState(state', Benchmark); { state' := state; if (Benchmark == 0) { //- No-op benchmark. TestResult := []; state' := NopState(); reveal_WellformedBenchmarkState(); reveal_CorrectBenchmarkState(); } else if (Benchmark == 2) { assert Benchmark == BenchmarkSha256(); reveal_WellformedBenchmarkState(); reveal_CorrectBenchmarkState(); if (state.arr_is_words) { if (state.use_original) { var dummy_TestResult_array := SHA256_impl_Words_arrays_original(state.arr); } else { var dummy_TestResult_array := SHA256_impl_Words_arrays(state.arr); } } else { if (state.use_original) { var dummy_TestResult_array := SHA256_impl_Bytes_arrays_original(state.arr); } else { var dummy_TestResult_array := SHA256_impl_Bytes_arrays(state.arr); } } TestResult := []; } else if (Benchmark == 3) { assert Benchmark == BenchmarkRsaKeyGen(); reveal_WellformedBenchmarkState(); reveal_CorrectBenchmarkState(); var dummy_keys := RSAKeyGen(state.num_key_bits); TestResult := []; } else if (Benchmark == 4) { assert Benchmark == BenchmarkRsaEncrypt(); reveal_WellformedBenchmarkState(); reveal_CorrectBenchmarkState(); TestResult := Encrypt(state.keypair.pub, state.text); } else if (Benchmark == 5) { assert Benchmark == BenchmarkRsaDecrypt(); reveal_WellformedBenchmarkState(); reveal_CorrectBenchmarkState(); var success; success, TestResult := Decrypt(state.keypair, state.text); } else if (Benchmark == 14) { assert Benchmark == BenchmarkFatAdd(); reveal_WellformedBenchmarkState(); reveal_CorrectBenchmarkState(); var c := FatNatAdd_optimized(state.a, state.b); TestResult := []; //-state' := FatNatAddState(state.a, c); state' := FatNatAddState(state.a, state.b); //-state' := FatNatAddState(c, c); reveal_WellformedBenchmarkState(); } else if (Benchmark == 15) { assert Benchmark == BenchmarkFatAddSlowly(); reveal_WellformedBenchmarkState(); reveal_CorrectBenchmarkState(); var a_ref := state.a; var b_ref := state.b; var c := FatNatAdd(state.a, state.b); TestResult := []; //-state' := FatNatAddState(state.a, c); state' := FatNatAddState(state.a, state.b); //-state' := FatNatAddState(c, c); reveal_WellformedBenchmarkState(); } else { TestResult := []; state' := NopState(); reveal_WellformedBenchmarkState(); reveal_CorrectBenchmarkState(); } /* else if (Benchmark == BenchmarkSha1()) { //- //- SHA1 Benchmark - Hash a block of bytes. //- CopyArraySimple(TestArray, TestInput); assert ti == TestInput[..]; assert IsByteSeq(TestInput[..]); assert IsByteSeq(TestArray[..]); var dummy_TestResult_array := SHA1_impl_Bytes_arrays(TestArray); } else if (Benchmark == BenchmarkDuplicateArray()) { CopyArraySimple(TestArray, TestInput); //-assert ti == TestInput[..]; } else if (Benchmark == BenchmarkRsaKeyGen()) { var TestKeyPair:RSAKeyPairImpl; //- //- RSA KeyGen Benchmark - Generate a public/private key pair. //- assert TestValue > 20; //- OBSERVE! assert TestValue < 0x10000; //- OBSERVE! calc { 0x10000; < { lemma_2toX32(); } power2(28); } debug_print(0x90, 0x09001000+TestValue); TestKeyPair := RSAKeyGen(TestValue); debug_print(0x90, 0x09002000); //- Save the keypair for future use. state' := BenchmarkState_c(KeyPairOptPresent(TestKeyPair)); } else if (Benchmark == BenchmarkRsaEncrypt()) { //- debug_print(0x90, 0x090e0001); if (state.kpo.KeyPairOptPresent?) { //- debug_print(0x90, 0x090e0002); var KeyPair := state.kpo.keypair; if (TestValue <= KeyPair.pub.size-12) { //- debug_print(0x90, 0x090e0003); //- RSA Encrypt with fake key. TestResult := Encrypt(KeyPair.pub, TestSeq); //- debug_print(0x90, 0x090e0004); } else { //- debug_print(0x90, 0x090e0040); //- debug_print(0x90, TestValue); //- debug_print(0x90, KeyPair.pub.size); //- debug_print(0x90, 0x090e004f); } //- debug_print(0x90, 0x090e0005); } //- debug_print(0x90, 0x090e0006); } else if (Benchmark == BenchmarkRsaDecrypt()) { if (state.kpo.KeyPairOptPresent?) { var KeyPair := state.kpo.keypair; if (TestValue <= KeyPair.pub.size-12) { var result; if (|TestSeq|==0) { debug_print(0x90, 0xffff0001); } else { var divr := TestValue / 4; var mulr := divr * 4; var modr := TestValue - mulr; assert modr == TestValue % 4; if (modr==0) { assert TestValue%4==0; result,TestResult := Decrypt(KeyPair, TestSeq); } else { debug_print(0x90, 0xffff0002); } } } } } else if (Benchmark == BenchmarkTpmExtractRandom()) { //- //- TPM benchmark - Extract random bytes from the TPM. //- lemma_2toX(); TestResult := get_random(TestValue); } else if (Benchmark == BenchmarkByteSeqToWordSeq()) { //- //- Benchmark ByteSeqToWordSeq method. //- ghost var TestPadding:seq; TestResult, TestPadding := BEByteSeqToWordSeq_impl(TestSeq); } else if (Benchmark == BenchmarkWordSeqToByteSeq()) { //- //- Benchmark WordSeqToByteSeq method. //- lemma_2toX(); TestResult := BEWordSeqToByteSeq_impl(TestSeq); } */ } //- //- Time a particular benchmark for the given number of iterations. //- method {:timeLimitMultiplier 2} TimeIt(Benchmark:int, Iterations:int, state:BenchmarkState, dummy_array:array) returns (BeginHigh:int, BeginLow:int, EndHigh:int, EndLow:int, TestResult:seq, state':BenchmarkState) requires Word32(Iterations); requires dummy_array != null; requires TPM_ready(); requires WellformedBenchmarkState(state); requires CorrectBenchmarkState(state, Benchmark); modifies this`TPM; modifies this`IoMemPerm; ensures TPM_ready(); ensures Word32(BeginHigh); ensures Word32(BeginLow); ensures Word32(EndHigh); ensures Word32(EndLow); ensures WellformedBenchmarkState(state'); ensures CorrectBenchmarkState(state, Benchmark); { lemma_2toX(); var a_ref := if state.FatNatAddState? then state.a else if state.ShaState? then state.arr else dummy_array; //- DafnyCC var b_ref := if state.FatNatAddState? then state.b else dummy_array; //- DafnyCC TestResult := []; var RemainingIterations:int := Iterations; state' := state; var a'_ref := if state'.FatNatAddState? then state'.a else dummy_array; //- DafnyCC var b'_ref := if state'.FatNatAddState? then state'.b else dummy_array; //- DafnyCC debug_print(0x90, 0x09000010); //- //- Take starting timestamp. //- BeginHigh, BeginLow := Asm_Rdtsc(); //-////////////// calc { true; ==> { reveal_WellformedBenchmarkState(); } WellformedBenchmarkState(state'); } //-////////////// //- //- Repeatedly do the thing we're timing. //- while (RemainingIterations > 0) decreases RemainingIterations; invariant RemainingIterations >= 0; invariant TPM_ready(); invariant WellformedBenchmarkState(state'); invariant CorrectBenchmarkState(state', Benchmark); { var a'_ref := if state'.FatNatAddState? then state'.a else if state'.ShaState? then state'.arr else dummy_array; //- DafnyCC var b'_ref := if state'.FatNatAddState? then state'.b else dummy_array; //- DafnyCC TestResult, state' := BenchmarkOp(Benchmark, state'); RemainingIterations := RemainingIterations - 1; } var a'2_ref := if state'.FatNatAddState? then state'.a else if state'.ShaState? then state'.arr else dummy_array; //- DafnyCC var b'2_ref := if state'.FatNatAddState? then state'.b else dummy_array; //- DafnyCC //- //- Take ending timestamp. //- EndHigh, EndLow := Asm_Rdtsc(); //-////////////// calc { true; ==> { reveal_WellformedBenchmarkState(); } WellformedBenchmarkState(state'); } //-////////////// } //- //- Time a particular benchmark (that requires a RSA key) for the given number of iterations. //- //-method TimeItWithRSAKey(Benchmark:int, Iterations:int, TestValue:int, TestData:seq) //- returns (BeginHigh:int, BeginLow:int, EndHigh:int, EndLow:int, TestResult:seq) //- requires IsByte(Benchmark); //- requires Word16(Iterations); //- requires Word16(TestValue); //- requires IsByteSeq(TestData); //- requires TPM_ready(); //- modifies this`TPM; //- modifies this`IoMemPerm; //- ensures TPM_ready(); //- ensures Word32(BeginHigh); //- ensures Word32(BeginLow); //- ensures Word32(EndHigh); //- ensures Word32(EndLow); //-{ //- lemma_2toX(); //- //- var RemainingIterations := Iterations; //- //- //- //- //- Pre-benchmark prep work. //- //- Some of this is specific to particular benchmarks. //- //- //- var TestBlock:seq := []; //- var TestKeyPair:RSAKeyPairImpl; //- TestResult := []; //- var ActualValue := TestValue; //- //- var NeedRSASizedValue:bool := Benchmark == BenchmarkRsaEncrypt(); //- if (NeedRSASizedValue && ActualValue > 245) //- { //- //- RSA request too big. //- debug_print(0x90, 0xde012210); //- ActualValue := 245; //- } //- //- TestBlock := RepeatDigit_impl(0x1c, ActualValue); //- //- //- //- //- Generate a 2048-bit public/private key pair. //- //- //- calc //- { //- 2048; //- < { lemma_2toX32(); } power2(29); //- } //- TestKeyPair := RSAKeyGen(2048); //- assert TestKeyPair.pub.size >= 2048 / 8; //-//- assert TestKeyPair.pub.size % 4 == 0; //- assert NeedRSASizedValue ==> |TestBlock| <= TestKeyPair.pub.size - 11; //- //- //- //- //- Take starting timestamp. //- //- //- BeginHigh, BeginLow := Asm_Rdtsc(); //- //- //- //- //- Repeatedly do the thing we're timing. //- //- //- while (RemainingIterations > 0) //- decreases RemainingIterations; //- invariant RemainingIterations >= 0; //- invariant TPM_ready(); //- invariant WellformedRSAKeyPairImpl(TestKeyPair); //- { //- if (Benchmark == BenchmarkRsaEncrypt()) //- { //- TestResult := Encrypt(TestKeyPair.pub, TestBlock); //- } //- else if (Benchmark == BenchmarkRsaDecrypt()) //- { //- var result; //- result,TestResult := Decrypt(TestKeyPair, TestBlock); //- } //- else if (Benchmark == BenchmarkRsaDigestedSign()) //- { //- //- RSA Digested Sign. //- } //- else if (Benchmark == BenchmarkRsaDigestedVerify()) //- { //- //- RSA Digested Verify. //- } //- //- RemainingIterations := RemainingIterations - 1; //- } //- //- //- //- //- Take ending timestamp. //- //- //- EndHigh, EndLow := Asm_Rdtsc(); //-} method DebugPrintSequence(Offset:int, Data:seq) requires 0 <= Offset <= 160 - 16; requires IsByteSeq(Data); requires |Data| >= 0; { var Index:int := 0; while (Index < |Data|) decreases |Data| - Index; invariant Index >= 0; invariant Index <= |Data|; { debug_print(Offset, Data[Index]); Index := Index + 1; } } ================================================ FILE: ironclad-apps/src/Dafny/Apps/BenchmarkService/BenchmarkList.i.dfy ================================================ //- //- List of benchmarks we support. //- static function method BenchmarkNothing():int { 0 } static function method BenchmarkSha1():int { 1 } static function method BenchmarkSha256():int { 2 } static function method BenchmarkRsaKeyGen():int { 3 } static function method BenchmarkRsaEncrypt():int { 4 } static function method BenchmarkRsaDecrypt():int { 5 } static function method BenchmarkRsaDigestedSign():int { 6 } static function method BenchmarkRsaDigestedVerify():int { 7 } static function method BenchmarkTpmExtractRandom():int { 8 } static function method BenchmarkByteSeqToWordSeq():int { 9 } static function method BenchmarkWordSeqToByteSeq():int { 10 } static function method BenchmarkSha1Raw():int { 11 } static function method BenchmarkSha256Raw():int { 12 } static function method BenchmarkDuplicateArray():int { 13 } static function method BenchmarkFatAdd():int { 14 } static function method BenchmarkFatAddSlowly():int { 15 } static function method BenchmarkMax():int { 16 } ================================================ FILE: ironclad-apps/src/Dafny/Apps/BenchmarkService/Main.i.dfy ================================================ //- include "../../Drivers/CPU/assembly_premium.i.dfy" include "../../Drivers/Network/Intel/driver.i.dfy" include "../../Libraries/Net/ethernet.i.dfy" include "../../Libraries/Net/IPv4.i.dfy" include "../../Libraries/Net/Udp.i.dfy" include "../../Libraries/Util/integer_sequences.i.dfy" include "../../Libraries/Util/word_bits.i.dfy" include "../../Libraries/Crypto/Hash/sha1.i.dfy" include "../../Libraries/Crypto/Hash/sha256.i.dfy" include "../../Libraries/Crypto/RSA/RSA.i.dfy" include "../../Libraries/Crypto/RSA/RSAOps.i.dfy" include "../../Libraries/Crypto/Rsa/RSA_Decrypt.i.dfy" include "BenchmarkList.i.dfy" include "BenchmarkCore.i.dfy" include "Protocol.i.dfy" include "../../Libraries/BigNum/BigNatTestLib.i.dfy" include "../../Libraries/Crypto/RSA/RSAPublicWrapper.i.dfy" //- //- A wrapper utility for benchmarking various parts of the system. //- //- //- Main benchmark app entry point. //- method Main() returns (Result:int) ensures public(true); requires TPM_valid(TPM); requires TPM_satisfies_integrity_policy(TPM); requires IoMemPerm.Null?; modifies this`TPM; modifies this`IoMemPerm; { lemma_2toX(); Result := 0; //- //- TPM initialization. //- establish_locality(); //- //- Network initialization. //- var NetUp, net_state := init_network_card(); if NetUp { lemma_2toX(); debug_print(0x90, 0xded0d0d0); var Success:bool := true; var EtherSource:ethernet_addr; var IPSource:IPv4Address; var IPDest:IPv4Address; var SourcePort:int; var DestPort:int; var Request:seq; while (Success) invariant valid_network_state(net_state); invariant TPM_ready(); { Success, net_state, EtherSource, IPSource, IPDest, SourcePort, DestPort, Request := UdpReceive(net_state); if (Success) { lemma_2toX(); //- DebugPrintSequence(0x90, Request); debug_print(0x90, 0xdedadada); if (DestPort == 77) { //- //- Port 77 is "any private remote job entry" port. //- We use our own custom protocol to issue benchmark job requests. //- var Response; Response := RunBenchmark(Request); net_state := UdpSend(net_state, EtherSource, IPDest, IPSource, DestPort, SourcePort, Response); } if (DestPort == 7) { //- //- Port 7 is the Echo Service port. //- Echo the data received back to the sender. //- net_state := UdpSend(net_state, EtherSource, IPDest, IPSource, DestPort, SourcePort, Request); } } else { Result := 0xdeadbeef; debug_print(0x90, 0xdeadbeef); } } } else { Result := 0xdeaddead; debug_print(0x90, 0xdeaddead); } } //- //- Handle a benchmark request. //- method RunBenchmark(Input:seq) returns (Output:seq) requires IsByteSeq(Input); requires |Input| >= 0 && |Input| <= 1472; requires TPM_ready(); modifies this`TPM; modifies this`IoMemPerm; ensures TPM_ready(); ensures IsByteSeq(Output); ensures |Output| <= 1472; { lemma_2toX(); var dummy_array := new int[1]; //- //- Decode input to extract benchmark to run, etc. //- var Error, Operation, Benchmark, Iterations, state := DecodeRequest(Input); var a_ref := if state.FatNatAddState? then state.a else if state.ShaState? then state.arr else dummy_array; //- DafnyCC var b_ref := if state.FatNatAddState? then state.b else dummy_array; //- DafnyCC if (Error != 0) { Output := EncodeErrorResponse(Error, Input); return; } if (Benchmark >= BenchmarkMax()) { Output := EncodeErrorResponse(2, Input); return; } //-////////////// calc { true; ==> { reveal_WellformedBenchmarkState(); } WellformedBenchmarkState(state); } //-////////////// //- //- Time the desired benchmark in a loop. //- var BeginHigh, BeginLow, EndHigh, EndLow, TestResult, state'; BeginHigh, BeginLow, EndHigh, EndLow, TestResult, state' := TimeIt(Benchmark, Iterations, state, dummy_array); //- //- Prepare results to send back to the client. //- Output := EncodeSuccessfulResponse(Input, BeginHigh, BeginLow, EndHigh, EndLow); } ================================================ FILE: ironclad-apps/src/Dafny/Apps/BenchmarkService/Protocol.i.dfy ================================================ include "../../Libraries/Util/integer_sequences.i.dfy" include "../../Libraries/Util/word_bits.i.dfy" include "BenchmarkCore.i.dfy" //- //- Methods related to the custom remote job entry protocol we use for running benchmarks. //- //- //- Decode a remote request to perform some benchmark tests. //- //- The Operation value is currently unused. //- The Benchmark value determines what benchmark we run. //- Iterations is the number of times to run the benchmark in a loop. //- TestValue and the TestData are benchmark-specific arguments. //- //- A non-zero Error value indicates a parsing failure. //- method DecodeRequest(Data:seq) returns (Error:int, Operation:int, Benchmark:int, Iterations:int, state:BenchmarkState) requires IsByteSeq(Data); requires TPM_ready(); modifies this`TPM; modifies this`IoMemPerm; ensures IsByte(Error); ensures Error == 0 ==> |Data| >= 15; ensures Error == 0 ==> IsByte(Operation); ensures Error == 0 ==> IsByte(Benchmark); ensures Error == 0 ==> Word32(Iterations); ensures Error == 0 ==> WellformedBenchmarkState(state); ensures Error == 0 ==> CorrectBenchmarkState(state, Benchmark); ensures TPM_ready(); { lemma_2toX(); state := NopState(); //- //- Initialize everything to keep DafnyCC happy. //- Error := 0; Operation := 0; Benchmark := 0; Iterations := 0; //- //- Our header is 15 bytes long. //- if (|Data| < 15) { Error := 1; return; } Benchmark := Data[0]; Iterations := BEFourBytesToWord_impl(Data[1..5]); var key_bits := BEFourBytesToWord_impl(Data[5..9]); var len_bits := BEFourBytesToWord_impl(Data[9..13]); //- //- Next byte is which interface to use (> 0 = words, 0 = bytes) //- var use_words := false; if Data[13] > 0 { use_words := true; } //- //- Next byte is which code version to use (> 0 = old version, 0 = current) //- var use_original := false; if Data[14] > 0 { use_original := true; } var valid; valid, state := prepare_state(Benchmark, key_bits, use_words, use_original, len_bits); if !valid { Error := 5; return; } } //- //- Encode an error response to return to the client that sent us the request. //- method EncodeErrorResponse(Error:int, OriginalRequest:seq) returns (Data:seq) requires IsByte(Error); requires Error != 0; requires IsByteSeq(OriginalRequest); requires |OriginalRequest| <= 1472; ensures IsByteSeq(Data); ensures |Data| <= 1472; { lemma_2toX(); //- //- On responses, first byte is the error code. //- Data := [Error]; //- //- On *error* responses, any subsequent bytes are the same as in the original request. //- This is to help the sender determine what went wrong. //- if (|OriginalRequest| != 0) { Data := Data + OriginalRequest[1..]; } } //- //- Encode the benchmark results to return to the client that sent us the request. //- method EncodeSuccessfulResponse(OriginalRequest:seq, BeginHigh:int, BeginLow:int, EndHigh:int, EndLow:int) returns (Data:seq) requires Word32(BeginHigh); requires Word32(BeginLow); requires Word32(EndHigh); requires Word32(EndLow); requires IsByteSeq(OriginalRequest); requires |OriginalRequest| >= 15; requires |OriginalRequest| <= 1472; ensures IsByteSeq(Data); ensures |Data| <= 1472; { //- //- Convert the four 32-bit words into four 4-byte sequences. //- var BeginHighSeq:seq := BEWordSeqToByteSeq_impl([BeginHigh]); var BeginLowSeq:seq := BEWordSeqToByteSeq_impl([BeginLow]); var EndHighSeq:seq := BEWordSeqToByteSeq_impl([EndHigh]); var EndLowSeq:seq := BEWordSeqToByteSeq_impl([EndLow]); //- //- On responses, first byte is the error code (zero indicates no error). //- Next 15 bytes are the request (for id purposes). //- The subsequent sixteen bytes are the begin and end timestamps. //- Data := [0] + OriginalRequest[..15] + BeginHighSeq + BeginLowSeq + EndHighSeq + EndLowSeq; } ================================================ FILE: ironclad-apps/src/Dafny/Apps/Common/.gitignore ================================================ *.bpl *.log ================================================ FILE: ironclad-apps/src/Dafny/Apps/Common/CommonState.i.dfy ================================================ include "CommonState.s.dfy" include "../../Drivers/TPM/tpm-wrapper.i.dfy" include "../../Libraries/Util/Halter.i.dfy" include "../../Libraries/Util/DebugPrint.i.dfy" include "../../Libraries/Crypto/RSA/rfc4251impl.i.dfy" include "../../Libraries/Crypto/RSA/RSAPublicWrapper.i.dfy" datatype CommonStateImpl = CommonStateImplConstructor(sk:TPMSessionAndKey, key_pair:RSAKeyPairImpl, key_bits:nat) function {:autoReq} CommonStateImplToSpec (s:CommonStateImpl) : CommonState { CommonStateConstructor(KeyPairImplToSpec(s.key_pair), s.key_bits) } static lemma AModestKeyCanBeEncodedWithRFC4251(key_pair:RSAKeyPairSpec) requires key_pair.pub.e < power2(power2(31)); requires key_pair.pub.n < power2(power2(31)); ensures key_pair.pub.e < power2(power2(34)); ensures key_pair.pub.n < power2(power2(34)); ensures IsWordSeq([|STR_SSH_RSA()|]); ensures IsWordSeq([|rfc4251_positive_to_twoscomplement(BEIntToByteSeq(key_pair.pub.e))|]); ensures IsWordSeq([|rfc4251_positive_to_twoscomplement(BEIntToByteSeq(key_pair.pub.n))|]); ensures IsByteSeq(rfc4251_sshrsa_encoding(key_pair.pub.e,key_pair.pub.n)); { reveal_power2(); lemma_power2_increases(31, 34); lemma_power2_increases(power2(31), power2(34)); lemma_rfc4251_sshrsa_encoding_premium(key_pair.pub.e, key_pair.pub.n); } static predicate KeyCanBeEncodedWithRFC4251(key_pair:RSAKeyPairSpec) requires key_pair.pub.e < power2(power2(31)); requires key_pair.pub.n < power2(power2(31)); ensures key_pair.pub.e < power2(power2(34)); ensures key_pair.pub.n < power2(power2(34)); ensures IsWordSeq([|STR_SSH_RSA()|]); ensures IsWordSeq([|rfc4251_positive_to_twoscomplement(BEIntToByteSeq(key_pair.pub.e))|]); ensures IsWordSeq([|rfc4251_positive_to_twoscomplement(BEIntToByteSeq(key_pair.pub.n))|]); ensures IsByteSeq(rfc4251_sshrsa_encoding(key_pair.pub.e,key_pair.pub.n)); { AModestKeyCanBeEncodedWithRFC4251(key_pair); true } predicate CommonStateImplValid (s:CommonStateImpl) { TPMSessionAndKeyValid(s.sk) && WellformedRSAKeyPairImpl(s.key_pair) && ModestKeyValue(s.key_pair.pub.e) && ModestKeyValue(s.key_pair.pub.n) && KeyCanBeEncodedWithRFC4251(KeyPairImplToSpec(s.key_pair)) } method ExtendPCRRepeatedly (s:seq>) returns (success:bool) requires forall i :: 0 <= i < |s| ==> IsByteSeqOfLen(s[i], 20); requires TPM_ready(); ensures success ==> TPM.PCR_19 == old(TPM.PCR_19) + s; ensures TPM_ready(); ensures TPMs_match(TPM, old(TPM)[PCR_19 := TPM.PCR_19]); modifies this`TPM; modifies this`IoMemPerm; { success := true; ghost var old_PCR_19 := TPM.PCR_19; var i:int := 0; while i < |s| invariant 0 <= i <= |s|; invariant TPM_ready(); invariant TPMs_match(TPM, old(TPM)[PCR_19 := old_PCR_19 + s[..i]]); { success := extend_PCR(s[i]); if !success { return; } i := i + 1; } } method GenerateKeyPair (key_bits:nat) returns (success:bool, key_pair:RSAKeyPairImpl) requires TPM_ready(); modifies this`TPM; modifies this`IoMemPerm; ensures success ==> WellformedRSAKeyPairImpl(key_pair) && RSAKeyGenerationValid(key_bits, KeyPairImplToSpec(key_pair), TPM_random_bytes(old(TPM).random_index, TPM.random_index)) && key_pair.pub.size >= key_bits / 8 && ModestKeyValue(key_pair.pub.e) && ModestKeyValue(key_pair.pub.n); ensures TPM_ready(); ensures TPMs_match_except_for_randoms(TPM, old(TPM)); { success := false; if (key_bits <= 20 || key_bits >= 0x10000000) { key_pair := GenDummyKey(); //- dafnycc: initialize variable return; } calc { key_bits; < 0x10000000; == { lemma_2toX(); lemma_power2_add8(24); } power2(28); } key_pair := RSAKeyGen(key_bits); var modest_e := IsModestKeyValue(key_pair.pub.e); var modest_n := IsModestKeyValue(key_pair.pub.n); if !modest_e || !modest_n { return; } success := true; } static predicate KeyCanBeExtendedIntoPCR(key_pair:RSAKeyPairSpec) { key_pair.pub.e < power2(power2(31)) && key_pair.pub.n < power2(power2(31)) && KeyCanBeEncodedWithRFC4251(key_pair) && var public_key_encoding := rfc4251_sshrsa_encoding(key_pair.pub.e, key_pair.pub.n); IsByteSeq(public_key_encoding) && var public_key_encoding_bits := BEByteSeqToBitSeq(public_key_encoding); IsBitSeq(public_key_encoding_bits) && |public_key_encoding_bits| < power2(64) } method ExtendCommonStateKeyIntoPCR19 (key_bits:nat, state:CommonStateImpl, ghost TPM_before_keygen:TPM_struct) requires TPM_ready(); requires CommonStateImplValid(state); requires WellformedRSAKeyPairImpl(state.key_pair); requires state.key_bits == key_bits; requires RSAKeyGenerationValid(key_bits, KeyPairImplToSpec(state.key_pair), TPM_random_bytes(TPM_before_keygen.random_index, TPM.random_index)); requires state.key_pair.pub.size >= key_bits / 8; requires ModestKeyValue(state.key_pair.pub.e); requires ModestKeyValue(state.key_pair.pub.n); requires TPMs_match(TPM, TPM_before_keygen[random_index := TPM.random_index]); ensures KeyCanBeExtendedIntoPCR(CommonStateImplToSpec(state).key_pair); ensures TPM_ready(); ensures CommonStateGeneratedCorrectly(key_bits, CommonStateImplToSpec(state), TPM_before_keygen, TPM); ensures TPMs_match(TPM, TPM_before_keygen[random_index := TPM.random_index][PCR_19 := TPM.PCR_19]); modifies this`TPM; modifies this`IoMemPerm; { var encoded_public_key := rfc4251_encode_sshrsa_pubkey(state.key_pair.pub); if |encoded_public_key| >= 0x20000000 { HaltMachine(0x31); } debug_print(0x90, 0x89280003); calc { |encoded_public_key|*8; < 0x20000000 * 8; == 0x100000000; == { lemma_2toX32(); } power2(32); } lemma_power2_strictly_increases(32, 64); var public_key_hash_words := SHA1_impl_Bytes(encoded_public_key); var public_key_hash_bytes := BEWordSeqToByteSeq_impl(public_key_hash_words); var success := extend_PCR(public_key_hash_bytes); if !success { HaltMachine(0x32); } } method GenerateCommonState (key_bits:nat) returns (state:CommonStateImpl) requires TPM_valid(TPM); requires IoMemPerm.Null?; requires TPM_satisfies_integrity_policy(TPM); ensures TPM_ready() && CommonStateImplValid(state) && KeyCanBeExtendedIntoPCR(CommonStateImplToSpec(state).key_pair) && CommonStateGeneratedCorrectly(key_bits, CommonStateImplToSpec(state), old(TPM), TPM); modifies this`TPM; modifies this`IoMemPerm; ensures TPMs_match_except_for_randoms(TPM, old(TPM)[PCR_19 := TPM.PCR_19]); ensures TPM_valid(TPM); ensures IoMemPerm.Null?; { ghost var old_TPM := TPM; establish_locality(); debug_print(0x90, 0x89280000); var success, sk := establish_TPM_session_and_key(); if !success { HaltMachine(0x2F); } debug_print(0x90, 0x89280001); //- swap comments to enable baked key var key_pair; success, key_pair := GenerateKeyPair(key_bits); //- key_pair := GetBakedKey(key_bits); //- success := true; debug_print(0x90, 0x89280002); if !success { HaltMachine(0x30); } assert WellformedRSAKeyPairImpl(key_pair); assert RSAKeyGenerationValid(key_bits, KeyPairImplToSpec(key_pair), TPM_random_bytes(old_TPM.random_index, TPM.random_index)); state := CommonStateImplConstructor(sk, key_pair, key_bits); ExtendCommonStateKeyIntoPCR19(key_bits, state, old_TPM); } method HandleGetQuoteRequest (common_state_in:CommonStateImpl, nonce_external:seq) returns (common_state_out:CommonStateImpl, encoded_public_key:seq, pcr_info_bytes:seq, sig_bytes:seq) requires IsByteSeqOfLen(nonce_external, 20); requires CommonStateImplValid(common_state_in); ensures HandleGetQuoteRequestValid(CommonStateImplToSpec(common_state_in), old(TPM), TPM, nonce_external, encoded_public_key, pcr_info_bytes, sig_bytes); requires TPM_ready(); modifies this`TPM; modifies this`IoMemPerm; ensures TPM_ready(); ensures TPMs_match(TPM, old(TPM)); ensures CommonStateImplValid(common_state_out); ensures common_state_out == common_state_in[sk := common_state_out.sk]; ensures IsByteSeq(encoded_public_key); ensures IsByteSeq(pcr_info_bytes); ensures IsByteSeq(sig_bytes); ensures Word32(|encoded_public_key|); ensures Word32(|pcr_info_bytes|); ensures Word32(|sig_bytes|); { ghost var old_TPM := TPM; lemma_2toX(); reveal_power2(); encoded_public_key := rfc4251_encode_sshrsa_pubkey(common_state_in.key_pair.pub); var success:bool; var new_sk:TPMSessionAndKey; success, new_sk, pcr_info_bytes, sig_bytes := quote(common_state_in.sk, nonce_external); if !success { HaltMachine(0x51); } if |encoded_public_key| > 0xFFFFFFFF { HaltMachine(0x52); } if |pcr_info_bytes| > 0xFFFFFFFF { HaltMachine(0x53); } if |sig_bytes| > 0xFFFFFFFF { HaltMachine(0x54); } common_state_out := common_state_in[sk := new_sk]; assert 0xFFFFFFFF < power2(32); } ================================================ FILE: ironclad-apps/src/Dafny/Apps/Common/CommonState.s.dfy ================================================ include "../../Libraries/Crypto/RSA/RSASpec.s.dfy" include "../../Libraries/Crypto/RSA/rfc4251.s.dfy" include "../../Libraries/Crypto/Hash/sha1.s.dfy" include "../../Libraries/Util/integer_sequences.s.dfy" include "../../Libraries/Util/be_sequences.s.dfy" include "../../Libraries/Math/power2.s.dfy" include "../../Drivers/TPM/tpm-device.s.dfy" datatype CommonState = CommonStateConstructor(key_pair:RSAKeyPairSpec, key_bits:nat) datatype CommonStateMachine = CommonStateMachine_ctor(initialized:bool, common_state:CommonState, TPM:TPM_struct) ghost var {:readonly} current_common_state:CommonStateMachine; static predicate {:autoReq} PCR19ReflectsKey (state:CommonState, before_TPM:TPM_struct, after_TPM:TPM_struct) { var encoded_public_key := rfc4251_sshrsa_encoding(state.key_pair.pub.e, state.key_pair.pub.n); after_TPM.PCR_19 == before_TPM.PCR_19 + [BEWordSeqToByteSeq(SHA1(BEByteSeqToBitSeq(encoded_public_key)))] } static predicate {:autoReq} CommonStateGeneratedCorrectly (key_bits:nat, state:CommonState, before_TPM:TPM_struct, after_TPM:TPM_struct) { state.key_bits == key_bits && RSAKeyGenerationValid(state.key_bits, state.key_pair, TPM_random_bytes(before_TPM.random_index, after_TPM.random_index)) && Locality3_obtained() && TPM_valid(after_TPM) && TPM_satisfies_integrity_policy(after_TPM) && PCR19ReflectsKey(state, before_TPM, after_TPM) && TPMs_match(after_TPM, before_TPM[random_index := after_TPM.random_index][PCR_19 := after_TPM.PCR_19]) } //- This function is used to ensure that the routine to get a quote operates correctly. //- It should output the public key and quote. static predicate {:autoReq} HandleGetQuoteRequestValid (state:CommonState, old_TPM:TPM_struct, new_TPM:TPM_struct, nonce_external_in:seq, encoded_public_key_out:seq, pcr_info_bytes_out:seq, sig_bytes_out:seq) { TPMs_match(new_TPM, old_TPM) && encoded_public_key_out == rfc4251_sshrsa_encoding(state.key_pair.pub.e, state.key_pair.pub.n) && Verve_quote(pcr_info_bytes_out, sig_bytes_out, nonce_external_in, old_TPM.PCR_19) } ghost method {:axiom} {:autoReq} InitializeCommonStateMachine(common_state:CommonState) requires !current_common_state.initialized; requires CommonStateGeneratedCorrectly(1024, common_state, current_common_state.TPM, TPM); ensures current_common_state == CommonStateMachine_ctor(true, common_state, TPM); modifies this`current_common_state; ghost method {:axiom} {:autoReq} AdvanceCommonStateMachineViaGetQuote (nonce_external_in:seq, encoded_public_key_out:seq, pcr_info_bytes_out:seq, sig_bytes_out:seq) returns (declassified_encoded_public_key_out:seq, declassified_pcr_info_bytes_out:seq, declassified_sig_bytes_out:seq) requires current_common_state.initialized; requires public(nonce_external_in); requires HandleGetQuoteRequestValid(current_common_state.common_state, current_common_state.TPM, TPM, nonce_external_in, encoded_public_key_out, pcr_info_bytes_out, sig_bytes_out); modifies this`current_common_state; ensures current_common_state == old(current_common_state)[TPM := TPM]; ensures IsByteSeqOfLen(declassified_encoded_public_key_out, |encoded_public_key_out|); ensures public(|encoded_public_key_out|); ensures relation(forall i :: left(i) == right(i) && 0 <= left(i) < left(|declassified_encoded_public_key_out|) ==> declassified(left(declassified_encoded_public_key_out[i]), right(declassified_encoded_public_key_out[i]), left(encoded_public_key_out[i]), right(encoded_public_key_out[i]))); ensures IsByteSeqOfLen(declassified_pcr_info_bytes_out, |pcr_info_bytes_out|); ensures public(|pcr_info_bytes_out|); ensures relation(forall i :: left(i) == right(i) && 0 <= left(i) < left(|declassified_pcr_info_bytes_out|) ==> declassified(left(declassified_pcr_info_bytes_out[i]), right(declassified_pcr_info_bytes_out[i]), left(pcr_info_bytes_out[i]), right(pcr_info_bytes_out[i]))); ensures public(|sig_bytes_out|); ensures IsByteSeqOfLen(declassified_sig_bytes_out, |sig_bytes_out|); ensures relation(forall i :: left(i) == right(i) && 0 <= left(i) < left(|declassified_sig_bytes_out|) ==> declassified(left(declassified_sig_bytes_out[i]), right(declassified_sig_bytes_out[i]), left(sig_bytes_out[i]), right(sig_bytes_out[i]))); ================================================ FILE: ironclad-apps/src/Dafny/Apps/DafnyCCTest/Main.i.dfy ================================================ //- //- //- //- //- //-private-import Core; //-private-import LogicalAddressing; //-private-import Overflow; //-private-import Util; //-private-import Stacks; //-private-import Partition; //-private-import Instructions; //-private-import Separation; //-private-import IntLemmasBase; //-private-import IntLemmasGc; //-private-import SimpleGcMemory; //-private-import SimpleCommon; //-private-import SimpleCollector; //-private-import IoMain; //-private-import IntLemmasMain; //-private-basmonly-import Trusted; //-private-basmonly-import Checked; //-private-import Heap; //-private-import Seq; //-private-import dafny_DafnyPrelude; //-private-import DafnyAssembly; //-private-import dafny_relational_s; //-private-import dafny_base_s; //-private-import dafny_power2_s; //-private-import dafny_mul_i; //-private-import dafny_assembly_i; //-private-import dafny_bit_vector_lemmas_i; //-private-import dafny_Main_i; //- //- //- include "../../../Dafny/Libraries/Util/relational.s.dfy" include "../../../Dafny/Libraries/Math/power2.s.dfy" include "../../../Dafny/Libraries/Math/mul.i.dfy" include "../../../Dafny/Drivers/CPU/assembly.i.dfy" include "../../../Dafny/Libraries/Math/bit_vector_lemmas.i.dfy" /* function True(x:int) : bool { true } method rel1(x:int, y:int) returns(z:int) requires relation(left(x) == right(x)); requires relation(True(left(x)) == True(right(x))); requires public(y); //- Equivalent to: relation(left(y) == right(y)); ensures relation(left(z) == right(z)); { z := x + y; } method rel2(x:int, y:int) returns(z:int) requires relation(left(x) == right(x)); ensures relation(left(z) == right(z)); { z := 0; //- z := rel1(x, y); //- should fail symdiff checking if uncommented z := rel1(x, x); //- if (y > 1) //- should fail symdiff checking if uncommented if (x > 1) { z := 1; } } method rel3(x:int, y:int) returns(z:int, w:int) requires relation(left(x) == right(x)); ensures relation(left(z) == right(z)); { z := 0; w := 0; //- while (z < y) //- should fail symdiff checking if uncommented while (z < x) invariant relation(left(x) == right(x)); invariant relation(left(z) == right(z)); invariant public(w); { //- z := z + y; //- should fail symdiff checking if uncommented z := z + y + 1 - y; } z := 5; } method rel4(x:int, y:int, s:int) returns(z:int) requires public(x); requires public(y); ensures public(z); { z := rel1(x, y); z := rel1(z, y); z := rel1(x, z); z := rel1(z, z); //- z := rel1(z, s); //- should fail symdiff checking if uncommented z := rel1(z, z); } method rel5(n:int) returns(s:seq) requires public(n); ensures public(s); { var i:int := 0; s := []; while (i < n) invariant public(i); invariant public(n); invariant public(s); { s := [i] + s; } } datatype D = D(d:int); method rel6(D:D) returns(d:int) requires public(D); ensures public(D.d); ensures public(d); { d := D.d; } method relQ(x:seq) returns(y:seq) requires relation(left(|x|) == right(|x|)); requires relation(forall i :: 0 <= i < |left(x)| ==> left(x[i]) == right(x[i])); ensures relation(|left(y)| == |right(y)|); ensures relation(forall i :: 0 <= i < right(|y|) ==> left(y)[i] == right(y)[i]); { y := x; } /* Example below behaves as expected in SymDiff Commented out, since the bodyless gen_secret causes compilation to fail. method gen_secret() returns (s:int) method rel4(x:int) returns(z:int) requires public(x); ensures public(z); { var secret := gen_secret(); //-z := x + secret; //- Causes the ensures to fail z := x + secret + 1 - secret; } */ method rel5(s:seq) returns (i:int) requires |s| == 1; requires public(s); ensures public(i); { i := s[0]; } method rel6(s:seq) returns (s_new:seq) requires |s| == 10; requires public(s); ensures public(s_new); { s_new := s[0..5]; } method rel7(s:seq, x:int) returns (t:seq) requires public(s); requires public(x); ensures public(t); { t := s + [x]; } method clone_array(a:array) returns(b:array) ensures b != a; ensures a.Length == b.Length; ensures (forall i::0 <= i < a.Length ==> b[i] == a[i]); ensures fresh(b); { b := new int[a.Length]; var k := 0; var n := a.Length; while (k < n) invariant 0 <= k <= a.Length; invariant a.Length == b.Length == n; invariant (forall i::0 <= i < k ==> b[i] == a[i]); invariant fresh(b); { b[k] := a[k]; k := k + 1; } } /* method test_modifies1(a:array) requires a.Length > 0; modifies a; ensures a[0] == 10; { a[0] := 10; } method test_modifies2(a:array, b:array) requires a != null; requires a.Length > 0; requires b.Length > 0; requires b[0] == 20; requires a != b; modifies a; ensures a[0] == 10; ensures b[0] == 20; { var k:int := 0; test_modifies1(a); while(k < 10) invariant a[0] == 10; { test_modifies1(a); k := k + 1; } assert a[0] == 10; assert b[0] == 20; } method test_seq() { //- assert [10,20] + [30] == [10,20,30]; //- assert [10,20,30][1..] == [20,30]; //- assert [10,20,30][1] == 20; //- assert [10,20,30][..1] == [10]; //- assert [10,20,30][1:=40] == [10,40,30]; var x := [10,20] + [30,40]; //- var n := |x|; //- assert n == 4; //- x := x[1..3]; //- assert x == [20,30]; var n := x[2]; assert n == 30; } method testNat(x:nat) returns(y:nat) { y := 0; while (y < 100) { y := y + 1 + x; } assert power2(100) > 0; } datatype List = Nil() | Cons(hd:A, tl:List); datatype DT = DT1(x1:int, y1:int) | DT2(x2:int, a2:List, y2:int, b2:DT, z2:int); function len(l:List):int ensures len(l) >= 0; { if l.Cons? then 1 + len(l.tl) else 0 } ghost method Length(l:List) returns(n:int) ensures n == len(l); { if (l.Cons?) { var m:int := Length(l.tl); n := 1 + m; } else { n := 0; } } ghost method TestLength() { var n:int; n := Length(Cons(10, Cons(20, Nil()))); assert unroll(1) && unroll(2); assert n == 2; } method GetLength(l:List) returns(n:int) ensures n == len(l); { n := 0; var iter := l; while (iter.Cons?) decreases len(iter); invariant n + len(iter) == len(l); { iter := iter.tl; n := n + 1; } } method TestGetLength() { var n:int; n := GetLength(Cons(10, Cons(20, Nil()))); assert unroll(1) && unroll(2); assert n == 2; } function method id(a:A):A { a } method Foo(i:int, j:int) returns(k:int) requires i >= 5 && j >= 6; ensures k == id(i) + j; { TestLength(); k := i + id(j); } method Bar() returns(k:int) ensures k == 15; { k := Foo(7, 8); } method A(x:List) returns(y:List) ensures x == y; { var i:int := 0; var z:List; z := x; y := z; while (i < 10) invariant y == x; { Skip(); i := i + 1; } } method Skip() { } method B(x:List) returns(y:List) ensures x == y; { var i:int := 0; var z:List; z := x; while (i < 10) invariant z == x; { Skip(); z := A(z); Skip(); i := i + 1; } y := z; } method TestAlloc(x:List) returns(y:List) ensures y.tl.hd == 20; ensures y == Cons(10, Cons(20, Nil())); ensures y.Cons?; { y := B(Cons(10, Cons(20, Nil()))); var b:bool := y.Nil?; assert y.hd == 10; assert y.tl.hd == 20; var i:int := y.hd; var j:int := y.tl.hd; assert !b; assert i == 10; assert j == 20; var d:DT := DT2(100, x, 200, DT1(1000, 2000), 300); assert d.DT2?; b := d.DT2?; assert b; assert d.b2.y1 == 2000; i := d.b2.y1; assert i == 2000; } */ */ //- From Dafny sample files method Cube(N: int) returns (c: int) requires 0 <= N; ensures c == N*N*N; { c := 0; var n := 0; var k := 1; var m := 6; while (n < N) invariant n <= N; invariant c == n*n*n; invariant k == 3*n*n + 3*n + 1; invariant m == 6*n + 6; { calc { 3 * (n + 1) * (n + 1) + 3 * (n + 1) + 1; (3 * n + 3) * (n + 1) + 3 * n + 4; { lemma_mul_is_distributive_forall(); } (3 * n + 3) * n + (3 * n + 3) * 1 + 3 * n + 4; { lemma_mul_is_distributive_forall(); } 3 * n * n + 3 * n + 3 * n + 3 + 3 * n + 4; k + m; } calc { (n + 1) * (n + 1) * (n + 1); { lemma_mul_is_distributive_forall(); } ((n + 1) * n + (n + 1) * 1) * (n + 1); { lemma_mul_is_distributive_forall(); } ((n * n + 1 * n) + (n * 1 + 1 * 1)) * (n + 1); (n * n + 2 * n + 1) * (n + 1); { lemma_mul_is_distributive_forall(); } (n * n + 2 * n + 1) * n + (n * n + 2 * n + 1) * 1; { lemma_mul_is_distributive_forall(); } n * n * n + 2 * n * n + 1 * n + n * n + 2 * n + 1; n * n * n + ((2 * n * n + 1 * n * n) + (1 * n + 2 * n) + 1); { lemma_mul_is_distributive_forall(); } n * n * n + ((2 + 1) * n * n + (1 + 2) * n + 1); c + k; } c := c + k; k := k + m; m := m + 6; n := n + 1; } return; } method Main() returns (result:int) { //-lemma_xor_bytes(0, 0); result := Cube(5); } /* function method{:axiom}{:imported} word_32(x:int):bool function method{:axiom}{:imported} and (x:int, y:int):int function method{:axiom}{:imported} or (x:int, y:int):int function method{:axiom}{:imported} xor (x:int, y:int):int /* //- mutural summay ensures that M_1[r_1] == M_2[r_2] //- ghost method Sample (M:map) returns (r:int) //- requires (forall x:int, y:int :: x in M && y in M ==> M[x] == M[y] ==> x == y); method{:axiom}{:imported} serialPortOut (x:int) method{:axiom}{:imported} serialPortIn () returns (r:int) ensures (word_32(r)); method{:axiom}{:imported} sample (ghost M:map) returns (r:int) ghost method{:axiom}{:imported} SampleLemma(p:int, M:map) ensures (forall x:int :: x in M ==> M[x] == xor(x,p)); */ ghost method{:axiom}{:imported} XorLemmas() ensures (forall x:int::xor(x, x) == 0); ensures (forall x:int::word_32(x) ==> xor(x, 0) == x); ensures (forall x:int, y:int::xor(x, y) == xor(y, x)); ensures (forall x:int, y:int:: word_32(x) && word_32(y) ==> word_32(xor(x, y))); ensures (forall x:int, y:int, z:int:: xor(x, xor(y,z)) == xor(y, xor(x,z))); ensures (forall x:int, y:int:: xor(x,xor(y,x)) == y); method XorIdentity(a:int) returns(r:int) requires word_32(a); ensures r == a; { XorLemmas(); lemma_word32(a); r := xor(xor(a, a), a); var z := asm_BitwiseXor(a, a); } /* method pad_one_block (p:int) returns (r:int) requires word_32(p); //- ensures r == One_Time_Pad(p, old(sample_index)); //- ensures (exists s:int :: sampleCall(old(index), index, s) && r == xor(p,s)); //- relational verification should verify that true ==> r<1> == r<2> { XorLemmas(); //- var i:int := 0; var k:int; ghost var M:map; SampleLemma(p, M); k := sample(M); r := xor(k,p); assert r == xor(k,p); //- return r; } method one_time_pad( ) returns () modifies this; //- add requirement on maintaining the serial port queue later //- requires ps != null; //- requires forall i :: 0<= i < index ==> word_32(ps[i]); //- ensures rs != null; //- ensures ps.Length == rs.Length; //- ensures forall i :: 0<= i < index ==> rs[i] == xor (k, ps[i]); //- ensures forall i :: 0<= i < index ==> word_32(rs[i]); { //- read in a value (plain text) from serial port var length:int := 10; var index:int := 0; var p:int := 0; var r:int := 0; //-while (index < length) { p := serialPortIn(); r := pad_one_block (p); //- write the xor(p,k) (encryption) to the serial port serialPortOut(r); index := index+1; //-} } */ /* encryption of multiple blocks. This function ensures that: 1. each block b is encrypted into xor(b,k), where k is the global key 2. each encrypted blocks are still words */ /* method Encrypt (ps: array, k:int) returns (rs: array) requires ps != null; requires forall i :: 0<= i < ps.Length ==> word_32(ps[i]); requires word_32(k); ensures rs != null; ensures ps.Length == rs.Length; ensures forall i :: 0<= i < ps.Length ==> rs[i] == xor (k, ps[i]); ensures forall i :: 0<= i < ps.Length ==> word_32(rs[i]); { var index:int := 0; rs := new int[ps.Length]; while (index < ps.Length) invariant 0 <= index <= ps.Length; invariant forall i :: 0 <= i < index ==> rs[i] == xor(k, ps[i]); { if (index == ps.Length) {break;} rs := encrypt_nat(ps, k, index); index := index + 1; } } */ */ ================================================ FILE: ironclad-apps/src/Dafny/Apps/DiffPriv/.gitignore ================================================ *.bpl *.log ================================================ FILE: ironclad-apps/src/Dafny/Apps/DiffPriv/Database.s.dfy ================================================ include "../../Libraries/Util/be_sequences.s.dfy" include "Math.s.dfy" datatype Row = Row_ctor(nonce:seq, data:seq); static predicate RowValid(row:Row) { IsWordSeq(row.data) } static predicate DatabaseValid(db:seq) { forall i:int :: 0 <= i < |db| ==> RowValid(db[i]) } static predicate DatabasesIdenticalExceptForOneRow (db1:seq, db2:seq, diff_row:int) { |db1| == |db2| && (forall i :: 0 <= i < |db1| && i != diff_row ==> db1[i] == db2[i]) } static predicate DatabasesSimilar (db1:seq, db2:seq) { exists diff_row :: DatabasesIdenticalExceptForOneRow(db1, db2, diff_row) } static predicate DatabaseContainsNonce (db:seq, nonce:seq) { exists i:int :: 0 <= i < |db| && db[i].nonce == nonce } ================================================ FILE: ironclad-apps/src/Dafny/Apps/DiffPriv/DiffPriv.i.dfy ================================================ //- //- include "../../Libraries/BigNum/BigRat.i.dfy" include "../../Libraries/Util/relational.s.dfy" include "../../Libraries/Util/arrays_and_seqs.i.dfy" include "../../Drivers/TPM/tpm-wrapper.i.dfy" include "../../Libraries/Crypto/RSA/RSA_Decrypt.i.dfy" include "DiffPriv.s.dfy" include "PacketParsing.i.dfy" include "ErrorCodes.i.dfy" include "Noise.i.dfy" include "SumReducer.i.dfy" include "RelationalProperties.i.dfy" include "../Common/CommonState.i.dfy" static function method{:CompiledSpec} CompiledSpec_Clip (value:int, min:int, max:int):int //-//////////////////////////////////////////// //- DiffPrivStateImpl //-//////////////////////////////////////////// datatype DiffPrivStateImpl = DiffPrivStateImpl_ctor(db:seq, budget:BigRat, rows_received:int); static function DiffPrivStateImplToSpec(s:DiffPrivStateImpl) : DiffPrivState { DiffPrivState_ctor(s.db, if WellformedBigRat(s.budget) then RV(s.budget) else 0.0, s.rows_received) } //-//////////////////////////////////////////// //- Query parameters //-//////////////////////////////////////////// static method GetDiffPrivParametersFromQueryParameters (q:QueryParametersImpl) returns (p:DiffPrivParametersImpl) requires QueryParametersImplValid(q); requires QueryParametersValid(QueryParametersImplToSpec(q)); ensures WellformedDiffPrivParameters(p); ensures DiffPrivParametersImplToSpec(p) == QueryParametersToDiffPrivParameters(QueryParametersImplToSpec(q)); requires public(q); ensures public(p); { var alpha := BigRat_ctor(MakeSmallLiteralBigNum(q.alpha_num), MakeSmallLiteralBigNat(q.alpha_den)); var beta := BigRat_ctor(MakeSmallLiteralBigNum(q.beta_num), MakeSmallLiteralBigNat(q.beta_den)); var delta := DivideRoundingUp(q.row_max - q.row_min, q.answer_units); Lemma_DivideRoundingUpPreservesWord32(q.row_max - q.row_min, q.answer_units); var B := q.answer_max - q.answer_min; assert RV(alpha) == real(q.alpha_num) / real(q.alpha_den); assert RV(beta) == real(q.beta_num) / real(q.beta_den); p := DiffPrivParametersImpl_ctor(alpha, beta, delta, B); } //-//////////////////////////////////////////// //- Comparing to one //-//////////////////////////////////////////// static lemma Lemma_CompareDivisionToOne(x:int, y:int) requires x >= 0; requires y > 0; ensures var x_over_y := real(x) / real(y); (x < y ==> x_over_y < 1.0) && (x == y ==> x_over_y == 1.0) && (x > y ==> x_over_y > 1.0); { if x == 0 { assert x < y; assert real(x) / real(y) == 0.0 < 1.0; } else { assert real(x) / real(x) == 1.0; if x == y { calc { real(x) / real(y); { assert real(y) == real(x); } real(x) / real(x); } } else if x < y { calc { real(x) / real(y); < { assert real(y) > real(x); } real(x) / real(x); } } else { assert x > y; calc { real(x) / real(y); > { lemma_real_div_gt(real(x), real(y)); } real(x) / real(x); } } } } //-//////////////////////////////////////////// //- Decrypting add-row requests //-//////////////////////////////////////////// static predicate WellformedDecryptedAddRowRequest(request:DecryptedAddRowRequest) { match request case DecryptedAddRowRequest_c(row, max_budget_num, max_budget_den) => RowValid(row) && Word32(max_budget_num) && Word32(max_budget_den) case InvalidAddRowRequest_c => true case UndecryptableAddRowRequest_c => true } static lemma Lemma_WellformedDecryptedAddRowRequest(request:DecryptedAddRowRequest) requires request.DecryptedAddRowRequest_c?; requires RowValid(request.row); requires Word32(request.max_budget_num); requires Word32(request.max_budget_den); ensures WellformedDecryptedAddRowRequest(request); { } static method ParseDecryptedAddRowRequest_impl (plaintext:seq) returns (request:DecryptedAddRowRequest) requires IsByteSeq(plaintext); ensures WellformedDecryptedAddRowRequest(request); ensures request == ParseDecryptedAddRowRequest(plaintext); { if |plaintext| < 16 { request := InvalidAddRowRequest_c(); return; } var row_nonce_size := BEFourBytesToWord_impl(plaintext[0..4]); var row_data_size := BEFourBytesToWord_impl(plaintext[4..8]); assert row_nonce_size == BEByteSeqToInt(plaintext[0..4]); assert row_data_size == BEByteSeqToInt(plaintext[4..8]); if row_nonce_size < 0 || row_data_size < 0 || |plaintext| < 16 + row_nonce_size + row_data_size || row_data_size % 4 != 0 { request := InvalidAddRowRequest_c(); return; } assert row_nonce_size >= 0 && row_data_size >= 0 && |plaintext| >= 16 + row_nonce_size + row_data_size && row_data_size % 4 == 0; ghost var fields := plaintext[8:4:4:row_nonce_size:row_data_size]; var max_budget_num := BEFourBytesToWord_impl(plaintext[8..12]); assert max_budget_num == BEByteSeqToInt(fields[1]); var max_budget_den := BEFourBytesToWord_impl(plaintext[12..16]); assert max_budget_den == BEByteSeqToInt(fields[2]); var row_nonce := plaintext[16..16+row_nonce_size]; assert row_nonce == fields[3]; var row_data := plaintext[16+row_nonce_size..16+row_nonce_size+row_data_size]; assert row_data == fields[4]; var row_data_words, padbytes := BEByteSeqToWordSeq_impl(row_data); assert row_data_words == BEByteSeqToWordSeq(row_data); var row:Row := Row_ctor(row_nonce, row_data_words); request := DecryptedAddRowRequest_c(row, max_budget_num, max_budget_den); Lemma_WellformedDecryptedAddRowRequest(request); } method DecryptAddRowRequest_impl(ciphertext:seq, key_pair:RSAKeyPairImpl) returns (request:DecryptedAddRowRequest) requires IsByteSeq(ciphertext); requires |ciphertext| > 0; requires WellformedRSAKeyPairImpl(key_pair); ensures AddRowRequestDecryptedCorrectly(ciphertext, KeyPairImplToSpec(key_pair), request); ensures WellformedDecryptedAddRowRequest(request); { var success, plaintext := Decrypt(key_pair, ciphertext); if !success { request := UndecryptableAddRowRequest_c(); return; } request := ParseDecryptedAddRowRequest_impl(plaintext); } //-//////////////////////////////////////////// //- Exported methods //-//////////////////////////////////////////// method DiffPrivInitialize() returns (diffpriv_state:DiffPrivStateImpl) ensures DiffPrivStateValid(DiffPrivStateImplToSpec(diffpriv_state)); ensures DiffPrivInitializeValid(DiffPrivStateImplToSpec(diffpriv_state)); ensures public(PublicPartOfDiffPrivState(DiffPrivStateImplToSpec(diffpriv_state))); { lemma_2toX(); var one := MakeSmallLiteralBigRat(1); diffpriv_state := DiffPrivStateImpl_ctor([], one, 0); assert PublicPartOfDiffPrivState(DiffPrivStateImplToSpec(diffpriv_state)) == DiffPrivState_ctor([], 1.0, 0); } static method DiffPrivInitializeDB(old_state:DiffPrivStateImpl, budget_num:int, budget_den:int) returns (error_code:int, new_state:DiffPrivStateImpl) requires DiffPrivStateValid(DiffPrivStateImplToSpec(old_state)); requires Word32(budget_num); requires Word32(budget_den); requires budget_den != 0; ensures Word32(error_code); ensures error_code == 0 ==> DiffPrivInitializedDBCorrectly(DiffPrivStateImplToSpec(old_state), DiffPrivStateImplToSpec(new_state), real(budget_num) / real(budget_den)); ensures error_code != 0 ==> new_state == old_state; requires public(PublicPartOfDiffPrivState(DiffPrivStateImplToSpec(old_state))); requires public(budget_num); requires public(budget_den); ensures public(PublicPartOfDiffPrivState(DiffPrivStateImplToSpec(new_state))); ensures public(error_code); { lemma_2toX(); if (old_state.rows_received != 0) { error_code := ErrorInitializingTooLate(); new_state := old_state; return; } assert real(budget_num) >= 0.0; assert real(budget_den) > 0.0; Lemma_CompareDivisionToOne(budget_num, budget_den); if budget_num < budget_den { error_code := ErrorBudgetLessThanOne(); new_state := old_state; return; } error_code := 0; //- At this point, the error code is set so we can look at private data. var budget := BigRat_ctor(MakeSmallLiteralBigNum(budget_num), MakeSmallLiteralBigNat(budget_den)); assert RV(budget) == real(budget_num) / real(budget_den); new_state := DiffPrivStateImpl_ctor([], budget, old_state.rows_received); } lemma Lemma_AddingValidRowToValidDatabasePreservesValidity (db_prev:seq, row:Row, db_next:seq) requires DatabaseValid(db_prev); requires RowValid(row); requires db_next == db_prev + [row]; ensures DatabaseValid(db_next); { } method DiffPrivAddRow (old_state:DiffPrivStateImpl, key_pair:RSAKeyPairImpl, request_ciphertext:seq) returns (new_state:DiffPrivStateImpl) requires DiffPrivStateValid(DiffPrivStateImplToSpec(old_state)); requires WellformedRSAKeyPairImpl(key_pair); requires IsByteSeq(request_ciphertext); requires |request_ciphertext| > 0; ensures DiffPrivRowAddedCorrectly(DiffPrivStateImplToSpec(old_state), DiffPrivStateImplToSpec(new_state), KeyPairImplToSpec(key_pair), request_ciphertext); requires public(PublicPartOfDiffPrivState(DiffPrivStateImplToSpec(old_state))); ensures public(PublicPartOfDiffPrivState(DiffPrivStateImplToSpec(new_state))); { lemma_2toX(); var request := DecryptAddRowRequest_impl(request_ciphertext, key_pair); new_state := old_state[rows_received := old_state.rows_received + 1]; if !request.DecryptedAddRowRequest_c? { return; } if request.max_budget_den == 0 { return; } var max_budget := BigRat_ctor(MakeSmallLiteralBigNum(request.max_budget_num), MakeSmallLiteralBigNat(request.max_budget_den)); var insufficient := BigRatGt(old_state.budget, max_budget); if insufficient { return; } //- At this point, the error code is set so we can look at private data. var already_exists:bool := DoesDatabaseContainNonce(old_state.db, request.row.nonce); if !already_exists { new_state := DiffPrivStateImpl_ctor(old_state.db + [request.row], old_state.budget, old_state.rows_received + 1); Lemma_AddingValidRowToValidDatabasePreservesValidity(old_state.db, request.row, new_state.db); assert DatabaseValid(DiffPrivStateImplToSpec(new_state).db); } } //-//////////////////////////////////////////// //- Helpers //-//////////////////////////////////////////// static method DoesDatabaseContainNonce (db:seq, nonce:seq) returns (already_exists:bool) requires DatabaseValid(db); ensures already_exists == DatabaseContainsNonce(db, nonce); { var i:int := 0; while i < |db| invariant 0 <= i <= |db|; invariant forall j :: 0 <= j < i ==> db[j].nonce != nonce; { if db[i].nonce == nonce { already_exists := true; return; } i := i + 1; } already_exists := false; } static method DetermineIfQueryParametersValid (q:QueryParametersImpl) returns (error_code:int, program:seq) requires QueryParametersImplValid(q); ensures Word32(error_code); ensures error_code == 0 <==> QueryParametersValid(QueryParametersImplToSpec(q)); ensures error_code == 0 ==> program == MessageToProgram(q.program_encoding); requires public(q); ensures public(error_code); ensures public(program); { lemma_2toX(); //- //- Validate the input values. //- program := []; //- dafnycc: initialize variable if (q.row_min > q.row_max) { error_code := ErrorRowMinGreaterThanRowMax(); return; } if (q.answer_min > q.answer_max) { error_code := ErrorAnswerMinGreaterThanAnswerMax(); return; } if (q.answer_units <= 0) { error_code := ErrorAnswerUnitsNotPositive(); return; } Lemma_CompareDivisionToOne(q.alpha_num, q.alpha_den); if (q.alpha_num <= q.alpha_den) { error_code := ErrorAlphaNotGreaterThanOne(); return; } Lemma_CompareDivisionToOne(q.beta_num, q.beta_den); if (q.beta_num <= q.beta_den) { error_code := ErrorBetaNotGreaterThanOne(); return; } //- //- Convert the program encoding into a program and validate it. //- program := ConvertMessageToProgram(q.program_encoding); var valid:bool := DetermineIfProgramIsValid(program); if (!valid) { error_code := ErrorProgramInvalid(); return; } error_code := 0; } method ParseQueryParameters (q:QueryParametersImpl) returns (error_code:int, program:seq, p:DiffPrivParametersImpl) requires QueryParametersImplValid(q); ensures Word32(error_code); ensures error_code == 0 ==> QueryParametersValid(QueryParametersImplToSpec(q)) && program == MessageToProgram(q.program_encoding) && ProgramValid(program) && Word32(q.answer_units * 2) && WellformedDiffPrivParameters(p) && DiffPrivParametersImplToSpec(p) == QueryParametersToDiffPrivParameters(QueryParametersImplToSpec(q)) && DiffPrivParametersValid(DiffPrivParametersImplToSpec(p)); requires public(q); ensures public(error_code); ensures public(program); ensures public(p); { //- //- Validate the input values. //- program := []; //- dafnycc: initialize variable var r0 := MakeSmallLiteralBigRat(0); p := DiffPrivParametersImpl_ctor(r0, r0, 0, 0); //- dafnycc: initialize variable error_code, program := DetermineIfQueryParametersValid(q); if (error_code != 0) { return; } //- //- Make sure the answer units aren't too high. //- error_code := TestAnswerUnits(q.answer_units); if (error_code != 0) { return; } //- //- Compute noise parameters and validate them. //- p := GetDiffPrivParametersFromQueryParameters(q); error_code := DetermineIfDiffPrivParametersValid(p); } method GetErrorCodeForPerformQuery (q:QueryParametersImpl, budget:BigRat) returns (error_code:int, program:seq, p:DiffPrivParametersImpl, num_randoms_needed:nat) requires QueryParametersImplValid(q); requires WellformedBigRat(budget); ensures Word32(error_code); ensures error_code == 0 ==> QueryParametersValid(QueryParametersImplToSpec(q)) && program == MessageToProgram(q.program_encoding) && ProgramValid(program) && Word32(q.answer_units * 2) && WellformedDiffPrivParameters(p) && DiffPrivParametersImplToSpec(p) == QueryParametersToDiffPrivParameters(QueryParametersImplToSpec(q)) && DiffPrivParametersValid(DiffPrivParametersImplToSpec(p)) && RV(budget) >= RV(p.beta) && Word32((num_randoms_needed-1)*8+1) && SufficientBytesForNoiseGeneration(DiffPrivParametersImplToSpec(p), num_randoms_needed); requires public(q); requires public(RV(budget)); ensures public(error_code); ensures public(program); ensures public(p); ensures public(num_randoms_needed); { lemma_2toX(); error_code, program, p := ParseQueryParameters(q); num_randoms_needed := 0; //- dafnycc: initialize variable if error_code != 0 { return; } //- //- See if there's sufficient budget. //- var InsufficientPrivacyBudget:bool := BigRatGt(p.beta, budget); if InsufficientPrivacyBudget { error_code := ErrorInsufficientPrivacyBudget(); return; } //- //- Determine how many random numbers we need. //- error_code, num_randoms_needed := ComputeBytesForNoiseGeneration(p); } method GenerateNoise (p:DiffPrivParametersImpl, budget:BigRat, num_randoms_needed:nat) returns (negate_noise:bool, absolute_noise:nat, ghost noise:int, remaining_budget:BigRat, randoms_used:seq) requires WellformedDiffPrivParameters(p); requires DiffPrivParametersValid(DiffPrivParametersImplToSpec(p)); requires WellformedBigRat(budget); requires Word32((num_randoms_needed-1)*8+1); requires SufficientBytesForNoiseGeneration(DiffPrivParametersImplToSpec(p), num_randoms_needed); requires RV(budget) >= RV(p.beta) >= 1.0; ensures Word32(absolute_noise); ensures WellformedBigRat(remaining_budget); ensures IsByteSeq(randoms_used); ensures noise == (if negate_noise then -absolute_noise else absolute_noise); ensures NoiseComputedCorrectly(DiffPrivParametersImplToSpec(p), randoms_used, noise); ensures randoms_used == TPM_random_bytes(old(TPM.random_index), TPM.random_index); ensures RV(remaining_budget) == RV(budget) / RV(p.beta); requires TPM_ready(); ensures TPM_ready(); ensures TPMs_match_except_for_randoms(old(TPM), TPM); modifies this`TPM; modifies this`IoMemPerm; ensures old(TPM.random_index) <= TPM.random_index; { ghost var old_random_index := TPM.random_index; randoms_used := get_random(num_randoms_needed); //- Compute the noise to use. negate_noise, absolute_noise, noise := ComputeNoise(p, randoms_used); //- Reduce the budget by beta. Lemma_IfBigRatGeOneItsNotZero(p.beta); remaining_budget := BigRatDiv(budget, p.beta); assert SufficientBytesForNoiseGeneration(DiffPrivParametersImplToSpec(p), num_randoms_needed); assert SufficientBytesForNoiseGeneration(DiffPrivParametersImplToSpec(p), |randoms_used|); } static method TestAnswerUnits (answer_units:int) returns (error_code:int) requires Word32(answer_units); ensures Word32(error_code); ensures error_code == 0 ==> Word32(answer_units * 2); requires public(answer_units); ensures public(error_code); { lemma_2toX(); error_code := if answer_units < 0x80000000 then 0 else ErrorAnswerUnitsTooLarge(); } static method AddNoise (ghost db:seq, ghost sum:int, answer:int, q:QueryParametersImpl, negate_noise:bool, absolute_noise:nat, ghost noise:int) returns (response:int) requires DatabaseValid(db); requires QueryParametersImplValid(q); requires QueryParametersValid(QueryParametersImplToSpec(q)); requires sum == MapperSum(db, MessageToProgram(q.program_encoding), q.row_min, q.row_max); requires answer == Clip(Scale(sum, q.answer_units), q.answer_min, q.answer_max); requires noise == if negate_noise then -absolute_noise else absolute_noise; requires Word32(absolute_noise); ensures Word32(response); ensures sum == MapperSum(db, MessageToProgram(q.program_encoding), q.row_min, q.row_max); ensures response == QueryResponse(db, QueryParametersImplToSpec(q), noise); { var noised_answer:int; if negate_noise { if (answer < absolute_noise) { noised_answer := 0; } else { noised_answer := answer - absolute_noise; } } else { noised_answer := SaturatingAdd(answer, absolute_noise); } //- //- Clip the noised answer to get the response. //- response := Clip(noised_answer, q.answer_min, q.answer_max); Lemma_QueryResponseComputedCorrectly(db, sum, QueryParametersImplToSpec(q), negate_noise, absolute_noise, noise, answer, noised_answer, response); } //-//////////////////////// //- Lemmas //-//////////////////////// static lemma {:timeLimitMultiplier 3} Lemma_QueryPerformedCorrectly (old_state:DiffPrivState, new_state:DiffPrivState, q:QueryParameters, p:DiffPrivParameters, old_TPM:TPM_struct, new_TPM:TPM_struct, ghost noise:int, response:int) requires DiffPrivStateValid(old_state); requires QueryParametersValid(q); requires DiffPrivParametersValid(p); requires p == QueryParametersToDiffPrivParameters(q); requires Word32(response); requires old_state.budget >= p.beta >= 1.0; requires new_state.db == old_state.db; requires new_state.rows_received == old_state.rows_received; requires new_state.budget == old_state.budget / p.beta; requires TPMs_match_except_for_randoms(old_TPM, new_TPM); requires NoiseComputedCorrectly(p, TPM_random_bytes(old_TPM.random_index, new_TPM.random_index), noise); requires response == QueryResponse(old_state.db, q, noise); ensures DiffPrivQueryPerformedCorrectly(old_state, new_state, q, response, old_TPM, new_TPM); ensures new_state.budget >= 1.0; { reveal_DiffPrivQueryPerformedCorrectly(); var program := MessageToProgram(q.program_encoding); Lemma_DividingBySmallerProducesAtLeastOne(old_state.budget, p.beta); assert QuerySuccessfulTrigger(noise); Lemma_SensitivityOfComputeSum(program, q.row_min, q.row_max, q.answer_units, q.answer_min, q.answer_max, DivideRoundingUp(q.row_max - q.row_min, q.answer_units)); assert QuerySuccessful(old_state, new_state, q, response, TPM_random_bytes(old_TPM.random_index, new_TPM.random_index), noise); } static lemma Lemma_QueryResponseComputedCorrectly (ghost db:seq, ghost sum:int, q:QueryParameters, negate_noise:bool, absolute_noise:nat, ghost noise:int, answer:int, noised_answer:int, response:int) requires DatabaseValid(db); requires QueryParametersValid(q); requires Word32(absolute_noise); requires Word32(answer); requires Word32(noised_answer); requires Word32(response); requires sum == MapperSum(db, MessageToProgram(q.program_encoding), q.row_min, q.row_max); requires answer == Clip(Scale(sum, q.answer_units), q.answer_min, q.answer_max); requires noise == if negate_noise then -absolute_noise else absolute_noise; requires noised_answer == (if negate_noise then (if answer < absolute_noise then 0 else answer - absolute_noise) else SaturatingAdd(answer, absolute_noise)); requires response == Clip(noised_answer, q.answer_min, q.answer_max); ensures response == QueryResponse(db, q, noise); { } static lemma Lemma_DividingBySmallerProducesAtLeastOne (x:real, y:real) requires x >= y > 0.0; ensures x/y >= 1.0; { } static lemma Lemma_IfBigRatGeOneItsNotZero (Q:BigRat) requires WellformedBigRat(Q); requires RV(Q) >= 1.0; ensures nonzero(Q.n.value); { if !nonzero(Q.n.value) { calc { RV(Q); real(BV(Q.n)) / real(I(Q.d)); 0.0 / real(I(Q.d)); 0.0; } assert false; } } static lemma Lemma_IndexingIntoSequenceConcatenation (seq1:seq, seq2:seq, i:nat) requires |seq1| <= i < |seq1| + |seq2|; ensures (seq1 + seq2)[i] == seq2[i-|seq1|]; { } ================================================ FILE: ironclad-apps/src/Dafny/Apps/DiffPriv/DiffPriv.s.dfy ================================================ include "../../Libraries/Util/be_sequences.s.dfy" include "../../Libraries/Crypto/RSA/RSASpec.s.dfy" include "../../Libraries/Crypto/RSA/rfc4251.s.dfy" include "../Common/CommonState.s.dfy" include "../../Drivers/TPM/tpm-device.s.dfy" include "Mapper.s.dfy" include "SumReducer.s.dfy" include "Noise.s.dfy" datatype DiffPrivState = DiffPrivState_ctor(db:seq, budget:real, rows_received:int); static predicate DiffPrivStateValid (s:DiffPrivState) { DatabaseValid(s.db) && s.budget >= 1.0 } static function PublicPartOfDiffPrivState (s:DiffPrivState) : DiffPrivState { DiffPrivState_ctor([], s.budget, s.rows_received) } //- This function is used to ensure that DiffPriv initialization operates correctly. static predicate {:autoReq} DiffPrivInitializeValid(diffpriv_state:DiffPrivState) { diffpriv_state.db == [] && diffpriv_state.budget == 1.0 && diffpriv_state.rows_received == 0 } datatype QueryParameters = QueryParameters_ctor(program_encoding:seq, row_min:int, row_max:int, answer_units:int, answer_min:int, answer_max:int, alpha:real, beta:real) static predicate QueryParametersValid (q:QueryParameters) { Word32(q.row_min) && Word32(q.row_max) && Word32(q.answer_units) && Word32(q.answer_min) && Word32(q.answer_max) && q.row_min <= q.row_max && q.answer_min <= q.answer_max && q.alpha > 1.0 && q.beta > 1.0 && q.answer_units > 0 && IsWordSeq(q.program_encoding) && ProgramValid(MessageToProgram(q.program_encoding)) } static predicate DiffPrivInitializedDBCorrectly (old_state:DiffPrivState, new_state:DiffPrivState, budget:real) { DiffPrivStateValid(new_state) && budget >= 1.0 && old_state.rows_received == 0 && new_state.db == [] && new_state.budget == budget && new_state.rows_received == old_state.rows_received } datatype DecryptedAddRowRequest = DecryptedAddRowRequest_c(row:Row, max_budget_num:int, max_budget_den:int) | InvalidAddRowRequest_c() | UndecryptableAddRowRequest_c(); static function ParseDecryptedAddRowRequest(plaintext:seq) : DecryptedAddRowRequest requires IsByteSeq(plaintext); { if |plaintext| < 16 then InvalidAddRowRequest_c() else ( var row_nonce_size := BEByteSeqToInt(plaintext[0..4]); var row_data_size := BEByteSeqToInt(plaintext[4..8]); if row_nonce_size < 0 || row_data_size < 0 || |plaintext| < 16 + row_nonce_size + row_data_size || row_data_size % 4 != 0 then InvalidAddRowRequest_c() else (var fields := plaintext[8 :4 :4 :row_nonce_size :row_data_size ]; var _, max_budget_num, max_budget_den, row_nonce, row_data := fields[0], BEByteSeqToInt(fields[1]), BEByteSeqToInt(fields[2]), fields[3], fields[4] ; var row_data_words := BEIntToDigitSeq(power2(32), |row_data|/4, BEDigitSeqToInt(power2(8), row_data)); DecryptedAddRowRequest_c(Row_ctor(row_nonce, row_data_words), max_budget_num, max_budget_den)) ) } static predicate AddRowRequestDecryptedCorrectly(ciphertext:seq, key_pair:RSAKeyPairSpec, request:DecryptedAddRowRequest) requires IsByteSeq(ciphertext); { ( exists plaintext:seq :: RSADecryptionRelation(key_pair, ciphertext, plaintext) && request == ParseDecryptedAddRowRequest(plaintext) ) || ( request == UndecryptableAddRowRequest_c() && !exists plaintext:seq :: RSADecryptionRelation(key_pair, ciphertext, plaintext) ) } static predicate DiffPrivRowAddedCorrectly (old_state:DiffPrivState, new_state:DiffPrivState, key_pair:RSAKeyPairSpec, request_ciphertext:seq) { IsByteSeq(request_ciphertext) && DiffPrivStateValid(new_state) && new_state.budget == old_state.budget && new_state.rows_received == old_state.rows_received + 1 && ( exists request:DecryptedAddRowRequest :: AddRowRequestDecryptedCorrectly(request_ciphertext, key_pair, request) && if request.DecryptedAddRowRequest_c? && request.max_budget_den > 0 && old_state.budget <= real(request.max_budget_num) / real(request.max_budget_den) && !DatabaseContainsNonce(old_state.db, request.row.nonce) then new_state.db == old_state.db + [request.row] else new_state.db == old_state.db ) } static function QueryResponse (db:seq, q:QueryParameters, noise:int) : int requires DatabaseValid(db); requires QueryParametersValid(q); { var program := MessageToProgram(q.program_encoding); var sum := MapperSum(db, program, q.row_min, q.row_max); var scaled_sum := Scale(sum, q.answer_units); var answer := Clip(scaled_sum, q.answer_min, q.answer_max); var noised_answer := answer + noise; Clip(noised_answer, q.answer_min, q.answer_max) } static function QueryParametersToDiffPrivParameters (q:QueryParameters) : DiffPrivParameters requires QueryParametersValid(q); { DiffPrivParameters_ctor(q.alpha, q.beta, DivideRoundingUp(q.row_max - q.row_min, q.answer_units), q.answer_max - q.answer_min) } static predicate QuerySuccessful (old_state:DiffPrivState, new_state:DiffPrivState, q:QueryParameters, response:int, randoms_used:seq, noise:int) requires DiffPrivStateValid(old_state); requires QueryParametersValid(q); { var p := QueryParametersToDiffPrivParameters(q); DiffPrivParametersValid(p) && old_state.budget >= p.beta && new_state.db == old_state.db && new_state.rows_received == old_state.rows_received && new_state.budget == old_state.budget / p.beta && NoiseComputedCorrectly(p, randoms_used, noise) && response == QueryResponse(old_state.db, q, noise) && (forall db1:seq, db2:seq :: (var program, row_min, row_max, answer_units, answer_min, answer_max := MessageToProgram(q.program_encoding), q.row_min, q.row_max, q.answer_units, q.answer_min, q.answer_max; var delta := DivideRoundingUp(row_max - row_min, answer_units); DatabaseValid(db1) && DatabaseValid(db2) && DatabasesSimilar(db1, db2) ==> -delta <= Clip(Scale(MapperSum(db1, program, row_min, row_max), answer_units), answer_min, answer_max) - Clip(Scale(MapperSum(db2, program, row_min, row_max), answer_units), answer_min, answer_max) <= delta) ) } static predicate QuerySuccessfulTrigger (noise:int) { true } static predicate {:opaque} DiffPrivQueryPerformedCorrectly (old_state:DiffPrivState, new_state:DiffPrivState, q:QueryParameters, response:int, old_TPM:TPM_struct, new_TPM:TPM_struct) requires DiffPrivStateValid(old_state); { DiffPrivStateValid(new_state) && QueryParametersValid(q) && TPMs_match(new_TPM, old_TPM[random_index := new_TPM.random_index]) && (exists noise:int {:trigger QuerySuccessfulTrigger(noise)} :: QuerySuccessful(old_state, new_state, q, response, TPM_random_bytes(old_TPM.random_index, new_TPM.random_index), noise)) } ================================================ FILE: ironclad-apps/src/Dafny/Apps/DiffPriv/DiffPrivPerformQuery.i.dfy ================================================ //- //- include "../../Libraries/BigNum/BigRat.i.dfy" include "../../Libraries/Util/relational.s.dfy" include "../../Libraries/Util/arrays_and_seqs.i.dfy" include "../../Drivers/TPM/tpm-wrapper.i.dfy" include "DiffPriv.s.dfy" include "ErrorCodes.i.dfy" include "Noise.i.dfy" include "SumReducer.i.dfy" include "../Common/CommonState.i.dfy" include "DiffPriv.i.dfy" method {:dafnycc_conservative_seq_triggers} {:timeLimitMultiplier 3} DiffPrivPerformQuery (old_state:DiffPrivStateImpl, q:QueryParametersImpl) returns (error_code:int, response:int, new_state:DiffPrivStateImpl) requires DiffPrivStateValid(DiffPrivStateImplToSpec(old_state)); requires QueryParametersImplValid(q); ensures DiffPrivStateValid(DiffPrivStateImplToSpec(new_state)); ensures Word32(error_code); ensures Word32(response); ensures error_code == 0 ==> DiffPrivQueryPerformedCorrectly(DiffPrivStateImplToSpec(old_state), DiffPrivStateImplToSpec(new_state), QueryParametersImplToSpec(q), response, old(TPM), TPM); ensures error_code != 0 ==> TPM == old(TPM) && new_state == old_state; requires public(q); requires public(PublicPartOfDiffPrivState(DiffPrivStateImplToSpec(old_state))); ensures public(error_code); ensures public(PublicPartOfDiffPrivState(DiffPrivStateImplToSpec(new_state))); //- TPM stuff: requires TPM_ready(); ensures TPM_ready(); modifies this`TPM; modifies this`IoMemPerm; { var program:seq, p:DiffPrivParametersImpl, num_randoms_needed:nat; error_code, program, p, num_randoms_needed := GetErrorCodeForPerformQuery(q, old_state.budget); if error_code != 0 { response := 0; new_state := old_state; return; } //- //- At this point, the error code is set so we can look at private data. //- (All we looked at before was old_state.budget and |old_state.randoms|.) //- //- //- Generate the noise. //- var negate_noise:bool, absolute_noise:nat, remaining_budget:BigRat, remaining_randoms:seq; ghost var noise:int, randoms_used:seq; negate_noise, absolute_noise, noise, remaining_budget, randoms_used := GenerateNoise(p, old_state.budget, num_randoms_needed); //- //- Run the reducer. //- var answer:int; ghost var sum:int; answer, sum := ComputeSum(old_state.db, program, q.row_min, q.row_max, q.answer_units, q.answer_min, q.answer_max); //- //- Convert the answer into a response by adding noise and clipping. //- response := AddNoise(old_state.db, sum, answer, q, negate_noise, absolute_noise, noise); //- //- Update the state to reduce the privacy budget and remove the random numbers used. //- new_state := DiffPrivStateImpl_ctor(old_state.db, remaining_budget, old_state.rows_received); Lemma_QueryPerformedCorrectly(DiffPrivStateImplToSpec(old_state), DiffPrivStateImplToSpec(new_state), QueryParametersImplToSpec(q), DiffPrivParametersImplToSpec(p), old(TPM), TPM, noise, response); } ================================================ FILE: ironclad-apps/src/Dafny/Apps/DiffPriv/ErrorCodes.i.dfy ================================================ static function method ErrorRowMinGreaterThanRowMax() : int { 1 } static function method ErrorAnswerMinGreaterThanAnswerMax() : int { 2 } static function method ErrorAnswerUnitsNotPositive() : int { 3 } static function method ErrorProgramInvalid() : int { 4 } static function method ErrorAnswerRangeNotPositive() : int { 5 } static function method ErrorAlphaNotGreaterThanOne() : int { 6 } static function method ErrorBetaNotGreaterThanAlphaToPowerOfSensitivity() : int { 7 } static function method ErrorRequiresTooManyBitsOfRandomness() : int { 8 } static function method ErrorAlphaDenominatorZero() : int { 9 } static function method ErrorBetaDenominatorZero() : int { 10 } static function method ErrorInsufficientPrivacyBudget() : int { 11 } static function method ErrorInsufficientRandomness() : int { 12 } static function method ErrorBetaNotGreaterThanOne() : int { 13 } static function method ErrorBudgetDenominatorZero() : int { 14 } static function method ErrorTooMuchBudgetToAddRow() : int { 15 } static function method ErrorBudgetLessThanOne() : int { 16 } static function method ErrorAnswerUnitsTooLarge() : int { 17 } static function method ErrorInitializingTooLate() : int { 18 } ================================================ FILE: ironclad-apps/src/Dafny/Apps/DiffPriv/Main.i.dfy ================================================ //- //- include "StateMachine.i.dfy" include "../../Libraries/Net/Udp.i.dfy" method MainInitialize () returns (diffpriv_state:DiffPrivStateImpl, common_state:CommonStateImpl, net_state:network_state) requires TPM_valid(TPM); requires IoMemPerm.Null?; requires TPM_satisfies_integrity_policy(TPM); requires current_common_state.TPM == TPM; requires !current_common_state.initialized; requires !current_diffpriv_state.initialized; ensures DiffPrivStateValid(DiffPrivStateImplToSpec(diffpriv_state)); ensures TPM_ready(); ensures CommonStateImplValid(common_state); ensures common_state.key_pair.pub.size >= 1024 / 8; ensures KeyCanBeExtendedIntoPCR(CommonStateImplToSpec(common_state).key_pair); ensures current_common_state == CommonStateMachine_ctor(true, CommonStateImplToSpec(common_state), TPM); ensures current_diffpriv_state == DiffPrivStateMachine_ctor(true, DiffPrivStateImplToSpec(diffpriv_state)); ensures valid_network_state(net_state); modifies this`TPM; modifies this`IoMemPerm; modifies this`current_common_state; modifies this`current_diffpriv_state; ensures TPMs_match_except_for_randoms(TPM, old(TPM)[PCR_19 := TPM.PCR_19]); ensures TPM_valid(TPM); ensures IoMemPerm.Null?; ensures public(PublicPartOfDiffPrivState(DiffPrivStateImplToSpec(diffpriv_state))); ensures public(net_state); { var success:bool; success, net_state := init_network_card(); if !success { HaltMachine(0x40); } common_state := GenerateCommonState(1024); assert TPMs_match_except_for_randoms(TPM, old(TPM)[PCR_19 := TPM.PCR_19]); ghost var common_state_key_pair := common_state.key_pair; ghost var common_state_spec := CommonStateImplToSpec(common_state); InitializeCommonStateMachine(common_state_spec); diffpriv_state := DiffPrivInitialize(); ghost var diffpriv_state_spec := DiffPrivStateImplToSpec(diffpriv_state); assert DiffPrivInitializeValid(diffpriv_state_spec); InitializeDiffPrivStateMachine(diffpriv_state_spec); } method {:dafnycc_conservative_seq_triggers} MainOneStep (diffpriv_state_in:DiffPrivStateImpl, common_state_in:CommonStateImpl, net_state_in:network_state) returns (diffpriv_state_out:DiffPrivStateImpl, common_state_out:CommonStateImpl, net_state_out:network_state) requires TPM_ready(); requires valid_network_state(net_state_in); requires DiffPrivStateValid(DiffPrivStateImplToSpec(diffpriv_state_in)); requires CommonStateImplValid(common_state_in); requires common_state_in.key_pair.pub.size >= 1024 / 8; requires current_common_state == CommonStateMachine_ctor(true, CommonStateImplToSpec(common_state_in), TPM); requires current_diffpriv_state == DiffPrivStateMachine_ctor(true, DiffPrivStateImplToSpec(diffpriv_state_in)); ensures DiffPrivStateValid(DiffPrivStateImplToSpec(diffpriv_state_out)); ensures TPM_ready(); ensures valid_network_state(net_state_out); ensures current_diffpriv_state == DiffPrivStateMachine_ctor(true, DiffPrivStateImplToSpec(diffpriv_state_out)); ensures current_common_state == old(current_common_state)[TPM := TPM]; ensures CommonStateImplValid(common_state_out); ensures CommonStateImplToSpec(common_state_out) == CommonStateImplToSpec(common_state_in); requires public(PublicPartOfDiffPrivState(DiffPrivStateImplToSpec(diffpriv_state_in))); requires public(net_state_in); ensures public(PublicPartOfDiffPrivState(DiffPrivStateImplToSpec(diffpriv_state_out))); ensures public(net_state_out); modifies this`TPM; modifies this`IoMemPerm; modifies this`current_diffpriv_state; modifies this`current_common_state; { ghost var diffpriv_state_in_spec := DiffPrivStateImplToSpec(diffpriv_state_in); ghost var common_state_spec := CommonStateImplToSpec(common_state_in); ghost var common_state_key_pair := common_state_in.key_pair; var success:bool, client_eth:ethernet_addr, client_ip:IPv4Address, my_ip:IPv4Address, client_port:int, my_port:int, request_bytes:seq; success, net_state_out, client_eth, client_ip, my_ip, client_port, my_port, request_bytes := UdpReceive(net_state_in); if !success { diffpriv_state_out := diffpriv_state_in; common_state_out := common_state_in; return; } var response_bytes:seq; response_bytes, diffpriv_state_out, common_state_out := HandleOneRequestRaw(request_bytes, diffpriv_state_in, common_state_in); if |response_bytes| <= 1472 { net_state_out := UdpSend(net_state_out, client_eth, my_ip, client_ip, my_port, client_port, response_bytes); } } method Main () returns (result:int) requires TPM_valid(TPM); requires IoMemPerm.Null?; requires TPM_satisfies_integrity_policy(TPM); requires current_common_state.TPM == TPM; requires !current_common_state.initialized; requires !current_diffpriv_state.initialized; modifies this`TPM; modifies this`IoMemPerm; modifies this`current_common_state; modifies this`current_diffpriv_state; ensures public(true); //- Needed to convince DafnyCC this procedure involves relational calls { var diffpriv_state, common_state, net_state := MainInitialize(); while true invariant TPM_ready(); invariant DiffPrivStateValid(DiffPrivStateImplToSpec(diffpriv_state)); invariant valid_network_state(net_state); invariant CommonStateImplValid(common_state); invariant common_state.key_pair.pub.size >= 1024 / 8; invariant current_common_state == CommonStateMachine_ctor(true, CommonStateImplToSpec(common_state), TPM); invariant current_diffpriv_state == DiffPrivStateMachine_ctor(true, DiffPrivStateImplToSpec(diffpriv_state)); invariant public(PublicPartOfDiffPrivState(DiffPrivStateImplToSpec(diffpriv_state))); invariant public(net_state); decreases *; { diffpriv_state, common_state, net_state := MainOneStep(diffpriv_state, common_state, net_state); } return 0; } ================================================ FILE: ironclad-apps/src/Dafny/Apps/DiffPriv/Mapper.i.dfy ================================================ include "../../Libraries/Math/power2.i.dfy" include "../../Drivers/CPU/assembly_premium.i.dfy" include "Mapper.s.dfy" static function method{:CompiledSpec} CompiledSpec_BooleanToInt(b:bool):int static function method{:CompiledSpec} CompiledSpec_ExtractColumn(column_index:int, row:Row):int //-static function method{:CompiledSpec} CompiledSpec_StackSizeChangeFromOperation(t:Operation):int static function method{:CompiledSpec} CompiledSpec_WordToOperation(w:int):Operation //-/////////////////////////////////////////////////// //- Premium versions of spec functions //-/////////////////////////////////////////////////// static lemma Lemma_BooleanToInt_IsWord32(b:bool) ensures Word32(BooleanToInt(b)); { lemma_2toX(); } static lemma Lemma_ApplyBinaryInstructionProducesWords(inst:BinaryInstruction, v1:int, v2:int) requires Word32(v1); requires Word32(v2); ensures Word32(ApplyBinaryInstruction(inst, v1, v2)); { lemma_2toX(); reveal_Mod0x100000000(); reveal_ApplyBinaryInstruction(); if inst.InstAdd? { lemma_mod0x100000000(v1+v2); } else if inst.InstSub? { lemma_mod0x100000000(v1-v2); } else if inst.InstMul? { lemma_mod0x100000000(v1 * v2); } else if inst.InstDiv? { if (v2 != 0) { lemma_mod0x100000000(v1 / v2); } } else if inst.InstMod? { if (v2 != 0) { lemma_mod0x100000000(v1 % v2); } } else if inst.InstGt? { Lemma_BooleanToInt_IsWord32(v1 > v2); } else if inst.InstLt? { Lemma_BooleanToInt_IsWord32(v1 < v2); } else if inst.InstEq? { Lemma_BooleanToInt_IsWord32(v1 == v2); } else if inst.InstGe? { Lemma_BooleanToInt_IsWord32(v1 >= v2); } else if inst.InstLe? { Lemma_BooleanToInt_IsWord32(v1 <= v2); } } static method ApplyBinaryInstructionImpl(inst:BinaryInstruction, v1:int, v2:int) returns (result:int) requires Word32(v1); requires Word32(v2); ensures result == ApplyBinaryInstruction(inst, v1, v2); ensures Word32(result); { lemma_2toX(); reveal_Mod0x100000000(); reveal_ApplyBinaryInstruction(); if inst.InstAdd? { lemma_mod0x100000000(v1+v2); result := Asm_Add(v1, v2); } else if inst.InstSub? { lemma_mod0x100000000(v1-v2); result := Asm_Sub(v1, v2); } else if inst.InstMul? { lemma_mod0x100000000(v1 * v2); result := Asm_Mul(v1, v2); } else if inst.InstDiv? { if (v2 == 0) { result := 0; } else { lemma_mod0x100000000(v1 / v2); result := Asm_Div(v1, v2); } } else if inst.InstMod? { if (v2 == 0) { result := 0; } else { lemma_mod0x100000000(v1 % v2); result := Asm_Mod(v1, v2); } } else if inst.InstGt? { Lemma_BooleanToInt_IsWord32(v1 > v2); result := BooleanToInt(v1 > v2); } else if inst.InstLt? { Lemma_BooleanToInt_IsWord32(v1 < v2); result := BooleanToInt(v1 < v2); } else if inst.InstEq? { Lemma_BooleanToInt_IsWord32(v1 == v2); result := BooleanToInt(v1 == v2); } else if inst.InstGe? { Lemma_BooleanToInt_IsWord32(v1 >= v2); result := BooleanToInt(v1 >= v2); } else { assert inst.InstLe?; Lemma_BooleanToInt_IsWord32(v1 <= v2); result := BooleanToInt(v1 <= v2); } } static function HowOperationChangesExpressionStackWhenValid(op:Operation, estack:seq):seq requires |estack| + StackSizeChangeFromOperation(op) >= 1; ensures |HowOperationChangesExpressionStackWhenValid(op, estack)| == |estack| + StackSizeChangeFromOperation(op); { match op case OperationPush(i) => estack + [ExpInt(i)] case OperationColumn => estack[..|estack|-1] + [ExpColumn(estack[|estack|-1])] case OperationBinary(inst) => estack[..|estack| - 2] + [ExpBinary(inst, estack[|estack| - 2], estack[|estack| - 1])] case OperationIf => estack[..|estack| - 3] + [ExpIf(estack[|estack|-3], estack[|estack| - 2], estack[|estack| - 1])] } static lemma Lemma_HowOperationChangesExpressionStackWhenValidEquivalent(op:Operation, estack:seq) requires |estack| + StackSizeChangeFromOperation(op) >= 1; ensures HowOperationChangesExpressionStackWhenValid(op, estack) == HowOperationChangesExpressionStack(op, estack); { if op.OperationPush? { assert StackSizeChangeFromOperation(op) == 1; } else if op.OperationColumn? { assert StackSizeChangeFromOperation(op) == 0; } else if op.OperationBinary? { assert StackSizeChangeFromOperation(op) == -1; } else if op.OperationIf? { assert StackSizeChangeFromOperation(op) == -2; } } static function HowOperationChangesExpressionStack_premium(op:Operation, estack:seq):seq requires |estack| + StackSizeChangeFromOperation(op) >= 1; ensures HowOperationChangesExpressionStack_premium(op, estack) == HowOperationChangesExpressionStack(op, estack); { Lemma_HowOperationChangesExpressionStackWhenValidEquivalent(op, estack); HowOperationChangesExpressionStackWhenValid(op, estack) } static lemma Lemma_PrefixOfValidProgramPrefixIsValid(program:seq, k:int) requires ProgramPrefixValid(program); requires 1 <= k <= |program|; ensures ProgramPrefixValid(program[..k]); { var prefix := program[..k]; assert forall i :: 1 <= i <= |prefix| ==> prefix[..i] == program[..i]; } static lemma Lemma_PrefixesOfValidProgramPrefixesAreValid(program:seq) requires ProgramPrefixValid(program); ensures forall k :: 1 <= k <= |program| ==> ProgramPrefixValid(program[..k]); { forall k:int | 1 <= k <= |program| ensures ProgramPrefixValid(program[..k]); { Lemma_PrefixOfValidProgramPrefixIsValid(program, k); } } static lemma Lemma_StackSizeAfterRunningProgramPrefix(program:seq) requires ProgramPrefixValid(program); ensures |ProgramPrefixToExpressionStack(program)| == StackSizeAfterRunning(program); { reveal_ProgramPrefixToExpressionStack(); Lemma_PrefixesOfValidProgramPrefixesAreValid(program); assert program[..|program|] == program; assert |program| == 1 ==> StackSizeAfterRunning(program[..0]) + StackSizeChangeFromOperation(program[|program|-1]) >= 1; assert |program| > 1 ==> StackSizeAfterRunning(program[..|program|-1]) + StackSizeChangeFromOperation(program[|program|-1]) >= 1; if |program| == 0 { } else if |program| == 1 { } else { calc { StackSizeAfterRunning(program); StackSizeAfterRunning(program[..|program| - 1]) + StackSizeChangeFromOperation(program[|program| - 1]); { Lemma_StackSizeAfterRunningProgramPrefix(program[..|program|-1]); } |ProgramPrefixToExpressionStack(program[..|program|-1])| + StackSizeChangeFromOperation(program[|program| - 1]); } calc { |ProgramPrefixToExpressionStack(program[..|program|-1])| + StackSizeChangeFromOperation(program[|program| - 1]); == StackSizeAfterRunning(program); >= 1; } calc { |ProgramPrefixToExpressionStack(program[..|program|-1])| + StackSizeChangeFromOperation(program[|program| - 1]); |HowOperationChangesExpressionStackWhenValid(program[|program|-1], ProgramPrefixToExpressionStack(program[..|program|-1]))|; { Lemma_HowOperationChangesExpressionStackWhenValidEquivalent(program[|program|-1], ProgramPrefixToExpressionStack(program[..|program|-1])); } |HowOperationChangesExpressionStack(program[|program|-1], ProgramPrefixToExpressionStack(program[..|program|-1]))|; |ProgramPrefixToExpressionStack(program)|; } } } static lemma Lemma_ProgramPrefixToExpressionStackContainsOnlyWords(program:seq) requires ProgramPrefixValid(program); ensures ExpressionStackContainsOnlyWords(ProgramPrefixToExpressionStack(program)); { Lemma_PrefixesOfValidProgramPrefixesAreValid(program); assert program[..|program|] == program; assert |program| == 1 ==> StackSizeAfterRunning(program[..0]) + StackSizeChangeFromOperation(program[|program|-1]) >= 1; assert |program| > 1 ==> StackSizeAfterRunning(program[..|program|-1]) + StackSizeChangeFromOperation(program[|program|-1]) >= 1; reveal_ProgramPrefixToExpressionStack(); if |program| == 0 { } else { Lemma_ProgramPrefixToExpressionStackContainsOnlyWords(program[..|program|-1]); } } static lemma Lemma_EvaluateExpressionProducesWord(e:Expression, row:Row) requires ExpressionValid(e); requires RowValid(row); ensures Word32(EvaluateExpression(e, row)); { if e.ExpInt? { } else if e.ExpColumn? { Lemma_EvaluateExpressionProducesWord(e.col, row); } else if e.ExpBinary? { Lemma_EvaluateExpressionProducesWord(e.e1, row); Lemma_EvaluateExpressionProducesWord(e.e2, row); Lemma_ApplyBinaryInstructionProducesWords(e.inst, EvaluateExpression(e.e1, row), EvaluateExpression(e.e2, row)); } else if e.ExpIf? { Lemma_EvaluateExpressionProducesWord(e.e_cond, row); Lemma_EvaluateExpressionProducesWord(e.e_true, row); Lemma_EvaluateExpressionProducesWord(e.e_false, row); } } static function EvaluateExpression_premium(e:Expression, row:Row):int requires ExpressionValid(e); requires RowValid(row); ensures Word32(EvaluateExpression_premium(e, row)); ensures EvaluateExpression_premium(e, row) == EvaluateExpression(e, row); { Lemma_EvaluateExpressionProducesWord(e, row); EvaluateExpression(e, row) } static lemma Lemma_ProgramToExpressionYieldsValidExpression(program:seq) requires ProgramValid(program); ensures ExpressionValid(ProgramToExpression(program)); { var estack := ProgramPrefixToExpressionStack(program); Lemma_StackSizeAfterRunningProgramPrefix(program); assert |estack| == 1; Lemma_ProgramPrefixToExpressionStackContainsOnlyWords(program); } static function ProgramToExpression_premium(program:seq):Expression requires ProgramValid(program); ensures ExpressionValid(ProgramToExpression_premium(program)); ensures ProgramToExpression_premium(program) == ProgramToExpression(program); { Lemma_ProgramToExpressionYieldsValidExpression(program); ProgramToExpression(program) } static lemma Lemma_MessageToProgramCreatesProgramOfOnlyWords(message:seq) requires forall i :: 0 <= i < |message| ==> Word32(message[i]); ensures ProgramContainsOnlyWords(MessageToProgram(message)); { if |message| == 0 { } else { Lemma_MessageToProgramCreatesProgramOfOnlyWords(message[..|message|-1]); } } static function MessageToProgram_premium(message:seq):seq requires forall i :: 0 <= i < |message| ==> Word32(message[i]); ensures ProgramContainsOnlyWords(MessageToProgram_premium(message)); ensures MessageToProgram_premium(message) == MessageToProgram(message); { Lemma_MessageToProgramCreatesProgramOfOnlyWords(message); MessageToProgram(message) } static lemma Lemma_EvaluateProgramProducesWord(program:seq, row:Row) requires ProgramValid(program); requires RowValid(row); ensures Word32(EvaluateProgram(program, row)); { Lemma_ProgramToExpressionYieldsValidExpression(program); Lemma_EvaluateExpressionProducesWord(ProgramToExpression(program), row); } static function EvaluateProgram_premium(program:seq, row:Row):int requires ProgramValid(program); requires RowValid(row); ensures Word32(EvaluateProgram_premium(program, row)); ensures EvaluateProgram_premium(program, row) == EvaluateProgram(program, row); { Lemma_EvaluateProgramProducesWord(program, row); EvaluateProgram(program, row) } //-////////////////////////////////////////////////////////////////////// //- Methods //-////////////////////////////////////////////////////////////////////// static method DetermineIfProgramIsValid(program:seq) returns (ret:bool) requires ProgramContainsOnlyWords(program); ensures ret == ProgramValid(program); { var k := 0; var stack_size := 0; while k < |program| invariant 0 <= k <= |program|; invariant stack_size == StackSizeAfterRunning(program[..k]); invariant forall i :: 1 <= i <= k ==> StackSizeAfterRunning(program[..i]) >= 1; { //- stack_size := stack_size + StackSizeChangeFromOperation(program[k]); //- dafnycc TODO: signed arithmetic match program[k] { case OperationPush(i) => stack_size := stack_size + 1; case OperationColumn => {} case OperationBinary(inst) => stack_size := stack_size - 1; case OperationIf => stack_size := stack_size - 2; } assert program[..k] + [program[k]] == program[..k+1]; k := k + 1; assert StackSizeAfterRunning(program[..k]) == stack_size; if stack_size < 1 { return false; } } assert program[..k] == program; return stack_size == 1; } static method ConvertMessageToProgram(message:seq) returns (ret:seq) requires forall i :: 0 <= i < |message| ==> Word32(message[i]); ensures ProgramContainsOnlyWords(ret); ensures ret == MessageToProgram(message); { var i := 0; ret := []; while i < |message| invariant 0 <= i <= |message|; invariant ProgramContainsOnlyWords(ret); invariant ret == MessageToProgram(message[..i]); { ret := ret + [WordToOperation(message[i])]; assert message[..i] + [message[i]] == message[..i+1]; i := i + 1; } assert message[..i] == message; } static method{:dafnycc_conservative_seq_triggers} RunOneInstructionPush(program:seq, row:Row, k:int, stack:seq, ghost estack:seq, i:int) returns (new_stack:seq, ghost new_estack:seq) requires ProgramValid(program); requires RowValid(row); requires 0 <= k < |program|; requires |stack| == StackSizeAfterRunning(program[..k]); requires |estack| == |stack|; requires estack == ProgramPrefixToExpressionStack(program[..k]); requires forall i :: 0 <= i < |stack| ==> Word32(stack[i]); requires forall i :: 0 <= i < |estack| ==> ExpressionValid(estack[i]); requires forall i :: 0 <= i < |stack| ==> stack[i] == EvaluateExpression_premium(estack[i], row); requires program[k] == OperationPush(i); ensures |new_stack| == StackSizeAfterRunning(program[..k+1]); ensures |new_estack| == |new_stack|; ensures new_estack == ProgramPrefixToExpressionStack(program[..k+1]); ensures forall i :: 0 <= i < |new_stack| ==> Word32(new_stack[i]); ensures forall i :: 0 <= i < |new_estack| ==> ExpressionValid(new_estack[i]); ensures forall i :: 0 <= i < |new_stack| ==> new_stack[i] == EvaluateExpression_premium(new_estack[i], row); { assert program[..k+1] == program[..k] + [program[k]]; new_estack := estack + [ExpInt(i)]; new_stack := stack + [i]; reveal_ProgramPrefixToExpressionStack(); } static method{:dafnycc_conservative_seq_triggers} RunOneInstructionColumn(program:seq, row:Row, k:int, stack:seq, ghost estack:seq) returns (new_stack:seq, ghost new_estack:seq) requires ProgramValid(program); requires RowValid(row); requires 0 <= k < |program|; requires |stack| == StackSizeAfterRunning(program[..k]); requires |estack| == |stack|; requires estack == ProgramPrefixToExpressionStack(program[..k]); requires forall i :: 0 <= i < |stack| ==> Word32(stack[i]); requires forall i :: 0 <= i < |estack| ==> ExpressionValid(estack[i]); requires forall i :: 0 <= i < |stack| ==> stack[i] == EvaluateExpression_premium(estack[i], row); requires program[k] == OperationColumn; ensures |new_stack| == StackSizeAfterRunning(program[..k+1]); ensures |new_estack| == |new_stack|; ensures new_estack == ProgramPrefixToExpressionStack(program[..k+1]); ensures forall i :: 0 <= i < |new_stack| ==> Word32(new_stack[i]); ensures forall i :: 0 <= i < |new_estack| ==> ExpressionValid(new_estack[i]); ensures forall i :: 0 <= i < |new_stack| ==> new_stack[i] == EvaluateExpression_premium(new_estack[i], row); { assert program[..k+1] == program[..k] + [program[k]]; new_estack := estack[..|estack|-1] + [ExpColumn(estack[|estack|-1])]; new_stack := stack[..|stack|-1] + [ExtractColumn(stack[|stack|-1], row)]; reveal_ProgramPrefixToExpressionStack(); } static method{:dafnycc_conservative_seq_triggers} RunOneInstructionBinary(program:seq, row:Row, k:int, stack:seq, ghost estack:seq, inst:BinaryInstruction) returns (new_stack:seq, ghost new_estack:seq) requires ProgramValid(program); requires RowValid(row); requires 0 <= k < |program|; requires |stack| == StackSizeAfterRunning(program[..k]); requires |estack| == |stack|; requires estack == ProgramPrefixToExpressionStack(program[..k]); requires forall i :: 0 <= i < |stack| ==> Word32(stack[i]); requires forall i :: 0 <= i < |estack| ==> ExpressionValid(estack[i]); requires forall i :: 0 <= i < |stack| ==> stack[i] == EvaluateExpression_premium(estack[i], row); requires program[k] == OperationBinary(inst); ensures |new_stack| == StackSizeAfterRunning(program[..k+1]); ensures |new_estack| == |new_stack|; ensures new_estack == ProgramPrefixToExpressionStack(program[..k+1]); ensures forall i :: 0 <= i < |new_stack| ==> Word32(new_stack[i]); ensures forall i :: 0 <= i < |new_estack| ==> ExpressionValid(new_estack[i]); ensures forall i :: 0 <= i < |new_stack| ==> new_stack[i] == EvaluateExpression_premium(new_estack[i], row); { assert program[..k+1] == program[..k] + [program[k]]; new_estack := estack[..|estack| - 2] + [ExpBinary(inst, estack[|estack| - 2], estack[|estack| - 1])]; var result := ApplyBinaryInstructionImpl(inst, stack[|stack| - 2], stack[|stack| - 1]); new_stack := stack[..|stack| - 2] + [result]; reveal_ProgramPrefixToExpressionStack(); } static method{:dafnycc_conservative_seq_triggers} RunOneInstructionIf(program:seq, row:Row, k:int, stack:seq, ghost estack:seq) returns (new_stack:seq, ghost new_estack:seq) requires ProgramValid(program); requires RowValid(row); requires 0 <= k < |program|; requires |stack| == StackSizeAfterRunning(program[..k]); requires |estack| == |stack|; requires estack == ProgramPrefixToExpressionStack(program[..k]); requires forall i :: 0 <= i < |stack| ==> Word32(stack[i]); requires forall i :: 0 <= i < |estack| ==> ExpressionValid(estack[i]); requires forall i :: 0 <= i < |stack| ==> stack[i] == EvaluateExpression_premium(estack[i], row); requires program[k] == OperationIf; ensures |new_stack| == StackSizeAfterRunning(program[..k+1]); ensures |new_estack| == |new_stack|; ensures new_estack == ProgramPrefixToExpressionStack(program[..k+1]); ensures forall i :: 0 <= i < |new_stack| ==> Word32(new_stack[i]); ensures forall i :: 0 <= i < |new_estack| ==> ExpressionValid(new_estack[i]); ensures forall i :: 0 <= i < |new_stack| ==> new_stack[i] == EvaluateExpression_premium(new_estack[i], row); { assert program[..k+1] == program[..k] + [program[k]]; new_estack := estack[..|estack| - 3] + [ExpIf(estack[|estack|-3], estack[|estack| - 2], estack[|estack| - 1])]; new_stack := stack[..|stack| - 3] + [if stack[|stack|-3] != 0 then stack[|stack| - 2] else stack[|stack| - 1]]; reveal_ProgramPrefixToExpressionStack(); } static method{:dafnycc_conservative_seq_triggers} RunOneInstruction(program:seq, row:Row, k:int, stack:seq, ghost estack:seq) returns (new_stack:seq, ghost new_estack:seq) requires ProgramValid(program); requires RowValid(row); requires 0 <= k < |program|; requires |stack| == StackSizeAfterRunning(program[..k]); requires |estack| == |stack|; requires estack == ProgramPrefixToExpressionStack(program[..k]); requires forall i :: 0 <= i < |stack| ==> Word32(stack[i]); requires forall i :: 0 <= i < |estack| ==> ExpressionValid(estack[i]); requires forall i :: 0 <= i < |stack| ==> stack[i] == EvaluateExpression_premium(estack[i], row); ensures |new_stack| == StackSizeAfterRunning(program[..k+1]); ensures |new_estack| == |new_stack|; ensures new_estack == ProgramPrefixToExpressionStack(program[..k+1]); ensures forall i :: 0 <= i < |new_stack| ==> Word32(new_stack[i]); ensures forall i :: 0 <= i < |new_estack| ==> ExpressionValid(new_estack[i]); ensures forall i :: 0 <= i < |new_stack| ==> new_stack[i] == EvaluateExpression_premium(new_estack[i], row); { assert program[..k+1] == program[..k] + [program[k]]; match program[k] { case OperationPush(i) => new_stack, new_estack := RunOneInstructionPush(program, row, k, stack, estack, i); case OperationColumn => new_stack, new_estack := RunOneInstructionColumn(program, row, k, stack, estack); case OperationBinary(inst) => new_stack, new_estack := RunOneInstructionBinary(program, row, k, stack, estack, inst); case OperationIf => new_stack, new_estack := RunOneInstructionIf(program, row, k, stack, estack); } } static lemma lemma_EmptyProgramPrefixToExpressionStack(program:seq) ensures ProgramPrefixToExpressionStack(program[..0]) == []; { reveal_ProgramPrefixToExpressionStack(); } static method RunProgram(program:seq, row:Row) returns(ret:int) requires ProgramValid(program); requires RowValid(row); ensures ret == EvaluateExpression_premium(ProgramToExpression_premium(program), row); ensures Word32(ret); { var stack:seq := []; var k:int := 0; ghost var estack:seq := []; Lemma_PrefixesOfValidProgramPrefixesAreValid(program); lemma_EmptyProgramPrefixToExpressionStack(program); while (k < |program|) invariant 0 <= k <= |program|; invariant |stack| == StackSizeAfterRunning(program[..k]); invariant |estack| == |stack|; invariant estack == ProgramPrefixToExpressionStack(program[..k]); invariant forall i :: 0 <= i < |stack| ==> Word32(stack[i]); invariant forall i :: 0 <= i < |estack| ==> ExpressionValid(estack[i]); invariant forall i :: 0 <= i < |stack| ==> stack[i] == EvaluateExpression_premium(estack[i], row); { stack, estack := RunOneInstruction(program, row, k, stack, estack); k := k + 1; } assert program == program[..|program|]; assert |stack| == 1; ret := stack[0]; } ================================================ FILE: ironclad-apps/src/Dafny/Apps/DiffPriv/Mapper.s.dfy ================================================ include "../../Drivers/CPU/assembly.s.dfy" include "Database.s.dfy" //-///////////////////////////////////////// //- Binary instructions //-///////////////////////////////////////// datatype BinaryInstruction = InstAdd | InstSub | InstMul | InstDiv | InstMod | InstGt | InstLt | InstEq | InstGe | InstLe static function method BooleanToInt(b:bool):int { if b then 1 else 0 } static function{:opaque} Mod0x100000000(i:int):int { i % 0x100000000 } static function{:opaque} ApplyBinaryInstruction(inst:BinaryInstruction, v1:int, v2:int):int { match inst case InstAdd => Mod0x100000000(v1 + v2) case InstSub => Mod0x100000000(v1 - v2) case InstMul => Mod0x100000000(v1 * v2) case InstDiv => if v2 == 0 then 0 else Mod0x100000000(v1 / v2) case InstMod => if v2 == 0 then 0 else Mod0x100000000(v1 % v2) case InstGt => BooleanToInt(v1 > v2) case InstLt => BooleanToInt(v1 < v2) case InstEq => BooleanToInt(v1 == v2) case InstGe => BooleanToInt(v1 >= v2) case InstLe => BooleanToInt(v1 <= v2) } //-///////////////////////////////////////// //- Expressions //-///////////////////////////////////////// datatype Expression = ExpInt(i:int) | ExpColumn(col:Expression) | ExpBinary(inst:BinaryInstruction, e1:Expression, e2:Expression) | ExpIf(e_cond:Expression, e_true:Expression, e_false:Expression) static predicate ExpressionValid(e:Expression) { match e case ExpInt(i) => Word32(i) case ExpColumn(e1) => ExpressionValid(e1) case ExpBinary(inst, e1, e2) => ExpressionValid(e1) && ExpressionValid(e2) case ExpIf(e1, e2, e3) => ExpressionValid(e1) && ExpressionValid(e2) && ExpressionValid(e3) } static predicate ExpressionStackContainsOnlyWords(estack:seq) { forall i:int :: 0 <= i < |estack| ==> ExpressionValid(estack[i]) } static function EvaluateExpression(e:Expression, row:Row):int { match e case ExpInt(i) => i case ExpColumn(e1) => ExtractColumn(EvaluateExpression(e1, row), row) case ExpBinary(inst, e1, e2) => ApplyBinaryInstruction(inst, EvaluateExpression(e1, row), EvaluateExpression(e2, row)) case ExpIf(e_cond, e_true, e_false) => if EvaluateExpression(e_cond, row) != 0 then EvaluateExpression(e_true, row) else EvaluateExpression(e_false, row) } //-///////////////////////////////////////// //- Operations //-///////////////////////////////////////// static function method ExtractColumn(column_index:int, row:Row):int { if 0 <= column_index < |row.data| then row.data[column_index] else 0 } datatype Operation = OperationPush(i:int) | OperationColumn | OperationBinary(inst:BinaryInstruction) | OperationIf static predicate OperationValid(op:Operation) { if op.OperationPush? then Word32(op.i) else true } static function method StackSizeChangeFromOperation(t:Operation):int { match t case OperationPush(_) => 1 case OperationColumn => 0 case OperationBinary(_) => -1 case OperationIf => -2 } /////////////////////////////////////////// /////////////////////////////////////////// static predicate ProgramContainsOnlyWords(program:seq) { forall k :: 0 <= k < |program| ==> OperationValid(program[k]) } /////////////////////////////////////////// /////////////////////////////////////////// static function HowOperationChangesExpressionStack(op:Operation, estack:seq):seq { match op case OperationPush(i) => estack + [ExpInt(i)] case OperationColumn => if |estack| >= 1 then estack[..|estack|-1] + [ExpColumn(estack[|estack|-1])] else [] case OperationBinary(inst) => if |estack| >= 2 then estack[..|estack|-2] + [ExpBinary(inst, estack[|estack| - 2], estack[|estack| - 1])] else [] case OperationIf => if |estack| >= 3 then estack[..|estack|-3] + [ExpIf(estack[|estack|-3], estack[|estack| - 2], estack[|estack| - 1])] else [] } static function StackSizeAfterRunning(program:seq):int { if |program| == 0 then 0 else StackSizeAfterRunning(program[..|program| - 1]) + StackSizeChangeFromOperation(program[|program| - 1]) } static predicate ProgramPrefixValid(program:seq) { ProgramContainsOnlyWords(program) && forall k :: 1 <= k <= |program| ==> StackSizeAfterRunning(program[..k]) >= 1 } static predicate ProgramValid(program:seq) { ProgramPrefixValid(program) && StackSizeAfterRunning(program) == 1 } static function {:opaque} ProgramPrefixToExpressionStack(program:seq):seq { if |program| == 0 then [] else HowOperationChangesExpressionStack(program[|program|-1], ProgramPrefixToExpressionStack(program[..|program|-1])) } static function ProgramToExpression(program:seq):Expression { var estack := ProgramPrefixToExpressionStack(program); if |estack| == 1 then estack[0] else ExpInt(0) } static function EvaluateProgram(program:seq, row:Row):int { EvaluateExpression(ProgramToExpression(program), row) } /////////////////////////////////////////// /////////////////////////////////////////// static function method WordToOperation(w:int):Operation requires Word32(w); { if w == 2000000001 then OperationColumn else if w == 2000000002 then OperationIf else if w == 2000000003 then OperationBinary(InstAdd) else if w == 2000000004 then OperationBinary(InstSub) else if w == 2000000005 then OperationBinary(InstMul) else if w == 2000000006 then OperationBinary(InstDiv) else if w == 2000000007 then OperationBinary(InstMod) else if w == 2000000008 then OperationBinary(InstGt) else if w == 2000000009 then OperationBinary(InstLt) else if w == 2000000010 then OperationBinary(InstEq) else if w == 2000000011 then OperationBinary(InstGe) else if w == 2000000012 then OperationBinary(InstLe) else OperationPush(w) } static function MessageToProgram(message:seq):seq requires IsWordSeq(message); { if |message| == 0 then [] else MessageToProgram(message[..|message|-1]) + [WordToOperation(message[|message|-1])] } ================================================ FILE: ironclad-apps/src/Dafny/Apps/DiffPriv/Math.s.dfy ================================================ include "../../Libraries/Math/round.s.dfy" static function method Clip (value:int, min:int, max:int):int requires min <= max; ensures min <= Clip(value, min, max) <= max; { if value < min then min else if value > max then max else value } static function method Scale (value:int, units:int) : int requires units > 0; { (value / units) + (if (value % units) * 2 >= units then 1 else 0) } ================================================ FILE: ironclad-apps/src/Dafny/Apps/DiffPriv/Noise.i.dfy ================================================ //- //- //- include "Noise.s.dfy" include "../../Libraries/BigNum/BigRat.i.dfy" include "../../Libraries/Math/round.i.dfy" include "../../Libraries/Util/arrays_and_seqs.i.dfy" include "../../Libraries/Util/seqs_and_ints.i.dfy" include "../../Libraries/BigNum/BigNumBEAdaptor.i.dfy" include "ErrorCodes.i.dfy" datatype DiffPrivParametersImpl = DiffPrivParametersImpl_ctor(alpha:BigRat, beta:BigRat, delta:int, B:int); static function WellformedDiffPrivParameters (p:DiffPrivParametersImpl) : bool { WellformedBigRat(p.alpha) && WellformedBigRat(p.beta) && Word32(p.delta) && Word32(p.B) } static function DiffPrivParametersImplToSpec (p:DiffPrivParametersImpl) : DiffPrivParameters requires WellformedDiffPrivParameters(p); { DiffPrivParameters_ctor(RV(p.alpha), RV(p.beta), p.delta, p.B) } method BigRatPower(x:BigRat, e:int) returns (r:BigRat) requires WellformedBigRat(x); requires e >= 0; ensures WellformedBigRat(r); ensures RV(r) == RealPower(RV(x), e); { r := MakeSmallLiteralBigRat(1); var k := 0; while k < e invariant 0 <= k <= e; invariant WellformedBigRat(r); invariant RV(r) == RealPower(RV(x), k); { r := BigRatMul(r, x); k := k + 1; } } method BigRatMin (a:BigRat, b:BigRat) returns (r:BigRat) requires WellformedBigRat(a); requires WellformedBigRat(b); ensures WellformedBigRat(r); ensures RV(r) == RealMin(RV(a), RV(b)); { var a_less_than_b:bool := BigRatLt(a, b); if (a_less_than_b) { r := a; } else { r := b; } } method {:timeLimitMultiplier 2} FindHigherPowerOfTwo (y:BigRat) returns (success:bool, x:nat) requires WellformedBigRat(y); ensures Word32(x); ensures success ==> real(power2(x)) >= RV(y); requires public(RV(y)); ensures public(success); ensures public(x); { lemma_2toX(); reveal_power2(); x := 0; var two_to_x:BigNat := MakeSmallLiteralBigNat(1); var two:BigNat := MakeSmallLiteralBigNat(2); while x < 0xFFFFFFFF invariant Word32(x); invariant WellformedBigNat(two_to_x); invariant I(two_to_x) == power2(x); invariant public(RV(y)); invariant public(x); invariant public(I(two_to_x)); invariant public(I(two)); { var done:bool := BigRatGe(BigNatToBigRat(two_to_x), y); if (done) { success := true; return; } ghost var old_two_to_x := two_to_x; two_to_x := BigNatMul(two, two_to_x); calc { I(two_to_x); I(two) * I(old_two_to_x); I(two) * power2(x); { lemma_mul_is_mul_boogie(I(two), power2(x)); } 2 * power2(x); power2(x+1); } x := x + 1; } //- At the end of the loop, handle the case of x == 0xFFFFFFFF. success := BigRatGe(BigNatToBigRat(two_to_x), y); } method DetermineIfDiffPrivParametersValid (p:DiffPrivParametersImpl) returns (error_code:int) requires WellformedDiffPrivParameters(p); requires p.delta >= 0; ensures Word32(error_code); ensures error_code == 0 <==> DiffPrivParametersValid(DiffPrivParametersImplToSpec(p)); requires public(p); ensures public(error_code); { lemma_2toX(); if p.B <= 0 { error_code := ErrorAnswerRangeNotPositive(); return; } var One := MakeSmallLiteralBigRat(1); var AlphaLeOne:bool := BigRatLe(p.alpha, One); if (AlphaLeOne) { error_code := ErrorAlphaNotGreaterThanOne(); return; } var AlphaToDelta := BigRatPower(p.alpha, p.delta); var BetaLeAlphaToDelta := BigRatLe(p.beta, AlphaToDelta); if (BetaLeAlphaToDelta) { error_code := ErrorBetaNotGreaterThanAlphaToPowerOfSensitivity(); return; } Lemma_RealPowerPreservesGeOne(RV(p.alpha), p.delta); error_code := 0; } method {:timeLimitMultiplier 6} ComputeRequiredNoiseEntropyPart1 (p:DiffPrivParametersImpl) returns (entropy:BigRat) requires WellformedDiffPrivParameters(p); requires DiffPrivParametersValid(DiffPrivParametersImplToSpec(p)); ensures WellformedBigRat(entropy); ensures RV(entropy) == RequiredNoiseEntropyPart1(DiffPrivParametersImplToSpec(p)); ensures RV(entropy) > 0.0; { lemma_2toX(); var One := MakeSmallLiteralBigRat(1); var Two := MakeSmallLiteralBigRat(2); var AlphaPlusOne := BigRatAdd(p.alpha, One); var BetaPlusOne := BigRatAdd(p.beta, One); var AlphaToDelta := BigRatPower(p.alpha, p.delta); var BetaMinusAlphaToDelta := BigRatSub(p.beta, AlphaToDelta); var Numerator := BigRatMul(AlphaPlusOne, BetaPlusOne); var AlphaMinusOne := BigRatSub(p.alpha, One); var MinAlphaMinusOneAndTwo := BigRatMin(AlphaMinusOne, Two); var Denominator := BigRatMul(BetaMinusAlphaToDelta, MinAlphaMinusOneAndTwo); entropy := BigRatDiv(Numerator, Denominator); Lemma_RequiredNoiseEntropyPart1Correct(DiffPrivParametersImplToSpec(p), RV(AlphaPlusOne), RV(BetaPlusOne), RV(One), RV(Two), RV(AlphaToDelta), RV(BetaMinusAlphaToDelta), RV(Numerator), RV(AlphaMinusOne), RV(MinAlphaMinusOneAndTwo), RV(Denominator), RV(entropy)); } method ComputeBytesForNoiseGeneration (p:DiffPrivParametersImpl) returns (error_code:int, bytes:nat) requires WellformedDiffPrivParameters(p); requires DiffPrivParametersValid(DiffPrivParametersImplToSpec(p)); ensures Word32(error_code); ensures error_code == 0 ==> Word32((bytes-1)*8+1); ensures error_code == 0 ==> SufficientBytesForNoiseGeneration(DiffPrivParametersImplToSpec(p), bytes); ensures error_code != 0 ==> bytes == 0; requires public(p); ensures public(error_code); ensures public(bytes); { lemma_2toX(); reveal_power2(); var entropy_part_1 := ComputeRequiredNoiseEntropyPart1(p); var success, r1 := FindHigherPowerOfTwo(entropy_part_1); if !success || r1 >= 0xFFFFFFE0 { error_code := ErrorRequiresTooManyBitsOfRandomness(); bytes := 0; return; } var log_alpha:nat; success, log_alpha := FindHigherPowerOfTwo(p.alpha); if !success || log_alpha > 0xFFFFFFFF / p.B { error_code := ErrorRequiresTooManyBitsOfRandomness(); bytes := 0; return; } lemma_mul_nonnegative(log_alpha, p.B-1); var r2:nat := log_alpha * (p.B-1); Lemma_SufficientR2(RV(p.alpha), p.B, log_alpha, r2); if r2 >= 0xFFFFFFC8 - r1 { error_code := ErrorRequiresTooManyBitsOfRandomness(); bytes := 0; return; } error_code := 0; var min_r := r1 + r2 + 7; //- need 7 extra bits so we can use an entire byte for the sign bit bytes := TurnSufficientBitsIntoSufficientBytes(min_r); Lemma_RealPowerPreservesPositivity(RV(p.alpha), p.B-1); Lemma_BreakdownOfSufficientBytesForNoiseGeneration(DiffPrivParametersImplToSpec(p), r1, r2, bytes); } static method TurnSufficientBitsIntoSufficientBytes (min_r:nat) returns (bytes:int) requires min_r < 0xFFFFFFD0; ensures Word32((bytes-1)*8+1); ensures bytes >= 1; ensures ModuloFour(bytes) == 1; ensures bytes * 8 >= min_r; requires public(min_r); ensures public(bytes); { reveal_ModuloFour(); var r:int := RoundUpToMultiple(min_r, 8); assert r == RoundUpToMultiple_premium(min_r, 8); lemma_mod_is_mod_boogie(r, 8); var bytes1:int := r / 8; var bytes2:int := RoundUpToMultiple(bytes1, 4); assert bytes2 == RoundUpToMultiple_premium(bytes1, 4); lemma_mod_is_mod_boogie(bytes2, 4); bytes := bytes2 + 1; lemma_mod_is_mod_boogie(bytes2, 4); calc { (bytes-1)*8 + 1; bytes2 * 8 + 1; < (bytes1 + 4) * 8 + 1; bytes1 * 8 + 33; (r / 8) * 8 + 33; <= ((min_r + 8) / 8) * 8 + 33; < ((0xFFFFFFD0 + 8) / 8) * 8 + 33; < 0xFFFFFFFF; < { lemma_2toX(); reveal_power2(); } power2(32); } } method BigNatPower2 (e:nat) returns (r:BigNat) requires Word32(e+1); ensures WellformedBigNat(r); ensures I(r) == power2(e); { lemma_2toX(); reveal_power2(); var One := MakeSmallLiteralBigNat(1); ghost var rc:nat; r, rc := BigNatBitShift_(One, 1, e); lemma_mul_is_mul_boogie(power2(e), I(One)); } method FindHighestPowerLeThreshold (alpha:BigRat, threshold:BigRat, max_power:nat, ghost u:BigRat) returns (e:nat) requires WellformedBigRat(alpha); requires WellformedBigRat(threshold); requires Word32(max_power); requires WellformedBigRat(u); requires RV(u) > 0.0; requires RV(alpha) > 1.0; requires RV(threshold) >= 1.0; requires RV(threshold) == NoiseThreshold(RV(alpha), RV(u)); ensures RealPower(RV(alpha), e) <= RV(threshold); ensures e == max_power || RealPower(RV(alpha), e+1) > RV(threshold); ensures Word32(e); ensures RV(threshold) == NoiseThreshold(RV(alpha), RV(u)); { var alpha_to_e := MakeSmallLiteralBigRat(1); e := 0; while e < max_power invariant 0 <= e <= max_power; invariant WellformedBigRat(alpha_to_e); invariant RV(alpha_to_e) == RealPower(RV(alpha), e); invariant RV(alpha_to_e) <= RV(threshold); { alpha_to_e := BigRatMul(alpha, alpha_to_e); var done := BigRatGt(alpha_to_e, threshold); if (done) { assert RealPower(RV(alpha), e+1) == RV(alpha_to_e) > RV(threshold); return; } e := e + 1; } } method {:timeLimitMultiplier 6} DeriveRandomValues (randoms:seq) returns (negate_noise:bool, u:BigRat) requires |randoms| > 0; requires Word32((|randoms|-1) * 8 + 1); requires IsByteSeq(randoms); ensures WellformedBigRat(u); ensures negate_noise == ShouldNegateNoise(randoms[0]); ensures RV(u) == GetUniformBetweenZeroAndOne(randoms[1..]); ensures 0.0 < RV(u) <= 1.0; { reveal_ShouldNegateNoise(); negate_noise := (randoms[0] % 2 == 1); lemma_2toX(); var U:BigNat := BEByteSeqToBigNat(randoms[1..]); assert I(U) == BEByteSeqToInt(randoms[1..]); var OneHalf:BigRat := BigRat_ctor(MakeSmallLiteralBigNum(1), MakeSmallLiteralBigNat(2)); var Numerator:BigRat := BigRatAdd(BigNatToBigRat(U), OneHalf); var Denominator:BigNat := BigNatPower2((|randoms|-1)*8); u := BigRatDiv(Numerator, BigNatToBigRat(Denominator)); assert WellformedBigRat(u); Lemma_RandomDerivationsCorrect(randoms, RV(u), negate_noise, I(U), RV(OneHalf), RV(Numerator), I(Denominator)); } method ComputeNoiseThreshold (alpha:BigRat, u:BigRat) returns (Threshold:BigRat) requires WellformedBigRat(alpha); requires WellformedBigRat(u); requires RV(alpha) > 1.0; requires 0.0 < RV(u) <= 1.0; ensures WellformedBigRat(Threshold); ensures RV(Threshold) == NoiseThreshold(RV(alpha), RV(u)); ensures RV(Threshold) >= 1.0; { lemma_2toX(); var ThresholdNumerator := BigRatMul(MakeSmallLiteralBigRat(2), alpha); var AlphaPlusOne := BigRatAdd(alpha, MakeSmallLiteralBigRat(1)); var ThresholdDenominator := BigRatMul(u, AlphaPlusOne); Threshold := BigRatDiv(ThresholdNumerator, ThresholdDenominator); Lemma_ThresholdCorrect(RV(alpha), RV(u), RV(ThresholdNumerator), RV(AlphaPlusOne), RV(ThresholdDenominator), RV(Threshold)); Lemma_ThresholdGeOne(RV(alpha), RV(u), RV(Threshold)); } method {:timeLimitMultiplier 6} ComputeNoise (p:DiffPrivParametersImpl, randoms:seq) returns (negate_noise:bool, absolute_noise:int, ghost noise:int) requires WellformedDiffPrivParameters(p); requires IsByteSeq(randoms); requires DiffPrivParametersValid(DiffPrivParametersImplToSpec(p)); requires |randoms| > 0; requires Word32((|randoms|-1)*8+1); requires SufficientBytesForNoiseGeneration(DiffPrivParametersImplToSpec(p), |randoms|); ensures Word32(absolute_noise); ensures noise == if negate_noise then -absolute_noise else absolute_noise; ensures NoiseComputedCorrectly(DiffPrivParametersImplToSpec(p), randoms, noise); { var u:BigRat; negate_noise, u := DeriveRandomValues(randoms); assert RV(u) == GetUniformBetweenZeroAndOne(randoms[1..]); var Threshold := ComputeNoiseThreshold(p.alpha, u); absolute_noise := FindHighestPowerLeThreshold(p.alpha, Threshold, p.B, u); assert RV(Threshold) == NoiseThreshold(RV(p.alpha), RV(u)); noise := if negate_noise then -absolute_noise else absolute_noise; Lemma_NoiseComputedCorrectlyFromRandomValues(DiffPrivParametersImplToSpec(p), randoms, RV(u), negate_noise, absolute_noise, noise); } static lemma {:timeLimitMultiplier 3} Lemma_RequiredNoiseEntropyPart1Correct (p:DiffPrivParameters, AlphaPlusOne:real, BetaPlusOne:real, One:real, Two:real, AlphaToDelta:real, BetaMinusAlphaToDelta:real, Numerator:real, AlphaMinusOne:real, MinAlphaMinusOneAndTwo:real, Denominator:real, entropy:real) requires Word32(p.delta); requires Word32(p.B); requires DiffPrivParametersValid(p); requires One == 1.0; requires Two == 2.0; requires AlphaPlusOne == p.alpha + One; requires BetaPlusOne == p.beta + One; requires AlphaToDelta == RealPower(p.alpha, p.delta); requires BetaMinusAlphaToDelta == p.beta - AlphaToDelta; requires Numerator == AlphaPlusOne * BetaPlusOne; requires AlphaMinusOne == p.alpha - One; requires MinAlphaMinusOneAndTwo == RealMin(AlphaMinusOne, Two); requires Denominator == BetaMinusAlphaToDelta * MinAlphaMinusOneAndTwo; requires Denominator != 0.0; requires entropy == Numerator / Denominator; ensures entropy == RequiredNoiseEntropyPart1(p); { calc { entropy; Numerator / Denominator; (AlphaPlusOne * BetaPlusOne) / Denominator; ((p.alpha + One) * BetaPlusOne) / Denominator; ((p.alpha + One) * (p.beta + One)) / Denominator; ((p.alpha + One) * (p.beta + One)) / (BetaMinusAlphaToDelta * MinAlphaMinusOneAndTwo); ((p.alpha + One) * (p.beta + One)) / ((p.beta - AlphaToDelta) * MinAlphaMinusOneAndTwo); ((p.alpha + One) * (p.beta + One)) / ((p.beta - RealPower(p.alpha, p.delta)) * MinAlphaMinusOneAndTwo); ((p.alpha + One) * (p.beta + One)) / ((p.beta - RealPower(p.alpha, p.delta)) * RealMin(AlphaMinusOne, Two)); ((p.alpha + One) * (p.beta + One)) / ((p.beta - RealPower(p.alpha, p.delta)) * RealMin(p.alpha - One, Two)); } } static lemma Lemma_RealPowerPreservesGeOne (x:real, e:nat) requires x >= 1.0; ensures RealPower(x, e) >= 1.0; decreases e; { if e != 0 { Lemma_RealPowerPreservesGeOne(x, e-1); } } static lemma Lemma_DividingByPositiveMaintainsInequality(smaller:real, larger:real, denominator:real) requires denominator > 0.0; requires smaller <= larger; ensures smaller / denominator <= larger / denominator; { } static lemma Lemma_RandomDerivationsCorrect (randoms:seq, u:real, negate_noise:bool, U:nat, OneHalf:real, Numerator:real, Denominator:nat) requires |randoms| > 0; requires IsByteSeq(randoms); requires negate_noise == (randoms[0] % 2 == 1); requires U == BEByteSeqToInt(randoms[1..]); requires OneHalf == 0.5; requires Numerator == real(U) + OneHalf; requires Denominator == power2((|randoms|-1)*8); requires u == Numerator / real(Denominator); ensures u == GetUniformBetweenZeroAndOne(randoms[1..]); ensures 0.0 < u <= 1.0; decreases U; { calc { Denominator; power2((|randoms|-1)*8); >= { lemma_power2_increases(0, (|randoms|-1)*8); } power2(0); == { reveal_power2(); } 1; } calc { real(Denominator); >= real(1); > 0.0; } calc ==> { true; { lemma_BEByteSeqToInt_bound(randoms[1..]); } U <= power2((|randoms|-1)*8) - 1; real(U) <= real(power2((|randoms|-1)*8) - 1); real(U) + OneHalf <= real(power2((|randoms|-1)*8) - 1) + OneHalf; { Lemma_DividingByPositiveMaintainsInequality(real(U) + OneHalf, real(power2((|randoms|-1)*8) - 1) + OneHalf, real(Denominator)); } (real(U) + OneHalf) / real(Denominator) <= (real(power2((|randoms|-1)*8) - 1) + OneHalf) / real(Denominator); } calc { u; Numerator / real(Denominator); (real(U) + OneHalf) / real(Denominator); <= (real(power2((|randoms|-1)*8) - 1) + OneHalf) / real(Denominator); (real(power2((|randoms|-1)*8) - 1) + 0.5) / real(Denominator); (real(power2((|randoms|-1)*8) - 1) + 0.5) / real(power2((|randoms|-1)*8)); < real(power2((|randoms|-1)*8)) / real(power2((|randoms|-1)*8)); 1.0; } } static lemma Lemma_ThresholdCorrect (alpha:real, u:real, ThresholdNumerator:real, AlphaPlusOne:real, ThresholdDenominator:real, Threshold:real) requires u > 0.0; requires alpha > 1.0; requires ThresholdNumerator == 2.0 * alpha; requires AlphaPlusOne == alpha + 1.0; requires ThresholdDenominator == u * AlphaPlusOne; requires Threshold == ThresholdNumerator / ThresholdDenominator; ensures Threshold == NoiseThreshold(alpha, u); { } static lemma Lemma_NoiseComputedCorrectlyFromRandomValues (p:DiffPrivParameters, randoms:seq, u:real, negate_noise:bool, absolute_noise:nat, ghost noise:int) requires DiffPrivParametersValid(p); requires p.alpha > 1.0; requires u > 0.0; requires IsByteSeq(randoms); requires |randoms| > 0; requires SufficientBytesForNoiseGeneration(p, |randoms|); requires negate_noise == ShouldNegateNoise(randoms[0]); requires u == GetUniformBetweenZeroAndOne(randoms[1..]); requires RealPower(p.alpha, absolute_noise) <= NoiseThreshold(p.alpha, u); requires (absolute_noise == p.B || RealPower(p.alpha, absolute_noise + 1) > NoiseThreshold(p.alpha, u)); requires noise == if negate_noise then -absolute_noise else absolute_noise; ensures NoiseComputedCorrectly(p, randoms, noise); { assert AbsoluteNoiseComputedCorrectlyTrigger(absolute_noise); assert NoiseOK(p, negate_noise, u, absolute_noise, noise); } static lemma Lemma_ThresholdGeOne (alpha:real, u:real, threshold:real) requires 1.0 >= u > 0.0; requires alpha > 1.0; requires threshold == NoiseThreshold(alpha, u); ensures threshold >= 1.0; { calc { threshold; (2.0 * alpha) / (u * (alpha + 1.0)); (alpha + alpha) / (u * (alpha + 1.0)); (alpha + alpha) / (u * (alpha + 1.0)); (alpha + alpha) / (alpha + 1.0) / u; >= 1.0 / u; >= 1.0; } } static function RequiredNoiseEntropyPart1 (p:DiffPrivParameters) : real requires DiffPrivParametersValid(p); ensures RequiredNoiseEntropyPart1(p) > 0.0; { assert p.beta - RealPower(p.alpha, p.delta) > 0.0; assert RealMin(p.alpha - 1.0, 2.0) > 0.0; (p.alpha + 1.0) * (p.beta + 1.0) / ((p.beta - RealPower(p.alpha, p.delta)) * RealMin(p.alpha - 1.0, 2.0)) } static lemma Lemma_SufficientR2 (alpha:real, B:int, log_alpha:nat, r2:nat) requires B > 0; requires alpha > 1.0; requires real(power2(log_alpha)) >= alpha; requires r2 >= log_alpha * (B-1); ensures real(power2(r2)) >= RealPower(alpha, B-1); decreases B; { if B > 1 { calc { r2 - log_alpha; >= log_alpha * (B-1) - log_alpha; log_alpha * (B-1) - log_alpha * 1; { lemma_mul_is_distributive_sub(log_alpha, B-1, 1); lemma_mul_is_mul_boogie(log_alpha, 1); } log_alpha * (B-1 - 1); log_alpha * (B-2); } lemma_mul_nonnegative(log_alpha, B-2); assert r2 - log_alpha >= log_alpha * (B-2) >= 0; Lemma_SufficientR2(alpha, B-1, log_alpha, r2 - log_alpha); assert real(power2(r2 - log_alpha)) >= RealPower(alpha, B-2); calc { real(power2(r2)); { lemma_power2_adds(log_alpha, r2-log_alpha); } real(power2(log_alpha) * power2(r2-log_alpha)); { Lemma_RealOfMultiplyIsMultiply(power2(log_alpha), power2(r2-log_alpha)); } real(power2(log_alpha)) * real(power2(r2-log_alpha)); >= alpha * real(power2(r2-log_alpha)); >= alpha * RealPower(alpha, B-2); RealPower(alpha, B-1); } } } static lemma Lemma_MultiplyDivideOrderIrrelevant (x:real, y:real, z:real) requires y != 0.0; ensures (x/y)*z == (x*z)/y; { } static lemma Lemma_BreakdownOfSufficientBytesForNoiseGeneration (p:DiffPrivParameters, r1:nat, r2:nat, bytes:nat) requires DiffPrivParametersValid(p); requires real(power2(r1)) >= RequiredNoiseEntropyPart1(p) > 0.0; requires real(power2(r2)) >= RealPower(p.alpha, p.B - 1) > 0.0; requires bytes >= 1; requires ModuloFour(bytes) == 1; requires bytes * 8 - 7 >= r1 + r2; ensures SufficientBytesForNoiseGeneration(p, bytes); decreases r1; { //- assert (p.beta - RealPower(p.alpha, p.delta)) > 0.0; //- assert RealMin(p.alpha - 1.0, 2.0) > 0.0; //- assert (p.beta - RealPower(p.alpha, p.delta)) * RealMin(p.alpha - 1.0, 2.0) > 0.0; //- assert real(power2(r2)) >= RealPower(p.alpha, p.B - 1); calc ==> { true; { calc { real(power2(bytes * 8 - 7)); >= { lemma_power2_increases(r1 + r2, bytes * 8 - 7); } real(power2(r1 + r2)); { lemma_power2_adds(r1, r2); } real(power2(r1) * power2(r2)); { Lemma_RealOfMultiplyIsMultiply(power2(r1), power2(r2)); } real(power2(r1)) * real(power2(r2)); >= RequiredNoiseEntropyPart1(p) * real(power2(r2)); } } real(power2(bytes * 8 - 7)) >= RequiredNoiseEntropyPart1(p) * real(power2(r2)); { calc { RequiredNoiseEntropyPart1(p) * real(power2(r2)); >= { assert real(power2(r2)) >= RealPower(p.alpha, p.B - 1); } RequiredNoiseEntropyPart1(p) * RealPower(p.alpha, p.B - 1); == { assert p.beta - RealPower(p.alpha, p.delta) > 0.0; assert RealMin(p.alpha - 1.0, 2.0) > 0.0; } ((p.alpha + 1.0) * (p.beta + 1.0) / ((p.beta - RealPower(p.alpha, p.delta)) * RealMin(p.alpha - 1.0, 2.0))) * RealPower(p.alpha, p.B - 1); == { Lemma_MultiplyDivideOrderIrrelevant((p.alpha + 1.0) * (p.beta + 1.0), (p.beta - RealPower(p.alpha, p.delta)) * RealMin(p.alpha - 1.0, 2.0), RealPower(p.alpha, p.B - 1)); } (p.alpha + 1.0) * (p.beta + 1.0) * RealPower(p.alpha, p.B - 1) / ((p.beta - RealPower(p.alpha, p.delta)) * RealMin(p.alpha - 1.0, 2.0)); RequiredNoiseEntropy(p); } } real(power2(bytes * 8 - 7)) >= RequiredNoiseEntropy(p); } //- calc { ModuloFour(bytes); { reveal_ModuloFour(); } 1; } calc { true; { reveal_SufficientBytesForNoiseGeneration(); } //- { assert bytes >= 1; } //- { assert ModuloFour(bytes) == 1; } //- { assert real(power2(bytes * 8 - 7)) >= RequiredNoiseEntropy(p); } SufficientBytesForNoiseGeneration(p, bytes); } } static lemma Lemma_RealPowerPreservesPositivity (x:real, e:nat) requires x > 0.0; ensures RealPower(x, e) > 0.0; decreases e; { if e > 0 { Lemma_RealPowerPreservesPositivity(x, e-1); } } ================================================ FILE: ironclad-apps/src/Dafny/Apps/DiffPriv/Noise.s.dfy ================================================ //- include "../../Libraries/Util/be_sequences.s.dfy" static function RealPower(x:real, e:nat) : real decreases e; { if e == 0 then 1.0 else x * RealPower(x, e-1) } static function RealMin(a:real, b:real) : real { if a < b then a else b } datatype DiffPrivParameters = DiffPrivParameters_ctor(alpha:real, beta:real, delta:int, B:int); static function DiffPrivParametersValid (p:DiffPrivParameters) : bool { p.delta >= 0 && p.alpha > 1.0 && p.beta > RealPower(p.alpha, p.delta) && p.B > 0 && p.beta >= 1.0 } static function RequiredNoiseEntropy (p:DiffPrivParameters) : real requires DiffPrivParametersValid(p); { (p.alpha + 1.0) * (p.beta + 1.0) * RealPower(p.alpha, p.B - 1) / ((p.beta - RealPower(p.alpha, p.delta)) * RealMin(p.alpha - 1.0, 2.0)) } static function {:opaque} ModuloFour (x:int) : int { x % 4 } static function {:opaque} SufficientBytesForNoiseGeneration (p:DiffPrivParameters, bytes:nat) : bool requires DiffPrivParametersValid(p); { bytes >= 1 && ModuloFour(bytes) == 1 && real(power2(bytes * 8 - 7)) >= RequiredNoiseEntropy(p) //- We need 7 extra bits because we use an entire byte for the sign bit. } static function NoiseThreshold (alpha:real, u:real) : real requires u > 0.0; requires alpha > 1.0; { (2.0 * alpha) / (u * (alpha + 1.0)) } static predicate {:opaque} ShouldNegateNoise (r:int) { (r % 2 == 1) } static function GetUniformBetweenZeroAndOne (randoms:seq) : real requires IsByteSeq(randoms); { (real(BEByteSeqToInt(randoms)) + 0.5) / real(power2(|randoms|*8)) } static function NoiseOK (p:DiffPrivParameters, negate_noise:bool, u:real, absolute_noise:nat, noise:int) : bool requires DiffPrivParametersValid(p); { u > 0.0 && RealPower(p.alpha, absolute_noise) <= NoiseThreshold(p.alpha, u) && (absolute_noise == p.B || RealPower(p.alpha, absolute_noise + 1) > NoiseThreshold(p.alpha, u)) && noise == (if negate_noise then -absolute_noise else absolute_noise) } static function AbsoluteNoiseComputedCorrectlyTrigger (absolute_noise:nat) : bool { true } static function NoiseComputedCorrectly (p:DiffPrivParameters, randoms:seq, noise:int) : bool requires DiffPrivParametersValid(p); { |randoms| > 0 && IsByteSeq(randoms) && SufficientBytesForNoiseGeneration(p, |randoms|) && exists absolute_noise:nat {:trigger AbsoluteNoiseComputedCorrectlyTrigger(absolute_noise)} :: NoiseOK(p, ShouldNegateNoise(randoms[0]), GetUniformBetweenZeroAndOne(randoms[1..]), absolute_noise, noise) } ================================================ FILE: ironclad-apps/src/Dafny/Apps/DiffPriv/PacketParsing.c.dfy ================================================ include "DiffPriv.s.dfy" //-/////////////////////////// //- Request parsing //-/////////////////////////// datatype DiffPrivRequest = InvalidRequest_ctor() | GetQuoteRequest_ctor(nonce_external:seq) | InitializeDBRequest_ctor(budget:real) | AddRowRequest_ctor(request_ciphertext:seq) | QueryRequest_ctor(q:QueryParameters); static predicate RequestParsedCorrectly (data:seq, request:DiffPrivRequest) requires IsByteSeq(data); { if |data| == 0 then request.InvalidRequest_ctor? else if data[0] == 1 then GetQuoteRequestParsedCorrectly(data, request) else if data[0] == 2 then InitializeDBRequestParsedCorrectly(data, request) else if data[0] == 3 then AddRowRequestParsedCorrectly(data, request) else if data[0] == 4 then QueryRequestParsedCorrectly(data, request) else request.InvalidRequest_ctor? } static predicate GetQuoteRequestParsedCorrectly(data:seq, request:DiffPrivRequest) requires |data| > 0; requires data[0] == 1; { if |data| < 21 then request.InvalidRequest_ctor? else request.GetQuoteRequest_ctor? && request.nonce_external == data[1..21] } static predicate InitializeDBRequestParsedCorrectly (data:seq, request:DiffPrivRequest) requires IsByteSeq(data); requires |data| > 0; requires data[0] == 2; { if |data| < 9 then request.InvalidRequest_ctor? else (var fields := data[1 :4 :4 ]; var _, budget_num, budget_den := fields[0], BEByteSeqToInt(fields[1]), BEByteSeqToInt(fields[2]) ; if budget_den == 0 then request.InvalidRequest_ctor? else request.InitializeDBRequest_ctor? && request.budget == real(budget_num) / real(budget_den)) } static predicate AddRowRequestParsedCorrectly (data:seq, request:DiffPrivRequest) requires IsByteSeq(data); requires |data| > 0; requires data[0] == 3; { if |data| == 1 then request == InvalidRequest_ctor() else request == AddRowRequest_ctor(data[1..]) } static predicate QueryRequestParsedCorrectly (data:seq, request:DiffPrivRequest) requires IsByteSeq(data); requires |data| > 0; requires data[0] == 4; { if |data| < 41 then request.InvalidRequest_ctor? else ( var program_size := BEByteSeqToInt(data[1..5]); if program_size < 0 || |data| < 41 + program_size || program_size % 4 != 0 then request.InvalidRequest_ctor? else (var fields := data[5:4:4:4:4:4:4:4:4:4:program_size]; var _, row_min, row_max, answer_units, answer_min, answer_max, alpha_num, alpha_den, beta_num, beta_den, program_encoding := fields[0], BEByteSeqToInt(fields[1]), BEByteSeqToInt(fields[2]), BEByteSeqToInt(fields[3]), BEByteSeqToInt(fields[4]), BEByteSeqToInt(fields[5]), BEByteSeqToInt(fields[6]), BEByteSeqToInt(fields[7]), BEByteSeqToInt(fields[8]), BEByteSeqToInt(fields[9]), fields[10]; if alpha_den == 0 || beta_den == 0 then request.InvalidRequest_ctor? else request.QueryRequest_ctor? && request.q.row_min == row_min && request.q.row_max == row_max && request.q.answer_units == answer_units && request.q.answer_min == answer_min && request.q.answer_max == answer_max && request.q.alpha == real(alpha_num) / real(alpha_den) && request.q.beta == real(beta_num) / real(beta_den) && request.q.program_encoding == BEIntToDigitSeq(power2(32), |program_encoding|/4, BEDigitSeqToInt(power2(8), program_encoding))) ) } //-/////////////////////////// //- Response parsing //-/////////////////////////// datatype DiffPrivResponse = NullResponse_ctor() | GetQuoteResponse_ctor(get_quote_error_code:int, encoded_public_key:seq, pcr_info_bytes:seq, sig_bytes:seq) | InitializeDBResponse_ctor(init_error_code:int) | AddRowResponse_ctor() | QueryResponse_ctor(query_error_code:int, response:int); static predicate ResponseFormedCorrectly (response:DiffPrivResponse, data:seq) requires IsByteSeq(data); { match response case NullResponse_ctor => |data| >= 1 && data[0] == 0 case GetQuoteResponse_ctor(get_quote_error_code, encoded_public_key, pcr_info_bytes, sig_bytes) => Word32(get_quote_error_code) && Word32(|encoded_public_key|) && Word32(|pcr_info_bytes|) && Word32(|sig_bytes|) && IsByteSeq(encoded_public_key) && IsByteSeq(pcr_info_bytes) && IsByteSeq(sig_bytes) && data == [1] + BEWordToFourBytes(get_quote_error_code) + BEWordToFourBytes(|encoded_public_key|) + BEWordToFourBytes(|pcr_info_bytes|) + BEWordToFourBytes(|sig_bytes|) + encoded_public_key + pcr_info_bytes + sig_bytes case InitializeDBResponse_ctor(error_code) => Word32(error_code) && data == [2] + BEWordToFourBytes(error_code) case AddRowResponse_ctor => data == [3] //- The error code is not public, so we can't output it. case QueryResponse_ctor(error_code, response_value) => Word32(error_code) && Word32(response_value) && data == [4] + BEWordToFourBytes(error_code) + BEWordToFourBytes(response_value) } ================================================ FILE: ironclad-apps/src/Dafny/Apps/DiffPriv/PacketParsing.i.dfy ================================================ //- include "PacketParsing.c.dfy" include "../../Libraries/Util/seqs_transforms.i.dfy" //-////////////////////////// //- Query parameters //-////////////////////////// datatype QueryParametersImpl = QueryParametersImpl_ctor(program_encoding:seq, row_min:int, row_max:int, answer_units:int, answer_min:int, answer_max:int, alpha_num:int, alpha_den:int, beta_num:int, beta_den:int) static predicate QueryParametersImplValid (q:QueryParametersImpl) { (forall i :: 0 <= i < |q.program_encoding| ==> Word32(q.program_encoding[i])) && Word32(q.row_min) && Word32(q.row_max) && Word32(q.answer_units) && Word32(q.answer_min) && Word32(q.answer_max) && Word32(q.alpha_num) && Word32(q.alpha_den) && Word32(q.beta_num) && Word32(q.beta_den) && q.alpha_den != 0 && q.beta_den != 0 } static function QueryParametersImplToSpec(q:QueryParametersImpl) : QueryParameters requires QueryParametersImplValid(q); { QueryParameters_ctor(q.program_encoding, q.row_min, q.row_max, q.answer_units, q.answer_min, q.answer_max, real(q.alpha_num) / real(q.alpha_den), real(q.beta_num) / real(q.beta_den)) } //-////////////////////////// //- Request implementation //-////////////////////////// datatype DiffPrivRequestImpl = InvalidRequestImpl_ctor() | GetQuoteRequestImpl_ctor(nonce_external:seq) | InitializeDBRequestImpl_ctor(budget_num:int, budget_den:int) | AddRowRequestImpl_ctor(request_ciphertext:seq) | QueryRequestImpl_ctor(q:QueryParametersImpl) static predicate WellformedDiffPrivRequest(request:DiffPrivRequestImpl) { match request case InvalidRequestImpl_ctor => true case GetQuoteRequestImpl_ctor(nonce_external) => IsByteSeqOfLen(nonce_external, 20) case InitializeDBRequestImpl_ctor(budget_num, budget_den) => Word32(budget_num) && Word32(budget_den) && budget_den != 0 case AddRowRequestImpl_ctor(request_ciphertext) => IsByteSeq(request_ciphertext) && |request_ciphertext| > 0 case QueryRequestImpl_ctor(q) => QueryParametersImplValid(q) } static function DiffPrivRequestImplToSpec(request:DiffPrivRequestImpl) : DiffPrivRequest requires WellformedDiffPrivRequest(request); { match request case InvalidRequestImpl_ctor => InvalidRequest_ctor() case GetQuoteRequestImpl_ctor(nonce_external) => GetQuoteRequest_ctor(nonce_external) case InitializeDBRequestImpl_ctor(budget_num, budget_den) => InitializeDBRequest_ctor(real(budget_num) / real(budget_den)) case AddRowRequestImpl_ctor(request_ciphertext) => AddRowRequest_ctor(request_ciphertext) case QueryRequestImpl_ctor(q:QueryParametersImpl) => QueryRequest_ctor(QueryParametersImplToSpec(q)) } //-////////////////////////// //- Request parsing //-////////////////////////// static lemma Lemma_InitializeDBWellformedDiffPrivRequest(request:DiffPrivRequestImpl) requires request.InitializeDBRequestImpl_ctor?; requires Word32(request.budget_num); requires Word32(request.budget_den); requires request.budget_den != 0; ensures WellformedDiffPrivRequest(request); { } static lemma Lemma_QueryWellformedDiffPrivRequest(request:DiffPrivRequestImpl) requires request.QueryRequestImpl_ctor?; requires QueryParametersImplValid(request.q); ensures WellformedDiffPrivRequest(request); { } method ParseRequestPacket (data:seq) returns (request:DiffPrivRequestImpl) requires IsByteSeq(data); ensures WellformedDiffPrivRequest(request); ensures RequestParsedCorrectly(data, DiffPrivRequestImplToSpec(request)); requires public(data); ensures public(request); { if |data| == 0 { request := InvalidRequestImpl_ctor(); return; } if data[0] == 1 { request := ParseGetQuoteRequestPacket(data); return; } if data[0] == 2 { request := ParseInitializeDBRequestPacket(data); return; } if data[0] == 3 { request := ParseAddRowRequestPacket(data); return; } if data[0] == 4 { request := ParseQueryRequestPacket(data); return; } request := InvalidRequestImpl_ctor(); } static method ParseGetQuoteRequestPacket (data:seq) returns (request:DiffPrivRequestImpl) requires IsByteSeq(data); requires |data| > 0; requires data[0] == 1; ensures WellformedDiffPrivRequest(request); ensures GetQuoteRequestParsedCorrectly(data, DiffPrivRequestImplToSpec(request)); requires public(data); ensures public(request); { if |data| < 21 { request := InvalidRequestImpl_ctor(); return; } var nonce_external := data[1..21]; return GetQuoteRequestImpl_ctor(nonce_external); } static method ParseInitializeDBRequestPacket (data:seq) returns (request:DiffPrivRequestImpl) requires IsByteSeq(data); requires |data| > 0; requires data[0] == 2; ensures WellformedDiffPrivRequest(request); ensures InitializeDBRequestParsedCorrectly(data, DiffPrivRequestImplToSpec(request)); requires public(data); ensures public(request); { if |data| < 9 { request := InvalidRequestImpl_ctor(); return; } var budget_num := BEFourBytesToWord_impl(data[1..5]); var budget_den := BEFourBytesToWord_impl(data[5..9]); if (budget_den == 0) { request := InvalidRequestImpl_ctor(); return; } request := InitializeDBRequestImpl_ctor(budget_num, budget_den); Lemma_InitializeDBWellformedDiffPrivRequest(request); } method ParseAddRowRequestPacket (data:seq) returns (request:DiffPrivRequestImpl) requires IsByteSeq(data); requires |data| > 0; requires data[0] == 3; ensures WellformedDiffPrivRequest(request); ensures AddRowRequestParsedCorrectly(data, DiffPrivRequestImplToSpec(request)); requires public(data); ensures public(request); { if |data| == 1 { request := InvalidRequestImpl_ctor(); return; } return AddRowRequestImpl_ctor(data[1..]); } static method ParseQueryRequestFields (data:seq, ghost fields:seq>, program_size:int) returns (row_min:int, row_max:int, answer_units:int, answer_min:int, answer_max:int, alpha_num:int, alpha_den:int, beta_num:int, beta_den:int, program_encoding_words:seq) requires 0 <= program_size <= |data| - 41; requires program_size % 4 == 0; requires IsByteSeq(data); requires fields == data[5:4:4:4:4:4:4:4:4:4:program_size]; ensures IsByteSeq(fields[1]); ensures IsByteSeq(fields[2]); ensures IsByteSeq(fields[3]); ensures IsByteSeq(fields[4]); ensures IsByteSeq(fields[5]); ensures IsByteSeq(fields[6]); ensures IsByteSeq(fields[7]); ensures IsByteSeq(fields[8]); ensures IsByteSeq(fields[9]); ensures row_min == BEByteSeqToInt(fields[1]); ensures row_max == BEByteSeqToInt(fields[2]); ensures answer_units == BEByteSeqToInt(fields[3]); ensures answer_min == BEByteSeqToInt(fields[4]); ensures answer_max == BEByteSeqToInt(fields[5]); ensures alpha_num == BEByteSeqToInt(fields[6]); ensures alpha_den == BEByteSeqToInt(fields[7]); ensures beta_num == BEByteSeqToInt(fields[8]); ensures beta_den == BEByteSeqToInt(fields[9]); ensures program_encoding_words == BEIntToDigitSeq(power2(32), |fields[10]|/4, BEDigitSeqToInt(power2(8), fields[10])); ensures Word32(row_min); ensures Word32(row_max); ensures Word32(answer_units); ensures Word32(answer_min); ensures Word32(answer_max); ensures Word32(alpha_num); ensures Word32(alpha_den); ensures Word32(beta_num); ensures Word32(beta_den); ensures forall i :: 0 <= i < |program_encoding_words| ==> Word32(program_encoding_words[i]); { row_min := BEFourBytesToWord_impl(data[5..9]); row_max := BEFourBytesToWord_impl(data[9..13]); answer_units := BEFourBytesToWord_impl(data[13..17]); answer_min := BEFourBytesToWord_impl(data[17..21]); answer_max := BEFourBytesToWord_impl(data[21..25]); alpha_num := BEFourBytesToWord_impl(data[25..29]); alpha_den := BEFourBytesToWord_impl(data[29..33]); beta_num := BEFourBytesToWord_impl(data[33..37]); beta_den := BEFourBytesToWord_impl(data[37..41]); var program_encoding := data[41..41+program_size]; ghost var padbytes:seq; program_encoding_words, padbytes := BEByteSeqToWordSeq_impl(program_encoding); assert program_encoding_words == BEByteSeqToWordSeq(program_encoding); } static method ParseQueryRequestPacket (data:seq) returns (request:DiffPrivRequestImpl) requires IsByteSeq(data); requires |data| > 0; requires data[0] == 4; ensures WellformedDiffPrivRequest(request); ensures QueryRequestParsedCorrectly(data, DiffPrivRequestImplToSpec(request)); requires public(data); ensures public(request); { if |data| < 41 { request := InvalidRequestImpl_ctor(); return; } var program_size := BEFourBytesToWord_impl(data[1..5]); if |data| < 41 + program_size || program_size % 4 != 0 { request := InvalidRequestImpl_ctor(); return; } assert program_size >= 0 && |data| >= 41 + program_size && program_size % 4 == 0; ghost var fields := data[5:4:4:4:4:4:4:4:4:4:program_size]; var row_min, row_max, answer_units, answer_min, answer_max, alpha_num, alpha_den, beta_num, beta_den, program_encoding_words := ParseQueryRequestFields(data, fields, program_size); if alpha_den == 0 || beta_den == 0 { request := InvalidRequestImpl_ctor(); return; } var q := QueryParametersImpl_ctor(program_encoding_words, row_min, row_max, answer_units, answer_min, answer_max, alpha_num, alpha_den, beta_num, beta_den); request := QueryRequestImpl_ctor(q); Lemma_QueryWellformedDiffPrivRequest(request); } //-////////////////////////// //- Response forming //-////////////////////////// static predicate WellformedResponse (response:DiffPrivResponse) { match response case NullResponse_ctor => true case GetQuoteResponse_ctor(error_code, encoded_public_key, pcr_info_bytes, sig_bytes) => Word32(error_code) && Word32(|encoded_public_key|) && Word32(|pcr_info_bytes|) && Word32(|sig_bytes|) && IsByteSeq(encoded_public_key) && IsByteSeq(pcr_info_bytes) && IsByteSeq(sig_bytes) case InitializeDBResponse_ctor(error_code) => Word32(error_code) case AddRowResponse_ctor => true case QueryResponse_ctor(error_code, response_value) => Word32(error_code) && Word32(response_value) } static method FormResponsePacket (response:DiffPrivResponse) returns (data:seq) requires WellformedResponse(response); ensures IsByteSeq(data); ensures ResponseFormedCorrectly(response, data); requires public(response); ensures public(data); { lemma_2toX(); match response { case NullResponse_ctor => data := [0]; case GetQuoteResponse_ctor(get_quote_error_code, encoded_public_key, pcr_info_bytes, sig_bytes) => var get_quote_error_code_encoded := BEWordToFourBytes_impl(get_quote_error_code); var encoded_public_key_len_encoded := BEWordToFourBytes_impl(|encoded_public_key|); var pcr_info_bytes_len_encoded := BEWordToFourBytes_impl(|pcr_info_bytes|); var sig_bytes_len_encoded := BEWordToFourBytes_impl(|sig_bytes|); data := [1] + get_quote_error_code_encoded + encoded_public_key_len_encoded + pcr_info_bytes_len_encoded + sig_bytes_len_encoded + encoded_public_key + pcr_info_bytes + sig_bytes; assert forall i :: 0 <= i < |data| ==> IsByte(data[i]); assert ResponseFormedCorrectly(response, data); case InitializeDBResponse_ctor(error_code) => var error_code_encoded := BEWordToFourBytes_impl(error_code); data := [2] + error_code_encoded; case AddRowResponse_ctor => data := [3]; case QueryResponse_ctor(error_code, response_value) => var error_code_encoded := BEWordToFourBytes_impl(error_code); var response_value_encoded := BEWordToFourBytes_impl(response_value); data := [4] + error_code_encoded + response_value_encoded; } } ================================================ FILE: ironclad-apps/src/Dafny/Apps/DiffPriv/RelationalProperties.i.dfy ================================================ include "SumReducer.i.dfy" ////////////////////////////////////////////// ////////////////////////////////////////////// static lemma Lemma_SensitivityOfMapperSumSpecific(db1:seq, db2:seq, diff_row:int, program:seq, row_min:int, row_max:int) requires DatabaseValid(db1); requires DatabaseValid(db2); requires DatabasesIdenticalExceptForOneRow(db1, db2, diff_row); requires ProgramValid(program); requires row_min <= row_max; ensures row_min - row_max <= MapperSum(db1, program, row_min, row_max) - MapperSum(db2, program, row_min, row_max) <= row_max - row_min; decreases |db1|; { if |db1| > 0 { if diff_row == |db1| - 1 { assert forall i:int :: 0 <= i < diff_row ==> db1[i] == db2[i]; assert db1[..diff_row] == db2[..diff_row]; } else { Lemma_SensitivityOfMapperSumSpecific(db1[..|db1|-1], db2[..|db2|-1], diff_row, program, row_min, row_max); } } } static lemma Lemma_SensitivityOfMapperSum(program:seq, row_min:int, row_max:int) requires ProgramValid(program); requires row_min <= row_max; ensures forall db1:seq, db2:seq :: DatabaseValid(db1) && DatabaseValid(db2) && DatabasesSimilar(db1, db2) ==> row_min - row_max <= MapperSum(db1, program, row_min, row_max) - MapperSum(db2, program, row_min, row_max) <= row_max - row_min; { forall db1:seq, db2:seq, diff_row:int | DatabaseValid(db1) && DatabaseValid(db2) && DatabasesIdenticalExceptForOneRow(db1, db2, diff_row) ensures row_min - row_max <= MapperSum(db1, program, row_min, row_max) - MapperSum(db2, program, row_min, row_max) <= row_max - row_min; { Lemma_SensitivityOfMapperSumSpecific(db1, db2, diff_row, program, row_min, row_max); } } static lemma Lemma_SensitivityOfComputeSumSpecific(db1:seq, db2:seq, diff_row:int, program:seq, row_min:int, row_max:int, answer_units:int, answer_min:int, answer_max:int, delta:int) requires DatabaseValid(db1); requires DatabaseValid(db2); requires DatabasesIdenticalExceptForOneRow(db1, db2, diff_row); requires ProgramValid(program); requires row_min <= row_max; requires answer_units > 0; requires answer_min <= answer_max; requires delta == DivideRoundingUp(row_max - row_min, answer_units); ensures -delta <= Clip(Scale(MapperSum(db1, program, row_min, row_max), answer_units), answer_min, answer_max) - Clip(Scale(MapperSum(db2, program, row_min, row_max), answer_units), answer_min, answer_max) <= delta; decreases |db1|; { Lemma_SensitivityOfMapperSumSpecific(db1, db2, diff_row, program, row_min, row_max); assert -(row_max-row_min) <= MapperSum(db1, program, row_min, row_max) - MapperSum(db2, program, row_min, row_max) <= row_max - row_min; Lemma_EffectOfScaleOnDifference(MapperSum(db1, program, row_min, row_max), MapperSum(db2, program, row_min, row_max), row_max - row_min, answer_units, delta); assert -delta <= Scale(MapperSum(db1, program, row_min, row_max), answer_units) - Scale(MapperSum(db2, program, row_min, row_max), answer_units) <= delta; Lemma_EffectOfClipOnDifference(Scale(MapperSum(db1, program, row_min, row_max), answer_units), Scale(MapperSum(db2, program, row_min, row_max), answer_units), delta, answer_min, answer_max); assert -delta <= Clip(Scale(MapperSum(db1, program, row_min, row_max), answer_units), answer_min, answer_max) - Clip(Scale(MapperSum(db2, program, row_min, row_max), answer_units), answer_min, answer_max) <= delta; } static lemma Lemma_SensitivityOfComputeSum(program:seq, row_min:int, row_max:int, answer_units:int, answer_min:int, answer_max:int, delta:int) requires ProgramValid(program); requires row_min <= row_max; requires answer_units > 0; requires answer_min <= answer_max; requires delta == DivideRoundingUp(row_max - row_min, answer_units); ensures forall db1:seq, db2:seq :: DatabaseValid(db1) && DatabaseValid(db2) && DatabasesSimilar(db1, db2) ==> -delta <= Clip(Scale(MapperSum(db1, program, row_min, row_max), answer_units), answer_min, answer_max) - Clip(Scale(MapperSum(db2, program, row_min, row_max), answer_units), answer_min, answer_max) <= delta; { forall db1:seq, db2:seq, diff_row:int | DatabaseValid(db1) && DatabaseValid(db2) && DatabasesIdenticalExceptForOneRow(db1, db2, diff_row) ensures -delta <= Clip(Scale(MapperSum(db1, program, row_min, row_max), answer_units), answer_min, answer_max) - Clip(Scale(MapperSum(db2, program, row_min, row_max), answer_units), answer_min, answer_max) <= delta; { Lemma_SensitivityOfComputeSumSpecific(db1, db2, diff_row, program, row_min, row_max, answer_units, answer_min, answer_max, delta); } } static lemma Lemma_EffectOfScaleOnDifference (v1:int, v2:int, delta:int, d:int, scaled_delta:int) requires delta >= 0; requires d > 0; requires -delta <= v1 - v2 <= delta; requires scaled_delta == DivideRoundingUp(delta, d); ensures -scaled_delta <= Scale(v1, d) - Scale(v2, d) <= scaled_delta; { var sv1 := Scale(v1, d); var sv2 := Scale(v2, d); Lemma_ScaledValueOffByNoMoreThanHalf(v1, d, sv1); Lemma_ScaledValueOffByNoMoreThanHalf(v2, d, sv2); Lemma_TwoThingsLessThanHalfDifferByLessThanWhole(d * sv1 - v1, d * sv2 - v2, d); assert -d < (d * sv1 - v1) - (d * sv2 - v2) < d; assert -d < (d * sv1) - (d * sv2) - (v1 - v2) < d; lemma_mul_is_distributive_sub(d, sv1, sv2); assert -d < d * (sv1 - sv2) - (v1 - v2) < d; assert -d + (v1 - v2) < d * (sv1 - sv2) < d + (v1 - v2); assert -(d+delta) < d * (sv1 - sv2) < d + delta; Lemma_ScalingDivision(sv1 - sv2, d, delta, scaled_delta); } static lemma Lemma_EffectOfClipOnDifference (v1:int, v2:int, delta:int, min:int, max:int) requires delta >= 0; requires -delta <= v1 - v2 <= delta; requires min <= max; ensures -delta <= Clip(v1, min, max) - Clip(v2, min, max) <= delta; { } static lemma Lemma_ScaledValueOffByNoMoreThanHalf (x:int, d:int, sx:int) requires d > 0; requires sx == Scale(x, d); ensures -d < 2 * (d * sx - x) <= d; { var q := x / d; var r := x % d; lemma_fundamental_div_mod(x, d); lemma_mod_remainder_specific(x, d); if r * 2 >= d { calc { 2 * (d * sx - x); 2 * (d * (q + 1) - x); { lemma_mul_is_distributive_add(d, q, 1); lemma_mul_is_mul_boogie(d, 1); } 2 * (d * q + d * 1 - x); 2 * (d * q + d - x); 2 * (d * q + r + d - r - x); 2 * (d - r); } } } static lemma Lemma_TwoThingsLessThanHalfDifferByLessThanWhole (x1:int, x2:int, y:int) requires -y < x1 * 2 <= y; requires -y < x2 * 2 <= y; ensures -y < x1 - x2 < y; { } static lemma Lemma_ScalingDivision (x:int, d:int, delta:int, scaled_delta:int) requires delta >= 0; requires d > 0; requires -(d+delta) < d * x < d+delta; requires scaled_delta == DivideRoundingUp(delta, d); ensures -scaled_delta <= x <= scaled_delta; { Lemma_DivideRoundingUpHasLimit(delta, d); assert delta <= d * scaled_delta < d + delta; lemma_mul_is_commutative_forall(); if x > scaled_delta { calc ==> { true; x-1 >= scaled_delta; { lemma_mul_inequality(scaled_delta, x-1, d); } d * (x-1) >= d * scaled_delta; d * (x-1) >= delta; { lemma_mul_is_distributive_sub(d, x, 1); lemma_mul_is_mul_boogie(d, 1); } d * x - d >= delta; d * x >= delta + d; false; } } else if x < -scaled_delta { lemma_mul_is_mul_boogie(-1, scaled_delta); lemma_mul_is_mul_boogie(-1, d); lemma_mul_is_mul_boogie(-1, d * scaled_delta); lemma_mul_is_mul_boogie(d, -1); calc ==> { true; x+1 <= -scaled_delta; { lemma_mul_inequality(x+1, -scaled_delta, d); } d * (x+1) <= d * (-scaled_delta); d * (x+1) <= d * (-1 * scaled_delta); { lemma_mul_is_associative(d, -1, scaled_delta); } d * (x+1) <= (d * -1) * scaled_delta; d * (x+1) <= (-1 * d) * scaled_delta; { lemma_mul_is_associative(-1, d, scaled_delta); } d * (x+1) <= -1 * (d * scaled_delta); d * (x+1) <= -1 * delta; { lemma_mul_is_mul_boogie(-1, delta); } d * (x+1) <= -delta; { lemma_mul_is_distributive_add(d, x, 1); lemma_mul_is_mul_boogie(d, 1); } d * x + d <= -delta; d * x <= -(d+delta); false; } } } static lemma Lemma_DivideRoundingUpHasLimit (x:int, d:int) requires x >= 0; requires d > 0; ensures x <= d * DivideRoundingUp(x, d) < x + d; { lemma_fundamental_div_mod(x, d); if x % d != 0 { calc { d * DivideRoundingUp(x, d); d * (x/d + 1); { lemma_mul_is_distributive_add(d, x/d, 1); lemma_mul_is_mul_boogie(d, 1); } d * (x/d) + d; } lemma_mod_remainder_specific(x, d); } } ================================================ FILE: ironclad-apps/src/Dafny/Apps/DiffPriv/StateMachine.i.dfy ================================================ //- //- include "StateMachine.s.dfy" include "DiffPriv.i.dfy" include "DiffPrivPerformQuery.i.dfy" include "StateMachine2.i.dfy" include "../../Libraries/Net/Udp.i.dfy" include "../../Libraries/Util/Halter.i.dfy" include "../../Libraries/Util/relational.i.dfy" method HandleQueryRequest(diffpriv_state_in:DiffPrivStateImpl, common_state:CommonStateImpl, q:QueryParametersImpl) returns (diffpriv_state_out:DiffPrivStateImpl, response:DiffPrivResponse) requires CommonStateImplValid(common_state); requires TPM_ready(); requires DiffPrivStateValid(DiffPrivStateImplToSpec(diffpriv_state_in)); requires current_common_state == CommonStateMachine_ctor(true, CommonStateImplToSpec(common_state), TPM); requires current_diffpriv_state == DiffPrivStateMachine_ctor(true, DiffPrivStateImplToSpec(diffpriv_state_in)); requires QueryParametersImplValid(q); modifies this`TPM; modifies this`IoMemPerm; modifies this`current_diffpriv_state; modifies this`current_common_state; ensures DiffPrivStateValid(DiffPrivStateImplToSpec(diffpriv_state_out)); ensures TPM_ready(); ensures WellformedResponse(response); ensures current_diffpriv_state == DiffPrivStateMachine_ctor(true, DiffPrivStateImplToSpec(diffpriv_state_out)); ensures current_common_state == old(current_common_state)[TPM := TPM]; requires public(PublicPartOfDiffPrivState(DiffPrivStateImplToSpec(diffpriv_state_in))); requires public(q); ensures public(PublicPartOfDiffPrivState(DiffPrivStateImplToSpec(diffpriv_state_out))); ensures public(response); { var query_error_code:int, answer:int; query_error_code, answer, diffpriv_state_out := DiffPrivPerformQuery(diffpriv_state_in, q); var usable_answer:int; if query_error_code != 0 { usable_answer := 0; } else { ghost var declassified_answer := AdvanceDiffPrivStateMachineByAnsweringQuery(QueryParametersImplToSpec(q), DiffPrivStateImplToSpec(diffpriv_state_out), answer); usable_answer := Asm_declassify_result(answer, declassified_answer); } response := QueryResponse_ctor(query_error_code, usable_answer); } method HandleOneRequest (request:DiffPrivRequestImpl, diffpriv_state_in:DiffPrivStateImpl, common_state_in:CommonStateImpl) returns (response:DiffPrivResponse, diffpriv_state_out:DiffPrivStateImpl, common_state_out:CommonStateImpl) requires CommonStateImplValid(common_state_in); requires common_state_in.key_pair.pub.size >= 1024 / 8; requires TPM_ready(); requires DiffPrivStateValid(DiffPrivStateImplToSpec(diffpriv_state_in)); requires current_common_state == CommonStateMachine_ctor(true, CommonStateImplToSpec(common_state_in), TPM); requires current_diffpriv_state == DiffPrivStateMachine_ctor(true, DiffPrivStateImplToSpec(diffpriv_state_in)); requires WellformedDiffPrivRequest(request); modifies this`TPM; modifies this`IoMemPerm; modifies this`current_diffpriv_state; modifies this`current_common_state; ensures DiffPrivStateValid(DiffPrivStateImplToSpec(diffpriv_state_out)); ensures TPM_ready(); ensures WellformedResponse(response); ensures current_diffpriv_state == DiffPrivStateMachine_ctor(true, DiffPrivStateImplToSpec(diffpriv_state_out)); ensures current_common_state == old(current_common_state)[TPM := TPM]; ensures CommonStateImplValid(common_state_out); ensures CommonStateImplToSpec(common_state_out) == CommonStateImplToSpec(common_state_in); requires public(PublicPartOfDiffPrivState(DiffPrivStateImplToSpec(diffpriv_state_in))); requires public(request); ensures public(PublicPartOfDiffPrivState(DiffPrivStateImplToSpec(diffpriv_state_out))); ensures public(response); { match request { case InvalidRequestImpl_ctor => response := NullResponse_ctor(); diffpriv_state_out := diffpriv_state_in; common_state_out := common_state_in; case GetQuoteRequestImpl_ctor(nonce_external) => diffpriv_state_out := diffpriv_state_in; response, common_state_out := HandleGetDiffPrivQuoteRequest(common_state_in, nonce_external); case InitializeDBRequestImpl_ctor(budget_num, budget_den) => diffpriv_state_out, response := HandleInitializeDBRequest(diffpriv_state_in, budget_num, budget_den); common_state_out := common_state_in; case AddRowRequestImpl_ctor(request_ciphertext) => diffpriv_state_out, response := HandleAddRowRequest(diffpriv_state_in, common_state_in, request_ciphertext); common_state_out := common_state_in; case QueryRequestImpl_ctor(q) => diffpriv_state_out, response := HandleQueryRequest(diffpriv_state_in, common_state_in, q); common_state_out := common_state_in; } } method HandleOneRequestRaw (request_bytes:seq, diffpriv_state_in:DiffPrivStateImpl, common_state_in:CommonStateImpl) returns (response_bytes:seq, diffpriv_state_out:DiffPrivStateImpl, common_state_out:CommonStateImpl) requires CommonStateImplValid(common_state_in); requires common_state_in.key_pair.pub.size >= 1024 / 8; requires TPM_ready(); requires DiffPrivStateValid(DiffPrivStateImplToSpec(diffpriv_state_in)); requires current_common_state == CommonStateMachine_ctor(true, CommonStateImplToSpec(common_state_in), TPM); requires current_diffpriv_state == DiffPrivStateMachine_ctor(true, DiffPrivStateImplToSpec(diffpriv_state_in)); requires IsByteSeq(request_bytes); modifies this`TPM; modifies this`IoMemPerm; modifies this`current_diffpriv_state; modifies this`current_common_state; ensures DiffPrivStateValid(DiffPrivStateImplToSpec(diffpriv_state_out)); ensures TPM_ready(); ensures IsByteSeq(response_bytes); ensures current_diffpriv_state == DiffPrivStateMachine_ctor(true, DiffPrivStateImplToSpec(diffpriv_state_out)); ensures current_common_state == old(current_common_state)[TPM := TPM]; ensures CommonStateImplValid(common_state_out); ensures CommonStateImplToSpec(common_state_out) == CommonStateImplToSpec(common_state_in); requires public(PublicPartOfDiffPrivState(DiffPrivStateImplToSpec(diffpriv_state_in))); requires public(request_bytes); ensures public(PublicPartOfDiffPrivState(DiffPrivStateImplToSpec(diffpriv_state_out))); ensures public(response_bytes); { var request := ParseRequestPacket(request_bytes); var response:DiffPrivResponse; response, diffpriv_state_out, common_state_out := HandleOneRequest(request, diffpriv_state_in, common_state_in); response_bytes := FormResponsePacket(response); } ================================================ FILE: ironclad-apps/src/Dafny/Apps/DiffPriv/StateMachine.s.dfy ================================================ include "DiffPriv.s.dfy" include "../../Drivers/TPM/tpm-device.s.dfy" include "../../Libraries/Crypto/RSA/RSASpec.s.dfy" include "../../Libraries/Util/be_sequences.s.dfy" //-/////////////////////////// //- State machine //-/////////////////////////// datatype DiffPrivStateMachine = DiffPrivStateMachine_ctor(initialized:bool, diffpriv_state:DiffPrivState) ghost var {:readonly} current_diffpriv_state:DiffPrivStateMachine; ghost method {:axiom} {:autoReq} InitializeDiffPrivStateMachine(diffpriv_state:DiffPrivState) requires !current_diffpriv_state.initialized; requires DiffPrivInitializeValid(diffpriv_state); ensures current_diffpriv_state == DiffPrivStateMachine_ctor(true, diffpriv_state); modifies this`current_diffpriv_state; ghost method {:axiom} {:autoReq} AdvanceDiffPrivStateMachineByInitializingDB(budget_in:real, new_diffpriv_state:DiffPrivState) requires current_diffpriv_state.initialized; requires current_common_state.initialized; requires current_common_state.TPM == TPM; requires public(budget_in); requires public(PublicPartOfDiffPrivState(new_diffpriv_state)); requires DiffPrivInitializedDBCorrectly(current_diffpriv_state.diffpriv_state, new_diffpriv_state, budget_in); modifies this`current_diffpriv_state; ensures current_diffpriv_state == old(current_diffpriv_state)[diffpriv_state := new_diffpriv_state]; ghost method {:axiom} {:autoReq} AdvanceDiffPrivStateMachineByAddingRow (request_ciphertext_in:seq, new_diffpriv_state:DiffPrivState) requires current_diffpriv_state.initialized; requires current_common_state.initialized; requires current_common_state.TPM == TPM; requires public(request_ciphertext_in); requires public(PublicPartOfDiffPrivState(new_diffpriv_state)); requires DiffPrivRowAddedCorrectly(current_diffpriv_state.diffpriv_state, new_diffpriv_state, current_common_state.common_state.key_pair, request_ciphertext_in); modifies this`current_diffpriv_state; ensures current_diffpriv_state == old(current_diffpriv_state)[diffpriv_state := new_diffpriv_state]; ghost method {:axiom} {:autoReq} AdvanceDiffPrivStateMachineByAnsweringQuery (query_parameters_in:QueryParameters, new_diffpriv_state:DiffPrivState, response_out:int) returns (declassified_response_out:int) requires current_diffpriv_state.initialized; requires current_common_state.initialized; requires public(query_parameters_in); requires public(PublicPartOfDiffPrivState(new_diffpriv_state)); requires DiffPrivQueryPerformedCorrectly(current_diffpriv_state.diffpriv_state, new_diffpriv_state, query_parameters_in, response_out, current_common_state.TPM, TPM); requires Word32(response_out); modifies this`current_common_state; modifies this`current_diffpriv_state; ensures current_common_state == old(current_common_state)[TPM := TPM]; ensures current_diffpriv_state == old(current_diffpriv_state)[diffpriv_state := new_diffpriv_state]; ensures relation(declassified(left(declassified_response_out), right(declassified_response_out), left(response_out), right(response_out))); ensures Word32(declassified_response_out); ================================================ FILE: ironclad-apps/src/Dafny/Apps/DiffPriv/StateMachine2.i.dfy ================================================ //- //- include "StateMachine.s.dfy" include "DiffPriv.i.dfy" include "DiffPrivPerformQuery.i.dfy" include "../../Libraries/Net/Udp.i.dfy" include "../../Libraries/Util/Halter.i.dfy" include "../../Libraries/Util/relational.i.dfy" method {:timeLimitMultiplier 4} HandleGetDiffPrivQuoteRequest(common_state_in:CommonStateImpl, nonce_external:seq) returns (response:DiffPrivResponse, common_state_out:CommonStateImpl) requires CommonStateImplValid(common_state_in); requires common_state_in.key_pair.pub.size >= 1024 / 8; requires TPM_ready(); requires current_common_state == CommonStateMachine_ctor(true, CommonStateImplToSpec(common_state_in), TPM); requires IsByteSeqOfLen(nonce_external, 20); modifies this`TPM; modifies this`IoMemPerm; modifies this`current_common_state; ensures TPM_ready(); ensures WellformedResponse(response); ensures current_common_state == old(current_common_state)[TPM := TPM]; ensures CommonStateImplValid(common_state_out); ensures CommonStateImplToSpec(common_state_out) == CommonStateImplToSpec(common_state_in); requires public(nonce_external); ensures public(response); { var encoded_public_key:seq, pcr_info_bytes:seq, sig_bytes:seq; common_state_out, encoded_public_key, pcr_info_bytes, sig_bytes := HandleGetQuoteRequest(common_state_in, nonce_external); ghost var declassified_encoded_public_key, declassified_pcr_info_bytes, declassified_sig_bytes := AdvanceCommonStateMachineViaGetQuote(nonce_external, encoded_public_key, pcr_info_bytes, sig_bytes); var usable_encoded_public_key := UseDeclassifiedByteSequence(encoded_public_key, declassified_encoded_public_key); var usable_pcr_info_bytes := UseDeclassifiedByteSequence(pcr_info_bytes, declassified_pcr_info_bytes); var usable_sig_bytes := UseDeclassifiedByteSequence(sig_bytes, declassified_sig_bytes); response := GetQuoteResponse_ctor(0, usable_encoded_public_key, usable_pcr_info_bytes, usable_sig_bytes); } method HandleInitializeDBRequest(diffpriv_state_in:DiffPrivStateImpl, budget_num:int, budget_den:int) returns (diffpriv_state_out:DiffPrivStateImpl, response:DiffPrivResponse) requires current_common_state.initialized; requires current_common_state.TPM == TPM; requires DiffPrivStateValid(DiffPrivStateImplToSpec(diffpriv_state_in)); requires current_diffpriv_state == DiffPrivStateMachine_ctor(true, DiffPrivStateImplToSpec(diffpriv_state_in)); requires Word32(budget_num); requires Word32(budget_den); requires budget_den != 0; modifies this`current_diffpriv_state; ensures DiffPrivStateValid(DiffPrivStateImplToSpec(diffpriv_state_out)); ensures WellformedResponse(response); ensures current_diffpriv_state == DiffPrivStateMachine_ctor(true, DiffPrivStateImplToSpec(diffpriv_state_out)); requires public(PublicPartOfDiffPrivState(DiffPrivStateImplToSpec(diffpriv_state_in))); requires public(budget_num); requires public(budget_den); ensures public(PublicPartOfDiffPrivState(DiffPrivStateImplToSpec(diffpriv_state_out))); ensures public(response); { var init_error_code:int; init_error_code, diffpriv_state_out := DiffPrivInitializeDB(diffpriv_state_in, budget_num, budget_den); if init_error_code == 0 { AdvanceDiffPrivStateMachineByInitializingDB(real(budget_num) / real(budget_den), DiffPrivStateImplToSpec(diffpriv_state_out)); } response := InitializeDBResponse_ctor(init_error_code); } method HandleAddRowRequest(diffpriv_state_in:DiffPrivStateImpl, common_state:CommonStateImpl, request_ciphertext:seq) returns (diffpriv_state_out:DiffPrivStateImpl, response:DiffPrivResponse) requires CommonStateImplValid(common_state); requires common_state.key_pair.pub.size >= 1024 / 8; requires TPM_ready(); requires DiffPrivStateValid(DiffPrivStateImplToSpec(diffpriv_state_in)); requires current_common_state == CommonStateMachine_ctor(true, CommonStateImplToSpec(common_state), TPM); requires current_diffpriv_state == DiffPrivStateMachine_ctor(true, DiffPrivStateImplToSpec(diffpriv_state_in)); requires IsByteSeq(request_ciphertext); requires |request_ciphertext| > 0; modifies this`current_diffpriv_state; ensures DiffPrivStateValid(DiffPrivStateImplToSpec(diffpriv_state_out)); ensures WellformedResponse(response); ensures current_diffpriv_state == DiffPrivStateMachine_ctor(true, DiffPrivStateImplToSpec(diffpriv_state_out)); requires public(PublicPartOfDiffPrivState(DiffPrivStateImplToSpec(diffpriv_state_in))); requires public(request_ciphertext); ensures public(PublicPartOfDiffPrivState(DiffPrivStateImplToSpec(diffpriv_state_out))); ensures public(response); { diffpriv_state_out := DiffPrivAddRow(diffpriv_state_in, common_state.key_pair, request_ciphertext); AdvanceDiffPrivStateMachineByAddingRow(request_ciphertext, DiffPrivStateImplToSpec(diffpriv_state_out)); response := AddRowResponse_ctor(); assert response.AddRowResponse_ctor?; // OBSERVE //assert DiffPrivStateValid(DiffPrivStateImplToSpec(diffpriv_state_out)); } ================================================ FILE: ironclad-apps/src/Dafny/Apps/DiffPriv/SumReducer.i.dfy ================================================ include "SumReducer.s.dfy" include "Mapper.i.dfy" static method ComputeSum (db:seq, program:seq, row_min:int, row_max:int, answer_units:int, answer_min:int, answer_max:int) returns (answer:int, ghost sum:int) requires DatabaseValid(db); requires ProgramValid(program); requires Word32(row_min); requires Word32(row_max); requires Word32(answer_units); requires Word32(answer_min); requires Word32(answer_max); requires row_min <= row_max; requires answer_units > 0; requires Word32(answer_units * 2); requires answer_min <= answer_max; ensures sum == MapperSum(db, program, row_min, row_max); ensures Word32(answer); ensures answer == Clip(Scale(sum, answer_units), answer_min, answer_max); { sum := 0; ghost var scaled_sum:int := 0; var clipped_scaled_sum:int := 0; var total_remainder:int := 0; lemma_mul_is_mul_boogie(answer_units, scaled_sum); var which_row := 0; while which_row < |db| invariant 0 <= which_row <= |db|; invariant Word32(clipped_scaled_sum); invariant sum == MapperSum(db[..which_row], program, row_min, row_max); invariant sum == answer_units * scaled_sum + total_remainder; invariant clipped_scaled_sum == (if scaled_sum < power2(32) then scaled_sum else power2(32) - 1); invariant 0 <= total_remainder < answer_units; invariant sum >= 0; { var row_value := RunProgram(program, db[which_row]); var clipped_value := ClipWord32(row_value, row_min, row_max); var scaled_value := clipped_value / answer_units; var scaling_remainder := clipped_value % answer_units; lemma_div_is_ordered_by_denominator(clipped_value, 1, answer_units); lemma_div_by_one_is_identity(clipped_value); lemma_div_pos_is_pos(clipped_value, answer_units); ghost var old_sum := sum; ghost var old_scaled_sum := scaled_sum; ghost var old_total_remainder := total_remainder; sum := sum + clipped_value; scaled_sum := scaled_sum + scaled_value; clipped_scaled_sum := SaturatingAdd(clipped_scaled_sum, scaled_value); lemma_mod_remainder_pos_specific(clipped_value, answer_units); assert 0 <= scaling_remainder < answer_units; assert Word32(total_remainder + scaling_remainder); //- so there's no need to use SaturatingAdd to add these total_remainder := total_remainder + scaling_remainder; calc { answer_units * scaled_sum + total_remainder; answer_units * (old_scaled_sum + scaled_value) + total_remainder; answer_units * (old_scaled_sum + scaled_value) + (old_total_remainder + scaling_remainder); { lemma_mul_is_distributive_add(answer_units, old_scaled_sum, scaled_value); } (answer_units * old_scaled_sum) + (answer_units * scaled_value) + (old_total_remainder + scaling_remainder); (answer_units * old_scaled_sum) + old_total_remainder + (answer_units * scaled_value) + scaling_remainder; old_sum + (answer_units * scaled_value) + scaling_remainder; { lemma_fundamental_div_mod(clipped_value, answer_units); } old_sum + clipped_value; sum; } if total_remainder >= answer_units { ghost var intermediate_scaled_sum := scaled_sum; ghost var intermediate_total_remainder := total_remainder; scaled_sum := scaled_sum + 1; clipped_scaled_sum := SaturatingAdd(clipped_scaled_sum, 1); total_remainder := total_remainder - answer_units; calc { answer_units * scaled_sum + total_remainder; answer_units * (intermediate_scaled_sum + 1) + total_remainder; { lemma_mul_is_distributive_add(answer_units, intermediate_scaled_sum, 1); lemma_mul_is_mul_boogie(answer_units, 1); } answer_units * intermediate_scaled_sum + answer_units * 1 + total_remainder; answer_units * intermediate_scaled_sum + answer_units + total_remainder; answer_units * intermediate_scaled_sum + answer_units + intermediate_total_remainder - answer_units; answer_units * intermediate_scaled_sum + intermediate_total_remainder; sum; } } which_row := which_row + 1; assert db[..which_row][..|db[..which_row]|-1] == db[..which_row-1]; } var extra:int := (if total_remainder * 2 >= answer_units then 1 else 0); clipped_scaled_sum := SaturatingAdd(clipped_scaled_sum, extra); assert db[..which_row] == db; lemma_mul_is_commutative(answer_units, scaled_sum); lemma_fundamental_div_mod_converse(sum, answer_units, scaled_sum, total_remainder); assert sum / answer_units == scaled_sum; assert sum % answer_units == total_remainder; calc { Scale(MapperSum(db, program, row_min, row_max), answer_units); Scale(sum, answer_units); (sum / answer_units) + (if (sum % answer_units) * 2 >= answer_units then 1 else 0); (sum / answer_units) + extra; scaled_sum + extra; } assert db[..which_row] == db; answer := ClipWord32(clipped_scaled_sum, answer_min, answer_max); } //-//////////////////////////////////// //- Helpers //-//////////////////////////////////// static function method SaturatingAdd(x:int, y:int):int requires Word32(x); requires Word32(y); ensures Word32(SaturatingAdd(x, y)); ensures SaturatingAdd(x, y) == if x + y < power2(32) then x + y else power2(32) - 1; { lemma_2toX(); if x + y <= 0xFFFFFFFF then x + y else 0xFFFFFFFF } static function method ClipWord32 (value:int, min:int, max:int) : int requires Word32(value); requires Word32(min); requires Word32(max); requires min <= max; ensures ClipWord32(value, min, max) == Clip(value, min, max); { if value < min then min else if value > max then max else value } ================================================ FILE: ironclad-apps/src/Dafny/Apps/DiffPriv/SumReducer.s.dfy ================================================ include "Math.s.dfy" include "Mapper.s.dfy" static function MapperSum (db:seq, program:seq, row_min:int, row_max:int) : int requires DatabaseValid(db); requires ProgramValid(program); requires row_min <= row_max; { if |db| == 0 then 0 else MapperSum(db[..|db|-1], program, row_min, row_max) + Clip(EvaluateProgram(program, db[|db|-1]), row_min, row_max) } ================================================ FILE: ironclad-apps/src/Dafny/Apps/EtherTest/EtherTest.i.dfy ================================================ include "../../Drivers/Network/Intel/driver.i.dfy" include "../../Libraries/Net/ethernet.i.dfy" include "../../Libraries/Util/integer_sequences.i.dfy" //- //- Ethernet Test App. //- //-method DebugPrintSequence(Offset:int, Data:seq) //- requires 0 <= Offset <= 160 - 16; //- requires IsByteSeq(Data); //- requires |Data| >= 0; //-{ //- var Index:int := 0; //- //- while (Index < |Data|) //- decreases |Data| - Index; //- invariant Index >= 0; //- invariant Index <= |Data|; //- { //- debug_print(Offset, Data[Index]); //- Index := Index + 1; //- } //-} method GenerateSecret() returns (secret:int) ensures IsByte(secret); { secret := 42; } method Main() returns (Result:int) ensures public(true); { lemma_2toX(); var NetUp, net_state := init_network_card(); //-var my_secret := GenerateSecret(); if NetUp { var Headers := [0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20]; var Data := [0x57, 0x6f, 0x72, 0x6c, 0x64, 0x21]; //- This line fails SymDiff, as expected //-Data := Data + [my_secret]; assert IsByteSeq(Headers); assert IsByteSeq(Data); debug_print(0x90, 0xded0d0d0); net_state := EtherSend(net_state, ethernet_addr_builder([0x60, 0x61, 0x62, 0x63, 0x64, 0x65]), Headers, Data); debug_print(0x90, 0xdedadada); Result := 0xdedadada; } else { Result := 0xdeaddead; debug_print(0x90, 0xdeaddead); } } ================================================ FILE: ironclad-apps/src/Dafny/Apps/Notary/.gitignore ================================================ *.bpl *.log ================================================ FILE: ironclad-apps/src/Dafny/Apps/Notary/Main.i.dfy ================================================ //- include "StateMachine.i.dfy" include "MainOneStep.i.dfy" include "../../Libraries/Net/Udp.i.dfy" method MainInitialize () returns (notary_state:NotaryStateImpl, common_state:CommonStateImpl, net_state:network_state) requires TPM_valid(TPM); requires IoMemPerm.Null?; requires TPM_satisfies_integrity_policy(TPM); requires current_common_state.TPM == TPM; requires !current_common_state.initialized; requires !current_notary_state.initialized; ensures TPM_ready(); ensures NotaryStateImplValid(notary_state); ensures CommonStateImplValid(common_state); ensures common_state.key_pair.pub.size >= 1024 / 8; ensures KeyCanBeExtendedIntoPCR(CommonStateImplToSpec(common_state).key_pair); ensures current_common_state == CommonStateMachine_ctor(true, CommonStateImplToSpec(common_state), TPM); ensures current_notary_state == NotaryStateMachine_ctor(true, NotaryStateImplToSpec(notary_state)); ensures valid_network_state(net_state); modifies this`TPM; modifies this`IoMemPerm; modifies this`current_common_state; modifies this`current_notary_state; ensures TPMs_match_except_for_randoms(TPM, old(TPM)[PCR_19 := TPM.PCR_19]); ensures TPM_valid(TPM); ensures IoMemPerm.Null?; ensures public(NotaryStateImplToSpec(notary_state)); ensures public(net_state); { var success:bool; success, net_state := init_network_card(); if !success { HaltMachine(0x40); } common_state := GenerateCommonState(1024); assert TPMs_match_except_for_randoms(TPM, old(TPM)[PCR_19 := TPM.PCR_19]); ghost var common_state_key_pair := common_state.key_pair; ghost var common_state_spec := CommonStateImplToSpec(common_state); InitializeCommonStateMachine(common_state_spec); notary_state := NotaryInitialize(); ghost var notary_state_spec := NotaryStateImplToSpec(notary_state); assert NotaryStateImplValid(notary_state) && NotaryInitializeValid(notary_state_spec); InitializeNotaryStateMachine(notary_state_spec); } //-////////////////////////////////// //- Main routine //-////////////////////////////////// method Main () returns (result:int) requires TPM_valid(TPM); requires IoMemPerm.Null?; requires TPM_satisfies_integrity_policy(TPM); requires current_common_state.TPM == TPM; requires !current_common_state.initialized; requires !current_notary_state.initialized; modifies this`TPM; modifies this`IoMemPerm; modifies this`current_common_state; modifies this`current_notary_state; ensures public(true); //- Needed to convince DafnyCC this procedure involves relational calls { var notary_state, common_state, net_state := MainInitialize(); ghost var post_init_TPM := TPM; while true invariant TPM_ready(); invariant valid_network_state(net_state); invariant NotaryStateImplValid(notary_state); invariant CommonStateImplValid(common_state); invariant common_state.key_pair.pub.size >= 1024 / 8; invariant current_common_state == CommonStateMachine_ctor(true, CommonStateImplToSpec(common_state), TPM); invariant current_notary_state == NotaryStateMachine_ctor(true, NotaryStateImplToSpec(notary_state)); invariant TPMs_match(TPM, post_init_TPM); invariant public(NotaryStateImplToSpec(notary_state)); invariant public(net_state); decreases *; { notary_state, common_state, net_state := MainOneStep(notary_state, common_state, net_state); } return 0; } ================================================ FILE: ironclad-apps/src/Dafny/Apps/Notary/MainOneStep.i.dfy ================================================ //- include "StateMachine.i.dfy" include "../../Libraries/Net/Udp.i.dfy" method {:dafnycc_conservative_seq_triggers} MainOneStep (notary_state_in:NotaryStateImpl, common_state_in:CommonStateImpl, net_state_in:network_state) returns (notary_state_out:NotaryStateImpl, common_state_out:CommonStateImpl, net_state_out:network_state) requires TPM_ready(); requires valid_network_state(net_state_in); requires CommonStateImplValid(common_state_in); requires common_state_in.key_pair.pub.size >= 1024 / 8; requires NotaryStateImplValid(notary_state_in); requires current_common_state == CommonStateMachine_ctor(true, CommonStateImplToSpec(common_state_in), TPM); requires current_notary_state == NotaryStateMachine_ctor(true, NotaryStateImplToSpec(notary_state_in)); ensures TPM_ready(); ensures valid_network_state(net_state_out); ensures NotaryStateImplValid(notary_state_out); ensures current_notary_state == NotaryStateMachine_ctor(true, NotaryStateImplToSpec(notary_state_out)); ensures current_common_state == old(current_common_state)[TPM := TPM]; ensures CommonStateImplValid(common_state_out); ensures CommonStateImplToSpec(common_state_out) == CommonStateImplToSpec(common_state_in); ensures TPMs_match(TPM, old(TPM)); requires public(NotaryStateImplToSpec(notary_state_in)); requires public(net_state_in); ensures public(NotaryStateImplToSpec(notary_state_out)); ensures public(net_state_out); modifies this`TPM; modifies this`IoMemPerm; modifies this`current_notary_state; modifies this`current_common_state; { ghost var notary_state_in_spec := NotaryStateImplToSpec(notary_state_in); ghost var common_state_spec := CommonStateImplToSpec(common_state_in); ghost var common_state_key_pair := common_state_in.key_pair; var success:bool, client_eth:ethernet_addr, client_ip:IPv4Address, my_ip:IPv4Address, client_port:int, my_port:int, request_packet:seq; success, net_state_out, client_eth, client_ip, my_ip, client_port, my_port, request_packet := UdpReceive(net_state_in); if !success { notary_state_out := notary_state_in; common_state_out := common_state_in; return; } var request := ParseRequestPacket(request_packet); var response:NotaryResponse; response, notary_state_out, common_state_out := HandleOneRequest(request, notary_state_in, common_state_in); var response_bytes := FormResponsePacket(response); if |response_bytes| <= 1472 { net_state_out := UdpSend(net_state_out, client_eth, my_ip, client_ip, my_port, client_port, response_bytes); } } ================================================ FILE: ironclad-apps/src/Dafny/Apps/Notary/Notary.i.dfy ================================================ //- include "Notary.s.dfy" include "../../Libraries/Util/relational.s.dfy" include "../../Libraries/BigNum/BigNum.i.dfy" include "../../Libraries/BigNum/BigNatBitCount.i.dfy" include "../../Libraries/Crypto/RSA/KeyGen.i.dfy" include "../../Libraries/Crypto/RSA/RSA.i.dfy" include "../../Libraries/Crypto/RSA/RSAOps.i.dfy" include "../../Libraries/Crypto/RSA/rfc4251impl.i.dfy" include "../Common/CommonState.i.dfy" //- This method has problems verifying unless it's the first one in the file. method {:timeLimitMultiplier 2} CreateNotaryStatement (new_counter_value:BigNat, message:seq) returns (success:bool, notary_statement:seq) requires WellformedBigNat(new_counter_value); requires ModestBigNatValue(new_counter_value); requires IsByteSeq(message); ensures I(new_counter_value) < power2(power2(34)); ensures notary_statement == [34] + rfc4251_mpint_encoding_premium(I(new_counter_value)) + message; ensures success == (|notary_statement| <= 0xFFFFFF); ensures success ==> Word32(|rfc4251_positive_to_twoscomplement(BEIntToByteSeq(I(new_counter_value)))|) && IsByteSeq(notary_statement) && |notary_statement| < power2(28) && Word32(|notary_statement|) && notary_statement == NotaryCounterAdvanceStatement(I(new_counter_value), message); { lemma_2toX(); lemma_power2_add8(24); var counter_encoding := rfc4251_encode_mpint_legacy(new_counter_value); notary_statement := [34] + counter_encoding + message; success := |notary_statement| <= 0xFFFFFF; if !success { return; } Lemma_NotaryCounterAdvanceStatementValid(notary_statement, I(new_counter_value), message, counter_encoding); assert IsByte(34); assert IsByteSeq(notary_statement); assert |notary_statement| <= 0xFFFFFFF < power2(28); assert Word32(|rfc4251_positive_to_twoscomplement(BEIntToByteSeq(I(new_counter_value)))|); assert Word32(|notary_statement|); assert notary_statement == NotaryCounterAdvanceStatement(I(new_counter_value), message); } //-//////////////////////////////////////////////////////////////////////// //- Implementing NotaryState with NotaryStateImpl //-//////////////////////////////////////////////////////////////////////// datatype NotaryStateImpl = NotaryStateImplConstructor(counter:BigNat); static function NotaryStateImplToSpec(s:NotaryStateImpl):NotaryState { NotaryStateConstructor(if WellformedBigNat(s.counter) then I(s.counter) else 0) } static predicate NotaryStateImplValid(notary_state:NotaryStateImpl) { WellformedBigNat(notary_state.counter) && ModestBigNatValue(notary_state.counter) } //-//////////////////////////////////////////////////////////////////////// //- Lemmas //-//////////////////////////////////////////////////////////////////////// lemma Lemma_NotaryCounterAdvanceStatementValid(statement:seq, new_counter_value:nat, message:seq, counter_encoding:seq) requires IsByteSeq(message); requires new_counter_value < power2(power2(34)); requires counter_encoding == rfc4251_mpint_encoding_premium(new_counter_value); requires statement == [34] + counter_encoding + message; ensures statement == NotaryCounterAdvanceStatement(new_counter_value, message); { } //-//////////////////////////////////////////////////////////////////////// //- Exported methods //-//////////////////////////////////////////////////////////////////////// method NotaryInitialize() returns (notary_state:NotaryStateImpl) ensures NotaryStateImplValid(notary_state); ensures NotaryInitializeValid(NotaryStateImplToSpec(notary_state)); ensures public(NotaryStateImplToSpec(notary_state)); { var zero := MakeSmallLiteralBigNat(0); notary_state := NotaryStateImplConstructor(zero); assert NotaryStateImplToSpec(notary_state) == NotaryStateConstructor(0); } static predicate NotaryAdvanceCounterValid_premium(in_state:NotaryState, out_state:NotaryState, common_state:CommonState, message_in:seq, notary_statement_out:seq, notary_attestation_out:seq) requires WellformedRSAKeyPairSpec(common_state.key_pair); requires IsByteSeq(message_in); requires IsByteSeq(notary_statement_out); requires Word32(|notary_statement_out|); requires IsByteSeq(notary_attestation_out); requires Word32(|notary_attestation_out|); requires out_state.counter < KindaBigNat(); requires RSASignatureRequires(common_state.key_pair, notary_statement_out); { calc { out_state.counter; < KindaBigNat(); == power2(power2(31)); <= { lemma_power2_increases(31, 34); lemma_power2_increases(power2(31), power2(34)); } power2(power2(34)); } assert IsByteSeq(rfc4251_mpint_encoding_premium(out_state.counter)); assert IsDigitSeq(power2(32), [|rfc4251_positive_to_twoscomplement(BEIntToByteSeq(out_state.counter))|]); NotaryAdvanceCounterValid(in_state, out_state, common_state, message_in, notary_statement_out, notary_attestation_out) } method AddOneAndRemainModest (n:BigNat) returns (success:bool, nPlusOne:BigNat) requires WellformedBigNat(n); ensures WellformedBigNat(nPlusOne); ensures I(nPlusOne) == I(n) + 1; ensures success == (WellformedBigNat(nPlusOne) && I(nPlusOne) < KindaBigNat()); { lemma_2toX(); var one := MakeSmallLiteralBigNat(1); nPlusOne := BigNatAdd(n, one); success := IsModestBigNat(nPlusOne); } method{:dafnycc_conservative_seq_triggers} NotaryAdvanceCounter (in_state:NotaryStateImpl, common_state:CommonStateImpl, message:seq) returns (out_state:NotaryStateImpl, error_code:int, notary_statement:seq, notary_attestation:seq) requires NotaryStateImplValid(in_state); requires CommonStateImplValid(common_state); requires common_state.key_pair.pub.size >= 1024 / 8; requires IsByteSeq(message); requires TPM_ready(); modifies this`TPM; modifies this`IoMemPerm; ensures TPM_ready(); ensures old(TPM)==TPM; ensures NotaryStateImplValid(out_state); ensures Word32(error_code); ensures Word32(|notary_statement|); ensures Word32(|notary_attestation|); ensures IsByteSeq(notary_statement); ensures IsByteSeq(notary_attestation); ensures error_code == 0 ==> RSASignatureRequires(CommonStateImplToSpec(common_state).key_pair, notary_statement) && NotaryAdvanceCounterValid_premium(NotaryStateImplToSpec(in_state), NotaryStateImplToSpec(out_state), CommonStateImplToSpec(common_state), message, notary_statement, notary_attestation); ensures error_code != 0 ==> out_state == in_state && notary_statement == [] && notary_attestation == []; requires public(NotaryStateImplToSpec(in_state)); requires public(message); ensures public(NotaryStateImplToSpec(out_state)); ensures public(error_code); ensures public(notary_statement); { lemma_2toX(); var success, new_counter_value := AddOneAndRemainModest(in_state.counter); if !success { error_code := 1; out_state := in_state; notary_statement := []; notary_attestation := []; return; } success, notary_statement := CreateNotaryStatement(new_counter_value, message); if !success { error_code := 2; out_state := in_state; notary_statement := []; notary_attestation := []; return; } assert old(TPM)==TPM; notary_attestation := DigestedSign(common_state.key_pair, notary_statement); assert old(TPM)==TPM; error_code := 0; out_state := NotaryStateImplConstructor(new_counter_value); assert NotaryStateImplToSpec(out_state) == NotaryStateConstructor(I(new_counter_value)); assert notary_statement == NotaryCounterAdvanceStatement(NotaryStateImplToSpec(out_state).counter, message); } ================================================ FILE: ironclad-apps/src/Dafny/Apps/Notary/Notary.s.dfy ================================================ include "../../Libraries/Util/be_sequences.s.dfy" include "../../Libraries/Crypto/RSA/RSASpec.s.dfy" include "../../Libraries/Crypto/RSA/rfc4251.s.dfy" include "../Common/CommonState.s.dfy" include "../../Drivers/TPM/tpm-device.s.dfy" //-/////////////////////////////////////////////////// //- Structures //-/////////////////////////////////////////////////// datatype NotaryState = NotaryStateConstructor(counter:nat); //-/////////////////////////////////////////////////// //- Helpers //-/////////////////////////////////////////////////// static function {:autoReq} NotaryCounterAdvanceStatement(new_counter_value:nat, message:seq) : seq { [34] + rfc4251_mpint_encoding(new_counter_value) + message } //-/////////////////////////////////////////////////// //- Specifications for correct method operation //-/////////////////////////////////////////////////// //- This function is used to ensure that notary initialization operates correctly. static predicate {:autoReq} NotaryInitializeValid(notary_state:NotaryState) { notary_state.counter == 0 } //- This function is used to ensure that NotaryAdvanceCounter operates //- correctly. That method is supposed to advance the given counter to the //- next counter value. It should then return an attestation that the //- counter was advanced. static predicate {:autoReq} NotaryAdvanceCounterValid(in_state:NotaryState, out_state:NotaryState, common_state:CommonState, message_in:seq, notary_statement_out:seq, notary_attestation_out:seq) { out_state.counter == in_state.counter + 1 && WellformedRSAKeyPairSpec(common_state.key_pair) && IsByteSeq(message_in) && IsByteSeq(notary_statement_out) && IsByteSeq(notary_attestation_out) && notary_statement_out == NotaryCounterAdvanceStatement(out_state.counter, message_in) && notary_attestation_out == RSASignature(common_state.key_pair, notary_statement_out) } ================================================ FILE: ironclad-apps/src/Dafny/Apps/Notary/PacketParsing.c.dfy ================================================ include "Notary.s.dfy" //-/////////////////////////// //- Request parsing //-/////////////////////////// datatype NotaryRequest = InvalidRequest_ctor() | GetQuoteRequest_ctor(nonce_external:seq) | AdvanceCounterRequest_ctor(message:seq) static predicate RequestParsedCorrectly(data:seq, request:NotaryRequest) { if |data| == 0 then request.InvalidRequest_ctor? else if data[0] == 1 then GetQuoteRequestParsedCorrectly(data, request) else if data[0] == 2 then AdvanceCounterRequestParsedCorrectly(data, request) else request.InvalidRequest_ctor? } static predicate GetQuoteRequestParsedCorrectly(data:seq, request:NotaryRequest) requires |data| > 0; requires data[0] == 1; { if |data| < 21 then request.InvalidRequest_ctor? else request.GetQuoteRequest_ctor? && request.nonce_external == data[1..21] } static predicate AdvanceCounterRequestParsedCorrectly(data:seq, request:NotaryRequest) requires |data| > 0; requires data[0] == 2; { if |data| < 2 then request.InvalidRequest_ctor? else ( var message_len := data[1]; if message_len < 0 || |data| < 2 + message_len then request.InvalidRequest_ctor? else request.AdvanceCounterRequest_ctor? && request.message == data[2..2+message_len] ) } //-/////////////////////////// //- Response parsing //-/////////////////////////// datatype NotaryResponse = NullResponse_ctor() | GetQuoteResponse_ctor(get_quote_error_code:int, encoded_public_key:seq, pcr_info_bytes:seq, sig_bytes:seq) | AdvanceCounterResponse_ctor(advance_error_code:int, notary_statement:seq, notary_attestation:seq) static predicate ResponseFormedCorrectly(response:NotaryResponse, data:seq) { match response case NullResponse_ctor => |data| >= 1 && data[0] == 0 case GetQuoteResponse_ctor(get_quote_error_code, encoded_public_key, pcr_info_bytes, sig_bytes) => Word32(get_quote_error_code) && Word32(|encoded_public_key|) && Word32(|pcr_info_bytes|) && Word32(|sig_bytes|) && IsByteSeq(encoded_public_key) && IsByteSeq(pcr_info_bytes) && IsByteSeq(sig_bytes) && data == [1] + BEWordToFourBytes(get_quote_error_code) + BEWordToFourBytes(|encoded_public_key|) + BEWordToFourBytes(|pcr_info_bytes|) + BEWordToFourBytes(|sig_bytes|) + encoded_public_key + pcr_info_bytes + sig_bytes case AdvanceCounterResponse_ctor(advance_error_code, notary_statement, notary_attestation) => Word32(advance_error_code) && IsByteSeq(notary_statement) && IsByteSeq(notary_attestation) && Word32(|notary_statement|) && Word32(|notary_attestation|) && data == [2] + BEWordToFourBytes(advance_error_code) + BEWordToFourBytes(|notary_statement|) + BEWordToFourBytes(|notary_attestation|) + notary_statement + notary_attestation } ================================================ FILE: ironclad-apps/src/Dafny/Apps/Notary/PacketParsing.i.dfy ================================================ //- include "PacketParsing.c.dfy" include "../../Libraries/Crypto/RSA/RSA.i.dfy" include "../../Libraries/Util/Halter.i.dfy" //-////////////////////////// //- Request parsing //-////////////////////////// static predicate RequestValid (request:NotaryRequest) { match request case InvalidRequest_ctor => true case GetQuoteRequest_ctor(nonce_external) => IsByteSeq(nonce_external) && |nonce_external| == 20 case AdvanceCounterRequest_ctor(message) => IsByteSeq(message) } static method ParseRequestPacket (data:seq) returns (request:NotaryRequest) requires IsByteSeq(data); requires public(data); ensures RequestParsedCorrectly(data, request); ensures RequestValid(request); ensures public(request); { if |data| == 0 { request := InvalidRequest_ctor(); return; } if data[0] == 1 { request := ParseGetQuoteRequestPacket(data); return; } if data[0] == 2 { request := ParseAdvanceCounterRequestPacket(data); return; } request := InvalidRequest_ctor(); } static method ParseGetQuoteRequestPacket (data:seq) returns (request:NotaryRequest) requires IsByteSeq(data); requires |data| > 0; requires data[0] == 1; requires public(data); ensures GetQuoteRequestParsedCorrectly(data, request); ensures RequestValid(request); ensures public(request); { if |data| < 21 { request := InvalidRequest_ctor(); return; } var nonce_external := data[1..21]; return GetQuoteRequest_ctor(nonce_external); } static method ParseAdvanceCounterRequestPacket (data:seq) returns (request:NotaryRequest) requires IsByteSeq(data); requires |data| > 0; requires data[0] == 2; requires public(data); ensures AdvanceCounterRequestParsedCorrectly(data, request); ensures RequestValid(request); ensures public(request); { if |data| < 2 { request := InvalidRequest_ctor(); return; } var message_len := data[1]; if |data| < 2 + message_len { request := InvalidRequest_ctor(); return; } request := AdvanceCounterRequest_ctor(data[2..2+message_len]); } //-////////////////////////// //- Response forming //-////////////////////////// static predicate WellformedResponse (response:NotaryResponse) { match response case NullResponse_ctor => true case GetQuoteResponse_ctor(error_code, encoded_public_key, pcr_info_bytes, sig_bytes) => Word32(error_code) && Word32(|encoded_public_key|) && Word32(|pcr_info_bytes|) && Word32(|sig_bytes|) && IsByteSeq(encoded_public_key) && IsByteSeq(pcr_info_bytes) && IsByteSeq(sig_bytes) case AdvanceCounterResponse_ctor(error_code, statement, attestation) => Word32(error_code) && Word32(|statement|) && Word32(|attestation|) && IsByteSeq(statement) && IsByteSeq(attestation) } static method FormResponsePacket (response:NotaryResponse) returns (data:seq) requires WellformedResponse(response); requires public(response); ensures IsByteSeq(data); ensures ResponseFormedCorrectly(response, data); ensures public(data); { lemma_2toX(); match response { case NullResponse_ctor => data := [0]; assert ResponseFormedCorrectly(response, data); case GetQuoteResponse_ctor(get_quote_error_code, encoded_public_key, pcr_info_bytes, sig_bytes) => var get_quote_error_code_encoded := BEWordToFourBytes_impl(get_quote_error_code); var encoded_public_key_len_encoded := BEWordToFourBytes_impl(|encoded_public_key|); var pcr_info_bytes_len_encoded := BEWordToFourBytes_impl(|pcr_info_bytes|); var sig_bytes_len_encoded := BEWordToFourBytes_impl(|sig_bytes|); data := [1] + get_quote_error_code_encoded + encoded_public_key_len_encoded + pcr_info_bytes_len_encoded + sig_bytes_len_encoded + encoded_public_key + pcr_info_bytes + sig_bytes; assert forall i :: 0 <= i < |data| ==> IsByte(data[i]); assert ResponseFormedCorrectly(response, data); case AdvanceCounterResponse_ctor(advance_error_code, notary_statement, notary_attestation) => var advance_error_code_encoded := BEWordToFourBytes_impl(advance_error_code); var notary_statement_len_encoded := BEWordToFourBytes_impl(|notary_statement|); var notary_attestation_len_encoded := BEWordToFourBytes_impl(|notary_attestation|); data := [2] + advance_error_code_encoded + notary_statement_len_encoded + notary_attestation_len_encoded + notary_statement + notary_attestation; assert forall i :: 0 <= i < |data| ==> IsByte(data[i]); assert ResponseFormedCorrectly(response, data); } } ================================================ FILE: ironclad-apps/src/Dafny/Apps/Notary/StateMachine.i.dfy ================================================ //- include "StateMachine.s.dfy" include "PacketParsing.i.dfy" include "Notary.i.dfy" include "../../Libraries/Crypto/RSA/RSA.i.dfy" include "../../Libraries/Crypto/RSA/RSAOps.i.dfy" include "../../Libraries/Net/Udp.i.dfy" include "../../Libraries/Util/Halter.i.dfy" include "../../Libraries/Util/relational.i.dfy" method {:timeLimitMultiplier 6} HandleOneRequest (request:NotaryRequest, notary_state_in:NotaryStateImpl, common_state_in:CommonStateImpl) returns (response:NotaryResponse, notary_state_out:NotaryStateImpl, common_state_out:CommonStateImpl) requires NotaryStateImplValid(notary_state_in); requires CommonStateImplValid(common_state_in); requires common_state_in.key_pair.pub.size >= 1024 / 8; requires TPM_ready(); requires current_common_state == CommonStateMachine_ctor(true, CommonStateImplToSpec(common_state_in), TPM); requires current_notary_state == NotaryStateMachine_ctor(true, NotaryStateImplToSpec(notary_state_in)); requires RequestValid(request); modifies this`TPM; modifies this`IoMemPerm; modifies this`current_notary_state; modifies this`current_common_state; ensures NotaryStateImplValid(notary_state_out); ensures TPM_ready(); ensures TPMs_match(TPM, old(TPM)); ensures WellformedResponse(response); ensures current_notary_state == NotaryStateMachine_ctor(true, NotaryStateImplToSpec(notary_state_out)); ensures current_common_state == old(current_common_state)[TPM := TPM]; ensures CommonStateImplValid(common_state_out); ensures CommonStateImplToSpec(common_state_out) == CommonStateImplToSpec(common_state_in); requires public(NotaryStateImplToSpec(notary_state_in)); requires public(request); ensures public(NotaryStateImplToSpec(notary_state_out)); ensures public(response); { ghost var old_TPM := TPM; match request { case InvalidRequest_ctor => notary_state_out := notary_state_in; response := NullResponse_ctor(); common_state_out := common_state_in; case GetQuoteRequest_ctor(nonce_external) => var encoded_public_key:seq, pcr_info_bytes:seq, sig_bytes:seq; common_state_out, encoded_public_key, pcr_info_bytes, sig_bytes := HandleGetQuoteRequest(common_state_in, nonce_external); ghost var declassified_encoded_public_key, declassified_pcr_info_bytes, declassified_sig_bytes := AdvanceCommonStateMachineViaGetQuote(nonce_external, encoded_public_key, pcr_info_bytes, sig_bytes); var usable_encoded_public_key := UseDeclassifiedByteSequence(encoded_public_key, declassified_encoded_public_key); var usable_pcr_info_bytes := UseDeclassifiedByteSequence(pcr_info_bytes, declassified_pcr_info_bytes); var usable_sig_bytes := UseDeclassifiedByteSequence(sig_bytes, declassified_sig_bytes); notary_state_out := notary_state_in; response := GetQuoteResponse_ctor(0, usable_encoded_public_key, usable_pcr_info_bytes, usable_sig_bytes); case AdvanceCounterRequest_ctor(message) => var error_code:int, notary_statement:seq, notary_attestation:seq; notary_state_out, error_code, notary_statement, notary_attestation := NotaryAdvanceCounter(notary_state_in, common_state_in, message); var usable_notary_attestation:seq; if error_code != 0 { usable_notary_attestation := []; } else { ghost var declassified_notary_attestation := AdvanceNotaryStateMachineViaAdvanceCounter(message, NotaryStateImplToSpec(notary_state_out), notary_statement, notary_attestation); usable_notary_attestation := UseDeclassifiedByteSequence(notary_attestation, declassified_notary_attestation); } response := AdvanceCounterResponse_ctor(error_code, notary_statement, usable_notary_attestation); common_state_out := common_state_in; } } method HandleOneRequestRaw (request_bytes:seq, notary_state_in:NotaryStateImpl, common_state_in:CommonStateImpl) returns (response_bytes:seq, notary_state_out:NotaryStateImpl, common_state_out:CommonStateImpl) requires NotaryStateImplValid(notary_state_in); requires CommonStateImplValid(common_state_in); requires common_state_in.key_pair.pub.size >= 1024 / 8; requires TPM_ready(); requires current_common_state == CommonStateMachine_ctor(true, CommonStateImplToSpec(common_state_in), TPM); requires current_notary_state == NotaryStateMachine_ctor(true, NotaryStateImplToSpec(notary_state_in)); requires IsByteSeq(request_bytes); modifies this`TPM; modifies this`IoMemPerm; modifies this`current_notary_state; modifies this`current_common_state; ensures NotaryStateImplValid(notary_state_out); ensures TPM_ready(); ensures TPMs_match(TPM, old(TPM)); ensures IsByteSeq(response_bytes); ensures current_notary_state == NotaryStateMachine_ctor(true, NotaryStateImplToSpec(notary_state_out)); ensures current_common_state == old(current_common_state)[TPM := TPM]; ensures CommonStateImplValid(common_state_out); ensures CommonStateImplToSpec(common_state_out) == CommonStateImplToSpec(common_state_in); requires public(NotaryStateImplToSpec(notary_state_in)); requires public(request_bytes); ensures public(NotaryStateImplToSpec(notary_state_out)); ensures public(response_bytes); { var request := ParseRequestPacket(request_bytes); var response:NotaryResponse; response, notary_state_out, common_state_out := HandleOneRequest(request, notary_state_in, common_state_in); response_bytes := FormResponsePacket(response); } ================================================ FILE: ironclad-apps/src/Dafny/Apps/Notary/StateMachine.s.dfy ================================================ include "Notary.s.dfy" include "../Common/CommonState.s.dfy" //-/////////////////////////// //- State machine //-/////////////////////////// datatype NotaryStateMachine = NotaryStateMachine_ctor(initialized:bool, notary_state:NotaryState) ghost var {:readonly} current_notary_state:NotaryStateMachine; ghost method {:axiom} {:autoReq} InitializeNotaryStateMachine(notary_state:NotaryState) requires !current_notary_state.initialized; requires NotaryInitializeValid(notary_state); ensures current_notary_state == NotaryStateMachine_ctor(true, notary_state); modifies this`current_notary_state; ghost method {:axiom} {:autoReq} AdvanceNotaryStateMachineViaAdvanceCounter (message_in:seq, new_notary_state:NotaryState, notary_statement_out:seq, notary_attestation_out:seq) returns (declassified_notary_attestation_out:seq) requires current_notary_state.initialized; requires current_common_state.initialized; requires current_common_state.TPM == TPM; requires public(message_in); requires public(new_notary_state); requires NotaryAdvanceCounterValid(current_notary_state.notary_state, new_notary_state, current_common_state.common_state, message_in, notary_statement_out, notary_attestation_out); modifies this`current_notary_state; ensures current_notary_state == old(current_notary_state)[notary_state := new_notary_state]; ensures IsByteSeqOfLen(declassified_notary_attestation_out, |notary_attestation_out|); ensures public(|notary_attestation_out|); ensures relation(forall i :: left(i) == right(i) && 0 <= left(i) < left(|declassified_notary_attestation_out|) ==> declassified(left(declassified_notary_attestation_out[i]), right(declassified_notary_attestation_out[i]), left(notary_attestation_out[i]), right(notary_attestation_out[i]))); ================================================ FILE: ironclad-apps/src/Dafny/Apps/PassHash/Main.i.dfy ================================================ //- include "StateMachine.s.dfy" include "PacketParsing.i.dfy" include "../../Libraries/Crypto/RSA/RSA.i.dfy" include "../../Libraries/Crypto/RSA/RSAOps.i.dfy" include "../../Libraries/Net/Udp.i.dfy" include "../../Libraries/Util/Halter.i.dfy" include "../../Libraries/Util/relational.i.dfy" include "PassHash.i.dfy" //-////////////////////////////// //- Initialization //-////////////////////////////// method MainInitialize () returns (passhash_state:PassHashStateImpl, net_state:network_state) requires TPM_valid(TPM); requires IoMemPerm.Null?; requires TPM_satisfies_integrity_policy(TPM); requires current_state.TPM == TPM; requires !current_state.initialized; ensures TPM_ready(); ensures PassHashStateImplValid(passhash_state); ensures PassHashInitializeValid(PassHashStateImplToSpec(passhash_state), old(TPM), TPM); ensures current_state == StateMachine_ctor(true, PassHashStateImplToSpec(passhash_state), TPM); ensures valid_network_state(net_state); modifies this`TPM; modifies this`IoMemPerm; modifies this`current_state; ensures TPMs_match_except_for_randoms(TPM, old(TPM)[PCR_19 := TPM.PCR_19]); ensures TPM_valid(TPM); ensures IoMemPerm.Null?; ensures public(net_state); { var success:bool; success, net_state := init_network_card(); if !success { HaltMachine(0x40); } passhash_state := PassHashInitialize(); assert TPMs_match_except_for_randoms(TPM, old(TPM)[PCR_19 := TPM.PCR_19]); assert PassHashStateImplValid(passhash_state) && PassHashInitializeValid(PassHashStateImplToSpec(passhash_state), old(TPM), TPM); ghost var passhash_state_spec := PassHashStateImplToSpec(passhash_state); InitializeStateMachine(passhash_state_spec); } //-////////////////////////////// //- Handling requests //-////////////////////////////// method HandleNullRequest() returns (response_data:seq) ensures IsByteSeq(response_data); ensures public(response_data); { var response := NullResponse_ctor(); response_data := FormResponsePacket(response); } method HandlePerformHashRequest (passhash_state:PassHashStateImpl, request:PassHashRequest) returns (response_data:seq) requires current_state == StateMachine_ctor(true, PassHashStateImplToSpec(passhash_state), TPM); requires PassHashStateImplValid(passhash_state); requires RequestValid(request); requires request.PerformHashRequest_ctor?; requires public(request); ensures IsByteSeq(response_data); ensures public(response_data); { var error_code, computed_hash := PassHashPerformHash(passhash_state, request.message, request.salt); ghost var declassified_hash:seq := AdvanceStateMachineViaPerformHash(request.message, request.salt, error_code, computed_hash); var usable_hash := UseDeclassifiedByteSequence(computed_hash, declassified_hash); var response := PerformHashResponse_ctor(error_code, usable_hash); response_data := FormResponsePacket(response); } method HandleRequest (passhash_state:PassHashStateImpl, request_data:seq) returns (response_data:seq) requires current_state == StateMachine_ctor(true, PassHashStateImplToSpec(passhash_state), TPM); requires PassHashStateImplValid(passhash_state); requires public(request_data); requires IsByteSeq(request_data); ensures IsByteSeq(response_data); ensures public(response_data); { var request := ParseRequestPacket(request_data); match request { case InvalidRequest_ctor => response_data := HandleNullRequest(); case PerformHashRequest_ctor(_, _) => response_data := HandlePerformHashRequest(passhash_state, request); } } method{:dafnycc_conservative_seq_triggers} ReceiveRequestAndSendReply (passhash_state:PassHashStateImpl, net_state_in:network_state) returns (net_state_out:network_state) requires current_state == StateMachine_ctor(true, PassHashStateImplToSpec(passhash_state), TPM); requires PassHashStateImplValid(passhash_state); requires valid_network_state(net_state_in); requires public(net_state_in); ensures valid_network_state(net_state_out); ensures public(net_state_out); { ghost var passhash_state_spec := PassHashStateImplToSpec(passhash_state); var success:bool, client_eth:ethernet_addr, client_ip:IPv4Address, my_ip:IPv4Address, client_port:int, my_port:int, request_data:seq; success, net_state_out, client_eth, client_ip, my_ip, client_port, my_port, request_data := UdpReceive(net_state_in); if !success { return; } var response_data:seq := HandleRequest(passhash_state, request_data); if |response_data| <= 1472 { net_state_out := UdpSend(net_state_out, client_eth, my_ip, client_ip, my_port, client_port, response_data); } } method Main() returns (result:int) requires TPM_valid(TPM); requires IoMemPerm.Null?; requires TPM_satisfies_integrity_policy(TPM); requires current_state.TPM == TPM; requires !current_state.initialized; modifies this`TPM; modifies this`IoMemPerm; modifies this`current_state; ensures public(true); //- Needed to convince DafnyCC this procedure involves relational calls { var passhash_state, net_state := MainInitialize(); ghost var post_init_TPM := TPM; while true invariant TPM_ready(); invariant valid_network_state(net_state); invariant PassHashStateImplValid(passhash_state); invariant current_state == StateMachine_ctor(true, PassHashStateImplToSpec(passhash_state), TPM); invariant TPM == post_init_TPM; invariant public(net_state); { net_state := ReceiveRequestAndSendReply(passhash_state, net_state); } return 0; } ================================================ FILE: ironclad-apps/src/Dafny/Apps/PassHash/PacketParsing.c.dfy ================================================ include "PassHash.s.dfy" //-/////////////////////////// //- Request parsing //-/////////////////////////// datatype PassHashRequest = InvalidRequest_ctor() | PerformHashRequest_ctor(message:seq, salt:seq) static predicate RequestParsedCorrectly(data:seq, request:PassHashRequest) requires IsByteSeq(data); { if |data| == 0 then request.InvalidRequest_ctor? else if data[0] == 1 then PerformHashRequestParsedCorrectly(data, request) else request.InvalidRequest_ctor? } static predicate PerformHashRequestParsedCorrectly(data:seq, request:PassHashRequest) requires IsByteSeq(data); requires |data| > 0; requires data[0] == 1; { if |data| < 9 then request.InvalidRequest_ctor? else ( var message_len := BEByteSeqToInt(data[1..5]); var salt_len := BEByteSeqToInt(data[5..9]); if message_len < 0 || salt_len < 0 || |data| < 9 + message_len + salt_len then request.InvalidRequest_ctor? else request.PerformHashRequest_ctor? && request.message == data[9..9+message_len] && request.salt == data[9+message_len..9+message_len+salt_len] ) } //-/////////////////////////// //- Response parsing //-/////////////////////////// datatype PassHashResponse = NullResponse_ctor() | PerformHashResponse_ctor(hash_error_code:int, passhash_hash:seq); static predicate ResponseFormedCorrectly(response:PassHashResponse, data:seq) { match response case NullResponse_ctor => |data| >= 1 && data[0] == 0 case PerformHashResponse_ctor(hash_error_code, passhash_hash) => Word32(hash_error_code) && IsByteSeqOfLen(passhash_hash, 32) && |data| >= 37 && data[0] == 1 && data[1..5] == BEWordToFourBytes(hash_error_code) && data[5..37] == passhash_hash } ================================================ FILE: ironclad-apps/src/Dafny/Apps/PassHash/PacketParsing.i.dfy ================================================ //- include "PacketParsing.c.dfy" include "../../Libraries/Crypto/RSA/RSA.i.dfy" include "../../Libraries/Util/Halter.i.dfy" //-////////////////////////// //- Request parsing //-////////////////////////// static predicate RequestValid (request:PassHashRequest) { match request case InvalidRequest_ctor => true case PerformHashRequest_ctor(message, salt) => IsByteSeq(message) && IsByteSeq(salt) } static lemma Lemma_PerformHashRequestPacketParsedCorrectly (data:seq, request:PassHashRequest) requires IsByteSeq(data); requires request.PerformHashRequest_ctor?; requires |data| >= 9 + |request.message| + |request.salt|; requires data[0] == 1; requires |request.message| == BEByteSeqToInt(data[1..5]); requires |request.salt| == BEByteSeqToInt(data[5..9]); requires request.message == data[9..9+|request.message|]; requires request.salt == data[9+|request.message|..9+|request.message|+|request.salt|]; ensures PerformHashRequestParsedCorrectly(data, request); { } static method ParseRequestPacket (data:seq) returns (request:PassHashRequest) requires IsByteSeq(data); requires public(data); ensures RequestParsedCorrectly(data, request); ensures RequestValid(request); ensures public(request); { if |data| == 0 { request := InvalidRequest_ctor(); return; } if data[0] == 1 { request := ParsePerformHashRequestPacket(data); return; } request := InvalidRequest_ctor(); } static method ParsePerformHashRequestPacket (data:seq) returns (request:PassHashRequest) requires IsByteSeq(data); requires |data| > 0; requires data[0] == 1; requires public(data); ensures PerformHashRequestParsedCorrectly(data, request); ensures RequestValid(request); ensures public(request); { if |data| < 9 { request := InvalidRequest_ctor(); return; } var message_len := BEFourBytesToWord_impl(data[1..5]); assert message_len == BEByteSeqToInt(data[1..5]); var salt_len := BEFourBytesToWord_impl(data[5..9]); assert salt_len == BEByteSeqToInt(data[5..9]); if message_len < 0 || salt_len < 0 || |data| < 9 + message_len + salt_len { request := InvalidRequest_ctor(); return; } var message := data[9..9+message_len]; var salt := data[9+message_len..9+message_len+salt_len]; request := PerformHashRequest_ctor(message, salt); Lemma_PerformHashRequestPacketParsedCorrectly(data, request); } //-////////////////////////// //- Response forming //-////////////////////////// static predicate WellformedResponse (response:PassHashResponse) { match response case NullResponse_ctor => true case PerformHashResponse_ctor(hash_error_code, passhash_hash) => Word32(hash_error_code) && IsByteSeqOfLen(passhash_hash, 32) } static method FormResponsePacket (response:PassHashResponse) returns (data:seq) requires WellformedResponse(response); requires public(response); ensures IsByteSeq(data); ensures ResponseFormedCorrectly(response, data); ensures public(data); { lemma_2toX(); match response { case NullResponse_ctor => data := [0]; assert ResponseFormedCorrectly(response, data); case PerformHashResponse_ctor(hash_error_code, passhash_hash) => var hash_error_code_encoded := BEWordToFourBytes_impl(hash_error_code); data := [1] + hash_error_code_encoded + passhash_hash; assert data[0] == 1; assert data[1..5] == hash_error_code_encoded == BEWordToFourBytes(hash_error_code); assert data[5..37] == passhash_hash; } } ================================================ FILE: ironclad-apps/src/Dafny/Apps/PassHash/PassHash.i.dfy ================================================ //- include "PassHash.s.dfy" include "../../Libraries/Util/relational.s.dfy" include "../../Libraries/Util/repeat_digit.i.dfy" include "../../Libraries/Crypto/Hash/sha256.i.dfy" include "../../Drivers/TPM/tpm-wrapper.i.dfy" //-//////////////////////////////////////////////////////////////////////// //- Implementing PassHashState with PassHashStateImpl //-//////////////////////////////////////////////////////////////////////// datatype PassHashStateImpl = PassHashStateImplConstructor(secret:seq); static function PassHashStateImplToSpec(s:PassHashStateImpl):PassHashState { PassHashStateConstructor(s.secret) } static predicate PassHashStateImplValid(s:PassHashStateImpl) { IsByteSeq(s.secret) && 32 <= |s.secret| <= 2048 } //-//////////////////////////////////////////////////////////////////////// //- Exported methods //-//////////////////////////////////////////////////////////////////////// method PassHashInitialize() returns (passhash_state:PassHashStateImpl) requires TPM_valid(TPM); requires IoMemPerm.Null?; requires TPM_satisfies_integrity_policy(TPM); ensures TPM_ready(); ensures PassHashStateImplValid(passhash_state); ensures PassHashInitializeValid(PassHashStateImplToSpec(passhash_state), old(TPM), TPM); modifies this`TPM; modifies this`IoMemPerm; ensures TPM_ready(); ensures TPMs_match_except_for_randoms(TPM, old(TPM)[PCR_19 := TPM.PCR_19]); ensures TPM_valid(TPM); ensures IoMemPerm.Null?; { lemma_2toX(); establish_locality(); var secret := get_random(32); passhash_state := PassHashStateImplConstructor(secret); } method{:dafnycc_conservative_seq_triggers} PassHashPerformHash (passhash_state:PassHashStateImpl, message:seq, salt:seq) returns (error_code:int, passhash_hash:seq) requires PassHashStateImplValid(passhash_state); requires IsByteSeq(message); requires IsByteSeq(salt); ensures Word32(error_code); ensures |passhash_hash| == 32; ensures IsByteSeq(passhash_hash); ensures error_code == 0 ==> |BEByteSeqToBitSeq_premium(passhash_state.secret + salt + message)| < power2(64); ensures PassHashPerformHashValid(PassHashStateImplToSpec(passhash_state), message, salt, error_code, passhash_hash); requires public(message); requires public(salt); ensures public(error_code); { lemma_2toX(); if !((|salt| + |message| + 2048) * 8 <= 0xFFFFFFFF) { error_code := 1; passhash_hash := RepeatDigit_impl(0, 32); return; } error_code := 0; var preimage := passhash_state.secret + salt + message; calc { |preimage| * 8; <= (|passhash_state.secret| + |salt| + |message|) * 8; <= (|salt| + |message| + 2048) * 8; <= 0xFFFFFFFF; < power2(32); } calc { |BEByteSeqToBitSeq_premium(preimage)|; == 8 * |preimage|; < power2(32); < { lemma_power2_strictly_increases(35, 64); } power2(64); } var hash := SHA256_impl_Bytes(preimage); passhash_hash := BEWordSeqToByteSeq_impl(hash); } ================================================ FILE: ironclad-apps/src/Dafny/Apps/PassHash/PassHash.s.dfy ================================================ include "../../Libraries/Util/be_sequences.s.dfy" include "../../Libraries/Crypto/Hash/sha256.s.dfy" include "../../Drivers/TPM/tpm-device.s.dfy" //-/////////////////////////////////////////////////// //- Structures //-/////////////////////////////////////////////////// datatype PassHashState = PassHashStateConstructor(secret:seq); //-/////////////////////////////////////////////////// //- Specifications for correct method operation //-/////////////////////////////////////////////////// static predicate {:autoReq} PassHashInitializeValid(passhash_state:PassHashState, before_TPM:TPM_struct, after_TPM:TPM_struct) { TPMs_match(after_TPM, before_TPM[random_index := after_TPM.random_index]) && passhash_state.secret == TPM_random_bytes(before_TPM.random_index, after_TPM.random_index) && IsByteSeq(passhash_state.secret) && |passhash_state.secret| >= 32 } static predicate {:autoReq} PassHashPerformHashValid(passhash_state:PassHashState, message_in:seq, salt_in:seq, error_code_out:int, passhash_hash_out:seq) { if error_code_out == 0 then IsByteSeq(passhash_state.secret) && passhash_hash_out == BEWordSeqToByteSeq(SHA256(BEByteSeqToBitSeq(passhash_state.secret + salt_in + message_in))) else passhash_hash_out == RepeatDigit(0, 32) } ================================================ FILE: ironclad-apps/src/Dafny/Apps/PassHash/StateMachine.s.dfy ================================================ include "PassHash.s.dfy" datatype StateMachine = StateMachine_ctor(initialized:bool, passhash_state:PassHashState, TPM:TPM_struct) ghost var {:readonly} current_state:StateMachine; ghost method {:axiom} InitializeStateMachine(passhash_state:PassHashState) requires !current_state.initialized; requires PassHashInitializeValid(passhash_state, current_state.TPM, TPM); ensures current_state == StateMachine_ctor(true, passhash_state, TPM); modifies this`current_state; ghost method {:axiom} {:autoReq} AdvanceStateMachineViaPerformHash(message_in:seq, salt_in:seq, error_code_out:int, hash_out:seq) returns (declassified_hash_out:seq) requires current_state.initialized; requires current_state.TPM == TPM; requires public(message_in); requires public(salt_in); requires PassHashPerformHashValid(current_state.passhash_state, message_in, salt_in, error_code_out, hash_out); ensures IsByteSeqOfLen(declassified_hash_out, |hash_out|); ensures relation(forall i :: left(i) == right(i) && 0 <= left(i) < left(|declassified_hash_out|) ==> declassified(left(declassified_hash_out[i]), right(declassified_hash_out[i]), left(hash_out[i]), right(hash_out[i]))); ================================================ FILE: ironclad-apps/src/Dafny/Apps/TPMTest/TPMTest.i.dfy ================================================ include "../../Drivers/TPM/tpm-wrapper.i.dfy" include "../../Drivers/IO/pci.i.dfy" include "../../Libraries/Util/repeat_digit.i.dfy" method test_get_pcr() requires Locality3_obtained(); requires TPM_valid(TPM); requires IoMemPerm.Null?; requires TPM_satisfies_integrity_policy(TPM); modifies this`TPM; modifies this`IoMemPerm; ensures TPM_valid(TPM); ensures IoMemPerm.Null?; ensures TPM_satisfies_integrity_policy(TPM); { var success, pcr17 := get_pcr(17); if !success { debug_print(0x30, 0xB000); } else { debug_print(0x30, 0x3333); debug_print(0x31, pcr17[0]); debug_print(0x32, pcr17[1]); debug_print(0x33, pcr17[2]); debug_print(0x34, pcr17[3]); debug_print(0x35, pcr17[4]); } var success2, pcr18 := get_pcr(18); if !success2 { debug_print(0x40, 0xB000); } else { debug_print(0x40, 0x4444); debug_print(0x41, pcr18[0]); debug_print(0x42, pcr18[1]); debug_print(0x43, pcr18[2]); debug_print(0x44, pcr18[3]); debug_print(0x45, pcr18[4]); } } method test_random() requires Locality3_obtained(); requires TPM_valid(TPM); requires IoMemPerm.Null?; requires TPM_satisfies_integrity_policy(TPM); modifies this`TPM; modifies this`IoMemPerm; ensures TPM_valid(TPM); ensures IoMemPerm.Null?; ensures TPM_satisfies_integrity_policy(TPM); { lemma_2toX(); var rand_bytes := get_random(100); debug_print(0x50, rand_bytes[0]); debug_print(0x51, rand_bytes[1]); debug_print(0x52, rand_bytes[2]); debug_print(0x53, rand_bytes[3]); debug_print(0x54, rand_bytes[4]); rand_bytes := get_random(100); debug_print(0x60, rand_bytes[0]); debug_print(0x61, rand_bytes[1]); debug_print(0x62, rand_bytes[2]); debug_print(0x63, rand_bytes[3]); debug_print(0x64, rand_bytes[4]); } method test_quote() requires Locality3_obtained(); requires TPM_valid(TPM); requires IoMemPerm.Null?; requires TPM_satisfies_integrity_policy(TPM); modifies this`TPM; modifies this`IoMemPerm; ensures TPM_valid(TPM); ensures IoMemPerm.Null?; ensures TPM_satisfies_integrity_policy(TPM); { var success:bool; var pcr_info_bytes:seq; var sig_bytes:seq; var nonce_external := RepeatDigit_impl(0, 20); success, pcr_info_bytes, sig_bytes := quote(nonce_external); if !success { debug_print(0x80, 0xB00B00); } else { debug_print(0x80, 0x4444); debug_print(0x81, |pcr_info_bytes|); debug_print(0x82, |sig_bytes|); if |sig_bytes| >= 2 { debug_print(0x83, sig_bytes[0]); debug_print(0x84, sig_bytes[1]); } } } method Main () returns (result:int) requires TPM_valid(TPM); requires IoMemPerm.Null?; requires TPM_satisfies_integrity_policy(TPM); modifies this`TPM; modifies this`IoMemPerm; { debug_print(0x10, 0x1111); establish_locality(); debug_print(0x20, 0x2222); test_get_pcr(); test_random(); test_quote(); return 0; } ================================================ FILE: ironclad-apps/src/Dafny/Apps/TrInc/.gitignore ================================================ *.bpl *.log ================================================ FILE: ironclad-apps/src/Dafny/Apps/TrInc/Main.i.dfy ================================================ //- include "StateMachine.i.dfy" include "../../Libraries/Net/Udp.i.dfy" method MainInitialize () returns (trinc_state:TrIncStateImpl, common_state:CommonStateImpl, net_state:network_state) requires TPM_valid(TPM); requires IoMemPerm.Null?; requires TPM_satisfies_integrity_policy(TPM); requires current_common_state.TPM == TPM; requires !current_common_state.initialized; requires !current_trinc_state.initialized; ensures TPM_ready(); ensures TrIncStateImplValid(trinc_state); ensures CommonStateImplValid(common_state); ensures common_state.key_pair.pub.size >= 1024 / 8; ensures KeyCanBeExtendedIntoPCR(CommonStateImplToSpec(common_state).key_pair); ensures current_common_state == CommonStateMachine_ctor(true, CommonStateImplToSpec(common_state), TPM); ensures current_trinc_state == TrIncStateMachine_ctor(true, TrIncStateImplToSpec(trinc_state)); ensures valid_network_state(net_state); modifies this`TPM; modifies this`IoMemPerm; modifies this`current_common_state; modifies this`current_trinc_state; ensures TPMs_match_except_for_randoms(TPM, old(TPM)[PCR_19 := TPM.PCR_19]); ensures TPM_valid(TPM); ensures IoMemPerm.Null?; ensures public(TrIncStateImplToSpec(trinc_state)); ensures public(net_state); { var success:bool; success, net_state := init_network_card(); if !success { HaltMachine(0x40); } common_state := GenerateCommonState(1024); assert TPMs_match_except_for_randoms(TPM, old(TPM)[PCR_19 := TPM.PCR_19]); ghost var common_state_key_pair := common_state.key_pair; ghost var common_state_spec := CommonStateImplToSpec(common_state); InitializeCommonStateMachine(common_state_spec); trinc_state := TrIncInitialize(); ghost var trinc_state_spec := TrIncStateImplToSpec(trinc_state); assert TrIncStateImplValid(trinc_state) && TrIncInitializeValid(trinc_state_spec); InitializeTrIncStateMachine(trinc_state_spec); } method {:dafnycc_conservative_seq_triggers} MainOneStep (trinc_state_in:TrIncStateImpl, common_state_in:CommonStateImpl, net_state_in:network_state) returns (trinc_state_out:TrIncStateImpl, common_state_out:CommonStateImpl, net_state_out:network_state) requires TPM_ready(); requires valid_network_state(net_state_in); requires CommonStateImplValid(common_state_in); requires common_state_in.key_pair.pub.size >= 1024 / 8; requires TrIncStateImplValid(trinc_state_in); requires current_common_state == CommonStateMachine_ctor(true, CommonStateImplToSpec(common_state_in), TPM); requires current_trinc_state == TrIncStateMachine_ctor(true, TrIncStateImplToSpec(trinc_state_in)); ensures TPM_ready(); ensures valid_network_state(net_state_out); ensures TrIncStateImplValid(trinc_state_out); ensures current_trinc_state == TrIncStateMachine_ctor(true, TrIncStateImplToSpec(trinc_state_out)); ensures current_common_state == old(current_common_state)[TPM := TPM]; ensures CommonStateImplValid(common_state_out); ensures CommonStateImplToSpec(common_state_out) == CommonStateImplToSpec(common_state_in); ensures TPMs_match(TPM, old(TPM)); requires public(TrIncStateImplToSpec(trinc_state_in)); requires public(net_state_in); ensures public(TrIncStateImplToSpec(trinc_state_out)); ensures public(net_state_out); modifies this`TPM; modifies this`IoMemPerm; modifies this`current_trinc_state; modifies this`current_common_state; { ghost var trinc_state_in_spec := TrIncStateImplToSpec(trinc_state_in); ghost var common_state_spec := CommonStateImplToSpec(common_state_in); ghost var common_state_key_pair := common_state_in.key_pair; var success:bool, client_eth:ethernet_addr, client_ip:IPv4Address, my_ip:IPv4Address, client_port:int, my_port:int, request_bytes:seq; success, net_state_out, client_eth, client_ip, my_ip, client_port, my_port, request_bytes := UdpReceive(net_state_in); if !success { trinc_state_out := trinc_state_in; common_state_out := common_state_in; return; } var response_bytes:seq; response_bytes, trinc_state_out, common_state_out := HandleOneRequestRaw(request_bytes, trinc_state_in, common_state_in); if |response_bytes| <= 1472 { net_state_out := UdpSend(net_state_out, client_eth, my_ip, client_ip, my_port, client_port, response_bytes); } } //-////////////////////////////////// //- Main routine //-////////////////////////////////// method Main () returns (result:int) requires TPM_valid(TPM); requires IoMemPerm.Null?; requires TPM_satisfies_integrity_policy(TPM); requires current_common_state.TPM == TPM; requires !current_common_state.initialized; requires !current_trinc_state.initialized; modifies this`TPM; modifies this`IoMemPerm; modifies this`current_common_state; modifies this`current_trinc_state; ensures public(true); //- Needed to convince DafnyCC this procedure involves relational calls { var trinc_state, common_state, net_state := MainInitialize(); ghost var post_init_TPM := TPM; while true invariant TPM_ready(); invariant valid_network_state(net_state); invariant TrIncStateImplValid(trinc_state); invariant CommonStateImplValid(common_state); invariant common_state.key_pair.pub.size >= 1024 / 8; invariant current_common_state == CommonStateMachine_ctor(true, CommonStateImplToSpec(common_state), TPM); invariant current_trinc_state == TrIncStateMachine_ctor(true, TrIncStateImplToSpec(trinc_state)); invariant TPMs_match(TPM, post_init_TPM); invariant public(TrIncStateImplToSpec(trinc_state)); invariant public(net_state); decreases *; { trinc_state, common_state, net_state := MainOneStep(trinc_state, common_state, net_state); } return 0; } ================================================ FILE: ironclad-apps/src/Dafny/Apps/TrInc/PacketParsing.c.dfy ================================================ include "TrInc.s.dfy" //-/////////////////////////// //- Request parsing //-/////////////////////////// datatype TrIncRequest = InvalidRequest_ctor() | GetQuoteRequest_ctor(nonce_external:seq) | CreateCounterRequest_ctor(public_key_encoding:seq) | AdvanceCounterRequest_ctor(counter_index:nat, new_counter_value_encoding:seq, message:seq, request_attestation:seq) static predicate RequestParsedCorrectly (data:seq, request:TrIncRequest) requires IsByteSeq(data); { if |data| == 0 then request.InvalidRequest_ctor? else if data[0] == 1 then GetQuoteRequestParsedCorrectly(data, request) else if data[0] == 2 then CreateCounterRequestParsedCorrectly(data, request) else if data[0] == 3 then AdvanceCounterRequestParsedCorrectly(data, request) else request.InvalidRequest_ctor? } static predicate GetQuoteRequestParsedCorrectly(data:seq, request:TrIncRequest) requires |data| > 0; requires data[0] == 1; { if |data| < 21 then request.InvalidRequest_ctor? else request.GetQuoteRequest_ctor? && request.nonce_external == data[1..21] } static predicate CreateCounterRequestParsedCorrectly (data:seq, request:TrIncRequest) requires IsByteSeq(data); requires |data| > 0; requires data[0] == 2; { if |data| < 5 then request.InvalidRequest_ctor? else ( var public_key_length := BEByteSeqToInt(data[1..5]); if public_key_length < 0 || |data| < 5 + public_key_length then request.InvalidRequest_ctor? else request.CreateCounterRequest_ctor? && request.public_key_encoding == data[5..5+public_key_length] ) } static predicate AdvanceCounterRequestParsedCorrectly (data:seq, request:TrIncRequest) requires IsByteSeq(data); requires |data| > 0; requires data[0] == 3; { if |data| < 17 then request.InvalidRequest_ctor? else ( var counter_index := BEByteSeqToInt(data[1..5]); var new_counter_len := BEByteSeqToInt(data[5..9]); var message_len := BEByteSeqToInt(data[9..13]); var request_attestation_len := BEByteSeqToInt(data[13..17]); if new_counter_len < 0 || message_len < 0 || request_attestation_len < 0 || |data| < 17 + new_counter_len + message_len + request_attestation_len then request.InvalidRequest_ctor? else request.AdvanceCounterRequest_ctor? && request.counter_index == counter_index && request.new_counter_value_encoding == data[17..17+new_counter_len] && request.message == data[17+new_counter_len..17+new_counter_len+message_len] && request.request_attestation == data[17+new_counter_len+message_len..17+new_counter_len+message_len+request_attestation_len] ) } //-/////////////////////////// //- Response parsing //-/////////////////////////// datatype TrIncResponse = NullResponse_ctor() | GetQuoteResponse_ctor(get_quote_error_code:int, encoded_public_key:seq, pcr_info_bytes:seq, sig_bytes:seq) | CreateCounterResponse_ctor(create_error_code:int, counter_index:nat) | AdvanceCounterResponse_ctor(advance_error_code:int, TrInc_statement:seq, TrInc_attestation:seq) static function ResponseFormedCorrectly (response:TrIncResponse, data:seq) : bool requires IsByteSeq(data); { match response case NullResponse_ctor => |data| >= 1 && data[0] == 0 case GetQuoteResponse_ctor(get_quote_error_code, encoded_public_key, pcr_info_bytes, sig_bytes) => Word32(get_quote_error_code) && Word32(|encoded_public_key|) && Word32(|pcr_info_bytes|) && Word32(|sig_bytes|) && IsByteSeq(encoded_public_key) && IsByteSeq(pcr_info_bytes) && IsByteSeq(sig_bytes) && data == [1] + BEWordToFourBytes(get_quote_error_code) + BEWordToFourBytes(|encoded_public_key|) + BEWordToFourBytes(|pcr_info_bytes|) + BEWordToFourBytes(|sig_bytes|) + encoded_public_key + pcr_info_bytes + sig_bytes case CreateCounterResponse_ctor(create_error_code, counter_index) => Word32(create_error_code) && Word32(counter_index) && data == [2] + BEWordToFourBytes(create_error_code) + BEWordToFourBytes(counter_index) case AdvanceCounterResponse_ctor(advance_error_code, TrInc_statement, TrInc_attestation) => Word32(advance_error_code) && IsByteSeq(TrInc_statement) && IsByteSeq(TrInc_attestation) && Word32(|TrInc_statement|) && Word32(|TrInc_attestation|) && data == [3] + BEWordToFourBytes(advance_error_code) + BEWordToFourBytes(|TrInc_statement|) + BEWordToFourBytes(|TrInc_attestation|) + TrInc_statement + TrInc_attestation } ================================================ FILE: ironclad-apps/src/Dafny/Apps/TrInc/PacketParsing.i.dfy ================================================ //- include "PacketParsing.c.dfy" include "../../Libraries/Util/seqs_transforms.i.dfy" //-////////////////////////// //- Request parsing //-////////////////////////// static predicate RequestValid (request:TrIncRequest) { match request case InvalidRequest_ctor => true case GetQuoteRequest_ctor(nonce_external) => IsByteSeq(nonce_external) && |nonce_external| == 20 case CreateCounterRequest_ctor(public_key_encoding) => IsByteSeq(public_key_encoding) case AdvanceCounterRequest_ctor(counter_index, new_counter_value_encoding, message, message_attestation) => Word32(counter_index) && IsByteSeq(new_counter_value_encoding) && IsByteSeq(message) && IsByteSeq(message_attestation) } static method ParseRequestPacket (data:seq) returns (request:TrIncRequest) requires IsByteSeq(data); requires public(data); ensures RequestParsedCorrectly(data, request); ensures RequestValid(request); ensures public(request); { if |data| == 0 { request := InvalidRequest_ctor(); return; } if data[0] == 1 { request := ParseGetQuoteRequestPacket(data); return; } if data[0] == 2 { request := ParseCreateCounterRequestPacket(data); return; } if data[0] == 3 { request := ParseAdvanceCounterRequestPacket(data); return; } request := InvalidRequest_ctor(); } static method ParseGetQuoteRequestPacket (data:seq) returns (request:TrIncRequest) requires IsByteSeq(data); requires |data| > 0; requires data[0] == 1; requires public(data); ensures GetQuoteRequestParsedCorrectly(data, request); ensures RequestValid(request); ensures public(request); { if |data| < 21 { request := InvalidRequest_ctor(); return; } var nonce_external := data[1..21]; return GetQuoteRequest_ctor(nonce_external); } static method ParseCreateCounterRequestPacket (data:seq) returns (request:TrIncRequest) requires IsByteSeq(data); requires |data| > 0; requires data[0] == 2; requires public(data); ensures CreateCounterRequestParsedCorrectly(data, request); ensures RequestValid(request); ensures public(request); { request := InvalidRequest_ctor(); if |data| < 5 { request := InvalidRequest_ctor(); return; } var public_key_len := BEFourBytesToWord_impl(data[1..5]); if public_key_len < 0 || |data| < 5 + public_key_len { request := InvalidRequest_ctor(); return; } request := CreateCounterRequest_ctor(data[5..5+public_key_len]); } static method ParseAdvanceCounterRequestPacket (data:seq) returns (request:TrIncRequest) requires IsByteSeq(data); requires |data| > 0; requires data[0] == 3; requires public(data); ensures AdvanceCounterRequestParsedCorrectly(data, request); ensures RequestValid(request); ensures public(request); { if |data| < 17 { request := InvalidRequest_ctor(); return; } var counter_index := BEFourBytesToWord_impl(data[1..5]); var new_counter_len := BEFourBytesToWord_impl(data[5..9]); var message_len := BEFourBytesToWord_impl(data[9..13]); var request_attestation_len := BEFourBytesToWord_impl(data[13..17]); if new_counter_len < 0 || message_len < 0 || request_attestation_len < 0 || |data| < 17 + new_counter_len + message_len + request_attestation_len { request := InvalidRequest_ctor(); return; } lemma_2toX(); reveal_power2(); assert Word32(counter_index); request := AdvanceCounterRequest_ctor(counter_index, data[17..17+new_counter_len], data[17+new_counter_len..17+new_counter_len+message_len], data[17+new_counter_len+message_len..17+new_counter_len+message_len+request_attestation_len]); } //-////////////////////////// //- Response forming //-////////////////////////// static predicate WellformedResponse (response:TrIncResponse) { match response case NullResponse_ctor => true case GetQuoteResponse_ctor(error_code, encoded_public_key, pcr_info_bytes, sig_bytes) => Word32(error_code) && Word32(|encoded_public_key|) && Word32(|pcr_info_bytes|) && Word32(|sig_bytes|) && IsByteSeq(encoded_public_key) && IsByteSeq(pcr_info_bytes) && IsByteSeq(sig_bytes) case CreateCounterResponse_ctor(error_code, counter_index) => Word32(error_code) && Word32(counter_index) case AdvanceCounterResponse_ctor(error_code, statement, attestation) => Word32(error_code) && Word32(|statement|) && Word32(|attestation|) && IsByteSeq(statement) && IsByteSeq(attestation) } static method FormResponsePacket (response:TrIncResponse) returns (data:seq) requires WellformedResponse(response); requires public(response); ensures IsByteSeq(data); ensures ResponseFormedCorrectly(response, data); ensures public(data); { lemma_2toX(); match response { case NullResponse_ctor => data := [0]; case GetQuoteResponse_ctor(get_quote_error_code, encoded_public_key, pcr_info_bytes, sig_bytes) => var get_quote_error_code_encoded := BEWordToFourBytes_impl(get_quote_error_code); var encoded_public_key_len_encoded := BEWordToFourBytes_impl(|encoded_public_key|); var pcr_info_bytes_len_encoded := BEWordToFourBytes_impl(|pcr_info_bytes|); var sig_bytes_len_encoded := BEWordToFourBytes_impl(|sig_bytes|); data := [1] + get_quote_error_code_encoded + encoded_public_key_len_encoded + pcr_info_bytes_len_encoded + sig_bytes_len_encoded + encoded_public_key + pcr_info_bytes + sig_bytes; assert forall i :: 0 <= i < |data| ==> IsByte(data[i]); assert ResponseFormedCorrectly(response, data); case CreateCounterResponse_ctor(create_error_code, counter_index) => var create_error_code_encoded := BEWordToFourBytes_impl(create_error_code); var counter_index_encoded := BEWordToFourBytes_impl(counter_index); data := [2] + create_error_code_encoded + counter_index_encoded; assert ResponseFormedCorrectly(response, data); case AdvanceCounterResponse_ctor(advance_error_code, TrInc_statement, TrInc_attestation) => var advance_error_code_encoded := BEWordToFourBytes_impl(advance_error_code); var TrInc_statement_len_encoded := BEWordToFourBytes_impl(|TrInc_statement|); var TrInc_attestation_len_encoded := BEWordToFourBytes_impl(|TrInc_attestation|); data := [3] + advance_error_code_encoded + TrInc_statement_len_encoded + TrInc_attestation_len_encoded + TrInc_statement + TrInc_attestation; assert IsByteSeq(data); assert ResponseFormedCorrectly(response, data); } } ================================================ FILE: ironclad-apps/src/Dafny/Apps/TrInc/StateMachine.i.dfy ================================================ //- include "StateMachine.s.dfy" include "PacketParsing.i.dfy" include "TrInc.i.dfy" include "../../Libraries/Crypto/RSA/RSA.i.dfy" include "../../Libraries/Crypto/RSA/RSAOps.i.dfy" include "../../Libraries/Net/Udp.i.dfy" include "../../Libraries/Util/relational.i.dfy" method {:timeLimitMultiplier 4} HandleOneRequest (request:TrIncRequest, trinc_state_in:TrIncStateImpl, common_state_in:CommonStateImpl) returns (response:TrIncResponse, trinc_state_out:TrIncStateImpl, common_state_out:CommonStateImpl) requires TrIncStateImplValid(trinc_state_in); requires CommonStateImplValid(common_state_in); requires common_state_in.key_pair.pub.size >= 1024 / 8; requires TPM_ready(); requires current_common_state == CommonStateMachine_ctor(true, CommonStateImplToSpec(common_state_in), TPM); requires current_trinc_state == TrIncStateMachine_ctor(true, TrIncStateImplToSpec(trinc_state_in)); requires RequestValid(request); modifies this`TPM; modifies this`IoMemPerm; modifies this`current_trinc_state; modifies this`current_common_state; ensures TrIncStateImplValid(trinc_state_out); ensures TPM_ready(); ensures TPMs_match(TPM, old(TPM)); ensures WellformedResponse(response); ensures current_trinc_state == TrIncStateMachine_ctor(true, TrIncStateImplToSpec(trinc_state_out)); ensures current_common_state == old(current_common_state)[TPM := TPM]; ensures CommonStateImplValid(common_state_out); ensures CommonStateImplToSpec(common_state_out) == CommonStateImplToSpec(common_state_in); requires public(TrIncStateImplToSpec(trinc_state_in)); requires public(request); ensures public(TrIncStateImplToSpec(trinc_state_out)); ensures public(response); { match request { case InvalidRequest_ctor => response := NullResponse_ctor(); trinc_state_out := trinc_state_in; common_state_out := common_state_in; case GetQuoteRequest_ctor(nonce_external) => var encoded_public_key:seq, pcr_info_bytes:seq, sig_bytes:seq; common_state_out, encoded_public_key, pcr_info_bytes, sig_bytes := HandleGetQuoteRequest(common_state_in, nonce_external); ghost var declassified_encoded_public_key, declassified_pcr_info_bytes, declassified_sig_bytes := AdvanceCommonStateMachineViaGetQuote(nonce_external, encoded_public_key, pcr_info_bytes, sig_bytes); var usable_encoded_public_key := UseDeclassifiedByteSequence(encoded_public_key, declassified_encoded_public_key); var usable_pcr_info_bytes := UseDeclassifiedByteSequence(pcr_info_bytes, declassified_pcr_info_bytes); var usable_sig_bytes := UseDeclassifiedByteSequence(sig_bytes, declassified_sig_bytes); trinc_state_out := trinc_state_in; response := GetQuoteResponse_ctor(0, usable_encoded_public_key, usable_pcr_info_bytes, usable_sig_bytes); case CreateCounterRequest_ctor(public_key_encoding) => var create_error_code:int, counter_index:nat; trinc_state_out, create_error_code, counter_index := TrIncCreateCounter(trinc_state_in, common_state_in, public_key_encoding); if create_error_code == 0 { AdvanceTrIncStateMachineViaCreateCounter(public_key_encoding, TrIncStateImplToSpec(trinc_state_out), counter_index); } response := CreateCounterResponse_ctor(create_error_code, counter_index); common_state_out := common_state_in; case AdvanceCounterRequest_ctor(counter_index, new_counter_value_encoding, message, message_attestation) => var advance_error_code:int, trinc_statement:seq, trinc_attestation:seq; trinc_state_out, advance_error_code, trinc_statement, trinc_attestation := TrIncAdvanceCounter(trinc_state_in, common_state_in, counter_index, new_counter_value_encoding, message, message_attestation); var usable_trinc_attestation:seq; if advance_error_code != 0 { usable_trinc_attestation := []; } else { ghost var declassified_trinc_attestation := AdvanceTrIncStateMachineViaAdvanceCounter(counter_index, new_counter_value_encoding, message, message_attestation, TrIncStateImplToSpec(trinc_state_out), trinc_statement, trinc_attestation); usable_trinc_attestation := UseDeclassifiedByteSequence(trinc_attestation, declassified_trinc_attestation); } response := AdvanceCounterResponse_ctor(advance_error_code, trinc_statement, usable_trinc_attestation); common_state_out := common_state_in; } } method HandleOneRequestRaw (request_bytes:seq, trinc_state_in:TrIncStateImpl, common_state_in:CommonStateImpl) returns (response_bytes:seq, trinc_state_out:TrIncStateImpl, common_state_out:CommonStateImpl) requires TrIncStateImplValid(trinc_state_in); requires CommonStateImplValid(common_state_in); requires common_state_in.key_pair.pub.size >= 1024 / 8; requires TPM_ready(); requires current_common_state == CommonStateMachine_ctor(true, CommonStateImplToSpec(common_state_in), TPM); requires current_trinc_state == TrIncStateMachine_ctor(true, TrIncStateImplToSpec(trinc_state_in)); requires IsByteSeq(request_bytes); modifies this`TPM; modifies this`IoMemPerm; modifies this`current_trinc_state; modifies this`current_common_state; ensures TrIncStateImplValid(trinc_state_out); ensures TPM_ready(); ensures TPMs_match(TPM, old(TPM)); ensures IsByteSeq(response_bytes); ensures current_trinc_state == TrIncStateMachine_ctor(true, TrIncStateImplToSpec(trinc_state_out)); ensures current_common_state == old(current_common_state)[TPM := TPM]; ensures CommonStateImplValid(common_state_out); ensures CommonStateImplToSpec(common_state_out) == CommonStateImplToSpec(common_state_in); requires public(TrIncStateImplToSpec(trinc_state_in)); requires public(request_bytes); ensures public(TrIncStateImplToSpec(trinc_state_out)); ensures public(response_bytes); { var request := ParseRequestPacket(request_bytes); var response:TrIncResponse; response, trinc_state_out, common_state_out := HandleOneRequest(request, trinc_state_in, common_state_in); response_bytes := FormResponsePacket(response); } ================================================ FILE: ironclad-apps/src/Dafny/Apps/TrInc/StateMachine.s.dfy ================================================ include "TrInc.s.dfy" //-/////////////////////////// //- State machine //-/////////////////////////// datatype TrIncStateMachine = TrIncStateMachine_ctor(initialized:bool, trinc_state:TrIncState) ghost var {:readonly} current_trinc_state:TrIncStateMachine; ghost method {:axiom} {:autoReq} InitializeTrIncStateMachine(trinc_state:TrIncState) requires !current_trinc_state.initialized; requires TrIncInitializeValid(trinc_state); ensures current_trinc_state == TrIncStateMachine_ctor(true, trinc_state); modifies this`current_trinc_state; ghost method {:axiom} {:autoReq} AdvanceTrIncStateMachineViaCreateCounter (public_key_encoding_in:seq, new_trinc_state:TrIncState, counter_index_out:nat) requires current_trinc_state.initialized; requires current_common_state.initialized; requires current_common_state.TPM == TPM; requires public(public_key_encoding_in); requires public(new_trinc_state); requires TrIncCreateCounterValid(current_trinc_state.trinc_state, new_trinc_state, current_common_state.common_state, public_key_encoding_in, counter_index_out); modifies this`current_trinc_state; ensures current_trinc_state == old(current_trinc_state)[trinc_state := new_trinc_state]; ghost method {:axiom} {:autoReq} AdvanceTrIncStateMachineViaAdvanceCounter (counter_index_in:nat, new_counter_value_encoding_in:seq, message_in:seq, message_attestation_in:seq, new_trinc_state:TrIncState, trinc_statement_out:seq, trinc_attestation_out:seq) returns (declassified_trinc_attestation_out:seq) requires current_trinc_state.initialized; requires current_common_state.initialized; requires current_common_state.TPM == TPM; requires public(counter_index_in); requires public(new_counter_value_encoding_in); requires public(message_in); requires public(message_attestation_in); requires public(new_trinc_state); requires TrIncAdvanceCounterValid(current_trinc_state.trinc_state, new_trinc_state, current_common_state.common_state, counter_index_in, new_counter_value_encoding_in, message_in, message_attestation_in, trinc_statement_out, trinc_attestation_out); modifies this`current_trinc_state; ensures current_trinc_state == old(current_trinc_state)[trinc_state := new_trinc_state]; ensures IsByteSeqOfLen(declassified_trinc_attestation_out, |trinc_attestation_out|); ensures public(|trinc_attestation_out|); ensures relation(forall i :: left(i) == right(i) && 0 <= left(i) < left(|declassified_trinc_attestation_out|) ==> declassified(left(declassified_trinc_attestation_out[i]), right(declassified_trinc_attestation_out[i]), left(trinc_attestation_out[i]), right(trinc_attestation_out[i]))); ================================================ FILE: ironclad-apps/src/Dafny/Apps/TrInc/TrInc.i.dfy ================================================ //- include "TrInc.s.dfy" include "../../Libraries/Util/relational.s.dfy" include "../../Libraries/BigNum/BigNum.i.dfy" include "../../Libraries/BigNum/BigNatBitCount.i.dfy" include "../../Libraries/Crypto/RSA/KeyGen.i.dfy" include "../../Libraries/Crypto/RSA/RSA.i.dfy" include "../../Libraries/Crypto/RSA/RSAOps.i.dfy" include "../../Libraries/Crypto/RSA/rfc4251decode.i.dfy" include "../Common/CommonState.i.dfy" //-//////////////////////////////////////////////////////////////////////// //- Implementing TrIncCounter with TrIncCounterImpl //-//////////////////////////////////////////////////////////////////////// datatype TrIncCounterImpl = TrIncCounterImpl_c(public_key:RSAPubKeyImpl, counter_value:BigNat); predicate TrIncCounterImplValid (c:TrIncCounterImpl) { WellformedBigNat(c.counter_value) && ModestBigNatValue(c.counter_value) && WellformedRSAPubKeyImpl(c.public_key) && WellformedRSAPubKeySpec(PubKeyImplToSpec(c.public_key)) && RSA_DIGEST_MIN_KEY_SIZE() <= PubKeyImplToSpec(c.public_key).size < power2(60) } predicate TrIncCounterImplSeqValid (s:seq) { forall i :: 0 <= i < |s| ==> TrIncCounterImplValid(s[i]) } function TrIncCounterImplToSpec (c:TrIncCounterImpl) : TrIncCounter requires TrIncCounterImplValid(c); { TrIncCounterConstructor(PubKeyImplToSpec(c.public_key), I(c.counter_value)) } function TrIncCounterImplSeqToSpec (s:seq) : seq requires TrIncCounterImplSeqValid(s); { if |s| == 0 then [] else TrIncCounterImplSeqToSpec(s[..|s|-1]) + [TrIncCounterImplToSpec(s[|s|-1])] } lemma Lemma_TrIncCounterImplSeqToSpecRelation (s_impl:seq, s_spec:seq) requires TrIncCounterImplSeqValid(s_impl); requires s_spec == TrIncCounterImplSeqToSpec(s_impl); ensures |s_spec| == |s_impl|; ensures forall i :: 0 <= i < |s_spec| ==> s_spec[i] == TrIncCounterImplToSpec(s_impl[i]); ensures forall i :: 0 <= i < |s_spec| ==> s_spec[i].public_key == PubKeyImplToSpec(s_impl[i].public_key); ensures forall i :: 0 <= i < |s_spec| ==> s_spec[i].counter_value == I(s_impl[i].counter_value); decreases |s_impl|; { if |s_impl| > 0 { assert s_spec == TrIncCounterImplSeqToSpec(s_impl[..|s_impl|-1]) + [TrIncCounterImplToSpec(s_impl[|s_impl|-1])]; assert s_spec[|s_spec|-1] == TrIncCounterImplToSpec(s_impl[|s_impl|-1]); Lemma_TrIncCounterImplSeqToSpecRelation(s_impl[..|s_impl|-1], s_spec[..|s_spec|-1]); assert forall i :: 0 <= i < |s_spec|-1 ==> s_spec[i] == TrIncCounterImplToSpec(s_impl[i]); } } lemma Lemma_TrIncCounterImplSeqToSpecOfOne(c:TrIncCounterImpl) requires TrIncCounterImplValid(c); ensures TrIncCounterImplSeqToSpec([c]) == [TrIncCounterImplToSpec(c)]; { calc { TrIncCounterImplSeqToSpec([c]); TrIncCounterImplSeqToSpec([c][..|[c]|-1]) + [TrIncCounterImplToSpec([c][|[c]|-1])]; TrIncCounterImplSeqToSpec([c][..0]) + [TrIncCounterImplToSpec([c][|[c]|-1])]; TrIncCounterImplSeqToSpec([]) + [TrIncCounterImplToSpec([c][|[c]|-1])]; [] + [TrIncCounterImplToSpec([c][|[c]|-1])]; [TrIncCounterImplToSpec([c][|[c]|-1])]; [TrIncCounterImplToSpec([c][0])]; [TrIncCounterImplToSpec(c)]; } } lemma Lemma_IndexIntoSequenceConcatenation(s1:seq, s2:seq, i:int) requires |s1| <= i < |s1| + |s2|; ensures (s1+s2)[i] == s2[i - |s1|]; { } lemma Lemma_TrIncCounterImplSeqToSpecConcatenation (s1:seq, s2:seq) requires TrIncCounterImplSeqValid(s1); requires TrIncCounterImplSeqValid(s2); ensures TrIncCounterImplSeqToSpec(s1+s2) == TrIncCounterImplSeqToSpec(s1) + TrIncCounterImplSeqToSpec(s2); { ghost var s12 := s1 + s2; ghost var s1_spec := TrIncCounterImplSeqToSpec(s1); ghost var s2_spec := TrIncCounterImplSeqToSpec(s2); ghost var s12_spec := TrIncCounterImplSeqToSpec(s1+s2); ghost var s1_spec_s2_spec := s1_spec + s2_spec; Lemma_TrIncCounterImplSeqToSpecRelation(s1, s1_spec); Lemma_TrIncCounterImplSeqToSpecRelation(s2, s2_spec); Lemma_TrIncCounterImplSeqToSpecRelation(s12, s12_spec); forall i | 0 <= i < |s1| ensures s1_spec_s2_spec[i] == s12_spec[i]; { calc { s1_spec_s2_spec[i]; s1_spec[i]; s12_spec[i]; } } forall i | |s1| <= i < |s1|+|s2| ensures s1_spec_s2_spec[i] == s12_spec[i]; { calc { s1_spec_s2_spec[i]; (s1_spec + s2_spec)[i]; { Lemma_IndexIntoSequenceConcatenation(s1_spec, s2_spec, i); } s2_spec[i - |s1_spec|]; s2_spec[i - |s1|]; { Lemma_TrIncCounterImplSeqToSpecRelation(s1, s1_spec); Lemma_TrIncCounterImplSeqToSpecRelation(s2, s2_spec); Lemma_TrIncCounterImplSeqToSpecRelation(s12, s12_spec); } s12_spec[i]; } } } //-//////////////////////////////////////////////////////////////////////// //- Implementing TrIncState with TrIncStateImpl //-//////////////////////////////////////////////////////////////////////// datatype TrIncStateImpl = TrIncStateImpl_c(counters:seq); predicate TrIncStateImplValid (trinc_state:TrIncStateImpl) { Word32(|trinc_state.counters|) && TrIncCounterImplSeqValid(trinc_state.counters) } function TrIncStateImplToSpec (s:TrIncStateImpl) : TrIncState requires TrIncStateImplValid(s); { TrIncStateConstructor(TrIncCounterImplSeqToSpec(s.counters)) } lemma Lemma_TrIncStateImplToSpecRelation (s_impl:TrIncStateImpl, s_spec:TrIncState) requires TrIncStateImplValid(s_impl); requires s_spec == TrIncStateImplToSpec(s_impl); ensures |s_spec.counters| == |s_impl.counters|; ensures forall i :: 0 <= i < |s_spec.counters| ==> s_spec.counters[i] == TrIncCounterImplToSpec(s_impl.counters[i]); { Lemma_TrIncCounterImplSeqToSpecRelation(s_impl.counters, s_spec.counters); } lemma Lemma_TrIncStateImplValidImpliesTrIncStateValid (trinc_state:TrIncStateImpl) requires TrIncStateImplValid(trinc_state); ensures TrIncStateValid(TrIncStateImplToSpec(trinc_state)); { Lemma_TrIncStateImplToSpecRelation(trinc_state, TrIncStateImplToSpec(trinc_state)); } lemma Lemma_ConvertStateCounterImpl (state:TrIncStateImpl, i:int) requires TrIncStateImplValid(state); requires 0 <= i < |state.counters|; ensures |TrIncStateImplToSpec(state).counters| == |state.counters|; ensures TrIncCounterImplToSpec(state.counters[i]) == TrIncStateImplToSpec(state).counters[i]; { Lemma_TrIncStateImplToSpecRelation(state, TrIncStateImplToSpec(state)); } lemma Lemma_SplittingOffHeadOfCounterSequence (s:seq, left:int, right:int) requires 0 <= left < right <= |s|; ensures s[left..right] == [s[left]] + s[left+1..right]; { } lemma Lemma_SplittingOffHeadOfTrIncCounterImplSequence (s:seq, left:int, right:int) requires 0 <= left < right <= |s|; ensures s[left..right] == [s[left]] + s[left+1..right]; { } lemma Lemma_ConvertStateCounterImplSeqSubset (state:TrIncStateImpl, left:int, right:int) requires TrIncStateImplValid(state); requires 0 <= left <= right <= |state.counters|; ensures |TrIncStateImplToSpec(state).counters| == |state.counters|; ensures TrIncCounterImplSeqToSpec(state.counters[left..right]) == TrIncStateImplToSpec(state).counters[left..right]; decreases right - left; { ghost var state_spec := TrIncStateImplToSpec(state); Lemma_TrIncStateImplToSpecRelation(state, state_spec); if left < right { calc { TrIncCounterImplSeqToSpec(state.counters[left..right]); { Lemma_SplittingOffHeadOfTrIncCounterImplSequence(state.counters, left, right); Lemma_TrIncCounterImplSeqToSpecConcatenation([state.counters[left]], state.counters[left+1..right]); } TrIncCounterImplSeqToSpec([state.counters[left]] + state.counters[left+1..right]); { Lemma_TrIncCounterImplSeqToSpecConcatenation([state.counters[left]], state.counters[left+1..right]); } TrIncCounterImplSeqToSpec([state.counters[left]]) + TrIncCounterImplSeqToSpec(state.counters[left+1..right]); { Lemma_ConvertStateCounterImplSeqSubset(state, left+1, right); } TrIncCounterImplSeqToSpec([state.counters[left]]) + state_spec.counters[left+1..right]; { Lemma_TrIncCounterImplSeqToSpecOfOne(state.counters[left]); } [TrIncCounterImplToSpec(state.counters[left])] + state_spec.counters[left+1..right]; { Lemma_ConvertStateCounterImpl(state, left); } [state_spec.counters[left]] + state_spec.counters[left+1..right]; { Lemma_SplittingOffHeadOfCounterSequence(state_spec.counters, left, right); } state_spec.counters[left..right]; } } } //-//////////////////////////////////////////////////////////////////////// //- Lemmas //-//////////////////////////////////////////////////////////////////////// lemma Lemma_UpdatingStateEnsuresProperUpdatesToSpec (in_state:TrIncStateImpl, out_state:TrIncStateImpl, in_state_spec:TrIncState, out_state_spec:TrIncState, counter_index:nat, new_counter_value:BigNat) requires TrIncStateImplValid(in_state); requires in_state_spec == TrIncStateImplToSpec(in_state); requires TrIncStateImplValid(out_state); requires out_state_spec == TrIncStateImplToSpec(out_state); requires |in_state_spec.counters| == |in_state.counters|; requires 0 <= counter_index < |in_state.counters|; requires WellformedBigNat(new_counter_value); requires |out_state.counters| == |in_state.counters|; requires forall i :: 0 <= i < |in_state.counters| && i != counter_index ==> out_state.counters[i] == in_state.counters[i]; requires out_state.counters[counter_index].public_key == in_state.counters[counter_index].public_key; requires out_state.counters[counter_index].counter_value == new_counter_value; ensures |in_state_spec.counters| == |out_state_spec.counters|; ensures forall i :: 0 <= i < |in_state.counters| && i != counter_index ==> out_state_spec.counters[i] == in_state_spec.counters[i]; ensures out_state_spec.counters[counter_index].public_key == in_state_spec.counters[counter_index].public_key; ensures out_state_spec.counters[counter_index].counter_value == I(new_counter_value); ensures TrIncStateImplValid(out_state); { Lemma_TrIncStateImplToSpecRelation(in_state, in_state_spec); Lemma_TrIncStateImplToSpecRelation(out_state, out_state_spec); } lemma Lemma_TrIncCounterAdvanceStatementValid (statement:seq, counter_index:nat, old_counter_value:nat, new_counter_value:nat, counter_index_encoding:seq, old_counter_value_encoding:seq, new_counter_value_encoding:seq, message:seq) requires IsByteSeq(message); requires Word32(counter_index); requires old_counter_value < power2(power2(34)); requires new_counter_value < power2(power2(34)); requires counter_index_encoding == rfc4251_word32_encoding(counter_index); requires old_counter_value_encoding == rfc4251_mpint_encoding_premium(old_counter_value); requires new_counter_value_encoding == rfc4251_mpint_encoding_premium(new_counter_value); requires statement == [34] + counter_index_encoding + old_counter_value_encoding + new_counter_value_encoding + message; ensures statement == TrIncCounterAdvanceStatement(counter_index, old_counter_value, new_counter_value, message); ensures IsByteSeq(statement); { lemma_2toX(); reveal_power2(); assert IsByte(34); assert counter_index_encoding == BEWordSeqToByteSeq_premium([counter_index]); assert IsByteSeq(counter_index_encoding); assert IsByteSeq(old_counter_value_encoding); assert IsByteSeq(new_counter_value_encoding); } lemma Lemma_SufficientlySmallMessageCanBeSigned (message:seq) requires IsByteSeq(message); requires |message| <= 0xFFFFFFFF; ensures |message| < power2(61); ensures |BEByteSeqToBitSeq(message)| < power2(64); { calc { |BEByteSeqToBitSeq(message)|; |BEByteSeqToBitSeq_premium(message)|; 8 * |message|; <= 8 * 0xFFFFFFFF; < 0x800000000; < { lemma_2toX(); reveal_power2(); } power2(64); } calc { |message|; <= 0xFFFFFFFF; < { lemma_2toX(); reveal_power2(); } power2(61); } } //-//////////////////////////////////////////////////////////////////////// //- Helpers //-//////////////////////////////////////////////////////////////////////// method CheckClientSignature (public_key:RSAPubKeyImpl, new_counter_value_encoding:seq, message:seq, request_attestation:seq) returns (error_code:int) requires WellformedRSAPubKeyImpl(public_key); requires RSA_DIGEST_MIN_KEY_SIZE() <= public_key.size < power2(60); requires IsByteSeq(new_counter_value_encoding); requires IsByteSeq(message); requires IsByteSeq(request_attestation); requires TPM_ready(); modifies this`TPM; modifies this`IoMemPerm; ensures TPM_ready(); ensures TPM==old(TPM); ensures Word32(error_code); ensures error_code == 0 ==> var request := new_counter_value_encoding + message; |request| < power2(28) && RSAVerificationRelationRequires(PubKeyImplToSpec(public_key), request, request_attestation) && RSAVerificationRelation(PubKeyImplToSpec(public_key), request, request_attestation); requires public(PubKeyImplToSpec(public_key)); requires public(new_counter_value_encoding); requires public(message); requires public(request_attestation); ensures public(error_code); { lemma_2toX32(); var request:seq := new_counter_value_encoding + message; if |request| >= 0x10000000 { error_code := 2; return; } calc { |request|; < 0x10000000; == { reveal_power2(); } power2(28); } Lemma_SufficientlySmallMessageCanBeSigned(request); if |request_attestation| != public_key.size { error_code := 3; return; } var signature_ok := DigestedVerify(public_key, request, request_attestation); if !signature_ok { error_code := 5; return; } error_code := 0; } method CheckAdvanceCounterParameters (in_state:TrIncStateImpl, counter_index:nat, new_counter_value_encoding:seq, message:seq, request_attestation:seq) returns (error_code:int, new_counter_value:BigNat) requires TrIncStateImplValid(in_state); requires IsByteSeq(new_counter_value_encoding); requires IsByteSeq(message); requires IsByteSeq(request_attestation); requires TPM_ready(); modifies this`TPM; modifies this`IoMemPerm; ensures TPM_ready(); ensures TPM==old(TPM); ensures Word32(error_code); ensures WellformedBigNat(new_counter_value); ensures error_code == 0 ==> 0 <= counter_index < |in_state.counters| && ModestBigNatValue(new_counter_value) && I(new_counter_value) < power2(power2(34)) && new_counter_value_encoding == rfc4251_mpint_encoding_premium(I(new_counter_value)) && I(in_state.counters[counter_index].counter_value) <= I(new_counter_value) && WellformedRSAPubKeyImpl(in_state.counters[counter_index].public_key) && RSAVerificationRelationRequires(PubKeyImplToSpec(in_state.counters[counter_index].public_key), new_counter_value_encoding + message, request_attestation) && RSAVerificationRelation(PubKeyImplToSpec(in_state.counters[counter_index].public_key), new_counter_value_encoding + message, request_attestation); requires public(TrIncStateImplToSpec(in_state)); requires public(counter_index); requires public(new_counter_value_encoding); requires public(message); requires public(request_attestation); ensures public(error_code); ensures public(I(new_counter_value)); { Lemma_TrIncStateImplToSpecRelation(in_state, TrIncStateImplToSpec(in_state)); new_counter_value := MakeSmallLiteralBigNat(0); lemma_2toX(); if counter_index < 0 || counter_index >= |in_state.counters| { error_code := 1; return; } error_code := CheckClientSignature(in_state.counters[counter_index].public_key, new_counter_value_encoding, message, request_attestation); if error_code != 0 { return; } var success:bool; var bytes_consumed:int; success, new_counter_value, bytes_consumed := rfc4251_decode_mpint_legacy(new_counter_value_encoding); if !success { error_code := 6; new_counter_value := MakeSmallLiteralBigNat(0); return; } if bytes_consumed != |new_counter_value_encoding| { error_code := 7; new_counter_value := MakeSmallLiteralBigNat(0); return; } assert I(in_state.counters[counter_index].counter_value) == TrIncStateImplToSpec(in_state).counters[counter_index].counter_value; var too_small := BigNatLt(new_counter_value, in_state.counters[counter_index].counter_value); if too_small { error_code := 7; return; } assert I(new_counter_value) >= I(in_state.counters[counter_index].counter_value); var modest := IsModestBigNat(new_counter_value); if !modest { error_code := 8; return; } error_code := 0; } method EncodeAdvanceStatement (in_state:TrIncStateImpl, counter_index:nat, new_counter_value:BigNat, new_counter_value_encoding:seq, message:seq) returns (error_code:int, TrInc_statement:seq, ghost ghost_old_counter_value_encoding:seq) requires TrIncStateImplValid(in_state); requires WellformedBigNat(new_counter_value); requires IsByteSeq(message); requires 0 <= counter_index < |in_state.counters|; requires I(in_state.counters[counter_index].counter_value) <= I(new_counter_value); requires ModestBigNatValue(new_counter_value); requires I(new_counter_value) < power2(power2(34)); requires new_counter_value_encoding == rfc4251_mpint_encoding_premium(I(new_counter_value)); ensures Word32(error_code); ensures ghost_old_counter_value_encoding == rfc4251_mpint_encoding_premium(I(in_state.counters[counter_index].counter_value)); ensures IsByteSeq(TrInc_statement); ensures TrInc_statement == TrIncCounterAdvanceStatement(counter_index, I(in_state.counters[counter_index].counter_value), I(new_counter_value), message); ensures error_code == 0 ==> I(in_state.counters[counter_index].counter_value) < power2(power2(34)) && Word32(|TrInc_statement|) && |TrInc_statement| < power2(28) && |BEByteSeqToBitSeq_premium(TrInc_statement)| < power2(64); requires public(TrIncStateImplToSpec(in_state)); requires public(counter_index); requires public(I(new_counter_value)); requires public(new_counter_value_encoding); requires public(message); ensures public(error_code); ensures public(TrInc_statement); { Lemma_TrIncStateImplToSpecRelation(in_state, TrIncStateImplToSpec(in_state)); lemma_2toX32(); assert KV(in_state.counters[counter_index].counter_value) == I(in_state.counters[counter_index].counter_value); assert KV(in_state.counters[counter_index].counter_value) == TrIncStateImplToSpec(in_state).counters[counter_index].counter_value; var counter_index_encoding := rfc4251_encode_word32(counter_index); var old_counter_value_encoding := rfc4251_encode_mpint_legacy(in_state.counters[counter_index].counter_value); ghost_old_counter_value_encoding := old_counter_value_encoding; TrInc_statement := [34] + counter_index_encoding + old_counter_value_encoding + new_counter_value_encoding + message; Lemma_TrIncCounterAdvanceStatementValid(TrInc_statement, counter_index, I(in_state.counters[counter_index].counter_value), I(new_counter_value), counter_index_encoding, old_counter_value_encoding, new_counter_value_encoding, message); if |TrInc_statement| >= 0x10000000 { error_code := 7; return; } calc { |TrInc_statement|; < 0x10000000; == power2(28); } error_code := 0; assert IsByte(34); assert IsByteSeq(TrInc_statement); Lemma_SufficientlySmallMessageCanBeSigned(TrInc_statement); assert TrInc_statement == TrIncCounterAdvanceStatement(counter_index, TrIncStateImplToSpec(in_state).counters[counter_index].counter_value, I(new_counter_value), message); } method {:dafnycc_conservative_seq_triggers} UpdateStateByModifyingCounterValue (in_state:TrIncStateImpl, ghost in_state_spec:TrIncState, counter_index:nat, new_counter_value:BigNat) returns (out_state:TrIncStateImpl) requires TrIncStateImplValid(in_state); requires in_state_spec == TrIncStateImplToSpec(in_state); requires 0 <= counter_index < |in_state.counters|; requires WellformedBigNat(new_counter_value); requires ModestBigNatValue(new_counter_value); ensures |out_state.counters| == |in_state.counters|; ensures forall i :: 0 <= i < |in_state.counters| && i != counter_index ==> out_state.counters[i] == in_state.counters[i]; ensures out_state.counters[counter_index].public_key == in_state.counters[counter_index].public_key; ensures out_state.counters[counter_index].counter_value == new_counter_value; requires public(in_state_spec); requires public(counter_index); requires public(I(new_counter_value)); ensures public(TrIncStateImplToSpec(out_state)); { Lemma_TrIncCounterImplSeqToSpecRelation(in_state.counters, TrIncCounterImplSeqToSpec(in_state.counters)); var counters:seq := []; var j:int := 0; counters := in_state.counters[..counter_index] + [TrIncCounterImpl_c(in_state.counters[counter_index].public_key, new_counter_value)] + in_state.counters[counter_index+1..]; out_state := TrIncStateImpl_c(counters); calc { TrIncStateImplToSpec(out_state); TrIncStateConstructor(TrIncCounterImplSeqToSpec(out_state.counters)); TrIncStateConstructor(TrIncCounterImplSeqToSpec(counters)); TrIncStateConstructor(TrIncCounterImplSeqToSpec( in_state.counters[..counter_index] + [TrIncCounterImpl_c(in_state.counters[counter_index].public_key, new_counter_value)] + in_state.counters[counter_index+1..])); { Lemma_TrIncCounterImplSeqToSpecConcatenation( in_state.counters[..counter_index] + [TrIncCounterImpl_c(in_state.counters[counter_index].public_key, new_counter_value)], in_state.counters[counter_index+1..]); } TrIncStateConstructor(TrIncCounterImplSeqToSpec( in_state.counters[..counter_index] + [TrIncCounterImpl_c(in_state.counters[counter_index].public_key, new_counter_value)]) + TrIncCounterImplSeqToSpec(in_state.counters[counter_index+1..])); { Lemma_TrIncCounterImplSeqToSpecConcatenation( in_state.counters[..counter_index], [TrIncCounterImpl_c(in_state.counters[counter_index].public_key, new_counter_value)]); } TrIncStateConstructor(TrIncCounterImplSeqToSpec(in_state.counters[..counter_index]) + TrIncCounterImplSeqToSpec([TrIncCounterImpl_c(in_state.counters[counter_index].public_key, new_counter_value)]) + TrIncCounterImplSeqToSpec(in_state.counters[counter_index+1..])); { Lemma_ConvertStateCounterImplSeqSubset(in_state, 0, counter_index); assert in_state.counters[..counter_index] == in_state.counters[0..counter_index]; assert in_state_spec.counters[..counter_index] == in_state_spec.counters[0..counter_index]; } TrIncStateConstructor(in_state_spec.counters[..counter_index] + TrIncCounterImplSeqToSpec([TrIncCounterImpl_c(in_state.counters[counter_index].public_key, new_counter_value)]) + TrIncCounterImplSeqToSpec(in_state.counters[counter_index+1..])); { Lemma_ConvertStateCounterImplSeqSubset(in_state, counter_index+1, |in_state.counters|); assert |in_state.counters| == |in_state_spec.counters|; assert in_state.counters[counter_index+1..] == in_state.counters[counter_index+1..|in_state.counters|]; assert in_state_spec.counters[counter_index+1..] == in_state_spec.counters[counter_index+1..|in_state.counters|]; } TrIncStateConstructor(in_state_spec.counters[..counter_index] + TrIncCounterImplSeqToSpec([TrIncCounterImpl_c(in_state.counters[counter_index].public_key, new_counter_value)]) + in_state_spec.counters[counter_index+1..]); { Lemma_TrIncCounterImplSeqToSpecOfOne(TrIncCounterImpl_c(in_state.counters[counter_index].public_key, new_counter_value)); } TrIncStateConstructor(in_state_spec.counters[..counter_index] + [TrIncCounterImplToSpec(TrIncCounterImpl_c(in_state.counters[counter_index].public_key, new_counter_value))] + in_state_spec.counters[counter_index+1..]); { Lemma_ConvertStateCounterImpl(in_state, counter_index); } TrIncStateConstructor(in_state_spec.counters[..counter_index] + [TrIncCounterConstructor(in_state_spec.counters[counter_index].public_key, I(new_counter_value))] + in_state_spec.counters[counter_index+1..]); } } //-//////////////////////////////////////////////////////////////////////// //- Exported methods //-//////////////////////////////////////////////////////////////////////// method TrIncInitialize () returns (trinc_state:TrIncStateImpl) ensures TrIncStateImplValid(trinc_state); ensures TrIncInitializeValid(TrIncStateImplToSpec(trinc_state)); ensures public(TrIncStateImplToSpec(trinc_state)); { trinc_state := TrIncStateImpl_c([]); //- dafnycc: initialize variable Lemma_TrIncStateImplToSpecRelation(trinc_state, TrIncStateImplToSpec(trinc_state)); } method TrIncCreateCounter (in_state:TrIncStateImpl, common_state:CommonStateImpl, public_key_encoding:seq) returns (out_state:TrIncStateImpl, error_code:int, counter_index:nat) requires TrIncStateImplValid(in_state); requires CommonStateImplValid(common_state); requires IsByteSeq(public_key_encoding); ensures TrIncStateImplValid(out_state); ensures error_code == 0 ==> TrIncCreateCounterValid(TrIncStateImplToSpec(in_state), TrIncStateImplToSpec(out_state), CommonStateImplToSpec(common_state), public_key_encoding, counter_index); ensures error_code != 0 ==> out_state == in_state; ensures Word32(error_code); ensures Word32(counter_index); requires public(TrIncStateImplToSpec(in_state)); requires public(public_key_encoding); ensures public(TrIncStateImplToSpec(out_state)); ensures public(error_code); ensures public(counter_index); { out_state := in_state; counter_index := 0; lemma_2toX(); Lemma_TrIncStateImplToSpecRelation(in_state, TrIncStateImplToSpec(in_state)); if |in_state.counters| >= 0xFFFFFFFF { error_code := 1; return; } if |public_key_encoding| >= 0xFFFFFFFF { error_code := 2; return; } var success, public_key := rfc4251_decode_sshrsa(public_key_encoding); if !success { error_code := 3; return; } assert WellformedRSAPubKeyImpl(public_key); assert WellformedRSAPubKeySpec(PubKeyImplToSpec(public_key)); if public_key.size < RSA_DIGEST_MIN_KEY_SIZE() || public_key.size >= 0xFFFFFFFF { error_code := 4; return; } error_code := 0; var zero := MakeSmallLiteralBigNat(0); var new_counter := TrIncCounterImpl_c(public_key, zero); out_state := TrIncStateImpl_c(in_state.counters + [new_counter]); counter_index := |out_state.counters| - 1; calc { TrIncStateImplToSpec(out_state); TrIncStateConstructor(TrIncCounterImplSeqToSpec(in_state.counters + [new_counter])); { Lemma_TrIncCounterImplSeqToSpecConcatenation(in_state.counters, [new_counter]); } TrIncStateConstructor(TrIncCounterImplSeqToSpec(in_state.counters) + TrIncCounterImplSeqToSpec([new_counter])); { Lemma_TrIncCounterImplSeqToSpecOfOne(new_counter); } TrIncStateConstructor(TrIncCounterImplSeqToSpec(in_state.counters) + [TrIncCounterImplToSpec(new_counter)]); TrIncStateConstructor(TrIncStateImplToSpec(in_state).counters + [TrIncCounterImplToSpec(new_counter)]); TrIncStateConstructor(TrIncStateImplToSpec(in_state).counters + [TrIncCounterConstructor(PubKeyImplToSpec(new_counter.public_key), I(new_counter.counter_value))]); TrIncStateConstructor(TrIncStateImplToSpec(in_state).counters + [TrIncCounterConstructor(PubKeyImplToSpec(new_counter.public_key), 0)]); TrIncStateConstructor(TrIncStateImplToSpec(in_state).counters + [TrIncCounterConstructor(PubKeyImplToSpec(public_key), 0)]); } //- Lemma_TrIncStateImplToSpecRelation(out_state, TrIncStateImplToSpec(out_state)); //- Lemma_TrIncCounterImplSeqToSpecConcatenation(in_state.counters, [new_counter]); assert counter_index == |TrIncStateImplToSpec(out_state).counters| - 1; } method{:dafnycc_conservative_seq_triggers} TrIncAdvanceCounter (in_state:TrIncStateImpl, common_state:CommonStateImpl, counter_index:nat, new_counter_value_encoding:seq, message:seq, request_attestation:seq) returns (out_state:TrIncStateImpl, error_code:int, TrInc_statement:seq, TrInc_attestation:seq) requires TrIncStateImplValid(in_state); requires CommonStateImplValid(common_state); requires RSA_DIGEST_MIN_KEY_SIZE() <= common_state.key_pair.pub.size; requires IsByteSeq(new_counter_value_encoding); requires IsByteSeq(message); requires IsByteSeq(request_attestation); requires TPM_ready(); modifies this`TPM; modifies this`IoMemPerm; ensures TPM==old(TPM); ensures TPM_ready(); ensures TrIncStateImplValid(out_state); ensures error_code == 0 ==> TrIncAdvanceCounterValid(TrIncStateImplToSpec(in_state), TrIncStateImplToSpec(out_state), CommonStateImplToSpec(common_state), counter_index, new_counter_value_encoding, message, request_attestation, TrInc_statement, TrInc_attestation); ensures error_code != 0 ==> out_state == in_state; ensures TrIncStateImplValid(out_state); ensures Word32(error_code); ensures Word32(|TrInc_statement|); ensures Word32(|TrInc_attestation|); ensures IsByteSeq(TrInc_statement); ensures IsByteSeq(TrInc_attestation); requires public(TrIncStateImplToSpec(in_state)); requires public(counter_index); requires public(new_counter_value_encoding); requires public(message); requires public(request_attestation); ensures public(TrIncStateImplToSpec(out_state)); ensures public(error_code); ensures public(TrInc_statement); { out_state := in_state; TrInc_statement := []; TrInc_attestation := []; ghost var in_state_spec := TrIncStateImplToSpec(in_state); Lemma_TrIncStateImplValidImpliesTrIncStateValid(in_state); var new_counter_value:BigNat; error_code, new_counter_value := CheckAdvanceCounterParameters(in_state, counter_index, new_counter_value_encoding, message, request_attestation); if (error_code != 0) { out_state := in_state; return; } ghost var old_counter_value_encoding:seq; error_code, TrInc_statement, old_counter_value_encoding := EncodeAdvanceStatement(in_state, counter_index, new_counter_value, new_counter_value_encoding, message); if (error_code != 0) { out_state := in_state; TrInc_statement := []; return; } TrInc_attestation := DigestedSign(common_state.key_pair, TrInc_statement); out_state := UpdateStateByModifyingCounterValue(in_state, in_state_spec, counter_index, new_counter_value); Lemma_TrIncCounterImplSeqToSpecRelation(in_state.counters, in_state_spec.counters); Lemma_UpdatingStateEnsuresProperUpdatesToSpec(in_state, out_state, in_state_spec, TrIncStateImplToSpec(out_state), counter_index, new_counter_value); Lemma_TrIncStateImplToSpecRelation(out_state, TrIncStateImplToSpec(out_state)); ghost var new_counter_value_int := I(new_counter_value); //- Introduce a witness Dafny needs } ================================================ FILE: ironclad-apps/src/Dafny/Apps/TrInc/TrInc.s.dfy ================================================ include "../../Libraries/Util/be_sequences.s.dfy" include "../../Libraries/Crypto/RSA/RSASpec.s.dfy" include "../../Libraries/Crypto/RSA/rfc4251.s.dfy" include "../Common/CommonState.s.dfy" include "../../Drivers/TPM/tpm-device.s.dfy" //-/////////////////////////////////////////////////// //- Structures //-/////////////////////////////////////////////////// //- Each counter has an RSA public key associated with it; only users //- in possession of the corresponding private key are allowed to //- advance the counter. datatype TrIncCounter = TrIncCounterConstructor(public_key:RSAPubKeySpec, counter_value:nat); datatype TrIncState = TrIncStateConstructor(counters:seq); //-/////////////////////////////////////////////////// //- Helpers //-/////////////////////////////////////////////////// static predicate TrIncStateValid(state:TrIncState) { Word32(|state.counters|) && (forall i :: 0 <= i < |state.counters| ==> WellformedRSAPubKeySpec(state.counters[i].public_key)) } static function {:autoReq} TrIncCounterAdvanceStatement(counter_index:nat, old_counter_value:nat, new_counter_value:nat, message:seq) : seq { [34] /* counter advance */ + rfc4251_word32_encoding(counter_index) + rfc4251_mpint_encoding(old_counter_value) + rfc4251_mpint_encoding(new_counter_value) + message } //-/////////////////////////////////////////////////// //- Specifications for correct method operation //-/////////////////////////////////////////////////// //- This function is used to ensure that TrInc initialization operates correctly. //- It should initialize the counter set to be empty. static predicate {:autoReq} TrIncInitializeValid(state:TrIncState) { |state.counters| == 0 } //- This function is used to ensure that TrIncCreateCounter operates correctly. //- That method is supposed to create a new counter with the given public key. //- It returns the index of the new counter. static predicate {:autoReq} TrIncCreateCounterValid(in_state:TrIncState, out_state:TrIncState, common_state:CommonState, public_key_encoding_in:seq, counter_index_out:nat) requires IsByteSeq(public_key_encoding_in); { TrIncStateValid(out_state) && exists public_key_in:RSAPubKeySpec :: public_key_encoding_in == rfc4251_sshrsa_encoding(public_key_in.e, public_key_in.n) && out_state.counters == in_state.counters + [TrIncCounterConstructor(public_key_in, 0)] && counter_index_out == |in_state.counters| } //- This function is used to ensure that TrIncAdvanceCounter operates //- correctly. That method is supposed to advance the given counter to the //- given new counter value. It should then return an attestation that the //- counter was advanced. static predicate {:autoReq} TrIncAdvanceCounterValid(in_state:TrIncState, out_state:TrIncState, common_state:CommonState, counter_index_in:nat, new_counter_value_encoding_in:seq, message_in:seq, request_attestation_in:seq, TrInc_statement_out:seq, TrInc_attestation_out:seq) requires IsByteSeq(new_counter_value_encoding_in); requires IsByteSeq(message_in); requires IsByteSeq(request_attestation_in); { //- Note that, as in the TrInc paper, it is acceptable to advance the counter to //- the same value that it had before. This is OK because the attestation will //- state the old and new counter values, so the recipient of that attestation //- can't mistake it for a non-zero counter advance. TrIncStateValid(out_state) && exists new_counter_value_in:nat :: //- The parameters are valid 0 <= counter_index_in < |in_state.counters| && new_counter_value_encoding_in == rfc4251_mpint_encoding(new_counter_value_in) && in_state.counters[counter_index_in].counter_value <= new_counter_value_in && WellformedRSAPubKeySpec(in_state.counters[counter_index_in].public_key) && RSAVerificationRelation(in_state.counters[counter_index_in].public_key, new_counter_value_encoding_in + message_in, request_attestation_in) && //- Most of the state stays the same... |out_state.counters| == |in_state.counters| && (forall i :: 0 <= i < |in_state.counters| && i != counter_index_in ==> out_state.counters[i] == in_state.counters[i]) && out_state.counters[counter_index_in].public_key == in_state.counters[counter_index_in].public_key && //- ...except for the counter value for the counter with the given index... out_state.counters[counter_index_in].counter_value == new_counter_value_in && //- ...and an attestation is returned. TrInc_statement_out == TrIncCounterAdvanceStatement(counter_index_in, in_state.counters[counter_index_in].counter_value, new_counter_value_in, message_in) && TrInc_attestation_out == RSASignature(common_state.key_pair, TrInc_statement_out) } ================================================ FILE: ironclad-apps/src/Dafny/Apps/UdpEchoService/UdpEchoService.i.dfy ================================================ include "../../Drivers/Network/Intel/driver.i.dfy" include "../../Libraries/Net/ethernet.i.dfy" include "../../Libraries/Net/IPv4.i.dfy" include "../../Libraries/Net/Udp.i.dfy" include "../../Libraries/Util/integer_sequences.i.dfy" //- //- A simple UDP Echo Service. //- method DebugPrintSequence(Offset:int, Data:seq) requires 0 <= Offset <= 160 - 16; requires IsByteSeq(Data); requires |Data| >= 0; { var Index:int := 0; while (Index < |Data|) decreases |Data| - Index; invariant Index >= 0; invariant Index <= |Data|; { debug_print(Offset, Data[Index]); Index := Index + 1; } } method Main() returns (Result:int) ensures public(true); { lemma_2toX(); Result := 0; var NetUp, net_state := init_network_card(); if NetUp { lemma_2toX(); debug_print(0x90, 0xded0d0d0); var Success:bool := true; var EtherSource:ethernet_addr; var IPSource:IPv4Address; var IPDest:IPv4Address; var SourcePort:int; var DestPort:int; var Data:seq; while (Success) invariant valid_network_state(net_state); invariant public(net_state); invariant public(Success); decreases *; { Success, net_state, EtherSource, IPSource, IPDest, SourcePort, DestPort, Data := UdpReceive(net_state); if (Success) { lemma_2toX(); //- DebugPrintSequence(0x90, Data); debug_print(0x90, 0xdedadada); if (DestPort == 7) { //- //- Port 7 is the Echo Service port. //- Echo the data received back to the sender. //- net_state := UdpSend(net_state, EtherSource, IPDest, IPSource, DestPort, SourcePort, Data); } } else { Result := 0xdeadbeef; debug_print(0x90, 0xdeadbeef); } } } else { Result := 0xdeaddead; debug_print(0x90, 0xdeaddead); } } ================================================ FILE: ironclad-apps/src/Dafny/Apps/apps.dfy.batch ================================================ # This file only activates the apps we want for the paper analysis. # Perhaps we should have another file for the build server to build everything. #src/Dafny/Apps/AppLoader/Main.i.dfy #src/Dafny/Apps/BenchmarkApp/Main.i.dfy src/Dafny/Apps/DafnyCCTest/Main.i.dfy src/Dafny/Apps/DiffPriv/Main.i.dfy src/Dafny/Apps/Notary/Main.i.dfy src/Dafny/Apps/PassHash/Main.i.dfy src/Dafny/Apps/TrInc/Main.i.dfy ================================================ FILE: ironclad-apps/src/Dafny/BuildExceptions.py ================================================ # this file is included by ironmake.py class Exceptions(): def __init__(self): self.flags = {} ############################################################################## ## Add flags here: self.addFlag("Noise.i.dfy", "/z3opt:ARITH_RANDOM_SEED=2") for real_file in ["Noise.s.dfy", "Noise.i.dfy", "BigRat.i.dfy", "DiffPriv.i.dfy", "DiffPrivPerformQuery.i.dfy", "mul_nonlinear.i.dfy", "div_nonlinear.i.dfy"]: self.addFlag(real_file, "/z3opt:NL_ARITH=true") ############################################################################## def addFlag(self, basename, flagstr): # flagstr may contain spaces for multiple flags. self.flags[basename.lower()] = flagstr def __getitem__(self, basename): basename = basename.lower() if (basename in self.flags): print "Exception for %s : %s" % (basename, self.flags[basename]) return self.flags[basename] return "" ================================================ FILE: ironclad-apps/src/Dafny/Drivers/.gitignore ================================================ *.bpl *.log ================================================ FILE: ironclad-apps/src/Dafny/Drivers/CPU/assembly.i.dfy ================================================ //- include "../../Libraries/base.s.dfy" include "../../Libraries/Util/relational.s.dfy" //-include "assembly.s.dfy" //-////////////////////////////////////////////////////// //- You should never need to call these! Please use the //- routines in assembly_premium.i.dfy instead. //- DafnyCC connects these methods to the underlying //- Boogie spec for the corresponding assembly //- instructions. Please do not change them, unless //- you also change the underlying Boogie spec. If //- you need more properties, add them to the Premium //- versions in assembly_premium.dfy //-////////////////////////////////////////////////////// static function {:imported} IntBit(index:int, val:int):bool static lemma{:decl} lemma_IntBit(index:int, val:int) ensures word32(val) && 0 <= index < 32 ==> IntBit(index, val) == if (index < 31) then IntBit(index + 1, val / 2) else val % 2 != 0; //- Undefined. Mapped to Boogie's word32 static function{:imported} word32(x:int):bool static lemma{:decl} lemma_word32(x:int) ensures word32(x) <==> 0 <= x < 0x100000000; static function{:imported} mod0x100000000(x:int):int static lemma{:decl} lemma_mod0x100000000(x:int) ensures mod0x100000000(x) == x % 0x100000000; static method{:decl}{:dafnycc_heap_unmodified}{:instruction "out@EDX", "inout@EAX", "in"}{:strict_operands} method_Mul(x:int, y:int) returns(hi:int, r:int) ensures r == x * y; static method{:decl}{:dafnycc_heap_unmodified}{:instruction "inout@EDX", "inout@EAX", "in"}{:strict_operands} method_DivMod(zero:int, x:int, y:int) returns(m:int, d:int) requires zero == 0; requires y != 0; ensures d == x / y; ensures m == x % y; static function method{:imported}{:instruction "inout", "in"} asm_Add(x:int, y:int):int requires word32(x); requires word32(y); ensures word32(asm_Add(x, y)); ensures asm_Add(x, y) == mod0x100000000(x + y); static function method{:imported}{:instruction "inout", "in"} asm_Sub(x:int, y:int):int requires word32(x); requires word32(y); ensures word32(asm_Sub(x, y)); ensures asm_Sub(x, y) == mod0x100000000(x - y); static function method{:imported} asm_Mul(x:int, y:int):int requires word32(x); requires word32(y); ensures word32(asm_Mul(x, y)); ensures asm_Mul(x, y) == mod0x100000000(x * y); static method{:imported}{:instruction "out@EDX", "inout@EAX", "in"}{:strict_operands} asm_Mul64(x:int, y:int) returns (hi:int, lo:int) requires word32(x); requires word32(y); ensures word32(hi); ensures word32(lo); ensures lo == mod0x100000000(x * y); ensures hi == (x * y) / 0x100000000; static function method{:imported} asm_Div(x:int, y:int):int requires word32(x); requires word32(y); requires y > 0; ensures word32(asm_Div(x, y)); ensures asm_Div(x, y) == mod0x100000000(x / y); static function method{:imported} asm_Mod(x:int, y:int):int requires word32(x); requires word32(y); requires y > 0; ensures word32(asm_Mod(x, y)); ensures asm_Mod(x, y) == x % y; static function method{:imported}{:instruction "inout", "in@ECX"} asm_LeftShift(x:int, amount:int):int requires word32(x); requires 0 <= amount < 32; ensures word32(asm_LeftShift(x, amount)); ensures forall i {:trigger IntBit(i, asm_LeftShift(x, amount))} :: 32 - amount <= i < 32 ==> IntBit(i, asm_LeftShift(x, amount)) == false; ensures forall i {:trigger IntBit(i, asm_LeftShift(x, amount))} :: 0 <= i < 32 - amount ==> IntBit(i, asm_LeftShift(x, amount)) == IntBit(i + amount, x); static function method{:imported}{:instruction "inout", "in@ECX"} asm_RightShift(x:int, amount:int):int requires word32(x); requires 0 <= amount < 32; ensures word32(asm_RightShift(x, amount)); ensures forall i {:trigger IntBit(i, asm_RightShift(x, amount))} :: 0 <= i < amount ==> IntBit(i, asm_RightShift(x, amount)) == false; ensures forall i {:trigger IntBit(i, asm_RightShift(x, amount))} :: amount <= i < 32 ==> IntBit(i, asm_RightShift(x, amount)) == IntBit(i - amount, x); static function method{:imported}{:instruction "inout", "in@ECX"} asm_RotateLeft(x:int, amount:int):int requires word32(x); requires 0 <= amount < 32; ensures word32(asm_RotateLeft(x, amount)); ensures forall i {:trigger IntBit(i, asm_RotateLeft(x, amount))} :: 0 <= i < 32 - amount ==> IntBit(i, asm_RotateLeft(x, amount)) == IntBit(i + amount, x); ensures forall i {:trigger IntBit(i, asm_RotateLeft(x, amount))} :: 32 - amount <= i < 32 ==> IntBit(i, asm_RotateLeft(x, amount)) == IntBit(i - (32 - amount), x); static function method{:imported}{:instruction "inout", "in@ECX"} asm_RotateRight(x:int, amount:int):int requires word32(x); requires 0 <= amount < 32; ensures word32(asm_RotateRight(x, amount)); ensures forall i {:trigger IntBit(i, asm_RotateRight(x, amount))} :: 0 <= i < amount ==> IntBit(i, asm_RotateRight(x, amount)) == IntBit((32 - amount)+i, x); ensures forall i {:trigger IntBit(i, asm_RotateRight(x, amount))} :: amount <= i < 32 ==> IntBit(i, asm_RotateRight(x, amount)) == IntBit(i - amount, x); static function method{:imported}{:instruction "inout"} asm_BitwiseNot(x:int):int requires word32(x); ensures word32(asm_BitwiseNot(x)); ensures forall i {:trigger IntBit(i, asm_BitwiseNot(x))} :: 0 <= i < 32 ==> IntBit(i, asm_BitwiseNot(x)) == !IntBit(i, x); static function method{:imported}{:instruction "inout", "in"} asm_BitwiseAnd(x:int, y:int):int requires word32(x); requires word32(y); ensures word32(asm_BitwiseAnd(x, y)); ensures forall i {:trigger IntBit(i, asm_BitwiseAnd(x, y))} :: 0 <= i < 32 ==> IntBit(i, asm_BitwiseAnd(x, y)) == (IntBit(i, x) && IntBit(i, y)); static function method{:imported}{:instruction "inout", "in"} asm_BitwiseOr(x:int, y:int):int requires word32(x); requires word32(y); ensures word32(asm_BitwiseOr(x, y)); ensures forall i {:trigger IntBit(i, asm_BitwiseOr(x, y))} :: 0 <= i < 32 ==> IntBit(i, asm_BitwiseOr(x, y)) == (IntBit(i, x) || IntBit(i, y)); static function method{:imported}{:instruction "inout", "in"} asm_BitwiseXor(x:int, y:int):int requires word32(x); requires word32(y); ensures word32(asm_BitwiseXor(x, y)); ensures forall i {:trigger IntBit(i, asm_BitwiseXor(x, y))} :: 0 <= i < 32 ==> IntBit(i, asm_BitwiseXor(x, y)) == (IntBit(i, x) != IntBit(i, y)); static method{:decl} asm_Rdtsc() returns (high:int, low:int) ensures word32(high); ensures word32(low); method{:decl} asm_declassify_result(concrete:int, ghost result:int) returns (pub_result:int) requires word32(concrete); requires relation(declassified(left(result), right(result), left(concrete), right(concrete))); ensures pub_result == result; ensures public(pub_result); static method{:decl} GetBootloaderArgWord(index:int) returns (word:int) requires 0 <= index < 256; ensures word32(word); ================================================ FILE: ironclad-apps/src/Dafny/Drivers/CPU/assembly.s.dfy ================================================ include "../../Libraries/Util/bytes_and_words.s.dfy" include "../../Libraries/Util/be_sequences.s.dfy" //-///////////////////////////////////////////// //- Abstract definitions of 32-bit operations //- that we may want to talk about in specs //-///////////////////////////////////////////// static function UndefinedBit(index:int, val:int):bool static function IntBit_spec(index:int, val:int):bool { var bits := BEWordToBitSeq(val); if 0 <= index < |bits| then bits[index] == 1 else UndefinedBit(index, val) } //-static lemma{:decl} lemma_IntBit_spec(index:int, val:int) //- ensures Word32(val) && 0 <= index < 32 ==> //- IntBit_spec(index, val) == if (index < 31) then IntBit_spec(index + 1, val / 2) else val % 2 != 0; static function{:axiom} BitwiseAnd(x:int, y:int) : int requires Word32(x); requires Word32(y); ensures Word32(BitwiseAnd(x, y)); ensures forall i {:trigger IntBit_spec(i, BitwiseAnd(x, y))} :: 0 <= i < 32 ==> IntBit_spec(i, BitwiseAnd(x, y)) == (IntBit_spec(i, x) && IntBit_spec(i, y)); static function{:axiom} BitwiseOr(x:int, y:int):int requires Word32(x); requires Word32(y); ensures Word32(BitwiseOr(x, y)); ensures forall i {:trigger IntBit_spec(i, BitwiseOr(x, y))} :: 0 <= i < 32 ==> IntBit_spec(i, BitwiseOr(x, y)) == (IntBit_spec(i, x) || IntBit_spec(i, y)); static function{:axiom} BitwiseNot(x:int) : int requires Word32(x); ensures Word32(BitwiseNot(x)); ensures forall i {:trigger IntBit_spec(i, BitwiseNot(x))} :: 0 <= i < 32 ==> IntBit_spec(i, BitwiseNot(x)) == !IntBit_spec(i, x); static function{:axiom} BitwiseXor(x:int, y:int) : int requires Word32(x); requires Word32(y); ensures Word32(BitwiseXor(x, y)); ensures forall i {:trigger IntBit_spec(i, BitwiseXor(x, y))} :: 0 <= i < 32 ==> IntBit_spec(i, BitwiseXor(x, y)) == (IntBit_spec(i, x) != IntBit_spec(i, y)); static function{:axiom} RotateRight(x:int, amount:int) : int requires Word32(x); requires 0 <= amount < 32; ensures Word32(RotateRight(x, amount)); ensures forall i {:trigger IntBit_spec(i, RotateRight(x, amount))} :: 0 <= i < amount ==> IntBit_spec(i, RotateRight(x, amount)) == IntBit_spec((32 - amount)+i, x); ensures forall i {:trigger IntBit_spec(i, RotateRight(x, amount))} :: amount <= i < 32 ==> IntBit_spec(i, RotateRight(x, amount)) == IntBit_spec(i - amount, x); static function{:axiom} RotateLeft(x:int, amount:int):int requires Word32(x); requires 0 <= amount < 32; ensures Word32(RotateLeft(x, amount)); ensures forall i {:trigger IntBit_spec(i, RotateLeft(x, amount))} :: 0 <= i < 32 - amount ==> IntBit_spec(i, RotateLeft(x, amount)) == IntBit_spec(i + amount, x); ensures forall i {:trigger IntBit_spec(i, RotateLeft(x, amount))} :: 32 - amount <= i < 32 ==> IntBit_spec(i, RotateLeft(x, amount)) == IntBit_spec(i - (32 - amount), x); static function{:axiom} RightShift(x:int, amount:int) : int requires Word32(x); requires 0 <= amount < 32; ensures Word32(RightShift(x, amount)); ensures forall i {:trigger IntBit_spec(i, RightShift(x, amount))} :: 0 <= i < amount ==> IntBit_spec(i, RightShift(x, amount)) == false; ensures forall i {:trigger IntBit_spec(i, RightShift(x, amount))} :: amount <= i < 32 ==> IntBit_spec(i, RightShift(x, amount)) == IntBit_spec(i - amount, x); static function{:axiom} LeftShift(x:int, amount:int):int requires Word32(x); requires 0 <= amount < 32; ensures Word32(LeftShift(x, amount)); ensures forall i {:trigger IntBit_spec(i, LeftShift(x, amount))} :: 32 - amount <= i < 32 ==> IntBit_spec(i, LeftShift(x, amount)) == false; ensures forall i {:trigger IntBit_spec(i, LeftShift(x, amount))} :: 0 <= i < 32 - amount ==> IntBit_spec(i, LeftShift(x, amount)) == IntBit_spec(i + amount, x); static function{:axiom} Add32(x:int, y:int):int requires Word32(x); requires Word32(y); ensures Word32(Add32(x, y)); ensures Add32(x, y) == (x + y) % 0x100000000; static function{:axiom} Sub32(x:int, y:int):int requires Word32(x); requires Word32(y); ensures Word32(Sub32(x, y)); ensures Sub32(x, y) == (x - y) % 0x100000000; static function{:axiom} Mul32(x:int, y:int):int requires Word32(x); requires Word32(y); ensures Word32(Mul32(x, y)); ensures Mul32(x, y) == (x * y) % 0x100000000; static function{:axiom} Div32(x:int, y:int):int requires Word32(x); requires Word32(y); requires y != 0; ensures Word32(Div32(x, y)); ensures Div32(x, y) == (x / y) % 0x100000000; static function{:axiom} Mod32(x:int, y:int):int requires Word32(x); requires Word32(y); requires y != 0; ensures Word32(Mod32(x, y)); ensures Mod32(x, y) == (x / y) % 0x100000000; //-////////////////////////////////////////////////////////////// //- Versions with bodies //-////////////////////////////////////////////////////////////// /* static function BitwiseNot(x:int) : int requires Word32(x); //-ensures Word32(BitwiseNot(x)); { BitwiseNot_helper(x, 32) } static function BitwiseNot_helper(x:int, bits:int) : int { if bits <= 0 then 0 else 2*BitwiseNot_helper(x, bits - 1) + (1 - (x % 2)) } static function BitwiseAnd(x:int, y:int) : int requires Word32(x); requires Word32(y); //-ensures Word32(BitwiseAnd(x, y)); { BitwiseAnd_helper(x, y, 32) } static function BitwiseAnd_helper(x:int, y:int, bits:int) : int { if bits <= 0 then 0 else 2*BitwiseAnd_helper(x, y, bits - 1) + if (x % 2) == 1 && (y % 2) == 1 then 1 else 0 } */ /* static function BitwiseNot(x:int) : int requires Word32(x); ensures Word32(BitwiseNot(x)); { BEBitSeqToInt(BitwiseNot_helper(x, 32)) } static function BitwiseNot_helper(x:int, bits:int) : seq { if bits <= 0 then [] else BitwiseNot_helper(x, bits - 1) + [(1 - BEWordToBitSeq(x)[bits-1])] } */ /* static function BitwiseNot(x:int) : int requires Word32(x); ensures Word32(BitwiseNot(x)); { var z :| Word32(z) && forall i :: 0 <= i < 32 ==> BEWordToBitSeq(z)[i] == 1 - BEWordToBitSeq(x)[i]; z } static function BitwiseAnd(x:int, y:int) : int requires Word32(x); requires Word32(y); ensures Word32(BitwiseAnd(x, y)); { var z :| Word32(z) && forall i :: 0 <= i < 32 ==> BEWordToBitSeq(z)[i] == if BEWordToBitSeq(x)[i] == 1 && BEWordToBitSeq(y)[i] == 1 then 1 else 0; z } static function BitwiseXor(x:int, y:int) : int requires Word32(x); requires Word32(y); ensures Word32(BitwiseXor(x, y)); { var z :| Word32(z) && forall i :: 0 <= i < 32 ==> BEWordToBitSeq(z)[i] == if BEWordToBitSeq(x)[i] != BEWordToBitSeq(y)[i] then 1 else 0; z } static function RotateRight(x:int, amount:int) : int requires Word32(x); requires 0 <= amount < 32; ensures Word32(RotateRight(x, amount)); { var z :| Word32(z) && forall i :: 0 <= i < 32 ==> BEWordToBitSeq(z) == BEWordToBitSeq(x)[32-amount..] + BEWordToBitSeq(x)[..32-amount]; z } static function RotateLeft(x:int, amount:int):int requires Word32(x); requires 0 <= amount < 32; ensures Word32(RotateLeft(x, amount)); { var z :| Word32(z) && forall i :: 0 <= i < 32 ==> BEWordToBitSeq(z) == BEWordToBitSeq(x)[amount..] + BEWordToBitSeq(x)[..amount]; z } static function RightShift(x:int, amount:int) : int requires Word32(x); requires 0 <= amount < 32; ensures Word32(RightShift(x, amount)); { var z :| Word32(z) && forall i :: 0 <= i < 32 ==> BEWordToBitSeq(z) == RepeatDigit(0, amount) + BEWordToBitSeq(x)[..32-amount]; z } static function LeftShift(x:int, amount:int):int requires Word32(x); requires 0 <= amount < 32; ensures Word32(LeftShift(x, amount)); { var z :| Word32(z) && forall i :: 0 <= i < 32 ==> BEWordToBitSeq(z) == BEWordToBitSeq(x)[amount..] + RepeatDigit(0, amount); z } static function Add32(x:int, y:int):int requires Word32(x); requires Word32(y); ensures Word32(Add32(x, y)); { (x + y) % 0x100000000 } */ /* //- Undefined. Mapped to Boogie's word32 static function{:imported} word32(x:int):bool static lemma{:imported} lemma_word32(x:int) ensures word32(x) <==> 0 <= x < 0x100000000; static function{:imported} mod0x100000000(x:int):int static lemma{:imported} lemma_mod0x100000000(x:int) ensures mod0x100000000(x) == x % 0x100000000; static function{:imported} IntBit_spec(index:int, n:int):bool static lemma{:imported} lemma_IntBit_spec(index:int, n:int) ensures IntBit_spec(index, n) == if (index > 0) then IntBit_spec(index - 1, n / 2) else n % 2 != 0; static method{:imported} method_Mul(x:int, y:int) returns(r:int) ensures r == x * y; static method{:imported} method_Div(x:int, y:int) returns(r:int) requires y != 0; ensures r == x / y; static method{:imported} method_Mod(x:int, y:int) returns(r:int) requires y != 0; ensures r == x % y; static function method{:imported} asm_Add(x:int, y:int):int requires word32(x); requires word32(y); ensures word32(asm_Add(x, y)); ensures asm_Add(x, y) == mod0x100000000(x + y); static function method{:imported} asm_Sub(x:int, y:int):int requires word32(x); requires word32(y); ensures word32(asm_Sub(x, y)); ensures asm_Sub(x, y) == mod0x100000000(x - y); static function method{:imported} asm_Mul(x:int, y:int):int requires word32(x); requires word32(y); ensures word32(asm_Mul(x, y)); ensures asm_Mul(x, y) == mod0x100000000(x * y); static function method{:imported} asm_Div(x:int, y:int):int requires word32(x); requires word32(y); requires y > 0; ensures word32(asm_Div(x, y)); ensures asm_Div(x, y) == mod0x100000000(x * y); static function method{:imported} asm_Mod(x:int, y:int):int requires word32(x); requires word32(y); requires y > 0; ensures word32(asm_Mod(x, y)); ensures asm_Mod(x, y) == x % y; static function method{:imported} asm_LeftShift(x:int, amount:int):int requires word32(x); requires 0 <= amount < 32; ensures word32(asm_LeftShift(x, amount)); ensures forall i {:trigger IntBit_spec(i, asm_LeftShift(x, amount))} :: 0 <= i < amount ==> IntBit_spec(i, asm_LeftShift(x, amount)) == false; ensures forall i {:trigger IntBit_spec(i, asm_LeftShift(x, amount))} :: amount <= i < 32 ==> IntBit_spec(i, asm_LeftShift(x, amount)) == IntBit_spec(i - amount, x); static function method{:imported} asm_RightShift(x:int, amount:int):int requires word32(x); requires 0 <= amount < 32; ensures word32(asm_RightShift(x, amount)); ensures forall i {:trigger IntBit_spec(i, asm_RightShift(x, amount))} :: 0 <= i < 32 - amount ==> IntBit_spec(i, asm_RightShift(x, amount)) == IntBit_spec(i + amount, x); ensures forall i {:trigger IntBit_spec(i, asm_RightShift(x, amount))} :: 32 - amount <= i < 32 ==> IntBit_spec(i, asm_RightShift(x, amount)) == false; static function method{:imported} asm_RotateLeft(x:int, amount:int):int requires word32(x); requires 0 <= amount < 32; ensures word32(asm_RotateLeft(x, amount)); ensures forall i {:trigger IntBit_spec(i, asm_RotateLeft(x, amount))} :: 0 <= i < amount ==> IntBit_spec(i, asm_RotateLeft(x, amount)) == IntBit_spec(i + 32 - amount, x); ensures forall i {:trigger IntBit_spec(i, asm_RotateLeft(x, amount))} :: amount <= i < 32 ==> IntBit_spec(i, asm_RotateLeft(x, amount)) == IntBit_spec(i - amount, x); static function method{:imported} asm_RotateRight(x:int, amount:int):int requires word32(x); requires 0 <= amount < 32; ensures word32(asm_RotateRight(x, amount)); ensures forall i {:trigger IntBit_spec(i, asm_RotateRight(x, amount))} :: 0 <= i < 32 - amount ==> IntBit_spec(i, asm_RotateRight(x, amount)) == IntBit_spec(i + amount, x); ensures forall i {:trigger IntBit_spec(i, asm_RotateRight(x, amount))} :: 32 - amount <= i < 32 ==> IntBit_spec(i, asm_RotateRight(x, amount)) == IntBit_spec(i + amount-32, x); static function method{:imported} asm_BitwiseNot(x:int):int requires word32(x); ensures word32(asm_BitwiseNot(x)); ensures forall i {:trigger IntBit_spec(i, asm_BitwiseNot(x))} :: 0 <= i < 32 ==> IntBit_spec(i, asm_BitwiseNot(x)) == !IntBit_spec(i, x); static function method{:imported} asm_BitwiseAnd(x:int, y:int):int requires word32(x); requires word32(y); ensures word32(asm_BitwiseAnd(x, y)); ensures forall i {:trigger IntBit_spec(i, asm_BitwiseAnd(x, y))} :: 0 <= i < 32 ==> IntBit_spec(i, asm_BitwiseAnd(x, y)) == (IntBit_spec(i, x) && IntBit_spec(i, y)); static function method{:imported} asm_BitwiseOr(x:int, y:int):int requires word32(x); requires word32(y); ensures word32(asm_BitwiseOr(x, y)); ensures forall i {:trigger IntBit_spec(i, asm_BitwiseOr(x, y))} :: 0 <= i < 32 ==> IntBit_spec(i, asm_BitwiseOr(x, y)) == (IntBit_spec(i, x) || IntBit_spec(i, y)); static function method{:imported} asm_BitwiseXor(x:int, y:int):int requires word32(x); requires word32(y); ensures word32(asm_BitwiseXor(x, y)); ensures forall i {:trigger IntBit_spec(i, asm_BitwiseXor(x, y))} :: 0 <= i < 32 ==> IntBit_spec(i, asm_BitwiseXor(x, y)) == (IntBit_spec(i, x) != IntBit_spec(i, y)); */ ================================================ FILE: ironclad-apps/src/Dafny/Drivers/CPU/assembly_premium.i.dfy ================================================ //- include "../../Libraries/Util/bytes_and_words.s.dfy" include "../../Libraries/Util/be_sequences.s.dfy" include "../../Libraries/Util/integer_sequences_premium.i.dfy" include "assembly.i.dfy" //-//////////////////////////////////////////////////////////// //- Upscale wrappers around the basic assembly instructions //- that Boogie exposes via assembly.i.dfy //-//////////////////////////////////////////////////////////// //-///////////////// Helpers //////////////////////////////// static lemma lemma_word32_Word32() ensures forall x:int {:trigger word32(x)} :: word32(x) == Word32(x); { forall x:int ensures word32(x) == Word32(x); { lemma_word32(x); lemma_power2_32(); } } static lemma lemma_IntBit_is_BEWordToBitSeq() ensures forall x, i :: Word32(x) && 0 <= i < 32 ==> (IntBit(i, x) <==> (BEWordToBitSeq_premium(x)[i] == 1)); ensures forall x, i :: Word32(x) && 0 <= i < 32 ==> (!IntBit(i, x) <==> (BEWordToBitSeq_premium(x)[i] == 0)); { forall x, i | Word32(x) && 0 <= i < 32 ensures IntBit(i, x) <==> (BEWordToBitSeq_premium(x)[i] == 1); ensures !IntBit(i, x) <==> (BEWordToBitSeq_premium(x)[i] == 0); { lemma_IntBit(i, x); lemma_IntBit_is_BEWordToBitSeq_specific(i, x); } } static lemma lemma_IntBit_is_IntBit_spec() ensures forall x, i :: Word32(x) && 0 <= i < 32 ==> IntBit(i, x) == IntBit_spec(i, x); { lemma_IntBit_is_BEWordToBitSeq(); } static lemma lemma_IntBit_is_BEWordToBitSeq_specific(index:int, x:int) requires 0 <= index < 32; requires Word32(x); ensures IntBit(index, x) <== (BEWordToBitSeq_premium(x)[index] == 1); ensures IntBit(index, x) ==> (BEWordToBitSeq_premium(x)[index] == 1); decreases 32 - index; { lemma_IntBit(index, x); lemma_word32(x); lemma_2toX(); calc { BEWordToBitSeq_premium(x); BEIntToDigitSeq(power2(1), 32, x); { reveal_power2(); } BEIntToDigitSeq(2, 32, x); BEIntToDigitSeq_private(2, 32, x); { reveal_BEIntToDigitSeq_private(); } BEIntToDigitSeq_private(2, 32-1, x/2) + [ x % 2]; } if (index == 31) { lemma_2toX(); calc { power(2, 31); { lemma_power2_is_power_2_general(); } power2(31); { lemma_power2_adds(24, 7); lemma_power2_adds(3, 4); reveal_power2(); } 0x80000000; } lemma_BEIntToDigitSeq_private_properties(2, 31, x/2); } else { lemma_IntBit_is_BEWordToBitSeq_specific(index + 1, x/2); assert IntBit(index, x) == IntBit(index + 1, x/2); assert IntBit(index + 1, x/2) ==> BEWordToBitSeq_premium(x/2)[index+1] == 1; calc { BEWordToBitSeq_premium(x/2)[index+1]; BEIntToDigitSeq_private(power2(1), 32, x/2)[index+1]; { lemma_power2_1_is_2(); } BEIntToDigitSeq_private(2, 32, x/2)[index+1]; { lemma_index_shift(index, x); } BEIntToDigitSeq_private(2, 32-1, x/2)[index]; BEWordToBitSeq_premium(x)[index]; } } } static lemma lemma_index_shift(index:int, x:int) requires 0 <= index < 31; requires Word32(x); ensures |BEIntToDigitSeq_private(2, 32, x/2)| == 32; //- To assuage function precondition below ensures |BEIntToDigitSeq_private(2, 32-1, x/2)| == 31; //- To assuage function precondition below ensures BEIntToDigitSeq_private(2, 32, x/2)[index+1] == BEIntToDigitSeq_private(2, 32-1, x/2)[index]; { reveal_power2(); var y := x/2; assert y < power2(31); lemma_power2_is_power_2(31); lemma_power2_increases(31,32); lemma_power2_is_power_2(32); lemma_BEIntToDigitSeq_private_properties(2, 32, y); assert |BEIntToDigitSeq_private(2, 32, x/2)| == 32; lemma_BEIntToDigitSeq_private_properties(2, 31, y); assert |BEIntToDigitSeq_private(2, 32-1, x/2)| == 31; calc { BEIntToDigitSeq_private(2, 32, y); BEIntToDigitSeq_private(power2(1), 32, y); { lemma_mul_is_mul_boogie(1,31); lemma_mul_is_mul_boogie(1,32); lemma_BEIntToDigitSeq_private_chop(1, 32, 31, y); } BEIntToDigitSeq_private(power2(1), 32-31, y/power2(1*31)) + BEIntToDigitSeq_private(power2(1), 31, y%power2(1*31)); { lemma_small_mod(y, power2(31)); } BEIntToDigitSeq_private(power2(1), 32-31, y/power2(1*31)) + BEIntToDigitSeq_private(2, 31, y); { lemma_small_div(); } BEIntToDigitSeq_private(2, 1, 0) + BEIntToDigitSeq_private(2, 31, y); { reveal_BEIntToDigitSeq_private(); lemma_small_div(); lemma_small_mod(0, 2); } [0] + BEIntToDigitSeq_private(2, 31, y); } assert BEIntToDigitSeq_private(2, 32, y)[index+1] == BEIntToDigitSeq_private(2, 31, y)[index]; } static lemma lemma_bits_match_implies_ints_match_general() ensures forall x, y :: Word32(x) && Word32(y) && (forall i :: 0 <= i < 32 ==> IntBit(i, x) == IntBit(i, y)) ==> x == y; { forall x, y | Word32(x) && Word32(y) && (forall i :: 0 <= i < 32 ==> IntBit(i, x) == IntBit(i, y)) ensures x == y; { lemma_bits_match_implies_ints_match(x, y); } } static lemma lemma_bits_match_implies_ints_match(x:int, y:int) requires Word32(x) && Word32(y); requires forall i :: 0 <= i < 32 ==> IntBit(i, x) == IntBit(i, y); ensures x == y; { var xb := BEWordToBitSeq_premium(x); var yb := BEWordToBitSeq_premium(y); assert |xb| == |yb| == 32; forall i | 0 <= i < 32 ensures xb[i] == yb[i]; { calc { xb[i] == 1; { lemma_IntBit_is_BEWordToBitSeq(); } IntBit(i, x); IntBit(i, y); { lemma_IntBit_is_BEWordToBitSeq(); } yb[i] == 1; } } assert xb == yb; calc { x; BEBitSeqToInt(xb); BEBitSeqToInt(yb); y; } } //-static lemma lemma_bits_match_implies_ints_match_helper(x:int, y:int, index:int) //- requires Word32(x) && Word32(y); //- requires forall i :: 0 <= i < 32 ==> IntBit(i, x) == IntBit(i, y); //-///////////////// Methods //////////////////////////////// static method{:instruction "out@EDX", "inout@EAX", "in"}{:strict_operands} Method_Mul(x:int, y:int) returns(hi:int, r:int) ensures r == x * y; { lemma_mul_is_mul_boogie(x, y); hi, r := method_Mul(x, y); } static method{:instruction "inout@EDX", "inout@EAX", "in"}{:strict_operands} Method_DivMod(zero:int, x:int, y:int) returns(m:int, r:int) requires zero == 0; requires y != 0; ensures r == x / y; ensures y > 0 ==> m == x % y; { lemma_div_is_div_boogie(x, y); if (y > 0) { lemma_mod_is_mod_boogie(x, y); } m, r := method_DivMod(zero, x, y); } static function method{:instruction "inout", "in"} Asm_Add(x:int, y:int):int requires Word32(x); requires Word32(y); ensures Word32(Asm_Add(x, y)); ensures Asm_Add(x, y) == mod0x100000000(x + y); ensures Asm_Add(x, y) == Add32(x, y); { lemma_word32_Word32(); lemma_mod0x100000000(x+y); asm_Add(x, y) } static function method{:instruction "inout", "in"} Asm_Sub(x:int, y:int):int requires Word32(x); requires Word32(y); ensures Word32(Asm_Sub(x, y)); ensures Asm_Sub(x, y) == mod0x100000000(x - y); { lemma_word32_Word32(); lemma_mod0x100000000(x-y); asm_Sub(x, y) } static function method Asm_Mul(x:int, y:int):int requires Word32(x); requires Word32(y); ensures Word32(Asm_Mul(x, y)); ensures Asm_Mul(x, y) == mod0x100000000(x*y); { lemma_word32_Word32(); lemma_mod0x100000000(x*y); asm_Mul(x, y) } static function method Asm_Div(x:int, y:int):int requires Word32(x); requires Word32(y); requires y > 0; ensures Word32(Asm_Div(x, y)); ensures Asm_Div(x, y) == mod0x100000000(x/y); { lemma_word32_Word32(); lemma_mod0x100000000(x/y); asm_Div(x, y) } static function method Asm_Mod(x:int, y:int):int requires Word32(x); requires Word32(y); requires y > 0; ensures Word32(Asm_Mod(x, y)); ensures Asm_Mod(x, y) == x % y; { lemma_word32_Word32(); lemma_mod0x100000000(x%y); asm_Mod(x, y) } static function method{:instruction "inout", "in@ECX"} Asm_LeftShift(x:int, amount:int):int requires Word32(x); requires 0 <= amount < 32; ensures Word32(Asm_LeftShift(x, amount)); ensures |BEWordToBitSeq_premium(x)| == 32; ensures BEWordToBitSeq_premium(Asm_LeftShift(x, amount)) == BEWordToBitSeq_premium(x)[amount..] + RepeatDigit_premium(0, amount); ensures Asm_LeftShift(x, amount) == LeftShift(x, amount); //- Fulfills spec { lemma_word32_Word32(); lemma_IntBit_is_BEWordToBitSeq(); lemma_bits_match_implies_ints_match_general(); lemma_IntBit_is_IntBit_spec(); asm_LeftShift(x, amount) } static function method{:instruction "inout", "in@ECX"} Asm_RightShift(x:int, amount:int):int requires Word32(x); requires 0 <= amount < 32; ensures Word32(Asm_RightShift(x, amount)); ensures |BEWordToBitSeq(x)| == 32; ensures BEWordToBitSeq_premium(Asm_RightShift(x, amount)) == RepeatDigit_premium(0, amount) + BEWordToBitSeq_premium(x)[..32-amount]; ensures Asm_RightShift(x, amount) == RightShift(x, amount); //- Fulfills spec { lemma_word32_Word32(); lemma_IntBit_is_BEWordToBitSeq(); lemma_bits_match_implies_ints_match_general(); lemma_IntBit_is_IntBit_spec(); asm_RightShift(x, amount) } static function method{:instruction "inout", "in@ECX"} Asm_RotateLeft(x:int, amount:int):int requires Word32(x); requires 0 <= amount < 32; ensures Word32(Asm_RotateLeft(x, amount)); ensures |BEWordToBitSeq(x)| == 32; ensures BEWordToBitSeq_premium(Asm_RotateLeft(x, amount)) == BEWordToBitSeq_premium(x)[amount..] + BEWordToBitSeq_premium(x)[..amount]; ensures Asm_RotateLeft(x, amount) == RotateLeft(x, amount); //- Fulfills spec { lemma_word32_Word32(); lemma_IntBit_is_BEWordToBitSeq(); lemma_bits_match_implies_ints_match_general(); lemma_IntBit_is_IntBit_spec(); asm_RotateLeft(x, amount) } static function method{:instruction "inout", "in@ECX"} Asm_RotateRight(x:int, amount:int):int requires Word32(x); requires 0 <= amount < 32; ensures Word32(Asm_RotateRight(x, amount)); ensures |BEWordToBitSeq(x)| == 32; ensures BEWordToBitSeq_premium(Asm_RotateRight(x, amount)) == BEWordToBitSeq_premium(x)[32-amount..] + BEWordToBitSeq_premium(x)[..32-amount]; ensures Asm_RotateRight(x, amount) == RotateRight(x, amount); //- Fulfills spec { lemma_word32_Word32(); lemma_IntBit_is_BEWordToBitSeq(); lemma_bits_match_implies_ints_match_general(); lemma_IntBit_is_IntBit_spec(); asm_RotateRight(x, amount) } static function method{:instruction "inout"} Asm_BitwiseNot(x:int):int requires Word32(x); ensures Word32(Asm_BitwiseNot(x)); ensures |BEWordToBitSeq_premium(x)| == |BEWordToBitSeq_premium(Asm_BitwiseNot(x))| == 32; ensures forall i {:trigger BEWordToBitSeq(Asm_BitwiseNot(x))[i]} :: 0 <= i < 32 ==> BEWordToBitSeq_premium(Asm_BitwiseNot(x))[i] == 1 - BEWordToBitSeq_premium(x)[i]; ensures Asm_BitwiseNot(x) == BitwiseNot(x); //- Fulfills spec { lemma_word32_Word32(); lemma_IntBit_is_BEWordToBitSeq(); lemma_bits_match_implies_ints_match_general(); lemma_IntBit_is_IntBit_spec(); asm_BitwiseNot(x) } static lemma lemma_bitwise_and_commutative(x:int, y:int) requires Word32(x) && Word32(y); ensures Asm_BitwiseAnd(x, y) == Asm_BitwiseAnd(y, x); { forall i | 0 <= i < 32 //-ensures Asm_BitwiseAnd(x, y) == Asm_BitwiseAnd(y, x); ensures BEWordToBitSeq_premium(Asm_BitwiseAnd(x, y))[i] == BEWordToBitSeq_premium(Asm_BitwiseAnd(y, x))[i]; { calc { BEWordToBitSeq_premium(Asm_BitwiseAnd(x, y))[i]; if (BEWordToBitSeq_premium(x)[i] == 1 && BEWordToBitSeq_premium(y)[i] == 1) then 1 else 0; BEWordToBitSeq_premium(Asm_BitwiseAnd(y, x))[i]; } } assert BEWordToBitSeq_premium(Asm_BitwiseAnd(x, y)) == BEWordToBitSeq_premium(Asm_BitwiseAnd(y, x)); } static function method{:instruction "inout", "in"} Asm_BitwiseAnd(x:int, y:int):int requires Word32(x); requires Word32(y); ensures Word32(Asm_BitwiseAnd(x, y)); ensures |BEWordToBitSeq_premium(x)| == |BEWordToBitSeq_premium(y)| == |BEWordToBitSeq_premium(Asm_BitwiseAnd(x, y))| == 32; ensures forall i {:trigger BEWordToBitSeq(Asm_BitwiseAnd(x, y))[i]} :: 0 <= i < 32 ==> BEWordToBitSeq_premium(Asm_BitwiseAnd(x, y))[i] == if (BEWordToBitSeq_premium(x)[i] == 1 && BEWordToBitSeq_premium(y)[i] == 1) then 1 else 0; ensures Asm_BitwiseAnd(x, y) == BitwiseAnd(x, y); //- Fulfills spec { lemma_word32_Word32(); lemma_IntBit_is_BEWordToBitSeq(); lemma_bits_match_implies_ints_match_general(); lemma_IntBit_is_IntBit_spec(); asm_BitwiseAnd(x,y) } static function method{:instruction "inout", "in"} Asm_BitwiseOr(x:int, y:int):int requires Word32(x); requires Word32(y); ensures Word32(Asm_BitwiseOr(x, y)); ensures |BEWordToBitSeq_premium(x)| == |BEWordToBitSeq_premium(y)| == |BEWordToBitSeq_premium(Asm_BitwiseOr(x, y))| == 32; ensures forall i {:trigger BEWordToBitSeq(Asm_BitwiseOr(x, y))[i]} :: 0 <= i < 32 ==> BEWordToBitSeq_premium(Asm_BitwiseOr(x, y))[i] == if (BEWordToBitSeq_premium(x)[i] == 1 || BEWordToBitSeq_premium(y)[i] == 1) then 1 else 0; ensures Asm_BitwiseOr(x, y) == BitwiseOr(x, y); { lemma_word32_Word32(); lemma_IntBit_is_BEWordToBitSeq(); lemma_bits_match_implies_ints_match_general(); lemma_IntBit_is_IntBit_spec(); asm_BitwiseOr(x, y) } static function method{:instruction "inout", "in"} Asm_BitwiseXor(x:int, y:int):int requires Word32(x); requires Word32(y); ensures Word32(Asm_BitwiseXor(x, y)); ensures |BEWordToBitSeq_premium(x)| == |BEWordToBitSeq_premium(y)| == |BEWordToBitSeq_premium(Asm_BitwiseXor(x, y))| == 32; ensures forall i {:trigger BEWordToBitSeq(Asm_BitwiseXor(x, y))[i]} :: 0 <= i < 32 ==> BEWordToBitSeq_premium(Asm_BitwiseXor(x, y))[i] == if (BEWordToBitSeq_premium(x)[i] != BEWordToBitSeq_premium(y)[i]) then 1 else 0; ensures Asm_BitwiseXor(x, y) == BitwiseXor(x, y); //- Fulfills spec { lemma_word32_Word32(); lemma_IntBit_is_BEWordToBitSeq(); lemma_bits_match_implies_ints_match_general(); lemma_IntBit_is_IntBit_spec(); asm_BitwiseXor(x, y) } static method Asm_Rdtsc() returns (high:int, low:int) ensures Word32(high); ensures Word32(low); { lemma_word32_Word32(); high, low := asm_Rdtsc(); } method Asm_declassify_result(concrete:int, ghost result:int) returns (pub_result:int) requires Word32(concrete); requires relation(declassified(left(result), right(result), left(concrete), right(concrete))); ensures pub_result == result; ensures public(pub_result); { lemma_word32_Word32(); pub_result := asm_declassify_result(concrete, result); } static method GetBootloaderArgWord_premium(index:int) returns (word:int) requires 0 <= index < 256; ensures Word32(word); { lemma_word32_Word32(); word := GetBootloaderArgWord(index); } static method GetBootloaderArgBytes(left:int, right:int) returns (s:seq) requires 0 <= left <= right < 256 * 4; requires left % 4 == 0; ensures IsByteSeqOfLen(s, right - left); { s := []; var cur := left; var done := false; while cur < right invariant !done ==> left <= cur <= right < 256 * 4; invariant cur % 4 == 0; invariant IsByteSeqOfLen(s, cur - left); { var word := GetBootloaderArgWord_premium(cur / 4); var bytes := BEWordToFourBytes_impl(word); var reverse_bytes := [bytes[3], bytes[2], bytes[1], bytes[0]]; s := s + reverse_bytes; cur := cur + 4; if cur > right { done := true; } } if cur > right { s := s[0..right - left]; } assert IsByteSeqOfLen(s, right - left); } ================================================ FILE: ironclad-apps/src/Dafny/Drivers/IO/io_mem.i.dfy ================================================ include "io_mem.s.dfy" /****************************************************** * Connection to Verve for interacting with IO memory * ******************************************************/ method {:decl} IoMemAddrRead(r_addr:int) returns (r_val:int) requires IoMemPerm.IoReadAddr?; requires IoMemPerm.r_addr == r_addr; modifies this`IoMemPerm; ensures IoMemPerm.Null?; ensures r_val == old(IoMemPerm).r_val; method {:decl} IoMemAddrWrite(w_addr:int, w_val:int) requires IoMemPerm.IoWriteAddr?; requires IoMemPerm.w_addr == w_addr; requires IoMemPerm.w_val == w_val; modifies this`IoMemPerm; ensures IoMemPerm.Null?; ================================================ FILE: ironclad-apps/src/Dafny/Drivers/IO/io_mem.s.dfy ================================================ /*********************************************************** * Spec for granting permission to interact with IO memory * ***********************************************************/ datatype {:imported} IoMemPerm_t = Null() | IoReadAddr(r_addr:int, r_val:int) | IoWriteAddr(w_addr:int, w_val:int); ghost var {:imported} {:readonly} IoMemPerm:IoMemPerm_t; ================================================ FILE: ironclad-apps/src/Dafny/Drivers/IO/pci.i.dfy ================================================ //- include "../../Libraries/Util/relational.s.dfy" include "../../Libraries/Util/bytes_and_words.s.dfy" function {:opaque} mod4(n:int):int { n % 4 } function {:opaque} mod16(n:int):int { n % 16 } function {:opaque} mod128(n:int):int { n % 128 } function {:opaque} div16(n:int):int { n / 16 } /************************************************** * Spec for interacting with the network card **************************************************/ //-function intel_NIC_device_vendor_id() : int { 0x107c8086 } //- Track whether we've initialized the network card //- TODO: dafnycc support for: var net_init:bool; function IsValidPciId(id:int):bool function PciMemAddr(id:int):int //- Region where the device's PCI config registers are mapped into memory function PciMemSize(id:int):int function DeviceMemAddr() : int //- Region where devices are allowed to read/write function DeviceMemSize() : int /**************************************** Connections to Verve's PCI interface ****************************************/ method {:decl} NetworkPciMemSetup() returns (id:int, size:int, addr:int, device_mem_addr:int) ensures Word32(size) && Word32(addr) && Word32(device_mem_addr); ensures IsValidPciId(id); ensures size == PciMemSize(id); ensures addr == PciMemAddr(id); ensures Word32(addr + size); ensures Word32(DeviceMemAddr() + DeviceMemSize()); ensures DeviceMemAddr() == device_mem_addr; ensures mod16(device_mem_addr) == 0; ensures DeviceMemSize() > 0x204004; ensures public(id); ensures public(size); ensures public(addr); ensures public(device_mem_addr); method {:decl} PciMemStore(id:int, dst:int, val:int) requires IsValidPciId(id); requires PciMemAddr(id) <= dst && dst + 4 <= PciMemAddr(id) + PciMemSize(id); requires Word32(val); requires public(id); requires public(dst); requires public(val); method {:decl} PciMemLoad(id:int, src:int) returns (val:int) requires IsValidPciId(id); requires PciMemAddr(id) <= src && src + 4 <= PciMemAddr(id) + PciMemSize(id); ensures Word32(val); requires public(id); requires public(src); ensures public(val); method {:decl} {:instruction "mem", "in"} {:modifies_io} DeviceMemStore(dst:int, val:int) requires DeviceMemAddr() <= dst && dst + 4 <= DeviceMemAddr() + DeviceMemSize(); requires Word32(dst); requires Word32(val); requires public(dst); requires public(val); method {:decl} {:instruction "mem", "out"} {:modifies_io} DeviceMemLoad(src:int) returns (val:int) requires DeviceMemAddr() <= src && src + 4 <= DeviceMemAddr() + DeviceMemSize(); requires Word32(src); requires public(src); ensures Word32(val); ensures public(val); static method {:decl} debug_print(loc:int, val:int) requires 0 <= loc <= 160 - 16; ================================================ FILE: ironclad-apps/src/Dafny/Drivers/Network/.gitignore ================================================ *.bpl *.log ================================================ FILE: ironclad-apps/src/Dafny/Drivers/Network/Intel/.gitignore ================================================ *.bpl *.log ================================================ FILE: ironclad-apps/src/Dafny/Drivers/Network/Intel/driver.i.dfy ================================================ //- include "../../../Libraries/base.s.dfy" include "../../../Libraries/Util/relational.s.dfy" include "../../CPU/assembly_premium.i.dfy" include "../../../Libraries/Math/bit_vector_lemmas_premium.i.dfy" include "../../../Libraries/Util/repeat_digit.i.dfy" include "../../../Libraries/Util/integer_sequences.i.dfy" include "../../../Libraries/Math/div.i.dfy" include "../../../Libraries/Util/word_bits.i.dfy" include "../../IO/pci.i.dfy" //- //- Driver for Intel Network Card 82541PI. //- Sofware Developer's Manual labelled 317453006EN.PDF, Revision 4.0. //- //- Implementation Notes: //- //- - We don't support VLAN mode. //- - We don't prefetch or write-back transmit descriptors. //- - We leave the transmit absolute delay function (see 13.4.44) disabled. //- - We don't support large segment offload. //- - We use the "legacy" format of transmit/receive descriptors. //- //- //- Register addresses relative to the card's base address. //- See Table 13-2 on pages 219-222. //- //- Note: all registers should be accessed as 32-bit words. //- //- General Registers: function method{:dafnycc_inline} register_ctrl(addr:int):int { addr + 0x0000 } function method{:dafnycc_inline} register_status(addr:int):int { addr + 0x0008 } function method{:dafnycc_inline} register_ctrl_ext(addr:int):int { addr + 0x0018 } function method{:dafnycc_inline} register_fcal(addr:int):int { addr + 0x0028 } function method{:dafnycc_inline} register_fcah(addr:int):int { addr + 0x002c } function method{:dafnycc_inline} register_fct(addr:int):int { addr + 0x0030 } function method{:dafnycc_inline} register_fcttv(addr:int):int { addr + 0x0170 } //- Receive Registers: function method{:dafnycc_inline} register_rx_ctrl(addr:int):int { addr + 0x0100 } function method{:dafnycc_inline} register_rx_desc_base_lo(addr:int):int { addr + 0x2800 } function method{:dafnycc_inline} register_rx_desc_base_hi(addr:int):int { addr + 0x2804 } function method{:dafnycc_inline} register_rx_desc_length(addr:int):int { addr + 0x2808 } function method{:dafnycc_inline} register_rx_desc_head(addr:int):int { addr + 0x2810 } function method{:dafnycc_inline} register_rx_desc_tail(addr:int):int { addr + 0x2818 } function method{:dafnycc_inline} register_rx_delay_timer(addr:int):int { addr + 0x2820 } function method{:dafnycc_inline} register_rx_int_abs_timer(addr:int):int { addr + 0x282c } function method{:dafnycc_inline} register_rx_cksum_ctrl(addr:int):int { addr + 0x5000 } function method{:dafnycc_inline} register_rx_mcast_table(addr:int):int { addr + 0x5200 } function method{:dafnycc_inline} register_rx_addrN_lo(addr:int):int { addr + 0x5400 } function method{:dafnycc_inline} register_rx_addrN_hi(addr:int):int { addr + 0x5404 } //- Transmit Registers: function method{:dafnycc_inline} register_tx_ctrl(addr:int):int { addr + 0x0400 } function method{:dafnycc_inline} register_tx_ipg(addr:int):int { addr + 0x0410 } function method{:dafnycc_inline} register_tx_desc_base_lo(addr:int):int { addr + 0x3800 } function method{:dafnycc_inline} register_tx_desc_base_hi(addr:int):int { addr + 0x3804 } function method{:dafnycc_inline} register_tx_desc_length(addr:int):int { addr + 0x3808 } function method{:dafnycc_inline} register_tx_desc_head(addr:int):int { addr + 0x3810 } function method{:dafnycc_inline} register_tx_desc_tail(addr:int):int { addr + 0x3818 } //- //- Register-related Constants: //- //- Device Control Register (register_ctrl). See Section 13.4.1. //- Device Reset Bit: function method{:dafnycc_inline} ctrl_reset():int { 0x04000000 } //- i.e. Bit 26. //- PHY Reset Bit: function method{:dafnycc_inline} ctrl_phy_reset():int { 0x80000000 } //- i.e. Bit 31. //- Receive Control Register (register_rx_ctrl). See Section 13.4.22. //- Receiver Enable Bit: function method{:dafnycc_inline} ctrl_rx_enable():int { 2 } //- i.e. Bit 1. //- Transmit Control Register (register_tx_ctrl). See Section 13.4.33. //- Transmit Enable Bit: function method{:dafnycc_inline} ctrl_tx_enable():int { 2 } //- i.e. Bit 1. //- Pad Short Packets Bit: function method{:dafnycc_inline} tx_pad_short_packets():int { 8 } //- i.e. Bit 3. //- Transmit Inter-Packet Gap Register (register_tx_ipg). See Section 13.4.34. //- Default Value: function method{:dafnycc_inline} tx_ipg_default():int { 10 } //- Receive Delay Timer (register_rx_delay_timer). See Section 13.4.30. //- Default Value: function method{:dafnycc_inline} rxdelaytimers_rx_delay_timer():int { 100 } //- ~100us. //- Receive Interrupt Absolute Delay Timer(register_rx_int_abs_timer). See Section 13.4.31. //- Default Value: function method{:dafnycc_inline} rxdelaytimers_rx_absolute_timer():int { 1000 } //- ~1000us. //- //- Ring Buffer Configuration Values. //- function method{:dafnycc_inline} bytes_per_descriptor():int { 16 } function method{:dafnycc_inline} num_descriptors():int { 512 } //-function method{:dafnycc_inline} total_desc_bytes():int { num_descriptors() * bytes_per_descriptor() } function method{:dafnycc_inline} total_desc_bytes():int { 512 * bytes_per_descriptor() } function method{:dafnycc_inline} bytes_per_buffer():int { 2 * 1024 } //-function method{:dafnycc_inline} total_buffer_bytes():int { num_descriptors() * bytes_per_buffer() } function method{:dafnycc_inline} total_buffer_bytes():int { 512 * bytes_per_buffer() } //- //- Hard code the MAC address to 90:e2:ba:4f:0c:5b. //- Hard code the MAC address to 00:1b:21:31:8e:d9. //- function method my_ethernet_addr() : ethernet_addr { ethernet_addr_builder( [ 0x90, 0xe2, 0xba, 0x4f, 0x0c, 0x5b] ) //- ethernet_addr_builder( [ 0x00, 0x1b, 0x21, 0x31, 0x8e, 0xd9] ) } //- //- Define what an "ethernet_addr" is. //- datatype ethernet_addr = ethernet_addr_builder(bytes:seq); function valid_ethernet_addr(addr:ethernet_addr) : bool { IsByteSeqOfLen(addr.bytes, 6) } /**************************************** Ring buffers used for tx/rx ****************************************/ datatype network_state = network_state_build(rx_rb:rx_ring_buffer, tx_rb:tx_ring_buffer); datatype rx_ring_buffer = rx_ring_buffer_build(rb:ring_buffer); datatype tx_ring_buffer = tx_ring_buffer_build(rb:ring_buffer); datatype ring_buffer = ring_buffer_build(base:int, size:int, head:int, tail:int, id:int, reg_addr:int); function valid_ring_buffer(rb:ring_buffer):bool requires num_descriptors() == 512; { mod16(rb.base) == 0 && rb.base >= 0 && Word32(rb.base + total_desc_bytes() + total_buffer_bytes()) && //- Include space for descriptors and the buffers they point at DeviceMemAddr() <= rb.base && rb.base + total_desc_bytes() + total_buffer_bytes() + 4 <= DeviceMemAddr() + DeviceMemSize() && DeviceMemSize() >= 0x204000 && mod128(rb.size) == 0 && 128 <= rb.size < power2(19) && div16(rb.size) == 512 && Word32(rb.base + rb.size) && 0 <= rb.head < power2(16) && rb.base + 16 * rb.head <= rb.base + rb.size - 16 && //- Assuming head and tail are measured in descriptors (16B each) 0 <= rb.tail < power2(16) && rb.base + 16 * rb.tail <= rb.base + rb.size - 16 && //- Assuming head and tail are measured in descriptors (16B each) rb.reg_addr == PciMemAddr(rb.id) && rb.reg_addr >= 0 && Word32(rb.reg_addr + 128 * 1024) && IsValidPciId(rb.id) && PciMemSize(rb.id) >= 128 * 1024 } function valid_network_state(state:network_state):bool { valid_ring_buffer(state.rx_rb.rb) && valid_ring_buffer(state.tx_rb.rb) } /* * Device Memory layout plan: * Verve gives us, via NetworkPciMemSetup, an address in device memory. * That memory is untrusted, but accessible to devices. We will lay it out as follows: * +1M * Rx Buffers x 512 (2K each) * +8K * Rx Ring Descriptors x 512 (16B each) * +1M * Tx Buffers x 512 (2K each) * +8K * Tx Ring Descriptors x 512 (16B each) * dev_addr-> * * Thus, we need 2M + 16K bytes = 0x204000. */ //-lemma init_network_card_lemma1(addr:int) //- //-requires mod4(addr) == 0; //- //-ensures mod4(register_fcal(addr)) == 0; //- //-ensures mod4(register_fcah(addr)) == 0; //- //-ensures mod4(register_fct(addr)) == 0; //- //-ensures mod4(register_fcttv(addr)) == 0; //- //-ensures mod4(register_rx_addrN_lo(addr)) == 0; //- //-ensures mod4(register_rx_addrN_hi(addr)) == 0; //- //-ensures mod4(register_rx_desc_base_lo(addr)) == 0; //- //-ensures mod4(register_rx_desc_base_hi(addr)) == 0; //- //-ensures mod4(register_rx_desc_length(addr)) == 0; //- //-ensures mod4(register_rx_desc_head(addr)) == 0; //- //-ensures mod4(register_rx_desc_tail(addr)) == 0; //- //-ensures mod4(register_rx_ctrl(addr)) == 0; //- //-ensures mod4(register_rx_delay_timer(addr)) == 0; //- //-ensures mod4(register_rx_int_abs_timer(addr)) == 0; //- //-ensures mod4(register_rx_cksum_ctrl(addr)) == 0; //- //-ensures mod4(register_tx_desc_base_lo(addr)) == 0; //- //-ensures mod4(register_tx_desc_base_hi(addr)) == 0; //- //-ensures mod4(register_tx_desc_length(addr)) == 0; //- //-ensures mod4(register_tx_desc_head(addr)) == 0; //- //-ensures mod4(register_tx_desc_tail(addr)) == 0; //- //-ensures mod4(register_tx_ctrl(addr)) == 0; //- //-ensures mod4(register_tx_ipg(addr)) == 0; //-{ //- reveal_mod4(); //- reveal_mod16(); //- reveal_mod128(); //- reveal_div16(); //-} lemma init_network_card_lemma2a(dev_addr:int) requires mod16(dev_addr) == 0; requires Word32(dev_addr); //- HACK to avoid timeout ensures mod4(dev_addr) == 0; { reveal_mod4(); reveal_mod16(); } lemma init_network_card_lemma2b(dev_addr:int) requires mod4(dev_addr) == 0; ensures mod4(dev_addr + 512 * 16 + 512 * 2 * 1024) == 0; { reveal_mod4(); } lemma init_network_card_lemma2c(dev_addr:int) requires mod16(dev_addr) == 0; ensures mod16(dev_addr + 512 * 16 + 512 * 2 * 1024) == 0; { reveal_mod16(); } lemma init_network_card_lemma3() ensures mod128(total_desc_bytes()) == 0; ensures div16(total_desc_bytes()) == 512; { reveal_mod4(); reveal_mod16(); reveal_mod128(); reveal_div16(); } //-lemma init_network_card_lemma4(addr:int, mta_register:int) //- //-requires mod4(addr) == 0; //- //-ensures mod4(register_rx_mcast_table(addr) + mta_register * 4) == 0; //-{ //- reveal_mod4(); //- reveal_mod16(); //- reveal_mod128(); //- reveal_div16(); //-} //- //- Debug print a register value. //- //-method debug_print_register(loc:int, id:int, reg:int) //- requires IsValidPciId(id); //- requires PciMemAddr(id) <= reg && reg + 4 <= PciMemAddr(id) + PciMemSize(id); //- requires 0 <= loc <= 160 - 16; //- requires public(id); //- requires public(reg); //-{ //- var reg_dbg := PciMemLoad(id, reg); //- debug_print(loc, reg_dbg); //-} //- //- Busy-wait something in the neighborhood of the requested amount of time. //- method delay(microseconds:int) requires 0 <= microseconds < 0xEFFFFFFF; { var ms := microseconds; while (ms > 0) decreases ms; { var count := 3 * 1000; //- 3K ops on a 3 GHz machine should be ~1 us. while (count > 0) decreases count; { count := count - 1; } ms := ms - 1; } } //- //- Card Initialization Routines. //- method init_network_card() returns (success:bool, state:network_state) ensures success ==> valid_network_state(state); ensures public(success); ensures public(state); { var id, size, addr, dev_addr := NetworkPciMemSetup(); //- debug_print(0x00, 0xbeefcafe); //- debug_print(0x00, addr); //- debug_print(0x12, size); //- debug_print(0x24, dev_addr); var rx_ring_buff:rx_ring_buffer; var tx_ring_buff:tx_ring_buffer; if (size < 128 * 1024) { //- //- We expect the Intel NIC to get 128K worth of PCI config space mapped into memory. //- So this is bad. //- success := false; var buff := ring_buffer_build(0, 0, 0, 0, 0, 0); //- TODO: dafnycc: had to add this line because dafnycc doesn't handle returning uninitialized variables. rx_ring_buff := rx_ring_buffer_build(buff); tx_ring_buff := tx_ring_buffer_build(buff); } else { assert 512 == num_descriptors(); lemma_2toX(); // // init_network_card_step1(id, addr); init_network_card_step2(id, addr); rx_ring_buff := init_network_card_step2rx(id, addr, size, dev_addr); init_network_card_step3(id, addr, size); tx_ring_buff := init_network_card_step3tx(id, addr, size, dev_addr); init_network_card_step4(id, addr, size); success := true; } state := network_state_build(rx_ring_buff, tx_ring_buff); } method init_network_card_step1a_stop_everything(id:int, addr:int) requires Word32(addr); requires IsValidPciId(id); requires addr == PciMemAddr(id); requires PciMemSize(id) >= 128 * 1024; requires public(id); requires public(addr); { init_network_card_lemma3(); lemma_2toX(); //- //- Stop everything. //- PciMemStore(id, register_rx_ctrl(addr), 0); PciMemStore(id, register_tx_ctrl(addr), tx_pad_short_packets()); //- Allow pending PCI transactions to complete. delay(10 * 1000); } method init_network_card_step1b_reset(id:int, addr:int) requires Word32(addr); requires IsValidPciId(id); requires addr == PciMemAddr(id); requires PciMemSize(id) >= 128 * 1024; requires public(id); requires public(addr); { lemma_2toX(); //- //- Reset the card. //- var ctrl_reg := PciMemLoad(id, register_ctrl(addr)); //-debug_print(0x48, ctrl_reg); var temp_reg := ctrl_reg; temp_reg := Asm_BitwiseOr(temp_reg, ctrl_phy_reset()); //-debug_print(0x48, temp_reg); PciMemStore(id, register_ctrl(addr), temp_reg); delay(5 * 1000); temp_reg := Asm_BitwiseOr(ctrl_reg, ctrl_reset()); PciMemStore(id, register_ctrl(addr), temp_reg); //-debug_print(0x48, temp_reg); //- Wait 3us (or more) for the board to quiesce. delay(20 * 1000); delay(1 * 1000 * 1000); } method init_network_card_step1c_set_ctrl(id:int, addr:int) requires Word32(addr); requires IsValidPciId(id); requires addr == PciMemAddr(id); requires PciMemSize(id) >= 128 * 1024; requires public(id); requires public(addr); { lemma_2toX(); //- Set the device control register to values we want: //- (See Table 13-3 in section 13.4.1) //- Bit 0: Full-Duplex (Must also set the Force-Duplex Bit (Bit 12)). //- Bit 5: Auto-Speed Detection Enable (ASDE). //- Bit 6: Set Link Up (SLU). //- Bit 12: Force-Duplex Bit. PciMemStore(id, register_ctrl(addr), 0x1061); //- Wait for the autonegotiation to complete. var negotiated := false; var ctrl:int := 0; var count := 0; while (!negotiated) decreases *; invariant public(id); invariant public(addr); invariant public(negotiated); { //-debug_print(0x90, count); ctrl := PciMemLoad(id, register_ctrl(addr)); var done := Asm_BitwiseAnd(ctrl, ctrl_reset()); if (done == 0) { negotiated := true; } count := count + 1; } } method init_network_card_step1d_disable_flow_ctrl(id:int, addr:int) requires Word32(addr); requires IsValidPciId(id); requires addr == PciMemAddr(id); requires PciMemSize(id) >= 128 * 1024; requires public(id); requires public(addr); { //- //- Turn off flow control. //- See Section 14.3, General Configuration. //- PciMemStore(id, register_fcal(addr), 0); PciMemStore(id, register_fcah(addr), 0); PciMemStore(id, register_fct(addr), 0); PciMemStore(id, register_fcttv(addr), 0); } method init_network_card_step1(id:int, addr:int) requires Word32(addr); requires IsValidPciId(id); requires addr == PciMemAddr(id); requires PciMemSize(id) >= 128 * 1024; requires public(id); requires public(addr); { init_network_card_step1a_stop_everything(id, addr); init_network_card_step1b_reset(id, addr); init_network_card_step1c_set_ctrl(id, addr); init_network_card_step1d_disable_flow_ctrl(id, addr); } //- //- Clear the multicast table. //- method clear_multicast(id:int, addr:int) requires Word32(addr); requires IsValidPciId(id); requires addr == PciMemAddr(id); requires PciMemSize(id) >= 128 * 1024; requires public(id); requires public(addr); { var mta_entry := 0; while (mta_entry < 128) invariant mta_entry >= 0; invariant public(id); invariant public(addr); invariant public(mta_entry); { PciMemStore(id, register_rx_mcast_table(addr) + mta_entry * 4, 0); mta_entry := mta_entry + 1; } } method init_network_card_step2(id:int, addr:int) requires Word32(addr); requires IsValidPciId(id); requires addr == PciMemAddr(id); requires PciMemSize(id) >= 128 * 1024; requires public(id); requires public(addr); { //-init_network_card_lemma1(addr); init_network_card_lemma3(); lemma_2toX(); //- //- Setup the MAC address. //- var mac_addr := my_ethernet_addr(); var addr_lo := mac_addr.bytes[0] + 256 * mac_addr.bytes[1] + 256 * 256 * mac_addr.bytes[2] + 256 * 256 * 256 * mac_addr.bytes[3]; //-little_endian_bytes_to_word(mac_addr.bytes[0..4]); var addr_hi := mac_addr.bytes[4] + 256 * mac_addr.bytes[5]; //-little_endian_bytes_to_word(mac_addr.bytes[4..6]); PciMemStore(id, register_rx_addrN_lo(addr), addr_lo); var temp_reg := addr_hi; temp_reg := Asm_BitwiseOr(temp_reg, 0x80000000); //- Set the Address Valid bit PciMemStore(id, register_rx_addrN_hi(addr), temp_reg); clear_multicast(id, addr); } method init_network_card_step2rx(id:int, addr:int, size:int, dev_addr:int) returns (rx_ring_buff:rx_ring_buffer) requires Word32(size) && Word32(addr) && Word32(dev_addr); requires IsValidPciId(id); requires size == PciMemSize(id); requires addr == PciMemAddr(id); requires Word32(addr + size); requires Word32(DeviceMemAddr() + DeviceMemSize()); requires size >= 128 * 1024; requires DeviceMemAddr() == dev_addr; requires mod16(dev_addr) == 0; requires DeviceMemSize() > 0x204004; requires public(id); requires public(addr); requires public(dev_addr); ensures valid_ring_buffer(rx_ring_buff.rb); ensures public(rx_ring_buff); { //-init_network_card_lemma1(addr); init_network_card_lemma2a(dev_addr); init_network_card_lemma2b(dev_addr); init_network_card_lemma2c(dev_addr); init_network_card_lemma3(); lemma_2toX(); //- //- Setup Receive Descriptor Queue. //- See Section 3.2.6. //- var rx_desc_base_lo := dev_addr + total_desc_bytes() + total_buffer_bytes(); var rx_desc_len := total_desc_bytes(); assert(rx_desc_base_lo == dev_addr + 512 * 16 + 512 * 2 * 1024); //- assert rx_desc_base_lo % 16 == 0; //- assert rx_desc_len % 128 == 0 && 128 <= rx_desc_len < power2(19); //- assert (512 * 16 + 512 * 2 * 1024) % 4 == 0; //- assert rx_desc_base_lo % 4 == dev_addr % 4; //- //- The head pointer references the next empty descriptor to be filled with an incoming packet. //- Once the hardware has written a packet to that descriptor, it advances the head pointer. //- The tail pointer references one descriptor past the last one the hardware is allowed to write to. //- Once the driver has processed the packet in the (tail + 1) descriptor, it advances the tail pointer. //- //- When the head pointer is advanced to equal the tail pointer, there are no free (empty) descriptors available //- for the hardware to fill, and the hardware will stop adding packets to the circular queue until the driver //- processes some packets and advances the tail pointer. //- //- When the tail pointer is advanced to the point where it is one less than the head pointer, then all the //- receive descriptors are empty and are waiting for the hardware to fill them with packets. //- This is the initial state we establish below. //- var rx_desc_head := 1; var rx_desc_tail := 0; assert rx_desc_head < power2(16); assert rx_desc_tail < power2(16); PciMemStore(id, register_rx_desc_base_lo(addr), rx_desc_base_lo); PciMemStore(id, register_rx_desc_base_hi(addr), 0); PciMemStore(id, register_rx_desc_length(addr), rx_desc_len); PciMemStore(id, register_rx_desc_head(addr), rx_desc_head); PciMemStore(id, register_rx_desc_tail(addr), rx_desc_tail); //- //- Create a full set of empty descriptors and buffers. //- BuildDescriptors(rx_desc_base_lo, false); rx_ring_buff := rx_ring_buffer_build(ring_buffer_build(rx_desc_base_lo, rx_desc_len, rx_desc_head, rx_desc_tail, id, addr)); } method init_network_card_step3(id:int, addr:int, size:int) requires Word32(size) && Word32(addr); requires IsValidPciId(id); requires size == PciMemSize(id); requires addr == PciMemAddr(id); requires Word32(addr + size); requires Word32(DeviceMemAddr() + DeviceMemSize()); requires size >= 128 * 1024; requires public(id); requires public(addr); { //-init_network_card_lemma1(addr); init_network_card_lemma3(); lemma_2toX(); //- //- Set Receiever Control flags (See Table 13-67 in Section 13.4.22): //- Bits 8-9: Receive Descriptor Minimum Threshold Size set to 1/4 of RDLEN (01). //- Bit 26: Strip Ethernet CRC from incoming packet. //- //- Note: We leave all other bits at their initial zero value. This means: //- - Receiver Enable is not set (we enable this in final step). //- - We do not store bad packets. //- - Unicast Promiscuous is disabled. //- - Multicast Promiscuous is disabled. //- - We discard packets longer than 1522 bytes. //- - Loopback is off. //- - Multicast Offset - bits 47:36 are used in the lookup. //- - We ignore broadcast packets. //- - Receive Buffer Size is set to 2048 bytes. //- - Various VLAN things (Filter, Canonical Form Indicator) are disabled. //- - We don't Discard Pause Frames (used by flow control, if it's enabled). //- assert bytes_per_buffer() == 2 * 1024; //- Ensure we match the Receive Buffer Size flag. PciMemStore(id, register_rx_ctrl(addr), 0x04000100); //- PciMemStore(id, register_rx_ctrl(addr), 0x04008118); //- Promiscuous everything. //- //- Setup the rx interrupt delay. //- TODO: Don't we have interrupts off? Why do this? //- TODO: Manual *strongly recommends* against using these fields. //- //- PciMemStore(id, register_rx_delay_timer(addr), rxdelaytimers_rx_delay_timer()); //- PciMemStore(id, register_rx_int_abs_timer(addr), rxdelaytimers_rx_absolute_timer()); //- //- Enable IP and TCP receive checksum calculation offloading. //- PciMemStore(id, register_rx_cksum_ctrl(addr), 0x00000700); //- Flags value above corresponds to: //- rxchecksum_ip_checksum_enable() | //- 1u << 8 //- rxchecksum_tcp_checksum_enable() | //- 1u << 9 //- rxchecksum_ip6_checksum_enable() )); //- 1u << 10 } method init_network_card_step3tx(id:int, addr:int, size:int, dev_addr:int) returns (tx_ring_buff:tx_ring_buffer) requires Word32(size) && Word32(addr) && Word32(dev_addr); requires IsValidPciId(id); requires size == PciMemSize(id); requires addr == PciMemAddr(id); requires Word32(addr + size); requires Word32(DeviceMemAddr() + DeviceMemSize()); requires size >= 128 * 1024; requires DeviceMemAddr() == dev_addr; requires mod16(dev_addr) == 0; requires DeviceMemSize() > 0x204000; requires public(id); requires public(addr); requires public(dev_addr); ensures valid_ring_buffer(tx_ring_buff.rb); ensures public(tx_ring_buff); { //-init_network_card_lemma1(addr); init_network_card_lemma2a(dev_addr); init_network_card_lemma2b(dev_addr); init_network_card_lemma2c(dev_addr); init_network_card_lemma3(); lemma_2toX(); //-debug_print(0x24, dev_addr); var tx_desc_base_lo := dev_addr; var tx_desc_len := total_desc_bytes(); var tx_desc_head := 0; var tx_desc_tail := 0; //- tail == head ==> queue is empty (Sec. 3.4) ==> no packets to transmit. assert tx_desc_head < power2(16); assert tx_desc_tail < power2(16); PciMemStore(id, register_tx_desc_base_lo(addr), tx_desc_base_lo); PciMemStore(id, register_tx_desc_base_hi(addr), 0); PciMemStore(id, register_tx_desc_length(addr), tx_desc_len); PciMemStore(id, register_tx_desc_head(addr), tx_desc_head); PciMemStore(id, register_tx_desc_tail(addr), tx_desc_tail); //- //- Create a full set of empty descriptors and buffers. //- BuildDescriptors(tx_desc_base_lo, true); tx_ring_buff := tx_ring_buffer_build(ring_buffer_build(tx_desc_base_lo, tx_desc_len, tx_desc_head, tx_desc_tail, id, addr)); } method init_network_card_step4(id:int, addr:int, size:int) requires Word32(size) && Word32(addr); requires IsValidPciId(id); requires size == PciMemSize(id); requires addr == PciMemAddr(id); requires Word32(addr + size); requires Word32(DeviceMemAddr() + DeviceMemSize()); requires size >= 128 * 1024; requires public(id); requires public(addr); { //-init_network_card_lemma1(addr); init_network_card_lemma3(); lemma_2toX(); //- //- Set Transmit Control flags: //- Bit 3: Pad Short Packets to 64 bytes (including CRC). //- Bits 4-11: Collision Threshold set to 0xf. TODO: Only for half-duplex? //- Bits 12-21: Collision Distance set to 0x40. //- //- Note: We leave all other bits at their initial zero value. This means: //- - Transmit Enable is not zet (we enable this in final step). //- - Software XOFF Transmission is disabled. //- - Re-transmit on Late Collision is disabled (ignored for full-duplex). //- PciMemStore(id, register_tx_ctrl(addr), 0x000400F8); //- Setup Transmit Inter Frame Gap. PciMemStore(id, register_tx_ipg(addr), tx_ipg_default()); //- //- Start receiving. //- var temp_reg := PciMemLoad(id, register_rx_ctrl(addr)); temp_reg := Asm_BitwiseOr(temp_reg, ctrl_rx_enable()); PciMemStore(id, register_rx_ctrl(addr), temp_reg); //- //- Start transmitting. //- temp_reg := PciMemLoad(id, register_tx_ctrl(addr)); temp_reg := Asm_BitwiseOr(temp_reg, ctrl_tx_enable()); PciMemStore(id, register_tx_ctrl(addr), temp_reg); //-debug_print_register(0x36, id, register_status(addr)); } //- //- Setup a static set of descriptors pointing at a static set of buffers. //- method BuildDescriptors(BaseAddress:int, Transmit:bool) requires mod4(BaseAddress) == 0; requires num_descriptors() == 512; requires bytes_per_descriptor() == 16; requires bytes_per_buffer() == 2 * 1024; requires Word32(BaseAddress); requires Word32(BaseAddress + total_desc_bytes() + total_buffer_bytes()); requires DeviceMemAddr() <= BaseAddress && BaseAddress + total_desc_bytes() + total_buffer_bytes() <= DeviceMemAddr() + DeviceMemSize(); requires public(BaseAddress); requires public(Transmit); { var Index := 0; var StartingStatus := 0; //- //- For transmit descriptors, we initialize the DD bit in the Status field to 1. //- This mimics the "transmission complete" state (i.e. our code is free to use them). //- For receive descriptors, we initialize the DD bit in the Status field to 0. //- This is the state that the hardware expects to find them prior to using them. //- if (Transmit) { StartingStatus := 1; //- Set the DD bit. } while (Index < 512) invariant Index >= 0; invariant public(BaseAddress); invariant public(Index); invariant public(StartingStatus); { var Descriptor := BaseAddress + Index * 16; var Buffer := BaseAddress + total_desc_bytes() + Index * 2 * 1024; DeviceMemStore(Descriptor + 0, Buffer); DeviceMemStore(Descriptor + 4, 0); DeviceMemStore(Descriptor + 8, 0); DeviceMemStore(Descriptor + 12, StartingStatus); Index := Index + 1; } } //- Write out the packet to device memory. method write_out_packet(addr:int, ghost data_buffer:int, packet:seq) returns (final_addr:int) requires IsWordSeq(packet); requires addr == data_buffer; requires Word32(addr); requires Word32(addr + 4 * |packet|); requires DeviceMemAddr() <= addr && data_buffer + 4 * |packet| <= DeviceMemAddr() + DeviceMemSize(); requires public(addr); requires public(packet); ensures final_addr == data_buffer + 4 * |packet|; { var i := 0; var local_addr := addr; if (|packet| > 0) { ghost var complete := false; while (i < |packet|) invariant i < |packet| ==> !complete; invariant !complete ==> 0 <= i < |packet|; invariant IsWordSeq(packet); invariant Word32(local_addr); invariant local_addr == data_buffer + 4 * i; //-invariant valid_ring_buffer(tx_buff); invariant !complete ==> DeviceMemAddr() <= local_addr && local_addr + 4 <= DeviceMemAddr() + DeviceMemSize(); invariant complete ==> i == |packet|; invariant public(local_addr); invariant public(i); invariant public(packet); { DeviceMemStore(local_addr, packet[i]); local_addr := local_addr + 4; i := i + 1; complete := complete || (i == |packet|); } } final_addr := local_addr; } //- //- Reverse the byte-order in the given 32-bit word. //- method ByteSwapWord32(InWord:int) returns (OutWord:int) requires Word32(InWord); ensures Word32(OutWord); ensures relation(left(InWord) == right(InWord) ==> left(OutWord) == right(OutWord)); { lemma_2toX(); var ByteA := Asm_RightShift(Asm_BitwiseAnd(InWord, 0xff000000), 24); var ByteB := Asm_RightShift(Asm_BitwiseAnd(InWord, 0x00ff0000), 8); var ByteC := Asm_LeftShift(Asm_BitwiseAnd(InWord, 0x0000ff00), 8); var ByteD := Asm_LeftShift(Asm_BitwiseAnd(InWord, 0x000000ff), 24); OutWord := Asm_BitwiseOr(Asm_BitwiseOr(ByteA, ByteB), Asm_BitwiseOr(ByteC, ByteD)); } //- //- Copy packet data to buffer. //- method CopyPacketToBuffer(BufferAddr:int, PacketData:seq) requires Word32(BufferAddr); requires IsByteSeq(PacketData); requires Word32(BufferAddr + |PacketData| + 4); requires DeviceMemAddr() <= BufferAddr; requires BufferAddr + |PacketData| + 4 <= DeviceMemAddr() + DeviceMemSize(); requires public(BufferAddr); requires public(PacketData); { lemma_2toX(); //- //- Convert the packet data byte sequence to a sequence of 32-bit words. //- var Words := BEByteSeqToWordSeqTailPadding(PacketData); var Index := 0; var WordAddr := BufferAddr; if (|Words| > 0) { ghost var Complete := false; //- //- Write the 32-bit words that comprise the packet data out to the buffer. //- We byte-swap the words in the process as BEByteSeqToWordSeqTailPadding gave //- us the opposite of what we need. //- while (Index < |Words|) invariant Index < |Words| ==> !Complete; invariant !Complete ==> 0 <= Index < |Words|; invariant IsWordSeq(Words); invariant Word32(WordAddr); invariant WordAddr == BufferAddr + 4 * Index; invariant !Complete ==> DeviceMemAddr() <= WordAddr && WordAddr + 4 <= DeviceMemAddr() + DeviceMemSize(); invariant Complete ==> Index == |Words|; invariant public(Words); invariant public(Index); invariant public(WordAddr); { var Word := ByteSwapWord32(Words[Index]); DeviceMemStore(WordAddr, Word); WordAddr := WordAddr + 4; Index := Index + 1; Complete := Complete || (Index == |Words|); } } } //- //- Copy buffer contents to packet representation. //- method CopyBufferToPacket(BufferAddr:int, Length:int) returns (Success:bool, PacketData:seq) requires Word32(BufferAddr); requires DeviceMemAddr() <= BufferAddr; requires Word16(Length); requires Word32(BufferAddr + 2048 + 4); requires BufferAddr + 2048 + 4 <= DeviceMemAddr() + DeviceMemSize(); requires public(BufferAddr); requires public(Length); ensures Success ==> IsByteSeq(PacketData); ensures Success ==> |PacketData| == Length; ensures public(PacketData); ensures public(Success); { reveal_mod4(); reveal_mod16(); reveal_mod128(); reveal_div16(); lemma_2toX(); PacketData := []; //- //- Sanity-check the amount of data this is supposedly in this buffer. //- We use 2K buffers, so anything more than that doesn't make sense. //- We also protect ourselves against the hardware indicating it received a zero byte packet. //- if ((Length <= 0) || (Length > 2048)) { Success := false; } else { //- //- Calculate the number of 32-bit words (containing valid data) in the buffer. //- Note that only some of the bytes in the last word of this count may contain valid data. //- var NumWords := ((Length - 1) / 4) + 1; assert 0 <= NumWords <= 512; //- //- Read in the packet data from the buffer. //- var Words := []; var Index := 0; var WordAddr := BufferAddr; ghost var Complete := false; while (Index < NumWords) invariant Index < NumWords ==> !Complete; invariant !Complete ==> 0 <= Index < NumWords; invariant IsWordSeq(Words); invariant Word32(WordAddr); //- invariant Word32(WordAddr) && WordAddr % 4 == 0; invariant WordAddr == BufferAddr + 4 * Index; invariant !Complete ==> DeviceMemAddr() <= WordAddr && WordAddr + 4 <= DeviceMemAddr() + DeviceMemSize(); invariant Complete ==> Index == NumWords; invariant |Words| == Index; invariant 0 <= Index <= 512; invariant public(WordAddr); invariant public(Words); invariant public(Index); invariant public(NumWords); invariant public(Length); invariant public(Complete); { var Word := DeviceMemLoad(WordAddr); Word := ByteSwapWord32(Word); Words := Words + [Word]; WordAddr := WordAddr + 4; Index := Index + 1; Complete := Complete || (Index == NumWords); } PacketData := BEWordSeqToByteSeq_impl(Words); PacketData := PacketData[0..Length]; Success := true; } } method update_tx_descriptor(tx_rb:tx_ring_buffer, packet_size:int) requires valid_ring_buffer(tx_rb.rb); requires Word32(packet_size); requires public(tx_rb); requires public(packet_size); { lemma_2toX(); //- //- Update the corresponding (legacy format) transmit descriptor. //- See Table 3-8 and 3-9 in Section 3.3.3. //- //- Bytes 0 to 7 of the transmit descriptor contain the address of its //- corresponding buffer, which we never change after initialization. //- //- Bytes 8 and 9 contain the length of the data to be sent. //- Byte 10 is the Checksum Offset, which we currently do not use. //- Byte 11 is the Command Field (See Section 3.3.3.1): //- Bit 0: Indicates this descriptor is the End Of Packet (EOP). //- Bit 1: Insert FCS/CRC field (IFCS). Valid only if EOP is set. //- Bit 2: Insert Checksum (IC). We currently do not set. //- Bit 3: Report Status (RS). Hardware sets Status DD bit when done. //- Bit 4: Only for 82544GC/CI, reserved bit for the 82541. //- Bit 5: Extention (DEXT). We write as 0 for legacy mode. //- Bit 6: VLAN Packet Enable (VLE). We currently do not set. //- Bit 7: Interrupt Delay Enable. We currently do not set. //- Byte 12 is the Status Field (bits 0-2, bits 3-7 are Reserved). //- Byte 13 is the Checksum Start Field, which we currently do not use. //- Bytes 14 and 15 is the Special Field (VLAN related, we do not use). //- //- We write 32 bits at a time, so we write bytes 8-11 in one operation, //- and 12-14 in another. //- var TailDesc := tx_rb.rb.base + 16 * tx_rb.rb.tail; //- debug_print(0x90, TailDesc); //- Debug. //- //- We set RS, IFCS, and EOP bits (i.e. 0xb) in the Command Field. //- var Temp := Asm_BitwiseOr(0x0b000000, packet_size); DeviceMemStore(TailDesc + 8, Temp); //- Bytes 8-11. DeviceMemStore(TailDesc + 12, 0); //- Bytes 12-15. } //- //- Before advancing the tail descriptor, make sure the hardware is done //- with the next entry. //- method wait_for_available_tx_buffer(tx_rb:tx_ring_buffer, NextIndex:int) requires valid_ring_buffer(tx_rb.rb); requires 0 <= NextIndex < 512; requires public(tx_rb); requires public(NextIndex); { lemma_2toX(); var done := 0; while (done != 1) invariant valid_ring_buffer(tx_rb.rb); invariant public(tx_rb); invariant public(done); invariant public(NextIndex); decreases *; { var NextDescStatus := DeviceMemLoad(tx_rb.rb.base + 16 * NextIndex + 12); done := Asm_BitwiseAnd(NextDescStatus, 1); //- Check DD bit. } } method tx_cleanup(tx_rb:tx_ring_buffer, NextIndex:int) requires valid_ring_buffer(tx_rb.rb); requires 0 <= NextIndex < 512; requires public(tx_rb); requires public(NextIndex); { lemma_2toX(); //- Clear out the status register. TODO: Why? DeviceMemStore(tx_rb.rb.base + 16 * NextIndex + 12, 0); //- //- Advance the tail pointer. This submits the descriptor pointed to by //- the current tail pointer to the hardware for processing. //- PciMemStore(tx_rb.rb.id, register_tx_desc_tail(tx_rb.rb.reg_addr), NextIndex); } //- //- Send an Ethernet packet on our interface. //- method NetIfSend(state:network_state, Headers:seq, Data:seq) returns (new_state:network_state) requires valid_network_state(state); requires public(state); requires |Headers| >= 14; //- Must contain at least an Ethernet header. requires |Headers| + |Data| <= 1514; //- Cannot exceed maximum Ethernet packet size. requires IsByteSeq(Headers); requires IsByteSeq(Data); requires public(Headers); requires public(Data); ensures valid_network_state(new_state); ensures new_state == state[tx_rb := tx_ring_buffer_build(ring_buffer_build(state.tx_rb.rb.base, state.tx_rb.rb.size, state.tx_rb.rb.head, (state.tx_rb.rb.tail + 1) % 512, state.tx_rb.rb.id, state.tx_rb.rb.reg_addr))]; ensures public(new_state); { reveal_mod4(); reveal_mod16(); reveal_mod128(); reveal_div16(); lemma_2toX(); var Ring:ring_buffer := state.tx_rb.rb; //-debug_print(0x60, Ring.base); //- debug_print(0x84, Ring.tail); //- //- Determine how much padding we need to add to meet minimal Ethernet packet size (if any). //- var Padding := []; if (|Headers| + |Data| < 60) { Padding := SequenceOfZerosIterative(60 - |Headers| - |Data|); } //- //- Write the packet data to the buffer indicated by the tail pointer. //- The tail pointer is the index of the next descriptor in the circular //- queue beyond that which has already been submitted to the hardware. //- //- The data buffers start at total_desc_bytes above the base address. //- Ring.tail is an index into the array, and each buffer is 2KB in size. //- var PacketBuffer := Ring.base + total_desc_bytes() + Ring.tail * 2048; CopyPacketToBuffer(PacketBuffer, Headers + Data + Padding); update_tx_descriptor(state.tx_rb, |Headers| + |Data| + |Padding|); //- //- Find the next entry in the descriptor ring. //- var NextIndex := (Ring.tail + 1) % 512; //- ModInstruction(Ring.tail + 1, 512); //-lemma_mod_512(Ring.tail + 1); assert NextIndex == (Ring.tail + 1) % 512; assert 0 <= NextIndex < 512; //- //- Before advancing the tail descriptor, make sure the hardware is done //- with the next entry. //- wait_for_available_tx_buffer(state.tx_rb, NextIndex); tx_cleanup(state.tx_rb, NextIndex); //- //- Update the ring buffer state that we pass around. //- var NewRing := tx_ring_buffer_build(ring_buffer_build(Ring.base, Ring.size, Ring.head, NextIndex, Ring.id, Ring.reg_addr)); new_state := state[tx_rb := NewRing]; } //- //- Advance a descriptor pointer to the next descriptor in the ring. //- method AdvanceDescriptorIndex(Index:int) returns (NewIndex:int) requires num_descriptors() == 512; requires 0 <= Index < 512; requires public(Index); ensures 0 <= NewIndex < 512; ensures public(NewIndex); { ghost var OldIndex := Index; NewIndex := (Index + 1) % 512; //-lemma_mod_512(OldIndex + 1); assert NewIndex == (OldIndex + 1) % 512; } //-method check_for_eop(TailDesc:int,TailIndex:int,rx_rb:rx_ring_buffer) returns (NewTailIndex:int, EndOfPacket:bool, Success:bool, NewData:seq) //- requires 0 <= TailIndex < 512 && rx_rb.rb.base + 16 * TailIndex < rx_rb.rb.base + rx_rb.rb.size; //- requires valid_ring_buffer(rx_rb.rb); //- requires public(TailDesc); //- requires public(rx_rb); //- ensures 0 <= NewTailIndex < 512; //- && rx_rb.rb.base + 16 * NewTailIndex < rx_rb.rb.base + rx_rb.rb.size; //- ensures Success ==> IsByteSeq(NewData); //- ensures public(NewTailIndex); //- ensures public(EndOfPacket); //- ensures public(Success); //- ensures public(NewData); //-{ //- //- //- //- Receive descriptor format. //- //- See Table 3-1 and 3-2 in Section 3.2.3. //- //- //- //- Bytes 0 to 7 of the receive descriptor contain the address of its //- //- corresponding buffer, which we never change after initialization. //- //- //- //- Bytes 8 and 9 contain the length of the data received into this descriptor's buffer. //- //- Bytes 10 and 11 contain the Packet Checksum, which we currently do not use. //- //- Byte 12 is the Status field (See Section 3.2.3.1): //- //- Bit 0: Indicates whether the hardware is Done with this Descriptor (DD). //- //- Bit 1: Indicates whether this descriptor is the End Of Packet (EOP). //- //- Bit 2: Ignore Checksum Indication (IXSM), which we currently do not use. //- //- Bit 3: VLAN related. We do not use. //- //- Bit 4: Reserved bit. We ignore it. //- //- Bit 5: Indicates whether the TCP CheckSum (TCPCS) was calculated on the packet. //- //- Bit 6: Indicates whether the IP CheckSum (IPCS) was calculated on the packet. //- //- Bit 7: Indicates whether the packet Passed an In-exact Filter (PIF). //- //- Byte 13 is the Errors field, which we currently do not use (note we do not store bad packets). //- //- Bytes 14 and 15 is the Special field (VLAN related, we do not use). //- //- //- //- We read 32 bits at a time, so we read bytes 8-11 in one operation, and 12-14 in another. //- //- //- //- //- //- //- Check the Descriptor Done (DD) bit in the Status field. //- //- //- var WordContainingStatus := DeviceMemLoad(TailDesc + 12); //- Bytes 12-14. //- var DDBit := Asm_BitwiseAnd(WordContainingStatus, 1); //- Bit 0. //- NewData := []; //- if (DDBit == 1) { //- var WordContainingLength := DeviceMemLoad(TailDesc + 8); //- Bytes 8-11. //- var Length := TruncateToWord16(WordContainingLength); //- Bytes 8-9. //- //- var PacketBuffer := rx_rb.rb.base + total_desc_bytes() + TailIndex * 2048; //- var ReadOkay, NewData := CopyBufferToPacket(PacketBuffer, Length); //- //- if (!ReadOkay || (|NewData| >= 0x10000)) { //- Success := false; //- NewData := []; //- } //- //- //- //- //- Clear out the status field before giving this descriptor back to the hardware. //- //- Note we still have a copy of the status value in WordContainingStatus. //- //- //- DeviceMemStore(TailDesc + 12, 0); //- //- //- //- //- Tell the hardware that we are done with all descriptors preceeding this one in the ring. //- //- TODO: Only do this after we reach end of packet? Optimization trade-off, not a correctness issue. //- //- //- PciMemStore(rx_rb.rb.id, register_rx_desc_tail(rx_rb.rb.reg_addr), TailIndex); //- //- //- //- //- Was this descriptor the end of the current packet? //- //- If not, proceed to the next descriptor in the ring. //- //- //- var Eop := Asm_BitwiseAnd(WordContainingStatus, 2); //- Bit 1. //- if (Eop > 0) { //- EndOfPacket := true; //- } //- else //- { //- NewTailIndex := AdvanceDescriptorIndex(TailIndex); //- } //- } //- //-} //- //- //-method NetIfReceive(state:network_state) //- returns (Success:bool, new_state:network_state, Data:seq) //- requires valid_network_state(state); //- requires public(state); //- requires num_descriptors() == 512; //- requires bytes_per_buffer() == 2048; //- ensures valid_network_state(new_state); //- ensures public(new_state); //- ensures Success ==> IsByteSeq(Data); //- ensures public(Success); //- ensures public(Data); //-{ //- reveal_mod4(); //- reveal_mod16(); //- reveal_mod128(); //- reveal_div16(); //- //- lemma_2toX(); //- //- Success := true; //- Data := []; //- //- var Ring := state.rx_rb.rb; //- //- //-debug_print(0x72, Ring.base); //- //- //- //- //- The next descriptor we should read is *the one after* the current tail pointer. //- //- //- var TailIndex:int := AdvanceDescriptorIndex(Ring.tail); //- //- //- //- //- Wait for the hardware to be done with this descriptor. //- //- Note that receipt of a single packet can result in the use of multiple descriptors, //- //- so we loop until we find a descriptor with the End-Of-Packet bit set. //- //- //- var EndOfPacket:bool := false; //- while (!EndOfPacket) //- decreases *; //- invariant IsByteSeq(Data); //- invariant valid_ring_buffer(Ring); //- invariant public(Ring); //- invariant 0 <= TailIndex < 512 && Ring.base + 16 * TailIndex < Ring.base + Ring.size; //- invariant |Data| < power2(16); //- invariant public(Data); //- invariant public(TailIndex); //- invariant public(Success); //- invariant public(EndOfPacket); //- { //- lemma_2toX(); //- //- //- //- //- Convert tail index to descriptor address. //- //- //- var TailDesc := Ring.base + 16 * TailIndex; //- var NewData:seq; //- TailDesc, EndOfPacket, Success, NewData := check_for_eop(TailDesc, TailIndex, state.rx_rb); //- Data := Data + NewData; //- } //- //- var NewRing := rx_ring_buffer_build(ring_buffer_build(Ring.base, Ring.size, Ring.head, TailIndex, Ring.id, Ring.reg_addr)); //- new_state := state[rx_rb := NewRing]; //-} //- //- Check the Descriptor Done (DD) bit in the Status field. //- method check_desc_dd(src:int) returns (DD:bool, Length:int, Eop:bool) requires DeviceMemAddr() <= src + 4 <= DeviceMemAddr() + DeviceMemSize(); requires DeviceMemAddr() <= src + 8 + 4 <= DeviceMemAddr() + DeviceMemSize(); requires DeviceMemAddr() <= src + 12 + 4 <= DeviceMemAddr() + DeviceMemSize(); requires Word32(src + 8); requires Word32(src + 12); requires public(src); ensures Word16(Length); ensures public (DD); ensures public(Length); ensures public(Eop); { DD := false; Length := 0; var WordContainingStatus := DeviceMemLoad(src + 12); //- Bytes 12-14. var DDBit := Asm_BitwiseAnd(WordContainingStatus, 1); //- Bit 0. if (DDBit == 1) { DD := true; var WordContainingLength := DeviceMemLoad(src + 8); //- Bytes 8-11. Length := TruncateToWord16(WordContainingLength); //- Bytes 8-9. } //- Was this descriptor the end of the current packet? var EopBit := Asm_BitwiseAnd(WordContainingStatus, 2); //- Bit 1. if EopBit > 0 { Eop := true; } else { Eop := false; } } method reset_descriptor(desc:int,rx_rb:rx_ring_buffer, TailIndex:int) requires DeviceMemAddr() <= desc + 12 && desc + 12 + 4 <= DeviceMemAddr() + DeviceMemSize(); requires Word32(desc + 12); requires valid_ring_buffer(rx_rb.rb); requires Word32(TailIndex); requires public(desc); requires public(rx_rb); requires public(TailIndex); { //- //- Clear out the status field before giving this descriptor back to the hardware. //- Note we still have a copy of the status value in WordContainingStatus. //- DeviceMemStore(desc + 12, 0); //- //- Tell the hardware that we are done with all descriptors preceeding this one in the ring. //- PciMemStore(rx_rb.rb.id, register_rx_desc_tail(rx_rb.rb.reg_addr), TailIndex); } method receive_loop_body(rx_rb:rx_ring_buffer, TailIndex:int) returns (NewTailIndex:int, EndOfPacket:bool, NewData:seq, Success:bool) requires valid_ring_buffer(rx_rb.rb); requires 0 <= TailIndex < 512; requires rx_rb.rb.base + 16 * TailIndex < rx_rb.rb.base + rx_rb.rb.size; requires public(rx_rb); requires public(TailIndex); ensures 0 <= NewTailIndex < 512; ensures IsByteSeq(NewData); ensures public(NewTailIndex); ensures public(EndOfPacket); ensures public(NewData); ensures public(Success); { lemma_2toX(); reveal_mod16(); NewTailIndex := TailIndex; NewData := []; EndOfPacket := false; Success := true; //- //- Convert tail index to descriptor address. //- var TailDesc := rx_rb.rb.base + 16 * TailIndex; //- //- Receive descriptor format. //- See Table 3-1 and 3-2 in Section 3.2.3. //- //- Bytes 0 to 7 of the receive descriptor contain the address of its //- corresponding buffer, which we never change after initialization. //- //- Bytes 8 and 9 contain the length of the data received into this descriptor's buffer. //- Bytes 10 and 11 contain the Packet Checksum, which we currently do not use. //- Byte 12 is the Status field (See Section 3.2.3.1): //- Bit 0: Indicates whether the hardware is Done with this Descriptor (DD). //- Bit 1: Indicates whether this descriptor is the End Of Packet (EOP). //- Bit 2: Ignore Checksum Indication (IXSM), which we currently do not use. //- Bit 3: VLAN related. We do not use. //- Bit 4: Reserved bit. We ignore it. //- Bit 5: Indicates whether the TCP CheckSum (TCPCS) was calculated on the packet. //- Bit 6: Indicates whether the IP CheckSum (IPCS) was calculated on the packet. //- Bit 7: Indicates whether the packet Passed an In-exact Filter (PIF). //- Byte 13 is the Errors field, which we currently do not use (note we do not store bad packets). //- Bytes 14 and 15 is the Special field (VLAN related, we do not use). //- //- We read 32 bits at a time, so we read bytes 8-11 in one operation, and 12-14 in another. //- //- //- Check the Descriptor Done (DD) bit in the Status field. //- var DD, Length, Eop := check_desc_dd(TailDesc); if (DD) { var PacketBuffer := rx_rb.rb.base + total_desc_bytes() + TailIndex * 2048; var ReadOkay:bool; ReadOkay, NewData := CopyBufferToPacket(PacketBuffer, Length); if (!ReadOkay || (|NewData| >= 0x10000)) { Success := false; NewData := []; } reset_descriptor(TailDesc, rx_rb, TailIndex); //- //- Was this descriptor the end of the current packet? //- If not, proceed to the next descriptor in the ring. //- if (Eop) { EndOfPacket := true; } else { NewTailIndex := AdvanceDescriptorIndex(TailIndex); } } } method NetIfReceive(state:network_state) returns (Success:bool, new_state:network_state, Data:seq) requires valid_network_state(state); requires public(state); requires num_descriptors() == 512; requires bytes_per_buffer() == 2048; ensures valid_network_state(new_state); ensures Success ==> IsByteSeq(Data); ensures public(Success); ensures public(new_state); ensures public(Data); { //- reveal_mod4(); //- reveal_mod16(); //- reveal_mod128(); reveal_div16(); lemma_2toX(); Success := true; Data := []; //-debug_print(0x72, state.rx_rb.rb.base); //- //- The next descriptor we should read is *the one after* the current tail pointer. //- var TailIndex:int := AdvanceDescriptorIndex(state.rx_rb.rb.tail); //- //- Wait for the hardware to be done with this descriptor. //- Note that receipt of a single packet can result in the use of multiple descriptors, //- so we loop until we find a descriptor with the End-Of-Packet bit set. //- var EndOfPacket:bool := false; while (!EndOfPacket) decreases *; invariant IsByteSeq(Data); invariant valid_ring_buffer(state.rx_rb.rb); invariant 0 <= TailIndex < 512 && state.rx_rb.rb.base + 16 * TailIndex < state.rx_rb.rb.base + state.rx_rb.rb.size; invariant |Data| < power2(16); invariant public(state); invariant public(Data); invariant public(TailIndex); invariant public(Success); invariant public(EndOfPacket); { var NewData:seq; TailIndex, EndOfPacket, NewData, Success := receive_loop_body(state.rx_rb, TailIndex); Data := Data + NewData; if !Success || |Data| >= 0x10000 { Success := false; Data := []; } } var NewRing := rx_ring_buffer_build(ring_buffer_build(state.rx_rb.rb.base, state.rx_rb.rb.size, state.rx_rb.rb.head, TailIndex, state.rx_rb.rb.id, state.rx_rb.rb.reg_addr)); new_state := state[rx_rb := NewRing]; } ================================================ FILE: ironclad-apps/src/Dafny/Drivers/TPM/.gitignore ================================================ *.bpl *.log ================================================ FILE: ironclad-apps/src/Dafny/Drivers/TPM/tpm-device.s.dfy ================================================ include "../../Libraries/Math/power2.s.dfy" include "../../Libraries/Util/integer_sequences.s.dfy" include "../../Libraries/Util/relational.s.dfy" include "../../Libraries/Crypto/Hash/sha1.s.dfy" include "../IO/io_mem.s.dfy" //-///////////////////////////////////// //- App Spec Interface //-///////////////////////////////////// //- App must specify an invariant on values it wants to write to the TPM then read later with assurance of integrity static function TPM_app_policy_okay_to_trust(trusted_data:seq) : bool //-////////////////////////////////////////////////////////// //- Basic functions and datatypes //- (Note: Sec. 2.1.1 of Part 2: Everything is big endian) //-////////////////////////////////////////////////////////// datatype CommandState = Idle | AlmostReady | Ready | CmdReception | Executing | CmdComplete; datatype TPM_struct = TPM_build( PCR_19 : seq>, //- Since we allow extension of this PCR, this represents the sequence of things extended into the PCR cmd_state : CommandState, cmd_buf : seq, reply_buf : seq, random_index : int //- Tracks our current position in the stream of randomness from the TPM ); static predicate TPM_valid(aTPM:TPM_struct) { IsByteSeq(aTPM.cmd_buf) && IsByteSeq(aTPM.reply_buf) } static predicate TPMs_match(TPM1:TPM_struct, TPM2:TPM_struct) { TPM1.PCR_19 == TPM2.PCR_19 && TPM1.random_index == TPM2.random_index } //-///////////////////////////////////// //- Verve Entry Interface //-///////////////////////////////////// //- Invariant that must be true on Verve entry, and that remains true throughout TPM executions static predicate TPM_satisfies_integrity_policy(aTPM:TPM_struct) { TPM_valid(aTPM) } //- Verve entry should include: //- requires TPM_valid(TPM); //- requires TPM_satisfies_integrity_policy(TPM); //- requires TPM.PCR_19 == []; //- We model the infinite stream of randomness as a series of "constants" returned //- by this function that are discovered by calls to read_random static function TPM_random_byte(index:int) : int static function TPM_random_bytes (old_random_index:int, new_random_index:int) : seq decreases new_random_index - old_random_index; { if old_random_index >= new_random_index then [] else TPM_random_bytes(old_random_index, new_random_index-1) + [TPM_random_byte(new_random_index-1)] } //- We only use this for 17 & 18, which don't change while we're executing static function PCR_val(index:int) : seq //- Tracks whether we have taken control of the TPM at access level 3 //- Tracked via a function, since it cannot change while we execute static predicate Locality3_requested() static predicate Locality3_obtained() ghost var{:readonly} TPM:TPM_struct; //- Condenses all of the public information in the TPM //- I.e., public = PCR_19 static function TPM_public(aTPM:TPM_struct, s:seq) : bool { (exists i:int | 0 <= i < |aTPM.PCR_19| :: s == aTPM.PCR_19[i]) } /* TODO: dafnycc static function TPM_public(aTPM:TPM_struct) : set> { (set i:int | 0 <= i < |aTPM.PCR_19| :: aTPM.PCR_19[i]) } */ /******************************************************** * Low-level TPM interactions ********************************************************/ ghost method {:axiom} TPM_enable_request_access() requires IoMemPerm.Null?; modifies this`IoMemPerm; ensures Locality3_requested(); ensures IoMemPerm == IoWriteAddr(0xFED43000, 2); //- movb 2 -> 0xFED43000 (0xFED4 || TPM_ACCESS_3 (3000h)) ghost method {:axiom} TPM_enable_check_access_status() returns (status:int) requires IoMemPerm.Null?; requires Locality3_requested(); modifies this`IoMemPerm; ensures Word32(status); ensures |BEWordToBitSeq(status)| == 32; ensures BEWordToBitSeq(status)[26] == 1 ==> Locality3_obtained(); //- bit 5 = activeLocality ensures IoMemPerm == IoReadAddr(0xFED43000, status); //- See Table 16 of the TCG PC Client Spec 1.20 ghost method {:axiom} TPM_enable_issue_command_ready() requires IoMemPerm.Null?; requires Locality3_obtained(); requires TPM_valid(TPM); ensures old(TPM.cmd_state.Idle? || TPM.cmd_state.AlmostReady?) ==> TPM.cmd_state.AlmostReady? || TPM.cmd_state.Ready?; ensures old(TPM.cmd_state.Ready?) ==> TPM.cmd_state == Ready; ensures old(TPM.cmd_state.CmdReception? || TPM.cmd_state.Executing? || TPM.cmd_state.CmdComplete?) ==> (TPM.cmd_state.Idle? || TPM.cmd_state.AlmostReady? || TPM.cmd_state.Ready?); //- Depends on TPM impl and timeout values ensures TPM_valid(TPM); modifies this`TPM; modifies this`IoMemPerm; ensures TPM == old(TPM)[cmd_state := TPM.cmd_state][cmd_buf := []][reply_buf := []]; ensures IoMemPerm == IoWriteAddr(0xFED43018, 0x40); ghost method {:axiom} TPM_enable_check_command_ready() returns (status:int) requires IoMemPerm.Null?; requires Locality3_obtained(); requires TPM_valid(TPM); requires TPM.cmd_state.AlmostReady? || TPM.cmd_state.Ready?; ensures Word32(status); ensures |BEWordToBitSeq(status)| == 32; ensures BEWordToBitSeq(status)[25] == 1 ==> TPM.cmd_state.Ready?; //- bit 6 = commandReady ensures BEWordToBitSeq(status)[25] != 1 ==> TPM.cmd_state == old(TPM.cmd_state); ensures TPM_valid(TPM); modifies this`TPM; modifies this`IoMemPerm; ensures TPM == old(TPM)[cmd_state := TPM.cmd_state]; ensures IoMemPerm == IoReadAddr(0xFED43018, status); ghost method {:axiom} TPM_enable_write_FIFO(c:int) requires IoMemPerm.Null?; requires Locality3_obtained(); requires TPM_valid(TPM); requires IsByte(c); requires TPM.cmd_state.Ready? || TPM.cmd_state.CmdReception?; ensures TPM_valid(TPM); modifies this`TPM; modifies this`IoMemPerm; ensures TPM == old(TPM)[cmd_state := CmdReception()][cmd_buf := old(TPM.cmd_buf) + [c]]; ensures IoMemPerm == IoWriteAddr(0xFED43024, c); ghost method {:axiom} TPM_enable_go() requires IoMemPerm.Null?; requires Locality3_obtained(); requires TPM_valid(TPM); requires power2(32) == 0x100000000; requires forall new_TPM : TPM_struct :: async_TPM_execution(TPM, new_TPM) ==> TPM_satisfies_integrity_policy(new_TPM); requires TPM.cmd_state.CmdReception?; //-dafnycc requires forall new_TPM : TPM_struct :: TPM_valid(new_TPM) && async_TPM_execution(TPM, new_TPM) ==> TPM_public(left(new_TPM)) == TPM_public(right(new_TPM)); //-Wait for SymDiff: requires forall new_TPM : TPM_struct :: TPM_valid(new_TPM) && async_TPM_execution(TPM, new_TPM) ==> forall s :: TPM_public(left(new_TPM), s) == TPM_public(right(new_TPM), s); ensures TPM_valid(TPM); modifies this`TPM; modifies this`IoMemPerm; ensures TPM == old(TPM)[cmd_state := Executing]; ensures IoMemPerm == IoWriteAddr(0xFED43018, 0x20); ghost method {:axiom} TPM_enable_check_data_available() returns (r:int) requires IoMemPerm.Null?; requires Locality3_obtained(); requires TPM_valid(TPM); requires TPM.cmd_state.Executing? || TPM.cmd_state.CmdComplete?; requires power2(32) == 0x100000000; ensures TPM_valid(TPM); ensures old(TPM.cmd_state.Executing?) ==> async_TPM_execution(old(TPM), TPM) //- May bump us to CmdComplete, or may leave us in Executing && (r == 0x90 <==> TPM.cmd_state.CmdComplete?); //- 0x90 = TIS_STS_VALID (0x80) + TIS_STS_DATA_AVAIL (0x10) ensures old(TPM.cmd_state.CmdComplete?) ==> (r == 0x90 ==> |TPM.reply_buf| > 0) && old(TPM) == TPM; ensures old(TPM.cmd_state.CmdComplete?) ==> (r == 0x80 ==> |TPM.reply_buf| == 0) && old(TPM) == TPM; modifies this`TPM; //- Modifications specified by Async_TPM, so no additional details below modifies this`IoMemPerm; ensures IoMemPerm == IoReadAddr(0xFED43018, r); ghost method {:axiom} TPM_enable_read_FIFO() returns (c:int) requires IoMemPerm.Null?; requires Locality3_obtained(); requires TPM_valid(TPM); requires TPM.cmd_state.CmdComplete? && |TPM.reply_buf| > 0; ensures TPM_valid(TPM); ensures old(TPM.reply_buf) == [c] + TPM.reply_buf; ensures IsByte(c); modifies this`TPM; modifies this`IoMemPerm; ensures TPM == old(TPM)[reply_buf := TPM.reply_buf]; ensures IoMemPerm == IoReadAddr(0xFED43024, c); static predicate async_TPM_execution(old_TPM:TPM_struct, new_TPM:TPM_struct) requires IsByteSeq(old_TPM.cmd_buf); { //- We execute a valid command (IsByteSeq(new_TPM.reply_buf) && |new_TPM.reply_buf| > 0 && TPM_executed_some_command(old_TPM, new_TPM)) || //- Or there's a valid command present, but the TPM is still executing it (valid_cmd_present(old_TPM) && old_TPM == new_TPM) || //- Or there's an unexpected command, so we know nothing about the TPM's state !valid_cmd_present(old_TPM) //- havoc! } /*************************************** * TPM Tags ***************************************/ static function TPM_TAG_RQU_COMMAND() : seq { [ 0, 0xC1 ] } static function TPM_TAG_RQU_AUTH1_COMMAND() : seq { [ 0, 0xC2 ] } static function method TPM_TAG_RSP_COMMAND() : seq { [ 0, 0xC4 ] } static function method TPM_TAG_RSP_AUTH1_COMMAND() : seq { [ 0, 0xC5 ] } /*************************************** * TPM Command Ordinals ***************************************/ static function TPM_ORD_Extend() : int { 0x14 } static function TPM_ORD_Quote2() : int { 0x3E } static function TPM_ORD_GetRandom() : int { 0x46 } static function TPM_ORD_PcrRead() : int { 0x15 } static function TPM_ORD_OIAP() : int { 0x0A } static function TPM_ORD_LoadKey2() : int { 0x41 } /*************************************** * TPM return codes ***************************************/ static function method TPM_SUCCESS() : int { 0 } /******************************************************** * TPM structure parsing ********************************************************/ static function method PCR_SELECTION_covering_PCRs_17_and_18() : seq { [ 0, 3, 0, 0, 6 ] //- pcrSelection = size (0x0003), PCR bit map. Selects PCR 17 & 18 from byte 2 (0-indexed } static function method PCR_SELECTION_covering_PCRs_17_through_19() : seq { [ 0, 3, 0, 0, 14 ] //- pcrSelection = size (0x0003), PCR bit map. Selects PCR 17, 18, 19 from byte 2 (0-indexed } datatype PCRInfoShort = PCRInfoShort17And18_c(pcrs_17_18_digest:seq) | PCRInfoShort17Through19_c(pcrs_17_18_19_digest:seq) | PCRInfoShortInvalid_c() static function parse_PCR_info_short(s:seq) : PCRInfoShort { if |s| != 26 then PCRInfoShortInvalid_c() else ( var fields := s[5 :1 :20 ]; var pcr_selection, localities_bit_vector, pcrs_digest := fields[0], fields[1], fields[2]; //- Note: we don't care about the localities: NVRAM uses PCR protections and it's irrelevant for Quote if pcr_selection == PCR_SELECTION_covering_PCRs_17_through_19() then PCRInfoShort17Through19_c(pcrs_digest) else if pcr_selection == PCR_SELECTION_covering_PCRs_17_and_18() then PCRInfoShort17And18_c(pcrs_digest) else PCRInfoShortInvalid_c() ) } static predicate is_TPM_COMPOSITE_HASH(h:seq, PCR_17:seq, PCR_18:seq) { var pcr_composite := PCR_SELECTION_covering_PCRs_17_and_18() + [0, 0, 0, 40] + //- size of next two PCRs PCR_17 + PCR_18; IsByteSeq(pcr_composite) && (var pcr_composite_bits := BEByteSeqToBitSeq(pcr_composite); IsBitSeq(pcr_composite_bits) && |pcr_composite_bits| < power2(64) && h == BEWordSeqToByteSeq(SHA1(pcr_composite_bits))) } static predicate Verve_quote(pcr_info:seq, sig:seq, nonce:seq, PCR_19_history:seq>) /******************************************************** * TPM command parsing ********************************************************/ datatype TPMCommand = TPMCommandQuote2_c(nonce_external:seq, key_handle:seq, auth_handle:seq) | TPMCommandReadPCR17Or18_c(pcr_to_read:int) | TPMCommandExtendPCR19_c(value_to_extend:seq) | TPMCommandGetRandom_c(random_bytes:int) | TPMCommandOIAP_c() | TPMCommandLoadKey2_c() | TPMCommandInvalid_c() static function parse_TPM_command_quote2(s:seq) : TPMCommand requires IsByteSeq(s); { if |s| != 85 then TPMCommandInvalid_c() else ( var fields := s[10 :4 :20 :5 :1 :4 :20 :1 :20 ]; var _, key_handle, nonce_external, pcr_selection, add_version, auth_handle, nonce_odd, continue_auth_session, priv_auth := fields[0], fields[1], fields[2], fields[3], fields[4], fields[5], fields[6], fields[7], fields[8] ; if pcr_selection == PCR_SELECTION_covering_PCRs_17_through_19() && add_version == [1] && //- When TRUE add TPM_CAP_VERSION_INFO to the output continue_auth_session == [1] then //- continueAuthSession? TPMCommandQuote2_c(nonce_external, key_handle, auth_handle) else TPMCommandInvalid_c() ) } static function parse_TPM_command_read_PCR_17_or_18(s:seq) : TPMCommand requires IsByteSeq(s); { if |s| != 14 then TPMCommandInvalid_c() else ( var pcr := BEByteSeqToInt(s[10..14]); if pcr == 17 || pcr == 18 then TPMCommandReadPCR17Or18_c(pcr) else TPMCommandInvalid_c() ) } static function parse_TPM_command_extend_PCR_19(s:seq) : TPMCommand requires IsByteSeq(s); { if |s| != 34 then TPMCommandInvalid_c() else ( var fields := s[10 :4 :20 ]; var _, pcr, data := fields[0], fields[1], fields[2] ; if BEByteSeqToInt(pcr) == 19 then TPMCommandExtendPCR19_c(data) else TPMCommandInvalid_c() ) } static function parse_TPM_command_get_random(s:seq) : TPMCommand requires IsByteSeq(s); { if |s| != 14 then TPMCommandInvalid_c() else ( var random_bytes := BEByteSeqToInt(s[10..14]); TPMCommandGetRandom_c(random_bytes) ) } static function parse_TPM_command_OIAP(s:seq) : TPMCommand requires IsByteSeq(s); { if |s| != 10 then TPMCommandInvalid_c() else TPMCommandOIAP_c() //- Nothing to the command but the header } static function parse_TPM_command_LoadKey2(s:seq) : TPMCommand requires IsByteSeq(s); { if |s| < 59 then TPMCommandInvalid_c() else TPMCommandLoadKey2_c() //- Nothing to track for security purposes } static function parse_TPM_command(s:seq) : TPMCommand requires IsByteSeq(s); { if |s| < 10 then TPMCommandInvalid_c() else ( var fields := s[2 :4 :4 ]; var tag, length, command := fields[0], fields[1], fields[2]; var command_code := BEByteSeqToInt(command); if BEByteSeqToInt(length) != |s| then TPMCommandInvalid_c() else if tag == TPM_TAG_RQU_COMMAND() then ( if command_code == TPM_ORD_PcrRead() then parse_TPM_command_read_PCR_17_or_18(s) else if command_code == TPM_ORD_Extend() then parse_TPM_command_extend_PCR_19(s) else if command_code == TPM_ORD_GetRandom() then parse_TPM_command_get_random(s) else if command_code == TPM_ORD_OIAP() then parse_TPM_command_OIAP(s) else if command_code == TPM_ORD_LoadKey2() then parse_TPM_command_LoadKey2(s) else TPMCommandInvalid_c() ) else if tag == TPM_TAG_RQU_AUTH1_COMMAND() then ( if command_code == TPM_ORD_Quote2() then parse_TPM_command_quote2(s) else if command_code == TPM_ORD_LoadKey2() then parse_TPM_command_LoadKey2(s) else TPMCommandInvalid_c() ) else TPMCommandInvalid_c() ) } static predicate valid_cmd(s:seq) requires IsByteSeq(s); { !(parse_TPM_command(s).TPMCommandInvalid_c?) } static predicate {:autoReq} valid_cmd_present(aTPM:TPM_struct) { valid_cmd(aTPM.cmd_buf) } /******************************************************** * TPM reply parsing ********************************************************/ datatype TPMReply = TPMReplyQuote2_c(nonce_even:seq, pcr_info:seq, sig:seq) | TPMReplyReadPCR17Or18_c(pcr_value_read:seq) | TPMReplyExtendPCR19_c() | TPMReplyGetRandom_c(randoms:seq) | TPMReplyOIAP() | TPMReplyLoadKey2() | TPMReplyInvalid_c() static predicate is_TPM_reply_header_ok(s:seq, expected_tag:seq) requires IsByteSeq(s); { |s| >= 10 && (var fields := s[2 :4 :4 ]; var tag, length, return_code := fields[0], BEByteSeqToInt(fields[1]), BEByteSeqToInt(fields[2]) ; tag == expected_tag && length == |s| && return_code == TPM_SUCCESS()) } static function parse_TPM_reply_quote2(s:seq) : TPMReply requires IsByteSeq(s); { if !is_TPM_reply_header_ok(s,TPM_TAG_RSP_AUTH1_COMMAND()) || |s| < 40 then TPMReplyInvalid_c() else ( var f_a := s[10 :26 :4 ]; var _, pcr_info_bytes, version_info_size := f_a[0], f_a[1], BEByteSeqToInt(f_a[2]) ; var pcr_info := parse_PCR_info_short(pcr_info_bytes); if !pcr_info.PCRInfoShort17Through19_c? || |s| < 44 + version_info_size || version_info_size < 0 then TPMReplyInvalid_c() else ( var f_b := s[40 :version_info_size :4 ]; var _, version_info, sig_size := f_b[0], f_b[1], BEByteSeqToInt(f_b[2]) ; if |s| != 85 + version_info_size + sig_size || sig_size < 0 then TPMReplyInvalid_c() else ( var f_c := s[44+version_info_size :sig_size :20 :1 :20 ]; var _, sig, nonce_even, continue_session, res_auth := f_c[0], f_c[1], f_c[2], f_c[3], f_c[4] ; if continue_session == [1] then TPMReplyQuote2_c(nonce_even, pcr_info_bytes, sig) else TPMReplyInvalid_c() ) ) ) } static function parse_TPM_reply_read_PCR_17_or_18(s:seq) : TPMReply requires IsByteSeq(s); { if !is_TPM_reply_header_ok(s,TPM_TAG_RSP_COMMAND()) || |s| != 30 then TPMReplyInvalid_c() else TPMReplyReadPCR17Or18_c(s[10..30]) } static function parse_TPM_reply_extend_PCR_19(s:seq) : TPMReply requires IsByteSeq(s); { if !is_TPM_reply_header_ok(s,TPM_TAG_RSP_COMMAND()) || |s| != 30 then TPMReplyInvalid_c() else TPMReplyExtendPCR19_c() } static function parse_TPM_reply_get_random(s:seq) : TPMReply requires IsByteSeq(s); { if !is_TPM_reply_header_ok(s,TPM_TAG_RSP_COMMAND()) || |s| < 14 then TPMReplyInvalid_c() else ( var random_bytes_size := BEByteSeqToInt(s[10..14]); if |s| != 14 + random_bytes_size || random_bytes_size < 0 then TPMReplyInvalid_c() else TPMReplyGetRandom_c(s[14..14+random_bytes_size]) ) } static function parse_TPM_reply_OIAP(s:seq) : TPMReply requires IsByteSeq(s); { if !is_TPM_reply_header_ok(s,TPM_TAG_RSP_COMMAND()) || |s| != 34 then TPMReplyInvalid_c() else TPMReplyOIAP() } static function parse_TPM_reply_LoadKey2(s:seq) : TPMReply requires IsByteSeq(s); { if !is_TPM_reply_header_ok(s, TPM_TAG_RSP_AUTH1_COMMAND()) || |s| != 55 then TPMReplyInvalid_c() else TPMReplyLoadKey2() } /******************************************************** * Semantic-level TPM Commands ********************************************************/ static predicate TPM_executed_extend_PCR_19(old_TPM:TPM_struct, new_TPM:TPM_struct) requires IsByteSeq(old_TPM.cmd_buf); requires IsByteSeq(new_TPM.reply_buf); { var cmd := parse_TPM_command(old_TPM.cmd_buf); var reply := parse_TPM_reply_extend_PCR_19(new_TPM.reply_buf); cmd.TPMCommandExtendPCR19_c? && (var data := cmd.value_to_extend; //- The PCR was successfully updated (reply.TPMReplyExtendPCR19_c? ==> new_TPM.PCR_19 == old_TPM.PCR_19 + [data]) //- If it was updated at all, it was updated with data && (new_TPM.PCR_19 == old_TPM.PCR_19 || new_TPM.PCR_19 == old_TPM.PCR_19 + [data]) && |new_TPM.reply_buf| > 0 && new_TPM == old_TPM[cmd_state := CmdComplete()][reply_buf := new_TPM.reply_buf][PCR_19 := new_TPM.PCR_19]) } static predicate TPM_executed_quote2(old_TPM:TPM_struct, new_TPM:TPM_struct) requires IsByteSeq(old_TPM.cmd_buf); requires IsByteSeq(new_TPM.reply_buf); { var cmd := parse_TPM_command(old_TPM.cmd_buf); var reply := parse_TPM_reply_quote2(new_TPM.reply_buf); cmd.TPMCommandQuote2_c? && (reply.TPMReplyQuote2_c? ==> Verve_quote(reply.pcr_info, reply.sig, cmd.nonce_external, old_TPM.PCR_19)) && 0 < |new_TPM.reply_buf| <= power2(33) && new_TPM == old_TPM[cmd_state := CmdComplete()][reply_buf := new_TPM.reply_buf] } static predicate TPM_executed_get_random(old_TPM:TPM_struct, new_TPM:TPM_struct) requires IsByteSeq(old_TPM.cmd_buf); requires IsByteSeq(new_TPM.reply_buf); { var cmd := parse_TPM_command(old_TPM.cmd_buf); var reply := parse_TPM_reply_get_random(new_TPM.reply_buf); cmd.TPMCommandGetRandom_c? && (reply.TPMReplyGetRandom_c? ==> |reply.randoms| <= cmd.random_bytes && new_TPM.random_index == old_TPM.random_index + |reply.randoms| && (forall j :: 0 <= j < |reply.randoms| ==> reply.randoms[j] == TPM_random_byte(old_TPM.random_index + j))) && (reply.TPMReplyInvalid_c? ==> old_TPM.random_index == new_TPM.random_index) && new_TPM == old_TPM[cmd_state := CmdComplete()][reply_buf := new_TPM.reply_buf][random_index := new_TPM.random_index] } static predicate TPM_executed_read_PCR_17_or_18(old_TPM:TPM_struct, new_TPM:TPM_struct) requires IsByteSeq(old_TPM.cmd_buf); requires IsByteSeq(new_TPM.reply_buf); { var cmd := parse_TPM_command(old_TPM.cmd_buf); var reply := parse_TPM_reply_read_PCR_17_or_18(new_TPM.reply_buf); cmd.TPMCommandReadPCR17Or18_c? && (reply.TPMReplyReadPCR17Or18_c? ==> reply.pcr_value_read == PCR_val(cmd.pcr_to_read)) && new_TPM == old_TPM[cmd_state := CmdComplete()][reply_buf := new_TPM.reply_buf] } static predicate TPM_executed_OIAP(old_TPM:TPM_struct, new_TPM:TPM_struct) requires IsByteSeq(old_TPM.cmd_buf); requires IsByteSeq(new_TPM.reply_buf); { var cmd := parse_TPM_command(old_TPM.cmd_buf); var reply := parse_TPM_reply_OIAP(new_TPM.reply_buf); cmd.TPMCommandOIAP_c? && new_TPM == old_TPM //- Doesn't affect any of the TPM state we track } static predicate TPM_executed_LoadKey2(old_TPM:TPM_struct, new_TPM:TPM_struct) requires IsByteSeq(old_TPM.cmd_buf); requires IsByteSeq(new_TPM.reply_buf); { var cmd := parse_TPM_command(old_TPM.cmd_buf); var reply := parse_TPM_reply_LoadKey2(new_TPM.reply_buf); cmd.TPMCommandLoadKey2_c? && new_TPM == old_TPM //- Doesn't affect any of the TPM state we track } static predicate TPM_executed_some_command(old_TPM:TPM_struct, new_TPM:TPM_struct) requires IsByteSeq(old_TPM.cmd_buf); requires IsByteSeq(new_TPM.reply_buf); { TPM_executed_extend_PCR_19(old_TPM, new_TPM) || TPM_executed_quote2(old_TPM, new_TPM) || TPM_executed_get_random(old_TPM, new_TPM) || TPM_executed_read_PCR_17_or_18(old_TPM, new_TPM) || TPM_executed_OIAP(old_TPM, new_TPM) || TPM_executed_LoadKey2(old_TPM, new_TPM) } ================================================ FILE: ironclad-apps/src/Dafny/Drivers/TPM/tpm-device.s.dfy.disabled ================================================ include "../../Libraries/Math/power2.s.dfy" include "../../Libraries/Util/integer_sequences.s.dfy" include "../../Libraries/Util/relational.s.dfy" include "../../Libraries/Crypto/Hash/sha1.s.dfy" include "../IO/io_mem.s.dfy" /////////////////////////////////////// // App Spec Interface /////////////////////////////////////// // App must specify an invariant on values it wants to write to the TPM then read later with assurance of integrity static function TPM_app_policy_okay_to_trust(trusted_data:seq) : bool //////////////////////////////////////////////////////////// // Basic functions and datatypes // (Note: Sec. 2.1.1 of Part 2: Everything is big endian) //////////////////////////////////////////////////////////// datatype CommandState = Idle | AlmostReady | Ready | CmdReception | Executing | CmdComplete; datatype TPM_struct = TPM_build( PCR_19 : seq>, // Since we allow extension of this PCR, this represents the sequence of things extended into the PCR NVRAM : seq>, NV_locked : bool, // Is the TPM enforcing NV restrictions? NV_perms_ok : seq, cmd_state : CommandState, cmd_buf : seq, reply_buf : seq, random_index : int // Tracks our current position in the stream of randomness from the TPM ); static predicate TPM_valid(aTPM:TPM_struct) { |aTPM.NVRAM| == |aTPM.NV_perms_ok| && Word32(|aTPM.NVRAM|) && (forall i {:trigger IsByteSeqOfLen(aTPM.PCR_19[i], 20)} :: 0 <= i < |aTPM.PCR_19| ==> IsByteSeqOfLen(aTPM.PCR_19[i], 20)) // Must be sets of 20 bytes && IsByteSeq(aTPM.cmd_buf) && IsByteSeq(aTPM.reply_buf) && (forall a :: valid_nv_index(aTPM, a) ==> IsByteSeq(aTPM.NVRAM[a]) && Word32(|aTPM.NVRAM[a]|+14)) // Added +14 because size of read really must be a word } static predicate TPMs_match(TPM1:TPM_struct, TPM2:TPM_struct) { TPM1.PCR_19 == TPM2.PCR_19 && TPM1.NVRAM == TPM2.NVRAM && TPM1.NV_locked == TPM2.NV_locked && TPM1.NV_perms_ok == TPM2.NV_perms_ok && TPM1.random_index == TPM2.random_index } /////////////////////////////////////// // Verve Entry Interface /////////////////////////////////////// // Invariant that must be true on Verve entry, and that remains true throughout TPM executions static predicate TPM_satisfies_integrity_policy(aTPM:TPM_struct) { TPM_valid(aTPM) && (forall a :: 0 <= a < |aTPM.NVRAM| && aTPM.NV_perms_ok[a] && aTPM.NV_locked ==> |aTPM.NVRAM[a]| == NV_size() && (TPM_app_policy_okay_to_trust(aTPM.NVRAM[a]) || aTPM.NVRAM[a] == newly_created_NV_value())) } // Verve entry should include: // requires TPM_valid(TPM); // requires TPM_satisfies_integrity_policy(TPM); // requires TPM.PCR_19 == []; // We model the infinite stream of randomness as a series of "constants" returned // by this function that are discovered by calls to read_random static function TPM_random_byte(index:int) : int static function TPM_random_bytes (old_random_index:int, new_random_index:int) : seq decreases new_random_index - old_random_index; { if old_random_index >= new_random_index then [] else TPM_random_bytes(old_random_index, new_random_index-1) + [TPM_random_byte(new_random_index-1)] } // We only use this for 17 & 18, which don't change while we're executing static function PCR_val(index:int) : seq // Tracks whether we have taken control of the TPM at access level 3 // Tracked via a function, since it cannot change while we execute static predicate Locality3_requested() static predicate Locality3_obtained() ghost var{:readonly} TPM:TPM_struct; // "Constants" static function NV_size() : int { 256 } static predicate valid_nv_index(aTPM:TPM_struct, a:int) { 0 <= a < |aTPM.NVRAM| && 0 <= a < |aTPM.NV_perms_ok| } static function newly_created_NV_value() : seq { RepeatDigit(0xFF, NV_size()) } // Condenses all of the public information in the TPM // I.e., public = PCR_19 + all NVRAM for which !perms_ok static function TPM_public(aTPM:TPM_struct, s:seq) : bool { (exists i:int | 0 <= i < |aTPM.PCR_19| :: s == aTPM.PCR_19[i]) || (exists a:int | 0 <= a < |aTPM.NVRAM| && 0 <= a < |aTPM.NV_perms_ok| && (!aTPM.NV_perms_ok[a] || !aTPM.NV_locked) :: s == aTPM.NVRAM[a]) } /* TODO: dafnycc static function TPM_public(aTPM:TPM_struct) : set> { (set i:int | 0 <= i < |aTPM.PCR_19| :: aTPM.PCR_19[i]) + (set a:int | 0 <= a < |aTPM.NVRAM| && 0 <= a < |aTPM.NV_perms_ok| && (!aTPM.NV_perms_ok[a] || !aTPM.NV_locked) :: aTPM.NVRAM[a]) } */ /******************************************************** * Low-level TPM interactions ********************************************************/ ghost method {:axiom} TPM_enable_request_access() requires IoMemPerm.Null?; modifies this`IoMemPerm; ensures Locality3_requested(); ensures IoMemPerm == IoWriteAddr(0xFED43000, 2); // movb 2 -> 0xFED43000 (0xFED4 || TPM_ACCESS_3 (3000h)) ghost method {:axiom} TPM_enable_check_access_status() returns (status:int) requires IoMemPerm.Null?; requires Locality3_requested(); modifies this`IoMemPerm; ensures Word32(status); ensures |BEWordToBitSeq(status)| == 32; ensures BEWordToBitSeq(status)[26] == 1 ==> Locality3_obtained(); // bit 5 = activeLocality ensures IoMemPerm == IoReadAddr(0xFED43000, status); // See Table 16 of the TCG PC Client Spec 1.20 ghost method {:axiom} TPM_enable_issue_command_ready() requires IoMemPerm.Null?; requires Locality3_obtained(); requires TPM_valid(TPM); ensures old(TPM.cmd_state.Idle? || TPM.cmd_state.AlmostReady?) ==> TPM.cmd_state.AlmostReady? || TPM.cmd_state.Ready?; ensures old(TPM.cmd_state.Ready?) ==> TPM.cmd_state == Ready; ensures old(TPM.cmd_state.CmdReception? || TPM.cmd_state.Executing? || TPM.cmd_state.CmdComplete?) ==> (TPM.cmd_state.Idle? || TPM.cmd_state.AlmostReady? || TPM.cmd_state.Ready?); // Depends on TPM impl and timeout values ensures TPM_valid(TPM); modifies this`TPM; modifies this`IoMemPerm; ensures TPM == old(TPM)[cmd_state := TPM.cmd_state][cmd_buf := []][reply_buf := []]; ensures IoMemPerm == IoWriteAddr(0xFED43018, 0x40); ghost method {:axiom} TPM_enable_check_command_ready() returns (status:int) requires IoMemPerm.Null?; requires Locality3_obtained(); requires TPM_valid(TPM); requires TPM.cmd_state.AlmostReady? || TPM.cmd_state.Ready?; ensures Word32(status); ensures |BEWordToBitSeq(status)| == 32; ensures BEWordToBitSeq(status)[25] == 1 ==> TPM.cmd_state.Ready?; // bit 6 = commandReady ensures BEWordToBitSeq(status)[25] != 1 ==> TPM.cmd_state == old(TPM.cmd_state); ensures TPM_valid(TPM); modifies this`TPM; modifies this`IoMemPerm; ensures TPM == old(TPM)[cmd_state := TPM.cmd_state]; ensures IoMemPerm == IoReadAddr(0xFED43018, status); ghost method {:axiom} TPM_enable_write_FIFO(c:int) requires IoMemPerm.Null?; requires Locality3_obtained(); requires TPM_valid(TPM); requires IsByte(c); requires TPM.cmd_state.Ready? || TPM.cmd_state.CmdReception?; ensures TPM_valid(TPM); modifies this`TPM; modifies this`IoMemPerm; ensures TPM == old(TPM)[cmd_state := CmdReception()][cmd_buf := old(TPM.cmd_buf) + [c]]; ensures IoMemPerm == IoWriteAddr(0xFED43024, c); ghost method {:axiom} TPM_enable_go() requires IoMemPerm.Null?; requires Locality3_obtained(); requires TPM_valid(TPM); requires power2(32) == 0x100000000; requires forall new_TPM : TPM_struct :: async_TPM_execution(TPM, new_TPM) ==> TPM_satisfies_integrity_policy(new_TPM); requires TPM.cmd_state.CmdReception?; //dafnycc requires forall new_TPM : TPM_struct :: TPM_valid(new_TPM) && async_TPM_execution(TPM, new_TPM) ==> TPM_public(left(new_TPM)) == TPM_public(right(new_TPM)); //Wait for SymDiff: requires forall new_TPM : TPM_struct :: TPM_valid(new_TPM) && async_TPM_execution(TPM, new_TPM) ==> forall s :: TPM_public(left(new_TPM), s) == TPM_public(right(new_TPM), s); ensures TPM_valid(TPM); modifies this`TPM; modifies this`IoMemPerm; ensures TPM == old(TPM)[cmd_state := Executing]; ensures IoMemPerm == IoWriteAddr(0xFED43018, 0x20); ghost method {:axiom} TPM_enable_check_data_available() returns (r:int) requires IoMemPerm.Null?; requires Locality3_obtained(); requires TPM_valid(TPM); requires TPM.cmd_state.Executing? || TPM.cmd_state.CmdComplete?; requires power2(32) == 0x100000000; ensures TPM_valid(TPM); ensures old(TPM.cmd_state.Executing?) ==> async_TPM_execution(old(TPM), TPM) // May bump us to CmdComplete, or may leave us in Executing && (r == 0x90 <==> TPM.cmd_state.CmdComplete?); // 0x90 = TIS_STS_VALID (0x80) + TIS_STS_DATA_AVAIL (0x10) ensures old(TPM.cmd_state.CmdComplete?) ==> (r == 0x90 ==> |TPM.reply_buf| > 0) && old(TPM) == TPM; ensures old(TPM.cmd_state.CmdComplete?) ==> (r == 0x80 ==> |TPM.reply_buf| == 0) && old(TPM) == TPM; modifies this`TPM; // Modifications specified by Async_TPM, so no additional details below modifies this`IoMemPerm; ensures IoMemPerm == IoReadAddr(0xFED43018, r); ghost method {:axiom} TPM_enable_read_FIFO() returns (c:int) requires IoMemPerm.Null?; requires Locality3_obtained(); requires TPM_valid(TPM); requires TPM.cmd_state.CmdComplete? && |TPM.reply_buf| > 0; ensures TPM_valid(TPM); ensures old(TPM.reply_buf) == [c] + TPM.reply_buf; ensures IsByte(c); modifies this`TPM; modifies this`IoMemPerm; ensures TPM == old(TPM)[reply_buf := TPM.reply_buf]; ensures IoMemPerm == IoReadAddr(0xFED43024, c); static predicate async_TPM_execution(old_TPM:TPM_struct, new_TPM:TPM_struct) requires IsByteSeq(old_TPM.cmd_buf); { // We execute a valid command (IsByteSeq(new_TPM.reply_buf) && |new_TPM.reply_buf| > 0 && TPM_executed_some_command(old_TPM, new_TPM)) || // Or there's a valid command present, but the TPM is still executing it (valid_cmd_present(old_TPM) && old_TPM == new_TPM) || // Or there's an unexpected command, so we know nothing about the TPM's state !valid_cmd_present(old_TPM) // havoc! } /*************************************** * TPM Tags ***************************************/ static function TPM_TAG_RQU_COMMAND() : seq { [ 0, 0xC1 ] } static function TPM_TAG_RQU_AUTH1_COMMAND() : seq { [ 0, 0xC2 ] } static function method TPM_TAG_RSP_COMMAND() : seq { [ 0, 0xC4 ] } static function method TPM_TAG_RSP_AUTH1_COMMAND() : seq { [ 0, 0xC5 ] } static function method TPM_TAG_NV_DATA_PUBLIC() : seq { [ 0, 0x18 ] } static function method TPM_TAG_NV_ATTRIBUTES() : seq { [ 0, 23 ] } static function TPM_TAG_PERMANENT_FLAGS() : seq { [ 0, 0x1f ] } /*************************************** * TPM Command Ordinals ***************************************/ static function TPM_ORD_GetCapability() : int { 0x65 } static function TPM_ORD_NV_ReadValue() : int { 0xCF } static function TPM_ORD_NV_WriteValue() : int { 0xCD } static function TPM_ORD_Extend() : int { 0x14 } static function TPM_ORD_Quote2() : int { 0x3E } static function TPM_ORD_GetRandom() : int { 0x46 } static function TPM_ORD_PcrRead() : int { 0x15 } static function TPM_ORD_OIAP() : int { 0x0A } static function TPM_ORD_LoadKey2() : int { 0x41 } static function TPM_CAP_NV_INDEX() : int { 0x11 } static function TPM_CAP_FLAG() : int { 4 } static function TPM_CAP_FLAG_PERMANENT() : int { 0x00000108 } /*************************************** * TPM return codes ***************************************/ static function method TPM_SUCCESS() : int { 0 } /******************************************************** * TPM structure parsing ********************************************************/ static function method PCR_SELECTION_covering_PCRs_17_and_18() : seq { [ 0, 3, 0, 0, 6 ] // pcrSelection = size (0x0003), PCR bit map. Selects PCR 17 & 18 from byte 2 (0-indexed } static function method PCR_SELECTION_covering_PCRs_17_through_19() : seq { [ 0, 3, 0, 0, 14 ] // pcrSelection = size (0x0003), PCR bit map. Selects PCR 17, 18, 19 from byte 2 (0-indexed } datatype PCRInfoShort = PCRInfoShort17And18_c(pcrs_17_18_digest:seq) | PCRInfoShort17Through19_c(pcrs_17_18_19_digest:seq) | PCRInfoShortInvalid_c() static function parse_PCR_info_short(s:seq) : PCRInfoShort { if |s| != 26 then PCRInfoShortInvalid_c() else ( var fields := s[5 :1 :20 ]; var pcr_selection, localities_bit_vector, pcrs_digest := fields[0], fields[1], fields[2]; // Note: we don't care about the localities: NVRAM uses PCR protections and it's irrelevant for Quote if pcr_selection == PCR_SELECTION_covering_PCRs_17_through_19() then PCRInfoShort17Through19_c(pcrs_digest) else if pcr_selection == PCR_SELECTION_covering_PCRs_17_and_18() then PCRInfoShort17And18_c(pcrs_digest) else PCRInfoShortInvalid_c() ) } static predicate is_TPM_COMPOSITE_HASH(h:seq, PCR_17:seq, PCR_18:seq) { var pcr_composite := PCR_SELECTION_covering_PCRs_17_and_18() + [0, 0, 0, 40] + // size of next two PCRs PCR_17 + PCR_18; IsByteSeq(pcr_composite) && (var pcr_composite_bits := BEByteSeqToBitSeq(pcr_composite); IsBitSeq(pcr_composite_bits) && |pcr_composite_bits| < power2(64) && h == BEWordSeqToByteSeq(SHA1(pcr_composite_bits))) } static predicate Verve_quote(pcr_info:seq, sig:seq, nonce:seq, PCR_19_history:seq>) /******************************************************** * TPM command parsing ********************************************************/ datatype TPMCommand = TPMCommandQuote2_c(nonce_external:seq, key_handle:seq, auth_handle:seq) | TPMCommandReadPCR17Or18_c(pcr_to_read:int) | TPMCommandExtendPCR19_c(value_to_extend:seq) | TPMCommandGetRandom_c(random_bytes:int) | TPMCommandGetNVRAMCapability_c(nvindex_to_get_cap:int) | TPMCommandGetPermanentFlags_c() | TPMCommandReadNVRAM_c(nvindex_to_read:int) | TPMCommandWriteNVRAM_c(nvindex_to_write:int, value_to_write:seq) | TPMCommandOIAP_c() | TPMCommandLoadKey2_c() | TPMCommandInvalid_c() static function parse_TPM_command_quote2(s:seq) : TPMCommand requires IsByteSeq(s); { if |s| != 85 then TPMCommandInvalid_c() else ( var fields := s[10 :4 :20 :5 :1 :4 :20 :1 :20 ]; var _, key_handle, nonce_external, pcr_selection, add_version, auth_handle, nonce_odd, continue_auth_session, priv_auth := fields[0], fields[1], fields[2], fields[3], fields[4], fields[5], fields[6], fields[7], fields[8] ; if pcr_selection == PCR_SELECTION_covering_PCRs_17_through_19() && add_version == [1] && // When TRUE add TPM_CAP_VERSION_INFO to the output continue_auth_session == [1] then // continueAuthSession? TPMCommandQuote2_c(nonce_external, key_handle, auth_handle) else TPMCommandInvalid_c() ) } static function parse_TPM_command_read_PCR_17_or_18(s:seq) : TPMCommand requires IsByteSeq(s); { if |s| != 14 then TPMCommandInvalid_c() else ( var pcr := BEByteSeqToInt(s[10..14]); if pcr == 17 || pcr == 18 then TPMCommandReadPCR17Or18_c(pcr) else TPMCommandInvalid_c() ) } static function parse_TPM_command_extend_PCR_19(s:seq) : TPMCommand requires IsByteSeq(s); { if |s| != 34 then TPMCommandInvalid_c() else ( var fields := s[10 :4 :20 ]; var _, pcr, data := fields[0], fields[1], fields[2] ; if BEByteSeqToInt(pcr) == 19 then TPMCommandExtendPCR19_c(data) else TPMCommandInvalid_c() ) } static function parse_TPM_command_get_random(s:seq) : TPMCommand requires IsByteSeq(s); { if |s| != 14 then TPMCommandInvalid_c() else ( var random_bytes := BEByteSeqToInt(s[10..14]); TPMCommandGetRandom_c(random_bytes) ) } static function parse_TPM_command_get_capability(s:seq) : TPMCommand requires IsByteSeq(s); { if |s| != 22 then TPMCommandInvalid_c() else ( var fields := s[10 :4 :4 :4 ]; var _, capability_area, subcap_size, subcap := fields[0], BEByteSeqToInt(fields[1]), BEByteSeqToInt(fields[2]), BEByteSeqToInt(fields[3]) ; if subcap_size != 4 then TPMCommandInvalid_c() else if capability_area == TPM_CAP_NV_INDEX() then TPMCommandGetNVRAMCapability_c(subcap) else if capability_area == TPM_CAP_FLAG() then if subcap == TPM_CAP_FLAG_PERMANENT() then TPMCommandGetPermanentFlags_c() else TPMCommandInvalid_c() else TPMCommandInvalid_c() ) } static function parse_TPM_command_read_NVRAM(s:seq) : TPMCommand requires IsByteSeq(s); { if |s| != 22 then TPMCommandInvalid_c() else ( var fields := s[10 :4 :4 :4 ]; var _, nvindex, offset, data_size := fields[0], BEByteSeqToInt(fields[1]), BEByteSeqToInt(fields[2]), BEByteSeqToInt(fields[3]) ; if offset == 0 && data_size == NV_size() then TPMCommandReadNVRAM_c(nvindex) else TPMCommandInvalid_c() ) } static function parse_TPM_command_write_NVRAM(s:seq) : TPMCommand requires IsByteSeq(s); { if |s| != 22 + NV_size() then TPMCommandInvalid_c() else ( var fields := s[10 :4 :4 :4 ]; var _, nvindex, offset, data_size := fields[0], BEByteSeqToInt(fields[1]), BEByteSeqToInt(fields[2]), BEByteSeqToInt(fields[3]) ; if offset == 0 && data_size == NV_size() then ( var data := s[22..22+NV_size()]; TPMCommandWriteNVRAM_c(nvindex, data) ) else TPMCommandInvalid_c() ) } static function parse_TPM_command_OIAP(s:seq) : TPMCommand requires IsByteSeq(s); { if |s| != 10 then TPMCommandInvalid_c() else TPMCommandOIAP_c() // Nothing to the command but the header } static function parse_TPM_command_LoadKey2(s:seq) : TPMCommand requires IsByteSeq(s); { if |s| < 59 then TPMCommandInvalid_c() else TPMCommandLoadKey2_c() // Nothing to track for security purposes } static function parse_TPM_command(s:seq) : TPMCommand requires IsByteSeq(s); { if |s| < 10 then TPMCommandInvalid_c() else ( var fields := s[2 :4 :4 ]; var tag, length, command := fields[0], fields[1], fields[2]; var command_code := BEByteSeqToInt(command); if BEByteSeqToInt(length) != |s| then TPMCommandInvalid_c() else if tag == TPM_TAG_RQU_COMMAND() then ( if command_code == TPM_ORD_PcrRead() then parse_TPM_command_read_PCR_17_or_18(s) else if command_code == TPM_ORD_Extend() then parse_TPM_command_extend_PCR_19(s) else if command_code == TPM_ORD_GetRandom() then parse_TPM_command_get_random(s) else if command_code == TPM_ORD_GetCapability() then parse_TPM_command_get_capability(s) else if command_code == TPM_ORD_NV_ReadValue() then parse_TPM_command_read_NVRAM(s) else if command_code == TPM_ORD_NV_WriteValue() then parse_TPM_command_write_NVRAM(s) else if command_code == TPM_ORD_OIAP() then parse_TPM_command_OIAP(s) else if command_code == TPM_ORD_LoadKey2() then parse_TPM_command_LoadKey2(s) else TPMCommandInvalid_c() ) else if tag == TPM_TAG_RQU_AUTH1_COMMAND() then ( if command_code == TPM_ORD_Quote2() then parse_TPM_command_quote2(s) else if command_code == TPM_ORD_LoadKey2() then parse_TPM_command_LoadKey2(s) else TPMCommandInvalid_c() ) else TPMCommandInvalid_c() ) } static predicate valid_cmd(s:seq) requires IsByteSeq(s); { !(parse_TPM_command(s).TPMCommandInvalid_c?) } static predicate {:autoReq} valid_cmd_present(aTPM:TPM_struct) { valid_cmd(aTPM.cmd_buf) } /******************************************************** * TPM reply parsing ********************************************************/ datatype TPMReply = TPMReplyQuote2_c(nonce_even:seq, pcr_info:seq, sig:seq) | TPMReplyReadPCR17Or18_c(pcr_value_read:seq) | TPMReplyExtendPCR19_c() | TPMReplyGetRandom_c(randoms:seq) | TPMReplyGetNVRAMCapability_c(nvindex:int, pcrs_digest:seq, data_size:int) | TPMReplyGetPermanentFlags_c(nv_locked:bool) | TPMReplyReadNVRAM_c(nvram_value_read:seq) | TPMReplyWriteNVRAM_c() | TPMReplyOIAP() | TPMReplyLoadKey2() | TPMReplyInvalid_c() static predicate is_TPM_reply_header_ok(s:seq, expected_tag:seq) requires IsByteSeq(s); { |s| >= 10 && (var fields := s[2 :4 :4 ]; var tag, length, return_code := fields[0], BEByteSeqToInt(fields[1]), BEByteSeqToInt(fields[2]) ; tag == expected_tag && length == |s| && return_code == TPM_SUCCESS()) } // REVIEW: Why so much detail about the reply? static function parse_TPM_reply_quote2(s:seq) : TPMReply requires IsByteSeq(s); { if !is_TPM_reply_header_ok(s,TPM_TAG_RSP_AUTH1_COMMAND()) || |s| < 40 then TPMReplyInvalid_c() else ( var f_a := s[10 :26 :4 ]; var _, pcr_info_bytes, version_info_size := f_a[0], f_a[1], BEByteSeqToInt(f_a[2]) ; var pcr_info := parse_PCR_info_short(pcr_info_bytes); if !pcr_info.PCRInfoShort17Through19_c? || |s| < 44 + version_info_size || version_info_size < 0 then TPMReplyInvalid_c() else ( var f_b := s[40 :version_info_size :4 ]; var _, version_info, sig_size := f_b[0], f_b[1], BEByteSeqToInt(f_b[2]) ; if |s| != 85 + version_info_size + sig_size || sig_size < 0 then TPMReplyInvalid_c() else ( var f_c := s[44+version_info_size :sig_size :20 :1 :20 ]; var _, sig, nonce_even, continue_session, res_auth := f_c[0], f_c[1], f_c[2], f_c[3], f_c[4] ; if continue_session == [1] then TPMReplyQuote2_c(nonce_even, pcr_info_bytes, sig) else TPMReplyInvalid_c() ) ) ) } static function parse_TPM_reply_read_PCR_17_or_18(s:seq) : TPMReply requires IsByteSeq(s); { if !is_TPM_reply_header_ok(s,TPM_TAG_RSP_COMMAND()) || |s| != 30 then TPMReplyInvalid_c() else TPMReplyReadPCR17Or18_c(s[10..30]) } static function parse_TPM_reply_extend_PCR_19(s:seq) : TPMReply requires IsByteSeq(s); { if !is_TPM_reply_header_ok(s,TPM_TAG_RSP_COMMAND()) || |s| != 30 then TPMReplyInvalid_c() else TPMReplyExtendPCR19_c() } static function parse_TPM_reply_get_random(s:seq) : TPMReply requires IsByteSeq(s); { if !is_TPM_reply_header_ok(s,TPM_TAG_RSP_COMMAND()) || |s| < 14 then TPMReplyInvalid_c() else ( var random_bytes_size := BEByteSeqToInt(s[10..14]); if |s| != 14 + random_bytes_size || random_bytes_size < 0 then TPMReplyInvalid_c() else TPMReplyGetRandom_c(s[14..14+random_bytes_size]) ) } static function parse_TPM_reply_get_NVRAM_capability(s:seq) : TPMReply requires IsByteSeq(s); { if !is_TPM_reply_header_ok(s,TPM_TAG_RSP_COMMAND()) || |s| != 85 then TPMReplyInvalid_c() else ( var fields := s[10 :4 :2 :4 :26 :26 :2 :4 :1 :1 :1 :4 ]; var _, resp_size, tag, nvindex, pcr_info_read, pcr_info_write, permission_tag, permission_attributes, read_st_clear, write_st_clear, write_define, data_size := fields[0], BEByteSeqToInt(fields[1]), fields[2], BEByteSeqToInt(fields[3]), parse_PCR_info_short(fields[4]), parse_PCR_info_short(fields[5]), fields[6], fields[7], fields[8], fields[9], fields[10], BEByteSeqToInt(fields[11]) ; if resp_size == 71 && tag == TPM_TAG_NV_DATA_PUBLIC() && pcr_info_read.PCRInfoShort17And18_c? && pcr_info_write.PCRInfoShort17And18_c? && pcr_info_read.pcrs_17_18_digest == pcr_info_write.pcrs_17_18_digest && permission_tag == TPM_TAG_NV_ATTRIBUTES() && permission_attributes == [ 0, 0, 0x20, 0 ] && // TPM_NV_PER_WRITEDEFINE=bit 13=0x20 read_st_clear == [0] && // bReadSTClear: Set to FALSE on each TPM_Startup(ST_Clear) and set to TRUE after a ReadValuexxx with datasize of 0 write_st_clear == [0] && // bWriteSTClear: Set to FALSE on each TPM_Startup(ST_CLEAR) and set to TRUE after a WriteValuexxx with a datasize of 0. write_define == [0] then // bWriteDefine: Set to FALSE after TPM_NV_DefineSpace and set to TRUE after a successful WriteValuexxx with a datasize of 0 TPMReplyGetNVRAMCapability_c(nvindex, pcr_info_read.pcrs_17_18_digest, data_size) else TPMReplyInvalid_c() ) } static function parse_TPM_reply_get_permanent_flags(s:seq) : TPMReply requires IsByteSeq(s); { if !is_TPM_reply_header_ok(s,TPM_TAG_RSP_COMMAND()) || |s| != 36 then TPMReplyInvalid_c() else ( var fields := s[10 :4 :2 :15 :1 ]; var _, resp_size, tag, _, nv_locked := fields[0], BEByteSeqToInt(fields[1]), fields[2], fields[3], fields[4] ; if resp_size == 22 && tag == TPM_TAG_PERMANENT_FLAGS() && (nv_locked == [0] || nv_locked == [1]) then TPMReplyGetPermanentFlags_c(nv_locked == [1]) else TPMReplyInvalid_c() ) } static function parse_TPM_reply_read_NVRAM(s:seq) : TPMReply requires IsByteSeq(s); { if !is_TPM_reply_header_ok(s,TPM_TAG_RSP_COMMAND()) || |s| < 14 then TPMReplyInvalid_c() else ( var data_size := BEByteSeqToInt(s[10..14]); if |s| == 14 + data_size then TPMReplyReadNVRAM_c(s[14..14+data_size]) else TPMReplyInvalid_c() ) } static function parse_TPM_reply_write_NVRAM(s:seq) : TPMReply requires IsByteSeq(s); { if !is_TPM_reply_header_ok(s,TPM_TAG_RSP_COMMAND()) || |s| != 10 then TPMReplyInvalid_c() else TPMReplyWriteNVRAM_c() } static function parse_TPM_reply_OIAP(s:seq) : TPMReply requires IsByteSeq(s); { if !is_TPM_reply_header_ok(s,TPM_TAG_RSP_COMMAND()) || |s| != 34 then TPMReplyInvalid_c() else TPMReplyOIAP() // For security purposes, we don't care. We only use this for quote, which is checked remotely } static function parse_TPM_reply_LoadKey2(s:seq) : TPMReply requires IsByteSeq(s); { if !is_TPM_reply_header_ok(s, TPM_TAG_RSP_AUTH1_COMMAND()) || |s| != 55 then TPMReplyInvalid_c() else TPMReplyLoadKey2() // For security purposes, we don't care. We only use this for quote, which is checked remotely } /******************************************************** * Semantic-level TPM Commands ********************************************************/ static predicate TPM_executed_read_NVRAM(old_TPM:TPM_struct, new_TPM:TPM_struct) requires IsByteSeq(old_TPM.cmd_buf); requires IsByteSeq(new_TPM.reply_buf); { var cmd := parse_TPM_command(old_TPM.cmd_buf); var reply := parse_TPM_reply_read_NVRAM(new_TPM.reply_buf); cmd.TPMCommandReadNVRAM_c? && (reply.TPMReplyReadNVRAM_c? ==> valid_nv_index(old_TPM, cmd.nvindex_to_read) && reply.nvram_value_read == old_TPM.NVRAM[cmd.nvindex_to_read]) && new_TPM == old_TPM[cmd_state := CmdComplete()][reply_buf := new_TPM.reply_buf] } static predicate TPM_executed_write_NVRAM(old_TPM:TPM_struct, new_TPM:TPM_struct) requires IsByteSeq(old_TPM.cmd_buf); requires IsByteSeq(new_TPM.reply_buf); { var cmd := parse_TPM_command(old_TPM.cmd_buf); var reply := parse_TPM_reply_write_NVRAM(new_TPM.reply_buf); cmd.TPMCommandWriteNVRAM_c? && (var a := cmd.nvindex_to_write; // If we get a successful reply, then the NVRAM has been updated to the requested value (reply.TPMReplyWriteNVRAM_c? ==> valid_nv_index(new_TPM, a) && new_TPM.NVRAM[a] == cmd.value_to_write) // If the NVRAM was updated, it was updated to the requested value // Note that this used to say: // reply.TPMReplyInvalid_c? ==> old_TPM.NVRAM == new_TPM.NVRAM // but, to be paranoid, we allow an error code to be returned even if the value was updated. && (valid_nv_index(old_TPM, a) && valid_nv_index(new_TPM, a) ==> new_TPM.NVRAM[a] == old_TPM.NVRAM[a] || new_TPM.NVRAM[a] == cmd.value_to_write) // All other NVRAM locations are unaffected && |old_TPM.NVRAM| == |new_TPM.NVRAM| && (forall a':int :: valid_nv_index(old_TPM, a') && valid_nv_index(new_TPM, a') && a' != a ==> new_TPM.NVRAM[a'] == old_TPM.NVRAM[a']) && |new_TPM.reply_buf| > 0 && new_TPM == old_TPM[cmd_state := CmdComplete()][reply_buf := new_TPM.reply_buf][NVRAM := new_TPM.NVRAM]) } static predicate TPM_executed_extend_PCR_19(old_TPM:TPM_struct, new_TPM:TPM_struct) requires IsByteSeq(old_TPM.cmd_buf); requires IsByteSeq(new_TPM.reply_buf); { var cmd := parse_TPM_command(old_TPM.cmd_buf); var reply := parse_TPM_reply_extend_PCR_19(new_TPM.reply_buf); cmd.TPMCommandExtendPCR19_c? && (var data := cmd.value_to_extend; // The PCR was successfully updated (reply.TPMReplyExtendPCR19_c? ==> new_TPM.PCR_19 == old_TPM.PCR_19 + [data]) // If it was updated at all, it was updated with data && (new_TPM.PCR_19 == old_TPM.PCR_19 || new_TPM.PCR_19 == old_TPM.PCR_19 + [data]) && |new_TPM.reply_buf| > 0 && new_TPM == old_TPM[cmd_state := CmdComplete()][reply_buf := new_TPM.reply_buf][PCR_19 := new_TPM.PCR_19]) } static predicate TPM_executed_get_NVRAM_capability(old_TPM:TPM_struct, new_TPM:TPM_struct) requires IsByteSeq(old_TPM.cmd_buf); requires IsByteSeq(new_TPM.reply_buf); { var cmd := parse_TPM_command(old_TPM.cmd_buf); var reply := parse_TPM_reply_get_NVRAM_capability(new_TPM.reply_buf); cmd.TPMCommandGetNVRAMCapability_c? && (var a := cmd.nvindex_to_get_cap; (reply.TPMReplyGetNVRAMCapability_c? && reply.nvindex == a && is_TPM_COMPOSITE_HASH(reply.pcrs_digest, PCR_val(17), PCR_val(18)) && reply.data_size == NV_size() ==> valid_nv_index(old_TPM, a) && old_TPM.NV_perms_ok[a]) && |new_TPM.reply_buf| > 0 && new_TPM == old_TPM[cmd_state := CmdComplete()][reply_buf := new_TPM.reply_buf]) } static predicate TPM_executed_get_permanent_flags(old_TPM:TPM_struct, new_TPM:TPM_struct) requires IsByteSeq(old_TPM.cmd_buf); requires IsByteSeq(new_TPM.reply_buf); { var cmd := parse_TPM_command(old_TPM.cmd_buf); var reply := parse_TPM_reply_get_permanent_flags(new_TPM.reply_buf); cmd.TPMCommandGetPermanentFlags_c? && (reply.TPMReplyGetPermanentFlags_c? ==> reply.nv_locked == old_TPM.NV_locked) && new_TPM == old_TPM[cmd_state := CmdComplete()][reply_buf := new_TPM.reply_buf] } static predicate TPM_executed_quote2(old_TPM:TPM_struct, new_TPM:TPM_struct) requires IsByteSeq(old_TPM.cmd_buf); requires IsByteSeq(new_TPM.reply_buf); { var cmd := parse_TPM_command(old_TPM.cmd_buf); var reply := parse_TPM_reply_quote2(new_TPM.reply_buf); cmd.TPMCommandQuote2_c? && (reply.TPMReplyQuote2_c? ==> Verve_quote(reply.pcr_info, reply.sig, cmd.nonce_external, old_TPM.PCR_19)) && 0 < |new_TPM.reply_buf| <= power2(33) && new_TPM == old_TPM[cmd_state := CmdComplete()][reply_buf := new_TPM.reply_buf] } static predicate TPM_executed_get_random(old_TPM:TPM_struct, new_TPM:TPM_struct) requires IsByteSeq(old_TPM.cmd_buf); requires IsByteSeq(new_TPM.reply_buf); { var cmd := parse_TPM_command(old_TPM.cmd_buf); var reply := parse_TPM_reply_get_random(new_TPM.reply_buf); cmd.TPMCommandGetRandom_c? && (reply.TPMReplyGetRandom_c? ==> |reply.randoms| <= cmd.random_bytes && new_TPM.random_index == old_TPM.random_index + |reply.randoms| && (forall j :: 0 <= j < |reply.randoms| ==> reply.randoms[j] == TPM_random_byte(old_TPM.random_index + j))) && (reply.TPMReplyInvalid_c? ==> old_TPM.random_index == new_TPM.random_index) && new_TPM == old_TPM[cmd_state := CmdComplete()][reply_buf := new_TPM.reply_buf][random_index := new_TPM.random_index] } static predicate TPM_executed_read_PCR_17_or_18(old_TPM:TPM_struct, new_TPM:TPM_struct) requires IsByteSeq(old_TPM.cmd_buf); requires IsByteSeq(new_TPM.reply_buf); { var cmd := parse_TPM_command(old_TPM.cmd_buf); var reply := parse_TPM_reply_read_PCR_17_or_18(new_TPM.reply_buf); cmd.TPMCommandReadPCR17Or18_c? && (reply.TPMReplyReadPCR17Or18_c? ==> reply.pcr_value_read == PCR_val(cmd.pcr_to_read)) && new_TPM == old_TPM[cmd_state := CmdComplete()][reply_buf := new_TPM.reply_buf] } static predicate TPM_executed_OIAP(old_TPM:TPM_struct, new_TPM:TPM_struct) requires IsByteSeq(old_TPM.cmd_buf); requires IsByteSeq(new_TPM.reply_buf); { var cmd := parse_TPM_command(old_TPM.cmd_buf); var reply := parse_TPM_reply_OIAP(new_TPM.reply_buf); cmd.TPMCommandOIAP_c? && new_TPM == old_TPM // Doesn't affect any of the TPM state we track } static predicate TPM_executed_LoadKey2(old_TPM:TPM_struct, new_TPM:TPM_struct) requires IsByteSeq(old_TPM.cmd_buf); requires IsByteSeq(new_TPM.reply_buf); { var cmd := parse_TPM_command(old_TPM.cmd_buf); var reply := parse_TPM_reply_LoadKey2(new_TPM.reply_buf); cmd.TPMCommandLoadKey2_c? && new_TPM == old_TPM // Doesn't affect any of the TPM state we track } static predicate TPM_executed_some_command(old_TPM:TPM_struct, new_TPM:TPM_struct) requires IsByteSeq(old_TPM.cmd_buf); requires IsByteSeq(new_TPM.reply_buf); { TPM_executed_read_NVRAM(old_TPM, new_TPM) || TPM_executed_write_NVRAM(old_TPM, new_TPM) || TPM_executed_extend_PCR_19(old_TPM, new_TPM) || TPM_executed_get_NVRAM_capability(old_TPM, new_TPM) || TPM_executed_get_permanent_flags(old_TPM, new_TPM) || TPM_executed_quote2(old_TPM, new_TPM) || TPM_executed_get_random(old_TPM, new_TPM) || TPM_executed_read_PCR_17_or_18(old_TPM, new_TPM) || TPM_executed_OIAP(old_TPM, new_TPM) || TPM_executed_LoadKey2(old_TPM, new_TPM) } ================================================ FILE: ironclad-apps/src/Dafny/Drivers/TPM/tpm-driver.i.dfy ================================================ include "tpm-device.s.dfy" include "../../Libraries/Math/mul.i.dfy" include "../../Libraries/Math/div.i.dfy" include "../../Libraries/Math/power2.i.dfy" include "../../Libraries/Math/bit_vector_lemmas_premium.i.dfy" include "../../Libraries/Util/integer_sequences.i.dfy" include "../CPU/assembly_premium.i.dfy" include "../IO/io_mem.i.dfy" static function method{:CompiledSpec} CompiledSpec_TPM_TAG_RSP_COMMAND() : seq static function method{:CompiledSpec} CompiledSpec_TPM_TAG_RSP_AUTH1_COMMAND() : seq /* static function method{:CompiledSpec} CompiledSpec_TPM_TAG_NV_DATA_PUBLIC() : seq static function method{:CompiledSpec} CompiledSpec_TPM_TAG_NV_ATTRIBUTES() : seq */ static function method{:CompiledSpec} CompiledSpec_TPM_SUCCESS() : int static function method{:CompiledSpec} CompiledSpec_PCR_SELECTION_covering_PCRs_17_and_18() : seq static function method{:CompiledSpec} CompiledSpec_PCR_SELECTION_covering_PCRs_17_through_19() : seq /*************************************************************************** * TPM INSTRUCTION WRAPPERS ***************************************************************************/ method TPM_instr_request_access() requires IoMemPerm.Null?; modifies this`IoMemPerm; ensures Locality3_requested(); ensures IoMemPerm.Null?; { TPM_enable_request_access(); IoMemAddrWrite(0xFED43000, 2); } method TPM_instr_check_access_status() returns (status:int) requires IoMemPerm.Null?; requires Locality3_requested(); modifies this`IoMemPerm; ensures Word32(status); ensures |BEWordToBitSeq(status)| == 32; ensures BEWordToBitSeq(status)[26] == 1 ==> Locality3_obtained(); //- bit 5 = activeLocality ensures IoMemPerm.Null?; { ghost var _ := TPM_enable_check_access_status(); status := IoMemAddrRead(0xFED43000); } method TPM_instr_issue_command_ready() requires IoMemPerm.Null?; requires Locality3_obtained(); requires TPM_valid(TPM); ensures old(TPM.cmd_state.Idle? || TPM.cmd_state.AlmostReady?) ==> TPM.cmd_state.AlmostReady? || TPM.cmd_state.Ready?; ensures old(TPM.cmd_state.Ready?) ==> TPM.cmd_state == Ready; ensures old(TPM.cmd_state.CmdReception? || TPM.cmd_state.Executing? || TPM.cmd_state.CmdComplete?) ==> (TPM.cmd_state.Idle? || TPM.cmd_state.AlmostReady? || TPM.cmd_state.Ready?); //- Depends on TPM impl and timeout values ensures TPM_valid(TPM); modifies this`TPM; modifies this`IoMemPerm; ensures TPM == old(TPM)[cmd_state := TPM.cmd_state][cmd_buf := []][reply_buf := []]; ensures IoMemPerm.Null?; { TPM_enable_issue_command_ready(); IoMemAddrWrite(0xFED43018, 0x40); } method TPM_instr_check_command_ready() returns (status:int) requires IoMemPerm.Null?; requires Locality3_obtained(); requires TPM_valid(TPM); requires TPM.cmd_state.AlmostReady? || TPM.cmd_state.Ready?; ensures Word32(status); ensures |BEWordToBitSeq(status)| == 32; ensures BEWordToBitSeq(status)[25] == 1 ==> TPM.cmd_state.Ready?; //- bit 6 = commandReady ensures BEWordToBitSeq(status)[25] != 1 ==> TPM.cmd_state == old(TPM.cmd_state); ensures TPM_valid(TPM); modifies this`TPM; modifies this`IoMemPerm; ensures TPM == old(TPM)[cmd_state := TPM.cmd_state]; ensures IoMemPerm.Null?; { ghost var _ := TPM_enable_check_command_ready(); status := IoMemAddrRead(0xFED43018); } method TPM_instr_write_FIFO(c:int) requires IoMemPerm.Null?; requires Locality3_obtained(); requires TPM_valid(TPM); requires IsByte(c); requires TPM.cmd_state.Ready? || TPM.cmd_state.CmdReception?; ensures TPM_valid(TPM); modifies this`TPM; modifies this`IoMemPerm; ensures TPM == old(TPM)[cmd_state := CmdReception()][cmd_buf := old(TPM.cmd_buf) + [c]]; ensures IoMemPerm.Null?; { TPM_enable_write_FIFO(c); IoMemAddrWrite(0xFED43024, c); } method TPM_instr_go() requires IoMemPerm.Null?; requires Locality3_obtained(); requires TPM_valid(TPM); requires power2(32) == 0x100000000; requires forall new_TPM : TPM_struct :: async_TPM_execution(TPM, new_TPM) ==> TPM_satisfies_integrity_policy(new_TPM); requires TPM.cmd_state.CmdReception?; ensures TPM_valid(TPM); modifies this`TPM; modifies this`IoMemPerm; ensures TPM == old(TPM)[cmd_state := Executing]; ensures IoMemPerm.Null?; { TPM_enable_go(); IoMemAddrWrite(0xFED43018, 0x20); } method TPM_instr_check_data_available() returns (r:int) requires IoMemPerm.Null?; requires Locality3_obtained(); requires TPM_valid(TPM); requires TPM.cmd_state.Executing? || TPM.cmd_state.CmdComplete?; requires power2(32) == 0x100000000; ensures TPM_valid(TPM); ensures old(TPM.cmd_state.Executing?) ==> async_TPM_execution(old(TPM), TPM) //- May bump us to CmdComplete, or may leave us in Executing && (r == 0x90 <==> TPM.cmd_state.CmdComplete?); //- 0x90 = TIS_STS_VALID (0x80) + TIS_STS_DATA_AVAIL (0x10) ensures old(TPM.cmd_state.CmdComplete?) ==> (r == 0x90 ==> |TPM.reply_buf| > 0) && old(TPM) == TPM; ensures old(TPM.cmd_state.CmdComplete?) ==> (r == 0x80 ==> |TPM.reply_buf|== 0) && old(TPM) == TPM; modifies this`TPM; //- Modifications specified by Async_TPM, so no additional details below modifies this`IoMemPerm; ensures IoMemPerm.Null?; { ghost var _ := TPM_enable_check_data_available(); r := IoMemAddrRead(0xFED43018); } method TPM_instr_read_FIFO() returns (c:int) requires IoMemPerm.Null?; requires Locality3_obtained(); requires TPM_valid(TPM); requires TPM.cmd_state.CmdComplete? && |TPM.reply_buf| > 0; ensures TPM_valid(TPM); ensures old(TPM.reply_buf) == [c] + TPM.reply_buf; ensures IsByte(c); modifies this`TPM; modifies this`IoMemPerm; ensures TPM == old(TPM)[reply_buf := TPM.reply_buf]; ensures IoMemPerm.Null?; { ghost var _ := TPM_enable_read_FIFO(); c := IoMemAddrRead(0xFED43024); } /*************************************************************************** * LOW-LEVEL TPM INTERACTION ***************************************************************************/ method establish_locality() requires IoMemPerm.Null?; ensures Locality3_obtained(); modifies this`IoMemPerm; ensures IoMemPerm.Null?; { TPM_instr_request_access(); lemma_2toX(); //-lemma_and_with_32_64_premium(); var done := false; while(!done) decreases *; invariant Locality3_requested(); invariant IoMemPerm.Null?; invariant done ==> Locality3_obtained(); { var status := TPM_instr_check_access_status(); ghost var old_status := status; status := Asm_BitwiseAnd(status, 32); lemma_and_with_32_64_specific_premium(old_status); if status > 0 { done := true; } } } // // // // // // // // // // // // // static lemma lemma_sequence_concatenation_is_associative(s1:seq, s2:seq, s3:seq) ensures s1 + s2 + s3 == s1 + (s2 + s3); { } method perform_command(command_bytes:seq) returns (reply_bytes:seq) requires Locality3_obtained(); requires TPM_valid(TPM); requires IoMemPerm.Null?; requires IsByteSeq(command_bytes); requires |command_bytes| >= 1; requires valid_cmd(command_bytes); requires var intermediate_TPM_1 := TPM[cmd_state := CmdReception][cmd_buf := command_bytes][reply_buf := []]; forall new_TPM : TPM_struct :: async_TPM_execution(intermediate_TPM_1, new_TPM) ==> TPM_satisfies_integrity_policy(new_TPM); modifies this`TPM; modifies this`IoMemPerm; ensures var intermediate_TPM_2:TPM_struct := old(TPM)[cmd_state := Executing][cmd_buf := command_bytes][reply_buf := []]; var intermediate_TPM_3:TPM_struct := TPM[cmd_state := CmdComplete][reply_buf := reply_bytes]; async_TPM_execution(intermediate_TPM_2, intermediate_TPM_3); ensures TPM_valid(TPM); ensures IoMemPerm.Null?; ensures TPM.cmd_state.CmdComplete?; ensures IsByteSeq(reply_bytes); { ghost var intermediate_TPM_1:TPM_struct := TPM[cmd_state := CmdReception][cmd_buf := command_bytes][reply_buf := []]; ghost var intermediate_TPM_2:TPM_struct := intermediate_TPM_1[cmd_state := Executing]; lemma_2toX(); send_command(command_bytes); assert TPM.cmd_buf == command_bytes; assert TPM == intermediate_TPM_1; assert forall new_TPM : TPM_struct :: async_TPM_execution(TPM, new_TPM) ==> TPM_satisfies_integrity_policy(new_TPM); execute_command(); assert TPM.cmd_state == Executing; assert TPM == intermediate_TPM_2; poll_data_available(); ghost var intermediate_TPM_3:TPM_struct := TPM; assert TPM_valid(intermediate_TPM_2); assert async_TPM_execution(intermediate_TPM_2, intermediate_TPM_3); reply_bytes := retrieve_response(); assert intermediate_TPM_3.reply_buf == reply_bytes; assert intermediate_TPM_3 == TPM[cmd_state := CmdComplete][reply_buf := reply_bytes]; assert async_TPM_execution(intermediate_TPM_2, intermediate_TPM_3); assert command_bytes == old(command_bytes); } method make_ready() requires Locality3_obtained(); requires TPM_valid(TPM); requires IoMemPerm.Null?; modifies this`TPM; modifies this`IoMemPerm; ensures TPM_valid(TPM); ensures IoMemPerm.Null?; ensures TPM == old(TPM)[cmd_state := Ready()][cmd_buf := []][reply_buf := []]; { assert TPM.cmd_state.Idle? || TPM.cmd_state.AlmostReady? || TPM.cmd_state.Ready? || TPM.cmd_state.CmdReception? || TPM.cmd_state.Executing? || TPM.cmd_state.CmdComplete?; TPM_instr_issue_command_ready(); TPM_instr_issue_command_ready(); assert TPM.cmd_state.AlmostReady? || TPM.cmd_state.Ready?; lemma_2toX(); var done := false; while(!done) decreases *; invariant Locality3_obtained(); invariant TPM_valid(TPM); invariant IoMemPerm.Null?; invariant TPM.cmd_state.AlmostReady? || TPM.cmd_state.Ready?; invariant TPM == old(TPM)[cmd_state := TPM.cmd_state][cmd_buf := []][reply_buf := []]; invariant done ==> TPM.cmd_state.Ready?; { var status := TPM_instr_check_command_ready(); ghost var old_status := status; status := Asm_BitwiseAnd(status, 64); lemma_and_with_32_64_specific_premium(old_status); //-assert status > 0 ==> BEWordToBitSeq(stat)[25] == 1; if status > 0 { done := true; } } } method send_command(command_bytes:seq) requires Locality3_obtained(); requires TPM_valid(TPM); requires IoMemPerm.Null?; requires IsByteSeq(command_bytes); requires |command_bytes| >= 1; requires power2(32) == 0x100000000; requires valid_cmd(command_bytes); modifies this`TPM; modifies this`IoMemPerm; ensures TPM_valid(TPM); ensures IoMemPerm.Null?; ensures TPM == old(TPM)[cmd_state := CmdReception()][cmd_buf := command_bytes[..]][reply_buf := []]; { //- assert TPM.cmd_state.Idle? || TPM.cmd_state.AlmostReady? || TPM.cmd_state.Ready? || TPM.cmd_state.CmdReception? || TPM.cmd_state.Executing? || TPM.cmd_state.CmdComplete?; //- TPM_instr_issue_command_ready(); //- TPM_instr_issue_command_ready(); //- assert TPM.cmd_state.Ready?; make_ready(); ghost var readyTPM := TPM; assert readyTPM == old(TPM)[cmd_state := Ready()][cmd_buf := []][reply_buf := []]; lemma_2toX(); //- Write one byte to move us into CmdReception TPM_instr_write_FIFO(command_bytes[0]); calc { TPM; readyTPM[cmd_state := CmdReception()][cmd_buf := readyTPM.cmd_buf + [command_bytes[0]]]; { assert readyTPM.cmd_buf + [command_bytes[0]] == [] + [command_bytes[0]] == [command_bytes[0]]; } readyTPM[cmd_state := CmdReception()][cmd_buf := [command_bytes[0]]]; old(TPM)[cmd_state := Ready()][cmd_buf := []][reply_buf := []][cmd_state := CmdReception()][cmd_buf := [command_bytes[0]]]; old(TPM)[cmd_state := CmdReception()][cmd_buf := [command_bytes[0]]][reply_buf := []]; { assert command_bytes[0..1] == [command_bytes[0]]; } old(TPM)[cmd_state := CmdReception()][cmd_buf := command_bytes[0..1]][reply_buf := []]; } var i := 1; while (i < |command_bytes|) invariant TPM_valid(TPM); invariant IoMemPerm.Null?; invariant 1 <= i <= |command_bytes|; invariant TPM == old(TPM)[cmd_state := CmdReception()][cmd_buf := command_bytes[0..i]][reply_buf := []]; { TPM_instr_write_FIFO(command_bytes[i]); i := i + 1; assert command_bytes[0..i] == command_bytes[0..i-1] + [command_bytes[i-1]]; } assert command_bytes[0..i] == command_bytes[..]; } method execute_command() requires Locality3_obtained(); requires TPM_valid(TPM); requires IoMemPerm.Null?; requires TPM.cmd_state.CmdReception?; requires power2(32) == 0x100000000; requires valid_cmd_present(TPM); requires forall new_TPM : TPM_struct :: async_TPM_execution(TPM, new_TPM) ==> TPM_satisfies_integrity_policy(new_TPM); modifies this`TPM; modifies this`IoMemPerm; ensures TPM == old(TPM)[cmd_state := Executing()]; ensures TPM_valid(TPM); ensures IoMemPerm.Null?; ensures valid_cmd_present(TPM); { TPM_instr_go(); } method poll_data_available() requires Locality3_obtained(); requires TPM_valid(TPM); requires IoMemPerm.Null?; requires TPM.cmd_state.Executing?; requires power2(32) == 0x100000000; requires valid_cmd_present(TPM); modifies this`TPM; modifies this`IoMemPerm; ensures TPM_valid(TPM); ensures IoMemPerm.Null?; ensures valid_cmd_present(TPM); ensures TPM.cmd_state.CmdComplete?; ensures |TPM.reply_buf| > 0; ensures async_TPM_execution(old(TPM), TPM); { //-ghost var old_TPM := TPM; var r := check_data_available_wrapper(); while (r != 0x90) invariant TPM_valid(TPM); invariant IoMemPerm.Null?; invariant valid_cmd_present(TPM); invariant TPM.cmd_state.CmdComplete? || TPM.cmd_state.Executing?; invariant r == 0x90 ==> |TPM.reply_buf| > 0; invariant r != 0x90 ==> TPM == old(TPM); invariant r == 0x90 ==> async_TPM_execution(old(TPM), TPM); invariant (r == 0x90 <==> TPM.cmd_state.CmdComplete?); decreases *; { r := check_data_available_wrapper(); } assert async_TPM_execution(old(TPM), TPM); } method retrieve_response() returns (ret:seq) requires Locality3_obtained(); requires TPM_valid(TPM); requires IoMemPerm.Null?; requires TPM.cmd_state.CmdComplete?; requires power2(32) == 0x100000000; requires valid_cmd_present(TPM); requires |TPM.reply_buf| > 0; modifies this`TPM; modifies this`IoMemPerm; ensures TPM_valid(TPM); ensures IoMemPerm.Null?; ensures valid_cmd_present(TPM); ensures ret == old(TPM).reply_buf; ensures TPM == old(TPM)[reply_buf := []]; { var r := check_data_available_wrapper(); assert TPM == old(TPM)[reply_buf := TPM.reply_buf]; ret := []; while (r == 0x90) invariant TPM_valid(TPM); invariant IoMemPerm.Null?; invariant valid_cmd_present(TPM); invariant TPM.cmd_state.CmdComplete?; invariant r == 0x90 <==> |TPM.reply_buf| > 0; invariant ret + TPM.reply_buf == old(TPM.reply_buf); decreases *; invariant TPM == old(TPM)[reply_buf := TPM.reply_buf]; { ghost var old_reply_buf := TPM.reply_buf; ghost var old_ret := ret; //-assert old_ret + old_reply_buf == old(TPM.reply_buf); var c := TPM_instr_read_FIFO(); //-assert [c] + TPM.reply_buf == old_reply_buf; ret := ret + [c]; assert ret == old_ret + [c]; calc { ret + TPM.reply_buf; old_ret + [c] + TPM.reply_buf; { lemma_sequence_concatenation_is_associative(old_ret, [c], TPM.reply_buf); } old_ret + ([c] + TPM.reply_buf); old_ret + old_reply_buf; old(TPM.reply_buf); } r := check_data_available_wrapper(); } } method check_data_available_wrapper() returns (r:int) requires Locality3_obtained(); requires TPM_valid(TPM); requires IoMemPerm.Null?; requires TPM.cmd_state.CmdComplete? || TPM.cmd_state.Executing?; requires power2(32) == 0x100000000; requires valid_cmd_present(TPM); modifies this`TPM; modifies this`IoMemPerm; ensures TPM_valid(TPM); ensures IoMemPerm.Null?; ensures r == 0x90 ==> TPM.cmd_state.CmdComplete?; ensures r == 0x90 ==> |TPM.reply_buf| > 0; ensures TPM.cmd_state.CmdComplete? || TPM.cmd_state.Executing?; //-ensures transitioned(old(TPM), TPM, r); ensures old(TPM) == TPM || (old(TPM.cmd_state.Executing?) && TPM.cmd_state.CmdComplete?); ensures old(TPM.cmd_state.Executing?) ==> async_TPM_execution(old(TPM), TPM) && //- May bump us to CmdComplete, or may leave us in Executing (r == 0x90 <==> TPM.cmd_state.CmdComplete?); //- 0x90 = TIS_STS_VALID (0x80) + TIS_STS_DATA_AVAIL (0x10) ensures old(TPM.cmd_state.CmdComplete?) ==> (r == 0x90 ==> |TPM.reply_buf| > 0) && old(TPM) == TPM; ensures old(TPM.cmd_state.CmdComplete?) ==> (r == 0x80 ==> |TPM.reply_buf| == 0) && old(TPM) == TPM; ensures valid_cmd_present(TPM); ensures r == 0x80 || r == 0x90; { //-r := TPM_instr_check_data_available(); r := 0; while (!(r == 0x80 || r == 0x90)) invariant Locality3_obtained(); invariant TPM_valid(TPM); invariant IoMemPerm.Null?; invariant TPM.cmd_state.CmdComplete? || TPM.cmd_state.Executing?; invariant power2(32) == 0x100000000; invariant valid_cmd_present(TPM); invariant r == 0x90 ==> TPM.cmd_state.CmdComplete?; invariant r == 0x90 ==> |TPM.reply_buf| > 0; invariant old(TPM) == TPM || (old(TPM.cmd_state.Executing?) && TPM.cmd_state.CmdComplete?); invariant old(TPM.cmd_state.Executing?) ==> async_TPM_execution(old(TPM), TPM) && //- May bump us to CmdComplete, or may leave us in Executing (r == 0x90 <==> TPM.cmd_state.CmdComplete?); //- 0x90 = TIS_STS_VALID (0x80) + TIS_STS_DATA_AVAIL (0x10) invariant old(TPM.cmd_state.CmdComplete?) ==> (r == 0x90 ==> |TPM.reply_buf| > 0) && old(TPM) == TPM; invariant old(TPM.cmd_state.CmdComplete?) ==> (r == 0x80 ==> |TPM.reply_buf| == 0) && old(TPM) == TPM; //-invariant r == 0x80 || r == 0x90; decreases *; { r := TPM_instr_check_data_available(); } } static lemma lemma_BEWordToFourBytesProducesByteSeq(v:int) requires Word32(v); ensures IsByteSeq(BEWordToFourBytes(v)); ensures |BEWordToFourBytes(v)| == 4; { lemma_2toX(); lemma_power2_is_power_2_general(); calc { power(power2(8), 4); power(power(2, 8), 4); { lemma_power_multiplies(2, 8, 4); } power(2, 8*4); power2(32); } lemma_BEIntToDigitSeq_private_properties(power2(8), 4, v); } static lemma lemma_BEWordToFourBytesAlwaysProducesByteSeq() ensures forall v:int :: Word32(v) ==> IsByteSeq(BEWordToFourBytes(v)) && |BEWordToFourBytes(v)| == 4; { forall v:int | Word32(v) ensures IsByteSeq(BEWordToFourBytes(v)); ensures |BEWordToFourBytes(v)| == 4; { lemma_BEWordToFourBytesProducesByteSeq(v); } } ================================================ FILE: ironclad-apps/src/Dafny/Drivers/TPM/tpm-wrapper-randoms.i.dfy ================================================ include "tpm-device.s.dfy" static predicate read_random_forall(start_index:int, random_bytes:seq) { forall j :: 0 <= j < |random_bytes| ==> TPM_random_byte(start_index + j) == random_bytes[j] } static lemma lemma_randoms_forall_is_TPM_random_bytes(start_index:int, random_bytes:seq) ensures read_random_forall(start_index, random_bytes) == (TPM_random_bytes(start_index, start_index+|random_bytes|) == random_bytes); decreases |random_bytes|; { if (|random_bytes|==0) { } else { lemma_randoms_forall_is_TPM_random_bytes(start_index, random_bytes[..|random_bytes|-1]); } } static lemma lemma_random_comprehension(start_index:int, ra:seq, rb:seq) requires TPM_random_bytes(start_index, start_index+|ra|) == ra; requires TPM_random_bytes(start_index+|ra|, start_index+|ra|+|rb|) == rb; ensures TPM_random_bytes(start_index, start_index+|ra|+|rb|) == ra+rb; { lemma_randoms_forall_is_TPM_random_bytes(start_index, ra); lemma_randoms_forall_is_TPM_random_bytes(start_index+|ra|, rb); lemma_randoms_forall_is_TPM_random_bytes(start_index, ra+rb); } static lemma lemma_TPM_random_bytes_length(old_random_index:int, new_random_index:int) requires old_random_index <= new_random_index; ensures |TPM_random_bytes(old_random_index, new_random_index)| == new_random_index - old_random_index; decreases new_random_index-old_random_index; { if (old_random_index == new_random_index) { } else { lemma_TPM_random_bytes_length(old_random_index, new_random_index-1); } } static function TPM_random_bytes_premium (old_random_index:int, new_random_index:int) : seq requires old_random_index <= new_random_index; ensures |TPM_random_bytes_premium(old_random_index, new_random_index)| == new_random_index - old_random_index; { lemma_TPM_random_bytes_length(old_random_index, new_random_index); TPM_random_bytes(old_random_index, new_random_index) } static predicate TPMs_match_except_for_randoms (TPM1:TPM_struct, TPM2:TPM_struct) { TPMs_match(TPM1, TPM2[random_index := TPM1.random_index]) } ================================================ FILE: ironclad-apps/src/Dafny/Drivers/TPM/tpm-wrapper.i.dfy ================================================ include "tpm-driver.i.dfy" include "tpm-wrapper-randoms.i.dfy" include "../../Libraries/Crypto/Hash/sha1_hmac.i.dfy" include "../../Libraries/Util/integer_sequences.i.dfy" include "../../Libraries/Util/repeat_digit.i.dfy" include "../IO/pci.i.dfy" /*************************************************************************** * Higher-level Implementation ***************************************************************************/ /*********************************************************************************** Datatypes ***********************************************************************************/ datatype TPMSessionAndKey = TPMSessionAndKey_c(auth_handle:seq, nonce_even:seq, key_handle:seq, key_auth:seq) predicate TPMSessionAndKeyValid(sk:TPMSessionAndKey) { IsByteSeqOfLen(sk.auth_handle, 4) && IsByteSeqOfLen(sk.nonce_even, 20) && IsByteSeqOfLen(sk.key_handle, 4) && IsByteSeqOfLen(sk.key_auth, 20) } /*********************************************************************************** Useful lemmas ***********************************************************************************/ static lemma lemma_length_two_sequences_match_iff_all_match(s1:seq, s2:seq) requires |s1| == |s2| == 2; ensures s1 != s2 <==> (s1[0] != s2[0] || s1[1] != s2[1]); { } static lemma lemma_length_five_sequences_match_iff_all_match(s1:seq, s2:seq) requires |s1| == |s2| == 5; ensures s1 != s2 <==> (s1[0] != s2[0] || s1[1] != s2[1] || s1[2] != s2[2] || s1[3] != s2[3] || s1[4] != s2[4]); { } /*********************************************************************************** Useful functions ***********************************************************************************/ predicate TPM_ready() reads this`TPM; reads this`IoMemPerm; { Locality3_obtained() && TPM_valid(TPM) && TPM_satisfies_integrity_policy(TPM) && IoMemPerm.Null? } /*********************************************************************************** Assemble the sequences for each cmd ***********************************************************************************/ /* static method build_get_permanent_flags_cmd() returns (cmd:seq) ensures IsByteSeq(cmd); ensures |cmd| > 1; ensures parse_TPM_command(cmd) == TPMCommandGetPermanentFlags_c(); { cmd := [ 0x00, 0xc1, 0x00, 0x00, 0x00, 22, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 4, 0x00, 0x00, 0x01, 0x08]; lemma_2toX(); lemma_ValueOfFourByteSeqSpecific(cmd[2..6], 22); //- command length lemma_ValueOfFourByteSeqSpecific(cmd[6..10], TPM_ORD_GetCapability()); lemma_ValueOfFourByteSeqSpecific(cmd[10..14], TPM_CAP_FLAG()); lemma_ValueOfFourByteSeqSpecific(cmd[14..18], 4); //- subcap length lemma_ValueOfFourByteSeqSpecific(cmd[18..22], TPM_CAP_FLAG_PERMANENT()); } static method build_write_NVRAM_cmd(secret:seq) returns (cmd:seq) requires IsByteSeqOfLen(secret, NV_size()); ensures IsByteSeq(cmd); ensures |cmd| > 1; ensures parse_TPM_command(cmd) == TPMCommandWriteNVRAM_c(0x00011228, secret); { var nvindex := 0x00011228; lemma_2toX(); var nvindex_bytes := BEWordToFourBytes_impl(nvindex); cmd := [ 0x00, 0xc1, 0, 0, 1, 22, 0x00, 0x00, 0x00, 0xcd] + nvindex_bytes + [ 0, 0, 0, 0, 0, 0, 1, 0 ] + secret; //- TPM_TAG_RQU_COMMAND cmd_len==22+256 TPM_ORD_NV_WriteValue offset==0 data_size==256 lemma_ValueOfFourByteSeqSpecific(cmd[2..6], 22 + 256); //- command length lemma_ValueOfFourByteSeqSpecific(cmd[6..10], TPM_ORD_NV_WriteValue()); assert cmd[10..14] == nvindex_bytes; lemma_ValueOfFourByteSeqSpecific(cmd[14..18], 0); //- offset lemma_ValueOfFourByteSeqSpecific(cmd[18..22], 256); //- data size assert cmd[22..22+NV_size()] == secret; } static method build_get_NVRAM_capability_cmd(a:int) returns (cmd:seq) requires Word32(a); ensures IsByteSeq(cmd); ensures |cmd| > 1; ensures parse_TPM_command(cmd) == TPMCommandGetNVRAMCapability_c(a); { lemma_2toX(); var a_bytes := BEWordToFourBytes_impl(a); cmd := [ 0x00, 0xc1, 0x00, 0x00, 0x00, 22, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 4] + a_bytes; lemma_ValueOfFourByteSeqSpecific(cmd[2..6], 22); //- command length lemma_ValueOfFourByteSeqSpecific(cmd[6..10], TPM_ORD_GetCapability()); lemma_ValueOfFourByteSeqSpecific(cmd[10..14], TPM_CAP_NV_INDEX()); lemma_ValueOfFourByteSeqSpecific(cmd[14..18], 4); //- subcap length assert cmd[18..22] == a_bytes; } */ static method build_read_PCR_17_or_18_cmd(a:int) returns (cmd:seq) requires a == 17 || a == 18; ensures IsByteSeq(cmd); ensures |cmd| > 1; ensures parse_TPM_command(cmd) == TPMCommandReadPCR17Or18_c(a); { cmd := [ 0x00, 0xc1, 0x00, 0x00, 0x00, 14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, a ]; lemma_2toX(); lemma_ValueOfFourByteSeqSpecific(cmd[2..6], 14); //- command length lemma_ValueOfFourByteSeqSpecific(cmd[6..10], TPM_ORD_PcrRead()); lemma_ValueOfFourByteSeqSpecific(cmd[10..14], a); } /* static method build_read_NVRAM_cmd(nvindex:int) returns (cmd:seq) requires Word32(nvindex); ensures IsByteSeq(cmd); ensures |cmd| > 1; ensures parse_TPM_command(cmd) == TPMCommandReadNVRAM_c(nvindex); { lemma_2toX(); var nvindex_bytes := BEWordToFourBytes_impl(nvindex); cmd := [ 0x00, 0xc1, 0x00, 0x00, 0x00, 22, 0x00, 0x00, 0x00, 0xcf ] + nvindex_bytes + [ 0, 0, 0, 0, 0, 0, 1, 0 ]; lemma_ValueOfFourByteSeqSpecific(cmd[2..6], 22); //- command length lemma_ValueOfFourByteSeqSpecific(cmd[6..10], TPM_ORD_NV_ReadValue()); assert cmd[10..14] == nvindex_bytes; lemma_ValueOfFourByteSeqSpecific(cmd[14..18], 0); //- offset lemma_ValueOfFourByteSeqSpecific(cmd[18..22], 256); //- data size } */ static method build_get_random_cmd(num_bytes:int) returns (cmd:seq) requires Word32(num_bytes); ensures IsByteSeq(cmd); ensures |cmd| > 1; ensures parse_TPM_command(cmd) == TPMCommandGetRandom_c(num_bytes); { var num_bytes_bytes := BEWordToFourBytes_impl(num_bytes); cmd := [ 0x00, 0xc1, 0x00, 0x00, 0x00, 14, 0x00, 0x00, 0x00, 0x46] + num_bytes_bytes; lemma_2toX(); lemma_ValueOfFourByteSeqSpecific(cmd[2..6], 14); //- command length lemma_ValueOfFourByteSeqSpecific(cmd[6..10], TPM_ORD_GetRandom()); assert cmd[10..14] == num_bytes_bytes; } method compute_quote_command_hmac(nonce_external:seq, pcr_selection:seq, add_version:seq, nonce_even:seq, nonce_odd:seq, continue_auth_session:seq, key_usage_auth:seq) returns (h:seq) requires IsByteSeqOfLen(nonce_external, 20) && IsByteSeqOfLen(pcr_selection, 5) && IsByteSeqOfLen(add_version, 1) && IsByteSeqOfLen(nonce_even, 20) && IsByteSeqOfLen(nonce_odd, 20) && IsByteSeqOfLen(continue_auth_session, 1) && IsByteSeqOfLen(key_usage_auth, 20); ensures IsByteSeqOfLen(h, 20); { var ordinal := [ 0x00, 0x00, 0x00, 0x3E ]; lemma_2toX(); var sha_input := ordinal + nonce_external + pcr_selection + add_version; var sha_words := SHA1_impl_Bytes(sha_input); var sha_output := BEWordSeqToByteSeq_impl(sha_words); var hmac_input := sha_output + nonce_even + nonce_odd + continue_auth_session; var auth_data_words := HMAC_SHA1_impl_Seqs(key_usage_auth, hmac_input); var auth_data := BEWordSeqToByteSeq_impl(auth_data_words); h := auth_data; } static lemma lemma_quote_cmd_ok (cmd:seq, key_handle:seq, nonce_external:seq, pcr_selection:seq, auth_handle:seq, nonce_odd:seq, auth_data:seq) requires IsByteSeqOfLen(key_handle, 4); requires IsByteSeqOfLen(nonce_external, 20); requires IsByteSeqOfLen(pcr_selection, 5); requires IsByteSeqOfLen(auth_handle, 4); requires IsByteSeqOfLen(nonce_odd, 20); requires IsByteSeqOfLen(auth_data, 20); requires cmd == [ 0x00, 0xc2, 0x00, 0x00, 0x00, 85, 0x00, 0x00, 0x00, 0x3e ] + key_handle + nonce_external + pcr_selection + [ 1 ] + auth_handle + nonce_odd + [ 1 ] + auth_data; ensures IsByteSeqOfLen(cmd, 85); ensures cmd[0..2] == TPM_TAG_RQU_AUTH1_COMMAND(); ensures cmd[0..2] != TPM_TAG_RQU_COMMAND(); ensures BEByteSeqToInt(cmd[2..6]) == 85; ensures BEByteSeqToInt(cmd[6..10]) == TPM_ORD_Quote2(); ensures cmd[10..14] == key_handle; ensures cmd[14..34] == nonce_external; ensures cmd[34..39] == pcr_selection; ensures cmd[39] == 1; ensures cmd[40..44] == auth_handle; ensures cmd[44..64] == nonce_odd; ensures cmd[64] == 1; ensures cmd[65..85] == auth_data; { lemma_2toX(); lemma_length_two_sequences_match_iff_all_match(cmd[0..2], TPM_TAG_RQU_COMMAND()); //- prove it's not TPM_TAG_RQU_COMMAND lemma_ValueOfFourByteSeqSpecific(cmd[2..6], 85); //- command length lemma_ValueOfFourByteSeqSpecific(cmd[6..10], TPM_ORD_Quote2()); } method build_quote_cmd (nonce_external:seq, key_handle:seq, auth_handle:seq, nonce_even:seq, usage_key:seq) returns (cmd:seq) requires IsByteSeqOfLen(nonce_external, 20); requires IsByteSeqOfLen(key_handle, 4); requires IsByteSeqOfLen(auth_handle, 4); requires IsByteSeqOfLen(nonce_even, 20); requires IsByteSeqOfLen(usage_key, 20); ensures IsByteSeq(cmd); ensures |cmd| > 1; ensures parse_TPM_command(cmd) == TPMCommandQuote2_c(nonce_external, key_handle, auth_handle); { lemma_2toX(); var pcr_selection := [ 0x00, 0x03, 0x00, 0x00, 0x0E ]; var nonce_odd := [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]; var auth_data := compute_quote_command_hmac(nonce_external, pcr_selection, [ 1 ], nonce_even, nonce_odd, [ 1 ], usage_key); cmd := [ 0x00, 0xc2, 0x00, 0x00, 0x00, 85, 0x00, 0x00, 0x00, 0x3e ] + key_handle + nonce_external + pcr_selection + [ 1 ] + auth_handle + nonce_odd + [ 1 ] + auth_data; assert cmd[44..64] == nonce_odd; lemma_quote_cmd_ok(cmd, key_handle, nonce_external, pcr_selection, auth_handle, nonce_odd, auth_data); } static method build_extend_PCR_19_cmd(data:seq) returns (cmd:seq) requires IsByteSeqOfLen(data, 20); ensures IsByteSeq(cmd); ensures |cmd| > 1; ensures parse_TPM_command(cmd) == TPMCommandExtendPCR19_c(data); { cmd := [ 0x00, 0xc1, 0x00, 0x00, 0x00, 34, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 19 ] + data; lemma_2toX(); lemma_ValueOfFourByteSeqSpecific(cmd[2..6], 34); //- command length lemma_ValueOfFourByteSeqSpecific(cmd[6..10], TPM_ORD_Extend()); lemma_ValueOfFourByteSeqSpecific(cmd[10..14], 19); //- pcr index assert cmd[14..34] == data; } static method build_oiap_cmd() returns (cmd:seq) ensures IsByteSeq(cmd); ensures |cmd| > 1; ensures parse_TPM_command(cmd) == TPMCommandOIAP_c(); { cmd := [ 0x00, 0xc1, 0x00, 0x00, 0x00, 10, 0x00, 0x00, 0x00, 0x0A ]; lemma_2toX(); lemma_ValueOfFourByteSeqSpecific(cmd[2..6], 10); //- command length lemma_ValueOfFourByteSeqSpecific(cmd[6..10], TPM_ORD_OIAP()); } method build_loadkey_cmd(key:seq, auth_handle:seq, nonce_even:seq) returns (cmd:seq) requires IsByteSeq(key); requires |key| < 10000; requires IsByteSeqOfLen(auth_handle, 4); requires IsByteSeqOfLen(nonce_even, 20); ensures IsByteSeq(cmd); ensures |cmd| > 1; ensures parse_TPM_command(cmd) == TPMCommandLoadKey2_c(); { lemma_2toX(); var len := 59 + |key|; var len_bytes := BEWordToFourBytes_impl(len); var ordinal := [ 0x00, 0x00, 0x00, 0x41 ]; var header := [ 0x00, 0xc2 ] + len_bytes + ordinal; var SRK_handle := [ 0x40, 0, 0, 0 ]; //-0x40000000 var nonce_odd := [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]; var srk_authdata := nonce_odd; //- SRK auth is 20 0s; just happens to match the nonce_odd we chose var continue := [ 1 ]; var sha_input := ordinal + key; var sha_words := SHA1_impl_Bytes(sha_input); var sha_output := BEWordSeqToByteSeq_impl(sha_words); var hmac_input := sha_output + nonce_even + nonce_odd + continue; var auth_data_words := HMAC_SHA1_impl_Seqs(srk_authdata, hmac_input); var auth_data := BEWordSeqToByteSeq_impl(auth_data_words); cmd := header + SRK_handle + key + auth_handle + nonce_odd + continue + auth_data; lemma_ValueOfFourByteSeqSpecific(cmd[6..10], TPM_ORD_LoadKey2()); lemma_length_two_sequences_match_iff_all_match(cmd[0..2], TPM_TAG_RQU_COMMAND()); //- prove it's not TPM_TAG_RQU_COMMAND assert cmd[2..6] == len_bytes; assert len == |cmd|; } //-//////////////////////////////////////////////////////////////////////////////// //- Methods for dealing with replies //-//////////////////////////////////////////////////////////////////////////////// static method compute_is_TPM_reply_header_ok(reply:seq, expected_tag:seq) returns (ok:int) requires IsByteSeq(reply); requires IsByteSeqOfLen(expected_tag, 2); ensures ok == 0 <==> is_TPM_reply_header_ok(reply, expected_tag); { if |reply| < 10 { ok := 1; return; } lemma_length_two_sequences_match_iff_all_match(reply[0..2], expected_tag); if reply[0] != expected_tag[0] || reply[1] != expected_tag[1] { ok := 2; return; } var packet_size := BEFourBytesToWord_impl(reply[2..6]); if packet_size != |reply| { ok := 0x8000000 + packet_size * 0x1000 + |reply|; if (ok == 0) { ok := 3; } //- Assure Dafny that ok didn't become 0 when added to packet_size return; } lemma_ValueOfFourByteSeq(reply[6..10]); if reply[6] != 0 || reply[7] != 0 || reply[8] != 0 || reply[9] != 0 { ok := 4; return; } ok := 0; } //-///////////////////////////////////////////////////////////////// //- Actual functionality //-///////////////////////////////////////////////////////////////// //- Template for TPM operations //- modifies this`TPM; //- Except... //- ensures old(TPM.PCR_19) == TPM.PCR_19; //- ensures old(TPM.NVRAM) == TPM.NVRAM; //- ensures old(TPM.NV_locked) == TPM.NV_locked; //- ensures old(TPM.NV_perms_ok) == TPM.NV_perms_ok; //- ensures old(TPM.cmd_state) == TPM.cmd_state; //- ensures old(TPM.cmd_buf) == TPM.cmd_buf; //- ensures old(TPM.reply_buf) == TPM.reply_buf; //- ensures old(TPM.random_index) == TPM.random_index; method get_pcr(a:int) returns (r:bool, pcr:seq) requires a == 17 || a == 18; requires TPM_ready(); modifies this`TPM; modifies this`IoMemPerm; ensures r ==> PCR_val(a) == pcr; ensures r ==> IsByteSeqOfLen(pcr, 20); ensures TPM_ready(); ensures TPMs_match(TPM, old(TPM)); { //- Build the command: var cmd := build_read_PCR_17_or_18_cmd(a); lemma_2toX(); ghost var intermediate_TPM:TPM_struct := TPM[cmd_state := Executing][cmd_buf := cmd]; var reply := perform_command(cmd); ghost var after_TPM:TPM_struct := TPM[reply_buf := reply]; assert async_TPM_execution(intermediate_TPM, after_TPM); assert TPM_executed_read_PCR_17_or_18(intermediate_TPM, after_TPM); r := false; pcr := []; var ok := compute_is_TPM_reply_header_ok(reply, [0, 0xC4]); if ok != 0 { return; } if |reply| != 30 { return; } r := true; pcr := reply[10..30]; } /* //- Determine whether the TPM NVRAM has been properly locked method check_locked() returns (r:bool) requires TPM_ready(); modifies this`TPM; modifies this`IoMemPerm; ensures r ==> TPM.NV_locked; ensures TPM_ready(); ensures TPMs_match(TPM, old(TPM)); { //- Build the command: var cmd := build_get_permanent_flags_cmd(); ghost var intermediate_TPM:TPM_struct := TPM[cmd_state := Executing][cmd_buf := cmd]; var reply := perform_command(cmd); ghost var after_TPM:TPM_struct := TPM[reply_buf := reply]; assert async_TPM_execution(intermediate_TPM, after_TPM); assert TPM_executed_get_permanent_flags(intermediate_TPM, after_TPM); r := false; lemma_2toX(); var ok := compute_is_TPM_reply_header_ok(reply, [0, 0xC4]); if ok != 0 { return; } if |reply| != 36 { return; } var resp_size := BEFourBytesToWord_impl(reply[10..14]); if resp_size != 22 { return; } lemma_length_two_sequences_match_iff_all_match(reply[14..16], TPM_TAG_PERMANENT_FLAGS()); var tag := reply[14..16]; if tag[0] != 0 || tag[1] != 0x1F { return; } var nv_locked := reply[31]; r := (nv_locked == 1); } function method{:dafnycc_conservative_seq_triggers} check_perms_reply_given_pcrs_digest(reply:seq, desired_pcrs_digest:seq) : bool requires |reply| == 85; { var tag := reply[14..16]; var pcr_info_read := reply[20..46]; var pcr_selection_read := pcr_info_read[0..5]; var localities_bit_vector_read := pcr_info_read[5]; var pcrs_digest_read := pcr_info_read[6..26]; var pcr_info_write := reply[46..72]; var pcr_selection_write := pcr_info_write[0..5]; var localities_bit_vector_write := pcr_info_write[5]; var pcrs_digest_write := pcr_info_write[6..26]; var permission_tag := reply[72..74]; var permission_attributes := reply[74..78]; var read_st_clear := reply[78]; var write_st_clear := reply[79]; var write_define := reply[80]; var desired_pcr_selection := [ 0, 3, 0, 0, 6 ]; !( tag[0] != 0 || tag[1] != 0x18 || pcr_selection_read != desired_pcr_selection || pcrs_digest_read != desired_pcrs_digest || pcr_selection_write != desired_pcr_selection || pcrs_digest_write != desired_pcrs_digest || permission_tag != [ 0, 23 ] || permission_attributes != [ 0, 0, 0x20, 0 ] || read_st_clear != 0 || write_st_clear != 0 || write_define != 0 ) } method{:dafnycc_conservative_seq_triggers} check_perms_given_pcrs_digest(a:int, desired_pcrs_digest:seq) returns (r:bool) requires TPM_ready(); modifies this`TPM; modifies this`IoMemPerm; requires Word32(a); ensures r && is_TPM_COMPOSITE_HASH(desired_pcrs_digest, PCR_val(17), PCR_val(18)) ==> valid_nv_index(TPM, a) && TPM.NV_perms_ok[a]; ensures TPM_ready(); ensures TPMs_match(TPM, old(TPM)); { //- Build the command: var cmd := build_get_NVRAM_capability_cmd(a); lemma_2toX(); ghost var intermediate_TPM:TPM_struct := TPM[cmd_state := Executing][cmd_buf := cmd]; var reply := perform_command(cmd); ghost var after_TPM:TPM_struct := TPM[reply_buf := reply]; assert var parsed := parse_TPM_reply_get_NVRAM_capability(reply); parsed.TPMReplyInvalid_c? || parsed.TPMReplyGetNVRAMCapability_c?; r := false; var ok := compute_is_TPM_reply_header_ok(reply, [0, 0xC4]); if ok != 0 { return; } if |reply| != 85 { return; } var resp_size := BEFourBytesToWord_impl(reply[10..14]); var nvindex := BEFourBytesToWord_impl(reply[16..20]); var data_size := BEFourBytesToWord_impl(reply[81..85]); if resp_size != 71 { return; } if nvindex != a { return; } if data_size != 256 { return; } r := check_perms_reply_given_pcrs_digest(reply, desired_pcrs_digest); ghost var tag := reply[14..16]; ghost var pcr_info_read := reply[20..46]; ghost var pcr_selection_read := pcr_info_read[0..5]; ghost var pcr_info_write := reply[46..72]; ghost var pcr_selection_write := pcr_info_write[0..5]; ghost var desired_pcr_selection := [ 0, 3, 0, 0, 6 ]; lemma_length_five_sequences_match_iff_all_match(pcr_selection_read, desired_pcr_selection); lemma_length_five_sequences_match_iff_all_match(pcr_selection_write, desired_pcr_selection); lemma_length_two_sequences_match_iff_all_match(tag, TPM_TAG_NV_DATA_PUBLIC()); } method create_pcrs_digest(PCR_17:seq, PCR_18:seq) returns (pcrs_digest:seq) requires IsByteSeqOfLen(PCR_17, 20); requires IsByteSeqOfLen(PCR_18, 20); ensures is_TPM_COMPOSITE_HASH(pcrs_digest, PCR_17, PCR_18); { lemma_2toX(); var pcr_composite := PCR_SELECTION_covering_PCRs_17_and_18() + [0, 0, 0, 40] + //- size of next two PCRs PCR_17 + PCR_18; var hash_words := SHA1_impl_Bytes(pcr_composite); pcrs_digest := BEWordSeqToByteSeq_impl(hash_words); } method check_perms(a:int) returns (r:bool) requires TPM_ready(); modifies this`TPM; modifies this`IoMemPerm; requires Word32(a); ensures r ==> valid_nv_index(TPM, a) && TPM.NV_perms_ok[a]; ensures TPM_ready(); ensures TPMs_match(TPM, old(TPM)); { var PCR_17:seq, PCR_18:seq; r, PCR_17 := get_pcr(17); if !r { return; } r, PCR_18 := get_pcr(18); if !r { return; } var pcrs_digest := create_pcrs_digest(PCR_17, PCR_18); r := check_perms_given_pcrs_digest(a, pcrs_digest); } */ method extend_PCR(data:seq) returns (r:bool) requires TPM_ready(); modifies this`TPM; modifies this`IoMemPerm; requires IsByteSeqOfLen(data, 20); ensures r ==> TPM.PCR_19 == old(TPM.PCR_19) + [data]; ensures TPM_ready(); ensures TPMs_match(TPM, old(TPM)[PCR_19 := TPM.PCR_19]); { //- Build the command: var cmd := build_extend_PCR_19_cmd(data); ghost var intermediate_TPM:TPM_struct := TPM[cmd_state := Executing][cmd_buf := cmd]; lemma_2toX(); var reply := perform_command(cmd); ghost var after_TPM:TPM_struct := TPM[reply_buf := reply]; assert TPM_executed_extend_PCR_19(intermediate_TPM, after_TPM); r := false; var ok := compute_is_TPM_reply_header_ok(reply,[0, 0xC4]); if ok != 0 { return; } if |reply| != 30 { return; } r := true; } /* method store_secret(secret:seq) returns (r:bool) requires TPM_ready(); modifies this`TPM; modifies this`IoMemPerm; requires IsByteSeqOfLen(secret, NV_size()); requires secret[0] != 0xFF; requires TPM_app_policy_okay_to_trust(secret); requires valid_nv_index(TPM, 0x00011228); ensures r ==> valid_nv_index(TPM, 0x00011228) && TPM.NVRAM[0x00011228] == secret; ensures |TPM.NVRAM| == |old(TPM).NVRAM|; ensures forall a :: a != 0x00011228 && old(valid_nv_index(TPM, a)) && valid_nv_index(TPM, a) ==> old(TPM.NVRAM[a]) == TPM.NVRAM[a]; ensures TPM_ready(); ensures TPMs_match(TPM, old(TPM)[NVRAM := TPM.NVRAM]); { lemma_2toX(); var nvindex := 0x00011228; var cmd := build_write_NVRAM_cmd(secret); var locked := check_locked(); var perms_okay := check_perms(nvindex); if (!locked || ! perms_okay) { return false; } assert TPM.NV_locked; assert TPM.NV_perms_ok[nvindex]; ghost var intermediate_TPM:TPM_struct := TPM[cmd_state := Executing][cmd_buf := cmd]; var reply := perform_command(cmd); ghost var after_TPM:TPM_struct := TPM[reply_buf := reply]; assert async_TPM_execution(intermediate_TPM, after_TPM); assert TPM_executed_write_NVRAM(intermediate_TPM, after_TPM); r := false; var ok := compute_is_TPM_reply_header_ok(reply,[0, 0xC4]); if ok != 0 { return; } if |reply| != 10 { return; } r := true; } method read_secret() returns (r:bool, secret:seq) requires TPM_ready(); modifies this`TPM; modifies this`IoMemPerm; requires valid_nv_index(TPM, 0x00011228); ensures r ==> TPM_app_policy_okay_to_trust(secret); ensures TPM_ready(); ensures TPMs_match(TPM, old(TPM)); { //- Build the command: var nvindex := 0x00011228; assert Word32(nvindex); r := false; secret := []; var locked := check_locked(); var perms_okay := check_perms(nvindex); if (!locked || ! perms_okay) { return; } var cmd := build_read_NVRAM_cmd(nvindex); ghost var intermediate_TPM:TPM_struct := TPM[cmd_state := Executing][cmd_buf := cmd]; var reply := perform_command(cmd); ghost var after_TPM:TPM_struct := TPM[reply_buf := reply]; lemma_2toX(); var ok := compute_is_TPM_reply_header_ok(reply,[0, 0xC4]); if ok != 0 { return; } if |reply| < 14 { return; } var data_size := BEFourBytesToWord_impl(reply[10..14]); if |reply| != 14 + data_size { return; } var data := reply[14..14+data_size]; if (data[0] == 0xFF) { return; } //- make sure it isn't newly_created_NV_value() assert TPM_satisfies_integrity_policy(TPM); assert data == TPM.NVRAM[nvindex]; assert TPM_app_policy_okay_to_trust(data) || data == newly_created_NV_value(); Lemma_RepeatDigitProperties(0xFF, NV_size()); //- This proves that newly_created_NV_value()[0] == 0xff, so data isn't newly_created_NV_value() assert data != newly_created_NV_value(); r := true; secret := data; } */ //- Start an authorization session with the TPM method start_oiap_session() returns (success:bool, auth_handle:seq, nonce_even:seq) requires TPM_ready(); modifies this`TPM; modifies this`IoMemPerm; ensures success ==> IsByteSeqOfLen(auth_handle, 4); ensures success ==> IsByteSeqOfLen(nonce_even, 20); ensures TPM_ready(); //-ensures TPMs_match(TPM, old(TPM)[random_index := old(TPM).random_index + |random_bytes|]); ensures TPM == old(TPM); { //- Build the command: var cmd := build_oiap_cmd(); lemma_2toX(); ghost var intermediate_TPM:TPM_struct := TPM[cmd_state := Executing][cmd_buf := cmd]; var reply := perform_command(cmd); ghost var after_TPM:TPM_struct := TPM[reply_buf := reply]; assert async_TPM_execution(intermediate_TPM, after_TPM); assert TPM_executed_OIAP(intermediate_TPM, after_TPM); var ok := compute_is_TPM_reply_header_ok(reply,[0, 0xC4]); auth_handle := []; nonce_even := []; if ok != 0 { if |reply| >= 10 { debug_print(0x49, ok); debug_print(0x50, reply[6]); debug_print(0x51, reply[7]); debug_print(0x52, reply[8]); debug_print(0x53, reply[9]); } success := false; return; } if |reply| != 34 { success := false; return; } var header:seq; var fields := reply[10: 4: 20]; header , auth_handle, nonce_even := fields[0], fields[1], fields[2]; success := true; } method debug_print_key_bytes(key_bytes:seq) { var i := 0; while (i<|key_bytes|) invariant 0 <= i <= |key_bytes|; { debug_print(0x28, key_bytes[i]); i := i + 1; } } method load_key(auth_handle:seq, nonce_even:seq) returns (success:bool, key_handle:seq, nonce_even_new:seq) requires TPM_ready(); requires IsByteSeqOfLen(auth_handle, 4); requires IsByteSeqOfLen(nonce_even, 20); modifies this`TPM; modifies this`IoMemPerm; ensures success ==> IsByteSeqOfLen(key_handle, 4); ensures success ==> IsByteSeqOfLen(nonce_even_new, 20); ensures TPM_ready(); ensures TPMs_match(TPM, old(TPM)); { key_handle := []; nonce_even_new := []; var key_len := GetBootloaderArgWord(1); debug_print(0x88, key_len); if (key_len > 1024 - 8 - 1 || key_len < 0) { success := false; return; } var key_bytes := GetBootloaderArgBytes(8, 8+key_len); //- debug_print_key_bytes(key_bytes); var cmd := build_loadkey_cmd(key_bytes, auth_handle, nonce_even); lemma_2toX(); ghost var intermediate_TPM:TPM_struct := TPM[cmd_state := Executing][cmd_buf := cmd]; var reply := perform_command(cmd); ghost var after_TPM:TPM_struct := TPM[reply_buf := reply]; assert async_TPM_execution(intermediate_TPM, after_TPM); assert TPM_executed_LoadKey2(intermediate_TPM, after_TPM); var ok := compute_is_TPM_reply_header_ok(reply,[0, 0xC5]); if ok != 0 { if |reply| >= 10 { debug_print(0x29, ok); debug_print(0x29, reply[6]); debug_print(0x29, reply[7]); debug_print(0x29, reply[8]); debug_print(0x29, reply[9]); } success := false; return; } if |reply| != 55 { success := false; return; } var header:seq, continue:seq, auth:seq; var fields := reply[10: 4: 20: 1: 20]; header , key_handle, nonce_even_new, continue, auth := fields[0], fields[1], fields[2], fields[3], fields[4]; success := true; } static method compute_aik_auth_data() returns (aik_auth:seq) ensures IsByteSeqOfLen(aik_auth, 20); { lemma_2toX(); var aik_secret := [115, 101, 99, 114, 101, 116]; // Shhh, don't tell! var hash_words := SHA1_impl_Bytes(aik_secret); aik_auth := BEWordSeqToByteSeq_impl(hash_words); } method establish_TPM_session_and_key () returns (success:bool, sk:TPMSessionAndKey) requires TPM_ready(); modifies this`TPM; modifies this`IoMemPerm; ensures success ==> TPMSessionAndKeyValid(sk); ensures TPM_ready(); ensures TPMs_match(TPM, old(TPM)); { lemma_2toX(); sk := TPMSessionAndKey_c([], [], [], []); var auth_handle:seq, nonce_even:seq; success, auth_handle, nonce_even := start_oiap_session(); if (!success) { debug_print(0x24, 0x0); return; } var key_handle:seq; success, key_handle, nonce_even := load_key(auth_handle, nonce_even); if (!success) { debug_print(0x24, 0xa); return; } var key_auth := compute_aik_auth_data(); sk := TPMSessionAndKey_c(auth_handle, nonce_even, key_handle, key_auth); } method{:dafnycc_conservative_seq_triggers} quote(sk_in:TPMSessionAndKey, nonce_external:seq) returns (r:bool, sk_out:TPMSessionAndKey, pcr_info:seq, sig:seq) requires TPM_ready(); modifies this`TPM; modifies this`IoMemPerm; requires TPMSessionAndKeyValid(sk_in); requires IsByteSeqOfLen(nonce_external, 20); ensures r ==> Verve_quote(pcr_info, sig, nonce_external, old(TPM).PCR_19); ensures TPMSessionAndKeyValid(sk_out); ensures IsByteSeq(pcr_info); ensures IsByteSeq(sig); ensures TPM_ready(); ensures TPMs_match(TPM, old(TPM)); { //- lemma_2toX(); //- //- var bootloader_bytes := GetBootloaderArgBytes(0, 48); //- var fields := bootloader_bytes[4 :4 :20 :20 ]; //- var key_handle, auth_handle, nonce_even, usage_key := //- fields[0], fields[1], fields[2], fields[3] ; //- //- //-auth_handle := [auth_handle[3], auth_handle[2], auth_handle[1], auth_handle[0]]; //- //- var success, auth_handle, nonce_even:= start_oiap_session(); //- r := false; //- q := []; //- if (!success) { debug_print(0x24, 0x0); return; } //- auth_handle := auth_handle_new; //- nonce_even := nonce_even_new; //- //- var key_handle:seq; //- success, key_handle, nonce_even := load_key(auth_handle, nonce_even); //- if (!success) { debug_print(0x24, 0xa); return; } //- //- var key_auth := compute_aik_auth_data(); //- //- var cmd := build_quote_cmd(nonce_external, key_handle, auth_handle, nonce_even, key_auth); r := false; pcr_info := []; sig := []; sk_out := sk_in; var cmd := build_quote_cmd(nonce_external, sk_in.key_handle, sk_in.auth_handle, sk_in.nonce_even, sk_in.key_auth); ghost var intermediate_TPM:TPM_struct := TPM[cmd_state := Executing][cmd_buf := cmd]; var reply := perform_command(cmd); assert old(intermediate_TPM) == intermediate_TPM; assert old(nonce_external) == nonce_external; lemma_2toX(); ghost var after_TPM:TPM_struct := TPM[reply_buf := reply]; assert async_TPM_execution(intermediate_TPM, after_TPM); assert TPM_executed_quote2(intermediate_TPM, after_TPM); var ok := compute_is_TPM_reply_header_ok(reply, [0, 0xC5]); if ok != 0 { if |reply| >= 10 { debug_print(0x20, ok); debug_print(0x20, reply[6]); debug_print(0x21, reply[7]); debug_print(0x22, reply[8]); debug_print(0x23, reply[9]); } return; } if |reply| < 40 { debug_print(0x24, 0x1); return; } pcr_info := reply[10..36]; var pcr_selection := pcr_info[0..5]; var localities_bit_vector := pcr_info[5]; lemma_length_five_sequences_match_iff_all_match(pcr_selection, PCR_SELECTION_covering_PCRs_17_through_19()); if pcr_selection[0] != 0 || pcr_selection[1] != 3 || pcr_selection[2] != 0 || pcr_selection[3] != 0 || pcr_selection[4] != 14 { debug_print(0x24, 0x3); return; } var version_info_size := BEFourBytesToWord_impl(reply[36..40]); if |reply| < 44 + version_info_size || version_info_size < 0 { debug_print(0x24, 0x4); return; } var sig_size := BEFourBytesToWord_impl(reply[40+version_info_size..44+version_info_size]); if |reply| != 85 + version_info_size + sig_size || sig_size < 0 { debug_print(0x24, 0x5); return; } var new_nonce_even := reply[44+version_info_size+sig_size..64+version_info_size+sig_size]; var continue_session := reply[64+version_info_size+sig_size]; if continue_session != 1 { debug_print(0x24, 0x6); return; } r := true; sig := reply[44+version_info_size..44+version_info_size+sig_size]; sk_out := sk_in[nonce_even := new_nonce_even]; } method get_random(num_bytes:nat) returns (random_bytes:seq) requires TPM_ready(); modifies this`TPM; modifies this`IoMemPerm; ensures IsByteSeqOfLen(random_bytes, num_bytes); ensures forall j :: 0 <= j < num_bytes ==> TPM_random_byte(old(TPM).random_index + j) == random_bytes[j]; ensures random_bytes == TPM_random_bytes(old(TPM).random_index, TPM.random_index); ensures TPM_ready(); ensures TPMs_match(TPM, old(TPM)[random_index := old(TPM).random_index + num_bytes]); { random_bytes := []; var num_bytes_still_needed := num_bytes; assert TPM == old(TPM)[cmd_state := TPM.cmd_state]; while (num_bytes_still_needed > 0) decreases *; invariant num_bytes_still_needed >= 0; invariant forall j :: 0 <= j < |random_bytes| ==> TPM_random_byte(old(TPM).random_index + j) == random_bytes[j]; invariant IsByteSeq(random_bytes); invariant |random_bytes| + num_bytes_still_needed == num_bytes; invariant TPM_ready(); invariant TPMs_match(TPM, old(TPM)[random_index := old(TPM).random_index + |random_bytes|]); { var bytes_to_get := if num_bytes_still_needed <= 0xFFFFFFFF then num_bytes_still_needed else 0xFFFFFFFF; lemma_2toX(); var bytes := get_random_basic(bytes_to_get); random_bytes := random_bytes + bytes; num_bytes_still_needed := num_bytes_still_needed - |bytes|; } lemma_randoms_forall_is_TPM_random_bytes(old(TPM).random_index, random_bytes); } //- Attempt to get a batch of random bytes from the TPM; TPM may reply with less method get_random_basic(num_bytes:int) returns (random_bytes:seq) requires TPM_ready(); requires Word32(num_bytes); modifies this`TPM; modifies this`IoMemPerm; ensures 0 <= |random_bytes| <= num_bytes; ensures IsByteSeq(random_bytes); ensures forall j :: 0 <= j < |random_bytes| ==> TPM_random_byte(old(TPM).random_index + j) == random_bytes[j]; ensures TPM_ready(); ensures TPMs_match(TPM, old(TPM)[random_index := old(TPM).random_index + |random_bytes|]); { //- Build the command: var cmd := build_get_random_cmd(num_bytes); lemma_2toX(); ghost var intermediate_TPM:TPM_struct := TPM[cmd_state := Executing][cmd_buf := cmd]; var reply := perform_command(cmd); ghost var after_TPM:TPM_struct := TPM[reply_buf := reply]; assert async_TPM_execution(intermediate_TPM, after_TPM); assert TPM_executed_get_random(intermediate_TPM, after_TPM); random_bytes := []; var ok := compute_is_TPM_reply_header_ok(reply,[0, 0xC4]); if ok != 0 { return; } if |reply| < 14 { return; } var random_bytes_size := BEFourBytesToWord_impl(reply[10..14]); if |reply| != 14 + random_bytes_size || random_bytes_size < 0 { return; } random_bytes := reply[14..14+random_bytes_size]; } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/.gitignore ================================================ *.bpl *.log ================================================ FILE: ironclad-apps/src/Dafny/Libraries/BigNum/.gitignore ================================================ *.bpl *.log ================================================ FILE: ironclad-apps/src/Dafny/Libraries/BigNum/BigNatAdd.i.dfy ================================================ include "Word32.i.dfy" include "BigNatCore.i.dfy" include "BigNatX86Shim.i.dfy" include "BigNatCompare.i.dfy" datatype Problem = Problem_ctor( A:BigNat, B:BigNat, c:nat); static predicate WellformedCarry(carry:nat) { carry==0 || carry==1 } static predicate WellformedProblem(p:Problem) { WellformedBigNat(p.A) && WellformedBigNat(p.B) && WellformedCarry(p.c) } static predicate WorksheetProblemsWellformed(ps:seq) { forall i :: 0 <= i < |ps| ==> WellformedProblem(ps[i]) } static function method ZeroProblem(p:Problem) : bool requires WellformedProblem(p); { zero(p.A) && zero(p.B) && p.c==0 } static predicate WorksheetProblemsConnected(p0:Problem, s0:nat, p1:Problem) requires WellformedProblem(p0); requires Word32(s0); requires WellformedProblem(p1); { p1.A == hi(p0.A) && p1.B == hi(p0.B) && lo(p0.A) + lo(p0.B) + p0.c == s0 + p1.c * Width() && !ZeroProblem(p0) } static predicate WellformedSolutions(ss:seq) { forall i :: 0 <= i < |ss| ==> ss[i]>=0 && Word32(ss[i]) } static predicate WorksheetConsistent(ps:seq, ss:seq) { WorksheetProblemsWellformed(ps) && |ps| == |ss|+1 && WellformedSolutions(ss) && (forall i:nat :: i < |ps|-1 ==> WorksheetProblemsConnected(ps[i], ss[i], ps[i+1])) } static predicate WorksheetComplete(ps:seq, ss:seq) { WorksheetConsistent(ps, ss) && ZeroProblem(ps[|ps|-1]) } static predicate problem_smaller(p0:Problem, p1:Problem) requires WellformedProblem(p0); requires WellformedProblem(p1); { I(p0.A) < I(p1.A) || (I(p0.A) == I(p1.A) && I(p0.B) < I(p1.B)) || (I(p0.A) == I(p1.A) && I(p0.B) == I(p1.B) && p0.c < p1.c) } static method solve_one_(p:Problem) returns (s:nat, pnew:Problem) requires WellformedProblem(p); requires !ZeroProblem(p); ensures s>=0 && Word32(s); ensures WellformedProblem(pnew); ensures Word32(s); ensures WorksheetProblemsConnected(p,s,pnew); ensures problem_smaller(pnew, p); ensures ZeroProblem(pnew) ==> s != 0; { var m:nat,c:nat := Add32_with_carry(lo(p.A), lo(p.B), p.c); s := m; pnew := Problem_ctor(hi(p.A), hi(p.B), c); if |p.A.words|==0 && |p.B.words|==0 { } else if |p.A.words|==0 { } else { } lemma_2to32(); lemma_mul_is_mul_boogie_Width(); reveal_I(); /* TODO: should dafnycc support ghost if statements in non-ghost methods? if (ZeroProblem(pnew)) { if (s==0) { calc { 0; s; lo(p.A) + lo(p.B) + p.c - c*Width(); lo(p.A) + lo(p.B) + p.c - pnew.c*Width(); { lemma_mul_basics_forall(); } lo(p.A) + lo(p.B) + p.c; } assert !ZeroProblem(p); assert false; } assert s != 0; } if (I(p.A)!=0) { lemma_hi_decreases(p.A); } else if (I(p.B)!=0) { lemma_hi_decreases(p.A); lemma_hi_decreases(p.B); } else { lemma_hi_decreases(p.A); lemma_hi_decreases(p.B); assert p.c > 0; //- !ZeroProblem(p) assert p.c == 1; //- WellformedProblem(p) if (pnew.c > 0) { calc { s+pnew.c*Width(); lo(p.A) + lo(p.B) + c; { assert zero(p.A); } 0 + lo(p.B) + c; { assert zero(p.B); } 0 + 0 + c; c; 1; } assert pnew.c == 1; calc { 1; < { lemma_2to32(); } Width(); { lemma_mul_basics(Width()); } pnew.c*Width(); } assert false; } assert pnew.c < p.c; } */ } static method BigNatAdd_(A:BigNat, B:BigNat) returns (ss:seq, ghost ps:seq) requires WellformedBigNat(A); requires WellformedBigNat(B); ensures |ps|>0; ensures ps[0].A == A; ensures ps[0].B == B; ensures ps[0].c == 0; ensures WorksheetComplete(ps,ss); ensures |ss|>0 ==> ss[|ss|-1]>0; { var p:Problem := Problem_ctor(A,B,0); ps := [ p ]; ss := []; lemma_I_is_nonnegative_forall(); while (!ZeroProblem(p)) decreases I(p.A),I(p.B),p.c; invariant 0 < |ps|; invariant ps[|ps|-1] == p; invariant WorksheetConsistent(ps, ss); invariant ps[0].A==A && ps[0].B==B && ps[0].c==0; invariant WellformedProblem(p); invariant forall i :: 0<=i<|ps|-1 ==> !ZeroProblem(ps[i]); invariant ZeroProblem(p) ==> (|ss|>0 ==> ss[|ss|-1]>0); { ghost var pold := p; var s:nat,pnew:Problem := solve_one_(p); ss := ss + [s]; ps := ps + [pnew]; assert WorksheetProblemsConnected(p,s,pnew); assert ps[|ps|-2] == p; assert ss[|ss|-1] == s; assert ps[|ps|-1] == pnew; assert WorksheetProblemsConnected(ps[|ps|-2], ss[|ss|-1], ps[|ps|-1]); assert forall i :: 0 <= i < |ps|-1 ==> WorksheetProblemsConnected(ps[i], ss[i], ps[i+1]); assert WorksheetConsistent(ps, ss); assert ZeroProblem(p) ==> ss[|ss|-1]>0; /* TODO: should dafnycc support forall statement in non-ghost methods? forall (i:nat | i < |ps|-1) ensures WorksheetProblemsConnected(ps[i], ss[i], ps[i+1]); { if (i < |ps|-2) { //- induction hypothesis WorksheetConsistent(ps,ss); assert WorksheetProblemsConnected(ps[i], ss[i], ps[i+1]); } else { //- solve_one ensures assert WorksheetProblemsConnected(p, s, pnew); assert WorksheetProblemsConnected(ps[i], ss[i], ps[i+1]); } } assert WorksheetConsistent(ps, ss); if (ZeroProblem(p)) { assert ss[|ss|-1]>0; } */ assert problem_smaller(pnew,p); p := pnew; lemma_I_is_nonnegative_forall(); assert 0<=I(p.A); assert 0<=I(p.B); } } static function ProblemValue(p:Problem) : int requires WellformedProblem(p); { I(p.A) + I(p.B) + p.c } static predicate WellformedBigNatSeq(R:seq) { forall i :: 0 <= i < |R| ==> WellformedBigNat(R[i]) } static predicate WellformedWordSeq(s:seq) { forall i :: 0 <= i < |s| ==> s[i]>=0 && Word32(s[i]) } //-//////////////////////////////////////////////////////////////////////////// //- These functions define the relationship between a sequence of words //- and a sequence of BigNats formed from subsequences of the word seq. //- That's so that we can show that the high-place-value partial sums //- (one word at a time) can be viewed as correct BigNat solutions to the //- truncated problems. Then we inductively include low-order words one //- at a time until we've reconstructed the original problem. static predicate BigNatsForSumWords_Base(ss:seq, R:seq) requires WellformedBigNatSeq(R); { |R| == |ss|+1 && R[|R|-1] == BigNat_ctor([]) && R[0] == BigNat_ctor(ss) } static predicate BigNatsForSumWords_Nonzero(ss:seq, R:seq) requires WellformedBigNatSeq(R); requires BigNatsForSumWords_Base(ss, R); { forall i :: 0 <= i < |ss| ==> nonzero(R[i]) } static predicate BigNatsForSumWords_Assembly(ss:seq, R:seq) requires WellformedBigNatSeq(R); requires BigNatsForSumWords_Base(ss, R); { forall i :: 0 <= i <=|ss| ==> R[i] == BigNat_ctor(ss[i..]) } static predicate ShiftRelation(M:seq, i:nat) requires WellformedBigNatSeq(M); requires i < |M|-1; { I(M[i]) == I(M[i+1]) * Width() + lo(M[i]) } static predicate ShiftRelationSeq(ss:seq, R:seq) requires WellformedBigNatSeq(R); requires |R| == |ss|+1; { forall i :: 0 <= i < |ss| ==> ShiftRelation(R, i) } static lemma ShiftRelationLemma(M:seq, i:nat) requires WellformedBigNatSeq(M); requires i < |M|-1; requires ShiftRelation(M,i); ensures I(M[i]) == I(M[i+1]) * Width() + lo(M[i]); { reveal_I(); } static predicate BigNatsForSumWords(ss:seq, R:seq) requires WellformedBigNatSeq(R); { BigNatsForSumWords_Base(ss,R) && BigNatsForSumWords_Nonzero(ss, R) && BigNatsForSumWords_Assembly(ss, R) && ShiftRelationSeq(ss,R) } static lemma ConstructBigNatsFromSumWords_lemma(ss:seq, R:seq) requires WellformedBigNatSeq(R); requires WellformedWordSeq(ss); requires |ss|>0; requires ss[|ss|-1] > 0; requires |R| == |ss|+1; requires BigNatsForSumWords(ss[1..],R[1..]); requires nonzero(R[0]); requires R[0] == BigNat_ctor(ss); ensures BigNatsForSumWords_Base(ss,R); ensures BigNatsForSumWords(ss,R); { forall (i:nat | i < |ss|) ensures nonzero(R[i]); { if (i>0) { assert nonzero(R[1..][i-1]); assert nonzero(R[i]); } } assert BigNatsForSumWords_Nonzero(ss,R); forall (i:nat | i <=|ss|) ensures R[i] == BigNat_ctor(ss[i..]); { if (i==0) { assert ss == ss[0..]; } else { assert R[1..][i-1] == R[i]; assert ss[1..][i-1..] == ss[i..]; } } assert BigNatsForSumWords_Assembly(ss,R); forall (i:nat | i < |ss|) ensures ShiftRelation(R, i); { if (i==0) { reveal_I(); assert ShiftRelation(R, 0); } else { assert R[1..][i-1] == R[i]; calc ==> { ShiftRelationSeq(ss[1..],R[1..]); ShiftRelation(R[1..], i-1); ShiftRelation(R, i); } } } assert ShiftRelationSeq(ss,R); } static lemma ConstructBigNatsFromSumWords_(ss:seq) returns (R:seq) requires WellformedWordSeq(ss); requires |ss|>0 ==> ss[|ss|-1] > 0; ensures WellformedBigNatSeq(R); ensures BigNatsForSumWords(ss,R); { var r:BigNat := BigNat_ctor(ss); var tail:seq; if |ss|==0 { tail := []; R := [r] + tail; } else { tail := ConstructBigNatsFromSumWords_(ss[1..]); R := [r] + tail; var next:BigNat:= tail[0]; ConstructBigNatsFromSumWords_lemma(ss, R); } } static lemma lemma_accumulate(s:int, ss:seq, ps:seq, Ms:seq) decreases |ss|-s; requires 0<=s<=|ss|; requires WorksheetComplete(ps,ss); requires WellformedBigNatSeq(Ms); requires BigNatsForSumWords(ss,Ms); ensures I(Ms[s]) == ProblemValue(ps[s]); { if (s==|ss|) { calc { ProblemValue(ps[s]); I(ps[s].A) + I(ps[s].B) + ps[s].c; { reveal_I(); } 0; { reveal_I(); } I(Ms[s]); } } else { calc { I(Ms[s]); { ShiftRelationLemma(Ms, s); } I(Ms[s+1]) * Width() + lo(Ms[s]); I(Ms[s+1]) * Width() + ss[s]; I(Ms[s+1]) * Width() + lo(ps[s].A)+lo(ps[s].B)+ps[s].c - ps[s+1].c * Width(); { lemma_accumulate(s+1, ss, ps, Ms); } I(Ms[s+1]) * Width() + lo(ps[s].A)+lo(ps[s].B)+ps[s].c - ((I(Ms[s+1]) - I(ps[s+1].A)) - I(ps[s+1].B)) * Width(); //-{ lemma_mul_properties(); } { lemma_mul_is_commutative(Width(), (I(Ms[s+1]) - I(ps[s+1].A)) - I(ps[s+1].B)); } I(Ms[s+1]) * Width() + lo(ps[s].A)+lo(ps[s].B)+ps[s].c - Width() * ((I(Ms[s+1]) - I(ps[s+1].A)) - I(ps[s+1].B)); //-{ lemma_mul_properties(); } { lemma_mul_is_distributive_sub(Width(), I(Ms[s+1]) - I(ps[s+1].A), I(ps[s+1].B)); } I(Ms[s+1]) * Width() + lo(ps[s].A)+lo(ps[s].B)+ps[s].c - (Width() * (I(Ms[s+1]) - I(ps[s+1].A)) - Width() * I(ps[s+1].B)); //-{ lemma_mul_properties(); } { lemma_mul_is_distributive_sub(Width(), I(Ms[s+1]), I(ps[s+1].A)); } I(Ms[s+1]) * Width() + lo(ps[s].A)+lo(ps[s].B)+ps[s].c - (Width() * I(Ms[s+1]) - Width() * I(ps[s+1].A) - Width() * I(ps[s+1].B)); //-{ lemma_mul_properties(); } { lemma_mul_is_commutative(Width(),I(Ms[s+1])); } Width() * I(Ms[s+1]) + lo(ps[s].A)+lo(ps[s].B)+ps[s].c - (Width() * I(Ms[s+1]) - Width() * I(ps[s+1].A) - Width() * I(ps[s+1].B)); Width() * I(Ms[s+1]) + lo(ps[s].A)+lo(ps[s].B)+ps[s].c - Width() * I(Ms[s+1]) + Width() * I(ps[s+1].A) + Width() * I(ps[s+1].B); //- Collapse the canceling terms lo(ps[s].A)+Width() * I( ps[s+1].A ) +lo(ps[s].B)+ps[s].c+Width() * I(ps[s+1].B); { lemma_mul_is_commutative(Width(),I( ps[s+1].A )); lemma_mul_is_commutative(Width(),I( ps[s+1].B )); } lo(ps[s].A)+I( ps[s+1].A ) * Width() +lo(ps[s].B)+ps[s].c+I(ps[s+1].B) * Width(); lo(ps[s].A)+I(hi(ps[s].A)) * Width() +lo(ps[s].B)+I(hi(ps[s].B)) * Width() +ps[s].c; { lemma_hilo(ps[s].A); lemma_hilo(ps[s].B); } I(ps[s].A) + I(ps[s].B)+ps[s].c; ProblemValue(ps[s]); } } } static method BigNatAdd(A:BigNat, B:BigNat) returns (R:BigNat) requires WellformedBigNat(A); requires WellformedBigNat(B); ensures WellformedBigNat(R); ensures I(A)+I(B) == I(R); { var ss:seq; ghost var ps:seq; ss,ps := BigNatAdd_(A,B); ghost var Ms:seq := ConstructBigNatsFromSumWords_(ss); //- Ms[i] is the BigNat formed by ss[i..]. It includes Ms[|ss|], which is always BigNat_ctor([]) (0) R := BigNat_ctor(ss); calc { I(R); I(Ms[0]); { lemma_accumulate(0,ss,ps,Ms); } ProblemValue(ps[0]); I(ps[0].A) + I(ps[0].B) + ps[0].c; I(ps[0].A) + I(ps[0].B); I(A) + I(B); } } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/BigNum/BigNatBitCount.i.dfy ================================================ include "../../Drivers/IO/pci.i.dfy" include "BigNatX86Shim.i.dfy" include "BigNatCore.i.dfy" include "BigNatCompare.i.dfy" //- just for the mul synonyms. clean up. include "../Math/power2.i.dfy" static lemma lemma_power2_5_is_32() ensures power2(5) == 32; { lemma_power2_1_is_2(); reveal_power2(); assert power2(2)==4; assert power2(3)==8; assert power2(4)==16; assert power2(5)==32; } static lemma lemma_mul32power226_is_power31() ensures 32 * power2(26) == power2(31); { calc { 32 * power2(26); { lemma_power2_5_is_32(); } power2(5) * power2(26); { lemma_exponentiation(5,26); } power2(5+26); power2(31); } } static predicate ZeroBitRepresentation(A:BigNat, c:nat) requires WellformedBigNat(A); { c==0 <==> zero(A) } static predicate BitCount(A:BigNat, c:nat) requires WellformedBigNat(A); { ZeroBitRepresentation(A,c) && ((c>0) ==> (power2(c-1) <= I(A))) && (I(A) < power2(c)) } static function {:opaque} IntBitCount_inner(a:nat) : nat { if (a==0) then 0 else IntBitCount_inner(a/2)+1 } static lemma lemma_IntBitCount(a:nat, b:nat) requires b == IntBitCount_inner(a); ensures (b>0) ==> (power2(b-1) <= a); ensures a < power2(b); decreases a; { reveal_IntBitCount_inner(); if (a==0) { } else { assert b == IntBitCount_inner(a) == IntBitCount_inner(a/2)+1; assert b-1 == IntBitCount_inner(a/2); lemma_IntBitCount(a/2, b-1); assert (b-1>0) ==> (power2(b-1-1) <= a/2); assert a/2 < power2(b-1); assert a/2 <= power2(b-1)-1; if (a==1) { assert b==1; calc { power2(b-1); power2(0); { lemma_power2_0_is_1(); } 1; <= a; } } else { assert b == IntBitCount_inner(a/4)+2; assert b>1; calc { power2(b-1); { reveal_power2(); } 2*power2(b-2); <= 2*(a/2); <= 2*(a/2)+a%2; a; } } calc { a; 2*(a/2)+a%2; <= 2*(power2(b-1)-1)+a%2; 2*power2(b-1)-2+a%2; < 2*power2(b-1); { reveal_power2(); } power2(b); } } } static function IntBitCount(a:nat) : nat ensures (IntBitCount(a)>0) ==> (power2(IntBitCount(a)-1) <= a); ensures a < power2(IntBitCount(a)); { lemma_IntBitCount(a, IntBitCount_inner(a)); IntBitCount_inner(a) } static function KindaBigNat() : nat { power2(power2(31)) } static predicate ModestBigNatValue(A:BigNat) { WellformedBigNat(A) && I(A) < KindaBigNat() } static predicate ModestBigNatBits(A:BigNat,ac:nat) { WellformedBigNat(A) && BitCount(A,ac) && ac<=power2(31) } static predicate ModestBigNatWords(A:BigNat) { WellformedBigNat(A) && |A.words| <= power2(26) } static lemma WordConstructOneBits(s:nat) returns (a:nat) requires s<=32; ensures power2(s)-1==a; ensures s==0 <==> (a==0); ensures Word32(a); { if (s==0) { a := 0; lemma_power2_0_is_1(); } else if (s==1) { a := 1; lemma_power2_1_is_2(); } else { var sub_a:nat := WordConstructOneBits(s-1); a := 2*sub_a + 1; reveal_power2(); } assert power2(s)-1==a; if (s>0) { assert power2(s)-1 < power2(s); lemma_power2_increases(s,32); assert power2(s) <= power2(32); assert a < power2(32); } } static lemma MakePower2Minus1(thirtytwos:nat,ones:nat) returns (S:BigNat) requires 0 S.words[i] == Width() - 1; { lemma_mul_nonnegative(32,thirtytwos); if (thirtytwos == 0) { var ones_word:nat := WordConstructOneBits(ones); assert ones_word > 0; S := BigNat_ctor([ones_word]); calc ==> { true; { selectively_reveal_I(S); } I(S) == I(BigNat_ctor(S.words[1..])) * Width()+S.words[0]; { assert |S.words[1..]| == 0; } I(S) == I(BigNat_ctor([])) * Width()+ones_word; { assert zero(BigNat_ctor([])); lemma_mul_annihilate(Width()); } I(S) == ones_word; I(S) == power2(ones)-1; { lemma_mul_annihilate(32); } I(S) == power2(32 * thirtytwos+ones)-1; } } else { var sub_S:BigNat := MakePower2Minus1(thirtytwos-1, ones); //- I(sub_S) == power2(32*(thirtytwos-1) + ones)-1; var low_word:nat := WordConstructOneBits(32); S := BigNat_ctor([low_word] + sub_S.words); calc { I(S); { selectively_reveal_I(S); } I(sub_S) * Width() + low_word; //- MakePower2Minus1(sub_S) ensures (power2(32*(thirtytwos-1) + ones)-1) * Width() + low_word; //- Width ensures (power2(32*(thirtytwos-1) + ones)-1) * power2(32) + low_word; { lemma_mul_is_commutative(power2(32*(thirtytwos-1) + ones)-1, power2(32)); } power2(32) * (power2(32*(thirtytwos-1) + ones)-1) + low_word; { lemma_mul_is_distributive_sub(power2(32),power2(32*(thirtytwos-1) + ones),1); } power2(32) * (power2(32*(thirtytwos-1) + ones)) - power2(32) * 1 + low_word; { lemma_exponentiation(32, 32*(thirtytwos-1) + ones); } power2(32+32*(thirtytwos-1) + ones) - power2(32) * 1 + low_word; { lemma_mul_is_distributive_add(32,1,thirtytwos-1); } power2(32*thirtytwos + ones) - power2(32) * 1 + low_word; //- WordConstructOneBits ensures power2(32*thirtytwos + ones) - power2(32) * 1 + power2(32) - 1; power2(32*thirtytwos + ones) - power2(32) + power2(32) - 1; power2(32*thirtytwos + ones) - 1; } } } static lemma lemma_bit_boundaries(A:BigNat, ac:nat, v:nat) requires WellformedBigNat(A); requires I(A) < power2(v); requires BitCount(A,ac); ensures ac <= v; { if (v { power2(ac-1) <= I(A); { lemma_power2_increases(v,ac-1); } power2(v) <= I(A); false; } } assert ac<=v; } static lemma lemma_modesty_bit_value_equivalence(A:BigNat,ac:nat) requires WellformedBigNat(A); requires BitCount(A,ac); ensures ModestBigNatBits(A,ac) <==> ModestBigNatValue(A); { if (ModestBigNatBits(A,ac)) { calc ==> { //- ModestBigNatBits ensures ac <= power2(31); { lemma_power2_increases(ac, power2(31)); } power2(ac) <= power2(power2(31)); //- BitCount(A,ac) ensures I(A) < power2(ac); I(A) < power2(power2(31)); I(A) < KindaBigNat(); ModestBigNatValue(A); } } assert ModestBigNatBits(A,ac) ==> ModestBigNatValue(A); if (ModestBigNatValue(A)) { calc ==> { //- ModestBigNatValue(A) ensures I(A) < KindaBigNat(); I(A) < power2(power2(31)); { lemma_bit_boundaries(A, ac, power2(31)); } ac <= power2(31); ModestBigNatBits(A,ac); } } assert ModestBigNatValue(A) ==> ModestBigNatBits(A,ac); } static lemma lemma_modesty_word_value_equivalence(A:BigNat) requires WellformedBigNat(A); ensures ModestBigNatWords(A) <==> ModestBigNatValue(A); { var kinda_bignum:BigNat := MakePower2Minus1(power2(26)-1,32); calc { I(kinda_bignum); power2(32*(power2(26)-1) + 32)-1; power2(32*(power2(26)-1) + 32 * 1)-1; { lemma_mul_is_distributive_add(32,power2(26)-1,1); } power2(32 * power2(26))-1; { lemma_power2_5_is_32(); } power2(power2(5) * power2(26))-1; { lemma_exponentiation(5,26); } power2(power2(5+26))-1; KindaBigNat()-1; } if (ModestBigNatWords(A)) { if (|A.words| < |kinda_bignum.words|) { lemma_cmp_inequal_length(A,kinda_bignum); assert I(A) <= I(kinda_bignum); } else { lemma_le_equal_length(A,kinda_bignum); assert I(A) <= I(kinda_bignum); } assert I(A) < KindaBigNat(); assert ModestBigNatValue(A); } assert ModestBigNatWords(A) ==> ModestBigNatValue(A); if (ModestBigNatValue(A)) { assert I(A) < KindaBigNat(); assert I(A) <= I(kinda_bignum); if (|A.words| > |kinda_bignum.words|) { lemma_cmp_inequal_length(kinda_bignum, A); assert I(kinda_bignum) < I(A); assert false; } assert |A.words| <= power2(26); assert ModestBigNatWords(A); } assert ModestBigNatValue(A) ==> ModestBigNatWords(A); } static lemma lemma_zero_bits(A:BigNat, ac:nat) requires WellformedBigNat(A); requires BitCount(A,ac); ensures zero(A) <==> (ac==0); { assert ZeroBitRepresentation(A,ac); } static function method {:opaque} MakeSmallLiteralBigNat_def(x:nat) : BigNat requires x < Width(); ensures WellformedBigNat(MakeSmallLiteralBigNat_def(x)); { if (x==0) then BigNat_ctor([]) else BigNat_ctor([x]) } static lemma lemma_MakeSmallLiteralBigNat(x:nat) requires x < Width(); ensures I(MakeSmallLiteralBigNat_def(x)) == x; { reveal_MakeSmallLiteralBigNat_def(); var R:BigNat := MakeSmallLiteralBigNat_def(x); assert WellformedBigNat(R); if (x==0) { assert zero(R); assert I(R) == 0; } else { assert R.words == [x]; calc { I(R); { reveal_I(); } I(BigNat_ctor(R.words[1..])) * Width()+R.words[0]; { assert |R.words[1..]| == 0; } I(BigNat_ctor([])) * Width()+R.words[0]; { reveal_I(); lemma_mul_basics_forall(); } R.words[0]; x; } assert I(R) == x; } } static function method MakeSmallLiteralBigNat(x:nat) : BigNat requires x < Width(); ensures WellformedBigNat(MakeSmallLiteralBigNat(x)); ensures I(MakeSmallLiteralBigNat(x))==x; { lemma_MakeSmallLiteralBigNat(x); MakeSmallLiteralBigNat_def(x) } //-//////////////////////////////////////////////////////////////////////////// //- FrumpyBigNat: For when you need room to multiply two numbers. static function Frump() : nat { power2(power2(30)) } static function FrumpyBigNat(N:BigNat) : bool { WellformedBigNat(N) && I(N) < Frump() } static lemma lemma_frumpy_is_modest(X:BigNat) requires FrumpyBigNat(X); ensures ModestBigNatWords(X); { lemma_power2_strictly_increases(30,31); lemma_power2_strictly_increases(power2(30),power2(31)); lemma_modesty_word_value_equivalence(X); } static lemma lemma_frumpy_product_is_modest(X:BigNat,Y:BigNat,XY:BigNat) requires FrumpyBigNat(X); requires FrumpyBigNat(Y); requires WellformedBigNat(XY); requires I(X)*I(Y) == I(XY); ensures ModestBigNatWords(XY); { calc { I(XY); I(X) * I(Y); <= { lemma_mul_inequality(I(X), Frump(), I(Y)); } Frump() * I(Y); { lemma_mul_is_commutative_forall(); } I(Y) * Frump(); < { lemma_mul_strict_inequality(I(Y), Frump(), Frump()); } Frump() * Frump(); power2(power2(30)) * power2(power2(30)); { lemma_power2_adds(power2(30), power2(30)); } power2(power2(30) + power2(30)); power2(2 * power2(30)); { reveal_power2(); } power2(power2(31)); } lemma_modesty_word_value_equivalence(XY); } static lemma lemma_frumpy_squared_is_modest(X:BigNat,Xsquared:BigNat) requires FrumpyBigNat(X); requires WellformedBigNat(Xsquared); requires I(X)*I(X) == I(Xsquared); ensures ModestBigNatWords(Xsquared); { lemma_frumpy_product_is_modest(X,X,Xsquared); } static lemma lemma_power2_strictly_increases_converse_imply(e1: int, e2: int) ensures 0 <= e1 && 0 < e2 && power2(e1) < power2(e2) ==> e1 < e2; { if (0 <= e1 && 0 < e2 && power2(e1) < power2(e2)) { lemma_power2_strictly_increases_converse(e1,e2); } } method WordCountBits(a:nat) returns (s:nat) requires Word32(a); ensures s>0 ==> power2(s-1) <= a; ensures s==0 <==> (a==0); ensures a < power2(s); ensures s<=32; { s := 0; var ps := 1; ghost var gps := 1; lemma_power2_0_is_1(); while (s<32 && ps<=a) decreases Width()-gps; invariant gps == power2(s); invariant s>0 ==> power2(s-1) <= a; invariant a==0 ==> s==0; invariant 0<=s<=32; invariant s<=31 ==> ps==gps; invariant s==0 ==> a==0 || gps<=a; { s := s + 1; //- ps := 2*ps; // TODO: implement * gps := gps+gps; if (s<32) { ps := ps+ps; } reveal_power2(); } //- if (s>1) { assert s>1 ==> power2(s-1) <= a; assert a < Width(); assert a < power2(32); assert s>1 ==> power2(s-1) < power2(32); lemma_power2_strictly_increases_converse_imply(s-1,32); assert s-1 < 32; assert s <= 32; } assert s <= 32; } method BigNatCountBits(A:BigNat) returns (c:nat) requires WellformedBigNat(A); requires ModestBigNatWords(A); ensures Word32(c); ensures BitCount(A, c); ensures c == NatNumBits(I(A)); { if (zero(A)) { c := 0; lemma_power2_0_is_1(); } else { var last_word:nat := A.words[|A.words|-1]; var last_word_bits:nat := WordCountBits(last_word); calc ==> { //- ModestBigNatWords(A) ensures |A.words| <= power2(26); { lemma_power2_increases(26,32); } |A.words| <= power2(32); |A.words| <= Width(); |A.words|-1 < Width(); Word32(|A.words|-1); } lemma_2to32(); assert Word32(32); var l,h := Product32(32, |A.words|-1); if (h>0) { h := h; // HACK: turn ghost if into real if until dafnycc can handle ghost if in real methods calc { Width(); <= { lemma_mul_properties(); } h * Width(); <= l+h * Width(); //- Product32 ensures <= 32 * (|A.words|-1); <= { lemma_mul_is_distributive_add(32,|A.words|,1); } 32 * |A.words|- 32 * 1; < { lemma_mul_strictly_positive_forall(); } 32 * |A.words|; //- Conflicts with ModestBigNat(A); } calc ==> { |A.words| <= power2(26); { lemma_mul_left_inequality(32,|A.words|,power2(26)); } 32 * |A.words| <= 32 * power2(26); { lemma_mul32power226_is_power31(); } 32 * |A.words| <= power2(31); { lemma_power2_strictly_increases(31,32); } 32 * |A.words| < Width(); } assert false; } assert h==0; lemma_mul_annihilate(Width()); assert l == 32 * (|A.words|-1); c := l + last_word_bits; assert c > 0; assert zero(A) <==> c==0; ghost var thirtytwos:nat; ghost var ones:nat; ghost var lo_proxy:BigNat; //- Prove lower bound. Requires special case at 1, where we can't ask for a //- MakePower2Minus1, since that's 2^0-1 == 0, which has no defined 'ones' part. //- So special-casing here keeps the main case cleaner. if (|A.words|==1 && last_word_bits==1) { last_word_bits := last_word_bits; // HACK: turn ghost if into real if until dafnycc can handle ghost if in real methods calc ==> { c == 32 * (|A.words|-1) + last_word_bits; { lemma_mul_annihilate(32); } c == 1; } lemma_power2_0_is_1(); lemma_power2_1_is_2(); assert power2(c-1) == power2(0) == 1 <= last_word < 2 == power2(c); assert last_word == 1; assert A.words[0] == last_word; assert A.words == [last_word]; calc { I(A); I(BigNat_ctor([1])); { selectively_reveal_I(BigNat_ctor([1])); } I(BigNat_ctor(A.words[1..])) * Width()+1; { selectively_reveal_I(BigNat_ctor([])); } { reveal_I(); } 0 * Width()+1; { lemma_mul_basics_forall(); } 1; } assert I(A) == 1; assert I(A) < power2(c); } else if (last_word_bits==1) { last_word_bits := last_word_bits; // HACK: turn ghost if into real if until dafnycc can handle ghost if in real methods assert 2<=|A.words|; //- ghost var thirtytwos:nat := |A.words|-2; //- ghost var ones:nat := 32; //- ghost var lo_proxy:BigNat := MakePower2Minus1(thirtytwos,ones); thirtytwos := |A.words|-2; ones := 32; lo_proxy := MakePower2Minus1(thirtytwos,ones); calc { 32*thirtytwos+ones; 32*thirtytwos+32 * 1; { lemma_mul_is_distributive_add(32,thirtytwos,1); } 32 * (thirtytwos+1); 32 * (|A.words|-1); c - 1; } assert power2(c-1)-1 == I(lo_proxy); lemma_cmp_inequal_length(lo_proxy, A); assert power2(c-1) <= I(A); } else { //- ghost var thirtytwos:nat := |A.words|-1; //- ghost var ones:nat := last_word_bits-1; //- ghost var lo_proxy:BigNat := MakePower2Minus1(thirtytwos,ones); thirtytwos := |A.words|-1; ones := last_word_bits-1; lo_proxy := MakePower2Minus1(thirtytwos,ones); assert c == 32*thirtytwos+ones+1; assert power2(c-1)-1 == I(lo_proxy); lemma_lt_equal_length(lo_proxy, A); assert power2(c-1) <= I(A); } ghost var hi_proxy:BigNat := MakePower2Minus1(|A.words|-1,last_word_bits); calc ==> { true; //- MakePower2Minus1 ensures I(hi_proxy) == power2(32*(|A.words|-1) + last_word_bits)-1; I(hi_proxy) == power2(c)-1; { assert |A.words| == |A.words|-1 + 1 == |hi_proxy.words|; assert A.words[|A.words|-1] < power2(c) <==> A.words[|A.words|-1] <= power2(c)-1 <==> A.words[|A.words|-1] <= hi_proxy.words[|hi_proxy.words|-1]; /* [ckh] current workaround for non-ghost calc doesn't handle nested calcs calc { |A.words|; |A.words|-1 + 1; |hi_proxy.words|; } calc ==> { A.words[|A.words|-1] < power2(c); A.words[|A.words|-1] <= power2(c)-1; A.words[|A.words|-1] <= hi_proxy.words[|hi_proxy.words|-1]; } */ lemma_le_equal_length(A, hi_proxy); } I(A) <= power2(c)-1; I(A) < power2(c); } calc ==> { c == 32*(|A.words|-1) + last_word_bits; c <= 32*(|A.words|-1) + 32; c <= 32*(|A.words|-1) + 32 * 1; { lemma_mul_is_distributive_add(32,|A.words|-1,1); } c <= 32 * |A.words|; //- ModestBigNatWords(A) ensures |A.words|<=power2(26) { lemma_mul_left_inequality(32,|A.words|,power2(26)); } c <= 32 * power2(26); { lemma_mul32power226_is_power31(); } c <= power2(31); { lemma_power2_strictly_increases(31,32); } c < Width(); Word32(c); } } lemma_Power2BoundIsNatNumBits(c, I(A)); } static lemma lemma_unroll_power2(exp:nat) ensures power2(0) == 1; ensures power2(exp + 1) == 2 * power2(exp); { reveal_power2(); } static method MakePower2Word32(exp:nat) returns (w:nat) requires exp<32; ensures w == power2(exp); ensures Word32(w); { lemma_2to32(); reveal_power2(); var n:int := 0; w := 1; //- lemma_unroll_power2(0); while (n < exp) invariant 0 <= n <= exp; invariant w == power2(n); invariant Word32(w); { //- lemma_unroll_power2(n); //- assert Word32(w + w); w := w + w; n := n + 1; lemma_power2_strictly_increases(n, 32); } /* w := [ 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608, 16777216, 33554432, 67108864, 134217728, 268435456, 536870912, 1073741824, 2147483648 ][exp]; lemma_2to32(); reveal_power2(); assert 1==power2(0); assert 2==power2(1); assert 4==power2(2); assert 8==power2(3); assert 16==power2(4); assert 32==power2(5); assert 64==power2(6); assert 128==power2(7); assert 256==power2(8); assert 512==power2(9); assert 1024==power2(10); assert 2048==power2(11); assert 4096==power2(12); assert 8192==power2(13); assert 16384==power2(14); assert 32768==power2(15); assert 65536==power2(16); assert 131072==power2(17); assert 262144==power2(18); assert 524288==power2(19); assert 1048576==power2(20); assert 2097152==power2(21); assert 4194304==power2(22); assert 8388608==power2(23); assert 16777216==power2(24); assert 33554432==power2(25); assert 67108864==power2(26); assert 134217728==power2(27); assert 268435456==power2(28); assert 536870912==power2(29); assert 1073741824==power2(30); assert 2147483648==power2(31); */ } static method IsModestBigNat (A:BigNat) returns (modest:bool) requires WellformedBigNat(A); ensures modest == ModestBigNatValue(A); { modest := (|A.words| <= 0x4000000); lemma_2to32(); reveal_power2(); assert 0x4000000 == power2(26); assert modest == ModestBigNatWords(A); lemma_modesty_word_value_equivalence(A); } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/BigNum/BigNatBitwise.i.dfy ================================================ include "BigNatCore.i.dfy" include "BigNatBitCount.i.dfy" include "BigNatCompare.i.dfy" include "BigNumBEAdaptor.i.dfy" include "../Math/BitwiseOperations.i.dfy" include "../Util/word_bits.i.dfy" include "../Util/arrays_2.i.dfy" static lemma lemma_SelectBitWord(b:nat, M:seq) requires b<|M|*32; requires IsWordSeq(M); ensures 0 <= b/32 < |M|; ensures SelectBit(b, BEWordSeqToInt_premium(M)) == SelectBit(b%32, M[|M|-1-b/32]); { ghost var m := BEWordSeqToInt_premium(M); ghost var br := (b/32)*32; lemma_div_pos_is_pos(m, power2(br)); calc { SelectBit(b, m); { lemma_SelectBit_div(b, m, br); } SelectBit(b-br, m / power2(br)); SelectBit(b%32, m / power2(br)); { lemma_SelectBit_mod(b%32, m/power2(br), 32); lemma_mod_pos_bound(m / power2(br), power2(32)); } SelectBit(b%32, (m / power2(br)) % power2(32)); { lemma_BEWordSeq_extract(M, b/32); } SelectBit(b%32, M[|M|-1-b/32]); } } static method BEBitwiseMask(X:seq, c:nat) returns (M:seq) requires IsWordSeq(X); //- requires |X| < power2(32); //- if we want to avoid runtime overflow requires Word32(c); ensures IsWordSeq(M); ensures PureBitwiseAnd(BEWordSeqToInt_premium(X), power2(c)-1) == BEWordSeqToInt(M); { ghost var mask_index := (|X|*32-(1+c))/32; var use_mask_index; var nonnegative_mask_index; if (|X|*32 < 1+c) { use_mask_index := false; nonnegative_mask_index := 0; } else { use_mask_index := true; nonnegative_mask_index := (|X|*32-(1+c))/32; } assert use_mask_index ==> nonnegative_mask_index == mask_index; assert 0<=nonnegative_mask_index; M := []; var i:=0; lemma_power2_increases(c%32,32); ghost var mask := power2(c)-1; ghost var x := BEWordSeqToInt_premium(X); assert IsWordSeq(RepeatDigit_premium(0,|X|-|M|)); while (i<|X|) invariant |M|==i; invariant i<=|X|; //- invariant forall i::0<=i<|M| //- ==> M[i] == if i==mask_index then Asm_BitwiseAnd(X[i], power2(c%32)-1) else X[i]; invariant IsWordSeq(M); invariant IsWordSeq(M + RepeatDigit(0,|X|-|M|)); invariant forall b:: ((|X|-|M|)*32 <= b < |X|*32) ==> (SelectBit(b, BEWordSeqToInt_premium(M + RepeatDigit(0,|X|-|M|))) == (if b=c; //- ...and we're off the top of the mask. calc { SelectBit(b, pm'); { lemma_SelectBitWord(b, PM'); } SelectBit(b%32, PM'[wordi]); SelectBit(b%32, 0); (div(0,power2(b%32))) % 2 == 1; { lemma_div_basics(power2(b%32)); } 0 == 1; false; if (b= (|X|-|M'|)*32; calc { SelectBit(b, pm'); { lemma_SelectBitWord(b, PM'); } SelectBit(b%32, PM'[wordi]); SelectBit(b%32, nextword); SelectBit(b%32, X[wordi]) && SelectBit(b%32, word_mask); { lemma_SelectBitWord(b, X); } SelectBit(b, x) && SelectBit(b%32, word_mask); { lemma_mask_structure(c%32, b%32); } SelectBit(b, x) && (b%32 (SelectBit(b, BEWordSeqToInt_premium(M' + RepeatDigit(0,|X|-|M'|))) == (if b=|X|*32) { lemma_BEWordSeqToInt_bound(M); lemma_power2_increases(|X|*32, b); lemma_SelectBit_overflow(b,m); lemma_BEWordSeqToInt_bound(X); lemma_SelectBit_overflow(b,x); } else if (b (a < b); //- //-method Eq32(a:nat, b:nat) returns (r:bool) //- requires Word32(a); //- requires Word32(b); //- ensures r <==> (a==b); //- //-/////////////////////////////////////////// static lemma lemma_bignum_lower_bound(A:BigNat) decreases |A.words|; requires WellformedBigNat(A); requires nonzero(A); ensures 0 <= 32 * (|A.words|-1); ensures power2(32 * (|A.words|-1)) <= I(A); { var alen:int := |A.words|; if (alen==1) { lemma_mul_nonnegative(32,(alen-1)); calc { power2(32 * (|A.words|-1)); power2(32 * 0); { lemma_mul_annihilate(32); } power2(0); { lemma_power2_0_is_1(); } 1; } calc { 1; <= { reveal_I(); } I(A); } } else { lemma_mul_nonnegative(32,(alen-1)); assert 0<=32 *(alen-1); lemma_mul_nonnegative(32,(alen-2)); assert 0<=32 *(alen-2); assert 0 < Width(); assert Width() == power2(32); assert 0 <= lo(A); calc ==> { true; { lemma_bignum_lower_bound(hi(A)); } power2(32*(alen-2)) <= I(hi(A)); { lemma_mul_left_inequality(Width(), power2(32*(alen-2)), I(hi(A))); } Width() * power2(32*(alen-2)) <= Width() * I(hi(A)); power2(32) * power2(32*(alen-2)) <= Width() * I(hi(A)); { lemma_power2_adds(32, 32*(alen-2)); } power2(32 + 32*(alen-2)) <= Width() * I(hi(A)); power2(32*1 + 32*(alen-2)) <= Width() * I(hi(A)); { lemma_mul_is_distributive_add(32, 1, alen-2); } power2(32 * (1 + (alen-2))) <= Width() * I(hi(A)); //- additive math power2(32 * (alen-1)) <= Width() * I(hi(A)); //- add 0<=lo(A) to each sides power2(32*(alen-1)) + 0 <= Width() * I(hi(A)) + lo(A); { lemma_hilo(A); lemma_mul_is_commutative(Width(), I(hi(A))); } power2(32*(alen-1)) <= I(A); power2(32 * (|A.words|-1)) <= I(A); } } } static lemma lemma_bignum_upper_bound(A:BigNat) decreases |A.words|; requires WellformedBigNat(A); ensures 0 <= 32 * |A.words|; ensures I(A) <= power2(32 * |A.words|)-1; { var alen:int := |A.words|; lemma_mul_nonnegative(32,alen); if (alen==0) { calc ==> { true; { reveal_I(); } I(A) == 0; { lemma_power2_0_is_1(); } I(A) < power2(0); { lemma_mul_annihilate(32); } I(A) < power2(32*0); I(A) < power2(32*alen); } } else { lemma_mul_nonnegative(32,alen-1); calc ==> { true; { lemma_bignum_upper_bound(hi(A)); } I(hi(A)) <= power2(32*(alen-1)) - 1; { lemma_mul_left_inequality(Width(), I(hi(A)), power2(32*(alen-1))-1); } Width() * I(hi(A)) <= Width() * (power2(32*(alen-1)) - 1); { lemma_mul_is_distributive_sub(Width(), power2(32*(alen-1)), 1); } Width() * I(hi(A)) <= Width() * power2(32*(alen-1)) - Width() * 1; Width() * I(hi(A)) <= Width() * power2(32*(alen-1)) - Width(); Width() * I(hi(A)) <= power2(32) * power2(32*(alen-1)) - Width(); { lemma_exponentiation(32, 32*(alen-1)); } Width() * I(hi(A)) <= power2(32 + 32*(alen-1)) - Width(); Width() * I(hi(A)) <= power2(32*1 + 32*(alen-1)) - Width(); { lemma_mul_is_distributive_add(32, 1, alen-1); } Width() * I(hi(A)) <= power2(32*alen) - Width(); //- add lo(A) <= power2(32)-1; Width() * I(hi(A)) + lo(A) <= power2(32*alen) - Width() + power2(32) - 1; { lemma_hilo(A); lemma_mul_is_commutative(Width(), I(hi(A))); } I(A) <= power2(32*alen) - 1; } } } static lemma lemma_word_bound(A:BigNat) requires WellformedBigNat(A); requires !zero(A); ensures 0<=32 * |A.words|; ensures I(A) < power2(32*|A.words|); ensures 0<=32*(|A.words|-1); ensures power2(32*(|A.words|-1)) <= I(A); { lemma_bignum_lower_bound(A); lemma_bignum_upper_bound(A); } static lemma{:dafnycc_conservative_seq_triggers} behead(A:BigNat,i:int) returns (t:int, m:int, l:int) requires WellformedBigNat(A); requires |A.words| > 0; requires 0<=i<|A.words|; ensures 32*i >= 0; ensures 32*(i+1) >= 0; ensures I(A)==power2(32*(i+1)) * t + power2(32*i) * m + l; ensures WellformedBigNat(BigNat_ctor(A.words[i+1..])); ensures t == I(BigNat_ctor(A.words[i+1..])); ensures m == A.words[i]; ensures 0 <= l < power2(32*i); { calc ==> { 0<=i; { lemma_mul_left_inequality(32,0,i); } 32*0 <= 32*i; { lemma_mul_annihilate(32); } 0 <= 32*i; } var ts:seq := A.words[i+1..]; var ms:seq := A.words[i..i+1]; var ls:seq := A.words[0..i]; var T:BigNat := BigNat_ctor(ts); assert WellformedBigNat(T); t := V(ts); lemma_V_I(T); assert V(ts) == I(T); m := V(ms); lemma_V_singleton(ms); assert m == A.words[i]; l := V(ls); lemma_V_lower_bound(ls); assert 0 <= l; lemma_V_upper_bound(ls); assert l < power2(32*i); lemma_V_power(ls,ms); assert V(ls+ms) == power2(32*i) *V(ms)+V(ls); lemma_V_power(ls+ms,ts); assert V((ls+ms)+ts) == power2(32*(i+1))*V(ts) +V(ls+ms); assert V((ls+ms)+ts) == power2(32*(i+1))*V(ts) + power2(32*i) * V(ms) + V(ls); assert V((ls+ms)+ts) == power2(32*(i+1))*t+power2(32*i) * m +l; assert ls+(ms+ts) == A.words; assert (ls+ms)+ts == A.words; lemma_V_I(A); assert I(A) == V(A.words); assert I(A) == V((ls+ms)+ts); assert I(A) == power2(32*(i+1))*t+power2(32*i)*m+l; } datatype BNCmp = BNCmpLt | BNCmpEq | BNCmpGt; static lemma BigNatLtEqualLengthOne_(A:BigNat, B:BigNat, i:int) decreases i; requires |A.words|==|B.words|; requires 0 <= i < |A.words|; requires WellformedBigNat(A); requires WellformedBigNat(B); requires forall k:int :: i < k < |A.words| ==> A.words[k]==B.words[k]; requires A.words[i] < B.words[i]; ensures I(A) < I(B); { ghost var At,Am,Al := behead(A,i); ghost var Bt,Bm,Bl := behead(B,i); var Atop:seq := A.words[i+1..]; var Btop:seq := B.words[i+1..]; assert Atop == Btop; calc { At; I(BigNat_ctor(Atop)); I(BigNat_ctor(Btop)); Bt; } ghost var t:int := power2(32*(i+1)); ghost var m:int := power2(32*i); assert I(B)==power2(32*(i+1)) * Bt + power2(32*i) * Bm + Bl; assert I(B)==t * Bt + m * Bm + Bl; calc ==> { //- behead I(A) == t * At + m * Am + Al; //- behead { Al <= k; } I(A) < t * At + m * Am + m; { lemma_mul_is_distributive_add(m,Am,1); } I(A) < t * At + m * (Am+1); { assert Am+1 <= Bm; lemma_mul_left_inequality(m,Am+1,Bm); } I(A) < t * Bt + m * Bm; //- behead { 0 <= Bl; } I(A) < t * Bt + m * Bm + Bl; //- behead I(A) < I(B); } } static lemma lemma_lt_equal_length(A:BigNat, B:BigNat) requires WellformedBigNat(A); requires WellformedBigNat(B); requires |A.words|==|B.words|; requires !zero(A); requires A.words[|A.words|-1] < B.words[|A.words|-1]; ensures I(A) < I(B); { BigNatLtEqualLengthOne_(A, B, |A.words|-1); } static lemma BigNatLeEqualLengthOne_(A:BigNat, B:BigNat, i:int) decreases i; requires |A.words|==|B.words|; requires 0 <= i < |A.words|; requires WellformedBigNat(A); requires WellformedBigNat(B); requires forall k:int :: i < k < |A.words| ==> A.words[k]==B.words[k]; requires forall j:int :: 0 <= j <= i ==> A.words[j]<=B.words[j]; ensures I(A) <= I(B); { if (A.words[i] < B.words[i]) { BigNatLtEqualLengthOne_(A, B, i); //- We've established inequality } else if (A.words[i] > B.words[i]) { assert false; } else if (i > 0) { //- continue in the loop towards equality. BigNatLeEqualLengthOne_(A, B, i - 1); } else { lemma_BigNatEqEqualLength_(A,B); } } static lemma lemma_BigNatEqEqualLength_(A:BigNat, B:BigNat) requires |A.words|==|B.words|; requires WellformedBigNat(A); requires WellformedBigNat(B); requires forall k:int :: 0 <= k < |A.words| ==> A.words[k]==B.words[k]; ensures I(A) == I(B); { calc ==> { A.words == B.words; A == B; I(A) == I(B); } } static method BigNatCmpEqualLength_(A:BigNat, B:BigNat, i:int) returns (c:BNCmp) requires |A.words|==|B.words|; requires 0 <= i < |A.words|; requires WellformedBigNat(A); requires WellformedBigNat(B); requires forall k:int :: i < k < |A.words| ==> A.words[k]==B.words[k]; ensures (c==BNCmpLt) <==> (I(A) < I(B)); ensures (c==BNCmpEq) <==> (I(A) == I(B)); ensures (c==BNCmpGt) <==> (I(A) > I(B)); { var n := i + 1; while (n > 0) invariant 0 <= n <= i + 1; invariant forall k:int :: n <= k < |A.words| ==> A.words[k]==B.words[k]; { n := n - 1; if (A.words[n] < B.words[n]) { BigNatLtEqualLengthOne_(A,B,n); c := BNCmpLt; return; } else if (A.words[n] > B.words[n]) { BigNatLtEqualLengthOne_(B,A,n); c := BNCmpGt; return; } } c := BNCmpEq; lemma_BigNatEqEqualLength_(A,B); } static lemma lemma_cmp_inequal_length(A:BigNat, B:BigNat) requires WellformedBigNat(A); requires WellformedBigNat(B); requires |A.words| < |B.words|; ensures I(A) < I(B); { lemma_bignum_upper_bound(A); assert I(A) < power2(32 * (|A.words|)); lemma_bignum_lower_bound(B); assert power2(32 * (|B.words|-1)) <= I(B); assert |A.words| <= |B.words|-1; lemma_mul_left_inequality(32, |A.words|, |B.words|-1); assert 32*|A.words| <= 32 * (|B.words|-1); lemma_power2_increases(32*|A.words|, 32 * (|B.words|-1)); assert power2(32 * (|A.words|)) <= power2(32 * (|B.words|-1)); } static lemma lemma_hi_decreases(A:BigNat) requires WellformedBigNat(A); ensures zero(A) || I(hi(A)) zero(hi(A)); { if (zero(A)) { assert zero(hi(A)); } else { assert |hi(A).words| < |A.words|; lemma_cmp_inequal_length(hi(A), A); } } static method BigNatCmp(A:BigNat, B:BigNat) returns (c:BNCmp) decreases |A.words|; requires WellformedBigNat(A); requires WellformedBigNat(B); ensures (c==BNCmpLt) <==> (I(A) < I(B)); ensures (c==BNCmpEq) <==> (I(A) == I(B)); ensures (c==BNCmpGt) <==> (I(A) > I(B)); { if (zero(A)) { if (zero(B)) { c := BNCmpEq; } else { c := BNCmpLt; } } else if (zero(B)) { c := BNCmpGt; } else if (|A.words| < |B.words|) { lemma_cmp_inequal_length(A,B); c := BNCmpLt; } else if (|A.words| > |B.words|) { lemma_cmp_inequal_length(B,A); c := BNCmpGt; } else { c := BigNatCmpEqualLength_(A,B,|A.words|-1); } } static method BigNatLt(A:BigNat, B:BigNat) returns (r:bool) requires WellformedBigNat(A); requires WellformedBigNat(B); ensures r <==> I(A) I(A)<=I(B); { var c := BigNatCmp(A,B); r := (c.BNCmpLt?) || (c.BNCmpEq?); } static method BigNatEq(A:BigNat, B:BigNat) returns (r:bool) requires WellformedBigNat(A); requires WellformedBigNat(B); ensures r <==> I(A)==I(B); { var c := BigNatCmp(A,B); r := (c.BNCmpEq?); } static method BigNatGe(A:BigNat, B:BigNat) returns (r:bool) requires WellformedBigNat(A); requires WellformedBigNat(B); ensures r <==> I(A)>=I(B); { var c := BigNatCmp(A,B); r := (c.BNCmpGt?) || (c.BNCmpEq?); } static method BigNatGt(A:BigNat, B:BigNat) returns (r:bool) requires WellformedBigNat(A); requires WellformedBigNat(B); ensures r <==> I(A)>I(B); { var c := BigNatCmp(A,B); r := (c.BNCmpGt?); } static function method TestEqSmallLiteralBigNat_def(x:nat, X: BigNat) : bool requires x < Width(); requires WellformedBigNat(X); { if (zero(X)) then x==0 else if |X.words|>1 then false else X.words[0]==x } static lemma lemma_TestEqSmallLiteralBigNat(x:nat, X: BigNat) requires x < Width(); requires WellformedBigNat(X); ensures x==I(X) <==> TestEqSmallLiteralBigNat_def(x,X); { if (zero(X)) { } else if (|X.words|>1) { calc ==> { 1 <= |X.words|-1; { lemma_mul_inequality_forall(); } 1 * 32 <= (|X.words|-1) * 32; { lemma_mul_is_mul_boogie(1,32); } 32 <= (|X.words|-1) * 32; { lemma_mul_is_commutative_forall(); } 32 <= 32 * (|X.words|-1); { lemma_power2_increases(32, 32 * (|X.words|-1)); } power2(32) <= power2(32 * (|X.words|-1)); { lemma_bignum_lower_bound(X); } Width() <= power2(32 * (|X.words|-1)) <= I(X); } assert x < Width(); } else { assert |X.words|==1; calc { I(X); { reveal_I(); } I(BigNat_ctor(X.words[1..])) * Width()+X.words[0]; { assert X.words[1..] == []; } I(BigNat_ctor([])) * Width()+X.words[0]; { reveal_I(); } 0 * Width()+X.words[0]; { lemma_mul_basics_forall(); } X.words[0]; } } } static function method TestEqSmallLiteralBigNat(x:nat, X: BigNat) : bool requires x < Width(); requires WellformedBigNat(X); ensures x==I(X) <==> TestEqSmallLiteralBigNat(x,X); { lemma_TestEqSmallLiteralBigNat(x, X); TestEqSmallLiteralBigNat_def(x, X) } static lemma lemma_le_equal_length(A:BigNat, B:BigNat) requires WellformedBigNat(A); requires WellformedBigNat(B); requires |A.words|==|B.words|; requires !zero(A); requires forall i:nat :: i < |A.words| ==> A.words[i] <= B.words[i]; ensures I(A) <= I(B); { BigNatLeEqualLengthOne_(A, B, |A.words|-1); } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/BigNum/BigNatCore.i.dfy ================================================ include "../Math/mul.i.dfy" include "Word32.i.dfy" datatype BigNat = BigNat_ctor( words : seq); static function WellformedBigNat(b:BigNat) : bool { (forall i :: 0 <= i < |b.words| ==> b.words[i]>=0 && Word32(b.words[i])) && (|b.words|==0 || b.words[|b.words|-1] > 0) } static function {:opaque} I(b:BigNat) : nat decreases |b.words|; requires WellformedBigNat(b); { lemma_mul_nonnegative_forall(); if (|b.words|==0) then 0 else I(BigNat_ctor(b.words[1..])) * Width()+b.words[0] } static function method lo(a:BigNat) : nat requires WellformedBigNat(a); ensures Word32(lo(a)); { if (|a.words|==0) then 0 else a.words[0] } static function method hi(a:BigNat) : BigNat requires WellformedBigNat(a); ensures WellformedBigNat(hi(a)); { if (|a.words|==0) then BigNat_ctor([]) else BigNat_ctor(a.words[1..]) } static lemma lemma_hilo(A:BigNat) requires WellformedBigNat(A); ensures I(A)==I(hi(A)) * Width() + lo(A); { reveal_I(); if (|A.words|==0) { calc { I(A); 0; { lemma_mul_properties(); } 0 * Width(); I(hi(A)) * Width(); } } } static lemma lemma_I_length_implies_value(a:BigNat) decreases |a.words|; requires WellformedBigNat(a); ensures |a.words|==0 ==> I(a)==0; ensures |a.words|>0 ==> I(a)>0; { if (|a.words|==0) { reveal_I(); assert I(a)==0; } else if (|a.words|==1) { reveal_I(); lemma_mul_basics_forall(); assert I(a)>0; } else { var sub_a:BigNat := hi(a); lemma_I_length_implies_value(sub_a); assert |sub_a.words| > 0; assert I(sub_a) > 0; calc { I(a); { reveal_I(); } I(BigNat_ctor(a.words[1..])) * Width() + a.words[0]; I(sub_a) * Width() + a.words[0]; > { assert I(sub_a) > 0; assert Width() > 0; lemma_mul_strictly_positive_forall(); assert I(sub_a) * Width() > 0; } 0; } assert I(a)>0; } } static lemma lemma_I_value_implies_length(a:BigNat) requires WellformedBigNat(a); ensures I(a)==0 ==> |a.words|==0; { if (I(a)==0) { if (|a.words|>0) { lemma_I_length_implies_value(a); assert I(a)>0; assert false; } assert |a.words|==0; } else { if (|a.words|==0) { lemma_I_length_implies_value(a); assert I(a)==0; assert false; } assert |a.words|>0; } } static function method nonzero(a:BigNat) : bool requires WellformedBigNat(a); ensures nonzero(a) <==> I(a)!=0; { lemma_I_length_implies_value(a); lemma_I_value_implies_length(a); |a.words|>0 } static function method zero(a:BigNat) : bool requires WellformedBigNat(a); ensures zero(a) <==> I(a)==0; { lemma_I_length_implies_value(a); lemma_I_value_implies_length(a); |a.words|==0 } static function method BigNatZero() : BigNat ensures WellformedBigNat(BigNatZero()); ensures zero(BigNatZero()); ensures zero(BigNatZero()) <==> I(BigNatZero())==0; ensures I(BigNatZero()) == 0; { reveal_I(); BigNat_ctor([]) } static lemma selectively_reveal_I(A:BigNat) requires WellformedBigNat(A); ensures I(A) == if (|A.words|==0) then 0 else I(BigNat_ctor(A.words[1..])) * Width()+A.words[0]; { reveal_I(); } static lemma lemma_I_is_nonnegative(A:BigNat) requires WellformedBigNat(A); ensures 0 <= I(A); { if (|A.words|==0) { } else { calc { I(A); { selectively_reveal_I(A); } I(BigNat_ctor(A.words[1..])) * Width()+A.words[0]; >= { lemma_mul_nonnegative_forall(); } 0+A.words[0]; >= 0; } } } static lemma lemma_I_is_nonnegative_forall() ensures forall A:BigNat :: WellformedBigNat(A) ==> 0 <= I(A); { forall (A:BigNat | WellformedBigNat(A)) ensures 0 <= I(A); { lemma_I_is_nonnegative(A); } } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/BigNum/BigNatDiv.i.dfy ================================================ include "BigNatSub.i.dfy" include "BigNatMul.i.dfy" include "BigNatBitCount.i.dfy" static method fill_sequence(value:nat, copies:nat) returns (vs:seq) decreases copies; ensures forall k :: 0 <= k < |vs| ==> vs[k] == value; ensures |vs|==copies; { vs := []; var i := 0; while (i < copies) invariant forall k :: 0 <= k < |vs| ==> vs[k] == value; invariant |vs| == i; invariant 0 <= i <= copies; { vs := [value] + vs; i := i + 1; } } static lemma lemma_MakePower2(S:BigNat) decreases |S.words|; requires WellformedBigNat(S); requires !zero(S); requires forall i:int :: 0<=i<|S.words|-1 ==> S.words[i]==0; ensures 0 <= 32 * (|S.words|-1); ensures I(S) == power2(32 * (|S.words|-1)) * S.words[|S.words|-1]; { lemma_mul_nonnegative(32,|S.words|-1); if (|S.words|==1) { calc { I(S); { selectively_reveal_I(S); } I(BigNat_ctor(S.words[1..])) * Width() +S.words[0]; { assert S.words[1..] == []; selectively_reveal_I(BigNat_ctor([])); } 0*Width()+S.words[0]; { lemma_mul_basics_forall(); } S.words[0]; 1 * S.words[|S.words|-1]; { lemma_mul_annihilate(32); lemma_power2_0_is_1(); } power2(32 * 0) * S.words[|S.words|-1]; power2(32 * (|S.words|-1)) * S.words[|S.words|-1]; } } else { var top:nat := S.words[|S.words|-1]; var sub_S := BigNat_ctor(S.words[1..]); lemma_mul_is_mul_boogie(32, |sub_S.words| - 1); //- dafnycc calc { I(S); { selectively_reveal_I(S); } I(sub_S) * Width()+S.words[0]; I(sub_S) * Width(); { lemma_MakePower2(sub_S); assert sub_S.words[|sub_S.words|-1] == top; } power2(32 * (|sub_S.words|-1)) * top * Width(); power2(32 * (|sub_S.words|-1)) * top * power2(32); { lemma_mul_is_commutative(top, power2(32 * (|sub_S.words|-1))); } top * power2(32 * (|sub_S.words|-1)) * power2(32); { lemma_mul_is_associative(top, power2(32 * (|sub_S.words|-1)), power2(32)); } top * (power2(32 * (|sub_S.words|-1)) * power2(32)); { lemma_exponentiation(32 * (|sub_S.words|-1), 32); } top * power2(32 * (|sub_S.words|-1)+32); top * power2(32 * (|sub_S.words|-1)+32 * 1); { lemma_mul_is_distributive_add(32, |sub_S.words|-1, 1); } top * power2(32 * (|sub_S.words|-1+1)); //- definition sub_S top * power2(32 * (|S.words|-1)); { lemma_mul_is_commutative(power2(32 * (|S.words|-1)), top); } power2(32 * (|S.words|-1)) * top; power2(32 * (|S.words|-1)) * S.words[|S.words|-1]; } } } method BNMakePower2(thirtytwos:nat,ones:nat) returns (S:BigNat) requires 0<=ones<32; ensures WellformedBigNat(S); ensures |S.words| == thirtytwos + 1; ensures 0 <= 32*thirtytwos; ensures I(S) == power2(32*thirtytwos+ones); ensures forall i::0<=i<|S.words|-1 ==> S.words[i]==0; ensures S.words[|S.words|-1] == power2(ones); { var vs:seq := fill_sequence(0,thirtytwos); var small_power_2 := MakePower2Word32(ones); S := BigNat_ctor(vs + [small_power_2]); assert WellformedBigNat(S); assert !zero(S); assert forall i:int :: 0<=i<|S.words|-1 ==> S.words[i]==0; lemma_MakePower2(S); calc { I(S); power2(32*(|S.words|-1)) * S.words[|S.words|-1]; power2(32*(|S.words|-1)) * power2(ones); { lemma_exponentiation(32*(|S.words|-1), ones); } power2(32*(|S.words|-1) + ones); power2(32*thirtytwos + ones); } } method MakePower2Simple(exp:nat) returns (S:BigNat) requires Word32(exp); ensures WellformedBigNat(S); ensures I(S) == power2(exp); { lemma_2to32(); var thirtytwos,ones := Divide32(exp, 32); assert thirtytwos*32+ones == exp; //- if (ones==0) //- { //- var new_thirtytwos := thirtytwos - 1; //- var new_ones := 32; //- calc { //- new_thirtytwos * 32+new_ones; //- (thirtytwos - 1) * 32+32; //- { lemma_mul_basics_forall(); } //- (thirtytwos - 1) * 32 + 32 * 1; //- { lemma_mul_is_commutative_forall(); } //- 32 * (thirtytwos - 1)+32*1; //- { lemma_mul_is_distributive_add_forall(); } //- 32*thirtytwos; //- 32*thirtytwos+ones; //- { lemma_mul_is_commutative_forall(); } //- thirtytwos*32+ones; //- exp; //- } //- thirtytwos := new_thirtytwos; //- ones := new_ones; //- assert thirtytwos*32+ones == exp; //- } S := BNMakePower2(thirtytwos,ones); calc { I(S); power2(32*thirtytwos+ones); { lemma_mul_is_commutative_forall(); } power2(thirtytwos*32+ones); power2(exp); } } static lemma lemma_BigNatWordShift_(A:BigNat, R:BigNat, w:nat) decreases w; requires WellformedBigNat(A); requires nonzero(A); requires WellformedBigNat(R); requires |R.words| == |A.words|+w; requires forall i :: 0<=i R.words[i] == 0; requires forall i :: 0<=i<|A.words| ==> A.words[i] == R.words[w+i]; ensures 0<=32 * w; ensures I(R) == I(A) * power2(32 * w); { lemma_mul_nonnegative(32,w); if (w==0) { calc { I(R); { assert R.words == A.words; } I(A); I(A) * 1; { lemma_power2_0_is_1(); } I(A) * power2(0); { lemma_mul_annihilate(32); } I(A) * power2(32 * 0); I(A) * power2(32 * w); } } else { var sub_A:BigNat := BigNat_ctor([0]+A.words); assert sub_A.words[|sub_A.words|-1] == A.words[|A.words|-1] > 0; assert WellformedBigNat(sub_A); forall (i | 0<=i<|sub_A.words|) ensures sub_A.words[i] == R.words[w-1+i]; { if (i==0) { assert sub_A.words[i] == 0 == R.words[w-1+i]; } else { calc { sub_A.words[i]; A.words[i-1]; R.words[w+i-1]; } } } lemma_mul_is_mul_boogie(32, w - 1); //- dafnycc calc { I(R); { lemma_BigNatWordShift_(sub_A, R, w-1); } I(sub_A) * power2(32*(w-1)); { selectively_reveal_I(sub_A); } I(BigNat_ctor(sub_A.words[1..])) * Width() * power2(32*(w-1)); I(A) * Width() * power2(32*(w-1)); I(A) * power2(32) * power2(32*(w-1)); { lemma_mul_is_associative(I(A),power2(32),power2(32*(w-1))); } I(A) * (power2(32) * power2(32*(w-1))); { lemma_power2_adds(32, 32*(w-1)); } I(A) * power2(32+32*(w-1)); I(A) * power2(32*1+32*(w-1)); { lemma_mul_is_distributive_add(32,1,w-1); } I(A) * power2(32 * w); } } } static method BigNatWordShift_(A:BigNat, ghost ac:nat, w:nat) returns (R:BigNat, ghost rc:nat) requires WellformedBigNat(A); requires nonzero(A); requires BitCount(A,ac); requires ac+32 * w < Width(); ensures 0<=32 * w; ensures WellformedBigNat(R); ensures I(R) == I(A) * power2(32 * w); ensures BitCount(R,rc); ensures rc == ac+32 * w; { lemma_mul_nonnegative(32,w); var vs:seq := fill_sequence(0,w); R := BigNat_ctor(vs + A.words); rc := ac + 32 * w; assert WellformedBigNat(R); lemma_BigNatWordShift_(A, R, w); calc ==> { !zero(A); { lemma_zero_bits(A,ac); } ac>0; } assert rc>0; assert !(rc==0) && !zero(R); assert rc==0 <==> zero(R); if (0 == w) { assert |vs|==0; assert R.words == vs + A.words == A.words; assert R==A; lemma_mul_annihilate(32); assert rc == ac; } else { //- lemma_mul_strictly_positive_forall(); ghost var w32 := 32*w; assert 0 < w32; calc ==> { power2(ac-1) <= I(A) < power2(ac); { lemma_mul_left_inequality(power2(w32), power2(ac-1), I(A)); lemma_mul_left_inequality(power2(w32), I(A), power2(ac)); } power2(w32) * power2(ac-1) <= power2(w32) * I(A) < power2(w32) * power2(ac); { lemma_power2_adds(w32, ac-1); assert power2(w32) * power2(ac-1) == power2((w32)+(ac-1));} power2(w32+(ac-1)) <= power2(w32) * I(A) < power2(w32) * power2(ac); { lemma_power2_adds(w32, ac); assert power2(w32 + ac) == power2(w32)*power2(ac); } power2(w32+(ac-1)) <= power2(w32) * I(A) < power2((w32)+ac); power2(w32+ac-1) <= power2(w32) * I(A) < power2((w32)+ac); { lemma_mul_is_commutative(power2(w32), I(A)); } power2(w32+ac-1) <= I(A) * power2(w32) < power2(ac+w32); power2((ac+w32)-1) <= I(A) * power2(w32) < power2(ac+w32); //- defn rc power2(rc-1) <= I(A) * power2(w32) < power2(rc); //- lemma_BigNatWordShift_ ensures power2(rc-1) <= I(R) < power2(rc); BitCount(R,rc); } } } //-function IsBit(a:int) //- { a==0 || a==1 } //- //-function IsBitSeq(bs:seq) //- { forall b in bs :: IsBit(b) } //- //-function BitsFor(A:BigNat, ac:nat, bits:seq) //- requires WellformedBigNat(A); //- requires BitCount(A,ac); //- requires IsBitSeq(bits); //- { forall i:int :: 0<=i decreases w; ensures w == |zero_seq(w)|; ensures forall i :: 0<=i zero_seq(w)[i]==0; { if (w==0) then [] else zero_seq(w-1)+[0] } method BigNatSmallBitShift_(A:BigNat, ghost ac:nat, s:nat) returns (R:BigNat, ghost rc:nat) requires WellformedBigNat(A); requires !zero(A); requires s < 32; requires BitCount(A,ac); requires ac+s < Width(); ensures WellformedBigNat(R); ensures |R.words| <= |A.words|+1; ensures I(R) == I(A) * power2(s); ensures BitCount(R,rc); ensures rc == ac+s; { var S:BigNat := BNMakePower2(0, s); lemma_mul_annihilate(32); assert I(S) == power2(s); R := BigNatMul(A,S); rc := ac + s; calc { I(R); I(A) * I(S); I(A) * power2(32 * 0+s); { lemma_mul_annihilate(32); } I(A) * power2(s); } calc ==> { I(A) < power2(ac); { lemma_mul_left_inequality(I(S), I(A), power2(ac)); } I(S) * I(A) < I(S) * power2(ac); { lemma_mul_is_commutative(I(A), I(S)); } I(A) * I(S) < I(S) * power2(ac); I(A) * I(S) < power2(s) * power2(ac); { lemma_exponentiation(s,ac); } I(A) * I(S) < power2(s+ac); I(R) < power2(rc); } if (rc>0) { calc ==> { power2(ac-1) <= I(A); { lemma_mul_left_inequality(I(S), power2(ac-1), I(A)); } I(S) * power2(ac-1) <= I(S) * I(A); { lemma_mul_is_commutative(I(A), I(S)); } I(S) * power2(ac-1) <= I(A) * I(S); power2(s) * power2(ac-1) <= I(A) * I(S); { lemma_exponentiation(s,ac-1); } power2(s+ac-1) <= I(A) * I(S); power2(rc-1) <= I(R); } } assert BitCount(R,rc); lemma_mul_is_mul_boogie(32, |R.words| - 1); //- dafnycc lemma_mul_is_mul_boogie(32, |A.words|); //- dafnycc lemma_mul_is_mul_boogie(32, |A.words| + 1); //- dafnycc calc ==> { true; { lemma_word_bound(A); } I(A) < power2(32 *|A.words|); { lemma_mul_left_inequality(power2(s), I(A), power2(32*|A.words|)); } power2(s) * I(A) < power2(s) * power2(32*|A.words|); { lemma_mul_is_commutative(power2(s), I(A)); assert I(R) == power2(s) * I(A); } I(R) < power2(s) * power2(32*|A.words|); { lemma_exponentiation(s, 32*|A.words|); } I(R) < power2(32*|A.words|+s); { calc ==> { s < 32; 32*|A.words| + s < 32*|A.words| + 32; { lemma_power2_strictly_increases(32*|A.words| + s, 32*|A.words| + 32); } power2(32*|A.words| + s) < power2(32*|A.words| + 32); I(R) < power2(32*|A.words| + 32); I(R) < power2(32*|A.words| + 32 *1); { lemma_mul_is_distributive_add(32, |A.words|, 1); } I(R) < power2(32 * (|A.words| + 1)); } lemma_mul_nonnegative_forall(); assert 0<=32 *(|A.words|+1); } I(R) < power2(32 *(|A.words|+1)); } calc ==> { true; { lemma_word_bound(R); } power2(32*(|R.words|-1)) <= I(R); //- by calc above { lemma_mul_nonnegative_forall(); assert 0<=32*(|A.words|+1); } power2(32*(|R.words|-1)) < power2(32*(|A.words|+1)); { lemma_power2_monotonic_inverse(32*(|R.words|-1), 32*(|A.words|+1)); } 32*(|R.words|-1) < 32*(|A.words|+1); { lemma_mul_is_commutative_forall(); } (|R.words|-1) * 32 < (|A.words|+1) * 32; { lemma_mul_strict_inequality_converse(|R.words|-1,|A.words|+1,32); } |R.words|-1 < |A.words|+1; |R.words| <= |A.words|+1; } } static lemma thirty_two_isnt_so_big_after_all() ensures Word32(32); { assert unroll(1) && unroll(2) && unroll(3) && unroll(4); reveal_power2(); lemma_power2_add8(0); lemma_2to32(); } method BigNatBitShift_(A:BigNat, ghost ac:nat, s:nat) returns (R:BigNat, ghost rc:nat) requires WellformedBigNat(A); requires nonzero(A); requires s < Width(); requires BitCount(A,ac); requires ac+s < Width(); ensures WellformedBigNat(R); ensures I(R) == power2(s) * I(A); ensures BitCount(R,rc); ensures rc == ac+s; { thirty_two_isnt_so_big_after_all(); var thirtytwos:nat,ones:nat := Divide32(s,32); //- Ensures thirtytwos*32 + ones == s; calc ==> { //- requires ac + s < Width(); ac + thirtytwos*32 + ones < Width(); { lemma_mul_nonnegative(thirtytwos,32); } ac + ones < Width(); } var R_ones:BigNat,r1c:nat := BigNatSmallBitShift_(A, ac, ones); calc ==> { ac + thirtytwos*32 + ones < Width(); //- BigNatSmallBitShift_ ensures r1c == ac+ones; ac + thirtytwos*32 + r1c - ac < Width(); { lemma_mul_is_commutative(thirtytwos,32); } //- and + math r1c + 32*thirtytwos < Width(); } R,rc := BigNatWordShift_(R_ones, r1c, thirtytwos); calc { rc; //- BigNatWordShift_ ensures r1c+32*thirtytwos; //- BigNatSmallBitShift_ ensures ac+ones+32*thirtytwos; //- Divide32 ensures { lemma_mul_is_commutative(thirtytwos,32); } ac+s; } calc { I(R); //- BigNatWordShift_ ensures I(R_ones) * power2(32*thirtytwos); //- BigNatSmallBitShift_ ensures I(A) * power2(ones) * power2(32*thirtytwos); { lemma_mul_is_associative(I(A), power2(ones), power2(32*thirtytwos)); } I(A) * (power2(ones) * power2(32*thirtytwos)); { lemma_exponentiation(ones,32*thirtytwos); } I(A) * power2(ones+32*thirtytwos); { lemma_mul_is_commutative(thirtytwos,32); } I(A) * power2(thirtytwos*32+ones); //- Divide32 ensures I(A) * power2(s); { lemma_mul_is_commutative(I(A), power2(s)); } power2(s) * I(A); } } static lemma lemma_modesty_preservation(A:BigNat, ac:nat, B:BigNat, bc:nat) requires WellformedBigNat(A); requires BitCount(A,ac); requires ModestBigNatBits(B,bc); requires I(A) <= I(B); ensures ModestBigNatWords(A); { calc ==> { ModestBigNatBits(B,bc); { lemma_modesty_bit_value_equivalence(B,bc); } ModestBigNatValue(B); I(B) < KindaBigNat(); I(A) < KindaBigNat(); ModestBigNatValue(A); { lemma_modesty_word_value_equivalence(A); } ModestBigNatWords(A); } } static lemma lemma_power2_monotonic_inverse(a:nat,b:nat) decreases a; requires power2(a)<=power2(b); ensures a<=b; { if (a>b) { lemma_power2_strictly_increases(b,a); assert power2(a) > power2(b); assert false; } assert a<=b; } static lemma lemma_ModestBigNatNremainder(N:BigNat, ghost nc:nat, D:BigNat, N_remainder:BigNat) requires ModestBigNatBits(N,nc); requires WellformedBigNat(D); requires WellformedBigNat(N_remainder); requires I(N)-I(D) == I(N_remainder); ensures ModestBigNatWords(N_remainder); { calc ==> { true; { lemma_modesty_bit_value_equivalence(N,nc); } I(N) < KindaBigNat(); { assert I(N_remainder) <= I(N); } //- BigNatSub ensures I(N_remainder) < KindaBigNat(); ModestBigNatValue(N_remainder); { lemma_modesty_word_value_equivalence(N_remainder); } ModestBigNatWords(N_remainder); } } static method bignum_one() returns (one:BigNat) ensures WellformedBigNat(one); ensures BitCount(one,1); ensures I(one)==1; { reveal_I(); one := BigNat_ctor([1]); lemma_2to32(); selectively_reveal_I(one); selectively_reveal_I(BigNat_ctor([])); assert 0 == I(BigNat_ctor([])); lemma_mul_annihilate(Width()); assert 1 == I(one); lemma_power2_0_is_1(); assert power2(1-1) == 1; assert 1 <= 1; assert power2(1-1) <= I(one); lemma_power2_1_is_2(); assert I(one) == 1 < 2 == power2(1); assert I(one) < power2(1); } /* static method BigNatDivInductiveStep(N:BigNat, ghost nc:nat, D:BigNat, ghost dc:nat, s:nat, DS:BigNat) returns (Q:BigNat, R:BigNat) decreases 2 * I(N); requires ModestBigNatBits(N,nc); requires ModestBigNatBits(D,dc); requires nonzero(D); requires WellformedBigNat(DS); requires 0 < I(DS) <= I(N); requires I(DS) == power2(s) * I(D); requires s+10 ==> power2(dc-1) <= I(D); requires nc < dc; ensures I(N) < I(D); { lemma_power2_increases(nc,dc-1); } /* static method BigNatDivBaseCase(N:BigNat, D:BigNat) returns (Q:BigNat, R:BigNat) requires WellformedBigNat(N); requires WellformedBigNat(D); requires I(N) < I(D); ensures WellformedBigNat(Q); ensures WellformedBigNat(R); ensures I(R) < I(D); ensures I(Q) * I(D) + I(R) == I(N); { R := N; Q := BigNatZero(); assert(I(Q)==0); calc { I(Q) * I(D) + I(R); 0 * I(D) + I(R); { lemma_mul_annihilate(I(D)); } 0 + I(R); I(R); I(N); } } static method BigNatDiv(N:BigNat, D:BigNat) returns (Q:BigNat, R:BigNat) decreases 2 * I(N) + 1; requires ModestBigNatWords(N); requires ModestBigNatWords(D); requires nonzero(D); ensures WellformedBigNat(Q); ensures WellformedBigNat(R); ensures I(R) < I(D); ensures I(Q) * I(D) + I(R) == I(N); { lemma_mul_nonnegative_forall(); if (zero(N)) { Q:=BigNatZero(); R:=BigNatZero(); lemma_mul_annihilate(I(D)); } else { var nc:nat :=BigNatCountBits(N); lemma_modesty_word_value_equivalence(N); lemma_modesty_bit_value_equivalence(N,nc); assert ModestBigNatBits(N,nc); var dc:nat :=BigNatCountBits(D); lemma_modesty_word_value_equivalence(D); lemma_modesty_bit_value_equivalence(D,dc); assert ModestBigNatBits(D,dc); if (nc < dc) { lemma_nbits(N,D,nc,dc); assert I(N) < I(D); Q,R := BigNatDivBaseCase(N,D); } else { var s:nat := nc - dc; assert s+1 I(N) < I(D); ensures !residue_small ==> WellformedBigNat(QS); ensures !residue_small ==> WellformedBigNat(DS); ensures !residue_small ==> 0 < I(DS) <= I(N); ensures !residue_small ==> I(QS)*I(D) == I(DS); { QS := BigNatZero(); DS := BigNatZero(); //-lemma_mul_nonnegative_forall(); if (zero(N)) { residue_small := true; } else { var nc:nat :=BigNatCountBits(N); lemma_modesty_word_value_equivalence(N); lemma_modesty_bit_value_equivalence(N,nc); assert ModestBigNatBits(N,nc); var dc:nat :=BigNatCountBits(D); lemma_modesty_word_value_equivalence(D); lemma_modesty_bit_value_equivalence(D,dc); assert ModestBigNatBits(D,dc); if (nc < dc) { lemma_nbits(N,D,nc,dc); assert I(N) < I(D); residue_small := true; } else { var s:nat := nc - dc; assert s+1 WellformedBigNat(DS); invariant !residue_small ==> WellformedBigNat(QS); decreases I(Nresidue); invariant ModestBigNatWords(Nresidue); invariant residue_small ==> I(Nresidue) < I(D); invariant !residue_small ==> 0 < I(DS) <= I(Nresidue); invariant !residue_small ==> I(QS)*I(D) == I(DS); invariant I(N) == I(Qaccum)*I(D) + I(Nresidue); { //-ProfileTally(Tally_BigNatDivWhileLoops(), 1); ghost var IQaccum_old := I(Qaccum); ghost var Nresidue_old := Nresidue; ghost var INresidue_old := I(Nresidue); Qaccum := BigNatAdd(Qaccum, QS); Nresidue := BigNatSub(Nresidue, DS); calc { I(N); IQaccum_old * I(D) + INresidue_old; IQaccum_old*I(D) + I(QS)*I(D) + INresidue_old - I(DS); //- { lemma_mul_is_distributive_forall(); } { lemma_mul_is_distributive_add(I(D), IQaccum_old, I(QS)); lemma_mul_is_commutative_forall(); } (IQaccum_old+I(QS))*I(D) + INresidue_old-I(DS); I(Qaccum)*I(D) + I(Nresidue); } //- assert ModestBigNatWords(Nresidue_old); lemma_modesty_word_value_equivalence(Nresidue_old); //- assert ModestBigNatValue(Nresidue_old); //- assert ModestBigNatValue(Nresidue); lemma_modesty_word_value_equivalence(Nresidue); QS,DS,residue_small := BigNatDivIterative_Split(Nresidue, D); } Q := Qaccum; R := Nresidue; } method BigNatDivImmodest(N:BigNat, D:BigNat) returns (Q:BigNat, R:BigNat) requires WellformedBigNat(N); requires WellformedBigNat(D); requires nonzero(D); ensures WellformedBigNat(Q); ensures WellformedBigNat(R); ensures I(R) < I(D); ensures I(Q) * I(D) + I(R) == I(N); { if (|N.words| <= 0x4000000 && |D.words| <= 0x4000000) { calc ==> { true; { lemma_2toX32(); } ModestBigNatWords(N) && ModestBigNatWords(D); } Q, R := BigNatDiv(N, D); return; } Q := MakeSmallLiteralBigNat(0); R := N; lemma_mul_basics(I(D)); while (true) invariant WellformedBigNat(Q); invariant WellformedBigNat(R); invariant I(Q) * I(D) + I(R) == I(N); decreases I(R); { var c := BigNatCmp(R, D); if (c.BNCmpLt?) { return; } var one := MakeSmallLiteralBigNat(1); calc { (I(Q) + 1) * I(D) + (I(R) - I(D)); { lemma_mul_is_distributive(I(D), I(Q) + 1, 1); } { lemma_mul_is_mul_boogie(1, I(D)); } I(Q) * I(D) + I(R); } Q := BigNatAdd(Q, one); R := BigNatSub(R, D); } } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/BigNum/BigNatMod.i.dfy ================================================ include "BigNatDiv.i.dfy" include "BigNatBitCount.i.dfy" include "../Math/power.i.dfy" method BigNatModulo(N:BigNat, M:BigNat) returns (R:BigNat) requires ModestBigNatWords(N); requires ModestBigNatWords(M); requires 0 <= I(N); requires 0 < I(M); ensures WellformedBigNat(R); ensures I(N) % I(M) == I(R); ensures I(R) < I(M); ensures ModestBigNatWords(R); { var Q:BigNat; Q,R := BigNatDiv(N,M); lemma_fundamental_div_mod_converse(I(N), I(M), I(Q), I(R)); assert I(R) x*y == 0; { forall (x:int, y:int | x==0 || y==0) ensures x*y==0; { if (x==0) { lemma_mul_basics(y); assert x*y == 0; } else { assert y==0; lemma_mul_basics(x); lemma_mul_is_commutative(x,y); assert x*y == 0; } } } static lemma lemma_mul_monotonic(x:int, y:int) ensures (1 < x && 0 < y) ==> (y < x*y); { lemma_mul_properties(); } //-//////////////////////////////////////////////////////////////////////////// method SmallMul_(a:nat, b:nat) returns (s:BigNat) requires Word32(a); requires Word32(b); ensures WellformedBigNat(s); ensures I(s) == a*b; { var l,h := Product32(a,b); if (l==0 && h==0) { lemma_mul_zero(); s := BigNat_ctor([]); reveal_I(); } else if (h==0) { s := BigNat_ctor([l]); reveal_I(); } else { s := BigNat_ctor([l,h]); calc { I(s); { reveal_I(); } I(BigNat_ctor(s.words[1..])) * Width() + l; { reveal_I(); lemma_mul_zero(); } h * Width() + l; //- Product32 ensures a*b; } } } method BigNatLeftShift_(A:BigNat) returns (R:BigNat) requires WellformedBigNat(A); ensures WellformedBigNat(R); ensures I(R) == I(A) * Width(); { if (zero(A)) { lemma_mul_zero(); R := A; } else { R := BigNat_ctor([0] + A.words); reveal_I(); } } static lemma lemma_step1(b:int, ihiAW:int, loA:int) ensures b * ihiAW + b * loA == b * (ihiAW + loA); { lemma_mul_is_distributive_add(b, ihiAW, loA); } method BigNatSingleMul_(A:BigNat, b:nat) returns (R:BigNat) decreases |A.words|; requires WellformedBigNat(A); requires Word32(b); ensures WellformedBigNat(R); ensures I(A) * b == I(R); { R := BigNatZero(); calc { I(BigNatZero()) * b; 0 * b; { lemma_mul_zero(); } 0; I(R); } var n := |A.words|; assert A.words[n..] == []; while (n > 0) invariant 0 <= n <= |A.words|; invariant WellformedBigNat(R); invariant I(R) == I(BigNat_ctor(A.words[n..])) * b; //- induction hypothesis { ghost var hi_A := BigNat_ctor(A.words[n..]); ghost var ugly_expression := I(hi_A) * Width(); n := n - 1; ghost var hilo_A := BigNat_ctor(A.words[n..]); assert hi_A.words == hi(hilo_A).words; var sub_R := R; var parent:BigNat := BigNatLeftShift_(sub_R); var child:BigNat := SmallMul_(A.words[n], b); R := BigNatAdd(parent, child); calc { I(R); I(parent) + I(child); I(parent) + A.words[n] * b; I(sub_R) * Width() + A.words[n] * b; (I(hi_A) * b) * Width() + A.words[n] * b; { lemma_mul_is_commutative(I(hi_A),b); } (b * I(hi_A)) * Width() + A.words[n] * b; { lemma_mul_is_associative(b, I(hi_A), Width()); } b * (I(hi_A) * Width()) + A.words[n] * b; { lemma_mul_is_commutative(b,A.words[n]); } b * ugly_expression + b * A.words[n]; { lemma_step1(b, ugly_expression, A.words[n]); } b * (ugly_expression + A.words[n]); { lemma_hilo(hilo_A); } b * I(hilo_A); { lemma_mul_is_commutative(b,I(hilo_A)); } I(hilo_A) * b; } } assert A.words[0..] == A.words; } method BigNatMul(A:BigNat, B:BigNat) returns (R:BigNat) decreases |B.words|; requires WellformedBigNat(A); requires WellformedBigNat(B); ensures WellformedBigNat(R); ensures I(A) * I(B) == I(R); { if (zero(A)) { lemma_mul_zero(); R := A; return; } R := BigNatZero(); var n := |B.words|; assert B.words[n..] == []; lemma_mul_zero(); while (n > 0) invariant 0 <= n <= |B.words|; invariant WellformedBigNat(R); invariant I(R) == I(A) * I(BigNat_ctor(B.words[n..])); //- induction hypothesis { ghost var hi_B := BigNat_ctor(B.words[n..]); n := n - 1; ghost var hilo_B := BigNat_ctor(B.words[n..]); assert hi_B.words == hi(hilo_B).words; var sub_R := R; var parent:BigNat := BigNatLeftShift_(sub_R); var child:BigNat := BigNatSingleMul_(A, B.words[n]); R := BigNatAdd(parent, child); calc { I(R); I(parent) + I(child); I(sub_R) * Width() + I(child); I(sub_R) * Width() + I(A) * B.words[n]; (I(A) * I(hi_B)) * Width() + I(A) * B.words[n]; { lemma_mul_is_associative(I(A), I(hi_B), Width()); } I(A) * (I(hi_B) * Width()) + I(A) * B.words[n]; { lemma_mul_is_distributive_add(I(A), I(hi_B) * Width(), B.words[n]); } I(A) * (I(hi_B) * Width() + B.words[n]); { lemma_hilo(hilo_B); } I(A) * I(hilo_B); } } assert B.words[0..] == B.words; } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/BigNum/BigNatPartial.i.dfy ================================================ //-include "../Util/assembly_deprecated.s.dfy" include "BigNatCore.i.dfy" include "../Util/integer_sequences.s.dfy" //-static predicate IsWordSeq(ws:seq) { IsIsWordSeq(ws) } ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// static function {:opaque} V(vs:seq) : int { if (|vs|==0) then 0 else Width() * V(vs[1..]) + vs[0] } static lemma selectively_reveal_V(vs:seq) ensures V(vs) == if (|vs|==0) then 0 else Width() * V(vs[1..])+vs[0]; { reveal_V(); } static lemma lemma_V_I(A:BigNat) decreases |A.words|; requires WellformedBigNat(A); ensures I(A) == V(A.words); { if (zero(A)) { reveal_V(); assert I(A) == 0 == V(A.words); } else { lemma_V_I(hi(A)); reveal_V(); reveal_V(); calc { I(A); { reveal_I(); } I(hi(A)) * Width() + lo(A); { lemma_mul_is_commutative(I(hi(A)), Width()); } Width() * I(hi(A)) + lo(A); Width() * V(hi(A).words) + lo(A); V(A.words); } } } static lemma{:dafnycc_conservative_seq_triggers} lemma_V_power(ls:seq, hs:seq) decreases |ls|; ensures 32 * |ls| >= 0; ensures V(ls+hs) == power2(32 * |ls|) * V(hs) + V(ls); { lemma_mul_left_inequality(32,0,|ls|); lemma_mul_basics(32); if (|ls|==0) { assert ls+hs == hs; calc { power2((32*|ls|)) * V(hs) + V(ls); power2(32 * 0) * V(hs) + V(ls); { lemma_mul_basics(32); } power2(0) * V(hs) + V(ls); { lemma_power2_0_is_1(); } 1 * V(hs) + V(ls); { lemma_mul_basics(V(hs)); } V(hs) + V(ls); { reveal_V(); } V(hs); V(ls+hs); } } else { lemma_V_power(ls[1..], hs); assert V(ls[1..]+hs) == power2(32 *(|ls|-1)) * V(hs) + V(ls[1..]); calc { V(ls+hs); { selectively_reveal_V(ls+hs); } Width() * V((ls+hs)[1..]) + (ls+hs)[0]; { assert (ls+hs)[1..] == ls[1..]+hs; } Width() * V(ls[1..]+hs) + (ls+hs)[0]; { assert (ls+hs)[0] == ls[0]; } Width() * V(ls[1..]+hs) + ls[0]; Width() * (power2(32*(|ls|-1)) * V(hs) + V(ls[1..])) + ls[0]; power2(32) * (power2(32*(|ls|-1)) * V(hs) + V(ls[1..])) + ls[0]; { lemma_mul_is_distributive_add(power2(32), power2(32*(|ls|-1)) * V(hs), V(ls[1..])); } power2(32) * (power2(32*(|ls|-1)) * V(hs)) + power2(32) * V(ls[1..]) + ls[0]; { lemma_mul_is_associative(power2(32), power2(32*(|ls|-1)), V(hs)); } power2(32) * power2(32*(|ls|-1)) * V(hs) + power2(32) * V(ls[1..]) + ls[0]; { lemma_power2_adds(32, 32*(|ls|-1)); } power2(32 + 32*(|ls|-1)) * V(hs) + power2(32) * V(ls[1..]) + ls[0]; { lemma_mul_basics(32); } power2(32*1 + 32*(|ls|-1)) * V(hs) + power2(32) * V(ls[1..]) + ls[0]; { lemma_mul_is_distributive_add(32,1,|ls|-1); } power2(32*|ls|) * V(hs) + power2(32) * V(ls[1..]) + ls[0]; { reveal_V(); } power2(32*|ls|) * V(hs) + V(ls); } } } static lemma lemma_V_singleton(s:seq) requires |s|==1; ensures V(s) == s[0]; { reveal_V(); lemma_mul_basics(Width()); } static lemma lemma_V_upper_bound(s:seq) decreases |s|; requires IsWordSeq(s); ensures 32 * |s| >= 0; ensures V(s) <= power2(32*|s|)-1; { reveal_V(); if (|s|==0) { lemma_power2_0_is_1(); lemma_mul_basics(32); } else { lemma_mul_nonnegative_forall(); calc { V(s); == { selectively_reveal_V(s); } Width() * V(s[1..]) + s[0]; <= { lemma_V_upper_bound(s[1..]); assert V(s[1..]) <= power2(32*(|s|-1))-1; lemma_mul_left_inequality(Width(), V(s[1..]), power2(32*(|s|-1))-1); } Width() * (power2(32*(|s|-1))-1) + s[0]; <= Width() * (power2(32*(|s|-1))-1) + power2(32) - 1; Width() * (power2(32*(|s|-1))-1) + Width() - 1; { lemma_mul_basics(Width()); } Width() * (power2(32*(|s|-1))-1) + Width()*1 - 1; { lemma_mul_is_distributive_add(Width(), power2(32*(|s|-1))-1, 1); } Width() * (power2(32*(|s|-1))-1+1) - 1; Width() * power2(32*(|s|-1)) - 1; power2(32) * power2(32*(|s|-1)) - 1; { lemma_power2_adds(32, 32*(|s|-1)); } power2(32 + 32*(|s|-1)) - 1; { lemma_mul_basics(32); } power2(32*1 + 32*(|s|-1)) - 1; { lemma_mul_is_distributive_add(32, 1, |s|-1); } power2(32*|s|) - 1; } } } static lemma lemma_V_lower_bound(s:seq) requires IsWordSeq(s); ensures 0 <= V(s); { reveal_V(); if (|s|==0) { } else { lemma_V_lower_bound(s[1..]); reveal_V(); lemma_mul_left_inequality(Width(), 0, V(s[1..])); lemma_mul_basics(Width()); } } static lemma lemma_V_high_zeros(s:seq) requires |s|>0; requires s[|s|-1]==0; ensures V(s) == V(s[..|s|-1]); { if (|s|==1) { calc { V(s); { selectively_reveal_V(s); } Width() * V(s[1..])+s[0]; { assert s[1..] == []; } Width() * V([])+s[0]; { selectively_reveal_V([]); } Width() * 0+s[0]; { lemma_mul_basics_forall(); } s[0]; s[|s|-1]; 0; { selectively_reveal_V([]); } V([]); { assert s[..|s|-1] == []; } V(s[..|s|-1]); } } else { var hi_s := s[1..]; var trunc_s := s[..|s|-1]; calc { //- 2,3,0,0 V(s); { selectively_reveal_V(s); } //- 3,0,0*w + 2 Width() * V(hi_s) +s[0]; { lemma_V_high_zeros(hi_s); } //- 3,0*w + 2 Width() * V(hi_s[..|hi_s|-1])+s[0]; calc { hi_s[..|hi_s|-1]; s[1..][..|s[1..]|-1]; s[1..][..|s|-2]; s[1..|s|-1]; s[..|s|-1][1..]; trunc_s[1..]; } Width() * V(trunc_s[1..]) + s[0]; Width() * V(trunc_s[1..]) + trunc_s[0]; //- 2,3,0 { selectively_reveal_V(trunc_s); } V(trunc_s); V(s[..|s|-1]); } } } static function {:opaque} TruncatingBigNatCtor_def(ss:seq) : BigNat decreases |ss|; requires IsWordSeq(ss); { if (|ss|==0) then BigNat_ctor([]) else if (ss[|ss|-1] > 0) then BigNat_ctor(ss) else TruncatingBigNatCtor_def(ss[..|ss|-1]) } static function TruncatingBigNatCtor(ss:seq) : BigNat requires IsWordSeq(ss); ensures WellformedBigNat(TruncatingBigNatCtor(ss)); ensures V(ss) == I(TruncatingBigNatCtor(ss)); ensures |TruncatingBigNatCtor(ss).words| <= |ss|; { lemma_TruncatingBigNatCtor(ss,TruncatingBigNatCtor_def(ss)); TruncatingBigNatCtor_def(ss) } static method TruncatingBigNatCtor_impl(ss:seq) returns(N:BigNat) requires IsWordSeq(ss); ensures N == TruncatingBigNatCtor(ss); { reveal_TruncatingBigNatCtor_def(); var k := |ss|; assert ss == ss[..k]; while (k > 0) invariant 0 <= k <= |ss|; invariant TruncatingBigNatCtor_def(ss) == TruncatingBigNatCtor_def(ss[..k]); invariant IsWordSeq(ss[..k]); { k := k - 1; if (ss[k] > 0) { N := BigNat_ctor(ss[..k+1]); return; } assert ss[..k+1][..k] == ss[..k]; } N := BigNat_ctor([]); } static lemma lemma_TruncatingBigNatCtor(ss:seq,N:BigNat) decreases |ss|; requires IsWordSeq(ss); requires N == TruncatingBigNatCtor_def(ss); ensures WellformedBigNat(N); ensures V(ss) == I(N); ensures |N.words| <= |ss|; { reveal_TruncatingBigNatCtor_def(); if (|ss|==0) { assert N == BigNat_ctor([]); calc { I(N); { reveal_I(); } 0; { reveal_V(); } V(ss); } } else if (ss[|ss|-1] > 0) { assert N == BigNat_ctor(ss); lemma_V_I(N); } else { assert N == TruncatingBigNatCtor_def(ss[..|ss|-1]); lemma_TruncatingBigNatCtor(ss[..|ss|-1],N); calc { I(N); V(ss[..|ss|-1]); { lemma_V_high_zeros(ss); } V(ss); } } } static lemma lemma_TruncatingBigNat_alignment(ss:seq,N:BigNat) decreases |ss|; requires IsWordSeq(ss); requires N == TruncatingBigNatCtor(ss); ensures forall i :: 0<=i<|N.words| ==> N.words[i] == ss[i]; ensures forall i :: |N.words|<=i<|ss| ==> ss[i] == 0; { reveal_TruncatingBigNatCtor_def(); if (|ss|==0) { selectively_reveal_V(ss); assert V(ss) == 0; assert I(N) == 0; assert zero(N); } else if (ss[|ss|-1] > 0) { assert N == BigNat_ctor(ss); assert |N.words| == |ss|; } else { assert N == TruncatingBigNatCtor(ss[..|ss|-1]); forall (i | 0<=i<|N.words|) ensures N.words[i] == ss[i]; { calc { N.words[i]; { lemma_TruncatingBigNat_alignment(ss[..|ss|-1], N); } ss[..|ss|-1][i]; ss[i]; } } forall (i | |N.words|<=i<|ss|) ensures ss[i] == 0; { if (i<|ss|-1) { calc { ss[i]; ss[..|ss|-1][i]; { lemma_TruncatingBigNat_alignment(ss[..|ss|-1], N); } 0; } } } } } static lemma lemma_TruncatingBigNat_hilo(ss:seq) requires IsWordSeq(ss); requires |ss|>0; ensures I(TruncatingBigNatCtor(ss)) == I(TruncatingBigNatCtor(ss[1..]))*Width() + ss[0]; { calc { I(TruncatingBigNatCtor(ss)); V(ss); { reveal_V(); lemma_mul_is_commutative_forall(); } V(ss[1..])*Width() + ss[0]; I(TruncatingBigNatCtor(ss[1..]))*Width() + ss[0]; } } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/BigNum/BigNatRandom.i.dfy ================================================ include "BigNatCompare.i.dfy" include "BigNatBitCount.i.dfy" include "../Crypto/RandomNumberGen.s.dfy" include "BigNumBEAdaptor.i.dfy" include "BigNatBitwise.i.dfy" include "../../Drivers/TPM/tpm-wrapper.i.dfy" static predicate CandidateSeedWorksheetValid_precondition(worksheet:CandidateSeedWorksheet) { 0 < |worksheet.rows| } static method truncate_high_zeros(ws:seq) returns (ts:seq) decreases |ws|; ensures |ts| <= |ws|; ensures forall i:nat :: i<|ts| ==> ws[i]==ts[i]; ensures 0<|ts| ==> ts[|ts|-1] != 0; { var n := |ws|; while (n > 0) invariant 0 <= n <= |ws|; invariant forall i :: n <= i < |ws| ==> ws[i] == 0; decreases n; { n := n - 1; if (ws[n] != 0) { ts := ws[0..n+1]; return; } } ts := []; } method BigNatRandomPower2(c:nat) returns (R:BigNat, ghost randoms:seq) requires Word32(c); requires TPM_ready(); ensures WellformedBigNat(R); ensures I(R) < power2(c); ensures |randoms| == DivideRoundingUp(c, 8); ensures IsByteSeq(randoms); ensures I(R) == BEByteSeqToInt(randoms) % power2(c); ensures TPM_ready(); modifies this`TPM; modifies this`IoMemPerm; ensures TPMs_match_except_for_randoms(old(TPM), TPM); ensures old(TPM).random_index <= TPM.random_index; ensures randoms == TPM_random_bytes_premium(old(TPM).random_index, TPM.random_index); { lemma_2to32(); var full_bytes,extra_bits := Divide32(c, 8); assert full_bytes*8+extra_bits == c; var byte_count := full_bytes; if (extra_bits > 0) { //- pluck an extra byte to get the extra bits from byte_count := full_bytes + 1; } lemma_mod_pos_bound(extra_bits, 8); assert c == full_bytes*8+extra_bits; lemma_fundamental_div_mod_converse(c, 8, full_bytes, extra_bits); ghost var L8 := 8; assert full_bytes == c/L8; assert extra_bits == c%L8; calc { DivideRoundingUp_premium(c, 8); { lemma_div_is_div_boogie(c+7, 8); } (c+7)/8; (c-1)/8 + 1; } calc { (c-1)/8 + 1; { lemma_hoist_over_denominator(c-1, 1, 8); } (c-1+1*8)/8; (c+7)/8; } if (extra_bits==0) { calc { byte_count; full_bytes; c/L8; { lemma_round_down(c, 7, 8); } (L8*((c+7)/L8))/L8; { lemma_hoist_over_denominator(0, (c+7)/L8, L8); lemma_mul_is_commutative_forall(); } div(0,L8) + (c+7)/L8; { lemma_div_basics(L8); } (c+7)/L8; { lemma_div_is_div_boogie(c+7,8); } (c+7)/8; (c-1)/8+1; } } else { calc { byte_count; full_bytes+1; c/L8+1; { calc { c - c%L8; c - extra_bits; <= c-1; } lemma_mod_properties(); assert c-1 < c + L8 - c%L8; if (c CandidateSeedWorksheetRowValid(req, worksheet.rows[i])) //- all but last row fail && (forall i:int :: 0<=i<|worksheet.rows|-1 ==> !worksheet.rows[i].accepted) //- last as specified && (|worksheet.rows|>0 ==> worksheet.rows[|worksheet.rows|-1].accepted == last_succeeds) //- randoms properly accounted for && CandidateSeedWorksheetConsumesRandoms(worksheet.rows) == worksheet.randoms } method BigNatRandomFromInclusiveRange(L:BigNat, H:BigNat, ghost req:SelectRandomRequest) returns (R:BigNat, ghost worksheet:CandidateSeedWorksheet) requires WellformedBigNat(L); requires ModestBigNatWords(H); requires I(L) <= I(H); requires req.l == I(L); requires req.h == I(H); requires SelectRandomRequestValid(req); requires TPM_ready(); ensures TPM_ready(); ensures WellformedBigNat(R); ensures I(L) <= I(R) <= I(H); ensures CandidateSeedWorksheetValid(req, worksheet); ensures I(R) == CandidateSeedWorksheetOutput(worksheet); modifies this`TPM; modifies this`IoMemPerm; ensures TPMs_match_except_for_randoms(old(TPM), TPM); ensures old(TPM).random_index <= TPM.random_index; ensures worksheet.randoms == TPM_random_bytes_premium(old(TPM).random_index, TPM.random_index); { var c:nat := BigNatCountBits(H); lemma_bit_count_is_unique(I(H), c, req.h_bits); var lobound:bool := false; var hibound:bool := false; ghost var randoms; worksheet := CandidateSeedWorksheet_c([], []); ghost var started := false; R := L; //- dafnycc: initialize variable var accepted := false; while (!accepted) decreases *; //- Possibly doesn't terminate. invariant started ==> WellformedBigNat(R); invariant started ==> lobound == (I(L)<=I(R)); invariant started ==> hibound == (I(R)<=I(H)); invariant started ==> 0<|worksheet.rows|; invariant accepted ==> started; invariant CandidateSeedWorksheetValid_incremental(req, worksheet, accepted); invariant accepted ==> CandidateSeedWorksheetOutput(worksheet) == I(R); invariant TPM_ready(); invariant TPMs_match_except_for_randoms(old(TPM), TPM); invariant old(TPM).random_index <= TPM.random_index; invariant worksheet.randoms == TPM_random_bytes_premium(old(TPM).random_index, TPM.random_index); invariant TPM.random_index - old(TPM).random_index == |worksheet.randoms|; { R,randoms := BigNatRandomPower2(c); lobound := BigNatLe(L, R); hibound := BigNatLe(R, H); started := true; accepted := lobound && hibound; ghost var row := CandidateSeedWorksheetRow_c(I(R), accepted, randoms); ghost var worksheet' := CandidateSeedWorksheet_c( worksheet.rows + [row], worksheet.randoms + randoms); lemma_random_comprehension(old(TPM).random_index, worksheet.randoms, randoms); worksheet := worksheet'; } } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/BigNum/BigNatSub.i.dfy ================================================ include "Word32.i.dfy" include "BigNatCore.i.dfy" include "BigNatPartial.i.dfy" include "BigNatX86Shim.i.dfy" include "../Util/ProfileIfc.i.dfy" datatype sub_Problem = sub_Problem_ctor( A:BigNat, B:BigNat, c:nat); static predicate WellformedBorrow(borrow:nat) { borrow==0 || borrow==1 } static predicate sub_WellformedProblem(p:sub_Problem) { WellformedBigNat(p.A) && WellformedBigNat(p.B) && I(p.A) >= (I(p.B) + p.c) && WellformedBorrow(p.c) } static predicate sub_WorksheetProblemsWellformed(ps:seq) { forall i :: 0 <= i < |ps| ==> sub_WellformedProblem(ps[i]) } static predicate method sub_ZeroProblem(p:sub_Problem) requires sub_WellformedProblem(p); { zero(p.A) && zero(p.B) && p.c==0 } static predicate sub_WorksheetProblemsConnected(p0:sub_Problem, s0:nat, p1:sub_Problem) requires sub_WellformedProblem(p0); requires Word32(s0); requires sub_WellformedProblem(p1); { p1.A == hi(p0.A) && p1.B == hi(p0.B) && lo(p0.A) - lo(p0.B) - p0.c == s0 - p1.c * Width() && !sub_ZeroProblem(p0) } static predicate sub_WellformedSolutions(ss:seq) { forall i :: 0 <= i < |ss| ==> ss[i]>=0 && Word32(ss[i]) } static predicate sub_IncompleteWorksheetConsistent(ps:seq, ss:seq) { sub_WorksheetProblemsWellformed(ps) && |ps| == |ss|+1 && sub_WellformedSolutions(ss) && (forall i:nat :: i < |ps|-1 ==> sub_WorksheetProblemsConnected(ps[i], ss[i], ps[i+1])) } static predicate sub_WorksheetConsistent(ps:seq, ss:seq) { sub_IncompleteWorksheetConsistent(ps, ss) && sub_ZeroProblem(ps[|ps|-1]) } static lemma lemma_sub_solve_one(p:sub_Problem, m:nat, c:nat, pnew:sub_Problem) requires sub_WellformedProblem(p); requires !zero(p.A); requires Word32(m); requires c==0 || c==1; requires lo(p.A)-lo(p.B)-p.c == m - c*Width(); requires pnew == sub_Problem_ctor(hi(p.A), hi(p.B), c); ensures sub_WellformedProblem(pnew); ensures Word32(m); ensures sub_WorksheetProblemsConnected(p, m, pnew); ensures I(pnew.A) < I(p.A); { lemma_2to32(); lemma_mul_is_mul_boogie_Width(); reveal_I(); if (I(pnew.A) < I(pnew.B) + pnew.c) //- proof by contradiction { calc { I(p.A); { lemma_hilo(p.A); } I(hi(p.A))*Width() + lo(p.A); I(pnew.A)*Width() + lo(p.A); <= { lemma_mul_inequality(I(pnew.A), (I(pnew.B) + pnew.c - 1), Width()); } (I(pnew.B) + pnew.c - 1) * Width() + lo(p.A); { lemma_mul_is_distributive_add_other_way(Width(), I(pnew.B) + pnew.c, -1); } I(pnew.B)*Width() + pnew.c*Width() + (-1) * Width() + lo(p.A); { lemma_mul_unary_negation(-1,Width()); } I(pnew.B)*Width() + pnew.c*Width() - 1 * Width() + lo(p.A); { lemma_mul_basics(Width()); } I(pnew.B)*Width() + pnew.c*Width() - Width() + lo(p.A); I(pnew.B)*Width() - Width() + m + lo(p.B) + p.c; < { assert m < Width(); } I(pnew.B)*Width() + lo(p.B) + p.c; I(hi(p.B))*Width() + lo(p.B) + p.c; { lemma_hilo(p.B); } I(p.B) + p.c; } assert false; } assert I(pnew.A) >= I(pnew.B) + pnew.c; assert sub_WellformedProblem(pnew); if (|p.A.words| == 1) { calc { I(pnew.A); I(hi(p.A)); { reveal_I(); } 0; < //- WellformedBigNat(p.A) && |p.A.words|==1 p.A.words[0]; { lemma_mul_basics_forall(); } 0 * Width()+p.A.words[0]; { reveal_I(); } I(BigNat_ctor(p.A.words[1..])) * Width()+p.A.words[0]; { reveal_I(); } I(p.A); } } else { assert |hi(p.A).words|>0; assert !zero(hi(p.A)); calc { I(pnew.A); I(hi(p.A)); < { assert 1, ghost ps:seq) requires WellformedBigNat(A); requires WellformedBigNat(B); requires I(A) >= I(B); ensures |ps|>0; ensures ps[0].A == A; ensures ps[0].B == B; ensures ps[0].c == 0; ensures sub_WorksheetConsistent(ps,ss); { var start_problem:sub_Problem := sub_Problem_ctor(A,B,0); var p:sub_Problem := start_problem; ps := [ p ]; ss := []; while (!sub_ZeroProblem(p)) decreases I(p.A); invariant sub_IncompleteWorksheetConsistent(ps, ss); invariant sub_WellformedProblem(p); invariant ps[0] == start_problem; invariant ps[|ps|-1] == p; { var s:nat,pnew:sub_Problem := sub_solve_one_(p); assert(I(pnew.A) < I(p.A)); ss := ss + [s]; ps := ps + [pnew]; //- assert sub_WorksheetProblemsConnected(p, s, pnew); // TODO delete //- should fall straight out of sub_solve_one_! //- assert sub_WellformedSolutions(ss); p := pnew; } assert sub_ZeroProblem(ps[|ps|-1]); assert sub_WorksheetConsistent(ps, ss); } static function sub_ProblemValue(p:sub_Problem) : int requires sub_WellformedProblem(p); { I(p.A) - I(p.B) - p.c } static predicate sub_WellformedBigNatSeq(R:seq) { forall i :: 0 <= i < |R| ==> WellformedBigNat(R[i]) } //-//////////////////////////////////////////////////////////////////////////// //- These functions define the relationship between a sequence of words //- and a sequence of BigNats formed from subsequences of the word seq. //- That's so that we can show that the high-place-value partial sums //- (one word at a time) can be viewed as correct BigNat solutions to the //- truncated problems. Then we inductively include low-order words one //- at a time until we've reconstructed the original problem. static predicate sub_BigNatsForSumWords_Base(ss:seq, R:seq) requires IsWordSeq(ss); requires sub_WellformedBigNatSeq(R); { |R| == |ss|+1 && R[|R|-1] == TruncatingBigNatCtor([]) && R[0] == TruncatingBigNatCtor(ss) } static predicate sub_BigNatsForSumWords_Assembly(ss:seq, R:seq) requires sub_WellformedBigNatSeq(R); requires IsWordSeq(ss); requires sub_BigNatsForSumWords_Base(ss, R); { forall i :: 0 <= i <=|ss| ==> R[i] == TruncatingBigNatCtor(ss[i..]) } static predicate sub_ShiftRelation(M:seq, i:nat) requires sub_WellformedBigNatSeq(M); requires i < |M|-1; { I(M[i]) == I(M[i+1]) * Width() + lo(M[i]) } static predicate sub_ShiftRelationSeq(ss:seq, R:seq) requires sub_WellformedBigNatSeq(R); requires |R| == |ss|+1; { forall i :: 0 <= i < |ss| ==> sub_ShiftRelation(R, i) } static lemma sub_ShiftRelationLemma(M:seq, i:nat) requires sub_WellformedBigNatSeq(M); requires i < |M|-1; requires sub_ShiftRelation(M,i); ensures I(M[i]) == I(M[i+1]) * Width() + lo(M[i]); { reveal_I(); } static predicate sub_BigNatsForSumWords(ss:seq, R:seq) requires IsWordSeq(ss); requires sub_WellformedBigNatSeq(R); { sub_BigNatsForSumWords_Base(ss,R) && sub_BigNatsForSumWords_Assembly(ss, R) && sub_ShiftRelationSeq(ss,R) } static lemma sub_ConstructBigNatsFromSumWords_lemma(ss:seq, R:seq) requires sub_WellformedBigNatSeq(R); requires IsWordSeq(ss); requires |ss|>0; requires |R| == |ss|+1; requires sub_BigNatsForSumWords(ss[1..],R[1..]); requires R[0] == TruncatingBigNatCtor(ss); ensures sub_BigNatsForSumWords_Base(ss,R); ensures sub_BigNatsForSumWords(ss,R); { forall (i:nat | i <=|ss|) ensures R[i] == TruncatingBigNatCtor(ss[i..]); { if (i==0) { assert ss == ss[0..]; } else { assert R[1..][i-1] == R[i]; assert ss[1..][i-1..] == ss[i..]; } } assert sub_BigNatsForSumWords_Assembly(ss,R); forall (i:nat | i < |ss|) ensures sub_ShiftRelation(R, i); { if (i==0) { if (zero(R[0])) { calc { ss[0]; { lemma_TruncatingBigNat_alignment(ss, R[0]); } 0; lo(R[0]); } } else { calc { ss[0]; { lemma_TruncatingBigNat_alignment(ss, R[0]); } lo(R[0]); } } calc { I(R[0]); I(TruncatingBigNatCtor(ss)); { lemma_TruncatingBigNat_hilo(ss); } I(TruncatingBigNatCtor(ss[1..]))*Width() + ss[0]; //- inductive application of sub_BigNatsForSumWords_Assembly I(R[1])*Width() + ss[0]; //- proven above this calc I(R[1])*Width() + lo(R[0]); } assert sub_ShiftRelation(R, 0); } else { assert R[1..][i-1] == R[i]; calc ==> { sub_ShiftRelationSeq(ss[1..],R[1..]); sub_ShiftRelation(R[1..], i-1); sub_ShiftRelation(R, i); } } } assert sub_ShiftRelationSeq(ss,R); } static ghost method sub_ConstructBigNatsFromSumWords_(ss:seq) returns (R:seq) requires IsWordSeq(ss); ensures sub_WellformedBigNatSeq(R); ensures sub_BigNatsForSumWords(ss,R); { var r:BigNat := TruncatingBigNatCtor(ss); var tail:seq; if |ss|==0 { tail := []; R := [r] + tail; } else { tail := sub_ConstructBigNatsFromSumWords_(ss[1..]); R := [r] + tail; sub_ConstructBigNatsFromSumWords_lemma(ss, R); } } static lemma sub_lemma_accumulate(s:int, ss:seq, ps:seq, Ms:seq) decreases |ss|-s; requires 0<=s<=|ss|; requires sub_WorksheetConsistent(ps,ss); requires sub_WellformedBigNatSeq(Ms); requires sub_BigNatsForSumWords(ss,Ms); ensures I(Ms[s]) == sub_ProblemValue(ps[s]); { if (s==|ss|) { calc { sub_ProblemValue(ps[s]); I(ps[s].A) - I(ps[s].B) - ps[s].c; { reveal_I(); } 0; { reveal_I(); } I(Ms[s]); } } else { calc { I(Ms[s]); { sub_ShiftRelationLemma(Ms, s); } I(Ms[s+1]) * Width() + lo(Ms[s]); { lemma_TruncatingBigNat_alignment(ss[s..], Ms[s]); if (0 == |Ms[s].words|) { assert zero(Ms[s]); calc { lo(Ms[s]); 0; ss[s..][0]; ss[s]; } } else { calc { lo(Ms[s]); Ms[s].words[0]; ss[s..][0]; ss[s]; } } } I(Ms[s+1]) * Width() + ss[s]; //- sub_WorksheetProblemsConnected(ps[s],ss[s],ps[s+1]); I(Ms[s+1]) * Width() + lo(ps[s].A)-lo(ps[s].B)-ps[s].c + ps[s+1].c * Width(); { sub_lemma_accumulate(s+1, ss, ps, Ms); assert ps[s+1].c == -I(Ms[s+1]) + I(ps[s+1].A) - I(ps[s+1].B); } I(Ms[s+1]) * Width() + lo(ps[s].A)-lo(ps[s].B)-ps[s].c + (-I(Ms[s+1]) + I(ps[s+1].A) - I(ps[s+1].B)) * Width(); { lemma_mul_is_commutative(Width(), -I(Ms[s+1]) + I(ps[s+1].A) - I(ps[s+1].B)); } I(Ms[s+1]) * Width() + lo(ps[s].A)-lo(ps[s].B)-ps[s].c + Width() * (I(ps[s+1].A) - I(Ms[s+1]) - I(ps[s+1].B)); { lemma_mul_is_distributive_sub(Width(), I(ps[s+1].A) - I(Ms[s+1]), I(ps[s+1].B)); } I(Ms[s+1]) * Width() + lo(ps[s].A)-lo(ps[s].B)-ps[s].c + Width() * (I(ps[s+1].A) - I(Ms[s+1])) - Width() * I(ps[s+1].B); { lemma_mul_is_distributive_sub(Width(), I(ps[s+1].A), I(Ms[s+1])); } I(Ms[s+1]) * Width() + lo(ps[s].A)-lo(ps[s].B)-ps[s].c + (Width() * I(ps[s+1].A) - Width() * I(Ms[s+1]) - Width() * I(ps[s+1].B)); I(Ms[s+1]) * Width() + lo(ps[s].A)-lo(ps[s].B)-ps[s].c + Width() * I(ps[s+1].A) - Width() * I(Ms[s+1]) - Width() * I(ps[s+1].B); { lemma_mul_is_commutative(Width(),I(Ms[s+1])); } Width() * I(Ms[s+1]) + lo(ps[s].A)-lo(ps[s].B)-ps[s].c + Width() * I(ps[s+1].A) - Width() * I(Ms[s+1]) - Width() * I(ps[s+1].B); //- cancel terms lo(ps[s].A)-lo(ps[s].B)-ps[s].c + Width() * I(ps[s+1].A) - Width() * I(ps[s+1].B); //- rearrange terms Width() * I(ps[s+1].A) + lo(ps[s].A) - (Width() * I(ps[s+1].B) + lo(ps[s].B)) - ps[s].c; //- sub_WorksheetProblemsConnected(ps[s],...,ps[s+1]); Width() * I(hi(ps[s].A)) + lo(ps[s].A) - (Width() * I(hi(ps[s].B)) + lo(ps[s].B)) - ps[s].c; { lemma_mul_is_commutative(Width(), I(hi(ps[s].A))); lemma_mul_is_commutative(Width(), I(hi(ps[s].B))); lemma_hilo(ps[s].A); lemma_hilo(ps[s].B); } I(ps[s].A) - I(ps[s].B) - ps[s].c; sub_ProblemValue(ps[s]); } } } static method BigNatSub(A:BigNat, B:BigNat) returns (R:BigNat) requires WellformedBigNat(A); requires WellformedBigNat(B); requires I(A) >= I(B); ensures WellformedBigNat(R); ensures I(A)-I(B) == I(R); { //-ProfileTally(Tally_BigNatSub(), 1); var ss:seq; ghost var ps:seq; ss,ps := BigNatSub_(A,B); ghost var Ms:seq := sub_ConstructBigNatsFromSumWords_(ss); //- Ms[i] is the BigNat formed by ss[i..]. It includes Ms[|ss|], which is always TruncatingBigNatCtor([]) (0) R := TruncatingBigNatCtor_impl(ss); calc { I(R); I(Ms[0]); { sub_lemma_accumulate(0,ss,ps,Ms); } sub_ProblemValue(ps[0]); I(ps[0].A) - I(ps[0].B) - ps[0].c; I(ps[0].A) - I(ps[0].B); I(A) - I(B); } } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/BigNum/BigNatTestLib.i.dfy ================================================ include "BigNatBitCount.i.dfy" include "BigNatMod.i.dfy" include "../Util/seqs_reverse.i.dfy" include "BigNumBEAdaptor.i.dfy" static method FakeBigNat(digit:nat, count:nat) returns (F:BigNat) requires Word32(digit); requires 1 F.words[i]==digit; { var s := RepeatDigit_impl(digit, count); ghost var rs := Reverse(s); F := BigNat_ctor(s); lemma_BigNatIIsLEDigitSeqToInt(F); lemma_Reverse_symmetry(rs, F.words); lemma_Reverse(rs, F.words); lemma_Reverse_converts_endianness(Width(), rs, F.words); calc { I(F); LEDigitSeqToInt(Width(), F.words); BEDigitSeqToInt_premium(Width(), rs); } lemma_BEDigitSeqToInt_bound(Width(), rs); lemma_2toX32(); calc { 32 * count; < { lemma_mul_strict_inequality_forall(); lemma_mul_is_commutative_forall(); } 32 * power2(25); power2(5)*power2(25); { lemma_power2_adds(5,25); } power2(30); } calc { I(F); BEDigitSeqToInt(Width(), rs); < power(Width(), |rs|); power(power2(32), |rs|); { lemma_power2_is_power_2(32); } power(power(2,32), |rs|); { lemma_power_multiplies(2,32,|rs|); } power(2,32*|rs|); { lemma_power2_is_power_2(32 * |rs|); } power2(32 * |rs|); power2(32 * count); < { lemma_power2_strictly_increases(32 * count, power2(30)); } power2(power2(30)); Frump(); } lemma_2toX(); lemma_power_1(Width()); lemma_power_increases(Width(), 1, |rs|-1); calc { 1; < power(Width(), |rs|-1); <= { lemma_mul_increases(rs[0], power(Width(), |rs|-1)); } rs[0] * power(Width(), |rs|-1); <= BEDigitSeqToInt(Width(), rs); I(F); } } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/BigNum/BigNatX86Shim.i.dfy ================================================ include "Word32.i.dfy" include "../../Drivers/CPU/assembly_premium.i.dfy" include "../Util/seqs_and_ints.i.dfy" static method Add32_two_arguments_ordered(a:nat, b:nat) returns (sum:nat, carry:nat) requires Word32(a); requires Word32(b); requires a<=b; ensures Word32(sum); ensures carry==0 || carry==1; ensures a+b == sum + 0x100000000 * carry; { lemma_2toX(); lemma_word32(a); lemma_word32(b); lemma_mod0x100000000(a + b); sum := asm_Add(a, b); carry := if sum < b then 1 else 0; /* lemma_2toX(); lemma_word32(a); lemma_word32(b); lemma_mod_properties(); lemma_mod0x100000000(a+b); lemma_mod_is_mod_boogie(a+b, Width()); lemma_mul_is_commutative_forall(); var tsum := asm_Add(a, b); carry := if tsum < b then 1 else 0; if (a+b < Width()) { calc { tsum; (a+b) % Width(); a+b; >= b; } assert carry == 0; lemma_small_div(); assert (a+b)/Width() == carry; } else { lemma_mod_properties(); assert tsum < a+b; assert tsum < b; assert carry == 1; lemma_div_basics(Width()); lemma_div_is_ordered(Width(), a+b, Width()); assert 0 < (a+b)/Width(); if (2 <= (a+b)/Width()) { var L2 := 2; calc { 2*Width(); { lemma_mul_is_mul_boogie(L2, Width()); } L2*Width(); <= { lemma_mul_inequality(2, (a+b)/Width(), Width()); } ((a+b)/Width())*Width(); <= { lemma_fundamental_div_mod(a+b, Width()); } a+b; < { lemma_mul_strict_inequality_forall(); } Width() + Width(); } assert false; } assert (a+b)/Width() < 2; assert (a+b)/Width() == carry; } calc { a+b; { lemma_fundamental_div_mod(a+b, Width()); } Width() * ((a+b)/Width()) + (a+b)%Width(); Width() * ((a+b)/Width()) + tsum; Width() * carry + tsum; tsum + carry * Width(); } sum := tsum; */ } static method Add32_two_arguments(a:nat, b:nat) returns (sum:nat, carry:nat) requires Word32(a); requires Word32(b); ensures Word32(sum); ensures carry==0 || carry==1; ensures a+b == sum + 0x100000000 * carry; { if (a<=b) { sum,carry := Add32_two_arguments_ordered(a, b); } else { sum,carry := Add32_two_arguments_ordered(b, a); } } static method Add32_with_carry(a:nat, b:nat, c:nat) returns (sum:nat, carry:nat) requires Word32(a); requires Word32(b); requires c==0 || c==1; ensures Word32(sum); ensures carry==0 || carry==1; ensures a+b+c == sum + carry * Width(); { lemma_2toX(); lemma_word32(a); lemma_word32(b); //- lemma_mul_basics_forall(); var psum,pcarry; if (a<=b) { psum,pcarry := Add32_two_arguments(a,b); } else { psum,pcarry := Add32_two_arguments(b,a); } var qsum,qcarry := Add32_two_arguments(c, psum); /* assert a+b == psum + pcarry * Width(); assert c == -psum + qsum + qcarry * Width(); assert a+b+c == pcarry * Width() + qsum + qcarry * Width(); calc { pcarry * Width() + qcarry * Width(); { lemma_mul_is_distributive_forall(); } (pcarry + qcarry) * Width(); } assert a+b+c == (pcarry + qcarry) * Width() + qsum; assert 0 <= pcarry <= 1; assert 0 <= qcarry <= 1; */ sum := qsum; var zcarry; carry,zcarry := Add32_two_arguments(pcarry, qcarry); lemma_mul_is_mul_boogie(carry, 0x100000000); /* if (zcarry > 0) { calc { Width(); <= { lemma_mul_increases(zcarry, Width()); } zcarry * Width(); <= carry + zcarry * Width(); pcarry + qcarry; <= 2; } } assert zcarry == 0; lemma_mul_basics(zcarry); */ } static method Sub32_two_arguments(a:nat, b:nat) returns (difference:nat, carry:nat) requires Word32(a); requires Word32(b); ensures Word32(difference); ensures carry==0 || carry==1; ensures a-b == difference - 0x100000000 * carry; { lemma_2toX(); lemma_word32(a); lemma_word32(b); //- lemma_mod_properties(); lemma_mod0x100000000(a-b); //- lemma_mod_is_mod_boogie(a-b, Width()); //- lemma_mul_is_commutative_forall(); difference := asm_Sub(a, b); carry := if a>=b then 0 else 1; } static method Sub32_with_borrow(a:nat, b:nat, c:nat) returns (difference:nat, carry:nat) requires Word32(a); requires Word32(b); requires c==0 || c==1; ensures Word32(difference); ensures carry==0 || carry==1; ensures a-b-c == difference - carry * Width(); { lemma_2toX(); //- lemma_mul_is_distributive_forall(); //- lemma_mul_basics_forall(); var pdiff, pcarry, qcarry; pdiff, pcarry := Sub32_two_arguments(a,b); difference, qcarry := Sub32_two_arguments(pdiff, c); carry := if (pcarry == 1 || qcarry == 1) then 1 else 0; assert carry == pcarry + qcarry; lemma_mul_is_mul_boogie(carry, 0x100000000); } static method Product32(a:nat, b:nat) returns (l:nat, h:nat) requires Word32(a); requires Word32(b); ensures Word32(l); ensures Word32(h); ensures l+(h*Width()) == a*b; { lemma_2toX(); lemma_word32_Word32(); var hi,lo := asm_Mul64(a,b); ghost var ab := a*b; calc { a*b; ab; { lemma_fundamental_div_mod(ab, 0x100000000); } 0x100000000 * (ab / 0x100000000) + ab % 0x100000000; { lemma_mod0x100000000(ab); } 0x100000000 * (ab / 0x100000000) + mod0x100000000(ab); 0x100000000 * (ab / 0x100000000) + mod0x100000000(a*b); 0x100000000 * (ab / 0x100000000) + lo; 0x100000000 * ((a*b) / 0x100000000) + lo; { lemma_mul_is_commutative_forall(); } ((a*b) / 0x100000000) * 0x100000000 + lo; hi * 0x100000000 + lo; hi * Width() + lo; } l := lo; h := hi; } static lemma lemma_small_division(n:nat, d:nat) requires Word32(n); requires Word32(d); requires 0 < d; ensures (n / d) % 0x100000000 == n / d; { lemma_2toX(); if d == 1 { } else if n == 0 { lemma_div_of_0(d); assert 0 / d == 0; assert 0 % 0x100000000 == 0; } else { calc < { n / d; { lemma_div_decreases(n, d); } n; power2(32); } calc <= { 0; { lemma_div_pos_is_pos(n, d); } n / d; } { lemma_small_mod(n / d, 0x100000000); } } } static method Divide32(n:nat, d:nat) returns (q:nat, r:nat) requires Word32(n); requires Word32(d); requires 0 < d; ensures Word32(q); ensures Word32(r); ensures 0<=r { r == n % d; { lemma_mod_properties(); } 0 <= r < d; } } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/BigNum/BigNum.i.dfy ================================================ include "BigNatDiv.i.dfy" datatype BigNum = BigNum_ctor( negate : bool, value : BigNat); static function WellformedBigNum(A:BigNum) : bool { WellformedBigNat(A.value) //- disallow redundant zero (-0) && (zero(A.value) ==> !A.negate) } static function BV(A:BigNum) : int requires WellformedBigNum(A); ensures (BV(A) < 0) <==> A.negate; { if (A.negate) then -I(A.value) else I(A.value) } static function method BigNumNegate(A:BigNum) : BigNum requires WellformedBigNum(A); ensures WellformedBigNum(BigNumNegate(A)); ensures BV(BigNumNegate(A)) == -BV(A); { if (zero(A.value)) then A else BigNum_ctor(!A.negate, A.value) } static method BigNumAddSameSign(A:BigNum, B:BigNum) returns (R:BigNum) requires A.negate == B.negate; requires WellformedBigNum(A); requires WellformedBigNum(B); ensures WellformedBigNum(R); ensures BV(A)+BV(B) == BV(R); { var value:BigNat := BigNatAdd(A.value, B.value); assert I(value) == I(A.value) + I(B.value); R := BigNum_ctor(A.negate, value); if (A.negate) { assert B.negate; calc { BV(R); -I(R.value); -(I(A.value)+I(B.value)); -I(A.value)-I(B.value); BV(A)+BV(B); } } else { assert !B.negate; calc { BV(R); I(R.value); I(A.value)+I(B.value); BV(A)+BV(B); } } } static method BigNumSubPos(A:BigNum, B:BigNum) returns (R:BigNum) requires !A.negate && !B.negate; requires WellformedBigNum(A); requires WellformedBigNum(B); ensures WellformedBigNum(R); ensures BV(A)-BV(B) == BV(R); { //- A - B ==> this is the interesting case var negate:bool := BigNatLt(A.value,B.value); if (negate) { assert I(B.value) > I(A.value); var value:BigNat := BigNatSub(B.value, A.value); R := BigNum_ctor(negate, value); calc { BV(R); -I(value); -(I(B.value)-I(A.value)); I(A.value)-I(B.value); BV(A) - BV(B); } } else { assert I(B.value) <= I(A.value); var value:BigNat := BigNatSub(A.value, B.value); R := BigNum_ctor(negate, value); calc { BV(R); I(value); I(A.value)-I(B.value); BV(A) - BV(B); } } } static method BigNumAdd(A:BigNum, B:BigNum) returns (R:BigNum) requires WellformedBigNum(A); requires WellformedBigNum(B); ensures WellformedBigNum(R); ensures BV(A)+BV(B) == BV(R); { if (A.negate == B.negate) { R := BigNumAddSameSign(A, B); } else if (A.negate) { assert !B.negate; R := BigNumSubPos(B,BigNumNegate(A)); calc { BV(R); BV(B) - BV(BigNumNegate(A)); BV(B) - (-BV(A)); BV(B) + BV(A); BV(A) + BV(B); } } else { //- A - B R := BigNumSubPos(A,BigNumNegate(B)); calc { BV(R); BV(A)-BV(BigNumNegate(B)); BV(A)-(-BV(B)); BV(A)+BV(B); } } } static method BigNumSub(A:BigNum, B:BigNum) returns (R:BigNum) requires WellformedBigNum(A); requires WellformedBigNum(B); ensures WellformedBigNum(R); ensures BV(A)-BV(B) == BV(R); { if (B.negate) { //- -A - -B == -A + B //- A - -B == A + B R := BigNumAdd(A, BigNumNegate(B)); calc { BV(R); BV(A) + BV(BigNumNegate(B)); BV(A) + -BV(B); BV(A) - BV(B); } } else if (A.negate) { assert !B.negate; //- -A - B == - (A + B) var value:BigNat := BigNatAdd(A.value, B.value); R := BigNum_ctor(true, value); calc { BV(R); -I(value); -(I(A.value) + I(B.value)); -I(A.value) - I(B.value); BV(A) - BV(B); } } else { R := BigNumSubPos(A, B); } } static method BigNumCmp(A:BigNum, B:BigNum) returns (c:BNCmp) requires WellformedBigNum(A); requires WellformedBigNum(B); ensures (c==BNCmpLt) <==> (BV(A) < BV(B)); ensures (c==BNCmpEq) <==> (BV(A) == BV(B)); ensures (c==BNCmpGt) <==> (BV(A) > BV(B)); { if (A.negate) { if (!B.negate) { //- -A, B c := BNCmpLt; assert BV(A) < 0 <= BV(B); } else { //- -A,-B var nc := BigNatCmp(A.value,B.value); if (nc.BNCmpEq?) { c := BNCmpEq; assert BV(A)==-I(A.value)==-I(B.value)==BV(B); } else if (nc.BNCmpLt?) { c := BNCmpGt; assert BV(A)==-I(A.value) > -I(B.value)==BV(B); } else { c := BNCmpLt; assert BV(A)==-I(A.value) < -I(B.value)==BV(B); } } } else { if (B.negate) { //- A, -B c := BNCmpGt; assert BV(A) >= 0 > BV(B); } else { //- A, B c := BigNatCmp(A.value,B.value); if (c==BNCmpEq) { assert BV(A)==I(A.value)==I(B.value)==BV(B); } else if (c==BNCmpLt) { assert BV(A)==I(A.value)I(B.value)==BV(B); } } } } static method BigNumLt(A:BigNum, B:BigNum) returns (r:bool) requires WellformedBigNum(A); requires WellformedBigNum(B); ensures r <==> BV(A) BV(A)<=BV(B); { var c := BigNumCmp(A,B); r := c.BNCmpLt? || c.BNCmpEq?; } static method BigNumEq(A:BigNum, B:BigNum) returns (r:bool) requires WellformedBigNum(A); requires WellformedBigNum(B); ensures r <==> BV(A)==BV(B); { var c := BigNumCmp(A,B); r := c.BNCmpEq?; } static method BigNumGe(A:BigNum, B:BigNum) returns (r:bool) requires WellformedBigNum(A); requires WellformedBigNum(B); ensures r <==> BV(A)>=BV(B); { var c := BigNumCmp(A,B); r := c.BNCmpGt? || c.BNCmpEq?; } static method BigNumGt(A:BigNum, B:BigNum) returns (r:bool) requires WellformedBigNum(A); requires WellformedBigNum(B); ensures r <==> BV(A)>BV(B); { var c := BigNumCmp(A,B); r := c.BNCmpGt?; } method BigNumMul(A:BigNum, B:BigNum) returns (R:BigNum) requires WellformedBigNum(A); requires WellformedBigNum(B); ensures WellformedBigNum(R); ensures BV(A)*BV(B) == BV(R); { if ((A.negate && B.negate) || (!A.negate && !B.negate)) { var value:BigNat := BigNatMul(A.value, B.value); R := BigNum_ctor(false, value); if (A.negate) { calc { BV(R); I(value); I(A.value) * I(B.value); { lemma_mul_cancels_negatives(I(A.value), I(B.value)); } (-I(A.value)) * (-I(B.value)); BV(A) * BV(B); } } else { calc { BV(R); I(value); I(A.value) * I(B.value); BV(A) * BV(B); } } } else //- if ((!A.negate && B.negate) || (A.negate && !B.negate)) { if ((B.negate && zero(A.value)) || (A.negate && zero(B.value))) { R := BigNum_ctor(false, BigNatZero()); if (zero(A.value)) { assert I(A.value)==0; calc { BV(A) * BV(B); I(A.value) * -I(B.value); 0 * (-I(B.value)); { lemma_mul_basics_forall(); } 0; I(BigNatZero()); BV(R); } } else { assert I(B.value)==0; calc { BV(A) * BV(B); (-I(A.value)) * I(B.value); (-I(A.value)) * 0; { lemma_mul_basics_forall(); } 0; I(BigNatZero()); BV(R); } } } else { var value:BigNat := BigNatMul(A.value, B.value); R := BigNum_ctor(true, value); calc ==> { !zero(A.value) && !zero(B.value); I(A.value)!=0 && I(B.value)!=0; { lemma_mul_nonzero_forall(); } I(A.value)*I(B.value) != 0; I(value) != 0; !zero(value); WellformedBigNum(R); } if (A.negate) { calc { BV(R); -I(value); -(I(A.value) * I(B.value)); { lemma_mul_properties(); } (-I(A.value)) * I(B.value); BV(A) * BV(B); } } else { calc { BV(R); -I(value); -(I(A.value) * I(B.value)); { lemma_mul_properties(); } I(A.value) * (-(I(B.value))); BV(A) * BV(B); } } } } } static predicate ModestBigNumWords(A:BigNum) { WellformedBigNum(A) && ModestBigNatWords(A.value) } method BigNumDiv(N:BigNum, D:BigNum) returns (Q:BigNum, R:BigNum) requires WellformedBigNum(N); requires WellformedBigNum(D); requires nonzero(D.value); requires BV(D) >= 0; ensures WellformedBigNum(Q); ensures WellformedBigNum(R); ensures 0 <= BV(R) < BV(D); //- negative D inverts this condition. ensures BV(Q)*BV(D) + BV(R) == BV(N); ensures BV(N) / BV(D) == BV(Q); ensures BV(N) % BV(D) == BV(R); { //- if (D.negate) //- { //- var q:BigNat,r:BigNat := BigNatDiv(N, BigNumNegate(D)); //- Q := BigNum_ctor(true, q); //- R := BigNum_ctor(false, r); //- } var q:BigNat,r:BigNat := BigNatDivImmodest(N.value, D.value); if (N.negate && !zero(r)) { var one := MakeSmallLiteralBigNat(1); q := BigNatAdd(q, one); Q := BigNum_ctor(true, q); r := BigNatSub(D.value, r); R := BigNum_ctor(false, r); calc ==> { 0 <= I(r) < I(D.value); 0 <= BV(R) < BV(D); } calc ==> { (I(q)-1)*I(D.value) + (I(D.value) - I(r)) == I(N.value); { lemma_mul_is_distributive_forall(); } { lemma_mul_is_mul_boogie(1, I(D.value)); } I(q)*I(D.value) - I(D.value) + (I(D.value) - I(r)) == I(N.value); I(q)*I(D.value) - I(r) == I(N.value); { lemma_mul_unary_negation(I(q), I(D.value)); } (-I(q))*I(D.value) + I(r) == -I(N.value); BV(Q)*BV(D) + BV(R) == BV(N); } } else { if (N.negate && zero(q)) { calc { I(q)*I(D.value) + I(r) == I(N.value); { lemma_mul_is_mul_boogie(0, I(D.value)); } 0*I(D.value) + 0 == I(N.value); false; } } Q := BigNum_ctor(N.negate, q); R := BigNum_ctor(false, r); calc ==> { 0 <= I(r) < I(D.value); 0 <= BV(R) < BV(D); } if (N.negate) { calc ==> { I(q)*I(D.value) + I(r) == I(N.value); I(q)*I(D.value) == I(N.value); { lemma_mul_unary_negation(I(q), I(D.value)); } (-I(q))*I(D.value) == -I(N.value); BV(Q)*BV(D) == BV(N); BV(Q)*BV(D) + BV(R) == BV(N); } } else { calc ==> { I(q)*I(D.value) + I(r) == I(N.value); BV(Q)*BV(D) + BV(R) == BV(N); } } } lemma_fundamental_div_mod_converse(BV(N), BV(D), BV(Q), BV(R)); } static function method MakeSmallLiteralBigNum_def(x:nat) : BigNum requires x < Width(); ensures WellformedBigNum(MakeSmallLiteralBigNum_def(x)); { if (x==0) then BigNum_ctor(false, BigNat_ctor([])) else BigNum_ctor(false, BigNat_ctor([x])) } static lemma lemma_MakeSmallLiteralBigNum(x:nat) requires x < Width(); ensures BV(MakeSmallLiteralBigNum_def(x)) == x; { var R:BigNum := MakeSmallLiteralBigNum_def(x); assert WellformedBigNum(R); assert WellformedBigNat(R.value); if (x==0) { assert zero(R.value); assert BV(R) == 0; } else { assert R.value.words == [x]; calc { I(R.value); { reveal_I(); } I(BigNat_ctor(R.value.words[1..]))*Width()+R.value.words[0]; { assert R.value.words[1..] == []; } I(BigNat_ctor([]))*Width()+R.value.words[0]; { reveal_I(); lemma_mul_basics_forall(); } R.value.words[0]; x; } assert I(R.value) == x; assert BV(R) == x; } } static function method MakeSmallLiteralBigNum(x:nat) : BigNum requires x < Width(); ensures WellformedBigNum(MakeSmallLiteralBigNum(x)); ensures BV(MakeSmallLiteralBigNum(x))==x; { lemma_MakeSmallLiteralBigNum(x); MakeSmallLiteralBigNum_def(x) } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/BigNum/BigNumBEAdaptor.i.dfy ================================================ include "BigNatCore.i.dfy" include "../Util/seqs_transforms.i.dfy" include "../Util/seqs_reverse.i.dfy" //-//////////////////////////////////////////////////////////////////////////// //- Convert between "legacy" little-endian, well-formed-required BigNats //- and new-style BEIsByteSeq static predicate ZeroPrefix(s:seq, s_suffix:seq) { |s| >= |s_suffix| && s[ |s|-|s_suffix| .. ] == s_suffix && forall i :: 0 <= i < |s|-|s_suffix| ==> s[i] == 0 } //- Takes a string that may contain leading zeros. //- Returns a string with no leading zeros. static method StripLeadingZeros(ghost pv:int, ins:seq) returns (outs:seq) requires 10 ==> outs[0]!=0; { var ptr := 0; while (ptr<|ins| && ins[ptr]==0) invariant 0 <= ptr <= |ins|; invariant forall i :: 0 <= i < ptr ==> ins[i] == 0; { ptr := ptr + 1; } outs := ins[ptr..]; } static lemma lemma_BigNatIIsLEDigitSeqToInt(a:BigNat) requires WellformedBigNat(a); decreases |a.words|; ensures I(a) == LEDigitSeqToInt(Width(), a.words); { reveal_I(); reveal_LEDigitSeqToInt_private(); if (|a.words|>0) { lemma_BigNatIIsLEDigitSeqToInt(BigNat_ctor(a.words[1..])); } } static method BigNatToBEByteSeq(M:BigNat) returns (m:seq) requires WellformedBigNat(M); ensures IsByteSeq(m); ensures BEByteSeqToInt(m) == I(M); ensures BEIntToByteSeq(I(M)) == m; ensures |m|==0 || 0) returns (M:BigNat) requires IsByteSeq(m); ensures WellformedBigNat(M); ensures BEByteSeqToInt(m) == I(M); //- ensures BEIntToByteSeq(I(M)) == m; //- not available, unless we require no prefix 0s. { lemma_2toX(); var be_words:seq; ghost var pad_bytes:seq; be_words,pad_bytes := BEByteSeqToWordSeq_impl(m); var be_words_normalized := StripLeadingZeros(4294967296, be_words); //- assert |be_words_normalized|>0 ==> be_words_normalized[0]!=0; var le_words := ReverseDigitSeq(4294967296, be_words_normalized); lemma_Reverse(be_words_normalized, le_words); //- assert |le_words|>0 ==> le_words[|le_words|-1]!=0; M := BigNat_ctor(le_words); calc { I(M); { lemma_BigNatIIsLEDigitSeqToInt(M); } LEDigitSeqToInt(Width(), le_words); { lemma_Reverse_converts_endianness_inner(Width(), be_words_normalized, le_words); } BEDigitSeqToInt(Width(), be_words_normalized); { lemma_LeadingZeros(Width(), be_words_normalized, be_words); } BEDigitSeqToInt(Width(), be_words); BEDigitSeqToInt(power2(8), m); BEByteSeqToInt(m); } } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/BigNum/BigRat.i.dfy ================================================ //- include "BigNum.i.dfy" include "../Math/mul.i.dfy" datatype BigRat = BigRat_ctor( n : BigNum, d : BigNat); static function WellformedBigRat(Q:BigRat) : bool { WellformedBigNum(Q.n) && WellformedBigNat(Q.d) && !zero(Q.d) } static function RV(Q:BigRat) : real requires WellformedBigRat(Q); { real(BV(Q.n)) / real(I(Q.d)) } static function method BigRatNegate(Q:BigRat) : BigRat requires WellformedBigRat(Q); ensures WellformedBigRat(BigRatNegate(Q)); ensures RV(BigRatNegate(Q)) == 0.0 - RV(Q); { BigRat_ctor(BigNumNegate(Q.n), Q.d) } static lemma Lemma_BigRatAdd(an:int, ad:int, bn:int, bd:int) requires ad != 0; requires bd != 0; ensures real(ad * bd) != 0.0; ensures real(an * bd + bn * ad) / real(ad * bd) == real(an) / real(ad) + real(bn) / real(bd); { lemma_mul_nonzero(ad, bd); Lemma_RealOfMultiplyIsMultiply(an, bd); Lemma_RealOfMultiplyIsMultiply(ad, bd); Lemma_RealOfMultiplyIsMultiply(bn, ad); Lemma_RealOfMultiplyIsMultiply(bd, ad); } method BigRatAdd(A:BigRat, B:BigRat) returns (R:BigRat) requires WellformedBigRat(A); requires WellformedBigRat(B); ensures WellformedBigRat(R); ensures RV(R) == RV(A) + RV(B); { var ScaledANumerator:BigNum := BigNumMul(A.n, BigNum_ctor(false, B.d)); var ScaledBNumerator:BigNum := BigNumMul(B.n, BigNum_ctor(false, A.d)); var ResultNumerator:BigNum := BigNumAdd(ScaledANumerator, ScaledBNumerator); var ResultDenominator:BigNat := BigNatMul(A.d, B.d); lemma_mul_nonzero(I(A.d), I(B.d)); R := BigRat_ctor(ResultNumerator, ResultDenominator); Lemma_BigRatAdd(BV(A.n), I(A.d), BV(B.n), I(B.d)); } static lemma Lemma_BigRatSub(an:int, ad:int, bn:int, bd:int) requires ad != 0; requires bd != 0; ensures real(ad * bd) != 0.0; ensures real(an * bd - bn * ad) / real(ad * bd) == real(an) / real(ad) - real(bn) / real(bd); { lemma_mul_nonzero(ad, bd); Lemma_RealOfMultiplyIsMultiply(an, bd); Lemma_RealOfMultiplyIsMultiply(ad, bd); Lemma_RealOfMultiplyIsMultiply(bn, ad); Lemma_RealOfMultiplyIsMultiply(bd, ad); } method BigRatSub(A:BigRat, B:BigRat) returns (R:BigRat) requires WellformedBigRat(A); requires WellformedBigRat(B); ensures WellformedBigRat(R); ensures RV(R) == RV(A) - RV(B); { var ScaledANumerator:BigNum := BigNumMul(A.n, BigNum_ctor(false, B.d)); var ScaledBNumerator:BigNum := BigNumMul(B.n, BigNum_ctor(false, A.d)); var ResultNumerator:BigNum := BigNumSub(ScaledANumerator, ScaledBNumerator); var ResultDenominator:BigNat := BigNatMul(A.d, B.d); lemma_mul_nonzero(I(A.d), I(B.d)); R := BigRat_ctor(ResultNumerator, ResultDenominator); Lemma_BigRatSub(BV(A.n), I(A.d), BV(B.n), I(B.d)); calc { RV(R); real(BV(R.n)) / real(I(R.d)); real(BV(A.n)) / real(I(A.d)) - real(BV(B.n)) / real(I(B.d)); RV(A) - RV(B); } } method BigRatCmp(A:BigRat, B:BigRat) returns (c:BNCmp) requires WellformedBigRat(A); requires WellformedBigRat(B); ensures (c==BNCmpLt) <==> (RV(A) < RV(B)); ensures (c==BNCmpEq) <==> (RV(A) == RV(B)); ensures (c==BNCmpGt) <==> (RV(A) > RV(B)); { var ScaledANumerator:BigNum := BigNumMul(A.n, BigNum_ctor(false, B.d)); var ScaledBNumerator:BigNum := BigNumMul(B.n, BigNum_ctor(false, A.d)); c := BigNumCmp(ScaledANumerator, ScaledBNumerator); ghost var CommonDenominator:BigNat := BigNatMul(A.d, B.d); lemma_mul_nonzero(I(A.d), I(B.d)); ghost var ScaledA := BigRat_ctor(ScaledANumerator, CommonDenominator); ghost var ScaledB := BigRat_ctor(ScaledBNumerator, CommonDenominator); Lemma_ScalingPreservesValue(A, ScaledA, B.d); lemma_mul_is_commutative(I(A.d), I(B.d)); Lemma_ScalingPreservesValue(B, ScaledB, A.d); Lemma_DivideByPositiveRealPreservesOrder(real(BV(ScaledANumerator)), real(BV(ScaledBNumerator)), real(I(CommonDenominator))); } method BigRatLt(A:BigRat, B:BigRat) returns (r:bool) requires WellformedBigRat(A); requires WellformedBigRat(B); ensures r == (RV(A) < RV(B)); { var c := BigRatCmp(A,B); r := (c.BNCmpLt?); } method BigRatLe(A:BigRat, B:BigRat) returns (r:bool) requires WellformedBigRat(A); requires WellformedBigRat(B); ensures r == (RV(A) <= RV(B)); { var c := BigRatCmp(A,B); r := (c.BNCmpLt? || c.BNCmpEq?); } method BigRatEq(A:BigRat, B:BigRat) returns (r:bool) requires WellformedBigRat(A); requires WellformedBigRat(B); ensures r == (RV(A) == RV(B)); { var c := BigRatCmp(A,B); r := (c.BNCmpEq?); } method BigRatNe(A:BigRat, B:BigRat) returns (r:bool) requires WellformedBigRat(A); requires WellformedBigRat(B); ensures r == (RV(A) != RV(B)); { var c := BigRatCmp(A,B); r := !(c.BNCmpEq?); } method BigRatGe(A:BigRat, B:BigRat) returns (r:bool) requires WellformedBigRat(A); requires WellformedBigRat(B); ensures r == (RV(A) >= RV(B)); { var c := BigRatCmp(A,B); r := (c.BNCmpGt? || c.BNCmpEq?); } method BigRatGt(A:BigRat, B:BigRat) returns (r:bool) requires WellformedBigRat(A); requires WellformedBigRat(B); ensures r == (RV(A) > RV(B)); { var c := BigRatCmp(A,B); r := (c.BNCmpGt?); } method BigRatMul(A:BigRat, B:BigRat) returns (R:BigRat) requires WellformedBigRat(A); requires WellformedBigRat(B); ensures WellformedBigRat(R); ensures RV(R) == RV(A) * RV(B); { var ResultNumerator:BigNum := BigNumMul(A.n, B.n); var ResultDenominator:BigNat := BigNatMul(A.d, B.d); lemma_mul_nonzero(I(A.d), I(B.d)); R := BigRat_ctor(ResultNumerator, ResultDenominator); Lemma_RealOfMultiplyIsMultiply(BV(A.n), BV(B.n)); Lemma_RealOfMultiplyIsMultiply(I(A.d), I(B.d)); assert !zero(R.d); } method BigRatDiv(A:BigRat, B:BigRat) returns (R:BigRat) requires WellformedBigRat(A); requires WellformedBigRat(B); requires nonzero(B.n.value); ensures WellformedBigRat(R); ensures RV(R) == RV(A) / RV(B); { if (zero(A.n.value)) { R := BigRat_ctor(MakeSmallLiteralBigNum(0), MakeSmallLiteralBigNat(1)); assert RV(R) == real(0) == RV(A) / RV(B); return; } var ResultNegative:bool := (A.n.negate != B.n.negate); var ResultNumerator:BigNum := BigNumMul(BigNum_ctor(ResultNegative, A.n.value), BigNum_ctor(false, B.d)); var ResultDenominator:BigNat := BigNatMul(B.n.value, A.d); lemma_mul_nonzero(I(B.n.value), I(A.d)); R := BigRat_ctor(ResultNumerator, ResultDenominator); Lemma_RealOfMultiplyIsMultiply(BV(BigNum_ctor(ResultNegative, A.n.value)), BV(BigNum_ctor(false, B.d))); Lemma_RealOfMultiplyIsMultiply(I(B.n.value), I(A.d)); assert I(ResultDenominator) == I(B.n.value) * I(A.d); calc { RV(R); real(BV(ResultNumerator)) / real(I(ResultDenominator)); real(BV(ResultNumerator)) / real(I(B.n.value) * I(A.d)); } } static function method MakeSmallLiteralBigRat(x:nat) : BigRat requires x < Width(); ensures WellformedBigRat(MakeSmallLiteralBigRat(x)); ensures RV(MakeSmallLiteralBigRat(x)) == real(x); { lemma_2toX(); BigRat_ctor(MakeSmallLiteralBigNum(x), MakeSmallLiteralBigNat(1)) } static function method BigNatToBigRat(x:BigNat) : BigRat requires WellformedBigNat(x); ensures WellformedBigRat(BigNatToBigRat(x)); ensures RV(BigNatToBigRat(x)) == real(I(x)); { lemma_2toX(); BigRat_ctor(BigNum_ctor(false, x), MakeSmallLiteralBigNat(1)) } //-///////////////////////////////// //- Useful mathematical lemmas //-///////////////////////////////// static lemma Lemma_RealOfMultiplyIsMultiply(a:int, b:int) ensures real(a * b) == real(a) * real(b); { lemma_mul_is_mul_boogie(a, b); } static lemma Lemma_ScalingPreservesValue(A:BigRat, ScaledA:BigRat, scale:BigNat) requires WellformedBigRat(A); requires WellformedBigRat(ScaledA); requires WellformedBigNat(scale); requires nonzero(scale); requires BV(ScaledA.n) == BV(A.n) * I(scale); requires I(ScaledA.d) == I(A.d) * I(scale); ensures RV(A) == RV(ScaledA); { Lemma_RealOfMultiplyIsMultiply(BV(A.n), I(scale)); Lemma_RealOfMultiplyIsMultiply(I(A.d), I(scale)); } static lemma Lemma_DivideByPositiveRealPreservesOrder(a:real, b:real, c:real) requires c > 0.0; ensures a < b <==> a/c < b/c; ensures a == b <==> a/c == b/c; ensures a > b <==> a/c > b/c; { } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/BigNum/Word32.i.dfy ================================================ //-include "../Util/assembly_deprecated.s.dfy" include "../Math/power2.i.dfy" //-static function Word(w:nat, x:nat) : bool //-{ //- 0 <= x < power2(w) //-} static function Width() : int ensures 0 < Width(); { power2(32) } //-static function Word32(x: nat): bool //- ensures Word32(x) <==> (x static lemma lemma_SHA256_DigestInfo_properties() ensures IsByteSeq(SHA256_DigestInfo()); ensures |SHA256_DigestInfo()|==19; { lemma_2toX(); } static function SHA256_DigestInfo_premium() : seq ensures IsByteSeq(SHA256_DigestInfo()); ensures |SHA256_DigestInfo()|==19; { lemma_2toX(); SHA256_DigestInfo() } static lemma lemma_SHA256_preserves_type(msg:seq) requires IsBitSeq(msg); requires |msg| < power2(64); ensures IsWordSeq(SHA256(msg)); { //- lemma_BitSeqToBoolSeq_ensures(msg); } static predicate SHA256_BytesRequires(msg_bytes:seq) { IsByteSeq(msg_bytes) && IsBitSeq(BEByteSeqToBitSeq(msg_bytes)) && |BEByteSeqToBitSeq(msg_bytes)| < power2(64) && IsWordSeq(SHA256(BEByteSeqToBitSeq(msg_bytes))) } static lemma lemma_SHA256_Bytes_preserves_IsByteSeq(msg:seq) requires IsByteSeq(msg); requires |msg| < power2(61); requires SHA256_BytesRequires(msg); ensures IsByteSeq(SHA256_Bytes(msg)); { lemma_BEByteSeqToBitSeq_ensures(msg); assert IsBitSeq(BEByteSeqToBitSeq(msg)); calc { |BEByteSeqToBitSeq(msg)|; |msg|*8; < power2(61)*8; { lemma_2to64(); lemma_power2_add8(56); } power2(64); } lemma_SHA256_preserves_type(BEByteSeqToBitSeq(msg)); lemma_BEWordSeqToByteSeq_ensures(SHA256(BEByteSeqToBitSeq(msg))); } //-static lemma lemma_SHA256Digest_properties(msg:seq) //- requires IsByteSeq(msg); //- requires |msg| < power2(60); //- ensures SHA256_BytesRequires(msg); //- ensures IsByteSeq(SHA256Digest(msg)); //- ensures |SHA256Digest(msg)|==32; //-{ //- lemma_2toX(); //- lemma_SHA256_DigestInfo_properties(); //- lemma_concat_preserves_IsByteSeq(SHA256_DigestInfo(), msg); //- calc { //- |SHA256_DigestInfo() + msg|; //- |SHA256_DigestInfo()|+|msg|; //- < 19+power2(60); //- <= { lemma_2to64(); lemma_power2_add8(56); } //- power2(61); //- } //- assert IsBitSeq(BEByteSeqToBitSeq_premium(SHA256_DigestInfo() + msg)); //- lemma_SHA256_Bytes_preserves_IsByteSeq(SHA256_DigestInfo() + msg); //- //- calc { //- |SHA256Digest(msg)|; //- |SHA256_Bytes(SHA256_DigestInfo() + msg)|; //- |BEWordSeqToByteSeq(SHA256(BEByteSeqToBitSeq(SHA256_DigestInfo() + msg)))|; //- } //- assert |SHA256(BEByteSeqToBitSeq(SHA256_DigestInfo() + msg))| == 8; //- lemma_BEWordSeqToByteSeq_ensures(SHA256(BEByteSeqToBitSeq(SHA256_DigestInfo() + msg))); //- assert |BEWordSeqToByteSeq(SHA256(BEByteSeqToBitSeq(SHA256_DigestInfo() + msg)))| == 4*8; //-} static lemma lemma_SHA256Digest_premium(msg:seq) requires IsByteSeq(msg); requires |msg|) : seq requires IsByteSeq(msg); requires |msg|) returns (digest:seq) requires IsByteSeq(msg); requires |msg| < power2(29); ensures IsByteSeq(digest); ensures |msg| < power2(61); ensures digest == SHA256Digest_premium(msg); ensures |digest| == 51; { lemma_2toX32(); lemma_power2_increases(29, 61); lemma_power2_increases(32, 64); var msg_digest_words := SHA256_impl_Bytes(msg); var msg_digest_bytes := BEWordSeqToByteSeq_impl(msg_digest_words); digest := SHA256_DigestInfo() + msg_digest_bytes; } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Crypto/Hash/Digest.s.dfy ================================================ include "../../Util/integer_sequences.s.dfy" include "../Hash/sha256.s.dfy" static function {:autoReq} SHA256_Bytes(msg_bytes:seq) : seq { BEWordSeqToByteSeq(SHA256(BEByteSeqToBitSeq(msg_bytes))) } //- http://www.ietf.org/rfc/rfc3447.txt //- (Note that https://tools.ietf.org/html/rfc5754 is a different //- thing, for SMIMECapability.) static function method {:autoReq} SHA256_DigestInfo() : seq { [ 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20 ] } static function {:autoReq} SHA256Digest(msg:seq) : seq { SHA256_DigestInfo() + SHA256_Bytes(msg) } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Crypto/Hash/hmac_common.i.dfy ================================================ include "hmac_common.s.dfy" include "../../../Drivers/CPU/assembly_premium.i.dfy" include "../../Util/integer_sequences_premium.i.dfy" include "sha_padding.i.dfy" //-/////////////////////////////////////////////////// //- ConstPad lemmas //-/////////////////////////////////////////////////// static lemma lemma_ConstPad_properties(len:int, const:int) requires len >= 0; requires Mod32_const(len) == 0; requires Word32(const); ensures IsBitSeq(ConstPad(len, const)); ensures |ConstPad(len, const)| == len; ensures ConstPad(len, const) == if len <= 0 then [] else BEWordToBitSeq(const) + ConstPad(len - 32, const); { reveal_ConstPad(); if len == 0 { } else { reveal_Mod32_const(); lemma_ConstPad_properties(len - 32, const); assert BEWordToBitSeq_premium(const) == BEWordToBitSeq(const); } } static function ConstPad_premium(len:int, const:int) : seq requires len >= 0; requires Mod32_const(len) == 0; requires Word32(const); ensures IsBitSeq(ConstPad_premium(len, const)); ensures |ConstPad_premium(len, const)| == len; ensures ConstPad_premium(len, const) == if len <= 0 then [] else BEWordToBitSeq(const) + ConstPad(len - 32, const); { lemma_ConstPad_properties(len, const); ConstPad(len, const) } static function Ipad_premium(len:int) : seq requires len >= 0; requires Mod32_const(len) == 0; ensures IsBitSeq(Ipad_premium(len)); ensures |Ipad_premium(len)| == len; { lemma_2toX(); lemma_ConstPad_properties(len, 0x36363636); Ipad(len) } static function Opad_premium(len:int) : seq requires len >= 0; requires Mod32_const(len) == 0; ensures IsBitSeq(Opad_premium(len)); ensures |Opad_premium(len)| == len; { lemma_2toX(); lemma_ConstPad_properties(len, 0x5c5c5c5c); Opad(len) } //-/////////////////////////////////////////////////// //- SeqXor lemmas //-/////////////////////////////////////////////////// static lemma{:dafnycc_conservative_seq_triggers} lemma_SeqXor_properties(a: seq, b: seq) requires IsBitSeq(a); requires IsBitSeq(b); requires |a|==|b|; ensures |SeqXor(a, b)| == |a|; ensures forall i :: 0 <= i < |a| ==> SeqXor(a, b)[i] == Xor(a[i], b[i]); { reveal_SeqXor(); if |a| != 0 { lemma_SeqXor_properties(a[1..], b[1..]); } } static function SeqXor_premium(a: seq, b: seq) : seq requires IsBitSeq(a); requires IsBitSeq(b); requires |a|==|b|; ensures |SeqXor_premium(a, b)| == |a|; ensures forall i {:trigger a[i]}{:trigger b[i]}{:trigger SeqXor_premium(a, b)[i]} :: 0 <= i < |a| ==> SeqXor_premium(a, b)[i] == Xor(a[i], b[i]); { lemma_SeqXor_properties(a, b); SeqXor(a, b) } static lemma{:dafnycc_conservative_seq_triggers} lemma_SeqXor_Split(a: seq, A: seq, b: seq, B: seq) requires IsBitSeq(a) && IsBitSeq(b) && IsBitSeq(A) && IsBitSeq(B); requires |a| == |b| && |A| == |B|; ensures SeqXor_premium(a + A, b + B) == SeqXor_premium(a, b) + SeqXor_premium(A, B); { if a == [] { assert a + A == A; assert b + B == B; } else { calc { SeqXor(a + A, b + B); { reveal_SeqXor(); } { assert a + A == [a[0]] + (a[1..] + A); assert b + B == [b[0]] + (b[1..] + B); } [Xor(a[0], b[0])] + SeqXor(a[1..] + A, b[1..]+B); { lemma_SeqXor_Split(a[1..], A, b[1..], B); } [Xor(a[0], b[0])] + SeqXor(a[1..], b[1..]) + SeqXor(A, B); { reveal_SeqXor(); } SeqXor(a, b) + SeqXor(A, B); } } } static lemma lemma_mul_mod_32(x:int, y:int) requires x == 32 * y; ensures x % 32 == 0; { } static lemma lemma_SeqXor_WordSeqToBitSeq(i:int, pad:seq, key:seq, const:int) requires |pad| == |key| == i; requires Word32(const); requires forall j {:trigger pad[j]}{:trigger key[j]} :: 0 <= j < |pad| ==> Word32(pad[j]) && Word32(key[j]); requires forall j {:trigger pad[j]}{:trigger key[j]} :: 0 <= j < |pad| ==> pad[j] == Asm_BitwiseXor(key[j], const); ensures Mod32_const(i*32) == 0; ensures BEWordSeqToBitSeq_premium(pad) == SeqXor(BEWordSeqToBitSeq_premium(key), ConstPad_premium(i*32, const)); { calc { Mod32_const(i*32); { lemma_Mod32_const(i*32); } 0; } if i == 0 { reveal_SeqXor(); assert BEWordSeqToBitSeq_premium(pad) == SeqXor(BEWordSeqToBitSeq_premium(key), ConstPad_premium(i*32, const)); } else { var len0 := i * 32; var len1 := (i - 1) * 32; ghost var x := SeqXor_premium(BEWordToBitSeq_premium(key[0]), BEWordToBitSeq_premium(const)); lemma_mul_mod_32(len0, i); calc { Mod32_const(len0); { reveal_Mod32_const(); } 0; } calc { SeqXor_premium(BEWordSeqToBitSeq_premium(key), ConstPad_premium(len0, const)); { lemma_WordSeqToBitSeqChopHead(key); } SeqXor_premium(BEWordToBitSeq_premium(key[0]) + BEWordSeqToBitSeq_premium(key[1..]), ConstPad_premium(len0, const)); { reveal_Mod32_const(); } SeqXor_premium(BEWordToBitSeq_premium(key[0]) + BEWordSeqToBitSeq_premium(key[1..]), BEWordToBitSeq_premium(const) + ConstPad_premium(len1, const)); { assert len1 % 32 == 0; } { assert |ConstPad_premium(len1, const)| == len1; } { lemma_SeqXor_Split(BEWordToBitSeq_premium(key[0]), BEWordSeqToBitSeq_premium(key[1..]), BEWordToBitSeq_premium(const), ConstPad_premium(len1, const)); } SeqXor_premium(BEWordToBitSeq_premium(key[0]), BEWordToBitSeq_premium(const)) + SeqXor_premium(BEWordSeqToBitSeq_premium(key[1..]), ConstPad_premium(len1, const)); x + SeqXor_premium(BEWordSeqToBitSeq_premium(key[1..]), ConstPad_premium(len1, const)); { assert |pad[1..]| == |key[1..]| == i - 1; } { lemma_SeqXor_WordSeqToBitSeq(i - 1, pad[1..], key[1..], const); } { assert BEWordSeqToBitSeq_premium(pad[1..]) == SeqXor_premium(BEWordSeqToBitSeq_premium(key[1..]), ConstPad_premium(len1, const)); } x + BEWordSeqToBitSeq_premium(pad[1..]); SeqXor_premium(BEWordToBitSeq_premium(key[0]), BEWordToBitSeq_premium(const)) + BEWordSeqToBitSeq_premium(pad[1..]); { lemma_SeqXor_properties(BEWordToBitSeq_premium(key[0]), BEWordToBitSeq_premium(const)); } { assert forall j :: 0 <= j < |BEWordToBitSeq_premium(key[0])| ==> SeqXor_premium(BEWordToBitSeq_premium(key[0]), BEWordToBitSeq_premium(const))[j] == BEWordToBitSeq_premium(Asm_BitwiseXor(key[0], const))[j]; } BEWordToBitSeq_premium(Asm_BitwiseXor(key[0], const)) + BEWordSeqToBitSeq_premium(pad[1..]); BEWordToBitSeq_premium(pad[0]) + BEWordSeqToBitSeq_premium(pad[1..]); { lemma_WordSeqToBitSeqChopHead(pad); } BEWordSeqToBitSeq_premium(pad); } } } //-/////////////////////////////////////////////////// //- HMAC //-/////////////////////////////////////////////////// static method xor_pad(key:array, const:int) returns (pad:array) requires key != null && key.Length == 16; requires forall i {:trigger key[i]} :: 0 <= i < key.Length ==> Word32(key[i]); requires Word32(const); ensures fresh(pad); ensures forall i {:trigger pad[i]} :: 0 <= i < pad.Length ==> Word32(pad[i]); ensures pad.Length == 16; ensures Mod32_const(512) == 0; ensures BEWordSeqToBitSeq_premium(pad[..]) == SeqXor(BEWordSeqToBitSeq_premium(key[..]), ConstPad_premium(512, const)); { pad := new int[16]; var i := 0; while (i < 16) invariant 0 <= i <= 16; invariant forall j {:trigger pad[j]} :: 0 <= j < i ==> Word32(pad[j]); invariant forall j {:trigger pad[j]}{:trigger key[j]} :: 0 <= j < i ==> pad[j] == Asm_BitwiseXor(key[j], const); { pad[i] := Asm_BitwiseXor(key[i], const); i := i + 1; } lemma_SeqXor_WordSeqToBitSeq(16, pad[..], key[..], const); calc { Mod32_const(512); { reveal_Mod32_const(); } 0; } } static lemma lemma_padded_length_32(x:int, y:int) requires x >= 0 && y >= 0; requires PaddedLength(32*x) / 32 == y; ensures y * 32 == PaddedLength(32*x); { reveal_NumPaddingZeroes(); reveal_PaddedLength(); calc { y * 32; (PaddedLength(32*x) / 32) * 32; ((32*x + 1 + NumPaddingZeroes(32*x) + 64) / 32) * 32; ((32*x + 1 + ((959 - (32*x) % 512) % 512) + 64) / 32) * 32; 32*x + 1 + ((959 - (32*x) % 512) % 512) + 64; PaddedLength(32*x); } } static method {:timeLimitMultiplier 4} consolidate_arrays(a:array, b:array) returns (c:array) requires a != null && b != null; requires forall i {:trigger a[i]} :: 0 <= i < a.Length ==> Word32(a[i]); requires forall i {:trigger b[i]} :: 0 <= i < b.Length ==> Word32(b[i]); ensures fresh(c); ensures forall i {:trigger c[i]} :: 0 <= i < c.Length ==> Word32(c[i]); ensures c.Length * 32 == PaddedLength(32*(a.Length+b.Length)); ensures c.Length >= a.Length + b.Length; ensures c[..a.Length+b.Length] == a[..] + b[..]; ensures a[..] == old(a[..]); ensures b[..] == old(b[..]); { calc { true; { reveal_PaddedLength(); } 0 <= a.Length + b.Length <= PaddedLength(32*(a.Length+b.Length))/ 32; } c := new int[PaddedLength(32*(a.Length+b.Length))/ 32]; assert c.Length >= a.Length + b.Length; var i := 0; while (i < a.Length) invariant 0 <= i <= a.Length; invariant forall j :: 0 <= j < a.Length ==> Word32(a[j]); invariant forall j :: 0 <= j < i ==> c[j] == a[j] && Word32(c[j]); invariant a[..] == old(a[..]); invariant b[..] == old(b[..]); { c[i] := a[i]; i := i+1; } var k := 0; while (k < b.Length) invariant 0 <= k <= b.Length; invariant i == k + a.Length; invariant a.Length <= i <= a.Length + b.Length; invariant forall j :: 0 <= j < a.Length ==> c[j] == a[j] && Word32(c[j]); invariant forall j :: 0 <= j < k ==> c[j+a.Length] == b[j]; //- invariant forall j :: a.Length <= j < a.Length + k ==> c[j] == b[j-a.Length]; invariant forall j :: a.Length <= j < a.Length + k ==> Word32(c[j]); invariant a[..] == old(a[..]); invariant b[..] == old(b[..]); { c[i] := b[k]; i := i + 1; k := k + 1; } while (i < c.Length) invariant a.Length + b.Length <= i <= c.Length; invariant forall j :: 0 <= j < a.Length ==> c[j] == a[j] && Word32(c[j]); invariant forall j :: a.Length <= j < a.Length + b.Length ==> c[j] == b[j-a.Length] && Word32(c[j]); invariant forall j :: a.Length + b.Length <= j < i ==> Word32(c[j]); invariant a[..] == old(a[..]); invariant b[..] == old(b[..]); { lemma_2toX(); c[i] := 0; i := i + 1; } assert forall j :: 0 <= j < a.Length ==> c[..a.Length + b.Length][j] == a[j]; assert forall j :: a.Length <= j < a.Length + b.Length ==> c[..a.Length + b.Length][j] == b[j - a.Length] && Word32(c[j]); lemma_padded_length_32(a.Length+b.Length, c.Length); } static method HMAC_outer_input(key: array, inner_hash: array) returns (input: array) requires IsWordArray(key); requires key.Length == 16; requires IsWordArray(inner_hash); ensures fresh(input); ensures IsWordArray(input); ensures input.Length * 32 == PaddedLength(32*(16+inner_hash.Length)); ensures 16+inner_hash.Length <= input.Length; ensures Mod32_const(|key[..]|*32) == 0; ensures BEWordSeqToBitSeq_premium(input[..]) == SeqXor(BEWordSeqToBitSeq_premium(key[..]), Opad_premium(|key[..]|*32)) + BEWordSeqToBitSeq_premium(inner_hash[..]) + BEWordSeqToBitSeq_premium(input[16+inner_hash.Length..]); { ghost var old_key := key[..]; lemma_2toX(); var opad := xor_pad(key, 0x5c5c5c5c); assert old_key == key[..]; ghost var old_opad := opad[..]; input := consolidate_arrays(opad, inner_hash); assert key[..] == old_key; assert opad[..] == old_opad; ghost var sum := opad.Length + inner_hash.Length; calc { BEWordSeqToBitSeq_premium(input[..]); { lemma_WordSeqToBitSeqChop(input[..], input[..sum], input[sum..]); } BEWordSeqToBitSeq_premium(input[..sum]) + BEWordSeqToBitSeq_premium(input[sum..]); BEWordSeqToBitSeq_premium(opad[..] + inner_hash[..]) + BEWordSeqToBitSeq_premium(input[sum..]); { lemma_WordSeqToBitSeqChop(opad[..] + inner_hash[..], opad[..], inner_hash[..]); } BEWordSeqToBitSeq_premium(opad[..]) + BEWordSeqToBitSeq_premium(inner_hash[..]) + BEWordSeqToBitSeq_premium(input[sum..]); { reveal_Mod32_const(); } SeqXor(BEWordSeqToBitSeq_premium(key[..]), Opad(|key[..]|*32)) + BEWordSeqToBitSeq_premium(inner_hash[..]) + BEWordSeqToBitSeq_premium(input[sum..]); } } static lemma lemma_HMAC_inner_input1(key: array, data: array, input:array, ipad:array) requires key != null; requires data != null; requires input != null; requires ipad != null; requires forall i {:trigger key[i]} :: 0 <= i < key.Length ==> Word32(key[i]); requires forall i {:trigger data[i]} :: 0 <= i < data.Length ==> Word32(data[i]); requires forall i {:trigger input[i]} :: 0 <= i < input.Length ==> Word32(input[i]); requires forall i {:trigger ipad[i]} :: 0 <= i < ipad.Length ==> Word32(ipad[i]); requires ipad.Length + data.Length <= input.Length; requires input[..(ipad.Length + data.Length)] == ipad[..] + data[..]; requires Mod32_const(|key[..]|*32) == 0; requires |BEWordSeqToBitSeq_premium(key[..])| == |Ipad_premium(|key[..]|*32)|; requires BEWordSeqToBitSeq_premium(ipad[..]) == SeqXor_premium(BEWordSeqToBitSeq_premium(key[..]), Ipad_premium(|key[..]|*32)); ensures BEWordSeqToBitSeq_premium(input[..]) == SeqXor_premium(BEWordSeqToBitSeq_premium(key[..]), Ipad_premium(|key[..]|*32)) + BEWordSeqToBitSeq_premium(data[..]) + BEWordSeqToBitSeq_premium(input[(ipad.Length + data.Length)..]); { ghost var sum := ipad.Length + data.Length; calc { BEWordSeqToBitSeq_premium(input[..]); { lemma_WordSeqToBitSeqChop(input[..], input[..sum], input[sum..]); } BEWordSeqToBitSeq_premium(input[..sum]) + BEWordSeqToBitSeq_premium(input[sum..]); BEWordSeqToBitSeq_premium(ipad[..] + data[..]) + BEWordSeqToBitSeq_premium(input[sum..]); { lemma_WordSeqToBitSeqChop(ipad[..] + data[..], ipad[..], data[..]); } BEWordSeqToBitSeq_premium(ipad[..]) + BEWordSeqToBitSeq_premium(data[..]) + BEWordSeqToBitSeq_premium(input[sum..]); { reveal_Mod32_const(); } SeqXor_premium(BEWordSeqToBitSeq_premium(key[..]), Ipad_premium(|key[..]|*32)) + BEWordSeqToBitSeq_premium(data[..]) + BEWordSeqToBitSeq_premium(input[sum..]); } } static lemma lemma_HMAC_inner_input2(len:int, dataLength32:int, inputLength32:int) requires inputLength32 == PaddedLength(512 + dataLength32); requires 0 <= len <= dataLength32; ensures len + 512 <= PaddedLength(len + 512) <= inputLength32; { reveal_PaddedLength(); reveal_NumPaddingZeroes(); lemma_PaddedLengthMonotonic(len+512, 512+dataLength32); } static method HMAC_inner_input(key: array, data: array, len: int) returns (input: array) requires Word32(len); requires key != null && key.Length == 16; requires forall i {:trigger key[i]} :: 0 <= i < key.Length ==> Word32(key[i]); requires data != null; requires 0 <= len <= data.Length * 32; requires forall i {:trigger data[i]} :: 0 <= i < data.Length ==> Word32(data[i]); ensures fresh(input); ensures forall i {:trigger input[i]} :: 0 <= i < input.Length ==> Word32(input[i]); ensures len + 512 <= PaddedLength(len + 512) <= input.Length * 32; ensures input.Length >= 16 + data.Length; ensures Mod32_const(|key[..]|*32) == 0; ensures BEWordSeqToBitSeq_premium(input[..]) == SeqXor_premium(BEWordSeqToBitSeq_premium(key[..]), Ipad_premium(|key[..]|*32)) + BEWordSeqToBitSeq_premium(data[..]) + BEWordSeqToBitSeq_premium(input[16+data.Length..]); { ghost var old_key := key[..]; lemma_2toX(); var ipad := xor_pad(key, 0x36363636); assert old_key == key[..]; ghost var old_ipad := ipad[..]; input := consolidate_arrays(ipad, data); assert key[..] == old_key; assert ipad[..] == old_ipad; reveal_Mod32_const(); lemma_HMAC_inner_input1(key, data, input, ipad); lemma_HMAC_inner_input2(len, data.Length * 32, input.Length * 32); } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Crypto/Hash/hmac_common.s.dfy ================================================ include "../../Util/be_sequences.s.dfy" //-//////////////////////////////////////////////////////////////////////////// //- HMAC specification based on: //- http://csrc.nist.gov/publications/fips/fips198-1/FIPS-198-1_final.pdf //-//////////////////////////////////////////////////////////////////////////// static function Xor(a:int, b:int) : int { if a!=b then 1 else 0 } static function{:opaque} SeqXor(a: seq, b: seq) : seq requires IsBitSeq(a); requires IsBitSeq(b); requires |a|==|b|; { if |a| == 0 then [] else [ Xor(a[0], b[0]) ] + SeqXor(a[1..], b[1..]) } static function {:autoReq} {:opaque} ConstPad(len:int, const:int) : seq //- requires len % 32 == 0; { if len <= 0 then [] else BEWordToBitSeq(const) + ConstPad(len - 32, const) } static function {:autoReq} Opad(len:int) : seq { ConstPad(len, 0x5c5c5c5c) } static function {:autoReq} Ipad(len:int) : seq { ConstPad(len, 0x36363636) } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Crypto/Hash/sha1.i.dfy ================================================ include "sha1.s.dfy" include "../../Util/seq_blocking.i.dfy" include "../../Util/arrays_and_seqs.i.dfy" include "../../Util/integer_sequences_premium.i.dfy" include "sha_padding.i.dfy" include "sha_common.i.dfy" static function method{:CompiledSpec} CompiledSpec_K_SHA1(n: int) : int static function method{:CompiledSpec} CompiledSpec_InitialH_SHA1(index: int) : int //-/////////////////////////////////////////////////// //- Utility functions for AtoE //-/////////////////////////////////////////////////// static predicate Word32AtoE(v:atoe_Type) { Word32(v.a) && Word32(v.b) && Word32(v.c) && Word32(v.d) && Word32(v.e) } static predicate IsAtoEWordSeq(vs:seq) { forall i :: 0 <= i < |vs| ==> Word32AtoE(vs[i]) } static function ConvertAtoEToSeq_premium(v:atoe_Type) : seq requires Word32AtoE(v); ensures IsWordSeqOfLen(ConvertAtoEToSeq_premium(v), 5); ensures ConvertAtoEToSeq_premium(v) == ConvertAtoEToSeq(v); { ConvertAtoEToSeq(v) } static predicate{:opaque} TheAtoEsAreOK(z:SHA1Trace, blk: int, t: int) requires 0 <= t <= 79; requires 0 <= blk; requires |z.atoe| > blk; requires |z.atoe[blk]| > t+1; requires Word32AtoE(z.atoe[blk][t]); requires |z.W| > blk; requires IsWordSeqOfLen(z.W[blk], 80); { var T := Add32(Add32(Add32(Add32(Asm_RotateLeft(z.atoe[blk][t].a, 5), ft(t, z.atoe[blk][t].b, z.atoe[blk][t].c, z.atoe[blk][t].d)), z.atoe[blk][t].e), K_SHA1(t)), z.W[blk][t]); z.atoe[blk][t+1].e == z.atoe[blk][t].d && z.atoe[blk][t+1].d == z.atoe[blk][t].c && z.atoe[blk][t+1].c == Asm_RotateLeft(z.atoe[blk][t].b, 30) && z.atoe[blk][t+1].b == z.atoe[blk][t].a && z.atoe[blk][t+1].a == T } static lemma Lemma_TheAtoEsAreOKIsStable(z1:SHA1Trace, z2:SHA1Trace, blk: int, t: int) requires 0 <= t <= 79; requires 0 <= blk; requires |z1.atoe| == |z2.atoe| > blk; requires |z1.atoe[blk]| > t+1; requires |z2.atoe[blk]| > t+1; requires Word32AtoE(z1.atoe[blk][t]); requires z1.atoe[blk][t+1] == z2.atoe[blk][t+1]; requires z1.atoe[blk][t] == z2.atoe[blk][t]; requires |z1.W| > blk; requires z1.W == z2.W; requires IsWordSeqOfLen(z1.W[blk], 80); requires TheAtoEsAreOK(z1, blk, t); ensures TheAtoEsAreOK(z2, blk, t); { reveal_TheAtoEsAreOK(); } //-/////////////////////////////////////////////////// //- Initialization of data structures //-/////////////////////////////////////////////////// static method InitH_SHA1(H:array) requires H != null && H.Length == 5; ensures forall i :: 0 <= i < H.Length ==> H[i] == InitialH_SHA1(i); modifies H; { reveal_InitialH_SHA1(); H[0] := 0x67452301; H[1] := 0xefcdab89; H[2] := 0x98badcfe; H[3] := 0x10325476; H[4] := 0xc3d2e1f0; } static method InitK_SHA1(Ks: array) requires Ks != null && Ks.Length == 80; ensures forall i :: 0 <= i < Ks.Length ==> Ks[i] == K_SHA1(i); modifies Ks; { reveal_InitialH_SHA1(); reveal_K_SHA1(); var i := 0; while i < 80 invariant 0 <= i <= 80; invariant forall j :: 0 <= j < i ==> Ks[j] == K_SHA1(j); { if 0 <= i <= 19 { Ks[i] := 0x5a827999; } else if 20 <= i <= 39 { Ks[i] := 0x6ed9eba1; } else if 40 <= i <= 59 { Ks[i] := 0x8f1bbcdc; } else { Ks[i] := 0xca62c1d6; } i := i + 1; } } //-/////////////////////////////////////////////////// //- Partial SHA1 traces //-/////////////////////////////////////////////////// static predicate PartialSHA1TraceHasCorrectHs(z:SHA1Trace) { |z.H| > 0 && |z.H| <= |z.atoe|+1 && (forall blk :: 0 <= blk < |z.H| ==> IsWordSeqOfLen(z.H[blk], 5)) && (forall j :: 0 <= j < 5 ==> z.H[0][j] == InitialH_SHA1(j)) && (forall blk {:trigger TBlk(blk)} :: TBlk(blk) && 0 <= blk < |z.H|-1 ==> IsAtoEWordSeqOfLen(z.atoe[blk], 81) && forall j :: 0 <= j < 5 ==> z.H[blk+1][j] == Add32(ConvertAtoEToSeq(z.atoe[blk][80])[j], z.H[blk][j])) } static predicate PartialSHA1TraceHasCorrectWs(z:SHA1Trace) { |z.W| <= |z.M| && forall blk :: 0 <= blk < |z.W| ==> IsWordSeqOfLen(z.W[blk], 80) && IsWordSeqOfLen(z.M[blk], 16) && forall t {:trigger TStep(t)} :: TStep(t) && 0 <= t < 80 ==> (0 <= t <= 15 ==> z.W[blk][t] == z.M[blk][t]) && (16 <= t <= 79 ==> z.W[blk][t] == Asm_RotateLeft(Asm_BitwiseXor(Asm_BitwiseXor(Asm_BitwiseXor(z.W[blk][t-3], z.W[blk][t-8]), z.W[blk][t-14]), z.W[blk][t-16]), 1)) } static predicate PartialSHA1TraceHasCorrectatoesWf(z:SHA1Trace) { |z.atoe| <= |z.H| && |z.atoe| <= |z.W| && (forall blk :: 0 <= blk < |z.atoe|-1 ==> IsAtoEWordSeqOfLen(z.atoe[blk], 81)) && forall blk :: 0 <= blk < |z.atoe| ==> |z.atoe[blk]| <= 81 && IsWordSeqOfLen(z.W[blk], 80) && IsAtoEWordSeq(z.atoe[blk]) && (|z.atoe[blk]| > 0 ==> IsWordSeqOfLen(z.H[blk], 5) && ConvertAtoEToSeq(z.atoe[blk][0]) == z.H[blk]) } static predicate{:opaque} PartialSHA1TraceHasCorrectatoesOpaque(z:SHA1Trace) { |z.atoe| <= |z.H| && |z.atoe| <= |z.W| && (forall blk :: 0 <= blk < |z.atoe|-1 ==> IsAtoEWordSeqOfLen(z.atoe[blk], 81)) && forall blk :: 0 <= blk < |z.atoe| ==> |z.atoe[blk]| <= 81 && IsWordSeqOfLen(z.W[blk], 80) && IsAtoEWordSeq(z.atoe[blk]) && (|z.atoe[blk]| > 0 ==> IsWordSeqOfLen(z.H[blk], 5) && ConvertAtoEToSeq(z.atoe[blk][0]) == z.H[blk]) && forall t {:trigger TStep(t)} :: TStep(t) && 0 <= t < |z.atoe[blk]|-1 ==> var T := Add32(Add32(Add32(Add32(Asm_RotateLeft(z.atoe[blk][t].a, 5), ft(t, z.atoe[blk][t].b, z.atoe[blk][t].c, z.atoe[blk][t].d)), z.atoe[blk][t].e), K_SHA1(t)), z.W[blk][t]); z.atoe[blk][t+1].e == z.atoe[blk][t].d && z.atoe[blk][t+1].d == z.atoe[blk][t].c && z.atoe[blk][t+1].c == Asm_RotateLeft(z.atoe[blk][t].b, 30) && z.atoe[blk][t+1].b == z.atoe[blk][t].a && z.atoe[blk][t+1].a == T } static predicate PartialSHA1TraceHasCorrectatoes(z:SHA1Trace) { PartialSHA1TraceHasCorrectatoesWf(z) && PartialSHA1TraceHasCorrectatoesOpaque(z) } static predicate PartialSHA1TraceIsCorrect(z:SHA1Trace) { PartialSHA1TraceHasCorrectWs(z) && PartialSHA1TraceHasCorrectHs(z) && PartialSHA1TraceHasCorrectatoes(z) } static lemma PartialSHA1TraceIsCorrectImpliesTraceIsCorrect(z:SHA1Trace) requires IsCompleteSHA1Trace(z); requires PartialSHA1TraceIsCorrect(z); ensures SHA1TraceIsCorrect(z); { reveal_PartialSHA1TraceHasCorrectatoesOpaque(); } //-/////////////////////////////////////////////////// //- Intermediate SHA1 state //-/////////////////////////////////////////////////// datatype SHA1_state = SHA1_state_c(M:seq, H:seq, W:seq, Ks:seq, atoe:atoe_Type, num_blocks:int); static function SHA1_vars_to_state(M:array, words:int, H:array, W:array, Ks:array, atoe:atoe_Type, num_blocks:int) : SHA1_state requires M != null && H != null && W != null && Ks != null; requires 0 <= words <= M.Length; reads M, H, W, Ks; { SHA1_state_c(M[..words], H[..], W[..], Ks[..], atoe, num_blocks) } static predicate AreSHA1TraceAndStateOK(z:SHA1Trace, s:SHA1_state) { PartialSHA1TraceIsCorrect(z) && IsWordSeq(s.M) && z.M == BreakIntoBlocks(s.M, 16) && (forall i :: 0 <= i < |z.M| ==> IsWordSeqOfLen(z.M[i], 16)) && Mul16(|z.M|) == |s.M| && |z.M| == s.num_blocks && |s.Ks| == 80 && (forall t :: 0 <= t <= 79 ==> s.Ks[t] == K_SHA1(t)) } static predicate IsSHA1ReadyForBlock(z:SHA1Trace, s:SHA1_state, nextBlock:int) requires 0 <= nextBlock; { AreSHA1TraceAndStateOK(z, s) && |z.H| == nextBlock + 1 && |z.W| == nextBlock && |z.atoe| == nextBlock && (forall blk :: 0 <= blk < nextBlock ==> IsAtoEWordSeqOfLen(z.atoe[blk], 81)) && s.H == z.H[nextBlock] } static predicate IsSHA1DoneComputingWs(z:SHA1Trace, s:SHA1_state, currentBlock:int) requires 0 <= currentBlock; { AreSHA1TraceAndStateOK(z, s) && |z.H| == currentBlock + 1 && |z.W| == currentBlock + 1 && |z.atoe| == currentBlock && (forall blk :: 0 <= blk < currentBlock ==> IsAtoEWordSeqOfLen(z.atoe[blk], 81)) && s.H == z.H[currentBlock] && s.W == z.W[currentBlock] } static predicate IsSHA1ReadyForStep(z:SHA1Trace, s:SHA1_state, currentBlock:int, nextStep:int) requires 0 <= currentBlock; requires 0 <= nextStep <= 80; { AreSHA1TraceAndStateOK(z, s) && |z.H| == currentBlock + 1 && |z.W| == currentBlock + 1 && |z.atoe| == currentBlock + 1 && (forall blk :: 0 <= blk < currentBlock ==> IsAtoEWordSeqOfLen(z.atoe[blk], 81)) && IsAtoEWordSeqOfLen(z.atoe[currentBlock], nextStep+1) && s.H == z.H[currentBlock] && s.W == z.W[currentBlock] && s.atoe == z.atoe[currentBlock][nextStep] } ///////////////////////////////////////////////////// ///////////////////////////////////////////////////// static lemma {:timeLimitMultiplier 3} lemma_SHA1TransitionOKAfterSettingHsStep1(z1:SHA1Trace, s1:SHA1_state, z2:SHA1Trace, s2:SHA1_state, currentBlock:int) requires 0 <= currentBlock; requires IsSHA1ReadyForStep(z1, s1, currentBlock, 80); requires s2.M == s1.M; requires IsWordSeqOfLen(s2.H, 5); requires forall j :: 0 <= j < 5 ==> s2.H[j] == Add32(ConvertAtoEToSeq_premium(s1.atoe)[j], s1.H[j]); requires s2.Ks == s1.Ks; requires s2.num_blocks == s1.num_blocks; requires z2 == SHA1Trace_c(z1.M, z1.H + [s2.H], z1.W, z1.atoe); ensures forall blk :: 0 <= blk < |z2.H| ==> IsWordSeqOfLen(z2.H[blk], 5); ensures forall blk {:trigger TBlk(blk)} :: TBlk(blk) && 0 <= blk < currentBlock + 1 ==> IsAtoEWordSeqOfLen(z2.atoe[blk], 81) && forall j :: 0 <= j < 5 ==> z2.H[blk+1][j] == Add32(ConvertAtoEToSeq_premium(z2.atoe[blk][80])[j], z2.H[blk][j]); { assert |z2.H| == currentBlock + 2; forall blk | 0 <= blk < |z2.H| ensures IsWordSeqOfLen(z2.H[blk], 5); { if (blk == |z2.H|-1) { assert z2.H[blk] == s2.H; } else { assert z2.H[blk] == z1.H[blk]; } } assert forall blk {:trigger TBlk(blk)} :: TBlk(blk) && 0 <= blk < currentBlock + 1 ==> IsWordSeqOfLen(z2.H[blk+1], 5); forall blk {:trigger TBlk(blk)} | TBlk(blk) && 0 <= blk < currentBlock + 1 ensures IsAtoEWordSeqOfLen(z2.atoe[blk], 81); ensures forall j :: 0 <= j < 5 ==> z2.H[blk+1][j] == Add32(ConvertAtoEToSeq_premium(z2.atoe[blk][80])[j], z2.H[blk][j]); { assert z2.atoe[blk] == z1.atoe[blk]; if blk == currentBlock { assert IsSHA1ReadyForStep(z1, s1, currentBlock, 80); assert IsAtoEWordSeqOfLen(z1.atoe[currentBlock], 80+1); assert IsAtoEWordSeqOfLen(z1.atoe[blk], 81); calc { true ==> forall j :: 0 <= j < 5 ==> s2.H[j] == Add32(ConvertAtoEToSeq_premium(s1.atoe)[j], s1.H[j]); ==> { assert z2.H[blk+1] == s2.H; } forall j :: 0 <= j < 5 ==> z2.H[blk+1][j] == Add32(ConvertAtoEToSeq_premium(s1.atoe)[j], s1.H[j]); ==> { assert z2.atoe[blk][80] == s1.atoe; } forall j :: 0 <= j < 5 ==> z2.H[blk+1][j] == Add32(ConvertAtoEToSeq_premium(z2.atoe[blk][80])[j], s1.H[j]); ==> { assert z2.H[blk] == s1.H; } forall j :: 0 <= j < 5 ==> z2.H[blk+1][j] == Add32(ConvertAtoEToSeq_premium(z2.atoe[blk][80])[j], z2.H[blk][j]); } } } } static lemma {:timeLimitMultiplier 3} lemma_SHA1TransitionOKAfterSettingHs(z1:SHA1Trace, s1:SHA1_state, z2:SHA1Trace, s2:SHA1_state, currentBlock:int) requires 0 <= currentBlock; requires IsSHA1ReadyForStep(z1, s1, currentBlock, 80); requires s2.M == s1.M; requires IsWordSeqOfLen(s2.H, 5); requires forall j :: 0 <= j < 5 ==> s2.H[j] == Add32(ConvertAtoEToSeq_premium(s1.atoe)[j], s1.H[j]); requires s2.Ks == s1.Ks; requires s2.num_blocks == s1.num_blocks; requires z2 == SHA1Trace_c(z1.M, z1.H + [s2.H], z1.W, z1.atoe); ensures IsSHA1ReadyForBlock(z2, s2, currentBlock+1); { lemma_SHA1TransitionOKAfterSettingHsStep1(z1, s1, z2, s2, currentBlock); reveal_PartialSHA1TraceHasCorrectatoesOpaque(); } static lemma lemma_EarlierWsAreWords(W:seq) requires IsWordSeqOfLen(W, 80); ensures forall t {:trigger TStep(t)} :: TStep(t) && 0 <= t < |W| ==> (16 <= t <= 79 ==> Word32(W[t-3]) && Word32(W[t-8]) && Word32(W[t-14]) && Word32(W[t-16])); { } static lemma lemma_SHA1TransitionOKAfterSettingWs(z1:SHA1Trace, s1:SHA1_state, z2:SHA1Trace, s2:SHA1_state, currentBlock:int) requires 0 <= currentBlock < |z1.M|; requires IsSHA1ReadyForBlock(z1, s1, currentBlock); requires IsWordSeqOfLen(s2.W, 80); requires forall t {:trigger TStep(t)} :: TStep(t) && 0 <= t <= 15 ==> s2.W[t] == z1.M[currentBlock][t]; requires forall t {:trigger TStep(t)} :: TStep(t) && 16 <= t <= 79 ==> s2.W[t] == Asm_RotateLeft(Asm_BitwiseXor(Asm_BitwiseXor(Asm_BitwiseXor(s2.W[t-3], s2.W[t-8]), s2.W[t-14]), s2.W[t-16]), 1); requires z2 == SHA1Trace_c(z1.M, z1.H, z1.W + [s2.W], z1.atoe); requires s2.M == s1.M; requires s2.H == s1.H; requires s2.Ks == s1.Ks; requires s2.num_blocks == s1.num_blocks; ensures IsSHA1DoneComputingWs(z2, s2, currentBlock); { assert z2.M == z1.M; assert z2.H == z1.H; assert |z2.W| == |z1.W| + 1; assert forall blk :: 0 <= blk < |z1.W| ==> z2.W[blk] == z1.W[blk]; assert z2.W[|z1.W|] == s2.W; assert z2.atoe == z1.atoe; forall blk | 0 <= blk < |z2.W| ensures IsWordSeqOfLen(z2.W[blk], 80); ensures forall t {:trigger TStep(t)} :: TStep(t) && 0 <= t < |z2.W[blk]| ==> (16 <= t <= 79 ==> Word32(z2.W[blk][t-3]) && Word32(z2.W[blk][t-8]) && Word32(z2.W[blk][t-14]) && Word32(z2.W[blk][t-16])); ensures forall t {:trigger TStep(t)} :: TStep(t) && 0 <= t < |z2.W[blk]| ==> (0 <= t <= 15 ==> z2.W[blk][t] == z2.M[blk][t]) && (16 <= t <= 79 ==> z2.W[blk][t] == Asm_RotateLeft(Asm_BitwiseXor(Asm_BitwiseXor(Asm_BitwiseXor(z2.W[blk][t-3], z2.W[blk][t-8]), z2.W[blk][t-14]), z2.W[blk][t-16]), 1)); { if blk < |z2.W|-1 { assert IsWordSeqOfLen(z2.W[blk], 80); lemma_EarlierWsAreWords(z2.W[blk]); assert forall t {:trigger TStep(t)} :: TStep(t) && 0 <= t < |z2.W[blk]| ==> (0 <= t <= 15 ==> z2.W[blk][t] == z2.M[blk][t]) && (16 <= t <= 79 ==> z2.W[blk][t] == Asm_RotateLeft(Asm_BitwiseXor(Asm_BitwiseXor(Asm_BitwiseXor(z2.W[blk][t-3], z2.W[blk][t-8]), z2.W[blk][t-14]), z2.W[blk][t-16]), 1)); } else { assert blk == |z2.W|-1; assert z2.W[blk] == s2.W; lemma_EarlierWsAreWords(z2.W[blk]); assert forall t {:trigger TStep(t)} :: TStep(t) && 0 <= t < |z2.W[blk]| ==> (0 <= t <= 15 ==> z2.W[blk][t] == z2.M[blk][t]) && (16 <= t <= 79 ==> z2.W[blk][t] == Asm_RotateLeft(Asm_BitwiseXor(Asm_BitwiseXor(Asm_BitwiseXor(z2.W[blk][t-3], z2.W[blk][t-8]), z2.W[blk][t-14]), z2.W[blk][t-16]), 1)); } } reveal_PartialSHA1TraceHasCorrectatoesOpaque(); } static lemma lemma_SHA1TransitionOKAfterSettingAtoEStep1Helper1(z:SHA1Trace, blk:int, t:int) requires 0 <= t <= 79; requires 0 <= blk; requires |z.atoe| > blk; requires |z.atoe[blk]| > t+1; requires Word32AtoE(z.atoe[blk][t]); requires |z.W| > blk; requires IsWordSeqOfLen(z.W[blk], 80); requires PartialSHA1TraceHasCorrectatoes(z); ensures TheAtoEsAreOK(z, blk, t); { assert TBlk(blk) && TStep(t); reveal_TheAtoEsAreOK(); reveal_PartialSHA1TraceHasCorrectatoesOpaque(); } static lemma lemma_SHA1TransitionOKAfterSettingAtoEStep1(z1:SHA1Trace, s1:SHA1_state, z2:SHA1Trace, s2:SHA1_state, currentBlock:int, currentStep:int) requires TBlk(currentBlock) && TBlk(currentBlock + 1) && TStep(currentStep) && TStep(currentStep + 1); requires 0 <= currentBlock < |z1.M|; requires 0 <= currentStep <= 79; requires IsSHA1ReadyForStep(z1, s1, currentBlock, currentStep); requires var T := Add32(Add32(Add32(Add32(Asm_RotateLeft(s1.atoe.a, 5), ft(currentStep, s1.atoe.b, s1.atoe.c, s1.atoe.d)), s1.atoe.e), s1.Ks[currentStep]), s1.W[currentStep]); s2.atoe.e == s1.atoe.d && s2.atoe.d == s1.atoe.c && s2.atoe.c == Asm_RotateLeft(s1.atoe.b, 30) && s2.atoe.b == s1.atoe.a && s2.atoe.a == T; requires s2.M == s1.M; requires s2.H == s1.H; requires s2.W == s1.W; requires s2.Ks == s1.Ks; requires s2.num_blocks == s1.num_blocks; requires z2.M == z1.M && z2.H == z1.H && z2.W == z1.W; requires z2.atoe == z1.atoe[..currentBlock] + [z1.atoe[currentBlock] + [s2.atoe]]; requires |z2.atoe| == |z1.atoe|; requires forall blk :: 0 <= blk < currentBlock ==> z2.atoe[blk] == z1.atoe[blk]; requires forall t :: 0 <= t < |z1.atoe[currentBlock]| ==> z2.atoe[currentBlock][t] == z1.atoe[currentBlock][t]; requires z2.atoe[currentBlock][|z1.atoe[currentBlock]|] == s2.atoe; ensures forall blk :: 0 <= blk < |z2.atoe| ==> |z2.atoe[blk]| <= |z2.W[blk]| + 1 && |z2.atoe[blk]| <= 81 && IsWordSeq(z2.W[blk]) && IsAtoEWordSeq(z2.atoe[blk]) && (|z2.atoe[blk]| > 0 ==> IsWordSeqOfLen(z2.H[blk], 5) && ConvertAtoEToSeq(z2.atoe[blk][0]) == z2.H[blk]) && (forall t :: 0 <= t < |z2.atoe[blk]|-1 ==> TheAtoEsAreOK(z2, blk, t)); { forall blk {:trigger TBlk(blk)} | TBlk(blk) && 0 <= blk < |z2.atoe| ensures |z2.atoe[blk]| <= |z2.W[blk]| + 1; ensures |z2.atoe[blk]| <= 81; ensures IsWordSeq(z2.W[blk]); ensures IsAtoEWordSeq(z2.atoe[blk]); ensures (|z2.atoe[blk]| > 0 ==> IsWordSeqOfLen(z2.H[blk], 5) && ConvertAtoEToSeq(z2.atoe[blk][0]) == z2.H[blk]); ensures forall t :: 0 <= t < |z2.atoe[blk]|-1 ==> TheAtoEsAreOK(z2, blk, t); { assert |z2.atoe[blk]| <= |z2.W[blk]| + 1; assert |z2.atoe[blk]| <= 81; assert IsWordSeq(z2.W[blk]); assert IsAtoEWordSeq(z2.atoe[blk]); if blk < |z2.atoe|-1 { assert blk < currentBlock; assert z2.atoe[blk] == z1.atoe[blk]; assert (|z2.atoe[blk]| > 0 ==> IsWordSeqOfLen(z2.H[blk], 5) && ConvertAtoEToSeq(z2.atoe[blk][0]) == z2.H[blk]); forall t | 0 <= t < |z1.atoe[blk]|-1 ensures TheAtoEsAreOK(z2, blk, t); { lemma_SHA1TransitionOKAfterSettingAtoEStep1Helper1(z1, blk, t); Lemma_TheAtoEsAreOKIsStable(z1, z2, blk, t); } assert forall t :: 0 <= t < |z2.atoe[blk]|-1 ==> TheAtoEsAreOK(z2, blk, t); } else { assert blk == currentBlock; assert (|z2.atoe[blk]| > 0 ==> IsWordSeqOfLen(z2.H[blk], 5) && ConvertAtoEToSeq(z2.atoe[blk][0]) == z2.H[blk]); forall t | 0 <= t < |z2.atoe[blk]|-1 ensures TheAtoEsAreOK(z2, blk, t); { if t < |z2.atoe[blk]|-2 { assert t < currentStep; lemma_SHA1TransitionOKAfterSettingAtoEStep1Helper1(z1, blk, t); Lemma_TheAtoEsAreOKIsStable(z1, z2, blk, t); } else { assert t == currentStep; calc { true; { reveal_TheAtoEsAreOK(); } TheAtoEsAreOK(z2, blk, t); } } } } } } static lemma lemma_SHA1TransitionOKAfterSettingAtoE(z1:SHA1Trace, s1:SHA1_state, z2:SHA1Trace, s2:SHA1_state, currentBlock:int, currentStep:int) requires TBlk(currentBlock) && TBlk(currentBlock + 1) && TStep(currentStep) && TStep(currentStep + 1); requires 0 <= currentBlock < |z1.M|; requires 0 <= currentStep <= 79; requires IsSHA1ReadyForStep(z1, s1, currentBlock, currentStep); requires var T := Add32(Add32(Add32(Add32(Asm_RotateLeft(s1.atoe.a, 5), ft(currentStep, s1.atoe.b, s1.atoe.c, s1.atoe.d)), s1.atoe.e), s1.Ks[currentStep]), s1.W[currentStep]); s2.atoe.e == s1.atoe.d && s2.atoe.d == s1.atoe.c && s2.atoe.c == Asm_RotateLeft(s1.atoe.b, 30) && s2.atoe.b == s1.atoe.a && s2.atoe.a == T; requires s2.M == s1.M; requires s2.H == s1.H; requires s2.W == s1.W; requires s2.Ks == s1.Ks; requires s2.num_blocks == s1.num_blocks; requires z2 == SHA1Trace_c(z1.M, z1.H, z1.W, z1.atoe[..currentBlock] + [z1.atoe[currentBlock] + [s2.atoe]]); ensures IsSHA1ReadyForStep(z2, s2, currentBlock, currentStep+1); { lemma_SHA1TransitionOKAfterSettingAtoEStep1(z1, s1, z2, s2, currentBlock, currentStep); assert forall blk :: 0 <= blk < |z2.atoe| ==> |z2.atoe[blk]| <= |z2.W[blk]| + 1 && |z2.atoe[blk]| <= 81 && IsWordSeq(z2.W[blk]) && IsAtoEWordSeq(z2.atoe[blk]) && (|z2.atoe[blk]| > 0 ==> IsWordSeqOfLen(z2.H[blk], 5) && ConvertAtoEToSeq(z2.atoe[blk][0]) == z2.H[blk]) && (forall t :: 0 <= t < |z2.atoe[blk]|-1 ==> TheAtoEsAreOK(z2, blk, t)); forall blk | 0 <= blk < |z2.atoe| ensures IsAtoEWordSeq(z2.atoe[blk]); ensures forall t {:trigger TStep(t)} :: TStep(t) && 0 <= t < |z2.atoe[blk]|-1 ==> Word32AtoE(z2.atoe[blk][t]) && var T := Add32(Add32(Add32(Add32(Asm_RotateLeft(z2.atoe[blk][t].a, 5), ft(t, z2.atoe[blk][t].b, z2.atoe[blk][t].c, z2.atoe[blk][t].d)), z2.atoe[blk][t].e), K_SHA1(t)), z2.W[blk][t]); z2.atoe[blk][t+1].e == z2.atoe[blk][t].d && z2.atoe[blk][t+1].d == z2.atoe[blk][t].c && z2.atoe[blk][t+1].c == Asm_RotateLeft(z2.atoe[blk][t].b, 30) && z2.atoe[blk][t+1].b == z2.atoe[blk][t].a && z2.atoe[blk][t+1].a == T; { forall t {:trigger TStep(t)} | TStep(t) && 0 <= t < |z2.atoe[blk]|-1 ensures Word32AtoE(z2.atoe[blk][t]); ensures var T := Add32(Add32(Add32(Add32(Asm_RotateLeft(z2.atoe[blk][t].a, 5), ft(t, z2.atoe[blk][t].b, z2.atoe[blk][t].c, z2.atoe[blk][t].d)), z2.atoe[blk][t].e), K_SHA1(t)), z2.W[blk][t]); z2.atoe[blk][t+1].e == z2.atoe[blk][t].d && z2.atoe[blk][t+1].d == z2.atoe[blk][t].c && z2.atoe[blk][t+1].c == Asm_RotateLeft(z2.atoe[blk][t].b, 30) && z2.atoe[blk][t+1].b == z2.atoe[blk][t].a && z2.atoe[blk][t+1].a == T; { reveal_TheAtoEsAreOK(); assert TheAtoEsAreOK(z2, blk, t); } } reveal_PartialSHA1TraceHasCorrectatoesOpaque(); } ///////////////////////////////////////////////////// ///////////////////////////////////////////////////// static method InitializeVars_SHA1(M:array, words:int, H:array, W:array, Ks:array) returns (atoe:atoe_Type, num_blocks:int, ghost z:SHA1Trace) requires H != null && H.Length == 5; requires W != null; requires Ks != null && Ks.Length == 80; requires M != null; requires 0 <= words <= M.Length; requires Mod16(words) == 0; requires forall i :: 0 <= i < words ==> Word32(M[i]); ensures IsSHA1ReadyForBlock(z, SHA1_vars_to_state(M, words, H, W, Ks, atoe, num_blocks), 0); ensures |z.M| == num_blocks; requires H != Ks && H != M && H != W && Ks != M && Ks != W; modifies H; modifies Ks; ensures M[..] == old(M[..]); ensures W[..] == old(W[..]); { reveal_Mul16(); reveal_Mod16(); reveal_PartialSHA1TraceHasCorrectatoesOpaque(); InitH_SHA1(H); InitK_SHA1(Ks); Lemma_AllBlocksAreOfEqualSize(M[..words], 16); Lemma_AllBlocksAreWordSeqs(M[..words], 16); z := SHA1Trace_c(BreakIntoBlocks(M[..words], 16), [H[..]], [], []); num_blocks := words / 16; atoe := atoe_c(0, 0, 0, 0, 0); } static method ComputeWsForBlockStep1_SHA1(M:array, words:int, H:array, W:array, Ks:array, atoe:atoe_Type, num_blocks:int, ghost z:SHA1Trace, currentBlock:int) requires H != null; requires W != null && W.Length == 80; requires Ks != null; requires M != null; requires 0 <= words <= M.Length; requires 0 <= currentBlock < |z.M|; requires IsSHA1ReadyForBlock(z, SHA1_vars_to_state(M, words, H, W, Ks, atoe, num_blocks), currentBlock); requires W != H && W != Ks && W != M; modifies W; ensures Ks[..] == old(Ks[..]); ensures H[..] == old(H[..]); ensures M[..] == old(M[..]); ensures forall t :: 0 <= t < 16 ==> Word32(W[t]); ensures forall t {:trigger TStep(t)} :: TStep(t) && 0 <= t < 16 ==> W[t] == z.M[currentBlock][t]; ensures IsSHA1ReadyForBlock(z, SHA1_vars_to_state(M, words, H, W, Ks, atoe, num_blocks), currentBlock); { ghost var s := SHA1_vars_to_state(M, words, H, W, Ks, atoe, num_blocks); var t:int := 0; while t < 16 invariant 0 <= t <= 16; invariant s.M == M[..words]; invariant forall step :: 0 <= step < t ==> Word32(W[step]); invariant forall step {:trigger TStep(step)} :: TStep(step) && 0 <= step < t ==> W[step] == z.M[currentBlock][step]; { reveal_Mul16(); calc { 0; <= { lemma_mul_nonnegative(currentBlock, 16); } currentBlock * 16; <= currentBlock * 16 + t; } calc { currentBlock * 16 + t; 16 * currentBlock + t; 16 * (currentBlock+1) - 16 + t; <= 16*|z.M| - 16 + t; < 16*|z.M|; == Mul16(|z.M|); == words; } W[t] := M[currentBlock * 16 + t]; calc { W[t]; { lemma_mul_is_mul_boogie(currentBlock, 16); Lemma_BlockedSequencePrefixContainsElement(M[..], words, 16, currentBlock, t); } BreakIntoBlocks(M[..words], 16)[currentBlock][t]; BreakIntoBlocks(s.M, 16)[currentBlock][t]; z.M[currentBlock][t]; } t := t + 1; } } static method ComputeWsForBlockStep2_SHA1(M:array, words:int, H:array, W:array, Ks:array, atoe:atoe_Type, num_blocks:int, ghost z:SHA1Trace, currentBlock:int) requires H != null; requires W != null && W.Length == 80; requires Ks != null; requires M != null; requires 0 <= words <= M.Length; requires 0 <= currentBlock < |z.M|; requires IsSHA1ReadyForBlock(z, SHA1_vars_to_state(M, words, H, W, Ks, atoe, num_blocks), currentBlock); requires forall t :: 0 <= t < 16 ==> Word32(W[t]); requires forall t {:trigger TStep(t)} :: TStep(t) && 0 <= t < 16 ==> W[t] == z.M[currentBlock][t]; requires W != H && W != Ks && W != M; modifies W; ensures Ks[..] == old(Ks[..]); ensures H[..] == old(H[..]); ensures M[..] == old(M[..]); ensures forall t :: 0 <= t <= 79 ==> Word32(W[t]); ensures forall t {:trigger TStep(t)} :: TStep(t) && 0 <= t < 16 ==> W[t] == z.M[currentBlock][t]; ensures forall t {:trigger TStep(t)} :: TStep(t) && 16 <= t <= 79 ==> W[t] == Asm_RotateLeft(Asm_BitwiseXor(Asm_BitwiseXor(Asm_BitwiseXor(W[t-3], W[t-8]), W[t-14]), W[t-16]), 1); { var t := 16; while t < 80 invariant 16 <= t <= 80; invariant forall step :: 0 <= step < t ==> Word32(W[step]); invariant forall step {:trigger TStep(step)} :: TStep(step) && 0 <= step < 16 ==> W[step] == z.M[currentBlock][step]; invariant forall step {:trigger TStep(step)} :: TStep(step) && 16 <= step < t ==> W[step] == Asm_RotateLeft(Asm_BitwiseXor(Asm_BitwiseXor(Asm_BitwiseXor(W[step-3], W[step-8]), W[step-14]), W[step-16]), 1); { W[t] := Asm_RotateLeft(Asm_BitwiseXor(Asm_BitwiseXor(Asm_BitwiseXor(W[t-3], W[t-8]), W[t-14]), W[t-16]), 1); t := t + 1; } } static method ComputeWsForBlock_SHA1(M:array, words:int, H:array, W:array, Ks:array, atoe:atoe_Type, num_blocks:int, ghost z:SHA1Trace, currentBlock:int) returns (ghost next_z:SHA1Trace) requires H != null; requires W != null && W.Length == 80; requires Ks != null; requires M != null; requires 0 <= words <= M.Length; requires 0 <= currentBlock < |z.M|; requires IsSHA1ReadyForBlock(z, SHA1_vars_to_state(M, words, H, W, Ks, atoe, num_blocks), currentBlock); requires W != H && W != Ks && W != M; modifies W; ensures Ks[..] == old(Ks[..]); ensures H[..] == old(H[..]); ensures M[..] == old(M[..]); ensures IsSHA1DoneComputingWs(next_z, SHA1_vars_to_state(M, words, H, W, Ks, atoe, num_blocks), currentBlock); { ghost var s := SHA1_vars_to_state(M, words, H, W, Ks, atoe, num_blocks); ComputeWsForBlockStep1_SHA1(M, words, H, W, Ks, atoe, num_blocks, z, currentBlock); ComputeWsForBlockStep2_SHA1(M, words, H, W, Ks, atoe, num_blocks, z, currentBlock); next_z := SHA1Trace_c(z.M, z.H, z.W + [W[..]], z.atoe); ghost var next_s := SHA1_vars_to_state(M, words, H, W, Ks, atoe, num_blocks); lemma_SHA1TransitionOKAfterSettingWs(z, s, next_z, next_s, currentBlock); } static method ComputeInitialAtoEForBlock_SHA1(M:array, words:int, H:array, W:array, Ks:array, atoe:atoe_Type, num_blocks:int, ghost z:SHA1Trace, currentBlock:int) returns (next_atoe:atoe_Type, ghost next_z:SHA1Trace) requires H != null; requires W != null; requires Ks != null; requires M != null; requires 0 <= words <= M.Length; requires 0 <= currentBlock < |z.M|; requires IsSHA1DoneComputingWs(z, SHA1_vars_to_state(M, words, H, W, Ks, atoe, num_blocks), currentBlock); ensures IsSHA1ReadyForStep(next_z, SHA1_vars_to_state(M, words, H, W, Ks, next_atoe, num_blocks), currentBlock, 0); { reveal_PartialSHA1TraceHasCorrectatoesOpaque(); next_atoe := atoe_c(H[0], H[1], H[2], H[3], H[4]); next_z := SHA1Trace_c(z.M, z.H, z.W, z.atoe + [[next_atoe]]); } static method ComputeOneStep_SHA1(M:array, words:int, H:array, W:array, Ks:array, atoe:atoe_Type, num_blocks:int, ghost z:SHA1Trace, currentBlock:int, currentStep:int) returns (next_atoe:atoe_Type, ghost next_z:SHA1Trace) requires H != null; requires W != null; requires Ks != null; requires M != null; requires 0 <= words <= M.Length; requires 0 <= currentBlock < |z.M|; requires 0 <= currentStep <= 79; requires IsSHA1ReadyForStep(z, SHA1_vars_to_state(M, words, H, W, Ks, atoe, num_blocks), currentBlock, currentStep); ensures IsSHA1ReadyForStep(next_z, SHA1_vars_to_state(M, words, H, W, Ks, next_atoe, num_blocks), currentBlock, currentStep+1); ensures Ks[..] == old(Ks[..]); ensures H[..] == old(H[..]); ensures M[..] == old(M[..]); ensures W[..] == old(W[..]); { assert TBlk(currentBlock) && TBlk(currentBlock + 1) && TStep(currentStep) && TStep(currentStep + 1); ghost var s := SHA1_vars_to_state(M, words, H, W, Ks, atoe, num_blocks); var T := Asm_Add(Asm_Add(Asm_Add(Asm_Add(Asm_RotateLeft(atoe.a, 5), ft_impl(currentStep, atoe.b, atoe.c, atoe.d)), atoe.e), Ks[currentStep]), W[currentStep]); next_atoe := atoe_c(T, atoe.a, Asm_RotateLeft(atoe.b, 30), atoe.c, atoe.d); next_z := SHA1Trace_c(z.M, z.H, z.W, z.atoe[..currentBlock] + [z.atoe[currentBlock] + [next_atoe]]); ghost var next_s := SHA1_vars_to_state(M, words, H, W, Ks, next_atoe, num_blocks); lemma_SHA1TransitionOKAfterSettingAtoE(z, s, next_z, next_s, currentBlock, currentStep); } static method ComputeHsForBlockStep1_SHA1(M:array, words:int, H:array, W:array, Ks:array, atoe:atoe_Type, num_blocks:int, ghost z:SHA1Trace, currentBlock:int) requires H != null && H.Length == 5; requires W != null; requires Ks != null; requires M != null; requires 0 <= words <= M.Length; requires 0 <= currentBlock < |z.M|; requires IsSHA1ReadyForStep(z, SHA1_vars_to_state(M, words, H, W, Ks, atoe, num_blocks), currentBlock, 80); requires H != W && H != Ks && H != M; modifies H; ensures Ks[..] == old(Ks[..]); ensures W[..] == old(W[..]); ensures M[..] == old(M[..]); ensures forall j :: 0 <= j < 5 ==> Word32(H[j]) && H[j] == Add32(ConvertAtoEToSeq_premium(atoe)[j], old(H[j])); { ghost var s := SHA1_vars_to_state(M, words, H, W, Ks, atoe, num_blocks); ghost var atoe_seq := ConvertAtoEToSeq_premium(atoe); H[0], H[1], H[2], H[3], H[4] := Asm_Add(atoe.a, H[0]), Asm_Add(atoe.b, H[1]), Asm_Add(atoe.c, H[2]), Asm_Add(atoe.d, H[3]), Asm_Add(atoe.e, H[4]); forall j | 0 <= j < 5 ensures Word32(H[j]); ensures H[j] == Add32(ConvertAtoEToSeq_premium(atoe)[j], s.H[j]); ensures M[..] == old(M[..]); ensures W[..] == old(W[..]); { ghost var atoe_seq := ConvertAtoEToSeq_premium(atoe); if j == 0 { assert H[0] == Add32(atoe_seq[0], s.H[0]); } else if j == 1 { assert H[1] == Add32(atoe_seq[1], s.H[1]); } else if j == 2 { assert H[2] == Add32(atoe_seq[2], s.H[2]); } else if j == 3 { assert H[3] == Add32(atoe_seq[3], s.H[3]); } else if j == 4 { assert H[4] == Add32(atoe_seq[4], s.H[4]); } } } static method ComputeHsForBlock_SHA1(M:array, words:int, H:array, W:array, Ks:array, atoe:atoe_Type, num_blocks:int, ghost z:SHA1Trace, currentBlock:int) returns (ghost next_z:SHA1Trace) requires H != null && H.Length == 5; requires W != null; requires Ks != null; requires M != null; requires 0 <= words <= M.Length; requires 0 <= currentBlock < |z.M|; requires IsSHA1ReadyForStep(z, SHA1_vars_to_state(M, words, H, W, Ks, atoe, num_blocks), currentBlock, 80); requires H != W && H != Ks && H != M; modifies H; ensures Ks[..] == old(Ks[..]); ensures W[..] == old(W[..]); ensures M[..] == old(M[..]); ensures IsSHA1ReadyForBlock(next_z, SHA1_vars_to_state(M, words, H, W, Ks, atoe, num_blocks), currentBlock+1); { ghost var s := SHA1_vars_to_state(M, words, H, W, Ks, atoe, num_blocks); ComputeHsForBlockStep1_SHA1(M, words, H, W, Ks, atoe, num_blocks, z, currentBlock); next_z := SHA1Trace_c(z.M, z.H + [H[..]], z.W, z.atoe); ghost var next_s := SHA1_vars_to_state(M, words, H, W, Ks, atoe, num_blocks); lemma_SHA1TransitionOKAfterSettingHs(z, s, next_z, next_s, currentBlock); } static method PerformOneBlockOfSHA1Computation(M:array, words:int, H:array, W:array, Ks:array, atoe:atoe_Type, num_blocks:int, ghost z:SHA1Trace, currentBlock:int) returns (next_atoe:atoe_Type, ghost next_z:SHA1Trace) requires H != null && H.Length == 5; requires W != null && W.Length == 80; requires Ks != null; requires M != null; requires 0 <= words <= M.Length; requires 0 <= currentBlock < |z.M|; requires IsSHA1ReadyForBlock(z, SHA1_vars_to_state(M, words, H, W, Ks, atoe, num_blocks), currentBlock); requires W != H && W != Ks && W != M && H != Ks && H != M; modifies H; modifies W; ensures M[..] == old(M[..]); ensures Ks[..] == old(Ks[..]); ensures IsSHA1ReadyForBlock(next_z, SHA1_vars_to_state(M, words, H, W, Ks, next_atoe, num_blocks), currentBlock+1); { var current_z := ComputeWsForBlock_SHA1(M, words, H, W, Ks, atoe, num_blocks, z, currentBlock); var current_atoe:atoe_Type; current_atoe, current_z := ComputeInitialAtoEForBlock_SHA1(M, words, H, W, Ks, atoe, num_blocks, current_z, currentBlock); var t := 0; while t < 80 invariant 0 <= t <= 80; invariant M[..] == old(M[..]); invariant Ks[..] == old(Ks[..]); invariant IsSHA1ReadyForStep(current_z, SHA1_vars_to_state(M, words, H, W, Ks, current_atoe, num_blocks), currentBlock, t); { current_atoe, current_z := ComputeOneStep_SHA1(M, words, H, W, Ks, current_atoe, num_blocks, current_z, currentBlock, t); t := t + 1; } current_z := ComputeHsForBlock_SHA1(M, words, H, W, Ks, current_atoe, num_blocks, current_z, currentBlock); next_atoe := current_atoe; next_z := current_z; } static lemma Lemma_IsSHA1ReadyForLastBlockImpliesTraceIsCorrect(messageBits:seq, z:SHA1Trace, s:SHA1_state) requires 0 <= s.num_blocks; requires IsSHA1ReadyForBlock(z, s, s.num_blocks); ensures SHA1TraceIsCorrect(z); { reveal_PartialSHA1TraceHasCorrectatoesOpaque(); } static lemma Lemma_IsSHA1Demonstration(messageBits:seq, hash:seq, z:SHA1Trace) requires IsBitSeq(messageBits); requires |messageBits| < power2(64); requires IsCompleteSHA1Trace(z); requires z.M == BlockMessageForSHA(PadMessageForSHA_premium(messageBits)); requires SHA1TraceIsCorrect(z); requires hash == z.H[|z.M|]; ensures IsSHA1(messageBits, hash); { } static lemma Lemma_MessageInSHA1TraceCorrespondsToMessageInArray(M:array, words:int, messageBits:seq, z:SHA1Trace) requires M != null; requires 0 <= words <= M.Length; requires Mod16(words) == 0; requires forall i :: 0 <= i < words ==> Word32(M[i]); requires IsBitSeq(messageBits); requires |messageBits| < power2(64); requires BEWordSeqToBitSeq(M[..words]) == PadMessageForSHA(messageBits); requires z.M == BreakIntoBlocks(M[..words], 16); ensures z.M == BlockMessageForSHA(PadMessageForSHA_premium(messageBits)); { assert |BEWordSeqToBitSeq_premium(M[..words])| == words * 32; calc { z.M; BreakIntoBlocks(M[..words], 16); { reveal_power2(); lemma_BEDigitSeqToInt_invertibility(power2(32), BEDigitSeqToInt_premium(power2(32), M[..words]), M[..words]); } BreakIntoBlocks(BEIntToDigitSeq(power2(32), words, BEWordSeqToInt_premium(M[..words])), 16); { lemma_BEBitSeqToInt_BEWordSeqToBitSeq(M[..words]); } BreakIntoBlocks(BEIntToDigitSeq(power2(32), words, BEBitSeqToInt(BEWordSeqToBitSeq(M[..words]))), 16); BreakIntoBlocks(BEIntToDigitSeq(power2(32), words, BEBitSeqToInt(PadMessageForSHA(messageBits))), 16); { lemma_mul_is_mul_boogie(words, 32); lemma_div_by_multiple(words, 32); assert (words*32)/32 == words; } BreakIntoBlocks(BEIntToDigitSeq(power2(32), (words*32)/32, BEBitSeqToInt(PadMessageForSHA(messageBits))), 16); BreakIntoBlocks(BEIntToDigitSeq(power2(32), |BEWordSeqToBitSeq_premium(M[..words])|/32, BEBitSeqToInt(PadMessageForSHA(messageBits))), 16); BreakIntoBlocks(BEIntToDigitSeq(power2(32), |PadMessageForSHA(messageBits)|/32, BEBitSeqToInt(PadMessageForSHA(messageBits))), 16); { reveal_BlockMessageForSHA(); lemma_PadMessageForSHA_properties(messageBits); } BlockMessageForSHA(PadMessageForSHA(messageBits)); } } static method{:dafnycc_conservative_seq_triggers} ComputeSHA1AfterPadding_arrays(M:array, words:int, ghost messageBits:seq) returns (hash:array) requires M != null; requires 0 <= words <= M.Length; requires Mod16(words) == 0; requires forall i :: 0 <= i < words ==> Word32(M[i]); requires IsBitSeq(messageBits); requires |messageBits| < power2(64); requires BEWordSeqToBitSeq(M[..words]) == PadMessageForSHA(messageBits); ensures hash!=null; ensures IsSHA1(messageBits, hash[..]); { var H := new int[5]; var W := new int[80]; var Ks := new int[80]; var atoe:atoe_Type; var num_blocks:int; ghost var z:SHA1Trace; atoe, num_blocks, z := InitializeVars_SHA1(M, words, H, W, Ks); var currentBlock:int := 0; while currentBlock < num_blocks invariant 0 <= currentBlock <= num_blocks; invariant M[..] == old(M[..]); invariant BEWordSeqToBitSeq(M[..words]) == PadMessageForSHA(messageBits); invariant IsSHA1ReadyForBlock(z, SHA1_vars_to_state(M, words, H, W, Ks, atoe, num_blocks), currentBlock); { atoe, z := PerformOneBlockOfSHA1Computation(M, words, H, W, Ks, atoe, num_blocks, z, currentBlock); currentBlock := currentBlock + 1; } hash := H; Lemma_MessageInSHA1TraceCorrespondsToMessageInArray(M, words, messageBits, z); Lemma_IsSHA1ReadyForLastBlockImpliesTraceIsCorrect(messageBits, z, SHA1_vars_to_state(M, words, H, W, Ks, atoe, num_blocks)); Lemma_IsSHA1Demonstration(messageBits, H[..], z); } static method{:dafnycc_conservative_seq_triggers} ComputeSHA1AfterPadding(M:array, words:int, ghost messageBits:seq) returns (hash:seq) requires M != null; requires 0 <= words <= M.Length; requires Mod16(words) == 0; requires forall i :: 0 <= i < words ==> Word32(M[i]); requires IsBitSeq(messageBits); requires |messageBits| < power2(64); requires BEWordSeqToBitSeq(M[..words]) == PadMessageForSHA(messageBits); ensures IsSHA1(messageBits, hash[..]); { var H := ComputeSHA1AfterPadding_arrays(M, words, messageBits); hash := H[..]; } static lemma lemma_PaddedLength_words(message_len:int, padded_len:int, words:int) requires padded_len == PaddedLength(message_len); requires words == padded_len / 32; ensures padded_len == words * 32; { lemma_PaddedLength_properties(message_len); } static method{:dafnycc_conservative_seq_triggers} SHA1_impl_ArrayInPlace(M:array, bits:int) returns (hash:seq) requires IsWordArray(M); requires Word32(bits); requires 0 <= bits < power2(64); requires 0 <= PaddedLength(bits) <= M.Length * 32; ensures bits <= M.Length * 32; ensures IsWordSeqOfLen(hash, 5); ensures IsSHA1(old(BEWordSeqToBitSeq_premium(M[..])[..bits]), hash); ensures hash == SHA1(old(BEWordSeqToBitSeq_premium(M[..])[..bits])); modifies M; { calc <= { bits; { lemma_PaddedLength_properties(bits); } |BEWordSeqToBitSeq_premium(M[..])|; } ghost var messageBits := BEWordSeqToBitSeq_premium(M[..])[..bits]; PadMessageArray(M, bits); var words := PaddedLength(bits)/32; calc { PadMessageForSHA(messageBits); BEWordSeqToBitSeq_premium(M[..])[..PaddedLength(bits)]; { lemma_PaddedLength_properties(bits); } BEWordSeqToBitSeq_premium(M[..])[..words*32]; { lemma_WordSeqToBitSeqChop(M[..], M[..words], M[words..]); } (BEWordSeqToBitSeq_premium(M[..words]) + BEWordSeqToBitSeq_premium(M[words..]))[..words*32]; BEWordSeqToBitSeq_premium(M[..words])[..words*32]; BEWordSeqToBitSeq_premium(M[..words]); } lemma_mod_words(bits, words); hash := ComputeSHA1AfterPadding(M, words, messageBits); lemma_SHA1IsAFunction(old(BEWordSeqToBitSeq_premium(M[..])[..bits]), hash); } static method SHA1_impl_Bytes(messageBytes:seq) returns (hash:seq) requires Word32(|messageBytes|*8); requires |messageBytes|*8 < power2(64); requires IsByteSeq(messageBytes); ensures IsWordSeqOfLen(hash, 5); ensures IsSHA1(BEByteSeqToBitSeq_premium(messageBytes), hash); ensures hash == SHA1(BEByteSeqToBitSeq_premium(messageBytes)); { var M, bits := CreateArrayForSHA(messageBytes); hash := SHA1_impl_ArrayInPlace(M, bits); lemma_SHA1IsAFunction(BEByteSeqToBitSeq_premium(messageBytes), hash); } static method SHA1_impl_Bytes_arrays(messageBytes:array) returns (hash:array) requires messageBytes != null; requires Word32(messageBytes.Length*8); requires messageBytes.Length*8 < power2(64); requires IsByteSeq(messageBytes[..]); ensures hash != null; ensures IsWordSeqOfLen(hash[..], 5); ensures IsSHA1(BEByteSeqToBitSeq_premium(messageBytes[..]), hash[..]); ensures hash[..] == SHA1(BEByteSeqToBitSeq_premium(messageBytes[..])); { var M, bits := CreateArrayForSHA_arrays(messageBytes); ghost var Minput_seq := M[..]; assert BEByteSeqToBitSeq_premium(messageBytes[..]) == BEWordSeqToBitSeq(Minput_seq)[..bits]; ghost var oldMessageBytes_seq := old(messageBytes)[..]; ghost var messageBits := BEWordSeqToBitSeq_premium(M[..])[..bits]; PadMessageArray(M, bits); var words := PaddedLength(bits)/32; calc { PadMessageForSHA(messageBits); BEWordSeqToBitSeq_premium(M[..])[..PaddedLength(bits)]; { lemma_PaddedLength_words(bits, PaddedLength(bits), words); } BEWordSeqToBitSeq_premium(M[..])[..words*32]; { lemma_WordSeqToBitSeqChop(M[..], M[..words], M[words..]); } (BEWordSeqToBitSeq_premium(M[..words]) + BEWordSeqToBitSeq_premium(M[words..]))[..words*32]; BEWordSeqToBitSeq_premium(M[..words])[..words*32]; BEWordSeqToBitSeq_premium(M[..words]); } lemma_mod_words(bits, words); hash := ComputeSHA1AfterPadding_arrays(M, words, messageBits); ghost var hash_seq := hash[..]; ghost var messageBytes_seq := old(messageBytes)[..]; assert IsSHA1(messageBits, hash_seq); assert old(messageBytes)[..] == oldMessageBytes_seq; lemma_SHA_impl_Bytes_arrays_bitmangle(old(messageBytes), messageBytes_seq, messageBits, Minput_seq, bits); assert IsSHA1(BEByteSeqToBitSeq_premium(messageBytes_seq), hash_seq); lemma_SHA1IsAFunction(BEByteSeqToBitSeq_premium(messageBytes_seq), hash_seq); } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Crypto/Hash/sha1.s.dfy ================================================ include "sha_common.s.dfy" include "hmac_common.s.dfy" //-/////////////////////////////////////////////////// //- Constants //-/////////////////////////////////////////////////// static function method{:opaque} K_SHA1(n: int) : int requires 0 <= n <= 79; ensures Word32(K_SHA1(n)); { /*call_lemma:*/lemma_power2_32(); if 0 <= n <= 19 then 0x5a827999 else if 20 <= n <= 39 then 0x6ed9eba1 else if 40 <= n <= 59 then 0x8f1bbcdc else 0xca62c1d6 } static function method{:opaque} InitialH_SHA1(index: int) : int requires 0 <= index <= 4; ensures Word32(InitialH_SHA1(index)); { /*call_lemma:*/lemma_power2_32(); [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0][index] } //-////////////////////////////////// //- SHA-1 trace //-////////////////////////////////// //- The fields of a SHA1Trace have the following meanings: //- //- M[blk][i] = word #i of message block #blk //- W[blk][t] = W_t during processing of message block #blk //- H[blk][j] = H_j before processing message block #blk //- atoe[blk][t].a = a before step t of processing of message block #blk //- ... //- atoe[blk][t].e = e before step t of processing message block #blk datatype atoe_Type = atoe_c(a:int, b:int, c:int, d:int, e:int); datatype SHA1Trace = SHA1Trace_c(M:seq>, H:seq>, W:seq>, atoe:seq>); static predicate IsAtoEWordSeqOfLen(vs:seq, len:int) { |vs| == len && forall i :: 0 <= i < len ==> Word32(vs[i].a) && Word32(vs[i].b) && Word32(vs[i].c) && Word32(vs[i].d) && Word32(vs[i].e) } static function ConvertAtoEToSeq(v:atoe_Type) : seq { [v.a, v.b, v.c, v.d, v.e] } static predicate IsCompleteSHA1Trace(z:SHA1Trace) { (forall i :: 0 <= i < |z.M| ==> IsWordSeqOfLen(z.M[i], 16)) && |z.H| == |z.M| + 1 && |z.W| == |z.atoe| == |z.M| && (forall blk :: 0 <= blk < |z.M| ==> IsWordSeqOfLen(z.W[blk], 80)) && (forall blk :: 0 <= blk < |z.M| ==> IsAtoEWordSeqOfLen(z.atoe[blk], 81)) && (forall blk :: 0 <= blk <= |z.M| ==> IsWordSeqOfLen(z.H[blk], 5)) } static predicate SHA1TraceHasCorrectHs(z:SHA1Trace) requires IsCompleteSHA1Trace(z); { (forall j :: 0 <= j < 5 ==> z.H[0][j] == InitialH_SHA1(j)) && (forall blk {:trigger TBlk(blk)} :: TBlk(blk) ==> forall j :: 0 <= blk < |z.M| && 0 <= j < 5 ==> z.H[blk+1][j] == Add32(ConvertAtoEToSeq(z.atoe[blk][80])[j], z.H[blk][j])) } static predicate SHA1TraceHasCorrectWs(z:SHA1Trace) requires IsCompleteSHA1Trace(z); { forall blk :: 0 <= blk < |z.M| ==> forall t {:trigger TStep(t)} :: TStep(t) ==> (0 <= t <= 15 ==> z.W[blk][t] == z.M[blk][t]) && (16 <= t <= 79 ==> z.W[blk][t] == RotateLeft(BitwiseXor(BitwiseXor(BitwiseXor(z.W[blk][t-3], z.W[blk][t-8]), z.W[blk][t-14]), z.W[blk][t-16]), 1)) } static predicate SHA1TraceHasCorrectatoes(z:SHA1Trace) requires IsCompleteSHA1Trace(z); { forall blk :: 0 <= blk < |z.M| ==> ConvertAtoEToSeq(z.atoe[blk][0]) == z.H[blk] && forall t {:trigger TStep(t)} :: TStep(t) && 0 <= t <= 79 ==> (var T := Add32(Add32(Add32(Add32(RotateLeft(z.atoe[blk][t].a, 5), ft(t, z.atoe[blk][t].b, z.atoe[blk][t].c, z.atoe[blk][t].d)), z.atoe[blk][t].e), K_SHA1(t)), z.W[blk][t]); z.atoe[blk][t+1].e == z.atoe[blk][t].d && z.atoe[blk][t+1].d == z.atoe[blk][t].c && z.atoe[blk][t+1].c == RotateLeft(z.atoe[blk][t].b, 30) && z.atoe[blk][t+1].b == z.atoe[blk][t].a && z.atoe[blk][t+1].a == T) } static predicate {:autoReq} SHA1TraceIsCorrect(z:SHA1Trace) { SHA1TraceHasCorrectHs(z) && SHA1TraceHasCorrectWs(z) && SHA1TraceHasCorrectatoes(z) } static predicate {:autoReq} IsSHA1(messageBits:seq, hash:seq) requires IsBitSeq(messageBits); { exists z:SHA1Trace :: IsCompleteSHA1Trace(z) && z.M == BlockMessageForSHA(PadMessageForSHA(messageBits)) && SHA1TraceIsCorrect(z) && hash == z.H[|z.M|] } static function {:axiom} SHA1(messageBits:seq) : seq requires IsBitSeq(messageBits); requires |messageBits| < power2(64); ensures IsWordSeqOfLen(SHA1(messageBits), 5); static lemma {:axiom} lemma_SHA1IsAFunction(messageBits:seq, hash:seq) requires IsBitSeq(messageBits); requires |messageBits| < power2(64); requires IsWordSeqOfLen(hash, 5); requires IsSHA1(messageBits, hash); ensures SHA1(messageBits) == hash; //-/////////////////////////////////////////////////////////////////////////////// //- HMAC specification based on: //- http://csrc.nist.gov/publications/fips/fips198-1/FIPS-198-1_final.pdf //-/////////////////////////////////////////////////////////////////////////////// static function {:autoReq} HMAC_SHA1(k: seq, m: seq) : seq requires |k|==512; { SHA1(SeqXor(k, Opad(|k|)) + BEWordSeqToBitSeq(SHA1(SeqXor(k, Ipad(|k|)) + m))) } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Crypto/Hash/sha1_hmac.i.dfy ================================================ include "sha_common.s.dfy" include "hmac_common.s.dfy" include "sha1.i.dfy" include "hmac_common.i.dfy" include "../../Util/arrays_and_seqs.i.dfy" method HMAC_SHA1_inner_hash(key: array, data: array, len: int) returns (hash: array) requires Word32(len); requires IsWordArray(key); requires key.Length == 16; requires len <= power2(32) - 1 - 512; requires IsWordArray(data); requires 0 <= data.Length; requires 0 <= len <= data.Length * 32; ensures fresh(hash); ensures key[..] == old(key[..]); ensures data[..] == old(data[..]); ensures IsWordArray(hash); ensures Mod32_const(512) == 0; ensures IsSHA1(SeqXor_premium(BEWordSeqToBitSeq_premium(key[..]), Ipad_premium(512)) + BEWordSeqToBitSeq_premium(data[..])[..len], hash[..]); { var input := HMAC_inner_input(key, data, len); assert data[..] == old(data[..]); assert key[..] == old(key[..]); lemma_2toX(); ghost var old_input := BEWordSeqToBitSeq_premium(input[..])[..len+512]; calc { old_input; BEWordSeqToBitSeq_premium(input[..])[..len+512]; (SeqXor_premium(BEWordSeqToBitSeq_premium(key[..]), Ipad_premium(512)) + BEWordSeqToBitSeq_premium(data[..]) + BEWordSeqToBitSeq_premium(input[16+data.Length..]))[..len+512]; { assert |SeqXor_premium(BEWordSeqToBitSeq_premium(key[..]), Ipad_premium(512))| == 512; } { assert |BEWordSeqToBitSeq_premium(data[..])| >= len; } //- == |data[..]|*32; SeqXor_premium(BEWordSeqToBitSeq_premium(key[..]), Ipad_premium(512)) + BEWordSeqToBitSeq_premium(data[..])[..len]; } var hash_seq := SHA1_impl_ArrayInPlace(input, len+512); hash := SeqToArray(hash_seq); lemma_Mod32_const(512); } method HMAC_SHA1_impl_Array(key: array, data: array, len: int) returns (hash: seq) requires Word32(len); requires IsWordArray(key); requires key.Length == 16; requires len <= power2(32) - 1 - 512; requires data != null; requires 0 <= len <= data.Length * 32; requires IsWordArray(data); ensures IsWordSeqOfLen(hash, 5); ensures key[..] == old(key[..]); ensures data[..] == old(data[..]); ensures var k := BEWordSeqToBitSeq_premium(key[..]); var m := BEWordSeqToBitSeq_premium(data[..])[..len]; IsBitSeqOfLen(k, 512) && IsBitSeqOfLen(Ipad(512), 512) && IsBitSeq(SeqXor(k, Ipad(512)) + m) && |SeqXor(k, Ipad(512)) + m| < power2(64) && IsBitSeqOfLen(Opad(512), 512) && IsBitSeq(SeqXor(k, Opad(512)) + BEWordSeqToBitSeq(SHA1(SeqXor(k, Ipad(512)) + m))) && |SeqXor(k, Opad(512)) + BEWordSeqToBitSeq(SHA1(SeqXor(k, Ipad(512)) + m))| < power2(64) && hash == HMAC_SHA1(k, m); { var inner_hash := HMAC_SHA1_inner_hash(key, data, len); assert key[..] == old( key[..]); assert data[..] == old(data[..]); lemma_2toX(); reveal_Mod32_const(); lemma_SHA1IsAFunction(SeqXor_premium(BEWordSeqToBitSeq_premium(key[..]), Ipad_premium(512)) + BEWordSeqToBitSeq_premium(data[..])[..len], inner_hash[..]); assert inner_hash[..] == SHA1(SeqXor_premium(BEWordSeqToBitSeq_premium(key[..]), Ipad_premium(512)) + BEWordSeqToBitSeq_premium(data[..])[..len]); ghost var old_inner_hash := inner_hash[..]; var input := HMAC_outer_input(key, inner_hash); assert old_inner_hash == inner_hash[..]; assert key[..] == old( key[..]); assert data[..] == old(data[..]); ghost var original_input := input[..]; var bit_len := 32*(key.Length + inner_hash.Length); assert old_inner_hash == inner_hash[..]; assert key[..] == old( key[..]); assert data[..] == old(data[..]); assert input[..] == original_input; ghost var old_input := BEWordSeqToBitSeq_premium(input[..])[..bit_len]; calc <= { 16+8; {lemma_PaddedLength_properties(32*(16+inner_hash.Length));} input.Length; } calc { old_input; BEWordSeqToBitSeq_premium(input[..])[..bit_len]; (SeqXor_premium(BEWordSeqToBitSeq_premium(key[..]), Opad_premium(512)) + BEWordSeqToBitSeq_premium(inner_hash[..]) + BEWordSeqToBitSeq_premium(input[16+8..]))[..bit_len]; (SeqXor_premium(BEWordSeqToBitSeq_premium(key[..]), Opad_premium(512)) + BEWordSeqToBitSeq_premium(inner_hash[..]))[..bit_len]; SeqXor_premium(BEWordSeqToBitSeq_premium(key[..]), Opad_premium(512)) + BEWordSeqToBitSeq_premium(inner_hash[..]); SeqXor_premium(BEWordSeqToBitSeq_premium(key[..]), Opad_premium(512)) + BEWordSeqToBitSeq_premium(SHA1(SeqXor_premium(BEWordSeqToBitSeq_premium(key[..]), Ipad_premium(512)) + BEWordSeqToBitSeq_premium(data[..])[..len])); } hash := SHA1_impl_ArrayInPlace(input, bit_len); assert hash == SHA1(old_input); assert old_inner_hash == inner_hash[..]; assert key[..] == old( key[..]); assert data[..] == old(data[..]); ghost var k := BEWordSeqToBitSeq_premium(key[..]); ghost var m := BEWordSeqToBitSeq_premium(data[..])[..len]; calc { hash; SHA1(old_input); SHA1(SeqXor_premium(BEWordSeqToBitSeq_premium(key[..]), Opad_premium(512)) + BEWordSeqToBitSeq_premium(SHA1(SeqXor_premium(BEWordSeqToBitSeq_premium(key[..]), Ipad_premium(512)) + BEWordSeqToBitSeq_premium(data[..])[..len]))); { assert BEWordSeqToBitSeq_premium(key[..])[..key.Length*32] == BEWordSeqToBitSeq_premium(key[..]); } SHA1(SeqXor_premium(k, Opad_premium(|k|)) + BEWordSeqToBitSeq_premium(SHA1(SeqXor_premium(k, Ipad_premium(|k|)) + m))); HMAC_SHA1(k, m); } } method HMAC_SHA1_impl_Seqs(keyBytes: seq, dataBytes: seq) returns (hash: seq) requires Word32(|dataBytes|*8); requires IsByteSeq(keyBytes); requires |keyBytes| <= 64; requires |dataBytes|*8 <= power2(32) - 1 - 512; requires IsByteSeq(dataBytes); ensures IsWordSeqOfLen(hash, 5); ensures var k := BEByteSeqToBitSeq_premium(keyBytes + RepeatDigit_premium(0, 64 - |keyBytes|)); var m := BEByteSeqToBitSeq_premium(dataBytes); IsBitSeqOfLen(k, 512) && IsBitSeqOfLen(Ipad(512), 512) && IsBitSeq(SeqXor(k, Ipad(512)) + m) && |SeqXor(k, Ipad(512)) + m| < power2(64) && IsBitSeqOfLen(Opad(512), 512) && IsBitSeq(SeqXor(k, Opad(512)) + BEWordSeqToBitSeq(SHA1(SeqXor(k, Ipad(512)) + m))) && |SeqXor(k, Opad(512)) + BEWordSeqToBitSeq(SHA1(SeqXor(k, Ipad(512)) + m))| < power2(64) && hash == HMAC_SHA1(k, m); { var requiredKeyBytePadding := RepeatDigit_impl(0, 64 - |keyBytes|); var keyBytesPadded := keyBytes + requiredKeyBytePadding; var keyWords, padbytes := BEByteSeqToWordSeq_impl(keyBytesPadded); var keyArray := SeqToArray(keyWords); var dataWords := BEByteSeqToWordSeqTailPadding(dataBytes); var dataArray := SeqToArray(dataWords); var len := |dataBytes|*8; calc { len; |dataBytes|*8; <= |BEWordSeqToBitSeq_premium(dataWords)|; |dataWords| * 32; dataArray.Length * 32; } calc { keyArray.Length; |keyWords|; |keyBytesPadded| / 4; (|keyBytes| + 64 - |keyBytes|) / 4; 64 / 4; 16; } hash := HMAC_SHA1_impl_Array(keyArray, dataArray, len); lemma_2toX(); ghost var k := BEByteSeqToBitSeq_premium(keyBytesPadded); ghost var m := BEByteSeqToBitSeq_premium(dataBytes); reveal_Mod32_const(); assert IsBitSeqOfLen(k, 512); assert IsBitSeqOfLen(Ipad_premium(512), 512); assert IsBitSeq(SeqXor_premium(k, Ipad_premium(512)) + m); assert |SeqXor_premium(k, Ipad_premium(512)) + m| < power2(64); assert IsBitSeqOfLen(Opad_premium(512), 512); assert IsBitSeq(SeqXor_premium(k, Opad_premium(512)) + BEWordSeqToBitSeq_premium(SHA1(SeqXor_premium(k, Ipad_premium(512)) + m))); assert |SeqXor_premium(k, Opad_premium(512)) + BEWordSeqToBitSeq_premium(SHA1(SeqXor_premium(k, Ipad_premium(512)) + m))| < power2(64); calc { hash; HMAC_SHA1(BEWordSeqToBitSeq_premium(keyArray[..]), BEWordSeqToBitSeq_premium(dataArray[..])[..len]); { assert keyWords == keyArray[..]; } HMAC_SHA1(BEWordSeqToBitSeq_premium(keyWords), BEWordSeqToBitSeq_premium(dataArray[..])[..len]); HMAC_SHA1(k, BEWordSeqToBitSeq_premium(dataArray[..])[..len]); HMAC_SHA1(k, BEByteSeqToBitSeq_premium(dataBytes)); HMAC_SHA1(k, m); } } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Crypto/Hash/sha256.i.dfy ================================================ include "sha256.s.dfy" include "../../Util/seq_blocking.i.dfy" include "../../Util/arrays_and_seqs.i.dfy" include "../../Util/integer_sequences_premium.i.dfy" include "sha_padding.i.dfy" include "sha_common.i.dfy" include "sha256opt.i.dfy" include "sha256opt2.i.dfy" include "sha256common.i.dfy" include "../../../Drivers/CPU/assembly_premium.i.dfy" static function method{:CompiledSpec} CompiledSpec_K_SHA256(t: int) : int static function method{:CompiledSpec} CompiledSpec_InitialH_SHA256(j: int) : int //-/////////////////////////////////////////////////// //- Utility functions for AtoH //-/////////////////////////////////////////////////// static function ConvertAtoHToSeq_premium(v:atoh_Type) : seq requires Word32AtoH(v); ensures IsWordSeqOfLen(ConvertAtoHToSeq_premium(v), 8); ensures ConvertAtoHToSeq_premium(v) == ConvertAtoHToSeq(v); { ConvertAtoHToSeq(v) } //-/////////////////////////////////////////////////// //- Initialization of data structures //-/////////////////////////////////////////////////// static method InitH_SHA256(H:array) requires H != null && H.Length == 8; ensures forall i :: 0 <= i < H.Length ==> H[i] == InitialH_SHA256(i); modifies H; { H[0] := 1779033703; H[1] := 3144134277; H[2] := 1013904242; H[3] := 2773480762; H[4] := 1359893119; H[5] := 2600822924; H[6] := 528734635; H[7] := 1541459225; reveal_InitialH_SHA256(); } //-/////////////////////////////////////////////////// //- Partial SHA256 traces //-/////////////////////////////////////////////////// static lemma PartialSHA256TraceIsCorrectImpliesTraceIsCorrect(z:SHA256Trace) requires IsCompleteSHA256Trace(z); requires PartialSHA256TraceIsCorrect(z); ensures SHA256TraceIsCorrect(z); { reveal_PartialSHA256TraceHasCorrectatohsOpaque(); } //-/////////////////////////////////////////////////// //- Intermediate SHA256 state //-/////////////////////////////////////////////////// static predicate IsSHA256DoneComputingWs(z:SHA256Trace, s:SHA256_state, currentBlock:int) requires 0 <= currentBlock; { AreSHA256TraceAndStateOK(z, s) && |z.H| == currentBlock + 1 && |z.W| == currentBlock + 1 && |z.atoh| == currentBlock && (forall blk :: 0 <= blk < currentBlock ==> IsAToHWordSeqOfLen(z.atoh[blk], 65)) && s.H == z.H[currentBlock] && s.W == z.W[currentBlock] } //-/////////////////////////////////////////////////// //- Proofs that transitions between states are OK //-/////////////////////////////////////////////////// static lemma{:dafnycc_conservative_seq_triggers} lemma_SHA256TransitionOKAfterSettingHsStep1(z1:SHA256Trace, s1:SHA256_state, z2:SHA256Trace, s2:SHA256_state, currentBlock:int) requires 0 <= currentBlock; requires IsSHA256ReadyForStep(z1, s1, currentBlock, 64); requires s2.M == s1.M; requires IsWordSeqOfLen(s2.H, 8); requires forall j :: 0 <= j < 8 ==> s2.H[j] == Asm_Add(ConvertAtoHToSeq_premium(s1.atoh)[j], s1.H[j]); requires s2.num_blocks == s1.num_blocks; requires z2 == SHA256Trace_c(z1.M, z1.H + [s2.H], z1.W, z1.atoh); ensures forall blk :: 0 <= blk < |z2.H| ==> IsWordSeqOfLen(z2.H[blk], 8); ensures forall blk {:trigger TBlk(blk)} :: TBlk(blk) && 0 <= blk < currentBlock + 1 ==> IsAToHWordSeqOfLen(z2.atoh[blk], 65) && forall j :: 0 <= j < 8 ==> z2.H[blk+1][j] == Asm_Add(ConvertAtoHToSeq_premium(z2.atoh[blk][64])[j], z2.H[blk][j]); { assert |z2.H| == currentBlock + 2; forall blk | 0 <= blk < |z2.H| ensures IsWordSeqOfLen(z2.H[blk], 8); { if (blk == |z2.H|-1) { assert z2.H[blk] == s2.H; } else { assert z2.H[blk] == z1.H[blk]; } } assert forall blk {:trigger TBlk(blk)} :: TBlk(blk) && 0 <= blk < currentBlock + 1 ==> IsWordSeqOfLen(z2.H[blk+1], 8); forall blk | TBlk(blk) && 0 <= blk < currentBlock + 1 ensures IsAToHWordSeqOfLen(z2.atoh[blk], 65); ensures forall j :: 0 <= j < 8 ==> z2.H[blk+1][j] == Asm_Add(ConvertAtoHToSeq_premium(z2.atoh[blk][64])[j], z2.H[blk][j]); { assert z2.atoh[blk] == z1.atoh[blk]; if blk == currentBlock { assert IsSHA256ReadyForStep(z1, s1, currentBlock, 64); assert IsAToHWordSeqOfLen(z1.atoh[currentBlock], 64+1); assert IsAToHWordSeqOfLen(z1.atoh[blk], 65); calc { true ==> forall j :: 0 <= j < 8 ==> s2.H[j] == Asm_Add(ConvertAtoHToSeq_premium(s1.atoh)[j], s1.H[j]); ==> { assert z2.H[blk+1] == s2.H; } forall j :: 0 <= j < 8 ==> z2.H[blk+1][j] == Asm_Add(ConvertAtoHToSeq_premium(s1.atoh)[j], s1.H[j]); ==> { assert z2.atoh[blk][64] == s1.atoh; } forall j :: 0 <= j < 8 ==> z2.H[blk+1][j] == Asm_Add(ConvertAtoHToSeq_premium(z2.atoh[blk][64])[j], s1.H[j]); ==> { assert z2.H[blk] == s1.H; } forall j :: 0 <= j < 8 ==> z2.H[blk+1][j] == Asm_Add(ConvertAtoHToSeq_premium(z2.atoh[blk][64])[j], z2.H[blk][j]); } } } } static lemma {:timeLimitMultiplier 3} {:dafnycc_conservative_seq_triggers} lemma_SHA256TransitionOKAfterSettingHs(z1:SHA256Trace, s1:SHA256_state, z2:SHA256Trace, s2:SHA256_state, currentBlock:int) requires 0 <= currentBlock; requires IsSHA256ReadyForStep(z1, s1, currentBlock, 64); requires s2.M == s1.M; requires IsWordSeqOfLen(s2.H, 8); requires forall j :: 0 <= j < 8 ==> s2.H[j] == Asm_Add(ConvertAtoHToSeq_premium(s1.atoh)[j], s1.H[j]); requires s2.num_blocks == s1.num_blocks; requires z2 == SHA256Trace_c(z1.M, z1.H + [s2.H], z1.W, z1.atoh); ensures IsSHA256ReadyForBlock(z2, s2, currentBlock+1); { lemma_SHA256TransitionOKAfterSettingHsStep1(z1, s1, z2, s2, currentBlock); reveal_PartialSHA256TraceHasCorrectatohsOpaque(); } static lemma lemma_Earlier256WsAreWords(W:seq) requires IsWordSeqOfLen(W, 64); ensures forall t {:trigger TStep(t)} :: TStep(t) && 0 <= t < |W| ==> (16 <= t <= 63 ==> Word32(W[t-2]) && Word32(W[t-7]) && Word32(W[t-15]) && Word32(W[t-16])); { } static lemma lemma_SHA256TransitionOKAfterSettingWs(z1:SHA256Trace, s1:SHA256_state, z2:SHA256Trace, s2:SHA256_state, currentBlock:int) requires 0 <= currentBlock < |z1.M|; requires IsSHA256ReadyForBlock(z1, s1, currentBlock); requires IsWordSeqOfLen(s2.W, 64); requires forall t :: TStep(t) && 0 <= t <= 15 ==> s2.W[t] == z1.M[currentBlock][t]; requires forall t :: TStep(t) && 16 <= t <= 63 ==> s2.W[t] == Asm_Add(Asm_Add(Asm_Add(SSIG1(s2.W[t-2]), s2.W[t-7]), SSIG0(s2.W[t-15])), s2.W[t-16]); requires z2 == SHA256Trace_c(z1.M, z1.H, z1.W + [s2.W], z1.atoh); requires s2.M == s1.M; requires s2.H == s1.H; requires s2.num_blocks == s1.num_blocks; ensures IsSHA256DoneComputingWs(z2, s2, currentBlock); { assert z2.M == z1.M; assert z2.H == z1.H; assert |z2.W| == |z1.W| + 1; assert forall blk :: 0 <= blk < |z1.W| ==> z2.W[blk] == z1.W[blk]; assert z2.W[|z1.W|] == s2.W; assert z2.atoh == z1.atoh; forall blk | 0 <= blk < |z2.W| ensures IsWordSeqOfLen(z2.W[blk], 64); ensures forall t :: 0 <= t < |z2.W[blk]| ==> (16 <= t <= 63 ==> Word32(z2.W[blk][t-2]) && Word32(z2.W[blk][t-7]) && Word32(z2.W[blk][t-15]) && Word32(z2.W[blk][t-16])); //- ensures forall t :: t < |z2.W[blk]| ==> 16 <= t <= 63 ==> Word32(z2.W[blk][t-16]); //- ensures forall t :: t < |z2.W[blk]| ==> 16 <= t <= 63 ==> Word32(z2.W[blk][t-15]); //- ensures forall t :: t < |z2.W[blk]| ==> 16 <= t <= 63 ==> Word32(z2.W[blk][t-7]); //- ensures forall t :: t < |z2.W[blk]| ==> 16 <= t <= 63 ==> Word32(z2.W[blk][t-2]); ensures forall t {:trigger TStep(t)} :: TStep(t) && t < |z2.W[blk]| ==> (0 <= t <= 15 ==> z2.W[blk][t] == z2.M[blk][t]) && (16 <= t <= 63 ==> z2.W[blk][t] == Asm_Add(Asm_Add(Asm_Add(SSIG1(z2.W[blk][t-2]), z2.W[blk][t-7]), SSIG0(z2.W[blk][t-15])), z2.W[blk][t-16])); { if blk < |z2.W|-1 { assert IsWordSeqOfLen(z2.W[blk], 64); lemma_Earlier256WsAreWords(z2.W[blk]); assert forall t {:trigger TStep(t)} :: TStep(t) && t < |z2.W[blk]| ==> (0 <= t <= 15 ==> z2.W[blk][t] == z2.M[blk][t]) && (16 <= t <= 63 ==> z2.W[blk][t] == Asm_Add(Asm_Add(Asm_Add(SSIG1(z2.W[blk][t-2]), z2.W[blk][t-7]), SSIG0(z2.W[blk][t-15])), z2.W[blk][t-16])); } else { assert blk == |z2.W|-1; assert z2.W[blk] == s2.W; lemma_Earlier256WsAreWords(z2.W[blk]); assert forall t {:trigger TStep(t)} :: TStep(t) && t < |z2.W[blk]| ==> (0 <= t <= 15 ==> z2.W[blk][t] == z2.M[blk][t]) && (16 <= t <= 63 ==> z2.W[blk][t] == Asm_Add(Asm_Add(Asm_Add(SSIG1(z2.W[blk][t-2]), z2.W[blk][t-7]), SSIG0(z2.W[blk][t-15])), z2.W[blk][t-16])); } } reveal_PartialSHA256TraceHasCorrectatohsOpaque(); } //-/////////////////////////////////////////////////// //- Methods for performing SHA-256 calculations //-/////////////////////////////////////////////////// static method InitializeVars_SHA256(M:array, words:int, H:array, W:array) returns (a_next:int, b_next:int, c_next:int, d_next:int, e_next:int, f_next:int, g_next:int, h_next:int,ghost atoh:atoh_Type, num_blocks:int, ghost z:SHA256Trace) requires H != null && H.Length == 8; requires W != null; requires M != null; requires 0 <= words <= M.Length; requires Mod16(words) == 0; requires forall i :: 0 <= i < words ==> Word32(M[i]); ensures IsSHA256ReadyForBlock(z, SHA256_vars_to_state(M, words, H, W, atoh, num_blocks), 0); ensures |z.M| == num_blocks; requires H != M && H != W; modifies H; ensures M[..] == old(M[..]); ensures W[..] == old(W[..]); ensures atoh == atoh_c(a_next, b_next, c_next, d_next, e_next, f_next, g_next, h_next); { reveal_Mul16(); reveal_Mod16(); reveal_PartialSHA256TraceHasCorrectatohsOpaque(); InitH_SHA256(H); Lemma_AllBlocksAreOfEqualSize(M[..words], 16); Lemma_AllBlocksAreWordSeqs(M[..words], 16); z := SHA256Trace_c(BreakIntoBlocks(M[..words], 16), [H[..]], [], []); num_blocks := words / 16; atoh := atoh_c(0, 0, 0, 0, 0, 0, 0, 0); a_next, b_next, c_next, d_next, e_next, f_next, g_next, h_next := 0, 0, 0, 0, 0, 0, 0, 0; } static method ComputeWsForBlockStep1_SHA256(M:array, words:int, H:array, W:array, ghost atoh:atoh_Type, num_blocks:int, ghost z:SHA256Trace, currentBlock:int) requires H != null; requires W != null && W.Length == 64; requires M != null; requires 0 <= words <= M.Length; requires 0 <= currentBlock < |z.M|; requires IsSHA256ReadyForBlock(z, SHA256_vars_to_state(M, words, H, W, atoh, num_blocks), currentBlock); requires W != H && W != M; modifies W; ensures H[..] == old(H[..]); ensures M[..] == old(M[..]); ensures forall t :: 0 <= t < 16 ==> Word32(W[t]); ensures forall t {:trigger TStep(t)} :: TStep(t) && 0 <= t < 16 ==> W[t] == z.M[currentBlock][t]; ensures IsSHA256ReadyForBlock(z, SHA256_vars_to_state(M, words, H, W, atoh, num_blocks), currentBlock); { ghost var s := SHA256_vars_to_state(M, words, H, W, atoh, num_blocks); var t:int := 0; var m_index := currentBlock * 16; while t < 16 invariant 0 <= t <= 16; invariant m_index == currentBlock * 16 + t; invariant s.M == M[..words]; invariant forall step :: 0 <= step < t ==> Word32(W[step]); invariant forall step {:trigger TStep(step)} :: TStep(step) && 0 <= step < t ==> W[step] == z.M[currentBlock][step]; { reveal_Mul16(); calc { 0; <= { lemma_mul_nonnegative(currentBlock, 16); } currentBlock * 16; <= currentBlock * 16 + t; } calc { currentBlock * 16 + t; 16 * currentBlock + t; 16 * (currentBlock+1) - 16 + t; <= 16*|z.M| - 16 + t; < 16*|z.M|; == Mul16(|z.M|); == words; } W[t] := M[m_index]; calc { W[t]; { lemma_mul_is_mul_boogie(currentBlock, 16); Lemma_BlockedSequencePrefixContainsElement(M[..], words, 16, currentBlock, t); } BreakIntoBlocks(M[..words], 16)[currentBlock][t]; BreakIntoBlocks(s.M, 16)[currentBlock][t]; z.M[currentBlock][t]; } t := t + 1; m_index := m_index + 1; } } static method ComputeWsForBlock_SHA256_original(M:array, words:int, H:array, W:array, ghost atoh:atoh_Type, num_blocks:int, ghost z:SHA256Trace, currentBlock:int) returns (ghost next_z:SHA256Trace) requires H != null; requires W != null && W.Length == 64; requires M != null; requires 0 <= words <= M.Length; requires 0 <= currentBlock < |z.M|; requires IsSHA256ReadyForBlock(z, SHA256_vars_to_state(M, words, H, W, atoh, num_blocks), currentBlock); requires W != H && W != M; modifies W; ensures H[..] == old(H[..]); ensures M[..] == old(M[..]); ensures IsSHA256DoneComputingWs(next_z, SHA256_vars_to_state(M, words, H, W, atoh, num_blocks), currentBlock); { ghost var s := SHA256_vars_to_state(M, words, H, W, atoh, num_blocks); ComputeWsForBlockStep1_SHA256(M, words, H, W, atoh, num_blocks, z, currentBlock); ComputeWsForBlockStep2_SHA256(M, words, H, W, atoh, num_blocks, z, currentBlock); next_z := SHA256Trace_c(z.M, z.H, z.W + [W[..]], z.atoh); ghost var next_s := SHA256_vars_to_state(M, words, H, W, atoh, num_blocks); lemma_SHA256TransitionOKAfterSettingWs(z, s, next_z, next_s, currentBlock); } static method ComputeWsForBlock_SHA256_optimized(M:array, words:int, H:array, W:array, ghost atoh:atoh_Type, num_blocks:int, ghost z:SHA256Trace, currentBlock:int) returns (ghost next_z:SHA256Trace) requires H != null; requires W != null && W.Length == 64; requires M != null; requires 0 <= words <= M.Length; requires 0 <= currentBlock < |z.M|; requires IsSHA256ReadyForBlock(z, SHA256_vars_to_state(M, words, H, W, atoh, num_blocks), currentBlock); requires W != H && W != M; modifies W; ensures H[..] == old(H[..]); ensures M[..] == old(M[..]); ensures IsSHA256DoneComputingWs(next_z, SHA256_vars_to_state(M, words, H, W, atoh, num_blocks), currentBlock); { ghost var s := SHA256_vars_to_state(M, words, H, W, atoh, num_blocks); ComputeWsForBlockStep1_SHA256_optimized(M, words, H, W, atoh, num_blocks, z, currentBlock); ComputeWsForBlockStep2_SHA256(M, words, H, W, atoh, num_blocks, z, currentBlock); next_z := SHA256Trace_c(z.M, z.H, z.W + [W[..]], z.atoh); ghost var next_s := SHA256_vars_to_state(M, words, H, W, atoh, num_blocks); lemma_SHA256TransitionOKAfterSettingWs(z, s, next_z, next_s, currentBlock); } static method ComputeInitialAtoHForBlock_SHA256(M:array, words:int, H:array, W:array, ghost atoh:atoh_Type, num_blocks:int, ghost z:SHA256Trace, currentBlock:int) returns (a_next:int, b_next:int, c_next:int, d_next:int, e_next:int, f_next:int, g_next:int, h_next:int, ghost next_atoh:atoh_Type, ghost next_z:SHA256Trace) requires H != null; requires W != null; requires M != null; requires 0 <= words <= M.Length; requires 0 <= currentBlock < |z.M|; requires IsSHA256DoneComputingWs(z, SHA256_vars_to_state(M, words, H, W, atoh, num_blocks), currentBlock); ensures IsSHA256ReadyForStep(next_z, SHA256_vars_to_state(M, words, H, W, next_atoh, num_blocks), currentBlock, 0); ensures next_atoh == atoh_c(a_next, b_next, c_next, d_next, e_next, f_next, g_next, h_next); { reveal_PartialSHA256TraceHasCorrectatohsOpaque(); a_next, b_next, c_next, d_next, e_next, f_next, g_next, h_next := H[0], H[1], H[2], H[3], H[4], H[5], H[6], H[7]; next_atoh := atoh_c(H[0], H[1], H[2], H[3], H[4], H[5], H[6], H[7]); next_z := SHA256Trace_c(z.M, z.H, z.W, z.atoh + [[next_atoh]]); } static method{:dafnycc_conservative_seq_triggers} ComputeOneStep_SHA256(M:array, words:int, H:array, W:array, ghost atoh:atoh_Type, num_blocks:int, a:int, b:int, c:int, d:int, e:int, f:int, g:int, h:int, ghost z:SHA256Trace, currentBlock:int, currentStep:int) returns (a_next:int, b_next:int, c_next:int, d_next:int, e_next:int, f_next:int, g_next:int, h_next:int, ghost next_atoh:atoh_Type, ghost next_z:SHA256Trace) requires H != null; requires W != null; requires M != null; requires atoh == atoh_c(a, b, c, d, e, f, g, h); requires 0 <= words <= M.Length; requires 0 <= currentBlock < |z.M|; requires 0 <= currentStep <= 63; requires IsSHA256ReadyForStep(z, SHA256_vars_to_state(M, words, H, W, atoh, num_blocks), currentBlock, currentStep); ensures IsSHA256ReadyForStep(next_z, SHA256_vars_to_state(M, words, H, W, next_atoh, num_blocks), currentBlock, currentStep+1); ensures H[..] == old(H[..]); ensures M[..] == old(M[..]); ensures W[..] == old(W[..]); ensures next_atoh == atoh_c(a_next, b_next, c_next, d_next, e_next, f_next, g_next, h_next); { assert TBlk(currentBlock) && TBlk(currentBlock + 1) && TStep(currentStep) && TStep(currentStep + 1); ghost var s := SHA256_vars_to_state(M, words, H, W, atoh, num_blocks); var bsig0 := Asm_BitwiseXor(Asm_BitwiseXor(Asm_RotateRight(a, 2), Asm_RotateRight(a, 13)), Asm_RotateRight(a, 22)); calc { bsig0; { reveal_BSIG0(); } BSIG0(a); } var bsig1 := Asm_BitwiseXor(Asm_BitwiseXor(Asm_RotateRight(e, 6), Asm_RotateRight(e, 11)), Asm_RotateRight(e, 25)); calc { bsig1; { reveal_BSIG1(); } BSIG1(e); } var my_ch := Asm_BitwiseXor(Asm_BitwiseAnd(e, f), Asm_BitwiseAnd(Asm_BitwiseNot(e), g)); calc { my_ch; { reveal_Ch(); } Ch(e, f, g); } var my_maj := Asm_BitwiseXor(Asm_BitwiseXor(Asm_BitwiseAnd(a, b), Asm_BitwiseAnd(a, c)), Asm_BitwiseAnd(b, c)); calc { my_maj; { reveal_Maj(); } Maj(a, b, c); } var K := K_SHA256(currentStep); var T1 := Asm_Add(Asm_Add(Asm_Add(Asm_Add(h, bsig1), my_ch), K), W[currentStep]); var T2 := Asm_Add(bsig0, my_maj); a_next, b_next, c_next, d_next, e_next, f_next, g_next, h_next := Asm_Add(T1, T2), a, b, c, Asm_Add(d, T1), e, f, g; next_atoh := atoh_c(Asm_Add(T1, T2), atoh.a, atoh.b, atoh.c, Asm_Add(atoh.d, T1), atoh.e, atoh.f, atoh.g); next_z := SHA256Trace_c(z.M, z.H, z.W, z.atoh[..currentBlock] + [z.atoh[currentBlock] + [next_atoh]]); ghost var next_s := SHA256_vars_to_state(M, words, H, W, next_atoh, num_blocks); lemma_SHA256TransitionOKAfterSettingAtoH(z, s, next_z, next_s, currentBlock, currentStep); } static method{:dafnycc_conservative_seq_triggers} ComputeHsForBlockStep1_SHA256(a:int, b:int, c:int, d:int, e:int, f:int, g:int, h:int, M:array, words:int, H:array, W:array, ghost atoh:atoh_Type, num_blocks:int, ghost z:SHA256Trace, currentBlock:int) requires atoh == atoh_c(a, b, c, d, e, f, g, h); requires H != null && H.Length == 8; requires W != null; requires M != null; requires 0 <= words <= M.Length; requires 0 <= currentBlock < |z.M|; requires IsSHA256ReadyForStep(z, SHA256_vars_to_state(M, words, H, W, atoh, num_blocks), currentBlock, 64); requires H != W && H != M; modifies H; ensures W[..] == old(W[..]); ensures M[..] == old(M[..]); ensures forall j :: 0 <= j < 8 ==> Word32(H[j]) && H[j] == Asm_Add(ConvertAtoHToSeq_premium(atoh)[j], old(H[j])); { ghost var s := SHA256_vars_to_state(M, words, H, W, atoh, num_blocks); ghost var atoh_seq := ConvertAtoHToSeq_premium(atoh); H[0], H[1], H[2], H[3], H[4], H[5], H[6], H[7] := Asm_Add(a, H[0]), Asm_Add(b, H[1]), Asm_Add(c, H[2]), Asm_Add(d, H[3]), Asm_Add(e, H[4]), Asm_Add(f, H[5]), Asm_Add(g, H[6]), Asm_Add(h, H[7]); forall j | 0 <= j < 8 ensures Word32(H[j]); ensures H[j] == Asm_Add(ConvertAtoHToSeq_premium(atoh)[j], s.H[j]); ensures M[..] == old(M[..]); ensures W[..] == old(W[..]); { ghost var atoh_seq := ConvertAtoHToSeq_premium(atoh); if j == 0 { assert H[0] == Asm_Add(a, s.H[0]); } else if j == 1 { assert H[1] == Asm_Add(b, s.H[1]); } else if j == 2 { assert H[2] == Asm_Add(c, s.H[2]); } else if j == 3 { assert H[3] == Asm_Add(d, s.H[3]); } else if j == 4 { assert H[4] == Asm_Add(e, s.H[4]); } else if j == 5 { assert H[5] == Asm_Add(f, s.H[5]); } else if j == 6 { assert H[6] == Asm_Add(g, s.H[6]); } else if j == 7 { assert H[7] == Asm_Add(h, s.H[7]); } } } static method{:dafnycc_conservative_seq_triggers} ComputeHsForBlock_SHA256(M:array, words:int, H:array, W:array, ghost atoh:atoh_Type, num_blocks:int, ghost z:SHA256Trace, currentBlock:int, a:int, b:int, c:int, d:int, e:int, f:int, g:int, h:int) returns (ghost next_z:SHA256Trace) requires atoh == atoh_c(a, b, c, d, e, f, g, h); requires H != null && H.Length == 8; requires W != null; requires M != null; requires 0 <= words <= M.Length; requires 0 <= currentBlock < |z.M|; requires IsSHA256ReadyForStep(z, SHA256_vars_to_state(M, words, H, W, atoh, num_blocks), currentBlock, 64); requires H != W && H != M; modifies H; ensures W[..] == old(W[..]); ensures M[..] == old(M[..]); ensures IsSHA256ReadyForBlock(next_z, SHA256_vars_to_state(M, words, H, W, atoh, num_blocks), currentBlock+1); { ghost var s := SHA256_vars_to_state(M, words, H, W, atoh, num_blocks); ComputeHsForBlockStep1_SHA256(a, b, c, d, e, f, g, h, M, words, H, W, atoh, num_blocks, z, currentBlock); next_z := SHA256Trace_c(z.M, z.H + [H[..]], z.W, z.atoh); ghost var next_s := SHA256_vars_to_state(M, words, H, W, atoh, num_blocks); lemma_SHA256TransitionOKAfterSettingHs(z, s, next_z, next_s, currentBlock); } static method{:dafnycc_conservative_seq_triggers} PerformOneBlockOfSHA256Computation(M:array, words:int, H:array, W:array, ghost atoh:atoh_Type, num_blocks:int, ghost z:SHA256Trace, currentBlock:int) returns (ghost next_atoh:atoh_Type, ghost next_z:SHA256Trace) requires H != null && H.Length == 8; requires W != null && W.Length == 64; requires M != null; requires 0 <= words <= M.Length; requires 0 <= currentBlock < |z.M|; requires IsSHA256ReadyForBlock(z, SHA256_vars_to_state(M, words, H, W, atoh, num_blocks), currentBlock); requires W != H && W != M && H != M; modifies H; modifies W; ensures M[..] == old(M[..]); ensures IsSHA256ReadyForBlock(next_z, SHA256_vars_to_state(M, words, H, W, next_atoh, num_blocks), currentBlock+1); { var current_z := ComputeWsForBlock_SHA256_original(M, words, H, W, atoh, num_blocks, z, currentBlock); ghost var current_atoh:atoh_Type; var local_a, local_b, local_c, local_d, local_e, local_f, local_g, local_h; local_a, local_b, local_c, local_d, local_e, local_f, local_g, local_h, current_atoh, current_z := ComputeInitialAtoHForBlock_SHA256(M, words, H, W, atoh, num_blocks, current_z, currentBlock); var t := 0; while t < 64 invariant 0 <= t <= 64; invariant M[..] == old(M[..]); invariant current_atoh == atoh_c(local_a, local_b, local_c, local_d, local_e, local_f, local_g, local_h); invariant IsSHA256ReadyForStep(current_z, SHA256_vars_to_state(M, words, H, W, current_atoh, num_blocks), currentBlock, t); { local_a, local_b, local_c, local_d, local_e, local_f, local_g, local_h, current_atoh, current_z := ComputeOneStep_SHA256(M, words, H, W, current_atoh, num_blocks, local_a, local_b, local_c, local_d, local_e, local_f, local_g, local_h, current_z, currentBlock, t); t := t + 1; } current_z := ComputeHsForBlock_SHA256(M, words, H, W, current_atoh, num_blocks, current_z, currentBlock, local_a, local_b, local_c, local_d, local_e, local_f, local_g, local_h); next_atoh := current_atoh; next_z := current_z; } static method{:dafnycc_conservative_seq_triggers} PerformOneBlockOfSHA256Computation_optimized(M:array, words:int, H:array, W:array, ghost atoh:atoh_Type, num_blocks:int, ghost z:SHA256Trace, currentBlock:int) returns (ghost next_atoh:atoh_Type, ghost next_z:SHA256Trace) requires H != null && H.Length == 8; requires W != null && W.Length == 64; requires M != null; requires 0 <= words <= M.Length; requires 0 <= currentBlock < |z.M|; requires IsSHA256ReadyForBlock(z, SHA256_vars_to_state(M, words, H, W, atoh, num_blocks), currentBlock); requires W != H && W != M && H != M; modifies H; modifies W; ensures M[..] == old(M[..]); ensures IsSHA256ReadyForBlock(next_z, SHA256_vars_to_state(M, words, H, W, next_atoh, num_blocks), currentBlock+1); { var current_z := ComputeWsForBlock_SHA256_optimized(M, words, H, W, atoh, num_blocks, z, currentBlock); ghost var current_atoh:atoh_Type; var local_a, local_b, local_c, local_d, local_e, local_f, local_g, local_h; local_a, local_b, local_c, local_d, local_e, local_f, local_g, local_h, current_atoh, current_z := ComputeInitialAtoHForBlock_SHA256(M, words, H, W, atoh, num_blocks, current_z, currentBlock); local_a, local_b, local_c, local_d, local_e, local_f, local_g, local_h, current_atoh, current_z := ComputeSHA256_optimized_loop(M, words, H, W, current_atoh, num_blocks, local_a, local_b, local_c, local_d, local_e, local_f, local_g, local_h, current_z, currentBlock); current_z := ComputeHsForBlock_SHA256(M, words, H, W, current_atoh, num_blocks, current_z, currentBlock, local_a, local_b, local_c, local_d, local_e, local_f, local_g, local_h); next_atoh := current_atoh; next_z := current_z; } static lemma Lemma_IsSHA256ReadyForLastBlockImpliesTraceIsCorrect(messageBits:seq, z:SHA256Trace, s:SHA256_state) requires 0 <= s.num_blocks; requires IsSHA256ReadyForBlock(z, s, s.num_blocks); ensures SHA256TraceIsCorrect(z); { reveal_PartialSHA256TraceHasCorrectatohsOpaque(); } static lemma Lemma_IsSHA256Demonstration(messageBits:seq, hash:seq, z:SHA256Trace) requires IsBitSeq(messageBits); requires |messageBits| < power2(64); requires IsCompleteSHA256Trace(z); requires z.M == BlockMessageForSHA(PadMessageForSHA_premium(messageBits)); requires SHA256TraceIsCorrect(z); requires hash == z.H[|z.M|]; ensures IsSHA256(messageBits, hash); { } static lemma Lemma_MessageInSHA256TraceCorrespondsToMessageInArray(M:array, words:int, messageBits:seq, z:SHA256Trace) requires M != null; requires 0 <= words <= M.Length; requires Mod16(words) == 0; requires forall i :: 0 <= i < words ==> Word32(M[i]); requires IsBitSeq(messageBits); requires |messageBits| < power2(64); requires BEWordSeqToBitSeq(M[..words]) == PadMessageForSHA(messageBits); requires z.M == BreakIntoBlocks(M[..words], 16); ensures z.M == BlockMessageForSHA(PadMessageForSHA_premium(messageBits)); { assert |BEWordSeqToBitSeq_premium(M[..words])| == words * 32; calc { z.M; BreakIntoBlocks(M[..words], 16); { reveal_power2(); lemma_BEDigitSeqToInt_invertibility(power2(32), BEDigitSeqToInt_premium(power2(32), M[..words]), M[..words]); } BreakIntoBlocks(BEIntToDigitSeq(power2(32), words, BEWordSeqToInt_premium(M[..words])), 16); { lemma_BEBitSeqToInt_BEWordSeqToBitSeq(M[..words]); } BreakIntoBlocks(BEIntToDigitSeq(power2(32), words, BEBitSeqToInt(BEWordSeqToBitSeq(M[..words]))), 16); BreakIntoBlocks(BEIntToDigitSeq(power2(32), words, BEBitSeqToInt(PadMessageForSHA(messageBits))), 16); { lemma_mul_is_mul_boogie(words, 32); lemma_div_by_multiple(words, 32); assert (words*32)/32 == words; } BreakIntoBlocks(BEIntToDigitSeq(power2(32), (words*32)/32, BEBitSeqToInt(PadMessageForSHA(messageBits))), 16); BreakIntoBlocks(BEIntToDigitSeq(power2(32), |BEWordSeqToBitSeq_premium(M[..words])|/32, BEBitSeqToInt(PadMessageForSHA(messageBits))), 16); BreakIntoBlocks(BEIntToDigitSeq(power2(32), |PadMessageForSHA(messageBits)|/32, BEBitSeqToInt(PadMessageForSHA(messageBits))), 16); { reveal_BlockMessageForSHA(); lemma_PadMessageForSHA_properties(messageBits); } BlockMessageForSHA(PadMessageForSHA(messageBits)); } } static lemma Lemma_ComputeSHA256AfterPadding(M:array, words:int, ghost messageBits:seq, z:SHA256Trace, s:SHA256_state, hash:seq) requires M != null; requires 0 <= words <= M.Length; requires Mod16(words) == 0; requires forall i :: 0 <= i < words ==> Word32(M[i]); requires IsBitSeq(messageBits); requires |messageBits| < power2(64); requires BEWordSeqToBitSeq(M[..words]) == PadMessageForSHA(messageBits); requires s.M == M[..words]; requires s.H == hash; requires 0 <= s.num_blocks; requires IsSHA256ReadyForBlock(z, s, s.num_blocks); ensures IsSHA256(messageBits, hash); { Lemma_MessageInSHA256TraceCorrespondsToMessageInArray(M, words, messageBits, z); Lemma_IsSHA256ReadyForLastBlockImpliesTraceIsCorrect(messageBits, z, s); Lemma_IsSHA256Demonstration(messageBits, hash, z); } static method{:dafnycc_conservative_seq_triggers} ComputeSHA256AfterPadding_arrays_original(M:array, words:int, ghost messageBits:seq) returns (hash:array) requires M != null; requires 0 <= words <= M.Length; requires Mod16(words) == 0; requires forall i :: 0 <= i < words ==> Word32(M[i]); requires IsBitSeq(messageBits); requires |messageBits| < power2(64); requires BEWordSeqToBitSeq(M[..words]) == PadMessageForSHA(messageBits); ensures hash!=null; ensures IsSHA256(messageBits, hash[..]); { //- Initialize arrays for use in computing SHA. var H := new int[8]; var W := new int[64]; //- Initialize state to get ready for first block. ghost var atoh:atoh_Type; var local_a, local_b, local_c, local_d, local_e, local_f, local_g, local_h; var num_blocks:int; ghost var z:SHA256Trace; local_a, local_b, local_c, local_d, local_e, local_f, local_g, local_h, atoh, num_blocks, z := InitializeVars_SHA256(M, words, H, W); //- Loop through the blocks one at a time. var currentBlock:int := 0; while currentBlock < num_blocks invariant 0 <= currentBlock <= num_blocks; invariant M[..] == old(M[..]); invariant BEWordSeqToBitSeq(M[..words]) == PadMessageForSHA(messageBits); invariant IsSHA256ReadyForBlock(z, SHA256_vars_to_state(M, words, H, W, atoh, num_blocks), currentBlock); { atoh, z := PerformOneBlockOfSHA256Computation(M, words, H, W, atoh, num_blocks, z, currentBlock); currentBlock := currentBlock + 1; } //- The final value of H is the desired hash. hash := H; //- The following is a proof that the hash is correct. Lemma_ComputeSHA256AfterPadding(M, words, messageBits, z, SHA256_vars_to_state(M, words, H, W, atoh, num_blocks), hash[..]); } static method{:dafnycc_conservative_seq_triggers} ComputeSHA256AfterPadding_arrays_optimized(M:array, words:int, ghost messageBits:seq) returns (hash:array) requires M != null; requires 0 <= words <= M.Length; requires Mod16(words) == 0; requires forall i :: 0 <= i < words ==> Word32(M[i]); requires IsBitSeq(messageBits); requires |messageBits| < power2(64); requires BEWordSeqToBitSeq(M[..words]) == PadMessageForSHA(messageBits); ensures hash!=null; ensures IsSHA256(messageBits, hash[..]); { //- Initialize arrays for use in computing SHA. var H := new int[8]; var W := new int[64]; //- Initialize state to get ready for first block. ghost var atoh:atoh_Type; var local_a, local_b, local_c, local_d, local_e, local_f, local_g, local_h; var num_blocks:int; ghost var z:SHA256Trace; local_a, local_b, local_c, local_d, local_e, local_f, local_g, local_h, atoh, num_blocks, z := InitializeVars_SHA256(M, words, H, W); //- Loop through the blocks one at a time. var currentBlock:int := 0; while currentBlock < num_blocks invariant 0 <= currentBlock <= num_blocks; invariant M[..] == old(M[..]); invariant BEWordSeqToBitSeq(M[..words]) == PadMessageForSHA(messageBits); invariant IsSHA256ReadyForBlock(z, SHA256_vars_to_state(M, words, H, W, atoh, num_blocks), currentBlock); { atoh, z := PerformOneBlockOfSHA256Computation_optimized(M, words, H, W, atoh, num_blocks, z, currentBlock); currentBlock := currentBlock + 1; } //- The final value of H is the desired hash. hash := H; //- The following is a proof that the hash is correct. Lemma_ComputeSHA256AfterPadding(M, words, messageBits, z, SHA256_vars_to_state(M, words, H, W, atoh, num_blocks), hash[..]); } static method{:dafnycc_conservative_seq_triggers} ComputeSHA256AfterPadding_original(M:array, words:int, ghost messageBits:seq) returns (hash:seq) requires M != null; requires 0 <= words <= M.Length; requires Mod16(words) == 0; requires forall i :: 0 <= i < words ==> Word32(M[i]); requires IsBitSeq(messageBits); requires |messageBits| < power2(64); requires BEWordSeqToBitSeq(M[..words]) == PadMessageForSHA(messageBits); ensures IsSHA256(messageBits, hash); { var H := ComputeSHA256AfterPadding_arrays_original(M, words, messageBits); hash := H[..]; } static method{:dafnycc_conservative_seq_triggers} ComputeSHA256AfterPadding_optimized(M:array, words:int, ghost messageBits:seq) returns (hash:seq) requires M != null; requires 0 <= words <= M.Length; requires Mod16(words) == 0; requires forall i :: 0 <= i < words ==> Word32(M[i]); requires IsBitSeq(messageBits); requires |messageBits| < power2(64); requires BEWordSeqToBitSeq(M[..words]) == PadMessageForSHA(messageBits); ensures IsSHA256(messageBits, hash); { var H := ComputeSHA256AfterPadding_arrays_optimized(M, words, messageBits); hash := H[..]; } static method {:timeLimitMultiplier 5} {:dafnycc_conservative_seq_triggers} SHA256_impl_ArrayInPlace(M:array, bits:int) returns (hash:seq) requires IsWordArray(M); requires Word32(bits); requires 0 <= bits < power2(64); requires 0 <= PaddedLength(bits) <= M.Length * 32; ensures bits <= M.Length * 32; ensures IsWordSeqOfLen(hash, 8); ensures IsSHA256(old(BEWordSeqToBitSeq_premium(M[..])[..bits]), hash); ensures hash == SHA256(old(BEWordSeqToBitSeq_premium(M[..])[..bits])); modifies M; { calc <= { bits; { lemma_PaddedLength_properties(bits); } |BEWordSeqToBitSeq_premium(M[..])|; } ghost var messageBits := BEWordSeqToBitSeq_premium(M[..])[..bits]; PadMessageArray(M, bits); var words := PaddedLength(bits)/32; calc { PadMessageForSHA(messageBits); BEWordSeqToBitSeq_premium(M[..])[..PaddedLength(bits)]; { lemma_PaddedLength_properties(bits); } BEWordSeqToBitSeq_premium(M[..])[..words*32]; { lemma_WordSeqToBitSeqChop(M[..], M[..words], M[words..]); } (BEWordSeqToBitSeq_premium(M[..words]) + BEWordSeqToBitSeq_premium(M[words..]))[..words*32]; BEWordSeqToBitSeq_premium(M[..words])[..words*32]; BEWordSeqToBitSeq_premium(M[..words]); } lemma_mod_words(bits, words); hash := ComputeSHA256AfterPadding_optimized(M, words, messageBits); lemma_SHA256IsAFunction(old(BEWordSeqToBitSeq_premium(M[..])[..bits]), hash); } static method SHA256_impl_Bytes(messageBytes:seq) returns (hash:seq) requires Word32(|messageBytes|*8); requires |messageBytes|*8 < power2(64); requires IsByteSeq(messageBytes); ensures IsWordSeqOfLen(hash, 8); ensures IsSHA256(BEByteSeqToBitSeq_premium(messageBytes), hash); ensures hash == SHA256(BEByteSeqToBitSeq_premium(messageBytes)); { var M, bits := CreateArrayForSHA(messageBytes); hash := SHA256_impl_ArrayInPlace(M, bits); lemma_SHA256IsAFunction(BEByteSeqToBitSeq_premium(messageBytes), hash); } static method SHA256_impl_Bytes_arrays_original(messageBytes:array) returns (hash:array) requires messageBytes != null; requires Word32(messageBytes.Length*8); requires messageBytes.Length*8 < power2(64); requires IsByteSeq(messageBytes[..]); ensures hash != null; ensures IsWordSeqOfLen(hash[..], 8); ensures IsSHA256(BEByteSeqToBitSeq_premium(messageBytes[..]), hash[..]); ensures hash[..] == SHA256(BEByteSeqToBitSeq_premium(messageBytes[..])); ensures messageBytes[..] == old(messageBytes[..]); { var M, bits := CreateArrayForSHA_arrays(messageBytes); ghost var Minput_seq := M[..]; assert BEByteSeqToBitSeq_premium(messageBytes[..]) == BEWordSeqToBitSeq(Minput_seq)[..bits]; ghost var messageBits := BEWordSeqToBitSeq_premium(M[..])[..bits]; PadMessageArray(M, bits); var words := PaddedLength(bits)/32; calc { PadMessageForSHA(messageBits); BEWordSeqToBitSeq_premium(M[..])[..PaddedLength(bits)]; { lemma_PaddedLength_properties(bits); } BEWordSeqToBitSeq_premium(M[..])[..words*32]; { lemma_WordSeqToBitSeqChop(M[..], M[..words], M[words..]); } (BEWordSeqToBitSeq_premium(M[..words]) + BEWordSeqToBitSeq_premium(M[words..]))[..words*32]; BEWordSeqToBitSeq_premium(M[..words])[..words*32]; BEWordSeqToBitSeq_premium(M[..words]); } lemma_mod_words(bits, words); hash := ComputeSHA256AfterPadding_arrays_original(M, words, messageBits); ghost var hash_seq := hash[..]; ghost var messageBytes_seq := old(messageBytes)[..]; assert IsSHA256(messageBits, hash_seq); lemma_SHA_impl_Bytes_arrays_bitmangle(old(messageBytes), messageBytes_seq, messageBits, Minput_seq, bits); assert IsSHA256(BEByteSeqToBitSeq_premium(messageBytes_seq), hash_seq); lemma_SHA256IsAFunction(BEByteSeqToBitSeq_premium(messageBytes_seq), hash_seq); } static method SHA256_impl_Words_arrays_original(messageWords:array) returns (hash:array) requires messageWords != null; requires Word32(messageWords.Length*32); requires messageWords.Length*32 < power2(64); requires IsWordSeq(messageWords[..]); ensures hash != null; ensures IsWordSeqOfLen(hash[..], 8); ensures IsSHA256(BEWordSeqToBitSeq_premium(messageWords[..]), hash[..]); ensures hash[..] == SHA256(BEWordSeqToBitSeq_premium(messageWords[..])); ensures messageWords[..] == old(messageWords[..]); { var M, bits := CreateArrayForSHA_arrays_words(messageWords); ghost var Minput_seq := M[..]; assert BEWordSeqToBitSeq_premium(messageWords[..]) == BEWordSeqToBitSeq(Minput_seq)[..bits]; ghost var messageBits := BEWordSeqToBitSeq_premium(M[..])[..bits]; PadMessageArray(M, bits); var words := PaddedLength(bits)/32; calc { PadMessageForSHA(messageBits); BEWordSeqToBitSeq_premium(M[..])[..PaddedLength(bits)]; { lemma_PaddedLength_properties(bits); } BEWordSeqToBitSeq_premium(M[..])[..words*32]; { lemma_WordSeqToBitSeqChop(M[..], M[..words], M[words..]); } (BEWordSeqToBitSeq_premium(M[..words]) + BEWordSeqToBitSeq_premium(M[words..]))[..words*32]; BEWordSeqToBitSeq_premium(M[..words])[..words*32]; BEWordSeqToBitSeq_premium(M[..words]); } lemma_mod_words(bits, words); hash := ComputeSHA256AfterPadding_arrays_original(M, words, messageBits); ghost var hash_seq := hash[..]; ghost var messageWords_seq := old(messageWords)[..]; assert IsSHA256(messageBits, hash_seq); lemma_SHA_impl_Words_arrays_bitmangle(old(messageWords), messageWords_seq, messageBits, Minput_seq, bits); assert IsSHA256(BEWordSeqToBitSeq_premium(messageWords_seq), hash_seq); lemma_SHA256IsAFunction(BEWordSeqToBitSeq_premium(messageWords_seq), hash_seq); } static method SHA256_impl_Bytes_arrays(messageBytes:array) returns (hash:array) requires messageBytes != null; requires Word32(messageBytes.Length*8); requires messageBytes.Length*8 < power2(64); requires IsByteSeq(messageBytes[..]); ensures hash != null; ensures IsWordSeqOfLen(hash[..], 8); ensures IsSHA256(BEByteSeqToBitSeq_premium(messageBytes[..]), hash[..]); ensures hash[..] == SHA256(BEByteSeqToBitSeq_premium(messageBytes[..])); ensures messageBytes[..] == old(messageBytes[..]); { var M, bits := CreateArrayForSHA_arrays(messageBytes); ghost var Minput_seq := M[..]; assert BEByteSeqToBitSeq_premium(messageBytes[..]) == BEWordSeqToBitSeq(Minput_seq)[..bits]; ghost var messageBits := BEWordSeqToBitSeq_premium(M[..])[..bits]; PadMessageArray(M, bits); var words := PaddedLength(bits)/32; calc { PadMessageForSHA(messageBits); BEWordSeqToBitSeq_premium(M[..])[..PaddedLength(bits)]; { lemma_PaddedLength_properties(bits); } BEWordSeqToBitSeq_premium(M[..])[..words*32]; { lemma_WordSeqToBitSeqChop(M[..], M[..words], M[words..]); } (BEWordSeqToBitSeq_premium(M[..words]) + BEWordSeqToBitSeq_premium(M[words..]))[..words*32]; BEWordSeqToBitSeq_premium(M[..words])[..words*32]; BEWordSeqToBitSeq_premium(M[..words]); } lemma_mod_words(bits, words); hash := ComputeSHA256AfterPadding_arrays_optimized(M, words, messageBits); ghost var hash_seq := hash[..]; ghost var messageBytes_seq := old(messageBytes)[..]; assert IsSHA256(messageBits, hash_seq); lemma_SHA_impl_Bytes_arrays_bitmangle(old(messageBytes), messageBytes_seq, messageBits, Minput_seq, bits); assert IsSHA256(BEByteSeqToBitSeq_premium(messageBytes_seq), hash_seq); lemma_SHA256IsAFunction(BEByteSeqToBitSeq_premium(messageBytes_seq), hash_seq); } static method SHA256_impl_Words_arrays(messageWords:array) returns (hash:array) requires messageWords != null; requires Word32(messageWords.Length*32); requires messageWords.Length*32 < power2(64); requires IsWordSeq(messageWords[..]); ensures hash != null; ensures IsWordSeqOfLen(hash[..], 8); ensures IsSHA256(BEWordSeqToBitSeq_premium(messageWords[..]), hash[..]); ensures hash[..] == SHA256(BEWordSeqToBitSeq_premium(messageWords[..])); ensures messageWords[..] == old(messageWords[..]); { var M, bits := CreateArrayForSHA_arrays_words(messageWords); ghost var Minput_seq := M[..]; assert BEWordSeqToBitSeq_premium(messageWords[..]) == BEWordSeqToBitSeq(Minput_seq)[..bits]; ghost var messageBits := BEWordSeqToBitSeq_premium(M[..])[..bits]; PadMessageArray(M, bits); var words := PaddedLength(bits)/32; calc { PadMessageForSHA(messageBits); BEWordSeqToBitSeq_premium(M[..])[..PaddedLength(bits)]; { lemma_PaddedLength_properties(bits); } BEWordSeqToBitSeq_premium(M[..])[..words*32]; { lemma_WordSeqToBitSeqChop(M[..], M[..words], M[words..]); } (BEWordSeqToBitSeq_premium(M[..words]) + BEWordSeqToBitSeq_premium(M[words..]))[..words*32]; BEWordSeqToBitSeq_premium(M[..words])[..words*32]; BEWordSeqToBitSeq_premium(M[..words]); } lemma_mod_words(bits, words); hash := ComputeSHA256AfterPadding_arrays_optimized(M, words, messageBits); ghost var hash_seq := hash[..]; ghost var messageWords_seq := old(messageWords)[..]; assert IsSHA256(messageBits, hash_seq); lemma_SHA_impl_Words_arrays_bitmangle(old(messageWords), messageWords_seq, messageBits, Minput_seq, bits); assert IsSHA256(BEWordSeqToBitSeq_premium(messageWords_seq), hash_seq); lemma_SHA256IsAFunction(BEWordSeqToBitSeq_premium(messageWords_seq), hash_seq); } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Crypto/Hash/sha256.s.dfy ================================================ include "sha_common.s.dfy" include "hmac_common.s.dfy" static function method{:opaque} K_SHA256(t: int) : int requires 0 <= t <= 63; ensures Word32(K_SHA256(t)); { /*call_lemma:*/lemma_power2_32(); if t < 8 then OneOf8(t - 0 , 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5) else if t < 16 then OneOf8(t - 8 , 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174) else if t < 24 then OneOf8(t - 16, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da) else if t < 32 then OneOf8(t - 24, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967) else if t < 40 then OneOf8(t - 32, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85) else if t < 48 then OneOf8(t - 40, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070) else if t < 56 then OneOf8(t - 48, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3) else OneOf8(t - 56, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2) /* causes excessive run-time allocation in current dafnycc implementation: [0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2][t] */ } static function method{:opaque} InitialH_SHA256(j: int) : int requires 0 <= j <= 7; ensures Word32(InitialH_SHA256(j)); { /*call_lemma:*/lemma_power2_32(); OneOf8(j, 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19) //- [0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19][j] } //- The fields of a SHA256Trace have the following meanings: //- //- M[blk][i] = word #i of message block #blk //- W[blk][t] = W_t during processing of message block #blk //- H[blk][j] = H_j before processing message block #blk //- atoh[blk][t].a = a before step t of processing of message block #blk //- ... //- atoh[blk][t].h = h before step t of processing message block #blk datatype atoh_Type = atoh_c(a:int, b:int, c:int, d:int, e:int, f:int, g:int, h:int); datatype SHA256Trace = SHA256Trace_c(M:seq>, H:seq>, W:seq>, atoh:seq>); static predicate IsAToHWordSeqOfLen(vs:seq, len:int) { |vs| == len && forall i :: 0 <= i < len ==> Word32(vs[i].a) && Word32(vs[i].b) && Word32(vs[i].c) && Word32(vs[i].d) && Word32(vs[i].e) && Word32(vs[i].f) && Word32(vs[i].g) && Word32(vs[i].h) } static function ConvertAtoHToSeq(v:atoh_Type) : seq { [v.a, v.b, v.c, v.d, v.e, v.f, v.g, v.h] } static predicate IsCompleteSHA256Trace(z:SHA256Trace) { (forall i :: 0 <= i < |z.M| ==> IsWordSeqOfLen(z.M[i], 16)) && |z.H| == |z.M| + 1 && |z.W| == |z.atoh| == |z.M| && (forall blk :: 0 <= blk < |z.M| ==> IsWordSeqOfLen(z.W[blk], 64)) && (forall blk :: 0 <= blk < |z.M| ==> IsAToHWordSeqOfLen(z.atoh[blk], 65)) && (forall blk :: 0 <= blk <= |z.M| ==> IsWordSeqOfLen(z.H[blk], 8)) } static predicate SHA256TraceHasCorrectHs(z:SHA256Trace) requires IsCompleteSHA256Trace(z); { (forall j :: 0 <= j < 8 ==> z.H[0][j] == InitialH_SHA256(j)) && (forall blk {:trigger TBlk(blk)} :: TBlk(blk) ==> forall j :: 0 <= blk < |z.M| && 0 <= j < 8 ==> z.H[blk+1][j] == Add32(ConvertAtoHToSeq(z.atoh[blk][64])[j], z.H[blk][j])) } static predicate SHA256TraceHasCorrectWs(z:SHA256Trace) requires IsCompleteSHA256Trace(z); { forall blk :: 0 <= blk < |z.M| ==> forall t {:trigger TStep(t)} :: TStep(t) ==> (0 <= t <= 15 ==> z.W[blk][t] == z.M[blk][t]) && (16 <= t <= 63 ==> z.W[blk][t] == Add32(Add32(Add32(SSIG1(z.W[blk][t-2]), z.W[blk][t-7]), SSIG0(z.W[blk][t-15])), z.W[blk][t-16])) } static predicate SHA256TraceHasCorrectatohs(z:SHA256Trace) requires IsCompleteSHA256Trace(z); { forall blk :: 0 <= blk < |z.M| ==> ConvertAtoHToSeq(z.atoh[blk][0]) == z.H[blk] && forall t {:trigger TStep(t)} :: TStep(t) && 0 <= t <= 63 ==> (var T1 := Add32(Add32(Add32(Add32(z.atoh[blk][t].h, BSIG1(z.atoh[blk][t].e)), Ch(z.atoh[blk][t].e, z.atoh[blk][t].f, z.atoh[blk][t].g)), K_SHA256(t)), z.W[blk][t]); var T2 := Add32(BSIG0(z.atoh[blk][t].a), Maj(z.atoh[blk][t].a, z.atoh[blk][t].b, z.atoh[blk][t].c)); z.atoh[blk][t+1].h == z.atoh[blk][t].g && z.atoh[blk][t+1].g == z.atoh[blk][t].f && z.atoh[blk][t+1].f == z.atoh[blk][t].e && z.atoh[blk][t+1].e == Add32(z.atoh[blk][t].d, T1) && z.atoh[blk][t+1].d == z.atoh[blk][t].c && z.atoh[blk][t+1].c == z.atoh[blk][t].b && z.atoh[blk][t+1].b == z.atoh[blk][t].a && z.atoh[blk][t+1].a == Add32(T1, T2)) } static predicate {:autoReq} SHA256TraceIsCorrect(z:SHA256Trace) { SHA256TraceHasCorrectHs(z) && SHA256TraceHasCorrectWs(z) && SHA256TraceHasCorrectatohs(z) } static predicate {:autoReq} IsSHA256(messageBits:seq, hash:seq) { exists z:SHA256Trace :: IsCompleteSHA256Trace(z) && z.M == BlockMessageForSHA(PadMessageForSHA(messageBits)) && SHA256TraceIsCorrect(z) && hash == z.H[|z.M|] } static function {:axiom} SHA256(messageBits:seq) : seq requires IsBitSeq(messageBits); requires |messageBits| < power2(64); ensures IsWordSeqOfLen(SHA256(messageBits), 8); static lemma {:axiom} lemma_SHA256IsAFunction(messageBits:seq, hash:seq) requires IsBitSeq(messageBits); requires |messageBits| < power2(64); requires IsWordSeqOfLen(hash, 8); requires IsSHA256(messageBits, hash); ensures SHA256(messageBits) == hash; static function {:autoReq} HMAC_SHA256(k:seq, m:seq) : seq { SHA256(SeqXor(k, Opad(512)) + BEWordSeqToBitSeq(SHA256(SeqXor(k, Ipad(512)) + m))) } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Crypto/Hash/sha256_hmac.i.dfy ================================================ include "sha_common.s.dfy" include "hmac_common.s.dfy" include "sha256.i.dfy" include "hmac_common.i.dfy" include "../../Util/arrays_and_seqs.i.dfy" method HMAC_SHA256_inner_hash(key: array, data: array, len: int) returns (hash: array) requires Word32(len); requires IsWordArray(key); requires key.Length == 16; requires len <= power2(32) - 1 - 512; requires IsWordArray(data); requires 0 <= data.Length; requires 0 <= len <= data.Length * 32; ensures fresh(hash); ensures key[..] == old(key[..]); ensures data[..] == old(data[..]); ensures IsWordArray(hash); ensures Mod32_const(512) == 0; ensures IsSHA256(SeqXor_premium(BEWordSeqToBitSeq_premium(key[..]), Ipad_premium(512)) + BEWordSeqToBitSeq_premium(data[..])[..len], hash[..]); { var input := HMAC_inner_input(key, data, len); assert data[..] == old(data[..]); assert key[..] == old(key[..]); lemma_2toX(); ghost var old_input := BEWordSeqToBitSeq_premium(input[..])[..len+512]; calc { old_input; BEWordSeqToBitSeq_premium(input[..])[..len+512]; (SeqXor_premium(BEWordSeqToBitSeq_premium(key[..]), Ipad_premium(512)) + BEWordSeqToBitSeq_premium(data[..]) + BEWordSeqToBitSeq_premium(input[16+data.Length..]))[..len+512]; { assert |SeqXor_premium(BEWordSeqToBitSeq_premium(key[..]), Ipad_premium(512))| == 512; } { assert |BEWordSeqToBitSeq_premium(data[..])| >= len; } //- == |data[..]|*32; SeqXor_premium(BEWordSeqToBitSeq_premium(key[..]), Ipad_premium(512)) + BEWordSeqToBitSeq_premium(data[..])[..len]; } var hash_seq := SHA256_impl_ArrayInPlace(input, len+512); hash := SeqToArray(hash_seq); lemma_Mod32_const(512); } method HMAC_SHA256_impl_Array(key: array, data: array, len: int) returns (hash: seq) requires Word32(len); requires IsWordArray(key); requires key.Length == 16; requires len <= power2(32) - 1 - 512; requires data != null; requires 0 <= len <= data.Length * 32; requires IsWordArray(data); ensures IsWordSeqOfLen(hash, 8); ensures key[..] == old(key[..]); ensures data[..] == old(data[..]); ensures var k := BEWordSeqToBitSeq_premium(key[..]); var m := BEWordSeqToBitSeq_premium(data[..])[..len]; IsBitSeqOfLen(k, 512) && IsBitSeqOfLen(Ipad(512), 512) && IsBitSeq(SeqXor(k, Ipad(512)) + m) && |SeqXor(k, Ipad(512)) + m| < power2(64) && IsBitSeqOfLen(Opad(512), 512) && IsBitSeq(SeqXor(k, Opad(512)) + BEWordSeqToBitSeq(SHA256(SeqXor(k, Ipad(512)) + m))) && |SeqXor(k, Opad(512)) + BEWordSeqToBitSeq(SHA256(SeqXor(k, Ipad(512)) + m))| < power2(64) && hash == HMAC_SHA256(k, m); { var inner_hash := HMAC_SHA256_inner_hash(key, data, len); assert key[..] == old( key[..]); assert data[..] == old(data[..]); lemma_2toX(); reveal_Mod32_const(); lemma_SHA256IsAFunction(SeqXor_premium(BEWordSeqToBitSeq_premium(key[..]), Ipad_premium(512)) + BEWordSeqToBitSeq_premium(data[..])[..len], inner_hash[..]); assert inner_hash[..] == SHA256(SeqXor_premium(BEWordSeqToBitSeq_premium(key[..]), Ipad_premium(512)) + BEWordSeqToBitSeq_premium(data[..])[..len]); ghost var old_inner_hash := inner_hash[..]; var input := HMAC_outer_input(key, inner_hash); assert old_inner_hash == inner_hash[..]; assert key[..] == old( key[..]); assert data[..] == old(data[..]); ghost var original_input := input[..]; var bit_len := 32*(key.Length + inner_hash.Length); assert old_inner_hash == inner_hash[..]; assert key[..] == old( key[..]); assert data[..] == old(data[..]); assert input[..] == original_input; ghost var old_input := BEWordSeqToBitSeq_premium(input[..])[..bit_len]; calc { old_input; BEWordSeqToBitSeq_premium(input[..])[..bit_len]; (SeqXor_premium(BEWordSeqToBitSeq_premium(key[..]), Opad_premium(512)) + BEWordSeqToBitSeq_premium(inner_hash[..]) + BEWordSeqToBitSeq_premium(input[16+8..]))[..bit_len]; (SeqXor_premium(BEWordSeqToBitSeq_premium(key[..]), Opad_premium(512)) + BEWordSeqToBitSeq_premium(inner_hash[..]))[..bit_len]; SeqXor_premium(BEWordSeqToBitSeq_premium(key[..]), Opad_premium(512)) + BEWordSeqToBitSeq_premium(inner_hash[..]); SeqXor_premium(BEWordSeqToBitSeq_premium(key[..]), Opad_premium(512)) + BEWordSeqToBitSeq_premium(SHA256(SeqXor_premium(BEWordSeqToBitSeq_premium(key[..]), Ipad_premium(512)) + BEWordSeqToBitSeq_premium(data[..])[..len])); } hash := SHA256_impl_ArrayInPlace(input, bit_len); assert hash == SHA256(old_input); assert old_inner_hash == inner_hash[..]; assert key[..] == old( key[..]); assert data[..] == old(data[..]); ghost var k := BEWordSeqToBitSeq_premium(key[..]); ghost var m := BEWordSeqToBitSeq_premium(data[..])[..len]; calc { hash; SHA256(old_input); SHA256(SeqXor_premium(BEWordSeqToBitSeq_premium(key[..]), Opad_premium(512)) + BEWordSeqToBitSeq_premium(SHA256(SeqXor_premium(BEWordSeqToBitSeq_premium(key[..]), Ipad_premium(512)) + BEWordSeqToBitSeq_premium(data[..])[..len]))); { assert BEWordSeqToBitSeq_premium(key[..])[..key.Length*32] == BEWordSeqToBitSeq_premium(key[..]); } SHA256(SeqXor_premium(k, Opad_premium(|k|)) + BEWordSeqToBitSeq_premium(SHA256(SeqXor_premium(k, Ipad_premium(|k|)) + m))); HMAC_SHA256(k, m); } } method HMAC_SHA256_impl_Seqs(keyBytes: seq, dataBytes: seq) returns (hash: seq) requires Word32(|dataBytes|*8); requires IsByteSeq(keyBytes); requires |keyBytes| <= 64; requires |dataBytes|*8 <= power2(32) - 1 - 512; requires IsByteSeq(dataBytes); ensures IsWordSeqOfLen(hash, 8); ensures var k := BEByteSeqToBitSeq_premium(keyBytes + RepeatDigit_premium(0, 64 - |keyBytes|)); var m := BEByteSeqToBitSeq_premium(dataBytes); IsBitSeqOfLen(k, 512) && IsBitSeqOfLen(Ipad(512), 512) && IsBitSeq(SeqXor(k, Ipad(512)) + m) && |SeqXor(k, Ipad(512)) + m| < power2(64) && IsBitSeqOfLen(Opad(512), 512) && IsBitSeq(SeqXor(k, Opad(512)) + BEWordSeqToBitSeq(SHA256(SeqXor(k, Ipad(512)) + m))) && |SeqXor(k, Opad(512)) + BEWordSeqToBitSeq(SHA256(SeqXor(k, Ipad(512)) + m))| < power2(64) && hash == HMAC_SHA256(k, m); { var requiredKeyBytePadding := RepeatDigit_impl(0, 64 - |keyBytes|); var keyBytesPadded := keyBytes + requiredKeyBytePadding; var keyWords, padbytes := BEByteSeqToWordSeq_impl(keyBytesPadded); var keyArray := SeqToArray(keyWords); var dataWords := BEByteSeqToWordSeqTailPadding(dataBytes); var dataArray := SeqToArray(dataWords); var len := |dataBytes|*8; calc { len; |dataBytes|*8; <= |BEWordSeqToBitSeq_premium(dataWords)|; |dataWords| * 32; dataArray.Length * 32; } calc { keyArray.Length; |keyWords|; |keyBytesPadded| / 4; (|keyBytes| + 64 - |keyBytes|) / 4; 64 / 4; 16; } hash := HMAC_SHA256_impl_Array(keyArray, dataArray, len); lemma_2toX(); ghost var k := BEByteSeqToBitSeq_premium(keyBytesPadded); ghost var m := BEByteSeqToBitSeq_premium(dataBytes); reveal_Mod32_const(); assert IsBitSeqOfLen(k, 512); assert IsBitSeqOfLen(Ipad_premium(512), 512); assert IsBitSeq(SeqXor_premium(k, Ipad_premium(512)) + m); assert |SeqXor_premium(k, Ipad_premium(512)) + m| < power2(64); assert IsBitSeqOfLen(Opad_premium(512), 512); assert IsBitSeq(SeqXor_premium(k, Opad_premium(512)) + BEWordSeqToBitSeq_premium(SHA256(SeqXor_premium(k, Ipad_premium(512)) + m))); assert |SeqXor_premium(k, Opad_premium(512)) + BEWordSeqToBitSeq_premium(SHA256(SeqXor_premium(k, Ipad_premium(512)) + m))| < power2(64); calc { hash; HMAC_SHA256(BEWordSeqToBitSeq_premium(keyArray[..]), BEWordSeqToBitSeq_premium(dataArray[..])[..len]); { assert keyWords == keyArray[..]; } HMAC_SHA256(BEWordSeqToBitSeq_premium(keyWords), BEWordSeqToBitSeq_premium(dataArray[..])[..len]); HMAC_SHA256(k, BEWordSeqToBitSeq_premium(dataArray[..])[..len]); HMAC_SHA256(k, BEByteSeqToBitSeq_premium(dataBytes)); HMAC_SHA256(k, m); } } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Crypto/Hash/sha256common.i.dfy ================================================ //- Stuff shared by sha256.i.dfy and sha256opt.i.dfy include "sha256.s.dfy" include "../../Util/seq_blocking.i.dfy" include "../../Util/arrays_and_seqs.i.dfy" include "../../Util/integer_sequences_premium.i.dfy" include "sha_padding.i.dfy" include "sha_common.i.dfy" include "../../../Drivers/CPU/assembly_premium.i.dfy" static predicate Word32AtoH(v:atoh_Type) { Word32(v.a) && Word32(v.b) && Word32(v.c) && Word32(v.d) && Word32(v.e) && Word32(v.f) && Word32(v.g) && Word32(v.h) } static predicate IsAToHWordSeq(vs:seq) { forall i :: 0 <= i < |vs| ==> Word32AtoH(vs[i]) } //-/////////////////////////////////////////////////// //- Intermediate SHA256 state //-/////////////////////////////////////////////////// datatype SHA256_state = SHA256_state_c(M:seq, H:seq, W:seq, atoh:atoh_Type, num_blocks:int); static function SHA256_vars_to_state(M:array, words:int, H:array, W:array, atoh:atoh_Type, num_blocks:int) : SHA256_state requires M != null && H != null && W != null; requires 0 <= words <= M.Length; reads M, H, W; { SHA256_state_c(M[..words], H[..], W[..], atoh, num_blocks) } static predicate PartialSHA256TraceHasCorrectHs(z:SHA256Trace) { |z.H| > 0 && |z.H| <= |z.atoh|+1 && (forall blk :: 0 <= blk < |z.H| ==> IsWordSeqOfLen(z.H[blk], 8)) && (forall j :: 0 <= j < 8 ==> z.H[0][j] == InitialH_SHA256(j)) && (forall blk {:trigger TBlk(blk)} :: TBlk(blk) && 0 <= blk < |z.H|-1 ==> IsAToHWordSeqOfLen(z.atoh[blk], 65) && forall j :: 0 <= j < 8 ==> z.H[blk+1][j] == Add32(ConvertAtoHToSeq(z.atoh[blk][64])[j], z.H[blk][j])) } static predicate PartialSHA256TraceHasCorrectWs(z:SHA256Trace) { |z.W| <= |z.M| && forall blk :: 0 <= blk < |z.W| ==> IsWordSeqOfLen(z.W[blk], 64) && IsWordSeqOfLen(z.M[blk], 16) && forall t {:trigger TStep(t)} :: TStep(t) && 0 <= t < 64 ==> (0 <= t <= 15 ==> z.W[blk][t] == z.M[blk][t]) && (16 <= t <= 63 ==> z.W[blk][t] == Add32(Add32(Add32(SSIG1(z.W[blk][t-2]), z.W[blk][t-7]), SSIG0(z.W[blk][t-15])), z.W[blk][t-16])) } static predicate PartialSHA256TraceHasCorrectatohsWf(z:SHA256Trace) { |z.atoh| <= |z.H| && |z.atoh| <= |z.W| && (forall blk :: 0 <= blk < |z.atoh|-1 ==> IsAToHWordSeqOfLen(z.atoh[blk], 65)) && forall blk :: 0 <= blk < |z.atoh| ==> |z.atoh[blk]| <= 65 && IsWordSeqOfLen(z.W[blk], 64) && IsAToHWordSeq(z.atoh[blk]) && (|z.atoh[blk]| > 0 ==> IsWordSeqOfLen(z.H[blk], 8) && ConvertAtoHToSeq(z.atoh[blk][0]) == z.H[blk]) } static predicate{:opaque} PartialSHA256TraceHasCorrectatohsOpaque(z:SHA256Trace) { |z.atoh| <= |z.H| && |z.atoh| <= |z.W| && (forall blk :: 0 <= blk < |z.atoh|-1 ==> IsAToHWordSeqOfLen(z.atoh[blk], 65)) && forall blk :: 0 <= blk < |z.atoh| ==> |z.atoh[blk]| <= 65 && IsWordSeqOfLen(z.W[blk], 64) && IsAToHWordSeq(z.atoh[blk]) && (|z.atoh[blk]| > 0 ==> IsWordSeqOfLen(z.H[blk], 8) && ConvertAtoHToSeq(z.atoh[blk][0]) == z.H[blk]) && forall t {:trigger TStep(t)} :: TStep(t) && 0 <= t < |z.atoh[blk]|-1 ==> var T1 := Add32(Add32(Add32(Add32(z.atoh[blk][t].h, BSIG1(z.atoh[blk][t].e)), Ch(z.atoh[blk][t].e, z.atoh[blk][t].f, z.atoh[blk][t].g)), K_SHA256(t)), z.W[blk][t]); var T2 := Add32(BSIG0(z.atoh[blk][t].a), Maj(z.atoh[blk][t].a, z.atoh[blk][t].b, z.atoh[blk][t].c)); z.atoh[blk][t+1].h == z.atoh[blk][t].g && z.atoh[blk][t+1].g == z.atoh[blk][t].f && z.atoh[blk][t+1].f == z.atoh[blk][t].e && z.atoh[blk][t+1].e == Add32(z.atoh[blk][t].d, T1) && z.atoh[blk][t+1].d == z.atoh[blk][t].c && z.atoh[blk][t+1].c == z.atoh[blk][t].b && z.atoh[blk][t+1].b == z.atoh[blk][t].a && z.atoh[blk][t+1].a == Add32(T1, T2) } static predicate PartialSHA256TraceHasCorrectatohs(z:SHA256Trace) { PartialSHA256TraceHasCorrectatohsWf(z) && PartialSHA256TraceHasCorrectatohsOpaque(z) } static predicate PartialSHA256TraceIsCorrect(z:SHA256Trace) { PartialSHA256TraceHasCorrectWs(z) && PartialSHA256TraceHasCorrectHs(z) && PartialSHA256TraceHasCorrectatohs(z) } static predicate AreSHA256TraceAndStateOK(z:SHA256Trace, s:SHA256_state) { PartialSHA256TraceIsCorrect(z) && IsWordSeq(s.M) && z.M == BreakIntoBlocks(s.M, 16) && (forall i :: 0 <= i < |z.M| ==> IsWordSeqOfLen(z.M[i], 16)) && Mul16(|z.M|) == |s.M| && |z.M| == s.num_blocks } static predicate IsSHA256ReadyForBlock(z:SHA256Trace, s:SHA256_state, nextBlock:int) requires 0 <= nextBlock; { AreSHA256TraceAndStateOK(z, s) && |z.H| == nextBlock + 1 && |z.W| == nextBlock && |z.atoh| == nextBlock && (forall blk :: 0 <= blk < nextBlock ==> IsAToHWordSeqOfLen(z.atoh[blk], 65)) && s.H == z.H[nextBlock] } static predicate{:opaque} TheAToHsAreOK(z:SHA256Trace, blk: int, t: int) requires 0 <= t <= 63; requires 0 <= blk; requires |z.atoh| > blk; requires |z.atoh[blk]| > t+1; requires Word32AtoH(z.atoh[blk][t]); requires |z.W| > blk; requires IsWordSeqOfLen(z.W[blk], 64); { var T1 := Add32(Add32(Add32(Add32(z.atoh[blk][t].h, BSIG1(z.atoh[blk][t].e)), Ch(z.atoh[blk][t].e, z.atoh[blk][t].f, z.atoh[blk][t].g)), K_SHA256(t)), z.W[blk][t]); var T2 := Add32(BSIG0(z.atoh[blk][t].a), Maj(z.atoh[blk][t].a, z.atoh[blk][t].b, z.atoh[blk][t].c)); z.atoh[blk][t+1].h == z.atoh[blk][t].g && z.atoh[blk][t+1].g == z.atoh[blk][t].f && z.atoh[blk][t+1].f == z.atoh[blk][t].e && z.atoh[blk][t+1].e == Add32(z.atoh[blk][t].d, T1) && z.atoh[blk][t+1].d == z.atoh[blk][t].c && z.atoh[blk][t+1].c == z.atoh[blk][t].b && z.atoh[blk][t+1].b == z.atoh[blk][t].a && z.atoh[blk][t+1].a == Add32(T1, T2) } static predicate IsSHA256ReadyForStep(z:SHA256Trace, s:SHA256_state, currentBlock:int, nextStep:int) requires 0 <= currentBlock; requires 0 <= nextStep <= 64; { AreSHA256TraceAndStateOK(z, s) && |z.H| == currentBlock + 1 && |z.W| == currentBlock + 1 && |z.atoh| == currentBlock + 1 && (forall blk :: 0 <= blk < currentBlock ==> IsAToHWordSeqOfLen(z.atoh[blk], 65)) && IsAToHWordSeqOfLen(z.atoh[currentBlock], nextStep+1) && s.H == z.H[currentBlock] && s.W == z.W[currentBlock] && s.atoh == z.atoh[currentBlock][nextStep] } static lemma lemma_SHA256TransitionOKAfterSettingAtoHStep1Helper1(z:SHA256Trace, blk:int, t:int) requires 0 <= t <= 63; requires 0 <= blk; requires |z.atoh| > blk; requires |z.atoh[blk]| > t+1; requires Word32AtoH(z.atoh[blk][t]); requires |z.W| > blk; requires IsWordSeqOfLen(z.W[blk], 64); requires PartialSHA256TraceHasCorrectatohs(z); ensures TheAToHsAreOK(z, blk, t); { assert TBlk(blk) && TStep(t); reveal_TheAToHsAreOK(); reveal_PartialSHA256TraceHasCorrectatohsOpaque(); } static lemma Lemma_TheAToHsAreOKIsStable(z1:SHA256Trace, z2:SHA256Trace, blk: int, t: int) requires 0 <= t <= 63; requires 0 <= blk; requires |z1.atoh| == |z2.atoh| > blk; requires |z1.atoh[blk]| > t+1; requires |z2.atoh[blk]| > t+1; requires Word32AtoH(z1.atoh[blk][t]); requires z1.atoh[blk][t+1] == z2.atoh[blk][t+1]; requires z1.atoh[blk][t] == z2.atoh[blk][t]; requires |z1.W| > blk; requires z1.W == z2.W; requires IsWordSeqOfLen(z1.W[blk], 64); requires TheAToHsAreOK(z1, blk, t); ensures TheAToHsAreOK(z2, blk, t); { reveal_TheAToHsAreOK(); } static lemma {:timeLimitMultiplier 2} lemma_SHA256TransitionOKAfterSettingAtoHStep1(z1:SHA256Trace, s1:SHA256_state, z2:SHA256Trace, s2:SHA256_state, currentBlock:int, currentStep:int) requires TBlk(currentBlock) && TBlk(currentBlock + 1) && TStep(currentStep) && TStep(currentStep + 1); requires 0 <= currentBlock < |z1.M|; requires 0 <= currentStep <= 63; requires IsSHA256ReadyForStep(z1, s1, currentBlock, currentStep); requires var T1 := Asm_Add(Asm_Add(Asm_Add(Asm_Add(s1.atoh.h, BSIG1(s1.atoh.e)), Ch(s1.atoh.e, s1.atoh.f, s1.atoh.g)), K_SHA256(currentStep)), s1.W[currentStep]); var T2 := Asm_Add(BSIG0(s1.atoh.a), Maj(s1.atoh.a, s1.atoh.b, s1.atoh.c)); s2.atoh.h == s1.atoh.g && s2.atoh.g == s1.atoh.f && s2.atoh.f == s1.atoh.e && s2.atoh.e == Asm_Add(s1.atoh.d, T1) && s2.atoh.d == s1.atoh.c && s2.atoh.c == s1.atoh.b && s2.atoh.b == s1.atoh.a && s2.atoh.a == Asm_Add(T1, T2); requires s2.M == s1.M; requires s2.H == s1.H; requires s2.W == s1.W; requires s2.num_blocks == s1.num_blocks; requires z2.M == z1.M && z2.H == z1.H && z2.W == z1.W; requires z2.atoh == z1.atoh[..currentBlock] + [z1.atoh[currentBlock] + [s2.atoh]]; requires |z2.atoh| == |z1.atoh|; requires forall blk :: 0 <= blk < currentBlock ==> z2.atoh[blk] == z1.atoh[blk]; requires forall t :: 0 <= t < |z1.atoh[currentBlock]| ==> z2.atoh[currentBlock][t] == z1.atoh[currentBlock][t]; requires z2.atoh[currentBlock][|z1.atoh[currentBlock]|] == s2.atoh; ensures forall blk :: 0 <= blk < |z2.atoh| ==> |z2.atoh[blk]| <= |z2.W[blk]| + 1 && |z2.atoh[blk]| <= 65 && IsWordSeq(z2.W[blk]) && IsAToHWordSeq(z2.atoh[blk]) && (|z2.atoh[blk]| > 0 ==> IsWordSeqOfLen(z2.H[blk], 8) && ConvertAtoHToSeq(z2.atoh[blk][0]) == z2.H[blk]) && (forall t :: 0 <= t < |z2.atoh[blk]|-1 ==> TheAToHsAreOK(z2, blk, t)); { forall blk | TBlk(blk) && 0 <= blk < |z2.atoh| ensures |z2.atoh[blk]| <= |z2.W[blk]| + 1; ensures |z2.atoh[blk]| <= 65; ensures IsWordSeq(z2.W[blk]); ensures IsAToHWordSeq(z2.atoh[blk]); ensures (|z2.atoh[blk]| > 0 ==> IsWordSeqOfLen(z2.H[blk], 8) && ConvertAtoHToSeq(z2.atoh[blk][0]) == z2.H[blk]); ensures forall t :: 0 <= t < |z2.atoh[blk]|-1 ==> TheAToHsAreOK(z2, blk, t); { assert |z2.atoh[blk]| <= |z2.W[blk]| + 1; assert |z2.atoh[blk]| <= 65; assert IsWordSeq(z2.W[blk]); if blk < |z2.atoh|-1 { assert blk < currentBlock; assert z2.atoh[blk] == z1.atoh[blk]; assert IsAToHWordSeq(z2.atoh[blk]); assert (|z2.atoh[blk]| > 0 ==> IsWordSeqOfLen(z2.H[blk], 8) && ConvertAtoHToSeq(z2.atoh[blk][0]) == z2.H[blk]); forall t | 0 <= t < |z1.atoh[blk]|-1 ensures TheAToHsAreOK(z2, blk, t); { lemma_SHA256TransitionOKAfterSettingAtoHStep1Helper1(z1, blk, t); Lemma_TheAToHsAreOKIsStable(z1, z2, blk, t); } assert forall t :: 0 <= t < |z2.atoh[blk]|-1 ==> TheAToHsAreOK(z2, blk, t); } else { assert blk == currentBlock; assert IsAToHWordSeq(z2.atoh[blk]); assert (|z2.atoh[blk]| > 0 ==> IsWordSeqOfLen(z2.H[blk], 8) && ConvertAtoHToSeq(z2.atoh[blk][0]) == z2.H[blk]); forall t | 0 <= t < |z2.atoh[blk]|-1 ensures TheAToHsAreOK(z2, blk, t); { if t < |z2.atoh[blk]|-2 { assert t < currentStep; lemma_SHA256TransitionOKAfterSettingAtoHStep1Helper1(z1, blk, t); Lemma_TheAToHsAreOKIsStable(z1, z2, blk, t); assert TheAToHsAreOK(z2, blk, t); } else { assert t == currentStep; calc { true; { reveal_TheAToHsAreOK(); } TheAToHsAreOK(z2, blk, t); } } } } } } static lemma{:dafnycc_conservative_seq_triggers} lemma_SHA256TransitionOKAfterSettingAtoH(z1:SHA256Trace, s1:SHA256_state, z2:SHA256Trace, s2:SHA256_state, currentBlock:int, currentStep:int) requires TBlk(currentBlock) && TBlk(currentBlock + 1) && TStep(currentStep) && TStep(currentStep + 1); requires 0 <= currentBlock < |z1.M|; requires 0 <= currentStep <= 63; requires IsSHA256ReadyForStep(z1, s1, currentBlock, currentStep); requires var T1 := Asm_Add(Asm_Add(Asm_Add(Asm_Add(s1.atoh.h, BSIG1(s1.atoh.e)), Ch(s1.atoh.e, s1.atoh.f, s1.atoh.g)), K_SHA256(currentStep)), s1.W[currentStep]); var T2 := Asm_Add(BSIG0(s1.atoh.a), Maj(s1.atoh.a, s1.atoh.b, s1.atoh.c)); s2.atoh.h == s1.atoh.g && s2.atoh.g == s1.atoh.f && s2.atoh.f == s1.atoh.e && s2.atoh.e == Asm_Add(s1.atoh.d, T1) && s2.atoh.d == s1.atoh.c && s2.atoh.c == s1.atoh.b && s2.atoh.b == s1.atoh.a && s2.atoh.a == Asm_Add(T1, T2); requires s2.M == s1.M; requires s2.H == s1.H; requires s2.W == s1.W; requires s2.num_blocks == s1.num_blocks; requires z2 == SHA256Trace_c(z1.M, z1.H, z1.W, z1.atoh[..currentBlock] + [z1.atoh[currentBlock] + [s2.atoh]]); ensures IsSHA256ReadyForStep(z2, s2, currentBlock, currentStep+1); { lemma_SHA256TransitionOKAfterSettingAtoHStep1(z1, s1, z2, s2, currentBlock, currentStep); assert forall blk :: 0 <= blk < |z2.atoh| ==> |z2.atoh[blk]| <= |z2.W[blk]| + 1 && |z2.atoh[blk]| <= 65 && IsWordSeq(z2.W[blk]) && IsAToHWordSeq(z2.atoh[blk]) && (|z2.atoh[blk]| > 0 ==> IsWordSeqOfLen(z2.H[blk], 8) && ConvertAtoHToSeq(z2.atoh[blk][0]) == z2.H[blk]) && (forall t :: 0 <= t < |z2.atoh[blk]|-1 ==> TheAToHsAreOK(z2, blk, t)); forall blk | 0 <= blk < |z2.atoh| ensures IsAToHWordSeq(z2.atoh[blk]); ensures forall t {:trigger TStep(t)} :: TStep(t) && 0 <= t < |z2.atoh[blk]|-1 ==> Word32AtoH(z2.atoh[blk][t]) && var T1 := Asm_Add(Asm_Add(Asm_Add(Asm_Add(z2.atoh[blk][t].h, BSIG1(z2.atoh[blk][t].e)), Ch(z2.atoh[blk][t].e, z2.atoh[blk][t].f, z2.atoh[blk][t].g)), K_SHA256(t)), z2.W[blk][t]); var T2 := Asm_Add(BSIG0(z2.atoh[blk][t].a), Maj(z2.atoh[blk][t].a, z2.atoh[blk][t].b, z2.atoh[blk][t].c)); z2.atoh[blk][t+1].h == z2.atoh[blk][t].g && z2.atoh[blk][t+1].g == z2.atoh[blk][t].f && z2.atoh[blk][t+1].f == z2.atoh[blk][t].e && z2.atoh[blk][t+1].e == Asm_Add(z2.atoh[blk][t].d, T1) && z2.atoh[blk][t+1].d == z2.atoh[blk][t].c && z2.atoh[blk][t+1].c == z2.atoh[blk][t].b && z2.atoh[blk][t+1].b == z2.atoh[blk][t].a && z2.atoh[blk][t+1].a == Asm_Add(T1, T2); { forall t {:trigger TStep(t)} | TStep(t) && 0 <= t < |z2.atoh[blk]|-1 ensures Word32AtoH(z2.atoh[blk][t]); ensures var T1 := Asm_Add(Asm_Add(Asm_Add(Asm_Add(z2.atoh[blk][t].h, BSIG1(z2.atoh[blk][t].e)), Ch(z2.atoh[blk][t].e, z2.atoh[blk][t].f, z2.atoh[blk][t].g)), K_SHA256(t)), z2.W[blk][t]); var T2 := Asm_Add(BSIG0(z2.atoh[blk][t].a), Maj(z2.atoh[blk][t].a, z2.atoh[blk][t].b, z2.atoh[blk][t].c)); z2.atoh[blk][t+1].h == z2.atoh[blk][t].g && z2.atoh[blk][t+1].g == z2.atoh[blk][t].f && z2.atoh[blk][t+1].f == z2.atoh[blk][t].e && z2.atoh[blk][t+1].e == Asm_Add(z2.atoh[blk][t].d, T1) && z2.atoh[blk][t+1].d == z2.atoh[blk][t].c && z2.atoh[blk][t+1].c == z2.atoh[blk][t].b && z2.atoh[blk][t+1].b == z2.atoh[blk][t].a && z2.atoh[blk][t+1].a == Asm_Add(T1, T2); { assert TheAToHsAreOK(z2, blk, t); reveal_TheAToHsAreOK(); } } reveal_PartialSHA256TraceHasCorrectatohsOpaque(); } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Crypto/Hash/sha256opt.i.dfy ================================================ //- HAND-OPTIMIZED PIECES of SHA 256 include "sha256.s.dfy" include "../../Util/seq_blocking.i.dfy" include "../../Util/arrays_and_seqs.i.dfy" include "../../Util/integer_sequences_premium.i.dfy" include "sha_padding.i.dfy" include "sha_common.i.dfy" include "sha256common.i.dfy" include "../../../Drivers/CPU/assembly_premium.i.dfy" static method InitK_SHA256(Ks: array) requires Ks != null && Ks.Length == 64; ensures forall i :: 0 <= i < Ks.Length ==> Ks[i] == K_SHA256(i); modifies Ks; { InitK_SHA256_0_to_10(Ks); } static method {:decl} InitK_SHA256_0_to_10(Ks: array) requires Ks != null && Ks.Length == 64; modifies Ks; ensures forall i :: 0 <= i < 64 ==> Ks[i] == K_SHA256(i); static method {:decl} ComputeWsForBlockStep2_SHA256(M:array, words:int, H:array, W:array, ghost atoh:atoh_Type, num_blocks:int, ghost z:SHA256Trace, currentBlock:int) requires H != null; requires W != null && W.Length == 64; requires M != null; requires 0 <= words <= M.Length; requires 0 <= currentBlock < |z.M|; requires IsSHA256ReadyForBlock(z, SHA256_vars_to_state(M, words, H, W, atoh, num_blocks), currentBlock); requires forall t :: 0 <= t < 16 ==> Word32(W[t]); requires forall t {:trigger TStep(t)} :: TStep(t) && 0 <= t < 16 ==> W[t] == z.M[currentBlock][t]; requires W != H && W != M; modifies W; ensures H[..] == old(H[..]); ensures M[..] == old(M[..]); ensures forall t :: 0 <= t <= 63 ==> Word32(W[t]); ensures forall t {:trigger TStep(t)} :: TStep(t) && 0 <= t < 16 ==> W[t] == z.M[currentBlock][t]; ensures forall t {:trigger TStep(t)} :: TStep(t) && 16 <= t <= 63 ==> W[t] == Asm_Add(Asm_Add(Asm_Add(SSIG1(W[t-2]), W[t-7]), SSIG0(W[t-15])), W[t-16]); //-{ //- var t := 16; //- while t < 64 //- invariant 16 <= t <= 64; //- invariant forall step :: 0 <= step < t ==> Word32(W[step]); //- invariant forall step {:trigger TStep(step)} :: TStep(step) && 0 <= step < 16 ==> W[step] == z.M[currentBlock][step]; //- invariant forall step {:trigger TStep(step)} :: TStep(step) && 16 <= step < t ==> //- W[step] == Asm_Add(Asm_Add(Asm_Add(SSIG1(W[step-2]), W[step-7]), SSIG0(W[step-15])), W[step-16]); //- { //- W[t] := Asm_Add(Asm_Add(Asm_Add(SSIG1_impl(W[t-2]), W[t-7]), SSIG0_impl(W[t-15])), W[t-16]); //- t := t + 1; //- } //-} ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Crypto/Hash/sha256opt2.i.dfy ================================================ //- OPTIMIZED VERSION include "sha256.s.dfy" include "../../Util/seq_blocking.i.dfy" include "../../Util/arrays_and_seqs.i.dfy" include "../../Util/integer_sequences_premium.i.dfy" include "sha_padding.i.dfy" include "sha_common.i.dfy" include "sha256opt.i.dfy" include "sha256common.i.dfy" include "../../../Drivers/CPU/assembly_premium.i.dfy" /* static method{:dafnycc_conservative_seq_triggers} ComputeOneStep_SHA256_optimized(M:array, words:int, H:array, W:array, ghost atoh:atoh_Type, num_blocks:int, a:int, b:int, c:int, d:int, e:int, f:int, g:int, h:int, ghost z:SHA256Trace, currentBlock:int, currentStep:int, K:int) returns (a_next:int, b_next:int, c_next:int, d_next:int, e_next:int, f_next:int, g_next:int, h_next:int, ghost next_atoh:atoh_Type, ghost next_z:SHA256Trace) requires H != null; requires W != null; requires M != null; requires atoh == atoh_c(a, b, c, d, e, f, g, h); requires 0 <= words <= M.Length; requires 0 <= currentBlock < |z.M|; requires 0 <= currentStep <= 63; requires K == K_SHA256(currentStep); requires IsSHA256ReadyForStep(z, SHA256_vars_to_state(M, words, H, W, atoh, num_blocks), currentBlock, currentStep); ensures IsSHA256ReadyForStep(next_z, SHA256_vars_to_state(M, words, H, W, next_atoh, num_blocks), currentBlock, currentStep+1); ensures H[..] == old(H[..]); ensures M[..] == old(M[..]); ensures W[..] == old(W[..]); ensures next_atoh == atoh_c(a_next, b_next, c_next, d_next, e_next, f_next, g_next, h_next); */ /* { assert TBlk(currentBlock) && TBlk(currentBlock + 1) && TStep(currentStep) && TStep(currentStep + 1); ghost var s := SHA256_vars_to_state(M, words, H, W, Ks, atoh, num_blocks); var bsig0 := Asm_BitwiseXor(Asm_BitwiseXor(Asm_RotateRight(a, 2), Asm_RotateRight(a, 13)), Asm_RotateRight(a, 22)); calc { bsig0; { reveal_BSIG0(); } BSIG0(a); } var bsig1 := Asm_BitwiseXor(Asm_BitwiseXor(Asm_RotateRight(e, 6), Asm_RotateRight(e, 11)), Asm_RotateRight(e, 25)); calc { bsig1; { reveal_BSIG1(); } BSIG1(e); } var my_ch := Asm_BitwiseXor(Asm_BitwiseAnd(e, f), Asm_BitwiseAnd(Asm_BitwiseNot(e), g)); calc { my_ch; { reveal_Ch(); } Ch(e, f, g); } var my_maj := Asm_BitwiseXor(Asm_BitwiseXor(Asm_BitwiseAnd(a, b), Asm_BitwiseAnd(a, c)), Asm_BitwiseAnd(b, c)); calc { my_maj; { reveal_Maj(); } Maj(a, b, c); } var T1 := Asm_Add(Asm_Add(Asm_Add(Asm_Add(h, bsig1), my_ch), Ks[currentStep]), W[currentStep]); var T2 := Asm_Add(bsig0, my_maj); a_next, b_next, c_next, d_next, e_next, f_next, g_next, h_next := Asm_Add(T1, T2), a, b, c, Asm_Add(d, T1), e, f, g; next_atoh := atoh_c(Asm_Add(T1, T2), atoh.a, atoh.b, atoh.c, Asm_Add(atoh.d, T1), atoh.e, atoh.f, atoh.g); next_z := SHA256Trace_c(z.M, z.H, z.W, z.atoh[..currentBlock] + [z.atoh[currentBlock] + [next_atoh]]); ghost var next_s := SHA256_vars_to_state(M, words, H, W, Ks, next_atoh, num_blocks); lemma_SHA256TransitionOKAfterSettingAtoH(z, s, next_z, next_s, currentBlock, currentStep); } */ static method{:dafnycc_conservative_seq_triggers}{:decl} ComputeSHA256_optimized_loop(M:array, words:int, H:array, W:array, ghost atoh:atoh_Type, num_blocks:int, a:int, b:int, c:int, d:int, e:int, f:int, g:int, h:int, ghost z:SHA256Trace, currentBlock:int) returns (a_final:int, b_final:int, c_final:int, d_final:int, e_final:int, f_final:int, g_final:int, h_final:int, ghost final_atoh:atoh_Type, ghost final_z:SHA256Trace) requires H != null && H.Length == 8; requires W != null && W.Length == 64; requires M != null; requires 0 <= words <= M.Length; requires 0 <= currentBlock < |z.M|; //-requires IsSHA256ReadyForBlock(z, SHA256_vars_to_state(M, words, H, W, atoh, num_blocks), currentBlock); requires IsSHA256ReadyForStep(z, SHA256_vars_to_state(M, words, H, W, atoh, num_blocks), currentBlock, 0); requires W != H && W != M && H != M; requires atoh == atoh_c(a, b, c, d, e, f, g, h); ensures M[..] == old(M[..]); ensures H[..] == old(H[..]); ensures W[..] == old(W[..]); ensures IsSHA256ReadyForStep(final_z, SHA256_vars_to_state(M, words, H, W, final_atoh, num_blocks), currentBlock, 64); //-ensures IsSHA256ReadyForBlock(next_z, SHA256_vars_to_state(M, words, H, W, next_atoh, num_blocks), currentBlock+1); ensures final_atoh == atoh_c(a_final, b_final, c_final, d_final, e_final, f_final, g_final, h_final); static method {:decl} ComputeWsForBlockStep1_SHA256_optimized(M:array, words:int, H:array, W:array, ghost atoh:atoh_Type, num_blocks:int, ghost z:SHA256Trace, currentBlock:int) requires H != null; requires W != null && W.Length == 64; requires M != null; requires 0 <= words <= M.Length; requires 0 <= currentBlock < |z.M|; requires IsSHA256ReadyForBlock(z, SHA256_vars_to_state(M, words, H, W, atoh, num_blocks), currentBlock); requires W != H && W != M; modifies W; ensures H[..] == old(H[..]); ensures M[..] == old(M[..]); ensures forall t :: 0 <= t < 16 ==> Word32(W[t]); ensures forall t {:trigger TStep(t)} :: TStep(t) && 0 <= t < 16 ==> W[t] == z.M[currentBlock][t]; ensures IsSHA256ReadyForBlock(z, SHA256_vars_to_state(M, words, H, W, atoh, num_blocks), currentBlock); //-{ //- ghost var s := SHA256_vars_to_state(M, words, H, W, atoh, num_blocks); //- //- var t:int := 0; //- var m_index := currentBlock * 16; //- while t < 16 //- invariant 0 <= t <= 16; //- invariant m_index == currentBlock * 16 + t; //- invariant s.M == M[..words]; //- invariant forall step :: 0 <= step < t ==> Word32(W[step]); //- invariant forall step {:trigger TStep(step)} :: TStep(step) && 0 <= step < t ==> W[step] == z.M[currentBlock][step]; //- { //- reveal_Mul16(); //- calc { //- 0; //- <= { lemma_mul_nonnegative(currentBlock, 16); } //- currentBlock * 16; //- <= currentBlock * 16 + t; //- } //- calc { //- currentBlock * 16 + t; //- 16 * currentBlock + t; //- 16 * (currentBlock+1) - 16 + t; //- <= 16*|z.M| - 16 + t; //- < 16*|z.M|; //- == Mul16(|z.M|); //- == words; //- } //- W[t] := M[m_index]; //- calc { //- W[t]; //- { lemma_mul_is_mul_boogie(currentBlock, 16); //- Lemma_BlockedSequencePrefixContainsElement(M[..], words, 16, currentBlock, t); } //- BreakIntoBlocks(M[..words], 16)[currentBlock][t]; //- BreakIntoBlocks(s.M, 16)[currentBlock][t]; //- z.M[currentBlock][t]; //- } //- t := t + 1; //- m_index := m_index + 1; //- } //-} ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Crypto/Hash/sha_common.i.dfy ================================================ include "../../base.s.dfy" include "../../../Drivers/CPU/assembly.s.dfy" include "../../../Drivers/CPU/assembly_premium.i.dfy" include "../../Util/integer_sequences.s.dfy" include "../../Util/seq_blocking.s.dfy" include "sha_common.s.dfy" static function method{:CompiledSpec} CompiledSpec_NumPaddingZeroes(message_len: int) : int static function method{:CompiledSpec} CompiledSpec_OneOf8(i: int, n0: int, n1: int, n2: int, n3: int, n4: int, n5: int, n6: int, n7: int) : int static function{:opaque} Mul16(i:int):int { i * 16 } static function{:opaque} Mod16(i:int):int { i % 16 } //-/////////////////////////////////////////////////// //- Ch, Maj, BSIG0, BSIG1, SSIG0, SSIG1 //-/////////////////////////////////////////////////// static function method Ch_impl(x: int, y: int, z: int) : int requires Word32(x); requires Word32(y); requires Word32(z); ensures Word32(Ch_impl(x, y, z)); ensures Ch_impl(x, y, z) == Ch(x, y, z); { reveal_Ch(); Asm_BitwiseXor(Asm_BitwiseAnd(x, y), Asm_BitwiseAnd(Asm_BitwiseNot(x), z)) } static function method Maj_impl(x: int, y: int, z: int) : int requires Word32(x); requires Word32(y); requires Word32(z); ensures Word32(Maj_impl(x, y, z)); ensures Maj_impl(x, y, z) == Maj(x, y, z); { reveal_Maj(); Asm_BitwiseXor(Asm_BitwiseXor(Asm_BitwiseAnd(x, y), Asm_BitwiseAnd(x, z)), Asm_BitwiseAnd(y, z)) } static function method Parity_impl(x: int, y: int, z: int) : int requires Word32(x); requires Word32(y); requires Word32(z); ensures Word32(Parity_impl(x, y, z)); ensures Parity_impl(x, y, z) == Parity(x, y, z); { reveal_Parity(); Asm_BitwiseXor(Asm_BitwiseXor(x, y), z) } static function method ft_impl(t: int, x: int, y: int, z: int) : int requires 0 <= t <= 79; requires Word32(x); requires Word32(y); requires Word32(z); ensures Word32(ft_impl(t, x, y, z)); ensures ft_impl(t, x, y, z) == ft(t, x, y, z); { reveal_ft(); if t >= 0 && t <= 19 then Ch_impl(x, y, z) else if t >= 40 && t <= 59 then Maj_impl(x, y, z) else Parity_impl(x, y, z) } static function method BSIG0_impl(x: int) : int requires Word32(x); ensures Word32(BSIG0_impl(x)); ensures BSIG0_impl(x) == BSIG0(x); { reveal_BSIG0(); Asm_BitwiseXor(Asm_BitwiseXor(Asm_RotateRight(x, 2), Asm_RotateRight(x, 13)), Asm_RotateRight(x, 22)) } static function method BSIG1_impl(x: int) : int requires Word32(x); ensures Word32(BSIG1_impl(x)); ensures BSIG1_impl(x) == BSIG1(x); { reveal_BSIG1(); Asm_BitwiseXor(Asm_BitwiseXor(Asm_RotateRight(x, 6), Asm_RotateRight(x, 11)), Asm_RotateRight(x, 25)) } static function method SSIG0_impl(x: int) : int requires Word32(x); ensures Word32(SSIG0_impl(x)); ensures SSIG0_impl(x) == SSIG0(x); { reveal_SSIG0(); Asm_BitwiseXor(Asm_BitwiseXor(Asm_RotateRight(x, 7), Asm_RotateRight(x, 18)), Asm_RightShift(x, 3)) } static function method SSIG1_impl(x: int) : int requires Word32(x); ensures Word32(SSIG1_impl(x)); ensures SSIG1_impl(x) == SSIG1(x); { reveal_SSIG1(); Asm_BitwiseXor(Asm_BitwiseXor(Asm_RotateRight(x, 17), Asm_RotateRight(x, 19)), Asm_RightShift(x, 10)) } static lemma lemma_SHA_impl_Bytes_arrays_bitmangle(messageBytes:array, messageBytes_seq:seq, messageBits:seq, M_seq:seq, bits:int) requires messageBytes!=null; requires IsWordSeq(M_seq); requires 0 <= bits <= |BEWordSeqToBitSeq_premium(M_seq)|; requires messageBits == BEWordSeqToBitSeq_premium(M_seq)[..bits]; requires messageBytes_seq == messageBytes[..]; requires IsByteSeq(messageBytes_seq); requires BEByteSeqToBitSeq_premium(messageBytes[..]) == BEWordSeqToBitSeq(M_seq)[..bits]; ensures messageBits == BEByteSeqToBitSeq_premium(messageBytes_seq); { calc { messageBits; BEWordSeqToBitSeq_premium(M_seq)[..bits]; BEWordSeqToBitSeq(M_seq)[..bits]; BEByteSeqToBitSeq_premium(messageBytes[..]); BEByteSeqToBitSeq_premium(messageBytes_seq); } } static lemma lemma_SHA_impl_Words_arrays_bitmangle(messageWords:array, messageWords_seq:seq, messageBits:seq, M_seq:seq, bits:int) requires messageWords!=null; requires IsWordSeq(M_seq); requires 0 <= bits <= |BEWordSeqToBitSeq_premium(M_seq)|; requires messageBits == BEWordSeqToBitSeq_premium(M_seq)[..bits]; requires messageWords_seq == messageWords[..]; requires IsWordSeq(messageWords_seq); requires BEWordSeqToBitSeq_premium(messageWords[..]) == BEWordSeqToBitSeq(M_seq)[..bits]; ensures messageBits == BEWordSeqToBitSeq_premium(messageWords_seq); { calc { messageBits; BEWordSeqToBitSeq_premium(M_seq)[..bits]; BEWordSeqToBitSeq(M_seq)[..bits]; BEWordSeqToBitSeq_premium(messageWords[..]); BEWordSeqToBitSeq_premium(messageWords_seq); } } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Crypto/Hash/sha_common.s.dfy ================================================ include "../../base.s.dfy" include "../../../Drivers/CPU/assembly.s.dfy" include "../../Util/integer_sequences.s.dfy" include "../../Util/seq_blocking.s.dfy" //-/////////////////////////////////////////////////// //- Ch, Maj, BSIG0, BSIG1, SSIG0, SSIG1 //-/////////////////////////////////////////////////// static function {:opaque} Ch(x: int, y: int, z: int) : int requires Word32(x); requires Word32(y); requires Word32(z); ensures Word32(Ch(x, y, z)); { BitwiseXor(BitwiseAnd(x, y), BitwiseAnd(BitwiseNot(x), z)) } static function {:opaque} Maj(x: int, y: int, z: int) : int requires Word32(x); requires Word32(y); requires Word32(z); ensures Word32(Maj(x, y, z)); { BitwiseXor(BitwiseXor(BitwiseAnd(x, y), BitwiseAnd(x, z)), BitwiseAnd(y, z)) } static function {:opaque} Parity(x: int, y: int, z: int) : int requires Word32(x); requires Word32(y); requires Word32(z); ensures Word32(Parity(x, y, z)); { BitwiseXor(BitwiseXor(x, y), z) } static function {:opaque} ft(t: int, x: int, y: int, z: int) : int requires 0 <= t <= 79; requires Word32(x); requires Word32(y); requires Word32(z); ensures Word32(ft(t, x, y, z)); { if t >= 0 && t <= 19 then Ch(x, y, z) else if t >= 40 && t <= 59 then Maj(x, y, z) else Parity(x, y, z) } static function {:opaque} BSIG0(x: int) : int requires Word32(x); ensures Word32(BSIG0(x)); { BitwiseXor(BitwiseXor(RotateRight(x, 2), RotateRight(x, 13)), RotateRight(x, 22)) } static function {:opaque} BSIG1(x: int) : int requires Word32(x); ensures Word32(BSIG1(x)); { BitwiseXor(BitwiseXor(RotateRight(x, 6), RotateRight(x, 11)), RotateRight(x, 25)) } static function {:opaque} SSIG0(x: int) : int requires Word32(x); ensures Word32(SSIG0(x)); { BitwiseXor(BitwiseXor(RotateRight(x, 7), RotateRight(x, 18)), RightShift(x, 3)) } static function {:opaque} SSIG1(x: int) : int requires Word32(x); ensures Word32(SSIG1(x)); { BitwiseXor(BitwiseXor(RotateRight(x, 17), RotateRight(x, 19)), RightShift(x, 10)) } static function method {:opaque} NumPaddingZeroes(message_len: int) : int //- According to the spec, this is the smallest non-negative k such that message_len + 1 + k = 448 (mod 512) //- ensures (message_len + 1 + NumPaddingZeroes(message_len)) % 512 == 448; //- ensures NumPaddingZeroes(message_len) <= (448 - message_len - 1) % 512; //- ensures (message_len + NumPaddingZeroes(message_len) + 1) % 32 == 0; ensures 0 <= NumPaddingZeroes(message_len) < 512; { (959 - (message_len % 512)) % 512 } static function PadMessageForSHA(messageBits: seq) : seq { messageBits + [1] + RepeatDigit(0, NumPaddingZeroes(|messageBits|)) + BEIntToDigitSeq(2, 64, |messageBits|) } static function {:opaque} BlockMessageForSHA(paddedMessageBits: seq) : seq> requires IsBitSeq(paddedMessageBits); requires |paddedMessageBits| % 512 == 0; { BreakIntoBlocks(BEIntToDigitSeq(power2(32), |paddedMessageBits|/32, BEBitSeqToInt(paddedMessageBits)), 16) } static function method OneOf8(i: int, n0: int, n1: int, n2: int, n3: int, n4: int, n5: int, n6: int, n7: int) : int requires 0 <= i < 8; { if i == 0 then n0 else if i == 1 then n1 else if i == 2 then n2 else if i == 3 then n3 else if i == 4 then n4 else if i == 5 then n5 else if i == 6 then n6 else n7 } //- Used to avoid matching loops in some uses of forall //- (avoid formulas of the form "forall i :: ...a[i]...a[i+1]...", which can loop //- if the trigger is a[i] and the i+1 in the body is used to instantiate the i in the trigger) static function TBlk(blk:int):bool { true } static function TStep(t:int):bool { true } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Crypto/Hash/sha_padding.i.dfy ================================================ include "sha_common.s.dfy" include "sha_common.i.dfy" include "../../Util/arrays_and_seqs.i.dfy" include "../../Util/integer_sequences_premium.i.dfy" static function {:opaque} Mul32_const(i:int):int { i * 32 } static function {:opaque} Div32_const(i:int):int { i / 32 } static function {:opaque} Mod32_const(i:int):int { i % 32 } static lemma lemma_Mul32_const(i:int) ensures Mul32_const(i) == i * 32; { reveal_Mul32_const(); } static lemma lemma_Div32_const(i:int) ensures Div32_const(i) == i / 32; { reveal_Div32_const(); } static lemma lemma_Mod32_const(i:int) ensures Mod32_const(i) == i % 32; { reveal_Mod32_const(); } //-/////////////////////////////////////////////////// //- Padding message //-/////////////////////////////////////////////////// static function method {:opaque} PaddedLength(message_len: int) : int { message_len + 1 + NumPaddingZeroes(message_len) + 64 } static lemma lemma_PaddedLength_properties(message_len: int) ensures PaddedLength(message_len) == message_len + 65 + NumPaddingZeroes(message_len); ensures PaddedLength(message_len) == message_len + 65 + (959 - (message_len%512)) % 512; ensures PaddedLength(message_len) % 512 == 0; { reveal_PaddedLength(); reveal_NumPaddingZeroes(); var padded_length := PaddedLength(message_len); var padding_zeroes := NumPaddingZeroes(message_len); var q := message_len/512; var r := message_len%512; calc { padded_length % 512; (message_len + 1 + padding_zeroes + 64) % 512; (message_len + 65 + padding_zeroes) % 512; { reveal_NumPaddingZeroes(); } (message_len + 65 + (959 - (message_len % 512)) % 512) % 512; (message_len + 65 + (959 - r) % 512) % 512; (q * 512 + r + 65 + (959 - r) % 512) % 512; (r + 65 + (959 - r) % 512) % 512; 1024 % 512; 0; } } static lemma{:dafnycc_conservative_seq_triggers} lemma_PadMessageForSHA_properties(m:seq) requires IsBitSeq(m); requires |m| < power2(64); ensures IsBitSeq(PadMessageForSHA(m)); ensures |PadMessageForSHA(m)| == PaddedLength(|m|); ensures |PadMessageForSHA(m)| == |m| + 1 + NumPaddingZeroes(|m|) + 64; ensures |PadMessageForSHA(m)| % 512 == 0; ensures forall i :: 0 <= i < |m| ==> PadMessageForSHA(m)[i] == m[i]; ensures PadMessageForSHA(m)[|m|] == 1; ensures forall i :: |m| + 1 <= i <= |m| + NumPaddingZeroes(|m|) ==> PadMessageForSHA(m)[i] == 0; ensures PadMessageForSHA(m)[|m|+NumPaddingZeroes(|m|)+1..] == BEIntToDigitSeq(2, 64, |m|); ensures PadMessageForSHA(m) == PadMessageForSHA(m); ensures IsBitSeq(PadMessageForSHA(m)); { lemma_PaddedLength_properties(|m|); reveal_power2(); assert 2 == power2(1); var paddedBits := PadMessageForSHA(m); var paddingZeroes := NumPaddingZeroes(|m|); Lemma_RepeatDigitProperties(0, paddingZeroes); calc { |PadMessageForSHA(m)|; |m + [1] + RepeatDigit(0, paddingZeroes) + BEIntToDigitSeq(2, 64, |m|)|; |m| + 1 + paddingZeroes + |BEIntToDigitSeq(2, 64, |m|)|; { lemma_power2_is_power_2(64); lemma_BEIntToDigitSeq_private_properties(2, 64, |m|); } |m| + 1 + paddingZeroes + 64; } forall i | 0 <= i < |paddedBits| ensures IsBit(paddedBits[i]); ensures 0 <= i < |m| ==> PadMessageForSHA(m)[i] == m[i]; ensures |m| + 1 <= i <= |m| + NumPaddingZeroes(|m|) ==> PadMessageForSHA(m)[i] == 0; { if 0 <= i < |m| { assert paddedBits[i] == m[i]; } else if i == |m| { assert paddedBits[i] == 1; } else if |m|+1 <= i <= |m| + paddingZeroes { calc { paddedBits[i]; (m + [1] + RepeatDigit_premium(0, paddingZeroes) + BEIntToDigitSeq(2, 64, |m|))[i]; ([1] + RepeatDigit_premium(0, paddingZeroes) + BEIntToDigitSeq(2, 64, |m|))[i - |m|]; (RepeatDigit_premium(0, paddingZeroes) + BEIntToDigitSeq(2, 64, |m|))[i - |m| - 1]; 0; } } else { calc { i; < |paddedBits|; == |m + [1] + RepeatDigit_premium(0, paddingZeroes) + BEIntToDigitSeq(2, 64, |m|)|; == |m| + 1 + paddingZeroes + |BEIntToDigitSeq(2, 64, |m|)|; } calc { paddedBits[i]; (m + [1] + RepeatDigit_premium(0, paddingZeroes) + BEIntToDigitSeq(2, 64, |m|))[i]; ([1] + RepeatDigit_premium(0, paddingZeroes) + BEIntToDigitSeq(2, 64, |m|))[i - |m|]; (RepeatDigit_premium(0, paddingZeroes) + BEIntToDigitSeq(2, 64, |m|))[i - |m| - 1]; BEIntToDigitSeq(2, 64, |m|)[i - |m| - 1 - paddingZeroes]; } lemma_BEIntToDigitSeq_produces_DigitSeq(2, 64, |m|); assert 0 <= BEIntToDigitSeq(2, 64, |m|)[i - |m| - 1 - paddingZeroes] < 2; assert 0 <= paddedBits[i] < 2; } } } static function PadMessageForSHA_premium(m:seq) : seq requires IsBitSeq(m); requires |m| < power2(64); ensures IsBitSeq(PadMessageForSHA_premium(m)); ensures |PadMessageForSHA_premium(m)| == PaddedLength(|m|); ensures |PadMessageForSHA_premium(m)| == |m| + 1 + NumPaddingZeroes(|m|) + 64; ensures |PadMessageForSHA_premium(m)| % 512 == 0; ensures |m| < power2(64) ==> |PadMessageForSHA_premium(m)| == |m| + 1 + NumPaddingZeroes(|m|) + 64; ensures forall i :: 0 <= i < |m| ==> PadMessageForSHA_premium(m)[i] == m[i]; ensures PadMessageForSHA_premium(m)[|m|] == 1; ensures forall i :: |m| + 1 <= i <= |m| + NumPaddingZeroes(|m|) ==> PadMessageForSHA_premium(m)[i] == 0; ensures PadMessageForSHA_premium(m)[|m|+NumPaddingZeroes(|m|)+1..] == BEIntToDigitSeq(2, 64, |m|); ensures PadMessageForSHA_premium(m) == PadMessageForSHA(m); { lemma_PadMessageForSHA_properties(m); lemma_PaddedLength_properties(|m|); PadMessageForSHA(m) } static lemma {:timeLimitMultiplier 2} lemma_ExtractingWordFromArray(n1:int, n2:int, a:array, b:int, s:seq) requires Mod32_const(n1) == 0; requires n1 + 32 == n2; requires 0 <= n1 < n2 <= |s|; requires IsWordArray(a); requires n2 <= a.Length * 32; requires forall i :: n1 <= i < n2 ==> s[i] == GetArrayBit(a, i); requires a[n1 / 32] == b; ensures s[n1..n2] == BEWordToBitSeq(b); { reveal_Mod32_const(); reveal_GetArrayBit(); assert IsBitSeq(BEWordToBitSeq_premium(b)); assert |BEWordToBitSeq(b)| == 32; assert forall i :: n1 <= i < n2 ==> s[i] == BEWordToBitSeq_premium(b)[i - n1]; } static lemma lemma_PaddedMessageLen(message_len: int) ensures Mod32_const(message_len + NumPaddingZeroes(message_len)) == 31; { reveal_Mod32_const(); reveal_NumPaddingZeroes(); } static lemma lemma_mod32_fact(x:int) requires Mod32_const(x) == 31; ensures Mod32_const(x + 1) == 0; ensures Mod32_const(x + 33) == 0; { reveal_Mod32_const(); } static lemma lemma_LengthInPaddedMessageIsWordAligned(message_len: int) ensures Mod32_const(message_len + NumPaddingZeroes(message_len) + 1) == 0; ensures Mod32_const(message_len + NumPaddingZeroes(message_len) + 33) == 0; { lemma_PaddedMessageLen(message_len); var x := message_len + NumPaddingZeroes(message_len); lemma_mod32_fact(x); } static lemma lemma_WhatHappensToMod512WhenYouAddOne(x:int) requires 0 <= x; ensures (x+1)%512 == x%512+1 || (x+1)%512 == x%512 - 511; { } static lemma lemma_WhatHappensToPaddedLengthWhenYouAddOne(x:int) requires 0 <= x; ensures PaddedLength(x+1) == PaddedLength(x) || PaddedLength(x+1) == PaddedLength(x)+512; { lemma_WhatHappensToMod512WhenYouAddOne(x); lemma_WhatHappensToMod512WhenYouAddOne(958 - x%512); if (x+1)%512 == x%512+1 { if (958 - x%512 + 1)%512 == (958 - x%512)%512 + 1 { calc { PaddedLength(x+1); { reveal_PaddedLength(); } x + 66 + NumPaddingZeroes(x+1); { reveal_NumPaddingZeroes(); } x + 66 + (959 - ((x+1)%512))%512; x + 66 + (959 - (x%512+1))%512; x + 66 + (958 - x%512)%512; x + 66 + (958 - x%512 + 1)%512 - 1; x + 65 + (959 - x%512)%512; { reveal_NumPaddingZeroes(); } x + 65 + NumPaddingZeroes(x); { reveal_PaddedLength(); } PaddedLength(x); } } else { assert (958 - x%512 + 1)%512 == (958 - x%512)%512 - 511; calc { PaddedLength(x+1); { reveal_PaddedLength(); } x + 66 + NumPaddingZeroes(x+1); { reveal_NumPaddingZeroes(); } x + 66 + (959 - ((x+1)%512))%512; x + 66 + (959 - (x%512+1))%512; x + 66 + (958 - x%512)%512; x + 66 + (958 - x%512 + 1)%512 + 511; x + 65 + (959 - x%512)%512 + 512; { reveal_NumPaddingZeroes(); } x + 65 + NumPaddingZeroes(x) + 512; { reveal_PaddedLength(); } PaddedLength(x) + 512; } } } else { assert (x+1)%512 == x%512-511; if (958 - x%512 + 1)%512 == (958 - x%512)%512 + 1 { calc { PaddedLength(x+1); { reveal_PaddedLength(); } x + 66 + NumPaddingZeroes(x+1); { reveal_NumPaddingZeroes(); } x + 66 + (959 - ((x+1)%512))%512; x + 66 + (959 - (x%512-511))%512; x + 66 + (959 + 511 - x%512)%512; x + 66 + (958 - x%512)%512; x + 66 + (958 - x%512 + 1)%512 - 1; x + 65 + (959 - x%512)%512; { reveal_NumPaddingZeroes(); } x + 65 + NumPaddingZeroes(x); { reveal_PaddedLength(); } PaddedLength(x); } } else { assert (958 - x%512 + 1)%512 == (958 - x%512)%512 - 511; calc { PaddedLength(x+1); { reveal_PaddedLength(); } x + 66 + NumPaddingZeroes(x+1); { reveal_NumPaddingZeroes(); } x + 66 + (959 - ((x+1)%512))%512; x + 66 + (959 - (x%512-511))%512; x + 66 + (959 + 511 - x%512)%512; x + 66 + (958 - x%512)%512; x + 66 + (958 - x%512 + 1)%512 + 511; x + 65 + (959 - x%512)%512 + 512; { reveal_NumPaddingZeroes(); } x + 65 + NumPaddingZeroes(x) + 512; { reveal_PaddedLength(); } PaddedLength(x) + 512; } } } } static lemma lemma_PaddedLengthMonotonic(a:int, b:int) requires 0 <= a <= b; decreases b; ensures PaddedLength(a) <= PaddedLength(b); { if a < b { lemma_PaddedLengthMonotonic(a, b-1); lemma_WhatHappensToPaddedLengthWhenYouAddOne(b-1); } } static lemma lemma_64BitValueIsZerosThen32Bits(v: int) requires Word32(v); ensures BEIntToDigitSeq(2, 64, v) == SequenceOfZeros(32) + BEWordToBitSeq(v); { lemma_power2_is_power_2_general(); lemma_BEIntToDigitSeqProducesRightSizedDigits(2, 32, v); calc { BEDigitSeqToInt(2, SequenceOfZeros(32) + BEIntToDigitSeq(2, 32, v)); { lemma_LeadingZeros(2, BEIntToDigitSeq(2, 32, v), SequenceOfZeros(32) + BEIntToDigitSeq(2, 32, v)); } BEDigitSeqToInt(2, BEIntToDigitSeq(2, 32, v)); } calc { BEDigitSeqToInt(2, SequenceOfZeros(32) + BEIntToDigitSeq(2, 32, v)); { lemma_BEIntToDigitSeq_private_properties(2, 32, v); lemma_BEIntToDigitSeq_invertibility(2, v, BEIntToDigitSeq(2, 32, v)); } v; } calc { BEIntToDigitSeq(2, 64, v); { lemma_BEDigitSeqToInt_invertibility(2, v, SequenceOfZeros(32) + BEIntToDigitSeq(2, 32, v)); lemma_BEIntToDigitSeq_private_properties(2, 32, v); } SequenceOfZeros(32) + BEIntToDigitSeq(2, 32, v); { lemma_power2_1_is_2(); } SequenceOfZeros(32) + BEWordToBitSeq(v); } } static function {:opaque} GetArrayBitOpaque(a: array, b:int) : int requires IsWordArray(a); requires 0 <= b < Mul32_const(a.Length); ensures IsBit(GetArrayBitOpaque(a, b)); ensures b < |BEWordSeqToBitSeq_premium(a[..])|; ensures /*REVIEW: GetArrayBitOpaque*/ GetArrayBit(a, b) == BEWordSeqToBitSeq_premium(a[..])[b]; reads a; { reveal_Mul32_const(); GetArrayBit(a, b) } ghost static method {:dafnycc_conservative_seq_triggers} {:timeLimitMultiplier 6} Lemma_ArrayIsPaddedMessageHelper(a: array, b: int, m: seq) requires IsWordArray(a); requires |m| == b; requires Word32(b); requires 0 <= b < power2(64); requires b + 1 + NumPaddingZeroes(b) + 64 <= Mul32_const(a.Length); requires 0 <= PaddedLength(b) <= Mul32_const(a.Length); requires forall i {:trigger GetArrayBit(a, i)}{:trigger m[i]} :: 0 <= i < b ==> GetArrayBitOpaque(a, i) == m[i]; requires GetArrayBitOpaque(a, b) == 1; requires a.Length > Div32_const(b + NumPaddingZeroes(b) + 33); requires 0 <= Div32_const(b + NumPaddingZeroes(b) + 1) < a.Length; requires 0 <= Div32_const(b + NumPaddingZeroes(b) + 33) < a.Length; requires forall i {:trigger GetArrayBit(a, i)} :: b + 1 <= i <= b + NumPaddingZeroes(b) ==> GetArrayBitOpaque(a, i) == 0; requires a[Div32_const(b + NumPaddingZeroes(b) + 1)] == 0; requires a[Div32_const(b + NumPaddingZeroes(b) + 33)] == b; ensures PaddedLength(b) <= |BEWordSeqToBitSeq(a[..])|; ensures BEWordSeqToBitSeq(a[..])[..PaddedLength(b)] == PadMessageForSHA(m); { ghost var s := BEWordSeqToBitSeq_premium(a[..]); assert forall j :: 0 <= j < a.Length ==> s[j] == GetArrayBit(a, j); calc <= { PaddedLength(b); { reveal_Mul32_const(); } |s|; } calc { s[..PaddedLength(b)]; { reveal_PaddedLength(); } s[0..|m|+NumPaddingZeroes(|m|)+65]; { lemma_LengthInPaddedMessageIsWordAligned(|m|); reveal_Mul32_const(); lemma_subseq_concatenation(s, 0, |m|+NumPaddingZeroes(|m|)+33, |m|+NumPaddingZeroes(|m|)+65); } s[0..|m|+NumPaddingZeroes(|m|)+33] + s[|m|+NumPaddingZeroes(|m|)+33..|m|+NumPaddingZeroes(|m|)+65]; { reveal_Mul32_const(); reveal_Div32_const(); } { lemma_LengthInPaddedMessageIsWordAligned(|m|); } { lemma_ExtractingWordFromArray(b+NumPaddingZeroes(b)+33, b+NumPaddingZeroes(b)+65, a, b, s); } s[0..|m|+NumPaddingZeroes(|m|)+33] + BEWordToBitSeq(b); { reveal_Mul32_const(); } { lemma_subseq_concatenation(s, 0, |m|+NumPaddingZeroes(|m|)+1, |m|+NumPaddingZeroes(|m|)+33); } s[0..|m|+NumPaddingZeroes(|m|)+1] + s[|m|+NumPaddingZeroes(|m|)+1..|m|+NumPaddingZeroes(|m|)+33] + BEWordToBitSeq(b); { reveal_Div32_const(); } { lemma_LengthInPaddedMessageIsWordAligned(|m|); } { lemma_ExtractingWordFromArray(b+NumPaddingZeroes(b)+1, b+NumPaddingZeroes(b)+33, a, 0, s); } s[0..|m|+NumPaddingZeroes(|m|)+1] + BEWordToBitSeq(0) + BEWordToBitSeq(b); { reveal_power2(); lemma_BEIntToDigitSeq_private_zero(power2(1), 32); } s[0..|m|+NumPaddingZeroes(|m|)+1] + SequenceOfZeros(32) + BEWordToBitSeq(b); { lemma_64BitValueIsZerosThen32Bits(b); } s[0..|m|+NumPaddingZeroes(|m|)+1] + BEIntToDigitSeq(2, 64, b); { lemma_subseq_concatenation(s, 0, |m|+1, |m|+NumPaddingZeroes(|m|)+1); } s[0..|m|+1] + s[|m|+1..|m|+NumPaddingZeroes(|m|)+1] + BEIntToDigitSeq(2, 64, b); { assert forall j :: |m|+1 <= j < |m|+NumPaddingZeroes(|m|)+1 ==> s[j] == GetArrayBit(a, j); reveal_GetArrayBitOpaque(); } s[0..|m|+1] + SequenceOfZeros(NumPaddingZeroes(|m|)) + BEIntToDigitSeq(2, 64, b); { lemma_subseq_concatenation(s, 0, |m|, |m|+1); } s[0..|m|] + s[|m|..|m|+1] + SequenceOfZeros(NumPaddingZeroes(|m|)) + BEIntToDigitSeq(2, 64, b); { reveal_GetArrayBitOpaque(); assert s[|m|] == 1; assert s[|m|..|m|+1] == [1]; } s[0..|m|] + [1] + SequenceOfZeros(NumPaddingZeroes(|m|)) + BEIntToDigitSeq(2, 64, b); { reveal_GetArrayBitOpaque(); assert forall i {:trigger GetArrayBit(a, i)}{:trigger m[i]} :: 0 <= i < b ==> GetArrayBit(a, i) == m[i]; lemma_seq_equality(s[0..|m|], m, b); } m + [1] + SequenceOfZeros(NumPaddingZeroes(|m|)) + BEIntToDigitSeq(2, 64, b); { lemma_SequenceOfZerosIsRepeatDigitZero(NumPaddingZeroes(|m|)); assert |m| == b; } PadMessageForSHA(m); } } ghost static method Lemma_ArrayIsPaddedMessage(a: array, b: int, m: seq) requires IsWordArray(a); requires |m| == b; requires Word32(b); requires 0 <= b < power2(64); requires b + 1 + NumPaddingZeroes(b) + 64 <= a.Length * 32; requires 0 <= PaddedLength(b) <= a.Length * 32; requires forall i {:trigger GetArrayBit(a, i)}{:trigger m[i]} :: 0 <= i < b ==> GetArrayBit(a, i) == m[i]; requires GetArrayBit(a, b) == 1; requires a.Length > (b + NumPaddingZeroes(b) + 33) / 32; requires forall i {:trigger GetArrayBit(a, i)} :: b + 1 <= i <= b + NumPaddingZeroes(b) ==> GetArrayBit(a, i) == 0; requires a[(b + NumPaddingZeroes(b) + 1) / 32] == 0; requires a[(b + NumPaddingZeroes(b) + 33) / 32] == b; ensures BEWordSeqToBitSeq(a[..])[..PaddedLength(b)] == PadMessageForSHA(m); { reveal_Mul32_const(); reveal_Div32_const(); reveal_GetArrayBitOpaque(); Lemma_ArrayIsPaddedMessageHelper(a, b, m); } static method {:dafnycc_conservative_seq_triggers} PadMessageArray(a: array, b: int) requires IsWordArray(a); requires Word32(b); requires 0 <= b < power2(64); requires 0 <= PaddedLength(b) <= a.Length * 32; ensures IsWordSeq(a[..]); ensures |BEWordSeqToBitSeq(a[..])| >= PaddedLength(b); ensures |old(BEWordSeqToBitSeq(a[..]))| >= b; ensures BEWordSeqToBitSeq(a[..])[..PaddedLength(b)] == old(PadMessageForSHA(BEWordSeqToBitSeq(a[..])[..b])); modifies a; { var numPad := NumPaddingZeroes(b); calc { a.Length * 32; >= PaddedLength(b); == { reveal_PaddedLength(); } b + 1 + NumPaddingZeroes(b) + 64; b + 1 + numPad + 64; > b + numPad + 33; } calc { (b + numPad + 1) % 32; (b + NumPaddingZeroes(b) + 1) % 32; == { reveal_NumPaddingZeroes(); } 0; } calc { (b + numPad + 33) % 32; (32 + b + numPad + 1) % 32; { lemma_mod_add_multiples_vanish(b + numPad + 1, 32); } (b + numPad + 1) % 32; 0; } lemma_BEWordSeqToBitSeq_ensures(a[..]); ghost var m := BEWordSeqToBitSeq(a[..])[..b]; AppendBitToArray(a, b, 1); AppendBitsToArray(a, b + 1, 0, numPad); AppendWordToArray(a, b + numPad + 1, 0); AppendWordToArray(a, b + numPad + 33, b); assert IsWordArray(a); assert forall i {:trigger m[i]}{:trigger GetArrayBit(a, i)} :: 0 <= i < b ==> GetArrayBit(a, i) == m[i]; assert GetArrayBit(a, b) == 1; assert forall i {:trigger GetArrayBit(a, i)} :: b + 1 <= i <= b + numPad ==> GetArrayBit(a, i) == 0; assert a[(b + numPad + 1) / 32] == 0; assert a[(b + numPad + 33) / 32] == b; Lemma_ArrayIsPaddedMessage(a, b, m); } static method {:dafnycc_conservative_seq_triggers} CreateArrayForSHA(messageBytes:seq) returns (a: array, b: int) requires IsByteSeq(messageBytes); ensures fresh(a); ensures b == |messageBytes| * 8; ensures b >= 0; ensures 0 <= PaddedLength(b) <= a.Length * 32; ensures IsWordArray(a); ensures |BEWordSeqToBitSeq_premium(a[..])| >= b; ensures BEByteSeqToBitSeq_premium(messageBytes) == BEWordSeqToBitSeq(a[..])[..b]; { reveal_PaddedLength(); b := |messageBytes| * 8; var paddedLength := PaddedLength(b); lemma_LengthInPaddedMessageIsWordAligned(b); reveal_Mod32_const(); assert paddedLength % 32 == 0; a := new int[paddedLength / 32]; var wordseq := BEByteSeqToWordSeqTailPadding(messageBytes); ghost var wordseq_extended := if |wordseq| <= a.Length then wordseq + RepeatDigit_premium(0, a.Length - |wordseq|) else wordseq[..a.Length]; assert |wordseq_extended| == a.Length; lemma_2toX(); var i := 0; while i < a.Length invariant 0 <= i <= a.Length; invariant forall j :: 0 <= j < i ==> Word32(a[j]); invariant a[..i] == wordseq_extended[..i]; { if i < |wordseq| { a[i] := wordseq[i]; } else { a[i] := 0; } assert a[..i+1] == a[..i] + [a[i]]; //- dafnycc triggering assert wordseq_extended[..i+1] == wordseq_extended[..i] + [wordseq_extended[i]]; //- dafnycc triggering i := i + 1; } assert a[..] == wordseq_extended[..a.Length] == wordseq_extended; if |wordseq| <= a.Length { calc { BEWordSeqToBitSeq_premium(wordseq_extended)[..b]; { lemma_WordSeqToBitSeqChop(wordseq_extended, wordseq, RepeatDigit(0, a.Length - |wordseq|)); } (BEWordSeqToBitSeq_premium(wordseq) + BEWordSeqToBitSeq_premium(RepeatDigit(0, a.Length - |wordseq|)))[..b]; BEWordSeqToBitSeq_premium(wordseq)[..b]; } } else { calc { BEWordSeqToBitSeq_premium(wordseq_extended)[..b]; BEWordSeqToBitSeq_premium(wordseq[..a.Length])[..b]; (BEWordSeqToBitSeq_premium(wordseq[..a.Length]) + BEWordSeqToBitSeq_premium(wordseq[a.Length..]))[..b]; { lemma_WordSeqToBitSeqChop(wordseq, wordseq[..a.Length], wordseq[a.Length..]); } BEWordSeqToBitSeq_premium(wordseq)[..b]; } } } static lemma lemma_wordseq_dafnycc_trigger(wordseq_extended:seq, i:int) requires 0 <= i < |wordseq_extended|; ensures wordseq_extended[..i+1] == wordseq_extended[..i] + [wordseq_extended[i]]; { } static method CreateArrayForSHA_arrays(messageBytes:array) returns (a: array, b: int) requires messageBytes!=null; requires IsByteSeq(messageBytes[..]); ensures fresh(a); ensures b == messageBytes.Length * 8; ensures b >= 0; ensures 0 <= PaddedLength(b) <= a.Length * 32; ensures IsWordArray(a); ensures |BEWordSeqToBitSeq_premium(a[..])| >= b; ensures BEByteSeqToBitSeq_premium(messageBytes[..]) == BEWordSeqToBitSeq(a[..])[..b]; { reveal_PaddedLength(); b := messageBytes.Length * 8; var paddedLength := PaddedLength(b); lemma_LengthInPaddedMessageIsWordAligned(b); reveal_Mod32_const(); assert paddedLength % 32 == 0; a := new int[paddedLength / 32]; ghost var messageByteSeq := messageBytes[..]; var wa,wordseq := BEByteSeqToWordSeqTailPadding_arrays(messageBytes, messageByteSeq); //- assert BEByteSeqToBitSeq(messageByteSeq) == BEWordSeqToBitSeq(wordseq)[..|messageByteSeq|*8]; ghost var wordseq_extended := if |wordseq| <= a.Length then wordseq + RepeatDigit_premium(0, a.Length - |wordseq|) else wordseq[..a.Length]; assert |wordseq_extended| == a.Length; lemma_2toX(); var i := 0; while i < a.Length invariant 0 <= i <= a.Length; invariant wa[..] == wordseq; invariant forall j :: 0 <= j < i ==> Word32(a[j]); invariant a[..i] == wordseq_extended[..i]; { if i < wa.Length { a[i] := wa[i]; } else { a[i] := 0; } assert a[..i+1] == a[..i] + [a[i]]; //- dafnycc triggering //-assert wordseq_extended[..i+1] == wordseq_extended[..i] + [wordseq_extended[i]]; //- dafnycc triggering lemma_wordseq_dafnycc_trigger(wordseq_extended, i); i := i + 1; } assert a[..] == wordseq_extended[..a.Length] == wordseq_extended; if |wordseq| <= a.Length { calc { BEWordSeqToBitSeq_premium(wordseq_extended)[..b]; { lemma_WordSeqToBitSeqChop(wordseq_extended, wordseq, RepeatDigit(0, a.Length - |wordseq|)); } (BEWordSeqToBitSeq_premium(wordseq) + BEWordSeqToBitSeq_premium(RepeatDigit(0, a.Length - |wordseq|)))[..b]; BEWordSeqToBitSeq_premium(wordseq)[..b]; } } else { calc { BEWordSeqToBitSeq_premium(wordseq_extended)[..b]; BEWordSeqToBitSeq_premium(wordseq[..a.Length])[..b]; (BEWordSeqToBitSeq_premium(wordseq[..a.Length]) + BEWordSeqToBitSeq_premium(wordseq[a.Length..]))[..b]; { lemma_WordSeqToBitSeqChop(wordseq, wordseq[..a.Length], wordseq[a.Length..]); } BEWordSeqToBitSeq_premium(wordseq)[..b]; } } assert messageByteSeq == messageBytes[..]; //- OBSERVE //- assert BEByteSeqToBitSeq(messageByteSeq) == BEWordSeqToBitSeq(wordseq)[..|messageByteSeq|*8]; //- assert BEByteSeqToBitSeq(messageBytes[..]) == BEWordSeqToBitSeq(wordseq)[..|messageBytes[..]|*8]; calc { BEByteSeqToBitSeq_premium(messageBytes[..]); BEWordSeqToBitSeq_premium(wordseq)[..b]; BEWordSeqToBitSeq_premium(wordseq_extended)[..b]; BEWordSeqToBitSeq(a[..])[..b]; } } static method CreateArrayForSHA_arrays_words(messageWords:array) returns (a: array, b: int) requires messageWords!=null; requires IsWordSeq(messageWords[..]); ensures fresh(a); ensures b == messageWords.Length * 32; ensures b >= 0; ensures 0 <= PaddedLength(b) <= a.Length * 32; ensures IsWordArray(a); ensures |BEWordSeqToBitSeq_premium(a[..])| >= b; ensures BEWordSeqToBitSeq_premium(messageWords[..]) == BEWordSeqToBitSeq(a[..])[..b]; { reveal_PaddedLength(); b := messageWords.Length * 32; var paddedLength := PaddedLength(b); lemma_LengthInPaddedMessageIsWordAligned(b); reveal_Mod32_const(); assert paddedLength % 32 == 0; a := new int[paddedLength / 32]; ghost var messageWordSeq := messageWords[..]; ghost var wordseq := messageWordSeq; //- var wa,wordseq := BEByteSeqToWordSeqTailPadding_arrays(messageBytes, messageByteSeq); //- assert BEByteSeqToBitSeq(messageByteSeq) == BEWordSeqToBitSeq(wordseq)[..|messageByteSeq|*8]; ghost var wordseq_extended := if |wordseq| <= a.Length then wordseq + RepeatDigit_premium(0, a.Length - |wordseq|) else wordseq[..a.Length]; assert |wordseq_extended| == a.Length; lemma_2toX(); var i := 0; while i < a.Length invariant 0 <= i <= a.Length; invariant messageWords[..] == wordseq; invariant forall j :: 0 <= j < i ==> Word32(a[j]); invariant a[..i] == wordseq_extended[..i]; { if i < messageWords.Length { a[i] := messageWords[i]; } else { a[i] := 0; } assert a[..i+1] == a[..i] + [a[i]]; //- dafnycc triggering //-assert wordseq_extended[..i+1] == wordseq_extended[..i] + [wordseq_extended[i]]; //- dafnycc triggering lemma_wordseq_dafnycc_trigger(wordseq_extended, i); i := i + 1; } assert a[..] == wordseq_extended[..a.Length] == wordseq_extended; if |wordseq| <= a.Length { calc { BEWordSeqToBitSeq_premium(wordseq_extended)[..b]; { lemma_WordSeqToBitSeqChop(wordseq_extended, wordseq, RepeatDigit(0, a.Length - |wordseq|)); } (BEWordSeqToBitSeq_premium(wordseq) + BEWordSeqToBitSeq_premium(RepeatDigit(0, a.Length - |wordseq|)))[..b]; BEWordSeqToBitSeq_premium(wordseq)[..b]; } } else { calc { BEWordSeqToBitSeq_premium(wordseq_extended)[..b]; BEWordSeqToBitSeq_premium(wordseq[..a.Length])[..b]; (BEWordSeqToBitSeq_premium(wordseq[..a.Length]) + BEWordSeqToBitSeq_premium(wordseq[a.Length..]))[..b]; { lemma_WordSeqToBitSeqChop(wordseq, wordseq[..a.Length], wordseq[a.Length..]); } BEWordSeqToBitSeq_premium(wordseq)[..b]; } } assert messageWordSeq == messageWords[..]; //- OBSERVE //- assert BEByteSeqToBitSeq(messageByteSeq) == BEWordSeqToBitSeq(wordseq)[..|messageByteSeq|*8]; //- assert BEByteSeqToBitSeq(messageBytes[..]) == BEWordSeqToBitSeq(wordseq)[..|messageBytes[..]|*8]; calc { BEWordSeqToBitSeq_premium(messageWords[..]); BEWordSeqToBitSeq_premium(wordseq)[..b]; BEWordSeqToBitSeq_premium(wordseq_extended)[..b]; BEWordSeqToBitSeq(a[..])[..b]; } } static lemma lemma_mod_words(bits:int, words:int) requires words == PaddedLength(bits)/32; ensures Mod16(words) == 0; { reveal_Mod16(); lemma_PaddedLength_properties(bits); } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Crypto/Hash/sha_test.i.dfy ================================================ include "sha256.i.dfy" include "sha1.i.dfy" static method PrintHash(hash:seq) { var i := 0; while (i < |hash|) invariant 0 <= i <= |hash|; { print hash[i]; i := i + 1; } } //- FIPS says: //- SHA1("abc") = A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D //- http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA1.pdf //- SHA256("abc") = BA7816BF 8F01CFEA 414140DE 5DAE2223 B00361A3 96177A9C B410FF61 F20015AD //- http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA256.pdf method Test1() { var data := [0x61, 0x62, 0x63]; lemma_2toX(); var hash_sha1 := SHA1_impl_Bytes(data); PrintHash(hash_sha1); var hash_sha256 := SHA256_impl_Bytes(data); PrintHash(hash_sha256); } //- FIPS says: //- SHA1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") = //- 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 //- http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA1.pdf //- SHA256("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") = //- 248D6A61 D20638B8 E5C02693 0C3E6039 A33CE459 64FF2167 F6ECEDD4 19DB06C1 //- http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA256.pdf method Test2() { var data := [ 0x61, 0x62, 0x63, 0x64, 0x62, 0x63, 0x64, 0x65, 0x63, 0x64, 0x65, 0x66, 0x64, 0x65, 0x66, 0x67, 0x65, 0x66, 0x67, 0x68, 0x66, 0x67, 0x68, 0x69, 0x67, 0x68, 0x69, 0x6A, 0x68, 0x69, 0x6A, 0x6B, 0x69, 0x6A, 0x6B, 0x6C, 0x6A, 0x6B, 0x6C, 0x6D, 0x6B, 0x6C, 0x6D, 0x6E, 0x6C, 0x6D, 0x6E, 0x6F, 0x6D, 0x6E, 0x6F, 0x70, 0x6E, 0x6F, 0x70, 0x71 ]; lemma_2toX(); var hash_sha1 := SHA1_impl_Bytes(data); PrintHash(hash_sha1); var hash_sha256 := SHA256_impl_Bytes(data); PrintHash(hash_sha256); } method Main() { Test1(); Test2(); } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Crypto/RSA/.gitignore ================================================ *.bpl *.log ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Crypto/RSA/BlockEncoding.i.dfy ================================================ include "../../BigNum/BigNum.i.dfy" include "../../Util/seqs_reverse.i.dfy" include "RSASpec.s.dfy" include "ByteSequences.i.dfy" include "../../../Drivers/TPM/tpm-wrapper.i.dfy" include "../../FatNat/FatNatCommon.i.dfy" include "../../FatNat/Transforms.i.dfy" static function method{:CompiledSpec} CompiledSpec_BlockType(pad_mode:PadMode) : int static function method{:CompiledSpec} CompiledSpec_SignaturePadByte() : int //-//////////////////////////////////////////////////////////////////////////// //- octet-string to octet-string encoding method PadMessage(msg:seq, keysize_octets:nat, pad_mode:PadMode) returns (padded_msg:seq) requires IsByteSeq(msg); requires |msg| <= keysize_octets - 11; requires TPM_ready(); modifies this`TPM; modifies this`IoMemPerm; ensures pad_mode==PadModeSign() ==> TPM == old(TPM); ensures pad_mode==PadModeSign() ==> IoMemPerm == old(IoMemPerm); ensures TPM_ready(); ensures IsByteSeq(padded_msg); ensures |padded_msg| == keysize_octets; ensures PKCS15_PaddingRelation(padded_msg, msg, pad_mode); ensures pad_mode==PadModeSign() ==> PKCS15_SignaturePad(msg, keysize_octets) == padded_msg; { var ps_len:int := keysize_octets - |msg| - 3; assert ps_len>=8; var ps := MakePaddingString(ps_len, pad_mode); padded_msg := [0, BlockType(pad_mode)] + ps + [0] + msg; assert |padded_msg| == keysize_octets; var i := ps_len + 3; //- PaddedMessageStartIndex conjuncts lemma_2toX(); assert IsByteSeq(padded_msg); assert 0 < i <= |padded_msg|; assert 2 <= |padded_msg|; var padding := ps; assert IsByteSeq(padding); assert (forall j :: 0 <= j < |padding| ==> padding[j]!=0); assert padded_msg[0]==0; assert padded_msg[1]==BlockType(pad_mode); assert 2 padded_msg[j]!=0; //- assert padded_msg[i-1]==0; assert PaddedMessageStartIndex(padded_msg, i, pad_mode, ps); assert i >= 11; assert padded_msg[i..] == msg; assert PKCS15_PaddingRelationWith(padded_msg, msg, pad_mode, ps); } method RandomNonzeroOctet() returns (octet:int) requires TPM_ready(); modifies this`TPM; modifies this`IoMemPerm; ensures TPM_ready(); ensures IsByte(octet); ensures 0!=octet; { lemma_2toX(); var byte_seq := get_random(1); octet := byte_seq[0]; if (octet==0) { octet:=42; // a popular value. } } static lemma lemma_RepeatDigit_for_ByteSeq(digit:int, count:int) decreases count; requires 0<=digit RepeatDigit(digit, count)[i] == digit; ensures IsByteSeq(RepeatDigit(digit, count)); { if (count>0) { lemma_RepeatDigit_for_ByteSeq(digit, count-1); } } method MakePaddingString(ps_len:nat, pad_mode:PadMode) returns (os:seq) requires 8 <= ps_len; requires TPM_ready(); modifies this`TPM; modifies this`IoMemPerm; ensures pad_mode==PadModeSign() ==> TPM == old(TPM); ensures pad_mode==PadModeSign() ==> IoMemPerm == old(IoMemPerm); ensures TPM_ready(); ensures IsByteSeq(os); ensures |os| == ps_len; ensures forall octet :: 0 <= octet < |os| ==> os[octet] != 0; ensures pad_mode==PadModeSign() ==> os == RepeatDigit(SignaturePadByte(), |os|); { os := []; while (|os| IsByte(os[octet]); invariant forall octet :: 0 <= octet < |os| ==> os[octet] != 0; invariant pad_mode==PadModeSign() ==> forall i :: 0<=i<|os| ==> os[i] == SignaturePadByte(); invariant TPM_ready(); invariant pad_mode==PadModeSign() ==> TPM == old(TPM); invariant pad_mode==PadModeSign() ==> IoMemPerm == old(IoMemPerm); { var next_octet:int; assert pad_mode.PadModeSign? || pad_mode.PadModeEncrypt?; if (pad_mode.PadModeSign?) { next_octet := 0xff; } else //- if (pad_mode.PadModeEncrypt?) { next_octet := RandomNonzeroOctet(); } /* else { assert false; } */ os := os + [next_octet]; } lemma_2toX(); lemma_RepeatDigit_for_ByteSeq(SignaturePadByte(), |os|); if (pad_mode.PadModeSign?) { ghost var obligation := RepeatDigit(SignaturePadByte(), |os|); assert |obligation| == |os|; forall (i | 0<=i<|os|) ensures obligation[i] == os[i]; { assert obligation[i] == SignaturePadByte() == os[i]; } assert obligation == os; } } static method UnpadMessage(padded_msg:seq, pad_mode:PadMode) returns (msg:seq) requires IsByteSeq(padded_msg); requires exists m :: IsByteSeq(m) && PKCS15_PaddingRelation(padded_msg, m, pad_mode); ensures IsByteSeq(msg); ensures PKCS15_PaddingRelation(padded_msg, msg, pad_mode); { ghost var gm :| IsByteSeq(gm) && PKCS15_PaddingRelation(padded_msg, gm, pad_mode); ghost var padding :| PKCS15_PaddingRelationWith(padded_msg, gm, pad_mode, padding); ghost var pl := |padding|+3; assert pl <= |padded_msg|; assert padded_msg[0]==0; assert padded_msg[1]==BlockType(pad_mode); var pad_idx:int := 2; if (2<=pad_idx < pl-1) { assert padded_msg[pad_idx] == padding[0]; assert padded_msg[pad_idx]!=0; } while (padded_msg[pad_idx]!=0) decreases pl - pad_idx; invariant forall j::2<=j padded_msg[j]!=0; invariant 2<=pad_idx < pl; invariant 2<=pad_idx < pl-1 ==> padded_msg[pad_idx]!=0; { pad_idx := pad_idx + 1; if (pad_idx >= pl) { assert padded_msg[pl-1] == 0; assert false; //- violates invariant } if (2<=pad_idx < pl-1) { assert padded_msg[pad_idx] == padding[pad_idx-2]; } } assert pad_idx == pl-1; pad_idx := pad_idx + 1; //- skip the end-of-pad zero msg := padded_msg[pad_idx..]; assert pad_idx==|padding|+3; assert padded_msg[|padding|+3..] == msg; assert PKCS15_PaddingRelationWith(padded_msg, msg, pad_mode, padding); } static method UnpadMessageOrFail(padded_msg:seq, pad_mode:PadMode) returns (success:bool, msg:seq) requires IsByteSeq(padded_msg); ensures IsByteSeq(msg); ensures (success <==> exists m :: (IsByteSeq(m) && PKCS15_PaddingRelation(padded_msg, m, pad_mode))); ensures (success ==> PKCS15_PaddingRelation(padded_msg, msg, pad_mode)); { msg := []; if (|padded_msg| < 11) { success := false; return; } //- must start with zero, BlockType if (padded_msg[0]!=0) { success := false; return; } if (padded_msg[1]!=BlockType(pad_mode)) { success := false; return; } var pad_idx:int := 2; while (pad_idx < |padded_msg| && padded_msg[pad_idx]!=0) invariant pad_idx >= 2; invariant forall j::2<=j padded_msg[j]!=0; { pad_idx := pad_idx + 1; } if (pad_idx >= |padded_msg|) { success := false; return; } ghost var padding := padded_msg[2..pad_idx]; assert padded_msg[pad_idx] == 0; pad_idx := pad_idx + 1; //- skip the end-of-pad zero if (pad_idx < 11) { success := false; forall (m:seq | IsByteSeq(m)) ensures !PKCS15_PaddingRelation(padded_msg, m, pad_mode); { forall (padding:seq) ensures !PKCS15_PaddingRelationWith(padded_msg, m, pad_mode, padding); { if (PKCS15_PaddingRelationWith(padded_msg, m, pad_mode, padding)) { assert |padding|>=8; assert padded_msg[2..|padding|+3-1] == padding; if (pad_idx >= 3) { calc { 0; padded_msg[pad_idx-1]; padded_msg[2..|padding|+3-1][pad_idx-3]; padding[pad_idx-3]; != 0; } assert false; } else { assert false; } } } //- assert !(exists padding:seq :: PKCS15_PaddingRelationWith(padded_msg, m, pad_mode, padding)); //- assert !PKCS15_PaddingRelation(padded_msg, m, pad_mode); } //- assert !exists m :: (IsByteSeq(m) && PKCS15_PaddingRelation(padded_msg, m, pad_mode)); return; } success := true; msg := padded_msg[pad_idx..]; assert PKCS15_PaddingRelationWith(padded_msg, msg, pad_mode, padding); assert PKCS15_PaddingRelation(padded_msg, msg, pad_mode); } //-//////////////////////////////////////////////////////////////////////////// //- encoding an octet string to integers static function method LEBytesToWord(os:seq) : int requires IsByteSeq(os); requires |os|==4; ensures Word32(LEBytesToWord(os)); { lemma_2to32(); os[0] + 256*os[1] + 65536*os[2] + 16777216*os[3] } static lemma lemma_LEBytesToWord(os:seq) requires IsByteSeq(os); requires |os|==4; ensures LittleEndianIntegerValue(os) == LEBytesToWord(os); { calc { LittleEndianIntegerValue(os); LittleEndianIntegerValue(os[1..])*256 + os[0]; (LittleEndianIntegerValue(os[1..][1..])*256 + os[1..][0])*256 + os[0]; { assert os[1..][1..] == os[2..]; assert os[1..][0] == os[1]; } (LittleEndianIntegerValue(os[2..])*256 + os[1])*256 + os[0]; ((LittleEndianIntegerValue(os[2..][1..])*256 + os[2..][0])*256 + os[1])*256 + os[0]; ((LittleEndianIntegerValue(os[3..])*256 + os[2])*256 + os[1])*256 + os[0]; (((LittleEndianIntegerValue(os[3..][1..])*256 + os[3..][0])*256 + os[2])*256 + os[1])*256 + os[0]; (((LittleEndianIntegerValue(os[4..])*256 + os[3])*256 + os[2])*256 + os[1])*256 + os[0]; (((LittleEndianIntegerValue([])*256 + os[3])*256 + os[2])*256 + os[1])*256 + os[0]; (((0*256 + os[3])*256 + os[2])*256 + os[1])*256 + os[0]; ((os[3]*256 + os[2])*256 + os[1])*256 + os[0]; (os[3]*256*256 + os[2]*256 + os[1])*256 + os[0]; os[3]*256*256*256 + os[2]*256*256 + os[1]*256 + os[0]; LEBytesToWord(os); } } static lemma lemma_BEByteSeqToWordSeq_preserves_nonzero_prefix_property(bs:seq, ws:seq, padbytes:seq) requires IsByteSeq(bs); requires IsWordSeq(ws); requires |bs|==0 || bs[0] > 0; requires |bs|>0 ==> |ws|>0; requires |ws| == (|bs|+3)/4; requires BEByteSeqToInt(bs) == BEWordSeqToInt(ws); requires |BEWordSeqToByteSeq(ws)| >= |bs|; requires padbytes == SequenceOfZeros(|ws|*4 - |bs|); requires IsByteSeq(padbytes); requires BEWordSeqToByteSeq(ws) == padbytes + bs; requires (|bs|%4)==0 ==> BEWordSeqToByteSeq(ws) == bs; ensures |ws| == 0 || ws[0] != 0; { lemma_2toX(); if (|bs|==0) { assert |ws| == 0; } else if (ws[0]==0) { var prefix := padbytes + bs[..4-|padbytes|]; assert prefix[|padbytes|] != 0; var L4 := 4; calc { BEIntToDigitSeq(power2(8), 1*4, 0); { lemma_BEDigitSeqToInt_of_zeros(power2(32), [0]); } BEIntToDigitSeq(power2(8), |[0]|*4, BEDigitSeqToInt(power2(32), [0])); BEWordSeqToByteSeq([0]); BEWordSeqToByteSeq([ws[0]]); { assert [ws[0]] == ws[..1]; } BEWordSeqToByteSeq(ws[..1]); //- BEIntToDigitSeq(power2(8), |ws[..1]|*4, BEDigitSeqToInt(power2(32), ws[..1])); BEIntToDigitSeq(power2(8), |ws[..1]|*4, BEDigitSeqToInt(power2(32), ws[..1])); { lemma_mul_is_mul_boogie(|ws[..1]|, 4); } BEIntToDigitSeq(power2(8), |ws[..1]|*L4, BEDigitSeqToInt(power2(32), ws[..1])); { lemma_mul_is_mul_boogie(8,4); lemma_mul_is_mul_boogie(1,4); lemma_select_from_transform(ws, ws[..1], ws[1..], 8, 4, 32, 4); //- assert |ws[..1]| == 1; lemma_mul_basics_forall(); //- assert |ws[..1]|*L4 == 4; lemma_BEIntToDigitSeq_mp_min(power2(8), |ws|*L4, BEDigitSeqToInt_premium(power2(32), ws)); lemma_mul_is_mul_boogie(|ws|, 4); //- assert 4 <= |ws|*L4; //- assert 4 <= |BEIntToDigitSeq(power2(8), |ws|*L4, BEDigitSeqToInt(power2(32), ws))|; } BEIntToDigitSeq(power2(8), |ws|*L4, BEDigitSeqToInt(power2(32), ws))[..4]; { lemma_mul_is_mul_boogie(|ws|, 4); } BEWordSeqToByteSeq(ws)[..4]; prefix; } //- assert prefix == BEIntToDigitSeq(power2(8), 4, 0); lemma_BEIntToDigitSeq_of_zero(power2(8), prefix); //- assert prefix[|padbytes|] == 0; assert false; } } method BESeqToInteger(be_padded_msg:seq) returns (M:array) requires IsByteSeq(be_padded_msg); //- requires |be_padded_msg|%4==0; requires |be_padded_msg|>0; //- requires be_padded_msg[1] != 0; ensures WellformedFatNat(M); ensures J(M) == BigEndianIntegerValue(be_padded_msg); ensures J(M) == BEByteSeqToInt(be_padded_msg); { lemma_2toX(); var trimmed_be_byte_string := TrimLeadingZeros(256, be_padded_msg); assert |trimmed_be_byte_string|==0 || trimmed_be_byte_string[0] != 0; var big_endian_word_string,padbytes := BEByteSeqToWordSeq_impl(trimmed_be_byte_string); lemma_BEByteSeqToWordSeq_preserves_nonzero_prefix_property(trimmed_be_byte_string, big_endian_word_string, padbytes); M := SeqToArray(big_endian_word_string); calc { J(M); BEDigitSeqToInt(power2(32), big_endian_word_string); BEByteSeqToInt(trimmed_be_byte_string); BEByteSeqToInt(be_padded_msg); { lemma_BigEndianIntegerValue_equals_BEByteSeqToInt(be_padded_msg); } BigEndianIntegerValue(be_padded_msg); } lemma_BigEndianIntegerValue_equals_BEByteSeqToInt(be_padded_msg); } method MessageToInteger(msg:seq, keysize_octets:nat, pad_mode:PadMode) returns (M:array, ghost pm:seq) requires IsByteSeq(msg); //- requires keysize_octets % 4 == 0; requires |msg| <= keysize_octets - 11; requires TPM_ready(); modifies this`TPM; modifies this`IoMemPerm; ensures TPM_ready(); ensures pad_mode==PadModeSign() ==> TPM == old(TPM); ensures pad_mode==PadModeSign() ==> IoMemPerm == old(IoMemPerm); ensures WellformedFatNat(M); ensures IsByteSeq(pm); ensures PKCS15_PaddingRelation(pm, msg, pad_mode); ensures pad_mode==PadModeSign() ==> PKCS15_SignaturePad(msg, keysize_octets) == pm; ensures BigEndianIntegerValue(pm)==J(M); ensures BEByteSeqToInt(pm)==J(M); ensures 0 < J(M) < power2(8*(keysize_octets-1)); ensures |pm|==keysize_octets; ensures fresh(M); { var be_padded_msg:seq := PadMessage(msg, keysize_octets, pad_mode); pm := be_padded_msg; var be_bytes := SeqToArray(be_padded_msg); M := BEByteArrayToWordArray(be_bytes); calc { BigEndianIntegerValue(be_padded_msg); { lemma_BigEndianIntegerValue_zero_prefix(be_padded_msg, be_padded_msg[1..]); } BigEndianIntegerValue(be_padded_msg[1..]); < { lemma_BigEndianIntegerValue_bound(be_padded_msg[1..]); } power2(8*|be_padded_msg[1..]|); power2(8*(|be_padded_msg|-1)); power2(8*(keysize_octets-1)); } calc { BigEndianIntegerValue(be_padded_msg); { lemma_BigEndianIntegerValue_zero_prefix(be_padded_msg, be_padded_msg[1..]); } BigEndianIntegerValue(be_padded_msg[1..]); >= { lemma_BigEndianIntegerValue_bound(be_padded_msg[1..]); } power2(8*(|be_padded_msg[1..]|-1))*be_padded_msg[1..][0]; { assert be_padded_msg[1..][0] == BlockType(pad_mode); } mul(power2(8*(|be_padded_msg[1..]|-1)),BlockType(pad_mode)); mul(power2(8*(|be_padded_msg|-2)),BlockType(pad_mode)); { lemma_mul_is_commutative_forall(); } mul(BlockType(pad_mode),power2(8*(|be_padded_msg|-2))); >= { assert 1 <= BlockType(pad_mode) <= 2; lemma_mul_increases(BlockType(pad_mode),power2(8*(|be_padded_msg|-2))); } power2(8*(|be_padded_msg|-2)); power2(8*|be_padded_msg|-16); >= { assert 11 <= keysize_octets; calc { 8*(|be_padded_msg|-2); 8*|be_padded_msg| - 16; 8*keysize_octets - 16; >= 8*11 - 16; 88 - 16; 72; > 0; } lemma_power2_increases(0, 8*(|be_padded_msg|-2)); } power2(0); { lemma_power2_0_is_1(); } 1; > 0; } lemma_2toX(); calc { BEByteSeqToInt(pm); BEByteSeqToInt(be_bytes[..]); BEWordSeqToInt(M[..]); J(M); } lemma_BigEndianIntegerValue_equals_BEByteSeqToInt(pm); } static method LEWordToBytes(word:int) returns (os:seq) requires Word32(word); ensures IsByteSeq(os); ensures |os|==4; ensures LEBytesToWord(os) == word; { var r0 := word % 256; var q0 := word / 256; var r1 := q0 % 256; var q1 := q0 / 256; var r2 := q1 % 256; var q2 := q1 / 256; os := [ r0, r1, r2, q2 ]; lemma_2to32(); calc { LEBytesToWord(os); os[0] + 256*os[1] + 65536*os[2] + 16777216*os[3]; r0 + 256*r1 + 65536*r2 + 16777216*q2; r0 + 256*(r1 + 256*r2 + 65536*q2); r0 + 256*(r1 + 256*(r2 + 256*q2)); { lemma_mul_is_mul_boogie(256,q2); lemma_mul_is_mul_boogie(256,r2 + 256*q2); lemma_mul_is_mul_boogie(256,r1 + 256*(r2 + 256*q2)); } r0 + mul(256,(r1 + mul(256,(r2 + mul(256,q2))))); { lemma_fundamental_div_mod(q1, 256); assert q1 == mul(256, div(q1, 256)) + mod(q1,256); assert div(q1,256) == q1/256 == q2; assert q1 == mul(256, q2) + r2; } r0 + mul(256,(r1 + mul(256,q1))); { lemma_fundamental_div_mod(q0, 256); assert q0 == mul(256, div(q0, 256)) + mod(q0,256); assert q0 == mul(256, q1) + r1; } r0 + mul(256,q0); { lemma_fundamental_div_mod(word, 256); assert word == mul(256, div(word, 256)) + mod(word,256); assert word == mul(256, q0) + r0; } word; } } static lemma lemma_LittleEndianIntegerValue_chomps_word(os:seq) requires IsByteSeq(os); requires |os|>=4; ensures LittleEndianIntegerValue(os) == LEBytesToWord(os[0..4]) + Width()*LittleEndianIntegerValue(os[4..]); { calc { LittleEndianIntegerValue(os); LittleEndianIntegerValue(os[1..])*256 + os[0]; (LittleEndianIntegerValue(os[1..][1..])*256 + os[1..][0])*256 + os[0]; { assert os[1..][1..] == os[2..]; assert os[1..][0] == os[1]; } (LittleEndianIntegerValue(os[2..])*256 + os[1])*256 + os[0]; ((LittleEndianIntegerValue(os[2..][1..])*256 + os[2..][0])*256 + os[1])*256 + os[0]; { assert os[2..][1..] == os[3..]; assert os[2..][0] == os[2]; } ((LittleEndianIntegerValue(os[3..])*256 + os[2])*256 + os[1])*256 + os[0]; (((LittleEndianIntegerValue(os[3..][1..])*256 + os[3..][0])*256 + os[2])*256 + os[1])*256 + os[0]; { assert os[3..][1..] == os[4..]; assert os[3..][0] == os[3]; } (((LittleEndianIntegerValue(os[4..])*256 + os[3])*256 + os[2])*256 + os[1])*256 + os[0]; ((LittleEndianIntegerValue(os[4..])*256*256 + os[3]*256 + os[2])*256 + os[1])*256 + os[0]; (LittleEndianIntegerValue(os[4..])*256*256*256 + os[3]*256*256 + os[2]*256 + os[1])*256 + os[0]; LittleEndianIntegerValue(os[4..])*256*256*256*256 + os[3]*256*256*256 + os[2]*256*256 + os[1]*256 + os[0]; calc { LittleEndianIntegerValue(os[4..])*256*256*256*256; { mul_associates256(LittleEndianIntegerValue(os[4..])); } LittleEndianIntegerValue(os[4..])*256*256*(256*256); { mul_associates256(LittleEndianIntegerValue(os[4..])); } LittleEndianIntegerValue(os[4..])*(256*256)*(256*256); { lemma_mul_is_associative(LittleEndianIntegerValue(os[4..]), (256*256), (256*256)); } LittleEndianIntegerValue(os[4..])*(256*256*256*256); } { lemma_2to32(); //-lemma_mul_is_mul_boogie(LittleEndianIntegerValue(os[4..]), Width()); } LittleEndianIntegerValue(os[4..])*Width() + os[3]*256*256*256 + os[2]*256*256 + os[1]*256 + os[0]; LittleEndianIntegerValue(os[4..])*Width() + os[0] + 256*os[1] + 65536*os[2] + 16777216*os[3]; { lemma_mul_is_commutative(LittleEndianIntegerValue(os[4..]),Width()); } LEBytesToWord(os[0..4]) + Width()*LittleEndianIntegerValue(os[4..]); } } static lemma mul_associates256(x:int) ensures (x*256)*256 == x * (256 * 256); { lemma_mul_is_associative(x, 256, 256); } static method WordsToOctets(ws:seq) returns (os:seq) requires IsWordSeq(ws); ensures IsByteSeq(os); ensures LittleEndianIntegerValue(os) == V(ws); { os := []; var end_ptr := |ws|; calc { LittleEndianIntegerValue(os); 0; { reveal_V(); } V([]); { assert ws[end_ptr..] == []; } V(ws[end_ptr..]); } while (end_ptr > 0) invariant 0 <= end_ptr <= |ws|; invariant IsByteSeq(os); invariant LittleEndianIntegerValue(os) == V(ws[end_ptr..]); { var word_os := LEWordToBytes(ws[end_ptr-1]); ghost var old_os := os; os := word_os + os; calc { LittleEndianIntegerValue(os); { lemma_LittleEndianIntegerValue_chomps_word(os); } LEBytesToWord(word_os) + Width()*LittleEndianIntegerValue(old_os); ws[end_ptr-1] + Width()*V(ws[end_ptr..]); { reveal_V(); } V([ws[end_ptr-1]] + ws[end_ptr..]); { assert [ws[end_ptr-1]] + ws[end_ptr..] == ws[end_ptr-1..]; } V(ws[end_ptr-1..]); } end_ptr := end_ptr - 1; } assert ws==ws[0..]; } predicate {:heap} CanDecodeFatInteger(M:array, keysize_octets:nat, pad_mode:PadMode) requires WellformedFatNat(M); reads M; { exists pm:seq, m:seq :: IsByteSeq(pm) && IsByteSeq(m) && PKCS15_PaddingRelation(pm, m, pad_mode) && BigEndianIntegerValue(pm)==J(M) && |pm|==keysize_octets } static predicate CanDecodeInteger(M:BigNat, keysize_octets:nat, pad_mode:PadMode) requires WellformedBigNat(M); { exists pm:seq, m:seq :: IsByteSeq(pm) && IsByteSeq(m) && PKCS15_PaddingRelation(pm, m, pad_mode) && BigEndianIntegerValue(pm)==I(M) && |pm|==keysize_octets } method IntegerToBESeq(M:array) returns (be_padded_msg:seq) requires WellformedFatNat(M); ensures IsByteSeq(be_padded_msg); ensures |be_padded_msg| > 0; ensures be_padded_msg[0] == 0; ensures (|be_padded_msg| > 1) ==> be_padded_msg[1] != 0; ensures J(M) == BigEndianIntegerValue(be_padded_msg); ensures |be_padded_msg| > 2 ==> power2(8*(|be_padded_msg|-2)) <= BigEndianIntegerValue(be_padded_msg); ensures [0] + BEIntToByteSeq(J(M)) == be_padded_msg; { var wordy_be_padded_msg := BEWordArrayToByteArray(M); lemma_2toX(); var stripped_be_padded_msg := StripLeadingZeros(256, wordy_be_padded_msg[..]); //- now no zeros. be_padded_msg := [0] + stripped_be_padded_msg; assert |stripped_be_padded_msg|>0 ==> stripped_be_padded_msg[0]!=0; assert |be_padded_msg|>1 ==> be_padded_msg[1]!=0; calc { BigEndianIntegerValue(be_padded_msg); { lemma_BigEndianIntegerValue_zero_prefix(be_padded_msg, stripped_be_padded_msg); } BigEndianIntegerValue(stripped_be_padded_msg); { lemma_BigEndianIntegerValue_zero_prefix(wordy_be_padded_msg[..], stripped_be_padded_msg); } BigEndianIntegerValue(wordy_be_padded_msg[..]); { lemma_BigEndianIntegerValue_equals_BEByteSeqToInt(wordy_be_padded_msg[..]); } BEByteSeqToInt(wordy_be_padded_msg[..]); J(M); } lemma_2toX(); if (|be_padded_msg| == 0) { assert false; } if (|be_padded_msg| <= 2) { lemma_BigEndianIntegerValue_equals_BEByteSeqToInt(be_padded_msg); } else { assert |stripped_be_padded_msg| > 0; calc { power2(8*(|be_padded_msg|-2)); power2(8*(|stripped_be_padded_msg|-1)); power2(8*(|stripped_be_padded_msg|-1))*1; { lemma_mul_is_mul_boogie(power2(8*(|stripped_be_padded_msg|-1)),1); } mul(power2(8*(|stripped_be_padded_msg|-1)),1); <= { lemma_mul_left_inequality(power2(8*(|stripped_be_padded_msg|-1)), 1, stripped_be_padded_msg[0]); } power2(8*(|stripped_be_padded_msg|-1))*stripped_be_padded_msg[0]; <= { lemma_BigEndianIntegerValue_bound(stripped_be_padded_msg); } BigEndianIntegerValue(stripped_be_padded_msg); { lemma_BigEndianIntegerValue_zero_prefix(be_padded_msg, stripped_be_padded_msg); } BigEndianIntegerValue(be_padded_msg); } lemma_BigEndianIntegerValue_equals_BEByteSeqToInt(be_padded_msg); } assert J(M) == BigEndianIntegerValue(be_padded_msg) == BEByteSeqToInt(be_padded_msg); ghost var beseq := BEIntToByteSeq(J(M)); lemma_BEIntToByteSeq_decoding(J(M)); assert IsByteSeq(beseq); calc { BigEndianIntegerValue(beseq); { lemma_BigEndianIntegerValue_equals_BEByteSeqToInt(beseq); } BEByteSeqToInt(beseq); { lemma_BEIntToByteSeq_decoding(J(M)); } J(M); } assert BigEndianIntegerValue(beseq) == J(M); assert BigEndianIntegerValue(beseq) == BigEndianIntegerValue(be_padded_msg); lemma_BEIntToByteSeq_form(J(M)); assert |beseq|==0 || beseq[0] != 0; ghost var zbeseq := [0]+beseq; lemma_BigEndianIntegerValue_zero_prefix(zbeseq, beseq); assert BigEndianIntegerValue(zbeseq) == BigEndianIntegerValue(be_padded_msg); //- lemma_BigEndianIntegerValue_zero_prefix_converse_inner(s0:seq, s1:seq) //- requires IsByteSeq(s0); //- requires IsByteSeq(s1); //- requires |s0| >= |s1|; //- requires BigEndianIntegerValue(s0) == BigEndianIntegerValue(s1); //- ensures ZeroPrefix(s0, s1); assert IsByteSeq(zbeseq); assert |zbeseq| > 0; assert zbeseq[0] == 0; assert |zbeseq|>1 ==> zbeseq[1] != 0; assert BigEndianIntegerValue(be_padded_msg) == BigEndianIntegerValue(zbeseq); lemma_SingleZeroPrefixedBigEndianIntegerValuesEqual(zbeseq, be_padded_msg); assert [0] + BEIntToByteSeq(J(M)) == zbeseq == be_padded_msg; } method IntegerToMessage(M:array, keysize_octets:nat, pad_mode:PadMode) returns (success:bool, msg:seq, ghost be_padded_msg:seq) requires WellformedFatNat(M); ensures IsByteSeq(msg); ensures success <==> CanDecodeFatInteger(M, keysize_octets, pad_mode); ensures success ==> IsByteSeq(be_padded_msg) && PKCS15_PaddingRelation(be_padded_msg, msg, pad_mode) && BigEndianIntegerValue(be_padded_msg)==J(M) && |be_padded_msg| == keysize_octets; { var be_padded_msg_real := IntegerToBESeq(M); be_padded_msg := be_padded_msg_real; if (|be_padded_msg_real| != keysize_octets) { success := false; msg := []; forall (pm:seq, m:seq | IsByteSeq(pm) && IsByteSeq(m) && PKCS15_PaddingRelation(pm, m, pad_mode) && BigEndianIntegerValue(pm)==J(M) && |pm|==keysize_octets) ensures false; { calc { keysize_octets; |pm|; { calc { BigEndianIntegerValue(be_padded_msg_real); J(M); BigEndianIntegerValue(pm); } lemma_SingleZeroPrefixedBigEndianIntegerValuesEqual(pm, be_padded_msg_real); } |be_padded_msg_real|; != keysize_octets; } } assert !CanDecodeFatInteger(M, keysize_octets, pad_mode); } else { success,msg := UnpadMessageOrFail(be_padded_msg_real, pad_mode); if (!success) { forall pm:seq, m:seq ensures !(IsByteSeq(pm) && IsByteSeq(m) && PKCS15_PaddingRelation(pm, m, pad_mode) && BigEndianIntegerValue(pm)==J(M)); { if (IsByteSeq(pm) && IsByteSeq(m) && BigEndianIntegerValue(pm)==J(M)) { lemma_BigEndianIntegerValue_zero_prefix_converse(pm, be_padded_msg); if (pm == be_padded_msg) { assert !(exists m :: (IsByteSeq(m) && PKCS15_PaddingRelation(be_padded_msg, m, pad_mode))); assert !PKCS15_PaddingRelation(pm, m, pad_mode); } else if (ZeroPrefix(pm, be_padded_msg)) { assert |pm| >= |be_padded_msg|; assert |pm| > |be_padded_msg|; if (1 < |pm|-|be_padded_msg|) { assert pm[1]==0; } else if (1 == |pm|-|be_padded_msg|) { calc { pm[1]; pm[ 1 .. ][0]; be_padded_msg[0]; 0; } } else { assert 0 == |pm|-|be_padded_msg|; assert pm == be_padded_msg; assert false; } assert !PKCS15_PaddingRelation(pm, m, pad_mode); } else { assert ZeroPrefix(be_padded_msg, pm); if (0 == |be_padded_msg|-|pm|) { assert pm == be_padded_msg; assert false; } else if (1 < |be_padded_msg|-|pm|) { assert be_padded_msg[1] == 0; assert false; } else if (|pm| < 1) { assert !PKCS15_PaddingRelation(pm, m, pad_mode); } else if (|be_padded_msg| < 2) { assert |pm| <= |be_padded_msg|; assert !PKCS15_PaddingRelation(pm, m, pad_mode); } else { assert 1 == |be_padded_msg|-|pm|; calc { be_padded_msg[1]; be_padded_msg[ 1.. ][0]; pm[0]; } assert pm[0]!=0; assert !PKCS15_PaddingRelation(pm, m, pad_mode); } } } } } else { assert IsByteSeq(be_padded_msg); assert PKCS15_PaddingRelation(be_padded_msg, msg, pad_mode); } } } static method BEWordToBytes(word:int) returns (os:seq) requires Word32(word); ensures IsByteSeq(os); ensures |os|==4; ensures BigEndianIntegerValue(os) == word; { var leseq := LEWordToBytes(word); os := ReverseOctetString(leseq); calc { BigEndianIntegerValue(os); { lemma_endian_reversal(os); } LittleEndianIntegerValue(Reverse(os)); { lemma_Reverse_symmetry(os, leseq); } LittleEndianIntegerValue(leseq); { lemma_LEBytesToWord(leseq); } LEBytesToWord(leseq); word; } } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Crypto/RSA/ByteSequences.i.dfy ================================================ include "RSASpec.s.dfy" include "../../Math/power2.i.dfy" include "../../Util/integer_sequences_premium.i.dfy" include "../../BigNum/BigNumBEAdaptor.i.dfy" static function BigEndianIntegerValue(os:seq) : nat decreases |os|; requires IsByteSeq(os); { if (os==[]) then 0 else BigEndianIntegerValue(os[0..|os|-1])*256 + os[|os|-1] } static lemma lemma_BigEndianIntegerValue_nonnegative(os:seq) decreases |os|; requires IsByteSeq(os); ensures 0 <= BigEndianIntegerValue(os); { if (os!=[]) { calc { BigEndianIntegerValue(os); BigEndianIntegerValue(os[0..|os|-1])*256 + os[|os|-1]; >= { lemma_BigEndianIntegerValue_nonnegative(os[0..|os|-1]); } 0*256 + os[|os|-1]; os[|os|-1]; >= 0; } } } static lemma lemma_BigEndianIntegerValue_strip_hi(os:seq) decreases |os|; requires IsByteSeq(os); requires 0 < |os|; ensures BigEndianIntegerValue(os) == os[0]*power2(8*(|os|-1)) + BigEndianIntegerValue(os[1..]); { if(|os|==1) { calc { BigEndianIntegerValue(os); BigEndianIntegerValue(os[0..|os|-1])*256 + os[|os|-1]; BigEndianIntegerValue([])*256 + os[0]; 0*256 + os[0]; os[0]; { lemma_mul_basics_forall(); } mul(os[0],1); { lemma_power2_0_is_1(); } os[0]*power2(0); os[0]*power2(8*0); os[0]*power2(8*(|os|-1)); os[0]*power2(8*(|os|-1)) + 0; os[0]*power2(8*(|os|-1)) + BigEndianIntegerValue(os[1..]); } } else { var sos := os[0..|os|-1]; calc { BigEndianIntegerValue(os); //- defn BigEndianIntegerValue BigEndianIntegerValue(os[0..|os|-1])*256 + os[|os|-1]; //- defn sos BigEndianIntegerValue(sos)*256 + os[|os|-1]; { lemma_BigEndianIntegerValue_strip_hi(sos); } (sos[0]*power2(8*(|sos|-1)) + BigEndianIntegerValue(sos[1..]))*256 + os[|os|-1]; //- distributitivity of boogie mul (sos[0]*power2(8*(|sos|-1)))*256 + BigEndianIntegerValue(sos[1..])*256 + os[|os|-1]; { assert |sos|-1 == |os|-2; assert sos[1..] == os[1..|os|-1]; } (os[0]*power2(8*(|os|-2)))*256 + BigEndianIntegerValue(os[1..|os|-1])*256 + os[|os|-1]; { lemma_mul_is_mul_boogie(os[0]*power2(8*(|os|-2)),256); } mul(os[0]*power2(8*(|os|-2)),256) + BigEndianIntegerValue(os[1..|os|-1])*256 + os[|os|-1]; { lemma_mul_is_associative_forall(); } os[0]*mul(power2(8*(|os|-2)),256) + BigEndianIntegerValue(os[1..|os|-1])*256 + os[|os|-1]; { lemma_2toX(); assert power2(8)==256; } os[0]*(power2(8*(|os|-2))*power2(8)) + BigEndianIntegerValue(os[1..|os|-1])*256 + os[|os|-1]; { lemma_power2_adds(8*(|os|-2), 8); } os[0]*power2(8*(|os|-2)+8) + BigEndianIntegerValue(os[1..|os|-1])*256 + os[|os|-1]; { lemma_mul_is_mul_boogie(8, |os|-2); lemma_mul_basics_forall(); } os[0]*power2(mul(8,(|os|-2))+mul(8,1)) + BigEndianIntegerValue(os[1..|os|-1])*256 + os[|os|-1]; { lemma_mul_is_distributive_forall(); } os[0]*power2(mul(8,(|os|-2)+1)) + BigEndianIntegerValue(os[1..|os|-1])*256 + os[|os|-1]; //- boogie additive arithmetic os[0]*power2(mul(8,|os|-1)) + BigEndianIntegerValue(os[1..|os|-1])*256 + os[|os|-1]; { lemma_mul_is_mul_boogie(8, |os|-1); } os[0]*power2(8*(|os|-1)) + BigEndianIntegerValue(os[1..|os|-1])*256 + os[|os|-1]; { assert os[1..|os|-1] == os[1..][0..|os[1..]|-1]; assert os[|os|-1] == os[1..][|os[1..]|-1]; } os[0]*power2(8*(|os|-1)) + BigEndianIntegerValue(os[1..][0..|os[1..]|-1])*256 + os[1..][|os[1..]|-1]; //- BigEndianIntegerValue ensures os[0]*power2(8*(|os|-1)) + BigEndianIntegerValue(os[1..]); } } } static lemma lemma_BigEndianIntegerValue_zero_prefix(s:seq, s_suffix:seq) requires IsByteSeq(s); requires IsByteSeq(s_suffix); requires ZeroPrefix(s, s_suffix); ensures BigEndianIntegerValue(s) == BigEndianIntegerValue(s_suffix); { if (|s| == |s_suffix|) { assert s == s_suffix; } else { calc { BigEndianIntegerValue(s); { lemma_BigEndianIntegerValue_strip_hi(s); } s[0]*power2(8*(|s|-1)) + BigEndianIntegerValue(s[1..]); mul(0,power2(8*(|s|-1))) + BigEndianIntegerValue(s[1..]); { lemma_mul_basics_forall(); } BigEndianIntegerValue(s[1..]); { lemma_BigEndianIntegerValue_zero_prefix(s[1..], s_suffix); } BigEndianIntegerValue(s_suffix); } } } static lemma lemma_BigEndianIntegerValue_bound(s:seq) decreases |s|; requires IsByteSeq(s); ensures |s|>0 ==> power2(8*(|s|-1))*s[0] <= BigEndianIntegerValue(s); ensures |s|>0 ==> BigEndianIntegerValue(s) < power2(8*(|s|-1))*(s[0]+1); ensures BigEndianIntegerValue(s) < power2(8*|s|); { if (s==[]) { calc { BigEndianIntegerValue(s); 0; < 1; { lemma_power2_0_is_1(); } power2(0); power2(8*|s|); } } else { calc { BigEndianIntegerValue(s); BigEndianIntegerValue(s[0..|s|-1])*256 + s[|s|-1]; <= { lemma_BigEndianIntegerValue_bound(s[0..|s|-1]); } (power2(8*|s[0..|s|-1]|)-1)*256 + s[|s|-1]; { assert |s[0..|s|-1]| == |s|-1; } (power2(8*(|s|-1))-1)*256 + s[|s|-1]; { lemma_mul_is_mul_boogie(power2(8*(|s|-1))-1,256); } mul(power2(8*(|s|-1))-1,256) + s[|s|-1]; { lemma_2toX(); assert power2(8)==256; } mul(power2(8*(|s|-1))-1,power2(8)) + s[|s|-1]; { lemma_mul_is_distributive_forall(); } mul(power2(8*(|s|-1)),power2(8))-mul(1,power2(8)) + s[|s|-1]; { lemma_power2_adds(8*(|s|-1), 8); } power2(8*(|s|-1)+8) - mul(1,power2(8)) + s[|s|-1]; { lemma_mul_basics_forall(); } power2(8*(|s|-1)+8) - power2(8) + s[|s|-1]; { lemma_2toX(); assert power2(8)==256; } power2(8*(|s|-1)+8) - 256 + s[|s|-1]; < { lemma_2toX(); assert s[|s|-1] < 256; } power2(8*(|s|-1)+8); power2(8*|s|); } calc { BigEndianIntegerValue(s); { lemma_BigEndianIntegerValue_strip_hi(s); } s[0]*power2(8*(|s|-1)) + BigEndianIntegerValue(s[1..]); < { lemma_BigEndianIntegerValue_bound(s[1..]); } s[0]*power2(8*(|s|-1)) + power2(8*|s[1..]|); s[0]*power2(8*(|s|-1)) + power2(8*(|s|-1)); { lemma_mul_basics_forall(); } s[0]*power2(8*(|s|-1)) + mul(1,power2(8*(|s|-1))); { lemma_mul_is_distributive_forall(); } (s[0]+1)*power2(8*(|s|-1)); { lemma_mul_is_commutative_forall(); } power2(8*(|s|-1))*(s[0]+1); } if (|s|==1) { calc { power2(8*(|s|-1))*s[0]; power2(8*0)*s[0]; power2(0)*s[0]; { lemma_power2_0_is_1(); } mul(1,s[0]); { lemma_mul_is_mul_boogie(1,s[0]); } 1*s[0]; s[0]; s[|s|-1]; 0*256 + s[|s|-1]; BigEndianIntegerValue([])*256 + s[|s|-1]; BigEndianIntegerValue(s[0..|s|-1])*256 + s[|s|-1]; BigEndianIntegerValue(s); } } else { calc { power2(8*(|s|-1))*s[0]; power2(8*(|s|-2+1))*s[0]; power2(8*(|s|-2)+8)*s[0]; { lemma_power2_adds(8*(|s|-2), 8); } (power2(8*(|s|-2))*power2(8))*s[0]; { lemma_mul_is_associative_forall(); } power2(8*(|s|-2))*(power2(8)*s[0]); { lemma_mul_is_commutative_forall(); } power2(8*(|s|-2))*(s[0]*power2(8)); { lemma_mul_is_associative_forall(); } (power2(8*(|s|-2))*s[0])*power2(8); { lemma_2toX(); assert power2(8)==256; } mul(power2(8*(|s|-2))*s[0],256); { lemma_mul_is_mul_boogie(power2(8*(|s|-2))*s[0],256); } (power2(8*(|s|-2))*s[0])*256; <= (power2(8*(|s|-2))*s[0])*256 + s[|s|-1]; <= { lemma_BigEndianIntegerValue_bound(s[0..|s|-1]); assert |s[0..|s|-1]|>0 ==> power2(8*(|s[0..|s|-1]|-1))*s[0..|s|-1][0] <= BigEndianIntegerValue(s[0..|s|-1]); assert power2(8*(|s[0..|s|-1]|-1))*s[0..|s|-1][0] <= BigEndianIntegerValue(s[0..|s|-1]); assert |s[0..|s|-1]|-1 == |s|-2; assert s[0..|s|-1][0] == s[0]; assert power2(8*(|s|-2))*s[0] <= BigEndianIntegerValue(s[0..|s|-1]); lemma_mul_inequality(power2(8*(|s|-2))*s[0], BigEndianIntegerValue(s[0..|s|-1]), 256); } BigEndianIntegerValue(s[0..|s|-1])*256 + s[|s|-1]; BigEndianIntegerValue(s); } } } } static lemma lemma_BigEndianIntegerValue_increases(prefix:seq, common:seq) requires IsByteSeq(prefix); requires IsByteSeq(common); ensures BigEndianIntegerValue(common) <= BigEndianIntegerValue(prefix+common); { if (|prefix|==0) { assert common == prefix+common; } else { calc { BigEndianIntegerValue(common); <= { lemma_BigEndianIntegerValue_increases(prefix[1..],common); } BigEndianIntegerValue(prefix[1..]+common); { assert prefix[1..]+common == (prefix+common)[1..]; } BigEndianIntegerValue((prefix+common)[1..]); <= { lemma_mul_nonnegative((prefix+common)[0], power2(8*(|(prefix+common)|-1))); } (prefix+common)[0]*power2(8*(|(prefix+common)|-1)) + BigEndianIntegerValue((prefix+common)[1..]); { lemma_BigEndianIntegerValue_strip_hi(prefix+common); } BigEndianIntegerValue(prefix+common); } } } static lemma lemma_BigEndianIntegerValue_equal_prefix_increases(s0:seq, s1:seq, i:int) requires IsByteSeq(s0); requires IsByteSeq(s1); requires 0<=i<|s0|==|s1|; requires forall j :: 0<=j s0[j] == s1[j]; requires s0[i] < s1[i]; ensures BigEndianIntegerValue(s0) < BigEndianIntegerValue(s1); { if (i==0) { calc { BigEndianIntegerValue(s0); < { lemma_BigEndianIntegerValue_bound(s0); } power2(8*(|s0|-1))*(s0[0]+1); power2(8*(|s1|-1))*(s0[0]+1); <= { lemma_mul_left_inequality(power2(8*(|s1|-1)),s0[0]+1,s1[0]); } power2(8*(|s1|-1))*s1[0]; <= { lemma_BigEndianIntegerValue_bound(s1); } BigEndianIntegerValue(s1); } } else { calc { BigEndianIntegerValue(s0); { lemma_BigEndianIntegerValue_strip_hi(s0); } s0[0]*power2(8*(|s0|-1)) + BigEndianIntegerValue(s0[1..]); < { lemma_BigEndianIntegerValue_equal_prefix_increases(s0[1..], s1[1..], i-1); } s0[0]*power2(8*(|s1|-1)) + BigEndianIntegerValue(s1[1..]); s1[0]*power2(8*(|s1|-1)) + BigEndianIntegerValue(s1[1..]); { lemma_BigEndianIntegerValue_strip_hi(s1); } BigEndianIntegerValue(s1); } } } static lemma lemma_BigEndianIntegerValue_equal_prefix_unequal(s0:seq, s1:seq, i:int) requires IsByteSeq(s0); requires IsByteSeq(s1); requires 0<=i<|s0|==|s1|; requires forall j :: 0<=j s0[j] == s1[j]; requires s0[i] != s1[i]; ensures BigEndianIntegerValue(s0) != BigEndianIntegerValue(s1); { if (s0[i], s1:seq) returns(w0':int) requires 0 <= w0 <= w1 < |s1| == |s0tail|; requires forall j :: 0 <= j < w0 ==> s0tail[j]==s1[j]; requires s0tail[w1] != s1[w1]; decreases w1 - w0; ensures 0 <= w0' <= w1 < |s1| == |s0tail|; ensures forall j :: 0 <= j < w0' ==> s0tail[j]==s1[j]; ensures s0tail[w0'] != s1[w0']; { w0' := w0; if (w0 <= w1 && s0tail[w0]==s1[w0]) { w0' := lemma_lemma_BigEndianIntegerValue_zero_prefix_converse_inner_helper(w0 + 1, w1, s0tail, s1); } } static lemma lemma_BigEndianIntegerValue_zero_prefix_converse_inner(s0:seq, s1:seq) requires IsByteSeq(s0); requires IsByteSeq(s1); requires |s0| >= |s1|; requires BigEndianIntegerValue(s0) == BigEndianIntegerValue(s1); ensures ZeroPrefix(s0, s1); { if !(forall i :: 0 <= i < |s0|-|s1| ==> s0[i] == 0) { //- a prefix byte isn't zero. var witness :| 0 <= witness < |s0|-|s1| && s0[witness] != 0; assert |s1| <= |s0|-witness-1; calc { BigEndianIntegerValue(s1); < { lemma_BigEndianIntegerValue_bound(s1); } power2(8*|s1|); <= { lemma_power2_increases(8*|s1|, 8*(|s0|-witness-1)); } power2(8*(|s0|-witness-1)); <= { lemma_mul_increases_forall(); } s0[witness]*power2(8*(|s0|-witness-1)); { lemma_mul_is_commutative_forall(); } power2(8*(|s0|-witness-1))*s0[witness]; power2(8*(|s0[witness..]|-1))*s0[witness..][0]; <= { lemma_BigEndianIntegerValue_bound(s0[witness..]); } BigEndianIntegerValue(s0[witness..]); <= { lemma_BigEndianIntegerValue_increases(s0[..witness], s0[witness..]); } BigEndianIntegerValue(s0[..witness]+s0[witness..]); { assert s0[..witness]+s0[witness..] == s0; } BigEndianIntegerValue(s0); } assert false; } else if (s0[ |s0|-|s1| .. ] != s1) { //- don't agree on suffix var s0tail := s0[ |s0|-|s1| .. ]; var w1 :| 0 <= w1 < |s1| && (s0tail[w1] != s1[w1]); assert w1 < |s1|; //- convince Dafny there's a LEAST such element. var w0 := lemma_lemma_BigEndianIntegerValue_zero_prefix_converse_inner_helper(0, w1, s0tail, s1); /* dafnycc TODO: ghost while loops var w0 := 0; while (w0 <= w1 && s0tail[w0]==s1[w0]) invariant w0 <= w1 < |s1| == |s0tail|; invariant forall j :: 0 <= j < w0 ==> s0tail[j]==s1[j]; { w0 := w0 + 1; } */ if (w0 > w1) { assert s0tail[w1]!=s1[w1]; assert forall j :: 0 <= j < w1 ==> s0tail[j]==s1[j]; } else { w1 := w0; assert s0tail[w1]!=s1[w1]; assert forall j :: 0 <= j < w1 ==> s0tail[j]==s1[j]; } lemma_BigEndianIntegerValue_zero_prefix(s0, s0tail); assert BigEndianIntegerValue(s0) == BigEndianIntegerValue(s0tail); lemma_BigEndianIntegerValue_equal_prefix_unequal(s0tail, s1, w1); assert BigEndianIntegerValue(s0tail) != BigEndianIntegerValue(s1); assert false; } else { assert ZeroPrefix(s0, s1); } } static lemma lemma_BigEndianIntegerValue_zero_prefix_converse(s0:seq, s1:seq) requires IsByteSeq(s0); requires IsByteSeq(s1); requires BigEndianIntegerValue(s0) == BigEndianIntegerValue(s1); ensures ZeroPrefix(s0, s1) || ZeroPrefix(s1, s0); { if (|s0| >= |s1|) { lemma_BigEndianIntegerValue_zero_prefix_converse_inner(s0, s1); } else { lemma_BigEndianIntegerValue_zero_prefix_converse_inner(s1, s0); } } static lemma lemma_SingleZeroPrefixedBigEndianIntegerValuesEqual(s0:seq, s1:seq) requires IsByteSeq(s0); requires IsByteSeq(s1); requires BigEndianIntegerValue(s0) == BigEndianIntegerValue(s1); requires |s0|>0; requires |s1|>0; //- requires |s0|>0 ==> s0[0] == 0; //- requires |s1|>0 ==> s1[0] == 0; requires s0[0] == 0; requires s1[0] == 0; requires |s0|>1 ==> s0[1] != 0; requires |s1|>1 ==> s1[1] != 0; ensures s0 == s1; { lemma_BigEndianIntegerValue_zero_prefix_converse(s0, s1); } static function LittleEndianIntegerValue(os:seq) : nat requires IsByteSeq(os); { if (os==[]) then 0 else LittleEndianIntegerValue(os[1..])*256 + os[0] } static method ReverseOctetString(os:seq) returns (rs:seq) ensures rs == Reverse(os); ensures IsByteSeq(os) ==> IsByteSeq(rs); ensures |os| == |rs|; ensures forall i :: 0<=i<|os| ==> os[i] == rs[|rs|-1-i]; { reveal_Reverse(); rs := []; var ptr:int := 0; while (ptr < |os|) invariant 0 <= ptr <= |os|; invariant rs == Reverse(os[0..ptr]); { ghost var old_rs := rs; rs := [os[ptr]] + rs; ghost var os1 := os[0..ptr+1]; calc { rs; [os[ptr]] + old_rs; [os[ptr]] + Reverse(os[0..ptr]); [os1[|os1|-1]] + Reverse(os[0..ptr]); { calc { os[0..ptr]; { assert forall i :: 0<=i os[0..ptr][i] == os1[0..ptr][i]; } os1[0..ptr]; os1[0..|os1|-1]; } } [os1[|os1|-1]] + Reverse(os1[0..|os1|-1]); Reverse(os1); } ptr := ptr + 1; } assert os[0..ptr] == os; lemma_Reverse(os, rs); if (IsByteSeq(os)) { forall (i | 0<=i<|rs|) ensures 0<=rs[i]) decreases |bes|; requires IsByteSeq(bes); ensures IsByteSeq(Reverse(bes)); ensures LittleEndianIntegerValue(Reverse(bes)) == BigEndianIntegerValue(bes); { reveal_Reverse(); lemma_Reverse(bes, Reverse(bes)); if (bes==[]) { } else { lemma_endian_reversal(bes[0..|bes|-1]); /* var les := Reverse(bes); assert les == [bes[|bes|-1]] + Reverse(bes[0..|bes|-1]); calc { LittleEndianIntegerValue(Reverse(bes)); LittleEndianIntegerValue(les); LittleEndianIntegerValue(les[1..])*256 + les[0]; LittleEndianIntegerValue( Reverse(bes[0..|bes|-1]) )*256 + bes[|bes|-1]; { lemma_endian_reversal(bes[0..|bes|-1]); } BigEndianIntegerValue(bes[0..|bes|-1])*256 + bes[|bes|-1]; BigEndianIntegerValue(bes); } */ } } static lemma lemma_BigEndianIntegerValue_equals_BEByteSeqToInt(bs:seq) decreases |bs|; requires IsByteSeq(bs); ensures BigEndianIntegerValue(bs) == BEByteSeqToInt(bs); { lemma_2toX(); if (bs==[]) { calc { BigEndianIntegerValue(bs); 0; { reveal_BEDigitSeqToInt_private(); } BEDigitSeqToInt_private(power2(8), bs); BEDigitSeqToInt(power2(8), bs); BEByteSeqToInt(bs); } } else { lemma_BigEndianIntegerValue_equals_BEByteSeqToInt(bs[0..|bs|-1]); calc { BigEndianIntegerValue(bs); BigEndianIntegerValue(bs[0..|bs|-1])*256 + bs[|bs|-1]; { lemma_BigEndianIntegerValue_equals_BEByteSeqToInt(bs[0..|bs|-1]); } BEByteSeqToInt(bs[0..|bs|-1])*256 + bs[|bs|-1]; BEDigitSeqToInt_private(256, bs[0..|bs|-1])*256 + bs[|bs|-1]; { lemma_mul_is_mul_boogie(BEDigitSeqToInt_private(256, bs[0..|bs|-1]), 256); } mul(BEDigitSeqToInt_private(256, bs[0..|bs|-1]),256) + bs[|bs|-1]; { reveal_BEDigitSeqToInt_private(); } BEDigitSeqToInt_private(256, bs); BEDigitSeqToInt(256, bs); { lemma_2toX(); } BEDigitSeqToInt(power2(8), bs); BEByteSeqToInt(bs); } } } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Crypto/RSA/Extended_GCD.i.dfy ================================================ //-include "../../BigNum/BigNatDiv.i.dfy" //-include "../../BigNum/BigNum.i.dfy" include "../../FatNat/FatInt.i.dfy" include "division.i.dfy" static predicate opposing_signs(x:int, y:int) { x==0 || y==0 || (x<0 <==> y>=0) } datatype Egcd_data = Egcd_data_c( R:array, X:FatInt, Y:FatInt, next_R:array, next_R_zero:bool, next_X:FatInt, next_Y:FatInt ); datatype Egcd_ghost = Egcd_ghost_c( a:nat, b:nat ); predicate {:heap} Egcd_invariant(d:Egcd_data, g:Egcd_ghost) reads d.R; reads d.X.value; reads d.Y.value; reads d.next_R; reads d.next_X.value; reads d.next_Y.value; { true && (WellformedFatNat(d.R)) && (WellformedFatInt(d.X)) && (WellformedFatInt(d.Y)) && (WellformedFatNat(d.next_R)) && (WellformedFatInt(d.next_X)) && (WellformedFatInt(d.next_Y)) && (J(d.R) != 0) && (g.b == 0 ==> J(d.next_R)==0 && FIV(d.X) == 1 && FIV(d.Y) == 0) && (g.a * FIV( d.X) + g.b * FIV( d.Y) == J( d.R)) && (g.a * FIV(d.next_X) + g.b * FIV(d.next_Y) == J(d.next_R)) //- && (gcd(J(A), g.b) == gcd(J(R), J(d.next_R))) && (forall c:nat :: is_gcd(J(d.R), J(d.next_R), c) ==> is_gcd(g.a, g.b, c)) && ((J(d.next_R)==0) <==> (BEWordSeqToInt(d.next_R[..])==0)) && (d.next_R_zero <==> J(d.next_R)==0) } predicate {:heap} Extended_gcd_requires(A:array, B:array) reads A; reads B; { (A!=null) && (IsWordSeq(A[..])) && (B!=null) && (IsWordSeq(B[..])) && (1<=BEWordSeqToInt(A[..])) && (BEWordSeqToInt(B[..]) < BEWordSeqToInt(A[..])) } predicate {:heap} Extended_gcd_ensures(A:array, B:array, X:FatInt, Y:FatInt) reads A; reads B; reads X.value; reads Y.value; requires Extended_gcd_requires(A, B); { (WellformedFatInt(X)) //- && (X.value.Length < power2(27)) && (WellformedFatInt(Y)) //- && (Y.value.Length < power2(27)) && (0 <= BEWordSeqToInt(A[..])*FIV(X) + BEWordSeqToInt(B[..])*FIV(Y)) && (0 <= BEWordSeqToInt(B[..])) //- satisfy precondition. Need a premium. && (is_gcd(BEWordSeqToInt(A[..]), BEWordSeqToInt(B[..]), BEWordSeqToInt(A[..])*FIV(X) + BEWordSeqToInt(B[..])*FIV(Y))) //- These size constraints are used to show downstream modesty, //- but also to show that the solution for 'd' is within a phi of [0,phi). && ((FIV(X)==1 && FIV(Y)==0) || -BEWordSeqToInt(B[..]) <= FIV(X) <= BEWordSeqToInt(B[..])) && (-BEWordSeqToInt(A[..]) <= FIV(Y) <= BEWordSeqToInt(A[..])) && (opposing_signs(FIV(X), FIV(Y))) && (FIV(X)!=0 || FIV(Y)!=0) } method Extended_gcd_init(A:array, B:array) returns (d:Egcd_data, ghost g:Egcd_ghost) requires Extended_gcd_requires(A, B); ensures g.a == BEWordSeqToInt(A[..]); ensures g.b == BEWordSeqToInt(B[..]); ensures Egcd_invariant(d, g); { ghost var a := J(A); ghost var b := J(B); lemma_2toX(); var X := MakeSmallLiteralFatInt(1); var x_ref := X.value; //- do something real to X.value to convince dafnycc it's allocated var Y := MakeSmallLiteralFatInt(0); var y_ref := Y.value; //- do something real to Y.value to convince dafnycc it's allocated var R := A; var next_R := B; var next_X := Y; var next_Y := X; calc { a * FIV(X) + b * FIV(Y); a * 1 + b * 0; a; J(R); } calc { a * FIV(next_X) + b * FIV(next_Y); a * 0 + b * 1; J(next_R); } var next_R_zero := FatNatIsZero(next_R); d := Egcd_data_c(R, X, Y, next_R, next_R_zero, next_X, next_Y); g := Egcd_ghost_c(a, b); } method {:timeLimitMultiplier 3} Extended_gcd_step(d:Egcd_data, ghost g:Egcd_ghost) returns (d':Egcd_data, ghost g':Egcd_ghost) requires Egcd_invariant(d, g); requires !d.next_R_zero; ensures Egcd_invariant(d', g'); ensures g'==g; ensures 0 <= J(d'.next_R) < J(d.next_R); { var dr_ref := d.R; //- do something real to d.R to convince dafnycc it's allocated var dnr_ref := d.next_R; //- do something real to d.next_R to convince dafnycc it's allocated var dx_ref := d.X.value; //- do something real to d.X.value to convince dafnycc it's allocated var dy_ref := d.Y.value; //- do something real to d.Y.value to convince dafnycc it's allocated var dnx_ref := d.next_X.value; //- do something real to d.next_X.value to convince dafnycc it's allocated var dny_ref := d.next_Y.value; //- do something real to d.next_Y.value to convince dafnycc it's allocated var Q, M := FatNatDiv(d.R, d.next_R); calc { J(d.next_R)*J(Q); { lemma_mul_is_commutative_forall(); } J(Q)*J(d.next_R); } lemma_fundamental_div_mod_converse(J(d.R), J(d.next_R), J(Q), J(M)); assert J(M) < J(d.next_R); //- lemma_modesty_word_value_equivalence(M); //- lemma_modesty_word_value_equivalence(d.next_R); var X' := FatIntMul(FatInt_ctor(false, Q), d.next_X); var x_ref := X'.value; //- do something real to X'.value to convince dafnycc it's allocated X' := FatIntSub(d.X, X'); x_ref := X'.value; //- do something real to X'.value to convince dafnycc it's allocated assert WellformedFatInt(d.Y); assert WellformedFatInt(d.next_Y); var Y' := FatIntMul(FatInt_ctor(false, Q), d.next_Y); var y_ref := Y'.value; //- do something real to Y'.value to convince dafnycc it's allocated assert WellformedFatInt(d.Y); Y' := FatIntSub(d.Y, Y'); y_ref := Y'.value; //- do something real to Y'.value to convince dafnycc it's allocated ghost var r := J(d.R); ghost var nr := J(d.next_R); ghost var x := FIV(d.X); ghost var y := FIV(d.Y); ghost var nx := FIV(d.next_X); ghost var ny := FIV(d.next_Y); ghost var x' := FIV(X'); ghost var y' := FIV(Y'); ghost var a := g.a; ghost var b := g.b; assert a * x + b * y == r; //- loop invariant assert a * nx + b * ny == nr; //- loop invariant calc { //- J(A)*FIV(X') + J(B)*FIV(Y'); a * x' + b * y'; a * (x - (r / nr) * nx) + b * (y - (r / nr) * ny); { lemma_mul_is_distributive(a, x, (r / nr) * nx); } { lemma_mul_is_distributive(b, y, (r / nr) * ny); } a * x + b * y - (a * ((r / nr) * nx) + b * ((r / nr) * ny)); { lemma_mul_is_commutative_forall(); } { lemma_mul_is_associative_forall(); } a * x + b * y - (a * nx * (r / nr) + b * ny * (r / nr)); { lemma_mul_is_distributive(r / nr, a * nx, b * ny); } a * x + b * y - (a * nx + b * ny) * (r / nr); r - nr * (r / nr); { lemma_fundamental_div_mod(r, nr); } r % nr; J(M); } forall g:nat ensures is_gcd(nr, r % nr, g) ==> is_gcd(a, b, g); { if (is_gcd(nr, r % nr, g)) { calc ==> { divides(g, r % nr) && divides(g, nr); { lemma_divides_multiple(g, nr, r / nr); } divides(g, r % nr) && divides(g, nr * (r / nr)); { lemma_divides_sum(g, r % nr, nr * (r / nr)); } divides(g, r % nr + nr * (r / nr)); divides(g, nr * (r / nr) + r % nr); { lemma_fundamental_div_mod(r, nr); } divides(g, r); } forall x:int ensures g < x ==> !(divides(x, r) && divides(x, nr)); { if (g < x && divides(x, r) && divides(x, nr)) { calc { (r % nr) % x; { lemma_fundamental_div_mod(nr, x); } (r % (x * (nr / x) + nr % x)) % x; (r % (x * (nr / x))) % x; { calc ==> { true; { lemma_nothing_bigger_divides(nr); } x <= nr; { lemma_div_is_ordered(x, nr, x); } x / x <= nr / x; { lemma_div_basics(x); } 1 <= nr / x; } } { lemma_mod_mod(r, x, nr / x); } r % x; } assert divides(x, r % nr); assert false; //- due to is_gcd(nr, r % nr, g) } } assert is_gcd(r, nr, g); assert is_gcd(a, b, g); //- by loop invariant } } var next_R_zero := FatNatIsZero(M); d' := Egcd_data_c(d.next_R, d.next_X, d.next_Y, M, next_R_zero, X', Y'); g' := Egcd_ghost_c(a, b); } method Extended_gcd_conclusion(A:array, B:array, d:Egcd_data, ghost g:Egcd_ghost) returns (X:FatInt, Y:FatInt) requires Extended_gcd_requires(A, B); requires Egcd_invariant(d, g); requires J(d.next_R)==0; //- loop termination condition requires BEWordSeqToInt(A[..]) == g.a; requires BEWordSeqToInt(B[..]) == g.b; ensures Extended_gcd_ensures(A, B, X, Y); { var dr_ref := d.R; //- do something real to d.R to convince dafnycc it's allocated var dnr_ref := d.next_R; //- do something real to d.next_R to convince dafnycc it's allocated var dx_ref := d.X.value; //- do something real to d.X.value to convince dafnycc it's allocated var dy_ref := d.Y.value; //- do something real to d.Y.value to convince dafnycc it's allocated var dnx_ref := d.next_X.value; //- do something real to d.next_X.value to convince dafnycc it's allocated var dny_ref := d.next_Y.value; //- do something real to d.next_Y.value to convince dafnycc it's allocated X := d.X; Y := d.Y; ghost var r := J(d.R); ghost var x := FIV(X); ghost var y := FIV(Y); ghost var a := g.a; ghost var b := g.b; calc { is_gcd(r, 0, r); { lemma_anything_divides_itself(r); } { lemma_anything_divides_zero(r); } { lemma_nothing_bigger_divides(r); } true; } assert is_gcd(r, 0, r); //- loop invariant: is_gcd(r, J(next_R), r) ==> is_gcd(a, b, r) //- loop termination: J(next_R) == 0 assert is_gcd(a, b, r); //- loop invariant: r == a * x + b * y assert is_gcd(a, b, a * x + b * y); //- put x, y into canonical form where 0 <= y < a //- y := y % a; //- x := x + b * (y / a); calc { a * (x + b * (y / a)) + b * (y % a); { lemma_mul_is_distributive(a, x, b * (y / a)); } a * x + a * (b * (y / a)) + b * (y % a); calc { a * (b * (y / a)); { lemma_mul_is_associative(a, b, y/a); } (a * b) * (y / a); { lemma_mul_is_commutative_forall(); } (b * a) * (y / a); { lemma_mul_is_associative(b, a, y/a); } b * (a * (y / a)); } a * x + b * (a * (y / a)) + b * (y % a); { lemma_mul_is_distributive(b, a * (y / a), y % a); } a * x + b * (a * (y / a) + (y % a)); { lemma_fundamental_div_mod(y, a); } a * x + b * y; } //- ensures -I(A) <= BV(Y) <= I(A); //- lemma_mod_remainder_specific(y, a); //- ensures (FIV(X)==1 && FIV(Y)==0) || -J(B) <= FIV(X) <= J(B); if (b == 0) { calc { x; x + 0 * (y / a); x + b * (y / a); 1; } calc { y; y % a; 0; } //- //- //- calc { //- x == 1; //- //-{ lemma_mul_is_mul_boogie(b, y / a); } //- x + b * (y / a) == 1; //- } //- calc { //- y == 0; //- //-{ lemma_mod_is_mod_boogie(0, a); } //- y % a == 0; //- } } else { calc ==> { true; { lemma_nothing_bigger_divides(a); } { lemma_nothing_bigger_divides(b); } r <= a && r <= b; } calc ==> { 0 <= y % a <= a - 1; { lemma_mul_inequality(y % a, a - 1, b); } { lemma_mul_inequality(0, y % a, b); } //- { lemma_mul_basics(b); } 0 <= (y % a) * b <= (a - 1) * b; { lemma_mul_is_distributive(b, a, 1); } //- { lemma_mul_basics(b); } 0 <= (y % a) * b <= a * b - b; //- { lemma_mul_is_commutative_forall(); } 0 <= b * (y % a) <= a * b - b; a * (x + b * (y / a)) <= a * (x + b * (y / a)) + b * (y % a) <= a * (x + b * (y / a)) + a * b - b; a * (x + b * (y / a)) <= r <= a * (x + b * (y / a)) + a * b - b; a * (x + b * (y / a)) <= r <= a * (x + b * (y / a)) + a * b; { lemma_mul_is_distributive(a, x + b * (y / a), b); } a * (x + b * (y / a)) <= r <= a * (x + b * (y / a) + b); { lemma_div_is_ordered(a * (x + b * (y / a)), r, a); } { lemma_div_is_ordered(r, a * (x + b * (y / a) + b), a); } a * (x + b * (y / a)) / a <= r / a <= a * (x + b * (y / a) + b) / a; { lemma_div_multiples_vanish(x + b * (y / a), a); } { lemma_div_multiples_vanish(x + b * (y / a) + b, a); } x + b * (y / a) <= r / a <= x + b * (y / a) + b; { assert 0 <= r <= a; } { lemma_small_div(); } //- { lemma_div_basics(a); } x + b * (y / a) <= 1 && 0 <= x + b * (y / a) + b; -b <= x + b * (y / a) <= b; } } //- assert Y.value.Length < power2(27); var YQ, YC := FatIntDiv(Y, FatInt_ctor(false, A)); var yq_ref := YQ.value; //- do something real to YQ.value to convince dafnycc it's allocated var yc_ref := YC.value; //- do something real to YC.value to convince dafnycc it's allocated lemma_fundamental_div_mod_converse(FIV(Y), J(A), FIV(YQ), FIV(YC)); assert J(YC.value) < J(A); //- lemma_modesty_word_value_equivalence(YC.value); //- lemma_modesty_word_value_equivalence(A); Y := YC; var XC := FatIntMul(FatInt_ctor(false, B), YQ); var xc_ref := XC.value; //- do something real to XC.value to convince dafnycc it's allocated X := FatIntAdd(X, XC); var x_ref := X.value; //- do something real to X.value to convince dafnycc it's allocated //- lemma_modesty_word_value_equivalence(X.value); //- lemma_modesty_word_value_equivalence(B); //- renaming these symbols to catch up with new values of X, Y x := FIV(X); y := FIV(Y); //- ensures FIV(X)!=0 || FIV(Y)!=0; calc <==> { x == 0 && y == 0; { assert is_gcd(a, b, a * x + b * y); lemma_mul_basics(a); lemma_mul_basics(b); } //- { lemma_mul_is_mul_boogie(a, 0); } //- { lemma_mul_is_mul_boogie(b, 0); } is_gcd(a, b, 0); false; } //- ensures opposing_signs(FIV(X), FIV(Y)); if (b != 0) { calc ==> { 1 <= x && 1 <= y; { lemma_mul_inequality(1, x, a); } { lemma_mul_inequality(1, y, b); } //- { lemma_mul_basics(a); } //- { lemma_mul_basics(b); } a <= x * a && b <= y * b; //- { lemma_mul_is_commutative_forall(); } { lemma_mul_is_commutative(a, b); lemma_mul_is_commutative(y, b); } a <= a * x && b <= b * y; a + b <= a * x + b * y; r < a * x + b * y; false; } } //- assert A.Length < power2(27); //- var Xc := CanonicalizeFatInt(X); //- ghost var pv := power2(32); //- lemma_2toX(); //- assert x < a; //- calc { //- BEDigitSeqToInt(pv, Xc.value[..]); //- BEDigitSeqToInt(pv, X.value[..]); //- < //- BEDigitSeqToInt(pv, A[..]); //- } //- lemma_CanonicalLength_inherit(pv, Xc.value[..], A[..], power2(27)); //- assert (Xc.value.Length < power2(27)); //- //- var Yc := CanonicalizeFatInt(Y); //- lemma_CanonicalLength_inherit(pv, Yc.value[..], A[..], power2(27)); //- //- X := Xc; //- Y := Yc; assert a == BEWordSeqToInt(A[..]); assert b == BEWordSeqToInt(B[..]); } method Extended_gcd(A:array, B:array) returns (X:FatInt, Y:FatInt) //- decreases J(A); requires Extended_gcd_requires(A, B); ensures Extended_gcd_ensures(A, B, X, Y); { var d; ghost var g; d,g := Extended_gcd_init(A, B); while (!d.next_R_zero) invariant Egcd_invariant(d, g); invariant g.a == BEWordSeqToInt(A[..]); invariant g.b == BEWordSeqToInt(B[..]); decreases J(d.next_R); { d, g := Extended_gcd_step(d, g); } X,Y := Extended_gcd_conclusion(A, B, d, g); } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Crypto/RSA/KeyGen.i.dfy ================================================ include "KeyGen.s.dfy" include "MillerRabin.i.dfy" static predicate PrimeGenerationWorksheetValid_precondition(worksheet:PrimeGenerationWorksheet) { 0 < |worksheet.rows| //- && CandidateSeedWorksheetValid_precondition(worksheet.rows[|worksheet.rows|-1].candidate) } static predicate PrimeGenerationWorksheetValid_incremental(keybits:int, worksheet:PrimeGenerationWorksheet, last_succeeds:bool) requires 0 PrimeGenerationWorksheetRowValid(keybits, worksheet.rows[i])) //- all but last row fail, last row as specified && (forall i :: 0<=i<|worksheet.rows|-1 ==> !worksheet.rows[i].miller_rabin_worksheet.is_probably_prime) && ( 0<|worksheet.rows| ==> worksheet.rows[|worksheet.rows|-1].miller_rabin_worksheet.is_probably_prime == last_succeeds ) //- randoms properly accounted for && PrimeGenerationWorksheetConsumesRandoms(worksheet.rows) == worksheet.randoms } static function PrimeGenerationWorksheetAppend(keybits:int, worksheet:PrimeGenerationWorksheet, worksheet_row:PrimeGenerationWorksheetRow, last_accepted:bool) : PrimeGenerationWorksheet requires 0, ghost worksheet:PrimeGenerationWorksheet) requires 3 < keybits; requires keybits < power2(32); ensures WellformedFatNat(Random); ensures IsProbablyPrime(J(Random), Configure_MillerRabinStrength()); ensures power2(keybits-1) <= J(Random) < power2(keybits); ensures PrimeGenerationWorksheetValid_precondition(worksheet); ensures PrimeGenerationWorksheetValid(keybits, worksheet); ensures PrimeGenerationOutput(worksheet) == J(Random); requires TPM_ready(); ensures TPM_ready(); modifies this`TPM; modifies this`IoMemPerm; ensures TPMs_match_except_for_randoms(old(TPM), TPM); ensures old(TPM).random_index <= TPM.random_index; ensures worksheet.randoms == TPM_random_bytes_premium(old(TPM).random_index, TPM.random_index); { var isProbablyPrime:bool := false; worksheet := PrimeGenerationWorksheet_c([], []); lemma_power2_strictly_increases(30,32); //- assert(Word32(keybits-1)); var Offset := FatPower2(keybits-1); Random := Offset; //- dafnycc: initialize variable ghost var started := false; while (!isProbablyPrime) decreases *; invariant WellformedFatNat(Offset); invariant J(Offset) == power2(keybits-1); invariant isProbablyPrime ==> WellformedFatNat(Random); invariant isProbablyPrime ==> power2(keybits-1) <= J(Random) < power2(keybits); invariant isProbablyPrime ==> IsProbablyPrime(J(Random), Configure_MillerRabinStrength()); invariant PrimeGenerationWorksheetValid_incremental(keybits, worksheet, isProbablyPrime); invariant isProbablyPrime ==> 0 < |worksheet.rows|; invariant isProbablyPrime ==> started; invariant started ==> PrimeGenerationWorksheetValid_precondition(worksheet); invariant isProbablyPrime ==> PrimeGenerationOutput(worksheet) == J(Random); invariant TPM_ready(); invariant TPMs_match_except_for_randoms(old(TPM), TPM); invariant old(TPM).random_index <= TPM.random_index; invariant worksheet.randoms == TPM_random_bytes_premium(old(TPM).random_index, TPM.random_index); { var Entropy:array; ghost var randoms:seq; ghost var loop_TPM_index := TPM.random_index; Entropy,randoms := FatNatRandomPower2(keybits-1); assert randoms == TPM_random_bytes_premium(loop_TPM_index, TPM.random_index); assert 0<=J(Entropy)); static predicate CandidatePrimeWorksheetValid(keybits:int, worksheet:CandidatePrimeWorksheet) requires 0); static predicate PrimeGenerationWorksheetRowValid(keybits:int, row:PrimeGenerationWorksheetRow) requires 0, randoms:seq); static function PrimeGenerationWorksheetConsumesRandoms(rows:seq) : seq { if (rows==[]) then [] else PrimeGenerationWorksheetConsumesRandoms(rows[..|rows|-1]) + rows[|rows|-1].randoms } static predicate {:autoReq} PrimeGenerationWorksheetValid(keybits:int, worksheet:PrimeGenerationWorksheet) { //- each row locally valid (forall i :: 0<=i<|worksheet.rows| ==> PrimeGenerationWorksheetRowValid(keybits, worksheet.rows[i])) //- all but last row fail, last row succeeds && (forall i :: 0<=i<|worksheet.rows|-1 ==> !worksheet.rows[i].miller_rabin_worksheet.is_probably_prime) && 0<|worksheet.rows| && worksheet.rows[|worksheet.rows|-1].miller_rabin_worksheet.is_probably_prime //- randoms properly accounted for && PrimeGenerationWorksheetConsumesRandoms(worksheet.rows) == worksheet.randoms } static function {:autoReq} PrimeGenerationOutput(worksheet:PrimeGenerationWorksheet) : int requires 0<|worksheet.rows|; { worksheet.rows[|worksheet.rows|-1].candidate.candidate } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Crypto/RSA/KeyImpl.i.dfy ================================================ include "RSASpec.s.dfy" include "../../FatNat/FatNatCommon.i.dfy" include "../../FatNat/FatNatReciprocal.i.dfy" datatype RSAPubKeyImpl_internal = RSAPubKeyImpl_c_internal( n:array, //- modulus size:nat, e:array, //- public key exponent nReciprocal:FNDivReciprocal ); predicate {:heap} WellformedRSAPubKeyImpl_internal(pub:RSAPubKeyImpl_internal) reads pub.n; reads pub.e; reads if pub.nReciprocal.FNDivKnownReciprocal? then pub.nReciprocal.TwoTo32wDividedByD else pub.n; { //- FrumpyBigNat(pub.n) true && WellformedFatNat(pub.n) && WellformedFatNat(pub.e) //- && pub.n.Length < power2(25) //- transitional, while converting to FatNats && 0 //- private key exponent ); predicate {:heap} WellformedRSAKeyPairImpl_internal(p:RSAKeyPairImpl_internal) reads p.pub.n; reads p.pub.e; reads p.d; reads if p.pub.nReciprocal.FNDivKnownReciprocal? then p.pub.nReciprocal.TwoTo32wDividedByD else p.pub.n; { WellformedRSAPubKeyImpl_internal(p.pub) && WellformedFatNat(p.d) //- && FrumpyBigNat(p.d) } function {:heap} PubKeyImplToSpec_internal(pubkey:RSAPubKeyImpl_internal) : RSAPubKeySpec requires WellformedRSAPubKeyImpl_internal(pubkey); reads pubkey.n; reads pubkey.e; reads if pubkey.nReciprocal.FNDivKnownReciprocal? then pubkey.nReciprocal.TwoTo32wDividedByD else pubkey.n; { RSAPublicKeySpec_c(J(pubkey.n), pubkey.size, J(pubkey.e)) } function {:heap} KeyPairImplToSpec_internal(key:RSAKeyPairImpl_internal) : RSAKeyPairSpec requires WellformedRSAKeyPairImpl_internal(key); reads key.d; reads key.pub.n; reads key.pub.e; reads if key.pub.nReciprocal.FNDivKnownReciprocal? then key.pub.nReciprocal.TwoTo32wDividedByD else key.pub.n; { RSAKeyPairSpec_c(PubKeyImplToSpec_internal(key.pub), J(key.d)) } lemma {:heap} lemma_WellformedPubKeyImplImpliesWellformedPubKeySpec (pubkey:RSAPubKeyImpl_internal) requires WellformedRSAPubKeyImpl_internal(pubkey); ensures WellformedRSAPubKeySpec(PubKeyImplToSpec_internal(pubkey)); { } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Crypto/RSA/KeybitsLength.i.dfy ================================================ include "../../BigNum/BigNumBEAdaptor.i.dfy" lemma lemma_keybits_implies_length(N:BigNat, w:nat) requires WellformedBigNat(N); requires 0 !divides(cf, n) } predicate IsEvenFatNat_inner(N:array) reads N; requires WellformedFatNat(N); { N.Length==0 || IsEven(ArrayDigitAt(N,0)) } lemma lemma_bignat_even(N:array) requires WellformedFatNat(N); ensures IsEven(BEWordSeqToInt(N[..])) == IsEvenFatNat_inner(N); { var Ns := N[..]; var Nv := BEWordSeqToInt(Ns); if (N.Length == 0) { calc { IsEven(BEWordSeqToInt(N[..])); IsEven(Nv); { lemma_even_mod_0_pos(Nv); } mod(Nv, 2) == 0; { reveal_BEDigitSeqToInt_private(); } mod(0, 2) == 0; { lemma_small_mod(0,2); } true; IsEvenFatNat_inner(N); } } else { lemma_2toX(); var pv := power2(32); var Hv := BEDigitSeqToInt(pv, SelectDigitRange(Ns, |Ns|, 1)); var Lv := DigitAt(Ns,0); if (|Ns|==1) { assert Ns == [Lv]; //- OBSERVE SEQ calc { Nv; BEDigitSeqToInt(pv, [Lv]); { lemma_BEDigitSeqToInt_singleton(pv, Lv); } Lv; ArrayDigitAt(N,0); } } else { var L2 := 2; calc { Nv; { lemma_BEInterpretation_Select(pv, Ns, 1); } Hv * power(pv,1) + BEDigitSeqToInt(pv, SelectDigitRange(Ns, 1, 0)); { lemma_SelectSingletonRange(Ns, 1, 0); } Hv * power(pv,1) + BEDigitSeqToInt(pv, [DigitAt(Ns,0)]); { lemma_BEDigitSeqToInt_singleton(pv, Lv); } Hv * power(pv,1) + Lv; { lemma_power2_unfolding(32, 1); lemma_mul_is_mul_boogie(32, 1); } Hv * power2(32*1) + Lv; { lemma_power2_adds(32*1-1,1); } Hv * (power2(32*1-1) * power2(1)) + Lv; { lemma_mul_is_associative_forall(); } (Hv*power2(32*1-1)) * power2(1) + Lv; { lemma_fundamental_div_mod(Lv,L2); } (Hv*power2(32*1-1)) * power2(1) + L2*(Lv/L2) + Lv%L2; { lemma_power2_1_is_2(); lemma_mul_is_commutative_forall(); } L2*(Hv*power2(32*1-1)) + L2*(Lv/L2) + Lv%L2; { lemma_mul_is_distributive_forall(); } L2*(Hv*power2(32*1-1) + Lv/L2) + Lv%L2; } var ugly := Hv*power2(32*1-1) + Lv/L2; calc { Nv % L2; (L2*ugly + Lv%L2) % L2; { lemma_mod_multiples_vanish(ugly, Lv%L2, L2); } (Lv%L2) % L2; { lemma_mod_properties(); lemma_small_mod(Lv%L2, L2); } Lv%L2; ArrayDigitAt(N,0) % L2; } } calc { IsEven(BEWordSeqToInt(N[..])); { lemma_even_mod_0_pos(Nv); } mod(Nv, 2) == 0; mod(ArrayDigitAt(N,0), 2) == 0; { lemma_even_mod_0_pos(ArrayDigitAt(N,0)); } IsEvenFatNat_inner(N); } } //- var w31 := power2(31); //- reveal_power2(); //- assert w31*2 == Width(); //- { lemma_mul_is_mul_boogie(w31,2); } //- assert mul(w31,2) == Width(); //- if (IsEven(lo(N))) //- { //- var y0:int :| mul(y0, 2) == lo(N); //- lemma_mul_is_mul_boogie(y0, 2); //- var y := w31 * J(hi(N)) + y0; //- //- calc { //- mul(y, 2); //- { lemma_mul_is_mul_boogie(y, 2); } //- y * 2; //- (w31*J(hi(N)) + y0) * 2; //- { lemma_mul_is_distributive_add_forall(); } //- (w31*J(hi(N)))*2 + y0*2; //- { lemma_mul_is_mul_boogie((w31*J(hi(N))),2); } //- mul(w31*J(hi(N)),2) + y0*2; //- { lemma_mul_is_commutative_forall(); } //- mul(2,w31*J(hi(N))) + y0*2; //- { lemma_mul_is_associative_forall(); } //- mul(mul(2,w31),J(hi(N))) + y0*2; //- { lemma_mul_is_commutative_forall(); } //- mul(mul(w31,2),J(hi(N))) + y0*2; //- mul(Width(),J(hi(N))) + y0*2; //- Width()*J(hi(N)) + y0*2; //- Width()*J(hi(N)) + lo(N); //- { //- lemma_hilo(N); //- lemma_mul_is_commutative_forall(); //- } //- J(N); //- } //- assert IsEven(J(N)); //- } //- if (IsEven(J(N))) //- { //- var y :| mul(y, 2) == J(N); //- lemma_mul_is_mul_boogie(y, 2); //- calc ==> { //- true; //- { //- lemma_hilo(N); //- lemma_mul_is_commutative_forall(); //- } //- y*2 == Width()*J(hi(N)) + lo(N); //- y*2 == mul(w31,2)*J(hi(N)) + lo(N); //- y*2 - mul(w31,2)*J(hi(N)) == lo(N); //- { //- lemma_mul_is_commutative_forall(); //- lemma_mul_is_associative_forall(); //- } //- y*2 - mul(mul(w31,J(hi(N))),2) == lo(N); //- { lemma_mul_is_mul_boogie(y,2); } //- mul(y,2) - mul(mul(w31,J(hi(N))),2) == lo(N); //- { lemma_mul_is_commutative_forall(); } //- mul(2,y) - mul(2,mul(w31,J(hi(N)))) == lo(N); //- { lemma_mul_is_distributive_sub(2, y, mul(w31,J(hi(N)))); } //- mul(2, y - mul(w31,J(hi(N)))) == lo(N); //- mul(2, y - w31*J(hi(N))) == lo(N); //- { lemma_mul_is_commutative_forall(); } //- mul(y - w31*J(hi(N)), 2) == lo(N); //- { lemma_mul_is_mul_boogie(y - w31*J(hi(N)),2); } //- IsEven(lo(N)); //- } //- } } static function method WordIsEven_def(x:nat) : bool requires Word32(x); { x%2 == 0 } static lemma lemma_WordIsEven(x:nat) requires Word32(x); ensures WordIsEven_def(x) == IsEven(x); { lemma_even_mod_0_pos(x); lemma_mod_is_mod_boogie(x, 2); } static function method WordIsEven(x:nat) : bool requires Word32(x); ensures IsEven(x) == WordIsEven(x); { lemma_WordIsEven(x); WordIsEven_def(x) } function method IsEvenFatNat_def(N:array) : bool reads N; requires WellformedFatNat(N); { if (N.Length==0) then true else WordIsEven(ArrayDigitAt(N,0)) } lemma lemma_IsEvenFatNat(N:array) requires WellformedFatNat(N); ensures IsEvenFatNat_def(N) == IsEven(J(N)); { if (N.Length==0) { calc { IsEvenFatNat_def(N); true; { lemma_mul_is_mul_boogie(0, 2); } { assert mul(0, 2) == 0; } IsEven(0); { reveal_BEDigitSeqToInt_private(); } IsEven(J(N)); } } else { calc { IsEvenFatNat_def(N); WordIsEven(ArrayDigitAt(N,0)); IsEven(ArrayDigitAt(N,0)); { lemma_bignat_even(N); } IsEven(J(N)); } } } function method IsEvenFatNat(N:array) : bool reads N; requires WellformedFatNat(N); ensures IsEvenFatNat(N) == IsEven(J(N)); { lemma_IsEvenFatNat(N); IsEvenFatNat_def(N) } static lemma lemma_dividing_by_two(n:nat, q:nat, r:nat) requires 0 < n; requires mul(q,2)+r==n; requires r<2; requires IsEven(n); ensures 0 < q; ensures q < n; ensures r == 0; { if (r!=0) { var y:int :| mul(y, 2) == n; assert r==1; calc ==> { mul(q,2)+1==n; mul(q,2)+1==mul(y,2); 1==mul(y,2) - mul(q,2); { lemma_mul_is_commutative_forall(); } 1==mul(2,y) - mul(2,q); { lemma_mul_is_distributive_sub(2,y,q); } 1==mul(2,y-q); { lemma_mul_is_mul_boogie(2,y-q); } 1==2*(y-q); { lemma_no_half(y-q); } false; } } assert r==0; calc ==> { 0 < mul(q,2); { lemma_mul_basics(2); } mul(0,2) < mul(q,2); { lemma_mul_strict_inequality_converse(0,q,2); } 0 < q; } calc ==> { true; { lemma_mul_strictly_increases(2,q); } q < mul(2,q); { lemma_mul_is_commutative_forall(); } q < mul(q,2); q < n; } } method MR_find_s_D(N:array, two:array) returns (s:nat, D:array) decreases J(N); //- requires ModestBigNatWords(N); requires WellformedFatNat(N); requires 0 < J(N); requires WellformedFatNat(two); requires J(two) == 2; //- requires ModestBigNatWords(two); ensures WellformedFatNat(D); ensures 0 < J(D); ensures power2(s)*J(D) == J(N); ensures J(D) <= J(N); ensures !IsEven(J(D)); { D := N; s := 0; calc { power2(s)*J(D); power2(0)*J(D); { lemma_power2_0_is_1(); } mul(1,J(D)); { lemma_mul_basics_forall(); } J(D); J(N); } while (IsEvenFatNat(D)) invariant WellformedFatNat(D); invariant 0 < J(D); invariant power2(s)*J(D) == J(N); invariant J(D) <= J(N); decreases J(D); { lemma_2to32(); assert 2 < Width(); //- assert ModestBigNatWords(D); var Nover2_nc:array,zero:array := FatNatDiv(D, two); var Nover2 := CanonicalizeArray(Nover2_nc); calc { mul(J(Nover2),2)+J(zero); { lemma_mul_is_commutative_forall(); } J(D); } lemma_dividing_by_two(J(D), J(Nover2), J(zero)); assert 0 < J(Nover2); assert J(Nover2) < J(D); assert J(zero)==0; //- else !WordIsEven() //- calc ==> { //- J(Nover2) <= J(D); //- { lemma_modesty_word_value_equivalence(D); } //- J(Nover2) < KindaBigNat(); //- { lemma_modesty_word_value_equivalence(Nover2); } //- ModestBigNatWords(Nover2); //- } calc { power2(s+1) * J(Nover2); { lemma_power2_adds(s,1); } (power2(s) * power2(1)) * J(Nover2); { lemma_mul_is_associative_forall(); } power2(s) * (power2(1) * J(Nover2)); { lemma_power2_1_is_2(); } power2(s) * mul(2, J(Nover2)); { lemma_mul_is_commutative_forall(); } power2(s) * mul(J(Nover2), 2); power2(s) * (J(D)); J(N); } D := Nover2; s := s + 1; } } static lemma lemma_even_divisble_by_2(x:int) requires 0 <= x; requires IsEven(x); ensures divides(2,x); { lemma_even_mod_0_pos(x); assert mod(x, 2) == 0; assert divides(2,x); } method ProbeLoop(N:array, Nminus1:array, Xinit:array, s:int, ghost problem:MRProblem, ghost probe_init:MRProbe) returns (isProbablyPrime:bool, ghost probe:MRProbe) requires WellformedFatNat(N); requires MRProblemNeedsProbes(problem); requires WellformedFatNat(Nminus1); requires J(Nminus1) == J(N) - 1; requires WellformedFatNat(Xinit); requires MRProblemValid(problem); requires probe_init.squares == [J(Xinit)]; requires J(Xinit) != 1; requires J(Xinit) != problem.n-1; requires MRProbeInit(problem, probe_init); requires problem.n == J(N); requires problem.s == s; ensures probe.a == probe_init.a; ensures isProbablyPrime ==> MRProbeSucceeds(problem, probe); ensures !isProbablyPrime ==> MRProbeFails(problem, probe); { //- lemma_frumpy_is_modest(N); isProbablyPrime := true; probe := probe_init; var si:int := 1; var probing := true; var X:array := Xinit; while (si <= s-1) //- invariant FrumpyBigNat(X); invariant MRProblemValid(problem); invariant 0 < |probe.squares|; invariant 0 |probe.squares| <= s; invariant MRProbeInit(problem, probe); invariant si==|probe.squares|; invariant probe.a == probe_init.a; invariant WellformedFatNat(X); invariant probe.squares[si-1] == J(X); invariant isProbablyPrime ==> (forall i :: 0 MRProbeChain(problem, probe, i)); invariant !isProbablyPrime || probing || MRProbeSucceeds(problem, probe); invariant !isProbablyPrime ==> MRProbeFails(problem, probe); invariant isProbablyPrime && !probing ==> probe.squares[|probe.squares|-1]==problem.n-1; invariant MRProbeValid(problem, probe); invariant forall i :: 0 probe.squares[i] != 1; invariant si <= MRProbeLimit(problem); invariant forall i :: 0<=i<|probe.squares| ==> probe.squares[i] != problem.n-1; { var Xsquared:array := FatNatMul(X,X); lemma_mul_nonnegative(J(X),J(X)); //- lemma_frumpy_squared_is_modest(X,Xsquared); assert 0 <= J(Xsquared); assert 0 < J(N); var oldX := X; var X_nc := FatNatModulo(Xsquared, N); X := CanonicalizeArray(X_nc); ghost var old_probe := probe; assert |old_probe.squares|==si; assert forall i :: 0 MRProbeChain(problem, old_probe, i); assert forall i :: 0 old_probe.squares[i] != 1; probe := MRProbe_c(probe.a, probe.squares + [J(X)]); lemma_mod_pos_bound(J(Xsquared),J(N)); assert J(X) < J(N); //- assert FrumpyBigNat(X); lemma_2to32(); calc { probe.squares[si]; J(X); J(Xsquared) % J(N); (J(oldX)*J(oldX)) % J(N); { lemma_square_is_power_2(J(oldX)); } power(J(oldX),2) % J(N); { assert probe.squares[si-1] == J(oldX); } power(probe.squares[si-1],2) % J(N); power(probe.squares[si-1],2) % problem.n; } var is_one:bool := TestEqSmallLiteralFatNat(1, X); if (is_one) { //- n divides (a^{d2^{r-1}}-1)(a^{d2^{r-1}}+1); //- hence n could be factored. isProbablyPrime := false; probing := false; assert probing ==> s <= si; forall (i:int | 0 probe.squares[i]!=1); } else { assert (0 probe.squares[i]!=1); } } assert 0 < |probe.squares| <= problem.s; assert MRProblemValid(problem); assert MRProbeInit(problem,probe); assert forall i:int :: (0 MRProbeChain(problem, probe, i)); assert forall i:int :: (0 probe.squares[i]!=1); assert MRProbeValid(problem, probe); assert probing ==> forall i :: 0<=i<|probe.squares| ==> probe.squares[i] != problem.n-1; break; } assert |probe.squares| == si+1; assert probe.squares[si] == power(probe.squares[si-1], 2) % problem.n; assert MRProbeChain(problem, probe, si); var is_nminus1:bool := FatNatEq(X, Nminus1); if (is_nminus1) { //- "do next WitnessLoop" -- this one is successful probing := false; calc { |probe.squares|; si+1; <= s; } calc { probe.squares[|probe.squares|-1]; J(X); J(Nminus1); J(N)-1; problem.n-1; } forall (i | 0 s <= si; assert MRProbeValid(problem, probe); assert probing ==> forall i :: 0<=i<|probe.squares| ==> probe.squares[i] != problem.n-1; break; } ghost var old_si:int := si; assert forall i :: 0 MRProbeChain(problem, old_probe, i); forall (i | 0 MRProbeChain(problem, probe, i); } if (probing) { //- Unsatisfactory initial X, and never //- found the x-1 we needed in s-1 additional steps. isProbablyPrime := false; } assert isProbablyPrime ==> MRProbeSucceeds(problem, probe); if (!isProbablyPrime) { assert MRProbeValid(problem, probe); assert (|probe.squares| == MRProbeLimit(problem) || (0 < |probe.squares| && probe.squares[|probe.squares|-1] == 1)); assert probe.squares!=[1]; assert probe.squares!=[problem.n-1]; assert probe.squares[|probe.squares|-1]!=problem.n-1; } assert !isProbablyPrime ==> MRProbeFails(problem, probe); } static predicate MillerRabinSpecSucceeding_incremental(problem:MRProblem, probes:seq) //- all probes succeed //- probed exactly as many times as problem strength requires { MRProblemNeedsProbes(problem) && problem.n%2==1 && problem.n>3 && forall i :: 0 <= i < |probes|-1 ==> MRProbeSucceeds(problem, probes[i]) } static predicate MillerRabinWorksheetValid_incremental(n:int, worksheet:MillerRabinWorksheet) { |worksheet.probes|==|worksheet.probe_candidates| && |worksheet.probes|==|worksheet.probe_seed_reqs| && (forall i :: 0<=i<|worksheet.probes| ==> MillerRabinProbeConsistency(n, worksheet.probe_candidates[i], worksheet.probe_seed_reqs[i], worksheet.probes[i])) && worksheet.problem.n == n && worksheet.problem.strength == Configure_MillerRabinStrength() && MillerRabinSpecSucceeding_incremental(worksheet.problem, worksheet.probes) && MillerRabinWorksheetConsumesRandoms(worksheet.probe_candidates) == worksheet.randoms } method GhostFatNatCountBits(x:array) returns (ghost e:nat) requires x!=null && IsWordSeq(x[..]); ensures FatNatBitCount(x[..], e); { var real_e := FatNatCountBits(x); e := real_e; } method {:timeLimitMultiplier 3} WitnessLoop(N:array, Nminus1:array, Nminus2:array, D:array, s:int, two:array, strength:nat, ghost problem:MRProblem) returns (isProbablyPrime:bool, ghost worksheet:MillerRabinWorksheet) requires WellformedFatNat(N); //- requires FrumpyBigNat(N); requires MRProblemNeedsProbes(problem); requires WellformedFatNat(Nminus1); requires J(Nminus1) == J(N) - 1; requires WellformedFatNat(Nminus2); //- requires ModestBigNatWords(Nminus2); requires J(Nminus2) == J(N) - 2; requires WellformedFatNat(D); //- requires FrumpyBigNat(D); requires WellformedFatNat(two); //- requires ModestBigNatWords(two); requires J(two) == 2; requires strength == Configure_MillerRabinStrength(); requires MRProblemValid(problem); requires problem.n == J(N); requires problem.strength == strength; requires problem.s == s; requires problem.d == J(D); ensures MillerRabinWorksheetValid(problem.n, worksheet); ensures MillerRabinSpecValid(problem, worksheet.probes, worksheet.is_probably_prime); ensures worksheet.is_probably_prime == isProbablyPrime; requires TPM_ready(); ensures TPM_ready(); modifies this`TPM; modifies this`IoMemPerm; ensures TPMs_match_except_for_randoms(old(TPM), TPM); ensures old(TPM).random_index <= TPM.random_index; ensures worksheet.randoms == TPM_random_bytes_premium(old(TPM).random_index, TPM.random_index); { ghost var probes := []; worksheet := MillerRabinWorksheet_c( problem, [], [], [], true, []); assert MillerRabinWorksheetValid_incremental(J(N), worksheet); var ki:int :=0; isProbablyPrime := true; while (ki < strength && isProbablyPrime) decreases strength - ki; invariant (forall i :: 0<=i<|probes|-1 ==> MRProbeSucceeds(problem, probes[i])); invariant !isProbablyPrime ==> 0<|probes| && MRProbeFails(problem, probes[|probes|-1]); invariant (forall probe :: 0 <= probe < |probes| ==> MRProbeValid(problem, probes[probe])); invariant isProbablyPrime ==> (forall probe :: 0 <= probe < |probes| ==> MRProbeSucceeds(problem, probes[probe])); invariant MRProblemValid(problem); invariant |probes|==ki; invariant ki <= strength; invariant worksheet.problem == problem; invariant worksheet.probes == probes; invariant MillerRabinWorksheetValid_incremental(J(N), worksheet); invariant worksheet.is_probably_prime == isProbablyPrime; invariant TPM_ready(); invariant TPMs_match_except_for_randoms(old(TPM), TPM); invariant old(TPM).random_index <= TPM.random_index; invariant worksheet.randoms == TPM_random_bytes_premium(old(TPM).random_index, TPM.random_index); { ghost var loop_TPM_index := TPM.random_index; ghost var Nminus2fatbits := GhostFatNatCountBits(Nminus2); ghost var req := SelectRandomRequest_c(2, J(Nminus2), Nminus2fatbits); lemma_power2_0_is_1(); var A:array,candidate_worksheet := FatNatRandomFromInclusiveRange(two, Nminus2, req); assert TPM_random_bytes_premium(loop_TPM_index, TPM.random_index) == candidate_worksheet.randoms; var X:array := FatNatModExp(A, D, N); //- assert FrumpyBigNat(X); ghost var probe:MRProbe := MRProbe_c(J(A), [J(X)]); calc { probe.squares[0]; J(X); power(J(A),J(D)) % J(N); power(probe.a, problem.d) % problem.n; } assert MRProbeInit(problem, probe); assert MRProbeValid(problem, probe); lemma_2toX(); var is_one:bool := TestEqSmallLiteralFatNat(1, X); if (is_one) { //- "continue" assert probe.squares==[J(X)]==[1]; assert MRProbeSucceeds(problem, probe); } else { var is_nminus1:bool := FatNatEq(X, Nminus1); if (is_nminus1) { //- "continue" calc { probe.squares; [J(X)]; [J(Nminus1)]; [J(N)-1]; [problem.n - 1]; } assert MRProbeSucceeds(problem, probe); } else { isProbablyPrime,probe := ProbeLoop(N, Nminus1, X, s, problem, probe); } //- "continue" } //- "continue" probes := probes + [probe]; ki := ki + 1; ghost var worksheet' := MillerRabinWorksheet_c( problem, worksheet.probe_candidates + [candidate_worksheet], worksheet.probe_seed_reqs + [req], worksheet.probes + [probe], isProbablyPrime, worksheet.randoms + candidate_worksheet.randoms); //- assert MillerRabinWorksheetConsumesRandoms(worksheet'.probe_candidates) == worksheet'.randoms; assert MillerRabinWorksheetValid_incremental(J(N), worksheet'); assert old(TPM).random_index + |worksheet.randoms| == loop_TPM_index; assert TPM_random_bytes_premium( old(TPM).random_index, old(TPM).random_index + |worksheet.randoms|) == worksheet.randoms; // loop invariant assert TPM_random_bytes_premium(loop_TPM_index, TPM.random_index) == candidate_worksheet.randoms; // FatNatRandomFromInclusiveRange assert loop_TPM_index == old(TPM).random_index + |worksheet.randoms|; assert TPM.random_index == loop_TPM_index + |candidate_worksheet.randoms|; assert TPM_random_bytes_premium( old(TPM).random_index + |worksheet.randoms|, old(TPM).random_index + |worksheet.randoms| + |candidate_worksheet.randoms|) == candidate_worksheet.randoms; lemma_random_comprehension(old(TPM).random_index, worksheet.randoms, candidate_worksheet.randoms); worksheet := worksheet'; assert (forall probe :: 0 <= probe < |probes| ==> MRProbeValid(problem, probes[probe])); } if (isProbablyPrime) { assert strength <= ki; assert forall probe :: 0 <= probe < |probes| ==> MRProbeSucceeds(problem, probes[probe]); calc { problem.strength; strength; <= ki; |probes|; } assert MillerRabinSpecSucceeds(problem, probes); } else { assert MRProbeValid(problem, probes[|probes|-1]); assert MillerRabinSpecFails(problem, probes); } } method {:timeLimitMultiplier 3} MillerRabinTest(N:array, strength:nat) returns (isProbablyPrime:bool, ghost worksheet:MillerRabinWorksheet) //- requires FrumpyBigNat(N); requires WellformedFatNat(N); requires J(N) > 3; requires strength == Configure_MillerRabinStrength(); ensures isProbablyPrime ==> IsProbablyPrime(J(N), strength); ensures MillerRabinWorksheetValid(J(N), worksheet); ensures worksheet.is_probably_prime == isProbablyPrime; requires TPM_ready(); ensures TPM_ready(); modifies this`TPM; modifies this`IoMemPerm; ensures TPMs_match_except_for_randoms(old(TPM), TPM); ensures old(TPM).random_index <= TPM.random_index; ensures worksheet.randoms == TPM_random_bytes_premium(old(TPM).random_index, TPM.random_index); { ProfileTally(Tally_MillerRabinTest(), 1); //- debug_print(0x90, 0x88778877); //- lemma_frumpy_is_modest(N); lemma_2toX(); var early_reject:bool := false; var three := MakeBELiteralArray(3); var too_small := FatNatLe(N, three); if (too_small) { early_reject := true; assert J(N)<=3; } else if (IsEvenFatNat(N)) { early_reject := true; lemma_even_divisble_by_2(J(N)); lemma_mod_is_mod_boogie(J(N), 2); assert J(N) % 2 == 0; //- assert divides(2, J(N)); //- assert !IsPrime(J(N)); } assert early_reject ==> (J(N) <= 3 || J(N)%2==0); if (early_reject) { isProbablyPrime := false; //- even N? s & d irrelevant. ghost var problem := MRProblem_c(J(N), strength, 0, 0); worksheet := MillerRabinWorksheet_c( problem, //- No probes in this case. [], [], [], false, []); assert MillerRabinSpecFails(problem, []); } else { var one:array := MakeBELiteralArray(1); lemma_2toX32(); assert 2 < Width(); var two:array := MakeBELiteralArray(2); var Nminus1:array := FatNatSub(N,one); //- lemma_modesty_word_value_equivalence(N); //- lemma_modesty_word_value_equivalence(Nminus1); //- assert ModestBigNatWords(Nminus1); var Nminus2:array := FatNatSub(N,two); //- lemma_modesty_word_value_equivalence(Nminus2); lemma_power2_increases(power2(1), power2(31)); //- lemma_modesty_word_value_equivalence(two); var s:int,D:array := MR_find_s_D(Nminus1, two); //- assert FrumpyBigNat(D); ghost var problem:MRProblem := MRProblem_c(J(N), strength, s, J(D)); assert s==problem.s; lemma_x_odd(J(N)); lemma_x_odd(J(D)); calc { power(2,problem.s)*problem.d; power(2,s)*J(D); { lemma_power2_is_power_2(s); } power2(s)*J(D); J(N)-1; } assert MRProblemValid(problem); isProbablyPrime,worksheet := WitnessLoop(N, Nminus1, Nminus2, D, s, two, strength, problem); if (isProbablyPrime) { MillerRabinSpec(problem, worksheet.probes); } } } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Crypto/RSA/MillerRabin.s.dfy ================================================ include "../RandomNumberGen.s.dfy" include "../../Math/power.s.dfy" static function method Configure_MillerRabinStrength() : int { 8 } //- According to HAC table 4.4, //- 512 bit key => 256 bit prime => 12 probes, //- 1024 bit key => 512 bit prime => 8 probes. //------------------------------------------------------------// //- This worksheet is valid if a MillerRabin worksheet (from //- MillerRabin.s) is correctly configured for this prime test, //- valid, and its probes legitimately constructed from the //- randoms supply. //- The MillerRabin.s file doesn't track randomness budget, //- hence the glue. datatype MillerRabinWorksheet = MillerRabinWorksheet_c( problem:MRProblem, probe_candidates:seq, probe_seed_reqs:seq, //- probe_seed_req merely defers the work of demonstrating existence //- of a feasible h_bits value to the implementation. probes:seq, is_probably_prime:bool, randoms:seq); static function MillerRabinWorksheetConsumesRandoms(rows:seq) : seq { if (rows==[]) then [] else MillerRabinWorksheetConsumesRandoms(rows[..|rows|-1]) + rows[|rows|-1].randoms } //-static predicate MillerRabinWorksheetConsumesRandoms(rows:seq, randoms:seq) //-{ //- if (|rows|==0) then //- |randoms|==0 //- else //- is_suffix(rows[|rows|-1].randoms, randoms) //- && MillerRabinWorksheetConsumesRandoms(rows[..|rows|-1], randoms[..|randoms|-|rows]) //- |rows[0].randoms|..]) //-} static predicate IsMillerRabinProbeSeed(n:int, req:SelectRandomRequest) { req.l == 2 && req.h == n-2 && SelectRandomRequestValid(req) } static predicate MillerRabinProbeConsistency( n:int, probe_candidate:CandidateSeedWorksheet, probe_seed_req:SelectRandomRequest, probe:MRProbe) { IsMillerRabinProbeSeed(n, probe_seed_req) && CandidateSeedWorksheetValid(probe_seed_req, probe_candidate) && probe.a == CandidateSeedWorksheetOutput(probe_candidate) } static predicate MillerRabinWorksheetValid(n:int, worksheet:MillerRabinWorksheet) { |worksheet.probes|==|worksheet.probe_candidates| && |worksheet.probes|==|worksheet.probe_seed_reqs| && (forall i :: 0<=i<|worksheet.probes| ==> MillerRabinProbeConsistency(n, worksheet.probe_candidates[i], worksheet.probe_seed_reqs[i], worksheet.probes[i])) && worksheet.problem.n == n && worksheet.problem.strength == Configure_MillerRabinStrength() && MillerRabinSpecValid(worksheet.problem, worksheet.probes, worksheet.is_probably_prime) && MillerRabinWorksheetConsumesRandoms(worksheet.probe_candidates) == worksheet.randoms } //------------------------------------------------------------// datatype MRProblem = MRProblem_c( n:nat, strength:nat, s:nat, d:nat) static predicate MRProblemEarlyReject(problem:MRProblem) { problem.n <= 3 || problem.n%2 == 0 } static predicate MRProblemNeedsProbes(problem:MRProblem) { !MRProblemEarlyReject(problem) //- Input: k, a parameter that determines the accuracy of the test && problem.strength == Configure_MillerRabinStrength() //- write n - 1 as 2^sd with d odd by factoring powers of 2 from n - 1 && problem.n-1 == power(2,problem.s)*problem.d && problem.d%2==1 } static predicate MRProblemValid(problem:MRProblem) { MRProblemEarlyReject(problem) || MRProblemNeedsProbes(problem) } //- The algorithm describes a "WitnessLoop" as one of the following. //- Our "MRProbe" is evidence of having done one of these. //- It captures a, plus the fact that we have either: //- one x value x==1 or x==n-1 ("then do next WitnessLoop") //- or //- <=s values, each the square-mod-n of the previous, //- with no intermediate values equal to 1, and //- with the last one equal to n-1. //- //- pick a random integer a in the range [2, n - 2] //- x := a^d mod n //- if x = 1 or x = n - 1 then do next WitnessLoop //- repeat s - 1 times: //- x := x^2 mod n //- if x = 1 then return composite //- if x = n - 1 then do next WitnessLoop //- return composite datatype MRProbe = MRProbe_c( a:nat, squares:seq) static predicate MRProbeInit(problem:MRProblem, probe:MRProbe) requires MRProblemNeedsProbes(problem); requires 0 < |probe.squares|; { probe.squares[0] == power(probe.a,problem.d) % problem.n } static predicate MRProbeChain(problem:MRProblem, probe:MRProbe, i:nat) requires MRProblemNeedsProbes(problem); requires 0 < i < |probe.squares|; { probe.squares[i]==power(probe.squares[i-1], 2) % problem.n } //- If problem.s == 0, then static predicate MRProbeValid(problem:MRProblem, probe:MRProbe) { MRProblemNeedsProbes(problem) && 0<|probe.squares| && MRProbeInit(problem,probe) && (forall i:int :: (0 MRProbeChain(problem, probe, i))) && (forall i:int :: (0 probe.squares[i]!=1)) } static function MRProbeLimit(problem:MRProblem) : int { if (problem.s==0) then 1 else problem.s } static predicate MRProbeSucceeds(problem:MRProblem, probe:MRProbe) requires MRProblemNeedsProbes(problem); { MRProbeValid(problem, probe) //- probe length: no more than s trials. && 0 < |probe.squares| <= MRProbeLimit(problem) //- probe structure: two early successes, or stop if we see an n-1 && ( probe.squares==[1] || probe.squares==[problem.n-1] || probe.squares[|probe.squares|-1]==problem.n-1 ) } static predicate MRProbeFails(problem:MRProblem, probe:MRProbe) requires MRProblemNeedsProbes(problem); { MRProbeValid(problem, probe) //- probe length: terminates after s trials, or if we found a 1. && (|probe.squares| == MRProbeLimit(problem) || (0 < |probe.squares| && probe.squares[|probe.squares|-1] == 1)) //- probe structure: not one of the success cases && ( probe.squares!=[1] && probe.squares!=[problem.n-1] && probe.squares[|probe.squares|-1]!=problem.n-1 ) } static predicate MillerRabinSpecFails(problem:MRProblem, probes:seq) //- last probe fails //- didn't probe more than problem strength requires { MRProblemEarlyReject(problem) || ( MRProblemNeedsProbes(problem) && ( 1 <= |probes| <= problem.strength && (forall i :: (0 <= i < |probes|-1 ==> MRProbeSucceeds(problem, probes[i]))) && MRProbeFails(problem, probes[|probes|-1]) ) ) } static predicate MillerRabinSpecSucceeds(problem:MRProblem, probes:seq) //- all probes succeed //- probed exactly as many times as problem strength requires { MRProblemNeedsProbes(problem) && problem.n%2==1 && problem.n>3 && |probes| == problem.strength && (forall i :: 0 <= i < |probes| ==> MRProbeSucceeds(problem, probes[i])) } static predicate MillerRabinSpecValid(problem:MRProblem, probes:seq, result:bool) { (MillerRabinSpecSucceeds(problem, probes) && result) || (MillerRabinSpecFails(problem, probes) && !result) } static predicate IsProbablyPrime(n:nat,strength:nat) static lemma {:axiom} MillerRabinSpec(problem:MRProblem, probes:seq) requires MRProblemValid(problem); requires MillerRabinSpecValid(problem, probes, true); ensures IsProbablyPrime(problem.n, problem.strength); ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Crypto/RSA/MultiplicativeInverse.i.dfy ================================================ include "RSASpec.s.dfy" include "../Hash/Digest.i.dfy" include "../../BigNum/BigNum.i.dfy" include "../../BigNum/BigNatDiv.i.dfy" include "../../BigNum/BigNatMod.i.dfy" include "Extended_GCD.i.dfy" include "KeyGen.i.dfy" include "BlockEncoding.i.dfy" include "KeyImpl.i.dfy" include "../../FatNat/BigNatToFatNatAdaptor.i.dfy" include "../../FatNat/FatNatMod.i.dfy" static function K(x:seq) : int requires IsWordSeq(x); { BEWordSeqToInt(x) } lemma lemma_MultiplicativeInverse(phi:seq, e:seq, d:seq, k_num:int, d_num:int, gcd:int) requires IsWordSeq(phi); requires IsWordSeq(e); requires IsWordSeq(d); requires gcd == K(phi)*k_num + K(e)*d_num; requires 1 == gcd; requires 0 <= K(e); requires 0 <= 1 < K(phi); requires d_num <= K(phi); requires is_gcd(K(phi), K(e), gcd); requires K(d) == if d_num < 0 then d_num + K(phi) else d_num; ensures K(d) <= K(phi); ensures mul(K(d), K(e)) % K(phi) == 1; ensures is_gcd(K(phi),K(e),1); { calc { 1; gcd; K(phi)*k_num + K(e)*d_num + 0*K(phi); { lemma_mul_is_mul_boogie(0, K(phi)); } K(phi) * k_num + K(e) * d_num + mul(0, K(phi)); } lemma_mul_basics_forall(); assert K(phi) * k_num + K(e) * d_num == mul(0, K(phi)) + 1; lemma_fundamental_div_mod_converse( K(phi) * k_num + K(e) * d_num, K(phi), 0, 1); assert (K(phi) * k_num + K(e) * d_num) % K(phi) == 1; calc ==> { true; (K(phi) * k_num + K(e) * d_num) % K(phi) == 1; { lemma_mod_multiples_vanish(k_num, K(e) * d_num, K(phi)); } (K(e) * d_num) % K(phi) == 1; { lemma_mul_is_commutative_forall(); } (d_num * K(e)) % K(phi) == 1; } if (0 <= d_num) { calc { K(d); d_num; <= K(phi); } } else { calc { 1; (d_num*K(e)) % K(phi); { lemma_mod_multiples_vanish(K(e), d_num*K(e), K(phi)); } (K(phi)*K(e) + d_num*K(e)) % K(phi); { lemma_mul_is_commutative_forall(); } (d_num*K(e) + K(e) * K(phi)) % K(phi); { lemma_mul_is_commutative_forall(); } (d_num*K(e) + K(phi) * K(e)) % K(phi); { lemma_mul_is_distributive_forall(); } ((d_num + K(phi)) * K(e)) % K(phi); //- (FIV(d_prime)*K(e)) % K(phi); (K(d)*K(e)) % K(phi); } //- assert WellformedFatInt(d_prime); calc { K(d); //- FIV(d_prime); d_num+K(phi); <= K(phi); } } } method {:timeLimitMultiplier 3} MultiplicativeInverse(phi:array, e:array) returns (success:bool, d:array) requires WellformedFatNat(phi); requires 1 WellformedFatNat(d); ensures success ==> J(d) <= J(phi); ensures success ==> mul(J(d), J(e)) % J(phi) == 1; ensures success <==> is_gcd(J(phi),J(e),1); { //- lemma_frumpy_is_modest(phi); //- lemma_frumpy_is_modest(e); ghost var phi_seq := phi[..]; ghost var phi_v := K(phi_seq); ghost var e_seq := e[..]; ghost var e_v := K(e_seq); assert IsWordSeq(e_seq); var k_num:FatInt,d_num:FatInt := Extended_gcd(phi,e); var k_ref := k_num.value; //- do something real to k_num.value so dafnycc realizes it's allocated var d_ref := d_num.value; //- do something real to d_num.value so dafnycc realizes it's allocated ghost var k_num_v := FIV(k_num); ghost var d_num_v := FIV(d_num); //- ghost var k_num_s := k_num.value[..]; assert WellformedFatInt(k_num); assert WellformedFatInt(d_num); var phik:FatInt := FatIntMul(FatInt_ctor(false, phi),k_num); var phik_ref := phik.value; //- do something real to phik.value so dafnycc realizes it's allocated ghost var phik_v := FIV(phik); assert phi_seq==phi[..]; //- OBSERVE array var ed:FatInt := FatIntMul(FatInt_ctor(false, e),d_num); var ed_ref := ed.value; //- do something real to ed.value so dafnycc realizes it's allocated assert phi_seq==phi[..]; //- OBSERVE array ghost var ed_v := FIV(ed); var gcd:FatInt := FatIntAdd(phik,ed); var gcd_ref := gcd.value; //- do something real to gcd.value so dafnycc realizes it's allocated assert phi_seq==phi[..]; //- OBSERVE array ghost var gcd_v := FIV(gcd); calc { gcd_v; phik_v+ed_v; phi_v*k_num_v + e_v*d_num_v; } assert WellformedFatInt(k_num); lemma_2toX(); var one := MakeSmallLiteralFatInt(1); var one_ref := one.value; //- do something real to one.value so dafnycc realizes it's allocated var sane_gcd:bool := FatIntEq(gcd, one); assert WellformedFatInt(k_num); if (sane_gcd) { success := true; } else { success := false; } if (success) { if (!d_num.negate) { d := d_num.value; assert WellformedFatNat(d); //- assert phi_seq==phi[..]; //- OBSERVE array } else { var d_prime:FatInt := FatIntAdd(d_num, FatInt_ctor(false, phi)); var dprime_ref := d_prime.value; //- do something real to d_prime.value so dafnycc realizes it's allocated //- assert phi_seq==phi[..]; //- OBSERVE array assert 0<=FIV(d_prime); d := d_prime.value; assert FIV(d_prime) == J(d); assert WellformedFatNat(d); } assert FIV(gcd)==gcd_v==phi_v*k_num_v + e_v*d_num_v; assert phi_seq==phi[..]; //- OBSERVE array assert phi_v==K(phi_seq); assert e_v==K(e[..]); assert k_num_v==FIV(k_num); assert d_num_v==FIV(d_num); assert e_seq==e[..]; lemma_MultiplicativeInverse(phi[..], e[..], d[..], FIV(k_num), FIV(d_num), FIV(gcd)); calc { mul(J(d), J(e)) % J(phi); mul(K(d[..]), K(e[..])) % K(phi[..]); 1; } calc ==> { true; is_gcd(K(phi[..]),K(e[..]),1); is_gcd(J(phi),J(e),1); } } else { //- dafnycc: initialize variables d := e; assert WellformedFatNat(d); } } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Crypto/RSA/OAEP.i.dfy ================================================ include "OAEP.s.dfy" include "../../Math/power.i.dfy" include "../../Math/power2.i.dfy" include "../../Math/round.i.dfy" include "../../Math/bit_vector_lemmas_premium.i.dfy" include "../../Util/integer_sequences_premium.i.dfy" static function SHA256_BytesToBytes_premium(M:seq) : seq requires IsByteSeq(M); requires |M| < power2(61) || |BEByteSeqToBitSeq(M)| < power2(64); ensures IsBitSeq(BEByteSeqToBitSeq(M)); ensures |BEByteSeqToBitSeq(M)| < power2(64); ensures SHA256_BytesToBytes_premium(M) == SHA256_BytesToBytes(M); ensures IsByteSeqOfLen(SHA256_BytesToBytes(M), hLen()); { calc { |M| < power2(61); ==> 8*|M| < 8*power2(61); ==> { lemma_2toX(); lemma_power2_add8(56); } 8*|M| < power2(64); ==> |BEByteSeqToBitSeq_premium(M)| < power2(64); } BEWordSeqToByteSeq_premium(SHA256(BEByteSeqToBitSeq_premium(M))) } static function ByteSeqXor_premium(X:seq, Y:seq) : seq requires IsByteSeq(X); requires IsByteSeq(Y); requires |X| == |Y|; ensures |ByteSeqXor_premium(X, Y)| == |X|; ensures IsByteSeq(ByteSeqXor_premium(X, Y)); ensures ByteSeqXor_premium(X, Y) == ByteSeqXor(X, Y); { if X == [] || Y == [] then [] else lemma_power2_strictly_increases(8, 32); lemma_2toX(); lemma_xor_bytes_premium(X[0], Y[0]); [BitwiseXor(X[0], Y[0])] + ByteSeqXor_premium(X[1..], Y[1..]) } static function I2OSP_premium(x:int, xLen:int) : seq requires 0 <= xLen; requires 0 <= x < power(power2(8), xLen); ensures IsByteSeq(I2OSP_premium(x, xLen)); ensures I2OSP_premium(x, xLen) == I2OSP(x, xLen); ensures |I2OSP_premium(x, xLen)| == xLen; { lemma_2toX(); BEIntToDigitSeq_premium(power2(8), xLen, x) } static function OS2IP_premium(X:seq) : int requires IsByteSeq(X); ensures OS2IP_premium(X) == OS2IP(X); ensures 0 <= OS2IP_premium(X) < power(power2(8), |X|); { lemma_2toX(); BEDigitSeqToInt_premium(power2(8), X) } static predicate MGF1_step_requirements_simplified(seed:seq, counter:nat) ensures MGF1_step_requirements_simplified(seed, counter) ==> MGF1_step_requirements(seed, counter); { if Word32(counter) && IsByteSeq(seed) && |seed| < power2(60) then Lemma_MGF1_step_requirements_simplified_imply_MGF1_step_requirements(seed, counter); true else false } static lemma Lemma_MGF1_step_requirements_simplified_imply_MGF1_step_requirements(seed:seq, counter:nat) requires IsByteSeq(seed); requires |seed| < power2(60); requires Word32(counter); ensures MGF1_step_requirements(seed, counter); { calc { counter; < { lemma_power2_unfolding(8, 4); lemma_mul_is_mul_boogie(8, 4); } power(power2(8), 4); } assert IsByteSeq(I2OSP_premium(counter, 4)); assert IsBitSeq(BEByteSeqToBitSeq_premium(seed + I2OSP_premium(counter, 4))); calc { |BEByteSeqToBitSeq_premium(seed + I2OSP_premium(counter, 4))|; |seed + I2OSP_premium(counter, 4)| * 8; == |seed| * 8 + |I2OSP_premium(counter, 4)| * 8; <= |seed| * 8 + 4 * 8; <= |seed| * 8 + 32; < power2(60) * 8 + 32; < { lemma_2toX(); } power2(64); } assert |BEByteSeqToBitSeq(seed + I2OSP_premium(counter, 4))| < power2(64); } static function MGF1_step_premium(seed:seq, counter:nat) : seq requires IsByteSeq(seed); requires |seed| < power2(60); requires Word32(counter); ensures MGF1_step_requirements(seed, counter); ensures MGF1_step_premium(seed, counter) == MGF1_step(seed, counter); ensures IsByteSeqOfLen(MGF1_step_premium(seed, counter), hLen()); { assert MGF1_step_requirements_simplified(seed, counter); var C := I2OSP_premium(counter, 4); SHA256_BytesToBytes_premium(seed + C) } static function MGF1_prefix_premium(seed:seq, counter:nat) : seq requires IsByteSeq(seed); requires |seed| < power2(60); requires Word32(counter); ensures forall j :: 0 <= j < counter ==> MGF1_step_requirements(seed, j); ensures MGF1_prefix_premium(seed, counter) == MGF1_prefix(seed, counter); ensures IsByteSeq(MGF1_prefix_premium(seed, counter)); ensures |MGF1_prefix_premium(seed, counter)| == hLen() * counter; decreases counter; { assert forall j :: 0 <= j < counter ==> MGF1_step_requirements_simplified(seed, j); if counter == 0 then calc { |[]|; 32 * 0; { lemma_mul_is_mul_boogie(32, 0); } hLen() * counter; } [] else calc { |MGF1_prefix_premium(seed, counter-1) + MGF1_step_premium(seed, counter-1)|; |MGF1_prefix_premium(seed, counter-1)| + |MGF1_step_premium(seed, counter-1)|; hLen() * (counter-1) + hLen(); hLen() * (counter-1) + hLen() * 1; { lemma_mul_is_distributive_add(hLen(), counter-1, 1); lemma_mul_is_mul_boogie(hLen(), 1); } hLen() * (counter-1+1); hLen() * counter; } MGF1_prefix_premium(seed, counter-1) + MGF1_step_premium(seed, counter-1) } static function MGF1_premium(seed:seq, maskLen:int) : seq requires IsByteSeq(seed); requires |seed| < power2(60); requires Word32(maskLen); ensures 0 <= maskLen <= power2(32) * hLen(); ensures var counter := DivideRoundingUp(maskLen, hLen()); counter >= 0 && (forall j :: 0 <= j < counter ==> MGF1_step_requirements(seed, j)) && |MGF1_prefix(seed, counter)| >= maskLen; ensures MGF1_premium(seed, maskLen) == MGF1(seed, maskLen); ensures IsByteSeqOfLen(MGF1_premium(seed, maskLen), maskLen); { calc { maskLen; < power2(32); == { lemma_2toX(); } 0x100000000; < 0x100000000 * 32; == { lemma_2toX(); } power2(32) * 32; == { lemma_mul_is_mul_boogie(power2(32), hLen()); } power2(32) * hLen(); } var counter := DivideRoundingUp_premium(maskLen, hLen()); lemma_mul_is_commutative(hLen(), counter); MGF1_prefix_premium(seed, counter)[..maskLen] } static function RSAEP_premium(pubkey:RSAPubKeySpec, m:int) : int requires WellformedRSAPubKeySpec(pubkey); requires 0 <= m < pubkey.n; ensures 0 <= RSAEP_premium(pubkey, m) < pubkey.n; { lemma_mod_properties(); power(m, pubkey.e) % pubkey.n } static function RSAES_OAEP_ENCRYPT_premium(pubkey:RSAPubKeySpec, M:seq, L:seq, seed:seq) : seq requires WellformedRSAPubKeySpec(pubkey); requires IsByteSeq(M); requires IsByteSeq(L); requires IsByteSeq(seed); requires |M| <= pubkey.size - 2 * hLen() - 2; requires |seed| == hLen(); requires Word32(pubkey.size); requires Word32(pubkey.size); requires |L| < power2(61); ensures IsBitSeq(BEByteSeqToBitSeq(L)) && |BEByteSeqToBitSeq(L)| < power2(64) && var lHash := SHA256_BytesToBytes(L); var k := pubkey.size; var PS := RepeatDigit(0, k - |M| - 2*hLen() - 2); var DB := lHash + PS + [0x01] + M; IsByteSeq(DB) && var maskLen := pubkey.size - hLen() - 1; var counter := DivideRoundingUp(maskLen, hLen()); 0 <= maskLen <= power2(32) * hLen() && counter >= 0 && (forall j :: 0 <= j < counter ==> MGF1_step_requirements(seed, j)) && |MGF1_prefix(seed, counter)| >= maskLen && var dbMask := MGF1(seed, k - hLen() - 1); IsByteSeq(DB) && IsByteSeq(dbMask) && var maskedDB := ByteSeqXor(DB, dbMask); var maskLen2 := hLen(); var counter2 := DivideRoundingUp(maskLen2, hLen()); 0 <= maskLen2 <= power2(32) * hLen() && counter2 >= 0 && (forall j :: 0 <= j < counter2 ==> MGF1_step_requirements(maskedDB, j)) && |MGF1_prefix(maskedDB, counter2)| >= maskLen2 && var seedMask := MGF1(maskedDB, hLen()); IsByteSeq(seedMask) && var maskedSeed := ByteSeqXor(seed, seedMask); var EM := [0x00] + maskedSeed + maskedDB; IsByteSeq(EM) && var m := OS2IP(EM); 0 <= m < pubkey.n && var c := RSAEP(pubkey, m); 0 <= c < power(power2(8), pubkey.size); ensures RSAES_OAEP_ENCRYPT_premium(pubkey, M, L, seed) == RSAES_OAEP_ENCRYPT(pubkey, M, L, seed); { calc { |BEByteSeqToBitSeq_premium(L)|; 8*|L|; < 8*power2(61); { lemma_2toX(); lemma_power2_add8(56); } power2(64); } var lHash := SHA256_BytesToBytes_premium(L); var k := pubkey.size; var PS := RepeatDigit_premium(0, k - |M| - 2*hLen() - 2); var DB := lHash + PS + [0x01] + M; calc { 0x01; < { lemma_2toX(); } power2(8); } assert IsByteSeq(DB); var maskLen := pubkey.size - hLen() - 1; var counter := DivideRoundingUp_premium(maskLen, hLen()); calc { maskLen; < power2(32) - hLen() - 1; == power2(32) - 33; == { lemma_2toX(); } 0x100000000 - 33; < 0x100000000 * 32; == { lemma_2toX(); } power2(32) * 32; == { lemma_mul_is_mul_boogie(power2(32), hLen()); } power2(32) * hLen(); } calc { |seed|; hLen(); < { lemma_2toX(); } power2(60); } var dbMask := MGF1_premium(seed, k - hLen() - 1); assert IsByteSeq(DB); assert IsByteSeq(dbMask); var maskedDB := ByteSeqXor_premium(DB, dbMask); calc { |maskedDB|; k - hLen() - 1; < power2(32); < { lemma_power2_strictly_increases(32, 60); } power2(60); } var seedMask := MGF1_premium(maskedDB, hLen()); assert IsByteSeq(seedMask); var maskedSeed := ByteSeqXor_premium(seed, seedMask); var EM := [0x00] + maskedSeed + maskedDB; assert IsByteSeq(EM); var m := OS2IP_premium(EM); calc { m; == { lemma_LeadingZeros(power2(8), EM[1..], EM); } OS2IP_premium(EM[1..]); < power(power2(8), |EM|-1); == power(power2(8), k-1); == { lemma_power2_unfolding(8, k-1); lemma_mul_is_mul_boogie(8, k-1); } power2(8*(k-1)); <= pubkey.n; } var c := RSAEP_premium(pubkey, m); calc { c; < pubkey.n; <= power2(8*k); == { lemma_power2_unfolding(8, k); lemma_mul_is_mul_boogie(8, k); } power(power2(8), k); } RSAES_OAEP_ENCRYPT(pubkey, M, L, seed) } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Crypto/RSA/OAEP.s.dfy ================================================ include "../../Math/power.s.dfy" include "../../Math/round.s.dfy" include "../../Util/be_sequences.s.dfy" include "../../../Drivers/TPM/tpm-device.s.dfy" include "RSASpec.s.dfy" //- //- The spec in this file is based on RFC 3447, which can be found at //- http://www.ietf.org/rfc/rfc3447.txt //- //-//////////////////////////////////////////////////////////////////////// //- High-level functions for external use //-//////////////////////////////////////////////////////////////////////// datatype OAEPDecryptionResult = OAEPDecryptionResult_Success(M:seq) | OAEPDecryptionResult_Undecryptable(); static predicate {:autoReq} OAEPEncryptionRelation(pubkey:RSAPubKeySpec, M:seq, EM:seq, old_TPM:TPM_struct, new_TPM:TPM_struct) { new_TPM.random_index - old_TPM.random_index == hLen() && EM == RSAES_OAEP_ENCRYPT(pubkey, M, [] /* use empty string as label */, TPM_random_bytes(old_TPM.random_index, new_TPM.random_index)) } static predicate {:autoReq} OAEPDecryptionRelation(key:RSAKeyPairSpec, C:seq, decryption_result:OAEPDecryptionResult) { RSAES_OAEP_DECRYPT(key, C, [] /* use empty string as label */) == decryption_result } //-//////////////////////////////////////////////////////////////////////// //- Helper functions //-//////////////////////////////////////////////////////////////////////// static function {:autoReq} SHA256_BytesToBytes(M:seq) : seq requires IsByteSeq(M); { BEWordSeqToByteSeq(SHA256(BEByteSeqToBitSeq(M))) } static function ByteSeqXor(X:seq, Y:seq) : seq requires IsByteSeq(X); requires IsByteSeq(Y); { if X == [] || Y == [] then [] else if Word32(X[0]) && Word32(Y[0]) then [BitwiseXor(X[0], Y[0])] + ByteSeqXor(X[1..], Y[1..]) else [0] + ByteSeqXor(X[1..], Y[1..]) } static function FindFirstNonzeroByte(s:seq, minpos:nat) : int ensures FindFirstNonzeroByte(s, minpos) >= minpos; decreases |s| - minpos; { if minpos >= |s| || s[minpos] != 0 then minpos else FindFirstNonzeroByte(s, minpos + 1) } //-//////////////////////////////////////////////////////////////////////// //- Definitions from RFC 3447 section 2 //-//////////////////////////////////////////////////////////////////////// static function hLen() : int { 32 } static function sLen() : int { hLen() } //-//////////////////////////////////////////////////////////////////////// //- I2OSP, OS2IP as defined in RFC 3447 section 4.1 //-//////////////////////////////////////////////////////////////////////// static function I2OSP(x:int, xLen:int) : seq requires 0 <= xLen; requires 0 <= x < power(power2(8), xLen); { BEIntToDigitSeq(power2(8), xLen, x) } static function OS2IP(X:seq) : int requires IsByteSeq(X); { BEByteSeqToInt(X) } //-//////////////////////////////////////////////////////////////////////// //- RSAEP, RSADP as defined in RFC 3447 section 5.1 //-//////////////////////////////////////////////////////////////////////// static function RSAEP(pubkey:RSAPubKeySpec, m:int) : int requires WellformedRSAPubKeySpec(pubkey); requires 0 <= m < pubkey.n; { power(m, pubkey.e) % pubkey.n } static function RSADP(keypair:RSAKeyPairSpec, c:int) : int requires WellformedRSAKeyPairSpec(keypair); requires 0 <= c < keypair.pub.n; { power(c, keypair.d) % keypair.pub.n } //-//////////////////////////////////////////////////////////////////////// //- RSASP1 as defined in RFC 3447 section 5.2 //-//////////////////////////////////////////////////////////////////////// static function RSASP1(key:RSAKeyPairSpec, m:int) : int requires WellformedRSAKeyPairSpec(key); requires 0 <= m < key.pub.n; { power(m, key.d) % key.pub.n } //-//////////////////////////////////////////////////////////////////////// //- MGF1 as defined in RFC 3447 section B.2.1 //-//////////////////////////////////////////////////////////////////////// static predicate MGF1_step_requirements(seed:seq, counter:nat) { 0 <= counter < power(power2(8), 4) && IsByteSeq(seed) && IsByteSeq(I2OSP(counter, 4)) && IsBitSeq(BEByteSeqToBitSeq(seed + I2OSP(counter, 4))) && |BEByteSeqToBitSeq(seed + I2OSP(counter, 4))| < power2(64) } static function MGF1_step(seed:seq, counter:nat) : seq requires MGF1_step_requirements(seed, counter); { var C := I2OSP(counter, 4); SHA256_BytesToBytes(seed + C) } static function MGF1_prefix(seed:seq, counter:nat) : seq requires forall j :: 0 <= j < counter ==> MGF1_step_requirements(seed, j); decreases counter; { if counter == 0 then [] else MGF1_prefix(seed, counter-1) + MGF1_step(seed, counter-1) } static function MGF1(seed:seq, maskLen:int) : seq requires 0 <= maskLen <= power2(32) * hLen(); requires var counter := DivideRoundingUp(maskLen, hLen()); counter >= 0 && (forall j :: 0 <= j < counter ==> MGF1_step_requirements(seed, j)) && |MGF1_prefix(seed, counter)| >= maskLen; { MGF1_prefix(seed, DivideRoundingUp(maskLen, hLen()))[..maskLen] } //-//////////////////////////////////////////////////////////////////////// //- RSAES_OAEP_ENCRYPT as defined in RFC 3447 section 7.1.1 //-//////////////////////////////////////////////////////////////////////// static function {:autoReq} RSAES_OAEP_ENCRYPT(pubkey:RSAPubKeySpec, M:seq, L:seq, seed:seq) : seq requires WellformedRSAPubKeySpec(pubkey); requires IsByteSeq(M); requires IsByteSeq(L); requires IsByteSeq(seed); requires |M| <= pubkey.size - 2 * hLen() - 2; requires |seed| == hLen(); { var lHash := SHA256_BytesToBytes(L); var k := pubkey.size; var PS := RepeatDigit(0, k - |M| - 2*hLen() - 2); var DB := lHash + PS + [0x01] + M; var dbMask := MGF1(seed, k - hLen() - 1); var maskedDB := ByteSeqXor(DB, dbMask); var seedMask := MGF1(maskedDB, hLen()); var maskedSeed := ByteSeqXor(seed, seedMask); var EM := [0x00] + maskedSeed + maskedDB; var m := OS2IP(EM); var c := RSAEP(pubkey, m); var C := I2OSP(c, k); C } //-//////////////////////////////////////////////////////////////////////// //- RSAES-OAEP-DECRYPT as defined in RFC 3447 section 7.1.2 //-//////////////////////////////////////////////////////////////////////// static function {:autoReq} RSAES_OAEP_DECRYPT(key:RSAKeyPairSpec, C:seq, L:seq) : OAEPDecryptionResult requires WellformedRSAKeyPairSpec(key); requires IsByteSeq(C); requires IsByteSeq(L); { var k := key.pub.size; if |C| != k || k < 2*hLen() + 2 then OAEPDecryptionResult_Undecryptable() else var c := OS2IP(C); var m := RSADP(key, c); var EM := I2OSP(m, k); var lHash := SHA256_BytesToBytes(L); if |EM| != k then OAEPDecryptionResult_Undecryptable() else var Y := EM[0]; var maskedSeed := EM[1..hLen()+1]; var maskedDB := EM[hLen()+1..k]; var seedMask := MGF1(maskedDB, hLen()); var seed := ByteSeqXor(maskedSeed, seedMask); var dbMask := MGF1(seed, k - hLen() - 1); var DB := ByteSeqXor(maskedDB, dbMask); if |DB| < hLen() then OAEPDecryptionResult_Undecryptable() else var lHash' := DB[..hLen()]; var firstNonZero := FindFirstNonzeroByte(DB, hLen()); if lHash' != lHash || firstNonZero >= |DB| || DB[firstNonZero] != 0x01 || Y != 0 then OAEPDecryptionResult_Undecryptable() else OAEPDecryptionResult_Success(DB[firstNonZero+1..]) } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Crypto/RSA/PSS.s.dfy ================================================ include "OAEP.s.dfy" //-//////////////////////////////////////////////////////////////////////// //- High-level functions for external use //-//////////////////////////////////////////////////////////////////////// static predicate {:autoReq} PSSSignatureRelation(key:RSAKeyPairSpec, M:seq, S:seq, old_TPM:TPM_struct, new_TPM:TPM_struct) { new_TPM.random_index - old_TPM.random_index == sLen() && S == RSASSA_PSS_SIGN(key, M, TPM_random_bytes(old_TPM.random_index, new_TPM.random_index)) } static predicate {:autoReq} PSSVerificationRelation(pubkey:RSAPubKeySpec, M:seq, S:seq, verification_result:bool) { RSASSA_PSS_VERIFY(pubkey, M, S) == verification_result } //-//////////////////////////////////////////////////////////////////////// //- Helper functions //-//////////////////////////////////////////////////////////////////////// static function CountBits(x:nat) : int { if x == 0 then 0 else 1 + CountBits(x/2) } static function ClearMSBs(s:seq, numZeroBits:int) : seq requires 0 <= numZeroBits <= 8; { if s == [] then s else s[0 := s[0] % power2(8 - numZeroBits)] } //-//////////////////////////////////////////////////////////////////////// //- RSAVP1 as defined in RFC 3447 section 5.2 //-//////////////////////////////////////////////////////////////////////// static function RSAVP1(pubkey:RSAPubKeySpec, s:int) : int requires WellformedRSAPubKeySpec(pubkey); requires 0 <= s < pubkey.n; { power(s, pubkey.e) % pubkey.n } //-//////////////////////////////////////////////////////////////////////// //- RSASSA-PSS-SIGN as defined in RFC 3447 section 8.1.1 //-//////////////////////////////////////////////////////////////////////// static function {:autoReq} RSASSA_PSS_SIGN(key:RSAKeyPairSpec, M:seq, salt:seq) : seq requires WellformedRSAKeyPairSpec(key); requires IsByteSeq(M); requires IsByteSeqOfLen(salt, sLen()); { var modBits := CountBits(key.pub.n); var EM := EMSA_PSS_ENCODE(M, modBits - 1, salt); var m := OS2IP(EM); var s := RSASP1(key, m); var S := I2OSP(s, key.pub.size); S } //-//////////////////////////////////////////////////////////////////////// //- RSASSA-RSS-VERIFY as defined in RFC 3447 section 8.1.2 //-//////////////////////////////////////////////////////////////////////// static predicate {:autoReq} RSASSA_PSS_VERIFY(pubkey:RSAPubKeySpec, M:seq, S:seq) requires WellformedRSAPubKeySpec(pubkey); requires IsByteSeq(M); requires IsByteSeq(S); { |S|==pubkey.size && var s := OS2IP(S); 0 <= s < pubkey.n && var m := RSAVP1(pubkey, s); var modBits := CountBits(pubkey.n); var emLen := DivideRoundingUp(modBits - 1, 8); emLen >= 0 && 0 <= m < power(power2(8), emLen) && var EM := I2OSP(m, emLen); EMSA_PSS_VERIFY(M, EM, modBits - 1) } //-//////////////////////////////////////////////////////////////////////// //- EMSA-PSS-ENCODE as defined in RFC 3447 section 9.1.1 //-//////////////////////////////////////////////////////////////////////// static function {:autoReq} EMSA_PSS_ENCODE(M:seq, emBits:int, salt:seq) : seq requires IsByteSeq(M); requires |M| * 8 >= emBits; requires IsByteSeqOfLen(salt, sLen()); requires DivideRoundingUp(emBits, 8) >= hLen() + sLen() + 2; requires 8 * DivideRoundingUp(emBits, 8) - emBits <= 8; { var mHash := SHA256_BytesToBytes(M); var emLen := DivideRoundingUp(emBits, 8); var M' := RepeatDigit(0, 8) + mHash + salt; var H := SHA256_BytesToBytes(M'); var PS := RepeatDigit(0, emLen - sLen() - hLen() - 2); var DB := PS + [0x01] + salt; var dbMask := MGF1(H, emLen - hLen() - 1); var maskedDB := ByteSeqXor(DB, dbMask); var nZeroBits := 8 * emLen - emBits; var maskedDB_reduced := ClearMSBs(maskedDB, nZeroBits); var EM := maskedDB_reduced + H + [0xbc]; EM } //-//////////////////////////////////////////////////////////////////////// //- EMSA-PSS-VERIFY as defined in RFC 3447 section 9.1.2 //-//////////////////////////////////////////////////////////////////////// static predicate {:autoReq} EMSA_PSS_VERIFY(M:seq, EM:seq, emBits:int) requires IsByteSeq(EM); requires IsByteSeq(M); { |M| < power2(61) && var mHash := SHA256_BytesToBytes(M); var emLen := DivideRoundingUp(emBits, 8); emLen >= hLen() + sLen() + 2 && |EM| >= emLen - 1 && EM[|EM|-1] == 0xbc && var maskedDB:seq := EM[.. emLen - hLen() - 1]; var H := EM[emLen - hLen() - 1 .. emLen - 1]; var nZeroBits := 8*emLen - emBits; |maskedDB| > 0 && 8 - nZeroBits >= 0 && maskedDB[0] < power2(8-nZeroBits) && var dbMask := MGF1(H, emLen - hLen() - 1); var DB := ByteSeqXor(maskedDB, dbMask); var DB_reduced := ClearMSBs(DB, nZeroBits); |DB_reduced| > emLen - hLen() - sLen() - 2 && DB_reduced[.. emLen - hLen() - sLen() - 2] == RepeatDigit(0, emLen - hLen() - sLen() - 2) && DB_reduced[emLen - hLen() - sLen() - 2] == 0x01 && |DB_reduced| >= sLen() && var salt := DB_reduced[|DB_reduced| - sLen() ..]; var M' := RepeatDigit(0, 8) + mHash + salt; var H' := SHA256_BytesToBytes(M'); H == H' } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Crypto/RSA/RSA.i.dfy ================================================ include "RSASpec.s.dfy" include "../Hash/Digest.i.dfy" include "../../BigNum/BigNum.i.dfy" include "../../BigNum/BigNatDiv.i.dfy" include "../../BigNum/BigNatMod.i.dfy" include "Extended_GCD.i.dfy" include "KeyGen.i.dfy" include "BlockEncoding.i.dfy" include "KeyImpl.i.dfy" include "../../FatNat/BigNatToFatNatAdaptor.i.dfy" include "../../FatNat/FatNatMod.i.dfy" include "../../FatNat/Transforms.i.dfy" include "../../FatNat/FatNatReciprocal.i.dfy" include "KeybitsLength.i.dfy" include "MultiplicativeInverse.i.dfy" method ComputeKeySize(N:array) returns (k:nat) requires WellformedFatNat(N); requires 00) { calc { power2(8*(k-1)); power2(8*k-8); <= { lemma_mod_remainder(); assert 0 <= mod(bit_count-1,8); assert 8*k-8 <= 8*k - 8 + mod(bit_count-1,8); lemma_power2_increases(8*k-8, 8*k - 8 + mod(bit_count-1,8)); } power2(8*k - 8 + mod(bit_count-1,8)); power2(bit_count-1); <= J(N); } } calc { J(N); < power2(bit_count); power2(bit_count-1+1); power2(8*k - 8 + mod(bit_count-1,8) + 1); power2(8*k - 7 + mod(bit_count-1,8)); <= { lemma_mod_remainder(); assert mod(bit_count-1,8) < 8; lemma_power2_increases(8*k - 7 + mod(bit_count-1,8), 8*k); } power2(8*k); } } static predicate RSAKeyGenerationWorksheetValid_premium(keybits:int, worksheet:RSAKeyGenerationWorksheet) requires forall i :: 0 <= i < |worksheet.rows| ==> 0 < |worksheet.rows[i].P.rows| && 0 < |worksheet.rows[i].Q.rows| ; //- && 0 < |worksheet.rows[i].P.rows[|worksheet.rows[i].P.rows|-1].candidate.rows| //- && 0 < |worksheet.rows[i].Q.rows[|worksheet.rows[i].Q.rows|-1].candidate.rows|; { RSAKeyGenerationWorksheetValid(keybits, worksheet) } static predicate RSAKeyConsistentWithWorksheet_precondition(worksheet:RSAKeyGenerationWorksheet) { (forall i :: 0 <= i < |worksheet.rows| ==> PrimeGenerationWorksheetValid_precondition(worksheet.rows[i].P) && PrimeGenerationWorksheetValid_precondition(worksheet.rows[i].Q)) } static predicate RSAKeyConsistentWithWorksheet_premium(requested_keybits:int, key:RSAKeyPairSpec, worksheet:RSAKeyGenerationWorksheet) requires RSAKeyConsistentWithWorksheet_precondition(worksheet); { RSAKeyConsistentWithWorksheet(requested_keybits, key, worksheet) } static predicate RSAKeyGenerationWorksheetSummaryValid_Impl(worksheet:RSAKeyGenerationWorksheet, last_accepted:bool) requires 0 < |worksheet.rows|; requires 0 < |worksheet.rows[|worksheet.rows|-1].P.rows|; requires 0 < |worksheet.rows[|worksheet.rows|-1].Q.rows|; { var final := worksheet.rows[|worksheet.rows|-1]; worksheet.rows[|worksheet.rows|-1].accepted == last_accepted && 0 < |final.P.rows| && worksheet.p == PrimeGenerationOutput(final.P) && 0 < |final.Q.rows| && worksheet.q == PrimeGenerationOutput(final.Q) && worksheet.phi == (worksheet.p-1)*(worksheet.q-1) && worksheet.phi != 0 && worksheet.n == worksheet.p*worksheet.q } static predicate RSAKeyGenerationWorksheetValid_Impl(keybits:int, worksheet:RSAKeyGenerationWorksheet, last_accepted:bool) requires RSAKeyConsistentWithWorksheet_precondition(worksheet); { (forall i :: 0 <= i < |worksheet.rows| ==> RSAKeyGenerationWorksheetRowValid(worksheet.keybits, worksheet.rows[i])) && (forall i :: 0 <= i < |worksheet.rows|-1 ==> !worksheet.rows[i].accepted) && (0<|worksheet.rows| ==> worksheet.rows[|worksheet.rows|-1].accepted == last_accepted) && (RSAKeyGenerationWorksheetConsumesRandoms(worksheet.rows) == worksheet.randoms) && (0<|worksheet.rows| ==> RSAKeyGenerationWorksheetSummaryValid_Impl(worksheet, last_accepted)) } static function RSAKeyGenerationWorksheetAppend(worksheet:RSAKeyGenerationWorksheet, worksheet_row:RSAKeyGenerationWorksheetRow, last_accepted:bool) : RSAKeyGenerationWorksheet requires 0 < |worksheet_row.P.rows|; requires 0 < |worksheet_row.Q.rows|; requires RSAKeyConsistentWithWorksheet_precondition(worksheet); requires RSAKeyGenerationWorksheetValid_Impl(worksheet.keybits, worksheet, false); { RSAKeyGenerationWorksheet_c( worksheet.keybits, worksheet.rows + [worksheet_row], worksheet.randoms + worksheet_row.randoms, PrimeGenerationOutput(worksheet_row.P), PrimeGenerationOutput(worksheet_row.Q), (PrimeGenerationOutput(worksheet_row.P)-1)*(PrimeGenerationOutput(worksheet_row.Q)-1), PrimeGenerationOutput(worksheet_row.P)*PrimeGenerationOutput(worksheet_row.Q)) } static lemma WorksheetAppend_lemma(worksheet:RSAKeyGenerationWorksheet, worksheet_row:RSAKeyGenerationWorksheetRow, last_accepted:bool, worksheet':RSAKeyGenerationWorksheet) requires RSAKeyConsistentWithWorksheet_precondition(worksheet); requires RSAKeyGenerationWorksheetValid_Impl(worksheet.keybits, worksheet, false); requires 0 < |worksheet_row.P.rows|; requires 0 < |worksheet_row.Q.rows|; requires worksheet' == RSAKeyGenerationWorksheetAppend(worksheet, worksheet_row, last_accepted); requires PrimeGenerationWorksheetValid_precondition(worksheet_row.P); requires PrimeGenerationWorksheetValid_precondition(worksheet_row.Q); requires RSAKeyGenerationWorksheetRowValid(worksheet'.keybits, worksheet_row); requires worksheet'.rows[|worksheet'.rows|-1].accepted == last_accepted; requires worksheet'.p == PrimeGenerationOutput(worksheet'.rows[|worksheet'.rows|-1].P); requires worksheet'.q == PrimeGenerationOutput(worksheet'.rows[|worksheet'.rows|-1].Q); requires worksheet'.phi == (worksheet'.p-1)*(worksheet'.q-1); requires worksheet'.phi != 0; requires worksheet'.n == worksheet'.p*worksheet'.q; ensures RSAKeyConsistentWithWorksheet_precondition(worksheet'); ensures last_accepted ==> RSAKeyGenerationWorksheetValid_Impl(worksheet'.keybits, worksheet', last_accepted); ensures RSAKeyGenerationWorksheetConsumesRandoms(worksheet'.rows) == worksheet'.randoms; ensures 0 < |worksheet'.rows|; { } method RSAKeyGenSetup(keybits:nat) returns (e:array, halfbits:nat) requires 20, q:array, n:int) requires keybits <= 2*halfbits-2; requires WellformedFatNat(p); requires WellformedFatNat(q); requires n == J(p)*J(q); requires power2(halfbits-1) <= J(p); requires power2(halfbits-1) <= J(q); ensures power2(keybits) <= n; { calc { power2(keybits); <= { lemma_power2_increases(keybits, halfbits-1 + halfbits-1); } power2(halfbits-1 + halfbits-1); { lemma_power2_adds(halfbits-1, halfbits-1); } power2(halfbits-1) * power2(halfbits-1); <= { lemma_mul_inequality(power2(halfbits-1), J(p), power2(halfbits-1)); } J(p) * power2(halfbits-1); <= { lemma_mul_left_inequality(J(p), power2(halfbits-1), J(q)); } J(p) * J(q); n; } } lemma lemma_RSAKeyGen_2(keybits:nat, halfbits:nat, p:array, q:array, n:int, e:array, pMinus1:array, qMinus1:array, phi_n:array) requires keybits <= 2*halfbits-2; //- requires 3 < halfbits < power2(30); requires 3 < halfbits < power2(32); requires 20, halfbits:nat, one:array) reads one; reads e; reads this`TPM; reads this`IoMemPerm; { true && (20, started:bool, p:array, q:array, d:array, n:int, worksheet:RSAKeyGenerationWorksheet) requires WellformedFatNat(e); reads e; reads p; reads d; reads q; { true && (WellformedFatNat(p)) && (WellformedFatNat(q)) && (WellformedFatNat(d)) && (n == J(p)*J(q)) && (n != 0) && (power2(keybits) <= n) && (((J(p)-1)*(J(q)-1)) != 0) && (mul(J(d), J(e)) % ((J(p)-1)*(J(q)-1)) == 1) && (started) && (worksheet.p == J(p)) && (worksheet.q == J(q)) } predicate RSAKeyGenLoop_invariant( keybits:nat, e:array, started:bool, success:bool, p:array, q:array, d:array, n:int, worksheet:RSAKeyGenerationWorksheet, oldTPM:TPM_struct, curTPM:TPM_struct) requires WellformedFatNat(e); reads e; reads p; reads q; reads d; { true && (success ==> RSAKeyGenLoop_success_properties(keybits, e, started, p, q, d, n, worksheet)) && (started ==> 0 < |worksheet.rows|) && (RSAKeyConsistentWithWorksheet_precondition(worksheet)) && (RSAKeyGenerationWorksheetValid_Impl(keybits, worksheet, success)) && (worksheet.keybits == keybits) && (RSAKeyGenerationWorksheetConsumesRandoms(worksheet.rows) == worksheet.randoms) && (TPMs_match_except_for_randoms(oldTPM, curTPM)) && (oldTPM.random_index <= curTPM.random_index) && (curTPM.random_index == oldTPM.random_index + |worksheet.randoms|) && (worksheet.randoms == TPM_random_bytes_premium(oldTPM.random_index, curTPM.random_index)) } method {:timeLimitMultiplier 2} RSAKeyGenLoop_step( keybits:nat, e:array, halfbits:nat, one:array, ghost started:bool, p:array, q:array, d:array, ghost n:int, ghost worksheet:RSAKeyGenerationWorksheet, ghost origTPM:TPM_struct) returns ( success':bool, p':array, q':array, d':array, ghost n':int, ghost worksheet':RSAKeyGenerationWorksheet) requires RSAKeyGenLoop_requires(keybits, e, halfbits, one); requires RSAKeyGenLoop_invariant(keybits, e, started, false, p, q, d, n, worksheet, origTPM, TPM); requires TPM_ready(); ensures RSAKeyGenLoop_invariant(keybits, e, true, success', p', q', d', n', worksheet', origTPM, TPM); ensures TPM_ready(); modifies this`TPM; modifies this`IoMemPerm; { ghost var loop_TPM_index := TPM.random_index; ghost var p_worksheet, q_worksheet; assert TPM_ready(); p', p_worksheet := GenRandomPrime(halfbits); ghost var mid_TPM_index := TPM.random_index; q', q_worksheet := GenRandomPrime(halfbits); //- assert J(p') < power2(power2(29)); //- assert J(q') < power2(power2(29)); assert J(p')!=0; assert J(q')!=0; n' := J(p')*J(q'); lemma_mul_nonzero(J(p'), J(q')); assert n'!=0; lemma_RSAKeyGen_1(keybits, halfbits, p', q', n'); var pMinus1:array := FatNatSub(p',one); var qMinus1:array := FatNatSub(q',one); //- assert J(pMinus1) < power2(power2(29)); //- assert J(qMinus1) < power2(power2(29)); var phi_n:array := FatNatMul(pMinus1,qMinus1); lemma_RSAKeyGen_2(keybits, halfbits, p', q', n', e, pMinus1, qMinus1, phi_n); //- assert J(phi_n) < power2(power2(30)) == Frump(); //- assert FrumpyBigNat(phi_n); //- assert J(e) < J(phi_n); //- assert FrumpyBigNat(e); success',d' := MultiplicativeInverse(phi_n, e); ghost var worksheet_row := RSAKeyGenerationWorksheetRow_c( p_worksheet, q_worksheet, success', p_worksheet.randoms + q_worksheet.randoms); /**/ assert TPM.random_index == mid_TPM_index + |q_worksheet.randoms|; /**/ assert mid_TPM_index == loop_TPM_index + |p_worksheet.randoms|; lemma_random_comprehension(loop_TPM_index, p_worksheet.randoms, q_worksheet.randoms); /**/ assert TPM.random_index == loop_TPM_index + |p_worksheet.randoms| + |q_worksheet.randoms|; worksheet' := RSAKeyGenerationWorksheetAppend(worksheet, worksheet_row, success'); /**/ assert worksheet.randoms == TPM_random_bytes_premium(origTPM.random_index, loop_TPM_index); /**/ assert worksheet.randoms == TPM_random_bytes(origTPM.random_index, origTPM.random_index + |worksheet.randoms|); /**/ assert loop_TPM_index + |worksheet_row.randoms| == TPM.random_index; /**/ assert TPM_random_bytes(loop_TPM_index, TPM.random_index) == worksheet_row.randoms; lemma_random_comprehension(origTPM.random_index, worksheet.randoms, worksheet_row.randoms); /**/ assert TPM.random_index == origTPM.random_index + |worksheet'.randoms|; ghost var randoms' := worksheet.randoms + worksheet_row.randoms; WorksheetAppend_lemma(worksheet, worksheet_row, success', worksheet'); assert worksheet'.randoms == randoms'; lemma_RSAKeyGen_3(worksheet, worksheet_row, worksheet', success'); calc { n'; J(p')*J(q'); } } method RSAKeyGenLoop(keybits:nat, e:array, halfbits:nat, one:array) returns (p:array, q:array, d:array, ghost worksheet:RSAKeyGenerationWorksheet, ghost n:int) requires RSAKeyGenLoop_requires(keybits, e, halfbits, one); modifies this`TPM; modifies this`IoMemPerm; ensures RSAKeyConsistentWithWorksheet_precondition(worksheet); ensures RSAKeyGenerationWorksheetValid_Impl(keybits, worksheet, true); ensures worksheet.keybits == keybits; ensures RSAKeyGenerationWorksheetConsumesRandoms(worksheet.rows) == worksheet.randoms; ensures TPM_ready(); ensures TPMs_match_except_for_randoms(old(TPM), TPM); ensures old(TPM).random_index <= TPM.random_index; ensures TPM.random_index == old(TPM).random_index + |worksheet.randoms|; ensures worksheet.randoms == TPM_random_bytes_premium(old(TPM).random_index, TPM.random_index); ensures 0 < |worksheet.rows|; ensures WellformedFatNat(p); ensures WellformedFatNat(q); ensures WellformedFatNat(d); ensures n == J(p)*J(q); ensures n != 0; ensures power2(keybits) <= n; ensures ((J(p)-1)*(J(q)-1)) != 0; ensures mul(J(d), J(e)) % ((J(p)-1)*(J(q)-1)) == 1; ensures worksheet.p == J(p); ensures worksheet.q == J(q); { worksheet := RSAKeyGenerationWorksheet_c(keybits, [], [], 0, 0, 0, 0); p := one; //- dafnycc: initialize variable q := one; //- dafnycc: initialize variable d := one; //- dafnycc: initialize variable ghost var started := false; var success:bool := false; while (!success) decreases *; invariant RSAKeyGenLoop_invariant(keybits, e, started, success, p, q, d, n, worksheet, old(TPM), TPM); invariant TPM_ready(); { success,p,q,d,n,worksheet := RSAKeyGenLoop_step(keybits, e, halfbits, one, started, p, q, d, n, worksheet, old(TPM)); started := true; } } lemma lemma_prime_bound(halfbits:nat, wks:CandidatePrimeWorksheet) requires 0, wks:RSAKeyGenerationWorksheet) //- requires keybits= power2(keybits); ensures key.pub.size >= keybits / 8; ensures RSAKeyGenerationValid(keybits, KeyPairImplToSpec_internal(key), TPM_random_bytes_premium(old(TPM).random_index, TPM.random_index)); { lemma_2to32(); var one := MakeBELiteralArray(1); var e, halfbits; lemma_power2_increases(28, 29); e,halfbits := RSAKeyGenSetup(keybits); var p:array, q:array, d:array; ghost var worksheet:RSAKeyGenerationWorksheet; ghost var n:int; lemma_power2_increases(28, 32); p, q, d, worksheet, n := RSAKeyGenLoop(keybits, e, halfbits, one); var N:array := FatNatMul(p, q); assert J(N)==n; //- assert FrumpyBigNat(N); assert J(N)!=0; var size := ComputeKeySize(N); var nReciprocal := FatNatComputeReciprocal(N); var recip_ref := if nReciprocal.FNDivKnownReciprocal? then nReciprocal.TwoTo32wDividedByD else p; //- do something real to nReciprocal.TwoTo32wDividedByD key := RSAKeyPairImpl_c_internal(RSAPubKeyImpl_c_internal(N, size, e, nReciprocal), d); if (key.pub.size < keybits/8) { calc { power2(keybits); <= J(key.pub.n); < power2(8 * key.pub.size); < { lemma_power2_strictly_increases(8 * key.pub.size, 8 * (keybits / 8)); } power2(8 * (keybits / 8)); <= { lemma_power2_increases(8 * (keybits / 8), keybits); } power2(keybits); } assert false; } //- lemma_modulus_length_acceptable(keybits, N, worksheet); assert WellformedFatNat(key.d); assert WellformedRSAKeyPairImpl_internal(key); assert RSAKeyGenerationWorksheetConsumesRandoms(worksheet.rows) == worksheet.randoms; assert RSAKeyGenerationWorksheetValid(keybits, worksheet); assert RSAKeyConsistentWithWorksheet(keybits, KeyPairImplToSpec_internal(key), worksheet); assert RSAKeyGenerationValid(keybits, KeyPairImplToSpec_internal(key), worksheet.randoms); } method GenDummyKey_internal() returns (key_pair:RSAKeyPairImpl_internal) //- used when dafnycc requires that we initialize a variable { var zilch := MakeBELiteralArray(0); key_pair := RSAKeyPairImpl_c_internal(RSAPubKeyImpl_c_internal(zilch, 0, zilch, FNDivUnknownReciprocal()), zilch); } method MakeNullKey(bits:nat) returns (key:RSAKeyPairImpl_internal) requires Word32(bits); { var n := FatPower2(bits); lemma_2to32(); var one := MakeBELiteralArray(1); key := RSAKeyPairImpl_c_internal(RSAPubKeyImpl_c_internal(n, 1, one, FNDivUnknownReciprocal()), one); } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Crypto/RSA/RSADigestedSign.i.dfy ================================================ include "RSASpec.s.dfy" include "RSA.i.dfy" include "RSAOps.i.dfy" method {:dafnycc_conservative_seq_triggers} DigestedSign_internal(key:RSAKeyPairImpl_internal, message:seq) returns (signature:array) requires WellformedRSAKeyPairImpl_internal(key); requires IsByteSeq(message); requires |message| < power2(28); requires RSA_DIGEST_MIN_KEY_SIZE() <= key.pub.size; requires TPM_ready(); modifies this`TPM; modifies this`IoMemPerm; ensures TPM_ready(); ensures TPM==old(TPM); ensures IoMemPerm==old(IoMemPerm); ensures RSASignatureRequires(KeyPairImplToSpec_internal(key), message); ensures signature!=null; ensures IsByteSeq(signature[..]); ensures RSASignature(KeyPairImplToSpec_internal(key), message) == signature[..]; ensures fresh(signature); //- ensures Word32(signature.Length); { var nref := key.pub.n; //- do something real to key.pub.n so dafnycc knows it's allocated var eref := key.pub.e; //- do something real to key.pub.e so dafnycc knows it's allocated var dref := key.d; //- do something real to key.d so dafnycc knows it's allocated var recip_ref := if key.pub.nReciprocal.FNDivKnownReciprocal? then key.pub.nReciprocal.TwoTo32wDividedByD else key.pub.n; //- dafnycc calc { |BEByteSeqToBitSeq_premium(message)|; < calc { |BEByteSeqToBitSeq_premium(message)|; { lemma_BEByteSeqToBitSeq_ensures(message); } |message|*8; { lemma_mul_is_mul_boogie(|message|, 8); } mul(|message|,8); { lemma_2toX32(); } |message|*power2(3); < { lemma_mul_strict_inequality(|message|,power2(28),power2(3)); } power2(28)*power2(3); { lemma_power2_adds(28,3); } power2(31); <= { lemma_power2_increases(31,64); } power2(64); } power2(64); } lemma_power2_increases(28,61); lemma_power2_increases(28,29); var digested_message := SHA256DigestImpl(message); signature := DigestedSignSecondPart(key, message, digested_message); } predicate {:heap} DigestedSignSecondPartRequirements(key:RSAKeyPairImpl_internal, message:seq, digested_message:seq) reads key.pub.n; reads key.pub.e; reads key.d; reads if key.pub.nReciprocal.FNDivKnownReciprocal? then key.pub.nReciprocal.TwoTo32wDividedByD else key.pub.n; { WellformedRSAKeyPairImpl_internal(key) && IsByteSeq(message) && |message| < power2(28) && |message| < power2(29) && |message| < power2(61) && RSA_DIGEST_MIN_KEY_SIZE() <= key.pub.size && |BEByteSeqToBitSeq(message)| < power2(64) && IsBitSeq(BEByteSeqToBitSeq(message)) && IsByteSeq(digested_message) && digested_message == SHA256Digest(message) && |digested_message| == 51 } method {:dafnycc_conservative_seq_triggers} DigestedSignSecondPart(key:RSAKeyPairImpl_internal, message:seq, digested_message:seq) returns (signature:array) requires DigestedSignSecondPartRequirements(key, message, digested_message); requires TPM_ready(); modifies this`TPM; modifies this`IoMemPerm; ensures TPM_ready(); ensures TPM==old(TPM); ensures IoMemPerm==old(IoMemPerm); ensures RSASignatureRequires(KeyPairImplToSpec_internal(key), message); ensures signature!=null; ensures IsByteSeq(signature[..]); ensures RSASignature(KeyPairImplToSpec_internal(key), message) == signature[..]; ensures fresh(signature); { var nref := key.pub.n; //- do something real to key.pub.n so dafnycc knows it's allocated var eref := key.pub.e; //- do something real to key.pub.e so dafnycc knows it's allocated var dref := key.d; //- do something real to key.d so dafnycc knows it's allocated var recip_ref := if key.pub.nReciprocal.FNDivKnownReciprocal? then key.pub.nReciprocal.TwoTo32wDividedByD else key.pub.n; //- dafnycc calc { PadCount(digested_message, key.pub.size); key.pub.size - 3 - |digested_message|; >= RSA_DIGEST_MIN_KEY_SIZE() - 3 - 51; 62 - 3 - 51; 8; } var messageN:array; ghost var padded_msg:seq; messageN,padded_msg := MessageToInteger(digested_message, key.pub.size, PadModeSign()); assert padded_msg == PKCS15_SignaturePad(SHA256Digest(message), key.pub.size); assert TPM == old(TPM); assert IoMemPerm == old(IoMemPerm); lemma_PKCS15_SignaturePad(SHA256Digest_premium(message), key.pub.size); assert RSASignatureRequires(KeyPairImplToSpec_internal(key), message); signature := DigestedSignThirdPart(key, message, digested_message, messageN, padded_msg); } predicate {:heap} DigestedSignThirdPartRequirements (key:RSAKeyPairImpl_internal, message:seq, digested_message:seq, messageN:seq, padded_msg:seq) reads key.pub.n; reads key.pub.e; reads key.d; reads if key.pub.nReciprocal.FNDivKnownReciprocal? then key.pub.nReciprocal.TwoTo32wDividedByD else key.pub.n; { DigestedSignSecondPartRequirements(key, message, digested_message) && IsWordSeq(messageN) && IsByteSeq(padded_msg) //- && PKCS15_SignaturePad(SHA256Digest(message), key.pub.size) == [0, BlockType(PadModeSign())] + RepeatDigit(SignaturePadByte(), key.pub.size - 3 - |SHA256Digest(message)|) + [0] + SHA256Digest(message) && PKCS15_SignaturePad(digested_message, key.pub.size) == padded_msg && PKCS15_PaddingRelation(padded_msg, digested_message, PadModeSign()) && RSASignatureRequires(KeyPairImplToSpec_internal(key), message) && BigEndianIntegerValue(padded_msg)==BEWordSeqToInt(messageN) && BEByteSeqToInt(padded_msg)==BEWordSeqToInt(messageN) && 0 < BEWordSeqToInt(messageN) < power2(8*(key.pub.size-1)) && |padded_msg|==key.pub.size } method {:dafnycc_conservative_seq_triggers} DigestedSignThirdPart(key:RSAKeyPairImpl_internal, ghost message:seq, ghost digested_message:seq, messageN:array, ghost padded_msg:seq) returns (signature:array) requires WellformedFatNat(messageN); requires DigestedSignThirdPartRequirements(key, message, digested_message, messageN[..], padded_msg); requires messageN != key.pub.n && messageN != key.pub.e; requires key.pub.nReciprocal.FNDivKnownReciprocal? ==> messageN != key.pub.nReciprocal.TwoTo32wDividedByD; ensures RSASignatureRequires(KeyPairImplToSpec_internal(key), message); ensures signature!=null; ensures IsByteSeq(signature[..]); ensures RSASignature(KeyPairImplToSpec_internal(key), message) == signature[..]; ensures fresh(signature); { var nref := key.pub.n; //- do something real to key.pub.n so dafnycc knows it's allocated var eref := key.pub.e; //- do something real to key.pub.e so dafnycc knows it's allocated var dref := key.d; //- do something real to key.d so dafnycc knows it's allocated var recip_ref := if key.pub.nReciprocal.FNDivKnownReciprocal? then key.pub.nReciprocal.TwoTo32wDividedByD else key.pub.n; //- dafnycc var signatureN:array := InnerDecrypt(key, messageN); var short_signature := BEWordArrayToByteArray(signatureN); calc { BEDigitSeqToInt(power2(8), short_signature[..]); J(signatureN); < J(key.pub.n); < power2(8*key.pub.size); { lemma_power2_unfolding(8, key.pub.size); lemma_mul_is_mul_boogie(8, key.pub.size); } power(power2(8), key.pub.size); } lemma_CanonicalLengthBound(power2(8), short_signature[..], key.pub.size); //-assert short_signature.Length <= key.pub.size; signature := DigestedSignFourthPart(key, message, digested_message, messageN[..], padded_msg, signatureN[..], short_signature); } predicate {:heap} DigestedSignFourthPartRequirements (key:RSAKeyPairImpl_internal, message:seq, digested_message:seq, messageN:seq, padded_msg:seq, signatureN:seq, short_signature:seq) reads key.pub.n; reads key.pub.e; reads key.d; reads if key.pub.nReciprocal.FNDivKnownReciprocal? then key.pub.nReciprocal.TwoTo32wDividedByD else key.pub.n; { DigestedSignThirdPartRequirements(key, message, digested_message, messageN, padded_msg) && IsWordSeq(signatureN) && BEWordSeqToInt(signatureN) == power(BEWordSeqToInt(messageN), BEWordSeqToInt(key.d[..])) % BEWordSeqToInt(key.pub.n[..]) && IsByteSeq(short_signature) && BEByteSeqToInt(short_signature) == BEWordSeqToInt(signatureN) && |short_signature| <= key.pub.size && BEByteSeqToInt(short_signature) < power(power2(8), key.pub.size) } method {:dafnycc_conservative_seq_triggers} DigestedSignFourthPart(key:RSAKeyPairImpl_internal, ghost message:seq, ghost digested_message:seq, ghost messageN:seq, ghost padded_msg:seq, ghost signatureN:seq, short_signature:array) returns (signature:array) requires short_signature != null; requires DigestedSignFourthPartRequirements(key, message, digested_message, messageN, padded_msg, signatureN, short_signature[..]); requires short_signature != key.pub.n && short_signature != key.pub.e; requires key.pub.nReciprocal.FNDivKnownReciprocal? ==> short_signature != key.pub.nReciprocal.TwoTo32wDividedByD; ensures RSASignatureRequires(KeyPairImplToSpec_internal(key), message); ensures signature!=null; ensures IsByteSeq(signature[..]); ensures RSASignature(KeyPairImplToSpec_internal(key), message) == signature[..]; ensures fresh(signature); { var nref := key.pub.n; //- do something real to key.pub.n so dafnycc knows it's allocated var eref := key.pub.e; //- do something real to key.pub.e so dafnycc knows it's allocated var dref := key.d; //- do something real to key.d so dafnycc knows it's allocated var recip_ref := if key.pub.nReciprocal.FNDivKnownReciprocal? then key.pub.nReciprocal.TwoTo32wDividedByD else key.pub.n; //- dafnycc signature := PadArrayLeft(key.pub.size - short_signature.Length, short_signature); ghost var shorts := short_signature[..]; ghost var longs := signature[..]; forall (i | |longs|-|shorts|<=i<|longs|) ensures longs[i] == shorts[i - (|longs|-|shorts|)]; { calc { longs[i]; signature[..][i]; signature[key.pub.size - short_signature.Length .. ][i - (key.pub.size - short_signature.Length)]; { assert signature[key.pub.size - short_signature.Length .. ] == short_signature[..]; } short_signature[..][i - (key.pub.size - short_signature.Length)]; shorts[i - (key.pub.size - short_signature.Length)]; shorts[i - (|longs|-|shorts|)]; } } calc { BEByteSeqToInt(signature[..]); { lemma_LeadingZeros(power2(8), short_signature[..], signature[..]); } BEByteSeqToInt(short_signature[..]); BEWordSeqToInt(signatureN); } Lemma_DigestedSignFourthPartHelper(KeyPairImplToSpec_internal(key), message, digested_message, messageN, padded_msg, signatureN, short_signature[..], signature[..]); } lemma {:dafnycc_conservative_seq_triggers} Lemma_DigestedSignFourthPartHelper(key:RSAKeyPairSpec, message:seq, digested_message:seq, messageN:seq, padded_msg:seq, signatureN:seq, short_signature:seq, signature:seq) requires WellformedRSAKeyPairSpec(key); requires IsByteSeq(message); requires RSA_DIGEST_MIN_KEY_SIZE() <= key.pub.size; requires IsByteSeq(padded_msg); requires IsByteSeq(digested_message); requires IsBitSeq(BEByteSeqToBitSeq(message)); requires |BEByteSeqToBitSeq(message)| < power2(64); requires digested_message == SHA256Digest(message); requires |digested_message| == 51; requires PKCS15_PaddingRelation(padded_msg, digested_message, PadModeSign()); requires PKCS15_SignaturePad(digested_message, key.pub.size) == padded_msg; requires RSASignatureRequires(key, message); requires IsWordSeq(messageN); requires BigEndianIntegerValue(padded_msg)==BEWordSeqToInt(messageN); requires BEByteSeqToInt(padded_msg)==BEWordSeqToInt(messageN); requires |padded_msg|==key.pub.size; requires IsWordSeq(signatureN); requires BEWordSeqToInt(signatureN) == power(BEWordSeqToInt(messageN), key.d) % key.pub.n; requires IsByteSeq(short_signature); requires BEByteSeqToInt(short_signature) == BEWordSeqToInt(signatureN); requires |short_signature| <= key.pub.size; requires BEByteSeqToInt(short_signature) < power(power2(8), key.pub.size); requires |signature| == key.pub.size; requires IsByteSeq(signature); requires forall i :: |signature|-|short_signature| <= i < |signature| ==> signature[i] == short_signature[i - (|signature| - |short_signature|)]; requires BEByteSeqToInt(signature) == BEWordSeqToInt(signatureN); ensures RSASignature(key, message) == signature; { //-assert BEIntToByteSeq(I(signatureN)) == signature; ghost var padded_nint := BEByteSeqToInt(PKCS15_SignaturePad(SHA256Digest(message), key.pub.size)); ghost var sign_n := power(padded_nint, key.d) % key.pub.n; assert power(padded_nint, key.d) % key.pub.n == BEWordSeqToInt(signatureN); ghost var sslen := |short_signature|; if (key.pub.size < sslen) { //- The calc below is nested to hide the internals of the calc from later code even in DafnyCC calc { true ==> calc { key.pub.n; < power2(8*key.pub.size); <= { lemma_power2_increases(8*key.pub.size, 8*(sslen-1)); } power2(8*(sslen-1)); { lemma_power2_unfolding(8, (sslen-1)); lemma_mul_is_mul_boogie(8, (sslen-1)); } power(power2(8), sslen-1); { lemma_mul_basics_forall(); } mul(1, power(power2(8), sslen-1)); <= { lemma_power_positive(power2(8), sslen-1); lemma_mul_inequality(1, short_signature[0], power(power2(8), sslen-1)); } short_signature[0] * power(power2(8), sslen-1); <= { lemma_BEDigitSeqToInt_bound(power2(8), short_signature); } BEByteSeqToInt(short_signature); BEWordSeqToInt(signatureN); } false; } } calc { signature; { lemma_BEDigitSeqToInt_invertibility(power2(8), BEWordSeqToInt(signatureN), signature); } BEIntToDigitSeq(power2(8), |signature|, BEWordSeqToInt(signatureN)); BEIntToDigitSeq(power2(8), key.pub.size, sign_n); { assert WellformedRSAKeyPairSpec(key); } RSASignature(key, message); } assert BEWordSeqToInt(signatureN) < key.pub.n; lemma_BEIntToDigitSeq_properties(power2(8), 0, BEWordSeqToInt(signatureN)); calc { |signature|; <= { if (BEWordSeqToInt(signatureN)==0) { reveal_BEIntToDigitSeq_private(); } } key.pub.size; } } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Crypto/RSA/RSAOps.i.dfy ================================================ include "RSASpec.s.dfy" include "RSA.i.dfy" //- Eventually useful for lemma_message_transmission predicate {:heap} EncryptionRelation(pubkey:RSAPubKeyImpl_internal, p:array, c:array) requires WellformedRSAPubKeyImpl_internal(pubkey); requires WellformedFatNat(p); requires WellformedFatNat(c); reads pubkey.n; reads pubkey.e; reads if pubkey.nReciprocal.FNDivKnownReciprocal? then pubkey.nReciprocal.TwoTo32wDividedByD else pubkey.n; reads p; reads c; { J(c)==power(J(p),J(pubkey.e)) % J(pubkey.n) } method InnerEncrypt(pubkey:RSAPubKeyImpl_internal, plaintext:array) returns (ciphertext:array) requires WellformedRSAPubKeyImpl_internal(pubkey); //- requires FrumpyBigNat(plaintext); requires WellformedFatNat(plaintext); requires 0 < J(plaintext) < J(pubkey.n); //- ensures FrumpyBigNat(ciphertext); ensures WellformedFatNat(ciphertext); ensures J(ciphertext) < J(pubkey.n); ensures EncryptionRelation(pubkey, plaintext, ciphertext); { //- ciphertext := BigNatModExp(plaintext, pubkey.e, pubkey.n); //- var B := BigNatToFatNat(plaintext); //- var E := BigNatToFatNat(pubkey.e); //- var N := BigNatToFatNat(pubkey.n); var B := plaintext; var E := pubkey.e; var N := pubkey.n; ghost var pv := power2(32); //- assert IsCanonicalDigitSeq(pv, B[..]); //- assert IsCanonicalDigitSeq(pv, E[..]); //- assert IsCanonicalDigitSeq(pv, N[..]); ghost var Bv := BEWordSeqToInt(B[..]); ghost var Ev := BEWordSeqToInt(E[..]); ghost var Nv := BEWordSeqToInt(N[..]); assert Bv < Nv; //- calc { //- Ev; //- < //- Frump(); //- power2(power2(30)); //- <= { lemma_power2_increases(30,31); //- lemma_power2_increases(power2(30),power2(31)); } //- power2(power2(31)); //- } //- lemma_CanonicalLength_inherit(pv, B[..], N[..], power2(25)); //- requires BEWordSeqToInt(E[..]) < power2(power2(31)); //- requires B.Length < power2(25); //- requires N.Length < power2(25); var R := FatNatModExpUsingReciprocal(B, E, N, pubkey.nReciprocal); //- ciphertext := FatNatToBigNat(R); ciphertext := R; } static predicate RSAEncryptionRequires(pubkey:RSAPubKeySpec, msg:seq, padding:seq) { WellformedRSAPubKeySpec(pubkey) && IsByteSeq(msg) && IsByteSeq(padding) && |padding| == PadCount(msg, pubkey.size) && PadCount(msg, pubkey.size) >= 8 && NonzeroPad(padding) && IsDigitSeq(power2(8), PKCS15_EncryptionPad(msg, pubkey.size, padding)) } static lemma lemma_seq_remove_first_element(s:seq, j:int) requires 0 <= j < |s|; ensures s[j..] == [s[j]] + s[j+1..]; { } static lemma lemma_seq_break_middle(s:seq, i:int, j:int) requires 0 <= i <= j <= |s|; ensures s[i..] == s[i..j] + s[j..]; { } lemma {:heap} lemma_Encrypt_fragile_bit(pubkey:RSAPubKeySpec, plaintext:seq, padded_plaintext:seq, ep:seq, padding:seq) requires WellformedRSAPubKeySpec(pubkey); requires IsByteSeq(plaintext); requires IsByteSeq(padded_plaintext); requires IsByteSeq(ep); requires IsByteSeq(padding); requires PKCS15_PaddingRelationWith(padded_plaintext, plaintext, PadModeEncrypt(), padding); requires |padding| == PadCount(plaintext, pubkey.size); requires ep == PKCS15_EncryptionPad(plaintext, pubkey.size, padding); ensures padded_plaintext == ep; { calc { padded_plaintext; { lemma_seq_remove_first_element(padded_plaintext, 0); } [padded_plaintext[0]] + padded_plaintext[1..]; [0] + padded_plaintext[1..]; { lemma_seq_remove_first_element(padded_plaintext, 1); } [0] + [padded_plaintext[1]] + padded_plaintext[2..]; [0] + [BlockType(PadModeEncrypt())] + padded_plaintext[2..]; { lemma_seq_break_middle(padded_plaintext, 2, |padding|+2); } [0] + [BlockType(PadModeEncrypt())] + padded_plaintext[2..|padding|+2] + padded_plaintext[|padding|+2..]; [0] + [BlockType(PadModeEncrypt())] + padding + padded_plaintext[|padding|+2..]; { lemma_seq_remove_first_element(padded_plaintext, |padding|+2); } [0] + [BlockType(PadModeEncrypt())] + padding + [padded_plaintext[|padding|+2]] + padded_plaintext[|padding|+3..]; [0] + [BlockType(PadModeEncrypt())] + padding + [0] + padded_plaintext[|padding|+3..]; [0] + [BlockType(PadModeEncrypt())] + padding + [0] + plaintext; { assert [0, BlockType(PadModeEncrypt())] == [0] + [BlockType(PadModeEncrypt())]; } [0, BlockType(PadModeEncrypt())] + padding + [0] + plaintext; PKCS15_EncryptionPad(plaintext, pubkey.size, padding); ep; } } method {:dafnycc_conservative_seq_triggers} Encrypt_internal(pubkey:RSAPubKeyImpl_internal, plaintext:seq) returns (ciphertext:seq) requires IsByteSeq(plaintext); requires WellformedRSAPubKeyImpl_internal(pubkey); requires |plaintext| <= pubkey.size - 11; requires TPM_ready(); modifies this`TPM; modifies this`IoMemPerm; ensures TPM_ready(); ensures WellformedRSAPubKeyImpl_internal(pubkey); ensures WellformedRSAPubKeySpec(PubKeyImplToSpec_internal(pubkey)); ensures IsByteSeq(ciphertext); ensures exists padding:seq :: RSAEncryptionRequires(PubKeyImplToSpec_internal(pubkey), plaintext, padding) && RSAEncryption(PubKeyImplToSpec_internal(pubkey), plaintext, padding) == ciphertext; { var nref := pubkey.n; //- do something real to pubkey.n so dafnycc knows it's allocated var eref := pubkey.e; //- do something real to pubkey.e so dafnycc knows it's allocated var recip_ref := if pubkey.nReciprocal.FNDivKnownReciprocal? then pubkey.nReciprocal.TwoTo32wDividedByD else pubkey.n; //- do something real to reciprocal for dafnycc var plainN:array; ghost var padded_plaintext:seq; plainN,padded_plaintext := MessageToInteger(plaintext, pubkey.size, PadModeEncrypt()); calc { J(plainN); <= power2(8*(pubkey.size-1)); <= { //- KeySizeIs ensures assert KeyModulusMatchesSizeInBytes(PubKeyImplToSpec_internal(pubkey).n, pubkey.size); assert (pubkey.size>0 ==> power2(8*(pubkey.size-1)) <= J(pubkey.n)); assert power2(8*(pubkey.size-1)) <= J(pubkey.n); } J(pubkey.n); } //- assert FrumpyBigNat(plainN); var cipherN:array := InnerEncrypt(pubkey, plainN); var ciphertext_raw := IntegerToBESeq(cipherN); assert IsByteSeq(ciphertext_raw); assert IsByteSeq(padded_plaintext); assert PKCS15_PaddingRelation(padded_plaintext, plaintext, PadModeEncrypt()); calc { BigEndianIntegerValue(ciphertext_raw); J(cipherN); //- InnerEncrypt ensures, EncryptionRelation ensures power(J(plainN),J(pubkey.e)) % J(pubkey.n); power(BigEndianIntegerValue(padded_plaintext),J(pubkey.e)) % J(pubkey.n); power(BigEndianIntegerValue(padded_plaintext),PubKeyImplToSpec_internal(pubkey).e) % PubKeyImplToSpec_internal(pubkey).n; } ciphertext := EncryptSecondStep(PubKeyImplToSpec_internal(pubkey), plaintext, J(plainN), padded_plaintext, J(cipherN), ciphertext_raw); } method {:dafnycc_conservative_seq_triggers} EncryptSecondStep(ghost pubkey:RSAPubKeySpec, ghost plaintext:seq, ghost plainN:int, ghost padded_plaintext:seq, ghost cipherN:int, ciphertext_raw:seq) returns (ciphertext:seq) requires IsByteSeq(plaintext); requires WellformedRSAPubKeySpec(pubkey); requires |plaintext| <= pubkey.size - 11; requires plainN < pubkey.n; requires IsByteSeqOfLen(padded_plaintext, pubkey.size); requires PKCS15_PaddingRelation(padded_plaintext, plaintext, PadModeEncrypt()); requires plainN == BigEndianIntegerValue(padded_plaintext); requires cipherN < pubkey.n; requires cipherN == power(plainN, pubkey.e) % pubkey.n; requires IsByteSeq(ciphertext_raw); requires |ciphertext_raw| >= 1; requires cipherN == BigEndianIntegerValue(ciphertext_raw); requires ciphertext_raw == [0] + BEIntToByteSeq(cipherN); requires BigEndianIntegerValue(ciphertext_raw) == power(BigEndianIntegerValue(padded_plaintext), pubkey.e) % pubkey.n; ensures IsByteSeq(ciphertext); ensures exists padding:seq :: RSAEncryptionRequires(pubkey, plaintext, padding) && RSAEncryption(pubkey, plaintext, padding) == ciphertext; { ciphertext := ciphertext_raw[1..]; ghost var padding:seq :| PKCS15_PaddingRelationWith(padded_plaintext, plaintext, PadModeEncrypt(), padding); ghost var ep := PKCS15_EncryptionPad(plaintext, pubkey.size, padding); //- assert IsByteSeq(ep); ghost var pad_msg := BEByteSeqToInt(ep); lemma_Encrypt_fragile_bit(pubkey, plaintext, padded_plaintext, ep, padding); calc { RSAEncryption(pubkey, plaintext, padding); BEIntToByteSeq(power(pad_msg, pubkey.e) % pubkey.n); { calc { power(pad_msg, pubkey.e) % pubkey.n; { calc { plainN; BigEndianIntegerValue(padded_plaintext); { lemma_BigEndianIntegerValue_equals_BEByteSeqToInt(padded_plaintext); } BEByteSeqToInt(ep); pad_msg; } } power(plainN, pubkey.e) % pubkey.n; cipherN; } //- Note that here we merely show equivalent integer values; //- the legacy function IntegerToBESeq has been equipped with an //- additional ensures about BEIntToByteSeq. } BEIntToByteSeq(cipherN); { assert [0] + BEIntToByteSeq(cipherN) == ciphertext_raw; } ciphertext_raw[1..]; ciphertext; } } //- Eventually useful for lemma_message_transmission predicate {:heap} DecryptionRelation(key:RSAKeyPairImpl_internal, c:array, p:array) requires WellformedRSAKeyPairImpl_internal(key); requires WellformedFatNat(c); requires WellformedFatNat(p); reads c; reads p; reads key.pub.n; reads key.pub.e; reads key.d; reads if key.pub.nReciprocal.FNDivKnownReciprocal? then key.pub.nReciprocal.TwoTo32wDividedByD else key.pub.n; { J(p)==power(J(c),J(key.d)) % J(key.pub.n) } method InnerDecrypt(key:RSAKeyPairImpl_internal, ciphertext:array) returns (plaintext:array) requires WellformedRSAKeyPairImpl_internal(key); requires WellformedFatNat(ciphertext); requires 0 < J(ciphertext) < J(key.pub.n); ensures WellformedFatNat(plaintext); ensures J(plaintext) < J(key.pub.n); ensures DecryptionRelation(key, ciphertext, plaintext); { plaintext := FatNatModExpUsingReciprocal(ciphertext, key.d, key.pub.n, key.pub.nReciprocal); } static lemma lemma_about_PKCS15_PaddingRelationWith(padded_msg:seq, msg:seq, pad_mode:PadMode, padding:seq) requires IsByteSeq(padded_msg); requires IsByteSeq(msg); requires PKCS15_PaddingRelationWith(padded_msg, msg, pad_mode, padding); ensures padded_msg == [0] + [BlockType(pad_mode)] + padding + [0] + msg; { } static lemma lemma_PKCS15_EncryptionPad(msg:seq, k:nat, padding:seq) requires IsByteSeq(msg); requires IsByteSeq(padding); requires |padding| == k - 3 - |msg|; requires |padding| >= 8; requires NonzeroPad(padding); ensures PKCS15_EncryptionPad(msg, k, padding) == [0, BlockType(PadModeEncrypt())] + padding + [0] + msg; ensures IsByteSeq(PKCS15_EncryptionPad(msg, k, padding)); { lemma_2toX(); } static lemma lemma_PKCS15_SignaturePad(msg:seq, k:nat) requires IsByteSeq(msg); requires k - 3 - |msg| >= 8; ensures PKCS15_SignaturePad(msg, k) == [0, BlockType(PadModeSign())] + RepeatDigit(SignaturePadByte(), k - 3 - |msg|) + [0] + msg; ensures IsByteSeq(PKCS15_SignaturePad(msg, k)); { lemma_2toX(); lemma_RepeatDigit_for_ByteSeq(SignaturePadByte(), k - 3 - |msg|); } static lemma lemma_obvious_concatenation(x:int, y:int) ensures [x] + [y] == [x,y]; { } static lemma lemma_obvious_length(x:seq, y:seq, z:seq) requires x == y + z; ensures |x| == |y| + |z|; { } static predicate RSASignatureRequires(key: RSAKeyPairSpec, message: seq) { WellformedRSAKeyPairSpec(key) && IsByteSeq(message) && IsBitSeq(BEByteSeqToBitSeq_premium(message)) && |BEByteSeqToBitSeq_premium( message)| < power2(64) && IsWordSeq(SHA256(BEByteSeqToBitSeq_premium(message))) && IsByteSeq(SHA256Digest(message)) && PadCount(SHA256Digest(message), key.pub.size) >= 8 && IsByteSeq(PKCS15_SignaturePad(SHA256Digest(message), key.pub.size)) } static lemma lemma_RSA_message_length_bound(message:seq) requires IsByteSeq(message); requires |message| < power2(28); ensures IsByteSeq(SHA256_DigestInfo_premium() + message); ensures |BEByteSeqToBitSeq_premium(SHA256_DigestInfo_premium() + message)| < power2(64); { calc { |SHA256_DigestInfo() + message|; 19 + |message|; < 19 + power2(28); < { lemma_2toX(); lemma_power2_add8(24); lemma_power2_add8(56); } power2(61); } //- Drop a hint to Dafny that IsByteSeq extends across seq addition: assert IsByteSeq(SHA256_DigestInfo_premium() + message); calc { |BEByteSeqToBitSeq_premium(SHA256_DigestInfo() + message)|; 8*|SHA256_DigestInfo() + message|; < 8*power2(61); { lemma_2toX(); lemma_power2_add8(56); } power2(64); } } static function method RSA_DIGEST_MIN_KEY_SIZE() : int { 62 } static predicate RSAVerificationRelationRequires(pubkey:RSAPubKeySpec, message:seq, signature:seq) { //- NB we premium-ify methods to trigger corresponding ensures IsByteSeq(signature) && IsByteSeq(message) && IsBitSeq(BEByteSeqToBitSeq_premium(message)) && |BEByteSeqToBitSeq_premium(message)| < power2(64) && IsWordSeq(SHA256(BEByteSeqToBitSeq_premium(message))) && IsByteSeq(SHA256Digest(message)) && PadCount(SHA256Digest(message), pubkey.size) >= 8 && IsByteSeq(PKCS15_SignaturePad(SHA256Digest(message), pubkey.size)) } method {:timeLimitMultiplier 3} DigestedVerifyCommonCase(pubkey:RSAPubKeyImpl_internal, message:seq, signature:seq, signatureN:array) returns (verifies:bool) requires WellformedRSAPubKeyImpl_internal(pubkey); requires RSA_DIGEST_MIN_KEY_SIZE() <= pubkey.size < power2(60); requires RSAVerificationRelationRequires(PubKeyImplToSpec_internal(pubkey), message, signature); requires |message| < power2(28); requires |signature| == pubkey.size; requires WellformedRSAPubKeySpec(PubKeyImplToSpec_internal(pubkey)); requires signatureN != null; requires IsWordSeq(signatureN[..]); requires BEWordSeqToInt(signatureN[..]) == BEByteSeqToInt(signature); requires |signature| == pubkey.size; requires BEWordSeqToInt(signatureN[..]) != 0; requires J(signatureN) < J(pubkey.n); requires TPM_ready(); modifies this`TPM; modifies this`IoMemPerm; ensures TPM_ready(); ensures TPM==old(TPM); ensures IoMemPerm==old(IoMemPerm); ensures WellformedRSAPubKeySpec(PubKeyImplToSpec_internal(pubkey)); ensures verifies <==> RSAVerificationRelation(PubKeyImplToSpec_internal(pubkey), message, signature); { var nref := pubkey.n; //- do something real to pubkey.n so dafnycc knows it's allocated var eref := pubkey.e; //- do something real to pubkey.e so dafnycc knows it's allocated var recip_ref := if pubkey.nReciprocal.FNDivKnownReciprocal? then pubkey.nReciprocal.TwoTo32wDividedByD else pubkey.n; //- dafnycc lemma_2toX32(); var digested_message := SHA256DigestImpl(message); var padded_message_raw := PadMessage(digested_message, pubkey.size, PadModeSign()); var padded_message := padded_message_raw; var padded_message_array := SeqToArray(padded_message); var padded_messageN := BEByteArrayToWordArray(padded_message_array); assert 0 < J(signatureN) < J(pubkey.n); var putative_padded_messageN := InnerEncrypt(pubkey, signatureN); verifies := FatNatEq(padded_messageN, putative_padded_messageN); lemma_RSA_message_length_bound(message); } method DigestedVerify_internal(pubkey:RSAPubKeyImpl_internal, message:seq, signature:seq) returns (verifies:bool) requires WellformedRSAPubKeyImpl_internal(pubkey); requires RSA_DIGEST_MIN_KEY_SIZE() <= pubkey.size < power2(60); requires IsByteSeq(message); //- requires |message| < power2(61); requires |message| < power2(28); requires IsByteSeq(signature); requires |signature| == pubkey.size; //- requires signature[0] == 0; requires TPM_ready(); modifies this`TPM; modifies this`IoMemPerm; ensures TPM_ready(); ensures TPM==old(TPM); ensures IoMemPerm==old(IoMemPerm); ensures WellformedRSAPubKeySpec(PubKeyImplToSpec_internal(pubkey)); ensures verifies <==> ( RSAVerificationRelationRequires(PubKeyImplToSpec_internal(pubkey), message, signature) && RSAVerificationRelation(PubKeyImplToSpec_internal(pubkey), message, signature)); { var nref := pubkey.n; //- do something real to pubkey.n so dafnycc knows it's allocated var eref := pubkey.e; //- do something real to pubkey.e so dafnycc knows it's allocated var recip_ref := if pubkey.nReciprocal.FNDivKnownReciprocal? then pubkey.nReciprocal.TwoTo32wDividedByD else pubkey.n; //- dafnycc lemma_WellformedPubKeyImplImpliesWellformedPubKeySpec(pubkey); var signature_array := SeqToArray(signature); var signatureN := BEByteArrayToWordArray(signature_array); var zerosig := FatNatIsZero(signatureN); if (|signature|!=pubkey.size || zerosig) { assert BEByteSeqToInt(signature)==0; verifies := false; return; } lemma_2toX32(); calc { |BEByteSeqToBitSeq_premium(message)|; |message|*8; <= power2(28)*8; { lemma_mul_is_mul_boogie(power2(28), 8); } power2(28)*power2(3); { lemma_power2_adds(28,3); } power2(31); } lemma_power2_strictly_increases(31,61); lemma_power2_strictly_increases(31,64); lemma_PKCS15_SignaturePad(SHA256Digest_premium(message), pubkey.size); var sig_short_enough := FatNatLt(signatureN, pubkey.n); if (!sig_short_enough) { assert !(BEByteSeqToInt(signature) < PubKeyImplToSpec_internal(pubkey).n); assert !RSAVerificationRelation(PubKeyImplToSpec_internal(pubkey), message, signature); verifies := false; return; } verifies := DigestedVerifyCommonCase(pubkey, message, signature, signatureN); } //-lemma lemma_message_transmission(key:RSAKeyPairImpl_internal, p_in:BigNat, c:BigNat, p_out:BigNat) //- requires WellformedRSAKeyPairImpl_internal(key); //- requires WellformedBigNat(p_in); //- requires WellformedBigNat(c); //- requires WellformedBigNat(p_out); //- requires I(p_in) < I(key.pub.n); //- requires I(c) < I(key.pub.n); //- requires I(p_out) < I(key.pub.n); //- requires EncryptionRelation(key.pub, p_in, c); //- requires DecryptionRelation(key, c, p_out); //- ensures p_in == p_out; // // // ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Crypto/RSA/RSAPublicWrapper.i.dfy ================================================ //- include "RSASpec.s.dfy" include "KeyImpl.i.dfy" include "RSA.i.dfy" include "RSAOps.i.dfy" include "RSADigestedSign.i.dfy" include "RSA_Decrypt.i.dfy" include "rfc4251impl.i.dfy" include "rfc4251decode.i.dfy" include "../../BigNum/BigNum.i.dfy" datatype RSAPubKeyImpl = RSAPubKeyImpl_c( n:BigNat, //- modulus size:nat, e:BigNat //- public key exponent ); predicate WellformedRSAPubKeyImpl(pub:RSAPubKeyImpl) { true && WellformedBigNat(pub.n) && WellformedBigNat(pub.e) && 0rc; { rc := IsModestBigNat(x); } //-//////////////////////////////////////////////////////////////////////////// method RSAPubKeyFromInternal(pi:RSAPubKeyImpl_internal) returns (pub:RSAPubKeyImpl) requires WellformedRSAPubKeyImpl_internal(pi); ensures WellformedRSAPubKeyImpl(pub); ensures pi.size == pub.size; ensures J(pi.n) == I(pub.n); ensures J(pi.e) == I(pub.e); { var nref := pi.n; //- do something real to pi.n so dafnycc knows it's allocated var eref := pi.e; //- do something real to pi.e so dafnycc knows it's allocated var recip_ref := if pi.nReciprocal.FNDivKnownReciprocal? then pi.nReciprocal.TwoTo32wDividedByD else pi.n; //- do something real to reciprocal for dafnycc var fn := FatNatToBigNat(pi.n); var fe := FatNatToBigNat(pi.e); pub := RSAPubKeyImpl_c(fn, pi.size, fe); } method RSAKeyPairFromInternal(kpi:RSAKeyPairImpl_internal) returns (kp:RSAKeyPairImpl) requires WellformedRSAKeyPairImpl_internal(kpi); ensures WellformedRSAKeyPairImpl(kp); ensures kpi.pub.size == kp.pub.size; ensures J(kpi.pub.n) == I(kp.pub.n); ensures J(kpi.pub.e) == I(kp.pub.e); ensures J(kpi.d) == I(kp.d); { var nref := kpi.pub.n; //- do something real to kpi.pub.n so dafnycc knows it's allocated var eref := kpi.pub.e; //- do something real to kpi.pub.e so dafnycc knows it's allocated var dref := kpi.d; //- do something real to kpi.d so dafnycc knows it's allocated var recip_ref := if kpi.pub.nReciprocal.FNDivKnownReciprocal? then kpi.pub.nReciprocal.TwoTo32wDividedByD else kpi.pub.n; //- do something real to reciprocal for dafnycc var pub := RSAPubKeyFromInternal(kpi.pub); var fd := FatNatToBigNat(kpi.d); kp := RSAKeyPairImpl_c(pub, fd); assert I(kp.pub.n) == J(kpi.pub.n); //- OBSERVE } method RSAInternalFromPubKey(pub:RSAPubKeyImpl) returns (pi:RSAPubKeyImpl_internal) requires WellformedRSAPubKeyImpl(pub); ensures WellformedRSAPubKeyImpl_internal(pi); ensures pi.size == pub.size; ensures J(pi.n) == I(pub.n); ensures J(pi.e) == I(pub.e); ensures PubKeyImplToSpec_internal(pi) == PubKeyImplToSpec(pub); { var bn := BigNatToFatNat(pub.n); var be := BigNatToFatNat(pub.e); var nReciprocal := FatNatComputeReciprocal(bn); var nReciprocal_ref := nReciprocal.TwoTo32wDividedByD; //- reference this array for DafnyCC's sake pi := RSAPubKeyImpl_c_internal(bn, pub.size, be, nReciprocal); } method RSAInternalFromKeyPair(kp:RSAKeyPairImpl) returns (kpi:RSAKeyPairImpl_internal) requires WellformedRSAKeyPairImpl(kp); ensures WellformedRSAKeyPairImpl_internal(kpi); ensures kpi.pub.size == kp.pub.size; ensures J(kpi.pub.n) == I(kp.pub.n); ensures J(kpi.pub.e) == I(kp.pub.e); ensures J(kpi.d) == I(kp.d); { var pi := RSAInternalFromPubKey(kp.pub); var nref := pi.n; //- do something real to pi.n so dafnycc knows it's allocated var eref := pi.e; //- do something real to pi.e so dafnycc knows it's allocated var recip_ref := if pi.nReciprocal.FNDivKnownReciprocal? then pi.nReciprocal.TwoTo32wDividedByD else pi.n; //- do something real to reciprocal for dafnycc var bd := BigNatToFatNat(kp.d); kpi := RSAKeyPairImpl_c_internal(pi, bd); assert J(pi.n) == I(kp.pub.n); assert J(pi.e) == I(kp.pub.e); } //-//////////////////////////////////////////////////////////////////////////// method GenDummyKey() returns (key_pair:RSAKeyPairImpl) { var zilch := MakeSmallLiteralBigNat(0); key_pair := RSAKeyPairImpl_c(RSAPubKeyImpl_c(zilch, 0, zilch), zilch); } function KV(X:BigNat) : int requires WellformedBigNat(X); { I(X) } method RSAKeyGen(keybits:nat) returns (key:RSAKeyPairImpl) requires 20= power2(keybits); ensures key.pub.size >= keybits / 8; ensures RSAKeyGenerationValid(keybits, KeyPairImplToSpec(key), TPM_random_bytes_premium(old(TPM).random_index, TPM.random_index)); { var kpi := RSAKeyGen_internal(keybits); var nref := kpi.pub.n; //- do something real to kpi.pub.n so dafnycc knows it's allocated var eref := kpi.pub.e; //- do something real to kpi.pub.e so dafnycc knows it's allocated var dref := kpi.d; //- do something real to kpi.d so dafnycc knows it's allocated var recip_ref := if kpi.pub.nReciprocal.FNDivKnownReciprocal? then kpi.pub.nReciprocal.TwoTo32wDividedByD else kpi.pub.n; //- do something real to reciprocal for dafnycc key := RSAKeyPairFromInternal(kpi); assert KeyPairImplToSpec(key)==KeyPairImplToSpec_internal(kpi); assert RSAKeyGenerationValid(keybits, KeyPairImplToSpec(key), TPM_random_bytes_premium(old(TPM).random_index, TPM.random_index)); calc { KV(key.pub.n); J(kpi.pub.n); >= power2(keybits); } } method rfc4251_encode_sshrsa_pubkey(pubkey:RSAPubKeyImpl) returns (msg:seq) requires ModestKeyValue(pubkey.e); requires ModestKeyValue(pubkey.n); requires WellformedRSAPubKeyImpl(pubkey); ensures IsByteSeq(msg); ensures PubKeyImplToSpec(pubkey).e < power2(power2(34)); ensures PubKeyImplToSpec(pubkey).n < power2(power2(34)); ensures msg == rfc4251_sshrsa_pubkey_encoding_premium(PubKeyImplToSpec(pubkey)); { var kpi := RSAInternalFromPubKey(pubkey); var nref := kpi.n; //- do something real to kpi.n so dafnycc knows it's allocated var eref := kpi.e; //- do something real to kpi.e so dafnycc knows it's allocated var recip_ref := if kpi.nReciprocal.FNDivKnownReciprocal? then kpi.nReciprocal.TwoTo32wDividedByD else kpi.n; //- do something real to reciprocal for dafnycc msg := rfc4251_encode_sshrsa_pubkey_internal(kpi); } method rfc4251_decode_sshrsa(msg:seq) returns (success:bool, pubkey:RSAPubKeyImpl) requires IsByteSeq(msg); requires Word32(|msg|); requires public(msg); ensures WellformedRSAPubKeyImpl(pubkey); ensures success ==> PubKeyImplToSpec(pubkey).e < power2(power2(34)); ensures success ==> PubKeyImplToSpec(pubkey).n < power2(power2(34)); ensures success ==> (msg == rfc4251_sshrsa_pubkey_encoding_premium(PubKeyImplToSpec(pubkey))); ensures public(success); ensures public(pubkey.size); ensures public(KV(pubkey.n)); ensures public(KV(pubkey.e)); { var pi; success,pi := rfc4251_decode_sshrsa_internal(msg); var nref := pi.n; //- do something real to pi.n so dafnycc knows it's allocated var eref := pi.e; //- do something real to pi.e so dafnycc knows it's allocated var recip_ref := if pi.nReciprocal.FNDivKnownReciprocal? then pi.nReciprocal.TwoTo32wDividedByD else pi.n; //- do something real to reciprocal for dafnycc pubkey := RSAPubKeyFromInternal(pi); assert PubKeyImplToSpec(pubkey) == PubKeyImplToSpec_internal(pi); } method rfc4251_encode_mpint_legacy(V:BigNat) returns (msg:seq) requires ModestBigNatValue(V); ensures KV(V) < power2(power2(34)); ensures IsByteSeq(msg); ensures msg == rfc4251_mpint_encoding_premium(KV(V)); { var vfn := BigNatToFatNat(V); msg := rfc4251_encode_mpint(vfn); } method rfc4251_decode_mpint_legacy(msg:seq) returns (success:bool,V:BigNat,bytes_consumed:int) requires IsByteSeq(msg); requires public(msg); ensures ModestKeyValue(V); ensures I(V) < power2(power2(34)); ensures 0 <= bytes_consumed <= |msg|; ensures success ==> (msg[..bytes_consumed] == rfc4251_mpint_encoding_premium(KV(V))); ensures public(success); ensures public(I(V)); ensures public(bytes_consumed); { var vfn; success,vfn,bytes_consumed := rfc4251_decode_mpint(msg); V := FatNatToBigNat(vfn); } method Decrypt(key:RSAKeyPairImpl, ciphertext:seq) returns (result:bool, plaintext:seq) requires WellformedRSAKeyPairImpl(key); requires IsByteSeq(ciphertext); requires |ciphertext|>0; //- requires |ciphertext|%4==0; ensures WellformedRSAKeyPairSpec(KeyPairImplToSpec(key)); ensures result ==> (IsByteSeq(plaintext) && RSADecryptionRelation(KeyPairImplToSpec(key), ciphertext, plaintext)); ensures !result ==> forall any_plaintext :: !(IsByteSeq(any_plaintext) && RSADecryptionRelation(KeyPairImplToSpec(key), ciphertext, any_plaintext)); { var kpi := RSAInternalFromKeyPair(key); var nref := kpi.pub.n; //- do something real to kpi.pub.n so dafnycc knows it's allocated var eref := kpi.pub.e; //- do something real to kpi.pub.e so dafnycc knows it's allocated var dref := kpi.d; //- do something real to kpi.d so dafnycc knows it's allocated var recip_ref := if kpi.pub.nReciprocal.FNDivKnownReciprocal? then kpi.pub.nReciprocal.TwoTo32wDividedByD else kpi.pub.n; //- do something real to reciprocal for dafnycc result,plaintext := Decrypt_internal(kpi, ciphertext); } method Encrypt(pubkey:RSAPubKeyImpl, plaintext:seq) returns (ciphertext:seq) requires IsByteSeq(plaintext); requires WellformedRSAPubKeyImpl(pubkey); requires |plaintext| <= pubkey.size - 11; requires TPM_ready(); modifies this`TPM; modifies this`IoMemPerm; ensures TPM_ready(); ensures WellformedRSAPubKeySpec(PubKeyImplToSpec(pubkey)); ensures IsByteSeq(ciphertext); ensures exists padding:seq :: RSAEncryptionRequires(PubKeyImplToSpec(pubkey), plaintext, padding) && RSAEncryption(PubKeyImplToSpec(pubkey), plaintext, padding) == ciphertext; { var pi := RSAInternalFromPubKey(pubkey); var nref := pi.n; //- do something real to pi.n so dafnycc knows it's allocated var eref := pi.e; //- do something real to pi.e so dafnycc knows it's allocated var recip_ref := if pi.nReciprocal.FNDivKnownReciprocal? then pi.nReciprocal.TwoTo32wDividedByD else pi.n; //- do something real to reciprocal for dafnycc ciphertext := Encrypt_internal(pi, plaintext); } method DigestedSign(key:RSAKeyPairImpl, message:seq) returns (signature:seq) requires WellformedRSAKeyPairImpl(key); requires IsByteSeq(message); requires |message| < power2(28); requires RSA_DIGEST_MIN_KEY_SIZE() <= key.pub.size; requires TPM_ready(); modifies this`TPM; modifies this`IoMemPerm; ensures TPM_ready(); ensures TPM==old(TPM); ensures IoMemPerm==old(IoMemPerm); ensures RSASignatureRequires(KeyPairImplToSpec(key), message); ensures IsByteSeq(signature); ensures RSASignature(KeyPairImplToSpec(key), message) == signature; ensures |signature|, signature:seq) returns (verifies:bool) requires WellformedRSAPubKeyImpl(pubkey); requires RSA_DIGEST_MIN_KEY_SIZE() <= pubkey.size < power2(60); requires IsByteSeq(message); //- requires |message| < power2(61); requires |message| < power2(28); requires IsByteSeq(signature); requires |signature| == pubkey.size; //- requires signature[0] == 0; requires TPM_ready(); modifies this`TPM; modifies this`IoMemPerm; ensures TPM_ready(); ensures TPM==old(TPM); ensures IoMemPerm==old(IoMemPerm); ensures WellformedRSAPubKeySpec(PubKeyImplToSpec(pubkey)); ensures verifies <==> ( RSAVerificationRelationRequires(PubKeyImplToSpec(pubkey), message, signature) && RSAVerificationRelation(PubKeyImplToSpec(pubkey), message, signature)); { var pi := RSAInternalFromPubKey(pubkey); var nref := pi.n; //- do something real to pi.n so dafnycc knows it's allocated var eref := pi.e; //- do something real to pi.e so dafnycc knows it's allocated var recip_ref := if pi.nReciprocal.FNDivKnownReciprocal? then pi.nReciprocal.TwoTo32wDividedByD else pi.n; //- do something real to reciprocal for dafnycc verifies := DigestedVerify_internal(pi, message, signature); } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Crypto/RSA/RSASpec.s.dfy ================================================ include "../Hash/Digest.s.dfy" include "../../Math/power.s.dfy" include "MillerRabin.s.dfy" include "../../Math/GCD.s.dfy" include "KeyGen.s.dfy" datatype PadMode = PadModeEncrypt() | PadModeSign(); static function method BlockType(pad_mode:PadMode) : int { if (pad_mode.PadModeSign?) then 1 else 2 } static function method SignaturePadByte() : int { 0xff } static predicate PaddedMessageStartIndex(padded_msg:seq, i:nat, pad_mode:PadMode, padding:seq) { IsByteSeq(padded_msg) && 0 < i <= |padded_msg| && 2 <= |padded_msg| && IsByteSeq(padding) && (forall j :: 0 <= j < |padding| ==> padding[j]!=0) && padded_msg[0]==0 && padded_msg[1]==BlockType(pad_mode) && 2, msg:seq, pad_mode:PadMode, padding:seq) requires IsByteSeq(padded_msg); requires IsByteSeq(msg); { |padding| >= 8 && PaddedMessageStartIndex(padded_msg, |padding|+3, pad_mode, padding) && padded_msg[|padding|+3..] == msg } static predicate PKCS15_PaddingRelation(padded_msg:seq, msg:seq, pad_mode:PadMode) requires IsByteSeq(padded_msg); requires IsByteSeq(msg); { exists padding:seq :: PKCS15_PaddingRelationWith(padded_msg, msg, pad_mode, padding) } static function PadCount(msg:seq, k:nat) : int { k - 3 - |msg| } static predicate NonzeroPad(padding:seq) { forall i :: 0 <= i < |padding| ==> padding[i] != 0 } static function PKCS15_EncryptionPad(msg:seq, k:nat, padding:seq) : seq requires IsByteSeq(msg); requires IsByteSeq(padding); requires |padding| == PadCount(msg, k); requires NonzeroPad(padding); requires PadCount(msg, k) >= 8; //- lemma proves PKCS15_PaddingRelation(PKCS15_EncryptionPad(msg), msg, PadModeEncrypt()) { [0, BlockType(PadModeEncrypt())] + padding + [0] + msg } static function PKCS15_SignaturePad(msg:seq, k:nat) : seq requires IsByteSeq(msg); requires PadCount(msg, k) >= 8; //- lemma proves PKCS15_PaddingRelation(PKCS15_SignaturePad(msg), msg, PadModeSign()) { [0, BlockType(PadModeSign())] + RepeatDigit(SignaturePadByte(), PadCount(msg,k)) + [0] + msg } datatype RSAPubKeySpec = RSAPublicKeySpec_c( n:nat, //- modulus size:nat, e:nat //- public key exponent ); static predicate KeyModulusMatchesSizeInBytes(n:nat, k:nat) { (k>0 ==> power2(8*(k-1)) <= n) && n < power2(8*k) } static predicate WellformedRSAPubKeySpec(pubkey:RSAPubKeySpec) { 0 < pubkey.n && KeyModulusMatchesSizeInBytes(pubkey.n, pubkey.size) } datatype RSAKeyPairSpec = RSAKeyPairSpec_c( pub:RSAPubKeySpec, d:nat //- private key exponent ); static predicate WellformedRSAKeyPairSpec(key:RSAKeyPairSpec) { WellformedRSAPubKeySpec(key.pub) } static function {:autoReq} RSAEncryption(pubkey:RSAPubKeySpec, msg:seq, padding:seq) : seq requires WellformedRSAPubKeySpec(pubkey); { var pad_msg := BEByteSeqToInt(PKCS15_EncryptionPad(msg, pubkey.size, padding)); BEIntToByteSeq(power(pad_msg, pubkey.e) % pubkey.n) } //- predicate form is appropriate here, where we don't actually know //- the value of the padding (and can't, until it's decrypted!) static predicate {:autoReq} RSADecryptionRelation(key:RSAKeyPairSpec, ciphertext:seq, msg:seq) { var cipher_n := BEByteSeqToInt(ciphertext); WellformedRSAKeyPairSpec(key) && cipher_n < key.pub.n //- Decrypter MUST ignore aliased ciphertexts. && exists padding:seq :: ( var padded_msg_n := BEByteSeqToInt(PKCS15_EncryptionPad(msg, key.pub.size, padding)); power(cipher_n, key.d) % key.pub.n == padded_msg_n) } static function {:autoReq} RSASignature(key:RSAKeyPairSpec, message:seq) : seq requires WellformedRSAKeyPairSpec(key); { var padded_nint := BEByteSeqToInt(PKCS15_SignaturePad(SHA256Digest(message), key.pub.size)); BEIntToDigitSeq(power2(8), key.pub.size, power(padded_nint, key.d) % key.pub.n) } //- predicate form is appropriate here, because that's the actual output. static predicate {:autoReq} RSAVerificationRelation(pubkey:RSAPubKeySpec, message:seq, signature:seq) { var sig_n := BEByteSeqToInt(signature); var padded_msg_n := BEByteSeqToInt(PKCS15_SignaturePad(SHA256Digest(message), pubkey.size)); WellformedRSAPubKeySpec(pubkey) && sig_n != 0 && |signature| == pubkey.size && sig_n < pubkey.n //- disallow "alias" signatures (sig_n + k * pubkey.n) && power(sig_n, pubkey.e) % pubkey.n == padded_msg_n } //-//////////////////////////////////////////////////////////////////////////// //------------------------------------------------------------// datatype RSAKeyGenerationWorksheetRow = RSAKeyGenerationWorksheetRow_c( P:PrimeGenerationWorksheet, Q:PrimeGenerationWorksheet, accepted:bool, randoms:seq); static function RSA_public_exponent() : int { 65537 } static predicate {:autoReq} RSAKeyAccepted(row:RSAKeyGenerationWorksheetRow) { var phi_n := (PrimeGenerationOutput(row.P)-1) * (PrimeGenerationOutput(row.Q)-1); if (phi_n < 0) then false //- case shouldn't occur, but don't want to prove that here. else is_gcd(phi_n, RSA_public_exponent(), 1) } static predicate {:autoReq} RSAKeyGenerationWorksheetRowValid(keybits:int, row:RSAKeyGenerationWorksheetRow) { var halfbits := keybits/2 + 2; PrimeGenerationWorksheetValid(halfbits, row.P) && PrimeGenerationWorksheetValid(halfbits, row.Q) && row.accepted == RSAKeyAccepted(row) && row.randoms == row.P.randoms + row.Q.randoms } //------------------------------------------------------------// datatype RSAKeyGenerationWorksheet = RSAKeyGenerationWorksheet_c( keybits:int, rows:seq, randoms:seq, p:int, q:int, phi:int, n:int ); static function RSAKeyGenerationWorksheetConsumesRandoms(rows:seq) : seq { if (rows==[]) then [] else RSAKeyGenerationWorksheetConsumesRandoms(rows[..|rows|-1]) + rows[|rows|-1].randoms } static predicate RSAKeyGenerationWorksheetSummaryValid(worksheet:RSAKeyGenerationWorksheet) requires 0 < |worksheet.rows|; { var final := worksheet.rows[|worksheet.rows|-1]; worksheet.rows[|worksheet.rows|-1].accepted && 0 < |final.P.rows| && worksheet.p == PrimeGenerationOutput(final.P) && 0 < |final.Q.rows| && worksheet.q == PrimeGenerationOutput(final.Q) && worksheet.phi == (worksheet.p-1)*(worksheet.q-1) && worksheet.phi != 0 && worksheet.n == worksheet.p*worksheet.q } static predicate {:autoReq} RSAKeyGenerationWorksheetValid(keybits:int, worksheet:RSAKeyGenerationWorksheet) { worksheet.keybits == keybits && (forall i :: 0 <= i < |worksheet.rows| ==> RSAKeyGenerationWorksheetRowValid(worksheet.keybits, worksheet.rows[i])) && (forall i :: 0 <= i < |worksheet.rows|-1 ==> !worksheet.rows[i].accepted) && RSAKeyGenerationWorksheetConsumesRandoms(worksheet.rows) == worksheet.randoms && 0<|worksheet.rows| && RSAKeyGenerationWorksheetSummaryValid(worksheet) } static predicate {:autoReq} RSAKeyConsistentWithWorksheet(requested_keybits:int, key:RSAKeyPairSpec, worksheet:RSAKeyGenerationWorksheet) { WellformedRSAKeyPairSpec(key) && RSAKeyGenerationWorksheetValid(requested_keybits, worksheet) && key.pub.n == worksheet.p * worksheet.q && key.pub.e == RSA_public_exponent() && key.pub.size >= requested_keybits / 8 && (key.d * key.pub.e) % worksheet.phi == 1 } static predicate {:autoReq} RSAKeyGenerationValid(requested_keybits:int, key:RSAKeyPairSpec, randoms:seq) { exists worksheet:RSAKeyGenerationWorksheet :: RSAKeyConsistentWithWorksheet(requested_keybits, key, worksheet) && worksheet.randoms == randoms } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Crypto/RSA/RSA_Decrypt.i.dfy ================================================ include "RSASpec.s.dfy" include "../Hash/Digest.i.dfy" include "../../BigNum/BigNum.i.dfy" include "../../BigNum/BigNatDiv.i.dfy" include "../../BigNum/BigNatMod.i.dfy" include "KeyGen.i.dfy" include "BlockEncoding.i.dfy" include "KeyImpl.i.dfy" include "RSA.i.dfy" include "RSAOps.i.dfy" static function PKCS15_EncryptionPad_premium(msg:seq, k:nat, padding:seq) : seq requires IsByteSeq(msg); requires IsByteSeq(padding); requires |padding| == PadCount(msg, k); requires NonzeroPad(padding); requires PadCount(msg, k) >= 8; ensures IsByteSeq(PKCS15_EncryptionPad_premium(msg, k, padding)); { lemma_PKCS15_EncryptionPad(msg, k, padding); PKCS15_EncryptionPad(msg, k, padding) } lemma lemma_zero_ciphertexts_do_not_decrypt(key:RSAKeyPairImpl_internal, ciphertext:seq, cipherN:array) requires WellformedRSAKeyPairImpl_internal(key); requires IsByteSeq(ciphertext); requires |ciphertext|>0; requires WellformedFatNat(cipherN); requires J(cipherN) == BEByteSeqToInt(ciphertext); requires J(cipherN)==0; ensures forall any_plaintext :: !RSADecryptionRelation(KeyPairImplToSpec_internal(key), ciphertext, any_plaintext); { forall (any_plaintext | IsByteSeq(any_plaintext)) ensures !RSADecryptionRelation(KeyPairImplToSpec_internal(key), ciphertext, any_plaintext); { forall (padding | IsByteSeq(padding) && |padding| == PadCount(any_plaintext, key.pub.size) && NonzeroPad(padding) && PadCount(any_plaintext, key.pub.size) >= 8) ensures var padded_msg_n := BEByteSeqToInt(PKCS15_EncryptionPad_premium(any_plaintext, key.pub.size, padding)); power(J(cipherN), J(key.d)) % J(key.pub.n) != padded_msg_n; { var padded_msg := PKCS15_EncryptionPad_premium(any_plaintext, key.pub.size, padding); var padtail := padded_msg[1..]; assert padtail[0]==2; var padded_msg_n := BEByteSeqToInt(padded_msg); var L0 := 0; var L1 := 1; assert J(cipherN) == 0; if (J(key.d)==0) { //- This case isn't really meaningful, but our spec doesn't currently disallow it. calc { power(J(cipherN), J(key.d)) % J(key.pub.n); { reveal_power(); } L1 % J(key.pub.n); <= { lemma_mod_decreases(L1, J(key.pub.n)); } 1; } } else { calc { power(J(cipherN), J(key.d)) % J(key.pub.n); { lemma_0_power(J(key.d)); } L0 % J(key.pub.n); { lemma_small_mod(L0, J(key.pub.n)); } L0; 0; } } calc { power(J(cipherN), J(key.d)) % J(key.pub.n); < 2; { lemma_mul_is_mul_boogie(1, 2); } mul(1, 2); <= { lemma_power_positive(power2(8), |padtail|-1); lemma_mul_inequality_forall(); } mul(power(power2(8), |padtail|-1), 2); { lemma_mul_is_commutative_forall(); } mul(2, power(power2(8), |padtail|-1)); <= { lemma_BEDigitSeqToInt_bound(power2(8), padtail); } BEByteSeqToInt(padtail); { lemma_LeadingZeros(power2(8), padtail, padded_msg); } BEByteSeqToInt(padded_msg); padded_msg_n; } } } } lemma lemma_mispadded_plaintexts_do_not_decrypt(key:RSAKeyPairImpl_internal, ciphertext:seq, cipherN:array, plainN:array) requires WellformedRSAKeyPairImpl_internal(key); requires IsByteSeq(ciphertext); requires |ciphertext|>0; requires WellformedFatNat(cipherN); requires WellformedFatNat(plainN); requires J(cipherN) == BEByteSeqToInt(ciphertext); requires J(plainN)==power(J(cipherN),J(key.d)) % J(key.pub.n); requires !CanDecodeFatInteger(plainN, key.pub.size, PadModeEncrypt()); ensures forall any_plaintext :: !RSADecryptionRelation(KeyPairImplToSpec_internal(key), ciphertext, any_plaintext); { forall (any_plaintext | IsByteSeq(any_plaintext)) ensures !RSADecryptionRelation(KeyPairImplToSpec_internal(key), ciphertext, any_plaintext); { forall (padding | IsByteSeq(padding) && |padding| == PadCount(any_plaintext, key.pub.size) && NonzeroPad(padding) && PadCount(any_plaintext, key.pub.size) >= 8) ensures var padded_msg_n := BEByteSeqToInt(PKCS15_EncryptionPad_premium(any_plaintext, key.pub.size, padding)); power(J(cipherN), J(key.d)) % J(key.pub.n) != padded_msg_n; { var pm := PKCS15_EncryptionPad_premium(any_plaintext, key.pub.size, padding); assert !IsByteSeq(pm) || !IsByteSeq(any_plaintext) || !PKCS15_PaddingRelation(pm, any_plaintext, PadModeEncrypt()) || !(BigEndianIntegerValue(pm)==J(plainN)) || !(|pm|==key.pub.size); //- OBSERVE var padded_msg_n := BEByteSeqToInt(PKCS15_EncryptionPad_premium(any_plaintext, key.pub.size, padding)); if (power(J(cipherN), J(key.d)) % J(key.pub.n) == padded_msg_n) { lemma_BigEndianIntegerValue_equals_BEByteSeqToInt(pm); assert !PKCS15_PaddingRelationWith(pm, any_plaintext, PadModeEncrypt(), padding); //- OBSERVE //- assert false; //- This is a contradiction. } } } } method{:dafnycc_conservative_seq_triggers} Decrypt_internal(key:RSAKeyPairImpl_internal, ciphertext:seq) returns (result:bool, plaintext:seq) requires WellformedRSAKeyPairImpl_internal(key); requires IsByteSeq(ciphertext); requires |ciphertext|>0; //- requires |ciphertext|%4==0; ensures WellformedRSAKeyPairSpec(KeyPairImplToSpec_internal(key)); ensures result ==> (IsByteSeq(plaintext) && RSADecryptionRelation(KeyPairImplToSpec_internal(key), ciphertext, plaintext)); ensures !result ==> forall any_plaintext :: !(IsByteSeq(any_plaintext) && RSADecryptionRelation(KeyPairImplToSpec_internal(key), ciphertext, any_plaintext)); { var nref := key.pub.n; //- do something real to key.pub.n so dafnycc knows it's allocated var eref := key.pub.e; //- do something real to key.pub.e so dafnycc knows it's allocated var dref := key.d; //- do something real to key.d so dafnycc knows it's allocated var recip_ref := if key.pub.nReciprocal.FNDivKnownReciprocal? then key.pub.nReciprocal.TwoTo32wDividedByD else key.pub.n; //- dafnycc var plaintext_raw := []; plaintext := []; //- dafnycc: initialize variable var cipherN:array := BESeqToInteger(ciphertext); assert WellformedFatNat(cipherN); var ciphertext_too_big:bool := FatNatGe(cipherN, key.pub.n); var cipherZero := FatNatIsZero(cipherN); if (cipherZero) { lemma_zero_ciphertexts_do_not_decrypt(key, ciphertext, cipherN); result := false; } else if (ciphertext_too_big) { //- basic condition of spec forall (any_plaintext | IsByteSeq(any_plaintext)) ensures !RSADecryptionRelation(KeyPairImplToSpec_internal(key), ciphertext, any_plaintext); { } result := false; } else { assert J(cipherN) < J(key.pub.n); //- we just checked. var plainN:array := InnerDecrypt(key, cipherN); ghost var padded_plaintext:seq; var success:bool; success,plaintext_raw,padded_plaintext := IntegerToMessage(plainN, key.pub.size, PadModeEncrypt()); if (!success) { lemma_mispadded_plaintexts_do_not_decrypt(key, ciphertext, cipherN, plainN); result := false; } else { result := true; plaintext := DecryptCommonCase(KeyPairImplToSpec_internal(key), ciphertext, J(cipherN), J(plainN), plaintext_raw, padded_plaintext); assert 0, ghost cipherN:int, ghost plainN:int, plaintext_raw:seq, ghost padded_plaintext:seq) returns (plaintext:seq) requires WellformedRSAKeyPairSpec(key); requires IsByteSeq(ciphertext); requires |ciphertext|>0; requires 0 < cipherN < key.pub.n; requires cipherN == BigEndianIntegerValue(ciphertext); requires 0 <= plainN < key.pub.n; requires plainN == power(cipherN, key.d) % key.pub.n; requires IsByteSeq(plaintext_raw); requires IsByteSeq(padded_plaintext); requires PKCS15_PaddingRelation(padded_plaintext, plaintext_raw, PadModeEncrypt()); requires BigEndianIntegerValue(padded_plaintext) == plainN; requires |padded_plaintext| == key.pub.size; ensures IsByteSeq(plaintext); ensures RSADecryptionRelation(key, ciphertext, plaintext); { ghost var padding:seq :| PKCS15_PaddingRelationWith(padded_plaintext, plaintext_raw, PadModeEncrypt(), padding); lemma_about_PKCS15_PaddingRelationWith(padded_plaintext, plaintext_raw, PadModeEncrypt(), padding); assert padded_plaintext == [0] + [BlockType(PadModeEncrypt())] + padding + [0] + plaintext_raw; plaintext := plaintext_raw; assert IsByteSeq(padded_plaintext); calc { power(BigEndianIntegerValue(ciphertext), key.d) % key.pub.n; power(cipherN, key.d) % key.pub.n; plainN; BigEndianIntegerValue(padded_plaintext); } assert power(BigEndianIntegerValue(ciphertext), key.d) % key.pub.n == BigEndianIntegerValue(padded_plaintext); assert PKCS15_PaddingRelation(padded_plaintext, plaintext_raw, PadModeEncrypt()); //- proving RSADecryptionRelation(key, ciphertext, plaintext) ghost var padding_n := padding; ghost var ep := PKCS15_EncryptionPad(plaintext, key.pub.size, padding_n); lemma_PKCS15_EncryptionPad(plaintext, key.pub.size, padding_n); assert IsByteSeq(ep); ghost var cipher_n := BEByteSeqToInt(ciphertext); ghost var padded_msg_n := BEByteSeqToInt(ep); assert IsByteSeq(ep); calc { padded_plaintext; [0] + [BlockType(PadModeEncrypt())] + padding + [0] + plaintext_raw; [0] + [BlockType(PadModeEncrypt())] + padding_n + [0] + plaintext; { lemma_obvious_concatenation(0, BlockType(PadModeEncrypt())); } [0, BlockType(PadModeEncrypt())] + padding_n + [0] + plaintext; ep; } calc { cipher_n; BEByteSeqToInt(ciphertext); { lemma_BigEndianIntegerValue_equals_BEByteSeqToInt(ciphertext); } BigEndianIntegerValue(ciphertext); cipherN; } calc { power(cipher_n, key.d) % key.pub.n; power(cipherN, key.d) % key.pub.n; plainN; calc { plainN; BigEndianIntegerValue(padded_plaintext); { lemma_BigEndianIntegerValue_equals_BEByteSeqToInt(padded_plaintext); } BEByteSeqToInt(ep); padded_msg_n; } padded_msg_n; } assert power(cipher_n, key.d) % key.pub.n == padded_msg_n; assert RSADecryptionRelation(key, ciphertext, plaintext); } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Crypto/RSA/division.i.dfy ================================================ include "../../Math/div.i.dfy" include "../../Math/GCD.s.dfy" static lemma lemma_anything_divides_itself(a:nat) requires a != 0; ensures divides(a, a); { lemma_mod_properties(); assert a % a == 0; } static lemma lemma_anything_divides_zero(a:nat) requires a != 0; ensures divides(a, 0); { lemma_mod_is_mod_recursive_forall(); } static lemma lemma_nothing_bigger_divides(a:nat) requires 0 !divides(x,a); { forall (x | a { BEWordSeqToByteSeq([w]) } static function {:autoReq} rfc4251_string_encoding(s:seq) : seq //- NB caller responsible to check that the result IsByteSeq(). { rfc4251_word32_encoding(|s|) + s } //- RFC4251 allows for encoding negative numbers two's-complement, //- and thus mandates how we encode positive numbers that use the top bit. static predicate rfc4251_positive_twoscomplement(s:seq) { (|s|==0 || 01 && s[1]>=128)) } //- Takes a normalized natural-valued seq (left byte nonzero) and returns //- an equivalently-valued rfc4251 twoscomplement number satisfying //- rfc4251_positive_twoscomplement(). static function rfc4251_positive_to_twoscomplement(s:seq) : seq { if |s|==0 || s[0]<128 then s else [0]+s } static function {:autoReq} rfc4251_mpint_encoding(v:nat) : seq { var tc := rfc4251_positive_to_twoscomplement(BEIntToByteSeq(v)); rfc4251_word32_encoding(|tc|) + tc } static function method STR_SSH_RSA() : seq //-ensures ByteSeq(STR_SSH_RSA()) { //- This sequence is the string "ssh-rsa" [115, 115, 104, 45, 114, 115, 97] } static function {:autoReq} rfc4251_sshrsa_encoding(e:nat, n:nat) : seq { rfc4251_string_encoding(STR_SSH_RSA()) + rfc4251_mpint_encoding(e) + rfc4251_mpint_encoding(n) } static function {:autoReq} rfc4251_sshrsa_pubkey_encoding(key:RSAPubKeySpec) : seq requires WellformedRSAPubKeySpec(key); { rfc4251_sshrsa_encoding(key.e, key.n) } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Crypto/RSA/rfc4251decode.i.dfy ================================================ //- include "rfc4251impl.i.dfy" include "KeybitsLength.i.dfy" include "../../FatNat/FatNatDiv.i.dfy" include "../../FatNat/FatNatReciprocal.i.dfy" lemma lemma_1_is_small_enough(N:array) requires WellformedFatNat(N); requires J(N) == 1; ensures J(N) < power2(power2(29)); { lemma_2toX32(); calc { J(N); 1; < power2(2); power2(power2(1)); <= { lemma_power2_increases(1, 29); lemma_power2_increases(power2(1), power2(29)); } power2(power2(29)); } } lemma lemma_prep_dummy_key(N:array, k:nat) requires WellformedFatNat(N); requires J(N)==1; requires k==1; //- ensures 1 < Frump(); ensures KeyModulusMatchesSizeInBytes(J(N), k); { lemma_2toX32(); calc { J(N); < 16; power2(4); <= { lemma_power2_increases(4, power2(30)); } power2(power2(30)); } //- assert FrumpyBigNat(N); ghost var n := 1; assert n == J(N); calc { power2(8*(k-1)); power2(8*0); power2(0); 1; <= n; } calc { n; <= 256; power2(8); power2(8*1); power2(8*k); } assert power2(8*(k-1)) <= n; assert n < power2(8*k); assert KeyModulusMatchesSizeInBytes(J(N), k); } method {:timeLimitMultiplier 3} make_dummy_key() returns (pubkey:RSAPubKeyImpl_internal) ensures WellformedRSAPubKeyImpl_internal(pubkey); ensures public(pubkey.size); ensures public(J(pubkey.n)); ensures public(J(pubkey.e)); { lemma_2toX32(); var N := MakeBELiteralArray(1); assert WellformedFatNat(N); var E := MakeBELiteralArray(1); lemma_prep_dummy_key(N, 1); //- assert FrumpyBigNat(E); pubkey := RSAPubKeyImpl_c_internal(N, 1, E, FNDivUnknownReciprocal()); //- dafnycc assert N == pubkey.n; //- OBSERVE assert KeyModulusMatchesSizeInBytes(J(pubkey.n), pubkey.size); lemma_1_is_small_enough(N); assert WellformedFatNat(N); assert J(N) < power2(power2(29)); //- lemma_keybits_implies_length25(N); lemma_power2_increases(29, 30); lemma_power2_increases(power2(25), power2(30)); assert N == pubkey.n; //- assert WellformedFatNat(N); assert WellformedRSAPubKeyImpl_internal(pubkey); } method rfc4251_decode_sshrsa_internal(msg:seq) returns (success:bool, pubkey:RSAPubKeyImpl_internal) requires IsByteSeq(msg); requires Word32(|msg|); requires public(msg); ensures WellformedRSAPubKeyImpl_internal(pubkey); ensures success ==> PubKeyImplToSpec_internal(pubkey).e < power2(power2(34)); ensures success ==> PubKeyImplToSpec_internal(pubkey).n < power2(power2(34)); ensures success ==> (msg == rfc4251_sshrsa_pubkey_encoding_premium(PubKeyImplToSpec_internal(pubkey))); ensures public(success); ensures public(pubkey.size); ensures public(J(pubkey.n)); ensures public(J(pubkey.e)); { success := false; var sub_rc,E,N := rfc4251_decode_sshrsa_inner(msg); if (!sub_rc) { pubkey := make_dummy_key(); return; } //- lemma_frumpy_is_modest(N); //- lemma_modesty_word_value_equivalence(N); var size_bits := FatNatCountBits(N); var size_bytes := (size_bits+7)/8; lemma_power2_increases(8*(size_bytes-1), size_bits-1); lemma_power2_increases(size_bits, 8*size_bytes); //-assert power2(8*(size_bytes-1)) <= J(N); //-assert J(N) < power2(8*size_bytes); var nReciprocal := FatNatComputeReciprocal(N); var nReciprocal_ref := nReciprocal.TwoTo32wDividedByD; //- reference this array for DafnyCC's sake pubkey := RSAPubKeyImpl_c_internal(N, size_bytes, E, nReciprocal); //- lemma_keybits_implies_length25(N); //-assert J(E) < power2(power2(30)); //-assert J(N) < power2(power2(30)); //-assert WellformedRSAPubKeyImpl_internal(pubkey); //- calc { //- PubKeyImplToSpec_internal(pubkey).e; //- J(E); //- < //- power2(power2(34)); //- } success := true; } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Crypto/RSA/rfc4251impl.i.dfy ================================================ //- //- include "../../BigNum/BigNum.i.dfy" include "rfc4251.s.dfy" include "RSASpec.s.dfy" include "../../Util/seqs_simple.i.dfy" include "BlockEncoding.i.dfy" include "KeyImpl.i.dfy" include "../../FatNat/FatNatModesty.i.dfy" static function method{:CompiledSpec} CompiledSpec_STR_SSH_RSA() : seq static method rfc4251_encode_word32(w:int) returns (msg:seq) requires Word32(w); //- redundant; falls out of definition. ensures IsByteSeq(msg); ensures msg == rfc4251_word32_encoding(w); ensures |msg|==4; { var wordseq := [w]; msg := BEWordSeqToByteSeq_impl(wordseq); } static method rfc4251_encode_string(s:seq) returns (msg:seq) requires IsByteSeq(s); requires Word32(|s|); ensures IsByteSeq(msg); ensures msg == rfc4251_string_encoding(s); { var l := rfc4251_encode_word32(|s|); msg := l + s; assert msg[0..4] == l; } static lemma lemma_rfc4251_positive_to_twoscomplement(s:seq) requires IsByteSeq(s); ensures |rfc4251_positive_to_twoscomplement(s)| <= |s|+1; ensures IsByteSeq(rfc4251_positive_to_twoscomplement(s)); { } static function rfc4251_positive_to_twoscomplement_premium(s:seq) : seq requires IsByteSeq(s); ensures |rfc4251_positive_to_twoscomplement(s)| <= |s|+1; ensures IsByteSeq(rfc4251_positive_to_twoscomplement(s)); ensures rfc4251_positive_to_twoscomplement_premium(s) == rfc4251_positive_to_twoscomplement(s); { lemma_rfc4251_positive_to_twoscomplement(s); rfc4251_positive_to_twoscomplement(s) } static lemma lemma_BEIntToByteSeq_length_bound(v:int) requires 0 <= v < power2(power2(34)); ensures |BEIntToByteSeq(v)| < power2(32)-1; { lemma_2toX(); var vs := BEIntToByteSeq(v); if (v==0) { reveal_BEIntToDigitSeq_private(); assert |vs| == 0; } else { if (power2(32)-1 <= |vs|) { lemma_2to32(); lemma_power2_add8(24); lemma_power2_add8(32); calc { v; < //- { requires assumption } power2(power2(34)); power2(8 * power2(31)); { lemma_mul_is_mul_boogie(8, power2(31)); } //-dafnycc power2(mul(8,power2(31))); { lemma_power2_is_power_2(mul(8,power2(31))); } power(2, mul(8,power2(31))); { lemma_power_multiplies(2, 8, power2(31)); } power(power(2,8), power2(31)); { lemma_power2_is_power_2(8); } power(256, power2(31)); <= { lemma_power_increases(256, power2(31), power2(32)-2); } power(256, power2(32)-2); <= { lemma_power_increases(256, power2(32)-2, |vs|-1); } //- contradiction hyp power(256, |vs|-1); power(power2(8), |vs|-1); <= { lemma_BEIntToDigitSeq_properties(power2(8), 0, v); } v; } assert false; } } lemma_2toX(); assert 0 <= |vs| < power2(32)-1; } static lemma lemma_TwosComplement_length_bound(x:int) requires 0 <= x < power2(power2(34)); ensures |rfc4251_positive_to_twoscomplement(BEIntToByteSeq(x))| < power2(32); { lemma_BEIntToByteSeq_length_bound(x); } static lemma lemma_rfc4251_mpint_encoding_premium(v:nat) requires v < power2(power2(34)); ensures |rfc4251_positive_to_twoscomplement(BEIntToByteSeq(v))| < power2(32); ensures IsByteSeq(rfc4251_mpint_encoding(v)); { lemma_2toX(); lemma_TwosComplement_length_bound(v); lemma_BEIntToByteSeq_decoding(v); var vs := BEIntToByteSeq(v); lemma_BEIntToDigitSeq_properties(power2(8), 0, v); assert v>0 ==> power(power2(8), |vs|-1) <= v; var tc := rfc4251_positive_to_twoscomplement(vs); assert |tc| <= |vs|+1; assert 0 <= |tc| < power2(32); lemma_BEInt_decoding_general(power2(8), 4, |tc|); assert IsDigitSeq(power2(8), BEIntToDigitSeq(power2(8), 4, |tc|)); assert IsByteSeq(BEIntToDigitSeq(power2(8), 4, |tc|)); assert IsDigitSeq(power2(32), [|tc|]); lemma_BEDigitSeqToInt_bound(power2(32), [|tc|]); lemma_BEIntToDigitSeq_produces_DigitSeq(power2(8), 4, BEDigitSeqToInt(power2(32), [|tc|])); assert IsDigitSeq(power2(8), BEIntToDigitSeq(power2(8), 4, BEDigitSeqToInt(power2(32), [|tc|]))); assert IsByteSeq(BEIntToDigitSeq(power2(8), 4, BEDigitSeqToInt(power2(32), [|tc|]))); calc { BEIntToDigitSeq(power2(8), 4, BEDigitSeqToInt(power2(32), [|tc|])); BEIntToDigitSeq(power2(8), |[|tc|]|*4, BEDigitSeqToInt(power2(32), [|tc|])); BEWordSeqToByteSeq([|tc|]); rfc4251_word32_encoding(|tc|); } assert IsByteSeq(rfc4251_word32_encoding(|tc|)); assert IsByteSeq(tc); assert IsByteSeq(rfc4251_mpint_encoding(v)); } static function rfc4251_mpint_encoding_premium(v:nat) : seq requires v < power2(power2(34)); ensures IsByteSeq(BEIntToByteSeq(v)); ensures IsByteSeq(rfc4251_mpint_encoding_premium(v)); ensures IsDigitSeq(power2(32), [|rfc4251_positive_to_twoscomplement(BEIntToByteSeq(v))|]); ensures rfc4251_mpint_encoding_premium(v) == rfc4251_mpint_encoding(v); { lemma_BEIntToByteSeq_decoding(v); var tc := rfc4251_positive_to_twoscomplement(BEIntToByteSeq(v)); assert 0<=|tc|; lemma_rfc4251_mpint_encoding_premium(v); assert IsDigitSeq(power2(32), [|tc|]); rfc4251_word32_encoding(|tc|) + tc } lemma lemma_rfc4251_modesty_suffices_for_encoding(V:array) requires ModestFatNatValue(V); ensures J(V) < power2(power2(34)); { lemma_power2_strictly_increases(31, 34); lemma_power2_strictly_increases(power2(31), power2(34)); } method {:dafnycc_conservative_seq_triggers} rfc4251_encode_mpint(V:array) returns (msg:seq) requires ModestFatNatValue(V); ensures J(V) < power2(power2(34)); ensures IsByteSeq(msg); ensures msg == rfc4251_mpint_encoding_premium(J(V)); { lemma_rfc4251_modesty_suffices_for_encoding(V); var v_bytes := IntegerToBESeq(V); lemma_2to32(); assert J(V) < power2(power2(31)); if (|v_bytes|>2) { assert power2(8*(|v_bytes|-2)) <= BigEndianIntegerValue(v_bytes); lemma_2to32(); lemma_power2_add8(0); lemma_power2_add8(24); calc ==> { power2(8*(|v_bytes|-2)) <= power2(power2(31)); { lemma_power2_increases_converse(8*(|v_bytes|-2), power2(31)); } 8*(|v_bytes|-2) <= power2(31); |v_bytes|-2 <= power2(28); |v_bytes| < Width(); } assert Word32(|v_bytes|); } else { assert |v_bytes| <= 2; assert Word32(|v_bytes|); } assert Word32(|v_bytes|); if (|v_bytes|>=2 && v_bytes[1]<128) { ghost var old_v_bytes := v_bytes; v_bytes := v_bytes[1..]; lemma_BigEndianIntegerValue_zero_prefix(old_v_bytes, v_bytes); } else if (|v_bytes|==1) { ghost var old_v_bytes := v_bytes; assert v_bytes[0]==0; v_bytes := []; } assert Word32(|v_bytes|); var v_seq := v_bytes; var len_bits := rfc4251_encode_word32(|v_seq|); msg := len_bits + v_seq; assert msg[0..4] == len_bits; } static lemma lemma_rfc4251_modest_twoscomplement(v:nat) requires 0 <= v < power2(power2(34)); ensures |rfc4251_positive_to_twoscomplement(BEIntToByteSeq(v))| < power2(32); { lemma_BEIntToByteSeq_length_bound(v); assert |BEIntToByteSeq(v)| < power2(32)-1; } static lemma lemma_rfc4251_word32_encoding(w:int) requires 0 <= w < power2(32); ensures IsByteSeq(rfc4251_word32_encoding(w)); { lemma_2toX(); lemma_BEDigitSeqToInt_bound(power2(32), [w]); lemma_BEIntToDigitSeq_produces_DigitSeq(power2(8), 4, BEWordSeqToInt([w])); } static function rfc4251_word32_encoding_premium(w:int) : seq requires 0 <= w < power2(32); ensures rfc4251_word32_encoding(w) == rfc4251_word32_encoding_premium(w); ensures IsByteSeq(rfc4251_word32_encoding(w)); { lemma_rfc4251_word32_encoding(w); rfc4251_word32_encoding(w) } static lemma lemma_rfc4251_string_encoding(s:seq) requires IsByteSeq(s); requires |s| < power2(32); ensures IsByteSeq(rfc4251_string_encoding(s)); { assert rfc4251_string_encoding(s) == rfc4251_word32_encoding_premium(|s|) + s; } static function rfc4251_string_encoding_premium(s:seq) : seq requires IsByteSeq(s); requires |s| < power2(32); ensures rfc4251_string_encoding(s) == rfc4251_string_encoding_premium(s); ensures IsByteSeq(rfc4251_string_encoding(s)); { lemma_rfc4251_string_encoding(s); rfc4251_string_encoding(s) } static lemma lemma_rfc4251_sshrsa_encoding_premium(e:nat, n:nat) requires e < power2(power2(34)); requires n < power2(power2(34)); ensures IsWordSeq([|STR_SSH_RSA()|]); ensures IsWordSeq([|rfc4251_positive_to_twoscomplement(BEIntToByteSeq(e))|]); ensures IsWordSeq([|rfc4251_positive_to_twoscomplement(BEIntToByteSeq(n))|]); ensures IsByteSeq(rfc4251_sshrsa_encoding(e,n)); { lemma_2toX(); lemma_rfc4251_modest_twoscomplement(e); lemma_rfc4251_modest_twoscomplement(n); assert IsByteSeq(rfc4251_string_encoding_premium(STR_SSH_RSA())); lemma_rfc4251_mpint_encoding_premium(e); assert rfc4251_mpint_encoding(e) == rfc4251_mpint_encoding_premium(e); assert IsByteSeq(rfc4251_mpint_encoding_premium(e)); lemma_rfc4251_mpint_encoding_premium(n); assert rfc4251_mpint_encoding(n) == rfc4251_mpint_encoding_premium(n); assert IsByteSeq(rfc4251_mpint_encoding(n)); } static function rfc4251_sshrsa_encoding_premium(e:nat, n:nat) : seq requires e < power2(power2(34)); requires n < power2(power2(34)); ensures IsWordSeq([|STR_SSH_RSA()|]); ensures IsWordSeq([|rfc4251_positive_to_twoscomplement(BEIntToByteSeq(e))|]); ensures IsWordSeq([|rfc4251_positive_to_twoscomplement(BEIntToByteSeq(n))|]); ensures rfc4251_sshrsa_encoding_premium(e,n) == rfc4251_sshrsa_encoding(e,n); { lemma_rfc4251_sshrsa_encoding_premium(e,n); rfc4251_sshrsa_encoding(e,n) } static function rfc4251_sshrsa_pubkey_encoding_premium(pubkey:RSAPubKeySpec) : seq requires WellformedRSAPubKeySpec(pubkey); requires pubkey.e < power2(power2(34)); requires pubkey.n < power2(power2(34)); ensures IsWordSeq([|STR_SSH_RSA()|]); ensures IsWordSeq([|rfc4251_positive_to_twoscomplement(BEIntToByteSeq(pubkey.e))|]); ensures IsWordSeq([|rfc4251_positive_to_twoscomplement(BEIntToByteSeq(pubkey.n))|]); ensures rfc4251_sshrsa_pubkey_encoding_premium(pubkey) == rfc4251_sshrsa_pubkey_encoding(pubkey); { lemma_rfc4251_sshrsa_encoding_premium(pubkey.e, pubkey.n); rfc4251_sshrsa_pubkey_encoding(pubkey) } method rfc4251_encode_sshrsa_inner(E:array, N:array) returns (msg:seq) requires ModestFatNatValue(E); requires ModestFatNatValue(N); ensures IsByteSeq(msg); ensures J(E) < power2(power2(34)); ensures J(N) < power2(power2(34)); ensures msg == rfc4251_sshrsa_encoding_premium(J(E), J(N)); { lemma_rfc4251_modesty_suffices_for_encoding(E); lemma_rfc4251_modesty_suffices_for_encoding(N); lemma_2to32(); //- reveal_rfc4251_sshrsa_encoding(); assert |STR_SSH_RSA()| < power2(32); var enc_s := rfc4251_encode_string(STR_SSH_RSA()); var enc_e := rfc4251_encode_mpint(E); var enc_n := rfc4251_encode_mpint(N); msg := enc_s + enc_e + enc_n; assert IsByteSeq(enc_s); assert IsByteSeq(enc_e); assert IsByteSeq(enc_n); assert IsByteSeq(msg); assert enc_s == rfc4251_string_encoding(STR_SSH_RSA()); assert enc_e == rfc4251_mpint_encoding_premium(J(E)); assert enc_n == rfc4251_mpint_encoding_premium(J(N)); assert msg == rfc4251_sshrsa_encoding_premium(J(E), J(N)); } method rfc4251_encode_sshrsa_pubkey_internal(pubkey:RSAPubKeyImpl_internal) returns (msg:seq) requires ModestFatNatValue(pubkey.e); requires ModestFatNatValue(pubkey.n); requires WellformedRSAPubKeyImpl_internal(pubkey); ensures IsByteSeq(msg); ensures PubKeyImplToSpec_internal(pubkey).e < power2(power2(34)); ensures PubKeyImplToSpec_internal(pubkey).n < power2(power2(34)); ensures msg == rfc4251_sshrsa_pubkey_encoding_premium(PubKeyImplToSpec_internal(pubkey)); { lemma_power2_increases(30, 34); lemma_power2_increases(power2(30), power2(34)); //- lemma_frumpy_is_modest(pubkey.e); //- lemma_modesty_word_value_equivalence(pubkey.e); //- lemma_frumpy_is_modest(pubkey.n); //- lemma_modesty_word_value_equivalence(pubkey.n); msg := rfc4251_encode_sshrsa_inner(pubkey.e, pubkey.n); } //-//////////////////////////////////////////////////////////////////////////// //- decoding method rfc4251_decode_word32(msg:seq) returns (success:bool, w:int, bytes_consumed:int) requires IsByteSeq(msg); requires public(msg); ensures Word32(w); ensures 0 <= bytes_consumed <= 4; ensures success ==> 4<=|msg|; ensures success ==> (msg[..bytes_consumed] == rfc4251_word32_encoding(w)); ensures public(success); ensures public(w); ensures public(bytes_consumed); { if (|msg|<4) { success := false; w := 0; bytes_consumed := 0; return; } else { var wordseq,padbytes := BEByteSeqToWordSeq_impl(msg[..4]); //- assert |wordseq| == 1; //- assert |padbytes| == 0; success := true; w := wordseq[0]; assert wordseq == [w]; //- hint required bytes_consumed := 4; } } method rfc4251_decode_string(msg:seq) returns (success:bool, s:seq, bytes_consumed:int) requires IsByteSeq(msg); requires Word32(|msg|); requires public(msg); ensures IsByteSeq(s); ensures Word32(|s|); ensures 0 <= bytes_consumed <= |msg|; ensures success ==> (msg[..bytes_consumed] == rfc4251_string_encoding(s)); ensures public(success); ensures public(s); ensures public(bytes_consumed); { //- failure case return values success := false; bytes_consumed := 0; s := []; var subrc,l,sub_bytes_consumed := rfc4251_decode_word32(msg); if (!subrc || !(0 <= l <= |msg|-sub_bytes_consumed)) { return; } s := msg[sub_bytes_consumed .. sub_bytes_consumed + l]; bytes_consumed := sub_bytes_consumed + l; success := true; // fixed liveness bug } lemma lemma_rfc4251_modesty_helper() ensures 0 < power2(power2(31)); ensures 0 < power2(power2(34)); ensures power2(power2(31)) < power2(power2(34)); { calc { 0; < { lemma_power2_0_is_1(); } power2(0); <= { lemma_power2_increases(0, power2(31)); } power2(power2(31)); } lemma_power2_strictly_increases(31, 34); lemma_power2_strictly_increases(power2(31), power2(34)); } method rfc4251_decode_mpint(msg:seq) returns (success:bool,V:array,bytes_consumed:int) requires IsByteSeq(msg); requires public(msg); ensures ModestFatNatValue(V); ensures J(V) < power2(power2(34)); ensures 0 <= bytes_consumed <= |msg|; ensures success ==> (msg[..bytes_consumed] == rfc4251_mpint_encoding_premium(J(V))); ensures public(success); ensures public(J(V)); ensures public(bytes_consumed); { lemma_2toX32(); success := false; V := FatNatZero(); bytes_consumed := 0; lemma_rfc4251_modesty_helper(); var subrc,l,sub_bytes_consumed := rfc4251_decode_word32(msg); if (!subrc || !(0 <= l <= |msg|-sub_bytes_consumed)) { return; } var S := msg[sub_bytes_consumed .. sub_bytes_consumed + l]; bytes_consumed := sub_bytes_consumed + l; var power2_28 := 0x10000000; if (|S| >= power2_28) { //- encoded integer too big return; } if (|S|>0 && S[0] >= 128) { //- msg encodes negative integer return; } if (|S|>0 && S[0]==0) { if (|S|-1==0 || S[1]<128) { //- message has an improper number of leading zeros. return; } } success := true; V := rfc4251_decode_mpint_common_case(msg, l, sub_bytes_consumed, S, bytes_consumed); } method {:dafnycc_conservative_seq_triggers} rfc4251_decode_mpint_common_case(msg:seq, w:int, sub_bytes_consumed:int, S:seq, bytes_consumed:int) returns (V:array) requires IsByteSeq(msg); requires Word32(w); requires 4 <= |msg|; requires 0 <= w <= |msg|-sub_bytes_consumed; requires 0 <= sub_bytes_consumed; requires msg[..sub_bytes_consumed] == rfc4251_word32_encoding(w); requires bytes_consumed == sub_bytes_consumed + w; requires 0 <= bytes_consumed <= |msg|; requires S == msg[sub_bytes_consumed .. bytes_consumed]; requires |S| < 0x10000000; requires |S| == 0 || S[0] < 128; requires |S|>0 && S[0] == 0 ==> |S| > 1 && S[1] >= 128; requires public(msg); requires public(w); requires public(sub_bytes_consumed); requires public(bytes_consumed); requires public(S); ensures ModestFatNatValue(V); ensures J(V) < power2(power2(34)); ensures msg[..bytes_consumed] == rfc4251_mpint_encoding_premium(J(V)); ensures public(J(V)); { lemma_2toX32(); var V_seq,padding := BEByteSeqToWordSeq_impl(S); V := SeqToArray(V_seq); if (|S|>0 && S[0]==0) { lemma_LeadingZeros(power2(8), S[1..], S); lemma_BEDigitSeqToInt_invertibility_tight(power2(8), J(V), S[1..]); assert S == rfc4251_positive_to_twoscomplement(BEIntToByteSeq_premium(J(V))); } else { lemma_BEDigitSeqToInt_invertibility_tight(power2(8), J(V), S); assert S == rfc4251_positive_to_twoscomplement(BEIntToByteSeq_premium(J(V))); } //- The nesting of the calc below is for dafnycc's sake calc { J(V); < calc { J(V); BEByteSeqToInt(S); < { lemma_BEByteSeqToInt_bound(S); } power2(8*|S|); power2(|S|*8); //-dafnycc power2(|S|*8); < { lemma_mul_is_mul_boogie(|S|, 8); lemma_mul_strict_inequality(|S|,power2(28),8); lemma_power2_strictly_increases(|S|*8, power2(28)*8); } power2(power2(28)*8); { lemma_mul_is_commutative(power2(28), 8); } power2(8*power2(28)); power2(power2(3)*power2(28)); { lemma_power2_adds(3,28); } power2(power2(31)); } power2(power2(31)); } calc { power2(power2(31)); <= { lemma_power2_increases(31, 34); lemma_power2_increases(power2(31), power2(34)); } power2(power2(34)); } } method {:dafnycc_conservative_seq_triggers} {:timeLimitMultiplier 3} rfc4251_decode_sshrsa_inner(msg:seq) returns (success:bool, E:array, N:array) requires IsByteSeq(msg); requires Word32(|msg|); requires public(msg); ensures ModestFatNatValue(E); ensures ModestFatNatValue(N); ensures J(N) < power2(power2(29)); ensures J(E) < power2(power2(30)); ensures J(N) < power2(power2(30)); ensures J(E) < power2(power2(34)); ensures J(N) < power2(power2(34)); ensures success ==> J(N) != 0; ensures success ==> (msg == rfc4251_sshrsa_encoding_premium(J(E), J(N))); ensures public(success); ensures public(J(E)); ensures public(J(N)); { lemma_power2_increases(30, 34); lemma_power2_increases(power2(30), power2(34)); lemma_2toX32(); var power2_29 := 0x20000000; var power2_30 := 0x40000000; //- reveal_rfc4251_sshrsa_encoding(); assert |STR_SSH_RSA()| < power2(32); success := false; E := FatNatZero(); N := FatNatZero(); lemma_rfc4251_modesty_helper(); lemma_rfc4251_modesty_suffices_for_encoding(E); lemma_rfc4251_modesty_suffices_for_encoding(N); var subrc,dec_s,bytes_consumed := rfc4251_decode_string(msg); if (!subrc || dec_s != STR_SSH_RSA()) { return; } var enc_s := msg[..bytes_consumed]; var msg2 := msg[bytes_consumed..]; var subrc2,dec_e,bytes_consumed2 := rfc4251_decode_mpint(msg2); if (!subrc2) { return; } //- lemma_modesty_word_value_equivalence(dec_e); assert BEWordSeqToInt_premium(dec_e[..]) == J(dec_e); var e_size := FatNatCountBits(dec_e); if (e_size >= power2_29) { return; } lemma_power2_increases(e_size, power2(30)); var enc_e := msg2[..bytes_consumed2]; var msg3 := msg2[bytes_consumed2..]; var subrc3,dec_n,bytes_consumed3 := rfc4251_decode_mpint(msg3); if (!subrc3 || bytes_consumed3!=|msg3|) { return; } //- lemma_modesty_word_value_equivalence(dec_n); assert BEWordSeqToInt_premium(dec_n[..]) == J(dec_n); var n_size := FatNatCountBits(dec_n); if (n_size >= power2_29) { return; } lemma_power2_increases(n_size, power2(29)); lemma_power2_increases(n_size, power2(30)); var enc_n := msg3[..bytes_consumed3]; E := dec_e; N := dec_n; assert IsZeroValue(N[..]) == (J(N) == 0); var nz := FatNatIsZero(N); if (nz) { return; } lemma_rfc4251_modesty_suffices_for_encoding(E); lemma_rfc4251_modesty_suffices_for_encoding(N); calc { msg2; msg2[..bytes_consumed2] + msg2[bytes_consumed2..]; enc_e + msg3; } calc { msg; enc_s + msg2; enc_s + (enc_e + msg3); enc_s + (enc_e + enc_n); { lemma_seq_concatenation_associative(enc_s, enc_e, enc_n); } enc_s + enc_e + enc_n; } assert IsByteSeq(enc_s); assert IsByteSeq(enc_e); assert IsByteSeq(enc_n); assert IsByteSeq(msg); assert enc_s == rfc4251_string_encoding(STR_SSH_RSA()); assert enc_e == rfc4251_mpint_encoding_premium(J(E)); assert enc_n == rfc4251_mpint_encoding_premium(J(N)); assert msg == rfc4251_sshrsa_encoding_premium(J(E), J(N)); success := true; } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Crypto/RandomNumberGen.s.dfy ================================================ include "../Math/power2.s.dfy" include "../Math/round.s.dfy" include "../Util/be_sequences.s.dfy" include "RandomTracing.s.dfy" //------------------------------------------------------------// //- Selecting a random number in a range //- Used to select the seeds for MillerRabin tests. datatype SelectRandomRequest = SelectRandomRequest_c( l:int, h:int, h_bits:int); static predicate SelectRandomRequestValid(req:SelectRandomRequest) { 0); static predicate CandidateSeedWorksheetRowValid(req:SelectRandomRequest, row:CandidateSeedWorksheetRow) { //- consume exactly the required number of random bytes SelectRandomRequestValid(req) && |row.randoms| == DivideRoundingUp(req.h_bits, 8) && IsByteSeq(row.randoms) && row.n == BEByteSeqToInt(row.randoms) % power2(req.h_bits) && row.accepted == (req.l<=row.n && row.n<=req.h) } //------------------------------------------------------------// datatype CandidateSeedWorksheet = CandidateSeedWorksheet_c( rows:seq, randoms:seq); //- NB Every predicate of the form *ConsumesRandoms() has exactly the same //- body -- they're duplicated because they're talking about different //- row types, and those types aren't polymorphic. static function CandidateSeedWorksheetConsumesRandoms(rows:seq) : seq { if (rows==[]) then [] else CandidateSeedWorksheetConsumesRandoms(rows[..|rows|-1]) + rows[|rows|-1].randoms } static predicate CandidateSeedWorksheetValid(req:SelectRandomRequest, worksheet:CandidateSeedWorksheet) { //- there is at least one candidate 0<|worksheet.rows| //- each row locally valid && (forall i :: 0<=i<|worksheet.rows| ==> CandidateSeedWorksheetRowValid(req, worksheet.rows[i])) //- all but last row fail, last row succeeds && (forall i:int :: 0<=i<|worksheet.rows|-1 ==> !worksheet.rows[i].accepted) && worksheet.rows[|worksheet.rows|-1].accepted //- randoms properly accounted for && CandidateSeedWorksheetConsumesRandoms(worksheet.rows) == worksheet.randoms } static function CandidateSeedWorksheetOutput(worksheet:CandidateSeedWorksheet) : int requires 0<|worksheet.rows|; { worksheet.rows[|worksheet.rows|-1].n } //------------------------------------------------------------// ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Crypto/RandomTracing.s.dfy ================================================ static predicate is_prefix(prefix:seq, super:seq) { |super| >= |prefix| && super[..|prefix|] == prefix } static predicate is_suffix(suffix:seq, super:seq) { |super| >= |suffix| && super[|suffix|..] == suffix } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/FatNat/BigNatToFatNatAdaptor.i.dfy ================================================ include "FatNatCommon.i.dfy" include "../BigNum/BigNatCore.i.dfy" include "../BigNum/BigNumBEAdaptor.i.dfy" include "CanonicalArrays.i.dfy" include "FatInt.i.dfy" include "../BigNum/BigNum.i.dfy" method BigNatToFatNat(B:BigNat) returns (F:array) requires WellformedBigNat(B); ensures F!=null && IsWordSeq(F[..]); ensures I(B) == BEWordSeqToInt(F[..]); ensures |B.words| == F.Length; ensures IsCanonicalDigitSeq(power2(32), F[..]); { F := new int[|B.words|]; var i:=0; while (i<|B.words|) invariant 0<=i<=|B.words|; invariant forall j::0<=j F[j] == B.words[|B.words|-1-j]; { F[i] := B.words[|B.words|-1-i]; i := i + 1; } lemma_2toX(); calc { I(B); { lemma_BigNatIIsLEDigitSeqToInt(B); } LEDigitSeqToInt(Width(), B.words); { lemma_Reverse_converts_endianness_inner(Width(), F[..], B.words); } BEDigitSeqToInt(Width(), F[..]); } } method FatNatToBigNat(F:array) returns (B:BigNat) requires F!=null && IsWordSeq(F[..]); ensures WellformedBigNat(B); ensures I(B) == BEWordSeqToInt(F[..]); ensures |B.words| <= F.Length; { lemma_2toX(); var t := CountTopZeroWords(F); var lewords := ReverseDigitSeq(power2(32), F[t..]); lemma_Reverse(F[t..], lewords); if (|lewords|>0) { assert lewords[|lewords|-1] == F[t..][0] == F[t]; //- OBSERVE } B := BigNat_ctor(lewords); calc { I(B); { lemma_BigNatIIsLEDigitSeqToInt(B); } LEDigitSeqToInt(Width(), B.words); { lemma_Reverse_converts_endianness_inner(Width(), F[t..], lewords); } BEDigitSeqToInt(Width(), F[t..]); { lemma_LeadingZeros(power2(32), F[t..], F[..]); } BEDigitSeqToInt(Width(), F[..]); } } method FatIntToBigNum(F:FatInt) returns (B:BigNum) requires WellformedFatInt(F); ensures WellformedBigNum(B); ensures BV(B) == FIV(F); ensures |B.value.words| <= F.value.Length; { var bv := FatNatToBigNat(F.value); B := BigNum_ctor(F.negate, bv); } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/FatNat/Bitwise.i.dfy ================================================ include "FatNatCommon.i.dfy" include "FatNatMul.i.dfy" include "CanonicalArrays.i.dfy" include "../Math/power2methods.i.dfy" include "../Util/seqs_common.i.dfy" include "../Util/seqs_and_ints.i.dfy" method BitShiftRight_Word(x:nat, b:nat) returns (xb:nat) requires IsWord(x); ensures IsWord(xb); ensures xb == x/power2(b); { if (b>=32) { xb := 0; lemma_power2_increases(32,b); lemma_small_div(); return; } lemma_power2_strictly_increases(b,32); var p2b := MakePower2(b); var r_discard; xb,r_discard := Divide32(x, p2b); lemma_fundamental_div_mod_converse(x, p2b, xb, r_discard); } method BitShiftLeft_Word(x:nat, b:nat) returns (xb:nat) requires IsWord(x); ensures IsWord(xb); ensures xb == (x*power2(b)) % power2(32); { if (b>=32) { xb := 0; calc { (x*power2(b)) % power2(32); { lemma_power2_adds(b-32,32); lemma_mul_is_associative_forall(); } (x*power2(b-32)*power2(32)) % power2(32); { lemma_mul_is_commutative_forall(); } power2(32)*(x*power2(b-32)) % power2(32); { lemma_mod_multiples_vanish(x*power2(b-32), 0, power2(32)); lemma_small_mod(0, power2(32)); } 0; } return; } lemma_power2_strictly_increases(b,32); var p2b := MakePower2(b); var r_discard; xb,r_discard := Product32(x, p2b); calc { (x*power2(b)) % power2(32); (xb + r_discard * power2(32)) % power2(32); { lemma_mul_is_commutative_forall(); } (power2(32)*r_discard + xb) % power2(32); { lemma_mod_multiples_vanish(r_discard, xb, power2(32)); lemma_small_mod(xb, power2(32)); } xb; } } method {:dafnycc_conservative_seq_triggers} TakeTopBits_first_word_ge_p2b(n:array, top_word:int, b:nat, first_word:int, n_length:int, ghost pv:int, ghost Ns_all:seq, ghost Ns:seq, ghost Nv:int) returns (s:int, e:nat) requires n!=null; requires IsWordSeq(n[..]); requires 0<=top_word n[j]==0; requires 0= power2(b); requires first_word == n[top_word]; requires n_length == n.Length - top_word; requires pv == power2(32); requires Ns == n[top_word..]; requires Ns_all == n[..]; requires Nv == BEWordSeqToInt(Ns); requires BEDigitSeqToInt(pv, Ns) == BEDigitSeqToInt(pv, Ns_all); requires 0 < BEDigitSeqToInt(pv, Ns); ensures 0 < s < power2(b); ensures s == BEWordSeqToInt(n[..]) / power2(e); ensures b>0 && e>0 ==> power2(b-1) <= s; { //- shift right a smidgen and we're done. var ne := CountBits(first_word); if (b > ne) { lemma_power2_strictly_increases(ne, b); assert false; } calc { b; < ne; } var shift := ne - b; s := BitShiftRight_Word(first_word, shift); e := 32*(n_length-1) + shift; assert e == 32*(|Ns|-1) + shift; if (0==s) { calc { first_word; { lemma_fundamental_div_mod(first_word, power2(shift)); } power2(shift) * (first_word/power2(shift)) + first_word%power2(shift); power2(shift) * s + first_word%power2(shift); { lemma_mul_basics(power2(shift)); } first_word%power2(shift); < { lemma_mod_properties(); } power2(shift); <= { lemma_power2_increases(shift, ne-1); } power2(ne-1); <= first_word; } assert false; } assert first_word < power2(ne); calc { s; first_word / power2(shift); first_word / power2(ne-b); < { lemma_power2_adds(b, ne-b); lemma_div_by_multiple_is_strongly_ordered(first_word, power2(ne), power2(b), power2(ne-b)); } power2(ne) / power2(ne-b); { lemma_power2_div_is_sub(ne-b, ne); } power2(b); } assert 0 < s < power2(b); calc { BEWordSeqToInt(n[..]) / power2(e); BEWordSeqToInt(Ns_all) / power2(e); BEWordSeqToInt(Ns) / power2(e); { lemma_BEInterpretation(pv, Ns, |Ns|-1); assert Ns[..1] == [Ns[0]]; //- OBSERVE lemma_BEDigitSeqToInt_singleton(pv, Ns[0]); } (Ns[0]*power(pv, |Ns|-1) + BEWordSeqToInt(Ns[1..])) / power2(e); { lemma_power2_unfolding(32, |Ns|-1); lemma_mul_is_mul_boogie(32, |Ns|-1); } (Ns[0]*power2(32*(|Ns|-1)) + BEWordSeqToInt(Ns[1..])) / power2(e); { lemma_fundamental_div_mod(Ns[0], power2(shift)); } ((power2(shift)*(Ns[0]/power2(shift)) + Ns[0]%power2(shift)) *power2(32*(|Ns|-1)) + BEWordSeqToInt(Ns[1..])) / power2(e); { lemma_mul_is_distributive_add_other_way(power2(32*(|Ns|-1)), power2(shift)*(Ns[0]/power2(shift)), Ns[0]%power2(shift)); } (power2(shift)*(Ns[0]/power2(shift))*power2(32*(|Ns|-1)) + (Ns[0]%power2(shift))*power2(32*(|Ns|-1)) + BEWordSeqToInt(Ns[1..])) / power2(e); { lemma_mul_is_associative(power2(shift), Ns[0]/power2(shift), power2(32*(|Ns|-1))); } { lemma_mul_is_commutative(Ns[0]/power2(shift), power2(32*(|Ns|-1))); } { lemma_mul_is_associative(power2(shift), power2(32*(|Ns|-1)), Ns[0]/power2(shift)); } { lemma_power2_adds(shift, 32*(|Ns|-1)); } (power2(e)*(Ns[0]/power2(shift)) + (Ns[0]%power2(shift))*power2(32*(|Ns|-1)) + BEWordSeqToInt(Ns[1..])) / power2(e); { lemma_mod_properties(); lemma_mul_nonnegative(Ns[0]%power2(shift),power2(32*(|Ns|-1))); assert 0<=Ns[0]%power2(shift); assert 0<=power2(32*(|Ns|-1)); calc { (Ns[0]%power2(shift))*power2(32*(|Ns|-1)) + BEWordSeqToInt(Ns[1..]); <= { lemma_mod_properties(); lemma_mul_inequality(Ns[0]%power2(shift), power2(shift)-1, power2(32*(|Ns|-1))); } (power2(shift)-1) * power2(32*(|Ns|-1)) + BEWordSeqToInt(Ns[1..]); < { lemma_BEDigitSeqToInt_bound(pv, Ns[1..]); lemma_power2_unfolding(32, |Ns|-1); lemma_mul_is_mul_boogie(32, |Ns|-1); } (power2(shift)-1)* power2(32*(|Ns|-1)) + power2(32*(|Ns|-1)); { lemma_mul_basics_forall(); } (power2(shift)-1)* power2(32*(|Ns|-1)) + mul(1,power2(32*(|Ns|-1))); { lemma_mul_is_distributive_add_other_way(power2(32*(|Ns|-1)), power2(shift)-1, 1); } power2(shift)*power2(32*(|Ns|-1)); { lemma_power2_adds(shift, 32*(|Ns|-1)); } power2(e); } assert (Ns[0]%power2(shift))*power2(32*(|Ns|-1)) + BEWordSeqToInt(Ns[1..]) < power2(e); lemma_BEDigitSeqToInt_bound(pv, Ns[1..]); lemma_div_multiples_vanish_fancy( Ns[0]/power2(shift), (Ns[0]%power2(shift))*power2(32*(|Ns|-1)) + BEWordSeqToInt(Ns[1..]), power2(e)); } Ns[0]/power2(shift); s; } if (00 ==> 0, top_word:int, b:nat) returns (s:int, e:nat) requires n!=null; requires IsWordSeq(n[..]); requires 0<=top_word n[j]==0; requires 00 && e>0 ==> power2(b-1) <= s; { lemma_2toX(); ghost var pv := power2(32); ghost var Ns_all := n[..]; ghost var Ns := n[top_word..]; lemma_LeadingZeros(pv, Ns, Ns_all); ghost var Nv := BEWordSeqToInt(Ns); assert Nv == BEWordSeqToInt(Ns_all); calc { 0; < { lemma_power_positive(pv, |Ns|-1); lemma_mul_strictly_positive(Ns[0], power(pv, |Ns|-1)); } Ns[0] * power(pv, |Ns|-1); <= { lemma_BEDigitSeqToInt_bound(pv, Ns); } BEDigitSeqToInt(pv, Ns); } var first_word := n[top_word]; var n_length := n.Length - top_word; var first_word_ge_p2b:bool; if (b==32) { first_word_ge_p2b := false; assert first_word < power2(b); } else { var p2b := MakePower2(b); first_word_ge_p2b := (first_word >= p2b); } assert first_word_ge_p2b == (first_word >= power2(b)); if (first_word_ge_p2b) { s, e := TakeTopBits_first_word_ge_p2b(n, top_word, b, first_word, n_length, pv, Ns_all, Ns, Nv); } else if (n_length == 1) { s := first_word; lemma_BEDigitSeqToInt_singleton(pv, s); assert Ns==[s]; //- OBSERVE SEQS assert BEWordSeqToInt(n[..])==s; e := 0; lemma_power2_0_is_1(); lemma_div_basics(BEWordSeqToInt(n[..])); } else { //- Need a left shift and some high bits from next word down. //- This is a lot like the case above, but even longer since //- we have to shuffle more power2()s around. var ne := CountBits(first_word); if (b <= ne-1) { lemma_power2_increases(b, ne-1); //- assert p2b <= power2(ne-1) <= first_word < p2b; } assert 0 < ne <= b; var left_shift := b - ne; var hi_s := BitShiftLeft_Word(first_word, left_shift); calc { first_word*power2(left_shift); < { lemma_mul_strict_inequality(first_word, power2(ne), power2(left_shift)); } power2(ne)*power2(left_shift); { lemma_power2_adds(ne, left_shift); } power2(b); <= { lemma_power2_increases(b,32); } power2(32); } lemma_mul_nonnegative(first_word, power2(left_shift)); lemma_small_mod(first_word*power2(left_shift), power2(32)); var second_word := n[top_word+1]; var right_shift := 32 - left_shift; var low_s := BitShiftRight_Word(second_word, right_shift); s := hi_s + low_s; e := 32*(n_length-1) - left_shift; lemma_mul_strictly_positive(first_word, power2(left_shift)); assert 0 < hi_s; assert 0 <= low_s; calc { low_s; second_word/power2(right_shift); < { lemma_power2_adds(32-right_shift, right_shift); lemma_div_by_multiple_is_strongly_ordered(second_word, power2(32), power2(32 - right_shift), power2(right_shift)); } power2(32)/power2(right_shift); { lemma_power2_div_is_sub(right_shift, 32); } power2(left_shift); } calc { s; hi_s + low_s; first_word*power2(left_shift) + low_s; < first_word*power2(left_shift) + power2(left_shift); { lemma_mul_basics_forall(); } first_word*power2(left_shift) + mul(1,power2(left_shift)); { lemma_mul_is_distributive_add_other_way(power2(left_shift), first_word, 1); } (first_word+1)*power2(left_shift); <= { lemma_mul_inequality(first_word+1, power2(ne), power2(left_shift)); } power2(ne)*power2(left_shift); { lemma_power2_adds(ne, left_shift); } power2(b); } assert 0 < s < power2(b); calc { BEWordSeqToInt(Ns); { lemma_BEInterpretation(pv, Ns, n_length-1); assert Ns[..1] == [Ns[0]]; //- OBSERVE lemma_BEDigitSeqToInt_singleton(pv, Ns[0]); lemma_power2_unfolding(32, n_length-1); lemma_mul_is_mul_boogie(32, n_length-1); } first_word*power2(32*(n_length-1)) + BEWordSeqToInt(Ns[1..]); { lemma_BEInterpretation(pv, Ns[1..], n_length-2); assert Ns[1..][..1] == [Ns[1]]; //- OBSERVE assert Ns[1..][1..] == Ns[2..]; //- OBSERVE lemma_BEDigitSeqToInt_singleton(pv, Ns[1]); lemma_power2_unfolding(32, n_length-2); lemma_mul_is_mul_boogie(32, n_length-2); } first_word*power2(32*(n_length-1)) + second_word*power2(32*(n_length-2)) + BEWordSeqToInt(Ns[2..]); { lemma_power2_adds(left_shift, 32*(n_length-1)-left_shift); lemma_mul_is_associative_forall(); } hi_s*power2(e) + second_word*power2(32*(n_length-2)) + BEWordSeqToInt(Ns[2..]); { lemma_fundamental_div_mod(second_word, power2(right_shift)); } hi_s*power2(e) + (power2(right_shift)*low_s + second_word%power2(right_shift)) *power2(32*(n_length-2)) + BEWordSeqToInt(Ns[2..]); { calc { (power2(right_shift)*low_s + second_word%power2(right_shift)) *power2(32*(n_length-2)); { lemma_mul_is_distributive_add_other_way(power2(32*(n_length-2)), power2(right_shift)*low_s, second_word%power2(right_shift)); } (power2(right_shift)*low_s)*power2(32*(n_length-2)) +(second_word%power2(right_shift))*power2(32*(n_length-2)); { lemma_mul_is_commutative(power2(right_shift), low_s); } (low_s*power2(right_shift))*power2(32*(n_length-2)) +(second_word%power2(right_shift))*power2(32*(n_length-2)); { lemma_mul_is_associative(low_s, power2(right_shift), power2(32*(n_length-2))); } low_s*(power2(right_shift)*power2(32*(n_length-2))) +(second_word%power2(right_shift))*power2(32*(n_length-2)); { lemma_power2_adds(right_shift, 32*(n_length-2)); } low_s*power2(e) +(second_word%power2(right_shift))*power2(32*(n_length-2)); } } hi_s*power2(e) + low_s*power2(e) + (second_word%power2(right_shift)) * power2(32*(n_length-2)) + BEWordSeqToInt(Ns[2..]); { lemma_mul_is_distributive_add_other_way(power2(e), hi_s, low_s); } s*power2(e) + (second_word%power2(right_shift)) * power2(32*(n_length-2)) + BEWordSeqToInt(Ns[2..]); } calc { 0; <= { lemma_mod_properties(); assert(power2(right_shift) > 0); } second_word%power2(right_shift); } lemma_mul_nonnegative( second_word%power2(right_shift), power2(32*(n_length-2))); lemma_BEDigitSeqToInt_bound(pv, Ns[2..]); calc { (second_word%power2(right_shift)) * power2(32*(n_length-2)) + BEWordSeqToInt(Ns[2..]); < { lemma_power2_unfolding(32, n_length-2); lemma_mul_is_mul_boogie(32, n_length-2); } (second_word%power2(right_shift)) * power2(32*(n_length-2)) + power2(32*(n_length-2)); <= { lemma_mod_properties(); lemma_mul_inequality( second_word%power2(right_shift), (power2(right_shift)-1), power2(32*(n_length-2))); } (power2(right_shift)-1) * power2(32*(n_length-2)) + power2(32*(n_length-2)); { lemma_mul_basics_forall(); } (power2(right_shift)-1) * power2(32*(n_length-2)) + mul(1,power2(32*(n_length-2))); //- OBSERVE { lemma_mul_is_distributive_add_other_way(power2(32*(n_length-2)), power2(right_shift)-1, 1); } power2(right_shift) * power2(32*(n_length-2)); { lemma_power2_adds(right_shift, 32*(n_length-2)); } power2(e); } lemma_div_multiples_vanish_fancy(s, (second_word%power2(right_shift)) * power2(32*(n_length-2)) + BEWordSeqToInt(Ns[2..]), power2(e)); lemma_mul_is_commutative_forall(); assert s == BEWordSeqToInt(n[..]) / power2(e); if (b>0 && e>0) { calc { power2(b-1); { lemma_power2_adds(ne-1, left_shift); } power2(ne-1)*power2(left_shift); <= { lemma_mul_inequality(power2(ne-1), first_word, power2(left_shift)); } first_word*power2(left_shift); <= s; } } } } method {:dafnycc_conservative_seq_triggers} TakeTopBits(n:array, b:nat) returns (s:int, e:nat) requires n!=null; requires IsWordSeq(n[..]); requires BEWordSeqToInt(n[..])!=0; requires 0 < b <= 32; ensures 0 < s < power2(b); ensures s == BEWordSeqToInt(n[..]) / power2(e); ensures b>0 && e>0 ==> power2(b-1) <= s; { lemma_2to32(); ghost var Ns := n[..]; if (n.Length==0) { reveal_BEDigitSeqToInt_private(); //- assert n[..] == Ns; assert BEWordSeqToInt(n[..])==0; assert false; } var top_word := CountTopZeroWords(n); if (top_word==n.Length) { lemma_LeadingZeros(power2(32), [], Ns); reveal_BEDigitSeqToInt_private(); //- assert BEWordSeqToInt(Ns)==0; //- assert BEWordSeqToInt(n[..])==0; s := 0; e := 0; //- dafnycc assert false; return; } s,e := TakeTopBits_inner(n, top_word, b); } method BitShiftLeft_Array(x:array, b:nat) returns (xb:array) requires x!=null; requires IsWordSeq(x[..]); requires IsWord(b); ensures xb!=null; ensures IsWordSeq(xb[..]); ensures BEWordSeqToInt(xb[..]) == BEWordSeqToInt(x[..])*power2(b); { lemma_2toX(); var s_words, s_bits := Divide32(b, 32); lemma_mul_is_mul_boogie(s_words, 32); lemma_mod_properties(); var base_word := MakePower2(s_bits); lemma_power2_strictly_increases(s_bits, 32); var Xs := x[..]; xb := MultiplyOneRow(x, base_word, s_words); calc { BEWordSeqToInt(xb[..]); base_word * power2(32*s_words) * BEWordSeqToInt(x[..]); base_word * power2(32*s_words) * BEWordSeqToInt(Xs); power2(s_bits) * power2(32*s_words) * BEWordSeqToInt(Xs); { lemma_power2_adds(s_bits, 32*s_words); } power2(s_bits + 32*s_words) * BEWordSeqToInt(Xs); power2(b) * BEWordSeqToInt(Xs); { lemma_mul_is_commutative_forall(); } BEWordSeqToInt(Xs) * power2(b); BEWordSeqToInt(x[..]) * power2(b); } } predicate FatNatBitCount(X:seq, e:nat) requires IsWordSeq(X); { true && (e>0 ==> 00 ==> power2(e-1) <= BEWordSeqToInt(X)) && (BEWordSeqToInt(X)>0 ==> 0) returns (e:nat) requires x!=null && IsWordSeq(x[..]); ensures FatNatBitCount(x[..], e); ensures e == NatNumBits(BEWordSeqToInt_premium(x[..])); { ghost var pv := power2(32); lemma_2toX(); ghost var Xs := x[..]; var t := CountTopZeroWords(x); ghost var Xss := x[t..]; ghost var Xv := BEWordSeqToInt(Xss); lemma_LeadingZeros(power2(32), Xss, Xs); if (t==x.Length) { e := 0; reveal_BEDigitSeqToInt_private(); lemma_power2_0_is_1(); lemma_Power2BoundIsNatNumBits(e, Xv); return; } var b := CountBits(x[t]); e := 32*(x.Length - t - 1) + b; calc { BEWordSeqToInt(x[..]); BEWordSeqToInt(Xs); BEWordSeqToInt(Xss); Xv; } assert Xss[0] == x[t]; assert 0) requires Word32(exp); ensures WellformedFatNat(S); ensures J(S) == power2(exp); { lemma_2toX(); var one := MakeBELiteralArray(1); S := BitShiftLeft_Array(one, exp); lemma_mul_basics_forall(); } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/FatNat/CanonicalArrays.i.dfy ================================================ include "../Util/seqs_canonical.i.dfy" include "../Util/seqs_and_ints.i.dfy" include "../Util/seqs_common.i.dfy" method CountTopZeroWords(n:array) returns (i:int) requires n!=null; //- requires IsWordSeq(n[..]); ensures 0<=i<=n.Length; ensures forall j :: 0<=j n[j]==0; ensures i n[i]!=0; { i := 0; while (i < n.Length) invariant 0<=i<=n.Length; invariant forall j :: 0<=j n[j]==0; { if (n[i]!=0) { return; } i := i + 1; } } method CopyArray(dst:array, doff:nat, src:array, soff:nat, count:nat) requires src!=null; requires soff+count <= src.Length; requires dst!=null; requires doff+count <= dst.Length; requires src!=dst; modifies dst; ensures dst[doff..doff+count] == src[soff..soff+count]; { var i:=0; while (i, src:array) requires dst != null; requires src != null; requires dst.Length == src.Length; requires dst != src; modifies dst; ensures dst != src; ensures dst[..] == src[..]; { CopyArray(dst, 0, src, 0, src.Length); assert dst[..] == dst[0..src.Length]; //- OBSERVE SEQ assert src[..] == src[0..src.Length]; //- OBSERVE SEQ } function CanonicalizeSeq_def(pv:int, s:seq) : seq requires 1) requires 1) : seq requires 1) returns (na:array) requires a!=null; requires IsDigitSeq(power2(32), a[..]); ensures na!=null; ensures IsCanonicalDigitSeq(power2(32), na[..]); ensures BEWordSeqToInt(na[..]) == BEWordSeqToInt(a[..]); ensures na.Length <= a.Length; ensures fresh(na) || na == a; { lemma_2toX(); ghost var As := a[..]; var t := CountTopZeroWords(a); if (t==0) { na := a; return; } var count := a.Length - t; na := new int[count]; CopyArray(na, 0, a, t, count); ghost var Nas := na[..]; assert Nas==Nas[0..count]; //- OBSERVE SEQ lemma_LeadingZeros(power2(32), Nas, As); } method MakeBELiteralArray(x:nat) returns (xa:array) requires IsWord(x); ensures xa!=null; ensures IsWordSeq(xa[..]); ensures BEWordSeqToInt(xa[..]) == x; ensures xa.Length == if x==0 then 0 else 1; ensures IsCanonicalDigitSeq(power2(32), xa[..]); ensures fresh(xa); { if (x==0) { xa := new int[0]; reveal_BEDigitSeqToInt_private(); return; } xa := new int[1]; xa[0] := x; lemma_2toX(); assert xa[..]==[x]; //- OBSERVE lemma_BEDigitSeqToInt_singleton(power2(32), x); } predicate IsZeroValue_def(a:seq) requires IsWordSeq(a); { forall j :: 0<=j<|a| ==> a[j]==0 } lemma lemma_IsZeroValue(a:seq) requires IsWordSeq(a); ensures IsZeroValue_def(a) <==> (BEWordSeqToInt(a[..])==0); decreases |a|; { reveal_BEDigitSeqToInt_private(); lemma_2toX(); if (IsZeroValue_def(a)) { if (0<|a|) { lemma_IsZeroValue(a[0..|a|-1]); } } else { lemma_BEDigitSeqToInt_bound(power2(32), a[0..|a|-1]); if (a[|a|-1]!=0) { calc { BEWordSeqToInt(a[..]); { reveal_BEDigitSeqToInt_private(); } BEWordSeqToInt(a[0..|a|-1])*power2(32) + a[|a|-1]; > 0; } } else { if (IsZeroValue_def(a[0..|a|-1])) { forall (i | 0<=i<|a|) ensures a[i]==0; { if (i<|a|-1) { assert a[i]==a[0..|a|-1][i]; //- OBSERVE SEQ } } assert false; } //- assert !IsZeroValue_def(a[0..|a|-1]); lemma_IsZeroValue(a[0..|a|-1]); //- assert BEWordSeqToInt(a)!=0; } } } predicate IsZeroValue(a:seq) requires IsWordSeq(a); ensures IsZeroValue(a) <==> (BEWordSeqToInt(a[..])==0); { lemma_IsZeroValue(a); IsZeroValue_def(a) } method FatNatIsZero(a:array) returns (rc:bool) requires a!=null; requires IsWordSeq(a[..]); ensures rc <==> IsZeroValue(a[..]); { var t := CountTopZeroWords(a); rc := t==a.Length; } method FatNatZero() returns (Z:array) ensures Z!=null; ensures IsWordSeq(Z[..]); ensures BEWordSeqToInt(Z[..]) == 0; ensures fresh(Z); { Z := new int[0]; assert IsZeroValue(Z[..]); } method TrimLeadingZerosArray(ghost pv:int, M:array) returns (N:array) requires 1) returns (c:array) requires a!=null; ensures c!=null; ensures fresh(c); ensures c.Length == zeros+a.Length; ensures forall i :: 0<=i c[i]==0; ensures c[zeros..] == a[..]; ensures IsByteSeq(a[..]) ==> IsByteSeq(c[..]); ensures IsWordSeq(a[..]) ==> IsWordSeq(c[..]); { var outlen := zeros+a.Length; c := new int[outlen]; var j := 0; while (j c[i]==0; { c[j] := 0; j := j + 1; } while (j c[i]==0; invariant c[zeros..j] == a[..j-zeros]; { c[j] := a[j-zeros]; assert c[zeros..j+1] == c[zeros..j] + [c[j]]; assert a[..j+1-zeros] == a[..j-zeros] + [a[j-zeros]]; j := j + 1; } assert c[zeros..] == c[zeros..j]; //- OBSERVE SEQ assert a[..j-zeros] == a[..]; //- OBSERVE SEQ lemma_2toX(); assert power2(8)==256; //- ensures IsByteSeq(a[..]) ==> IsByteSeq(c[..]); if (IsByteSeq(a[..])) { forall (i | 0<=i); //-//////////////////////////////////////////////////////////////////////////// function {:heap} WellformedFatInt(A:FatInt) : bool reads A.value; { A.value != null && IsWordSeq(A.value[..]) && (IsZeroValue(A.value[..]) ==> !A.negate) //- disallow redundant zero (-0) } //-//////////////////////////////////////////////////////////////////////////// function {:heap} FIV(A:FatInt) : int requires WellformedFatInt(A); reads A.value; ensures (FIV(A) < 0) <==> A.negate; { lemma_2toX(); lemma_BEDigitSeqToInt_bound(power2(32), A.value[..]); if (A.negate) then -BEWordSeqToInt(A.value[..]) else BEWordSeqToInt(A.value[..]) } method FatIntNegate(A:FatInt) returns (R:FatInt) requires WellformedFatInt(A); ensures WellformedFatInt(R); ensures FIV(R) == -FIV(A); { var z := FatNatIsZero(A.value); if (z) { R := A; } else { R := FatInt_ctor(!A.negate, A.value); } } method FatIntAddSameSign(A:FatInt, B:FatInt) returns (R:FatInt) requires A.negate == B.negate; requires WellformedFatInt(A); requires WellformedFatInt(B); ensures WellformedFatInt(R); ensures FIV(A)+FIV(B) == FIV(R); { ghost var As := A.value[..]; ghost var Bs := B.value[..]; var value:array := FatNatAdd(A.value, B.value); ghost var Rs := value[..]; assert BEWordSeqToInt(Rs) == BEWordSeqToInt(As) + BEWordSeqToInt(Bs); R := FatInt_ctor(A.negate, value); lemma_BEDigitSeqToInt_bound(power2(32), As); lemma_BEDigitSeqToInt_bound(power2(32), Bs); if (A.negate) { assert B.negate; calc { FIV(R); -BEWordSeqToInt(Rs); -(BEWordSeqToInt(As)+BEWordSeqToInt(Bs)); -BEWordSeqToInt(As)-BEWordSeqToInt(Bs); FIV(A)+FIV(B); } } else { assert !B.negate; calc { FIV(R); BEWordSeqToInt(Rs); BEWordSeqToInt(As)+BEWordSeqToInt(Bs); FIV(A)+FIV(B); } } } method FatIntSubPos(A:FatInt, B:FatInt) returns (R:FatInt) requires !A.negate && !B.negate; requires WellformedFatInt(A); requires WellformedFatInt(B); ensures WellformedFatInt(R); ensures FIV(A)-FIV(B) == FIV(R); { //- A - B ==> this is the interesting case ghost var As := A.value[..]; ghost var Bs := B.value[..]; var cmp := FatNatCompare(A.value,B.value); lemma_BEDigitSeqToInt_bound(power2(32), As); lemma_BEDigitSeqToInt_bound(power2(32), Bs); if (cmp.CmpLt?) { var value:array := FatNatSub(B.value, A.value); R := FatInt_ctor(true, value); } else { var value:array := FatNatSub(A.value, B.value); R := FatInt_ctor(false, value); } } method FatIntAdd(A:FatInt, B:FatInt) returns (R:FatInt) requires WellformedFatInt(A); requires WellformedFatInt(B); ensures WellformedFatInt(R); ensures FIV(A)+FIV(B) == FIV(R); { var a_ref := A.value; //- do something real to A.value to convince dafyncc it's allocated var b_ref := B.value; //- do something real to B.value to convince dafyncc it's allocated if (A.negate == B.negate) { R := FatIntAddSameSign(A, B); } else if (A.negate) { assert !B.negate; var NA := FatIntNegate(A); var na_ref := NA.value; //- do something real to NA.value to convince dafnycc it's allocated R := FatIntSubPos(B,NA); } else { //- A - B var NB := FatIntNegate(B); var nb_ref := NB.value; //- do something real to NB.value to convince dafnycc it's allocated R := FatIntSubPos(A,NB); } } method FatIntSub(A:FatInt, B:FatInt) returns (R:FatInt) requires WellformedFatInt(A); requires WellformedFatInt(B); ensures WellformedFatInt(R); ensures FIV(A)-FIV(B) == FIV(R); { var a_ref := A.value; //- do something real to A.value to convince dafyncc it's allocated var b_ref := B.value; //- do something real to B.value to convince dafyncc it's allocated if (B.negate) { //- -A - -B == -A + B //- A - -B == A + B var NB := FatIntNegate(B); var nb_ref := NB.value; //- do something real to NB.value to convince dafnycc it's allocated R := FatIntAdd(A, NB); calc { FIV(R); FIV(A) + FIV(NB); FIV(A) + -FIV(B); FIV(A) - FIV(B); } } else if (A.negate) { assert !B.negate; //- -A - B == - (A + B) ghost var As := A.value[..]; ghost var Bs := B.value[..]; var value:array := FatNatAdd(A.value, B.value); lemma_BEDigitSeqToInt_bound(power2(32), As); lemma_BEDigitSeqToInt_bound(power2(32), Bs); R := FatInt_ctor(true, value); } else { R := FatIntSubPos(A, B); } } method FatIntCmp(A:FatInt, B:FatInt) returns (c:Cmp) requires WellformedFatInt(A); requires WellformedFatInt(B); ensures (c.CmpLt?) <==> (FIV(A) < FIV(B)); ensures (c.CmpEq?) <==> (FIV(A) == FIV(B)); ensures (c.CmpGt?) <==> (FIV(A) > FIV(B)); { var a_ref := A.value; //- do something real to A.value to convince dafyncc it's allocated var b_ref := B.value; //- do something real to B.value to convince dafyncc it's allocated if (A.negate) { if (!B.negate) { //- -A, B c := CmpLt; assert FIV(A) < 0 <= FIV(B); } else { //- -A,-B var nc := FatNatCompare(A.value,B.value); if (nc.CmpEq?) { c := CmpEq; } else if (nc.CmpLt?) { c := CmpGt; } else { c := CmpLt; } } } else { if (B.negate) { //- A, -B c := CmpGt; assert FIV(A) >= 0 > FIV(B); } else { //- A, B c := FatNatCompare(A.value,B.value); } } } method FatIntLt(A:FatInt, B:FatInt) returns (r:bool) requires WellformedFatInt(A); requires WellformedFatInt(B); ensures r <==> FIV(A) FIV(A)<=FIV(B); { var c := FatIntCmp(A,B); r := c.CmpLt? || c.CmpEq?; } method FatIntEq(A:FatInt, B:FatInt) returns (r:bool) requires WellformedFatInt(A); requires WellformedFatInt(B); ensures r <==> FIV(A)==FIV(B); { var c := FatIntCmp(A,B); r := c.CmpEq?; } method FatIntGe(A:FatInt, B:FatInt) returns (r:bool) requires WellformedFatInt(A); requires WellformedFatInt(B); ensures r <==> FIV(A)>=FIV(B); { var c := FatIntCmp(A,B); r := c.CmpGt? || c.CmpEq?; } method FatIntGt(A:FatInt, B:FatInt) returns (r:bool) requires WellformedFatInt(A); requires WellformedFatInt(B); ensures r <==> FIV(A)>FIV(B); { var c := FatIntCmp(A,B); r := c.CmpGt?; } method FatIntMul(A:FatInt, B:FatInt) returns (R:FatInt) requires WellformedFatInt(A); requires WellformedFatInt(B); ensures WellformedFatInt(R); ensures FIV(A)*FIV(B) == FIV(R); { var a_ref := A.value; //- do something real to A.value to convince dafyncc it's allocated var b_ref := B.value; //- do something real to B.value to convince dafyncc it's allocated ghost var As := A.value[..]; ghost var Bs := B.value[..]; lemma_BEDigitSeqToInt_bound(power2(32), As); lemma_BEDigitSeqToInt_bound(power2(32), Bs); if ((A.negate && B.negate) || (!A.negate && !B.negate)) { var value:array := FatNatMul(A.value, B.value); ghost var Rs := value[..]; R := FatInt_ctor(false, value); if (A.negate) { calc { FIV(R); BEWordSeqToInt(Rs); BEWordSeqToInt(As) * BEWordSeqToInt(Bs); { lemma_mul_cancels_negatives(BEWordSeqToInt(As), BEWordSeqToInt(Bs)); } (-BEWordSeqToInt(As)) * (-BEWordSeqToInt(Bs)); FIV(A) * FIV(B); } } else { calc { FIV(R); BEWordSeqToInt(Rs); BEWordSeqToInt(As) * BEWordSeqToInt(Bs); FIV(A) * FIV(B); } } } else //- if ((!A.negate && B.negate) || (A.negate && !B.negate)) { var za := FatNatIsZero(A.value); var zb := FatNatIsZero(B.value); assert za <==> (BEWordSeqToInt(As)==0); if ((B.negate && za) || (A.negate && zb)) { var Z := FatNatZero(); R := FatInt_ctor(false, Z); lemma_mul_basics_forall(); } else { var value:array := FatNatMul(A.value, B.value); ghost var Rs := value[..]; R := FatInt_ctor(true, value); calc ==> { !IsZeroValue(As) && !IsZeroValue(Bs); BEWordSeqToInt(As)!=0 && BEWordSeqToInt(Bs)!=0; { lemma_mul_nonzero_forall(); } BEWordSeqToInt(As)*BEWordSeqToInt(Bs) != 0; BEWordSeqToInt(Rs) != 0; !IsZeroValue(Rs); WellformedFatInt(R); } if (A.negate) { calc { FIV(R); -BEWordSeqToInt(Rs); -(BEWordSeqToInt(As) * BEWordSeqToInt(Bs)); { lemma_mul_properties(); } (-BEWordSeqToInt(As)) * BEWordSeqToInt(Bs); FIV(A) * FIV(B); } } else { calc { FIV(R); -BEWordSeqToInt(Rs); -(BEWordSeqToInt(As) * BEWordSeqToInt(Bs)); { lemma_mul_properties(); } BEWordSeqToInt(As) * (-(BEWordSeqToInt(Bs))); FIV(A) * FIV(B); } } } } } method FatIntDiv(N:FatInt, D:FatInt) returns (Q:FatInt, R:FatInt) requires WellformedFatInt(N); //- requires N.value.Length < power2(27); requires WellformedFatInt(D); requires BEWordSeqToInt(D.value[..])!=0; requires FIV(D) >= 0; ensures WellformedFatInt(Q); ensures WellformedFatInt(R); ensures 0 <= FIV(R) < FIV(D); //- negative D inverts this condition. ensures FIV(Q)*FIV(D) + FIV(R) == FIV(N); ensures FIV(N) / FIV(D) == FIV(Q); ensures FIV(N) % FIV(D) == FIV(R); { var n_ref := N.value; //- do something real to N.value to convince dafyncc it's allocated var d_ref := D.value; //- do something real to D.value to convince dafyncc it's allocated //- if (D.negate) //- { //- var q:BigNat,r:BigNat := BigNatDiv(N, FatIntNegate(D)); //- Q := FatInt_ctor(true, q); //- R := FatInt_ctor(false, r); //- } ghost var Ns := N.value[..]; ghost var Nv := BEWordSeqToInt(Ns); ghost var Ds := D.value[..]; ghost var Dv := BEWordSeqToInt(Ds); var q:array,r:array := FatNatDiv(N.value, D.value); ghost var Qs := q[..]; ghost var Qv := BEWordSeqToInt(Qs); ghost var Rs := r[..]; ghost var Rv := BEWordSeqToInt(Rs); var zr := FatNatIsZero(r); if (N.negate && !zr) { var one := MakeBELiteralArray(1); ghost var Ones := one[..]; ghost var Onev := BEWordSeqToInt(Ones); var q' := FatNatAdd(q, one); ghost var Q's := q'[..]; ghost var Q'v := BEWordSeqToInt(Q's); Q := FatInt_ctor(true, q'); lemma_BEDigitSeqToInt_bound(power2(32), Qs); var r' := FatNatSub(D.value, r); ghost var R's := r'[..]; ghost var R'v := BEWordSeqToInt(R's); R := FatInt_ctor(false, r'); calc ==> { true; 0 <= R'v < Dv; 0 <= FIV(R) < FIV(D); } calc ==> { true; Dv*Qv + Rv == Nv; { lemma_mul_is_commutative_forall(); } Qv*Dv + Rv == Nv; (Q'v-1)*Dv + (Dv - R'v) == Nv; { lemma_mul_is_distributive_forall(); } { lemma_mul_is_mul_boogie(1, Dv); } Q'v*Dv - Dv + (Dv - R'v) == Nv; Q'v*Dv - R'v == Nv; { lemma_mul_unary_negation(Q'v, Dv); } (-Q'v)*Dv + R'v == -Nv; FIV(Q)*FIV(D) + FIV(R) == FIV(N); } } else { var zq := FatNatIsZero(q); if (N.negate && zq) { calc ==> { true; Dv*Qv + Rv == Nv; { lemma_mul_is_commutative_forall(); } Qv*Dv + Rv == Nv; Qv*Dv == Nv; { lemma_mul_is_mul_boogie(0, Dv); } 0*Dv == Nv; false; } } Q := FatInt_ctor(N.negate, q); R := FatInt_ctor(false, r); calc ==> { 0 <= Rv < Dv; 0 <= FIV(R) < FIV(D); } if (N.negate) { calc ==> { true; Dv*Qv + Rv == Nv; { lemma_mul_is_commutative_forall(); } Qv*Dv + Rv == Nv; Qv*Dv == Nv; { lemma_mul_unary_negation(Qv, Dv); } (-Qv)*Dv == -Nv; FIV(Q)*FIV(D) == FIV(N); FIV(Q)*FIV(D) + FIV(R) == FIV(N); } } else { calc ==> { true; Dv*Qv + Rv == Nv; { lemma_mul_is_commutative_forall(); } Qv*Dv + Rv == Nv; FIV(Q)*FIV(D) + FIV(R) == FIV(N); } } } lemma_fundamental_div_mod_converse(FIV(N), FIV(D), FIV(Q), FIV(R)); } method MakeSmallLiteralFatInt(x:nat) returns (f:FatInt) requires x < Width(); ensures WellformedFatInt(f); ensures FIV(f)==x; { var a; if (x==0) { a := FatNatZero(); } else { a := MakeBELiteralArray(x); } f := FatInt_ctor(false, a); } method CanonicalizeFatInt(f:FatInt) returns (na:FatInt) requires WellformedFatInt(f); ensures WellformedFatInt(na); ensures FIV(f) == FIV(na); ensures na.value.Length <= f.value.Length; ensures IsCanonicalDigitSeq(power2(32), na.value[..]); { var fvc := CanonicalizeArray(f.value); na := FatInt_ctor(f.negate, fvc); } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/FatNat/FatNatAdd.i.dfy ================================================ include "FatNatCommon.i.dfy" include "FatNatX86.i.dfy" include "../Util/beseqs_simple.i.dfy" include "FatNatAddLemmas.i.dfy" predicate FNAddRelation_local(pv:int, a:seq, b:seq, c:seq, carryin:seq, i:int) requires 1, b:seq, c:seq, carryin:seq) requires 1 FNAddRelation_local(pv, a, b, c, carryin, i) } lemma lemma_FNAddition_recursive(pv:int, a:seq, b:seq, c:seq, carryin:seq) requires 1, b:seq, c:seq, carryin:seq) requires 1, b:seq, c:seq, carryin:seq, j:int) requires 1= j; { forall i :: 0 <= i < j ==> FNAddRelation_local(pv, a, b, c[|c|-j..], carryin, i) } lemma lemma_AddRelationInduction(pv:int, a:seq, b:seq, c:seq, carryin:seq, j:int) requires 1 0) { lemma_mul_increases(DigitAt(carryin,i), pv); assert false; } } } } lemma lemma_FNAddition_induction(pv:int, oml:int, a:seq, b:seq, oldc:seq, c:seq, oldcarryin:seq, carryin:seq, oldj:int, j:int, lastcarry:int) requires 1 DigitAt(c, i) == DigitAt(oldc, i); requires FNAddRelation_inductive(pv, a, b, oldc, oldcarryin, oldj); requires DigitAt(a,oldj)+DigitAt(b,oldj)+DigitAt(oldcarryin,oldj) == DigitAt(c,oldj) + DigitAt(carryin,j) * pv; ensures 0 <= |c|-j < |c|; ensures IsDigitSeq(pv, c[|c|-j..]); ensures FNAddRelation_inductive(pv, a, b, c, [lastcarry]+oldcarryin, j); { assert 0 <= |c|-j < |c|; assert lastcarry == DigitAt(carryin, j); ghost var olda := a; ghost var oldb := b; ghost var newc := c[|c|-j..]; forall (i | 0 <= i < j) ensures FNAddRelation_local(pv, a, b, newc, carryin, i); { if (i FNAddRelation_local(pv, a, b, newc, carryin, i); assert forall i :: 0 <= i < j ==> FNAddRelation_local(pv, a, b, c[|c|-j..], carryin, i); assert FNAddRelation_inductive(pv, a, b, c, carryin, j); } method FatNatAdd(a:array, b:array) returns (c:array) requires a!=null; requires b!=null; requires IsDigitSeq(power2(32), a[..]); requires IsDigitSeq(power2(32), b[..]); ensures c!=null; ensures IsDigitSeq(power2(32), c[..]); ensures BEWordSeqToInt(a[..]) + BEWordSeqToInt(b[..]) == BEWordSeqToInt(c[..]); { ghost var pv := power2(32); lemma_2toX32(); ghost var carryin:seq := [0]; var iml := (if a.Length > b.Length then a.Length else b.Length); var oml := iml + 1; //- +1 => leave space for overflow c := new int[oml]; assert oml == MaxLen3(a[..],b[..],c[..]); var lastcarry := 0; var j:=0; while (j < oml) invariant 0 <= j <= oml; invariant IsBitSeq(carryin); invariant lastcarry == DigitAt(carryin, j); invariant DigitAt(carryin, 0) == 0; invariant IsDigitSeq(pv, c[c.Length-j..]); invariant |carryin| == j+1; invariant FNAddRelation_inductive(pv, a[..], b[..], c[..], carryin, j); { ghost var olda := a[..]; ghost var oldb := b[..]; ghost var oldc := c[..]; ghost var oldcarryin := carryin[..]; ghost var oldj := j; assert FNAddRelation_inductive(pv, olda, oldb, oldc, oldcarryin, oldj); var sum,carry := Add32_with_carry( ArrayDigitAt_add(a,j), ArrayDigitAt_add(b,j), lastcarry); assert c[..] == oldc; //- OBSERVE carryin := [carry] + carryin; lastcarry := carry; c[c.Length - 1 - j] := sum; assert c[c.Length-1-j..] == [c[c.Length-1-j]] + c[c.Length-j..]; //- OBSERVE j:=j+1; assert olda==a[..]; assert oldb==b[..]; lemma_FNAddition_induction(pv, oml, a[..], b[..], oldc, c[..], oldcarryin, carryin, oldj, j, lastcarry); } assert c[..] == c[c.Length-oml..]; //- OBSERVE lemma_AddRelationInduction(pv, a[..], b[..], c[..], carryin, oml); ghost var la := [0]+a[..]; ghost var lb := [0]+b[..]; ghost var lc := [0]+c[..]; lemma_FNAddition(pv, la, lb, lc, carryin); lemma_LeadingZeros(pv, a[..], la); lemma_LeadingZeros(pv, b[..], lb); lemma_LeadingZeros(pv, c[..], lc); } lemma lemma_FNAddition_induction_unrolled(pv:int, a:seq, b:seq, oldc:seq, c:seq, oldcarryin:seq, carryin:seq, oldj:int, j:int, loopsize:int, loopcarries:seq) requires 1 DigitAt(c, i) == DigitAt(oldc, i); requires FNAddRelation_inductive(pv, a, b, oldc, oldcarryin, oldj); requires forall i :: 0<=i DigitAt(a,oldj+i)+DigitAt(b,oldj+i)+DigitAt(carryin,oldj+i) == DigitAt(c,oldj+i) + DigitAt(carryin,oldj+i+1) * pv; //- ensures 0 <= |c|-j < |c|; ensures IsDigitSeq(pv, c[|c|-j..]); ensures FNAddRelation_inductive(pv, a, b, c, carryin, j); decreases loopsize; { if (loopsize==0) { //- assert oldc==c; assert oldj==j; assert FNAddRelation_inductive(pv, a, b, oldc, oldcarryin, oldj); assert forall i :: 0 <= i < oldj ==> FNAddRelation_local(pv, a, b, oldc[|oldc|-oldj..], oldcarryin, i); forall (i | 0 <= i < j) ensures FNAddRelation_local(pv, a, b, c[|c|-j..], carryin, i); { if (i < oldj) { assert j == |c[|c|-j..]| == |oldc[|oldc|-oldj..]|; forall (ci | 0 <= ci < j) ensures c[|c|-j..][ci] == oldc[|oldc|-oldj..][ci]; { calc { c[|c|-j..][ci]; c[|c|-j+ci]; DigitAt(c, j-ci-1); DigitAt(oldc, j-ci-1); oldc[|oldc|-oldj+ci]; oldc[|oldc|-oldj..][ci]; } } assert c[|c|-j..] == oldc[|oldc|-oldj..]; assert FNAddRelation_local(pv, a, b, oldc[|oldc|-oldj..], oldcarryin, i); assert FNAddRelation_local(pv, a, b, c[|c|-j..], carryin, i); } else { } } assert forall i :: 0 <= i < j ==> FNAddRelation_local(pv, a, b, c[|c|-j..], carryin, i); assert FNAddRelation_inductive(pv, a, b, c, carryin, j); } else { lemma_2toX32(); forall (ci | 0 <= ci < |c[|c|-(j-1)..]|) ensures 0 <= c[|c|-(j-1)..][ci] < pv; { var v := c[|c|-j+1+ci]; assert v == c[|c|-(j-1)..][ci]; //- OBSERVE assert v == c[|c|-j..][ci+1]; //- OBSERVE assert IsDigitSeq(pv, c[|c|-j..]); assert 0 <= v < pv; } assert IsDigitSeq(pv, c[|c|-(j-1)..]); var r_carryin := carryin[1..]; lemma_selection_preserves_digit_seq(2, carryin, 1); var r_loopcarries := loopcarries[1..]; calc { r_carryin; carryin[1..]; (loopcarries + oldcarryin)[1..]; loopcarries[1..] + oldcarryin; r_loopcarries + oldcarryin; } lemma_FNAddition_induction_unrolled(pv, a, b, oldc, c, oldcarryin, r_carryin, oldj, j-1, loopsize-1, r_loopcarries); lemma_FNAddition_induction(pv, |c|, a, b, c, c, r_carryin, carryin, j-1, j, loopcarries[0]); } } method {:timeLimitMultiplier 3} FatNatAddUnrolledLoop(a:array, b:array) returns (c:array) requires a!=null; requires b!=null; requires IsDigitSeq(power2(32), a[..]); requires IsDigitSeq(power2(32), b[..]); requires a.Length == b.Length; requires a.Length%8 == 0; ensures c!=null; ensures IsDigitSeq(power2(32), c[..]); ensures BEWordSeqToInt(a[..]) + BEWordSeqToInt(b[..]) == BEWordSeqToInt(c[..]); ensures fresh(c); { ghost var pv := power2(32); lemma_2toX32(); ghost var carryin:seq := [0]; var iml := a.Length; var oml := iml + 1; //- +1 => leave space for carry overflow c := new int[oml]; assert oml == MaxLen3(a[..],b[..],c[..]); var lastcarry := 0; var j:=0; while (j < iml) invariant j%8 == 0; invariant 0 <= j <= iml; invariant IsBitSeq(carryin); invariant lastcarry == DigitAt(carryin, j); invariant DigitAt(carryin, 0) == 0; invariant IsDigitSeq(pv, c[c.Length-j..]); invariant |carryin| == j+1; invariant FNAddRelation_inductive(pv, a[..], b[..], c[..], carryin, j); { ghost var olda := a[..]; ghost var oldb := b[..]; ghost var oldc := c[..]; ghost var oldcarryin := carryin[..]; ghost var oldj := j; ghost var old_lastcarry := lastcarry; assert FNAddRelation_inductive(pv, olda, oldb, oldc, oldcarryin, oldj); //- ghost var c1,c2,c3,c4,c5,c6,c7,carries; //- lastcarry,c1,c2,c3,c4,c5,c6,c7,carries := Add32_unrolled_8(a, j, b, j, c, j, lastcarry); ghost var carries; lastcarry,carries := Add32_unrolled_8(a, j, b, j, c, j, lastcarry); ghost var c1,c2,c3,c4,c5,c6,c7; c1 := carries[1]; assert c1 == if a[a.Length-1-(j+0)] +b[b.Length-1-(j+0)] + carries[0] >= 0x100000000 then 1 else 0; c2 := carries[2]; c3 := carries[3]; c4 := carries[4]; c5 := carries[5]; c6 := carries[6]; c7 := carries[7]; ghost var loopcarries := [ lastcarry, c7, c6, c5, c4, c3, c2, c1 ]; //- ghost var loopcarries := [ lastcarry ] + carries; carryin := loopcarries + carryin; ghost var sc := c[..]; lemma_FatNatAddUnrolledLoop_DigitSeq_preservation(oldc, sc, j); lemma_Add32_unrolled_8_glue( a[..], j, b[..], j, c[..], j, old_lastcarry, lastcarry, c1, c2, c3, c4, c5, c6, c7, //- lastcarry, carries[1], carries[2], carries[3], carries[4], carries[5], carries[6], carries[7], loopcarries, oldcarryin, carryin); j:=j+8; assert olda==a[..]; assert oldb==b[..]; assert |carryin| == j+1; ghost var loopsize := 8; lemma_FNAddition_induction_unrolled(pv, a[..], b[..], oldc, c[..], oldcarryin, carryin, oldj, j, loopsize, loopcarries); } assert c[..] == c[c.Length-oml..]; //- OBSERVE SEQ //- Original FatNatAdd, to propagate the carry //- into c's last slot, used ArrayDigitAt's implicit zeros for a and b. //- We avoid ArrayDigitAt entirely, which is nice, but instead we //- must stuff the lastcarry into c explicitly after the loop. c[0] := lastcarry; ghost var sa := a[..]; ghost var sb := b[..]; ghost var sc := c[..]; assert |carryin|==j+1; ghost var fcarryin := [0] + carryin; //- that's f/inal/ carryin. forall (i | 0<=i<|sc|) ensures 0<=sc[i]0) { //- assert IsDigitSeq(pv, sc[1..]); assert sc[i] == sc[1..][i-1]; //- OBSERVE SEQ } } forall (i | 0 <= i < oml) ensures FNAddRelation_local(pv, sa, sb, sc[|sc|-oml..], fcarryin, i); { if (i, si:int, i:int) requires 0 <= si; requires si+8 <= |s|; requires 0 <= i < 8; { 0 <= s[|s|-1-(si+i)] < 0x100000000 } lemma {:timeLimitMultiplier 2} lemma_Add32_unrolled_8_glue( a:seq, ai:int, b:seq, bi:int, s:seq, si:int, c_in:int, c_out:int, ghost c1:int, ghost c2:int, ghost c3:int, ghost c4:int, ghost c5:int, ghost c6:int, ghost c7:int, loopcarries:seq, oldcarries:seq, allcarries:seq) //- Add32_unrolled_8 requires requires IsWordSeq(a); requires 0 <= ai; requires ai+8 <= |a|; requires IsWordSeq(b); requires 0 <= bi; requires bi+8 <= |b|; requires 0 <= si; requires si+8 <= |s|; requires 0<=c_in<=1; //- Add32_unrolled_8 ensures requires 0<=c_out<=1; requires s[FatNatAddIndex(|s|,si,0)] == mod0x100000000(a[|a|-1-(ai+0)] +b[|b|-1-(bi+0)] + c_in); requires s[FatNatAddIndex(|s|,si,1)] == mod0x100000000(a[|a|-1-(ai+1)] +b[|b|-1-(bi+1)] + c1); requires s[FatNatAddIndex(|s|,si,2)] == mod0x100000000(a[|a|-1-(ai+2)] +b[|b|-1-(bi+2)] + c2); requires s[FatNatAddIndex(|s|,si,3)] == mod0x100000000(a[|a|-1-(ai+3)] +b[|b|-1-(bi+3)] + c3); requires s[FatNatAddIndex(|s|,si,4)] == mod0x100000000(a[|a|-1-(ai+4)] +b[|b|-1-(bi+4)] + c4); requires s[FatNatAddIndex(|s|,si,5)] == mod0x100000000(a[|a|-1-(ai+5)] +b[|b|-1-(bi+5)] + c5); requires s[FatNatAddIndex(|s|,si,6)] == mod0x100000000(a[|a|-1-(ai+6)] +b[|b|-1-(bi+6)] + c6); requires s[FatNatAddIndex(|s|,si,7)] == mod0x100000000(a[|a|-1-(ai+7)] +b[|b|-1-(bi+7)] + c7); requires c1 == if a[|a|-1-(ai+0)] +b[|b|-1-(bi+0)] + c_in >= 0x100000000 then 1 else 0; requires c2 == if a[|a|-1-(ai+1)] +b[|b|-1-(bi+1)] + c1 >= 0x100000000 then 1 else 0; requires c3 == if a[|a|-1-(ai+2)] +b[|b|-1-(bi+2)] + c2 >= 0x100000000 then 1 else 0; requires c4 == if a[|a|-1-(ai+3)] +b[|b|-1-(bi+3)] + c3 >= 0x100000000 then 1 else 0; requires c5 == if a[|a|-1-(ai+4)] +b[|b|-1-(bi+4)] + c4 >= 0x100000000 then 1 else 0; requires c6 == if a[|a|-1-(ai+5)] +b[|b|-1-(bi+5)] + c5 >= 0x100000000 then 1 else 0; requires c7 == if a[|a|-1-(ai+6)] +b[|b|-1-(bi+6)] + c6 >= 0x100000000 then 1 else 0; requires c_out == if a[|a|-1-(ai+7)] +b[|b|-1-(bi+7)] + c7 >= 0x100000000 then 1 else 0; requires IsDigitSeq(power2(32), a); requires IsDigitSeq(power2(32), b); requires loopcarries == [ c_out, c7, c6, c5, c4, c3, c2, c1 ]; requires |oldcarries| == si+1; requires oldcarries[0] == c_in; requires allcarries == loopcarries + oldcarries; requires IsDigitSeq(power2(32), s[|s|-si..]); ensures IsDigitSeq(power2(32), s[|s|-(si+8)..]); ensures IsDigitSeq(2, loopcarries); ensures forall i :: 0<=i<8 ==> DigitAt(s, si+i) + DigitAt(loopcarries, i) * 0x100000000 == DigitAt(a, ai+i) + DigitAt(b, bi+i) + DigitAt(allcarries, si+i); { lemma_2toX(); forall (i | 0<=i<8) ensures DigitAt(s,si+i) == mod0x100000000(DigitAt(a, ai+i) + DigitAt(b, bi+i) + DigitAt(allcarries,si+i)); { } forall (i | 0<=i<8) ensures HappyDigit(s, si, i); { if (i==0) { lemma_mod0x100000000(a[|a|-1-(ai+0)] +b[|b|-1-(bi+0)] + c_in); } else if (i==1) { lemma_mod0x100000000(a[|a|-1-(ai+1)] +b[|b|-1-(bi+1)] + c1); } else if (i==2) { lemma_mod0x100000000(a[|a|-1-(ai+2)] +b[|b|-1-(bi+2)] + c2); } else if (i==3) { lemma_mod0x100000000(a[|a|-1-(ai+3)] +b[|b|-1-(bi+3)] + c3); } else if (i==4) { lemma_mod0x100000000(a[|a|-1-(ai+4)] +b[|b|-1-(bi+4)] + c4); } else if (i==5) { lemma_mod0x100000000(a[|a|-1-(ai+5)] +b[|b|-1-(bi+5)] + c5); } else if (i==6) { lemma_mod0x100000000(a[|a|-1-(ai+6)] +b[|b|-1-(bi+6)] + c6); } else if (i==7) { lemma_mod0x100000000(a[|a|-1-(ai+7)] +b[|b|-1-(bi+7)] + c7); } } var stail := s[|s|-(si+8)..]; forall (ri | 0<=ri<|stail|) ensures 0<=stail[ri]= 0x100000000 then 1 else 0; { var co := DigitAt(allcarries,si+i+1); var ei := if DigitAt(a,ai+i) +DigitAt(b,bi+i) + DigitAt(allcarries,si+i) >= 0x100000000 then 1 else 0; if (i==0) { assert c1 == DigitAt(allcarries, si+i+1); assert c_in == DigitAt(allcarries, si+i); assert co == ei; } else if (i==1) { assert c2 == DigitAt(allcarries, si+i+1); assert c1 == DigitAt(allcarries, si+i); assert co == ei; } else if (i==2) { assert c3 == DigitAt(allcarries, si+i+1); assert c2 == DigitAt(allcarries, si+i); assert co == ei; } else if (i==3) { assert c4 == DigitAt(allcarries, si+i+1); assert c3 == DigitAt(allcarries, si+i); assert co == ei; } else if (i==4) { assert c5 == DigitAt(allcarries, si+i+1); assert c4 == DigitAt(allcarries, si+i); assert co == ei; } else if (i==5) { assert c6 == DigitAt(allcarries, si+i+1); assert c5 == DigitAt(allcarries, si+i); assert co == ei; } else if (i==6) { assert c7 == DigitAt(allcarries, si+i+1); assert c6 == DigitAt(allcarries, si+i); assert co == ei; } else if (i==7) { assert c_out == DigitAt(allcarries, si+i+1); assert c7 == DigitAt(allcarries, si+i); assert co == ei; } else { assert false; } } forall (i | 0<=i<8) ensures DigitAt(s, si+i) + DigitAt(loopcarries, i) * 0x100000000 == DigitAt(a, ai+i) + DigitAt(b, bi+i) + DigitAt(allcarries, si+i); { var va := DigitAt(a, ai+i); var vb := DigitAt(b, bi+i); var vs := DigitAt(s, si+i); var ci := DigitAt(allcarries, si+i); var cox := DigitAt(allcarries, si+i+1); lemma_mod0x100000000(va + vb + ci); var fs := (va+vb+ci); assert 0 <= fs < 0x200000000; assert vs == fs % 0x100000000; assert cox == if fs >= 0x100000000 then 1 else 0; assert cox == fs/0x100000000; lemma_fundamental_div_mod_converse(fs, 0x100000000, cox, vs); assert vs + cox*0x100000000 == fs; } } lemma lemma_FatNatAddUnrolledLoop_DigitSeq_preservation(oldc:seq, sc:seq, j:int) requires |oldc|==|sc|; requires 0<=j<|oldc|; requires IsDigitSeq(power2(32), oldc[|oldc|-j..]); requires forall i :: 0<=i<|sc| && !(j<=i sc[|sc|-1-i]==oldc[|sc|-1-i]; ensures IsDigitSeq(power2(32), sc[|sc|-j..]); { var pv:=power2(32); forall (i | 0<=i s[s.Length-1-i]==old(s[s.Length-1-i]); assert 0<=ri<|sc| && !(j<=ri, b:array) returns (c:array) requires a!=null; requires b!=null; requires IsDigitSeq(power2(32), a[..]); requires IsDigitSeq(power2(32), b[..]); ensures c!=null; ensures IsDigitSeq(power2(32), c[..]); ensures BEWordSeqToInt(a[..]) + BEWordSeqToInt(b[..]) == BEWordSeqToInt(c[..]); ensures fresh(c); { var maxlen := if a.Length > b.Length then a.Length else b.Length; var padding := if (maxlen%8==0) then 0 else 8 - maxlen % 8; var paddedlen := maxlen + padding; assert paddedlen % 8 == 0; //- OBSERVE lemma_2toX(); var apad := PadArrayLeft(paddedlen-a.Length, a); lemma_LeadingZeros(power2(32), a[..], apad[..]); var bpad := PadArrayLeft(paddedlen-b.Length, b); lemma_LeadingZeros(power2(32), b[..], bpad[..]); c := FatNatAddUnrolledLoop(apad, bpad); } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/FatNat/FatNatCommon.i.dfy ================================================ include "../Util/seqs_and_ints.i.dfy" include "../Util/seqs_common.i.dfy" include "../BigNum/BigNatX86Shim.i.dfy" include "CanonicalArrays.i.dfy" function FatNatAddIndex(L:int, index:int, i:int) : int { L - 1 - (index + i) } //- Treat i as a "little-endian index", so LEDigitAt(0) is the least-valued, //- rightmost digit in a BE sequence. static function method DigitAt(a:seq, i:int) : int { if (0 <= i < |a|) then a[|a|-1-i] else 0 } //- SelectDigitRange(a, 1, 0) is the bottom digit of a BEDigitSeq //- (just as a[0..1] is the bottom digit of a LEDigitSeq). function method SelectDigitRange(a:seq, i:int, j:int) : seq requires 0<=j<=i<=|a|; { a[|a|-i..|a|-j] } lemma lemma_SelectSingletonRange(a:seq, i:int, j:int) requires 0<=j<|a|; requires i==j+1; ensures SelectDigitRange(a,i,j)==[DigitAt(a,j)]; { calc { SelectDigitRange(a, i, j); a[|a|-i..|a|-j]; [a[|a|-i]]; [a[|a|-1-j]]; [DigitAt(a, j)]; } } lemma lemma_SelectDigitNest(a:seq, h1:int, l1:int, h0:int, l0:int) requires 0<=l1<=h1<=|a|; requires 0<=l0<=h0<=(h1-l1); ensures SelectDigitRange(SelectDigitRange(a, h1, l1), h0, l0) == SelectDigitRange(a, h0+l1, l0+l1); { var inner := SelectDigitRange(a, h1, l1); assert inner == a[|a|-h1..|a|-l1]; var outer := SelectDigitRange(inner, h0, l0); assert outer == inner[|inner|-h0..|inner|-l0]; assert |inner| == h1-l1; var p := |a|-h1; var q := |a|-l1; var r := h1-l1-h0; var s := h1-l1-l0; assert |a[p..q][r..s]| == |a[p+r..p+s]|; forall (i | 0<=i<|a[p+r..p+s]|) ensures a[p..q][r..s][i] == a[p+r..p+s][i]; { //- OBSERVE SEQ wow, Dafny really needed teeth pulled here! } assert a[p..q][r..s] == a[p+r..p+s]; //- calc { //- SelectDigitRange(SelectDigitRange(a, h1, l1), h0, l0); //- SelectDigitRange(inner, h0, l0); //- a[|a|-h1..|a|-l1][h1-l1-h0..h1-l1-l0]; //- a[p..q][r..s]; //- a[p+r..p+s]; //- a[h1-l1-h0+|a|-h1..h1-l1-l0+|a|-h1]; //- a[|a|-(h0+l1)..|a|-(l0+l1)]; //- SelectDigitRange(a, h0+l1, l0+l1); //- } } lemma lemma_BEInterpretation_Select(pv:int, A:seq, i:int) //- i counts from right (in LE order) requires 1, h:int, m:int, l:int) requires 0<=l<=m<=h<=|a|; ensures SelectDigitRange(a, h, l) == SelectDigitRange(a, h, m) + SelectDigitRange(a, m, l); { } //- Note that SelectDigits(a,0) == []. function method SelectDigits(a:seq, i:int) : seq requires 0<=i<=|a|; ensures SelectDigits(a,i) == SelectDigitRange(a,i,0); { a[|a|-i..] } function {:opaque} MaxLen_def(ss:seq>) : int decreases |ss|; { if (|ss|==0) then 0 else var carlen := |ss[0]|; var cdrlen := MaxLen_def(ss[1..]); if (carlen > cdrlen) then carlen else cdrlen } lemma lemma_MaxLen(ss:seq>) ensures forall i :: 0<=i<|ss| ==> |ss[i]| <= MaxLen_def(ss); ensures |ss|>0 ==> exists i :: 0<=i<|ss| && |ss[i]|==MaxLen_def(ss); { reveal_MaxLen_def(); if (|ss|==0) { } else { var cdr := ss[1..]; lemma_MaxLen(cdr); var carlen := |ss[0]|; var cdrlen := MaxLen_def(cdr); var i; if (carlen > cdrlen) { i := 0; assert 0<=i<|ss| && |ss[i]|==MaxLen_def(ss); } else if (|cdr|==0) { i := 0; assert 0<=i<|ss| && |ss[i]|==MaxLen_def(ss); } else { assert |cdr|>0; assert exists j :: 0<=j<|cdr| && |cdr[j]|==MaxLen_def(cdr); var j :| 0<=j<|cdr| && |cdr[j]|==MaxLen_def(cdr); i := j+1; assert 0<=i<|ss| && |ss[i]|==MaxLen_def(ss); } forall (i | 0<=i<|ss|) ensures |ss[i]| <= MaxLen_def(ss); { if (i==0) { } else { assert cdr[i-1] == ss[i]; } } } } function MaxLen(ss:seq>) : int ensures forall i :: 0<=i<|ss| ==> |ss[i]| <= MaxLen(ss); ensures |ss|>0 ==> exists i :: 0<=i<|ss| && |ss[i]|==MaxLen(ss); { lemma_MaxLen(ss); MaxLen_def(ss) } function MaxLen3(a:seq, b:seq, c:seq) : int ensures |a| <= MaxLen3(a,b,c); ensures |b| <= MaxLen3(a,b,c); ensures |c| <= MaxLen3(a,b,c); ensures |a|==MaxLen3(a,b,c) || |b|==MaxLen3(a,b,c) || |c|==MaxLen3(a,b,c); { var s3 := [a,b,c]; assert a == s3[0]; assert b == s3[1]; assert c == s3[2]; MaxLen(s3) } function Stretch(s:seq, len:int) : seq requires |s| <= len; { RepeatDigit_premium(0, len-|s|) + s } //-//////////////////////////////////////////////////////////////////////////// //- Array access static function method ArrayDigitAt(a:array, i:int) : int requires a!=null; reads a; ensures ArrayDigitAt(a,i) == DigitAt(a[..],i); { if (0 <= i < a.Length) then a[a.Length-1-i] else 0 } function method ArrayDigitAt_add(a:array, i:int) : int requires a!=null; reads a; ensures ArrayDigitAt_add(a,i) == DigitAt(a[..],i); { if (0 <= i < a.Length) then a[a.Length-1-i] else 0 } function method ArrayDigitAt_sub(a:array, i:int) : int requires a!=null; reads a; ensures ArrayDigitAt_sub(a,i) == DigitAt(a[..],i); { if (0 <= i < a.Length) then a[a.Length-1-i] else 0 } function method ArrayDigitAt_cmp(a:array, i:int) : int requires a!=null; reads a; ensures ArrayDigitAt_cmp(a,i) == DigitAt(a[..],i); { if (0 <= i < a.Length) then a[a.Length-1-i] else 0 } function method ArrayDigitAt_mul(a:array, i:int) : int requires a!=null; reads a; ensures ArrayDigitAt_mul(a,i) == DigitAt(a[..],i); { if (0 <= i < a.Length) then a[a.Length-1-i] else 0 } predicate {:heap} WellformedFatNat(X:array) //- Word-specific wellformedness. reads X; { X!=null && IsWordSeq(X[..]) } function {:heap} J(X:array) : int reads X; requires WellformedFatNat(X); ensures 0<=J(X); { lemma_BEDigitSeqToInt_bound(power2(32), X[..]); BEWordSeqToInt(X[..]) } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/FatNat/FatNatCompare.i.dfy ================================================ include "../Util/seqs_common.i.dfy" include "FatNatCommon.i.dfy" include "CanonicalArrays.i.dfy" datatype Cmp = CmpLt | CmpEq | CmpGt; predicate DefCmp(a:int, cmp:Cmp, b:int) { (cmp==CmpLt <==> (a < b)) && (cmp==CmpEq <==> (a == b)) && (cmp==CmpGt <==> (a > b)) } lemma lemma_FNCompare_inner_core_eq(pv:int, As:seq, Bs:seq, i:int, da:int, db:int) requires pv==power2(32); requires IsWordSeq(As); requires IsWordSeq(Bs); requires |As| == |Bs|; requires 0 < i <= |Bs|; requires DigitAt(As,i-1) == da; requires DigitAt(Bs,i-1) == db; requires BEDigitSeqToInt(pv, SelectDigitRange(As, |As|, i)) == BEDigitSeqToInt(pv, SelectDigitRange(Bs, |Bs|, i)); requires da==db; ensures BEDigitSeqToInt(pv, SelectDigitRange(As, |As|, i-1)) == BEDigitSeqToInt(pv, SelectDigitRange(Bs, |Bs|, i-1)); { ghost var Ass := SelectDigitRange(As, |As|, i); ghost var Asl := SelectDigitRange(As, |As|, i-1); ghost var Bss := SelectDigitRange(Bs, |Bs|, i); ghost var Bsl := SelectDigitRange(Bs, |Bs|, i-1); calc { Asl[|Asl|-1]; DigitAt(As,i-1); DigitAt(Bs,i-1); Bsl[|Bsl|-1]; } calc { BEDigitSeqToInt(pv, Asl); { reveal_BEDigitSeqToInt_private(); assert Asl[0..|Asl|-1] == Asl[..|Asl|-1]; //- OBSERVE SEQ assert Asl[..|Asl|-1] == Ass; //- OBSERVE SEQ } BEDigitSeqToInt(pv, Ass)*pv + Asl[|Asl|-1]; BEDigitSeqToInt(pv, Bss)*pv + Bsl[|Bsl|-1]; { reveal_BEDigitSeqToInt_private(); assert Bsl[0..|Bsl|-1] == Bsl[..|Bsl|-1]; //- OBSERVE SEQ assert Bsl[..|Bsl|-1] == Bss; //- OBSERVE SEQ } BEDigitSeqToInt(pv, Bsl); } } lemma lemma_FNCompare_inner_core_lt(pv:int, As:seq, Bs:seq, i:int, da:int, db:int) requires pv==power2(32); requires IsWordSeq(As); requires IsWordSeq(Bs); requires |As| == |Bs|; requires 0 < i <= |Bs|; requires DigitAt(As,i-1) == da; requires DigitAt(Bs,i-1) == db; requires BEDigitSeqToInt(pv, SelectDigitRange(As, |As|, i)) == BEDigitSeqToInt(pv, SelectDigitRange(Bs, |Bs|, i)); requires da, b:array) returns (cmp:Cmp) requires a!=null; requires IsWordSeq(a[..]); requires b!=null; requires IsWordSeq(b[..]); requires a.Length<=b.Length; ensures (cmp==CmpLt) <==> (BEWordSeqToInt(a[..]) < BEWordSeqToInt(b[..])); ensures (cmp==CmpEq) <==> (BEWordSeqToInt(a[..]) == BEWordSeqToInt(b[..])); ensures (cmp==CmpGt) <==> (BEWordSeqToInt(a[..]) > BEWordSeqToInt(b[..])); { lemma_2to32(); ghost var pv := power2(32); ghost var Bs := b[..]; ghost var As_short := a[..]; ghost var As := RepeatDigit_premium(0,b.Length-a.Length) + As_short; lemma_LeadingZeros(pv, As_short, As); assert BEWordSeqToInt(As_short) == BEWordSeqToInt(As); //- assert |Bs|==b.Length; //- assert |As|==|Bs|; if (b.Length==0) { cmp := CmpEq; reveal_BEDigitSeqToInt_private(); return; } assert 0<|Bs|; var i_plus_one := b.Length+1; //- DafnyCC ints can't go negative! ghost var i := |Bs|; assert As[..0] == []; //- OBSERVE SEQ assert Bs[..0] == []; //- OBSERVE SEQ //- i is the number of digits, starting from MSW, not yet known to be equal. //- If As==[x y z] and i==1, then As[0]==x==Bs[0], //- and da==As[1]==y and db==Bs[1]==y'. while (i_plus_one > 0+1) invariant 0+1 <= i_plus_one <= |Bs|+1; invariant i_plus_one == i+1; invariant 0 <= i <= |Bs|; invariant As_short == a[..]; invariant Bs == b[..]; invariant BEDigitSeqToInt(pv, SelectDigitRange(As, |As|, i)) == BEDigitSeqToInt(pv, SelectDigitRange(Bs, |Bs|, i)); { var da := ArrayDigitAt_cmp(a, i_plus_one-1-1); var db := ArrayDigitAt_cmp(b, i_plus_one-1-1); if (da < db) { cmp := CmpLt; lemma_FNCompare_inner_core_lt(pv, As, Bs, i, da, db); return; } if (db < da) { cmp := CmpGt; lemma_FNCompare_inner_core_lt(pv, Bs, As, i, db, da); return; } lemma_FNCompare_inner_core_eq(pv, Bs, As, i, db, da); i_plus_one := i_plus_one - 1; i := i - 1; } cmp := CmpEq; assert i==0; assert As==As[0..|As|]; //- OBSERVE SEQ assert Bs==Bs[0..|Bs|]; //- OBSERVE SEQ assert BEWordSeqToInt(a[..]) == BEWordSeqToInt(b[..]); } method FatNatCompare(a:array, b:array) returns (cmp:Cmp) requires a!=null; requires IsWordSeq(a[..]); requires b!=null; requires IsWordSeq(b[..]); ensures (cmp.CmpLt?) <==> (BEWordSeqToInt(a[..]) < BEWordSeqToInt(b[..])); ensures (cmp.CmpEq?) <==> (BEWordSeqToInt(a[..]) == BEWordSeqToInt(b[..])); ensures (cmp.CmpGt?) <==> (BEWordSeqToInt(a[..]) > BEWordSeqToInt(b[..])); { if (a.Length > b.Length) { var neg_cmp := FNCompare_inner(b, a); match neg_cmp { case CmpEq => cmp := CmpEq; case CmpLt => cmp := CmpGt; case CmpGt => cmp := CmpLt; } } else { cmp := FNCompare_inner(a, b); } } method FatNatLt(a:array, b:array) returns (rc:bool) requires WellformedFatNat(a); requires WellformedFatNat(b); ensures rc <==> (BEWordSeqToInt(a[..]) < BEWordSeqToInt(b[..])); { var cv := FatNatCompare(a, b); rc := cv.CmpLt?; } method FatNatLe(a:array, b:array) returns (rc:bool) requires WellformedFatNat(a); requires WellformedFatNat(b); ensures rc <==> (BEWordSeqToInt(a[..]) <= BEWordSeqToInt(b[..])); { var cv := FatNatCompare(a, b); rc := cv.CmpEq? || cv.CmpLt?; } method FatNatEq(a:array, b:array) returns (rc:bool) requires WellformedFatNat(a); requires WellformedFatNat(b); ensures rc <==> (BEWordSeqToInt(a[..]) == BEWordSeqToInt(b[..])); { var cv := FatNatCompare(a, b); rc := cv.CmpEq?; } method FatNatGe(a:array, b:array) returns (rc:bool) requires WellformedFatNat(a); requires WellformedFatNat(b); ensures rc <==> (BEWordSeqToInt(a[..]) >= BEWordSeqToInt(b[..])); { var cv := FatNatCompare(a, b); rc := cv.CmpEq? || cv.CmpGt?; } method FatNatGt(a:array, b:array) returns (rc:bool) requires WellformedFatNat(a); requires WellformedFatNat(b); ensures rc <==> (BEWordSeqToInt(a[..]) > BEWordSeqToInt(b[..])); { var cv := FatNatCompare(a, b); rc := cv.CmpGt?; } method TestEqSmallLiteralFatNat(x:nat, X:array) returns (rc:bool) requires IsWord(x); requires WellformedFatNat(X); ensures rc <==> J(X)==x; { if (X.Length==0) { reveal_BEDigitSeqToInt_private(); assert J(X)==0; rc := x==0; } else if (X.Length==1) { lemma_2toX(); lemma_BEDigitSeqToInt_singleton(power2(32), X[0]); assert X[..] == [X[0]]; //- OBSERVE SEQ assert J(X)==X[0]; rc := x==X[0]; } else { var probe := MakeBELiteralArray(x); rc := FatNatEq(probe, X); } } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/FatNat/FatNatDiv.i.dfy ================================================ include "../Util/seqs_canonical.i.dfy" include "FatNatDivDefs.i.dfy" include "FatNatDivEstTrivial.i.dfy" include "FatNatDivEstDiv32.i.dfy" include "FatNatReciprocal.i.dfy" include "../FleetNat/FleetNatMul.i.dfy" include "../FleetNat/FleetNatSub.i.dfy" include "CanonicalArrays.i.dfy" method FNDivision_init(n:array, dv:array) returns (d:FNDivData, ghost g:FNDivGhost) requires n!=null; requires IsWordSeq(n[..]); //- requires n.Length < power2(27); requires dv!=null; requires IsWordSeq(dv[..]); requires 1, r:array) requires FNDivision_invariant(d, g); requires BEWordSeqToInt(g.Rs) < BEWordSeqToInt(g.Ds); ensures q!=null; ensures r!=null; ensures FNDivision_invariant(d, g); //- we don't lose any structure here ensures IsWordSeq(q[..]); ensures IsWordSeq(r[..]); ensures 0 <= BEWordSeqToInt(r[..]) < BEWordSeqToInt(d.dv[..]); ensures BEWordSeqToInt(d.n[..]) == BEWordSeqToInt(d.dv[..]) * BEWordSeqToInt(q[..]) + BEWordSeqToInt(r[..]); { q := d.q; r := d.r; lemma_BEDigitSeqToInt_bound(power2(32), r[..]); lemma_mul_is_commutative_forall(); } method FNDivision_trivial(n:array, dv:array) returns (success:bool, q:array, r:array) requires n!=null; requires dv!=null; requires IsWordSeq(n[..]); requires IsWordSeq(dv[..]); ensures !success ==> 1!=BEWordSeqToInt(dv[..]); ensures success ==> q!=null && IsWordSeq(q[..]); ensures success ==> r!=null && IsWordSeq(r[..]); ensures success ==> 0 <= BEWordSeqToInt(r[..]) < BEWordSeqToInt(dv[..]); ensures success ==> BEWordSeqToInt(n[..]) == BEWordSeqToInt(dv[..]) * BEWordSeqToInt(q[..]) + BEWordSeqToInt(r[..]); ensures success ==> BEWordSeqToInt(q[..]) == BEWordSeqToInt(n[..]) / BEWordSeqToInt(dv[..]); ensures success ==> BEWordSeqToInt(r[..]) == BEWordSeqToInt(n[..]) % BEWordSeqToInt(dv[..]); ensures n[..]==old(n[..]); ensures dv[..]==old(dv[..]); { lemma_2toX(); var one := MakeBELiteralArray(1); ghost var ones := one[..]; assert BEWordSeqToInt(ones) == 1; ghost var divs := dv[..]; var one_cmp:Cmp := FatNatCompare(one, dv); if (one_cmp.CmpEq?) { success := true; q := n; r := new int[0]; reveal_BEDigitSeqToInt_private(); lemma_mul_basics_forall(); lemma_mul_is_commutative(BEWordSeqToInt(dv[..]), BEWordSeqToInt(q[..])); lemma_fundamental_div_mod_converse(BEWordSeqToInt_premium(n[..]), BEWordSeqToInt_premium(dv[..]), BEWordSeqToInt_premium(q[..]), BEWordSeqToInt_premium(r[..])); return; } else { q := new int[0]; //- dafnycc. r := q; success := false; } } method FatNatDivUsingReciprocal(n:array, dv:array, reciprocal:FNDivReciprocal) returns (q:array, r:array) requires n!=null; requires dv!=null; //- requires n.Length < power2(27); requires IsWordSeq(n[..]); requires IsWordSeq(dv[..]); requires 0 (BEWordSeqToInt(g.Rs) < BEWordSeqToInt(g.Ds)); decreases BEWordSeqToInt(d.r[..]); { ghost var old_d := d; d,g := FNDivision_step(d,g,reciprocal); var r_ref := d.r; //- do something real to d.r to convince dafyncc it's allocated var q_ref := d.q; //- do something real to d.q to convince dafyncc it's allocated assert BEWordSeqToInt(d.r[..]) < BEWordSeqToInt(old_d.r[..]); //- OBSERVE r_d_cmp := FatNatCompare(d.r, d.dv); } q,r := FNDivision_conclusion(d, g); assert n[..] == g.Ns; //- OBSERVE assert dv[..] == g.Ds; //- OBSERVE lemma_mul_is_commutative(BEWordSeqToInt(dv[..]), BEWordSeqToInt(q[..])); lemma_fundamental_div_mod_converse(BEWordSeqToInt_premium(n[..]), BEWordSeqToInt_premium(dv[..]), BEWordSeqToInt_premium(q[..]), BEWordSeqToInt_premium(r[..])); } method FatNatDiv(n:array, dv:array) returns (q:array, r:array) requires n!=null; requires dv!=null; //- requires n.Length < power2(27); requires IsWordSeq(n[..]); requires IsWordSeq(dv[..]); requires 0) requires |s| > 0; requires s[0] == 1; requires forall i :: 1 <= i < |s| ==> s[i] == 0; requires IsWordSeq(s); ensures BEWordSeqToInt(s) == power2(32*(|s|-1)); { calc { BEWordSeqToInt(s); { reveal_BEDigitSeqToInt_private(); } BEWordSeqToInt(s[0..|s|-1])*power2(32) + s[|s|-1]; { assert s[0..|s|-1] == s[..|s|-1]; } BEWordSeqToInt(s[..|s|-1])*power2(32) + s[|s|-1]; } if |s| == 1 { calc { BEWordSeqToInt(s[..|s|-1])*power2(32) + s[|s|-1]; { assert s[..|s|-1] == []; } BEWordSeqToInt([])*power2(32) + s[|s|-1]; { reveal_BEDigitSeqToInt_private(); } { lemma_mul_is_mul_boogie(0, power2(32)); } 0*power2(32) + s[|s|-1]; s[|s|-1]; s[0]; 1; { reveal_power2(); } power2(0); power2(32*(|s|-1)); } } else { calc { BEWordSeqToInt(s[..|s|-1])*power2(32) + s[|s|-1]; BEWordSeqToInt(s[..|s|-1])*power2(32); { Lemma_OneFollowedByxZeroesIsPower2To32x(s[..|s|-1]); } power2(32*(|s|-2)) * power2(32); { lemma_power2_adds(32*(|s|-2), 32); } power2(32*(|s|-2) + 32); power2(32*(|s|-1)); } } } method FatNatPower2To32x(x:nat) returns (q:array) ensures fresh(q); ensures q != null; ensures IsWordSeq(q[..]); ensures BEWordSeqToInt(q[..]) == power2(32 * x); { q := new int[x+1]; q[0] := 1; lemma_2toX(); var i := 1; while i < q.Length invariant 1 <= i <= q.Length; invariant q[0] == 1; invariant forall j :: 1 <= j < i ==> q[j] == 0; invariant IsWordSeq(q[..i]); { q[i] := 0; i := i + 1; } assert q[..] == q[..q.Length]; Lemma_OneFollowedByxZeroesIsPower2To32x(q[..]); } method FatNatComputeReciprocal(dv:array) returns (reciprocal:FNDivReciprocal) requires dv != null; requires IsWordSeq(dv[..]); requires BEWordSeqToInt(dv[..]) > 0; ensures reciprocal.FNDivKnownReciprocal?; ensures FNDivReciprocalValid(reciprocal, dv); { var w := dv.Length * 2; var two_to_32w := FatNatPower2To32x(w); var q,r := FatNatDiv(two_to_32w, dv); reciprocal := FNDivKnownReciprocal(w, q); } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/FatNat/FatNatDivDefs.i.dfy ================================================ include "FatNatCommon.i.dfy" include "FatNatMul.i.dfy" include "FatNatSub.i.dfy" include "FatNatCompare.i.dfy" include "../Util/seqs_canonical.i.dfy" datatype FNDivData = FNDivData_c( n:array, dv:array, r:array, q:array); datatype FNDivGhost = FNDivGhost_c( Ns:seq, Ds:seq, Rs:seq, Qs:seq, wks:seq, remainders:seq); predicate {:heap} FNDivision_invariant(d:FNDivData, g:FNDivGhost) reads d.n; reads d.dv; reads d.r; reads d.q; { d.n != null && d.dv != null && d.r != null && d.n[..] == g.Ns && d.dv[..] == g.Ds && d.r[..] == g.Rs && d.q != null && d.q[..] == g.Qs && IsWordSeq(g.Ns) && IsWordSeq(g.Ds) && IsWordSeq(g.Rs) //- && IsCanonicalDigitSeq(power2(32), g.Rs) //- && |g.Ns| < power2(27) && BEWordSeqToInt(g.Rs) <= BEWordSeqToInt(g.Ns) && IsWordSeq(g.Qs) && 1 < BEWordSeqToInt(g.Ds) && FNMulProblemValid_partial(g.wks, BEWordSeqToInt(g.Ds), 0) && |g.wks| == |g.remainders| && g.remainders[|g.remainders|-1] == BEWordSeqToInt(g.Rs) && g.wks[|g.wks|-1].a_partial_sum == BEWordSeqToInt(g.Qs) && (forall i :: 0<=i<|g.wks| ==> g.wks[i].product + g.remainders[i] == BEWordSeqToInt(g.Ns)) //- && (forall i :: 1<=i<|g.wks| ==> //- g.wks[i].product + g.remainders[i] == g.wks[i-1].product + g.remainders[i-1]) } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/FatNat/FatNatDivEstDiv32.i.dfy ================================================ include "FatNatDivDefs.i.dfy" include "FatNatDivEstTrivial.i.dfy" include "Bitwise.i.dfy" include "WordBoundHack.i.dfy" method FNDivision_Estimate_Q_div32(n:array, dv:array) returns (q:array) requires n!=null; requires IsWordSeq(n[..]); requires dv!=null; requires IsWordSeq(dv[..]); requires 1 < BEWordSeqToInt(dv[..]) <= BEWordSeqToInt(n[..]); ensures q!=null; ensures IsWordSeq(q[..]); ensures 0 < BEWordSeqToInt(q[..])*BEWordSeqToInt(dv[..]); ensures BEWordSeqToInt(q[..])*BEWordSeqToInt(dv[..]) <= BEWordSeqToInt(n[..]); { lemma_2toX32(); ghost var Ns := n[..]; ghost var Nv := BEWordSeqToInt(Ns); ghost var Divs := dv[..]; ghost var Divv := BEWordSeqToInt(Divs); var n_approx,n_approx_exp := TakeTopBits(n, 32); assert n_approx == Nv / power2(n_approx_exp); assert 0 < BEWordSeqToInt(dv[..]); var div_approx,div_approx_exp := TakeTopBits(dv, 16); assert div_approx == Divv / power2(div_approx_exp); //- this step is redundant, since dv never changes. var div_approx_conservative := div_approx + 1; var q_approx,r_discard := Divide32(n_approx,div_approx_conservative); lemma_fundamental_div_mod_converse(n_approx,div_approx_conservative,q_approx,r_discard); assert q_approx == n_approx/div_approx_conservative; lemma_power_0(power2(32)); lemma_mul_basics_forall(); if (q_approx == 0) { //- this should only occur when n and d are very close //- (and hence n_approx_exp==d_approx_expr==0); //- otherwise, TakeBits(n) should be able to find more //- bits of n. q := FNDivision_Estimate_Q_trivial(n,dv); return; } calc { Divv; { lemma_fundamental_div_mod(Divv, power2(div_approx_exp)); } power2(div_approx_exp)*(Divv/power2(div_approx_exp))+Divv%power2(div_approx_exp); <= { lemma_mod_properties(); } power2(div_approx_exp)*(Divv/power2(div_approx_exp))+power2(div_approx_exp); { lemma_mul_is_distributive_add(power2(div_approx_exp), Divv/power2(div_approx_exp), 1); } power2(div_approx_exp)*(Divv/power2(div_approx_exp)+1); power2(div_approx_exp)*(div_approx+1); power2(div_approx_exp)*(div_approx_conservative); } calc { n_approx*power2(n_approx_exp); { lemma_mul_is_commutative(n_approx, power2(n_approx_exp)); } power2(n_approx_exp)*n_approx; power2(n_approx_exp)*(Nv/power2(n_approx_exp)); <= { lemma_mod_properties(); } power2(n_approx_exp)*(Nv/power2(n_approx_exp))+Nv%power2(n_approx_exp); { lemma_fundamental_div_mod(Nv, power2(n_approx_exp)); } Nv; } if (n_approx_exp >= div_approx_exp) { //- common case: n much bigger than d var q_approx_exp := n_approx_exp - div_approx_exp; var q_approx_ary := new int[1]; q_approx_ary[0] := q_approx; ghost var Qas := q_approx_ary[..]; ghost var Qav := BEWordSeqToInt(Qas); reveal_BEDigitSeqToInt_private(); calc { Qav; BEWordSeqToInt(Qas[0..|Qas|-1])*power(power2(32),0)+Qas[|Qas|-1]; BEWordSeqToInt([])*power(power2(32),0)+Qas[|Qas|-1]; mul(0,power(power2(32),0))+Qas[|Qas|-1]; Qas[|Qas|-1]; q_approx; } constrain_word_from_overflowing(q_approx_exp); //- if (power2(32)<=q_approx_exp) //- { //- calc { //- power2(power2(32)); //- <= { lemma_power2_increases(power2(32), n_approx_exp); } //- power2(n_approx_exp); //- <= { lemma_mul_increases(n_approx, power2(n_approx_exp)); } //- n_approx*power2(n_approx_exp); //- <= //- BEDigitSeqToInt(power2(32), Ns); //- < { lemma_BEDigitSeqToInt_bound(power2(32), Ns); } //- power(power2(32),|Ns|); //- { lemma_power2_unfolding(32, |Ns|); //- lemma_mul_is_mul_boogie(32, |Ns|); } //- power2(32*|Ns|); //- <= { lemma_power2_increases(32*|Ns|, 32*power2(27)); } //- power2(32*power2(27)); //- { lemma_2toX32(); lemma_mul_is_mul_boogie(32, power2(27)); } //- power2(power2(5)*power2(27)); //- { lemma_power2_adds(5, 27); } //- power2(power2(32)); //- } //- assert false; //- } assert IsWord(q_approx_exp); q := BitShiftLeft_Array(q_approx_ary, q_approx_exp); ghost var Qs := q[..]; ghost var Qv := BEWordSeqToInt(Qs); assert Qv == Qav * power2(q_approx_exp); assert 0 < q_approx; lemma_BEDigitSeqToInt_bound(power2(32), Qas); lemma_power2_positive(); lemma_mul_strictly_positive(BEWordSeqToInt(Qas), power2(q_approx_exp)); assert 0 < Qv; assert 0 < Divv; lemma_mul_strictly_positive(Qv,Divv); assert 0 < Qv*Divv; assert 0 < div_approx_conservative; assert 0 < power2(div_approx_exp); lemma_mul_strictly_positive(div_approx_conservative, power2(div_approx_exp)); calc { Qv; Qav * power2(q_approx_exp); q_approx * power2(q_approx_exp); (n_approx/div_approx_conservative)*power2(q_approx_exp); <= { lemma_mul_is_commutative(power2(q_approx_exp), n_approx/div_approx_conservative); lemma_mul_hoist_inequality(power2(q_approx_exp), n_approx, div_approx_conservative); lemma_mul_is_commutative(n_approx, power2(q_approx_exp)); } (n_approx*power2(q_approx_exp))/div_approx_conservative; { lemma_mul_nonnegative(n_approx, power2(q_approx_exp)); lemma_div_multiples_vanish_quotient(power2(div_approx_exp), n_approx*power2(q_approx_exp), div_approx_conservative); } (power2(div_approx_exp)*(n_approx*power2(q_approx_exp))) /(power2(div_approx_exp)*div_approx_conservative); // Commute (n_approx*power2(q_approx_exp)*power2(div_approx_exp)) /(power2(div_approx_exp)*div_approx_conservative); // Commute (n_approx*power2(q_approx_exp)*power2(div_approx_exp)) /(div_approx_conservative*power2(div_approx_exp)); { lemma_mul_is_associative(n_approx, power2(q_approx_exp), power2(div_approx_exp)); lemma_power2_adds(q_approx_exp,div_approx_exp); } (n_approx*power2(n_approx_exp)) /(div_approx_conservative*power2(div_approx_exp)); <= { lemma_div_is_ordered(n_approx*power2(n_approx_exp), Nv, div_approx_conservative*power2(div_approx_exp)); } Nv / (div_approx_conservative*power2(div_approx_exp)); <= { lemma_mul_is_commutative(div_approx_conservative, power2(div_approx_exp)); lemma_div_is_ordered_by_denominator(Nv, Divv, div_approx_conservative*power2(div_approx_exp)); } Nv / Divv; } calc { BEWordSeqToInt(Qs)*BEWordSeqToInt(Divs); Qv * Divv; <= { lemma_mul_inequality(Qv, Nv / Divv, Divv); lemma_mul_is_commutative(Nv / Divv, Divv); } Divv * (Nv / Divv); <= { lemma_mul_hoist_inequality(Divv, Nv, Divv); } (Divv * Nv) / Divv; { lemma_mul_is_commutative(Divv, Nv); lemma_div_multiples_vanish(Nv, Divv); } Nv; BEWordSeqToInt(Ns); } return; } //- n very nearly d; negative exponent implies some bits //- of result are actually describing the remainder, not the quotient. lemma_word32(q_approx); var neg_exp := div_approx_exp - n_approx_exp; assert 0 <= neg_exp; if (neg_exp >= 32) //- contradiction { calc { Nv; { lemma_fundamental_div_mod(Nv, power2(n_approx_exp)); } power2(n_approx_exp) * (Nv / power2(n_approx_exp)) + Nv % power2(n_approx_exp); <= { lemma_mod_properties(); } power2(n_approx_exp) * (Nv / power2(n_approx_exp)) + power2(n_approx_exp); power2(n_approx_exp) * n_approx + mul(power2(n_approx_exp),1); { lemma_mul_is_distributive(power2(n_approx_exp), n_approx, 1); } power2(n_approx_exp) * (n_approx + 1); <= { lemma_mul_inequality(n_approx + 1, power2(32), power2(n_approx_exp)); lemma_mul_is_commutative(power2(n_approx_exp), n_approx + 1); lemma_mul_is_commutative(power2(n_approx_exp), power2(32)); } power2(n_approx_exp) * power2(32); { lemma_power2_adds(n_approx_exp, 32); } power2(n_approx_exp + 32); <= { lemma_power2_increases(n_approx_exp+32, div_approx_exp); } power2(div_approx_exp); < { lemma_mul_strictly_increases( (Divv / power2(div_approx_exp)), power2(div_approx_exp)); assert 1 < (Divv / power2(div_approx_exp)); assert 0 < power2(div_approx_exp); } (Divv / power2(div_approx_exp)) * power2(div_approx_exp); { lemma_mul_is_commutative(power2(div_approx_exp), Divv / power2(div_approx_exp)); } power2(div_approx_exp) * (Divv / power2(div_approx_exp)); <= { lemma_mul_hoist_inequality(power2(div_approx_exp), Divv, power2(div_approx_exp)); } (power2(div_approx_exp) * Divv) / power2(div_approx_exp); { lemma_div_multiples_vanish(Divv, power2(div_approx_exp)); } Divv; } assert false; } assert 0 < div_approx_exp; var q_approx_scaled := BitShiftRight_Word(q_approx, neg_exp); assert q_approx_scaled == q_approx / power2(neg_exp); if (q_approx_scaled == 0) { q := FNDivision_Estimate_Q_trivial(n,dv); return; } lemma_word32(q_approx_scaled); q := new int[1]; q[0] := q_approx_scaled; ghost var Qs := q[..]; ghost var Qv := BEWordSeqToInt(Qs); assert Qs == [q_approx_scaled]; //- OBSERVE lemma_BEDigitSeqToInt_singleton(power2(32), q_approx_scaled); assert Qv == q_approx_scaled; lemma_mul_strictly_positive(Qv, Divv); assert 0 < BEWordSeqToInt(Qs)*BEWordSeqToInt(Divs); calc { Qv * Divv; <= { lemma_mul_is_commutative(Qv, Divv); lemma_mul_is_associative(Qv, power2(div_approx_exp), div_approx_conservative); lemma_mul_is_commutative(Qv, power2(div_approx_exp) * div_approx_conservative); lemma_mul_inequality(Divv, power2(div_approx_exp)*div_approx_conservative, Qv); } Qv * power2(div_approx_exp) * div_approx_conservative; { lemma_power2_adds(n_approx_exp, neg_exp); lemma_mul_is_associative(Qv, power2(n_approx_exp), power2(neg_exp)); } Qv * power2(n_approx_exp) * power2(neg_exp) * div_approx_conservative; (q_approx / power2(neg_exp)) * power2(n_approx_exp) * power2(neg_exp) * div_approx_conservative; { lemma_mul_is_associative(q_approx / power2(neg_exp), power2(n_approx_exp), power2(neg_exp)); } (q_approx / power2(neg_exp)) * (power2(n_approx_exp) * power2(neg_exp)) * div_approx_conservative; { lemma_mul_is_commutative(power2(n_approx_exp), power2(neg_exp)); } (q_approx / power2(neg_exp)) * (power2(neg_exp) * power2(n_approx_exp)) * div_approx_conservative; { lemma_mul_is_associative(q_approx / power2(neg_exp), power2(neg_exp), power2(n_approx_exp)); } (q_approx / power2(neg_exp)) * power2(neg_exp) * power2(n_approx_exp) * div_approx_conservative; { lemma_mul_is_commutative(q_approx / power2(neg_exp), power2(neg_exp)); } power2(neg_exp) * (q_approx / power2(neg_exp)) * power2(n_approx_exp) * div_approx_conservative; { lemma_mul_is_associative(power2(neg_exp) * (q_approx / power2(neg_exp)), power2(n_approx_exp), div_approx_conservative); } power2(neg_exp) * (q_approx / power2(neg_exp)) * (power2(n_approx_exp) * div_approx_conservative); <= { lemma_fundamental_div_mod(q_approx, power2(neg_exp)); lemma_mod_properties(); lemma_mul_nonnegative(power2(n_approx_exp), div_approx_conservative); lemma_mul_inequality( power2(neg_exp) * (q_approx / power2(neg_exp)), q_approx, (power2(n_approx_exp) * div_approx_conservative)); } q_approx * (power2(n_approx_exp) * div_approx_conservative); { lemma_mul_is_commutative(power2(n_approx_exp), div_approx_conservative); lemma_mul_is_associative(q_approx, div_approx_conservative, power2(n_approx_exp)); } q_approx * div_approx_conservative * power2(n_approx_exp); <= { calc { q_approx * div_approx_conservative; { lemma_mul_is_commutative(q_approx, div_approx_conservative); } div_approx_conservative * (n_approx / div_approx_conservative); <= { lemma_mul_hoist_inequality(div_approx_conservative, n_approx, div_approx_conservative); } (div_approx_conservative * n_approx) / div_approx_conservative; { lemma_div_multiples_vanish(n_approx, div_approx_conservative); } n_approx; } lemma_mul_inequality_forall(); } n_approx * power2(n_approx_exp); <= Nv; } assert BEWordSeqToInt(Qs)*BEWordSeqToInt(Divs) <= BEWordSeqToInt(n[..]); } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/FatNat/FatNatDivEstTrivial.i.dfy ================================================ include "FatNatDivDefs.i.dfy" //- The simplest possible estimator: it subtracts q=1 copy of dv at a time. //- Runtime is linear in the value of the final quotient. method FNDivision_Estimate_Q_trivial(n:array, dv:array) returns (q:array) requires n!=null; requires IsWordSeq(n[..]); requires dv!=null; requires IsWordSeq(dv[..]); requires 0 < BEWordSeqToInt(dv[..]) <= BEWordSeqToInt(n[..]); ensures q!=null; ensures IsWordSeq(q[..]); ensures 0 < BEWordSeqToInt(q[..])*BEWordSeqToInt(dv[..]); ensures BEWordSeqToInt(q[..])*BEWordSeqToInt(dv[..]) <= BEWordSeqToInt(n[..]); { ghost var Divs := dv[..]; q := new int[1]; q[0] := 1; ghost var Qs := q[..]; lemma_2toX(); ghost var Qv := BEWordSeqToInt(Qs); reveal_BEDigitSeqToInt_private(); lemma_mul_basics_forall(); assert Qs[0..|Qs|-1] == []; //- OBSERVE assert Qv == BEWordSeqToInt(Qs[0..|Qs|-1])*power2(32) + Qs[|Qs|-1]; //- OBSERVE assert Qv == 1; calc { BEWordSeqToInt(q[..])*BEWordSeqToInt(dv[..]); BEWordSeqToInt(Qs)*BEWordSeqToInt(Divs); Qv*BEWordSeqToInt(Divs); BEWordSeqToInt(Divs); BEWordSeqToInt(dv[..]); } lemma_BEDigitSeqToInt_bound(power2(32), Qs); lemma_BEDigitSeqToInt_bound(power2(32), Divs); assert 0 < BEWordSeqToInt(q[..]); assert 0 < BEWordSeqToInt(dv[..]); lemma_mul_strictly_positive(BEWordSeqToInt(q[..]), BEWordSeqToInt(dv[..])); } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/FatNat/FatNatMod.i.dfy ================================================ include "../Util/seqs_canonical.i.dfy" include "FatNatDiv.i.dfy" include "../FleetNat/FleetNatMUl.i.dfy" include "CanonicalArrays.i.dfy" include "WordBoundHack.i.dfy" method FatNatModuloUsingReciprocal(X:array, N:array, Nreciprocal:FNDivReciprocal) returns (R:array) requires X!=null && IsWordSeq(X[..]); requires N!=null && IsWordSeq(N[..]); //- requires X.Length < power2(27); requires 0 <= BEWordSeqToInt(X[..]); requires 0 < BEWordSeqToInt(N[..]); requires FNDivReciprocalValid(Nreciprocal, N); ensures R!=null && IsWordSeq(R[..]); ensures BEWordSeqToInt(X[..]) % BEWordSeqToInt(N[..]) == BEWordSeqToInt(R[..]); ensures BEWordSeqToInt(R[..]) < BEWordSeqToInt(N[..]); { ProfileTally(Tally_FatNatMod(), 1); var Q:array; Q,R := FatNatDivUsingReciprocal(X,N,Nreciprocal); lemma_mul_is_commutative_forall(); lemma_fundamental_div_mod_converse( BEWordSeqToInt(X[..]), BEWordSeqToInt(N[..]), BEWordSeqToInt(Q[..]), BEWordSeqToInt(R[..])); } method FatNatModulo(X:array, N:array) returns (R:array) requires X!=null && IsWordSeq(X[..]); requires N!=null && IsWordSeq(N[..]); //- requires X.Length < power2(27); requires 0 <= BEWordSeqToInt(X[..]); requires 0 < BEWordSeqToInt(N[..]); ensures R!=null && IsWordSeq(R[..]); ensures BEWordSeqToInt(X[..]) % BEWordSeqToInt(N[..]) == BEWordSeqToInt(R[..]); ensures BEWordSeqToInt(R[..]) < BEWordSeqToInt(N[..]); { R := FatNatModuloUsingReciprocal(X, N, FNDivUnknownReciprocal()); } lemma lemma_lengths_squared(pv:int, X:seq, Y:seq, e:nat, Z:seq) requires pv==power2(32); requires IsDigitSeq(pv, X); requires IsDigitSeq(pv, Y); //- requires 00) { lemma_mul_basics_forall(); calc { 0; < { lemma_power_positive(pv,|Z|-1); lemma_mul_strictly_positive(Z[0], power(pv,|Z|-1)); } Z[0]*power(pv,|Z|-1); <= { lemma_BEDigitSeqToInt_bound(pv, Z); } Zv; } assert false; } lemma_power2_positive(); } else { calc { Zv; Xv*Yv; <= { lemma_BEDigitSeqToInt_bound(pv, X); lemma_BEDigitSeqToInt_bound(pv, Y); lemma_mul_inequality(Xv, power(pv,|X|)-1, Yv); lemma_mul_inequality(Yv, power(pv,|Y|)-1, power(pv,|X|)-1); lemma_mul_is_commutative_forall(); } (power(pv, |X|)-1) * (power(pv,|Y|)-1); { lemma_mul_is_distributive_forall(); } power(pv, |X|)*(power(pv, |Y|)-1) - mul(1,(power(pv, |Y|)-1)); { lemma_mul_basics_forall(); } power(pv, |X|)*(power(pv, |Y|)-1) - (power(pv, |Y|)-1); < { reveal_BEDigitSeqToInt_private(); calc { 1; < pv; { lemma_power_1(pv); } power(pv,1); <= { lemma_power_increases(pv,1,|Y|); } power(pv,|Y|); } } power(pv, |X|)*(power(pv, |Y|)-1); { lemma_mul_is_distributive_forall(); } power(pv, |X|)*power(pv, |Y|)-mul(power(pv, |X|),1); { lemma_mul_basics_forall(); } power(pv, |X|)*power(pv, |Y|)-power(pv, |X|); <= { lemma_power_positive(pv, |X|); } power(pv, |X|)*power(pv, |Y|)-1; { lemma_power_adds(pv, |X|, |Y|); } power(pv, |X|+|Y|)-1; { lemma_power2_unfolding(32, |X|+|Y|); lemma_mul_is_mul_boogie(32, |X|+|Y|); } power2(32*(|X|+|Y|))-1; <= { calc { |X|+|Y|; < power2(e)+power2(e); { lemma_mul_is_mul_boogie(2,power2(e)); } mul(2,power2(e)); { lemma_power2_1_is_2(); } mul(power2(1),power2(e)); { lemma_power2_adds(1,e); } power2(e+1); } lemma_power2_increases(32*(|X|+|Y|), 32*power2(e+1)); } power2(32*power2(e+1)); { lemma_power2_unfolding(32, power2(e+1)); lemma_mul_is_mul_boogie(32, power2(e+1)); } power(pv, power2(e+1)); <= { lemma_power2_strictly_increases(e+1,e+2); lemma_power_increases(pv, power2(e+1), power2(e+2)-1); } power(pv, power2(e+2)-1); } lemma_CanonicalLengthBound(pv, Z, power2(e+2)-1); assert |Z| < power2(e+2); } } datatype FatNatModExp_data = FatNatModExp_data_c( bp2:int, B:array, E:array, N:array, R:array, ec:int, E1:array, one:array); datatype FatNatModExp_ghost = FatNatModExp_ghost_c( Bv:int, Ev:int, Nv:int, Rv:int, E1v:int, Onev:int); predicate FatNatRepresents(a:array, av:int) reads a; { a!=null && IsWordSeq(a[..]) && BEWordSeqToInt(a[..]) == av && 0<=BEWordSeqToInt(a[..]) } predicate {:heap} FatNatModExp_invariant(d:FatNatModExp_data, g:FatNatModExp_ghost) reads d.B; reads d.E; reads d.N; reads d.R; reads d.E1; reads d.one; { true && FatNatRepresents(d.B, g.Bv) //- && (d.B.Length < power2(25)) && g.Bv != 0 && FatNatRepresents(d.E, g.Ev) && (0 <= d.bp2 <= d.ec < power2(32)) && FatNatBitCount(d.E[..], d.ec) && FatNatRepresents(d.N, g.Nv) //- && (d.N.Length < power2(25)) && FatNatRepresents(d.R, g.Rv) //- && (IsCanonicalDigitSeq(power2(32), d.R[..])) && d.R != null && (IsWordSeq(d.R[..])) //- && (d.R.Length < power2(25)) && (g.Rv < g.Nv) && FatNatRepresents(d.E1, g.E1v) && (g.E1v < power2(d.bp2)) && FatNatRepresents(d.one, g.Onev) && g.Onev == 1 && ((power(g.Bv,g.E1v) * power(g.Rv,power2(d.bp2))) % g.Nv == power(g.Bv,g.Ev) % g.Nv) } method FatNatModExp_init( B:array, E:array, N:array) returns (d:FatNatModExp_data, ghost g:FatNatModExp_ghost) requires B!=null && IsWordSeq(B[..]); requires E!=null && IsWordSeq(E[..]); requires N!=null && IsWordSeq(N[..]); requires BEWordSeqToInt(B[..])!=0; requires 1 < BEWordSeqToInt(N[..]); //- requires BEWordSeqToInt(E[..]) < power2(power2(31)); //- requires B.Length < power2(25); //- requires N.Length < power2(25); ensures FatNatModExp_invariant(d, g); ensures d.B == B; ensures d.E == E; ensures d.N == N; { ghost var pv := power2(32); lemma_2toX32(); lemma_mul_basics_forall(); ghost var Bs := B[..]; ghost var Bv := BEWordSeqToInt(Bs); ghost var Es := E[..]; ghost var Ev := BEWordSeqToInt(Es); ghost var Ns := N[..]; ghost var Nv := BEWordSeqToInt(Ns); lemma_BEDigitSeqToInt_bound(pv, Bs); lemma_BEDigitSeqToInt_bound(pv, Es); lemma_BEDigitSeqToInt_bound(pv, Ns); var one := MakeBELiteralArray(1); ghost var Ones := one[..]; ghost var Onev := BEWordSeqToInt(Ones); var ec:nat := FatNatCountBits(E); constrain_word_from_overflowing(ec); //- if (power2(32) <= ec) //- { //- calc { //- power2(power2(31)); //- < { lemma_2toX32(); //- lemma_power2_strictly_increases(power2(31), power2(32)-1); } //- power2(power2(32)-1); //- <= { lemma_power2_increases(power2(32)-1, ec-1); } //- Ev; //- < //- power2(power2(31)); //- } //- assert false; //- } d := FatNatModExp_data_c(ec, B, E, N, one, ec, E, one); g := FatNatModExp_ghost_c(Bv, Ev, Nv, Onev, Ev, Onev); lemma_1_power(power2(ec)); } lemma {:heap} lemma_E_propagation(d:FatNatModExp_data, ghost g:FatNatModExp_ghost, E_subv:int, R_bigv:int, bp2':nat) requires FatNatModExp_invariant(d, g); requires 0, ghost E2v:int, R2:array, ghost R2v:int, R2modN:array, ghost R2modNv:int) returns (E_sub:array, ghost E_subv:int, R':array, ghost Rv':int) requires FatNatModExp_invariant(d, g); requires 0, ghost E2v:int, R2:array, ghost R2v:int, R2modN:array, ghost R2modNv:int) returns (E_sub:array, ghost E_subv:int, R':array, ghost Rv':int) requires FatNatModExp_invariant(d, g); requires 0 := FleetNatMul(d.R, d.R); //- nc == "non-canonical" ghost var R2ncv := BEWordSeqToInt(R2nc[..]); //- var R2 := CanonicalizeArray(R2nc; //- UNDONE length constraints var R2 := R2nc; ghost var R2v := BEWordSeqToInt(R2[..]); //- lemma_lengths_squared(pv, d.R[..], d.R[..], 25, R2[..]); //- assert R2.Length < power2(27); lemma_mul_nonnegative(g.Rv, g.Rv); var R2modN := FatNatModuloUsingReciprocal(R2, d.N, Nreciprocal); ghost var R2modNv := BEWordSeqToInt(R2modN[..]); lemma_BEDigitSeqToInt_bound(pv, R2modN[..]); var E2:array := BitShiftLeft_Array(d.one, bp2'); ghost var E2v := BEWordSeqToInt(E2[..]); calc { E2v; g.Onev*power2(bp2'); { lemma_mul_basics_forall(); } power2(bp2'); } var R':array; ghost var Rv':int; var E_sub:array; ghost var E_subv:int; var cmpE1E2 := FatNatCompare(d.E1, E2); var use_this_product:bool := (!cmpE1E2.CmpLt?); if (use_this_product) { E_sub,E_subv,R',Rv' := FatNatModExp_step_add(d, Nreciprocal, g, bp2', E2, E2v, R2, R2v, R2modN, R2modNv); } else { E_sub,E_subv,R',Rv' := FatNatModExp_step_noadd(d, g, bp2', E2, E2v, R2, R2v, R2modN, R2modNv); } R' := CanonicalizeArray(R'); var E1' := E_sub; d' := FatNatModExp_data_c(bp2', d.B, d.E, d.N, R', d.ec, E1', d.one); g' := FatNatModExp_ghost_c(g.Bv, g.Ev, g.Nv, Rv', BEWordSeqToInt(E1'[..]), g.Onev); lemma_BEDigitSeqToInt_bound(pv, d'.R[..]); //- lemma_CanonicalLength_inherit(pv, R'[..], d.N[..], power2(25)); } method FatNatModExp_conclusion(d:FatNatModExp_data, ghost g:FatNatModExp_ghost) requires FatNatModExp_invariant(d, g); requires d.bp2==0; //- loop termination condition ensures 0<=BEWordSeqToInt(d.E[..]); //- to meet precondition on next line ensures power(BEWordSeqToInt(d.B[..]),BEWordSeqToInt(d.E[..])) % BEWordSeqToInt(d.N[..]) == BEWordSeqToInt(d.R[..]); ensures BEWordSeqToInt(d.R[..]) < BEWordSeqToInt(d.N[..]); ensures FatNatModExp_invariant(d, g); { calc { power(g.Bv,g.Ev) % g.Nv; //- loop invariant mul(power(g.Bv,g.E1v), power(g.Rv,power2(d.bp2))) % g.Nv; { lemma_power2_0_is_1(); } //- loop termination mul(power(g.Bv,0), power(g.Rv,1)) % g.Nv; { lemma_power_0(g.Bv); lemma_power_1(g.Rv); } mul(1, g.Rv) % g.Nv; { lemma_mul_basics_forall(); } g.Rv % g.Nv; { lemma_small_mod(g.Rv, g.Nv); } g.Rv; } } method FatNatModExpUsingReciprocal(B:array, E:array, N:array, Nreciprocal:FNDivReciprocal) returns (R:array) requires B!=null && IsWordSeq(B[..]); requires E!=null && IsWordSeq(E[..]); requires N!=null && IsWordSeq(N[..]); requires BEWordSeqToInt(B[..])!=0; requires 1 < BEWordSeqToInt(N[..]); //- requires BEWordSeqToInt(E[..]) < power2(power2(31)); requires FNDivReciprocalValid(Nreciprocal, N); //- requires B.Length < power2(25); //- requires N.Length < power2(25); ensures R!=null; ensures IsWordSeq(R[..]); ensures 0<=BEWordSeqToInt(E[..]); //- to meet precondition on next line ensures power(BEWordSeqToInt(B[..]),BEWordSeqToInt(E[..])) % BEWordSeqToInt(N[..]) == BEWordSeqToInt(R[..]); ensures BEWordSeqToInt(R[..]) < BEWordSeqToInt(N[..]); { ProfileTally(Tally_FatNatModExp(), 1); var recip_ref := if Nreciprocal.FNDivKnownReciprocal? then Nreciprocal.TwoTo32wDividedByD else B; //- do something real to Nreciprocal.TwoTo32wDividedByD var d; ghost var g; d,g := FatNatModExp_init(B, E, N); var db_ref := d.B; //- do something real to d.B so dafnycc realizes it's allocated var de_ref := d.E; //- do something real to d.E so dafnycc realizes it's allocated var dn_ref := d.N; //- do something real to d.N so dafnycc realizes it's allocated var dr_ref := d.R; //- do something real to d.R so dafnycc realizes it's allocated var de1_ref := d.E1; //- do something real to d.E1 so dafnycc realizes it's allocated var done_ref := d.one; //- do something real to d.one so dafnycc realizes it's allocated while (d.bp2 != 0) decreases d.bp2; invariant d.B == B; invariant d.E == E; invariant d.N == N; invariant FatNatModExp_invariant(d, g); invariant IsWordSeq(d.R[..]); { d,g := FatNatModExp_step(d, Nreciprocal, g); db_ref := d.B; //- do something real to d.B so dafnycc realizes it's allocated de_ref := d.E; //- do something real to d.E so dafnycc realizes it's allocated dn_ref := d.N; //- do something real to d.N so dafnycc realizes it's allocated dr_ref := d.R; //- do something real to d.R so dafnycc realizes it's allocated de1_ref := d.E1; //- do something real to d.E1 so dafnycc realizes it's allocated done_ref := d.one; //- do something real to d.one so dafnycc realizes it's allocated //- print d.R.Length; //- print "\n"; } FatNatModExp_conclusion(d, g); R := d.R; } method FatNatModExp(B:array, E:array, N:array) returns (R:array) requires B!=null && IsWordSeq(B[..]); requires E!=null && IsWordSeq(E[..]); requires N!=null && IsWordSeq(N[..]); requires BEWordSeqToInt(B[..])!=0; requires 1 < BEWordSeqToInt(N[..]); //- requires BEWordSeqToInt(E[..]) < power2(power2(31)); //- requires B.Length < power2(25); //- requires N.Length < power2(25); ensures R!=null && IsWordSeq(R[..]); ensures 0<=BEWordSeqToInt(E[..]); //- to meet precondition on next line ensures power(BEWordSeqToInt(B[..]),BEWordSeqToInt(E[..])) % BEWordSeqToInt(N[..]) == BEWordSeqToInt(R[..]); ensures BEWordSeqToInt(R[..]) < BEWordSeqToInt(N[..]); { R := FatNatModExpUsingReciprocal(B, E, N, FNDivUnknownReciprocal()); } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/FatNat/FatNatModesty.i.dfy ================================================ include "FatNatCommon.i.dfy" include "Bitwise.i.dfy" predicate {:heap} ModestFatNatValue(X:array) reads X; { WellformedFatNat(X) && J(X) < power2(power2(31)) } method IsModestFatNat(X:array) returns (rc:bool) requires WellformedFatNat(X); ensures rc <==> ModestFatNatValue(X); { var xc := FatNatCountBits(X); rc := xc <= 0x80000000; lemma_2toX32(); if (rc) { lemma_power2_increases(xc, 0x80000000); } else { lemma_power2_increases(power2(31), xc-1); } } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/FatNat/FatNatMul.i.dfy ================================================ include "../Util/seqs_common.i.dfy" include "FatNatCommon.i.dfy" include "FatNatAddUnrolled.i.dfy" include "../FleetNat/FleetNatAdd.i.dfy" include "../Util/ProfileIfc.i.dfy" include "../Util/ProfileIfc.i.dfy" datatype MulRow = MulRow_c( a_fragment:int, a_partial_sum:int, product:int); predicate FNMulBase(row:MulRow) { row.a_partial_sum == row.a_fragment } predicate FNMulRelation(row:MulRow, b:int, r:int) { row.product == row.a_partial_sum * b + r } predicate FNMulNext(row:MulRow, row':MulRow) { row'.a_partial_sum == row'.a_fragment + row.a_partial_sum } predicate FNMulEnd(row:MulRow, p:int, a:int) { row.product == p && row.a_partial_sum == a } predicate FNMulProblemValid_partial(wks:seq, b:int, r:int) { 0<|wks| && (forall i :: 0<=i<|wks| ==> FNMulRelation(wks[i], b, r)) && FNMulBase(wks[0]) && (forall i :: 1<=i<|wks| ==> FNMulNext(wks[i-1], wks[i])) } predicate FNMulProblemValid(wks:seq, p:int, a:int, b:int, r:int) { FNMulProblemValid_partial(wks, b, r) && FNMulEnd(wks[|wks|-1], p, a) } lemma lemma_FNMultiplication(wks:seq, p:int, a:int, b:int, r:int) requires FNMulProblemValid(wks, p, a, b, r); ensures p == a * b + r; { } predicate FNMulRowReflectsBEDigits(pv:int, wks:seq, i:int, a:seq) requires 1, a:seq) requires 1 FNMulRowReflectsBEDigits(pv, wks, i, a) } predicate FNMulProblemReflectsBESeq(pv:int, wks:seq, p:seq, a:seq, b:seq, r:seq) requires 1, p:seq, a:seq, b:seq, r:seq) requires 1) requires right_zeros<=c; ensures a!=null; ensures fresh(a); ensures a.Length==c; ensures forall i :: 0<=i ArrayDigitAt(a, i)==0; { a := new int[c]; var j := 0; while (j < right_zeros) invariant 0 <= j <= right_zeros; invariant forall i :: 0<=i ArrayDigitAt(a, i)==0; { assert forall i :: 0<=i a[c-1-i]==ArrayDigitAt(a,i); //- OBSERVE a[c-1-j] := 0; j := j + 1; // BURNED AGAIN by lack of termination-checking (decreases)! } } datatype M1Data = M1Data_c(b:array, a:int, shiftd:int, pp:array, i:int, carry:int); datatype M1Ghost = M1Ghost_c(Bs:seq, Ps:seq); predicate {:heap} M1invariant(d:M1Data, g:M1Ghost) reads d.b; reads d.pp; { 0<=d.a DigitAt(g.Ps, j)==0) && IsDigitSeq(power2(32), SelectDigitRange(g.Ps, d.shiftd+d.i, d.shiftd)) && d.a * BEWordSeqToInt(SelectDigits(g.Bs, d.i)) == BEWordSeqToInt(SelectDigitRange(g.Ps, d.shiftd+d.i, d.shiftd)) + d.carry * power2(32*d.i) } method M1init(b:array, a:int, shiftd:int) returns (d:M1Data, ghost g:M1Ghost) requires b!=null; requires IsDigitSeq(power2(32), b[..]); requires 0<=a ArrayDigitAt(pp, i)==DigitAt(Ps,i); assert forall j :: 0<=j DigitAt(Ps, j)==0; d := M1Data_c(b, a, shiftd, pp, 0, 0); g := M1Ghost_c(b[..], pp[..]); assert Ps==pp[..]; lemma_mul_basics_forall(); reveal_BEDigitSeqToInt_private(); assert IsWordSeq(SelectDigits(g.Bs, d.i)); calc { BEWordSeqToInt(SelectDigits(g.Bs, d.i)); d.a*BEWordSeqToInt(g.Bs[|g.Bs|-d.i..|g.Bs|]); d.a*BEWordSeqToInt(g.Bs[|g.Bs|..|g.Bs|]); { assert g.Bs[|g.Bs|..|g.Bs|]==[]; } //- OBSERVE d.a*BEWordSeqToInt([]); 0; BEWordSeqToInt([]); { assert g.Ps[|g.Ps|-d.shiftd..|g.Ps|-d.shiftd]==[]; } //- OBSERVE BEWordSeqToInt(g.Ps[|g.Ps|-d.shiftd-d.i..|g.Ps|-d.shiftd]); BEWordSeqToInt(g.Ps[|g.Ps|-d.shiftd-d.i..|g.Ps|-d.shiftd]) + d.carry*power2(32*d.i); BEWordSeqToInt(SelectDigitRange(g.Ps, d.shiftd+d.i, d.shiftd)) + d.carry*power2(32*d.i); } } lemma lemma_M1step_a(g'Bs:seq, di:int, d'i:int, b':seq, t:seq, b:seq) requires IsWordSeq(g'Bs); requires 0<=di; requires di+1==d'i; requires d'i<=|g'Bs|; requires b'== SelectDigitRange(g'Bs, d'i, 0); requires t == SelectDigitRange(g'Bs, d'i, di); requires b == SelectDigitRange(g'Bs, di, 0); ensures b' == t+b; ensures b'[..|b'|-di] == t; ensures b'[|b'|-di..] == b; { assert b' == t+b; //- OBSERVE assert b'[..|b'|-di] == t; assert b'[|b'|-di..] == b; } method M1step(d:M1Data, ghost g:M1Ghost) returns (d':M1Data, ghost g':M1Ghost) requires M1invariant(d, g); requires d.i<|g.Bs|; modifies d.pp; ensures M1invariant(d', g'); ensures d'.pp == d.pp; ensures d'.a == d.a; ensures d'.shiftd == d.shiftd; ensures d'.b == d.b; { var dpp_ref := d.pp; //- do something real to d.pp so dafnycc will realize that d.pp is allocated, and thus that d.pp is unaffected by methods that don't affect allocated parts of the heap ghost var pv := power2(32); lemma_2toX(); var ml,mh := Product32(d.a, ArrayDigitAt_mul(d.b,d.i)); var sl,acarry := Add32_two_arguments(ml, d.carry); dpp_ref[dpp_ref.Length - 1 - d.shiftd - d.i] := sl; assert 0 <= acarry < 2; var zero,carry; carry,zero := Add32_two_arguments(mh, acarry); ghost var m := ml + mh*pv; lemma_mul_nonnegative(mh,pv); calc { m; d.a * ArrayDigitAt(d.b,d.i); <= { lemma_mul_inequality(d.a, pv-1, ArrayDigitAt(d.b,d.i)); } (pv-1) * ArrayDigitAt(d.b,d.i); { lemma_mul_is_commutative_forall(); } ArrayDigitAt(d.b,d.i) * (pv-1); <= { lemma_mul_inequality(ArrayDigitAt(d.b,d.i), pv-1, pv-1); } (pv-1) * (pv-1); { lemma_mul_is_distributive_forall(); } pv*(pv-1)-mul(1,pv-1); { lemma_mul_basics_forall(); } pv*(pv-1)-(pv-1); { lemma_mul_is_distributive_forall(); } pv*pv-mul(pv,1)-(pv-1); { lemma_mul_basics_forall(); } pv*pv-pv-pv+1; { lemma_mul_is_mul_boogie(2,pv); } pv*pv-mul(2,pv)+1; { lemma_mul_is_distributive_forall(); } (pv-2)*pv+1; } calc { mh; { lemma_fundamental_div_mod_converse(m, pv, mh, ml); } m / pv; <= { lemma_div_is_ordered(m, ((pv-2)*pv + 1), pv); } ((pv-2)*pv + 1) / pv; { lemma_mul_is_commutative_forall(); } (pv*(pv-2) + 1) / pv; { lemma_div_multiples_vanish_fancy(pv-2, 1, pv); } pv-2; } assert mh+acarry < pv; lemma_mul_is_mul_boogie(0x100000000,zero); assert zero==0; d' := M1Data_c(d.b, d.a, d.shiftd, d.pp, d.i+1, carry); g' := M1Ghost_c(d.b[..], d.pp[..]); forall (j | 0<=j0) { assert 0 <= le_range[j-1] < pv; calc { le_range[j-1]; be_range[j-1]; g.Ps[|g.Ps|-d.shiftd-d.i..|g.Ps|-d.shiftd][j-1]; g.Ps[|g.Ps|-d.shiftd-d.i+j-1]; g'.Ps[|g'.Ps|-d'.shiftd-d'.i+j]; be_range'[j]; le_range'[j]; } assert 0 <= le_range'[j] < pv; } } assert IsDigitSeq(power2(32), SelectDigitRange(g'.Ps, d'.shiftd+d'.i, d'.shiftd)); ghost var b' := SelectDigitRange(g'.Bs, d'.i, 0); ghost var t := SelectDigitRange(g'.Bs, d'.i, d.i); ghost var b := SelectDigitRange(g'.Bs, d.i, 0); lemma_M1step_a(g'.Bs, d.i, d'.i, b', t, b); //- nicknames for subsequences of the product sequence ghost var HL := SelectDigitRange(g'.Ps, d'.i+d.shiftd, d.shiftd); ghost var HM := SelectDigitRange(g'.Ps, d'.i+d.shiftd, d.i+d.shiftd); ghost var ML := SelectDigitRange(g'.Ps, d.i+d.shiftd, d.shiftd); assert ML == SelectDigitRange(g.Ps, d.i+d.shiftd, d.shiftd); //- OBSERVE assert IsDigitSeq(pv, ML); calc { d'.a * BEWordSeqToInt(SelectDigits(g'.Bs, d'.i)); d'.a * BEWordSeqToInt(SelectDigitRange(g'.Bs, d'.i, 0)); { lemma_BEInterpretation(pv, b', d.i);} d'.a *( BEWordSeqToInt(SelectDigitRange(g'.Bs, d'.i, d.i))*power(pv,d.i) + BEWordSeqToInt(SelectDigitRange(g'.Bs, d.i, 0))); { lemma_mul_is_distributive_forall(); lemma_mul_is_associative_forall(); } d'.a*BEWordSeqToInt(SelectDigitRange(g'.Bs, d'.i, d.i))*power(pv,d.i) + d'.a*BEWordSeqToInt(SelectDigitRange(g'.Bs, d.i, 0)); //- equal primed terms { assert d'.a==d.a; assert g'.Bs==g.Bs; //- OBSERVE } d.a*BEWordSeqToInt(SelectDigitRange(g.Bs, d'.i, d.i))*power(pv,d.i) + d.a*BEWordSeqToInt(SelectDigitRange(g.Bs, d.i, 0)); //- induction hypothesis and { lemma_power2_unfolding(32, d.i); lemma_mul_is_mul_boogie(32, d.i); } d.a*BEWordSeqToInt(SelectDigitRange(g.Bs, d'.i, d.i))*power(pv,d.i) + BEWordSeqToInt(SelectDigitRange(g.Ps, d.i+d.shiftd, d.shiftd)) + d.carry * power(pv,d.i); { lemma_mul_is_distributive_add_other_way(power(pv, d.i), d.a*BEWordSeqToInt(SelectDigitRange(g.Bs, d'.i, d.i)), d.carry); } (d.a*BEWordSeqToInt(SelectDigitRange(g.Bs, d'.i, d.i)) + d.carry)*power(pv,d.i) + BEWordSeqToInt(SelectDigitRange(g.Ps, d.i+d.shiftd, d.shiftd)); { reveal_BEDigitSeqToInt_private(); lemma_SelectSingletonRange(g.Bs, d'.i, d.i); var s := [DigitAt(g.Bs, d.i)]; assert s[0..|s|-1] == []; lemma_BEDigitSeqToInt_singleton(pv, DigitAt(g.Bs, d.i)); } (d.a*DigitAt(g.Bs,d.i) + d.carry)*power(pv,d.i) + BEWordSeqToInt(SelectDigitRange(g.Ps, d.i+d.shiftd, d.shiftd)); { //- apply the 32-bit multiplication: assert ml+mh*pv == d.a * ArrayDigitAt(d.b,d.i); assert ArrayDigitAt(d.b,d.i)==DigitAt(g.Bs,d.i); } (ml+mh*pv + d.carry)*power(pv,d.i) + BEWordSeqToInt(SelectDigitRange(g.Ps, d.i+d.shiftd, d.shiftd)); { lemma_mul_is_distributive_add_other_way(power(pv,d.i), ml + d.carry, mh*pv); } (ml+ d.carry)*power(pv,d.i)+mh*pv *power(pv,d.i) + BEWordSeqToInt(SelectDigitRange(g.Ps, d.i+d.shiftd, d.shiftd)); { //- apply the first 32-bit add lemma_mul_is_mul_boogie(acarry, pv); } (sl+acarry*pv)*power(pv,d.i)+mh*pv *power(pv,d.i) + BEWordSeqToInt(SelectDigitRange(g.Ps, d.i+d.shiftd, d.shiftd)); { lemma_mul_is_distributive_add_other_way(power(pv,d.i), sl, acarry*pv); } sl*power(pv,d.i)+acarry*pv*power(pv,d.i)+mh*pv*power(pv,d.i) + BEWordSeqToInt(SelectDigitRange(g.Ps, d.i+d.shiftd, d.shiftd)); { lemma_mul_is_associative(mh, pv, power(pv,d.i)); } { lemma_mul_is_associative(acarry, pv, power(pv,d.i)); } { lemma_mul_is_distributive_add_other_way(pv*power(pv,d.i), acarry, mh); } { lemma_mul_is_associative(acarry + mh, pv, power(pv,d.i)); } sl*power(pv,d.i)+(acarry+mh)*pv*power(pv,d.i) + BEWordSeqToInt(SelectDigitRange(g.Ps, d.i+d.shiftd, d.shiftd)); { //- apply the second 32-bit add lemma_mul_basics_forall(); assert carry == carry+zero*pv == mh+acarry; } sl*power(pv,d.i) + BEWordSeqToInt(SelectDigitRange(g.Ps, d.i+d.shiftd, d.shiftd)) +carry*pv*power(pv,d.i); //- re-prime sl*power(pv,d.i) + BEWordSeqToInt(ML) +carry*pv*power(pv,d.i); { lemma_SelectSingletonRange(g'.Ps, d'.i+d.shiftd, d.i+d.shiftd); lemma_BEDigitSeqToInt_singleton(pv, sl); } BEWordSeqToInt(HM)*power(pv,d.i) + BEWordSeqToInt(ML) +carry*pv*power(pv,d.i); { lemma_SelectDigitSubrange(g'.Ps, d'.i+d.shiftd, d.i+d.shiftd, d.shiftd); assert HL == HM+ML; lemma_BEInterpretation(pv, HL, d.i); assert BEWordSeqToInt(HL) == BEWordSeqToInt(HM)*power(pv,d.i) + BEWordSeqToInt(ML); } BEWordSeqToInt(SelectDigitRange(g'.Ps, d'.i+d.shiftd, d.shiftd)) +carry*pv*power(pv,d.i); //- assignment of local into d' BEWordSeqToInt(SelectDigitRange(g'.Ps, d'.i+d.shiftd, d.shiftd)) +d'.carry*pv*power(pv,d.i); { lemma_mul_is_associative_forall(); } BEWordSeqToInt(SelectDigitRange(g'.Ps, d'.i+d.shiftd, d.shiftd)) +d'.carry*(pv*power(pv,d.i)); { lemma_power_1(pv); } BEWordSeqToInt(SelectDigitRange(g'.Ps, d'.i+d.shiftd, d.shiftd)) +d'.carry*(power(pv,1)*power(pv,d.i)); { lemma_power_adds(pv,1,d.i); } BEWordSeqToInt(SelectDigitRange(g'.Ps, d'.i+d.shiftd, d.shiftd)) +d'.carry*power(pv,d'.i); { lemma_power2_unfolding(32, d'.i); lemma_mul_is_mul_boogie(32, d'.i); } BEWordSeqToInt(SelectDigitRange(g'.Ps, d'.shiftd+d'.i, d'.shiftd)) + d'.carry * power2(32*d'.i); } } method M1conclusion(d:M1Data, ghost g:M1Ghost) returns (pp:array) requires M1invariant(d, g); requires d.i == |g.Bs|; modifies d.pp; ensures pp!=null; ensures IsDigitSeq(power2(32), pp[..]); ensures d.a * power2(32*d.shiftd) * BEWordSeqToInt(d.b[..]) == BEWordSeqToInt(pp[..]); ensures d.a * power(power2(32),d.shiftd) * BEWordSeqToInt(d.b[..]) == BEWordSeqToInt(pp[..]); ensures pp == d.pp; //- used to propagate fresh() { ghost var pv:=power2(32); lemma_2toX(); var db_ref := d.b; //- do something real to d.b so dafnycc will realize that d.b is allocated, and thus that d.b is unaffected by methods that don't affect allocated parts of the heap pp := d.pp; pp[0] := d.carry; ghost var Ps := pp[..]; //- assert IsWordSeq(SelectDigitRange(g.Ps, d.shiftd+d.i, d.shiftd)); forall (j | 0<=j<|Ps|) ensures 0<=Ps[j] MLs[i]==0; calc { BEWordSeqToInt(pp[..]); BEWordSeqToInt(Ps); { lemma_BEInterpretation(pv, Ps, d.shiftd); } BEDigitSeqToInt(pv, HMs) * power(pv,d.shiftd) + BEDigitSeqToInt(pv, MLs); { lemma_LeadingZeros(pv, [], MLs); } BEDigitSeqToInt(pv, HMs) * power(pv,d.shiftd) + BEDigitSeqToInt(pv, []); { reveal_BEDigitSeqToInt_private(); } BEDigitSeqToInt(pv, HMs) * power(pv,d.shiftd); } ghost var HMi := HMs[..|HMs|-d.i]; ghost var MLi := HMs[|HMs|-d.i..]; assert HMs == HMi+MLi; calc { BEWordSeqToInt(HMs); { lemma_BEInterpretation(pv, HMs, d.i); } BEWordSeqToInt(HMi)*power(pv,d.i)+BEWordSeqToInt(MLi); { assert HMi==[d.carry]; //- OBSERVE lemma_BEDigitSeqToInt_singleton(pv, d.carry); } d.carry*power(pv,d.i)+BEWordSeqToInt(MLi); { lemma_power2_unfolding(32, d.i); lemma_mul_is_mul_boogie(32, d.i); } d.carry*power2(32*d.i)+BEWordSeqToInt(MLi); { assert MLi == SelectDigitRange(g.Ps, d.shiftd+d.i, d.shiftd); //- OBSERVE } d.carry*power2(32*d.i) +BEWordSeqToInt(SelectDigitRange(g.Ps, d.shiftd+d.i, d.shiftd)); d.a * BEWordSeqToInt(SelectDigits(g.Bs, d.i)); { assert g.Bs[0..|g.Bs|] == g.Bs; //- OBSERVE } d.a * BEWordSeqToInt(g.Bs); d.a * BEWordSeqToInt(d.b[..]); } calc { BEWordSeqToInt(pp[..]); d.a * BEWordSeqToInt(d.b[..]) * power(pv,d.shiftd); { lemma_mul_is_associative(d.a, BEWordSeqToInt(d.b[..]), power(pv,d.shiftd)); lemma_mul_is_commutative(BEWordSeqToInt(d.b[..]), power(pv,d.shiftd)); lemma_mul_is_associative(d.a, power(pv,d.shiftd), BEWordSeqToInt(d.b[..])); } d.a * power(pv,d.shiftd) * BEWordSeqToInt(d.b[..]); } lemma_power2_unfolding(32, d.shiftd); lemma_mul_is_mul_boogie(32, d.shiftd); } method MultiplyOneRow(b:array, a:int, shiftd:int) returns (pp:array) requires b!=null; requires IsDigitSeq(power2(32), b[..]); requires 0<=a, ghost Bs:seq, a:int, shiftd:int) returns (pp:array, ghost Ps:seq) requires b!=null; requires Bs == b[..]; requires IsDigitSeq(power2(32), Bs); requires 0<=a, ghost As:seq, b:array, ghost Bs:seq) returns (c:array, ghost Cs:seq) requires a!=null; requires As == a[..]; requires b!=null; requires Bs == b[..]; requires IsDigitSeq(power2(32), As); requires IsDigitSeq(power2(32), Bs); ensures c!=null; ensures Cs == c[..]; ensures IsDigitSeq(power2(32), Cs); ensures BEWordSeqToInt(As) + BEWordSeqToInt(Bs) == BEWordSeqToInt(Cs); { c := FatNatAdd(a, b); //- c := new int[0]; // // // //- c := FleetNatAdd(c, a, b); Cs := c[..]; } predicate FNMultiply_loop_invariant(pv:int, As:seq, Bs:seq, Rs:seq, wks:seq, i:int) { 1, Bs:seq, Rs:seq, wks:seq) requires 1, Bs:seq, old_Rs:seq, old_wks:seq, old_i:int, Ms:seq, a_fragment:int, a_partial_sum:int, rowi:MulRow, Rs:seq, wks:seq, i:int) requires FNMultiply_loop_invariant(pv, As, Bs, old_Rs, old_wks, old_i); requires IsDigitSeq(pv, Ms); requires i==old_i+1; requires old_i < |As|; requires BEDigitSeqToInt(pv,Ms) == DigitAt(As,old_i) * power(pv,old_i) * BEDigitSeqToInt(pv,Bs); requires IsDigitSeq(pv, Rs); requires BEDigitSeqToInt(pv,Rs) == BEDigitSeqToInt(pv,old_Rs) + BEDigitSeqToInt(pv,Ms); requires wks == old_wks + [rowi]; requires a_fragment == DigitAt(As,old_i)*power(pv,old_i); requires a_partial_sum == a_fragment + old_wks[|old_wks|-1].a_partial_sum; requires rowi == MulRow_c(a_fragment, a_partial_sum, BEDigitSeqToInt(pv,Rs)); ensures FNMultiply_loop_invariant(pv, As, Bs, Rs, wks, i); { assert IsDigitSeq(pv, Rs); assert 0 < i == |wks| <= |As|; assert IsDigitSeq(pv, Rs); var Bv := BEDigitSeqToInt(pv,Bs); assert 0<|wks|; forall (j | 0<=j<|wks|) ensures FNMulRelation(wks[j], Bv, 0); { if (j<|old_wks|) { assert FNMulRelation(old_wks[j], Bv, 0); } else { calc { wks[j].product; rowi.product; BEDigitSeqToInt(pv,Rs); BEDigitSeqToInt(pv,old_Rs) + BEDigitSeqToInt(pv,Ms); old_wks[|old_wks|-1].a_partial_sum*Bv + BEDigitSeqToInt(pv,Ms); old_wks[|old_wks|-1].a_partial_sum*Bv + DigitAt(As,old_i) * power(pv,old_i) * Bv; DigitAt(As,old_i)*power(pv,old_i)*Bv + old_wks[|old_wks|-1].a_partial_sum*Bv; a_fragment*Bv + old_wks[|old_wks|-1].a_partial_sum*Bv; { lemma_mul_is_distributive_forall(); } (a_fragment + old_wks[|old_wks|-1].a_partial_sum) * Bv; rowi.a_partial_sum * Bv; wks[j].a_partial_sum * Bv + 0; } assert FNMulRelation(wks[j], Bv, 0); } } assert FNMulBase(wks[0]); forall (j | 1<=j<|wks|) ensures FNMulNext(wks[j-1], wks[j]); { if (j<|old_wks|) { assert FNMulNext(old_wks[j-1], old_wks[j]); } else { assert FNMulNext(wks[j-1], wks[j]); } } assert FNMulProblemValid_partial(wks, Bv, 0); forall (j | 0<=j<|wks|) ensures FNMulRowReflectsBEDigits(pv, wks, j, As); { if (j<|old_wks|) { assert FNMulRowReflectsBEDigits(pv, old_wks, j, As); } else { assert j==|old_wks|==|wks|-1==i-1; var As1j := As[|As|-1-j..]; assert |As1j| == j+1; calc { BEDigitSeqToInt(pv, As[|As|-1-j..]); BEDigitSeqToInt(pv, As1j); { lemma_BEInterpretation(pv, As1j, j); } BEDigitSeqToInt(pv, As1j[..|As1j|-j]) * power(pv,j) + BEDigitSeqToInt(pv, As1j[|As1j|-j..]); { assert As1j[..|As1j|-j] == As[|As|-1-j..|As|-j]; assert As1j[|As1j|-j..] == As[|As|-j..]; } BEDigitSeqToInt(pv, As[|As|-1-j..|As|-j]) * power(pv,j) + BEDigitSeqToInt(pv, As1j[|As1j|-j..]); } ghost var Astail := As[|As|-1-j..]; calc { wks[j].a_partial_sum; a_partial_sum; a_fragment + old_wks[|old_wks|-1].a_partial_sum; DigitAt(As,old_i)*power(pv,old_i) + old_wks[|old_wks|-1].a_partial_sum; { assert FNMulRowReflectsBEDigits(pv, old_wks, j-1, As); } DigitAt(As,old_i)*power(pv,old_i) + BEDigitSeqToInt(pv, As[|As|-j..]); { assert As[|As|-j..] == Astail[|Astail|-old_i..]; } DigitAt(As,old_i)*power(pv,old_i) + BEDigitSeqToInt(pv, Astail[|Astail|-old_i..]); { assert Astail[..|Astail|-old_i] == [DigitAt(As,old_i)]; lemma_mul_basics_forall(); reveal_BEDigitSeqToInt_private(); assert [DigitAt(As,old_i)][0..|[DigitAt(As,old_i)]|-1] == []; calc { DigitAt(As,old_i); mul(0,power(pv,1)) + DigitAt(As,old_i); BEDigitSeqToInt(pv, [])*power(pv,1) + DigitAt(As,old_i); BEDigitSeqToInt(pv, [DigitAt(As,old_i)]); BEDigitSeqToInt(pv, Astail[..|Astail|-old_i]); } } BEDigitSeqToInt(pv, Astail[..|Astail|-old_i]) * power(pv,old_i) + BEDigitSeqToInt(pv, Astail[|Astail|-old_i..]); { lemma_BEInterpretation(pv, Astail, old_i); } BEDigitSeqToInt(pv, As[|As|-1-j..]); } assert FNMulRowReflectsBEDigits(pv, wks, j, As); } } assert PNWksReflectsBEDigits(pv, wks, As); assert wks[|wks|-1].product == BEDigitSeqToInt(pv,Rs); } datatype FNMulData = FNMulData_c(a:array, b:array, running_sum:array, i:int); datatype FNMulGhost = FNMulGhost_c(As:seq, Bs:seq, Rs:seq, wks:seq); predicate {:heap} FNMultiply_loop_invariant_kit(d:FNMulData, g:FNMulGhost) reads d.a; reads d.b; reads d.running_sum; { d.a != null && d.a[..] == g.As && d.b != null && d.b[..] == g.Bs && d.running_sum != null && d.running_sum[..] == g.Rs && FNMultiply_loop_invariant(power2(32), g.As, g.Bs, g.Rs, g.wks, d.i) } method FNMultiply_init_kit(a:array, b:array) returns (d:FNMulData, ghost g:FNMulGhost) requires a!=null; requires 0) requires FNMultiply_loop_invariant_kit(d, g); requires d.i == |g.As|; ensures p!=null; ensures IsWordSeq(p[..]); ensures BEWordSeqToInt(d.a[..]) * BEWordSeqToInt(d.b[..]) == BEWordSeqToInt(p[..]); { ghost var pv := power2(32); p := d.running_sum; assert g.As[|g.As|-d.i..] == g.As; //- OBSERVE assert g.As == d.a[..]; //- OBSERVE assert PNWksReflectsBEDigits(pv, g.wks, g.As); assert FNMulRowReflectsBEDigits(pv, g.wks, |g.wks|-1, g.As); //- OBSERVE ghost var Av := BEDigitSeqToInt(pv, g.As); ghost var Bv := BEDigitSeqToInt(pv, g.Bs); //- calc { //- wks[|wks|-1].a_partial_sum; //- BEDigitSeqToInt(pv, As[|As|-1-(|wks|-1)..]); //- Av; //- } //- assert g.wks[|g.wks|-1].a_partial_sum == Av; //- assert FNMulEnd(g.wks[|g.wks|-1], BEDigitSeqToInt(pv, g.Rs), Av); //- assert FNMulProblemValid(g.wks, BEDigitSeqToInt(pv, g.Rs), Av, Bv, 0); reveal_BEDigitSeqToInt_private(); //- assert FNMulProblemValid(g.wks, BEDigitSeqToInt(pv, g.Rs), BEDigitSeqToInt(pv, g.As), BEDigitSeqToInt(pv, g.Bs), BEDigitSeqToInt(pv, [])); //- assert FNMulProblemReflectsBESeq(pv, g.wks, g.Rs, g.As, g.Bs, []); //- assert FNMulProblemReflectsBESeq(pv, g.wks, p[..], d.a[..], d.b[..], []); lemma_FNMultiplication_BE(pv, g.wks, p[..], d.a[..], d.b[..], []); } method FatNatMul(a:array, b:array) returns (p:array) requires a!=null; requires b!=null; requires IsDigitSeq(power2(32), a[..]); requires IsDigitSeq(power2(32), b[..]); ensures p!=null; ensures IsDigitSeq(power2(32), p[..]); ensures BEWordSeqToInt(a[..]) * BEWordSeqToInt(b[..]) == BEWordSeqToInt(p[..]); { ProfileTally(Tally_FatNatMul(), 1); //- 0* case if (a.Length==0) { lemma_2toX32(); reveal_BEDigitSeqToInt_private(); lemma_mul_basics_forall(); lemma_mul_nonnegative_forall(); p := new int[0]; return; } var d:FNMulData; ghost var g:FNMulGhost; d,g := FNMultiply_init_kit(a, b); while (d.i < a.Length) invariant a[..] == g.As; invariant b[..] == g.Bs; invariant FNMultiply_loop_invariant_kit(d, g); invariant d.a == a; invariant d.b == b; { d,g := FNMultiply_step_kit(d, g); } p := FNMultiply_conclusion_kit(d, g); calc { BEWordSeqToInt(a[..]) * BEWordSeqToInt(b[..]); BEWordSeqToInt(d.a[..]) * BEWordSeqToInt(d.b[..]); BEWordSeqToInt(p[..]); } } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/FatNat/FatNatRandom.i.dfy ================================================ include "FatNatCompare.i.dfy" include "Bitwise.i.dfy" include "../Crypto/RandomNumberGen.s.dfy" include "../../Drivers/TPM/tpm-wrapper.i.dfy" //-include "../Math/round.i.dfy" //-include "../Math/BitwiseOperations.i.dfy" //-include "../../Drivers/TPM/tpm-wrapper.i.dfy" //-include "../../Drivers/CPU/assembly_premium.i.dfy" method BEWordSeqToFatNat(s:seq) returns (F:array) requires IsWordSeq(s); ensures fresh(F); ensures WellformedFatNat(F); ensures F[..] == s; ensures J(F) == BEWordSeqToInt(s); { F := new int[|s|]; var i:int := 0; while i < |s| invariant 0 <= i <= |s|; invariant IsWordSeq(F[..i]); invariant F[..i] == s[..i]; { F[i] := s[i]; assert F[..i+1] == F[..i] + [F[i]]; assert s[..i+1] == s[..i] + [s[i]]; i := i + 1; } calc { F[..]; F[..i]; s[..i]; s; } } method MakeTopBitsZero(x:int, bits:int) returns (y:int) requires 0 <= bits < 32; requires Word32(x); ensures y == x % power2(32-bits); ensures Word32(y); { if bits == 0 { y := x; lemma_small_mod(x, power2(32)); } else { var two_to_bits := ComputePower2(32-bits); y := Asm_Mod(x, two_to_bits); lemma_mod_is_mod_boogie(x, power2(32-bits)); } } lemma Lemma_ModMultiplies(a:int, b:int, m:int) requires a >= 0; requires b > 0; requires m > 0; ensures m * b != 0; ensures (a % m) * b == (a * b) % (m * b); { calc { m * b; > { lemma_mul_strict_inequality(0, m, b); lemma_mul_is_mul_boogie(0, b); } 0 * b; 0; } calc { a * b; { lemma_mul_is_commutative(a, b); } b * a; { lemma_fundamental_div_mod(a, m); } b * (m * (a / m) + (a % m)); { lemma_mul_is_distributive_add(b, m * (a / m), a % m); } b * (m * (a / m)) + b * (a % m); { lemma_mul_is_associative(b, m, a/m); } (b * m) * (a / m) + b * (a % m); { lemma_mul_is_commutative(a/m, b*m); } (a / m) * (b * m) + b * (a % m); { lemma_mul_is_commutative(b, m); } (a / m) * (m * b) + b * (a % m); } calc { b * (a % m); { lemma_mul_is_commutative(b, a % m); } (a % m) * b; <= { lemma_mod_pos_bound(a, m); lemma_mul_inequality(a % m, m-1, b); } (m - 1) * b; { lemma_mul_is_commutative(b, m-1); } b * (m - 1); { lemma_mul_is_distributive_sub(b, m, 1); lemma_mul_is_mul_boogie(b, 1); } b * m - b * 1; { lemma_mul_is_commutative(m, b); } m * b - b * 1; < m * b; } calc { (a * b) % (m * b); { lemma_mul_nonnegative(m, b); lemma_mod_pos_bound(a, m); lemma_mul_nonnegative(b, a % m); lemma_fundamental_div_mod_converse(a * b, m * b, a / m, b * (a % m)); } b * (a % m); } lemma_mul_is_commutative(b, a % m); } lemma Lemma_ExpressWordSeqInTermsOfTopWord(y:seq) requires IsWordSeq(y); requires |y| > 0; ensures BEWordSeqToInt(y) == y[0] * power2(32*(|y|-1)) + BEWordSeqToInt(y[1..]); { reveal_BEDigitSeqToInt_private(); calc { BEWordSeqToInt([y[0]]); BEWordSeqToInt([y[0]][0..|[y[0]]|-1])*power2(32) + [y[0]][|[y[0]]|-1]; BEWordSeqToInt([])*power2(32) + [y[0]][|[y[0]]|-1]; BEWordSeqToInt([])*power2(32) + y[0]; { lemma_mul_is_mul_boogie(0, power2(32)); } 0*power2(32) + y[0]; y[0]; } calc { BEWordSeqToInt(y); { lemma_2to32(); lemma_BEInterpretation(power2(32), y, |y|-1); } BEWordSeqToInt(y[..1]) * power(power2(32), |y|-1) + BEWordSeqToInt(y[1..]); { assert y[..1] == [y[0]]; } BEWordSeqToInt([y[0]]) * power(power2(32), |y|-1) + BEWordSeqToInt(y[1..]); { assert BEWordSeqToInt([y[0]]) == y[0]; } y[0] * power(power2(32), |y|-1) + BEWordSeqToInt(y[1..]); { lemma_power2_unfolding(32, |y|-1); lemma_mul_is_mul_boogie(32, |y|-1); } y[0] * power2(32*(|y|-1)) + BEWordSeqToInt(y[1..]); } } lemma Lemma_MakingTopBitsZeroAffectsEntireSequence(x:seq, y:seq, bits:int) requires 0 <= bits < 32; requires |x| == |y|; requires |x| > 0; requires IsWordSeq(x); requires IsWordSeq(y); requires y[0] == x[0] % power2(32-bits); requires forall i :: 0 < i < |x| ==> y[i] == x[i]; ensures BEWordSeqToInt(y) == BEWordSeqToInt(x) % power2(|x|*32-bits); decreases |x|; { reveal_BEDigitSeqToInt_private(); calc { BEWordSeqToInt(y); { Lemma_ExpressWordSeqInTermsOfTopWord(y); } y[0] * power2(32*(|y|-1)) + BEWordSeqToInt(y[1..]); { assert y[1..] == x[1..]; } y[0] * power2(32*(|x|-1)) + BEWordSeqToInt(x[1..]); (x[0] % power2(32-bits)) * power2(32*(|x|-1)) + BEWordSeqToInt(x[1..]); } calc { BEWordSeqToInt(x[1..]); < { lemma_BEDigitSeqToInt_bound(power2(32), x[1..]); } power(power2(32), |x|-1); { lemma_power2_unfolding(32, |x|-1); lemma_mul_is_mul_boogie(32, |x|-1); } power2(32 * (|x|-1)); } calc { (x[0] % power2(32-bits)) * power2(32*(|x|-1)) + BEWordSeqToInt(x[1..]); < (x[0] % power2(32-bits)) * power2(32*(|x|-1)) + power2(32*(|x|-1)); { lemma_mul_is_commutative(x[0] % power2(32-bits), power2(32*(|x|-1))); } power2(32*(|x|-1)) * (x[0] % power2(32-bits)) + power2(32*(|x|-1)); power2(32*(|x|-1)) * (x[0] % power2(32-bits)) + power2(32*(|x|-1)) * 1; { lemma_mul_is_distributive_add(power2(32*(|x|-1)), x[0] % power2(32-bits), 1); lemma_mul_is_mul_boogie(power2(32*(|x|-1)), 1); } power2(32*(|x|-1)) * (x[0] % power2(32-bits) + 1); { lemma_mul_is_commutative(power2(32*(|x|-1)), x[0] % power2(32-bits) + 1); } (x[0] % power2(32-bits) + 1) * power2(32*(|x|-1)); <= { lemma_mod_properties(); lemma_mul_inequality(x[0] % power2(32-bits) + 1, power2(32-bits), power2(32*(|x|-1))); } power2(32-bits) * power2(32*(|x|-1)); { lemma_power2_adds(32-bits, 32*(|x|-1)); } power2(32 - bits + 32*(|x|-1)); { lemma_mul_is_mul_boogie(32, |x|-1); lemma_mul_is_distributive_sub(32, |x|, 1); lemma_mul_is_mul_boogie(32, 1); } power2(32 - bits + 32*|x| - 32*1); power2(32*|x| - bits); } calc { (x[0] % power2(32-bits)) * power2(32*(|x|-1)) + BEWordSeqToInt(x[1..]); { Lemma_ModMultiplies(x[0], power2(32*(|x|-1)), power2(32-bits)); } (x[0] * power2(32*(|x|-1))) % (power2(32-bits)*power2(32*(|x|-1))) + BEWordSeqToInt(x[1..]); { lemma_power2_adds(32-bits, 32*(|x|-1)); } (x[0] * power2(32*(|x|-1))) % power2(32-bits + 32*(|x|-1)) + BEWordSeqToInt(x[1..]); { lemma_mul_is_mul_boogie(32, |x|-1); lemma_mul_is_distributive_sub(32, |x|, 1); lemma_mul_is_mul_boogie(32, 1); } (x[0] * power2(32*(|x|-1))) % power2(32-bits + 32*|x|-32*1) + BEWordSeqToInt(x[1..]); (x[0] * power2(32*(|x|-1))) % power2(32*|x|-bits) + BEWordSeqToInt(x[1..]); calc { BEWordSeqToInt(x[1..]); < { lemma_BEDigitSeqToInt_bound(power2(32), x[1..]); } power(power2(32), |x|-1); { lemma_power2_unfolding(32, |x|-1); lemma_mul_is_mul_boogie(32, |x|-1); } power2(32 * (|x|-1)); { lemma_mul_is_distributive_sub(32, |x|, 1); lemma_mul_is_mul_boogie(32, |x|-1); lemma_mul_is_mul_boogie(32, |x|); lemma_mul_is_mul_boogie(32, 1); } power2(32 * |x| - 32 * 1); power2(32 * |x| - 32); <= { lemma_power2_increases(32 * |x| - 32, 32 * |x| - bits); } power2(32 * |x| - bits); } { lemma_small_mod(BEWordSeqToInt_premium(x[1..]), power2(32 * |x| - bits)); } (x[0] * power2(32*(|x|-1))) % power2(32*|x|-bits) + BEWordSeqToInt(x[1..]) % power2(32*|x|-bits); } calc { (x[0] * power2(32*(|x|-1))) % power2(32*|x|-bits) + BEWordSeqToInt(x[1..]) % power2(32*|x|-bits); { assert (x[0] * power2(32*(|x|-1))) % power2(32*|x|-bits) + BEWordSeqToInt(x[1..]) % power2(32*|x|-bits) == BEWordSeqToInt_premium(y); } { lemma_small_mod((x[0] * power2(32*(|x|-1))) % power2(32*|x|-bits) + BEWordSeqToInt(x[1..]) % power2(32*|x|-bits), power2(32*|x|-bits)); } ((x[0] * power2(32*(|x|-1))) % power2(32*|x|-bits) + BEWordSeqToInt(x[1..]) % power2(32*|x|-bits)) % power2(32*|x|-bits); { lemma_add_mod_noop(x[0] * power2(32*(|x|-1)), BEWordSeqToInt(x[1..]), power2(32*|x|-bits)); } (x[0] * power2(32*(|x|-1)) + BEWordSeqToInt(x[1..])) % power2(32*|x|-bits); { Lemma_ExpressWordSeqInTermsOfTopWord(x); } BEWordSeqToInt(x) % power2(32*|x|-bits); } } method FatNatRandomPower2(c:nat) returns (R:array, ghost randoms:seq) requires TPM_ready(); ensures fresh(R); ensures R != null; ensures WellformedFatNat(R); ensures IsByteSeqOfLen(randoms, DivideRoundingUp(c, 8)); ensures J(R) == BEByteSeqToInt(randoms) % power2(c); ensures J(R) < power2(c); ensures TPM_ready(); modifies this`TPM; modifies this`IoMemPerm; ensures TPMs_match_except_for_randoms(old(TPM), TPM); ensures old(TPM).random_index <= TPM.random_index; ensures randoms == TPM_random_bytes_premium(old(TPM).random_index, TPM.random_index); { lemma_2to32(); var byte_count := DivideRoundingUp_premium(c, 8); var byte_seq := get_random(byte_count); randoms := byte_seq; assert |randoms| == byte_count == DivideRoundingUp(c, 8); var word_seq,padding := BEByteSeqToWordSeq_impl(byte_seq); assert |word_seq| == (|byte_seq|+3)/4; //- var trim_seq := TrimLeadingZeros(4294967296, word_seq); R := BEWordSeqToFatNat(word_seq); assert WellformedFatNat(R); assert J(R) == BEWordSeqToInt(word_seq) == BEByteSeqToInt(randoms); calc { byte_count*8; >= { lemma_mul_is_mul_boogie(byte_count, 8); } c; } if byte_count > 0 { calc { |word_seq| * 32 - c; (byte_count+3)/4 * 32 - c; (DivideRoundingUp_premium(c, 8)+3)/4 * 32 - c; ((c + 7)/8 +3)/4 * 32 - c; ((c + 7)/8 + 24 / 8)/4 * 32 - c; ((c + 31)/8)/4 * 32 - c; (c + 31)/32 * 32 - c; DivideRoundingUp_premium(c, 32) * 32 - c; < { lemma_mul_is_commutative(DivideRoundingUp_premium(c, 32), 32); } c + 32 - c; 32; } R[0] := MakeTopBitsZero(R[0], |word_seq| * 32 - c); Lemma_MakingTopBitsZeroAffectsEntireSequence(word_seq, R[..], |word_seq| * 32 - c); calc { J(R); BEWordSeqToInt(word_seq) % power2(|word_seq|*32-(|word_seq|*32-c)); BEWordSeqToInt(word_seq) % power2(c); } assert J(R) == BEByteSeqToInt(randoms) % power2(c); } else { calc { J(R); BEWordSeqToInt([]); { reveal_BEDigitSeqToInt_private(); } 0; } calc { BEByteSeqToInt(randoms) % power2(c); < { lemma_mod_properties(); } power2(c); { reveal_power2(); } 1; } } lemma_mod_properties(); assert J(R) < power2(c); } //- static predicate CandidateSeedWorksheetValid_incremental(req:SelectRandomRequest, worksheet:CandidateSeedWorksheet, last_succeeds:bool) { (forall i :: 0<=i<|worksheet.rows| ==> CandidateSeedWorksheetRowValid(req, worksheet.rows[i])) //- all but last row fail && (forall i:int :: 0<=i<|worksheet.rows|-1 ==> !worksheet.rows[i].accepted) //- last as specified && (|worksheet.rows|>0 ==> worksheet.rows[|worksheet.rows|-1].accepted == last_succeeds) //- randoms properly accounted for && CandidateSeedWorksheetConsumesRandoms(worksheet.rows) == worksheet.randoms } method FatNatRandomFromInclusiveRange(L:array, H:array, ghost req:SelectRandomRequest) returns (R:array, ghost worksheet:CandidateSeedWorksheet) requires WellformedFatNat(L); requires WellformedFatNat(H); requires J(L) <= J(H); requires req.l == J(L); requires req.h == J(H); requires SelectRandomRequestValid(req); requires TPM_ready(); ensures TPM_ready(); ensures WellformedFatNat(R); ensures J(L) <= J(R) <= J(H); ensures CandidateSeedWorksheetValid(req, worksheet); ensures J(R) == CandidateSeedWorksheetOutput(worksheet); modifies this`TPM; modifies this`IoMemPerm; ensures TPMs_match_except_for_randoms(old(TPM), TPM); ensures old(TPM).random_index <= TPM.random_index; ensures worksheet.randoms == TPM_random_bytes_premium(old(TPM).random_index, TPM.random_index); { var c:nat := FatNatCountBits(H); lemma_bit_count_is_unique(J(H), c, req.h_bits); var lobound:bool := false; var hibound:bool := false; ghost var randoms; worksheet := CandidateSeedWorksheet_c([], []); ghost var started := false; R := new int[0]; //- dafnycc requires us to initialize this variable, and doesn't support initializing it to null. var accepted := false; while (!accepted) decreases *; //- Possibly doesn't terminate. invariant started ==> WellformedFatNat(R); invariant started ==> lobound == (J(L)<=J(R)); invariant started ==> hibound == (J(R)<=J(H)); invariant started ==> 0<|worksheet.rows|; invariant accepted ==> started; invariant CandidateSeedWorksheetValid_incremental(req, worksheet, accepted); invariant accepted ==> CandidateSeedWorksheetOutput(worksheet) == J(R); invariant TPM_ready(); invariant TPMs_match_except_for_randoms(old(TPM), TPM); invariant old(TPM).random_index <= TPM.random_index; invariant worksheet.randoms == TPM_random_bytes_premium(old(TPM).random_index, TPM.random_index); invariant TPM.random_index - old(TPM).random_index == |worksheet.randoms|; { R, randoms := FatNatRandomPower2(c); lobound := FatNatLe(L, R); hibound := FatNatLe(R, H); started := true; accepted := lobound && hibound; ghost var row := CandidateSeedWorksheetRow_c(J(R), accepted, randoms); ghost var worksheet' := CandidateSeedWorksheet_c( worksheet.rows + [row], worksheet.randoms + randoms); lemma_random_comprehension(old(TPM).random_index, worksheet.randoms, randoms); worksheet := worksheet'; } } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/FatNat/FatNatReciprocal.i.dfy ================================================ include "FatNatDivDefs.i.dfy" include "../FleetNat/FleetNatMul.i.dfy" include "CanonicalArrays.i.dfy" datatype FNDivReciprocal = FNDivKnownReciprocal(w:int, TwoTo32wDividedByD:array) | FNDivUnknownReciprocal(); predicate FNDivReciprocalValid(reciprocal:FNDivReciprocal, dv:array) reads dv; reads if reciprocal.FNDivKnownReciprocal? then reciprocal.TwoTo32wDividedByD else dv; { dv != null && IsWordSeq(dv[..]) && BEWordSeqToInt(dv[..]) != 0 && (reciprocal.FNDivKnownReciprocal? ==> (reciprocal.w >= dv.Length * 2 && reciprocal.TwoTo32wDividedByD != null && IsWordSeq(reciprocal.TwoTo32wDividedByD[..]) && BEWordSeqToInt(reciprocal.TwoTo32wDividedByD[..]) == power2(32*reciprocal.w) / BEWordSeqToInt(dv[..]))) } lemma Lemma_RemovingLastWordDividesBy2To32(s:seq) requires |s| > 0; requires IsWordSeq(s); ensures BEWordSeqToInt(s[..|s|-1]) == BEWordSeqToInt(s) / power2(32); { var pv := power2(32); lemma_2toX(); lemma_BEInterpretation(pv, s, 1); lemma_power2_unfolding(32, 1); lemma_BEDigitSeqToInt_bound(pv, s[|s|-1..]); lemma_fundamental_div_mod_converse( BEDigitSeqToInt(pv, s), pv, BEDigitSeqToInt(pv, s[..|s|-1]), BEDigitSeqToInt(pv, s[|s|-1..])); } lemma Lemma_RemovingLastNWordsDividesBy2To32n(s:seq, n:nat) requires |s| >= n; requires IsWordSeq(s); ensures BEWordSeqToInt(s[..|s|-n]) == BEWordSeqToInt(s) / power2(32 * n); decreases n; { if n == 0 { calc { BEWordSeqToInt(s[..|s|-n]); { assert s == s[..|s|]; } BEWordSeqToInt(s); BEWordSeqToInt(s) / 1; { reveal_power2(); lemma_div_is_div_boogie(BEWordSeqToInt(s), 1); } BEWordSeqToInt(s) / power2(0); BEWordSeqToInt(s) / power2(32 * n); } } else { Lemma_RemovingLastNWordsDividesBy2To32n(s, n-1); assert BEWordSeqToInt(s[..|s|-(n-1)]) == BEWordSeqToInt(s) / power2(32 * (n-1)); calc { BEWordSeqToInt(s[..|s|-n]); { Lemma_RemovingLastWordDividesBy2To32(s[..|s|-(n-1)]); assert var q := s[..|s|-(n-1)]; q[..|q|-1] == s[..|s|-n]; } BEWordSeqToInt(s[..|s|-(n-1)]) / power2(32); { Lemma_RemovingLastNWordsDividesBy2To32n(s, n-1); } (BEWordSeqToInt(s) / power2(32 * (n-1))) / power2(32); { assert BEWordSeqToInt_premium(s) >= 0; lemma_div_denominator(BEWordSeqToInt(s), power2(32 * (n-1)), power2(32)); lemma_power2_positive(); lemma_mul_strictly_positive(power2(32 * (n-1)), power2(32)); } BEWordSeqToInt(s) / (power2(32 * (n-1)) * power2(32)); { lemma_power2_adds(32 * (n-1), 32); } BEWordSeqToInt(s) / power2(32 * (n-1) + 32); BEWordSeqToInt(s) / power2(32 * n); } } } method FNShiftRightByWords(n:array, w:nat) returns (r:array) requires n != null; requires IsWordSeq(n[..]); ensures r != null; ensures fresh(r); ensures IsWordSeq(r[..]); ensures BEWordSeqToInt(r[..]) == BEWordSeqToInt(n[..]) / power2(32*w); { if n.Length <= w { lemma_BEDigitSeqToInt_bound(power2(32), n[..]); calc { BEWordSeqToInt(n[..]); < power(power2(32), n.Length); { lemma_power2_is_power_2(32); } power(power(2, 32), n.Length); { lemma_power_multiplies(2, 32, n.Length); lemma_mul_is_mul_boogie(32, n.Length); } power(2, 32 * n.Length); { lemma_power2_is_power_2(32 * n.Length); } power2(32 * n.Length); <= { lemma_mul_is_commutative_forall(); lemma_mul_is_mul_boogie(32, n.Length); lemma_mul_is_mul_boogie(32, w); lemma_mul_inequality(n.Length, w, 32); lemma_power2_increases(32 * n.Length, 32 * w); } power2(32 * w); } r := new int[0]; calc { BEWordSeqToInt(r[..]); { assert r[..] == []; } BEWordSeqToInt([]); { reveal_BEDigitSeqToInt_private(); } 0; { lemma_small_div(); } BEWordSeqToInt(n[..]) / power2(32*w); } return; } r := new int[n.Length - w]; var i := 0; assert IsWordSeq(n[..]); while i < r.Length invariant 0 <= i <= r.Length; invariant r[..i] == n[..i]; invariant IsWordSeq(r[..i]); { r[i] := n[i]; assert r[..i+1] == r[..i] + [r[i]]; assert n[..i+1] == n[..i] + [n[i]]; i := i + 1; } assert r[..] == n[..r.Length]; Lemma_RemovingLastNWordsDividesBy2To32n(n[..], w); assert BEWordSeqToInt(r[..]) == BEWordSeqToInt(n[..]) / power2(32*w); } lemma Lemma_AnyDigitNonzeroMakesValueNonzero(s:seq, i:int) requires IsWordSeq(s); requires 0 <= i < |s|; requires s[i] != 0; ensures BEWordSeqToInt(s) != 0; decreases |s|; { reveal_BEDigitSeqToInt_private(); if i == |s| - 1 { calc { BEWordSeqToInt_premium(s); BEWordSeqToInt_premium(s[0..|s|-1])*power2(32) + s[|s|-1]; >= { lemma_mul_inequality(0, BEWordSeqToInt_premium(s[0..|s|-1]), power2(32)); lemma_mul_is_mul_boogie(0, power2(32)); } 0*power2(32) + s[|s|-1]; s[|s|-1]; > 0; } } else { Lemma_AnyDigitNonzeroMakesValueNonzero(s[0..|s|-1], i); calc { BEWordSeqToInt_premium(s); BEWordSeqToInt_premium(s[0..|s|-1])*power2(32) + s[|s|-1]; > { lemma_mul_strict_inequality(0, BEWordSeqToInt_premium(s[0..|s|-1]), power2(32)); lemma_mul_is_mul_boogie(0, power2(32)); } 0*power2(32) + s[|s|-1]; s[|s|-1]; >= 0; } } } method IsFatNatZero(n:array) returns (b:bool) requires n != null; requires IsWordSeq(n[..]); ensures b == (BEWordSeqToInt(n[..]) == 0); { var i := 0; calc { BEWordSeqToInt(n[..0]); { assert n[..0] == []; } BEWordSeqToInt([]); { reveal_BEDigitSeqToInt_private(); } 0; } while i < n.Length invariant 0 <= i <= n.Length; invariant forall j :: 0 <= j < i ==> n[j] == 0; invariant BEWordSeqToInt(n[..i]) == 0; { if n[i] != 0 { b := false; Lemma_AnyDigitNonzeroMakesValueNonzero(n[..], i); return; } calc { BEWordSeqToInt(n[..i+1]); { assert |n[..i+1]| == i+1; assert n[..i+1][0..i] == n[..i]; reveal_BEDigitSeqToInt_private(); } BEWordSeqToInt(n[..i])*power2(32) + n[i]; { lemma_mul_is_mul_boogie(0, power2(32)); } 0*power2(32) + n[i]; n[i]; 0; } i := i + 1; } b := true; assert n[..] == n[..i]; } lemma Lemma_VerySpecificDivisionInequality(x:int, y:int, z:int) requires x >= 0; requires y > 0; requires z > 0; ensures (x * (y / z) / y) * z <= x; { var y_div_z := y / z; var y_mod_z := y % z; var w := x * y_div_z; var w_div_y := w / y; var w_mod_y := w % y; calc { x * y + z * w_mod_y + x * y_mod_z; >= { lemma_mod_properties(); lemma_mul_nonnegative(z, w_mod_y); lemma_mul_nonnegative(x, y_mod_z); } x * y; { lemma_fundamental_div_mod(y, z); } x * (z * y_div_z + y_mod_z); { lemma_mul_is_distributive_add(x, z * y_div_z, y_mod_z); } x * (z * y_div_z) + x * y_mod_z; } calc { x * y + z * w_mod_y; >= x * (z * y_div_z); { lemma_mul_is_commutative(z, y_div_z); } x * (y_div_z * z); { lemma_mul_is_associative(x, y_div_z, z); } (x * y_div_z) * z; w * z; { lemma_fundamental_div_mod(w, y); } (y * w_div_y + w_mod_y) * z; { lemma_mul_is_commutative(y * w_div_y + w_mod_y, z); } z * (y * w_div_y + w_mod_y); { lemma_mul_is_distributive_add(z, y * w_div_y, w_mod_y); } z * (y * w_div_y) + z * w_mod_y; } calc { x * y; >= z * (y * w_div_y); { lemma_mul_is_commutative(y, w_div_y); } z * (w_div_y * y); { lemma_mul_is_associative(z, w_div_y, y); } (z * w_div_y) * y; { lemma_mul_is_commutative(z, w_div_y); } (w_div_y * z) * y; } if x < w_div_y * z { lemma_mul_strict_inequality(x, w_div_y * z, y); } assert x >= w_div_y * z; } method FNDivision_Estimate_Q_Reciprocal(n:array, dv:array, reciprocal:FNDivReciprocal) returns (q:array) requires n!=null; requires IsWordSeq(n[..]); requires dv!=null; requires IsWordSeq(dv[..]); requires 1 < BEWordSeqToInt(dv[..]) <= BEWordSeqToInt(n[..]); requires reciprocal.FNDivKnownReciprocal?; requires FNDivReciprocalValid(reciprocal, dv); ensures q!=null; ensures IsWordSeq(q[..]); ensures 0 < BEWordSeqToInt(q[..])*BEWordSeqToInt(dv[..]); ensures BEWordSeqToInt(q[..])*BEWordSeqToInt(dv[..]) <= BEWordSeqToInt(n[..]); { ghost var g_x := BEWordSeqToInt(reciprocal.TwoTo32wDividedByD[..]); ghost var g_two_to_32w := power2(32 * reciprocal.w); ghost var g_dv := BEWordSeqToInt(dv[..]); ghost var w := reciprocal.w; ghost var g_y := g_two_to_32w - g_x * g_dv; ghost var g_n := BEWordSeqToInt(n[..]); ghost var g_nx := g_n * g_x; assert g_x == g_two_to_32w / g_dv; assert g_x * g_dv + g_y == g_two_to_32w; var nx := FleetNatMul(n, reciprocal.TwoTo32wDividedByD); assert BEWordSeqToInt(nx[..]) == g_nx; q := FNShiftRightByWords(nx, reciprocal.w); ghost var g_q := BEWordSeqToInt(q[..]); assert g_q == g_nx / power2(32*w); var q_is_zero := IsFatNatZero(q); if q_is_zero { lemma_2toX(); q := MakeBELiteralArray(1); assert BEWordSeqToInt(q[..]) == 1; calc { BEWordSeqToInt_premium(q[..])*BEWordSeqToInt_premium(dv[..]); { lemma_mul_is_mul_boogie(1, BEWordSeqToInt_premium(dv[..])); } 1*BEWordSeqToInt_premium(dv[..]); <= BEWordSeqToInt_premium(n[..]); } } else { calc { BEWordSeqToInt_premium(q[..])*BEWordSeqToInt_premium(dv[..]); g_q * g_dv; (g_nx / power2(32*w)) * g_dv; (g_n * g_x / power2(32*w)) * g_dv; (g_n * (power2(32*w) / g_dv) / power2(32*w)) * g_dv; <= { Lemma_VerySpecificDivisionInequality(g_n, power2(32*w), g_dv); } g_n; } } calc { BEWordSeqToInt_premium(q[..])*BEWordSeqToInt_premium(dv[..]); >= { lemma_mul_inequality(1, BEWordSeqToInt_premium(q[..]), BEWordSeqToInt_premium(dv[..])); lemma_mul_is_mul_boogie(1, BEWordSeqToInt_premium(dv[..])); } 1*BEWordSeqToInt_premium(dv[..]); BEWordSeqToInt_premium(dv[..]); > 1; } } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/FatNat/FatNatSub.i.dfy ================================================ include "FatNatCommon.i.dfy" predicate FNSubRelation_local(pv:int, a:seq, b:seq, c:seq, carryin:seq, i:int) requires 1, b:seq, c:seq, carryin:seq) requires 1 FNSubRelation_local(pv, a, b, c, carryin, i) } lemma lemma_FNSubtraction_recursive(pv:int, a:seq, b:seq, c:seq, carryin:seq) requires 1, b:seq, c:seq, carryin:seq) requires 1, b:seq, c:seq, carryin:seq, j:int) requires 1= j; { forall i :: 0 <= i < j ==> FNSubRelation_local(pv, a, b, c[|c|-j..], carryin, i) } lemma lemma_SubRelationInduction(pv:int, a:seq, b:seq, c:seq, carryin:seq, j:int) requires 1, b:seq, oldc:seq, c:seq, oldcarryin:seq, carryin:seq, oldj:int, j:int, lastcarry:int) requires 1 DigitAt(c, i) == DigitAt(oldc, i); requires FNSubRelation_inductive(pv, a, b, oldc, oldcarryin, oldj); requires DigitAt(carryin,j) * pv + DigitAt(a,oldj) == DigitAt(b,oldj) + DigitAt(c,oldj) + DigitAt(oldcarryin,oldj); ensures IsDigitSeq(pv, c[|c|-j..]); ensures FNSubRelation_inductive(pv, a, b, c, [lastcarry]+oldcarryin, j); { assert 0 <= |c|-j < |c|; assert lastcarry == DigitAt(carryin, j); ghost var olda := a; ghost var oldb := b; ghost var newc := c[|c|-j..]; forall (i | 0 <= i < j) ensures FNSubRelation_local(pv, a, b, newc, carryin, i); { if (i FNSubRelation_local(pv, a, b, newc, carryin, i); assert forall i :: 0 <= i < j ==> FNSubRelation_local(pv, a, b, c[|c|-j..], carryin, i); assert FNSubRelation_inductive(pv, a, b, c, carryin, j); } //- inner variant exposes the borrow method FNSubtract_inner(ghost pv:int, a:array, b:array) returns (c:array, ghost borrow:int) requires pv == power2(32); requires a!=null; requires b!=null; requires IsDigitSeq(pv, a[..]); requires IsDigitSeq(pv, b[..]); ensures c!=null; ensures IsDigitSeq(pv, c[..]); ensures c.Length <= a.Length || c.Length <= b.Length; ensures 0<=borrow; ensures borrow * power(pv,MaxLen3(a[..],b[..],c[..])) + BEDigitSeqToInt(pv,a[..]) == BEDigitSeqToInt(pv,b[..]) + BEDigitSeqToInt(pv,c[..]); { lemma_2toX32(); ghost var carryin:seq := [0]; var iml := (if a.Length > b.Length then a.Length else b.Length); var oml := iml; c := new int[oml]; assert oml == MaxLen3(a[..],b[..],c[..]); var lastcarry := 0; var j:=0; while (j < oml) invariant 0 <= j <= oml; invariant IsBitSeq(carryin); invariant lastcarry == DigitAt(carryin, j); invariant DigitAt(carryin, 0) == 0; invariant IsDigitSeq(pv, c[c.Length-j..]); invariant |carryin| == j+1; invariant FNSubRelation_inductive(pv, a[..], b[..], c[..], carryin, j); { ghost var olda := a[..]; ghost var oldb := b[..]; ghost var oldc := c[..]; ghost var oldcarryin := carryin[..]; ghost var oldj := j; assert FNSubRelation_inductive(pv, olda, oldb, oldc, oldcarryin, oldj); var difference,carry := Sub32_with_borrow( ArrayDigitAt_sub(a,j), ArrayDigitAt_sub(b,j), lastcarry); assert c[..] == oldc; //- OBSERVE carryin := [carry] + carryin; lastcarry := carry; c[c.Length - 1 - j] := difference; assert c[c.Length-1-j..] == [c[c.Length-1-j]] + c[c.Length-j..]; //- OBSERVE j:=j+1; assert olda==a[..]; assert oldb==b[..]; lemma_FNSubtraction_induction(pv, oml, a[..], b[..], oldc, c[..], oldcarryin, carryin, oldj, j, lastcarry); } assert c[..] == c[c.Length-oml..]; //- OBSERVE lemma_SubRelationInduction(pv, a[..], b[..], c[..], carryin, oml); assert DigitAt(carryin,0)==0; borrow := DigitAt(carryin,oml); calc { borrow * power(pv,MaxLen3(a[..],b[..],c[..])) + BEDigitSeqToInt(pv,a[..]); DigitAt(carryin,oml) * power(pv,oml) + BEDigitSeqToInt(pv,a[..]); { lemma_FNSubtraction(pv, a[..], b[..], c[..], carryin); } BEDigitSeqToInt(pv,b[..]) + BEDigitSeqToInt(pv,c[..]) + DigitAt(carryin,0); BEDigitSeqToInt(pv,b[..]) + BEDigitSeqToInt(pv,c[..]); } } method FatNatSub(a:array, b:array) returns (c:array) requires a!=null; requires b!=null; requires IsDigitSeq(power2(32), a[..]); requires IsDigitSeq(power2(32), b[..]); requires BEDigitSeqToInt(power2(32), a[..]) >= BEDigitSeqToInt(power2(32), b[..]); ensures c!=null; ensures IsDigitSeq(power2(32), c[..]); ensures c.Length <= a.Length || c.Length <= b.Length; ensures BEDigitSeqToInt(power2(32),a[..]) == BEDigitSeqToInt(power2(32),b[..]) + BEDigitSeqToInt(power2(32),c[..]); { ghost var As := a[..]; ghost var Bs := b[..]; lemma_mul_basics_forall(); ghost var borrow; c,borrow := FNSubtract_inner(power2(32), a, b); if (borrow > 0) { ghost var pv := power2(32); calc { BEDigitSeqToInt(pv,c[..]); < { lemma_BEDigitSeqToInt_bound(pv, c[..]); } power(pv,|c[..]|); <= { lemma_power_increases(pv, |c[..]|, MaxLen3(a[..],b[..],c[..])); } power(pv,MaxLen3(a[..],b[..],c[..])); } calc { BEDigitSeqToInt(pv,a[..]); < power(pv,MaxLen3(a[..],b[..],c[..])) + BEDigitSeqToInt(pv,a[..]) - BEDigitSeqToInt(pv,c[..]); { lemma_mul_basics_forall(); } mul(1, power(pv,MaxLen3(a[..],b[..],c[..]))) + BEDigitSeqToInt(pv,a[..]) - BEDigitSeqToInt(pv,c[..]); <= { lemma_power_positive(pv, MaxLen3(a[..],b[..],c[..])); lemma_mul_inequality(1, borrow, power(pv,MaxLen3(a[..],b[..],c[..]))); } borrow * power(pv,MaxLen3(a[..],b[..],c[..])) + BEDigitSeqToInt(pv,a[..]) - BEDigitSeqToInt(pv,c[..]); BEDigitSeqToInt(pv,b[..]); } assert false; } assert borrow == 0; ghost var pv := power2(32); calc { BEDigitSeqToInt(power2(32),a[..]); { lemma_mul_basics(power(pv,MaxLen3(a[..],b[..],c[..]))); } borrow * power(pv,MaxLen3(a[..],b[..],c[..])) + BEDigitSeqToInt(pv,a[..]); BEDigitSeqToInt(power2(32),b[..]) + BEDigitSeqToInt(power2(32),c[..]); BEDigitSeqToInt(pv,b[..]) + BEDigitSeqToInt(pv,c[..]); } } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/FatNat/FatNatX86.i.dfy ================================================ include "FatNatCommon.i.dfy" include "../BigNum/BigNatX86Shim.i.dfy" //-include "FatNatX86big.i.dfy" method {:decl} Add32_unrolled_8( a:array, ai:int, b:array, bi:int, s:array, si:int, c_in:int) returns (c_out:int, ghost carries:seq) requires a!=null; requires IsWordSeq(a[..]); requires 0 <= ai; requires ai+8 <= a.Length; requires b!=null; requires IsWordSeq(b[..]); requires 0 <= bi; requires bi+8 <= b.Length; requires s!=null; requires 0 <= si; requires si+8 <= s.Length; requires 0<=c_in<=1; requires b!=s; requires a!=s; modifies s; ensures forall i :: 0<=i s[s.Length-1-i]==old(s[s.Length-1-i]); ensures 0<=c_out<=1; ensures |carries| == 9; ensures carries[0] == c_in; ensures carries[8] == c_out; ensures forall i :: 0<=i<8 ==> carries[i+1] == if a[a.Length-1-(ai+i)] +b[b.Length-1-(bi+i)] + carries[i] >= 0x100000000 then 1 else 0; ensures forall i {:trigger s[FatNatAddIndex(s.Length, si, i)]} :: 0<=i<8 ==> s[FatNatAddIndex(s.Length, si, i)] == mod0x100000000(a[FatNatAddIndex(a.Length, ai,i)] +b[FatNatAddIndex(b.Length, bi, i)] + carries[i]); method {:decl} Add32_unrolled_16( a:array, ai:int, b:array, bi:int, s:array, si:int, c_in:int) returns (c_out:int, ghost carries:seq) requires a!=null; requires IsWordSeq(a[..]); requires 0 <= ai; requires ai+16 <= a.Length; requires b!=null; requires IsWordSeq(b[..]); requires 0 <= bi; requires bi+16 <= b.Length; requires s!=null; requires 0 <= si; requires si+16 <= s.Length; requires 0<=c_in<=1; requires b!=s; requires a!=s; modifies s; ensures forall i :: 0<=i s[s.Length-1-i]==old(s[s.Length-1-i]); ensures 0<=c_out<=1; ensures |carries| == 17; ensures carries[0] == c_in; ensures carries[16] == c_out; ensures forall i {:trigger a[FatNatAddIndex(a.Length, ai, i)]} :: 0<=i<16 ==> carries[i+1] == if a[FatNatAddIndex(a.Length,ai,i)] +b[FatNatAddIndex(b.Length,bi,i)] + carries[i] >= 0x100000000 then 1 else 0; ensures forall i {:trigger s[FatNatAddIndex(s.Length, si, i)]} :: 0<=i<16 ==> s[FatNatAddIndex(s.Length, si, i)] == mod0x100000000(a[FatNatAddIndex(a.Length, ai,i)] +b[FatNatAddIndex(b.Length, bi, i)] + carries[i]); ================================================ FILE: ironclad-apps/src/Dafny/Libraries/FatNat/FatNatX86big.i.dfy ================================================ include "FatNatCommon.i.dfy" include "../BigNum/BigNatX86Shim.i.dfy" /* method {:decl} Add32_unrolled_32( a:array, ai:int, b:array, bi:int, s:array, si:int, c_in:int) returns (c_out:int, ghost carries:seq) requires a!=null; requires IsWordSeq(a[..]); requires 0 <= ai; requires ai+32 <= a.Length; requires b!=null; requires IsWordSeq(b[..]); requires 0 <= bi; requires bi+32 <= b.Length; requires s!=null; requires 0 <= si; requires si+32 <= s.Length; requires 0<=c_in<=1; requires b!=s; requires a!=s; modifies s; ensures forall i :: 0<=i s[s.Length-1-i]==old(s[s.Length-1-i]); ensures 0<=c_out<=1; ensures |carries| == 33; ensures carries[0] == c_in; ensures carries[32] == c_out; //- This line will go through in 347s ensures forall i {:trigger a[FatNatAddIndex(a.Length, ai, i)]} :: 0<=i<32 ==> carries[i+1] == if a[FatNatAddIndex(a.Length,ai,i)] +b[FatNatAddIndex(b.Length,bi,i)] + carries[i] >= 0x100000000 then 1 else 0; //- This line times out after 687s ensures forall i {:trigger s[FatNatAddIndex(s.Length, si, i)]} :: 0<=i<32 ==> s[FatNatAddIndex(s.Length, si, i)] == mod0x100000000(a[FatNatAddIndex(a.Length, ai,i)] +b[FatNatAddIndex(b.Length, bi, i)] + carries[i]); */ ================================================ FILE: ironclad-apps/src/Dafny/Libraries/FatNat/Transforms.i.dfy ================================================ include "../Util/arrays_and_seqs.i.dfy" include "CanonicalArrays.i.dfy" method BEWordArrayToByteArray(M:array) returns (m:array) requires M!=null; requires IsWordSeq(M[..]); ensures m!=null; ensures IsByteSeq(m[..]); ensures BEByteSeqToInt(m[..]) == BEWordSeqToInt(M[..]); //- ensures BEIntToByteSeq(I(M)) == m; //- no seq relation equivalence ensures m.Length==0 || 0) returns (M:array) requires m!=null; requires IsByteSeq(m[..]); ensures M!=null; ensures IsWordSeq(M[..]); ensures BEByteSeqToInt(m[..]) == BEWordSeqToInt(M[..]); //- ensures BEIntToByteSeq(I(M)) == m; //- no seq relation equivalence ensures M.Length==0 || 0, lastcs:seq, bs:seq, bdigits:int, cs:seq, lastj:int, j:int, lastborrow:int, borrow:int) requires 1<=j<=bdigits<=|oldcs|==|lastcs|==|cs|; requires bdigits <= |bs|; requires lastj+1 == j; requires 0<=lastborrow<2; requires 0<=borrow<2; requires pv==power2(32)==0x100000000; requires IsDigitSeq(power2(32), oldcs); requires IsDigitSeq(power2(32), bs); requires IsDigitSeq(power2(32), cs); requires IsDigitSeq(power2(32), lastcs); requires BEWordSeqToInt(oldcs) - BEWordSeqToInt(bs) == ( BEWordSeqToInt(SelectDigitRange(lastcs, |lastcs|, lastj)) + lastborrow - BEWordSeqToInt(SelectDigitRange(bs, bdigits, lastj)) ) * power(pv,lastj) + BEWordSeqToInt(SelectDigitRange(lastcs, lastj, 0)); ensures IsDigitSeq(power2(32), cs); ensures BEWordSeqToInt(oldcs) - BEWordSeqToInt(bs) == ( BEWordSeqToInt(SelectDigitRange(cs, |cs|, j)) + borrow - BEWordSeqToInt(SelectDigitRange(bs, bdigits, j)) ) * power(pv,j) + BEWordSeqToInt(SelectDigitRange(cs, j, 0)); { assume false; } lemma lemma_FleetNatSub_c_adequate_length(cs:seq, bs:seq, bdigits:int) requires IsWordSeq(cs); requires IsWordSeq(bs); requires BEWordSeqToInt(bs) <= BEWordSeqToInt(cs); requires (BEWordSeqToInt(bs)==0 && bdigits==0) || (0, b:array) //- always in-place because c always has enough room! requires b!=null; requires IsWordSeq(b[..]); requires c!=null; requires IsWordSeq(c[..]); requires c!=b; requires BEWordSeqToInt(b[..]) <= BEWordSeqToInt(c[..]); modifies c; ensures IsWordSeq(c[..]); ensures BEWordSeqToInt(old(c[..])) - BEWordSeqToInt(b[..]) == BEWordSeqToInt(c[..]); { ghost var pv := power2(32); lemma_2toX(); var bdigits := CountNonzeroDigits(b); lemma_FleetNatSub_c_adequate_length(c[..], b[..], bdigits); var borrow := 0; var blenm1 := b.Length - 1; var clenm1 := c.Length - 1; var j:=0; //- bridge from preconditions to subtract loop invariant calc { BEWordSeqToInt(old(c[..])) - BEWordSeqToInt(b[..]); { lemma_power_0(pv); } ( BEWordSeqToInt(c[..]) - BEWordSeqToInt(b[..]) ) * power(pv,j); { assert SelectDigitRange(c[..], c.Length, j) == c[..]; //- OBSERVE SEQ } ( BEWordSeqToInt(SelectDigitRange(c[..], c.Length, j)) + borrow - BEWordSeqToInt(SelectDigitRange(b[..], bdigits, j)) ) * power(pv,j); { assert SelectDigitRange(c[..], j, 0)==[]; //- OBSERVE SEQ reveal_BEDigitSeqToInt_private(); } ( BEWordSeqToInt(SelectDigitRange(c[..], c.Length, j)) + borrow - BEWordSeqToInt(SelectDigitRange(b[..], bdigits, j)) ) * power(pv,j) + BEWordSeqToInt(SelectDigitRange(c[..], j, 0)); } var C, B; assume C - B == borrow; while (j, bdigits:int, lastcs:seq, oldcs:seq, newcs:seq, j:int, oldj:int, lastcarry:int, prevcarry:int) requires pv==power2(32); requires 0 <= bdigits <= |bs|; requires bdigits <= |lastcs| == |oldcs| == |newcs|; requires 1<=j<=bdigits; requires oldj+1 == j; requires IsDigitSeq(pv, bs); requires IsDigitSeq(pv, SelectDigitRange(bs, j, oldj)); requires IsDigitSeq(pv, SelectDigitRange(lastcs, oldj, 0)); requires IsDigitSeq(pv, oldcs); requires IsDigitSeq(pv, SelectDigitRange(newcs, j, 0)); requires IsDigitSeq(pv, SelectDigitRange(newcs, oldj, 0)); requires IsDigitSeq(pv, SelectDigitRange(newcs, j, oldj)); //- things right of oldj are stable requires SelectDigitRange(lastcs, oldj, 0) == SelectDigitRange(newcs, oldj, 0); //- local step math result requires BEWordSeqToInt(SelectDigitRange(bs, j, oldj)) + BEWordSeqToInt(SelectDigitRange(oldcs, j, oldj)) + prevcarry == BEWordSeqToInt(SelectDigitRange(newcs, j, oldj)) + pv * lastcarry; //- induction hypothesis loop invariant requires BEWordSeqToInt(SelectDigitRange(bs, oldj, 0)) + BEWordSeqToInt(SelectDigitRange(oldcs, oldj, 0)) == BEWordSeqToInt(SelectDigitRange(lastcs, oldj, 0)) + prevcarry * power(pv, oldj); ensures BEWordSeqToInt(SelectDigitRange(bs, j, 0)) + BEWordSeqToInt(SelectDigitRange(oldcs, j, 0)) == BEWordSeqToInt(SelectDigitRange(newcs, j, 0)) + lastcarry * power(pv, j); { lemma_2toX32(); calc { BEWordSeqToInt(SelectDigitRange(bs, j, 0)) + BEWordSeqToInt(SelectDigitRange(oldcs, j, 0)); { lemma_BEInterpretation_Select_general(pv, bs, j, oldj, 0); } BEWordSeqToInt(SelectDigitRange(bs, j, oldj))*power(pv,oldj) + BEWordSeqToInt(SelectDigitRange(bs, oldj, 0)) + BEWordSeqToInt(SelectDigitRange(oldcs, j, 0)); { lemma_BEInterpretation_Select_general(pv, oldcs, j, oldj, 0); } BEWordSeqToInt(SelectDigitRange(bs, j, oldj))*power(pv,oldj) + BEWordSeqToInt(SelectDigitRange(bs, oldj, 0)) + BEWordSeqToInt(SelectDigitRange(oldcs, j, oldj))*power(pv,oldj) + BEWordSeqToInt(SelectDigitRange(oldcs, oldj, 0)); { lemma_mul_is_distributive_forall(); } (BEWordSeqToInt(SelectDigitRange(bs, j, oldj)) + BEWordSeqToInt(SelectDigitRange(oldcs, j, oldj))) *power(pv,oldj) + BEWordSeqToInt(SelectDigitRange(bs, oldj, 0)) + BEWordSeqToInt(SelectDigitRange(oldcs, oldj, 0)); //- induction hypothesis loop invariant transforms last lines of expressions (BEWordSeqToInt(SelectDigitRange(bs, j, oldj)) + BEWordSeqToInt(SelectDigitRange(oldcs, j, oldj))) *power(pv,oldj) + BEWordSeqToInt(SelectDigitRange(bs, oldj, 0)) + BEWordSeqToInt(SelectDigitRange(oldcs, oldj, 0)); { lemma_mul_is_distributive_forall(); } (BEWordSeqToInt(SelectDigitRange(bs, j, oldj)) + BEWordSeqToInt(SelectDigitRange(oldcs, j, oldj)) +prevcarry) *power(pv,oldj) + BEWordSeqToInt(SelectDigitRange(lastcs, oldj, 0)); //- by local math step (BEWordSeqToInt(SelectDigitRange(newcs, j, oldj)) + pv * lastcarry)*power(pv, oldj) + BEWordSeqToInt(SelectDigitRange(lastcs, oldj, 0)); (BEWordSeqToInt(SelectDigitRange(newcs, j, oldj)) + pv * lastcarry)*power(pv, oldj) + BEWordSeqToInt(SelectDigitRange(newcs, oldj, 0)); { lemma_mul_is_distributive_forall(); } BEWordSeqToInt(SelectDigitRange(newcs, j, oldj))*power(pv, oldj) + (pv * lastcarry)*power(pv, oldj) + BEWordSeqToInt(SelectDigitRange(newcs, oldj, 0)); { lemma_mul_is_associative_forall(); } BEWordSeqToInt(SelectDigitRange(newcs, j, oldj))*power(pv, oldj) + lastcarry*(pv*power(pv, oldj)) + BEWordSeqToInt(SelectDigitRange(newcs, oldj, 0)); { lemma_power_1(pv); lemma_power_adds(pv,1,oldj); } BEWordSeqToInt(SelectDigitRange(newcs, j, oldj))*power(pv, oldj) + lastcarry*power(pv, j) + BEWordSeqToInt(SelectDigitRange(newcs, oldj, 0)); { lemma_BEInterpretation_Select_general(pv, newcs, j, oldj, 0); } BEWordSeqToInt(SelectDigitRange(newcs, j, 0)) + lastcarry * power(pv, j); } } method FleetNatAddSimple(c:array, b:array, bdigits:int) returns (carry:int) requires c!=null; requires b!=null; requires c!=b; requires IsDigitSeq(power2(32), c[..]); requires IsDigitSeq(power2(32), b[..]); requires 0<=bdigits<=b.Length; requires bdigits <= c.Length; modifies c; ensures c!=null; ensures c==old(c); ensures IsDigitSeq(power2(32), c[..]); //- ensures BEWordSeqToInt(old(c[c.Length-bdigits..])) + BEWordSeqToInt(b[b.Length-bdigits..]) //- == BEWordSeqToInt(c[c.Length-bdigits..]) + power(power2(32), bdigits)*carry; ensures 0<=carry<2; ensures BEWordSeqToInt(old(c[..])) + BEWordSeqToInt(b[b.Length-bdigits..]) == BEWordSeqToInt(c[..]) + power(power2(32), bdigits)*carry; { ghost var pv := power2(32); lemma_2toX32(); ghost var bs := b[..]; ghost var oldcs := c[..]; ghost var clen := c.Length; var lastcarry:int := 0; var j:=0; calc { BEWordSeqToInt(SelectDigitRange(bs, j, 0)) + BEWordSeqToInt(SelectDigitRange(oldcs, j, 0)); { reveal_BEDigitSeqToInt_private(); } BEWordSeqToInt(SelectDigitRange(c[..], j, 0)) + lastcarry * power(pv, j); } var clenm1 := c.Length - 1; var blenm1 := b.Length - 1; while (j, place:nat, carry:int) returns (c':array) requires c!=null; requires IsDigitSeq(power2(32), c[..]); requires 0<=place<=c.Length; requires 0<=carry, a:array, b:array) returns (c':array) requires a!=null; requires IsDigitSeq(power2(32), a[..]); requires b!=null; requires IsDigitSeq(power2(32), b[..]); requires c!=null; requires IsDigitSeq(power2(32), c[..]); requires c!=b; requires c!=a; modifies c; ensures c'!=null; ensures c'==c || fresh(c'); ensures IsDigitSeq(power2(32), c'[..]); ensures BEWordSeqToInt(old(a[..])) + BEWordSeqToInt(b[..]) == BEWordSeqToInt(c'[..]); { lemma_2toX(); var bdigits := CountNonzeroDigits(b); //- RevealAbssValue(); //- if (c!=a) //- { //- assert c!=a; c' := FleetCopy(c, a, bdigits); assert BEWordSeqToInt(old(a[..])) == BEWordSeqToInt(c'[..]); //- } //- else if (c.Length, b:array) returns (c:array) requires a!=null; requires b!=null; requires IsDigitSeq(power2(32), a[..]); requires IsDigitSeq(power2(32), b[..]); ensures c!=null; ensures IsDigitSeq(power2(32), c[..]); ensures BEWordSeqToInt(a[..]) + BEWordSeqToInt(b[..]) == BEWordSeqToInt(c[..]); { c := FleetAlloc(a.Length); //- could just be c:=null, but DafnyCC doesn't allow it yet assert c!=a; c := FleetNatAdd(c, a, b); } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/FleetNat/FleetNatCommon.i.dfy ================================================ include "../Util/seqs_and_ints.i.dfy" include "../Util/seqs_common.i.dfy" include "../FatNat/FatNatCommon.i.dfy" include "../FatNat/CanonicalArrays.i.dfy" //- dafnycc was having a hard time stringing these together. lemma lemma_FasterCopyArray_helper(dst:array, doff:int, rdi:int, src:array, soff:int, rsi:int) requires dst!=null; requires src!=null; requires 0<=doff, doff:nat, src:array, soff:nat, count:nat) requires src!=null; requires soff+count <= src.Length; requires dst!=null; requires doff+count <= dst.Length; requires src!=dst; modifies dst; ensures dst[doff..doff+count] == src[soff..soff+count]; ensures dst[..doff] == old(dst[..doff]); ensures dst[doff+count..] == old(dst[doff+count..]); { var rdi := doff; var rsi := soff; var rcount := count; while (rcount>8) invariant 0<=rcount<=count; invariant rdi + rcount == doff + count; invariant rsi + rcount == soff + count; invariant dst[doff..rdi] == src[soff..rsi]; invariant dst[..doff] == old(dst[..doff]); invariant dst[doff+count..] == old(dst[doff+count..]); { assert dst[doff..rdi] == src[soff..rsi]; dst[rdi] := src[rsi]; rdi:=rdi+1; rsi:=rsi+1; lemma_FasterCopyArray_helper(dst, doff, rdi, src, soff, rsi); assert dst[doff..rdi] == src[soff..rsi]; dst[rdi] := src[rsi]; rdi:=rdi+1; rsi:=rsi+1; lemma_FasterCopyArray_helper(dst, doff, rdi, src, soff, rsi); assert dst[doff..rdi] == src[soff..rsi]; dst[rdi] := src[rsi]; rdi:=rdi+1; rsi:=rsi+1; lemma_FasterCopyArray_helper(dst, doff, rdi, src, soff, rsi); assert dst[doff..rdi] == src[soff..rsi]; dst[rdi] := src[rsi]; rdi:=rdi+1; rsi:=rsi+1; lemma_FasterCopyArray_helper(dst, doff, rdi, src, soff, rsi); assert dst[doff..rdi] == src[soff..rsi]; dst[rdi] := src[rsi]; rdi:=rdi+1; rsi:=rsi+1; lemma_FasterCopyArray_helper(dst, doff, rdi, src, soff, rsi); assert dst[doff..rdi] == src[soff..rsi]; dst[rdi] := src[rsi]; rdi:=rdi+1; rsi:=rsi+1; lemma_FasterCopyArray_helper(dst, doff, rdi, src, soff, rsi); assert dst[doff..rdi] == src[soff..rsi]; dst[rdi] := src[rsi]; rdi:=rdi+1; rsi:=rsi+1; lemma_FasterCopyArray_helper(dst, doff, rdi, src, soff, rsi); assert dst[doff..rdi] == src[soff..rsi]; dst[rdi] := src[rsi]; rdi:=rdi+1; rsi:=rsi+1; lemma_FasterCopyArray_helper(dst, doff, rdi, src, soff, rsi); assert dst[doff..rdi] == src[soff..rsi]; rcount := rcount - 8; } while (rcount>0) invariant 0<=rcount<=count; invariant rdi + rcount == doff + count; invariant rsi + rcount == soff + count; invariant dst[doff..rdi] == src[soff..rsi]; invariant dst[..doff] == old(dst[..doff]); invariant dst[doff+count..] == old(dst[doff+count..]); { dst[rdi] := src[rsi]; rdi:=rdi+1; rsi:=rsi+1; rcount := rcount - 1; lemma_FasterCopyArray_helper(dst, doff, rdi, src, soff, rsi); assert dst[doff..rdi] == src[soff..rsi]; } } method CountNonzeroDigits(c:array) returns (digits:int) requires c!=null; ensures 0<=digits<=c.Length; ensures forall i :: 0<=i c[i]==0; requires IsWordSeq(c[..]); ensures BEWordSeqToInt(c[..]) == BEWordSeqToInt(SelectDigitRange(c[..], digits, 0)); ensures BEWordSeqToInt(c[..]) < power(power2(32), digits); ensures (BEWordSeqToInt(c[..])==0 && digits==0) || (0 c[i]==0; { zeros := zeros + 1; } digits := c.Length - zeros; lemma_2toX(); lemma_LeadingZeros(power2(32), SelectDigitRange(c[..], digits, 0), c[..]); lemma_BEDigitSeqToInt_bound(power2(32), SelectDigitRange(c[..], digits, 0)); if (digits==0) { reveal_BEDigitSeqToInt_private(); assert BEWordSeqToInt(c[..])==0; } else { lemma_power_positive(power2(32), digits-1); lemma_mul_inequality(1, SelectDigitRange(c[..], digits, 0)[0], power(power2(32), digits-1)); } } method FleetCopy_copy_step(c:array, a:array, adigits:int) requires a!=null; requires IsDigitSeq(power2(32), a[..]); requires a!=c; requires c!=null; requires adigits <= c.Length; requires 0<=adigits<=a.Length; modifies c; ensures adigits<=c.Length; ensures c[c.Length-adigits..]==a[a.Length-adigits..]; ensures IsDigitSeq(power2(32), c[c.Length-adigits..]); { var alen := a.Length; var clen := c.Length; var cz:=clen-adigits; var ai:=alen-adigits; var ci:=cz; ghost var az := alen-adigits; while (ai, adigits:int) requires c!=null; requires 0 <= adigits <= c.Length; modifies c; ensures forall i :: 0<=i c[i]==0; ensures c[c.Length-adigits..] == old(c[c.Length-adigits..]); { var cz:=c.Length-adigits; var ci:=0; while (ci c[j]==0; { c[ci] := 0; ci:=ci+1; } } lemma lemma_FleetCopy_IsDigitSeq(asq:seq, is:seq, cs:seq, adigits:int) requires IsDigitSeq(power2(32), asq); requires 0<=adigits<=|asq|; requires adigits<=|is|; requires forall i :: 0<=i<|asq|-adigits ==> asq[i]==0; requires is[|is|-adigits..]==asq[|asq|-adigits..]; requires IsDigitSeq(power2(32), is[|is|-adigits..]); requires |is|<=|cs|; requires forall i :: 0<=i<|cs|-adigits ==> cs[i]==0; requires cs[|cs|-adigits..] == is[|is|-adigits..]; ensures IsDigitSeq(power2(32), cs); ensures BEDigitSeqToInt(power2(32), asq) == BEDigitSeqToInt(power2(32), cs); { ghost var pv := power2(32); lemma_2toX(); ghost var az := |asq| - adigits; ghost var cz := |cs| - adigits; forall (i | 0<=i<|cs|) ensures 0<=cs[i]=cz) { calc { cs[i]; cs[cz..][i-cz]; asq[az..][i-cz]; asq[i-cz+az]; asq[i-|cs|+adigits+|asq|-adigits]; asq[i-|cs|+|asq|]; } } } ghost var azeros := |asq|-adigits; ghost var shorta := asq[azeros..]; lemma_LeadingZeros(power2(32), shorta, cs[..]); lemma_LeadingZeros(power2(32), shorta, asq[..]); } //- mimics polar's mpi_copy method FleetCopy(c:array, a:array, minlen:nat) returns (c':array) requires a!=null; requires IsDigitSeq(power2(32), a[..]); requires a!=c; requires c != null; modifies c; ensures c'!=null; ensures c'==c || fresh(c'); ensures minlen <= c'.Length; ensures IsDigitSeq(power2(32), c'[..]); ensures BEDigitSeqToInt(power2(32), c'[..]) == BEDigitSeqToInt(power2(32), a[..]); { var alen := a.Length; if (/*c!=null &&*/ alen==c.Length && minlen<=c.Length) //- Fastpath { FasterCopyArray(c,0,a,0,alen); c':=c; calc { //- OBSERVE SEQ c'[..]; c[..]; c[0..alen]; a[0..alen]; a[..]; } return; } ghost var pv := power2(32); lemma_2toX(); var adigits:int := CountNonzeroDigits(a); var mindigits := adigits; if (mindigits < minlen) { mindigits := minlen; } if (/*c==null ||*/ c.Length < mindigits) { c' := new int[mindigits]; } else { c' := c; } ghost var c'len := c'.Length; assert adigits<=c'len; ghost var asq := a[..]; FleetCopy_copy_step(c', a, adigits); ghost var is := c'[..]; FleetCopy_zero_step(c', adigits); lemma_FleetCopy_IsDigitSeq(asq, is, c'[..], adigits); } method FleetGrow(c:array, minlen:nat) returns (c':array) requires c!=null; requires IsDigitSeq(power2(32), c[..]); requires c.Length < minlen; //- else why call me? ensures c'!=null; ensures c'==c || fresh(c'); ensures minlen == c'.Length; ensures IsDigitSeq(power2(32), c'[..]); ensures BEDigitSeqToInt(power2(32), c'[..]) == BEDigitSeqToInt(power2(32), c[..]); ensures c'[c'.Length-c.Length..] == c[..]; { c' := new int[minlen]; ghost var asq := c[..]; FleetCopy_copy_step(c', c, c.Length); ghost var is := c'[..]; FleetCopy_zero_step(c', c.Length); lemma_FleetCopy_IsDigitSeq(asq, is, c'[..], c.Length); } method FleetAlloc(len:nat) returns (c:array) ensures c!=null; ensures fresh(c); ensures c.Length == len; ensures forall i :: 0<=i c[i]==0; ensures BEDigitSeqToInt(power2(32), c[..]) == 0; { c := new int[len]; FleetCopy_zero_step(c, 0); lemma_2toX(); lemma_LeadingZeros(power2(32), [], c[..]); reveal_BEDigitSeqToInt_private(); } //- This generalized version tolerates h<|a| and 0, h:int, m:int, l:int) requires 1, b:seq, h:int, hi:int, li:int, l:int) requires 0<=l<=li<=hi<=h<=|a|==|b|; requires SelectDigitRange(a, h, l) == SelectDigitRange(b, h, l); ensures SelectDigitRange(a, hi, li) == SelectDigitRange(b, hi, li); { var ai := SelectDigitRange(a, hi, li); var bi := SelectDigitRange(b, hi, li); assert |ai| == |bi|; forall (i | 0<=i<|ai|) ensures ai[i] == bi[i]; { var xi := h-hi+i; calc { ai[i]; SelectDigitRange(a, hi, li)[i]; a[|a|-hi..|a|-li][i]; a[|a|-hi+i]; a[|a|-h+xi]; a[|a|-h..|a|-l][xi]; SelectDigitRange(a, h, l)[xi]; SelectDigitRange(b, h, l)[xi]; b[|b|-h..|b|-l][xi]; b[|b|-h+xi]; b[|b|-hi+i]; b[|b|-hi..|b|-li][i]; SelectDigitRange(b, hi, li)[i]; bi[i]; } } assert ai==bi; } lemma lemma_asm_Add_properties(x:int, y:int, z:int, c:int) requires word32(x); requires word32(y); requires z == mod0x100000000(x + y); requires c==0 || c==1; requires (c==1) <==> (z < y); ensures z == (x+y) % 0x100000000; ensures x+y == z + 0x100000000*c; { var pv := 0x100000000; lemma_mod0x100000000(x+y); lemma_word32(x); lemma_word32(y); lemma_mod_properties(); lemma_fundamental_div_mod(x+y, pv); } lemma lemma_BEWordSeqToInt_SelectDigitRange_empty(s:seq) requires IsDigitSeq(power2(32), s); ensures BEWordSeqToInt(SelectDigitRange(s, 0, 0)) == 0; { assert SelectDigitRange(s, 0, 0) == []; reveal_BEDigitSeqToInt_private(); } lemma lemma_PluckDigit_general(s:seq, h:int, i:int, l:int) requires IsDigitSeq(power2(32), s); requires 0<=l<=i, i:int) requires IsDigitSeq(power2(32), s); requires 0 <= i < |s|; ensures BEWordSeqToInt(s) == BEWordSeqToInt(SelectDigitRange(s, |s|, i+1)) * power(power2(32), i+1) + DigitAt(s, i) * power(power2(32), i) + BEWordSeqToInt(SelectDigitRange(s, i, 0)); { assert SelectDigitRange(s, |s|, 0) == s; //- OBSERVE SEQ lemma_PluckDigit_general(s, |s|, i, 0); } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/FleetNat/FleetNatMul.i.dfy ================================================ include "FleetNatAdd.i.dfy" include "FleetNatMulLoopOpt.i.dfy" method FleetNatMul_one(c:array, bi:nat, a:array, adigits:int, bv:int) requires c!=null; requires IsDigitSeq(power2(32), c[..]); requires a!=c; requires a!=null; requires IsDigitSeq(power2(32), a[..]); requires 0<=adigits<=a.Length; requires adigits <= c.Length; //- c-adequate-length requirement: requires BEWordSeqToInt(c[..]) + BEWordSeqToInt(SelectDigitRange(a[..], adigits, 0)) * bv * power(power2(32),bi) < power(power2(32), c.Length); requires adigits + bi <= c.Length; requires 0 <= bv < power2(32); modifies c; ensures IsDigitSeq(power2(32), c[..]); ensures BEWordSeqToInt(c[..]) == BEWordSeqToInt(old(c[..])) + BEWordSeqToInt(SelectDigitRange(a[..], adigits, 0)) * bv * power(power2(32),bi); { ghost var pv := power2(32); lemma_2toX(); ghost var oldcs := c[..]; var clenm1 := c.Length-1; var j := adigits; var carry; if (0 == adigits) { carry := 0; lemma_BEWordSeqToInt_SelectDigitRange_empty(a[..]); } else { carry := FleetNatMul_one_loop_opt(c, bi, a, adigits, bv); } //- propagate the carry out while (carry > 0) invariant adigits<=j<=c.Length; invariant 0<=carry= c.Length) { calc { power(pv, c.Length); > //- contradicts requirement c-adequate-length. BEWordSeqToInt(oldcs) + BEWordSeqToInt(SelectDigitRange(a[..], adigits, 0)) * bv * power(pv, bi); BEWordSeqToInt(c[..]) + carry*power(pv, j+bi); >= { lemma_BEWordSeqToInt_bound(c[..]); } carry*power(pv, j+bi); >= { lemma_power_positive(pv,j+bi); lemma_mul_increases(carry, power(pv, j+bi)); } power(pv, j+bi); >= { lemma_power_increases(pv, c.Length, j+bi); } power(pv, c.Length); } } var ci := clenm1 - (j+bi); var lastcj := c[ci]; lemma_word32(carry); lemma_word32(lastcj); var newcj := asm_Add(carry, lastcj); lemma_mod0x100000000(carry+lastcj); c[ci] := newcj; carry := 0; if (newcj < lastcj) { carry := 1; } j := j + 1; calc { newcj * power(pv, lastj+bi) + carry*power(pv, j+bi); { lemma_mod0x100000000(lastcarry+lastcj); lemma_mod_properties(); lemma_asm_Add_properties(lastcarry, lastcj, newcj, carry); } (lastcarry+lastcj-pv*carry) * power(pv, lastj+bi) + carry*power(pv, j+bi); { lemma_mul_is_distributive_forall(); } (lastcarry+lastcj) * power(pv, lastj+bi) - (pv*carry) * power(pv, lastj+bi) + carry*power(pv, j+bi); { lemma_mul_is_distributive_forall(); } lastcarry*power(pv, lastj+bi) + lastcj*power(pv, lastj+bi) - (pv*carry) * power(pv, lastj+bi) + carry*power(pv, j+bi); lastcj*power(pv,lastj+bi) + lastcarry*power(pv,lastj+bi) - (pv*carry)*power(pv,lastj+bi) + carry*power(pv, j+bi); { calc { (pv * carry) * power(pv,lastj+bi); { lemma_mul_is_associative_forall(); } carry * (pv*power(pv,lastj+bi)); { lemma_power_1(pv); } carry * (power(pv,1)*power(pv,lastj+bi)); { lemma_power_adds(pv,1,lastj+bi); } carry * power(pv,j+bi); } } lastcj*power(pv, lastj+bi) + lastcarry * power(pv, lastj+bi); } ghost var leftjunk := BEWordSeqToInt(SelectDigitRange(c[..], c.Length, j+bi)); assert SelectDigitRange(c[..], c.Length, j+bi) == SelectDigitRange(lastcs, |lastcs|, j+bi); //- OBSERVE SEQ ghost var rightjunk := BEWordSeqToInt(SelectDigitRange(c[..], lastj+bi, 0)); assert SelectDigitRange(c[..], lastj+bi, 0) == SelectDigitRange(lastcs, lastj+bi, 0); //- OBSERVE SEQ calc { BEWordSeqToInt(c[..]) + carry*power(pv, j+bi); { lemma_PluckDigit(c[..], lastj+bi); } BEWordSeqToInt(SelectDigitRange(c[..], c.Length, j+bi)) * power(pv, j+bi) + DigitAt(c[..], lastj+bi) * power(pv, lastj+bi) + BEWordSeqToInt(SelectDigitRange(c[..], lastj+bi, 0)) + carry*power(pv, j+bi); leftjunk * power(pv, j+bi) + newcj * power(pv, lastj+bi) + rightjunk + carry*power(pv, j+bi); leftjunk * power(pv, j+bi) + lastcj * power(pv, lastj+bi) + rightjunk + lastcarry * power(pv, lastj+bi); BEWordSeqToInt(SelectDigitRange(lastcs, |lastcs|, j+bi)) * power(pv, j+bi) + DigitAt(lastcs, lastj+bi) * power(pv, lastj+bi) + BEWordSeqToInt(SelectDigitRange(lastcs, lastj+bi, 0)) + lastcarry * power(pv, lastj+bi); { lemma_PluckDigit(lastcs, lastj+bi); } BEWordSeqToInt(lastcs) + lastcarry * power(pv, lastj+bi); } } } lemma {:timeLimitMultiplier 2} lemma_FleetNatMul_c_adequate_length(a:array, b:array, adigits:nat, bdigits:nat, bi:nat, bv:int) requires a!=null; requires IsDigitSeq(power2(32), a[..]); requires b!=null; requires IsDigitSeq(power2(32), b[..]); requires 0<=adigits<=a.Length; requires 0<=bi, b:array) returns (c:array) requires a!=null; requires IsDigitSeq(power2(32), a[..]); requires b!=null; requires IsDigitSeq(power2(32), b[..]); ensures c!=null; ensures fresh(c); ensures IsDigitSeq(power2(32), c[..]); ensures BEWordSeqToInt(c[..]) == BEWordSeqToInt(a[..]) * BEWordSeqToInt(b[..]); { ghost var pv := power2(32); lemma_2toX(); var adigits := CountNonzeroDigits(a); var bdigits := CountNonzeroDigits(b); var cdigits := adigits + bdigits; c := FleetAlloc(cdigits); var bi := 0; lemma_LeadingZeros(pv, [], SelectDigitRange(b[..], bi, 0)); lemma_BEWordSeqToInt_SelectDigitRange_empty(b[..]); var blenm1 := b.Length - 1; while (bi < bdigits) invariant 0<=bi<=bdigits; invariant IsDigitSeq(power2(32), c[..]); invariant BEWordSeqToInt(c[..]) == BEWordSeqToInt(a[..]) * BEWordSeqToInt(SelectDigitRange(b[..], bi, 0)); { ghost var lastc := c[..]; ghost var lastbi := bi; var bv := b[blenm1 - bi]; lemma_FleetNatMul_c_adequate_length(a, b, adigits, bdigits, bi, bv); FleetNatMul_one(c, bi, a, adigits, bv); bi := bi + 1; calc { BEWordSeqToInt(c[..]); BEWordSeqToInt(lastc) + BEWordSeqToInt(SelectDigitRange(a[..], adigits, 0)) * bv * power(pv,lastbi); BEWordSeqToInt(lastc) + BEWordSeqToInt(a[..]) * bv * power(pv,lastbi); BEWordSeqToInt(a[..]) * BEWordSeqToInt(SelectDigitRange(b[..], lastbi, 0)) + BEWordSeqToInt(a[..]) * bv * power(pv,lastbi); { lemma_mul_is_associative(BEWordSeqToInt(a[..]), bv, power(pv,lastbi)); } BEWordSeqToInt(a[..]) * BEWordSeqToInt(SelectDigitRange(b[..], lastbi, 0)) + BEWordSeqToInt(a[..]) * (bv * power(pv,lastbi)); { lemma_mul_is_distributive(BEWordSeqToInt(a[..]), BEWordSeqToInt(SelectDigitRange(b[..], lastbi, 0)), bv * power(pv,lastbi)); } BEWordSeqToInt(a[..]) * ( BEWordSeqToInt(SelectDigitRange(b[..], lastbi, 0)) + bv * power(pv,lastbi)); { lemma_SelectSingletonRange(b[..], bi, lastbi); lemma_BEDigitSeqToInt_singleton(pv, DigitAt(b[..], lastbi)); } BEWordSeqToInt(a[..]) * ( BEWordSeqToInt(SelectDigitRange(b[..], bi, lastbi)) * power(pv, lastbi) + BEWordSeqToInt(SelectDigitRange(b[..], lastbi, 0))); { lemma_BEInterpretation_Select_general(pv, b[..], bi, lastbi, 0); } BEWordSeqToInt(a[..]) * BEWordSeqToInt(SelectDigitRange(b[..], bi, 0)); } } lemma_LeadingZeros(pv, SelectDigitRange(b[..], bi, 0), b[..]); } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/FleetNat/FleetNatMulLemmas.i.dfy ================================================ include "FleetNatAdd.i.dfy" lemma lemma_asm_Mul64(x:int, y:int, hi:int, lo:int) requires word32(x); requires word32(y); requires word32(hi); requires word32(lo); requires lo == mod0x100000000(x * y); requires hi == (x * y) / 0x100000000; ensures hi*power2(32)+lo == x*y; ensures 0 <= lo < power2(32); ensures 0 <= hi < power2(32)-1; ensures 0 <= x*y; { lemma_2toX(); var pv:=power2(32); lemma_word32(x); lemma_word32(y); lemma_word32(hi); lemma_word32(lo); calc { x*y; <= { lemma_mul_inequality(x,pv-1,y); } (pv-1)*y; <= { lemma_mul_inequality(y,pv-1,pv-1); } (pv-1)*(pv-1); { lemma_mul_is_distributive_forall(); } pv*pv-2*pv+1; } lemma_mod_properties(); lemma_mod0x100000000(x*y); lemma_fundamental_div_mod(x*y, pv); if (pv<=hi) { calc { pv*pv; <= { lemma_fundamental_div_mod(x*y,pv); } pv*((x*y)/pv); <= x*y; < { lemma_mul_strict_inequality(x, pv, y); } pv*y; < { lemma_mul_strict_inequality(y, pv, pv); } pv*pv; } //- contradiction } if (hi == pv-1) { calc { pv*pv - pv; < (pv-1)*pv; <= (pv-1)*pv+lo; hi*pv+lo; x*y; < (pv-1)*(pv-1); pv*pv-2*pv-1; < pv*pv - pv; } //- contradiction } } lemma lemma_FleetNatMul_one_element_properties(pv:int, aj:int, bv:int, mhi:int, mlo:int, lastcarry:int, add1:int, carry1:int, lastcj:int, newcj:int, carry2:int, add3:int, carry3:int, carry:int, carry4:int) requires pv==power2(32); requires 0<=aj= pv*pv; //- assert aj*bv + lastcarry + lastcj < pv*pv; //- } //- assert carry4==0; } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/FleetNat/FleetNatMulLoopOpt.i.dfy ================================================ include "FleetNatMulOpt.i.dfy" include "FleetNatMulLoopOptLemmas.i.dfy" // Bryan, here's the most important loop we run. This is a working // implementation that calls out to your FleetNatMulMathOpt inner-loop // to exploit adc propagation. // Your goal is to optimize the loop, in particular by inlining the // mul/add/adc bit. I think we'll get a bunch of benefit even without // unrolling. method FleetNatMul_one_loop_opt(c:array, bi:nat, a:array, adigits:int, bv:int) returns (carry:int) requires c!=null; requires IsDigitSeq(power2(32), c[..]); requires a!=c; requires a!=null; requires IsDigitSeq(power2(32), a[..]); requires 0= 0; requires a.Length > 0; requires c.Length > 0; requires 0 <= bv < power2(32); modifies c; ensures 0 <= carry < power2(32); ensures IsDigitSeq(power2(32), c[..]); ensures BEWordSeqToInt(c[..]) + carry*power(power2(32), adigits+bi) == BEWordSeqToInt(old(c[..])) + BEWordSeqToInt(SelectDigitRange(a[..], adigits, 0)) * bv * power(power2(32), bi); ensures forall k :: 0 <= k < c.Length-1-(adigits+bi) ==> c[k] == old(c[k]); { ghost var pv := power2(32); lemma_2toX(); ghost var oldcs := c[..]; var alenm1 := a.Length-1; var clenm1 := c.Length-1; var j := 0; carry := 0; lemma_BEWordSeqToInt_SelectDigitRange_empty(a[..]); //- establish partial sum invariant while (j < adigits) invariant 0<=j<=adigits; invariant IsDigitSeq(pv, c[..]); invariant 0<=carry c[k] == old(c[k]); { ghost var lastj := j; ghost var lastcarry := carry; ghost var lastcs := c[..]; ghost var asq := a[..]; var ci := clenm1 - (j+bi); var ai := alenm1 - j; var aj := a[ai]; var lastcj := c[ci]; var newcj; //- #if opt newcj,carry := FleetNatMulMathOpt(aj, bv, lastcj, carry); //- #endif opt //- #if standard //- //- mul //- lemma_mod_properties(); //- lemma_word32(aj); //- lemma_word32(bv); //- var mhi,mlo := asm_Mul64(aj, bv); //- lemma_asm_Mul64(aj, bv, mhi, mlo); //- //- //- add1 //- lemma_word32(mlo); //- lemma_word32(lastcarry); //- var add1 := asm_Add(mlo, carry); //- var carry1 := 0; //- if (add1 < carry) { carry1 := 1; } //- lemma_asm_Add_properties(mlo, lastcarry, add1, carry1); //- //- //- add2 //- lemma_word32(lastcj); //- newcj := asm_Add(add1, lastcj); //- var carry2 := 0; //- if (newcj < lastcj) { carry2 := 1; } //- lemma_asm_Add_properties(add1, lastcj, newcj, carry2); //- //- //- add3 //- lemma_word32(carry1); //- lemma_word32(carry2); //- var add3 := asm_Add(carry1, carry2); //- ghost var carry3 := 0; //- if (add3 < carry2) { carry3 := 1; } //- lemma_asm_Add_properties(carry1, carry2, add3, carry3); //- //- //- add4 //- carry := asm_Add(add3, mhi); //- ghost var carry4 := 0; //- if (carry < mhi) { carry4 := 1; } //- lemma_asm_Add_properties(add3, mhi, carry, carry4); //- //- lemma_FleetNatMul_one_element_properties(pv, //- aj, bv, mhi, mlo, //- lastcarry, add1, carry1, //- lastcj, newcj, carry2, //- add3, carry3, //- carry, carry4); //- #endif standard c[ci] := newcj; j := j + 1; lemma_FleetNatMul_one_partial_sum_induction( pv, oldcs, lastcs, c[..], a[..], adigits, bi, bv, j, lastj, carry, lastcarry, lastcj, newcj); } } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/FleetNat/FleetNatMulLoopOptLemmas.i.dfy ================================================ include "FleetNatAdd.i.dfy" //- mpi_mul_hlp uses 16/8/1 unrolling and muladdc and optionally a special MULADDC_HUIT instruction //- then it propagates the carries out. //- s is the source value, d is the dest value (shifted with pointer math), b is the single //- limb being multiplied in. //- mpi_mul_mpi counts up the zeros and preallocates i+j, since that's actually precise. // Noice. // The contents of X is always discarded, so all we could possibly save is an allocation. // Let's ignore that option for now. lemma lemma_FleetNatMul_one_element(pv:int, newcj:int, carry:int, aj:int, bv:int, lastcj:int, lastcarry:int, mlo:int, mhi:int, add1:int, carry1:int, carry2:int) requires pv==power2(32); requires Word32(newcj); requires Word32(carry); requires Word32(aj); requires Word32(bv); requires Word32(lastcj); requires Word32(lastcarry); requires mhi == (aj * bv) / 0x100000000; requires mlo == mod0x100000000(aj * bv); requires add1 == mod0x100000000(mlo + lastcarry); requires carry1 == if add1 < lastcarry then 1 else 0; requires newcj == mod0x100000000(mod0x100000000(mlo + lastcarry) + lastcj); requires carry2 == if mod0x100000000(mlo + lastcarry) + lastcj >= 0x100000000 then 1 else 0; requires carry == mod0x100000000(mhi + carry1 + carry2); ensures newcj + carry*pv == aj * bv + lastcj + lastcarry; { lemma_2toX(); calc { 0; <= { lemma_mul_nonnegative_forall(); } aj * bv; } // Strip off Boogie-level definitions lemma_mod0x100000000(aj * bv); assert mlo == (aj * bv) % 0x100000000; lemma_mod0x100000000(mlo + lastcarry); assert add1 == (mlo + lastcarry) % 0x100000000; lemma_mod0x100000000(((mlo + lastcarry) % 0x100000000) + lastcj); assert newcj == (((mlo + lastcarry) % 0x100000000) + lastcj) % 0x100000000; var product := aj * bv; calc { product; { lemma_fundamental_div_mod(product, pv); } pv * (product / pv) + (product % pv); pv * mhi + mlo; } assert product == pv * mhi + mlo; calc { mlo + lastcarry; { lemma_word32(mlo); lemma_word32(lastcarry); lemma_word32(add1); lemma_asm_Add_properties(mlo, lastcarry, add1, carry1); } carry1 * pv + add1; } calc { add1 + lastcj; { lemma_word32(add1); lemma_word32(lastcj); lemma_word32(newcj); lemma_asm_Add_properties(add1, lastcj, newcj, carry2); } carry2 * pv + newcj; } var untruncated_carry := mhi + carry1 + carry2; calc { untruncated_carry * pv; (mhi + carry1 + carry2) * pv; { lemma_mul_is_distributive_forall(); } mhi * pv + carry1 * pv + carry2 * pv; mhi * pv + (mlo + lastcarry - add1) + carry2*pv; mhi * pv + (mlo + lastcarry - add1) + (add1 + lastcj - newcj); mhi * pv + mlo + lastcarry + lastcj - newcj; } calc { newcj + untruncated_carry * pv; mhi * pv + mlo + lastcarry + lastcj; { lemma_mul_is_commutative_forall(); } product + lastcarry + lastcj; } if (untruncated_carry >= pv) { calc { newcj + untruncated_carry * pv; product + lastcarry + lastcj; <= calc { product; aj*bv; <= { lemma_mul_upper_bound(aj, pv - 1, bv, pv - 1); } (pv - 1)*(pv - 1); } (pv-1)*(pv-1) + pv - 1 + pv - 1; pv*pv - 2*pv + 1 + pv - 1 + pv - 1; pv*pv - 1; < pv * pv; } assert untruncated_carry * pv >= pv * pv; } assert untruncated_carry < pv; lemma_div_pos_is_pos(product, pv); assert 0 <= untruncated_carry; lemma_small_mod(untruncated_carry, pv); lemma_mod0x100000000(untruncated_carry); assert mod0x100000000(untruncated_carry) == untruncated_carry; } lemma lemma_FleetNatMul_one_partial_sum_induction(pv:int, oldcs:seq, lastcs:seq, cs:seq, asq:seq, adigits:int, bi:int, bv:int, j:int, lastj:int, carry:int, lastcarry:int, lastcj:int, newcj:int) requires pv==power2(32); requires IsWordSeq(cs); requires IsWordSeq(oldcs); requires IsWordSeq(lastcs); requires IsWordSeq(asq); requires |cs|==|lastcs|==|oldcs|; requires forall i :: 0<=i<|cs| && i!=|cs|-1-(lastj+bi) ==> lastcs[i]==cs[i]; requires lastj+1 == j <= adigits <= |asq|; requires 0 <= lastj; requires 0 <= bi; requires lastj+bi < |cs|; //- element operation components requires lastcj == DigitAt(lastcs, lastj+bi); requires newcj == DigitAt(cs, lastj+bi); requires newcj + carry*pv == DigitAt(asq, lastj) * bv + lastcj + lastcarry; requires 0<=carry x < y; requires z == mod0x100000000(x - y); ensures z == (x - y) % 0x100000000; ensures x-y == z - 0x100000000*c; { var pv := 0x100000000; lemma_mod0x100000000(x-y); lemma_word32(x); lemma_word32(y); lemma_mod_properties(); lemma_fundamental_div_mod(x-y, pv); } lemma lemma_FleetNatSub_local_math(pv:int, lastcj:int, newcj:int, midcj:int, bj:int, lastborrow:int, borrow1:int, borrow2:int, borrow:int) requires pv==power2(32)==0x100000000; requires 0<=lastcj, cs:seq, lastj:int, j:int, lastborrow:int) requires 1<=j<=|lastcs|==|cs|; requires lastj+1 == j; requires 0<=lastborrow<2; requires pv==power2(32)==0x100000000; requires IsDigitSeq(power2(32), cs); requires IsDigitSeq(power2(32), lastcs); requires SelectDigitRange(lastcs, |lastcs|, j) == SelectDigitRange(cs, |cs|, j); //- stability requires SelectDigitRange(lastcs, lastj, 0) == SelectDigitRange(cs, lastj, 0); //- stability ensures BEWordSeqToInt(SelectDigitRange(lastcs, |lastcs|, lastj)) * power(pv,lastj) - lastborrow * power(pv,lastj) + BEWordSeqToInt(SelectDigitRange(lastcs, lastj, 0)) == BEWordSeqToInt(SelectDigitRange(cs, |cs|, j)) * power(pv,j) + DigitAt(lastcs, lastj) * power(pv,lastj) - lastborrow * power(pv,lastj) + BEWordSeqToInt(SelectDigitRange(cs, lastj, 0)); { calc { BEWordSeqToInt(SelectDigitRange(lastcs, |lastcs|, lastj)) * power(pv,lastj) - lastborrow * power(pv,lastj) + BEWordSeqToInt(SelectDigitRange(lastcs, lastj, 0)); { lemma_BEInterpretation_Select_general(pv, lastcs, |lastcs|, j, lastj); } ( BEWordSeqToInt(SelectDigitRange(lastcs, |lastcs|, j)) * power(pv,1) + BEWordSeqToInt(SelectDigitRange(lastcs, j, lastj)) ) * power(pv,lastj) - lastborrow * power(pv,lastj) + BEWordSeqToInt(SelectDigitRange(lastcs, lastj, 0)); { lemma_mul_is_distributive_forall(); } BEWordSeqToInt(SelectDigitRange(lastcs, |lastcs|, j)) * power(pv,1) * power(pv,lastj) + BEWordSeqToInt(SelectDigitRange(lastcs, j, lastj)) * power(pv,lastj) - lastborrow * power(pv,lastj) + BEWordSeqToInt(SelectDigitRange(lastcs, lastj, 0)); { lemma_mul_is_associative_forall(); lemma_power_adds(pv, 1, lastj); } BEWordSeqToInt(SelectDigitRange(lastcs, |lastcs|, j)) * power(pv,j) + BEWordSeqToInt(SelectDigitRange(lastcs, j, lastj)) * power(pv,lastj) - lastborrow * power(pv,lastj) + BEWordSeqToInt(SelectDigitRange(lastcs, lastj, 0)); { lemma_SelectSingletonRange(lastcs, j, lastj); lemma_BEDigitSeqToInt_singleton(pv, DigitAt(lastcs,lastj)); } BEWordSeqToInt(SelectDigitRange(lastcs, |lastcs|, j)) * power(pv,j) + DigitAt(lastcs, lastj) * power(pv,lastj) - lastborrow * power(pv,lastj) + BEWordSeqToInt(SelectDigitRange(lastcs, lastj, 0)); //- stability hypothesis BEWordSeqToInt(SelectDigitRange(cs, |cs|, j)) * power(pv,j) + DigitAt(lastcs, lastj) * power(pv,lastj) - lastborrow * power(pv,lastj) + BEWordSeqToInt(SelectDigitRange(cs, lastj, 0)); } } lemma lemma_FleetNatSub_digit_rearrangement(pv:int, oldcs:seq, lastcs:seq, bs:seq, bdigits:int, cs:seq, lastj:int, j:int, lastborrow:int, borrow:int) requires 1<=j<=bdigits<=|oldcs|==|lastcs|==|cs|; requires bdigits <= |bs|; requires lastj+1 == j; requires 0<=lastborrow<2; requires 0<=borrow<2; requires pv==power2(32)==0x100000000; requires IsDigitSeq(power2(32), oldcs); requires IsDigitSeq(power2(32), bs); requires IsDigitSeq(power2(32), cs); requires IsDigitSeq(power2(32), lastcs); requires SelectDigitRange(lastcs, |lastcs|, j) == SelectDigitRange(cs, |cs|, j); //- stability requires SelectDigitRange(lastcs, lastj, 0) == SelectDigitRange(cs, lastj, 0); //- stability requires BEWordSeqToInt(oldcs) - BEWordSeqToInt(bs) == ( BEWordSeqToInt(SelectDigitRange(lastcs, |lastcs|, lastj)) - lastborrow - BEWordSeqToInt(SelectDigitRange(bs, bdigits, lastj)) ) * power(pv,lastj) + BEWordSeqToInt(SelectDigitRange(lastcs, lastj, 0)); requires DigitAt(lastcs, lastj) - lastborrow - DigitAt(bs, lastj) == DigitAt(cs, lastj) - pv*borrow; //- local math step ensures 0<=borrow<2; ensures IsDigitSeq(power2(32), cs); ensures BEWordSeqToInt(oldcs) - BEWordSeqToInt(bs) == ( BEWordSeqToInt(SelectDigitRange(cs, |cs|, j)) - borrow - BEWordSeqToInt(SelectDigitRange(bs, bdigits, j)) ) * power(pv,j) + BEWordSeqToInt(SelectDigitRange(cs, j, 0)); { //-ghost var pv := power2(32); lemma_2toX(); lemma_2toX(); lemma_SelectSingletonRange(lastcs, j, lastj); lemma_BEDigitSeqToInt_singleton(pv, DigitAt(lastcs,lastj)); //- assert BEWordSeqToInt(SelectDigitRange(lastcs, j, lastj)) == DigitAt(lastcs, lastj); lemma_SelectSingletonRange(cs, j, lastj); lemma_BEDigitSeqToInt_singleton(pv, DigitAt(cs,lastj)); //- assert BEWordSeqToInt(SelectDigitRange(cs, j, lastj)) == DigitAt(cs, lastj); //- b-split calc { BEWordSeqToInt(SelectDigitRange(bs, bdigits, lastj)) * power(pv,lastj); { lemma_BEInterpretation_Select_general(pv, bs, bdigits, j, lastj); } ( BEWordSeqToInt(SelectDigitRange(bs, bdigits, j)) * power(pv,1) + BEWordSeqToInt(SelectDigitRange(bs, j, lastj)) ) * power(pv,lastj); { lemma_mul_is_distributive_forall(); } BEWordSeqToInt(SelectDigitRange(bs, bdigits, j)) * power(pv,1) * power(pv, lastj) + BEWordSeqToInt(SelectDigitRange(bs, j, lastj)) * power(pv, lastj); { lemma_mul_is_associative_forall(); lemma_power_adds(pv, 1, lastj); } BEWordSeqToInt(SelectDigitRange(bs, bdigits, j)) * power(pv,j) + BEWordSeqToInt(SelectDigitRange(bs, j, lastj)) * power(pv, lastj); { lemma_SelectSingletonRange(bs, j, lastj); lemma_BEDigitSeqToInt_singleton(pv, DigitAt(bs,lastj)); } BEWordSeqToInt(SelectDigitRange(bs, bdigits, j)) * power(pv,j) + DigitAt(bs, lastj) * power(pv, lastj); } //- core calc { DigitAt(lastcs, lastj) * power(pv,lastj) - lastborrow * power(pv,lastj) - DigitAt(bs, lastj) * power(pv, lastj); { lemma_mul_is_distributive_forall(); } (DigitAt(lastcs, lastj) - lastborrow - DigitAt(bs, lastj)) * power(pv, lastj); //- requires "local math step" (DigitAt(cs, lastj) - borrow*pv) * power(pv, lastj); { lemma_mul_is_distributive_forall(); } DigitAt(cs, lastj)*power(pv,lastj) - borrow * pv * power(pv,lastj); { lemma_mul_is_associative_forall(); lemma_power_adds(pv, 1, lastj); lemma_power_1(pv); } DigitAt(cs, lastj)*power(pv,lastj) - borrow * power(pv,j); } calc { BEWordSeqToInt(oldcs) - BEWordSeqToInt(bs); ( BEWordSeqToInt(SelectDigitRange(lastcs, |lastcs|, lastj)) - lastborrow - BEWordSeqToInt(SelectDigitRange(bs, bdigits, lastj)) ) * power(pv,lastj) + BEWordSeqToInt(SelectDigitRange(lastcs, lastj, 0)); { lemma_mul_is_distributive_forall(); } BEWordSeqToInt(SelectDigitRange(lastcs, |lastcs|, lastj)) * power(pv,lastj) - lastborrow * power(pv,lastj) - BEWordSeqToInt(SelectDigitRange(bs, bdigits, lastj)) * power(pv,lastj) + BEWordSeqToInt(SelectDigitRange(lastcs, lastj, 0)); { lemma_FleetNatSub_rearrangement_left(pv, lastcs, cs, lastj, j, lastborrow); } BEWordSeqToInt(SelectDigitRange(cs, |cs|, j)) * power(pv,j) + DigitAt(lastcs, lastj) * power(pv,lastj) - lastborrow * power(pv,lastj) + BEWordSeqToInt(SelectDigitRange(cs, lastj, 0)) - BEWordSeqToInt(SelectDigitRange(bs, bdigits, lastj)) * power(pv,lastj); //- calc "b-split" BEWordSeqToInt(SelectDigitRange(cs, |cs|, j))*power(pv,j) + DigitAt(lastcs, lastj) * power(pv,lastj) - lastborrow * power(pv,lastj) - BEWordSeqToInt(SelectDigitRange(bs, bdigits, j)) * power(pv,j) - DigitAt(bs, lastj) * power(pv, lastj) + BEWordSeqToInt(SelectDigitRange(cs, lastj, 0)); //- calc "core" BEWordSeqToInt(SelectDigitRange(cs, |cs|, j)) * power(pv,j) - borrow * power(pv,j) - BEWordSeqToInt(SelectDigitRange(bs, bdigits, j)) * power(pv,j) + DigitAt(cs, lastj)*power(pv,lastj) + BEWordSeqToInt(SelectDigitRange(cs, lastj, 0)); BEWordSeqToInt(SelectDigitRange(cs, |cs|, j)) * power(pv,j) - borrow * power(pv,j) - BEWordSeqToInt(SelectDigitRange(bs, bdigits, j)) * power(pv,j) + BEWordSeqToInt(SelectDigitRange(cs, j, lastj))*power(pv,lastj) + BEWordSeqToInt(SelectDigitRange(cs, lastj, 0)); { lemma_BEInterpretation_Select_general(pv, cs, j, lastj, 0); } BEWordSeqToInt(SelectDigitRange(cs, |cs|, j)) * power(pv,j) - borrow * power(pv,j) - BEWordSeqToInt(SelectDigitRange(bs, bdigits, j)) * power(pv,j) + BEWordSeqToInt(SelectDigitRange(cs, j, 0)); { lemma_mul_is_distributive_forall(); } ( BEWordSeqToInt(SelectDigitRange(cs, |cs|, j)) - borrow - BEWordSeqToInt(SelectDigitRange(bs, bdigits, j)) ) * power(pv,j) + BEWordSeqToInt(SelectDigitRange(cs, j, 0)); } } lemma lemma_FleetNatSub_c_adequate_length(cs:seq, bs:seq, bdigits:int) requires IsWordSeq(cs); requires IsWordSeq(bs); requires BEWordSeqToInt(bs) <= BEWordSeqToInt(cs); requires (BEWordSeqToInt(bs)==0 && bdigits==0) || (0, lastcs:seq, bs:seq, cs:seq, lastj:int, j:int, lastborrow:int, borrow:int) requires 1<=j<=|oldcs|==|lastcs|==|cs|; requires lastj+1 == j; requires 0<=lastborrow<2; requires 0<=borrow<2; requires pv==power2(32)==0x100000000; requires IsDigitSeq(power2(32), oldcs); requires IsDigitSeq(power2(32), bs); requires IsDigitSeq(power2(32), cs); requires IsDigitSeq(power2(32), lastcs); requires SelectDigitRange(lastcs, |lastcs|, j) == SelectDigitRange(cs, |cs|, j); //- stability requires SelectDigitRange(lastcs, lastj, 0) == SelectDigitRange(cs, lastj, 0); //- stability requires DigitAt(lastcs, lastj) - lastborrow == DigitAt(cs, lastj) - borrow * pv; //- core step requires BEWordSeqToInt(oldcs) - BEWordSeqToInt(bs) == ( BEWordSeqToInt(SelectDigitRange(lastcs, |lastcs|, lastj)) - lastborrow) * power(pv,lastj) + BEWordSeqToInt(SelectDigitRange(lastcs, lastj, 0)); ensures BEWordSeqToInt(oldcs) - BEWordSeqToInt(bs) == ( BEWordSeqToInt(SelectDigitRange(cs, |cs|, j)) - borrow) * power(pv,j) + BEWordSeqToInt(SelectDigitRange(cs, j, 0)); { calc { DigitAt(lastcs, lastj) * power(pv,lastj) - lastborrow * power(pv,lastj); { lemma_mul_is_distributive_forall(); } (DigitAt(lastcs, lastj) - lastborrow) * power(pv,lastj); //- core step (DigitAt(cs, lastj) - borrow * pv) * power(pv,lastj); { lemma_mul_is_distributive_forall(); } DigitAt(cs, lastj) * power(pv, lastj) - borrow * pv * power(pv,lastj); { lemma_mul_is_associative_forall(); lemma_power_adds(pv, 1, lastj); lemma_power_1(pv); } DigitAt(cs, lastj) * power(pv, lastj) - borrow * power(pv,j); } calc { ( BEWordSeqToInt(SelectDigitRange(lastcs, |lastcs|, lastj)) - lastborrow) * power(pv,lastj) + BEWordSeqToInt(SelectDigitRange(lastcs, lastj, 0)); { lemma_mul_is_distributive_forall(); } BEWordSeqToInt(SelectDigitRange(lastcs, |lastcs|, lastj)) * power(pv,lastj) - lastborrow * power(pv,lastj) + BEWordSeqToInt(SelectDigitRange(lastcs, lastj, 0)); { lemma_FleetNatSub_rearrangement_left(pv, lastcs, cs, lastj, j, lastborrow); } BEWordSeqToInt(SelectDigitRange(cs, |cs|, j)) * power(pv,j) + DigitAt(lastcs, lastj) * power(pv,lastj) - lastborrow * power(pv,lastj) + BEWordSeqToInt(SelectDigitRange(cs, lastj, 0)); //- core calc BEWordSeqToInt(SelectDigitRange(cs, |cs|, j)) * power(pv,j) - borrow * power(pv,j) + DigitAt(cs, lastj) * power(pv, lastj) + BEWordSeqToInt(SelectDigitRange(cs, lastj, 0)); { lemma_SelectSingletonRange(cs, j, lastj); lemma_BEDigitSeqToInt_singleton(pv, DigitAt(cs,lastj)); } BEWordSeqToInt(SelectDigitRange(cs, |cs|, j)) * power(pv,j) - borrow * power(pv,j) + BEWordSeqToInt(SelectDigitRange(cs, j, lastj)) * power(pv, lastj) + BEWordSeqToInt(SelectDigitRange(cs, lastj, 0)); { lemma_BEInterpretation_Select_general(pv, cs, j, lastj, 0); } BEWordSeqToInt(SelectDigitRange(cs, |cs|, j)) * power(pv,j) - borrow * power(pv,j) + BEWordSeqToInt(SelectDigitRange(cs, j, 0)); { lemma_mul_is_distributive_forall(); } ( BEWordSeqToInt(SelectDigitRange(cs, |cs|, j)) - borrow) * power(pv,j) + BEWordSeqToInt(SelectDigitRange(cs, j, 0)); } } method FleetNatSub(c:array, b:array) //- always in-place because c always has enough room! requires b!=null; requires IsWordSeq(b[..]); requires c!=null; requires IsWordSeq(c[..]); requires c!=b; requires BEWordSeqToInt(b[..]) <= BEWordSeqToInt(c[..]); modifies c; ensures IsWordSeq(c[..]); ensures BEWordSeqToInt(old(c[..])) - BEWordSeqToInt(b[..]) == BEWordSeqToInt(c[..]); { ghost var pv := power2(32); lemma_2toX(); var bdigits := CountNonzeroDigits(b); lemma_FleetNatSub_c_adequate_length(c[..], b[..], bdigits); var borrow := 0; var blenm1 := b.Length - 1; var clenm1 := c.Length - 1; var j:=0; //- bridge from preconditions to subtract loop invariant calc { BEWordSeqToInt(old(c[..])) - BEWordSeqToInt(b[..]); { lemma_power_0(pv); } ( BEWordSeqToInt(c[..]) - BEWordSeqToInt(b[..]) ) * power(pv,j); { assert SelectDigitRange(c[..], c.Length, j) == c[..]; //- OBSERVE SEQ } ( BEWordSeqToInt(SelectDigitRange(c[..], c.Length, j)) + borrow - BEWordSeqToInt(SelectDigitRange(b[..], bdigits, j)) ) * power(pv,j); { assert SelectDigitRange(c[..], j, 0)==[]; //- OBSERVE SEQ reveal_BEDigitSeqToInt_private(); } ( BEWordSeqToInt(SelectDigitRange(c[..], c.Length, j)) + borrow - BEWordSeqToInt(SelectDigitRange(b[..], bdigits, j)) ) * power(pv,j) + BEWordSeqToInt(SelectDigitRange(c[..], j, 0)); } //- subtract loop while (j0) { //- borrow can't fall off the top, because we requires-ed that c>=b. calc { BEWordSeqToInt(old(c[..])) - BEWordSeqToInt(b[..]); ( BEWordSeqToInt(SelectDigitRange(c[..], c.Length, j)) - 1) * power(pv,j) + BEWordSeqToInt(SelectDigitRange(c[..], j, 0)); { assert SelectDigitRange(c[..], c.Length, j)==[]; reveal_BEDigitSeqToInt_private(); } - 1 * power(pv,j) + BEWordSeqToInt(SelectDigitRange(c[..], j, 0)); < { lemma_BEDigitSeqToInt_bound(pv, SelectDigitRange(c[..], j, 0)); } 0; } assert false; } } //- Caller assumes newly-allocated c. method ICantBelieveItsNotFatNatSub(a:array, b:array) returns (c:array) requires a!=null; requires b!=null; requires IsDigitSeq(power2(32), a[..]); requires IsDigitSeq(power2(32), b[..]); requires BEWordSeqToInt(b[..]) <= BEWordSeqToInt(a[..]); ensures c!=null; ensures fresh(c); ensures IsDigitSeq(power2(32), c[..]); ensures BEWordSeqToInt(a[..]) - BEWordSeqToInt(b[..]) == BEWordSeqToInt(c[..]); { c := FleetAlloc(a.Length); //- could just be c:=null, but DafnyCC doesn't allow it yet assert c!=null; c := FleetCopy(c, a, 0); FleetNatSub(c, b); } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/FleetNat/FleetNatSubOpt.i.dfy ================================================ method FleetNatSub_local_math_core(lastcj:int, bj:int, lastborrow:int) returns (newcj:int, borrow:int) requires 0<=lastcj<0x100000000; requires 0<=bj<0x100000000; requires 0<=lastborrow<2; ensures 0<=newcj<0x100000000; ensures 0<=borrow<2; ensures lastcj - lastborrow - bj == newcj - 0x100000000*borrow; { var lastcj := c[ci]; var borrow1 := 0; if (lastcj < borrow) { borrow1 := 1; } lemma_word32(lastcj); lemma_word32(borrow); var midcj := asm_Sub(lastcj, borrow); lemma_asm_Sub_properties(lastcj, borrow, midcj, borrow1); lemma_word32(1); var borrow2 := 0; if (midcj < bj) { borrow2 := 1; } lemma_word32(bj); newcj := asm_Sub(midcj, bj); lemma_asm_Sub_properties(midcj, bj, newcj, borrow2); lemma_word32(borrow1); borrow := asm_Add(borrow1, borrow2); lemma_mod0x100000000(borrow1+borrow2); } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Math/.gitignore ================================================ *.bpl *.log ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Math/BitwiseOperations.i.dfy ================================================ include "power2.s.dfy" include "power2.i.dfy" include "../Util/be_sequences.s.dfy" //-//////////////////////////////////////////////////////////////////////////// //- Pure bitwise operations -- "pure" in that they're defined over nats, //- not Word32s. static function BitAnd(x:nat, y:nat) : nat requires IsBit(x); requires IsBit(y); ensures IsBit(BitAnd(x,y)); { if x==1 && y==1 then 1 else 0 } static function PureBitwiseAnd(x:nat, y:nat) : nat decreases x+y; { if (x==0 || y==0) then 0 else PureBitwiseAnd(x/2, y/2)*2 + BitAnd(x%2, y%2) } static predicate SelectBit(b:nat, x:nat) { (x/power2(b)) % 2 == 1 } static lemma lemma_SelectBit_mod(b:nat, x:nat, y:nat) requires 0<=b forall b:nat :: !SelectBit(b,x); decreases x; { if (x==0) { forall (b:nat) ensures !SelectBit(b,x); { lemma_power2_positive(); lemma_SelectBit_overflow(b,x); } } if (forall b:nat :: !SelectBit(b,x)) { if (x==1) { lemma_power2_0_is_1(); lemma_div_is_div_boogie(x,1); assert SelectBit(0,x); } else if (x>1) { lemma_SelectBit_zero(x/2); var b:nat :| SelectBit(b,x/2); var L2 := 2; calc { (x/power2(b+1)) % 2; { reveal_power2(); } (x/(2*power2(b))) % 2; { lemma_mul_is_mul_boogie(2,power2(b)); } (x/(L2*power2(b))) % 2; { lemma_div_denominator(x,2,power2(b)); } ((x/L2)/power2(b)) % 2; { lemma_div_is_div_boogie(x,2); } ((x/2)/power2(b)) % 2; 1; } assert SelectBit(b+1,x); assert false; } assert x==0; } } static predicate BitwiseAndPredicate(x:nat, y:nat, z:nat) { forall b:nat :: (SelectBit(b, x) && SelectBit(b, y)) == SelectBit(b, z) } static lemma lemma_mask_div_mod(x:nat, c:nat) requires 0 !(divides(x,a) && divides(x,b)) } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Math/bit_vector_lemmas.i.dfy ================================================ include "../../Drivers/CPU/assembly.i.dfy" //-/////////////////////////////////////////////////// //- These connect to the underlying lemmas proven //- in Boogie. It is strongly suggested that you //- call the premium versions of these lemmas //- (in bit_vector_lemmas_premium.i.dfy) instead of //- calling these directly. //-/////////////////////////////////////////////////// static lemma {:decl} lemma_xor_bytes(x:int, y:int) requires 0 <= x < 256; requires 0 <= y < 256; requires word32(x); requires word32(y); ensures 0 <= asm_BitwiseXor(x, y) < 256; static lemma {:decl} lemma_and_with_ff(x:int) requires word32(x); requires word32(0xFF); ensures 0 <= asm_BitwiseAnd(x, 0xFF) < 256; static lemma {:decl} lemma_and_with_ffff(x:int) requires word32(x); requires word32(0xFFFF); ensures 0 <= asm_BitwiseAnd(x, 0xFFFF) < 0x10000; static lemma {:decl} lemma_and_with_32_64(x:int) requires word32(x); requires word32(32); requires word32(64); ensures asm_BitwiseAnd(x, 32) > 0 ==> IntBit(26, x); ensures asm_BitwiseAnd(x, 64) > 0 ==> IntBit(25, x); ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Math/bit_vector_lemmas_premium.i.dfy ================================================ include "bit_vector_lemmas.i.dfy" include "../../Drivers/CPU/assembly_premium.i.dfy" static lemma lemma_and_with_ff_premium() ensures Word32(0xFF); ensures forall x :: Word32(x) ==> 0 <= Asm_BitwiseAnd(x, 0xFF) < 256 && IsByte(Asm_BitwiseAnd(x, 0xFF)); { lemma_2toX(); forall x | Word32(x) ensures 0 <= Asm_BitwiseAnd(x, 0xFF) < 256; ensures Word16(Asm_BitwiseAnd(x, 0xFF)); { lemma_word32_Word32(); lemma_and_with_ff(x); } } static lemma lemma_and_with_ffff_premium() ensures Word32(0xFFFF); ensures forall x :: Word32(x) ==> 0 <= Asm_BitwiseAnd(x, 0xFFFF) < 0x10000 && Word16(Asm_BitwiseAnd(x, 0xFFFF)); { lemma_2toX(); forall x | Word32(x) ensures 0 <= Asm_BitwiseAnd(x, 0xFFFF) < 0x10000; ensures Word16(Asm_BitwiseAnd(x, 0xFFFF)); { lemma_word32_Word32(); lemma_and_with_ffff(x); } } static lemma lemma_and_with_32_64_specific_premium(x:int) requires Word32(x); ensures Word32(32) && Word32(64); ensures Asm_BitwiseAnd(x, 32) > 0 ==> BEWordToBitSeq(x)[26] == 1; ensures Asm_BitwiseAnd(x, 64) > 0 ==> BEWordToBitSeq(x)[25] == 1; { lemma_and_with_32_64_premium(); } static lemma lemma_and_with_32_64_premium() ensures Word32(32) && Word32(64); ensures forall x :: Word32(x) ==> (Asm_BitwiseAnd(x, 32) > 0 ==> BEWordToBitSeq(x)[26] == 1); ensures forall x :: Word32(x) ==> (Asm_BitwiseAnd(x, 64) > 0 ==> BEWordToBitSeq(x)[25] == 1); { lemma_2toX(); forall x | Word32(x) ensures Asm_BitwiseAnd(x, 32) > 0 ==> BEWordToBitSeq(x)[26] == 1; ensures Asm_BitwiseAnd(x, 64) > 0 ==> BEWordToBitSeq(x)[25] == 1; { lemma_word32_Word32(); lemma_and_with_32_64(x); lemma_IntBit_is_BEWordToBitSeq(); } } static lemma lemma_xor_bytes_premium(x:int, y:int) requires 0 <= x < 256; requires 0 <= y < 256; ensures word32(x); ensures word32(y); ensures Word32(x); ensures Word32(y); ensures 0 <= asm_BitwiseXor(x, y) < 256; ensures 0 <= Asm_BitwiseXor(x, y) < 256; ensures 0 <= BitwiseXor(x, y) < 256; { lemma_2toX(); lemma_word32(x); lemma_word32(y); lemma_xor_bytes(x, y); } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Math/div.i.dfy ================================================ include "power.i.dfy" include "mul.i.dfy" include "div_def.i.dfy" include "div_boogie.i.dfy" include "div_nonlinear.i.dfy" //-//////////////////////////////////////////////////////////////////////////// //- //- Core div lemmas, with named arguments. //- //-//////////////////////////////////////////////////////////////////////////// static lemma lemma_div_by_one_is_identity(x:int) ensures x/1 == x; { } static lemma lemma_div_basics(x:int) ensures x != 0 ==> 0 / x == 0; ensures x / 1 == x; ensures x!=0 ==> x / x == 1; { lemma_div_by_one_is_identity(x); forall x:int | x != 0 ensures x / x == 1; ensures 0 / x == 0; { lemma_div_by_self(x); lemma_div_of_0(x); } } static lemma lemma_small_div_converse() ensures forall x, d :: 0<=x && 0 x < d; { forall (x,d | 0<=x && 0= d) { calc { 1; { lemma_div_basics(d); } d/d; <= { lemma_div_is_ordered(d, x, d); } x/d; } assert false; } } } static lemma lemma_div_is_ordered_by_denominator(x:int, y:int, z:int) requires x >= 0; requires 1 <= y <= z; ensures x / y >= x / z; decreases x; { lemma_div_is_div_recursive_forall(); if (x < z) { lemma_div_is_ordered(0, x, y); } else { lemma_div_is_ordered(x-z, x-y, y); lemma_div_is_ordered_by_denominator(x-z, y, z); } } static lemma lemma_div_is_strictly_ordered_by_denominator(x:int, d:int) requires 0 < x; requires 1 < d; ensures x/d < x; decreases x; { lemma_div_is_div_recursive_forall(); if (x { a%d + b%d == R + (a+b)%d; (a+b)-(a+b)%d - R == a-(a%d) + b - (b%d); { lemma_fundamental_div_mod(a+b,d); lemma_fundamental_div_mod(a,d); lemma_fundamental_div_mod(b,d); } d*((a+b)/d) - R == d*(a/d) + d*(b/d); } } //-static lemma lemma_negative_divisor(x:int, d:int) //- requires d < 0; //- ensures x / (-1*d) == -1*(x / d); //-{ //- var q := x / (-1*d); //- var r := x % (-1*d); //- //- calc { //- x; //- { lemma_fundamental_div_mod(x, -1*d); } //- q * (-1*d) + r; //- { lemma_mul_is_associative(q, -1, d); } //- (q*-1)*d + r; //- { lemma_mul_is_commutative(q, -1); } //- (-q) * d + r; //- } //- lemma_mod_range(x, -1*d); //- lemma_fundamental_div_mod_converse(x, d, -q, r); //- assert x / d == -q; //- assert -1*(x/d) == q; //-} static lemma lemma_div_pos_is_pos(x:int, divisor:int) requires 0 <= x; requires 0 < divisor; ensures x / divisor >= 0; { if (x < divisor) { lemma_small_div(); } else { calc { x / divisor; { lemma_div_is_div_recursive_forall(); } 1 + ((x - divisor) / divisor); >= { lemma_div_pos_is_pos(x-divisor, divisor); } 0; } } } //-//////////////////////////////////////////////////////////////////////////// //- //- Forall lemmas: these restate the core lemmas with foralls, //- so callers needn't name the specific expressions to manipulate. //- //- These are all boilerplate transformations of args/requires/ensures //- into forall args :: requires ==> ensures, with a correpsonding //- mechanically generated forall proof that invokes the core lemma. //- //-//////////////////////////////////////////////////////////////////////////// static lemma lemma_div_basics_forall() ensures forall x :: x != 0 ==> 0 / x == 0; ensures forall x :: x / 1 == x; ensures forall x, y :: x >= 0 && y > 0 ==> x/y >= 0; ensures forall x, y :: x >= 0 && y > 0 ==> x/y <= x; { forall (x:int) ensures x != 0 ==> 0 / x == 0; ensures x / 1 == x; { lemma_div_basics(x); } forall x:int, y:int | x >= 0 && y > 0 ensures x / y >= 0; ensures x / y <= x; { lemma_div_pos_is_pos(x, y); lemma_div_is_ordered_by_denominator(x, 1, y); } } ////////////////////////////////////////////////////////////////////////////// // static lemma lemma_div_neg_neg(x:int, d:int) requires d > 0; ensures x/d == -((-x+d-1)/d); decreases if x > 0 then x + 1 else -x; { if (x<0) { calc { x/d; { lemma_div_is_div_recursive_forall(); } -1 + my_div_pos(x+d, d); { lemma_div_is_div_recursive_forall(); } -1 + (x+d)/d; { if (x < -d) { lemma_div_neg_neg(x+d,d); } else { calc { (x+d)/d; { lemma_div_is_div_recursive_forall(); } 0; { lemma_div_is_div_recursive_forall(); } -((-(x+d)+d-1)/d); } } } -1 + -((-(x+d)+d-1)/d); -1 + -1*((-(x+d)+d-1)/d); -1 * (1 + ((-(x+d)+d-1)/d)); -1 * (1 + ((-(x+d)+d-1)/d)); { lemma_div_is_div_recursive_forall(); } -1 * ((-1*x+d-1)/d); -((-x+d-1)/d); } } else if (x= 0; requires x % 2 == 1; ensures (x+1)%2 == 0; { } static lemma lemma_mod2_plus2(x:int) requires x % 2 == 1; ensures (x+2) % 2 == 1; { } static lemma lemma_mod32(x:int) requires x >= 32; ensures (x-32) % 32 == x % 32; { } //////////////////////////////////////////////// //////////////////////////////////////////////// static lemma lemma_mod_remainder_neg_specific(x:int, m:int) requires m > 0 && x < 0; ensures 0 <= x%m < m; decreases -1*x; { lemma_mod_is_mod_recursive_forall(); if (x + m >= 0) { lemma_mod_remainder_pos(); } else { lemma_mul_is_mul_recursive_forall(); lemma_mod_remainder_neg_specific(m+x, m); } } static lemma lemma_mod_remainder_neg() ensures forall x:int, m:int :: m > 0 && x < 0 ==> 0 <= x%m < m; { forall x:int, m:int | m > 0 && x < 0 ensures 0 <= x%m < m; { lemma_mod_remainder_neg_specific(x,m); } } static lemma lemma_mod_remainder_pos_specific(x:int, m:int) requires m > 0 && x >= 0; ensures 0 <= x % m < m; { lemma_mod_is_mod_recursive_forall(); if x == 0 { } else if x < m { } else { lemma_mod_remainder_pos_specific(x - m, m); } } static lemma lemma_mod_remainder_pos() ensures forall x, m :: m > 0 && x >= 0 ==> 0 <= x % m < m; { forall x, m | m > 0 && x >= 0 ensures 0 <= x % m < m; { lemma_mod_remainder_pos_specific(x,m); } } static lemma lemma_mod_remainder_specific(x:int, m:int) requires m > 0; ensures 0 <= x % m < m; { if (x < 0) { lemma_mod_remainder_neg_specific(x, m); } else { lemma_mod_remainder_pos_specific(x, m); } } static lemma lemma_mod_remainder() ensures forall x:int, m:int :: m > 0 ==> 0 <= x%m < m; { lemma_mod_remainder_pos(); lemma_mod_remainder_neg(); } static lemma lemma_mod_basics() ensures forall m:int :: m > 0 ==> m % m == 0; ensures forall x:int, m:int :: m > 0 ==> (x%m)% m == x%m; { forall m:int | m>0 ensures m > 0 ==> m % m == 0; { lemma_mod_yourself(m); } forall (x,m | m>0) ensures (x%m)% m == x%m; { assert x%m < m; lemma_small_mod(x%m,m); } } static lemma lemma_mod_properties() ensures forall m:int :: m > 0 ==> m % m == 0; ensures forall x:int, m:int :: m > 0 ==> (x%m)% m == x%m; ensures forall x:int, m:int :: m > 0 ==> 0 <= x%m < m; { lemma_mod_basics(); forall (x,m | m>0) ensures m > 0 ==> 0 <= x%m < m; { lemma_mod_remainder(); assert x%m 0 then a else -a; requires 0 < m; ensures (m*a + b) % m == b % m; { if (0 == a) { assert (m*a + b) % m == b % m; } else if (0 < a) { calc { (m*a + b) % m; (m*((a-1)+1) + b) % m; { lemma_mul_is_distributive_forall(); } (m*(a-1)+m*1 + b) % m; { lemma_mul_basics_forall(); } (m*(a-1) + m + b) % m; { lemma_mod_multiples_vanish(a-1,m+b,m); } (m + b) % m; { lemma_mod_add_multiples_vanish(b, m); } b % m; } } else { calc { (m*a + b) % m; (m*((a+1)-1) + b) % m; { lemma_mul_is_distributive_forall(); } (m*(a+1)+m*-1 + b) % m; (m*(a+1) - m + b) % m; { lemma_mod_multiples_vanish(a+1,-m+b,m); } (- m + b) % m; { lemma_mod_sub_multiples_vanish(b, m); } b % m; } } } static lemma lemma_add_mod_noop(x:int, y:int, m:int) requires 0 < m; ensures ((x % m) + (y % m)) % m == (x+y) % m; { calc { (x%m + y%m) % m; { lemma_fundamental_div_mod(x,m); lemma_fundamental_div_mod(y,m); } (x - m*(x/m) + y - m*(y/m)) % m; { lemma_mul_unary_negation(m,x/m); lemma_mul_unary_negation(m,y/m); } (x + m*(-(x/m)) + y + m*(-(y/m))) % m; { lemma_mod_multiples_vanish(-(x/m), x+y+m*(-(y/m)), m); } (x + y + m*(-(y/m))) % m; { lemma_mod_multiples_vanish(-(y/m), x+y, m); } (x + y) % m; } } static lemma lemma_mod_equivalence(x:int, y:int, m:int) requires 0 < m; ensures x % m == y % m <==> (x - y) % m == 0; { calc ==> { x % m == y % m; { lemma_fundamental_div_mod(x,m); } x - (m * (x/m)) == y % m; { lemma_fundamental_div_mod(y,m); } x - (m * (x/m)) == y - (m * (y/m)); x - y == (m * (x/m)) - (m * (y/m)); { lemma_mul_is_distributive_forall(); } x - y == m * (x/m - y/m); (x - y) % m == (m * (x/m - y/m)) % m; { lemma_mod_multiples_vanish(x/m - y/m, 0, m); } (x - y) % m == 0 % m; { lemma_0_mod_anything(); } (x - y) % m == 0; } var k := ((x-y)/m); calc ==> { (x - y) % m == 0; { lemma_fundamental_div_mod(x-y,m); } (x - y) - m * ((x-y)/m) == 0; (x - y) - m * k == 0; x == y + m * k; x % m == (y + m * k) % m; { lemma_mod_multiples_vanish(k, y, m); } x % m == y % m; } } static lemma lemma_sub_mod_noop_helper(x:int, y:int, m:int) requires 0 < m; ensures ((x % m) - (y % m)) % m == ((x % m) + (-y % m)) % m; { var minus_y := -y; var diff := ((x % m) - (y % m)) - ((x % m) + (-y % m)); calc { diff % m; calc { diff; ((x % m) - (y % m)) - ((x % m) + (-y % m)); -(y % m) - (-y % m); -(y % m) - (minus_y % m); { lemma_fundamental_div_mod(y,m); } -(y - m * (y/m)) - (minus_y % m); { lemma_fundamental_div_mod(minus_y,m); } - (y - m * (y/m)) - (minus_y - m * (minus_y/m)); { lemma_mul_is_distributive_forall(); } m * (y/m) + m * (minus_y/m); { lemma_mul_is_distributive_forall(); } m * (y/m + minus_y/m); } (m * (y/m + minus_y/m)) % m; { lemma_mod_multiples_vanish(y/m + minus_y/m, 0, m); } 0 % m; { lemma_0_mod_anything(); } 0; } lemma_mod_equivalence((x % m) - (y % m), (x % m) + (-y % m), m); } static lemma lemma_sub_mod_noop(x:int, y:int, m:int) requires 0 < m; ensures ((x % m) - (y % m)) % m == (x-y) % m; { var A := -y; calc { (x-y) % m; (x+A) % m; { lemma_add_mod_noop(x, A, m); } ((x % m) + (A % m)) % m; ((x % m) + (-y % m)) % m; { lemma_sub_mod_noop_helper(x, y, m); } ((x % m) - (y % m)) % m; } } static lemma lemma_mod_adds(a:int, b:int, d:int) requires 0 a%d + b%d == (a+b)%d; { calc { a%d + b%d; { lemma_fundamental_div_mod(a%d+b%d, d); } d*((a%d + b%d)/d) + (a%d + b%d)%d; { lemma_add_mod_noop(a, b, d); } d*((a%d + b%d)/d) + (a+b)%d; } if ((a%d + b%d) < d) { lemma_mod_properties(); assert 0 <= a%d + b%d; lemma_small_div(); assert (a%d + b%d)/d == 0; lemma_mul_basics_forall(); assert d*((a%d + b%d)/d) == d*0 == 0; calc { a%d + b%d; (a+b)%d + d*((a%d + b%d)/d); (a+b)%d; } } } static lemma lemma_mod_neg_neg(x:int, d:int) requires d > 0; ensures x%d == (x*(1-d))%d; { calc { (x*(1-d)) % d; { lemma_mul_is_distributive_forall(); } (x - x*d) % d; { lemma_mul_unary_negation_forall(); } (x + -1*x*d) % d; { lemma_mul_is_associative_forall(); lemma_mul_is_commutative_forall(); } (x + (-x)*d) % d; { lemma_mul_is_commutative(-x,d); } (d*(-x) + x) % d; { lemma_mod_multiples_vanish(-x, x, d); } x % d; } } static lemma lemma_fundamental_div_mod_unique_helper(x:int, d:nat, q1:int, r1:nat, q2:int, r2:nat) requires 0 < d; requires r1 < d; requires r2 < d; requires q1 > q2; requires x == q1 * d + r1; requires x == q2 * d + r2; ensures q1 == q2; { calc ==> { true; d * q1 - d * q2 + r1 - r2 == 0; { lemma_mul_is_distributive_forall(); } d * (q1 - q2) + r1 - r2 == 0; d * (q1 - q2) == r2 - r1; { lemma_mul_increases(q1-q2, d); } r2 - r1 >= d; false; } } static lemma lemma_fundamental_div_mod_unique(x:int, d:nat, q1:int, r1:nat, q2:int, r2:nat) requires 0 < d; requires r1 < d; requires r2 < d; requires x == d * q1 + r1; requires x == d * q2 + r2; ensures q1 == q2; ensures r1 == r2; { if q1 == q2 { calc <==> { x == x; d * q1 + r1 == d * q2 + r2; r1 == r2; } } else { if (q1 > q2) { lemma_fundamental_div_mod_unique_helper(x, d, q1, r1, q2, r2); } else { lemma_fundamental_div_mod_unique_helper(x, d, q2, r2, q1, r1); } } } static lemma lemma_fundamental_div_mod_converse(x:int, d:int, q:int, r:int) requires d != 0; requires 0 <= r < d; requires x == q * d + r; ensures q == x/d; ensures r == x%d; { if q != x / d || r != x % d { calc ==> { true; { lemma_fundamental_div_mod(x, d); } x == d * (x / d) + (x % d); x == d * (x / d) + (x % d); { lemma_mul_is_commutative_forall(); lemma_fundamental_div_mod_unique(x, d, q, r, x / d, x % d); } false; } } } static lemma lemma_mod_pos_bound(x:int, m:int) decreases x; requires 0 <= x; requires 0 < m; ensures 0 <= x%m < m; { if (x < m) { lemma_mod_is_mod_recursive_forall(); } else { assert 0 <= x - m; lemma_mod_is_mod_recursive_forall(); lemma_mod_pos_bound(x -m, m); } } static lemma lemma_mul_mod_noop_left(x:int, y:int, m:int) requires 0 < m; ensures (x % m)*y % m == x*y % m; { calc { (x*y) % m; { lemma_fundamental_div_mod(x,m); } ((m*(x/m) + x%m) * y) % m; { lemma_mul_is_distributive_forall(); } ((m*(x/m))*y + (x%m)*y) % m; { lemma_mul_is_associative_forall(); } (m*((x/m)*y) + (x%m)*y) % m; { lemma_add_mod_noop(m*((x/m)*y), (x%m)*y, m); } (((m*((x/m)*y)) % m) + (((x%m)*y) % m)) % m; (((m*((x/m)*y) + 0) % m) + (((x%m)*y) % m)) % m; { lemma_mod_multiples_vanish((x/m)*y, 0, m); lemma_small_mod(0, m); } ((0 % m) + (((x%m)*y) % m)) % m; { lemma_mod_of_zero_is_zero(m); } (((x%m)*y) % m) % m; { lemma_mod_properties(); } ((x%m)*y) % m; } } static lemma lemma_mul_mod_noop_right(x:int, y:int, m:int) requires 0 < m; ensures x*(y % m) % m == (x*y) % m; { lemma_mul_is_commutative_forall(); lemma_mul_mod_noop_left(y, x, m); } static lemma lemma_mul_mod_noop_general(x:int, y:int, m:int) requires 0 < m; ensures ((x % m) * y ) % m == (x * y) % m; ensures ( x * (y % m)) % m == (x * y) % m; ensures ((x % m) * (y % m)) % m == (x * y) % m; { lemma_mod_properties(); lemma_mul_mod_noop_left(x, y, m); lemma_mul_mod_noop_right(x, y, m); lemma_mul_mod_noop_right(x % m, y, m); } static lemma lemma_mul_mod_noop(x:int, y:int, m:int) requires 0 < m; ensures (x % m) * (y % m) % m == (x*y) % m; { lemma_mul_mod_noop_general(x, y, m); } static lemma lemma_power_mod_noop(b:int, e:nat, m:int) decreases e; requires 0 < m; ensures power(b % m, e) % m == power(b, e) % m; { reveal_power(); lemma_mod_properties(); if (e > 0) { calc { power(b % m, e) % m; ((b % m) * power(b % m, e - 1)) % m; { lemma_mul_mod_noop_general(b, power(b % m, e - 1), m); } ((b % m) * (power(b % m, e - 1) % m) % m) % m; { lemma_power_mod_noop(b, e - 1, m); } ((b % m) * (power(b, e - 1) % m) % m) % m; { lemma_mul_mod_noop_general(b, power(b, e - 1), m); } (b * (power(b, e - 1)) % m) % m; (b * (power(b, e - 1))) % m; power(b, e) % m; } } } static lemma lemma_mod_subtraction(x:nat, s:nat, d:nat) requires 0 0; requires x >= 0; ensures (x * m) % m == 0; decreases if x > 0 then x else -x; { lemma_mod_is_mod_recursive_forall(); if (x < 0) { calc { (x * m) % m; (x * m + m) % m; (x * m + 1*m) % m; { lemma_mul_is_distributive_forall(); } ((x+1)*m) % m; { lemma_mod_multiples_basic(x+1, m); } 0; } } else if (x == 0) { calc { (x*m)%m; { assert x 0; //-requires x >= 0; ensures 1 + x / d == (d + x) / d; { var A := (d + x) / d; var Z := 1 + x / d; calc { d * A; d * ((d + x) / d); { lemma_fundamental_div_mod(d+x, d); } (d + x) - ((d + x) % d); { lemma_add_mod_noop(d, x, d); lemma_mod_properties(); } (d + x) - x % d; { lemma_fundamental_div_mod(x, d); } d + d * (x / d); { lemma_mul_is_distributive_forall(); } d * (1 + x / d); d * Z; } lemma_mul_equality_converse(A, Z, d); lemma_mul_is_commutative_forall(); } static lemma lemma_div_minus_one(x:int, d:int) requires d > 0; ensures -1 + x / d == (-d + x) / d; { var A := (-d + x) / d; var Z := -1 + x / d; calc { d * A; d * ((-d + x) / d); { lemma_fundamental_div_mod(x-d, d); } (x - d) - ((x - d) % d); { lemma_sub_mod_noop(x, d, d); lemma_mod_properties(); } (x - d) - x % d; { lemma_fundamental_div_mod(x, d); } -d + d * (x / d); { lemma_mul_is_distributive_forall(); } d * (-1 + x / d); d * Z; } lemma_mul_equality_converse(A, Z, d); lemma_mul_is_commutative_forall(); } static lemma lemma_mod_mod(x:int, a:int, b:int) requires 0 0; decreases if x >= 0 then x else -(x-d); ensures my_div_pos(x, d) == x / d; { if x < 0 { calc { my_div_pos(x, d); -1 + my_div_pos(x+d, d); { lemma_div_is_div_pos(x+d, d); } -1 + (x+d) / d; { lemma_div_minus_one(x+d, d); } (-d + x + d) / d; x / d; } } else if x < d { lemma_small_div(); } else { calc { my_div_pos(x, d); 1 + my_div_pos(x-d, d); { lemma_div_is_div_pos(x-d, d); } 1 + (x-d) / d; { lemma_div_plus_one(x-d, d); } x / d; } } } static lemma lemma_div_is_div_recursive(x:int, d:int) requires d > 0; ensures my_div_recursive(x, d) == x / d; { lemma_div_is_div_pos(x, d); // //- if d > 0 { //- lemma_div_is_div_pos(x, d); //- } else { //- calc { //- my_div_recursive(x, d); //- -1 * my_div_pos(x, -1*d); //- { lemma_div_is_div_pos(x, -1*d); } //- -1 * (x / (-1*d)); //- { lemma_negative_divisor(x, d); } //- x / d; //- } //- } } static lemma lemma_div_is_div_recursive_forall() ensures forall x:int, d:int :: d > 0 ==> my_div_recursive(x, d) == x / d; { forall x:int, d:int | d > 0 ensures my_div_recursive(x, d) == x / d; { lemma_div_is_div_recursive(x, d); } } //-///////////////////////////////////////////////////// //-///////////////////////////////////////////////////// //- Proof that mod is recursive mod //-///////////////////////////////////////////////////// static lemma lemma_mod_is_mod_recursive(x:int, m:int) requires m > 0; ensures my_mod_recursive(x, m) == x % m; decreases if x < 0 then -x + m else x; { if x < 0 { calc { my_mod_recursive(x, m); my_mod_recursive(x + m, m); { lemma_mod_is_mod_recursive(x + m, m); } (x + m) % m; { lemma_add_mod_noop(x, m, m); } ((x % m) + (m % m)) % m; { lemma_mod_basics(); } (x % m) % m; { lemma_mod_basics(); } x % m; } } else if x < m { lemma_small_mod(x, m); } else { calc { my_mod_recursive(x, m); my_mod_recursive(x - m, m); { lemma_mod_is_mod_recursive(x - m, m); } (x - m) % m; { lemma_sub_mod_noop(x, m, m); } ((x % m) - (m % m)) % m; { lemma_mod_basics(); } (x % m) % m; { lemma_mod_basics(); } x % m; } } } static lemma lemma_mod_is_mod_recursive_forall() ensures forall x:int, d:int :: d > 0 ==> my_mod_recursive(x, d) == x % d; { forall x:int, d:int | d > 0 ensures my_mod_recursive(x, d) == x % d; { lemma_mod_is_mod_recursive(x, d); } } //-///////////////////////////////////////////////////// static lemma lemma_basic_div(d:int) requires d > 0; ensures forall x :: 0 <= x < d ==> x / d == 0; { lemma_div_is_div_recursive_forall(); } static lemma lemma_odd_div(d:int) requires d >= 0; requires d % 2 == 1; ensures 2 * (d / 2) + 1 == d; { lemma_div_is_div_recursive_forall(); if (d >= 2) { lemma_odd_div(d - 2); } } static lemma lemma_div_is_ordered(x:int, y:int, z:int) requires x <= y; requires z > 0; ensures x / z <= y / z; decreases if x >= 0 then x else z - x; { if (x < 0) { calc <= { x / z; { lemma_div_is_div_recursive_forall(); } -1 + (x+z)/z; { lemma_div_is_ordered(x+z, y+z, z); } -1 + (y+z) / z; { lemma_div_is_div_recursive_forall(); } y / z; } } else if (x < z) { lemma_small_div(); lemma_div_pos_is_pos(y, z); } else { calc <= { x / z; { lemma_div_is_div_recursive_forall(); } 1 + (x-z) / z; { lemma_div_is_ordered(x-z, y-z, z); } 1 + (y-z) / z; { lemma_div_is_div_recursive_forall(); } y / z; } } } static lemma lemma_div_decreases(x:int, d:int) requires 0 { x <= x/d; { lemma_mul_inequality(x, x/d, d); lemma_mul_is_commutative_forall(); } d*x <= d*(x/d); d*x + x%d <= d*(x/d) + x%d; { lemma_fundamental_div_mod(x,d); assert d*(x/d) + x%d == x; } d*x + x%d <= x; { lemma_mod_properties(); } d*x <= x; false; } } } static lemma lemma_div_nonincreasing(x:int, d:int) requires 0<=x; requires 0 { lemma_remainder_upper(x-divisor, divisor); } 1*divisor + ((x - divisor) - divisor); { lemma_mul_properties(); } x-divisor; } } } static lemma lemma_remainder_lower(x:int, divisor:int) requires 0 <= x; requires 0 < divisor; ensures x >= x / divisor * divisor; { if (x < divisor) { lemma_mul_properties(); lemma_small_div(); } else { calc { x / divisor * divisor; { lemma_div_is_div_recursive_forall(); } (1 + (x-divisor) / divisor) * divisor; { lemma_mul_properties(); } 1*divisor + ((x-divisor) / divisor) * divisor; <= { lemma_remainder_lower(x-divisor, divisor); } 1*divisor + x - divisor; { lemma_mul_properties(); } x; } } } static lemma lemma_remainder(x:int, divisor:int) requires 0 <= x; requires 0 < divisor; ensures 0 <= x - x / divisor * divisor < divisor; { lemma_remainder_upper(x, divisor); lemma_remainder_lower(x, divisor); } static lemma lemma_div_denominator(x:int,c:nat,d:nat) requires 0 <= x; requires 0= d) { lemma_fundamental_div_mod(R, c); //- assert R >= c*(R/c); lemma_mul_inequality(d, R/c, c); lemma_mul_is_commutative_forall(); //- assert c*(R/c) >= c*d; //- assert R >= c*d; assert false; } assert R/c < d; lemma_mul_basics_forall(); lemma_fundamental_div_mod_converse(R/c, d, 0, R/c); assert (R/c) % d == R/c; lemma_fundamental_div_mod(R, c); assert c*(R/c) + R%c == R; assert c*((R/c) % d) + R%c == R; var k := x/(c*d); lemma_fundamental_div_mod(x, c*d); assert x == (c*d)*(x/(c*d)) + x % (c*d); assert R == x - (c*d)*(x/(c*d)); assert R == x - (c*d)*k; calc { c*((x/c)%d) + x%c; { lemma_mod_multiples_vanish(-k, x/c, d); lemma_mul_is_commutative_forall(); } c*((x/c+(-k)*d) % d) + x%c; { lemma_hoist_over_denominator(x, (-k)*d, c); } c*(((x+(((-k)*d)*c))/c) % d) + x%c; { lemma_mul_is_associative(-k,d,c); } c*(((x+((-k)*(d*c)))/c) % d) + x%c; { lemma_mul_unary_negation(k,d*c); } c*(((x+(-(k*(d*c))))/c) % d) + x%c; { lemma_mul_is_associative(k,d,c); } c*(((x+(-(k*d*c)))/c) % d) + x%c; c*(((x-k*d*c)/c) % d) + x%c; { lemma_mul_is_associative_forall(); lemma_mul_is_commutative_forall(); } c*((R/c) % d) + x%c; c*(R/c) + x%c; { lemma_fundamental_div_mod(R,c); assert R == c*(R/c) + R % c; lemma_mod_mod(x,c,d); assert R%c == x%c; } R; { lemma_mod_is_mod_recursive_forall(); } R%(c*d); (x-(c*d)*k) % (c*d); { lemma_mul_unary_negation(c*d,k); } (x+(c*d)*(-k)) % (c*d); { lemma_mod_multiples_vanish(-k, x, c*d); } x % (c*d); } calc ==> { c*(x/c) + x%c - R == c*(x/c) - c*((x/c)%d); { lemma_fundamental_div_mod(x,c); } x - R == c*(x/c) - c*((x/c)%d); } calc ==> { true; { lemma_fundamental_div_mod(x/c,d); } d*((x/c)/d) == x/c - ((x/c)%d); c*(d*((x/c)/d)) == c*(x/c - ((x/c)%d)); { lemma_mul_is_associative_forall(); } (c*d)*((x/c)/d) == c*(x/c - ((x/c)%d)); { lemma_mul_is_distributive_forall(); } (c*d)*((x/c)/d) == c*(x/c) - c*((x/c)%d); (c*d)*((x/c)/d) == x - R; { lemma_fundamental_div_mod(x, c*d); } (c*d)*((x/c)/d) == (c*d)*(x/(c*d)) + x%(c*d) - R; (c*d)*((x/c)/d) == (c*d)*(x/(c*d)); { lemma_mul_one_to_one(c*d, (x/c)/d, x/(c*d)); } (x/c)/d == x/(c*d); } } static lemma lemma_mul_hoist_inequality(x:int, y:int, z:int) requires 0 <= x; requires 0 < z; ensures x*(y/z) <= (x*y)/z; { calc { (x*y)/z; { lemma_fundamental_div_mod(y, z); } (x*(z*(y/z)+y%z))/z; { lemma_mul_is_distributive_forall(); } (x*(z*(y/z))+x*(y%z))/z; >= { lemma_mod_properties(); lemma_mul_nonnegative(x, y%z); lemma_div_is_ordered(x*(z*(y/z)), x*(z*(y/z))+x*(y%z), z); } (x*(z*(y/z)))/z; { lemma_mul_is_associative_forall(); lemma_mul_is_commutative_forall(); } (z*(x*(y/z)))/z; { lemma_div_multiples_vanish(x*(y/z), z); } x*(y/z); } } static lemma lemma_indistinguishable_quotients(a:int, b:int, d:int) requires 0 a/d) { calc { a - a%d + d; d*(a/d)+d; { lemma_mul_basics_forall(); } d*(a/d)+d*1; { lemma_mul_is_distributive_forall(); } d*(a/d+1); <= { lemma_mul_inequality(a/d+1, b/d, d); lemma_mul_is_commutative_forall(); } d*(b/d); <= { lemma_mod_properties(); lemma_fundamental_div_mod(b,d); } b; } assert false; } } static lemma lemma_truncate_middle(x:int, b:int, c:int) requires 0<=x; requires 0 { true; { lemma_fundamental_div_mod(x,c); } x == c*(x/c) + x%c; b*x == b*(c*(x/c) + x%c); { lemma_mul_is_distributive_forall(); } b*x == b*(c*(x/c)) + b*(x%c); { lemma_mul_is_associative_forall(); } b*x == (b*c)*(x/c) + b*(x%c); } } static lemma lemma_div_multiples_vanish_quotient(x:int, a:int, d:int) requires 0 0; ensures x / z < y / z; { lemma_div_by_multiple(m, z); assert(y / z == m); var k := x / z; var r := x - x / z * z; lemma_remainder(x, z); lemma_div_pos_is_pos(x, z); assert r >= 0; assert k*z <= k*z + r < m*z; lemma_div_by_multiple(k, z); assert (k*z) / z == k; lemma_mul_properties(); calc { x / z; k; < { lemma_mul_strict_inequality_converse(k,m,z); } m; y / z; } } static lemma lemma_hoist_over_denominator(x:int, j:int, d:nat) requires 0 { true; { lemma_mod_properties(); } b*(a/b) % (b*c) < b*c; b*((a/b) - (c*((b*(a/b))/(b*c)))) < b*c; { lemma_mul_is_commutative_forall(); lemma_mul_strict_inequality_converse_forall(); } ((a/b) - (c*((b*(a/b))/(b*c)))) < c; ((a/b) - (c*((b*(a/b))/(b*c)))) <= c-1; { lemma_mul_is_commutative_forall(); lemma_mul_inequality_forall(); } b*((a/b) - (c*((b*(a/b))/(b*c)))) <= b*(c-1); b*(a/b) % (b*c) <= b*(c-1); } } lemma lemma_part_bound2(a:int, b:int, c:int) requires 0<=a; requires 0 c * d != 0; ensures forall x:int,c:nat,d:nat :: 0 <= x && 0 < c && 0 < d ==> (x/c)/d == x/(c*d); { lemma_mul_nonzero_forall(); forall (x:int,c:nat,d:nat | 0 <= x && 0 < c && 0 < d) ensures c * d != 0; ensures (x/c)/d == x/(c*d); { lemma_div_denominator(x,c,d); } } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Math/div_boogie.i.dfy ================================================ include "div_def.i.dfy" include "mul.i.dfy" static lemma lemma_div_is_div_boogie(x:int, d:int) requires d != 0; //- ensures INTERNAL_div(x, d) == INTERNAL_div_boogie(x, d); { } static lemma lemma_mod_is_mod_boogie(x:int, d:int) requires d > 0; //-ensures INTERNAL_mod(x, d) == INTERNAL_mod_boogie(x, d); { } //-static lemma lemma_div_is_div_boogie_at_least_for_2(x:int) //- ensures INTERNAL_div(x, 2) == INTERNAL_div_boogie(x,2); //-{ //-} //- //-static lemma lemma_div_is_div_boogie_for_4_which_is_also_a_number(x:int) //- ensures INTERNAL_div(x, 4) == INTERNAL_div_boogie(x,4); //-{ //-} //- //-static lemma lemma_div_is_div_boogie_for_8_which_is_also_a_number(x:int) //- ensures INTERNAL_div(x, 8) == INTERNAL_div_boogie(x,8); //-{ //-} //- //-static lemma lemma_div_is_div_boogie_for_16_which_is_also_a_number(x:int) //- ensures INTERNAL_div(x, 16) == INTERNAL_div_boogie(x,16); //-{ //-} //- //-static lemma lemma_div_is_div_boogie_for_256_which_is_also_a_number(x:int) //- ensures INTERNAL_div(x, 256) == INTERNAL_div_boogie(x,256); //-{ //-} //- //-static lemma lemma_div_is_div_boogie_for_65536_which_is_also_a_number(x:int) //- ensures INTERNAL_div(x, 65536) == INTERNAL_div_boogie(x,65536); //-{ //-} //- //-static lemma lemma_div_is_div_boogie_for_16777216_which_is_also_a_number(x:int) //- ensures INTERNAL_div(x, 16777216) == INTERNAL_div_boogie(x,16777216); //-{ //-} //- //-static lemma lemma_mod_is_mod_boogie_for_2_which_is_also_a_number(x:int) //- ensures INTERNAL_mod(x, 2) == INTERNAL_mod_boogie(x,2); //-{ //-} //- //-static lemma lemma_mod_is_mod_boogie_for_4_which_is_also_a_number(x:int) //- ensures INTERNAL_mod(x, 4) == INTERNAL_mod_boogie(x,4); //-{ //-} //- //-static lemma lemma_mod_is_mod_boogie_for_16_which_is_also_a_number(x:int) //- ensures INTERNAL_mod(x, 16) == INTERNAL_mod_boogie(x,16); //-{ //-} //- //-static lemma lemma_mod_is_mod_boogie_for_256_which_is_also_a_number(x:int) //- ensures INTERNAL_mod(x, 256) == INTERNAL_mod_boogie(x,256); //-{ //-} //- //-static lemma lemma_mod_is_mod_boogie_for_65536_which_is_also_a_number(x:int) //- ensures INTERNAL_mod(x, 65536) == INTERNAL_mod_boogie(x,65536); //-{ //-} ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Math/div_def.i.dfy ================================================ //- Specs/implements mathematical div and mod, not the C version. //- This may produce "surprising" results for negative values //- For example, -3 div 5 is -1 and -3 mod 5 is 2. //- Note this is consistent: -3 * -1 + 2 == 5 /* static function mod(x:int, m:int) : int requires m > 0; decreases if x < 0 then (m - x) else x; { if x < 0 then mod(m + x, m) else if x < m then x else mod(x - m, m) } */ static function div(x:int, d:int) : int requires d != 0; { x/d } static function mod(x:int, d:int) : int requires d != 0; { x%d } static function div_recursive(x:int, d:int) : int requires d != 0; { INTERNAL_div_recursive(x,d) } static function mod_recursive(x:int, d:int) : int requires d > 0; { INTERNAL_mod_recursive(x,d) } static function mod_boogie(x:int, y:int) : int requires y != 0; { x % y } //- INTERNAL_mod_boogie(x,y) } static function div_boogie(x:int, y:int) : int requires y != 0; { x / y } //-{ INTERNAL_div_boogie(x,y) } static function my_div_recursive(x:int, d:int) : int requires d != 0; { if d > 0 then my_div_pos(x, d) else -1 * my_div_pos(x, -1*d) } static function my_div_pos(x:int, d:int) : int requires d > 0; decreases if x < 0 then (d - x) else x; { if x < 0 then -1 + my_div_pos(x+d, d) else if x < d then 0 else 1 + my_div_pos(x-d, d) } static function my_mod_recursive(x:int, m:int) : int requires m > 0; decreases if x < 0 then (m - x) else x; { if x < 0 then my_mod_recursive(m + x, m) else if x < m then x else my_mod_recursive(x - m, m) } //- Kept for legacy reasons: //-static function INTERNAL_mod_boogie(x:int, m:int) : int { x % y } static function INTERNAL_mod_recursive(x:int, m:int) : int requires m > 0; { my_mod_recursive(x, m) } //-static function INTERNAL_div_boogie(x:int, m:int) : int { x / m } static function INTERNAL_div_recursive(x:int, d:int) : int requires d != 0; { my_div_recursive(x, d) } /* static ghost method mod_test() { assert -3 % 5 == 2; assert 10 % -5 == 0; assert 1 % -5 == 1; assert -3 / 5 == -1; } */ ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Math/div_nonlinear.i.dfy ================================================ //- //- WARNING: In general, you shouldn't need to call these directly. Try //- to use the ones in div.i.dfy instead. They're more full-featured anyway. static lemma lemma_div_of_0(d:int) requires d != 0; ensures 0/d == 0; { } static lemma lemma_div_by_self(d:int) requires d != 0; ensures d/d == 1; { } static lemma lemma_small_div() ensures forall x, d :: 0 <= x < d && d > 0 ==> x / d == 0; { } static lemma lemma_mod_of_zero_is_zero(m:int) requires 0 < m; ensures 0 % m == 0; { } static lemma lemma_fundamental_div_mod(x:int, d:int) requires d != 0; ensures x == d * (x/d) + (x%d); { } static lemma lemma_0_mod_anything() ensures forall m:int :: m > 0 ==> 0 % m == 0; { } static lemma lemma_mod_yourself(m:int) ensures m > 0 ==> m % m == 0; { } static lemma lemma_small_mod(x:nat, m:nat) requires x 0; ensures 0 <= x % m < m; { } static lemma lemma_real_div_gt(x:real, y:real) requires x > y; requires x >= 0.0; requires y > 0.0; ensures x / y > real(1); { } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Math/evenodd.i.dfy ================================================ include "mul.i.dfy" include "div.i.dfy" static function IsEven(x:int) : bool { exists y:int :: mul(y, 2) == x } static lemma lemma_no_half(i:int) ensures 2*i != 1; { /* if (i==0) { } else if (i>0) { lemma_mul_increases(i,2); assert 2<=mul(i,2); lemma_mul_is_commutative_forall(); assert 2 <= 2*i; assert 1 != 2*i; } else { var mi:int := -i; assert 0= -1*mul(mi,2); lemma_mul_is_mul_boogie(-1,mul(mi,2)); lemma_mul_is_associative_forall(); assert -2 >= mul(mul(-1,mi),2); assert mul(mul(-1,mi),2) <= -2; assert 2*i <= -2; assert 2*i <= 2*(-1); lemma_mul_inequality_converse_forall(); assert 2*i <= -1; } */ } //-datatype IntDivResult = IntDivResult_c(q:int, r:int); //- //-function DivMod(x:int, d:int) : IntDivResult //- requires d>0; //- ensures d*DivMod(x,d).q+DivMod(x,d).r == x; //- ensures 0<=DivMod(x,d).r (mod(x, 2) == 0); { lemma_mod_is_mod_boogie(x, 2); if (IsEven(x)) { var y:int :| mul(y, 2) == x; lemma_mul_is_mul_boogie(y, 2); assert mod(x, 2) == 0; } if (mod(x, 2) == 0) { lemma_mul_is_mul_boogie(x / 2, 2); assert mul(x / 2, 2) == x; assert IsEven(x); } /* var q:int,r:int := DivMod(x,2); lemma_mul_is_mul_boogie(2,q); assert 2*q+r == mul(2,q)+r == x; assert 0<=r<2; assert r==mod(x,2); if (mod(x,2) == 0) { assert r == 0; assert 2*q == x; lemma_mul_is_commutative(2,q); assert q*2 == x; assert IsEven(x); } else { assert r == 1; assert 2*q+1 == x; assert 1 == x-2*q; if (IsEven(x)) { var y:int :| y*2 == x; lemma_mul_is_commutative(2,y); assert 2*y == x; assert 1 == 2*y - 2*q; lemma_mul_is_distributive_sub(2,y,q); assert 1 == 2*(y - q); var z:int := y - q; assert 1 == 2*z; lemma_no_half(z); assert false; } assert !IsEven(x); } */ } static lemma lemma_x_odd(x:int) requires 0 <= x; requires !IsEven(x); ensures mod(x,2)==1; { lemma_even_mod_0_pos(x); assert mod(x,2) != 0; lemma_mod_pos_bound(x,2); assert mod(x,2) < 2; assert mod(x,2) == 1; } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Math/mul.i.dfy ================================================ include "mul_nonlinear.i.dfy" static function mul(x:int, y:int) : int { x*y } //-//////////////////////////////////////////////////////////// //- Recursive definitions that can be handy for proving //- properties we can't or don't want to rely on nonlinear for //-//////////////////////////////////////////////////////////// static function mul_recursive(x:int, y:int) : int { if x >= 0 then mul_pos(x, y) else -1*mul_pos(-1*x, y) } static function mul_pos(x:int, y:int) : int requires x >= 0; { if x == 0 then 0 else y + mul_pos(x - 1, y) } static lemma lemma_mul_is_mul_recursive(x:int, y:int) ensures x * y == mul_recursive(x, y); { if x >= 0 { lemma_mul_is_mul_pos(x, y); } else { var neg_x := -1 * x; calc { mul_recursive(x, y); -1 * mul_pos(-1*x, y); -1 * mul_pos(neg_x, y); { lemma_mul_is_mul_pos(neg_x, y); } -1 * (neg_x * y); { lemma_mul_is_associative(-1, neg_x, y); } (-1 * neg_x) * y; { lemma_mul_is_associative(-1, -1, x); } ((-1 * -1) * x) * y; x * y; } } } static lemma lemma_mul_is_mul_pos(x:int, y:int) requires x >= 0; ensures x * y == mul_pos(x, y); { if x == 0 { } else { calc { y + mul_pos(x - 1, y); { lemma_mul_is_mul_pos(x - 1, y); } y + (x-1)*y; 1*y + (x-1)*y; { lemma_mul_is_commutative_forall(); lemma_mul_is_distributive_add(y, 1, x-1); } (1 + x - 1) * y; x * y; } } } //-//////////////////////////////////////////////////////////////////////////// //- //- Core lemmas, with named arguments. //- //-//////////////////////////////////////////////////////////////////////////// static lemma lemma_mul_basics(x:int) ensures 0*x == 0; ensures x*0 == 0; ensures 1*x == x; ensures x*1 == x; { } static lemma lemma_mul_is_commutative(x:int, y:int) ensures x*y == y*x; { } static lemma lemma_mul_ordering_general() ensures forall x:int, y:int, b:int :: (0 < x && 0 < y && 0 <= x*y < b) ==> x < b && y < b; { forall x:int, y:int, b:int | 0 < x && 0 < y && 0 <= x*y < b ensures x < b && y < b; { lemma_mul_ordering(x, y, b); } } static lemma lemma_mul_is_mul_boogie(x:int, y:int) { } static lemma lemma_mul_inequality(x:int, y:int, z:int) requires x <= y; requires z >= 0; ensures x*z <= y*z; { if z == 0 { } else { if (x == y) { } else { lemma_mul_strict_inequality(x, y, z); } } } static lemma lemma_mul_upper_bound(x:int, x_bound:int, y:int, y_bound:int) requires x <= x_bound; requires y <= y_bound; requires 0<=x; requires 0<=y; ensures x*y <= x_bound * y_bound; { lemma_mul_inequality(x, x_bound, y); lemma_mul_inequality(y, y_bound, x_bound); } //- This lemma is less precise than the non-strict version, since //- it uses two < facts to achieve only one < result. Thus, use it with //- caution -- it may be throwing away precision you'll require later. static lemma lemma_mul_strict_upper_bound(x:int, x_bound:int, y:int, y_bound:int) requires x < x_bound; requires y < y_bound; requires 0<=x; requires 0<=y; ensures x*y < x_bound * y_bound; { if (y_bound==1) { lemma_mul_strictly_positive(x_bound, y_bound); } else { calc { x*y; <= { lemma_mul_upper_bound(x, x_bound-1, y, y_bound-1); } (x_bound-1)*(y_bound-1); < { lemma_mul_strict_inequality(x_bound-1, x_bound, y_bound-1); } (y_bound-1)*x_bound; < { lemma_mul_strict_inequality(y_bound-1, y_bound, x_bound); } x_bound * y_bound; } } } static lemma lemma_mul_left_inequality(x:int, y:int, z:int) requires x > 0; ensures y <= z ==> x*y <= x*z; ensures y < z ==> x*y < x*z; { lemma_mul_is_commutative_forall(); lemma_mul_inequality_forall(); lemma_mul_strict_inequality_forall(); } static lemma lemma_mul_strict_inequality_converse(x:int, y:int, z:int) requires x*z < y*z; requires z >= 0; ensures x < y; { if (x >= y) { lemma_mul_inequality(y, x, z); assert false; } } static lemma lemma_mul_inequality_converse(x:int, y:int, z:int) requires x*z <= y*z; requires z > 0; ensures x <= y; { if (x > y) { lemma_mul_strict_inequality(y, x, z); assert false; } } static lemma lemma_mul_equality_converse(x:int, y:int, z:int) requires x*z == y*z; requires 0=0 then x else -1*x; { lemma_mul_is_mul_recursive_forall(); if (x == 0) { } else if (x > 0) { lemma_mul_is_distributive_sub(x - 1, y, z); } else { lemma_mul_is_distributive_sub(x + 1, y, z); } } static lemma lemma_mul_is_distributive(x:int, y:int, z:int) ensures x*(y + z) == x*y + x*z; ensures x*(y - z) == x*y - x*z; ensures (y + z)*x == y*x + z*x; ensures (y - z)*x == y*x - z*x; ensures x*(y + z) == (y + z)*x; ensures x*(y - z) == (y - z)*x; ensures x*y == y*x; ensures x*z == z*x; { lemma_mul_is_distributive_add(x, y, z); lemma_mul_is_distributive_sub(x, y, z); lemma_mul_is_commutative_forall(); } static lemma lemma_mul_strictly_increases(x:int, y:int) requires 1 < x; requires 0 < y; ensures y < x*y; { if (1 < x && 0 < y) { lemma_mul_strict_inequality(1,x,y); } } static lemma lemma_mul_increases(x:int, y:int) requires 0y) { lemma_mul_strict_inequality(y,x,m); assert m*y < m*x; } assert x==y; } static lemma lemma_mul_one_to_one(m:int, x:int, y:int) requires m!=0; requires m*x == m*y; ensures x == y; { if (m>0) { lemma_mul_one_to_one_pos(m,x,y); } else { lemma_mul_unary_negation(m,x); lemma_mul_unary_negation(m,y); lemma_mul_one_to_one_pos(-m,x,y); } } //-//////////////////////////////////////////////////////////////////////////// //- //- Forall lemmas: these restate the core lemmas with foralls, //- so callers needn't name the specific expressions to manipulate. //- //- These are all boilerplate transformations of args/requires/ensures //- into forall args :: requires ==> ensures, with a correpsonding //- mechanically generated forall proof that invokes the core lemma. //- //-//////////////////////////////////////////////////////////////////////////// static lemma lemma_mul_is_mul_recursive_forall() ensures forall x:int, y:int :: x * y == mul_recursive(x, y); { forall x:int, y:int ensures x * y == mul_recursive(x, y); { lemma_mul_is_mul_recursive(x, y); } } static lemma lemma_mul_basics_forall() ensures forall x:int :: 0*x == 0; ensures forall x:int :: x*0 == 0; ensures forall x:int :: 1*x == x; ensures forall x:int :: x*1 == x; { } static lemma lemma_mul_is_commutative_forall() ensures forall x:int, y:int :: x*y == y*x; { } static lemma lemma_mul_ordering_forall() ensures forall x:int, y:int, b:int :: 0 < x && 0 < y && 0 <= x*y < b ==> x < b && y < b; { forall (x:int, y:int, b:int | 0 < x && 0 < y && 0 <= x*y < b) ensures x < b && y < b; { lemma_mul_ordering(x,y,b); } } static lemma lemma_mul_strict_inequality_forall() ensures forall x:int, y:int, z:int :: x < y && z>0 ==> x*z < y*z; { forall (x:int, y:int, z:int | x < y && z>0) ensures x*z < y*z; { lemma_mul_strict_inequality(x, y, z); } } static lemma lemma_mul_inequality_forall() ensures forall x:int, y:int, z:int :: x <= y && z>=0 ==> x*z <= y*z; { forall (x:int, y:int, z:int | x <= y && z>=0) ensures x*z <= y*z; { lemma_mul_inequality(x, y, z); } } static lemma lemma_mul_strict_inequality_converse_forall() ensures forall x:int, y:int, z:int :: x*z < y*z && z>=0 ==> x < y; { forall (x:int, y:int, z:int | x*z < y*z && z>=0) ensures x < y; { lemma_mul_strict_inequality_converse(x,y,z); } } static lemma lemma_mul_inequality_converse_forall() ensures forall x:int, y:int, z:int :: x*z <= y*z && z>0 ==> x <= y; { forall (x:int, y:int, z:int | x*z <= y*z && z>0) ensures x <= y; { lemma_mul_inequality_converse(x,y,z); } } static lemma lemma_mul_is_distributive_add_forall() ensures forall x:int, y:int, z:int :: x*(y + z) == x*y + x*z; { forall (x:int, y:int, z:int) ensures x*(y + z) == x*y + x*z; { lemma_mul_is_distributive_add(x,y,z); } } static lemma lemma_mul_is_distributive_sub_forall() ensures forall x:int, y:int, z:int :: x*(y - z) == x*y - x*z; { forall (x:int, y:int, z:int) ensures x*(y - z) == x*y - x*z; { lemma_mul_is_distributive_sub(x,y,z); } } static lemma lemma_mul_is_distributive_forall() ensures forall x:int, y:int, z:int :: x*(y + z) == x*y + x*z; ensures forall x:int, y:int, z:int :: x*(y - z) == x*y - x*z; ensures forall x:int, y:int, z:int :: (y + z)*x == y*x + z*x; ensures forall x:int, y:int, z:int :: (y - z)*x == y*x - z*x; { lemma_mul_is_distributive_add_forall(); lemma_mul_is_distributive_sub_forall(); lemma_mul_is_commutative_forall(); } static lemma lemma_mul_is_associative_forall() ensures forall x:int, y:int, z:int :: x * (y * z) == (x * y) * z; { forall (x:int, y:int, z:int) ensures x * (y * z) == (x * y) * z; { lemma_mul_is_associative(x,y,z); } } static lemma lemma_mul_nonzero_forall() ensures forall x:int, y:int :: x*y != 0 <==> x != 0 && y != 0; { forall (x:int, y:int) ensures x*y != 0 <==> x != 0 && y != 0; { lemma_mul_nonzero(x,y); } } static lemma lemma_mul_nonnegative_forall() ensures forall x:int, y:int :: 0 <= x && 0 <= y ==> 0 <= x*y; { forall (x:int, y:int | 0 <= x && 0 <= y) ensures 0 <= x*y; { lemma_mul_nonnegative(x,y); } } static lemma lemma_mul_unary_negation_forall() ensures forall x:int, y:int :: (-x)*y == -(x*y) == x*(-y); { forall (x:int, y:int) ensures (-x)*y == -(x*y) == x*(-y); { lemma_mul_unary_negation(x,y); } } static lemma lemma_mul_strictly_increases_forall() ensures forall x:int, y:int :: (1 < x && 0 < y) ==> (y < x*y); { forall (x:int, y:int | 1 < x && 0 < y) ensures y < x*y; { lemma_mul_strictly_increases(x,y); } } static lemma lemma_mul_increases_forall() ensures forall x:int, y:int :: (0 < x && 0 < y) ==> (y <= x*y); { forall (x:int, y:int | 0 < x && 0 < y) ensures y <= x*y; { lemma_mul_increases(x,y); } } static lemma lemma_mul_strictly_positive_forall() ensures forall x:int, y:int :: (0 < x && 0 < y) ==> (0 < x*y); { forall (x:int, y:int | 0 < x && 0 < y) ensures 0 < x*y; { lemma_mul_strictly_positive(x,y); } } static lemma lemma_mul_one_to_one_forall() ensures forall m:int, x:int, y:int :: (m!=0 && m*x == m*y) ==> x==y; { forall (m:int, x:int, y:int | m!=0 && m*x == m*y) ensures x==y; { lemma_mul_one_to_one(m, x, y); } } ////////////////////////////////////////////////////////////////////////////// // // ////////////////////////////////////////////////////////////////////////////// static lemma lemma_mul_properties() ensures forall x:int, y:int :: x*y == y*x; ensures forall x:int :: x*0 == 0*x == 0; ensures forall x:int :: x*1 == 1*x == x; ensures forall x:int, y:int, z:int :: x < y && z > 0 ==> x*z < y*z; ensures forall x:int, y:int, z:int :: x <= y && z >= 0 ==> x*z <= y*z; ensures forall x:int, y:int, z:int :: x*(y + z) == x*y + x*z; ensures forall x:int, y:int, z:int :: x*(y - z) == x*y - x*z; ensures forall x:int, y:int, z:int :: (y + z)*x == y*x + z*x; ensures forall x:int, y:int, z:int :: (y - z)*x == y*x - z*x; ensures forall x:int, y:int, z:int :: x*y*z == x*y*z; ensures forall x:int, y:int :: x*y != 0 <==> x != 0 && y != 0; ensures forall x:int, y:int :: 0 <= x && 0 <= y ==> 0 <= x*y; ensures forall x:int, y:int, b:int :: 0 < x && 0 < y && 0 <= x*y < b ==> x < b && y < b; ensures forall x:int, y:int :: (1 < x && 0 < y) ==> (y < x*y); ensures forall x:int, y:int :: (0 < x && 0 < y) ==> (y <= x*y); ensures forall x:int, y:int :: (0 < x && 0 < y) ==> (0 < x*y); { lemma_mul_strict_inequality_forall(); lemma_mul_inequality_forall(); lemma_mul_is_distributive_forall(); lemma_mul_is_associative_forall(); lemma_mul_ordering_forall(); lemma_mul_nonzero_forall(); lemma_mul_nonnegative_forall(); lemma_mul_strictly_increases_forall(); lemma_mul_increases_forall(); } lemma lemma_mul_cancels_negatives(a:int, b:int) ensures a*b == (-a)*(-b); { lemma_mul_properties(); } //- Kept for legacy reasons: static function INTERNAL_mul_recursive(x:int, y:int) : int { mul_recursive(x, y) } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Math/mul_nonlinear.i.dfy ================================================ //- //- WARNING: In general, you shouldn't need to call these directly. Try //- to use the ones in mul.i.dfy instead. They're more full-featured anyway. static lemma lemma_mul_strictly_positive(x:int, y:int) ensures (0 < x && 0 < y) ==> (0 < x*y); {} static lemma lemma_mul_nonzero(x:int, y:int) ensures x*y != 0 <==> x != 0 && y != 0; {} static lemma lemma_mul_is_associative(x:int, y:int, z:int) ensures x * (y * z) == (x * y) * z; {} static lemma lemma_mul_is_distributive_add(x:int, y:int, z:int) ensures x*(y + z) == x*y + x*z; {} static lemma lemma_mul_ordering(x:int, y:int, b:int) requires 0 < x; requires 0 < y; requires 0 <= x*y < b; ensures x < b && y < b; { } static lemma lemma_mul_strict_inequality(x:int, y:int, z:int) requires x < y; requires z > 0; ensures x*z < y*z; {} ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Math/power.i.dfy ================================================ include "power.s.dfy" include "mul.i.dfy" //-lemma lemma_mul_passes_harmlessly_through_mod( //- ensures mul(x,y) % m == mul(x static lemma lemma_power_0(b:int) ensures power(b,0) == 1; { reveal_power(); } static lemma lemma_power_1(b:int) ensures power(b,1) == b; { calc { power(b,1); { reveal_power(); } b*power(b,0); { lemma_power_0(b); } b*1; { lemma_mul_basics_forall(); } b; } } static lemma lemma_0_power(e:nat) requires e > 0; ensures power(0,e) == 0; { reveal_power(); lemma_mul_basics_forall(); if (e != 1) { lemma_0_power(e - 1); } } static lemma lemma_1_power(e:nat) ensures power(1,e) == 1; { reveal_power(); lemma_mul_basics_forall(); if (e != 0) { lemma_1_power(e - 1); } } static lemma lemma_power_adds(b:int, e1:nat, e2:nat) decreases e1; ensures power(b,e1)*power(b,e2) == power(b,e1+e2); { if (e1==0) { calc { power(b,e1)*power(b,e2); { lemma_power_0(b); } 1*power(b,e2); { lemma_mul_basics_forall(); } power(b,0+e2); } } else { calc { power(b,e1)*power(b,e2); { reveal_power(); } (b*power(b,e1-1))*power(b,e2); { lemma_mul_is_associative_forall(); } b*(power(b,e1-1)*power(b,e2)); { lemma_power_adds(b, e1-1, e2); } b*power(b,e1-1+e2); { reveal_power(); } power(b,e1+e2); } } } static lemma lemma_power_multiplies(a:nat,b:nat,c:nat) decreases c; ensures 0<=b*c; ensures power(a,b*c) == power(power(a,b),c); { lemma_mul_nonnegative(b,c); if (0==c) { lemma_mul_basics_forall(); calc { power(a,b*c); { lemma_power_0(a); } 1; { lemma_power_0(power(a,b)); } power(power(a,b),c); } } else { calc { b*c - b; { lemma_mul_basics_forall(); } b*c - mul(b,1); { lemma_mul_is_distributive_forall(); } b*(c-1); } lemma_mul_nonnegative(b,c-1); assert 0 <= b*c-b; calc { power(a,b*c); power(a,b+b*c-b); { lemma_power_adds(a,b,b*c-b); } power(a,b)*power(a,b*c-b); power(a,b)*power(a,b*(c-1)); { lemma_power_multiplies(a,b,c-1); } power(a,b)*power(power(a,b),c-1); { reveal_power(); } power(power(a,b),c); } } } static lemma lemma_power_distributes(a:int, b:int, e:nat) decreases e; ensures power(a*b, e) == power(a, e) * power(b, e); { reveal_power(); lemma_mul_basics_forall(); if (e > 0) { calc { power(a*b, e); (a*b) * power(a*b, e - 1); { lemma_power_distributes(a, b, e - 1); } (a*b) * (power(a, e - 1) * power(b, e - 1)); { lemma_mul_is_associative_forall(); lemma_mul_is_commutative_forall(); } (a*power(a, e - 1)) * (b*power(b, e - 1)); power(a,e) * power(b,e); } lemma_mul_is_distributive_forall(); } } static lemma lemma_power_positive(b:int, e:nat) decreases e; requires 0 { lemma_power_positive(b,e-1); lemma_mul_strictly_positive_forall(); } 0; } } } static lemma lemma_power_increases(b:nat,e1:nat,e2:nat) requires 0 0; { if (exp==0) then 1 else 2*power2(exp-1) } */ static lemma lemma_power2_strictly_increases(e1: int, e2: int) requires 0 <= e1 < e2; ensures power2(e1) < power2(e2); decreases e2; { if e1+1 == e2 { reveal_power2(); } else { reveal_power2(); lemma_power2_strictly_increases(e1, e2-1); } } static lemma lemma_power2_increases(e1: int, e2: int) requires 0 <= e1 <= e2; ensures power2(e1) <= power2(e2); decreases e2; { if e2 == e1 { } else { reveal_power2(); lemma_power2_increases(e1, e2-1); } } static lemma lemma_power2_positive() ensures forall e:nat :: 0 < power2(e); { forall (e:nat) ensures 0 < power2(e); { lemma_power2_0_is_1(); lemma_power2_increases(0,e); } } static lemma lemma_power2_nonzero_bigger_than_one() ensures forall e:nat :: 0 1 < power2(e); { forall (e:nat | 0= e2) { lemma_power2_increases(e2, e1); assert false; } } static lemma lemma_power2_increases_converse(e1: int, e2: int) requires 0 < e1; requires 0 < e2; requires power2(e1) <= power2(e2); ensures e1 <= e2; { if (e1 > e2) { lemma_power2_strictly_increases(e2, e1); assert false; } } static lemma lemma_power2_adds(e1:nat, e2:nat) decreases e2; ensures power2(e1 + e2) == power2(e1) * power2(e2); { if e2 == 0 { lemma_mul_properties(); reveal_power2(); } else { var e2min1 := e2 - 1; calc { power2(e1 + e2); { reveal_power2(); } power2(e1 + e2 - 1) * 2; power2(e1 + e2min1) * 2; { lemma_power2_adds(e1, e2min1); } (power2(e1) * power2(e2min1)) * 2; { lemma_mul_is_associative(power2(e1), power2(e2min1), 2); } (power2(e1) * (power2(e2min1) * 2)); { assert e2!=0; reveal_power2(); assert power2(e2min1) * 2 == power2(e2); } power2(e1) * power2(e2); } assert power2(e1 + e2) == power2(e1) * power2(e2); } } static lemma lemma_power2_div_is_sub(x:int, y:int) requires 0 <= x <= y; ensures power2(y - x) == power2(y) / power2(x) >= 0; { calc { power2(y) / power2(x); { lemma_power2_adds(y-x, x); } (power2(y-x)*power2(x)) / power2(x); { lemma_div_by_multiple(power2(y-x), power2(x)); } power2(y-x); } } static lemma lemma_2toX32() ensures power2(0) == 0x1; ensures power2(1) == 0x2; ensures power2(2) == 0x4; ensures power2(3) == 0x8; ensures power2(4) == 0x10; ensures power2(5) == 0x20; ensures power2(6) == 0x40; ensures power2(7) == 0x80; ensures power2(8) == 0x100; ensures power2(9) == 0x200; ensures power2(10) == 0x400; ensures power2(11) == 0x800; ensures power2(12) == 0x1000; ensures power2(13) == 0x2000; ensures power2(14) == 0x4000; ensures power2(15) == 0x8000; ensures power2(16) == 0x10000; ensures power2(17) == 0x20000; ensures power2(18) == 0x40000; ensures power2(19) == 0x80000; ensures power2(20) == 0x100000; ensures power2(21) == 0x200000; ensures power2(22) == 0x400000; ensures power2(23) == 0x800000; ensures power2(24) == 0x1000000; ensures power2(25) == 0x2000000; ensures power2(26) == 0x4000000; ensures power2(27) == 0x8000000; ensures power2(28) == 0x10000000; ensures power2(29) == 0x20000000; ensures power2(30) == 0x40000000; ensures power2(31) == 0x80000000; ensures power2(32) == 0x100000000; { reveal_power2(); } static lemma lemma_2toX() ensures power2(64) == 18446744073709551616; ensures power2(60) == 1152921504606846976; ensures power2(32) == 4294967296; ensures power2(24) == 16777216; ensures power2(19) == 524288; ensures power2(16) == 65536; ensures power2(8) == 256; { lemma_2to32(); lemma_2to64(); } static lemma lemma_power2_add8(n:int) requires n >= 0; ensures power2(n + 1) == 2 * power2(n); ensures power2(n + 2) == 4 * power2(n); ensures power2(n + 3) == 8 * power2(n); ensures power2(n + 4) == 16 * power2(n); ensures power2(n + 5) == 32 * power2(n); ensures power2(n + 6) == 64 * power2(n); ensures power2(n + 7) == 128 * power2(n); ensures power2(n + 8) == 256 * power2(n); { reveal_power2(); } static lemma lemma_2to32() ensures power2(32) == 4294967296; ensures power2(24) == 16777216; ensures power2(19) == 524288; ensures power2(16) == 65536; ensures power2(8) == 256; ensures power2(0) == 1; { lemma_power2_0_is_1(); lemma_power2_add8(0); lemma_power2_add8(8); lemma_power2_add8(16); lemma_power2_add8(24); } static lemma lemma_2to64() ensures power2(64) == 18446744073709551616; ensures power2(60) == 1152921504606846976; { lemma_2to32(); lemma_power2_add8(32); lemma_power2_add8(40); lemma_power2_add8(48); lemma_power2_add8(56); } static lemma lemma_power2_0_is_1() ensures power2(0) == 1; { reveal_power2(); } static lemma lemma_power2_1_is_2() ensures power2(1) == 2; { lemma_power2_0_is_1(); reveal_power2(); } static lemma lemma_bit_count_is_unique(x:int, a:int, b:int) requires 0= 0 ==> x / power2(24) == x / 16777216; ensures forall x :: x >= 0 ==> x / power2(16) == x / 65536; ensures forall x :: x >= 0 ==> x / power2(8) == x / 256; { lemma_2toX(); reveal_power2(); lemma_div_is_div_recursive_forall(); forall x | x >= 0 ensures x / power2(24) == x / 16777216 && x / power2(16) == x / 65536 && x / power2(8) == x / 256; { lemma_div_2_to_8(x); lemma_div_2_to_16(x); lemma_div_2_to_24(x); } } static lemma lemma_div_2_to_8(x:int) requires x >= 0; ensures x / power2(8) == x / 256; { lemma_2toX(); lemma_div_is_div_recursive_forall(); if (x < 256) { } else { lemma_div_2_to_8(x - 256); } } static lemma lemma_div_2_to_16(x:int) requires x >= 0; ensures x / power2(16) == x / 65536; { lemma_2toX(); lemma_div_is_div_recursive_forall(); if (x < 65536) { } else { lemma_div_2_to_16(x - 65536); } } static lemma lemma_div_2_to_24(x:int) requires x >= 0; ensures x / power2(24) == x / 16777216; { lemma_2toX(); lemma_div_is_div_recursive_forall(); if (x < 16777216) { } else { lemma_div_2_to_24(x - 16777216); } } //- //-//////////////////////////////////////////////////////////////////////////// static lemma lemma_power2_is_power_2_general() ensures forall x:nat :: power2(x) == power(2,x); { forall x:nat ensures power2(x) == power(2,x); { lemma_power2_is_power_2(x); } } static lemma lemma_power2_is_power_2(x:nat) ensures power2(x) == power(2,x); { if (x==0) { reveal_power2(); reveal_power(); } else { calc { power2(x); { reveal_power2(); } 2*power2(x-1); { lemma_mul_is_mul_boogie(2,power2(x-1)); } (2 * power2(x-1)); { lemma_power2_is_power_2(x-1); } (2 * power(2,x-1)); { reveal_power(); } power(2,x); } } } lemma lemma_word_to_bytes_unique_specific_power2_helper1(a:int, b:int) requires a % 256 == b % 256; requires (a / power2(8)) % 256 == (b / power2(8)) % 256; requires 0 <= a; requires 0 <= b; ensures a % 65536 == b % 65536; { var d := 256; var c := 256; assert d*c == 65536; lemma_2toX(); calc { a % 65536; a % (d*c); { lemma_mod_breakdown(a,d,c); } d * ((a/d)%c) + a%d; d * ((b/d)%c) + b%d; { lemma_mod_breakdown(b,d,c); } b % (d*c); b % 65536; } } lemma lemma_word_to_bytes_unique_specific_power2_helper2(a:int, b:int) requires (a / power2(16)) % 256 == (b / power2(16)) % 256; requires a / power2(24) == b / power2(24); requires 0 <= a; requires 0 <= b; ensures a / power2(16) == b / power2(16); { var ap := a/power2(16); var bp := b/power2(16); var d := power2(8); lemma_2toX(); lemma_mul_strictly_positive_forall(); calc { ap/d; { lemma_div_denominator(a,power2(16),power2(8)); } a/(power2(16)*power2(8)); { lemma_power2_adds(16,8); } a/power2(24); b/power2(24); { lemma_power2_adds(16,8); } b/(power2(16)*power2(8)); { lemma_div_denominator(b,power2(16),power2(8)); } bp/d; } calc { a/power2(16); ap; { lemma_fundamental_div_mod(ap,d); } d*(ap/d)+ap%d; d*(bp/d)+bp%d; { lemma_fundamental_div_mod(bp,d); } bp; b/power2(16); } } lemma lemma_word_to_bytes_unique_specific_power2_helper3(a:int, b:int) requires a % 65536 == b % 65536; requires a / power2(16) == b / power2(16); requires 0 <= a; requires 0 <= b; ensures a == b; { lemma_2toX(); lemma_fundamental_div_mod(a,65536); lemma_fundamental_div_mod(b,65536); } lemma lemma_word_to_bytes_unique_specific_power2(a:int, b:int) requires a % 256 == b % 256; requires (a / power2(8)) % 256 == (b / power2(8)) % 256; requires (a / power2(16)) % 256 == (b / power2(16)) % 256; requires a / power2(24) == b / power2(24); requires 0 <= a; requires 0 <= b; ensures a == b; { lemma_word_to_bytes_unique_specific_power2_helper1(a, b); lemma_word_to_bytes_unique_specific_power2_helper2(a, b); lemma_word_to_bytes_unique_specific_power2_helper3(a, b); } static lemma lemma_pull_out_powers_of_2(x:nat, y:nat, z:nat) ensures 0<=x*y; ensures 0<=y*z; ensures power(power2(x*y), z) == power(power2(x), y*z); { lemma_mul_nonnegative(x,y); lemma_mul_nonnegative(y,z); lemma_power_positive(2,x); calc { power(power2(x*y), z); { lemma_power2_is_power_2(x*y); } power(power(2,x*y), z); { lemma_power_multiplies(2, x, y); } power(power(power(2,x),y), z); { lemma_power_multiplies(power(2,x), y, z); } power(power(2,x), y*z); { lemma_power2_is_power_2(x); } power(power2(x), y*z); } } static lemma lemma_SequenceOfZerosIsRepeatDigitZero(count: int) requires count >= 0; ensures SequenceOfZeros(count) == RepeatDigit(0, count); { if (count > 0) { lemma_SequenceOfZerosIsRepeatDigitZero(count - 1); } } static lemma lemma_mask_div_2(c:nat) requires 0 { x/power2(s) >= power2(p-s); { lemma_mul_inequality(power2(p-s), x/power2(s), power2(s)); } (x/power2(s))*power2(s) >= power2(p-s)*power2(s); { lemma_fundamental_div_mod(x, power2(s)); lemma_mul_is_commutative_forall(); } x - x%power2(s) >= power2(p-s)*power2(s); { lemma_power2_adds(p-s, s); } x - x%power2(s) >= power2(p); { lemma_mod_properties(); } x >= power2(p); false; } } static lemma lemma_power2_unfolding(a:nat, b:nat) ensures 0<=a*b; ensures power(power2(a), b) == power2(a*b); { lemma_mul_nonnegative(a,b); lemma_power2_is_power_2(a); lemma_power_multiplies(2,a,b); lemma_power2_is_power_2(a*b); } static function{:opaque} NatNumBits(n:nat):nat ensures NatNumBits(n) >= 0; { if n == 0 then 0 else 1 + NatNumBits(n / 2) } static lemma lemma_Power2BoundIsNatNumBits(c:nat, n:nat) ensures (((c>0) ==> (power2(c-1) <= n)) && (n < power2(c))) <==> c == NatNumBits(n); { reveal_NatNumBits(); reveal_power2(); if (c > 0) { lemma_Power2BoundIsNatNumBits(c - 1, n / 2); } assert NatNumBits(n / 2) >= 0; //- dafnycc } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Math/power2.s.dfy ================================================ include "../base.s.dfy" static function {:opaque} power2(exp: nat) : nat ensures power2(exp) > 0; { if (exp==0) then 1 else 2*power2(exp-1) } static lemma lemma_power2_32() ensures power2(8) == 0x100; ensures power2(16) == 0x10000; ensures power2(24) == 0x1000000; ensures power2(32) == 0x100000000; { reveal_power2(); assert unroll(1) && unroll(2) && unroll(3) && unroll(4) && unroll(5) && unroll(6) && unroll(7) && unroll(8); assert power2(0) == 0x1; assert power2(2) == 0x4; assert power2(4) == 0x10; assert power2(6) == 0x40; assert power2(8) == 0x100; assert power2(10) == 0x400; assert power2(12) == 0x1000; assert power2(14) == 0x4000; assert power2(16) == 0x10000; assert power2(18) == 0x40000; assert power2(20) == 0x100000; assert power2(22) == 0x400000; assert power2(24) == 0x1000000; assert power2(26) == 0x4000000; assert power2(28) == 0x10000000; assert power2(30) == 0x40000000; } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Math/power2methods.i.dfy ================================================ include "power2.i.dfy" method MakePower2(e:nat) returns (x:nat) requires e < 32; ensures x==power2(e); { lemma_2toX32(); if (e<16) { if (e<8) { if (e<4) { if (e<2) { if (e<1) { x := 1; } else { x := 2; } } else { if (e<3) { x := 4; } else { x := 8; } } } else { if (e<6) { if (e<5) { x := 16; } else { x := 32; } } else { if (e<7) { x := 64; } else { x := 128; } } } } else { if (e<12) { if (e<10) { if (e<9) { x := 256; } else { x := 512; } } else { if (e<11) { x := 1024; } else { x := 2048; } } } else { if (e<14) { if (e<13) { x := 4096; } else { x := 8192; } } else { if (e<15) { x := 16384; } else { x := 32768; } } } } } else { if (e<24) { if (e<20) { if (e<18) { if (e<17) { x := 65536; } else { x := 131072; } } else { if (e<19) { x := 262144; } else { x := 524288; } } } else { if (e<22) { if (e<21) { x := 1048576; } else { x := 2097152; } } else { if (e<23) { x := 4194304; } else { x := 8388608; } } } } else { if (e<28) { if (e<26) { if (e<25) { x := 16777216; } else { x := 33554432; } } else { if (e<27) { x := 67108864; } else { x := 134217728; } } } else { if (e<30) { if (e<29) { x := 268435456; } else { x := 536870912; } } else { if (e<31) { x := 1073741824; } else { x := 2147483648; } } } } } } method CountBits(x:nat) returns (e:nat) requires x0 ==> 0 0; requires x >= 0; ensures RoundUpToMultiple(x, m) % m == 0; ensures x <= RoundUpToMultiple(x, m) < x + m; ensures RoundUpToMultiple(x, m) == (if x%m == 0 then x else x + m - x%m); { var r := RoundUpToMultiple(x, m); lemma_div_pos_is_pos(x + m - 1, m); lemma_mod_multiples_basic(((x + m - 1) / m), m); ghost var a := x / m; ghost var b := x % m; lemma_div_pos_is_pos(x, m); lemma_mul_nonnegative(a, m); lemma_mul_is_commutative(a, m); lemma_fundamental_div_mod(x, m); assert x == m * a + b; if (b == 0) { calc { r; ((x + m - 1) / m) * m; ((m * a + m - 1) / m) * m; { lemma_fundamental_div_mod_converse(m * a + m - 1, m, a, m - 1); } a * m; x; } } else { calc <= { 1; { lemma_mod_properties(); } b; } calc <= { b; { lemma_mod_properties(); } m - 1; } lemma_mul_nonnegative(m, a+1); lemma_mul_is_commutative(m, a+1); calc { r; ((x + m - 1) / m) * m; ((m * a + b + m - 1) / m) * m; (((m * a + m) + b - 1) / m) * m; (((m * a + m * 1) + b - 1) / m) * m; { lemma_mul_is_distributive_add(m, a, 1); } ((m * (a + 1) + b - 1) / m) * m; { lemma_fundamental_div_mod_converse(m * (a+1) + b - 1, m, a + 1, b - 1); } (a + 1) * m; m * (a + 1); { lemma_mul_is_distributive_add(m, a, 1); } a * m + 1 * m; m * a + 1 * m; a * m + m; } } } static function RoundUpToMultiple_premium(x:int, m:int) : int requires m > 0; requires x >= 0; ensures RoundUpToMultiple(x, m) % m == 0; ensures x <= RoundUpToMultiple(x, m) < x + m; ensures RoundUpToMultiple(x, m) == (if x%m == 0 then x else x + m - x%m); { lemma_RoundUpToMultiple_properties(x, m); RoundUpToMultiple(x, m) } //-////////////////////////////////////// //- DivideRoundingUp //-////////////////////////////////////// static lemma Lemma_DivideRoundingUpPreservesWord32 (x:int, m:int) requires m > 0; ensures Word32(x) ==> Word32(DivideRoundingUp(x, m)); { if Word32(x) { if m == 1 { calc { DivideRoundingUp(x, m); (x / m) + (if x % m == 0 then 0 else 1); { Lemma_Mod1IsZero(x); } (x / m) + 0; x / m; { lemma_div_basics(x); } x; } } else { lemma_2toX(); calc { 0; <= { lemma_div_pos_is_pos(x, m); } x / m; <= (x / m) + (if x % m == 0 then 0 else 1); DivideRoundingUp(x, m); } calc { DivideRoundingUp(x, m); (x / m) + (if x % m == 0 then 0 else 1); <= (x / m) + 1; <= { lemma_div_is_ordered_by_denominator(x, 2, m); } (x / 2) + 1; <= power2(32) / 2 + 1; } } } } static lemma Lemma_Mod1IsZero (x:int) requires x >= 0; ensures x % 1 == 0; { lemma_mod_is_mod_recursive_forall(); if x >= 1 { Lemma_Mod1IsZero(x-1); } } static lemma Lemma_DivideRoundingUpProducesCeiling (x:int, m:int) requires x >= 0; requires m > 0; ensures x <= DivideRoundingUp(x, m) * m < x + m; { if x % m == 0 { calc { DivideRoundingUp(x, m) * m; (x/m) * m; { lemma_mul_is_commutative(m, x/m); } m * (x/m); m * (x/m) + x % m; { lemma_fundamental_div_mod(x, m); } x; } } else { calc { DivideRoundingUp(x, m) * m; (x/m + 1) * m; { lemma_mul_is_commutative(m, x/m + 1); } m * (x/m + 1); { lemma_mul_is_distributive_add(m, x/m, 1); lemma_mul_is_mul_boogie(m, 1); } m * (x/m) + m * 1; m * (x/m) + m; { lemma_fundamental_div_mod(x, m); } x + m - x%m; } calc { x + m - x%m; > { lemma_mod_properties(); } x; } calc { x + m - x%m; < { lemma_mod_properties(); } x + m; } } } static lemma Lemma_DivideMultipleGeneral (x:int, y:int, m:int) requires m > 0; requires x >= 0; requires 0 <= y < m; ensures (x * m + y) / m == x; { calc { x * m + y; { lemma_fundamental_div_mod(x * m + y, m); } m * ((x * m + y) / m) + ((x * m + y) % m); { lemma_mul_is_commutative(x, m); } { lemma_mod_multiples_vanish(x, y, m); } m * ((x * m + y) / m) + (y % m); { lemma_small_mod(y, m); } m * ((x * m + y) / m) + y; { lemma_mul_is_commutative(m, (x * m + y) / m); } ((x * m + y) / m) * m + y; } assert x * m == ((x * m + y) / m) * m; assert (x * m) / m == (((x * m + y) / m) * m) / m; lemma_div_by_multiple(x, m); lemma_mul_nonnegative(x, m); lemma_div_pos_is_pos(x * m + y, m); lemma_div_by_multiple((x * m + y) / m, m); } static lemma Lemma_DivideRoundingUpEquivalentFormula (x:int, m:int) requires x >= 0; requires m > 0; ensures DivideRoundingUp(x, m) == (x+m-1)/m; ensures DivideRoundingUp(x, m) == (x-1)/m+1; { if x % m == 0 { calc { x+m-1; { lemma_fundamental_div_mod(x+m-1, m); } m * ((x+m-1)/m) + (x+m-1)%m; { lemma_small_mod(m-1, m); lemma_mod_adds(x, m-1, m); } m * ((x+m-1)/m) + m-1; { lemma_mul_is_commutative(m, (x+m-1)/m); } ((x+m-1)/m) * m + m-1; } assert x == ((x+m-1)/m) * m; lemma_div_pos_is_pos(x+m-1, m); lemma_div_by_multiple(((x+m-1)/m), m); assert x / m == ((x+m-1)/m); } else { calc { x + m - 1; { lemma_fundamental_div_mod(x, m); } m * (x/m) + (x%m) + m - 1; >= { lemma_mod_properties(); } m * (x/m) + 1 + m - 1; m * (x/m) + m; m * (x/m) + m * 1; { lemma_mul_is_distributive_add(m, x/m, 1); lemma_mul_is_mul_boogie(m, 1); } m * (x/m + 1); { lemma_mul_is_commutative(m, x/m+1); } (x/m + 1) * m; } calc { (x + m - 1) / m; >= { lemma_div_is_ordered((x/m + 1) * m, x + m - 1, m); } ((x/m + 1) * m) / m; { lemma_div_pos_is_pos(x, m); } { lemma_div_by_multiple(x/m + 1, m); } x/m + 1; DivideRoundingUp(x, m); } calc { x + m - 1; { lemma_fundamental_div_mod(x, m); } m * (x/m) + (x%m) + m - 1; < { lemma_mod_properties(); } m * (x/m) + m + m - 1; m * (x/m) + m * 1 + m - 1; { lemma_mul_is_distributive_add(m, x/m, 1); lemma_mul_is_mul_boogie(m, 1); } m * (x/m + 1) + m - 1; { lemma_mul_is_commutative(m, x/m+1); } (x/m + 1) * m + m - 1; } calc { (x + m - 1) / m; <= { lemma_div_is_ordered(x + m - 1, (x/m + 1) * m + m - 1, m); } ((x/m + 1) * m + m - 1) / m; { lemma_div_pos_is_pos(x, m); Lemma_DivideMultipleGeneral(x/m + 1, m-1, m); } x/m + 1; DivideRoundingUp(x, m); } } calc { (x-1)/m+1; { lemma_hoist_over_denominator(x-1, 1, m); } ((x-1)+mul(1,m)) / m; { lemma_mul_basics_forall(); } (x+m-1) / m; } } static function method DivideRoundingUp_premium (x:int, m:int) : int requires x >= 0; requires m > 0; ensures DivideRoundingUp_premium(x, m) == DivideRoundingUp(x, m); ensures DivideRoundingUp_premium(x, m) >= 0; ensures Word32(x) ==> Word32(DivideRoundingUp_premium(x, m)); ensures x <= DivideRoundingUp_premium(x, m) * m < x + m; ensures DivideRoundingUp_premium(x, m) == (x + m - 1) / m; ensures DivideRoundingUp_premium(x, m) == (x-1)/m+1; { calc { (x/m) + (if x % m == 0 then 0 else 1); >= x/m; >= { lemma_div_pos_is_pos(x, m); } 0; } Lemma_DivideRoundingUpPreservesWord32(x, m); Lemma_DivideRoundingUpProducesCeiling(x, m); Lemma_DivideRoundingUpEquivalentFormula(x, m); DivideRoundingUp(x, m) } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Math/round.s.dfy ================================================ static function method RoundUpToMultiple (x:int, m:int) : int requires m > 0; requires x >= 0; { ((x + m - 1) / m) * m } static function method DivideRoundingUp (x:int, m:int) : int requires x >= 0; requires m > 0; { (x/m) + (if x % m == 0 then 0 else 1) } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Net/.gitignore ================================================ *.bpl *.log ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Net/IPv4.i.dfy ================================================ //- include "../Util/bytes_and_words.s.dfy" include "../Util/integer_sequences.i.dfy" include "../Math/power2.i.dfy" include "../../Drivers/Network/Intel/driver.i.dfy" include "ethernet.i.dfy" include "InternetChecksum.i.dfy" // // function method {:opaque} Serialize16(Value:int) : seq requires Word16(Value); ensures IsByteSeqOfLen(Serialize16(Value), 2); { lemma_2toX(); [Value / 0x100] + [Value % 0x100] } function method {:opaque} Deserialize16(Bytes:seq) : int requires IsByteSeq(Bytes); requires |Bytes| == 2; ensures Word16(Deserialize16(Bytes)); { lemma_2toX(); Bytes[0] * 0x100 + Bytes[1] } //- //- Define an IPv4 Address. //- datatype IPv4Address = IPv4AddressBuilder(bytes:seq); function ValidIPv4Address(Addr:IPv4Address) : bool { //- //- Technically all 2^32 are valid, although some are reserved. //- IsByteSeqOfLen(Addr.bytes, 4) } //- //- IPv4 Header Format: //- //- Byte 0 Byte 1 Byte 2 Byte 3 //- --------------------------------------------------------------------- //- | Vers / Hdr Len | DSCP / ECN | Total Length | //- --------------------------------------------------------------------- //- | Identification | Flags / Frag Offset | //- --------------------------------------------------------------------- //- | Time To Live | Protocol | Header Checksum | //- --------------------------------------------------------------------- //- | Source IP Address | //- --------------------------------------------------------------------- //- | Destination IP Address | //- --------------------------------------------------------------------- //- //- Version = 4 and Header Length = 5 (32-bit words), so first byte = 0x45. //- DSCP / ECN we can leave at zero. //- Total Length = Header + Payload Length in bytes. We need to set this. //- Identification should be unique per packet, but can be ignored if we never fragment? //- Flags / Fragment Offset we can leave at zero. //- Time To Live (TTL) is really a hop count, we can use anything reasonable (e.g. 0x80). //- Protocol could be passed to us, or can be hard-wired to UDP (0x11). //- Header checksum needs to be calculated properly. //- Source IP Address could be passed to us or can be hard-wired. //- Destination IP Address should be passed to us. //- //- //- Send the given Data via IPv4 to the given destination ethernet address and IPv4 address. //- Use the given Protocol value as the number for the contained protocol. //- Use the given Headers as the header for the contained prtocol. //- Use the given source IPv4 address as the source. //- //- Note: Caller is responsible for ensuring that the provided destination IPv4 address is valid for the station with the provided ethernet address. //- method{:dafnycc_conservative_seq_triggers} compute_header(TotalLength:int, Id:int, Protocol:int, Checksum:int, IPSource:IPv4Address, IPDest:IPv4Address) returns (IpHeader:seq) requires 0 <= TotalLength <= 1500; requires IsByte(Id); requires IsByte(Protocol); requires Word16(Checksum); requires ValidIPv4Address(IPSource); requires ValidIPv4Address(IPDest); requires public(TotalLength); requires public(Id); requires public(Protocol); requires public(Checksum); requires public(IPSource); requires public(IPDest); ensures IsByteSeqOfLen(IpHeader,20); ensures public(IpHeader); { lemma_2toX(); IpHeader := [0x45] //- Version and Header Length. + [0x00] //- DSCP bits and ECN bit. + Serialize16(TotalLength) //- Total Length. + Serialize16(Id) //- Identification. + [0x0] //- First byte of Flags and Fragement Offset. + [0x0] //- Second byte of Flags and Fragement Offset. + [0x80] //- Time to live (TTL). + [Protocol] //- Higher-level Protocol. + Serialize16(Checksum) //- IP Header Checksum. + IPSource.bytes //- Source IP address. + IPDest.bytes; //- Destination IP address. } method{:dafnycc_conservative_seq_triggers} IPv4Send(state:network_state, EtherDest:ethernet_addr, IPSource:IPv4Address, IPDest:IPv4Address, Protocol:int, Headers:seq, Data:seq) returns (new_state:network_state) requires valid_network_state(state); requires ValidIPv4Address(IPSource); requires ValidIPv4Address(IPDest); requires valid_ethernet_addr(EtherDest); requires IsByte(Protocol); requires |Headers| + |Data| <= 1480; requires IsByteSeq(Headers); requires IsByteSeq(Data); requires public(state); requires public(EtherDest); requires public(IPSource); requires public(IPDest); requires public(Protocol); requires public(Headers); requires public(Data); ensures valid_network_state(new_state); ensures public(new_state); { lemma_2toX(); var TotalLength := 20 + |Headers| + |Data|; var Id := 0; //- //- First create the header over which to calculate the checksum. //- var Checksum := 0; var IpHeader := compute_header(TotalLength, Id, Protocol, Checksum, IPSource, IPDest); //- //- Re-create the header using the valid checksum. //- Checksum := InternetChecksum(IpHeader); IpHeader := compute_header(TotalLength, Id, Protocol, Checksum, IPSource, IPDest); new_state := EtherSend(state, EtherDest, IpHeader + Headers, Data); } method{:dafnycc_conservative_seq_triggers} IPv4Receive(state:network_state) returns (Success:bool, new_state:network_state, EtherSource:ethernet_addr, IPSource:IPv4Address, IPDest:IPv4Address, Protocol:int, Data:seq) requires valid_network_state(state); requires public(state); ensures valid_network_state(new_state); ensures Success ==> valid_ethernet_addr(EtherSource); ensures Success ==> ValidIPv4Address(IPSource); ensures Success ==> ValidIPv4Address(IPDest); ensures Success ==> IsByte(Protocol); ensures Success ==> IsByteSeq(Data); ensures Success ==> |Data| <= 1480; ensures public(new_state); ensures public(Success); ensures public(EtherSource); ensures public(IPSource); ensures public(IPDest); ensures public(Protocol); ensures public(Data); { lemma_2toX(); var EtherType:seq; Protocol := 0; IPSource := IPv4AddressBuilder([0, 0, 0, 0]); IPDest := IPv4AddressBuilder([0, 0, 0, 0]); Success, new_state, EtherSource, EtherType, Data := EtherReceive(state); if (Success) { if (EtherType[0] != 0x08 || EtherType[1] != 0x00) { //- Wrong Ethernet type field for IPv4. Success := false; //-debug_print(0x90, 0xdead3001); } else if (|Data| < 20) { //- Received data too short to contain an IPv4 header. Success := false; //-debug_print(0x90, 0xdead3002); } else { var Checksum := InternetChecksum(Data[0..20]); if (Checksum != 0) { //- Checksum failed, packet corrupted. Success := false; //-debug_print(0x90, 0xdead3003); } else if (Data[0] != 0x45) { //- Not an option-less IPv4 header. Success := false; //-debug_print(0x90, 0xdead3004); } else { var TotalLength := Deserialize16(Data[2..4]); if (TotalLength < 20) { //- TotalLength field is bogus (too small to include IPv4 header). Success := false; //-debug_print(0x90, 0xdead3005); } else if (TotalLength > |Data|) { //- Not enough data to hold packet described by IPv4 header. Success := false; //-debug_print(0x90, 0xdead3006); } else { Protocol := Data[9]; IPSource := IPv4AddressBuilder(Data[12..16]); IPDest := IPv4AddressBuilder(Data[16..20]); //- //- Everything looks good. //- Strip off the IPv4 header and trim to TotalLength. //- Data := Data[20..TotalLength]; } } } } //- else //- { //- debug_print(0x90, 0xdead3000); //- } } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Net/InternetChecksum.i.dfy ================================================ //- include "../Math/power2.s.dfy" include "../Math/bit_vector_lemmas_premium.i.dfy" include "../../Drivers/CPU/assembly.s.dfy" include "../../Drivers/CPU/assembly_premium.i.dfy" include "../Util/word_bits.i.dfy" include "../Util/relational.s.dfy" //- //- The "Internet Checksum" is the checksum used for error-checking of the IPv4 //- header (see RFC 791) as well as for error-checking of the UDP (see RFC 768) //- and TCP (see RFC 793) headers and payloads. //- //- The checksum is the 16 bit one's complement of the one's complement sum of //- all the 16 bit values covered by the checksum. If an odd number of bytes //- are being checksummed, a virtual zero byte is added at the end. //- //- See also RFC 1071. //- method InternetChecksum(Data:seq) returns (Checksum:int) requires IsByteSeq(Data); requires |Data| > 0; requires public(Data); ensures Word16(Checksum); ensures public(Checksum); { lemma_power2_32(); Checksum := PartialChecksum(Data); Checksum := Asm_BitwiseAnd(Asm_BitwiseNot(Checksum), 0xffff); lemma_and_with_ffff_premium(); } method PartialChecksum(Data:seq) returns (Checksum:int) requires IsByteSeq(Data); requires |Data| > 0; requires public(Data); ensures Word16(Checksum); ensures public(Checksum); { lemma_power2_32(); Checksum := 0; var Index := 0; while (Index < |Data| - 1) invariant Index >= 0; invariant Word16(Checksum); invariant public(Index); invariant public(Checksum); invariant public(Data); { Checksum := OnesComplementSum16(Checksum, Data[Index] * 0x100 + Data[Index + 1]); Index := Index + 2; } if (Index < |Data|) { Checksum := OnesComplementSum16(Checksum, Data[Index] * 0x100); } } method OnesComplementSum16(x:int, y:int) returns (Sum:int) requires Word16(x); requires Word16(y); requires public(x); requires public(y); ensures Word16(Sum); ensures public(Sum); { //- //- First calculate the conventional sum. //- Sum := x + y; //- //- To convert this value into a 16 bit one's complement representation, //- we need to check whether this sum has overflowed the maximum 16 bit //- value. If so, we need to perform an "end-around carry". This entails //- taking the overflow (i.e. carry) value and adding it back into the sum. //- //- Note that the maximum value the conventional sum of two unsigned 16 bit //- values can reach is 2 * 0xffff = 0x1fffe. This means that at most the //- overflow is a single carry bit, which we can safely add back into our //- remaining value (i.e. max 0xfffe) without concern for another overflow. //- if (Sum >= 0x10000) { Sum := Sum - 0x10000 + 1; } } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Net/Udp.i.dfy ================================================ //- include "../Util/bytes_and_words.s.dfy" include "../Util/integer_sequences.i.dfy" include "../Math/power2.i.dfy" include "IPv4.i.dfy" //- //- UDP Header Format: //- //- Byte 0 Byte 1 Byte 2 Byte 3 //- --------------------------------------------------------------------- //- | Source Port | Destination Port | //- --------------------------------------------------------------------- //- | Length | Checksum | //- --------------------------------------------------------------------- //- //- Source Port is the sender's 16 bit port number. //- Destination Port is the receiver's 16 bit port number. //- Length = UDP Header + Payload Length in bytes. //- Checksum is the standard Internet Checksum computed over the Pseudo Header and data. //- //- //- Send the given Data via UDP to the given destination ethernet address, IPv4 address, and UDP port. //- Use the given source IPv4 address and UDP port as the source. //- //- Note: Caller is responsible for ensuring that the provided destination IPv4 address is valid for the station with the provided ethernet address. //- method{:dafnycc_conservative_seq_triggers} UdpSend(state:network_state, EtherDest:ethernet_addr, IPSource:IPv4Address, IPDest:IPv4Address, SourcePort:int, DestPort:int, Data:seq) returns (new_state:network_state) requires valid_network_state(state); requires ValidIPv4Address(IPSource); requires ValidIPv4Address(IPDest); requires valid_ethernet_addr(EtherDest); requires Word16(SourcePort); requires Word16(DestPort); requires |Data| <= 1472; requires IsByteSeq(Data); requires public(state); requires public(EtherDest); requires public(IPSource); requires public(IPDest); requires public(SourcePort); requires public(DestPort); requires public(Data); ensures valid_network_state(new_state); ensures public(new_state); { lemma_2toX(); var Length := 8 + |Data|; var PseudoHeader := IPSource.bytes + IPDest.bytes + [0] + [17] + Serialize16(Length); var Checksum := 0; var UdpHeader:seq := Serialize16(SourcePort) + Serialize16(DestPort) + Serialize16(Length) + Serialize16(Checksum); Checksum := InternetChecksum(PseudoHeader + UdpHeader + Data); if (Checksum == 0) { Checksum := 0xffff; } UdpHeader := Serialize16(SourcePort) + Serialize16(DestPort) + Serialize16(Length) + Serialize16(Checksum); new_state := IPv4Send(state, EtherDest, IPSource, IPDest, 17, UdpHeader, Data); } method{:dafnycc_conservative_seq_triggers} UdpReceive(state:network_state) returns (Success:bool, new_state:network_state, EtherSource:ethernet_addr, IPSource:IPv4Address, IPDest:IPv4Address, SourcePort:int, DestPort:int, Data:seq) requires valid_network_state(state); requires public(state); ensures valid_network_state(new_state); ensures Success ==> valid_ethernet_addr(EtherSource); ensures Success ==> ValidIPv4Address(IPSource); ensures Success ==> ValidIPv4Address(IPDest); ensures Success ==> Word16(SourcePort); ensures Success ==> Word16(DestPort); ensures Success ==> IsByteSeq(Data); ensures Success ==> |Data| <= 1472; ensures public(Success); ensures public(new_state); ensures public(EtherSource); ensures public(IPSource); ensures public(IPDest); ensures public(SourcePort); ensures public(DestPort); ensures public(Data); { lemma_2toX(); var Protocol:int; SourcePort := 0; DestPort := 0; Success, new_state, EtherSource, IPSource, IPDest, Protocol, Data := IPv4Receive(state); if (Success) { if (Protocol != 17) { //- Not a UDP packet. Success := false; } else if (|Data| < 8 ) { //- Received data is too short to contain a UDP header. Success := false; } else { var Length:int := Deserialize16(Data[4..6]); if (Length < 8) { //- Length field is bogus (too small to include UDP header). Success := false; } else if (Length > |Data|) { //- Not enough data to hold packet described by IPv4 header. Success := false; } else { var PseudoHeader := IPSource.bytes + IPDest.bytes + [0] + [17] + Serialize16(Length); var Checksum:int := InternetChecksum(PseudoHeader + Data); if (Checksum != 0) { //- Checksum failed, packet corrupted. Success := false; } else { SourcePort := Deserialize16(Data[0..2]); DestPort := Deserialize16(Data[2..4]); //- //- Everything looks good. //- Strip off the UDP header and trim to Length. //- Data := Data[8..Length]; } } } } } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Net/ethernet.i.dfy ================================================ //- include "../Util/integer_sequences.i.dfy" include "../../Drivers/Network/Intel/driver.i.dfy" //- //- Ethernet-level interface to the network. //- //- //- Send the given Headers and Data to the given ethernet destination address. //- method EtherSend(state:network_state, EtherDest:ethernet_addr, Headers:seq, Data:seq) returns (new_state:network_state) requires valid_network_state(state); requires valid_ethernet_addr(EtherDest); requires IsByteSeq(Headers); requires IsByteSeq(Data); requires |Headers| + |Data| <= 1500; requires public(state); requires public(EtherDest); requires public(Headers); requires public(Data); ensures valid_network_state(new_state); ensures public(new_state); { lemma_2toX(); //- //- Create an Ethernet header to prepend to the caller's headers and data. //- var EtherSource := my_ethernet_addr(); var EtherType := [0x08, 0x00]; //- Fix the type to be IPv4 var EtherHeader := EtherDest.bytes + EtherSource.bytes + EtherType; assert |EtherHeader| == 14; //- assert Data == old(Data); //- assert app_approves_disclosure(left(UserData), right(UserData), 1500); new_state := NetIfSend(state, EtherHeader + Headers, Data); } method EtherReceive(state:network_state) returns (Success:bool, new_state:network_state, EtherSource:ethernet_addr, EtherType:seq, Data:seq) //- requires net_init; requires valid_network_state(state); requires public(state); ensures valid_network_state(new_state); ensures Success ==> valid_ethernet_addr(EtherSource); ensures Success ==> IsByteSeq(EtherType); ensures Success ==> |EtherType| == 2; ensures Success ==> IsByteSeq(Data); ensures Success ==> 46 <= |Data| <= 1500; ensures public(Success); ensures public(new_state); ensures public(EtherSource); ensures public(EtherType); ensures public(Data); { lemma_2toX(); EtherSource := ethernet_addr_builder([]); // TODO: dafnycc: had to add this line because dafnycc doesn't handle returning uninitialized variables. EtherType := [0x00, 0x00]; Success, new_state, Data := NetIfReceive(state); if (Success) { if (|Data| < 60) { //- //- Too short for an Ethernet packet. //- Success := false; //-debug_print(0x90, 0xdead2001); } else { // // var EtherDest := ethernet_addr_builder(Data[0..6]); assert valid_ethernet_addr(EtherDest); EtherSource := ethernet_addr_builder(Data[6..12]); assert valid_ethernet_addr(EtherSource); EtherType := Data[12..14]; //- //- Remove the Ethernet Header and trim the data length to a maximum of 1500 bytes. //- var Length := |Data| - 14; if (Length > 1500) { Length := 1500; } Data := Data[14..14 + Length]; } } else { //-debug_print(0x90, 0xdead2000); } } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Util/.gitignore ================================================ *.bpl *.log ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Util/DebugPrint.i.dfy ================================================ include "../../Drivers/IO/pci.i.dfy" include "../../Drivers/CPU/assembly.i.dfy" include "seqs_and_ints.i.dfy" static method debug_print_seq(marker:int, seqn:seq) requires 0<=marker<256; requires IsByteSeq(seqn); { var i := 0; var shifted_marker := marker * 256 * 256; debug_print(0x90, 0x41000000 + shifted_marker); while (i < |seqn|) invariant 0 <= i <= |seqn|; { debug_print(0x90, 0x48000000 + shifted_marker + seqn[i]); i := i + 1; } debug_print(0x90, 0x4f000000 + shifted_marker); } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Util/Halter.i.dfy ================================================ include "../../Libraries/Math/power2.i.dfy" include "DebugPrint.i.dfy" //-include "../../Libraries/Net/Udp.i.dfy" method HaltMachine(error_code:int) requires 0 <= error_code < 0x10000; ensures false; { lemma_2toX(); debug_print(0, 0x44440000 + error_code); while true decreases *; { } } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Util/ProfileIfc.i.dfy ================================================ static function method Tally_TestDigits() : int { 1 } static function method Tally_BigNatSub() : int { 2 } static function method Tally_BigNatModExpCalls() : int { 3 } static function method Tally_BigNatModExpWhileLoops() : int { 4 } static function method Tally_BigNatDivCalls() : int { 5 } static function method Tally_BigNatDivWhileLoops() : int { 6 } static function method Tally_FatNatModExp() : int { 7 } static function method Tally_FatNatMul() : int { 8 } static function method Tally_FatNatMod() : int { 9 } static function method Tally_MillerRabinTest() : int { 10 } //- Mark these 'ghost' unless profiling to avoid creating runtime code //- in real build. static ghost method ResetTally() {} static ghost method ProfileTally(category:int, value:int) {} static ghost method DisplayTally() {} ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Util/arrays.i.dfy ================================================ include "bytes_and_words.s.dfy" static method ArrayCpy(dst:array, dst_offset:nat, src:array, src_offset:nat, count:nat) requires dst != null; requires src != null; requires dst_offset+count <= dst.Length; requires src_offset+count <= src.Length; requires src != dst; modifies dst; ensures dst[..dst_offset] == old(dst)[..dst_offset]; ensures dst[dst_offset+count..] == old(dst)[dst_offset+count..]; ensures dst[dst_offset..dst_offset+count] == src[src_offset..src_offset+count]; { var i := 0; while (i < count) invariant 0 <= i <= count; invariant dst[..dst_offset] == old(dst)[..dst_offset]; invariant dst[dst_offset+count..] == old(dst)[dst_offset+count..]; invariant dst[dst_offset..dst_offset+i] == src[src_offset..src_offset+i]; { ghost var old_src := src[..]; ghost var old_dst := dst[..]; ghost var old_i := i; assert old_dst[dst_offset..dst_offset+old_i] == old_src[src_offset..src_offset+old_i]; assert src[..]==old_src; dst[dst_offset+i] := src[src_offset+i]; i := i + 1; assert src[..]==old_src; assert old_dst[dst_offset..dst_offset+old_i] == old_src[src_offset..src_offset+old_i]; forall (k | 0<=k, dst_offset:nat, count:nat, value:int) requires dst != null; requires dst_offset+count <= dst.Length; modifies dst; ensures forall i :: 0<=i dst[i]==old(dst[..])[i]; ensures forall i :: dst_offset+count<=i dst[i]==old(dst[..])[i]; ensures forall i :: dst_offset<=i dst[i]==value; { var j := 0; while (j < count) invariant 0 <= j <= count; invariant forall i :: 0<=i dst[i]==old(dst[..])[i]; invariant forall i :: dst_offset+count<=i dst[i]==old(dst[..])[i]; invariant forall i :: dst_offset<=i dst[i]==value; { dst[dst_offset+j] := value; j := j + 1; } } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Util/arrays_2.i.dfy ================================================ include "../../Drivers/CPU/assembly_premium.i.dfy" include "../Math/BitwiseOperations.i.dfy" static lemma lemma_SelectBit_is_IntBit_spec(b:nat, x:nat) requires b<32; requires x=32) { lemma_power2_increases(32,i); lemma_SelectBit_overflow(i, x); } } lemma_BitwiseAnd_equivalence(x,y,z); } static lemma lemma_Asm_BitwiseAnd(x:int, c:nat) requires Word32(x); requires 0) requires Word32(w); requires bs == [ w / 16777216, (w / 65536) % 256, (w / 256) % 256, w % 256 ]; ensures IsByteSeq(bs); ensures BEWordSeqToByteSeq([w])==bs; { lemma_2toX(); calc { w; { lemma_fundamental_div_mod(w, 256); lemma_mul_is_commutative_forall(); } mul(div(w,256),256) + mod(w, 256); { lemma_fundamental_div_mod(div(w,256), 256); lemma_mul_is_commutative_forall(); } mul(mul(div(div(w,256),256),256) + mod(div(w,256),256),256) + mod(w, 256); { lemma_div_denominator_forall(); } mul(mul(div(w,mul(256,256)),256) + mod(div(w,256),256),256) + mod(w, 256); { lemma_mul_is_mul_boogie(256, 256); } mul(mul(div(w,65536),256) + mod(div(w,256),256),256) + mod(w, 256); { lemma_fundamental_div_mod(div(w,65536), 256); lemma_mul_is_commutative_forall(); } mul(mul(mul(div(div(w,65536),256),256) + mod(div(w,65536),256),256) + mod(div(w,256),256),256) + mod(w, 256); { lemma_div_denominator_forall(); } mul(mul(mul(div(w,mul(65536,256)),256) + mod(div(w,65536),256),256) + mod(div(w,256),256),256) + mod(w, 256); { lemma_mul_is_mul_boogie(65536, 256); } mul(mul(mul(div(w,16777216),256) + mod(div(w,65536),256),256) + mod(div(w,256),256),256) + mod(w, 256); mul(mul(mul(div(w,16777216),power2(8)) + mod(div(w,65536),256),power2(8)) + mod(div(w,256),256),power2(8)) + mod(w, 256); mul(mul(mul(w/16777216,power2(8)) + mod(w/65536,256),power2(8)) + mod(w/256,256),power2(8)) + mod(w, 256); mul(mul(mul(w/16777216,power2(8)) + (w/65536)%256,power2(8)) + (w/256)%256,power2(8)) + w%256; } reveal_BEDigitSeqToInt_private(); lemma_mul_basics_forall(); var ws := [w]; calc { BEByteSeqToInt(bs); { lemma_BEByteSeqToInt_unpack_four(bs, []); } BEByteSeqToInt([])*power2(32) + (((bs[|bs|-4])*power2(8) + bs[|bs|-3])*power2(8) + bs[|bs|-2])*power2(8) + bs[|bs|-1]; (((bs[0])*power2(8) + bs[1])*power2(8) + bs[2])*power2(8) + bs[3]; mul(mul(mul(bs[0],power2(8)) + bs[1],power2(8)) + bs[2],power2(8)) + bs[3]; mul(mul(mul(w/16777216,power2(8)) + (w/65536)%256,power2(8)) + (w/256)%256,power2(8)) + w%256; w; BEDigitSeqToInt(power2(32), ws[0..0])*power2(32) + ws[0]; BEWordSeqToInt(ws); } lemma_BEDigitSeqToInt_bound(power2(8), bs); lemma_BEDigitSeqToInt_invertibility(power2(8), BEByteSeqToInt(bs), bs); } static lemma lemma_WordToByte_concatenation(ws:seq, prefix_words:seq, suffix_words:seq, bs:seq, prefix_bytes:seq, suffix_bytes:seq) requires IsWordSeq(ws); requires IsWordSeq(prefix_words); requires IsWordSeq(suffix_words); requires ws == prefix_words + suffix_words; requires IsByteSeq(bs); requires IsByteSeq(prefix_bytes); requires IsByteSeq(suffix_bytes); requires bs == prefix_bytes + suffix_bytes; requires |suffix_words| == 1; requires |suffix_bytes| == 4; requires BEByteSeqToInt(prefix_bytes) == BEWordSeqToInt(prefix_words); requires BEByteSeqToInt(suffix_bytes) == BEWordSeqToInt(suffix_words); ensures BEByteSeqToInt(bs) == BEWordSeqToInt(ws); { reveal_BEDigitSeqToInt_private(); lemma_2toX(); lemma_mul_basics_forall(); calc { BEByteSeqToInt(bs); { lemma_BEByteSeqToInt_strip_four(bs, prefix_bytes, suffix_bytes); } BEByteSeqToInt(prefix_bytes) * power2(32) + BEByteSeqToInt(suffix_bytes); BEWordSeqToInt(prefix_words) * power2(32) + BEWordSeqToInt(suffix_words); BEWordSeqToInt(prefix_words) * power2(32) + (BEDigitSeqToInt(power2(32), suffix_words[0..0])*power2(32) + suffix_words[0]); BEWordSeqToInt(prefix_words) * power2(32) + (BEDigitSeqToInt(power2(32), [])*power2(32) + suffix_words[0]); BEWordSeqToInt(prefix_words) * power2(32) + (mul(0,power2(32)) + suffix_words[0]); BEWordSeqToInt(prefix_words) * power2(32) + suffix_words[0]; { assert suffix_words[0] == ws[|ws|-1]; } BEWordSeqToInt(prefix_words) * power2(32) + ws[|ws|-1]; { assert prefix_words == ws[0..|ws|-1]; } BEDigitSeqToInt(power2(32), ws[0..|ws|-1])*power2(32) + ws[|ws|-1]; BEWordSeqToInt(ws); } } static lemma lemma_divide_power2_24(w:int) requires Word32(w); ensures w/power2(24) < 256; { lemma_2toX(); calc { w/power2(24); div(w,16777216); { lemma_div_is_div_boogie(w, 16777216); } w/16777216; < 256; } } static lemma lemma_Asm_Div_premiumer(x:int, d:int, q:int) requires Word32(x); requires Word32(d); requires 0, ba:array) requires wa!=null; requires ba!=null; requires wa!=ba; requires ba.Length == wa.Length*4; requires IsWordSeq(wa[..]); modifies ba; ensures IsByteSeq(ba[..]); ensures BEWordSeqToByteSeq(wa[..])==ba[..]; { lemma_2toX32(); var i:=0; var j:=0; //- calc { //- BEWordSeqToByteSeq_premium(wa[..i]); //- BEWordSeqToByteSeq([]); //- { reveal_BEDigitSeqToInt_private(); } //- ba[..j]; //- } while (i 0<=bs[k]<256; assert forall k :: 0<=k ba[k]==bs[k]; assert forall k :: 0<=k 0<=ba[k]<256; ghost var bss := ba[j..j+4]; lemma_div_is_div_boogie(wa[i], 16777216); lemma_div_is_div_boogie(wa[i], 65536); lemma_mod_is_mod_boogie(wa[i]/65536, 256); lemma_div_is_div_boogie(wa[i], 256); lemma_mod_is_mod_boogie(wa[i]/256, 256); lemma_mod_is_mod_boogie(wa[i], 256); lemma_WordToByte_properties(wa[i], ba[j..j+4]); ghost var wss := [wa[i]]; lemma_BEWordSeqToInt_BEIntToByteSeq(bs, ws); calc { BEByteSeqToInt(bs[..j]); { assert bs[..j] == bs; } BEByteSeqToInt(bs); //- BEByteSeqToInt(ba[..j]); //- BEByteSeqToInt(bs); BEWordSeqToInt(ws); BEWordSeqToInt(wa[..i]); } lemma_BEWordSeqToInt_BEIntToByteSeq(bss, wss); calc { BEByteSeqToInt(bss); { lemma_BEIntToByteSeq_BEWordSeqToInt(bss, wss); } BEWordSeqToInt(wss); } assert BEByteSeqToInt(bss) == BEWordSeqToInt(wss); //- OBSERVE lemma_WordToByte_concatenation(wa[..i+1], wa[..i], wss, ba[..j+4], bs[..j], bss); lemma_BEIntToByteSeq_BEWordSeqToInt(ba[..j+4], wa[..i+1]); i:=i+1; j:=j+4; } assert ba[..j] == ba[..]; assert wa[..i] == wa[..]; assert IsByteSeq(ba[..j]); assert BEWordSeqToByteSeq(wa[..i])==ba[..j]; } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Util/arrays_and_seqs.i.dfy ================================================ include "be_sequences.s.dfy" include "seqs_and_ints.i.dfy" include "integer_sequences_premium.i.dfy" include "word_bits.i.dfy" include "seqs_transforms.i.dfy" include "../Math/div.i.dfy" include "../Math/power2.i.dfy" include "../Math/power.i.dfy" include "../base.s.dfy" //-include "../assembly.s.dfy" static predicate IsWordArray(a: array) reads a; { a != null && forall i :: 0 <= i < a.Length ==> Word32(a[i]) } static function {:opaque} GetArrayBit(a: array, b:int) : int requires IsWordArray(a); requires 0 <= b < a.Length * 32; ensures IsBit(GetArrayBit(a, b)); ensures GetArrayBit(a, b) == BEWordSeqToBitSeq_premium(a[..])[b]; reads a; { calc { BEWordSeqToBitSeq_premium(a[..])[b]; BEIntToDigitSeq(power2(1), |a[..]|*32, BEDigitSeqToInt(power2(32), a[..]))[b]; { lemma_power2_1_is_2(); } BEIntToDigitSeq(2, |a[..]|*32, BEDigitSeqToInt(power2(32), a[..]))[b]; { lemma_BEIntToWordSeq_decomposition(a[..], b); } BEIntToDigitSeq(2, 32, a[..][b/32])[b%32]; BEIntToDigitSeq(2, 32, a[b/32])[b%32]; { lemma_power2_1_is_2(); } BEWordToBitSeq(a[b/32])[b%32]; GetWordBit(a[b / 32], b % 32); } GetWordBit(a[b / 32], b % 32) } //-///////////////////// //- Updating arrays //-///////////////////// static method UpdateBitOfArray(a: array, pos: int, value: int) requires IsWordArray(a); requires 0 <= pos < a.Length * 32; requires IsBit(value); ensures IsWordArray(a); ensures GetArrayBit(a, pos) == value; ensures forall i {:trigger GetArrayBit(a, i)}{:trigger old(GetArrayBit(a, i))} :: 0 <= i < a.Length * 32 && i != pos ==> GetArrayBit(a, i) == old(GetArrayBit(a, i)); modifies a; { reveal_GetArrayBit(); a[pos / 32] := UpdateBitOfWord(a[pos / 32], pos % 32, value); calc { GetArrayBit(a, pos); { reveal_GetArrayBit(); } GetWordBit(a[pos / 32], pos % 32); value; } forall i | 0 <= i < a.Length * 32 && i != pos ensures GetArrayBit(a, i) == old(GetArrayBit(a, i)); { if (i / 32 != pos / 32) { reveal_GetArrayBit(); } else { calc { GetArrayBit(a, i); { reveal_GetArrayBit(); } GetWordBit(a[pos / 32], i % 32); { lemma_fundamental_div_mod(i, 32); lemma_fundamental_div_mod(pos, 32); assert i % 32 != pos % 32; } GetWordBit(old(a[i / 32]), i % 32); old(GetArrayBit(a, i)); } assert GetArrayBit(a, i) == old(GetArrayBit(a, i)); } } } static method AppendBitToArray(a: array, b: int, value: int) requires IsWordArray(a); requires 0 <= b < a.Length * 32; requires IsBit(value); ensures IsWordArray(a); ensures forall i {:trigger GetArrayBit(a, i)}{:trigger old(GetArrayBit(a, i))} :: 0 <= i < b ==> GetArrayBit(a, i) == old(GetArrayBit(a, i)); ensures GetArrayBit(a, b) == value; modifies a; { UpdateBitOfArray(a, b, value); } static method AppendWordToArray(a: array, b: int, value: int) requires IsWordArray(a); requires 0 <= b; requires b % 32 == 0; requires b + 32 <= a.Length * 32; requires Word32(value); ensures IsWordArray(a); ensures forall i {:trigger GetArrayBit(a, i)}{:trigger old(GetArrayBit(a, i))} :: 0 <= i < b ==> GetArrayBit(a, i) == old(GetArrayBit(a, i)); ensures forall i {:trigger a[i]}:: 0 <= i * 32 < b ==> a[i] == old(a[i]); ensures a[b / 32] == value; modifies a; { reveal_GetArrayBit(); a[b / 32] := value; reveal_GetArrayBit(); } static method AppendBitsToArray(a: array, b: int, value: int, num_values: int) requires IsWordArray(a); requires 0 <= b; requires 0 <= num_values; requires b + num_values <= a.Length * 32; requires IsBit(value); ensures IsWordArray(a); ensures forall i {:trigger GetArrayBit(a, i)}{:trigger old(GetArrayBit(a, i))} :: 0 <= i < b ==> GetArrayBit(a, i) == old(GetArrayBit(a, i)); ensures forall i {:trigger GetArrayBit(a, i)} :: b <= i < b + num_values ==> GetArrayBit(a, i) == value; modifies a; { var j := 0; while (j < num_values) invariant 0 <= b <= b + j <= b + num_values <= a.Length * 32; invariant forall i :: 0 <= i < a.Length ==> Word32(a[i]); invariant forall i :: 0 <= i < b ==> GetArrayBit(a, i) == old(GetArrayBit(a, i)); invariant forall i :: b <= i < b + j ==> GetArrayBit(a, i) == value; { var old_j := j; if (value == 0 && (b + j) % 32 == 0 && j + 32 <= num_values) { lemma_2toX(); AppendWordToArray(a, b + j, 0); j := j + 32; forall (i | b + old_j <= i < b + j) ensures GetArrayBit(a, i) == 0; { assert i/32 == (b + old_j) / 32; assert (b + old_j) % 32 == 0; var k := i - (b+old_j); assert k < 32; assert i == k + (b+old_j); assert i/32 == (k + (b+old_j))/32 == (b+old_j)/32; assert a[i/32] == a[(b+old_j)/ 32] == 0; assert k == i % 32; calc { GetArrayBit(a, i); { reveal_GetArrayBit(); } GetWordBit(a[i / 32], i % 32); GetWordBit(0, i % 32); GetWordBit(0, k); { reveal_power2(); lemma_BEIntToDigitSeq_private_zero(power2(1), 32); } 0; } } } else { AppendBitToArray(a, b + j, value); j := j + 1; forall (i | b <= i < b + j) ensures GetArrayBit(a, i) == value; { if (i == b + old_j) { } } } reveal_GetArrayBit(); } } static lemma lemma_array_seq_equality(a:array, b:array, a_start:int, a_end:int, b_start:int, b_end:int) requires a != null && b != null; requires b_end - b_start == a_end - a_start; requires 0 <= a_start < a_end <= a.Length; requires 0 <= b_start < b_end <= b.Length; requires forall i :: 0 <= i < a_end - a_start ==> a[a_start + i] == b[b_start + i]; ensures a[a_start..a_end] == b[b_start..b_end]; { ghost var A := a[a_start..a_end]; ghost var B := b[b_start..b_end]; assert |A| == |B|; forall i | 0 <= i < |A| ensures 0 <= i < |A| ==> A[i] == B[i]; { calc { A[i]; a[a_start..a_end][i]; a[a_start + i]; { assert forall j :: 0 <= j < a_end - a_start ==> a[a_start + j] == b[b_start + j]; } //-{ assert 0 <= i < a_end - a_start; } b[b_start + i]; b[b_start..b_end][i]; B[i]; } assert A[i] == B[i]; //-assert a[a_start..a_end][i] == b[b_start..b_end][i]; } assert A == B; assert a[a_start..a_end] == b[b_start..b_end]; } method SeqToArray(s:seq) returns (a:array) ensures fresh(a); ensures a != null; ensures a.Length == |s|; ensures forall i :: 0 <= i < |s| ==> s[i] == a[i]; ensures a[..] == s; ensures fresh(a); { a := new int[|s|]; var i := 0; while i < |s| invariant 0 <= i <= |s|; invariant forall j :: 0 <= j < i ==> s[j] == a[j]; { a[i] := s[i]; i := i + 1; } } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Util/be_sequences.s.dfy ================================================ include "../Math/power2.s.dfy" include "bytes_and_words.s.dfy" //-//////////////////////////////////////////////////////////////////////////// //- Sequence types //-//////////////////////////////////////////////////////////////////////////// static predicate IsDigitSeq(place_value:int, digits:seq) { forall i {:trigger digits[i]} :: 0<=i<|digits| ==> 0 <= digits[i] < place_value } static predicate IsBitSeq(bs:seq) { IsDigitSeq(power2(1), bs) } static predicate IsByteSeq(os:seq) { IsDigitSeq(power2(8), os) } static predicate IsWordSeq(ws:seq) { IsDigitSeq(power2(32), ws) } static predicate IsBitSeqOfLen(os:seq, len:int) { IsBitSeq(os) && |os| == len } static predicate IsByteSeqOfLen(os:seq, len:int) { IsByteSeq(os) && |os| == len } static predicate IsWordSeqOfLen(os:seq, len:int) { IsWordSeq(os) && |os| == len } //-//////////////////////////////////////////////////////////////////////////// //- Relationships among sequences of different digit sizes //- (bit, byte, word, and ghost int) //-//////////////////////////////////////////////////////////////////////////// //- BE/LE refers to the endianness of the transformation. There's no //- inherent endianness in a sequence until it's interpreted. static function {:opaque} BEDigitSeqToInt_private(place_value:int, digits:seq) : int decreases |digits|; { if (digits==[]) then 0 else BEDigitSeqToInt_private(place_value, digits[0..|digits|-1])*place_value + digits[|digits|-1] } static function BEDigitSeqToInt(place_value:int, digits:seq) : int requires IsDigitSeq(place_value, digits); { BEDigitSeqToInt_private(place_value, digits) } static function {:autoReq}BEBitSeqToInt(bits:seq) : int { BEDigitSeqToInt(power2(1), bits) } static function {:autoReq} BEByteSeqToInt(bytes:seq) : int { BEDigitSeqToInt(power2(8), bytes) } static function {:autoReq} BEWordSeqToInt(words:seq) : int { BEDigitSeqToInt(power2(32), words) } static function {:opaque} BEIntToDigitSeq_private(place_value:int, min_places:int, v:int) : seq decreases if v>min_places then v else min_places; { if (1 n/d < n; ensures n<=0 ==> n/d <= 0; static function BEIntToDigitSeq(place_value:int, min_places:int, v:int) : seq { BEIntToDigitSeq_private(place_value, min_places, v) } //-//////////////////////////////////////////////////////////////////////////// static predicate BEDigitSeqEqInt(place_value:int, digits:seq, v:int) { IsDigitSeq(place_value, digits) && BEDigitSeqToInt(place_value, digits)==v } static predicate BEBitSeqEqInt(bitseq:seq, v:int) { BEDigitSeqEqInt(2, bitseq, v) } static predicate BEBitSeqEqByte(bitseq:seq, byte:int) { IsByte(byte) && BEBitSeqEqInt(bitseq, byte) } static predicate BEBitSeqEqWord(bitseq:seq, word:int) { IsWord(word) && BEBitSeqEqInt(bitseq, word) } static predicate BEByteSeqEqInt(byteseq:seq, v:int) { BEDigitSeqEqInt(256, byteseq, v) } static predicate BEByteSeqEqWord(byteseq:seq, word:int) { IsWord(word) && BEByteSeqEqInt(byteseq, word) } static predicate BEWordSeqEqInt(byteseq:seq, v:int) { BEDigitSeqEqInt(power2(32), byteseq, v) } static predicate BEBitSeqEqByteSeq(bitseq:seq, byteseq:seq) { exists v:int :: BEBitSeqEqInt(bitseq, v) && BEByteSeqEqInt(byteseq, v) } static predicate BEBitSeqEqWordSeq(bitseq:seq, wordseq:seq) { exists v:int :: BEBitSeqEqInt(bitseq, v) && BEWordSeqEqInt(wordseq, v) } static predicate BEByteSeqEqWordSeq(byteseq:seq, wordseq:seq) { exists v:int :: BEByteSeqEqInt(byteseq, v) && BEWordSeqEqInt(wordseq, v) } //-//////////////////////////////////////////////////////////////////////////// //- Generator functions (as opposed to recognizer predicates) //-//////////////////////////////////////////////////////////////////////////// // static function BEIntToByteSeq(x: int) : seq { BEIntToDigitSeq(power2(8), 0, x) } static function BEWordToFourBytes(x: int) : seq requires Word32(x); { BEIntToDigitSeq(power2(8), 4, x) } static function BEWordToBitSeq(x:int) : seq { BEIntToDigitSeq(power2(1), 32, x) } static function {:autoReq} BEWordSeqToBitSeq(wordseq:seq) : seq { BEIntToDigitSeq(power2(1), |wordseq|*32, BEDigitSeqToInt(power2(32), wordseq)) } static function {:autoReq} BEByteSeqToBitSeq(byteseq:seq) : seq { BEIntToDigitSeq(power2(1), |byteseq|*8, BEDigitSeqToInt(power2(8), byteseq)) } static function {:autoReq} BEWordSeqToByteSeq(wordseq:seq) : seq { BEIntToDigitSeq(power2(8), |wordseq|*4, BEDigitSeqToInt(power2(32), wordseq)) } static function RepeatDigit(digit:int, count:int) : seq decreases count; { if (count<=0) then [] else RepeatDigit(digit, count-1) + [digit] } static function {:opaque} Reverse(os:seq) : seq decreases |os|; { if (os==[]) then [] else [os[|os|-1]] + Reverse(os[0..|os|-1]) } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Util/beseqs_simple.i.dfy ================================================ include "be_sequences.s.dfy" static lemma lemma_selection_preserves_digit_seq(pv:int, a:seq, i:int) requires IsDigitSeq(pv, a); requires 0 <= i <= |a|; ensures IsDigitSeq(pv, a[i..]); ensures IsDigitSeq(pv, a[..i]); { } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Util/bytes_and_words.s.dfy ================================================ include "../Math/power2.s.dfy" static predicate IsBit(b:int) { 0 <= b < 2 } static predicate IsByte(b:int) { 0 <= b < 256 } // // static predicate Word16(x:int) { 0 <= x < 0x10000 } static predicate Word32(x: int) { 0 <= x < power2(32) } // // static predicate IsWord(w: int) { Word32(w) } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Util/insecure_prng.i.dfy ================================================ include "../../Drivers/CPU/assembly_premium.i.dfy" include "../Math/bit_vector_lemmas_premium.i.dfy" //- Implements an Xorshift random number generator based on the example from: //- http://en.wikipedia.org/wiki/Xorshift method update_state(w:int, x:int, y:int, z:int) returns (w':int, x':int, y':int, z':int) requires Word32(w) && Word32(x) && Word32(y) && Word32(z); ensures Word32(w') && Word32(x') && Word32(y') && Word32(z'); { lemma_2toX(); var t := Asm_BitwiseXor(x, Asm_LeftShift(x, 11)); x' := y; y' := z; z' := w; w' := Asm_BitwiseXor(w, Asm_BitwiseXor(Asm_RightShift(w, 19), Asm_BitwiseXor(t, Asm_RightShift(t, 8)))); } method insecure_get_random(num_bytes:int) returns (random_bytes:seq) requires Word32(num_bytes); ensures IsByteSeqOfLen(random_bytes, num_bytes); { //- Use rdtsc as a seed var x, y := Asm_Rdtsc(); var w := 5331; var z := 4229; lemma_2toX(); //- Iterate the PRNG a few times to absorb the rdtsc 'randomness' var i := 0; while (i < 100) invariant Word32(w) && Word32(x) && Word32(y) && Word32(z); { w, x, y, z := update_state(w, x, y, z); i := i + 1; } //- Generate the actual 'random' bytes requested var bytes := []; i := 0; while (i < num_bytes) invariant 0 <= i <= num_bytes; invariant IsByteSeqOfLen(bytes, i); invariant Word32(w) && Word32(x) && Word32(y) && Word32(z); { w, x, y, z := update_state(w, x, y, z); var rand_byte := Asm_BitwiseAnd(w, 0xFF); lemma_and_with_ff_premium(); //- Grab the lowest byte for our collection bytes := [rand_byte] + bytes; i := i + 1; } random_bytes := bytes; } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Util/integer_sequences.i.dfy ================================================ include "integer_sequences.s.dfy" include "seqs_simple.i.dfy" include "seqs_and_ints.i.dfy" include "seqs_transforms.i.dfy" include "seqs_reverse.i.dfy" ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Util/integer_sequences.s.dfy ================================================ include "be_sequences.s.dfy" ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Util/integer_sequences_premium.i.dfy ================================================ include "../Math/power.i.dfy" include "integer_sequences.i.dfy" //- "Premium" versions of {:autoReq} spec functions, which include //- explicit requires and appropriate ensures for composition with //- other functions. static function BEDigitSeqToInt_premium(place_value:int, digits:seq) : int requires 1) : int requires IsBitSeq(bits); { BEBitSeqToInt(bits) } static function BEByteSeqToInt_premium(bytes:seq) : int requires IsByteSeq(bytes); { BEByteSeqToInt(bytes) } static function BEWordSeqToInt_premium(words:seq) : int requires IsWordSeq(words); ensures 0<=BEWordSeqToInt(words); { lemma_BEDigitSeqToInt_bound(power2(32), words); BEWordSeqToInt(words) } static lemma lemma_BEIntToDigitSeq_IsDigitSeq(place_value:int, min_places:int, v:int) requires 1min_places then v else min_places; //- decreases if (v>0) then v else 0,min_places; { var sq := BEIntToDigitSeq(place_value, min_places, v); reveal_BEIntToDigitSeq_private(); if (00) { lemma_div_decreases(v, place_value); lemma_div_pos_is_pos(v, place_value); } else { lemma_small_div(); } lemma_BEIntToDigitSeq_IsDigitSeq(place_value, min_places-1, v/place_value); lemma_mod_properties(); } else { assert |sq|==0; } } static function BEIntToDigitSeq_premium(place_value:int, min_places:int, v:int) : seq requires 1 |BEIntToDigitSeq(place_value, min_places, v)| == min_places; { lemma_BEIntToDigitSeq_IsDigitSeq(place_value, min_places, v); lemma_BEIntToDigitSeq_properties(place_value, min_places, v); BEIntToDigitSeq(place_value, min_places, v) } //-//////////////////////////////////////////////////////////////////////////// //- Generator functions (as opposed to recognizer predicates) //-//////////////////////////////////////////////////////////////////////////// static function BEIntToByteSeq_premium(x: int) : seq requires 0 <= x; ensures IsByteSeq(BEIntToByteSeq(x)); ensures BEByteSeqToInt(BEIntToByteSeq(x)) == x; { reveal_power2(); lemma_BEInt_decoding_general(power2(8), 0, x); BEIntToByteSeq(x) } //- Lost static tag because lemmas in seqs_transforms aren't static. static function BEWordToFourBytes_premium(x: int) : seq requires Word32(x); ensures IsByteSeq(BEWordToFourBytes(x)); { reveal_power2(); calc { x; < power2(32); { lemma_power2_is_power_2(32); } power(2, 8*4); { lemma_mul_is_mul_boogie(8,4); lemma_power_multiplies(2,8,4); } power(power(2,8), 4); { lemma_power2_is_power_2(8); } power(power2(8), 4); } lemma_BEIntToDigitSeqProducesRightSizedDigits(power2(8), 4, x); BEWordToFourBytes(x) } static function BEWordToBitSeq_premium(x:int) : seq requires Word32(x); ensures IsBitSeq(BEWordToBitSeq(x)); ensures |BEWordToBitSeq(x)| == 32; ensures forall i :: 0 <= i < 32 ==> IsBit(BEWordToBitSeq(x)[i]); ensures BEBitSeqToInt(BEWordToBitSeq(x)) == x; { reveal_power2(); lemma_power2_is_power_2(1); calc { x; < power2(32); { lemma_power2_is_power_2(32); } power(2, 32); power(power2(1), 32); } lemma_BEIntToDigitSeqProducesRightSizedDigits(power2(1), 32, x); lemma_BEIntToDigitSeq_private_properties(power2(1), 32, x); lemma_BEIntToBitSeq_decoding(x); BEWordToBitSeq(x) } static function BEWordSeqToBitSeq_premium(wordseq:seq) : seq requires IsWordSeq(wordseq); ensures IsBitSeq(BEWordSeqToBitSeq(wordseq)); ensures |BEWordSeqToBitSeq(wordseq)| == |wordseq|*32; { lemma_BEWordSeqToBitSeq_ensures(wordseq); BEWordSeqToBitSeq(wordseq) } static function BEByteSeqToBitSeq_premium(byteseq:seq) : seq requires IsByteSeq(byteseq); ensures IsBitSeq(BEByteSeqToBitSeq(byteseq)); ensures |BEByteSeqToBitSeq(byteseq)| == |byteseq|*8; //- ensures BEBitSeqToInt(BEByteSeqToBitSeq(byteseq)) == BEByteSeqToInt(byteseq); { lemma_BEByteSeqToBitSeq_ensures(byteseq); BEByteSeqToBitSeq(byteseq) } static function BEWordSeqToByteSeq_premium(wordseq:seq) : seq requires IsWordSeq(wordseq); ensures IsByteSeq(BEWordSeqToByteSeq(wordseq)); ensures |BEWordSeqToByteSeq(wordseq)| == |wordseq|*4; //- ensures BEByteSeqToInt(BEWordSeqToByteSeq(wordseq)) == BEWordSeqToInt(wordseq); { lemma_BEWordSeqToByteSeq_ensures(wordseq); BEWordSeqToByteSeq(wordseq) } ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// //- Two equal-valued DigitSeqs differ only by a zero prefix, //- regardless of how they are constructed with BEIntToDigitSeq static lemma lemma_equal_suffixes(pv:int, short:seq, long:seq) requires 1 long[i] == 0; ensures forall i :: |long|-|short|<=i<|long| ==> long[i] == short[i - (|long|-|short|)]; decreases |long|; { reveal_BEDigitSeqToInt_private(); var x := BEDigitSeqToInt_premium(pv, short); if (|short|==0) { if (|long|==0) { } else { assert BEDigitSeqToInt_premium(pv, short)==0; forall (i | 0<=i<|long|-|short|) ensures long[i] == 0; { if (i==|long|-1) { calc { 0; x; BEDigitSeqToInt_premium(pv, long[0..|long|-1])*pv + long[|long|-1]; } lemma_mul_nonnegative(BEDigitSeqToInt_premium(pv, long[0..|long|-1]), pv); assert long[i] == 0; } else { if (BEDigitSeqToInt_premium(pv, long[0..|long|-1])>0) { lemma_mul_strictly_positive(BEDigitSeqToInt_premium(pv, long[0..|long|-1]), pv); assert false; } calc { long[i]; long[0..|long|-1][i]; { lemma_equal_suffixes(pv, short, long[0..|long|-1]); } 0; } } } } } else { //- assert x == BEDigitSeqToInt_premium(pv, short[0..|short|-1])*pv + short[|short|-1]; //- assert x == BEDigitSeqToInt_premium(pv, long[0..|long|-1])*pv + long[|long|-1]; lemma_fundamental_div_mod_converse(x, pv, BEDigitSeqToInt_premium(pv, short[0..|short|-1]), short[|short|-1]); lemma_fundamental_div_mod_converse(x, pv, BEDigitSeqToInt_premium(pv, long[0..|long|-1]), long[|long|-1]); calc { BEDigitSeqToInt_premium(pv, short[0..|short|-1]); x/pv; BEDigitSeqToInt_premium(pv, long[0..|long|-1]); } calc { short[|short|-1]; x%pv; long[|long|-1]; } //- assert short[|short|-1] == long[|long|-1]; lemma_equal_suffixes(pv, short[0..|short|-1], long[0..|long|-1]); forall (i | 0<=i<|long|-|short|) ensures long[i] == 0; { if (i==|long|-1) { assert long[i] == 0; } else { calc { long[i]; long[0..|long|-1][i]; { lemma_equal_suffixes(pv, short[0..|short|-1], long[0..|long|-1]); } 0; } assert long[i] == 0; } } forall (i | |long|-|short|<=i<|long|) ensures long[i] == short[i - (|long|-|short|)]; { if (i==|long|-1) { assert long[i] == short[i - (|long|-|short|)]; } else { assert long[i] == short[i - (|long|-|short|)]; } } } } ////////////////////////////////////////////////////////////////////////////// static lemma lemma_BEIntToDigitSeq_of_zero(pv:int, s:seq) requires 1 s[i] == 0; decreases |s|; { if (|s|==0) { } else if (s[0]==0) { calc { 0; { lemma_BEInt_decoding_general(pv, |s|, 0); } BEDigitSeqToInt(pv, s); { lemma_LeadingZeros(pv, s[1..], s); } BEDigitSeqToInt(pv, s[1..]); } lemma_BEDigitSeqToInt_invertibility(pv, 0, s[1..]); assert s[1..] == BEIntToDigitSeq(pv, |s[1..]|, 0); //- recurse. lemma_BEIntToDigitSeq_of_zero(pv, s[1..]); forall (i | 0<=i<|s|) ensures s[i]==0; { if (i>0) { assert s[i] == s[1..][i-1]; } } } else { lemma_BEInt_decoding_general(pv, |s|, 0); assert BEDigitSeqToInt(pv, s) == 0; lemma_BEDigitSeqToInt_bound(pv, s); calc { 0; < s[0]; <= { lemma_power_positive(pv, |s|-1); lemma_mul_increases(power(pv, |s|-1), s[0]); } power(pv, |s|-1) * s[0]; { lemma_mul_is_commutative_forall(); } s[0] * power(pv, |s|-1); <= BEDigitSeqToInt(pv, s); 0; } assert false; } } static lemma lemma_BEDigitSeqToInt_of_zeros(pv:int, s:seq) requires 1 s[i] == 0; ensures BEDigitSeqToInt(pv, s) == 0; decreases |s|; { if (|s|==0) { reveal_BEDigitSeqToInt_private(); } else { calc { BEDigitSeqToInt(pv, s); { reveal_BEDigitSeqToInt_private(); } BEDigitSeqToInt_private(pv, s[0..|s|-1])*pv + s[0]; { lemma_BEDigitSeqToInt_of_zeros(pv, s[0..|s|-1]); } mul(0,pv) + s[0]; { lemma_mul_basics_forall(); } 0; } } } ////////////////////////////////////////////////////////////////////////////// static lemma lemma_select_from_transform(inseq:seq, headseq:seq, tailseq:seq, outbits:nat, scale:nat, inbits:nat, crop:nat) requires IsDigitSeq(power2(inbits), inseq); requires IsDigitSeq(power2(inbits), inseq); requires IsDigitSeq(power2(inbits), headseq); requires IsDigitSeq(power2(inbits), tailseq); requires inseq == headseq + tailseq; requires 0 include "relational.s.dfy" include "be_sequences.s.dfy" include "../Math/power2.i.dfy" include "../../Drivers/CPU/assembly_premium.i.dfy" method UseDeclassifiedByteSequence(computed:seq, ghost declassed:seq) returns (usable:seq) requires |declassed| == |computed|; requires IsByteSeq(computed); requires public(|computed|); requires relation(forall i :: left(i) == right(i) && 0 <= left(i) < left(|declassed|) ==> declassified(left(declassed[i]), right(declassed[i]), left(computed[i]), right(computed[i]))); ensures |usable| == |declassed|; ensures forall i :: 0 <= i < |declassed| ==> declassed[i] == usable[i]; ensures public(usable); { var i := 0; usable := []; while (i < |computed|) invariant 0 <= i <= |computed|; invariant |usable| == i; invariant forall j :: 0 <= j < i ==> declassed[j] == usable[j]; invariant IsByteSeq(computed); invariant public(i); invariant public(|computed|); invariant public(usable); invariant relation(forall j :: left(j) == right(j) && 0 <= left(j) < left(|declassed|) ==> declassified(left(declassed[j]), right(declassed[j]), left(computed[j]), right(computed[j]))); invariant |computed| == |declassed|; { calc { computed[i]; < power2(8); < { lemma_power2_strictly_increases(8, 32); } power2(32); } var result := Asm_declassify_result(computed[i], declassed[i]); usable := usable + [result]; i := i + 1; } } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Util/relational.s.dfy ================================================ //-////////////////////////////////////////// //- Relational interface used by SymDiff //-////////////////////////////////////////// //- Dummy functions that are translated into BoogieAsm keywords: static function left(x:t) : t { x } static function right(x:t) : t { x } static predicate relation(x:t) { true } static predicate public(x:t) { true } //- Imported functions: static predicate{:imported} declassified(lg:int, rg:int, l:int, r:int) ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Util/repeat_digit.i.dfy ================================================ include "be_sequences.s.dfy" include "../Math/div.i.dfy" include "seqs_simple.i.dfy" static lemma Lemma_RepeatDigitProperties(digit:int, count:int) decreases count; ensures |RepeatDigit(digit, count)| == if count < 0 then 0 else count; ensures forall i :: 0 <= i < count ==> RepeatDigit(digit, count)[i] == digit; { if (count > 0) { Lemma_RepeatDigitProperties(digit, count - 1); } } static function RepeatDigit_premium(digit:int, count:int) : seq ensures |RepeatDigit(digit, count)| == if count < 0 then 0 else count; ensures forall i :: 0 <= i < count ==> RepeatDigit(digit, count)[i] == digit; { Lemma_RepeatDigitProperties(digit, count); RepeatDigit(digit, count) } static function {:opaque} SequenceOfZeros(n:nat) : seq //- ensures SequenceOfZeros(n)!=NSeqInt_n(); ensures |SequenceOfZeros(n)|==n; ensures forall i :: 0<=i SequenceOfZeros(n)[i]==0; ensures forall pv :: 0 IsDigitSeq(pv, SequenceOfZeros(n)); { if (n==0) then [] else SequenceOfZeros(n-1)+[0] } static lemma lemma_SequenceOfZeros_is_RepeatDigit(count:nat) ensures SequenceOfZeros(count) == RepeatDigit(0, count); { Lemma_RepeatDigitProperties(0, count); } static method SequenceOfZerosIterative(n:nat) returns (Z:seq) requires Word32(n); ensures Z == SequenceOfZeros(n); //- ensures Z!=NSeqInt_n(); ensures |Z|==n; ensures forall i :: 0<=i Z[i]==0; ensures forall pv :: 0 IsDigitSeq(pv, Z); { reveal_SequenceOfZeros(); var num_zeros := 0; var z := []; while (num_zeros < n) invariant 0 <= num_zeros <= n; invariant z == SequenceOfZeros(num_zeros); { z := z + [0]; num_zeros := num_zeros + 1; } Z := z; } static lemma lemma_BEIntToDigitSeq_private_zero(pv:int, b:int) requires 1 BEIntToDigitSeq_private(pv, b, 0)[i] == 0; { reveal_BEIntToDigitSeq_private(); if (b==0) { } else { lemma_BEIntToDigitSeq_private_zero(pv, b-1); calc { BEIntToDigitSeq_private(pv, b, 0); { lemma_div_pos_is_pos(0,pv); } BEIntToDigitSeq_private(pv, b-1, div(0,pv)) + [ mod(0,pv) ]; { lemma_small_mod(0,pv); } BEIntToDigitSeq_private(pv, b-1, div(0,pv)) + [ 0 ]; { lemma_div_basics(pv); } BEIntToDigitSeq_private(pv, b-1, 0) + [ 0 ]; } forall (i | 0<=i BEIntToDigitSeq_private(pv, b, 0)[i] == 0; } } static lemma lemma_BEIntToDigitSeq_invertibility_zero(pv:int, digitseq:seq) requires 1 digitseq[i] == 0; decreases |digitseq|; ensures BEDigitSeqToInt(pv, digitseq) == 0; { reveal_BEDigitSeqToInt_private(); reveal_BEIntToDigitSeq_private(); if (|digitseq|==0) { } else { calc { BEDigitSeqToInt(pv, digitseq); BEDigitSeqToInt_private(pv, digitseq); BEDigitSeqToInt_private(pv, digitseq[0..|digitseq|-1])*pv + digitseq[|digitseq|-1]; { var prefix := digitseq[..|digitseq|-1]; lemma_BEIntToDigitSeq_private_zero(pv, |digitseq|-1); var subzero := BEIntToDigitSeq_private(pv, |digitseq|-1, 0); assert |subzero| == |digitseq| - 1; assert forall i::0<=i<|digitseq|-1 ==> subzero[i] == 0; assert subzero == prefix; lemma_BEIntToDigitSeq_invertibility_zero(pv, subzero); assert BEDigitSeqToInt(pv, subzero) == 0; assert BEDigitSeqToInt_private(pv, prefix) == 0; calc { BEDigitSeqToInt_private(pv, digitseq[0..|digitseq|-1]); { lemma_vacuous_statement_about_a_sequence(digitseq, |digitseq|-1); } BEDigitSeqToInt_private(pv, prefix); 0; } } mul(0,pv) + digitseq[|digitseq|-1]; { lemma_mul_basics_forall(); } digitseq[|digitseq|-1]; 0; } } } static method RepeatDigit_impl(digit:int, count:int) returns (os:seq) ensures os == RepeatDigit_premium(digit, count); { os := []; if count < 0 { return; } var i := 0; while i < count invariant 0 <= i <= count; invariant os == RepeatDigit(digit, i); { os := os + [digit]; i := i + 1; } } static method RepeatDigit_impl_arrays(digit:int, count:int) returns (os:array) ensures os != null; ensures os[..] == RepeatDigit_premium(digit, count); { if count < 0 { os := new int[0]; return; } os := new int[count]; var i := 0; while i < count invariant 0 <= i <= count; invariant os[..i] == RepeatDigit(digit, i); { os[i] := digit; i := i + 1; } } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Util/seq_blocking.i.dfy ================================================ include "seq_blocking.s.dfy" include "seqs_simple.i.dfy" include "arrays_and_seqs.i.dfy" include "../Math/round.i.dfy" include "../Math/div.i.dfy" include "../Math/mul.i.dfy" static lemma Lemma_SubtractOneBlock(block_num:int, block_size:int, block_index:int) ensures (block_num-1)*block_size + block_index == block_num * block_size + block_index - block_size; { calc { (block_num-1)*block_size; { lemma_mul_is_commutative(block_num-1, block_size);} block_size * (block_num-1); { lemma_mul_is_distributive_sub(block_size, block_num, 1); } (block_size * block_num) - (block_size * 1); (block_size * block_num) - block_size; { lemma_mul_is_commutative(block_size, block_num); } (block_num * block_size) - block_size; } } static lemma{:dafnycc_conservative_seq_triggers} Lemma_BlockedSequenceContainsElement(os:seq, block_size:int, block_num:int, block_index:int) requires 0 <= block_index < block_size; requires 0 <= block_num; requires 0 <= block_num * block_size + block_index < |os|; ensures block_num < |BreakIntoBlocks(os, block_size)|; ensures block_index < |BreakIntoBlocks(os, block_size)[block_num]|; ensures 0 <= block_num * block_size + block_index; ensures os[block_num * block_size + block_index] == BreakIntoBlocks(os, block_size)[block_num][block_index]; { reveal_BreakIntoBlocks(); calc { |os|; > block_num * block_size + block_index; >= { lemma_mul_inequality(0, block_num, block_size); lemma_mul_is_mul_boogie(0, block_size); } (0 * block_size) + block_index; == 0 + block_index; >= 0; } assert |os| > 0; calc { block_num * block_size + block_index; >= { lemma_mul_inequality(0, block_num, block_size); lemma_mul_is_mul_boogie(0, block_size); } (0 * block_size) + block_index; == 0 + block_index; >= 0; } if |os| < block_size { if block_num >= 1 { calc { |os|; > block_num * block_size + block_index; >= { lemma_mul_inequality(1, block_num, block_size); lemma_mul_is_mul_boogie(1, block_size); } (1 * block_size) + block_index; == block_size + block_index; >= block_size; >= |os|; } assert false; } assert 0 == block_num < |BreakIntoBlocks(os, block_size)|; calc { |BreakIntoBlocks(os, block_size)[block_num]|; == |os|; > block_num * block_size + block_index; == { lemma_mul_is_mul_boogie(0, block_size); } 0 * block_size + block_index; == block_index; } calc { os[block_num * block_size + block_index]; { lemma_mul_is_mul_boogie(0, block_size); } os[0 * block_size + block_index]; os[block_index]; BreakIntoBlocks(os, block_size)[0][block_index]; BreakIntoBlocks(os, block_size)[block_num][block_index]; } } else { if block_num > 0 { calc { (block_num-1)*block_size + block_index; >= { lemma_mul_nonnegative(block_num-1, block_size); } 0 + block_index; >= 0; } calc { (block_num-1)*block_size + block_index; { Lemma_SubtractOneBlock(block_num, block_size, block_index); } block_num * block_size - block_size + block_index; < |os| - block_size; == |os[block_size..]|; } Lemma_BlockedSequenceContainsElement(os[block_size..], block_size, block_num-1, block_index); calc { os[block_num * block_size + block_index]; calc { block_num * block_size + block_index; >= { lemma_mul_inequality(1, block_num, block_size); lemma_mul_is_mul_boogie(1, block_size); } 1 * block_size + block_index; == block_size + block_index; >= block_size; } { lemma_seq_suffix(os, block_size, block_num * block_size + block_index); } os[block_size..][block_num * block_size + block_index - block_size]; { Lemma_SubtractOneBlock(block_num, block_size, block_index); } os[block_size..][(block_num-1) * block_size + block_index]; { Lemma_BlockedSequenceContainsElement(os[block_size..], block_size, block_num-1, block_index); } BreakIntoBlocks(os[block_size..], block_size)[block_num-1][block_index]; ([os[..block_size]] + BreakIntoBlocks(os[block_size..], block_size))[block_num][block_index]; BreakIntoBlocks(os, block_size)[block_num][block_index]; } } else { calc { os[block_num * block_size + block_index]; { lemma_mul_is_mul_boogie(0, block_size); } os[0 * block_size + block_index]; os[block_index]; os[..block_size][block_index]; ([os[..block_size]] + BreakIntoBlocks(os[block_size..], block_size))[0][block_index]; ([os[..block_size]] + BreakIntoBlocks(os[block_size..], block_size))[block_num][block_index]; BreakIntoBlocks(os, block_size)[block_num][block_index]; } } } } static lemma Lemma_BlockedSequencePrefixContainsElement(os:seq, prefix_size:int, block_size:int, block_num:int, block_index:int) requires 0 <= block_index < block_size; requires 0 <= block_num; requires 0 <= prefix_size; requires 0 <= block_num * block_size + block_index < prefix_size <= |os|; ensures block_num < |BreakIntoBlocks(os, block_size)|; ensures block_index < |BreakIntoBlocks(os, block_size)[block_num]|; ensures block_num < |BreakIntoBlocks(os[..prefix_size], block_size)|; ensures block_index < |BreakIntoBlocks(os[..prefix_size], block_size)[block_num]|; ensures os[block_num * block_size + block_index] == BreakIntoBlocks(os[..prefix_size], block_size)[block_num][block_index]; { Lemma_BlockedSequenceContainsElement(os, block_size, block_num, block_index); Lemma_BlockedSequenceContainsElement(os[..prefix_size], block_size, block_num, block_index); calc { os[block_num * block_size + block_index]; (os[..prefix_size] + os[prefix_size..])[block_num * block_size + block_index]; os[..prefix_size][block_num * block_size + block_index]; BreakIntoBlocks(os[..prefix_size], block_size)[block_num][block_index]; } } static lemma Lemma_AllBlocksAreOfEqualSize(os:seq, block_size:int) requires 0 < block_size; requires |os| % block_size == 0; ensures |BreakIntoBlocks(os, block_size)| == |os| / block_size; ensures forall blk :: 0 <= blk < |BreakIntoBlocks(os, block_size)| ==> |BreakIntoBlocks(os, block_size)[blk]| == block_size; { reveal_BreakIntoBlocks(); var num_blocks := |os| / block_size; var blocks := BreakIntoBlocks(os, block_size); calc { |os|; { lemma_fundamental_div_mod(|os|, block_size); } block_size * (|os| / block_size) + |os| % block_size; block_size * num_blocks + |os| % block_size; block_size * num_blocks + 0; block_size * num_blocks; } if |os| == 0 { lemma_div_basics(block_size); } else if |os| < block_size { calc { (0 * block_size) + |os|; |os|; } lemma_fundamental_div_mod_converse(|os|, block_size, 0, |os|); assert |os| % block_size == |os| == 0; assert false; } else { calc { num_blocks; == |os| / block_size; >= { lemma_div_is_ordered(block_size, |os|, block_size); } block_size / block_size; { lemma_div_basics(block_size); } 1; } calc { |os[block_size..]| % block_size; (|os| - block_size) % block_size; (-1 * block_size + |os|) % block_size; (block_size * -1 + |os|) % block_size; { lemma_mul_is_mul_boogie(block_size, -1); lemma_mod_multiples_vanish(-1, |os|, block_size); } |os| % block_size; 0; } Lemma_AllBlocksAreOfEqualSize(os[block_size..], block_size); assert |BreakIntoBlocks(os[block_size..], block_size)| == |os[block_size..]| / block_size; calc { |blocks|; 1 + |BreakIntoBlocks(os[block_size..], block_size)|; 1 + |os[block_size..]| / block_size; 1 + (|os| - block_size) / block_size; 1 + (block_size * num_blocks - block_size) / block_size; 1 + (block_size * num_blocks - 1 * block_size) / block_size; { lemma_mul_is_mul_boogie(1, block_size); lemma_mul_is_commutative(1, block_size); lemma_mul_is_distributive_sub(block_size, num_blocks, 1); } 1 + (block_size * (num_blocks - 1)) / block_size; { lemma_mul_is_commutative(block_size, num_blocks - 1); lemma_div_by_multiple(num_blocks - 1, block_size); } 1 + (num_blocks - 1); |os| / block_size; } } } static lemma Lemma_AllBlocksAreWordSeqs(os:seq, block_size:int) requires 0 < block_size; requires IsWordSeq(os); ensures forall blk :: 0 <= blk < |BreakIntoBlocks(os, block_size)| ==> IsWordSeq(BreakIntoBlocks(os, block_size)[blk]); { reveal_BreakIntoBlocks(); if (|os| >= block_size) { Lemma_AllBlocksAreWordSeqs(os[block_size..], block_size); assert BreakIntoBlocks(os, block_size) == [os[..block_size]] + BreakIntoBlocks(os[block_size..], block_size); //- dafnycc triggering } } static predicate BlockBoundariesAreWithinSequence(i:int, block_size:int, len:int) { 0 <= i*block_size <= (i+1)*block_size <= len } static lemma Lemma_BoundariesOfSeqBlock(s:seq, block_size:int) requires 0 < block_size; requires |s| % block_size == 0; ensures forall i :: 0 <= i < (|s| / block_size) ==> BlockBoundariesAreWithinSequence(i, block_size, |s|); ensures |s| == (|s| / block_size) * block_size; { Lemma_AllBlocksAreOfEqualSize(s, block_size); var num_blocks := |s| / block_size; calc { |s|; { lemma_fundamental_div_mod(|s|, block_size); } block_size * (|s| / block_size) + |s| % block_size; block_size * num_blocks + |s| % block_size; block_size * num_blocks + 0; block_size * num_blocks; { lemma_mul_is_commutative(block_size, num_blocks); } num_blocks * block_size; } forall j | 0 <= j < num_blocks ensures 0 <= j*block_size; { lemma_mul_nonnegative(j, block_size); } forall j | 0 <= j < num_blocks ensures j*block_size <= (j+1)*block_size <= |s|; { calc { j*block_size; <= { lemma_mul_inequality(j, j+1, block_size); } (j+1)*block_size; } calc { (j+1) * block_size; <= { lemma_mul_inequality(j+1, num_blocks, block_size); } num_blocks * block_size; |s|; } } } static lemma Lemma_EqualBlockingCausesSpecificSubsequences(s:seq, block_size:int, i:int) requires 0 < block_size; requires |s| % block_size == 0; requires 0 <= i < (|s| / block_size); ensures 0 <= i*block_size <= (i+1)*block_size <= |s|; ensures |BreakIntoBlocks(s, block_size)| == |s| / block_size; ensures BreakIntoBlocks(s, block_size)[i] == s[i*block_size .. (i+1)*block_size]; { Lemma_AllBlocksAreOfEqualSize(s, block_size); Lemma_BoundariesOfSeqBlock(s, block_size); assert BlockBoundariesAreWithinSequence(i, block_size, |s|); if i == 0 { calc <= {1; {reveal_BreakIntoBlocks();} |s|;} if |s| < block_size { lemma_small_div(); assert |s| / block_size == 0; assert false; } else if |s| == block_size { calc { BreakIntoBlocks(s, block_size)[i]; { reveal_BreakIntoBlocks(); } [s][i]; [s][0]; s; s[0..|s|]; s[0..block_size]; s[0*block_size..1*block_size]; { lemma_mul_is_mul_boogie(0, block_size); } s[i*block_size..1*block_size]; { reveal_BreakIntoBlocks(); } s[i*block_size..(i+1)*block_size]; } } else { calc { BreakIntoBlocks(s, block_size)[i]; BreakIntoBlocks(s, block_size)[0]; { reveal_BreakIntoBlocks(); } ([s[..block_size]] + BreakIntoBlocks(s[block_size..], block_size))[0]; s[..block_size]; s[0..block_size]; s[0*block_size..1*block_size]; { lemma_mul_is_mul_boogie(0, block_size); } s[i*block_size..1*block_size]; { lemma_mul_is_mul_boogie(1, block_size); } s[i*block_size..(i+1)*block_size]; } } } else { if |s| < block_size { lemma_small_div(); assert |s| / block_size == 0; assert false; } else if |s| == block_size { calc {|s| / block_size; { reveal_BreakIntoBlocks(); } 1;} assert false; } else { calc { BreakIntoBlocks(s, block_size)[i]; { reveal_BreakIntoBlocks(); } ([s[..block_size]] + BreakIntoBlocks(s[block_size..], block_size))[i]; BreakIntoBlocks(s[block_size..], block_size)[i-1]; { calc { (|s| - block_size) % block_size; (-block_size + |s|) % block_size; (block_size * -1 + |s|) % block_size; { lemma_mod_multiples_vanish(-1, |s|, block_size); } { lemma_mul_is_mul_boogie(block_size, -1); } |s| % block_size; 0; } calc { i-1; < |s|/block_size - 1; { lemma_hoist_over_denominator(|s|, -1, block_size); lemma_mul_is_mul_boogie(-1, block_size); } (|s| + -1 * block_size) / block_size; (|s| - block_size)/block_size; } Lemma_EqualBlockingCausesSpecificSubsequences(s[block_size..], block_size, i-1); } s[block_size..][(i-1)*block_size..(i-1+1)*block_size]; s[block_size..][(i-1)*block_size..i*block_size]; { lemma_mul_nonnegative(i - 1, block_size); /* dafnycc */ } s[(i-1)*block_size+block_size..i*block_size+block_size]; s[(i-1)*block_size+block_size*1..i*block_size+block_size]; { lemma_mul_is_commutative(i-1, block_size); } s[block_size*(i-1)+block_size*1..i*block_size+block_size]; { lemma_mul_is_mul_boogie(block_size, 1); lemma_mul_is_distributive_add(block_size, i-1, 1); } s[block_size*(i-1+1)..i*block_size+block_size]; s[block_size*i..i*block_size+block_size]; { lemma_mul_is_commutative(i, block_size); } s[i*block_size..block_size*i+block_size]; s[i*block_size..block_size*i+block_size*1]; { lemma_mul_is_mul_boogie(block_size, 1); lemma_mul_is_distributive_add(block_size, i, 1); } s[i*block_size..block_size*(i+1)]; { lemma_mul_is_commutative(i+1, block_size); } s[i*block_size..(i+1)*block_size]; } } } } static method DivideSeqIntoEqualBlocks(s:seq, block_size:int) returns (r:seq>) requires 0 < block_size; requires |s| % block_size == 0; ensures r == BreakIntoBlocks(s, block_size); ensures forall i :: 0 <= i < |r| ==> |r[i]| == block_size; { Lemma_AllBlocksAreOfEqualSize(s, block_size); var num_blocks := |s| / block_size; var i := 0; r := []; Lemma_BoundariesOfSeqBlock(s, block_size); assert forall j :: 0 <= j < num_blocks ==> BlockBoundariesAreWithinSequence(j, block_size, |s|); while i < num_blocks invariant 0 <= i <= num_blocks; invariant |r| == i; invariant forall j :: 0 <= j < i ==> BlockBoundariesAreWithinSequence(j, block_size, |s|) && r[j] == s[j*block_size .. (j+1)*block_size]; { assert BlockBoundariesAreWithinSequence(i, block_size, |s|); r := r + [s[i * block_size .. (i+1) * block_size]]; i := i + 1; } assert |r| == |BreakIntoBlocks(s, block_size)|; forall j | 0 <= j < num_blocks ensures r[j] == BreakIntoBlocks(s, block_size)[j]; { Lemma_EqualBlockingCausesSpecificSubsequences(s, block_size, j); } } static function{:opaque} PadSequenceToMultiple(os:seq, block_size:int) : seq requires 0 < block_size; { if |os| % block_size == 0 then os else os + RepeatDigit(0, block_size - (|os| % block_size)) } static function PadAndBreakIntoBlocks(os:seq, block_size:int) : seq> requires 0 < block_size; { BreakIntoBlocks(PadSequenceToMultiple(os, block_size), block_size) } static lemma lemma_PadSequenceToMultiple_premium_properties(os:seq, block_size:int) requires 0 < block_size; ensures var padded_len := RoundUpToMultiple(|os|, block_size); var num_blocks := padded_len / block_size; |PadSequenceToMultiple(os, block_size)| == padded_len && padded_len % block_size == 0 && (forall i :: 0 <= i < num_blocks ==> 0 <= block_size*i == i*block_size) && (forall i :: 0 <= i < num_blocks ==> i*block_size == block_size*i <= (i+1)*block_size == block_size*(i+1) <= padded_len) && (forall i :: 0 <= i < num_blocks ==> 0 <= block_size*i == i*block_size <= (i+1)*block_size == block_size*(i+1) <= padded_len); { reveal_BreakIntoBlocks(); reveal_PadSequenceToMultiple(); var padded_len := RoundUpToMultiple_premium(|os|, block_size); var num_blocks := padded_len / block_size; if |os| % block_size != 0 { calc { |PadSequenceToMultiple(os, block_size)|; |os + RepeatDigit(0, block_size - |os| % block_size)|; |os| + |RepeatDigit_premium(0, block_size - |os| % block_size)|; { lemma_mod_remainder_pos_specific(|os|, block_size); } |os| + block_size - |os| % block_size; } } forall i | 0 <= i < num_blocks ensures 0 <= block_size*i == i*block_size; { lemma_mul_nonnegative(block_size, i); lemma_mul_is_commutative(i, block_size); } forall i | 0 <= i < num_blocks ensures i*block_size == block_size*i <= (i+1)*block_size == block_size*(i+1) <= padded_len; { calc { i*block_size; <= { lemma_mul_inequality(i, i+1, block_size); } (i+1)*block_size; } calc { (i+1) * block_size; <= { lemma_mul_inequality(i+1, num_blocks, block_size); } num_blocks * block_size; { lemma_mul_is_commutative(num_blocks, block_size); } block_size * num_blocks; { lemma_fundamental_div_mod(padded_len, block_size); } padded_len - padded_len % block_size; padded_len; } lemma_mul_is_commutative(i, block_size); lemma_mul_is_commutative(i+1, block_size); } } static function PadSequenceToMultiple_premium(os:seq, block_size:int) : seq requires 0 < block_size; ensures var padded_len := RoundUpToMultiple(|os|, block_size); var num_blocks := padded_len / block_size; |PadSequenceToMultiple(os, block_size)| == padded_len && padded_len % block_size == 0 && (forall i :: 0 <= i < num_blocks ==> 0 <= block_size*i == i*block_size) && (forall i :: 0 <= i < num_blocks ==> i*block_size == block_size*i <= (i+1)*block_size == block_size*(i+1) <= padded_len) && (forall i :: 0 <= i < num_blocks ==> 0 <= block_size*i == i*block_size <= (i+1)*block_size == block_size*(i+1) <= padded_len); { lemma_PadSequenceToMultiple_premium_properties(os, block_size); PadSequenceToMultiple(os, block_size) } static lemma lemma_PadAndBreakIntoBlocks_premium_properties(os:seq, block_size:int) requires 0 < block_size; ensures var padded_len := RoundUpToMultiple(|os|, block_size); var num_blocks := padded_len / block_size; |PadSequenceToMultiple(os, block_size)| == padded_len && padded_len % block_size == 0 && |PadAndBreakIntoBlocks(os, block_size)| == num_blocks && (forall i :: 0 <= i < num_blocks ==> |PadAndBreakIntoBlocks(os, block_size)[i]| == block_size && BlockBoundariesAreWithinSequence(i, block_size, padded_len) && PadAndBreakIntoBlocks(os, block_size)[i] == PadSequenceToMultiple(os, block_size)[i*block_size..(i+1)*block_size]); { var ps := PadSequenceToMultiple_premium(os, block_size); var padded_len := |ps|; var num_blocks := padded_len / block_size; Lemma_AllBlocksAreOfEqualSize(ps, block_size); forall i | 0 <= i < num_blocks ensures PadAndBreakIntoBlocks(os, block_size)[i] == ps[i*block_size..(i+1)*block_size]; { Lemma_EqualBlockingCausesSpecificSubsequences(ps, block_size, i); } } static function PadAndBreakIntoBlocks_premium(os:seq, block_size:int) : seq> requires 0 < block_size; ensures var padded_len := RoundUpToMultiple(|os|, block_size); var num_blocks := padded_len / block_size; |PadSequenceToMultiple(os, block_size)| == padded_len && padded_len % block_size == 0 && |PadAndBreakIntoBlocks(os, block_size)| == num_blocks && (forall i :: 0 <= i < num_blocks ==> |PadAndBreakIntoBlocks(os, block_size)[i]| == block_size && BlockBoundariesAreWithinSequence(i, block_size, padded_len) && PadAndBreakIntoBlocks(os, block_size)[i] == PadSequenceToMultiple(os, block_size)[i*block_size..(i+1)*block_size]); { lemma_PadAndBreakIntoBlocks_premium_properties(os, block_size); PadAndBreakIntoBlocks(os, block_size) } static method PadSequenceToMultiple_impl(os:seq, block_size:int) returns (ps:seq) requires 0 < block_size; ensures ps == PadSequenceToMultiple(os, block_size); { reveal_PadSequenceToMultiple(); if |os| % block_size == 0 { ps := os; } else { var rs := RepeatDigit_impl(0, block_size - |os| % block_size); ps := os + rs; } } static method PadAndBreakIntoBlocks_impl(os:seq, block_size:int) returns (r:seq>) requires 0 < block_size; ensures r == PadAndBreakIntoBlocks_premium(os, block_size); { reveal_PadSequenceToMultiple(); var ps := PadSequenceToMultiple_impl(os, block_size); assert ps == PadSequenceToMultiple_premium(os, block_size); r := DivideSeqIntoEqualBlocks(ps, block_size); } static lemma lemma_PadAndBreakIntoBlocksMaintainsByteSequence(os:seq, block_size:int) requires 0 < block_size; requires IsByteSeq(os); ensures forall i :: 0 <= i < |PadAndBreakIntoBlocks(os, block_size)| ==> IsByteSeq(PadAndBreakIntoBlocks(os, block_size)[i]); { reveal_BreakIntoBlocks(); reveal_PadSequenceToMultiple(); var ps := PadSequenceToMultiple_premium(os, block_size); var bs := BreakIntoBlocks(ps, block_size); lemma_2toX(); if (|os| % block_size != 0) { forall i | 0 <= i < |ps| ensures IsByte(ps[i]); { if i >= |os| { calc { ps[i]; (os + RepeatDigit(0, block_size - (|os| % block_size)))[i]; RepeatDigit(0, block_size - (|os| % block_size))[i-|os|]; RepeatDigit_premium(0, block_size - (|os| % block_size))[i-|os|]; 0; } } } } forall i | 0 <= i < |bs| ensures IsByteSeq(bs[i]); { lemma_PadAndBreakIntoBlocks_premium_properties(os, block_size); assert BlockBoundariesAreWithinSequence(i, block_size, |ps|); assert bs[i] == ps[i*block_size..(i+1)*block_size]; } } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Util/seq_blocking.s.dfy ================================================ include "be_sequences.s.dfy" static function{:opaque} BreakIntoBlocks(os:seq, block_size:int) : seq> requires 0 < block_size; decreases |os|; { if |os| == 0 then [] else if |os| < block_size then [os] else [os[..block_size]] + BreakIntoBlocks(os[block_size..], block_size) } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Util/seqs_and_ints.i.dfy ================================================ include "integer_sequences.s.dfy" include "seqs_simple.i.dfy" include "repeat_digit.i.dfy" include "../Math/div.i.dfy" include "../Math/power.i.dfy" include "../Math/power2.i.dfy" //-//////////////////////////////////////////////////////////////////////////// //- This file establishes properties that relate BEDigitSeqs //- to their Int interpretation. In particular, it culminates //- in reasoning about invertibility properties: For example, there's //- only one byte sequence to represent a given int, and vice versa. //-//////////////////////////////////////////////////////////////////////////// //- properties about DigitSeqToInt static lemma lemma_BEDigitSeqToInt_bound(pv:nat, inseq:seq) requires 0 < pv; requires IsDigitSeq(pv, inseq); decreases |inseq|; ensures |inseq|>0 ==> inseq[0] * power(pv, |inseq|-1) <= BEDigitSeqToInt(pv, inseq); ensures BEDigitSeqToInt(pv, inseq) < power(pv, |inseq|); ensures 0 <= BEDigitSeqToInt(pv, inseq); { var result := BEDigitSeqToInt(pv, inseq); reveal_BEDigitSeqToInt_private(); if (inseq==[]) { assert result == 0; lemma_power_positive(pv, |inseq|); } else { lemma_BEDigitSeqToInt_bound(pv, inseq[0..|inseq|-1]); if (|inseq|==1) { calc { inseq[0] * power(pv, |inseq|-1); { lemma_power_0(pv); } mul(inseq[0], 1); { lemma_mul_basics_forall(); } inseq[0]; inseq[|inseq|-1]; { lemma_mul_basics_forall(); } 0*pv + inseq[|inseq|-1]; BEDigitSeqToInt_private(pv, [])*pv + inseq[|inseq|-1]; BEDigitSeqToInt_private(pv, inseq[0..|inseq|-1])*pv + inseq[|inseq|-1]; BEDigitSeqToInt_private(pv, inseq); BEDigitSeqToInt(pv, inseq); } } else { calc { inseq[0] * power(pv, |inseq|-1); { lemma_power_adds(pv, |inseq|-2, 1); } inseq[0] * (power(pv, |inseq|-2) * power(pv,1)); { lemma_power_1(pv); } inseq[0] * (power(pv, |inseq|-2) * pv); { lemma_mul_is_associative_forall(); } (inseq[0] * power(pv, |inseq|-2)) * pv; (inseq[0] * power(pv, |inseq[0..|inseq|-1]|-1)) * pv; <= (inseq[0] * power(pv, |inseq[0..|inseq|-1]|-1)) * pv + inseq[|inseq|-1]; (inseq[0..|inseq|-1][0] * power(pv, |inseq[0..|inseq|-1]|-1)) * pv + inseq[|inseq|-1]; <= { lemma_mul_inequality(inseq[0..|inseq|-1][0] * power(pv, |inseq[0..|inseq|-1]|-1), BEDigitSeqToInt_private(pv, inseq[0..|inseq|-1]), pv); } BEDigitSeqToInt_private(pv, inseq[0..|inseq|-1])*pv + inseq[|inseq|-1]; BEDigitSeqToInt_private(pv, inseq); BEDigitSeqToInt(pv, inseq); } } assert 0 <= BEDigitSeqToInt_private(pv, inseq[0..|inseq|-1]); calc { 0; <= { lemma_mul_nonnegative_forall(); } pv*BEDigitSeqToInt_private(pv, inseq[0..|inseq|-1]); { lemma_mul_is_commutative_forall(); } BEDigitSeqToInt_private(pv, inseq[0..|inseq|-1])*pv; <= BEDigitSeqToInt_private(pv, inseq[0..|inseq|-1])*pv + inseq[|inseq|-1]; result; } calc { BEDigitSeqToInt_private(pv, inseq[0..|inseq|-1])+1; <= { lemma_BEDigitSeqToInt_bound(pv, inseq[0..|inseq|-1]); } power(pv, |inseq[0..|inseq|-1]|); power(pv, |inseq|-1); } lemma_mul_inequality( BEDigitSeqToInt_private(pv, inseq[0..|inseq|-1])+1, power(pv, |inseq|-1), pv); calc { result; BEDigitSeqToInt_private(pv, inseq[0..|inseq|-1])*pv + inseq[|inseq|-1]; < BEDigitSeqToInt_private(pv, inseq[0..|inseq|-1])*pv + pv; { lemma_mul_basics_forall(); } BEDigitSeqToInt_private(pv, inseq[0..|inseq|-1])*pv + mul(1,pv); { lemma_mul_is_distributive_forall(); } (BEDigitSeqToInt_private(pv, inseq[0..|inseq|-1])+1)*pv; <= power(pv, |inseq|-1)*pv; { reveal_power(); lemma_mul_is_commutative_forall(); } power(pv, |inseq|-1+1); power(pv, |inseq|); } } } static lemma lemma_BEIntToDigitSeq_mp_min(pv:int, mp:int, x:int) requires 10) { lemma_div_basics_forall(); lemma_BEIntToDigitSeq_zero(pv, mp-1); } } static lemma lemma_BEIntToDigitSeq_properties_inner(pv:int, mp:int, x:int) requires 10 ==> 0 < |BEIntToDigitSeq_private(pv, mp, x)|; ensures (x>0 && (mp<=0 || power(pv,mp-1)<=x)) ==> power(pv, |BEIntToDigitSeq_private(pv, mp, x)|-1) <= x; { lemma_BEIntToDigitSeq_mp_min(pv, mp, x); if (x==0) { lemma_power_positive(pv, |BEIntToDigitSeq_private(pv, mp, x)|); } else { lemma_div_pos_is_pos(x,pv); lemma_div_is_strictly_ordered_by_denominator(x,pv); calc ==> { true; { lemma_BEIntToDigitSeq_properties_inner(pv, mp-1, x/pv); } x/pv+1 <= power(pv, |BEIntToDigitSeq_private(pv, mp-1, x/pv)|); { lemma_mul_inequality_forall(); } (x/pv+1)*pv <= power(pv, |BEIntToDigitSeq_private(pv, mp-1, x/pv)|)*pv; { lemma_mul_is_distributive_forall(); } (x/pv)*pv+mul(1,pv) <= power(pv, |BEIntToDigitSeq_private(pv, mp-1, x/pv)|)*pv; { lemma_mul_basics_forall(); } (x/pv)*pv + pv <= power(pv, |BEIntToDigitSeq_private(pv, mp-1, x/pv)|)*pv; { lemma_fundamental_div_mod(x,pv); lemma_mul_is_commutative_forall(); } x - x%pv + pv <= power(pv, |BEIntToDigitSeq_private(pv, mp-1, x/pv)|)*pv; } calc { x; < { lemma_mod_properties(); } x - x%pv + pv; <= power(pv, |BEIntToDigitSeq_private(pv, mp-1, x/pv)|)*pv; { lemma_power_1(pv); } power(pv, |BEIntToDigitSeq_private(pv, mp-1, x/pv)|)*power(pv, 1); { lemma_power_adds(pv, |BEIntToDigitSeq_private(pv, mp-1, x/pv)|, 1); } power(pv, |BEIntToDigitSeq_private(pv, mp-1, x/pv)|+1); power(pv, |BEIntToDigitSeq_private(pv, mp-1, x/pv) + [x%pv]|); { reveal_BEIntToDigitSeq_private(); } power(pv, |BEIntToDigitSeq_private(pv, mp, x)|); } reveal_BEIntToDigitSeq_private(); assert 0 < |BEIntToDigitSeq_private(pv, mp, x)|; if (x>0 && (mp<=0 || power(pv,mp-1)<=x)) //- one more obligation. { if (x/pv <= 0) //- can't recurse, case I { calc ==> { true; { lemma_small_div_converse(); } 01) { calc { power(pv,mp-1); { lemma_power_adds(pv,mp-2,1); } power(pv,mp-2)*power(pv,1); >= { lemma_power_positive(pv,1); lemma_power_positive(pv,mp-2); lemma_mul_increases(power(pv,mp-2), power(pv,1)); } power(pv,1); { lemma_power_1(pv); } pv; } assert false; } } mp<=1; |BEIntToDigitSeq_private(pv, mp, x)| <= 1; |BEIntToDigitSeq_private(pv, mp, x)|-1 <= 0; |BEIntToDigitSeq_private(pv, mp, x)|-1 == 0; { lemma_power_0(pv); } power(pv, |BEIntToDigitSeq_private(pv, mp, x)|-1) == 1; power(pv, |BEIntToDigitSeq_private(pv, mp, x)|-1) <= x; } } else if (mp-1>0 && power(pv,mp-1-1)>x/pv) //- can't recurse, case II { assert power(pv,mp-1)<=x; calc ==> { mp>1; power(pv,mp-2) > x/pv; { lemma_div_by_multiple(power(pv,mp-2), pv); } (power(pv,mp-2)*pv)/pv > x/pv; { lemma_power_1(pv); } (power(pv,mp-2)*power(pv,1))/pv > x/pv; { lemma_power_adds(pv,mp-2,1); } power(pv,mp-1)/pv > x/pv; { if (power(pv,mp-1) <= x) { lemma_power_positive(pv,mp-1); lemma_div_is_ordered(power(pv,mp-1), x, pv); assert false; } } power(pv,mp-1) > x; false; } } else //- can recurse { assert x/pv > 0 && (mp-1<=0 || power(pv,mp-1-1)<=x/pv); assert |BEIntToDigitSeq_private(pv, mp-1, x/pv)|-1 >= 0; calc ==> { true; { lemma_BEIntToDigitSeq_properties_inner(pv, mp-1, x/pv); } power(pv, |BEIntToDigitSeq_private(pv, mp-1, x/pv)|-1) <= x/pv; power(pv, |BEIntToDigitSeq_private(pv, mp-1, x/pv)|-1) <= x/pv; { lemma_mul_inequality_forall(); } power(pv, |BEIntToDigitSeq_private(pv, mp-1, x/pv)|-1)*pv <= (x/pv)*pv; { lemma_fundamental_div_mod(x,pv); lemma_mul_is_commutative_forall(); } power(pv, |BEIntToDigitSeq_private(pv, mp-1, x/pv)|-1)*pv <= x - x%pv; } calc { power(pv, |BEIntToDigitSeq_private(pv, mp, x)|-1); power(pv, |BEIntToDigitSeq_private(pv, mp-1, x/pv) + [x%pv]|-1); power(pv, |BEIntToDigitSeq_private(pv, mp-1, x/pv)|); power(pv, |BEIntToDigitSeq_private(pv, mp-1, x/pv)|-1+1); { lemma_power_adds(pv, |BEIntToDigitSeq_private(pv, mp-1, x/pv)|-1, 1); } power(pv, |BEIntToDigitSeq_private(pv, mp-1, x/pv)|-1)*power(pv,1); { lemma_power_1(pv); } power(pv, |BEIntToDigitSeq_private(pv, mp-1, x/pv)|-1)*pv; <= x - x%pv; <= { lemma_mod_properties(); } x; } } } } } static lemma lemma_BEIntToDigitSeq_when_mp_dominates_x(pv:int, mp:int, x:int) requires 1= power(pv,mp-1)) { calc { x; >= { lemma_fundamental_div_mod(x,pv); lemma_mod_properties(); } pv*(x/pv); >= { lemma_mul_inequality_forall(); lemma_mul_is_commutative_forall(); } //- and contradiction hypothesis pv*power(pv,mp-1); { reveal_power(); } power(pv,mp); } } lemma_BEIntToDigitSeq_when_mp_dominates_x(pv, mp-1, x/pv); } mp-1+1; mp; } } } static lemma lemma_BEIntToDigitSeq_properties(pv:int, mp:int, x:int) requires 10 ==> 0 < |BEIntToDigitSeq_private(pv, mp, x)|; ensures (x>0 && (mp<=0 || power(pv,mp-1)<=x)) ==> power(pv, |BEIntToDigitSeq_private(pv, mp, x)|-1) <= x; ensures (0<=mp && x mp == |BEIntToDigitSeq_private(pv, mp, x)|; { lemma_BEIntToDigitSeq_properties_inner(pv, mp, x); if (0<=mp && x0 ==> 0 < |BEIntToDigitSeq_private(pv, 0, x/pv)|; assert x/pv>0 ==> power(pv, |BEIntToDigitSeq_private(pv, 0, x/pv)|-1) <= x/pv; if (|BEIntToDigitSeq_private(pv, 0, x/pv)|+1 < |BEIntToDigitSeq_private(pv, 0, x)|) { //- should be able to place a too-low upper bound on x. calc ==> { true; { lemma_BEIntToDigitSeq_properties_inner(pv, 0, x/pv); } x/pv < power(pv, |BEIntToDigitSeq_private(pv, 0, x/pv)|); x/pv + 1 <= power(pv, |BEIntToDigitSeq_private(pv, 0, x/pv)|); { lemma_mul_inequality_forall(); lemma_mul_is_commutative_forall(); } pv*(x/pv + 1) <= pv*power(pv, |BEIntToDigitSeq_private(pv, 0, x/pv)|); { lemma_mul_is_distributive_forall(); } pv*(x/pv) + mul(pv,1) <= pv*power(pv, |BEIntToDigitSeq_private(pv, 0, x/pv)|); { lemma_mul_basics_forall(); } pv*(x/pv) + pv <= pv*power(pv, |BEIntToDigitSeq_private(pv, 0, x/pv)|); { lemma_power_1(pv); lemma_power_adds(pv, 1, |BEIntToDigitSeq_private(pv, 0, x/pv)|); } pv*(x/pv) + pv <= power(pv, |BEIntToDigitSeq_private(pv, 0, x/pv)|+1); { lemma_mod_properties(); } pv*(x/pv) + x%pv < power(pv, |BEIntToDigitSeq_private(pv, 0, x/pv)|+1); { lemma_fundamental_div_mod(x,pv); } x < power(pv, |BEIntToDigitSeq_private(pv, 0, x/pv)|+1); } calc ==> { true; |BEIntToDigitSeq_private(pv, 0, x/pv)|+2 <= |BEIntToDigitSeq_private(pv, 0, x)|; { lemma_power_increases(pv, |BEIntToDigitSeq_private(pv, 0, x/pv)|+1, |BEIntToDigitSeq_private(pv, 0, x)|-1); } power(pv, |BEIntToDigitSeq_private(pv, 0, x/pv)|+1) <= power(pv, |BEIntToDigitSeq_private(pv, 0, x)|-1); } calc { x; < power(pv, |BEIntToDigitSeq_private(pv, 0, x/pv)|+1); <= power(pv, |BEIntToDigitSeq_private(pv, 0, x)|-1); <= { lemma_BEIntToDigitSeq_properties_inner(pv, 0, x); } x; } assert false; } else if (|BEIntToDigitSeq_private(pv, 0, x/pv)|+1 > |BEIntToDigitSeq_private(pv, 0, x)|) { //- should be able to place a too-high lower bound on x. if (x/pv==0) { calc { 1; 0+1; { reveal_BEIntToDigitSeq_private(); } |BEIntToDigitSeq_private(pv, 0, x/pv)|+1; > //- contradiction hypothesis |BEIntToDigitSeq_private(pv, 0, x)|; } assert |BEIntToDigitSeq_private(pv, 0, x)| == 0; assert x == 0; } else { calc ==> { true; { lemma_BEIntToDigitSeq_properties_inner(pv, 0, x/pv); } power(pv, |BEIntToDigitSeq_private(pv, 0, x/pv)|-1) <= x/pv; { lemma_mul_inequality_forall(); lemma_mul_is_commutative_forall(); } pv*power(pv, |BEIntToDigitSeq_private(pv, 0, x/pv)|-1) <= pv*(x/pv); { lemma_mod_properties(); } pv*power(pv, |BEIntToDigitSeq_private(pv, 0, x/pv)|-1) <= pv*(x/pv) + x%pv; { lemma_fundamental_div_mod(x,pv); } pv*power(pv, |BEIntToDigitSeq_private(pv, 0, x/pv)|-1) <= x; { lemma_power_1(pv); lemma_power_adds(pv, 1, |BEIntToDigitSeq_private(pv, 0, x/pv)|-1); } power(pv, |BEIntToDigitSeq_private(pv, 0, x/pv)|) <= x; } calc ==> { true; |BEIntToDigitSeq_private(pv, 0, x/pv)| >= |BEIntToDigitSeq_private(pv, 0, x)|; { lemma_power_increases(pv, |BEIntToDigitSeq_private(pv, 0, x)|, |BEIntToDigitSeq_private(pv, 0, x/pv)|); } power(pv, |BEIntToDigitSeq_private(pv, 0, x/pv)|) >= power(pv, |BEIntToDigitSeq_private(pv, 0, x)|); } calc { x; < { lemma_BEIntToDigitSeq_properties_inner(pv, 0, x); } pv*power(pv, |BEIntToDigitSeq_private(pv, 0, x)|); <= pv*power(pv, |BEIntToDigitSeq_private(pv, 0, x/pv)|); <= x; } } } } static lemma lemma_BEIntToDigitSeq_mp_irrelevant(pv:int, mp:int, x:int) requires 1 |BEIntToDigitSeq(pv, 0, x/pv)|) { lemma_BEIntToDigitSeq_length(pv, x); assert false; } lemma_BEIntToDigitSeq_mp_irrelevant(pv, mp-1, x/pv); } BEIntToDigitSeq_private(pv, 0, x/pv) + [x%pv]; { lemma_BEIntToDigitSeq_private_unbounded_mp_irrelevant(pv, x/pv, 0, -1); } BEIntToDigitSeq_private(pv, -1, x/pv) + [x%pv]; BEIntToDigitSeq_private(pv, 0, x); BEIntToDigitSeq(pv, 0, x); } } } static lemma lemma_BEIntToDigitSeq_shortest_form(pv:int, digitseq:seq, mp:int) requires 1) requires 1 0 0 x y == ID(4, xy) //- have: xyz==DI(0 0 x y z) //- have: DI(0 0 x y z) == DI(0 0 x y)*pv + z //- have: xyz == xy*pv + z //- want: 0 0 x y z == ID(5, xyz) //- ID(5, xyz) == ID(4, xyz/pv) + [xyz%pv] //- fundamental_div_mod, with: ...? //- == ID(4, xy) + [z] //- == 0 0 x y + [z] //- digitseq if (|digitseq|==0) { reveal_BEDigitSeqToInt_private(); assert x==0; reveal_BEIntToDigitSeq_private(); } else { calc ==> { true; { reveal_BEDigitSeqToInt_private(); } x == BEDigitSeqToInt_private(pv, digitseq) == BEDigitSeqToInt_private(pv, digitseq[0..|digitseq|-1])*pv + digitseq[|digitseq|-1]; { lemma_BEDigitSeqToInt_bound(pv, digitseq[0..|digitseq|-1]); lemma_fundamental_div_mod_converse( x, pv, BEDigitSeqToInt_private(pv, digitseq[0..|digitseq|-1]), digitseq[|digitseq|-1]); } x/pv == BEDigitSeqToInt_private(pv, digitseq[0..|digitseq|-1]) && x%pv == digitseq[|digitseq|-1]; { lemma_div_pos_is_pos(x, pv); //- lemma_div_is_strictly_ordered_by_denominator(x, pv); lemma_BEDigitSeqToInt_invertibility(pv, x/pv, digitseq[0..|digitseq|-1]); } BEIntToDigitSeq(pv, |digitseq|-1, x/pv) == digitseq[0..|digitseq|-1] && x%pv == digitseq[|digitseq|-1]; } calc { //- ID(5, xyz) BEIntToDigitSeq(pv, |digitseq|, x); { reveal_BEIntToDigitSeq_private(); } //- ID( 4, xyz/pv) + [xyz%pv] digitseq[0..|digitseq|-1] + [ digitseq[|digitseq|-1] ]; digitseq; } } } static lemma lemma_BEDigitSeqToInt_invertibility_tight(pv:int, x:int, digitseq:seq) requires 10; ensures digitseq == BEIntToDigitSeq(pv, |digitseq|, x); ensures digitseq == BEIntToDigitSeq(pv, 0, x); { lemma_BEDigitSeqToInt_invertibility(pv, x, digitseq); lemma_BEIntToDigitSeq_shortest_form(pv, digitseq, 0); } //-//////////////////////////////////////////////////////////////////////////// //- properties about IntToDigitSeq static predicate IsZero(sx:seq, xi:int) requires 0<=xi<|sx|; { sx[xi]==0 } static predicate AreEqual(sx:seq, xi:int, sy:seq, yi:int) requires 0<=xi<|sx|; requires 0<=yi<|sy|; { sx[xi]==sy[yi] } static lemma lemma_LeadingZeros(pv:int, short:seq, long:seq) requires 1 IsZero(long,i); requires forall i :: |long|-|short|<=i<|long| ==> AreEqual(long, i, short, i - (|long|-|short|)); decreases |short|; ensures BEDigitSeqToInt(pv, short) == BEDigitSeqToInt(pv, long); { if (|short|==0) { lemma_BEIntToDigitSeq_private_zero(pv, |short|); lemma_BEIntToDigitSeq_invertibility_zero(pv, short); lemma_BEIntToDigitSeq_private_zero(pv, |long|); forall (i | 0<=i<|long|) ensures long[i]==0; { assert IsZero(long, i); //- OBSERVE trigger } assert long == BEIntToDigitSeq_private(pv, |long|, 0); lemma_BEIntToDigitSeq_invertibility_zero(pv, long); } else { var shortp := short[..|short|-1]; var longp := long[..|long|-1]; calc { BEDigitSeqToInt(pv, short); { reveal_BEDigitSeqToInt_private(); } BEDigitSeqToInt_private(pv, short[0..|short|-1])*pv + short[|short|-1]; { lemma_vacuous_statement_about_a_sequence(short, |short|-1); } BEDigitSeqToInt_private(pv, shortp)*pv + short[|short|-1]; { //- Unwrap triggers forall (i | 0<=i<|longp|-|shortp|) ensures longp[i]==0; { assert IsZero(long, i); //- OBSERVE trigger } forall (i | |longp|-|shortp|<=i<|longp|) ensures AreEqual(longp, i, shortp, i - (|longp|-|shortp|)); { assert AreEqual(long, i, short, i - (|long|-|short|)); //- OBSERVE trigger } lemma_LeadingZeros(pv, shortp, longp); assert BEDigitSeqToInt(pv, shortp) == BEDigitSeqToInt(pv, longp); assert BEDigitSeqToInt_private(pv, shortp) == BEDigitSeqToInt_private(pv, longp); //- calc { //- long[|long|-1]; //- long[|long|-1-(|long|-|short|)]; //- short[|short|-1]; //- } assert AreEqual(long, |long|-1, short, |long|-1-(|long|-|short|)); assert short[|short|-1] == long[|long|-1]; } BEDigitSeqToInt_private(pv, longp)*pv + long[|long|-1]; { lemma_vacuous_statement_about_a_sequence(long, |long|-1); } BEDigitSeqToInt_private(pv, long[0..|long|-1])*pv + long[|long|-1]; { reveal_BEDigitSeqToInt_private(); } BEDigitSeqToInt(pv, long); } } } //- the "opposite" of lemma_LeadingZeros; lets us prove properties //- of the sequence structure when generating extra bits (e.g. converting //- a Word32 to a 32-bit sequence). static lemma lemma_zero_extension(pv:int, mp:nat, x:nat, tight:seq) requires 1) returns (TM:seq) requires 10; { var ptr:=0; assert M[ptr..] == M; while (ptr<|M| && M[ptr]==0) invariant 0<=ptr<=|M|; invariant forall j :: 0<=j M[j]==0; invariant BEDigitSeqToInt(pv, M[ptr..]) == BEDigitSeqToInt(pv, M); { ptr := ptr + 1; lemma_LeadingZeros(pv, M[ptr..], M); } TM := M[ptr..]; } static lemma lemma_BEIntToDigitSeq_invertibility(pv:int, x:int, digitseq:seq) requires 10; var prefix := BEIntToDigitSeq_private(pv, |digitseq|-1, x/pv); var tail := [ x % pv ]; var digits := prefix + tail; assert 0<|digits|; lemma_div_pos_is_pos(x,pv); if (x/pv == 0) { if (x >= pv) { lemma_div_basics(pv); lemma_div_is_ordered(pv,x,pv); assert false; } assert x < pv; var prefix2 := BEIntToDigitSeq(pv, |digitseq|-1, x/pv); assert prefix2 == BEIntToDigitSeq(pv, |digitseq|-1, 0); lemma_BEIntToDigitSeq_private_zero(pv, |digitseq|-1); lemma_BEIntToDigitSeq_invertibility_zero(pv, prefix2); assert BEDigitSeqToInt(pv, prefix2) == 0; lemma_small_mod(x, pv); assert digitseq == prefix2 + [ x ]; calc { BEDigitSeqToInt_private(pv, digitseq); BEDigitSeqToInt_private(pv, digitseq[0..|digitseq|-1])*pv + digitseq[|digitseq|-1]; { lemma_vacuous_statement_about_a_sequence(digitseq, |digitseq|-1); } BEDigitSeqToInt_private(pv, prefix2)*pv + digitseq[|digitseq|-1]; mul(0,pv) + digitseq[|digitseq|-1]; { lemma_mul_basics_forall(); } 0 + digitseq[|digitseq|-1]; x; } } else { assert 00; lemma_div_is_strictly_ordered_by_denominator(x,pv); assert x/pv < x; lemma_BEIntToDigitSeq_invertibility(pv, x/pv, prefix); } x/pv; } } calc { BEDigitSeqToInt(pv, BEIntToDigitSeq(pv, |digitseq|, x)); BEDigitSeqToInt(pv, BEIntToDigitSeq_private(pv, |digitseq|, x)); //- { reveal_BEIntToDigitSeq_private(); } BEDigitSeqToInt(pv, BEIntToDigitSeq_private(pv, |digitseq|-1, x/pv) + [ x % pv ]); BEDigitSeqToInt(pv, prefix + tail); BEDigitSeqToInt(pv, digits); BEDigitSeqToInt_private(pv, digits[0..|digits|-1])*pv + digits[|digits|-1]; { calc { digits[0..|digits|-1]; BEIntToDigitSeq_private(pv, |digitseq|-1, x/pv); } } BEDigitSeqToInt_private(pv, BEIntToDigitSeq_private(pv, |digitseq|-1, x/pv))*pv + digits[|digits|-1]; BEDigitSeqToInt_private(pv, BEIntToDigitSeq_private(pv, |digitseq|-1, x/pv)) *pv + (x % pv); //- apply calcs proven in previous case analysis (x/pv)*pv + (x%pv); { lemma_mul_is_commutative_forall(); } pv*(x/pv) + (x%pv); { lemma_fundamental_div_mod(x,pv); } x; x; } } } //-//////////////////////////////////////////////////////////////////////////// //- more properties about IntToDigitSeq static lemma lemma_BEIntToDigitSeq_private_unbounded_mp_irrelevant(pv:int, x:int, mp1:int, mp2:int) requires 1 0 <= BEIntToDigitSeq_private(pv,mp,x)[i] < pv; ensures IsDigitSeq(pv, BEIntToDigitSeq_private(pv,mp,x)); { forall (i | 0<=i<|BEIntToDigitSeq_private(pv,mp,x)|) ensures 0 <= BEIntToDigitSeq_private(pv,mp,x)[i] < pv; { reveal_BEIntToDigitSeq_private(); if (0 x then mp else x; ensures IsDigitSeq(pv, BEIntToDigitSeq(pv, mp, x)); { if (x==0 && mp<=0) { reveal_BEIntToDigitSeq_private(); assert BEIntToDigitSeq(pv, mp, x) == []; assert IsDigitSeq(pv, BEIntToDigitSeq(pv, mp, x)); } else { reveal_BEIntToDigitSeq_private(); lemma_div_pos_is_pos(x,pv); if (x>0) { lemma_div_decreases(x,pv); lemma_IsDigitSeq_BEIntToDigitSeq(pv, mp-1, x/pv); calc { BEIntToDigitSeq(pv, mp, x); BEIntToDigitSeq_private(pv, mp-1, x/pv) + [ x % pv ]; } lemma_mod_properties(); } else { lemma_BEIntToDigitSeq_private_zero(pv, mp); } } } //- The converse of this lemma is lemma_BEDigitSeqToInt_invertibility static lemma lemma_BEInt_decoding_general(pv:int, mp:int, x:int) requires 1 x then mp else x; ensures IsDigitSeq(pv, BEIntToDigitSeq(pv, mp, x)); ensures BEDigitSeqToInt(pv, BEIntToDigitSeq(pv, mp, x)) == x; { lemma_IsDigitSeq_BEIntToDigitSeq(pv, mp, x); if (x==0) { if (mp<=0) { calc { BEDigitSeqToInt(pv, BEIntToDigitSeq(pv, mp, x)); { reveal_BEIntToDigitSeq_private(); } BEDigitSeqToInt(pv, []); { reveal_BEDigitSeqToInt_private(); } 0; x; } assert BEDigitSeqToInt(pv, BEIntToDigitSeq(pv, mp, x)) == x; } else { lemma_BEIntToDigitSeq_private_zero(pv, mp); lemma_BEIntToDigitSeq_private_zero(pv, mp-1); lemma_BEIntToDigitSeq_invertibility_zero(pv, BEIntToDigitSeq(pv, mp, 0)); lemma_BEIntToDigitSeq_invertibility_zero(pv, BEIntToDigitSeq(pv, mp-1, 0)); } } else { var digits := BEIntToDigitSeq_private(pv, mp-1, x/pv) + [ x % pv ]; lemma_div_decreases(x,pv); lemma_div_pos_is_pos(x,pv); lemma_IsDigitSeq_BEIntToDigitSeq(pv, mp-1, x/pv); calc { BEDigitSeqToInt(pv, BEIntToDigitSeq(pv, mp, x)); { reveal_BEIntToDigitSeq_private(); } BEDigitSeqToInt(pv, digits); { reveal_BEDigitSeqToInt_private(); } BEDigitSeqToInt_private(pv, digits[0..|digits|-1])*pv + digits[|digits|-1]; { assert digits[|digits|-1] == x%pv; } BEDigitSeqToInt_private(pv, digits[0..|digits|-1])*pv + x%pv; { assert digits[0..|digits|-1] == digits[..|digits|-1]; } BEDigitSeqToInt_private(pv, digits[..|digits|-1])*pv + x%pv; { calc { BEDigitSeqToInt_private(pv, digits[..|digits|-1]); { assert BEIntToDigitSeq(pv, mp-1, x/pv) == digits[..|digits|-1]; } BEDigitSeqToInt_private(pv, BEIntToDigitSeq(pv, mp-1, x/pv)); BEDigitSeqToInt(pv, BEIntToDigitSeq(pv, mp-1, x/pv)); { lemma_BEInt_decoding_general(pv, mp-1, x/pv); } x/pv; } } (x/pv)*pv + x%pv; { lemma_mul_is_commutative_forall(); lemma_fundamental_div_mod(x,pv); } x; } } } static lemma lemma_BEIntToByteSeq_decoding(x:int) requires 0<=x; decreases x; ensures IsDigitSeq(power2(8), BEIntToByteSeq(x)); ensures x == BEByteSeqToInt(BEIntToByteSeq(x)); { lemma_2toX(); lemma_BEInt_decoding_general(power2(8), 0, x); } static lemma lemma_BEIntToBitSeq_decoding(x:int) requires 0<=x; decreases x; ensures IsDigitSeq(power2(1), BEWordToBitSeq(x)); ensures x == BEBitSeqToInt(BEWordToBitSeq(x)); { reveal_power2(); lemma_2toX(); lemma_BEInt_decoding_general(power2(1), 32, x); } static lemma lemma_BEIntToDigitSeq_private_form(pv:int, i:int) requires 1) requires IsWordSeq(inseq); ensures 0 <= BEWordSeqToInt(inseq); ensures BEWordSeqToInt(inseq) < power2(32*|inseq|); { lemma_BEDigitSeqToInt_bound(power2(32), inseq); calc { BEWordSeqToInt(inseq); < power(power2(32), |inseq|); { lemma_power2_is_power_2(32); } power(power(2,32), |inseq|); { lemma_power_multiplies(2,32,|inseq|); } //-[dafnycc] power(2,mul(32, |inseq|)); { lemma_power2_is_power_2(mul(32, |inseq|)); } power2(mul(32, |inseq|)); { lemma_mul_is_mul_boogie(32, |inseq|); } power2(32*|inseq|); } } static lemma lemma_BEByteSeqToInt_bound(inseq:seq) requires IsByteSeq(inseq); ensures 0 <= BEByteSeqToInt(inseq); ensures BEByteSeqToInt(inseq) < power2(8*|inseq|); { lemma_BEDigitSeqToInt_bound(power2(8), inseq); calc { BEByteSeqToInt(inseq); < power(power2(8), |inseq|); { lemma_power2_is_power_2(8); } power(power(2,8), |inseq|); { lemma_power_multiplies(2,8,|inseq|); } //-[dafnycc] power(2,mul(8, |inseq|)); { lemma_power2_is_power_2(mul(8, |inseq|)); } power2(mul(8, |inseq|)); { lemma_mul_is_mul_boogie(8, |inseq|); } power2(8*|inseq|); } } static lemma lemma_BEDigitSeq_extract(pv:int, inseq:seq, i:nat) requires 1, i:nat) requires IsWordSeq(inseq); requires i < |inseq|; ensures inseq[|inseq|-1-i] == (BEWordSeqToInt(inseq) / power2(32*i)) % power2(32); { lemma_2toX(); lemma_BEDigitSeq_extract(power2(32), inseq, i); calc { power(power2(32),i); { lemma_power2_is_power_2(32); } power(power(2,32),i); { lemma_power_multiplies(2,32,i); } //-[dafnycc] power(2,mul(32,i)); { lemma_power2_is_power_2(mul(32,i)); } power2(mul(32,i)); { lemma_mul_is_mul_boogie(32,i); } power2(32*i); } } //-static lemma lemma_BEDigitSeqToInt_lower_bound(pv:nat, inseq:seq, i:nat) //- requires 0 < pv; //- requires IsDigitSeq(pv, inseq); //- requires i<|inseq|; //- ensures inseq[|inseq|-1-i] * power(pv, i) <= BEDigitSeqToInt(pv, inseq); //- decreases |inseq|; ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Util/seqs_canonical.i.dfy ================================================ include "seqs_and_ints.i.dfy" //- Reason about the lengths of sequences with no preceding zeros static predicate IsCanonicalDigitSeq(pv:nat, inseq:seq) { IsDigitSeq(pv, inseq) && (|inseq|>0 ==> inseq[0]!=0) } static lemma lemma_CanonicalLengthBound(pv:nat, inseq:seq, l:nat) requires IsCanonicalDigitSeq(pv, inseq); requires BEDigitSeqToInt(pv, inseq) < power(pv, l); ensures |inseq| <= l; { if (|inseq|>0) { if (l < |inseq|) { calc { power(pv, l); <= { lemma_power_increases(pv, l, |inseq|-1); } power(pv, |inseq|-1); <= { lemma_power_positive(pv, |inseq|-1); lemma_mul_increases(inseq[0], power(pv, |inseq|-1)); } inseq[0] * power(pv, |inseq|-1); <= { lemma_BEDigitSeqToInt_bound(pv, inseq); } BEDigitSeqToInt(pv, inseq); < power(pv,l); } } } } lemma lemma_CanonicalLength_inherit(pv:int, A:seq, B:seq, l:nat) requires 1, i:int) requires 1) : int decreases |digits|; { if (digits==[]) then 0 else LEDigitSeqToInt_private(place_value, digits[1..])*place_value + digits[0] } static function LEDigitSeqToInt(place_value:int, digits:seq) : int requires IsDigitSeq(place_value, digits); { LEDigitSeqToInt_private(place_value, digits) } //-//////////////////////////////////////////////////////////////////////////// //- Reverse //-//////////////////////////////////////////////////////////////////////////// static lemma{:dafnycc_conservative_seq_triggers} lemma_Reverse(os:seq, rs:seq) requires rs == Reverse(os); ensures |os| == |rs|; ensures forall i :: 0<=i<|os| ==> os[i] == rs[|rs|-1-i]; decreases |os|; { reveal_Reverse(); if (os==[]) { } else { var sos := os[0..|os|-1]; lemma_Reverse(sos, Reverse(sos)); forall (i | 0<=i<|os|) ensures os[i] == rs[|rs|-1-i]; { if (i==|os|-1) { } else { calc { os[i]; sos[i]; Reverse(sos)[|Reverse(sos)|-1-i]; rs[|rs|-1-i]; } } } } } static lemma lemma_Reverse_symmetry(os:seq, rs:seq) requires os == Reverse(rs); ensures rs == Reverse(os); { lemma_Reverse(os, Reverse(os)); assert |os| == |Reverse(os)|; assert forall i :: 0<=i<|os| ==> os[i] == Reverse(os)[|Reverse(os)|-1-i]; lemma_Reverse(rs, Reverse(rs)); assert |rs| == |Reverse(rs)|; assert forall i :: 0<=i<|rs| ==> rs[i] == Reverse(rs)[|Reverse(rs)|-1-i]; assert |Reverse(os)| == |os| == |Reverse(rs)| == |rs|; forall (i | 0<=i<|rs|) ensures Reverse(os)[i] == rs[i]; { } } static method{:dafnycc_conservative_seq_triggers} ReverseDigitSeq(ghost pv:int, ds:seq) returns (rs:seq) requires 1 ds[0..ptr][i] == os1[0..ptr][i]; } os1[0..ptr]; os1[0..|os1|-1]; } } [os1[|os1|-1]] + Reverse(os1[0..|os1|-1]); Reverse(os1); } ptr := ptr + 1; } assert ds[0..ptr] == ds; lemma_Reverse(ds, rs); lemma_ReverseDigitSeq_helper(pv, ds, ptr, rs); } static lemma lemma_ReverseDigitSeq_helper(pv:int, ds:seq, ptr:int, rs:seq) requires 0<= ptr <= |ds|; requires ds[0..ptr] == ds; requires 1 0<=rs[i], rs:seq) requires 1, rs:seq) requires 1 ds[i] == rs[|rs|-1-i]; decreases |ds|; ensures BEDigitSeqToInt(pv, ds) == LEDigitSeqToInt(pv, rs); { reveal_BEDigitSeqToInt_private(); reveal_LEDigitSeqToInt_private(); if (|ds|!=0) { lemma_Reverse_converts_endianness_inner(pv, ds[0..|ds|-1], rs[1..]); } } static lemma lemma_Reverse_converts_endianness(pv:int, ds:seq, rs:seq) requires 1, j:int) requires 0<=j<|intseq|; ensures intseq[0..j]==intseq[..j]; { } static lemma lemma_painful_statement_about_a_sequence(intseq:seq) ensures intseq==intseq[..|intseq|]; { } static lemma lemma_obvious_statement_about_a_sequence(boolseq:seq, j:int) requires 0<=j<|boolseq|-1; ensures boolseq[1..][j] == boolseq[j+1]; { } static lemma lemma_obvious_statement_about_a_sequence_int(intseq:seq, j:int) requires 0<=j<|intseq|-1; ensures intseq[1..][j] == intseq[j+1]; { } static lemma lemma_straightforward_statement_about_a_sequence(intseq:seq, j:int) requires 0<=j<|intseq|; ensures intseq[..j] + intseq[j..] == intseq; { } static lemma lemma_sequence_reduction(s:seq, b:nat) requires 0, b:seq, c:seq) ensures (a+b)+c == a+(b+c); { } static lemma lemma_subseq_concatenation(s: seq, left: int, middle: int, right: int) requires 0 <= left <= middle <= right <= |s|; ensures s[left..right] == s[left..middle] + s[middle..right]; { } static lemma lemma_seq_equality(a:seq, b:seq, len:int) requires |a| == |b| == len; requires forall i {:trigger a[i]}{:trigger b[i]} :: 0 <= i < len ==> a[i] == b[i]; ensures a == b; { assert forall i :: 0 <= i < len ==> a[i] == b[i]; } static lemma lemma_seq_suffix(s: seq, prefix_length: int, index: int) requires 0 <= prefix_length <= index < |s|; ensures s[index] == s[prefix_length..][index - prefix_length]; { } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Util/seqs_transforms.i.dfy ================================================ include "integer_sequences.s.dfy" include "../Math/div.i.dfy" include "../Math/power.i.dfy" include "../Math/power2.i.dfy" include "seqs_simple.i.dfy" include "seqs_and_ints.i.dfy" include "repeat_digit.i.dfy" include "../../Drivers/CPU/assembly.i.dfy" include "arrays.i.dfy" //-//////////////////////////////////////////////////////////////////////////// //- This file is focused on methods and lemmas that relate sequences of //- different digit place values, eg Bit and Byte sequences. //- It builds on seqs_and_ints, which establishes more fundamental lemmas //- about the meanings of digit sequences. static lemma lemma_power2_8_and_32() ensures power2(8)*power2(8)*power2(8)*power2(8) == power2(32); { lemma_mul_is_associative_forall(); lemma_power2_adds(8,8); lemma_power2_adds(16,16); } //-//////////////////////////////////////////////////////////////////////////// static lemma lemma_BEByteSeqToInt_unpack_four(m:seq, prefix:seq) requires IsByteSeq(m); requires 4<=|m|; requires IsByteSeq(prefix); requires prefix + m[|m|-4..] == m; ensures BEByteSeqToInt(m) == BEByteSeqToInt(prefix)*power2(32) + (((m[|m|-4])*power2(8) + m[|m|-3])*power2(8) + m[|m|-2])*power2(8) + m[|m|-1]; { reveal_BEDigitSeqToInt_private(); lemma_mul_basics_forall(); assert m[0..|m|-4] == prefix; calc { BEByteSeqToInt(m); BEDigitSeqToInt(power2(8), m); BEDigitSeqToInt_private(power2(8), m); BEDigitSeqToInt_private(power2(8), m); BEDigitSeqToInt_private(power2(8), m[0..|m|-1])*power2(8) + m[|m|-1]; (BEDigitSeqToInt_private(power2(8), m[0..|m|-1][0..|m[0..|m|-1]|-1])*power2(8) + m[0..|m|-1][|m[0..|m|-1]|-1])*power2(8) + m[|m|-1]; { lemma_sequence_reduction(m, |m|-1); } (BEDigitSeqToInt_private(power2(8), m[0..|m|-2])*power2(8) + m[|m|-2])*power2(8) + m[|m|-1]; ((BEDigitSeqToInt_private(power2(8), m[0..|m|-2][0..|m[0..|m|-2]|-1])*power2(8) + m[0..|m|-2][|m[0..|m|-2]|-1])*power2(8) + m[|m|-2])*power2(8) + m[|m|-1]; { lemma_sequence_reduction(m, |m|-2); } ((BEDigitSeqToInt_private(power2(8), m[0..|m|-3])*power2(8) + m[|m|-3])*power2(8) + m[|m|-2])*power2(8) + m[|m|-1]; (((BEDigitSeqToInt_private(power2(8), m[0..|m|-3][0..|m[0..|m|-3]|-1])*power2(8) + m[0..|m|-3][|m[0..|m|-3]|-1])*power2(8) + m[|m|-3])*power2(8) + m[|m|-2])*power2(8) + m[|m|-1]; { lemma_sequence_reduction(m, |m|-3); } (((BEDigitSeqToInt_private(power2(8), m[0..|m|-4])*power2(8) + m[|m|-4])*power2(8) + m[|m|-3])*power2(8) + m[|m|-2])*power2(8) + m[|m|-1]; { lemma_mul_is_distributive_forall(); lemma_mul_is_commutative_forall(); lemma_mul_is_associative_forall(); } BEDigitSeqToInt_private(power2(8), prefix)*(power2(8)*power2(8)*power2(8)*power2(8)) + (((m[|m|-4])*power2(8) + m[|m|-3])*power2(8) + m[|m|-2])*power2(8) + m[|m|-1]; BEByteSeqToInt(prefix)*(power2(8)*power2(8)*power2(8)*power2(8)) + (((m[|m|-4])*power2(8) + m[|m|-3])*power2(8) + m[|m|-2])*power2(8) + m[|m|-1]; { lemma_power2_8_and_32(); } BEByteSeqToInt(prefix)*power2(32) + (((m[|m|-4])*power2(8) + m[|m|-3])*power2(8) + m[|m|-2])*power2(8) + m[|m|-1]; } } static lemma lemma_BEByteSeqToInt_strip_four(m:seq, prefix:seq, suffix:seq) requires IsByteSeq(m); requires IsByteSeq(prefix); requires IsByteSeq(suffix); requires 4<=|m|; requires prefix == m[0..|m|-4]; requires suffix == m[|m|-4..]; ensures BEByteSeqToInt(m) == BEByteSeqToInt(prefix) * power2(32) + BEByteSeqToInt(suffix); ensures 0 <= BEByteSeqToInt(suffix) < power2(32); { reveal_BEDigitSeqToInt_private(); lemma_mul_basics_forall(); lemma_BEByteSeqToInt_unpack_four(m, prefix); calc { BEByteSeqToInt(suffix); BEDigitSeqToInt_private(power2(8), suffix); BEDigitSeqToInt_private(power2(8), suffix[0..|suffix|-1])*power2(8) + suffix[|suffix|-1]; (BEDigitSeqToInt_private(power2(8), suffix[0..|suffix|-1][0..|suffix[0..|suffix|-1]|-1])*power2(8) + suffix[0..|suffix|-1][|suffix[0..|suffix|-1]|-1])*power2(8) + suffix[|suffix|-1]; { lemma_sequence_reduction(suffix, |suffix|-1); } (BEDigitSeqToInt_private(power2(8), suffix[0..|suffix|-2])*power2(8) + suffix[|suffix|-2])*power2(8) + suffix[|suffix|-1]; ((BEDigitSeqToInt_private(power2(8), suffix[0..|suffix|-2][0..|suffix[0..|suffix|-2]|-1])*power2(8) + suffix[0..|suffix|-2][|suffix[0..|suffix|-2]|-1])*power2(8) + suffix[|suffix|-2])*power2(8) + suffix[|suffix|-1]; { lemma_sequence_reduction(suffix, |suffix|-2); } ((BEDigitSeqToInt_private(power2(8), suffix[0..|suffix|-3])*power2(8) + suffix[|suffix|-3])*power2(8) + suffix[|suffix|-2])*power2(8) + suffix[|suffix|-1]; (((BEDigitSeqToInt_private(power2(8), suffix[0..|suffix|-3][0..|suffix[0..|suffix|-3]|-1])*power2(8) + suffix[0..|suffix|-3][|suffix[0..|suffix|-3]|-1])*power2(8) + suffix[|suffix|-3])*power2(8) + suffix[|suffix|-2])*power2(8) + suffix[|suffix|-1]; { lemma_sequence_reduction(suffix, |suffix|-3); } (((BEDigitSeqToInt_private(power2(8), suffix[0..|suffix|-4])*power2(8) + suffix[|suffix|-4])*power2(8) + suffix[|suffix|-3])*power2(8) + suffix[|suffix|-2])*power2(8) + suffix[|suffix|-1]; (((BEDigitSeqToInt_private(power2(8), [])*power2(8) + suffix[0])*power2(8) + suffix[1])*power2(8) + suffix[2])*power2(8) + suffix[3]; ((suffix[0]*power2(8) + suffix[1])*power2(8) + suffix[2])*power2(8) + suffix[3]; (((m[|m|-4])*power2(8) + m[|m|-3])*power2(8) + m[|m|-2])*power2(8) + m[|m|-1]; } lemma_mul_nonnegative_forall(); assert 0 <= BEByteSeqToInt(suffix); calc { (m[|m|-4])*power2(8); <= { lemma_mul_inequality(m[|m|-4], power2(8)-1, power2(8)); } (power2(8)-1)*power2(8); { lemma_mul_is_distributive_forall(); } power2(8)*power2(8) - mul(1,power2(8)); power2(8)*power2(8) - power2(8); } calc { ((m[|m|-4])*power2(8) + m[|m|-3])*power2(8); <= { lemma_mul_inequality(((m[|m|-4])*power2(8) + m[|m|-3]), (power2(8)*power2(8) - power2(8) + m[|m|-3]), power2(8)); } (power2(8)*power2(8) - power2(8) + m[|m|-3])*power2(8); <= { lemma_mul_inequality((power2(8)*power2(8) - power2(8) + m[|m|-3]), (power2(8)*power2(8)-1), power2(8)); } (power2(8)*power2(8)-1)*power2(8); { lemma_mul_is_distributive_forall(); } (power2(8)*power2(8))*power2(8) - mul(1,power2(8)); (power2(8)*power2(8))*power2(8) - power2(8); } calc { (((m[|m|-4])*power2(8) + m[|m|-3])*power2(8) + m[|m|-2])*power2(8); <= { lemma_mul_inequality((((m[|m|-4])*power2(8) + m[|m|-3])*power2(8) + m[|m|-2]), ((power2(8)*power2(8))*power2(8) - power2(8) + m[|m|-2]), power2(8)); } ((power2(8)*power2(8))*power2(8) - power2(8) + m[|m|-2])*power2(8); <= { lemma_mul_inequality(((power2(8)*power2(8))*power2(8) - power2(8) + m[|m|-2]), ((power2(8)*power2(8))*power2(8) - 1), power2(8)); } ((power2(8)*power2(8))*power2(8) - 1)*power2(8); { lemma_mul_is_distributive_forall(); } ((power2(8)*power2(8))*power2(8))*power2(8) - mul(1,power2(8)); ((power2(8)*power2(8))*power2(8))*power2(8) - power2(8); } calc { BEByteSeqToInt(suffix); (((m[|m|-4])*power2(8) + m[|m|-3])*power2(8) + m[|m|-2])*power2(8) + m[|m|-1]; <= ((power2(8)*power2(8))*power2(8))*power2(8) - 1; { lemma_power2_adds(8,8); } (power2(16)*power2(8))*power2(8) - 1; { lemma_power2_adds(16,8); } power2(24)*power2(8) - 1; { lemma_power2_adds(24,8); } power2(32) - 1; } } static lemma lemma_BEIntToDigitSeq_produces_DigitSeq(pv:int, mp:int, x:int) requires 1 x then mp else x; { reveal_BEIntToDigitSeq_private(); if (10) //- prove decreases { lemma_div_decreases(x,pv); } else { lemma_small_div(); } forall (i | 0<=i<|BEIntToDigitSeq(pv, mp, x)|) ensures 0 <= BEIntToDigitSeq(pv, mp, x)[i] < pv; { if (i<|BEIntToDigitSeq(pv, mp, x)|-1) { lemma_BEIntToDigitSeq_produces_DigitSeq(pv, mp-1, x/pv); } else { lemma_mod_properties(); } } assert IsDigitSeq(pv, BEIntToDigitSeq(pv, mp, x)); //- BEIntToDigitSeq_private(pv, mp-1, x/pv) + [ x % pv ] } else { assert IsDigitSeq(pv, BEIntToDigitSeq(pv, mp, x)); } } static lemma lemma_BEIntToDigitSeq_private_properties(pv:int, mp:int, x:int) requires 1 0 <= BEIntToDigitSeq_private(pv,mp,x)[i] < pv; ensures IsDigitSeq(pv, BEIntToDigitSeq_private(pv,mp,x)); { reveal_BEIntToDigitSeq_private(); if (mp==0) { lemma_power_0(pv); assert x == 0; assert BEIntToDigitSeq_private(pv,mp,x) == []; } else { assert pv!=0; assert mp>0; calc { BEIntToDigitSeq_private(pv,mp,x); BEIntToDigitSeq_private(pv, mp-1, x/pv) + [ x % pv ]; } if (x/pv >= power(pv,mp-1)) { calc { x; >= { lemma_remainder_lower(x, pv); } (x/pv)*pv; >= { lemma_mul_inequality(power(pv,mp-1), x/pv, pv); } power(pv,mp-1)*pv; { reveal_power(); lemma_mul_is_commutative_forall(); } power(pv,mp); } assert false; } lemma_div_pos_is_pos(x,pv); lemma_BEIntToDigitSeq_private_properties(pv, mp-1, x/pv); assert |BEIntToDigitSeq_private(pv,mp,x)| == mp; forall (i | 0<=i, outbits:nat, scale:nat, inbits:nat) requires IsDigitSeq(power2(inbits), inseq); requires 0 { true; { lemma_fundamental_div_mod(v, power2(outbits*delta)); } v == power2(outbits*delta)*(v/power2(outbits*delta)) + v%power2(outbits*delta); v/power2(outbits) == (power2(outbits*delta)*(v/power2(outbits*delta)) + v%power2(outbits*delta))/power2(outbits); v/d == (a + b)/d; { calc { d*((a+b)/d); d*((a+b)/d) - R; { lemma_dividing_sums(a, b, d, R); } d*(a/d) + d*(b/d); { lemma_mul_is_distributive_forall(); } d*(a/d + b/d); } lemma_mul_one_to_one_pos(d, (a+b)/d, a/d+b/d); } v/d == a/d + b/d; v/d == a/d + left; } calc { a/d; (power2(outbits*delta)*(v/power2(outbits*delta))) / d; //- another application of lemma_adding_one_outbits ((d*power2(outbits*(delta-1)))*(v/power2(outbits*delta))) / d; { lemma_mul_is_associative_forall(); } (d*(power2(outbits*(delta-1))*(v/power2(outbits*delta)))) / d; { lemma_mul_is_commutative_forall(); } ((power2(outbits*(delta-1))*(v/power2(outbits*delta)))*d) / d; { lemma_div_pos_is_pos(v, power2(outbits*delta)); lemma_mul_nonnegative_forall(); assert 0<=power2(outbits*(delta-1))*(v/power2(outbits*delta)); assert 0= power2(outbits*(count-1))) { calc ==> { v/power2(outbits) >= power2(outbits*(count-1)); { lemma_mul_inequality(power2(outbits*(count-1)), v/power2(outbits), power2(outbits)); } (v/power2(outbits))*power2(outbits) >= power2(outbits*(count-1))*power2(outbits); { lemma_power2_adds(outbits*(count-1), outbits); } (v/power2(outbits))*power2(outbits) >= power2(outbits*(count-1)+outbits); { lemma_mul_is_distributive_forall(); } (v/power2(outbits))*power2(outbits) >= power2((outbits*count-mul(outbits,1))+outbits); { lemma_mul_basics_forall(); } (v/power2(outbits))*power2(outbits) >= power2(outbits*count); { lemma_mod_properties(); } (v/power2(outbits))*power2(outbits) + v%power2(outbits) >= power2(outbits*count); { lemma_fundamental_div_mod(v, power2(outbits)); lemma_mul_is_commutative_forall(); } v >= power2(outbits*count); } } assert v/power2(outbits) < power2(outbits*(count-1)); lemma_BEIntToDigitSeq_private_chop_proper(outbits, count-1, delta-1, v/power2(outbits)); } BEIntToDigitSeq_private(power2(outbits), count-1, v/power2(outbits)); } BEIntToDigitSeq_private(power2(outbits), count-1, v/power2(outbits)) + [ v % power2(outbits) ]; { reveal_BEIntToDigitSeq_private(); } BEIntToDigitSeq_private(power2(outbits), count, v); } } } static lemma lemma_BEIntToDigitSeq_private_chop(outbits:nat, count:nat, delta:nat, v:int) requires 0, headseq:seq, tailseq:seq, outbits:nat, scale:nat, inbits:nat) requires IsDigitSeq(power2(inbits), inseq); requires IsDigitSeq(power2(inbits), headseq); requires IsDigitSeq(power2(inbits), tailseq); requires inseq == headseq + tailseq; requires |tailseq| == 1; requires 0 { true; { lemma_BEDigitSeqToInt_bound(power2(inbits), inseq[0..|inseq|-1]); } 0 <= BEDigitSeqToInt_private(power2(inbits), inseq[0..|inseq|-1]) < power(power2(inbits), |inseq[0..|inseq|-1]|); 0 <= BEDigitSeqToInt_private(power2(inbits), inseq[0..|inseq|-1]) < power(power2(inbits), |inseq|-1); 0 <= BEDigitSeqToInt_private(power2(inbits), inseq[0..|inseq|-1]) <= power(power2(inbits), |inseq|-1)-1; { lemma_mul_inequality_forall(); } mul(0,power2(inbits)) <= mul(BEDigitSeqToInt_private(power2(inbits), inseq[0..|inseq|-1]),power2(inbits)) <= mul(power(power2(inbits), |inseq|-1)-1, power2(inbits)); { lemma_mul_basics_forall(); } 0 <= mul(BEDigitSeqToInt_private(power2(inbits), inseq[0..|inseq|-1]),power2(inbits)) <= mul(power(power2(inbits), |inseq|-1)-1, power2(inbits)); 0 <= mul(BEDigitSeqToInt_private(power2(inbits), inseq[0..|inseq|-1]),power2(inbits)) <= mul(power(power2(inbits), |inseq|-1) - 1, power2(inbits)); { lemma_mul_is_distributive_forall(); } 0 <= mul(BEDigitSeqToInt_private(power2(inbits), inseq[0..|inseq|-1]),power2(inbits)) <= mul(power(power2(inbits), |inseq|-1), power2(inbits))-mul(1,power2(inbits)); { lemma_mul_basics_forall(); } 0 <= mul(BEDigitSeqToInt_private(power2(inbits), inseq[0..|inseq|-1]),power2(inbits)) <= mul(power(power2(inbits), |inseq|-1), power2(inbits))-power2(inbits); 0 <= mul(BEDigitSeqToInt_private(power2(inbits), inseq[0..|inseq|-1]),power2(inbits)) + inseq[|inseq|-1] <= mul(power(power2(inbits), |inseq|-1), power2(inbits))-power2(inbits) + inseq[|inseq|-1]; 0 <= bigv < mul(power(power2(inbits), |inseq|-1), power2(inbits))-power2(inbits) + power2(inbits); 0 <= bigv < mul(power(power2(inbits), |inseq|-1), power2(inbits)); { lemma_power_1(power2(inbits)); } 0 <= bigv < mul(power(power2(inbits), |inseq|-1), power(power2(inbits), 1)); { lemma_power_adds(power2(inbits), |inseq|-1, 1); } 0 <= bigv < power(power2(inbits), |inseq|-1+1); { lemma_power2_is_power_2(inbits); } 0 <= bigv < power(power(2, inbits), |inseq|-1+1); 0 <= bigv < power(power(2, inbits), |inseq|); { lemma_power_multiplies(2, inbits, |inseq|); } 0 <= bigv < power(2, inbits*|inseq|); { lemma_power2_is_power_2(inbits*|inseq|); } 0 <= bigv < power2(inbits*|inseq|); { lemma_mul_is_commutative_forall(); } 0 <= bigv < power2(|inseq|*inbits); 0 <= bigv < power2(|inseq|*(outbits*scale)); { lemma_mul_is_commutative_forall(); lemma_mul_is_associative_forall(); } 0 <= bigv < power2(outbits*(|inseq|*scale)); } calc { BEIntToDigitSeq(power2(outbits), |headseq|*scale, BEDigitSeqToInt(power2(inbits), headseq)) + BEIntToDigitSeq(power2(outbits), |tailseq|*scale, BEDigitSeqToInt(power2(inbits), tailseq)); BEIntToDigitSeq_private(power2(outbits), |headseq|*scale, BEDigitSeqToInt_private(power2(inbits), headseq)) + BEIntToDigitSeq_private(power2(outbits), |tailseq|*scale, BEDigitSeqToInt_private(power2(inbits), tailseq)); { assert |headseq| == |inseq|-1; assert |tailseq|==1; lemma_mul_basics(scale); assert |tailseq|*scale == scale; } BEIntToDigitSeq_private(power2(outbits), (|inseq|-1)*scale, BEDigitSeqToInt_private(power2(inbits), headseq)) + BEIntToDigitSeq_private(power2(outbits), scale, BEDigitSeqToInt_private(power2(inbits), tailseq)); { assert headseq == inseq[0..|inseq|-1]; } BEIntToDigitSeq_private(power2(outbits), (|inseq|-1)*scale, bigv/power2(inbits)) + BEIntToDigitSeq_private(power2(outbits), scale, bigv % power2(inbits)); BEIntToDigitSeq_private(power2(outbits), (|inseq|-1)*scale, bigv/power2(inbits)) + BEIntToDigitSeq_private(power2(outbits), scale, bigv % power2(inbits)); BEIntToDigitSeq_private(power2(outbits), (|inseq|-1)*scale, bigv/(power2(outbits*scale))) + BEIntToDigitSeq_private(power2(outbits), scale, bigv % (power2(outbits*scale))); { calc { (|inseq|-1)*scale; { lemma_mul_is_distributive_forall(); } |inseq|*scale-mul(1,scale); { lemma_mul_basics_forall(); } |inseq|*scale-scale; } } BEIntToDigitSeq_private(power2(outbits), |inseq|*scale-scale, bigv/power2(outbits*scale)) + BEIntToDigitSeq_private(power2(outbits), scale, bigv%power2(outbits*scale)); { lemma_mul_nonnegative(|inseq|,scale); assert bigv < power2(outbits*(|inseq|*scale)); lemma_mul_increases(|inseq|,scale); assert scale <= |inseq|*scale; lemma_BEIntToDigitSeq_private_chop_proper(outbits, |inseq|*scale, scale, bigv); } BEIntToDigitSeq_private(power2(outbits), |inseq|*scale, bigv); BEIntToDigitSeq_private(power2(outbits), |inseq|*scale, BEDigitSeqToInt_private(power2(inbits), inseq[0..|inseq|-1])*power2(inbits) + inseq[|inseq|-1]); //- expand defn BEIntToDigitSeq BEIntToDigitSeq(power2(outbits), |inseq|*scale, BEDigitSeqToInt_private(power2(inbits), inseq[0..|inseq|-1])*power2(inbits) + inseq[|inseq|-1]); { reveal_BEDigitSeqToInt_private(); } BEIntToDigitSeq(power2(outbits), |inseq|*scale, BEDigitSeqToInt(power2(inbits), inseq)); } } static lemma lemma_SeqTransformChop(inseq:seq, headseq:seq, tailseq:seq, outbits:nat, scale:nat, inbits:nat) requires IsDigitSeq(power2(inbits), inseq); requires IsDigitSeq(power2(inbits), headseq); requires IsDigitSeq(power2(inbits), tailseq); requires inseq == headseq + tailseq; requires 0, b:seq, c:seq) //- requires a == b + c; //- ensures a[|b|..] == c; //-{ //-} static lemma lemma_SeqTransformChopOne(inseq:seq, head:int, tailseq:seq, outbits:nat, scale:nat, inbits:nat) requires IsDigitSeq(power2(inbits), inseq); requires 0 <= head < power2(inbits); requires IsDigitSeq(power2(inbits), tailseq); requires inseq == [head] + tailseq; requires 0, headseq:seq, tailseq:seq) requires IsWordSeq(inseq); requires IsWordSeq(headseq); requires IsWordSeq(tailseq); requires inseq == headseq + tailseq; ensures BEWordSeqToBitSeq(headseq) + BEWordSeqToBitSeq(tailseq) == BEWordSeqToBitSeq(inseq); { lemma_mul_is_mul_boogie(1, 32); lemma_mul_is_mul_boogie(|inseq|, 32); lemma_mul_is_mul_boogie(|headseq|, 32); lemma_mul_is_mul_boogie(|tailseq|, 32); lemma_SeqTransformChop(inseq, headseq, tailseq, 1, 32, 32); } static lemma lemma_WordSeqToBitSeqChopOne(inseq:seq, head:int, tailseq:seq) requires IsWordSeq(inseq); requires Word32(head); requires IsWordSeq(tailseq); requires inseq == [head] + tailseq; ensures BEWordToBitSeq(head) + BEWordSeqToBitSeq(tailseq) == BEWordSeqToBitSeq(inseq); { lemma_mul_is_mul_boogie(1, 32); lemma_mul_is_mul_boogie(|inseq|, 32); lemma_mul_is_mul_boogie(|tailseq|, 32); lemma_SeqTransformChopOne(inseq, head, tailseq, 1, 32, 32); } static lemma lemma_WordSeqToBitSeqChopHead(inseq:seq) requires IsWordSeq(inseq); requires |inseq| > 0; ensures BEWordToBitSeq(inseq[0]) + BEWordSeqToBitSeq(inseq[1..]) == BEWordSeqToBitSeq(inseq); { lemma_WordSeqToBitSeqChopOne(inseq, inseq[0], inseq[1..]); } static lemma lemma_SeqTransformContentsTail(inseq:seq, tailseq:seq, outbits:nat, scale:nat, inbits:nat) requires IsDigitSeq(power2(inbits), inseq); requires 0<|inseq|; requires IsDigitSeq(power2(inbits), tailseq); requires inseq[|inseq|-1..] == tailseq; requires 0, truncseq:seq, outbits:nat, scale:nat, inbits:nat) requires IsDigitSeq(power2(inbits), inseq); requires 0<|inseq|; requires IsDigitSeq(power2(inbits), truncseq); requires inseq[..|inseq|-1] == truncseq; requires 0) ensures IsByteSeq(byteseq) ==> IsBitSeq(BEByteSeqToBitSeq(byteseq)); ensures IsByteSeq(byteseq) ==> |BEByteSeqToBitSeq(byteseq)| == |byteseq|*8; { if (IsByteSeq(byteseq)) { lemma_mul_is_mul_boogie(1,8); lemma_SeqTransform_structure(byteseq, 1, 8, 8); lemma_mul_is_mul_boogie(|byteseq|,8); } } static lemma lemma_BEWordSeqToByteSeq_ensures(wordseq:seq) ensures IsWordSeq(wordseq) ==> IsByteSeq(BEWordSeqToByteSeq(wordseq)); ensures IsWordSeq(wordseq) ==> |BEWordSeqToByteSeq(wordseq)| == |wordseq|*4; { if (IsWordSeq(wordseq)) { lemma_mul_is_mul_boogie(8,4); lemma_SeqTransform_structure(wordseq, 8, 4, 32); lemma_mul_is_mul_boogie(|wordseq|,4); } } static lemma lemma_BEWordSeqToBitSeq_ensures(wordseq:seq) ensures IsWordSeq(wordseq) ==> IsBitSeq(BEWordSeqToBitSeq(wordseq)); ensures IsWordSeq(wordseq) ==> |BEWordSeqToBitSeq(wordseq)| == |wordseq|*32; { if (IsWordSeq(wordseq)) { lemma_mul_is_mul_boogie(1,32); lemma_SeqTransform_structure(wordseq, 1, 32, 32); lemma_mul_is_mul_boogie(|wordseq|,32); } } static lemma lemma_concat_preserves_IsByteSeq(x:seq, y:seq) requires IsByteSeq(x); requires IsByteSeq(y); ensures IsByteSeq(x + y); { } static lemma lemma_BEByteSeqToBitSeq_BEWordSeqToByteSeq(wordseq:seq) requires IsWordSeq(wordseq); ensures IsByteSeq(BEWordSeqToByteSeq(wordseq)); ensures BEByteSeqToBitSeq(BEWordSeqToByteSeq(wordseq)) == BEWordSeqToBitSeq(wordseq); { var wordvalue := BEDigitSeqToInt(power2(32), wordseq); lemma_BEDigitSeqToInt_bound(power2(32), wordseq); var byteseq := BEIntToDigitSeq(power2(8), |wordseq|*4, wordvalue); assert byteseq == BEWordSeqToByteSeq(wordseq); lemma_power2_nonzero_bigger_than_one(); calc { BEDigitSeqToInt(power2(32), wordseq); < { lemma_BEDigitSeqToInt_bound(power2(32), wordseq); } power(power2(32), |wordseq|); { lemma_mul_is_mul_boogie(8, 4); lemma_pull_out_powers_of_2(8, 4, |wordseq|); lemma_mul_is_mul_boogie(4, |wordseq|); } power(power2(8), |wordseq|*4); } lemma_BEIntToDigitSeq_private_properties(power2(8), |wordseq|*4, BEDigitSeqToInt(power2(32), wordseq)); assert IsByteSeq(byteseq); var bytevalue := BEDigitSeqToInt(power2(8), byteseq); var bitseq := BEIntToDigitSeq(power2(1), |byteseq|*8, bytevalue); lemma_mul_is_mul_boogie(|wordseq|,4); calc { BEWordSeqToByteSeq(wordseq); BEIntToDigitSeq(power2(8), |wordseq|*4, wordvalue); } lemma_mul_is_mul_boogie(8,4); lemma_SeqTransform_structure(wordseq, 8, 4, 32); assert |byteseq| == |wordseq|*4; assert |byteseq|*8 == |wordseq|*32; calc { bytevalue; BEDigitSeqToInt(power2(8), byteseq); { lemma_2toX(); lemma_BEIntToDigitSeq_invertibility(power2(8), wordvalue, byteseq); } wordvalue; } calc { BEByteSeqToBitSeq(BEWordSeqToByteSeq(wordseq)); BEByteSeqToBitSeq(byteseq); BEIntToDigitSeq(power2(1), |byteseq|*8, BEDigitSeqToInt(power2(8), byteseq)); BEIntToDigitSeq(power2(1), |byteseq|*8, bytevalue); BEIntToDigitSeq(power2(1), |wordseq|*32, wordvalue); BEWordSeqToBitSeq(wordseq); } } static lemma lemma_BEIntToWordSeq_decomposition(data:seq, i:int) requires IsWordSeq(data); requires 0<=i<|data|*32; decreases |data|; ensures |BEIntToDigitSeq(2, 32, data[i/32])| == 32; ensures |BEIntToDigitSeq(2, |data|*32, BEDigitSeqToInt(power2(32), data))| == |data| * 32; ensures BEIntToDigitSeq(2, 32, data[i/32])[i%32] == BEIntToDigitSeq(2, |data|*32, BEDigitSeqToInt(power2(32), data))[i]; { lemma_2toX(); lemma_BEDigitSeqToInt_bound(power2(32), data); calc { power(power2(32), |data|); { lemma_power2_is_power_2(32); } power(power(2,32), |data|); { lemma_power_multiplies(2, 32, |data|); } power(2, mul(32,|data|)); { lemma_mul_is_mul_boogie(32,|data|); } power(2, |data|*32); } lemma_power2_is_power_2(32); assert data[i/32] < power(2,32); calc { 32; { lemma_BEIntToDigitSeq_private_properties(2, 32, data[i/32]); } |BEIntToDigitSeq(2, 32, data[i/32])|; } assert BEDigitSeqToInt(power2(32), data) < power(power2(32), |data|); calc { |data|*32; { lemma_BEIntToDigitSeq_private_properties(2, |data|*32, BEDigitSeqToInt(power2(32), data)); } |BEIntToDigitSeq(2, |data|*32, BEDigitSeqToInt(power2(32), data))|; } lemma_power2_1_is_2(); assert 0<|data|; if (|data|*32-32 <= i) { //- i points into last word. Collapse away front of sequence. var tailseq := data[|data|-1..]; lemma_mul_is_mul_boogie(1, 32); lemma_SeqTransform_structure(tailseq, 1, 32, 32); lemma_mul_is_mul_boogie(|tailseq|,32); assert |tailseq| == 1; assert IsDigitSeq(power2(32), tailseq); calc { BEIntToDigitSeq(2, 32, data[i/32]); BEIntToDigitSeq(2, 32, tailseq[0]); { lemma_mul_basics_forall(); } BEIntToDigitSeq(2, 32, mul(0,power2(32)) + tailseq[0]); { reveal_BEDigitSeqToInt_private(); } BEIntToDigitSeq(2, 32, mul(BEDigitSeqToInt_private(power2(32), []),power2(32)) + tailseq[0]); { assert [] == tailseq[0..|tailseq|-1]; } BEIntToDigitSeq(2, 32, BEDigitSeqToInt_private(power2(32), tailseq[0..|tailseq|-1])*power2(32) + tailseq[|tailseq|-1] ); { reveal_BEDigitSeqToInt_private(); } BEIntToDigitSeq(2, 32, BEDigitSeqToInt_private(power2(32), tailseq)); BEIntToDigitSeq(2, 32, BEDigitSeqToInt(power2(32), tailseq)); } calc { BEIntToDigitSeq(2, 32, data[i/32])[i%32]; BEIntToDigitSeq(2, 32, BEDigitSeqToInt(power2(32), tailseq))[i%32]; BEIntToDigitSeq(2, 32, BEDigitSeqToInt(power2(32), tailseq))[i-(|data|-1)*32]; { lemma_mul_basics_forall(); lemma_SeqTransformContentsTail(data, tailseq, 1, 32, 32); lemma_mul_is_mul_boogie(|data|,32); lemma_mul_is_mul_boogie(|data|-1,32); } BEIntToDigitSeq(2, |data|*32, BEDigitSeqToInt(power2(32), data))[(|data|-1)*32..][i-(|data|-1)*32]; BEIntToDigitSeq(2, |data|*32, BEDigitSeqToInt(power2(32), data))[i]; } } else { //- i doesn't point to last word; strip it off and recurse. //- i points to last word var truncseq := data[0..|data|-1]; calc { BEIntToDigitSeq(2, 32, data[i/32])[i%32]; BEIntToDigitSeq(2, 32, truncseq[i/32])[i%32]; { lemma_BEIntToWordSeq_decomposition(truncseq, i); } BEIntToDigitSeq(2, |truncseq|*32, BEDigitSeqToInt(power2(32), truncseq))[i]; { lemma_mul_basics_forall(); lemma_SeqTransformContentsLeft(data, truncseq, 1, 32, 32); lemma_mul_is_mul_boogie(|truncseq|,32); lemma_mul_is_mul_boogie(|data|,32); } BEIntToDigitSeq(2, |data|*32, BEDigitSeqToInt(power2(32), data))[..(|data|-1)*32][i]; BEIntToDigitSeq(2, |data|*32, BEDigitSeqToInt(power2(32), data))[i]; } } } //- converse of lemma_BEWordSeqToInt_BEIntToByteSeq static lemma lemma_BEIntToByteSeq_BEWordSeqToInt(byteseq:seq, wordseq:seq) requires IsByteSeq(byteseq); requires IsWordSeq(wordseq); requires BEByteSeqToInt(byteseq) == BEWordSeqToInt(wordseq); requires |byteseq| == |wordseq|*4; ensures BEWordSeqToByteSeq(wordseq) == byteseq; { lemma_2toX(); var intvalue := BEByteSeqToInt(byteseq); lemma_BEDigitSeqToInt_bound(power2(8), byteseq); assert 0<=intvalue; lemma_BEDigitSeqToInt_invertibility(power2(8), intvalue, byteseq); assert byteseq == BEIntToDigitSeq(power2(8), |byteseq|, intvalue); lemma_BEDigitSeqToInt_invertibility(power2(32), intvalue, wordseq); assert wordseq == BEIntToDigitSeq(power2(32), |wordseq|, intvalue); calc { BEWordSeqToByteSeq(wordseq); BEIntToDigitSeq(power2(8), |wordseq|*4, BEDigitSeqToInt(power2(32), wordseq)); BEIntToDigitSeq(power2(8), |byteseq|, BEDigitSeqToInt(power2(32), wordseq)); BEIntToDigitSeq(power2(8), |byteseq|, BEDigitSeqToInt(power2(8), byteseq)); BEIntToDigitSeq(power2(8), |byteseq|, intvalue); byteseq; } } //- converse of lemma_BEIntToByteSeq_BEWordSeqToInt static lemma lemma_BEWordSeqToInt_BEIntToByteSeq(byteseq:seq, wordseq:seq) requires IsByteSeq(byteseq); requires IsWordSeq(wordseq); requires BEWordSeqToByteSeq(wordseq) == byteseq; requires |byteseq| == |wordseq|*4; ensures BEByteSeqToInt(byteseq) == BEWordSeqToInt(wordseq); { lemma_2toX(); lemma_BEDigitSeqToInt_bound(power2(32), wordseq); calc { BEByteSeqToInt(byteseq); BEByteSeqToInt(BEWordSeqToByteSeq(wordseq)); BEDigitSeqToInt(power2(8), BEWordSeqToByteSeq(wordseq)); BEDigitSeqToInt(power2(8), BEIntToDigitSeq(power2(8), |wordseq|*4, BEDigitSeqToInt(power2(32), wordseq))); { lemma_BEInt_decoding_general(power2(8), |byteseq|, BEDigitSeqToInt(power2(32), wordseq)); } BEDigitSeqToInt(power2(32), wordseq); BEWordSeqToInt(wordseq); } } static lemma BEByteSeqToWordSeq_base1(bs:seq, ws:seq) requires |bs|==1; requires IsByteSeq(bs); requires ws == [bs[0]]; ensures IsWordSeq(ws); ensures BEWordSeqToInt(ws) == BEByteSeqToInt(bs); { reveal_BEDigitSeqToInt_private(); lemma_mul_basics_forall(); lemma_power2_increases(8,32); lemma_2toX(); calc { BEWordSeqToInt(ws); BEDigitSeqToInt(power2(32), ws[0..0])*power2(32) + ws[0]; BEDigitSeqToInt(power2(8), bs[0..0])*power2(8) + bs[0]; BEByteSeqToInt(bs); } } static lemma BEByteSeqToWordSeq_base2(bs:seq, ws:seq) requires |bs|==2; requires IsByteSeq(bs); requires ws == [bs[0] * 256 + bs[1]]; ensures IsWordSeq(ws); ensures BEWordSeqToInt(ws) == BEByteSeqToInt(bs); { reveal_BEDigitSeqToInt_private(); lemma_mul_basics_forall(); lemma_power2_increases(8,32); lemma_2toX(); calc { BEWordSeqToInt(ws); BEDigitSeqToInt(power2(32), ws[0..0])*power2(32) + ws[0]; bs[0] * 256 + bs[1]; { lemma_mul_is_mul_boogie(bs[0], power2(8)); } bs[0] * power2(8) + bs[1]; (BEDigitSeqToInt_private(power2(8), bs[0..0])*power2(8) + bs[0])*power2(8)+bs[1]; { lemma_sequence_reduction(bs, 1); } BEDigitSeqToInt(power2(8), bs[0..1])*power2(8) + bs[1]; BEByteSeqToInt(bs); } } static lemma BEByteSeqToWordSeq_base3(bs:seq, ws:seq) requires |bs|==3; requires IsByteSeq(bs); requires ws == [bs[0] * 256*256 + bs[1] * 256 + bs[2]]; ensures IsWordSeq(ws); ensures BEWordSeqToInt(ws) == BEByteSeqToInt(bs); { reveal_BEDigitSeqToInt_private(); lemma_mul_basics_forall(); lemma_power2_increases(8,32); lemma_2toX(); calc { BEWordSeqToInt(ws); BEDigitSeqToInt(power2(32), ws[0..0])*power2(32) + ws[0]; bs[0] * 256*256 + bs[1] * 256 + bs[2]; (bs[0] * 256 + bs[1]) * 256 + bs[2]; { lemma_mul_is_mul_boogie(bs[0], power2(8)); lemma_mul_is_mul_boogie(bs[0] * power2(8) + bs[1], power2(8)); } (bs[0] * power2(8) + bs[1]) * power2(8) + bs[2]; ((BEDigitSeqToInt_private(power2(8), bs[0..0])*power2(8) + bs[0])*power2(8)+bs[1])*power2(8) + bs[2]; (BEDigitSeqToInt_private(power2(8), bs[0..1])*power2(8)+bs[1])*power2(8) + bs[2]; { lemma_sequence_reduction(bs, 2); } BEDigitSeqToInt_private(power2(8), bs[0..2])*power2(8) + bs[2]; //- BEDigitSeqToInt_private(power2(8), bs); //- BEDigitSeqToInt(power2(8), bs); BEByteSeqToInt(bs); } } static lemma BEByteSeqToWordSeq_base4(bs:seq, ws:seq) requires |bs|==4; requires IsByteSeq(bs); requires ws == [bs[0] * 256*256*256 + bs[1] * 256*256 + bs[2] * 256 + bs[3]]; ensures IsWordSeq(ws); ensures BEWordSeqToInt(ws) == BEByteSeqToInt(bs); { reveal_BEDigitSeqToInt_private(); lemma_mul_basics_forall(); lemma_power2_increases(8,32); lemma_2toX(); calc { BEWordSeqToInt(ws); BEDigitSeqToInt(power2(32), ws[0..0])*power2(32) + ws[0]; bs[0] * 256*256*256 + bs[1] * 256*256 + bs[2] * 256 + bs[3]; ((bs[0] * 256 + bs[1]) * 256 + bs[2]) * 256 + bs[3]; { lemma_mul_is_mul_boogie(bs[0], power2(8)); lemma_mul_is_mul_boogie(bs[0] * power2(8) + bs[1], power2(8)); lemma_mul_is_mul_boogie((bs[0] * power2(8) + bs[1]) * power2(8) + bs[2], power2(8)); } ((bs[0] * power2(8) + bs[1]) * power2(8) + bs[2])*power2(8) + bs[3]; (((bs[0])*power2(8) + bs[1])*power2(8) + bs[2])*power2(8) + bs[3]; (((bs[|bs|-4])*power2(8) + bs[|bs|-3])*power2(8) + bs[|bs|-2])*power2(8) + bs[|bs|-1]; BEByteSeqToInt([])*power2(32) + (((bs[|bs|-4])*power2(8) + bs[|bs|-3])*power2(8) + bs[|bs|-2])*power2(8) + bs[|bs|-1]; { lemma_BEByteSeqToInt_unpack_four(bs, []); } BEByteSeqToInt(bs); } } static predicate BEByteSeqToWordSeq_base_props(bs:seq, ws:seq, padbytes:seq) requires IsByteSeq(bs); { IsWordSeq(ws) && (|bs|>0 ==> |ws|>0) && |ws| == (|bs|+3)/4 && BEByteSeqToInt(bs) == BEWordSeqToInt(ws) && |BEWordSeqToByteSeq(ws)| >= |bs| && padbytes == SequenceOfZeros(|ws|*4 - |bs|) && IsByteSeq(padbytes) && BEWordSeqToByteSeq(ws) == padbytes + bs && ((|bs|%4)==0 ==> BEWordSeqToByteSeq(ws) == bs) && |ws|<=1 } static method BEByteSeqToWordSeq_base(bs:seq) returns (ws:seq, ghost padbytes:seq) //- decreases |bs|; requires IsByteSeq(bs); requires |bs|<=4; ensures BEByteSeqToWordSeq_base_props(bs, ws, padbytes); //- ensures IsWordSeq(ws); //- ensures |bs|>0 ==> |ws|>0; //- ensures |ws| == (|bs|+3)/4; //- ensures BEByteSeqToInt(bs) == BEWordSeqToInt(ws); //- ensures |BEWordSeqToByteSeq(ws)| >= |bs|; //- ensures padbytes == SequenceOfZeros(|ws|*4 - |bs|); //- ensures IsByteSeq(padbytes); //- ensures BEWordSeqToByteSeq(ws) == padbytes + bs; //- ensures (|bs|%4)==0 ==> BEWordSeqToByteSeq(ws) == bs; //- ensures |ws|<=1; { reveal_BEDigitSeqToInt_private(); lemma_mul_basics_forall(); lemma_power2_increases(8,32); lemma_2toX(); if (|bs|==0) { ws := []; } else if (|bs|==1) { ws := [bs[0]]; BEByteSeqToWordSeq_base1(bs, ws); } else if (|bs|==2) { ws := [bs[0] * 256 + bs[1]]; BEByteSeqToWordSeq_base2(bs, ws); } else if (|bs|==3) { ws := [bs[0] * 256*256 + bs[1] * 256 + bs[2]]; BEByteSeqToWordSeq_base3(bs, ws); } else if (|bs|==4) { ws := [bs[0] * 256*256*256 + bs[1] * 256*256 + bs[2] * 256 + bs[3]]; BEByteSeqToWordSeq_base4(bs, ws); } else { assert false; ws := []; //- dafnycc } padbytes := SequenceOfZeros(|ws|*4 - |bs|); lemma_BEByteSeqToWordSeq_impl_helper(bs, ws, padbytes); } static lemma lemma_BEByteSeqToWordSeq_base_empty(bs:seq) returns (ws:seq, padbytes:seq) requires IsByteSeq(bs); requires |bs|==0; ensures BEByteSeqToWordSeq_base_props(bs, ws, padbytes); { ws := []; padbytes := []; reveal_BEDigitSeqToInt_private(); lemma_BEWordSeqToByteSeq_ensures(ws); } static method BEByteSeqToWordSeq_base_arrays(ba:array, a_off:nat, a_len:nat, ghost bs:seq) returns (wv:int, ghost ws:seq, ghost padbytes:seq) decreases |bs|; requires ba!=null; requires a_off+a_len <= ba.Length; requires ba[a_off..a_off+a_len]==bs; requires IsByteSeq(bs); requires |bs|<=4; ensures IsWordSeq(ws); ensures |bs|>0 ==> |ws|>0; ensures |bs|>0 ==> ws==[wv]; ensures |ws| == (|bs|+3)/4; ensures BEByteSeqToInt(bs) == BEWordSeqToInt(ws); ensures |BEWordSeqToByteSeq(ws)| >= |bs|; ensures padbytes == SequenceOfZeros(|ws|*4 - |bs|); ensures IsByteSeq(padbytes); ensures BEWordSeqToByteSeq(ws) == padbytes + bs; ensures (|bs|%4)==0 ==> BEWordSeqToByteSeq(ws) == bs; ensures |ws|<=1; { reveal_BEDigitSeqToInt_private(); lemma_mul_basics_forall(); lemma_power2_increases(8,32); lemma_2toX(); if (a_len==0) { wv := 0; ws := []; } else if (a_len==1) { wv := ba[a_off+0]; ws := [wv]; BEByteSeqToWordSeq_base1(bs, ws); } else if (a_len==2) { wv := ba[a_off+0] * 256 + ba[a_off+1]; ws := [wv]; BEByteSeqToWordSeq_base2(bs, ws); } else if (a_len==3) { wv := ba[a_off+0] * 256*256 + ba[a_off+1] * 256 + ba[a_off+2]; ws := [wv]; BEByteSeqToWordSeq_base3(bs, ws); } else if (a_len==4) { wv := ba[a_off+0] * 256*256*256 + ba[a_off+1] * 256*256 + ba[a_off+2] * 256 + ba[a_off+3]; ws := [wv]; BEByteSeqToWordSeq_base4(bs, ws); } else { assert false; wv := 0; //- dafnycc ws := []; //- dafnycc } padbytes := SequenceOfZeros(|ws|*4 - |bs|); lemma_BEByteSeqToWordSeq_impl_helper(bs, ws, padbytes); } static lemma lemma_BEByteSeqToWordSeq_impl_helper(bs:seq, ws:seq, padbytes:seq) requires IsByteSeq(bs); requires IsWordSeq(ws); requires IsByteSeq(padbytes); requires |bs| <= |ws|*4; requires |ws| == (|bs|+3)/4; requires BEWordSeqToInt(ws) == BEByteSeqToInt(bs); requires padbytes == SequenceOfZeros(|ws|*4 - |bs|); ensures |BEWordSeqToByteSeq(ws)| >= |bs|; ensures BEWordSeqToByteSeq(ws) == padbytes + bs; ensures (|bs|%4)==0 ==> BEWordSeqToByteSeq(ws) == bs; { lemma_2toX(); lemma_BEWordSeqToByteSeq_ensures(ws); assert |BEWordSeqToByteSeq(ws)| == |padbytes| + |bs|; ghost var padded_bs := padbytes + bs; calc { BEByteSeqToInt(padded_bs); { lemma_LeadingZeros(power2(8), bs, padded_bs); } BEByteSeqToInt(bs); BEWordSeqToInt(ws); } lemma_BEIntToByteSeq_BEWordSeqToInt(padded_bs, ws); assert BEWordSeqToByteSeq(ws) == padded_bs; assert BEWordSeqToByteSeq(ws) == padbytes + bs; if (|bs|%4==0) { lemma_round_down(|bs|, 3, 4); calc { |bs|; mul(4,div((|bs|+3),4)); mul(4,(|bs|+3)/4); { assert |ws| == (|bs|+3)/4; } mul(4,|ws|); { lemma_mul_is_mul_boogie(4, |ws|); } 4*|ws|; } lemma_BEIntToByteSeq_BEWordSeqToInt(bs, ws); } } static lemma lemma_BEByteSeqToInt_BEWordSeqToInt_concatenation(bsa:seq, bsb:seq, wsa:seq, wsb:seq) requires IsByteSeq(bsa); requires IsByteSeq(bsb); requires IsWordSeq(wsa); requires IsWordSeq(wsb); //- requires |bsa| == |wsa|*4; requires |bsb| == |wsb|*4; requires BEByteSeqToInt(bsa)==BEWordSeqToInt(wsa); requires BEByteSeqToInt(bsb)==BEWordSeqToInt(wsb); decreases |wsb|; ensures BEByteSeqToInt(bsa + bsb)==BEWordSeqToInt(wsa+wsb); { if (|wsb|==0) { assert bsa + bsb == bsa; assert wsa + wsb == wsa; } else { reveal_BEDigitSeqToInt_private(); var sub_bsb := bsb[..|bsb|-4]; var tail_bsb := bsb[|bsb|-4..]; assert sub_bsb + tail_bsb == bsb; var sub_wsb := wsb[..|wsb|-1]; var tail_wsb := wsb[|wsb|-1..]; assert sub_wsb + tail_wsb == wsb; lemma_BEByteSeqToInt_strip_four(bsb, sub_bsb, tail_bsb); assert BEByteSeqToInt(bsb) == BEByteSeqToInt(sub_bsb)*power2(32) + BEByteSeqToInt(tail_bsb); assert 0 <= BEByteSeqToInt(tail_bsb) < power2(32); lemma_fundamental_div_mod_converse(BEByteSeqToInt(bsb), power2(32), BEByteSeqToInt(sub_bsb), BEByteSeqToInt(tail_bsb)); calc { BEWordSeqToInt(tail_wsb); BEDigitSeqToInt_private(power2(32), tail_wsb[0..|tail_wsb|-1])*power2(32) + tail_wsb[|tail_wsb|-1]; BEDigitSeqToInt_private(power2(32), [])*power2(32) + tail_wsb[|tail_wsb|-1]; { lemma_mul_basics_forall(); } tail_wsb[|tail_wsb|-1]; tail_wsb[0]; } assert 0 <= BEWordSeqToInt(tail_wsb) < power2(32); calc { BEWordSeqToInt(wsb); BEDigitSeqToInt_private(power2(32), wsb[0..|wsb|-1])*power2(32) + wsb[|wsb|-1]; { lemma_vacuous_statement_about_a_sequence(wsb, |wsb|-1); } BEDigitSeqToInt_private(power2(32), sub_wsb)*power2(32) + wsb[|wsb|-1]; BEDigitSeqToInt_private(power2(32), sub_wsb)*power2(32) + tail_wsb[0]; BEWordSeqToInt(sub_wsb)*power2(32) + tail_wsb[0]; BEWordSeqToInt(sub_wsb)*power2(32) + BEWordSeqToInt(tail_wsb); } lemma_fundamental_div_mod_converse(BEWordSeqToInt(wsb), power2(32), BEWordSeqToInt(sub_wsb), BEWordSeqToInt(tail_wsb)); assert BEByteSeqToInt(sub_bsb)==BEWordSeqToInt(sub_wsb); assert BEByteSeqToInt(tail_bsb)==BEWordSeqToInt(tail_wsb); calc { BEByteSeqToInt(bsa+bsb); BEByteSeqToInt(bsa+bsb); BEByteSeqToInt(bsa+(sub_bsb+tail_bsb)); { lemma_seq_concatenation_associative(bsa, sub_bsb, tail_bsb); } //-{ assert bsa+(sub_bsb+tail_bsb) == (bsa+sub_bsb)+tail_bsb; } BEByteSeqToInt((bsa+sub_bsb)+tail_bsb); { lemma_BEByteSeqToInt_strip_four( (bsa+sub_bsb)+tail_bsb, bsa+sub_bsb, tail_bsb); } BEByteSeqToInt(bsa+sub_bsb)*power2(32) + BEByteSeqToInt(tail_bsb); { assert BEByteSeqToInt(sub_bsb)==BEWordSeqToInt(sub_wsb); lemma_BEByteSeqToInt_BEWordSeqToInt_concatenation(bsa, sub_bsb, wsa, sub_wsb); } BEWordSeqToInt(wsa+sub_wsb)*power2(32) + BEByteSeqToInt(tail_bsb); { assert BEByteSeqToInt(tail_bsb)==BEWordSeqToInt(tail_wsb); lemma_mul_basics_forall(); calc { BEByteSeqToInt([]); 0; BEWordSeqToInt([]); } lemma_BEByteSeqToInt_BEWordSeqToInt_concatenation(tail_bsb, [], tail_wsb, []); } BEWordSeqToInt(wsa+sub_wsb)*power2(32) + BEWordSeqToInt(tail_wsb); { reveal_BEDigitSeqToInt_private(); var digits := (wsa+sub_wsb)+tail_wsb; assert digits[0..|digits|-1] == (wsa+sub_wsb); assert digits[|digits|-1..] == tail_wsb; calc { digits[|digits|-1]; tail_wsb[0]; { lemma_mul_basics_forall(); } mul(0,power2(32)) + tail_wsb[0]; BEDigitSeqToInt_private(power2(32), [])*power2(32) + tail_wsb[0]; BEDigitSeqToInt_private(power2(32), tail_wsb[0..|tail_wsb|-1])*power2(32) + tail_wsb[0]; BEDigitSeqToInt_private(power2(32), tail_wsb[0..|tail_wsb|-1])*power2(32) + tail_wsb[|tail_wsb|-1]; BEDigitSeqToInt_private(power2(32), tail_wsb); BEWordSeqToInt(tail_wsb); } calc { BEWordSeqToInt((wsa+sub_wsb)+tail_wsb); BEDigitSeqToInt_private(power2(32), (wsa+sub_wsb))*power2(32) + tail_wsb[0]; BEWordSeqToInt(wsa+sub_wsb)*power2(32) + BEWordSeqToInt(tail_wsb); } assert IsWordSeq((wsa+sub_wsb)+tail_wsb); } BEWordSeqToInt((wsa+sub_wsb)+tail_wsb); { lemma_seq_concatenation_associative(wsa,sub_wsb,tail_wsb); } BEWordSeqToInt(wsa+(sub_wsb+tail_wsb)); BEWordSeqToInt(wsa+wsb); } } } static predicate BEByteSeqToWordSeq_loop_invariants( bs:seq, ptr:int, ws:seq) requires IsByteSeq(bs); requires |bs|>0; requires ptr <= |bs|; { ptr>0 && IsWordSeq(ws) && |bs[ptr..]| <= |ws|*4 && |ws| == (|bs[ptr..]|+3)/4 && BEWordSeqToInt(ws) == BEByteSeqToInt(bs[ptr..]) && (|bs|-ptr) % 4 == 0 && |bs[ptr..]| == mul(|ws|,4) } static lemma lemma_BEByteSeqToWordSeq_iterative_loop( bs:seq, prefix_bs:seq, prefix_word:seq, ptr:int, ws:seq, ptr':int, ws':seq) requires IsByteSeq(bs); requires |bs|>0; requires ptr <= |bs|; requires IsWordSeq(prefix_word); requires |prefix_word|==1; requires IsByteSeq(prefix_bs); requires ptr > 4; requires prefix_bs == bs[ptr-4..ptr]; requires BEByteSeqToInt(prefix_bs) == BEWordSeqToInt(prefix_word); requires BEByteSeqToWordSeq_loop_invariants(bs, ptr, ws); requires ptr' == ptr - 4; requires ws' == prefix_word + ws; ensures BEByteSeqToWordSeq_loop_invariants(bs, ptr', ws'); { calc { BEWordSeqToInt(ws'); BEWordSeqToInt(prefix_word + ws); { lemma_mul_is_mul_boogie(|ws|,4); assert |bs[ptr..]| == |ws|*4; lemma_BEByteSeqToInt_BEWordSeqToInt_concatenation( prefix_bs, bs[ptr..], prefix_word, ws); } BEByteSeqToInt(prefix_bs + bs[ptr..]); BEByteSeqToInt(prefix_bs + bs[ptr..]); BEByteSeqToInt(bs[ptr-4..ptr] + bs[ptr..]); { assert bs[ptr-4..ptr] + bs[ptr..] == bs[ptr-4..]; } BEByteSeqToInt(bs[ptr-4..]); } calc { (|bs| - ptr') % 4; (|bs| - (ptr-4)) % 4; (|bs| - ptr + 4) % 4; mod(|bs| - ptr + 4, 4); { lemma_mul_basics_forall(); lemma_mod_multiples_vanish(1, |bs|-ptr, 4); } mod(|bs| - ptr, 4); (|bs| - ptr) % 4; 0; } //- assert |ws|+1 == |ws'|; calc { |bs[ptr'..]|; |bs[ptr..]|+4; { lemma_mul_basics_forall(); } mul(|ws|,4)+mul(1,4); { lemma_mul_is_distributive_forall(); } mul(|ws|+1,4); mul(|ws'|,4); } } static lemma lemma_BEByteSeqToWordSeq_loop_invariants_initial(bs:seq, ptr:int, ws:seq) requires |bs|==ptr; requires |ws|==0; requires IsByteSeq(bs); requires |bs|>0; ensures BEByteSeqToWordSeq_loop_invariants(bs, ptr, ws); { calc { true; { reveal_BEDigitSeqToInt_private(); calc { BEWordSeqToInt(ws); BEWordSeqToInt([]); 0; BEByteSeqToInt([]); BEByteSeqToInt(bs[ptr..]); } } BEWordSeqToInt(ws) == BEByteSeqToInt(bs[ptr..]); { lemma_mul_basics(4); } BEByteSeqToWordSeq_loop_invariants(bs, ptr, ws); } } static lemma lemma_BEByteSeqToWordSeq_impl_final(bs:seq, ws:seq, padbytes:seq, ptr:int, old_ws:seq, prefix_bs:seq, prefix_word:seq) requires IsByteSeq(bs); requires IsByteSeq(prefix_bs); requires IsWordSeq(ws); requires IsWordSeq(prefix_word); requires 0 < ptr <= 4; requires (|bs|-ptr) % 4 == 0; requires ptr <= |bs|; requires BEByteSeqToWordSeq_loop_invariants(bs, ptr, old_ws); requires |old_ws| == (|bs[ptr..]|+3)/4; requires ws == prefix_word + old_ws; requires prefix_bs == bs[0..ptr]; requires BEByteSeqToWordSeq_base_props(prefix_bs, prefix_word, padbytes); ensures |ws| == (|bs|+3)/4; ensures BEByteSeqToInt(bs) == BEWordSeqToInt(ws); ensures |BEWordSeqToByteSeq(ws)| >= |bs|; ensures padbytes == SequenceOfZeros(|ws|*4 - |bs|); ensures BEWordSeqToByteSeq(ws) == padbytes + bs; ensures (|bs|%4)==0 ==> BEWordSeqToByteSeq(ws) == bs; { calc { |ws|; |prefix_word| + |old_ws|; |prefix_word| + (|bs[ptr..]|+3)/4; { assert BEByteSeqToWordSeq_base_props(prefix_bs, prefix_word, padbytes); assert |prefix_word| == (|prefix_bs|+3)/4; assert prefix_bs == bs[0..ptr]; } (|bs[0..ptr]|+3)/4 + (|bs[ptr..]|+3)/4; (ptr+3)/4 + (|bs|-ptr+3)/4; 1 + (|bs|-ptr)/4; (|bs|+3)/4; (|bs[0..]|+3)/4; } lemma_mul_is_mul_boogie(|old_ws|,4); assert |bs[ptr..]| == |old_ws|*4; lemma_BEByteSeqToInt_BEWordSeqToInt_concatenation( prefix_bs, bs[ptr..], prefix_word, old_ws); assert bs[0..ptr] + bs[ptr..] == bs[0..] + [] == bs; assert BEWordSeqToInt(ws) == BEByteSeqToInt(bs); calc { padbytes; SequenceOfZeros(|prefix_word|*4 - |bs[0..ptr]|); calc { |bs[0..ptr]|; ptr; |bs|-(|bs|-ptr); { assert (|bs|-ptr) % 4 == 0 ; } |bs|-((|bs|-ptr+3)/4)*4; |bs|-((|bs[ptr..]|+3)/4)*4; |bs|-|old_ws|*4; } SequenceOfZeros(|prefix_word|*4 + |old_ws|*4 - |bs|); SequenceOfZeros((|prefix_word| + |old_ws|)*4 - |bs|); SequenceOfZeros(|ws|*4 - |bs|); } lemma_BEByteSeqToWordSeq_impl_helper(bs, ws, padbytes); } static lemma lemma_WordsBytesEquivalence(bs:seq, ws:seq) requires IsByteSeq(bs); requires IsWordSeq(ws); requires BEByteSeqToInt(bs) == BEWordSeqToInt(ws); requires (|bs|%4)==0; requires |ws|*4==|bs|; ensures BEWordSeqToByteSeq(ws) == bs; ensures BEByteSeqToWordSeq(bs) == ws; { lemma_2toX(); lemma_BEDigitSeqToInt_bound(power2(8), bs); lemma_BEDigitSeqToInt_bound(power2(32), ws); lemma_BEDigitSeqToInt_invertibility(power2(8), BEByteSeqToInt(bs), bs); lemma_BEDigitSeqToInt_invertibility(power2(32), BEWordSeqToInt(ws), ws); } static method BEByteSeqToWordSeq_impl(bs:seq) returns (ws:seq, ghost padbytes:seq) //- decreases |bs|; requires IsByteSeq(bs); ensures IsWordSeq(ws); ensures |bs|>0 ==> |ws|>0; ensures |ws| == (|bs|+3)/4; ensures BEByteSeqToInt(bs) == BEWordSeqToInt(ws); ensures |BEWordSeqToByteSeq(ws)| >= |bs|; ensures padbytes == SequenceOfZeros(|ws|*4 - |bs|); ensures IsByteSeq(padbytes); ensures BEWordSeqToByteSeq(ws) == padbytes + bs; ensures (|bs|%4)==0 ==> BEWordSeqToByteSeq(ws) == bs; ensures (|bs|%4)==0 ==> BEByteSeqToWordSeq(bs) == ws; { lemma_mul_basics_forall(); lemma_power2_increases(8,32); lemma_2toX(); if (|bs|==0) { ws,padbytes := BEByteSeqToWordSeq_base([]); } else { ws := []; var prefix_bs; var prefix_word; ghost var old_ws; ghost var old_ptr; var ptr := |bs|; lemma_BEByteSeqToWordSeq_loop_invariants_initial(bs, ptr, ws); while (ptr > 4) invariant ptr <= |bs|; invariant BEByteSeqToWordSeq_loop_invariants(bs, ptr, ws); { prefix_bs := bs[ptr-4..ptr]; prefix_word,padbytes := BEByteSeqToWordSeq_base(prefix_bs); old_ws := ws; old_ptr := ptr; ws := prefix_word + ws; ghost var old_ptr2 := ptr; ptr := ptr - 4; lemma_BEByteSeqToWordSeq_iterative_loop( bs, prefix_bs, prefix_word, old_ptr2, old_ws, ptr, ws); } assert {:split_here} true; prefix_bs := bs[0..ptr]; prefix_word,padbytes := BEByteSeqToWordSeq_base(prefix_bs); old_ws := ws; assert |old_ws| == (|bs[ptr..]|+3)/4; ws := prefix_word + ws; lemma_BEByteSeqToWordSeq_impl_final(bs, ws, padbytes, ptr, old_ws, prefix_bs, prefix_word); } if ((|bs|%4)==0) { lemma_WordsBytesEquivalence(bs, ws); } } static method BEByteSeqToWordSeq_impl_arrays(ba:array, ghost bs:seq) returns (wa:array, ghost ws:seq, ghost padbytes:seq) requires ba!=null; requires ba[..]==bs; requires IsByteSeq(bs); ensures wa!=null; ensures wa[..]==ws; ensures IsWordSeq(ws); ensures |bs|>0 ==> |ws|>0; ensures |ws| == (|bs|+3)/4; ensures BEByteSeqToInt(bs) == BEWordSeqToInt(ws); ensures |BEWordSeqToByteSeq(ws)| >= |bs|; ensures padbytes == SequenceOfZeros(|ws|*4 - |bs|); ensures IsByteSeq(padbytes); ensures BEWordSeqToByteSeq(ws) == padbytes + bs; ensures (|bs|%4)==0 ==> BEWordSeqToByteSeq(ws) == bs; ensures fresh(wa); { if (ba.Length==0) { wa := new int[0]; ws,padbytes := lemma_BEByteSeqToWordSeq_base_empty([]); } else { wa := new int[(ba.Length+3)/4]; var ptr := ba.Length; var wptr := wa.Length; ws := wa[..wa.Length-wptr]; var wv:int; ghost var prefix_bs; ghost var prefix_word; ghost var old_ws; ghost var old_ptr; assert |bs|==ptr; lemma_BEByteSeqToWordSeq_loop_invariants_initial(bs, ptr, ws); while (ptr > 4) invariant ptr <= |bs|; invariant BEByteSeqToWordSeq_loop_invariants(bs, ptr, ws); invariant wptr == (ptr+3)/4; invariant wa[wptr..] == ws; { prefix_bs := bs[ptr-4..ptr]; wv,prefix_word,padbytes := BEByteSeqToWordSeq_base_arrays(ba, ptr-4, 4, prefix_bs); old_ws := ws; old_ptr := ptr; ws := prefix_word + ws; wptr := wptr - 1; wa[wptr] := wv; ghost var old_ptr2 := ptr; ptr := ptr - 4; lemma_BEByteSeqToWordSeq_iterative_loop( bs, prefix_bs, prefix_word, old_ptr2, old_ws, ptr, ws); } prefix_bs := bs[0..ptr]; wv,prefix_word,padbytes := BEByteSeqToWordSeq_base_arrays(ba, 0, ptr, prefix_bs); if (ptr>0) { old_ws := ws; wa[0] := wv; ws := wa[..wa.Length]; assert wv == prefix_word[0]; //- OBSERVE forall (i | 0<=i) returns (bs:seq) requires IsWordSeq(ws); decreases |ws|; ensures IsByteSeq(bs); ensures |bs| == |ws|*4; ensures BEByteSeqToInt(bs) == BEWordSeqToInt(ws); ensures BEWordSeqToByteSeq(ws) == bs; { reveal_BEDigitSeqToInt_private(); lemma_2toX(); lemma_mul_basics_forall(); if (|ws|==0) { bs := []; //- calc { //- BEByteSeqToInt(bs); //- 0; //- BEWordSeqToInt(ws); //- } } else if (|ws|==1) { var i := ws[0]; bs := [ i / 16777216, (i / 65536) % 256, (i / 256) % 256, i % 256 ]; calc { i; { lemma_fundamental_div_mod(i, 256); lemma_mul_is_commutative_forall(); } mul(div(i,256),256) + mod(i, 256); { lemma_fundamental_div_mod(div(i,256), 256); lemma_mul_is_commutative_forall(); } mul(mul(div(div(i,256),256),256) + mod(div(i,256),256),256) + mod(i, 256); { lemma_div_denominator_forall(); } mul(mul(div(i,mul(256,256)),256) + mod(div(i,256),256),256) + mod(i, 256); { lemma_mul_is_mul_boogie(256, 256); } mul(mul(div(i,65536),256) + mod(div(i,256),256),256) + mod(i, 256); { lemma_fundamental_div_mod(div(i,65536), 256); lemma_mul_is_commutative_forall(); } mul(mul(mul(div(div(i,65536),256),256) + mod(div(i,65536),256),256) + mod(div(i,256),256),256) + mod(i, 256); { lemma_div_denominator_forall(); } mul(mul(mul(div(i,mul(65536,256)),256) + mod(div(i,65536),256),256) + mod(div(i,256),256),256) + mod(i, 256); { lemma_mul_is_mul_boogie(65536, 256); } mul(mul(mul(div(i,16777216),256) + mod(div(i,65536),256),256) + mod(div(i,256),256),256) + mod(i, 256); mul(mul(mul(div(i,16777216),power2(8)) + mod(div(i,65536),256),power2(8)) + mod(div(i,256),256),power2(8)) + mod(i, 256); mul(mul(mul(i/16777216,power2(8)) + mod(i/65536,256),power2(8)) + mod(i/256,256),power2(8)) + mod(i, 256); mul(mul(mul(i/16777216,power2(8)) + (i/65536)%256,power2(8)) + (i/256)%256,power2(8)) + i%256; } calc { BEByteSeqToInt(bs); { lemma_BEByteSeqToInt_unpack_four(bs, []); } BEByteSeqToInt([])*power2(32) + (((bs[|bs|-4])*power2(8) + bs[|bs|-3])*power2(8) + bs[|bs|-2])*power2(8) + bs[|bs|-1]; (((bs[0])*power2(8) + bs[1])*power2(8) + bs[2])*power2(8) + bs[3]; mul(mul(mul(bs[0],power2(8)) + bs[1],power2(8)) + bs[2],power2(8)) + bs[3]; mul(mul(mul(i/16777216,power2(8)) + (i/65536)%256,power2(8)) + (i/256)%256,power2(8)) + i%256; i; BEDigitSeqToInt(power2(32), ws[0..0])*power2(32) + ws[0]; BEWordSeqToInt(ws); } } else { var prefix_words := ws[0..|ws|-1]; var suffix_words := ws[|ws|-1..]; var prefix_bytes := BEWordSeqToByteSeq_impl(prefix_words); var suffix_bytes := BEWordSeqToByteSeq_impl(suffix_words); bs := prefix_bytes + suffix_bytes; calc { BEByteSeqToInt(bs); { lemma_BEByteSeqToInt_strip_four(bs, prefix_bytes, suffix_bytes); } BEByteSeqToInt(prefix_bytes) * power2(32) + BEByteSeqToInt(suffix_bytes); BEWordSeqToInt(prefix_words) * power2(32) + BEWordSeqToInt(suffix_words); BEWordSeqToInt(prefix_words) * power2(32) + (BEDigitSeqToInt(power2(32), suffix_words[0..0])*power2(32) + suffix_words[0]); BEDigitSeqToInt(power2(32), ws[0..|ws|-1])*power2(32) + ws[|ws|-1]; BEWordSeqToInt(ws); } } lemma_BEIntToByteSeq_BEWordSeqToInt(bs, ws); } static predicate BEWordSeqToByteSeq_iterative_loop_invariant(ws:seq, bs:seq, ptr:int) requires IsWordSeq(ws); { 0 <= ptr <= |ws| && IsByteSeq(bs) && |bs| == mul(|ws[ptr..]|,4) && BEByteSeqToInt(bs) == BEWordSeqToInt(ws[ptr..]) } static function method SplitOneWord(i:int) : seq requires Word32(i); { [ i / 16777216, (i / 65536) % 256, (i / 256) % 256, i % 256 ] } static lemma lemma_BEWordSeqToByteSeq_iterative_loop(ws:seq, bs:seq, ptr:int, bs':seq, ptr':int) requires IsWordSeq(ws); requires BEWordSeqToByteSeq_iterative_loop_invariant(ws, bs, ptr); requires ptr > 0; requires ptr' == ptr - 1; requires bs' == SplitOneWord(ws[ptr']) + bs; ensures BEWordSeqToByteSeq_iterative_loop_invariant(ws, bs', ptr'); { lemma_2toX(); reveal_BEDigitSeqToInt_private(); lemma_mul_basics_forall(); var i := ws[ptr']; var newbytes := SplitOneWord(ws[ptr']); calc { i; { lemma_fundamental_div_mod(i, 256); lemma_mul_is_commutative_forall(); } mul(div(i,256),256) + mod(i, 256); { lemma_fundamental_div_mod(div(i,256), 256); lemma_mul_is_commutative_forall(); } mul(mul(div(div(i,256),256),256) + mod(div(i,256),256),256) + mod(i, 256); { lemma_div_denominator_forall(); } mul(mul(div(i,mul(256,256)),256) + mod(div(i,256),256),256) + mod(i, 256); { lemma_mul_is_mul_boogie(256, 256); } mul(mul(div(i,65536),256) + mod(div(i,256),256),256) + mod(i, 256); { lemma_fundamental_div_mod(div(i,65536), 256); lemma_mul_is_commutative_forall(); } mul(mul(mul(div(div(i,65536),256),256) + mod(div(i,65536),256),256) + mod(div(i,256),256),256) + mod(i, 256); { lemma_div_denominator_forall(); } mul(mul(mul(div(i,mul(65536,256)),256) + mod(div(i,65536),256),256) + mod(div(i,256),256),256) + mod(i, 256); { lemma_mul_is_mul_boogie(65536, 256); } mul(mul(mul(div(i,16777216),256) + mod(div(i,65536),256),256) + mod(div(i,256),256),256) + mod(i, 256); mul(mul(mul(div(i,16777216),power2(8)) + mod(div(i,65536),256),power2(8)) + mod(div(i,256),256),power2(8)) + mod(i, 256); mul(mul(mul(i/16777216,power2(8)) + mod(i/65536,256),power2(8)) + mod(i/256,256),power2(8)) + mod(i, 256); mul(mul(mul(i/16777216,power2(8)) + (i/65536)%256,power2(8)) + (i/256)%256,power2(8)) + i%256; } var nbs := newbytes; var ows := ws[ptr..]; var nws := [ws[ptr']]; calc { BEByteSeqToInt(nbs); { lemma_BEByteSeqToInt_unpack_four(nbs, []); } BEByteSeqToInt([])*power2(32) + (((nbs[|nbs|-4])*power2(8) + nbs[|nbs|-3])*power2(8) + nbs[|nbs|-2])*power2(8) + nbs[|nbs|-1]; (((nbs[0])*power2(8) + nbs[1])*power2(8) + nbs[2])*power2(8) + nbs[3]; mul(mul(mul(nbs[0],power2(8)) + nbs[1],power2(8)) + nbs[2],power2(8)) + nbs[3]; mul(mul(mul(i/16777216,power2(8)) + (i/65536)%256,power2(8)) + (i/256)%256,power2(8)) + i%256; i; BEDigitSeqToInt(power2(32), nws[0..0])*power2(32) + nws[0]; BEWordSeqToInt(nws); } calc { |bs'|; |bs| + 4; mul(|ws[ptr..]|,4) + 4; mul(|ws[ptr'..]|-1,4) + 4; { lemma_mul_is_distributive_forall(); } mul(|ws[ptr'..]|,4)+ mul(-1,4) + 4; { lemma_mul_is_mul_boogie(-1,4); } mul(|ws[ptr'..]|,4); } calc { BEByteSeqToInt(bs'); BEByteSeqToInt(newbytes+bs); { lemma_mul_is_mul_boogie(|ows|,4); lemma_BEByteSeqToInt_BEWordSeqToInt_concatenation( newbytes, bs, nws, ows); } BEWordSeqToInt(nws+ows); BEWordSeqToInt([ws[ptr']] + ws[ptr..]); { assert [ws[ptr']] + ws[ptr..] == ws[ptr'..]; } BEWordSeqToInt(ws[ptr'..]); } } static method BEWordSeqToByteSeq_impl(ws:seq) returns (bs:seq) requires IsWordSeq(ws); decreases |ws|; ensures IsByteSeq(bs); ensures |bs| == |ws|*4; ensures BEByteSeqToInt(bs) == BEWordSeqToInt(ws); ensures BEWordSeqToByteSeq(ws) == bs; ensures BEByteSeqToWordSeq(bs) == ws; { reveal_BEDigitSeqToInt_private(); lemma_mul_basics_forall(); lemma_power2_increases(8,32); lemma_2toX(); if (|ws|==0) { bs := []; assert BEByteSeqToInt(bs) == BEWordSeqToInt(ws); assert |bs| == |ws|*4; } else { bs := []; ghost var old_bs; ghost var old_ptr; var ptr := |ws|; calc { |bs|; 0; { lemma_mul_basics_forall(); } |ws[ptr..]|*4; } while (ptr > 0) invariant BEWordSeqToByteSeq_iterative_loop_invariant(ws, bs, ptr); { old_bs := bs; old_ptr := ptr; ptr := ptr - 1; var i := ws[ptr]; bs := SplitOneWord(ws[ptr]) + bs; lemma_BEWordSeqToByteSeq_iterative_loop(ws, old_bs, old_ptr, bs, ptr); } assert ptr==0; assert ws == ws[0..]; assert ws == ws[0..]; assert BEByteSeqToInt(bs) == BEWordSeqToInt(ws); } lemma_mul_is_mul_boogie(|ws|,4); assert |bs| == |ws|*4; lemma_BEIntToByteSeq_BEWordSeqToInt(bs, ws); lemma_WordsBytesEquivalence(bs, ws); } //-lemma lemma_NSeqIntConcatMultiplePreservesIsDigitSeq(place_value:int, seqs:seq>) //- requires forall i :: 0 <= i < |seqs| ==> IsDigitSeq(place_value, seqs[i]); //- ensures IsDigitSeq(place_value, NSeqIntConcatMultiple(seqs)); //- decreases |seqs|; //-{ //- reveal_NSeqIntConcatMultiple(); //- if |seqs| > 0 { //- lemma_NSeqIntConcatMultiplePreservesIsDigitSeq(place_value, seqs[1..]); //- lemma_concat_preserves_IsDigitSeq(place_value, seqs[0], NSeqIntConcatMultiple(seqs[1..])); //- } //-} static lemma lemma_concat_preserves_IsDigitSeq(place_value:int, x:seq, y:seq) requires IsDigitSeq(place_value, x); requires IsDigitSeq(place_value, y); ensures IsDigitSeq(place_value, x + y); { } static lemma lemma_BEByteSeqToBitSeq_selection(bs:seq, len:int) requires IsByteSeq(bs); requires 0 <= len <= |bs|; ensures |BEByteSeqToBitSeq(bs)| >= len*8; ensures BEByteSeqToBitSeq(bs)[..len*8] == BEByteSeqToBitSeq(bs[..len]); { lemma_BEByteSeqToBitSeq_ensures(bs); calc { |BEByteSeqToBitSeq(bs)[..len*8]|; len*8; { lemma_BEByteSeqToBitSeq_ensures(bs[..len]); } |BEByteSeqToBitSeq(bs[..len])|; } forall (i | 0<=i<|BEByteSeqToBitSeq(bs)[..len*8]|) ensures BEByteSeqToBitSeq(bs)[..len*8][i] == BEByteSeqToBitSeq(bs[..len])[i]; { lemma_mul_is_mul_boogie(1,8); var headbs := bs[..len]; var tailbs := bs[len..]; calc { BEByteSeqToBitSeq(headbs) + BEByteSeqToBitSeq(tailbs); BEIntToDigitSeq(power2(1), |headbs|*8, BEDigitSeqToInt(power2(8), headbs)) + BEIntToDigitSeq(power2(1), |tailbs|*8, BEDigitSeqToInt(power2(8), tailbs)); { lemma_SeqTransformChop(bs, headbs, tailbs, 1, 8, 8); lemma_mul_is_mul_boogie(|headbs|,8); lemma_mul_is_mul_boogie(|tailbs|,8); lemma_mul_is_mul_boogie(|bs|,8); } BEIntToDigitSeq(power2(1), |bs|*8, BEDigitSeqToInt(power2(8), bs)); BEByteSeqToBitSeq(bs); } calc { BEByteSeqToBitSeq(bs)[..len*8][i]; BEByteSeqToBitSeq(bs)[i]; BEByteSeqToBitSeq(headbs)[i]; BEByteSeqToBitSeq(bs[..len])[i]; } } } static method BEWordToFourBytes_impl(x:int) returns (bytes:seq) requires Word32(x); ensures bytes == BEWordToFourBytes(x); ensures IsByteSeq(bytes); ensures |bytes| == 4; ensures BEByteSeqToInt(bytes) == x; { bytes := BEWordSeqToByteSeq_impl([x]); calc { x; { lemma_mul_basics_forall(); } mul(0,power2(32)) + [x][|[x]|-1]; { reveal_BEDigitSeqToInt_private(); } BEDigitSeqToInt_private(power2(32), [])*power2(32)+ [x][|[x]|-1]; { assert [] == [x][0..|[x]|-1]; } BEDigitSeqToInt_private(power2(32), [x][0..|[x]|-1])*power2(32)+ [x][|[x]|-1]; { reveal_BEDigitSeqToInt_private(); } BEDigitSeqToInt_private(power2(32), [x]); BEDigitSeqToInt(power2(32), [x]); BEDigitSeqToInt(power2(8), bytes); } lemma_2toX(); lemma_BEDigitSeqToInt_invertibility(power2(8), x, bytes); } static lemma lemma_BEWordToFourBytesUnique(a:int, b:int) requires Word32(a); requires Word32(b); requires BEWordToFourBytes(a) == BEWordToFourBytes(b); ensures a == b; { lemma_2toX(); calc { power(power2(8), 4); { lemma_power2_is_power_2(8); } power(power(2, 8), 4); { lemma_power_multiplies(2,8,4); } power(2, mul(8, 4)); { lemma_mul_is_mul_boogie(8,4); } power(2, 32); { lemma_power2_is_power_2(32); } power2(32); } assert power(power2(8), 4) == power2(32); lemma_BEIntToDigitSeq_private_properties(power2(8), 4, a); lemma_BEIntToDigitSeq_private_properties(power2(8), 4, b); lemma_BEIntToDigitSeq_invertibility(power2(8), a, BEWordToFourBytes(a)); lemma_BEIntToDigitSeq_invertibility(power2(8), b, BEWordToFourBytes(b)); } static lemma lemma_BEWordToFourBytes_literal(x:int) requires 0<=x, n:int) requires 0 < n <= |s|; ensures s[0..n][0..n-1] == s[0..n-1]; { assert |s[0..n][0..n-1]| == n-1; forall i | 0 <= i < n - 1 ensures s[0..n][0..n-1][i] == s[0..n-1][i]; { calc { s[0..n][0..n-1][i]; s[0..n][i]; s[0..n-1][i]; } } } static lemma lemma_BEFourBytesToWordIsWord(bs:seq) requires IsByteSeqOfLen(bs, 4); ensures Word32(BEByteSeqToInt(bs)); { lemma_BEByteSeqToInt_bound(bs); calc { BEByteSeqToInt(bs); < power2(8*|bs|); <= power2(8*4); == power2(32); } } static method BEFourBytesToWord_impl(bs:seq) returns (ret:int) requires IsByteSeqOfLen(bs, 4); ensures ret == BEByteSeqToInt(bs); ensures Word32(ret); { var ws, padbytes := BEByteSeqToWordSeq_impl(bs); ret := ws[0]; reveal_BEDigitSeqToInt_private(); calc { BEWordSeqToInt(ws); BEDigitSeqToInt_private(power2(32), ws[0..|ws|-1])*power2(32) + ws[0]; { assert |ws|==1; assert ws[0..|ws|-1] == ws[0..0] == []; } BEDigitSeqToInt_private(power2(32), [])*power2(32) + ws[0]; { lemma_mul_is_mul_boogie(0, power2(32)); } 0*power2(32) + ws[0]; } lemma_BEFourBytesToWordIsWord(bs); } static lemma lemma_ValueOfFourByteSeq(s:seq) requires IsByteSeqOfLen(s, 4); ensures BEByteSeqToInt(s) == 0x1000000 * s[0] + 0x10000 * s[1] + 0x100 * s[2] + s[3]; { reveal_BEDigitSeqToInt_private(); calc { BEByteSeqToInt(s); BEDigitSeqToInt_private(power2(8), s); BEDigitSeqToInt_private(power2(8), s[0..3])*power2(8) + s[3]; { lemma_AllButLastOfPrefixIsPrefix(s, 3); } (BEDigitSeqToInt_private(power2(8), s[0..2])*power2(8) + s[2])*power2(8) + s[3]; { lemma_AllButLastOfPrefixIsPrefix(s, 2); } ((BEDigitSeqToInt_private(power2(8), s[0..1])*power2(8) + s[1])*power2(8) + s[2])*power2(8) + s[3]; { lemma_AllButLastOfPrefixIsPrefix(s, 1); } (((BEDigitSeqToInt_private(power2(8), s[0..0])*power2(8) + s[0])*power2(8) + s[1])*power2(8) + s[2])*power2(8) + s[3]; (((BEDigitSeqToInt_private(power2(8), [])*power2(8) + s[0])*power2(8) + s[1])*power2(8) + s[2])*power2(8) + s[3]; { lemma_mul_is_mul_boogie(0, power2(8)); } (((0*power2(8) + s[0])*power2(8) + s[1])*power2(8) + s[2])*power2(8) + s[3]; ((s[0]*power2(8) + s[1])*power2(8) + s[2])*power2(8) + s[3]; { lemma_mul_is_commutative_forall(); } power2(8)*(power2(8)*(power2(8)*s[0] + s[1]) + s[2]) + s[3]; { lemma_mul_is_distributive_add(power2(8), power2(8)*s[0], s[1]); } power2(8)*(power2(8)*(power2(8)*s[0]) + power2(8)*s[1] + s[2]) + s[3]; { lemma_mul_is_distributive_add(power2(8), power2(8)*(power2(8)*s[0]) + power2(8)*s[1], s[2]); } power2(8)*(power2(8)*(power2(8)*s[0]) + power2(8)*s[1]) + power2(8)*s[2] + s[3]; { lemma_mul_is_distributive_add(power2(8), power2(8)*(power2(8)*s[0]), power2(8)*s[1]); } power2(8)*(power2(8)*(power2(8)*s[0])) + power2(8)*(power2(8)*s[1]) + power2(8)*s[2] + s[3]; { lemma_mul_is_associative_forall(); } power2(8)*power2(8)*power2(8)*s[0] + power2(8)*power2(8)*s[1] + power2(8)*s[2] + s[3]; { lemma_power2_adds(8, 8); } power2(16)*power2(8)*s[0] + power2(16)*s[1] + power2(8)*s[2] + s[3]; { lemma_power2_adds(16, 8); } power2(24)*s[0] + power2(16)*s[1] + power2(8)*s[2] + s[3]; { lemma_2to32(); lemma_mul_is_mul_boogie(0x1000000, s[0]); lemma_mul_is_mul_boogie(0x10000, s[1]); lemma_mul_is_mul_boogie(0x100, s[2]); } 0x1000000 * s[0] + 0x10000 * s[1] + 0x100 * s[2] + s[3]; } } static lemma lemma_ValueOfFourByteSeqSpecific(s:seq, n:int) requires IsByteSeqOfLen(s, 4); requires n == 0x1000000 * s[0] + 0x10000 * s[1] + 0x100 * s[2] + s[3]; ensures BEByteSeqToInt(s) == n; { lemma_ValueOfFourByteSeq(s); } static lemma lemma_BEIntToDigitSeqProducesRightSizedDigits(place_value:int, min_places:int, v:int) requires 1) : seq requires IsByteSeq(bs); requires |bs|%4==0; //- ensures IsWordSeq(BEByteSeqToWordSeq(bs)); //- ensures BEWordSeqToByteSeq(BEByteSeqToWordSeq(bs)) == bs; { BEIntToDigitSeq(power2(32), |bs|/4, BEDigitSeqToInt(power2(8), bs)) } static function TailPad4(bs:seq) : seq { bs+RepeatDigit(0, ((|bs|+3)/4)*4-|bs|) } static lemma lemma_BEByteSeqToWordSeqTailPadding_constructive_form(ws:seq, bs:seq, pad_len:nat) requires IsWordSeq(ws); requires IsByteSeq(bs); requires |ws| == (|bs| + 3) / 4; requires pad_len == ((|bs|+3)/4)*4-|bs|; requires BEWordSeqToByteSeq(ws) == bs + RepeatDigit(0, pad_len); ensures IsByteSeq(TailPad4(bs)); ensures |TailPad4(bs)|%4 == 0; ensures ws == BEByteSeqToWordSeq(TailPad4(bs)); { lemma_2toX(); assert TailPad4(bs) == bs+RepeatDigit_premium(0, ((|bs|+3)/4)*4-|bs|); //- OBSERVE var padsize := |TailPad4(bs)| - |bs|; var wx := BEWordSeqToInt(ws); var bx := BEByteSeqToInt(TailPad4(bs)); var L8 := 8; lemma_mul_nonnegative(L8, |TailPad4(bs)|); lemma_BEDigitSeqToInt_bound(power2(8), TailPad4(bs)); assert 0 <= bx; calc { bx; BEDigitSeqToInt(power2(8), TailPad4(bs)); < power(power2(8), |TailPad4(bs)|); { lemma_power2_is_power_2(8); } power(power(2,8), |TailPad4(bs)|); { lemma_power_multiplies(2,8,|TailPad4(bs)|); } power(2,L8*|TailPad4(bs)|); { lemma_power2_is_power_2(L8*|TailPad4(bs)|); } power2(L8*|TailPad4(bs)|); } assert bx < power2(L8*|TailPad4(bs)|); lemma_BEIntToDigitSeq_private_chop(8, |TailPad4(bs)|, padsize, bx); lemma_mul_nonnegative(L8, padsize); assert BEIntToDigitSeq_private(power2(8), |bs|, bx/power2(L8*padsize)) + BEIntToDigitSeq_private(power2(8), padsize, bx%power2(L8*padsize)) == BEIntToDigitSeq_private(power2(8), |TailPad4(bs)|, bx); calc { wx; BEWordSeqToInt(ws); { lemma_BEWordSeqToInt_BEIntToByteSeq(BEWordSeqToByteSeq(ws), ws); } BEByteSeqToInt(BEWordSeqToByteSeq(ws)); BEByteSeqToInt(bs + RepeatDigit(0, pad_len)); BEByteSeqToInt(TailPad4(bs)); bx; } assert wx == bx; calc { ws; { lemma_BEDigitSeqToInt_invertibility(power2(32), wx, ws); } BEIntToDigitSeq(power2(32), |ws|, wx); BEIntToDigitSeq(power2(32), |ws|, bx); { assert |ws| == |TailPad4(bs)|/4; } BEIntToDigitSeq(power2(32), |TailPad4(bs)|/4, bx); BEIntToDigitSeq(power2(32), |TailPad4(bs)|/4, BEDigitSeqToInt(power2(8), TailPad4(bs))); BEByteSeqToWordSeq(TailPad4(bs)); } } // // static lemma lemma_BEByteSeqToWordSeqTailPadding_bit_equivalence(bs:seq, ws:seq, padded_bs:seq, padding:seq, ghost_padding:seq) requires IsByteSeq(bs); requires IsWordSeq(ws); requires IsByteSeq(padded_bs); requires IsByteSeq(padding); requires padded_bs == bs + padding; requires ghost_padding + padded_bs == BEWordSeqToByteSeq(ws); requires ghost_padding == []; ensures |bs|*8 <= |BEWordSeqToBitSeq(ws)|; ensures BEByteSeqToBitSeq(bs) == BEWordSeqToBitSeq(ws)[..|bs|*8]; { var padding_len := |padding|; calc { BEWordSeqToBitSeq(ws); { lemma_BEByteSeqToBitSeq_BEWordSeqToByteSeq(ws); } BEByteSeqToBitSeq(BEWordSeqToByteSeq(ws)); BEByteSeqToBitSeq(ghost_padding + padded_bs); { assert ghost_padding + padded_bs == padded_bs; /* OBSERVE */ } BEByteSeqToBitSeq(padded_bs); } calc { |BEWordSeqToBitSeq(ws)|; { lemma_BEWordSeqToBitSeq_ensures(ws); } 32*|ws|; 8*(4*|ws|); { lemma_BEWordSeqToByteSeq_ensures(ws); } 8*(|BEWordSeqToByteSeq(ws)|); 8*(|ghost_padding|+|padded_bs|); 8*|padded_bs|; >= 8*|bs|; } var head := padded_bs[..|padded_bs|-padding_len]; var tail := padded_bs[|padded_bs|-padding_len..]; calc { BEByteSeqToBitSeq(bs); BEByteSeqToBitSeq(padded_bs[..|padded_bs|-padding_len]); BEByteSeqToBitSeq(head); BEByteSeqToBitSeq(head)[..|BEByteSeqToBitSeq(head)|]; (BEByteSeqToBitSeq(head) + BEByteSeqToBitSeq(tail))[..|BEByteSeqToBitSeq(head)|]; { assert padded_bs == head + tail; calc { BEByteSeqToBitSeq(head) + BEByteSeqToBitSeq(tail); { lemma_mul_is_mul_boogie(|head|,8); } { lemma_mul_is_mul_boogie(|tail|,8); } BEIntToDigitSeq(power2(1), mul(|head|,8), BEDigitSeqToInt(power2(8), head)) + BEIntToDigitSeq(power2(1), mul(|tail|,8), BEDigitSeqToInt(power2(8), tail)); { lemma_mul_basics_forall(); lemma_SeqTransformChop(padded_bs, head, tail, 1, 8, 8); } BEIntToDigitSeq(power2(1), mul(|padded_bs|,8), BEDigitSeqToInt(power2(8), padded_bs)); { lemma_mul_is_mul_boogie(|padded_bs|,8); } BEByteSeqToBitSeq(padded_bs); } } BEByteSeqToBitSeq(padded_bs)[..|BEByteSeqToBitSeq(head)|]; { lemma_BEByteSeqToBitSeq_ensures(head); } BEByteSeqToBitSeq(padded_bs)[..|head|*8]; BEByteSeqToBitSeq(padded_bs)[..|bs|*8]; BEWordSeqToBitSeq(ws)[..|bs|*8]; } } static lemma lemma_BEByteSeqToWordSeqTailPadding_more( bs:seq, ws_len:int, padding_len:int, padding:seq, padded_bs:seq, ws:seq, ghost_padding:seq) requires IsByteSeq(bs); requires ws_len == (|bs|-1)/4+1; requires padding_len == ws_len*4 - |bs|; requires padding == RepeatDigit_premium(0, padding_len); requires IsWordSeq(bs); requires IsByteSeq(padded_bs); requires padded_bs == bs + padding; requires IsWordSeq(ws); requires |padded_bs|>0 ==> |ws|>0; requires |ws| == (|padded_bs|+3)/4; requires BEByteSeqToInt(padded_bs) == BEWordSeqToInt(ws); requires |BEWordSeqToByteSeq(ws)| >= |padded_bs|; requires ghost_padding == SequenceOfZeros(|ws|*4 - |padded_bs|); requires IsByteSeq(ghost_padding); requires BEWordSeqToByteSeq(ws) == ghost_padding + padded_bs; requires (|padded_bs|%4)==0 ==> BEWordSeqToByteSeq(ws) == padded_bs; ensures ghost_padding==[]; ensures |padded_bs|%4 == 0; ensures BEWordSeqToByteSeq(ws) == padded_bs; { calc { |ghost_padding|; |SequenceOfZeros(|ws|*4 - |padded_bs|)|; |ws|*4 - |padded_bs|; ((|padded_bs|+3)/4)*4 - |padded_bs|; 0; } assert ghost_padding == []; calc { |padded_bs|%4; |bs + padding|%4; (|bs| + |padding|)%4; (|bs| + padding_len)%4; (|bs| + ws_len*4 - |bs|)%4; (ws_len*4)%4; 0; } assert BEWordSeqToByteSeq(ws) == padded_bs; calc { BEWordSeqToByteSeq(ws); ghost_padding + padded_bs; padded_bs; bs + padding; { lemma_SequenceOfZeros_is_RepeatDigit(padding_len); } bs + RepeatDigit(0, padding_len); } } static method BEByteSeqToWordSeqTailPadding(bs:seq) returns (ws:seq) requires IsByteSeq(bs); ensures IsWordSeq(ws); ensures |bs| > 0 ==> |ws| > 0; ensures |ws| == (|bs| + 3) / 4; ensures |bs|*8 <= |BEWordSeqToBitSeq(ws)|; ensures BEByteSeqToBitSeq(bs) == BEWordSeqToBitSeq(ws)[..|bs|*8]; ensures IsByteSeq(TailPad4(bs)); ensures |TailPad4(bs)|%4==0; ensures ws == BEByteSeqToWordSeq(TailPad4(bs)); { lemma_2toX(); var ws_len := (|bs|-1)/4+1; var padding_len := ws_len*4 - |bs|; var padding := SequenceOfZerosIterative(padding_len); var padded_bs := bs + padding; ghost var ghost_padding; ws,ghost_padding := BEByteSeqToWordSeq_impl(padded_bs); lemma_SequenceOfZeros_is_RepeatDigit(padding_len); lemma_BEByteSeqToWordSeqTailPadding_more(bs, ws_len, padding_len, padding, padded_bs, ws, ghost_padding); lemma_BEByteSeqToWordSeqTailPadding_bit_equivalence(bs, ws, padded_bs, padding, ghost_padding); lemma_BEByteSeqToWordSeqTailPadding_constructive_form(ws, bs, padding_len); } static method BEByteSeqToWordSeqTailPadding_arrays(ba:array, ghost bs:seq) returns (wa:array, ghost ws:seq) requires ba!=null; requires ba[..]==bs; requires IsByteSeq(bs); ensures wa!=null; ensures wa[..]==ws; ensures IsWordSeq(ws); ensures |bs| > 0 ==> |ws| > 0; ensures |ws| == (|bs| + 3) / 4; ensures |bs|*8 <= |BEWordSeqToBitSeq(ws)|; ensures BEByteSeqToBitSeq(bs) == BEWordSeqToBitSeq(ws)[..|bs|*8]; ensures IsByteSeq(TailPad4(bs)); ensures |TailPad4(bs)|%4==0; ensures ws == BEByteSeqToWordSeq(TailPad4(bs)); { lemma_2toX(); var ws_len := (ba.Length-1)/4+1; var padding_len := ws_len*4 - ba.Length; ghost var padding := RepeatDigit_premium(0, padding_len); ghost var padded_bs := bs + padding; var padded_ba := new int[ba.Length + padding_len]; ArrayCpy(padded_ba, 0, ba, 0, ba.Length); calc { padded_ba[..ba.Length]; padded_ba[0..ba.Length]; ba[0..ba.Length]; ba[..]; bs; } ghost var first_ba_seq := padded_ba[..]; assert forall k :: 0<=k first_ba_seq[k] == ba[k]; ArraySet(padded_ba, ba.Length, padding_len, 0); assert forall i :: 0<=i padded_ba[i]==first_ba_seq[i]; Lemma_RepeatDigitProperties(0, padding_len); assert |padded_ba[ba.Length..]|==|RepeatDigit_premium(0, padding_len)|; assert padded_ba[ba.Length..]==RepeatDigit_premium(0, padding_len); ghost var ghost_padding; assert padded_ba.Length == |padded_ba[..]| == |padded_bs|; forall (k | 0<=k) requires IsWordSeq(ws); ensures IsBitSeq(BEWordSeqToBitSeq(ws)); ensures BEBitSeqToInt(BEWordSeqToBitSeq(ws)) == BEWordSeqToInt(ws); { lemma_BEWordSeqToBitSeq_ensures(ws); calc { BEBitSeqToInt(BEWordSeqToBitSeq(ws)); BEBitSeqToInt(BEIntToDigitSeq(power2(1), |ws|*32, BEDigitSeqToInt(power2(32), ws))); BEDigitSeqToInt(power2(1), BEIntToDigitSeq(power2(1), |ws|*32, BEDigitSeqToInt(power2(32), ws))); { reveal_power2(); lemma_BEDigitSeqToInt_bound(power2(32), ws); lemma_BEIntToDigitSeq_invertibility(power2(1), BEDigitSeqToInt(power2(32), ws), BEIntToDigitSeq(power2(1), |ws|*32, BEDigitSeqToInt(power2(32), ws))); } BEDigitSeqToInt(power2(32), ws); BEWordSeqToInt(ws); } } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/Util/word_bits.i.dfy ================================================ include "integer_sequences_premium.i.dfy" include "../../Drivers/CPU/assembly_premium.i.dfy" include "../Math/bit_vector_lemmas_premium.i.dfy" //------------------------------------------------------------------------- static lemma lemma_LeftShiftOfOneProperties(e: int) requires 0 <= e < 32; ensures Word32(1) && Word32(e); ensures |BEWordToBitSeq(LeftShift(1, e))| == 32; ensures BEWordToBitSeq(LeftShift(1, e)) == SequenceOfZeros(31-e) + [1] + SequenceOfZeros(e); ensures forall i :: 0 <= i < 32 ==> BEWordToBitSeq(LeftShift(1, e))[i] == if i == 31 - e then 1 else 0; { lemma_2toX(); reveal_power2(); calc { BEWordToBitSeq(LeftShift(1, e)); BEWordToBitSeq(Asm_LeftShift(1, e)); { lemma_SequenceOfZerosIsRepeatDigitZero(e); } BEWordToBitSeq(1)[e..] + SequenceOfZeros(e); calc { BEWordToBitSeq(1); BEIntToDigitSeq(power2(1), 32, 1); { reveal_BEIntToDigitSeq_private(); lemma_small_div(); lemma_small_mod(1, 2); } BEIntToDigitSeq(power2(1), 31, 0) + [1]; { lemma_BEIntToDigitSeq_private_zero(power2(1), 31); } SequenceOfZeros(31) + [1]; } (SequenceOfZeros(31) + [1])[e..] + SequenceOfZeros(e); (SequenceOfZeros(e) + SequenceOfZeros(31-e) + [1])[e..] + SequenceOfZeros(e); SequenceOfZeros(31-e) + [1] + SequenceOfZeros(e); } forall i | 0 <= i < 32 ensures BEWordToBitSeq(LeftShift(1, e))[i] == if i == 31 - e then 1 else 0; { if i < 31-e { calc { BEWordToBitSeq(LeftShift(1, e))[i]; (SequenceOfZeros(31-e) + [1] + SequenceOfZeros(e))[i]; (SequenceOfZeros(i+1) + SequenceOfZeros(31-e-i-1) + [1] + SequenceOfZeros(e))[i]; 0; } } else if i > 31-e { calc { BEWordToBitSeq(LeftShift(1, e))[i]; (SequenceOfZeros(31-e) + [1] + SequenceOfZeros(e))[i]; (SequenceOfZeros(31-e) + [1] + SequenceOfZeros(i-(31-e)) + SequenceOfZeros(31-i))[i]; 0; } } } } static lemma lemma_bits_of_power2(bs:seq, c:nat) requires bs == [1] + SequenceOfZeros(c); ensures IsBitSeq(bs); ensures BEBitSeqToInt(bs) == power2(c); decreases c; { reveal_BEDigitSeqToInt_private(); lemma_power2_1_is_2(); var L2 := 2; if (|bs|==1) { calc { BEBitSeqToInt(bs); BEDigitSeqToInt_private(power2(1), bs); BEDigitSeqToInt_private(power2(1), [])*L2 + 1; { lemma_mul_basics_forall(); } 1; { lemma_power2_0_is_1(); } power2(c); } } else { var sm := [1] + SequenceOfZeros(c-1); assert bs[0..|bs|-1] == sm; assert bs[|bs|-1] == 0; calc { BEBitSeqToInt(bs); BEDigitSeqToInt_private(power2(1), bs); BEDigitSeqToInt_private(power2(1), sm)*L2 + 0; { lemma_bits_of_power2(sm, c-1); } power2(c-1)*L2; { reveal_power2(); lemma_mul_is_mul_boogie(power2(c-1),L2); } power2(c); } } } static lemma lemma_ComputePower2_is_power2(e:int, p2:int) requires 0 <= e < 32; requires Word32(p2); requires BEWordToBitSeq(p2) == SequenceOfZeros(31-e) + [1] + SequenceOfZeros(e); ensures p2 == power2(e); { var normal_form := [1] + SequenceOfZeros(e); lemma_power2_1_is_2(); var input_string := SequenceOfZeros(31-e) + normal_form; calc { p2; BEBitSeqToInt(BEWordToBitSeq_premium(p2)); { assert input_string == SequenceOfZeros(31-e) + [1] + SequenceOfZeros(e); } BEBitSeqToInt(input_string); BEBitSeqToInt(SequenceOfZeros(31-e) + normal_form); { lemma_LeadingZeros(2, normal_form, SequenceOfZeros(31-e) + normal_form); } BEBitSeqToInt(normal_form); { lemma_bits_of_power2(normal_form, e); } power2(e); } } static function method ComputePower2(e:int) : int requires 0 <= e < 32; ensures Word32(1) && Word32(e); ensures |BEWordToBitSeq(ComputePower2(e))| == 32; ensures BEWordToBitSeq(ComputePower2(e)) == SequenceOfZeros(31-e) + [1] + SequenceOfZeros(e); ensures forall i :: 0 <= i < 32 ==> BEWordToBitSeq(ComputePower2(e))[i] == if i == 31 - e then 1 else 0; ensures ComputePower2(e) == power2(e); { lemma_LeftShiftOfOneProperties(e); lemma_ComputePower2_is_power2(e, Asm_LeftShift(1, e)); Asm_LeftShift(1, e) } //------------------------------------------------------------------------- //-static function power2minus1_word(e:nat) : seq //- requires 0 <= e <= 32; //-{ //- SequenceOfZeros(32-e) + RepeatDigit_premium(1, e) //-} //- //-static lemma lemma_bits_of_power2minus1_word(bs:seq, e:nat) //- requires 0 <= e < 32; //- ensures Word32(1) && Word32(e); //- ensures |BEWordToBitSeq(power2minus1_word(e))| == 32; //- ensures forall i :: 0 <= i < 32 ==> BEWordToBitSeq(power2minus1_word(e))[i] == if i < 32-e then 0 else 1; //-{ //-} static lemma lemma_bits_of_power2minus1(bs:seq, c:nat) requires bs == RepeatDigit_premium(1, c); ensures IsBitSeq(bs); ensures BEBitSeqToInt(bs) == power2(c)-1; decreases c; { reveal_BEDigitSeqToInt_private(); lemma_power2_0_is_1(); lemma_power2_1_is_2(); var L2 := 2; if (|bs|==0) { calc { BEBitSeqToInt(bs); BEDigitSeqToInt_private(power2(1), bs); 0; power2(c)-1; } } else { var sm := RepeatDigit(1, c-1); assert bs[0..|bs|-1] == sm; assert bs[|bs|-1] == 1; calc { BEBitSeqToInt(bs); BEDigitSeqToInt_private(power2(1), bs); BEDigitSeqToInt_private(power2(1), sm)*L2 + 1; { lemma_bits_of_power2minus1(sm, c-1); } (power2(c-1) - 1)*L2 + 1; { lemma_mul_is_mul_boogie(power2(c-1)-1,L2); } power2(c-1)*2 - 1; { reveal_power2(); } power2(c) - 1; } } } static lemma lemma_ComputePower2Minus1(e:int, p2m1:int) requires 0 <= e <= 32; requires p2m1 == power2(e)-1; ensures Word32(p2m1); ensures |BEWordToBitSeq_premium(p2m1)| == 32; ensures BEWordToBitSeq(p2m1) == RepeatDigit_premium(0, 32-e) + RepeatDigit_premium(1, e); ensures forall i :: 0 <= i < 32 ==> BEWordToBitSeq(p2m1)[i] == if i < 32-e then 0 else 1; { lemma_power2_1_is_2(); lemma_2toX(); lemma_power2_increases(e, 32); //-assert p2m1 < power2(32); var tight := RepeatDigit_premium(1, e); lemma_bits_of_power2minus1(tight, e); assert BEBitSeqToInt(tight) == power2(e)-1; lemma_BEDigitSeqToInt_invertibility(2, p2m1, tight); assert BEIntToDigitSeq(2, e, p2m1) == tight; lemma_BEIntToDigitSeq_properties(2, 0, p2m1); if (e > |BEIntToDigitSeq_private(2, 0, p2m1)|) { calc { power2(e); > { lemma_power2_strictly_increases(|BEIntToDigitSeq_private(2, 0, p2m1)|, e); } power2(|BEIntToDigitSeq_private(2, 0, p2m1)|); { lemma_power2_is_power_2(|BEIntToDigitSeq_private(2, 0, p2m1)|); } power(2, |BEIntToDigitSeq_private(2, 0, p2m1)|); >= p2m1 + 1; power2(e); } } assert e <= |BEIntToDigitSeq(2, 0, p2m1)|; lemma_BEIntToDigitSeq_mp_irrelevant(2, e, p2m1); assert BEIntToDigitSeq(2, 0, p2m1) == tight; calc { BEWordToBitSeq(p2m1); BEIntToDigitSeq(2, 32, p2m1); { lemma_zero_extension(2, 32, p2m1, tight); } RepeatDigit_premium(0, 32-|tight|) + tight; RepeatDigit_premium(0, 32-e) + tight; } } static function method ComputePower2Minus1_mostly(e:int) : int requires 0 <= e < 32; ensures Word32(1) && Word32(e); ensures |BEWordToBitSeq(ComputePower2Minus1_mostly(e))| == 32; ensures BEWordToBitSeq(ComputePower2Minus1_mostly(e)) == SequenceOfZeros(32-e) + RepeatDigit(1, e); ensures forall i :: 0 <= i < 32 ==> BEWordToBitSeq(ComputePower2Minus1_mostly(e))[i] == if i < 32-e then 0 else 1; ensures ComputePower2Minus1_mostly(e) == power2(e)-1; { lemma_2toX(); lemma_ComputePower2Minus1(e, ComputePower2(e)-1); ComputePower2(e)-1 } static lemma lemma_0xffffffff_is_2to32minus1() ensures 0xffffffff == power2(32)-1; { lemma_2toX(); } static function method ComputePower2Minus1(e:int) : int requires 0 <= e < 32; ensures Word32(1) && Word32(e); ensures |BEWordToBitSeq(ComputePower2Minus1(e))| == 32; ensures BEWordToBitSeq(ComputePower2Minus1(e)) == SequenceOfZeros(32-e) + RepeatDigit(1, e); ensures forall i :: 0 <= i < 32 ==> BEWordToBitSeq(ComputePower2Minus1(e))[i] == if i < 32-e then 0 else 1; ensures ComputePower2Minus1(e) == power2(e)-1; { lemma_0xffffffff_is_2to32minus1(); if (e==32) then 0xffffffff else ComputePower2Minus1_mostly(e) } //------------------------------------------------------------------------- static function GetWordBit(x: int, b: int) : int requires Word32(x); requires 0 <= b < 32; ensures IsBit(GetWordBit(x, b)); { BEWordToBitSeq_premium(x)[b] } static method UpdateBitOfWord(x: int, pos: int, value: int) returns (y: int) requires Word32(x); requires 0 <= pos < 32; requires IsBit(value); ensures Word32(y); ensures |BEWordToBitSeq(x)| == |BEWordToBitSeq(y)| == 32; ensures BEWordToBitSeq(y)[pos] == value; ensures forall i {:trigger BEWordToBitSeq(x)[i]}{:trigger BEWordToBitSeq(y)[i]} :: 0 <= i < 32 && i != pos ==> BEWordToBitSeq(y)[i] == BEWordToBitSeq(x)[i]; { if value == 1 { var y := Asm_BitwiseOr(x, ComputePower2(31-pos)); forall i | 0 <= i < 32 && i != pos ensures BEWordToBitSeq(y)[i] == BEWordToBitSeq(x)[i]; { calc { BEWordToBitSeq(y)[i]; if BEWordToBitSeq(x)[i] == 1 || BEWordToBitSeq(ComputePower2(31-pos))[i] == 1 then 1 else 0; if BEWordToBitSeq(x)[i] == 1 || false then 1 else 0; if BEWordToBitSeq(x)[i] == 1 then 1 else 0; { reveal_power2(); } BEWordToBitSeq_premium(x)[i]; BEWordToBitSeq(x)[i]; } } return y; } else { var y := Asm_BitwiseAnd(x, Asm_BitwiseNot(ComputePower2(31-pos))); forall i | 0 <= i < 32 && i != pos ensures BEWordToBitSeq(y)[i] == BEWordToBitSeq(x)[i]; { calc { BEWordToBitSeq(y)[i]; if BEWordToBitSeq(x)[i] == 1 && BEWordToBitSeq(Asm_BitwiseNot(ComputePower2(31-pos)))[i] == 1 then 1 else 0; if BEWordToBitSeq(x)[i] == 1 && BEWordToBitSeq(ComputePower2(31-pos))[i] == 0 then 1 else 0; if BEWordToBitSeq(x)[i] == 1 then 1 else 0; { reveal_power2(); } BEWordToBitSeq_premium(x)[i]; BEWordToBitSeq(x)[i]; } } return y; } } //------------------------------------------------------------------------- static method TruncateToByte(Value:int) returns (NewValue: int) requires Word32(Value); ensures IsByte(NewValue); ensures Word32(0xff); ensures NewValue == Asm_BitwiseAnd(Value, 0xff); //- Help SymDiff out { lemma_2toX(); lemma_and_with_ff_premium(); NewValue := Asm_BitwiseAnd(Value, 0xff); } static method TruncateToWord16(Value:int) returns (NewValue: int) requires Word32(Value); ensures Word16(NewValue); ensures Word32(0xffff); ensures NewValue == Asm_BitwiseAnd(Value, 0xffff); //- Help SymDiff out { lemma_2toX(); lemma_and_with_ffff_premium(); NewValue := Asm_BitwiseAnd(Value, 0xffff); } ================================================ FILE: ironclad-apps/src/Dafny/Libraries/base.s.dfy ================================================ static function{:imported} unroll(i:int):bool { true } static function Trigger(i:int):bool { true } static function sizeof(a:A):int ================================================ FILE: ironclad-apps/src/DafnyTestDriver/DafnyTestDriver/App.config ================================================  ================================================ FILE: ironclad-apps/src/DafnyTestDriver/DafnyTestDriver/DafnyTestDriver.csproj ================================================  Debug AnyCPU {069C5421-5138-4F5C-BA5D-A2AFE201CFBF} Exe Properties ConsoleApplication1 ConsoleApplication1 v4.5 512 AnyCPU true full false bin\Debug\ DEBUG;TRACE prompt 4 AnyCPU pdbonly true bin\Release\ TRACE prompt 4 ================================================ FILE: ironclad-apps/src/DafnyTestDriver/DafnyTestDriver/Program.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Numerics; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { Console.WriteLine("Hiya, world!"); @__default prog = new __default(); BigInteger @result; prog.Main(out @result); } } } ================================================ FILE: ironclad-apps/src/DafnyTestDriver/DafnyTestDriver/Properties/AssemblyInfo.cs ================================================ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; [assembly: AssemblyTitle("ConsoleApplication1")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("ConsoleApplication1")] [assembly: AssemblyCopyright("Copyright © 2014")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] [assembly: Guid("837486e7-41bf-4b80-be6b-013696ddd61d")] // // [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: ironclad-apps/src/DafnyTestDriver/DafnyTestDriver/assembly.cs ================================================ using System.Numerics; using System.Diagnostics; using System.Text; public partial class @__default { public static BigInteger @asm__BitwiseXor(BigInteger a, BigInteger b) { return a ^ b; } public static BigInteger @asm__BitwiseAnd(BigInteger a, BigInteger b) { return a & b; } public static BigInteger @asm__BitwiseOr(BigInteger a, BigInteger b) { return a | b; } public static BigInteger @asm__LeftShift(BigInteger a, BigInteger b) { BigInteger mask = 1; mask = mask << 32; mask -= 1; return mask & (a << (int)b); } public static BigInteger @asm__RightShift(BigInteger a, BigInteger b) { return a >> (int)b; } public static BigInteger @asm__BitwiseNot(BigInteger a) { return ~a; } public static BigInteger @asm__RotateRight(BigInteger a, BigInteger b) { BigInteger mask = 1; mask = mask << 32; mask -= 1; int amount = (int)b; return mask & ((a >> amount) | (a << (32 - amount))); } public static BigInteger @asm__RotateLeft(BigInteger a, BigInteger b) { BigInteger mask = 1; mask = mask << 32; mask -= 1; int amount = (int)b; return mask & ((a << amount) | (a >> (32 - amount))); } static BigInteger two = 2; static BigInteger pow32 = BigInteger.Pow(two, 32); static void Word32(BigInteger a) { Debug.Assert(0 <= a); Debug.Assert(a < pow32); } public static BigInteger @asm__Add(BigInteger a, BigInteger b) { Word32(a); Word32(b); profiler.ProfileTally(1000, 1); BigInteger result = (a + b) % pow32; Debug.Assert(((a + b) - (a+b >= pow32 ? pow32 : 0)).Equals(result)); return result; } public static BigInteger @asm__Sub(BigInteger a, BigInteger b) { Word32(a); Word32(b); profiler.ProfileTally(1001, 1); BigInteger result = (a - b + pow32) % pow32; Debug.Assert((a - b + ((b>a) ? pow32 : 0)).Equals(result)); return result; } public static void @method__Mul(BigInteger a, BigInteger b, out BigInteger hi, out BigInteger lo) { Word32(a); Word32(b); profiler.ProfileTally(1002, 1); @asm__Mul64(a, b, out hi, out lo); } public static void @asm__Mul64(BigInteger a, BigInteger b, out BigInteger hi, out BigInteger lo) { Word32(a); Word32(b); profiler.ProfileTally(1003, 1); BigInteger pow64 = 2; pow64 = BigInteger.Pow(pow64, 64); BigInteger product = (a * b) % pow64; hi = product / pow32; lo = product % pow32; Debug.Assert((hi * pow32 + lo).Equals(a * b)); } public static BigInteger @asm__Mul(BigInteger a, BigInteger b) { Word32(a); Word32(b); profiler.ProfileTally(1004, 1); BigInteger hi, lo; @method__Mul(a, b, out hi, out lo); return lo; } public static BigInteger @asm__Div(BigInteger a, BigInteger b) { Word32(a); Word32(b); profiler.ProfileTally(1005, 1); return BigInteger.Divide(a,b); } public static BigInteger @asm__Mod(BigInteger a, BigInteger b) { Word32(a); Word32(b); profiler.ProfileTally(1006, 1); return BigInteger.Remainder(a,b); } public static void @method__DivMod(BigInteger zero/*?*/, BigInteger a, BigInteger b, out BigInteger div, out BigInteger mod) { Word32(a); Word32(b); div = BigInteger.DivRem(a, b, out mod); Debug.Assert((b * div + mod).Equals(a)); } public static void @asm__Rdtsc(out BigInteger hi, out BigInteger lo) { hi = 0; lo = 0; } public void @asm__declassify__result(BigInteger @concrete, out BigInteger @pub__result) { @pub__result = @concrete; } public static void @GetBootloaderArgWord(BigInteger @index, out BigInteger @result) { @result = 0; } System.Random rng = new System.Random(); public void display_seq(BigInteger[] x) { StringBuilder sb = new StringBuilder(); foreach (BigInteger xs in x) { sb.Append(string.Format("{0,2:X2}", (int)xs)); } System.Console.WriteLine(sb.ToString()); } public void @get__random(BigInteger countb, out Dafny.Sequence @result) { int counti = (int)countb; BigInteger[] bary = new BigInteger[counti]; for (int i=0; i(bary); display_seq(bary); } public static void InitK__SHA256__0__to__10(BigInteger[] @result) { Debug.Assert(false); @result = null; } public static void @ComputeWsForBlockStep2__SHA256(BigInteger[] @M, BigInteger @words, BigInteger[] @H, BigInteger[] @W, BigInteger[] @Ks, BigInteger @num__blocks, BigInteger @currentBlock) { Debug.Assert(false); } public static void debug__print(BigInteger m1, BigInteger m2) { System.Console.WriteLine(string.Format("debug_print {0,2:X} {1,8:X}", (int) m1, (int) m2)); } } ================================================ FILE: ironclad-apps/src/DafnyTestDriver/DafnyTestDriver/debug.cs ================================================ using System.Numerics; public partial class @__default { public static BigInteger BIFake(int val, int count) { if (count == 1) { return val; } else { return BIFake(val, count - 1) * BigInteger.Pow(2,32) + val; } } // // // //// // // // // // //// // // // // } ================================================ FILE: ironclad-apps/src/DafnyTestDriver/DafnyTestDriver/profile.cs ================================================ using System; using System.IO; using System.Numerics; using System.Collections.Generic; using System.Diagnostics; public class Profiler { Dictionary labels; Dictionary profileMap; Stopwatch stopwatch; StreamWriter tw; public Profiler(StreamWriter tw) { this.tw = tw; labels = new Dictionary(); labels[1] = "TestDigits"; labels[2] = "BigNatSub"; labels[3] = "BigNatModExpCalls"; labels[4] = "BigNatModExpWhileLoops"; labels[5] = "BigNatDivCalls"; labels[6] = "BigNatDivWhileLoops"; labels[1000] = "Add"; labels[1001] = "Sub"; labels[1002] = "method_Mul"; labels[1003] = "Mul64"; labels[1004] = "Mul"; labels[1005] = "Div"; labels[1006] = "Mod"; ResetTally(); } public void ResetTally() { profileMap = new Dictionary(); stopwatch = new Stopwatch(); stopwatch.Start(); } public void ProfileTally(int category, int value) { if (!profileMap.ContainsKey(category)) { profileMap[category] = 0; } profileMap[category] += value; } public void DisplayTally() { stopwatch.Stop(); TimeSpan elapsed = stopwatch.Elapsed; foreach (int key in profileMap.Keys) { tw.WriteLine( String.Format("{0}: {1}", labels[key], profileMap[key])); } tw.WriteLine("ElapsedTime: " + elapsed); tw.WriteLine(); tw.FlushAsync(); } } public partial class @__default { static Profiler profiler = new Profiler(new StreamWriter("profiler.txt")); public static void ResetTally() { profiler.ResetTally(); } public static void ProfileTally(BigInteger _category, BigInteger _value) { profiler.ProfileTally((int) _category, (int) _value); } public static void DisplayTally() { profiler.DisplayTally(); } } ================================================ FILE: ironclad-apps/src/DafnyTestDriver/DafnyTestDriver.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2012 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DafnyTestDriver", "DafnyTestDriver\DafnyTestDriver.csproj", "{069C5421-5138-4F5C-BA5D-A2AFE201CFBF}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {069C5421-5138-4F5C-BA5D-A2AFE201CFBF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {069C5421-5138-4F5C-BA5D-A2AFE201CFBF}.Debug|Any CPU.Build.0 = Debug|Any CPU {069C5421-5138-4F5C-BA5D-A2AFE201CFBF}.Release|Any CPU.ActiveCfg = Release|Any CPU {069C5421-5138-4F5C-BA5D-A2AFE201CFBF}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: ironclad-apps/src/Trusted/DafnySpec/Seq.s.dfy ================================================ include "../../Dafny/Libraries/base.s.dfy" //- Trusted sequence definitions (used in trusted specifications) datatype Seq = Seq_Nil() | Seq_Cons(hd:A, tl:Seq); function{:opaque} Seq_Length(s:Seq):int ensures Seq_Length(s) >= 0; { if s.Seq_Cons? then 1 + Seq_Length(s.tl) else 0 } function Seq_Empty():Seq { Seq_Nil() } function{:opaque} Seq_Singleton(a:A):Seq { Seq_Cons(a, Seq_Nil()) } function{:opaque} Seq_Build(s:Seq, a:A):Seq { if s.Seq_Cons? then Seq_Cons(s.hd, Seq_Build(s.tl, a)) else Seq_Singleton(a) } function Seq_Dummy():A function{:opaque} Seq_Index(s:Seq, k:int):A { if s.Seq_Cons? then if k == 0 then s.hd else Seq_Index(s.tl, k - 1) else Seq_Dummy() } function Seq_Equal(s0:Seq, s1:Seq):bool { s0 == s1 } function{:opaque} Seq_Append(s0:Seq, s1:Seq):Seq { if s0.Seq_Cons? then Seq_Cons(s0.hd, Seq_Append(s0.tl, s1)) else s1 } function{:opaque} Seq_Update(s:Seq, k:int, a:A):Seq { if s.Seq_Cons? then if k == 0 then Seq_Cons(a, s.tl) else Seq_Cons(s.hd, Seq_Update(s.tl, k - 1, a)) else s } function{:opaque} Seq_Take(s:Seq, n:int):Seq { if s.Seq_Cons? && n > 0 then Seq_Cons(s.hd, Seq_Take(s.tl, n - 1)) else Seq_Nil() } function{:opaque} Seq_Drop(s:Seq, n:int):Seq { if s.Seq_Cons? && n > 0 then Seq_Drop(s.tl, n - 1) else s } lemma Seq_Seq(s:Seq) ensures 0 <= sizeof(s); ensures s.Seq_Nil? != s.Seq_Cons?; ensures{:typearg "A"} s.Seq_Nil? <==> s == Seq_Nil(); ensures s.Seq_Cons? ==> Seq_Cons(s.hd, s.tl) == s; ensures s.Seq_Cons? ==> 0 <= sizeof(s.tl) < sizeof(s); { } lemma Seq_Cons_All() ensures forall s:Seq :: s.Seq_Nil? != s.Seq_Cons?; ensures{:typearg "A"} forall s:Seq :: s.Seq_Nil? <==> s == Seq_Nil(); ensures forall hd:A, tl:Seq :: Seq_Cons(hd, tl).Seq_Cons?; ensures forall hd:A, tl:Seq :: Seq_Cons(hd, tl).hd == hd; ensures forall hd:A, tl:Seq :: Seq_Cons(hd, tl).tl == tl; { } // ================================================ FILE: ironclad-apps/src/Trusted/Spec/AddPerf/AppRequirements.ifc.stitch ================================================ //-private-import dafny_assembly_s; //-private-import dafny_be_sequences_s; //-private-import dafny_bytes_and_words_s; //-Xrivate-import dafny_Digest_s; //-Xrivate-import dafny_GCD_s; //-Xrivate-import dafny_hmac_common_s; //-private-import dafny_integer_sequences_s; //-Xrivate-import dafny_io_mem_s; //-Xrivate-import dafny_KeyGen_s; //-Xrivate-import dafny_MillerRabin_s; //-Xrivate-import dafny_power_s; //-Xrivate-import dafny_RandomNumberGen_s; //-Xrivate-import dafny_RandomTracing_s; //-Xrivate-import dafny_rfc4251_s; //-Xrivate-import dafny_round_s; //-Xrivate-import dafny_RSASpec_s; //-Xrivate-import dafny_seq_blocking_s; //-Xrivate-import dafny_sha_common_s; //-Xrivate-import dafny_sha1_s; //-Xrivate-import dafny_sha256_s; //-Xrivate-import dafny_tpm_device_s; // requires fun_TPM__valid($ghost_TPM); // requires fun_TPM__satisfies__integrity__policy($ghost_TPM); // requires $ghost_IoMemPerm is Null; // modifies $ghost_TPM; ================================================ FILE: ironclad-apps/src/Trusted/Spec/AppLoader/AppRequirements.ifc.stitch ================================================ //-private-import dafny_assembly_s; //-private-import dafny_base_s; //-private-import dafny_be_sequences_s; //-private-import dafny_bytes_and_words_s; //-private-import dafny_DafnyPrelude; //-private-import dafny_hmac_common_s; //-private-import dafny_integer_sequences_s; //-private-import dafny_io_mem_s; //-private-import dafny_power_s; //-private-import dafny_power2_s; //-private-import dafny_relational_s; //-private-import dafny_round_s; //-private-import dafny_seq_blocking_s; //-private-import dafny_Seq_s; //-private-import dafny_sha_common_s; //-private-import dafny_sha1_s; //-private-import dafny_tpm_device_s; requires fun_TPM__valid($ghost_TPM); requires fun_TPM__satisfies__integrity__policy($ghost_TPM); requires $ghost_IoMemPerm is Null; modifies $ghost_TPM; ================================================ FILE: ironclad-apps/src/Trusted/Spec/AppLoaderContract.ifc.basm ================================================ //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module interface AppLoaderContract { //-//////////////////////////////////////////////////////////////////////////// //- //- This function defines the contract between AppLoader and the App it launches //- AppLoader must, effectively, ensure it, while the app gets to assume it //- //-//////////////////////////////////////////////////////////////////////////// function AppLoaderContractGeneric( core_id:int, init:bool, r:regs, core_state:core_state, initState:InitStateMachine, mem:mem, code_mem:mem, io:IOState, app_entry:int, app_code_base:int, code_word_seq:Seq___int ):bool { app_code_base == r.regs[EAX] && app_entry == r.regs[EBX] && Aligned(app_code_base) && app_code_base mod 0x10000 == 0 && app_code_base <= app_entry && app_entry < app_code_base + 0x100000 //- Code must be < 1MB && ?memLo <= app_code_base + 0x101000 //- Usable memory starts at the end of the code + 1K && ?memHi >= app_code_base + 123*1024*1024 && ?memHi == 0x08000000 && (forall i:int::{memAddr(i)}{mem.dom[i]} app_code_base + 0x101000 <= i && i < ?memHi <==> mem.dom[i]) //- App expects 123 MB of memory && r.regs[ESP] == add(app_code_base, 123*1024*1024) //- Stack starts at the very top && (forall k:int::{memAddr(k)} ?memLo <= k && k < ?memHi ==> memAddr(k)) && ValidPrePagingState(core_state.cregs[CR0]) && core_state.seg_regs[SS].descriptor.segBase == 0 && core_state.seg_regs[SS].descriptor.segType == ?SegmentDescriptorTypeData && core_state.seg_regs[DS].descriptor.segBase == 0 && core_state.seg_regs[DS].descriptor.segType == ?SegmentDescriptorTypeData && core_id == 0 //- Must be run on the bootstrap processor && !init && (forall j:int :: 0 <= j && j < 256*1024 ==> fun_Seq__Index___int(code_word_seq, j) == code_mem.map[app_code_base + j*4]) //- App loader knows its constants by now, but the app we launch doesn't #ifndef AppLoader && initState is EntryPoint && ?CodeBase == app_code_base //- New definition, since app is linked at a different base #endif //- Trusted code has not yet done anything to the PCI configuration && (forall s:int::{PciConfigState#PciState(_pci#IOState(io))[s]} 0 <= s && s < 65536 ==> io._pci.PciConfigState[s] == 0) // TODO: fix triggering } } ================================================ FILE: ironclad-apps/src/Trusted/Spec/AppLoaderContract.imp.basm ================================================ //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module implementation AppLoaderContract { } ================================================ FILE: ironclad-apps/src/Trusted/Spec/AssemblySpec.ifc.basm ================================================ //- //- //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module interface AssemblySpec { //-//////////////////////////////////////////////////////////////////////////// //- ASSEMBLY LANGUAGE DEFINITIONS //-//////////////////////////////////////////////////////////////////////////// //- Decide whether conditional jumps will be taken (true) or not taken (false), depending on condition and efl: function Je (efl:int):bool; function Jne(efl:int):bool; function Jbe(efl:int):bool; function Jb (efl:int):bool; function Jae(efl:int):bool; function Ja (efl:int):bool; //- Is the carry flag (CF) set? function Cf (efl:int):bool; //- invariant: word(r) for each register r //- To maintain invariant, simply check word(exp) for each assignment r := exp //- invariant: word(r) for each word w in memory //- To maintain invariant, simply check word(exp) for each store of exp to memory const EAX:int := 0; const ECX:int := 1; const EDX:int := 2; const EBX:int := 3; const ESI:int := 4; const EDI:int := 5; const EBP:int := 6; const ESP:int := 7; //- fictitious temporary registers for microinstructions: const TMP1:int := 0 - 1; const TMP2:int := 0 - 2; function RegOk(r:int):bool { EAX <= r && r <= ESP } //- Ordering chosen based on Table 4-1 in the Intel Manual //- Actual values have no impact; just need to be distinct (and consecutive for SegRegOk to work) const ES:int := 0; const CS:int := 1; const SS:int := 2; const DS:int := 3; const FS:int := 4; const GS:int := 5; function SegRegOk(r:int):bool { ES <= r && r <= GS } const CR0:int := 0; const CR3:int := 1; const CR4:int := 2; function CtrlRegOk(r:int):bool { CR0 <= r && r <= CR4 } type mem_opn = MConst(_mconst:int) | MReg(_mreg:int, _moffset:int) | MIndex(_mbase:int, _mscale:int, _mindex:int, _moff:int); type opn = OConst(_const:int) | OReg(_reg:int); type opn_mem = OMem(_ptr:mem_opn); // TODO: get rid of this //- TLB holds cached PTEs. //- The label represents the possibility that the processor implements multiple TLBs (e.g., code and data) //- We model the TLB as an infinitely large cache. //- A nondeterministic process updates the TLB, so when the page structures in memory change, //- the TLBs may or may not reflect the new value. Once the TLB is invalidated, we immediately //- populate it with the current value in memory, representing the fact that the next access will //- force the processor to go to memory to learn the correct mapping. //- DTLB holds cached PDEs //- The activeLabels select the {D}TLB that will be used for the next memory option //- We havoc them on every operation, so there are no guarantees as to which one will be used // TODO: MUST HAVOC {D}TLB_activeLabels !!!! <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< type TLB_label; type DTLB_label; type paging_caches = paging_caches(TLB:[int][TLB_label]PageEntry, DTLB:[int][DTLB_label]PageEntry, TLB_activeLabel:TLB_label, DTLB_activeLabel:DTLB_label); //- GDT Base: Addr in mem where Global Descriptor Table (GDT) starts. Len = # seg descriptors in GDT type GDT_regs = GDT_regs(GDT_base:int, GDT_len:int); //- state shared among cores // TODO: move these to the proper files //- These types deliberately omit linear constructors; the programmer cannot construct them directly type VgaEvent; type VgaState = VgaState(VgaEvents:[int]VgaEvent, VgaNextEvent:int); type KeyboardState = KeyboardState(KeyboardEvents:[int]int, KeyboardAvailable:int, KeyboardDone:int); type IomState = IomState(IomMem:[int]int, IomFrozen:bool, IoMmuState:[int]int, IoMmuEnabled:bool, DevEnabled:bool); //type IOQueue = IOQueue(Events:[int]int, Count:int); type PciState = PciState(PciConfigId:int, PciConfigOffset:int, PciConfigState:[int]int); type IOState = IOState(_vga:VgaState, _keyboard:KeyboardState, _iom:IomState, _pci:PciState, _inCtr:int, _outCtr:int); //- mem.map[i] = data at address i, if PhysPtrOk(i) type mem = mem(map:[int]int, dom:[int]bool); //- no linear constructors function mem_update(mem:mem, ptr:int, val:int):mem { mem(mem.map[ptr := val], mem.dom) } //- core-local state type regs = regs(_regs:[int]int, _efl:int); //- no linear constructors type core_state = core_state(_cregs:[int]int, _gdt_regs:GDT_regs, _seg_regs:[int]SegmentRegister, _caches:paging_caches); //- no linear constructors function .regs(r:regs):[int]int { r._regs } function .efl(r:regs):int { r._efl } function .cregs(c:core_state):[int]int { c._cregs } function .gdt_regs(c:core_state):GDT_regs { c._gdt_regs } function .seg_regs(c:core_state):[int]SegmentRegister { c._seg_regs } function .caches(c:core_state):paging_caches { c._caches } type SerialPortState = SerialPortState(Mode:SerialPortMode, In:SerialPortQueue, Out:SerialPortQueue); type SerialPortQueue = SerialPortQueue(Events:[int]int, Available:int, Done:int); type SerialPortMode = SerialPortMode(DLAB:bool); //readonly var $serialState:SerialPortState; //readonly var $randomSource:[int]int; //readonly var $global_sample_index:int; function PhysPtrOk(mem:mem, ptr:int):bool { mem.dom[ptr] && Aligned(ptr) } function EvalMemOpn(r:regs, m:mem_opn):int { if m is MConst then m._mconst else if m is MReg then r.regs[m._mreg] + m._moffset else r.regs[m._mbase] + m._mscale * r.regs[m._mindex] + m._moff } function EvalMemOpnOk(m:mem_opn):bool { if m is MConst then true else if m is MReg then RegOk(m._mreg) else RegOk(m._mbase) && RegOk(m._mindex) } function Eval(r:regs, o:opn):int { if o is OConst then o._const else r.regs[o._reg] } function EvalPtr(r:regs, o:opn_mem):int { EvalMemOpn(r, o._ptr) } function EvalPtrOk(o:opn_mem):bool { EvalMemOpnOk(o._ptr) } function EvalViaSegment(r:regs, c:core_state, m:mem, segment_index:int, o:opn_mem):int { // REVIEW: Eventually, should update ?System to depend on CPL! LogicalLoad(c.seg_regs[segment_index], paging_enabled(c), m, c.caches.TLB, c.caches.TLB_activeLabel, ?System, EvalPtr(r, o)).<> //m.map[EvalPtr(r, o)] } function SrcOkViaSegment(r:regs, c:core_state, m:mem, segment_index:int, o:opn_mem):bool { //PhysPtrOk(EvalPtr(r, o)) // REVIEW: Eventually, should update ?System to depend on CPL! EvalPtrOk(o) && LogicalLoad(c.seg_regs[segment_index], paging_enabled(c), m, c.caches.TLB, c.caches.TLB_activeLabel, ?System, EvalPtr(r, o)) != <>() } function DstOkViaSegment(r:regs, c:core_state, m:mem, segment_index:int, o:opn_mem):bool { // REVIEW: Eventually, should update ?System to depend on CPL! (forall $val:int :: EvalPtrOk(o) && LogicalStore(c.seg_regs[segment_index], paging_enabled(c), m, c.caches.TLB, c.caches.TLB_activeLabel, ?System, EvalPtr(r, o), $val) != <>()) } function EvalMem(r:regs, c:core_state, m:mem, o:opn_mem):int { EvalViaSegment(r, c, m, DS, o) } function SrcOk(o:opn):bool { if o is OConst then word(o._const) else RegOk(o._reg) } function DstOk(o:opn):bool { o is OReg && RegOk(o._reg) } //- By default, everyone uses DS function MemSrcOk(r:regs, c:core_state, m:mem, o:opn_mem):bool { SrcOkViaSegment(r, c, m, DS, o) } function MemDstOk(r:regs, c:core_state, m:mem, o:opn_mem):bool { DstOkViaSegment(r, c, m, DS, o) } //- Where is the instruction that follows Eip? //- (This equals Eip + sizeof(instruction at Eip).) function NextEip(Eip:int):int; function Efl_Cmp(_efl:int, x:int, y:int):int; function Efl_Add(_efl:int, x:int, y:int):int; function Efl_Sub(_efl:int, x:int, y:int):int; function Efl_Mul(_efl:int, x:int, y:int):int; function Efl_Div(_efl:int, x:int, y:int):int; function Efl_Not(_efl:int, x:int):int; function Efl_And(_efl:int, x:int, y:int):int; function Efl_Or(_efl:int, x:int, y:int):int; function Efl_Xor(_efl:int, x:int, y:int):int; function Efl_Shl(_efl:int, x:int, y:int):int; function Efl_Shr(_efl:int, x:int, y:int):int; function Efl_Rol(_efl:int, x:int, y:int):int; function Efl_Ror(_efl:int, x:int, y:int):int; //- Entirely ghost update function InOutUpdate(io:IOState):IOState { IOState( io._vga, io._keyboard, io._iom, io._pci, io._inCtr + 1, io._outCtr + 1 ) } //- Entirely ghost update function OutUpdate(io:IOState):IOState { IOState( io._vga, io._keyboard, io._iom, io._pci, io._inCtr, io._outCtr+1 ) } function VgaUpdate(io:IOState, vga:VgaState):IOState { IOState( vga, io._keyboard, io._iom, io._pci, io._inCtr, io._outCtr ) } function KeyboardUpdate(io:IOState, keyboard:KeyboardState):IOState { IOState( io._vga, keyboard, io._iom, io._pci, io._inCtr, io._outCtr ) } function IomUpdate(io:IOState, iom:IomState):IOState { IOState( io._vga, io._keyboard, iom, io._pci, io._inCtr, io._outCtr ) } function PciUpdate(io:IOState, pci:PciState):IOState { IOState( io._vga, io._keyboard, io._iom, pci, io._inCtr, io._outCtr ) } function MemUpdate1ViaSegment(r:regs, c:core_state, m:mem, segment_index:int, dst:opn_mem, v:int):mem { // REVIEW: Eventually, should update ?System to depend on CPL! LogicalStore(c.seg_regs[segment_index], paging_enabled(c), m, c.caches.TLB, c.caches.TLB_activeLabel, ?System, EvalPtr(r, dst), v).<> } function MemUpdate1(r:regs, c:core_state, m:mem, dst:opn_mem, v:int):mem { MemUpdate1ViaSegment(r, c, m, DS, dst, v) } function StackUpdate1(r:regs, c:core_state, m:mem, dst:opn_mem, v:int):mem { MemUpdate1ViaSegment(r, c, m, SS, dst, v) } //-//////////////////////////////////////////////////////////////////////////// //- GHOST OPERATIONS //-//////////////////////////////////////////////////////////////////////////// atomic ghost procedure memEmpty() returns(linear m:mem); ensures (forall i:int::{m.dom[i]} !m.dom[i]); atomic ghost procedure memTransfer(linear src:mem, linear dst:mem, b:[int]bool) returns(linear _src:mem, linear _dst:mem); requires (forall i:int::b[i] ==> src.dom[i]); ensures (forall i:int::{b[i]}{_src.dom[i]}{TV(i)} TV(i) ==> (_src.dom[i] <==> src.dom[i] && !b[i])); ensures (forall i:int::{b[i]}{_dst.dom[i]}{TV(i)} TV(i) ==> ( _dst.dom[i] <==> dst.dom[i] || b[i])); ensures _src.map == src.map; ensures (forall i:int::{b[i]}{_dst.map[i]}{TV(i)} TV(i) ==> ( _dst.map[i] == (if b[i] then src else dst).map[i])); atomic ghost procedure memDisjoint(const linear m1:mem, const linear m2:mem); ensures (forall i:int::{m1.dom[i]} {m2.dom[i]} !m1.dom[i] || !m2.dom[i]); atomic ghost procedure memDomIsMemAddr(const linear m:mem, i:int); requires m.dom[i]; ensures memAddr(i); // REVIEW atomic procedure instr_DropTempRegs(my r:regs, _regs:[int]int) returns(my _r:regs); requires (forall i:int :: RegOk(i) ==> _regs[i] == r.regs[i]); ensures _r.regs == _regs; ensures _r.efl == r.efl; type InitStateMachine = EntryPoint() | StaticsEnabled(); //- Proving the code is where we expect enables access to static variables //- in the code segment of the 64K of protected memory atomic ghost procedure enableStatics(linear initState:InitStateMachine) returns (linear _initState:InitStateMachine, linear static_mem:mem); #ifdef AppLoader requires ?CodeBase == 0x300000; #else requires ?CodeBase == 0x340000; #endif requires initState is EntryPoint; ensures _initState is StaticsEnabled; ensures (forall i:int::{memAddr(i)}{static_mem.dom[i]} memAddr(i) && !memAddrMain(i) ==> static_mem.dom[i]); //-//////////////////////////////////////////////////////////////////////////// //- INSTRUCTIONS //-//////////////////////////////////////////////////////////////////////////// atomic procedure instr_Mov(my r:regs, x:int, y:opn) returns(my _r:regs); ensures _r.regs == r.regs[x := Eval(r, y)]; ensures _r.efl == r.efl; ensures word(_r.regs[x]); atomic procedure instr_Add(my r:regs, x:int, y:opn) returns(my _r:regs); ensures _r.regs == r.regs[x := wrap32(r.regs[x] + Eval(r, y))]; ensures _r.efl == Efl_Add(r.efl, r.regs[x], Eval(r, y)); ensures word(_r.regs[x]); //- Add with carry (ADC) atomic procedure instr_AddCarry(my r:regs, x:int, y:opn) returns(my _r:regs); ensures let carry:int := if Cf(r.efl) then 1 else 0 in _r.regs == r.regs[x := wrap32(r.regs[x] + Eval(r, y) + carry)] && _r.efl == Efl_Add(r.efl, r.regs[x] + carry, Eval(r, y)); ensures word(_r.regs[x]); atomic procedure instr_Sub(my r:regs, x:int, y:opn) returns(my _r:regs); ensures _r.regs == r.regs[x := wrap32(r.regs[x] - Eval(r, y))]; ensures word(_r.regs[x]); atomic procedure instr_AddNoFlags(my r:regs, x:int, y:opn) returns(my _r:regs); ensures _r.regs == r.regs[x := wrap32(r.regs[x] + Eval(r, y))]; ensures _r.efl == r.efl; ensures word(_r.regs[x]); atomic procedure instr_SubNoFlags(my r:regs, x:int, y:opn) returns(my _r:regs); ensures _r.regs == r.regs[x := wrap32(r.regs[x] - Eval(r, y))]; ensures _r.efl == r.efl; ensures word(_r.regs[x]); //- run-time overflow checked atomic procedure instr_AddChecked(my r:regs, x:int, y:opn) returns(my _r:regs); ensures _r.regs == r.regs[x := r.regs[x] + Eval(r, y)]; ensures word(_r.regs[x]); atomic procedure instr_SubChecked(my r:regs, x:int, y:opn) returns(my _r:regs); ensures _r.regs == r.regs[x := r.regs[x] - Eval(r, y)]; ensures word(_r.regs[x]); atomic procedure instr_Mul(my r:regs, y:opn) returns(my _r:regs); ensures (exists hi:int :: _r.regs == r.regs[EDX := hi][EAX := wrap32(Mult(r.regs[EAX], Eval(r, y)))]); ensures word(_r.regs[EAX]) && word(_r.regs[EDX]); atomic procedure instr_Mul64(my r:regs, y:opn) returns(my _r:regs); ensures _r.regs == r.regs [EDX := Div(Mult(r.regs[EAX], Eval(r, y)), 0x100000000)] [EAX := wrap32(Mult(r.regs[EAX], Eval(r, y)))]; ensures word(_r.regs[EAX]) && word(_r.regs[EDX]); //- run-time overflow checked atomic procedure instr_MulChecked(my r:regs, y:opn) returns(my _r:regs); ensures (exists hi:int :: _r.regs == r.regs[EDX := hi][EAX := Mult(r.regs[EAX], Eval(r, y))]); ensures word(_r.regs[EAX]) && word(_r.regs[EDX]); //- Note: we only support 32-bit division, so the upper 32 bits EDX must be 0 //- EDX <- remainder EAX mod y //- EAX <- quotient EAX div y atomic procedure instr_Div(my r:regs, y:opn) returns(my _r:regs); requires r.regs[EDX] == 0; requires Eval(r, y) != 0; ensures _r.regs == r.regs [EDX := r.regs[EAX] mod Eval(r, y)] [EAX := r.regs[EAX] div Eval(r, y)]; ensures word(_r.regs[EAX]) && word(_r.regs[EDX]); atomic procedure instr_Not(my r:regs, x:int) returns(my _r:regs); ensures _r.regs == r.regs[x := neg(r.regs[x])]; ensures word(_r.regs[x]); atomic procedure instr_And(my r:regs, x:int, y:opn) returns(my _r:regs); ensures _r.regs == r.regs[x := and(r.regs[x], Eval(r, y))]; ensures word(_r.regs[x]); atomic procedure instr_Or(my r:regs, x:int, y:opn) returns(my _r:regs); ensures _r.regs == r.regs[x := or(r.regs[x], Eval(r, y))]; ensures word(_r.regs[x]); atomic procedure instr_Xor(my r:regs, x:int, y:opn) returns(my _r:regs); ensures _r.regs == r.regs[x := xor(r.regs[x], Eval(r, y))]; ensures word(_r.regs[x]); atomic procedure instr_Shl(my r:regs, x:int, y:opn) returns(my _r:regs); requires Eval(r, y) < 32; ensures _r.regs == r.regs[x := shl(r.regs[x], Eval(r, y))]; ensures word(_r.regs[x]); atomic procedure instr_Shr(my r:regs, x:int, y:opn) returns(my _r:regs); requires Eval(r, y) < 32; ensures _r.regs == r.regs[x := shr(r.regs[x], Eval(r, y))]; ensures word(_r.regs[x]); atomic procedure instr_Rol(my r:regs, x:int, y:opn) returns(my _r:regs); requires Eval(r, y) < 32; ensures _r.regs == r.regs[x := rol(r.regs[x], Eval(r, y))]; ensures word(_r.regs[x]); atomic procedure instr_Ror(my r:regs, x:int, y:opn) returns(my _r:regs); requires Eval(r, y) < 32; ensures _r.regs == r.regs[x := ror(r.regs[x], Eval(r, y))]; ensures word(_r.regs[x]); //- Sticks the carry flag (CF) in a register (see SETC instruction) atomic procedure instr_GetCf(my r:regs, x:int) returns(my _r:regs); requires r.regs[x] < 256; //- Instruction only writes a byte, so this simplifies the ensures ensures _r.regs == r.regs[x := if Cf(r.efl) then 1 else 0]; ensures word(_r.regs[x]); atomic procedure instr_Cmp(my r:regs, x:int, y:opn) returns(my _r:regs); ensures _r.regs == r.regs; ensures _r.efl == Efl_Cmp(r.efl, r.regs[x], Eval(r, y)); // Compare EAX with Mem[ptr]. If equal, Mem[ptr] := val. Otherwise M[ptr] is stored in EAX. //atomic procedure instr_Cmpxchg(linear s:state, ptr:opn, val:opn) returns (linear _s:state); // requires DstOk(ptr); // requires SrcOk(val); // modifies regs, efl; // ensures word(_s._cores[me]._regs[EAX]); // ensures _s == let _efl:int := Efl_Cmp(s._cores[me]._efl, s._cores[me]._regs[EAX], EvalMem(r, c, s, ptr)) in // if s._cores[me]._regs[EAX] == EvalMem(r, c, s, ptr) // then InsUpdate1(me, s, ptr, Eval(r, val), _efl) // else InsUpdate1(me, s, OReg(EAX), EvalMem(r, c, s, ptr), _efl); atomic procedure instr_Load(my r:regs, const my c:core_state, const linear m:mem, x:int, y:opn_mem) returns(my _r:regs); requires MemSrcOk(r, c, m, y); ensures _r.regs == r.regs[x := EvalMem(r, c, m, y)]; ensures _r.efl == r.efl; ensures word(_r.regs[x]); atomic procedure instr_Store(const my r:regs, const my c:core_state, linear m:mem, x:opn_mem, y:opn) returns(linear _m:mem); requires MemDstOk(r, c, m, x); ensures _m == MemUpdate1(r, c, m, x, Eval(r, y)); ensures word(EvalMem(r, c, _m, x)); atomic procedure instr_LoadStack(my r:regs, const my c:core_state, const linear m:mem, x:int, y:opn_mem) returns(my _r:regs); requires SrcOkViaSegment(r, c, m, SS, y); ensures _r.regs == r.regs[x := EvalViaSegment(r, c, m, SS, y)]; ensures _r.efl == r.efl; atomic procedure instr_StoreStack(const my r:regs, const my c:core_state, linear m:mem, x:opn_mem, y:opn) returns(linear _m:mem); requires DstOkViaSegment(r, c, m, SS, x); ensures _m == StackUpdate1(r, c, m, x, Eval(r, y)); atomic procedure instr_Lea(my r:regs, x:int, y:opn_mem) returns(my _r:regs); requires word(EvalPtr(r, y)); ensures _r.regs == r.regs[x := EvalPtr(r, y)]; ensures _r.efl == r.efl; atomic procedure instr_LeaUnchecked(my r:regs, x:int, y:opn_mem) returns(my _r:regs); ensures (exists v:int :: _r.regs == old(r.regs)[x := v]); ensures _r.efl == r.efl; // REVIEW: add more general support for signed arithmetic? atomic procedure instr_LeaSignedIndex(my r:regs, x:int, base:int, scale:int, index:int, offset:opn) returns(my _r:regs); requires scale == 1 || scale == 2 || scale == 4 || scale == 8; requires word(r.regs[base] + scale * asSigned(r.regs[index]) + Eval(r, offset)); ensures _r.regs == r.regs[x := r.regs[base] + scale * asSigned(r.regs[index]) + Eval(r, offset)]; ensures _r.efl == r.efl; //// TODO: the Ro instructions need to segment/page map! //// read and zero-extend 8 bits //atomic procedure instr_RoLoadU8(linear s:state, x:int, y:opn_mem) returns(linear _s:state); // requires DstOk(x); // requires inRo(EvalPtr(r, y), 1); // ensures word(regs[x]); // ensures _s == InsUpdate1(me, s, x, roU8(EvalPtr(r, y)), s._cores[me]._efl); // //// read and sign-extend 8 bits //atomic procedure instr_RoLoadS8(linear s:state, x:int, y:opn_mem) returns(linear _s:state); // requires DstOk(x); // requires inRo(EvalPtr(r, y), 1); // ensures word(regs[x]); // ensures (exists v:int:: asSigned(v) == roS8(EvalPtr(r, y)) // && _s == InsUpdate1(me, s, x, v, s._cores[me]._efl)); // //// read and zero-extend 16 bits //atomic procedure instr_RoLoadU16(linear s:state, x:int, y:opn_mem) returns(linear _s:state); // requires DstOk(x); // requires inRo(EvalPtr(r, y), 2); // ensures word(regs[x]); // ensures _s == InsUpdate1(me, s, x, roU16(EvalPtr(r, y)), s._cores[me]._efl); // //// read and sign-extend 16 bits //atomic procedure instr_RoLoadS16(linear s:state, x:int, y:opn_mem) returns(linear _s:state); // requires DstOk(x); // requires inRo(EvalPtr(r, y), 2); // ensures word(regs[x]); // ensures (exists v:int:: asSigned(v) == roS16(EvalPtr(r, y)) // && _s == InsUpdate1(me, s, x, v, s._cores[me]._efl)); // //atomic procedure instr_RoLoad32(linear s:state, x:int, y:opn_mem) returns(linear _s:state); // requires DstOk(x); // requires inRo(EvalPtr(r, y), 4); // ensures word(regs[x]); // ensures _s == InsUpdate1(me, s, x, ro32(EvalPtr(r, y)), s._cores[me]._efl); //- Used to check linearity in translation of "if(Jcc(r.efl)) { goto L; }" and procedure calls atomic procedure boogie_CheckJcc(const my r:regs); atomic procedure boogie_CheckCall(const my r:regs); function ReturnToCaller(r:regs):ReturnTo { #ifdef x64 ReturnToAddr64(r.regs[TMP1], r.regs[TMP2]) #else ReturnToAddr32(r.regs[TMP1]) #endif } //- Read eip of next instruction (used to model call instruction) //- A call instruction consists of: //- - esp := SubNoFlags(esp, 4) for x86 or esp := SubNoFlags(esp, 8) for x64 //- - TMP1 := MovNextEip() //- - StoreStack(esp, TMP1) //- - Boogie call to the procedure //- In x64 keep track of both words of RIP #ifdef x64 atomic procedure instr_MovNextEip64(my r:regs, x:int, y:int) returns(my _r:regs); ensures (exists nextEipLow:int, nextEipHigh:int :: _r.regs == r.regs[x := nextEipLow][y := nextEipHigh]); ensures _r.efl == r.efl; #else atomic procedure instr_MovNextEip32(my r:regs, x:int) returns(my _r:regs); ensures (exists nextEip:int :: _r.regs == r.regs[x := nextEip]); ensures _r.efl == r.efl; #endif //- A return instruction consists of: //- - TMP1 := LoadStack(esp) //- - esp := AddNoFlags(esp, 4) //- - Ret() //- - Boogie return //- Ret requires that the procedure returns to whoever called it //- (i.e. call/return is last-in, first-out). It does not //- require that the stack pointer be the same as before. #ifdef x64 atomic procedure instr_Ret(const my r:regs); requires RET == ReturnToAddr64(r.regs[TMP1], r.regs[TMP2]); #else atomic procedure instr_Ret(const my r:regs); requires RET == ReturnToAddr32(r.regs[TMP1]); #endif // An iret instruction consists of a call to IRet, which // models popping the 3 words eip, cs, eflags. // Example: // call $State := instr_IRet($State); return; // Needs to discuss the effect on CS, in particular, that the shadow descriptor is updated from memory // Also, someone needs to care about CS for that matter and this to be sound //atomic procedure instr_IRet(linear s:state) returns(linear _s:state); // requires MemSrcOk(r, c, s, OMem(MReg(ESP, 0))); // requires MemSrcOk(r, c, s, OMem(MReg(ESP, 4))); // requires MemSrcOk(r, c, s, OMem(MReg(ESP, 8))); // requires RET == ReturnToInterrupted( // EvalMem(r, c, s, OMem(MReg(ESP, 0))), // EvalMem(r, c, s, OMem(MReg(ESP, 4))), // EvalMem(r, c, s, OMem(MReg(ESP, 8)))); // ensures _s == InsUpdate1(me, // s, // OReg(ESP), // s._cores[me]._regs[ESP]+12, // s._cores[me]._efl); //- Read time-stamp counter (cycle counter) atomic procedure instr_Rdtsc(my r:regs) returns(my _r:regs); ensures (exists t1:int, t2:int :: word(t1) && word(t2) && _r.regs == r.regs[EAX := t1][EDX := t2]); ensures _r.efl == r.efl; //-//////////////////////////////////////////////////////////////////////////// //- Declassification //-//////////////////////////////////////////////////////////////////////////// function declassified(lg:int, rg:int, l:int, r:int):bool; function fun_declassified(lg:int, rg:int, l:int, r:int):bool { declassified(lg, rg, l, r) } //- Dafny-friendly name //- Convert a declassified word into a public word atomic procedure declassify(my r:regs, x:int, g:int) returns (my _r:regs); requires relation(declassified(left(g), right(g), left(r.regs[x]), right(r.regs[x]))); ensures _r.regs == r.regs[x := g]; ensures public(_r.regs[x]); //-//////////////////////////////////////////////////////////////////////////// //- SEGMENTS AND PAGES //-//////////////////////////////////////////////////////////////////////////// type SegmentDescriptor = SegmentDescriptor(segBase:int, segType:int); type SegmentRegister = SegmentRegister(index:int, descriptor:SegmentDescriptor); const ?SegmentDescriptorSize:int := 8; const ?SegmentDescriptorTypeData:int := 2; const ?SegmentDescriptorTypeCode:int := 8; function ValidSegmentDescriptor(descriptor:SegmentDescriptor):bool { (descriptor.segType == ?SegmentDescriptorTypeData && word(descriptor.segBase)) || descriptor.segType == ?SegmentDescriptorTypeCode } function SegmentDescriptorWord0(descriptor:SegmentDescriptor):int { or(shl(descriptor.segBase, 16), 0xffff) } // TODO: Bit-field manipulation function SegmentDescriptorWord1(descriptor:SegmentDescriptor):int { or( and(descriptor.segBase, 0xff000000), //- Upper 8 bits of base are upper 8 bits of the word or( shr(and(descriptor.segBase, 0x00ff0000),16), //- Next 8 bits of base are the lower 8 bits of the word //- Middle 16 bits of the word are the following flags: //- G = 1, D/B = 1, L = 0, AVL = 0, SegLimit = 0xf, P=1, DPL=00, S=1 (1=code/data,0=system), Type=0x2=Data shl(or(0xCF90, descriptor.segType), 8) //- 0xCF90 = binary 1100111110010000 ) ) } function ValidSegmentSelector(register:int, index:int):bool { register == shl(index, 3) //- Sets TI bit to 0 for GDT, and RPL to 0 } //function ValidSegmentRegister(register:SegmentRegister):bool //{ // ValidSegmentDescriptor(register.descriptor) //} function ValidGdtDescriptor(gdt_regs:GDT_regs, index:int, descriptor:SegmentDescriptor, mem:mem):bool { 0 < index && index < gdt_regs.GDT_len && ValidSegmentDescriptor(descriptor) && SegmentDescriptorWord0(descriptor) == mem.map[gdt_regs.GDT_base + index * ?SegmentDescriptorSize] && SegmentDescriptorWord1(descriptor) == mem.map[gdt_regs.GDT_base + index * ?SegmentDescriptorSize + 4] } //- Sample usage: //- call core := instr_ActivateDataSelector(r, core, state, index, descriptor, eax, DS); atomic procedure instr_ActivateDataSelector(const my r:regs, my c:core_state, const linear m:mem, index:int, descriptor:SegmentDescriptor, srcRegister:int, dstRegister:int) returns(my _c:core_state); requires ValidSegmentSelector(r.regs[srcRegister], index); requires ValidGdtDescriptor(c.gdt_regs, index, descriptor, m); requires descriptor.segType == ?SegmentDescriptorTypeData; requires SegRegOk(dstRegister) && dstRegister != CS; //ensures ValidSegmentRegister(SegmentRegister(index, descriptor)); ensures _c == core_state(c.cregs, c.gdt_regs, c.seg_regs[dstRegister := SegmentRegister(index, descriptor)], c.caches); // c[_seg_regs := c._seg_regs[dstRegister := SegmentRegister(index, descriptor)] ); //// Copies the value in a data segment selector into an ordinary register //atomic procedure instr_ReadDataSelector(linear s:state, srcRegister:int, dstRegister:int) // returns (linear _s:state); // requires SegRegOk(srcRegister) && srcRegister != CS; // ensures regs == old(regs)[dstRegister := ???]; // ensures core_state == old(core_state); ////[ckh] TODO: correct srcRegister: ensures _s == InsUpdate1(me, s, dstRegister, s._cores[me]._regs[srcRegister], s._cores[me]._efl); // Not sure what you would use this for, since you activate CS via a task switch or a jump, etc, not via mov eax cs //procedure ActivateCodeSelector($index:int, $descriptor:SegmentDescriptor, $srcRegister:int); // requires ValidSegmentSelector($srcRegister, $index); // requires ValidGdtDescriptor(s._cores[me]._gdt_regs, $index, $descriptor, $Mem); // requires $descriptor.segType == ?SegmentDescriptorTypeCode; // modifies $Cs; // ensures $Cs == SegmentRegister($index, $descriptor); // ensures ValidSegmentRegister($Cs); // procedure FetchSelector($register:SegmentRegister) returns ($index:int); function GdtParamsWord0(base:int, len:int):int { or(shl(base, 16), len * ?SegmentDescriptorSize) } function GdtParamsWord1(base:int, len:int):int { shr(base, 16) } //- len is specified in number of GDT entries, even though Intel expects it in bytes // TODO: break into micro-instructions atomic procedure instr_LoadGDT(const my r:regs, my c:core_state, const linear m:mem, base:int, len:int, addr:opn_mem) returns(my _c:core_state); requires 0 <= len && len < 8192; requires word(base); requires base >= ?memLo && base + len * ?SegmentDescriptorSize <= ?memHi; requires PhysPtrOk(m, EvalPtr(r, addr)) && PhysPtrOk(m, EvalPtr(r, addr) + 4); requires GdtParamsWord0(base, len) == m.map[EvalPtr(r, addr)]; requires GdtParamsWord1(base, len) == m.map[EvalPtr(r, addr) + 4]; ensures _c == core_state(c.cregs, GDT_regs(base, len), c.seg_regs, c.caches); //-/////////////////////////////////////////////////////////////////////////////// //- Protected Memory //- Note that Intel refers to a general pointer value as a "logical" address //- Segmentation transforms logical addresses into "linear" addresses, //- and paging (if enabled) transforms linear addresses into physical addresses //-/////////////////////////////////////////////////////////////////////////////// const ?User:bool := true; const ?System:bool := false; const ?Write:bool := true; const ?Read:bool := false; const ?Present:bool := true; const ?Absent:bool := false; //- Base should be the full ptr value (including lower 12 bits of 0s) type PageEntry = PageEntry(base:int, user:bool, write:bool, present:bool); // If you add a field, need to update the ensures clause of EnablePaging //type CR0 = CR0(PE:bool, PG:bool, WP:bool); // Protection enabled, Paging Enabled type <>; type <>; //- Creates a ternary bool value. Allows us to require Foo() != NULL, and then ensure Foo() == true type <>; type <>; //- Relevant CR0 bit positions const ?CR0_paging_enabled:int := 31; const ?CR0_write_protect:int := 16; const ?CR0_protection_enabled:int := 0; function paging_enabled(c:core_state):bool { GetBit(?CR0_paging_enabled, c.cregs[CR0]) } //- Requires protection is enabled, paging isn't function ValidPrePagingState(CR0:int):bool { GetBit(?CR0_protection_enabled, CR0) && !GetBit(?CR0_paging_enabled, CR0) && !GetBit(?CR0_write_protect, CR0) //- Supervisor can write to any page } //- Ensures that you can only write modified versions of existing CR0 values function fresh_CR0_val(val:int):bool; atomic procedure instr_ReadCR0(my r:regs, const my c:core_state, dstReg:int) returns(my _r:regs); ensures fresh_CR0_val(r.regs[dstReg]); ensures _r.regs == r.regs[dstReg := c.cregs[CR0]]; //- modifies efl ensures word(_r.regs[dstReg]); //- Currently, only allowed to use this to enable paging atomic procedure instr_WriteCR0(my r:regs, my c:core_state, newCR0:opn) returns(my _r:regs, my _c:core_state); requires word(Eval(r, newCR0)); requires ValidPrePagingState(c.cregs[CR0]); requires (exists x:int :: { fresh_CR0_val(x) } (Eval(r, newCR0) == SetBit(?CR0_paging_enabled, x)) && fresh_CR0_val(x)); ensures _r.regs == r.regs; //- modifies efl ensures _c == core_state(c.cregs[CR0 := SetBit(?CR0_paging_enabled, c.cregs[CR0])], c.gdt_regs, c.seg_regs, c.caches); //-///////////////////////////////////////////////////// //- Protected memory load //-///////////////////////////////////////////////////// function LogicalLoad(segReg:SegmentRegister, cr0_pg:bool, mem:mem, TLB:[int][TLB_label]PageEntry, cacheLabel:TLB_label, user:bool, ptr:int): <> { let linear_addr:int := SegmentMap(segReg, ptr) in LinearLoad(cr0_pg, mem, linear_addr, user, TLB, cacheLabel) // if SegmentMap(segReg, ptr) != <>() && // LinearLoad($CR0.PG, s._mem, SegmentMap(segReg, ptr).<>, user, $TLB, $TLB_activeLabel) != <>() // then // LinearLoad($CR0.PG, s._mem, SegmentMap(segReg, ptr).<>, user, $TLB, $TLB_activeLabel); // else // <>() } //// REVIEW: Is a single $TLB_activeLabel sufficient? What if there's an implied instruction load via a different label? //// Read a word from segmented memory //// REVIEW: Should we restructure so the PhysLoad is done on the result of paging application in the ensures below? function LogicalStore(segReg:SegmentRegister, cr0_pg:bool, mem:mem, TLB:[int][TLB_label]PageEntry, cacheLabel:TLB_label, user:bool, ptr:int, val:int):<> { let linear_addr:int := SegmentMap(segReg, ptr) in LinearStore(cr0_pg, mem, linear_addr, user, TLB, cacheLabel, val) } function SegmentMap(segReg:SegmentRegister, ptr:int):int { segReg.descriptor.segBase + ptr // if ValidSegmentRegister($segReg) then // <>($segReg.descriptor.segBase + $ptr) // else // <>() } function LinearLoad(pagingEnabled:bool, mem:mem, ptr:int, user:bool, TLB:[int][TLB_label]PageEntry, cacheLabel:TLB_label):<> { if pagingEnabled then let <> memAddr:int := PageMap(ptr, user, ?Read, TLB, cacheLabel) in LoadPhysical(mem, memAddr) else LoadPhysical(mem, ptr) } function LinearStore(pagingEnabled:bool, mem:mem, ptr:int, user:bool, TLB:[int][TLB_label]PageEntry, cacheLabel:TLB_label, val:int):<> { if pagingEnabled then let <> memAddr:int := PageMap(ptr, user, ?Write, TLB, cacheLabel) in StorePhysical(mem, memAddr, val) else StorePhysical(mem, ptr, val) } function PageMap(ptr:int, user:bool, write:bool, TLB:[int][TLB_label]PageEntry, cacheLabel:TLB_label):<> { let cpte:PageEntry := TLB[PageNumber(ptr)][cacheLabel] in if cpte.present && (user == ?System || !write || cpte.write == ?Write) && (user == ?System || cpte.user == ?User) then <>(or(cpte.base, PhysOffset(ptr))) else <>() } //- The top 20 bits (bits 31:12) of the memory address are used to index into the TLB function PageNumber(ptr:int):int { shr(ptr, 12) } //- The top 10 bits (bits 31:22) of the memory address are used to index into the PDE cache function PteNumber(ptr:int):int { shr(ptr, 22) } function IsUser(CPL:int):bool { CPL == 3 } //-///////////////////////////////////////////////////// //- TLB updates //-///////////////////////////////////////////////////// // TODO: Must call this to model processor's unpredictable behavior w.r.t. paging caches <<<<<<<<<<<<<<<<<<<<<<<< //-atomic procedure instr_HavocPagingCaches(linear m:mem, c:core_state) returns(linear _m:mem); //- requires c == core_state; //- requires paging_enabled(s._cores[me]) ==> //- (forall $ptr:int, $dlabel:DTLB_label :: //- word($ptr) ==> DTLBIsFreshWrtMemOneEntry(c._cregs[CR3], c._caches.DTLB, $dlabel, m, $ptr) != <>()); //- requires paging_enabled(s._cores[me]) ==> //- (forall $ptr:int, $dlabel:DTLB_label, $label:TLB_label :: //- word($ptr) ==> TLBIsFreshWrtDTLBOneEntry(c._cregs[CR3], c._caches.DTLB, $dlabel, c._caches.TLB, $label, m, $ptr) != <>()); //- modifies core_state; //- ensures paging_enabled(s._cores[me]) ==> //- core_state == core_state(c._cregs, c._gdt_regs, c._seg_regs, //- paging_caches(_s._cores[me]._ext._caches.TLB, _s._cores[me]._ext._caches.DTLB, //- c._caches.TLB_activeLabel, c._caches.DTLB_activeLabel)); //- ensures paging_enabled(s._cores[me]) ==> //- (forall $ptr:int, $dlabel:DTLB_label :: //- _s._cores[me]._ext._caches.DTLB[PteNumber($ptr)][$dlabel] == c._caches.DTLB[PteNumber($ptr)][$dlabel] || //- (word($ptr) ==> DTLBIsFreshWrtMemOneEntry(c._cregs[CR3], _s._cores[me]._ext._caches.DTLB, $dlabel, m, $ptr).<>)); //- ensures paging_enabled(s._cores[me]) ==> //- (forall $ptr:int, $label:TLB_label, $dlabel:DTLB_label :: //- _s._cores[me]._ext._caches.TLB[PageNumber($ptr)][$label] == c._caches.TLB[PageNumber($ptr)][$label] || //- (word($ptr) ==> TLBIsFreshWrtDTLBOneEntry(c._cregs[CR3], c._caches.DTLB, $dlabel, //- _s._cores[me]._ext._caches.TLB, $label, m, $ptr).<>)); //- //-atomic procedure instr_WriteCR3(linear m:mem, newCR3:opn) returns(linear _m:mem); //- requires ValidCR3(Eval(r, newCR3)); //- requires DTLBsAreFreshWrtMem(Eval(r, newCR3), core_state._caches.DTLB, m) != <>(); //- requires TLBsAreFreshWrtMem(Eval(r, newCR3), core_state._caches.TLB, m) != <>(); //- modifies efl, core_state; //- ensures core_state == (let c:core_state := old(core_state) in // Everything is the same, except CR3 and the TLB and DTLB //- core_state(c._cregs[CR3 := Eval(r, newCR3)], c._gdt_regs, c._seg_regs, //- paging_caches(_s._cores[me]._ext._caches.TLB, _s._cores[me]._ext._caches.DTLB, //- c._caches.TLB_activeLabel, c._caches.DTLB_activeLabel))); //- ensures DTLBsAreFreshWrtMem(Eval(r, newCR3), _s._cores[me]._ext._caches.DTLB, m) == <>(true); //- ensures TLBsAreFreshWrtMem(Eval(r, newCR3), _s._cores[me]._ext._caches.TLB, m) == <>(true); //- //-// Specifies the INVLPG instruction //-atomic procedure instr_InvalidatePagingCaches(linear m:mem, ptr:opn_mem) returns(linear _m:mem); //- requires word(EvalPtr(regs, ptr)); //- requires DTLBsAreFreshWrtMem(core_state._cregs[CR3], core_state._caches.DTLB, m) != <>(); //- requires TLBsAreFreshWrtMemOneEntry(core_state._cregs[CR3], core_state._caches.TLB, m, EvalPtr(regs, ptr)) != <>(); //- modifies efl, core_state; //- ensures core_state == (let c:core_state := old(core_state) in // Everything is the same, except the TLB and DTLB //- core_state(c._cregs, c._gdt_regs, c._seg_regs, //- paging_caches(_s._cores[me]._ext._caches.TLB, _s._cores[me]._ext._caches.DTLB, //- c._caches.TLB_activeLabel, c._caches.DTLB_activeLabel))); //- ensures DTLBsAreFreshWrtMem(old(core_state)._cregs[CR3], _s._cores[me]._ext._caches.DTLB, m) == <>(true); //- ensures TLBsAreFreshWrtMemOneEntry(old(core_state)._cregs[CR3], _s._cores[me]._ext._caches.TLB, m, EvalPtr(r, ptr)) == <>(true); function DTLBsAreFreshWrtMem(CR3:int, DTLB:[int][DTLB_label]PageEntry, mem:mem):<> { if (forall ptr:int :: {DTLBsAreFreshWrtMemOneEntry(CR3, DTLB, mem, ptr)} {DTLB[PteNumber(ptr)]} word(ptr) ==> DTLBsAreFreshWrtMemOneEntry(CR3, DTLB, mem, ptr) != <>()) then <>((forall ptr:int :: {DTLBsAreFreshWrtMemOneEntry(CR3, DTLB, mem, ptr)} word(ptr) ==> DTLBsAreFreshWrtMemOneEntry(CR3, DTLB, mem, ptr) == <>(true))) else <>() } function TLBsAreFreshWrtMem(CR3:int, TLB:[int][TLB_label]PageEntry, mem:mem):<> { if (forall ptr:int :: {TLB[PageNumber(ptr)]} word(ptr) ==> TLBsAreFreshWrtMemOneEntry(CR3, TLB, mem, ptr) != <>()) then <>((forall ptr:int :: {TLB[PageNumber(ptr)]} word(ptr) ==> TLBsAreFreshWrtMemOneEntry(CR3, TLB, mem, ptr) == <>(true))) else <>() } function DTLBsAreFreshWrtMemOneEntry(CR3:int, DTLB:[int][DTLB_label]PageEntry, mem:mem, ptr:int):<> { if (forall x:DTLB_label :: {DTLBIsFreshWrtMemOneEntry(CR3, DTLB, x, mem, ptr)} {DTLB[PteNumber(ptr)][x]} DTLBIsFreshWrtMemOneEntry(CR3, DTLB, x, mem, ptr) != <>()) then <>((forall y:DTLB_label :: {DTLBIsFreshWrtMemOneEntry(CR3, DTLB, y, mem, ptr)} {DTLB[PteNumber(ptr)][y]} DTLBIsFreshWrtMemOneEntry(CR3, DTLB, y, mem, ptr) == <>(true))) else <>() } function TLBsAreFreshWrtMemOneEntry(CR3:int, TLB:[int][TLB_label]PageEntry, mem:mem, ptr:int):<> { if (forall x:TLB_label :: {TLB[PageNumber(ptr)][x]} TLBIsFreshWrtMemOneEntry(CR3, TLB, x, mem, ptr) != <>()) then <>((forall y:TLB_label :: {TLB[PageNumber(ptr)][y]} TLBIsFreshWrtMemOneEntry(CR3, TLB, y, mem, ptr) == <>(true))) else <>() } function DTLBIsFreshWrtMemOneEntry(CR3:int, DTLB:[int][DTLB_label]PageEntry, dlabel:DTLB_label, mem:mem, ptr:int):<> { let <> pdeWord:int := LoadPhysical(mem, PDEaddr(CR3, ptr)) in <>(PageEntryToWord(DTLB[PteNumber(ptr)][dlabel]) == pdeWord) } function TLBIsFreshWrtMemOneEntry(CR3:int, TLB:[int][TLB_label]PageEntry, label:TLB_label, mem:mem, ptr:int):<> { let <> pdeWord:int := LoadPhysical(mem, PDEaddr(CR3, ptr)) in let <> pde:PageEntry := WordToPageEntry(pdeWord) in TLBIsFreshWrtMemOneEntryHelper(TLB, label, mem, ptr, pde) } function TLBIsFreshWrtDTLBOneEntry(CR3:int, DTLB:[int][DTLB_label]PageEntry, dlabel:DTLB_label, TLB:[int][TLB_label]PageEntry, label:TLB_label, mem:mem, ptr:int):<> { let cpde:PageEntry := DTLB[PteNumber(ptr)][dlabel] in if cpde.present then TLBIsFreshWrtMemOneEntryHelper(TLB, label, mem, ptr, cpde) else <>() } //- This one expects that you've already retrieved the PDE in some fashion function TLBIsFreshWrtMemOneEntryHelper(TLB:[int][TLB_label]PageEntry, label:TLB_label, mem:mem, ptr:int, pde:PageEntry):<> { if pde.present then let <> pteWord:int := LoadPhysical(mem, PTEaddr(pde, ptr)) in let <> pte:PageEntry := WordToPageEntry(pteWord) in <>(TLB[PageNumber(ptr)][label] == CombinePerms(pte, pde)) else <>(TLB[PageNumber(ptr)][label] == PageEntry(0, false, false, ?Absent)) //- All we care about is the absent bit } function CombinePerms(pte:PageEntry, pde:PageEntry):PageEntry { PageEntry(pte.base, pte.user && pde.user, pte.write && pde.write, pte.present) } //- size in bytes const ?sizeofPDE:int := 4; const ?sizeofPTE:int := 4; function PDEaddr(CR3:int, ptr:int):int { PageDirectoryBase(CR3) + mul(PageDirectoryOffset(ptr), ?sizeofPDE) } function PTEaddr(pde:PageEntry, ptr:int):int { pde.base + mul(PageTableOffset(ptr), ?sizeofPTE) } //-///////////////////////////////////////////////////// //- Functions that split a memory pointer into various //- offsets into the hierachical paging structures //-///////////////////////////////////////////////////// function PageEntryBase(ptr:int):int { ClearLSBs(12, ptr) } function PageDirectoryBase(CR3:int):int { PageEntryBase(CR3) } //- Top 10 bits index into the list of PDEs function PageDirectoryOffset(ptr:int):int { SelectLSBs(10, shr(ptr, 22)) //- Note that with 32 bits, the selectLSBs is actually a NO-OP. } //- Next 10 bits index into the list of PTEs pointed at by the PDE selected above function PageTableOffset(ptr:int):int { SelectLSBs(10, shr(ptr, 12)) } //- Final 12 bits are an index into the physical 4096-byte page frame pointed at by the PTE selected above function PhysOffset(ptr:int):int { SelectLSBs(12, ptr) } const ?PagingPATbitPos:int := 7; const ?PagingPCDbitPos:int := 4; const ?PagingPWTbitPos:int := 3; const ?PagingUserBitPos:int := 2; const ?PagingWriteBitPos:int := 1; const ?PagingPresentBitPos:int := 0; function ValidCR3(cr3:int):bool { //- We require that PCD=0 and PWT=0 GetBit(?PagingPCDbitPos, cr3) == false && GetBit(?PagingPWTbitPos, cr3) == false } //- Actual memory layout of a page entry function PageEntryToWord(pe:PageEntry):int { ClearBit(?PagingPATbitPos, //- Must be 0 for PDE. For PTE, it's the PAT bit. // REVIEW: This affects the memory type used. Is 0 okay? ClearBit(?PagingPCDbitPos, //- PCD ClearBit(?PagingPWTbitPos, //- PWT AssignBit(?PagingUserBitPos, pe.user, AssignBit(?PagingWriteBitPos, pe.write, AssignBit(?PagingPresentBitPos, pe.present, pe.base)))))) } function WordToPageEntry(word:int):<> { if !GetBit(?PagingPATbitPos, word) && !GetBit(?PagingPCDbitPos, word) && !GetBit(?PagingPWTbitPos, word) then <>(PageEntry( ClearLSBs(12, word), GetBit(?PagingUserBitPos, word), GetBit(?PagingWriteBitPos, word), GetBit(?PagingPresentBitPos, word))) else <>() } function GetBit (i:int, val:int):bool { and(val, shl(1, i)) != 0 } function SetBit (i:int, val:int):int { or(val, shl(1, i)) } function ClearBit (i:int, val:int):int { and(val, neg(shl(1, i))) } function AssignBit(i:int, bit:bool, val:int):int { if bit then SetBit(i, val) else ClearBit(i, val) } //- Clears the lower amount bits of val function ClearLSBs (amount:int, val:int):int { and(val, neg(sub(shl(1, amount), 1))) } //- Clears all but the lower amount bits of val function SelectLSBs(amount:int, val:int):int { and(val, sub(shl(1, amount), 1)) } //-//////////////////////////////////////////////////////////// //- Functions that represent direct access to physical memory //-//////////////////////////////////////////////////////////// function LoadPhysical(mem:mem, ptr:int):<> { if PhysPtrOk(mem, ptr) then <>(mem.map[ptr]) else <>() } // REVIEW: Should this require word($val)? // It appears all of the callers ensure it, but that seems brittle function StorePhysical(mem:mem, ptr:int, val:int):<> { if PhysPtrOk(mem, ptr) then <>(mem_update(mem, ptr, val)) else <>() } } ================================================ FILE: ironclad-apps/src/Trusted/Spec/AssemblySpec.imp.basm ================================================ //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- //- module implementation AssemblySpec { implementation memEmpty() returns(linear m:mem) {} implementation memTransfer(linear src:mem, linear dst:mem, b:[int]bool) returns(linear _src:mem, linear _dst:mem) {} implementation memDisjoint(const linear m1:mem, const linear m2:mem) {} implementation memDomIsMemAddr(const linear m:mem, i:int) {} implementation enableStatics(linear initState:InitStateMachine) returns (linear _initState:InitStateMachine, linear static_mem:mem) {} implementation declassify(my r:regs, x:int, g:int) returns (my _r:regs) {} } ================================================ FILE: ironclad-apps/src/Trusted/Spec/Assembly_axioms.bpl ================================================ //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- //-//////////////////////////////////////////////////////////////////////////// //- ASSEMBLY LANGUAGE //-//////////////////////////////////////////////////////////////////////////// //-///// Flag Handling //////////// axiom (forall f:int, x:int, y:int::{Je (Efl_Cmp(f, x, y))} Je (Efl_Cmp(f, x, y)) == (x == y)); axiom (forall f:int, x:int, y:int::{Jne(Efl_Cmp(f, x, y))} Jne(Efl_Cmp(f, x, y)) == (x != y)); axiom (forall f:int, x:int, y:int::{Jbe(Efl_Cmp(f, x, y))} Jbe(Efl_Cmp(f, x, y)) == (x <= y)); axiom (forall f:int, x:int, y:int::{Jb (Efl_Cmp(f, x, y))} Jb (Efl_Cmp(f, x, y)) == (x < y)); axiom (forall f:int, x:int, y:int::{Jae(Efl_Cmp(f, x, y))} Jae(Efl_Cmp(f, x, y)) == (x >= y)); axiom (forall f:int, x:int, y:int::{Ja (Efl_Cmp(f, x, y))} Ja (Efl_Cmp(f, x, y)) == (x > y)); axiom (forall f:int, x:int, y:int::{Cf (Efl_Add(f, x, y))} Cf (Efl_Add(f, x, y)) == (x + y >= WORD_HI)); ================================================ FILE: ironclad-apps/src/Trusted/Spec/BaseSpec.ifc.basm ================================================ //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module interface BaseSpec { //-//////////////////////////////////////////////////////////////////////////// //- TRIGGERS //-//////////////////////////////////////////////////////////////////////////// //- Triggers for quantifiers //- We could use a single trigger for all values; the distinction between the //- various triggers below is just to help the prover run fast. //- TV is a trigger for values in general, including addresses. function{:expand false} TV(val:int):bool { true } //- TO is a trigger specifically for word offsets from addresses, where //- word offset n is byte offset 4 * n. function{:expand false} TO(wordOffset:int):bool { true } //-//////////////////////////////////////////////////////////////////////////// //- WORDS //-//////////////////////////////////////////////////////////////////////////// //- i1 <= x < i2 function between(i1:int, i2:int, x:int):bool { i1 <= x && x < i2 } //- valid 32-bit unsigned words //- word(i) <==> 0 <= i < 2^32 const WORD_HI:int; //- 2^32 function word(val:int):bool { 0 <= val && val < WORD_HI } atomic ghost procedure reveal_WORD_HI(); ensures WORD_HI == 4294967296; function wrap32(val:int):int; atomic ghost procedure reveal_wrap32(val:int); ensures wrap32(val) == val mod WORD_HI; //- converts 2's complement 32-bit val into signed integer function asSigned(val:int) returns(int); function{:expand false} add(i1:int, i2:int):int { i1 + i2 } function{:expand false} sub(i1:int, i2:int):int { i1 - i2 } function{:expand false} mul(i1:int, i2:int):int { i1 * i2 } function{:expand false} _div(i1:int, i2:int):int { i1 div i2 } function{:expand false} _mod(i1:int, i2:int):int { i1 mod i2 } function{:expand false} le(i1:int, i2:int):bool { i1 <= i2 } function{:expand false} lt(i1:int, i2:int):bool { i1 < i2 } function{:expand false} ge(i1:int, i2:int):bool { i1 >= i2 } function{:expand false} gt(i1:int, i2:int):bool { i1 > i2 } function neg (x:int):int; function and (x:int, y:int):int; function or (x:int, y:int):int; function xor (x:int, y:int):int; function shl (x:int, y:int):int; function shr (x:int, y:int):int; function rol (x:int, y:int):int; function ror (x:int, y:int):int; function int_bit(n:int, index:int):bool; atomic ghost procedure reveal_int_bit(n:int, index:int); ensures int_bit(n, index) == (if (index > 0) then int_bit(n div 2, index - 1) else n mod 2 != 0); atomic ghost procedure axiom_neg(x:int); ensures word(x) ==> word(neg(x)); ensures (forall i:int::{int_bit(neg(x), i)} 0 <= i && i < 32 ==> int_bit(neg(x), i) == !int_bit(x, i)); atomic ghost procedure axiom_and(x:int, y:int); ensures word(x) && word(y) ==> word(and(x, y)); ensures (forall i:int::{int_bit(and(x, y), i)} 0 <= i && i < 32 ==> int_bit(and(x, y), i) == (int_bit(x, i) && int_bit(y, i))); atomic ghost procedure axiom_or (x:int, y:int); ensures word(x) && word(y) ==> word(or (x, y)); ensures (forall i:int::{int_bit(or (x, y), i)} 0 <= i && i < 32 ==> int_bit(or (x, y), i) == (int_bit(x, i) || int_bit(y, i))); atomic ghost procedure axiom_xor(x:int, y:int); ensures word(x) && word(y) ==> word(xor(x, y)); ensures (forall i:int::{int_bit(xor(x, y), i)} 0 <= i && i < 32 ==> int_bit(xor(x, y), i) == (int_bit(x, i) != int_bit(y, i))); atomic ghost procedure axiom_shl(x:int, y:int); ensures word(x) && word(y) ==> word(shl(x, y)); ensures (forall i:int::{int_bit(shl(x, y), i)} 0 <= i && i < 32 ==> int_bit(shl(x, y), i) == (i - y >= 0 && int_bit(x, i - y))); atomic ghost procedure axiom_shr(x:int, y:int); ensures word(x) && word(y) ==> word(shr(x, y)); ensures (forall i:int::{int_bit(shr(x, y), i)} 0 <= i && i < 32 ==> int_bit(shr(x, y), i) == (i + y < 32 && int_bit(x, i + y))); atomic ghost procedure axiom_rol(x:int, y:int); ensures word(x) && word(y) ==> word(rol(x, y)); ensures (forall i:int::{int_bit(rol(x, y), i)} 0 <= i && i < 32 ==> int_bit(rol(x, y), i) == int_bit(x, (i - y) mod 32)); atomic ghost procedure axiom_ror(x:int, y:int); ensures word(x) && word(y) ==> word(ror(x, y)); ensures (forall i:int::{int_bit(ror(x, y), i)} 0 <= i && i < 32 ==> int_bit(ror(x, y), i) == int_bit(x, (i + y) mod 32)); //- null value(s) const NULL:int := 0; function{:expand false} TVM(a:int, b:int):bool { true } function Mult(a:int, b:int):int; function implementation{TVM(a, b)} Mult(a:int, b:int):int { a * b } function{:expand false} TVD(a:int, b:int):bool { true } function Div(a:int, b:int):int; function implementation{TVD(a, b)} Div(a:int, b:int):int { a div b } function{:expand false} TVM3(a:int, b1:int, b2:int):bool { true } //-//////////////////////////////////////////////////////////////////////////// //- PROCEDURES //-//////////////////////////////////////////////////////////////////////////// //- Where must the called procedure return to? //- (called procedure must return to RET:ReturnTo that was implicitly passed into the procedure) type ReturnTo; //- Return to return address $eip via "ret" instruction #ifdef x64 function ReturnToAddr64($eip_low:int, $eip_high:int) returns(ReturnTo); #else function ReturnToAddr32($eip:int) returns(ReturnTo); #endif //- Return to stack (eip, cs, eflags, ...) at $esp function ReturnToInterrupted($eip:int, $cs:int, $efl:int) returns(ReturnTo); //-//////////////////////////////////////////////////////////////////////////// //- INITIALIZATION //-//////////////////////////////////////////////////////////////////////////// // REVIEW: if we had a better way to initialize this to false, we could move it out of the spec var init:bool; //-//////////////////////////////////////////////////////////////////////////// //- LINEARITY //-//////////////////////////////////////////////////////////////////////////// // TODO: when we start using linear maps, we probably won't need this: atomic ghost procedure new_linear_int() returns(linear i:int); } ================================================ FILE: ironclad-apps/src/Trusted/Spec/BaseSpec.imp.basm ================================================ //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module implementation BaseSpec { implementation reveal_WORD_HI() {} implementation reveal_wrap32(val:int) {} implementation reveal_int_bit(n:int, index:int) {} implementation axiom_neg(x:int) {} implementation axiom_and(x:int, y:int) {} implementation axiom_or (x:int, y:int) {} implementation axiom_xor(x:int, y:int) {} implementation axiom_shl(x:int, y:int) {} implementation axiom_shr(x:int, y:int) {} implementation axiom_rol(x:int, y:int) {} implementation axiom_ror(x:int, y:int) {} implementation new_linear_int() returns(i:int) {} } ================================================ FILE: ironclad-apps/src/Trusted/Spec/Base_axioms.bpl ================================================ //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- //-//////////////////////////////////////////////////////////////////////////// //- WORDS //-//////////////////////////////////////////////////////////////////////////// axiom WORD_HI >= 100; // REVIEW: should we go ahead and set WORD_HI to exactly 2^32? // REVIEW: one would hope that this axiom is derivable from // Mult(a, b) == a * b, using b = b1 + b2, but Z3 couldn't seem to do it yet: axiom (forall a:int, b1:int, b2:int::{TVM3(a, b1, b2)} Mult(a, b1 + b2) == a * (b1 + b2)); ================================================ FILE: ironclad-apps/src/Trusted/Spec/BenchmarkApp/AppRequirements.ifc.stitch ================================================ //-private-import dafny_assembly_s; //-private-import dafny_be_sequences_s; //-private-import dafny_bytes_and_words_s; //-private-import dafny_Digest_s; //-private-import dafny_GCD_s; //-private-import dafny_hmac_common_s; //-private-import dafny_integer_sequences_s; //-private-import dafny_io_mem_s; //-private-import dafny_KeyGen_s; //-private-import dafny_MillerRabin_s; //-private-import dafny_power_s; //-private-import dafny_RandomNumberGen_s; //-private-import dafny_RandomTracing_s; //-private-import dafny_rfc4251_s; //-private-import dafny_round_s; //-private-import dafny_RSASpec_s; //-private-import dafny_seq_blocking_s; //-private-import dafny_sha_common_s; //-private-import dafny_sha1_s; //-private-import dafny_sha256_s; //-private-import dafny_tpm_device_s; requires fun_TPM__valid($ghost_TPM); requires fun_TPM__satisfies__integrity__policy($ghost_TPM); requires $ghost_IoMemPerm is Null; modifies $ghost_TPM; ================================================ FILE: ironclad-apps/src/Trusted/Spec/BenchmarkService/AppRequirements.ifc.stitch ================================================ //-private-import dafny_assembly_s; //-private-import dafny_be_sequences_s; //-private-import dafny_bytes_and_words_s; //-private-import dafny_Digest_s; //-private-import dafny_GCD_s; //-private-import dafny_hmac_common_s; //-private-import dafny_integer_sequences_s; //-private-import dafny_io_mem_s; //-private-import dafny_KeyGen_s; //-private-import dafny_MillerRabin_s; //-private-import dafny_power_s; //-private-import dafny_RandomNumberGen_s; //-private-import dafny_RandomTracing_s; //-private-import dafny_seq_blocking_s; //-private-import dafny_sha_common_s; //-private-import dafny_sha1_s; //-private-import dafny_sha256_s; //-private-import dafny_tpm_device_s; //-private-import dafny_round_s; requires fun_TPM__valid($ghost_TPM); requires fun_TPM__satisfies__integrity__policy($ghost_TPM); requires $ghost_IoMemPerm is Null; modifies $ghost_TPM; ================================================ FILE: ironclad-apps/src/Trusted/Spec/BitVector_axioms.bpl ================================================ //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- //module BitVectorSpec //{ //- Bit vector definitions, exposing native bit-vector support function {:bvbuiltin "bvadd"} $add(x:bv32, y:bv32) returns(bv32); function {:bvbuiltin "bvsub"} $sub(x:bv32, y:bv32) returns(bv32); function {:bvbuiltin "bvmul"} $mul(x:bv32, y:bv32) returns(bv32); function {:bvbuiltin "bvudiv"} $div(x:bv32, y:bv32) returns(bv32); function {:bvbuiltin "bvurem"} $mod(x:bv32, y:bv32) returns(bv32); function {:bvbuiltin "bvand"} $and(x:bv32, y:bv32) returns(bv32); function {:bvbuiltin "bvor"} $or (x:bv32, y:bv32) returns(bv32); function {:bvbuiltin "bvxor"} $xor(x:bv32, y:bv32) returns(bv32); function {:bvbuiltin "bvlshr"} $shr(x:bv32, y:bv32) returns(bv32); function {:bvbuiltin "bvshl"} $shl(x:bv32, y:bv32) returns(bv32); function {:bvbuiltin "bvnot"} $neg(x:bv32) returns(bv32); function {:bvbuiltin "bvule"} $le (x:bv32, y:bv32) returns(bool); function {:bvbuiltin "bvult"} $lt (x:bv32, y:bv32) returns(bool); function {:bvbuiltin "bvuge"} $ge (x:bv32, y:bv32) returns(bool); function {:bvbuiltin "bvugt"} $gt (x:bv32, y:bv32) returns(bool); function{:expand false} TBV(b:bv32) returns(bool) { true } //- meaning undefined if !word(i) function B(i:int) returns(bv32); function I(b:bv32) returns(int); //} ================================================ FILE: ironclad-apps/src/Trusted/Spec/DafnyCCTest/AppRequirements.ifc.stitch ================================================ ================================================ FILE: ironclad-apps/src/Trusted/Spec/DiffPriv/AppRequirements.ifc.stitch ================================================ //-private-import dafny_assembly_s; //-private-import dafny_be_sequences_s; //-private-import dafny_bytes_and_words_s; //-private-import dafny_Digest_s; //-private-import dafny_GCD_s; //-private-import dafny_hmac_common_s; //-private-import dafny_integer_sequences_s; //-private-import dafny_io_mem_s; //-private-import dafny_KeyGen_s; //-private-import dafny_MillerRabin_s; //-private-import dafny_power_s; //-private-import dafny_RandomNumberGen_s; //-private-import dafny_RandomTracing_s; //-private-import dafny_rfc4251_s; //-private-import dafny_round_s; //-private-import dafny_RSASpec_s; //-private-import dafny_seq_blocking_s; //-private-import dafny_sha_common_s; //-private-import dafny_sha1_s; //-private-import dafny_sha256_s; //-private-import dafny_tpm_device_s; //-private-import dafny_CommonState_s; //-private-import dafny_DiffPriv_s; //-private-import dafny_StateMachine_s; //-private-import dafny_Database_s; //-private-import dafny_Mapper_s; //-private-import dafny_Math_s; //-private-import dafny_Noise_s; //-private-import dafny_SumReducer_s; requires fun_TPM__valid($ghost_TPM); requires fun_TPM__satisfies__integrity__policy($ghost_TPM); requires $ghost_IoMemPerm is Null; requires TPM#CommonStateMachine_ctor($ghost_current_common_state) == $ghost_TPM; requires !initialized#CommonStateMachine_ctor($ghost_current_common_state); requires !initialized#DiffPrivStateMachine_ctor($ghost_current_diffpriv_state); modifies $ghost_TPM; modifies $ghost_current_common_state; modifies $ghost_current_diffpriv_state; ================================================ FILE: ironclad-apps/src/Trusted/Spec/Entry.ifc.basm.stitch ================================================ #line 1 Entry.ifc.basm.stitch // // Copyright (c) Microsoft Corporation. All rights reserved. // //readonly var $ghost_sample_index:int; ////////////////////////////////////////////////////////////////////////////// // // This procedure is the entry point from the boot loader/SKINIT // ////////////////////////////////////////////////////////////////////////////// // // After an SKINIT (see Section 15.27 in AMD's Volume 2: System Programming): // - eax points to the beginning of the SL // - At the beginning of the code, there is a 16-bit pointer to our entry point, // followed by a 16-bit length field that indicates the end of our code and static data // - esp points at eax + 64K // - CS and SS are set to full, flat mappings #ifdef AppLoader procedure LoaderEntryPoint( my r:regs, my core_state:core_state, linear initState:InitStateMachine, linear mem:mem, linear io:IOState, linear dev_states:DEV_StateMachines, $sl_len:int, $cpu_info:int); requires initState is EntryPoint; requires ?CodeBase == r.regs[EAX]; requires Aligned(?CodeBase) && ?CodeBase mod 0x10000 == 0; // SLB must be 64K aligned // Spec says $sl_len <= 65535 = 64K-1, but we have a more stringent requirement // Assembler must guarantee the SL is only 35K, to allow 8K for stack and heap use requires ?memLo == ?CodeBase + 58*1024; // Usable memory between end of the SL and the end of the SLB requires (forall i:int::{memAddr(i)}{mem.dom[i]} ?memLo <= i && i < ?CodeBase + 0x10000 <==> mem.dom[i]); // Can only access the 64K of SKINIT-protected memory requires r.regs[ESP] == add(?CodeBase, 0x10000); requires ValidPrePagingState(core_state.cregs[CR0]); requires core_state.seg_regs[SS].descriptor.segBase == 0 && core_state.seg_regs[SS].descriptor.segType == ?SegmentDescriptorTypeData; requires ?memHi == 0x08000000; // Eventually, DEV permits 128 MB, but note mem.dom above is restricted to 64K initially requires (forall i:int::{memAddr(i)} ?memLo <= i && i < ?memHi ==> memAddr(i)); requires me == 0; // Must be run on the bootstrap processor requires !init; // Trusted code has not yet done anything to the PCI configuration requires (forall i:int::{PciConfigState#PciState(_pci#IOState(io))[i]} io._pci.PciConfigState[i] == 0); // TODO: fix triggering // Trusted code has not yet configured any of the DEVs beyond what SKINIT provides requires (forall i:int::{ dev_states.states[i] } dev_states.states[i] is Init); // Same number of IO events initially requires public(io._inCtr); requires public(io._outCtr); // Initialize ghost TPM state requires fun_TPM__valid($ghost_TPM); requires fun_TPM__satisfies__integrity__policy($ghost_TPM); requires $ghost_IoMemPerm is Null; requires fun_Seq__Equal___Seq___int(PCR_19#TPM_build($ghost_TPM), fun_Seq__Empty___Seq___int()); modifies init; modifies $commonVars, $gcVars, $Time; modifies $IdtMem, $IdtMemOk, $IdtOk; modifies $TimerSeq, $TimerFreq, $PicSeq; modifies ptMem; modifies $ghost_IoMemPerm; modifies $ghost_TPM; #endif ////////////////////////////////////////////////////////////////////////////// // // This procedure is the entry point for normal apps launched via AppLoader // WARNING: DO NOT ADD ANY REQUIREMENTS TO THIS PROCEDURE!!! // If you have general requirements, add them to AppLoaderContract.ifc.basm. // ////////////////////////////////////////////////////////////////////////////// #ifndef AppLoader procedure AppEntryPoint( my r:regs, my core_state:core_state, linear initState:InitStateMachine, linear mem:mem, linear code_mem:mem, linear io:IOState, app_entry:int, app_code_base:int, code_word_seq:Seq___int ); requires AppLoaderContractGeneric(me, init, r, core_state, initState, mem, code_mem, io, app_entry, app_code_base, code_word_seq); // Same number of IO events initially. Must be here instead of AppLoaderContract, since we can't use public in functions requires public(io._inCtr); requires public(io._outCtr); //- SENTINEL_APP_SPECIFIC_GOES_HERE modifies init; modifies $commonVars, $gcVars, $Time; modifies $IdtMem, $IdtMemOk, $IdtOk; modifies $TimerSeq, $TimerFreq, $PicSeq; modifies ptMem; modifies $ghost_IoMemPerm; ensures false; #endif // TODO add this interrupt handler here to allow reasoning about syscalls and preemption of user-mode code. /* procedure InterruptHandler(linear s:state, $_stackState:[int]StackState, $ebp:int, $esp:int, $eip:int) returns(linear statics:mem, linear io:IOState); requires word(eax) && word(ebx) && word(ecx) && word(edx) && word(esi) && word(edi) && word(ebp) && word(esp); requires isStack($S) && $StackState[$S] == StackRunning; requires SpRequire($S, esp, 12); requires $_stackState == $StackState [$S := StackInterrupted(eax, ebx, ecx, edx, esi, edi, ebp, esp + 12, $Mem[esp], $Mem[esp + 4], $Mem[esp + 8])] [?InterruptStack := StackRunning]; requires (StackStateTag($StackState[?InterruptStack]) == ?STACK_YIELDED ==> $RET == ReturnToAddr($eip) && $StackState[?InterruptStack] == StackYielded($ebp, $esp, $eip)); // modifies eax, ebx, ecx, edx, esi, edi, ebp, esp; modifies $commonVars, $gcVars, $Time, core, $part, mems, $sepVars; // modifies StackCheck; ensures StackCheckInv(?InterruptStack, StackCheck); ensures (StackStateTag($StackState[?InterruptStack]) == ?STACK_YIELDED ==> NucleusInv(?InterruptStack, $_stackState, $toAbs, $AbsMem, $commonVars, $gcVars, state, core, $part, mems, $sepVars, $StacksFrames, $IoMmuEnabled, $PciConfigState, $ioVars) && ebp == $ebp && esp == $esp); */ ================================================ FILE: ironclad-apps/src/Trusted/Spec/ExtendedAssembly.ifc.basm ================================================ //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module interface ExtendedAssembly { //-//////////////////////////////////////////////////////////////////////////// //- //- The AppLoader calls this instruction to jump into the real code //- //-//////////////////////////////////////////////////////////////////////////// #ifdef AppLoader atomic procedure instr_Launch( my r:regs, my core_state:core_state, linear initState:InitStateMachine, linear mem:mem, linear code_mem:mem, linear io:IOState, app_entry:int, app_code_base:int, code_word_seq:Seq___int ); requires AppLoaderContractGeneric(me, init, r, core_state, initState, mem, code_mem, io, app_entry, app_code_base, code_word_seq); //- Same number of IO events initially. Must be here instead of AppLoaderContract, since we can't use public in functions requires public(io._inCtr); requires public(io._outCtr); //- PCR19 must have been extended with SHA1([app_code_base, app_entry] + app_code_words) //- Other apps don't need to know this is what we put in PCR 19 requires (let hash_input:Seq___int := fun_BEWordSeqToBitSeq( fun_Seq__Append___int(fun_Seq__Build___int(fun_Seq__Build___int(fun_Seq__Empty___int(), app_code_base), app_entry), code_word_seq)) in //fun_Seq__Length___int(hash_input) < fun_power2(64) && (fun_IsBitSeq(hash_input))) && fun_Seq__Equal___Seq___int((PCR_19#TPM_build($ghost_TPM)), fun_Seq__Build___Seq___int(fun_Seq__Empty___Seq___int(), fun_BEWordSeqToByteSeq(fun_SHA1(hash_input))))); ensures false; #endif } ================================================ FILE: ironclad-apps/src/Trusted/Spec/ExtendedAssembly.imp.basm ================================================ //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module implementation ExtendedAssembly { } ================================================ FILE: ironclad-apps/src/Trusted/Spec/IntSpec.ifc.basm ================================================ //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module interface IntSpec { //- Bit vector definitions, hiding native bit-vector support function $add(x:bv32, y:bv32) returns(bv32); function $sub(x:bv32, y:bv32) returns(bv32); function $mul(x:bv32, y:bv32) returns(bv32); function $div(x:bv32, y:bv32) returns(bv32); function $mod(x:bv32, y:bv32) returns(bv32); function $and(x:bv32, y:bv32) returns(bv32); function $or (x:bv32, y:bv32) returns(bv32); function $xor(x:bv32, y:bv32) returns(bv32); function $shr(x:bv32, y:bv32) returns(bv32); function $shl(x:bv32, y:bv32) returns(bv32); function $neg(x:bv32) returns(bv32); function $le (x:bv32, y:bv32) returns(bool); function $lt (x:bv32, y:bv32) returns(bool); function $ge (x:bv32, y:bv32) returns(bool); function $gt (x:bv32, y:bv32) returns(bool); function{:expand false} TBV(b:bv32) returns(bool) { true } //- meaning undefined if !word(i) function B(i:int) returns(bv32); function I(b:bv32) returns(int); } ================================================ FILE: ironclad-apps/src/Trusted/Spec/IntSpec.imp.basm ================================================ //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module implementation IntSpec {} ================================================ FILE: ironclad-apps/src/Trusted/Spec/IntSpec_axioms.bpl ================================================ //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- //- Axioms about bit vectors axiom I(1bv32) == 1; axiom (forall i1:int, i2:int::{B(i1),B(i2)} word(i1) && word(i2) ==> (i1 == i2 <==> B(i1) == B(i2))); axiom (forall b1:bv32, b2:bv32::{I(b1),I(b2)} b1 == b2 <==> I(b1) == I(b2)); axiom (forall b:bv32::{I(b)} word(I(b))); axiom (forall b:bv32::{B(I(b))} B(I(b)) == b); axiom (forall i:int::{I(B(i))} word(i) ==> I(B(i)) == i); axiom (forall i1:int, i2:int::{add(i1, i2)} word(i1) && word(i2) && word(add(i1, i2)) ==> add(i1, i2) == I($add(B(i1), B(i2)))); axiom (forall i1:int, i2:int::{sub(i1, i2)} word(i1) && word(i2) && word(sub(i1, i2)) ==> sub(i1, i2) == I($sub(B(i1), B(i2)))); axiom (forall i1:int, i2:int::{mul(i1, i2)} word(i1) && word(i2) && word(mul(i1, i2)) ==> mul(i1, i2) == I($mul(B(i1), B(i2)))); axiom (forall i1:int, i2:int::{_div(i1, i2)} word(i1) && word(i2) && word(_div(i1, i2)) ==> _div(i1, i2) == I($div(B(i1), B(i2)))); axiom (forall i1:int, i2:int::{_mod(i1, i2)} word(i1) && word(i2) && word(_mod(i1, i2)) ==> _mod(i1, i2) == I($mod(B(i1), B(i2)))); axiom (forall i1:int, i2:int::{le(i1, i2)} word(i1) && word(i2) ==> le(i1, i2) == $le(B(i1), B(i2)) ); axiom (forall i1:int, i2:int::{lt(i1, i2)} word(i1) && word(i2) ==> lt(i1, i2) == $lt(B(i1), B(i2)) ); axiom (forall i1:int, i2:int::{ge(i1, i2)} word(i1) && word(i2) ==> ge(i1, i2) == $ge(B(i1), B(i2)) ); axiom (forall i1:int, i2:int::{gt(i1, i2)} word(i1) && word(i2) ==> gt(i1, i2) == $gt(B(i1), B(i2)) ); axiom (forall i1:int, i2:int::{and(i1, i2)} and(i1, i2) == I($and(B(i1), B(i2))) ); axiom (forall i1:int, i2:int::{or(i1, i2)} or (i1, i2) == I($or (B(i1), B(i2))) ); axiom (forall i1:int, i2:int::{xor(i1, i2)} xor(i1, i2) == I($xor(B(i1), B(i2))) ); axiom (forall i1:int, i2:int::{shl(i1, i2)} shl(i1, i2) == I($shl(B(i1), B(i2))) ); axiom (forall i1:int, i2:int::{shr(i1, i2)} shr(i1, i2) == I($shr(B(i1), B(i2))) ); axiom (forall i:int::{neg(i)} neg(i) == I($neg(B(i)))); axiom (forall i:int::{Aligned(i)} word(i) ==> Aligned(i) == ($and(B(i), 3bv32) == 0bv32)); ================================================ FILE: ironclad-apps/src/Trusted/Spec/InterruptsSpec.ifc.basm ================================================ //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module interface InterruptsSpec { const ?FatalHandler:int; //- Handler for fatal machine exceptions (must halt machine) const ?ErrorHandler:int; //- Handler for expected traps/faults (with error codes) const ?FaultHandler:int; //- Handler for expected traps/faults (without error codes) const ?InterruptHandler:int; //- Handler for interrupts //- Interrupt table layout: //- 0: divide error --> FaultHandler //- 4: overflow --> FaultHandler //- 13: general protection --> ErrorHandler //- 14: page fault --> ErrorHandler //- 1-3, 5-12, 15-31 --> FatalHandler //- 32-255 --> InterruptHandler //- Table contains 256 entries. //- Each entry is an 8 byte "interrupt gate" (which guarantees that exceptions are disabled upon entry): //- 0: bits 31..16 = handler[31..16] //- bits 15...0 = 0x8e00 (P=1, DPL=0, D=1) //- 4: bits 31..16 = codeSegmentSelector //- bits 15...0 = handler[15...0] const ?NIdt:int := 256; function IsHandlerForEntry($entry:int, $handler:int) returns(bool) { $handler == ?FatalHandler //- ($handler == ?FaultHandler && ($entry == 0 || between(3, 5, $entry))) //- || ($handler == ?ErrorHandler && ($entry == 13 || $entry == 14)) //- || ($handler == ?FatalHandler && (between(1, 3, $entry) || between(5, 13, $entry) || between(15, 32, $entry))) //- || ($handler == ?InterruptHandler && between(32, ?NIdt, $entry)) } // REVIEW: don't hard-code the segment selector here... const ?CodeSegmentSelector:int := 0x20; // (set by boot loader) const ?Mask16Hi:int := 0xffff0000; const ?Mask16Lo:int := 0x0000ffff; const ?IdtWord4Lo:int := 0x8e00; function IdtWord0(handler:int) returns(int) { or(shl(?CodeSegmentSelector, 16), and(handler, ?Mask16Lo)) } function IdtWord4(handler:int) returns(int) { or(and(handler, ?Mask16Hi), ?IdtWord4Lo) } //- Verification should ensure that: //- - no instruction in the Nucleus can cause a fault. //- - interrupts are always disabled in the Nucleus. //- However, it's conceivable that we could get an NMI on some hardware. //- Therefore, it seems safest to verify that the interrupt table is //- always valid, even when running Nucleus code. //- To ensure this, we reserve special memory for the interrupt table, //- and verify that only valid entries are stored there. readonly var $IdtMem:[int]int; readonly var $IdtMemOk:[int]bool; const ?idtLo:int; const ?idtHi:int := ?idtLo + ?NIdt * 8; //// Write a word to the interrupt table //atomic procedure instr_IdtStore(linear s:state, entry:int, offset:int, handler:int, ptr:opn_mem, val:opn) // returns(linear _s:state); // requires 0 <= entry && entry < ?NIdt; // requires (offset == 0 && Eval(r, val) == IdtWord0(handler)) || (offset == 4 && Eval(r, val) == IdtWord4(handler)); // requires IsHandlerForEntry(entry, handler); // requires ptr is OMem; // requires EvalPtr(r, ptr) == ?idtLo + 8 * entry + offset; // modifies $IdtMem, $IdtMemOk; // ensures $IdtMem == old($IdtMem)[EvalPtr(r, ptr) := Eval(r, val)]; // ensures $IdtMemOk == old($IdtMemOk)[EvalPtr(r, ptr) := true]; // ensures _s == InsUpdate0(me, s, s._cores[me]._efl); function IdtMemOk($IdtMemOk:[int]bool) returns(bool) { (forall i:int::{TV(i)} TV(i) ==> 0 <= i && i < ?NIdt ==> $IdtMemOk[?idtLo + 8 * i] && $IdtMemOk[?idtLo + 8 * i + 4]) } readonly var $IdtOk:bool; //// LIDT instruction. Loads IDT register from memory. //// $ptr + 0: 0...15: limit (size in bytes - 1) //// 16..31: addr[0...15] //// $ptr + 4: 0...15: addr[16..31] //// TODO: break into micro-instructions //atomic procedure instr_Lidt(linear s:state, ptr:opn_mem) returns(linear _s:state); // requires memAddr(EvalPtr(r, ptr)) && memAddr(EvalPtr(r, ptr) + 4); // requires Aligned(EvalPtr(r, ptr)); // requires s._mem[EvalPtr(r, ptr)] == or(shl(?idtLo, 16), ?idtHi - ?idtLo - 1); // requires s._mem[EvalPtr(r, ptr) + 4] == shr(?idtLo, 16); // requires IdtMemOk($IdtMemOk); // modifies $IdtOk; // ensures $IdtOk; // ensures _s == InsUpdate0(me, s, s._cores[me]._efl); //- Legacy programmable interrupt controller //- (VirtualPC doesn't have much APIC support yet, so use legacy PIC) //- command sequence: //- control word, interrupt vector spec, master/secondary spec, mode spec, eoi, eoi, eoi, eoi, ... //- (eoi = end of interrupt) readonly var $PicSeq:[int]int; // which steps in the command sequence have we completed? function PicOk($PicSeq:[int]int) returns(bool) { $PicSeq[0] >= 5 && $PicSeq[1] >= 5 } //atomic procedure instr_PicOut8(linear s:state, pic:int, offset:int, seq:int) returns(linear _s:state); // requires (pic == 0 && s._cores[me]._regs[EDX] == 32 + offset) || (pic == 1 && s._cores[me]._regs[EDX] == 160 + offset); // requires offset == 0 || offset == 1; // requires (seq == 0 || seq == $PicSeq[pic] + 1); // requires // // edge triggered, cascaded PICs, send 4 command words: // (seq == 0 && offset == 0 && s._cores[me]._regs[EAX] == 17) // // use interrupt vectors 112..119 and 120..127: // || (seq == 1 && offset == 1 && pic == 0 && s._cores[me]._regs[EAX] == 112) // || (seq == 1 && offset == 1 && pic == 1 && s._cores[me]._regs[EAX] == 120) // // 4 ==> connect slave to IRQ2, 2 ==> slave ID 2: // || (seq == 2 && offset == 1 && pic == 0 && s._cores[me]._regs[EAX] == 4) // || (seq == 2 && offset == 1 && pic == 1 && s._cores[me]._regs[EAX] == 2) // // Non-buffered, normal EOI, x86 mode: // || (seq == 3 && offset == 1 && s._cores[me]._regs[EAX] == 1) // // for now, only allow timer interrupts (vector 0 on pic 0): // || (seq == 4 && offset == 1 && pic == 0 && s._cores[me]._regs[EAX] == 254) // || (seq == 4 && offset == 1 && pic == 1 && s._cores[me]._regs[EAX] == 255) // // send eoi: // || (seq >= 5 && offset == 0 && s._cores[me]._regs[EAX] == 32) // ; // modifies $PicSeq; // ensures $PicSeq == old($PicSeq)[pic := seq]; // ensures _s == InsUpdate0(me, s, s._cores[me]._efl); //- Legacy programmer interval timer //- (using timer0 only) readonly var $TimerSeq:int; //- which step in the initialization have we completed? readonly var $TimerFreq:int; function TimerOk($TimerSeq:int) returns(bool) { $TimerSeq == 2 } //atomic procedure instr_PitModeOut8(linear s:state, freq:int) returns(linear _s:state); // requires s._cores[me]._regs[EAX] == 48; // one-shot 16-bit mode // modifies $TimerSeq, $TimerFreq; // ensures $TimerSeq == 0; // ensures $TimerFreq == freq; // ensures _s == InsUpdate0(me, s, s._cores[me]._efl); // //atomic procedure instr_PitFreqOut8(linear s:state) returns(linear _s:state); // requires 0 <= $TimerSeq && $TimerSeq < 2; // requires $TimerSeq == 0 ==> s._cores[me]._regs[EAX] == $TimerFreq; // al == bits 0-7 of $freq // requires $TimerSeq == 1 ==> s._cores[me]._regs[EAX] == shr($TimerFreq, 8); // al == bits 8-15 of $freq // modifies $TimerSeq; // ensures $TimerSeq == old($TimerSeq) + 1; // ensures _s == InsUpdate0(me, s, s._cores[me]._efl); } ================================================ FILE: ironclad-apps/src/Trusted/Spec/InterruptsSpec.imp.basm ================================================ //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module implementation InterruptsSpec {} ================================================ FILE: ironclad-apps/src/Trusted/Spec/IoSpec.ifc.basm ================================================ //- //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module interface IoSpec { //- We model input and output as unbounded streams of input events or output events. function VgaTextStore($ptr:int, $val:int) returns(VgaEvent); const ?VgaTextLo:int := 0xb8000; const ?VgaTextHi:int := 0xb9f40; function vgaAddr2(i:int) returns (bool) {?VgaTextLo <= i && i <= ?VgaTextHi - 2} atomic procedure instr_VgaTextStore16(const my r:regs, linear io:IOState, ptr:opn_mem, val:opn) returns(linear _io:IOState); requires SrcOk(val); requires vgaAddr2(EvalPtr(r, ptr)); requires public(ptr); requires public(val); requires public(io._inCtr); requires public(io._outCtr); ensures _io == OutUpdate(VgaUpdate(io, VgaState( io._vga.VgaEvents[io._vga.VgaNextEvent := VgaTextStore(EvalPtr(r, ptr), Eval(r, val))], io._vga.VgaNextEvent + 1 ))); //- For diagnostics, allow arbitrary writes to the first line of the screen. //- (If no diagnostics are needed, this can be disabled.) // TODO: Disable for Oakland! atomic procedure instr_VgaDebugStore16(const my r:regs, ptr:opn_mem, val:opn); requires SrcOk(val); requires vgaAddr2(EvalPtr(r, ptr)); requires ?VgaTextLo <= EvalPtr(r, ptr) && EvalPtr(r, ptr) <= ?VgaTextLo + 158; atomic procedure instr_KeyboardStatusIn8(my r:regs, linear io:IOState) returns(my _r:regs, linear _io:IOState); requires public(io._inCtr); requires public(io._outCtr); ensures (exists eax_val:int, available:int:: _r.regs == r.regs[EAX := eax_val] && _r.efl == r.efl && _io == InOutUpdate( KeyboardUpdate(io, KeyboardState( io._keyboard.KeyboardEvents, available, io._keyboard.KeyboardDone))) && (and(eax_val, 1) == 0 ==> available == io._keyboard.KeyboardDone) && (and(eax_val, 1) != 0 ==> available > io._keyboard.KeyboardDone)); ensures public(_r.regs[EAX]); atomic procedure instr_KeyboardDataIn8(my r:regs, linear io:IOState) returns(my _r:regs, linear _io:IOState); requires io._keyboard.KeyboardAvailable > io._keyboard.KeyboardDone; requires public(io._inCtr); requires public(io._outCtr); ensures (exists eax_val:int:: _r.regs == r.regs[EAX := eax_val] && _r.efl == r.efl && _io == InOutUpdate( KeyboardUpdate(io, KeyboardState( io._keyboard.KeyboardEvents, io._keyboard.KeyboardAvailable, io._keyboard.KeyboardDone+1))) && and(eax_val, 255) == io._keyboard.KeyboardEvents[io._keyboard.KeyboardDone]); ensures public(_r.regs[EAX]); //function ValidBaudRateLSB(a:int):bool //{ // a == 0x01 || a == 0x03 || a == 0x06 || a == 0x0c || a == 0x10 || a == 0x18 || a == 0x20 || a == 0x3a || a == 0x40 || a == 0x60 || a == 0xc0 // || a == 0x80 || a == 0x00 || a == 0x17 //} // //function ValidBaudRateMSB(a:int):bool //{ // a == 0x00 || a == 0x01 || a == 0x03 || a == 0x04 || a == 0x09 //} // //// line status register //function IsLSR(d:int):bool //{ // d == 0x3fd //} // //// transmit/receive buffer //function IsTRB(d:int):bool //{ // d == 0x3f8 //} // //function ValidSerialConfig(regs:[int]int, mode:SerialPortMode):bool //{ // (regs[EDX] == 0x3f8 ==> (mode.DLAB == true && ValidBaudRateLSB(regs[EAX]))) // || (regs[EDX] == 0x3f9 ==> (mode.DLAB == true ==> ValidBaudRateMSB(regs[EAX]))) // || regs[EDX] == 0x3fa // || regs[EDX] == 0x3fb // || regs[EDX] == 0x3fc //} //- Interface for serial port output; used for debugging underspecified code, //- e.g., the network driver // TODO: Disable serial for Oakland submission function serialPortConfigged():bool; //- For more info, see http://www.lammertbies.nl/comm/info/RS-232_io.html atomic procedure instr_SerialDbgConfigOut(const my r:regs); requires 0x3f8 <= r.regs[EDX] && r.regs[EDX] <= 0x3ff; //- Must be in I/O range for COM1 ensures serialPortConfigged(); atomic procedure instr_SerialDbgStatusOut8(my r:regs) returns(my _r:regs); requires r.regs[EDX] == 0x3fd; //- LSR = line status register ensures (exists eax_val:int :: _r.regs == r.regs[EAX := eax_val]); atomic procedure instr_SerialDbgDataOut8(const my r:regs); requires r.regs[EDX] == 0x3f8; //[ckh] How is p related to $serialState? //atomic procedure instr_SerialDbgConfig(const my r:regs, p:SerialPortState); // requires ValidSerialConfig(r.regs, p.Mode); // modifies $serialState; // ensures (exists mode:bool:: // $serialState == SerialPortState(SerialPortMode(mode), p.In, p.Out) // && (r.regs[EAX] == 0x80 && r.regs[EDX] == 0x3fb ==> mode == true) // && (r.regs[EAX] != 0x80 && r.regs[EDX] == 0x3fb ==> mode == false) // && (r.regs[EDX] != 0x3fb ==> mode == p.Mode.DLAB)); // //atomic procedure instr_SerialDbgDataOut8(const my r:regs, p:SerialPortState); // requires IsTRB(r.regs[EDX]) && p.Mode.DLAB == false; // requires p.Out.Available > p.Out.Done; // modifies $serialState; // ensures $serialState == SerialPortState(p.Mode, p.In, SerialPortQueue(p.Out.Events, p.Out.Available, p.Out.Done+1)); // ensures and(r.regs[EAX], 255) == $serialState.Out.Events[$serialState.Out.Done]; // //atomic procedure instr_SerialDbgStatusOut8(my r:regs, p:SerialPortState) returns(my _r:regs); // requires IsLSR(r.regs[EDX]); // modifies $serialState; // ensures (exists eax_val:int, available:int:: // _r.regs == r.regs[EAX := eax_val] // && $serialState == SerialPortState(p.Mode, p.In, SerialPortQueue(p.Out.Events, available, p.Out.Done)) // && (and(eax_val, 0x20) == 0 ==> available == p.Out.Done) // && (and(eax_val, 0x20) != 0 ==> available > p.Out.Done)); // //atomic procedure instr_SerialDbgDataIn8(my r:regs, p:SerialPortState) returns(my _r:regs); // requires IsTRB(r.regs[EDX]) && p.Mode.DLAB == false; // requires p.In.Available > p.In.Done; // modifies $serialState; // ensures (exists eax_val:int:: // _r.regs == r.regs[EAX := eax_val] // && $serialState == SerialPortState(p.Mode, SerialPortQueue(p.In.Events, p.In.Available, p.In.Done+1), p.Out) // && (and(eax_val, 255) == $serialState.In.Events[$serialState.In.Done])); // //atomic procedure instr_SerialDbgStatusIn8(my r:regs, p:SerialPortState) returns(my _r:regs); // requires IsLSR(r.regs[EDX]); // modifies $serialState; // ensures (exists eax_val:int, available:int:: // _r.regs == r.regs[EAX := eax_val] // && $serialState == SerialPortState(p.Mode, SerialPortQueue(p.In.Events, available, p.In.Done), p.Out) // && (and(eax_val, 0x1) == 0 ==> available == p.In.Done) // && (and(eax_val, 0x1) != 0 ==> available > p.In.Done)); //function SampleCall (source:[int]int, indexOld:int, index:int, retval:int ) : bool //{ // (retval == source[indexOld]) // && (index == indexOld+1) //} // //function OneOneMap (M:[int]int) : bool //{ // (forall x:int, y:int :: word(x) && word(y) ==> M[x] == M[y] ==> x == y) //} //// This instruction should be connected to Intel Rdrand instruction in Ivy Bridge processors //atomic procedure instr_SampleIn32(linear s:state, M:[int]int) returns(linear _s:state); // requires OneOneMap(M); // modifies $global_sample_index; // ensures (exists eax:int :: // _s == InsUpdate1(me, s, OReg(EAX), eax, s._cores[me]._efl) // && SampleCall ($randomSource, old($global_sample_index), $global_sample_index, eax)); //// ACPI tables //const ?RsdpPtr:int; //const ?RsdpExists:bool; //const ?RsdtPtr:int; //const ?RsdtCount:int; //const ?DmarPtr:int; //const ?DmarExists:bool; //const ?DmarLen:int; //const ?DrhdPtr:[int]int; //const ?DrhdCount:int; //const ?DrhdRegs:[int]int; // //const ?RoBiosLo:int := 0xE0000; //const ?RoBiosHi:int := 0x100000; //function inBiosRo(i:int) returns(bool) { ?RoBiosLo <= i && i < ?RoBiosHi } // //function ByteSum(ptr:int, end:int) returns(int); // //function MatchesRsdp(ptr:int) returns(bool) //{ // ro32(ptr + 0) == 0x20445352 // "RSD " // && ro32(ptr + 4) == 0x20525450 // "PTR " // && and(ByteSum(ptr, ptr + 20), 255) == 0 //} // //function MatchesDmar(ptr:int) returns(bool) //{ // ro32(ptr + 0) == 0x52414d44 // "DMAR" //} // //function MatchesDrhd(ptr:int) returns(bool) //{ // roU16(ptr) == 0 //} // //function MaybeDrhd(ptr:int, entry:int) returns(bool) //{ // ?DrhdPtr[entry] == ptr // && inRo(ptr + 0, 2) // && inRo(ptr + 2, 2) // && ptr + roU16(ptr + 2) <= ?DmarPtr + ?DmarLen //} // //function DrhdInv(ptr:int, entry:int) returns(bool) //{ // inRo(ptr + 8, 4) // && inRo(ptr + 12, 4) // && (ro32(ptr + 12) == 0 ==> ?DrhdRegs[entry] == ro32(?DrhdPtr[entry] + 8)) //} // //atomic ghost procedure rsdpExists($ptr:int, $entry:int); // requires $ptr == ?RoBiosLo + 16 * $entry; // requires inBiosRo($ptr); // requires MatchesRsdp($ptr); // requires (forall j:int::{TV(j)} TV(j) && j < $entry && inBiosRo(?RoBiosLo + 16 * j) // ==> !MatchesRsdp(?RoBiosLo + 16 * j)); // ensures ?RsdpExists; // ensures ?RsdpPtr == $ptr; // //atomic ghost procedure dmarExists($ptr:int, $entry:int); // requires $ptr == ro32(?RsdtPtr + 36 + 4 * $entry); // requires ?RsdpExists; // requires 0 <= $entry && $entry < ?RsdtCount; // requires MatchesDmar($ptr); // requires (forall j:int::{TV(j)} TV(j) && 0 <= j && j < ?RsdtCount && $entry != j // ==> !MatchesDmar(ro32(?RsdtPtr + 36 + 4 * j))); // ensures ?DmarExists; // ensures ?DmarPtr == $ptr; // //atomic ghost procedure drhdExists($ptr:int, $entry:int); // requires MaybeDrhd($ptr, $entry); // requires $ptr < ?DmarPtr + ?DmarLen; // requires MatchesDrhd($ptr); // ensures ?DrhdPtr[$entry] == $ptr; // ensures MaybeDrhd($ptr + roU16($ptr + 2), $entry + 1); // ensures DrhdInv($ptr, $entry); // //atomic ghost procedure drhdEnd($ptr:int, $entry:int); // requires MaybeDrhd($ptr, $entry); // requires $ptr == ?DmarPtr + ?DmarLen || !MatchesDrhd($ptr); // ensures ?DrhdCount == $entry; // //// IOMMU, DMA // //// Note: iom and dma must be contiguous (?iomHi == ?dmaLo), //// because iom contains the byte[] header for the dma region //const ?iomLo:int; //const ?iomHi:int := ?iomLo + 65536; //const ?dmaLo:int; //const ?dmaHi:int := ?dmaLo + 18 * 1024 * 1024; // //function iomAddr(i:int) returns (bool) {?iomLo <= i && i < ?iomHi} //// TODO: Disable Iom* instructions for Oakland //atomic procedure instr_IomStore(linear s:state, ptr:opn_mem, val:opn) returns(linear _s:state); // requires iomAddr(EvalPtr(r, ptr)); // requires Aligned(EvalPtr(r, ptr)); // requires word(Eval(r, val)); // requires !s._io._iom.IomFrozen; // ensures _s == IomUpdate(s, // IomState( // s._io._iom.IomMem[EvalPtr(r, ptr) := Eval(r, val)], // s._io._iom.IomFrozen, // s._io._iom.IoMmuState, // s._io._iom.IoMmuEnabled, // s._io._iom.DevEnabled // )); // //atomic procedure instr_IomRegLoad(entry:int, val:int, ptr:opn_mem); // requires EvalPtr(r, ptr) == ?DrhdRegs[entry] + 28 // || EvalPtr(r, ptr) == ?DrhdRegs[entry] + 0 // || EvalPtr(r, ptr) == ?DrhdRegs[entry] + 8 // || EvalPtr(r, ptr) == ?DrhdRegs[entry] + 12; // modifies regs; // ensures word(Eval(r, val)); // ensures (exists v:int :: regs == r.regs[val := v]); // //// TODO: invalidate context-cache and IOTLB? //atomic procedure instr_IomRegStore(linear s:state, entry:int, ptr:opn_mem, val:opn) returns(linear _s:state); // requires (s._io._iom.IoMmuState[entry] == 0 && EvalPtr(r, ptr) == ?DrhdRegs[entry] + 32 && IoRootTable(s._io._iom.IomMem, Eval(r, val))) // || (s._io._iom.IoMmuState[entry] == 1 && EvalPtr(r, ptr) == ?DrhdRegs[entry] + 36 && Eval(r, val) == 0) // || (s._io._iom.IoMmuState[entry] == 2 && EvalPtr(r, ptr) == ?DrhdRegs[entry] + 24 && Eval(r, val) == shl(1, 30)) // || (s._io._iom.IoMmuState[entry] == 3 && EvalPtr(r, ptr) == ?DrhdRegs[entry] + 24 && Eval(r, val) == shl(1, 31)); // ensures _s == IomUpdate(s, // IomState( // s._io._iom.IomMem, // true, // s._io._iom.IoMmuState[entry := 1 + s._io._iom.IoMmuState[entry]], // s._io._iom.IoMmuEnabled, // s._io._iom.DevEnabled // )); // //atomic procedure instr_ghost_IomEnabled(linear s:state) returns (linear _s:state); // requires (forall i:int::{s._io._iom.IoMmuState[i]} 0 <= i && i < ?DrhdCount ==> s._io._iom.IoMmuState[i] == 4); // requires false; // $IomMem[?dmaLo - 8] == ?BYTE_VECTOR_VTABLE; // byte[].VTable // requires s._io._iom.IomMem[?dmaLo - 4] == ?dmaHi - ?dmaLo; // byte[].Length // // REVIEW we often casually spec that a bunch of operations keep EFL // // constant. We should probably check or let it vary nondeterministically. // ensures _s == IomUpdate(s, // IomState( // s._io._iom.IomMem, // s._io._iom.IomFrozen, // s._io._iom.IoMmuState, // true, // s._io._iom.DevEnabled // )); //// Does physical page n fit inside dma area? If so, we can map it. //function IsDmaPage(ptr:int) returns(bool) //{ // and(ptr, 4095) == 0 // && ?dmaLo <= ptr && ptr + 4096 <= ?dmaHi //} // //function IoPageTableEntry(w0:int, w1:int) returns(bool) //{ // w1 == 0 && (w0 == 0 || IsDmaPage(w0 - 3)) //} // //function{:expand false} IoPageTable($IomMem:[int]int, ptr:int) returns(bool) //{ // and(ptr, 4095) == 0 // && (forall i:int::{TV(i)} TV(i) && 0 <= i && i < 512 ==> // IoPageTableEntry($IomMem[ptr + 8 * i], $IomMem[ptr + 8 * i + 4])) //} // //function IoPageDirEntry($IomMem:[int]int, w0:int, w1:int) returns(bool) //{ // w1 == 0 && (w0 == 0 || IoPageTable($IomMem, w0 - 3)) //} // //function{:expand false} IoPageDir($IomMem:[int]int, ptr:int) returns(bool) //{ // and(ptr, 4095) == 0 // && (forall i:int::{TV(i)} TV(i) && 0 <= i && i < 512 ==> // IoPageDirEntry($IomMem, $IomMem[ptr + 8 * i], $IomMem[ptr + 8 * i + 4])) //} // //function{:expand false} IoPageDirStub($IomMem:[int]int, ptr:int) returns(bool) //{ // and(ptr, 4095) == 0 // && $IomMem[ptr + 4] == 0 // && (forall i:int::{TV(i)} TV(i) && 1 <= i && i < 512 ==> // $IomMem[ptr + 8 * i] == 0 && $IomMem[ptr + 8 * i + 4] == 0) //} // //function IoContextEntry($IomMem:[int]int, w0:int, w1:int, w2:int, w3:int) returns(bool) //{ // w3 == 0 && w2 == 258 && w1 == 0 // && IoPageDirStub($IomMem, w0 - 3) // && IoPageDirStub($IomMem, $IomMem[w0 - 3] - 3) // && IoPageDir($IomMem, $IomMem[$IomMem[w0 - 3] - 3] - 3) //} // //function{:expand false} IoContextTable($IomMem:[int]int, ptr:int) returns(bool) //{ // and(ptr, 4095) == 0 // && (forall i:int::{TV(i)} TV(i) && 0 <= i && i < 256 ==> // IoContextEntry($IomMem, // $IomMem[ptr + 16 * i + 0], // $IomMem[ptr + 16 * i + 4], // $IomMem[ptr + 16 * i + 8], // $IomMem[ptr + 16 * i + 12])) //} // //function IoRootEntry($IomMem:[int]int, w0:int, w1:int, w2:int, w3:int) returns(bool) //{ // w3 == 0 && w2 == 0 && w1 == 0 && IoContextTable($IomMem, w0 - 1) //} // //function{:expand false} IoRootTable($IomMem:[int]int, ptr:int) returns(bool) //{ // and(ptr, 4095) == 0 // && (forall i:int::{TV(i)} TV(i) && 0 <= i && i < 256 ==> // IoRootEntry($IomMem, // $IomMem[ptr + 16 * i + 0], // $IomMem[ptr + 16 * i + 4], // $IomMem[ptr + 16 * i + 8], // $IomMem[ptr + 16 * i + 12])) //} //- PCI //- The 16-bit value BusNumber||DeviceNumber||FunctionNumber function IsValidPciId(id:int) returns(bool) { 0 <= id && id < 65536 } function IsValidPciOffset(o:int) returns(bool) { 0 <= o && o < 256 && (o mod 4 == 0) } //- Note: these three functions record the fact that some read/load/store //- occured at some time. We could make them more precise by recording the //- exact time (or some sequence number). function PciConfigReadResult(id:int, offset:int, val:int) returns(bool); function PciMemLoaded(id:int, ptr:int, val:int) returns(bool); function PciMemStored(id:int, ptr:int, val:int) returns(bool); function PciMemAddr(id:int) returns(int); function PciMemSize(id:int) returns(int); function PciDeviceAtId(id:int) returns(bool); //- Is there actually a device present at id? function PciSupportsCapabilityList(id:int) returns (bool); function PciCapabilityPtr(id:int, index:int) returns (int); //- Returns a pointer to the index-th capability for ID function PciCapabilityID(id:int, index:int) returns (int); //- ID of the index-th capability function SafePciMemRegion(addr:int, size:int) returns(bool) { word(addr) && addr >= 0xC0000000 && //- We designate the upper regions of memory for memory-mapped PCI-configuration registers ((addr + size) < 0xFED40000 || addr >= 0xFED45000) //- Don't clobber the TPM's memory mapping } //- $PciConfigState[id] in {0,1,2,3,4} //- 0 ==> start state //- 1 ==> memory space disabled //- 2 ==> BAR set to 0xffffffff //- 3 ==> BAR set to address //- 4 ==> memory space enabled function PciVendorId(config0:int) returns(int) { and(config0, 65535) } function PciHeaderType(config12:int) returns(int) { and(shr(config12, 16), 255) } atomic procedure instr_PciConfigAddrOut32(const my r:regs, linear io:IOState, id:int, offset:int) returns(linear _io:IOState); requires r.regs[EAX] == or(or(shl(id, 8), offset), 0x80000000); requires r.regs[EDX] == 0xcf8; requires public(id); //- Secret values should have no effect on our id/address choices (which devices may see) requires public(offset); requires public(io._inCtr); requires public(io._outCtr); requires IsValidPciId(id); requires IsValidPciOffset(offset); ensures _io == OutUpdate(PciUpdate(io, PciState(id, offset, io._pci.PciConfigState))); atomic procedure instr_PciConfigDataIn32(my r:regs, linear io:IOState, id:int, offset:int) returns(my _r:regs, linear _io:IOState); requires id == io._pci.PciConfigId; requires offset == io._pci.PciConfigOffset; requires r.regs[EDX] == 0xcfc; requires public(id); //- Secret values should have no effect on our id/address choices (which devices may see) requires public(offset); // REVIEW: Is this redundant with the checks on PciConfigAddrOut32 above? requires public(io._inCtr); requires public(io._outCtr); requires IsValidPciId(id); requires IsValidPciOffset(offset); ensures (exists eax_val:int :: _io == InOutUpdate(io) //- Since addr we read is publicly visible, this is both an In and Out event && _r.regs == r.regs[EAX := eax_val] && _r.efl == r.efl && PciConfigReadResult(id, offset, eax_val) && (offset == 0 ==> (eax_val == 0xFFFFFFFF <==> !PciDeviceAtId(id))) //- Bus master must return Fs if you ask for offset 0 of a non-present device && (PciDeviceAtId(id) ==> (offset == 4 ==> PciSupportsCapabilityList(id) == GetBit(20, eax_val)) && (offset == 0x34 && PciSupportsCapabilityList(id) ==> PciCapabilityPtr(id, 0) == SelectLSBs(8, eax_val) && IsValidPciOffset(PciCapabilityPtr(id, 0))) && (forall cap_index:int :: PciCapabilityPtr(id, cap_index) == offset && offset != 0 ==> ( PciCapabilityID(id, cap_index) == SelectLSBs(8, eax_val) && PciCapabilityPtr(id, cap_index+1) == shr(SelectLSBs(16, eax_val), 8) && IsValidPciOffset(PciCapabilityPtr(id, cap_index+1)))) ) && (io._pci.PciConfigState[id] == 0 && offset == 16 && and(eax_val, 15) == 0 ==> PciMemAddr(id) == eax_val) && (io._pci.PciConfigState[id] == 2 && offset == 16 ==> PciMemSize(id) == 1 + neg(eax_val)) && word(eax_val) && word(PciMemSize(id))); ensures public(_r.regs[EAX]); //- If a device doesn't exist, then it doesn't support capabilities atomic ghost procedure non_existent_devices(id:int); requires !PciDeviceAtId(id); ensures !PciSupportsCapabilityList(id); //- Once you reach a NULL pointer, there are no interesting IDs remaining atomic ghost procedure cap_list_termination(id:int, cap_index:int); requires PciCapabilityPtr(id, cap_index) == 0; ensures (forall other_cap_index:int :: {PciCapabilityID(id, other_cap_index)} other_cap_index >= cap_index ==> PciCapabilityID(id, other_cap_index) == 0); atomic procedure instr_PciConfigDataOut32(const my r:regs, linear io:IOState, id:int, offset:int, config0:int, config4:int, config12:int, config16:int) returns(linear _io:IOState); requires id == io._pci.PciConfigId; requires offset == io._pci.PciConfigOffset; requires r.regs[EDX] == 0xcfc; requires public(id); //- Secret values should have no effect on our id/address choices (which devices may see) requires public(offset); // REVIEW: Is this redundant with the checks on PciConfigAddrOut32 above? requires public(io._inCtr); requires public(io._outCtr); requires IsValidPciId(id); requires IsValidPciOffset(offset); requires and(id, 7) == 0; //- support only function 0 for now requires PciConfigReadResult(id, 0, config0); requires PciConfigReadResult(id, 4, config4); requires PciConfigReadResult(id, 12, config12); requires PciConfigReadResult(id, 16, config16); requires PciVendorId(config0) != 65535; requires PciHeaderType(config12) == 0; requires io._pci.PciConfigState[id] == 0 ==> offset == 4 && r.regs[EAX] == and(config4, 0xfffffffd); requires io._pci.PciConfigState[id] == 1 ==> offset == 16 && r.regs[EAX] == 0xffffffff; requires io._pci.PciConfigState[id] == 2 ==> offset == 16 && r.regs[EAX] == PciMemAddr(id) && SafePciMemRegion(PciMemAddr(id), PciMemSize(id)); requires io._pci.PciConfigState[id] == 3 ==> offset == 4 && r.regs[EAX] == or(config4, 2); requires io._pci.PciConfigState[id] != 4; ensures (exists _pci_config:int, _pci_config_offset:int:: _io == OutUpdate(PciUpdate( io, PciState( _pci_config, _pci_config_offset, io._pci.PciConfigState[id := 1 + io._pci.PciConfigState[id]] )))); atomic procedure instr_PciMemLoad32(my r:regs, linear io:IOState, id:int, dst:int, ptr:opn_mem) returns(my _r:regs, linear _io:IOState); //requires io._iom.IoMmuEnabled; requires io._pci.PciConfigState[id] == 4; requires PciMemAddr(id) <= EvalPtr(r, ptr) && EvalPtr(r, ptr) + 4 <= PciMemAddr(id) + PciMemSize(id); requires public(id); //- Secret values should have no effect on our id choices (which devices may see) requires public(io._inCtr); requires public(io._outCtr); requires public(EvalPtr(r, ptr)); //- Secret vals shouldn't affect addr we read on bus ensures PciMemLoaded(id, EvalPtr(r, ptr), _r.regs[dst]); ensures word(_r.regs[dst]); ensures (exists v:int:: //- Since addr we read is publicly visible, this is both an In and Out event _io == InOutUpdate(io) && _r.regs == r.regs[dst := v] && _r.efl == r.efl && word(v) ); ensures public(_r.regs[dst]); atomic procedure instr_PciMemStore32(const my r:regs, linear io:IOState, id:int, ptr:opn_mem, src:opn) returns(linear _io:IOState); //requires io._iom.IoMmuEnabled; requires io._pci.PciConfigState[id] == 4; requires PciMemAddr(id) <= EvalPtr(r, ptr) && EvalPtr(r, ptr) + 4 <= PciMemAddr(id) + PciMemSize(id); requires word(Eval(r, src)); requires public(id); //- Secret values should have no effect on our id choices (which devices may see) requires public(io._inCtr); requires public(io._outCtr); requires public(EvalPtr(r, ptr)); //- Secret vals shouldn't affect addr we read on bus requires public(Eval(r, src)); //- nor the value itself ensures PciMemStored(id, EvalPtr(r, ptr), Eval(r, src)); ensures _io == OutUpdate(io); //- Device memory is a region where devices can freely read and write, so we can't assume anything about its contents const ?devMemLo:int := 0x08000000; //- 128 MB up const ?devMemHi:int := 0xF0000000; //const ?devMemHi:int := ?devMemLo + 64 * 1024 * 1024; // 64 MB // TODO: Restore if we enable DEV const ?wordsPerPacket:int := 1500 div 4; atomic procedure instr_DeviceLoad(my r:regs, linear io:IOState, dst:int, ptr:opn_mem) returns(my _r:regs, linear _io:IOState); //requires io._iom.DevEnabled; // TODO: Restore if we enable the DEV requires ?devMemLo <= EvalPtr(r, ptr) && EvalPtr(r, ptr) + 4 <= ?devMemHi; requires public(io._inCtr); requires public(io._outCtr); requires public(EvalPtr(r, ptr)); //- Secret vals shouldn't affect addr we read on bus ensures (exists v:int:: //- Since addr we read is publicly visible, this is both an In and Out event _io == InOutUpdate(io) && _r.regs == r.regs[dst := v] && _r.efl == r.efl && word(v)); ensures public(_r.regs[dst]); atomic procedure instr_DeviceStore(const my r:regs, linear io:IOState, ptr:opn_mem, src:opn) returns(linear _io:IOState); requires ?devMemLo <= EvalPtr(r, ptr) && EvalPtr(r, ptr) + 4 <= ?devMemHi; // requires SrcOk(src); // not needed, checked by boogieasm requires public(io._inCtr); requires public(io._outCtr); requires public(EvalPtr(r, ptr)); //- Secret vals shouldn't affect addr we read on bus requires public(Eval(r, src)); //- nor the value itself ensures _io == OutUpdate(io); //-//////////////////////////////////////////////////////////////// //- Device Exclusion Vector (DEV) Configuration //-//////////////////////////////////////////////////////////////// const ?DEVLo:int := ?CodeBase + 60*1024; //- Must be 4K aligned const ?DEVHi:int := ?CodeBase + 64*1024; //- 4K at the top of our 64K located at ?CodeBase //- Is this the capability portion of the DEV's PCI config space? function DEV_PciCapabilityAt(id:int, dev_offset:int) : bool { dev_offset != 0 && PciSupportsCapabilityList(id) && (exists cap_index:int :: {TV(cap_index)} TV(cap_index) && 0 <= cap_index && PciCapabilityPtr(id, cap_index) == dev_offset //- The offset points at some PCI capability && PciCapabilityID(id, cap_index) == 0x0f) //- The capability is the DEV capability (AMD vol2, Table 15-16) } //- According to the spec, a PCI capability ID is vendor agnostic, //- so finding the DEV capability ID should suffice function Is_DEV_PCI_config(id:int) : bool { (exists offset:int :: {TV(offset)} TV(offset) && DEV_PciCapabilityAt(id, offset)) } //- Are we addressing the DEV_OP register in the DEV's capability block? function DEV_Op(id:int, dev_offset:int, write_offset:int) : bool { DEV_PciCapabilityAt(id, dev_offset) && write_offset == dev_offset + 4 } //- Are we addressing the DEV_DATA register in the DEV's capability block? function DEV_Data(id:int, dev_offset:int, write_offset:int) : bool { DEV_PciCapabilityAt(id, dev_offset) && write_offset == dev_offset + 8 } //- Has the memory for the DEV been configured properly, i.e., in the right location and with all 1s to block all access? function ValidDEV(dev_mem:mem) : bool { (forall i:int :: dev_mem.dom[i] <==> (?DEVLo <= i && i < ?DEVHi)) && (forall i:int :: PhysPtrOk(dev_mem, i) ==> if ?DEVLo <= i && i < ?DEVLo + 96 then dev_mem.map[i] == 0 else dev_mem.map[i] == 0xFFFFFFFF) //- First 96 bytes of DEV cover the first 3MB of memory (up to the base of our code). //- Allow device access so things like legacy VGA will work } //- How many DEV_MAP registers does this DEV support? function num_DEV_map_regs(id:int) returns(int); //-///////////////////////////////////////////////////// //- PCI data writes that advance us through the //- DEV configuration state machine defined below //-///////////////////////////////////////////////////// function DEV_OpBaseLo(id:int, dev_offset:int, write_offset:int, val:int) : bool { DEV_Op(id, dev_offset, write_offset) && val == 0x000 } function DEV_OpBaseHi(id:int, dev_offset:int, write_offset:int, val:int) : bool { DEV_Op(id, dev_offset, write_offset) && val == 0x100 } function DEV_OpMap(id:int, dev_offset:int, write_offset:int, val:int, map_index:int) : bool { DEV_Op(id, dev_offset, write_offset) && val == (0x200 + map_index) } function DEV_OpCap(id:int, dev_offset:int, write_offset:int, val:int) : bool { DEV_Op(id, dev_offset, write_offset) && val == 0x300 } function DEV_OpCtrl(id:int, dev_offset:int, write_offset:int, val:int) : bool { DEV_Op(id, dev_offset, write_offset) && val == 0x400 } function DEV_DataBaseLo(id:int, dev_offset:int, write_offset:int, val:int) : bool { DEV_Data(id, dev_offset, write_offset) && val == ?CodeBase + 60*1024 + 1 //- Bit 0 = 1 ==> Valid. Size = 0 ==> DEV covers 4 GB. Address must be ?CodeBase+60K } function DEV_DataBaseHi(id:int, dev_offset:int, write_offset:int, val:int) : bool { DEV_Data(id, dev_offset, write_offset) && val == 0 //- Only using 32-bit addressing } function DEV_DataMap(id:int, dev_offset:int, write_offset:int, val:int) : bool { DEV_Data(id, dev_offset, write_offset) && val == 0 //- Only using 32-bit addressing } function DEV_DataCtrl(id:int, dev_offset:int, write_offset:int, val:int) : bool { DEV_Data(id, dev_offset, write_offset) && val == 0x31 //- Enabled bits: [0]=DEV enable, [4]=Invalidate DEV cache, [5]=Keep existing 64K SKINIT protection //- Disabled bits: [6]=>Host bridge probes processor cache when reading DEV } //- Must not have any linear constructors! type DEV_StateMachines = States(states:[int]DEV_StateMachine); //- States of all north bridges type DEV_StateMachine = Init() | MemApproved() | SetOpBaseLo() | SetDataBaseLo() | SetOpBaseHi() | SetDataBaseHi() | SetOpCap() | GotDataCap() | SetOpMap(o_map_index:int) | SetDataMap(d_map_index:int) | SetOpCtrl() | SetDataCtrl() | Complete() | Invalid(); type DEV_PCI_op = DEV_Read(rval:int) | DEV_Write(wval:int); function DEV_AdvanceStateMachine(op:DEV_PCI_op, DEV_state:DEV_StateMachine, id:int, dev_offset:int, write_offset:int) : DEV_StateMachine { if op is DEV_Write then if DEV_state is MemApproved && DEV_OpBaseLo (id, dev_offset, write_offset, op.wval) then SetOpBaseLo() else if DEV_state is SetOpBaseLo && DEV_DataBaseLo(id, dev_offset, write_offset, op.wval) then SetDataBaseLo() else if DEV_state is SetDataBaseLo && DEV_OpBaseHi (id, dev_offset, write_offset, op.wval) then SetOpBaseHi() else if DEV_state is SetOpBaseHi && DEV_DataBaseHi(id, dev_offset, write_offset, op.wval) then SetDataBaseHi() else if DEV_state is SetDataBaseHi && DEV_OpCap (id, dev_offset, write_offset, op.wval) then SetOpCap() else if DEV_state is GotDataCap && DEV_OpCtrl (id, dev_offset, write_offset, op.wval) && num_DEV_map_regs(id) == 0 then SetOpCtrl() //- If there are no maps, go directly to ctrl configuration. else if DEV_state is GotDataCap && DEV_OpMap (id, dev_offset, write_offset, op.wval, 0) then SetOpMap(0) //- If there are maps, we need to configure each one. else if DEV_state is SetOpMap && DEV_DataMap (id, dev_offset, write_offset, op.wval) then SetDataMap(DEV_state.o_map_index) else if DEV_state is SetDataMap then if DEV_state.d_map_index + 1 < num_DEV_map_regs(id) && DEV_OpMap (id, dev_offset, write_offset, op.wval, DEV_state.d_map_index+1) then SetOpMap(DEV_state.d_map_index + 1) //- Progress to the next map else if DEV_state.d_map_index + 1 >= num_DEV_map_regs(id) && DEV_OpCtrl(id, dev_offset, write_offset, op.wval) then SetOpCtrl() //- We've set all the maps, so we can set the ctrl reg else Invalid() else if DEV_state is SetOpCtrl && DEV_DataCtrl (id, dev_offset, write_offset, op.wval) then SetDataCtrl() else Invalid() else //- read_op if DEV_state is SetDataCtrl && DEV_Data(id, dev_offset, write_offset) then //- Valid read op if !GetBit(4, op.rval) then //- Cache invalidation completed Complete() else SetDataCtrl() //- Cache invalidation still in progress, so stay in the same state else if DEV_state is SetOpCap && DEV_Data(id, dev_offset, write_offset) then GotDataCap() else Invalid() } //- To start the DEV state machine, you must prove that the memory in dev_mem //- constitutes a well-formed (for our purposes) DEV bit-vector. It consumes //- the linear token for dev_mem, which prevents future loads/store to the memory region. atomic ghost procedure begin_DEV_enablement(linear DEV_states:DEV_StateMachines, linear dev_mem:mem) returns (linear _DEV_states:DEV_StateMachines); requires ?CodeBase == 0x300000; //- Format of the DEV spec expects this requires (forall i:int::{ DEV_states.states[i] } DEV_states.states[i] is Init); requires ValidDEV(dev_mem); ensures (forall i:int::{ _DEV_states.states[i] } _DEV_states.states[i] is MemApproved); atomic procedure instr_DEV_PciConfigDataIn32(my r:regs, linear io:IOState, linear DEV_states:DEV_StateMachines, id:int, dev_offset:int, offset:int) returns(my _r:regs, linear _io:IOState, linear _DEV_states:DEV_StateMachines); requires id == io._pci.PciConfigId; requires offset == io._pci.PciConfigOffset; requires r.regs[EDX] == 0xcfc; requires IsValidPciId(id); requires IsValidPciOffset(offset); requires (forall read_val:int :: DEV_AdvanceStateMachine(DEV_Read(read_val), DEV_states.states[id], id, dev_offset, offset) != Invalid()); requires public(id); //- Secret values should have no effect on our id/address choices (which devices may see) requires public(offset); // REVIEW: Is this redundant with the checks on PciConfigAddrOut32 above? requires public(io._inCtr); requires public(io._outCtr); ensures _DEV_states == States(DEV_states.states[id := DEV_AdvanceStateMachine(DEV_Read(_r.regs[EAX]), DEV_states.states[id], id, dev_offset, offset)]); ensures (exists eax_val:int :: //- Since addr we read is publicly visible, this is both an In and Out event _io == InOutUpdate(io) && _r.regs == r.regs[EAX := eax_val] && _r.efl == r.efl && (_DEV_states.states[id] is GotDataCap ==> num_DEV_map_regs(id) == SelectLSBs(8, shr(eax_val, 16))) && word(eax_val)); ensures public(_r.regs[EAX]); atomic procedure instr_DEV_PciConfigDataOut32(const my r:regs, linear io:IOState, linear DEV_states:DEV_StateMachines, id:int, dev_offset:int, offset:int) returns(linear _io:IOState, linear _DEV_states:DEV_StateMachines); requires id == io._pci.PciConfigId; requires offset == io._pci.PciConfigOffset; requires r.regs[EDX] == 0xcfc; requires DEV_AdvanceStateMachine(DEV_Write(r.regs[EAX]), DEV_states.states[id], id, dev_offset, offset) != Invalid(); requires public(id); //- Secret values should have no effect on our id/address choices (which devices may see) requires public(offset); // REVIEW: Is this redundant with the checks on PciConfigAddrOut32 above? requires public(io._inCtr); requires public(io._outCtr); ensures _DEV_states == States(DEV_states.states[id := DEV_AdvanceStateMachine(DEV_Write(r.regs[EAX]), DEV_states.states[id], id, dev_offset, offset)]); ensures (exists _pci_config:int, _pci_config_offset:int:: _io == OutUpdate(PciUpdate( io, PciState( _pci_config, _pci_config_offset, io._pci.PciConfigState )))); atomic ghost procedure complete_DEV_enablement(linear DEV_states:DEV_StateMachines) returns (linear new_mem:mem); requires (forall i:int :: IsValidPciId(i) ==> (Is_DEV_PCI_config(i) ==> DEV_states.states[i] is Complete)); ensures (forall i:int ::{ new_mem.dom[i] } {TV(i)} new_mem.dom[i] <==> TV(i) && ?CodeBase + 64*1024 <= i && i < 128*1024*1024); //- Top=base+64K DEV covers 128MB total // TODO: Need to fix triggers here! //-//////////////////////////////////////////////////////////////// //- Generic Dafny interface for reading/writing device memory //-//////////////////////////////////////////////////////////////// type IoMemPerm_t = Null() | IoReadAddr(r_addr:int, r_val:int) | IoWriteAddr(w_addr:int, w_val:int); readonly var $ghost_IoMemPerm:IoMemPerm_t; // REVIEW: Add relational requirements here or handle at the points where // we dole out the IoMemPerms? atomic procedure instr_IoMemAddrRead(my r:regs, dst:int, ptr:opn_mem) returns(my _r:regs); requires $ghost_IoMemPerm is IoReadAddr; requires $ghost_IoMemPerm.r_addr == EvalPtr(r, ptr); modifies $ghost_IoMemPerm; ensures $ghost_IoMemPerm is Null; ensures _r.regs == r.regs[dst := old($ghost_IoMemPerm).r_val]; ensures _r.efl == r.efl; ensures word(_r.regs[dst]); atomic procedure instr_IoMemAddrWrite(const my r:regs, ptr:opn_mem, src:opn); requires $ghost_IoMemPerm is IoWriteAddr; requires $ghost_IoMemPerm.w_addr == EvalPtr(r, ptr); requires $ghost_IoMemPerm.w_val == Eval(r, src); modifies $ghost_IoMemPerm; ensures $ghost_IoMemPerm is Null; } //- End of module ================================================ FILE: ironclad-apps/src/Trusted/Spec/IoSpec.imp.basm ================================================ //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- //- //- seed 1 module implementation IoSpec { //implementation rsdpExists($ptr:int, $entry:int) { } // //implementation dmarExists($ptr:int, $entry:int) { } // //implementation drhdExists($ptr:int, $entry:int) { } // //implementation drhdEnd($ptr:int, $entry:int) { } implementation non_existent_devices(id:int) { } implementation cap_list_termination(id:int, cap_index:int) { } implementation begin_DEV_enablement(linear DEV_states:DEV_StateMachines, linear dev_mem:mem) returns (linear _DEV_states:DEV_StateMachines) { } implementation complete_DEV_enablement(linear DEV_states:DEV_StateMachines) returns (linear new_mem:mem) { } } ================================================ FILE: ironclad-apps/src/Trusted/Spec/IoTypesSpec.ifc.basm ================================================ //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module interface IoTypesSpec { } ================================================ FILE: ironclad-apps/src/Trusted/Spec/IoTypesSpec.imp.basm ================================================ //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module implementation IoTypesSpec {} ================================================ FILE: ironclad-apps/src/Trusted/Spec/Io_axioms.bpl ================================================ //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- //// REVIEW: Why is the bound inclusive? //axiom (forall i:int,size:int::{inRo(i,size)} ?RoBiosLo <= i && i + size <= ?RoBiosHi ==> inRo(i,size)); // //axiom (forall ptr:int::{ByteSum(ptr, ptr)} ByteSum(ptr, ptr) == 0); //axiom (forall ptr:int,end:int::{ByteSum(ptr, end)} ptr <= end ==> ByteSum(ptr, end + 1) == ByteSum(ptr, end) + roU8(end)); // //axiom ?RsdpExists ==> // ?RsdtPtr == ro32(?RsdpPtr + 16) // && inRo(?RsdtPtr + 4, 4) // && 36 + 4 * ?RsdtCount == ro32(?RsdtPtr + 4) // && ?RsdtCount >= 0 // && word(?RsdtPtr) && word(?RsdtPtr + 36 + 4 * ?RsdtCount) // && (forall i:int::{TV(i)} TV(i) && 0 <= i && i < ?RsdtCount ==> // inRo( ?RsdtPtr + 36 + 4 * i, 4) // && inRo(ro32(?RsdtPtr + 36 + 4 * i), 4)); // //axiom ?DmarExists ==> // inRo(?DmarPtr + 4, 4) // && ?DmarLen == ro32(?DmarPtr + 4) // && ?DmarLen >= 48 // && word(?DmarPtr) && word(?DmarPtr + ?DmarLen) // && MaybeDrhd(?DmarPtr + 48, 0); // ////axiom word(?BYTE_VECTOR_VTABLE); ================================================ FILE: ironclad-apps/src/Trusted/Spec/MachineStateSpec.ifc.basm ================================================ //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module interface MachineStateSpec { } ================================================ FILE: ironclad-apps/src/Trusted/Spec/MachineStateSpec.imp.basm ================================================ //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module implementation MachineStateSpec {} ================================================ FILE: ironclad-apps/src/Trusted/Spec/MemorySpec.ifc.basm ================================================ //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module interface MemorySpec { //-//////////////////////////////////////////////////////////////////////////// //- MEMORY ADDRESSES //-//////////////////////////////////////////////////////////////////////////// //- Aligned(i) <==> i is a multiple of 4 function Aligned(i:int) returns(bool); atomic ghost procedure reveal_Aligned(val:int); ensures Aligned(val) == (val mod 4 == 0); //-//////////////////////////////////////////////////////////////////////////// //- MAIN MEMORY //-//////////////////////////////////////////////////////////////////////////// const ?CodeBase:int; const ?memLo: int; const ?memHi: int; function memAddr(i:int) returns (bool); function memAddrMain(i:int) returns (bool) {?memLo <= i && i < ?memHi} function memAddrMainEx(i:int) returns (bool) {?memLo <= i && i <= ?memHi} // TODO: remove atomic ghost procedure memAddrBounds(i:int); ensures memAddr(i) ==> 4 <= i && i + 4 < WORD_HI; //- require 4 bytes on either end to help push/pop //-//////////////////////////////////////////////////////////////////////////// //- STATIC DATA MEMORY //-//////////////////////////////////////////////////////////////////////////// function StaticAddrToId(i:int):int; //- each static variable has an id within a module //-//////////////////////////////////////////////////////////////////////////// //- READ-ONLY MEMORY //-//////////////////////////////////////////////////////////////////////////// function roS8(ptr:int) returns(int); function roU8(ptr:int) returns(int); function roS16(ptr:int) returns(int); function roU16(ptr:int) returns(int); function ro32(ptr:int) returns(int); function inRo(ptr:int, size:int) returns(bool); ////////////////////////////////////////////////////////////////////////////// // GC MEMORY ////////////////////////////////////////////////////////////////////////////// // valid gc-controlled addresses (must be disjoint from null values) // warning: because of interior pointers, ?gcHi must be a 32-bit word // (it can equal 2^32 - 1, but not 2^32) //const ?gcLo:int := ?memLo + 0x110000 + 0x402000 + 8 * 65536; //const ?gcHi:int := ?memHi; //function gcAddr(i:int) returns (bool) {?gcLo <= i && i < ?gcHi} //function gcAddrEx(i:int) returns (bool) {?gcLo <= i && i <= ?gcHi} } ================================================ FILE: ironclad-apps/src/Trusted/Spec/MemorySpec.imp.basm ================================================ //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module implementation MemorySpec { implementation memAddrBounds(i:int) {} implementation reveal_Aligned(val:int) {} } ================================================ FILE: ironclad-apps/src/Trusted/Spec/Memory_axioms.bpl ================================================ //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- //-//////////////////////////////////////////////////////////////////////////// //- GC-CONTROLLED MEMORY //-//////////////////////////////////////////////////////////////////////////// //- Aligned(i) <==> i is a multiple of 4 axiom (forall i:int, j:int::{TV(i), TO(j)} TV(i) && TO(j) ==> Aligned(i) == Aligned(i + 4 * j)); axiom NULL < ?memLo; axiom ?memLo <= ?memHi; axiom ?memHi < WORD_HI; axiom Aligned(?memLo); axiom Aligned(?memHi); ================================================ FILE: ironclad-apps/src/Trusted/Spec/Notary/AppRequirements.ifc.stitch ================================================ //-private-import dafny_assembly_s; //-private-import dafny_be_sequences_s; //-private-import dafny_bytes_and_words_s; //-private-import dafny_Digest_s; //-private-import dafny_GCD_s; //-private-import dafny_hmac_common_s; //-private-import dafny_integer_sequences_s; //-private-import dafny_io_mem_s; //-private-import dafny_KeyGen_s; //-private-import dafny_MillerRabin_s; //-private-import dafny_power_s; //-private-import dafny_RandomNumberGen_s; //-private-import dafny_RandomTracing_s; //-private-import dafny_rfc4251_s; //-private-import dafny_round_s; //-private-import dafny_RSASpec_s; //-private-import dafny_seq_blocking_s; //-private-import dafny_sha_common_s; //-private-import dafny_sha1_s; //-private-import dafny_sha256_s; //-private-import dafny_tpm_device_s; //-private-import dafny_CommonState_s; //-private-import dafny_Notary_s; //-private-import dafny_StateMachine_s; requires fun_TPM__valid($ghost_TPM); requires fun_TPM__satisfies__integrity__policy($ghost_TPM); requires $ghost_IoMemPerm is Null; requires TPM#CommonStateMachine_ctor($ghost_current_common_state) == $ghost_TPM; requires !initialized#CommonStateMachine_ctor($ghost_current_common_state); requires !initialized#NotaryStateMachine_ctor($ghost_current_notary_state); modifies $ghost_TPM; modifies $ghost_current_common_state; modifies $ghost_current_notary_state; ================================================ FILE: ironclad-apps/src/Trusted/Spec/NucleusInvCopying.bpl ================================================ //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- //- The Nucleus defines and establishes NucleusInv, which is abstract to managed code. function NucleusInv($S:int, $StackState:[int]StackState, $toAbs:[int]int, $AbsMem:[int][int]int, CurrentStack:int, $gcSlice:[int]int, BF:int, BT:int, HeapLo:int, Fi:int, Fk:int, Fl:int, Ti:int, Tj:int, Tk:int, Tl:int, $Mem:[int]int, stk:[int]int, $dMem:[int]int, $pciMem:[int]int, $tMems:[int][int]int, $fMems:[int][int]int, $gcMem:[int]int, SLo:int, DLo:int, PciLo:int, TLo:int, FLo:int, GcLo:int, GcHi:int, $FrameCounts:[int]int, $FrameAddrs:[int][int]int, $FrameLayouts:[int][int]$FrameLayout, $FrameSlices:[int][int]int, $FrameAbss:[int][int][int]int, $FrameOffsets:[int][int]int, $IoMmuEnabled:bool, $PciConfigState:[int]int, DmaAddr:int ) returns(bool); ================================================ FILE: ironclad-apps/src/Trusted/Spec/Overflow.ifc.basm ================================================ //-private-import BaseSpec; //-private-import MemorySpec; //-private-import IoTypesSpec; //-private-import MachineStateSpec; //-private-import AssemblySpec; //-private-import InterruptsSpec; //-private-import IoSpec; //- //- //- //-private-import Partition; //-private-import Core; //-private-import LogicalAddressing; //-private-import Stacks; //-private-import Instructions; //-private-import Separation; //-private-import Util; //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- module interface Overflow modifies state; { //- Handler for arithmetic overflow (always fatal) procedure Overflow(my r:regs, my c:core_state); ensures false; } ================================================ FILE: ironclad-apps/src/Trusted/Spec/PassHash/AppRequirements.ifc.stitch ================================================ //-private-import dafny_assembly_s; //-private-import dafny_be_sequences_s; //-private-import dafny_bytes_and_words_s; //-private-import dafny_Digest_s; //-private-import dafny_GCD_s; //-private-import dafny_hmac_common_s; //-private-import dafny_integer_sequences_s; //-private-import dafny_io_mem_s; //-private-import dafny_KeyGen_s; //-private-import dafny_MillerRabin_s; //-private-import dafny_power_s; //-private-import dafny_RandomNumberGen_s; //-private-import dafny_RandomTracing_s; //-private-import dafny_seq_blocking_s; //-private-import dafny_sha_common_s; //-private-import dafny_sha1_s; //-private-import dafny_sha256_s; //-private-import dafny_tpm_device_s; //-private-import dafny_round_s; //-private-import dafny_PassHash_s; //-private-import dafny_StateMachine_s; requires fun_TPM__valid($ghost_TPM); requires fun_TPM__satisfies__integrity__policy($ghost_TPM); requires $ghost_IoMemPerm is Null; requires TPM#StateMachine_ctor($ghost_current_state) == $ghost_TPM; requires !initialized#StateMachine_ctor($ghost_current_state); modifies $ghost_TPM; modifies $ghost_current_state; ================================================ FILE: ironclad-apps/src/Trusted/Spec/TPMTest/AppRequirements.ifc.stitch ================================================ requires fun_TPM__valid($ghost_TPM); requires fun_TPM__satisfies__integrity__policy($ghost_TPM); requires $ghost_IoMemPerm is Null; modifies $ghost_TPM; ================================================ FILE: ironclad-apps/src/Trusted/Spec/TrInc/AppRequirements.ifc.stitch ================================================ //-private-import dafny_assembly_s; //-private-import dafny_be_sequences_s; //-private-import dafny_bytes_and_words_s; //-private-import dafny_Digest_s; //-private-import dafny_GCD_s; //-private-import dafny_hmac_common_s; //-private-import dafny_integer_sequences_s; //-private-import dafny_io_mem_s; //-private-import dafny_KeyGen_s; //-private-import dafny_MillerRabin_s; //-private-import dafny_power_s; //-private-import dafny_RandomNumberGen_s; //-private-import dafny_RandomTracing_s; //-private-import dafny_rfc4251_s; //-private-import dafny_round_s; //-private-import dafny_RSASpec_s; //-private-import dafny_seq_blocking_s; //-private-import dafny_sha_common_s; //-private-import dafny_sha1_s; //-private-import dafny_sha256_s; //-private-import dafny_tpm_device_s; //-private-import dafny_CommonState_s; //-private-import dafny_TrInc_s; //-private-import dafny_StateMachine_s; requires fun_TPM__valid($ghost_TPM); requires fun_TPM__satisfies__integrity__policy($ghost_TPM); requires $ghost_IoMemPerm is Null; requires TPM#CommonStateMachine_ctor($ghost_current_common_state) == $ghost_TPM; requires !initialized#CommonStateMachine_ctor($ghost_current_common_state); requires !initialized#TrIncStateMachine_ctor($ghost_current_trinc_state); modifies $ghost_TPM; modifies $ghost_current_common_state; modifies $ghost_current_trinc_state; ================================================ FILE: ironclad-apps/src/Trusted/Spec/Word_axioms.bpl ================================================ //- //- Copyright (c) Microsoft Corporation. All rights reserved. //- //- Axioms about words axiom WORD_HI == 4294967296; ================================================ FILE: ironclad-apps/tools/Beat/ast.fs ================================================ type id = string type loc = string * int type bigint = Microsoft.FSharp.Math.bigint type btyp = | BInt | BBool | BReal | BArray of btyp list * btyp | BNamedType of id type field_op = BFieldNative | BFieldFun | BFieldDotFun type buop = | BNot | BNeg | BOld | BInOutOp | BField of string * (string * string * field_op) option | BIs of string type bbop = | BEquiv | BImply | BAnd | BOr | BEq | BNe | BLt | BGt | BLe | BGe | BAdd | BSub | BMul | BDiv | BMod | BRealDiv | BAddChecked | BSubChecked | BFieldUpdate of string * string option type bquant = | BForall | BExists | BLambda type lin_const = LinConst | LinVar | LinInOut type lin_scope = LinMy | LinOur type linearity = Lin of lin_const * lin_scope | Non type bformal = id * btyp type bpformal = id * btyp * linearity type bexp = | BLoc of loc * bexp | BVar of id | BIntConst of bigint | BRealConst of string | BBv32 of bigint | BBoolConst of bool | BUop of buop * bexp | BBop of bbop * bexp * bexp | BQuant of bquant * bformal list * bexp list list * bexp | BSubscript of bexp * bexp list | BUpdate of bexp * bexp list * bexp | BApply of id * bexp list | BCond of bexp * bexp * bexp type bformal_typ = | BFormalType of btyp | BFormalAlias of bexp type bformal_var = id * bformal_typ * linearity type bformal_fun = id * btyp * bexp option type ret_kind = BRet | BIRet | BEmbellishRet type par_call = id * bexp list type bstmt = | BLocalDecl of id * bformal_typ * linearity * bexp option | BLabel of id | BGoto of id | BAssign of bexp * bexp | BGroup of bblock | BIf of bexp * bblock * bblock option | BWhile of bexp * (loc * bexp) list * bblock | BForallGhost of bformal list * bexp list list * bexp * bblock | BAssume of bexp | BAssert of bexp * bool | BSplit | BYield of bexp | BHavoc of bexp | BCall of bexp list * id * bexp list * par_call list | BReturn of ret_kind and bblock = (loc * bstmt) list type bspec = | BRequires of bexp | BEnsures of bexp | BModifies of bexp list | BInOut of bpformal list type proc_atomicity = Atomic | Yields | Stable type proc_ghost = PGhost | PReal type proc_kind = Procedure of proc_ghost * proc_atomicity | Implementation | Instruction type battr = string type fun_decl = id * bformal_fun list * btyp * bexp option * battr option * bexp list list option type proc_decl = id * bformal_var list * bpformal list * (loc * bspec) list * bblock option * proc_kind type readwrite = Readonly | ReadWrite type bdecl = | BGlobalDecl of id * btyp * linearity * readwrite | BGlobalStaticDecl of id * id | BStaticDecl of id | BConstDecl of id * btyp * bexp option | BAxiomDecl of bexp | BTypeDecl of id * (id list * (linearity * id * bpformal list) list) option | BFunDecl of fun_decl | BProcDecl of proc_decl type bdecls = (loc * bdecl) list type _module = {mName:id; mIsImpl:bool; mImports:id list; mModifies:id list; mYields:id list; mDecls:(loc * bdecl) list} ================================================ FILE: ironclad-apps/tools/Beat/beat.vim ================================================ " Vim syntax file " Language: Beat " Maintainer: Bryan Parno " Last Change: April 2, 2013 " Version: 1 " Use the following lines in your .vimrc file to make use of this file: " " Syntax coloring for Beat/Boogie " au BufRead,BufNewFile *.beat set filetype=beat " au BufRead,BufNewFile *.bpl set filetype=beat " "au! Syntax beat source $VIM/beat.vim if exists("b:current_syntax") finish endif syn case match syn keyword bDecl function procedure implementation atomic module returns instruction syn keyword bCond if then else syn keyword bRepeat while syn keyword bPreReqs requires invariant syn keyword bProof ensures modifies assert syn keyword bCommentTodo TODO REVIEW contained syn keyword bConst const type linear var syn match bLineComment "\/\/.*" contains=@Spell,bCommentTodo syn region bComment start="/\*" end="\*/" contains=@Spell,bCommentTodo syn match bNumber "-\=\<\d\+L\=\>\|0[xX][0-9a-fA-F]\+\>" syn match bType ":[a-zA-Z_[\]]\+[0-9a-zA-Z_[\]]\+" syn match bTrigger "::\(\_[\t ]*{.\{-}}\)\+" hi def link bDecl PreCondit hi def link bCond Conditional hi def link bRepeat Repeat hi def link bProof Macro hi def link bType Type hi def link bComment Comment hi def link bLineComment Comment hi def link bCommentTodo Todo hi def link bConst Keyword hi def link bNumber Number hi def link bTrigger Debug hi def link bPreReqs Underlined let b:current_syntax = "beat" ================================================ FILE: ironclad-apps/tools/Beat/lex.fsl ================================================ { open Lexing;; open Parse;; open Parse_util;; open Microsoft.FSharp.Compatibility.OCaml.Big_int;; let macros = ref (Map.empty:Map) let pushed_tokens = ref ([]:token list) let rec get_token token_fun buf = match !pushed_tokens with | [] -> ( let token = token_fun buf in match token with | Parse.UID x | Parse.LID x | Parse.DUID x | Parse.DLID x | Parse.QUID x | Parse.QLID x -> ( match Map.tryFind x !macros with | Some l -> pushed_tokens := l @ !pushed_tokens; get_token token_fun buf | None -> token ) | _ -> token ) | h::t -> pushed_tokens := t; h } rule comment = parse | "*/" { () } | "*)" { () } | "/*" { comment lexbuf ; comment lexbuf } | "(*" { comment lexbuf ; comment lexbuf } | "\n\r" { incr line; comment lexbuf } | "\r\n" { incr line; comment lexbuf } | ['\n''\r'] { incr line; comment lexbuf } | _ { comment lexbuf } and preprocess_skip deep = parse | "#else" { if deep then preprocess_skip deep lexbuf else () } | "#endif" { () } | "#ifdef" { preprocess_skip true lexbuf; preprocess_skip deep lexbuf } | "#ifndef" { preprocess_skip true lexbuf; preprocess_skip deep lexbuf } | "\n\r" { incr line; preprocess_skip deep lexbuf } | "\r\n" { incr line; preprocess_skip deep lexbuf } | ['\n''\r'] { incr line; preprocess_skip deep lexbuf } | _ { preprocess_skip deep lexbuf } and macro_def = parse | [' ']+[^'\n''\r']* { lexeme lexbuf } | "" { "" } and token = parse | "\n\r" { incr line; token lexbuf } | "\r\n" { incr line; token lexbuf } | ['\n''\r'] { incr line; token lexbuf } | [' ''\t'] { token lexbuf } | "//"[^'\n''\r']* { token lexbuf } | "#line"[' '][^'\n''\r']* { token lexbuf } | "/*" { comment lexbuf ; token lexbuf } | "(*" { comment lexbuf ; token lexbuf } | "#ifdef"[' ']+['A'-'Z''a'-'z''0'-'9''_''$''?']+ { let s = lexeme lexbuf in let x = s.Substring("#ifdef".Length).Trim() in if Map.contains x !macros then token lexbuf else (preprocess_skip false lexbuf ; token lexbuf) } | "#ifndef"[' ']+['A'-'Z''a'-'z''0'-'9''_''$''?']+ { let s = lexeme lexbuf in let x = s.Substring("#ifndef".Length).Trim() in if not (Map.contains x !macros) then token lexbuf else (preprocess_skip false lexbuf ; token lexbuf) } | "#else" { preprocess_skip false lexbuf ; token lexbuf } | "#endif" { token lexbuf } | "#define"[' ']+['A'-'Z''a'-'z''0'-'9''_''$''?']+ { let s = lexeme lexbuf in let x = s.Substring("#define".Length).Trim() in let def = macro_def lexbuf in let buf = Lexing.from_string def in let rec f l = match get_token token buf with | EOF -> l | t -> f (t::l) in macros := Map.add x (List.rev (f [])) !macros; token lexbuf } | ":" { COLON (!file, !line) } | ";" { SEMI (!file, !line) } | "(" { LPAREN } | ")" { RPAREN } | "[" { LBRACKET } | "]" { RBRACKET } | "{" { LBRACE (!file, !line) } | "}" { RBRACE (!file, !line) } | "<" { LT } | ">" { GT } | "|" { BAR } | "=" { EQ } | "+" { PLUS } | "-" { MINUS } | "*" { STAR } | "/" { SLASH } | "!" { BANG } | "#" { HASH } | "^" { CARET } | "?" { QUESTION } | "," { COMMA } | "." { DOT } | "_" { UNDERSCORE } | "'" { SQUOTE } | "`" { BQUOTE } | "@" { AT } | "$" { DOLLAR } | "mod" { MOD } | "div" { DIV } | "&" { AMP } | "&&&" { AMPAMPAMP } | "\\" { BACKSLASH } | "++" { PLUSPLUS } | "->" { RARROW } | "<-" { LARROW } | "-o" { RLOL } | "=>" { REQARROW } | ":=" { COLONEQ (!file, !line) } | "<=" { LE } | ">=" { GE } | "==" { EQEQ (!file, !line) } | "!=" { NE } | "&&" { AMPAMP (!file, !line) } | "||" { BARBAR (!file, !line) } | "::" { COLONCOLON } | ">>" { GTGT } | "<<" { LTLT } | "==>" { EQEQGT (!file, !line) } | "<==>" { LTEQEQGT (!file, !line) } | "const" { CONST (!file, !line) } | "readonly" { READONLY (!file, !line) } | "function" { FUNCTION (!file, !line) } | "returns" { RETURNS (!file, !line) } | "type" { TYPE (!file, !line) } | "axiom" { AXIOM (!file, !line) } | "procedure" { PROCEDURE (!file, !line) } | "implementation" { IMPLEMENTATION (!file, !line) } | "instruction" { INSTRUCTION (!file, !line) } | "requires" { REQUIRES (!file, !line) } | "ensures" { ENSURES (!file, !line) } | "modifies" { MODIFIES (!file, !line) } | "invariant" { INVARIANT (!file, !line) } | "assume" { ASSUME (!file, !line) } | "assert" { ASSERT (!file, !line) } | "goto" { GOTO (!file, !line) } | "call" { CALL (!file, !line) } | "forall" { FORALL (!file, !line) } | "exists" { EXISTS (!file, !line) } | "lambda" { LAMBDA (!file, !line) } | "old" { OLD } | "fun" { FUN } | "int" { INT } | "real" { REAL } | "bool" { BOOL } | "null" { NULL } | "true" { LITBOOL true } | "false" { LITBOOL false } | "is" { IS } | "let" { LET (!file, !line) } | "in" { IN } | "inout" { INOUT (!file, !line) } | "var" { VAR (!file, !line) } | "if" { IF (!file, !line) } | "then" { THEN (!file, !line) } | "else" { ELSE (!file, !line) } | "while" { WHILE (!file, !line) } | "return" { RETURN (!file, !line) } | "ireturn" { IRETURN (!file, !line) } | "Return" { RRETURN (!file, !line) } | "yield" { YIELD (!file, !line) } | "linear" { LINEAR } | ":split_here" { SPLIT } | "my" { MY } | "module" { MODULE (!file, !line) } | "interface" { INTERFACE (!file, !line) } | "import" { IMPORT (!file, !line) } | "atomic" { ATOMIC } | "stable" { STABLE } | "ghost" { GHOST } | "static" { STATIC (!file, !line) } (* | "eax" { EAX } | "ebx" { EBX } | "ecx" { ECX } | "edx" { EDX } | "esi" { ESI } | "edi" { EDI } | "ebp" { EBP } | "esp" { ESP } *) | "0x"['0'-'9''a'-'f''A'-'F']+ { let s = lexeme lexbuf in let s = String.sub s 2 (String.length s - 2) in let rec explode (n:int) s = if n = String.length s then [] else (String.get s n)::(explode (n+1) s) in let digits = List.map (Char.code << Char.lowercase) (explode 0 s) in let rec hex digits n = match digits with | [] -> n | h::t -> let d = if h >= (Char.code 'a') then h - (Char.code 'a') + 10 else h - (Char.code '0') in hex t (add_int_big_int d (mult_int_big_int 16 n)) in LITINT (hex digits zero_big_int) } | ['0'-'9']+ { LITINT (big_int_of_string(lexeme lexbuf)) } | ['0'-'9']+['.']['0'-'9']+ { LITREAL (lexeme lexbuf) } | ['0'-'9']+"bv32" { let s = lexeme lexbuf in LITBV32 (big_int_of_string(s.Substring(0, s.Length - 4))) } | ['_']*['A'-'Z']['#''_''a'-'z''A'-'Z''0'-'9']* { UID ((lexeme lexbuf)) } | ['_']*['a'-'z']['#''_''a'-'z''A'-'Z''0'-'9']* { LID ((lexeme lexbuf)) } | '?'['_']*['A'-'Z']['#''_''a'-'z''A'-'Z''0'-'9']* { QUID ((lexeme lexbuf)) } | '?'['_']*['a'-'z']['#''_''a'-'z''A'-'Z''0'-'9']* { QLID ((lexeme lexbuf)) } | '$'['_']*['A'-'Z']['#''_''a'-'z''A'-'Z''0'-'9']* { DUID ((lexeme lexbuf)) } | '$'['_']*['a'-'z']['#''_''a'-'z''A'-'Z''0'-'9']* { DLID ((lexeme lexbuf)) } | ['_']+['#''_''0'-'9']* { LID ((lexeme lexbuf)) } | eof { EOF } | '\000' { EOF } | _ { parse_err ("cannot parse character: \"" ^ (lexeme lexbuf) ^ "\"" ^ "\n(ascii code " ^ (string_of_int (Char.code (String.get (lexeme lexbuf) 0))) ^ ")") } ================================================ FILE: ironclad-apps/tools/Beat/main.fs ================================================ open Ast open Parse open Parse_util open Microsoft.FSharp.Compatibility.OCaml.Big_int;; exception LocErr of loc * exn let print_and_exit = ref false let print_nonghost_and_exit = ref false let Map_containsKey (x:'a) (m:Map<'a,'b>) = match m.TryFind x with None -> false | Some _ -> true let Map_ofList (l:('k * 'a) list):Map<'k,'a> = List.fold (fun m (k, a) -> Map.add k a m) Map.empty l let Map_toList (m:Map<'k,'a>):('k * 'a) list = Map.fold (fun k a l -> (k, a)::l) m [] let Map_cardinal (m:Map<'k,'a>):int = List.length (Map_toList m) let Set_ofList (l:'a list):Set<'a> = List.fold (fun s a -> Set.add a s) Set.empty l let Set_toList (s:Set<'a>):'a list = Set.fold (fun l a -> a::l) [] s let Set_difference (s1:Set<'a>) (s2:Set<'a>) = Set.fold (fun s a -> Set.remove a s) s1 s2 exception InternalError of string let multi_add (k:'k) (a:'a) (m:Map<'k,'a list>) = match m.TryFind(k) with | None -> m.Add(k, [a]) | Some l -> m.Add(k, a::l) type env = { global_decls:Map; global_static_decls:Map; const_decls:Map; type_decls:Map; fun_decls:Map; proc_decls:Map; } let build_env decls:env = List.fold_left (fun env (l, decl) -> match decl with | BGlobalDecl (x, t, _, _) -> {env with global_decls = env.global_decls.Add(x, t)} | BGlobalStaticDecl (x, mem) -> {env with global_static_decls = env.global_static_decls.Add(x, mem)} | BConstDecl (x, t, e) -> {env with const_decls = env.const_decls.Add(x, (t, e))} | BTypeDecl (x, t) -> {env with type_decls = env.type_decls.Add(x, t)} | BFunDecl ((x, _, _, _, _, _) as d) -> {env with fun_decls = env.fun_decls.Add(x, (l, d))} | BProcDecl ((x, _, _, _, _, _) as d) when not (Map_containsKey x env.proc_decls) -> {env with proc_decls = env.proc_decls.Add(x, (l, d))} | BProcDecl ((x, _, _, _, _, _) as d) -> env | _ -> env) {global_decls = Map.empty; global_static_decls = Map.empty; const_decls = Map.empty; type_decls = Map.empty; fun_decls = Map.empty; proc_decls = Map.empty; } decls let extra_proc_invariants = ref (Map.empty:Map) let extra_proc_modifies = ref (Map.empty:Map) let find_constructor (env:env) (xt:id) (xc:id):(linearity * bpformal list) = match Map.tryFind xt env.type_decls with | None -> err ("cannot find declaration of type " + xt) | Some None -> err ("cannot find case " + xc + " in type " + xt) | Some (Some (_, cases)) -> ( let cases = List.map (fun (lin, x, fs) -> (x, (lin, fs))) cases in if not (List.mem_assoc xc cases) then err ("cannot find case " + xc + " in type " + xt) else List.assoc xc cases ) let static_addr (x:id):id = "?ADDR__" + x (*****************************************************************************) let rec map_exp (f:bexp -> bexp option) (e:bexp):bexp = match (f e) with | Some e -> e | None -> ( let r = map_exp f in match e with | BLoc (l, e) -> BLoc (l, r e) | BVar x -> BVar x | BIntConst _ -> e | BRealConst _ -> e | BBv32 _ -> e | BBoolConst _ -> e | BUop (op, e) -> BUop (op, r e) | BBop (op, e1, e2) -> BBop (op, r e1, r e2) | BQuant (q, fs, ts, e) -> BQuant (q, fs, List.map (List.map r) ts, r e) | BSubscript (e, es) -> BSubscript (r e, List.map r es) | BUpdate (e, es, ee) -> BUpdate (r e, List.map r es, r ee) | BApply (x, es) -> BApply (x, List.map r es) | BCond (e1, e2, e3) -> BCond (r e1, r e2, r e3) ) let rec map_stmt (fe:bexp -> bexp) (fs:bstmt -> bstmt option) (l:loc, s:bstmt):(loc * bstmt) = match fs s with | Some s -> (l, s) | None -> ( match s with | BLocalDecl (x, t, lin, None) -> (l, s) | BLocalDecl (x, t, lin, Some e) -> (l, BLocalDecl (x, t, lin, Some (fe e))) | BLabel x -> (l, s) | BGoto x -> (l, s) | BAssign (x, e) -> (l, BAssign (x, fe e)) | BGroup b -> (l, BGroup (map_block fe fs b)) | BIf (e, b1, None) -> (l, BIf (fe e, map_block fe fs b1, None)) | BIf (e, b1, Some b2) -> (l, BIf (fe e, map_block fe fs b1, Some (map_block fe fs b2))) | BWhile (e, invs, b) -> (l, BWhile ( fe e, List.map (fun (l, e) -> (l, fe e)) invs, map_block fe fs b)) | BForallGhost (xs, ts, e, b) -> (l, BForallGhost (xs, List.map (List.map fe) ts, fe e, map_block fe fs b)) | BAssume e -> (l, BAssume (fe e)) | BAssert (e, inv) -> (l, BAssert (fe e, inv)) | BSplit -> (l, BSplit) | BYield e -> (l, BYield (fe e)) | BHavoc e -> (l, BHavoc (fe e)) | BCall (xs, f, es, pars) -> (l, BCall (xs, f, List.map (fe) es, List.map (fun (x, es) -> (x, List.map fe es)) pars)) | BReturn _ -> (l, s) ) and map_block (fe:bexp -> bexp) (fs:bstmt -> bstmt option) (b:bblock):bblock = List.map (map_stmt fe fs) b let map_spec (fe:bexp -> bexp) (l:loc, s:bspec):(loc * bspec) = match s with | BRequires e -> (l, BRequires (fe e)) | BEnsures e -> (l, BEnsures (fe e)) | BModifies es -> (l, BModifies (List.map fe es)) | BInOut _ -> (l, s) // TODO: make more robust? let rename_formal_funs (fs:bformal_fun list) (m:Map):(bformal_fun list * Map) = let m = List.fold (fun m (x, _, _) -> Map.add x (BVar (x + "__BEAT")) m) m fs in let fs = List.map (fun (x, t, e) -> (x + "__BEAT", t, e)) fs in (fs, m) let rename_formals (fs:bformal list) (m:Map):(bformal list * Map) = let (fs, m) = rename_formal_funs (List.map (fun (x, t) -> (x, t, None)) fs) m in (List.map (fun (x, t, _) -> (x, t)) fs, m) let subst_id (m:Map) (x:id):id = if (m.ContainsKey(x)) then match m.[x] with | BVar y -> y | _ -> err ("internal substitution error: " + x) else x let rec subst_exp (m:Map) (e:bexp):bexp = map_exp (fun e -> match e with | BVar x when m.ContainsKey(x) -> Some (m.[x]) | BQuant (q, fs, ts, e) -> let (fs, m) = rename_formals fs m in Some (BQuant (q, fs, List.map (List.map (subst_exp m)) ts, subst_exp m e)) | _ -> None) e let rec subst_stmt (m:Map) (l:loc, s:bstmt):(loc * bstmt) = map_stmt (subst_exp m) (fun s -> match s with | BAssign (x, e) -> Some (BAssign (subst_exp m x, subst_exp m e)) | BCall (xs, f, es, pars) -> Some (BCall (List.map (subst_exp m) xs, f, List.map (subst_exp m) es, List.map (fun (x, es) -> (x, List.map (subst_exp m) es)) pars)) | _ -> None) (l, s) let subst_block (m:Map) (b:bblock):bblock = List.map (subst_stmt m) b let subst_spec (m:Map) (l:loc, s:bspec):(loc * bspec) = map_spec (subst_exp m) (l, s) (*****************************************************************************) let regs_id = "r" let regs_arr = BUop (BField ("regs", None), BVar regs_id) let reg_efl = BUop (BField ("efl", None), BVar regs_id) let all_regs = ["eax"; "ebx"; "ecx"; "edx"; "esi"; "edi"; "esp"; "ebp"] let id_is_reg (x:id) = match x with "eax" | "ebx" | "ecx" | "edx" | "esi" | "edi" | "ebp" | "esp" -> true | _ -> false type procKind = PIns | PInline | PProc let proc_kind (x:id):procKind = let rec f i = match x.[i] with | '_' -> f (i + 1) | c when System.Char.IsLower(c) -> PInline | c when System.Char.IsUpper(c) -> PProc | _ -> err ("bad procedure name: " + x) in if x.StartsWith("instr_") then PIns else f 0 (* let get_op f = match f with | "Add" | "AddChecked" -> BAdd | "Sub" | "SubChecked" -> BSub | _ -> err ("unsupported memory operation: " + f) in *) let expand_deep_conjuncts = ref true; let rec list_of_conjuncts (env:env) (depth:int) ((fBase, lBase):loc) ((f, l):loc) (e:bexp):(loc * bexp) list = let lb = if lBase = l && fBase.EndsWith(f) then (fBase, lBase) else (fBase + "(" + (string lBase) + ") --> " + f, l) in match e with | (BApply ("&&&", [ee])) -> list_of_conjuncts env (depth + 1) (fBase, lBase) (f, l) ee | _ -> ( if depth = 0 then [(lb, e)] else let f0 = list_of_conjuncts env (depth - 0) lb in let f1 = list_of_conjuncts env (depth - 1) lb in match e with | BLoc (lAnd, BBop (BAnd, e1, e2)) -> (f0 lb e1) @ (f1 lAnd e2) | BApply (x, es) when env.fun_decls.ContainsKey(x) -> ( let (lf, (_, fs, _, ee, _, _)) = env.fun_decls.[x] in match ee with | None -> [(lb, e)] | Some ee -> let m = List.map2 (fun (x, _, _) e -> (x, e)) fs es in let s = new Map(m) f0 lf (subst_exp s ee) ) | BBop (BImply, e1, e2) when !expand_deep_conjuncts -> List.map (fun (l, e) -> (l, BBop (BImply, e1, e))) (f0 lb e2) | BCond (e1, e2, e3) when !expand_deep_conjuncts -> f0 lb (BLoc (lb, BBop (BAnd, BBop(BImply, e1, e2), BBop(BImply, BUop(BNot, e1), e3)))) | BQuant (q, fs, ts, e) when !expand_deep_conjuncts -> List.map (fun (l, e) -> (l, BQuant (q, fs, ts, e))) (f0 lb e) | _ -> [(lb, e)] ) let rec expand_conjuncts_stmt (env:env) (depth:int) (l:loc, s:bstmt):(loc * bstmt) list = let f = expand_conjuncts_block env depth in match s with | BIf (e, b1, b2) -> [(l, BIf (e, f b1, match b2 with None -> None | Some b2 -> Some (f b2)))] | BWhile (e, invs, b) -> let invs = List.flatten (List.map (fun (l, e) -> list_of_conjuncts env depth l l e) invs) in [(l, BWhile (e, invs, f b))] | BAssert (e, inv) -> List.map (fun (l, e) -> (l, BAssert (e, inv))) (list_of_conjuncts env depth l l e) | _ -> [(l, s)] and expand_conjuncts_block (env:env) (depth:int) (b:bblock):bblock = List.flatten (List.map (expand_conjuncts_stmt env depth) b) let expand_conjuncts_spec (env:env) (depth:int) (l:loc, s:bspec):(loc * bspec) list = match s with | BRequires e -> List.map (fun (l, e) -> (l, BRequires e)) (list_of_conjuncts env depth l l e) | BEnsures e -> List.map (fun (l, e) -> (l, BEnsures e)) (list_of_conjuncts env depth l l e) | _ -> [(l, s)] let expand_conjuncts_decl (env:env) (depth:int) (l:loc, d:bdecl):(loc * bdecl) = match d with | BProcDecl (x, ps, rets, specs, b, p) -> (l, BProcDecl (x, ps, rets, List.flatten (List.map (expand_conjuncts_spec env depth) specs), (match b with None -> None | Some b -> Some (expand_conjuncts_block env depth b)), p)) | _-> (l, d) let expand_conjuncts_decls (env:env) (depth:int) = List.map (expand_conjuncts_decl env depth) (* let expand_apply_decl (env:env) (l:loc, d:bdecl):(loc * bdecl) = let rec fe e = match e with | BApply (x, es) when x.StartsWith("&") && x.Length > 1 -> ( match Map.tryFind (x.Substring(1)) env.fun_decls with | Some (_, (_, fs, _, Some ef, _, _)) -> let m = List.map2 (fun (xf, _, _) ea -> (xf, ea)) fs es in Some (BApply ("&", [map_exp fe (subst_exp (Map_ofList m) ef)])) | _ -> err ("could not find definition for function instantiation " + x) ) | _ -> None in match d with | BProcDecl (x, ps, rets, specs, b, p) -> (l, BProcDecl (x, ps, rets, (List.map (map_spec (map_exp fe)) specs), (match b with None -> None | Some b -> Some (map_block (map_exp fe) (fun s -> None) b)), p)) | _-> (l, d) let expand_apply_decls (env:env) = List.map (expand_apply_decl env) *) (*****************************************************************************) let rec sep_list (sep:string) (l:string list) = match l with | [] -> "" | [x] -> x | h::t -> h + sep + (sep_list sep t) let rec string_of_btyp t = match t with | BInt -> "int" | BBool -> "bool" | BReal -> "real" | BArray (ts, t) -> "[" + (sep_list "," (List.map string_of_btyp ts)) + "]" + (string_of_btyp t) | BNamedType x -> x let string_of_buop op = match op with | BNot -> "!" | BNeg -> "-" | BOld -> "old" | _ -> "<<>>" let string_of_bbop op = match op with | BEquiv -> "<==>" | BImply -> "==>" | BAnd -> "&&" | BOr -> "||" | BEq -> "==" | BNe -> "!=" | BLt -> "<" | BGt -> ">" | BLe -> "<=" | BGe -> ">=" | BAdd -> "+" | BSub -> "-" | BMul -> "*" | BDiv -> " div " | BMod -> " mod " | BRealDiv -> " / " | BAddChecked -> "$+" | BSubChecked -> "$-" | _ -> "<<>>" let string_of_bquant q = match q with | BForall -> "forall" | BExists -> "exists" | BLambda -> "lambda" let string_of_linearity (l:linearity) = match l with | Lin (LinVar, LinOur) -> "linear " | Lin (LinVar, LinMy) -> "my " | Lin (LinConst, LinOur) -> "const linear " | Lin (LinConst, LinMy) -> "const my " | Lin (LinInOut, LinOur) -> "inout linear " | Lin (LinInOut, LinMy) -> "inout my " | Non -> "" let string_of_bformal (x, t) = x + ":" + (string_of_btyp t) let string_of_bpformal (x, t, lin) = (string_of_linearity lin) + x + ":" + (string_of_btyp t) let string_of_bformal_fun (x, t, _) = x + ":" + (string_of_btyp t) let string_of_bformal_var (x, t) = match t with | BFormalType t -> x + ":" + (string_of_btyp t) | BFormalAlias t -> ("<<>>") let string_of_bpformal_var (x, t, lin) = (string_of_linearity lin) + (string_of_bformal_var (x, t)) let prec_of_uop op = match op with | BNot -> 50 | BNeg -> 50 | BOld -> 99 | _ -> 99 let prec_of_bop op = match op with | BEquiv -> 10 | BImply -> 10 | BAnd -> 15 | BOr -> 15 | BEq -> 20 | BNe -> 20 | BLt -> 20 | BGt -> 20 | BLe -> 20 | BGe -> 20 | BAdd -> 30 | BSub -> 30 | BAddChecked -> 30 | BSubChecked -> 30 | BMul -> 35 | BDiv -> 35 | BMod -> 35 | BRealDiv -> 35 | _ -> 99 let can_eval_op op = match op with | BAdd | BSub | BMul | BDiv -> true | _ -> false //-evaluates integers only let eval_op op (i1:bigint) (i2:bigint) = match op with | BAdd -> i1 + i2 | BSub -> i1 - i2 | BMul -> i1 * i2 | BDiv -> i1 / i2 | _ -> raise (InternalError("eval_op does not expect this operator")) //-evaluates integer constants only let rec eval_constants_in_bexp e = match e with | BBop (op, e1, e2) when (can_eval_op op) -> let e1' = eval_constants_in_bexp e1 in let e2' = eval_constants_in_bexp e2 in (match e1', e2' with //do not reduce 0-1 etc | (BIntConst i1), (BIntConst i2) when not (i1 = 0I && op = BSub) -> BIntConst (eval_op op i1 i2) | _ -> BBop(op, e1', e2') ) | _ -> e let rec multiline_string_of_bexp (multiline:bool) (prec:int) (e:bexp):string = let string_of_bexp = multiline_string_of_bexp multiline in let e' = eval_constants_in_bexp e in let loc_string (f, i) = "/*LOC*//*LOC:" + f + "," + (string i) + "*/" in let bbop s op e1 e2 = let ep = prec_of_bop op in let (epLeft, epRight) = match op with | BAdd | BSub | BMul | BDiv | BMod | BRealDiv | BAddChecked | BSubChecked -> (ep, ep + 1) | _ -> (ep + 1, ep + 1) ((string_of_bexp epLeft e1) + s + (string_of_bbop op) + (string_of_bexp epRight e2), ep) let (s, ePrec) = match e' with | BVar x -> (x, 99) | BIntConst i -> (string i, 99) | BRealConst r -> (r, 99) | BBv32 i -> ((string i) + "bv32", 99) | BBoolConst true -> ("true", 99) | BBoolConst false -> ("false", 99) | BUop (BField (x, Some (_, xc, BFieldNative)), e) -> (x + "#" + xc + "(" + (string_of_bexp 5 e) + ")", 99) | BUop (BField (x, Some (_, xc, BFieldFun)), e) -> (xc + "__" + x + "(" + (string_of_bexp 5 e) + ")", 99) | BUop (BField (x, _), e) -> ("(" + (string_of_bexp 5 e) + "." + x + ")", 99) | BUop (BNeg, e) -> ("(-" + (string_of_bexp ((prec_of_uop BNot) + 1) e) + ")", 99) | BUop (BIs x, e) -> ("(" + (string_of_bexp 5 e) + " is " + x + ")", 99) | BUop (op, e) -> let ep = prec_of_uop op in ((string_of_buop op) + (string_of_bexp (ep + 1) e), ep) | BBop (BFieldUpdate (xf, Some xc), e1, e2) -> (xc + "_update__" + xf + "(" + (string_of_bexp 5 e1) + "," + (string_of_bexp 5 e2) + ")", 99) | BBop (BFieldUpdate (xf, None), e1, e2) -> ("<<>>", 99) | BLoc (l, (BBop (op, e1, e2))) when multiline -> bbop (loc_string l) op e1 e2 | BBop (op, e1, e2) -> bbop "" op e1 e2 | BQuant (q, fs, ts, e) -> ( (string_of_bquant q) + " " + (sep_list "," (List.map string_of_bformal fs)) + "::" + (sep_list "" (List.map (fun t -> "{"+ (sep_list "," (List.map (string_of_bexp 5) t)) + "}") ts)) + (string_of_bexp 6 e), (-5) ) | BSubscript (e, es) -> ((string_of_bexp 90 e) + "[" + (sep_list "," (List.map (string_of_bexp 5) es)) + "]", 40) | BUpdate (e, es, ee) -> ((string_of_bexp 90 e) + "[" + (sep_list "," (List.map (string_of_bexp 90) es)) + ":=" + (string_of_bexp 90 ee) + "]", 40) | BApply ("&&&", [ee]) -> (string_of_bexp prec ee, prec) | BApply ("static", [emem; BApply (x, _)]) -> (string_of_bexp prec (BSubscript (BUop (BField ("map", Some ("mem", "mem", BFieldNative)), emem), [BVar (static_addr x)])), prec) | BApply (x, es) -> (x + "(" + (sep_list "," (List.map (string_of_bexp 5) es)) + ")", 90) | BCond (e1, e2, e3) -> ("if " + (string_of_bexp 90 e1) + " then " + (string_of_bexp 90 e2) + " else " + (string_of_bexp 90 e3), 0) | BLoc (l, e) when multiline -> (loc_string l + (string_of_bexp prec e), 0) | BLoc ((f, i), e) -> (string_of_bexp prec e, 0) in if prec <= ePrec then s else "(" + s + ")" type print_state = { print_out:System.IO.TextWriter; indent:string; cur_loc:loc ref; } member this.PrintLine (s:string) = if s.Trim() = "" && (!print_and_exit || !print_nonghost_and_exit) then () else let ss = s.Split ([|"/*LOC*/"|], System.StringSplitOptions.None) in this.print_out.Write (this.indent) let newline () = let (f, i) = !this.cur_loc in (this.cur_loc := (f, i + 1)); this.print_out.WriteLine () in for s in ss do ( if s.StartsWith("/*LOC:") then let i1 = "/*LOC:".Length in let i2 = s.IndexOf(",") in let i3 = i2 + (",".Length) in let i4 = s.IndexOf("*/") in let i5 = i4 + ("*/".Length) in let f = s.Substring(i1, i2 - i1) in let i = System.Int32.Parse(s.Substring(i3, i4 - i3)) in let rest = s.Substring(i5) in let (cf, ci) = !this.cur_loc in if f = cf && i <= ci then this.print_out.Write (rest) else newline (); this.SetLoc (f, i); this.print_out.Write (" " + rest) else this.print_out.Write (s) ); newline () member this.SetLoc (((f, i) as l):loc) = if (!print_and_exit || !print_nonghost_and_exit) then this.cur_loc := l else let (cf, ci) as cl = !this.cur_loc in if l = cl then () else if f <> cf || i < ci || i > ci + 8 then this.cur_loc := l; this.print_out.WriteLine ("#line " + (string i) + " " + f) else this.PrintLine ""; this.SetLoc l let rec print_bstmt (state:print_state) (l:loc, s) = let () = state.SetLoc l in let p:(string -> unit) = state.PrintLine in let string_of_bexp = multiline_string_of_bexp true let fcall x es = x + "(" + (sep_list "," (List.map (string_of_bexp 5) es)) + ")" in let fpars pars = String.concat "" (List.map (fun (x, es) -> " | " + fcall x es) pars) in match s with | BLocalDecl (x, t, lin, None) -> p ((string_of_linearity lin) + "var " + (string_of_bformal_var (x, t)) + ";") | BLocalDecl (x, t, lin, Some e) -> p ((string_of_linearity lin) + "var " + (string_of_bformal_var (x, t)) + "=" + (string_of_bexp 0 e) + ";") | BLabel x -> p (x + ":") | BGoto x -> p ("goto " + x + ";") | BAssign (x, e) -> p ((string_of_bexp (-5) x) + ":=" + (string_of_bexp 0 e) + ";") | BGroup b -> print_bblock_s state "{:" ":}" b | BIf (e, b1, b2) -> ( p ("if(" + (string_of_bexp 0 e) + ")"); print_bblock state b1; (match b2 with None -> () | Some b -> print_bblock state b) ) | BWhile (e, invs, b) -> ( p ("while(" + (string_of_bexp 0 e) + ")"); List.iter (fun (l:loc, e) -> state.SetLoc l; p ("invariant " + (string_of_bexp 0 e))) invs; print_bblock state b ) | BForallGhost (fs, ts, e, b) -> ( p ("forall " + (sep_list "," (List.map string_of_bformal fs)) + "::" + (sep_list "" (List.map (fun t -> "{" + (sep_list "," (List.map (string_of_bexp 5) t)) + "}") ts)) + (string_of_bexp 6 e)); print_bblock state b ) | BAssume e -> p ("assume " + (string_of_bexp 0 e) + ";") | BAssert (e, inv) -> p ((if inv then "invariant " else "assert ") + (string_of_bexp 0 e) + ";") | BSplit -> p ("assert {:split_here} true;") | BYield e -> p ("yield " + (string_of_bexp 0 e) + ";") | BHavoc e -> p ("havoc " + (string_of_bexp (-5) e) + ";") | BCall (xs, f, es, []) when f.StartsWith("construct##") -> let f = f.Substring("construct##".Length) in p ("let " + (sep_list "," (List.map (string_of_bexp (-5)) xs)) + ":=" + (fcall f es) + ";") | BCall (es, f, xs, []) when f.StartsWith("destruct##") -> let f = f.Substring("destruct##".Length) in p ("let " + (fcall f es) + ":=" + (sep_list "," (List.map (string_of_bexp (-5)) xs)) + ";") | BCall ([], f, es, pars) -> p ("call " + (fcall f es) + (fpars pars) + ";") | BCall (xs, f, es, pars) -> p ("call " + (sep_list "," (List.map (string_of_bexp (-5)) xs)) + ":=" + (fcall f es) + (fpars pars) + ";") | BReturn BRet -> p "return;" | BReturn BIRet -> p "ireturn;" | BReturn BEmbellishRet -> p "Return;" and print_bblock (state:print_state) b = print_bblock_s state "{" "}" b and print_bblock_s (state:print_state) sl sr b = state.PrintLine sl; List.iter (print_bstmt {state with indent = " " + state.indent}) b; state.PrintLine sr let print_bspec (state:print_state) (l:loc, s) = let () = state.SetLoc l in let p:(string -> unit) = state.PrintLine in let string_of_bexp = multiline_string_of_bexp true match s with | BRequires e -> p ("requires " + (string_of_bexp 0 e) + ";") | BEnsures e -> p ("ensures " + (string_of_bexp 0 e) + ";") | BModifies [] | BInOut [] -> () | BModifies es -> p ("modifies " + (sep_list "," (List.map (string_of_bexp (-99) ) es)) + ";") | BInOut fs -> p ("inout " + (sep_list "," (List.map string_of_bpformal fs)) + ";") let string_of_procimpl p = let gs g = match g with PReal -> "" | PGhost -> "ghost " in match p with | Procedure (g, Yields) -> (gs g) + "procedure" | Procedure (g, Atomic) -> "atomic " + (gs g) + "procedure" | Procedure (g, Stable) -> "stable " + (gs g) + "procedure" | Implementation -> "implementation" | Instruction -> "instruction" let string_of_readwrite rw = match rw with Readonly -> "readonly " | ReadWrite -> "" let print_bdecl (state:print_state) (l:loc, decl) = let () = state.SetLoc l in let p:(string -> unit) = state.PrintLine in let string_of_bexp = multiline_string_of_bexp true match decl with | BGlobalDecl (x, t, l, rw) -> p ((string_of_readwrite rw) + (string_of_linearity l) + "var " + x + ":" + (string_of_btyp t) + ";") | BGlobalStaticDecl (x, mem) -> p ("var " + x + " @ " + mem + ";") | BConstDecl (x, t, e_opt) -> let init = (match e_opt with None -> "" | Some e -> " := " + (string_of_bexp 0 e)) in p ("const " + x + ":" + (string_of_btyp t) + init + ";") | BStaticDecl x -> p ("static " + x + ";") | BAxiomDecl e -> p ("axiom " + (string_of_bexp 0 e) + ";") | BTypeDecl (x, None) -> p ("type " + x + ";") | BTypeDecl (x, Some (_, cs)) -> p ("type{:overload} " + x + " = " + (String.concat " | " (List.map (fun (lin, x, fs) -> (string_of_linearity lin) + x + "(" + (String.concat "," (List.map string_of_bpformal fs)) + ")") cs)) + ";") | BFunDecl (x, ps, t, e, a, ts_opt) -> ( let attr = match a with None -> "" | Some s -> "{" + s + "}" in let impl = match ts_opt with | None -> "" | Some ts -> " implementation" + (sep_list "" (List.map (fun t -> "{"+ (sep_list "," (List.map (string_of_bexp 5) t)) + "}") ts)) in let r = ":" + (string_of_btyp t) + (match e with None -> ";" | _ -> "") in p ("function" + attr + impl + " " + x + "(" + (sep_list "," (List.map string_of_bformal_fun ps)) + ")" + r); (match e with None -> () | Some e -> ( p ("{"); p (" " + (string_of_bexp 0 e)); p ("}") ) ) ) | BProcDecl (x, ps, rets, specs, b, pi) -> ( let r = (match rets with _::_ -> ("returns(" + (sep_list "," (List.map string_of_bpformal rets)) + ")") | _ -> "") in let semi = (match b with None -> ";" | _ -> "") in p ((string_of_procimpl pi) + " " + x + "(" + (sep_list "," (List.map string_of_bpformal_var ps)) + ")" + r + semi) List.iter (print_bspec state) specs; (match b with None -> () | Some b -> print_bblock state b) ) let print_module (state:print_state) (m:_module):unit = state.PrintLine ("module " + (if m.mIsImpl then "implementation" else "interface") + " " + m.mName); (if List.length m.mImports > 0 then state.PrintLine (" import " + (String.concat ", " (m.mImports)) + ";")); (if List.length m.mModifies > 0 then state.PrintLine (" modifies " + (String.concat ", " (m.mModifies)) + ";")); (if List.length m.mYields > 0 then state.PrintLine (" yield " + (String.concat ", " (m.mYields)) + ";")); //state.PrintLine "{"; // HACK: omit braces to enable file concatenation List.iter (print_bdecl state) m.mDecls; //state.PrintLine "}" let string_of_bexp = multiline_string_of_bexp false (*****************************************************************************) let expand_opaque_decl (l:loc, d:bdecl):(loc * bdecl) list = try ( match d with | BFunDecl (x, ps, t, Some e, Some a, None) when a = ":opaque" -> // function{:opaque} f(x:tx):tr { e } // ==> // function T___BEAT_f(x:tx):bool { true } // function f(x:tx):tr; // function implementation{T___BEAT_f(x)} f(x:tx):tr { e } // atomic ghost procedure reveal_f() ensures (forall x:tx::{f(x)} f(x) == e); // { forall x:t::{f(x)} f(x) == e {assert T___BEAT_f(x);} } let xtrig = "T___BEAT_" + x in let args = List.map (fun (xf, _, _) -> BVar xf) ps in let ps_bformal = List.map (fun (xf, tf, _) -> (xf, tf)) ps in let ftrig = BFunDecl (xtrig, ps, BBool, Some (BBoolConst true), None, None) in let fdecl = BFunDecl (x, ps, t, None, None, None) in let fimpl = BFunDecl (x, ps, t, Some e, None, Some [[BApply (xtrig, args)]]) in let fapp = BApply (x, args) in let eq = BBop (BEq, fapp, e) in let ens = BEnsures (BQuant (BForall, ps_bformal, [[fapp]], eq)) in let s_assert = BAssert (BApply (xtrig, args), false) in let s_forall = BForallGhost (ps_bformal, [[fapp]], eq, [(l, s_assert)]) in let pk = Procedure (PGhost, Atomic) in let preveal = BProcDecl ("reveal_" + x, [], [], [(l, ens)], Some [(l, s_forall)], pk) in [(l, ftrig); (l, fdecl); (l, fimpl); (l, preveal)] | _ -> [(l, d)] ) with e -> raise (LocErr (l, e)) let expand_opaque_decls ds = List.collect expand_opaque_decl ds (*****************************************************************************) type senv = Map //- map function name to function return type type cenv = Map //- map type name to constructor names and field names let do_compile = ref false let add_summary_env (decls:bdecl list) (senv:senv) (cenv:cenv):(senv * cenv) = List.fold (fun (senv, cenv) d -> match d with | BGlobalDecl (x, t, _, _) -> (Map.add x t senv, cenv) | BTypeDecl (xt, Some (_, cases)) -> ( let senv = List.fold (fun senv (_, xc, ps) -> let senv = Map.add ("##" + xc) (BNamedType xt) senv in List.fold (fun senv (xf, tf, _) -> Map.add (xf + "#" + xc) tf senv) senv ps) senv cases in let cenv = Map.add xt (List.map (fun (_, xc, ps) -> (xc, List.map (fun (xf, _, _) -> xf) ps)) cases) cenv in (senv, cenv) ) | BFunDecl (x, _, ret, _, _, _) -> (Map.add ("##" + x) ret senv, cenv) | _ -> (senv, cenv)) (senv, cenv) decls let summary_env (decls:bdecl list):(senv * cenv) = add_summary_env decls Map.empty Map.empty (*****************************************************************************) //- replace f with this.f for each f in this's datatype let expand_this_decl (cenv:cenv) (l:loc, d:bdecl):(loc * bdecl) = try ( let this_subst (t:btyp) = match t with | BNamedType xt -> ( match Map.tryFind xt cenv with | Some cs -> let fields = List.collect (fun (xc, fs) -> List.map (fun xf -> (xc, xf)) fs) cs in List.fold (fun m (xc, xf) -> Map.add xf (BUop (BField (xf, Some (xt, xc, BFieldNative)), BVar "this")) m) Map.empty fields | None -> err ("could not find fields of type " + xt) ) | _ -> err ("'this' parameter must be a datatype") in match d with | BFunDecl (xfun, ps, tret, Some e, a, ts) when List.exists (fun (x, _, _) -> x = "this") ps -> let (_, t, _) = List.find (fun (x, _, _) -> x = "this") ps in let e = subst_exp (this_subst t) e (l, BFunDecl (xfun, ps, tret, Some e, a, ts)) | BProcDecl (xp, ps, rs, specs, b_opt, pk) -> ( let var_ps = List.choose (fun (x, tf, _) -> match tf with BFormalType t -> Some (x, t) | _ -> None) ps in let inouts = List.collect (fun (_, s) -> match s with BInOut es -> es | _ -> []) specs in let var_rs = List.map (fun (x, t, _) -> (x, t)) (inouts @ rs) in let vars = var_ps @ var_rs in if (List.mem_assoc "this" vars) then let subst_map = this_subst (List.assoc "this" vars) in let specs = List.map (subst_spec subst_map) specs in let b_opt = match b_opt with None -> None | Some b -> Some (subst_block subst_map b) in (l, BProcDecl (xp, ps, rs, specs, b_opt, pk)) else (l, BProcDecl (xp, ps, rs, specs, b_opt, pk)) ) | _ -> (l, d) ) with e -> raise (LocErr (l, e)) let expand_this_decls (cenv:cenv) ds = List.map (expand_this_decl cenv) ds (*****************************************************************************) let rec expand_overload_exp (senv:senv) (cenv:cenv) (e:bexp):bexp = fst (expand_overload_exp_typ senv cenv e) and expand_overload_exp_typ (senv:senv) (cenv:cenv) (e:bexp):(bexp * btyp option) = let fe = expand_overload_exp senv cenv in let ft = expand_overload_exp_typ senv cenv in match e with | BLoc (l, e1) -> let (e1, t) = ft e1 in (BLoc (l, e1), t) | BVar x -> (e, Map.tryFind x senv) | BIntConst _ -> (e, None) | BRealConst _ -> (e, None) | BBv32 _ -> (e, None) | BBoolConst _ -> (e, None) // | BBitVectorConst _ -> (e, None) | BUop (BOld, e1) -> let (e1, t) = ft e1 in (BUop (BOld, e1), t) | BUop (BField (xf, _), e1) -> ( match ft e1 with | (e1, Some (BNamedType xt)) -> ( let app () = ( match (Map.tryFind ("##" + xt + "__" + xf) senv, Map.tryFind ("##." + xf) senv) with | (None, None) -> (BUop (BField (xf, None), e1), None) // unknown | (Some tr, None) -> (BUop (BField (xf, Some (xt, xt, BFieldFun)), e1), Some tr) | (_, Some tr) -> (BUop (BField (xf, Some (xt, xt, BFieldDotFun)), e1), Some tr) ) in match Map.tryFind xt cenv with | None -> app () | Some cases -> ( // record selector let fields = List.map (fun (xc, fs) -> List.map (fun xf -> (xc, xf)) fs) cases in let fields = List.flatten fields in match List.filter (fun (xc, _xf) -> xf = _xf) fields with | [(xc, _)] -> let selector = xf + "#" + xc in (BUop (BField (xf, Some (xt, xc, BFieldNative)), e1), Map.tryFind selector senv) | _ -> app () ) ) // | (BVar x1, None) -> ft (BVar (x1 + "#" + xf)) // module component | (e1, t) -> (BUop (BField (xf, None), e1), None) ) | BUop (op, e1) -> (BUop (op, fe e1), None) | BBop (BFieldUpdate (xf, _), e1, e2) -> ( match ft e1 with | (e1, Some ((BNamedType xt) as t)) -> ( match Map.tryFind xt cenv with | None -> err ("no type found for field update " + xf) | Some cases -> ( let fields = List.map (fun (xc, fs) -> List.map (fun xf -> (xc, xf)) fs) cases in let fields = List.flatten fields in match List.filter (fun (xc, _xf) -> xf = _xf) fields with | [(xc, _)] -> (BBop (BFieldUpdate (xf, Some xc), e1, fe e2), Some t) | _ -> err ("field " + xf + " not found in type " + xt) ) ) | _ -> err ("no type found for field update " + xf) ) | BBop (op, e1, e2) -> (BBop (op, fe e1, fe e2), None) | BCond (e1, e2, e3) -> let (e2, t) = ft e2 in (BCond (fe e1, e2, fe e3), t) | BQuant (q, xs, ts, ev) -> ( let senv = List.fold (fun senv (x, t) -> Map.add x t senv) senv xs in let fe = expand_overload_exp senv cenv in (BQuant (q, xs, List.map (List.map fe) ts, fe ev), None) ) | BSubscript (ea, es) -> ( match ft ea with | (ea, Some (BArray (_, t))) -> (BSubscript (ea, List.map fe es), Some t) | (ea, Some (BNamedType xt)) -> let (bf, t) = match (Map.tryFind ("map#" + xt) senv, Map.tryFind ("##" + xt + "__map") senv) with | (Some (BArray (_, t)), _) -> (BFieldNative, Some t) | (_, Some (BArray (_, t))) -> (BFieldFun, Some t) | _ -> (BFieldNative, None) in (BSubscript (BUop (BField ("map", Some (xt, xt, bf)), ea), List.map fe es), t) | (ea, _) -> (BSubscript (ea, List.map fe es), None) ) | BUpdate (ea, es, ev) -> ( match ft ea with | (ea, ((Some (BNamedType xt)) as t)) -> (BApply (xt + "_update", [ea] @ (List.map fe es) @ [fe ev]), t) | (ea, t) -> (BUpdate (ea, List.map fe es, fe ev), t) ) | BApply ("sizeof", [e1]) -> ( let (e1, t1_opt) = ft e1 in match t1_opt with | Some (BNamedType xt1) -> (BApply ("sizeof##" + xt1, [fe e1]), Some BInt) | _ -> err ("in sizeof, no datatype found for expression") ) | BApply (x, es) -> (BApply (x, List.map fe es), Map.tryFind ("##" + x) senv) let rec expand_overload_stmt (senv:senv) (cenv:cenv) (s:bstmt):bstmt = let fe = expand_overload_exp senv cenv in let fb = expand_overload_block senv cenv in let ft t = match t with BFormalAlias e -> BFormalAlias (fe e) | _ -> t in match s with | BLocalDecl (x, t, lin, None) -> BLocalDecl (x, ft t, lin, None) | BLocalDecl (x, t, lin, Some e) -> BLocalDecl (x, ft t, lin, Some (fe e)) | BLabel _ -> s | BGoto _ -> s | BAssign (x, e) -> BAssign (fe x, fe e) | BGroup b -> BGroup (fb b) | BIf (e, b1, b2_opt) -> BIf (fe e, fb b1, match b2_opt with None -> None | Some b2 -> Some (fb b2)) | BWhile (e, invs, b) -> BWhile (fe e, List.map (fun (l, e) -> (l, fe e)) invs, fb b) | BForallGhost (fs, ts, e, b) -> let senv = List.fold (fun senv (x, t) -> Map.add x t senv) senv fs in let fe = expand_overload_exp senv cenv in let fb = expand_overload_block senv cenv in BForallGhost (fs, List.map (List.map fe) ts, fe e, fb b) | BAssume e -> BAssume (fe e) | BAssert (e, inv) -> BAssert (fe e, inv) | BSplit -> BSplit | BYield e -> BYield (fe e) | BHavoc e -> BHavoc (fe e) | BCall (xs, id, es, pars) -> BCall (List.map fe xs, id, List.map fe es, List.map (fun (x, es) -> (x, List.map fe es)) pars) | BReturn _ -> s and expand_overload_block (senv:senv) (cenv:cenv) (b:bblock):bblock = let senv = List.fold (fun senv (l, s) -> try ( match s with BLocalDecl (x, BFormalType t, _, _) -> Map.add x t senv | _ -> senv ) with e -> raise (LocErr (l, e))) senv b in List.map (fun (l, s) -> (l, expand_overload_stmt senv cenv s)) b let expand_overload_spec (senv:senv) (senv_ret:senv) (cenv:cenv) ((l:loc), (s:bspec)):(loc * bspec) list = try ( match s with | BRequires e -> [(l, BRequires (expand_overload_exp senv cenv e))] | BEnsures e -> [(l, BEnsures (expand_overload_exp senv_ret cenv e))] | BModifies es -> [] | BInOut _ -> [] ) with e -> raise (LocErr (l, e)) type id_path = id list //- path is a list of ids: x.y.z = [x; y; z] let expand_overload_specs (proc:id) (env:env) (senv:senv) (senv_ret:senv) (cenv:cenv) (gmap:Map) (specs:(loc * bspec) list):(loc * bspec) list = let rec preserved_paths (get_children:id_path -> id list) (paths:id_path list):id_path list = //- given list of paths that do change, compute paths that don't change let indexed_paths = List.fold (fun m path -> match path with [] -> m | h::t -> multi_add h t m) Map.empty paths in let indexed_paths = Map_toList indexed_paths in let children = Set_ofList (get_children []) in let mod_children = Set_ofList (List.map fst indexed_paths) in let preserved_children = Set_toList (Set_difference children mod_children) in let preserved_child_paths = List.map (fun x -> [x]) preserved_children in let preserved_subpaths ((x:id), (subpaths:id_path list)) = if List.exists (fun p -> p = []) subpaths then [] else // "modifies x" ==> preserve nothing from x let g (p:id_path):id list = get_children (x::p) in List.map (fun p -> x::p) (preserved_paths g subpaths) in preserved_child_paths @ (List.collect preserved_subpaths indexed_paths) let modified_vars (paths:id_path list):id list = List.collect (fun path -> match path with [] -> [] | x::_ -> [x]) paths in let rec path_of_exp (e:bexp):id_path = match e with | BVar x -> [x] | BUop (BField (x, _), e) -> (path_of_exp e) @ [x] | BSubscript (e, [BVar x]) when id_is_reg (x.ToLower()) -> (path_of_exp e) @ ["[]" + x] | _ -> err ("unexpected modifies: " + (string_of_bexp 0 e)) let rec add_suffix (p:id_path) (e:bexp):bexp = match p with | [] -> e | x::xs when x.StartsWith("[]") -> add_suffix xs (BSubscript (e, [BVar (x.Substring("[]".Length))])) | x::xs -> add_suffix xs (BUop (BField (x, None), e)) in let get_children (p:id_path) = match p with | [] -> [] | x::xs -> ( let (_, t) = expand_overload_exp_typ senv cenv (add_suffix xs (BVar x)) in match t with | (Some (BArray ([BInt], BInt))) -> List.map (fun (r:string) -> "[]" + (r.ToUpper())) all_regs | (Some (BNamedType "regs")) -> ["regs"; "efl"] // REVIEW: should this be hard-wired? | (Some (BNamedType xt)) -> ( match Map.tryFind xt env.type_decls with | Some (Some ([], [(_, _, fs)])) -> List.map (fun (xf, _, _) -> xf) fs | Some (Some (fs, _)) -> fs | _ -> [] ) | _ -> [] ) in let mods = List.collect (fun (l, s) -> match s with BModifies es -> List.map (fun e -> (l, subst_exp gmap e)) es | _ -> []) specs in let (static_mods, mods) = List.partition (fun e -> match e with (_, BApply ("static", _)) -> true | _ -> false) mods in //- datatype variables: let locs_paths = List.map (fun (l, e) -> (l, path_of_exp e)) mods in let paths = List.map snd locs_paths in let loc_map = Map_ofList (List.map (fun (l, p) -> (List.hd p, l)) locs_paths) in let preserved = preserved_paths get_children paths in let mod_vars = Set_toList (Set_ofList (modified_vars paths)) in let modified = List.map (fun x -> (loc_map.[x], BModifies [BVar x])) mod_vars in let ensures_loc (ls:string, li) e = (ls + " (ensures " + (string_of_bexp 0 e) + "))", li) in let ensure p = match p with | [] -> err "internal error: expand_overload_specs" | x::xs -> let e = BBop (BEq, add_suffix xs (BVar x), add_suffix xs (BUop (BOld, BVar x))) in (ensures_loc (loc_map.[x]) e, expand_overload_exp senv cenv e) in let preserves = List.map ensure preserved in //- static variables: let static_mods = List.choose (fun (l, e) -> match e with (BApply ("static", [BVar mem; BApply (x, _)])) -> Some (mem, (l, x)) | _ -> None) static_mods in let static_mod_xs = Set_toList (Set_ofList (List.map fst static_mods)) in let static_mod_ls = List.map (fun mem -> (fst (List.assoc mem static_mods), mem)) static_mod_xs in let mod_vars = (List.map (fun (l, mem) -> mem) static_mod_ls) @ mod_vars in let modified = (List.map (fun (l, mem) -> (l, BModifies [BVar mem])) static_mod_ls) @ modified in let preserves_static = List.map (fun (l, mem) -> let xs = List.choose (fun (m, (_, x)) -> if m = mem then Some x else None) static_mods in let i = "i" in let mem_map = BUop (BField ("map", Some ("mem", "mem", BFieldNative)), BVar mem) in let mem_i = BSubscript (mem_map, [BVar i]) in let disjunct = List.fold_left (fun disjunct x -> BBop (BOr, disjunct, BBop (BEq, BVar i, BVar (static_addr x)))) (BBop (BEq, mem_i, BUop (BOld, mem_i))) xs in (l, BQuant (BForall, [(i, BInt)], [[mem_i]], disjunct))) static_mod_ls in //- put everything together: let preserves = preserves_static @ preserves in let ensured = List.map (fun (l, e) -> (l, BEnsures e)) preserves in (if List.length preserves > 0 then extra_proc_invariants := Map.add proc preserves !extra_proc_invariants); (if List.length mod_vars > 0 then extra_proc_modifies := Map.add proc mod_vars !extra_proc_modifies); modified @ ensured @ (List.collect (expand_overload_spec senv senv_ret cenv) specs) let expand_overload_decl (env:env) (senv:senv) (cenv:cenv) (gmap:Map) (d:bdecl):bdecl = match d with | BAxiomDecl e -> BAxiomDecl (expand_overload_exp senv cenv e) // | BInvariantDecl e -> BInvariantDecl (expand_overload_exp senv cenv e) | BFunDecl (id, ps, ret, Some e, a, ts) -> ( let senv = List.fold (fun senv (x, t, _) -> Map.add x t senv) senv ps in let f_ts ts = List.map (fun t -> List.map (expand_overload_exp senv cenv) t) ts in let ts = match ts with None -> None | Some ts -> Some (f_ts ts) in BFunDecl (id, ps, ret, Some (expand_overload_exp senv cenv e), a, ts) ) | BProcDecl (id, ps, rets, specs, b_opt, proc) -> ( let pspecs = match Map.tryFind id env.proc_decls with Some (_, (_, _, _, pspecs, _, _)) -> pspecs | None -> specs in let inouts = List.collect (fun (_, s) -> match s with BInOut io -> io | _ -> []) pspecs in let senv = List.fold (fun senv (x, t, _) -> Map.add x t senv) senv inouts in let senv = List.fold (fun senv (x, t, _) -> match t with BFormalType t -> Map.add x t senv | _ -> senv) senv ps in let senv_ret = List.fold (fun senv (x, t, _) -> Map.add x t senv) senv rets in let specs = expand_overload_specs id env senv senv_ret cenv gmap specs in let b_opt = match b_opt with None -> None | Some b -> Some (expand_overload_block senv_ret cenv b) in BProcDecl (id, ps, rets, specs, b_opt, proc) ) | d -> d (*****************************************************************************) let exp_get_smem (e:bexp):bexp option = match e with | BSubscript (BUop (BField ("map", Some ("mem", "mem", BFieldNative)), e), [eptr]) -> Some e | _ -> None let bcall xs p es = BCall (xs, p, es, []) let exp_get_mem (e:bexp):(bexp * (loc -> bblock) * (loc -> bexp -> bblock) * (loc -> id -> bblock) * (loc -> bexp -> bblock)) option = let stack_ptr eptr = let sload = fun l -> [] in let sstore = fun l e -> [] in let sLoad = fun l dest -> [(l, bcall [BVar dest] "SLoad" [eptr])] in let sStore = fun l e -> [(l, bcall [] "SStore" [eptr; e])] in Some (eptr, sload, sstore, sLoad, sStore) in let rec _datatype_ptr is_shared arr eptr = match arr with | BVar x -> ( let sload = fun l -> [] in let sstore = fun l e -> [] in let sLoad = fun l dest -> [(l, bcall [BVar dest] "Load" [arr; eptr])] in let sStore = fun l e -> [(l, bcall [] "Store" [BUop (BInOutOp, arr); eptr; e])] in (None, Some (eptr, sload, sstore, sLoad, sStore)) ) | _ -> (None, None) in let rec datatype_ptr is_shared arr eptr = let part_map_of e id = BSubscript (BUop (BField ("vars", Some ("partition", "partition", BFieldNative)), e), [id]) in let rec assign_rhs yt path eRead = match path with | [] -> BBop (BFieldUpdate ("part", Some yt), eRead, BVar "BEAT__partition") | (None, xf, xt, bf)::t -> let rhs = assign_rhs yt t (BUop (BField (xf, Some (xt, xt, bf)), eRead)) in BBop (BFieldUpdate (xf, Some xt), eRead, rhs) | (Some ei, xf, xt, bf)::t -> let ef = BUop (BField (xf, Some (xt, xt, bf)), eRead) in let rhs = assign_rhs yt t (BSubscript (ef, [ei])) in BBop (BFieldUpdate (xf, Some xt), eRead, BUpdate (ef, [ei], rhs)) in match arr with // REVIEW: should we automatically treat any global var x as shared? | BApply ("Shared", [edata]) -> datatype_ptr true edata eptr | BVar x when is_shared -> ( // call part_load(x__id, eptr); let id = BVar (x + "__id") in let lin = BVar "BEAT__linear" in let sload = fun l -> [(l, bcall [] "part_load" [id; eptr])] in let sstore = fun l e -> [ (l, BAssign (lin, id)); (l, bcall [lin] "part_store_shared" [lin; eptr; e]); (l, BAssign (id, lin))] in let sLoad = fun l dest -> (sload l) @ [(l, bcall [BVar dest] "Load" [eptr])] in let sStore = fun l e -> (sstore l e) @ [(l, bcall [] "Store" [eptr; e])] in (Some (part_map_of (BVar "$part") id, [(None, x, "", BFieldFun)]), Some (eptr, sload, sstore, sLoad, sStore)) ) | BVar x -> ( // call partition_load(x__id, my_part, $part.vars[me], eptr); // call part_load(me, eptr); let id = BVar (x + "__id") in let part = BVar "my_part" in let part_map = part_map_of (BVar "$part") (BVar "me") in let sload = fun l -> [ (l, bcall [] "partition_load" [id; part; part_map; eptr]); (l, bcall [] "part_load" [BVar "me"; eptr])] in let sstore = fun l e -> [(l, bcall [part] "partition_store" [id; part; part_map; eptr; e])] in let sLoad = fun l dest -> (sload l) @ [(l, bcall [BVar dest] "Load" [eptr])] in let sStore = fun l e -> (sstore l e) @ [(l, bcall [] "Store" [eptr; e])] in (Some (part_map_of part id, [(None, x, "", BFieldFun)]), Some (eptr, sload, sstore, sLoad, sStore)) ) | BUop (BField (xf, Some (xt, _, bf)), edata) -> ( match datatype_ptr is_shared edata eptr with | (Some (parent_map, path), Some (_, sload, sstore, sLoad, sStore)) -> // call partition_load(xt__xf__id, edata.part, parent_map, eptr); let id = BVar (xt + "__" + xf + "__id") in let part = BUop (BField ("part", Some (xt, xt, bf)), edata) in let root = let (_, x, _, _) = List.hd path in BVar x in let sload = fun l -> (l, bcall [] "partition_load" [id; part; parent_map; eptr])::(sload l) in let sstore = (fun l e -> (l, bcall [BVar "BEAT__partition"] "partition_store" [id; part; parent_map; eptr; e]):: (l, BAssign (root, assign_rhs xt (List.tl path) root)):: (sstore l e)) in let sLoad = fun l dest -> (sload l) @ [(l, bcall [BVar dest] "Load" [eptr])] in let sStore = fun l e -> (sstore l e) @ [(l, bcall [] "Store" [eptr; e])] in (Some (part_map_of part id, path @ [(None, xf, xt, bf)]), Some (eptr, sload, sstore, sLoad, sStore)) | _ -> (None, None) ) | BSubscript (BUop (BField ("map", Some (xt, _, bf)), edata), [ei]) -> ( match datatype_ptr is_shared edata eptr with | (Some (parent_map, path), Some (_, sload, sstore, sLoad, sStore)) -> // call partition_load(ei, edata.part, parent_map, eptr); let part = BUop (BField ("part", Some (xt, xt, bf)), edata) in let root = let (_, x, _, _) = List.hd path in BVar x in let sload = fun l -> (l, bcall [] "partition_load" [ei; part; parent_map; eptr])::(sload l) in let sstore = (fun l e -> (l, bcall [BVar "BEAT__partition"] "partition_store" [ei; part; parent_map; eptr; e]):: (l, BAssign (root, assign_rhs xt (List.tl path) root)):: (sstore l e)) in let sLoad = fun l dest -> (sload l) @ [(l, bcall [BVar dest] "Load" [eptr])] in let sStore = fun l e -> (sstore l e) @ [(l, bcall [] "Store" [eptr; e])] in (Some (part_map_of part ei, path @ [(Some ei, "map", xt, bf)]), Some (eptr, sload, sstore, sLoad, sStore)) | _ -> (None, None) ) | _ -> (None, None) in match e with | BSubscript (BUop (BField ("map", Some ("mem", _, BFieldNative)), edata), [eptr]) -> snd (_datatype_ptr false edata eptr) | BSubscript (BUop (BField ("map", Some ("finite_map", _, BFieldNative)), BUop (BField ("stk", Some ("mems", _, _)), BVar _)), [eptr]) -> stack_ptr eptr | BSubscript (BUop (BField ("map", Some ("finite_map", _, BFieldNative)), edata), [eptr]) -> snd (datatype_ptr false edata eptr) | BVar x when x.StartsWith("$beat__stackvar__") -> let x2 = x.Substring("$beat__stackvar__".Length) in let xi = x2.Substring(0, x2.IndexOf("_esp__")) in stack_ptr (BBop (BAdd, BVar "esp", BIntConst (big_int_of_string xi))) //correct, but slower: //let edata = BUop (BField ("stk", Some ("mems", BFieldFun)), BVar "$mem") in //let eptr = BBop (BAdd, BVar "esp", BIntConst (big_int_of_string xi)) in //snd (datatype_ptr false edata eptr) | BUop (BField (xf, Some (xt, _, BFieldFun)), e) -> let eptr = BVar (static_addr xf) in let id = BVar ("?Id" + xf) in let sload = fun l -> [(l, bcall [] ("loadInt_" + xt) [id; eptr])] in let sstore = fun l e -> [(l, bcall [] ("storeInt_" + xt) [id; eptr; e])] in let sLoad = fun l dest -> (sload l) @ [(l, bcall [BVar dest] "Load" [eptr])] in let sStore = fun l e -> (sstore l e) @ [(l, bcall [] "Store" [eptr; e])] in Some (eptr, sload, sstore, sLoad, sStore) | BApply ("static", [emem; BApply (x, _)]) -> let eptr = BVar (static_addr x) in let sload = fun l -> [] in let sstore = fun l e -> [] in let sLoad = fun l dest -> [(l, bcall [BVar dest] "Load" [emem; eptr])] in let sStore = fun l e -> [(l, bcall [] "Store" [emem; eptr; e])] in Some (eptr, sload, sstore, sLoad, sStore) | _ -> None let exp_is_reg (e:bexp) = match e with BVar x when id_is_reg x -> true | _ -> false // REVIEW: this may pull in non-const variables let exp_is_const (e:bexp) = match e with BIntConst _ -> true | BVar x when not (id_is_reg x) -> true | _ -> false let exp_is_mem (e:bexp) = match exp_get_mem e with Some _ -> true | None -> false let exp_is_reg_or_const (e:bexp) = (exp_is_reg e) || (exp_is_const e) let exp_is_reg_mem_or_const (e:bexp) = (exp_is_reg e) || (exp_is_const e) || (exp_is_mem e) let exps_for_x86_mem (e1:bexp) (e2:bexp):bool = ((exp_is_reg e1) && (exp_is_reg_mem_or_const e2)) || ((exp_is_reg e2) && (exp_is_reg_mem_or_const e1)) || ((exp_is_const e2) && (exp_is_reg_mem_or_const e1)) //let opn_of_exp (l:loc) (e:bexp):bexp * (loc * bstmt) list = // match exp_get_mem e with // | Some (eptr, mLoad, _, _, _) -> (BApply ("OpnMem", [eptr]), mLoad l) // | None -> (BApply ("OpnReg", [e]), []) let negate_comparison_op (op:bbop):bbop = match op with | BEq -> BNe | BNe -> BEq | BLt -> BGe | BGt -> BLe | BLe -> BGt | BGe -> BLt | _ -> err "conditional expression must be a comparison expression" let flip_comparison_op (op:bbop):bbop = match op with | BEq -> BEq | BNe -> BNe | BLt -> BGt | BGt -> BLt | BLe -> BGe | BGe -> BLe | _ -> err "conditional expression must be a comparison expression" let get_comparison_exp (polarity:bool) (e:bexp):(bbop * bexp * bexp) = let reorder (op, e1, e2) = let may_be_const e = match e with BIntConst _ -> true | BVar x when x.StartsWith("?") -> true | _ -> false in // HACK if may_be_const e2 || (exp_is_reg_or_const e2 && not (exp_is_const e1)) then (op, e1, e2) else (flip_comparison_op op, e2, e1) // move consts to right, memory ops to left in match (polarity, e) with | (true, BBop (op, e1, e2)) -> reorder (op, e1, e2) | (false, BBop (op, e1, e2)) -> reorder (negate_comparison_op op, e1, e2) | _ -> err "conditional expression must be a comparison expression" let new_label:unit->id = let nextLabel = ref 0 in fun () -> incr nextLabel; "__L" + (string !nextLabel) let add_local (locals:(id * (bformal_typ * linearity)) list ref) (x:id) (t:bformal_typ) (lin:linearity):unit = if not (List.mem_assoc x !locals) then locals := (x, (t, lin))::(!locals); (* let tmp_var (i:int):id = "__tmp" + (string i) let get_tmp_var (locals:(id * bformal_typ) list ref) (i:int):id = let x = tmp_var i in add_local locals x (BFormalType BInt); x *) let global_param_name (f:id) (p:id) = "__" + f + "$" + p let ghost_subst_map (ds:(loc * bdecl) list):Map = List.fold (fun m (l, d) -> match d with | BGlobalStaticDecl (x, mem) -> m.Add(x, BApply ("static", [BVar mem; BApply (x, [])])) | BFunDecl (x, _, _, Some e, _, _) when x.StartsWith("__Beat_") -> ( let x = x.Substring("__Beat_".Length) in if x.StartsWith("define_") then m.Add(x.Substring("define_".Length), e) else if x.StartsWith("defineD_") then m.Add("$" + x.Substring("defineD_".Length), e) else if x.StartsWith("defineQ_") then m.Add("?" + x.Substring("defineQ_".Length), e) else err ("unknown Beat definition: " + x) ) | _ -> m) (List.fold (fun m r -> m.Add(r, BSubscript(regs_arr, [BVar (r.ToUpper())]))) (Map.add "efl" (reg_efl) Map.empty) all_regs) ds let static_subst_map (ds:(loc * bdecl) list):Map = List.fold (fun m (l, d) -> match d with | BGlobalStaticDecl (x, mem) -> m.Add(x, BApply ("static", [BVar mem; BApply (x, [])])) | _ -> m) Map.empty ds let rec compile_exp (locals:(id * (bformal_typ * linearity)) list ref) (l:loc) (dest:id) (temp:int) (e:bexp):(loc * bstmt) list = let er () = err ("cannot compile assignment " + dest + " := " + (string_of_bexp 0 e) + " at line " + (string l)) in match e with | BLoc (l, e) -> compile_exp locals l dest temp e | BIntConst i -> [(l, BAssign (BVar dest, e))] | BBop (op, ((BVar x1) as e1), e2) when dest = x1 && exps_for_x86_mem e1 e2 -> ( match op with | BAdd -> [(l, bcall [BVar dest] "Add" [e1; e2])] | BSub -> [(l, bcall [BVar dest] "Sub" [e1; e2])] | BAddChecked -> [(l, bcall [BVar dest] "AddChecked" [e1; e2])] | BSubChecked -> [(l, bcall [BVar dest] "SubChecked" [e1; e2])] | _ -> er () ) | BBop (op, e1, e2) -> er () | _ -> ( match (e, exp_get_mem e) with | (_, Some (_, _, _, mLoad, _)) -> mLoad l dest | (BVar x, None) -> if dest = x then [] else [(l, BAssign (BVar dest, e))] | _ -> er () ) let compile_comparison (polarity:bool) (locals:(id * (bformal_typ * linearity)) list ref) (l:loc) (e:bexp):(bexp * (loc * bstmt) list) = let f op e1 e2 ss = let jop = match op with | BEq -> "Je" | BNe -> "Jne" | BLt -> "Jb" | BGt -> "Ja" | BLe -> "Jbe" | BGe -> "Jae" | _ -> err ("unsupported comparison at line " + (string l)) in // let ((o1, ss1), (o2, ss2)) = (opn_of_exp l e1, opn_of_exp l e2) in let is_stack = match e1 with BVar x when x.StartsWith("$beat__stackvar__") -> true | _ -> false in let cmp_ins = if exp_is_reg e1 then "Cmp" else if is_stack then "SCmpLoad" else "CmpLoad" in (BApply (jop, [BVar "efl"]), ss @ [(l, bcall [] cmp_ins [e1; e2])]) in let (op, e1, e2) = get_comparison_exp polarity e in if (exps_for_x86_mem e1 e2) then (f op e1 e2 []) else err ("unsupported comparison operands at line " + (string l)) let rec compile_stmt (env:env) (pk:proc_kind) (locals:(id * (bformal_typ * linearity)) list ref) (l:loc, s:bstmt):(loc * bstmt) list = try compile_stmt_inner env pk locals (l, s) with e -> raise (LocErr (l, e)) and compile_stmt_inner (env:env) (pk:proc_kind) (locals:(id * (bformal_typ * linearity)) list ref) (l:loc, s:bstmt):(loc * bstmt) list = let is_ghost = match pk with (Procedure (PGhost, _)) -> true | _ -> false in let dot_name xdata xf = xdata + "___BEAT_" + xf in let unpack unpacks xdata xt xc = if List.mem_assoc xdata !unpacks then () else let (_, fs) = find_constructor env xt xc in let xfs = List.map (fun (xf, _, _) -> BVar (dot_name xdata xf)) fs in let s1 = BCall (xfs, "destruct##" + xc, [BVar xdata], []) in let s2 = BCall ([BVar xdata], "construct##" + xc, xfs, []) in unpacks := (xdata, (s1, s2))::!unpacks; List.iter (fun (xf, t, lin) -> add_local locals (dot_name xdata xf) (BFormalType t) lin) fs in let rec inout_exp (unpacks:(id * (bstmt * bstmt)) list ref) (e:bexp):id = match e with | BVar x -> x | BUop (BField (xf, Some (xt, xc, _)), edata) -> ( let xdata = inout_exp unpacks edata in unpack unpacks xdata xt xc; dot_name xdata xf ) | BUop (BField (xf, None), _) -> err ("cannot determine type of field access " + xf + " in expression " + (string_of_bexp 0 e)) | _ -> err ("expected variable or field access in 'inout' argument") in let unpack_stmts unpacks = let ss1 = List.map (fun (_, (s1, _)) -> (l, s1)) (List.rev !unpacks) in let ss2 = List.map (fun (_, (_, s2)) -> (l, s2)) !unpacks in (ss1, ss2) match s with | BLocalDecl (x, t, lin, None) -> add_local locals x t lin; [] | BLocalDecl (x, t, lin, Some e) -> add_local locals x t lin; compile_stmt env pk locals (l, BAssign (BVar x, e)) | BLabel x -> [(l, s)] | BGoto x -> [(l, s)] | BAssign (BVar x, e) when not (id_is_reg x) -> [(l, s)] | BAssign (BVar x, e) -> ( let ss = compile_exp locals l x 0 e match ss with [(_, ((BCall _) as s))] -> compile_stmt env pk locals (l, s) | _ -> ss ) | BAssign ((BUop (BField (xf, Some (xt, xc, BFieldNative)), e1)) as lhs, e2) -> ( let (lin, _) = find_constructor env xt xc in match lin with | Non -> compile_stmt env pk locals (l, BAssign (e1, BBop (BFieldUpdate (xf, Some xt), e1, e2))) | Lin _ -> ( let unpacks = ref ([]:(id * (bstmt * bstmt)) list) in let xlhs = BVar (inout_exp unpacks lhs) in let (ss1, ss2) = unpack_stmts unpacks in ss1 @ [(l, BAssign (xlhs, e2))] @ ss2 ) ) | BAssign ((BUop (BField _, _)) as lhs, e) | BAssign ((BApply ("static", _)) as lhs, e) -> ( match exp_get_mem lhs with | Some (_, _, _, _, store) -> store l e | _ -> [(l, s)] ) | BAssign (BSubscript (x1, x2), e) -> compile_stmt env pk locals (l, BAssign (x1, BUpdate (x1, x2, e))) | BAssign (x, e) -> [(l, s)] | BGroup b -> [(l, BGroup (compile_block env pk locals b))] | BIf (BApply (_, [BVar "efl"]), [(lg, BGoto target)], None) -> [(l, s)] | BIf (e, [(lg, BGoto target)], None) -> ( let (eb, ss) = compile_comparison true locals l e in ( ss @ [(l, BIf (eb, [(lg, BGoto target)], None))] ) ) | BIf (e, b1, None) when is_ghost -> ( [(l, BIf (e, compile_block env pk locals b1, None))] ) | BIf (e, b1, Some b2) when is_ghost -> ( [ (l, BIf (e, compile_block env pk locals b1, None)); (l, BIf (BUop (BNot, e), compile_block env pk locals b2, None))] ) | BIf (e, b1, None) -> ( let (eb, ss) = compile_comparison false locals l e in let l1 = new_label () in ( ss @ [(l, BIf (eb, [(l, BGoto l1)], None))] @ (compile_block env pk locals b1) @ [(l, BLabel l1)] ) ) | BIf (e, b1, Some b2) -> ( let (eb, ss) = compile_comparison false locals l e in let l1 = new_label () in let l2 = new_label () in ( ss @ [(l, BIf (eb, [(l, BGoto l1)], None))] @ (compile_block env pk locals b1) @ [(l, BGoto l2)] @ [(l, BLabel l1)] @ (compile_block env pk locals b2) @ [(l, BLabel l2)] ) ) | BWhile (e, invs, b) -> ( let (eb, ss) = compile_comparison false locals l e in let l1 = new_label () in let l2 = new_label () in ( [(l, BLabel l1)] @ (List.map (fun (l, e) -> (l, BAssert (e, true))) invs) @ ss @ [(l, BIf (eb, [(l, BGoto l2)], None))] @ (compile_block env pk locals b) @ [(l, BGoto l1)] @ [(l, BLabel l2)] ) ) | BForallGhost (fs, ts, e, b) -> [(l, s)] | BAssume e -> [(l, s)] | BAssert (e, inv) -> [(l, s)] | BSplit -> [(l, s)] | BYield _ -> [(l, s)] | BHavoc e -> [(l, s)] (* | BCall ([x], p, [e1; (BUop (BField _, _)) as rhs]) when proc_kind p = PIns -> ( match exp_get_mem rhs with | Some (eptr, load, _, _, _) -> ( let call = BCall ([x], p + "Load", [e1; BApply ("OpnMem", [eptr])]) in (load l) @ [(l, call)] ) | _ -> [(l, s)] ) | BCall ([(BUop (BField _, _)) as lhs], p, [lhs2; e2]) when proc_kind p = PIns && lhs = lhs2 -> ( match exp_get_mem lhs with | Some (eptr, load, store, _, _) -> ( let e = BBop (get_op p, lhs, e2) in let call = BCall ([], p + "Store", [BApply ("OpnMem", [eptr]); e2]) in (load l) @ (store l e) @ [(l, call)] ) | _ -> [(l, s)] ) | BCall (xs, p, es, pars) -> // TODO: clean up or eliminate? if not (env.proc_decls.ContainsKey p) then [(l, BCall (xs, p, es, pars))] else let (_, (_, ps, rets, specs, b, _)) = env.proc_decls.[p] in let ps = List.filter (fun (_, t, _) -> match t with BFormalType _ -> true | _ -> false) ps in [(l, BCall (xs, p, es, pars))] *) | BCall (xs, p, es, pars) when env.proc_decls.ContainsKey(p) -> // call p(inout x.f) // ==> // linear var tmp_xf:tf // let tx(...,tmp_xf,...) := x; // call p(inout tmp_xf) // let x := tx(...,tmp_xf,...); let (_, (_, proc_fs, _, _, _, _)) = env.proc_decls.[p] in let unpacks = ref ([]:(id * (bstmt * bstmt)) list) in let arg proc_f e = match (proc_f, e) with | ((_, _, Lin (LinInOut, _)), BUop (BInOutOp, ei)) -> BUop (BInOutOp, BVar (inout_exp unpacks ei)) | ((x, _, _), BUop (BInOutOp, ei)) -> err ("inout argument passed to non-inout parameter " + x) | ((x, _, Lin (LinInOut, _)), _) -> err ("argument to inout parameter " + x + " must be marked inout") | ((_, _, Lin (LinConst, _)), _) -> BVar (inout_exp unpacks e) | _ -> e in let (n_proc_fs, n_es) = (List.length proc_fs, List.length es) in if n_proc_fs <> n_es then err ("proc: " + p + " expected " + (string n_proc_fs) + " arguments, found " + (string n_es)) else let es = List.map2 arg proc_fs es in let (ss1, ss2) = unpack_stmts unpacks in ss1 @ [(l, BCall (xs, p, es, pars))] @ ss2 | BCall (xs, p, es, pars) -> [(l, s)] | BReturn _ -> [(l, s)] and embellish_stmts (env:env) (b:bblock):bblock = let embellish = embellish_stmts env in let get_instruction p = match Map.tryFind p env.proc_decls with | Some (_, (_, ps, rets, specs, Some b, Instruction)) -> Some (ps, rets, specs, b) | _ -> None let build_instruction l xs p args = match get_instruction p with | Some (ps, rets, specs, b) -> ( if List.length args != List.length ps then err ("wrong number of arguments to " + p) else if List.length xs != List.length rets then err ("wrong number of return values from " + p) else let resultMap = List.collect (fun (_, s) -> match s with | BEnsures (BApply ("Output", [BVar x; e])) -> [(x, (false, e))] | BEnsures (BApply ("InputOutput", [BVar x; e])) -> [(x, (true, e))] | _ -> []) specs in let resultMap = Map_ofList resultMap in let substs = List.map2 (fun (x, ft, _) e -> let app f args = BApply (f, args) in let reg (r:string) = BVar (r.ToUpper()) in let (ft, e) = match (ft, exp_get_mem e) with | (BFormalType (BNamedType "opn"), Some (eptr, _, _, _, _)) | (BFormalType (BNamedType "opn_mem_of_int"), Some (eptr, _, _, _, _)) -> (BFormalType (BNamedType "opn_mem_of_int"), eptr) | _ -> (ft, e) in match (ft, e) with | (BFormalType (BNamedType "reg"), BVar r) when id_is_reg r -> (x, reg r) | (BFormalType (BNamedType "opn"), BVar r) when id_is_reg r -> (x, app "OReg" [reg r]) | (BFormalType (BNamedType "opn"), BVar xc) -> (x, app "OConst" [e]) | (BFormalType (BNamedType "opn"), BIntConst _ ) -> (x, app "OConst" [e]) | (BFormalType (BNamedType "opn_mem_of_int"), BBop (BAdd, BBop (BAdd, BVar r1, BBop (BMul, scale, BVar r2)), off)) when id_is_reg r1 && id_is_reg r2 -> (x, app "OMem" [app "MIndex" [reg r1; scale; reg r2; off]]) | (BFormalType (BNamedType "opn_mem_of_int"), BBop (BAdd, BVar r1, BBop (BMul, scale, BVar r2))) when id_is_reg r1 && id_is_reg r2 -> (x, app "OMem" [app "MIndex" [reg r1; scale; reg r2; BIntConst zero_big_int]]) | (BFormalType (BNamedType "opn_mem_of_int"), BBop (BAdd, BVar r1, BVar r2)) when id_is_reg r1 && id_is_reg r2 -> (x, app "OMem" [app "MIndex" [reg r1; BIntConst unit_big_int; reg r2; BIntConst zero_big_int]]) | (BFormalType (BNamedType "opn_mem_of_int"), BBop (BAdd, BVar r, off)) when id_is_reg r -> (x, app "OMem" [app "MReg" [reg r; off]]) | (BFormalType (BNamedType "opn_mem_of_int"), BVar r) when id_is_reg r -> (x, app "OMem" [app "MReg" [reg r; BIntConst zero_big_int]]) | (BFormalType (BNamedType "opn_mem_of_int"), BVar xc) -> (x, app "OMem" [app "MConst" [BVar xc]]) // TODO: more cases | _ -> (x, e)) (ps @ (List.map (fun (x, t, l) -> (x, BFormalType t, l)) rets)) (args @ xs) in let substs = Map_ofList substs in let coercions = List.map2 (fun (x, _, _) e -> match (Map.tryFind x resultMap, exp_get_mem e) with | (_, None) -> [] | (None, Some (_, sLoad, _, _, _)) -> sLoad l | (Some (false, ev), Some (_, _, sStore, _, _)) -> sStore l (subst_exp substs ev) | (Some (true, ev), Some (_, sLoad, sStore, _, _)) -> (sLoad l) @ (sStore l (subst_exp substs ev))) ps args in (List.flatten coercions) @ (List.map (fun (_, s) -> (l, s)) (subst_block substs b)) ) | None -> err ("Could not find instruction declaration for " + p) in let group_h l ss h t = (l, BGroup (ss @ [h]))::(embellish t) in match b with | [] -> [] | (l, BCall (xs, p, args, []))::t when not (get_instruction p = None) -> (build_instruction l xs p args) @ (embellish t) | ((l, BCall (_, x, _, _)) as h)::t when (proc_kind x = PProc) -> group_h l (build_instruction l [] "Call" []) h t | (l, BReturn BRet)::t -> group_h l (build_instruction l [] "Ret" []) (l, BReturn BRet) t | (l, BReturn BIRet)::t -> group_h l (build_instruction l [] "IRet" []) (l, BReturn BIRet) t | (l, BReturn BEmbellishRet)::t -> group_h l (build_instruction l [] "Ret" []) (l, BReturn BRet) t | (l, BAssign (BVar x, e))::t when (id_is_reg x) -> embellish ((l, bcall [BVar x] "Mov" [e])::t) | h::t -> h::(embellish t) and compile_block (env:env) (pk:proc_kind) (locals:(id * (bformal_typ * linearity)) list ref) (b:bblock):bblock = let b = List.flatten (List.map (compile_stmt env pk locals) b) in b let rec aliases_block (m:Map) (mptr:Map) (mInvs:(loc * bexp) list) (b:bblock):bblock = match b with | [] -> [] | (l, BLocalDecl (x, BFormalAlias (BVar y), _, None))::ss -> aliases_block (m.Add(x, BVar y)) mptr mInvs ss | (l, BLocalDecl (x, BFormalAlias (BVar y), _, Some e))::ss -> (l, BAssign (BVar y, subst_exp m e))::(aliases_block (m.Add(x, BVar y)) mptr mInvs ss) | (l, BLocalDecl (x, BFormalAlias y, lin, e_opt))::ss -> ( match (exp_get_mem y, exp_get_smem y) with | (Some ((BBop (BAdd, BVar "esp", BIntConst i)) as eptr, _, _, _, sStore), Some e_smem) -> ( let xx = "$beat__stackvar__" + (string i) + "_esp__" + x in let mm = m.Add(x, BVar xx) in let mptr = mptr.Add(x, y) in let mInvs = (l, BBop (BEq, BVar xx, y))::mInvs in let decl e = BLocalDecl (xx, BFormalType BInt, lin, Some e) in let ss = aliases_block mm mptr mInvs ss in match e_opt with | None -> (l, decl (BSubscript (BUop (BField ("map", Some ("mem", "mem", BFieldNative)), e_smem), [eptr])))::ss | Some e -> (l, decl e)::(subst_block m (sStore l e)) @ ss ) | _ -> err ("unexpected alias: " + x) ) | ((l, BAssign (BVar x, e)) as s)::ss when m.ContainsKey(x) -> ( match (m.[x], exp_get_mem m.[x]) with | (BVar y, Some (eptr, _, _, _, store)) -> let assign = (l, BAssign (BVar y, subst_exp m e)) in assign::(subst_block m (store l e)) @ (aliases_block m mptr mInvs ss) | _ -> (subst_stmt m s)::(aliases_block m mptr mInvs ss) ) (* | ((l, BCall ([x], f, [e1; BVar x2])) as s)::ss when proc_kind f = PIns && m.ContainsKey(x2) -> ( match (m.[x2], exp_get_mem m.[x2]) with | (BVar y, Some (eptr, load, _, _, _)) -> ( let call = BCall ([x], f + "Load", [subst_exp m e1; BApply ("OpnMem", [eptr])]) in (load l) @ (l, call)::(aliases_block m mptr mInvs ss) ) | _ -> (subst_stmt m s)::(aliases_block m mptr mInvs ss) ) | ((l, BCall ([BVar x], f, [BVar x1; e2])) as s)::ss when proc_kind f = PIns && m.ContainsKey(x) && x = x1 -> ( match (m.[x], exp_get_mem m.[x]) with | (BVar y, Some (eptr, load, store, _, _)) -> ( let e = subst_exp m (BBop (get_op f, BVar x1, e2)) in let call = BCall ([], f + "Store", [BApply ("OpnMem", [eptr]); subst_exp m e2]) in let assign = BAssign (BVar y, e) in (load l) @ (store l e) @ (l, call)::(l, assign)::(aliases_block m mptr mInvs ss) ) | _ -> (subst_stmt m s)::(aliases_block m mptr mInvs ss) ) *) | ((l, BCall ([BVar x], f, _, _)) as s)::ss when m.ContainsKey(x) -> ( match (m.[x], exp_get_mem m.[x]) with | (BVar y, Some (eptr, _, _, _, _)) -> ( let assign = BAssign (BVar y, mptr.[x]) in (subst_stmt m s)::(subst_stmt m (l, assign))::(aliases_block m mptr mInvs ss) ) | _ -> (subst_stmt m s)::(aliases_block m mptr mInvs ss) ) | (l, BIf (e, s1, None))::ss -> (l, BIf (subst_exp m e, aliases_block m mptr mInvs s1, None))::(aliases_block m mptr mInvs ss) | (l, BIf (e, s1, Some s2))::ss -> (l, BIf (subst_exp m e, aliases_block m mptr mInvs s1, Some (aliases_block m mptr mInvs s2))) ::(aliases_block m mptr mInvs ss) | (l, BWhile (e, invs, s))::ss -> let invs = List.map (fun (l, e) -> (l, subst_exp m e)) invs in (l, BWhile (subst_exp m e, mInvs @ invs, aliases_block m mptr mInvs s))::(aliases_block m mptr mInvs ss) | ((_, BLabel _) as s1)::((l, BAssert (_, true)) as s2)::ss -> (s1::(List.map (fun (l, e) -> (l, BAssert (e, true))) mInvs)) @ (aliases_block m mptr mInvs (s2::ss)) | s::ss -> (subst_stmt m s)::(aliases_block m mptr mInvs ss) //- Replace missing function arguments with defaults let fun_defaults_exp (env:env) (e:bexp):bexp = map_exp (fun e -> match e with | BApply (x, es) when env.fun_decls.ContainsKey(x) -> let (_, (_, ps, _, _, _, _)) = env.fun_decls.[x] in let arg_err s = err (s + "; expected: " + (sep_list ", " (List.map string_of_bformal_fun ps)) + " found: " + (sep_list ", " (List.map (string_of_bexp (-5)) es))) in let rec f ps es = match (ps, es) with | ([], []) -> [] | ([], _) -> arg_err ("too many arguments to " + x) | ((_, _, None)::_, []) -> arg_err ("missing arguments to " + x) | ((_, _, Some e)::ps, []) -> e::(f ps es) | (_::ps, e::es) -> e::(f ps es) in Some (BApply (x, f ps es)) | _ -> None) e let compile_decl (env:env) (gmap:Map) (static_map:Map) (modify:bexp list ref) (l:loc, d:bdecl):(loc * bdecl) list = try ( match d with | BGlobalDecl _ -> [(l, d)] | BGlobalStaticDecl (x, mem) -> [(l, BStaticDecl x)] | BStaticDecl _ -> [(l, d)] | BConstDecl (x, t, Some e) -> [(l, BConstDecl (x, t, Some (subst_exp gmap e)))] | BConstDecl _ -> [(l, d)] | BAxiomDecl e -> [(l, BAxiomDecl (subst_exp gmap e))] | BTypeDecl (xt, Some (_, cs)) -> ( let get (_, xc, fs) = List.map (fun (xf, tf, _) -> let x1 = "___x1" in let e = BUop (BField (xf, Some (xt, xc, BFieldNative)), BVar x1) in (l, BFunDecl (xc + "__" + xf, [(x1, BNamedType xt, None)], tf, Some e, None, None))) fs in let update (_, xc, fs) = List.map (fun (xf, tf, _) -> let x1 = "___x1" in let x2 = "___x2" in let args = List.map (fun (_xf, _, _) -> if xf = _xf then BVar x2 else BUop (BField (_xf, Some (xt, xc, BFieldNative)), BVar x1)) fs in let e = BApply (xc, args) in let t = BNamedType xt in (l, BFunDecl (xc + "_update__" + xf, [(x1, t, None); (x2, tf, None)], t, Some e, None, None))) fs in [(l, d)] @ (List.collect get cs) @ (List.collect update cs) ) | BTypeDecl _ -> [(l, d)] | BFunDecl (x, fs, t, e_opt, attrs, ts_opt) -> let (fs, gmap) = rename_formal_funs fs gmap in let subst e = subst_exp gmap (subst_exp static_map e) in let e_opt = match e_opt with None -> None | Some e -> Some (subst e) in let ts_opt = match ts_opt with None -> None | Some ts -> Some (List.map (List.map subst) ts) in [(l, BFunDecl (x, fs, t, e_opt, attrs, ts_opt))] | BProcDecl (x, ps, rets, specs, None, p) -> let specs = List.map (map_spec (fun_defaults_exp env)) specs in let specs = List.map (subst_spec gmap) specs in [(l, BProcDecl (x, ps, rets, specs, None, p))] | BProcDecl (x, ps, rets, specs, Some b, p) -> let (_, (_, _, _, _, _, pk)) = env.proc_decls.[x] in let is_ghost = match pk with (Procedure (PGhost, _)) -> true | _ -> false in let b = map_block (fun_defaults_exp env) (fun s -> None) b in let specs = List.map (map_spec (fun_defaults_exp env)) specs in let (gps_rev, aps_rev) = List.fold_left (fun (gps, aps) (x, t, lin) -> match t with | BFormalType _ -> ((x, t, lin)::gps, aps) | BFormalAlias (BVar t) -> (gps, (x, t, lin)::aps) | _ -> err ("non-register alias not supported: " + x)) ([], []) ps in let (gps, aps) = (List.rev gps_rev, List.rev aps_rev) in let m = new Map(List.map (fun (xp, xa, _) -> (xp, BVar xa)) aps) in let specs = List.map (subst_spec m) specs in let b = subst_block m b in let locals = ref ([]:(id * (bformal_typ * linearity)) list) in let invs = match Map.tryFind x !extra_proc_invariants with None -> [] | Some invs -> invs in let b = subst_block static_map b in let b = aliases_block Map.empty Map.empty invs b in let b = compile_block env pk locals b in let b = if is_ghost then b else embellish_stmts env b in let bLocals = !locals in let bLocals = List.map (fun (x, (t, lin)) -> (l, BLocalDecl (x, t, lin, None))) bLocals in let mSpec = (l, BModifies (!modify)) in let specs = List.map (subst_spec gmap) specs in let b = subst_block gmap b in [(l, BProcDecl (x, gps, rets, mSpec::specs, Some (bLocals @ b), p))] ) with e -> raise (LocErr (l, e)) let compile_decls (env:env) (gmap:Map) (static_map:Map) ds = List.collect (compile_decl env gmap static_map (ref ([]:bexp list))) ds (*****************************************************************************) // REVIEW: compared to inout parameters, this is a bit of a hack (more like dynamic scope) let expand_inout_decl (env:env) (l:loc, d:bdecl):(loc * bdecl) = // procedure p() inout x:t; requires r(x); ensures e(x, old(...x...)); // ==> procedure p(old__x) returns(x); requires r(old__x); ensures e(x, old(...old__x...)); // procedure p(inout x:t) requires r(x); ensures e(x, old(...x...)); // ==> procedure p(old__x) returns(x); requires r(old__x); ensures e(x, old(...old__x...)); try ( let does_modify xp specs x = (match Map.tryFind xp !extra_proc_modifies with None -> false | Some xs -> List.mem x xs) || List.exists (fun (_, d) -> match d with | BModifies es -> List.exists (fun e -> e = BVar x) es | _ -> false) specs in match d with | BProcDecl (xp, ps, rets, specs, b_opt, pk) when Map_containsKey xp env.proc_decls -> ( let old m x = if m then x + "__BEAT__old" else x in let (_, (_, _, _, pspecs, _, _)) = env.proc_decls.[xp] in let inouts = List.collect (fun (l, s) -> match s with BInOut io -> io | _ -> []) pspecs in let inouts_mod = List.map (fun (x, t, l) -> ((x, t, l), does_modify xp pspecs x)) inouts in let inouts_ret = List.choose (fun (f, m) -> if m then Some f else None) inouts_mod in let inouts_ps = List.map (fun ((x, t, lin), m) -> let lin = (match (m, lin) with (false, Lin (_, scope)) -> (Lin (LinConst, scope)) | _ -> lin) in (old m x, BFormalType t, lin)) inouts_mod in let ps_inouts = List.choose (fun (x, ft, l) -> match (l, ft) with (Lin (LinInOut, scope), BFormalType t) -> Some (x, t, Lin (LinVar, scope)) | _ -> None) ps in let ps_inouts_mod = List.map (fun p -> (p, true)) ps_inouts in let ps = List.map (fun (x, t, l) -> match l with Lin (LinInOut, scope) -> (old true x, t, Lin (LinVar, scope)) | _ -> (x, t, l)) ps in let ps = inouts_ps @ ps in let rets = inouts_ret @ ps_inouts @ rets in let oldMap = Map_ofList (List.map (fun ((x, _, _), m) -> (x, BVar (old m x))) (inouts_mod @ ps_inouts_mod)) in let fe = fun e -> match e with BUop (BOld, ee) -> Some (BUop (BOld, subst_exp oldMap ee)) | _ -> None in let fs = fun s -> match s with | BCall (rs, xc, args, pars) -> let io_rets = List.choose (fun ea -> match ea with BUop (BInOutOp, e) -> Some e | _ -> None) args in let rec fe_arg e = map_exp (fun ea -> match ea with BUop (BInOutOp, e) -> Some (fe_arg e) | _ -> None) e in let args = List.map fe_arg args in let rs = List.map fe_arg (io_rets @ rs) in let (rs, args) = if Map_containsKey xc env.proc_decls then let (_, (_, _, _, c_specs, _, _)) = env.proc_decls.[xc] in let c_inouts = List.collect (fun (_, s) -> match s with BInOut io -> io | _ -> []) c_specs in let xs = List.map (fun (x, _, _) -> x) c_inouts in let xs_ret = List.choose (fun (x, _, l) -> if does_modify xc c_specs x then Some x else None) c_inouts in let x2es = List.map (fun x -> BVar x) in (((x2es xs_ret) @ rs), ((x2es xs) @ args)) else (rs, args) in Some (BCall (List.map (map_exp fe) rs, xc, List.map (map_exp fe) args, List.map (fun (x, es) -> (x, List.map (map_exp fe) es)) pars)) | _ -> None let specs = List.collect (fun (l, d) -> match d with | BRequires e -> [(l, BRequires (subst_exp oldMap e))] | BEnsures e -> [(l, BEnsures (map_exp fe e))] | BModifies _ -> [(l, d)] | BInOut _ -> [] ) specs in let xinouts = List.map (fun (x, _, _) -> x) inouts in let fmod = List.filter (fun e -> match e with BVar x -> not (List.mem x xinouts) | _ -> true) in let specs = List.map (fun (l, d) -> (l, match d with BModifies xs -> BModifies (fmod xs) | _ -> d)) specs in let b_opt = match b_opt with | None -> None | Some b -> let rec f b = match b with | (l, ((BLocalDecl _) as s))::t -> (l, s)::(f t) | t -> (List.map (fun (x, _, _) -> (l, BAssign (BVar x, BVar (old true x)))) (inouts_ret @ ps_inouts)) @ t in Some (map_block (map_exp fe) fs (f b)) in // TODO: initialize x from old__x (l, BProcDecl (xp, ps, rets, specs, b_opt, pk)) ) | _ -> (l, d) ) with e -> raise (LocErr (l, e)) let expand_inout_decls (env:env) ds = List.map (expand_inout_decl env) ds (*****************************************************************************) let is_ghost_proc (env:env) (x:string):bool = match Map.tryFind x env.proc_decls with | Some (_, (_, _, _, _, _, Procedure (g, _))) -> g = PGhost | Some (_, (_, _, _, _, _, Instruction)) -> false | None when x.StartsWith("reveal_") -> true | _ -> err ("could not find declaration of procedure " + x) let rec remove_ghost_stmt (env:env) (xs:id list ref) (l:loc, s) = let rs = remove_ghost_stmt env xs in let rb = remove_ghost_block env xs in match s with | BLocalDecl (x, BFormalType _, lin, _) -> [] | BLocalDecl (x, BFormalAlias _, lin, _) -> xs := x::!xs; [(l, s)] | BLabel x -> [(l, s)] | BGoto x -> [(l, s)] | BAssign (BVar x, _) when List.mem x !xs -> [(l, s)] | BAssign (_, _) -> [] | BGroup b -> rb b | BIf (e, b1, None) -> [(l, BIf (e, rb b1, None))] | BIf (e, b1, Some b2) -> [(l, BIf (e, rb b1, Some (rb b2)))] | BWhile (e, invs, b) -> [(l, BWhile (e, [], rb b))] | BForallGhost (fs, ts, e, b) -> [] | BAssume e -> [] | BAssert (e, inv) -> [] | BSplit -> [] | BYield e -> [] | BHavoc e -> [] | BCall (_, f, _, []) when f.StartsWith("construct##") -> [] | BCall (_, f, _, []) when f.StartsWith("destruct##") -> [] | BCall (_, f, _, _) -> if is_ghost_proc env f then [] else [(l, s)] | BReturn _ -> [(l, s)] and remove_ghost_block (env:env) (xs:id list ref) b = List.collect (remove_ghost_stmt env xs) b let remove_ghost_decl (env:env) (l:loc, d:bdecl):(loc * bdecl) list = try ( match d with | BGlobalDecl _ -> [] | BGlobalStaticDecl _ -> [(l, d)] | BStaticDecl _ -> [(l, d)] | BConstDecl _ -> [] | BAxiomDecl _ -> [] | BTypeDecl _ -> [(l, d)] | BFunDecl _ -> [] | BProcDecl (x, fs, rs, _, b_opt, pk) -> if is_ghost_proc env x then [] else let xs = ref [] in let b_opt = match b_opt with None -> None | Some b -> Some (remove_ghost_block env xs b) in [(l, BProcDecl (x, fs, rs, [], b_opt, pk))] ) with e -> raise (LocErr (l, e)) let remove_ghost_decls (env:env) ds = List.collect (remove_ghost_decl env) ds (*****************************************************************************) let expand_depth = ref 0 let in_file = ref (None:string option) let include_files = ref ([]:string list) (* Each command-line argument is the name of a lemma *) let args = [ ("-expand" , Arg.Int (fun i -> expand_depth := i) , "Expand formula definitions (for better error messages)") ("-i" , Arg.String (fun s -> include_files := s::(!include_files)), "Include file") ("-in" , Arg.String (fun s -> in_file := Some s), "Input file") ("-def" , Arg.String (fun s -> Lex.macros := Map.add s [] !Lex.macros), "Define a macro (as an empty string) for use by ifdef/ifndef") ("-printAndExit", Arg.Set print_and_exit, "Pretty-print the input file and then exit") ("-printNonghostAndExit", Arg.Set print_nonghost_and_exit, "Pretty-print the input file, omitting ghost code, and then exit") ] let main (argv) = let print_error_loc (file, line) = print_endline ("error near line " + (string line) + " of file " + file) in let print_error_prefix () = print_error_loc (!file, !line) in let rec print_error e = match e with | LocErr (l, e) -> print_error_loc l; print_error e | Err s -> (print_endline "error:"; print_endline s; exit 1) | ParseErr x -> (print_error_prefix (); print_endline x; exit 1) | :? System.ArgumentException as x -> (print_error_prefix (); print_endline (x.ToString ()); exit 1) | Failure x -> (print_error_prefix (); print_endline x; exit 1) | x -> (print_endline (x.ToString ()); exit 1) try ( let cmd_args = System.Environment.GetCommandLineArgs () in Arg.parse_argv (ref 0) cmd_args args (fun _ -> ()) "error parsing arguments"; let lex_token = Lex.get_token Lex.token in let parse_file name = file := name; line := 1; Parse.start lex_token (Lexing.from_channel (open_in name)) in let includes = List.map parse_file (List.rev !include_files) in let includes = List.map (fun m -> m.mDecls) includes in let {mName = mName; mIsImpl = isImpl; mImports = imports; mModifies = modifies; mYields = yields; mDecls = p} = match !in_file with | None -> ( file := ""; line := 1; Parse.start lex_token (Lexing.from_channel stdin) ) | Some name -> ( file := name; line := 1; Parse.start lex_token (Lexing.from_channel (open_in name)) ) in let includes2 = List.flatten includes in if (!print_and_exit || !print_nonghost_and_exit) then let env = build_env (includes2 @ p) in let p = if !print_nonghost_and_exit then remove_ghost_decls env p else p in print_module { print_out = System.Console.Out; indent = ""; cur_loc = ref ("", 1); } {mName = mName; mIsImpl = isImpl; mImports = imports; mModifies = modifies; mYields = yields; mDecls = p}; else let includes2 = expand_opaque_decls includes2 in let env = build_env (includes2 @ p) in let gmap = ghost_subst_map (includes2 @ p) in let static_map = static_subst_map (includes2 @ p) in let (senv, cenv) = summary_env (List.map snd (includes2 @ p)) in let p = expand_this_decls cenv p in let p = expand_conjuncts_decls env 0 p in let _ = List.map (fun (l, d) -> try (l, expand_overload_decl env senv cenv gmap d) with e -> raise (LocErr (l, e))) includes2 in let p = List.map (fun (l, d) -> try (l, expand_overload_decl env senv cenv gmap d) with e -> raise (LocErr (l, e))) p in let p = compile_decls env gmap static_map p in let p = expand_opaque_decls p in let p = expand_inout_decls env p in let p = List.filter (fun (_, d) -> match d with BProcDecl (_, _, _, _, _, Instruction) -> false | _ -> true) p in print_module { print_out = System.Console.Out; indent = ""; cur_loc = ref ("", 1); } {mName = mName; mIsImpl = isImpl; mImports = imports; mModifies = modifies; mYields = yields; mDecls = p}; () (* print_program inlines p; *) ) with e -> print_error e ;; let () = main (System.Environment.GetCommandLineArgs ()) ================================================ FILE: ironclad-apps/tools/Beat/makefile ================================================ # # Copyright (c) 2007 Microsoft Corporation. All rights reserved. # BUILD = ..\fsharp FSC = $(BUILD)\fsc -g FSLEX = $(BUILD)\fslex FSYACC = $(BUILD)\fsyacc SRC = . BEAT_SOURCES = \ $(SRC)\ast.fs \ $(SRC)\parse_util.fs \ $(OBJ)\parse.fs \ $(OBJ)\lex.fs \ $(SRC)\main.fs \ beat: $(OBJ) $(BIN) $(BIN)\beat.exe $(OBJ): md $(OBJ) $(BIN): md $(BIN) $(OBJ)\lex.fsi $(OBJ)\lex.fs: $(OBJ) $(SRC)\lex.fsl $(FSLEX) $(SRC)\lex.fsl -o $(OBJ)\lex.fs $(OBJ)\parse.fsi $(OBJ)\parse.fs: $(OBJ) $(SRC)\parse.fsy $(FSYACC) -v $(SRC)\parse.fsy -o $(OBJ)\parse.fs $(BIN)\beat.exe: $(BEAT_SOURCES) $(FSC) --standalone --mlcompatibility -O $(BEAT_SOURCES) -o $(BIN)\beat.exe -r FSharp.PowerPack.dll ================================================ FILE: ironclad-apps/tools/Beat/makefile.fs ================================================ #light module MakeBeat open Def let env = Def.env.Cd @"tools\beat" let obj = Def.obj +/ @"beat" let bin = Def.bin +/ @"beat" env.Dep "all" <| [bin+/"beat.exe"] <| fun () -> () env.Dep obj <| [] <| fun () -> env.Mkdir obj env.Dep bin <| [] <| fun () -> env.Mkdir bin env.Fslex (obj+/"lex.fs") [obj] [] ["lex.fsl"] env.Fsyacc (obj+/"parse.fs") [obj] [] ["parse.fsy"] env.Fsc (bin+/"beat.exe") [bin] (split "--standalone --mlcompatibility -O -r FSharp.PowerPack.dll") ["ast.fs"; "parse_util.fs"; obj+/"parse.fs"; obj+/"lex.fs"; "main.fs"] ================================================ FILE: ironclad-apps/tools/Beat/nubuild-manifest.txt ================================================ dependency ast.fs dependency lex.fsl dependency main.fs dependency makefile dependency makefile.fs dependency parse.fsy dependency parse_util.fs output beat.exe ================================================ FILE: ironclad-apps/tools/Beat/parse.fsy ================================================ %{ open Ast;; open Parse_util;; open Microsoft.FSharp.Compatibility.OCaml.Big_int;; let rec type_id (t:btyp):id = match t with | BInt -> "int" | BBool -> "bool" | BReal -> "real" | BArray (t1s, t2) -> "__ARR1_" + (String.concat "_" (List.map type_id t1s)) + "__ARR2_" + (type_id t2) + "__ARR3_" | BNamedType x -> "__NAME_" + x let option_type_id (t:btyp):id = "__OPTION_" + (type_id t) %} %start start %type <_module> start %token UID %token LID %token DUID %token DLID %token QUID %token QLID %token IF THEN ELSE WHILE RETURN IRETURN RRETURN VAR LBRACE RBRACE SEMI %token LITINT %token LITREAL %token LITBV32 %token LITBOOL %token COLON %token LPAREN RPAREN LBRACKET RBRACKET %token LT GT BAR EQ BANG QUESTION COMMA RARROW LARROW LE GE NE %token PLUS MINUS STAR SLASH %token AMPAMP BARBAR LET LTEQEQGT EQEQGT EQEQ %token PLUSPLUS HASH CARET LTLT GTGT %token RLOL BACKSLASH AT DOLLAR DIV MOD SQUOTE BQUOTE %token REQARROW %token COLONEQ %token FUN %token UNDERSCORE %token DOT %token INT REAL BOOL %token NULL %token AMP AMPAMPAMP %token IS IN LINEAR SPLIT MY ATOMIC STABLE GHOST %token CONST READONLY FUNCTION RETURNS TYPE AXIOM PROCEDURE IMPLEMENTATION INSTRUCTION MODULE STATIC INTERFACE IMPORT %token REQUIRES ENSURES MODIFIES INVARIANT ASSUME ASSERT GOTO CALL INOUT YIELD %token FORALL EXISTS LAMBDA %token OLD COLONCOLON %token EAX EBX ECX EDX ESI EDI EBP ESP %token EOF /* Precedence declarations. */ %right AMPAMPAMP %right LET IN IF THEN ELSE %left LTEQEQGT %right EQEQGT %left AMPAMP BARBAR %left LT GT LE GE EQEQ NE IS %left PLUS MINUS %left STAR SLASH DIV MOD %right BANG %left LPAREN RPAREN LBRACKET RBRACKET DOT %% start: | MODULE INTERFACE AnyId Modifies Yields LBRACE Decls RBRACE EOF { {mName = $3; mIsImpl = false; mImports = []; mModifies = $4; mYields = $5; mDecls = $7} } | MODULE IMPLEMENTATION AnyId Imports LBRACE Decls RBRACE EOF { {mName = $3; mIsImpl = true; mImports = $4; mModifies = []; mYields = []; mDecls = $6} } | MODULE INTERFACE AnyId Modifies Yields Decls EOF { {mName = $3; mIsImpl = false; mImports = []; mModifies = $4; mYields = $5; mDecls = $6} } | MODULE IMPLEMENTATION AnyId Imports Decls EOF { {mName = $3; mIsImpl = true; mImports = $4; mModifies = []; mYields = []; mDecls = $5} } | Decls EOF { {mName = ""; mIsImpl = true; mImports = []; mModifies = []; mYields = []; mDecls = $1} } ID : LID { $1 } | UID { $1 } Type : INT { BInt } | BOOL { BBool } | REAL { BReal } | LBRACKET Types RBRACKET Type { BArray ($2, $4) } | AnyId { BNamedType $1 } | LTLT Type GTGT { BNamedType (option_type_id $2) } Types : Type { [$1] } | Type COMMA Types { $1::$3 } Triggers : { [] } | LBRACE Exps RBRACE Triggers { $2::$4 } Exp : LPAREN Exp RPAREN { $2 } | IF Exp THEN Exp ELSE Exp { BLoc ($1, BCond ($2, $4, $6)) } | LET Formal COLONEQ Exp IN Exp { BLoc ($1, BSubscript (BQuant (BLambda, [$2], [], $6), [$4])) } | Exp LTEQEQGT Exp { BLoc ($2, BBop (BEquiv, $1, $3)) } | Exp EQEQGT Exp { BLoc ($2, BBop (BImply, $1, $3)) } | Exp AMPAMP Exp { BLoc ($2, BBop (BAnd, $1, $3)) } /* TODO: this should match the Boogie grammar better */ | Exp BARBAR Exp { BLoc ($2, BBop (BOr, $1, $3)) } | Exp EQEQ Exp { BBop (BEq, $1, $3) } | Exp NE Exp { BBop (BNe, $1, $3) } | Exp LT Exp { BBop (BLt, $1, $3) } | Exp GT Exp { BBop (BGt, $1, $3) } | Exp LE Exp { BBop (BLe, $1, $3) } | Exp GE Exp { BBop (BGe, $1, $3) } | Exp PLUS Exp { BBop (BAdd, $1, $3) } | Exp MINUS Exp { BBop (BSub, $1, $3) } | Exp STAR Exp { BBop (BMul, $1, $3) } | Exp SLASH Exp { BBop (BRealDiv, $1, $3) } | Exp DIV Exp { BBop (BDiv, $1, $3) } | Exp MOD Exp { BBop (BMod, $1, $3) } | Exp IS AnyId { BUop (BIs $3, $1) } | LPAREN MINUS Exp RPAREN { BUop (BNeg, $3) } | BANG Exp { BUop (BNot, $2) } | LPAREN FORALL Formals COLONCOLON Triggers Exp RPAREN { BLoc ($2, BQuant (BForall, $3, $5, $6)) } | LPAREN EXISTS Formals COLONCOLON Triggers Exp RPAREN { BLoc ($2, BQuant (BExists, $3, $5, $6)) } | LPAREN LAMBDA Formals COLONCOLON Exp RPAREN { BLoc ($2, BQuant (BLambda, $3, [], $5)) } | Exp LBRACKET Exps RBRACKET { BSubscript ($1, $3) } | Exp LBRACKET Exps COLONEQ Exp RBRACKET { BUpdate ($1, $3, $5) } | Exp DOT AnyId { BUop (BField ($3, None), $1) } | Exp DOT LPAREN AnyId COLONEQ Exp RPAREN { BBop (BFieldUpdate ($4, None), $1, $6) } | LET LTLT Type GTGT Formal COLONEQ Exp IN Exp { let (x, tx) = $5 in let o = option_type_id $3 in let ox = option_type_id tx in BLoc ($1, BCond (BUop (BIs (ox + "_None"), $7), BApply (o + "_None", []), BSubscript (BQuant (BLambda, [$5], [], $9), [BUop (BField (ox + "_Value", None), $7)]))) } | LTLT Type GTGT LPAREN Exp RPAREN { let o = option_type_id $2 in BApply (o + "_Some", [$5]) } | LTLT Type GTGT LPAREN RPAREN { let o = option_type_id $2 in BApply (o + "_None", []) } | Exp DOT LTLT Type GTGT { let o = option_type_id $4 in BUop(BField (o + "_Value", None), $1) } | LITINT { BIntConst $1 } | LITREAL { BRealConst $1 } | LITBV32 { BBv32 $1 } | LITBOOL { BBoolConst $1 } | OLD LPAREN Exp RPAREN { BUop (BOld, $3) } | AnyId LPAREN Exps RPAREN { BApply ($1, $3) } | REAL LPAREN Exp RPAREN { BApply ("real", [$3]) } | INT LPAREN Exp RPAREN { BApply ("int", [$3]) } | AMP ID { BVar ("?ADDR__" + $2) } | AMPAMPAMP Exp { BApply ("&&&", [$2]) } | UID { BVar $1 } | LID { BVar $1 } | DUID { BVar $1 } | DLID { BVar $1 } | QUID { BVar $1 } | QLID { BVar $1 } Exps : { [] } | Exp { [$1] } | Exp COMMA Exps { $1::$3 } CallExp : Exp { $1 } | INOUT Exp { BUop (BInOutOp, $2) } CallExps : { [] } | CallExp { [$1] } | CallExp COMMA CallExps { $1::$3 } LhsExps : { [] } | AnyId { (BVar $1)::[] } | AnyId DOT AnyId { (BUop (BField ($3, None), BVar $1))::[] } | LPAREN Exp RPAREN { [$2] } | AnyId COMMA LhsExps { (BVar $1)::$3 } | AnyId DOT AnyId COMMA LhsExps { (BUop (BField ($3, None), BVar $1))::$5 } | LPAREN Exp RPAREN COMMA LhsExps { $2::$5 } AnyId : UID { $1 } | LID { $1 } | DUID { $1 } | DLID { $1 } | QUID { $1 } | QLID { $1 } | UNDERSCORE { "_" } AnyIds : { [] } | AnyId { [$1] } | AnyId COMMA AnyIds { $1::$3 } FunDeclId : AnyId { $1 } | DOT AnyId { "." ^ $2 } LoopInvs : { [] } | INVARIANT Exp SEMI LoopInvs { ($1, $2)::$4 } Linearity : { Non } | LINEAR { Lin (LinVar, LinOur) } | MY { Lin (LinVar, LinMy) } BFormalTyp : COLON Type { BFormalType $2 } | AT Exp { BFormalAlias $2 } ParCalls : { [] } | BAR LID LPAREN Exps RPAREN ParCalls { ($2, $4)::$6 } Stmt : ID COLON { ($2, BLabel $1) } | GOTO ID SEMI { ($1, BGoto $2) } | Linearity VAR AnyId BFormalTyp SEMI { ($2, BLocalDecl ($3, $4, $1, None)) } | Linearity VAR AnyId BFormalTyp COLONEQ Exp SEMI { ($2, BLocalDecl ($3, $4, $1, Some $6)) } | LBRACE COLON Stmts COLON RBRACE { ($2, BGroup $3) } | IF LPAREN Exp RPAREN Block { ($1, BIf ($3, $5, None)) } | IF LPAREN Exp RPAREN Block ELSE Block { ($1, BIf ($3, $5, Some $7)) } | WHILE LPAREN Exp RPAREN LoopInvs Block { ($1, BWhile ($3, $5, $6)) } | FORALL Formals COLONCOLON Triggers Exp Block { ($1, BForallGhost ($2, $4, $5, $6)) } | ASSUME Exp SEMI { ($1, BAssume $2) } | ASSERT Exp SEMI { ($1, BAssert ($2, false)) } | ASSERT LBRACE SPLIT RBRACE LITBOOL SEMI { ($1, if $5 then BSplit else parse_err "Must use: assert {:split_here} true;" ) } | YIELD Exp SEMI { ($1, BYield $2) } | INVARIANT Exp SEMI { ($1, BAssert ($2, true)) } | Exp COLONEQ Exp SEMI { ($2, BAssign ($1, $3)) } | LET AnyId COLONEQ AnyId LPAREN Exps RPAREN SEMI { ($3, BCall ([BVar $2], "construct##" ^ $4, $6, [])) } | LET AnyId LPAREN LhsExps RPAREN COLONEQ Exp SEMI { ($6, BCall ($4, "destruct##" ^ $2, [$7], [])) } | CALL AnyId LPAREN CallExps RPAREN ParCalls SEMI { ($1, BCall ([], $2, $4, $6)) } | CALL LhsExps COLONEQ AnyId LPAREN CallExps RPAREN ParCalls SEMI { ($1, BCall ($2, $4, $6, $8)) } | RETURN SEMI { ($1, BReturn BRet) } | IRETURN SEMI { ($1, BReturn BIRet) } | RRETURN SEMI { ($1, BReturn BEmbellishRet) } Stmts : { [] } | Stmt Stmts { $1::$2 } Block : LBRACE Stmts RBRACE { $2 } FormalVar : AnyId COLON Type { ($1, BFormalType $3, Non) } | LINEAR AnyId COLON Type { ($2, BFormalType $4, Lin (LinVar, LinOur)) } | MY AnyId COLON Type { ($2, BFormalType $4, Lin (LinVar, LinMy)) } | CONST LINEAR AnyId COLON Type { ($3, BFormalType $5, Lin (LinConst, LinOur)) } | CONST MY AnyId COLON Type { ($3, BFormalType $5, Lin (LinConst, LinMy)) } | INOUT LINEAR AnyId COLON Type { ($3, BFormalType $5, Lin (LinInOut, LinOur)) } | INOUT MY AnyId COLON Type { ($3, BFormalType $5, Lin (LinInOut, LinMy)) } | AnyId AT Exp { ($1, BFormalAlias $3, Non) } FormalVars : { [] } | FormalVar { [$1] } | FormalVar COMMA FormalVars { $1::$3 } Formal : AnyId COLON Type { ($1, $3) } Formals : { [] } | Formal { [$1] } | Formal COMMA Formals { $1::$3 } PFormal : AnyId COLON Type { ($1, $3, Non) } | LINEAR AnyId COLON Type { ($2, $4, Lin (LinVar, LinOur)) } | MY AnyId COLON Type { ($2, $4, Lin (LinVar, LinMy)) } PFormals : { [] } | PFormal { [$1] } | PFormal COMMA PFormals { $1::$3 } FormalFun : AnyId COLON Type { ($1, $3, None) } | AnyId COLON Type COLONEQ Exp { ($1, $3, Some $5) } FormalFuns : { [] } | FormalFun { [$1] } | FormalFun COMMA FormalFuns { $1::$3 } Spec : REQUIRES Exp SEMI { ($1, BRequires $2) } | ENSURES Exp SEMI { ($1, BEnsures $2) } | MODIFIES Exps SEMI { ($1, BModifies $2) } | INOUT PFormals SEMI { ($1, BInOut $2) } Specs : { [] } | Spec Specs { $1::$2 } Returns : { [] } | RETURNS LPAREN PFormals RPAREN { $3 } | RETURNS LPAREN PFormals RPAREN SEMI { $3 } TypeCase : AnyId LPAREN PFormals RPAREN { (Non, $1, $3) } | MY AnyId LPAREN PFormals RPAREN { (Lin (LinVar, LinMy), $2, $4) } | LINEAR AnyId LPAREN PFormals RPAREN { (Lin (LinVar, LinOur), $2, $4) } TypeCases : { [] } | TypeCase { [$1] } | TypeCase BAR TypeCases { $1::$3 } Attr : { None } | LBRACE COLON AnyId RBRACE { Some (":" + $3) } | LBRACE COLON AnyId LITBOOL RBRACE { Some (":" + $3 + " " + (if $4 then "true" else "false")) } GhostOpt: { PReal } | GHOST { PGhost } ProcKind : GhostOpt PROCEDURE { ($2, Procedure ($1, Yields)) } | ATOMIC GhostOpt PROCEDURE { ($3, Procedure ($2, Atomic)) } | STABLE GhostOpt PROCEDURE { ($3, Procedure ($2, Stable)) } | IMPLEMENTATION { ($1, Implementation) } | INSTRUCTION { ($1, Instruction) } FunRet : RETURNS LPAREN Type RPAREN { $3 } | RETURNS LPAREN AnyId COLON Type RPAREN { $5 } | COLON Type { $2 } Decl : Linearity VAR AnyId COLON Type SEMI { ($2, BGlobalDecl ($3, $5, $1, ReadWrite)) } | READONLY VAR AnyId COLON Type SEMI { ($2, BGlobalDecl ($3, $5, Non, Readonly)) } | Linearity VAR AnyId AT AnyId SEMI { ($2, BGlobalStaticDecl ($3, $5)) } | CONST AnyId COLON Type SEMI { ($1, BConstDecl ($2, $4, None)) } | CONST AnyId COLON Type COLONEQ Exp SEMI { ($1, BConstDecl ($2, $4, Some $6)) } | STATIC UID SEMI { ($1, BStaticDecl $2) } | ProcKind AnyId LPAREN FormalVars RPAREN SEMI Returns Specs { (fst $1, BProcDecl ($2, $4, $7, $8, None, snd $1)) } | ProcKind AnyId LPAREN FormalVars RPAREN Returns Specs { (fst $1, BProcDecl ($2, $4, $6, $7, None, snd $1)) } | ProcKind AnyId LPAREN FormalVars RPAREN Returns Specs Block { (fst $1, BProcDecl ($2, $4, $6, $7, Some $8, snd $1)) } | FUNCTION Attr FunDeclId LPAREN FormalFuns RPAREN FunRet LBRACE Exp RBRACE { ($1, BFunDecl ($3, $5, $7, Some $9, $2, None)) } | FUNCTION Attr FunDeclId LPAREN FormalFuns RPAREN FunRet SEMI { ($1, BFunDecl ($3, $5, $7, None, $2, None)) } | FUNCTION IMPLEMENTATION Triggers FunDeclId LPAREN FormalFuns RPAREN FunRet LBRACE Exp RBRACE { ($1, BFunDecl ($4, $6, $8, Some $10, None, Some $3)) } | TYPE AnyId SEMI { ($1, BTypeDecl ($2, None)) } | TYPE AnyId EQ TypeCases SEMI { ($1, BTypeDecl ($2, Some ([], $4))) } | LINEAR LPAREN AnyIds RPAREN TYPE AnyId EQ TypeCases SEMI { ($5, BTypeDecl ($6, Some ($3, $8))) } | TYPE LTLT Type GTGT SEMI { let o = option_type_id $3 in ($1, BTypeDecl (o, Some ([], [(Non, o + "_None", []); (Non, o + "_Some", [(o + "_Value", $3, Non)])]))) } | AXIOM Exp SEMI { ($1, BAxiomDecl $2) } Decls : { [] } | Decl Decls { $1::$2 } Modifies : { [] } | MODIFIES AnyIds SEMI Modifies { $2 @ $4 } Yields : { [] } | YIELD AnyIds SEMI Yields { $2 @ $4 } Imports : { [] } | IMPORT AnyIds SEMI Imports { $2 @ $4 } ================================================ FILE: ironclad-apps/tools/Beat/parse_util.fs ================================================ open Ast;; exception Err of string exception ParseErr of string let err (s:string):'a = raise (Err s) let parse_err (s:string):'a = raise (ParseErr s) let file = ref "";; let line = ref 1;; ================================================ FILE: ironclad-apps/tools/BoogieAsm/SymdiffMerge.cs ================================================ using System; using System.Collections.Generic; using System.IO; using System.Linq; //- Add custom mutual summaries to symdiff-generated bpl file (by changing mutual summary function bodies) //- Add custom mutual preconditions to symdiff-generated bpl files (by adding requires clauses to Check procedures) class SymdiffMerge { public static int Main(string[] args) { try { switch(args[0]) { case "-config": new SymdiffMerge().Config(args[1], args[2]); return 0; case "-merge": { string axiomWhitelist = (args.Length > 4 && args[3] == "-axiomWhitelist") ? args[4] : null; new SymdiffMerge().Merge(args[1], args[2], axiomWhitelist); return 0; } default: throw new Exception("unexpected argument " + args[0]); } } catch (Exception e) { Console.Error.WriteLine(e); return -1; } } Dictionary> preconditions = new Dictionary>(); Dictionary> postconditions = new Dictionary>(); Dictionary> postconditionVars = new Dictionary>(); const string funPrefix = "function {:inline true} "; public List FunVars(string line) { string parms = line.Substring(line.IndexOf('(') + 1); parms = parms.Substring(0, parms.IndexOf(')')); return new List(parms.Split(new char[] { ',' })) .ConvertAll(s => s.Substring(0, s.IndexOf(':')).Trim()); } public void ReadMutualSummaries(string msfile) { bool inFun = false; List data = null; foreach (string line in File.ReadAllLines(msfile)) { bool isPre = line.StartsWith(funPrefix + "MP$"); bool isPost = line.StartsWith(funPrefix + "MS$"); if (isPre || isPost) { inFun = true; data = new List(); string f = line.Substring(0, line.IndexOf('(')).Substring(funPrefix.Length); (isPre ? preconditions : postconditions).Add(f, data); if (!isPre) { postconditionVars.Add(f, FunVars(line)); } } if (inFun) { data.Add(line); } if (line.StartsWith("}")) { inFun = false; } } } public void Config(string msfile, string configfile) { ReadMutualSummaries(msfile); foreach (string line in File.ReadAllLines(configfile)) { if (line.StartsWith("procedure:")) { string name = line.Substring(line.IndexOf('(') + 1); name = name.Substring(0, name.IndexOf(')')); name = "MS$" + name.Replace(", ", "$"); if (postconditions.ContainsKey(name)) { Console.WriteLine(line); } } else { Console.WriteLine(line); } } } public void Merge(string msfile, string mergefile, string axiomWhitelistFile) { Dictionary axiomWhitelist = (axiomWhitelistFile == null) ? null : new List(File.ReadAllLines(axiomWhitelistFile)).ToDictionary(x => x); Dictionary alreadyPrintedAxiom = new Dictionary(); ReadMutualSummaries(msfile); bool inFun = false; foreach (string _line in File.ReadAllLines(mergefile)) { string line = _line; string lineTrim = line.Trim(); if (line.StartsWith(funPrefix + "MS$")) { //- Write mutual summary (mutual postcondition): inFun = true; string funPost = line.Substring(0, line.IndexOf('(')).Substring(funPrefix.Length); if (postconditions.ContainsKey(funPost)) { List symdiffVars = FunVars(line); List ourVars = postconditionVars[funPost]; string lambdasBegin = ""; string lambdasEnd = ""; foreach (string ourVar in ourVars) { if (ourVar.StartsWith("v1_u.out_") && !symdiffVars.Contains(ourVar)) { string x = ourVar.Substring("v1_u.out_".Length); if (line.Contains("v1_u.in_" + x + ":")) { if (line.Contains("v1_u.in_old_" + x + ":")) { line = line.Replace("v1_u.in_" + x + ":", "v1_u.out_" + x + ":"); line = line.Replace("v2_u.in_" + x + ":", "v2_u.out_" + x + ":"); line = line.Replace("v1_u.in_old_" + x + ":", "v1_u.in_" + x + ":"); line = line.Replace("v2_u.in_old_" + x + ":", "v2_u.in_" + x + ":"); } else { string decl = line.Substring(line.IndexOf("v1_u.in_" + x + ":")); decl = decl.Substring(0, decl.IndexOf(',')); string lb1 = "(lambda " + decl.Replace("v1_u.in_", "v1_u.out_") + "::("; string le1 = "))[" + "v1_u.in_" + x + "]"; string lb2 = lb1.Replace("v1_u.", "v2_u."); string le2 = le1.Replace("v1_u.", "v2_u."); lambdasBegin = lb1 + lb2 + lambdasBegin; lambdasEnd = lambdasEnd + le2 + le1; line = line.Replace("{:inline true}", ""); } } } } //- Write mutual summary body Console.WriteLine(line); List linesPost = postconditions[funPost]; for (int i = 1; i < linesPost.Count; i++) { if (linesPost[i] == "}" && lambdasEnd != "") { Console.WriteLine(lambdasEnd); } Console.WriteLine(linesPost[i]); if (linesPost[i] == "{" && lambdasBegin != "") { Console.WriteLine(lambdasBegin); } } } } // Avoid duplicate linear collectors until Boogie collector problem is fixed if (line.Contains("v1_u.OurCollector")) { line = line.Replace("{:linear \"our\"}", ""); } //- Try to improve performance by suppressing axioms that aren't needed bool suppressAxiom = axiomWhitelist != null && line.StartsWith("axiom ") && !axiomWhitelist.ContainsKey(line); suppressAxiom = suppressAxiom || alreadyPrintedAxiom.ContainsKey(line); if (!inFun && !suppressAxiom) { Console.WriteLine(line); if (line.StartsWith("axiom ")) { alreadyPrintedAxiom.Add(line, line); } } string constPrefix = "const v1_u."; if (lineTrim.StartsWith(constPrefix)) { string x = lineTrim.Substring(constPrefix.Length); x = x.Substring(0, x.IndexOf(':')); Console.WriteLine("axiom v1_u." + x + " == v2_u." + x + ";"); } string mpPrefix = "procedure MP_Check_"; string msPrefix = "procedure MS_Check_"; if (lineTrim.StartsWith(mpPrefix) || lineTrim.StartsWith(msPrefix)) { //- Write mutual precondition: bool isMp = lineTrim.StartsWith(mpPrefix); string funPost = lineTrim.Substring(0, lineTrim.IndexOf('(')); string s = lineTrim.Substring((isMp ? mpPrefix : msPrefix).Length); int v2i = s.IndexOf("v2_u."); int lparen = s.IndexOf('('); string v1 = s.Substring(0, v2i - 2); string v2 = s.Substring(v2i, lparen - v2i); string funPre = "MP$" + v1 + "$" + v2; if (preconditions.ContainsKey(funPre)) { Console.WriteLine(isMp ? " requires" : " free requires"); List linesPre = preconditions[funPre]; for (int i = 2; i < linesPre.Count - 1; i++) Console.WriteLine(" " + linesPre[i]); Console.WriteLine(" ;"); } } if (line.StartsWith("}")) { inFun = false; } } } } ================================================ FILE: ironclad-apps/tools/BoogieAsm/ast.fs ================================================ open Microsoft.FSharp.Math type loc = string * int type reg = string type id = string type attr = string type typ = | TInt | TBool | TReal | TName of id | TMap of typ * typ type lin_const = LinConst | LinVar type lin_scope = LinMy | LinOur type linearity = Lin of lin_const * lin_scope | Non type formal = id * typ type pformal = id * typ * linearity type op = | Bop of string | Uop of string | Subscript | Update | Cond type quant = Forall | Exists | Lambda type exp = | EVar of id | EInt of bigint | EReal of string | EBv32 of bigint | EBool of bool | EOp of op * exp list | EApply of id * exp list | EQuant of quant * formal list * exp list list * exp let eAdd (e1:exp) (e2:exp):exp = EOp (Bop "+", [e1; e2]) let eMul (e1:exp) (e2:exp):exp = EOp (Bop "*", [e1; e2]) type is_relation = IsRel | NotRel type is_invariant = IsInv of is_relation | NotInv type par_call = id * exp list type stmt = | SLabel of id | SGoto of id | SReturn | SIReturn | SYield of exp | SAssert of is_invariant * exp | SSplit | SAssign of id * exp | SIfJcc of id * id * id | SGroup of (loc * stmt) list | SIfGhost of exp * (loc * stmt) list | SForallGhost of formal list * exp list list * exp * formal list * (loc * stmt) list | SExistsGhost of formal list * exp list list * exp | SInline of id list * id * exp list * par_call list | SCall of id list * id * exp list type spec = | Requires of is_relation * exp | Ensures of is_relation * exp | Modifies of id list type proc_atomicity = Atomic | Yields | Stable type proc_ghost = PGhost | PReal type proc_kind = Procedure of proc_ghost * proc_atomicity | Implementation type inline_kind = Outline | Inline type fun_decl = id * formal list option * typ option * exp option * attr option * exp list list option type proc_decl = id * proc_kind * inline_kind * pformal list * pformal list * (loc * spec) list * (pformal list * (loc * stmt) list) option type readwrite = Readonly | ReadWrite type decl = | DType of id * bool * bool * (linearity * id * pformal list) list option | DStatic of id | DStaticGhost of id * typ * linearity * readwrite | DFunDecl of fun_decl | DProc of proc_decl type _module = {mName:id; mIsImpl:bool; mModifies:id list; mYields:id list; mDecls:(loc * decl) list} ================================================ FILE: ironclad-apps/tools/BoogieAsm/emit_bpl.fs ================================================ open Ast open Parse open Parse_util open Microsoft.FSharp.Math let symdiff = ref false let symdiff_allow = ref false let symdiff_lin_decls = ref (["me"]) // symdiff doesn't handle linear variables yet let symdiff_invariant = ref ("", (([]:string list), ([]:(string * string) list))) let symdiff_proc = ref ("", (fun loop -> "")) let symdiff_globals = ref ([]:pformal list) let symdiff_consts = ref ([]:string list) let symdiff_rets = ref ([]:string list) let symdiff_params = ref ([]:string list) let symdiff_locals = ref ([]:string list) let symdiff_writer = ref (null:System.IO.TextWriter) let symdiff_proc_mods = ref ([]:(string * pformal list) list) let symdiff_proc_local_clones = ref ([]:(string * int ref) list) let symdiff_proc_global_clones = ref ([]:(string * int ref) list) let symdiff_current_exp_scope = ref ([]:string list) let rec sep_list (sep:string) (l:string list) = match l with | [] -> "" | [x] -> x | h::t -> h + sep + (sep_list sep t) let rec string_of_typ (t:typ):string = match t with | TInt -> "int" | TBool -> "bool" | TReal -> "real" | TName x -> x | TMap (t1, t2) -> "[" + (string_of_typ t1) + "]" + (string_of_typ t2) let string_of_lin_param (l:linearity):string = match (!symdiff, l) with | (false, Lin (LinVar, LinOur)) -> "{:linear_in \"our\"}" | (false, Lin (LinConst, LinOur)) -> "{:linear \"our\"}" | (false, Lin (LinVar, LinMy)) -> "{:linear_in \"my\"}" | (false, Lin (LinConst, LinMy)) -> "{:linear \"my\"}" | _ -> "" let string_of_lin_var (l:linearity):string = match (!symdiff, l) with | (false, Lin (_, LinOur)) -> "{:linear \"our\"}" | (false, Lin (_, LinMy)) -> "{:linear \"my\"}" | _ -> "" let string_of_quant (q:quant):string = match q with Forall -> "forall" | Exists -> "exists" | Lambda -> "lambda" let string_of_formal ((x, t):formal) = x + ":" + (string_of_typ t) let string_of_pformal_param ((x, t, l):pformal) = (string_of_lin_param l) + x + ":" + (string_of_typ t) let string_of_pformal_var ((x, t, l):pformal) = (string_of_lin_var l) + x + ":" + (string_of_typ t) let string_of_formals (fs:formal list) = String.concat "," (List.map string_of_formal fs) let string_of_pformals_param (fs:pformal list) = String.concat "," (List.map string_of_pformal_param fs) let string_of_pformals_var (fs:pformal list) = String.concat "," (List.map string_of_pformal_var fs) type rel = NoRel | RelPre of bool | RelPost of bool type side = Outside | Left | Right let rec string_of_exp_r ((r:rel), (side:side)) (e:exp):string = let symdiff_nonglobal x = (List.mem x !symdiff_rets) || (List.mem x !symdiff_params) || (List.mem x !symdiff_locals) in let symdiff_const x = List.mem x !symdiff_consts in let pre loop n x = "v" + n + "_u." + ( if symdiff_nonglobal x then (if loop then "in_" else "") + x else if symdiff_const x then x else "" + x + "_old") in let post loop n x = "v" + n + "_u." + ( if symdiff_nonglobal x then (if loop then (if List.mem x !symdiff_params then "in_" else "out_") else "") + x else if symdiff_const x then x else "" + x + "_") let is_datatype_field (x:id) = x.Contains("#") && x.IndexOf('#') == x.LastIndexOf('#') in match (r, side, e) with | (_, _, EVar x) when List.mem x !symdiff_current_exp_scope -> "(" + x + ")" | ((RelPre _ | RelPost _), Outside, EVar x) -> err ("variable " + x + " must appear inside left or right expression") | (NoRel, _, EOp (Uop ("left" | "right"), _)) -> err ("'left' and 'right' can only be used inside a relation expression") | (_, (Outside | Left), EOp (Uop "left", [e0])) -> string_of_exp_r (r, Left) e0 | (_, (Outside | Right), EOp (Uop "right", [e0])) -> string_of_exp_r (r, Right) e0 | (_, (Left | Right), EOp (Uop ("left" | "right"), _)) -> err ("'left' appears inside 'right', or vice-versa") | (RelPre loop, Left, EVar x) -> "(" + (pre loop "1" x) + ")" | (RelPre loop, Right, EVar x) -> "(" + (pre loop "2" x) + ")" | (RelPost loop, Left, EVar x) -> "(" + (post loop "1" x) + ")" | (RelPost loop, Right, EVar x) -> "(" + (post loop "2" x) + ")" | (RelPost loop, Left, EOp (Uop "old", [EVar x])) -> "(v1_u." + x + "_old)" | (RelPost loop, Right, EOp (Uop "old", [EVar x])) -> "(v2_u." + x + "_old)" | ((RelPre _ | RelPost _), _, EApply (x, es)) when not (is_datatype_field x) -> "(v2_u." + x + "(" + (string_of_exps (r, side) es) + "))" | _ -> string_of_exp_norel (r, side) e and string_of_exp_norel (r:rel * side) (e:exp):string = let s = match e with | EVar x -> x | EInt i -> string i | EReal r -> r | EBv32 i -> (string i) + "bv32" | EBool true -> "true" | EBool false -> "false" | EOp (Bop op, [e1; e2]) -> (string_of_exp_r r e1) + op + (string_of_exp_r r e2) | EOp (Uop "relation", _) -> err "'relation' and 'public' can only be used around an entire 'requires', 'ensures', or 'invariant'" | EOp (Uop ("left" | "right"), _) -> err "internal error: left/right" | EOp (Uop op, [e1]) -> op + (string_of_exp_r r e1) | EOp (Subscript, [e1; e2]) -> (string_of_exp_r r e1) + "[" + (string_of_exp_r r e2) + "]" | EOp (Update, [e1; e2; e3]) -> (string_of_exp_r r e1) + "[" + (string_of_exp_r r e2) + ":=" + (string_of_exp_r r e3) + "]" | EOp (Cond, [e1; e2; e3]) -> "if " + (string_of_exp_r r e1) + " then " + (string_of_exp_r r e2) + " else " + (string_of_exp_r r e3) | EOp _ -> err "internal error: EOp" | EApply (x, es) -> x + "(" + (string_of_exps r es) + ")" | EQuant (_, [], _, e) -> string_of_exp_r r e | EQuant (q, fs, ts, e) -> ( let save_scope = !symdiff_current_exp_scope in symdiff_current_exp_scope := (List.map fst fs) @ !symdiff_current_exp_scope; let rhs = (string_of_triggers r ts) + (string_of_exp_r r e) in symdiff_current_exp_scope := save_scope; (string_of_quant q) + " " + (string_of_formals fs) + "::" + rhs ) in "(" + s + ")" and string_of_exps (r:rel * side) (es:exp list):string = String.concat "," (List.map (string_of_exp_r r) es) and string_of_trigger (r:rel * side) (t:exp list):string = "{" + (string_of_exps r t) + "}" and string_of_triggers (r:rel * side) (ts:exp list list):string = String.concat "" (List.map (string_of_trigger r) ts) let string_of_exp = string_of_exp_r (NoRel, Outside) let string_of_exp_ignore_rel (r:is_relation) (e:exp):string = match r with IsRel -> "true" | NotRel -> string_of_exp e let string_of_outs (xs:id list):string = match xs with [] -> "" | _ -> (String.concat "," xs) + " := " let dummyCounter = ref 0; let string_of_stmt (s:stmt):string = match s with | SLabel l -> l + ":" | SGoto l -> "goto " + l + ";" | SGroup _ -> "" | SIfJcc (x, cond, l) -> "call boogie_CheckJcc(me, RET, " + x + "); if (" + cond + "(.efl(" + x + "))) { goto " + l + "; }" | SIfGhost (e, b) -> "if (" + (string_of_exp e) + ")" | SForallGhost _ -> "if (*)" | SExistsGhost _ -> "if (*)" | SAssert (NotInv, e) -> "assert " + (string_of_exp e) + ";" | SAssert (IsInv r, e) -> "assert " + (string_of_exp_ignore_rel r e) + ";" | SSplit -> "assert {:split_here} true;" | SYield e -> incr dummyCounter; "yield; assert " + (string_of_exp e) + "; #DUMMY_LABEL" + (string !dummyCounter) + ":" | SAssign (x, e) -> x + " := " + (string_of_exp e) + ";" | SInline (xs, p, es, pars) -> let f x es = x + "(" + (String.concat "," ("me"::"RET"::(List.map (string_of_exp) es))) + ")" in "call " + (string_of_outs xs) + (f p es) + (String.concat "" (List.map (fun (x, es) -> " | " + f x es) pars)) + ";" | SCall (xs, p, es) -> let xr = List.hd xs in "call boogie_CheckCall(me, RET, " + xr + "); " + "call " + (string_of_outs xs) + p + "(" + (String.concat "," ("me"::"ReturnToCaller(" + xr + ")"::(List.map (string_of_exp) es))) + ");" | SReturn -> "return;" | SIReturn -> "return;" let string_of_spec (s:spec):string = match s with | Requires (r, e) -> "requires " + (string_of_exp_ignore_rel r e) + ";" | Ensures (r, e) -> "ensures " + (string_of_exp_ignore_rel r e) + ";" | Modifies xs -> "modifies " + (String.concat "," xs) + ";" let string_of_attrs (a:attr option):string = match a with None -> "" | Some s -> "{:" + s + "}" type print_state = { all_vars:id list; all_typedefs:id list; all_procs:(id * proc_decl) list; publics:(loc * decl) list; print_out:System.IO.TextWriter; cur_loc:loc ref; cur_indent:string ref; } member this.PrintLine (s:string) = let (f, i) = !this.cur_loc in (this.cur_loc := (f, i + 1)); this.print_out.WriteLine (!this.cur_indent + s) member this.Indent () = this.cur_indent := " " + !this.cur_indent member this.Unindent () = this.cur_indent := (!this.cur_indent).Substring(2) member this.SetLoc (((f, i) as l):loc) = let (cf, ci) as cl = !this.cur_loc in if l = cl then () else if f <> cf || i < ci || i > ci + 8 then this.cur_loc := l; this.print_out.WriteLine ("#line " + (string i) + " " + f) else this.PrintLine ""; this.SetLoc l let string_of_proc_kind (pk:proc_kind):string = match pk with | Procedure (_, Atomic) -> "procedure" | Procedure (_, Yields) | Procedure (_, Stable) -> "procedure" // TODO: "procedure{:yields}" | Implementation -> "implementation" let rename_var xs x = if List.mem x xs then "#RENAME#" + x else x in let rename_formals xs fs = List.map (fun (x, t) -> (rename_var xs x, t)) fs in let rec rename_exp xs e = let rs = List.map (rename_exp xs) in match e with | EVar x -> EVar (rename_var xs x) | EInt _ | EReal _ | EBv32 _ | EBool _ -> e | EOp (op, es) -> EOp (op, rs es) | EApply (x, es) -> EApply (x, rs es) | EQuant (q, fs, ts, e) -> let xs = (List.map fst fs) @ xs in let rs = List.map (rename_exp xs) in EQuant (q, rename_formals xs fs, List.map rs ts, rename_exp xs e) in let rec symdiff_emit_linearity (state:print_state):unit = let assumes = List.mapi (fun i s -> "###symdiff_linearity[" + s + "] == " + (string i)) !symdiff_lin_decls in let terms = sep_list " && " assumes in state.PrintLine ("assume (exists ###symdiff_linearity:[int]int::" + terms + ");") let symdiff_write_fun (loop:bool) (impl:bool) (pre:string list) (post:string list):unit = if pre = [] && post = [] then () else let s_loop = if loop then "_loop_" + (fst !symdiff_invariant) else "" in let s_pre = String.concat "" (List.map (fun s -> " && " + s) pre) in let s_post = String.concat "" (List.map (fun s -> " && " + s) post) in let write_decl s = (!symdiff_writer).WriteLine( "function {:inline true} " + s + "$v1_u." + (fst !symdiff_proc) + s_loop + "$v2_u." + (fst !symdiff_proc) + s_loop + "(" + (snd !symdiff_proc loop) + "):bool") in write_decl "MP"; (!symdiff_writer).WriteLine("{"); (!symdiff_writer).WriteLine(" true" + s_pre); (!symdiff_writer).WriteLine("}"); // warning: this does not handle recursion write_decl "MS"; (!symdiff_writer).WriteLine("{") (!symdiff_writer).WriteLine(" (true" + s_pre + ")"); (!symdiff_writer).WriteLine(" ==> (true" + s_post + ")"); (!symdiff_writer).WriteLine("}"); (!symdiff_writer).WriteLine() // NOTE: Since we're providing symdiff with two copies of the same code, // we can restrict programs to the special case where a call in the // left program must match the same call in the right program (not // another call to the same procedure). // To encode this for SymDiff, rename the called procedure at each call site // so that different call sites in a procedure are distinguished. let symdiff_clone_call (state:print_state) (p:string):string = if not (List.mem_assoc p state.all_procs) then p else let (_, _, _, _, _, specs, _) = List.assoc p state.all_procs in let rels = List.filter (fun (_, spec) -> match spec with Requires (IsRel, _) | Ensures (IsRel, _) -> true | _ -> false) specs in if rels = [] then p else let get_int_ref l = if not (List.mem_assoc p !l) then l := (p, ref 0)::!l; List.assoc p !l in let (li, gi) = (get_int_ref symdiff_proc_local_clones, get_int_ref symdiff_proc_global_clones) in incr li; if !li > !gi then gi := !li; "#clone" + (string !li) + "#" + p let rec emit_stmt (rec_context:string * pformal list) (state:print_state) (l:loc, s:stmt):unit = state.SetLoc l; (match (rec_context, s) with | ((xp, (x0, _, _)::xs), SInline (_, xc, e0::es, _)) when xp = xc -> // inductive call to self; check termination let se0 = string_of_exp e0 in state.PrintLine ("assert 0 <= " + se0 + " && " + se0 + " < " + x0 + ";") | (_, SAssert (NotInv, e)) when !symdiff -> state.PrintLine ("assume " + (string_of_exp e) + ";") | _ -> () ); let s_clone = ( match (!symdiff, s) with | (true, SInline (xs, p, es, pars)) -> SInline (xs, symdiff_clone_call state p, es, pars) | (true, SCall (xs, p, es)) -> SCall (xs, symdiff_clone_call state p, es) | _ -> s ) in state.PrintLine (string_of_stmt s_clone); (match s with | SAssert (IsInv IsRel, e) when !symdiff -> symdiff_invariant := (fst !symdiff_invariant, ((fst (snd !symdiff_invariant)), (string_of_exp_r (RelPre true, Outside) e, string_of_exp_r (RelPost true, Outside) e)::(snd (snd !symdiff_invariant)))) | SAssert (IsInv NotRel, e) when !symdiff -> symdiff_invariant := (fst !symdiff_invariant, (((string_of_exp e)::(fst (snd !symdiff_invariant))), snd (snd !symdiff_invariant))) | SAssert (IsInv _, _) -> () | SSplit -> () | _ when !symdiff && (snd !symdiff_invariant <> ([], [])) -> symdiff_write_fun true false (List.map fst (snd (snd !symdiff_invariant))) (List.map snd (snd (snd !symdiff_invariant))); List.iter (fun x -> state.PrintLine ("assert " + x + " == " + x + ";")) !symdiff_params; // tell symdiff not to prune loop procedure's parameter list List.iter (fun s -> state.PrintLine ("assume " + s + ";")) (fst (snd !symdiff_invariant)); List.iter (fun x -> state.PrintLine (x + " := " + x + ";")) !symdiff_locals; // tell symdiff not to prune loop procedure's parameter list symdiff_invariant := ("", ([], [])) | _ -> () ); (match s with | SGroup b -> List.iter (emit_stmt rec_context state) b | SIfGhost (e, b) -> ( state.PrintLine "{"; state.Indent (); List.iter (emit_stmt rec_context state) b; state.Unindent (); state.PrintLine "}" ) | SForallGhost (fs, ts, e, _, b) -> ( state.PrintLine "{"; state.Indent (); List.iter (fun (x, _) -> state.PrintLine ("havoc " + x + ";")) fs; // need some constants or havoc'd variables; declare at top level? as locals? List.iter (emit_stmt rec_context state) b; state.PrintLine ("assert " + (string_of_exp e) + ";"); state.PrintLine ("assume false;"); // in one branch, prove assertion, then block (assume false) state.Unindent (); state.PrintLine "}" // in other branch, assume what was asserted, but quantify over all variables state.PrintLine ("assume " + (string_of_exp (rename_exp [] (EQuant (Forall, fs, ts, e)))) + ";"); ) | SExistsGhost (fs, ts, e) -> ( state.PrintLine "{"; state.Indent (); state.PrintLine ("assert " + (string_of_exp (rename_exp [] (EQuant (Exists, fs, ts, e)))) + ";"); state.PrintLine ("assume false;"); // in one branch, prove assertion, then block (assume false) state.Unindent (); state.PrintLine "}" List.iter (fun (x, _) -> state.PrintLine ("havoc " + x + ";")) fs; // in other branch, assume what was asserted, but for newly havoc'd variables state.PrintLine ("assume " + (string_of_exp e) + ";") ) //| SAssert (EOp (Uop "!", [EBool false])) when !symdiff -> symdiff_emit_linearity state // HACK | SLabel x when !symdiff -> symdiff_invariant := (x, ([], [])) | _ -> ()) let rec emit_stmt_decl (forall_vars:id list) (state:print_state) (l:loc, s:stmt):unit = // HACK: we don't yet support duplicate variable names across forall statements, // so just declare all the variables together, and rely on Boogie to flag duplicates as errors let check_assign x = if List.mem x forall_vars then err ("cannot assign to readonly variable " + x) in match s with | SLabel _ | SGoto _ | SReturn | SIReturn | SIfJcc _ -> () // illegal in ghost code | SYield _ | SAssert _ | SSplit -> () | SAssign (x, _) -> check_assign x | SInline (xs, _, _, _) | SCall (xs, _, _) -> List.iter check_assign xs | SGroup b -> List.iter (emit_stmt_decl forall_vars state) b | SIfGhost (_, b) -> List.iter (emit_stmt_decl forall_vars state) b | SForallGhost (fs, _, _, fa_vars, b) -> ( List.iter (fun (x, t) -> state.PrintLine ("var " + x + ":" + (string_of_typ t) + ";")) (fs @ fa_vars); List.iter (emit_stmt_decl ((List.map fst fs) @ forall_vars) state) b ) | SExistsGhost (fs, _, _) -> ( List.iter (fun (x, t) -> state.PrintLine ("var " + x + ":" + (string_of_typ t) + ";")) fs ) let rec collect_forall_vars (l:loc, s:stmt):formal list = match s with | SLabel _ | SGoto _ | SReturn | SIReturn | SIfJcc _ -> [] | SYield _ | SAssert _ | SSplit -> [] | SAssign (x, _) -> [] | SInline (xs, _, _, _) | SCall (xs, _, _) -> [] | SGroup b -> List.collect collect_forall_vars b | SIfGhost (_, b) -> List.collect collect_forall_vars b | SForallGhost (fs, _, _, vars, b) -> vars @ (List.collect collect_forall_vars b) | SExistsGhost (fs, _, _) -> [] let emit_spec (state:print_state) (l:loc, s:spec):unit = state.SetLoc l; state.PrintLine (string_of_spec s) // Rather than raising an error for non-terminating functions, we rewrite // non-terminating functions to be terminating: non-terminating calls (calls that // fail to decrease the termination metric or produce a negative termination metric) // simply return unspecified dummy values. let rewrite_recursive_fun (state:print_state) (x:string) (fs:formal list) (t:typ) (e:exp):exp = let emitted = ref false in let call_rec_fun (args:exp list):exp = let name = "##rec##" + x in match (fs, args) with | ((x0, TInt)::_, _::_) -> ( if not (!emitted) then ( let app = name + "(##d, " + (sep_list "," (List.map fst fs)) + ")" in let app0 = x + "(" + (sep_list "," (List.map fst fs)) + ")" in state.PrintLine ("function " + name + "(##d:int, " + (string_of_formals fs) + "):" + (string_of_typ t) + ";"); state.PrintLine ("axiom (forall ##d:int, " + (string_of_formals fs) + "::{" + app + "} 0 <= " + x0 + " && " + x0 + " < ##d ==> " + app + " == " + app0 + ");"); emitted := true ); EApply (name, (EVar x0)::args) ) | _ -> err ("recursive function " + x + " must have a decreasing, nonnegative integer first argument") in let rec r e = match e with | EVar _ | EInt _ | EReal _ | EBv32 _ | EBool _ -> e | EOp (op, es) -> EOp (op, List.map r es) | EApply (y, es) when x = y -> call_rec_fun (List.map r es) | EApply (y, es) -> EApply (y, List.map r es) | EQuant (q, qfs, ts, e) -> EQuant (q, qfs, List.map (List.map r) ts, r e) in r e let rec emit_decl (state:print_state) (l:loc, d:decl):unit = state.SetLoc l; match d with | DType (x, _, _, None) -> ( (if not (List.mem x state.all_typedefs) then state.PrintLine ("type " + x + ";")); state.PrintLine ("function sizeof##" + x + "(x:" + x + "):int;") ) | DType (x, overload, impl, Some cs) -> state.PrintLine ("type{:datatype} " + x + ";"); (if not impl then state.PrintLine ("function sizeof##" + x + "(x:" + x + "):int;")); state.PrintLine ("axiom (forall x:" + x + "::{sizeof##" + x + "(x)} sizeof##" + x + "(x) >= 0);"); List.iter (fun (lin, c, fs) -> let ffs = List.map (fun (fx, ft, fl) -> (fx, ft)) fs in state.PrintLine ("function{:constructor} " + c + "(" + (string_of_formals ffs) + "):" + x + ";"); (match lin with | Non -> () | Lin (LinConst, _) -> err ("in type " + x + ", linear constructor cannot be declared const") | _ -> let sfs = string_of_pformals_param fs in let sfs_out = string_of_pformals_var fs in let sc = (string_of_lin_var lin) + "#x:" + x in let sc_out = (string_of_lin_param lin) + "#x:" + x in let sis = "is#" + c + "(#x);" in let ens = " ensures #x == " + c + "(" + (String.concat "," (List.map fst ffs)) + ");" in state.PrintLine ("procedure construct##" + c + "(#me:int, #r:ReturnTo, " + sfs + ") returns(" + sc + ");" + ens); state.PrintLine ("procedure destruct##" + c + "(#me:int, #r:ReturnTo, " + sc_out + ") returns(" + sfs_out + "); requires " + sis + ens)); (List.iter (fun (fx, ft, fl) -> (match (lin, fl) with | (_, Lin (LinConst, _)) -> err ("in type " + x + ", linear field cannot be declared const") | (Lin (_, LinOur), Lin (_, LinMy)) -> err ("in type " + x + ", linear constructor cannot contain 'my' field") | _ -> ()); match ft with | TInt | TBool | TReal | TMap _ -> () | TName xft -> let subsize = "sizeof##" + xft + "(" + fx + "#" + c + "(x))" in state.PrintLine ("axiom (forall x:" + x + "::{" + subsize + "} is#" + c + "(x) ==> " + subsize + " < sizeof##" + x + "(x));")) fs); if not overload then List.iter (fun (fx, ft, _) -> state.PrintLine ("function{:inline true} ." + fx + "(x:" + x + "):" + (string_of_typ ft) + " { " + fx + "#" + c + "(x) }")) fs) cs | DStatic x -> let a = "?ADDR__" + x in let id = "#ID__" + x in state.PrintLine ("const " + a + ":int;"); state.PrintLine ("const unique " + id + ":int;"); state.PrintLine ("axiom StaticAddrToId(" + a + ") == " + id + ";"); state.PrintLine ("axiom Aligned(" + a + ");"); state.PrintLine ("axiom word(" + a + ");"); state.PrintLine ("axiom ge(" + a + ", 4096);"); state.PrintLine ("axiom memAddr(" + a + ");"); state.PrintLine ("axiom !memAddrMain(" + a + ");") | DStaticGhost (x, t, lin, _) -> (if (!symdiff && lin <> Non) then symdiff_lin_decls := x::!symdiff_lin_decls); state.PrintLine ("var " + (string_of_lin_var lin) + x + ":" + (string_of_typ t) + ";") | DFunDecl (x, None, Some t, e_opt, None, None) -> ( state.PrintLine ("const " + x + ":" + (string_of_typ t) + ";") match e_opt with None -> () | Some e -> state.PrintLine ("axiom " + x + " == " + (string_of_exp e) + ";") ) | DFunDecl (x, Some fs, Some t, e_opt, a, None) -> let e_opt = (match e_opt with None -> None | Some e -> Some (rewrite_recursive_fun state x fs t e)) in state.PrintLine ("function " + (string_of_attrs a) + x + "(" + (string_of_formals fs) + ") returns(" + (string_of_typ t) + ")"); state.PrintLine (match e_opt with None -> ";" | Some e -> "{ " + (string_of_exp e) + "}") | DFunDecl (x, Some fs, Some t, Some e, None, Some ts) -> ( let e = rewrite_recursive_fun state x fs t e in let forall = (match fs with [] -> "" | _ -> "forall " + (string_of_formals fs) + "::" + (string_of_triggers (NoRel, Outside) ts)) in state.PrintLine ("axiom (" + forall + x + "(" + (String.concat "," (List.map fst fs)) + ") == " + (string_of_exp e) + ");"); ) | DFunDecl (x, _, _, _, _, _) -> err ("internal error: const/function " + x) | DProc (x, pk, ik, fs, rs, specs, b_opt) -> ( let rec_context = (x, fs) in let x2 = "##verify##" + x in let specs = match pk with | Procedure (_, Atomic) | Implementation -> specs | Procedure (_, Yields) | Procedure (_, Stable) -> (l, Modifies state.all_vars)::specs in let fs = ("me", TInt, Lin (LinConst, LinOur))::("RET", TName "ReturnTo", Non)::fs in let impl_fs = List.map (fun (x, t, l) -> (x, t, Non)) fs in // Boogie only allows "linear" on proc, not impl let impl_rs = List.map (fun (x, t, _) -> (x, t, Non)) rs in let symdiff_mods = if not !symdiff then [] else match pk with | Procedure _ -> let mods = List.collect (fun s -> match s with (_, Modifies xs) -> xs | _ -> []) specs in let globs = List.map (fun (x, t, lin) -> (x, (t, lin))) !symdiff_globals in let mods = List.map (fun x -> (if not (List.mem_assoc x globs) then err ("Found " + x + " in a modifies clause. Cannot find in global variables.")); let (t, lin) = List.assoc x globs in (x, t, lin)) mods in symdiff_proc_mods := (x, mods)::!symdiff_proc_mods; mods | Implementation _ -> List.assoc x !symdiff_proc_mods in (if !symdiff then symdiff_invariant := ("", ([], [])); symdiff_proc_local_clones := []; let pfdecl n pre suf (x, t, _) = "v" + n + "_u." + pre + x + suf + ": " + (string_of_typ t) in let local_vars = match b_opt with None -> [] | Some (vars, _) -> vars in let ins loop n = List.map (pfdecl n (if loop then "in_" else "") "") fs in let outs_ins loop n = List.map (pfdecl n "in_" "") rs in let outs loop n = List.map (pfdecl n (if loop then "out_" else "") "") rs in let locals is_out n = List.map (pfdecl n (if is_out then "out_" else "in_") "") local_vars in let globals is_out n = List.map (pfdecl n "" (if is_out then "_" else "_old")) (if is_out then symdiff_mods else !symdiff_globals) in let vars loop n = if loop then (ins loop n) @ (outs_ins loop n) @ (locals false n) @ (globals false n) @ (globals true n) @ (outs loop n) @ (locals true n) else (ins loop n) @ (globals false n) @ (globals true n) @ (outs loop n) in let vars12 loop = (vars loop "1") @ (vars loop "2") in let f_vars loop = sep_list ", " (vars12 loop) in symdiff_proc := (x, f_vars); symdiff_rets := List.map (fun (x, _, _) -> x) rs; symdiff_params := List.map (fun (x, _, _) -> x) fs; symdiff_locals := List.map (fun (x, _, _) -> x) local_vars; let pres = List.collect (fun s -> match s with (_, Requires (IsRel, e)) -> [string_of_exp_r (RelPre false, Outside) e] | _ -> []) specs in let posts = List.collect (fun s -> match s with (_, Ensures (IsRel, e)) -> [string_of_exp_r (RelPost false, Outside) e] | _ -> []) specs in symdiff_proc := (x, f_vars); (match pk with Implementation -> () | Procedure _ -> symdiff_write_fun false false pres posts); symdiff_proc := (x2, f_vars); (match pk with | Implementation -> () | Procedure _ -> let req_strings = List.collect (fun s -> match s with (_, Requires (r, e)) -> [" && " + (string_of_exp_ignore_rel r e)] | _ -> []) specs in state.PrintLine ("procedure #symdiff_proc_reqs##" + x2 + "(" + (string_of_pformals_var fs) + ");"); state.PrintLine (" ensures true " + (String.concat "" req_strings) + ";"); symdiff_write_fun false true pres posts) ); let f x pk p_fs p_rs b_opt = let rets = match p_rs with [] -> "" | _ -> "returns(" + (string_of_pformals_var p_rs) + ")" in let semi = match pk with Procedure _ -> ";" | Implementation -> "" in state.PrintLine ((string_of_proc_kind pk) + " " + x + "(" + (string_of_pformals_param p_fs) + ")" + rets + semi); state.Indent (); List.iter (emit_spec state) (match pk with Procedure _ -> specs | Implementation -> []); state.Unindent (); (match b_opt with | None -> () | Some (vars, b) -> ( state.PrintLine "{"; state.Indent (); List.iter (fun (x, t, l) -> state.PrintLine ("var " + (string_of_lin_var l) + x + ":" + (string_of_typ t) + ";")) vars; List.iter (emit_stmt_decl [] state) b; (if !symdiff then state.PrintLine ("call #symdiff_proc_reqs##" + x2 + "(" + (String.concat "," (List.map (fun (x, _, _) -> x) p_fs)) + ");"); List.iter (fun (x, _, _) -> state.PrintLine(x + " := " + x + ";")) symdiff_mods; // make sure symdiff reports modified variables in predictable order (TODO: get /doModSetAnalysis completely turned off) () // symdiff_emit_linearity state ); List.iter (emit_stmt rec_context state) b; state.Unindent (); state.PrintLine "}" )) in ( match (b_opt, pk) with | (None, Procedure _) -> f x pk fs rs None; f x2 pk fs rs None | (None, Implementation) -> err "implementation must have body" | (Some _, Procedure _) -> f x pk fs rs None; f x2 pk fs rs None; f x2 Implementation impl_fs impl_rs b_opt | (Some _, Implementation) -> f x2 Implementation impl_fs impl_rs b_opt); state.PrintLine "" ) let emit_module (state:print_state) (m:_module):unit = try List.iter (emit_decl state) m.mDecls with Err s -> let (f, l) = !state.cur_loc in err ("error near location " + f + " line " + (string l) + ": " + s); if !symdiff then // generate clone procedure declarations List.iter (fun (p, count) -> let (_, pk, ik, fs, rs, specs, ts) = List.assoc p state.all_procs in for i = 1 to !count do let pc = "#clone" + (string i) + "#" + p in let d = DProc (pc, pk, ik, fs, rs, specs, ts) in emit_decl state (("clone", 0), d) ) !symdiff_proc_global_clones let emit_entry_point (state:print_state):unit = // call all interface procedures from a dummy entry point let vars = List.collect (fun (_, d) -> match d with DStaticGhost (x, _, _, _) -> [x] | _ -> []) state.publics in let mods = "modifies " + (String.concat "," vars) + ";" in state.PrintLine "procedure{:yields} ###DummyCallTarget();"; let procs = List.fold_left (fun procs (loc, d) -> match d with | DProc (xp, Procedure (_, atomicity), ik, fs, rs, specs, _) -> ( state.SetLoc(loc); let fs = ("me", TInt, Lin (LinConst, LinOur))::("RET", TName "ReturnTo", Non)::fs in let attr = match atomicity with Atomic -> "" | _ -> "{:verify false}" in state.PrintLine ("procedure{:yields}" + attr + " ###Dummy#" + xp + "()"); state.Indent (); state.PrintLine mods; state.Unindent (); state.PrintLine "{"; state.Indent (); List.iter (fun (x, t, lin) -> state.PrintLine ("var" + (string_of_lin_var lin) + " " + x + ":" + (string_of_typ t) + ";")) (fs @ rs); state.SetLoc(loc); List.iter (fun (_, s) -> match (atomicity, s) with | (Atomic, Requires (r, e)) -> state.PrintLine ("assume " + (string_of_exp_ignore_rel r e) + ";") | _ -> ()) specs; let stable = match atomicity with Stable -> "###DummyEntryPoint() | " | _ -> "" in let args = String.concat "," (List.map (fun (x, _, _) -> x) fs) in let rets = String.concat "," (List.map (fun (x, _, _) -> x) rs) in let rets = rets + (if List.length rs = 0 then "" else " := ") in state.SetLoc(loc); state.PrintLine ("free call " + stable + rets + "##verify##" + xp + "(" + args + ");"); state.Unindent (); state.PrintLine "}"; (xp, atomicity)::procs ) | _ -> procs) [] state.publics if procs.Length > 0 then state.SetLoc(("fake entry point", 1)); state.PrintLine "procedure{:entrypoint}{:verify false} ###DummyEntryPoint()"; state.PrintLine mods; state.PrintLine "{"; state.Indent (); state.PrintLine ("###loop: goto " + (String.concat "," (List.map fst procs)) + ";"); List.iter (fun (xp, atomicity) -> state.PrintLine (xp + ": async call ###Dummy#" + xp + "(); goto ###loop;")) (List.rev procs); state.Unindent (); state.PrintLine "}" ================================================ FILE: ironclad-apps/tools/BoogieAsm/lex.fsl ================================================ { open Lexing;; open Parse;; open Parse_util;; open Microsoft.FSharp.Compatibility.OCaml.Big_int;; let macros = ref (Map.empty:Map) } rule comment = parse | "*/" { () } | "*)" { () } | "/*" { comment lexbuf ; comment lexbuf } | "(*" { comment lexbuf ; comment lexbuf } | "\n\r" { incr line; comment lexbuf } | "\r\n" { incr line; comment lexbuf } | ['\n''\r'] { incr line; comment lexbuf } | _ { comment lexbuf } and preprocess_skip deep = parse | "#else" { if deep then preprocess_skip deep lexbuf else () } | "#endif" { () } | "#ifdef" { preprocess_skip true lexbuf; preprocess_skip deep lexbuf } | "#ifndef" { preprocess_skip true lexbuf; preprocess_skip deep lexbuf } | "\n\r" { incr line; preprocess_skip deep lexbuf } | "\r\n" { incr line; preprocess_skip deep lexbuf } | ['\n''\r'] { incr line; preprocess_skip deep lexbuf } | _ { preprocess_skip deep lexbuf } and file_name = parse | [' ']*[^' ''\n''\r']+[^'\n''\r']* { file := (lexeme lexbuf).Trim() ; token lexbuf } | [^'\n''\r']* { token lexbuf } and line_number = parse | ['0'-'9']+ { line := int_of_string(lexeme lexbuf) - 1 ; file_name lexbuf } and token = parse | "\n\r" { incr line; token lexbuf } | "\r\n" { incr line; token lexbuf } | ['\n''\r'] { incr line; token lexbuf } | [' ''\t'] { token lexbuf } | "//"[^'\n''\r']* { token lexbuf } | "#line"[' ']* { line_number lexbuf } | "/*" { comment lexbuf ; token lexbuf } | "(*" { comment lexbuf ; token lexbuf } | "#ifdef"[' ']+['A'-'Z''a'-'z''0'-'9''_''$''?']+ { let s = lexeme lexbuf in let x = s.Substring("#ifdef".Length).Trim() in if Map.contains x !macros then token lexbuf else (preprocess_skip false lexbuf ; token lexbuf) } | "#ifndef"[' ']+['A'-'Z''a'-'z''0'-'9''_''$''?']+ { let s = lexeme lexbuf in let x = s.Substring("#ifndef".Length).Trim() in if not (Map.contains x !macros) then token lexbuf else (preprocess_skip false lexbuf ; token lexbuf) } | "#else" { preprocess_skip false lexbuf ; token lexbuf } | "#endif" { token lexbuf } | ":" { COLON (!file, !line) } | ";" { SEMI } | "(" { LPAREN } | ")" { RPAREN } | "[" { LBRACKET } | "]" { RBRACKET } | "{" { LBRACE (!file, !line) } | "}" { RBRACE (!file, !line) } | "<" { LT } | ">" { GT } | "=" { EQ } | "+" { PLUS } | "-" { MINUS } | "*" { STAR } | "/" { SLASH } | "!" { BANG } | "mod" { MOD } | "div" { DIV } | "," { COMMA } | "|" { BAR } | "." { DOT } | "#" { HASH } | ":=" { COLONEQ (!file, !line) } | "<=" { LE } | ">=" { GE } | "==" { EQEQ } | "!=" { NE } | "&&" { AMPAMP } | "||" { BARBAR } | "::" { COLONCOLON } | ">>" { GTGT } | "<<" { LTLT } | "==>" { EQEQGT } | "<==>" { LTEQEQGT } | "type" { TYPE (!file, !line) } | "const" { CONST (!file, !line) } | "readonly" { READONLY (!file, !line) } | "function" { FUNCTION (!file, !line) } | "returns" { RETURNS (!file, !line) } | "axiom" { AXIOM (!file, !line) } | "procedure" { PROCEDURE (!file, !line) } | "implementation" { IMPLEMENTATION (!file, !line) } | "requires" { REQUIRES (!file, !line) } | "ensures" { ENSURES (!file, !line) } | "modifies" { MODIFIES (!file, !line) } | "invariant" { INVARIANT (!file, !line) } | "assert" { ASSERT (!file, !line) } | "havoc" { HAVOC } | "goto" { GOTO (!file, !line) } | "call" { CALL (!file, !line) } | "forall" { FORALL (!file, !line) } | "exists" { EXISTS (!file, !line) } | "lambda" { LAMBDA (!file, !line) } | "old" { OLD } | "left" { LEFT } | "right" { RIGHT } | "relation" { RELATION } | "public" { PUBLIC } | "int" { INT } | "real" { REAL } | "bool" { BOOL } | "true" { LITBOOL true } | "false" { LITBOOL false } | "is" { IS } | "let" { LET } | "in" { IN } | "var" { VAR (!file, !line) } | "if" { IF (!file, !line) } | "then" { THEN } | "else" { ELSE } | "return" { RETURN (!file, !line) } | "ireturn" { IRETURN (!file, !line) } | "yield" { YIELD (!file, !line) } | "linear" { LINEAR } | ":split_here" { SPLIT } | "my" { MY } | "static" { STATIC (!file, !line) } | "module" { MODULE (!file, !line) } | "interface" { INTERFACE (!file, !line) } | "import" { IMPORT (!file, !line) } | "atomic" { ATOMIC } | "stable" { STABLE } | "ghost" { GHOST } | "CS" { SEGNAME (lexeme lexbuf) } | "DS" { SEGNAME (lexeme lexbuf) } | "SS" { SEGNAME (lexeme lexbuf) } | "ES" { SEGNAME (lexeme lexbuf) } | "FS" { SEGNAME (lexeme lexbuf) } | "GS" { SEGNAME (lexeme lexbuf) } | "EAX" { REGNAME (lexeme lexbuf) } | "EBX" { REGNAME (lexeme lexbuf) } | "ECX" { REGNAME (lexeme lexbuf) } | "EDX" { REGNAME (lexeme lexbuf) } | "ESI" { REGNAME (lexeme lexbuf) } | "EDI" { REGNAME (lexeme lexbuf) } | "EBP" { REGNAME (lexeme lexbuf) } | "ESP" { REGNAME (lexeme lexbuf) } | "0x"['0'-'9''a'-'f''A'-'F']+ { let s = lexeme lexbuf in let s = String.sub s 2 (String.length s - 2) in let rec explode (n:int) s = if n = String.length s then [] else (String.get s n)::(explode (n+1) s) in let digits = List.map (Char.code << Char.lowercase) (explode 0 s) in let rec hex digits n = match digits with | [] -> n | h::t -> let d = if h >= (Char.code 'a') then h - (Char.code 'a') + 10 else h - (Char.code '0') in hex t (add_int_big_int d (mult_int_big_int 16 n)) in LITINT (hex digits zero_big_int) } | ['0'-'9']+ { LITINT (big_int_of_string(lexeme lexbuf)) } | ['0'-'9']+['.']['0'-'9']+ { LITREAL (lexeme lexbuf) } | ['0'-'9']+"bv32" { let s = lexeme lexbuf in LITBV32 (big_int_of_string(s.Substring(0, s.Length - 4))) } | ['_']*['A'-'Z']['_''a'-'z''A'-'Z''0'-'9']* { UID ((lexeme lexbuf).Replace("_old", "__old")) } | ['_']*['a'-'z']['_''a'-'z''A'-'Z''0'-'9']* { LID ((lexeme lexbuf).Replace("_old", "__old")) } | '?'['_']*['A'-'Z']['_''a'-'z''A'-'Z''0'-'9']* { QUID ((lexeme lexbuf).Replace("_old", "__old")) } | '?'['_']*['a'-'z']['_''a'-'z''A'-'Z''0'-'9']* { QLID ((lexeme lexbuf).Replace("_old", "__old")) } | '$'['_']*['A'-'Z']['_''a'-'z''A'-'Z''0'-'9']* { DUID ((lexeme lexbuf).Replace("_old", "__old")) } | '$'['_']*['a'-'z']['_''a'-'z''A'-'Z''0'-'9']* { DLID ((lexeme lexbuf).Replace("_old", "__old")) } | ['_']+['_''0'-'9']* { LID ((lexeme lexbuf).Replace("_old", "__old")) } | eof { EOF } | '\000' { EOF } | _ { parse_err ("cannot parse character: \"" ^ (lexeme lexbuf) ^ "\"" ^ "\n(ascii code " ^ (string_of_int (Char.code (String.get (lexeme lexbuf) 0))) ^ ")") } ================================================ FILE: ironclad-apps/tools/BoogieAsm/main.fs ================================================ open Ast open Parse open Parse_util open Emit_bpl open Microsoft.FSharp.Math let check_concurrent = ref false let proc_name (s:string) = "_?" + s let const_name (s:string) = "?_" + s let label (ctxt:string) (s:string) = ctxt ^ "$" ^ s let sym = ref 0 let gensym () = incr sym; "$$" ^ (string_of_int !sym) let list_remove x l = List.filter (fun y -> x <> y) l type width = W8 | W16 | W32 let string_of_width w = match w with W8 -> "byte" | W16 -> "word" | W32 -> "dword" type con = string type operand = | OConst of con | OReg of reg | OTmpReg of reg | OSelector of string | OConstPtr of con | OOffset of reg * con | OIndex of reg * con * reg * con | OExp of bigint option type varMap = (id * operand) list type insCtxt = string * varMap type inlineMap = InlineMap of (string * (operand list -> inlineMap * insCtxt * (loc * stmt) list)) list type inlinePreMap = (string * (operand list -> insCtxt * (loc * stmt) list)) list let is_32bit_bigint i = BigInt.Zero <= i && i < (BigInt.Parse "4294967296") let is_32bit_bigint_signed i = (BigInt.Parse "-4294967296") <= i && i < (BigInt.Parse "4294967296") let x64 = ref false //32-bit by default let const_of_exp (e:exp):con = match e with | EInt i when is_32bit_bigint i -> i.ToString() | EVar x -> const_name x | _ -> err "unexpected constant" let const_of_exp_signed (e:exp):con = match e with | EInt i when is_32bit_bigint_signed i -> i.ToString() | EOp (Uop "-", [EInt i]) when is_32bit_bigint_signed (-i) -> (-i).ToString() | _ -> const_of_exp e let operand_of_exp (varMap:varMap) (e:exp):operand = match e with | EApply ("OConst", [c]) -> OConst (const_of_exp c) | EApply ("OReg", [EVar x]) when x.StartsWith("TMP") -> OTmpReg x | EApply ("OReg", [EVar x]) -> OReg x | EApply ("OMem", [EApply ("MConst", [c])]) -> OConstPtr (const_of_exp c) | EApply ("OMem", [EApply ("MReg", [EVar x; c])]) -> OOffset (x, const_of_exp_signed c) | EApply ("OMem", [EApply ("MIndex", [EVar xb; EInt i; EVar xi; c])]) when (match i.ToString() with "1" | "2" | "4" | "8" -> true | _ -> false) -> OIndex (xb, i.ToString(), xi, const_of_exp_signed c) | EVar x when List.mem_assoc x varMap -> List.assoc x varMap | EVar ("EAX" | "EBX" | "ECX" | "EDX" | "ESI" | "EDI" | "EBP" | "ESP" as x) -> OReg x | EVar x when x.StartsWith("TMP") -> OTmpReg x | EVar ("CS" | "DS" | "ES" | "FS" | "GS" | "SS" as x) -> OSelector x | EInt i -> OExp (Some i) | _ -> OExp None let rec free_vars_exp (scopeVars:string list) (e:exp):string list = match e with | EVar x -> if (List.mem x scopeVars) then [] else [x] | EInt _ | EReal _ | EBv32 _ | EBool _ -> [] | EOp (_, es) -> List.collect (free_vars_exp scopeVars) es | EApply (_, es) -> List.collect (free_vars_exp scopeVars) es | EQuant (_, xs, ts, e) -> List.collect (free_vars_exp ((List.map fst xs) @ scopeVars)) (e::(List.concat ts)) let check_module (included:_module list) (ifc:_module) (imp:_module) = let allDs = (List.collect (fun m -> m.mDecls) (imp::ifc::included)) in let pubDs = (List.collect (fun m -> m.mDecls) (ifc::included)) in let procMap = List.collect (fun (_, d) -> match d with DProc ((x, Procedure (g, a), _, _, _, specs, _) as p) -> [(x, ((g, a), specs))] | _ -> []) allDs in let includeNames = List.map (fun i -> i.mName) included in let ds = ifc.mDecls @ imp.mDecls in let allVars = List.collect (fun (_, d) -> match d with DStaticGhost (x, _, _, _) -> [x] | _ -> []) allDs in let allRwVars = List.collect (fun (_, d) -> match d with DStaticGhost (x, _, _, ReadWrite) -> [x] | _ -> []) allDs in let declVars = List.collect (fun (_, d) -> match d with DStaticGhost (x, _, _, _) -> [x] | _ -> []) ds in let implVars = List.collect (fun (_, d) -> match d with DStaticGhost (x, _, _, _) -> [x] | _ -> []) imp.mDecls in let ifcProcs = List.collect (fun (_, d) -> match d with DProc (x, _, _, _, _, _, _) -> [x] | _ -> []) ifc.mDecls in let pubProcs = List.collect (fun (_, d) -> match d with DProc (x, _, _, _, _, _, _) -> [x] | _ -> []) pubDs in // check that all procedures have implementations let mProcDecls = List.collect (fun (_, d) -> match d with DProc (x, _, _, _, _, _, _) -> [x] | _ -> []) (imp.mDecls @ ifc.mDecls) in let mProcDefs = List.collect (fun (_, d) -> match d with DProc (x, _, _, _, _, _, Some _) -> [x] | _ -> []) (imp.mDecls @ ifc.mDecls) in List.iter (fun x -> if (not (List.mem x mProcDefs)) then err ("module " + ifc.mName + " does not implement procedure " + x)) mProcDecls; // check that untrusted modules do not declare built-in instructions List.iter (fun (x:string) -> if x.StartsWith("instr_") then err ("untrusted module " + ifc.mName + " cannot declare instruction " + x)) mProcDecls; // check that imported module list matches included list // TODO consult Chris about synchronization between include/import // I think we're delegating all this responsibility to build system anyway. // List.iter (fun x -> if not (List.mem x imp.mImports) then err ("included module " + x + " must be imported")) includeNames; // List.iter (fun x -> if not (List.mem x includeNames) then err ("imported module " + x + " must be included")) imp.mImports; // check each procedure List.iter (fun ((locF, locL), d) -> match d with | DProc (xp, _, ik, ps, rs, specs, b_opt) -> ( try ( let check_spec spec = match spec with | (_, Requires (IsRel, _)) | (_, Ensures (IsRel, _)) when not !symdiff_allow -> err "'relation' expression only allowed when using -symdiffok flag or -symdiffms option" | _ -> () in List.iter check_spec specs; let proc_decl = try List.assoc xp procMap with :? System.Collections.Generic.KeyNotFoundException as x -> err ("procedure " + xp + " not found") in let ((ghost, atomicity), dspecs) = proc_decl in let procRel = List.exists (fun spec -> match spec with (_, Ensures (IsRel, _)) -> true | (_, Requires (IsRel, _)) -> true | _ -> false) dspecs in let locals = ps @ rs @ (match b_opt with None -> [] | Some (ls, _) -> ls) in let local_xs = List.map (fun (x, _, _) -> x) locals in // public variables in yield statements must be declared in module yields let check_yield e = List.iter (fun x -> match (List.mem x allVars, List.mem x implVars, List.mem x ifc.mModifies, List.mem x ifc.mYields) with | (false, _, _, _) -> () // not a variable (is a constant, or an invalid variable that will cause a Boogie error) | (true, true, false, _) -> () // private variable; no one else is allowed to modify x | (true, _, _, true) -> () // variable declared in yields | (true, _, _, false) -> err ("variable " + x + " occurs in yield, must be declared in module yields")) (free_vars_exp local_xs e) in // if any assigned variables are in the module's modifies list, check that the assignment is in public atomic action let check_assign forallScope x = match forallScope with | Some fa_xs -> if not (List.mem x fa_xs) then err ("cannot assign to variable " + x + " inside forall statement") else () | None -> ( if List.mem x local_xs then () else match (List.mem x allVars, List.mem x allRwVars, List.mem x declVars, List.mem x ifc.mModifies, atomicity, List.mem xp ifcProcs) with | (false, _, _, _, _, _) -> err ("in procedure " + xp + ", cannot find declaration of variable " + x) | (true, false, _, _, _, _) -> err ("procedure " + xp + " assigns to readonly variable " + x) | (true, true, false, false, _, _) -> err ("procedure " + xp + " assigns to " + x + " without declaring " + x + " in module modifies") | (true, true, true, false, _, _) -> () // private variable; no one else is allowed to yield on x (REVIEW: require List.mem x implVars here for clarity?) | (true, true, _, true, Atomic, true) -> () // assignment is publicized via public atomic procedure | (true, true, _, true, _, true) -> err ("procedure " + xp + " must be atomic to assign to variable " + x) | (true, true, _, true, _, false) -> err ("procedure " + xp + " must be declared in module interface to assign to variable " + x) ) in let check_call is_inline ghost forallScope (xc:id) = if xc.StartsWith("construct##") || xc.StartsWith("destruct##") then () else try let ((gc, ac), specs) = List.assoc xc procMap in List.iter (fun (_, s) -> match (forallScope, s) with | (Some _, Modifies _) -> err "forall statement cannot call procedure with modifies clause" | (_, Requires (IsRel, _)) when not !symdiff_allow -> err "call to procedure with relational requires only allowed when using -symdiffok flag or -symdiffms option" | (_, Requires (IsRel, _)) when not procRel -> err "call to procedure with relational requires only allowed from procedure with relational requires or relational ensures (hint: try adding 'ensures public(true);')" | _ -> ()) specs; if xp = xc then ( match (ghost, is_inline, ps) with | (PGhost, true, _::_) -> () | _ -> err ("recursive procedures must be ghost, inline, with a decreasing, non-negative first parameter: " + xc) ); (match (atomicity, ac) with | (Atomic, Yields) | (Atomic, Stable) -> err ("atomic procedure " + xp + " cannot call non-atomic procedure " + xc) | _ -> ()); (match (ghost, gc) with | (PGhost, PReal) -> err ("cannot call non-ghost procedure " + xc + " in ghost context") | (PGhost, PGhost) | (PReal, _) -> ()) with :? System.Collections.Generic.KeyNotFoundException as x -> err ("procedure " + xc + " not found") in let check_par forallScope xc (xpar, _) = try let ((_, ac), _) = List.assoc xc procMap in let ((gpar, apar), specs) = List.assoc xpar procMap in List.iter (fun s -> match (forallScope, s) with (Some _, (_, Modifies _)) -> err "forall statement cannot call procedure with modifies clause" | _ -> ()) specs; if xp = xc then err ("recursive parallel calls not allowed: " + xc); match (ac, apar, gpar) with // All parallel call targets must be stable // All parallel call targets except for first must be ghost | (Atomic, _, _) | (Yields, _, _) -> err ("target of parallel call " + xc + " must be declared 'stable'") | (Stable, Atomic, _) | (Stable, Yields, _) -> err ("target of parallel call " + xpar + " must be declared 'stable'") | (Stable, Stable, PReal) -> err ("target of parallel call " + xpar + " must be declared 'ghost'") | (Stable, Stable, PGhost) -> () with :? System.Collections.Generic.KeyNotFoundException as x -> err ("procedure " + xc + " or " + xpar + " not found") in // if specifications must be stable, check that variables are declared in yields (if atomicity = Stable then List.iter (fun (_, s) -> match s with Requires (_, e) | Ensures (_, e) -> check_yield e | _ -> ()) specs else ()); // check all statements let rec check_stmt ghost forallScope = (fun ((locF, locL), stmt) -> try ( (match (stmt, ik) with ((SReturn | SIReturn), Inline) -> err "return not allowed in inline procedure" | _ -> ()); match stmt with | SLabel _ | SGoto _ | SReturn | SIReturn | SIfJcc _ -> (match ghost with PReal -> () | PGhost -> err ("illegal control construct in ghost context")) | SGroup b -> List.iter (check_stmt ghost forallScope) b | SIfGhost (_, b) -> List.iter (check_stmt PGhost forallScope) b // REVIEW: we allow forall bodies to read (but not write) linear variables | SForallGhost (_, _, _, fVars, b) -> List.iter (check_stmt PGhost (Some (List.map fst fVars))) b | SExistsGhost (_, _, _) -> () | SAssert _ -> () | SSplit -> () | SYield _ when atomicity = Atomic -> err ("procedure " + xp + " cannot be declared atomic because it contains a yield statement") | SYield _ when ghost = PGhost -> err ("yield cannot appear in ghost context") | SYield e -> check_yield e | SAssign (x, _) -> check_assign forallScope x | SInline (xs, target, _, pars) -> check_call true ghost forallScope target; List.iter (check_assign forallScope) xs; List.iter (check_par forallScope target) pars | SCall _ when ghost = PGhost -> err ("call to non-inline procedure cannot appear in ghost context") | SCall (xs, target, _) -> check_call false ghost forallScope target; List.iter (check_assign forallScope) xs ) with Err s -> err ("In procedure " + xp + " (" + locF + " line " + (string locL) + "):" + System.Environment.NewLine + s)) in let check_stmts b = let rec body_end b = match b with | (_, SGroup b)::_ -> body_end (List.rev b) | (_, (SReturn | SIReturn | SGoto _))::_ -> () | _ -> err "body must end with return or goto" in (match ik with Inline -> () | Outline -> body_end (List.rev b)); List.iter (check_stmt ghost None) b in (match b_opt with None -> () | Some (_, stmts) -> check_stmts stmts) ) with Err s -> err ("In procedure " + xp + " (" + locF + " line " + (string locL) + "):" + System.Environment.NewLine + s) ) | _ -> ()) ds; () let rec applied_funs_exp (maskVars:string list) (e:exp):string list = let f = applied_funs_exp maskVars in match e with | EVar _ | EInt _ | EReal _ | EBv32 _ | EBool _ -> [] | EOp (_, es) -> List.collect f es | EApply (x, es) -> let x = x + "(...)" in (if (List.mem x maskVars) then [] else [x]) @ (List.collect f es) | EQuant (_, _, ts, e) -> List.collect f (e::(List.concat ts)) // Returns list of declarations that e depends on let rec link_check_exp (scopeVars:string list) (e:exp):string list = (free_vars_exp scopeVars e) @ (applied_funs_exp scopeVars e) let rec stmt_calls (_, stmt:stmt):string list = match stmt with | SLabel _ | SGoto _ | SReturn | SIReturn | SIfJcc _ | SAssert _ | SSplit | SYield _ | SAssign _ | SExistsGhost _ -> [] | SGroup b -> List.collect stmt_calls b | SIfGhost (_, b) -> List.collect stmt_calls b | SForallGhost (_, _, _, _, b) -> List.collect stmt_calls b | SInline (_, target, _, pars) -> [target] @ (List.map fst pars) | SCall (_, target, _) -> [target] let link_check_module (scopeVars:string list) (mIntf:_module, mImpl:_module):string list = let intf = mIntf.mDecls in let impl = mImpl.mDecls in let check_decl (_, d:decl):string list * (string * string list) list = let pid (x:string):string = x + "(..);" in let fid (ps_opt:formal list option) (x:string):string = match ps_opt with None -> x | Some _ -> x + "(...)" in let param_ids (ps_opt:formal list option):id list = match ps_opt with None -> [] | Some ps -> List.map fst ps in match d with | DFunDecl (x, ps_opt, _, None, _, _) -> ([fid ps_opt x], []) | DFunDecl (x, ps_opt, _, Some e, _, Some _) -> ([], [(fid ps_opt x, link_check_exp ((x + "(...)")::(param_ids ps_opt) @ scopeVars) e)]) | DFunDecl (x, ps_opt, _, Some e, _, None) -> ([fid ps_opt x], [(fid ps_opt x, link_check_exp ((x + "(...)")::(param_ids ps_opt) @ scopeVars) e)]) | DType (xt, _, _, None) -> ([("sizeof##" + xt + "(...)")], []) | DType (xt, overload, impl, Some cs) -> // Note: we use sizeof##'s checking to check for correct definition of xt (e.g. to check that xt not defined more than once) // TODO: check that xc not declared twice? ((if impl then [] else ["sizeof##" + xt + "(...)"]) @ (List.collect (fun (_, xc, fs) -> (xc + "(...)")::(pid ("construct##" + xc))::(pid ("destruct##" + xc))::("is#" + xc + "(...)") ::(List.collect (fun (xf, _, _) -> (if overload then [] else ["." + xf + "(...)"]) @ [xf + "#" + xc + "(...)"]) fs)) cs), [("sizeof##" + xt + "(...)"), []]) | DStatic x -> (["?ADDR__" + x], []) | DStaticGhost _ -> ([], []) | DProc (x, _, _, _, _, _, None) -> ([pid x], []) | DProc (x, Implementation, _, _, _, _, Some (_, b)) -> ([], [(pid x, List.filter (fun y -> not (List.mem y ((pid x)::scopeVars))) (List.map pid (List.collect stmt_calls b)))]) | DProc (x, Procedure _, _, _, _, _, Some (_, b)) -> ([pid x], [(pid x, List.filter (fun y -> not (List.mem y ((pid x)::scopeVars))) (List.map pid (List.collect stmt_calls b)))]) let pubs = List.map check_decl intf in let prvs = List.map check_decl impl in let (pub_decls, pub_defs) = (List.collect fst pubs, List.collect snd pubs) in let (prv_decls, prv_defs) = (List.collect fst prvs, List.collect snd prvs) in let decls = pub_decls @ prv_decls in List.iter (fun d -> if List.mem d scopeVars then err (d ^ " declared more than once")) decls; let defs = pub_defs @ prv_defs in let undefs = List.filter (fun d -> not (List.mem_assoc d defs)) decls in let rec check_defs (ds:(string * string list) list):unit = // move definitions with no unresolved dependencies to front //System.Console.WriteLine(); List.iter (fun ds -> System.Console.WriteLine("" + (fst ds) + " --> " + (String.concat "," (snd ds)))) ds; let (defs_ready, defs_wait) = List.partition (fun (x, deps) -> List.isEmpty deps) ds in match (defs_ready @ defs_wait) with | [] -> () | (d,[])::_ when not (List.mem d decls) -> err (d ^ " not declared in current module") | (d,[])::ds when (List.mem_assoc d ds) -> err (d ^ " defined more than once") | (d,[])::ds -> check_defs (List.map (fun (d2,deps) -> (d2, list_remove d deps)) ds) | (d1,(d2::_))::_ -> err (d1 ^ " can't find dependency " ^ d2 ^ " (or these are circularly defined). This in module " ^ mIntf.mName) in let () = check_defs ((List.map (fun d -> (d, [])) undefs) @ defs) in pub_decls @ scopeVars let link_check_modules (ms:(_module * _module) list):unit = // check that all module names are unique List.iter (fun ({mName = ifName; mIsImpl = ifImpl}, {mName = imName; mIsImpl = imImpl}) -> if ifName <> imName then err ("module interface and implementation have different names: " + ifName + ", " + imName) else if ifImpl then err ("expected module interface, found implementation: " + ifName) else if not imImpl then err ("expected module implementation, found interface: " + imName) else if (List.length (List.filter (fun ({mName = x}, _) -> ifName = x) ms) <> 1) then err ("more than one module named " + ifName)) ms; // For each variable x modified by xM, check that anyone yielding on x imports xM // For each variable x declared in xM but not modified by xM, check that no one yields on x List.iter (fun ({mName = xM; mModifies = xMods; mDecls = xDs}, _) -> List.iter (fun ({mName = yM; mYields = yYields}, {mName=_ (* mImports = yImports*) }) -> List.iter (fun (_, d) -> match d with | DStaticGhost (x, _, _, _) -> ( if List.mem x yYields && not (List.mem x xMods) then err ("module " + yM + " yields on non-exported variable " + x) ) | _ -> ()) xDs; List.iter (fun x -> // if List.mem x yYields && not (List.mem xM (yM::yImports)) then // This branch has no yield (concurrency) support, and the import // behavior has changed, so for now, we disallow all yields on the // grounds that we can't check the import sanity. if List.mem x yYields && true then err ("module " + yM + " must import " + xM + " to yield on variable " + x)) xMods) ms) ms; // check that definitions are well founded let _ = List.fold link_check_module [] ms in () let sw_reg (w:width) (r:reg): string = match (w, r) with | (W32, "EAX") -> "eax" | (W32, "EBX") -> "ebx" | (W32, "ECX") -> "ecx" | (W32, "EDX") -> "edx" | (W32, "ESI") -> "esi" | (W32, "EDI") -> "edi" | (W32, "EBP") -> "ebp" | (W32, "ESP") -> "esp" | (W16, "EAX") -> "ax" | (W16, "EBX") -> "bx" | (W16, "ECX") -> "cx" | (W16, "EDX") -> "dx" | (W8, "EAX") -> "al" | (W8, "EBX") -> "bl" | (W8, "ECX") -> "cl" | (W8, "EDX") -> "dl" | _ -> err "unexpected register" let s_reg (r:reg): string = sw_reg W32 r let seg_reg (r:reg): string = match r with // | "CS" -> "cs" | "DS" -> "ds" | "SS" -> "ss" | "FS" -> "fs" | "GS" -> "gs" | _ -> err "unexpected segment register" let simple_w_operand (w:width) (o:operand): string = match (w, o) with | (W32, OConst i) -> i | (_, OReg r) -> sw_reg w r | _ -> err "unexpected operand" let simple_operand (o:operand): string = simple_w_operand W32 o let src_operand (ctxt:string) (o:operand): string = match o with | OConst i -> i | OReg r -> s_reg r | _ -> err "unexpected operand" let r_operand (o:operand): string = match o with | OReg r -> s_reg r | _ -> err "unexpected reg operand" let addr_operand (o:operand): string = match o with (* TODO: check offset and scale *) (* TODO: 1-byte and 2-byte mems *) | OConstPtr i -> i | OOffset (r, i) -> (s_reg r) ^ " + " ^ (i) | OIndex (rb, s, rs, i) -> (s_reg rb) ^ " + " ^ (s) ^ " * " ^ (s_reg rs) ^ " + " ^ (i) | _ -> err "unexpected addr operand" let mem_operand (width:width) (o:operand): string = (string_of_width width) ^ " ptr [" ^ (addr_operand o) ^ "]" let src_mem_operand (ctxt:string) (width:width) (o:operand): string = match o with | OConst _ | OReg _ -> src_operand ctxt o | OConstPtr _ | OOffset _ | OIndex _ -> mem_operand width o | _ -> err "unexpected src_mem operand" let dest_mem_operand (ctxt:string) (width:width) (o:operand): string = match o with | OReg r -> s_reg r | OConstPtr _ | OOffset _ | OIndex _ -> mem_operand width o | _ -> err "unexpected dest_mem operand" let s_pair (s1:string) (s2:string): string = s1 ^ ", " ^ s2 let bin_operands (ctxt:string) (args:operand list): string = match args with | [_; OReg r1; o2] -> s_pair (s_reg r1) (src_operand ctxt o2) | _ -> err "unexpected bin operands" let bin_lock (args:operand list): string = match args with | _ when not !check_concurrent -> "" | [_; OReg r1; _] -> "" | _ -> "lock " let shift_operands (ctxt:string) (args:operand list): string = match args with | [_; OReg r1; OConst i] -> s_pair (s_reg r1) i | [_; OReg r1; OReg Ecx] -> s_pair (s_reg r1) "cl" | _ -> err "unexpected shift operands" let mul_operands (ctxt:string) (args:operand list): string = (* TODO: operand o3 cannot be a constant *) match args with | ([_; o3]) -> src_operand ctxt o3 | _ -> err "unexpected mul operands" let div_operands (ctxt:string) (args:operand list): string = (* TODO: operand o3 cannot be a constant *) match args with | [_; o3] -> r_operand o3 | _ -> err "unexpected div operands" let unary_operands1 (ctxt:string) (args:operand list): string = match args with | [_; o1] -> (dest_mem_operand ctxt W32 o1) | _ -> err "unexpected unary operands" let unary_operands_small (args:operand list): string = match args with | [_; OReg r1] -> (sw_reg W8 r1) | _ -> err "unexpected small unary operands" let unary_lock (args:operand list): string = match args with | _ when not !check_concurrent -> "" | [_; OReg r1] -> "" | _ -> "lock " let lea_operands (ctxt:string) (args:operand list): string = match args with | [_; OReg rd; o2] -> s_pair (s_reg rd) (mem_operand W32 o2) | _ -> err "unexpected lea operands" let lea_signed_index_operands (ctxt:string) (args:operand list): string = match args with | [_; OReg rd; OReg r1; OExp (Some c1); OReg r2; OConst c2] -> s_pair (s_reg rd) ("dword ptr [" ^ (s_reg r1) ^ " + " ^ (c1.ToString()) ^ " * " ^ (s_reg r2) ^ " + " ^ c2 ^ "]") | _ -> err "unexpected lea_signed operands" let load_operands (ctxt:string) (width:width) (args:operand list): string = match args with | [_; _; _; OReg rd; o2] -> s_pair (s_reg rd) (mem_operand width o2) | _ -> err "unexpected load operands" let iom_reg_load_operands (ctxt:string) (width:width) (args:operand list): string = match args with | [OExp _; OReg rd; o2] -> s_pair (s_reg rd) (mem_operand width o2) | _ -> err "unexpected iom_reg_load operands" let store_operands (ctxt:string) (width:width) (args:operand list): string = match args with | [_; _; _; o1; o2] -> s_pair (mem_operand width o1) (simple_w_operand width o2) | _ -> err "unexpected store operands" let idt_store_operands (ctxt:string) (width:width) (args:operand list): string = match args with | [OExp _; OExp _; OExp _; o1; o2] -> s_pair (mem_operand width o1) (simple_w_operand width o2) | _ -> err "unexpected idt store operands" let iom_reg_store_operands (ctxt:string) (width:width) (args:operand list): string = match args with | [OExp _; o1; o2] -> s_pair (mem_operand width o1) (simple_w_operand width o2) | _ -> err "unexpected iom_reg_store operands" let lidt_operands (ctxt:string) (args:operand list): string = match args with | [o] -> "fword ptr [" ^ (addr_operand o) ^ "]" | _ -> err "unexpected lidt operands" let cmp_operands (ctxt:string) (args:operand list): string = match args with (* TODO: o1 cannot be OConst *) (* TODO: support more cases ? *) | [_; OReg r1; o2] -> s_pair (s_reg r1) (src_mem_operand ctxt W32 o2) | [_; o1; OReg r2] -> s_pair (src_mem_operand ctxt W32 o1) (s_reg r2) | [_; o1; (OConst c2) as o2] -> s_pair (src_mem_operand ctxt W32 o1) (src_operand ctxt o2) | _ -> err "unexpected cmp operands" let cmpxchg_operands (ctxt:string) (args:operand list): string = match args with | [o1; OReg r2] -> s_pair (mem_operand W32 o1) (s_reg r2) | _ -> err "unexpected operands" let launch_operands (ctxt:string) (args:operand list): string = match args with | [_;_;_;_;_;_;_;_;_] -> "ebx" //(s_reg r) | _ -> err "unexpected launch operands" let print_ins (ctxt:string) (i:string) (args:operand list): unit = let bin s = print_endline (" " ^ (bin_lock args) ^ s ^ " " ^ (bin_operands ctxt args)) in let check_over () = print_endline " jc _?Overflow" in // Note: when check_concurrent is true, instructions with multiple memory accesses must be marked "lock" // (currently, these are just the bin_operands and unary_operands instructions whose destination is memory, plus cmpxchg) match i with | "DropTempRegs" -> () | "Mov" -> bin "mov" | "Not" -> print_endline (" " ^ (unary_lock args) ^ "not " ^ (unary_operands1 ctxt args)) | "Add" -> bin "add" | "AddCarry" -> bin "adc" | "AddChecked" -> bin "add"; check_over () | "Sub" -> bin "sub" | "SubChecked" -> bin "sub"; check_over () | "Mul" -> print_endline (" mul " ^ (mul_operands ctxt args)) | "Mul64" -> print_endline (" mul " ^ (mul_operands ctxt args)) | "MulChecked" -> print_endline (" mul " ^ (mul_operands ctxt args)); check_over () | "Div" -> print_endline (" div " ^ (div_operands ctxt args)) | "And" -> bin "and" | "Or" -> bin "or" | "Xor" -> bin "xor" | "Shl" -> print_endline (" shl " ^ (shift_operands ctxt args)) | "Shr" -> print_endline (" shr " ^ (shift_operands ctxt args)) | "Rol" -> print_endline (" rol " ^ (shift_operands ctxt args)) | "Ror" -> print_endline (" ror " ^ (shift_operands ctxt args)) | "GetCf" -> print_endline (" " ^ (unary_lock args) ^ "setc " ^ (unary_operands_small args)) | "Cmp" -> print_endline (" cmp " ^ (cmp_operands ctxt args)) // TODO | "Cmpxchg" -> print_endline (" lock cmpxchg " ^ (cmpxchg_operands ctxt args)) | "KeyboardDataIn8" -> print_endline " in al, 060h" | "KeyboardStatusIn8" -> print_endline " in al, 064h" | "SerialDbgConfigOut" -> print_endline " out dx, al" | "SerialDbgDataOut8" -> print_endline " out dx, al" | "SerialDbgStatusOut8" -> print_endline " in al, dx" (* | "SerialDbgDataIn8" -> print_endline " in al, dx" | "SerialDbgStatusIn8" -> print_endline " in al, dx" | "SampleIn32" -> print_endline (" rdrand eax") | "PicOut8" -> print_endline " out dx, al" | "PitModeOut8" -> print_endline " out 43h, al" | "PitFreqOut8" -> print_endline " out 40h, al" *) | "PciConfigAddrOut32" -> print_endline " out dx, eax" | "PciConfigDataOut32" -> print_endline " out dx, eax" | "PciConfigDataIn32" -> print_endline " in eax, dx" | "DEV_PciConfigDataOut32" -> print_endline " out dx, eax" | "DEV_PciConfigDataIn32" -> print_endline " in eax, dx" (* | "RoLoadU8" -> print_endline (" movzx " ^ (load_operands ctxt W8 args)) | "RoLoadS8" -> print_endline (" movsx " ^ (load_operands ctxt W8 args)) | "RoLoadU16" -> print_endline (" movzx " ^ (load_operands ctxt W16 args)) | "RoLoadS16" -> print_endline (" movsx " ^ (load_operands ctxt W16 args)) | "RoLoad32" | "SectionLoad" -> *) | "Load" -> print_endline (" mov " ^ (load_operands ctxt W32 args)) // | "IomRegLoad" | "PciMemLoad32" -> // print_endline (" mov " ^ (iom_reg_load_operands ctxt W32 args)) | "VgaTextStore16" -> print_endline (" mov " ^ (store_operands ctxt W16 ((OExp None)::args))) | "VgaDebugStore16" -> print_endline (" mov " ^ (store_operands ctxt W16 ((OExp None)::(OExp None)::args))) (* | "IdtStore" -> print_endline (" mov " ^ (idt_store_operands ctxt W32 args)) | "IomRegStore" | "PciMemStore32" -> print_endline (" mov " ^ (iom_reg_store_operands ctxt W32 args)) *) | "Store" -> print_endline (" mov " ^ (store_operands ctxt W32 args)) //| "SectionStore" | "IomStore" -> | "ghost_IomEnabled" -> print_endline " ; instr_ghost_IomEnabled" // TODO: this is not an instruction // | "Lidt" -> print_endline (" lidt " ^ (lidt_operands ctxt args)) | "Lea" -> print_endline (" lea " ^ (lea_operands ctxt args)) | "LeaUnchecked" -> print_endline (" lea " ^ (lea_operands ctxt args)) | "LeaSignedIndex" -> print_endline (" lea " ^ (lea_signed_index_operands ctxt args)) | "Rdtsc" -> print_endline (" rdtsc") | "Launch" -> print_endline (" jmp " ^ (launch_operands ctxt args)) | _ -> ( let load32 o1 o2 = print_endline (" mov " ^ (s_pair (r_operand o1) (mem_operand W32 o2))) in let store32 o1 o2 = print_endline (" mov " ^ (s_pair (mem_operand W32 o1) (simple_w_operand W32 o2))) in let load8 o1 o2 = print_endline (" movzx " ^ (s_pair (r_operand o1) (mem_operand W8 o2))) in let store8 o1 o2 = print_endline (" mov " ^ (s_pair (mem_operand W8 o1) (simple_w_operand W8 o2))) in match (i, args) with | ("DeviceLoad", [_; _; o1; o2]) -> load32 o1 o2 | ("DeviceStore", [_; _; o1; o2 ]) -> store32 o1 o2 | ("PciMemLoad32", [_; _; _; o1; o2]) -> load32 o1 o2 | ("PciMemStore32", [_; _; _; o1; o2]) -> store32 o1 o2 | ("ActivateDataSelector", [_; _; _; OExp _; OExp _; OReg r; OSelector s]) -> print_endline (" mov " ^ (s_pair (seg_reg s) (sw_reg W16 r))) | ("LoadGDT", [_; _; _; OExp _; OExp _; o]) -> print_endline (" lgdt fword ptr [" ^ (addr_operand o) ^ "]") | ("ReadCR0", [_; _; OReg r]) -> print_endline (" mov " ^ (s_reg r) ^ ", cr0") | ("WriteCR0", [_; _; OReg r]) -> print_endline (" mov cr0, " ^ (s_reg r) ) | ("WriteCR3", [_; _; OReg r]) -> print_endline (" mov cr3, " ^ (s_reg r) ) | ("IoMemAddrRead", [_;o1;o2]) -> load8 o1 o2 | ("IoMemAddrWrite", [_;o1;o2]) -> store8 o1 o2 | _ -> err ("instruction " ^ i ^ " : unsupported instruction or operands") ) let print_ins_group (inss:(string * string * operand list) list): unit = let inss = List.map (fun (c, i:string, a) -> if not (i.StartsWith("instr_")) then err ("unsupported instruction: " + i) else (c, i.Substring("instr_".Length), a)) inss in match inss with | [(ctxt, i, args)] -> print_ins ctxt i args | [(_, "SubNoFlags", [_; OReg "ESP"; OConst "4"]); (_, "StoreStack", [_; _; _; OOffset ("ESP", "0"); OReg r])] -> print_endline (" push " ^ (s_reg r)) | [(_, "Load", [_; _; _; OTmpReg "TMP1"; omem]); (_, "Sub", [_; OReg r; OTmpReg "TMP1"])] -> // TODO: check for yields print_endline (" sub " ^ (s_reg r) ^ ", " ^ (mem_operand W32 omem)) | [(_, "Load", [_; _; _; OTmpReg "TMP1"; omem]); (ctxt, "Cmp", [_; OTmpReg "TMP1"; (OReg _ | OConst _) as o2])] -> print_endline (" cmp " ^ (mem_operand W32 omem) ^ ", " ^ (src_operand ctxt o2)) | _ -> err ("unrecognized instruction group: " ^ (String.concat ", " (List.map (fun (_, i, _) -> i) inss))) let rec print_stmt_group (stmts:(insCtxt * loc * stmt) list): unit = let rec get_ins_group stmts = match stmts with | [] -> [] | ((ctxt, varMap), l, SInline (_, p, args, []))::tl -> (ctxt, p, (List.map (operand_of_exp varMap) args))::(get_ins_group tl) | (_, l, _)::_ -> err ("unrecognized instruction at location " ^ (string l)) let print_yielded stmts = match stmts with | [] -> () | [((ctxt, _), _, SGoto l)] -> print_endline (" jmp " ^ (label ctxt l)) | [ins1; ins2; ins3; ins4; (_, l, SReturn)] -> ( match get_ins_group [ins1; ins2; ins3; ins4] with | [(_, "instr_LoadStack", [_; _; _; OTmpReg "TMP1"; OOffset ("ESP", "0")]); (_, "instr_AddNoFlags", [_; OReg "ESP"; OConst "4"]); (_, "instr_Ret", _); (_, "instr_DropTempRegs", _)] when not !x64 -> print_endline " ret" | inss -> err ("at location " ^ (string l) ^ ": incorrect (32-bit) ret: " ^ (String.concat ", " (List.map (fun (_, i, _) -> i) inss))) ) | [ins1; ins2; ins3; ins4; ins5; (_, l, SReturn)] -> ( match get_ins_group [ins1; ins2; ins3; ins4; ins5] with //64 bit return | [(_, "instr_LoadStack", [_; _; _; OTmpReg "TMP1"; OOffset ("ESP", "0")]); (_, "instr_LoadStack", [_; _; _; OTmpReg "TMP2"; OOffset ("ESP", "4")]); (_, "instr_AddNoFlags", [_; OReg "ESP"; OConst "8"]); (_, "instr_Ret", _); (_, "instr_DropTempRegs", _)] when !x64 -> print_endline " ret" | inss -> err ("at location " ^ (string l) ^ ": incorrect (64-bit) ret: " ^ (String.concat ", " (List.map (fun (_, i, _) -> i) inss))) ) // TODO: | [(_, _, SInline ("instr_IRet", [])); (_, _, SIReturn)] -> print_endline " iretd" | [((ctxt, _), _, SIfJcc (_, jcc, l))] -> ( // REVIEW: maybe redesign the AST rather than matching on strings? match jcc with | "Je" | "Jne" | "Jbe" | "Jb" | "Jae" | "Ja" -> print_endline (" " ^ (jcc.ToLower ()) ^ " " ^ (label ctxt l)) | _ -> err ("unexpected conditional jump: " + jcc) ) | [ins1; ins2; ins3; (_, l, SCall (_, p, _))] -> ( match get_ins_group [ins1; ins2; ins3] with | [(_, "instr_SubNoFlags", [_; OReg "ESP"; OConst "4"]); (_, "instr_MovNextEip32", [_; OTmpReg "TMP1"]); (_, "instr_StoreStack", [_; _; _; OOffset ("ESP", "0"); OTmpReg "TMP1"]); ] when not !x64 -> print_endline (" call " ^ (proc_name p)) | inss -> err ("at location " ^ (string l) ^ ": incorrect (32-bit) call: " ^ (String.concat ", " (List.map (fun (_, i, _) -> i) inss))) ) //64 bit call | [ins1; ins2; ins3; ins4; (_, l, SCall (_, p, _))] -> ( match get_ins_group [ins1; ins2; ins3; ins4] with | [(_, "instr_SubNoFlags", [_; OReg "ESP"; OConst "8"]); (_, "instr_MovNextEip64", [_; OTmpReg "TMP1"; OTmpReg "TMP2"]); (_, "instr_StoreStack", [_; _; _; OOffset ("ESP", "0"); OTmpReg "TMP1"]); (_, "instr_StoreStack", [_; _; _; OOffset ("ESP", "4"); OTmpReg "TMP2"]); ] when !x64 -> print_endline (" call " ^ (proc_name p)) | inss -> err ("at location " ^ (string l) ^ ": incorrect (64-bit) call: " ^ (String.concat ", " (List.map (fun (_, i, _) -> i) inss))) ) | (_, l, _)::_ -> try print_ins_group (get_ins_group stmts) with Err e -> err ("at location " ^ (string l) ^ ": " ^ (string e)) in match stmts with | [] -> () | [((ctxt, _), _, SLabel l)] -> print_endline (" " ^ label ctxt l ^ ":") | (_, _, SYield _)::tl -> print_yielded tl | _ when not !check_concurrent -> print_yielded stmts | (_, l, _)::_ -> err ("missing yield before instruction at location " ^ (string l)) // expand all inline procedure calls, and eliminate ghost operations let rec expand_inline_calls (ic:insCtxt) (InlineMap inlines) (l:loc, s:stmt):(insCtxt * loc * stmt) list list = match s with | SLabel _ | SGoto _ | SReturn | SIReturn | SYield _ | SIfJcc _ | SCall _ -> [[(ic, l, s)]] | SAssert _ | SSplit | SAssign _ | SIfGhost _ | SForallGhost _ | SExistsGhost _ -> [] | SGroup b -> [List.concat (List.collect (expand_inline_calls ic (InlineMap inlines)) b)] | SInline (_, p, _, []) when p.StartsWith("instr_") -> [[(ic, l, s)]] | SInline (_, p, _, []) when p.StartsWith("construct##") -> [] | SInline (_, p, _, []) when p.StartsWith("destruct##") -> [] | SInline (_, p, args, _) -> let (_, varMap) = ic in let (inline_inlines, inline_ic, stmts) = try List.assoc p inlines (List.map (operand_of_exp varMap) args) with :? System.Collections.Generic.KeyNotFoundException as x -> err ("at location " ^ (string l) ^ ": procedure " ^ p ^ " not found") in List.collect (expand_inline_calls inline_ic inline_inlines) stmts let print_decl (inlines:inlineMap) (_, d:decl): unit = match d with | DType _ -> () | DFunDecl (x, None, _, Some (EInt i), None, _) when BigInt.Zero <= i && i < (BigInt.Parse "4294967296") -> print_endline ("?_" ^ x ^ " EQU " ^ ((string)i)) | DFunDecl _ -> () | DStatic x -> print_endline ".data"; print_endline "align 4"; print_endline ("?_?ADDR__" ^ x ^ " DD 0") | DStaticGhost _ -> () | DProc (p, pk, Inline, ps, _, _, Some (_, b)) -> () | DProc (p, _, Outline, _, _, _, Some (_, b)) -> print_endline ".code"; print_endline "align 16"; print_endline ((proc_name p) ^ " proc"); let stmts = List.collect (expand_inline_calls (p, []) inlines) b in List.iter print_stmt_group stmts; print_endline ((proc_name p) ^ " endp") | DProc (_, _, _, _, _, _, None) -> () #nowarn "40" let rec print_modules (ghost_procs:string list) (InlineMap inlines) (p:(_module * _module) list): unit = let find_all_procs (_, d:decl) = match d with | DType _ | DFunDecl _ | DStatic _ | DStaticGhost _ -> [] | DProc (x, pk, _, _, _, _, _) -> [x] let find_ghost_procs (_, d:decl) = match d with | DType _ | DFunDecl _ | DStatic _ | DStaticGhost _ -> [] | DProc (x, pk, _, _, _, _, _) -> (match pk with Implementation -> [] | Procedure (PReal, _) -> [] | Procedure (PGhost, _) -> [x]) let add_inline (ghost_procs:string list) (_, d:decl):inlinePreMap = match d with | DType _ | DFunDecl _ | DStatic _ | DStaticGhost _ -> [] | DProc (_, _, _, _, _, _, None) -> [] | DProc (p, pk, inlining, ps, _, _, Some (_, b)) -> [(p, fun args -> match inlining with | Inline -> let ctxt = gensym () in let varMap = List.zip (List.map (fun (x, _, _) -> x) ps) args in let stmts = if List.mem p ghost_procs then [] else b in ((ctxt, varMap), stmts) | Outline -> err ("cannot inline " ^ p))] in match p with | [] -> () | (intf, impl)::ms -> let intf_procs = List.collect find_all_procs intf.mDecls in let intf_ghost_procs = (List.collect find_ghost_procs intf.mDecls) @ ghost_procs in let impl_ghost_procs = (List.collect find_ghost_procs impl.mDecls) @ intf_ghost_procs in let inft_pre_inlines = List.collect (add_inline intf_ghost_procs) intf.mDecls in let impl_pre_inlines = List.collect (add_inline impl_ghost_procs) impl.mDecls in let pre_inlines = inft_pre_inlines @ impl_pre_inlines in let rec lazy_impl_inlines = lazy (List.map (fun (x, f) -> (x, fun args -> let (ic, ss) = f args in (InlineMap (lazy_impl_inlines.Force() @ inlines), ic, ss))) pre_inlines) in let impl_inlines = lazy_impl_inlines.Force() in let intf_inlines = List.filter (fun (x, _) -> List.mem x intf_procs) impl_inlines in print_endline (";; BEGIN_MODULE: " + impl.mName); List.iter (print_decl (InlineMap (intf_inlines @ inlines))) intf.mDecls; List.iter (print_decl (InlineMap (impl_inlines @ inlines))) impl.mDecls; print_endline (";; END_MODULE: " + impl.mName); print_modules intf_ghost_procs (InlineMap (intf_inlines @ inlines)) ms let rec print_program (inlines:inlineMap) (p:(_module * _module) list): unit = //if not !x64 then ( print_endline ".686p"; print_endline ".model flat"; //); print_modules [] inlines p; print_endline "end"; () (* Each command-line argument is the name of a module *) (* Each module M must contain two files: M_i.bpl and M.bpl *) let main (argv) = let print_error_prefix () = print_endline ("error near line " + (string !line) + " of file " + !file) in try ( let mods_rev = ref ([]:(bool * string) list) in let link = ref false in let outfile = ref (None:string option) in let symdiff_file = ref (None:string option) in let distinctLinearInts = ref false in let add_mod (trusted:bool) (s:string) = mods_rev := (trusted, s)::(!mods_rev) in Arg.parse_argv (ref 0) argv [ ("-trusted" , Arg.String (add_mod true), "Trusted module"); ("-verify" , Arg.Clear link , "Verify single module"); ("-link" , Arg.Set link , "Link modules together and generate code"); ("-symdiffok" , Arg.Set symdiff_allow, "Allow relational specifications for symdiff"); ("-symdiffms" , Arg.String (fun s -> symdiff_allow := true; symdiff := true; symdiff_file := Some s), "Generate symdiff mutual summary file for relational checks"); ("-distinctLinearInts", Arg.Set distinctLinearInts, "Use axioms ensuring distinctness of linear integers (sound, but may be slow)"); ("-out" , Arg.String (fun s -> outfile := Some s) , "Specify output file"); ("-def" , Arg.String (fun s -> Lex.macros := Map.add s [] !Lex.macros), "Define a macro (as an empty string) for use by ifdef/ifndef"); ("-x64" , Arg.Set x64 , "Compile 64 bit binaries"); ] (add_mod false) "error parsing arguments"; let mods = List.rev (!mods_rev) in let parse_file comment name = print_endline (comment + "parsing " + name); file := name; line := 1; Parse.start Lex.token (Lexing.from_channel (open_in name)) in if !link then let (_, modIfcs, modImps) = List.foldBack (fun (_, x) (b, l1, l2) -> (not b, (if b then l1 else x::l1), (if b then x::l2 else l2))) mods (true, [], []) in let modIfcImps = List.combine modIfcs modImps in let modules = List.map (fun (xIfc, xImp) -> (parse_file ";;" xIfc, parse_file ";;" xImp)) modIfcImps in link_check_modules modules; print_program (InlineMap []) modules else (match !symdiff_file with None -> () | Some s -> symdiff_writer := ((new System.IO.StreamWriter(new System.IO.FileStream(s, System.IO.FileMode.Create))):>System.IO.TextWriter)); let stream = match !outfile with | None -> System.Console.Out | Some s -> (new System.IO.StreamWriter(new System.IO.FileStream(s, System.IO.FileMode.Create))):>System.IO.TextWriter in if (!distinctLinearInts) then ( stream.WriteLine ("function {:builtin \"MapConst\"} MapConstBool(bool) : [int]bool;"); stream.WriteLine ("function {:inline} {:linear \"our\"} LinearIntDistinctness(x:int) : [int]bool { MapConstBool(false)[x := true] }") ); let xms_rev = List.fold (fun xms_rev (_, x:string) -> if x.StartsWith("/trustedBoogie:") then let x = x.Substring("/trustedBoogie:".Length) in let f = new System.IO.StreamReader(new System.IO.FileStream(x, System.IO.FileMode.Open, System.IO.FileAccess.Read)) in stream.WriteLine ("#line 1 " + x); stream.WriteLine (f.ReadToEnd()); f.Close (); xms_rev else let m = parse_file "//" x in (x, m)::xms_rev) [] mods in let ms_rev = List.map snd xms_rev in (match ms_rev with | [] -> () | {mIsImpl = false}::_ -> () | ({mName = imName; mIsImpl = true} as m)::({mName = ifName; mIsImpl = false} as i)::ifs when imName = ifName -> check_module (List.rev ifs) i m | _ -> err "expected last file to be interface, or last two files to be interface/implementation"); stream.WriteLine ("#line 1 fake entry point"); let publics = List.collect (fun m -> if m.mIsImpl then [] else m.mDecls) ms_rev in let impls = List.collect (fun m -> if m.mIsImpl then m.mDecls else []) ms_rev in let all_vars = List.collect (fun (_, d) -> match d with DStaticGhost (x, _, _, _) -> [x] | _ -> []) publics in let all_typedefs = List.collect (fun (_, d) -> match d with DType (x, _, _, Some _) -> [x] | _ -> []) impls in let all_procs = List.collect (fun (_, d) -> match d with DProc ((x, Procedure _, _, _, _, _, _) as p) -> [(x, p)] | _ -> []) (publics @ impls) in let ctxt x = { all_vars = (if !check_concurrent then all_vars else []); all_typedefs = all_typedefs; all_procs = all_procs; publics = publics; print_out = stream; cur_loc = ref (x, 1); cur_indent = ref ""; } in // TODO: (if not !symdiff then emit_entry_point { print_out = stream; cur_loc = ref ("fake entry point", 1); cur_indent = ref ""; } publics); stream.WriteLine("function {:linear \"our\"} OurCollector(x:[int]bool):[int]bool { x }"); List.iter (fun (x, m) -> (if !symdiff then symdiff_globals := (List.collect (fun (_, d) -> match d with DStaticGhost (x, t, lin, _) -> [(x, t, lin)] | _ -> []) (List.collect (fun m -> m.mDecls) (List.rev ms_rev))); symdiff_consts := (List.collect (fun (_, d) -> match d with DFunDecl (x, None, _, _, _, _) -> [x] | _ -> []) (List.collect (fun m -> m.mDecls) (List.rev ms_rev)))); stream.WriteLine ("#line 1 " + x); emit_module (ctxt x) m) (List.rev xms_rev); (if !symdiff then (!symdiff_writer).Close ()); stream.Close () ) with | (Err s) as x -> (print_endline "error:"; print_endline s; print_endline (x.ToString ()); exit 1) | ParseErr x -> (print_error_prefix (); print_endline x; exit 1) | :? System.ArgumentException as x -> (print_error_prefix (); print_endline (x.ToString ()); exit 1) | Failure x -> (print_error_prefix (); print_endline x; exit 1) | x -> (print_endline (x.ToString ()); exit 1) ;; (* TODO: check that procedure implementations are correctly placed and not duplicated? *) (* TODO: check that no procedures are recursive, even if they aren't used (e.g. readField) *) let () = main (System.Environment.GetCommandLineArgs ()) ================================================ FILE: ironclad-apps/tools/BoogieAsm/makefile ================================================ # # Copyright (c) 2007 Microsoft Corporation. All rights reserved. # BUILD = ..\fsharp FSC = $(BUILD)\fsc -g FSLEX = $(BUILD)\fslex FSYACC = $(BUILD)\fsyacc CORE = . CSC = %SystemRoot%\Microsoft.NET\Framework\v4.0.30319\csc.exe CSC0 = ..\..\..\base\build-private\v4.0.30319\csc.exe CSC1 = ..\..\..\base\build-private\v4.0.30319-Windows8.1\csc.exe SRC = \ $(CORE)\ast.fs \ $(CORE)\parse_util.fs \ $(OBJ)\parse.fs \ $(OBJ)\lex.fs \ $(CORE)\emit_bpl.fs \ $(CORE)\main.fs \ all: $(OBJ) $(BIN) $(BIN)\boogieasm.exe $(BIN)\symdiffmerge.exe $(OBJ): md $(OBJ) $(BIN): md $(BIN) $(OBJ)\lex.fsi $(OBJ)\lex.fs: $(CORE)\lex.fsl $(FSLEX) $(CORE)\lex.fsl -o $(OBJ)\lex.fs $(OBJ)\parse.fsi $(OBJ)\parse.fs: $(CORE)\parse.fsy $(FSYACC) -v $(CORE)\parse.fsy -o $(OBJ)\parse.fs $(BIN)\boogieasm.exe: $(SRC) $(FSC) --standalone --mlcompatibility -O $(SRC) -o $(BIN)\boogieasm.exe -r FSharp.PowerPack.dll $(BIN)\symdiffmerge.exe: SymdiffMerge.cs if exist $(CSC). ($(CSC) /debug+ /out:$(BIN)\symdiffmerge.exe SymdiffMerge.cs.) else ($(CSC0) /debug+ /out:$(BIN)\dafnycc.exe SymdiffMerge.cs.) clean: del /q $(BIN)\boogieasm.exe del /q $(OBJ)\*.fs ================================================ FILE: ironclad-apps/tools/BoogieAsm/makefile.fs ================================================ #light module MakeBoogieAsm open Def let env = Def.env.Cd @"tools\boogieasm" let obj = Def.obj +/ @"boogieasm" let bin = Def.bin +/ @"boogieasm" env.Dep "all" <| [bin+/"boogieasm.exe"] <| fun () -> () env.Dep obj <| [] <| fun () -> env.Mkdir obj env.Dep bin <| [] <| fun () -> env.Mkdir bin env.Fslex (obj+/"lex.fs") [obj] [] ["lex.fsl"] env.Fsyacc (obj+/"parse.fs") [obj] [] ["parse.fsy"] env.Fsc (bin+/"boogieasm.exe") [bin] (split "--standalone --mlcompatibility -O -r FSharp.PowerPack.dll") ["ast.fs"; "parse_util.fs"; obj+/"parse.fs"; obj+/"lex.fs"; "main.fs"] ================================================ FILE: ironclad-apps/tools/BoogieAsm/nubuild-manifest.txt ================================================ dependency ast.fs dependency emit_bpl.fs dependency lex.fsl dependency main.fs dependency makefile dependency makefile.fs dependency parse.fsy dependency parse_util.fs dependency SymdiffMerge.cs output boogieasm.exe output symdiffmerge.exe ================================================ FILE: ironclad-apps/tools/BoogieAsm/parse.fsy ================================================ %{ open Ast;; open Parse_util;; open Microsoft.FSharp.Math;; let rec type_id (t:typ):id = match t with | TInt -> "int" | TBool -> "bool" | TReal -> "real" | TMap (t1, t2) -> "__ARR1_" + (type_id t1) + "__ARR2_" + (type_id t2) + "__ARR3_" | TName x -> "__NAME_" + x let option_type_id (t:typ):id = "__OPTION_" + (type_id t) let maybe_relation (e:exp):(is_relation * exp) = match e with EOp ((Uop "relation"), [e1]) -> (IsRel, e1) | _ -> (NotRel, e) %} %start start %type <_module> start %token UID %token LID %token DUID %token DLID %token QUID %token QLID %token SEGNAME %token REGNAME %token LITINT %token LITREAL %token LITBV32 %token LITBOOL %token SEMI LPAREN RPAREN LBRACKET RBRACKET BAR DOT HASH %token LT GT EQ BANG COMMA LE GE EQEQ NE PLUS MINUS STAR SLASH DIV MOD AMPAMP BARBAR INT REAL BOOL %token HAVOC OLD COLONCOLON EQEQGT LTEQEQGT LTLT GTGT %token LEFT RIGHT RELATION PUBLIC %token EAX EBX ECX EDX ESI EDI EBP ESP %token OPNREG OPNMEM IS THEN ELSE LET IN LINEAR SPLIT MY ATOMIC STABLE GHOST %token TYPE VAR CONST READONLY FUNCTION AXIOM PROCEDURE IMPLEMENTATION STATIC MODULE INTERFACE IMPORT %token CALL RETURN IRETURN IF GOTO ASSERT INVARIANT COLON COLONEQ YIELD LBRACE RBRACE %token RETURNS REQUIRES ENSURES MODIFIES %token FORALL EXISTS LAMBDA %token EOF /* Precedence declarations. */ %right LET IN IF THEN ELSE %left LTEQEQGT %right EQEQGT %left AMPAMP BARBAR %left LT GT LE GE EQEQ NE IS %left PLUS MINUS %left STAR SLASH DIV MOD %right BANG %left LPAREN RPAREN LBRACKET RBRACKET DOT %% start: | MODULE INTERFACE AnyId Imports Modifies Yields LBRACE Decls RBRACE EOF { {mName = $3; mIsImpl = false; mModifies = $5; mYields = $6; mDecls = $8} } | MODULE IMPLEMENTATION AnyId LBRACE Decls RBRACE EOF { {mName = $3; mIsImpl = true; mModifies = []; mYields = []; mDecls = $5} } | MODULE INTERFACE AnyId Imports Modifies Yields Decls EOF { {mName = $3; mIsImpl = false; mModifies = $5; mYields = $6; mDecls = $7} } | MODULE IMPLEMENTATION AnyId Decls EOF { {mName = $3; mIsImpl = true; mModifies = []; mYields = []; mDecls = $4} } ID : LID { $1 } | UID { $1 } Type : INT { TInt } | BOOL { TBool } | REAL { TReal } | LBRACKET Type RBRACKET Type { TMap ($2, $4) } | AnyId { TName $1 } | LTLT Type GTGT { TName (option_type_id $2) } Triggers : { [] } | LBRACE Exps RBRACE Triggers { $2::$4 } Exp : LPAREN Exp RPAREN { $2 } | IF Exp THEN Exp ELSE Exp { EOp (Cond, [$2; $4; $6]) } | LET Formal COLONEQ Exp IN Exp { EOp (Subscript, [EQuant (Lambda, [$2], [], $6); $4]) } | Exp LTEQEQGT Exp { EOp (Bop "<==>", [$1; $3]) } | Exp EQEQGT Exp { EOp (Bop "==>", [$1; $3]) } | Exp AMPAMP Exp { EOp (Bop "&&", [$1; $3]) } | Exp BARBAR Exp { EOp (Bop "||", [$1; $3]) } | Exp EQEQ Exp { EOp (Bop "==", [$1; $3]) } | Exp NE Exp { EOp (Bop "!=", [$1; $3]) } | Exp LT Exp { EOp (Bop "<", [$1; $3]) } | Exp GT Exp { EOp (Bop ">", [$1; $3]) } | Exp LE Exp { EOp (Bop "<=", [$1; $3]) } | Exp GE Exp { EOp (Bop ">=", [$1; $3]) } | Exp PLUS Exp { EOp (Bop "+", [$1; $3]) } | Exp MINUS Exp { EOp (Bop "-", [$1; $3]) } | Exp STAR Exp { EOp (Bop "*", [$1; $3]) } | Exp SLASH Exp { EOp (Bop "/", [$1; $3]) } | Exp DIV Exp { EOp (Bop " div ", [$1; $3]) } | Exp MOD Exp { EOp (Bop " mod ", [$1; $3]) } | Exp IS AnyId { EApply ("is#" + $3, [$1]) } | LPAREN MINUS Exp RPAREN { EOp (Uop "-", [$3]) } | BANG Exp { EOp (Uop "!", [$2]) } | LPAREN FORALL Formals COLONCOLON Triggers Exp RPAREN { EQuant (Forall, $3, $5, $6) } | LPAREN EXISTS Formals COLONCOLON Triggers Exp RPAREN { EQuant (Exists, $3, $5, $6) } | LPAREN LAMBDA Formals COLONCOLON Exp RPAREN { EQuant (Lambda, $3, [], $5) } | Exp LBRACKET Exp RBRACKET { EOp (Subscript, [$1; $3]) } | Exp LBRACKET Exp COLONEQ Exp RBRACKET { EOp (Update, [$1; $3; $5]) } | Exp DOT AnyId { EApply ("." + $3, [$1]) } | LET LTLT Type GTGT Formal COLONEQ Exp IN Exp { let (x, tx) = $5 in let o = option_type_id $3 in let ox = option_type_id tx in EOp (Cond, [EApply ("is#" + ox + "_None", [$7]); EApply (o + "_None", []); EOp (Subscript, [EQuant (Lambda, [$5], [], $9); EApply ("." + ox + "_Value", [$7])])]) } | LTLT Type GTGT LPAREN Exp RPAREN { let o = option_type_id $2 in EApply (o + "_Some", [$5]) } | LTLT Type GTGT LPAREN RPAREN { let o = option_type_id $2 in EApply (o + "_None", []) } | Exp DOT LTLT Type GTGT { let o = option_type_id $4 in EApply ("." + o + "_Value", [$1]) } | LITINT { EInt $1 } | LITREAL { EReal $1 } | LITBV32 { EBv32 $1 } | LITBOOL { EBool $1 } | OLD LPAREN Exp RPAREN { EOp (Uop "old", [$3]) } | LEFT LPAREN Exp RPAREN { EOp (Uop "left", [$3]) } | RIGHT LPAREN Exp RPAREN { EOp (Uop "right", [$3]) } | RELATION LPAREN Exp RPAREN { EOp (Uop "relation", [$3]) } | PUBLIC LPAREN Exp RPAREN { EOp (Uop "relation", [EOp (Bop "==", [EOp (Uop "left", [$3]); EOp (Uop "right", [$3])])]) } | AnyId LPAREN Exps RPAREN { EApply ($1, $3) } | AnyId HASH AnyId LPAREN Exps RPAREN { EApply ($1 + "#" + $3, $5) } | AnyId HASH HASH AnyId LPAREN Exps RPAREN { EApply ($1 + "##" + $4, $6) } | REAL LPAREN Exp RPAREN { EOp (Uop "real", [$3]) } | INT LPAREN Exp RPAREN { EOp (Uop "int", [$3]) } | AnyId { EVar $1 } | SEGNAME { EVar $1 } | REGNAME { EVar $1 } Exps : { [] } | Exp { [$1] } | Exp COMMA Exps { $1::$3 } AnyId : ID { $1 } | DUID { $1 } | DLID { $1 } | QUID { $1 } | QLID { $1 } AnyIds : { [] } | AnyId { [$1] } | AnyId COMMA AnyIds { $1::$3 } FunDeclId : AnyId { $1 } | DOT AnyId { "." ^ $2 } ParCalls : { [] } | BAR LID LPAREN Exps RPAREN ParCalls { ($2, $4)::$6 } Stmt : ID COLON { ($2, SLabel $1) } | GOTO ID SEMI { ($1, SGoto $2) } | RETURN SEMI { ($1, SReturn) } | IRETURN SEMI { ($1, SIReturn) } | LBRACE COLON Block COLON RBRACE { ($2, SGroup $3) } | IF LPAREN Exp RPAREN LBRACE Block RBRACE { match ($3, $6) with | (EApply (f, [EApply (".efl", [EVar x])]), [(_, SGoto l)]) -> ($1, SIfJcc (x, f, l)) | _ -> ($1, SIfGhost ($3, $6)) } | FORALL LocalFormals COLONCOLON Triggers Exp LBRACE ProcDecls Block RBRACE { let decls = List.map (fun (x, t, lin) -> match lin with Non -> (x, t) | Lin _ -> err "cannot declare linear variable in forall statement") $7 in ($1, SForallGhost ($2, $4, $5, decls, $8)) } | EXISTS LocalFormals COLONCOLON Triggers Exp SEMI { ($1, SExistsGhost ($2, $4, $5)) } | INVARIANT Exp SEMI { ($1, let (r, e) = maybe_relation $2 in SAssert (IsInv r, e)) } | ASSERT Exp SEMI { ($1, SAssert (NotInv, $2)) } | ASSERT LBRACE SPLIT RBRACE LITBOOL SEMI { ($1, if $5 then SSplit else parse_err "Must use: assert {:split_here} true;" ) } | YIELD Exp SEMI { ($1, SYield $2) } | AnyId COLONEQ Exp SEMI { ($2, SAssign ($1, $3)) } | LET AnyId COLONEQ AnyId LPAREN Exps RPAREN SEMI { ($3, SInline ([$2], "construct##" ^ $4, $6, [])) } | LET AnyId LPAREN AnyIds RPAREN COLONEQ Exp SEMI { ($6, SInline ($4, "destruct##" ^ $2, [$7], [])) } | CALL LID LPAREN Exps RPAREN ParCalls SEMI { ($1, SInline ([], $2, $4, $6)) } | CALL AnyIds COLONEQ LID LPAREN Exps RPAREN ParCalls SEMI { ($1, SInline ($2, $4, $6, $8)) } | CALL UID LPAREN Exps RPAREN SEMI { ($1, SCall ([], $2, $4)) } | CALL AnyIds COLONEQ UID LPAREN Exps RPAREN SEMI { ($1, SCall ($2, $4, $6)) } Block : { [] } | Stmt Block { $1::$2 } ProcDecls : { [] } | VAR AnyId COLON Type SEMI ProcDecls { ($2, $4, Non)::$6 } | LINEAR VAR AnyId COLON Type SEMI ProcDecls { ($3, $5, Lin (LinVar, LinOur))::$7 } | MY VAR AnyId COLON Type SEMI ProcDecls { ($3, $5, Lin (LinVar, LinMy))::$7 } Formal : AnyId COLON Type { ($1, $3) } Formals : { [] } | Formal { [$1] } | Formal COMMA Formals { $1::$3 } LocalFormal : AnyId COLON Type { ($1, $3) } LocalFormals : { [] } | LocalFormal { [$1] } | LocalFormal COMMA LocalFormals { $1::$3 } ProcFormal : AnyId COLON Type { ($1, $3, Non) } | LINEAR AnyId COLON Type { ($2, $4, Lin (LinVar, LinOur)) } | MY AnyId COLON Type { ($2, $4, Lin (LinVar, LinMy)) } | CONST LINEAR AnyId COLON Type { ($3, $5, Lin (LinConst, LinOur)) } | CONST MY AnyId COLON Type { ($3, $5, Lin (LinConst, LinMy)) } ProcFormals : { [] } | ProcFormal { [$1] } | ProcFormal COMMA ProcFormals { $1::$3 } Spec : REQUIRES Exp SEMI { ($1, let (r, e) = maybe_relation $2 in Requires (r, e)) } | ENSURES Exp SEMI { ($1, let (r, e) = maybe_relation $2 in Ensures (r, e)) } | MODIFIES AnyIds SEMI { ($1, Modifies $2) } Specs : { [] } | Spec Specs { $1::$2 } TypeCase : AnyId LPAREN ProcFormals RPAREN { (Non, $1, $3) } | MY AnyId LPAREN ProcFormals RPAREN { (Lin (LinVar, LinMy), $2, $4) } | LINEAR AnyId LPAREN ProcFormals RPAREN { (Lin (LinVar, LinOur), $2, $4) } TypeCases : { [] } | TypeCase { [$1] } | TypeCase BAR TypeCases { $1::$3 } AnyIdExp: AnyId { $1 } | LPAREN AnyIdExp RPAREN { $2 } AnyIdExps : { [] } | AnyIdExp { [$1] } | AnyIdExp COMMA AnyIdExps { $1::$3 } AnyIdLists : { ([], "") } | LPAREN AnyIdExps RPAREN AnyIdLists { ($2 @ (fst $4), "(" + (String.concat "," $2) + ")" + (snd $4)) } FunAttr : { None } | LBRACE COLON ID LITBOOL RBRACE { assrt ($3 = "expand" || $3 = "never_pattern"); Some ($3 + " " + (if $4 then "true" else "false")) } GhostOpt: { PReal } | GHOST { PGhost } ProcOrImpl : GhostOpt PROCEDURE { ($2, Procedure ($1, Yields)) } | ATOMIC GhostOpt PROCEDURE { ($3, Procedure ($2, Atomic)) } | STABLE GhostOpt PROCEDURE { ($3, Procedure ($2, Stable)) } | IMPLEMENTATION { ($1, Implementation) } ProcRet : { [] } | RETURNS LPAREN ProcFormals RPAREN { $3 } FunRet : RETURNS LPAREN Type RPAREN { $3 } | RETURNS LPAREN AnyId COLON Type RPAREN { $5 } | COLON Type { $2 } Decl : TYPE AnyId SEMI { ($1, DType ($2, false, false, None)) } | TYPE AnyId EQ TypeCases SEMI { ($1, DType ($2, false, false, Some $4)) } | TYPE LBRACE COLON ID RBRACE AnyId EQ TypeCases SEMI { assrt ($4 = "overload"); ($1, DType ($6, true, false, Some $8)) } | TYPE LTLT Type GTGT SEMI { let o = option_type_id $3 in ($1, DType (o, false, false, Some [(Non, o + "_None", []); (Non, o + "_Some", [(o + "_Value", $3, Non)])])) } | TYPE IMPLEMENTATION AnyId EQ TypeCases SEMI { ($1, DType ($3, false, true, Some $5)) } | TYPE IMPLEMENTATION LBRACE COLON ID RBRACE AnyId EQ TypeCases SEMI { assrt ($5 = "overload"); ($1, DType ($7, true, true, Some $9)) } | VAR AnyId COLON Type SEMI { ($1, DStaticGhost ($2, $4, Non, ReadWrite)) } | READONLY VAR AnyId COLON Type SEMI { ($1, DStaticGhost ($3, $5, Non, Readonly)) } | LINEAR VAR AnyId COLON Type SEMI { ($2, DStaticGhost ($3, $5, Lin (LinVar, LinOur), ReadWrite)) } | STATIC AnyId SEMI { ($1, DStatic $2) } | ProcOrImpl LID LPAREN ProcFormals RPAREN ProcRet SEMI Specs { assrt (match $1 with (_, Procedure _) -> true | _ -> false); (fst $1, DProc ($2, snd $1, Inline, $4, $6, $8, None)) } | ProcOrImpl UID LPAREN ProcFormals RPAREN ProcRet SEMI Specs { assrt (match $1 with (_, Procedure _) -> true | _ -> false); (fst $1, DProc ($2, snd $1, Outline, $4, $6, $8, None)) } | ProcOrImpl LID LPAREN ProcFormals RPAREN ProcRet Specs LBRACE ProcDecls Block RBRACE { (fst $1, DProc ($2, snd $1, Inline, $4, $6, $7, Some ($9, $10))) } | ProcOrImpl UID LPAREN ProcFormals RPAREN ProcRet Specs LBRACE ProcDecls Block RBRACE { (fst $1, DProc ($2, snd $1, Outline, $4, $6, $7, Some ($9, $10))) } | CONST AnyId COLON Type SEMI { ($1, DFunDecl ($2, None, Some $4, None, None, None)) } | CONST AnyId COLON Type COLONEQ Exp SEMI { ($1, DFunDecl ($2, None, Some $4, Some $6, None, None)) } | CONST SEGNAME COLON Type COLONEQ Exp SEMI { ($1, DFunDecl ($2, None, Some $4, Some $6, None, None)) } | CONST REGNAME COLON Type COLONEQ Exp SEMI { ($1, DFunDecl ($2, None, Some $4, Some $6, None, None)) } | FUNCTION FunAttr FunDeclId LPAREN Formals RPAREN FunRet LBRACE Exp RBRACE { ($1, DFunDecl ($3, Some $5, Some $7, Some $9, $2, None)) } | FUNCTION FunAttr FunDeclId LPAREN Formals RPAREN FunRet SEMI { ($1, DFunDecl ($3, Some $5, Some $7, None, $2, None)) } | FUNCTION IMPLEMENTATION Triggers FunDeclId LPAREN Formals RPAREN FunRet LBRACE Exp RBRACE { ($1, DFunDecl ($4, Some $6, Some $8, Some $10, None, Some $3)) } Decls : { [] } | Decl Decls { $1::$2 } Modifies : { [] } | MODIFIES AnyIdExps SEMI Modifies { $2 @ $4 } Yields : { [] } | YIELD AnyIdExps SEMI Yields { $2 @ $4 } Imports : { [] } | IMPORT AnyIdExps SEMI Imports { $2 @ $4 } ================================================ FILE: ironclad-apps/tools/BoogieAsm/parse_util.fs ================================================ open Ast;; exception Err of string exception ParseErr of string let err (s:string):'a = raise (Err s) let parse_err (s:string):'a = raise (ParseErr s) let assrt b = if b then () else err "assert failure" let line = ref 1;; let file = ref "";; let parse_require b = if b then () else parse_err "parse requirement violated" ================================================ FILE: ironclad-apps/tools/Dafny/BVD.exe.config ================================================  ================================================ FILE: ironclad-apps/tools/Dafny/Boogie.vshost.exe.manifest ================================================  ================================================ FILE: ironclad-apps/tools/Dafny/Dafny.exe.config ================================================ ================================================ FILE: ironclad-apps/tools/Dafny/Dafny.vshost.exe.config ================================================ ================================================ FILE: ironclad-apps/tools/Dafny/Dafny.vshost.exe.manifest ================================================  ================================================ FILE: ironclad-apps/tools/Dafny/DafnyPrelude.bpl ================================================ // Dafny prelude // Created 9 February 2008 by Rustan Leino. // Converted to Boogie 2 on 28 June 2008. // Edited sequence axioms 20 October 2009 by Alex Summers. // Modified 2014 by Dan Rosen. // Copyright (c) 2008-2014, Microsoft. const $$Language$Dafny: bool; // To be recognizable to the ModelViewer as axiom $$Language$Dafny; // coming from a Dafny program. // --------------------------------------------------------------- // -- Types ------------------------------------------------------ // --------------------------------------------------------------- type Ty; const unique TBool : Ty; const unique TChar : Ty; const unique TInt : Ty; const unique TNat : Ty; const unique TReal : Ty; function TSet(Ty) : Ty; function TMultiSet(Ty) : Ty; function TSeq(Ty) : Ty; function TMap(Ty, Ty) : Ty; function Inv0_TSet(Ty) : Ty; axiom (forall t: Ty :: { TSet(t) } Inv0_TSet(TSet(t)) == t); function Inv0_TSeq(Ty) : Ty; axiom (forall t: Ty :: { TSeq(t) } Inv0_TSeq(TSeq(t)) == t); function Inv0_TMultiSet(Ty) : Ty; axiom (forall t: Ty :: { TMultiSet(t) } Inv0_TMultiSet(TMultiSet(t)) == t); function Inv0_TMap(Ty) : Ty; function Inv1_TMap(Ty) : Ty; axiom (forall t, u: Ty :: { TMap(t,u) } Inv0_TMap(TMap(t,u)) == t); axiom (forall t, u: Ty :: { TMap(t,u) } Inv1_TMap(TMap(t,u)) == u); // -- Classes and Datatypes -- // -- Type Tags -- type TyTag; function Tag(Ty) : TyTag; const unique TagBool : TyTag; const unique TagChar : TyTag; const unique TagInt : TyTag; const unique TagNat : TyTag; const unique TagReal : TyTag; const unique TagSet : TyTag; const unique TagMultiSet : TyTag; const unique TagSeq : TyTag; const unique TagMap : TyTag; const unique TagClass : TyTag; axiom Tag(TBool) == TagBool; axiom Tag(TChar) == TagChar; axiom Tag(TInt) == TagInt; axiom Tag(TNat) == TagNat; axiom Tag(TReal) == TagReal; axiom (forall t: Ty :: { TSet(t) } Tag(TSet(t)) == TagSet); axiom (forall t: Ty :: { TMultiSet(t) } Tag(TMultiSet(t)) == TagMultiSet); axiom (forall t: Ty :: { TSeq(t) } Tag(TSeq(t)) == TagSeq); axiom (forall t, u: Ty :: { TMap(t,u) } Tag(TMap(t,u)) == TagMap); // --------------------------------------------------------------- // -- Literals --------------------------------------------------- // --------------------------------------------------------------- function {:identity} LitInt(x: int): int { x } axiom (forall x: int :: { $Box(LitInt(x)) } $Box(LitInt(x)) == Lit($Box(x)) ); function {:identity} LitReal(x: real): real { x } axiom (forall x: real :: { $Box(LitReal(x)) } $Box(LitReal(x)) == Lit($Box(x)) ); function {:identity} Lit(x: T): T { x } axiom (forall x: T :: { $Box(Lit(x)) } $Box(Lit(x)) == Lit($Box(x)) ); // --------------------------------------------------------------- // -- Characters ------------------------------------------------- // --------------------------------------------------------------- type char; function char#FromInt(int): char; function char#ToInt(char): int; // inverse of char#FromInt axiom (forall ch: char :: { char#ToInt(ch) } char#FromInt(char#ToInt(ch)) == ch); axiom (forall n: int :: { char#FromInt(n) } 0 <= n && n < 65536 ==> char#ToInt(char#FromInt(n)) == n); // --------------------------------------------------------------- // -- References ------------------------------------------------- // --------------------------------------------------------------- type ref; const null: ref; // --------------------------------------------------------------- // -- Boxing and unboxing ---------------------------------------- // --------------------------------------------------------------- type Box; const $ArbitraryBoxValue: Box; function $Box(T): Box; function $Unbox(Box): T; axiom (forall x : T :: { $Box(x) } $Unbox($Box(x)) == x); axiom (forall bx : Box :: { $IsBox(bx, TInt) } ( $IsBox(bx, TInt) ==> $Box($Unbox(bx) : int) == bx && $Is($Unbox(bx) : int, TInt))); axiom (forall bx : Box :: { $IsBox(bx, TNat) } ( $IsBox(bx, TNat) ==> $Box($Unbox(bx) : int) == bx && $Is($Unbox(bx) : int, TNat))); axiom (forall bx : Box :: { $IsBox(bx, TReal) } ( $IsBox(bx, TReal) ==> $Box($Unbox(bx) : real) == bx && $Is($Unbox(bx) : real, TReal))); axiom (forall bx : Box :: { $IsBox(bx, TBool) } ( $IsBox(bx, TBool) ==> $Box($Unbox(bx) : bool) == bx && $Is($Unbox(bx) : bool, TBool))); axiom (forall bx : Box :: { $IsBox(bx, TChar) } ( $IsBox(bx, TChar) ==> $Box($Unbox(bx) : char) == bx && $Is($Unbox(bx) : char, TChar))); axiom (forall bx : Box, t : Ty :: { $IsBox(bx, TSet(t)) } ( $IsBox(bx, TSet(t)) ==> $Box($Unbox(bx) : Set Box) == bx && $Is($Unbox(bx) : Set Box, TSet(t)))); axiom (forall bx : Box, t : Ty :: { $IsBox(bx, TMultiSet(t)) } ( $IsBox(bx, TMultiSet(t)) ==> $Box($Unbox(bx) : MultiSet Box) == bx && $Is($Unbox(bx) : MultiSet Box, TMultiSet(t)))); axiom (forall bx : Box, t : Ty :: { $IsBox(bx, TSeq(t)) } ( $IsBox(bx, TSeq(t)) ==> $Box($Unbox(bx) : Seq Box) == bx && $Is($Unbox(bx) : Seq Box, TSeq(t)))); axiom (forall bx : Box, s : Ty, t : Ty :: { $IsBox(bx, TMap(s, t)) } ( $IsBox(bx, TMap(s, t)) ==> $Box($Unbox(bx) : Map Box Box) == bx && $Is($Unbox(bx) : Map Box Box, TMap(s, t)))); axiom (forall v : T, t : Ty :: { $IsBox($Box(v), t) } ( $IsBox($Box(v), t) <==> $Is(v,t) )); axiom (forall v : T, t : Ty, h : Heap :: { $IsAllocBox($Box(v), t, h) } ( $IsAllocBox($Box(v), t, h) <==> $IsAlloc(v,t,h) )); // The following functions and axioms are used to obtain a $Box($Unbox(_)) wrapper around // certain expressions. Note that it assumes any booleans (or, indeed, values of any type) contained // in the (multi)set are canonical (which is the case for any (multi)set that occurs in an execution of // a Dafny program). // The role of the parameter 'dummy' in the following is (an unfortunately clumsy construction // whose only purpose is) simply to tell Boogie how to instantiate the type parameter 'T'. /* function $IsGoodSet_Extended(s: Set Box, dummy: T): bool; axiom (forall ss: Set Box, dummy: T, bx: Box :: { $IsGoodSet_Extended(ss, dummy), ss[bx] } $IsGoodSet_Extended(ss, dummy) ==> ss[bx] ==> bx == $Box($Unbox(bx): T)); function $IsGoodMultiSet_Extended(ms: MultiSet Box, dummy: T): bool; axiom (forall ms: MultiSet Box, dummy: T, bx: Box :: { $IsGoodMultiSet_Extended(ms, dummy), ms[bx] } $IsGoodMultiSet_Extended(ms, dummy) ==> 0 < ms[bx] ==> bx == $Box($Unbox(bx): T)); */ // --------------------------------------------------------------- // -- Is and IsAlloc --------------------------------------------- // --------------------------------------------------------------- // Type-argument to $Is is the /representation type/, // the second value argument to $Is is the actual type. function $Is(T,Ty): bool; // no heap for now function $IsAlloc(T,Ty,Heap): bool; // Corresponding entries for boxes... // This could probably be solved by having Box also inhabit Ty function $IsBox(T,Ty): bool; function $IsAllocBox(T,Ty,Heap): bool; axiom(forall v : int :: { $Is(v,TInt) } $Is(v,TInt)); axiom(forall v : int :: { $Is(v,TNat) } $Is(v,TNat) <==> v >= 0); axiom(forall v : real :: { $Is(v,TReal) } $Is(v,TReal)); axiom(forall v : bool :: { $Is(v,TBool) } $Is(v,TBool)); axiom(forall v : char :: { $Is(v,TChar) } $Is(v,TChar)); axiom(forall h : Heap, v : int :: { $IsAlloc(v,TInt,h) } $IsAlloc(v,TInt,h)); axiom(forall h : Heap, v : int :: { $IsAlloc(v,TNat,h) } $IsAlloc(v,TNat,h)); axiom(forall h : Heap, v : real :: { $IsAlloc(v,TReal,h) } $IsAlloc(v,TReal,h)); axiom(forall h : Heap, v : bool :: { $IsAlloc(v,TBool,h) } $IsAlloc(v,TBool,h)); axiom(forall h : Heap, v : char :: { $IsAlloc(v,TChar,h) } $IsAlloc(v,TChar,h)); axiom (forall v: Set Box, t0: Ty :: { $Is(v, TSet(t0)) } $Is(v, TSet(t0)) <==> (forall bx: Box :: { v[bx] } v[bx] ==> $IsBox(bx, t0))); axiom (forall v: MultiSet Box, t0: Ty :: { $Is(v, TMultiSet(t0)) } $Is(v, TMultiSet(t0)) <==> (forall bx: Box :: { v[bx] } 0 < v[bx] ==> $IsBox(bx, t0))); axiom (forall v: MultiSet Box, t0: Ty :: { $Is(v, TMultiSet(t0)) } $Is(v, TMultiSet(t0)) ==> $IsGoodMultiSet(v)); axiom (forall v: Seq Box, t0: Ty :: { $Is(v, TSeq(t0)) } $Is(v, TSeq(t0)) <==> (forall i : int :: { Seq#Index(v, i) } 0 <= i && i < Seq#Length(v) ==> $IsBox(Seq#Index(v, i), t0))); axiom (forall v: Set Box, t0: Ty, h: Heap :: { $IsAlloc(v, TSet(t0), h) } $IsAlloc(v, TSet(t0), h) <==> (forall bx: Box :: { v[bx] } v[bx] ==> $IsAllocBox(bx, t0, h))); axiom (forall v: MultiSet Box, t0: Ty, h: Heap :: { $IsAlloc(v, TMultiSet(t0), h) } $IsAlloc(v, TMultiSet(t0), h) <==> (forall bx: Box :: { v[bx] } 0 < v[bx] ==> $IsAllocBox(bx, t0, h))); axiom (forall v: Seq Box, t0: Ty, h: Heap :: { $IsAlloc(v, TSeq(t0), h) } $IsAlloc(v, TSeq(t0), h) <==> (forall i : int :: { Seq#Index(v, i) } 0 <= i && i < Seq#Length(v) ==> $IsAllocBox(Seq#Index(v, i), t0, h))); axiom (forall v: Map Box Box, t0: Ty, t1: Ty :: { $Is(v, TMap(t0, t1)) } $Is(v, TMap(t0, t1)) <==> (forall bx: Box :: { Map#Elements(v)[bx] } { Map#Domain(v)[bx] } Map#Domain(v)[bx] ==> $IsBox(Map#Elements(v)[bx], t1) && $IsBox(bx, t0))); axiom (forall v: Map Box Box, t0: Ty, t1: Ty, h: Heap :: { $IsAlloc(v, TMap(t0, t1), h) } $IsAlloc(v, TMap(t0, t1), h) <==> (forall bx: Box :: { Map#Elements(v)[bx] } { Map#Domain(v)[bx] } Map#Domain(v)[bx] ==> $IsAllocBox(Map#Elements(v)[bx], t1, h) && $IsAllocBox(bx, t0, h))); // --------------------------------------------------------------- // -- Encoding of type names ------------------------------------- // --------------------------------------------------------------- type ClassName; const unique class._System.int: ClassName; const unique class._System.bool: ClassName; const unique class._System.set: ClassName; const unique class._System.seq: ClassName; const unique class._System.multiset: ClassName; function /*{:never_pattern true}*/ dtype(ref): Ty; // changed from ClassName to Ty function TypeTuple(a: ClassName, b: ClassName): ClassName; function TypeTupleCar(ClassName): ClassName; function TypeTupleCdr(ClassName): ClassName; // TypeTuple is injective in both arguments: axiom (forall a: ClassName, b: ClassName :: { TypeTuple(a,b) } TypeTupleCar(TypeTuple(a,b)) == a && TypeTupleCdr(TypeTuple(a,b)) == b); // -- Function handles ------------------------------------------- type HandleType; // --------------------------------------------------------------- // -- Datatypes -------------------------------------------------- // --------------------------------------------------------------- type DatatypeType; type DtCtorId; function DatatypeCtorId(DatatypeType): DtCtorId; function DtRank(DatatypeType): int; function BoxRank(Box): int; axiom (forall d: DatatypeType :: {BoxRank($Box(d))} BoxRank($Box(d)) == DtRank(d)); // --------------------------------------------------------------- // -- Axiom contexts --------------------------------------------- // --------------------------------------------------------------- // used to make sure function axioms are not used while their consistency is being checked const $ModuleContextHeight: int; const $FunctionContextHeight: int; // --------------------------------------------------------------- // -- Layers of function encodings ------------------------------- // --------------------------------------------------------------- type LayerType; const $LZ: LayerType; function $LS(LayerType): LayerType; function AtLayer([LayerType]A, LayerType): A; axiom (forall f : [LayerType]A, ly : LayerType :: { AtLayer(f,ly) } AtLayer(f,ly) == f[ly]); axiom (forall f : [LayerType]A, ly : LayerType :: { AtLayer(f,$LS(ly)) } AtLayer(f,$LS(ly)) == AtLayer(f,ly)); // --------------------------------------------------------------- // -- Fields ----------------------------------------------------- // --------------------------------------------------------------- type Field alpha; function FDim(Field T): int; function IndexField(int): Field Box; axiom (forall i: int :: { IndexField(i) } FDim(IndexField(i)) == 1); function IndexField_Inverse(Field T): int; axiom (forall i: int :: { IndexField(i) } IndexField_Inverse(IndexField(i)) == i); function MultiIndexField(Field Box, int): Field Box; axiom (forall f: Field Box, i: int :: { MultiIndexField(f,i) } FDim(MultiIndexField(f,i)) == FDim(f) + 1); function MultiIndexField_Inverse0(Field T): Field T; function MultiIndexField_Inverse1(Field T): int; axiom (forall f: Field Box, i: int :: { MultiIndexField(f,i) } MultiIndexField_Inverse0(MultiIndexField(f,i)) == f && MultiIndexField_Inverse1(MultiIndexField(f,i)) == i); function DeclType(Field T): ClassName; type NameFamily; function DeclName(Field T): NameFamily; function FieldOfDecl(ClassName, NameFamily): Field alpha; axiom (forall cl : ClassName, nm: NameFamily :: {FieldOfDecl(cl, nm): Field T} DeclType(FieldOfDecl(cl, nm): Field T) == cl && DeclName(FieldOfDecl(cl, nm): Field T) == nm); function $IsGhostField(Field T): bool; // --------------------------------------------------------------- // -- Allocatedness and Heap Succession -------------------------- // --------------------------------------------------------------- // $IsAlloc and $IsAllocBox are monotonic axiom(forall h, k : Heap, v : T, t : Ty :: { $HeapSucc(h, k), $IsAlloc(v, t, h) } $HeapSucc(h, k) ==> $IsAlloc(v, t, h) ==> $IsAlloc(v, t, k)); axiom(forall h, k : Heap, bx : Box, t : Ty :: { $HeapSucc(h, k), $IsAllocBox(bx, t, h) } $HeapSucc(h, k) ==> $IsAllocBox(bx, t, h) ==> $IsAllocBox(bx, t, k)); // No axioms for $Is and $IsBox since they don't talk about the heap. const unique alloc: Field bool; axiom FDim(alloc) == 0 && !$IsGhostField(alloc); // treat as non-ghost field, because it cannot be changed by ghost code // --------------------------------------------------------------- // -- Arrays ----------------------------------------------------- // --------------------------------------------------------------- function _System.array.Length(a: ref): int; axiom (forall o: ref :: 0 <= _System.array.Length(o)); // --------------------------------------------------------------- // -- Reals ------------------------------------------------------ // --------------------------------------------------------------- function Int(x: real): int { int(x) } function Real(x: int): real { real(x) } axiom (forall i: int :: { Int(Real(i)) } Int(Real(i)) == i); function {:inline true} _System.real.Trunc(x: real): int { Int(x) } // --------------------------------------------------------------- // -- The heap --------------------------------------------------- // --------------------------------------------------------------- type Heap = [ref,Field alpha]alpha; function {:inline true} read(H:Heap, r:ref, f:Field alpha): alpha { H[r, f] } function {:inline true} update(H:Heap, r:ref, f:Field alpha, v:alpha): Heap { H[r,f := v] } function $IsGoodHeap(Heap): bool; var $Heap: Heap where $IsGoodHeap($Heap); function $HeapSucc(Heap, Heap): bool; axiom (forall h: Heap, r: ref, f: Field alpha, x: alpha :: { update(h, r, f, x) } $IsGoodHeap(update(h, r, f, x)) ==> $HeapSucc(h, update(h, r, f, x))); axiom (forall a,b,c: Heap :: { $HeapSucc(a,b), $HeapSucc(b,c) } $HeapSucc(a,b) && $HeapSucc(b,c) ==> $HeapSucc(a,c)); axiom (forall h: Heap, k: Heap :: { $HeapSucc(h,k) } $HeapSucc(h,k) ==> (forall o: ref :: { read(k, o, alloc) } read(h, o, alloc) ==> read(k, o, alloc))); function $HeapSuccGhost(Heap, Heap): bool; axiom (forall h: Heap, k: Heap :: { $HeapSuccGhost(h,k) } $HeapSuccGhost(h,k) ==> $HeapSucc(h,k) && (forall o: ref, f: Field alpha :: { read(k, o, f) } !$IsGhostField(f) ==> read(h, o, f) == read(k, o, f))); // --------------------------------------------------------------- // -- Non-determinism -------------------------------------------- // --------------------------------------------------------------- type TickType; var $Tick: TickType; // --------------------------------------------------------------- // -- Useful macros ---------------------------------------------- // --------------------------------------------------------------- // havoc everything in $Heap, except {this}+rds+nw procedure $YieldHavoc(this: ref, rds: Set Box, nw: Set Box); modifies $Heap; ensures (forall $o: ref, $f: Field alpha :: { read($Heap, $o, $f) } $o != null && read(old($Heap), $o, alloc) ==> $o == this || rds[$Box($o)] || nw[$Box($o)] ==> read($Heap, $o, $f) == read(old($Heap), $o, $f)); ensures $HeapSucc(old($Heap), $Heap); // havoc everything in $Heap, except rds-modi-{this} procedure $IterHavoc0(this: ref, rds: Set Box, modi: Set Box); modifies $Heap; ensures (forall $o: ref, $f: Field alpha :: { read($Heap, $o, $f) } $o != null && read(old($Heap), $o, alloc) ==> rds[$Box($o)] && !modi[$Box($o)] && $o != this ==> read($Heap, $o, $f) == read(old($Heap), $o, $f)); ensures $HeapSucc(old($Heap), $Heap); // havoc $Heap at {this}+modi+nw procedure $IterHavoc1(this: ref, modi: Set Box, nw: Set Box); modifies $Heap; ensures (forall $o: ref, $f: Field alpha :: { read($Heap, $o, $f) } $o != null && read(old($Heap), $o, alloc) ==> read($Heap, $o, $f) == read(old($Heap), $o, $f) || $o == this || modi[$Box($o)] || nw[$Box($o)]); ensures $HeapSucc(old($Heap), $Heap); procedure $IterCollectNewObjects(prevHeap: Heap, newHeap: Heap, this: ref, NW: Field (Set Box)) returns (s: Set Box); ensures (forall bx: Box :: { s[bx] } s[bx] <==> read(newHeap, this, NW)[bx] || ($Unbox(bx) != null && !read(prevHeap, $Unbox(bx):ref, alloc) && read(newHeap, $Unbox(bx):ref, alloc))); // --------------------------------------------------------------- // -- Axiomatizations -------------------------------------------- // --------------------------------------------------------------- // --------------------------------------------------------------- // -- Axiomatization of sets ------------------------------------- // --------------------------------------------------------------- type Set T = [T]bool; function Set#Card(Set T): int; axiom (forall s: Set T :: { Set#Card(s) } 0 <= Set#Card(s)); function Set#Empty(): Set T; axiom (forall o: T :: { Set#Empty()[o] } !Set#Empty()[o]); axiom (forall s: Set T :: { Set#Card(s) } (Set#Card(s) == 0 <==> s == Set#Empty()) && (Set#Card(s) != 0 ==> (exists x: T :: s[x]))); // the empty set could be of anything //axiom (forall t: Ty :: { $Is(Set#Empty() : [T]bool, TSet(t)) } $Is(Set#Empty() : [T]bool, TSet(t))); function Set#Singleton(T): Set T; axiom (forall r: T :: { Set#Singleton(r) } Set#Singleton(r)[r]); axiom (forall r: T, o: T :: { Set#Singleton(r)[o] } Set#Singleton(r)[o] <==> r == o); axiom (forall r: T :: { Set#Card(Set#Singleton(r)) } Set#Card(Set#Singleton(r)) == 1); function Set#UnionOne(Set T, T): Set T; axiom (forall a: Set T, x: T, o: T :: { Set#UnionOne(a,x)[o] } Set#UnionOne(a,x)[o] <==> o == x || a[o]); axiom (forall a: Set T, x: T :: { Set#UnionOne(a, x) } Set#UnionOne(a, x)[x]); axiom (forall a: Set T, x: T, y: T :: { Set#UnionOne(a, x), a[y] } a[y] ==> Set#UnionOne(a, x)[y]); axiom (forall a: Set T, x: T :: { Set#Card(Set#UnionOne(a, x)) } a[x] ==> Set#Card(Set#UnionOne(a, x)) == Set#Card(a)); axiom (forall a: Set T, x: T :: { Set#Card(Set#UnionOne(a, x)) } !a[x] ==> Set#Card(Set#UnionOne(a, x)) == Set#Card(a) + 1); function Set#Union(Set T, Set T): Set T; axiom (forall a: Set T, b: Set T, o: T :: { Set#Union(a,b)[o] } Set#Union(a,b)[o] <==> a[o] || b[o]); axiom (forall a, b: Set T, y: T :: { Set#Union(a, b), a[y] } a[y] ==> Set#Union(a, b)[y]); axiom (forall a, b: Set T, y: T :: { Set#Union(a, b), b[y] } b[y] ==> Set#Union(a, b)[y]); axiom (forall a, b: Set T :: { Set#Union(a, b) } Set#Disjoint(a, b) ==> Set#Difference(Set#Union(a, b), a) == b && Set#Difference(Set#Union(a, b), b) == a); // Follows from the general union axiom, but might be still worth including, because disjoint union is a common case: // axiom (forall a, b: Set T :: { Set#Card(Set#Union(a, b)) } // Set#Disjoint(a, b) ==> // Set#Card(Set#Union(a, b)) == Set#Card(a) + Set#Card(b)); function Set#Intersection(Set T, Set T): Set T; axiom (forall a: Set T, b: Set T, o: T :: { Set#Intersection(a,b)[o] } Set#Intersection(a,b)[o] <==> a[o] && b[o]); axiom (forall a, b: Set T :: { Set#Union(Set#Union(a, b), b) } Set#Union(Set#Union(a, b), b) == Set#Union(a, b)); axiom (forall a, b: Set T :: { Set#Union(a, Set#Union(a, b)) } Set#Union(a, Set#Union(a, b)) == Set#Union(a, b)); axiom (forall a, b: Set T :: { Set#Intersection(Set#Intersection(a, b), b) } Set#Intersection(Set#Intersection(a, b), b) == Set#Intersection(a, b)); axiom (forall a, b: Set T :: { Set#Intersection(a, Set#Intersection(a, b)) } Set#Intersection(a, Set#Intersection(a, b)) == Set#Intersection(a, b)); axiom (forall a, b: Set T :: { Set#Card(Set#Union(a, b)) }{ Set#Card(Set#Intersection(a, b)) } Set#Card(Set#Union(a, b)) + Set#Card(Set#Intersection(a, b)) == Set#Card(a) + Set#Card(b)); function Set#Difference(Set T, Set T): Set T; axiom (forall a: Set T, b: Set T, o: T :: { Set#Difference(a,b)[o] } Set#Difference(a,b)[o] <==> a[o] && !b[o]); axiom (forall a, b: Set T, y: T :: { Set#Difference(a, b), b[y] } b[y] ==> !Set#Difference(a, b)[y] ); axiom (forall a, b: Set T :: { Set#Card(Set#Difference(a, b)) } Set#Card(Set#Difference(a, b)) + Set#Card(Set#Difference(b, a)) + Set#Card(Set#Intersection(a, b)) == Set#Card(Set#Union(a, b)) && Set#Card(Set#Difference(a, b)) == Set#Card(a) - Set#Card(Set#Intersection(a, b))); function Set#Subset(Set T, Set T): bool; axiom(forall a: Set T, b: Set T :: { Set#Subset(a,b) } Set#Subset(a,b) <==> (forall o: T :: {a[o]} {b[o]} a[o] ==> b[o])); // axiom(forall a: Set T, b: Set T :: // { Set#Subset(a,b), Set#Card(a), Set#Card(b) } // very restrictive trigger // Set#Subset(a,b) ==> Set#Card(a) <= Set#Card(b)); function Set#Equal(Set T, Set T): bool; axiom(forall a: Set T, b: Set T :: { Set#Equal(a,b) } Set#Equal(a,b) <==> (forall o: T :: {a[o]} {b[o]} a[o] <==> b[o])); axiom(forall a: Set T, b: Set T :: { Set#Equal(a,b) } // extensionality axiom for sets Set#Equal(a,b) ==> a == b); function Set#Disjoint(Set T, Set T): bool; axiom (forall a: Set T, b: Set T :: { Set#Disjoint(a,b) } Set#Disjoint(a,b) <==> (forall o: T :: {a[o]} {b[o]} !a[o] || !b[o])); // --------------------------------------------------------------- // -- Axiomatization of multisets -------------------------------- // --------------------------------------------------------------- function Math#min(a: int, b: int): int; axiom (forall a: int, b: int :: { Math#min(a, b) } a <= b <==> Math#min(a, b) == a); axiom (forall a: int, b: int :: { Math#min(a, b) } b <= a <==> Math#min(a, b) == b); axiom (forall a: int, b: int :: { Math#min(a, b) } Math#min(a, b) == a || Math#min(a, b) == b); function Math#clip(a: int): int; axiom (forall a: int :: { Math#clip(a) } 0 <= a ==> Math#clip(a) == a); axiom (forall a: int :: { Math#clip(a) } a < 0 ==> Math#clip(a) == 0); type MultiSet T = [T]int; function $IsGoodMultiSet(ms: MultiSet T): bool; // ints are non-negative, used after havocing, and for conversion from sequences to multisets. axiom (forall ms: MultiSet T :: { $IsGoodMultiSet(ms) } $IsGoodMultiSet(ms) <==> (forall bx: T :: { ms[bx] } 0 <= ms[bx] && ms[bx] <= MultiSet#Card(ms))); function MultiSet#Card(MultiSet T): int; axiom (forall s: MultiSet T :: { MultiSet#Card(s) } 0 <= MultiSet#Card(s)); axiom (forall s: MultiSet T, x: T, n: int :: { MultiSet#Card(s[x := n]) } 0 <= n ==> MultiSet#Card(s[x := n]) == MultiSet#Card(s) - s[x] + n); function MultiSet#Empty(): MultiSet T; axiom (forall o: T :: { MultiSet#Empty()[o] } MultiSet#Empty()[o] == 0); axiom (forall s: MultiSet T :: { MultiSet#Card(s) } (MultiSet#Card(s) == 0 <==> s == MultiSet#Empty()) && (MultiSet#Card(s) != 0 ==> (exists x: T :: 0 < s[x]))); function MultiSet#Singleton(T): MultiSet T; axiom (forall r: T, o: T :: { MultiSet#Singleton(r)[o] } (MultiSet#Singleton(r)[o] == 1 <==> r == o) && (MultiSet#Singleton(r)[o] == 0 <==> r != o)); axiom (forall r: T :: { MultiSet#Singleton(r) } MultiSet#Singleton(r) == MultiSet#UnionOne(MultiSet#Empty(), r)); function MultiSet#UnionOne(MultiSet T, T): MultiSet T; // pure containment axiom (in the original multiset or is the added element) axiom (forall a: MultiSet T, x: T, o: T :: { MultiSet#UnionOne(a,x)[o] } 0 < MultiSet#UnionOne(a,x)[o] <==> o == x || 0 < a[o]); // union-ing increases count by one axiom (forall a: MultiSet T, x: T :: { MultiSet#UnionOne(a, x) } MultiSet#UnionOne(a, x)[x] == a[x] + 1); // non-decreasing axiom (forall a: MultiSet T, x: T, y: T :: { MultiSet#UnionOne(a, x), a[y] } 0 < a[y] ==> 0 < MultiSet#UnionOne(a, x)[y]); // other elements unchanged axiom (forall a: MultiSet T, x: T, y: T :: { MultiSet#UnionOne(a, x), a[y] } x != y ==> a[y] == MultiSet#UnionOne(a, x)[y]); axiom (forall a: MultiSet T, x: T :: { MultiSet#Card(MultiSet#UnionOne(a, x)) } MultiSet#Card(MultiSet#UnionOne(a, x)) == MultiSet#Card(a) + 1); function MultiSet#Union(MultiSet T, MultiSet T): MultiSet T; // union-ing is the sum of the contents axiom (forall a: MultiSet T, b: MultiSet T, o: T :: { MultiSet#Union(a,b)[o] } MultiSet#Union(a,b)[o] == a[o] + b[o]); axiom (forall a: MultiSet T, b: MultiSet T :: { MultiSet#Card(MultiSet#Union(a,b)) } MultiSet#Card(MultiSet#Union(a,b)) == MultiSet#Card(a) + MultiSet#Card(b)); function MultiSet#Intersection(MultiSet T, MultiSet T): MultiSet T; axiom (forall a: MultiSet T, b: MultiSet T, o: T :: { MultiSet#Intersection(a,b)[o] } MultiSet#Intersection(a,b)[o] == Math#min(a[o], b[o])); // left and right pseudo-idempotence axiom (forall a, b: MultiSet T :: { MultiSet#Intersection(MultiSet#Intersection(a, b), b) } MultiSet#Intersection(MultiSet#Intersection(a, b), b) == MultiSet#Intersection(a, b)); axiom (forall a, b: MultiSet T :: { MultiSet#Intersection(a, MultiSet#Intersection(a, b)) } MultiSet#Intersection(a, MultiSet#Intersection(a, b)) == MultiSet#Intersection(a, b)); // multiset difference, a - b. clip() makes it positive. function MultiSet#Difference(MultiSet T, MultiSet T): MultiSet T; axiom (forall a: MultiSet T, b: MultiSet T, o: T :: { MultiSet#Difference(a,b)[o] } MultiSet#Difference(a,b)[o] == Math#clip(a[o] - b[o])); axiom (forall a, b: MultiSet T, y: T :: { MultiSet#Difference(a, b), b[y], a[y] } a[y] <= b[y] ==> MultiSet#Difference(a, b)[y] == 0 ); axiom (forall a, b: MultiSet T :: { MultiSet#Card(MultiSet#Difference(a, b)) } MultiSet#Card(MultiSet#Difference(a, b)) + MultiSet#Card(MultiSet#Difference(b, a)) + 2 * MultiSet#Card(MultiSet#Intersection(a, b)) == MultiSet#Card(MultiSet#Union(a, b)) && MultiSet#Card(MultiSet#Difference(a, b)) == MultiSet#Card(a) - MultiSet#Card(MultiSet#Intersection(a, b))); // multiset subset means a must have at most as many of each element as b function MultiSet#Subset(MultiSet T, MultiSet T): bool; axiom(forall a: MultiSet T, b: MultiSet T :: { MultiSet#Subset(a,b) } MultiSet#Subset(a,b) <==> (forall o: T :: {a[o]} {b[o]} a[o] <= b[o])); function MultiSet#Equal(MultiSet T, MultiSet T): bool; axiom(forall a: MultiSet T, b: MultiSet T :: { MultiSet#Equal(a,b) } MultiSet#Equal(a,b) <==> (forall o: T :: {a[o]} {b[o]} a[o] == b[o])); // extensionality axiom for multisets axiom(forall a: MultiSet T, b: MultiSet T :: { MultiSet#Equal(a,b) } MultiSet#Equal(a,b) ==> a == b); function MultiSet#Disjoint(MultiSet T, MultiSet T): bool; axiom (forall a: MultiSet T, b: MultiSet T :: { MultiSet#Disjoint(a,b) } MultiSet#Disjoint(a,b) <==> (forall o: T :: {a[o]} {b[o]} a[o] == 0 || b[o] == 0)); // conversion to a multiset. each element in the original set has duplicity 1. function MultiSet#FromSet(Set T): MultiSet T; axiom (forall s: Set T, a: T :: { MultiSet#FromSet(s)[a] } (MultiSet#FromSet(s)[a] == 0 <==> !s[a]) && (MultiSet#FromSet(s)[a] == 1 <==> s[a])); axiom (forall s: Set T :: { MultiSet#Card(MultiSet#FromSet(s)) } MultiSet#Card(MultiSet#FromSet(s)) == Set#Card(s)); // conversion to a multiset, from a sequence. function MultiSet#FromSeq(Seq T): MultiSet T; // conversion produces a good map. axiom (forall s: Seq T :: { MultiSet#FromSeq(s) } $IsGoodMultiSet(MultiSet#FromSeq(s)) ); // cardinality axiom axiom (forall s: Seq T :: { MultiSet#Card(MultiSet#FromSeq(s)) } MultiSet#Card(MultiSet#FromSeq(s)) == Seq#Length(s)); // building axiom axiom (forall s: Seq T, v: T :: { MultiSet#FromSeq(Seq#Build(s, v)) } MultiSet#FromSeq(Seq#Build(s, v)) == MultiSet#UnionOne(MultiSet#FromSeq(s), v) ); axiom (forall :: MultiSet#FromSeq(Seq#Empty(): Seq T) == MultiSet#Empty(): MultiSet T); // concatenation axiom axiom (forall a: Seq T, b: Seq T :: { MultiSet#FromSeq(Seq#Append(a, b)) } MultiSet#FromSeq(Seq#Append(a, b)) == MultiSet#Union(MultiSet#FromSeq(a), MultiSet#FromSeq(b)) ); // update axiom axiom (forall s: Seq T, i: int, v: T, x: T :: { MultiSet#FromSeq(Seq#Update(s, i, v))[x] } 0 <= i && i < Seq#Length(s) ==> MultiSet#FromSeq(Seq#Update(s, i, v))[x] == MultiSet#Union(MultiSet#Difference(MultiSet#FromSeq(s), MultiSet#Singleton(Seq#Index(s,i))), MultiSet#Singleton(v))[x] ); // i.e. MS(Update(s, i, v)) == MS(s) - {{s[i]}} + {{v}} axiom (forall s: Seq T, x: T :: { MultiSet#FromSeq(s)[x] } (exists i : int :: { Seq#Index(s,i) } 0 <= i && i < Seq#Length(s) && x == Seq#Index(s,i)) <==> 0 < MultiSet#FromSeq(s)[x] ); // --------------------------------------------------------------- // -- Axiomatization of sequences -------------------------------- // --------------------------------------------------------------- type Seq T; function Seq#Length(Seq T): int; axiom (forall s: Seq T :: { Seq#Length(s) } 0 <= Seq#Length(s)); function Seq#Empty(): Seq T; axiom (forall :: Seq#Length(Seq#Empty(): Seq T) == 0); axiom (forall s: Seq T :: { Seq#Length(s) } Seq#Length(s) == 0 ==> s == Seq#Empty()); // The empty sequence $Is any type axiom (forall t: Ty :: {$Is(Seq#Empty(): Seq T, t)} $Is(Seq#Empty(): Seq T, t)); function Seq#Singleton(T): Seq T; axiom (forall t: T :: { Seq#Length(Seq#Singleton(t)) } Seq#Length(Seq#Singleton(t)) == 1); function Seq#Build(s: Seq T, val: T): Seq T; axiom (forall s: Seq T, v: T :: { Seq#Length(Seq#Build(s,v)) } Seq#Length(Seq#Build(s,v)) == 1 + Seq#Length(s)); axiom (forall s: Seq T, i: int, v: T :: { Seq#Index(Seq#Build(s,v), i) } (i == Seq#Length(s) ==> Seq#Index(Seq#Build(s,v), i) == v) && (i != Seq#Length(s) ==> Seq#Index(Seq#Build(s,v), i) == Seq#Index(s, i))); // Build preserves $Is axiom (forall s: Seq Box, bx: Box, t: Ty :: { $Is(Seq#Build(s,bx),TSeq(t)) } $Is(s,TSeq(t)) && $IsBox(bx,t) ==> $Is(Seq#Build(s,bx),TSeq(t))); function Seq#Append(Seq T, Seq T): Seq T; axiom (forall s0: Seq T, s1: Seq T :: { Seq#Length(Seq#Append(s0,s1)) } Seq#Length(Seq#Append(s0,s1)) == Seq#Length(s0) + Seq#Length(s1)); // Append preserves $Is axiom (forall s0 : Seq Box, s1 : Seq Box, t : Ty :: { $Is(Seq#Append(s0,s1),t) } $Is(s0,t) && $Is(s1,t) ==> $Is(Seq#Append(s0,s1),t)); function Seq#Index(Seq T, int): T; axiom (forall t: T :: { Seq#Index(Seq#Singleton(t), 0) } Seq#Index(Seq#Singleton(t), 0) == t); axiom (forall s0: Seq T, s1: Seq T, n: int :: { Seq#Index(Seq#Append(s0,s1), n) } (n < Seq#Length(s0) ==> Seq#Index(Seq#Append(s0,s1), n) == Seq#Index(s0, n)) && (Seq#Length(s0) <= n ==> Seq#Index(Seq#Append(s0,s1), n) == Seq#Index(s1, n - Seq#Length(s0)))); function Seq#Update(Seq T, int, T): Seq T; axiom (forall s: Seq T, i: int, v: T :: { Seq#Length(Seq#Update(s,i,v)) } 0 <= i && i < Seq#Length(s) ==> Seq#Length(Seq#Update(s,i,v)) == Seq#Length(s)); axiom (forall s: Seq T, i: int, v: T, n: int :: { Seq#Index(Seq#Update(s,i,v),n) } 0 <= n && n < Seq#Length(s) ==> (i == n ==> Seq#Index(Seq#Update(s,i,v),n) == v) && (i != n ==> Seq#Index(Seq#Update(s,i,v),n) == Seq#Index(s,n))); function Seq#Contains(Seq T, T): bool; axiom (forall s: Seq T, x: T :: { Seq#Contains(s,x) } Seq#Contains(s,x) <==> (exists i: int :: { Seq#Index(s,i) } 0 <= i && i < Seq#Length(s) && Seq#Index(s,i) == x)); axiom (forall x: ref :: { Seq#Contains(Seq#Empty(), x) } !Seq#Contains(Seq#Empty(), x)); axiom (forall s0: Seq T, s1: Seq T, x: T :: { Seq#Contains(Seq#Append(s0, s1), x) } Seq#Contains(Seq#Append(s0, s1), x) <==> Seq#Contains(s0, x) || Seq#Contains(s1, x)); axiom (forall s: Seq T, v: T, x: T :: // needed to prove things like '4 in [2,3,4]', see method TestSequences0 in SmallTests.dfy { Seq#Contains(Seq#Build(s, v), x) } Seq#Contains(Seq#Build(s, v), x) <==> (v == x || Seq#Contains(s, x))); axiom (forall s: Seq T, n: int, x: T :: { Seq#Contains(Seq#Take(s, n), x) } Seq#Contains(Seq#Take(s, n), x) <==> (exists i: int :: { Seq#Index(s, i) } 0 <= i && i < n && i < Seq#Length(s) && Seq#Index(s, i) == x)); axiom (forall s: Seq T, n: int, x: T :: { Seq#Contains(Seq#Drop(s, n), x) } Seq#Contains(Seq#Drop(s, n), x) <==> (exists i: int :: { Seq#Index(s, i) } 0 <= n && n <= i && i < Seq#Length(s) && Seq#Index(s, i) == x)); function Seq#Equal(Seq T, Seq T): bool; axiom (forall s0: Seq T, s1: Seq T :: { Seq#Equal(s0,s1) } Seq#Equal(s0,s1) <==> Seq#Length(s0) == Seq#Length(s1) && (forall j: int :: { Seq#Index(s0,j) } { Seq#Index(s1,j) } 0 <= j && j < Seq#Length(s0) ==> Seq#Index(s0,j) == Seq#Index(s1,j))); axiom (forall a: Seq T, b: Seq T :: { Seq#Equal(a,b) } // extensionality axiom for sequences Seq#Equal(a,b) ==> a == b); function Seq#SameUntil(Seq T, Seq T, int): bool; axiom (forall s0: Seq T, s1: Seq T, n: int :: { Seq#SameUntil(s0,s1,n) } Seq#SameUntil(s0,s1,n) <==> (forall j: int :: { Seq#Index(s0,j) } { Seq#Index(s1,j) } 0 <= j && j < n ==> Seq#Index(s0,j) == Seq#Index(s1,j))); function Seq#Take(s: Seq T, howMany: int): Seq T; axiom (forall s: Seq T, n: int :: { Seq#Length(Seq#Take(s,n)) } 0 <= n && n <= Seq#Length(s) ==> Seq#Length(Seq#Take(s,n)) == n); axiom (forall s: Seq T, n: int, j: int :: {:weight 25} { Seq#Index(Seq#Take(s,n), j) } { Seq#Index(s, j), Seq#Take(s,n) } 0 <= j && j < n && j < Seq#Length(s) ==> Seq#Index(Seq#Take(s,n), j) == Seq#Index(s, j)); function Seq#Drop(s: Seq T, howMany: int): Seq T; axiom (forall s: Seq T, n: int :: { Seq#Length(Seq#Drop(s,n)) } 0 <= n && n <= Seq#Length(s) ==> Seq#Length(Seq#Drop(s,n)) == Seq#Length(s) - n); axiom (forall s: Seq T, n: int, j: int :: {:weight 25} { Seq#Index(Seq#Drop(s,n), j) } 0 <= n && 0 <= j && j < Seq#Length(s)-n ==> Seq#Index(Seq#Drop(s,n), j) == Seq#Index(s, j+n)); axiom (forall s: Seq T, n: int, k: int :: {:weight 25} { Seq#Index(s, k), Seq#Drop(s,n) } 0 <= n && n <= k && k < Seq#Length(s) ==> Seq#Index(Seq#Drop(s,n), k-n) == Seq#Index(s, k)); axiom (forall s, t: Seq T :: { Seq#Append(s, t) } Seq#Take(Seq#Append(s, t), Seq#Length(s)) == s && Seq#Drop(Seq#Append(s, t), Seq#Length(s)) == t); function Seq#FromArray(h: Heap, a: ref): Seq Box; axiom (forall h: Heap, a: ref :: { Seq#Length(Seq#FromArray(h,a)) } Seq#Length(Seq#FromArray(h, a)) == _System.array.Length(a)); axiom (forall h: Heap, a: ref :: { Seq#FromArray(h, a) } (forall i: int :: // it's important to include both triggers, so that assertions about the // the relation between the array and the sequence can be proved in either // direction { read(h, a, IndexField(i)) } { Seq#Index(Seq#FromArray(h, a): Seq Box, i) } 0 <= i && i < Seq#Length(Seq#FromArray(h, a)) // this will trigger the previous axiom to get a connection with _System.array.Length(a) ==> Seq#Index(Seq#FromArray(h, a), i) == read(h, a, IndexField(i)))); axiom (forall h0, h1: Heap, a: ref :: { Seq#FromArray(h1, a), $HeapSucc(h0, h1) } $IsGoodHeap(h0) && $IsGoodHeap(h1) && $HeapSucc(h0, h1) && (forall i: int :: 0 <= i && i < _System.array.Length(a) ==> read(h0, a, IndexField(i)) == read(h1, a, IndexField(i))) ==> Seq#FromArray(h0, a) == Seq#FromArray(h1, a)); axiom (forall h: Heap, i: int, v: Box, a: ref :: { Seq#FromArray(update(h, a, IndexField(i), v), a) } 0 <= i && i < _System.array.Length(a) ==> Seq#FromArray(update(h, a, IndexField(i), v), a) == Seq#Update(Seq#FromArray(h, a), i, v) ); // Commutability of Take and Drop with Update. axiom (forall s: Seq T, i: int, v: T, n: int :: { Seq#Take(Seq#Update(s, i, v), n) } 0 <= i && i < n && n <= Seq#Length(s) ==> Seq#Take(Seq#Update(s, i, v), n) == Seq#Update(Seq#Take(s, n), i, v) ); axiom (forall s: Seq T, i: int, v: T, n: int :: { Seq#Take(Seq#Update(s, i, v), n) } n <= i && i < Seq#Length(s) ==> Seq#Take(Seq#Update(s, i, v), n) == Seq#Take(s, n)); axiom (forall s: Seq T, i: int, v: T, n: int :: { Seq#Drop(Seq#Update(s, i, v), n) } 0 <= n && n <= i && i < Seq#Length(s) ==> Seq#Drop(Seq#Update(s, i, v), n) == Seq#Update(Seq#Drop(s, n), i-n, v) ); axiom (forall s: Seq T, i: int, v: T, n: int :: { Seq#Drop(Seq#Update(s, i, v), n) } 0 <= i && i < n && n < Seq#Length(s) ==> Seq#Drop(Seq#Update(s, i, v), n) == Seq#Drop(s, n)); // Extension axiom, triggers only on Takes from arrays. axiom (forall h: Heap, a: ref, n0, n1: int :: { Seq#Take(Seq#FromArray(h, a), n0), Seq#Take(Seq#FromArray(h, a), n1) } n0 + 1 == n1 && 0 <= n0 && n1 <= _System.array.Length(a) ==> Seq#Take(Seq#FromArray(h, a), n1) == Seq#Build(Seq#Take(Seq#FromArray(h, a), n0), read(h, a, IndexField(n0): Field Box)) ); // drop commutes with build. axiom (forall s: Seq T, v: T, n: int :: { Seq#Drop(Seq#Build(s, v), n) } 0 <= n && n <= Seq#Length(s) ==> Seq#Drop(Seq#Build(s, v), n) == Seq#Build(Seq#Drop(s, n), v) ); function Seq#Rank(Seq T): int; axiom (forall s: Seq Box, i: int :: { DtRank($Unbox(Seq#Index(s, i)): DatatypeType) } 0 <= i && i < Seq#Length(s) ==> DtRank($Unbox(Seq#Index(s, i)): DatatypeType) < Seq#Rank(s) ); axiom (forall s: Seq T, i: int :: { Seq#Rank(Seq#Drop(s, i)) } 0 < i && i <= Seq#Length(s) ==> Seq#Rank(Seq#Drop(s, i)) < Seq#Rank(s) ); axiom (forall s: Seq T, i: int :: { Seq#Rank(Seq#Take(s, i)) } 0 <= i && i < Seq#Length(s) ==> Seq#Rank(Seq#Take(s, i)) < Seq#Rank(s) ); axiom (forall s: Seq T, i: int, j: int :: { Seq#Rank(Seq#Append(Seq#Take(s, i), Seq#Drop(s, j))) } 0 <= i && i < j && j <= Seq#Length(s) ==> Seq#Rank(Seq#Append(Seq#Take(s, i), Seq#Drop(s, j))) < Seq#Rank(s) ); // Additional axioms about common things axiom (forall s: Seq T, n: int :: { Seq#Drop(s, n) } n == 0 ==> Seq#Drop(s, n) == s); axiom (forall s: Seq T, n: int :: { Seq#Take(s, n) } n == 0 ==> Seq#Take(s, n) == Seq#Empty()); axiom (forall s: Seq T, m, n: int :: { Seq#Drop(Seq#Drop(s, m), n) } 0 <= m && 0 <= n && m+n <= Seq#Length(s) ==> Seq#Drop(Seq#Drop(s, m), n) == Seq#Drop(s, m+n)); // --------------------------------------------------------------- // -- Axiomatization of Maps ------------------------------------- // --------------------------------------------------------------- type Map U V; function Map#Domain(Map U V): [U] bool; function Map#Elements(Map U V): [U]V; function Map#Card(Map U V): int; axiom (forall m: Map U V :: { Map#Card(m) } 0 <= Map#Card(m)); function Map#Empty(): Map U V; axiom (forall u: U :: { Map#Domain(Map#Empty(): Map U V)[u] } !Map#Domain(Map#Empty(): Map U V)[u]); axiom (forall m: Map U V :: { Map#Card(m) } Map#Card(m) == 0 <==> m == Map#Empty()); function Map#Glue([U] bool, [U]V): Map U V; axiom (forall a: [U] bool, b:[U]V :: { Map#Domain(Map#Glue(a, b)) } Map#Domain(Map#Glue(a, b)) == a); axiom (forall a: [U] bool, b:[U]V :: { Map#Elements(Map#Glue(a, b)) } Map#Elements(Map#Glue(a, b)) == b); //Build is used in displays, and for map updates function Map#Build(Map U V, U, V): Map U V; /*axiom (forall m: Map U V, u: U, v: V :: { Map#Domain(Map#Build(m, u, v))[u] } { Map#Elements(Map#Build(m, u, v))[u] } Map#Domain(Map#Build(m, u, v))[u] && Map#Elements(Map#Build(m, u, v))[u] == v);*/ axiom (forall m: Map U V, u: U, u': U, v: V :: { Map#Domain(Map#Build(m, u, v))[u'] } { Map#Elements(Map#Build(m, u, v))[u'] } (u' == u ==> Map#Domain(Map#Build(m, u, v))[u'] && Map#Elements(Map#Build(m, u, v))[u'] == v) && (u' != u ==> Map#Domain(Map#Build(m, u, v))[u'] == Map#Domain(m)[u'] && Map#Elements(Map#Build(m, u, v))[u'] == Map#Elements(m)[u'])); axiom (forall m: Map U V, u: U, v: V :: { Map#Card(Map#Build(m, u, v)) } Map#Domain(m)[u] ==> Map#Card(Map#Build(m, u, v)) == Map#Card(m)); axiom (forall m: Map U V, u: U, v: V :: { Map#Card(Map#Build(m, u, v)) } !Map#Domain(m)[u] ==> Map#Card(Map#Build(m, u, v)) == Map#Card(m) + 1); //equality for maps function Map#Equal(Map U V, Map U V): bool; axiom (forall m: Map U V, m': Map U V:: { Map#Equal(m, m') } Map#Equal(m, m') <==> (forall u : U :: Map#Domain(m)[u] == Map#Domain(m')[u]) && (forall u : U :: Map#Domain(m)[u] ==> Map#Elements(m)[u] == Map#Elements(m')[u])); // extensionality axiom (forall m: Map U V, m': Map U V:: { Map#Equal(m, m') } Map#Equal(m, m') ==> m == m'); function Map#Disjoint(Map U V, Map U V): bool; axiom (forall m: Map U V, m': Map U V :: { Map#Disjoint(m, m') } Map#Disjoint(m, m') <==> (forall o: U :: {Map#Domain(m)[o]} {Map#Domain(m')[o]} !Map#Domain(m)[o] || !Map#Domain(m')[o])); // ------------------------------------------------------------------------- // -- Provide arithmetic wrappers to improve triggering and non-linear math // ------------------------------------------------------------------------- function INTERNAL_add_boogie(x:int, y:int) : int { x + y } function INTERNAL_sub_boogie(x:int, y:int) : int { x - y } function INTERNAL_mul_boogie(x:int, y:int) : int { x * y } function INTERNAL_div_boogie(x:int, y:int) : int { x div y } function INTERNAL_mod_boogie(x:int, y:int) : int { x mod y } function {:never_pattern true} INTERNAL_lt_boogie(x:int, y:int) : bool { x < y } function {:never_pattern true} INTERNAL_le_boogie(x:int, y:int) : bool { x <= y } function {:never_pattern true} INTERNAL_gt_boogie(x:int, y:int) : bool { x > y } function {:never_pattern true} INTERNAL_ge_boogie(x:int, y:int) : bool { x >= y } // ------------------------------------------------------------------------- ================================================ FILE: ironclad-apps/tools/Dafny/DafnyRuntime.cs ================================================ using System; // for Func using System.Numerics; namespace Dafny { using System.Collections.Generic; public class Set { Dictionary dict; Set(Dictionary d) { dict = d; } public static Set Empty { get { return new Set(new Dictionary(0)); } } public static Set FromElements(params T[] values) { Dictionary d = new Dictionary(values.Length); foreach (T t in values) d[t] = true; return new Set(d); } public static Set FromCollection(ICollection values) { Dictionary d = new Dictionary(); foreach (T t in values) d[t] = true; return new Set(d); } public IEnumerable Elements { get { return dict.Keys; } } / / / / public IEnumerable> AllSubsets { get { var elmts = new List(); elmts.AddRange(dict.Keys); var n = elmts.Count; var which = new bool[n]; var s = new Set(new Dictionary(0)); while (true) { yield return s; int i = 0; for (; i < n && which[i]; i++) { which[i] = false; s.dict.Remove(elmts[i]); } if (i == n) { break; } which[i] = true; s.dict.Add(elmts[i], true); } } } public bool Equals(Set other) { return dict.Count == other.dict.Count && IsSubsetOf(other); } public override bool Equals(object other) { return other is Set && Equals((Set)other); } public override int GetHashCode() { return dict.GetHashCode(); } public override string ToString() { var s = "{"; var sep = ""; foreach (var t in dict.Keys) { s += sep + t.ToString(); sep = ", "; } return s + "}"; } public bool IsProperSubsetOf(Set other) { return dict.Count < other.dict.Count && IsSubsetOf(other); } public bool IsSubsetOf(Set other) { if (other.dict.Count < dict.Count) return false; foreach (T t in dict.Keys) { if (!other.dict.ContainsKey(t)) return false; } return true; } public bool IsSupersetOf(Set other) { return other.IsSubsetOf(this); } public bool IsProperSupersetOf(Set other) { return other.IsProperSubsetOf(this); } public bool IsDisjointFrom(Set other) { Dictionary a, b; if (dict.Count < other.dict.Count) { a = dict; b = other.dict; } else { a = other.dict; b = dict; } foreach (T t in a.Keys) { if (b.ContainsKey(t)) return false; } return true; } public bool Contains(T t) { return dict.ContainsKey(t); } public Set Union(Set other) { if (dict.Count == 0) return other; else if (other.dict.Count == 0) return this; Dictionary a, b; if (dict.Count < other.dict.Count) { a = dict; b = other.dict; } else { a = other.dict; b = dict; } Dictionary r = new Dictionary(); foreach (T t in b.Keys) r[t] = true; foreach (T t in a.Keys) r[t] = true; return new Set(r); } public Set Intersect(Set other) { if (dict.Count == 0) return this; else if (other.dict.Count == 0) return other; Dictionary a, b; if (dict.Count < other.dict.Count) { a = dict; b = other.dict; } else { a = other.dict; b = dict; } var r = new Dictionary(); foreach (T t in a.Keys) { if (b.ContainsKey(t)) r.Add(t, true); } return new Set(r); } public Set Difference(Set other) { if (dict.Count == 0) return this; else if (other.dict.Count == 0) return this; var r = new Dictionary(); foreach (T t in dict.Keys) { if (!other.dict.ContainsKey(t)) r.Add(t, true); } return new Set(r); } } public class MultiSet { Dictionary dict; MultiSet(Dictionary d) { dict = d; } public static MultiSet Empty { get { return new MultiSet(new Dictionary(0)); } } public static MultiSet FromElements(params T[] values) { Dictionary d = new Dictionary(values.Length); foreach (T t in values) { var i = 0; if (!d.TryGetValue(t, out i)) { i = 0; } d[t] = i + 1; } return new MultiSet(d); } public static MultiSet FromCollection(ICollection values) { Dictionary d = new Dictionary(); foreach (T t in values) { var i = 0; if (!d.TryGetValue(t, out i)) { i = 0; } d[t] = i + 1; } return new MultiSet(d); } public static MultiSet FromSeq(Sequence values) { Dictionary d = new Dictionary(); foreach (T t in values.Elements) { var i = 0; if (!d.TryGetValue(t, out i)) { i = 0; } d[t] = i + 1; } return new MultiSet(d); } public static MultiSet FromSet(Set values) { Dictionary d = new Dictionary(); foreach (T t in values.Elements) { d[t] = 1; } return new MultiSet(d); } public bool Equals(MultiSet other) { return other.IsSubsetOf(this) && this.IsSubsetOf(other); } public override bool Equals(object other) { return other is MultiSet && Equals((MultiSet)other); } public override int GetHashCode() { return dict.GetHashCode(); } public override string ToString() { var s = "multiset{"; var sep = ""; foreach (var kv in dict) { var t = kv.Key.ToString(); for (int i = 0; i < kv.Value; i++) { s += sep + t.ToString(); sep = ", "; } } return s + "}"; } public bool IsProperSubsetOf(MultiSet other) { return !Equals(other) && IsSubsetOf(other); } public bool IsSubsetOf(MultiSet other) { foreach (T t in dict.Keys) { if (!other.dict.ContainsKey(t) || other.dict[t] < dict[t]) return false; } return true; } public bool IsSupersetOf(MultiSet other) { return other.IsSubsetOf(this); } public bool IsProperSupersetOf(MultiSet other) { return other.IsProperSubsetOf(this); } public bool IsDisjointFrom(MultiSet other) { foreach (T t in dict.Keys) { if (other.dict.ContainsKey(t)) return false; } foreach (T t in other.dict.Keys) { if (dict.ContainsKey(t)) return false; } return true; } public bool Contains(T t) { return dict.ContainsKey(t); } public MultiSet Union(MultiSet other) { if (dict.Count == 0) return other; else if (other.dict.Count == 0) return this; var r = new Dictionary(); foreach (T t in dict.Keys) { var i = 0; if (!r.TryGetValue(t, out i)) { i = 0; } r[t] = i + dict[t]; } foreach (T t in other.dict.Keys) { var i = 0; if (!r.TryGetValue(t, out i)) { i = 0; } r[t] = i + other.dict[t]; } return new MultiSet(r); } public MultiSet Intersect(MultiSet other) { if (dict.Count == 0) return this; else if (other.dict.Count == 0) return other; var r = new Dictionary(); foreach (T t in dict.Keys) { if (other.dict.ContainsKey(t)) { r.Add(t, other.dict[t] < dict[t] ? other.dict[t] : dict[t]); } } return new MultiSet(r); } public MultiSet Difference(MultiSet other) { if (dict.Count == 0) return this; else if (other.dict.Count == 0) return this; var r = new Dictionary(); foreach (T t in dict.Keys) { if (!other.dict.ContainsKey(t)) { r.Add(t, dict[t]); } else if (other.dict[t] < dict[t]) { r.Add(t, dict[t] - other.dict[t]); } } return new MultiSet(r); } public IEnumerable Elements { get { List l = new List(); foreach (T t in dict.Keys) { int n; dict.TryGetValue(t, out n); for (int i = 0; i < n; i ++) { l.Add(t); } } return l; } } } public class Map { Dictionary dict; Map(Dictionary d) { dict = d; } public static Map Empty { get { return new Map(new Dictionary()); } } public static Map FromElements(params Pair[] values) { Dictionary d = new Dictionary(values.Length); foreach (Pair p in values) { d[p.Car] = p.Cdr; } return new Map(d); } public static Map FromCollection(List> values) { Dictionary d = new Dictionary(values.Count); foreach (Pair p in values) { d[p.Car] = p.Cdr; } return new Map(d); } public bool Equals(Map other) { foreach (U u in dict.Keys) { V v1, v2; if (!dict.TryGetValue(u, out v1)) { return false; } if (!other.dict.TryGetValue(u, out v2)) { return false; } if (!v1.Equals(v2)) { return false; } } foreach (U u in other.dict.Keys) { if (!dict.ContainsKey(u)) { return false; } } return true; } public override bool Equals(object other) { return other is Map && Equals((Map)other); } public override int GetHashCode() { return dict.GetHashCode(); } public override string ToString() { var s = "map["; var sep = ""; foreach (var kv in dict) { s += sep + kv.Key.ToString() + " := " + kv.Value.ToString(); sep = ", "; } return s + "]"; } public bool IsDisjointFrom(Map other) { foreach (U u in dict.Keys) { if (other.dict.ContainsKey(u)) return false; } foreach (U u in other.dict.Keys) { if (dict.ContainsKey(u)) return false; } return true; } public bool Contains(U u) { return dict.ContainsKey(u); } public V Select(U index) { return dict[index]; } public Map Update(U index, V val) { Dictionary d = new Dictionary(dict); d[index] = val; return new Map(d); } public IEnumerable Domain { get { return dict.Keys; } } } public class Sequence { T[] elmts; public Sequence(T[] ee) { elmts = ee; } public static Sequence Empty { get { return new Sequence(new T[0]); } } public static Sequence FromElements(params T[] values) { return new Sequence(values); } public static Sequence FromString(string s) { return new Sequence(s.ToCharArray()); } public int Length { get { return elmts.Length; } } public long LongLength { get { return elmts.LongLength; } } public T[] Elements { get { return elmts; } } public IEnumerable UniqueElements { get { var st = Set.FromElements(elmts); return st.Elements; } } public T Select(ulong index) { return elmts[index]; } public T Select(long index) { return elmts[index]; } public T Select(uint index) { return elmts[index]; } public T Select(int index) { return elmts[index]; } public T Select(BigInteger index) { return elmts[(int)index]; } public Sequence Update(long index, T t) { T[] a = (T[])elmts.Clone(); a[index] = t; return new Sequence(a); } public Sequence Update(ulong index, T t) { return Update((long)index, t); } public Sequence Update(BigInteger index, T t) { return Update((long)index, t); } public bool Equals(Sequence other) { int n = elmts.Length; return n == other.elmts.Length && EqualUntil(other, n); } public override bool Equals(object other) { return other is Sequence && Equals((Sequence)other); } public override int GetHashCode() { return elmts.GetHashCode(); } public override string ToString() { if (elmts is char[]) { var s = ""; foreach (var t in elmts) { s += t.ToString(); } return s; } else { var s = "["; var sep = ""; foreach (var t in elmts) { s += sep + t.ToString(); sep = ", "; } return s + "]"; } } bool EqualUntil(Sequence other, int n) { for (int i = 0; i < n; i++) { if (!elmts[i].Equals(other.elmts[i])) return false; } return true; } public bool IsProperPrefixOf(Sequence other) { int n = elmts.Length; return n < other.elmts.Length && EqualUntil(other, n); } public bool IsPrefixOf(Sequence other) { int n = elmts.Length; return n <= other.elmts.Length && EqualUntil(other, n); } public Sequence Concat(Sequence other) { if (elmts.Length == 0) return other; else if (other.elmts.Length == 0) return this; T[] a = new T[elmts.Length + other.elmts.Length]; System.Array.Copy(elmts, 0, a, 0, elmts.Length); System.Array.Copy(other.elmts, 0, a, elmts.Length, other.elmts.Length); return new Sequence(a); } public bool Contains(T t) { int n = elmts.Length; for (int i = 0; i < n; i++) { if (t.Equals(elmts[i])) return true; } return false; } public Sequence Take(long m) { if (elmts.LongLength == m) return this; T[] a = new T[m]; System.Array.Copy(elmts, a, m); return new Sequence(a); } public Sequence Take(ulong n) { return Take((long)n); } public Sequence Take(BigInteger n) { return Take((long)n); } public Sequence Drop(long m) { if (m == 0) return this; T[] a = new T[elmts.Length - m]; System.Array.Copy(elmts, m, a, 0, elmts.Length - m); return new Sequence(a); } public Sequence Drop(ulong n) { return Drop((long)n); } public Sequence Drop(BigInteger n) { if (n.IsZero) return this; return Drop((long)n); } } public struct Pair { public readonly A Car; public readonly B Cdr; public Pair(A a, B b) { this.Car = a; this.Cdr = b; } } public partial class Helpers { public static bool QuantBool(bool frall, System.Predicate pred) { if (frall) { return pred(false) && pred(true); } else { return pred(false) || pred(true); } } public static bool QuantInt(BigInteger lo, BigInteger hi, bool frall, System.Predicate pred) { for (BigInteger i = lo; i < hi; i++) { if (pred(i) != frall) { return !frall; } } return frall; } public static bool QuantSet(Dafny.Set set, bool frall, System.Predicate pred) { foreach (var u in set.Elements) { if (pred(u) != frall) { return !frall; } } return frall; } public static bool QuantMap(Dafny.Map map, bool frall, System.Predicate pred) { foreach (var u in map.Domain) { if (pred(u) != frall) { return !frall; } } return frall; } public static bool QuantSeq(Dafny.Sequence seq, bool frall, System.Predicate pred) { foreach (var u in seq.Elements) { if (pred(u) != frall) { return !frall; } } return frall; } public static bool QuantDatatype(IEnumerable set, bool frall, System.Predicate pred) { foreach (var u in set) { if (pred(u) != frall) { return !frall; } } return frall; } public delegate Dafny.Set ComprehensionDelegate(); public delegate Dafny.Map MapComprehensionDelegate(); public static IEnumerable AllBooleans { get { yield return false; yield return true; } } public static IEnumerable AllIntegers { get { yield return new BigInteger(0); for (var j = new BigInteger(1);; j++) { yield return j; yield return -j; } } } // pre: b != 0 // post: result == a/b, as defined by Euclidean Division (http://en.wikipedia.org/wiki/Modulo_operation) public static sbyte EuclideanDivision_sbyte(sbyte a, sbyte b) { return (sbyte)EuclideanDivision_int(a, b); } public static short EuclideanDivision_short(short a, short b) { return (short)EuclideanDivision_int(a, b); } public static int EuclideanDivision_int(int a, int b) { if (0 <= a) { if (0 <= b) { // +a +b: a/b return (int)(((uint)(a)) / ((uint)(b))); } else { // +a -b: -(a/(-b)) return -((int)(((uint)(a)) / ((uint)(unchecked(-b))))); } } else { if (0 <= b) { // -a +b: -((-a-1)/b) - 1 return -((int)(((uint)(-(a + 1))) / ((uint)(b)))) - 1; } else { // -a -b: ((-a-1)/(-b)) + 1 return ((int)(((uint)(-(a + 1))) / ((uint)(unchecked(-b))))) + 1; } } } public static long EuclideanDivision_long(long a, long b) { if (0 <= a) { if (0 <= b) { // +a +b: a/b return (long)(((ulong)(a)) / ((ulong)(b))); } else { // +a -b: -(a/(-b)) return -((long)(((ulong)(a)) / ((ulong)(unchecked(-b))))); } } else { if (0 <= b) { // -a +b: -((-a-1)/b) - 1 return -((long)(((ulong)(-(a + 1))) / ((ulong)(b)))) - 1; } else { // -a -b: ((-a-1)/(-b)) + 1 return ((long)(((ulong)(-(a + 1))) / ((ulong)(unchecked(-b))))) + 1; } } } public static BigInteger EuclideanDivision(BigInteger a, BigInteger b) { if (0 <= a.Sign) { if (0 <= b.Sign) { return BigInteger.Divide(a, b); } else { return BigInteger.Negate(BigInteger.Divide(a, BigInteger.Negate(b))); } } else { if (0 <= b.Sign) { return BigInteger.Negate(BigInteger.Divide(BigInteger.Negate(a) - 1, b)) - 1; } else { return BigInteger.Divide(BigInteger.Negate(a) - 1, BigInteger.Negate(b)) + 1; } } } // pre: b != 0 // post: result == a%b, as defined by Euclidean Division (http://en.wikipedia.org/wiki/Modulo_operation) public static sbyte EuclideanModulus_sbyte(sbyte a, sbyte b) { return (sbyte)EuclideanModulus_int(a, b); } public static short EuclideanModulus_short(short a, short b) { return (short)EuclideanModulus_int(a, b); } public static int EuclideanModulus_int(int a, int b) { uint bp = (0 <= b) ? (uint)b : (uint)(unchecked(-b)); if (0 <= a) { // +a: a % b' return (int)(((uint)a) % bp); } else { // c = ((-a) % b') // -a: b' - c if c > 0 // -a: 0 if c == 0 uint c = ((uint)(unchecked(-a))) % bp; return (int)(c == 0 ? c : bp - c); } } public static long EuclideanModulus_long(long a, long b) { ulong bp = (0 <= b) ? (ulong)b : (ulong)(unchecked(-b)); if (0 <= a) { // +a: a % b' return (long)(((ulong)a) % bp); } else { // c = ((-a) % b') // -a: b' - c if c > 0 // -a: 0 if c == 0 ulong c = ((ulong)(unchecked(-a))) % bp; return (long)(c == 0 ? c : bp - c); } } public static BigInteger EuclideanModulus(BigInteger a, BigInteger b) { var bp = BigInteger.Abs(b); if (0 <= a.Sign) { return BigInteger.Remainder(a, bp); } else { var c = BigInteger.Remainder(BigInteger.Negate(a), bp); return c.IsZero ? c : BigInteger.Subtract(bp, c); } } public static Sequence SeqFromArray(T[] array) { return new Sequence(array); } public static U ExpressionSequence(T t, U u) { return u; } public static U Let(T t, Func f) { return f(t); } public delegate Result Function(Input input); public static A Id(A a) { return a; } } public struct BigRational { public static readonly BigRational ZERO = new BigRational(0); BigInteger num, den; // invariant 1 <= den public override string ToString() { return string.Format("({0}.0 / {1}.0)", num, den); } public BigRational(int n) { num = new BigInteger(n); den = BigInteger.One; } public BigRational(BigInteger n, BigInteger d) { // requires 1 <= d num = n; den = d; } public BigInteger ToBigInteger() { if (0 <= num) { return num / den; } else { return (num - den + 1) / den; } } /// /// Returns values such that aa/dd == a and bb/dd == b. /// private static void Normalize(BigRational a, BigRational b, out BigInteger aa, out BigInteger bb, out BigInteger dd) { var gcd = BigInteger.GreatestCommonDivisor(a.den, b.den); var xx = a.den / gcd; var yy = b.den / gcd; // We now have a == a.num / (xx * gcd) and b == b.num / (yy * gcd). aa = a.num * yy; bb = b.num * xx; dd = a.den * yy; } public int CompareTo(BigRational that) { // simple things first int asign = this.num.Sign; int bsign = that.num.Sign; if (asign < 0 && 0 <= bsign) { return 1; } else if (asign <= 0 && 0 < bsign) { return 1; } else if (bsign < 0 && 0 <= asign) { return -1; } else if (bsign <= 0 && 0 < asign) { return -1; } BigInteger aa, bb, dd; Normalize(this, that, out aa, out bb, out dd); return aa.CompareTo(bb); } public override int GetHashCode() { return num.GetHashCode() + 29 * den.GetHashCode(); } public override bool Equals(object obj) { if (obj is BigRational) { return this == (BigRational)obj; } else { return false; } } public static bool operator ==(BigRational a, BigRational b) { return a.CompareTo(b) == 0; } public static bool operator !=(BigRational a, BigRational b) { return a.CompareTo(b) != 0; } public static bool operator >(BigRational a, BigRational b) { return 0 < a.CompareTo(b); } public static bool operator >=(BigRational a, BigRational b) { return 0 <= a.CompareTo(b); } public static bool operator <(BigRational a, BigRational b) { return a.CompareTo(b) < 0; } public static bool operator <=(BigRational a, BigRational b) { return a.CompareTo(b) <= 0; } public static BigRational operator +(BigRational a, BigRational b) { BigInteger aa, bb, dd; Normalize(a, b, out aa, out bb, out dd); return new BigRational(aa + bb, dd); } public static BigRational operator -(BigRational a, BigRational b) { BigInteger aa, bb, dd; Normalize(a, b, out aa, out bb, out dd); return new BigRational(aa - bb, dd); } public static BigRational operator -(BigRational a) { return new BigRational(-a.num, a.den); } public static BigRational operator *(BigRational a, BigRational b) { return new BigRational(a.num * b.num, a.den * b.den); } public static BigRational operator /(BigRational a, BigRational b) { // Compute the reciprocal of b BigRational bReciprocal; if (0 < b.num) { bReciprocal = new BigRational(b.den, b.num); } else { // this is the case b.num < 0 bReciprocal = new BigRational(-b.den, -b.num); } return a * bReciprocal; } } } ================================================ FILE: ironclad-apps/tools/Dafny/Microsoft.Z3.xml ================================================ Microsoft.Z3 ApplyResult objects represent the result of an application of a tactic to a goal. It contains the subgoals that were produced. Internal base class for interfacing with native Z3 objects. Should not be used externally. Finalizer. Convert a model for the subgoal into a model for the original goal g, that the ApplyResult was obtained from. A model for g A string representation of the ApplyResult. The number of Subgoals. Retrieves the subgoals from the ApplyResult. The abstract syntax tree (AST) class. Comparison operator. An AST An AST True if and are from the same context and represent the same sort; false otherwise. Comparison operator. An AST An AST True if and are not from the same context or represent different sorts; false otherwise. Object comparison. Object Comparison. Another AST Negative if the object should be sorted before , positive if after else zero. The AST's hash code. A hash code Translates (copies) the AST to the Context . A context A copy of the AST which is associated with A string representation of the AST. A string representation of the AST in s-expression notation. A unique identifier for the AST (unique among all ASTs). The kind of the AST. Indicates whether the AST is an Expr Indicates whether the AST is a BoundVariable Indicates whether the AST is a Quantifier Indicates whether the AST is a Sort Indicates whether the AST is a FunctionDeclaration Map from AST to AST Checks whether the map contains the key . An AST True if is a key in the map, false otherwise. Finds the value associated with the key . This function signs an error when is not a key in the map. An AST Stores or replaces a new key/value pair in the map. The key AST The value AST Erases the key from the map. An AST Removes all keys from the map. Retrieves a string representation of the map. The size of the map The keys stored in the map. Vectors of ASTs. Resize the vector to . The new size of the vector. Add the AST to the back of the vector. The size is increased by 1. An AST Translates all ASTs in the vector to . A context A new ASTVector Retrieves a string representation of the vector. The size of the vector Retrieves the i-th object in the vector. May throw an IndexOutOfBoundsException when is out of range. Index An AST Constructors are used for datatype sorts. Destructor. The number of fields of the constructor. The function declaration of the constructor. The function declaration of the tester. The function declarations of the accessors Lists of constructors Destructor. Z3_lbool Z3_symbol_kind Z3_parameter_kind Z3_sort_kind Z3_ast_kind Z3_decl_kind Z3_ast_print_mode Z3_error_code Z3_goal_prec Expressions are terms. Returns a simplified version of the expression. A set of parameters to configure the simplifier Update the arguments of the expression using the arguments The number of new arguments should coincide with the current number of arguments. Substitute every occurrence of from[i] in the expression with to[i], for i smaller than num_exprs. The result is the new expression. The arrays from and to must have size num_exprs. For every i smaller than num_exprs, we must have that sort of from[i] must be equal to sort of to[i]. Substitute every occurrence of from in the expression with to. Substitute the free variables in the expression with the expressions in For every i smaller than num_exprs, the variable with de-Bruijn index i is replaced with term to[i]. Translates (copies) the term to the Context . A context A copy of the term which is associated with Returns a string representation of the expression. Constructor for Expr Constructor for Expr The function declaration of the function that is applied in this expression. Indicates whether the expression is the true or false expression or something else (Z3_L_UNDEF). The number of arguments of the expression. The arguments of the expression. Indicates whether the term is a numeral Indicates whether the term is well-sorted. True if the term is well-sorted, false otherwise. The Sort of the term. Indicates whether the term represents a constant. Indicates whether the term is an integer numeral. Indicates whether the term is a real numeral. Indicates whether the term is an algebraic number Indicates whether the term has Boolean sort. Indicates whether the term is the constant true. Indicates whether the term is the constant false. Indicates whether the term is an equality predicate. Indicates whether the term is an n-ary distinct predicate (every argument is mutually distinct). Indicates whether the term is a ternary if-then-else term Indicates whether the term is an n-ary conjunction Indicates whether the term is an n-ary disjunction Indicates whether the term is an if-and-only-if (Boolean equivalence, binary) Indicates whether the term is an exclusive or Indicates whether the term is a negation Indicates whether the term is an implication Indicates whether the term is of integer sort. Indicates whether the term is of sort real. Indicates whether the term is an arithmetic numeral. Indicates whether the term is a less-than-or-equal Indicates whether the term is a greater-than-or-equal Indicates whether the term is a less-than Indicates whether the term is a greater-than Indicates whether the term is addition (binary) Indicates whether the term is subtraction (binary) Indicates whether the term is a unary minus Indicates whether the term is multiplication (binary) Indicates whether the term is division (binary) Indicates whether the term is integer division (binary) Indicates whether the term is remainder (binary) Indicates whether the term is modulus (binary) Indicates whether the term is a coercion of integer to real (unary) Indicates whether the term is a coercion of real to integer (unary) Indicates whether the term is a check that tests whether a real is integral (unary) Indicates whether the term is of an array sort. Indicates whether the term is an array store. It satisfies select(store(a,i,v),j) = if i = j then v else select(a,j). Array store takes at least 3 arguments. Indicates whether the term is an array select. Indicates whether the term is a constant array. For example, select(const(v),i) = v holds for every v and i. The function is unary. Indicates whether the term is a default array. For example default(const(v)) = v. The function is unary. Indicates whether the term is an array map. It satisfies map[f](a1,..,a_n)[i] = f(a1[i],...,a_n[i]) for every i. Indicates whether the term is an as-array term. An as-array term is n array value that behaves as the function graph of the function passed as parameter. Indicates whether the term is set union Indicates whether the term is set intersection Indicates whether the term is set difference Indicates whether the term is set complement Indicates whether the term is set subset Indicates whether the terms is of bit-vector sort. Indicates whether the term is a bit-vector numeral Indicates whether the term is a one-bit bit-vector with value one Indicates whether the term is a one-bit bit-vector with value zero Indicates whether the term is a bit-vector unary minus Indicates whether the term is a bit-vector addition (binary) Indicates whether the term is a bit-vector subtraction (binary) Indicates whether the term is a bit-vector multiplication (binary) Indicates whether the term is a bit-vector signed division (binary) Indicates whether the term is a bit-vector unsigned division (binary) Indicates whether the term is a bit-vector signed remainder (binary) Indicates whether the term is a bit-vector unsigned remainder (binary) Indicates whether the term is a bit-vector signed modulus Indicates whether the term is a bit-vector signed division by zero Indicates whether the term is a bit-vector unsigned division by zero Indicates whether the term is a bit-vector signed remainder by zero Indicates whether the term is a bit-vector unsigned remainder by zero Indicates whether the term is a bit-vector signed modulus by zero Indicates whether the term is an unsigned bit-vector less-than-or-equal Indicates whether the term is a signed bit-vector less-than-or-equal Indicates whether the term is an unsigned bit-vector greater-than-or-equal Indicates whether the term is a signed bit-vector greater-than-or-equal Indicates whether the term is an unsigned bit-vector less-than Indicates whether the term is a signed bit-vector less-than Indicates whether the term is an unsigned bit-vector greater-than Indicates whether the term is a signed bit-vector greater-than Indicates whether the term is a bit-wise AND Indicates whether the term is a bit-wise OR Indicates whether the term is a bit-wise NOT Indicates whether the term is a bit-wise XOR Indicates whether the term is a bit-wise NAND Indicates whether the term is a bit-wise NOR Indicates whether the term is a bit-wise XNOR Indicates whether the term is a bit-vector concatenation (binary) Indicates whether the term is a bit-vector sign extension Indicates whether the term is a bit-vector zero extension Indicates whether the term is a bit-vector extraction Indicates whether the term is a bit-vector repetition Indicates whether the term is a bit-vector reduce OR Indicates whether the term is a bit-vector reduce AND Indicates whether the term is a bit-vector comparison Indicates whether the term is a bit-vector shift left Indicates whether the term is a bit-vector logical shift right Indicates whether the term is a bit-vector arithmetic shift left Indicates whether the term is a bit-vector rotate left Indicates whether the term is a bit-vector rotate right Indicates whether the term is a bit-vector rotate left (extended) Similar to Z3_OP_ROTATE_LEFT, but it is a binary operator instead of a parametric one. Indicates whether the term is a bit-vector rotate right (extended) Similar to Z3_OP_ROTATE_RIGHT, but it is a binary operator instead of a parametric one. Indicates whether the term is a coercion from integer to bit-vector This function is not supported by the decision procedures. Only the most rudimentary simplification rules are applied to this function. Indicates whether the term is a coercion from bit-vector to integer This function is not supported by the decision procedures. Only the most rudimentary simplification rules are applied to this function. Indicates whether the term is a bit-vector carry Compute the carry bit in a full-adder. The meaning is given by the equivalence (carry l1 l2 l3) <=> (or (and l1 l2) (and l1 l3) (and l2 l3))) Indicates whether the term is a bit-vector ternary XOR The meaning is given by the equivalence (xor3 l1 l2 l3) <=> (xor (xor l1 l2) l3) Indicates whether the term is a label (used by the Boogie Verification condition generator). The label has two parameters, a string and a Boolean polarity. It takes one argument, a formula. Indicates whether the term is a label literal (used by the Boogie Verification condition generator). A label literal has a set of string parameters. It takes no arguments. Indicates whether the term is a binary equivalence modulo namings. This binary predicate is used in proof terms. It captures equisatisfiability and equivalence modulo renamings. Indicates whether the term is a Proof for the expression 'true'. Indicates whether the term is a proof for a fact asserted by the user. Indicates whether the term is a proof for a fact (tagged as goal) asserted by the user. Indicates whether the term is proof via modus ponens Given a proof for p and a proof for (implies p q), produces a proof for q. T1: p T2: (implies p q) [mp T1 T2]: q The second antecedents may also be a proof for (iff p q). Indicates whether the term is a proof for (R t t), where R is a reflexive relation. This proof object has no antecedents. The only reflexive relations that are used are equivalence modulo namings, equality and equivalence. That is, R is either '~', '=' or 'iff'. Indicates whether the term is proof by symmetricity of a relation Given an symmetric relation R and a proof for (R t s), produces a proof for (R s t). T1: (R t s) [symmetry T1]: (R s t) T1 is the antecedent of this proof object. Indicates whether the term is a proof by transitivity of a relation Given a transitive relation R, and proofs for (R t s) and (R s u), produces a proof for (R t u). T1: (R t s) T2: (R s u) [trans T1 T2]: (R t u) Indicates whether the term is a proof by condensed transitivity of a relation Condensed transitivity proof. This proof object is only used if the parameter PROOF_MODE is 1. It combines several symmetry and transitivity proofs. Example: T1: (R a b) T2: (R c b) T3: (R c d) [trans* T1 T2 T3]: (R a d) R must be a symmetric and transitive relation. Assuming that this proof object is a proof for (R s t), then a proof checker must check if it is possible to prove (R s t) using the antecedents, symmetry and transitivity. That is, if there is a path from s to t, if we view every antecedent (R a b) as an edge between a and b. Indicates whether the term is a monotonicity proof object. T1: (R t_1 s_1) ... Tn: (R t_n s_n) [monotonicity T1 ... Tn]: (R (f t_1 ... t_n) (f s_1 ... s_n)) Remark: if t_i == s_i, then the antecedent Ti is suppressed. That is, reflexivity proofs are supressed to save space. Indicates whether the term is a quant-intro proof Given a proof for (~ p q), produces a proof for (~ (forall (x) p) (forall (x) q)). T1: (~ p q) [quant-intro T1]: (~ (forall (x) p) (forall (x) q)) Indicates whether the term is a distributivity proof object. Given that f (= or) distributes over g (= and), produces a proof for (= (f a (g c d)) (g (f a c) (f a d))) If f and g are associative, this proof also justifies the following equality: (= (f (g a b) (g c d)) (g (f a c) (f a d) (f b c) (f b d))) where each f and g can have arbitrary number of arguments. This proof object has no antecedents. Remark. This rule is used by the CNF conversion pass and instantiated by f = or, and g = and. Indicates whether the term is a proof by elimination of AND Given a proof for (and l_1 ... l_n), produces a proof for l_i T1: (and l_1 ... l_n) [and-elim T1]: l_i Indicates whether the term is a proof by eliminiation of not-or Given a proof for (not (or l_1 ... l_n)), produces a proof for (not l_i). T1: (not (or l_1 ... l_n)) [not-or-elim T1]: (not l_i) Indicates whether the term is a proof by rewriting A proof for a local rewriting step (= t s). The head function symbol of t is interpreted. This proof object has no antecedents. The conclusion of a rewrite rule is either an equality (= t s), an equivalence (iff t s), or equi-satisfiability (~ t s). Remark: if f is bool, then = is iff. Examples: (= (+ x 0) x) (= (+ x 1 2) (+ 3 x)) (iff (or x false) x) Indicates whether the term is a proof by rewriting A proof for rewriting an expression t into an expression s. This proof object is used if the parameter PROOF_MODE is 1. This proof object can have n antecedents. The antecedents are proofs for equalities used as substitution rules. The object is also used in a few cases if the parameter PROOF_MODE is 2. The cases are: - When applying contextual simplification (CONTEXT_SIMPLIFIER=true) - When converting bit-vectors to Booleans (BIT2BOOL=true) - When pulling ite expression up (PULL_CHEAP_ITE_TREES=true) Indicates whether the term is a proof for pulling quantifiers out. A proof for (iff (f (forall (x) q(x)) r) (forall (x) (f (q x) r))). This proof object has no antecedents. Indicates whether the term is a proof for pulling quantifiers out. A proof for (iff P Q) where Q is in prenex normal form. This proof object is only used if the parameter PROOF_MODE is 1. This proof object has no antecedents Indicates whether the term is a proof for pushing quantifiers in. A proof for: (iff (forall (x_1 ... x_m) (and p_1[x_1 ... x_m] ... p_n[x_1 ... x_m])) (and (forall (x_1 ... x_m) p_1[x_1 ... x_m]) ... (forall (x_1 ... x_m) p_n[x_1 ... x_m]))) This proof object has no antecedents Indicates whether the term is a proof for elimination of unused variables. A proof for (iff (forall (x_1 ... x_n y_1 ... y_m) p[x_1 ... x_n]) (forall (x_1 ... x_n) p[x_1 ... x_n])) It is used to justify the elimination of unused variables. This proof object has no antecedents. Indicates whether the term is a proof for destructive equality resolution A proof for destructive equality resolution: (iff (forall (x) (or (not (= x t)) P[x])) P[t]) if x does not occur in t. This proof object has no antecedents. Several variables can be eliminated simultaneously. Indicates whether the term is a proof for quantifier instantiation A proof of (or (not (forall (x) (P x))) (P a)) Indicates whether the term is a hypthesis marker. Mark a hypothesis in a natural deduction style proof. Indicates whether the term is a proof by lemma T1: false [lemma T1]: (or (not l_1) ... (not l_n)) This proof object has one antecedent: a hypothetical proof for false. It converts the proof in a proof for (or (not l_1) ... (not l_n)), when T1 contains the hypotheses: l_1, ..., l_n. Indicates whether the term is a proof by unit resolution T1: (or l_1 ... l_n l_1' ... l_m') T2: (not l_1) ... T(n+1): (not l_n) [unit-resolution T1 ... T(n+1)]: (or l_1' ... l_m') Indicates whether the term is a proof by iff-true T1: p [iff-true T1]: (iff p true) Indicates whether the term is a proof by iff-false T1: (not p) [iff-false T1]: (iff p false) Indicates whether the term is a proof by commutativity [comm]: (= (f a b) (f b a)) f is a commutative operator. This proof object has no antecedents. Remark: if f is bool, then = is iff. Indicates whether the term is a proof for Tseitin-like axioms Proof object used to justify Tseitin's like axioms: (or (not (and p q)) p) (or (not (and p q)) q) (or (not (and p q r)) p) (or (not (and p q r)) q) (or (not (and p q r)) r) ... (or (and p q) (not p) (not q)) (or (not (or p q)) p q) (or (or p q) (not p)) (or (or p q) (not q)) (or (not (iff p q)) (not p) q) (or (not (iff p q)) p (not q)) (or (iff p q) (not p) (not q)) (or (iff p q) p q) (or (not (ite a b c)) (not a) b) (or (not (ite a b c)) a c) (or (ite a b c) (not a) (not b)) (or (ite a b c) a (not c)) (or (not (not a)) (not a)) (or (not a) a) This proof object has no antecedents. Note: all axioms are propositional tautologies. Note also that 'and' and 'or' can take multiple arguments. You can recover the propositional tautologies by unfolding the Boolean connectives in the axioms a small bounded number of steps (=3). Indicates whether the term is a proof for introduction of a name Introduces a name for a formula/term. Suppose e is an expression with free variables x, and def-intro introduces the name n(x). The possible cases are: When e is of Boolean type: [def-intro]: (and (or n (not e)) (or (not n) e)) or: [def-intro]: (or (not n) e) when e only occurs positively. When e is of the form (ite cond th el): [def-intro]: (and (or (not cond) (= n th)) (or cond (= n el))) Otherwise: [def-intro]: (= n e) Indicates whether the term is a proof for application of a definition [apply-def T1]: F ~ n F is 'equivalent' to n, given that T1 is a proof that n is a name for F. Indicates whether the term is a proof iff-oeq T1: (iff p q) [iff~ T1]: (~ p q) Indicates whether the term is a proof for a positive NNF step Proof for a (positive) NNF step. Example: T1: (not s_1) ~ r_1 T2: (not s_2) ~ r_2 T3: s_1 ~ r_1' T4: s_2 ~ r_2' [nnf-pos T1 T2 T3 T4]: (~ (iff s_1 s_2) (and (or r_1 r_2') (or r_1' r_2))) The negation normal form steps NNF_POS and NNF_NEG are used in the following cases: (a) When creating the NNF of a positive force quantifier. The quantifier is retained (unless the bound variables are eliminated). Example T1: q ~ q_new [nnf-pos T1]: (~ (forall (x T) q) (forall (x T) q_new)) (b) When recursively creating NNF over Boolean formulas, where the top-level connective is changed during NNF conversion. The relevant Boolean connectives for NNF_POS are 'implies', 'iff', 'xor', 'ite'. NNF_NEG furthermore handles the case where negation is pushed over Boolean connectives 'and' and 'or'. Indicates whether the term is a proof for a negative NNF step Proof for a (negative) NNF step. Examples: T1: (not s_1) ~ r_1 ... Tn: (not s_n) ~ r_n [nnf-neg T1 ... Tn]: (not (and s_1 ... s_n)) ~ (or r_1 ... r_n) and T1: (not s_1) ~ r_1 ... Tn: (not s_n) ~ r_n [nnf-neg T1 ... Tn]: (not (or s_1 ... s_n)) ~ (and r_1 ... r_n) and T1: (not s_1) ~ r_1 T2: (not s_2) ~ r_2 T3: s_1 ~ r_1' T4: s_2 ~ r_2' [nnf-neg T1 T2 T3 T4]: (~ (not (iff s_1 s_2)) (and (or r_1 r_2) (or r_1' r_2'))) Indicates whether the term is a proof for (~ P Q) here Q is in negation normal form. A proof for (~ P Q) where Q is in negation normal form. This proof object is only used if the parameter PROOF_MODE is 1. This proof object may have n antecedents. Each antecedent is a PR_DEF_INTRO. Indicates whether the term is a proof for (~ P Q) where Q is in conjunctive normal form. A proof for (~ P Q) where Q is in conjunctive normal form. This proof object is only used if the parameter PROOF_MODE is 1. This proof object may have n antecedents. Each antecedent is a PR_DEF_INTRO. Indicates whether the term is a proof for a Skolemization step Proof for: [sk]: (~ (not (forall x (p x y))) (not (p (sk y) y))) [sk]: (~ (exists x (p x y)) (p (sk y) y)) This proof object has no antecedents. Indicates whether the term is a proof by modus ponens for equi-satisfiability. Modus ponens style rule for equi-satisfiability. T1: p T2: (~ p q) [mp~ T1 T2]: q Indicates whether the term is a proof for theory lemma Generic proof for theory lemmas. The theory lemma function comes with one or more parameters. The first parameter indicates the name of the theory. For the theory of arithmetic, additional parameters provide hints for checking the theory lemma. The hints for arithmetic are: - farkas - followed by rational coefficients. Multiply the coefficients to the inequalities in the lemma, add the (negated) inequalities and obtain a contradiction. - triangle-eq - Indicates a lemma related to the equivalence: (iff (= t1 t2) (and (<= t1 t2) (<= t2 t1))) - gcd-test - Indicates an integer linear arithmetic lemma that uses a gcd test. Indicates whether the term is of an array sort. Indicates whether the term is an relation store Insert a record into a relation. The function takes n+1 arguments, where the first argument is the relation and the remaining n elements correspond to the n columns of the relation. Indicates whether the term is an empty relation Indicates whether the term is a test for the emptiness of a relation Indicates whether the term is a relational join Indicates whether the term is the union or convex hull of two relations. The function takes two arguments. Indicates whether the term is the widening of two relations The function takes two arguments. Indicates whether the term is a projection of columns (provided as numbers in the parameters). The function takes one argument. Indicates whether the term is a relation filter Filter (restrict) a relation with respect to a predicate. The first argument is a relation. The second argument is a predicate with free de-Brujin indices corresponding to the columns of the relation. So the first column in the relation has index 0. Indicates whether the term is an intersection of a relation with the negation of another. Intersect the first relation with respect to negation of the second relation (the function takes two arguments). Logically, the specification can be described by a function target = filter_by_negation(pos, neg, columns) where columns are pairs c1, d1, .., cN, dN of columns from pos and neg, such that target are elements in x in pos, such that there is no y in neg that agrees with x on the columns c1, d1, .., cN, dN. Indicates whether the term is the renaming of a column in a relation The function takes one argument. The parameters contain the renaming as a cycle. Indicates whether the term is the complement of a relation Indicates whether the term is a relational select Check if a record is an element of the relation. The function takes n+1 arguments, where the first argument is a relation, and the remaining n arguments correspond to a record. Indicates whether the term is a relational clone (copy) Create a fresh copy (clone) of a relation. The function is logically the identity, but in the context of a register machine allows for terms of kind to perform destructive updates to the first argument. Indicates whether the term is of an array sort. Indicates whether the term is a less than predicate over a finite domain. The de-Burijn index of a bound variable. Bound variables are indexed by de-Bruijn indices. It is perhaps easiest to explain the meaning of de-Bruijn indices by indicating the compilation process from non-de-Bruijn formulas to de-Bruijn format. abs(forall (x1) phi) = forall (x1) abs1(phi, x1, 0) abs(forall (x1, x2) phi) = abs(forall (x1) abs(forall (x2) phi)) abs1(x, x, n) = b_n abs1(y, x, n) = y abs1(f(t1,...,tn), x, n) = f(abs1(t1,x,n), ..., abs1(tn,x,n)) abs1(forall (x1) phi, x, n) = forall (x1) (abs1(phi, x, n+1)) The last line is significant: the index of a bound variable is different depending on the scope in which it appears. The deeper x appears, the higher is its index. Boolean expressions Constructor for BoolExpr Constructor for BoolExpr Arithmetic expressions (int/real) Constructor for ArithExpr Int expressions Constructor for IntExpr Real expressions Constructor for RealExpr Bit-vector expressions Constructor for BitVecExpr The size of the sort of a bit-vector term. Array expressions Constructor for ArrayExpr Datatype expressions Constructor for DatatypeExpr Object for managing fixedpoints Assert a constraint (or multiple) into the fixedpoint solver. Register predicate as recursive relation. Add rule into the fixedpoint solver. Add table fact to the fixedpoint solver. Query the fixedpoint solver. A query is a conjunction of constraints. The constraints may include the recursively defined relations. The query is satisfiable if there is an instance of the query variables and a derivation for it. The query is unsatisfiable if there are no derivations satisfying the query variables. Query the fixedpoint solver. A query is an array of relations. The query is satisfiable if there is an instance of some relation that is non-empty. The query is unsatisfiable if there are no derivations satisfying any of the relations. Retrieve satisfying instance or instances of solver, or definitions for the recursive predicates that show unsatisfiability. Retrieve explanation why fixedpoint engine returned status Unknown. Retrieve internal string representation of fixedpoint object. Instrument the Datalog engine on which table representation to use for recursive predicate. Convert benchmark given as set of axioms, rules and queries to a string. Function declarations. Comparison operator. True if and share the same context and are equal, false otherwise. Comparison operator. True if and do not share the same context or are not equal, false otherwise. Object comparison. A hash code. A string representations of the function declaration. Create expression that applies function to arguments. Returns a unique identifier for the function declaration. The arity of the function declaration The size of the domain of the function declaration The domain of the function declaration The range of the function declaration The kind of the function declaration. The name of the function declaration The number of parameters of the function declaration The parameters of the function declaration Create expression that applies function to arguments. Function declarations can have Parameters associated with them. The int value of the parameter. The double value of the parameter. The Symbol value of the parameter. The Sort value of the parameter. The AST value of the parameter. The FunctionDeclaration value of the parameter. The rational string value of the parameter. The kind of the parameter. A function interpretation is represented as a finite map and an 'else' value. Each entry in the finite map represents the value of a function given a set of arguments. A string representation of the function interpretation. The number of entries in the function interpretation. The entries in the function interpretation The (symbolic) `else' value of the function interpretation. The arity of the function interpretation An Entry object represents an element in the finite map used to encode a function interpretation. A string representation of the function entry. Return the (symbolic) value of this entry. The number of arguments of the entry. The arguments of the function entry. A goal (aka problem). A goal is essentially a set of formulas, that can be solved and/or transformed using tactics and solvers. Adds the to the given goal. Erases all formulas from the given goal. Translates (copies) the Goal to the target Context . Simplifies the goal. Essentially invokes the `simplify' tactic on the goal. Goal to string conversion. A string representation of the Goal. The precision of the goal. Goals can be transformed using over and under approximations. An under approximation is applied when the objective is to find a model for a given goal. An over approximation is applied when the objective is to find a proof for a given goal. Indicates whether the goal is precise. Indicates whether the goal is an under-approximation. Indicates whether the goal is an over-approximation. Indicates whether the goal is garbage (i.e., the product of over- and under-approximations). Indicates whether the goal contains `false'. The depth of the goal. This tracks how many transformations were applied to it. The number of formulas in the goal. The formulas in the goal. The number of formulas, subformulas and terms in the goal. Indicates whether the goal is empty, and it is precise or the product of an under approximation. Indicates whether the goal contains `false', and it is precise or the product of an over approximation. A Model contains interpretations (assignments) of constants and functions. Retrieves the interpretation (the assignment) of in the model. A Constant An expression if the constant has an interpretation in the model, null otherwise. Retrieves the interpretation (the assignment) of in the model. A function declaration of zero arity An expression if the function has an interpretation in the model, null otherwise. Retrieves the interpretation (the assignment) of a non-constant in the model. A function declaration of non-zero arity A FunctionInterpretation if the function has an interpretation in the model, null otherwise. Evaluates the expression in the current model. This function may fail if contains quantifiers, is partial (MODEL_PARTIAL enabled), or if is not well-sorted. In this case a ModelEvaluationFailedException is thrown. An expression When this flag is enabled, a model value will be assigned to any constant or function that does not have an interpretation in the model. The evaluation of in the model. Alias for Eval. The finite set of distinct values that represent the interpretation for sort . An uninterpreted sort An array of expressions, where each is an element of the universe of Conversion of models to strings. A string representation of the model. The number of constants that have an interpretation in the model. The function declarations of the constants in the model. The number of function interpretations in the model. The function declarations of the function interpretations in the model. All symbols that have an interpretation in the model. The number of uninterpreted sorts that the model has an interpretation for. The uninterpreted sorts that the model has an interpretation for. Z3 also provides an intepretation for uninterpreted sorts used in a formula. The interpretation for a sort is a finite set of distinct values. We say this finite set is the "universe" of the sort. A ModelEvaluationFailedException is thrown when an expression cannot be evaluated by the model. The exception base class for error reporting from Z3 Constructor. Constructor. Constructor. An exception that is thrown when model evaluation fails. Integer Numerals Returns a string representation of the numeral. Retrieve the 64-bit unsigned integer value. Retrieve the int value. Retrieve the 64-bit int value. Retrieve the int value. Retrieve the BigInteger value. Rational Numerals Returns a string representation in decimal notation. The result has at most decimal places. Returns a string representation of the numeral. The numerator of a rational numeral. The denominator of a rational numeral. Converts the numerator of the rational to a BigInteger Converts the denominator of the rational to a BigInteger Bit-vector numerals Returns a string representation of the numeral. Retrieve the 64-bit unsigned integer value. Retrieve the int value. Retrieve the 64-bit int value. Retrieve the int value. Retrieve the BigInteger value. Algebraic numbers Return a upper bound for a given real algebraic number. The interval isolating the number is smaller than 1/10^. the precision of the result A numeral Expr of sort Real Return a lower bound for the given real algebraic number. The interval isolating the number is smaller than 1/10^. A numeral Expr of sort Real Returns a string representation in decimal notation. The result has at most decimal places. A ParameterSet represents a configuration in the form of Symbol/value pairs. Adds a parameter setting. Adds a parameter setting. Adds a parameter setting. Adds a parameter setting. Adds a parameter setting. Adds a parameter setting. Adds a parameter setting. Adds a parameter setting. A string representation of the parameter set. Patterns comprise a list of terms. The list should be non-empty. If the list comprises of more than one term, it is also called a multi-pattern. A string representation of the pattern. The number of terms in the pattern. The terms in the pattern. Objects of this class track statistical information about solvers. A string representation of the statistical data. The number of statistical data. The data entries. The statistical counters. The value of a particular statistical counter. Returns null if the key is unknown. Statistical data is organized into pairs of [Key, Entry], where every Entry is either a DoubleEntry or a UIntEntry The key of the entry. The string representation of the Entry. The uint-value of the entry. The double-value of the entry. True if the entry is uint-valued. True if the entry is double-valued. The string representation of the the entry's value. Status values. Used to signify an unsatisfiable status. Used to signify an unknown status. Used to signify a satisfiable status. The main interaction with Z3 happens via the Context. Constructor. Constructor. Creates a new symbol using an integer. Not all integers can be passed to this function. The legal range of unsigned integers is 0 to 2^30-1. Create a symbol using a string. Create an array of symbols. Create a new Boolean sort. Create a new uninterpreted sort. Create a new uninterpreted sort. Create a new integer sort. Create a real sort. Create a new bit-vector sort. Create a new array sort. Create a new tuple sort. Create a new enumeration sort. Create a new enumeration sort. Create a new list sort. Create a new list sort. Create a new finite domain sort. Create a new finite domain sort. Create a datatype constructor. constructor name name of recognizer function. names of the constructor fields. field sorts, 0 if the field sort refers to a recursive sort. reference to datatype sort that is an argument to the constructor; if the corresponding sort reference is 0, then the value in sort_refs should be an index referring to one of the recursive datatypes that is declared. Create a datatype constructor. Create a new datatype sort. Create a new datatype sort. Create mutually recursive datatypes. names of datatype sorts list of constructors, one list per sort. Create mutually recursive data-types. Creates a new function declaration. Creates a new function declaration. Creates a new function declaration. Creates a new function declaration. Creates a fresh function declaration with a name prefixed with . Creates a new constant function declaration. Creates a new constant function declaration. Creates a fresh constant function declaration with a name prefixed with . Creates a new bound variable. The de-Bruijn index of the variable The sort of the variable Create a quantifier pattern. Creates a new Constant of sort and named . Creates a new Constant of sort and named . Creates a fresh Constant of sort and a name prefixed with . Creates a fresh constant from the FuncDecl . A decl of a 0-arity function Create a Boolean constant. Create a Boolean constant. Creates an integer constant. Creates an integer constant. Creates a real constant. Creates a real constant. Creates a bit-vector constant. Creates a bit-vector constant. Create a new function application. The true Term. The false Term. Creates a Boolean value. Creates the equality = . Creates a distinct term. Mk an expression representing not(a). Create an expression representing an if-then-else: ite(t1, t2, t3). An expression with Boolean sort An expression An expression with the same sort as Create an expression representing t1 iff t2. Create an expression representing t1 -> t2. Create an expression representing t1 xor t2. Create an expression representing t[0] and t[1] and .... Create an expression representing t[0] or t[1] or .... Create an expression representing t[0] + t[1] + .... Create an expression representing t[0] * t[1] * .... Create an expression representing t[0] - t[1] - .... Create an expression representing -t. Create an expression representing t1 / t2. Create an expression representing t1 mod t2. The arguments must have int type. Create an expression representing t1 rem t2. The arguments must have int type. Create an expression representing t1 ^ t2. Create an expression representing t1 < t2 Create an expression representing t1 <= t2 Create an expression representing t1 > t2 Create an expression representing t1 >= t2 Coerce an integer to a real. There is also a converse operation exposed. It follows the semantics prescribed by the SMT-LIB standard. You can take the floor of a real by creating an auxiliary integer Term k and and asserting MakeInt2Real(k) <= t1 < MkInt2Real(k)+1. The argument must be of integer sort. Coerce a real to an integer. The semantics of this function follows the SMT-LIB standard for the function to_int. The argument must be of real sort. Creates an expression that checks whether a real number is an integer. Bitwise negation. The argument must have a bit-vector sort. Take conjunction of bits in a vector, return vector of length 1. The argument must have a bit-vector sort. Take disjunction of bits in a vector, return vector of length 1. The argument must have a bit-vector sort. Bitwise conjunction. The arguments must have a bit-vector sort. Bitwise disjunction. The arguments must have a bit-vector sort. Bitwise XOR. The arguments must have a bit-vector sort. Bitwise NAND. The arguments must have a bit-vector sort. Bitwise NOR. The arguments must have a bit-vector sort. Bitwise XNOR. The arguments must have a bit-vector sort. Standard two's complement unary minus. The arguments must have a bit-vector sort. Two's complement addition. The arguments must have the same bit-vector sort. Two's complement subtraction. The arguments must have the same bit-vector sort. Two's complement multiplication. The arguments must have the same bit-vector sort. Unsigned division. It is defined as the floor of t1/t2 if \c t2 is different from zero. If t2 is zero, then the result is undefined. The arguments must have the same bit-vector sort. Signed division. It is defined in the following way: - The \c floor of t1/t2 if \c t2 is different from zero, and t1*t2 >= 0. - The \c ceiling of t1/t2 if \c t2 is different from zero, and t1*t2 < 0. If t2 is zero, then the result is undefined. The arguments must have the same bit-vector sort. Unsigned remainder. It is defined as t1 - (t1 /u t2) * t2, where /u represents unsigned division. If t2 is zero, then the result is undefined. The arguments must have the same bit-vector sort. Signed remainder. It is defined as t1 - (t1 /s t2) * t2, where /s represents signed division. The most significant bit (sign) of the result is equal to the most significant bit of \c t1. If t2 is zero, then the result is undefined. The arguments must have the same bit-vector sort. Two's complement signed remainder (sign follows divisor). If t2 is zero, then the result is undefined. The arguments must have the same bit-vector sort. Unsigned less-than The arguments must have the same bit-vector sort. Two's complement signed less-than The arguments must have the same bit-vector sort. Unsigned less-than or equal to. The arguments must have the same bit-vector sort. Two's complement signed less-than or equal to. The arguments must have the same bit-vector sort. Unsigned greater than or equal to. The arguments must have the same bit-vector sort. Two's complement signed greater than or equal to. The arguments must have the same bit-vector sort. Unsigned greater-than. The arguments must have the same bit-vector sort. Two's complement signed greater-than. The arguments must have the same bit-vector sort. Bit-vector concatenation. The arguments must have a bit-vector sort. The result is a bit-vector of size n1+n2, where n1 (n2) is the size of t1 (t2). Bit-vector extraction. Extract the bits down to from a bitvector of size m to yield a new bitvector of size n, where n = high - low + 1. The argument must have a bit-vector sort. Bit-vector sign extension. Sign-extends the given bit-vector to the (signed) equivalent bitvector of size m+i, where \c m is the size of the given bit-vector. The argument must have a bit-vector sort. Bit-vector zero extension. Extend the given bit-vector with zeros to the (unsigned) equivalent bitvector of size m+i, where \c m is the size of the given bit-vector. The argument must have a bit-vector sort. Bit-vector repetition. The argument must have a bit-vector sort. Shift left. It is equivalent to multiplication by 2^x where \c x is the value of . NB. The semantics of shift operations varies between environments. This definition does not necessarily capture directly the semantics of the programming language or assembly architecture you are modeling. The arguments must have a bit-vector sort. Logical shift right It is equivalent to unsigned division by 2^x where \c x is the value of . NB. The semantics of shift operations varies between environments. This definition does not necessarily capture directly the semantics of the programming language or assembly architecture you are modeling. The arguments must have a bit-vector sort. Arithmetic shift right It is like logical shift right except that the most significant bits of the result always copy the most significant bit of the second argument. NB. The semantics of shift operations varies between environments. This definition does not necessarily capture directly the semantics of the programming language or assembly architecture you are modeling. The arguments must have a bit-vector sort. Rotate Left. Rotate bits of \c t to the left \c i times. The argument must have a bit-vector sort. Rotate Right. Rotate bits of \c t to the right \c i times. The argument must have a bit-vector sort. Rotate Left. Rotate bits of to the left times. The arguments must have the same bit-vector sort. Rotate Right. Rotate bits of to the right times. The arguments must have the same bit-vector sort. Create an bit bit-vector from the integer argument . NB. This function is essentially treated as uninterpreted. So you cannot expect Z3 to precisely reflect the semantics of this function when solving constraints with this function. The argument must be of integer sort. Create an integer from the bit-vector argument . If \c is_signed is false, then the bit-vector \c t1 is treated as unsigned. So the result is non-negative and in the range [0..2^N-1], where N are the number of bits in . If \c is_signed is true, \c t1 is treated as a signed bit-vector. NB. This function is essentially treated as uninterpreted. So you cannot expect Z3 to precisely reflect the semantics of this function when solving constraints with this function. The argument must be of bit-vector sort. Create a predicate that checks that the bit-wise addition does not overflow. The arguments must be of bit-vector sort. Create a predicate that checks that the bit-wise addition does not underflow. The arguments must be of bit-vector sort. Create a predicate that checks that the bit-wise subtraction does not overflow. The arguments must be of bit-vector sort. Create a predicate that checks that the bit-wise subtraction does not underflow. The arguments must be of bit-vector sort. Create a predicate that checks that the bit-wise signed division does not overflow. The arguments must be of bit-vector sort. Create a predicate that checks that the bit-wise negation does not overflow. The arguments must be of bit-vector sort. Create a predicate that checks that the bit-wise multiplication does not overflow. The arguments must be of bit-vector sort. Create a predicate that checks that the bit-wise multiplication does not underflow. The arguments must be of bit-vector sort. Create an array constant. Create an array constant. Array read. The argument a is the array and i is the index of the array that gets read. The node a must have an array sort [domain -> range], and i must have the sort domain. The sort of the result is range. Array update. The node a must have an array sort [domain -> range], i must have sort domain, v must have sort range. The sort of the result is [domain -> range]. The semantics of this function is given by the theory of arrays described in the SMT-LIB standard. See http://smtlib.org for more details. The result of this function is an array that is equal to a (with respect to select) on all indices except for i, where it maps to v (and the select of a with respect to i may be a different value). Create a constant array. The resulting term is an array, such that a selecton an arbitrary index produces the value v. Maps f on the argument arrays. Eeach element of args must be of an array sort [domain_i -> range_i]. The function declaration f must have type range_1 .. range_n -> range. v must have sort range. The sort of the result is [domain_i -> range]. Access the array default value. Produces the default range value, for arrays that can be represented as finite maps with a default range value. Create a set type. Create an empty set. Create the full set. Add an element to the set. Remove an element from a set. Take the union of a list of sets. Take the intersection of a list of sets. Take the difference between two sets. Take the complement of a set. Check for set membership. Check for subsetness of sets. Create a Term of a given sort. A string representing the Term value in decimal notation. If the given sort is a real, then the Term can be a rational, that is, a string of the form [num]* / [num]*. The sort of the numeral. In the current implementation, the given sort can be an int, real, or bit-vectors of arbitrary size. A Term with value and sort Create a Term of a given sort. This function can be use to create numerals that fit in a machine integer. It is slightly faster than MakeNumeral since it is not necessary to parse a string. Value of the numeral Sort of the numeral A Term with value and type Create a Term of a given sort. This function can be use to create numerals that fit in a machine integer. It is slightly faster than MakeNumeral since it is not necessary to parse a string. Value of the numeral Sort of the numeral A Term with value and type Create a Term of a given sort. This function can be use to create numerals that fit in a machine integer. It is slightly faster than MakeNumeral since it is not necessary to parse a string. Value of the numeral Sort of the numeral A Term with value and type Create a Term of a given sort. This function can be use to create numerals that fit in a machine integer. It is slightly faster than MakeNumeral since it is not necessary to parse a string. Value of the numeral Sort of the numeral A Term with value and type Create a real from a fraction. numerator of rational. denominator of rational. A Term with value / and sort Real Create a real numeral. A string representing the Term value in decimal notation. A Term with value and sort Real Create a real numeral. value of the numeral. A Term with value and sort Real Create a real numeral. value of the numeral. A Term with value and sort Real Create a real numeral. value of the numeral. A Term with value and sort Real Create a real numeral. value of the numeral. A Term with value and sort Real Create an integer numeral. A string representing the Term value in decimal notation. Create an integer numeral. value of the numeral. A Term with value and sort Integer Create an integer numeral. value of the numeral. A Term with value and sort Integer Create an integer numeral. value of the numeral. A Term with value and sort Integer Create an integer numeral. value of the numeral. A Term with value and sort Integer Create a bit-vector numeral. A string representing the value in decimal notation. the size of the bit-vector Create a bit-vector numeral. value of the numeral. the size of the bit-vector Create a bit-vector numeral. value of the numeral. the size of the bit-vector Create a bit-vector numeral. value of the numeral. /// the size of the bit-vector Create a bit-vector numeral. value of the numeral. the size of the bit-vector Create a universal Quantifier. Creates a forall formula, where is the weight, is an array of patterns, is an array with the sorts of the bound variables, is an array with the 'names' of the bound variables, and is the body of the quantifier. Quantifiers are associated with weights indicating the importance of using the quantifier during instantiation. the sorts of the bound variables. names of the bound variables the body of the quantifier. quantifiers are associated with weights indicating the importance of using the quantifier during instantiation. By default, pass the weight 0. array containing the patterns created using MkPattern. array containing the anti-patterns created using MkPattern. optional symbol to track quantifier. optional symbol to track skolem constants. Create a universal Quantifier. Create an existential Quantifier. Create an existential Quantifier. Create a Quantifier. Create a Quantifier. Convert a benchmark into an SMT-LIB formatted string. Name of the benchmark. The argument is optional. The benchmark logic. The status string (sat, unsat, or unknown) Other attributes, such as source, difficulty or category. Auxiliary assumptions. Formula to be checked for consistency in conjunction with assumptions. A string representation of the benchmark. Parse the given string using the SMT-LIB parser. The symbol table of the parser can be initialized using the given sorts and declarations. The symbols in the arrays and don't need to match the names of the sorts and declarations in the arrays and . This is a useful feature since we can use arbitrary names to reference sorts and declarations. Parse the given file using the SMT-LIB parser. Parse the given string using the SMT-LIB2 parser. A conjunction of assertions in the scope (up to push/pop) at the end of the string. Parse the given file using the SMT-LIB2 parser. Parse the given string using the Z3 native parser. A conjunction of asserts made in . Parse the given file using the Z3 native parser. A conjunction of asserts made in the file. Creates a new Goal. Note that the Context must have been created with proof generation support if is set to true here. Indicates whether model generation should be enabled. Indicates whether unsat core generation should be enabled. Indicates whether proof generation should be enabled. Creates a new ParameterSet. Returns a string containing a description of the tactic with the given name. Creates a new Tactic. Create a tactic that applies to a Goal and then to every subgoal produced by . Create a tactic that applies to a Goal and then to every subgoal produced by . Shorthand for AndThen. Create a tactic that first applies to a Goal and if it fails then returns the result of applied to the Goal. Create a tactic that applies to a goal for milliseconds. If does not terminate within milliseconds, then it fails. Create a tactic that applies to a given goal if the probe evaluates to true. If evaluates to false, then the new tactic behaves like the skip tactic. Create a tactic that applies to a given goal if the probe evaluates to true and otherwise. Create a tactic that keeps applying until the goal is not modified anymore or the maximum number of iterations is reached. Create a tactic that just returns the given goal. Create a tactic always fails. Create a tactic that fails if the probe evaluates to false. Create a tactic that fails if the goal is not triviall satisfiable (i.e., empty) or trivially unsatisfiable (i.e., contains `false'). Create a tactic that applies using the given set of parameters . Create a tactic that applies using the given set of parameters . Alias for UsingParams Create a tactic that applies the given tactics in parallel. Create a tactic that applies to a given goal and then to every subgoal produced by . The subgoals are processed in parallel. Interrupt the execution of a Z3 procedure. This procedure can be used to interrupt: solvers, simplifiers and tactics. Returns a string containing a description of the probe with the given name. Creates a new Probe. Create a probe that always evaluates to . Create a probe that evaluates to "true" when the value returned by is less than the value returned by Create a probe that evaluates to "true" when the value returned by is greater than the value returned by Create a probe that evaluates to "true" when the value returned by is less than or equal the value returned by Create a probe that evaluates to "true" when the value returned by is greater than or equal the value returned by Create a probe that evaluates to "true" when the value returned by is equal to the value returned by Create a probe that evaluates to "true" when the value and evaluate to "true". Create a probe that evaluates to "true" when the value or evaluate to "true". Create a probe that evaluates to "true" when the value does not evaluate to "true". Creates a new (incremental) solver. This solver also uses a set of builtin tactics for handling the first check-sat command, and check-sat commands that take more than a given number of milliseconds to be solved. Creates a new (incremental) solver. Creates a new (incremental) solver. Creates a solver that is implemented using the given tactic. The solver supports the commands Push and Pop, but it will always solve each check from scratch. Create a Fixedpoint context. Return a string describing all available parameters to Expr.Simplify. Enable/disable printing of warning messages to the console. Note that this function is static and effects the behaviour of all contexts globally. Update a mutable configuration parameter. The list of all configuration parameters can be obtained using the Z3 executable: z3.exe -ini? Only a few configuration parameters are mutable once the context is created. An exception is thrown when trying to modify an immutable parameter. Get a configuration parameter. Returns null if the parameter value does not exist. Finalizer. Disposes of the context. Retrieves the Boolean sort of the context. Retrieves the Integer sort of the context. Retrieves the Real sort of the context. Selects the format used for pretty-printing expressions. The default mode for pretty printing expressions is to produce SMT-LIB style output where common subexpressions are printed at each occurrence. The mode is called Z3_PRINT_SMTLIB_FULL. To print shared common subexpressions only once, use the Z3_PRINT_LOW_LEVEL mode. To print in way that conforms to SMT-LIB standards and uses let expressions to share common sub-expressions use Z3_PRINT_SMTLIB_COMPLIANT. The number of SMTLIB formulas parsed by the last call to ParseSMTLIBString or ParseSMTLIBFile. The formulas parsed by the last call to ParseSMTLIBString or ParseSMTLIBFile. The number of SMTLIB assumptions parsed by the last call to ParseSMTLIBString or ParseSMTLIBFile. The assumptions parsed by the last call to ParseSMTLIBString or ParseSMTLIBFile. The number of SMTLIB declarations parsed by the last call to ParseSMTLIBString or ParseSMTLIBFile. The declarations parsed by the last call to ParseSMTLIBString or ParseSMTLIBFile. The number of SMTLIB sorts parsed by the last call to ParseSMTLIBString or ParseSMTLIBFile. The declarations parsed by the last call to ParseSMTLIBString or ParseSMTLIBFile. The number of supported tactics. The names of all supported tactics. The number of supported Probes. The names of all supported Probes. Probes are used to inspect a goal (aka problem) and collect information that may be used to decide which solver and/or preprocessing step will be used. The complete list of probes may be obtained using the procedures Context.NumProbes and Context.ProbeNames. It may also be obtained using the command (help-tactics) in the SMT 2.0 front-end. Execute the probe over the goal. A probe always produce a double value. "Boolean" probes return 0.0 for false, and a value different from 0.0 for true. Apply the probe to a goal. Solvers. Creates a backtracking point. Backtracks backtracking points. Note that an exception is thrown if is not smaller than NumScopes Resets the Solver. This removes all assertions from the solver. Assert a constraint (or multiple) into the solver. Checks whether the assertions in the solver are consistent or not. A string representation of the solver. A string that describes all available solver parameters. Sets the solver parameters. The current number of backtracking points (scopes). The number of assertions in the solver. The set of asserted formulas. The model of the last Check. The result is null if Check was not invoked before, if its results was not SATISFIABLE, or if model production is not enabled. The proof of the last Check. The result is null if Check was not invoked before, if its results was not UNSATISFIABLE, or if proof production is disabled. The unsat core of the last Check. The unsat core is a subset of Assertions The result is empty if Check was not invoked before, if its results was not UNSATISFIABLE, or if core production is disabled. A brief justification of why the last call to Check returned UNKNOWN. Solver statistics. Tactics are the basic building block for creating custom solvers for specific problem domains. The complete list of tactics may be obtained using Context.NumTactics and Context.TacticNames. It may also be obtained using the command (help-tactics) in the SMT 2.0 front-end. Execute the tactic over the goal. A string containing a description of parameters accepted by the tactic. Apply the tactic to a goal. Creates a solver that is implemented using the given tactic. Interaction logging for Z3. Note that this is a global, static log and if multiple Context objects are created, it logs the interaction with all of them. Open an interaction log file. the name of the file to open True if opening the log file succeeds, false otherwise. Closes the interaction log. Appends the user-provided string to the interaction log. Checks whether the interaction log is opened. True if the interaction log is open, false otherwise. Quantifier expressions. Indicates whether the quantifier is universal. Indicates whether the quantifier is existential. The weight of the quantifier. The number of patterns. The patterns. The number of no-patterns. The no-patterns. The number of bound variables. The symbols for the bound variables. The sorts of the bound variables. The body of the quantifier. The Sort class implements type information for ASTs. Comparison operator. A Sort A Sort True if and are from the same context and represent the same sort; false otherwise. Comparison operator. A Sort A Sort True if and are not from the same context or represent different sorts; false otherwise. Equality operator for objects of type Sort. Hash code generation for Sorts A hash code A string representation of the sort. Sort constructor Returns a unique identifier for the sort. The kind of the sort. The name of the sort A Boolean sort. An arithmetic sort, i.e., Int or Real. An Integer sort A real sort Bit-vector sorts. The size of the bit-vector sort. Array sorts. The domain of the array sort. The range of the array sort. Datatype sorts. The number of constructors of the datatype sort. The constructors. The recognizers. The constructor accessors. Uninterpreted Sorts Tuple sorts. The constructor function of the tuple. The number of fields in the tuple. The field declarations. Enumeration sorts. The function declarations of the constants in the enumeration. The constants in the enumeration. The test predicates for the constants in the enumeration. List sorts. The declaration of the nil function of this list sort. The empty list. The declaration of the isNil function of this list sort. The declaration of the cons function of this list sort. The declaration of the isCons function of this list sort. The declaration of the head function of this list sort. The declaration of the tail function of this list sort. Relation sorts. The arity of the relation sort. The sorts of the columns of the relation sort. Finite domain sorts. The size of the finite domain sort. Set sorts. Symbols are used to name several term and type constructors. Indicates whether the symbol is of Int kind Indicates whether the symbol is of string kind. A string representation of the symbol. Symbol constructor The kind of the symbol (int or string) Numbered symbols The int value of the symbol. Throws an exception if the symbol is not of int kind. Named symbols The string value of the symbol. Throws an exception if the symbol is not of string kind. Version information. Note that this class is static. A string representation of the version information. The major version The minor version The build version The revision ================================================ FILE: ironclad-apps/tools/Dafny/PrepareBoogieZip.bat ================================================ @echo off setlocal set DEST_DIR=export if exist %DEST_DIR% del /q %DEST_DIR%\* if not exist %DEST_DIR% mkdir %DEST_DIR% for %%f in ( AbsInt.dll AbsInt.pdb Basetypes.dll Basetypes.pdb Boogie.exe Boogie.pdb BVD.exe BVD.pdb CodeContractsExtender.dll CodeContractsExtender.pdb Core.dll Core.pdb Doomed.dll Doomed.pdb Graph.dll Graph.pdb Houdini.dll Houdini.pdb Model.dll Model.pdb ParserHelper.dll ParserHelper.pdb Predication.dll Predication.pdb Provers.SMTLib.dll Provers.SMTLib.pdb UnivBackPred2.smt UnivBackPred2.smt2 VCExpr.dll VCExpr.pdb VCGeneration.dll VCGeneration.pdb ) do ( copy %%f %DEST_DIR% ) xcopy /E /I /Y CodeContracts "%DEST_DIR%/CodeContracts" echo Done. Now, manually put the contents of the %DEST_DIR% directory into Boogie.zip ================================================ FILE: ironclad-apps/tools/Dafny/PrepareDafnyZip.bat ================================================ @echo off setlocal set DEST_DIR=export if exist %DEST_DIR% del /q %DEST_DIR%\* if not exist %DEST_DIR% mkdir %DEST_DIR% for %%f in ( AbsInt.dll AbsInt.pdb Basetypes.dll Basetypes.pdb CodeContractsExtender.dll CodeContractsExtender.pdb Concurrency.dll Concurrency.pdb Core.dll Core.pdb Dafny.exe Dafny.pdb DafnyPipeline.dll DafnyPipeline.pdb DafnyPrelude.bpl DafnyRuntime.cs Doomed.dll Doomed.pdb ExecutionEngine.dll ExecutionEngine.pdb Graph.dll Graph.pdb Houdini.dll Houdini.pdb Model.dll Model.pdb ModelViewer.dll ModelViewer.pdb ParserHelper.dll ParserHelper.pdb Provers.SMTLib.dll Provers.SMTLib.pdb VCExpr.dll VCExpr.pdb VCGeneration.dll VCGeneration.pdb DafnyLanguageService.vsix ) do ( copy %%f %DEST_DIR% ) xcopy /E /I /Y CodeContracts "%DEST_DIR%\CodeContracts" for %%d in ( Util Util\emacs Util\vim Util\latex ) do ( if not exist %DEST_DIR%\%%d mkdir %DEST_DIR%\%%d ) for %%f in ( Util\emacs\dafny-mode.el Util\vim\dafny.vim Util\latex\dafny.sty ) do ( copy ..\%%f %DEST_DIR%\%%f ) echo Done. Now, manually put the contents of the %DEST_DIR% directory into Dafny.zip ================================================ FILE: ironclad-apps/tools/Dafny/README ================================================ When upgrading to a new version of Boogie, it's important to increase the stack size it uses, since some of Boogie's internals use way too much for some of our DafnyCC-generated files. You can accomplish this using a Visual Studio Command Prompt and the command: editbin /stack:268435456 Boogie.exe which gives it a 256 MB stack. ================================================ FILE: ironclad-apps/tools/Dafny/extension.vsixmanifest ================================================ DafnyMenu This is a menu for interacting with Dafny. ================================================ FILE: ironclad-apps/tools/Dafny/libiz3.lib ================================================ [File too large to display: 16.4 MB] ================================================ FILE: ironclad-apps/tools/DafnyCC/.gitignore ================================================ *.suo ================================================ FILE: ironclad-apps/tools/DafnyCC/Analyze.cs ================================================ using System; using System.Linq; using System.Collections.Generic; using System.Collections.ObjectModel; using Microsoft.Dafny; using Bpl = Microsoft.Boogie; using System.Numerics; public class Set { private bool full; private Dictionary map = new Dictionary(); public Set(bool full = false) { this.full = full; } public Set(Set s) { this.full = s.full; this.map = new Dictionary(s.map); } public Set(IEnumerable elems) { this.full = false; this.map = elems.ToDictionary(a => a); } public bool Contains(A a) { return full || map.ContainsKey(a); } public void Add(A a) { if (!full) map[a] = a; } public bool IntersectFrom(Set s) { if (s.full) { return false; } else if (full) { full = false; map = new Dictionary(s.map); return true; } else { List toRemove = map.Keys.Where(a => !s.Contains(a)).ToList(); toRemove.ForEach(a => map.Remove(a)); return toRemove.Count > 0; } } public override bool Equals(object o) { Set s = o as Set; return s != null && full == s.full && map.Count == s.map.Count && map.Keys.ToList().TrueForAll(s.map.ContainsKey); } public override string ToString() { return full ? "*" : String.Join(" ", map.Keys); } public override int GetHashCode() { return map.GetHashCode(); } } public abstract class Analyze { protected List inVars; protected List outVars; protected List stmts; protected Dictionary labels = new Dictionary(); protected List> preds = new List>(); protected List> succs = new List>(); protected List> liveVars = new List>(); //- set of live vars before each stmt; also record distance to next use protected List> defVars = new List>(); //- set of definitely-defined vars after each stmt public Analyze(List inVars, List outVars, List stmts) { this.inVars = inVars; this.outVars = outVars; this.stmts = stmts; ComputeControl(); ComputeLiveVars(); ComputeDefVars(); } void ComputeControl() { for (int i = 0; i < stmts.Count; i++) { RtlLabel label = stmts[i] as RtlLabel; if (label != null) { labels.Add(label.label, i); } } stmts.ForEach(_ => preds.Add(new List())); for (int i = 0; i < stmts.Count; i++) { RtlJump jump = stmts[i] as RtlJump; RtlReturn ret = stmts[i] as RtlReturn; List succs_i = new List(); succs.Add(succs_i); if (jump != null) { int target = labels[jump.label]; succs[i].Add(target); preds[target].Add(i); } if (ret == null && i + 1 < stmts.Count && (jump == null || jump.cond != null)) { succs[i].Add(i + 1); preds[i + 1].Add(i); } } } void Dataflow(bool forward, bool addAll, Action init, Func work) { bool[] workSet = new bool[stmts.Count]; Stack workList = new Stack(); for (int i = 0; i < stmts.Count; i++) { if (i == 0 || addAll) { workSet[i] = true; workList.Push((forward && addAll) ? (stmts.Count - i - 1) : i); } init(i); } while (workList.Count != 0) { int i = workList.Pop(); workSet[i] = false; bool changed = work(i, stmts[i]); if (changed) { foreach (int p in (forward ? succs : preds)[i]) { if (!workSet[p]) { workSet[p] = true; workList.Push(p); } } } } } void ComputeLiveVars() { Func work = (i, stmt) => { bool changed = false; List uses = stmt.Uses(); List defs = stmt.Defs(); Dictionary live = liveVars[i]; Action addLiveVar = (x, dist) => { bool contains = live.ContainsKey(x); if (!contains || (contains && dist < live[x])) { changed = true; live[x] = dist; } }; uses.ForEach(x => addLiveVar(x, 0)); if (stmt is RtlReturn) { foreach (string x in outVars) { if (!defs.Contains(x)) { addLiveVar(x, 1); } } } foreach (int s in succs[i]) { foreach (var keyVal in liveVars[s]) { string x = keyVal.Key; if (!defs.Contains(x)) { addLiveVar(x, keyVal.Value + 1); } } } return changed; }; Dataflow(false, true, i => { liveVars.Add(new Dictionary()); }, work); } void ComputeDefVars() { Func work = (i, stmt) => { List defs = stmt.Defs(); Set def = new Set(i == 0 ? new Set(inVars) : defVars[i]); List ps = preds[i]; preds[i].ForEach(p => def.IntersectFrom(defVars[p])); defs.ForEach(x => def.Add(x)); bool changed = !def.Equals(defVars[i]); defVars[i] = def; return changed; }; //- null set represents all variables Dataflow(true, false, i => { defVars.Add(new Set(true)); }, work); } } public class Optimize: Analyze { bool[] liveStmts; public Optimize(List inVars, List outVars, List stmts): base(inVars, outVars, stmts) { ComputeLiveStmts(); } void ComputeLiveStmts() { liveStmts = new bool[stmts.Count]; Stack workList = new Stack(); liveStmts[0] = true; workList.Push(0); while (workList.Count != 0) { int i = workList.Pop(); foreach (int s in succs[i]) { if (!liveStmts[s]) { liveStmts[s] = true; workList.Push(s); } } } } public List Run() { //- eliminate dead code return stmts.Where((_, i) => liveStmts[i]).ToList(); } } ================================================ FILE: ironclad-apps/tools/DafnyCC/CompileMethod.cs ================================================ using System; using System.IO; using System.Linq; using System.Collections.Generic; using System.Collections.ObjectModel; using Microsoft.Dafny; using Bpl = Microsoft.Boogie; using Type = Microsoft.Dafny.Type; using System.Numerics; public class CompileMethod: CompileMethodGhost { public readonly DafnyCC dafnycc; Dictionary jumpOps = new Dictionary(); Dictionary jumpOpsNot = new Dictionary(); RegAlloc alloc; List whileEnd = new List(); List instructionProcArgs = null; public int IPSize; public CompileMethod(DafnySpec dafnySpec, Method method, TypeApply typeApply, TextWriter writer, TextWriter iwriter, string moduleName, List imports): base(dafnySpec, method, typeApply, writer, iwriter, moduleName, imports) { dafnycc = (DafnyCC)dafnySpec; IPSize = dafnycc.IPSize; jumpOps.Add("Eq", "=="); jumpOps.Add("Neq", "!="); jumpOps.Add("Lt", "<"); jumpOps.Add("Gt", ">"); jumpOps.Add("Le", "<="); jumpOps.Add("Ge", ">="); jumpOpsNot.Add("Eq", "!="); jumpOpsNot.Add("Neq", "=="); jumpOpsNot.Add("Lt", ">="); jumpOpsNot.Add("Gt", "<="); jumpOpsNot.Add("Le", ">"); jumpOpsNot.Add("Ge", "<"); } public static string ProcName(bool isGhost, string x) { return DafnyCC.ProcName(isGhost, x); } string NewLabel() { return "L" + (tempCount++); } public RtlVar AsVarOrTemp(Expression exp) { RtlVar var = AsVar(exp); if (var == null) { var = TempVar(exp.Type); AddExpression(var, exp); } return var; } BigInteger? AsInt(Expression exp) { exp = GetExp(exp); LiteralExpr literal = exp as LiteralExpr; BinaryExpr binary = exp as BinaryExpr; if (literal != null) { if (literal.Value == null) { throw new Exception("unexpected null literal"); } else if (literal.Value is bool) { return new BigInteger(((bool)(literal.Value)) ? 1 : 0); } else { return (BigInteger)(literal.Value); } } else if (binary != null) { BigInteger? i1 = AsInt(binary.E0); BigInteger? i2 = AsInt(binary.E1); if (i1 != null && i2 != null) { switch (binary.Op) { case BinaryExpr.Opcode.Add: return i1 + i2; case BinaryExpr.Opcode.Sub: return i1 - i2; case BinaryExpr.Opcode.Mul: return i1 * i2; } } return null; } else { return null; } } RtlExp AsSimple(Expression exp) { exp = GetExp(exp); RtlVar var = AsVar(exp); BigInteger? i = AsInt(exp); if (var != null) { return var; } else if (i != null) { return new RtlInt((BigInteger)i); } else { return null; } } RtlExp AsSimpleOrTemp(Expression exp) { RtlExp re = AsSimple(exp); if (re == null) { RtlVar var = TempVar(exp.Type); AddExpression(var, exp); re = var; } return re; } //- group stmts[startIndex..stmts.Count-1] into single statement public void GroupStatements(int startIndex) { List group = new List(); while (stmts.Count > startIndex) { group.Add(stmts[startIndex]); stmts.RemoveAt(startIndex); } stmts.Add(new RtlStmtGroup(group)); } void Move(RtlVar dest, RtlExp src, bool isPtr) { RtlVar src_var = src as RtlVar; string comment = "move:: " + dest + " := " + src + " // isPtr = " + isPtr; if (!dest.isGhost) { if (src is RtlMem) { throw new Exception("internal error: Move RtlMem"); } string ins = "instr_Mov"; stmts.Add(new RtlInst(ins, new RtlVar[] { dest }, new RtlVar[0], new RtlExp[] { src }, false) .WithComment(comment)); } if (dest.isGhost || isPtr) { stmts.Add(new RtlInst(null, new RtlVar[] { dest }, new RtlVar[0], new RtlExp[] { src }, true) .WithComment(comment)); } if (isPtr && src_var != null) { RtlVar dest_abs = new RtlVar(dest.x + "__abs", dest.isGhost, dest.type); RtlVar src_abs = new RtlVar(src_var.x + "__abs", src_var.isGhost, src_var.type); stmts.Add(new RtlInst(null, new RtlVar[] { dest_abs }, new RtlVar[0], new RtlExp[] { src_abs }, true) .WithComment(comment)); } } void Label(string label, bool loop = false) { stmts.Add(new RtlLabel(label, loop).WithComment("label:: " + label + " // isLoop = " + loop)); } void JumpIfHasType(string label, RtlVar e0, string constructor, Type targetType, bool jumpIf) { int start = stmts.Count; string targetTag = "Tag_" + TypeString(AppType(targetType)) + "_" + constructor; RtlVar objTag = TempVar(Type.Int); stmts.Add(new RtlStmtComputed( s => "call r, mems := loadTag_" + TypeString(AppType(targetType)) + "(r, core_state, stk, statics, io, mems, $commonVars, " + "$gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, " + s.args[0] + ", " + new RtlMem(s.args[1].e, "4").AsOperand() + ", " + e0 + ", " + e0 + "__abs, " + RegAlloc.Reg(s.args[1].ToString()) + ");", new List { new RtlArg(false, true, objTag), new RtlArg(true, false, e0) }, false) .WithComment("datatype_isConstructor:: " + targetTag)); GroupStatements(start); Jump(label, new RtlBinary( (jumpIf ? "==" : "!="), objTag, new RtlLiteral("OConst(" + targetTag + ")"))); } void Jump(string label, RtlBinary e = null) { if (e != null) { RtlInt ri0 = e.e0 as RtlInt; RtlInt ri1 = e.e1 as RtlInt; if (ri0 != null && ri1 != null) { //- would be illegal x86 instruction, so optimize away var i0 = ri0.i; var i1 = ri1.i; bool b; switch (e.op) { case "==": b = i0 == i1; break; case "!=": b = i0 != i1; break; case "<": b = i0 < i1; break; case "<=": b = i0 <= i1; break; case ">": b = i0 > i1; break; case ">=": b = i0 >= i1; break; default: throw new Exception("not implemented: " + e.op); } if (!b) { return; //- branch not taken } e = null; //- branch taken } else if (ri0 != null) { //- would be illegal x86 instruction, so swap operands string op; switch (e.op) { case "==": op = "=="; break; case "!=": op = "!="; break; case "<": op = ">"; break; case "<=": op = ">="; break; case ">": op = "<"; break; case ">=": op = "<="; break; default: throw new Exception("not implemented: " + e.op); } e = new RtlBinary(op, e.e1, e.e0); } } stmts.Add(new RtlJump(label, e).WithComment("jump_to_label:: " + label + " condition = " + e)); } void Jump(string label, Expression exp, bool jumpIf = true) { exp = GetExp(exp); RtlExp e = AsSimple(exp); BinaryExpr binary = exp as BinaryExpr; UnaryExpr unary = exp as UnaryExpr; MemberSelectExpr memberSelect = exp as MemberSelectExpr; if (e != null) { Jump(label, new RtlBinary(jumpIf ? "!=" : "==", e, new RtlInt(0))); } else if (binary != null && jumpOps.ContainsKey(binary.Op.ToString())) { Type t = AppType(binary.E0.Type); UserDefinedType ut = t as UserDefinedType; if (!t.Equals(AppType(binary.E1.Type))) { throw new Exception("not supported: comparison of values with different types"); } else if (t is SeqType && (binary.Op == BinaryExpr.Opcode.Eq || binary.Op == BinaryExpr.Opcode.Neq)) { var tmp = TempVar(Type.Bool); var m = dafnySpec.GetSeqMethod(AppType(t), "seq_Equal"); AddCall(new List { tmp }, false, true, m.Item1, new List { null, null }, new List { binary.E0, binary.E1 }, m.Item1.Outs, m.Item2); jumpIf = (jumpIf == (binary.Op == BinaryExpr.Opcode.Eq)); Jump(label, new RtlBinary(jumpIf ? "!=" : "==", tmp, new RtlInt(0))); } else if (t is IntType || t is BoolType || (ut != null && ut.Name == "array")) { RtlExp e0 = AsSimpleOrTemp(binary.E0); RtlExp e1 = AsSimpleOrTemp(binary.E1); Jump(label, new RtlBinary( (jumpIf ? jumpOps : jumpOpsNot)[binary.Op.ToString()], e0, e1)); } else { throw new Exception("not supported: comparison of values of type " + t); } } else if (binary != null && binary.Op == BinaryExpr.Opcode.Iff && jumpIf) { Jump(label, DafnySpec.MakeBinaryExpr(BinaryExpr.Opcode.Or, BinaryExpr.ResolvedOpcode.Or, Type.Bool, DafnySpec.MakeBinaryExpr(BinaryExpr.Opcode.And, BinaryExpr.ResolvedOpcode.And, Type.Bool, binary.E0, binary.E1), DafnySpec.MakeBinaryExpr(BinaryExpr.Opcode.And, BinaryExpr.ResolvedOpcode.And, Type.Bool, new UnaryOpExpr(binary.tok, UnaryOpExpr.Opcode.Not, binary.E0), new UnaryOpExpr(binary.tok, UnaryOpExpr.Opcode.Not, binary.E1))), jumpIf); } else if (binary != null && binary.Op == BinaryExpr.Opcode.Imp) { Jump(label, DafnySpec.MakeBinaryExpr(BinaryExpr.Opcode.Or, BinaryExpr.ResolvedOpcode.Or, Type.Bool, new UnaryOpExpr(binary.tok, UnaryOpExpr.Opcode.Not, binary.E0), binary.E1), jumpIf); } else if (binary != null && ( (binary.Op == BinaryExpr.Opcode.Or && jumpIf) || (binary.Op == BinaryExpr.Opcode.And && !jumpIf))) { Jump(label, binary.E0, jumpIf); Jump(label, binary.E1, jumpIf); } else if (binary != null && ( (binary.Op == BinaryExpr.Opcode.Or && !jumpIf) || (binary.Op == BinaryExpr.Opcode.And && jumpIf))) { string skip = NewLabel(); Jump(skip, binary.E0, !jumpIf); Jump(label, binary.E1, jumpIf); Label(skip); } else if (unary != null && unary is UnaryOpExpr && ((UnaryOpExpr)unary).Op == UnaryOpExpr.Opcode.Not) { Jump(label, unary.E, !jumpIf); } else if (memberSelect != null && memberSelect.Member is Field && memberSelect.MemberName.EndsWith("?")) { string constructor = memberSelect.MemberName.Substring(0, memberSelect.MemberName.Length - 1); RtlVar e0 = AsVarOrTemp(memberSelect.Obj); JumpIfHasType(label, e0, constructor, memberSelect.Obj.Type, jumpIf); } else { RtlVar tmp = TempVar(exp.Type); AddExpression(tmp, exp); Jump(label, new RtlBinary(jumpIf ? "!=" : "==", tmp, new RtlInt(0))); } } void ArrayLength(RtlVar dest, RtlExp eArr) { string abs = eArr + "__abs"; int start = stmts.Count; stmts.Add(new RtlStmtComputed( s => "call r, mems := loadArrayElement(r, core_state, stk, statics, io, mems, $commonVars, " + "$gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, " + s.args[0] + ", " + new RtlMem(s.args[1].e, new RtlInt(4)).AsOperand() + ", " + "(0 - 1), " + abs + ", " + RegAlloc.Reg(s.args[1].ToString()) + ");", new List { new RtlArg(false, true, dest), new RtlArg(true, false, eArr) }, false) .WithComment("loadArrayElement")); GroupStatements(start); } string BinaryInstOp(BinaryExpr.Opcode op) { string wrapped_op = "instr_" + op.ToString(); switch (op) { case BinaryExpr.Opcode.Add: case BinaryExpr.Opcode.Sub: case BinaryExpr.Opcode.Mul: return wrapped_op + "Checked"; default: return wrapped_op; } } void AddBoolViaJump(RtlVar dest, Expression exp) { //- dest = 0 //- if (e1 == e2) goto skip //- dest = 1 //- skip: Move(dest, new RtlInt(0), false); string skip = NewLabel(); Jump(skip, exp, false); Move(dest, new RtlInt(1), false); Label(skip); } void AddBinary(RtlVar dest, string op, Expression exp0, Expression exp1, List pinRegs = null, string envIn = null, string envOut = null) { exp0 = GetExp(exp0); exp1 = GetExp(exp1); RtlVar x0 = AsVar(exp0); RtlVar x1 = AsVar(exp1); RtlExp e1 = AsSimple(exp1); if (x0 == null) { RtlVar tmp = TempVar(exp0.Type); AddExpression(tmp, exp0); x0 = tmp; } else if (x0.getName() != dest.getName()) { if ((x1 != null && x1.getName() != dest.getName()) || (x1 == null && e1 != null)) { //- a := b - c; //- ==> //- a := b; //- a := a - c; Move(dest, x0, false); x0 = dest; } else { //- a := b - a; //- ==> //- tmp := b; //- tmp := tmp - a; //- a := tmp; RtlVar tmp = TempVar(exp0.Type); Move(tmp, x0, false); x0 = tmp; } } if (e1 == null) { RtlVar tmp = TempVar(exp1.Type); AddExpression(tmp, exp1); e1 = tmp; } var inst = new RtlInst( op, new RtlVar[0], new RtlVar[] { x0 }, new RtlExp[] { e1 }, false, envIn, envOut); if (pinRegs != null) { for (int i = 0; i < 2; i++) { inst.args[i].pinReg = pinRegs[i]; } } stmts.Add(inst.WithComment("binary_assignment:: " + dest + " := " + op + "(" + x0 + ", " + x1 + ")")); if (x0.getName() != dest.getName()) { Move(dest, x0, false); } } SeqTree AddBuildSequenceRec(Expression exp, List> flatExps) { BinaryExpr binary = exp as BinaryExpr; SeqDisplayExpr seqDisplay = exp as SeqDisplayExpr; if (seqDisplay != null) { foreach (Expression ei in seqDisplay.Elements) { flatExps.Add(Tuple.Create(false, ei)); } return new SeqTree(null, null, seqDisplay.Elements.Count); } else if (binary != null && binary.ResolvedOp == BinaryExpr.ResolvedOpcode.Concat) { var s0 = AddBuildSequenceRec(binary.E0, flatExps); var s1 = AddBuildSequenceRec(binary.E1, flatExps); return new SeqTree(s0, s1, -1); } else { //- leaf of the append tree (assumed to be a sequence) flatExps.Add(Tuple.Create(true, exp)); return null; } } void AddBuildSequence(RtlVar dest, Expression exp) { List> flatExps = new List>(); var tree = AddBuildSequenceRec(exp, flatExps); var m = dafnycc.GetSeqBuildMethod(AppType(exp.Type), tree, flatExps.ConvertAll(x => x.Item1)); AddCall(new List { dest }, false, true, m.Item1, flatExps.ConvertAll(x => x.Item2), m.Item1.Outs, m.Item2); } void AddFieldSelect(RtlVar dest, RtlVar obj, Type objType, string fieldName, Type fieldType, RtlExp expGhost) { string typeAndField = TypeString(AppType(objType)) + "_" + fieldName; string abs = obj + "__abs"; string offset = "Offset_" + typeAndField; int start = stmts.Count; stmts.Add(new RtlStmtComputed( s => "call r, mems := loadField_" + typeAndField + "(r, core_state, stk, statics, io, mems, $commonVars, " + "$gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, " + s.args[0] + ", " + new RtlMem(s.args[1].e, offset).AsOperand() + ", " + obj + ", " + abs + ", " + RegAlloc.Reg(s.args[1].ToString()) + ");", new List { new RtlArg(false, true, dest), new RtlArg(true, false, obj) }, false) .WithComment("datatype_loadField:: " + fieldName)); GroupStatements(start); if (IsPtrType(AppType(fieldType))) { RtlVar dest_abs = new RtlVar(dest + "__abs", dest.isGhost, dest.type); RtlExp src_abs = new RtlLiteral("$absMem[" + abs + "][" + offset + " div 4 + 1]"); stmts.Add(new RtlInst(null, new RtlVar[] { dest }, new RtlVar[0], new RtlExp[] { expGhost }, true)); stmts.Add(new RtlInst(null, new RtlVar[] { dest_abs }, new RtlVar[0], new RtlExp[] { src_abs }, true)); } } public void AddMatch(RtlVar dest, Expression src, List cases, Func bodyExp, Func> bodyStmts) where Case:MatchCase { //- match src { case c1(ps1) => s1 ... cn(psn) => sn } //- --> //- var x := src; //- if x is c1 { var ps1 := ...x.f1...; s1 } else //- if x is c2 { var ps2 := ...x.f2...; s2 } else //- { var ps3 := ...x.f3...; s3 } string end = NewLabel(); RtlVar x = TempVar(src.Type); AddExpression(x, src); for (int k = 0; k < cases.Count; k++) { Case c = cases[k]; bool isLast = (k == cases.Count - 1); string skip = NewLabel(); if (!isLast) { JumpIfHasType(skip, x, c.Ctor.Name, src.Type, false); } var oldRenamer = PushRename(); for (int i = 0; i < c.Arguments.Count; i++) { var a = c.Arguments[i]; var f = c.Ctor.Formals[i]; AddVarDecl(a.Name, a.Type, a.IsGhost); RtlExp ghostExp = new RtlLiteral("(" + f.Name + "#" + c.Ctor.Name + "(" + x + "))"); if (a.IsGhost) { MoveGhost(AsVar(a), ghostExp); } else { AddFieldSelect(AsVar(a), x, src.Type, f.Name, f.Type, ghostExp); } } if (bodyExp != null) { AddExpression(dest, bodyExp(c)); } if (bodyStmts != null) { bodyStmts(c).ForEach(AddStatement); } if (!isLast) { Jump(end); Label(skip); } PopRename(oldRenamer); } Label(end); } void AddExpression(RtlVar dest, Expression exp) { Util.Assert(!isPrinting); Util.Assert(!dest.isGhost); exp = GetExp(exp); Util.DebugWriteLine("exp: " + exp.GetType()); StmtExpr stmtExpr = exp as StmtExpr; RtlVar var = AsVar(exp); BigInteger? intExp = AsInt(exp); BinaryExpr binary = exp as BinaryExpr; UnaryExpr unary = exp as UnaryExpr; ITEExpr ite = exp as ITEExpr; LetExpr letExp = exp as LetExpr; MatchExpr matchExp = exp as MatchExpr; FunctionCallExpr funCall = exp as FunctionCallExpr; DatatypeValue dataVal = exp as DatatypeValue; MemberSelectExpr memberSelect = exp as MemberSelectExpr; SeqSelectExpr seqSelect = exp as SeqSelectExpr; SeqUpdateExpr seqUpdate = exp as SeqUpdateExpr; SeqDisplayExpr seqDisplay = exp as SeqDisplayExpr; if (stmtExpr != null) { if (stmtExprEnabled) { if (ignoreStmtExpr == 0) { AddGhostStatement(stmtExpr.S, null); } AddExpression(dest, stmtExpr.E); return; } else { throw new Exception("not implemented: cannot handle statement expression here"); } } if (var != null) { Util.DebugWriteLine("dest = " + dest + " var = " + var); Move(dest, var, IsPtrType(AppType(exp.Type))); } else if (intExp != null) { Move(dest, new RtlInt((BigInteger)intExp), false); } else if (binary != null) { switch (binary.ResolvedOp) { case BinaryExpr.ResolvedOpcode.Concat: { AddBuildSequence(dest, exp); return; } } if (IsPtrType(AppType(binary.E0.Type)) || IsPtrType(AppType(binary.E1.Type))) { throw new Exception("binary operators only implemented for integer and bool types"); } if (jumpOps.ContainsKey(binary.Op.ToString())) { AddBoolViaJump(dest, exp); } else { switch (binary.Op) { case BinaryExpr.Opcode.And: case BinaryExpr.Opcode.Or: case BinaryExpr.Opcode.Imp: case BinaryExpr.Opcode.Iff: AddBoolViaJump(dest, exp); break; case BinaryExpr.Opcode.Mul: case BinaryExpr.Opcode.Div: case BinaryExpr.Opcode.Mod: { bool nonlinear = !(IsConstant(binary.E0) || IsConstant(binary.E1)); bool isDivMod = (binary.Op == BinaryExpr.Opcode.Div || binary.Op == BinaryExpr.Opcode.Mod); string sop = isDivMod ? "DivMod" : binary.Op.ToString(); var m = dafnySpec.FindMethod((nonlinear ? "Method_" : "method_") + sop); //Expression zero = new LiteralExpr(binary.tok, 0); AddCallInstruction( (binary.Op == BinaryExpr.Opcode.Mod) ? new List { dest, TempVar(Type.Int) } : new List { TempVar(Type.Int), dest }, m.Ins, DafnySpec.SimpleSanitizedName(m), isDivMod ? new List { null, binary.E0, binary.E1 } : new List { binary.E0, binary.E1 }, m.Attributes, isDivMod ? new List { new RtlInt(0), null, null } : null); break; } default: AddBinary(dest, BinaryInstOp(binary.Op), binary.E0, binary.E1); break; } } } else if (unary != null && unary is UnaryOpExpr && ((UnaryOpExpr)unary).Op == UnaryOpExpr.Opcode.Not) { AddBoolViaJump(dest, exp); } else if (unary != null && unary is UnaryOpExpr && ((UnaryOpExpr)unary).Op == UnaryOpExpr.Opcode.Cardinality) { var m = dafnySpec.GetSeqMethod(AppType(unary.E.Type), "seq_Length"); AddCall(new List { dest }, false, false, m.Item1, new List { unary.E }, m.Item1.Outs, m.Item2); } else if (ite != null) { //- if (!e) goto skip1 //- then-body //- goto skip2 //- skip1: //- else-body //- skip2: string skip1 = NewLabel(); Jump(skip1, ite.Test, false); AddExpression(dest, ite.Thn); string skip2 = NewLabel(); Jump(skip2); Label(skip1); AddExpression(dest, ite.Els); Label(skip2); } else if (letExp != null) { if (!letExp.Exact) { throw new Exception("not implemented: LetExpr: " + letExp); } for (int i = 0; i < letExp.LHSs.Count; i++) { var lhs = letExp.LHSs[i]; var rhs = letExp.RHSs[i]; string name = GhostVar(lhs.Var.Name); if (allVars.Keys.Contains(name)) { AddRename(lhs.Var.Name); name = GhostVar(lhs.Var.Name); } RtlVar lhsVar = new RtlVar(name, lhs.Var.IsGhost, AppType(lhs.Var.Type)); allVars.Add(name, lhsVar); AddExpression(lhsVar, rhs); } AddExpression(dest, letExp.Body); } else if (matchExp != null) { if (matchExp.MissingCases.Count != 0) { throw new Exception("not implemented: MatchExpr with missing cases: " + matchExp); } AddMatch(dest, matchExp.Source, matchExp.Cases, c => c.Body, null); } else if (funCall != null) { if (Attributes.Contains(funCall.Function.Attributes, "dafnycc_inline")) { TypeApply app = dafnySpec.Compile_Function(funCall.Function, funCall.TypeArgumentSubstitutions.ToDictionary(p => p.Key, p => AppType(p.Value))); string funName = FunName(SimpleName(app.AppName())); Dictionary substMap = new Dictionary(); for (int i = 0; i < funCall.Function.Formals.Count; i++) { substMap.Add(funCall.Function.Formals[i], funCall.Args[i]); } Translator.Substituter subst = new Translator.Substituter(null, substMap, new Dictionary(), null); Expression body = subst.Substitute(funCall.Function.Body); AddExpression(dest, body); List rtlArgs = funCall.Args.ConvertAll(e => GhostExpression(e)); stmts.Add(new RtlAssert(new RtlBinary("==", dest, new RtlApply(funName, rtlArgs)))); return; } string name = SimpleName(funCall.Function.Name); switch (name) { case "and": case "or": case "xor": { string op = "instr_" + Char.ToUpper(name[0]) + name.Substring(1); AddBinary(dest, op, funCall.Args[0], funCall.Args[1]); break; } default: { TypeApply app = dafnySpec.Compile_Function(funCall.Function, funCall.TypeArgumentSubstitutions.ToDictionary(p => p.Key, p => AppType(p.Value))); AddCall(new List { dest }, false, DafnySpec.IsHeapFunction(funCall.Function), funCall.Function, funCall.Args, new List { new Formal(funCall.tok, "__result", funCall.Type, false, false) }, app); SymdiffLinearityPoint(); break; } } } else if (dataVal != null) { List args = new List { dataVal }.Concat(dataVal.Arguments).ToList(); List ins = new List { new Formal(dataVal.tok, "data", AppType(dataVal.Type), true, true) } .Concat(dataVal.Ctor.Formals).ToList(); string name = dafnySpec.Compile_Constructor(dataVal.Type, dataVal.Ctor.Name, dataVal.InferredTypeArgs, typeApply.typeArgs).AppName(); AddCall(new List { dest }, false, true, ins, "Alloc_" + name, args, new List { new Formal(dataVal.tok, "ret", AppType(dataVal.Type), false, false) }); } else if (memberSelect != null && memberSelect.Member is Field && memberSelect.MemberName.EndsWith("?")) { AddBoolViaJump(dest, exp); } else if (memberSelect != null && memberSelect.Member is Field && DafnySpec.IsArrayType(AppType(memberSelect.Obj.Type)) && memberSelect.MemberName == "Length") { RtlVar eArr = AsVarOrTemp(memberSelect.Obj); ArrayLength(dest, eArr); } else if (memberSelect != null && memberSelect.Member is Field && !memberSelect.Member.IsStatic && AppType(memberSelect.Obj.Type) is UserDefinedType && memberSelect.Member is DatatypeDestructor) { RtlVar e0 = AsVarOrTemp(memberSelect.Obj); if (minVerify) { //- run-time type check string fail = NewLabel(); string ok = NewLabel(); DatatypeDestructor field = (DatatypeDestructor) memberSelect.Member; JumpIfHasType(ok, e0, field.EnclosingCtor.Name, memberSelect.Obj.Type, true); Label(fail, true); Jump(fail); Label(ok, false); } AddFieldSelect(dest, e0, memberSelect.Obj.Type, memberSelect.MemberName, exp.Type, GhostExpression(exp)); } else if (seqSelect != null) { if (seqSelect.SelectOne && DafnySpec.IsArrayType(AppType(seqSelect.Seq.Type))) { RtlVar eArr = AsVarOrTemp(seqSelect.Seq); RtlExp eInd = AsSimpleOrTemp(seqSelect.E0); if (minVerify) { //- run-time bounds check string fail = NewLabel(); string ok = NewLabel(); RtlVar eLen = TempVar(Type.Int); ArrayLength(eLen, eArr); Jump(ok, new RtlBinary("<", eInd, eLen)); Label(fail, true); Jump(fail); Label(ok, false); } string abs = eArr + "__abs"; int start = stmts.Count; stmts.Add(new RtlStmtComputed( s => "call r, mems := loadArrayElement(r, core_state, stk, statics, io, mems, $commonVars, " + "$gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, " + s.args[0] + ", " + new RtlMem(s.args[1].e, new RtlInt(4), s.args[2].e, new RtlInt(8)).AsOperand() + ", " + eInd + ", " + abs + ", " + RegAlloc.Reg(s.args[1].ToString()) + ");", new List { new RtlArg(false, true, dest), new RtlArg(true, false, eArr), new RtlArg(true, false, eInd) }, false) .WithComment("loadArrayElement")); GroupStatements(start); } else if (seqSelect.SelectOne) { var m = dafnySpec.GetSeqMethod(AppType(seqSelect.Seq.Type), "seq_Index"); AddCall(new List { dest }, false, true, m.Item1, new List { seqSelect.Seq, seqSelect.E0 }, m.Item1.Outs, m.Item2); } else { RtlVar seq; if (DafnySpec.IsArrayType(AppType(seqSelect.Seq.Type))) { seq = TempVar(seqSelect.Type); var m = dafnySpec.FindMethod("seq_FromArray"); AddCall(new List { seq }, false, true, m, new List() { seqSelect.Seq }, m.Outs); } else { seq = AsVarOrTemp(seqSelect.Seq); } if (seqSelect.E0 != null && seqSelect.E1 != null) { var m = dafnySpec.GetSeqMethod(AppType(seqSelect.Type), "seq_TakeDrop"); AddCall(new List { dest }, false, true, m.Item1, new List { seq, null, null }, new List { null, seqSelect.E0, seqSelect.E1 }, m.Item1.Outs, m.Item2); } else if (seqSelect.E1 != null) { var m = dafnySpec.GetSeqMethod(AppType(seqSelect.Type), "seq_Take"); AddCall(new List { dest }, false, true, m.Item1, new List { seq, null }, new List { null, seqSelect.E1 }, m.Item1.Outs, m.Item2); } else if (seqSelect.E0 != null) { var m = dafnySpec.GetSeqMethod(AppType(seqSelect.Type), "seq_Drop"); AddCall(new List { dest }, false, true, m.Item1, new List { seq, null }, new List { null, seqSelect.E0 }, m.Item1.Outs, m.Item2); } else { Move(dest, seq, true); } } } else if (seqUpdate != null) { if (seqUpdate.ResolvedUpdateExpr != null) { AddExpression(dest, seqUpdate.ResolvedUpdateExpr); } else { var m = dafnySpec.GetSeqMethod(AppType(seqSelect.Seq.Type), "seq_Update"); AddCall(new List { dest }, false, true, m.Item1, new List { seqUpdate.Seq, seqUpdate.Index, seqUpdate.Value }, m.Item1.Outs, m.Item2); } } else if (seqDisplay != null) { AddBuildSequence(dest, exp); return; } else { throw new Exception("not implemented: " + dest + " := " + exp); } } void AddAssignmentRhs(RtlVar dest, AssignmentRhs rhs) { Util.DebugWriteLine("dest = " + dest + " rhs: " + rhs.GetType()); ExprRhs expRhs = rhs as ExprRhs; TypeRhs typRhs = rhs as TypeRhs; if (expRhs != null) { AddExpression(dest, expRhs.Expr); } else if (typRhs != null && DafnySpec.IsArrayType(AppType(typRhs.Type)) && typRhs.ArrayDimensions.Count == 1) { List ins = new List { new Formal(Bpl.Token.NoToken, "count", Type.Int, true, false) }; AddCall(new List { dest }, false, true, ins, "AllocArrayOfInt", new List { typRhs.ArrayDimensions[0] }, new List { new Formal(Bpl.Token.NoToken, "ret", AppType(typRhs.Type), false, false) }); } else { throw new Exception("not implemented: " + rhs + ": " + rhs.GetType()); } } RtlExp AssignmentRhsAsSimpleOrTemp(Type t, AssignmentRhs rhs) { ExprRhs expRhs = rhs as ExprRhs; if (expRhs != null) { RtlExp re = AsSimple(expRhs.Expr); if (re != null) { return re; } } RtlVar tmp = TempVar(t); AddAssignmentRhs(tmp, rhs); return tmp; } void AssignSeqLhs(RtlVar eSeq, RtlExp eInd, RtlExp eVal) { if (minVerify) { string fail = NewLabel(); string ok = NewLabel(); RtlVar eLen = TempVar(Type.Int); ArrayLength(eLen, eSeq); Jump(ok, new RtlBinary("<", eInd, eLen)); Label(fail, true); Jump(fail); Label(ok, false); } string abs = eSeq + "__abs"; RtlExp dest = new RtlMem(eSeq, new RtlInt(4), eInd, new RtlInt(8)); int start = stmts.Count; stmts.Add(new RtlStmtComputed( s => "call mems, $absMem := storeArrayElement(r, core_state, stk, statics, io, mems, " + "$commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap, " + s.args[1].AsOperand() + ", " + s.args[2].AsOperand() + ", " + eInd + ", " + eVal + ", " + abs + ", " + RegAlloc.Reg(s.args[0].ToString()) + ");", new List { new RtlArg(true, false, eSeq), new RtlArg(true, false, dest), //- make sure dest, eVal are loaded before call to storeArrayElement new RtlArg(true, false, eVal) //- (otherwise, invariants fail) }, false) .WithComment("storeArrayElement")); GroupStatements(start); } Tuple AssignLhs(Expression lhs) { IdentifierExpr idExp = lhs as IdentifierExpr; SeqSelectExpr seqSelect = lhs as SeqSelectExpr; if (idExp != null) { return Tuple.Create(AsVar(idExp), (Action)(() => {})); } else if (seqSelect != null && seqSelect.SelectOne && DafnySpec.IsArrayType(AppType(seqSelect.Seq.Type))) { RtlVar eSeq = AsVarOrTemp(seqSelect.Seq); RtlExp eInd = AsSimpleOrTemp(seqSelect.E0); RtlVar tmp = TempVar(lhs.Type); return Tuple.Create(tmp, (Action)(() => { AssignSeqLhs(eSeq, eInd, tmp); })); } else { throw new Exception("not implemented: assignment to " + lhs); } } List> InstructionAttributes(Attributes attrs) { for (; attrs.Name != "instruction"; attrs = attrs.Prev) {} return attrs.Args.ConvertAll(a => ((string)((StringLiteralExpr)a).Value)).ConvertAll(a => a.Contains("@") ? Tuple.Create(a.Substring(0, a.IndexOf('@')), a.Substring(a.IndexOf('@') + 1)) : Tuple.Create(a, (string)null)); } public RtlMem AsRtlMem(Expression e) { BinaryExpr bin = e as BinaryExpr; if (bin != null && bin.Op == BinaryExpr.Opcode.Add && AsSimple(bin.E1) is RtlInt) { return new RtlMem(AsVarOrTemp(bin.E0), AsSimple(bin.E1)); } else { return new RtlMem(AsVarOrTemp(e), new RtlInt(0)); } } public void AddCallInstruction(List destVars, List ins, string name, List args, Attributes attrs, List rtlExps = null) { name = GhostProcName(name); var operands = InstructionAttributes(attrs); bool strictOperands = Attributes.Contains(attrs, "strict_operands"); bool modifiesIo = Attributes.Contains(attrs, "modifies_io"); string envArgs = ", objLayouts, $S, $toAbs, $absMem, $commonVars, $gcVars, init, stk, statics, core_state, ptMem, mems, $stacksFrames"; string envIn = modifiesIo ? ", io" + envArgs : ""; string envOut = modifiesIo ? ", io" : ""; for (int i = 0; i < args.Count; i++) { RtlExp re = (rtlExps == null) ? null : rtlExps[i]; envIn += ", " + ((re != null) ? re.ToString() : GhostExpression(args[i]).ToString()); } envOut += String.Concat(destVars.Select(x => ", " + x)); if (instructionProcArgs != null) { var operandString = String.Concat(instructionProcArgs.Select(arg => ", " + arg)); stmts.Add(new RtlGhostStmtComputed(s => "call r" + envOut + " := " + name + "(r" + envIn + operandString + ");", new RtlExp[0])); } else if (destVars.Count == 1 && args.Count == 2 && operands.Count == 2 && operands[0].Item1 == "inout" && operands[1].Item1 == "in" && !strictOperands) { //- optimized path for binary expressions AddBinary(destVars[0], name, args[0], args[1], operands.ConvertAll(o => o.Item2), envIn, envOut); } else { List rtlArgs = new List(); int kIn = 0; int kOut = 0; foreach (var opn in operands) { RtlExp re = (rtlExps == null) ? null : rtlExps[kIn]; RtlArg arg; switch (opn.Item1) { case "in": if (strictOperands && (re == null || re is RtlInt)) { var tmp = TempVar(Type.Int); if (re == null) { AddExpression(tmp, args[kIn]); } else { Move(tmp, re, false); } arg = new RtlArg(true, false, tmp); } else { arg = new RtlArg(true, false, re != null ? re : AsSimpleOrTemp(args[kIn])); } kIn++; break; case "inout": if (re == null) { AddExpression(destVars[kOut], args[kIn]); } else { Move(destVars[kOut], re, false); } kIn++; arg = new RtlArg(true, true, destVars[kOut++]); break; case "out": arg = new RtlArg(false, true, destVars[kOut++]); break; case "mem": arg = new RtlArg(true, false, re != null ? re : AsRtlMem(args[kIn])); kIn++; break; default: throw new Exception("expected 'in', 'inout', 'out', or 'mem' on instruction attributes"); } arg.pinReg = opn.Item2; rtlArgs.Add(arg); } stmts.Add(new RtlInst(name, rtlArgs, false, envIn, envOut)); } } public void AddCall(List destVars, bool isGhost, bool isHeap, List ins, string name, List argVars, List args, List rets) { if (isGhost) { AddGhostCall(destVars, name, args, isHeap); return; } Util.Assert(args.Count == ins.Count); Util.Assert(args.Count == argVars.Count); Util.Assert(rets != null || destVars.Count == 1); List rtlArgs = new List(); int numIntRets = (rets == null) ? 1 : rets.Count(x => !x.IsGhost && !IsPtrType(AppType(x.Type))); int numPtrRets = (rets == null) ? 1 : rets.Count(x => !x.IsGhost && IsPtrType(AppType(x.Type))); int argIntIndex = numIntRets; int argPtrIndex = numPtrRets; List argStmts = new List(); for (int i = 0; i < args.Count; i++) { Util.Assert(argVars[i] != null || args[i] != null); Util.Assert(argVars[i] == null || args[i] == null); var arg = args[i]; var formal = ins[i]; RtlVar argVar = (argVars[i] != null) ? argVars[i] : AsVar(arg); bool isPtr = IsPtrType((argVars[i] != null) ? argVars[i].type : AppType(arg.Type)); if (formal.IsGhost) { rtlArgs.Add(GhostExpression(arg)); } else { if (argVar != null) { rtlArgs.Add(argVar); } else { RtlVar tmp = TempVar(args[i].Type); AddExpression(tmp, args[i]); rtlArgs.Add(tmp); } argStmts.Add(new RtlCallInOut(isPtr ? argPtrIndex : argIntIndex, false, rtlArgs[i]) .WithComment("push argument #" + i + " at index " + (isPtr ? argPtrIndex : argIntIndex) + " isPtr = " + isPtr + " argument = " + rtlArgs[i])); if (isPtr) { argPtrIndex++; } else { argIntIndex++; } } } name = ProcName(isGhost, name); if (name == procName) { throw new Exception("recursive calls not supported in non-ghost procedure: " + method.Name); } stmts.AddRange(argStmts); calledMethods.Add(name); stmts.Add(new RtlCall(name, destVars, rtlArgs, isGhost) .WithComment("call:: " + String.Join(",", destVars) + " := " + name + "(" + String.Join(", ", rtlArgs.ToList()) + ") // isGhost = " + isGhost)); if (rets != null) { int retIntIndex = 0; int retPtrIndex = 0; Util.Assert(rets.Count == destVars.Count); for (int i = 0; i < rets.Count; i++) { Util.Assert(destVars[i] == null || destVars[i].isGhost || !rets[i].IsGhost); if (!rets[i].IsGhost) { RtlVar dest = destVars[i]; if (dest == null || dest.isGhost) { dest = TempVar(rets[i].Type); } bool isPtr = IsPtrType(AppType(rets[i].Type)); stmts.Add(new RtlCallInOut(isPtr ? retPtrIndex : retIntIndex, true, dest) .WithComment("pop return value #" + i + " at index " + (isPtr ? retPtrIndex : retIntIndex) + " into destination " + destVars[i] + " isPtr = " + isPtr)); if (isPtr) { retPtrIndex++; } else { retIntIndex++; } } } } else { stmts.Add(new RtlCallInOut(0, true, destVars[0]) .WithComment("pop single return value from function into destination:: " + destVars[0])); } } public void AddCall(List destVars, bool isGhost, bool isHeap, List ins, string name, List args, List rets) { AddCall(destVars, isGhost, isHeap, ins, name, new RtlVar[args.Count].ToList(), args, rets); } private void AddCall(List destVars, bool isGhost, bool isHeap, T target, List args, List rets) where T : MemberDecl, ICallable { AddCall(destVars, isGhost, isHeap, target.Ins, DafnySpec.SimpleSanitizedName(target), args, rets); } private void AddCall(List destVars, bool isGhost, bool isHeap, T target, List argVars, List args, List rets, TypeApply typeApply) where T : MemberDecl, ICallable { rets = rets.ConvertAll(x => new Formal(x.tok, x.Name, typeApply.AppType(x.Type), x.InParam, x.IsGhost)); Method method = target as Method; Function fun = target as Function; Attributes attrs = (method != null) ? method.Attributes : (fun != null) ? fun.Attributes : null; if (Attributes.Contains(attrs, "instruction")) { AddCallInstruction(destVars, target.Ins, DafnySpec.SimpleSanitizedName(target), args, attrs); } else { AddCall(destVars, isGhost, isHeap, target.Ins, SimpleName(typeApply.AppName()), argVars, args, rets); } } private void AddCall(List destVars, bool isGhost, bool isHeap, T target, List args, List rets, TypeApply typeApply) where T : MemberDecl, ICallable { AddCall(destVars, isGhost, isHeap, target, new RtlVar[args.Count].ToList(), args, rets, typeApply); } void AddReturn(List rhss) { Util.Assert(!isGhost); if (rhss != null) { Util.Assert(method.Outs.Count == rhss.Count); for (int i = 0; i < method.Outs.Count; i++) { RtlVar dest = new RtlVar(GhostVar(method.Outs[i].Name, false), method.Outs[i].IsGhost, AppType(method.Outs[i].Type)); AddAssignmentRhs(dest, rhss[i]); } } if (instructionProcArgs == null) { stmts.Add(new RtlReturn(method.Outs.Select(x => new RtlVar(GhostVar(x.Name), x.IsGhost, AppType(x.Type)))) .WithComment("return")); } } void AddVarDecl(string varName, Type t, bool isGhost) { string name = GhostVar(varName); if (allVars.Keys.Contains(name)) { AddRename(varName); name = GhostVar(varName); } allVars.Add(name, new RtlVar(name, isGhost, AppType(t))); } public override void AddResolvedGhostStatement(Statement stmt, Attributes attrs) { MatchStmt matchStmt = stmt as MatchStmt; if (matchStmt != null) { if (matchStmt.MissingCases.Count != 0) { throw new Exception("not implemented: MatchStmt with missing cases: " + matchStmt); } var cases = matchStmt.Cases; RtlVar x = TempVar(matchStmt.Source.Type); MoveGhost(x, GhostExpression(matchStmt.Source)); foreach (MatchCaseStmt c in cases) { var oldRenamer = PushRename(); for (int i = 0; i < c.Arguments.Count; i++) { var a = c.Arguments[i]; var f = c.Ctor.Formals[i]; AddGhostVarDecl(a.Name, a.Type, true); RtlExp ghostExp = new RtlLiteral("(" + f.Name + "#" + c.Ctor.Name + "(" + x + "))"); MoveGhost(AsVar(a), ghostExp); } stmts.Add(new RtlGhostStmtComputed(s => "if (" + x + " is " + c.Ctor.Name + ") {", new RtlExp[] {})); Indent(); c.Body.ForEach(s => AddGhostStatement(s, attrs)); Unindent(); stmts.Add(new RtlGhostStmtComputed(s => "}", new RtlExp[0])); PopRename(oldRenamer); } } else { base.AddResolvedGhostStatement(stmt, attrs); } } void AddResolvedStatement(Statement stmt) { Util.DebugWriteLine("stmt: " + stmt.GetType()); Util.Assert(!isGhost); Util.Assert(!stmt.IsGhost || stmt is CalcStmt); BlockStmt block = stmt as BlockStmt; IfStmt ifStmt = stmt as IfStmt; WhileStmt whileStmt = stmt as WhileStmt; BreakStmt breakStmt = stmt as BreakStmt; ReturnStmt returnStmt = stmt as ReturnStmt; AssertStmt assertStmt = stmt as AssertStmt; AssignStmt assignStmt = stmt as AssignStmt; CallStmt callStmt = stmt as CallStmt; VarDeclStmt varDecl = stmt as VarDeclStmt; MatchStmt matchStmt = stmt as MatchStmt; CalcStmt calcStmt = stmt as CalcStmt; ForallStmt forallStmt = stmt as ForallStmt; PrintStmt printStmt = stmt as PrintStmt; if (block != null) { var oldRenamer = PushRename(); block.Body.ForEach(AddStatement); PopRename(oldRenamer); } else if (varDecl != null) { foreach (var varLocal in varDecl.Locals) { AddVarDecl(varLocal.Name, varLocal.Type, varLocal.IsGhost); } if (varDecl.Update != null) { Util.Assert(varDecl.Update is UpdateStmt); //Util.Assert(varDecl.Update.Lhss.Count() == 1); //AddAssignmentRhs(AsVar(varDecl.Update.Lhss[0]), ((UpdateStmt)varDecl.Update).Rhss[0]); AddStatement(varDecl.Update); } } else if (assignStmt != null) { IdentifierExpr idExp = assignStmt.Lhs as IdentifierExpr; SeqSelectExpr seqSelect = assignStmt.Lhs as SeqSelectExpr; if (idExp != null) { AddAssignmentRhs(AsVar(assignStmt.Lhs), assignStmt.Rhs); } else if (seqSelect != null && seqSelect.SelectOne && DafnySpec.IsArrayType(AppType(seqSelect.Seq.Type))) { RtlVar eSeq = AsVarOrTemp(seqSelect.Seq); RtlExp eInd = AsSimpleOrTemp(seqSelect.E0); RtlExp eVal = AssignmentRhsAsSimpleOrTemp(assignStmt.Lhs.Type, assignStmt.Rhs); AssignSeqLhs(eSeq, eInd, eVal); } else { throw new Exception("not implemented: assignment to " + assignStmt.Lhs); } } else if (callStmt != null) { var lhss = callStmt.Lhs.ConvertAll(AssignLhs); AddCall(lhss.ConvertAll(lhs => lhs.Item1), stmt.IsGhost, DafnySpec.IsHeapMethod(callStmt.Method), callStmt.Method, callStmt.Args, callStmt.Method.Outs, dafnySpec.Compile_Method(callStmt.Method, callStmt.MethodSelect.TypeArgumentSubstitutions().ToDictionary(p => p.Key, p => AppType(p.Value)))); lhss.ForEach(lhs => lhs.Item2()); SymdiffLinearityPoint(); } else if (ifStmt != null) { //- if (!e) goto skip1 //- then-body //- goto skip2 //- skip1: //- else-body //- skip2: string skip1 = NewLabel(); Jump(skip1, ifStmt.Guard, false); AddStatement(ifStmt.Thn); if (ifStmt.Els == null) { Label(skip1); } else { string skip2 = NewLabel(); Jump(skip2); Label(skip1); AddStatement(ifStmt.Els); Label(skip2); } } else if (whileStmt != null) { //- goto begin //- loop: //- body //- begin: //- assert ...; //- if (e) goto loop //- end: string loop = NewLabel(); string begin = NewLabel(); string end = NewLabel(); whileEnd.Add(end); Jump(begin); Label(loop); AddStatement(whileStmt.Body); Label(begin, true); foreach (MaybeFreeExpression mexp in whileStmt.Invariants) { Util.Assert(!mexp.IsFree); if (!minVerify) { bool old_stmtExprEnabled = stmtExprEnabled; stmtExprEnabled = false; stmts.Add(new RtlAssert(GhostExpression(mexp.E), true)); stmtExprEnabled = old_stmtExprEnabled; } } SymdiffLinearityPoint(); stmts.Add(new RtlLoopStart()); Jump(loop, whileStmt.Guard); whileEnd.RemoveAt(whileEnd.Count - 1); Label(end); } else if (breakStmt != null && breakStmt.TargetLabel == null) { Jump(whileEnd[whileEnd.Count - breakStmt.BreakCount]); } else if (returnStmt != null) { AddReturn(returnStmt.rhss); } else if (assertStmt != null) { if (minVerify) { return; } stmts.Add(new RtlAssert(GhostExpression(assertStmt.Expr))); } else if (matchStmt != null) { if (matchStmt.MissingCases.Count != 0) { throw new Exception("not implemented: MatchStmt with missing cases: " + matchStmt); } AddMatch(null, matchStmt.Source, matchStmt.Cases, null, c => c.Body); } else if (calcStmt != null) { AddGhostStatement(calcStmt, null); } else if (forallStmt != null) { AddGhostStatement(forallStmt, null); } else if (printStmt != null) { Util.Assert(printStmt.Args.Count == 1); var m = dafnySpec.FindMethod("print_int"); AddCall(new List(), false, true, m, new List() { printStmt.Args[0] }, m.Outs); } else { throw new Exception("not implemented: " + stmt); } } void AddStatement(Statement stmt) { Util.Assert(!isPrinting); if (isGhost || (stmt.IsGhost && !(stmt is CalcStmt))) { AddGhostStatement(stmt, null); return; } stmts.Add(new RtlComment("###LINE: " + stmt.Tok.filename + ": " + stmt.Tok.line)); List resolved = ResolveStmt(stmt); if (resolved != null) { resolved.ForEach(AddStatement); } else { AddResolvedStatement(stmt); } } public static bool IsPtrType(Type t) { return DafnySpec.IsPtrType(t); } protected void WriteDefaultRelationalRequires(bool isRelational) { if (isRelational) { iwriter.WriteLine(" requires public(io_old._inCtr);"); iwriter.WriteLine(" requires public(io_old._outCtr);"); } } protected void WriteDefaultRelationalEnsures(bool isRelational) { if (isRelational) { iwriter.WriteLine(" ensures public(io._inCtr);"); iwriter.WriteLine(" ensures public(io._outCtr);"); } else if (dafnycc.relational) { iwriter.WriteLine(" ensures io._inCtr == io_old._inCtr && io._outCtr == io_old._outCtr;"); } } protected void WriteAllVars() { allVars.Keys .Where(x => !method.Ins.Select(y => GhostVar(y.Name)).ToList().Contains(x) && !method.Outs.Select(y => GhostVar(y.Name)).ToList().Contains(x)).ToList() .ForEach(x => writer.WriteLine(" var " + x + ":" + TypeString(allVars[x].type) + ";")); allVars.Where(x => !x.Value.isGhost && IsPtrType(x.Value.type)) .ToList().ForEach(x => writer.WriteLine(" var " + x.Key + "__abs:int;")); } public void CompileInstruction() { string name = GhostProcName(DafnySpec.SimpleSanitizedName(method)); bool strictOperands = Attributes.Contains(method.Attributes, "strict_operands"); List reqs = method.Req.ConvertAll(a => GhostExpression(a.E, false, false, a.Attributes)); List enss = method.Ens.ConvertAll(a => GhostExpression(a.E, false, false, a.Attributes)); AddTypeWellFormed(reqs, method.Ins); AddTypeWellFormed(enss, method.Outs); List> operands = InstructionAttributes(method.Attributes); List> ins = new List>(); List> outs = new List>(); int kIn = 0, kOut = 0; List parms = new List(); List args = new List(); Func opnName = s => "$opn_" + DafnySpec.CleanName(s); string outRegs = ""; List opnReqs = new List(); List allPins = operands.ConvertAll(p => p.Item2).Where(p => p != null).ToList(); foreach (var r in operands) { string arg; Action> opnReq = (a, f) => { if (r.Item2 != null) { opnReqs.Add(a + " == " + f(r.Item2)); } else if (allPins.Count > 0) { opnReqs.Add(String.Join(" && ", allPins.Select(pin => a + " != " + f(pin)))); } }; switch (r.Item1) { case "in": arg = opnName(method.Ins[kIn].Name); parms.Add(arg + ":opn"); opnReq(arg, s => "OReg(" + s + ")"); ins.Add(Tuple.Create(method.Ins[kIn], "Eval(r_old, " + arg + ")")); kIn++; break; case "inout": arg = opnName(method.Ins[kIn].Name); parms.Add(arg + ":int"); opnReq(arg, s => s); ins.Add(Tuple.Create(method.Ins[kIn], "r_old.regs[" + arg + "]")); kIn++; outs.Add(Tuple.Create(method.Outs[kOut], "r.regs[" + arg + "]")); outRegs += "[" + arg + " := " + GhostVar(method.Outs[kOut].Name) + "]"; kOut++; break; case "out": arg = opnName(method.Outs[kOut].Name); parms.Add(arg + ":int"); opnReq(arg, s => s); outs.Add(Tuple.Create(method.Outs[kOut], "r.regs[" + arg + "]")); outRegs += "[" + arg + " := " + GhostVar(method.Outs[kOut].Name) + "]"; kOut++; break; case "mem": arg = opnName(method.Ins[kIn].Name); parms.Add(arg + ":opn_mem"); ins.Add(Tuple.Create(method.Ins[kIn], "EvalPtr(r_old, " + arg + ")")); kIn++; break; default: throw new Exception("expected 'in' or 'inout' or 'out' or 'mem' in attributes of method" + method.Name); } args.Add(arg); } if (method.Body != null) { stmtExprEnabled = true; instructionProcArgs = args; foreach (var x in method.Ins.Concat(method.Outs)) { string xName = GhostVar(x.Name); allVars[xName] = new RtlVar(xName, x.IsGhost, AppType(x.Type)); } foreach (Statement stmt in method.Body.Body) { AddStatement(stmt); } instructionProcArgs = null; stmtExprEnabled = false; } bool isRelational = dafnycc.relational && reqs.Concat(enss).ToList().Exists(s => s is RtlApply && (((RtlApply)s).op == "public" || ((RtlApply)s).op == "relation")); bool modifiesIo = Attributes.Contains(method.Attributes, "modifies_io"); string envOther = ", objLayouts:[int]ObjLayout, $S:int, $toAbs:[int]int, $absMem:[int][int]int, $commonVars:commonVars, $gcVars:gcVars, init:bool, stk:mem, statics:mem, core_state:core_state, ptMem:mem, mems:mems, $stacksFrames:[int]Frames"; string nucArgs = "objLayouts, $S, $toAbs, $absMem, $commonVars, $gcVars, me, init, stk, statics, core_state, ptMem, mems, $stacksFrames"; string envIn = modifiesIo ? ", linear io_old:IOState" + envOther : ""; string envOut = modifiesIo ? ", linear io:IOState" : ""; string pIns = String.Concat(method.Ins.Select(f => ", " + GhostVar(f.Name) + ":" + TypeString(f.Type))); string pOuts = String.Concat(method.Outs.Select(f => ", " + GhostVar(f.Name) + ":" + TypeString(f.Type))); envIn += pIns; envOut += pOuts; Util.Assert(!isPrinting); isPrinting = true; string operandList = String.Concat(parms.Select(p => ", " + p)); iwriter.WriteLine("atomic procedure " + name + "(my r_old:regs" + envIn + operandList + ") returns(my r:regs" + envOut + ");"); Func lets_e = (lets, e) => !(e is RtlApply) ? lets + e : ((RtlApply)e).op == "public" ? "public(" + lets + ((RtlApply)e).args[0] + ")" : ((RtlApply)e).op == "relation" ? "relation(" + lets + ((RtlApply)e).args[0] + ")" : lets + e; if (strictOperands) { opnReqs.ForEach(e => iwriter.WriteLine(" requires " + e + ";")); } ins.ForEach(p => iwriter.WriteLine(" requires " + GhostVar(p.Item1.Name) + " == " + p.Item2 + ";")); reqs.ForEach(e => iwriter.WriteLine(" requires " + e + ";")); if (modifiesIo) { WriteDefaultRelationalRequires(isRelational); } if (modifiesIo) { iwriter.WriteLine(" requires NucleusInv(" + nucArgs + ", io_old);"); } GetStaticFieldMods().ForEach(x => iwriter.WriteLine(" modifies " + x + ";")); enss.ForEach(e => iwriter.WriteLine(" ensures " + e + ";")); iwriter.WriteLine(" ensures r.regs == r_old.regs" + outRegs + ";"); if (modifiesIo) { WriteDefaultRelationalEnsures(isRelational); } if (modifiesIo) { iwriter.WriteLine(" ensures NucleusInv(" + nucArgs + ", io);"); } if (method.Body != null) { writer.WriteLine("implementation " + name + "(my r_old:regs" + envIn + operandList + ") returns(my r:regs" + envOut + ")"); writer.WriteLine("{"); WriteAllVars(); writer.WriteLine("r := r_old;"); if (modifiesIo) { writer.WriteLine("io := io_old;"); } dafnySpec.WriteLemmas(writer, this, visibleModules, method.Attributes); foreach (RtlStmt s in stmts) { writer.WriteLine(s); } writer.WriteLine("}"); } isPrinting = false; } public override void Compile() { Util.Assert(!isPrinting); isGhost = method is Lemma || method.IsGhost; procName = ProcName(isGhost, SimpleName(typeApply.AppName())); bool isAxiom = Attributes.Contains(method.Attributes, "axiom"); bool isPublic = Attributes.Contains(method.Attributes, "public"); bool isImported = Attributes.Contains(method.Attributes, "imported"); bool isInstruction = Attributes.Contains(method.Attributes, "instruction"); bool isHeapUnmodified = Attributes.Contains(method.Attributes, "dafnycc_heap_unmodified"); if (isImported && method.Body == null) { return; } if (method.Body == null && method.Name.StartsWith("reveal_")) { return; } if (isGhost) { if (!minVerify) { CompileGhost(); } return; } if (isInstruction) { CompileInstruction(); return; } List inVars = method.Ins.Where(x => !x.IsGhost).ToList().Select(x => GhostVar(x.Name)).ToList(); List outVars = method.Outs.Where(x => !x.IsGhost).ToList().Select(x => GhostVar(x.Name)).ToList(); List inInts = method.Ins.Where(x => !x.IsGhost && !IsPtrType(AppType(x.Type))).ToList(); List outInts = method.Outs.Where(x => !x.IsGhost && !IsPtrType(AppType(x.Type))).ToList(); List inPtrs = method.Ins.Where(x => !x.IsGhost && IsPtrType(AppType(x.Type))).ToList(); List outPtrs = method.Outs.Where(x => !x.IsGhost && IsPtrType(AppType(x.Type))).ToList(); foreach (var x in method.Ins.Concat(method.Outs)) { string name = GhostVar(x.Name); allVars[name] = new RtlVar(name, x.IsGhost, AppType(x.Type)); } BlockStmt body = method.Body; if (body != null) { bool lastReturn = false; stmtExprEnabled = true; foreach (Statement stmt in body.Body) { lastReturn = (stmt is ReturnStmt); AddStatement(stmt); } if (!lastReturn && !isGhost) { AddReturn(null); } stmtExprEnabled = false; stmts = new Optimize(inVars, outVars, stmts).Run(); } alloc = new RegAlloc(dafnySpec, this, inVars, outVars, inInts, outInts, inPtrs, outPtrs, allVars, stmts); if (body != null) { stmts = alloc.Alloc(); } else if (isAxiom) { stmts = new List { new RtlComment("dummy method body for axiom"), new RtlReturn(new RtlVar[0]) }; } List reqs = minVerify ? new List() : method.Req.ConvertAll(a => GhostExpression(a.E, false, true, a.Attributes)); List enss = minVerify ? new List() : method.Ens.ConvertAll(a => GhostExpression(a.E, false, false, a.Attributes)); AddTypeWellFormed(reqs, method.Ins); AddTypeWellFormed(enss, method.Outs); bool isRelational = dafnycc.relational && reqs.Concat(enss).ToList().Exists(s => s is RtlApply && (((RtlApply)s).op == "public" || ((RtlApply)s).op == "relation")); Util.DebugWriteLine(); Func regold = s => "r_old.regs[" + s + "]"; Func reg = s => "r.regs[" + s + "]"; string sMemOld = "stk_old"; string sMem = "stk"; string parms = String.Join(", ", method.Ins.Select(x => GhostVar(x.Name) + ":" + TypeString(AppType(x.Type)))); string rets = String.Join(", ", method.Outs.Select(x => GhostVar(x.Name) + ":" + TypeString(AppType(x.Type)))); string memVarsOld = "me,init,stk_old,statics_old,core_state,ptMem,mems_old"; string memVars = "me,init,stk,statics,core_state,ptMem,mems"; int frameCount = alloc.FrameCount() + dafnycc.framePointerCount; int frameSize = frameCount * 4; int inOutSize = 4 * alloc.InsOutsCount(); Func, string> f = l => (l.Count != 0) ? ", " : ""; List> preserveExps = new List>(); for (int i = 0; i < method.Mod.Expressions.Count; i++) { Expression modExp = method.Mod.Expressions[i].E; if (!(modExp is ThisExpr)) { RtlExp e = GhostExpression(modExp, false, true); preserveExps.Add(Tuple.Create("mod" + i, "(" + e + ").arrAbs")); } } string absExtend = isHeapUnmodified ? "$toAbs == $toAbs_old && objLayouts == objLayouts_old" : "AbsExtend($toAbs, $toAbs_old, objLayouts, objLayouts_old)"; string preserveHeap = isHeapUnmodified ? "heap == heap_old && $absMem == $absMem_old" : DafnyCC.PreserveHeap(minVerify, preserveExps.ConvertAll(p => p.Item2)); Util.Assert(!isPrinting); isPrinting = true; string stackPrefix = "stack_size__DafnyCC__"; //- calculate the statck size Func g = s => (calledMethods.Count == 0) ? "0" : s; if (!isPublic) { iwriter.WriteLine("const " + stackPrefix + procName + ":int := " + frameSize + " + " + g("max(" + String.Join(", max(", calledMethods.Select(s => stackPrefix + s + " + " + IPSize)) + ", 0)" + String.Join(")", calledMethods.Select(s => ""))) + ";"); iwriter.WriteLine("procedure " + procName + "(my r_old:regs, const my core_state:core_state, linear stk_old:mem, linear statics_old:mem, linear io_old:IOState, linear mems_old:mems" + ", $commonVars_old:commonVars, $gcVars_old:gcVars" + ", $toAbs_old:[int]int, $absMem_old:[int][int]int, $stacksFrames_old:[int]Frames, objLayouts_old:[int]ObjLayout, heap_old:Heap" + f(method.Ins) + parms + ") returns(my r:regs, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems" + ", $commonVars:commonVars, $gcVars:gcVars" + ", $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap" + f(method.Outs) + rets + ");"); iwriter.WriteLine(" requires MemInv(" + memVarsOld + ");"); iwriter.WriteLine(" requires NucleusInv(objLayouts_old,$S,$toAbs_old,$absMem_old,$commonVars_old,$gcVars_old,me,init,stk_old,statics_old,core_state,ptMem,mems_old,$stacksFrames_old,io_old);"); iwriter.WriteLine(" requires SMemRequireGcRA(" + stackPrefix + procName + ", " + inOutSize + ", " + sMemOld + ", " + regold("ESP") + ", RET);"); iwriter.WriteLine(" requires HeapInv($absMem_old, objLayouts_old, heap_old);"); WriteDefaultRelationalRequires(isRelational); foreach (var p in alloc.inInts) { int offset = alloc.InIntsOffset() - alloc.OutsOffset() + IPSize + p.Value; string val = sMemOld + ".map[" + regold("ESP") + " + " + offset + "]"; iwriter.WriteLine(" requires " + IntEqTyped(allVars[p.Key].type, p.Key, val) + ";"); } for (int i = 0; i < inPtrs.Count; i++) { Formal x = inPtrs[i]; int offset = alloc.InPtrsOffset() - alloc.OutsOffset() + IPSize + alloc.inPtrs[GhostVar(x.Name)]; string loc = regold("ESP") + " + " + offset + " + stackGcOffset"; iwriter.WriteLine(" requires StackAbsSlot(heap_old, $stacksFrames_old, " + loc + ") == Abs_" + TypeString(AppType(x.Type)) + "(" + GhostVar(x.Name) + ");"); if (DafnySpec.IsArrayType(AppType(x.Type))) { iwriter.WriteLine(" requires frameGet($stacksFrames_old, " + loc + ") == " + GhostVar(x.Name) + ".arrAbs;"); } } reqs.ForEach(e => iwriter.WriteLine(" requires " + e + ";")); iwriter.WriteLine(" modifies $Time;"); GetStaticFieldMods().ForEach(x => iwriter.WriteLine(" modifies " + x + ";")); iwriter.WriteLine(" ensures " + reg("ESP") + " == old(" + regold("ESP") + ") + " + IPSize + ";"); iwriter.WriteLine(" ensures MemInv(" + memVars + ");"); iwriter.WriteLine(" ensures NucleusInv(objLayouts,$S,$toAbs,$absMem,$commonVars,$gcVars,me,init,stk,statics,core_state,ptMem,mems,$stacksFrames,io);"); iwriter.WriteLine(" ensures SMemEnsureGcF(" + inOutSize + ", " + sMem + ", old(" + sMemOld + "), " + reg("ESP") + ", old(" + regold("ESP") + "), $stacksFrames, $stacksFrames_old);"); iwriter.WriteLine(" ensures HeapInv($absMem, objLayouts, heap);"); iwriter.WriteLine(" ensures " + absExtend + ";"); iwriter.WriteLine(" ensures " + preserveHeap + ";"); WriteDefaultRelationalEnsures(isRelational); enss.ForEach(e => iwriter.WriteLine(" ensures " + e + ";")); /* foreach (var p in retMap) { writer.WriteLine(" ensures " + reg(p.Value) + " == " + p.Key + ";"); } */ foreach (var p in alloc.outInts) { int offset = IPSize + p.Value; string val = sMem + ".map[" + regold("ESP") + " + " + offset + "]"; iwriter.WriteLine(" ensures " + IntEqTyped(allVars[p.Key].type, p.Key, val) + ";"); } for (int i = 0; i < outPtrs.Count; i++) { Formal x = outPtrs[i]; int offset = IPSize + alloc.outPtrs[GhostVar(x.Name)]; string loc = regold("ESP") + " + " + offset + " + stackGcOffset"; iwriter.WriteLine(" ensures StackAbsSlot(heap, $stacksFrames, " + loc + ") == Abs_" + TypeString(AppType(x.Type)) + "(" + GhostVar(x.Name) + ");"); if (DafnySpec.IsArrayType(AppType(x.Type))) { iwriter.WriteLine(" ensures frameGet($stacksFrames, " + loc + ") == " + GhostVar(x.Name) + ".arrAbs;"); } } } if (body != null || isAxiom) { writer.WriteLine("implementation " + procName + "(my r_old:regs, const my core_state:core_state, linear stk_old:mem, linear statics_old:mem, linear io_old:IOState, linear mems_old:mems" + ", $commonVars_old:commonVars, $gcVars_old:gcVars" + ", $toAbs_old:[int]int, $absMem_old:[int][int]int, $stacksFrames_old:[int]Frames, objLayouts_old:[int]ObjLayout, heap_old:Heap" + f(method.Ins) + parms + ") returns(my r:regs, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems" + ", $commonVars:commonVars, $gcVars:gcVars" + ", $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap" + f(method.Outs) + rets + ")"); writer.WriteLine("{"); writer.WriteLine(" var $absMem_tmp:[int][int]int;"); writer.WriteLine(" var objLayouts_tmp:[int]ObjLayout;"); writer.WriteLine(" var heap_tmp:Heap;"); writer.WriteLine(" var obj_tmp:int;"); writer.WriteLine(" var val_tmp:int;"); preserveExps.ForEach(p => writer.WriteLine(" var " + p.Item1 + ":int;")); WriteAllVars(); dafnySpec.WriteLemmas(writer, this, visibleModules, method.Attributes); writer.WriteLine(" r := r_old;"); writer.WriteLine(" stk := stk_old;"); writer.WriteLine(" statics := statics_old;"); writer.WriteLine(" io := io_old;"); writer.WriteLine(" mems := mems_old;"); writer.WriteLine(" $commonVars := $commonVars_old;"); writer.WriteLine(" $gcVars := $gcVars_old;"); writer.WriteLine(" $toAbs := $toAbs_old;"); writer.WriteLine(" $absMem := $absMem_old;"); writer.WriteLine(" $stacksFrames := $stacksFrames_old;"); writer.WriteLine(" objLayouts := objLayouts_old;"); writer.WriteLine(" heap := heap_old;"); for (int i = 0; i < inPtrs.Count; i++) { Formal x = inPtrs[i]; int offset = alloc.InPtrsOffset() - alloc.OutsOffset() + IPSize + alloc.inPtrs[GhostVar(x.Name)]; writer.WriteLine(" " + GhostVar(x.Name) + "__abs := frameGet($stacksFrames, " + regold("ESP") + " + " + offset + " + stackGcOffset);"); } preserveExps.ForEach(p => writer.WriteLine(" " + p.Item1 + " := " + p.Item2 + ";")); writer.WriteLine(" assert TV(" + reg("ESP") + ");"); for (int i = 0; i < frameCount; i++) { writer.WriteLine(" assert TO(0 - " + (i + 1) + ");"); writer.WriteLine(" assert TO(" + RegAlloc.stackGcOffset / 4 + " - " + (i + 1) + ");"); } for (int i = frameCount; i < alloc.FrameVisibleCount(); i++) { writer.WriteLine(" assert TO(" + (i - frameCount) + ");"); writer.WriteLine(" assert TO(" + (RegAlloc.stackGcOffset / 4 + i - frameCount) + ");"); } if (frameSize != 0) { writer.WriteLine(" call r := logical_Sub(r, ESP, OConst(" + frameSize + "));"); if (dafnycc.useFramePointer) { writer.WriteLine(" call stk := logical_Store(r, core_state, stk, OMem(MReg(ESP, " + (frameSize - 4) + ")), OReg(EBP));"); writer.WriteLine(" call r := instr_LeaUnchecked(r, EBP, OMem(MReg(ESP, " + (frameSize - 4) + ")));"); } } bool wasComment= false; string indent = " "; foreach (RtlStmt s in stmts) { RtlIndent rtlIndent = s as RtlIndent; RtlLabel label = s as RtlLabel; RtlCall call = s as RtlCall; if (rtlIndent != null) { indent = rtlIndent.Positive ? indent + " " : indent.Substring(4); continue; } if (s is RtlReturn && frameSize != 0) { if (dafnycc.useFramePointer) { writer.WriteLine(" call r := logical_Load(r, core_state, stk, EBP, OMem(MReg(ESP, " + (frameSize - 4) + ")));"); } writer.WriteLine(indent + "call r := logical_Add(r, ESP, OConst(" + frameSize + "));"); } /* if (call != null && call.op == "Proc_sample") { writer.WriteLine(indent + GhostVar(samplemap) + " := F();"); } */ if (s.comment != null) { if (!wasComment) { writer.WriteLine(); } writer.WriteLine(indent + "// " + s.comment().Replace(Environment.NewLine, Environment.NewLine + indent)); } wasComment = true; if (s.ToString() != "") { writer.WriteLine(indent + s.ToString().Replace(Environment.NewLine, Environment.NewLine + indent)); wasComment = false; } if (call != null) { writer.WriteLine(indent + "assert SMemInvGcF(" + (inOutSize + 4) + ", " + sMem + ", old(" + sMemOld + "), " + reg("ESP") + " + " + frameSize + ", old(" + regold("ESP") + "), $stacksFrames, $stacksFrames_old);"); if (dafnycc.useFramePointer) { writer.WriteLine(indent + "call r := instr_LeaUnchecked(r, EBP, OMem(MReg(ESP, " + (frameSize - 4) + ")));"); } } if (label != null && label.loop) { writer.WriteLine(indent + "invariant MemInv(" + memVars + ");"); writer.WriteLine(indent + "invariant NucleusInv(objLayouts,$S,$toAbs,$absMem,$commonVars,$gcVars,me,init,stk,statics,core_state,ptMem,mems,$stacksFrames,io);"); writer.WriteLine(indent + "invariant SMemInvGcF(" + (inOutSize + 4) + ", " + sMem + ", old(" + sMemOld + "), " + reg("ESP") + " + " + frameSize + ", old(" + regold("ESP") + "), $stacksFrames, $stacksFrames_old);"); writer.WriteLine(indent + "invariant HeapInv($absMem, objLayouts, heap);"); writer.WriteLine(indent + "invariant " + absExtend + ";"); writer.WriteLine(indent + "invariant " + preserveHeap + ";"); if (isRelational) { writer.WriteLine(" invariant public(io._inCtr);"); writer.WriteLine(" invariant public(io._outCtr);"); } else if (dafnycc.relational) { writer.WriteLine(" invariant io._inCtr == io_old._inCtr && io._outCtr == io_old._outCtr;"); } } if (s is RtlLoopStart) { dafnySpec.WriteLemmas(writer, this, visibleModules, method.Attributes, true); } } writer.WriteLine("}"); } isPrinting = false; } } ================================================ FILE: ironclad-apps/tools/DafnyCC/DafnyCC.cs ================================================ using System; using System.IO; using System.Linq; using System.Collections.Generic; using System.Collections.ObjectModel; using Microsoft.Dafny; using Bpl = Microsoft.Boogie; using Type = Microsoft.Dafny.Type; using System.Numerics; public class DafnyCC_Options: DafnySpec_Options { public bool relational; public bool x64 = false; public bool useFramePointer = false; protected override bool ParseOption(string name, Bpl.CommandLineOptionEngine.CommandLineParseState ps) { switch (name) { case "relational": relational = true; return true; case "x64": x64 = true; return true; case "useFramePointer": useFramePointer = true; return true; default: break; } return base.ParseOption(name, ps); } } public class DafnyCC: DafnySpec { TextWriter heapWriter = null; TextWriter heapIWriter = null; TextWriter checkedWriter = null; TextWriter checkedIWriter = null; TextWriter seqWriter = null; TextWriter seqIWriter = null; TextWriter mainWriter = Console.Out; public bool relational = false; public bool x64 = false; public bool useFramePointer = false; public int IPSize; public int framePointerCount = 0; public List lemmas = new List { new LemmaCall("Heap", (Type)null, "assert fun_unroll(0);", false), new LemmaCall("Heap", (Type)null, "assert fun_unroll(1);", false), }; public List lazyLemmas = new List { "Seq_FromArray_Length", "Seq_FromArray_Index", "Seq_FromArray_Update", }; public List seqLemmas = new List { "Seq_Empty_ToZero", "Seq_Empty_FromZero", "Seq_Singleton_Length", "Seq_Build_Length", "Seq_Build_Index", "Seq_Append_Length", "Seq_Index_Singleton", "Seq_Append_Index", "Seq_Update_Length", "Seq_Index_Update", "Seq_Equal_Equiv", "Seq_Take_Length", "Seq_Take_Index", "Seq_Drop_Length", "Seq_Drop_Index", "Seq_Append_TakeDrop", "Seq_Append_TakeDrop_Restricted", "Seq_Update_CommuteTake1", "Seq_Update_CommuteTake2", "Seq_Update_CommuteDrop1", "Seq_Update_CommuteDrop2", "Seq_Build_CommuteDrop", "Seq_Take_Empty", "Seq_Drop_Empty", }; public static new void Main(string[] args) { try { Util.DebugWriteLine("hello"); DafnyCC_Options options = new DafnyCC_Options(); DafnyOptions.Install(options); DafnyOptions.O.AllowGlobals = true; DafnyOptions.O.Dafnycc = true; Bpl.CommandLineOptions.Clo.RunningBoogieFromCommandLine = true; if (!Bpl.CommandLineOptions.Clo.Parse(args)) { throw new Exception("argument parse error"); } IList files = Bpl.CommandLineOptions.Clo.Files; if (files.Count == 0) { throw new Exception("*** Error: No input files were specified."); } if (options.useFramePointer && options.x64) { throw new Exception("64-bit frame pointer not yet implemented"); } new DafnyCC().CompileCode(options, files); } catch (Exception e) { Console.OpenStandardOutput().Flush(); Console.WriteLine(e); Console.Error.WriteLine(e); Environment.Exit(-1); } } public static string ProcName(bool isGhost, string x) { return (isGhost ? "proc_" : "Proc_") + CleanName(x); } public static string PreserveHeap(bool minVerify, List mods, string absMem = "$absMem", string absMemOld = "$absMem_old", string heap = "heap", string heap_old = "heap_old") { return "(forall i:int::{" + absMem + "[i]}{" + heap + ".absData[i]} " + heap_old + ".absData[i] is AbsNone" + " || (" + heap + ".absData[i] == " + heap_old + ".absData[i]" + " && (" + absMem + "[i] == " + absMemOld + "[i]" + (minVerify ? " || " + heap_old + ".absData[i] is Abs_ArrayOfInt" : String.Concat(mods.Select(s => " || i == (" + s +")"))) + ")))"; } public static string PreserveHeap(bool minVerify) { return PreserveHeap(minVerify, new List()); } public override void AddLemma(LemmaCall lemma) { lemmas.Add(lemma); } public override void AddMethodAsLemma(Method method) { if (lazyLemmas.Contains(method.Name)) { lazyLemmas.Remove(method.Name); lemmas.Add(new LemmaCall("Seq", (Type)null, "call " + ProcName(true, DafnySpec.SimpleSanitizedName(method)) + "();", Attributes.Contains(method.Attributes, "loop_lemma"))); } } public override void WriteLemmas(TextWriter writer, CompileBase context, List visibleModules, Attributes attrs, bool loopLemmasOnly = false) { if (minVerify) { return; } if (!Attributes.Contains(attrs, "dafnycc_no_lemmas")) { foreach (var x in lemmas.Where(x => visibleModules.Contains(x.module))) { if (x.type != null && context.visibleElementType != null && x.type.ToString() != context.visibleElementType.ToString()) { continue; } if (loopLemmasOnly && !x.loopLemma) { continue; } string line = x.stmt; if (line.Contains("Seq__Append__TakeDrop")) { bool isRestricted = line.Contains("Seq__Append__TakeDrop__Restricted"); bool isConservative = Attributes.Contains(attrs, "dafnycc_conservative_seq_triggers"); if (isConservative != isRestricted) { continue; } } writer.WriteLine(" " + line); } } } /* TODO: reduce number of imports for specs public void WriteImplementationHeader(TextWriter writer, string name, List imports) { writer.WriteLine("module implementation " + name); writer.WriteLine(" import BaseSpec, MemorySpec, IoTypesSpec, MachineStateSpec, AssemblySpec, InterruptsSpec, IoSpec, OverflowSpec;"); writer.WriteLine(" import Core, LogicalAddressing, Util, Stacks, Partition, Separation;"); writer.WriteLine(" import IntLemmasGc, GcMemory, Common, GcCollector;"); writer.WriteLine(" import IntLemmasMain, IntLemmasBase, IoMain" + String.Join("", imports.Select(s => ", " + s)) + ";"); writer.WriteLine("{"); } */ private void WriteAxiomAnnotations(TextWriter writer, IEnumerable axioms) { foreach (string axiom in axioms) { writer.WriteLine("//"); } } public override Tuple> ChooseOutDirWriter(string filename) { if (outDir == null) { throw new Exception("It would be nice to specify outDir"); } if (!outDirWriters.ContainsKey(filename)) { string moduleName = ModuleNameFromFilename(filename); string baseName = Path.Combine(outDir, moduleName); TextWriter implWriter = new StreamWriter(baseName + ImpBasmExtn); TextWriter intfWriter = new StreamWriter(baseName + IfcBasmExtn); Dictionary imports = new Dictionary(StringComparer.CurrentCultureIgnoreCase); imports.Add("Trusted", ""); imports.Add("Checked", ""); imports.Add("Heap", ""); imports.Add("Seq", ""); if (moduleName != "dafny_DafnyPrelude") { imports.Add("dafny_DafnyPrelude", ""); imports.Add("DafnyAssembly", ""); } AddImports(imports, filename); List importModules = imports.Keys.ToList(); if (outListWriter != null && moduleName != "dafny_DafnyPrelude") { outListWriter.WriteLine(moduleName + String.Concat( imports.Where(x => x.Value != "").Select(x => " " + x.Key))); } WriteImplementationHeader(implWriter, moduleName, importModules); WriteAxiomAnnotations(implWriter, new string[] { "Assembly", "Base", "Memory", "Word", "Io"}); intfWriter.WriteLine("module interface " + moduleName); WriteInterfaceImports(intfWriter, GatherAllImports(importModules)); intfWriter.WriteLine("{"); outDirWriters.Add(filename, Tuple.Create(implWriter, intfWriter, moduleName, importModules)); imports.Values.Where(x => x != "").ToList().ForEach(x => {ChooseOutDirWriter(x);}); } return outDirWriters[filename]; } public override Tuple> ChooseWriter( Bpl.IToken tok, string name, TypeApply app = null) { string filename = Path.GetFullPath(tok.filename); bool trustedArg = (app != null && app.typeArgs.Count == 1 && TrustedType(app.typeArgs.Values)); if (IsSeqFile(filename, true)) { return Tuple.Create(trustedArg ? trustedWriter : checkedWriter, (name.StartsWith("lemma_Seq") ? (trustedArg ? trustedWriter : checkedWriter) : (trustedArg ? trustedIWriter : checkedIWriter)), trustedArg ? "Trusted" : "Checked", trustedArg ? new List() : new List { "Trusted" }); } else if (IsSeqFile(filename, false)) { return Tuple.Create(seqWriter, (name.StartsWith("lemma_Seq") ? seqWriter : seqIWriter), "Seq", new List { "Trusted", "Checked", "Heap" }); } else { return ChooseOutDirWriter(filename); } } void CompileDatatype1Code(Type t, TypeApply app) { string dataName = app.AppName(); List ctors = compileDatatypes[app].AsDatatype.Ctors; bool isSeq = dataName.StartsWith("Seq_"); for (int i = 0; i < ctors.Count; i++) { heapIWriter.WriteLine("const Tag_" + dataName + "_" + ctors[i].Name + ":int := " + (i + 1) + ";"); } heapWriter.WriteLine("function HeapWordInv_" + dataName + "(absData:[int]AbsData, objLayout:ObjLayout, wordMem:[int]int, data:" + dataName + "):bool"); heapWriter.WriteLine("{"); heapWriter.WriteLine(" true"); foreach (var ctor in ctors) { var ints = ctor.Formals.Where(x => !IsPtrType(app.AppType(x.Type))).ToList(); var ptrs = ctor.Formals.Where(x => IsPtrType(app.AppType(x.Type))).ToList(); var sorted = ints.Concat(ptrs).ToList(); string ctorName = Compile_Constructor(t, ctor.Name, app.typeArgs).AppName(); string wordMems = ""; for (int i = 0; i < sorted.Count; i++) { heapIWriter.WriteLine("const Offset_" + dataName + "_" + sorted[i].Name + ":int := " + (8 + 4 * i) + ";"); if (IsPtrType(app.AppType(sorted[i].Type))) { wordMems += " && absData[wordMem[" + (3 + i) + "]] == Abs_" + TypeString(app.AppType(sorted[i].Type)) + "(" + sorted[i].Name + (isSeq ? "_" : "#") + ctorName + "(data))"; } else { wordMems += " && " + CompileBase.IntEqTyped( app.AppType(sorted[i].Type), sorted[i].Name + (isSeq ? "_" : "#") + ctorName + "(data)", "wordMem[" + (3 + i) + "]"); } } string dataIs = isSeq ? ("is_" + ctorName + "(data)") : "data is " + ctorName; heapWriter.WriteLine("&& (" + dataIs + " ==> objLayout == ObjLayout(" + (3 + sorted.Count) + ", " + (3 + ints.Count) + ") && wordMem[2] == Tag_" + dataName + "_" + ctor.Name + wordMems + ")"); } heapWriter.WriteLine("}"); } void CompileDatatype1(Type t, TypeApply app) { string dataName = app.AppName(); List ctors = compileDatatypes[app].AsDatatype.Ctors; bool isSeq = dataName.StartsWith("Seq_"); bool isTrusted = isSeq ? TrustedType(app.typeArgs.Values) : TrustedType(t); CompileDatatype1Ghost(t, app, isTrusted ? trustedWriter : checkedWriter, isTrusted ? trustedIWriter : checkedIWriter); CompileDatatype1Code(t, app); } string loadTagDecl(String List, String tags) { return String.Format(@" atomic procedure loadTag_{0}(my r_old:regs, const my core_state:core_state, const linear stk:mem, const linear statics:mem, const linear io:IOState, linear mems_old:mems, $commonVars:commonVars, $gcVars:gcVars, $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap, x:int, y:opn_mem, data:{0}, abs:int, obj:int) returns(my r:regs, linear mems:mems); requires MemInv(me,init,stk,statics,core_state,ptMem,mems_old); requires isStack($S); requires NucleusInv(objLayouts,$S,$toAbs,$absMem,$commonVars,$gcVars,me,init,stk,statics,core_state,ptMem,mems_old,$stacksFrames,io); requires HeapInv($absMem, objLayouts, heap); requires HeapAbsData(heap, abs) == Abs_{0}(data); requires HeapValue(objLayouts, true, $toAbs, obj, abs); requires EvalPtrOk(y); requires EvalPtr(r_old, y) == obj + 4; ensures mems == mems_old; ensures r.regs == r_old.regs[x := r.regs[x]]; ensures {1};", List, tags); } string allocDecl1(string list, string cons, string _cons, string Params, string args, string argRet) { return @" procedure Proc_Alloc_" + cons + @"(my r_old:regs, const my core_state:core_state, linear stk_old:mem, linear statics_old:mem, linear io_old:IOState, linear mems_old:mems, $commonVars_old:commonVars, $gcVars_old:gcVars, $toAbs_old:[int]int, $absMem_old:[int][int]int, $stacksFrames_old:[int]Frames, objLayouts_old:[int]ObjLayout, heap_old:Heap, data:" + list + @", " + Params + @") returns(my r:regs, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars, $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap, data_out:" + list + @"); requires MemInv(me,init,stk_old,statics_old,core_state,ptMem,mems_old); requires isStack($S); requires NucleusInv(objLayouts_old,$S,$toAbs_old,$absMem_old,$commonVars_old,$gcVars_old,me,init,stk_old,statics_old,core_state,ptMem,mems_old,$stacksFrames_old,io_old); requires SMemRequireGcRA(256, " + argRet + @", stk_old, r_old.regs[ESP], RET); requires HeapInv($absMem_old, objLayouts_old, heap_old); "; } string allocDecl2(string list, string cons, string preserve, string args) { return @" modifies $Time; ensures MemInv(me,init,stk,statics,core_state,ptMem,mems); ensures NucleusInv(objLayouts,$S,$toAbs,$absMem,$commonVars,$gcVars,me,init,stk,statics,core_state,ptMem,mems,$stacksFrames,io); ensures SMemEnsureGcF(4, stk, old(stk_old), r.regs[ESP], old(r_old.regs[ESP]), $stacksFrames, $stacksFrames_old); ensures HeapInv($absMem, objLayouts, heap); ensures AbsExtend($toAbs, $toAbs_old, objLayouts, objLayouts_old); ensures io._inCtr == io_old._inCtr && io._outCtr == io_old._outCtr; ensures heap_old.absData[frameGet($stacksFrames, r.regs[ESP] + stackGcOffset)] is AbsNone; ensures StackAbsSlot(heap, $stacksFrames, r.regs[ESP] + stackGcOffset) == Abs_" + list + @"(data_out); ensures data_out == " + cons + @"(" + args + @"); ensures " + preserve + @"; "; } string allocDeclArray(int IPSize, string preserve) { return @" const stack_size__DafnyCC__Proc_AllocArrayOfInt:int := 256; procedure Proc_AllocArrayOfInt(my r_old:regs, const my core_state:core_state, linear stk_old:mem, linear statics_old:mem, linear io_old:IOState, linear mems_old:mems, $commonVars_old:commonVars, $gcVars_old:gcVars, $toAbs_old:[int]int, $absMem_old:[int][int]int, $stacksFrames_old:[int]Frames, objLayouts_old:[int]ObjLayout, heap_old:Heap, count:int) returns(my r:regs, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars, $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap, data:ArrayOfInt); requires MemInv(me,init,stk_old,statics_old,core_state,ptMem,mems_old); requires isStack($S); requires NucleusInv(objLayouts_old,$S,$toAbs_old,$absMem_old,$commonVars_old,$gcVars_old,me,init,stk_old,statics_old,core_state,ptMem,mems_old,$stacksFrames_old,io_old); requires SMemRequireGcRA(256, 4, stk_old, r_old.regs[ESP], RET); requires HeapInv($absMem_old, objLayouts_old, heap_old); requires stk_old.map[r_old.regs[ESP] + " + IPSize + @"] == count; modifies $Time; ensures MemInv(me,init,stk,statics,core_state,ptMem,mems); ensures NucleusInv(objLayouts,$S,$toAbs,$absMem,$commonVars,$gcVars,me,init,stk,statics,core_state,ptMem,mems,$stacksFrames,io); ensures SMemEnsureGcF(4, stk, old(stk_old), r.regs[ESP], old(r_old.regs[ESP]), $stacksFrames, $stacksFrames_old); ensures HeapInv($absMem, objLayouts, heap); ensures " + preserve + @"; ensures AbsExtend($toAbs, $toAbs_old, objLayouts, objLayouts_old); ensures io._inCtr == io_old._inCtr && io._outCtr == io_old._outCtr; ensures data.arrCount == count; ensures data.arrAbs == frameGet($stacksFrames, r.regs[ESP] + stackGcOffset); ensures heap_old.absData[data.arrAbs] is AbsNone; ensures StackAbsSlot(heap, $stacksFrames, r.regs[ESP] + stackGcOffset) == Abs_ArrayOfInt(data); "; } string loadField(string list, string dataIsCons, string tl) { return @" atomic procedure loadField_" + list + "_" + tl + @"(my r_old:regs, const my core_state:core_state, const linear stk:mem, const linear statics:mem, const linear io:IOState, linear mems_old:mems, $commonVars_old:commonVars, $gcVars_old:gcVars, $toAbs_old:[int]int, $absMem_old:[int][int]int, $stacksFrames_old:[int]Frames, objLayouts_old:[int]ObjLayout, heap:Heap, x:int, y:opn_mem, data:" + list + @", abs:int, obj:int) returns(my r:regs, linear mems:mems); requires MemInv(me,init,stk,statics,core_state,ptMem,mems_old); requires isStack($S); requires NucleusInv(objLayouts_old,$S,$toAbs_old,$absMem_old,$commonVars_old,$gcVars_old,me,init,stk,statics,core_state,ptMem,mems_old,$stacksFrames_old,io); requires HeapInv($absMem_old, objLayouts_old, heap); requires HeapAbsData(heap, abs) == Abs_" + list + @"(data); requires HeapValue(objLayouts_old, true, $toAbs_old, obj, abs); requires " + dataIsCons + @"; requires EvalPtrOk(y); requires EvalPtr(r_old, y) == obj + Offset_" + list + "_" + tl + @"; ensures mems == mems_old; ensures r.regs == r_old.regs[x := r.regs[x]]; "; } string arrayElementProperties() { return @" atomic procedure arrayElementProperties(const my core_state:core_state, const linear stk:mem, const linear statics:mem, const linear io:IOState, const linear mems_old:mems, $commonVars_old:commonVars, $gcVars_old:gcVars, $toAbs_old:[int]int, $absMem_old:[int][int]int, $stacksFrames_old:[int]Frames, objLayouts_old:[int]ObjLayout, heap:Heap, index:int, abs:int, obj:int); requires MemInv(me,init,stk,statics,core_state,ptMem,mems_old); requires isStack($S); requires NucleusInv(objLayouts_old,$S,$toAbs_old,$absMem_old,$commonVars_old,$gcVars_old,me,init,stk,statics,core_state,ptMem,mems_old,$stacksFrames_old,io); requires HeapInv($absMem_old, objLayouts_old, heap); requires HeapAbsData(heap, abs) is Abs_ArrayOfInt; requires (0 - 1 == index) || (0 <= index && index < HeapAbsData(heap, abs).arr.arrCount); requires HeapValue(objLayouts_old, true, $toAbs_old, obj, abs); ensures word(obj + 4 * (2 + index)); ensures abs == HeapAbsData(heap, abs).arr.arrAbs; "; } string loadArrayElement() { return @" atomic procedure loadArrayElement(my r_old:regs, const my core_state:core_state, const linear stk:mem, const linear statics:mem, const linear io:IOState, linear mems_old:mems, $commonVars_old:commonVars, $gcVars_old:gcVars, $toAbs_old:[int]int, $absMem_old:[int][int]int, $stacksFrames_old:[int]Frames, objLayouts_old:[int]ObjLayout, heap:Heap, x:int, y:opn_mem, index:int, abs:int, obj:int) returns(my r:regs, linear mems:mems); requires MemInv(me,init,stk,statics,core_state,ptMem,mems_old); requires isStack($S); requires NucleusInv(objLayouts_old,$S,$toAbs_old,$absMem_old,$commonVars_old,$gcVars_old,me,init,stk,statics,core_state,ptMem,mems_old,$stacksFrames_old,io); requires HeapInv($absMem_old, objLayouts_old, heap); requires HeapAbsData(heap, abs) is Abs_ArrayOfInt; requires (0 - 1 == index) || (0 <= index && index < HeapAbsData(heap, abs).arr.arrCount); requires HeapValue(objLayouts_old, true, $toAbs_old, obj, abs); requires EvalPtrOk(y); requires EvalPtr(r_old, y) == obj + 4 * (2 + index); ensures abs == HeapAbsData(heap, abs).arr.arrAbs; ensures mems == mems_old; ensures r.regs == r_old.regs[x := r.regs[x]]; ensures r.regs[x] == if index >= 0 then fun_INTERNAL__array__elems__index($absMem_old[abs], index) else HeapAbsData(heap, abs).arr.arrCount; ensures r.efl == r_old.efl; ensures word(r.regs[x]); "; } string storeArrayElement() { return @" atomic procedure storeArrayElement(const my r:regs, const my core_state:core_state, const linear stk:mem, const linear statics:mem, const linear io:IOState, linear mems_old:mems, $commonVars_old:commonVars, $gcVars_old:gcVars, $toAbs_old:[int]int, $absMem_old:[int][int]int, $stacksFrames_old:[int]Frames, objLayouts_old:[int]ObjLayout, heap:Heap, x:opn_mem, y:opn, index:int, val:int, abs:int, obj:int) returns(linear mems:mems, absMem:[int][int]int); requires MemInv(me,init,stk,statics,core_state,ptMem,mems_old); requires isStack($S); requires NucleusInv(objLayouts_old,$S,$toAbs_old,$absMem_old,$commonVars_old,$gcVars_old,me,init,stk,statics,core_state,ptMem,mems_old,$stacksFrames_old,io); requires HeapInv($absMem_old, objLayouts_old, heap); requires HeapAbsData(heap, abs) is Abs_ArrayOfInt; requires 0 <= index && index < HeapAbsData(heap, abs).arr.arrCount; requires HeapValue(objLayouts_old, true, $toAbs_old, obj, abs); requires word(val); requires EvalPtrOk(x); requires EvalPtr(r, x) == obj + 4 * (2 + index); requires SrcOk(y); requires val == Eval(r, y); ensures NucleusInv(objLayouts_old,$S,$toAbs_old,absMem,$commonVars_old,$gcVars_old,me,init,stk,statics,core_state,ptMem,mems,$stacksFrames_old,io); ensures HeapInv(absMem, objLayouts_old, heap); ensures tcb#mems(mems)==tcb#mems(mems_old); ensures pci#mems(mems)==pci#mems(mems_old); ensures frm#mems(mems)==frm#mems(mems_old); ensures dat#mems(mems)==dat#mems(mems_old); ensures abs == HeapAbsData(heap, abs).arr.arrAbs; ensures absMem == fun_INTERNAL__array__update($absMem_old, HeapAbsData(heap, abs).arr, index, val); ensures (forall i:int::{fun_INTERNAL__array__elems__index(absMem[abs], i)} i != index ==> fun_INTERNAL__array__elems__index(absMem[abs], i) == fun_INTERNAL__array__elems__index($absMem_old[abs], i)); "; } string allocImpl1(string list, string con, string cons, string _cons, string Params, string args, string size, string sizeInts, string triggers, string seqLemma) { return @" implementation Proc_Alloc_" + cons + @"(my r_old:regs, const my core_state:core_state, linear stk_old:mem, linear statics_old:mem, linear io_old:IOState, linear mems_old:mems, $commonVars_old:commonVars, $gcVars_old:gcVars, $toAbs_old:[int]int, $absMem_old:[int][int]int, $stacksFrames_old:[int]Frames, objLayouts_old:[int]ObjLayout, heap_old:Heap, data:" + list + @", " + Params + @") returns(my r:regs, linear stk:mem, linear statics:mem, linear io:IOState, mems:mems, $commonVars:commonVars, $gcVars:gcVars, $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap, data_out:" + list + @") { var abs:int; var _mem:[int]int; var obj:int; r := r_old; stk := stk_old; statics := statics_old; io := io_old; mems := mems_old; $commonVars := $commonVars_old; $gcVars := $gcVars_old; $toAbs := $toAbs_old; $absMem := $absMem_old; $stacksFrames := $stacksFrames_old; objLayouts := objLayouts_old; heap := heap_old; data_out := " + _cons + "(" + args + @"); assert THeapInv($absMem, objLayouts, heap); " + seqLemma + @" assert TV(r.regs[ESP]) && " + triggers + @" && TO(0 - 1) && TO(0 - 2) && TO(0 - 3); call r := logical_Sub(r, ESP, OConst(12)); call heap, abs := freshAbs(?gcHi, $toAbs, heap); call r := instr_Mov(r, EBP, OConst(0)); call r := instr_Mov(r, ECX, OConst(" + size + @")); call stk := logical_Store(r, core_state, stk, OMem(MReg(ESP,4)), OReg(ECX)); call r := instr_Mov(r, ECX, OConst(" + sizeInts + @")); call stk := logical_Store(r, core_state, stk, OMem(MReg(ESP,8)), OReg(ECX)); call alignCall(r.regs[ESP]); {: call r, stk := logical_Call(r, core_state, stk); call r, stk, statics, mems, $commonVars, $gcVars, $absMem, $toAbs, objLayouts := AllocObject(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, abs, " + size + " div 4, " + sizeInts + @" div 4); :} call r := logical_Load(r, core_state, stk, EAX, OMem(MReg(ESP,0))); call mems, $absMem := gcStoreField(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, OMem(MReg(EAX, 4)), OConst(Tag_" + list + "_" + con + @"), r.regs[EAX] - 4, 2, Tag_" + list + "_" + con + @"); "; } string allocImplInt(string list, string cons, string tl, string stackOffset) { return @" call r := logical_Load(r, core_state, stk, EDX, OMem(MReg(ESP," + stackOffset + @"))); call mems, $absMem := gcStoreField(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, OMem(MReg(EAX, Offset_" + list + "_" + tl + @")), OReg(EDX), r.regs[EAX] - 4, 1 + (Offset_" + list + "_" + tl + @" div 4), r.regs[EDX]); "; } string allocImplPtr(string list, string cons, string tl, string stackOffset) { return @" call r, mems := gcLoadStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, EDX, OMem(MReg(ESP," + stackOffset + @")), r.regs[ESP] + " + stackOffset + @"); assert THeapValue(objLayouts, true, $toAbs, r.regs[EDX], frameGet($stacksFrames, r.regs[ESP] + " + stackOffset + @")); call mems, $absMem := gcStoreField(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, OMem(MReg(EAX, Offset_" + list + "_" + tl + @")), OReg(EDX), r.regs[EAX] - 4, 1 + (Offset_" + list + "_" + tl + @" div 4), frameGet($stacksFrames, r.regs[ESP] + " + stackOffset + @")); "; } string allocImpl2(string list, string cons, string destOffset) { return @" call mems, $stacksFrames := gcStoreStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, OMem(MReg(ESP, " + destOffset + @")), OReg(EAX), r.regs[ESP] + " + destOffset + @", abs); heap := Heap(heap.absData[abs := Abs_" + list + @"(data_out)], heap.freshAbs - 1); assert THeapInv($absMem, objLayouts, heap); call r := logical_Add(r, ESP, OConst(12)); {: call r := logical_Ret(r, core_state, stk); return; :} } "; } string allocArrayImpl(int IPSize, string triggers, string destOffset) { return @" implementation Proc_AllocArrayOfInt(my r_old:regs, const my core_state:core_state, linear stk_old:mem, linear statics_old:mem, linear io_old:IOState, linear mems_old:mems, $commonVars_old:commonVars, $gcVars_old:gcVars, $toAbs_old:[int]int, $absMem_old:[int][int]int, $stacksFrames_old:[int]Frames, objLayouts_old:[int]ObjLayout, heap_old:Heap, count:int) returns(my r:regs, linear stk:mem, linear statics:mem, linear io:IOState, linear mems:mems, $commonVars:commonVars, $gcVars:gcVars, $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap, data:ArrayOfInt) { var abs:int; var _mem:[int]int; var obj:int; r := r_old; stk := stk_old; statics := statics_old; io := io_old; mems := mems_old; $commonVars := $commonVars_old; $gcVars := $gcVars_old; $toAbs := $toAbs_old; $absMem := $absMem_old; $stacksFrames := $stacksFrames_old; objLayouts := objLayouts_old; heap := heap_old; assert THeapInv($absMem, objLayouts, heap); assert TV(r.regs[ESP]) && " + triggers + @" && TO(0 - 1) && TO(0 - 2) && TO(0 - 3); call r := logical_Sub(r, ESP, OConst(12)); call heap, abs := freshAbs(?gcHi, $toAbs, heap); call r := instr_Mov(r, EBP, OConst(0)); call r := logical_Load(r, core_state, stk, ECX, OMem(MReg(ESP," + (12 + IPSize) + @"))); call r := instr_AddChecked(r, ECX, OReg(ECX)); call r := instr_AddChecked(r, ECX, OReg(ECX)); call r := instr_AddChecked(r, ECX, OConst(12)); call stk := logical_Store(r, core_state, stk, OMem(MReg(ESP,4)), OReg(ECX)); call stk := logical_Store(r, core_state, stk, OMem(MReg(ESP,8)), OReg(ECX)); call alignCall(r.regs[ESP]); {: call r, stk := logical_Call(r, core_state, stk); call r, stk, statics, mems, $commonVars, $gcVars, $absMem, $toAbs, objLayouts := AllocObject(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, abs, count + 3, count + 3); :} call r := logical_Load(r, core_state, stk, EAX, OMem(MReg(ESP,0))); call r := logical_Load(r, core_state, stk, ECX, OMem(MReg(ESP," + (12 + IPSize) + @"))); call mems, $absMem := gcStoreField(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, OMem(MReg(EAX, 4)), OReg(ECX), r.regs[EAX] - 4, 2, count); call mems, $stacksFrames := gcStoreStack(r, core_state, stk, statics, io, mems, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, OMem(MReg(ESP," + destOffset + ")), OReg(EAX), r.regs[ESP]+" + destOffset + @", abs); data := ArrayOfInt(count, abs); heap := Heap(heap.absData[abs := Abs_ArrayOfInt(data)], heap.freshAbs - 1); assert THeapInv($absMem, objLayouts, heap); call r := logical_Add(r, ESP, OConst(12)); {: call r := logical_Ret(r, core_state, stk); return; :} } "; } string arrayElementPropertiesImpl() { return @" implementation arrayElementProperties(const my core_state:core_state, const linear stk:mem, const linear statics:mem, const linear io:IOState, const linear mems_old:mems, $commonVars:commonVars, $gcVars:gcVars, $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap, index:int, abs:int, obj:int) { assert THeapInv($absMem, objLayouts, heap); assert THeapValue(objLayouts, true, $toAbs, obj, abs); call gcFieldProperties(core_state, stk, statics, io, mems_old, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, obj - 4, 3 + index); } "; } string loadArrayElementImpl() { return @" implementation loadArrayElement(my r_old:regs, const my core_state:core_state, const linear stk:mem, const linear statics:mem, const linear io:IOState, linear mems_old:mems, $commonVars:commonVars, $gcVars:gcVars, $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap, x:int, y:opn_mem, index:int, abs:int, obj:int) returns(my r:regs, linear mems:mems) { assert THeapInv($absMem, objLayouts, heap); assert THeapValue(objLayouts, true, $toAbs, obj, abs); call r, mems := gcLoadField(r_old, core_state, stk, statics, io, mems_old, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, x, y, obj - 4, 3 + index); } "; } string storeArrayElementImpl() { return @" implementation storeArrayElement(const my r:regs, const my core_state:core_state, const linear stk:mem, const linear statics:mem, const linear io:IOState, linear mems_old:mems, $commonVars:commonVars, $gcVars:gcVars, $toAbs:[int]int, $absMem_old:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap, x:opn_mem, y:opn, index:int, val:int, abs:int, obj:int) returns(mems:mems, absMem:[int][int]int) { assert THeapValue(objLayouts, true, $toAbs, obj, abs); assert THeapInv($absMem_old, objLayouts, heap); call mems, absMem := gcStoreField(r, core_state, stk, statics, io, mems_old, $commonVars, $gcVars, $absMem_old, $toAbs, $stacksFrames, objLayouts, x, y, obj - 4, 3 + index, val); assert THeapInv(absMem, objLayouts, heap); } "; } void CompileDatatype2(Type t, TypeApply app) { string dataName = app.AppName(); string suffix = dataName.Substring(((UserDefinedType)t).Name.Length); bool isSeq = dataName.StartsWith("Seq_"); string lemma = isSeq ? "call proc_Seq__Cons__All" + suffix + "();" : ""; TextWriter iwriter = heapIWriter; List ctors = compileDatatypes[app].AsDatatype.Ctors; Func dataIs = c => isSeq ? ("is_" + c + "(data)") : ("data is " + c); string tags = String.Join(" || ", ctors.Select(c => "(r.regs[x] == Tag_" + dataName + "_" + c.Name + " && " + dataIs( Compile_Constructor(t, c.Name, app.typeArgs).AppName()) + ")")); iwriter.WriteLine(loadTagDecl(dataName, tags)); heapWriter.WriteLine("implementation loadTag_" + dataName + "(my r_old:regs, const my core_state:core_state, const linear stk:mem, const linear statics:mem, const linear io:IOState, linear mems_old:mems, $commonVars:commonVars, $gcVars:gcVars, $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap, x:int, y:opn_mem, data:" + dataName + ", abs:int, obj:int)"); heapWriter.WriteLine(" returns(my r:regs, linear mems:mems)"); heapWriter.WriteLine("{"); heapWriter.WriteLine(" assert THeapValue(objLayouts, true, $toAbs, obj, abs);"); heapWriter.WriteLine(" assert THeapInv($absMem, objLayouts, heap);"); heapWriter.WriteLine(" " + lemma); heapWriter.WriteLine(" call r, mems := gcLoadField(r_old, core_state, stk, statics, io, mems_old,"); heapWriter.WriteLine(" $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts,"); heapWriter.WriteLine(" x, y, obj - 4, 2);"); heapWriter.WriteLine("}"); foreach (var ctor in ctors) { var ints = ctor.Formals.Where(x => !IsPtrType(app.AppType(x.Type))).ToList(); var ptrs = ctor.Formals.Where(x => IsPtrType(app.AppType(x.Type))).ToList(); var sorted = ints.Concat(ptrs).ToList(); string ctorName = Compile_Constructor(t, ctor.Name, app.typeArgs).AppName(); string cons = isSeq ? ("_" + ctorName) : ctorName; string parms = String.Join(", ", ctor.Formals.Select( c => "arg_" + c.Name + ":" + TypeString(app.AppType(c.Type)))); string args = String.Join(", ", ctor.Formals.Select(c => "arg_" + c.Name)); int argRetSize = 4 + 4 * Math.Max(ints.Count, ptrs.Count); heapIWriter.WriteLine("const stack_size__DafnyCC__Proc_Alloc_" + ctorName + ":int := 256;"); iwriter.WriteLine(allocDecl1( dataName, ctorName, cons, parms, args, argRetSize.ToString())); string triggers = (IPSize == 8) ? String.Format("{0} && {1}", GcTO64(1), GcTO(3)) : GcTO(1); for (int i = 0; i < ints.Count; i++) { string val = "stk_old.map[r_old.regs[ESP] + " + (IPSize + 4 * i) + "]"; iwriter.WriteLine("requires " + CompileBase.IntEqTyped(app.AppType(ints[i].Type), "arg_" + ints[i].Name, val) + ";"); triggers += String.Format(" && {0}", (IPSize == 8 ? StackTO64(i + 1): StackTO(i + 1))); } for (int i = 0; i < ptrs.Count; i++) { iwriter.WriteLine("requires StackAbsSlot(heap_old, $stacksFrames_old, r_old.regs[ESP] + " + (IPSize + 4 + 4 * i) + " + stackGcOffset) == Abs_" + TypeString(app.AppType(ptrs[i].Type)) + "(arg_" + ptrs[i].Name + ");"); triggers += String.Format(" && {0}", (IPSize == 8 ? GcTO64(i + 2): GcTO(i + 2))); } iwriter.WriteLine(allocDecl2( dataName, cons, PreserveHeap(minVerify), args)); heapWriter.WriteLine(allocImpl1( dataName, ctor.Name, ctorName, cons, parms, args, (12 + 4 * sorted.Count).ToString(), (12 + 4 * ints.Count).ToString(), triggers, lemma)); for (int i = 0; i < ints.Count; i++) { heapWriter.WriteLine(allocImplInt( dataName, ctorName, ints[i].Name, (12 + IPSize + 4 * i).ToString())); } for (int i = 0; i < ptrs.Count; i++) { heapWriter.WriteLine(allocImplPtr( dataName, ctorName, ptrs[i].Name, (RegAlloc.stackGcOffset + 16 + IPSize + 4 * i).ToString() + "/* stackGcOffset + 16 + IPSize + " + (4 * i) + " */")); } heapWriter.WriteLine(allocImpl2( dataName, ctorName, (RegAlloc.stackGcOffset + 12 + IPSize).ToString() + "/* stackGcOffset + 12 + IPSize */")); for (int i = 0; i < sorted.Count; i++) { var formal = sorted[i]; iwriter.WriteLine(loadField( dataName, dataIs(ctorName), formal.Name)); if (IsPtrType(app.AppType(formal.Type))) { iwriter.WriteLine("ensures HeapAbsData(heap, $absMem_old[abs][" + (3 + i) + "]) == Abs_" + TypeString(app.AppType(formal.Type)) + "(" + formal.Name + (isSeq ? "_" : "#") + ctorName + "(data));"); iwriter.WriteLine("ensures HeapValue(objLayouts_old, true, $toAbs_old, r.regs[x], $absMem_old[abs][" + (3 + i) + "]);"); if (DafnySpec.IsArrayType(app.AppType(formal.Type))) { iwriter.WriteLine("ensures $absMem_old[abs][" + (3+i) + "] == " + formal.Name + "#" + ctorName + "(data).arrAbs;"); } } else { iwriter.WriteLine("ensures " + CompileBase.IntEqTyped( app.AppType(formal.Type), formal.Name + (isSeq ? "_" : "#") + ctorName + "(data)", "r.regs[x]") + ";"); } heapWriter.WriteLine("implementation loadField_" + dataName + "_" + formal.Name + "(my r_old:regs, const my core_state:core_state, const linear stk:mem, const linear statics:mem, const linear io:IOState, linear mems_old:mems, $commonVars:commonVars, $gcVars:gcVars, $toAbs:[int]int, $absMem:[int][int]int, $stacksFrames:[int]Frames, objLayouts:[int]ObjLayout, heap:Heap, x:int, y:opn_mem, data:" + dataName + ", abs:int, obj:int)"); heapWriter.WriteLine(" returns(my r:regs, linear mems:mems)"); heapWriter.WriteLine("{"); heapWriter.WriteLine(" assert THeapValue(objLayouts, true, $toAbs, obj, abs);"); heapWriter.WriteLine(" assert THeapInv($absMem, objLayouts, heap);"); heapWriter.WriteLine(" call r, mems := gcLoadField(r_old, core_state, stk, statics, io, mems_old, $commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts,"); heapWriter.WriteLine(" x, y, obj - 4, " + (3 + i) + ");"); heapWriter.WriteLine(" assert THeapValue(objLayouts, true, $toAbs, r.regs[x], $absMem[abs][" + (3 + i) + "]);"); heapWriter.WriteLine("}"); } } } string heapDecl() { return @" type Heap = Heap(absData:[int]AbsData, freshAbs:int); function HeapAbsData(heap:Heap, abs:int):AbsData { heap.absData[abs] } function StackAbsSlot(heap:Heap, stacksFrames:[int]Frames, ptr:int):AbsData { heap.absData[frameGet(stacksFrames, ptr)] } function HeapValue(objLayouts:[int]ObjLayout, isPtr:bool, rev:[int]int, val:int, abs:int):bool; function HeapInv(absMem:[int][int]int, objLayouts:[int]ObjLayout, heap:Heap):bool; atomic ghost procedure initHeap(absMem:[int][int]int, objLayouts:[int]ObjLayout) returns(heap:Heap); requires (forall i:int::{objLayouts[i]} objLayouts[i] == NoObjLayout()); ensures HeapInv(absMem, objLayouts, heap); atomic procedure heapLoadStack(my r__BEAT__old:regs,const my core_state:core_state,const linear stk:mem,const linear statics:mem,const linear io:IOState,linear mems__BEAT__old:mems,$commonVars:commonVars,$gcVars:gcVars,$absMem:[int][int]int,$toAbs:[int]int,$stacksFrames:[int]Frames,objLayouts:[int]ObjLayout,x:int,y:opn_mem,ptr:int) returns(my r:regs,linear mems:mems); requires isStack($S); requires NucleusInv(objLayouts,$S,$toAbs,$absMem,$commonVars,$gcVars,me,init,stk,statics,core_state,ptMem,mems__BEAT__old,$stacksFrames,io); requires StackLo($S)<=ptr&&ptr objLayouts[i] == NoObjLayout()) && (forall i:int::{absMem[i]}{heap.absData[i]} heap.absData[i] != AbsNone() ==> !word(i)) && (forall i:int::{heap.absData[i]} i <= heap.freshAbs ==> heap.absData[i] == AbsNone()) && (forall i:int::{absMem[i]}{heap.absData[i]} HeapWordInv(heap.absData, objLayouts[i], absMem[i], heap.absData[i], i)) } atomic ghost procedure freshAbs(k:int, $toAbs:[int]int, heap_old:Heap) returns(heap:Heap, abs:int) requires (forall i:int::{$toAbs[i]} k <= i && i < ?gcHi ==> heap_old.freshAbs < $toAbs[i]); ensures heap == Heap(heap_old.absData, heap.freshAbs); ensures abs == heap.freshAbs; ensures abs < heap_old.freshAbs; ensures (forall i:int::{$toAbs[i]} 0 <= i && i < ?gcHi ==> abs < $toAbs[i]); { heap := Heap(heap_old.absData, heap_old.freshAbs - 1); if (k > 0) { if (heap.freshAbs >= $toAbs[k - 1]) { heap := Heap(heap.absData, $toAbs[k - 1] - 1); } call heap, abs := freshAbs(k - 1, $toAbs, heap); } abs := heap.freshAbs; } implementation initHeap(absMem:[int][int]int, objLayouts:[int]ObjLayout) returns(heap:Heap) { heap := Heap((lambda i:int::AbsNone()), NO_ABS - 1); assert THeapInv(absMem, objLayouts, heap); } implementation heapLoadStack(my r__BEAT__old:regs,const my core_state:core_state,const linear stk:mem,const linear statics:mem,const linear io:IOState,linear mems__BEAT__old:mems,$commonVars:commonVars,$gcVars:gcVars,$absMem:[int][int]int,$toAbs:[int]int,$stacksFrames:[int]Frames,objLayouts:[int]ObjLayout,x:int,y:opn_mem,ptr:int) returns(my r:regs,linear mems:mems) { call r, mems := gcLoadStack(r__BEAT__old,core_state,stk,statics,io,mems__BEAT__old,$commonVars,$gcVars,$absMem,$toAbs,$stacksFrames,objLayouts,x,y,ptr); assert THeapValue(objLayouts,true,$toAbs,(r.regs)[x],Abss#Frames($stacksFrames[$S])[ptr]); } implementation heapStoreStack(const my r:regs,const my core_state:core_state,const linear stk:mem,const linear statics:mem,const linear io:IOState,linear mems__BEAT__old:mems,$commonVars:commonVars,$gcVars:gcVars,$absMem:[int][int]int,$toAbs:[int]int,$stacksFrames__BEAT__old:[int]Frames,objLayouts:[int]ObjLayout,x:opn_mem,y:opn,ptr:int,abs:int) returns(linear mems:mems,$stacksFrames:[int]Frames) { assert THeapValue(objLayouts,true,$toAbs,Eval(r,y),abs); call mems, $stacksFrames := gcStoreStack(r,core_state,stk,statics,io,mems__BEAT__old,$commonVars,$gcVars,$absMem,$toAbs,$stacksFrames__BEAT__old,objLayouts,x,y,ptr,abs); } "; } string heapWordInvArray() { return @" function HeapWordInvArray(absData:[int]AbsData, objLayout:ObjLayout, wordMem:[int]int, data:ArrayOfInt, abs:int):bool { data.arrCount >= 0 && objLayout == ObjLayout(3 + data.arrCount, 3 + data.arrCount) && wordMem[2] == data.arrCount && data.arrAbs == abs } "; } string StackTO(int offset) { return String.Format("TO({0})", offset); } string StackTO64(int offset) { return String.Format("{0} && {1}", StackTO(offset), StackTO(offset + 1)); } string GcTO(int offset) { return String.Format("TO({0} + {1}) /*stackGcOffsetWord + {1} */", RegAlloc.stackGcOffset / 4, offset); } string GcTO64(int offset) { return String.Format("{0} && {1}", GcTO(offset), GcTO(offset + 1)); } void CompileDatatypes() { heapIWriter.WriteLine(" function Arr_Index(absMem:[int][int]int, arr:ArrayOfInt, i:int):int { absMem[arr.arrAbs][3 + i] }"); heapIWriter.WriteLine(" function Arr_Length(arr:ArrayOfInt):int { if arr.arrCount >= 0 then arr.arrCount else 0 }"); heapIWriter.WriteLine(" function fun_INTERNAL__array__elems(absMem:[int][int]int, arr:ArrayOfInt):[int]int { absMem[arr.arrAbs] }"); heapIWriter.WriteLine(" function fun_INTERNAL__array__elems__index(arr:[int]int, k:int):int { arr[3 + k] }"); heapIWriter.WriteLine(" function fun_INTERNAL__array__elems__update(arr:[int]int, k:int, v:int):[int]int { arr[3 + k := v] }"); heapIWriter.WriteLine(" function fun_INTERNAL__array__update(absMem:[int][int]int, arr:ArrayOfInt, k:int, v:int):[int][int]int { absMem[arr.arrAbs := absMem[arr.arrAbs][3 + k := v]] }"); heapIWriter.WriteLine(allocDeclArray(IPSize, PreserveHeap(minVerify))); heapIWriter.WriteLine(arrayElementProperties()); heapIWriter.WriteLine(loadArrayElement()); heapIWriter.WriteLine(storeArrayElement()); heapWriter.WriteLine(heapWordInvArray()); for (int i = 0; i < compileDatatypeList.Count; i++) { var app = compileDatatypeList[i]; CompileDatatype1(compileDatatypes[app], app); } heapIWriter.WriteLine("type AbsData = AbsNone() | Abs_ArrayOfInt(arr:ArrayOfInt) | " + String.Join(" | ", compileDatatypes.Select(d => d.Key.AppName()) .Select(x => "Abs_" + x + "(" + x + ":" + x + ")")) + ";"); heapWriter.WriteLine("function HeapWordInv(absData:[int]AbsData, objLayout:ObjLayout, wordMem:[int]int, data:AbsData, abs:int):bool"); heapWriter.WriteLine("{"); heapWriter.WriteLine(" true"); heapWriter.WriteLine(" && (data is Abs_ArrayOfInt ==> HeapWordInvArray(absData, objLayout, wordMem, data.arr, abs))"); foreach (var d in compileDatatypes) { string name = d.Key.AppName(); heapWriter.WriteLine(" && (data is Abs_" + name + " ==> HeapWordInv_" + name + "(absData, objLayout, wordMem, data." + name + "))"); } heapWriter.WriteLine("}"); heapIWriter.WriteLine(heapDecl()); heapWriter.WriteLine(heapProcs()); heapWriter.WriteLine(allocArrayImpl(IPSize, String.Format("{0} && {1}", (IPSize == 8 ? StackTO64(1): StackTO(1)), (IPSize == 8 ? GcTO64(1): GcTO(1))), (RegAlloc.stackGcOffset + 12 + IPSize).ToString())); heapWriter.WriteLine(arrayElementPropertiesImpl()); heapWriter.WriteLine(loadArrayElementImpl()); heapWriter.WriteLine(storeArrayElementImpl()); compileDatatypes.ToList().ForEach(p => CompileDatatype2(p.Value, p.Key)); } public override void AddDatatypeLemmas(UserDefinedType t, TypeApply apply) { switch (t.Name) { case "Seq": { List lemmaApps = new List(); Dictionary loopLemmas = new Dictionary(); foreach (string lemmaName in seqLemmas) { Method lemma = FindMethod(lemmaName); var a = Compile_Method(lemma, apply.typeArgs); lemmaApps.Add(a); if (Attributes.Contains(lemma.Attributes, "loop_lemma")) { loopLemmas.Add(a.AppName(), ""); } } Type elementType = (t.TypeArgs.Count == 1) ? t.TypeArgs[0] : null; lemmaApps.ForEach(a => lemmas.Add(new LemmaCall("Seq", elementType, "call " + ProcName(true, SimpleName(a.AppName())) + "();", loopLemmas.ContainsKey(a.AppName())))); break; } } } public override CompileMethodGhost NewCompileMethod(DafnySpec dafnySpec, Method method, TypeApply typeApply, TextWriter writer, TextWriter iwriter, string moduleName, List imports) { return new CompileMethod(dafnySpec, method, typeApply, writer, iwriter, moduleName, imports); } public override void Compile_FunctionAsMethod(Function function, Dictionary typeArgs, Dictionary substArgs) { var tok = function.tok; if (Attributes.Contains(function.Attributes, "CompiledSpec")) { string specName = function.Name.Substring("CompiledSpec_".Length); function = FindFunction(specName); } bool hidden = Attributes.Contains(function.Attributes, "opaque"); Formal result = new Formal(function.tok, "__result", function.ResultType, false, function.IsGhost); string funName = function.Name; string name = FunName(DafnySpec.SimpleSanitizedName(function)); FunctionCallExpr call = new FunctionCallExpr(tok, name, new ThisExpr(tok), tok, function.Formals.ConvertAll(f => (Expression) MakeIdentifierExpr(f.Name, f.Type, f.IsGhost))); call.Function = function; call.TypeArgumentSubstitutions = typeArgs; call.Type = function.ResultType; CallStmt revealCall = null; if (hidden) { var selectExpr = new MemberSelectExpr(tok, new ThisExpr(tok), "reveal_" + function.Name); selectExpr.Member = FindMethod(selectExpr.MemberName); // Manually resolve here selectExpr.TypeApplication = new List(); // Manually resolve here selectExpr.Type = new InferredTypeProxy(); // Manually resolve here revealCall = new CallStmt(tok, tok, new List(), selectExpr, new List()); revealCall.IsGhost = true; ClassDecl cls = (ClassDecl)function.EnclosingClass; string fullName = "#" + function.Name + "_FULL"; function = (Function)cls.Members.Find(m => m.Name == fullName); if (function == null) { throw new Exception("internal error: could not find function " + fullName); } substArgs = new Dictionary(); function.TypeArgs.ForEach(t => substArgs.Add(t.Name, t)); typeArgs = typeArgs.ToDictionary(p => substArgs[p.Key.Name], p => p.Value); } Expression funBody = function.Body; BlockStmt body = null; if (funBody != null) { ReturnStmt retStmt = new ReturnStmt(tok, tok, new List() { new ExprRhs(funBody) }); body = new BlockStmt(tok, tok, hidden ? (new List() { revealCall, retStmt }) : (new List() { retStmt })); } List ens = new List { MakeBinaryExpr(BinaryExpr.Opcode.Eq, BinaryExpr.ResolvedOpcode.EqCommon, Type.Bool, MakeIdentifierExpr("__result", function.ResultType, function.IsGhost), call) }.Concat(function.Ens).ToList(); Method method = new Method(tok, funName, function.IsStatic, function.IsGhost, function.TypeArgs, function.Formals, new List { result }, function.Req.ConvertAll(e => new MaybeFreeExpression(e)), new Specification(new List(), null), ens.ConvertAll(e => new MaybeFreeExpression(e)), function.Decreases, body, function.Attributes, function.SignatureEllipsis); method.EnclosingClass = function.EnclosingClass; Compile_Method(method, typeArgs); } public Tuple GetSeqBuildMethod(Type t, SeqTree tree, List elemDimensions) { if (elemDimensions.Count == 0) { return GetSeqMethod(t, "seq_Empty"); } if (elemDimensions.Count == 2 && elemDimensions[0] && elemDimensions[1]) { return GetSeqMethod(t, "seq_Append"); } string op = "seq_" + SeqTree.TreeName(tree); DatatypeDecl seqDecl = FindDatatype("Seq"); var tok = new Bpl.Token(0, 0); tok.filename = @"!\Seq.dfy"; TypeApply tApp = Compile_SeqType((SeqType)t); Type dataType = new UserDefinedType(tok, "Seq", seqDecl, new List { ((SeqType)t).Arg }); Type elemType = ((SeqType)t).Arg; Func idExpr = (x, typ) => { var e = new IdentifierExpr(tok, x); e.Type = typ; e.Var = new LocalVariable(tok, tok, x, typ, false); return e; }; Func,FunctionCallExpr> seqCall = (x, args) => { var seqOp = GetSeqOperation(t, x); FunctionCallExpr callExpr = new FunctionCallExpr( tok, "Seq_Empty", new ThisExpr(tok), tok, args); callExpr.Function = seqOp.Item1; callExpr.TypeArgumentSubstitutions = seqOp.Item2.typeArgs; return callExpr; }; Expression empty = seqCall("Seq_Empty", new List {}); int varCount = 0; Func resultRec = null; resultRec = (subtree) => { if (subtree == null) { return idExpr("s" + (varCount++), dataType); } if (subtree.buildCount >= 0) { Expression build = empty; for (int i = 0; i < subtree.buildCount; i++) { build = seqCall("Seq_Build", new List { build, idExpr("a" + (varCount++), elemType) }); } return build; } else { return seqCall("Seq_Append", new List { resultRec(subtree.left), resultRec(subtree.right) }); } }; Expression result = resultRec(tree); Expression post = seqCall("Seq_Equal", new List { idExpr("s", dataType), result }); List stmts = new List(); for (int i = elemDimensions.Count; i > 0;) { bool isFirst = (i == elemDimensions.Count); i--; if (elemDimensions[i]) { if (isFirst) { stmts.Add(new AssignStmt(tok, tok, idExpr("s", dataType), new ExprRhs(idExpr("s" + i, dataType)))); } else { // s := seq_Append(s9, s); var selectExpr = new MemberSelectExpr(tok, new ThisExpr(tok), "seq_Append"); selectExpr.Member = FindMethod(selectExpr.MemberName); // Manually resolve here selectExpr.TypeApplication = new List() { elemType }; // Manually resolve here selectExpr.Type = new InferredTypeProxy(); // Manually resolve here CallStmt callStmt = new CallStmt(tok, tok, new List {idExpr("s", dataType)}, selectExpr, new List { idExpr("s" + i, dataType), idExpr("s", dataType) }); stmts.Add(callStmt); } } else { if (isFirst) { DatatypeValue nil = new DatatypeValue(tok, "Seq", "Nil", new List() {}); nil.Type = dataType; nil.InferredTypeArgs = new List { elemType }; nil.Ctor = seqDecl.Ctors[0]; Util.Assert(nil.Ctor.Name == "Seq_Nil"); stmts.Add(new AssignStmt(tok, tok, idExpr("s", dataType), new ExprRhs(nil))); } // lemma_Seq_Cons(ai, s); var selectExpr = new MemberSelectExpr(tok, new ThisExpr(tok), "lemma_Seq_Cons"); selectExpr.Member = FindMethod(selectExpr.MemberName); // Manually resolve here selectExpr.TypeApplication = new List() { elemType }; // Manually resolve here selectExpr.Type = new InferredTypeProxy(); // Manually resolve here CallStmt callStmt = new CallStmt(tok, tok, new List {}, selectExpr, new List { idExpr("a" + i, elemType), idExpr("s", dataType) }); callStmt.IsGhost = true; stmts.Add(callStmt); DatatypeValue cons = new DatatypeValue(tok, "Seq", "Cons", new List() { idExpr("a" + i, elemType), idExpr("s", dataType) }); cons.Type = dataType; cons.InferredTypeArgs = new List { elemType }; cons.Ctor = seqDecl.Ctors[1]; Util.Assert(cons.Ctor.Name == "Seq_Cons"); stmts.Add(new AssignStmt(tok, tok, idExpr("s", dataType), new ExprRhs(cons))); } } BlockStmt body = new BlockStmt(tok, tok, stmts); List ins = new List(); for (int i = 0; i < elemDimensions.Count; i++) { bool isSeq = elemDimensions[i]; ins.Add(new Formal(tok, (isSeq ? "s" : "a") + i, isSeq ? dataType : elemType, true, false)); } List outs = new List { new Formal(tok, "s", dataType, false, false) }; List reqs = new List(); List enss = new List { new MaybeFreeExpression(post) }; Specification mods = new Specification(new List(), null); Specification decs = new Specification(new List(), null); Attributes attrs = new Attributes("dafnycc_conservative_seq_triggers", new List(), null); Method m = new Method(tok, op, true, false, tApp.typeParams, ins, outs, reqs, mods, enss, decs, body, attrs, tok); m.EnclosingClass = GetSeqMethod(t, "seq_Append").Item1.EnclosingClass; return Tuple.Create(m, Compile_Method(m, tApp.typeArgs)); } void addAxioms(TextWriter sw, IEnumerable axiomModules) { foreach (string axiomModule in axiomModules) { sw.WriteLine(String.Format("//", axiomModule)); } } public Dictionary CompileCodeStart(DafnyCC_Options options, IList files) { IEnumerable axioms = new string[] { "Base_axioms", "Word_axioms", "Memory_axioms", "Assembly_axioms", "Io_axioms" }; Dictionary allModules = CompileSpecStart(options, files); relational = options.relational; x64 = options.x64; IPSize = x64 ? 8 : 4; useFramePointer = options.useFramePointer; framePointerCount = useFramePointer ? 1 : 0; heapWriter = new StreamWriter(Path.Combine(outDir, "Heap"+ImpBasmExtn)); heapIWriter = new StreamWriter(Path.Combine(outDir, "Heap"+IfcBasmExtn)); checkedWriter = new StreamWriter(Path.Combine(outDir, "Checked"+ImpBasmExtn)); checkedIWriter = new StreamWriter(Path.Combine(outDir, "Checked"+IfcBasmExtn)); List checkedImports = new List { "Trusted" }; checkedIWriter.WriteLine("module interface Checked"); WriteInterfaceImports(checkedIWriter, GatherAllImports(checkedImports)); checkedIWriter.WriteLine("{"); checkedIWriter.WriteLine("type ArrayOfInt = ArrayOfInt(arrCount:int, arrAbs:int);"); WriteImplementationHeader(checkedWriter, "Checked", new List() { "Trusted" }); List heapImports = new List { "Trusted", "Checked" }; heapIWriter.WriteLine("module interface Heap"); WriteInterfaceImports(heapIWriter, GatherAllImports(heapImports)); addAxioms(heapWriter, axioms); heapIWriter.WriteLine("{"); WriteImplementationHeader(heapWriter, "Heap", heapImports); List seqImports = new List { "Trusted", "Checked", "Heap" }; seqWriter = new StreamWriter(Path.Combine(outDir, "Seq"+ImpBasmExtn)); seqIWriter = new StreamWriter(Path.Combine(outDir, "Seq"+IfcBasmExtn)); seqIWriter.WriteLine("module interface Seq"); WriteInterfaceImports(seqIWriter, GatherAllImports(seqImports)); seqIWriter.WriteLine("{"); addAxioms(seqWriter, axioms); WriteImplementationHeader(seqWriter, "Seq", seqImports); return allModules; } public void CompileCodeEnd(DafnyCC_Options options) { checkedIWriter.WriteLine("}"); checkedWriter.WriteLine("}"); checkedIWriter.Close(); checkedWriter.Close(); heapIWriter.WriteLine("}"); heapWriter.WriteLine("}"); seqIWriter.WriteLine("}"); seqWriter.WriteLine("}"); seqIWriter.Close(); seqWriter.Close(); if (outDir == null) { mainWriter.WriteLine("}"); } heapWriter.Close(); heapIWriter.Close(); CompileSpecEnd(); } public void CompileCode(DafnyCC_Options options, IList files) { Dictionary allModules = CompileCodeStart(options, files); Program program; string errors = Microsoft.Dafny.Main.ParseCheck( allModules.Values.ToList(), "DAFNYCC_PROGRAM", out program); if (errors != null) { throw new Exception(errors); } Util.DebugWriteLine(program); DeclareProgram(program); CompileProgram(program); CompileDatatypes(); CompileCodeEnd(options); } } ================================================ FILE: ironclad-apps/tools/DafnyCC/DafnyCC.csproj ================================================  Debug AnyCPU {5EADF212-4CF1-4883-8F35-019F9550BA0A} Exe Properties DafnyCC dafnycc v4.5 512 publish\ true Disk false Foreground 7 Days false false true 0 1.0.0.%2a false false true AnyCPU true full false bin\ DEBUG;TRACE prompt 4 AnyCPU pdbonly true bin\ TRACE prompt 4 DafnyCC False ..\Dafny\Basetypes.dll False ..\Dafny\Core.dll False ..\Dafny\DafnyPipeline.dll False ..\Dafny\ParserHelper.dll False Microsoft .NET Framework 4.5 %28x86 and x64%29 true False .NET Framework 3.5 SP1 Client Profile false False .NET Framework 3.5 SP1 false CodeContractsExtender.dll Always Provers.SMTLib.dll Always VCGeneration.dll Always z3.exe Always DafnyPrelude.dfy Always ================================================ FILE: ironclad-apps/tools/DafnyCC/DafnyCC.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0.30501.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DafnyCC", "DafnyCC.csproj", "{5EADF212-4CF1-4883-8F35-019F9550BA0A}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {5EADF212-4CF1-4883-8F35-019F9550BA0A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5EADF212-4CF1-4883-8F35-019F9550BA0A}.Debug|Any CPU.Build.0 = Debug|Any CPU {5EADF212-4CF1-4883-8F35-019F9550BA0A}.Release|Any CPU.ActiveCfg = Release|Any CPU {5EADF212-4CF1-4883-8F35-019F9550BA0A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: ironclad-apps/tools/DafnyCC/Makefile ================================================ # # Copyright (c) 2007 Microsoft Corporation. All rights reserved. # MSBUILD=C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe BIN = ..\..\bin_tools\dafnycc SRC = . SPC = ..\DafnySpec DAFNYCC_SOURCES = \ $(SPC)\Util.cs \ $(SPC)\RtlGhost.cs \ $(SRC)\Rtl.cs \ $(SRC)\Analyze.cs \ $(SRC)\RegAlloc.cs \ $(SPC)\Compile.cs \ $(SPC)\CompileField.cs \ $(SPC)\CompileFunction.cs \ $(SPC)\CompileMethodGhost.cs \ $(SRC)\CompileMethod.cs \ $(SPC)\DafnySpec.cs \ $(SRC)\DafnyCC.cs \ all: dafnycc dafnycc: $(BIN) $(BIN)\dafnycc.exe $(BIN): md $(BIN) $(BIN)\dafnycc.exe: $(DAFNYCC_SOURCES) DafnyCC.sln $(MSBUILD) DafnyCC.sln ================================================ FILE: ironclad-apps/tools/DafnyCC/RegAlloc.cs ================================================ using System; using System.Linq; using System.Collections.Generic; using System.Collections.ObjectModel; using Microsoft.Dafny; using Bpl = Microsoft.Boogie; using System.Numerics; using Type = Microsoft.Dafny.Type; public class RegAlloc : Analyze { public const int stackGcOffset = 0x111000; DafnySpec dafnySpec; internal CompileMethod compileMethod; public readonly List regs; public readonly List initAssign; public readonly List retAssign; public readonly Dictionary inInts = new Dictionary(); public readonly Dictionary inPtrs = new Dictionary(); public readonly Dictionary outInts = new Dictionary(); public readonly Dictionary outPtrs = new Dictionary(); public readonly Dictionary spillInts = new Dictionary(); public readonly Dictionary spillPtrs = new Dictionary(); public readonly Dictionary varTypes = new Dictionary(); public int callIntArgs = 0; public int callPtrArgs = 0; public int callIntRets = 0; public int callPtrRets = 0; List> assigned; public int IPSize; public int IPWords; public RegAlloc( DafnySpec dafnySpec, CompileMethod compileMethod, List inVars, List outVars, List inIntList, List outIntList, List inPtrList, List outPtrList, Dictionary allVars, List stmts): base(inVars, outVars, stmts) { this.dafnySpec = dafnySpec; this.compileMethod = compileMethod; IPSize = ((DafnyCC)dafnySpec).IPSize; IPWords = IPSize/4; if (compileMethod.dafnycc.useFramePointer) { regs = new List(new string[] { "EAX", "ECX", "EDX", "EBX", "ESI", "EDI" }); } else { regs = new List(new string[] { "EAX", "ECX", "EDX", "EBX", "ESI", "EDI", "EBP" }); } initAssign = new List(new string[regs.Count]); retAssign = new List(new string[regs.Count]); for (int i = 0; i < inIntList.Count; i++) { inInts.Add(compileMethod.GhostVar(inIntList[i].Name), 4 * i); } for (int i = 0; i < outIntList.Count; i++) { outInts.Add(compileMethod.GhostVar(outIntList[i].Name), 4 * i); } for (int i = 0; i < inPtrList.Count; i++) { string x = compileMethod.GhostVar(inPtrList[i].Name); inPtrs.Add(x, 4 * i); } for (int i = 0; i < outPtrList.Count; i++) { string x = compileMethod.GhostVar(outPtrList[i].Name); outPtrs.Add(x, 4 * i); } allVars.ToList().ForEach(p => varTypes.Add(p.Key, p.Value.type)); /* for now, just use the stack for simplicity if (inVars.Count >= 1) { initAssign[regs.IndexOf("ECX")] = inVars[0]; } if (inVars.Count >= 2) { initAssign[regs.IndexOf("EDX")] = inVars[1]; } if (inVars.Count >= 3) { initAssign[regs.IndexOf("EBX")] = inVars[2]; } if (inVars.Count >= 4) { throw new Exception("not implemented: more than two arguments"); } if (outVars.Count >= 1) { retAssign[regs.IndexOf("EAX")] = outVars[0]; } if (outVars.Count >= 2) { retAssign[regs.IndexOf("ESI")] = outVars[1]; } if (outVars.Count >= 3) { throw new Exception("not implemented: more than two return values"); } */ } public static string Reg(string s) { return "r.regs[" + s + "]"; } public string TypeString(Type t) { return dafnySpec.TypeString(t); } public bool IsPtr(string x) { return CompileMethod.IsPtrType(varTypes[x]); } public bool IsArray(string x) { return DafnySpec.IsArrayType(varTypes[x]); } public int ArgsRetsCount() { return Math.Max(callIntArgs + callIntRets, callPtrArgs + callPtrRets); } public int LocalsCount() { return Math.Max(spillInts.Count, spillPtrs.Count); } public int InsOutsCount() { return Math.Max(inInts.Count + outInts.Count, inPtrs.Count + outPtrs.Count); } public int FrameCount() { return ArgsRetsCount() + LocalsCount(); } public int FrameVisibleCount() { return ArgsRetsCount() + LocalsCount() + IPWords + InsOutsCount() + compileMethod.dafnycc.framePointerCount; } public int LocalsOffset() { return ArgsRetsCount() * 4; } public int OutsOffset() { return LocalsOffset() + 4 * LocalsCount() + /*return address*/ IPSize + 4 * compileMethod.dafnycc.framePointerCount; } public int InIntsOffset() { return OutsOffset() + 4 * outInts.Count; } public int InPtrsOffset() { return OutsOffset() + 4 * outPtrs.Count; } private string StackOMem(int offset) { return "OMem(MReg(ESP, " + offset + "))"; } private string StackOMemPtr(int offset) { return StackOMem(offset + stackGcOffset); } private RtlExp Spill(string x) { Func offset; var isPtr = IsPtr(x); if (inInts.ContainsKey(x)) { offset = () => InIntsOffset() + inInts[x]; } else if (outInts.ContainsKey(x)) { offset = () => OutsOffset() + outInts[x]; } else if (inPtrs.ContainsKey(x)) { offset = () => InPtrsOffset() + inPtrs[x]; } else if (outPtrs.ContainsKey(x)) { offset = () => OutsOffset() + outPtrs[x]; } else { Util.DebugWriteLine(" *** SPILL: " + x); var spilled = isPtr ? spillPtrs : spillInts; if (!spilled.ContainsKey(x)) { spilled.Add(x, spilled.Count * 4); } offset = () => LocalsOffset() + spilled[x]; } return new RtlExpComputed(e => isPtr ? StackOMemPtr(offset()) : StackOMem(offset())); } static int debugTag = 0; public List Alloc() { assigned = new List>(new List[stmts.Count]); Func slotMem = offset => "stk.map[r.regs[ESP] + " + offset + "]"; Func spillLoc = e => "EvalPtr(r, " + e.AsOperand() + ")"; Func spillMem = e => "stk.map[" + spillLoc(e) + "]"; Stack workList = new Stack(); List newStmts = new List(); Action move = (string dest, string src) => { if (dest != src) { newStmts.Add(new RtlInst("instr_Mov", new RtlVar[] { new RtlVar(dest, false) }, new RtlVar[0], new RtlExp[] { new RtlVar(src, false) }, false) .WithComment("regalloc_move:: " + dest + " := " + src)); } }; Action sLoad = (string dest, RtlExp src, string var) => { int dbgTag = debugTag++; Util.DebugWriteLine("sLoad: dest = " + dest + " " + dbgTag); newStmts.Add(new RtlStmtComputed((inst => { var eDst = inst.args[0].e; string opPtr = inst.args[1].e.AsOperand(); string ptr = "EvalPtr(r, " + opPtr + ")"; return IsPtr(var) ? "call r, mems := heapLoadStack(r, core_state, stk, statics, io, mems, " + "$commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, " + eDst + ", " + opPtr + ", " + ptr + ");" + Environment.NewLine + " " + var + "__abs := frameGet($stacksFrames, " + ptr + ");" : "call r := logical_Load(r, core_state, stk, " + eDst + ", " + opPtr + ");"; }), new RtlArg[] { new RtlArg(true, false, new RtlVar(dest, false)), new RtlArg(true, false, src) }, false) .WithComment(() => "regalloc_stack_load:: " + dest + " := " + src + " // var = " + var + " " + dbgTag)); }; Action sStore = (RtlExp dest, string src, string var) => { newStmts.Add(new RtlStmtComputed((inst => { string opPtr = inst.args[0].e.AsOperand(); string opVal = inst.args[1].e.AsOperand(); string ptr = "EvalPtr(r, " + opPtr + ")"; string val = "Eval(r, " + opVal + ")"; return IsPtr(var) ? "call mems, $stacksFrames := " + "heapStoreStack(r, core_state, stk, statics, io, mems, " + "$commonVars, $gcVars, $absMem, $toAbs, $stacksFrames, objLayouts, " + opPtr + ", " + opVal + ", " + ptr + ", " + var + "__abs);" : "call stk := logical_Store(r, core_state, stk, " + opPtr + ", " + opVal + ");"; }), new RtlArg[] { new RtlArg(true, false, dest), new RtlArg(true, false, new RtlVar(src, false)) }, false) .WithComment(() => "regalloc_stack_store:: " + dest + " := " + src + " // var = " + var)); }; workList.Push(0); while (workList.Count > 0) { int i = workList.Pop(); RtlStmt stmt = stmts[i]; stmt.Uses().ForEach(x => preds[i].ForEach(p => { if (!defVars[p].Contains(x)) throw new Exception( "variable " + x + " is used before it is assigned"); })); Util.DebugWriteLine(i + ": " + stmt); List vars = stmt.Vars(); List assignment = new List((i == 0) ? initAssign : preds[i].ConvertAll(p => assigned[p]).Find(a => a != null)); Util.DebugWriteLine(" " + String.Join(", ", assignment)); RtlInst inst = stmt as RtlInst; List> pinVars = (inst == null) ? new List>() : inst.args.Where(arg => arg.pinReg != null && arg.e is RtlVar) .Select(arg => Tuple.Create(((RtlVar)arg.e).x, arg.pinReg)).ToList(); for (int r = 0; r < regs.Count; r++) { string rx = assignment[r]; if (rx != null && !liveVars[i].ContainsKey(rx)) { assignment[r] = null; } if (pinVars.Exists(p => p.Item1 == rx)) { assignment[r] = null; } foreach (var p in pinVars) { if (p.Item2 == regs[r]) { assignment[r] = p.Item1; } } } if (stmt is RtlCall) { RtlCall call = (RtlCall)stmt; if (!call.ghost) { for (int r = 0; r < regs.Count; r++) { assignment[r] = null; } /* Func shouldSkip = (RtlExp e) => ((e is RtlVar) && ((RtlVar)e).isGhost); int[] outsToReg = new int[2] { regs.IndexOf("EAX"), regs.IndexOf("ESI") }; int[] argsToReg = new int[3] { regs.IndexOf("ECX"), regs.IndexOf("EDX"), regs.IndexOf("EBX") }; for (int r = 0; r < regs.Count; r++) { string rx = assignment[r]; if (rx != null && (call.outs.Where(v => v.ToString() == rx).Count() != 0 || call.args.Where(v => v.ToString() == rx).Count() != 0)) { assignment[r] = null; } } for (int idx = 0; idx < 2; idx++) { if (call.outs.Count >= idx + 1 && !shouldSkip(call.outs[idx])) { int r = outsToReg[idx]; string rx = assignment[r]; if (rx != null) { sStore(Spill(rx), regs[r]); } assignment[r] = call.outs[idx].ToString(); } } for (int idx = 0; idx < 3; idx++) { if (call.args.Count >= idx + 1 && !shouldSkip(call.args[idx])) { int r = argsToReg[idx]; string rx = assignment[r]; if (rx != null) { sStore(Spill(rx), regs[r]); } assignment[r] = call.args[idx].ToString(); } } */ } } else if (stmt is RtlReturn) { for (int r = 0; r < regs.Count; r++) { assignment[r] = null; } } else if (inst == null || !inst.ghost) { foreach (string x in vars) { Tuple bestEvict = null; for (int r = 0; r < regs.Count; r++) { var rx = assignment[r]; if (rx == x) { goto done; } if (!vars.Contains(rx)) { int thisEvict = (rx == null) ? Int32.MaxValue : liveVars[i][rx]; if (bestEvict == null || thisEvict > bestEvict.Item2) { bestEvict = Tuple.Create(r, thisEvict); } } } string ex = assignment[bestEvict.Item1]; if (ex != null) { Spill(ex); } assignment[bestEvict.Item1] = x; done: {} } } Util.DebugWriteLine(" vars = " + String.Join(", ", vars)); Util.DebugWriteLine(" preds = " + String.Join(", ", preds[i])); Util.DebugWriteLine(" succs = " + String.Join(", ", succs[i])); Util.DebugWriteLine(" live = " + String.Join(", ", liveVars[i].Keys.Select(x => Tuple.Create(x, liveVars[i][x])))); Util.DebugWriteLine(" assign: " + String.Join(", ", assignment)); assigned[i] = assignment; succs[i].Where(s => assigned[s] == null).ToList().ForEach(workList.Push); } for (int i = 0; i < stmts.Count; i++) { RtlJump jump = stmts[i] as RtlJump; if (jump != null && jump.cond != null) { List assignment1 = assigned[i]; List assignment2 = assigned[labels[jump.label]]; List condVars = jump.cond.Vars(); for (int r = 0; r < regs.Count; r++) { string x1 = assignment1[r]; string x2 = assignment2[r]; if (x1 != null && x2 != null && condVars.Contains(x1) && x1 != x2) { assignment2[r] = null; Spill(x2); } } } } Action, Dictionary, Dictionary, Dictionary> transition = (List assignment2, Dictionary live, Dictionary liveAlt, Dictionary varToReg) => { Util.DebugWriteLine("start transition"); varToReg.Keys.Where(x => x != null && !live.ContainsKey(x) && !liveAlt.ContainsKey(x)).ToList() .ForEach(x => varToReg.Remove(x)); bool done; do { done = true; for (int rx = 0; rx < regs.Count; rx++) { string x = assignment2[rx]; string reg = regs[rx]; if (x != null && varToReg.ContainsKey(x) && varToReg[x] != reg && !varToReg.ContainsValue(reg)) { Util.DebugWriteLine("move " + x + ": " + regs[rx] + " <- " + varToReg[x]); move(regs[rx], varToReg[x]); varToReg[x] = reg; done = false; } } } while (!done); List toSpill = new List(); foreach (var current in varToReg) { string x = current.Key; int rx = regs.IndexOf(current.Value); Util.DebugWriteLine("current = " + x + " -> " + regs[rx]); Util.DebugWriteLine("assign = " + assignment2[rx] + " -> " + regs[rx]); if (assignment2[rx] != x && (live.ContainsKey(x) || liveAlt.ContainsKey(x))) { Util.DebugWriteLine("spilling " + x + " from " + regs[rx]); toSpill.Add(x); sStore(Spill(x), regs[rx], x); } } toSpill.ForEach(x => varToReg.Remove(x)); Util.DebugWriteLine("live = " + String.Join(", ", live)); for (int rx = 0; rx < regs.Count; rx++) { string x = assignment2[rx]; if (x != null && live.ContainsKey(x)) { Util.DebugWriteLine("assign = " + x + " -> " + regs[rx]); if (varToReg.ContainsKey(x)) { Util.Assert(varToReg[x] == regs[rx]); } else { Util.DebugWriteLine("loading " + x + " to " + regs[rx]); sLoad(regs[rx], Spill(x), x); Util.DebugWriteLine("loaded " + x + " to " + regs[rx]); varToReg.Add(x, regs[rx]); } } } }; Util.DebugWriteLine("spilled: " + String.Join(", ", spillInts.Keys)); Action DebugWriteLine = s => { }; if (stmts.Count > 0) { transition(assigned[0], liveVars[0], liveVars[0], new Dictionary()); } for (int i = 0; i < stmts.Count; i++) { List assignment = assigned[i]; RtlStmt stmt = stmts[i]; List vars = stmt.Vars(); List uses = stmt.Uses(); Dictionary varToReg = new Dictionary(); Util.DebugWriteLine(i + ": " + stmt); Util.DebugWriteLine(" assignment: " + String.Join(", ", assignment)); Util.DebugWriteLine(" vars:" + String.Join(", ", vars)); Util.DebugWriteLine(" uses:" + String.Join(", ", uses)); DebugWriteLine(i + ": " + stmt.GetType() + ": " + stmt); DebugWriteLine(" vars = " + String.Join(", ", vars)); DebugWriteLine(" uses = " + String.Join(", ", uses)); DebugWriteLine(" preds = " + String.Join(", ", preds[i])); DebugWriteLine(" succs = " + String.Join(", ", succs[i])); DebugWriteLine(" live = " + String.Join(", ", liveVars[i].Keys.Select(x => Tuple.Create(x, liveVars[i][x])))); DebugWriteLine(" defs = " + String.Join(", ", defVars[i])); DebugWriteLine(" assign: " + String.Join(", ", assignment)); Action transitionTarget = (int target, int altTarget) => { Util.DebugWriteLine("transition from " + i + " to " + target); transition(assigned[target], liveVars[target], liveVars[altTarget], varToReg); }; int r; for (r = 0; r < regs.Count; r++) { string x = assignment[r]; if (x != null) { varToReg.Add(x, regs[r]); } } r = 0; foreach (string x in vars) { if (varToReg.ContainsKey(x) || stmt is RtlReturn) { continue; } int rx = assignment.IndexOf(x); if (rx < 0) { rx = assignment.IndexOf(null, r); Util.Assert(rx >= 0); Util.DebugWriteLine(i + ": MOVE(1): " + x); sLoad(regs[rx], Spill(x), x); r = rx + 1; } varToReg.Add(x, regs[rx]); } Util.DebugWriteLine("vars = " + String.Join(", ", vars)); List defs = stmt.Defs(); stmt = stmt.Subst(varToReg); Dictionary regToVar = new Dictionary(); varToReg.ToList().ForEach(p => regToVar.Add(p.Value, p.Key)); RtlJump jump = stmt as RtlJump; RtlReturn ret = stmt as RtlReturn; RtlLabel label = stmt as RtlLabel; RtlCall call = stmt as RtlCall; RtlCallInOut inOut = stmt as RtlCallInOut; if (ret != null) { Util.DebugWriteLine("RETURN: " + outVars.Count); for (int rr = 0; rr < regs.Count; rr++) { string rx = assignment[rr]; if (rx != null) { newStmts.Add(new RtlComment("spill variable " + rx + " from register " + regs[rr])); sStore(Spill(rx), regs[rr], rx); } } } if (jump == null) { List spilledArgs = new List(); if (inOut != null) { string reg = ((RtlVar)(inOut.args[0].e)).getName(); string var = regToVar[reg]; bool isPtr = IsPtr(var); int offset = 4 * inOut.index; RtlExp slot = new RtlExpComputed(e => isPtr ? StackOMemPtr(offset) : StackOMem(offset)); newStmts.Add(new RtlComment(inOut.comment)); if (inOut.isRet) { if (isPtr) { callPtrRets = Math.Max(callPtrRets, inOut.index + 1); } else { callIntRets = Math.Max(callIntRets, inOut.index + 1); newStmts.Add(new RtlInst(null, new RtlVar[] {new RtlVar(var, true)}, new RtlVar[0], new RtlExp[] {new RtlLiteral( CompileMethod.IntToTyped(varTypes[var], slotMem(offset)))}, true)); } Util.DebugWriteLine(" var = " + var + " live = " + String.Join(",", liveVars[i].Keys) + " live' = " + String.Join(",", liveVars[i + 1].Keys)); if (i + 1 >= liveVars.Count || liveVars[i + 1].ContainsKey(var)) { Util.DebugWriteLine("sLoad inOut: " + reg + " " + slot + " " + var); sLoad(reg, slot, var); } } else { if (isPtr) { callPtrArgs = Math.Max(callPtrArgs, inOut.index + 1); } else { callIntArgs = Math.Max(callIntArgs, inOut.index + 1); } sStore(slot, reg, var); } } else { newStmts.Add(stmt); defs.Where(x => !IsPtr(x)).ToList() .ForEach(x => newStmts.Add(new RtlInst(null, new RtlVar[] {new RtlVar(x, true)}, new RtlVar[0], new RtlExp[] {new RtlLiteral( CompileBase.IntToTyped(varTypes[x], Reg(varToReg[x])))}, true))); } Util.DebugWriteLine("sLoad spilled: " + String.Join(", ", spilledArgs.Select(arg => "(" + varToReg[arg] + " <- " + arg + ")"))); spilledArgs.ForEach(arg => sLoad(varToReg[arg], Spill(arg), arg)); } if (label != null && label.loop) { List typeInvs = new List(); newStmts.Add(new RtlComment("loop invariants")); foreach (string x in liveVars[i].Keys) { if (defVars[i].Contains(x)) { compileMethod.AddTypeWellFormed(typeInvs, x, false, varTypes[x]); string save_x = x; RtlExp loc = varToReg.ContainsKey(x) ? new RtlVar(Reg(varToReg[x]), false) : (RtlExp)new RtlExpComputed(e => spillMem(Spill(save_x))); if (IsPtr(x)) { string absData = "Abs_" + TypeString(varTypes[x]) + "(" + x + ")"; if (varToReg.ContainsKey(x)) { newStmts.Add(new RtlAssert(new RtlLiteral( "HeapAbsData(heap, " + x + "__abs) == " + absData), true)); newStmts.Add(new RtlAssert(new RtlExpComputed(e => "HeapValue(objLayouts, true, $toAbs, " + loc + ", " + save_x + "__abs)"), true)); if (IsArray(x)) { newStmts.Add(new RtlAssert(new RtlLiteral( x + "__abs == " + x + ".arrAbs"), true)); } } else { newStmts.Add(new RtlAssert(new RtlExpComputed(e => "StackAbsSlot(heap, $stacksFrames, " + spillLoc(Spill(save_x)) + ") == " + absData), true)); if (IsArray(x)) { newStmts.Add(new RtlAssert(new RtlExpComputed(e => "frameGet($stacksFrames, " + spillLoc(Spill(save_x)) + ") == " + save_x + ".arrAbs"), true)); } } } else { newStmts.Add(new RtlAssert(CompileMethod.IntEqTyped(varTypes[x], new RtlVar(x, false), new RtlExpComputed(e => loc.ToString())), true)); } } } typeInvs.ForEach(e => newStmts.Add(new RtlAssert(e, true))); } bool fallThru = (ret == null && i + 1 < stmts.Count && (jump == null || jump.cond != null)); if (jump != null) { transitionTarget(labels[jump.label], fallThru ? (i + 1) : labels[jump.label]); newStmts.Add(stmt); } if (fallThru) { transitionTarget(i + 1, i + 1); } } return newStmts; } public Dictionary MakeMap(List assignment) { Dictionary map = new Dictionary(); for (int i = 0; i < regs.Count; i++) { if (assignment[i] != null) { map.Add(assignment[i], regs[i]); } } return map; } } ================================================ FILE: ironclad-apps/tools/DafnyCC/Rtl.cs ================================================ using System; using System.Linq; using System.Collections.Generic; using System.Collections.ObjectModel; using Microsoft.Dafny; using Bpl = Microsoft.Boogie; using System.Numerics; public class RtlMem: RtlExp { public readonly RtlExp ptr; public readonly RtlExp scale; public readonly RtlExp index; public readonly RtlExp offset; public RtlMem(RtlExp ptr, string offset):this(ptr, new RtlLiteral(offset)) { } public RtlMem(RtlExp ptr, RtlExp offset):this(ptr, null, null, offset) { } public RtlMem(RtlExp ptr, RtlExp scale, RtlExp index, RtlExp offset) { if (index is RtlInt) { Util.Assert(scale is RtlInt && offset is RtlInt); offset = new RtlInt(((RtlInt)offset).i + ((RtlInt)scale).i * ((RtlInt)index).i); scale = null; index = null; } this.ptr = ptr; this.scale = scale; this.index = index; this.offset = offset; } public override void AddVars(List vars) { ptr.AddVars(vars); if (index != null) { index.AddVars(vars); } } public override RtlExp Subst(Dictionary map) { return new RtlMem(ptr.Subst(map), scale, (index == null) ? null : index.Subst(map), offset); } public override string ToString() { return "INVALID_BOOGIE_CODE+RtlMem"; } public override string AsOperand() { return (index == null) ? "OMem(MReg(" + ptr + ", " + offset + "))" : (index is RtlInt) ? "OMem(MReg(" + ptr + ", " + scale + " * " + index + " + " + offset + "))" : "OMem(MIndex(" + ptr + ", " + scale + ", " + index + ", " + offset + "))"; } } public class RtlLoopStart: RtlStmt { public RtlLoopStart() {} public override string ToString() { return ""; } } public class RtlStmtGroup: RtlStmt { public readonly ReadOnlyCollection stmts; public RtlStmtGroup(IEnumerable stmts) { this.stmts = stmts.ToList().AsReadOnly(); comment = () => String.Join(Environment.NewLine + "// ", stmts.Select(s => s.comment == null ? "" : s.comment())); } public override RtlStmt Subst(Dictionary map) { return new RtlStmtGroup(stmts.Select(s => s.Subst(map))); } public override void AddDefs(List vars) { stmts.ToList().ForEach(s => s.AddDefs(vars)); } public override void AddUses(List vars) { stmts.ToList().ForEach(s => s.AddUses(vars)); } public override string ToString() { return String.Join(Environment.NewLine, stmts.Select(s => s.ToString()));; } } public class RtlArg { public readonly bool isIn; public readonly bool isOut; public readonly RtlExp e; public string pinReg; public RtlArg(bool isIn, bool isOut, RtlExp e, string pinReg = null) { this.isIn = isIn; this.isOut = isOut; this.e = e; this.pinReg = pinReg; } public virtual RtlArg Subst(Dictionary map) { return new RtlArg(isIn, isOut, e.Subst(map), pinReg); } public override string ToString() { return e.ToString(); } public virtual string AsOperand() { return isOut ? e.ToString() : e.AsOperand(); } } public class RtlInst: RtlStmt { public readonly string op; public readonly ReadOnlyCollection args; public readonly bool ghost; public readonly string envIns; public readonly string envOuts; public RtlInst(string op, IEnumerable args, bool ghost, string envIns = null, string envOuts = null) { this.op = op; this.args = args.ToList().AsReadOnly(); this.ghost = ghost; this.envIns = envIns; this.envOuts = envOuts; } public RtlInst(string op, IEnumerable outs, IEnumerable insOuts, IEnumerable ins, bool ghost, string envIns = null, string envOuts = null): this(op, outs.Select(x => new RtlArg(false, true, x)).Concat( insOuts.Select(x => new RtlArg(true, true, x)).Concat( ins.Select(x => new RtlArg(true, false, x)))), ghost, envIns, envOuts) { } public override void AddDefs(List vars) { if (!ghost) { args.ToList().ForEach(x => {if (x.isOut) x.e.AddVars(vars);}); } } public override void AddUses(List vars) { if (!ghost) { args.ToList().ForEach(x => {if (x.isIn) x.e.AddVars(vars);}); } } public override RtlStmt Subst(Dictionary map) { return ghost ? this : new RtlInst(op, args.Select(e => e.Subst(map)), ghost, envIns, envOuts).WithComment(comment); } public override string ToString() { if (op == null) { var ins = args.Where(x => x.isIn); var outs = args.Where(x => x.isOut).ToList(); return String.Join(", ", outs) + (outs.Count == 0 ? "" : " := ") + String.Join(", ", ins) + ";"; } else { return "call r" + envOuts + " := " + op + "(r" + envIns + ", " + String.Join(", ", args.Select(e => e.AsOperand())) + ");"; } } } public class RtlCallInOut: RtlInst { public int index; public readonly bool isRet; public RtlCallInOut(int index, bool isRet, RtlExp e): base(null, new RtlArg[] { new RtlArg(!isRet, isRet, e) }, false) { this.index = index; this.isRet = isRet; } public override RtlStmt Subst(Dictionary map) { return new RtlCallInOut(index, isRet, args[0].e.Subst(map)).WithComment(comment); } public override string ToString() { return "INVALID_BOOGIE_CODE_RtlAssignStack;"; } } public class RtlCall: RtlInst { public RtlCall(string op, IEnumerable outs, IEnumerable args, bool ghost): base(op, outs, new RtlVar[0], args, ghost) { } public override void AddDefs(List vars) { } public override void AddUses(List vars) { } public override RtlStmt Subst(Dictionary map) { return this; } public override string ToString() { Func,string> commaList = ss => String.Concat(ss.Select(s => ", " + s)); var ins = args.Where(x => x.isIn); var outs = args.Where(x => x.isOut).ToList(); if (ghost) { return "call " + String.Join(", ", outs) + (outs.Count == 0 ? "" : " := ") + op + "(" + String.Join(", ", ins) + ");"; } else { string inouts = "stk, statics, io, mems, $commonVars, $gcVars, $toAbs, $absMem, $stacksFrames, objLayouts, heap"; string call_string = "call alignCall(r.regs[ESP]);" + System.Environment.NewLine; call_string += "{: call r, stk := logical_Call(r, core_state, stk);" + System.Environment.NewLine; call_string += "call r, " + inouts + String.Concat(outs.Select(s => ", " + s)) + " := " + op + "(r, core_state, " + inouts + String.Concat(ins.Select(s => ", " + s)) + "); :}"; return call_string; } } } public class RtlStmtComputed: RtlInst { public readonly Func toString; public RtlStmtComputed(Func toString, IEnumerable args, bool ghost): base(null, args, ghost) { this.toString = toString; } public override RtlStmt Subst(Dictionary map) { return ghost ? this : new RtlStmtComputed(toString, args.Select(e => e.Subst(map)), ghost).WithComment(comment); } public override string ToString() { return toString(this); } } public class RtlLabel: RtlStmt { public readonly string label; public readonly bool loop; public RtlLabel(string label, bool loop = false) { this.label = label; this.loop = loop; } public override string ToString() { return label + ":"; } } public class RtlJump: RtlStmt { public readonly string label; public readonly RtlBinary cond; public RtlJump(string label, RtlBinary cond) { this.label = label; this.cond = cond; Util.Assert(cond == null || !(cond.e0 is RtlInt && cond.e1 is RtlInt)); } public override void AddUses(List vars) { if (cond != null) { cond.AddVars(vars); } } public override RtlStmt Subst(Dictionary map) { return new RtlJump(label, (cond == null) ? null : (RtlBinary)cond.Subst(map)).WithComment(comment); } public override string ToString() { if (cond == null) { return "goto " + label + ";"; } else { string jop; switch (cond.op) { case "==": jop = "Je"; break; case "!=": jop = "Jne"; break; case "<": jop = "Jb"; break; case "<=": jop = "Jbe"; break; case ">": jop = "Ja"; break; case ">=": jop = "Jae"; break; default: throw new Exception("not implemented: " + cond.op); } return "call r := instr_Cmp(r, " + cond.e0 + ", " + cond.e1.AsOperand() + "); if (" + jop + "(r.efl)) { goto " + label + "; }"; } } } public class RtlReturn: RtlStmt { public readonly ReadOnlyCollection args; public RtlReturn(IEnumerable args) { this.args = args.ToList().AsReadOnly(); } public override void AddUses(List vars) { args.ToList().ForEach(x => x.AddVars(vars)); } public override RtlStmt Subst(Dictionary map) { return new RtlReturn(args.Select(e => (RtlVar)(e.Subst(map)))).WithComment(comment); } public override string ToString() { string ret = "{: call r := logical_Ret(r, core_state, stk); return; :}"; return ret; } } ================================================ FILE: ironclad-apps/tools/DafnyCC/blueprints/Analyze.bpl ================================================ // /useArrayTheory /loopUnroll:5 type id; const nStmts:int; axiom nStmts > 0; function N(i:int):bool { 0 <= i && i < nStmts } procedure ComputeLiveVars( outVars:[id]bool, rets:[int]bool, uses:[int][id]bool, defs:[int][id]bool, pred:[int][int]bool, succ:[int][int]bool) returns(live:[int][id]bool) requires (forall i:int :: rets[i] <==> N(i) && !(exists j:int :: N(j) && succ[i][j])); requires (forall i:int, x:id :: !N(i) ==> !uses[i][x] && !defs[i][x]); requires (forall i:int, j:int :: !N(i) || !N(j) ==> !pred[i][j] && !succ[i][j]); requires (forall i:int, j:int :: N(i) && N(j) ==> pred[i][j] <==> succ[j][i]); ensures (forall i:int, x:id :: N(i) ==> live[i][x] == ( uses[i][x] || ( !defs[i][x] && (if rets[i] then outVars[x] else (exists j:int :: N(j) && succ[i][j] && live[j][x]) )))); { var work:[int]bool; var k:int; var live_k:[id]bool; work := (lambda i:int :: N(i)); live := (lambda i:int :: (lambda x:id :: false)); while ((exists i:int :: N(i) && work[i])) { havoc k; assume N(k) && work[k]; work := work[k := false]; /* cleanest solution: live_k := if rets[k] then outVars else live[k]; live_k := (lambda x:id :: live_k[x] || (exists s:int :: N(k) && succ[k][s] && live[s][x])); live_k := (lambda x:id :: live_k[x] && !defs[k][x]); live_k := (lambda x:id :: live_k[x] || uses[k][x]); */ // more like actual implementation: live_k := live[k]; live_k := (lambda x:id :: live_k[x] || uses[k][x]); if (rets[k]) { live_k := (lambda x:id :: live_k[x] || (outVars[x] && !defs[k][x])); } live_k := (lambda x:id :: live_k[x] || (exists s:int :: N(k) && succ[k][s] && live[s][x] && !defs[k][x])); if ((exists x:id :: live_k[x] != live[k][x])) { live := live[k := live_k]; work := (lambda p:int :: N(p) && (work[p] || pred[k][p])); } } } procedure ComputeDefVars( inVars:[id]bool, uses:[int][id]bool, defs:[int][id]bool, pred:[int][int]bool, succ:[int][int]bool) returns(def:[int][id]bool) requires (forall i:int, x:id :: !N(i) ==> !uses[i][x] && !defs[i][x]); requires (forall i:int, j:int :: !N(i) || !N(j) ==> !pred[i][j] && !succ[i][j]); requires (forall i:int, j:int :: N(i) && N(j) ==> pred[i][j] <==> succ[j][i]); requires (forall j:int :: !pred[0][j]); ensures (forall x:id :: def[0][x] == (defs[0][x] || inVars[x])); ensures (forall i:int, x:id :: N(i) && i != 0 ==> def[i][x] == (defs[i][x] || (forall j:int :: N(j) && pred[i][j] ==> def[j][x]))); { var work:[int]bool; var k:int; var def_k:[id]bool; work := (lambda i:int :: i == 0); def := (lambda i:int :: (lambda x:id :: N(i))); while ((exists i:int :: N(i) && work[i])) { havoc k; assume N(k) && work[k]; work := work[k := false]; def_k := if k == 0 then inVars else def[k]; def_k := (lambda x:id :: def_k[x] && (forall p:int :: N(p) && pred[k][p] ==> def[p][x])); def_k := (lambda x:id :: def_k[x] || defs[k][x]); if ((exists x:id :: def_k[x] != def[k][x])) { def := def[k := def_k]; work := (lambda p:int :: N(p) && (work[p] || succ[k][p])); } } } ================================================ FILE: ironclad-apps/tools/DafnyCC/blueprints/RegAlloc.bpl ================================================ // /useArrayTheory /loopUnroll:5 const none:id; type reg; const unique r0:reg; const unique r1:reg; function R(r:reg):bool { r == r0 || r == r1 } //function R(r:reg):bool { true } //function R(r:reg):bool; procedure Alloc( inVars:[id]bool, outVars:[id]bool, initAssign:[reg]id, rets:[int]bool, uses:[int][id]bool, defs:[int][id]bool, pred:[int][int]bool, succ:[int][int]bool) returns(assigned:[int][reg]id, is_assigned:[int]bool) requires (forall r:reg :: !R(r) ==> initAssign[r] == none); requires (forall r1:reg, r2:reg :: R(r1) && R(r2) && initAssign[r1] != none && initAssign[r1] == initAssign[r2] ==> r1 == r2); requires (forall i:int :: rets[i] <==> N(i) && !(exists j:int :: N(j) && succ[i][j])); requires (forall i:int, x:id :: !N(i) ==> !uses[i][x] && !defs[i][x]); requires (forall i:int :: !uses[i][none] && !defs[i][none]); requires (forall i:int, j:int :: !N(i) || !N(j) ==> !pred[i][j] && !succ[i][j]); requires (forall i:int, j:int :: N(i) && N(j) ==> pred[i][j] <==> succ[j][i]); requires (forall j:int :: !pred[0][j]); { var live:[int][id]bool; var def:[int][id]bool; var work:[int]bool; var vars_k:[id]bool; var vars_loop:[id]bool; var assign_k:[reg]id; var xvar:id; var k:int; var kp:int; var bestEvict:reg; var assigned_spill:[int][reg]bool; var card:[id]int; // var xmap:[id]reg; // call live := ComputeLiveVars(outVars, rets, uses, defs, pred, succ); // call def := ComputeDefVars(inVars, uses, defs, pred, succ); assigned := (lambda i:int :: (lambda r:reg :: none)); is_assigned := (lambda i:int :: false); work := (lambda i:int :: i == 0); while ((exists i:int :: N(i) && work[i])) { havoc k; assume N(k) && work[k]; work := work[k := false]; assume (forall p:int, x:id :: pred[k][p] && uses[k][x] ==> def[p][x]); // variable x must be assigned before use vars_k := (lambda x:id :: defs[k][x] || uses[k][x]); // limit cardinality of vars_k // havoc xmap; // assume (forall x1:id, x2:id :: xmap[x1] == xmap[x2] ==> x1 == x2); // assume (forall x:id :: vars_k[x] ==> R(xmap[x])); havoc card; assume (forall x1:id, x2:id :: card[x1] == card[x2] ==> x1 == x2); assume (forall x:id :: vars_k[x] ==> 0 <= card[x] && card[x] < 2); assert R(r0) && R(r1); if (k == 0) { assign_k := initAssign; } else { assert (exists p:int :: pred[k][p] && is_assigned[p]); havoc kp; assume pred[k][kp] && is_assigned[kp]; assign_k := assigned[kp]; } assign_k := (lambda r:reg :: if assign_k[r] != none && live[k][assign_k[r]] then assign_k[r] else none); if (*) // call { assign_k := (lambda r:reg :: none); } else { vars_loop := vars_k; while ((exists x:id :: vars_loop[x])) { havoc xvar; assume vars_loop[xvar]; vars_loop := vars_loop[xvar := false]; if ((exists r:reg :: R(r) && assign_k[r] == xvar)) { // already allocated } else { assert (exists r:reg :: R(r) && !vars_k[assign_k[r]]); havoc bestEvict; assume R(bestEvict) && !vars_k[assign_k[bestEvict]]; assign_k := assign_k[bestEvict := xvar]; } } } assigned := assigned[k := assign_k]; is_assigned := is_assigned[k := true]; work := (lambda s:int :: work[s] || (succ[k][s] && !is_assigned[s])); } // insert arbitrary spills havoc assigned_spill; assigned := (lambda i:int :: (lambda r:reg :: if assigned_spill[i][r] then none else assigned[i][r])); // TODO: generate statements, spills, etc. } ================================================ FILE: ironclad-apps/tools/DafnyCC/nubuild-manifest.txt ================================================ # REVIEW: Everything in this file could be infered from the .csproj file. # Dependencies listed as References in .csproj file: dependency ..\Dafny\Basetypes.dll dependency ..\Dafny\Core.dll dependency ..\Dafny\DafnyPipeline.dll dependency ..\Dafny\ParserHelper.dll # Dependencies listed as Content in .csproj file: dependency ..\Dafny\CodeContractsExtender.dll dependency ..\Dafny\Provers.SMTLib.dll dependency ..\Dafny\VCGeneration.dll dependency ..\Dafny\z3.exe dependency ..\DafnySpec\DafnyPrelude.dfy # Outputs (References marked "Copy Local" in .csproj file): output Basetypes.dll output Core.dll output DafnyPipeline.dll output ParserHelper.dll # Outputs (Content marked "Copy to Output Directory" in .csproj file): output CodeContractsExtender.dll output Provers.SMTLib.dll output VCGeneration.dll output z3.exe output DafnyPrelude.dfy # Outputs actually built by this .csproj file: output dafnycc.exe ================================================ FILE: ironclad-apps/tools/DafnySpec/.gitignore ================================================ *.suo ================================================ FILE: ironclad-apps/tools/DafnySpec/Compile.cs ================================================ using System; using System.IO; using System.Linq; using System.Collections.Generic; using System.Collections.ObjectModel; using Microsoft.Dafny; using Bpl = Microsoft.Boogie; using Type = Microsoft.Dafny.Type; using System.Numerics; public class TypeApply { public readonly DafnySpec dafnySpec; public readonly string name; public readonly List typeParams; public readonly Dictionary typeArgs; public readonly Dictionary typeSubsts; readonly string appName; readonly string appFullName; public TypeApply(DafnySpec dafnySpec, string name, List typeParams, Dictionary typeArgs) { this.dafnySpec = dafnySpec; this.name = name; this.typeParams = typeParams; this.typeArgs = new Dictionary(); typeArgs.ToList().ForEach(a => this.typeArgs.Add(a.Key, ToType(a.Value))); this.typeSubsts = new Dictionary(); typeArgs.ToList().ForEach(a => this.typeSubsts.Add(a.Key.Name, ToType(a.Value))); string suffix = String.Concat(typeParams.Select(p => "___" + dafnySpec.TypeString(typeArgs[p]))); appName = name + suffix; appFullName = name + "__FULL" + suffix; int i = appFullName.Contains('.') ? appFullName.LastIndexOf('.') + 1 : 0; appFullName = appFullName.Insert(i, DafnySpec.CleanName("#")); } static Type ToType(Type t) { return DafnySpec.ToType(t); } public Type AppType(Type t) { Util.Assert(t != null); return Resolver.SubstType(t, typeArgs); } public string AppName() { return appName; } public string AppFullName() { return appFullName; } public override bool Equals(object obj) { TypeApply that = obj as TypeApply; if (that != null && that.name == this.name && that.typeArgs.Count == this.typeArgs.Count) { Dictionary thisArgs = this.typeArgs.ToDictionary(p => p.Key.ToString(), p => p.Value); Dictionary thatArgs = that.typeArgs.ToDictionary(p => p.Key.ToString(), p => p.Value); return thatArgs.Keys.ToList().TrueForAll(x => thisArgs.ContainsKey(x) && thatArgs[x].Equals(thisArgs[x])); } return false; } public override int GetHashCode() { return name.GetHashCode() + typeArgs.Values.Sum(t => ("" + t.ToString()).GetHashCode()); } } public class SeqTree { public readonly SeqTree left; public readonly SeqTree right; public readonly int buildCount; public SeqTree(SeqTree left, SeqTree right, int buildCount) { this.left = left; this.right = right; this.buildCount = buildCount; } public static string TreeName(SeqTree s) { return (s == null) ? "e" : (s.buildCount >= 0) ? s.buildCount.ToString() : "a_" + TreeName(s.left) + "_" + TreeName(s.right); } } public class CompileBase { public DafnySpec dafnySpec; public TypeApply typeApply; public bool isRecursive; public string procName; public string recFunName; public bool minVerify; public bool stmtExprEnabled; public int ignoreStmtExpr; public List stmts = new List(); public List> recCalls = new List>(); public Dictionary allVars = new Dictionary(); public List> forallVars = new List>(); public Dictionary renamer = new Dictionary(); public int nextRename; public static bool isPrinting = false; public TextWriter writer; public TextWriter iwriter; public string moduleName; public List imports; public List visibleModules; public Type visibleElementType; public int tempCount = 0; public CompileBase(DafnySpec dafnySpec, TypeApply typeApply, TextWriter writer, TextWriter iwriter, string moduleName, List imports) { this.dafnySpec = dafnySpec; this.typeApply = typeApply; this.writer = writer; this.iwriter = iwriter; this.moduleName = moduleName; this.imports = imports; this.visibleModules = imports.Concat(new List { moduleName, "private##" + moduleName }).ToList(); } public static string GhostProcName(string x) { return DafnySpec.GhostProcName(x); } public static string FunName(string x) { return DafnySpec.FunName(x); } public static string SimpleName(string x) { return DafnySpec.SimpleName(x); } public Type AppType(Type t) { return typeApply.AppType(t); } public string TypeString(Type t) { return dafnySpec.TypeString(t); } public string GhostVar(string x, bool allowRename = true) { return (x == "INTERNAL_absMem") ? "$absMem" : "$ghost_" + (allowRename && renamer.ContainsKey(x) ? renamer[x] : "") + DafnySpec.CleanName(x); } public string TempName() { return "temp__" + (tempCount++); } public void AddRename(string x) { renamer[x] = "_" + (nextRename++) + "_"; } public Dictionary PushRename() { return new Dictionary(renamer); } public Dictionary PushRename(string x) { var oldRenamer = PushRename(); AddRename(x); return oldRenamer; } public Dictionary PushRename(IEnumerable xs) { var oldRenamer = PushRename(); xs.ToList().ForEach(AddRename); return oldRenamer; } public void PopRename(Dictionary oldRenamer) { renamer = oldRenamer; } public RtlStmt PushForall() { var dict = new Dictionary(); forallVars.Add(dict); return new RtlGhostStmtComputed(s => String.Concat(dict.Values.Select( x => "var " + x.x + ":" + TypeString(x.type) + ";")), new RtlExp[0]); } public void PopForall() { forallVars.RemoveAt(forallVars.Count - 1); } public void Indent() { stmts.Add(new RtlIndent(true)); } public void Unindent() { stmts.Add(new RtlIndent(false)); } public static bool IsConstant(Expression e) { UnaryOpExpr unary = e as UnaryOpExpr; BinaryExpr binary = e as BinaryExpr; if (unary!= null) { return IsConstant(unary.E); } if (binary != null) { return IsConstant(binary.E0) && IsConstant(binary.E1); } return e is LiteralExpr; } public static string IntToTyped(Type t, string e) { return (t is BoolType) ? "((" + e + ") != 0)" : (t is RealType) ? "(real(" + e + "))" : e; } //- Assert that et is a well-formed value of type t, represented by integer ei public static RtlExp IntEqTyped(Type t, RtlExp et, RtlExp ei) { return (t is BoolType) ? new RtlBinary("||", new RtlBinary("&&", et, new RtlBinary("==", ei, new RtlInt(1))), new RtlBinary("&&", new RtlApply("!", new RtlExp[] { et }), new RtlBinary("==", ei, new RtlInt(0)))) : (t is RealType) ? new RtlBinary("==", et, new RtlApply("real", new RtlExp[] { ei })) : new RtlBinary("==", et, ei); } public static string IntEqTyped(Type t, string et, string ei) { return "(" + IntEqTyped(t, new RtlLiteral(et), new RtlLiteral(ei)) + ")"; } public Expression GetExp(Expression e) { Expression r = e.WasResolved() ? e.Resolved : e; ParensExpression p = e as ParensExpression; return (r != null) ? r : (p != null) ? GetExp(p.E) : e; } public RtlVar TempVar(Type t, bool declare = true) { string name = "$ghost__" + TempName(); RtlVar ret = new RtlVar(name, false, AppType(t)); if (declare) { allVars.Add(name, ret); } return ret; } public RtlVar AsVar(Expression exp) { exp = GetExp(exp); IdentifierExpr id = exp as IdentifierExpr; if (id != null) { //- We're assuming this is a local variable for the moment; otherwise we shouldn't call AppType string name = GhostVar(id.Name); RtlVar ret = new RtlVar(name, id.Var.IsGhost, AppType(id.Type)); return ret; } else { return null; } } public RtlVar AsVar(BoundVar x) { string name = GhostVar(x.Name); return new RtlVar(name, x.IsGhost, AppType(x.Type)); } public string Triggers(Attributes attrs, Func f) { List> triggers = new List>(); for (; attrs != null; attrs = attrs.Prev) { if (attrs.Name == "trigger") { triggers.Add(attrs.Args.ConvertAll(a => f(a))); } } return String.Concat(triggers.Select(es => "{" + String.Join(", ", es) + "}")); } public RtlExp GhostIfThenElse(RtlExp eTest, Func feThen, Func feElse) { if (stmtExprEnabled && ignoreStmtExpr == 0) { stmts.Add(new RtlGhostStmtComputed(s => "if (" + eTest + ") {", new RtlExp[0])); Indent(); } var eThen = feThen(); if (stmtExprEnabled && ignoreStmtExpr == 0) { Unindent(); stmts.Add(new RtlGhostStmtComputed(s => "}", new RtlExp[0])); stmts.Add(new RtlGhostStmtComputed(s => "if (!(" + eTest + ")) {", new RtlExp[0])); Indent(); } var eElse = feElse(); if (stmtExprEnabled && ignoreStmtExpr == 0) { Unindent(); stmts.Add(new RtlGhostStmtComputed(s => "}", new RtlExp[0])); } return new RtlLiteral("(if (" + eTest + ") then (" + eThen + ") else (" + eElse + "))"); } public RtlExp GhostLet(Microsoft.Boogie.IToken tok, List lhss, List rhss, Func body) { if (stmtExprEnabled && ignoreStmtExpr == 0) { var oldRenamer1 = PushRename(); for (int i = 0; i < lhss.Count; i++) { var lhs = lhss[i]; var rhs = rhss[i]; AddGhostVarDecl(lhs.Name, lhs.Type, true); MoveGhost(new RtlVar(GhostVar(lhs.Name), true, AppType(lhs.Type)), rhs); } body(); PopRename(oldRenamer1); } var oldRenamer2 = PushRename(); lhss.ForEach(e => AddRename(e.Name)); ignoreStmtExpr++; RtlExp rExp = new RtlLiteral("(" + String.Concat(lhss.Zip(rhss, (lhs, rhs) => "let " + GhostVar(lhs.Name) + ":" + TypeString(AppType(lhs.Type)) + " := (" + rhs + ") in ")) + " (" + body() + "))"); ignoreStmtExpr--; PopRename(oldRenamer2); return rExp; } public RtlExp GhostExpressionRec(Expression exp, bool inRecSpec = false, bool inRequiresOrOld = false) { Util.Assert(!isPrinting); exp = GetExp(exp); StmtExpr stmtExpr = exp as StmtExpr; IdentifierExpr idExp = exp as IdentifierExpr; LiteralExpr literal = exp as LiteralExpr; BinaryExpr binary = exp as BinaryExpr; UnaryExpr unary = exp as UnaryExpr; ITEExpr ite = exp as ITEExpr; ExistsExpr existsExp = exp as ExistsExpr; ForallExpr forallExp = exp as ForallExpr; LetExpr letExp = exp as LetExpr; MatchExpr matchExp = exp as MatchExpr; OldExpr oldExp = exp as OldExpr; FunctionCallExpr funCall = exp as FunctionCallExpr; DatatypeValue dataVal = exp as DatatypeValue; MemberSelectExpr memberSelect = exp as MemberSelectExpr; SeqSelectExpr seqSelect = exp as SeqSelectExpr; SeqUpdateExpr seqUpdate = exp as SeqUpdateExpr; SeqDisplayExpr seqDisplay = exp as SeqDisplayExpr; Func G = e => GhostExpression(e, inRecSpec, inRequiresOrOld); if (stmtExpr != null) { if (stmtExprEnabled) { if (ignoreStmtExpr == 0) { AddGhostStatement(stmtExpr.S, null); } return G(stmtExpr.E); } else { throw new Exception("not implemented: cannot handle statement expression here"); } } else if (idExp != null) { return AsVar(idExp); } else if (literal != null && literal.Value is BigInteger) { return new RtlInt((BigInteger)(literal.Value)); } else if (literal != null && literal.Value is bool) { return new RtlLiteral((bool)(literal.Value) ? "true" : "false"); } else if (literal != null && literal.Value == null) { return new RtlLiteral("ArrayOfInt(0 - 1, NO_ABS)"); } else if (literal != null && literal.Value is Microsoft.Basetypes.BigDec) { return new RtlLiteral(((Microsoft.Basetypes.BigDec)literal.Value).ToDecimalString()); } else if (binary != null) { string op = null; string internalOp = null; CompileFunction compileFunction = this as CompileFunction; string thisFuncName = (compileFunction == null) ? null : compileFunction.function.Name; switch (binary.ResolvedOp) { case BinaryExpr.ResolvedOpcode.SeqEq: return new RtlApply(dafnySpec.GetSeqOperationName(AppType(binary.E0.Type), "Seq_Equal"), new RtlExp[] { G(binary.E0), G(binary.E1) }); case BinaryExpr.ResolvedOpcode.SeqNeq: return new RtlLiteral("(!" + new RtlApply(dafnySpec.GetSeqOperationName(AppType(binary.E0.Type), "Seq_Equal"), new RtlExp[] { G(binary.E0), G(binary.E1) }) + ")"); case BinaryExpr.ResolvedOpcode.Concat: return new RtlApply(dafnySpec.GetSeqOperationName(AppType(binary.Type), "Seq_Append"), new RtlExp[] { G(binary.E0), G(binary.E1) }); } if (binary.Op == BinaryExpr.Opcode.Exp) { binary = new BinaryExpr(binary.tok, BinaryExpr.Opcode.Imp, binary.E0, binary.E1); } switch (binary.Op) { case BinaryExpr.Opcode.Disjoint: case BinaryExpr.Opcode.In: case BinaryExpr.Opcode.NotIn: throw new Exception("not implemented: binary operator '" + BinaryExpr.OpcodeString(binary.Op) + "'"); } if (AppType(binary.E0.Type) is IntType && AppType(binary.E1.Type) is IntType) { switch (binary.Op) { case BinaryExpr.Opcode.Le: internalOp = "INTERNAL_le_boogie"; break; case BinaryExpr.Opcode.Lt: internalOp = "INTERNAL_lt_boogie"; break; case BinaryExpr.Opcode.Ge: internalOp = "INTERNAL_ge_boogie"; break; case BinaryExpr.Opcode.Gt: internalOp = "INTERNAL_gt_boogie"; break; case BinaryExpr.Opcode.Add: internalOp = "INTERNAL_add_boogie"; break; case BinaryExpr.Opcode.Sub: internalOp = "INTERNAL_sub_boogie"; break; case BinaryExpr.Opcode.Mul: op = "*"; if (thisFuncName != "INTERNAL_mul") { internalOp = FunName("INTERNAL__mul"); } break; case BinaryExpr.Opcode.Div: op = "div"; if (thisFuncName != "INTERNAL_div") { internalOp = FunName("INTERNAL__div"); } break; case BinaryExpr.Opcode.Mod: op = "mod"; if (thisFuncName != "INTERNAL_mod") { internalOp = FunName("INTERNAL__mod"); } break; default: op = BinaryExpr.OpcodeString(binary.Op); break; } } else { op = BinaryExpr.OpcodeString(binary.Op); } if (internalOp == null) { return new RtlBinary(op, G(binary.E0), G(binary.E1)); } else { return new RtlApply(internalOp, new RtlExp[] { G(binary.E0), G(binary.E1) }); } } else if (unary != null) { if (unary is UnaryOpExpr) { UnaryOpExpr unaryOp = (UnaryOpExpr)unary; if (unaryOp.Op == UnaryOpExpr.Opcode.Not) { return new RtlLiteral("(!(" + G(unaryOp.E) + "))"); } else if (unaryOp.Op == UnaryOpExpr.Opcode.Cardinality) { return new RtlApply(dafnySpec.GetSeqOperationName(AppType(unaryOp.E.Type), "Seq_Length"), new RtlExp[] { G(unaryOp.E) }); } else if (unaryOp.Op == UnaryOpExpr.Opcode.Fresh) { Util.Assert(DafnySpec.IsArrayType(unaryOp.E.Type)); string abs = G(unaryOp.E) + ".arrAbs"; return new RtlLiteral("(heap_old.absData[" + abs + "] is AbsNone)"); } else { throw new Exception("not implemented: " + exp); } } else if (unary is ConversionExpr) { var e = (ConversionExpr)unary; var fromInt = e.E.Type.IsNumericBased(Type.NumericPersuation.Int); var toInt = e.ToType.IsNumericBased(Type.NumericPersuation.Int); if (fromInt && !toInt) { return new RtlApply("real", new RtlExp[] { G(e.E) }); } else if (!fromInt && toInt) { return new RtlApply("int", new RtlExp[] { G(e.E) }); } else { Util.Assert(fromInt == toInt); return GhostExpressionRec(e.E, inRecSpec, inRequiresOrOld); } } else { throw new Exception("not implemented: " + exp); } } else if (ite != null) { return GhostIfThenElse(G(ite.Test), () => G(ite.Thn), () => G(ite.Els)); } else if (funCall != null) { switch (funCall.Function.Name) { case "left": case "right": case "relation": case "public": Util.Assert(funCall.Args.Count == 1); return new RtlApply(funCall.Function.Name, new RtlExp[] { G(funCall.Args[0]) }); case "sizeof": Util.Assert(funCall.Args.Count == 1); return new RtlApply(funCall.Function.Name + "##" + TypeString(AppType(funCall.Args[0].Type)), new RtlExp[] { G(funCall.Args[0]) }); case "INTERNAL_add_raw": Util.Assert(funCall.Args.Count == 2); return new RtlBinary("+", G(funCall.Args[0]), G(funCall.Args[1])); case "INTERNAL_sub_raw": Util.Assert(funCall.Args.Count == 2); return new RtlBinary("-", G(funCall.Args[0]), G(funCall.Args[1])); } TypeApply app = dafnySpec.Compile_Function(funCall.Function, funCall.TypeArgumentSubstitutions.ToDictionary(p => p.Key, p => AppType(p.Value))); string name = FunName(SimpleName(app.AppName())); string fullName = FunName(SimpleName(app.AppFullName())); List rtlArgs = funCall.Args.Select(G).ToList(); List rtlReads = funCall.Function.Reads.Where(e => e.Field != null).ToList() .ConvertAll(e => (RtlExp)new RtlVar( GhostVar(e.FieldName), e.Field.IsGhost, AppType(e.Field.Type))); rtlArgs = rtlReads.Concat(rtlArgs).ToList(); if (name.EndsWith("__INTERNAL__HEAP")) { name = name.Substring(0, name.Length - "__INTERNAL__HEAP".Length); } else if (DafnySpec.IsHeapFunction(funCall.Function)) { rtlArgs.Insert(0, new RtlLiteral(inRequiresOrOld ? "$absMem_old" : "$absMem")); } if (Attributes.Contains(funCall.Function.Attributes, "opaque") && funCall.Function.Formals.Count + rtlReads.Count == 0) { rtlArgs.Insert(0, new RtlLiteral("true")); } if (fullName == recFunName) { name = fullName; } if (name == recFunName) { recCalls.Add(new List(rtlArgs)); rtlArgs.Insert(0, new RtlApply("decreases_" + name, new List(rtlArgs))); rtlArgs.Insert(1, new RtlLiteral(inRecSpec ? "__unroll" : "__unroll + 1")); name = "rec_" + name; } return new RtlApply(name, rtlArgs); } else if (dataVal != null) { bool isSeq = dataVal.Type.TypeName(null).StartsWith("Seq<"); return new RtlApply((isSeq ? "_" : "") + dafnySpec.Compile_Constructor( dataVal.Type, dataVal.Ctor.Name, dataVal.InferredTypeArgs, typeApply.typeArgs).AppName(), dataVal.Arguments.Select(G)); } else if (existsExp != null || forallExp != null) { QuantifierExpr qExp = (QuantifierExpr)exp; bool isForall = forallExp != null; var varTuples = qExp.BoundVars.Select(v => Tuple.Create(GhostVar(v.Name), v.IsGhost, v.Type)); var oldRenamer = PushRename(qExp.BoundVars.Select(v => v.Name)); var oldStmtExprEnabled = stmtExprEnabled; stmtExprEnabled = false; RtlExp rExp = new RtlLiteral((isForall ? "(forall " : "(exists ") + string.Join(", ", qExp.BoundVars.Select(v => GhostVar(v.Name) + ":" + TypeString(AppType(v.Type)))) + " :: " + Triggers(qExp.Attributes, G) + " " + GetTypeWellFormedExp(varTuples.ToList(), isForall ? "==>" : "&&", G(qExp.Term)) + ")"); stmtExprEnabled = oldStmtExprEnabled; PopRename(oldRenamer); return rExp; } else if (letExp != null) { List rhss; if (letExp.Exact) { rhss = letExp.RHSs.ConvertAll(e => G(e)); } else if (letExp.LHSs.Count == 1 && LiteralExpr.IsTrue(letExp.RHSs[0]) && AppType(letExp.LHSs[0].Var.Type) is IntType) { rhss = new List { new RtlLiteral("0") }; } else { throw new Exception("not implemented: LetExpr: " + letExp); } return GhostLet(exp.tok, letExp.LHSs.ConvertAll(lhs => lhs.Var), rhss, () => G(letExp.Body)); } else if (matchExp != null) { if (matchExp.MissingCases.Count != 0) { throw new Exception("not implemented: MatchExpr with missing cases: " + matchExp); } //- match src case c1(ps1) => e1 ... cn(psn) => en //- --> //- let x := src in //- if x is c1 then let ps1 := ...x.f1... in e1 else //- if x is c2 then let ps2 := ...x.f2... in e2 else //- let ps3 := ...x.f3... in e3 var src = G(matchExp.Source); var cases = matchExp.Cases; string x = TempName(); Func body = null; for (int i = cases.Count; i > 0; ) { i--; MatchCaseExpr c = cases[i]; Func> cRhss = () => c.Ctor.Formals.ConvertAll(f => (RtlExp)new RtlLiteral("(" + f.Name + "#" + c.Ctor.Name + "(" + GhostVar(x) + "))")); Func ec = () => GhostLet(exp.tok, c.Arguments, cRhss(), () => G(c.Body)); if (body == null) { body = ec; } else { var prevBody = body; body = () => GhostIfThenElse(new RtlLiteral("(" + GhostVar(x) + " is " + c.Ctor.Name + ")"), ec, prevBody); } } return GhostLet(exp.tok, new List { new BoundVar(exp.tok, x, matchExp.Source.Type) }, new List { src }, body); } else if (oldExp != null) { return new RtlLiteral("old(" + GhostExpression(oldExp.E, inRecSpec, true) + ")"); } else if (memberSelect != null && memberSelect.MemberName.EndsWith("?")) { string constructor = memberSelect.MemberName.Substring(0, memberSelect.MemberName.Length - 1); constructor = dafnySpec.Compile_Constructor(memberSelect.Obj.Type, constructor, null, typeApply.typeArgs).AppName(); bool isSeq = memberSelect.Obj.Type.TypeName(null).StartsWith("Seq<"); return isSeq ? new RtlLiteral("is_" + constructor + "(" + G(memberSelect.Obj) + ")") : new RtlLiteral("((" + G(memberSelect.Obj) + ") is " + constructor + ")"); } else if (memberSelect != null && memberSelect.Member is Field && !memberSelect.Member.IsStatic && AppType(memberSelect.Obj.Type) is UserDefinedType && memberSelect.Member is DatatypeDestructor) { DatatypeDestructor field = (DatatypeDestructor) memberSelect.Member; string constructor = dafnySpec.Compile_Constructor(memberSelect.Obj.Type, field.EnclosingCtor.Name, null, typeApply.typeArgs).AppName(); bool isSeq = memberSelect.Obj.Type.TypeName(null).StartsWith("Seq<"); return new RtlLiteral("(" + memberSelect.MemberName + (isSeq ? "_" : "#") + constructor + "(" + G(memberSelect.Obj) + "))"); } else if (memberSelect != null && memberSelect.Member is Field && DafnySpec.IsArrayType(AppType(memberSelect.Obj.Type)) && memberSelect.MemberName == "Length") { return new RtlLiteral("(Arr_Length(" + G(memberSelect.Obj) + "))"); } else if (memberSelect != null && memberSelect.Member is Field && memberSelect.Obj is ImplicitThisExpr) { //- we don't support objects yet, so interpret this as a global variable return new RtlVar(GhostVar(memberSelect.MemberName), true, memberSelect.Type); } else if (seqSelect != null) { if (seqSelect.SelectOne && DafnySpec.IsArrayType(AppType(seqSelect.Seq.Type))) { return new RtlExpComputed(e => "fun_INTERNAL__array__elems__index(" + (inRequiresOrOld ? "$absMem_old" : "$absMem") + "[" + e.args[0] + ".arrAbs], (" + e.args[1] + "))", new RtlExp[] { G(seqSelect.Seq), G(seqSelect.E0) }); } else if (seqSelect.SelectOne) { return new RtlApply(dafnySpec.GetSeqOperationName(AppType(seqSelect.Seq.Type), "Seq_Index"), new RtlExp[] { G(seqSelect.Seq), G(seqSelect.E0) }); } else { RtlExp seq = G(seqSelect.Seq); if (DafnySpec.IsArrayType(AppType(seqSelect.Seq.Type))) { seq = new RtlApply(FunName("Seq__FromArray"), new RtlExp[] { new RtlLiteral(inRequiresOrOld ? "$absMem_old" : "$absMem"), seq }); } if (seqSelect.E1 != null) { seq = new RtlApply(dafnySpec.GetSeqOperationName(AppType(seqSelect.Type), "Seq_Take"), new RtlExp[] { seq, G(seqSelect.E1) }); } if (seqSelect.E0 != null) { seq = new RtlApply(dafnySpec.GetSeqOperationName(AppType(seqSelect.Type), "Seq_Drop"), new RtlExp[] { seq, G(seqSelect.E0) }); } return seq; } } else if (seqUpdate != null) { if (seqUpdate.ResolvedUpdateExpr != null) { return GhostExpressionRec(seqUpdate.ResolvedUpdateExpr, inRecSpec, inRequiresOrOld); } return new RtlApply(dafnySpec.GetSeqOperationName(AppType(seqUpdate.Seq.Type), "Seq_Update"), new RtlExp[] { G(seqUpdate.Seq), G(seqUpdate.Index), G(seqUpdate.Value) }); } else if (seqDisplay != null) { RtlExp seq = new RtlApply(dafnySpec.GetSeqOperationName(AppType(seqDisplay.Type), "Seq_Empty"), new RtlExp[0]); foreach (Expression ei in seqDisplay.Elements) { seq = new RtlApply(dafnySpec.GetSeqOperationName(AppType(seqDisplay.Type), "Seq_Build"), new RtlExp[] { seq, G(ei) }); } return seq; } else { throw new Exception("not implemented: " + exp); } } public RtlExp GhostExpression(Expression exp, bool inRecSpec = false, bool inRequiresOrOld = false, Attributes attrs = null) { Type oldDefault = StartTypeArg(attrs); var e = GhostExpressionRec(exp, inRecSpec, inRequiresOrOld); DafnySpec.defaultPolyType = oldDefault; return e; } public string DecreasesExp(ICallable target) { Util.Assert(!isPrinting); Expression decrease; if (target.Decreases.Expressions.Count == 0 && target.Ins.Count > 0) { decrease = DafnySpec.MakeIdentifierExpr(target.Ins[0].Name, target.Ins[0].Type, target.Ins[0].IsGhost); } else if (target.Decreases.Expressions.Count == 1) { decrease = target.Decreases.Expressions[0]; } else if (target.Decreases.Expressions.Count > 1) { decrease = target.Decreases.Expressions[0]; } else { throw new Exception("recursive methods must have at least one parameter or supply a decreases clause"); } Type decreaseType = AppType(decrease.Type); if (decreaseType.AsDatatype != null) { return "sizeof##" + TypeString(decreaseType) + "(" + GhostExpression(decrease) + ")"; } else if (decreaseType is SeqType) { return new RtlApply(dafnySpec.GetSeqOperationName(decreaseType, "Seq_Length"), new RtlExp[] { GhostExpression(decrease) }).ToString(); } else if (decreaseType.Equals(Type.Int)) { return GhostExpression(decrease).ToString(); } else { throw new Exception("decreases clauses must be an integer or datatype"); } } public void AddTypeWellFormed(List specs, RtlExp exp, bool isGhost, Type t, List recs) { UserDefinedType ut = t as UserDefinedType; if (minVerify && !isGhost && t is IntType) { specs.Add(new RtlApply("word", new RtlExp[] { exp })); return; } if (t is NatType) { specs.Add(new RtlBinary(">=", exp, new RtlInt(0))); } if (ut != null && ut.AsDatatype != null && recs.TrueForAll(r => ut.Name != r.Name) ) { recs.Add(ut); foreach (var ctor in ut.AsDatatype.Ctors) { List cspecs = new List(); foreach (var f in ctor.Formals) { AddTypeWellFormed(cspecs, new RtlLiteral(f.Name + "#" + ctor.Name + "(" + exp + ")"), isGhost, f.Type, recs); } foreach (var spec in cspecs) { specs.Add(new RtlLiteral("((" + exp + ") is " + ctor.Name + " ==> (" + spec + "))")); } } recs.RemoveAt(recs.Count - 1); } } public void AddTypeWellFormed(List specs, string name, bool isGhost, Type t) { AddTypeWellFormed(specs, new RtlVar(name, isGhost, t), isGhost, t, new List()); } public void AddTypeWellFormed(List specs, List formals) { formals.ForEach(f => AddTypeWellFormed(specs, GhostVar(f.Name), f.IsGhost, f.Type)); } public List GetTypeWellFormed(List> vars) { List exps = new List(); vars.ForEach(x => AddTypeWellFormed(exps, x.Item1, x.Item2, x.Item3)); return exps; } public RtlExp GetTypeWellFormedExp(List> vars, string op, RtlExp rhs) { var exps = GetTypeWellFormed(vars); foreach(var e in exps) { rhs = new RtlBinary(op, e, rhs); } return rhs; } public void SymdiffLinearityPoint() { stmts.Add(new RtlAssert(new RtlLiteral("!false"))); } public void AddGhostCall(List destVars, string name, List args, bool isHeap) { List rtlArgs = args.ConvertAll(e => GhostExpression(e)); name = GhostProcName(name); if (isHeap) { rtlArgs.Insert(0, new RtlLiteral("$absMem")); } if (name == procName) { isRecursive = true; rtlArgs.Insert(0, new RtlApply("decreases_" + name, new List(rtlArgs))); name = "rec_" + name; } stmts.Add(new RtlGhostCall(name, destVars, rtlArgs) .WithComment("call:: " + String.Join(",", destVars) + " := " + name + "(" + String.Join(", ", rtlArgs.ToList()) + ") // isGhost = " + true)); } private void AddGhostCall(List destVars, List args, TypeApply typeApply, bool isHeap) { AddGhostCall(destVars, SimpleName(typeApply.AppName()), args, isHeap); } public void AddGhostVarDecl(string varName, Type t, bool isGhost) { string name = GhostVar(varName); if (allVars.ContainsKey(name) || forallVars.Exists(d => d.ContainsKey(name))) { AddRename(varName); name = GhostVar(varName); } var dict = (forallVars.Count == 0) ? allVars : forallVars[forallVars.Count - 1]; dict.Add(name, new RtlVar(name, isGhost, AppType(t))); } public void MoveGhost(RtlVar destVar, RtlExp rhs) { stmts.Add(new RtlGhostMove(new RtlVar[] { destVar }, new RtlExp[] { rhs })); } public virtual void AddResolvedGhostStatement(Statement stmt, Attributes attrs) { BlockStmt block = stmt as BlockStmt; IfStmt ifStmt = stmt as IfStmt; AssertStmt assertStmt = stmt as AssertStmt; AssignStmt assignStmt = stmt as AssignStmt; CallStmt callStmt = stmt as CallStmt; VarDeclStmt varDecl = stmt as VarDeclStmt; CalcStmt calcStmt = stmt as CalcStmt; ForallStmt forallStmt = stmt as ForallStmt; AssignSuchThatStmt existsStmt = stmt as AssignSuchThatStmt; if (block != null) { var oldRenamer = PushRename(); block.Body.ForEach(s => AddGhostStatement(s, attrs)); PopRename(oldRenamer); } else if (varDecl != null) { foreach (var varLocal in varDecl.Locals) { AddGhostVarDecl(varLocal.Name, varLocal.Type, varLocal.IsGhost); } if (varDecl.Update != null) { Util.Assert(varDecl.Update is UpdateStmt || varDecl.Update is AssignSuchThatStmt); AddGhostStatement((Statement)varDecl.Update, attrs); //Util.Assert(varDecl.Update.Lhss.Count() == 1); //var destVar = AsVar(varDecl.Update.Lhss[0]); //Util.Assert(destVar != null); //ExprRhs expRhs = ((UpdateStmt)varDecl.Update).Rhss[0] as ExprRhs; //if (expRhs != null) { // stmts.Add(new RtlGhostMove(new RtlVar[] { destVar }, // new RtlExp[] { GhostExpression(expRhs.Expr) })); //} else { // throw new Exception("not implemented: " + ((UpdateStmt)varDecl.Update).Rhss[0]); //} } } else if (minVerify) { return; } else if (assignStmt != null) { ExprRhs expRhs = assignStmt.Rhs as ExprRhs; if (expRhs != null) { MemberSelectExpr memberSelect = assignStmt.Lhs as MemberSelectExpr; RtlVar destVar; if (memberSelect != null && memberSelect.Member is Field) { // assume that this is a global variable; we don't support objects yet destVar = new RtlVar(GhostVar(memberSelect.MemberName), true, memberSelect.Type); } else { destVar = AsVar(assignStmt.Lhs); Util.Assert(destVar != null); } stmts.Add(new RtlGhostMove(new RtlVar[] { destVar }, new RtlExp[] { GhostExpression(expRhs.Expr) })); } else { throw new Exception("not implemented: " + assignStmt.Rhs); } } else if (callStmt != null) { var extraTypeargs = GetTypeArgs(attrs); var extraTypeargsDict = extraTypeargs.Select((t,index) => Tuple.Create(new TypeParameter(callStmt.Tok, "Fake" + index),t)).ToDictionary(tuple => tuple.Item1, tuple => tuple.Item2); var subst = callStmt.MethodSelect.TypeArgumentSubstitutions().Concat(extraTypeargsDict); AddGhostCall(callStmt.Lhs.ConvertAll(AsVar), callStmt.Args, dafnySpec.Compile_Method((Method)callStmt.MethodSelect.Member, subst.ToDictionary(p => p.Key, p => AppType(p.Value)), extraTypeargsDict.Keys.ToList()), DafnySpec.IsHeapMethod((Method)callStmt.MethodSelect.Member)); SymdiffLinearityPoint(); } else if (ifStmt != null) { stmts.Add(new RtlGhostStmtComputed(s => "if (" + s.args[0] + ") {", new RtlExp[] { GhostExpression(ifStmt.Guard) })); Indent(); AddGhostStatement(ifStmt.Thn, attrs); Unindent(); stmts.Add(new RtlGhostStmtComputed(s => "}", new RtlExp[0])); if (ifStmt.Els != null) { stmts.Add(new RtlGhostStmtComputed(s => "if (" + s.args[0] + ") {", new RtlExp[] { GhostExpression(new UnaryOpExpr(Bpl.Token.NoToken, UnaryOpExpr.Opcode.Not, ifStmt.Guard)) })); Indent(); AddGhostStatement(ifStmt.Els, attrs); Unindent(); stmts.Add(new RtlGhostStmtComputed(s => "}", new RtlExp[0])); } } else if (assertStmt != null) { stmts.Add(new RtlAssert(GhostExpression(assertStmt.Expr))); } else if (forallStmt != null) { var oldRenamer = PushRename(forallStmt.BoundVars.Select(v => v.Name)); RtlExp ens = new RtlLiteral("true"); foreach (var e in forallStmt.Ens) { ens = new RtlBinary("&&", ens, GhostExpression(e.E)); } RtlExp range = (forallStmt.Range == null) ? new RtlLiteral("true") : GhostExpression(forallStmt.Range); List wellFormed = GetTypeWellFormed(forallStmt.BoundVars. Select(x => Tuple.Create(GhostVar(x.Name), x.IsGhost, x.Type)).ToList()); wellFormed.ForEach(e => range = new RtlBinary("&&", e, range)); ens = new RtlBinary("==>", range, ens); string vars = String.Join(", ", forallStmt.BoundVars.Select(x => GhostVar(x.Name) + ":" + TypeString(AppType(x.Type)))); stmts.Add(new RtlGhostStmtComputed(s => "forall " + vars + "::(" + s.args[0] + ")", new List { ens })); stmts.Add(new RtlGhostStmtComputed(s => "{", new RtlExp[0])); Indent(); stmts.Add(PushForall()); stmts.Add(new RtlGhostStmtComputed(s => "if (" + s.args[0] + ")", new List { range })); stmts.Add(new RtlGhostStmtComputed(s => "{", new RtlExp[0])); Indent(); AddGhostStatement(forallStmt.Body, attrs); foreach (var e in forallStmt.Ens) { stmts.Add(new RtlAssert(GhostExpression(e.E))); } PopForall(); Unindent(); stmts.Add(new RtlGhostStmtComputed(s => "}", new RtlExp[0])); Unindent(); stmts.Add(new RtlGhostStmtComputed(s => "}", new RtlExp[0])); PopRename(oldRenamer); } else if (existsStmt != null) { List assigns = new List(); List tmps = new List(); List> varTuples = new List>(); var oldRenamer = PushRename(); foreach (var lhs in existsStmt.Lhss) { IdentifierExpr idExp = lhs.Resolved as IdentifierExpr; RtlVar origVar = AsVar(lhs); AddRename(idExp.Name); RtlVar renameVar = AsVar(lhs); tmps.Add(renameVar); varTuples.Add(Tuple.Create(renameVar.ToString(), true, idExp.Type)); assigns.Add(new RtlGhostMove(new RtlVar[] { origVar }, new RtlExp[] { renameVar })); } string vars = String.Join(", ", tmps.Select(x => x.getName() + ":" + TypeString(AppType(x.type)))); stmts.Add(new RtlGhostStmtComputed(s => "exists " + vars + "::(" + s.args[0] + ");", new List { GetTypeWellFormedExp(varTuples.ToList(), "&&", GhostExpression(existsStmt.Expr)) })); stmts.AddRange(assigns); PopRename(oldRenamer); } else if (calcStmt != null) { Util.Assert(calcStmt.Steps.Count == calcStmt.Hints.Count); CalcStmt.BinaryCalcOp binOp = calcStmt.Op as CalcStmt.BinaryCalcOp; bool isImply = binOp != null && binOp.Op == BinaryExpr.Opcode.Imp && calcStmt.Steps.Count > 0; if (isImply) { stmts.Add(new RtlGhostStmtComputed(s => "if (" + s.args[0] + ")", new RtlExp[] { GhostExpression(CalcStmt.Lhs(calcStmt.Steps[0])) })); stmts.Add(new RtlGhostStmtComputed(s => "{", new RtlExp[0])); Indent(); } var stepCount = calcStmt.Hints.Last().Body.Count == 0 ? calcStmt.Steps.Count - 1 : calcStmt.Steps.Count; for (int i = 0; i < stepCount; i++) { if (calcStmt.Hints[i] == null) { stmts.Add(new RtlAssert(GhostExpression(calcStmt.Steps[i]))); } else { stmts.Add(new RtlGhostStmtComputed(s => "forall::(" + s.args[0] + ")", new List { GhostExpression(calcStmt.Steps[i]) })); stmts.Add(new RtlGhostStmtComputed(s => "{", new RtlExp[0])); Indent(); var dict = new Dictionary(); stmts.Add(new RtlGhostStmtComputed(s => String.Concat(dict.Values.Select( x => "var " + x.x + ":" + TypeString(x.type) + ";")), new RtlExp[0])); forallVars.Add(dict); AddGhostStatement(calcStmt.Hints[i], attrs); forallVars.RemoveAt(forallVars.Count - 1); Unindent(); stmts.Add(new RtlGhostStmtComputed(s => "}", new RtlExp[0])); } } if (isImply) { Unindent(); stmts.Add(new RtlGhostStmtComputed(s => "}", new RtlExp[0])); } } else { throw new Exception("not implemented in ghost methods: " + stmt); } } public List ResolveStmt(Statement s) { /* ConcreteSyntaxStatement concrete = s as ConcreteSyntaxStatement; if (concrete != null && concrete.ResolvedStatements != null) { return concrete.ResolvedStatements; } */ UpdateStmt update = s as UpdateStmt; if (update != null && update.ResolvedStatements != null) { return update.ResolvedStatements; } return null; } public List GetTypeArgs(Attributes attrs) { var args = Attributes.FindExpressions(attrs, "typearg"); var types = new List(); foreach (var arg in args ?? new List()) { string s = (string)(((StringLiteralExpr)arg).Value); switch (s) { case "int": types.Add(Type.Int) ; break; case "bool": types.Add(Type.Bool); break; case "real": types.Add(Type.Real); break; default: if (typeApply.typeSubsts.ContainsKey(s)) { types.Add(typeApply.typeSubsts[s]); } else { throw new Exception("not implemented: StartTypeArg: " + s); } break; } } return types; } public Type StartTypeArg(Attributes attrs) { Type prev = DafnySpec.defaultPolyType; for (var a = attrs; a != null; a = a.Prev) { if (a.Name == "typearg") { string s = (string)(((StringLiteralExpr)a.Args[0]).Value); switch (s) { case "int": DafnySpec.defaultPolyType = Type.Int; break; case "bool": DafnySpec.defaultPolyType = Type.Bool; break; case "real": DafnySpec.defaultPolyType = Type.Real; break; default: if (typeApply.typeSubsts.ContainsKey(s)) { DafnySpec.defaultPolyType = typeApply.typeSubsts[s]; } else { throw new Exception("not implemented: StartTypeArg: " + s); } break; } break; } } return prev; } public void AddGhostStatement(Statement stmt, Attributes attribs) { Util.Assert(!isPrinting); stmts.Add(new RtlComment("###LINE: " + stmt.Tok.filename + ": " + stmt.Tok.line)); List resolved = ResolveStmt(stmt); if (resolved != null) { UpdateStmt u = stmt as UpdateStmt; if (u != null) { Type oldDefault = StartTypeArg(u.Rhss[0].Attributes); resolved.ForEach(s => AddGhostStatement(s, u.Rhss[0].Attributes)); DafnySpec.defaultPolyType = oldDefault; } else { resolved.ForEach(s => AddGhostStatement(s, attribs)); } } else { AddResolvedGhostStatement(stmt, attribs); } } } ================================================ FILE: ironclad-apps/tools/DafnySpec/CompileField.cs ================================================ using System; using System.IO; using System.Linq; using System.Collections.Generic; using System.Collections.ObjectModel; using Microsoft.Dafny; using Bpl = Microsoft.Boogie; using Type = Microsoft.Dafny.Type; using System.Numerics; public class CompileField { DafnySpec dafnySpec; Field field; TextWriter iwriter; public CompileField(DafnySpec dafnySpec, Field field, TextWriter iwriter) { this.dafnySpec = dafnySpec; this.field = field; this.iwriter = iwriter; } public void Compile() { if (Attributes.Contains(field.Attributes, "imported")) { //- do nothing } else if (field.IsGhost) { string rw = Attributes.Contains(field.Attributes, "readonly") ? "readonly " : ""; iwriter.WriteLine(rw + "var " + "$ghost_" + DafnySpec.CleanName(field.Name) + ":" + dafnySpec.TypeString(field.Type) + ";"); } else { throw new Exception("not implemented: non-ghost global variables"); } } } ================================================ FILE: ironclad-apps/tools/DafnySpec/CompileFunction.cs ================================================ using System; using System.IO; using System.Linq; using System.Collections.Generic; using System.Collections.ObjectModel; using Microsoft.Dafny; using Bpl = Microsoft.Boogie; using Type = Microsoft.Dafny.Type; using System.Numerics; public class CompileFunction: CompileBase { public Function function; public CompileFunction(DafnySpec dafnySpec, Function function, TypeApply typeApply, TextWriter writer, TextWriter iwriter, string moduleName, List imports): base(dafnySpec, typeApply, writer, iwriter, moduleName, imports) { this.function = function; } public void Compile() { Util.Assert(!isPrinting); string name = FunName(DafnySpec.SimpleName(typeApply.AppName())); string fullName = FunName(DafnySpec.SimpleName(typeApply.AppFullName())); bool isAxiom = Attributes.Contains(function.Attributes, "axiom"); bool isPrivate = Attributes.Contains(function.Attributes, "private"); bool hidden = Attributes.Contains(function.Attributes, "opaque"); bool isHeap = DafnySpec.IsHeapFunction(function); List heapParams = isHeap ? new List { "$absMem:[int][int]int" } : new List(); List heapArgs = isHeap ? new List { "$absMem" } : new List(); var formals = function.Formals; var reads = function.Reads.Where(e => e.Field != null).ToList().ConvertAll(e => new Formal(e.tok, e.FieldName, e.Field.Type, true, e.Field.IsGhost)); formals = reads.Concat(formals).ToList(); if (hidden && formals.Count == 0) { formals = new List { new Formal(function.tok, "___dummy", Type.Bool, true, true) }; } if (hidden && !function.Name.EndsWith("_FULL")) { ClassDecl cls = (ClassDecl)function.EnclosingClass; Function full = (Function)cls.Members.Find(m => m.Name == "#" + function.Name + "_FULL"); dafnySpec.Compile_Function(full, typeApply.typeArgs); } bool isFull = hidden && function.Name.EndsWith("_FULL"); string unfullName = isFull ? name.Substring(0, name.Length - "__FULL".Length) .Replace("#", "").Replace("____HASH", "") : null; string argsNoRec = String.Join(", ", heapArgs.Concat(formals.Select(f => GhostVar(f.Name)))); List reqsNoRec = minVerify ? new List() : function.Req.ConvertAll(e => GhostExpression(e, true)); List enssNoRec = minVerify ? new List() : function.Ens.ConvertAll(e => GhostExpression(e, true)); AddTypeWellFormed(reqsNoRec, formals); AddTypeWellFormed(enssNoRec, name + "(" + argsNoRec + ")", function.IsGhost, function.ResultType); if (function.Body != null && !minVerify) { recFunName = name; stmtExprEnabled = true; GhostExpression(function.Body); function.IsRecursive = recCalls.Count != 0; stmtExprEnabled = false; stmts = new List(); recCalls = new List>(); recFunName = null; } if (function.IsRecursive) { recFunName = name; } stmts = new List(); stmtExprEnabled = true; var bodyDecls = PushForall(); RtlExp body = (function.Body == null || minVerify) ? null : GhostExpression(function.Body); List bodyStmts = stmts; PopForall(); stmtExprEnabled = false; stmts = new List(); string parms = String.Join(", ", heapParams.Concat( formals.Select(f => GhostVar(f.Name) + ":" + TypeString(AppType(f.Type))))); string args = String.Join(", ", heapArgs.Concat( formals.Select(f => GhostVar(f.Name)))); string sep = (heapArgs.Count + formals.Count != 0) ? ", " : ""; string ret = TypeString(AppType(function.ResultType)); string recName = "rec_" + name; string decreases = null; List reqs = minVerify ? new List() : function.Req.ConvertAll(e => GhostExpression(e, true)); List enss = minVerify ? new List() : function.Ens.ConvertAll(e => GhostExpression(e, true)); AddTypeWellFormed(reqs, formals); AddTypeWellFormed(enss, name + "(" + args + ")", function.IsGhost, function.ResultType); string reqConjunct = "(true" + String.Concat(reqs.Select(e => " && (" + e + ")")) + ")"; string ensConjunct = "(true" + String.Concat(enss.Select(e => " && (" + e + ")")) + ")"; Util.Assert(!isPrinting); if (function.IsRecursive && function.Body != null && !minVerify) { decreases = DecreasesExp(function); } List enssRec = null; if (function.IsRecursive && (!hidden || isFull) && body != null && !minVerify) { enssRec = function.Ens.ConvertAll(e => GhostExpression(e, true)); } isPrinting = true; var fiWriter = isPrivate ? writer : iwriter; if (function.IsRecursive && function.Body != null && !minVerify) { iwriter.WriteLine("function decreases0_" + name + "(" + parms + "):int { " + decreases + " }"); iwriter.WriteLine("function decreases_" + name + "(" + parms + "):int { if decreases0_" + name + "(" + args + ") < 0 then 0 else 1 + decreases0_" + name + "(" + args + ") }"); iwriter.WriteLine("function " + recName + "(__decreases:int, __unroll:int" + sep + parms + "):" + ret + ";"); fiWriter.WriteLine("function implementation{" + FunName("unroll") + "(__unroll), " + recName + "(__decreases, __unroll" + sep + args + ")} " + recName + "(__decreases:int, __unroll:int" + sep + parms + "):" + ret); fiWriter.WriteLine("{"); fiWriter.WriteLine(" " + body.ToString()); fiWriter.WriteLine("}"); } iwriter.WriteLine("function " + name + "(" + parms + "):" + ret + ";"); if (hidden && !isFull && !minVerify) { iwriter.WriteLine("function unhide_" + name + "(" + parms + "):bool { true }"); fiWriter.WriteLine("function implementation{unhide_" + name + "(" + args + ")} " + name + "(" + parms + "):" + ret); fiWriter.WriteLine("{"); fiWriter.WriteLine(" " + fullName + "(" + args + ")"); fiWriter.WriteLine("}"); iwriter.WriteLine("atomic ghost procedure " + GhostProcName("reveal__" + DafnySpec.SimpleName(typeApply.AppName())) + "();"); string forall = "forall " + parms + "::" + name + "(" + args + ") == " + fullName + "(" + args +")"; iwriter.WriteLine(" ensures (" + forall + ");"); writer.WriteLine("implementation " + GhostProcName("reveal__" + DafnySpec.SimpleName(typeApply.AppName())) + "()"); writer.WriteLine("{"); writer.WriteLine(" " + forall); writer.WriteLine(" {"); writer.WriteLine(" assert unhide_" + name + "(" + args + ");"); writer.WriteLine(" }"); writer.WriteLine("}"); } if (body != null && (!hidden || isFull)) { fiWriter.WriteLine("function implementation{" + name + "(" + args + ")" + "} " + name + "(" + parms + "):" + ret); fiWriter.WriteLine("{"); if (function.IsRecursive) { fiWriter.WriteLine(" " + recName + "(decreases_" + name + "(" + args + "), 0" + sep + args + ")"); } else { fiWriter.WriteLine(" " + body.ToString()); } fiWriter.WriteLine("}"); } if (function.IsRecursive && (!hidden || isFull) && body != null && !minVerify) { AddTypeWellFormed(enssRec, recName + "(__decreases, __unroll" + sep + args + ")", function.IsGhost, function.ResultType); string ensRecConjunct = "(true" + String.Concat(enssRec.Select(e => " && (" + e + ")")) + ")"; iwriter.WriteLine("atomic ghost procedure lemma_unroll2_" + recName + "(__decreases:int, __unroll:int, __unroll2:int" + sep + parms + ");"); iwriter.WriteLine(" requires __decreases == decreases_" + name + "(" + args + ");"); iwriter.WriteLine(" ensures " + reqConjunct + " ==> " + ensRecConjunct + " && " + recName + "(__decreases, __unroll" + sep + args + ") == " + recName + "(__decreases, __unroll2" + sep + args + ");"); writer.WriteLine("implementation lemma_unroll2_" + recName + "(__decreases:int, __unroll:int, __unroll2:int" + sep + parms + ")"); writer.WriteLine("{"); writer.WriteLine(" " + bodyDecls); writer.WriteLine(" assert fun_unroll(__unroll) && fun_unroll(__unroll2);"); dafnySpec.WriteLemmas(writer, this, visibleModules, function.Attributes); writer.WriteLine(" if (" + reqConjunct + ")"); writer.WriteLine(" {"); bodyStmts.ForEach(s => writer.WriteLine(" " + s)); writer.WriteLine(" }"); foreach (List recArgs in recCalls) { string rec_args = String.Join(", ", recArgs); string rec_decrease = "decreases_" + name + "(" + rec_args + ")"; writer.WriteLine(" if (0 <= " + rec_decrease + " && " + rec_decrease + " < __decreases)"); writer.WriteLine(" {"); writer.WriteLine(" call lemma_unroll2_" + recName + "(" + rec_decrease + ", __unroll + 1, __unroll2 + 1" + sep + rec_args + ");"); writer.WriteLine(" }"); } writer.WriteLine("}"); string unroll_args = "decreases_" + name + "(" + args + "), __unroll"; string unroll_args0 = "decreases_" + name + "(" + args + "), 0"; string unroll = recName + "(" + unroll_args + sep + args + ")"; string unroll0 = recName + "(" + unroll_args0 + sep + args + ")"; var lwriter = isPrivate ? writer : iwriter; string recForall = "forall __unroll:int" + sep + parms + "::" + "{fun_unroll(__unroll), " + unroll + "} " + reqConjunct + " ==> fun_unroll(__unroll) ==> " + unroll + " == " + body; lwriter.WriteLine("atomic ghost procedure lemma_unroll_" + recName + "();"); lwriter.WriteLine(" ensures (" + recForall + ");"); writer.WriteLine("implementation lemma_unroll_" + recName + "()"); writer.WriteLine("{"); dafnySpec.WriteLemmas(writer, this, visibleModules, function.Attributes); writer.WriteLine(" " + recForall); writer.WriteLine(" {"); writer.WriteLine(" " + bodyDecls); writer.WriteLine(" if (" + reqConjunct + ")"); writer.WriteLine(" {"); bodyStmts.ForEach(s => writer.WriteLine(" " + s)); writer.WriteLine(" }"); writer.WriteLine(" }"); writer.WriteLine("}"); dafnySpec.AddLemma(new LemmaCall((isPrivate ? "private##" : "") + moduleName, visibleElementType, "call lemma_unroll_" + recName + "();", false)); Func forall = s => "forall __unroll:int" + sep + parms + "::" + "{" + s + unroll + "} " + "{fun_unroll__all(__unroll), " + unroll + "} " + reqConjunct + " ==> " + unroll + " == " + name + "(" + args + ") && " + ensConjunct; iwriter.WriteLine("atomic ghost procedure lemma_unroll_" + name + "();"); iwriter.WriteLine(" ensures (" + forall(unroll0 + ", ") + ");"); writer.WriteLine("implementation lemma_unroll_" + name + "()"); writer.WriteLine("{"); dafnySpec.WriteLemmas(writer, this, visibleModules, function.Attributes); writer.WriteLine(" " + forall("")); writer.WriteLine(" {"); writer.WriteLine(" call lemma_unroll2_" + recName + "(" + unroll_args + ", 0" + sep + args + ");"); writer.WriteLine(" if (" + reqConjunct + ")"); writer.WriteLine(" {"); enss.ForEach(e => writer.WriteLine(" assert " + e + ";")); writer.WriteLine(" }"); writer.WriteLine(" }"); writer.WriteLine("}"); dafnySpec.AddLemma(new LemmaCall(moduleName, visibleElementType, "call lemma_unroll_" + name + "();", false)); } else if (enssNoRec.Count > 0 && !minVerify) { string reqConjunctNoRec = "(true" + String.Concat(reqsNoRec.Select(e => " && (" + e + ")")) + ")"; string ensConjunctNoRec = "(true" + String.Concat(enssNoRec.Select(e => " && (" + e + ")")) + ")"; iwriter.WriteLine("function trigger_" + name + "(" + parms + "):bool { true }"); iwriter.WriteLine("atomic ghost procedure lemma_fun_ensures_" + name + "();"); string forallNoRec = "forall " + parms + "::{" + name + "(" + argsNoRec + ")}" + (isFull ? ("{" + unfullName + "(" + argsNoRec + ")}") : "") + "{trigger_" + name + "(" + argsNoRec + ")}" + "trigger_" + name + "(" + argsNoRec + ") ==> " + reqConjunctNoRec + " ==> " + ensConjunctNoRec; iwriter.WriteLine(" ensures (" + forallNoRec + ");"); if (body != null || hidden || isAxiom) { writer.WriteLine("implementation lemma_fun_ensures_" + name + "()"); writer.WriteLine("{"); dafnySpec.WriteLemmas(writer, this, visibleModules, function.Attributes); writer.WriteLine(" " + forallNoRec); writer.WriteLine(" {"); writer.WriteLine(" " + bodyDecls); writer.WriteLine(" if (" + reqConjunct + ")"); writer.WriteLine(" {"); if (isAxiom) { writer.WriteLine(" // dummy lemma body for axiom"); } else { bodyStmts.ForEach(s => writer.WriteLine(" " + s)); } writer.WriteLine(" }"); if (hidden && !isFull) { writer.WriteLine(" assert unhide_" + name + "(" + argsNoRec + ");"); } if (hidden && isFull) { writer.WriteLine(" assert unhide_" + unfullName + "(" + argsNoRec + ");"); } writer.WriteLine(" if (" + reqConjunct + ")"); writer.WriteLine(" {"); enssNoRec.ForEach(e => writer.WriteLine(" assert " + e + ";")); writer.WriteLine(" }"); writer.WriteLine(" }"); writer.WriteLine("}"); } dafnySpec.AddLemma(new LemmaCall(moduleName, visibleElementType, "call lemma_fun_ensures_" + name + "();", false)); } isPrinting = false; } } ================================================ FILE: ironclad-apps/tools/DafnySpec/CompileMethodGhost.cs ================================================ using System; using System.IO; using System.Linq; using System.Collections.Generic; using System.Collections.ObjectModel; using Microsoft.Dafny; using Bpl = Microsoft.Boogie; using Type = Microsoft.Dafny.Type; using System.Numerics; public class CompileMethodGhost: CompileBase { protected Method method; protected bool isGhost; protected List calledMethods = new List(); public CompileMethodGhost(DafnySpec dafnySpec, Method method, TypeApply typeApply, TextWriter writer, TextWriter iwriter, string moduleName, List imports): base(dafnySpec, typeApply, writer, iwriter, moduleName, imports) { this.method = method; } public List GetStaticFieldMods() { return (method.Mod.Expressions.Exists(e => e.E is ThisExpr && e.FieldName == null)) ? dafnySpec.allStaticFields.ConvertAll(x => GhostVar(x)) : method.Mod.Expressions.Where(e => e.E is ThisExpr).Select(e => GhostVar(e.FieldName)).ToList(); } public void CompileGhost(string name, string parms, string rets, string req, Action printBody) { List reqs = method.Req.ConvertAll(a => GhostExpression(a.E, false, false, a.Attributes)); List enss = method.Ens.ConvertAll(a => GhostExpression(a.E, false, false, a.Attributes)); AddTypeWellFormed(reqs, method.Ins); AddTypeWellFormed(enss, method.Outs); Util.Assert(!isPrinting); isPrinting = true; iwriter.WriteLine("atomic ghost procedure " + name + "(" + parms + ") returns(" + rets + ");"); if (req != null) { iwriter.WriteLine(" requires " + req + ";"); } reqs.ForEach(e => iwriter.WriteLine(" requires " + e + ";")); enss.ForEach(e => iwriter.WriteLine(" ensures " + e + ";")); GetStaticFieldMods().ForEach(x => iwriter.WriteLine(" modifies " + x + ";")); if (printBody != null) { writer.WriteLine("implementation " + name + "(" + parms + ") returns(" + rets + ")"); writer.WriteLine("{"); allVars.Keys .Where(x => !method.Ins.Select(y => GhostVar(y.Name)).ToList().Contains(x) && !method.Outs.Select(y => GhostVar(y.Name)).ToList().Contains(x)).ToList() .ForEach(x => writer.WriteLine(" var " + x + ":" + TypeString(allVars[x].type) + ";")); dafnySpec.WriteLemmas(writer, this, visibleModules, method.Attributes); printBody(); writer.WriteLine("}"); } isPrinting = false; } public void CompileGhost() { bool isAxiom = Attributes.Contains(method.Attributes, "axiom"); bool isHeap = DafnySpec.IsHeapMethod(method); BlockStmt body = method.Body; List heapParams = isHeap ? new List { "$absMem:[int][int]int" } : new List(); List heapArgs = isHeap ? new List { "$absMem" } : new List(); string parms = String.Join(", ", heapParams.Concat( method.Ins.Select(x => GhostVar(x.Name) + ":" + TypeString(AppType(x.Type))))); string rets = String.Join(", ", method.Outs.Select(x => GhostVar(x.Name) + ":" + TypeString(AppType(x.Type)))); if (body != null) { foreach (Statement stmt in body.Body) { AddGhostStatement(stmt, null); } Action printStmts = () => { string indent = " "; foreach (RtlStmt s in stmts) { RtlIndent rtlIndent = s as RtlIndent; if (rtlIndent != null) { indent = rtlIndent.Positive ? indent + " " : indent.Substring(4); continue; } if (s.comment != null) { writer.WriteLine(indent + "// " + s.comment().Replace(Environment.NewLine, Environment.NewLine + indent)); } if (s.ToString() != "") { writer.WriteLine(indent + s.ToString().Replace(Environment.NewLine, Environment.NewLine + indent)); } } }; if (isRecursive) { Util.Assert(!isPrinting); string decreases = DecreasesExp(method); isPrinting = true; iwriter.WriteLine("function decreases_" + procName + "(" + parms + "):int { " + decreases + " }"); isPrinting = false; string applyDecrease = "decreases_" + procName + "(" + String.Join(", ", heapArgs.Concat(method.Ins.Select(x => GhostVar(x.Name)))) + ")"; string sep = (method.Ins.Count + heapArgs.Count == 0) ? "" : ", "; CompileGhost("rec_" + procName, "__decreases:int" + sep + parms, rets, "__decreases == " + applyDecrease, printStmts); CompileGhost(procName, parms, rets, null, () => { writer.WriteLine(" call " + String.Join(", ", method.Outs.Select(x => GhostVar(x.Name))) + (method.Outs.Count == 0 ? "" : " := ") + "rec_" + procName + "(" + applyDecrease + String.Concat(heapArgs.Concat(method.Ins.Select(x => GhostVar(x.Name))) .Select(x => ", " + x)) + ");"); }); } else { CompileGhost(procName, parms, rets, null, printStmts); } } else if (isAxiom) { CompileGhost(procName, parms, rets, null, () => writer.WriteLine(" // dummy method body for axiom")); } else { CompileGhost(procName, parms, rets, null, null); } } public virtual void Compile() { Util.Assert(!isPrinting); isGhost = method is Lemma || method.IsGhost; bool isImported = Attributes.Contains(method.Attributes, "imported"); bool isAxiom = Attributes.Contains(method.Attributes, "axiom"); if (isImported && method.Body == null) { return; } if (!isGhost) { throw new Exception("only ghost methods can appear in specifications"); } procName = GhostProcName(SimpleName(typeApply.AppName())); if (method.Body == null && method.Name.StartsWith("reveal_")) { return; } CompileGhost(); } } ================================================ FILE: ironclad-apps/tools/DafnySpec/DafnyPrelude.dfy ================================================ /////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////// static function INTERNAL_mul(x:int, y:int) : int { x * y } // Formerly anonymous function // static function INTERNAL_mod(x:int, m:int) : int { x % m } // Formerly anonymous function static function INTERNAL_div(x:int, m:int) : int { x / m } // Formerly anonymous function // // function dummy_seqs(i:seq, b:seq, ii:seq>, bb:seq>):bool ================================================ FILE: ironclad-apps/tools/DafnySpec/DafnySpec.cs ================================================ using System; using System.IO; using System.Linq; using System.Collections.Generic; using System.Collections.ObjectModel; using Microsoft.Dafny; using Bpl = Microsoft.Boogie; using Type = Microsoft.Dafny.Type; using System.Numerics; public class DafnySpec_Options: DafnyOptions { public string outDir; public bool minVerify = false; protected override bool ParseOption(string name, Bpl.CommandLineOptionEngine.CommandLineParseState ps) { switch (name) { case "outdir": if (ps.ConfirmArgumentCount(1)) { outDir = ps.args[ps.i]; } return true; case "minVerify": minVerify = true; return true; default: break; } return base.ParseOption(name, ps); } } public class LemmaCall { public readonly string module; public readonly Type type; public readonly string stmt; public readonly bool loopLemma; public LemmaCall(string module, Type type, string stmt, bool loopLemma) { this.module = module; this.type = type; this.stmt = stmt; this.loopLemma = loopLemma; } } public class NonglobalVariable { public static string CompilerizeName(string s) { return s.Replace("_", "__"); } } public class DafnySpec { public const string ImpBasmExtn = ".imp.basm"; public const string IfcBasmExtn = ".ifc.basm"; protected TextWriter trustedWriter = null; protected TextWriter trustedIWriter = null; protected string outDir = null; protected TextWriter outListWriter = null; public bool minVerify = false; protected Dictionary> fileImports = new Dictionary>(); protected Dictionary compileMethods = new Dictionary(); protected Dictionary compileFunctions = new Dictionary(); protected Dictionary compileDatatypes = new Dictionary(); protected List compileDatatypeList = new List(); protected Dictionary allMethods = new Dictionary(); protected Dictionary allFunctions = new Dictionary(); protected Dictionary allDatatypes = new Dictionary(); public List allStaticFields = new List(); public static Type defaultDefaultPolyType = Type.Int; public static Type defaultPolyType = defaultDefaultPolyType; // HACK protected Dictionary>> outDirWriters = new Dictionary>>(StringComparer.CurrentCultureIgnoreCase); public static void Main(string[] args) { try { Util.DebugWriteLine("hello"); DafnySpec_Options options = new DafnySpec_Options(); DafnyOptions.Install(options); Bpl.CommandLineOptions.Clo.RunningBoogieFromCommandLine = true; if (!Bpl.CommandLineOptions.Clo.Parse(args)) { throw new Exception("argument parse error"); } IList files = Bpl.CommandLineOptions.Clo.Files; if (files.Count == 0) { throw new Exception("*** Error: No input files were specified."); } new DafnySpec().CompileSpec(options, files); } catch (Exception e) { Console.OpenStandardOutput().Flush(); Console.WriteLine(e); Console.Error.WriteLine(e); Environment.Exit(-1); } } public static string CleanName(string x) { return x.Replace("'", "___PRIME_").Replace("#", "___HASH_"); } public static string GhostProcName(string x) { return "proc_" + CleanName(x); } public static string FunName(string x) { return "fun_" + CleanName(x); } public static string SimpleName(string x) { return x.Contains('.') ? x.Substring(x.LastIndexOf('.') + 1) : x; } public static string SanitizedName(MemberDecl m) { return /* m.EnclosingClass.FullSanitizedName + "." + */ NonglobalVariable.CompilerizeName(m.Name.Replace("#", "&")).Replace("&", "#"); } public static string SimpleSanitizedName(MemberDecl m) { return SimpleName(SanitizedName(m)); } public static bool IsArrayType(Type t) { return t is UserDefinedType && ((UserDefinedType)t).Name == "array"; } public static bool IsHeapFunction(Function f) { // TODO: use f.Reads? return Attributes.Contains(f.Attributes, "heap") || f.Formals.Exists(p => IsArrayType(p.Type)) || IsArrayType(f.ResultType); } public static bool IsHeapMethod(Method m) { return Attributes.Contains(m.Attributes, "heap") || !m.IsGhost || m.Ins.Exists(p => IsArrayType(p.Type)) || m.Outs.Exists(p => IsArrayType(p.Type)); } public static bool IsPtrType(Type t) { return !(t is BoolType) && !(t is IntType) && !(t is NatType) && !(t is RealType); } public static IdentifierExpr MakeIdentifierExpr(string name, Type type, bool isGhost) { Util.Assert(type != null); IdentifierExpr id = new IdentifierExpr(Bpl.Token.NoToken, name); id.Type = type; id.Var = new LocalVariable(Bpl.Token.NoToken, Bpl.Token.NoToken, name, type, isGhost); return id; } public static BinaryExpr MakeBinaryExpr(BinaryExpr.Opcode op, BinaryExpr.ResolvedOpcode rop, Type t, Expression e0, Expression e1) { Util.Assert(t != null && e0.Type != null && e1.Type != null); BinaryExpr e = new BinaryExpr(e0.tok, op, e0, e1); e.ResolvedOp = rop; e.Type = t; return e; } public static Type ToType(Type t) { TypeProxy proxy = t as TypeProxy; if (proxy != null && proxy.T == null) { Util.Assert(false); // Dafny appears to be doing sane type resolution now return defaultPolyType; //- pick arbitrary type } if (proxy != null) { return ToType(proxy.T); } return t; } public string TypeString(Type t) { t = ToType(t); MapType mt = t as MapType; UserDefinedType ut = t as UserDefinedType; SeqType seq = t as SeqType; if (t is BoolType) { return "bool"; } else if (t is IntType) { return "int"; } else if (t is RealType) { return "real"; } else if (mt != null) { return "[" + TypeString(mt.Domain) + "]" + TypeString(mt.Range); } else if (ut != null && ut.AsDatatype != null) { return Compile_Datatype(ut).AppName(); } else if (ut != null && ut.Name == "array") { if (!(ToType(ut.TypeArgs[0]) is IntType) || ToType(ut.TypeArgs[0]) is NatType) { throw new Exception("not implemented: arrays of non-int types: " + ToType(ut.TypeArgs[0])); } return "ArrayOfInt"; } else if (ut != null && ut.Name == "INTERNAL_AbsMem") { return "[int][int]int"; } else if (ut != null && ut.Name == "INTERNAL_ArrayElems") { return "[int]int"; } else if (ut != null && !ut.IsTypeParameter) { return ut.Name; } else if (seq != null) { return Compile_SeqType(seq).AppName(); } else { throw new Exception("not implemented: " + t + ": " + t.GetType()); } } public Method FindMethod(string name) { if (allMethods.ContainsKey(name)) { return allMethods[name]; } else { throw new Exception("could not find method " + name); } } public Function FindFunction(string name) { if (allFunctions.ContainsKey(name)) { return allFunctions[name]; } else { throw new Exception("could not find function " + name); } } public DatatypeDecl FindDatatype(string name) { if (allDatatypes.ContainsKey(name)) { return allDatatypes[name]; } else { throw new Exception("could not find datatype " + name); } } public virtual void AddLemma(LemmaCall lemma) { } public virtual void AddMethodAsLemma(Method method) { } public virtual void WriteLemmas(TextWriter writer, CompileBase context, List visibleModules, Attributes attrs, bool loopLemmasOnly = false) { } // This emits way overkill, as it doesn't exploit import inheritance. // But it's autogenerated code, so we don't care, I guess. --jonh public void WriteInterfaceImports(TextWriter writer, IEnumerable importList) { foreach (string module in importList) { string importWord = "//private-import"; writer.WriteLine(" "+importWord+" "+module+";"); } } public IEnumerable GatherAllImports(List imports) { IEnumerable stockImports = new string[] { "BaseSpec", "MemorySpec", "IoTypesSpec", "MachineStateSpec", "AssemblySpec", "InterruptsSpec", "IoSpec", "Overflow", "Core", "LogicalAddressing", "Util", "Stacks", "Partition", "Instructions", "Separation", "IntLemmasGc", "SimpleGcMemory", "SimpleCommon", "SimpleCollector", "IntLemmasMain", "IntLemmasBase", "IoMain" }; return stockImports.Concat(imports); } public void WriteImplementationHeader(TextWriter writer, string name, List imports) { writer.WriteLine("module implementation " + name); WriteInterfaceImports(writer, GatherAllImports(imports)); writer.WriteLine("{"); } // TODO: this should be based on attributes, not based on the name public bool IsSeqFile(string filename, bool spec) { return filename.EndsWith(spec ? @"\Seq.s.dfy" : @"\Seq.dfy"); } // TODO: this should be based on attributes, not based on the name public bool IsSpecFile(string filename) { return filename.EndsWith(@".s.dfy"); } public string ModuleNameFromFilename(string filename) { string suffix = Path.GetFileNameWithoutExtension(filename).Replace("-", "_").Replace(".", "_"); return "dafny_" + suffix; } public void AddImports(Dictionary imports, string filename) { Dictionary myImports; if (!fileImports.ContainsKey(filename)) { myImports = new Dictionary(StringComparer.CurrentCultureIgnoreCase); StreamReader reader = new StreamReader(filename); while (true) { string line = reader.ReadLine(); if (line == null) { reader.Close(); break; } string[] tokens = line.Trim().Split(' '); if (tokens.Length >= 2 && tokens[0] == "include" && tokens[1].StartsWith("\"") && tokens[1].EndsWith("\"")) { string imp = tokens[1].Substring(1, tokens[1].Length - 2).Replace('/', '\\'); if (filename.EndsWith(".s.dfy") && imp.EndsWith(".i.dfy")) { throw new Exception("specification " + filename + " includes implementation " + imp); } if (!Path.IsPathRooted(imp)) { imp = Path.Combine(Path.GetDirectoryName(filename), imp); } imp = new FileInfo(imp).FullName; AddImports(myImports, imp); string moduleName = ModuleNameFromFilename(imp); if (!myImports.ContainsKey(moduleName)) { myImports.Add(moduleName, imp); } } } fileImports.Add(filename, myImports); } myImports = fileImports[filename]; foreach (var p in myImports) { if (!imports.ContainsKey(p.Key)) { imports.Add(p.Key, p.Value); } } } public virtual Tuple> ChooseOutDirWriter(string filename) { if (!outDirWriters.ContainsKey(filename)) { string moduleName = ModuleNameFromFilename(filename); string baseName = Path.Combine(outDir, moduleName); TextWriter implWriter = new StreamWriter(baseName + ImpBasmExtn); TextWriter intfWriter = new StreamWriter(baseName + IfcBasmExtn); Dictionary imports = new Dictionary(StringComparer.CurrentCultureIgnoreCase); imports.Add("Trusted", ""); if (moduleName != "dafny_DafnyPrelude") { imports.Add("dafny_DafnyPrelude", ""); if (moduleName.EndsWith("_i")) { imports.Add("DafnyAssembly", ""); } } AddImports(imports, filename); List importModules = imports.Keys.ToList(); if (outListWriter != null && moduleName != "dafny_DafnyPrelude") { outListWriter.WriteLine(moduleName + String.Concat( imports.Where(x => x.Value != "").Select(x => " " + x.Key))); } WriteImplementationHeader(implWriter, moduleName, importModules); WriteInterfaceImports(intfWriter, GatherAllImports(importModules)); intfWriter.WriteLine("module interface " + moduleName); intfWriter.WriteLine("{"); outDirWriters.Add(filename, Tuple.Create(implWriter, intfWriter, moduleName, importModules)); //- make sure each import gets a file: imports.Values.Where(x => x != "").ToList().ForEach(x => {ChooseOutDirWriter(x);}); } return outDirWriters[filename]; } public bool TrustedType(Type t) { SeqType seq = t as SeqType; UserDefinedType ut = t as UserDefinedType; if (seq != null) { return TrustedType(seq.Arg); } else if (ut != null) { return IsSpecFile(ut.AsDatatype.tok.filename) && TrustedType(ut.TypeArgs); } else { return true; } } public bool TrustedType(IEnumerable ts) { return ts.ToList().TrueForAll(t => TrustedType(t)); } public virtual Tuple> ChooseWriter( Bpl.IToken tok, string name, TypeApply app = null) { string filename = Path.GetFullPath(tok.filename); if (app != null && !TrustedType(app.typeArgs.Values)) { throw new Exception("specification cannot refer to untrusted type: " + name); } if (IsSeqFile(filename, true)) { return Tuple.Create(trustedWriter, (name.StartsWith("lemma_Seq") ? trustedWriter : trustedIWriter), "Trusted", new List()); } else { return ChooseOutDirWriter(filename); } } public void CompileDatatype1Ghost(Type t, TypeApply app, TextWriter writer, TextWriter iwriter) { // type List = Nil() | Cons(hd:int, tl:List); string dataName = app.AppName(); // List List ctors = compileDatatypes[app].AsDatatype.Ctors; bool isSeq = dataName.StartsWith("Seq_"); if (isSeq) { iwriter.WriteLine("type " + dataName + ";"); } (isSeq ? writer : iwriter).WriteLine( "type " + (isSeq ? "implementation" : "") + "{:overload} " + dataName + " = " + String.Join(" | ", ctors.Select(c => Compile_Constructor(t, c.Name, app.typeArgs).AppName() + "(" + String.Join(", ", c.Formals.Select(f => f.Name + ":" + TypeString(app.AppType(f.Type)))) + ")")) + ";"); if (isSeq) { foreach (var c in ctors) { string cName = Compile_Constructor(t, c.Name, app.typeArgs).AppName(); string args = String.Join(", ", c.Formals.Select(f => f.Name)); string parms = String.Join(", ", c.Formals.Select(f => f.Name + ":" + TypeString(app.AppType(f.Type)))); iwriter.WriteLine("function _" + cName + "(" + parms + "):" + dataName + ";"); writer.WriteLine("function implementation _" + cName + "(" + parms + "):" + dataName + " { " + cName + "(" + args + ") }"); foreach (var f in c.Formals) { string tName = TypeString(app.AppType(f.Type)); iwriter.WriteLine("function " + f.Name + "_" + cName + "(x:" + dataName + "):" + tName + ";"); writer.WriteLine("function implementation " + f.Name + "_" + cName + "(x:" + dataName + "):" + tName + " { " + f.Name + "#" + cName + "(x) }"); } iwriter.WriteLine("function is_" + cName + "(x:" + dataName + "):bool;"); writer.WriteLine("function implementation is_" + cName + "(x:" + dataName + "):bool { x is " + cName + " }"); } } } const string baseDecls = @" function fun_unroll(i:int):bool { true } function fun_unroll__all(i:int):bool { true } function fun_word__32(i:int):bool { word(i) } function INTERNAL_add_boogie(x:int, y:int) : int { x + y } function INTERNAL_sub_boogie(x:int, y:int) : int { x - y } function{:never_pattern true} INTERNAL_lt_boogie(x:int, y:int) : bool { x < y } function{:never_pattern true} INTERNAL_le_boogie(x:int, y:int) : bool { x <= y } function{:never_pattern true} INTERNAL_gt_boogie(x:int, y:int) : bool { x > y } function{:never_pattern true} INTERNAL_ge_boogie(x:int, y:int) : bool { x >= y } "; void CompileDatatypesGhost() { for (int i = 0; i < compileDatatypeList.Count; i++) { // note that compileDatatypes may get extended during loop var app = compileDatatypeList[i]; CompileDatatype1Ghost(compileDatatypes[app], app, trustedWriter, trustedIWriter); } } public virtual CompileMethodGhost NewCompileMethod(DafnySpec dafnySpec, Method method, TypeApply typeApply, TextWriter writer, TextWriter iwriter, string moduleName, List imports) { return new CompileMethodGhost(dafnySpec, method, typeApply, writer, iwriter, moduleName, imports); } public TypeApply Compile_Method(Method method, Dictionary typeArgs, List extraTypeParams = null) { Dictionary substArgs = new Dictionary(); var fullTypeArgs = method.TypeArgs.Concat(extraTypeParams ?? new List()).ToList(); fullTypeArgs.ForEach(t => substArgs.Add(t.Name, t)); typeArgs = typeArgs.ToDictionary(p => substArgs[p.Key.Name], p => p.Value); TypeApply apply = new TypeApply(this, DafnySpec.SanitizedName(method), fullTypeArgs, typeArgs); //Console.Error.WriteLine("Compile_Method: " + method + " :: " + method.GetType() + " " + String.Join(",", typeArgs)); if (!compileMethods.ContainsKey(apply)) { //Console.Error.WriteLine("Compile_Method# " + method + " :: " + method.GetType() + " " + String.Join(",", typeArgs)); compileMethods.Add(apply, apply); var tok = method.tok; var writers = ChooseWriter(tok, method.Name, apply); CompileMethodGhost compile = NewCompileMethod(this, method, apply, writers.Item1, writers.Item2, writers.Item3, writers.Item4); if (writers.Item3 == "Seq" && typeArgs.Count == 1) { compile.visibleElementType = new List(apply.typeArgs.Values)[0]; } compile.minVerify = minVerify; try { compile.Compile(); } catch(Exception e) { throw new Exception("while compiling method " + method.Name, e); } } return apply; } public virtual void Compile_FunctionAsMethod(Function function, Dictionary typeArgs, Dictionary substArgs) { } public TypeApply Compile_Function(Function function, Dictionary typeArgs) { Dictionary substArgs = new Dictionary(); function.TypeArgs.ForEach(t => substArgs.Add(t.Name, t)); typeArgs = typeArgs.ToDictionary(p => substArgs[p.Key.Name], p => p.Value); TypeApply apply = new TypeApply(this, DafnySpec.SanitizedName(function), function.TypeArgs, typeArgs); if (!compileFunctions.ContainsKey(apply)) { compileFunctions.Add(apply, apply); var tok = function.tok; //Console.Error.WriteLine("function: " + function + " :: " + function.GetType()); //Console.Error.WriteLine(" " + function.Body); //Console.Error.WriteLine(" " + function.IsRecursive + " " + function.IsGhost); var writers = ChooseWriter(tok, function.Name, apply); if (!Attributes.Contains(function.Attributes, "imported")) { try { var compile = new CompileFunction(this, function, apply, writers.Item1, writers.Item2, writers.Item3, writers.Item4); if (writers.Item3 == "Seq" && typeArgs.Count == 1) { compile.visibleElementType = new List(apply.typeArgs.Values)[0]; } compile.minVerify = minVerify; compile.Compile(); } catch(Exception e) { throw new Exception("while compiling function " + function.Name, e); } } else { // imported if (function.Ens.Count > 0) { string name = FunName(SimpleName(apply.AppName())); AddLemma(new LemmaCall(writers.Item3, (Type)null, "call lemma_fun_ensures_" + name + "();", false)); } } bool hidden = Attributes.Contains(function.Attributes, "opaque"); bool isFull = function.Name.Contains("#") && function.Name.EndsWith("_FULL"); if (!function.IsGhost && !isFull && !IsSpecFile(function.tok.filename)) { Compile_FunctionAsMethod(function, typeArgs, substArgs); } } return apply; } public virtual void AddDatatypeLemmas(UserDefinedType t, TypeApply apply) { } public TypeApply Compile_Datatype(UserDefinedType t) { Dictionary subst = new Dictionary(); for (int i = 0; i < t.TypeArgs.Count; i++) { subst.Add(t.AsDatatype.TypeArgs[i], t.TypeArgs[i]); } TypeApply apply = new TypeApply(this, t.Name, t.AsDatatype.TypeArgs, subst); if ( !compileDatatypes.ContainsKey(apply) && !Attributes.Contains(t.AsDatatype.Attributes, "imported")) { compileDatatypes.Add(apply, t); compileDatatypeList.Add(apply); AddDatatypeLemmas(t, apply); } return apply; } public TypeApply Compile_Constructor(Type t, string constructor, List dataTypeArgs, Dictionary typeArgs) { UserDefinedType ut = (UserDefinedType) t; if (dataTypeArgs == null) { dataTypeArgs = ut.TypeArgs; } Util.Assert(ut.AsDatatype.TypeArgs.Count == dataTypeArgs.Count); Dictionary typeMap = new Dictionary(); for (int i = 0; i < dataTypeArgs.Count; i++) { typeMap.Add(ut.AsDatatype.TypeArgs[i], Resolver.SubstType(dataTypeArgs[i], typeArgs)); } return new TypeApply(this, constructor, ut.AsDatatype.TypeArgs, typeMap); } // REVIEW: is this receiving the correct typeArgs? public TypeApply Compile_Constructor(Type t, string constructor, Dictionary typeArgs) { UserDefinedType ut = (UserDefinedType) t; Dictionary substArgs = new Dictionary(); ut.AsDatatype.TypeArgs.ForEach(tt => substArgs.Add(tt.Name, tt)); typeArgs = typeArgs.ToDictionary(p => substArgs[p.Key.Name], p => p.Value); return new TypeApply(this, constructor, ut.AsDatatype.TypeArgs, typeArgs); } public TypeApply Compile_SeqType(SeqType t) { Dictionary typeArgs = new Dictionary(); DatatypeDecl decl = FindDatatype("Seq"); return Compile_Datatype(new UserDefinedType(Bpl.Token.NoToken, "Seq", decl, new List { t.Arg })); } public Tuple GetSeqOperation(Type t, string op) { Function f = FindFunction(op); TypeApply tApp = Compile_SeqType((SeqType)t); return Tuple.Create(f, Compile_Function(f, tApp.typeArgs)); } public string GetSeqOperationName(Type t, string op) { TypeApply tApp = Compile_SeqType((SeqType)t); TypeApply fApp = Compile_Function(FindFunction(op), tApp.typeArgs); return FunName(SimpleName(GetSeqOperation(t, op).Item2.AppName())); } public Tuple GetSeqMethod(Type t, string op) { Method m = FindMethod(op); TypeApply tApp = Compile_SeqType((SeqType)t); return Tuple.Create(m, Compile_Method(m, tApp.typeArgs)); } public Dictionary CompileSpecStart(DafnySpec_Options options, IList files) { minVerify = options.minVerify; outDir = options.outDir; outListWriter = new StreamWriter(Path.Combine(outDir, "dafny_modules.txt")); trustedWriter = new StreamWriter(Path.Combine(outDir, "Trusted"+ImpBasmExtn)); trustedIWriter = new StreamWriter(Path.Combine(outDir, "Trusted"+IfcBasmExtn)); WriteInterfaceImports(trustedIWriter, GatherAllImports(new List())); trustedIWriter.WriteLine("module interface Trusted"); trustedIWriter.WriteLine("{"); trustedIWriter.WriteLine(baseDecls); WriteImplementationHeader(trustedWriter, "Trusted", new List()); Dictionary allModules = new Dictionary(StringComparer.CurrentCultureIgnoreCase); foreach (string file in files) { string filename = new FileInfo(file).FullName; string moduleName = ModuleNameFromFilename(filename); if (!allModules.ContainsKey(moduleName)) { AddImports(allModules, filename); allModules.Add(moduleName, filename); } } return allModules; } public void CompileSpecEnd() { trustedIWriter.WriteLine("}"); trustedWriter.WriteLine("}"); trustedIWriter.Close(); trustedWriter.Close(); foreach (var writers in outDirWriters.Values) { writers.Item1.WriteLine("}"); writers.Item1.Close(); writers.Item2.WriteLine("}"); writers.Item2.Close(); } if (outListWriter != null) { outListWriter.Close(); } } public void DeclareProgram(Program program) { foreach (ModuleDefinition mod in program.Modules) { foreach (TopLevelDecl top in mod.TopLevelDecls) { ClassDecl cls = top as ClassDecl; DatatypeDecl dataDecl = top as DatatypeDecl; if (cls != null) { foreach (MemberDecl member in cls.Members) { Method method = member as Method; Function function = member as Function; if (method != null && !allMethods.ContainsKey(method.Name)) { allMethods[method.Name] = method; } if (function != null && !allFunctions.ContainsKey(function.Name)) { allFunctions[function.Name] = function; } } } if (dataDecl != null && !allDatatypes.ContainsKey(dataDecl.Name)) { allDatatypes[dataDecl.Name] = dataDecl; } } } } public void CompileProgram(Program program) { foreach (ModuleDefinition mod in program.Modules) { Util.DebugWriteLine("module: " + mod.Name + " " + mod.GetType()); //Console.WriteLine("type Tri = Triple(Pwd:int, Salt:int, Key:int);"); //Console.WriteLine("type Map = MapCons(Domain:[Tri]bool, Range:[Tri]int);"); //Console.WriteLine("var $ghost_Hashed:Map;"); foreach (TopLevelDecl top in mod.TopLevelDecls) { Util.DebugWriteLine("top-decl: " + top.Name + " " + top.GetType()); ClassDecl cls = top as ClassDecl; if (cls != null) { foreach (MemberDecl member in cls.Members) { //Console.Error.WriteLine("declaration: " + member + " :: " + member.GetType()); Util.DebugWriteLine("member-decl: " + member.Name + " " + member.GetType()); Field field = member as Field; Method method = member as Method; Function function = member as Function; if (field != null && !allStaticFields.Contains(field.Name)) { allStaticFields.Add(field.Name); if (!field.IsGhost) { throw new Exception("not implemented: non-ghost fields: " + field.Name); } var writers = ChooseWriter(field.tok, field.Name); new CompileField(this, field, writers.Item2).Compile(); } if (method != null && method.TypeArgs.Count == 0) { if (method.Body == null) { //Console.Error.WriteLine("declaration: " + member + " :: " + member.GetType()); } Compile_Method(method, new Dictionary()); AddMethodAsLemma(method); } else if (function != null && function.TypeArgs.Count == 0) { Compile_Function(function, new Dictionary()); } else { //Console.Error.WriteLine("skipping declaration: " + member + " :: " + member.GetType()); } } } } } } public void CompileSequenceSpecs() { Compile_Function(FindFunction("dummy_seqs"), new Dictionary()); List seqFunctions = allFunctions.Values.Where(f => IsSeqFile(f.tok.filename, true)).ToList(); List seqMethods = allMethods.Values.Where(m => IsSeqFile(m.tok.filename, true)).ToList(); for (int i = 0; i < compileDatatypeList.Count; i++) { //- note that compileDatatypes may get extended during loop var app = compileDatatypeList[i]; string dataName = app.AppName(); // List List ctors = compileDatatypes[app].AsDatatype.Ctors; bool isSeq = dataName.StartsWith("Seq_"); if (isSeq) { seqFunctions.ForEach(f => Compile_Function(f, app.typeArgs)); seqMethods.ForEach(m => Compile_Method(m, app.typeArgs)); } } } public void CompileSpec(DafnySpec_Options options, IList files) { Dictionary allModules = CompileSpecStart(options, files); Program program; string errors = Microsoft.Dafny.Main.ParseCheck( allModules.Values.ToList(), "DAFNYCC_PROGRAM", out program); if (errors != null) { throw new Exception(errors); } Util.DebugWriteLine(program); DeclareProgram(program); CompileProgram(program); CompileDatatypesGhost(); CompileSequenceSpecs(); files.ToList().ForEach(f => ChooseOutDirWriter(f)); //- make sure even empty modules get written CompileSpecEnd(); } } ================================================ FILE: ironclad-apps/tools/DafnySpec/DafnySpec.csproj ================================================ Debug AnyCPU {D2031609-BC52-4F67-8560-6D8F07C38497} Exe Properties DafnySpec dafnyspec v4.5 512 AnyCPU true full false bin\ DEBUG;TRACE prompt 4 AnyCPU pdbonly true bin\Release\ TRACE prompt 4 {be5e53dc-b929-4031-b85b-71138ad363cf} DafnySpecAst {0c1e9d4f-6aae-455c-b5c7-5de6063ca99e} Parser ================================================ FILE: ironclad-apps/tools/DafnySpec/DafnySpec.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0.30501.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DafnySpec", "DafnySpec.csproj", "{D2031609-BC52-4F67-8560-6D8F07C38497}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DafnySpecAst", "DafnySpecAst\DafnySpecAst.csproj", "{BE5E53DC-B929-4031-B85B-71138AD363CF}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Parser", "Parser\Parser.csproj", "{0C1E9D4F-6AAE-455C-B5C7-5DE6063CA99E}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {D2031609-BC52-4F67-8560-6D8F07C38497}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D2031609-BC52-4F67-8560-6D8F07C38497}.Debug|Any CPU.Build.0 = Debug|Any CPU {D2031609-BC52-4F67-8560-6D8F07C38497}.Release|Any CPU.ActiveCfg = Release|Any CPU {D2031609-BC52-4F67-8560-6D8F07C38497}.Release|Any CPU.Build.0 = Release|Any CPU {BE5E53DC-B929-4031-B85B-71138AD363CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {BE5E53DC-B929-4031-B85B-71138AD363CF}.Debug|Any CPU.Build.0 = Debug|Any CPU {BE5E53DC-B929-4031-B85B-71138AD363CF}.Release|Any CPU.ActiveCfg = Release|Any CPU {BE5E53DC-B929-4031-B85B-71138AD363CF}.Release|Any CPU.Build.0 = Release|Any CPU {0C1E9D4F-6AAE-455C-B5C7-5DE6063CA99E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0C1E9D4F-6AAE-455C-B5C7-5DE6063CA99E}.Debug|Any CPU.Build.0 = Debug|Any CPU {0C1E9D4F-6AAE-455C-B5C7-5DE6063CA99E}.Release|Any CPU.ActiveCfg = Release|Any CPU {0C1E9D4F-6AAE-455C-B5C7-5DE6063CA99E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: ironclad-apps/tools/DafnySpec/DafnySpecAst/DafnySpecAst.cs ================================================ using System; using System.IO; using System.Collections.Generic; using System.Collections.ObjectModel; using Microsoft.Dafny; using Bpl = Microsoft.Boogie; namespace Microsoft.Boogie { public interface IToken { string filename { get; } int line { get; } } public class Token: IToken { public static Token NoToken = new Token("nofile", 0); string _filename; int _line; public Token(string filename, int line) { this._filename = filename; this._line = line; } public string filename { get { return _filename; } } public int line { get { return _line; } } } } namespace Microsoft.Basetypes { public class BigDec { string s; internal BigDec(string s) { this.s = s; } public static BigDec FromString(string s) { return new BigDec(s); } public override string ToString() { return s; } public string ToDecimalString() { return s; } } } namespace Microsoft.Dafny { using Token = Bpl.Token; public class Attributes { public string Name; public List Args; public Attributes Prev; public Attributes(string Name, List Args, Attributes Prev) { this.Name = Name; this.Args = Args; this.Prev = Prev; } public static void Resolve(Resolver resolver, Attributes attrs) { if (attrs != null) { for (int i = 0; i < attrs.Args.Count; i++) { attrs.Args[i] = attrs.Args[i].Resolve(resolver, null); } Resolve(resolver, attrs.Prev); } } public static bool Contains(Attributes attrs, string name) { return attrs != null && (attrs.Name == name || Contains(attrs.Prev, name)); } public static List FindExpressions(Attributes attrs, string nm) { for (; attrs != null; attrs = attrs.Prev) { if (attrs.Name == nm) { return attrs.Args; } } return null; } } public abstract class Type { public static IntType Int = new IntType(); public static NatType Nat = new NatType(); public static RealType Real = new RealType(); public static BoolType Bool = new BoolType(); public enum NumericPersuation { Int, Real } public bool IsNumericBased(NumericPersuation p) { return (this is IntType && p == NumericPersuation.Int) || (this is RealType && p == NumericPersuation.Real); } public abstract string TypeName(object o); public virtual DatatypeDecl AsDatatype { get { return null; } } public override abstract bool Equals(Object o); public override int GetHashCode() { return 0; } public abstract Type Subst(Dictionary map); public virtual void Resolve(Resolver resolver) {} } public class TypeParameter { public string Name; public TypeParameter(string Name) { this.Name = Name; } public TypeParameter(Token tok, string Name) { this.Name = Name; } public override bool Equals(object other) { TypeParameter that = other as TypeParameter; return that != null && that.Name == this.Name; } public override int GetHashCode() { return Name.GetHashCode(); } } public class TypeProxy: Type { public Type T; public TypeProxy(Type T) { this.T = T; } public override bool Equals(Object o) { return T.Equals(o); } public override int GetHashCode() { return T.GetHashCode(); } public override string TypeName(object o) { return T.TypeName(o); } public override Type Subst(Dictionary map) { return new TypeProxy(T.Subst(map)); } } public class IntType: Type { public override bool Equals(Object o) { return o is IntType && !(o is NatType); } public override int GetHashCode() { return 0; } public override string TypeName(object o) { return "int"; } public override Type Subst(Dictionary map) { return this; } } public class NatType: IntType { public override bool Equals(Object o) { return o is NatType; } public override int GetHashCode() { return 0; } public override string TypeName(object o) { return "nat"; } public override Type Subst(Dictionary map) { return this; } } public class RealType: Type { public override bool Equals(Object o) { return o is RealType; } public override int GetHashCode() { return 0; } public override string TypeName(object o) { return "real"; } public override Type Subst(Dictionary map) { return this; } } public class BoolType: Type { public override bool Equals(Object o) { return o is BoolType; } public override int GetHashCode() { return 0; } public override string TypeName(object o) { return "bool"; } public override Type Subst(Dictionary map) { return this; } } public class SeqType: Type { public Type Arg; public SeqType(Type Arg) { this.Arg = Arg; } public override bool Equals(Object o) { SeqType that = o as SeqType; return that != null && Arg.Equals(that.Arg); } public override int GetHashCode() { return Arg.GetHashCode(); } public override string TypeName(object o) { return "seq<" + Arg.TypeName(o) + ">"; } public override Type Subst(Dictionary map) { return new SeqType(Arg.Subst(map)); } public override void Resolve(Resolver resolver) { Arg.Resolve(resolver); } } public class MapType: Type { public Type Domain; public Type Range; public MapType(Type Domain, Type Range) { this.Domain = Domain; this.Range = Range; } public override bool Equals(Object o) { MapType that = o as MapType; return that != null && Domain.Equals(that.Domain) && Range.Equals(that.Range); } public override int GetHashCode() { return Range.GetHashCode(); } public override string TypeName(object o) { return "map<" + Domain.TypeName(o) + "," + Range.TypeName(o) + ">"; } public override Type Subst(Dictionary map) { return new MapType(Domain.Subst(map), Range.Subst(map)); } public override void Resolve(Resolver resolver) { Domain.Resolve(resolver); Range.Resolve(resolver); } } public class UserDefinedType: Type { DatatypeDecl datatype; public string Name; public Attributes Attributes; public List TypeArgs; public bool IsTypeParameter; public UserDefinedType(Token tok, string name, DatatypeDecl decl, List typeArgs, bool IsTypeParameter, Attributes Attributes) { this.datatype = decl; this.Name = name; this.Attributes = Attributes; this.TypeArgs = typeArgs; this.IsTypeParameter = IsTypeParameter; } public UserDefinedType(Token tok, string name, DatatypeDecl decl, List typeArgs) :this(tok, name, decl, typeArgs, false, null) { } internal UserDefinedType(string name) :this(Token.NoToken, name, null, null, true, null) { } public override string TypeName(object o) { if (TypeArgs == null) { return Name; } string[] args = new string[TypeArgs.Count]; for (int i = 0; i < args.Length; i++) args[i] = TypeArgs[i].TypeName(o); return Name + "<" + String.Join(",", args) + ">"; } public override DatatypeDecl AsDatatype { get { return datatype; } } public override bool Equals(Object o) { UserDefinedType that = o as UserDefinedType; if (that == null || Name != that.Name || IsTypeParameter != that.IsTypeParameter || TypeArgs.Count != that.TypeArgs.Count) { return false; } for (int i = 0; i < TypeArgs.Count; i++) { if (!TypeArgs[i].Equals(that.TypeArgs[i])) { return false; } } return true; } public override int GetHashCode() { return Name.GetHashCode(); } public override Type Subst(Dictionary map) { if (IsTypeParameter && map.ContainsKey(new TypeParameter(Name))) { return map[new TypeParameter(Name)]; } else { List typeArgs = new List(); foreach (Type t in TypeArgs) { typeArgs.Add(t.Subst(map)); } return new UserDefinedType(Token.NoToken, Name, datatype, typeArgs, IsTypeParameter, Attributes); } } public override void Resolve(Resolver resolver) { if (resolver.typeParams.ContainsKey(Name)) { IsTypeParameter = true; } else { datatype = resolver.Find(resolver.datatypes, Name); } if (TypeArgs != null) { foreach (Type arg in TypeArgs) { arg.Resolve(resolver); } } } } public class BoundVar { public string Name; public Type Type; public bool IsGhost; public BoundVar(Token tok, string name, Type Type) { this.Name = name; this.Type = Type; } public void Resolve(Resolver resolver, Type t) { if (this.Type == null) { this.Type = t; } Type.Resolve(resolver); this.IsGhost = resolver.IsGhost(); } } public class Formal { public string Name; public Type Type; public bool IsGhost; public Formal(string name, Type type, bool IsGhost) { this.Name = name; this.Type = type; this.IsGhost = IsGhost; } public Formal(Token tok, string name, Type type, bool b1, bool b2) { if (b1 != b2) { throw new Exception("internal error"); } this.Name = name; this.Type = type; this.IsGhost = b1; } public void Resolve(Resolver resolver) { Type.Resolve(resolver); IsGhost = IsGhost || resolver.IsGhost(); } } public class Expression { public Token tok = Token.NoToken; public Type Type; public Expression Resolved; public bool WasResolved() { return false; } public virtual Expression Resolve(Resolver resolver, Type t) { Type = (Type == null) ? t : Type; return this; } } public class IdentifierExpr: Expression { public string Name; public LocalVariable Var; public IdentifierExpr(Token tok, string name) { this.Name = name; } public override Expression Resolve(Resolver resolver, Type t) { VarDecl VarDecl = resolver.Var(Name); if (VarDecl == null) { if (resolver.fields.ContainsKey(Name)) { MemberSelectExpr ret = new MemberSelectExpr(new ImplicitThisExpr(), Name); ret.Member = resolver.fields[Name]; ret.Type = resolver.fields[Name].Type; return ret; } else if (resolver.constructors.ContainsKey(Name)) { DatatypeCtor ctor = resolver.constructors[Name]; DatatypeValue ret = new DatatypeValue(new List(), ctor, new List(), new UserDefinedType(Token.NoToken, ctor.datatype.Name, ctor.datatype, new List())); return ret; } else { throw new Exception("cannot find variable/field/constructor named " + Name); } } else { Var = new LocalVariable(tok, tok, Name, VarDecl.Type, VarDecl.IsGhost); resolver.CollectVar(Name); } Type = Var.Type; return this; } } public class ThisExpr: Expression { } public class ImplicitThisExpr: Expression { public ImplicitThisExpr() { this.Type = Type.Bool; } // HACK } public class ParensExpression: Expression { public Expression E; private ParensExpression() {} // never created } public abstract class StmtExpr: Expression { public abstract Statement S { get; } public Expression E; } public class StmtExprCall: StmtExpr { string Name; List Args; CallStmt call; public override Statement S { get { return call; } } public StmtExprCall(string Name, List Args, Expression E) { this.Name = Name; this.Args = Args; this.E = E; } public override Expression Resolve(Resolver resolver, Type t) { Method method = resolver.Find(resolver.methods, Name); for (int i = 0; i < Args.Count; i++) { Args[i] = Args[i].Resolve(resolver, method.Formals[i].Type); } call = new CallStmt(Args, new Dictionary(), method); E = E.Resolve(resolver, t); Type = E.Type; return this; } } public delegate LiteralExpr MakeBigInt(string i); public class LiteralExpr: Expression { public object Value; public LiteralExpr(object Value) { this.Value = Value; } public override Expression Resolve(Resolver resolver, Type t) { Type = Value is bool ? (Type)Type.Bool : Value is Microsoft.Basetypes.BigDec ? (Type)Type.Real : (Type)Type.Int; return this; } public static bool IsTrue(Expression e) { LiteralExpr lit = e as LiteralExpr; return lit != null && lit.Value is bool && ((bool)lit.Value); } public static MakeBigInt MakeBigInt; } public class StringLiteralExpr : LiteralExpr { public StringLiteralExpr(string s) : base(s) {} } public class UnaryExpr: Expression { } public class UnaryOpExpr: UnaryExpr { public enum Opcode { Not, Cardinality, Fresh } public Opcode Op; public Expression E; public UnaryOpExpr(Token tok, Opcode op, Expression e) { this.Op = op; this.E = e; } public override Expression Resolve(Resolver resolver, Type t) { switch (Op) { case Opcode.Not: E = E.Resolve(resolver, Type.Bool); Type = Type.Bool; break; case Opcode.Cardinality: E = E.Resolve(resolver, null); Type = Type.Int; break; case Opcode.Fresh: E = E.Resolve(resolver, Type.Bool); Type = Type.Bool; break; } return this; } } public class ConversionExpr : UnaryExpr { public Type ToType; public Expression E; public ConversionExpr(Type ToType, Expression Input) { this.ToType = ToType; this.E = Input; } public override Expression Resolve(Resolver resolver, Type t) { this.Type = ToType; this.E = this.E.Resolve(resolver, t); return this; } } public class BinaryExpr: Expression { public enum Opcode { None, Iff, Imp, Exp, And, Or, In, NotIn, Disjoint, Eq, Neq, Le, Lt, Ge, Gt, Add, Sub, Mul, Div, Mod, } public enum ResolvedOpcode { None, SeqEq, SeqNeq, Concat } public Opcode Op = Opcode.None; public ResolvedOpcode ResolvedOp = ResolvedOpcode.None; public Expression E0; public Expression E1; public BinaryExpr(Token tok, Opcode op, Expression e0, Expression e1) { this.Op = op; this.E0 = e0; this.E1 = e1; } public override Expression Resolve(Resolver resolver, Type t) { Type t0 = null; Type t1 = null; switch (Op) { case Opcode.Iff: case Opcode.Imp: case Opcode.Exp: case Opcode.And: case Opcode.Or: t0 = Type.Bool; t1 = Type.Bool; Type = Type.Bool; break; case Opcode.Eq: case Opcode.Neq: Type = Type.Bool; break; case Opcode.Le: case Opcode.Lt: case Opcode.Ge: case Opcode.Gt: t0 = Type.Int; t1 = Type.Int; Type = Type.Bool; break; case Opcode.Sub: case Opcode.Mul: case Opcode.Div: case Opcode.Mod: t0 = Type.Int; t1 = Type.Int; Type = Type.Int; break; } switch (Op) { case Opcode.Eq: case Opcode.Neq: case Opcode.Le: case Opcode.Lt: case Opcode.Ge: case Opcode.Gt: //- ((a < b) < c) < d //- --> //- ((a < b) < c) && c < d BinaryExpr B0 = E0 as BinaryExpr; if (B0 != null) { switch (B0.Op) { case Opcode.Eq: case Opcode.Neq: case Opcode.Le: case Opcode.Lt: case Opcode.Ge: case Opcode.Gt: Expression _e0 = B0; Expression _e1 = new BinaryExpr(tok, Op, B0.E1, E1); Expression _e = new BinaryExpr(tok, Opcode.And, _e0, _e1); return _e.Resolve(resolver, Type.Bool); } } break; } E0 = E0.Resolve(resolver, t0); E1 = E1.Resolve(resolver, t1); if (E0.Type == null) { E0 = E0.Resolve(resolver, E1.Type); } // HACK if (E1.Type == null) { E1 = E1.Resolve(resolver, E0.Type); } // HACK switch (Op) { case Opcode.Add: if (E0.Type is SeqType) { ResolvedOp = ResolvedOpcode.Concat; Type = E0.Type; } else if (E0.Type is RealType) { Type = E0.Type; } else { Type = Type.Int; } break; case Opcode.Sub: case Opcode.Mul: case Opcode.Div: if (E0.Type is RealType) { Type = E0.Type; } break; case Opcode.Eq: if (E0.Type is SeqType) { ResolvedOp = ResolvedOpcode.SeqEq; } break; case Opcode.Neq: if (E0.Type is SeqType) { ResolvedOp = ResolvedOpcode.SeqNeq; } break; } return this; } public static string OpcodeString(Opcode Op) { switch (Op) { case Opcode.Iff: return "<==>"; case Opcode.Imp: return "==>"; case Opcode.Exp: return "<=="; case Opcode.And: return "&&"; case Opcode.Or: return "||"; case Opcode.In: return null; case Opcode.NotIn: return null; case Opcode.Disjoint: return null; case Opcode.Eq: return "=="; case Opcode.Neq: return "!="; case Opcode.Le: return "<="; case Opcode.Lt: return "<"; case Opcode.Ge: return ">="; case Opcode.Gt: return ">"; case Opcode.Add: return "+"; case Opcode.Sub: return "-"; case Opcode.Mul: return "*"; case Opcode.Div: return "/"; case Opcode.Mod: return "%"; } return null; } } public class ITEExpr: Expression { public Expression Test; public Expression Thn; public Expression Els; public ITEExpr(Expression Test, Expression Thn, Expression Els) { this.Test = Test; this.Thn = Thn; this.Els = Els; } public override Expression Resolve(Resolver resolver, Type t) { Test = Test.Resolve(resolver, Type.Bool); Thn = Thn.Resolve(resolver, t); Els = Els.Resolve(resolver, t); if (Thn.Type == null) { Thn = Thn.Resolve(resolver, Els.Type); } // HACK if (Els.Type == null) { Els = Els.Resolve(resolver, Thn.Type); } // HACK Type = Thn.Type; return this; } } public abstract class QuantifierExpr: Expression { public List BoundVars; public Attributes Attributes; public Expression Term; public QuantifierExpr(List BoundVars, Attributes Attributes, Expression Term) { this.BoundVars = BoundVars; this.Attributes = Attributes; this.Term = Term; } public override Expression Resolve(Resolver resolver, Type t) { foreach (BoundVar x in BoundVars) { //- "Infer" missing types as int. If we're wrong, type checking will fail and the //- programmer will have to supply an explicit type. // TODO: should we implement real type inference? Type tx = (x.Type != null) ? x.Type : Type.Int; x.Resolve(resolver, tx); resolver.PushVar(x); } Attributes.Resolve(resolver, Attributes); Term = Term.Resolve(resolver, Type.Bool); foreach (BoundVar x in BoundVars) { resolver.PopVar(x.Name); } Type = Type.Bool; return this; } } public class ExistsExpr: QuantifierExpr { public ExistsExpr(List BoundVars, Attributes Attributes, Expression Term): base(BoundVars, Attributes, Term) {} } public class ForallExpr: QuantifierExpr { public ForallExpr(List BoundVars, Attributes Attributes, Expression Term): base(BoundVars, Attributes, Term) {} } public class Lhs { } public class LetExpr: Expression { public bool tryToEliminate; public bool Exact; public List LHSs; public List RHSs; public Expression Body; public LetExpr(bool Exact, List LHSs, List RHSs, Expression Body) { this.Exact = Exact; this.LHSs = LHSs; this.RHSs = RHSs; this.Body = Body; } public override Expression Resolve(Resolver resolver, Type t) { resolver.PushVarCollect(); for (int i = 0; i < RHSs.Count; i++) { RHSs[i] = RHSs[i].Resolve(resolver, LHSs[i].Var.Type); LHSs[i].Var.Resolve(resolver, RHSs[i].Type); resolver.PushVar(LHSs[i].Var); } Body = Body.Resolve(resolver, t); for (int i = 0; i < RHSs.Count; i++) { resolver.PopVar(LHSs[i].Var.Name); } Type = Body.Type; Dictionary neededVars = resolver.PopVarCollect(); bool needed = false; foreach (ExprLhs lhs in LHSs) { if (neededVars.ContainsKey(lhs.Var.Name)) { needed = true; } } if (tryToEliminate && !needed) { return Body; } return this; } } public class MatchCaseExpr { public string name; public DatatypeCtor Ctor; public List Arguments; public Expression Body; public MatchCaseExpr(string name, List Arguments, Expression Body) { this.name = name; this.Arguments = Arguments; this.Body = Body; } public void Resolve(Resolver resolver, DatatypeDecl data, Type t) { foreach (DatatypeCtor ctor in data.Ctors) { if (ctor.Name == name) { Ctor = ctor; for (int i = 0; i < Arguments.Count; i++) { Arguments[i].Resolve(resolver, ctor.Formals[i].Type); resolver.PushVar(Arguments[i]); } Body = Body.Resolve(resolver, t); for (int i = 0; i < Arguments.Count; i++) { resolver.PopVar(Arguments[i].Name); } } } } } public class MatchExpr: Expression { public Expression Source; public List Cases; public List MissingCases; public MatchExpr(Expression Source, List Cases) { this.Source = Source; this.Cases = Cases; this.MissingCases = new List(); } public override Expression Resolve(Resolver resolver, Type t) { Type = t; Source = Source.Resolve(resolver, null); DatatypeDecl data = resolver.Find(resolver.datatypes, Source.Type.AsDatatype.Name); foreach (MatchCaseExpr c in Cases) { c.Resolve(resolver, data, t); t = c.Body.Type; Type = t; } return this; } } public class OldExpr: Expression { public Expression E; public OldExpr(Expression E) { this.E = E; } public override Expression Resolve(Resolver resolver, Type t) { E = E.Resolve(resolver, t); Type = E.Type; return this; } } public class FunctionCallExpr: Expression { public string name; public List typeArgs; public Function Function; public Dictionary TypeArgumentSubstitutions; public List Args; public FunctionCallExpr(string name, List typeArgs, List Args) { this.name = name; this.typeArgs = typeArgs; this.Args = Args; } public override Expression Resolve(Resolver resolver, Type t) { List typeParams = null; List formals = null; Expression ret = this; List parentParams = (resolver.currentFunction != null) ? resolver.currentFunction.TypeArgs : (resolver.currentMethod != null) ? resolver.currentMethod.TypeArgs : null; if (parentParams != null) { typeArgs = new List(); foreach (TypeParameter p in parentParams) { typeArgs.Add(new UserDefinedType(p.Name)); } // HACK } if (resolver.functions.ContainsKey(name)) { Function = resolver.functions[name]; if (Function == resolver.currentFunction) { Function.IsRecursive = true; } // TODO: mutual recursion typeParams = Function.TypeArgs; formals = Function.Formals; Type = Function.ResultType; } else if (resolver.constructors.ContainsKey(name)) { DatatypeCtor ctor = resolver.constructors[name]; DatatypeDecl data = ctor.datatype; typeParams = data.TypeArgs; formals = ctor.Formals; Type = new UserDefinedType(Token.NoToken, data.Name, data, typeArgs); ret = new DatatypeValue(typeArgs, ctor, Args, Type); } else if (name == "IntToReal") { Function = new Function(name); formals = new List(new Formal[] { new Formal("x", Type.Int, true) }); Type = Type.Real; } else if (name == "RealToInt") { Function = new Function(name); formals = new List(new Formal[] { new Formal("x", Type.Real, true) }); Type = Type.Int; } else { throw new Exception("function not found: " + name); } // HACK: since Dafny has no syntax for explicit function type arguments, and we have no type inference, use heuristic for typeArgs: TypeArgumentSubstitutions = new Dictionary(); for (int i = 0; i < typeArgs.Count; i++) { TypeArgumentSubstitutions.Add(typeParams[i], typeArgs[i]); typeArgs[i].Resolve(resolver); } //foreach (Formal f in formals) { f.Resolve(resolver); } for (int i = 0; i < Args.Count; i++) { Args[i] = Args[i].Resolve(resolver, formals[i].Type); } return ret; } } public class DatatypeValue: Expression { public List InferredTypeArgs; public DatatypeCtor Ctor; public List Arguments; public DatatypeValue(List InferredTypeArgs, DatatypeCtor Ctor, List Arguments, Type t) { this.InferredTypeArgs = InferredTypeArgs; this.Ctor = Ctor; this.Arguments = Arguments; this.Type = t; } public override Expression Resolve(Resolver resolver, Type t) { for (int i = 0; i < Arguments.Count; i++) { Arguments[i] = Arguments[i].Resolve(resolver, Ctor.Formals[i].Type); } return this; } } public class LocalVariable { public String Name; public Type Type; public bool IsGhost; public LocalVariable(Token Tok, Token EndTok, String Name, Type Type, bool IsGhost) { this.Name = Name; this.Type = Type; this.IsGhost = IsGhost; } } public class MemberSelectExpr: Expression { public Expression Obj; public string MemberName; public MemberDecl Member; internal Dictionary TypeArgumentSubst; public MemberSelectExpr(Expression Obj, string FieldName) { this.Obj = Obj; this.MemberName = FieldName; } public MemberSelectExpr(Method Method, Dictionary TypeArgumentSubstitutions) { this.Member = Method; this.TypeArgumentSubst = TypeArgumentSubstitutions; } public Dictionary TypeArgumentSubstitutions() { return TypeArgumentSubst; } public override Expression Resolve(Resolver resolver, Type t) { Obj = Obj.Resolve(resolver, null); DatatypeDecl data = Obj.Type.AsDatatype; if (MemberName.EndsWith("?")) { Type = Type.Bool; } else if (data != null) { foreach (DatatypeCtor ctor in data.Ctors) { foreach (Formal f in ctor.Formals) { if (f.Name == MemberName) { Member = new DatatypeDestructor(ctor, Obj.tok, null, f.Name, f.IsGhost, f.Type); Type = f.Type; } } } } return this; } } public class SeqSelectExpr: Expression { public bool SelectOne; public Expression Seq; public Expression E0; public Expression E1; public SeqSelectExpr(bool SelectOne, Expression Seq, Expression E0, Expression E1) { this.SelectOne = SelectOne; this.Seq = Seq; this.E0 = E0; this.E1 = E1; } public override Expression Resolve(Resolver resolver, Type t) { Seq = Seq.Resolve(resolver, null); if (E0 != null) { E0 = E0.Resolve(resolver, Type.Int); } if (E1 != null) { E1 = E1.Resolve(resolver, Type.Int); } Type = SelectOne ? ((SeqType)Seq.Type).Arg : Seq.Type; return this; } } public class SeqUpdateExpr: Expression { public Expression Seq; public Expression Index; public Expression Value; public Expression ResolvedUpdateExpr = null; public SeqUpdateExpr(Expression Seq, Expression Index, Expression Value) { this.Seq = Seq; this.Index = Index; this.Value = Value; } static int xCount = 0; public override Expression Resolve(Resolver resolver, Type t) { Seq = Seq.Resolve(resolver, null); if (Seq.Type is SeqType) { Index = Index.Resolve(resolver, Type.Int); Value = Value.Resolve(resolver, ((SeqType)Seq.Type).Arg); Type = Seq.Type; return this; } else { UserDefinedType ut = (UserDefinedType)(Seq.Type); string name = ((IdentifierExpr)Index).Name; foreach (DatatypeCtor ctor in ut.AsDatatype.Ctors) { foreach (Formal formal in ctor.Formals) { if (formal.Name == name) { //- Seq[name := Value] //- --> //- let x := Seq in ctor(x.f1, ..., Value, ..., x.fn) IdentifierExpr x = new IdentifierExpr(tok, "#UPDATE##" + (xCount++)); List args = new List(); // args = (x.f1, ..., Value, ..., x.fn) foreach (Formal f in ctor.Formals) { Expression arg = (f.Name == name) ? Value : new MemberSelectExpr(x, f.Name); args.Add(arg); } Expression body = new DatatypeValue(ut.TypeArgs, ctor, args, ut); Expression ret = new LetExpr(true, new List(new ExprLhs[] { new ExprLhs(new BoundVar(tok, x.Name, Seq.Type)) }), new List(new Expression[] { Seq }), body); return ret.Resolve(resolver, Seq.Type); } } } throw new Exception("field update selector not found: " + name); } } } public class SeqDisplayExpr: Expression { public List Elements; public SeqDisplayExpr(List Elements) { this.Elements = Elements; } public override Expression Resolve(Resolver resolver, Type t) { SeqType tSeq = t as SeqType; for (int i = 0; i < Elements.Count; i++) { Elements[i] = Elements[i].Resolve(resolver, tSeq == null ? null : tSeq.Arg); } Type = (Elements.Count == 0) ? t : new SeqType(Elements[0].Type); return this; } } public class ExprLhs { public BoundVar Var; public ExprLhs(BoundVar Var) { this.Var = Var; } } public class ExprRhs { public Expression Expr; public ExprRhs(Expression Expr) { this.Expr = Expr; } } public class SpecExpression { public Attributes Attributes; public Expression E; public SpecExpression(Attributes Attributes, Expression E) { this.Attributes = Attributes; this.E = E; } public void Resolve(Resolver resolver) { Attributes.Resolve(resolver, Attributes); E = E.Resolve(resolver, Type.Bool); } } public class FrameExpression { public Token tok; public Expression E = new ThisExpr(); public string FieldName; public Field Field; public FrameExpression(string FieldName) { this.FieldName = FieldName; } public void Resolve(Resolver resolver) { Field = resolver.Find(resolver.fields, FieldName); } } public class Statement { public Token Tok = Token.NoToken; } public class BlockStmt: Statement { public List Body; public BlockStmt() { Body = new List(); } } public class VarDeclStmt: Statement { public List Locals; public object Update; public bool IsGhost; //public VarDeclStmt(string name, Type type, bool isGhost) { this.Name = name; this.Type = type; this.IsGhost = isGhost; } //public VarDeclStmt(Token tok1, Token tok2, string name, Type type, bool isGhost): this(name, type, isGhost) {} } internal class VarDecl { public string Name; public Type Type; public bool IsGhost; public VarDecl(string name, Type type, bool isGhost) { this.Name = name; this.Type = type; this.IsGhost = isGhost; } public VarDecl(Token tok1, Token tok2, string name, Type type, bool isGhost): this(name, type, isGhost) {} } public class IfStmt: Statement { public Expression Guard; public Statement Thn; public Statement Els; } public class AssertStmt: Statement { public Expression Expr; } public class AssignStmt: Statement { public Expression Lhs; public ExprRhs Rhs; } public class CallStmt: Statement { public List Lhs; public List Args; public MemberSelectExpr MethodSelect; internal CallStmt(List Args, Dictionary TypeArgumentSubstitutions, Method Method) { this.Lhs = new List(); this.Args = Args; this.MethodSelect = new MemberSelectExpr(Method, TypeArgumentSubstitutions); } } public class CalcStmt: Statement { public class BinaryCalcOp { public BinaryExpr.Opcode Op; } public List Steps; public List Hints; public BinaryCalcOp Op; public static Expression Lhs(Expression e) { return null; } } public class ForallStmt: Statement { public List BoundVars; public List Ens; public Expression Range; public Statement Body; } public class AssignSuchThatStmt: Statement { public List Lhss; public Expression Expr; } public class UpdateStmtRhs { public Attributes Attributes; } public class ConcreteSyntaxStatement: Statement { public List ResolvedStatements; } public class UpdateStmt: Statement { public List Rhss; public List ResolvedStatements; } public class Mod { public List Expressions; public Mod(List Expressions) { this.Expressions = Expressions; } } public class Decreases { public List Expressions; public Decreases(List Expressions) { this.Expressions = Expressions; } public void Resolve(Resolver resolver) { for (int i = 0; i < Expressions.Count; i++) { Expressions[i] = Expressions[i].Resolve(resolver, Type.Int); if (Expressions[i].Type is NatType) { Expressions[i].Type = Type.Int; } // HACK } } } public interface ICallable { Decreases Decreases { get; } List Ins { get; } } public class MemberDecl { public Token tok; public Attributes Attributes; public string Name; public bool IsGhost; public bool IsStatic = false; public MemberDecl(Token tok, Attributes Attributes, string Name, bool IsGhost) { this.tok = tok; this.Attributes = Attributes; this.Name = Name; this.IsGhost = IsGhost; } } public class Field: MemberDecl { public Type Type; public Field(Token tok, Attributes Attributes, string Name, bool IsGhost, Type Type) :base(tok, Attributes, Name, IsGhost) { this.Type = Type; } //internal VarDeclStmt AsVarDecl() { return new VarDeclStmt(Name, Type, IsGhost); } } public class Function: MemberDecl, ICallable { public ClassDecl EnclosingClass; public List TypeArgs; public List Formals; public Type ResultType; public List Req; public List Ens; Decreases decreases; public Expression Body; public List Reads = new List(); // TODO public bool IsRecursive; internal Function(string Name): base(Token.NoToken, null, Name, true) {} public Function(Token tok, Attributes Attributes, string Name, bool IsGhost, List TypeArgs, List Formals, Type ResultType, List Req, List Ens, Decreases decreases, Expression Body) :base(tok, Attributes, Name, IsGhost) { this.EnclosingClass = ClassDecl.TheClass; this.TypeArgs = TypeArgs; this.Formals = new List(); foreach (Formal f in Formals) { this.Formals.Add(new Formal(f.Name, f.Type, f.IsGhost || IsGhost)); } this.ResultType = ResultType; this.Req = Req; this.Ens = Ens; this.decreases = decreases; this.Body = Body; } public Decreases Decreases { get { return decreases; } } public List Ins { get { return Formals; } } } public class Method: MemberDecl, ICallable { Decreases decreases; public List TypeArgs; public List Formals; public List Outs; public List Req; public List Ens; public Mod Mod; public BlockStmt Body; public Method(Token tok, Attributes Attributes, string Name, bool IsGhost, List TypeArgs, List Formals, List Outs, List Req, List Ens, Mod Mod, Decreases decreases, BlockStmt Body) :base(tok, Attributes, Name, IsGhost) { this.TypeArgs = TypeArgs; this.Formals = new List(); foreach (Formal f in Formals) { this.Formals.Add(new Formal(f.Name, f.Type, f.IsGhost || IsGhost)); } this.Outs = new List(); foreach (Formal f in Outs) { this.Outs.Add(new Formal(f.Name, f.Type, f.IsGhost || IsGhost)); } this.Req = Req; this.Ens = Ens; this.Mod = Mod; this.decreases = decreases; this.Body = Body; } public Decreases Decreases { get { return decreases; } } public List Ins { get { return Formals; } } } abstract public class Lemma: Method { public Lemma(Token tok, Attributes Attributes, string Name, bool IsGhost, List TypeArgs, List Formals, List Outs, List Req, List Ens, Mod Mod, Decreases decreases, BlockStmt Body) :base(tok, Attributes, Name, IsGhost, TypeArgs, Formals, Outs, Req, Ens, Mod, decreases, Body) { } } public class TopLevelDecl { public Token tok; public Attributes Attributes; public string Name; } public class DatatypeCtor { public DatatypeDecl datatype; public string Name; public List Formals; public DatatypeCtor(string Name, List Formals) { this.Name = Name; this.Formals = Formals; } } public class DatatypeDestructor : Field { public DatatypeCtor EnclosingCtor; public DatatypeDestructor(DatatypeCtor EnclosingCtor, Token tok, Attributes Attributes, string Name, bool IsGhost, Type Type) : base(tok, Attributes, Name, IsGhost, Type) { this.EnclosingCtor = EnclosingCtor; } } public class DatatypeDecl: TopLevelDecl { public List TypeArgs; public List Ctors; public DatatypeDecl(Token tok, string name, Attributes attrs, List TypeArgs, List Ctors) { this.tok = tok; this.Name = name; this.Attributes = attrs; this.TypeArgs = TypeArgs; this.Ctors = Ctors; } } public class ClassDecl: TopLevelDecl { public static ClassDecl TheClass = new ClassDecl(); public List Members = new List(); } public class ModuleDefinition { public string Name; public List TopLevelDecls; public ModuleDefinition(string Name, List TopLevelDecls) { this.Name = Name; this.TopLevelDecls = TopLevelDecls; } } public class Program { public List Modules; public Program(List Modules) { this.Modules = Modules; } public static List MakeList(IEnumerable e) { return new List(e); } } public class Resolver { public A Find(Dictionary dict, string key) { if (!dict.ContainsKey(key)) { throw new Exception("could not find: " + key); } else return dict[key]; } public Dictionary datatypes = new Dictionary(); public Dictionary constructors = new Dictionary(); public Dictionary fields = new Dictionary(); public Dictionary functions = new Dictionary(); public Dictionary methods = new Dictionary(); public Function currentFunction; public Method currentMethod; public Dictionary typeParams = new Dictionary(); Dictionary> vars = new Dictionary>(); int ghost; List> collectVars = new List>(); public Resolver(Program program) { foreach (ModuleDefinition module in program.Modules) { foreach (TopLevelDecl decl in module.TopLevelDecls) { DatatypeDecl data = decl as DatatypeDecl; if (data != null) { datatypes.Add(data.Name, data); foreach (DatatypeCtor ctor in data.Ctors) { constructors.Add(ctor.Name, ctor); ctor.datatype = data; } } } } foreach (MemberDecl member in ClassDecl.TheClass.Members) { Field field = member as Field; Function fun = member as Function; Method method = member as Method; if (field != null) { fields.Add(field.Name, field); } if (fun != null) { functions.Add(fun.Name, fun); } if (method != null) { methods.Add(method.Name, method); } } } List varList(string x) { if (!vars.ContainsKey(x)) { vars.Add(x, new List()); } return vars[x]; } public void PushTypeParam(TypeParameter p) { typeParams.Add(p.Name, p); } public void PopTypeParam(TypeParameter p) { typeParams.Remove(p.Name); } public void PushVar(string x, Type t, bool isGhost) { varList(x).Add(new VarDecl(x, t, isGhost)); } public void PushVar(BoundVar x) { PushVar(x.Name, x.Type, x.IsGhost); } public void PopVar(string x) { vars[x].RemoveAt(vars[x].Count - 1); } internal VarDecl Var(string x) { return vars.ContainsKey(x) && vars[x].Count > 0 ? vars[x][vars[x].Count - 1] : null; } public void PushGhost() { ghost++; } public void PopGhost() { ghost--; } public bool IsGhost() { return ghost != 0; } public void PushVarCollect() { collectVars.Add(new Dictionary()); } public Dictionary PopVarCollect() { Dictionary r = collectVars[collectVars.Count - 1]; collectVars.RemoveAt(collectVars.Count - 1); return r; } public void CollectVar(string x) { foreach (Dictionary d in collectVars) { d[x] = true; } } public static Type SubstType(Type t, Dictionary map) { return t.Subst(map); } } } ================================================ FILE: ironclad-apps/tools/DafnySpec/DafnySpecAst/DafnySpecAst.csproj ================================================ Debug AnyCPU {BE5E53DC-B929-4031-B85B-71138AD363CF} Library Properties DafnySpecAst DafnySpecAst v3.5 512 true full false ..\bin\ DEBUG;TRACE prompt 4 pdbonly true ..\bin\Release\ TRACE prompt 4 ================================================ FILE: ironclad-apps/tools/DafnySpec/DafnySpecAst/nubuild-manifest.txt ================================================ # This file only exists because NuBuild requires that it be here. # You could argue that this is a bug in NuBuild. ================================================ FILE: ironclad-apps/tools/DafnySpec/Makefile ================================================ # # Copyright (c) 2007 Microsoft Corporation. All rights reserved. # BUILD = ..\..\build MSBUILD=C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe #FSC = $(BUILD)\fsc -g #FSLEX = $(BUILD)\fslex #FSYACC = $(BUILD)\fsyacc #OLD_CSC = ..\..\..\base\build\csc.exe #CSC = %SystemRoot%\Microsoft.NET\Framework\v4.0.30319\csc.exe #CSC0 = ..\..\..\base\build-private\v4.0.30319\csc.exe #CSC1 = ..\..\..\base\build-private\v4.0.30319-Windows8.1\csc.exe OBJ = ..\..\obj_tools\dafnyspec BIN = ..\..\bin_tools\dafnyspec SRC = . DAFNYSPEC_SOURCES = \ $(SRC)\Util.cs \ $(SRC)\RtlGhost.cs \ $(SRC)\Compile.cs \ $(SRC)\CompileField.cs \ $(SRC)\CompileFunction.cs \ $(SRC)\CompileMethodGhost.cs \ $(SRC)\ParseMain.cs \ $(SRC)\DafnySpec.cs \ PARSER_SOURCES = \ $(SRC)\parse_util.fs \ $(SRC)\parser.fs \ REFS = /r:System.Numerics.dll /r:dafnyspecast.dll /r:$(BIN)\parser.dll all: dafnyspec dafnyspec: $(OBJ) $(BIN) $(BIN)\dafnyspec.exe $(OBJ): md $(OBJ) $(BIN): md $(BIN) $(BIN)\dafnyspec.exe: $(DAFNYSPEC_SOURCES) $(SRC)\DafnySpecAst.cs $(PARSER_SOURCES) $(SRC)\lex.fsl $(SRC)\parse.fsy $(MSBUILD) DafnySpec.sln #$(BIN)\dafnyspecast.dll: $(SRC)\DafnySpecAst.cs # $(OLD_CSC) /debug+ /target:library /out:$(BIN)\dafnyspecast.dll $(SRC)\DafnySpecAst.cs # #$(OBJ)\lex.fsi $(OBJ)\lex.fs: $(SRC)\lex.fsl # $(FSLEX) $(SRC)\lex.fsl -o $(OBJ)\lex.fs # #$(OBJ)\parse.fsi $(OBJ)\parse.fs: $(SRC)\parse.fsy # $(FSYACC) -v $(SRC)\parse.fsy -o $(OBJ)\parse.fs # #$(BIN)\parser.dll: $(PARSER_SOURCES) $(BIN)\dafnyspecast.dll # $(FSC) --standalone --mlcompatibility --target:library -O $(PARSER_SOURCES) -o $(BIN)\parser.dll -r FSharp.PowerPack.dll -r $(BIN)\dafnyspecast.dll # #$(BIN)\dafnyspec.exe: $(DAFNYSPEC_SOURCES) $(BIN)\dafnyspecast.dll $(BIN)\parser.dll # if exist $(CSC). ($(CSC) /debug+ /out:$(BIN)\dafnyspec.exe /lib:$(BIN) $(DAFNYSPEC_SOURCES) $(REFS).) else ($(CSC0) /debug+ /out:$(BIN)\dafnyspec.exe /lib:$(BIN) $(DAFNYSPEC_SOURCES) $(REFS).) # ================================================ FILE: ironclad-apps/tools/DafnySpec/ParseMain.cs ================================================ using System; using System.IO; using System.Linq; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Numerics; using Microsoft.Boogie; using Microsoft.Dafny; namespace Microsoft.Boogie { public class CommandLineOptionEngine { public class CommandLineParseState { public List args; public int i; public bool ConfirmArgumentCount(int n) { return (i++) + n <= args.Count; } } } public class CommandLineOptions { public static CommandLineOptions Clo = new CommandLineOptions(); public bool RunningBoogieFromCommandLine; public List Files = new List(); protected virtual bool ParseOption(string name, CommandLineOptionEngine.CommandLineParseState ps) { return false; } public bool Parse(string[] args) { CommandLineOptionEngine.CommandLineParseState ps = new CommandLineOptionEngine.CommandLineParseState(); Func replaceAt = (s, i, c) => s.Substring(0, i) + c + s.Substring(i + 1); ps.args = new List(args) .ConvertAll(s => s.StartsWith("/") && s.Contains(":") ? replaceAt(s, s.IndexOf(':'), '*') : s) .SelectMany(s => s.Split(new char[] {'*'})).ToList(); ps.i = 0; for (ps.i = 0; ps.i < ps.args.Count; ps.i++) { string name = ps.args[ps.i]; if (name.StartsWith("-") || name.StartsWith("/")) { if (!Clo.ParseOption(name.Substring(1), ps)) { throw new Exception("unknown command-line switch: " + name); } } else { Files.Add(new FileInfo(ps.args[ps.i]).FullName); } } return true; } } } namespace Microsoft.Dafny { public class DafnyOptions: CommandLineOptions { public static void Install(DafnyOptions options) { Clo = options; } } class AutoReq { Resolver resolver; Dictionary doneFunctions = new Dictionary(); Dictionary doneMethods = new Dictionary(); internal AutoReq(Resolver resolver) { this.resolver = resolver; } internal void ReqFunction(Function fun) { if (!doneFunctions.ContainsKey(fun.Name)) { doneFunctions.Add(fun.Name, ""); if (Attributes.Contains(fun.Attributes, "autoReq")) { if (Attributes.Contains(fun.Attributes, "opaque") && !fun.Name.EndsWith("_FULL")) { var new_reqs = new List(); Function full = (Function)ClassDecl.TheClass.Members.Find( m => m.Name == "#" + fun.Name + "_FULL"); ReqFunction(full); fun.Req.Clear(); fun.Req.AddRange(full.Req); } else { List auto_reqs = new List(); foreach (Expression req in fun.Req) { auto_reqs.AddRange(GenerateAutoReqs(req, fun)); } fun.Req.InsertRange(0, auto_reqs); if (fun.Body != null) { auto_reqs = GenerateAutoReqs(fun.Body, fun); fun.Req.AddRange(auto_reqs); } } } } } internal void ReqMethod(Method method) { if (!doneMethods.ContainsKey(method.Name)) { doneMethods.Add(method.Name, ""); if (Attributes.Contains(method.Attributes, "autoReq")) { List auto_reqs = new List(); foreach (SpecExpression req in method.Req) { List local_auto_reqs = GenerateAutoReqs(req.E, null); foreach (Expression local_auto_req in local_auto_reqs) { auto_reqs.Add(new SpecExpression(null, local_auto_req)); } } method.Req.InsertRange(0, auto_reqs); } } } Expression Andify(List exprs) { Expression ret = null; foreach (var expr in exprs) { ret = (ret == null) ? expr : new BinaryExpr(Token.NoToken, BinaryExpr.Opcode.And, ret, expr); ret.Type = Type.Bool; } return ret != null ? ret : new LiteralExpr(true); } List GatherReqs(Function fun, List args) { List translated_f_reqs = new List(); if (fun.Req.Count > 0) { List> substs = fun.Formals.Zip(args, (f, arg) => Tuple.Create(new BoundVar(Token.NoToken, f.Name, f.Type), arg)).ToList(); substs = substs.Where(p => !(p.Item2 is IdentifierExpr) || ((IdentifierExpr)p.Item2).Name != p.Item1.Name).ToList(); List lhss = substs.ConvertAll(p => new ExprLhs(p.Item1)); foreach (var req in fun.Req) { var letExpr = new LetExpr(true, lhss, substs.ConvertAll(p => p.Item2), req); letExpr.tryToEliminate = true; translated_f_reqs.Add(letExpr); } } return translated_f_reqs; } List GenerateAutoReqs(Expression expr, Function parent) { List reqs = new List(); Func> generateAutoReqs = e => GenerateAutoReqs(e, parent); if (expr is LiteralExpr) { } else if (expr is ThisExpr) { } else if (expr is IdentifierExpr) { } else if (expr is SeqDisplayExpr) { SeqDisplayExpr e = (SeqDisplayExpr)expr; foreach (var elt in e.Elements) { reqs.AddRange(generateAutoReqs(elt)); } } else if (expr is MemberSelectExpr && ((MemberSelectExpr)expr).Member is Field) { MemberSelectExpr e = (MemberSelectExpr)expr; reqs.AddRange(generateAutoReqs(e.Obj)); } else if (expr is SeqSelectExpr) { SeqSelectExpr e = (SeqSelectExpr)expr; reqs.AddRange(generateAutoReqs(e.Seq)); if (e.E0 != null) { reqs.AddRange(generateAutoReqs(e.E0)); } if (e.E1 != null) { reqs.AddRange(generateAutoReqs(e.E1)); } } else if (expr is SeqUpdateExpr) { SeqUpdateExpr e = (SeqUpdateExpr)expr; reqs.AddRange(generateAutoReqs(e.Seq)); reqs.AddRange(generateAutoReqs(e.Index)); reqs.AddRange(generateAutoReqs(e.Value)); } else if (expr is FunctionCallExpr) { FunctionCallExpr e = (FunctionCallExpr)expr; foreach (var arg in e.Args) { reqs.AddRange(generateAutoReqs(arg)); } if (parent == null || parent.Name != e.name) { ReqFunction(e.Function); reqs.AddRange(GatherReqs(e.Function, e.Args)); } } else if (expr is DatatypeValue) { DatatypeValue dtv = (DatatypeValue)expr; for (int i = 0; i < dtv.Arguments.Count; i++) { Expression arg = dtv.Arguments[i]; reqs.AddRange(generateAutoReqs(arg)); } } else if (expr is OldExpr) { } else if (expr is MatchExpr) { MatchExpr e = (MatchExpr)expr; reqs.AddRange(generateAutoReqs(e.Source)); List newMatches = new List(); foreach (MatchCaseExpr caseExpr in e.Cases) { MatchCaseExpr c = new MatchCaseExpr(caseExpr.name, caseExpr.Arguments, Andify(generateAutoReqs(caseExpr.Body))); newMatches.Add(c); } reqs.Add(new MatchExpr(e.Source, newMatches)); } else if (expr is UnaryOpExpr) { UnaryOpExpr e = (UnaryOpExpr)expr; Expression arg = e.E; reqs.AddRange(generateAutoReqs(arg)); } else if (expr is BinaryExpr) { BinaryExpr e = (BinaryExpr)expr; switch (e.Op) { case BinaryExpr.Opcode.Imp: case BinaryExpr.Opcode.And: reqs.AddRange(generateAutoReqs(e.E0)); foreach (var req in generateAutoReqs(e.E1)) { reqs.Add(new BinaryExpr(Token.NoToken, BinaryExpr.Opcode.Imp, e.E0, req)); } break; case BinaryExpr.Opcode.Or: reqs.AddRange(generateAutoReqs(e.E0)); foreach (var req in generateAutoReqs(e.E1)) { reqs.Add(new BinaryExpr(Token.NoToken, BinaryExpr.Opcode.Imp, new UnaryOpExpr(Token.NoToken, UnaryOpExpr.Opcode.Not, e.E0), req)); } break; default: reqs.AddRange(generateAutoReqs(e.E0)); reqs.AddRange(generateAutoReqs(e.E1)); break; } } else if (expr is LetExpr) { var e = (LetExpr)expr; if (e.Exact) { foreach (var rhs in e.RHSs) { reqs.AddRange(generateAutoReqs(rhs)); } var new_reqs = generateAutoReqs(e.Body); if (new_reqs.Count > 0) { reqs.Add(new LetExpr(e.Exact, e.LHSs, e.RHSs, Andify(new_reqs))); } } } else if (expr is QuantifierExpr) { QuantifierExpr e = (QuantifierExpr)expr; var auto_reqs = generateAutoReqs(e.Term); if (auto_reqs.Count > 0) { Expression allReqsSatisfied = Andify(auto_reqs); Expression allReqsSatisfiedAndTerm = new BinaryExpr(Token.NoToken, BinaryExpr.Opcode.And, allReqsSatisfied, e.Term); e.Term = allReqsSatisfiedAndTerm; } } else if (expr is StmtExpr) { var e = (StmtExpr)expr; reqs.AddRange(generateAutoReqs(e.E)); } else if (expr is ITEExpr) { ITEExpr e = (ITEExpr)expr; reqs.AddRange(generateAutoReqs(e.Test)); reqs.Add(new ITEExpr(e.Test, Andify(generateAutoReqs(e.Thn)), Andify(generateAutoReqs(e.Els)))); } return reqs; } } public class Main { public static void Resolve(Resolver resolver, Program program) { try { foreach (ModuleDefinition module in program.Modules) { foreach (TopLevelDecl decl in module.TopLevelDecls) { DatatypeDecl data = decl as DatatypeDecl; if (data != null) { foreach (var ctor in data.Ctors) { resolver.PushGhost(); data.TypeArgs.ForEach(p => resolver.PushTypeParam(p)); ctor.Formals.ForEach(f => f.Resolve(resolver)); data.TypeArgs.ForEach(p => resolver.PopTypeParam(p)); resolver.PopGhost(); } } } } foreach (MemberDecl member in ClassDecl.TheClass.Members) { Field field = member as Field; Function fun = member as Function; Method method = member as Method; if (field != null) { if (field.IsGhost) { resolver.PushGhost(); } field.Type.Resolve(resolver); if (field.IsGhost) { resolver.PopGhost(); } } if (fun != null) { resolver.currentFunction = fun; resolver.PushGhost(); fun.TypeArgs.ForEach(p => resolver.PushTypeParam(p)); fun.Formals.ForEach(x => { x.Resolve(resolver); }); fun.ResultType.Resolve(resolver); fun.TypeArgs.ForEach(p => resolver.PopTypeParam(p)); resolver.PopGhost(); resolver.currentFunction = null; } if (method != null) { resolver.currentMethod = method; if (method.IsGhost) { resolver.PushGhost(); } method.TypeArgs.ForEach(p => resolver.PushTypeParam(p)); method.Formals.ForEach(x => { x.Resolve(resolver); }); method.Outs.ForEach(x => { x.Resolve(resolver); }); method.TypeArgs.ForEach(p => resolver.PopTypeParam(p)); if (method.IsGhost) { resolver.PopGhost(); } resolver.currentMethod = null; } } foreach (MemberDecl member in ClassDecl.TheClass.Members) { Function fun = member as Function; Method method = member as Method; if (fun != null) { resolver.currentFunction = fun; resolver.PushGhost(); fun.TypeArgs.ForEach(p => resolver.PushTypeParam(p)); fun.Formals.ForEach(x => { resolver.PushVar(x.Name, x.Type, true); }); fun.ResultType.Resolve(resolver); fun.Req = fun.Req.ConvertAll(e => e.Resolve(resolver, Type.Bool)); fun.Ens = fun.Ens.ConvertAll(e => e.Resolve(resolver, Type.Bool)); fun.Decreases.Resolve(resolver); if (fun.Body != null) { fun.Body = fun.Body.Resolve(resolver, fun.ResultType); } if (fun.IsRecursive && fun.Decreases.Expressions.Count == 0) { fun.Decreases.Expressions.Add(new IdentifierExpr(Token.NoToken, fun.Formals[0].Name)); fun.Decreases.Resolve(resolver); } fun.Formals.ForEach(x => resolver.PopVar(x.Name)); fun.TypeArgs.ForEach(p => resolver.PopTypeParam(p)); resolver.PopGhost(); resolver.currentFunction = null; } if (method != null) { resolver.currentMethod = method; if (method.IsGhost) { resolver.PushGhost(); } method.TypeArgs.ForEach(p => resolver.PushTypeParam(p)); method.Formals.ForEach(x => { resolver.PushVar(x.Name, x.Type, true); }); method.Req.ForEach(e => e.Resolve(resolver)); method.Outs.ForEach(x => { resolver.PushVar(x.Name, x.Type, true); }); method.Ens.ForEach(e => e.Resolve(resolver)); method.Decreases.Resolve(resolver); method.Outs.ForEach(x => resolver.PopVar(x.Name)); method.Formals.ForEach(x => resolver.PopVar(x.Name)); method.TypeArgs.ForEach(p => resolver.PopTypeParam(p)); if (method.IsGhost) { resolver.PopGhost(); } resolver.currentMethod = null; } } } catch (Exception e) { string ctxt = (resolver.currentMethod != null) ? "in method " + resolver.currentMethod.Name + ": ": (resolver.currentFunction != null) ? "in function " + resolver.currentFunction.Name + ": ": ""; throw new Exception(ctxt, e); } } public static string ParseCheck(List modules, string name, out Program program) { LiteralExpr.MakeBigInt = new MakeBigInt(s => new LiteralExpr(BigInteger.Parse(s))); program = new Program(modules.ConvertAll(m => new ModuleDefinition(m, Parser.parse(m)))); Resolver resolver = new Resolver(program); Resolve(resolver, program); List fullFunctions = new List(); foreach (MemberDecl member in ClassDecl.TheClass.Members) { Function fun = member as Function; if (fun != null && Attributes.Contains(fun.Attributes, "opaque")) { Function full = new Function(fun.tok, fun.Attributes, "#" + fun.Name + "_FULL", fun.IsGhost, fun.TypeArgs, fun.Formals, fun.ResultType, fun.Req, fun.Ens, fun.Decreases, fun.Body); full.IsRecursive = fun.IsRecursive; fun.Body = null; fullFunctions.Add(full); } } ClassDecl.TheClass.Members.AddRange(fullFunctions); AutoReq autoReq = new AutoReq(resolver); foreach (MemberDecl member in ClassDecl.TheClass.Members) { Function fun = member as Function; Method method = member as Method; if (fun != null) { autoReq.ReqFunction(fun); } if (method != null) { autoReq.ReqMethod(method);} } Resolve(resolver, program); return null; } } } ================================================ FILE: ironclad-apps/tools/DafnySpec/Parser/Parser.csproj ================================================  Debug AnyCPU {0C1E9D4F-6AAE-455C-B5C7-5DE6063CA99E} Library Properties Parser Parser v4.5 512 true full false bin\Debug\ DEBUG;TRACE prompt 4 pdbonly true bin\Release\ TRACE prompt 4 {be5e53dc-b929-4031-b85b-71138ad363cf} DafnySpecAst $(SolutionDir)\..\fsharp\fslex $(SolutionDir)\Parser\lex.fsl -o lex.fs $(SolutionDir)\..\fsharp\fsyacc -v $(SolutionDir)\Parser\parse.fsy -o parse.fs $(SolutionDir)\..\fsharp\fsc -g --standalone --mlcompatibility --target:library -O $(SolutionDir)\Parser\parse_util.fs parse.fs lex.fs $(SolutionDir)\Parser\parser.fs -o parser.dll -r $(SolutionDir)\..\fsharp\FSharp.PowerPack.dll -r dafnyspecast.dll ================================================ FILE: ironclad-apps/tools/DafnySpec/Parser/ReadMe.txt ================================================ The real purpose of this project is to run its post-build event, which creates parser.dll. The build system, however, will first create a bogus parser.dll with nothing of import in it. The post-build event will then overwrite this with the real parser.dll. Ideally, we'd replace this with an actual F# project that would build parser.dll directly. However, we're currently using specific F# tooling (it's checked into the repository), but non-specific (whatever the user has on their machine) C# and msbuild tooling. So this dance is to use the specific F# binaries in the non-specific build environment. ================================================ FILE: ironclad-apps/tools/DafnySpec/Parser/lex.fsl ================================================ { open Lexing;; open Parse;; open Parse_util;; open Microsoft.FSharp.Compatibility.OCaml.Big_int;; let macros = ref (Map.empty:Map) let cur_loc ():Microsoft.Boogie.Token = new Microsoft.Boogie.Token(!file, !line) } rule comment = parse | "*/" { () } | "*)" { () } | "/*" { comment lexbuf ; comment lexbuf } | "(*" { comment lexbuf ; comment lexbuf } | "\n\r" { incr line; comment lexbuf } | "\r\n" { incr line; comment lexbuf } | ['\n''\r'] { incr line; comment lexbuf } | _ { comment lexbuf } and preprocess_skip deep = parse | "#else" { if deep then preprocess_skip deep lexbuf else () } | "#endif" { () } | "#ifdef" { preprocess_skip true lexbuf; preprocess_skip deep lexbuf } | "#ifndef" { preprocess_skip true lexbuf; preprocess_skip deep lexbuf } | "\n\r" { incr line; preprocess_skip deep lexbuf } | "\r\n" { incr line; preprocess_skip deep lexbuf } | ['\n''\r'] { incr line; preprocess_skip deep lexbuf } | _ { preprocess_skip deep lexbuf } and file_name = parse | [' ']*[^' ''\n''\r']+[^'\n''\r']* { file := (lexeme lexbuf).Trim() ; token lexbuf } | [^'\n''\r']* { token lexbuf } and line_number = parse | ['0'-'9']+ { line := int_of_string(lexeme lexbuf) - 1 ; file_name lexbuf } and token = parse | "\n\r" { incr line; token lexbuf } | "\r\n" { incr line; token lexbuf } | ['\n''\r'] { incr line; token lexbuf } | [' ''\t'] { token lexbuf } | "//"[^'\n''\r']* { token lexbuf } | "#line"[' ']* { line_number lexbuf } | "/*call_lemma:*/" { CALL_LEMMA } | "/*" { comment lexbuf ; token lexbuf } | "(*" { comment lexbuf ; token lexbuf } | "#ifdef"[' ']+['A'-'Z''a'-'z''0'-'9''_''$''?']+ { let s = lexeme lexbuf in let x = s.Substring("#ifdef".Length).Trim() in if Map.contains x !macros then token lexbuf else (preprocess_skip false lexbuf ; token lexbuf) } | "#ifndef"[' ']+['A'-'Z''a'-'z''0'-'9''_''$''?']+ { let s = lexeme lexbuf in let x = s.Substring("#ifndef".Length).Trim() in if not (Map.contains x !macros) then token lexbuf else (preprocess_skip false lexbuf ; token lexbuf) } | "#else" { preprocess_skip false lexbuf ; token lexbuf } | "#endif" { token lexbuf } | ":" { COLON (cur_loc ()) } | ";" { SEMI } | "(" { LPAREN } | ")" { RPAREN } | "[" { LBRACKET } | "]" { RBRACKET } | "{" { LBRACE (cur_loc ()) } | "}" { RBRACE (cur_loc ()) } | "<" { LT } | ">" { GT } | "=" { EQ } | "+" { PLUS } | "-" { MINUS } | "*" { STAR } | "!" { BANG } | "?" { QUESTION } | "%" { MOD } | "/" { DIV } | "," { COMMA } | "|" { BAR } | "#" { HASH } | "`" { TICK } | "." { DOT } | ".." { DOTDOT } | ":=" { COLONEQ (cur_loc ()) } | "<=" { LE } | ">=" { GE } | "==" { EQEQ } | "!=" { NE } | "&&" { AMPAMP } | "||" { BARBAR } | ":|" { COLONBAR } | "::" { COLONCOLON } | "=>" { EQGT } | "==>" { EQEQGT } | "<==" { LTEQEQ } | "<==>" { LTEQEQGT } | "type" { TYPE (cur_loc ()) } //| "const" { CONST (cur_loc ()) } //| "readonly" { READONLY (cur_loc ()) } | "datatype" { DATATYPE (cur_loc ()) } | "function" { FUNCTION (cur_loc ()) } | "predicate" { PREDICATE (cur_loc ()) } | "method" { METHOD (cur_loc ()) } | "lemma" { LEMMA (cur_loc ()) } | "returns" { RETURNS (cur_loc ()) } //| "axiom" { AXIOM (cur_loc ()) } //| "procedure" { PROCEDURE (cur_loc ()) } //| "implementation" { IMPLEMENTATION (cur_loc ()) } | "requires" { REQUIRES (cur_loc ()) } | "ensures" { ENSURES (cur_loc ()) } | "modifies" { MODIFIES (cur_loc ()) } | "decreases" { DECREASES (cur_loc ()) } | "invariant" { INVARIANT (cur_loc ()) } | "assert" { ASSERT (cur_loc ()) } //| "havoc" { HAVOC } | "goto" { GOTO (cur_loc ()) } | "call" { CALL (cur_loc ()) } | "forall" { FORALL (cur_loc ()) } | "exists" { EXISTS (cur_loc ()) } //| "lambda" { LAMBDA (cur_loc ()) } | "old" { OLD } //| "left" { LEFT } //| "right" { RIGHT } //| "relation" { RELATION } //| "public" { PUBLIC } | "int" { INT } | "nat" { NAT } | "real" { REAL } | "bool" { BOOL } | "seq" { SEQ } | "true" { LITBOOL true } | "false" { LITBOOL false } | "this" { THIS } //| "is" { IS } //| "let" { LET } | "in" { IN } | "match" { MATCH } | "case" { CASE } | "var" { VAR (cur_loc ()) } | "if" { IF (cur_loc ()) } | "then" { THEN } | "else" { ELSE } | "return" { RETURN (cur_loc ()) } //| "ireturn" { IRETURN (cur_loc ()) } //| "yield" { YIELD (cur_loc ()) } //| "linear" { LINEAR } //| "my" { MY } | "static" { STATIC (cur_loc ()) } //| "module" { MODULE (cur_loc ()) } //| "interface" { INTERFACE (cur_loc ()) } //| "import" { IMPORT (cur_loc ()) } | "include" { INCLUDE (cur_loc ()) } //| "atomic" { ATOMIC } //| "stable" { STABLE } | "ghost" { GHOST } | "0x"['0'-'9''a'-'f''A'-'F']+ { let s = lexeme lexbuf in let s = String.sub s 2 (String.length s - 2) in let rec explode (n:int) s = if n = String.length s then [] else (String.get s n)::(explode (n+1) s) in let digits = List.map (Char.code << Char.lowercase) (explode 0 s) in let rec hex digits n = match digits with | [] -> n | h::t -> let d = if h >= (Char.code 'a') then h - (Char.code 'a') + 10 else h - (Char.code '0') in hex t (add_int_big_int d (mult_int_big_int 16 n)) in LITINT (hex digits zero_big_int) } | ['0'-'9']+ { LITINT (big_int_of_string(lexeme lexbuf)) } | ['0'-'9']+['.']['0'-'9']+ { LITREAL (lexeme lexbuf) } | ['0'-'9']+"bv32" { let s = lexeme lexbuf in LITBV32 (big_int_of_string(s.Substring(0, s.Length - 4))) } | ['_']*['A'-'Z']['_''a'-'z''A'-'Z''0'-'9''\'']* { UID ((lexeme lexbuf)) } | ['_']*['a'-'z']['_''a'-'z''A'-'Z''0'-'9''\'']* { LID ((lexeme lexbuf)) } | ['_']+['_''0'-'9''\'']* { LID ((lexeme lexbuf)) } | ['"'][^'"']*['"'] { LITSTRING (let s = lexeme lexbuf in s.Substring(1, s.Length - 2)) } | eof { EOF } | '\000' { EOF } | _ { parse_err ("cannot parse character: \"" ^ (lexeme lexbuf) ^ "\"" ^ "\n(ascii code " ^ (string_of_int (Char.code (String.get (lexeme lexbuf) 0))) ^ ")") } ================================================ FILE: ironclad-apps/tools/DafnySpec/Parser/nubuild-manifest.txt ================================================ # Project's PostBuildEvent uses FSharp tools: dependency ..\..\fsharp\fslex.exe dependency ..\..\fsharp\fsyacc.exe dependency ..\..\fsharp\fsc.exe dependency ..\..\fsharp\FSharp.Core.dll dependency ..\..\fsharp\FSharp.Compiler.dll # Project's PostBuildEvent takes the following inputs to create the output: dependency lex.fsl dependency parse.fsy dependency parse_util.fs dependency parser.fs dependency ..\..\fsharp\FSharp.PowerPack.dll # We don't list parser.dll as an output here because the project file already believes it is creating it. ================================================ FILE: ironclad-apps/tools/DafnySpec/Parser/parse.fsy ================================================ %{ open Microsoft.Dafny;; open Microsoft.Boogie;; open Parse_util;; open Microsoft.FSharp.Math;; open Microsoft.FSharp.Compatibility.OCaml.Big_int;; type decl = TopDecl of TopLevelDecl | MemDecl of MemberDecl | EmptyDecl let processDecls (ds:decl list) = List.collect (fun d -> match d with | TopDecl t -> [t] | MemDecl m -> ClassDecl.TheClass.Members.Add(m); [] | EmptyDecl -> []) ds type spec = Requires of Attributes * Expression | Ensures of Attributes * Expression | Modifies of string list | Decreases of Expression let processSpecs (ss:spec list) = ( List.collect (fun s -> match s with Requires (a, e) -> [(a, e)] | _ -> []) ss, List.collect (fun s -> match s with Ensures (a, e) -> [(a, e)] | _ -> []) ss, List.collect (fun s -> match s with Modifies xs -> xs | _ -> []) ss, List.collect (fun s -> match s with Decreases e -> [e] | _ -> []) ss) let colonExpSeq (src:Expression) (idxs:Expression list):Expression = let rec f l n = match l with | [] -> [] | h::t -> let m = new BinaryExpr(Token.NoToken, BinaryExpr.Opcode.Add, n, h) :> Expression in (n, m)::(f t m) in let zero = LiteralExpr.MakeBigInt.Invoke("0") :> Expression in let subseqs = List.map (fun (i1, i2) -> new SeqSelectExpr(false, src, i1, i2) :> Expression) (f idxs zero) in new SeqDisplayExpr(toList subseqs) :> Expression let underscores = ref 0; let renameBv (x:string):string = match x with "_" -> incr underscores; x + (string !underscores) | _ -> x %} %start start %type start %token UID %token LID %token DUID %token DLID %token QUID %token QLID %token SEGNAME %token REGNAME %token LITINT %token LITREAL %token LITBV32 %token LITBOOL %token LITSTRING %token SEMI LPAREN RPAREN LBRACKET RBRACKET BAR DOT HASH %token LT GT EQ BANG QUESTION COMMA LE GE EQEQ NE PLUS MINUS STAR DIV MOD AMPAMP BARBAR INT NAT REAL BOOL SEQ %token HAVOC OLD DOTDOT COLONBAR COLONCOLON EQGT EQEQGT LTEQEQ LTEQEQGT %token LEFT RIGHT RELATION PUBLIC CALL_LEMMA %token EAX EBX ECX EDX ESI EDI EBP ESP %token OPNREG OPNMEM IS THEN ELSE LET IN MATCH CASE LINEAR MY ATOMIC STABLE GHOST THIS TICK %token TYPE VAR CONST READONLY DATATYPE FUNCTION PREDICATE METHOD LEMMA AXIOM PROCEDURE IMPLEMENTATION STATIC MODULE INTERFACE IMPORT INCLUDE %token CALL RETURN IRETURN IF GOTO ASSERT INVARIANT COLON COLONEQ YIELD LBRACE RBRACE %token RETURNS REQUIRES ENSURES MODIFIES DECREASES %token FORALL EXISTS LAMBDA %token EOF /* Precedence declarations. */ %right LET IN IF THEN ELSE FORALL EXISTS COLONCOLON MATCH CASE EQGT %left LTEQEQGT %right EQEQGT LTEQEQ %left AMPAMP BARBAR %left LT GT LE GE EQEQ NE IS %left PLUS MINUS %left STAR DIV MOD %right BANG %left LPAREN RPAREN LBRACKET RBRACKET DOT %% //start: INT EOF { [] } start: Decls EOF { (ClassDecl.TheClass :> TopLevelDecl)::(processDecls $1) } Id : LID { $1 } | UID { $1 } Ids : { [] } | Id { [$1] } | Id COMMA Ids { $1::$3 } AttrArgs : { [] } | Exp { [$1] } | Exp COMMA AttrArgs { $1::$3 } Attrs : { null } | LBRACE COLON Id AttrArgs RBRACE Attrs { new Attributes($3, toList $4, $6) } Type : INT { Type.Int :> Type } | NAT { Type.Nat :> Type } | REAL { Type.Real :> Type } | BOOL { Type.Bool :> Type } | SEQ LT Type GT { new SeqType($3) :> Type } | Id { new UserDefinedType(Token.NoToken, $1, null, toList []) :> Type } | Id LT Types GT { new UserDefinedType(Token.NoToken, $1, null, toList $3) :> Type } Types : { [] } | Type { [$1] } | Type COMMA Types { $1::$3 } BoundVar : Id { new BoundVar(Token.NoToken, renameBv $1, null) } | Id COLON Type { new BoundVar(Token.NoToken, renameBv $1, $3) } BoundVars : { [] } | BoundVar { [$1] } | BoundVar COMMA BoundVars { $1::$3 } Formal : Id COLON Type { new Formal($1, $3, false) } | GHOST Id COLON Type { new Formal($2, $4, true) } Formals : { [] } | Formal { [$1] } | Formal COMMA Formals { $1::$3 } Case : CASE Id EQGT Exp1 { new MatchCaseExpr($2, toList [], $4) } | CASE Id LPAREN BoundVars RPAREN EQGT Exp1 { new MatchCaseExpr($2, toList $4, $7) } Cases : { [] } | Case Cases { $1::$2 } ColonExpList : COLON Exp1 { [$2] } | COLON Exp1 ColonExpList { $2::$3 } Exp : Exp2 { $1 } | CALL_LEMMA Id LPAREN Exps RPAREN SEMI Exp { new StmtExprCall($2, toList $4, $7) :> Expression } | VAR BoundVars COLONEQ Exps SEMI Exp { new LetExpr (true, toList (List.map (fun x -> new ExprLhs(x)) $2), toList $4, $6) :> Expression } | VAR BoundVars COLONBAR Exps SEMI Exp { new LetExpr (false, toList (List.map (fun x -> new ExprLhs(x)) $2), toList $4, $6) :> Expression } Exp2 : Exp1 { $1 } | MATCH Exp1 Cases { new MatchExpr($2, toList $3) :> Expression } Exp1 : LPAREN Exp RPAREN { $2 } | IF Exp1 THEN Exp1 ELSE Exp1 { new ITEExpr($2, $4, $6) :> Expression } | Exp1 LTEQEQGT Exp1 { new BinaryExpr(Token.NoToken, BinaryExpr.Opcode.Iff, $1, $3) :> Expression } | Exp1 EQEQGT Exp1 { new BinaryExpr(Token.NoToken, BinaryExpr.Opcode.Imp, $1, $3) :> Expression } //TODO: check precedence, associativity | Exp1 LTEQEQ Exp1 { new BinaryExpr(Token.NoToken, BinaryExpr.Opcode.Exp1, $1, $3) :> Expression } | Exp1 AMPAMP Exp1 { new BinaryExpr(Token.NoToken, BinaryExpr.Opcode.And, $1, $3) :> Expression } | Exp1 BARBAR Exp1 { new BinaryExpr(Token.NoToken, BinaryExpr.Opcode.Or, $1, $3) :> Expression } | Exp1 EQEQ Exp1 { new BinaryExpr(Token.NoToken, BinaryExpr.Opcode.Eq, $1, $3) :> Expression } | Exp1 NE Exp1 { new BinaryExpr(Token.NoToken, BinaryExpr.Opcode.Neq, $1, $3) :> Expression } | Exp1 LT Exp1 { new BinaryExpr(Token.NoToken, BinaryExpr.Opcode.Lt, $1, $3) :> Expression } | Exp1 GT Exp1 { new BinaryExpr(Token.NoToken, BinaryExpr.Opcode.Gt, $1, $3) :> Expression } | Exp1 LE Exp1 { new BinaryExpr(Token.NoToken, BinaryExpr.Opcode.Le, $1, $3) :> Expression } | Exp1 GE Exp1 { new BinaryExpr(Token.NoToken, BinaryExpr.Opcode.Ge, $1, $3) :> Expression } | Exp1 PLUS Exp1 { new BinaryExpr(Token.NoToken, BinaryExpr.Opcode.Add, $1, $3) :> Expression } | Exp1 MINUS Exp1 { new BinaryExpr(Token.NoToken, BinaryExpr.Opcode.Sub, $1, $3) :> Expression } | Exp1 STAR Exp1 { new BinaryExpr(Token.NoToken, BinaryExpr.Opcode.Mul, $1, $3) :> Expression } | Exp1 DIV Exp1 { new BinaryExpr(Token.NoToken, BinaryExpr.Opcode.Div, $1, $3) :> Expression } | Exp1 MOD Exp1 { new BinaryExpr(Token.NoToken, BinaryExpr.Opcode.Mod, $1, $3) :> Expression } | MINUS Exp1 { new BinaryExpr(Token.NoToken, BinaryExpr.Opcode.Sub, (LiteralExpr.MakeBigInt.Invoke("0") :> Expression), $2) :> Expression } | BANG Exp1 { new UnaryOpExpr(Token.NoToken, UnaryOpExpr.Opcode.Not, $2) :> Expression } | FORALL BoundVars Attrs COLONCOLON Exp1 { new ForallExpr(toList $2, $3, $5) :> Expression } | EXISTS BoundVars Attrs COLONCOLON Exp1 { new ExistsExpr(toList $2, $3, $5) :> Expression } | FORALL BoundVars Attrs BAR Exp1 COLONCOLON Exp1 { new ForallExpr(toList $2, $3, new BinaryExpr(Token.NoToken, BinaryExpr.Opcode.Imp, $5, $7)) :> Expression } | EXISTS BoundVars Attrs BAR Exp1 COLONCOLON Exp1 { new ExistsExpr(toList $2, $3, new BinaryExpr(Token.NoToken, BinaryExpr.Opcode.Imp, $5, $7)) :> Expression } | Exp1 LBRACKET Exp1 RBRACKET { new SeqSelectExpr(true, $1, $3, null) :> Expression } | Exp1 LBRACKET DOTDOT Exp1 RBRACKET { new SeqSelectExpr(false, $1, null, $4) :> Expression } | Exp1 LBRACKET Exp1 DOTDOT RBRACKET { new SeqSelectExpr(false, $1, $3, null) :> Expression } | Exp1 LBRACKET Exp1 DOTDOT Exp1 RBRACKET { new SeqSelectExpr(false, $1, $3, $5) :> Expression } | Exp1 LBRACKET Exp1 COLONEQ Exp1 RBRACKET { new SeqUpdateExpr($1, $3, $5) :> Expression } | Exp1 LBRACKET Exp1 ColonExpList RBRACKET { colonExpSeq $1 ($3::$4) } | LBRACKET Exps RBRACKET { new SeqDisplayExpr(toList $2) :> Expression } | BAR Exp1 BAR { new UnaryOpExpr(Token.NoToken, UnaryOpExpr.Opcode.Cardinality, $2); :> Expression } | Exp1 DOT Id { new MemberSelectExpr($1, $3) :> Expression } | Exp1 DOT Id QUESTION { new MemberSelectExpr($1, $3 + "?") :> Expression } | LITBOOL { new LiteralExpr($1) :> Expression } | LITINT { LiteralExpr.MakeBigInt.Invoke(string_of_big_int $1) :> Expression } | LITREAL { new LiteralExpr(Microsoft.Basetypes.BigDec.FromString($1)) :> Expression } | OLD LPAREN Exp1 RPAREN { new OldExpr($3) :> Expression } | Id LPAREN Exps RPAREN { new FunctionCallExpr($1, toList [], toList $3) :> Expression } | REAL LPAREN Exp RPAREN { new ConversionExpr(new RealType(), $3) :> Expression } | INT LPAREN Exp RPAREN { new ConversionExpr(new IntType(), $3) :> Expression } | Id { new IdentifierExpr(Token.NoToken, $1) :> Expression } | LITSTRING { new StringLiteralExpr($1) :> Expression } Exps : { [] } | Exp { [$1] } | Exp COMMA Exps { $1::$3 } Stmt : Exp2 SEMI { () } | ASSERT Exp2 SEMI { () } | BlockStmt { () } Stmts : { () } | Stmt Stmts { () } BlockStmt: LBRACE Stmts RBRACE { () } BlockStmtOpt: { null } | BlockStmt { new BlockStmt() } Mod: THIS TICK Id { $3 } Mods : { [] } | Mod { [$1] } | Mod COMMA Mods { $1::$3 } Spec : REQUIRES Attrs Exp1 SEMI { Requires ($2, $3) } | ENSURES Attrs Exp1 SEMI { Ensures ($2, $3) } | MODIFIES Mods SEMI { Modifies $2 } | DECREASES Exp1 SEMI { Decreases $2 } Specs : { [] } | Spec Specs { $1::$2 } StaticOpt: { () } | STATIC { () } GhostOpt: { false } | GHOST { true } MethodGhost : METHOD { ($1, false) } | GHOST METHOD { ($2, true) } | LEMMA { ($1, true) } FunctionGhost : FUNCTION { ($1, true) } | FUNCTION METHOD { ($1, false) } BodyOpt: { null } | LBRACE Exp RBRACE { $2 } TypeCase : Id { new DatatypeCtor($1, toList []) } | Id LPAREN Formals RPAREN { new DatatypeCtor($1, toList $3) } TypeCases : { [] } | TypeCase { [$1] } | TypeCase BAR TypeCases { $1::$3 } TypeParamsOpt : { [] } | LT Ids GT { List.map (fun t -> new TypeParameter(t)) $2 } ReturnsOpt : { [] } | RETURNS LPAREN Formals RPAREN { $3 } SemiOpt: { () } | SEMI { () } Decl : DATATYPE Attrs Id TypeParamsOpt EQ TypeCases SemiOpt { TopDecl(new DatatypeDecl($1, $3, $2, toList $4, toList $6)) } | StaticOpt GhostOpt VAR Attrs Id COLON Type SEMI { MemDecl(new Field($3, $4, $5, $2, $7)) } | StaticOpt PREDICATE Attrs Id TypeParamsOpt LPAREN Formals RPAREN Specs BodyOpt { let (reqs, enss, mods, decs) = processSpecs $9 in let reqs = List.map snd reqs in let enss = List.map snd enss in MemDecl(new Function($2, $3, $4, true, toList $5, toList $7, Type.Bool, toList reqs, toList enss, new Decreases(toList decs), $10)) } | StaticOpt FunctionGhost Attrs Id TypeParamsOpt LPAREN Formals RPAREN COLON Type Specs BodyOpt { let (reqs, enss, mods, decs) = processSpecs $11 in let reqs = List.map snd reqs in let enss = List.map snd enss in MemDecl(new Function(fst $2, $3, $4, snd $2, toList $5, toList $7, $10, toList reqs, toList enss, new Decreases(toList decs), $12)) } | StaticOpt MethodGhost Attrs Id TypeParamsOpt LPAREN Formals RPAREN ReturnsOpt Specs BlockStmtOpt { let (reqs, enss, mods, decs) = processSpecs $10 in let reqs = List.map (fun (a, e) -> new SpecExpression(a, e)) reqs in let enss = List.map (fun (a, e) -> new SpecExpression(a, e)) enss in let md = new Mod(toList (List.map (fun x -> new FrameExpression(x)) mods)) in MemDecl(new Method(fst $2, $3, $4, snd $2, toList $5, toList $7, toList $9, toList reqs, toList enss, md, new Decreases(toList decs), $11)) } | INCLUDE LITSTRING { EmptyDecl } Decls : { [] } | Decl Decls { $1::$2 } /* Stmt | RETURN SEMI { ($1, SReturn) } | LBRACE COLON Block COLON RBRACE { ($2, SGroup $3) } | IF LPAREN Exp RPAREN LBRACE Block RBRACE { match ($3, $6) with | (EApply (f, [EApply (".efl", [EVar x])]), [(_, SGoto l)]) -> ($1, SIfJcc (x, f, l)) | _ -> ($1, SIfGhost ($3, $6)) } | FORALL LocalFormals COLONCOLON Triggers Exp LBRACE ProcDecls Block RBRACE { let decls = List.map (fun (x, t, lin) -> match lin with Non -> (x, t) | Lin _ -> err "cannot declare linear variable in forall statement") $7 in ($1, SForallGhost ($2, $4, $5, decls, $8)) } | EXISTS LocalFormals COLONCOLON Triggers Exp SEMI { ($1, SExistsGhost ($2, $4, $5)) } | ASSERT Exp SEMI { ($1, SAssert (NotInv, $2)) } | Id COLONEQ Exp SEMI { ($2, SAssign ($1, $3)) } Decl | VAR Id COLON Type SEMI { ($1, DStaticGhost ($2, $4, Non, ReadWrite)) } | CONST Id COLON Type SEMI { ($1, DFunDecl ($2, None, Some $4, None, None, None)) } | CONST Id COLON Type COLONEQ Exp SEMI { ($1, DFunDecl ($2, None, Some $4, Some $6, None, None)) } | CONST SEGNAME COLON Type COLONEQ Exp SEMI { ($1, DFunDecl ($2, None, Some $4, Some $6, None, None)) } | CONST REGNAME COLON Type COLONEQ Exp SEMI { ($1, DFunDecl ($2, None, Some $4, Some $6, None, None)) } */ ================================================ FILE: ironclad-apps/tools/DafnySpec/Parser/parse_util.fs ================================================ open System.Collections.Generic; open Microsoft.Boogie open Microsoft.Dafny type loc = Token exception Err of string exception ParseErr of string let err (s:string):'a = raise (Err s) let parse_err (s:string):'a = raise (ParseErr s) let assrt b = if b then () else err "assert failure" let line = ref 1;; let file = ref "";; let parse_require b = if b then () else parse_err "parse requirement violated" let toList (l:'a list):List<'a> = Program.MakeList(l :> IEnumerable<'a>) ================================================ FILE: ironclad-apps/tools/DafnySpec/Parser/parser.fs ================================================ open Parse open Parse_util open System.Collections.Generic; open Microsoft.Dafny let parse (filename:string):List = let print_error_prefix () = print_endline ("error near line " + (string !line) + " of file " + !file) in try ( file := filename; line := 1; toList (Parse.start Lex.token (Lexing.from_channel (open_in filename))) ) with | (Err s) as x -> (print_endline "error:"; print_endline s; print_endline (x.ToString ()); exit 1) | ParseErr x -> (print_error_prefix (); print_endline x; exit 1) | :? System.ArgumentException as x -> (print_error_prefix (); print_endline (x.ToString ()); exit 1) | Failure x -> (print_error_prefix (); print_endline x; exit 1) | x -> (print_endline (x.ToString ()); exit 1) ;; ================================================ FILE: ironclad-apps/tools/DafnySpec/RtlGhost.cs ================================================ using System; using System.Linq; using System.Collections.Generic; using System.Collections.ObjectModel; using Microsoft.Dafny; using Bpl = Microsoft.Boogie; using System.Numerics; public abstract class RtlExp { public List Vars() { var vars = new List(); AddVars(vars); return vars; } public virtual RtlExp Subst(Dictionary map) { Util.Assert(Vars().Count == 0); return this; } public virtual void AddVars(List vars) {} public virtual string AsOperand() { return ToString(); } } public class RtlLiteral: RtlExp { public readonly string str; public RtlLiteral(string s) { this.str = s; } public override void AddVars(List vars) {} public override RtlExp Subst(Dictionary map) { return this; } public override string ToString() { return str; } } public class RtlVar: RtlExp { public readonly string x; public readonly bool isGhost; public readonly Microsoft.Dafny.Type type; //- used to declare local ghost variables; may be null if no declaration required public RtlVar(string x, bool isGhost, Microsoft.Dafny.Type t = null) { this.x = x; this.isGhost = isGhost; this.type = t; } public string getName() { return x; } //- no register allocation for ghost variables public override void AddVars(List vars) { if (!isGhost) { vars.Add(x); } } public override string ToString() { return x; } public override string AsOperand() { return isGhost ? x.ToString() : ("OReg(" + x + ")"); } public override RtlExp Subst(Dictionary map) { return map.ContainsKey(x) ? new RtlVar(map[x], this.isGhost, this.type) : this; } } public class RtlInt: RtlExp { public readonly BigInteger i; public RtlInt(int i) { this.i = new BigInteger(i); } public RtlInt(BigInteger i) { this.i = i; } public override string ToString() { return i.ToString(); } public override string AsOperand() { return "OConst(" + i + ")"; } } public class RtlBinary: RtlExp { public readonly string op; public readonly RtlExp e0; public readonly RtlExp e1; public RtlBinary(string op, RtlExp e0, RtlExp e1) { this.op = op; this.e0 = e0; this.e1 = e1; } public override void AddVars(List vars) { e0.AddVars(vars); e1.AddVars(vars); } public override RtlExp Subst(Dictionary map) { return new RtlBinary(op, e0.Subst(map), e1.Subst(map)); } public override string ToString() { Func f = e => (e is RtlVar || e is RtlInt) ? e.ToString() : "(" + e + ")"; return f(e0) + " " + op + " " + f(e1); } } public class RtlApply: RtlExp { public readonly string op; public readonly ReadOnlyCollection args; public RtlApply(string op, IEnumerable args) { this.op = op; this.args = args.ToList().AsReadOnly(); } public override void AddVars(List vars) { args.ToList().ForEach(e => e.AddVars(vars)); } public override RtlExp Subst(Dictionary map) { return new RtlApply(op, args.Select(e => e.Subst(map))); } public override string ToString() { return op + "(" + String.Join(", ", args.Select(e => e.ToString())) + ")"; } } public class RtlExpComputed: RtlExp { public readonly ReadOnlyCollection args; public readonly Func toString; public RtlExpComputed(Func toString, IEnumerable args = null) { this.toString = toString; this.args = ((args == null) ? new List() : args.ToList()).AsReadOnly(); } public override void AddVars(List vars) { args.ToList().ForEach(e => e.AddVars(vars)); } public override RtlExp Subst(Dictionary map) { return new RtlExpComputed(toString, args.Select(e => e.Subst(map))); } public override string ToString() { return toString(this); } } public abstract class RtlStmt { public Func comment; public RtlStmt WithComment(string comment) { this.comment = () => comment; return this; } public RtlStmt WithComment(Func comment) { this.comment = comment; return this; } public List Defs() { var vars = new List(); AddDefs(vars); return vars; } public List Uses() { var vars = new List(); AddUses(vars); return vars; } public List Vars() { var vars = new List(); AddDefs(vars); AddUses(vars); return vars; } public virtual RtlStmt Subst(Dictionary map) { Util.Assert(Vars().Count == 0); return this; } public virtual void AddDefs(List vars) {} public virtual void AddUses(List vars) {} } public class RtlComment: RtlStmt { public RtlComment(string comment) { this.comment = () => comment; } public RtlComment(Func comment) { this.comment = comment; } public override string ToString() { return ""; } } public class RtlIndent: RtlStmt { public bool Positive; public RtlIndent(bool Positive) { this.Positive = Positive; } public override string ToString() { return ""; } } public class RtlGhostMove: RtlStmt { public readonly ReadOnlyCollection outs; public readonly ReadOnlyCollection ins; public RtlGhostMove(IEnumerable outs, IEnumerable ins) { this.outs = outs.ToList().AsReadOnly(); this.ins = ins.ToList().AsReadOnly(); } public override string ToString() { return String.Join(", ", outs) + (outs.Count == 0 ? "" : " := ") + String.Join(", ", ins) + ";"; } } public class RtlGhostCall: RtlGhostMove { public readonly string op; public RtlGhostCall(string op, IEnumerable outs, IEnumerable args): base(outs, args) { this.op = op; } public override string ToString() { return "call " + String.Join(", ", outs) + (outs.Count == 0 ? "" : " := ") + op + "(" + String.Join(", ", ins) + ");"; } } public class RtlGhostStmtComputed: RtlStmt { public readonly Func toString; public readonly ReadOnlyCollection args; public RtlGhostStmtComputed(Func toString, IEnumerable args) { this.toString = toString; this.args = args.ToList().AsReadOnly(); } public override string ToString() { return toString(this); } } public class RtlAssert: RtlStmt { public readonly bool isLoop; public readonly RtlExp e; //- ghost expression, does not count as a use public RtlAssert(RtlExp e, bool isLoop = false) { this.e = e; this.isLoop = isLoop; } public override RtlStmt Subst(Dictionary map) { return this; } public override string ToString() { return (isLoop ? "invariant " : "assert ") + e + ";"; } } ================================================ FILE: ironclad-apps/tools/DafnySpec/Util.cs ================================================ using System; using System.Linq; using System.Collections.Generic; using System.Collections.ObjectModel; using Microsoft.Dafny; using Bpl = Microsoft.Boogie; using System.Numerics; public class Util { public static void Assert(bool b) { if (!b) { throw new Exception(); } } public static void DebugWriteLine() { DebugWriteLine(""); } public static void DebugWriteLine(object o) { } } ================================================ FILE: ironclad-apps/tools/DafnySpec/nubuild-manifest.txt ================================================ # This file only exists because NuBuild requires that it be here. # You could argue that this is a bug in NuBuild. ================================================ FILE: ironclad-apps/tools/LineCount/lex.fsl ================================================ { open Lexing;; open Parse_util;; } rule comment = parse | "*/" { () } | "*)" { () } | "/*" { comment lexbuf ; comment lexbuf } | "(*" { comment lexbuf ; comment lexbuf } | "\n\r" { incr line; comment lexbuf } | "\r\n" { incr line; comment lexbuf } | ['\n''\r'] { incr line; comment lexbuf } | _ { comment lexbuf } and token = parse | "\n\r" { end_line (); incr line; token lexbuf } | "\r\n" { end_line (); incr line; token lexbuf } | ['\n''\r'] { end_line (); incr line; token lexbuf } | [' ''\t'] { token lexbuf } | "//"[^'\n''\r']* { token lexbuf } | "/*" { comment lexbuf ; token lexbuf } | "(*" { comment lexbuf ; token lexbuf } | ['"'][^'"''\n''\r']*['"'] { token lexbuf } | eof { EOF } | '\000' { EOF } | _ { content_on_line := true; token lexbuf } ================================================ FILE: ironclad-apps/tools/LineCount/main.fs ================================================ open Parse_util let main (argv) = let total = ref 0; let mods_rev = ref ([]:string list) in let add_mod (s:string) = mods_rev := s::(!mods_rev) in Arg.parse_argv (ref 0) argv [ ] add_mod "error parsing arguments"; let mods = List.rev (!mods_rev) in let parse_file name = file := name; line := 1; count := 0; let lexbuf = (Lexing.from_channel (open_in name)); let _ = Lex.token lexbuf in print_endline (string (!count) ^ " " ^ name); total := !total + !count List.iter parse_file mods; print_endline (string (!total)); ;; let () = main (System.Environment.GetCommandLineArgs ()) ================================================ FILE: ironclad-apps/tools/LineCount/makefile ================================================ # # Copyright (c) 2007 Microsoft Corporation. All rights reserved. # BUILD = ..\..\build FSC = $(BUILD)\fsc -g FSLEX = $(BUILD)\fslex OBJ = ..\..\obj_tools\linecount BIN = ..\..\bin_tools\linecount CORE = . SRC = \ $(CORE)\parse_util.fs \ $(OBJ)\lex.fs \ $(CORE)\main.fs \ all: $(OBJ) $(BIN) $(BIN)\linecount.exe $(OBJ): md $(OBJ) $(BIN): md $(BIN) $(OBJ)\lex.fsi $(OBJ)\lex.fs: $(CORE)\lex.fsl $(FSLEX) $(CORE)\lex.fsl -o $(OBJ)\lex.fs $(BIN)\linecount.exe: $(SRC) $(FSC) --standalone --mlcompatibility -O $(SRC) -o $(BIN)\linecount.exe -r FSharp.PowerPack.dll clean: del /q $(BIN)\linecount.exe del /q $(OBJ)\*.fs ================================================ FILE: ironclad-apps/tools/LineCount/parse_util.fs ================================================ exception Err of string exception ParseErr of string let err (s:string):'a = raise (Err s) let parse_err (s:string):'a = raise (ParseErr s) let assrt b = if b then () else err "assert failure" let line = ref 1;; let file = ref "";; let count = ref 0;; let content_on_line = ref false; let parse_require b = if b then () else parse_err "parse requirement violated" let end_line () = if (!content_on_line) then incr count; content_on_line := false type token = EOF ================================================ FILE: ironclad-apps/tools/NuBuild/.gitignore ================================================ *.suo ================================================ FILE: ironclad-apps/tools/NuBuild/AzureManager/App.config ================================================  ================================================ FILE: ironclad-apps/tools/NuBuild/AzureManager/AzureAccount.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace AzureManager { using System; using System.Globalization; using System.Security.Cryptography.X509Certificates; using Microsoft.WindowsAzure; using Microsoft.WindowsAzure.Management.Compute; using Microsoft.WindowsAzure.Management.Compute.Models; using Microsoft.WindowsAzure.Management.Storage; using Microsoft.WindowsAzure.Management.Storage.Models; /// /// Representation of an Azure Account Subscription. /// public class AzureAccount { /// /// Credentials associated with this Azure account. /// private SubscriptionCloudCredentials credentials; /// /// ComputeManagementClient for managing Azure compute resources. /// private ComputeManagementClient computeManager; /// /// StorageManagementClient for managing Azure storage resources. /// private StorageManagementClient storageManager; /// /// Initializes a new instance of the AzureAccount class. /// /// Subscription ID of the Azure account. /// X509 certificate used for authentication. public AzureAccount(string subscriptionId, X509Certificate2 cert) { this.credentials = new CertificateCloudCredentials(subscriptionId, cert); this.computeManager = CloudContext.Clients.CreateComputeManagementClient(this.credentials); this.storageManager = CloudContext.Clients.CreateStorageManagementClient(this.credentials); } /// /// Gets the service information for the specified service. /// /// Name of the service to query. /// A HostedServiceGetDetailedResponse object containing the information. public HostedServiceGetDetailedResponse GetServiceInformation(string serviceName) { HostedServiceGetDetailedResponse service; service = this.computeManager.HostedServices.GetDetailed(serviceName); return service; } /// /// Creates a service specification (configuration?) entry in Azure's database. /// This reserves the (Azure-unique) DNS prefix name used to access the service. /// /// /// Note that this does not deploy and start the service. /// /// Name of the cloud service. /// Geographical region where the service should be hosted. public void CreateServiceSpecification(string serviceName, string location) { // Required: Label, ServiceName. // One Required (but not both): AffinityGroup, Location. // Optional: Description, ExtendedProperties, HostedServiceCreateParameters parameters = new HostedServiceCreateParameters(); parameters.Label = serviceName; parameters.ServiceName = serviceName; parameters.Location = location; this.computeManager.HostedServices.Create(parameters); } /// /// Deletes the specified service deployment. /// /// Name of the service /// Environment for this deployment (e.g. Production or Staging). public void DeleteDeployment(string serviceName, DeploymentSlot deploymentSlot) { this.computeManager.Deployments.DeleteBySlot(serviceName, deploymentSlot); } /// /// Deploys a service. /// /// /// Note that the service specification must already have been created. /// /// Name of the service. /// Name of this deployment. /// Environment for this deployment (e.g. Production or Staging). /// Deployment configuration information (i.e. .cscfg file contents). /// URI for blob containing package (i.e. .cspkg) file contents. /// Whether to start the deployment immediately after it is created. public void DeployService( string serviceName, string deploymentName, DeploymentSlot deploymentSlot, string configuration, Uri packageBlob, bool startImmediately = true) { // Required: Configuration, Label, Name, PackageUri. // Optional: ExtendedProperties, ExtensionConfiguration, StartDeployment, TreatWarningsAsError. DeploymentCreateParameters parameters = new DeploymentCreateParameters(); parameters.Configuration = configuration; // Contents of .cscfg file. parameters.Label = serviceName; // Name for hosted service. Does not need to match serviceName. parameters.Name = deploymentName; // Unique name for this particular deployment. parameters.PackageUri = packageBlob; // URI for blob containing .cspkg file. parameters.StartDeployment = startImmediately; // Whether to start the deployment immediately after it is created. this.computeManager.Deployments.Create(serviceName, deploymentSlot, parameters); } /// /// Gets the connection string for the given storage account. /// /// A storage account name. /// The connection string for the given storage account. public string GetConnectionStringForStorageAccount(string storageAccountName) { // This makes a call to the Azure infrastructure to get the keys. // REVIEW: Check status code of the response? StorageAccountGetKeysResponse keys = this.storageManager.StorageAccounts.GetKeys(storageAccountName); string connectionString = string.Format( CultureInfo.InvariantCulture, "DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1}", storageAccountName, keys.PrimaryKey); return connectionString; } /// /// Procedure for testing random things. /// public void TestSomething() { HostedServiceListResponse response; response = this.computeManager.HostedServices.List(); Console.WriteLine("List of hosted services:"); foreach (HostedServiceListResponse.HostedService service in response.HostedServices) { Console.WriteLine("\n{0}\n", service.ServiceName); // Note: The HostedServiceListResponse.HostedService class // contains many of the same properties as the // HostedServiceGetDetailedResponse class. } } /// /// Displays all the deployments in a given service. /// /// /// This is an alternative way to access the deployments. /// HostedServiceGetDetailedResponse.Deployment is another. /// /// The service to query. public void ShowDeployments(string serviceName) { DeploymentGetResponse response; try { response = this.computeManager.Deployments.GetBySlot(serviceName, DeploymentSlot.Production); Console.WriteLine("Production Deployment"); Console.WriteLine("Label = {0}", response.Label); } catch (Microsoft.WindowsAzure.CloudException except) { Console.WriteLine("Show Deployment Exception: {0}", except.ErrorMessage); } } } } ================================================ FILE: ironclad-apps/tools/NuBuild/AzureManager/AzureManager.csproj ================================================  Debug AnyCPU {8ADB4B14-715D-4CE1-BFD2-E7D65007CE5C} Exe Properties AzureManager AzureManager v4.5 512 AnyCPU true full false ..\..\..\bin_tools\NuBuild\ DEBUG;TRACE prompt 4 AnyCPU pdbonly true bin\Release\ TRACE prompt 4 ..\References\Microsoft.Threading.Tasks.dll ..\References\Microsoft.WindowsAzure.Common.dll ..\References\Microsoft.WindowsAzure.Common.NetFramework.dll False ..\References\Microsoft.WindowsAzure.Management.Compute.dll ..\References\Microsoft.WindowsAzure.Management.Storage.dll False ..\References\Microsoft.WindowsAzure.Storage.dll CustomDictionary.xml ================================================ FILE: ironclad-apps/tools/NuBuild/AzureManager/Program.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace AzureManager { using System; using System.Collections.Specialized; using System.Configuration; using System.IO; using System.Security.Cryptography.X509Certificates; using Microsoft.WindowsAzure.Management.Compute.Models; using Microsoft.WindowsAzure.Storage; using Microsoft.WindowsAzure.Storage.Blob; /// /// Program to manage Azure cloud resources used by NuBuild. /// public class Program { /// /// Name of our service (hard-wired). /// private const string NuBuildServiceName = "NuBuildExecutionService"; /// /// Name of the deployment package blob we use for the "start" and /// "upload" commands (hard-wired). /// private const string NuBuildServicePackageName = "NuBuildExecutionEngine"; /// /// Default package file name used by "deploy" and "upload" commands. /// Can be overridden by command line argument. /// private const string DefaultPackageFilename = "NuBuildExecutionService.cspkg"; /// /// Default configuration file name used by the "deploy" command /// Can be overridden by command line argument. /// private const string DefaultConfigurationFilename = "ServiceConfiguration.Cloud.cscfg"; /// /// Default number of service instances to "start". /// Can be overridden by command line argument. /// private const int DefaultInstanceCount = 10; /// /// Main program entry point. /// /// The parameter is unused. private static void Main(string[] args) { Console.WriteLine(); // Set some defaults. string packageFilename = DefaultPackageFilename; string configurationFilename = DefaultConfigurationFilename; int instanceCount = DefaultInstanceCount; string command = "status"; // Parse command line arguments. if (args.Length > 0) { command = args[0].ToLower(); if (args.Length > 1) { if (command == "start") { if (!int.TryParse(args[1], out instanceCount)) { Usage(-1); } } else { packageFilename = args[1]; } if (args.Length > 2) { configurationFilename = args[2]; } } } // Get our Azure account information. AzureAccount azureAccount = GetOurAzureAccount(); // Perform user requested action. CloudBlockBlob packageBlob; switch (command) { case "create": azureAccount.CreateServiceSpecification(NuBuildServiceName, "West US"); break; case "deploy": // Upload our package (.cspkg file) to a blob. // We name the blob after the package filename. string blobName = Path.GetFileNameWithoutExtension(packageFilename); packageBlob = GetPackageBlob(azureAccount, blobName); packageBlob.UploadFromFile(packageFilename, System.IO.FileMode.Open); // Create a new deployment using the desired package blob. // TODO: Provide an unique name for each deployment? // REVIEW: Upload to "Staging" slot instead? string configuration = File.ReadAllText(configurationFilename); azureAccount.DeployService(NuBuildServiceName, "Production", DeploymentSlot.Production, configuration, packageBlob.Uri, startImmediately: true); Console.WriteLine("Issued deployment request"); break; case "start": // Create a new deployment using a hard-coded configuration and a previously uploaded blob. ServiceConfiguration config = new ServiceConfiguration( NuBuildServiceName, "4", "*", "2014-06.2.4", "CloudExecutionWorker", instanceCount); packageBlob = GetPackageBlob(azureAccount, NuBuildServicePackageName); azureAccount.DeployService(NuBuildServiceName, "Production", DeploymentSlot.Production, config.ToXml(), packageBlob.Uri, startImmediately: true); Console.WriteLine("Issued deployment request"); break; case "status": HostedServiceGetDetailedResponse serviceInfo = azureAccount.GetServiceInformation(NuBuildServiceName); DisplayServiceInformation(serviceInfo); break; case "stop": // Delete the Azure deployment. // This stops the currently running service, but leaves the // configuration for this service in the Azure database. azureAccount.DeleteDeployment(NuBuildServiceName, DeploymentSlot.Production); break; case "test": ////azureAccount.TestSomething(); ServiceConfiguration testConfig = new ServiceConfiguration(NuBuildServiceName, "4", "*", "2014-06.2.4", "CloudExecutionWorker", 42); Console.WriteLine(testConfig.ToXml()); break; case "upload": // Upload our package (.cspkg file) to a blob. packageBlob = GetPackageBlob(azureAccount, NuBuildServicePackageName); packageBlob.UploadFromFile(packageFilename, System.IO.FileMode.Open); Console.WriteLine("Uploaded package"); break; case "/?": case "help": Usage(0); break; default: Usage(-1); break; } } /// /// Display a (hopefully) helpful usage message to the user, /// and exit the process. /// /// Process exit code to use. private static void Usage(int exitcode) { Console.WriteLine("Usage: AzureManager [create | deploy [package file [config file]] |"); Console.WriteLine(" start [instances] | status | stop |"); Console.WriteLine(" upload [package file]]"); Console.WriteLine(); Console.WriteLine(" where"); Console.WriteLine(" instances Number of service instances to start."); Console.WriteLine(" (default: {0})", DefaultInstanceCount); Console.WriteLine(" package file Package file to deploy."); Console.WriteLine(" (default: .\\{0})", DefaultPackageFilename); Console.WriteLine(" config file Configuration file for deployment."); Console.WriteLine(" (default: .\\{0})", DefaultConfigurationFilename); Console.WriteLine(); Console.WriteLine(" Commands:"); Console.WriteLine(" create Create a new service configuration (using hard-wired info)."); Console.WriteLine(" deploy Deploy using the given package and configuration"); Console.WriteLine(" (overwrites existing hard-wired package blob)."); Console.WriteLine(" start Start the given number of instances of an existing package"); Console.WriteLine(" named '{0}'.", NuBuildServicePackageName); Console.WriteLine(" status Display the current service and deployment status."); Console.WriteLine(" stop Stop the current deployment of the service."); Console.WriteLine(" upload Upload the given package file to hard-wired package blob"); Console.WriteLine(" named '{0}'.", NuBuildServicePackageName); Environment.Exit(exitcode); } /// /// Gets our Azure account. /// /// An Azure account. private static AzureAccount GetOurAzureAccount() { string subscriptionId = null; string certBase64Encoded = null; NameValueCollection appSettings = ConfigurationManager.AppSettings; if (appSettings != null) { subscriptionId = appSettings["Subscription Id"]; certBase64Encoded = appSettings["Certificate (Base 64 Encoded)"]; } if (string.IsNullOrEmpty(subscriptionId)) { throw new ConfigurationException("Subscription Id setting missing from your AzureManager.exe.config file!"); } if (string.IsNullOrEmpty(certBase64Encoded)) { throw new ConfigurationException("Certificate setting missing from your AzureManager.exe.config file!"); } byte[] cert = Convert.FromBase64String(certBase64Encoded); X509Certificate2 x509Cert = new X509Certificate2(cert); AzureAccount azureAccount = new AzureAccount(subscriptionId, x509Cert); return azureAccount; } /// /// Writes selected fields of the give HostedServiceGetDetailedResponse /// object out to the console. /// /// /// The HostedServiceGetDetailedResponse object to display. /// private static void DisplayServiceInformation(HostedServiceGetDetailedResponse service) { Console.WriteLine("Service Name {0}:", service.ServiceName); Console.WriteLine(" Date Created = {0}", service.Properties.DateCreated); Console.WriteLine(" Date Last Modified = {0}", service.Properties.DateLastModified); Console.WriteLine(" Description = {0}", service.Properties.Description); Console.WriteLine(" Label = {0}", service.Properties.Label); Console.WriteLine(" Location = {0}", service.Properties.Location); Console.WriteLine(" Status = {0}", service.Properties.Status); #if false foreach(string size in service.ComputeCapabilities.VirtualMachinesRoleSizes) { Console.WriteLine("VM Role Size = {0}", size); } Console.WriteLine("URI = {0}", service.Uri); #endif if (service.Deployments.Count == 0) { Console.WriteLine(" No current deployments!"); } foreach (HostedServiceGetDetailedResponse.Deployment deployment in service.Deployments) { Console.WriteLine(); Console.WriteLine(" Deployment Name {0}:", deployment.Name); Console.WriteLine(" Created = {0}", deployment.CreatedTime); Console.WriteLine(" Label = {0}", deployment.Label); Console.WriteLine(" Slot = {0}", deployment.DeploymentSlot); Console.WriteLine(" Status = {0}", deployment.Status); Console.WriteLine(" Instances = {0}", deployment.RoleInstances.Count); ////Console.WriteLine(deployment.Configuration); } } /// /// Uploads the given file to the specified Azure blob. /// /// Azure account to use. /// Name of the blob to upload to. /// A reference to the CloudBlockBlob. private static CloudBlockBlob GetPackageBlob(AzureAccount azureAccount, string blobName) { // Get connection string for our storage account. // TODO: Remove hard-coded storage account name. const string StorageAccountName = "ironcladstoretest"; string connectionString = azureAccount.GetConnectionStringForStorageAccount(StorageAccountName); ////Console.WriteLine("Using connection string " + connectionString); // Use our storage account connection string to get our CloudStorageAccount. CloudStorageAccount storageAccount = CloudStorageAccount.Parse(connectionString); ////Console.WriteLine("Storage account URI = {0}", storageAccount.BlobEndpoint.AbsoluteUri); // Use our CloudStorageAccount to create a CloudBlobClient. CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient(); ////Console.WriteLine("Blob base URI = {0}", blobClient.BaseUri); // Find or create our "packages" blob storage container. CloudBlobContainer container = blobClient.GetContainerReference("packages"); container.CreateIfNotExists(BlobContainerPublicAccessType.Container); // Get the package blob we want to deploy. // This is a 'cspkg' file stored as a blob. CloudBlockBlob packageBlob = container.GetBlockBlobReference(blobName); return packageBlob; } } } ================================================ FILE: ironclad-apps/tools/NuBuild/AzureManager/Properties/AssemblyInfo.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("AzureManager")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("AzureManager")] [assembly: AssemblyCopyright("Copyright © 2015")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("067c0004-c47f-4a37-b93d-009d5718b965")] // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: ironclad-apps/tools/NuBuild/AzureManager/ServiceConfiguration.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace AzureManager { using System; using System.Diagnostics; using System.Globalization; using System.IO; using System.Text; using System.Xml; /// /// /// Representation of the "service configuration" (.cscfg) file contents /// used for Azure deployments. /// /// /// /// /// Format is defined by the "Azure Service Configuration Schema". /// See . /// This class implements only the small subset of the schema that we use. /// /// /// This is the format of the "Configuration" member of various /// deployment-related classes (DeploymentChangeConfigurationParameters, /// DeploymentCreateParameters, DeploymentUpgradeParameters, /// HostedServiceGetDetailedResponse.Deployment, etc). /// /// /// Note that this is separate from the "Azure Service Definition Schema" /// (.csdef file) used to create the service proper. /// /// public class ServiceConfiguration { /// /// XML namespace for this object. /// public const string XmlNamespace = "http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration"; /// /// XML element name for this object. /// public const string XmlTag = "ServiceConfiguration"; /// /// XML attribute name for our service name field. /// private const string XmlServiceNameAttribute = "serviceName"; /// /// XML attribute name for our OS family field. /// private const string XmlOSFamilyAttribute = "osFamily"; /// /// XML attribute name for our OS version field. /// private const string XmlOSVersionAttribute = "osVersion"; /// /// XML attribute name for our schema version field. /// private const string XmlSchemaVersionAttribute = "schemaVersion"; /// /// XML element name for our role field. /// private const string XmlRoleElement = "Role"; /// /// XML attribute name for our role name field. /// private const string XmlRoleNameAttribute = "name"; // Note we don't currently support the "vmName" attribute. /// /// XML element name for our instances field. /// private const string XmlInstancesElement = "Instances"; /// /// XML element name for our instance count field. /// private const string XmlInstanceCountAttribute = "count"; /// /// XML element name for our configuration settings field. /// /// /// Note we don't currently support any configuration settings. /// private const string XmlConfigurationSettingsElement = "ConfigurationSettings"; // Note we don't currently support any certificates. // Note we don't currently support the NetworkConfiguration element. /// /// Name of the service. /// private string serviceName; /// /// OS Family. /// private string osFamily; /// /// OS Version. /// private string osVersion; /// /// Schema Version. /// private string schemaVersion; /// /// Name of the role. /// private string roleName; /// /// Count of the number of role instances. /// private int instanceCount; /// /// Initializes a new instance of the ServiceConfiguration class. /// /// Name of the cloud service. /// Guest OS that will run on role instances in the cloud service. /// Version of the Guest OS that will run on role instances in the cloud service. /// Version of the Service Configuration schema. /// Name of the role. /// Number of instances to deploy for this role. public ServiceConfiguration( string serviceName, string osFamily, string osVersion, string schemaVersion, string roleName, int instanceCount) { this.serviceName = serviceName; this.osFamily = osFamily; this.osVersion = osVersion; this.schemaVersion = schemaVersion; this.roleName = roleName; this.instanceCount = instanceCount; } /// /// Gets the service name. /// public string ServiceName { get { return this.serviceName; } } /// /// Gets the OS Family. /// public string OsFamily { get { return this.osFamily; } } /// /// Gets the OS Version. /// public string OsVersion { get { return this.osVersion; } } /// /// Gets the Schema Version. /// public string SchemaVersion { get { return this.schemaVersion; } } /// /// Gets the name of the role. /// public string RoleName { get { return this.roleName; } } /// /// Gets the number of instances. /// public int InstanceCount { get { return this.instanceCount; } } /// /// Creates a ServiceConfiguration from an XML representation. /// /// /// A string containing an XML document representing a request. /// /// /// A new request corresponding to the XML representation read. /// public static ServiceConfiguration FromXml(string xs) { XmlReader xr = XmlReader.Create(new StringReader(xs)); while (xr.Read()) { if (xr.NodeType == XmlNodeType.Element) { break; } } return ReadXml(xr); } /// /// Helper function to read an XML element (not a full document) /// representing an Azure Service Configuration. /// /// /// Note that the XmlReader is expected to be positioned in the XML /// document such that the current node is a request element. /// /// The XmlReader object to read from. /// /// A new request corresponding to the XML representation read. /// public static ServiceConfiguration ReadXml(XmlReader xr) { Debug.Assert(xr.Name.Equals(ServiceConfiguration.XmlTag), "Invalid call"); string serviceName = xr.GetAttribute(ServiceConfiguration.XmlServiceNameAttribute); string osFamily = xr.GetAttribute(ServiceConfiguration.XmlOSFamilyAttribute); string osVersion = xr.GetAttribute(ServiceConfiguration.XmlOSVersionAttribute); string schemaVersion = xr.GetAttribute(ServiceConfiguration.XmlSchemaVersionAttribute); string roleName = string.Empty; int instanceCount = 0; while (xr.Read()) { if (xr.NodeType == XmlNodeType.Element) { switch (xr.Name) { case XmlRoleElement: roleName = xr.GetAttribute(ServiceConfiguration.XmlRoleNameAttribute); break; case XmlInstancesElement: string temp = xr.GetAttribute(ServiceConfiguration.XmlInstanceCountAttribute); instanceCount = int.Parse(temp); break; case XmlConfigurationSettingsElement: break; } } else if (xr.NodeType == XmlNodeType.EndElement) { if (xr.Name.Equals(ServiceConfiguration.XmlTag)) { break; // All done. } } } // REVIEW: Sanity check elements here? return new ServiceConfiguration( serviceName, osFamily, osVersion, schemaVersion, roleName, instanceCount); } /// /// Creates an XML document representing this cloud execution request. /// /// /// A string containing an XML document representing this request. /// public string ToXml() { StringBuilder sb = new StringBuilder(); XmlWriterSettings settings = new XmlWriterSettings(); settings.Indent = true; ////settings.OmitXmlDeclaration = true; XmlWriter xw = XmlWriter.Create(sb, settings); xw.WriteStartDocument(); this.WriteXml(xw); xw.Close(); return sb.ToString(); } /// /// Helper function to write an XML element (not a full document) /// representing this result record. /// /// The XmlWriter object to write to. public void WriteXml(XmlWriter xw) { // Start writing the element for this object. xw.WriteStartElement(XmlTag, ServiceConfiguration.XmlNamespace); xw.WriteAttributeString(ServiceConfiguration.XmlServiceNameAttribute, this.serviceName); xw.WriteAttributeString(ServiceConfiguration.XmlOSFamilyAttribute, this.osFamily); xw.WriteAttributeString(ServiceConfiguration.XmlOSVersionAttribute, this.osVersion); xw.WriteAttributeString(ServiceConfiguration.XmlSchemaVersionAttribute, this.schemaVersion); // Start writing the Role element. xw.WriteStartElement(ServiceConfiguration.XmlRoleElement); xw.WriteAttributeString(ServiceConfiguration.XmlRoleNameAttribute, this.roleName); // Write the Instances element. xw.WriteStartElement(ServiceConfiguration.XmlInstancesElement); xw.WriteAttributeString(ServiceConfiguration.XmlInstanceCountAttribute, this.instanceCount.ToString(CultureInfo.InvariantCulture)); xw.WriteEndElement(); // Write the ConfigurationSettings element. xw.WriteElementString(ServiceConfiguration.XmlConfigurationSettingsElement, string.Empty); // Finish writing the Role element. xw.WriteEndElement(); // Finish writing the element for this object. xw.WriteEndElement(); } /// /// Gets a string representation of this instance. /// Primarily intended as a debugging aid. /// /// A string representation of this instance. public override string ToString() { StringBuilder output = new StringBuilder(); output.AppendFormat("Service Name: {0}", this.serviceName); output.AppendLine(); output.AppendFormat("OS Family: {0}", this.osFamily); output.AppendLine(); output.AppendFormat("OS Version: {0}", this.osVersion); output.AppendLine(); output.AppendFormat("Schema Version: {0}", this.schemaVersion); output.AppendLine(); output.AppendFormat("Role Name: {0}", this.roleName); output.AppendLine(); output.AppendFormat("Number of Instances: {0}", this.instanceCount); output.AppendLine(); return output.ToString(); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/CloudExecutionEngine/App.config ================================================  ================================================ FILE: ironclad-apps/tools/NuBuild/CloudExecutionEngine/CloudExecutionEngine.csproj ================================================  Debug AnyCPU {2668E334-0B79-4023-A621-2D1433CE7C9E} Exe Properties CloudExecutionEngineStandalone CloudExecutionEngine v4.5 512 AnyCPU true full false bin\Debug\ DEBUG;TRACE prompt 4 AnyCPU pdbonly true bin\Release\ TRACE prompt 4 False ..\References\Microsoft.WindowsAzure.Storage.dll {4f3de22c-cae9-408b-aa54-10dcd7e12f09} CloudExecutionWorker ================================================ FILE: ironclad-apps/tools/NuBuild/CloudExecutionEngine/Program.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace CloudExecutionEngineStandalone { using System; using System.Collections.Generic; using System.IO; using CloudExecutionWorker; /// /// Representation of the Cloud Execution Engine. /// internal class Program { /// /// Run executable requests posted to the requests queue. /// /// The parameter is unused. public static void Main(string[] args) { CloudExecutionEngine engine = new CloudExecutionEngine(); engine.Run(); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/CloudExecutionEngine/Properties/AssemblyInfo.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("CloudExecutionEngine")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("CloudExecutionEngine")] [assembly: AssemblyCopyright("Copyright © 2014")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("5ff7c12f-584f-4104-8e04-8f6f63873a02")] // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: ironclad-apps/tools/NuBuild/CloudExecutionWorker/CloudExecutionEngine.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace CloudExecutionWorker { using System; using System.Collections.Generic; using System.IO; using NuBuild; /// /// Representation of the Cloud Execution Engine. /// public class CloudExecutionEngine { /// /// Root directory path. /// private string virtualIronRoot; /// /// Cloud implementation of the item cache. /// Used to explicitly store things in the cloud. /// private ItemCacheCloud cloudCache; /// /// Multiplexed cloud/local implementation of the item cache. /// private IItemCache multiplexedItemCache; /// /// Main queue of client execution requests. /// private CloudExecutionQueue mainQueue; /// /// Whether to continue servicing the queue requests. /// private bool keepSwimming; /// /// Initializes a new instance of the CloudExecutionEngine class. /// public CloudExecutionEngine() { // Establish various infrastructure. // TODO: Clean this up. this.virtualIronRoot = Directory.GetCurrentDirectory(); string localCacheDirectory = Path.Combine(this.virtualIronRoot, "nucache"); this.cloudCache = new ItemCacheCloud(); this.multiplexedItemCache = new ItemCacheMultiplexer( new ItemCacheLocal(localCacheDirectory), this.cloudCache, null); Console.WriteLine("Accessing execution queue."); this.mainQueue = new CloudExecutionQueue(); } /// /// Runs the execution engine, which eternally processes execution /// requests posted to the main queue. /// public void Run() { this.keepSwimming = true; while (this.keepSwimming) { // Pull request off queue. Console.WriteLine("Waiting for new work request."); CloudExecutionRequest executionRequest = this.mainQueue.GetRequest(block: true); if (!this.keepSwimming) { // Exit without deleting request from queue. // Request will become visible again after timeout expires. break; } // TODO: For now, we immediately delete the requests we take. // Eventually we'll want to leave the request invisible until // some timeout expires so that other engines can pick it up // if we crash. this.mainQueue.DeleteRequest(executionRequest); Console.WriteLine("Received request with ID {0}.", executionRequest.Identifier); // Make a progress report to soothe nervous users. CloudExecutionReport statusUpdate = new CloudExecutionReport( executionRequest.Identifier, CloudExecutionReport.StatusCode.InProgress, 0, null, null, 0, null); // Submit progress report. this.mainQueue.SubmitReport(statusUpdate, executionRequest.ReportQueue); // Do the requested operation. CloudExecutionReport report = null; switch (executionRequest.RequestedOperation) { case CloudExecutionRequest.Operation.RunExecutable: report = this.RunAnExecutable(executionRequest); break; case CloudExecutionRequest.Operation.CommitSuicide: this.keepSwimming = false; goto case CloudExecutionRequest.Operation.None; case CloudExecutionRequest.Operation.DeleteQueue: this.mainQueue.DeleteQueue(executionRequest.ReportQueue); goto case CloudExecutionRequest.Operation.None; case CloudExecutionRequest.Operation.None: report = new CloudExecutionReport( executionRequest.Identifier, CloudExecutionReport.StatusCode.Completed); break; default: // ToDo: This should probably be treated as an error. goto case CloudExecutionRequest.Operation.None; } // Submit report. this.mainQueue.SubmitReport(report, executionRequest.ReportQueue); } } /// /// Stops the execution engine. /// public void Stop() { this.keepSwimming = false; } /// /// Run the requested executable and produce a report of the results. /// /// The execution request. /// A report of the results. private CloudExecutionReport RunAnExecutable(CloudExecutionRequest executionRequest) { // REVIEW: How/whether to use this. BuildObject diagnosticsBase = new BuildObject(Path.Combine("nuobj", "diagnostics", "process")); // Prep working directory with input files and output dirs. // TODO: The below will throw cache exceptions if something // isn't there (they should all be though). Need to catch // these and fail the execution request when this happens. WorkingDirectory workingDirectory = new WorkingDirectory(this.virtualIronRoot); foreach (BuildObjectValuePointer inputFile in executionRequest.InputFileMappings) { // REVIEW: How to determine cache container here. ItemCacheContainer container = ItemCacheContainer.Sources; if (this.multiplexedItemCache.GetItemSize(container, inputFile.ObjectHash) == -1) { container = ItemCacheContainer.Objects; } // TODO: Move path/directory manipulation code into // WorkingDirectory and/or ItemCache. string inputFilePath = workingDirectory.PathTo(inputFile.RelativePath); Directory.CreateDirectory(Path.GetDirectoryName(inputFilePath)); // REVIEW: Still neeeded? this.multiplexedItemCache.FetchItemToFile( container, inputFile.ObjectHash, inputFilePath); } foreach (BuildObject outputFile in executionRequest.OutputFiles) { workingDirectory.CreateDirectoryFor(outputFile); } // Run executable. ProcessInvoker pinv = new ProcessInvoker( workingDirectory, executionRequest.Executable, new string[] { executionRequest.Arguments }, diagnosticsBase, null, // This is captureStdout. TODO: Should cleanup how this is used in ProcessInvoker. null); // This is dbgText. REVIEW: How/whether to use this. // When ProcessInvoker's constructor returns, the process has // finished running. Console.WriteLine("Request {0} completed in {1} seconds.", executionRequest.Identifier, pinv.CpuTime); // Store output files in the (cloud) item cache, and create a // list of the mappings. List outputFileMappings = new List(); foreach (BuildObject outFile in executionRequest.OutputFiles) { if (File.Exists(workingDirectory.PathTo(outFile))) { string fileHash = Util.hashFilesystemPath(workingDirectory.PathTo(outFile)); Util.Assert(!string.IsNullOrEmpty(fileHash)); // Note we explicitly write to the cloud cache here. this.cloudCache.StoreItemFromFile(ItemCacheContainer.Objects, fileHash, workingDirectory.PathTo(outFile)); outputFileMappings.Add(new BuildObjectValuePointer(fileHash, outFile.getRelativePath())); } } // Collect the results into a report. CloudExecutionReport report = new CloudExecutionReport( executionRequest.Identifier, CloudExecutionReport.StatusCode.Completed, pinv.ExitCode, pinv.GetStdout(), pinv.GetStderr(), pinv.CpuTime, outputFileMappings); return report; } } } ================================================ FILE: ironclad-apps/tools/NuBuild/CloudExecutionWorker/CloudExecutionWorker.csproj ================================================  Debug AnyCPU 8.0.30703 2.0 {4F3DE22C-CAE9-408B-AA54-10DCD7E12F09} Library Properties CloudExecutionWorker CloudExecutionWorker v4.5 512 Worker true full false bin\Debug\ DEBUG;TRACE prompt 4 pdbonly true bin\Release\ TRACE prompt 4 True False Designer {4d7220c0-3caa-4659-9f16-a564db3ccc1b} NuBuild ================================================ FILE: ironclad-apps/tools/NuBuild/CloudExecutionWorker/Properties/AssemblyInfo.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("CloudExecutionWorker")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("CloudExecutionWorker")] [assembly: AssemblyCopyright("Copyright © 2015")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("4143a7eb-b9aa-4dfb-87ac-1b961e44a2e7")] // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: ironclad-apps/tools/NuBuild/CloudExecutionWorker/WorkerRole.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace CloudExecutionWorker { using System; using System.Diagnostics; using System.Net; using Microsoft.WindowsAzure; using Microsoft.WindowsAzure.Diagnostics; using Microsoft.WindowsAzure.ServiceRuntime; /// /// Our worker role. /// This is what Azure knows how to interact with. /// /// /// For information on handling configuration changes /// . /// public class WorkerRole : RoleEntryPoint { /// /// Our CloudExecutionEngine that does the real work. /// private CloudExecutionEngine engine; /// /// Azure calls this method to do the main work. /// If this method returns, Azure will recycle this role instance. /// public override void Run() { Trace.TraceInformation("CloudExecutionWorker entry point called"); this.engine = new CloudExecutionEngine(); // TODO: Multi-thread this. this.engine.Run(); } /// /// Called when this role instance is brought online by Azure. /// /// /// Whether Azure should proceed with calling our Run method. /// public override bool OnStart() { // Set the maximum number of concurrent connections. //// ServicePointManager.DefaultConnectionLimit = 12; return base.OnStart(); } /// /// Called after this role instance has been taken offline by Azure /// but before the process exits. /// public override void OnStop() { this.engine.Stop(); base.OnStop(); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/CloudExecutionWorker/app.config ================================================  ================================================ FILE: ironclad-apps/tools/NuBuild/CloudQueueTool/App.config ================================================  ================================================ FILE: ironclad-apps/tools/NuBuild/CloudQueueTool/CloudQueueTool.csproj ================================================  Debug AnyCPU {DD7B4AD9-1EB0-47BF-B4C2-5BC1CA85D242} Exe Properties CloudQueueTool CloudQueueTool v4.5 512 AnyCPU true full false bin\Debug\ DEBUG;TRACE prompt 4 AnyCPU pdbonly true bin\Release\ TRACE prompt 4 False ..\References\Microsoft.WindowsAzure.Storage.dll ================================================ FILE: ironclad-apps/tools/NuBuild/CloudQueueTool/Program.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace CloudQueueTool { using System; using System.Collections.Generic; using System.Configuration; using System.IO; using Microsoft.WindowsAzure.Storage; using Microsoft.WindowsAzure.Storage.Queue; /// /// Cloud queue management program. /// internal class Program { /// /// Acts upon command line arguments. /// /// Command line arguments. private static void Main(string[] args) { // Create our CloudQueueClient object. // REVIEW: Hard-coded connection string index "Ironclad". string connectionString = null; ConnectionStringSettings settings = ConfigurationManager.ConnectionStrings["Ironclad"]; if (settings != null) { connectionString = settings.ConnectionString; } if (string.IsNullOrEmpty(connectionString)) { throw new ConfigurationException("Azure connection string missing from your .exe.config file!"); } CloudStorageAccount storageAccount = CloudStorageAccount.Parse(connectionString); CloudQueueClient queueClient = storageAccount.CreateCloudQueueClient(); switch (args.Length) { case 0: Status(queueClient.ListQueues()); break; case 2: { CloudQueue queue = queueClient.GetQueueReference(args[1]); if (!queue.Exists()) { Console.WriteLine("No such queue '{0}'", args[1]); return; } queue.FetchAttributes(); switch (args[0]) { case "clear": case "Clear": queue.Clear(); Console.WriteLine("Queue '{0}' cleared.", queue.Name); break; case "peek": case "Peek": int numberToPeekAt = (queue.ApproximateMessageCount != null) ? (int)queue.ApproximateMessageCount : 0; Console.WriteLine("Queue '{0}' contains {1} messages:", queue.Name, numberToPeekAt); if (numberToPeekAt != 0) { // Peek API only allows a maximum of 32 messages to be peeked at. numberToPeekAt = Math.Min(numberToPeekAt, 32); foreach (CloudQueueMessage message in queue.PeekMessages(numberToPeekAt)) { Console.WriteLine( "\t{0} {1} {2}", message.Id, message.InsertionTime, message.ExpirationTime); } } break; case "status": case "Status": Status(new CloudQueue[]{queue}); break; default: Usage(); break; } } break; default: Usage(); break; } } private static void Status(IEnumerable queues) { foreach (CloudQueue queue in queues) { queue.FetchAttributes(); Console.WriteLine("Queue '{0}' contains about {1} messages.", queue.Name, queue.ApproximateMessageCount); } } private static void Usage() { Console.WriteLine("Usage: CloudQueueTool [ ]"); Console.WriteLine("\t = Clear | Peek | Status"); Console.WriteLine("\t = reports | requests"); Console.WriteLine(); Console.WriteLine("If given no arguments, CloudQueueTool returns the status of all queues."); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/CloudQueueTool/Properties/AssemblyInfo.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("CloudQueueTool")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("CloudQueueTool")] [assembly: AssemblyCopyright("Copyright © 2014")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("0321a4d8-87f1-4467-b44a-b5e355a614b9")] // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: ironclad-apps/tools/NuBuild/CustomDictionary.xml ================================================ asynchronicity cscfg csdef cspkg cpu Dafny filesystem ifc Ironfleet munged nuobj rejectable src obj Nu ================================================ FILE: ironclad-apps/tools/NuBuild/ItemCacheTool/App.config ================================================  ================================================ FILE: ironclad-apps/tools/NuBuild/ItemCacheTool/CacheState.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace ItemCacheTool { using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using NuBuild; public class CacheState { private ItemCacheCloud cloudCache; private ItemCacheLocal localCache; public CacheState() { this.cloudCache = new ItemCacheCloud(); this.localCache = new ItemCacheLocal( Path.Combine(GetDefaultIronRoot(), "nucache")); } public ItemCacheCloud GetCloudCache { get { return this.cloudCache; } } public ItemCacheLocal GetLocalCache { get { return this.localCache; } } public IItemCache[] GetAllCaches { get { return new IItemCache[] { this.cloudCache, this.localCache }; } } public ItemCacheContainer[] GetAllContainers { get { return (ItemCacheContainer[])Enum.GetValues(typeof(ItemCacheContainer)); } } public IItemCache[] ParseCacheName(string input) { if (input == "*") { return this.GetAllCaches; } if (string.Equals(input, "cloud", StringComparison.CurrentCultureIgnoreCase)) { return new IItemCache[] { this.cloudCache }; } if (string.Equals(input, "local", StringComparison.CurrentCultureIgnoreCase)) { return new IItemCache[] { this.localCache }; } return null; } public ItemCacheContainer[] ParseContainerName(string input) { ItemCacheContainer container; if (input == "*") { return this.GetAllContainers; } if (Enum.TryParse(input, true, out container)) { if (Enum.IsDefined(typeof(ItemCacheContainer), container)) { return new ItemCacheContainer[] { container }; } } return null; } /// /// Gets the default iron root path. /// /// String containing the default iron root path. private static string GetDefaultIronRoot() { string assyUri = System.Reflection.Assembly.GetExecutingAssembly().CodeBase; string assyPath = new Uri(assyUri).LocalPath; string exepath = Path.GetDirectoryName(assyPath); exepath = Path.GetFullPath(exepath); string[] parts = exepath.Split(new char[] { '\\' }); int ironIndex = Array.IndexOf(parts, "iron"); string rc = string.Join("\\", parts.Take(ironIndex + 1)); return rc; } } } ================================================ FILE: ironclad-apps/tools/NuBuild/ItemCacheTool/ItemCacheTool.csproj ================================================ Debug AnyCPU {9A231EB8-BDA1-4304-93A1-20457C00D7D9} Exe Properties ItemCacheTool ItemCacheTool v4.5 512 AnyCPU true full false bin\Debug\ DEBUG;TRACE prompt 4 AllRules.ruleset AnyCPU pdbonly true bin\Release\ TRACE prompt 4 False ..\References\Microsoft.WindowsAzure.Storage.dll {4d7220c0-3caa-4659-9f16-a564db3ccc1b} NuBuild CustomDictionary.xml ================================================ FILE: ironclad-apps/tools/NuBuild/ItemCacheTool/Program.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace ItemCacheTool { using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using Microsoft.WindowsAzure.Storage; using Microsoft.WindowsAzure.Storage.Blob; using NuBuild; /// /// Representation of the ItemCacheTool program. /// public static class Program { /// /// Program entry point. /// /// Command line arguments. private static void Main(string[] args) { CacheState caches = new CacheState(); string query; IItemCache[] queriedCaches; ItemCacheContainer[] queriedContainers; string queriedItems; DateTimeOffset queriedDate; // - // Default values. // This corresponds to "status * *". // - query = "status"; queriedCaches = caches.GetAllCaches; queriedContainers = caches.GetAllContainers; queriedItems = string.Empty; queriedDate = DateTimeOffset.MinValue; // - // Parse arguments. // - if (args.Length != 0) { if (args.Length != 3) { if (args.Length == 4) { if (!DateTimeOffset.TryParse(args[3], out queriedDate)) { queriedItems = args[3]; } } else { Usage(caches); return; } } query = args[0]; queriedCaches = caches.ParseCacheName(args[1]); queriedContainers = caches.ParseContainerName(args[2]); if ((queriedCaches == null) || (queriedContainers == null)) { Usage(caches); return; } } // - // Process request. // - switch (query) { case "list": case "List": { CacheStatus(queriedCaches, queriedContainers, true); break; } case "compare": case "Compare": { if (queriedCaches.Length < 2) { Console.WriteLine("Error: can't compare fewer than two caches!"); Usage(caches); return; } CompareCacheContainers(queriedCaches, queriedContainers); break; } case "status": case "Status": { CacheStatus(queriedCaches, queriedContainers, false); break; } case "delete": case "Delete": { if (args.Length < 4) { Console.WriteLine("Error: missing argument. Need date earlier than or specific item(s) to delete."); Usage(caches); return; } if (queriedDate == DateTimeOffset.MinValue) { DeleteItems(queriedCaches, queriedContainers, queriedItems); } else { DeleteItems(queriedCaches, queriedContainers, queriedDate); } break; } case "check": case "Check": { CheckResults(queriedCaches, false); break; } case "cleanup": case "Cleanup": { CheckResults(queriedCaches, true); break; } case "dump": case "Dump": { DumpItems(queriedCaches, queriedContainers, queriedItems); break; } } } /// /// Prints a user-friendly message explaining how to use the program. /// /// The caches the program is using. private static void Usage(CacheState caches) { string containers = string.Empty; foreach (ItemCacheContainer container in caches.GetAllContainers) { containers += container.ToString() + " | "; } containers += " *"; Console.WriteLine("Usage: ItemCacheTool [ | ]"); Console.WriteLine("\t = Check | Cleanup | Compare | Delete | List | Status"); Console.WriteLine("\t = Cloud | Local | *"); Console.WriteLine("\t = {0}", containers); Console.WriteLine("\t [ | ] = specifies item(s) to delete."); } /// /// Provides a status report of the number of items in the specified /// cache containers, and optionally a list of those items. /// /// Caches to examine. /// Containers in those caches to examine. /// Whether to list the cache contents. private static void CacheStatus( IItemCache[] queriedCaches, ItemCacheContainer[] queriedContainers, bool listContents) { string lineTerminator = "."; if (listContents) { lineTerminator = ":"; } foreach (IItemCache cache in queriedCaches) { foreach (ItemCacheContainer container in queriedContainers) { HashSet items = cache.GetItemsInContainer(container); Console.WriteLine("{0} cache {1} container holds {2} items{3}", cache.Name, container.ToString(), items.Count, lineTerminator); if (listContents) { foreach (string item in items) { ////Console.WriteLine("Item: {0}, Date:{1}", item, cache.GetItemLastModifiedTime(container, item)); Console.WriteLine(item); } Console.WriteLine(); } } Console.WriteLine(); } } /// /// Compares the contents of two caches. /// /// Caches to compare. /// Containers in those caches to compare. private static void CompareCacheContainers( IItemCache[] queriedCaches, ItemCacheContainer[] queriedContainers) { foreach (ItemCacheContainer container in queriedContainers) { IItemCache cacheA = queriedCaches[0]; IItemCache cacheB = queriedCaches[1]; HashSet cacheAItems = cacheA.GetItemsInContainer(container); HashSet cacheBItems = cacheB.GetItemsInContainer(container); Console.WriteLine("There are {0} items in the {1} cache {2} container.", cacheAItems.Count, cacheA.Name, container.ToString()); Console.WriteLine("There are {0} items in the {1} cache {2} container.", cacheBItems.Count, cacheB.Name, container.ToString()); HashSet syncedItems = new HashSet(cacheAItems); syncedItems.IntersectWith(cacheBItems); Console.WriteLine("There are {0} items present in both cache's {1} container.", syncedItems.Count, container); Console.WriteLine(); } } /// /// Deletes the given items from the given caches and containers. /// /// Caches to look in. /// Containers to look in. /// Items to delete. private static void DeleteItems( IItemCache[] queriedCaches, ItemCacheContainer[] queriedContainers, string queriedItems) { if (queriedItems == "*") { if (!DeleteItemsConfirmation()) { return; } } foreach (IItemCache cache in queriedCaches) { foreach (ItemCacheContainer container in queriedContainers) { if (queriedItems == "*") { HashSet items = cache.GetItemsInContainer(container); foreach (string item in items) { cache.DeleteItem(container, item); } } else { cache.DeleteItem(container, queriedItems); } } } } /// /// Deletes the items from the given caches and containers /// that have an earlier last modified time than the given one. /// /// Caches to look in. /// Containers to look in. /// Date to compare against. private static void DeleteItems( IItemCache[] queriedCaches, ItemCacheContainer[] queriedContainers, DateTimeOffset queriedDate) { if (!DeleteItemsConfirmation()) { return; } foreach (IItemCache cache in queriedCaches) { foreach (ItemCacheContainer container in queriedContainers) { HashSet items = cache.GetItemsInContainer(container); foreach (string item in items) { DateTimeOffset? lastModified = cache.GetItemLastModifiedTime(container, item); if (lastModified.HasValue && (lastModified.Value.CompareTo(queriedDate) < 0)) { cache.DeleteItem(container, item); } } } } } /// /// Asks the user for confirmation that deleting a large number of cache items is okay. /// /// True if deletion is okay, false otherwise. private static bool DeleteItemsConfirmation() { string input; string annoyingConfirmationString = "Yes I mean to do this!"; Console.WriteLine("You are about to delete a potentially large number of cache items!"); Console.WriteLine("To proceed, please enter '{0}':", annoyingConfirmationString); input = Console.ReadLine(); if (input != annoyingConfirmationString) { Console.WriteLine("Your input didn't match. Exiting without deleting anything."); return false; } return true; } /// /// Dumps the given items from the given caches and containers. /// /// Caches to look in. /// Containers to look in. /// Items to dump. private static void DumpItems( IItemCache[] queriedCaches, ItemCacheContainer[] queriedContainers, string queriedItems) { foreach (IItemCache cache in queriedCaches) { foreach (ItemCacheContainer container in queriedContainers) { if (queriedItems == "*") { HashSet items = cache.GetItemsInContainer(container); foreach (string item in items) { DumpItem(cache, container, item); } } else { DumpItem(cache, container, queriedItems); } } } } /// /// Dumps the given item from the given cache and container. /// /// Cache to look in. /// Container to look in. /// Item to dump. private static void DumpItem(IItemCache cache, ItemCacheContainer container, string item) { #if true byte[] content = cache.FetchItem(container, item); if (content != null) { BinaryWriter writer = new BinaryWriter(Console.OpenStandardOutput()); writer.Write(content); writer.Close(); } #endif #if false ResultSummaryRecord record = FetchRecord(cache, container, item); if (record != null) { Console.WriteLine(); Console.WriteLine("IsVerificationTimeout = {0}", record.IsVerificationTimeout); Console.WriteLine("IsFailure = {0}", record.IsFailure); } else { Console.WriteLine(); Console.WriteLine("FetchRecord failed for {0}", item); } #endif } /// /// Checks the given cache(s) Results and FailedResults for goodness. /// /// Caches to check. /// Whether to cleanup after bad cache entries. private static void CheckResults( IItemCache[] queriedCaches, bool cleanup) { // We can do this for Local, Cloud, or both. foreach (IItemCache cache in queriedCaches) { // We have one Objects container for objects referenced by // results in both the Results and FailedResults containers. HashSet objects = cache.GetItemsInContainer(ItemCacheContainer.Objects); // Likewise, we have only one Sources container. // REVIEW: Should a "source" ever show up as a verb result? HashSet sources = cache.GetItemsInContainer(ItemCacheContainer.Sources); // We initialize the orphanedObjects set to all objects and // then remove objects from the set when we find them listed // in a result (stored in either Results or FailedResults). HashSet orphanedObjects = cache.GetItemsInContainer(ItemCacheContainer.Objects); // We check both successful and failed results. foreach (ItemCacheContainer resultsContainer in new ItemCacheContainer[] { ItemCacheContainer.Results, ItemCacheContainer.FailedResults }) { HashSet parseErrors = new HashSet(); // Misfiled results (i.e. failures in Results container or // non-failures in FailedResults container). HashSet misfiledResults = new HashSet(); // Results that are missing one or more ouput objects. HashSet resultsMissingOutputs = new HashSet(); HashSet missingOutputHashes = new HashSet(); HashSet missingOutputPaths = new HashSet(); int timeouts = 0; int failures = 0; int missing = 0; HashSet results = cache.GetItemsInContainer(resultsContainer); foreach (string result in results) { ResultSummaryRecord record = FetchRecord(cache, resultsContainer, result); if (record == null) { Console.WriteLine("Parse error in {0}.", result); parseErrors.Add(result); } else { if (record.IsFailure) { if (resultsContainer == ItemCacheContainer.Results) { // We shouldn't have any failures in Results! misfiledResults.Add(result); } if (record.IsVerificationTimeout) { ////Console.WriteLine("Timeout in {0}.", result); timeouts++; } else { ////Console.WriteLine("Failure in {0}.", result); failures++; } } else if (resultsContainer == ItemCacheContainer.FailedResults) { // We should only have failures in FailedResults! misfiledResults.Add(result); } // Verify each output is in the cache. bool hasMissingOuputs = false; foreach (BuildObjectValuePointer output in record.Outputs) { if (objects.Contains(output.ObjectHash)) { // Output present in object cache. // Remove it from orphaned objects list. orphanedObjects.Remove(output.ObjectHash); } else if (sources.Contains(output.ObjectHash)) { // Output present in sources cache. Console.WriteLine("Has 'source' file listed as an output: {0}!", result); } else { // Output missing from both object and sources caches. hasMissingOuputs = true; missingOutputHashes.Add(output.ObjectHash); missingOutputPaths.Add(output.RelativePath); missing++; Console.WriteLine("Missing Output Listed in {0}, Object {1} ({2}).", result, output.ObjectHash, output.RelativePath); } } if (hasMissingOuputs) { resultsMissingOutputs.Add(result); } } } Console.WriteLine(); Console.WriteLine("Checked {0} results in {1} cache {2} container:", results.Count, cache.Name, resultsContainer.ToString()); Console.WriteLine("Corrupted (parsing errors or otherwise unreadable): {0}", parseErrors.Count); Console.WriteLine("Filed in wrong container: {0}", misfiledResults.Count); Console.WriteLine("Timeouts: {0}, Other failures: {1}, Total failures: {2}", timeouts, failures, timeouts + failures); Console.WriteLine("Missing at least one output object: {0}", resultsMissingOutputs.Count); Console.WriteLine("Total missing output objects: {0}, Unique contents: {1}, Unique paths: {2}", missing, missingOutputHashes.Count, missingOutputPaths.Count); Console.WriteLine(); if (cleanup) { if (misfiledResults.Count != 0) { Console.Write("Deleting misfiled results..."); foreach (string misfiledResult in misfiledResults) { cache.DeleteItem(resultsContainer, misfiledResult); } Console.WriteLine("Done."); } if (resultsMissingOutputs.Count != 0) { Console.Write("Deleting results with missing outputs..."); foreach (string resultMissingOutputs in resultsMissingOutputs) { cache.DeleteItem(resultsContainer, resultMissingOutputs); } Console.WriteLine("Done."); } Console.WriteLine(); } } // REVIEW: in at least one instance, we cache an intermediate // object that isn't referenced by a result. That instance is // DafnyIncludes.ExpandDafny(), which is called from // DafnyCompileOneVerb. This is to allow cloud execution of the // process invoke part of the verb's execution (with the dafny // expansion happening in the verb's getWorker() method). Since // ExpandDafny() is a work-around for a Dafny issue, it's not // clear whether we should further accommodate this in the build // system (i.e. by making ExpandDafny its own verb) or not. // At any rate, having orphaned objects is not necessarily bad. Console.WriteLine("Orphaned objects not listed in any result: {0}", orphanedObjects.Count); if (cleanup) { Console.WriteLine(); if (orphanedObjects.Count != 0) { Console.Write("Deleting orphaned objects..."); foreach (string orphanedObject in orphanedObjects) { cache.DeleteItem(ItemCacheContainer.Objects, orphanedObject); } Console.WriteLine("Done."); } } } } /// /// Retrieves the requested result from the given cache. /// /// Cache to query. /// Container to query. /// Result to get. /// The requested ResultSummaryRecord, or null if not found. private static ResultSummaryRecord FetchRecord(IItemCache cache, ItemCacheContainer container, string itemHash) { byte[] result = cache.FetchItem(container, itemHash); if (result != null) { MemoryStream resultStream = new MemoryStream(result); try { using (StreamReader inReader = new StreamReader(resultStream)) { string xmlSummary = inReader.ReadToEnd(); ResultSummaryRecord record = ResultSummaryRecord.FromXml(xmlSummary); if (record == null) { Console.WriteLine("FromXml failed for {0}", itemHash); } return record; } } catch (System.Xml.XmlException ex) { Console.WriteLine("Malformed xml in {0}: {1}", itemHash, ex.ToString()); return null; } finally { resultStream.Dispose(); } } else { Console.WriteLine("FetchItem failed for {0}", itemHash); return null; } } } } ================================================ FILE: ironclad-apps/tools/NuBuild/ItemCacheTool/Properties/AssemblyInfo.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("ItemCacheTool")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("ItemCacheTool")] [assembly: AssemblyCopyright("Copyright © 2014")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("47dce4f0-18af-4c9e-b177-4ae324563ed6")] // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/.gitignore ================================================ *.user ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/AbstractId.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; internal class AbstractId { private const int MASTER_VERSION = 3; // Bump this to invalidate every verb in all caches. private string verbName; private int version; private string abstractOnly; // PoundDefines should appear in both abstract and concrete descriptions: // abstract because we run one verb with multiple poundDefine configurations, // and concrete because the variation appears only in this parameter to the // verb, not in any input file contents. private PoundDefines poundDefines; private string concrete; public AbstractId(string verbName, int version, string abstractOnly, PoundDefines poundDefines = null, string concrete = null) { this.verbName = verbName; this.version = version + MASTER_VERSION; this.abstractOnly = abstractOnly; this.poundDefines = poundDefines == null ? PoundDefines.empty() : poundDefines; this.concrete = concrete; } public override bool Equals(object obj) { AbstractId other = obj as AbstractId; if (other != null) { return this.verbName == other.verbName && this.version == other.version && this.abstractOnly == other.abstractOnly && this.poundDefines.Equals(other.poundDefines) && this.concrete == other.concrete; } else { return false; } } public override int GetHashCode() { return this.ToString().GetHashCode(); } public override string ToString() { if (this.concrete == null) { return string.Format("{0}(#{1},{2},{3})", this.verbName, this.version, this.abstractOnly, this.poundDefines.getAbstractIdString()); } else { return string.Format("{0}(#{1},{2},{3},{4})", this.verbName, this.version, this.abstractOnly, this.poundDefines.getAbstractIdString(), this.concrete); } } public int CompareTo(object other) { return this.ToString().CompareTo(((AbstractId)other).ToString()); } public string getConcreteId() { // The entire purpose of this class is to avoid encoding the input filename in a verb's concrete identity, // instead encoding it via the input's hash. That enables two verbs to have the same hash when they have // the same configuration, and hence converge -- we can reuse the outputs. // Except that the design is presently flawed: they'd have the same output contents, but not the same // output locations. Until we work that out, I'm neutering this convergence opportunity to preserve // soundness. (--jonh) return this.ToString(); ////if (this.concrete == null) { //// return string.Format("{0}(#{1},{2})", this.verbName, this.version, this.poundDefines); ////} else { //// return string.Format("{0}(#{1},{2},{3})", this.verbName, this.version, this.poundDefines, this.concrete); ////} } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/AnnotationScanner.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Text.RegularExpressions; internal class AnnotationScanner { private BuildObject inputObject; private List annotations; private bool complete; // Constructor for emitting new/code-assembled annotations. public AnnotationScanner() { this.inputObject = null; this.annotations = new List(); this.complete = false; } public AnnotationScanner(BuildObject inputObject) { this.inputObject = inputObject; this.annotations = new List(); Regex re = new Regex("]*)/>"); using (TextReader tr = BuildEngine.theEngine.Repository.OpenRead(inputObject)) { while (true) { string line = tr.ReadLine(); if (line == null) { break; } Match match = re.Match(line); if (match.Success) { string[] arguments = match.Groups[1].ToString().Split(null).Where(s => s.Length > 0).ToArray(); this.annotations.Add(arguments); } } } this.complete = true; } public void addAnnotation(string[] annotation) { Util.Assert(!this.complete); this.annotations.Add(annotation); } public string emit(string commentToken) { this.complete = true; StringBuilder sb = new StringBuilder(); foreach (string[] annotation in this.annotations) { sb.AppendLine(commentToken + ""); } return sb.ToString(); } public IEnumerable getAnnotations(string label) { return this.annotations.Where(sa => sa[0].Equals(label)); } // Look for 0 or 1 instance of a single-valued annotation. public string getTheAnnotation(string label, string defaultValue) { IEnumerable anns = this.getAnnotations(label); if (anns.Count() == 0) { return defaultValue; } string[] ann = anns.First(); if (ann.Length != 2) { throw new SourceConfigurationError( string.Format( "Annotation {0} in file {1} should have exactly one argument", ann[0], this.inputObject.getRelativePath())); } return ann[1]; } internal static void transferAnnotations(WorkingDirectory workingDirectory, BuildObject source, BuildObject dest, string commentToken) { new AnnotationScanner(source).injectAnnotations(workingDirectory, dest, commentToken); } // REVIEW: Make this private? internal void injectAnnotations(WorkingDirectory workingDirectory, BuildObject dest, string commentToken) { string annotations = this.emit(commentToken); // REVIEW: Improve upon this round-about way of prepending to a file? string destStr = File.ReadAllText(workingDirectory.PathTo(dest)); File.Delete(workingDirectory.PathTo(dest)); File.WriteAllText(workingDirectory.PathTo(dest), annotations + destStr); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/App.config ================================================  ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/AsmRewriterVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; internal class AsmRewriterVerb : Verb, IProcessInvokeAsyncVerb, IAsmProducer { public const string WASM_EXTN = ".wasm"; private const int version = 1; private BoogieAsmLinkVerb asmVerb; private AbstractId abstractId; private BuildObject asmFileOut; private BuildObject asmFileIn; private BuildObject pythonScript; public AsmRewriterVerb(BoogieAsmLinkVerb asmVerb) { this.asmVerb = asmVerb; this.asmFileIn = asmVerb.getAsmFile(); this.asmFileOut = this.asmFileIn.makeOutputObject(WASM_EXTN); this.abstractId = new AbstractId(this.GetType().Name, version, this.asmFileOut.ToString()); this.pythonScript = new SourcePath("tools\\scripts\\build-standalone-asm.py", SourcePath.SourceType.Tools); } public override AbstractId getAbstractIdentifier() { return this.abstractId; } public BuildObject getAsmFile() { return this.asmFileOut; } public override IEnumerable getDependencies(out DependencyDisposition ddisp) { ddisp = DependencyDisposition.Complete; return new List() { this.asmFileIn, this.pythonScript }; } public override IEnumerable getVerbs() { return new List() { this.asmVerb }; } public override IEnumerable getOutputs() { return new List() { this.getAsmFile() }; } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { List args = new List() { this.pythonScript.getRelativePath(), this.asmFileIn.getRelativePath() }; string python_exe = @"C:\Python27\pythonw.exe"; if (!File.Exists(python_exe)) { throw new FileNotFoundException("Missing python executable: " + python_exe + ". Try installing from: https://www.python.org/"); } return new ProcessInvokeAsyncWorker( workingDirectory, this, python_exe, args.ToArray(), ProcessExitCodeHandling.NonzeroIsFailure, getDiagnosticsBase(), allowAbsoluteExe: true, captureStdout: this.asmFileOut); } public Disposition Complete(WorkingDirectory workingDirectory, double cpuTimeSeconds, string stdout, string stderr, Disposition disposition) { return disposition; } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/BackgroundWorker.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; /// /// Type of procedure that the background worker thread runs. /// /// Some argument. /// Another argument. public delegate void BackgroundWorkerProcedure(object argument1, object argument2); /// /// Represents a single background worker thread that sequentially performs /// the work added to its queue. /// /// /// This class is not related to System.ComponentModel.BackgroundWorker, /// which provides different functionality. /// public class BackgroundWorker : IDisposable { /// /// Thread that performs the background work. /// private Thread workerThread; /// /// Queue of work for background worker to perform. /// private Queue workQueue; /// /// Lock protecting the work queue. /// private Mutex workQueueLock; /// /// Event that is signalled when new items are placed on the workQueue. /// private AutoResetEvent workQueueHasNewWork; /// /// Count of work items queued to this BackgroundWorker. /// private volatile uint workItemsQueued; /// /// Count of work item procedures performed by this BackgroundWorker. /// private volatile uint workItemsPerformed; /// /// Count of work item procedures known to have failed. /// private volatile uint workItemsFailed; /// /// Flag indicating whether or not the worker thread should exit. /// private volatile bool ourWorkIsNotDone; /// /// Flag indicating whether or not Dispose has already been called. /// private bool disposed; /// /// Initializes a new instance of the BackgroundWorker class. /// public BackgroundWorker() { this.workQueue = new Queue(); this.workQueueLock = new Mutex(); this.workQueueHasNewWork = new AutoResetEvent(false); this.workItemsQueued = 0; this.workItemsPerformed = 0; this.workItemsFailed = 0; this.ourWorkIsNotDone = true; this.disposed = false; this.workerThread = new Thread(new ThreadStart(this.WorkerThreadMain)); // REVIEW: Start worker thread only after the first item is queued? this.workerThread.Start(); } /// /// Gets the count of work items queued to this BackgroundWorker. /// public uint GetWorkItemsQueued { get { return this.workItemsQueued; } } /// /// Gets the count of work item procedures performed by this /// BackgroundWorker. /// public uint GetWorkItemsPerformed { get { return this.workItemsPerformed; } } /// /// Gets the count of work item procedures known to have failed. /// public uint GetWorkItemsFailed { get { return this.workItemsFailed; } } /// /// Adds new work to the background worker's work queue. /// /// /// Procedure the background worker will run. /// /// First argument for procedure. /// Second argument for procedure. public void QueueWork(BackgroundWorkerProcedure procedure, object argument1, object argument2) { BackgroundWorkerQueueItem workItem = new BackgroundWorkerQueueItem(procedure, argument1, argument2); this.workQueueLock.WaitOne(); this.workQueue.Enqueue(workItem); this.workItemsQueued++; this.workQueueLock.ReleaseMutex(); this.workQueueHasNewWork.Set(); } /// /// Tells the worker thread to stop running after completing the /// currently queued work items. /// public void StopWork() { this.QueueWork(this.StopWorkerThread, null, null); } /// /// Wait for the worker thread to exit after a StopWork request. /// /// /// This routine is primarily for making sure the worker thread has /// completed operation before collecting stats from it /// (i.e. calling 'GetWorkItemsPerformed'). Since we don't mark our /// worker thread as a "background" thread, the process will not exit /// until after our thread exits. So this method is not needed for the /// purpose of keeping the main thread and thus process alive until the /// worker thread is done. /// public void WaitForCompletion() { this.workerThread.Join(); } /// /// Releases resources. /// public void Dispose() { this.Dispose(true); GC.SuppressFinalize(this); } /// /// Releases unmanaged and (optionally) managed resources. /// /// Whether or not to release managed resources. protected virtual void Dispose(bool disposing) { if (this.disposed) { return; } if (disposing) { this.workQueueLock.Dispose(); this.workQueueHasNewWork.Dispose(); } this.disposed = true; } /// /// Special BackgroundWorkerProcedure for stopping the worker thread. /// /// /// Note that this procedure ends up being counted in the statistics /// we keep about the number of work items queued/performed. /// /// The parameter is not used. /// The parameter is not used. private void StopWorkerThread( object unused1, object unused2) { this.ourWorkIsNotDone = false; } /// /// Procedure performed by the background worker thread. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "We really do want to catch all exceptions in this case")] private void WorkerThreadMain() { List toDoList = new List(); // - // Run until we're told to stop. // - while (this.ourWorkIsNotDone) { // - // Wait for new work to be added to the queue. // - if (this.workQueueHasNewWork.WaitOne()) { toDoList.Clear(); // - // Pull all queued work items off the global work queue // (while holding the lock), and place them on our // thread-local toDoList. // - this.workQueueLock.WaitOne(); while (this.workQueue.Count > 0) { toDoList.Add(this.workQueue.Dequeue()); } this.workQueueLock.ReleaseMutex(); // - // Do the requested work. // - foreach (BackgroundWorkerQueueItem workItem in toDoList) { try { workItem.Procedure(workItem.Argument1, workItem.Argument2); this.workItemsPerformed++; } catch { // - // Swallow all errors caused by the work item. // But count how often this happens. // - this.workItemsFailed++; } } } } } /// /// Represents a work item on the background worker's work queue. /// private class BackgroundWorkerQueueItem { /// /// The procedure the background worker runs. /// private BackgroundWorkerProcedure procedure; /// /// The first argument to pass to the procedure. /// private object argument1; /// /// The second argument to pass to the procedure. /// private object argument2; /// /// Initializes a new instance of the BackgroundWorkerQueueItem class. /// /// Procedure to run. /// First argument for procedure. /// Second argument for procedure. public BackgroundWorkerQueueItem( BackgroundWorkerProcedure procedure, object argument1, object argument2) { this.procedure = procedure; this.argument1 = argument1; this.argument2 = argument2; } /// /// Gets the procedure the background worker runs. /// public BackgroundWorkerProcedure Procedure { get { return this.procedure; } } /// /// Gets the first argument to pass to the procedure. /// public object Argument1 { get { return this.argument1; } } /// /// Gets the second argument to pass to the procedure. /// public object Argument2 { get { return this.argument2; } } } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/BasmObligationIncludes.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; internal class BasmObligationIncludes : IIncludeFactory { private IIncludePathContext includePathSearcher; private BeatIncludes directIncludes; public BasmObligationIncludes(IIncludePathContext includePathSearcher) { this.includePathSearcher = includePathSearcher; this.directIncludes = new BeatIncludes(includePathSearcher); } public IEnumerable getIncludes(BuildObject beatsrc) { IHasher hasher = BuildEngine.theEngine.getHasher(); OrderPreservingSet includes = new OrderPreservingSet(); BuildObject ifcFile = hasher.search(this.includePathSearcher, beatsrc.getFileNameWithoutExtension(), ModPart.Ifc); BuildObject impFile = hasher.search(this.includePathSearcher, beatsrc.getFileNameWithoutExtension(), ModPart.Imp); Util.Assert(ifcFile.Equals(beatsrc) || impFile.Equals(beatsrc)); includes.AddRange(this.directIncludes.getBasmIncludes(ifcFile)); includes.AddRange(this.directIncludes.getBasmIncludes(impFile)); return includes; } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/BasmTransitiveDepsVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; internal class BasmTransitiveDepsVerb : TransitiveDepsVerb { private IContextGeneratingVerb contextVerb; public BasmTransitiveDepsVerb(IContextGeneratingVerb contextVerb, BuildObject input) : base(input) { this.contextVerb = contextVerb; } protected override TransitiveDepsVerb factory(BuildObject obj) { return new BasmTransitiveDepsVerb(this.contextVerb, obj); } protected override void extendDeps(List deps) { deps.Add(this.contextVerb.getContextOutput()); } protected override IIncludeFactory getIncludeFactory() { ContextContents context = (ContextContents) BuildEngine.theEngine.Repository.FetchVirtual(this.contextVerb.getContextOutput()); return new BasmObligationIncludes(context.Context); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/BatchVerifyVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; using System.Linq; internal class BatchVerifyVerb : Verb, IObligationsProducer { private const string BATCH_EXTN = ".batch"; private const int version = 1; private BuildObject outputObject; private HashSet producers; private AbstractId abstractId; private BatchMode mode; // REVIEW: Never used? private List deps; public BatchVerifyVerb(SourcePath batch_file, BatchMode mode, VerificationRequest verificationRequest, DafnyCCVerb.FramePointerMode useFramePointer) { this.mode = mode; this.producers = new HashSet(); foreach (string line in File.ReadAllLines(IronRootDirectory.PathTo(batch_file))) { if (line.Equals("") || line[0] == '#') { continue; } SourcePath src = new SourcePath(line); switch (mode) { case BatchMode.DAFNY: if (verificationRequest.verifyMode != VerificationRequest.VerifyMode.Verify) { throw new UserError("BatchVerify DAFNY only supports full verification (but maybe we should add selective?)"); } this.producers.Add(new DafnyVerifyTreeVerb(src)); break; case BatchMode.APP: this.producers.Add(new IroncladAppVerb(src, IroncladAppVerb.TARGET.BARE_METAL, useFramePointer, verificationRequest)); break; default: throw new Exception("Unknown batch file type"); } } string parameters = mode.ToString() + "," + verificationRequest.ToString(); this.outputObject = batch_file.makeLabeledOutputObject(parameters, BATCH_EXTN + VerificationObligationList.VOL_EXTN); this.abstractId = new AbstractId(this.GetType().Name, version, batch_file.ToString(), concrete: parameters); } public BatchVerifyVerb(BuildObject batch_label, HashSet producers, BatchMode mode) { this.mode = mode; this.producers = producers; this.outputObject = batch_label.makeOutputObject(BATCH_EXTN + VerificationObligationList.VOL_EXTN); this.abstractId = new AbstractId(this.GetType().Name, version, batch_label.ToString(), concrete: mode.ToString()); } public enum BatchMode { DAFNY, APP } public override AbstractId getAbstractIdentifier() { return this.abstractId; } public BuildObject getObligationSet() { return this.outputObject; } public override IEnumerable getDependencies(out DependencyDisposition ddisp) { if (this.deps == null) { this.deps = new List(); foreach (IObligationsProducer producer in this.producers) { this.deps.Add(producer.getObligationSet()); } } ddisp = DependencyDisposition.Complete; return this.deps; } public override IEnumerable getVerbs() { // Pass this request upstream to expose upstream verbs. HashSet upstreamVerbs = new HashSet(); foreach (IVerb producer in this.producers) { upstreamVerbs.UnionWith(producer.getVerbs()); upstreamVerbs.Add(producer); } return upstreamVerbs; } public override IEnumerable getOutputs() { return new HashSet() { this.outputObject }; } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { // Coallesce the VerificationObligationLists from each producer into a single result set IEnumerable master = new HashSet(); foreach (IObligationsProducer producer in this.producers) { VerificationObligationList vol = VerificationObligationList.fetch(producer.getObligationSet()); master = master.Union(vol.getVerificationObligations()); } VerificationObligationList myVOL = new VerificationObligationList(master); myVOL.store(workingDirectory, this.outputObject); return new VerbSyncWorker(workingDirectory, new Fresh()); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/BeatExtensions.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; public enum ModPart { Ifc, Imp, Unknown } public static class ModPartExtensions { public const string ModPartIfc = ".ifc"; public const string ModPartImp = ".imp"; public const string ModPartUnknown = ".unk"; public static string ExtnStr(this ModPart modPart) { switch (modPart) { case ModPart.Ifc: return ModPartIfc; case ModPart.Imp: return ModPartImp; case ModPart.Unknown: return ModPartUnknown; default: return null; } } } internal class BeatExtensions { public const string BEAT_EXTN = ".beat"; public const string BEATIFC_EXTN = ".ifc.beat"; public const string BEATIMP_EXTN = ".imp.beat"; public static ModPart whichPart(string filenameOrExtn) { string modPartStr = "." + filenameOrExtn.Split('.')[1]; switch (modPartStr) { case ModPartExtensions.ModPartIfc: return ModPart.Ifc; case ModPartExtensions.ModPartImp: return ModPart.Imp; default: return ModPart.Unknown; } } public static BuildObject makeOutputObject(BuildObject input, string typeExtn) { return makeLabeledOutputObject(input, null, typeExtn); } internal static BuildObject makeLabeledOutputObject(BuildObject input, string appLabel, string typeExtn) { ModPart part = whichPart(input); if (part == ModPart.Unknown) { // Input must be a raw boogie file. Util.Assert(input.getExtension().EndsWith(BoogieVerb.BPL_EXTN)); return input.makeLabeledOutputObject(appLabel, typeExtn); } else { return input.makeLabeledOutputObject(appLabel, part.ExtnStr() + typeExtn); } } public static ModPart whichPart(BuildObject obj) { return whichPart(obj.getExtension()); } private static IEnumerable getBeatFlavoredShallowIncludesLabeled( IContextGeneratingVerb contextVerb, BuildObject rootObj) { ContextContents context = (ContextContents) BuildEngine.theEngine.Repository.FetchVirtual(contextVerb.getContextOutput()); BeatIncludes includes = new BeatIncludes(context.Context); OrderPreservingSet result = new OrderPreservingSet( includes.getLabeledIncludes(rootObj)); if (BeatExtensions.whichPart(rootObj) == ModPart.Imp) { BuildObject rootIfc = context.Context.search(rootObj.getFileNameWithoutExtension(), ModPart.Ifc); result.Add(new BeatIncludes.LabeledInclude(BeatIncludes.ImportFilter.ForBeatOrBasm, rootIfc)); } return result; } public static IEnumerable getBeatFlavoredShallowIncludes( IContextGeneratingVerb contextVerb, BuildObject rootObj, BeatIncludes.ImportFilter importFilter) { return getBeatFlavoredShallowIncludesLabeled(contextVerb, rootObj) .Where(li => importFilter == BeatIncludes.ImportFilter.ForBasmOnly || li.importFilter == BeatIncludes.ImportFilter.ForBeatOrBasm) .Select(li => li.buildObject); } public static void propagatePrivateImports( WorkingDirectory workingDirectory, IContextGeneratingVerb contextVerb, BuildObject srcobj, BuildObject dstobj) { // Rewrite basm output to propagate any import statements from the beat file. // TODO this step really should be a beat function, not part of the build system. IEnumerable beatImports = getBeatFlavoredShallowIncludesLabeled(contextVerb, srcobj); StringBuilder sb = new StringBuilder(); foreach (BeatIncludes.LabeledInclude li in beatImports) { sb.Append("//-"); sb.Append(li.importFilter == BeatIncludes.ImportFilter.ForBasmOnly ? "private-basmonly-import" : "private-import"); sb.Append(" "); sb.Append(li.buildObject.getFileNameWithoutExtension()); sb.AppendLine(";"); } // REVIEW: Improve upon this round-about way of prepending to a file? string beatOutput = File.ReadAllText(workingDirectory.PathTo(dstobj)); File.Delete(workingDirectory.PathTo(dstobj)); File.WriteAllText(workingDirectory.PathTo(dstobj), sb.ToString() + beatOutput); } // This used to use a BeatTransitiveDepsVerb, but we're going with shallow dependencies at the moment. // We may want to restore that behavior later, if we can get some sane transitive dep tree worked out for // Verve code. // The returned list belongs to the caller to .Add() to as desired. // TODO this really needs to be factored to supply the actual Beat-flavored references separately // from the auxiliary deps (transitive dep objects and context dep objects), so we don't have // client code trying to filter back out the part it wants. Brittle. public static OrderPreservingSet getBeatFlavoredShallowDependencies( IContextGeneratingVerb contextVerb, BuildObject rootObj, out DependencyDisposition ddisp, BeatIncludes.ImportFilter filter) { OrderPreservingSet result = new OrderPreservingSet(); result.Add(contextVerb.getContextOutput()); try { result.AddRange(getBeatFlavoredShallowIncludes(contextVerb, rootObj, filter)); ddisp = DependencyDisposition.Complete; } catch (ObjectNotReadyException) { ddisp = DependencyDisposition.Incomplete; } catch (ObjectFailedException) { ddisp = DependencyDisposition.Failed; } result.Add(rootObj); // root really needs to go at the end of the list. return result; } public static BasmTransitiveDepsVerb getBasmFlavoredTransitiveDepVerb(IContextGeneratingVerb context, BuildObject rootObj) { return new BasmTransitiveDepsVerb(context, rootObj); } // The list belongs to the caller to .Add() to as desired. public static OrderPreservingSet getBasmFlavoredTransitiveDependencies(IContextGeneratingVerb context, BuildObject rootObj, out DependencyDisposition ddisp) { OrderPreservingSet result = new OrderPreservingSet(); TransitiveDepsVerb depsVerb = getBasmFlavoredTransitiveDepVerb(context, rootObj); result.Add(depsVerb.depsObj()); result.AddRange(depsVerb.getAvailableDeps(out ddisp)); // NB add root object at end of list, to keep it in definition-dependency order. result.Add(rootObj); return result; } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/BeatIncludes.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Text.RegularExpressions; internal class BeatIncludes { private static CachedHash fetchModuleCaches = new CachedHash(delegate(IIncludePathContext context) { return new FetchModuleCache(context); }); private IIncludePathContext includePathSearcher; public BeatIncludes(IIncludePathContext includePathSearcher) { this.includePathSearcher = includePathSearcher; } public enum ImportFilter { ForBeatOrBasm, ForBasmOnly } public static List parseLabeledIncludes(IIncludePathContext context, BuildObject beatsrc) { ////Logger.WriteLine("parseLabeledIncludes " + beatsrc.getRelativePath() + " context " + context.GetHashCode()); List outlist = new List(); ////Regex re = new Regex("^\\s*import\\s*([^\\s,]*(,\\s*[^\\s,]*)*)\\s*;"); // TODO allow commented-out imports until Beat accepts (ignores) them in ifcs files. Regex import_re = new Regex("^[\\s/-]*private-import\\s*([^\\s,]*(,\\s*[^\\s,]*)*)\\s*;"); Regex basmonly_re = new Regex("^[\\s/-]*private-basmonly-import\\s*([^\\s,]*(,\\s*[^\\s,]*)*)\\s*;"); FetchModuleCache fmcache = fetchModuleCaches.get(context); using (TextReader tr = BuildEngine.theEngine.Repository.OpenRead(beatsrc)) { while (true) { string line = tr.ReadLine(); if (line == null) { break; } Match match = import_re.Match(line); if (match.Success) { outlist.Add(new LabeledInclude(ImportFilter.ForBeatOrBasm, fmcache.get(match.Groups[1].ToString()))); } match = basmonly_re.Match(line); if (match.Success) { outlist.Add(new LabeledInclude(ImportFilter.ForBasmOnly, fmcache.get(match.Groups[1].ToString()))); } } ////Logger.WriteLine(string.Format("{0} includes {1} things", dfysource.getFilesystemPath(), outlist.Count)); return outlist; } } public List getLabeledIncludes(BuildObject beatsrc) { ////return caches.get(includePathSearcher).get(beatsrc); return this.computeLabeledIncludes(beatsrc); } public IEnumerable getBasmIncludes(BuildObject beatsrc) { return this.computeLabeledIncludes(beatsrc).Select(li => li.buildObject); } protected List computeLabeledIncludes(BuildObject beatsrc) { return BuildEngine.theEngine.getHasher().getParsedIncludes(this.includePathSearcher, beatsrc); } private BuildObject fetchModule(string module) { ////Logger.WriteLine("fetchmodule " + module + " ctx " + includePathSearcher.GetHashCode()); string includedModule = module.Trim(); BuildObject path = this.includePathSearcher.search(includedModule); if (path == null) { throw new SourceConfigurationError( string.Format( "Cannot find module {0} in search path {1}", includedModule, this.includePathSearcher)); } return path; } public class LabeledInclude { public ImportFilter importFilter; public BuildObject buildObject; public LabeledInclude(ImportFilter importFilter, BuildObject buildObject) { this.importFilter = importFilter; this.buildObject = buildObject; } } private class FetchModuleCache { private CachedHash cache; private BeatIncludes beatIncludes; public FetchModuleCache(IIncludePathContext context) { this.beatIncludes = new BeatIncludes(context); this.cache = new CachedHash(this.fetchModule); } public BuildObject get(string module) { return this.cache.get(module); } private BuildObject fetchModule(string module) { return this.beatIncludes.fetchModule(module); } } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/BeatVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; internal class BeatVerb : Verb, IProcessInvokeAsyncVerb { private const int version = 34; private static NmakeVerb beatBuildExecutableVerb = new NmakeVerb(new SourcePath("tools\\Beat\\makefile", SourcePath.SourceType.Tools)); private IContextGeneratingVerb contextVerb; private BuildObject beatobj; private string appLabel; private AbstractId abstractId; public BeatVerb(IContextGeneratingVerb contextVerb, BuildObject beatobj, string appLabel) { this.contextVerb = contextVerb; this.beatobj = beatobj; this.appLabel = appLabel; this.abstractId = new AbstractId(this.GetType().Name, version, beatobj.ToString(), contextVerb.getPoundDefines(), concrete: appLabel); } public static bool isBeat(BuildObject obj) { return obj.getExtension().Equals(BeatExtensions.BEATIFC_EXTN) || obj.getExtension().Equals(BeatExtensions.BEATIMP_EXTN); } public override IEnumerable getDependencies(out DependencyDisposition ddisp) { OrderPreservingSet deps = BeatExtensions.getBeatFlavoredShallowDependencies( this.contextVerb, this.beatobj, out ddisp, BeatIncludes.ImportFilter.ForBeatOrBasm); deps.Add(this.getBeatExecutable()); return deps; } public override IEnumerable getVerbs() { return new IVerb[] { this.contextVerb, beatBuildExecutableVerb }; } public override IEnumerable getOutputs() { return new BuildObject[] { this.outputFile() }; } public override AbstractId getAbstractIdentifier() { return this.abstractId; } public BuildObject getBeatExecutable() { // Whaaat? Why doesn't beatBuildExecutableVerb.getOutputPath() already end with beat.exe!? Weirdly, // nope, its getOutputPath() is a directory. return new BuildObject(Path.Combine(beatBuildExecutableVerb.getOutputPath().getRelativePath(), "beat.exe")); } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { // "beat $BUILD_DEFS -out $out.tmp -in $in $incls" List args = new List(); args.Add("-in"); args.Add(this.beatobj.getRelativePath()); IEnumerable beatImports = BeatExtensions.getBeatFlavoredShallowIncludes(this.contextVerb, this.beatobj, BeatIncludes.ImportFilter.ForBeatOrBasm); foreach (BuildObject ifcObj in beatImports.Where(obj => !obj.Equals(this.beatobj))) { Util.Assert(!ifcObj.getRelativePath().Contains(".imp")); // Erk, don't feed imp files as includes! args.Add("-i"); args.Add(ifcObj.getRelativePath()); } args.AddRange(this.contextVerb.getPoundDefines().ToDefArgs()); string dbgText = string.Format( "rem verb {0}{1}", this, System.Environment.NewLine); return new ProcessInvokeAsyncWorker( workingDirectory, this, this.getBeatExecutable().getRelativePath(), args.ToArray(), ProcessExitCodeHandling.NonzeroIsFailure, captureStdout: this.outputFile(), failureBase: getDiagnosticsBase(), dbgText: dbgText); } public Disposition Complete(WorkingDirectory workingDirectory, double cpuTimeSeconds, string stdout, string stderr, Disposition disposition) { if (disposition is Fresh) { BeatExtensions.propagatePrivateImports(workingDirectory, this.contextVerb, this.beatobj, this.outputFile()); // And then propagate the NuBuild annotations, too. AnnotationScanner.transferAnnotations( workingDirectory, this.beatobj, this.outputFile(), BoogieAsmDepBase.CommentSymbol); } return disposition; } private BuildObject outputFile() { string outputAppLabel = (this.appLabel == null ? string.Empty : this.appLabel) + this.contextVerb.getPoundDefines().ToString(); string extn = this.beatobj.getExtension().Equals(BeatExtensions.BEATIFC_EXTN) ? BoogieAsmVerifyVerb.BASMIFC_EXTN : BoogieAsmVerifyVerb.BASMIMP_EXTN; return this.beatobj.makeLabeledOutputObject(outputAppLabel, extn); } private string getModuleNameForObj(BuildObject obj) { return obj.getFileNameWithoutExtension(); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/BoogieAsmDepBase.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; internal abstract class BoogieAsmDepBase : Verb { public const string BASM_EXTN = ".basm"; public const string BASMIFC_EXTN = ".ifc.basm"; public const string BASMIMP_EXTN = ".imp.basm"; public const string CommentSymbol = "//"; protected static NmakeVerb boogieAsmBuildExecutableVerb = new NmakeVerb(new SourcePath("tools\\BoogieAsm\\makefile", SourcePath.SourceType.Tools)); protected IContextGeneratingVerb context; protected BuildObject basmInput; protected BuildObject upstreamObj; private const int version = 20; private AbstractId abstractId = null; public BoogieAsmDepBase(IContextGeneratingVerb context, BuildObject input) { this.context = context; this.upstreamObj = input; this.basmInput = computeBasmInput(context.getPoundDefines(), input); } public static bool isBasm(BuildObject obj) { return obj.getExtension().Equals(BASMIFC_EXTN) || obj.getExtension().Equals(BASMIMP_EXTN); } public abstract BuildObject outputFile(); protected abstract int getVersion(); protected abstract bool includeAllImps(); protected virtual string getExtraAbstractID() { return string.Empty; } protected static BuildObject getBoogieasmExecutable() { return new BuildObject(Path.Combine(boogieAsmBuildExecutableVerb.getOutputPath().getRelativePath(), "boogieasm.exe")); } protected virtual IEnumerable getExtraDeps(out DependencyDisposition ddisp) { ddisp = DependencyDisposition.Complete; return new BuildObject[] { }; } public static BuildObject computeBasmInput(PoundDefines poundDefines, BuildObject upstreamObj) { if (BoogieAsmDepBase.isBasm(upstreamObj)) { // We'll be reading upstreamObj directly. Don't makeOutputObject, // because it may well be a source file. return upstreamObj; } return BeatExtensions.makeLabeledOutputObject(upstreamObj, poundDefines.ToString(), BASM_EXTN); } public override IEnumerable getOutputs() { return new BuildObject[] { outputFile() }; } public override AbstractId getAbstractIdentifier() { if (this.abstractId == null) { this.abstractId = new AbstractId(this.GetType().Name, getVersion() + version, this.upstreamObj.ToString(), context.getPoundDefines(), getExtraAbstractID()); } return abstractId; } internal class BasmModuleAccumulator { private IContextGeneratingVerb _contextGenVerb; private HashSet _mutableVerbSet; private OrderPreservingSet _basmModules; // these are the bits we want to pass in as Execute() arguments private HashSet _auxiliaryDeps; // these plus modules are the deps we need to wait on. We need these to get the right .tdeps. private IIncludePathContext context; private DependencyDisposition _ddisp; public IEnumerable verbs { get { return _mutableVerbSet; } } public IEnumerable basmModules { get { return _basmModules; } } public IEnumerable getDeps() { return _auxiliaryDeps.Concat(_basmModules); } public DependencyDisposition ddisp { get { return _ddisp; } } public BasmModuleAccumulator(IContextGeneratingVerb contextGenVerb, BuildObject upstreamObj, bool linkMode) { this._contextGenVerb = contextGenVerb; this._mutableVerbSet = new HashSet(); // NB preserve module definition-dependency order. this._basmModules = new OrderPreservingSet(); this._auxiliaryDeps = new HashSet(); _ddisp = DependencyDisposition.Complete; ////try ////{ _mutableVerbSet.Add(contextGenVerb); _auxiliaryDeps.UnionWith(contextGenVerb.getOutputs()); context = contextGenVerb.fetchIfAvailable(ref _ddisp); if (context != null) { OrderPreservingSet deps; if (!linkMode) { deps = BeatExtensions.getBeatFlavoredShallowDependencies( contextGenVerb, upstreamObj, out _ddisp, BeatIncludes.ImportFilter.ForBasmOnly); } else { deps = BeatExtensions.getBasmFlavoredTransitiveDependencies(contextGenVerb, upstreamObj, out _ddisp); _mutableVerbSet.Add(BeatExtensions.getBasmFlavoredTransitiveDepVerb(_contextGenVerb, upstreamObj)); } // REVIEW: The following two variables are unused. Remove? string targetModName = upstreamObj.getFileNameWithoutExtension(); ModPart targetModPart = BeatExtensions.whichPart(upstreamObj); // NB security policy note: When verifying X.imp, we must be sure to supply X.ifc // to BoogieAsm, so that we know that we're actually verifying the promises // that other modules are relying on when they say "X" (which is how X got on // the verification obligation list). That property happens automatically here, // because we make a list of modules (ignoring ifc/imp part), such as {A,B,X}, // and include *every* .ifc. If we're verifying X.imp, a conditional test // includes it at the time we consider module X. foreach (BuildObject dep in deps) { string depExtn = dep.getExtension(); if (depExtn == null || depExtn.EndsWith(TransitiveDepsVerb.TDEP_EXTN) || depExtn.EndsWith(ContextGeneratingVerb.CONTEXT_EXTN)) { _auxiliaryDeps.Add(dep); } else { Util.Assert(depExtn.Equals(BeatExtensions.BEATIFC_EXTN) || depExtn.Equals(BeatExtensions.BEATIMP_EXTN) || depExtn.Equals(BASMIFC_EXTN) || depExtn.Equals(BASMIMP_EXTN)); // Burned too many times by this silly filter-out strategy. string modName = dep.getFileNameWithoutExtension(); ModPart modPart = BeatExtensions.whichPart(dep); getBasmModule(modName, ModPart.Ifc); if ((dep.Equals(upstreamObj) && modPart == ModPart.Imp) || linkMode) { getBasmModule(modName, ModPart.Imp); } } } } ////} ////catch (ObjNotReadyException) ////{ //// // oh, we don't even have the context object yet. //// _ddisp = DependencyDisposition.Incomplete; ////} ////catch (ObjFailedException) ////{ //// _ddisp = DependencyDisposition.Failed; ////} } private BuildObject maybeBeat(BuildObject obj, HashSet mutableVerbSet) { BuildObject result = obj; if (BeatVerb.isBeat(obj)) { BeatVerb beatVerb = new BeatVerb(_contextGenVerb, obj, appLabel: null); IEnumerable beatOuts = beatVerb.getOutputs(); Util.Assert(beatOuts.Count() == 1); mutableVerbSet.Add(beatVerb); result = beatVerb.getOutputs().First(); } else { // No, this thing should already be ready to consume. ////mutableVerbSet.Add(new BoogieAsmVerifyVerb(context, obj)); } Util.Assert(BoogieAsmVerifyVerb.isBasm(result)); return result; } private void getBasmModule(string modName, ModPart modPart) { ////Logger.WriteLine(string.Format("context {0} modName {1} modPart {2}", context, modName, modPart)); ////BuildObject ifcObj = context.search(modName, modPart); BuildObject ifcObj = BuildEngine.theEngine.getHasher().search(context, modName, modPart); if (ifcObj == null) { Util.Assert(false); // I'm not sure this case even occur anymore, since we guard the foreach on incomplete deps. _ddisp = _ddisp.combine(DependencyDisposition.Incomplete); } else { ifcObj = maybeBeat(ifcObj, _mutableVerbSet); _basmModules.Add(ifcObj); } } } protected IEnumerable getBoogieVerbs(VerificationRequest verificationRequest) { if (verificationRequest.verifyMode == VerificationRequest.VerifyMode.NoVerify) { return new BoogieVerb[] { }; } BoogieAsmDepBase.BasmModuleAccumulator acc = new BoogieAsmDepBase.BasmModuleAccumulator(context, upstreamObj, includeAllImps()); List basmModules = new List(acc.basmModules.Where(mod => !mod.IsTrusted)); OrderPreservingSet normal_Boogie = new OrderPreservingSet(); OrderPreservingSet SymDiff_Boogie = new OrderPreservingSet(); foreach (BuildObject basmModule in basmModules) { if (verificationRequest.verifyMode == VerificationRequest.VerifyMode.SelectiveVerify && !verificationRequest.selectiveVerifyModuleNames.Contains(basmModule.getFileNameWithoutExtension())) { continue; } normal_Boogie.Add(new BoogieVerb(context, basmModule, symdiff: VerificationRequest.SymDiffMode.NoSymDiff)); if (verificationRequest.getSymDiffMode() == VerificationRequest.SymDiffMode.UseSymDiff && BoogieAsmVerifyVerb.needs_symdiff(basmModule)) { SymDiff_Boogie.Add(new BoogieVerb(context, basmModule, symdiff: VerificationRequest.SymDiffMode.UseSymDiff)); } } return SymDiff_Boogie.Union(normal_Boogie); } protected IEnumerable getVerifyishVerbs() { // All the available things that make Beat or Basm ... BasmModuleAccumulator acc = new BasmModuleAccumulator(context, upstreamObj, includeAllImps()); // Plus the transitive deps. IEnumerable extraDeps = new IVerb[] { context, boogieAsmBuildExecutableVerb }; return acc.verbs.Concat(extraDeps).Concat(context.getVerbs()); } public override IEnumerable getDependencies(out DependencyDisposition ddisp) { BasmModuleAccumulator acc = new BasmModuleAccumulator(context, upstreamObj, includeAllImps()); IEnumerable result = acc.getDeps(); DependencyDisposition ddisp_extra; IEnumerable result_extra = getExtraDeps(out ddisp_extra); ddisp = acc.ddisp.combine(ddisp_extra); return result.Concat(result_extra).Concat(new[] { getBoogieasmExecutable() }); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/BoogieAsmLinkVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; internal class BoogieAsmLinkVerb : BoogieAsmWorkerBase, IAsmProducer { public BoogieAsmLinkVerb(IContextGeneratingVerb context, BuildObject input) : base(context, input) { } public BuildObject getAsmFile() { return basmInput.makeOutputObject(MasmVerb.MASM_EXTN); } public override BuildObject outputFile() { return this.getAsmFile(); } public override IEnumerable getVerbs() { return getVerifyishVerbs(); } protected override int getVersion() { return 23; } protected override string getAction() { return "-link"; } protected override bool outFlagWorks() { return false; } protected override bool includeAllImps() { return true; } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/BoogieAsmVerificationObligationListVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Linq; // NB we generate the obligation list in a seperate verb from the actual BoogieAsm -link step // because the latter is quite slow, and the former frees up a bunch of downstream // parallelism. internal class BoogieAsmVerificationObligationListVerb : BoogieAsmDepBase, IObligationsProducer { private BuildObject obligations; private VerificationRequest verificationRequest; public BoogieAsmVerificationObligationListVerb(IContextGeneratingVerb context, BuildObject input, VerificationRequest verificationRequest) : base(context, input) { this.verificationRequest = verificationRequest; obligations = input.makeOutputObject(BASM_EXTN + VerificationObligationList.VOL_EXTN); } public BuildObject getObligationSet() { return obligations; } public override BuildObject outputFile() { return obligations; } public override IEnumerable getVerbs() { IEnumerable result = getVerifyishVerbs(); IEnumerable boogieVerbs = new List(); try { boogieVerbs = getBoogieVerbs(verificationRequest); ////Logger.Out.WriteLine("Successfully retrieved the Boogie verbs."); } catch (ObjectNotReadyException) { ////Logger.Out.WriteLine("Caught an exception: " + e); } return result.Concat(boogieVerbs); } public IEnumerable getObligationSatisfyingVerbs() { return getBoogieVerbs(verificationRequest); } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { IEnumerable verificationResults = getBoogieVerbs(verificationRequest) .Select(boogie_verb => boogie_verb.getOutputFile()); VerificationObligationList vol = new VerificationObligationList(verificationResults); vol.store(workingDirectory, this.obligations); return new VerbSyncWorker(workingDirectory, new Fresh()); } protected override int getVersion() { return 5; } protected override bool includeAllImps() { return true; } protected override string getExtraAbstractID() { return verificationRequest.ToString(); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/BoogieAsmVerifyVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; internal class BoogieAsmVerifyVerb : BoogieAsmWorkerBase { public const string MUTUAL_SUMMARY_EXTN = ".ms"; public const string SYMDIFF_EXTN = ".symdiff"; public const string SYMDIFF_DIR_EXTN = ".dir"; private const string AddBoogieAxiomAnnotation = "AddBoogieAxiom"; private const string BasmEnableSymdiffAnnotation = "BasmEnableSymdiff"; private bool buildSymDiffMutualSummary; private bool enableSymdiff = false; private string dirName; public BoogieAsmVerifyVerb(IContextGeneratingVerb context, BuildObject input, bool buildSymDiffMutualSummary) : base(context, input) { this.buildSymDiffMutualSummary = buildSymDiffMutualSummary; this.enableSymdiff = BoogieAsmVerifyVerb.needs_symdiff(basmInput); } public static bool needs_symdiff(BuildObject basm) { AnnotationScanner annotations = new AnnotationScanner(basm); bool symdiff = false; foreach (string[] ann in annotations.getAnnotations(BasmEnableSymdiffAnnotation)) { if (ann.Length != 2 || !ann[1].Equals("true")) { throw new SourceConfigurationError("Expected " + BasmEnableSymdiffAnnotation + " to have argument 'true'."); } symdiff = true; } return symdiff; } public override BuildObject outputFile() { if (buildSymDiffMutualSummary) { // SymDiff files need to go into their own directory BuildObject normalName = BeatExtensions.makeOutputObject(basmInput, SYMDIFF_EXTN); dirName = normalName.getFileName() + SYMDIFF_DIR_EXTN; BuildObject dirExtendedName = new BuildObject(Path.Combine(normalName.getDirPath(), dirName, normalName.getFileName())); return dirExtendedName; } else { return BeatExtensions.makeOutputObject(basmInput, BoogieVerb.BPL_EXTN); } } public override IEnumerable getVerbs() { // Hey BJP: why do we have BoogieAsmLink here offering boogie verbs? I guess because it's safe and hint-y? return getVerifyishVerbs(); } public BuildObject getMutualSummary() { // SymDiff files need to go into their own directory. BuildObject normalName = BeatExtensions.makeOutputObject(basmInput, MUTUAL_SUMMARY_EXTN); BuildObject dirExtendedName = new BuildObject(Path.Combine(normalName.getDirPath(), dirName, normalName.getFileName())); return dirExtendedName; } public override IEnumerable getOutputs() { List outputs = new List { outputFile() }; if (buildSymDiffMutualSummary) { outputs.Add(getMutualSummary()); } return outputs; } protected override IEnumerable getExtraDeps(out DependencyDisposition ddisp) { try { ddisp = DependencyDisposition.Complete; return getTrustedBoogieAxioms(); } catch (ObjectNotReadyException) { // All the basms aren't here yet, so we can't scan them. Don't sweat it; // those deps are already being called for. ddisp = DependencyDisposition.Incomplete; return new BuildObject[] { }; } catch (ObjectFailedException) { ddisp = DependencyDisposition.Failed; return new BuildObject[] { }; } } protected override void extendArgs(List args) { if (!buildSymDiffMutualSummary && enableSymdiff) { args.Add("-symdiffok"); } else if (buildSymDiffMutualSummary) { args.Add("-symdiffms"); args.Add(getMutualSummary().getRelativePath()); } ////foreach (SourcePath includedAxiom in getTrustedBoogieAxioms(acc.basmModules)) foreach (SourcePath includedAxiom in getTrustedBoogieAxioms()) { if (!includedAxiom.IsTrusted) { throw new SourceConfigurationError(AddBoogieAxiomAnnotation + " annotation points at untrusted file " + includedAxiom.ToString()); } // SECURITY POLICY: you can only include trusted things labeled "_axioms.bpl". if (!includedAxiom.getExtension().Equals(BoogieVerb.BPL_EXTN) || !includedAxiom.getFileNameWithoutExtension().EndsWith("_axioms")) { throw new SourceConfigurationError(AddBoogieAxiomAnnotation + " annotation points at file that isn't a Boogie axioms file: " + includedAxiom.ToString()); } args.Add("/trustedBoogie:" + includedAxiom.getRelativePath()); } } protected override void postprocess(WorkingDirectory workingDirectory) { AnnotationScanner.transferAnnotations(workingDirectory, basmInput, outputFile(), BoogieVerb.CommentSymbol); } protected override int getVersion() { return 20; } protected override string getAction() { return "-verify"; } protected override bool outFlagWorks() { return true; } protected override bool includeAllImps() { return false; } protected override string getExtraAbstractID() { return buildSymDiffMutualSummary ? ", relational" : ", functional"; } private IEnumerable getTrustedBoogieAxioms() { OrderPreservingSet result = new OrderPreservingSet(); AnnotationScanner anns = new AnnotationScanner(basmInput); foreach (string[] annotation in anns.getAnnotations(AddBoogieAxiomAnnotation)) { string module = annotation[1]; SourcePath trustedPath = new SourcePath(Path.Combine( BuildEngine.theEngine.getSrcRoot(), BuildEngine.VerveTrustedSpecDir, module + BoogieVerb.BPL_EXTN)); result.Add(trustedPath); } return result; } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/BoogieAsmWorkerBase.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; internal abstract class BoogieAsmWorkerBase : BoogieAsmDepBase, IProcessInvokeAsyncVerb { public BoogieAsmWorkerBase(IContextGeneratingVerb context, BuildObject input) : base(context, input) { } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { List args = new List(); //// args.add(BUILD_DEFS //// args.add(boogieasm_flags) args.Add(getAction()); BuildObject captureStdout = null; if (outFlagWorks()) { args.Add("-out"); args.Add(outputFile().getRelativePath()); } else { captureStdout = outputFile(); } BasmModuleAccumulator acc = new BasmModuleAccumulator(context, upstreamObj, includeAllImps()); Util.Assert(acc.ddisp == DependencyDisposition.Complete); args.AddRange(acc.basmModules.Select(module => module.getRelativePath())); args.AddRange(context.getPoundDefines().ToDefArgs()); extendArgs(args); return new ProcessInvokeAsyncWorker( workingDirectory, this, getBoogieasmExecutable().getRelativePath(), args.ToArray(), ProcessExitCodeHandling.NonzeroIsFailure, getDiagnosticsBase(), captureStdout: captureStdout); } public Disposition Complete(WorkingDirectory workingDirectory, double cpuTimeSeconds, string stdout, string stderr, Disposition disposition) { postprocess(workingDirectory); return disposition; } protected abstract string getAction(); protected abstract bool outFlagWorks(); // Weird that it works for -verify but not -link! protected virtual void extendArgs(List args) { } protected virtual void postprocess(WorkingDirectory workingDirectory) { } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/BoogieVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; using System.Linq; internal class BoogieVerb : VerificationResultVerb, IProcessInvokeAsyncVerb { public const string BPL_EXTN = ".bpl"; public const string CommentSymbol = "//-"; private const int version = 17; private const string AddBoogieFlagAnnotation = "AddBoogieFlag"; // SECURITY POLICY: we only allow checked files to specify the flags below. // Otherwise, one might thing it reasonable to specify "/noVerify:1" or something. private static readonly string[] validFlagsAnyValue = { "/restartProver", "/timeLimit", "/trace" }; private static readonly string[] validFlagsSpecificValues = { "/proverOpt:OPTIMIZE_FOR_BV=true", "/z3opt:NL_ARITH=false" }; private static SourcePath boogieExecutable; private BuildObject bplInput; private AbstractId abstractId; private IEnumerable upstreamVerbs; private int timeLimit = 3600; public BoogieVerb(IContextGeneratingVerb context, BuildObject bplInput, VerificationRequest.SymDiffMode symdiff) { if (bplInput.getExtension().Equals(BPL_EXTN)) { this.bplInput = bplInput; upstreamVerbs = new List(); // TODO this will probably break, since we don't know where this bplInput came from. Maybe that's okay, since the verb had to already exist to reach this point. } else if (symdiff == VerificationRequest.SymDiffMode.NoSymDiff) { IVerb boogieAsmVerb = new BoogieAsmVerifyVerb(context, bplInput, false); this.bplInput = boogieAsmVerb.getOutputs().First(); upstreamVerbs = new IVerb[] { boogieAsmVerb }; } else { IVerb workerVerb; SymDiffEngine.BuildPipeline(context, bplInput, out this.bplInput, out workerVerb); upstreamVerbs = new IVerb[] { workerVerb }; } this.abstractId = new AbstractId( this.GetType().Name, version, bplInput.ToString(), concrete: symdiff.ToString()); } public override IEnumerable getDependencies(out DependencyDisposition ddisp) { ddisp = DependencyDisposition.Complete; List result = new List() { bplInput }; result.Add(getBoogieExecutable()); result.AddRange(getBoogieExecutableDependencies()); return result; } public override IEnumerable getVerbs() { return upstreamVerbs; } public override BuildObject getOutputFile() { return BeatExtensions.makeOutputObject(bplInput, BPL_EXTN + VerificationResultVerb.VERIFICATION_RESULT_EXTN); } public override IEnumerable getOutputs() { return new BuildObject[] { getOutputFile() }; } public override AbstractId getAbstractIdentifier() { return abstractId; } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { if (false) { #pragma warning disable 162 File.WriteAllText(workingDirectory.PathTo(getOutputFile()), "Verification disabled temporarily for debugging"); return new VerbSyncWorker(workingDirectory, new Fresh()); #pragma warning restore 162 } List args = new List(); args.Add("/noinfer"); args.Add("/typeEncoding:m"); args.Add("/z3opt:ARITH_RANDOM_SEED=1"); args.Add("/timeLimit:" + timeLimit); args.AddRange(getFlags()); args.Add(bplInput.getRelativePath()); return new ProcessInvokeAsyncWorker( workingDirectory, this, getBoogieExecutable().getRelativePath(), args.ToArray(), ProcessExitCodeHandling.NonzeroIsOkay, getDiagnosticsBase(), allowCloudExecution: true, returnStandardOut: true, returnStandardError: true); } public Disposition Complete(WorkingDirectory workingDirectory, double cpuTimeSeconds, string stdout, string stderr, Disposition disposition) { VerificationResult vr = new VerificationResult( bplInput.getRelativePath(), cpuTimeSeconds, stdout, stderr, new VerificationResultBoogieParser()); vr.addBasicPresentation(); vr.toXmlFile(workingDirectory.PathTo(getOutputFile())); setWasRejectableFailure(vr.wasOnlyTimeouts()); return disposition; } protected override BuildObject getSource() { return bplInput; } private static SourcePath getBoogieExecutable() { // TODO this should eventually be a BuildObject from *building* the executable. if (BoogieVerb.boogieExecutable == null) { BoogieVerb.boogieExecutable = new SourcePath("tools\\Dafny\\Boogie.exe", SourcePath.SourceType.Tools); } return BoogieVerb.boogieExecutable; } private static IEnumerable getBoogieExecutableDependencies() { List exeDepends = new List(); exeDepends.Add(new SourcePath("tools\\Dafny\\AbsInt.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\BaseTypes.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\CodeContractsExtender.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\Concurrency.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\Core.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\Doomed.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\ExecutionEngine.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\Graph.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\Model.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\msvcp100.dll", SourcePath.SourceType.Tools)); // Needed by z3. exeDepends.Add(new SourcePath("tools\\Dafny\\msvcr100.dll", SourcePath.SourceType.Tools)); // Needed by z3. exeDepends.Add(new SourcePath("tools\\Dafny\\ParserHelper.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\Predication.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\Provers.SMTLib.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\VCExpr.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\VCGeneration.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\vcomp100.dll", SourcePath.SourceType.Tools)); // Needed by z3. exeDepends.Add(new SourcePath("tools\\Dafny\\z3.exe", SourcePath.SourceType.Tools)); return exeDepends; } private IEnumerable getFlags() { List flags = new List(); foreach (string[] ann in new AnnotationScanner(bplInput).getAnnotations(AddBoogieFlagAnnotation)) { if (ann.Count() != 2) { throw new SourceConfigurationError(bplInput + " has malformed annotation: " + string.Join(" ", ann)); } string flag = ann[1]; string[] flagParts = flag.Split(new char[] { ':' }, 2); if (validFlagsAnyValue.Contains(flagParts[0])) { flags.Add(flag); } else if (validFlagsSpecificValues.Contains(flag)) { flags.Add(flag); } else { throw new SourceConfigurationError(bplInput + " contains disallowed flag " + flag); } if (flagParts[0].Equals("/timeLimit")) { Util.Assert(flagParts.Count() == 2); timeLimit = Int32.Parse(flagParts[1]); } } return flags; } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/BootableAppVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; // Needs to: // 1) Build the bootloader into pxeloader // 2) Build two IroncladApps: Loader and specified app // Do this via a Batch // 3) Create a boot.ini internal class BootableAppVerb : Verb { ////public const string BOOT_EXTN = ".ini"; public const string LOADER_DFY = "src\\Dafny\\Apps\\AppLoader\\Main.i.dfy"; private const int version = 4; private SourcePath dfyroot; // REVIEW: Never used? private AbstractId abstractId; private VerificationRequest verificationRequest; // Dependencies private BuildObject bootloader = new SourcePath("obj\\Checked\\BootLoader\\pxe-loader", SourcePath.SourceType.PrebakedObjExpediency); // Outputs private BuildObject bootIniFile; private BuildObject loaderCopy; private BuildObject bootloaderCopy; private BuildObject appExecutableCopy; // Intermediate verbs private IroncladAppVerb loaderVerb; private IroncladAppVerb appVerb; private BatchVerifyVerb batchVerb; private VerificationResultSummaryVerb batchSummaryVerb; public BootableAppVerb(SourcePath dfyroot, DafnyCCVerb.FramePointerMode useFramePointer, VerificationRequest verificationRequest) { this.dfyroot = dfyroot; this.verificationRequest = verificationRequest; string concreteId = verificationRequest.ToString() + "," + useFramePointer.ToString(); this.abstractId = new AbstractId(this.GetType().Name, version, dfyroot.ToString(), concrete: concreteId); string targetDirectory = Path.Combine( BuildEngine.theEngine.getObjRoot(), dfyroot.getDirPath(), "bootable-" + verificationRequest.ToString()); this.bootIniFile = new BuildObject(Path.Combine(targetDirectory, "safeos\\boot.ini")); // TODO: Create the bootloader verb. this.loaderVerb = new IroncladAppVerb(new SourcePath(LOADER_DFY), IroncladAppVerb.TARGET.BARE_METAL, useFramePointer, verificationRequest); this.appVerb = new IroncladAppVerb(dfyroot, IroncladAppVerb.TARGET.BARE_METAL, useFramePointer, verificationRequest); this.batchVerb = new BatchVerifyVerb(dfyroot, new HashSet() { this.appVerb, this.loaderVerb }, BatchVerifyVerb.BatchMode.APP); this.batchSummaryVerb = new VerificationResultSummaryVerb(this.batchVerb); this.loaderCopy = new BuildObject(Path.Combine(targetDirectory, this.targetExecutableName(this.loaderVerb))); this.bootloaderCopy = new BuildObject(Path.Combine(targetDirectory, this.bootloader.getFileName())); this.appExecutableCopy = new BuildObject(Path.Combine(targetDirectory, this.targetExecutableName(this.appVerb))); } public override IEnumerable getDependencies(out DependencyDisposition ddisp) { List result = new List(); result.Add(this.bootloader); // TODO: Replace with the bootloader verbs's output. result.Add(this.loaderVerb.getExe()); result.Add(this.appVerb.getExe()); result.AddRange(this.batchSummaryVerb.getOutputs()); ddisp = DependencyDisposition.Complete; return result; } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { if (this.verificationRequest.isComplete()) { VerificationResult vr = VerificationResult.fromXmlFile(this.batchSummaryVerb.getOutputFile()); if (!vr.pass) { Util.Assert(false); // Should never get here, since Ironclad app should fail before producing a verified exe. return new VerbSyncWorker(workingDirectory, new Failed()); } } // Copy the AppLoader binary and the bootloader into the same directory as the app's binary, so the pxe-loader can find them. // REVIEW: Not clear this is doing the right thing with shift to WorkingDirectory. File.Copy(workingDirectory.PathTo(this.loaderVerb.getExe()), workingDirectory.PathTo(this.loaderCopy), true); File.Copy(workingDirectory.PathTo(this.appVerb.getExe()), workingDirectory.PathTo(this.appExecutableCopy), true); File.Copy(workingDirectory.PathTo(this.bootloader), workingDirectory.PathTo(this.bootloaderCopy), true); this.writeBootFile(workingDirectory); return new VerbSyncWorker(workingDirectory, new Fresh()); } public override IEnumerable getVerbs() { List result = new List(); ////result.Add(bootloaderVerb); // TODO when we're building the bootloader as part of NuBuild. result.Add(this.batchSummaryVerb); result.Add(this.appVerb); result.Add(this.loaderVerb); return result; } public override IEnumerable getOutputs() { return new BuildObject[] { this.bootIniFile, this.loaderCopy, this.bootloaderCopy, this.appExecutableCopy }; } public override AbstractId getAbstractIdentifier() { return this.abstractId; } public override Presentation getPresentation() { return this.batchSummaryVerb.getPresentation(); } private string targetExecutableName(IroncladAppVerb fromVerb) { // It's okay that we're saving an unverified binary to a .exe extension, because it's // getting placed inside targetDirectory, which is labeled "bootable-unverified." return fromVerb.getAppLabel() + IroncladAppVerb.TRUSTED_EXE_EXTN; } // TODO: Rename obj to something meaningful. Is it a boot file? private string mkBootFileEntry(WorkingDirectory workingDirectory, BuildObject obj) { return string.Format("Size={0} Path=/{1}", new FileInfo(workingDirectory.PathTo(obj)).Length, obj.getFileName()); } private void writeBootFile(WorkingDirectory workingDirectory) { List lines = new List(); lines.Add(this.mkBootFileEntry(workingDirectory, this.loaderCopy)); lines.Add(this.mkBootFileEntry(workingDirectory, this.appExecutableCopy)); File.WriteAllLines(workingDirectory.PathTo(this.bootIniFile), lines); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/BuildEngine.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.IO; internal class BuildEngine { public const string VerveTrustedSpecDir = "Trusted\\Spec"; private static BuildEngine _theEngine = new BuildEngine(); private PathNormalizer pathNormalizer; private SourcePathIncludeContext vervePathContext; private string ironRoot; private Hasher hasher; private Repository repository; private CloudExecutionQueue cloudExecutionQueue; private string cloudReportQueueName; private ItemCacheCloud cloudItemCache; private IItemCache itemCache; private string localCacheLocation = "nucache"; public BuildEngine() { this.pathNormalizer = new PathNormalizer(); this.hasher = new Hasher(); } public static BuildEngine theEngine { get { return _theEngine; } } internal Repository Repository { get { return this.repository; } set { this.repository = value; } } internal CloudExecutionQueue CloudExecutionQueue { get { return this.cloudExecutionQueue; } set { this.cloudExecutionQueue = value; } } internal string CloudReportQueueName { get { return this.cloudReportQueueName; } set { this.cloudReportQueueName = value; } } internal ItemCacheCloud CloudCache { get { return this.cloudItemCache; } set { this.cloudItemCache = value; } } internal IItemCache ItemCache { get { return this.itemCache; } set { this.itemCache = value; } } public SourcePathIncludeContext getVervePathContext() { if (this.vervePathContext == null) { Util.Assert(this.ironRoot != null); this.vervePathContext = new SourcePathIncludeContext(); this.vervePathContext.addDirectory(VerveTrustedSpecDir); this.vervePathContext.addDirectory("Checked\\Nucleus\\Base"); this.vervePathContext.addDirectory("Checked\\Nucleus\\GC"); this.vervePathContext.addDirectory("Checked\\Nucleus\\Devices"); this.vervePathContext.addDirectory("Checked\\Nucleus\\Main"); this.vervePathContext.addDstExtension(BeatExtensions.BEATIFC_EXTN); this.vervePathContext.addDstExtension(BeatExtensions.BEATIMP_EXTN); this.vervePathContext.addDstExtension(BoogieAsmVerifyVerb.BASMIFC_EXTN); this.vervePathContext.addDstExtension(BoogieAsmVerifyVerb.BASMIMP_EXTN); } return this.vervePathContext; } public IContextGeneratingVerb getVerveContextVerb(PoundDefines poundDefines) { return new StaticContextVerb(this.getVervePathContext(), "Verve", poundDefines); } ////public TransitiveIncludesCache getDafnyIncludeCache() ////{ //// return dafnyIncludeCache; ////} ////public TransitiveIncludesCache getBeatIncludeCache(IIncludePathContext context) ////{ //// if (!contextToCache.ContainsKey(context)) //// { //// contextToCache[context] = new TransitiveIncludesCache(new BeatIncludes(context)); //// } //// return contextToCache[context]; ////} public string getIronRoot() { return this.ironRoot; } internal void setIronRoot(string ironRoot) { this.ironRoot = this.pathNormalizer.normalizeAbsolutePath(ironRoot); } // Normalize the case of an ironRoot-relative path to the case present in the filesystem. internal string normalizeIronPath(string ironRelPath) { string abspath = this.pathNormalizer.normalizeAbsolutePath(Path.GetFullPath(Path.Combine(this.ironRoot, ironRelPath))); Util.Assert(abspath.StartsWith(this.ironRoot)); return abspath.Substring(this.ironRoot.Length); } internal string getObjRoot() { return "nuobj"; } internal string getSrcRoot() { return "src"; } internal string getVirtualRoot() { return this.getObjRoot() + "\\virtual"; // Should never exist in filesystem! } internal string getToolsRoot() { return "tools"; } internal string getBinToolsRoot() { return "bin_tools"; } internal void setLocalCache(string path) { this.localCacheLocation = path; } internal string getLocalCache() { return this.localCacheLocation; } internal IHasher getHasher() { return this.hasher; } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/BuildObject.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Diagnostics; using System.IO; using System.Linq; using System.Xml; /// /// An abstract identifier for "nouns" (i.e. the things that verbs operate /// on -- both verb outputs and dependencies are BuildObjects). /// /// /// Note that sometimes the code and/or comments about the code refer to /// BuildObjects as if they are the concrete thing that they identify as /// opposed to just being the abstract identifier for that thing. This is /// probably okay, as there should be just one concrete instance of any /// particular abstract build object during a given run of the system. /// public class BuildObject { /// /// The XML element name for this object. /// public const string XmlTag = "BuildObject"; /// /// Path to this object as stored in the local filesystem, relative to /// the IronRoot (i.e. begins with "src", "obj", etc.). /// /// /// This string is expected to be normalized to have consistent casing. /// protected string path; /// /// Whether this object is considered "trusted" for verification /// purposes. /// private bool isTrusted; /// /// The filename of this object, without the file extension. /// private string filenameWithoutExtension; /// /// The filename extension for this object. /// private string filenameExtension; /// /// Initializes a new instance of the BuildObject class. /// /// /// Relative path to this object in the local filesystem. /// /// /// Whether this object is considered "trusted" for verification /// purposes. /// public BuildObject(string path, bool isTrusted = false) { // ToDo: Fix VSSolutionVerb and/or IronfleetTestDriver.sln to work in "src" tree without hitting below Assert. Then re-instate below Assert. ////Util.Assert(!path.StartsWith(BuildEngine.theEngine.getSrcRoot(), StringComparison.OrdinalIgnoreCase)); this.path = BuildEngine.theEngine.normalizeIronPath(path); this.isTrusted = isTrusted; } /// /// Initializes a new instance of the BuildObject class. /// /// /// Relative path to this object in the local filesystem. /// protected BuildObject(string path) { this.path = BuildEngine.theEngine.normalizeIronPath(path); } /// /// Gets or sets a value indicating whether this object is considered /// "trusted" for verification purposes. /// /// /// REVIEW: Giving build objects properties like this is dangerous, /// as they are supposed to be just abstract ids. Two equivalent /// (per Equals() below) build objects could be created, and should /// reference the same bag of bits, yet have different properties! /// public bool IsTrusted { get { return this.isTrusted; } protected set { this.isTrusted = value; } } /// /// Gets the relative path for this instance. /// /// /// TODO: Replace this with a property ("RelativePath"?) that is /// public get and protected set. And change this.path from /// protected to private. /// /// The relative path for this instance. public string getRelativePath() { return this.path; } /// /// Returns a string that represents this instance. /// /// A string that represents this instance. public override string ToString() { return this.path; } /// /// Gets the directory information for this instance. /// /// The directory information for this instance. public string getDirPath() { return Path.GetDirectoryName(this.path); } /// /// Gets the file name and extension for this instance. /// /// The file name and extension for this instance. public string getFileName() { return Path.GetFileName(this.path); } /// /// Gets the file name (sans extension) for this instance. /// /// The file name (sans extension) for this instance. public string getFileNameWithoutExtension() { this.splitExtension(); return this.filenameWithoutExtension; } /// /// Gets the file extension for this instance. /// /// The file extension for this instance. public string getExtension() { this.splitExtension(); return this.filenameExtension; } /// /// Determines whether this instance and another specified BuildObject /// object have the same value (identity?). Really, the same path. /// /// The object to compare to this instance. /// /// True if the given object is equivalent to this instance, /// false otherwise. /// public override bool Equals(object obj) { BuildObject other = obj as BuildObject; if (other != null) { return this.path.Equals(other.path, StringComparison.Ordinal); } else { return false; } } /// /// Returns the hash code for this instance. /// /// /// Note that equivalent (as in .Equals returns true) instances /// will have the same hash code. /// /// The hash code for this instance. public override int GetHashCode() { return this.path.GetHashCode(); } /// /// Creates a new instance based on this one, but with the given /// extension, and guaranteed to be in the obj directory. /// /// Extension to give new instance. /// A new instance. public BuildObject makeOutputObject(string extension) { return new BuildObject(this.mashedPathname(BuildEngine.theEngine.getObjRoot(), extension)); } /// /// Creates a new instance based on this one, but for the given /// appLabel (REVIEW: what does this mean?), with the given /// extension, and guaranteed to be in the obj directory. /// /// The app label to use. /// Extension to give new instance. /// A new instance. public BuildObject makeLabeledOutputObject(string appLabel, string extension) { string appSpecificPrefix = appLabel == null ? BuildEngine.theEngine.getObjRoot() : Path.Combine(BuildEngine.theEngine.getObjRoot(), appLabel); // REVIEW: Ordinal vs. OrdinalIgnoreCase. if (this.path.StartsWith(appSpecificPrefix, StringComparison.OrdinalIgnoreCase)) { // Input is already in the correct subtree; don't nest subtrees. return this.makeOutputObject(extension); } else { // Input is coming from elsewhere; give it a parallel location under app-specific subtree. return new BuildObject(this.mashedPathname(appSpecificPrefix, extension)); } } /// /// Creates a new VirtualBuildObject based on this instance, but with /// a path modified to be virtual and have the given extension. /// /// /// Filename extension to give the new object. /// /// A new VirtualBuildObject. public BuildObject makeVirtualObject(string extension) { return new VirtualBuildObject(this.mashedPathname(BuildEngine.theEngine.getVirtualRoot(), extension)); } /// /// Helper function to read an XML element (not a full document) /// representing a BuildObject. /// /// /// Note that the XmlReader is expected to be positioned in the XML /// document such that the current node is a BuildObject element. /// /// The XmlReader object to read from. /// /// A new BuildObject corresponding to the XML representation read. /// public static BuildObject ReadXml(XmlReader xr) { Util.Assert(xr.Name.Equals(XmlTag)); string relativePath = xr.ReadElementContentAsString(); return new BuildObject(relativePath); } /// /// Helper function to write an XML element (not a full document) /// representing this BuildObject. /// /// The XmlWriter object to write to. public void WriteXml(XmlWriter xw) { xw.WriteStartElement(XmlTag); xw.WriteString(this.path); xw.WriteEndElement(); } /// /// Splits the filename of this object into its separate base and /// extension components. /// private void splitExtension() { if (this.filenameWithoutExtension == null) { string filename = this.getFileName(); int dot = filename.IndexOf('.'); if (dot < 0) { this.filenameWithoutExtension = filename; this.filenameExtension = null; } else { this.filenameExtension = filename.Substring(dot); // TODO: This is a (possibly brittle) workaround for dfy .s // and .i, which aren't part of the file type, they're part // of the name. Sorta. if (DafnyTransformBaseVerb.DAFNY_LONG_EXTNS.Contains(this.filenameExtension)) { dot += 2; this.filenameExtension = filename.Substring(dot); } this.filenameWithoutExtension = filename.Substring(0, dot); } } } /// /// Combines the provided root path and extension with this /// instance's relative path and munged (for DafnySpec/CC) filename. /// /// The desired root path. /// The desired extension. /// A combined pathname. private string mashedPathname(string root, string extension) { string filename = this.getFileNameWithoutExtension(); // Remap dafny filenames so resulting objects have correctly-parsed extns. filename = Util.dafnySpecMungeName(filename); return Path.Combine(root, this.getDirRelativeToSrcOrObj(), filename + extension); } /// /// Strips off the initial 'src\' or 'obj\' from the path. /// /// /// The directory containing this object, relative to the source or /// object directory. /// private string getDirRelativeToSrcOrObj() { string dirname = this.getDirPath(); int slash = dirname.IndexOf('\\'); Util.Assert(slash >= 0); return dirname.Substring(slash + 1); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/BuildObjectValuePointer.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Xml; /// /// Mapping between a BuildObject (an abstract identifier) and the hash /// value of the build object's contents (concrete identifier) for this run. /// REVIEW: Come up with a better name for this? /// public class BuildObjectValuePointer { /// /// The XML element name for this object. /// public const string XmlTag = "BuildObjectValuePointer"; /// /// The XML attribute name for the ObjectHash value. /// private const string XmlObjectHashAttribute = "ObjectHash"; /// /// The XML attribute name for the RelativePath value. /// private const string XmlRelativePathAttribute = "RelativePath"; /// /// Hash of the contents referenced by the build object. /// private string objectHash; /// /// Path to the build object, relative to the IronRoot. /// private string relativePath; /// /// Initializes a new instance of the BuildObjectValuePointer class. /// /// /// Hash of the contents referenced by the build object. /// /// /// Path to the build object, relative to the IronRoot. /// public BuildObjectValuePointer(string objectHash, string relativePath) { this.objectHash = objectHash; this.relativePath = relativePath; } /// /// Gets the hash of the contents referenced by the build object. /// public string ObjectHash { get { return this.objectHash; } } /// /// Gets the path to the build object, relative to the IronRoot. /// public string RelativePath { get { return this.relativePath; } } /// /// Helper function to read an XML element (not a full document) /// representing a BuildObjectValuePointer. /// /// /// Note that the XmlReader is expected to be positioned in the XML /// document such that the current node is a BuildObjectValuePointer /// element. /// /// The XmlReader object to read from. /// /// A new BuildObjectValuePointer corresponding to the XML /// representation read. /// public static BuildObjectValuePointer ReadXml(XmlReader xr) { Util.Assert(xr.Name.Equals(XmlTag)); string objectHash = xr.GetAttribute(XmlObjectHashAttribute); string relativePath = xr.GetAttribute(XmlRelativePathAttribute); return new BuildObjectValuePointer(objectHash, relativePath); } /// /// Helper function to write an XML element (not a full document) /// representing this BuildObjectValuePointer. /// /// The XmlWriter object to write to. public void WriteXml(XmlWriter xw) { xw.WriteStartElement(XmlTag); xw.WriteAttributeString(XmlObjectHashAttribute, this.objectHash); xw.WriteAttributeString(XmlRelativePathAttribute, this.relativePath); xw.WriteEndElement(); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/CachedHash.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; internal class CachedHash { private Dictionary hashCache; private HashFunc hashFunc; private FailureBehavior failureBehavior; private CachabilityTestFunc cachabilityTest; public CachedHash( HashFunc hashFunc, FailureBehavior failureBehavior = FailureBehavior.AssertFailures, CachabilityTestFunc cachabilityTest = null) { this.hashCache = new Dictionary(); this.hashFunc = hashFunc; this.failureBehavior = failureBehavior; this.cachabilityTest = cachabilityTest; } public delegate ValueType HashFunc(HashedObjectType hashObj); public delegate bool CachabilityTestFunc(ValueType value); public enum FailureBehavior { IgnoreFailures, AssertFailures } public ValueType get(HashedObjectType hashObj) { if (!this.hashCache.ContainsKey(hashObj)) { ValueType value = this.hashFunc(hashObj); if (value == null) { Util.Assert(this.failureBehavior == FailureBehavior.IgnoreFailures); return value; } else if (this.cachabilityTest != null && !this.cachabilityTest(value)) { return value; } else { this.hashCache[hashObj] = value; } } return this.hashCache[hashObj]; } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/CloudExecutionQueue.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Configuration; using System.IO; using System.Threading; using Microsoft.WindowsAzure.Storage; using Microsoft.WindowsAzure.Storage.Queue; /// /// Represents the queue used to make requests of cloud execution engines. /// public class CloudExecutionQueue { // Note that queue names must be all lowercase. // See http://msdn.microsoft.com/en-us/library/dd179349.aspx. /// /// Maximum interval to wait between polls of the request queue. /// In milliseconds. /// /// /// REVIEW: Is 30 seconds a reasonable cap? /// private const int RequestQueuePollIntervalCap = 30000; /// /// Name of the request queue. /// private const string RequestQueueName = "requests"; /// /// Name of the default report queue. /// private const string ReportQueueName = "reports"; /// /// Expiration time for request/report queue entries. /// Most queue entries should be picked up almost immediately, /// this is to prevent orphaned entries from hanging around "forever". /// private readonly TimeSpan queueEntryTtl; /// /// Azure storage account we're using. /// private CloudStorageAccount storageAccount; /// /// Cloud queue client for working with cloud queues. /// private CloudQueueClient queueClient; /// /// Queue to hold execution requests. /// private CloudQueue requestQueue; /// /// Queue to hold execution reports. /// private CloudQueue clientReportQueue; /// /// Cache of current request's report queue. /// private CloudQueue cachedServerReportQueue; /// /// Name of the cached report queue. /// private string cachedServerReportQueueName; /// /// Waiters for execution reports. /// private Dictionary reportWaiters; /// /// Lock for the reportWaiters dictionary. /// private Mutex reportWaitersLock; /// /// Event that is signaled (i.e. set) if we have active waiters for execution reports. /// private ManualResetEvent haveReportWaiters; /// /// Thread that monitors the report queue. /// private Thread monitoringThread; /// /// Initializes a new instance of the CloudExecutionQueue class. /// /// /// This is the constructor for servers. /// public CloudExecutionQueue() { // Work-around for running this code in CloudExecutionEngine. TODO: Clean this up! // The BuildEngine.theEngine.getIronRoot() call needs to work for BuildObject code to function properly. if (BuildEngine.theEngine.getIronRoot() == null) { BuildEngine.theEngine.setIronRoot(Directory.GetCurrentDirectory()); } this.queueEntryTtl = new TimeSpan(0, 30, 0); // 30 minutes. // Create our CloudStorageAccount object. // REVIEW: Hard-coded connection string index "Ironclad". string connectionString = null; ConnectionStringSettings settings = ConfigurationManager.ConnectionStrings["Ironclad"]; if (settings != null) { connectionString = settings.ConnectionString; } if (string.IsNullOrEmpty(connectionString)) { throw new ConfigurationException("Azure connection string missing from your NuBuild.exe.config file!"); } this.storageAccount = CloudStorageAccount.Parse(connectionString); this.queueClient = this.storageAccount.CreateCloudQueueClient(); this.requestQueue = this.queueClient.GetQueueReference(CloudExecutionQueue.RequestQueueName); this.requestQueue.CreateIfNotExists(); } /// /// Initializes a new instance of the CloudExecutionQueue class. /// /// /// This is the constructor for clients (does extra stuff). /// /// Name of the report queue this client is using. public CloudExecutionQueue(string reportQueueName) : this() { if (string.IsNullOrEmpty(reportQueueName)) { // Use default shared report queue if none is specified. reportQueueName = CloudExecutionQueue.ReportQueueName; } else { // Schedule auto-deletion of our private report queue. // We do this by setting the initial invisibility of a delete queue request. // This will auto-clean up our private report queue if we exit unexpectedly. CloudExecutionRequest deleteQueueRequest = new CloudExecutionRequest( reportQueueName, reportQueueName, CloudExecutionRequest.Operation.DeleteQueue, null, null, null, null ); CloudQueueMessage deleteQueueMessage = new CloudQueueMessage(deleteQueueRequest.ToXml()); this.requestQueue.AddMessage(deleteQueueMessage, new TimeSpan(12, 0, 0), new TimeSpan(4, 0, 0)); } this.clientReportQueue = this.queueClient.GetQueueReference(reportQueueName); this.clientReportQueue.CreateIfNotExists(); this.reportWaiters = new Dictionary(); this.reportWaitersLock = new Mutex(); this.haveReportWaiters = new ManualResetEvent(false); this.monitoringThread = new Thread(new ThreadStart(this.MonitorReportQueue)); this.monitoringThread.IsBackground = true; this.monitoringThread.Name = "Report Queue Monitor"; this.monitoringThread.Start(); } /// /// Deletes the specified queue. /// /// Name of the queue to delete. public void DeleteQueue(string queueName) { CloudQueue goner = this.queueClient.GetQueueReference(queueName); goner.DeleteIfExists(); } /// /// Submits a request for cloud execution. /// /// /// The CloudExecutionRequest detailing this request. /// public void SubmitRequest(CloudExecutionRequest request) { CloudQueueMessage message = new CloudQueueMessage(request.ToXml()); this.requestQueue.AddMessage(message, this.queueEntryTtl); } /// /// Gets the next request from the request queue. /// /// Whether to block. /// Next request on the queue. public CloudExecutionRequest GetRequest(bool block = false) { int pollInterval = 1000; // In milliseconds. CloudQueueMessage message = null; while ((message = this.requestQueue.GetMessage()) == null) { if (block) { Thread.Sleep(pollInterval); // Increase poll interval if we're below the cap. if (pollInterval < RequestQueuePollIntervalCap) { // Increase by 1/10th of a second each time. // This will take 14.5s to reach a 2s interval. pollInterval += 100; } continue; } else { return null; } } ////Console.WriteLine(message.AsString); CloudExecutionRequest request = CloudExecutionRequest.FromMessage(message); return request; } /// /// Deletes a request from the queue. /// Used by reader to indicate request completion. /// /// Request to delete. public void DeleteRequest(CloudExecutionRequest request) { CloudQueueMessage message = request.Message; this.requestQueue.DeleteMessage(message); } /// /// Submits a report of cloud execution for processing by the submitter. /// /// Report to submit. /// Name of the report queue to submit to. public void SubmitReport(CloudExecutionReport report, string reportQueueName) { // Check to see if we need to update the cached report queue. if (reportQueueName != this.cachedServerReportQueueName) { this.cachedServerReportQueue = this.queueClient.GetQueueReference(reportQueueName); this.cachedServerReportQueue.CreateIfNotExists(); this.cachedServerReportQueueName = reportQueueName; } CloudQueueMessage message = new CloudQueueMessage(report.ToXml()); this.cachedServerReportQueue.AddMessage(message, this.queueEntryTtl); } /// /// Gets the requested execution report off of the queue. /// /// Report to retrieve. /// Count of remaining waiters after our report arrives. /// The execution report in question. public CloudExecutionReport GetReport(string reportIdentifier, out int numberOfOtherWaiters) { CloudExecutionWaiter waiter = new CloudExecutionWaiter(); // Add the desired report to the dictionary under lock. this.reportWaitersLock.WaitOne(); this.reportWaiters.Add(reportIdentifier, waiter); this.haveReportWaiters.Set(); this.reportWaitersLock.ReleaseMutex(); // Wait for report to arrive, and then return it. return waiter.WaitForReport(out numberOfOtherWaiters); } /// /// Procedure performed by the report queue monitoring thread. /// private void MonitorReportQueue() { const int MaxBatchSize = 32; // Maximum allowed by API. TimeSpan invisibleTime = new TimeSpan(0, 0, 2); // Two seconds. TimeSpan pollInterval = new TimeSpan(0, 0, 1); // One second. List messages; bool anyForUs; while (true) { // Don't bother doing anything if we don't have any active waiters. this.haveReportWaiters.WaitOne(); // Get a new batch of messages. // No other queue readers will see these until the invisibleTime expires. messages = new List(this.clientReportQueue.GetMessages(MaxBatchSize, invisibleTime)); anyForUs = false; foreach (CloudQueueMessage message in messages) { CloudExecutionReport report = CloudExecutionReport.FromMessage(message); // Lookup the waiter for this report under lock. CloudExecutionWaiter waiter; int remainingWaitersCount = 0; this.reportWaitersLock.WaitOne(); bool foundWaiter = this.reportWaiters.TryGetValue(report.Identifier, out waiter); if (foundWaiter && report.Status == CloudExecutionReport.StatusCode.Completed) { this.reportWaiters.Remove(report.Identifier); remainingWaitersCount = this.reportWaiters.Count; if (remainingWaitersCount == 0) { // We don't have anyone else waiting for a report. this.haveReportWaiters.Reset(); } } this.reportWaitersLock.ReleaseMutex(); if (foundWaiter) { // We delete the report from the queue right away, // as nobody else should ever be interested in it. this.clientReportQueue.DeleteMessage(message); anyForUs = true; switch (report.Status) { case CloudExecutionReport.StatusCode.Completed: waiter.GiveReportToWaiter(report, remainingWaitersCount); break; case CloudExecutionReport.StatusCode.InProgress: Console.WriteLine("Node '{0}' reports request '{1}' is in progress.", report.ProcessingNode, report.Identifier); break; default: // REVIEW: Or just Assert here? This should never happen. Console.WriteLine("Node '{0}' reports strange status '{1}' for request '{2}'.", report.ProcessingNode, report.Status, report.Identifier); break; } } } if ((messages.Count != 0) && !anyForUs) { // Give other client(s) a chance to get their messages. Thread.Sleep(invisibleTime + pollInterval + pollInterval); } else { Thread.Sleep(pollInterval); } } } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/CloudExecutionReport.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Text; using System.Xml; using Microsoft.WindowsAzure.Storage.Queue; /// /// Message that is put on the cloud "reports" queue to inform a cloud /// execution engine client of the status of its request. /// public class CloudExecutionReport { /// /// XML element name for this object. /// public const string XmlTag = "CloudExecutionReport"; /// /// Version of this object we create by default. /// private const int Version = 1; /// /// XML element name for our version field. /// private const string XmlVersionAttribute = "Version"; /// /// XML element name for our identifier field. /// private const string XmlIdentifierElement = "Identifier"; /// /// XML element name for our status field. /// private const string XmlStatusElement = "Status"; /// /// XML element name for our processingNode field. /// private const string XmlProcessingNodeElement = "ProcessingNode"; /// /// XML element name for our exitCode field. /// private const string XmlExitCodeElement = "ExitCode"; /// /// XML element name for our standardOutput field. /// private const string XmlStandardOutputElement = "StandardOutput"; /// /// XML element name for our standardError field. /// private const string XmlStandardErrorElement = "StandardError"; /// /// XML element name for our cpuTime field. /// private const string XmlCpuTimeElement = "CpuTime"; /// /// XML element name for our outputFileMappings field. /// private const string XmlOutputFileMappingsElement = "OutputFileMappings"; /// /// Queued message this instance was created from (if it was). /// private CloudQueueMessage message; /// /// Version of this object instance. /// private int version; /// /// Request identifier this report is in response to. /// private string identifier; /// /// Status of request being conveyed by this report. /// private StatusCode status; /// /// Name of the node that produced this report. /// private string processingNode; /// /// Exit code returned from the process after execution. /// private int exitCode; /// /// Standard out from the process. /// private string standardOutput; /// /// Standard error from the process. /// private string standardError; /// /// CPU time used by the process. /// private double cpuTime; /// /// Collection of output files resulting from this execution, /// represented by both their item cache identifier and /// their relative path. /// private List outputFileMappings; /// /// Initializes a new instance of the CloudExecutionReport class. /// /// Unique ID for this instance. /// Status of the request. /// Exit code from the process. /// /// Standard output from the process execution. /// /// /// Standard error from the process execution. /// /// CPU time used by the process. /// /// Output files generated by this process execution. /// public CloudExecutionReport( string identifier, StatusCode status, int exitCode, string standardOutput, string standardError, double cpuTime, List outputFileMappings) : this( CloudExecutionReport.Version, identifier, status, Environment.MachineName, // REVIEW: Probably insecure (from user settable environment variable?). Do we care? exitCode, standardOutput, standardError, cpuTime, outputFileMappings) { } /// /// Initializes a new instance of the CloudExecutionReport class. /// /// Unique ID for this instance. /// Status of the request. public CloudExecutionReport( string identifier, StatusCode status) : this( CloudExecutionReport.Version, identifier, status, Environment.MachineName, 0, null, null, 0, null) { } /// /// Initializes a new instance of the CloudExecutionReport class. /// /// Version of this class instance. /// Unique ID for this instance. /// Status of the request. /// Name of node producing this report. /// Exit code from the process. /// /// Standard output from the process execution. /// /// /// Standard error from the process execution. /// /// CPU time used by the process. /// /// Output files generated by this process execution. /// private CloudExecutionReport( int version, string identifier, StatusCode status, string processingNode, int exitCode, string standardOutput, string standardError, double cpuTime, List outputFileMappings) { this.version = version; this.identifier = identifier; this.status = status; this.processingNode = processingNode; this.exitCode = exitCode; this.standardOutput = standardOutput; this.standardError = standardError; this.cpuTime = cpuTime; this.outputFileMappings = outputFileMappings; } /// /// Definition of Status field values. /// public enum StatusCode : int { /// /// The request was processed to completion and all other fields are meaningful. /// Note: this does NOT mean the request completed successfully. /// Completed, /// /// The request was aborted. /// Aborted, /// /// The request is in progress. /// InProgress } /// /// Gets the CloudQueueMessage this instance was derived from (if any). /// public CloudQueueMessage Message { get { return this.message; } } /// /// Gets the unique identifier for the request this report is in response to. /// public string Identifier { get { return this.identifier; } } /// /// Gets the current status of the request. /// public StatusCode Status { get { return this.status; } } /// /// Gets the name of processing node that produced this report. /// public string ProcessingNode { get { return this.processingNode; } } /// /// Gets the exit code returned from the process after execution. /// public int ExitCode { get { return this.exitCode; } } /// /// Gets the standard output from the process. /// public string StandardOutput { get { return this.standardOutput; } } /// /// Gets the standard error output from the process. /// public string StandardError { get { return this.standardError; } } /// /// Gets the CPU time used by the process execution. /// public double CpuTime { get { return this.cpuTime; } } /// /// Gets the collection of files generated by the process execution. /// public IEnumerable OutputFileMappings { get { return this.outputFileMappings; } } /// /// Creates a CloudExecutionReport from a CloudQueueMessage /// representation. /// /// /// A CloudQueueMessage containing an XML document representing a /// CloudExecutionReport. /// /// /// A new report corresponding to the XML representation contained in /// the message. /// public static CloudExecutionReport FromMessage(CloudQueueMessage message) { CloudExecutionReport report = CloudExecutionReport.FromXml(message.AsString); report.message = message; return report; } /// /// Creates a CloudExecutionReport from an XML representation. /// /// /// A string containing an XML document representing a report. /// /// /// A new report corresponding to the XML representation read. /// public static CloudExecutionReport FromXml(string xs) { XmlReader xr = XmlReader.Create(new StringReader(xs)); while (xr.Read()) { if (xr.NodeType == XmlNodeType.Element) { break; } } return ReadXml(xr); } /// /// Helper function to read an XML element (not a full document) /// representing a cloud execution report. /// /// /// Note that the XmlReader is expected to be positioned in the XML /// document such that the current node is a report element. /// /// The XmlReader object to read from. /// /// A new report corresponding to the XML representation read. /// public static CloudExecutionReport ReadXml(XmlReader xr) { Util.Assert(xr.Name.Equals(CloudExecutionReport.XmlTag)); string versionText = xr.GetAttribute(CloudExecutionReport.XmlVersionAttribute); int version = int.Parse(versionText, CultureInfo.InvariantCulture); string identifier = string.Empty; StatusCode status = StatusCode.Completed; string processingNode = "Unknown Benevolence"; int exitCode = 0; string standardOutput = string.Empty; string standardError = string.Empty; double cpuTime = 0; bool inOutputFileMappings = false; List outputFileMappings = new List(); List outputFiles = new List(); while (xr.Read()) { if (xr.NodeType == XmlNodeType.Element) { switch (xr.Name) { case XmlIdentifierElement: identifier = xr.ReadElementContentAsString(); break; case XmlStatusElement: status = (StatusCode)Enum.Parse(typeof(StatusCode), xr.ReadElementContentAsString()); break; case XmlProcessingNodeElement: processingNode = xr.ReadElementContentAsString(); break; case XmlExitCodeElement: exitCode = xr.ReadElementContentAsInt(); break; case XmlStandardOutputElement: standardOutput = xr.ReadElementContentAsString(); break; case XmlStandardErrorElement: standardError = xr.ReadElementContentAsString(); break; case XmlCpuTimeElement: cpuTime = xr.ReadElementContentAsDouble(); break; case XmlOutputFileMappingsElement: inOutputFileMappings = true; break; case BuildObjectValuePointer.XmlTag: Util.Assert(inOutputFileMappings); outputFileMappings.Add(BuildObjectValuePointer.ReadXml(xr)); break; } } else if (xr.NodeType == XmlNodeType.EndElement) { if (xr.Name.Equals(CloudExecutionReport.XmlTag)) { break; // All done. } switch (xr.Name) { case XmlOutputFileMappingsElement: inOutputFileMappings = false; break; } } } // REVIEW: Require element presence? Sanity check things here? return new CloudExecutionReport( version, identifier, status, processingNode, exitCode, standardOutput, standardError, cpuTime, outputFileMappings); } /// /// Creates an XML document representing this cloud execution report. /// /// /// A string containing an XML document representing this report. /// public string ToXml() { StringBuilder sb = new StringBuilder(); XmlWriterSettings settings = new XmlWriterSettings(); settings.Indent = true; XmlWriter xw = XmlWriter.Create(sb, settings); xw.WriteStartDocument(); this.WriteXml(xw); xw.Close(); return sb.ToString(); } /// /// Helper function to write an XML element (not a full document) /// representing this result record. /// /// The XmlWriter object to write to. public void WriteXml(XmlWriter xw) { // Start writing the element for this object. xw.WriteStartElement(XmlTag); xw.WriteAttributeString(XmlVersionAttribute, this.version.ToString(CultureInfo.InvariantCulture)); // Write the Identifier element. xw.WriteElementString(XmlIdentifierElement, this.identifier); // Write the Status element. xw.WriteElementString(XmlStatusElement, this.status.ToString()); // Write the ProcessingNode element. xw.WriteElementString(XmlProcessingNodeElement, this.processingNode); if (this.status == StatusCode.Completed) { // Write the ExitCode element. xw.WriteElementString(XmlExitCodeElement, this.exitCode.ToString(CultureInfo.InvariantCulture)); // Write the Standard Output element. xw.WriteElementString(XmlStandardOutputElement, this.standardOutput); // Write the Standard Error element. xw.WriteElementString(XmlStandardErrorElement, this.standardError); // Write the CPU Time element. xw.WriteElementString(XmlCpuTimeElement, this.cpuTime.ToString(CultureInfo.InvariantCulture)); // Write the OutputFileMappings element. xw.WriteStartElement(XmlOutputFileMappingsElement); foreach (BuildObjectValuePointer outputFile in this.outputFileMappings) { outputFile.WriteXml(xw); } xw.WriteEndElement(); } // Finish writing the element for this object. xw.WriteEndElement(); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/CloudExecutionRequest.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Text; using System.Xml; using Microsoft.WindowsAzure.Storage.Queue; /// /// Message that is put on the cloud "requests" queue to ask a cloud /// execution engine to do some work on the requester's behalf. /// public class CloudExecutionRequest { /// /// XML element name for this object. /// public const string XmlTag = "CloudExecutionRequest"; /// /// Version of this object we create by default. /// private const int Version = 2; /// /// XML element name for our version field. /// private const string XmlVersionAttribute = "Version"; /// /// XML element name for our reportQueue field. /// private const string XmlReportQueueElement = "ReportQueue"; /// /// XML element name for our identifier field. /// private const string XmlIdentifierElement = "Identifier"; /// /// XML element name for our operation field. /// private const string XmlOperationElement = "Operation"; /// /// XML element name for our executable field. /// private const string XmlExecutableElement = "Executable"; /// /// XML element name for our arguments field. /// private const string XmlArgumentsElement = "Arguments"; /// /// XML element name for our inputFileMappings field. /// private const string XmlInputFileMappingsElement = "InputFileMappings"; /// /// XML element name for our outputFiles field. /// private const string XmlOutputFilesElement = "OutputFiles"; /// /// Queued message this instance was created from (if it was). /// private CloudQueueMessage message; /// /// Version of this object instance. /// private int version; /// /// Queue on which to add the report of the disposition of this request. /// private string reportQueue; /// /// Unique identifier for this request. /// private string identifier; /// /// Operation to perform. /// private Operation operation; /// /// Executable to be run. /// private string executable; /// /// Arguments to the executable. /// private string arguments; /// /// Collection of input files required for this execution, /// represented by both their item cache identifier and /// their relative path. /// private List inputFileMappings; /// /// Collection of expected output files from this execution. /// private IEnumerable outputFiles; /// /// Initializes a new instance of the CloudExecutionRequest class. /// /// /// Queue on which to add the report of the disposition of this request. /// /// Unique ID for this instance. /// Operation to perform. /// Executable to be run. /// Arguments to the executable. /// /// Input files required for this execution. /// /// Expected output files. public CloudExecutionRequest( string reportQueue, string identifier, Operation operation, string executable, string arguments, List inputFileMappings, IEnumerable outputFiles) : this( CloudExecutionRequest.Version, reportQueue, identifier, operation, executable, arguments, inputFileMappings, outputFiles) { // REVIEW: Use different random string generator for identifier? } /// /// Initializes a new instance of the CloudExecutionRequest class. /// /// Version of this class instance. /// /// Queue on which to add the report of the disposition of this request. /// /// Unique ID for this instance. /// Operation to perform. /// Executable to be run. /// Arguments to the executable. /// /// Input files required for this execution. /// /// Expected output files. private CloudExecutionRequest( int version, string reportQueue, string identifier, Operation operation, string executable, string arguments, List inputFileMappings, IEnumerable outputFiles) { this.version = version; this.reportQueue = reportQueue; this.identifier = identifier; this.operation = operation; this.executable = executable; this.arguments = arguments; this.inputFileMappings = inputFileMappings; this.outputFiles = outputFiles; } /// /// Various types of operation that can be requested. /// public enum Operation : int { /// /// Don't do anything (no-op). /// None, /// /// Run the specified executable. /// RunExecutable, /// /// Delete the specified report queue. /// DeleteQueue, /// /// Exit (and thus quit handling requests). /// CommitSuicide, } /// /// Gets the CloudQueueMessage this instance was derived from (if any). /// public CloudQueueMessage Message { get { return this.message; } } /// /// Gets the queue on which to report the disposition of this request. /// public string ReportQueue { get { return this.reportQueue; } } /// /// Gets the unique identifier for this request. /// public string Identifier { get { return this.identifier; } } /// /// Gets the operation to perform. /// public Operation RequestedOperation { get { return this.operation; } } /// /// Gets the executable to run. /// public string Executable { get { return this.executable; } } /// /// Gets the arguments to the executable. /// public string Arguments { get { return this.arguments; } } /// /// Gets the collection of files needed as input to the execution, /// as both BuildObjects and as their cached hash values. /// public IEnumerable InputFileMappings { get { return this.inputFileMappings; } } /// /// Gets the collection of potential output files from this execution, /// as BuildObjects. /// public IEnumerable OutputFiles { get { return this.outputFiles; } } /// /// Creates a CloudExecutionRequest from a CloudQueueMessage /// representation. /// /// /// A CloudQueueMessage containing an XML document representing a /// CloudExecutionRequest. /// /// /// A new request corresponding to the XML representation contained in /// the message. /// public static CloudExecutionRequest FromMessage(CloudQueueMessage message) { CloudExecutionRequest request = CloudExecutionRequest.FromXml(message.AsString); request.message = message; return request; } /// /// Creates a CloudExecutionRequest from an XML representation. /// /// /// A string containing an XML document representing a request. /// /// /// A new request corresponding to the XML representation read. /// public static CloudExecutionRequest FromXml(string xs) { XmlReader xr = XmlReader.Create(new StringReader(xs)); while (xr.Read()) { if (xr.NodeType == XmlNodeType.Element) { break; } } return ReadXml(xr); } /// /// Helper function to read an XML element (not a full document) /// representing a cloud execution request. /// /// /// Note that the XmlReader is expected to be positioned in the XML /// document such that the current node is a request element. /// /// The XmlReader object to read from. /// /// A new request corresponding to the XML representation read. /// public static CloudExecutionRequest ReadXml(XmlReader xr) { Util.Assert(xr.Name.Equals(CloudExecutionRequest.XmlTag)); string versionText = xr.GetAttribute(CloudExecutionRequest.XmlVersionAttribute); int version = int.Parse(versionText, CultureInfo.InvariantCulture); string reportQueue = "reports"; string identifier = string.Empty; Operation operation = Operation.RunExecutable; string executable = string.Empty; string arguments = string.Empty; bool inInputFileMappings = false; List inputFileMappings = new List(); bool inOutputFiles = false; List outputFiles = new List(); while (xr.Read()) { if (xr.NodeType == XmlNodeType.Element) { switch (xr.Name) { case XmlReportQueueElement: reportQueue = xr.ReadElementContentAsString(); break; case XmlIdentifierElement: identifier = xr.ReadElementContentAsString(); break; case XmlOperationElement: operation = (Operation)Enum.Parse(typeof(Operation), xr.ReadElementContentAsString()); break; case XmlExecutableElement: executable = xr.ReadElementContentAsString(); break; case XmlArgumentsElement: arguments = xr.ReadElementContentAsString(); break; case XmlInputFileMappingsElement: inInputFileMappings = true; break; case BuildObjectValuePointer.XmlTag: Util.Assert(inInputFileMappings); inputFileMappings.Add(BuildObjectValuePointer.ReadXml(xr)); break; case XmlOutputFilesElement: inOutputFiles = true; break; case BuildObject.XmlTag: Util.Assert(inOutputFiles); outputFiles.Add(BuildObject.ReadXml(xr)); break; } } else if (xr.NodeType == XmlNodeType.EndElement) { if (xr.Name.Equals(CloudExecutionRequest.XmlTag)) { break; // All done. } switch (xr.Name) { case XmlInputFileMappingsElement: inInputFileMappings = false; break; case XmlOutputFilesElement: inOutputFiles = false; break; } } } // REVIEW: Require presence of (some/all) elements? Sanity check things here? return new CloudExecutionRequest( version, reportQueue, identifier, operation, executable, arguments, inputFileMappings, outputFiles); } /// /// Creates an XML document representing this cloud execution request. /// /// /// A string containing an XML document representing this request. /// public string ToXml() { StringBuilder sb = new StringBuilder(); XmlWriterSettings settings = new XmlWriterSettings(); settings.Indent = true; XmlWriter xw = XmlWriter.Create(sb, settings); xw.WriteStartDocument(); this.WriteXml(xw); xw.Close(); return sb.ToString(); } /// /// Helper function to write an XML element (not a full document) /// representing this result record. /// /// The XmlWriter object to write to. public void WriteXml(XmlWriter xw) { // Start writing the element for this object. xw.WriteStartElement(XmlTag); xw.WriteAttributeString(CloudExecutionRequest.XmlVersionAttribute, this.version.ToString(CultureInfo.InvariantCulture)); // Write the ReportQueue element. xw.WriteElementString(XmlReportQueueElement, this.reportQueue); // Optionally write the Identifier element. if (!string.IsNullOrEmpty(this.identifier)) { xw.WriteElementString(CloudExecutionRequest.XmlIdentifierElement, this.identifier); } // Write the Operation element. xw.WriteElementString(XmlOperationElement, this.operation.ToString()); if (this.operation == Operation.RunExecutable) { // Write the Executable element. xw.WriteElementString(XmlExecutableElement, this.executable); // Write the Arguments element. xw.WriteElementString(XmlArgumentsElement, this.arguments); // Write the InputFileMappings element. xw.WriteStartElement(XmlInputFileMappingsElement); foreach (BuildObjectValuePointer inputFile in this.inputFileMappings) { inputFile.WriteXml(xw); } xw.WriteEndElement(); // Write the OutputFiles element. xw.WriteStartElement(XmlOutputFilesElement); foreach (BuildObject outputFile in this.outputFiles) { outputFile.WriteXml(xw); } xw.WriteEndElement(); } // Finish writing the element for this object. xw.WriteEndElement(); } /// /// Gets a string representation of this instance. /// Primarily intended as a debugging aid. /// /// A string representation of this instance. public override string ToString() { StringBuilder output = new StringBuilder(); output.AppendFormat("Version: {0}", this.version); output.AppendLine(); output.AppendFormat("Report Queue: {0}", this.reportQueue); output.AppendLine(); output.AppendFormat("Identifier: {0}", this.identifier); output.AppendLine(); output.AppendFormat("Operation: {0}", this.operation); output.AppendLine(); output.AppendFormat("Executable: {0}", this.executable); output.AppendLine(); output.AppendFormat("Arguments: {0}", this.arguments); output.AppendLine(); output.AppendFormat("InputFileMappings ({0} files):", this.inputFileMappings.Count); output.AppendLine(); #if false foreach (BuildObjectValuePointer mapping in this.inputFileMappings) { output.AppendFormat("{0} = {1}", mapping.RelativePath, mapping.ObjectHash); output.AppendLine(); } #endif output.AppendLine("OutputFiles:"); foreach (BuildObject file in this.outputFiles) { output.AppendLine(file.getRelativePath()); } return output.ToString(); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/CloudExecutionWaiter.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Threading; /// /// Represents a thread waiting for a particular cloud execution report. /// internal class CloudExecutionWaiter { /// /// Event that is signalled when a new report is ready. /// private AutoResetEvent reportIsReady; /// /// Execution report that just arrived. /// private CloudExecutionReport executionReport; /// /// Count of other waiters. /// private int otherWaitersCount; /// /// Initializes a new instance of the CloudExecutionWaiter class. /// public CloudExecutionWaiter() { this.reportIsReady = new AutoResetEvent(false); } /// /// Wait for an execution report to arrive. /// /// Count of other report waiters. /// An execution report. public CloudExecutionReport WaitForReport(out int numberOfOtherWaiters) { this.reportIsReady.WaitOne(); numberOfOtherWaiters = this.otherWaitersCount; return this.executionReport; } /// /// Give an execution report to this waiter. /// /// The execution report to give. /// Count of other report waiters. public void GiveReportToWaiter(CloudExecutionReport executionReport, int numberOfOtherWaiters) { this.executionReport = executionReport; this.otherWaitersCount = numberOfOtherWaiters; this.reportIsReady.Set(); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/CloudSubmitter.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Text; /// /// Submits requests for verb execution to remote cloud worker pool. /// internal class CloudSubmitter : IProcessInvoker { /// /// Whether to always emit diagnostic output. /// private const bool AlwaysEmitDiagnostics = true; /// /// The CPU time used by the process, in seconds. /// private double cpuTime; /// /// The exit code returned by the process. /// private int exitCode; /// /// Where standard out is collected by default. /// private string stdout; /// /// Where standard error is collected. /// private string stderr; /// /// The private working directory for the process we invoke. /// private WorkingDirectory workingDirectory; /// /// Initializes a new instance of the CloudSubmitter class. /// /// /// Unique identifier for this request. /// /// /// Working directory the process is started in. /// /// /// List of input files expected by the process. /// /// /// List of potential output files generated by the process. /// /// Executable to run. /// /// Command line arguments to provide to the executable. /// /// Not sure what this is -- some debugging/diagnostic thing. /// Where to (optionally) store the captured standard out. /// Debugging text for something or another. public CloudSubmitter( string requestIdentifier, WorkingDirectory workingDirectory, IEnumerable inputFiles, IEnumerable outputFiles, string executable, string[] args, BuildObject failureBase, BuildObject captureStdout = null, string dbgText = null) { // Catch bad verb authors before they hurt themselves. Util.Assert(!executable.Contains(":")); // Hey, this looks like an absolute path! Use .getRelativePath(); it makes your output more stable. foreach (string arg in args) { // Pardon my distasteful heuristic to avoid flagging /flag:value args. Util.Assert(arg.Length < 2 || arg[1] != ':'); // Hey, this looks like an absolute path! Use .getRelativePath() to tolerate crossing machine boundaries. } // Stash away things we'll want to remember later. this.workingDirectory = workingDirectory; // Create list of input file mappings. // REVIEW: We're not running on the main thread at this point. Are below calls all thread-safe? List inputFileMappings = new List(); foreach (BuildObject file in inputFiles) { string fileHash = BuildEngine.theEngine.Repository.GetHash(file); Util.Assert(!string.IsNullOrEmpty(fileHash)); inputFileMappings.Add(new BuildObjectValuePointer(fileHash, file.getRelativePath())); // Ensure that the input files are in the cloud cache. // REVIEW: best way to determine this is a source file? ItemCacheContainer container; if (file is SourcePath) { container = ItemCacheContainer.Sources; } else { container = ItemCacheContainer.Objects; } ItemCacheMultiplexer multiplexedCache = BuildEngine.theEngine.ItemCache as ItemCacheMultiplexer; Util.Assert(multiplexedCache != null); multiplexedCache.SyncItemToCloud(container, fileHash); } // Prepare cloud execution request for submission. string arguments = string.Join(" ", args); CloudExecutionRequest request = new CloudExecutionRequest( BuildEngine.theEngine.CloudReportQueueName, requestIdentifier, CloudExecutionRequest.Operation.RunExecutable, executable, arguments, inputFileMappings, outputFiles); BuildEngine.theEngine.CloudExecutionQueue.SubmitRequest(request); // Wait for remote execution to finish. int requestsOutstanding; Console.WriteLine("Waiting on remote execution report for request '{0}'.", requestIdentifier); CloudExecutionReport executionReport = BuildEngine.theEngine.CloudExecutionQueue.GetReport(requestIdentifier, out requestsOutstanding); Console.WriteLine("Received remote execution report for request '{0}'. {1} others still outstanding.", requestIdentifier, requestsOutstanding); // Record what we got back. this.exitCode = executionReport.ExitCode; this.stdout = executionReport.StandardOutput; this.stderr = executionReport.StandardError; this.cpuTime = executionReport.CpuTime; // Copy output files from cloud cache back to local working dir. // REVIEW: This is just to set things up as expected for the // Scheduler's recordResult routine. Could re-architect this to // be more efficient for the remote execution case. foreach (BuildObjectValuePointer outputFileMapping in executionReport.OutputFileMappings) { BuildEngine.theEngine.CloudCache.FetchItemToFile( ItemCacheContainer.Objects, outputFileMapping.ObjectHash, workingDirectory.PathTo(outputFileMapping.RelativePath)); } } /// /// Gets the exit code returned by the process. /// public int ExitCode { get { return this.exitCode; } } /// /// Gets the CPU time used by the process, in seconds. /// public double CpuTime { get { return this.cpuTime; } } /// /// Gets the process's standard output in the default case. /// Does not return the standard output if it is redirected to a file /// (i.e. if captureStdout is non-null). /// /// The process's standard output. public string GetStdout() { return this.stdout; } /// /// Gets the process's standard error output.. /// /// The process's standard error output. public string GetStderr() { return this.stderr; } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/ConcatContext.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; internal class ConcatContext : IncludePathContext { private List contexts; private string descr; public ConcatContext(IEnumerable contexts) { this.contexts = new List(contexts); this.descr = "Context(" + string.Join(",", this.contexts) + ")"; } public override string ToString() { return this.descr; } public override BuildObject search(string basename, ModPart modPart = ModPart.Ifc) { foreach (IIncludePathContext context in this.contexts) { BuildObject obj = context.search(basename, modPart); if (obj != null) { return obj; } } return null; } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/ConcatContextVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Linq; internal class ConcatContextVerb : ContextGeneratingVerb { private List parents; public ConcatContextVerb(IEnumerable parents, PoundDefines poundDefines) : base("Cat(" + string.Join(",", parents) + ")", poundDefines) { this.parents = new List(parents); } public ConcatContextVerb(IContextGeneratingVerb parentA, IContextGeneratingVerb parentB, PoundDefines poundDefines) : this(new IContextGeneratingVerb[] { parentA, parentB }, poundDefines) { } public ConcatContextVerb(IContextGeneratingVerb parentA, IContextGeneratingVerb parentB, IContextGeneratingVerb parentC, PoundDefines poundDefines) : this(new IContextGeneratingVerb[] { parentA, parentB, parentC }, poundDefines) { } public override IEnumerable getDependencies(out DependencyDisposition ddisp) { ddisp = DependencyDisposition.Complete; return this.parents.Select(parent => parent.getContextOutput()); } public override IEnumerable getVerbs() { return this.parents; } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { IEnumerable contexts = this.parents.Select(parent => ((ContextContents)BuildEngine.theEngine.Repository.FetchVirtual(parent.getContextOutput())).Context); ConcatContext context = new ConcatContext(contexts); ContextContents contents = new ContextContents(context); BuildEngine.theEngine.Repository.StoreVirtual(this.getContextOutput(), new Fresh(), contents); return new VerbSyncWorker(workingDirectory, new Fresh()); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/ContextContents.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; internal class ContextContents : VirtualContents { private IIncludePathContext context; public ContextContents(IIncludePathContext context) { this.context = context; } public IIncludePathContext Context { get { return this.context; } } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/ContextGeneratingVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; internal abstract class ContextGeneratingVerb : Verb, IContextGeneratingVerb { public const string CONTEXT_EXTN = ".ctxt"; // Virtual, so it shouldn't appear in filesystem. private int version = 1; private string nickname; private PoundDefines poundDefines; private BuildObject outputObj; /// NB nickname will need to be unique over a run; it's used as the verb AbstractIdentifier, and /// hence hash identity in caches. public ContextGeneratingVerb(string nickname, PoundDefines poundDefines) { this.nickname = nickname; this.poundDefines = poundDefines; } public PoundDefines getPoundDefines() { return this.poundDefines; } public string getContextIdentifier() { return this.nickname; } public override AbstractId getAbstractIdentifier() { return new AbstractId(this.GetType().Name, this.version, this.getContextIdentifier()); } public override IEnumerable getOutputs() { return new BuildObject[] { this.getContextOutput() }; } public BuildObject getContextOutput() { if (this.outputObj == null) { this.outputObj = new VirtualBuildObject( Path.Combine(BuildEngine.theEngine.getVirtualRoot(), Util.mungeClean(this.getAbstractIdentifier().ToString()) + CONTEXT_EXTN)); } return this.outputObj; } } internal static class ContextGeneratingVerbExtensions { internal static IIncludePathContext fetchIfAvailable(this IContextGeneratingVerb verb, ref DependencyDisposition ddisp) { try { return ((ContextContents) BuildEngine.theEngine.Repository.FetchVirtual(verb.getContextOutput())).Context; } catch (ObjectNotReadyException) { // Oh, we don't even have the context object yet. ddisp = ddisp.combine(DependencyDisposition.Incomplete); } catch (ObjectFailedException) { ddisp = ddisp.combine(DependencyDisposition.Failed); } return null; } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/CustomManifestParser.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; using System.Text; internal class CustomManifestParser { private HashSet dependencies = new HashSet(); private HashSet outputs = new HashSet(); public CustomManifestParser(SourcePath basePath) { this.parseCustomManifest(basePath); } public IEnumerable getDependencies() { return this.dependencies; } public IEnumerable getOutputs() { return this.outputs; } private void parseCustomManifest(SourcePath basePath) { SourcePath manifest = basePath.getNewSourcePath("nubuild-manifest.txt"); this.dependencies.Add(manifest); using (StreamReader stream = new StreamReader(IronRootDirectory.PathTo(manifest))) { string origline; while ((origline = stream.ReadLine()) != null) { string line = origline.Trim(); if (line.Length == 0) { continue; } if (line.Substring(0, 1) == "#") { continue; } string[] parts = line.Split(); if (parts.Length != 2) { throw new UserError(string.Format("{0}: badly formed manifest line {1}", IronRootDirectory.PathTo(manifest), origline)); } if ("output".Equals(parts[0])) { this.outputs.Add(new BuildObject(Path.Combine(basePath.getDirPath(), parts[1]))); } else if ("dependency".Equals(parts[0])) { this.dependencies.Add(basePath.getNewSourcePath(parts[1])); } } } } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/DafnyCCVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; using System.Linq; internal class DafnyCCVerb : DafnyTransformBaseVerb { private AbstractId abstractId; private FramePointerMode useFramePointer; private VSSolutionVerb dafnyCCBuildExecutableVerb; public DafnyCCVerb(SourcePath dfyroot, string appLabel, FramePointerMode useFramePointer) : base(dfyroot, appLabel) { this.useFramePointer = useFramePointer; this.abstractId = new AbstractId(this.GetType().Name, this.getVersion() + version, dfyroot.ToString(), concrete: useFramePointer.ToString()); this.dafnyCCBuildExecutableVerb = new VSSolutionVerb(new SourcePath("tools\\DafnyCC\\DafnyCC.sln", SourcePath.SourceType.Tools)); } public enum FramePointerMode { UseFramePointer, NoFramePointer } public override IEnumerable getVerbs() { return base.getVerbs().Concat(new[] { this.dafnyCCBuildExecutableVerb }); } public override AbstractId getAbstractIdentifier() { return this.abstractId; } // This is merely an assert double-check that we didn't let a spec generated // by DafnyCC slip through to be used in the BoogieAsmVerify step. internal static void AssertSmellsImplementy(BuildObject obj) { string fn = obj.getFileNameWithoutExtension(); Util.Assert(fn.EndsWith("_" + DafnyTransformBaseVerb.DAFNY_I_SUFFIX) || fn.EndsWith("_" + DafnyTransformBaseVerb.DAFNY_C_SUFFIX) || fn.Equals("Checked") || fn.Equals("Heap") || fn.Equals("Seq")); } protected override int getVersion() { return 18; } protected override BuildObject getExecutable() { return new BuildObject(Path.Combine(this.dafnyCCBuildExecutableVerb.getOutputPath().getRelativePath(), "dafnycc.exe")); } protected override IEnumerable getExtraDependencies() { string exePath = this.dafnyCCBuildExecutableVerb.getOutputPath().getRelativePath(); // REVIEW: Should we extract the dafnycc.exe dependencies from the project file instead of listing them manually? // REVIEW: What about Graph.dll? Not needed? return new BuildObject[] { new BuildObject(Path.Combine(exePath, "Basetypes.dll")), new BuildObject(Path.Combine(exePath, "CodeContractsExtender.dll")), new BuildObject(Path.Combine(exePath, "Core.dll")), new BuildObject(Path.Combine(exePath, "DafnyPipeline.dll")), new BuildObject(Path.Combine(exePath, "ParserHelper.dll")), new BuildObject(Path.Combine(exePath, "Provers.SMTLib.dll")), new BuildObject(Path.Combine(exePath, "VCGeneration.dll")), new BuildObject(Path.Combine(exePath, "z3.exe")), getDafnyPrelude() }; } protected override IEnumerable getRootArgs() { DependencyDisposition ddisp; IEnumerable result = getAllDafnyModules(out ddisp); Util.Assert(ddisp == DependencyDisposition.Complete); return result; } protected override IEnumerable getExtraSpecialOutputs() { // Work around some undesirable behavior presently in DafnyCC: // We can't pass DafnyPrelude on the command line (getRootArgs) to DafnyCC, // yet it emits a dafny_DafnyPrelude file that we want to account for in the output. return new string[] { "Checked", "Heap", "Seq" }; ////, "dafny_DafnyPrelude" }; } protected override void addExtraArgs(List args) { args.Add("/relational"); if (this.useFramePointer == FramePointerMode.UseFramePointer) { args.Add("/useFramePointer"); } } protected override IEnumerable getRoots() { return new SourcePath[] { new SourcePath("src\\Trusted\\DafnySpec\\Seq.s.dfy"), new SourcePath("src\\Checked\\Libraries\\DafnyCC\\Seq.dfy"), dfyroot }; } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/DafnyCompileOneVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; /// /// Verb to compile Dafny source code to CSharp target. /// internal class DafnyCompileOneVerb : Verb, IProcessInvokeAsyncVerb { private const int Version = 10; private const string IntermediateSourceFilename = "ExpandedSource.dfy"; private const string CSharpExt = ".cs"; private readonly SourcePath input; private readonly BuildObject output; private readonly AbstractId abstractId; private readonly IVerb[] verbs; private readonly DafnyTransitiveDepsVerb transitiveDepsVerb; private List dependencies; private SourcePath expandedSource; public DafnyCompileOneVerb(SourcePath input) { if (input == null) { throw new ArgumentNullException("input"); } this.abstractId = new AbstractId(GetType().Name, Version, input.ToString()); this.input = input; this.output = input.makeOutputObject(CSharpExt); this.transitiveDepsVerb = new DafnyTransitiveDepsVerb(input); this.verbs = new IVerb[] { this.transitiveDepsVerb }; } public override IEnumerable getDependencies(out DependencyDisposition ddisp) { if (this.dependencies == null) { DependencyDisposition dd; var dependencies = new List(); // This method's implementation is dependent upon transitiveDepsVerb being the only element of verbs. Trace.Assert(this.verbs.Length == 1 && this.verbs[0] is DafnyTransitiveDepsVerb); dependencies.AddRange(this.transitiveDepsVerb.getAvailableDeps(out dd)); dependencies.AddRange(DafnyExecutableDependencies.getDafnyExecutableDependencies()); if (dd != DependencyDisposition.Complete) { ddisp = dd; // Dependency resolution isn't complete yet and we don't want to cache the incomplete list. return dependencies; } this.dependencies = dependencies; } Trace.Assert(this.dependencies != null); ddisp = DependencyDisposition.Complete; return this.dependencies; } public override IEnumerable getVerbs() { return this.verbs; } public override IEnumerable getOutputs() { return new[] { this.output }; } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { // First expand our Dafny source file to inline all its includes. this.expandedSource = this.input.getNewSourcePath("ExpandedSource.dfy"); DafnyIncludes dafnyIncludes = new DafnyIncludes(); dafnyIncludes.ExpandDafny(workingDirectory, this.input, this.expandedSource); // Call Dafny.exe to compile Dafny source to CSharp target. var args = new[] { "/noVerify", "/spillTargetCode:1", "/compile:2", "/ironDafny", this.expandedSource.getRelativePath() }; Console.WriteLine("expanded source: " + this.expandedSource.getRelativePath()); ////Logger.WriteLine("arguments: " + String.Join(" ", args)); return new ProcessInvokeAsyncWorker( workingDirectory, this, DafnyExecutableDependencies.getDafnyExecutable().getRelativePath(), args, ProcessExitCodeHandling.NonzeroIsFailure, getDiagnosticsBase(), returnStandardOut: true, // REVIEW: Doesn't appear to be needed. returnStandardError: true, // REVIEW: Doesn't appear to be needed. allowCloudExecution: true); } public override AbstractId getAbstractIdentifier() { return this.abstractId; } public Disposition Complete(WorkingDirectory workingDirectory, double cpuTimeSeconds, string stdout, string stderr, Disposition disposition) { var dis = disposition; string cSharpPath = Path.ChangeExtension(workingDirectory.PathTo(this.expandedSource), CSharpExt); if (!File.Exists(cSharpPath)) { // Dafny has a bug where compilation fails but result code is still 0. dis = new Failed(); } if (dis is Fresh) { this.RewriteCSharpFile(cSharpPath, workingDirectory.PathTo(this.output)); } return dis; } private void RewriteCSharpFile(string inputPath, string outputPath) { using (TextWriter writer = new StreamWriter(outputPath)) { // Compile a list of namespaces that require edits var namespaces = new Dictionary(); using (TextReader reader = new StreamReader(inputPath)) { string line; System.Text.RegularExpressions.Regex pattern = new System.Text.RegularExpressions.Regex("namespace @_(\\d+)_([\\w_]+) {", System.Text.RegularExpressions.RegexOptions.Compiled); while ((line = reader.ReadLine()) != null) { var result = pattern.Match(line); if (result.Success) { string old_name = "_" + result.Groups[1] + "_" + result.Groups[2]; string new_name = "_" + result.Groups[2]; namespaces.Add(old_name, new_name); } } } using (TextReader reader = new StreamReader(inputPath)) { string line; while ((line = reader.ReadLine()) != null) { line = line.Replace(IntermediateSourceFilename, this.input.getFileName()); line = line.Replace("public class @__default {", "public partial class @__default {"); line = line.Replace("@#", "@"); // Temporary work-around. ToDo: Remove this after Dafny is fixed. line = line.Replace("public class ", "public partial class "); // Another temporary work-around. ToDo: Figure out better solution. line = line.Replace("@_default_Main", "@IronfleetMain"); // Find a more efficient approach? foreach (KeyValuePair entry in namespaces) { line = line.Replace(entry.Key, entry.Value); } writer.WriteLine(line); } } } } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/DafnyExecutableDependencies.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace NuBuild { class DafnyExecutableDependencies { private static SourcePath dafnyExecutable; public static SourcePath getDafnyExecutable() { // TODO this should eventually be a BuildObject from *building* the executable. if (dafnyExecutable == null) { dafnyExecutable = new SourcePath("tools\\Dafny\\Dafny.exe", SourcePath.SourceType.Tools); } return dafnyExecutable; } public static IEnumerable getDafnyExecutableDependencies() { List exeDepends = new List(); exeDepends.Add(getDafnyExecutable()); exeDepends.Add(new SourcePath("tools\\Dafny\\AbsInt.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\BaseTypes.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\CodeContractsExtender.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\Concurrency.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\Core.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\Dafny.exe.config", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\DafnyPipeline.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\DafnyPrelude.bpl", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\Doomed.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\ExecutionEngine.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\Graph.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\Model.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\msvcp100.dll", SourcePath.SourceType.Tools)); // Needed by z3. exeDepends.Add(new SourcePath("tools\\Dafny\\msvcr100.dll", SourcePath.SourceType.Tools)); // Needed by z3. exeDepends.Add(new SourcePath("tools\\Dafny\\ParserHelper.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\Provers.SMTLib.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\VCExpr.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\VCGeneration.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\vcomp100.dll", SourcePath.SourceType.Tools)); // Needed by z3. exeDepends.Add(new SourcePath("tools\\Dafny\\DafnyRuntime.cs", SourcePath.SourceType.Tools)); // Needed for compilation exeDepends.Add(new SourcePath("tools\\Dafny\\z3.exe", SourcePath.SourceType.Tools)); return exeDepends; } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/DafnyExtensions.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Linq; internal class DafnyExtensions { public static HashSet getForestDependencies(IEnumerable roots, out DependencyDisposition ddisp) { HashSet result = new HashSet(); ddisp = DependencyDisposition.Complete; foreach (BuildObject dfysource in roots) { TransitiveDepsVerb depsVerb = new DafnyTransitiveDepsVerb(dfysource); DependencyDisposition localDDisp; result.UnionWith(depsVerb.getAvailableDeps(out localDDisp)); ddisp = ddisp.combine(localDDisp); result.Add(dfysource); // TransitiveDeps *exclude* the root, so we need to add that in, too. } return result; } public static IEnumerable getForestVerbs(IEnumerable roots) { return roots.Select(root => new DafnyTransitiveDepsVerb(root)); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/DafnyIncludes.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; using System.Text.RegularExpressions; /// /// Extractor of Dafny include file names (and related functionality). /// internal class DafnyIncludes : IIncludeFactory { /// /// Regular expression matching Dafny include lines. /// private Regex includeRegex; /// /// Temporary working directory used by ExpandDafny method. /// private WorkingDirectory workingDirectory; /// /// TextWriter used by ExpandDafny method. /// private TextWriter outputWriter; /// /// Set of include files already visited. /// Used by ExpandDafny method. /// private HashSet visited; /// /// Initializes a new instance of the DafnyIncludes class. /// public DafnyIncludes() { this.includeRegex = new Regex("^\\s*include\\s*\"(.*)\""); } /// /// Gets a list of the include files included in the given Dafny source file. /// /// Source file to extract include file names from. /// List of include file BuildObjects. public IEnumerable getIncludes(BuildObject dfysource) { List outlist = new List(); using (TextReader tr = BuildEngine.theEngine.Repository.OpenRead(dfysource)) { while (true) { string line = tr.ReadLine(); if (line == null) { break; } Match match = this.includeRegex.Match(line); int count = 0; while (match.Success) { string includedPath = match.Groups[1].ToString(); string gluedPath = Path.Combine(dfysource.getDirPath(), includedPath); SourcePath sp = new SourcePath(gluedPath); outlist.Add(sp); count += 1; match = match.NextMatch(); // That would be unexpected! } Util.Assert(count <= 1); } } ////Logger.WriteLine(String.Format("{0} includes {1} things", dfysource.getFilesystemPath(), outlist.Count)); return outlist; } /// /// Expand a dafny source file to include all of its includes inline. /// /// Temporary working directory to use. /// Source build object. /// Where to create build object for expanded source file. public void ExpandDafny(WorkingDirectory workingDirectory, SourcePath input, SourcePath output) { // Prepare the output stream. using (TextWriter outWriter = new StreamWriter(workingDirectory.PathTo(output))) { // Stash away a few things for use by our recursive helper function. this.workingDirectory = workingDirectory; this.outputWriter = outWriter; this.visited = new HashSet(); // Recursively expand the initial Dafny source file to inline all of its includes. this.ExpandDafnyRecurse(input); } // Cache the output file in the Repository. BuildEngine.theEngine.Repository.Store(workingDirectory, output, new Fresh()); } /// /// Helper function for ExpandDafny method. /// /// Next include file to visit. /// True if the given file wasn't already included, false otherwise. private bool ExpandDafnyRecurse(SourcePath input) { // Only visit each unique include file once. // Note that SourcePaths (like all BuildObjects) have normalized file paths. string inputPath = input.getRelativePath(); if (this.visited.Contains(inputPath)) { return false; } else { this.visited.Add(inputPath); } using (TextReader reader = new StreamReader(this.workingDirectory.PathTo(input))) { while (true) { string line = reader.ReadLine(); if (line == null) { return true; } Match match = this.includeRegex.Match(line); if (match.Success) { // This is an "include" line. Find the included object. string includedPath = match.Groups[1].ToString(); string gluedPath = Path.Combine(input.getDirPath(), includedPath); SourcePath nextInclude = new SourcePath(gluedPath); string nextPath = nextInclude.getRelativePath(); // Recurse on the new include file. this.outputWriter.WriteLine("//- Begin include {0} (from {1})", nextPath, inputPath); if (!this.ExpandDafnyRecurse(nextInclude)) { this.outputWriter.WriteLine("//- Already included {0}", nextPath); } this.outputWriter.WriteLine("//- End include {0} (from {1})", nextPath, inputPath); } else { // This isn't an "include" line. Write it to our output. this.outputWriter.WriteLine(line); } } } } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/DafnySpecVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; using System.Linq; internal class DafnySpecVerb : DafnyTransformBaseVerb { private AbstractId abstractId; private VSSolutionVerb dafnySpecBuildExecutableVerb; public DafnySpecVerb(SourcePath dfyroot, string appLabel) : base(dfyroot, appLabel) { this.abstractId = new AbstractId(this.GetType().Name, this.getVersion() + version, dfyroot.ToString()); this.dafnySpecBuildExecutableVerb = new VSSolutionVerb(new SourcePath("tools\\DafnySpec\\DafnySpec.sln", SourcePath.SourceType.Tools)); } public override AbstractId getAbstractIdentifier() { return this.abstractId; } public override IEnumerable getVerbs() { return base.getVerbs().Concat(new[] { this.dafnySpecBuildExecutableVerb }); } protected override int getVersion() { return 15; } protected override BuildObject getExecutable() { return new BuildObject(Path.Combine(this.dafnySpecBuildExecutableVerb.getOutputPath().getRelativePath(), "dafnyspec.exe")); } protected override IEnumerable getExtraDependencies() { string exePath = this.dafnySpecBuildExecutableVerb.getOutputPath().getRelativePath(); // REVIEW: Should we extract the dafnyspec.exe dependencies from the project file instead of listing them manually? return new BuildObject[] { new BuildObject(Path.Combine(exePath, "DafnySpecAst.dll")), new BuildObject(Path.Combine(exePath, "Parser.dll")), }; } protected override IEnumerable getRoots() { // TODO why doesn't DafnyCC require DafnyPreludePath? return new SourcePath[] { this.getDafnyPrelude(), this.getSeqSpec(), dfyroot }; } protected override bool transformFilterAccepts(BuildObject dfysource) { string fn = dfysource.getFileNameWithoutExtension(); if (fn.EndsWith("." + DafnyTransformBaseVerb.DAFNY_S_SUFFIX)) { return true; } else { Util.Assert(fn.EndsWith("." + DafnyTransformBaseVerb.DAFNY_I_SUFFIX) || fn.EndsWith("." + DafnyTransformBaseVerb.DAFNY_C_SUFFIX) || dfysource.Equals(this.getDafnyPrelude())); return false; } } protected override IEnumerable getRootArgs() { OrderPreservingSet specFiles = new OrderPreservingSet(); specFiles.Add(this.getDafnyPrelude()); specFiles.Add(this.getSeqSpec()); DependencyDisposition ddisp; foreach (SourcePath src in this.getAllDafnyModules(out ddisp)) { if (this.transformFilterAccepts(src)) { specFiles.Add(src); } } return specFiles; } private SourcePath getSeqSpec() { return new SourcePath("src\\Trusted\\DafnySpec\\Seq.s.dfy"); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/DafnyTransformBaseVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; using System.Linq; internal abstract class DafnyTransformBaseVerb : Verb, IProcessInvokeAsyncVerb { public const char DAFNY_S_SUFFIX = 's'; // a trusted specification file public const char DAFNY_C_SUFFIX = 'c'; // a checked specification file public const char DAFNY_I_SUFFIX = 'i'; // a checked implementation file public static readonly char[] DAFNY_SUFFIXES = { DAFNY_S_SUFFIX, DAFNY_C_SUFFIX, DAFNY_I_SUFFIX }; // REVIEW: Never used? public static readonly string[] DAFNY_LONG_EXTNS = { "." + DAFNY_S_SUFFIX + DafnyVerifyOneVerb.DAFNY_EXTN, "." + DAFNY_C_SUFFIX + DafnyVerifyOneVerb.DAFNY_EXTN, "." + DAFNY_I_SUFFIX + DafnyVerifyOneVerb.DAFNY_EXTN }; protected const int version = 15; protected const string DAFNY_PRELUDE_DIRECTORY = "tools\\DafnySpec"; protected const string DAFNY_PRELUDE_FILENAME = "DafnyPrelude.dfy"; protected SourcePath dfyroot; protected string appLabel; public DafnyTransformBaseVerb(SourcePath dfyroot, string appLabel) { this.dfyroot = dfyroot; this.appLabel = appLabel; // REVIEW: This is never used by anything. Remove? IEnumerable roots = this.getRoots().Select(obj => obj.ToString()); } private delegate void Tacker(BuildObject dfysource, string filename); public override IEnumerable getDependencies(out DependencyDisposition ddisp) { HashSet result = DafnyExtensions.getForestDependencies(this.getRoots(), out ddisp); result.Add(this.getExecutable()); result.UnionWith(this.getExtraDependencies()); return result; } public override IEnumerable getVerbs() { return DafnyExtensions.getForestVerbs(this.getRoots()); } public override IEnumerable getOutputs() { List outputs = new List(); foreach (InOutMapping mapping in this.getInOutMappings()) { if (mapping.dfysource == null || mapping.dfysource.Equals(this.getDafnyPrelude()) || this.transformFilterAccepts(mapping.dfysource)) { outputs.Add(mapping.basmIfc); outputs.Add(mapping.basmImp); } } outputs.Add(new BuildObject(Path.Combine( this.getDestPath(), "dafny_modules.txt"))); return outputs; } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { BuildObject absDestPath = this.getAbsDestPath(); ////Directory.Delete(vfs.ToPath(absDestPath), true); // This verb should be the only one writing here, so let's keep it tidy. Directory.CreateDirectory(workingDirectory.PathTo(absDestPath)); // REVIEW: Shouldn't PrepareForVerb already do this? string dafnyccExecutable = this.getExecutable().getRelativePath(); List args = new List(); args.AddRange(this.getRootArgs().Select(sp => sp.getRelativePath())); args.Add("/outdir:" + this.getDestPath()); this.addExtraArgs(args); return new ProcessInvokeAsyncWorker( workingDirectory, this, dafnyccExecutable, args.ToArray(), ProcessExitCodeHandling.NonzeroIsFailure, getDiagnosticsBase()); } public Disposition Complete(WorkingDirectory workingDirectory, double cpuTimeSeconds, string stdout, string stderr, Disposition disposition) { if (disposition is Failed) { return disposition; } HashSet createdFiles = new HashSet(Directory.GetFiles(workingDirectory.PathTo(this.getAbsDestPath())).Select(path => Path.GetFileName(path))); HashSet expectedFiles = new HashSet(this.getOutputs().Select(obj => obj.getFileName())); // DafnyCC/DafnySpec process a big batch of files together. Did we correctly understand what it did? if (!createdFiles.SetEquals(expectedFiles)) { // REVIEW: These are never used by anything. Remove? bool dummy = createdFiles.SetEquals(expectedFiles); int missing = expectedFiles.Except(createdFiles).Count(); int extra = createdFiles.Except(expectedFiles).Count(); string msg = "Missing files: " + string.Join(",", expectedFiles.Except(createdFiles)) + "\n" + " Extra files: " + string.Join(",", createdFiles.Except(expectedFiles)); return new Failed(msg); } // Propagate the NuBuild annotations. foreach (InOutMapping mapping in this.getInOutMappings()) { if (mapping.dfysource != null && this.transformFilterAccepts(mapping.dfysource)) { AnnotationScanner.transferAnnotations( workingDirectory, mapping.dfysource, mapping.basmIfc, BoogieAsmDepBase.CommentSymbol); AnnotationScanner.transferAnnotations( workingDirectory, mapping.dfysource, mapping.basmImp, BoogieAsmDepBase.CommentSymbol); } } return new Fresh(); } protected abstract int getVersion(); protected abstract BuildObject getExecutable(); // getRoots is the set of dafny files from which we explore to // discover the set of dependencies. We use the same transitive // closure to compute the set of allDafnyModules, which tell // us what output files to expect. protected abstract IEnumerable getRoots(); // roots -> dependencies // roots -> allDafnyModules -> getRootArgs // getRootArgs is the set of dafny files we hand to the executable. // In the DafnyCC case, it's the transitive closure (allDafnyModules), // in the DafnySpec case, it's the roots only. Weird. And there are // weird exceptions in both cases. protected abstract IEnumerable getRootArgs(); protected virtual IEnumerable getExtraDependencies() { return new BuildObject[] { }; } protected virtual IEnumerable getExtraSpecialOutputs() { return new string[] { }; } protected virtual void addExtraArgs(List args) { } protected virtual bool transformFilterAccepts(BuildObject dfysource) { return true; } protected virtual IEnumerable getAllDafnyModules(out DependencyDisposition ddisp) { HashSet result = DafnyExtensions.getForestDependencies(this.getRoots(), out ddisp); // Now we assert that all Dafny inputs are actually SourcePaths. HashSet rc = new HashSet(); foreach (BuildObject obj in result) { if (obj.getExtension().EndsWith(DafnyVerifyOneVerb.DAFNY_EXTN)) { rc.Add((SourcePath)obj); } else { Util.Assert(obj.getExtension().EndsWith(TransitiveDepsVerb.TDEP_EXTN)); // Discard it. } } return rc; } protected SourcePath getDafnyPrelude() { return new SourcePath(Path.Combine(DAFNY_PRELUDE_DIRECTORY, DAFNY_PRELUDE_FILENAME), SourcePath.SourceType.Tools); } private string getDestPath() { // This logic duplicates BuildObject.makeLabeledOutputObject; the interface isn't tidily // factored for reuse yet. string path = this.GetType().Name; if (this.appLabel != null) { path = Path.Combine(this.appLabel, path); } path = Path.Combine(BuildEngine.theEngine.getObjRoot(), path); return path; } private BuildObject basmOutputForDafnyModule(string modulename, string extn) { bool isTrusted = (modulename.EndsWith("_" + DAFNY_S_SUFFIX) || modulename.Equals("Trusted")) && BeatExtensions.whichPart(extn) == ModPart.Imp; return new BuildObject(Path.Combine(this.getDestPath(), modulename + extn), isTrusted: isTrusted); } private BuildObject getAbsDestPath() { return new BuildObject(this.getDestPath()); } private List getInOutMappings() { List mapping = new List(); Tacker tack = delegate(BuildObject dfysource, string filename) { mapping.Add(new InOutMapping( dfysource, this.basmOutputForDafnyModule(filename, BoogieAsmVerifyVerb.BASMIFC_EXTN), this.basmOutputForDafnyModule(filename, BoogieAsmVerifyVerb.BASMIMP_EXTN))); }; DependencyDisposition ddispDummy; foreach (SourcePath dfy in this.getAllDafnyModules(out ddispDummy)) { // Trim off ".dfy" but not ".s" or ".i". string dfyname = dfy.getFileName(); Util.Assert(dfyname.EndsWith(".dfy")); string basename = dfyname.Substring(0, dfyname.Length - 4); Util.Assert(basename.Equals(dfy.getFileNameWithoutExtension())); // TODO delete prior lines. basename = Util.dafnySpecMungeName(basename); if ((this is DafnyCCVerb) && (basename.Equals("Seq") || basename.Equals("Seq_s"))) { // TODO undesirable workaround -- DafnyCC doesn't want 'seq.dfy' in its output list, but DafnySpec does...? continue; } tack(dfy, "dafny_" + basename); } tack(null, "Trusted"); // DafnyCC doesn't really want this, but meh, it emits it, so we account for it. foreach (string basename in this.getExtraSpecialOutputs()) { tack(null, basename); } return mapping; } private class InOutMapping { public readonly BuildObject dfysource; // null --> outputs come from bowels of DafnySpec/DafnyCC. public readonly BuildObject basmIfc; public readonly BuildObject basmImp; public InOutMapping(BuildObject dfysource, BuildObject basmIfc, BuildObject basmImp) { this.dfysource = dfysource; this.basmIfc = basmIfc; this.basmImp = basmImp; } } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/DafnyTransitiveDepsVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; internal class DafnyTransitiveDepsVerb : TransitiveDepsVerb { public DafnyTransitiveDepsVerb(BuildObject input) : base(input) { } protected override TransitiveDepsVerb factory(BuildObject obj) { return new DafnyTransitiveDepsVerb(obj); } protected override IIncludeFactory getIncludeFactory() { return new DafnyIncludes(); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/DafnyVerifyOneVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; internal class DafnyVerifyOneVerb : VerificationResultVerb, IProcessInvokeAsyncVerb { public const string DAFNY_EXTN = ".dfy"; private const int version = 18; private const string ADDDAFNYFLAG_LABEL = "AddDafnyFlag"; private SourcePath dfysource; private AbstractId abstractId; public DafnyVerifyOneVerb(SourcePath dfysource) { this.dfysource = dfysource; this.abstractId = new AbstractId(this.GetType().Name, version, dfysource.ToString()); } public override AbstractId getAbstractIdentifier() { return this.abstractId; } public override IEnumerable getDependencies(out DependencyDisposition ddisp) { TransitiveDepsVerb depsVerb = this.getTransitiveDepsVerb(); HashSet result = depsVerb.getAvailableDeps(out ddisp); result.UnionWith(DafnyExecutableDependencies.getDafnyExecutableDependencies()); return result; } public override IEnumerable getVerbs() { return new IVerb[0]; // All inputs are sources. } public override BuildObject getOutputFile() { return this.dfysource.makeOutputObject(".dfy.v"); } public override IEnumerable getOutputs() { return new[] { this.getOutputFile() }; } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { List arguments = new List(); arguments.Add("/noNLarith"); arguments.Add("/allowGlobals"); arguments.Add("/dafnycc"); arguments.Add("/z3opt:ARITH_RANDOM_SEED=1"); arguments.Add("/z3opt:NL_ARITH=false"); arguments.Add("/compile:0"); arguments.Add("/timeLimit:30"); arguments.Add("/noCheating:1"); foreach (string[] ann in new AnnotationScanner(this.dfysource).getAnnotations(ADDDAFNYFLAG_LABEL)) { if (ann.Length != 2) { throw new SourceConfigurationError("Expected exactly 1 argument to " + ADDDAFNYFLAG_LABEL); } if (ann[1].StartsWith("/z3opt:NL_ARITH=true")) { arguments.Remove("/noNLarith"); } arguments.Add(ann[1]); } arguments.Add(this.dfysource.getRelativePath()); Logger.WriteLine("arguments: " + string.Join(" ", arguments)); return new ProcessInvokeAsyncWorker( workingDirectory, this, DafnyExecutableDependencies.getDafnyExecutable().getRelativePath(), arguments.ToArray(), ProcessExitCodeHandling.NonzeroIsOkay, getDiagnosticsBase(), returnStandardOut: true, returnStandardError: true, allowCloudExecution: true); } public Disposition Complete(WorkingDirectory workingDirectory, double cpuTimeSeconds, string stdout, string stderr, Disposition disposition) { VerificationResult vr = new VerificationResult( this.dfysource.getRelativePath(), cpuTimeSeconds, stdout, stderr, new VerificationResultDafnyParser()); vr.addBasicPresentation(); vr.toXmlFile(workingDirectory.PathTo(this.getOutputFile())); this.setWasRejectableFailure(!vr.pass); return disposition; } public IEnumerable getDirectIncludes() { // By the time this method is called by VerbToposorter, // this verb is scheduled for execution, and hence its deps // are complete. So all of these lookups should succeed. // (wait, does that follow?) return this.getTransitiveDepsVerb().getShallowIncludes(); } protected override BuildObject getSource() { return this.dfysource; } private TransitiveDepsVerb getTransitiveDepsVerb() { return new DafnyTransitiveDepsVerb(this.dfysource); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/DafnyVerifyTreeVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Linq; internal class DafnyVerifyTreeVerb : Verb, IObligationsProducer { private const int version = 30; private const string DFYTREE_EXTN = ".dfytree"; private SourcePath displayRoot; // used only in labeling the output private BuildObject obligations; private AbstractId abstractId; public DafnyVerifyTreeVerb(SourcePath root) { this.displayRoot = root; this.obligations = root.makeOutputObject(DFYTREE_EXTN + VerificationObligationList.VOL_EXTN); this.abstractId = new AbstractId(this.GetType().Name, version, root.ToString()); } public override AbstractId getAbstractIdentifier() { return this.abstractId; } public BuildObject getObligationSet() { return this.obligations; } public override IEnumerable getDependencies(out DependencyDisposition ddisp) { HashSet availableDeps = this.getAvailableDeps(out ddisp); List true_deps = new List(); foreach (BuildObject dep in availableDeps) { if (dep.getExtension().EndsWith(DafnyVerifyOneVerb.DAFNY_EXTN)) { true_deps.Add(this.mkVerificationObject(dep)); } else { true_deps.Add(dep); } } return true_deps; } public override IEnumerable getVerbs() { // TODO cast below assumes dafny files are always source files. // That's easy enough to remedy in DafnyVerifyOneVerb ctor, but for // now, we continue assuming it. // This will matter if we ever auto-generate a Dafny file. DependencyDisposition ddispDummy; IEnumerable result = this.getDafnyDependencies(out ddispDummy) .Select(dfysource => new DafnyVerifyOneVerb((SourcePath)dfysource)) .Concat(new List() { new DafnyTransitiveDepsVerb(this.displayRoot) }); return result; } public override IEnumerable getOutputs() { return new HashSet() { this.obligations }; } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { IEnumerable verificationResults = this.getVerbs() .Where(verb => verb is VerificationResultVerb) .Select(dfy_one => ((VerificationResultVerb)dfy_one).getOutputFile()); VerificationObligationList vol = new VerificationObligationList(verificationResults); vol.store(workingDirectory, this.obligations); return new VerbSyncWorker(workingDirectory, new Fresh()); } private BuildObject mkVerificationObject(BuildObject dfysource) { return dfysource.makeOutputObject(DafnyVerifyOneVerb.DAFNY_EXTN + VerificationResultVerb.VERIFICATION_RESULT_EXTN); } private HashSet getAvailableDeps(out DependencyDisposition ddisp) { TransitiveDepsVerb depsVerb = new DafnyTransitiveDepsVerb(this.displayRoot); HashSet availableDeps = depsVerb.getAvailableDeps(out ddisp); availableDeps.Add(this.displayRoot); // TransitiveDeps *exclude* the root, so we need to add that in, too. return availableDeps; } private IEnumerable getDafnyDependencies(out DependencyDisposition ddisp) { HashSet result = this.getAvailableDeps(out ddisp); return result.Where(dep => dep.getExtension().EndsWith(DafnyVerifyOneVerb.DAFNY_EXTN)); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/DbgFileCopySpeedTest.cs ================================================ namespace NuBuild { using System; using System.IO; internal class DbgFileCopySpeedTest { public static void thing() { Directory.SetCurrentDirectory("c:\\users\\howell\\verve2\\iron"); Directory.CreateDirectory("dummy"); Directory.CreateDirectory("dummy\\Results"); Directory.CreateDirectory("dummy\\Objects"); Directory.CreateDirectory("dummy\\Sources"); foreach (string path in Directory.EnumerateFiles("nucache", "*", SearchOption.AllDirectories)) { string fn = path.Substring(path.IndexOf("nucache") + 8); string source = Path.Combine("nucache", fn); string dest = Path.Combine("dummy", fn); ////Logger.WriteLine("Copy " + source + " to " + dest); ////File.Copy(source, dest); File.Delete(dest); using (FileStream outStream = File.OpenWrite(dest)) { bool dummy = File.Exists(source); using (Stream inStream = File.OpenRead(source)) { inStream.CopyTo(outStream); } } } } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/DbgHashSpeedTest.cs ================================================ namespace NuBuild { using System; using System.IO; using System.Linq; internal class DbgHashSpeedTest { public static void thing() { Directory.SetCurrentDirectory("c:\\users\\howell\\verve2\\iron"); string[] theFiles = File.ReadAllLines("hashlist"); Logger.WriteLine("I found " + theFiles.Count() + " files"); foreach (string file in theFiles) { string s = Util.hashFilesystemPath(file); Logger.WriteLine(s); } } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/DbgVerbCounter.cs ================================================ namespace NuBuild { using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; // I used this class to determine how much effort we were wasting // re-computing verb.getDependencies. internal class DbgVerbCounter { public enum DbgVerbCondition { DVWake, DVDepsIncomplete, DVDepsStale, DVDepsNonstale, DVTotal } private Dictionary, int> dbgCounts = new Dictionary, int>(); public void dbgDisplayCounts() { List> keys = new List>(dbgCounts.Keys); keys.Sort(); foreach (Tuple key in keys) { Logger.WriteLine(string.Format("{0:20}: {1}", key, dbgCounts[key])); } } public void consider(IVerb verb, DbgVerbCondition cond) { consider_inner(new Tuple(verb, cond)); consider_inner(new Tuple(verb, DbgVerbCondition.DVTotal)); } private void consider_inner(Tuple key) { if (!dbgCounts.ContainsKey(key)) { dbgCounts[key] = 0; } dbgCounts[key] += 1; } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/DependencyCache.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; internal class DependencyCache { private Dictionary theCache; private int dbgQueries = 0; private int dbgMisses = 0; public DependencyCache() { this.theCache = new Dictionary(); } public IEnumerable getDependencies(IVerb verb, out DependencyDisposition ddisp) { this.dbgQueries += 1; DependencyResult result; bool present = this.theCache.TryGetValue(verb, out result); if (!present) { this.dbgMisses += 1; result = new DependencyResult(); result.deps = verb.getDependencies(out result.ddisp); if (result.ddisp != DependencyDisposition.Incomplete) { // Can't cache incomplete results, since they may change upon // later inspection. this.theCache[verb] = result; } } ddisp = result.ddisp; return result.deps; } public void dbgPrintStats() { Logger.WriteLine(string.Format( "DependencyCache queries {0} misses {1}", this.dbgQueries, this.dbgMisses)); } private class DependencyResult { public IEnumerable deps; public DependencyDisposition ddisp; } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/DependencyDisposition.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; public enum DependencyDisposition { Complete, Incomplete, Failed // Something failed upstream } public static class DependencyDispositionExtensions { public static DependencyDisposition combine(this DependencyDisposition a, DependencyDisposition b) { if (a == DependencyDisposition.Failed || b == DependencyDisposition.Failed) { return DependencyDisposition.Failed; } if (a == DependencyDisposition.Incomplete || b == DependencyDisposition.Incomplete) { return DependencyDisposition.Incomplete; } return DependencyDisposition.Complete; } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/Disposition.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Xml; internal class Disposition { public const string _xml_tag = "Disposition"; private const string _xml_value_attr = "Value"; public static Disposition readXml(XmlReader xr) { Util.Assert(xr.Name.Equals(_xml_tag)); string value = xr.GetAttribute(_xml_value_attr); if (value.Equals(Fresh.Value)) { return new Fresh(); } else if (value.Equals(Failed.Value)) { return Failed.readXml(xr); } else { throw new Exception("Invalid disposition value " + value); } } public virtual IEnumerable getMessages() { return new string[0]; } public virtual void writeXml(XmlWriter xw) { xw.WriteStartElement(_xml_tag); xw.WriteAttributeString(_xml_value_attr, ToString()); this.writeXmlExtend(xw); xw.WriteEndElement(); } protected virtual void writeXmlExtend(XmlWriter xw) { } } internal class Stale : Disposition { public const string Value = "Stale"; public override string ToString() { return Value; } } internal class Fresh : Disposition { public const string Value = "Fresh"; public override string ToString() { return Value; } } /// /// Failed represents a PERMANENT failure. Any non-Stale disposition is recorded /// permanently in the build cache (including the globally-shared build cache!), /// preventing that particular verb from ever being tried again. Only record a /// Failed disposition if repeating the verb is guaranteed to fail again the same way. /// internal class Failed : Disposition { public const string Value = "Failed"; private const string _xml_MessageTag = "Message"; private List messages; public Failed(string msg = null) { this.messages = new List(); if (msg != null) { this.AddError(msg); } } public Failed(IEnumerable messages) { this.messages = new List(messages); } public static new Disposition readXml(XmlReader xr) { List messages = new List(); if (!xr.IsEmptyElement) { while (xr.Read()) { if (xr.NodeType == XmlNodeType.Element) { if (xr.Name.Equals(_xml_MessageTag)) { messages.Add(xr.ReadElementContentAsString()); } else { throw new Exception("Unrecognized Disposition::Failed tag " + xr.Name); } } else if (xr.NodeType == XmlNodeType.EndElement) { Util.Assert(xr.Name.Equals(Disposition._xml_tag)); break; } } } Failed f = new Failed(); f.messages = messages; return f; } public void AddError(string msg) { this.messages.Add(msg); } public override string ToString() { return Failed.Value; } public override IEnumerable getMessages() { return this.messages; } protected override void writeXmlExtend(XmlWriter xw) { foreach (string message in this.messages) { xw.WriteStartElement(_xml_MessageTag); xw.WriteString(message); xw.WriteEndElement(); } } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/EntryStitcherVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; using System.Linq; internal class EntryStitcherVerb : Verb { private const int version = 10; private const string SENTINEL_APP_SPECIFIC_GOES_HERE = "//- SENTINEL_APP_SPECIFIC_GOES_HERE"; private string appLabel; private IContextGeneratingVerb context; // Label our abstractIdentifier private BeatVerb mainBeatVerb; private SourcePath genericStitch; private SourcePath appSpecificStitch; private BuildObject dafnyMainImpInput; private BuildObject dafnyMainIfcInput; private SourcePath entryImpInput; public EntryStitcherVerb(IContextGeneratingVerb context, string appLabel) { this.appLabel = appLabel; this.context = context; this.entryImpInput = new SourcePath("src\\Checked\\Nucleus\\Main\\Entry.imp.beat"); SourcePath mainBeatSrc = new SourcePath("src\\Checked\\Nucleus\\Main\\Main.ifc.beat"); this.mainBeatVerb = new BeatVerb(context, mainBeatSrc, appLabel); this.genericStitch = new SourcePath("src\\Trusted\\Spec\\Entry.ifc.basm.stitch"); this.appSpecificStitch = new SourcePath(string.Format("src\\Trusted\\Spec\\{0}\\AppRequirements.ifc.stitch", appLabel)); } public override AbstractId getAbstractIdentifier() { return new AbstractId(this.GetType().Name, version, this.genericStitch.ToString(), concrete: this.appLabel); } public override IEnumerable getDependencies(out DependencyDisposition ddisp) { ddisp = DependencyDisposition.Complete; OrderPreservingSet deps = new OrderPreservingSet(); // Things we need to stitch the interface: deps.Add(this.genericStitch); deps.Add(this.appSpecificStitch); deps.AddRange(this.mainBeatVerb.getOutputs()); // Things we need to stitch the imports into the imp file: deps.Add(this.entryImpInput); deps.Add(this.context.getContextOutput()); IIncludePathContext pathContext = this.context.fetchIfAvailable(ref ddisp); if (pathContext != null) { this.dafnyMainIfcInput = pathContext.search("dafny_Main_i", ModPart.Ifc); Util.Assert(this.dafnyMainIfcInput != null); deps.Add(this.dafnyMainIfcInput); this.dafnyMainImpInput = pathContext.search("dafny_Main_i", ModPart.Ifc); Util.Assert(this.dafnyMainImpInput != null); deps.Add(this.dafnyMainImpInput); } return deps; } public override IEnumerable getVerbs() { return new IVerb[] { this.mainBeatVerb, this.context }; } public override IEnumerable getOutputs() { return new BuildObject[] { this.getIfcOutput(), this.getEntryImpOutput() }; } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { // Mimic this line from src\Checked\Nucleus\Main\build.ps1: // _cat -out $OBJ\EntryCP_i.bpl -in $OBJ\MainCP_i.bpl,$SPEC_OBJ\EntryCP_i.bpl // TODO: eliminate this special-case workaround. try { // This is the trusted bit, creating the stitched ifc file. ////IEnumerable ifcImports = extractImportStatements(dafnyMainIfcInput); string[] mainLines = File.ReadAllLines(workingDirectory.PathTo(this.mainBeatVerb.getOutputs().First())); string[] entryLines = File.ReadAllLines(workingDirectory.PathTo(this.genericStitch)); int sentinel_index = Array.IndexOf(entryLines, SENTINEL_APP_SPECIFIC_GOES_HERE); if (sentinel_index < 0) { throw new UserError("Sentinel string missing in " + this.genericStitch); } IEnumerable entryPrologue = entryLines.Take(sentinel_index + 1); IEnumerable entryEpilogue = entryLines.Skip(sentinel_index + 1); string[] appSpecificLines = File.ReadAllLines(workingDirectory.PathTo(this.appSpecificStitch)); ////File.WriteAllLines(getIfcOutput().getFilesystemPath(), ifcImports.Concat(mainLines.Concat(entryLines))); File.WriteAllLines( workingDirectory.PathTo(this.getIfcOutput()), mainLines.Concat(entryPrologue).Concat(appSpecificLines).Concat(entryEpilogue)); // Here's some (at least untrusted) workaround, snarfing and repurposing the // import list from dafny_Main_i up to Entry.imp. IEnumerable impImports = extractImportStatements(workingDirectory, this.dafnyMainImpInput); string[] intext = File.ReadAllLines(workingDirectory.PathTo(this.entryImpInput)); File.WriteAllLines(workingDirectory.PathTo(this.getEntryImpOutput()), impImports.Concat(intext)); return new VerbSyncWorker(workingDirectory, new Fresh()); } catch (IOException ex) { return new VerbSyncWorker(workingDirectory, new Failed(ex.ToString())); } } // We also have to stitch the imp, to borrow the private-import list from dafny_Main. internal BuildObject getEntryImpOutput() { return new SourcePath("src\\Checked\\Nucleus\\Main\\EntryStitched.x").makeLabeledOutputObject(this.appLabel, BeatExtensions.BEATIMP_EXTN); } private static IEnumerable extractImportStatements(WorkingDirectory workingDirectory, BuildObject obj) { // Well, it might be nice to use BeatExtensions.propagatePrivateImports, but that requires // a context to interpret the input imports. We don't really want to cons up yet ANOTHER // intermediate context, so here's a temporary workaround. Caution; may be brittle. IEnumerable imports = File.ReadAllLines(workingDirectory.PathTo(obj)) .Where(line => line.Contains("private-import")); // Note that dafny_Main_i didn't really expect us to steal its // imports, so it hasn't conditioned the Checked and Trusted imports to be beat-resistant. imports = imports.Select( line => line.Contains("Checked") || line.Contains("Trusted") ? line.Replace("private-import", "private-basmonly-import") : line); return imports; } private BuildObject getIfcOutput() { // TODO will probably require parameterization per app return new SourcePath("src\\Trusted\\Spec\\EntryStitched.x").makeLabeledOutputObject(this.appLabel, BoogieAsmVerifyVerb.BASMIFC_EXTN); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/Hasher.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; /// /// Strange mixture of hash-related functionality and a /// mapping from build objects to the verbs that created them? /// Actually, looks like everything here would more appropriately be elsewhere. /// DONE: Move outputToVerbMap to Scheduler. /// DONE: Move marshalledFilesystemPaths to Repository. /// TODO: Move contextResolutionCache to boogie/asm something or other. /// TODO: Move parsedIncludesCache to BeatIncludes? /// internal class Hasher : IHasher { private CachedHash, BuildObject> contextResolutionCache; private CachedHash, List> parsedIncludesCache; public Hasher() { this.contextResolutionCache = new CachedHash, BuildObject>( delegate(Tuple key) { return key.Item1.search(key.Item2, key.Item3); }); this.parsedIncludesCache = new CachedHash, List>( delegate(Tuple key) { return BeatIncludes.parseLabeledIncludes(key.Item1, key.Item2); }); } public BuildObject search(IIncludePathContext context, string modName, ModPart modPart) { return this.contextResolutionCache.get(new Tuple(context, modName, modPart)); } public List getParsedIncludes(IIncludePathContext context, BuildObject beatsrc) { return this.parsedIncludesCache.get(new Tuple(context, beatsrc)); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/IAsmProducer.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; internal interface IAsmProducer : IVerb { BuildObject getAsmFile(); } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/IContextGeneratingVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; internal interface IContextGeneratingVerb : IVerb { string getContextIdentifier(); PoundDefines getPoundDefines(); BuildObject getContextOutput(); } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/IHasher.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; /// /// REVIEW: Why is this an interface? /// internal interface IHasher { BuildObject search(IIncludePathContext context, string modName, ModPart modPart); List getParsedIncludes(IIncludePathContext context, BuildObject beatsrc); } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/IIncludeFactory.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; internal interface IIncludeFactory { IEnumerable getIncludes(BuildObject path); } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/IIncludePathContext.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; internal interface IIncludePathContext { BuildObject search(string basename, ModPart modPart = ModPart.Ifc); } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/IItemCache.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; /// /// Enumeration of the containers in the item cache. /// /// /// Important: The names of the values in the enumeration below become the /// actual names of the item cache containers. For the Azure blob backing /// store, this means they must be a valid DNS name (i.e. may ONLY be /// comprised of letters, numbers and the dash ('-') character). /// public enum ItemCacheContainer { /// /// Item cache container for source files. /// Sources = 0, /// /// Item cache container for object files. /// Objects = 1, /// /// Item cache container for (successful) result records. /// Results = 2, /// /// Item cache container for unsuccessful result records. /// FailedResults = 3 } /// /// Definition of the interface to the item cache. /// public interface IItemCache { /// /// Gets a human-readable name for this item cache implementation. /// string Name { get; } /// /// Copies the given item from the cache to a new byte array. /// /// /// Identifier for the cache container holding the item. /// /// /// Hash key for the desired item. /// /// A byte array containing a copy of the item. byte[] FetchItem( ItemCacheContainer container, string itemHash); /// /// Copies the given item from the cache to the given location in the /// local file system. /// /// /// Identifier for the cache container holding the item. /// /// /// Hash key for the desired item. /// /// /// Location in the local file system to copy the item. /// void FetchItemToFile( ItemCacheContainer container, string itemHash, string localFilesystemDestinationPath); /// /// Copies the given byte array to the desired cache item. /// /// /// Identifier for the cache container to hold the item. /// /// /// Hash key for the item. /// /// Byte array containing the item. void StoreItem( ItemCacheContainer container, string itemHash, byte[] contents); /// /// Copies the given file from the local file system into the cache. /// /// /// Identifier for the cache container to hold the item. /// /// /// Hash key for the item. /// /// /// Location in the local file system from which to source the item. /// void StoreItemFromFile( ItemCacheContainer container, string itemHash, string localFilesystemSourcePath); /// /// Deletes an item from the cache. /// /// /// Identifier for the cache container holding the item. /// /// /// Hash key for the desired item. /// void DeleteItem( ItemCacheContainer container, string itemHash); /// /// Gets a HashSet containing the hash keys of all the items in the /// given container. /// /// Identifier for the cache container. /// A HashSet containing the hash keys. HashSet GetItemsInContainer( ItemCacheContainer container); /// /// Gets the size of the item. /// Returns -1 if the item is absent. /// /// /// Identifier for the cache container holding the item. /// /// /// Hash key for the desired item. /// /// Size of the item in bytes, or -1 if item is absent. long GetItemSize( ItemCacheContainer container, string itemHash); /// /// Gets the last-modified time of the item. /// /// /// Identifier for the cache container holding the item. /// /// /// Hash key for the desired item. /// /// A DateTimeOffset containing the item's last-modified time. DateTimeOffset? GetItemLastModifiedTime( ItemCacheContainer container, string itemHash); } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/IObligationsProducer.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; internal interface IObligationsProducer : IVerb { BuildObject getObligationSet(); ////BuildObject getIdentifier(); } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/IProcessInvokeAsyncVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; /// /// Interface that verbs which use ProcessInvokeAsyncWorker as their /// VerbWorker must provide (for callbacks from same). /// internal interface IProcessInvokeAsyncVerb : IVerb { /// /// Records the CPU time used by the async worker process. /// /// The CPU time used. void RecordProcessInvokeCpuTime(double cpuTimeSeconds); /// /// Performs any required post-processing and/or cleanup of the /// results of the async worker process. /// /// /// The private working directory the verb executed in. /// /// /// CPU time used by async process. /// /// /// Standard out from async process (if requested). /// /// /// Standard error from async process (if requested). /// /// /// The disposition of the async process. /// /// /// The ultimate disposition of the worker activity. /// Disposition Complete(WorkingDirectory workingDirectory, double cpuTimeSeconds, string stdout, string stderr, Disposition disposition); } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/IProcessInvoker.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { /// /// Definition of the interface to local and cloud process invokers. /// internal interface IProcessInvoker { /// /// Gets the exit code returned by the process. /// int ExitCode { get; } /// /// Gets the CPU time used by the process, in seconds. /// double CpuTime { get; } /// /// Gets the process's standard output in the default case. /// Does not return the standard output if it is redirected to a file (i.e. if CaptureStdout is non-null). /// /// The process's standard output. string GetStdout(); /// /// Gets the process's standard error output. /// /// The process's standard error output. string GetStderr(); } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/IRejectable.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; internal interface IRejectable { bool resultWasRejectableFailure(); } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/IVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Xml; /// /// Definition of the interface to Verbs. /// internal interface IVerb : IComparable { /// /// Gets a possibly-incomplete list of things we depend on. /// /// /// When the list is complete, it should cover every BuildObject /// this verb can see when running its worker's methods. /// That means that it's not safe, for example, to say /// "I only depend on my .exe and DafnyTransitiveDepsVerb(root).obj()". /// One might think so, since the Freshness of the latter implies that /// every object this verb needs is Fresh, but that doesn't convey /// what BuildObjects need to (potentially) be transmitted remotely for /// running the verb's worker's methods on a remote machine. /// /// It should also cover any buildObjects needed to complete the list. /// That is, if the verb depends on a .tdep, and that .tdep is incomplete, /// the list should include that .tdep's partial dependency list, so /// the scheduler can figure out how to get it done. /// /// The returned DependencyDisposition. /// /// A collection of build objects this verb depends upon. /// IEnumerable getDependencies(out DependencyDisposition ddisp); /// /// Gets a list of the verbs that can build the dependencies visible to /// getDependencies. May return an incomplete list if getDependencies /// is incomplete. /// /// /// A collection of verbs that can build this verb's dependencies. /// IEnumerable getVerbs(); /// /// Gets a list of the build objects this verb generates upon successful /// execution. /// /// /// getOutputs is only meaningful once getDependencies indicates /// a complete disposition. The set of outputs doesn't change. /// /// A collection of build objects built by this verb. IEnumerable getOutputs(); /// /// Gets the list of BuildObjects this verb generates containing /// diagnostic information. Diagnostics are never used as inputs /// by other verbs; they are only for the user's inspection. /// TODO: Rename to getDiagnosticOutputs(). /// /// The collection of diagnostic BuildObjects. IEnumerable getFailureOutputs(); /// /// Gets an identifier that describes the verb up to differences in /// input. /// /// /// This method must always be evaluable. /// Example: /// DafnyVerifyOneVerb(SourcePath("src\\foo\\bar.dfy")) /// /// A unique identifier for the abstract verb. AbstractId getAbstractIdentifier(); /// /// Gets a worker for this verb that performs this verb's work. /// /// /// Working directory to use for this verb's execution. /// /// A worker for this verb instance. IVerbWorker getWorker(WorkingDirectory workingDirectory); /// /// Gets a structured form of output UI for informing the user what /// happened. /// /// Something to present to the user. Presentation getPresentation(); /// /// Gets a structured form of output UI for informing the user what is /// currently happening. /// /// /// The disposition of this verb's worker. /// /// Something to present to the user. Presentation getRealtimePresentation(Disposition disposition); /// /// Writes an XML representation of this verb's CPU usage using the /// provided XmlWriter. /// /// /// The XmlWriter to use to write the XML. /// void writeTimingXml(XmlWriter xmlWriter); /// /// Writes an XML representation of this verb's internal state /// (for debugging purposes) using the provided XmlWriter. /// /// /// The XmlWriter to use to write the XML. /// void writeDebugXml(XmlWriter xmlWriter); } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/IVerbWorker.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { /// /// Enumeration of the verb worker types: synchronous and asynchronous. /// /// /// REVIEW: Couldn't this just be a boolean? /// internal enum VerbWorkerType { /// /// The worker runs synchronously. /// Sync, /// /// The worker runs asynchronously. /// Async } /// /// Enumeration of the ways to treat process exit codes. /// /// /// REVIEW: Couldn't this just be a boolean? /// internal enum ProcessExitCodeHandling { /// /// Treat non-zero return codes as the process reporting a failure. /// NonzeroIsFailure, /// /// Ignore non-zero return codes from the process. /// NonzeroIsOkay } /// /// Definition of the interface to Verb workers. /// /// /// The scheduler's VerbRunner component uses this interface to /// run verbs (both synchronous and asynchronous verbs). /// internal interface IVerbWorker { /// /// Indicates whether this work needs to be scheduled asynchronously. /// If it returns Sync, the runAsync method will not be called. /// /// Sync for synchronous verbs, Async otherwise. VerbWorkerType IsSync(); /// /// Gets the private working directory this verb executes in. /// /// The directory this verb executes in. WorkingDirectory GetWorkingDirectory(); /// /// Performs the slow, asynchronous work. /// /// /// Does not run on the main thread, so should not access caches /// (or do anything else that expects to be synchronous). /// void RunAsync(); /// /// Performs the completion work for Async workers, and is called /// after the runAsync method returns. For Sync workers, it performs /// all the work not done by the getWorker call. /// /// /// This method runs synchronously on the main thread. REVIEW: Not true /// for Async workers! It runs under lock, but on separate thread. /// It can tidy up the state after async work, and store results /// in the Repository. /// This method must not return the Stale Disposition; once completed /// a verb is either Fresh or Failed. /// /// The disposition of this verb's worker's work. Disposition Complete(); } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/IVerificationResultParser.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; internal interface IVerificationResultParser { void parseOutput( string s, out int parseFailures, out int verificationFailures, out int timeouts); } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/IncludePathContext.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; internal abstract class IncludePathContext : IIncludePathContext { public abstract BuildObject search(string basename, ModPart modPart = ModPart.Ifc); public override int GetHashCode() { return ToString().GetHashCode(); } public override bool Equals(object obj) { return ToString().Equals(obj.ToString()); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/IronRootDirectory.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.IO; /// /// A directory tree in the local filesystem to fetch sources from. /// Used to identify and isolate accesses to things under iron root. /// internal static class IronRootDirectory { /// /// Gets the absolute path to the given build object under IronRoot. /// /// A build object. /// The absolute path to the build object. public static string PathTo(BuildObject obj) { return Path.Combine(BuildEngine.theEngine.getIronRoot(), obj.getRelativePath()); } /// /// Gets the absolute path corresponding to the given relative path under IronRoot. /// /// Relative path to convert. /// The absolute path corresponding to the given relative path. public static string PathTo(string relativePath) { return Path.Combine(BuildEngine.theEngine.getIronRoot(), relativePath); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/IroncladAppVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; using System.Linq; internal class IroncladAppVerb : Verb, IObligationsProducer { public const string TRUSTED_EXE_EXTN = ".exe"; public const string UNVERIFIED_SENTINEL_EXTENSION = ".usentinel"; private const int version = 5; ////public enum VerifyMode { Verify, NoVerify }; ////public enum SymDiffMode { UseSymDiff, NoSymDiff }; private SourcePath dfyroot; // REVIEW: Never used? private AbstractId abstractId; private DafnySpecVerb dafnyspecVerb; private DafnyCCVerb dafnyccVerb; private EntryStitcherVerb stitcherVerb; private VerificationResultSummaryVerb verifyResultsVerb; private LinkerVerb linkerVerb; private PoundDefines poundDefines; private VerificationRequest verificationRequest; private string appLabel; private BuildObject srcObject; private BuildObject exeObject; private BuildObject outputObject; public IroncladAppVerb(SourcePath dfyroot, TARGET target, DafnyCCVerb.FramePointerMode framePointerMode, VerificationRequest verificationRequest) { this.dfyroot = dfyroot; // TODO this is the only #define we support just yet, so I'm stuffing it in here. // We'll need to plumb more carefully when we want to add x64. if (dfyroot.getDirPath().Split(Path.DirectorySeparatorChar).Last().Equals("AppLoader")) { this.poundDefines = new PoundDefines(new string[] { "AppLoader" }); } else { this.poundDefines = PoundDefines.empty(); } this.verificationRequest = verificationRequest; this.abstractId = new AbstractId( this.GetType().Name, version, dfyroot.ToString(), this.poundDefines, concrete: string.Format( "{0},{1},{2}", target, framePointerMode.ToString(), verificationRequest.ToString())); this.appLabel = dfyroot.getDirPath().Split(Path.DirectorySeparatorChar).Last(); this.dafnyspecVerb = new DafnySpecVerb(dfyroot, this.appLabel); this.dafnyccVerb = new DafnyCCVerb(dfyroot, this.appLabel, framePointerMode); bool isLoader = dfyroot.getRelativePath().Equals(BootableAppVerb.LOADER_DFY); // NB we keep dafnyccVerb as the lowest-priority context, so that our hand-written // beat impls will override its output. IContextGeneratingVerb contextWithDafny = new ConcatContextVerb( BuildEngine.theEngine.getVerveContextVerb(this.poundDefines), new VerbOutputsContextVerb(this.dafnyspecVerb, false), new VerbOutputsContextVerb(this.dafnyccVerb, true), this.poundDefines); this.stitcherVerb = new EntryStitcherVerb(contextWithDafny, this.appLabel); IContextGeneratingVerb contextWithDafnyAndEntry = new ConcatContextVerb( new VerbOutputsContextVerb(this.stitcherVerb, false), contextWithDafny, this.poundDefines); BuildObject entryImpObj = this.stitcherVerb.getEntryImpOutput(); BoogieAsmLinkVerb entryVerb = new BoogieAsmLinkVerb(contextWithDafnyAndEntry, entryImpObj); if (target == TARGET.BARE_METAL) { MasmVerb masmVerb = new MasmVerb(entryVerb); this.linkerVerb = new LinkerVerb(masmVerb, isLoader); } else if (target == TARGET.WINDOWS) { // Rewrite the asm that comes out of entryVerb before linking it AsmRewriterVerb rewriter = new AsmRewriterVerb(entryVerb); MasmVerb masmVerb = new MasmVerb(rewriter); this.linkerVerb = new WinLinkerVerb(masmVerb, isLoader); } BoogieAsmVerificationObligationListVerb bavolVerb = new BoogieAsmVerificationObligationListVerb(contextWithDafnyAndEntry, entryImpObj, verificationRequest); this.verifyResultsVerb = new VerificationResultSummaryVerb(bavolVerb); this.srcObject = this.linkerVerb.getUntrustedExe(); if (verificationRequest.isComplete()) { this.exeObject = dfyroot.makeOutputObject(TRUSTED_EXE_EXTN); this.outputObject = this.exeObject; } else { this.exeObject = this.srcObject; this.outputObject = dfyroot.makeVirtualObject(UNVERIFIED_SENTINEL_EXTENSION); } } public enum TARGET { BARE_METAL, WINDOWS } public override IEnumerable getDependencies(out DependencyDisposition ddisp) { List result = new List(); result.Add(this.srcObject); result.Add(this.verifyResultsVerb.getOutputFile()); ddisp = DependencyDisposition.Complete; return result; } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { if (this.verificationRequest.isComplete()) { // If the verification succeeded, then we convert the untrusted exe into a trusted exe (via a copy). VerificationResult vr = VerificationResult.fromXmlFile(this.verifyResultsVerb.getOutputFile()); if (!vr.pass) { return new VerbSyncWorker(workingDirectory, new Failed()); } File.Copy(workingDirectory.PathTo(this.srcObject), workingDirectory.PathTo(this.outputObject), true); // True => Overwrite } else { UnverifiedSentinelVirtualContents contents = new UnverifiedSentinelVirtualContents(); BuildEngine.theEngine.Repository.StoreVirtual(this.outputObject, new Fresh(), contents); } return new VerbSyncWorker(workingDirectory, new Fresh()); } public override IEnumerable getVerbs() { List result = new List(); result.Add(this.dafnyccVerb); result.Add(this.stitcherVerb); result.Add(this.linkerVerb); result.Add(this.verifyResultsVerb); result.AddRange(this.verifyResultsVerb.getVerbs()); // Sleazy. return result; } public override IEnumerable getOutputs() { return new BuildObject[] { this.outputObject }; } public BuildObject getObligationSet() { return this.verifyResultsVerb.getObligationSet(); } public override AbstractId getAbstractIdentifier() { return this.abstractId; } public BuildObject getExe() { return this.exeObject; } public override Presentation getPresentation() { return this.verifyResultsVerb.getPresentation(); } public string getAppLabel() { return this.appLabel; } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/IronfleetAppVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; /// /// Verb to build an Ironfleet application. /// This is a top-level verb. /// internal class IronfleetAppVerb : Verb, IObligationsProducer { private const int Version = 7; private const string UnverifiedExeExt = ".unverified.exe"; private const string VerifiedExeExt = ".exe"; private readonly BuildObject input; private readonly BuildObject exeOutput; private readonly List otherOutputs; private readonly AbstractId abstractId; private readonly VerificationResultSummaryVerb verifyVerb; private readonly VSSolutionVerb buildVerb; private readonly IVerb[] verbs; private List dependencies; /// /// Initializes a new instance of the IronfleetAppVerb class. /// /// Main dafny file for the application. public IronfleetAppVerb(SourcePath input, VerificationRequest verificationRequest, bool releaseBuild = false) { if (input == null) { throw new ArgumentNullException("input"); } this.abstractId = new AbstractId(GetType().Name, Version, input.ToString() + verificationRequest.ToString()); this.input = input; this.buildVerb = new VSSolutionVerb(new SourcePath(@"src\IronfleetTestDriver\IronfleetTestDriver.sln"), input, releaseBuild); if (verificationRequest.verifyMode == VerificationRequest.VerifyMode.NoVerify) { this.exeOutput = this.input.makeOutputObject(UnverifiedExeExt); this.verifyVerb = null; this.verbs = new IVerb[] { this.buildVerb }; } else { this.exeOutput = this.input.makeOutputObject(VerifiedExeExt); this.verifyVerb = new VerificationResultSummaryVerb(new DafnyVerifyTreeVerb(input)); this.verbs = new IVerb[] { this.verifyVerb, this.buildVerb }; } this.otherOutputs = new List(); var ohs = this.buildVerb.getOutputs().ToList(); ohs.RemoveAll(o => o.getExtension() == ".exe"); foreach (var o in ohs) { this.otherOutputs.Add(RelocateBuildObjectToExeDirectory(o)); } } private BuildObject RelocateBuildObjectToExeDirectory(BuildObject sourceOb) { return new BuildObject(exeOutput.getDirPath() + "\\" + sourceOb.getFileName()); } public override IEnumerable getDependencies(out DependencyDisposition ddisp) { if (this.dependencies == null) { var dependencies = new List(); // Select and append results returned from verb.getDependencies() to dependencies. // If the dependency disposition is ever reported as not complete, we reflect this through to the caller. dependencies.AddRange(this.verbs.SelectMany(verb => verb.getOutputs())); this.dependencies = dependencies; } Trace.Assert(this.dependencies != null); ddisp = DependencyDisposition.Complete; return this.dependencies; } public override IEnumerable getVerbs() { return this.verbs; } public override IEnumerable getOutputs() { var result = new List { this.exeOutput }; result.AddRange(this.otherOutputs); return result; } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { Disposition disposition = new Fresh(); if (this.verifyVerb != null) { VerificationResult verificationResult = VerificationResult.fromXmlFile(this.verifyVerb.getOutputs().Single()); if (!verificationResult.pass) { disposition = new Failed(); } } if (!(disposition is Failed)) { foreach (var o in this.buildVerb.getOutputs()) { if (o.getExtension() == ".exe") { File.Copy(workingDirectory.PathTo(o), workingDirectory.PathTo(this.exeOutput), overwrite: true); } else { var dest = this.RelocateBuildObjectToExeDirectory(o); File.Copy( workingDirectory.PathTo(o), workingDirectory.PathTo(dest), overwrite: true); } } } return new VerbSyncWorker(workingDirectory, disposition); } public override AbstractId getAbstractIdentifier() { return this.abstractId; } public Disposition Complete(WorkingDirectory workingDirectory, double cpuTimeSeconds, string stdout, string stderr, Disposition disposition) { return disposition; } public BuildObject getObligationSet() { return this.verifyVerb.getObligationSet(); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/ItemCacheCloud.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Configuration; using System.Globalization; using System.IO; using Microsoft.WindowsAzure.Storage; using Microsoft.WindowsAzure.Storage.Blob; /// /// An implementation of the item cache that uses Azure blobs as the /// backing store. /// public class ItemCacheCloud : IItemCache { /// /// Azure storage account we're using. /// private readonly CloudStorageAccount storageAccount; /// /// Blob client object for working with blobs. /// private readonly CloudBlobClient blobClient; /// /// Array of blob containers corresponding to item cache containers. /// private readonly CloudBlobContainer[] cloudContainers; /// /// Initializes a new instance of the ItemCacheCloud class. /// public ItemCacheCloud() { // - // Create our CloudStorageAccount object. // REVIEW: Hard-coded connection string index "Ironclad". // - string connectionString = null; ConnectionStringSettings settings = ConfigurationManager.ConnectionStrings["Ironclad"]; if (settings != null) { connectionString = settings.ConnectionString; } if (string.IsNullOrEmpty(connectionString)) { throw new ConfigurationException("Azure connection string missing from your NuBuild.exe.config file!"); } this.storageAccount = CloudStorageAccount.Parse(connectionString); // - // Create our CloudBlobClient object. // - this.blobClient = this.storageAccount.CreateCloudBlobClient(); // - // Set up the blob storage containers. // - Array containers = Enum.GetValues(typeof(ItemCacheContainer)); this.cloudContainers = new CloudBlobContainer[containers.Length]; foreach (ItemCacheContainer container in containers) { CloudBlobContainer cloudContainer = this.blobClient.GetContainerReference(container.ToString().ToLower(CultureInfo.InvariantCulture)); cloudContainer.CreateIfNotExists(); this.cloudContainers[(int)container] = cloudContainer; } } /// /// Gets a human-readable name for this item cache implementation. /// public string Name { get { return "Cloud"; } } /// /// Copies the given item from the cache to a new byte array. /// /// /// Identifier for the cache container holding the item. /// /// /// Hash key for the desired item. /// /// A byte array containing a copy of the item. public byte[] FetchItem( ItemCacheContainer container, string itemHash) { CloudBlockBlob cloudBlob = this.cloudContainers[(int)container].GetBlockBlobReference(itemHash); if (!cloudBlob.Exists()) { return null; } using (MemoryStream memoryStream = new MemoryStream()) { cloudBlob.DownloadToStream(memoryStream); return memoryStream.ToArray(); } } /// /// Copies the given item from the cache to the given location in the /// local file system. /// /// /// Identifier for the cache container holding the item. /// /// /// Hash key for the desired item. /// /// /// Location in the local file system to copy the item. /// public void FetchItemToFile( ItemCacheContainer container, string itemHash, string localFilesystemDestinationPath) { CloudBlockBlob cloudBlob = this.cloudContainers[(int)container].GetBlockBlobReference(itemHash); try { cloudBlob.DownloadToFile(localFilesystemDestinationPath, FileMode.Create); } catch (Microsoft.WindowsAzure.Storage.StorageException) { throw new ObjectMissingFromCacheException(itemHash, "Item missing from cloud cache."); } } /// /// Copies the given byte array to the desired cache item. /// /// /// Identifier for the cache container to hold the item. /// /// /// Hash key for the item. /// /// /// Byte array containing the item. /// public void StoreItem( ItemCacheContainer container, string itemHash, byte[] contents) { CloudBlockBlob cloudBlob = this.cloudContainers[(int)container].GetBlockBlobReference(itemHash); cloudBlob.UploadFromByteArray(contents, 0, contents.Length); } /// /// Copies the given file from the local file system into the cache. /// /// /// Identifier for the cache container to hold the item. /// /// /// Hash key for the item. /// /// /// Location in the local file system from which to source the item. /// public void StoreItemFromFile( ItemCacheContainer container, string itemHash, string localFilesystemSourcePath) { CloudBlockBlob cloudBlob = this.cloudContainers[(int)container].GetBlockBlobReference(itemHash); cloudBlob.UploadFromFile(localFilesystemSourcePath, FileMode.Open); } /// /// Deletes an item from the cache. /// /// /// Identifier for the cache container holding the item. /// /// /// Hash key for the desired item. /// public void DeleteItem( ItemCacheContainer container, string itemHash) { CloudBlockBlob cloudBlob = this.cloudContainers[(int)container].GetBlockBlobReference(itemHash); cloudBlob.DeleteIfExists(); } /// /// Gets a HashSet containing the hash keys of all the items in the /// given container. /// /// Identifier for the cache container. /// A HashSet containing the hash keys. public HashSet GetItemsInContainer(ItemCacheContainer container) { HashSet itemHashes = new HashSet(); foreach (CloudBlockBlob item in this.cloudContainers[(int)container].ListBlobs(null, true)) { itemHashes.Add(item.Name); } return itemHashes; } /// /// Gets the size of the item. /// Returns -1 if the item is absent. /// /// /// Identifier for the cache container holding the item. /// /// /// Hash key for the desired item. /// /// Size of the item in bytes, or -1 if item is absent. public long GetItemSize( ItemCacheContainer container, string itemHash) { CloudBlockBlob cloudBlob = this.cloudContainers[(int)container].GetBlockBlobReference(itemHash); if (cloudBlob.Exists()) { return cloudBlob.Properties.Length; } return -1; } /// /// Gets the last-modified time of the item. /// /// /// Identifier for the cache container holding the item. /// /// /// Hash key for the desired item. /// /// A DateTimeOffset containing the item's last-modified time. public DateTimeOffset? GetItemLastModifiedTime( ItemCacheContainer container, string itemHash) { CloudBlockBlob cloudBlob = this.cloudContainers[(int)container].GetBlockBlobReference(itemHash); if (cloudBlob.Exists()) { return cloudBlob.Properties.LastModified; } return null; } /// /// Checks whether the specified item exists in the cache. /// /// /// Identifier for the cache container holding the item. /// /// /// Hash key for the desired item. /// /// /// True if the specified item is in the cache, false otherwise. /// public bool ItemExists( ItemCacheContainer container, string itemHash) { CloudBlockBlob cloudBlob = this.cloudContainers[(int)container].GetBlockBlobReference(itemHash); return cloudBlob.Exists(); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/ItemCacheLocal.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; using System.Threading; /// /// An implementation of the item cache that uses the local file system /// as the backing store. /// public class ItemCacheLocal : IItemCache { /// /// Array of local file system paths corresponding to item cache /// containers. /// private readonly string[] localPaths; /// /// Lock protecting local file system state from concurrent accesses. /// private object cacheLock; /// /// Initializes a new instance of the ItemCacheLocal class. /// /// /// Generates local path names corresponding to the various item cache /// containers, and creates local directories for each, if they don't /// already exit. /// /// Root of the local cache. public ItemCacheLocal(string localCacheDirectory) { // - // Set up the local "container" directories and paths to them. // - Array containers = Enum.GetValues(typeof(ItemCacheContainer)); this.localPaths = new string[containers.Length]; foreach (ItemCacheContainer container in containers) { string directory = Path.Combine( localCacheDirectory, container.ToString()); this.localPaths[(int)container] = directory; Directory.CreateDirectory(directory); } this.cacheLock = new object(); } /// /// Gets a human-readable name for this item cache implementation. /// public string Name { get { return "Local"; } } /// /// Copies the given item from the cache to a new byte array. /// /// /// Identifier for the cache container holding the item. /// /// /// Hash key for the desired item. /// /// A byte array containing a copy of the item. public byte[] FetchItem( ItemCacheContainer container, string itemHash) { string itemPath = this.ItemPath(container, itemHash); lock (this.cacheLock) { if (!File.Exists(itemPath)) { return null; } return File.ReadAllBytes(itemPath); } } /// /// Copies the given item from the cache to the given location in the /// local file system. /// /// /// This method is a performance optimization over getting a readable /// stream for the item and copying it to a local file using CopyTo(). /// /// /// Identifier for the cache container holding the item. /// /// /// Hash key for the desired item. /// /// /// Location in the local file system to copy the item. /// public void FetchItemToFile( ItemCacheContainer container, string itemHash, string localFilesystemDestinationPath) { lock (this.cacheLock) { try { Directory.CreateDirectory(Path.GetDirectoryName(localFilesystemDestinationPath)); File.Copy(this.ItemPath(container, itemHash), localFilesystemDestinationPath, true); } catch (FileNotFoundException) { throw new ObjectMissingFromCacheException(itemHash, "Item missing from local cache."); } } } /// /// Copies the given byte array to the desired cache item. /// /// /// Identifier for the cache container to hold the item. /// /// /// Hash key for the item. /// /// /// Byte array containing the item. /// public void StoreItem( ItemCacheContainer container, string itemHash, byte[] contents) { string itemPath = this.ItemPath(container, itemHash); lock (this.cacheLock) { File.Delete(itemPath); File.WriteAllBytes(itemPath, contents); } } /// /// Copies the given file from the local file system into the cache. /// /// /// Identifier for the cache container to hold the item. /// /// /// Hash key for the item. /// /// /// Location in the local file system from which to source the item. /// public void StoreItemFromFile( ItemCacheContainer container, string itemHash, string localFilesystemSourcePath) { string itemPath = this.ItemPath(container, itemHash); lock (this.cacheLock) { File.Delete(itemPath); File.Copy(localFilesystemSourcePath, itemPath); } } /// /// Gets a HashSet containing the hash keys of all the items in the /// given container. /// /// Identifier for the cache container. /// A HashSet containing the hash keys. public HashSet GetItemsInContainer(ItemCacheContainer container) { HashSet itemHashes = new HashSet(); foreach (string filename in Directory.EnumerateFiles(this.localPaths[(int)container])) { itemHashes.Add(Path.GetFileName(filename)); } return itemHashes; } /// /// Deletes an item from the cache. /// /// /// Identifier for the cache container holding the item. /// /// /// Hash key for the desired item. /// public void DeleteItem( ItemCacheContainer container, string itemHash) { lock (this.cacheLock) { File.Delete(this.ItemPath(container, itemHash)); } } /// /// Gets the size of the item. /// Returns -1 if the item is absent. /// /// /// Identifier for the cache container holding the item. /// /// /// Hash key for the desired item. /// /// Size of the item in bytes, or -1 if item is absent. public long GetItemSize( ItemCacheContainer container, string itemHash) { lock (this.cacheLock) { FileInfo fileInfo = new FileInfo(this.ItemPath(container, itemHash)); if (fileInfo.Exists) { return fileInfo.Length; } return -1; } } /// /// Gets the last-modified time of the item. /// /// /// Identifier for the cache container holding the item. /// /// /// Hash key for the desired item. /// /// A DateTimeOffset containing the item's last-modified time. public DateTimeOffset? GetItemLastModifiedTime( ItemCacheContainer container, string itemHash) { lock (this.cacheLock) { FileInfo fileInfo = new FileInfo(this.ItemPath(container, itemHash)); if (fileInfo.Exists) { return fileInfo.CreationTimeUtc; } return null; } } /// /// Gets the local path name for the given item. /// /// /// Identifier for the cache container holding the item. /// /// /// Hash key for the desired item. /// /// Path for the item. private string ItemPath(ItemCacheContainer container, string itemHash) { return Path.Combine( this.localPaths[(int)container], itemHash); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/ItemCacheMultiplexer.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; /// /// An implementation of the item cache that multiplexes two other /// backing store implementations together. /// public class ItemCacheMultiplexer : IItemCache { /// /// The maximum size of items to upload to the cloud. /// private const long MaxUploadSizeThreshold = 50 * (1 << 20); /// /// The underlying local item cache implementation. /// private readonly ItemCacheLocal localCache; /// /// The underlying cloud item cache implementation. /// private readonly ItemCacheCloud cloudCache; /// /// A worker thread and queue for performing background work. /// /// /// While this is currently private to the multiplexer, /// the BackgroundWorker code is generic and could be used /// for other purposes. If that happens, we should move this /// to the main build engine. /// private readonly BackgroundWorker backgroundWorker; /// /// Initializes a new instance of the ItemCacheMultiplexer class. /// /// A local cache instance. /// A cloud cache instance. /// A background worker instance. public ItemCacheMultiplexer( ItemCacheLocal localCache, ItemCacheCloud cloudCache, BackgroundWorker backgroundWorker) { this.localCache = localCache; this.cloudCache = cloudCache; this.backgroundWorker = backgroundWorker; } /// /// Gets a human-readable name for this item cache implementation. /// public string Name { get { return "Multiplexer"; } } /// /// Copies the given item from the cache to a new byte array. /// /// /// Identifier for the cache container holding the item. /// /// /// Hash key for the desired item. /// /// A byte array containing a copy of the item. public byte[] FetchItem( ItemCacheContainer container, string itemHash) { byte[] contents; contents = this.localCache.FetchItem(container, itemHash); if (contents == null) { contents = this.cloudCache.FetchItem(container, itemHash); if (contents == null) { return null; } this.localCache.StoreItem(container, itemHash, contents); } else { // - // Schedule cloud push on successful local read. // REVIEW: Is this rare optimization really worth it? // - this.QueueItemForCloudSync(container, itemHash); } return contents; } /// /// Copies the given item from the cache to the given location in the /// local file system. /// /// /// As with GetReadableStreamForItem, we first try locally and only /// go to the cloud if needed. /// /// /// Identifier for the cache container holding the item. /// /// /// Hash key for the desired item. /// /// /// Location in the local file system to copy the item. /// public void FetchItemToFile( ItemCacheContainer container, string itemHash, string localFilesystemDestinationPath) { try { this.localCache.FetchItemToFile(container, itemHash, localFilesystemDestinationPath); // - // Schedule cloud push on successful local read. // REVIEW: Is this rare optimization really worth it? // - this.QueueItemForCloudSync(container, itemHash); } catch (ObjectMissingFromCacheException) { // - // If it is missing locally, try to retrieve it from the cloud. // Note we stash a copy in the local cache prior to copying it // to the desired local file. // - byte[] temp = this.cloudCache.FetchItem(container, itemHash); if (temp == null) { throw new ObjectMissingFromCacheException(itemHash, "Item missing from multiplexed cache."); } this.localCache.StoreItem(container, itemHash, temp); this.localCache.FetchItemToFile(container, itemHash, localFilesystemDestinationPath); } } /// /// Copies the given byte array to the desired cache item. /// /// /// Identifier for the cache container to hold the item. /// /// /// Hash key for the item. /// /// Byte array containing the item. public void StoreItem( ItemCacheContainer container, string itemHash, byte[] contents) { this.localCache.StoreItem(container, itemHash, contents); this.QueueItemForCloudSync(container, itemHash); } /// /// Copies the given file from the local file system into the cache. /// /// /// Identifier for the cache container to hold the item. /// /// /// Hash key for the item. /// /// /// Location in the local file system from which to source the item. /// public void StoreItemFromFile( ItemCacheContainer container, string itemHash, string localFilesystemSourcePath) { this.localCache.StoreItemFromFile(container, itemHash, localFilesystemSourcePath); this.QueueItemForCloudSync(container, itemHash); } /// /// Deletes an item from the cache. /// /// /// Note that our cache sync code (CheckForAndOrUploadMissingItem) /// will fail if given an item to sync, and that item is subsequently /// deleted from the local cache before the sync code gets around to /// syncing it. This method is really only intended for cache /// management purposes and not for general use. If that changes, /// the cache sync code should change as well. /// /// /// Identifier for the cache container holding the item. /// /// /// Hash key for the desired item. /// public void DeleteItem( ItemCacheContainer container, string itemHash) { this.localCache.DeleteItem(container, itemHash); this.cloudCache.DeleteItem(container, itemHash); } /// /// Gets a HashSet containing the hash keys of all the items in the /// given container. /// /// Identifier for the cache container. /// A HashSet containing the hash keys. public HashSet GetItemsInContainer(ItemCacheContainer container) { // - // REVIEW: What to return here? Both caches contents? Nothing? // - return new HashSet(); } /// /// Gets the size of the item. /// Returns -1 if the item is absent. /// /// /// Identifier for the cache container holding the item. /// /// /// Hash key for the desired item. /// /// Size of the item in bytes, or -1 if item is absent. public long GetItemSize( ItemCacheContainer container, string itemHash) { long size = this.localCache.GetItemSize(container, itemHash); if (size == -1) { size = this.cloudCache.GetItemSize(container, itemHash); } return size; } /// /// Gets the last-modified time of the item. /// /// /// Identifier for the cache container holding the item. /// /// /// Hash key for the desired item. /// /// A DateTimeOffset containing the item's last-modified time. public DateTimeOffset? GetItemLastModifiedTime( ItemCacheContainer container, string itemHash) { DateTimeOffset? modifiedTime = this.localCache.GetItemLastModifiedTime(container, itemHash); if (modifiedTime == null) { modifiedTime = this.cloudCache.GetItemLastModifiedTime(container, itemHash); } return modifiedTime; } /// /// Public API for private CheckForAndOrUploadMissingItem method. /// /// /// Identifier for the item's cache container. /// /// Hash key for the item. public void SyncItemToCloud( ItemCacheContainer container, string itemHash) { this.CheckForAndOrUploadMissingItem(container, itemHash); } /// /// Queue the given item for asynchronous cloud cache synchronization. /// /// /// Identifier for the item's cache container. /// /// Hash key for the item. private void QueueItemForCloudSync( ItemCacheContainer container, string itemHash) { if (this.backgroundWorker != null) { this.backgroundWorker.QueueWork(this.CheckForAndOrUploadMissingItem, container, itemHash); } } /// /// Check if the given item is already present in the cloud cache, /// and if not, upload the local cache item to the cloud. /// /// /// Identifier for the item's cache container. /// /// Hash key for the item. private void CheckForAndOrUploadMissingItem( object containerObject, object itemHashObject) { ItemCacheContainer container = (ItemCacheContainer)containerObject; string itemHash = (string)itemHashObject; if (this.localCache.GetItemSize(container, itemHash) > MaxUploadSizeThreshold) { Logger.WriteLine(string.Format( "Warning: skipping upload of {0} because it's really big. Compress?", itemHash)); return; } // - // Check if the item is already present in the cloud cache. // TODO present doesn't mean we don't want to overwrite it (eg when // replacing a Failed verification result with a succeeding one.) // - if (this.cloudCache.ItemExists(container, itemHash)) { return; } // - // The item is missing from the cloud cache. Upload it. // - byte[] temp = this.localCache.FetchItem(container, itemHash); if (temp == null) { // This should never happen barring a serious logic error. throw new ObjectMissingFromCacheException(itemHash, "Can't upload non-existant cache item!"); } this.cloudCache.StoreItem(container, itemHash, temp); } #if false /// /// A wrapper for a stream that queues up a cloud cache sync after it is /// closed. /// /// /// REVIEW: a lot of boilerplate code just to hook one call. Better way to do this? /// private class MultiplexerWrappedStream : Stream { /// /// Flag indicating whether or not Dispose has already been called. /// private bool disposed; /// /// Stream we are wrapping. /// private Stream stream; /// /// Item cache multiplexer that holds the item behind the stream. /// private ItemCacheMultiplexer multiplexer; /// /// Item cache container for the item behind the stream. /// private ItemCacheContainer container; /// /// Item cache hash for the item behind the stream. /// private string itemHash; /// /// Initializes a new instance of the MultiplexerWrappedStream /// class. /// /// A stream to wrap. /// /// The multiplexer cache instance owning item. /// /// /// The container for the item in the multiplexer cache. /// /// /// The hash for the item in the multiplexer cache. /// public MultiplexerWrappedStream( Stream stream, ItemCacheMultiplexer multiplexer, ItemCacheContainer container, string itemHash) { this.stream = stream; this.multiplexer = multiplexer; this.container = container; this.itemHash = itemHash; } /// /// Gets a value indicating whether the current steam supports /// reading. /// public override bool CanRead { get { return this.stream.CanRead; } } /// /// Gets a value indicating whether the current stream supports /// seeking. /// public override bool CanSeek { get { return this.stream.CanSeek; } } /// /// Gets a value indicating whether the current stream supports /// writing. /// public override bool CanWrite { get { return this.stream.CanWrite; } } /// /// Gets the length in bytes of the stream. /// public override long Length { get { return this.stream.Length; } } /// /// Gets or sets the position within the current stream. /// public override long Position { get { return this.stream.Position; } set { this.stream.Position = value; } } /// /// Reads a sequence of bytes from the current stream and advances /// the position within the stream by the number of bytes read. /// /// /// An array of bytes. When this method returns, the buffer /// contains the specified byte array with the values between /// offset and (offset + count - 1) replaced by the bytes read from /// the current source. /// /// /// The zero-based byte offset in buffer at which to begin storing /// the data read from the current stream. /// /// /// The maximum number of bytes to be read from the current stream. /// /// /// The total number of bytes read into the buffer. This can be /// less than the number of bytes requested if that many bytes are /// not currently available, or zero (0) if the end of the stream /// has been reached. /// public override int Read(byte[] buffer, int offset, int count) { return this.stream.Read(buffer, offset, count); } /// /// Writes a sequence of bytes to the current stream and advances /// the position within this stream by the number of bytes written. /// /// /// An array of bytes. This method copies count bytes from buffer /// to the current stream. /// /// /// The zero-based offset in buffer at which to begin copying bytes /// to the current stream. /// /// /// The number of bytes to be written to the current stream. /// public override void Write(byte[] buffer, int offset, int count) { this.stream.Write(buffer, offset, count); } /// /// Clears all buffers for this stream and causes any buffered data /// to be written to the underlying device. /// public override void Flush() { this.stream.Flush(); } /// /// Sets the position within the current stream. /// /// /// A byte offset relative to the origin parameter. /// /// /// A value of type SeekOrigin indicating the reference point used /// to obtain the new position. /// /// The new position within the public override long Seek(long offset, SeekOrigin origin) { return this.stream.Seek(offset, origin); } /// /// Sets the length of the current stream. /// /// /// Desired length of the current stream in bytes. /// public override void SetLength(long value) { this.stream.SetLength(value); } /// /// Releases unmanaged and (optionally) managed resources. /// /// /// Whether or not to release managed resources. /// protected override void Dispose(bool disposing) { if (this.disposed) { return; } if (disposing) { this.stream.Dispose(); this.multiplexer.QueueItemForCloudSync(this.container, this.itemHash); } this.disposed = true; base.Dispose(disposing); } } #endif } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/Job.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.InteropServices; using Microsoft.Win32.SafeHandles; /// /// Represents a Windows Job Object. /// /// /// This class is only used by ProcessInvoker, so it could be private to that class. /// [SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1121:UseBuiltInTypeAlias", Justification = "UInt* is more appropriate for system programming")] internal class Job : IDisposable { /// /// Handle to the native Windows job object. /// private SafeFileHandle jobObjectHandle; /// /// Flag indicating whether or not Dispose has already been called. /// private bool disposed; /// /// Initializes a new instance of the Job class. /// public Job() { this.jobObjectHandle = NativeMethods.CreateJobObject(IntPtr.Zero, null); if (this.jobObjectHandle.IsInvalid) { // Note that the parameterless Win32Exception constructor calls Marshal.GetLastWin32Error internally. throw new Win32Exception(); } // - // Set up this job object so that any processes assigned to it will // be terminated when it is closed (since this job object will be // closed automatically when the owning process exits, all assigned // processes will also be closed when the owning process exists). // - // Note that to set the JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE flag, // the call to SetInformationJobObject must be of JobObjectInfoClass // ExtendedLimitInformation, even though the flag is in the simpler // BasicLimitInformation structure contained in the former. // - NativeMethods.JOBOBJECT_EXTENDED_LIMIT_INFORMATION info = new NativeMethods.JOBOBJECT_EXTENDED_LIMIT_INFORMATION(); int infoSize = Marshal.SizeOf(typeof(NativeMethods.JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); info.BasicLimitInformation.LimitFlags = NativeMethods.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; IntPtr infoPtr = Marshal.AllocHGlobal(infoSize); try { Marshal.StructureToPtr(info, infoPtr, false); if (!NativeMethods.SetInformationJobObject( this.jobObjectHandle, NativeMethods.JOBOBJECTINFOCLASS.ExtendedLimitInformation, infoPtr, (UInt32)infoSize)) { // Note that the parameterless Win32Exception constructor calls Marshal.GetLastWin32Error internally. throw new Win32Exception(); } } finally { Marshal.FreeHGlobal(infoPtr); } } /// /// Adds the given process to the job object. /// /// Process to add. /// True if successful, false otherwise. public bool AddProcess(Process process) { return NativeMethods.AssignProcessToJobObject(this.jobObjectHandle, process.Handle); } /// /// Gets the total CPU consumed by all processes associated with this job object. /// /// Total CPU time. public TimeSpan GetCpuTime() { UInt64 totalCpuTime = 0; NativeMethods.JOBOBJECT_BASIC_ACCOUNTING_INFORMATION basicAccountingInfo; basicAccountingInfo = this.GetBasicAccountingInformation(); totalCpuTime = basicAccountingInfo.TotalKernelTime + basicAccountingInfo.TotalUserTime; return new TimeSpan((long)totalCpuTime); } /// /// Terminates all processes currently associated with this job object. /// /// Exit code to be used by all processes and threads. /// True if successful, false otherwise. public bool Terminate(UInt32 exitCode) { return NativeMethods.TerminateJobObject(this.jobObjectHandle, exitCode); } /// /// Closes this Job object. /// public void Close() { this.jobObjectHandle.Close(); } /// /// Releases resources. /// public void Dispose() { this.Dispose(true); GC.SuppressFinalize(this); } /// /// Releases unmanaged and (optionally) managed resources. /// /// Whether or not to release managed resources. private void Dispose(bool disposing) { if (this.disposed) { return; } if (disposing) { this.jobObjectHandle.Dispose(); } this.disposed = true; } /// /// Gets a struct containing the basic accounting information for the job object. /// /// A JOBOBJECT_BASIC_ACCOUNTING_INFORMATION structure. private NativeMethods.JOBOBJECT_BASIC_ACCOUNTING_INFORMATION GetBasicAccountingInformation() { NativeMethods.JOBOBJECT_BASIC_ACCOUNTING_INFORMATION info; int infoSize = Marshal.SizeOf(typeof(NativeMethods.JOBOBJECT_BASIC_ACCOUNTING_INFORMATION)); IntPtr infoPtr = Marshal.AllocHGlobal(infoSize); try { if (!NativeMethods.QueryInformationJobObject( this.jobObjectHandle, NativeMethods.JOBOBJECTINFOCLASS.BasicAccountingInformation, infoPtr, (UInt32)infoSize, IntPtr.Zero)) { // Note that the parameterless Win32Exception constructor calls Marshal.GetLastWin32Error internally. throw new Win32Exception(); } info = (NativeMethods.JOBOBJECT_BASIC_ACCOUNTING_INFORMATION)Marshal.PtrToStructure(infoPtr, typeof(NativeMethods.JOBOBJECT_BASIC_ACCOUNTING_INFORMATION)); } finally { Marshal.FreeHGlobal(infoPtr); } return info; } /// /// Represents the native Windows API for accessing job objects. /// [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1310:FieldNamesMustNotContainUnderscore", Justification = "Part of Windows API")] [SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:ElementsMustBeDocumented", Justification = "Part of Windows API")] [SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1602:EnumerationItemsMustBeDocumented", Justification = "Part of Windows API")] private static class NativeMethods { public const UInt32 JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE = 0x2000; public enum JOBOBJECTINFOCLASS { BasicAccountingInformation = 1, BasicLimitInformation = 2, ExtendedLimitInformation = 9 } [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] public static extern SafeFileHandle CreateJobObject(IntPtr jobAttributes, string name); [DllImport("kernel32.dll")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool AssignProcessToJobObject(SafeHandle jobHandle, IntPtr processHandle); [DllImport("kernel32.dll")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool SetInformationJobObject(SafeHandle jobHandle, JOBOBJECTINFOCLASS infoClass, IntPtr info, UInt32 infoLength); [DllImport("kernel32.dll")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool QueryInformationJobObject(SafeHandle jobHandle, JOBOBJECTINFOCLASS infoClass, IntPtr info, UInt32 infoLength, IntPtr returnLength); [DllImport("kernel32.dll")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool TerminateJobObject(SafeHandle job, UInt32 exitCode); [StructLayout(LayoutKind.Sequential, Pack = 8)] public struct JOBOBJECT_BASIC_LIMIT_INFORMATION { public UInt64 PerProcessUserTimeLimit; public UInt64 PerJobUserTimeLimit; public UInt32 LimitFlags; public UIntPtr MinimumWorkingSetSize; public UIntPtr MaximumWorkingSetSize; public UInt32 ActiveProcessLimit; public UIntPtr Affinity; public UInt32 PriorityClass; public UInt32 SchedulingClass; } [StructLayout(LayoutKind.Sequential)] public struct IO_COUNTERS { public UInt64 ReadOperationCount; public UInt64 WriteOperationCount; public UInt64 OtherOperationCount; public UInt64 ReadTransferCount; public UInt64 WriteTransferCount; public UInt64 OtherTransferCount; } [StructLayout(LayoutKind.Sequential)] public struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION { public JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation; public IO_COUNTERS IoInfo; public UIntPtr ProcessMemoryLimit; public UIntPtr JobMemoryLimit; public UIntPtr PeakProcessMemoryLimit; public UIntPtr PeakJobMemoryUsed; } [StructLayout(LayoutKind.Sequential)] public struct JOBOBJECT_BASIC_ACCOUNTING_INFORMATION { public UInt64 TotalUserTime; public UInt64 TotalKernelTime; public UInt64 ThisPeriodTotalUserTime; public UInt64 ThisPeriodTotalKernelTime; public UInt32 TotalPageFaultCount; public UInt32 TotalProcesses; public UInt32 ActiveProcesses; public UInt32 TotalTerminatedProcesses; } } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/LinkerVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; using System.Linq; internal class LinkerVerb : Verb, IProcessInvokeAsyncVerb { public const string UNTRUSTED_EXE_EXTN = ".uexe"; protected BuildObject outputObject; protected BuildObject objFile; protected long maxExeSize; protected string entryPoint; protected int baseAddr; private const int version = 4; private bool isLoader; private MasmVerb masmVerb; private AbstractId abstractId; public LinkerVerb(MasmVerb masmVerb, bool isLoader) { this.masmVerb = masmVerb; this.isLoader = isLoader; this.objFile = masmVerb.getObj(); this.abstractId = new AbstractId(this.GetType().Name, version + this.getVersion(), this.objFile.ToString(), concrete: isLoader ? "Loader" : "NonLoader"); this.outputObject = this.objFile.makeOutputObject(this.outputExtension()); // Default settings for the apps. this.maxExeSize = 1 * 1024 * 1024; // 1 MB. this.entryPoint = "?AppEntryPoint"; this.baseAddr = 0x340000; if (this.isLoader) { // Override the settings above with loader-specific values. this.maxExeSize = 58 * 1024; // 58 KB this.entryPoint = "?LoaderEntryPoint"; this.baseAddr = 0x300000; } } public override AbstractId getAbstractIdentifier() { return this.abstractId; } public BuildObject getUntrustedExe() { return this.outputObject; } public override IEnumerable getDependencies(out DependencyDisposition ddisp) { ddisp = DependencyDisposition.Complete; List basic = new List() { this.getLinkerExe(), this.objFile }; basic.AddRange(this.getExtraDependencies()); return basic; } public override IEnumerable getVerbs() { return new List() { this.masmVerb }; } public override IEnumerable getOutputs() { return new List() { this.getUntrustedExe() }.Union(this.getExtraOutputs()); } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { List args = new List() { "/LARGEADDRESSAWARE", "/driver", "/fixed", "/subsystem:native", "/nodefaultlib" }; args.Add(this.objFile.getRelativePath()); args.Add("/out:" + this.outputObject.getRelativePath()); args.Add("/entry:" + this.entryPoint); args.Add("/base:" + this.baseAddr); return new ProcessInvokeAsyncWorker( workingDirectory, this, this.getLinkerExe().getRelativePath(), args.ToArray(), ProcessExitCodeHandling.NonzeroIsFailure, this.getDiagnosticsBase()); } public virtual Disposition Complete(WorkingDirectory workingDirectory, double cpuTimeSeconds, string stdout, string stderr, Disposition disposition) { if (!(disposition is Failed)) { // Check that the executable isn't too large. long exeSize = new FileInfo(workingDirectory.PathTo(this.outputObject)).Length; if (exeSize > this.maxExeSize) { return new Failed("Executable too big"); } } return disposition; } protected virtual int getVersion() { // REVIEW: Is this right? There is a private version field in this object. return 0; } protected virtual string outputExtension() { return UNTRUSTED_EXE_EXTN; } protected virtual BuildObject getLinkerExe() { return new SourcePath("tools\\Assembler\\link-base.exe", SourcePath.SourceType.Tools); } protected virtual IEnumerable getExtraDependencies() { List extraDepends = new List(); extraDepends.Add(new SourcePath("tools\\Assembler\\mspdb80.dll", SourcePath.SourceType.Tools)); return extraDepends; } protected virtual IEnumerable getExtraOutputs() { return new List(); } protected virtual bool runLinker(BuildObject asmFile, string linkerExecutable, string entryPoint, int baseAddr, long maxExeSize = -1) { return true; } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/Logger.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.IO; /// /// Utility for writing log messages simultaneously to the console and /// a log file. /// internal class Logger { /// /// The log file. /// private static StreamWriter log; /// /// Writes a message to both the log file and the console. /// /// Message to write. public static void Write(string msg) { OpenLog(); log.Write(msg); log.Flush(); System.Console.Write(msg); } /// /// Writes a message and the newline string to both the log file /// and the console. /// /// Message to write. public static void WriteLine(string msg) { Write(msg + System.Environment.NewLine); } /// /// Opens the log file (if it isn't already open). /// private static void OpenLog() { if (log == null) { log = new StreamWriter("nubuild.log"); } } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/MasmVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; internal class MasmVerb : Verb, IProcessInvokeAsyncVerb { public const string MASM_EXTN = ".asm"; public const string OBJ_EXTN = ".obj"; private const int version = 4; private IAsmProducer asmVerb; private AbstractId abstractId; private BuildObject outputObject; private BuildObject asmFile; public MasmVerb(IAsmProducer asmVerb) { this.asmVerb = asmVerb; this.asmFile = asmVerb.getAsmFile(); this.abstractId = new AbstractId(this.GetType().Name, version, this.asmFile.ToString()); this.outputObject = this.asmFile.makeOutputObject(OBJ_EXTN); } public override AbstractId getAbstractIdentifier() { return this.abstractId; } public BuildObject getObj() { return this.outputObject; } public BuildObject getLis() { return this.asmFile.makeOutputObject(".lis"); } ////public BuildObject getMap() { return this.asmFile.makeOutputObject(".map"); } public override IEnumerable getDependencies(out DependencyDisposition ddisp) { ddisp = DependencyDisposition.Complete; return new List() { this.getMasmExe(), this.asmVerb.getAsmFile() }; } public override IEnumerable getVerbs() { return new List() { this.asmVerb }; } public override IEnumerable getOutputs() { return new List() { this.getObj(), this.getLis(), //// this.getMap() }; } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { List args = new List() { "/Cp", "/c", "/Zd", "/Zf", "/Zi" }; args.Add("/Fo" + this.getObj().getRelativePath()); args.Add("/Fl" + this.getLis().getRelativePath()); ////args.Add("/Fm" + getMap().getRelativePath()); // TODO: "/I$SPEC_INCLUDE_DIR" args.Add(this.asmFile.getRelativePath()); return new ProcessInvokeAsyncWorker( workingDirectory, this, this.getMasmExe().getRelativePath(), args.ToArray(), ProcessExitCodeHandling.NonzeroIsFailure, this.getDiagnosticsBase()); } public Disposition Complete(WorkingDirectory workingDirectory, double cpuTimeSeconds, string stdout, string stderr, Disposition disposition) { return disposition; } private BuildObject getMasmExe() { return new SourcePath("tools\\Assembler\\ml.exe", SourcePath.SourceType.Tools); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/NMakeVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Diagnostics; using System.IO; using System.Linq; internal class NmakeVerb : Verb, IProcessInvokeAsyncVerb { private const int version = 7; private static SourcePath nmakeExecutable; private SourcePath makefile; private CustomManifestParser customManifest; private AbstractId abstractId; private string outputPath; private string outputPathSuffix; public NmakeVerb(SourcePath makefile) { this.makefile = makefile; this.abstractId = new AbstractId(this.GetType().Name, version, this.makefile.ToString()); // Generate output path. this.outputPath = "."; int depth = this.makefile.getDirPath().Split(@"\/".ToCharArray(), StringSplitOptions.RemoveEmptyEntries).Length; for (int i = 0; i < depth; i++) { this.outputPath = Path.Combine(this.outputPath, ".."); } this.outputPathSuffix = Path.Combine(BuildEngine.theEngine.getObjRoot(), this.makefile.getDirPath()); this.outputPath = Path.Combine(this.outputPath, this.outputPathSuffix); this.customManifest = new CustomManifestParser(this.makefile); } public override IEnumerable getDependencies(out DependencyDisposition ddisp) { ddisp = DependencyDisposition.Complete; return this.customManifest.getDependencies().Union(new List() { getNmakeExecutable() }); } public override IEnumerable getVerbs() { return new IVerb[] { }; } public override IEnumerable getOutputs() { return from output in this.customManifest.getOutputs() select new BuildObject(Path.Combine(BuildEngine.theEngine.getObjRoot(), output.getRelativePath())); } public BuildObject getOutputPath() { return new BuildObject(this.outputPathSuffix); } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { // Scrub the "makeflags" environment variable from our environment // so we don't pass it down to our worker process. Some users may // have things there that conflict with our usage. Process myProcess = System.Diagnostics.Process.GetCurrentProcess(); StringDictionary environmentVariables = myProcess.StartInfo.EnvironmentVariables; environmentVariables.Remove("MAKEFLAGS"); List args = new List(); args.Add(string.Format("OBJ={0}\\obj", workingDirectory.PathTo(this.outputPathSuffix))); args.Add(string.Format("BIN={0}", workingDirectory.PathTo(this.outputPathSuffix))); args.Add("-f"); args.Add(workingDirectory.PathTo(this.makefile)); // TODO: Remove reliance on workingDirOverride, which currently hides dependency issues and other problems. return new ProcessInvokeAsyncWorker( workingDirectory, this, getNmakeExecutable().getRelativePath(), ////"c:/Program Files (x86)/Microsoft Visual Studio 12.0/VC/bin/nmake.exe", args.ToArray(), ProcessExitCodeHandling.NonzeroIsFailure, workingDirOverride: IronRootDirectory.PathTo(this.makefile.getDirPath()), failureBase: getDiagnosticsBase(), //allowAbsoluteExe: true, allowAbsoluteArgs: true); } public Disposition Complete(WorkingDirectory workingDirectory, double cpuTimeSeconds, string stdout, string stderr, Disposition disposition) { return disposition; } public override AbstractId getAbstractIdentifier() { return this.abstractId; } private static SourcePath getNmakeExecutable() { // TODO this should eventually be a BuildObject from *building* the executable. if (nmakeExecutable == null) { nmakeExecutable = new SourcePath("tools\\nmake\\nmake.exe", SourcePath.SourceType.Tools); } return nmakeExecutable; } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/NuBuild.csproj ================================================  Debug AnyCPU {4D7220C0-3CAA-4659-9F16-A564DB3CCC1B} Exe Properties NuBuild NuBuild v4.5 512 false publish\ true Disk false Foreground 7 Days false false true 0 1.0.0.%2a false true AnyCPU true full false ..\..\..\bin_tools\NuBuild\ TRACE;DEBUG prompt 4 AllRules.ruleset false AnyCPU pdbonly true bin\Release\ TRACE prompt 4 False ..\References\Microsoft.WindowsAzure.Storage.dll False Code Code False Microsoft .NET Framework 4.5 %28x86 and x64%29 true False .NET Framework 3.5 SP1 Client Profile false False .NET Framework 3.5 SP1 false CustomDictionary.xml ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/ObjectFailedException.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; internal class ObjectFailedException : Exception { public ObjectFailedException(BuildObject obj, Failed failed) : base(obj.ToString() + ": " + failed.ToString()) { } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/ObjectMissingFromCacheException.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; internal class ObjectMissingFromCacheException : Exception { private string itemHash; public ObjectMissingFromCacheException(string itemHash, string msg) : base(string.Format("item {0} missing from cache: {1}", itemHash, msg)) { this.itemHash = itemHash; } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/ObjectNotReadyException.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; internal class ObjectNotReadyException : Exception { public ObjectNotReadyException(BuildObject obj) : base(obj.ToString()) { } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/OrderPreservingSet.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Linq; /// /// Representation of an order-preserving set. /// /// /// Inspired by ICollection example at /// . /// /// Type of objects in the set. internal class OrderPreservingSet : ICollection { private readonly HashSet membership; private readonly List order; public OrderPreservingSet() : this(EqualityComparer.Default) { } public OrderPreservingSet(IEqualityComparer comparer) { this.membership = new HashSet(comparer); this.order = new List(); } public OrderPreservingSet(IEnumerable initialContents) : this() { this.AddRange(initialContents); } public int Count { get { return this.membership.Count(); } } int ICollection.Count { get { return this.membership.Count; } } // TODO I don't know what this property is for. bool ICollection.IsReadOnly { get { return false; } } public void Add(T item) { if (!this.membership.Contains(item)) { this.membership.Add(item); this.order.Add(item); } } void ICollection.Add(T item) { this.Add(item); } public void AddRange(IEnumerable range) { foreach (T obj in range) { this.Add(obj); } } void ICollection.Clear() { this.membership.Clear(); this.order.Clear(); } bool ICollection.Contains(T item) { return this.membership.Contains(item); } void ICollection.CopyTo(T[] array, int arrayIndex) { this.order.CopyTo(array, arrayIndex); } IEnumerator IEnumerable.GetEnumerator() { return this.order.GetEnumerator(); } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return this.order.GetEnumerator(); } bool ICollection.Remove(T item) { this.membership.Remove(item); return this.order.Remove(item); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/PathNormalizer.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; internal class PathNormalizer { private Dictionary cache; private char[] directorySeparators; public PathNormalizer() { this.cache = new Dictionary(); this.directorySeparators = new char[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }; } public static string dbg_normalizePath_nocache(string requestPath, bool presumedDirectory) { return PathNormalizer.normalizePath_nocache(requestPath, presumedDirectory); } // Normalize the case of an absolute path to the case present in the filesystem. public string normalizeAbsolutePath(string absPath) { string dotdotfreepath = this.cleanDotDots(absPath); if (!Path.IsPathRooted(dotdotfreepath)) { throw new ArgumentException("Requires absolute path"); } return this.normalizePath(dotdotfreepath, false); } private static string normalizePath_nocache(string requestPath, bool presumedDirectory) { try { string rc; string childName = Path.GetFileName(requestPath); if (string.IsNullOrEmpty(childName)) { // absPath was a "root" (MSDOS drive letter) // by fiat, drive letters are uppercase. rc = requestPath.ToUpper(CultureInfo.InvariantCulture) + Path.DirectorySeparatorChar; } else { string parentPath = Path.GetDirectoryName(requestPath); // Recurse to handle parent prefix: string normalizedParent = normalizePath_nocache(parentPath, true); DirectoryInfo parentDirectoryInfo = new DirectoryInfo(normalizedParent); FileSystemInfo[] childrenFileSystemInfos = null; string normalizedPath; try { childrenFileSystemInfos = parentDirectoryInfo.GetFileSystemInfos(childName); } catch (System.IO.DirectoryNotFoundException) { // Fall through and assume we're to create it. } if (childrenFileSystemInfos == null || childrenFileSystemInfos.Length == 0) { // Looks like a nonexistent path. I guess the caller gets to decide the // capitalization. NB this is fraught with danger, since we're not actually // creating the path in the filesystem, so someone else might try to create // a path with a different capitalization. However, if we memorize our // results, we should end up canonicalizing to the first capitalization // we see. normalizedPath = Path.Combine(normalizedParent, childName); // Unfortunately, we can't tell whether we should add a path separator here! if (presumedDirectory) { normalizedPath += Path.DirectorySeparatorChar; } } else { FileSystemInfo childFileSystemInfo = childrenFileSystemInfos.First(); // Since we passed a normalized path into DirectoryInfo, we'll get // the normalized path back out, plus the filesystem's idea of the // child name's case. normalizedPath = childFileSystemInfo.FullName; if ((childFileSystemInfo.Attributes & FileAttributes.Directory) == FileAttributes.Directory) { normalizedPath += Path.DirectorySeparatorChar; } } rc = normalizedPath; } ////Logger.WriteLine(string.Format("{0}\n => {1}", requestPath, rc)); return rc; } catch (Exception ex) { Trace.TraceError(ex.Message); throw new ArgumentException("invalid path"); } } // Invariant: input is an absolute path, free of ..s, lowercased, with // normalized path separators. // Based on suggestions in http://stackoverflow.com/questions/1214513/normalize-directory-names-in-c-sharp. private string normalizePath(string requestPath, bool presumedDirectory) { string lowerPath = requestPath.ToLower(CultureInfo.InvariantCulture); if (this.cache.ContainsKey(lowerPath)) { return this.cache[lowerPath]; } string rc = PathNormalizer.normalizePath_nocache(requestPath, presumedDirectory); this.cache[lowerPath] = rc; return rc; } private string cleanDotDots(string path) { string[] parts = path.Split(this.directorySeparators); List outParts = new List(); for (int i = 0; i < parts.Length; i++) { if (parts[i].Equals(string.Empty)) { // Null path segment: foo//bar. continue; } else if (parts[i].Equals(".")) { // Semantically-null segment. continue; } else if (parts[i].Equals("..")) { outParts.RemoveAt(outParts.Count() - 1); } else { outParts.Add(parts[i]); } } return string.Join(Path.DirectorySeparatorChar.ToString(), outParts.ToArray()); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/PoundDefines.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; internal class PoundDefines { private List definedSymbols; private string descr; public PoundDefines(IEnumerable definedSymbols) { this.definedSymbols = new List(definedSymbols); this.definedSymbols.Sort(); // NB the null list gets a *null* ToString, which is interpreted as no appLabel. this.descr = this.definedSymbols.Count == 0 ? null : "#" + string.Join(",", this.definedSymbols); } public override string ToString() { return this.descr; } public string getAbstractIdString() { return this.descr == null ? string.Empty : ", " + this.descr; } public override int GetHashCode() { return this.descr.GetHashCode(); } public override bool Equals(object obj) { PoundDefines other = obj as PoundDefines; if (other != null) { return (this.descr == null && other.descr == null) || (this.descr != null && this.descr.Equals(other.descr)); } else { return false; } } internal static string toAppLabel(PoundDefines poundDefines) { return poundDefines == null ? null : poundDefines.ToString(); } internal static PoundDefines empty() { return new PoundDefines(new string[] { }); } internal IEnumerable ToDefArgs() { List args = new List(); foreach (string symbol in this.definedSymbols) { args.Add("-def"); args.Add(symbol); } return args; } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/Presentater.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Text; /// /// TODO: Rename this (and the file) to IPresentater, or maybe IPresenter. /// REVIEW: These all just emit strings. Wouldn't a simple table suffice? /// internal interface Presentater { void startHeader(); void endHeader(); void startLine(); void endLine(); void startSpacer(); void endSpacer(); void startColor(string colorName); void endColor(); void startBullet(); void endBullet(); void startPre(); void endPre(); void doText(string text); } public class HTMLPresentater : Presentater { private StringBuilder document; public HTMLPresentater() { this.document = new StringBuilder(); this.document.Append("\n\n"); } public override string ToString() { this.document.Append("\n\n"); return this.document.ToString(); } public void startHeader() { this.document.Append("

"); } public void endHeader() { this.document.Append("

"); } public void startLine() { this.document.Append("
"); } public void endLine() { this.document.Append("
\n"); } public void startSpacer() { this.document.Append("

\n"); } public void endSpacer() { this.document.Append("

\n"); } public void startColor(string colorName) { string htmlColor; switch (colorName) { case Presentation.RED: htmlColor = "red"; break; case Presentation.GREEN: htmlColor = "green"; break; default: htmlColor = "black"; break; } this.document.Append(""); } public void endColor() { this.document.Append(""); } public void startBullet() { this.document.Append("
  • "); } public void endBullet() { this.document.Append("
  • \n"); } public void startPre() { this.document.Append("
    ");
            }
    
            public void endPre()
            {
                this.document.Append("
    \n"); } public void doText(string text) { this.document.Append(text); } } /// /// Appears to be a "Presentater" that uses "ANSI escape sequences" to /// produce colored output on console terminals that support it. /// /// /// /// "ANSI escape sequences" is probably the most common name for these /// things, although it is technically a misnomer, as ANSI withdrew the /// ANSI X3.64 spec in 1997. The real spec is ECMA-48, aka ISO/IEC 6429. /// See
    . /// /// /// Windows cmd.exe doesn't implement this spec. So only those folks /// using alternative shells will get easily-readable output from this. /// /// public class ASCIIPresentater : Presentater { // REVIEW: These don't appear to properly follow the ECMA-48 spec. // All of these commands are of type "Select Graphic Rendition" or SGR. // In the spec, this is covered in section 8.3.117. // The 0 code is supposed to cancel the effect of any preceding SGR, // i.e. "\x1b[0m" should cancel everything. Thus the following stop // codes don't just stop what their start codes started (and are overly // verbose). A universal stop code would suffice for this usage. // Notes on codes used below: // 0 = cancel the effect of any preceding SGR. // 1 = bold. // 32 = green display (i.e. text). // 37 = white display (i.e. text). // 39 = default display (i.e. text) color. // 40 = black background. // 41 = red background. // 43 = yellow background. // 49 = default background color. private static ColorEnum Red = new ColorEnum("\x1b[01;41m", "\x1b[0;49m"); private static ColorEnum Green = new ColorEnum("\x1b[01;32m", "\x1b[0;0m"); private static ColorEnum BlackBackground = new ColorEnum("\x1b[01;40m", "\x1b[0;49m"); private static ColorEnum YellowBackground = new ColorEnum("\x1b[01;43m", "\x1b[0;49m"); private static ColorEnum BoldWhite = new ColorEnum("\x1b[01;37m", "\x1b[0;39m"); private static ColorEnum WhiteOnBlack = ColorEnum.join(BlackBackground, BoldWhite); private static ColorEnum Ordinary = new ColorEnum(string.Empty, string.Empty); private StringBuilder document; private ColorEnum colorEnum; public ASCIIPresentater() { this.document = new StringBuilder(); } public override string ToString() { return this.document.ToString(); } public void startHeader() { this.document.Append(WhiteOnBlack.start); } public void endHeader() { this.document.Append(WhiteOnBlack.stop + "\n"); } public void startLine() { } public void endLine() { this.document.Append("\n"); } public void startSpacer() { } public void endSpacer() { this.document.Append("\n"); } public void startColor(string colorName) { Util.Assert(this.colorEnum == null); switch (colorName) { case Presentation.RED: this.colorEnum = Red; break; case Presentation.GREEN: this.colorEnum = Green; break; default: this.colorEnum = Ordinary; break; } this.document.Append(this.colorEnum.start); } public void endColor() { this.document.Append(this.colorEnum.stop); this.colorEnum = null; } public void startBullet() { this.document.Append(" * "); } public void endBullet() { this.document.Append("\n"); } public void startPre() { } public void endPre() { if (!this.document.ToString().EndsWith("\n")) { this.document.Append("\n"); } } public void doText(string text) { this.document.Append(text); } /// /// Definition of the start and stop sequences for a color. /// /// /// REVIEW: This class is not needed, as there is only one stop sequence. /// private class ColorEnum { public string start; public string stop; public ColorEnum(string start, string stop) { this.start = start; this.stop = stop; } public static ColorEnum join(ColorEnum a, ColorEnum b) { return new ColorEnum(a.start + b.start, b.stop + a.stop); } } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/Presentation.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.IO; using System.Text; using System.Xml; internal class Presentation : XmlFiller { // Completed representation. private string xmls; public const string _xml_tag = "Presentation"; public const string HEADER = "Header"; public const string LINE = "Line"; public const string SPACER = "Spacer"; public const string COLOR = "Color"; public const string BULLET = "Bullet"; public const string PRE = "Pre"; public const string RED = "red"; public const string GREEN = "green"; public const string _xml_ColorValue_attr = "Value"; public Presentation(string xmls) { this.xmls = xmls; } public static Presentation fromXml(XmlReader xr) { StringBuilder sb = new StringBuilder(); using (XmlWriter xw = XmlWriter.Create(sb)) { xw.WriteStartDocument(); xw.WriteNode(xr, false); xw.WriteEndDocument(); xw.Close(); } return new Presentation(sb.ToString()); } public void fillXml(XmlWriter xw) { using (XmlReader xr = XmlReader.Create(new StringReader(this.xmls))) { xr.ReadToFollowing(_xml_tag); xw.WriteNode(xr, false); } } public void format(Presentater p) { using (XmlReader xr = XmlReader.Create(new StringReader(this.xmls))) { xr.ReadToFollowing(_xml_tag); while (xr.Read()) { if (xr.NodeType == XmlNodeType.Element) { switch (xr.Name) { case HEADER: p.startHeader(); break; case LINE: p.startLine(); break; case SPACER: p.startSpacer(); break; case COLOR: p.startColor(xr.GetAttribute(_xml_ColorValue_attr)); break; case BULLET: p.startBullet(); break; case PRE: p.startPre(); break; default: Util.Assert(false); break; } } else if (xr.NodeType == XmlNodeType.EndElement) { switch (xr.Name) { case _xml_tag: break; case HEADER: p.endHeader(); break; case LINE: p.endLine(); break; case SPACER: p.endSpacer(); break; case COLOR: p.endColor(); break; case BULLET: p.endBullet(); break; case PRE: p.endPre(); break; default: Util.Assert(false); break; } } else if (xr.NodeType == XmlNodeType.Text) { p.doText(xr.Value); } } } } internal static string abbreviateLines(string m) { StringBuilder sb = new StringBuilder(); int count = 0; const int limit = 20; using (StringReader sr = new StringReader(m)) { string line; while ((line = sr.ReadLine()) != null) { if (count == limit) { sb.AppendLine("[...error messages truncated. See failure log.]"); break; } sb.AppendLine(line); count += 1; } } return sb.ToString(); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/PresentationBuilder.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Text; using System.Xml; internal class PresentationBuilder { // Build-up interface. private StringBuilder sb; private XmlWriter xw; public PresentationBuilder() { this.sb = new StringBuilder(); // Notice no indentation, to avoid mungling text. this.xw = XmlWriter.Create(this.sb); this.xw.WriteStartDocument(); this.xw.WriteStartElement(Presentation._xml_tag); } public Presentation fix() { this.xw.WriteEndElement(); this.xw.WriteEndDocument(); this.xw.Close(); return new Presentation(this.sb.ToString()); } public void text(string s) { this.xw.WriteString(s); } public void color(string color, string s) { this.xw.WriteStartElement(Presentation.COLOR); this.xw.WriteAttributeString(Presentation._xml_ColorValue_attr, color); this.text(s); this.xw.WriteEndElement(); } public void header(string s) { this.simpleTag(Presentation.HEADER, s); } public void line(string s) { this.simpleTag(Presentation.LINE, s); } public void spacer() { this.simpleTag(Presentation.SPACER, string.Empty); } public void bullet(string s) { this.simpleTag(Presentation.BULLET, s); } public void pre(string s) { this.simpleTag(Presentation.PRE, s); } public void startHeader() { this.xw.WriteStartElement(Presentation.HEADER); } public void endHeader() { this.xw.WriteEndElement(); } public void startLine() { this.xw.WriteStartElement(Presentation.LINE); } public void endLine() { this.xw.WriteEndElement(); } public void startBullet() { this.xw.WriteStartElement(Presentation.BULLET); } public void endBullet() { this.xw.WriteEndElement(); } private void simpleTag(string tag, string s) { this.xw.WriteStartElement(tag); this.text(s); this.xw.WriteEndElement(); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/ProcessInvokeAsyncWorker.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; /// /// Representation of an asynchronous verb worker. /// internal class ProcessInvokeAsyncWorker : IVerbWorker { /// /// The private working directory for this worker to work in. /// private WorkingDirectory workingDirectory; /// /// The verb whose worker this is. /// private IProcessInvokeAsyncVerb verb; /// /// The executable to run. /// private string executable; /// /// The command line arguments to provide to the executable. /// private string[] args; /// /// How to handle the exit code from running the executable. /// private ProcessExitCodeHandling exitCodeHandling; /// /// Where to (optionally) collect diagnostics. /// private BuildObject failureBase; /// /// Where to capture standard out (I think). /// private BuildObject captureStdout; /// /// Debugging text for something or another. /// private string dbgText; /// /// Whether to allow an absolute (rather than relative) file path to the executable. /// private bool allowAbsoluteExe; /// /// Whether to allow absolute (rather than relative) file paths as arguments. /// private bool allowAbsoluteArgs; /// /// The working directory to use. /// private string workingDirOverride; /// /// Whether to return the standard output from the process in the Complete call. /// private bool returnStandardOut; /// /// Whether to return the error output from the process in the Complete call. /// private bool returnStandardError; /// /// The IProcessInvoker (either a ProcessInvoker or a CloudSubmitter) instance we use to run this executable (either locally or in the cloud). /// private IProcessInvoker pinv; /// /// Whether to run the executable in the cloud. /// private bool useCloudExecution; /// /// List of input files needed by the executable. /// private List inputFiles; /// /// List of output files produced by the executable. /// private List outputFiles; /// /// Initializes a new instance of the ProcessInvokeAsyncWorker class. /// /// The private working directory for this worker to work in. /// The verb whose worker this is. /// The executable to run. /// The command line arguments to provide to the executable. /// How to handle the return code from running the executable. /// Not sure what this is -- some debugging/diagnostic thing. /// Where to capture standard out (I think). /// Debugging text for something or another. /// Whether to allow an absolute (rather than relative) file path to the executable. /// Whether to allow absolute (rather than relative) file paths as arguments. /// The working directory to use. /// Whether to return the standard output of the process. /// Whether to return the standard error output of the process. /// Whether to allow this worker to run the executable in the cloud. /// /// TODO: executable should be a BuildObject, like every other dependency. /// public ProcessInvokeAsyncWorker( WorkingDirectory workingDirectory, IProcessInvokeAsyncVerb verb, string executable, string[] args, ProcessExitCodeHandling exitCodeHandling, BuildObject failureBase, BuildObject captureStdout = null, string dbgText = null, bool allowAbsoluteExe = false, bool allowAbsoluteArgs = false, string workingDirOverride = null, bool returnStandardOut = false, bool returnStandardError = false, bool allowCloudExecution = false) { this.workingDirectory = workingDirectory; this.verb = verb; this.executable = executable; this.args = args; this.exitCodeHandling = exitCodeHandling; this.failureBase = failureBase; this.captureStdout = captureStdout; this.dbgText = dbgText; this.allowAbsoluteExe = allowAbsoluteExe; this.allowAbsoluteArgs = allowAbsoluteArgs; this.workingDirOverride = workingDirOverride; this.returnStandardOut = returnStandardOut; this.returnStandardError = returnStandardError; if (allowCloudExecution) { // Verbs cannot allow cloud execution if they allow absolute paths to exes or args. Util.Assert(!this.allowAbsoluteExe); Util.Assert(!this.allowAbsoluteArgs); Util.Assert(this.workingDirOverride == null); if (BuildEngine.theEngine.CloudExecutionQueue != null) { // We're good to go for cloud execution. this.useCloudExecution = true; // REVIEW: If there are other things we should do on the main thread prior to CloudSubmitter invocation, we should do them here. this.inputFiles = this.GetInputFiles(); this.outputFiles = new List(this.verb.getOutputs()); this.outputFiles.AddRange(this.verb.getFailureOutputs()); } } } /// /// Indicates whether this work needs to be scheduled asynchronously. /// Since this is the asynchronous implementation, always returns Async. /// /// Always returns Async. public VerbWorkerType IsSync() { return VerbWorkerType.Async; } /// /// Gets the private working directory this verb executes in. /// /// The directory this verb executes in. public WorkingDirectory GetWorkingDirectory() { return this.workingDirectory; } /// /// Performs the slow, asynchronous work. /// /// /// Does not run on the main thread, so should not access caches /// (or do anything else that expects to be synchronous). /// When this returns, the work is expected to have completed. /// public void RunAsync() { if (this.useCloudExecution) { // REVIEW: Would prefer to use the verb's input hash value as the request identifier below. this.pinv = new CloudSubmitter( Path.GetRandomFileName(), this.workingDirectory, this.inputFiles, this.outputFiles, this.executable, this.args, this.failureBase, this.captureStdout, this.dbgText); } else { this.pinv = new ProcessInvoker( this.workingDirectory, this.executable, this.args, this.failureBase, this.captureStdout, this.dbgText, this.allowAbsoluteExe, this.allowAbsoluteArgs, this.workingDirOverride); } } /// /// Performs the completion work for Async workers, and is called /// after the runAsync method returns. Returns the ultimate /// disposition of the activity. /// /// /// This method runs synchronously on the main thread. /// It can tidy up the state after async work, and store results /// in the Repository. /// Thou shalt not return Stale. /// /// The disposition of this verb's worker's work. public Disposition Complete() { this.verb.RecordProcessInvokeCpuTime(this.pinv.CpuTime); string stdout = null; if (this.returnStandardOut) { stdout = this.pinv.GetStdout(); } string stderr = null; if (this.returnStandardError) { stderr = this.pinv.GetStderr(); } Disposition disposition; if (this.exitCodeHandling == ProcessExitCodeHandling.NonzeroIsOkay || this.pinv.ExitCode == 0) { disposition = new Fresh(); } else { // Sheesh. Some tools emit error messages to stdout. // REVIEW: Provide full command line here rather than just executable (like old version did)? Failed f = new Failed(this.pinv.GetStdout() + this.pinv.GetStderr()); f.AddError("Executable: " + this.executable + "\n"); disposition = f; } return this.verb.Complete(this.workingDirectory, this.pinv.CpuTime, stdout, stderr, disposition); } /// /// Gets the input files needed for verb execution. /// /// List of the verb's input files. private List GetInputFiles() { DependencyDisposition ddisp; List inputFiles = new List(); foreach (BuildObject input in this.verb.getDependencies(out ddisp)) { if (!(input is VirtualBuildObject)) { inputFiles.Add(input); } } return inputFiles; } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/ProcessInvoker.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Diagnostics; using System.IO; using System.Text; /// /// Represents the invoker of processes that do the work of a verb worker. /// public class ProcessInvoker : IProcessInvoker { /// /// Whether to always emit diagnostic output. /// private const bool AlwaysEmitDiagnostics = true; /// /// The CPU time used by the process, in seconds. /// private double cpuTime; /// /// The exit code returned by the process. /// private int exitCode; /// /// The stream used to collect standard out to a file (if requested). /// private StreamWriter stdoutFile; /// /// The temporary file in which to store standard out (if requested). /// private BuildObject tmpStdout; /// /// Where standard out is collected by default. /// private StringBuilder stdout; /// /// Where standard error is collected. /// private StringBuilder stderr; /// /// The private working directory for the process we invoke. /// private WorkingDirectory workingDirectory; /// /// Initializes a new instance of the ProcessInvoker class. /// /// The working directory the process is started in. /// The executable to run. /// The command line arguments to provide to the executable. /// Not sure what this is -- some debugging/diagnostic thing. /// Where to (optionally) capture standard out. /// Debugging text for something or another. /// Whether to allow an absolute (rather than relative) file path to the executable. /// Whether to allow absolute (rather than relative) file paths as arguments. /// The working directory to use. public ProcessInvoker( WorkingDirectory workingDirectory, string executable, string[] args, BuildObject failureBase, BuildObject captureStdout = null, string dbgText = null, bool allowAbsoluteExe = false, bool allowAbsoluteArgs = false, string workingDirOverride = null) { // Catch bad verb authors before they hurt themselves. Util.Assert(allowAbsoluteExe || !executable.Contains(":")); // Hey, this looks like an absolute path! Use .getRelativePath(); it makes your output more stable. foreach (string arg in args) { // Pardon my distasteful heuristic to avoid flagging /flag:value args. Util.Assert(allowAbsoluteArgs || arg.Length < 2 || arg[1] != ':'); // Hey, this looks like an absolute path! Use .getRelativePath() to tolerate crossing machine boundaries. } this.workingDirectory = workingDirectory; this.stdout = new StringBuilder(); this.stderr = new StringBuilder(); using (Job job = new Job()) { using (Process proc = new Process()) { if (allowAbsoluteExe) { proc.StartInfo.FileName = executable; } else { // TODO: *All* async verbs need to list their executable (and all the libs it depends upon) as dependencies. proc.StartInfo.FileName = workingDirectory.PathTo(executable); } // TODO Is there a better way to escape the args to avoid problems with spaces? proc.StartInfo.Arguments = string.Join(" ", args); proc.StartInfo.WorkingDirectory = workingDirOverride == null ? workingDirectory.Root : workingDirOverride; proc.StartInfo.RedirectStandardOutput = true; // REVIEW: Maybe we should always capture stdout in a StringBuilder and just write it out to a file afterwards if requested? if (captureStdout != null) { this.tmpStdout = new BuildObject(captureStdout.getRelativePath() + ".tmp"); this.stdoutFile = new StreamWriter(workingDirectory.PathTo(this.tmpStdout)); proc.OutputDataReceived += new DataReceivedEventHandler(this.StdoutRedirectHandler); } else { // Collect stdout here for diagnostics. proc.OutputDataReceived += new DataReceivedEventHandler(this.StdoutHandler); } proc.StartInfo.RedirectStandardError = true; proc.ErrorDataReceived += new DataReceivedEventHandler(this.StderrHandler); proc.StartInfo.UseShellExecute = false; string commandLine = proc.StartInfo.FileName + " " + proc.StartInfo.Arguments; if (failureBase != null && AlwaysEmitDiagnostics) { // In diagnostic mode, we emit the command line twice, once ahead in case Boogie decides // to run away and never come back. BuildObject failureBatObj = failureBase.makeOutputObject(".bat"); workingDirectory.CreateDirectoryFor(failureBatObj); File.WriteAllText(workingDirectory.PathTo(failureBatObj), commandLine); } proc.Start(); job.AddProcess(proc); proc.BeginOutputReadLine(); proc.BeginErrorReadLine(); proc.WaitForExit(); this.cpuTime = job.GetCpuTime().TotalSeconds; this.exitCode = proc.ExitCode; if (this.stdoutFile != null) { this.stdoutFile.Close(); } if (failureBase != null && AlwaysEmitDiagnostics) { workingDirectory.CreateDirectoryFor(failureBase); File.WriteAllText(workingDirectory.PathTo(failureBase.makeOutputObject(".bat")), commandLine); File.WriteAllText(workingDirectory.PathTo(failureBase.makeOutputObject(".txt")), dbgText); File.WriteAllText(workingDirectory.PathTo(failureBase.makeOutputObject(".stdout")), this.GetStdoutString()); File.WriteAllText(workingDirectory.PathTo(failureBase.makeOutputObject(".stderr")), this.GetStderr()); } } } // REVIEW: Add Delete, Exists and Move methods to WorkingDirectory class? if (this.tmpStdout != null && File.Exists(workingDirectory.PathTo(this.tmpStdout))) { // REVIEW: Nothing should be here. Bother with the delete? File.Delete(workingDirectory.PathTo(captureStdout)); File.Move(workingDirectory.PathTo(this.tmpStdout), workingDirectory.PathTo(captureStdout)); this.tmpStdout = null; } } /// /// Gets the exit code returned by the process. /// public int ExitCode { get { return this.exitCode; } } /// /// Gets the CPU time used by the process, in seconds. /// public double CpuTime { get { return this.cpuTime; } } /// /// Gets the process's standard output in the default case. /// Does not return the standard output if it is redirected to a file (i.e. if CaptureStdout is non-null). /// /// The process's standard output. public string GetStdout() { return this.stdout.ToString(); } /// /// Gets the process's standard error output.. /// /// The process's standard error output. public string GetStderr() { return this.stderr.ToString(); } /// /// Gets the process's standard output, regardless of whether it was redirected to a file. /// /// The process's standard output. private string GetStdoutString() { if (this.tmpStdout != null) { return File.ReadAllText(this.workingDirectory.PathTo(this.tmpStdout)); } else { return this.GetStdout(); } } /// /// Alternate handler for the OutputDataReceived event. /// Stores the data in the previously specified file. /// /// The parameter is not used. /// Contains a line of characters read from the process's standard out. private void StdoutRedirectHandler(object sendingProcess, DataReceivedEventArgs dataLine) { this.stdoutFile.WriteLine(dataLine.Data); } /// /// Default handler for the OutputDataReceived event. /// Stores the data in a local StringBuilder instance. /// /// The parameter is not used. /// Contains a line of characters read from the process's standard out. private void StdoutHandler(object sendingProcess, DataReceivedEventArgs dataLine) { // REVIEW: Can't we use AppendLine here instead? this.stdout.Append(dataLine.Data + "\n"); } /// /// Handler for the ErrorDataReceived event. /// Stores the data in a local StringBuilder instance. /// /// The parameter is not used. /// Contains a line of characters read from the process's standard error. private void StderrHandler(object sendingProcess, DataReceivedEventArgs dataLine) { // REVIEW: Can't we use AppendLine here instead? this.stderr.Append(dataLine.Data + "\n"); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/Program.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; internal class Program { private bool useCloudExecution; private bool useCloudCache; private BackgroundWorker backgroundWorker; private string[] args; private VerificationRequest verificationRequest = new VerificationRequest(); public Program() { this.useCloudExecution = false; this.useCloudCache = true; this.backgroundWorker = new BackgroundWorker(); } static void Main(string[] args) { new Program().main(args); ////DbgHashSpeedTest.thing(); ////DbgFileCopySpeedTest.thing(); } void usage(string msg) { Logger.WriteLine(msg); Logger.WriteLine(string.Format( "Usage: {0} [opts] [Verb Target]*", System.AppDomain.CurrentDomain.FriendlyName)); throw new UserError("Invalid options"); } string ironRoot; int jobParallelism = 1; List verbs = new List(); string html_output = null; IroncladAppVerb.TARGET target_platform = IroncladAppVerb.TARGET.BARE_METAL; DafnyCCVerb.FramePointerMode useFramePointer = DafnyCCVerb.FramePointerMode.NoFramePointer; private bool releaseBuild = true; int argi; string takeArg(string expectedThing) { if (argi >= args.Count()) { usage("Expected " + expectedThing); } string rc = args[argi]; argi += 1; return rc; } SourcePath conditionSourcePath(string path) { return new SourcePath(path); } void fixIronRoot() { if (ironRoot == null) { ironRoot = getDefaultIronRoot(); if (ironRoot == null) { usage("--ironRoot not specified and cannot infer ironRoot"); } } BuildEngine.theEngine.setIronRoot(ironRoot); } void parseArgs(string[] args) { this.args = args; argi = 0; while (argi < args.Count()) { string next = takeArg("option or verb"); // Should always succeed due to while condition. if (next.StartsWith("-")) { if (next.Equals("--ironRoot")) { if (this.ironRoot != null) { usage("ironRoot set after use"); } this.ironRoot = takeArg("value for ironRoot"); } else if (next.Equals("-j") || next.Equals("--jobs")) { this.jobParallelism = Int32.Parse(takeArg("value for jobs")); } else if (next.Equals("--localcache")) { BuildEngine.theEngine.setLocalCache(takeArg("path for localcache")); } else if (next.ToLower().Equals("--cloudcache")) { this.useCloudCache = true; } else if (next.ToLower().Equals("--no-cloudcache")) { this.useCloudCache = false; } else if (next.Equals("--cloudexecution")) { this.useCloudExecution = true; } else if (next.ToLower().Equals("--verify")) { this.verificationRequest.verifyMode = VerificationRequest.VerifyMode.Verify; } else if (next.ToLower().Equals("--no-verify")) { this.verificationRequest.verifyMode = VerificationRequest.VerifyMode.NoVerify; } else if (next.ToLower().Equals("--no-symdiff")) { this.verificationRequest.verifyMode = VerificationRequest.VerifyMode.NoSymDiff; } else if (next.ToLower().Equals("--verify-select")) { this.verificationRequest.verifyMode = VerificationRequest.VerifyMode.SelectiveVerify; this.verificationRequest.selectiveVerifyModuleNames.Add(takeArg("filename for selective-verify")); } else if (next.ToLower().Equals("--html")) { this.html_output = takeArg("filename for html report"); } else if (next.ToLower().Equals("--windows")) { this.target_platform = IroncladAppVerb.TARGET.WINDOWS; } else if (next.ToLower().Equals("--useframepointer")) { this.useFramePointer = DafnyCCVerb.FramePointerMode.UseFramePointer; } else if (next.ToLower().Equals("--debug")) { this.releaseBuild = false; } else { usage("unrecognized option " + next); } } else { string verb = next; string target = takeArg("verb-target"); fixIronRoot(); if (verb.Equals("DafnyVerifyTree")) { verbs.Add(new VerificationResultSummaryVerb(new DafnyVerifyTreeVerb(conditionSourcePath(target)))); } else if (verb.Equals("BatchDafny")) { if (!target.EndsWith(".batch")) { usage("Batching expects a .batch file containing a list of .dfy files"); } verbs.Add(new VerificationResultSummaryVerb(new BatchVerifyVerb(conditionSourcePath(target), BatchVerifyVerb.BatchMode.DAFNY, this.verificationRequest, useFramePointer))); } else if (verb.Equals("BatchApps")) { if (!target.EndsWith(".batch")) { usage("Batching expects a .batch file containing a list of .dfy files"); } verbs.Add(new VerificationResultSummaryVerb(new BatchVerifyVerb(conditionSourcePath(target), BatchVerifyVerb.BatchMode.APP, this.verificationRequest, useFramePointer))); } else if (verb.Equals("Beat")) { verbs.Add(new BeatVerb(BuildEngine.theEngine.getVerveContextVerb(PoundDefines.empty()), conditionSourcePath(target), appLabel: null)); } else if (verb.Equals("Boogie")) { verbs.Add(new BoogieVerb(BuildEngine.theEngine.getVerveContextVerb(PoundDefines.empty()), conditionSourcePath(target), symdiff: this.verificationRequest.getSymDiffMode())); } else if (verb.Equals("IroncladApp")) { verbs.Add(new IroncladAppVerb(conditionSourcePath(target), target_platform, this.useFramePointer, this.verificationRequest)); } else if (verb.Equals("IronfleetApp")) { verbs.Add(new IronfleetAppVerb(conditionSourcePath(target), this.verificationRequest, this.releaseBuild)); } else if (verb.Equals("DafnyCompileOne")) { verbs.Add(new DafnyCompileOneVerb(conditionSourcePath(target))); } else if (verb.Equals("VSSolution")) { verbs.Add(new VSSolutionVerb(new SourcePath(target, SourcePath.SourceType.Tools))); } else if (verb.Equals("nmake")) { verbs.Add(new NmakeVerb(new SourcePath(target, SourcePath.SourceType.Tools))); } else if (verb.Equals("BootableApp")) { verbs.Add(new BootableAppVerb(conditionSourcePath(target), this.useFramePointer, this.verificationRequest)); } else { usage("Unknown verb " + verb); } } } fixIronRoot(); } private IItemCache GetItemCache() { string localCacheDirectory = Path.Combine( BuildEngine.theEngine.getIronRoot(), BuildEngine.theEngine.getLocalCache()); if (this.useCloudCache) { try { BuildEngine.theEngine.CloudCache = new ItemCacheCloud(); return new ItemCacheMultiplexer( new ItemCacheLocal(localCacheDirectory), BuildEngine.theEngine.CloudCache, this.backgroundWorker); } catch (Microsoft.WindowsAzure.Storage.StorageException) { // - // This will handle the case of being disconnected // at NuBuild launch time. // - Logger.WriteLine("Failed to create multiplexed cloud cache -- falling back to just local cache."); } } return new ItemCacheLocal(localCacheDirectory); } const string IRONROOT_sentinel = "IRONROOT.sentinel"; string getAssemblyPath() { string assyUri = System.Reflection.Assembly.GetExecutingAssembly().CodeBase; string assyPath = new Uri(assyUri).LocalPath; return assyPath; } string getDefaultIronRoot() { string exepath = Path.GetDirectoryName(getAssemblyPath()); exepath = Path.GetFullPath(exepath); string[] parts = exepath.Split(new char[] { '\\' }); for (int i = parts.Length; i > 0; i--) { string proposal = string.Join("\\", parts.Take(i)); if (File.Exists(Path.Combine(proposal, IRONROOT_sentinel))) { return proposal; } } return null; } void logNubuildInvocation(string[] args) { Logger.WriteLine(string.Format("{0} {1}", getAssemblyPath(), string.Join(" ", args))); } // NB this file is found in the default ironroot, since we // grab it before we parse your --ironroot argument. private const string NUBUILD_CONFIG = "nubuild.config"; private IEnumerable fetchConfigArgs() { string config_path = Path.Combine(getDefaultIronRoot(), NUBUILD_CONFIG); if (!File.Exists(config_path)) { return new string[] { }; } List config_args = new List(); foreach (string line in File.ReadAllLines(config_path)) { foreach (string word in line.Trim().Split(new char[] { ' ' })) { config_args.Add(word); } } return config_args; } void main(string[] cmdline_args) { string[] all_args = fetchConfigArgs().Concat(cmdline_args).ToArray(); logNubuildInvocation(all_args); try { parseArgs(all_args); } catch (UserError err) { usage(err.Message); } BuildEngine.theEngine.ItemCache = GetItemCache(); BuildEngine.theEngine.Repository = new Repository(BuildEngine.theEngine.ItemCache); if (this.useCloudExecution) { if (!this.useCloudCache) { usage("Cloud Execution requires Cloud Cache!"); } BuildEngine.theEngine.CloudReportQueueName = Path.GetRandomFileName().Substring(0, 8); BuildEngine.theEngine.CloudExecutionQueue = new CloudExecutionQueue(BuildEngine.theEngine.CloudReportQueueName); Logger.WriteLine("Using cloud report queue name: " + BuildEngine.theEngine.CloudReportQueueName); } Scheduler scheduler = new Scheduler(jobParallelism); scheduler.addTargetVerbs(verbs); ////try ////{ scheduler.parallelSchedule(); ////} ////catch (Exception ex) ////{ //// scheduler.dbgDisplayCounts(); //// throw; ////} IEnumerable targets = scheduler.getTargets(); BuildObject outputTarget = null; if (targets.Count() > 0) { outputTarget = targets.First(); } else { Logger.WriteLine("No targets requested."); } if (targets.Count() > 1) { // TODO need a better story for relaying failure results. Right now // they get stuck in the results cache, but don't appear where we // can find them. Emit to a log, or to files in nuobj? Logger.WriteLine("Multiple targets build. First result follows."); } if (outputTarget != null) { Disposition d = scheduler.getObjectDisposition(outputTarget); if (d is Fresh) { ASCIIPresentater ascii = new ASCIIPresentater(); IVerb verb = scheduler.getParent(outputTarget); verb.getPresentation().format(ascii); Logger.Write(ascii.ToString()); if (this.html_output != null) { HTMLPresentater html = new HTMLPresentater(); verb.getPresentation().format(html); try { using (StreamWriter sw = new StreamWriter(this.html_output)) { sw.Write(html.ToString()); } } catch (Exception e) { Logger.WriteLine("Failed to write html output to file: " + html_output); Logger.WriteLine("Exception was: " + e); } } } else { Logger.WriteLine("Build failed."); foreach (string msg in d.getMessages()) { Logger.Write(msg); } } } else if (targets.Count() == 0) { Logger.WriteLine("No targets requested."); } else { Logger.WriteLine("Multiple targets built. Look for results in nuobj/."); } // - // We have to explicitly ask the BackgroundWorker thread to exit // as it will prevent the process from exiting until it does. // - this.backgroundWorker.StopWork(); // - // Report what the background worker accomplished during this run. // - this.backgroundWorker.WaitForCompletion(); Logger.WriteLine(string.Format("Background Worker completed {0} work items out of {1} queued.", this.backgroundWorker.GetWorkItemsPerformed, this.backgroundWorker.GetWorkItemsQueued)); if (this.backgroundWorker.GetWorkItemsFailed != 0) { Logger.WriteLine(string.Format( "{0} work item procedures failed (threw an exception).", this.backgroundWorker.GetWorkItemsFailed)); } } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/Properties/AssemblyInfo.cs ================================================ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("NuBuild")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("NuBuild")] [assembly: AssemblyCopyright("Copyright © 2014")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("1855bc44-97d2-41da-89fc-dae901580a54")] // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/Repository.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; /// /// Tracker of BuildObjects, in their various forms. /// For virtual build objects, also provides the content store. /// /// /// There is only one instance of this class in the system. /// This class includes functionality from the old ResultCache and /// NuObjContents classes. /// Old NuObjContents comment: /// This class keeps track of the data we've stored into nuobj/. /// The invariant is that we never read data out of nuobj/ if it's /// not data we put there ourselves this execution (perhaps by /// fetching it from the cache). Data from the cache is safe, /// because it is tracked by concreteIdentifier. But data in /// nuobj/ may be stale, leading us to build the wrong thing. /// (A wrong thing would be correctly labeled, so it won't poison /// the cache, but it wouldn't be the output the user asked for.) /// internal class Repository { /// /// Collection of information about build objects. /// private Dictionary entries; /// /// Record of the verbs for which we've already added the /// output objects resulting from their (cached) execution. /// /// /// This avoids re-adding the entire set if we ask for another object /// in the same verb's output list. Note that this ignores the hash /// value of the verb; it assumes that the hash values don't change /// across a run of this process. /// private HashSet alreadyAddedVerbs; /// /// The item cache we're using. /// private IItemCache itemCache; /// /// Initializes a new instance of the Repository class. /// /// The item cache we're using. public Repository(IItemCache itemCache) { this.itemCache = itemCache; this.entries = new Dictionary(); this.alreadyAddedVerbs = new HashSet(); } /// /// Reads a build object from the local filesystem and stores it in the /// cache. /// /// /// Private directory for verb execution. /// /// The build object to store in the cache. /// /// Disposition of verb which created this object (if known). /// /// A BuildObjectValuePointer describing the object. public BuildObjectValuePointer Store(WorkingDirectory workingDirectory, BuildObject obj, Disposition disposition) { string contentHash = Util.hashFilesystemPath(workingDirectory.PathTo(obj)); this.itemCache.StoreItemFromFile(ItemCacheContainer.Objects, contentHash, workingDirectory.PathTo(obj)); this.Add(obj, disposition, contentHash, null); return new BuildObjectValuePointer(contentHash, obj.getRelativePath()); } /// /// Fetches a build object and stores it in the local filesystem. /// /// /// Directory under which to store the fetched object. /// /// The object to fetch. public void Fetch(WorkingDirectory workingDirectory, BuildObject obj) { RepositoryEntry entry = this.FetchFresh(obj); // REVIEW: best way to determine this is a source file? ItemCacheContainer container; if (obj is SourcePath) { container = ItemCacheContainer.Sources; } else { container = ItemCacheContainer.Objects; } this.itemCache.FetchItemToFile(container, entry.Hash, workingDirectory.PathTo(obj)); } /// /// Gets a readable stream for the given build object contents. /// /// The object in question. /// An open, readable stream to the contents. public TextReader OpenRead(BuildObject obj) { RepositoryEntry entry = this.FetchFresh(obj); // REVIEW: best way to determine this is a source file? ItemCacheContainer container; if (obj is SourcePath) { container = ItemCacheContainer.Sources; } else { container = ItemCacheContainer.Objects; } byte[] contents = this.itemCache.FetchItem(container, entry.Hash); MemoryStream stream = new MemoryStream(contents, false); return new StreamReader(stream); } /// /// Stores a result record in the cache. /// /// /// Item cache hash key to store result under. /// /// The result record to store. public void StoreResult(string inputHash, ResultSummaryRecord result) { ItemCacheContainer container; if (result.IsVerificationTimeout || (result.Disposition is Failed)) { container = ItemCacheContainer.FailedResults; } else { container = ItemCacheContainer.Results; } using (MemoryStream outStream = new MemoryStream()) { using (StreamWriter outWriter = new StreamWriter(outStream)) { outWriter.Write(result.ToXml()); } this.itemCache.StoreItem(container, inputHash, outStream.ToArray()); } } /// /// Fetches a result record from the cache. /// /// /// Item cache hash key the result is stored under. /// /// /// Whether to return cached failures as well as successes. /// /// /// The result record requested if available, otherwise returns a /// summary record with Stale disposition. /// public ResultSummaryRecord FetchResult(string inputHash, bool includeFailedResults = false) { byte[] result = this.itemCache.FetchItem(ItemCacheContainer.Results, inputHash); if ((result == null) && includeFailedResults) { result = this.itemCache.FetchItem(ItemCacheContainer.FailedResults, inputHash); } if (result != null) { MemoryStream resultStream = new MemoryStream(result); try { using (StreamReader inReader = new StreamReader(resultStream)) { string xmlSummary = inReader.ReadToEnd(); return ResultSummaryRecord.FromXml(xmlSummary); } } catch (System.Xml.XmlException ex) { throw new ObjectMissingFromCacheException(inputHash, "Malformed xml: " + ex.ToString()); } finally { resultStream.Dispose(); } } else { return new ResultSummaryRecord(new Stale(), new BuildObjectValuePointer[] { }, false); } } /// /// Add information about a virtual object to the Repository, /// including its contents. /// /// The object in question. /// /// Disposition of the verb which created this object. /// /// Contents of the object. public void StoreVirtual(BuildObject obj, Disposition disposition, VirtualContents contents) { Util.Assert(obj is VirtualBuildObject); this.Add(obj, disposition, null, contents); } /// /// Retrieves the virtual content referenced by the given build object. /// /// The object in question. /// The virtual contents of the object. public VirtualContents FetchVirtual(BuildObject obj) { return this.FetchFresh(obj).VirtualContents; } /// /// Gets the disposition of the verb that generated a build object. /// /// The object in question. /// Disposition of the object. public Disposition GetDisposition(BuildObject obj) { RepositoryEntry value = this.GetValue(obj); if (value != null) { return value.Disposition; } return new Stale(); } /// /// Gets the hash of an object registered with this Repository. /// /// The object in question. /// /// The hash of the object (if known), otherwise null. /// public string GetHash(BuildObject obj) { string hash = null; RepositoryEntry value = this.GetValue(obj); if (value != null) { if (value.Disposition is Failed) { hash = null; } else if (obj is VirtualBuildObject) { hash = "virtual"; } else { hash = value.Hash; } } return hash; } /// /// Adds the output objects from a cached verb execution to the /// repository, and ensures they are present in the item cache. /// /// The verb whose outputs to add. /// /// The result summary record of the verb execution. /// /// /// Call only when output objects are known to be cached /// (i.e. because FetchResult returned non-Stale). /// REVIEW: This function probably shouldn't be in this file. /// It does something similar for cached verb results that /// the scheduler's recordResult method does for new verb /// executions. Move this there and/or refactor? /// public void AddVerbResults(IVerb verb, ResultSummaryRecord resultRecord) { if (this.alreadyAddedVerbs.Contains(verb)) { // We only need to add a cached verb execution's outputs once. return; } Disposition disposition = resultRecord.Disposition; // REVIEW: In the below, some of these IEnumerables should be // HashSets, and the HashSet should be a simple List. // Create a collection of the potential outputs. IEnumerable outputs = verb.getOutputs(); IEnumerable failureOutputs = verb.getFailureOutputs(); outputs = outputs.Concat(failureOutputs); Dictionary potentialOutputs = new Dictionary(); foreach (BuildObject obj in outputs) { potentialOutputs.Add(obj.getRelativePath(), obj); } // Compare the actual outputs with the potential outputs, // and add the actual ones to the repository. HashSet recorded = new HashSet(); foreach (BuildObjectValuePointer actualOutput in resultRecord.Outputs) { if (potentialOutputs.ContainsKey(actualOutput.RelativePath)) { BuildObject obj = potentialOutputs[actualOutput.RelativePath]; // TODO: Verify that the object exists in the item cache! this.AddObject(obj, disposition, actualOutput.ObjectHash); recorded.Add(obj); // Store a copy of this verb output as a file in the real nuobj directory. Util.Assert(actualOutput.RelativePath.StartsWith(BuildEngine.theEngine.getObjRoot(), StringComparison.Ordinal)); this.itemCache.FetchItemToFile(ItemCacheContainer.Objects, actualOutput.ObjectHash, IronRootDirectory.PathTo(actualOutput.RelativePath)); } else { // Complain if we find interloping outputs. throw new Exception("Distressing: some actual verb outputs aren't in the verb's list of potential outputs"); } } // Create a collection of missing outputs. IEnumerable unrecorded = outputs.Except(recorded).Except(failureOutputs); // For non-Failed verb runs, complain if all expected outputs don't // show up in the actual outputs. Util.Assert(unrecorded.Count() == 0 || disposition is Failed); // For cached verb runs with permanent failures (i.e. disposition // is Failed), we want to mark all of the expected outputs as Failed // even if no corresponding actual output was produced during the // failed verb run. foreach (BuildObject obj in unrecorded) { this.AddObject(obj, disposition, null); } // Remember that we've already added this verb's outputs. this.alreadyAddedVerbs.Add(verb); } /// /// Add information about an object to the Repository. /// The object path must be under the object root. /// /// The object in question. /// /// Disposition of the verb which created this object. /// /// Hash of the object's contents. public void AddObject(BuildObject obj, Disposition disposition, string hash) { Util.Assert(obj.getRelativePath().StartsWith(BuildEngine.theEngine.getObjRoot(), StringComparison.Ordinal)); this.Add(obj, disposition, hash, null); } /// /// Gets the number of entries in this repository, for debugging. /// /// Number of objects recorded in this repository. internal int DbgCacheSize() { return this.entries.Count(); } /// /// Fetches information about the given object in this repository. /// /// The object to fetch. /// Information about the object. private RepositoryEntry FetchFresh(BuildObject obj) { RepositoryEntry value = this.GetValue(obj); if (value == null) { throw new ObjectNotReadyException(obj); } if (value.Disposition is Failed) { throw new ObjectFailedException(obj, (Failed)value.Disposition); } Util.Assert(value.Disposition is Fresh); // This isn't really a 'not ready' condition; we shouldn't be here. REVIEW: What is meant by this comment? return value; } /// /// Gets information about an object in this repository. /// Will add missing source objects to the repository as needed. /// /// The object to look up. /// Information about the object. /// /// Returns null if obj isn't in this run's cache. /// Cannot return value.disposition==Stale, I guess? /// private RepositoryEntry GetValue(BuildObject obj) { if (this.entries.ContainsKey(obj)) { return this.entries[obj]; } else { SourcePath src = obj as SourcePath; if (src != null) { // Special case to get local source files into the // repository (and the item cache). // REVIEW: Should we require that source files are explicitly added? try { // Complain if someone uses tabs or non-CRLF line endings in a source file. // Visual Studio is pretty insistent on using tabs in solution (.sln) files, so we let it. if ((src.Type == SourcePath.SourceType.Src) && (src.getExtension() != ".sln")) { if (!Util.CheckSourceFileForBadCharacters(IronRootDirectory.PathTo(obj))) { throw new SourceConfigurationError("Bad characters (tabs?) or non-CRLF line endings in source file " + obj.getRelativePath()); } } string hash = Util.hashFilesystemPath(IronRootDirectory.PathTo(obj)); this.itemCache.StoreItemFromFile(ItemCacheContainer.Sources, hash, IronRootDirectory.PathTo(obj)); this.Add(obj, new Fresh(), hash, null); } catch (IOException) { throw new SourceConfigurationError("Cannot find source path " + obj.getRelativePath()); } return this.entries[obj]; } else { return null; } } } /// /// Add information about an object to the Repository. /// /// The object to add. /// /// Disposition of the verb which created this object. /// /// Hash of the object's contents. /// Contents of the object (if virtual). private void Add(BuildObject obj, Disposition disposition, string hash, VirtualContents contents) { // Every object in the repository should either have a hash value // or virtual contents, but not both. Util.Assert((string.IsNullOrEmpty(hash) && contents != null) || (!string.IsNullOrEmpty(hash) && (contents == null))); // Check to see if the object is already in this repository. if (this.entries.ContainsKey(obj)) { // We shouldn't be adding conflicting information for // the same object during the same build run. RepositoryEntry entry = this.entries[obj]; Util.Assert(entry.Disposition.GetType() == disposition.GetType()); Util.Assert(entry.Hash.Equals(hash, StringComparison.Ordinal)); Util.Assert(entry.VirtualContents == contents); // Don't replace existing entry with equivalent. return; } this.entries[obj] = new RepositoryEntry(disposition, hash, contents); } /// /// Information we keep about build objects in our collection. /// private class RepositoryEntry { /// /// Disposition of the verb that created this object. /// private Disposition disposition; /// /// Hash of the object's contents (if non-virtual). /// private string hash; /// /// For objects not stored in the item cache or the filesystem, /// here's the computed value. /// private VirtualContents virtualContents; /// /// Initializes a new instance of the RepositoryEntry class. /// /// /// Disposition of the verb that created this object. /// /// Hash of the object's contents. /// /// Computed value of the object (if virtual, null otherwise). /// public RepositoryEntry(Disposition disposition, string hash, VirtualContents virtualContents) { this.hash = hash; this.disposition = disposition; this.virtualContents = virtualContents; } /// /// Gets the hash of the object's contents. /// public string Hash { get { return this.hash; } } /// /// Gets the disposition of the verb that created this object. /// public Disposition Disposition { get { return this.disposition; } } /// /// Gets the computed value of the object (if a virtual object, /// returns null otherwise). /// public VirtualContents VirtualContents { get { return this.virtualContents; } } } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/ResultSummaryRecord.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; using System.Text; using System.Xml; /// /// Representation of the result of a particular verb's execution. /// public class ResultSummaryRecord { /// /// The XML element name for this object. /// public const string XmlTag = "ResultSummaryRecord"; /// /// The XML attribute name for the IsVerificationTimeout value. /// public const string XmlIsVerificationTimeoutAttribute = "IsVerificationTimeout"; /// /// The verb whose execution this is the result of. /// private IVerb verb; /// /// The disposition of the verb execution. /// private Disposition disposition; /// /// Whether this result is a rejectable failure. /// private bool isRejectableFailure; /// /// The build objects that were produced by this verb execution. /// private List outputs; /// /// Initializes a new instance of the ResultSummaryRecord class. /// /// /// The verb whose execution this is the result of. /// /// /// The disposition of the verb execution. /// /// /// The build objects that were produced by this verb execution. /// internal ResultSummaryRecord( IVerb verb, Disposition disposition, IEnumerable outputs) : this(verb, disposition, outputs, false) { } /// /// Initializes a new instance of the ResultSummaryRecord class. /// /// /// The disposition of the verb execution. /// /// /// The build objects that were produced by this verb execution. /// /// /// Whether this result is a verification timeout. /// internal ResultSummaryRecord( Disposition disposition, IEnumerable outputs, bool isVerificationTimeout) : this(null, disposition, outputs, isVerificationTimeout) { } /// /// Initializes a new instance of the ResultSummaryRecord class. /// /// /// The verb whose execution this is the result of. /// /// /// The disposition of the verb execution. /// /// /// The build objects that were produced by this verb execution. /// /// /// Whether this result is a rejectable failure. /// internal ResultSummaryRecord( IVerb verb, Disposition disposition, IEnumerable outputs, bool isRejectableFailure) { this.verb = verb; this.disposition = disposition; this.outputs = new List(outputs); this.isRejectableFailure = isRejectableFailure; IRejectable rejectableVerb = verb as IRejectable; if (rejectableVerb != null) { this.isRejectableFailure = rejectableVerb.resultWasRejectableFailure(); } } /// /// Gets a value indicating whether this result is a failure of /// some sort (includes verification timeouts). /// public bool IsFailure { get { return this.isRejectableFailure || (this.disposition is Failed); } } /// /// Gets a value indicating whether this result is a verification /// timeout. /// public bool IsVerificationTimeout { get { return this.isRejectableFailure; } } /// /// Gets the build objects that were produced by this verb execution. /// public IEnumerable Outputs { get { return this.outputs; } } /// /// Gets the disposition of the verb execution. /// internal Disposition Disposition { get { return this.disposition; } } /// /// Creates a result record from an XML representation. /// /// /// A string containing an XML document representing this result record. /// /// /// A new result record corresponding to the XML representation read. /// public static ResultSummaryRecord FromXml(string xs) { XmlReader xr = XmlReader.Create(new StringReader(xs)); while (xr.Read()) { if (xr.NodeType == XmlNodeType.Element) { break; } } return ReadXml(xr); } /// /// Helper function to read an XML element (not a full document) /// representing a result record. /// /// /// Note that the XmlReader is expected to be positioned in the XML /// document such that the current node is a result record element. /// /// The XmlReader object to read from. /// /// A new result record corresponding to the XML representation read. /// public static ResultSummaryRecord ReadXml(XmlReader xr) { Util.Assert(xr.Name.Equals(ResultSummaryRecord.XmlTag)); bool isVerificationTimeout = false; bool.TryParse( xr.GetAttribute(XmlIsVerificationTimeoutAttribute), out isVerificationTimeout); xr.ReadToFollowing(Disposition._xml_tag); Disposition d = Disposition.readXml(xr); List lbovp = new List(); while (xr.Read()) { if (xr.NodeType == XmlNodeType.EndElement) { Util.Assert(xr.Name.Equals(ResultSummaryRecord.XmlTag)); break; } else if (xr.NodeType == XmlNodeType.Element) { if (xr.Name.Equals(BuildObjectValuePointer.XmlTag)) { lbovp.Add(BuildObjectValuePointer.ReadXml(xr)); } else { throw new Exception("Unknown xml tag " + xr.Name); } } } return new ResultSummaryRecord(d, lbovp, isVerificationTimeout); } /// /// Creates an XML document representing this result record. /// /// /// A string containing an XML document representing this result record. /// public string ToXml() { StringBuilder sb = new StringBuilder(); XmlWriterSettings settings = new XmlWriterSettings(); settings.Indent = true; XmlWriter xw = XmlWriter.Create(sb, settings); xw.WriteStartDocument(); this.WriteXml(xw); xw.Close(); return sb.ToString(); } /// /// Helper function to write an XML element (not a full document) /// representing this result record. /// /// The XmlWriter object to write to. public void WriteXml(XmlWriter xw) { xw.WriteStartElement(XmlTag); xw.WriteAttributeString( ResultSummaryRecord.XmlIsVerificationTimeoutAttribute, this.isRejectableFailure.ToString()); if (this.verb != null) { this.verb.writeTimingXml(xw); this.verb.writeDebugXml(xw); } this.disposition.writeXml(xw); foreach (BuildObjectValuePointer bovp in this.outputs) { bovp.WriteXml(xw); } xw.WriteEndElement(); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/Scheduler.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; /// /// Mechanism for determining which verbs need to be run and in what order. /// internal class Scheduler { /// /// Whether to produce conditional debug output in the scheduler and /// some of its components. /// internal const bool Debug = false; /// /// Where to write scheduler progress information (for debugging). /// private const string DbgProgressFileName = "nubuild.progress"; /// /// REVIEW: Not used. Remove? /// private const string DispositionFileExtension = ".disp"; /// /// The second-order verb sorter we use. /// private VerbToposorter verbToposorter; /// /// Collection of initial output targets. /// private HashSet targets; /// /// Waiting verb tracker? /// private WaitIndex waitIndex; /// /// Tracker of build objects. /// private Repository repository; /// /// The component of the scheduler that runs verbs for us. /// private VerbRunner verbRunner; /// /// Count of verbs submitted to the verbRunner for running during /// this round? /// private int submittedCount; /// /// Map of build objects to the verb that creates them. /// private Dictionary outputToVerbMap; /// /// Verbs in the outputToVerbMap. /// REVIEW: These verbs should be equivalent to those in /// outputToVerbMap.Values. Worth keeping this separate HashSet /// for performance reasons? /// private HashSet knownVerbs; /// /// Cache of verb dependencies. /// private DependencyCache depCache; /// /// Verbs that have been submitted for execution or failed, /// and need not be further considered. /// private HashSet resolvedVerbs; /// /// Verbs that have been completed, and hence can't contribute /// to resolving any pending dependencies. /// (If it's resolved and not completed, it must be submitted /// for asynchronous execution.) /// private HashSet completedVerbs; /// /// Our general strategy is to record the outcome of every verb in /// a persistent result cache, and then to evaluate each downstream /// BuildObject by querying that cache. But when one verb fails, /// it may make the downstream verb unable to even compute its input /// set, and hence its concreteIdentifier (the key to a persistent /// cache). If we don't record the outcome somehow, we'll loop /// forever trying to learn the outcome of the downstream failure. /// So we record it here in-process, keyed by abstractIdentifier /// (which is assumed to be stable over a single run of NuBuild). /// Invariant: all values in this dictionary are Faileds. (We store /// them because they might (someday) propagate information about /// what failed for an error message.) /// private Dictionary unrecordableFailures; /// /// Whether to reject cached failures, apparently. /// Value comes from a command-line argument. /// private bool rejectCachedFailures; /// /// Verbs that are (still) required to be run to build our target(s). /// Verbs are removed from this collection as they are completed. /// private HashSet requiredVerbs; /// /// Verbs to look at on next pass through parallelSchedule's main loop? /// Serves as a method for passing a collection of verbs between /// parallelSchedule and disposeCurrentVerbs. /// private HashSet nextVerbs; ////private DbgVerbCounter dbgVerbCounter = new DbgVerbCounter(); /// /// Initializes a new instance of the Scheduler class. /// /// /// Degree of parallel execution to allow. /// /// /// Whether to reject cached failures. /// public Scheduler(int jobParallelism) { this.targets = new HashSet(); this.waitIndex = new WaitIndex(); this.repository = BuildEngine.theEngine.Repository; this.unrecordableFailures = new Dictionary(); this.verbToposorter = new VerbToposorter(); this.verbRunner = new VerbRunner(this.verbToposorter, jobParallelism); this.resolvedVerbs = new HashSet(); this.completedVerbs = new HashSet(); this.outputToVerbMap = new Dictionary(); this.knownVerbs = new HashSet(); this.depCache = new DependencyCache(); this.rejectCachedFailures = true; // this is now permanent. The code path for caching Failure results has rotted. } /// /// Adds one or more build objects to our collection of targets. /// /// /// REVIEW: Make this private (or inline into addVerbTargets)? /// /// Build objects to add. public void addTargets(IEnumerable newTargets) { this.targets.UnionWith(newTargets); } /// /// Schedules the verbs for execution. /// This is the top-level method driving the build. /// public void parallelSchedule() { // Convert our collection of initial targets into a // collection of verbs we need to run to create them. this.requiredVerbs = new HashSet(); foreach (BuildObject target in this.targets) { this.requiredVerbs.Add(this.getParent(target)); } // The set of verbs we're evaluating now. HashSet currentVerbs = new HashSet(this.requiredVerbs); // A set into which we accumulate verbs to evaluate on the next pass. this.nextVerbs = new HashSet(); // Loop until we've run all the verbs we need to run. while (this.requiredVerbs.Count() > 0) { this.disposeCurrentVerbs(currentVerbs); currentVerbs = null; // Just to be obvious. // Okay, now we wait around for some deps to finish, freeing up new targets. while (this.nextVerbs.Count() == 0 && this.requiredVerbs.Count() > 0) { this.Say(string.Format("scheduler waits, having submitted {0} verbs", this.submittedCount)); ////Util.Assert(submittedCount > 0); // False because we might be waiting for other stuff to complete. List taskCompletions; taskCompletions = this.verbRunner.scheduleAndWait(this); this.Say("received " + taskCompletions.Count() + " taskCompletions"); Util.Assert(this.requiredVerbs.Count() == 0 || taskCompletions.Count() > 0); this.processTaskCompletions(taskCompletions); currentVerbs = this.nextVerbs; this.nextVerbs = new HashSet(); if (currentVerbs.Count() > 0 || this.requiredVerbs.Count() == 0) { // Hey, something changed that we could reschedule on, // or we're actually all done. break; } // Hmm, we've got no opportunity to schedule new stuff, // so the VerbRunner better not return empty-handed the // next time through. // We've got an assert taskCompletions.Count()>0 to check // for that. this.Say("Scheduler waiting for more results."); } } } /// /// Display various debugging information. /// public void dbgDisplayCounts() { ////dbgVerbCounter.dbgDisplayCounts(); this.depCache.dbgPrintStats(); } /// /// Display various debugging information. /// internal void dbgDumpWaitIndex() { this.waitIndex.dbgDisplayIndex(this); } /// /// Determine the status of a verb (for debugging purposes). /// /// Verb being examined. /// A string containing the verb's current status. internal string dbgGetVerbStatus(IVerb verb) { if (this.completedVerbs.Contains(verb)) { return "completed"; } if (this.resolvedVerbs.Contains(verb)) { return "submitted"; } return "pending"; } /// /// Adds a verb to the mapping of build objects to the verb which /// creates them. /// /// /// TODO: Make this private. /// /// The verb to add. internal void addVerb(IVerb verb) { if (!this.knownVerbs.Add(verb)) { // We've already added this verb. return; } // Add all verb outputs to the output-to-verb map. foreach (BuildObject obj in verb.getOutputs()) { if (this.outputToVerbMap.ContainsKey(obj)) { Util.Assert(this.outputToVerbMap[obj].Equals(verb)); } else { this.outputToVerbMap[obj] = verb; } } // Recursively add all the verbs this verb is dependent upon, // so that we have a complete index of outputs back to the // verbs that generate them. foreach (IVerb dependentVerb in verb.getVerbs()) { this.addVerb(dependentVerb); } } /// /// Adds a collection of verbs (or rather their outputs) as /// targets for this build. /// /// A list of verbs to run. internal void addTargetVerbs(List verbs) { foreach (IVerb verb in verbs) { this.addVerb(verb); this.addTargets(verb.getOutputs()); } } /// /// Gets a list of target objects for this build. /// /// A list of target objects for this build. internal IEnumerable getTargets() { return this.targets; } /// /// Gets the verb that created the given object. /// /// /// Would like to rename this to "GetCreator" or "GetCreatorVerb" /// as it seems strange to call something a parent when it is a /// completely different object type, but the terminology seems /// to be widely used in the system. /// /// The object in question. /// The verb that creates the given object. internal IVerb getParent(BuildObject obj) { IVerb result; this.outputToVerbMap.TryGetValue(obj, out result); return result; } /// /// Gets the disposition of the verb that created the given object. /// /// The object in question. /// The disposition of the verb that created the given object. internal Disposition getObjectDisposition(BuildObject obj) { return this.repository.GetDisposition(obj); } /// /// Updates the "progress" output file with current status information. /// /// /// Count of verbs currently able to be run. /// /// /// Count of verbs currently running. /// internal void dbgUpdateProgress(int runnableVerbsCount, int runningVerbsCount) { StringBuilder sb = new StringBuilder(); sb.AppendLine("completedVerbs: " + this.completedVerbs.Count()); sb.AppendLine("resolvedVerbs: " + this.resolvedVerbs.Count()); sb.AppendLine("runnableVerbs: " + runnableVerbsCount); sb.AppendLine("runningVerbs: " + runningVerbsCount); sb.AppendLine("waitingVerbs: " + this.waitIndex.Count()); File.WriteAllText(DbgProgressFileName, sb.ToString()); } /// /// Computes a concrete identifier for a verb operation and its /// specific inputs. /// /// The verb to compute the hash for. /// /// Whether to assert if we can't compute the hash. /// /// /// A concrete identifier for a verb operation and its specific inputs. /// private string computeInputHash(IVerb verb, bool assertHashAvailable) { StringBuilder sb = new StringBuilder(); sb.Append(verb.getAbstractIdentifier().getConcreteId()); DependencyDisposition ddisp; foreach (BuildObject obj in this.depCache.getDependencies(verb, out ddisp)) { sb.Append(","); string hash = this.repository.GetHash(obj); Util.Assert(!assertHashAvailable || (hash != null)); sb.Append(hash); } if (ddisp == DependencyDisposition.Failed) { // This happens when we're trying to markFailed, // but the upstream has failed and we can't compute // our dependencies. In that case, markFailed // settles for noting the failure in-process, // but not caching the result. (Okay, since this // failure propagation is cheap to rediscover.) Util.Assert(!assertHashAvailable); return null; } Util.Assert(ddisp == DependencyDisposition.Complete); string rc = Util.hashString(sb.ToString()); return rc; } /// /// Finds some verbs that could possibly complete in the future and help /// resolve one of these dependencies. /// /// A list of unresolved dependencies. /// /// A list of verbs that could possibly create one or more of the /// missing dependencies. /// private List robustDiscoverReadyDeps(IEnumerable staleDeps) { List newParents = new List(); foreach (BuildObject dep in staleDeps) { IVerb parent = this.getParent(dep); if (parent != null) { if (this.completedVerbs.Contains(parent)) { // Wait, if the parent is completed, why is the child a stale dependency? Util.Assert(false); } newParents.Add(parent); } } return newParents; } /// /// Push each potential target somewhere else: replace it with its /// dependencies, or mark its outputs failed, or mark it runnable and /// give it to the verb runner. /// /// Set of verbs to process. private void disposeCurrentVerbs(HashSet currentVerbs) { this.submittedCount = 0; this.Say("disposeCurrentVerbs"); while (currentVerbs.Count() > 0) { foreach (IVerb verb in currentVerbs) { this.Say("disposeCurrentVerbs considering " + verb); ////dbgVerbCounter.consider(verb, DbgVerbCounter.DbgVerbCondition.DVWake); if (this.resolvedVerbs.Contains(verb)) { // Enthusiastic wakeup? continue; } if (this.waitIndex.isWaiting(verb)) { // He's already waiting for something else. continue; } DependencyDisposition ddisp; List knownDeps = new List(this.depCache.getDependencies(verb, out ddisp)); List staleDeps = new List(); List failedDeps = new List(); foreach (BuildObject dep in knownDeps) { Disposition disp = this.repository.GetDisposition(dep); if (disp is Stale) { staleDeps.Add(dep); } else if (disp is Failed) { failedDeps.Add(dep); } } if (staleDeps.Count() > 0 || ddisp == DependencyDisposition.Incomplete) { // Some inputs aren't yet available, so we can prompt one of those verbs // instead, and wake this one up when those are done. Util.Assert(staleDeps.Count() > 0); // REVIEW: Clean this up post SOSP. #if false List newParents = this.robustDiscoverReadyDeps(staleDeps); if (newParents.Count() == 0) { this.reexamineVerb(verb); newParents = this.robustDiscoverReadyDeps(staleDeps); Util.Assert(newParents.Count() > 0); } #else this.reexamineVerb(verb); List newParents = this.robustDiscoverReadyDeps(staleDeps); Util.Assert(newParents.Count() > 0); #endif this.nextVerbs.UnionWith(newParents); this.Say( string.Format( "disposeCurrentVerbs waits {0} dependent on {1} liberating {2}", verb, string.Join(",", staleDeps), string.Join(",", newParents))); this.waitIndex.insert(verb, staleDeps); } else if (ddisp == DependencyDisposition.Failed || failedDeps.Count() > 0) { this.Say(string.Format("disposeCurrentVerbs marks {0} failed", verb)); this.markFailed(verb); this.resolvedVerbs.Add(verb); ////dbgVerbCounter.consider(verb, DbgVerbCounter.DbgVerbCondition.DVDepsNonstale); } else { // All inputs are available, so we can compute concrete identifier // to retrieve from cache... string inputHash = this.computeInputHash(verb, true); Util.Assert(inputHash != null); if (!this.fetchFromCache(verb, inputHash)) { ////if (verb is BoogieAsmVerificationObligationListVerb) { System.Environment.Exit(0); } this.Say(string.Format("disposeCurrentVerbs submits {0}", verb)); // Or if it's not in cache, we can execute. // Verb's inputs are ready, and output is stale: mark verb runnable. ////Say(string.Format(" {0} submitted", verb)); this.verbRunner.submitVerb(verb); this.submittedCount += 1; } this.resolvedVerbs.Add(verb); ////dbgVerbCounter.consider(verb, DbgVerbCounter.DbgVerbCondition.DVDepsNonstale); } } // We've disposed all the current verbs. But maybe we found some more // we can pop loose right now. currentVerbs = this.nextVerbs; this.nextVerbs = new HashSet(); } } /// /// Checks the cache for a previous execution of this verb operating on /// the same inputs; updates our state with the cached results if so. /// /// The verb to check for prior execution. /// /// An identifier for this verb operating on a specific set of inputs. /// /// /// True if usable previous execution was found, false otherwise. /// private bool fetchFromCache(IVerb verb, string inputHash) { try { ResultSummaryRecord summary = this.repository.FetchResult(inputHash); if (summary.Disposition is Stale) { return false; } // REVIEW: Since we aren't asking FetchResult to return failures, // this check is no longer needed. Or at least it won't be once // the "Results" cache is cleared of all existing failure records. if (this.rejectCachedFailures && (summary.Disposition is Failed || summary.IsVerificationTimeout)) { Logger.WriteLine(string.Format( "NOTE: rejecting failure from cache {0}", verb)); return false; } this.Say(string.Format("disposeCurrentVerbs pulls {0} from cache", verb)); // Hey, this verb is already computed! Nothing to do. // Add the verb execution's results to the repository. this.repository.AddVerbResults(verb, summary); this.verbIsComplete(verb, summary.Disposition); return true; } catch (ObjectMissingFromCacheException ex) { Logger.WriteLine(string.Format( "WARNING: expected object {0} missing from cache; discarding cached result {1}", ex, verb)); return false; } } /// /// Reexamines a verb to see if it now knows more regarding what other /// verbs need to run first in order to create its dependencies. /// /// The verb to reexamine. private void reexamineVerb(IVerb verb) { foreach (IVerb parentVerb in verb.getVerbs()) { this.addVerb(parentVerb); } } /// /// Processes task completion messages. /// /// /// A list of task completion messages. /// private void processTaskCompletions(List taskCompletions) { foreach (VerbRunner.TaskCompletion tc in taskCompletions) { // We may record a Failure if the verb didn't output // everything it promised to. Disposition recordedDisposition = this.recordResult(tc); this.Say(string.Format(" {0} completed with disposition {1}", tc.verb, tc.disposition)); } // Waking process may have shaken some verbs loose for us to evaluate next time around. } /// /// Conditionally debug print a message. /// /// The message to print. private void Say(string s) { if (Debug) { #pragma warning disable 162 Logger.WriteLine("[sched] " + s); #pragma warning restore 162 } } /// /// Logs output regarding a verb's execution disposition. /// /// The verb in question. /// Disposition of the verb execution. private void emitRealtimeReport(IVerb verb, Disposition disposition) { Presentation pr = verb.getRealtimePresentation(disposition); ASCIIPresentater ascii = new ASCIIPresentater(); pr.format(ascii); Logger.Write(ascii.ToString()); } /// /// Mark a verb as completed, and adjust our schedule accordingly. /// /// The verb that completed. /// The disposition of the verb's execution. private void verbIsComplete(IVerb verb, Disposition disp) { ////Say(string.Format(" {0} is complete: {1}", verb, dbgDisposition)); ////if (disp is Failed) ////{ //// // Failures can be hard to debug, since they don't leave any //// // output in nuobj/. So report these even if they aren't //// // built this run. //// emitRealtimeReport(verb, disp); ////} // Invariant: all of this verb's objs are non-Stale. foreach (BuildObject obj in verb.getOutputs()) { ////Say(string.Format(" waking {0}", obj)); IEnumerable wokenSet = this.waitIndex.awaken(obj); ////foreach (IVerb wokenVerb in wokenSet) ////{ //// //Say(string.Format(" {0} woken", wokenVerb)); ////} this.nextVerbs.UnionWith(wokenSet); } this.emitRealtimeReport(verb, disp); this.requiredVerbs.Remove(verb); this.completedVerbs.Add(verb); } /// /// Record how each output of a task appeared. /// /// The task completion notification. /// Overall result of the verb execution. private Disposition recordResult(VerbRunner.TaskCompletion completion) { WorkingDirectory workingDirectory = completion.workingDirectory; IVerb verb = completion.verb; Disposition executionDisposition = completion.disposition; List outputs = new List(); List missingOutputs = new List(); IEnumerable expectedOutputs = verb.getOutputs(); if (executionDisposition is Failed) { expectedOutputs = expectedOutputs.Concat(verb.getFailureOutputs()); } bool hasVirtualOutputs = false; foreach (BuildObject outobj in expectedOutputs) { if (!(outobj is VirtualBuildObject)) { // For expected file outputs, check for existence in working directory. // REVIEW: Add method to WorkingDirectory which does this? if (File.Exists(workingDirectory.PathTo(outobj))) { // Try to catch accidental case mismatches that would burn us when we // try to fetch the file back in. ////string fsname = PathNormalizer.dbg_normalizePath_nocache(outobj.deprecatedGetFilesystemPath(), false); ////Util.Assert(Path.GetFileName(fsname).Equals(outobj.getFileName())); // REVIEW: Do we need to worry about case mismatches anymore? See comments above. outputs.Add(this.repository.Store(workingDirectory, outobj, executionDisposition)); // Store a copy of this verb output as a file in the real nuobj directory. Util.Assert(outobj.getRelativePath().StartsWith(BuildEngine.theEngine.getObjRoot(), StringComparison.Ordinal)); string nuobjPath = IronRootDirectory.PathTo(outobj); Directory.CreateDirectory(Path.GetDirectoryName(nuobjPath)); File.Copy(workingDirectory.PathTo(outobj), nuobjPath, true); } else { missingOutputs.Add(string.Format("Missing expected output {0}", outobj.getRelativePath())); } } else { hasVirtualOutputs = true; if (this.repository.GetDisposition(outobj) is Fresh) { // Nothing to cache; virtual objects only survive in the Repository, the in-process store. } else { missingOutputs.Add(string.Format("Missing expected virtual {0}", outobj.getRelativePath())); } } } if (!(executionDisposition is Failed) && missingOutputs.Count() > 0) { executionDisposition = new Failed(missingOutputs); } ResultSummaryRecord summary = new ResultSummaryRecord(verb, executionDisposition, outputs); string inputHash = this.computeInputHash(verb, true); Util.Assert(inputHash != null); if (!hasVirtualOutputs) { this.repository.StoreResult(inputHash, summary); } else { this.Say("Not caching verb persistently: " + verb); } this.verbIsComplete(verb, executionDisposition); return executionDisposition; } /// /// Mark a verb as having failed. /// /// The verb that failed. private void markFailed(IVerb verb) { // At least one of verb's inputs has a permanent failure, so we didn't // even try to execute it. Disposition disposition = new Failed("upstream failure"); ResultSummaryRecord summary = new ResultSummaryRecord(verb, disposition, new BuildObjectValuePointer[] { }); // NB never store upstream failures to the persistent cache, because // they depend on our knowledge this run that the upstream verb failed. // If, in another run, the verb or its inputs are modified, produce the // same outputs, but returns success, we'll be stuck pulling this // upstream failure out of cache but calling this verb a failure. ////string inputHash = computeInputHash(verb, false); ////if (inputHash != null) ////{ //// Util.Assert(false); //// // "Upstream failures" will never have a computable inputHash, because their inputs //// // can't be considered known. Even if the upstream verb wrote something to disk, //// // what if the upstream verb changes to no longer fail but still emit the same thing? //// // We wouldn't want to conclude that, because the inputs hadn't changed, this //// // verb still had an upstream failure. //// repository.StoreResult(inputHash, summary); ////} ////else ////{ this.unrecordableFailures[verb] = disposition; ////} // Mark all the verb's outputs as Failed in the repository. foreach (BuildObject obj in verb.getOutputs()) { if (obj is VirtualBuildObject) { this.repository.StoreVirtual(obj, disposition, null); } else { this.repository.AddObject(obj, disposition, null); } } this.verbIsComplete(verb, disposition); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/SourceConfigurationError.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; internal class SourceConfigurationError : Exception { public SourceConfigurationError(string msg) : base(msg) { } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/SourcePath.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.IO; /// /// Representation of a source BuildObject. /// These are things which we expect to pre-exist, instead of built by us. /// internal class SourcePath : BuildObject { /// /// The type of "source" this is. /// private SourceType sourceType; /// /// Initializes a new instance of the SourcePath class. /// /// /// Relative path to this object in the local filesystem. /// /// /// The type of "source" this is. /// public SourcePath(string inpath, SourceType sourceType = SourceType.Src) : base(inpath) { // Sanity checks. this.checkPrefix(sourceType, SourceType.Src, BuildEngine.theEngine.getSrcRoot()); this.checkPrefix(sourceType, SourceType.Tools, BuildEngine.theEngine.getToolsRoot()); this.checkPrefix(sourceType, SourceType.BinTools, BuildEngine.theEngine.getBinToolsRoot()); this.checkPrefix(sourceType, SourceType.PrebakedObjExpediency, "obj"); // TODO remove. this.sourceType = sourceType; this.IsTrusted = getRelativePath().StartsWith( Path.Combine(BuildEngine.theEngine.getSrcRoot(), BuildEngine.VerveTrustedSpecDir), StringComparison.OrdinalIgnoreCase); } /// /// Various types of "sources". /// public enum SourceType { /// /// Source file. /// Src, /// /// Tools (executables usually) that we don't build ourselves. /// Tools, /// /// Tools that we could build ourselves. /// Probably don't really want this in the long run, /// since we can build these. /// BinTools, /// /// Special purpose expediency. /// Used to point at bootloader, until we can get an nmake verb working. TODO remove. /// PrebakedObjExpediency } /// /// Gets the source type of this instance. /// public SourceType Type { get { return this.sourceType; } } /// /// Creates a new SourcePath, where the source type is the same as this /// SourcePath's, and the path is relative to the directory containing /// this SourcePath. /// /// /// REVIEW: This should be renamed to MakeNewSourcePath to correspond /// with BuildObject /// /// Relative path to the new object. /// The new SourcePath. public SourcePath getNewSourcePath(string inpath) { return new SourcePath(Path.Combine(getDirPath(), inpath), this.sourceType); } /// /// Checks that the path prefix for this object is reasonable for the /// given source type. /// /// The given source type. /// /// Source type the prefix parameter matches. /// /// /// Prefix that paths of the matchType parameter should have. /// private void checkPrefix(SourceType givenType, SourceType matchType, string prefix) { if (givenType == matchType) { if (!path.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) { throw new UserError(string.Format( "Source path {0} should begin with {1}", this.path, prefix)); } } } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/SourcePathIncludeContext.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; using System.Linq; // This context looks for files in a set of source path locations. internal class SourcePathIncludeContext : IncludePathContext { private List directories; private List dstExtensions; private string _descr; public SourcePathIncludeContext() { this.directories = new List(); this.dstExtensions = new List(); } public override string ToString() { if (this._descr == null) { this._descr = "{" + string.Join(",", this.directories.Select(d => d.directory)) + "}; {" + string.Join(",", this.dstExtensions) + "}"; } return this._descr; } // Add a directory path relative to ironRoot. public void addDirectory(string directory) { Util.Assert(this._descr == null); this.directories.Add(new DirectoryRecord(directory)); } public void addDstExtension(string extension) { Util.Assert(this._descr == null); this.dstExtensions.Add(extension); } public override BuildObject search(string basename, ModPart modPart) { List results = new List(); foreach (string extension in this.dstExtensions.Where(extn => BeatExtensions.whichPart(extn) == modPart)) { string filename = basename + extension; foreach (DirectoryRecord directoryRecord in this.directories) { if (directoryRecord.Contains(filename)) { string proposed = Path.Combine( BuildEngine.theEngine.getIronRoot(), BuildEngine.theEngine.getSrcRoot(), directoryRecord.directory, basename + extension); ////Logger.WriteLine("SourcePathIncludeContext Trying " + proposed); ////Util.Assert(File.Exists(proposed)); results.Add(new SourcePath(proposed)); } } } if (results.Count() == 0) { return null; } else if (results.Count() > 1) { throw new SourceConfigurationError(string.Format( "Reference {0} matches {1} paths: {2}", basename, results.Count(), string.Join(",", results))); } else { return results.First(); } } private class DirectoryRecord { private readonly string _directory; private readonly HashSet _files; public DirectoryRecord(string directory) { this._directory = directory; string absDir = Path.Combine( BuildEngine.theEngine.getIronRoot(), BuildEngine.theEngine.getSrcRoot(), this._directory); this._files = new HashSet(Directory.EnumerateFiles(absDir) .Select(path => Path.GetFileName(path))); } public string directory { get { return this._directory; } } public bool Contains(string file) { return this._files.Contains(file); } } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/StaticContextVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; // Recipient needs to accept IContextGeneratingVerbs, but we don't need // any dependencies to produce this (static) context. So this is a simple, // non-dependent verb that just spews a ContextContents. internal class StaticContextVerb : ContextGeneratingVerb { private IIncludePathContext _context; public StaticContextVerb(IIncludePathContext context, string nickname, PoundDefines poundDefines) : base(nickname, poundDefines) { this._context = context; } public override IEnumerable getDependencies(out DependencyDisposition ddisp) { ddisp = DependencyDisposition.Complete; return new BuildObject[] { }; } public override IEnumerable getVerbs() { return new IVerb[] { }; } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { ContextContents contents = new ContextContents(this._context); BuildEngine.theEngine.Repository.StoreVirtual(this.getContextOutput(), new Fresh(), contents); return new VerbSyncWorker(workingDirectory, new Fresh()); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/SymDiffBaseVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Linq; internal abstract class SymDiffBaseVerb : Verb, IProcessInvokeAsyncVerb { private const int version = 10; public abstract IEnumerable getInputFiles(); public abstract BuildObject getOutputFile(); public override IEnumerable getDependencies(out DependencyDisposition ddisp) { ddisp = DependencyDisposition.Complete; List deps = new List(this.getInputFiles()); deps.Add(getSymDiffExecutable()); deps.AddRange(getSymDiffExecutableDependencies()); // REVIEW: Probably need to add SymDiffExecutable's dependencies too. return deps; } public override IEnumerable getOutputs() { return new List() { this.getOutputFile() }; } public virtual void preprocess(WorkingDirectory workingDirectory) { } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { List args = this.getArgs(); preprocess(workingDirectory); // We use workingDirOverride flag here to change the path that the // process starts in to one that is still in our workingDirectory. // So this isn't so bad. It would be better if NuBuild would only // let us supply a relative path here, however. string overrideDir = null; if (this.getWorkingDir() != null) { overrideDir = workingDirectory.PathTo(this.getWorkingDir()); } return new ProcessInvokeAsyncWorker( workingDirectory, this, getSymDiffExecutable().getRelativePath(), args.ToArray(), ProcessExitCodeHandling.NonzeroIsFailure, getDiagnosticsBase(), workingDirOverride: overrideDir, returnStandardOut: true); } public virtual Disposition Complete(WorkingDirectory workingDirectory, double cpuTimeSeconds, string stdout, string stderr, Disposition disposition) { return disposition; } protected static SourcePath getSymDiffExecutable() { return new SourcePath("tools\\SymDiff\\SymDiff.exe", SourcePath.SourceType.Tools); } protected static IEnumerable getSymDiffExecutableDependencies() { List exeDepends = new List(); exeDepends.Add(new SourcePath("tools\\SymDiff\\Basetypes.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\SymDiff\\Core.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\SymDiff\\CodeContractsExtender.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\SymDiff\\Graph.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\SymDiff\\ParserHelper.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\SymDiff\\Provers.SMTLib.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\SymDiff\\VCGeneration.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\SymDiff\\z3.exe", SourcePath.SourceType.Tools)); return exeDepends; } protected abstract List getArgs(); protected virtual string getWorkingDir() { return getOutputFile().getDirPath(); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/SymDiffCombineVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; internal class SymDiffCombineVerb : SymDiffBaseVerb, IProcessInvokeAsyncVerb { public const string MERGED_FILE_NAME = "mergedProgSingle.bpl"; private const int version = 3; private AbstractId abstractId; private SymDiffExtractVerb left; private SymDiffExtractVerb right; private SymDiffMergeConfigVerb merger; private BuildObject outputFile; public SymDiffCombineVerb(SymDiffExtractVerb left, SymDiffExtractVerb right, SymDiffMergeConfigVerb merger) { this.left = left; this.right = right; this.merger = merger; // Naming one of the files should be sufficient to uniquely identify the combiner. this.abstractId = new AbstractId(this.GetType().Name, version, left.getOutputFile().ToString()); ////abstractId = String.Format("{0}(#{1},{2},{3},{4})", //// this.GetType().Name, //// version, //// left.getOutputFile(), //// right.getOutputFile(), //// merger.getOutputFile()); this.outputFile = this.mkOutputFile(); } public override IEnumerable getInputFiles() { return new List() { this.left.getOutputFile(), this.right.getOutputFile(), this.merger.getOutputFile() }; } public override BuildObject getOutputFile() { return this.outputFile; } public override AbstractId getAbstractIdentifier() { return this.abstractId; } public override IEnumerable getVerbs() { return new List() { this.left, this.right, this.merger }; } public override IEnumerable getOutputs() { return new List() { this.getOutputFile() }; } protected override List getArgs() { List args = new List(); args.Add("-allInOne"); args.Add(this.left.getOutputFile().getFileName()); args.Add(this.right.getOutputFile().getFileName()); args.Add(this.merger.getOutputFile().getFileName()); ////args.Add(left.getOutputFile().getRelativePath()); ////args.Add(right.getOutputFile().getRelativePath()); ////args.Add(merger.getOutputFile().getRelativePath()); List extra_args = new List() { "-asserts", "-freeContracts", "-usemutual", "-sound", "-dontUseHoudiniForMS", "-checkMutualPrecondNonTerminating" }; args.AddRange(extra_args); return args; } private BuildObject mkOutputFile() { // SymDiff always uses the same file name in the working directory. return new BuildObject(Path.Combine(this.left.getOutputFile().getDirPath(), MERGED_FILE_NAME)); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/SymDiffEngine.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; internal class SymDiffEngine { public static void BuildPipeline(IContextGeneratingVerb context, BuildObject input, out BuildObject bplFile, out IVerb workerVerb) { BoogieAsmVerifyVerb basmVerb = new BoogieAsmVerifyVerb(context, input, true); SymDiffExtractVerb left = new SymDiffExtractVerb(basmVerb, SymDiffExtractVerb.Mode.LEFT); SymDiffExtractVerb right = new SymDiffExtractVerb(basmVerb, SymDiffExtractVerb.Mode.RIGHT); SymDiffInferVerb infer = new SymDiffInferVerb(left, right); SymDiffMergeConfigVerb mergeConfig = new SymDiffMergeConfigVerb(basmVerb, infer); SymDiffCombineVerb combiner = new SymDiffCombineVerb(left, right, mergeConfig); SymDiffMergeVerb merger = new SymDiffMergeVerb(basmVerb, combiner); bplFile = merger.getOutputFile(); workerVerb = merger; } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/SymDiffExtractVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; internal class SymDiffExtractVerb : SymDiffBaseVerb { public const string UNROLLED_EXTN = "_u"; public const string LEFT_FILE = "v1"; public const string RIGHT_FILE = "v2"; private const int version = 5; private AbstractId abstractId; private BoogieAsmVerifyVerb basmVerb; private BuildObject basmIn; private Mode mode; public SymDiffExtractVerb(BoogieAsmVerifyVerb basmVerb, Mode mode) { this.basmVerb = basmVerb; this.basmIn = basmVerb.outputFile(); this.mode = mode; this.abstractId = new AbstractId(this.GetType().Name, version, this.basmIn.ToString(), concrete: mode.ToString()); } public enum Mode { LEFT, RIGHT } public override IEnumerable getInputFiles() { return new List() { this.basmIn }; } public string getFileName() { switch (mode) { case Mode.LEFT: return LEFT_FILE; case Mode.RIGHT: return RIGHT_FILE; default: throw new Exception("Unexpected mode for SymDiffExtractVerb"); } } private BuildObject getTmpInputFile() { return new BuildObject(Path.Combine(basmIn.getDirPath(), getFileName() + BoogieVerb.BPL_EXTN)); } public override BuildObject getOutputFile() { return new BuildObject(Path.Combine(this.basmIn.getDirPath(), getFileName() + UNROLLED_EXTN + BoogieVerb.BPL_EXTN)); ////return basmIn.makeOutputObject(extension + BoogieVerb.BPL_EXTN); } public override AbstractId getAbstractIdentifier() { return this.abstractId; } public override IEnumerable getVerbs() { return new List() { this.basmVerb }; } public override IEnumerable getOutputs() { return new List() { this.getOutputFile() }; } public override void preprocess(WorkingDirectory workingDirectory) { base.preprocess(workingDirectory); File.Copy(workingDirectory.PathTo(basmIn), workingDirectory.PathTo(getTmpInputFile()), true); } protected override List getArgs() { List args = new List(); args.Add("-extractLoops"); args.Add(getTmpInputFile().getFileName()); args.Add(getOutputFile().getFileName()); return args; } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/SymDiffInferVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; internal class SymDiffInferVerb : SymDiffBaseVerb, IProcessInvokeAsyncVerb { public const string CONFIG = ".partial_config"; private const int version = 6; private AbstractId abstractId; private SymDiffExtractVerb left; private SymDiffExtractVerb right; public SymDiffInferVerb(SymDiffExtractVerb left, SymDiffExtractVerb right) { this.left = left; this.right = right; this.abstractId = new AbstractId(this.GetType().Name, version, left.getOutputFile().ToString().ToString()); // Left should suffice to uniquely ID. } public override IEnumerable getInputFiles() { return new List() { this.left.getOutputFile(), this.right.getOutputFile() }; } public override BuildObject getOutputFile() { // Choice of left/right doesn't matter here, since we're dropping the extension. return this.left.getOutputFile().makeOutputObject(CONFIG); } public override AbstractId getAbstractIdentifier() { return this.abstractId; } public override IEnumerable getVerbs() { return new List() { this.left, this.right }; } public override IEnumerable getOutputs() { return new List() { this.getOutputFile() }; } public override Disposition Complete(WorkingDirectory workingDirectory, double cpuTimeSeconds, string stdout, string stderr, Disposition disposition) { if (!(disposition is Failed)) { File.WriteAllText(workingDirectory.PathTo(this.getOutputFile()), stdout); } return disposition; } protected override List getArgs() { List args = new List(); args.Add("-inferConfig"); args.Add(this.left.getOutputFile().getFileName()); args.Add(this.right.getOutputFile().getFileName()); return args; } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/SymDiffMergeBaseVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; using System.Linq; internal abstract class SymDiffMergeBaseVerb : Verb, IProcessInvokeAsyncVerb { private const int version = 3; private static NmakeVerb boogieAsmBuildExecutableVerb = new NmakeVerb(new SourcePath("tools\\BoogieAsm\\makefile", SourcePath.SourceType.Tools)); public abstract BuildObject getOutputFile(); public override IEnumerable getDependencies(out DependencyDisposition ddisp) { ddisp = DependencyDisposition.Complete; List deps = new List(this.getInputFiles()); deps.Add(getSymDiffMergeExecutable()); // REVIEW: Probably need to add SymDiffMergeExecutable's dependencies too. return deps; } public override IEnumerable getVerbs() { return new[] { boogieAsmBuildExecutableVerb }; } public override IEnumerable getOutputs() { return new List() { this.getOutputFile() }; } protected string getWorkingDir() { return getOutputFile().getDirPath(); } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { List args = this.getArgs(); // We use workingDirOverride flag here to change the path that the // process starts in to one that is still in our workingDirectory. // So this isn't so bad. It would be better if NuBuild would only // let us supply a relative path here, however. string overrideDir = null; if (this.getWorkingDir() != null) { overrideDir = workingDirectory.PathTo(this.getWorkingDir()); } return new ProcessInvokeAsyncWorker( workingDirectory, this, this.getSymDiffMergeExecutable().getRelativePath(), args.ToArray(), ProcessExitCodeHandling.NonzeroIsFailure, getDiagnosticsBase(), captureStdout: this.getOutputFile(), workingDirOverride:overrideDir); } public Disposition Complete(WorkingDirectory workingDirectory, double cpuTimeSeconds, string stdout, string stderr, Disposition disposition) { return disposition; } protected abstract IEnumerable getInputFiles(); protected abstract List getArgs(); private BuildObject getSymDiffMergeExecutable() { return new BuildObject(Path.Combine(boogieAsmBuildExecutableVerb.getOutputPath().getRelativePath(), "symdiffmerge.exe")); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/SymDiffMergeConfigVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Linq; internal class SymDiffMergeConfigVerb : SymDiffMergeBaseVerb, IProcessInvokeAsyncVerb { public const string CONFIG_EXTN = ".config"; private const int version = 7; private AbstractId abstractId; private BoogieAsmVerifyVerb basmVerb; private BuildObject mutualSummary; private SymDiffInferVerb inferVerb; private BuildObject inferredConfig; private BuildObject output; public SymDiffMergeConfigVerb(BoogieAsmVerifyVerb basmVerb, SymDiffInferVerb inferVerb) { this.basmVerb = basmVerb; this.mutualSummary = basmVerb.getMutualSummary(); this.inferVerb = inferVerb; this.inferredConfig = inferVerb.getOutputFile(); this.abstractId = new AbstractId(this.GetType().Name, version, this.inferredConfig.ToString()); // One should suffice for uniqueness: String.Format("{0},{1}", mutualSummary,inferredConfig)); this.output = this.basmVerb.outputFile().makeOutputObject(CONFIG_EXTN); } public override AbstractId getAbstractIdentifier() { return this.abstractId; } public override BuildObject getOutputFile() { return this.output; } public override IEnumerable getVerbs() { return base.getVerbs().Concat(new List() { this.basmVerb, this.inferVerb }); } protected override IEnumerable getInputFiles() { return new List() { this.mutualSummary, this.inferredConfig }; } protected override List getArgs() { List args = new List(); args.Add("-config"); args.Add(this.mutualSummary.getFileName()); args.Add(this.inferredConfig.getFileName()); return args; } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/SymDiffMergeVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Linq; internal class SymDiffMergeVerb : SymDiffMergeBaseVerb, IProcessInvokeAsyncVerb { public const string MERGED_EXTN = ".merge"; private const int version = 8; private AbstractId abstractId; private BoogieAsmVerifyVerb basmVerb; private BuildObject mutualSummary; private SymDiffCombineVerb combiner; private BuildObject output; public SymDiffMergeVerb(BoogieAsmVerifyVerb basmVerb, SymDiffCombineVerb combiner) { this.basmVerb = basmVerb; this.mutualSummary = basmVerb.getMutualSummary(); this.combiner = combiner; this.abstractId = new AbstractId(this.GetType().Name, version, this.combiner.getOutputFile().ToString()); // String.Format("{0},{1}", One should suffice for uniqueness: mutualSummary, combiner.getOutputFile())); this.output = this.basmVerb.outputFile().makeOutputObject(MERGED_EXTN + BoogieVerb.BPL_EXTN); } public override AbstractId getAbstractIdentifier() { return this.abstractId; } public override BuildObject getOutputFile() { return this.output; } public override IEnumerable getVerbs() { return base.getVerbs().Concat(new List() { this.basmVerb, this.combiner }); } protected override IEnumerable getInputFiles() { return new List() { this.mutualSummary, this.combiner.getOutputFile() }; } protected override List getArgs() { List args = new List(); args.Add("-merge"); args.Add(this.mutualSummary.getFileName()); args.Add(this.combiner.getOutputFile().getFileName()); return args; } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/TransitiveDepsContents.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; internal class TransitiveDepsContents : VirtualContents { OrderPreservingSet _shallowDeps, _transitiveDeps; public IEnumerable shallowDeps { get { return this._shallowDeps; } } public IEnumerable transitiveDeps { get { return this._transitiveDeps; } } public TransitiveDepsContents(OrderPreservingSet shallowDeps, OrderPreservingSet transitiveDeps) { this._shallowDeps = shallowDeps; this._transitiveDeps = transitiveDeps; } ////public override string getConcreteSummary() ////{ //// return "(" + String.Join(",", transitiveDeps) + ")"; ////} } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/TransitiveDepsVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Linq; internal abstract class TransitiveDepsVerb : Verb { public const string TDEP_EXTN = ".tdep"; private const int version = 3; private BuildObject obj; private BuildObject _depsObj; protected TransitiveDepsVerb(BuildObject obj) { this.obj = obj; this._depsObj = obj.makeVirtualObject(BeatExtensions.whichPart(obj).ExtnStr() + TDEP_EXTN); } public BuildObject depsObj() { return this._depsObj; } public override AbstractId getAbstractIdentifier() { return new AbstractId(this.GetType().Name, version, this.obj.getRelativePath()); } public override IEnumerable getOutputs() { return new BuildObject[] { this.depsObj() }; } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { OrderPreservingSet shallowDeps = new OrderPreservingSet(); OrderPreservingSet transitiveDeps = new OrderPreservingSet(); IEnumerable includes = this.getIncludeFactory().getIncludes(this.obj); foreach (BuildObject child in includes) { shallowDeps.Add(child); transitiveDeps.AddRange(this.factory(child).getTransitiveIncludes()); transitiveDeps.Add(child); } VirtualContents contents = new TransitiveDepsContents(shallowDeps, transitiveDeps); BuildEngine.theEngine.Repository.StoreVirtual(this.depsObj(), new Fresh(), contents); return new VerbSyncWorker(workingDirectory, new Fresh()); } // Available only after this verb is Fresh. // These are called the "transitive includes" because from this point of view, these aren't // dependencies, they're the included files. The caller may be using them to describe // his dependencies, though. public IEnumerable getTransitiveIncludes() { TransitiveDepsContents contents = (TransitiveDepsContents)BuildEngine.theEngine.Repository.FetchVirtual(this.depsObj()); return contents.transitiveDeps; } public IEnumerable getShallowIncludes() { TransitiveDepsContents contents = (TransitiveDepsContents)BuildEngine.theEngine.Repository.FetchVirtual(this.depsObj()); return contents.shallowDeps; } // This is a helper method for the downstream verb's getDependencies(). // It emits this verb's output token so that if this verb is // not yeat Fresh, the scheduler will strive to get this verb Executed, // plus if this verb is Fresh, tacks on all of the deps computed by // this verb. // The returned HashSet belongs to the caller, who is free // to stuff more into it. public HashSet getAvailableDeps(out DependencyDisposition ddisp) { HashSet result = new HashSet(); result.Add(this.depsObj()); try { result.UnionWith(this.getTransitiveIncludes()); result.Add(this.obj); // Add this last, since BoogieAsmLinkVerb appears to depend on this ordering ddisp = DependencyDisposition.Complete; } catch (ObjectNotReadyException) { ddisp = DependencyDisposition.Incomplete; } catch (ObjectFailedException) { ddisp = DependencyDisposition.Failed; } return result; } public override IEnumerable getVerbs() { try { IEnumerable includes = this.getIncludeFactory().getIncludes(this.obj); // NB evaluating eagerly so we can catch the exception here rather // than hide it in a lazy evaluation later. List result = new List(includes.Select(parent => this.factory(parent))); return result; } catch (ObjectNotReadyException) { } catch (SourceConfigurationError except) { throw new SourceConfigurationError(except.Message + " which is included by " + this.obj.getRelativePath()); } return new IVerb[] { }; } public override IEnumerable getDependencies(out DependencyDisposition ddisp) { // NB we'll either return the singleton list {obj} if obj isn't yet available, // or we'll return the entire list of deps on obj's parents. List deps = new List(); this.extendDeps(deps); deps.Add(this.obj); try { IEnumerable includes = this.getIncludeFactory().getIncludes(this.obj); if (includes.Contains(this.obj)) { throw new SourceConfigurationError("Include loop starting at " + this.obj); } deps.AddRange(includes.Select(parent => this.factory(parent).depsObj())); ddisp = DependencyDisposition.Complete; } catch (ObjectNotReadyException) { ddisp = DependencyDisposition.Incomplete; } catch (ObjectFailedException) { ddisp = DependencyDisposition.Failed; } return deps; } protected virtual void extendDeps(List deps) { } protected abstract TransitiveDepsVerb factory(BuildObject obj); protected abstract IIncludeFactory getIncludeFactory(); } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/UnverifiedSentinelVirtualContents.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; internal class UnverifiedSentinelVirtualContents : VirtualContents { } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/UserError.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; internal class UserError : Exception { public UserError(string msg) : base(msg) { } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/Util.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Diagnostics; using System.IO; using System.Runtime.Remoting.Metadata.W3cXsd2001; using System.Security.Cryptography; using System.Text; using System.Threading; /// /// General Utility Functions. /// public class Util { // Win32 MAX_PATH is 260 according to Internets. private const int MAX_MUNGED_LENGTH = 150; public static string hashString(string input) { byte[] buffer = new byte[input.Length * sizeof(char)]; System.Buffer.BlockCopy(input.ToCharArray(), 0, buffer, 0, buffer.Length); SHA256Managed hasher = new SHA256Managed(); byte[] rawHash = hasher.ComputeHash(buffer); return new SoapHexBinary(rawHash).ToString(); } public static string hashFilesystemPath(string filesystemPath) { ////Logger.WriteLine("Hashing " + filesystemPath); using (FileStream stream = File.OpenRead(filesystemPath)) { SHA256 sha = new SHA256Managed(); byte[] rawHash = sha.ComputeHash(stream); string rc = new SoapHexBinary(rawHash).ToString(); ////Logger.WriteLine("fresh hash of " + obj.getFilesystemPath() + " yields " + rc); return rc; } } public static string mungeClean(string s) { StringBuilder sb = new StringBuilder(); bool lastIsLetter = false; foreach (char c in s) { if (char.IsLetter(c) || char.IsNumber(c)) { sb.Append(c); lastIsLetter = true; } else { if (lastIsLetter) { sb.Append('-'); } lastIsLetter = false; } } if (sb.Length > MAX_MUNGED_LENGTH) { string originalPathHash = Util.hashString(sb.ToString()); int additionsLength = originalPathHash.Length + 3; sb.Remove(MAX_MUNGED_LENGTH - additionsLength, sb.Length - (MAX_MUNGED_LENGTH - additionsLength)); sb.Append("..."); sb.Append(originalPathHash); } return sb.ToString(); } // Replace characters in a filename the same way DafnySpec/DafnyCC does. public static string dafnySpecMungeName(string s) { return s.Replace('.', '_').Replace('-', '_'); } // Returns null if s doesn't end with eold. public static string replaceExtension(string s, string eold, string enew) { if (s.EndsWith(eold)) { return s.Substring(0, s.Length - eold.Length) + enew; } else { return null; } } /// /// Check an ASCII encoded file for the presence of bad characters /// and character combinations. What we consider bad: /// - Tab characters. /// - Carraige returns not followed by a line feed. /// - Line feeds not preceeded by a carraige return. /// /// File to check. /// True if no bad characters found. False otherwise. public static bool CheckSourceFileForBadCharacters(string sourcePath) { const int HT = 0x09; // Horizontal tab. const int LF = 0x0a; // Line feed. const int CR = 0x0d; // Carraige return. using (StreamReader reader = new StreamReader(sourcePath)) { int octet; // REVIEW: Sanity check reader.CurrentEncoding here? while ((octet = reader.Read()) > 0) { switch (octet) { case CR: if (reader.Read() != LF) { return false; } break; case LF: case HT: return false; } } } return true; } public static void Assert(bool condition) { if (!condition) { Logger.WriteLine("Assert failure."); Debug.Assert(condition); for (int loop = 10; loop > 0; loop--) { Logger.WriteLine("Something broke in assert. Attach a debugger to debug."); Logger.WriteLine(string.Format("You have {0} seconds to comply.", loop * 10)); Debugger.Break(); Thread.Sleep(10000); } Environment.Exit(-1); } } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/VSProjectParser.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; using System.Xml; /// /// Mechanism for parsing Visual Studio project Files. /// Determines project dependencies and outputs. /// internal class VSProjectParser { private SourcePath projectFile; private HashSet dependencies = new HashSet(); private HashSet outputs = new HashSet(); private string outputType = null; private string assemblyName = null; ////private string outputPath = null; /// /// Initializes a new instance of the VSProjectParser class. /// /// Visual Studio project file to parse. public VSProjectParser(SourcePath projectFile) { this.projectFile = projectFile; this.Parse(); CustomManifestParser cm = new CustomManifestParser(this.projectFile); this.dependencies.UnionWith(cm.getDependencies()); this.outputs.UnionWith(cm.getOutputs()); } public IEnumerable getDependencies() { return this.dependencies; } public IEnumerable getOutputs() { return this.outputs; } private void Parse() { this.dependencies.Add(this.projectFile); using (XmlTextReader reader = new XmlTextReader(IronRootDirectory.PathTo(this.projectFile))) { while (reader.Read()) { if (reader.NodeType == XmlNodeType.Element) { if (string.Compare(reader.Name, "Compile") == 0) { this.dependencies.Add(this.projectFile.getNewSourcePath(reader.GetAttribute("Include"))); } else if (string.Compare(reader.Name, "PropertyGroup") == 0) { this.ParseOutput(reader); } } } reader.Close(); } if (this.outputType != null && this.assemblyName != null) //// && outputPath != null) { string path = Path.Combine(this.projectFile.getDirPath(), string.Format("{0}.{1}", this.assemblyName, this.OutputTypeToExtension(this.outputType))); ////Console.WriteLine("{0}: generating {1}", this.projectFile.getRelativePath(), path); this.outputs.Add(new BuildObject(path)); } else { throw new UserError(string.Format("Project {0} doesn't seem to have output specification in the expected format", this.projectFile.getRelativePath())); } } private void ValidateConsistentOption(string optionName, string oldValue, string newValue) { if (oldValue == null) { return; } if (!oldValue.Equals(newValue)) { throw new UserError( string.Format( "Values for {0} not consistent across all build configurations in {1} ({2} vs {3})", optionName, this.projectFile.getRelativePath(), oldValue, newValue)); } } private void ParseOutput(XmlTextReader reader) { string lastElement = null; while (reader.Read()) { if (reader.NodeType == XmlNodeType.EndElement) { lastElement = null; if ("PropertyGroup".Equals(reader.Name)) { break; } } if (reader.NodeType == XmlNodeType.Element) { lastElement = reader.Name; } if (reader.NodeType == XmlNodeType.Text && lastElement != null) { string val = reader.Value; ////if ("OutputPath".Equals(lastElement)) ////{ //// validateConsistentOption("OutputPath", outputPath, val); //// outputPath = val; ////} if ("AssemblyName".Equals(lastElement)) { this.ValidateConsistentOption("AssemblyName", this.assemblyName, val); this.assemblyName = val; } if ("OutputType".Equals(lastElement)) { this.ValidateConsistentOption("OutputType", this.outputType, val); this.outputType = val; } } } } private string OutputTypeToExtension(string outputType) { switch (outputType) { case "Exe": return "exe"; case "Library": return "dll"; default: throw new SourceConfigurationError("VSProjectParser doesn't know how to canonicalize " + outputType); } } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/VSSolutionParser.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; using System.Text.RegularExpressions; internal class VSSolutionParser { private SourcePath solutionFile; private List dependencies = new List(); private List outputs = new List(); public VSSolutionParser(SourcePath solutionFile) { this.solutionFile = solutionFile; this.Parse(); } public IEnumerable getDependencies() { return this.dependencies; } public IEnumerable getOutputs() { return this.outputs; } private void Parse() { this.dependencies.Add(this.solutionFile); using (StreamReader stream = new StreamReader(IronRootDirectory.PathTo(this.solutionFile))) { Regex regex = new Regex(@"Project\([\S]+\)[\s]+=[\s]+([^$]*)", RegexOptions.IgnoreCase); string line; while ((line = stream.ReadLine()) != null) { MatchCollection matches = regex.Matches(line); if (matches.Count > 0) { SourcePath projFile = this.solutionFile.getNewSourcePath(matches[0].Groups[1].Value.Split("\", ".ToCharArray())[5]); ////Console.WriteLine(String.Format("Found project file {0}", projFile.getFilesystemPath())); VSProjectParser proj = new VSProjectParser(projFile); this.dependencies.AddRange(proj.getDependencies()); this.outputs.AddRange(proj.getOutputs()); } } stream.Close(); } } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/VSSolutionVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; using System.Linq; /// /// Verb to build a Visual Studio solution. /// internal class VSSolutionVerb : Verb, IProcessInvokeAsyncVerb { private const int Version = 5; private readonly SourcePath solutionFile; private readonly AbstractId abstractId; private readonly VSSolutionParser solutionParser; private readonly string outputPathSuffix; private readonly DafnyCompileOneVerb dafnyCompileOneVerb; private readonly bool releaseBuild; /// /// Initializes a new instance of the VSSolutionVerb class. /// /// Solution file to build. /// Optional dafny-derived-CSharp dependency. public VSSolutionVerb(SourcePath solutionFile, SourcePath optionalDafnyInput = null, bool releaseBuild = false) { this.solutionFile = solutionFile; this.abstractId = new AbstractId(this.GetType().Name, VSSolutionVerb.Version, this.solutionFile.ToString()); this.releaseBuild = releaseBuild; // Parse the solution file (and project files contained in the solution). this.solutionParser = new VSSolutionParser(this.solutionFile); this.outputPathSuffix = Path.Combine(BuildEngine.theEngine.getObjRoot(), this.solutionFile.getDirPath()); if (optionalDafnyInput != null) { this.dafnyCompileOneVerb = new DafnyCompileOneVerb(optionalDafnyInput); } } public override IEnumerable getDependencies(out DependencyDisposition ddisp) { ddisp = DependencyDisposition.Complete; List dependencies = new List(this.solutionParser.getDependencies()); if (this.dafnyCompileOneVerb != null) { dependencies.AddRange(this.dafnyCompileOneVerb.getOutputs()); } return dependencies; } public override IEnumerable getVerbs() { if (this.dafnyCompileOneVerb != null) { return new IVerb[] { this.dafnyCompileOneVerb }; } else { return new IVerb[] {}; } } public override IEnumerable getOutputs() { // Note that since we override the solution output directory in our // getWorker() below, we also need to override the output paths // coming from the solution parser. return from output in this.solutionParser.getOutputs() select new BuildObject(Path.Combine(this.outputPathSuffix, output.getFileName())); } public BuildObject getOutputPath() { return new BuildObject(this.outputPathSuffix); } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { // If we were given an optional dafny input, let this build know about the resulting verb's output. // Note: this is deliberately written to break if someone changes DafnyCompileOneVerb to have multiple outputs. if (this.dafnyCompileOneVerb != null) { File.Copy( workingDirectory.PathTo(this.dafnyCompileOneVerb.getOutputs().Single()), Path.Combine(workingDirectory.PathTo(this.outputPathSuffix), "DafnyDerivedInput.cs")); } List args = new List(); args.Add(string.Format("/p:OutDir={0}", workingDirectory.PathTo(this.outputPathSuffix))); args.Add(string.Format("/p:Configuration={0}", this.releaseBuild ? "Release" : "Debug")); ////args.Add("/fileLogger"); // Uncomment to log MSBuild execution. args.Add(workingDirectory.PathTo(this.solutionFile)); // TODO: Fix absolute path to MSBuild.exe (at least use %SystemRoot%)! return new ProcessInvokeAsyncWorker( workingDirectory, this, "c:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\MSBuild.exe", args.ToArray(), ProcessExitCodeHandling.NonzeroIsFailure, failureBase: getDiagnosticsBase(), allowAbsoluteExe: true, allowAbsoluteArgs: true); } public Disposition Complete(WorkingDirectory workingDirectory, double cpuTimeSeconds, string stdout, string stderr, Disposition disposition) { return disposition; } public override AbstractId getAbstractIdentifier() { return this.abstractId; } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/Verb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; using System.Xml; internal abstract class Verb : IVerb { public override bool Equals(object obj) { IVerb other = obj as IVerb; if (other != null) { return this.getAbstractIdentifier().Equals(other.getAbstractIdentifier()); } else { return false; } } public override int GetHashCode() { return this.getAbstractIdentifier().GetHashCode(); } public override string ToString() { return this.getAbstractIdentifier().ToString(); } public int CompareTo(object other) { return this.getAbstractIdentifier().CompareTo(((IVerb)other).getAbstractIdentifier()); } public abstract IEnumerable getDependencies(out DependencyDisposition ddisp); public abstract IEnumerable getVerbs(); public abstract IEnumerable getOutputs(); public virtual BuildObject getDiagnosticsBase() { return new BuildObject(Path.Combine( BuildEngine.theEngine.getObjRoot(), "diagnostics", Util.mungeClean(this.getAbstractIdentifier().ToString()))); } public virtual IEnumerable getFailureOutputs() { return new BuildObject[] { this.getDiagnosticsBase().makeOutputObject(".bat"), this.getDiagnosticsBase().makeOutputObject(".stdout"), this.getDiagnosticsBase().makeOutputObject(".stderr"), }; } public abstract IVerbWorker getWorker(WorkingDirectory workingDirectory); // Called by tool when this is the top-level output, it has generated a Fresh // result, and we want to print that result on the display. public virtual Presentation getPresentation() { PresentationBuilder pr = new PresentationBuilder(); pr.line("Okay."); return pr.fix(); } // Called by tool when we want a short (one-line) // summary for showing in-progress results. public virtual Presentation getRealtimePresentation(Disposition d) { PresentationBuilder pr = new PresentationBuilder(); pr.startLine(); pr.color( d is Fresh ? Presentation.GREEN : Presentation.RED, this.ToString() + " " + d.ToString()); pr.endLine(); if (d is Failed) { // This isn't a verification failure, a tool itself broke. // Provide that report. foreach (string m in d.getMessages()) { pr.pre(Presentation.abbreviateLines(m)); } } return pr.fix(); } //////////////////////////////////////////////////// // Handy helper for verbs using ProcessInvoker. private bool cpuTimeSecondsValid = false; private double cpuTimeSeconds; public virtual void RecordProcessInvokeCpuTime(double cpuTimeSeconds) { this.cpuTimeSeconds = cpuTimeSeconds; this.cpuTimeSecondsValid = true; } public static string XML_SubprocessTiming = "SubprocessTiming"; public static string XML_SubprocessTiming_Valid_Attr = "Valid"; public static string XML_SubprocessTiming_CPUTimeSeconds_Attr = "CPUTimeSeconds"; public void writeTimingXml(XmlWriter xw) { xw.WriteStartElement(XML_SubprocessTiming); xw.WriteAttributeString(XML_SubprocessTiming_Valid_Attr, this.cpuTimeSecondsValid.ToString()); if (this.cpuTimeSecondsValid) { xw.WriteAttributeString(XML_SubprocessTiming_CPUTimeSeconds_Attr, this.cpuTimeSeconds.ToString()); } xw.WriteEndElement(); } //////////////////////////////////////////////////// public abstract AbstractId getAbstractIdentifier(); public static string XML_DebugVerb = "DebugVerb"; public static string XML_DebugVerb_Value_Attr = "value"; public static string XML_DebugDep = "DebugDep"; public static string XML_DebugDep_Name_Attr = "name"; public static string XML_DebugDep_Hash_Attr = "hash"; public void writeDebugXml(XmlWriter xw) { xw.WriteStartElement(XML_DebugVerb); xw.WriteAttributeString(XML_DebugVerb_Value_Attr, this.getAbstractIdentifier().ToString()); xw.WriteEndElement(); DependencyDisposition ddisp; foreach (BuildObject obj in this.getDependencies(out ddisp)) { xw.WriteStartElement(XML_DebugDep); xw.WriteAttributeString(XML_DebugDep_Name_Attr, obj.getRelativePath()); if (!(obj is VirtualBuildObject)) { string hash = BuildEngine.theEngine.Repository.GetHash(obj); if (string.IsNullOrEmpty(hash)) { // REVIEW: Can this happen? Do something else here? hash = "unknown"; } xw.WriteAttributeString( XML_DebugDep_Hash_Attr, hash); } xw.WriteEndElement(); } Util.Assert(ddisp == DependencyDisposition.Complete); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/VerbOutputsContext.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; internal class VerbOutputsContext : IncludePathContext { private IVerb sourceVerb; private string descr; private HashSet dafnyOutputs; private bool assertSuspiciousDafnyImpls; public VerbOutputsContext(IVerb sourceVerb, bool assertSuspiciousDafnyImpls) { this.sourceVerb = sourceVerb; this.descr = "VerbOutputs(" + sourceVerb + ")"; this.assertSuspiciousDafnyImpls = assertSuspiciousDafnyImpls; } private HashSet DafnyOutputs { get { if (this.dafnyOutputs == null) { this.dafnyOutputs = new HashSet(this.sourceVerb.getOutputs()); } return this.dafnyOutputs; } } public override string ToString() { return this.descr; } public override BuildObject search(string basename, ModPart modPart) { // Kinda linear. ////Logger.WriteLine("Looking for " + basename); foreach (BuildObject obj in this.DafnyOutputs) { if (BeatExtensions.whichPart(obj) != modPart) { continue; } ////Logger.WriteLine(" trying " + obj.getFileNameWithoutExtension() + " from " + obj); if (string.Equals(obj.getFileNameWithoutExtension(), basename, StringComparison.OrdinalIgnoreCase)) { if (this.assertSuspiciousDafnyImpls) { DafnyCCVerb.AssertSmellsImplementy(obj); } return obj; } } return null; } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/VerbOutputsContextVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Linq; /// /// This verb waits for a parent verb to complete, then emits /// a ContextContents that searches the parent verb's results. /// internal class VerbOutputsContextVerb : ContextGeneratingVerb { private IVerb parent; private bool assertSuspiciousDafnyImpls; public VerbOutputsContextVerb(IVerb parent, bool assertSuspiciousDafnyImpls) : base(parent.getAbstractIdentifier().ToString(), null) { this.parent = parent; this.assertSuspiciousDafnyImpls = assertSuspiciousDafnyImpls; } public override IEnumerable getDependencies(out DependencyDisposition ddisp) { ddisp = DependencyDisposition.Complete; // I really don't care how many outputs the parent has; any one will // link me to the parent. IEnumerable result = this.parent.getOutputs(); Util.Assert(result.Count() > 0); return result; } public override IEnumerable getVerbs() { return new IVerb[] { this.parent }; } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { VerbOutputsContext context = new VerbOutputsContext(this.parent, this.assertSuspiciousDafnyImpls); ContextContents contents = new ContextContents(context); BuildEngine.theEngine.Repository.StoreVirtual(this.getContextOutput(), new Fresh(), contents); return new VerbSyncWorker(workingDirectory, new Fresh()); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/VerbRunner.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; /// /// Infrastructure for performing VerbWorker work, possibly asynchronously. /// Conceptually, this is the part of the scheduler that runs verbs. /// /// /// There is only one instance of this class in the system. /// internal class VerbRunner { /// /// Whether or not to run in a special debugging mode where everything /// is run on a single thread (including any 'async' work). /// /// /// Without this, JonH reported problems: "Breaking and examining /// variables on a second thread seems to send VS into fits". /// private const bool DebugOneThread = false; /// /// A sorter of verbs (special case for DafnyVerifyOneVerb only?). /// private VerbToposorter verbToposorter; /// /// Event used to signal the completion of some (possibly asynchronous) /// work. /// private ManualResetEvent completionEvent; /// /// Lock protecting the runnableVerbs and startedVerbs collections. /// private ReaderWriterLock verbStateLock; /// /// Verbs that have been submitted, but have not yet started to run. /// private HashSet runnableVerbs; /// /// Verbs that have started to run (and may or may not have /// completed; once added we never remove them from this collection). /// private HashSet startedVerbs; /// /// Degree of asynchronicity to allow (i.e. number of async threads). /// private int jobParallelism; /// /// Lock protecting the taskCompletions list. /// private ReaderWriterLock taskCompletionsLock; /// /// Tasks that have completed running, but not yet processed. /// private List taskCompletions; /// /// Number of currently running tasks. /// private int runningTasks; /// /// Initializes a new instance of the VerbRunner class. /// /// The verb sorter to use. /// Degree of parallelism to allow. public VerbRunner(VerbToposorter verbToposorter, int jobParallelism) { this.verbToposorter = verbToposorter; this.jobParallelism = jobParallelism; this.completionEvent = new ManualResetEvent(true); this.verbStateLock = new ReaderWriterLock(); this.runnableVerbs = new HashSet(); this.startedVerbs = new HashSet(); this.taskCompletionsLock = new ReaderWriterLock(); this.taskCompletions = new List(); this.runningTasks = 0; } /// /// Submits a verb for execution. /// /// The verb to submit. public void submitVerb(IVerb verb) { this.verbStateLock.AcquireWriterLock(Timeout.Infinite); // If lock contention were an issue, we could accumulate these // on a thread-local collection, then batch them into runnableVerbs // during the lock inside scheduleAndWait. if (!this.startedVerbs.Contains(verb)) { this.runnableVerbs.Add(verb); } this.verbStateLock.ReleaseLock(); } /// /// Called by the scheduler to run the verbs which can be run. /// /// /// The scheduler calling us (for debugging). /// /// A list of tasks (verb runs) that have completed. public List scheduleAndWait(Scheduler dbgScheduler) { while (true) { List taskCompletionBatch; // Loop until something gets done. while (true) { this.dbgUpdateProgress(dbgScheduler); this.taskCompletionsLock.AcquireWriterLock(Timeout.Infinite); taskCompletionBatch = this.taskCompletions; this.taskCompletions = new List(); this.completionEvent.Reset(); this.taskCompletionsLock.ReleaseLock(); bool canProcessCompletedTask = taskCompletionBatch.Count() > 0; bool canStartNewTask = (this.runnableVerbs.Count() > 0) && (this.jobParallelism > this.runningTasks); if (!(canProcessCompletedTask || canStartNewTask)) { // Nothing will change until a running task finishes. Snooze. if (this.runningTasks == 0) { dbgScheduler.dbgDumpWaitIndex(); Util.Assert(false); } this.completionEvent.WaitOne(); continue; } break; } int numCompletedTasks = taskCompletionBatch.Count(); Say(string.Format("marking {0} tasks completing; runningTasks now {1}", numCompletedTasks, this.runningTasks)); this.runningTasks -= numCompletedTasks; int idleTasks = this.jobParallelism - this.runningTasks; if (idleTasks > 0) { this.verbStateLock.AcquireWriterLock(Timeout.Infinite); List runnableVerbsBatch = new List(this.runnableVerbs); Say("AsyncRunner toposorting " + runnableVerbsBatch.Count() + " verbs"); runnableVerbsBatch.Sort(this.verbToposorter); ////Logger.WriteLine(string.Format("verbToposorter({0}) yields:", runnableVerbsBatch.Count)); ////foreach (IVerb verb in runnableVerbsBatch) ////{ //// Logger.WriteLine(" " + verb.ToString() + " @ "+ this.verbToposorter.getDepth(verb)); ////} for (int i = 0; i < idleTasks && i < runnableVerbsBatch.Count(); i++) { IVerb verb = runnableVerbsBatch[i]; this.startTask(verb); this.runnableVerbs.Remove(verb); this.startedVerbs.Add(verb); } this.verbStateLock.ReleaseLock(); } if (taskCompletionBatch.Count() > 0 || this.runningTasks == 0) { // Something actually got done, so the caller could meaningfully schedule more work. return taskCompletionBatch; } } } /// /// Writes debugging output to the logger. /// /// The message to write. private static void Say(string msg) { if (Scheduler.Debug) { #pragma warning disable 162 Logger.WriteLine("[async] " + msg); #pragma warning restore 162 } } /// /// Reports current progress to the scheduler. /// /// The scheduler. private void dbgUpdateProgress(Scheduler dbgScheduler) { dbgScheduler.dbgUpdateProgress(this.runnableVerbs.Count(), this.runningTasks); } /// /// Starts a task (i.e. runs a verb). /// /// The verb to run. private void startTask(IVerb verb) { this.runningTasks += 1; // We execute the verb in a private build tree (WorkingDirectory). WorkingDirectory workingDirectory = new WorkingDirectory(BuildEngine.theEngine.getIronRoot()); // Note that we call PrepareForVerb prior to the verb's getWorker // method as the getWorker call might do some of the work directly. // REVIEW: We might want to change our contract with getWorker to // disallow it from touching files in the working directory (so we // don't have to prep the working dir in the remote execution case). this.PrepareForVerb(workingDirectory, verb); IVerbWorker worker = verb.getWorker(workingDirectory); if (worker.IsSync() == VerbWorkerType.Sync) { this.completeTask(verb, worker); } else { AsyncVerbTask task = new AsyncVerbTask(this, worker, verb); Say(string.Format("scheduling {0}", verb)); #pragma warning disable 162 if (DebugOneThread) { task.Run(); } else { new Thread(new ThreadStart(task.Run)).Start(); } #pragma warning restore 162 } } /// /// Prepares the working directory tree for a verb's execution. /// /// The verb whose execution we're preparing for. private void PrepareForVerb(WorkingDirectory workingDirectory, IVerb verb) { // Debugging aide: write out the abstract id for this verb. File.WriteAllText(workingDirectory.PathTo("Debug.txt"), verb.getAbstractIdentifier().ToString()); Repository repository = BuildEngine.theEngine.Repository; // Copy all verb inputs from the item cache to here. DependencyDisposition ddisp; foreach (BuildObject input in verb.getDependencies(out ddisp)) { if (!(input is VirtualBuildObject)) { workingDirectory.CreateDirectoryFor(input); // REVIEW: No longer needed? repository.Fetch(workingDirectory, input); } } // Ensures that the directory tree for each of the verb's outputs exists. foreach (BuildObject output in verb.getOutputs()) { workingDirectory.CreateDirectoryFor(output); } } /// /// Completes a task (verb run). /// /// /// Note that for Async verb workers, this method runs on a separate thread. /// /// The verb which was run. /// The verb's worker. private void completeTask(IVerb verb, IVerbWorker worker) { this.taskCompletionsLock.AcquireWriterLock(Timeout.Infinite); Disposition disp = worker.Complete(); TaskCompletion tc = new TaskCompletion(worker.GetWorkingDirectory(), verb, disp); this.taskCompletions.Add(tc); this.completionEvent.Set(); this.taskCompletionsLock.ReleaseWriterLock(); } /// /// Represents a completed task. /// Ties a Disposition to the Verb instance which created it. /// /// /// REVIEW: Keep the entire worker instead of just the working dir? /// Might want to run worker.Complete on main thread after pulling this /// off the task completions list instead of on separate thread prior to /// putting it on the task completions list. /// public class TaskCompletion { /// /// The directory the verb executed in. /// public WorkingDirectory workingDirectory; /// /// The verb whose completion this instance describes. /// public IVerb verb; /// /// The disposition of this task. /// public Disposition disposition; /// /// Initializes a new instance of the TaskCompletion class. /// /// /// The private working directory the task executed in. /// /// /// The verb whose completion this instance describes. /// /// /// The disposition of this task. /// public TaskCompletion(WorkingDirectory workingDirectory, IVerb verb, Disposition disposition) { this.workingDirectory = workingDirectory; this.verb = verb; this.disposition = disposition; } } /// /// Representation of an asynchronous task. /// /// /// REVIEW: Do we need this class? It is 1:1 with the worker. /// private class AsyncVerbTask { /// /// The verb-running part of the scheduler. /// private VerbRunner runner; /// /// The worker of this verb task. /// private IVerbWorker worker; /// /// The verb associated with this task/worker. /// /// /// Don't call any methods on this guy while on async thread! /// It's just here to carry back to the TaskCompletion on the main thread. /// private IVerb verb; /// /// Initializes a new instance of the AsyncVerbTask class. /// /// /// The verb running part of the scheduler. /// /// /// The worker of this verb task. /// /// /// The verb associated with this task/worker. /// public AsyncVerbTask(VerbRunner runner, IVerbWorker worker, IVerb verb) { this.runner = runner; this.worker = worker; this.verb = verb; } /// /// Runs the task. /// /// /// Note that this method runs on a separate thread. /// Only make thread-safe calls from here. /// public void Run() { Say(string.Format("launching {0}", this.verb)); Logger.WriteLine(string.Format("{0} launched", this.verb)); this.worker.RunAsync(); this.runner.completeTask(this.verb, this.worker); Say(string.Format("completed {0}", this.verb)); } } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/VerbSyncWorker.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { /// /// Representation of a synchronous verb worker. /// internal class VerbSyncWorker : IVerbWorker { /// /// The private working directory for this worker to work in. /// private WorkingDirectory workingDirectory; /// /// The disposition of this activity. /// private Disposition result; /// /// Initializes a new instance of the VerbSyncWorker class. /// /// /// The private working directory for this worker to work in. /// /// The Disposition to return on complete. public VerbSyncWorker(WorkingDirectory workingDirectory, Disposition result) { this.workingDirectory = workingDirectory; this.result = result; } /// /// Indicates whether this work needs to be scheduled asynchronously. /// Since this is the synchronous implementation, always returns Sync. /// /// Always returns Sync. public virtual VerbWorkerType IsSync() { return VerbWorkerType.Sync; } /// /// Gets the private working directory this verb executes in. /// /// The directory this verb executes in. public WorkingDirectory GetWorkingDirectory() { return this.workingDirectory; } /// /// Performs the asynchronous work for this worker, which for a /// synchronous worker like this one, should not exist. Therefore, /// this implementation just asserts. /// /// /// Shouldn't ever be called, since our IsSync returns Sync. /// public void RunAsync() { Util.Assert(false); } /// /// Performs the work of this synchronous worker (or whatever isn't /// done in the constructor at least). /// Returns the ultimate disposition of the activity. /// /// /// Thou shalt not return Stale. /// /// The disposition of this worker's work. public virtual Disposition Complete() { return this.result; } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/VerbToposorter.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; /// /// Mechanism for ordering verbs topologically. /// Used by the Scheduler and related components. /// internal class VerbToposorter : IComparer { /// /// Mapping of verbs to their verb depth. /// private Dictionary verbDepth; /// /// Initializes a new instance of the /// class. /// public VerbToposorter() { this.verbDepth = new Dictionary(); } /// /// Compares two verbs topologically. /// /// /// This is the IComparer.Compare method. /// /// One verb to compare. /// The other verb to compare. /// /// A signed integer that indicates the relative values of x and y, /// see IComparer.Compare interface. /// public int Compare(IVerb x, IVerb y) { int rc; int c0 = this.GetDepth(x) - this.GetDepth(y); if (c0 != 0) { rc = c0; } else { // Break depth ties alphabetically. rc = x.ToString().CompareTo(y.ToString()); } ////Logger.WriteLine(String.Format("Compare({0},{1})=={2}", x, y, rc)); return rc; } /// /// Gets the "depth" (dependency order) of a verb. /// /// The verb in question. /// The verb depth. private int GetDepth(IVerb verb) { if (this.verbDepth.ContainsKey(verb)) { return this.verbDepth[verb]; } int depth; DafnyVerifyOneVerb vone = verb as DafnyVerifyOneVerb; if (vone != null) { int deepestParent = -1; foreach (SourcePath sourcePath in vone.getDirectIncludes()) { IVerb parent = new DafnyVerifyOneVerb(sourcePath); int parentDepth = this.GetDepth(parent); deepestParent = Math.Max(deepestParent, parentDepth); } depth = deepestParent + 1; } else { // Right now we only care about ordering the DafnyVerifyOneVerbs // wrt one another. Other verbs will be constrained by build // dependency anyway. depth = 0; } this.verbDepth[verb] = depth; return depth; } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/VerificationMessage.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Xml; internal class VerificationMessage { public const string _xml_tag = "VerificationMessage"; private const string _xml_message_sourcefile_attr = "SourceFile"; private string sourceLabel; private string message; public VerificationMessage(string sourceLabel, string message) { this.sourceLabel = sourceLabel; this.message = message; } public string SourceLabel { get { return this.sourceLabel; } } public string Message { get { return this.message; } } public static VerificationMessage ReadXml(XmlReader xr) { Util.Assert(xr.Name.Equals(VerificationMessage._xml_tag)); string relSourcePath = xr.GetAttribute(VerificationMessage._xml_message_sourcefile_attr); string message = xr.ReadElementContentAsString(); return new VerificationMessage(relSourcePath, message); } public void WriteXml(XmlWriter xw) { xw.WriteStartElement(VerificationMessage._xml_tag); xw.WriteAttributeString(VerificationMessage._xml_message_sourcefile_attr, this.sourceLabel); xw.WriteString(this.message); xw.WriteEndElement(); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/VerificationObligationList.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; internal class VerificationObligationList { public const string VOL_EXTN = ".vol"; // VOL = Verification Object List private readonly List verificationObligations; private bool complete; public VerificationObligationList() { this.verificationObligations = new List(); } public VerificationObligationList(IEnumerable data) { this.verificationObligations = new List(data); this.complete = true; } public static VerificationObligationList fetch(BuildObject obj) { VerificationObligationList vol = new VerificationObligationList(); using (TextReader sr = BuildEngine.theEngine.Repository.OpenRead(obj)) { string line; while ((line = sr.ReadLine()) != null) { Util.Assert(!line.StartsWith(BuildEngine.theEngine.getSrcRoot())); // unimplemented Util.Assert(!line.StartsWith(BuildEngine.theEngine.getVirtualRoot())); // nonsense vol.Add(new BuildObject(line)); } } vol.complete = true; return vol; } public void Add(BuildObject obj) { Util.Assert(!this.complete); this.verificationObligations.Add(obj); } public IEnumerable getVerificationObligations() { Util.Assert(this.complete); return this.verificationObligations; } public void store(WorkingDirectory workingDirectory, BuildObject location) { this.complete = true; string[] lines = this.verificationObligations.Select(vo => vo.getRelativePath()).ToArray(); File.WriteAllLines(workingDirectory.PathTo(location), lines); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/VerificationRequest.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; internal class VerificationRequest { public VerifyMode verifyMode; public List selectiveVerifyModuleNames; public VerificationRequest() { this.verifyMode = VerifyMode.Verify; this.selectiveVerifyModuleNames = new List(); } public enum VerifyMode { Verify, NoSymDiff, SelectiveVerify, NoVerify } public enum SymDiffMode { UseSymDiff, NoSymDiff } public bool isComplete() { return this.verifyMode == VerifyMode.Verify; } public override string ToString() { if (this.verifyMode == VerifyMode.SelectiveVerify) { return this.verifyMode.ToString() + "(" + string.Join(",", this.selectiveVerifyModuleNames) + ")"; } else { return this.verifyMode.ToString(); } } public SymDiffMode getSymDiffMode() { return this.verifyMode == VerifyMode.Verify ? SymDiffMode.UseSymDiff : SymDiffMode.NoSymDiff; } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/VerificationResult.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; using System.Text.RegularExpressions; using System.Xml; internal class VerificationResult { public const string _VERIFICATION_RESULT_PLACEHOLDER = "_VERIFICATION_RESULT_PLACEHOLDER"; public const string _xml_tag = "VerificationResult"; private const string _xml_sourcePath_attr = "SourcePath"; private const string _xml_outcome_attr = "Outcome"; private const string _xml_parseFailures_attr = "ParseFailures"; private const string _xml_verificationFailures_attr = "VerificationFailures"; private const string _xml_timeouts_attr = "Timeouts"; private const string _xml_cputime_attr = "CPUTime"; private const string _xml_message_tag = "Message"; private const string _xml_message_sourcefile_attr = "SourceFile"; private const string PASS = "pass"; private const string FAIL = "fail"; private static Regex whitespace = new Regex("^\\s*$"); private string _sourceLabel; private bool _pass; private double _cpuTime; private int _parseFailures; private int _verificationFailures; private int _timeouts; private List messages; private Presentation _presentation; public VerificationResult(string sourceLabel, double cpuTime, string stdout, string stderr, IVerificationResultParser parser) { this._sourceLabel = sourceLabel; this._cpuTime = cpuTime; this.messages = new List(); // REVIEW: Switch from whitespace Regex to string.IsNullOrWhiteSpace()? if (!whitespace.Match(stdout).Success) { this.messages.Add(new VerificationMessage(sourceLabel, stdout)); } if (!whitespace.Match(stderr).Success) { this.messages.Add(new VerificationMessage(sourceLabel, stderr)); } this._parseFailures = 0; this._verificationFailures = 0; this._timeouts = 0; parser.parseOutput(stdout + stderr, out this._parseFailures, out this._verificationFailures, out this._timeouts); this._pass = this._parseFailures == 0 && this._verificationFailures == 0 && this._timeouts == 0; } public VerificationResult(string sourceLabel, bool pass, double cpuTime, int parseFailures, int verificationFailures, int timeouts, IEnumerable messages) { this._sourceLabel = sourceLabel; this._pass = pass; this._cpuTime = cpuTime; this._parseFailures = parseFailures; this._verificationFailures = verificationFailures; this._timeouts = timeouts; this.messages = new List(messages); } private VerificationResult() { } public string sourceLabel { get { return this._sourceLabel; } } public bool pass { get { return this._pass; } } public double cpuTime { get { return this._cpuTime; } } public int parseFailures { get { return this._parseFailures; } } public int verificationFailures { get { return this._verificationFailures; } } public int timeouts { get { return this._timeouts; } } public Presentation presentation { get { return this._presentation; } } public static VerificationResult fromXmlFile(BuildObject obj) { using (TextReader ins = BuildEngine.theEngine.Repository.OpenRead(obj)) { XmlReader xr = XmlReader.Create(ins); while (xr.Read()) { if (xr.NodeType == XmlNodeType.Element) { break; } } return readXml(xr); } } public static VerificationResult readXml(XmlReader xr) { Util.Assert(xr.Name.Equals(_xml_tag)); VerificationResult rc = new VerificationResult(); rc._sourceLabel = xr.GetAttribute(_xml_sourcePath_attr); string outcome = xr.GetAttribute(_xml_outcome_attr); if (outcome.Equals(PASS)) { rc._pass = true; } else if (outcome.Equals(FAIL)) { rc._pass = false; } else { throw new Exception("Invalid outcome value " + outcome); } rc._cpuTime = Double.Parse(xr.GetAttribute(_xml_cputime_attr)); rc._parseFailures = Int32.Parse(xr.GetAttribute(_xml_parseFailures_attr)); rc._verificationFailures = Int32.Parse(xr.GetAttribute(_xml_verificationFailures_attr)); rc._timeouts = Int32.Parse(xr.GetAttribute(_xml_timeouts_attr)); rc.messages = new List(); while (xr.Read()) { if (xr.NodeType == XmlNodeType.EndElement) { Util.Assert(xr.Name.Equals(_xml_tag)); break; } else if (xr.NodeType == XmlNodeType.Element) { if (xr.Name.Equals(VerificationMessage._xml_tag)) { rc.messages.Add(VerificationMessage.ReadXml(xr)); } else if (xr.Name.Equals(Presentation._xml_tag)) { rc._presentation = Presentation.fromXml(xr.ReadSubtree()); } else { throw new Exception("Unknown xml tag " + xr.Name); } } } return rc; } public IEnumerable getMessages() { return this.messages; } public void addXmlFiller(Presentation presentation) { this._presentation = presentation; } public void toXmlFile(string path) { File.Delete(path); using (FileStream s = File.OpenWrite(path)) { XmlWriterSettings settings = new XmlWriterSettings(); settings.Indent = true; XmlWriter xw = XmlWriter.Create(s, settings); xw.WriteStartDocument(); this.writeXml(xw); xw.Close(); } } public void writeXml(XmlWriter xw) { xw.WriteStartElement(_xml_tag); xw.WriteAttributeString(_xml_sourcePath_attr, this._sourceLabel); xw.WriteAttributeString(_xml_outcome_attr, this._pass ? PASS : FAIL); xw.WriteAttributeString(_xml_cputime_attr, this._cpuTime.ToString()); xw.WriteAttributeString(_xml_parseFailures_attr, this._parseFailures.ToString()); xw.WriteAttributeString(_xml_verificationFailures_attr, this._verificationFailures.ToString()); xw.WriteAttributeString(_xml_timeouts_attr, this._timeouts.ToString()); foreach (VerificationMessage message in this.messages) { message.WriteXml(xw); } if (this._presentation != null) { this._presentation.fillXml(xw); // TODO we don't know yet how to parse this stuff back in. } xw.WriteEndElement(); } public void addBasicPresentation() { PresentationBuilder pr = new PresentationBuilder(); int any_failures = this.parseFailures + this.verificationFailures + this.timeouts; string overall_status = any_failures > 0 ? "Fail" : "Success"; pr.pre(_VERIFICATION_RESULT_PLACEHOLDER+"\n"); pr.spacer(); pr.startHeader(); pr.color(any_failures == 0 ? Presentation.GREEN : Presentation.RED, "Overall status: " + overall_status); pr.endHeader(); pr.line( string.Format( "{0} parse failures, {1} verification failures, {2} timeouts", this._parseFailures, this._verificationFailures, this._timeouts)); pr.spacer(); foreach (VerificationMessage message in this.messages) { pr.pre(message.Message); } Presentation pres = pr.fix(); this.addXmlFiller(pres); } internal bool wasOnlyTimeouts() { return this.verificationFailures == 0 && this.timeouts > 0; } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/VerificationResultBoogieParser.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Text.RegularExpressions; internal class VerificationResultBoogieParser : IVerificationResultParser { private static Regex dispositionTimeoutsRegex = new Regex("Boogie program verifier finished with (\\d*) verified, (\\d*) errors*, (\\d) time outs*"); private static Regex dispositionNoTimeoutsRegex = new Regex("Boogie program verifier finished with (\\d*) verified, (\\d*) errors*"); private static Regex dispositionParseErrorRegex = new Regex("Error opening file"); private static Regex dispositionParseError2Regex = new Regex("(\\d*) parse errors detected in"); private static Regex dispositionParseError3Regex = new Regex("(\\d*) type checking errors detected in"); private static Regex dispositionParseError4Regex = new Regex("(\\d*) name resolution errors detected in"); private static Regex dispositionProverDiedRegex = new Regex("Prover error: Prover died"); public void parseOutput(string output, out int parseFailures, out int verificationFailures, out int timeouts) { parseFailures = 0; verificationFailures = 0; timeouts = 0; Match match = dispositionTimeoutsRegex.Match(output); if (match.Success) { ////int succeeding_methods = Int32.Parse(m.Groups[1].ToString()); verificationFailures = Int32.Parse(match.Groups[2].ToString()); timeouts = Int32.Parse(match.Groups[3].ToString()); return; } match = dispositionNoTimeoutsRegex.Match(output); if (match.Success) { ////int succeeding_methods = Int32.Parse(m.Groups[1].ToString()); verificationFailures = Int32.Parse(match.Groups[2].ToString()); return; } match = dispositionParseErrorRegex.Match(output); if (match.Success) { parseFailures = 1; return; } match = dispositionParseError2Regex.Match(output); if (match.Success) { parseFailures = Int32.Parse(match.Groups[1].ToString()); return; } match = dispositionParseError3Regex.Match(output); if (match.Success) { parseFailures = Int32.Parse(match.Groups[1].ToString()); return; } match = dispositionParseError4Regex.Match(output); if (match.Success) { parseFailures = Int32.Parse(match.Groups[1].ToString()); return; } match = dispositionProverDiedRegex.Match(output); if (match.Success) { parseFailures = 1; return; } parseFailures = 1; ////throw new Exception("Unable to parse Dafny output"); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/VerificationResultDafnyParser.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Text.RegularExpressions; internal class VerificationResultDafnyParser : IVerificationResultParser { private static Regex dispositionTimeoutsRegex = new Regex("Dafny program verifier finished with (\\d*) verified, (\\d*) errors*, (\\d) time outs*"); private static Regex dispositionNoTimeoutsRegex = new Regex("Dafny program verifier finished with (\\d*) verified, (\\d*) errors*"); private static Regex dispositionParseErrorRegex = new Regex("Error opening file"); private static Regex dispositionParseError2Regex = new Regex("(\\d*) parse errors detected in"); private static Regex dispositionParseError3Regex = new Regex("(\\d*) resolution/type errors detected in"); private static Regex dispositionProverDiedRegex = new Regex("Prover error: Prover died"); public void parseOutput(string output, out int parseFailures, out int verificationFailures, out int timeouts) { parseFailures = 0; verificationFailures = 0; timeouts = 0; Match match = dispositionTimeoutsRegex.Match(output); if (match.Success) { ////int succeeding_methods = Int32.Parse(m.Groups[1].ToString()); verificationFailures = Int32.Parse(match.Groups[2].ToString()); timeouts = Int32.Parse(match.Groups[3].ToString()); return; } match = dispositionNoTimeoutsRegex.Match(output); if (match.Success) { ////int succeeding_methods = Int32.Parse(m.Groups[1].ToString()); verificationFailures = Int32.Parse(match.Groups[2].ToString()); return; } match = dispositionParseErrorRegex.Match(output); if (match.Success) { parseFailures = 1; return; } match = dispositionParseError2Regex.Match(output); if (match.Success) { parseFailures = Int32.Parse(match.Groups[1].ToString()); return; } match = dispositionParseError3Regex.Match(output); if (match.Success) { parseFailures = Int32.Parse(match.Groups[1].ToString()); return; } match = dispositionProverDiedRegex.Match(output); if (match.Success) { parseFailures = 1; return; } parseFailures = 1; Logger.WriteLine("NuBuild WARNING: unexpected Dafny error message; lumping into parse errors."); ////throw new Exception("Unable to parse Dafny output"); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/VerificationResultSummaryVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; internal class VerificationResultSummaryVerb : VerificationResultVerb ////, IObligationsProducer { private const string SUMMARY_EXTN = ".summary"; private const int version = 4; private BuildObject outputObject; private IObligationsProducer producer; private IEnumerable verificationResults; private AbstractId abstractId; public VerificationResultSummaryVerb(IObligationsProducer producer) { this.producer = producer; BuildObject id = producer.getObligationSet(); ////producer.getIdentifier(); this.outputObject = id.makeOutputObject(id.getExtension() + SUMMARY_EXTN); this.abstractId = new AbstractId(this.GetType().Name, version, id.ToString()); this.verificationResults = null; } public override AbstractId getAbstractIdentifier() { return this.abstractId; } public override IEnumerable getDependencies(out DependencyDisposition ddisp) { BuildObject obligations = this.producer.getObligationSet(); HashSet deps = new HashSet(); deps.Add(obligations); try { VerificationObligationList vol = VerificationObligationList.fetch(obligations); this.verificationResults = vol.getVerificationObligations(); deps.UnionWith(this.verificationResults); ddisp = DependencyDisposition.Complete; } catch (ObjectNotReadyException) { ddisp = DependencyDisposition.Incomplete; } catch (ObjectFailedException) { ddisp = DependencyDisposition.Failed; } return deps; } public override IEnumerable getVerbs() { IEnumerable verbs = new IVerb[] { this.producer }; verbs = verbs.Union(this.producer.getVerbs()); return verbs; // VerificationResultSummaryVerb depends on objects mentioned by producer, // but the necessary verbs haven't been mentioned. Is it sufficient for // the upstream guy (BoogieAsmVerificationObligationList) to ... hopefully ... // mention them? (Hopefully because he might only be incompletely queried, // since he's not actually dependent on the verbs he's advertising.) // Maybe we should provide a way for his complete() method to push the // verbs into the cache. } public override IEnumerable getOutputs() { return new HashSet() { this.outputObject }; } public override BuildObject getOutputFile() { return this.outputObject; } public BuildObject getObligationSet() { return this.producer.getObligationSet(); } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { // Read and aggregate all the input results. int parseFailures = 0; int verificationFailures = 0; int timeouts = 0; int filesWithParseFailures = 0; int filesWithVerificationFailures = 0; int filesWithTimeouts = 0; int passCount = 0; int failCount = 0; double cpuTime = 0; List failMessages = new List(); List results = new List(); // REVIEW: Why pull out the enumerator this way? IEnumerable verificationResultsEnumerator = this.verificationResults; foreach (BuildObject verificationResult in verificationResultsEnumerator) { VerificationResult vr = VerificationResult.fromXmlFile(verificationResult); results.Add(vr); if (vr == null) { return new VerbSyncWorker( workingDirectory, new Failed("Build system broke: missing VerificationResult for " + verificationResult)); } if (vr.pass) { passCount += 1; } else { failCount += 1; failMessages.AddRange(vr.getMessages()); } parseFailures += vr.parseFailures; verificationFailures += vr.verificationFailures; timeouts += vr.timeouts; filesWithParseFailures += vr.parseFailures > 0 ? 1 : 0; filesWithVerificationFailures += vr.verificationFailures > 0 ? 1 : 0; filesWithTimeouts += vr.timeouts > 0 ? 1 : 0; ////Logger.WriteLine("Synthesizing cpuTime from " + verificationResult); cpuTime += vr.cpuTime; } bool allPass = failCount == 0; PresentationBuilder pr = new PresentationBuilder(); int any_failures = parseFailures + verificationFailures + timeouts; string overall_status = any_failures > 0 ? "Fail" : "Success"; pr.pre(VerificationResult._VERIFICATION_RESULT_PLACEHOLDER+"\n"); pr.spacer(); pr.startHeader(); pr.color(this.colorByFailureCount(any_failures), "Overall status: " + overall_status); pr.endHeader(); pr.line("Count of files with failures: " + failCount); pr.startBullet(); pr.color(this.colorByFailureCount(filesWithParseFailures), "Files with parse failures: " + filesWithParseFailures.ToString()); pr.endBullet(); pr.startBullet(); pr.color(this.colorByFailureCount(filesWithVerificationFailures), "Files with verification failures: " + filesWithVerificationFailures.ToString()); pr.endBullet(); pr.startBullet(); pr.color(this.colorByFailureCount(filesWithTimeouts), "Files with timeouts: " + filesWithTimeouts.ToString()); pr.endBullet(); pr.spacer(); pr.header(string.Format("Total processing time: {0:0.0}s {1}", cpuTime, new TimeSpan((long)(cpuTime * 10000000L)))); int top_n = 10; pr.header(string.Format("Slowest {0} verifications:", top_n)); results.Sort(this.ByCpuTimeDecreasing); foreach (VerificationResult slowResult in results.Take(top_n)) { pr.startBullet(); pr.color( this.colorByFailureCount(slowResult.pass ? 0 : 1), string.Format("{0,6:##0.0}s {1}", slowResult.cpuTime, slowResult.sourceLabel)); pr.endBullet(); } foreach (VerificationMessage message in failMessages) { pr.spacer(); pr.header("Failure with " + message.SourceLabel); pr.pre(message.Message); } Presentation pres = pr.fix(); VerificationResult outvr = new VerificationResult("summary", allPass, cpuTime, parseFailures, verificationFailures, timeouts, failMessages); outvr.addXmlFiller(pres); outvr.toXmlFile(workingDirectory.PathTo(this.outputObject)); this.setWasRejectableFailure(!outvr.pass); return new VerbSyncWorker(workingDirectory, new Fresh()); } public override Presentation getRealtimePresentation(Disposition d) { if (d is Failed) { return base.getRealtimePresentation(d); } VerificationResult vr = VerificationResult.fromXmlFile(this.outputObject); PresentationBuilder pr = new PresentationBuilder(); pr.startLine(); pr.color( vr.pass ? Presentation.GREEN : Presentation.RED, string.Format( "{0} {1} {2,1:0.0}s", this.getAbstractIdentifier(), vr.pass ? "Success" : "Fail", vr.cpuTime)); pr.endLine(); if (!vr.pass) { foreach (VerificationMessage msg in vr.getMessages()) { pr.pre(msg.Message); } } return pr.fix(); } public override Presentation getPresentation() { VerificationResult vr = VerificationResult.fromXmlFile(this.outputObject); return vr.presentation; } protected override BuildObject getSource() { return this.producer.getObligationSet(); } private int ByCpuTimeDecreasing(VerificationResult va, VerificationResult vb) { return -(va.cpuTime.CompareTo(vb.cpuTime)); } private string colorByFailureCount(int count) { return count == 0 ? Presentation.GREEN : Presentation.RED; } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/VerificationResultVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; internal abstract class VerificationResultVerb : Verb, IRejectable { public const string VERIFICATION_RESULT_EXTN = ".v"; private bool dbgWasVerificationTimeoutRecorded; private bool wasRejectableFailure; public abstract BuildObject getOutputFile(); public override Presentation getRealtimePresentation(Disposition d) { if (d is Failed) { return base.getRealtimePresentation(d); } VerificationResult vr = VerificationResult.fromXmlFile(this.getOutputFile()); PresentationBuilder pr = new PresentationBuilder(); pr.startLine(); pr.color( vr.pass ? Presentation.GREEN : Presentation.RED, string.Format( "{0} {1} {2,5:0.0}s", ////getSource().getRelativePath(), this.getAbstractIdentifier(), vr.pass ? "Success" : "Fail", vr.cpuTime)); pr.endLine(); if (!vr.pass) { foreach (VerificationMessage msg in vr.getMessages()) { pr.pre(msg.Message); } } return pr.fix(); } public override Presentation getPresentation() { VerificationResult vr = VerificationResult.fromXmlFile(this.getOutputFile()); return vr.presentation; } public bool resultWasRejectableFailure() { Util.Assert(this.dbgWasVerificationTimeoutRecorded); return this.wasRejectableFailure; } protected abstract BuildObject getSource(); protected void setWasRejectableFailure(bool value) { this.dbgWasVerificationTimeoutRecorded = true; this.wasRejectableFailure = value; } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/VirtualBuildObject.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; /// /// Representation of a virtual BuildObject. /// A VirtualBuildObject is never actually stored in the filesystem; /// it is only materialized inside the process. It's used for results /// that are easy to compute, but which still need to be established /// in dependency order. Instances: transitive deps, contexts. /// internal class VirtualBuildObject : BuildObject { /// /// Initializes a new instance of the VirtualBuildObject class. /// /// Virtual path name of the object. public VirtualBuildObject(string inpath) : base(inpath) { Util.Assert(inpath.StartsWith(BuildEngine.theEngine.getVirtualRoot(), StringComparison.OrdinalIgnoreCase)); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/VirtualContents.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; /// /// This class is perfectly named; it contains nothing. /// Serves solely as a base class for other derived classes. /// internal class VirtualContents { } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/WaitIndex.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Linq; /// /// Used by the Scheduler to track waiting verbs and their dependencies. /// internal class WaitIndex { private Dictionary waitingVerbs; private Dictionary> fwdDeps; public WaitIndex() { this.waitingVerbs = new Dictionary(); this.fwdDeps = new Dictionary>(); } public int Count() { return this.waitingVerbs.Count; } public void dbgDisplayIndex(Scheduler dbgScheduler) { List waitRecords = new List(this.waitingVerbs.Values); for (int i = 0; i < waitRecords.Count(); i++) { WaitRecord wr = waitRecords[i]; List depNums = new List(); List unknownDeps = new List(); List unscheduledDeps = new List(); foreach (BuildObject dep in wr.knownDeps) { IVerb depOnVerb = dbgScheduler.getParent(dep); if (depOnVerb == null) { unknownDeps.Add(dep); } else if (!this.waitingVerbs.ContainsKey(depOnVerb)) { unscheduledDeps.Add( string.Format( "{0} waiting on {1} {2}", dep, depOnVerb, dbgScheduler.dbgGetVerbStatus(depOnVerb))); } else { WaitRecord depWr = this.waitingVerbs[depOnVerb]; depNums.Add(waitRecords.IndexOf(depWr)); } } Logger.WriteLine( string.Format( "{0}. {1} waits on ({2}), {3} unknown, {4} unscheduled", i, wr.verb, string.Join(",", depNums), unknownDeps.Count(), unscheduledDeps.Count())); this.dbgPreview("Unknown", unknownDeps.Select(it => it.ToString()), 3); this.dbgPreview("Unscheduled", unscheduledDeps, 20); } } internal void insert(IVerb verb, IEnumerable knownDeps) { // Insert one fwd pointer for each obj verb is already known to // depend upon. The fact that this verb is waiting implies that // one of these deps is stale here and needs built/fetched. WaitRecord waitRecord = new WaitRecord(verb, knownDeps); foreach (BuildObject dep in knownDeps) { if (!this.fwdDeps.ContainsKey(dep)) { this.fwdDeps.Add(dep, new HashSet()); } this.fwdDeps[dep].Add(waitRecord); } this.waitingVerbs.Add(verb, waitRecord); this.Say("sleeps " + verb); } // Remove any verb with obj in its dependency set. internal IEnumerable awaken(BuildObject obj) { this.Say("awaken " + obj); HashSet wokenRecords; HashSet result = new HashSet(); if (this.fwdDeps.ContainsKey(obj)) { wokenRecords = this.fwdDeps[obj]; this.fwdDeps.Remove(obj); // Remove all the other index pointers for each removed verb. foreach (WaitRecord waitRecord in wokenRecords) { foreach (BuildObject dep in waitRecord.knownDeps) { if (this.fwdDeps.ContainsKey(dep)) { this.fwdDeps[dep].Remove(waitRecord); } } result.Add(waitRecord.verb); this.waitingVerbs.Remove(waitRecord.verb); this.Say(" wakes " + waitRecord.verb); } } else { result = new HashSet(); } return result; } internal bool isWaiting(IVerb verb) { return this.waitingVerbs.ContainsKey(verb); } private void dbgPreview(string s, IEnumerable items, int max) { int i = 0; foreach (string o in items) { Logger.WriteLine( string.Format( " {0} {1}/{2} {3}", s, i, items.Count(), o)); i += 1; if (i == max) { break; } } } private void Say(string msg) { ////Logger.WriteLine("[wtidx] " + msg); } private class WaitRecord { public IVerb verb; public IEnumerable knownDeps; public WaitRecord(IVerb verb, IEnumerable knownDeps) { this.verb = verb; this.knownDeps = knownDeps; } } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/WinLinkerVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; internal class WinLinkerVerb : LinkerVerb { public const string WIN_APP_EXE_EXTN = ".winapp"; private const int version = 6; public WinLinkerVerb(MasmVerb masmVerb, bool isLoader) : base(masmVerb, isLoader) { } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { // TODO: We shouldn't be using absolute paths to any of these things. // Change this to allow VS and SDKs to be installed anywhere. string linker = @"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin\link.exe"; string vc_lib_dir = @"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\lib"; string sdk_dir = @"C:\Program Files (x86)\Windows Kits\8.1\Lib\winv6.3\um\x86"; string kernel_lib = @"C:\Program Files (x86)\Windows Kits\8.1\Lib\winv6.3\um\x86\kernel32.Lib"; string standalone_support_lib = getStandaloneLib().getRelativePath(); SourcePath zero1 = new SourcePath("tools\\scripts\\zero.obj", SourcePath.SourceType.Tools); SourcePath zero2 = new SourcePath("tools\\scripts\\zero2.obj", SourcePath.SourceType.Tools); // TODO: Fail more gracefully? Or better yet, move these into iron/tools. if (!Directory.Exists(vc_lib_dir)) { throw new FileNotFoundException("Missing Visual C++ library directory: " + vc_lib_dir); } if (!Directory.Exists(sdk_dir) || !File.Exists(kernel_lib)) { throw new FileNotFoundException("Missing Windows SDK libraries: " + sdk_dir + ", " + kernel_lib + @". Try installing the Windows SDK from: \\research\Root\Products\Developers\Windows Driver Kit 8.1"); } // TODO: Unpack/generate these automatically. // TODO: Brian, we're really not going to want to cache these big, empty sources. Or compress? All big (>10MB) files. // are mostly zeros. if (!File.Exists(IronRootDirectory.PathTo(zero1)) || !File.Exists(IronRootDirectory.PathTo(zero2))) { throw new FileNotFoundException("Missing object files of zeroes: " + zero1 + ", " + zero2 + ". Try running: tools\\scripts\\build-standalone-init.sh"); } List args = new List() { "/DEBUG", "/subsystem:console", "/LARGEADDRESSAWARE", "/fixed" }; args.Add(objFile.getRelativePath()); args.Add(zero1.getRelativePath()); args.Add(zero2.getRelativePath()); args.Add(standalone_support_lib); args.Add(@"""" + kernel_lib + @""""); args.Add("\"/libpath:" + vc_lib_dir + '"'); args.Add("\"/libpath:" + sdk_dir + '"'); args.Add("/out:" + outputObject.getRelativePath()); args.Add("/entry:" + this.entryPoint); args.Add("/base:" + this.baseAddr); args.Add("/PDB:" + this.getPdb()); return new ProcessInvokeAsyncWorker( workingDirectory, this, linker, args.ToArray(), ProcessExitCodeHandling.NonzeroIsFailure, getDiagnosticsBase(), allowAbsoluteExe: true, allowAbsoluteArgs: true); } public override Disposition Complete(WorkingDirectory workingDirectory, double cpuTimeSeconds, string stdout, string stderr, Disposition disposition) { // No cleanup to do. return disposition; } // TODO: We should build this! protected static SourcePath getStandaloneLib() { return new SourcePath("tools\\standalone\\Debug\\StandAloneSupport.lib", SourcePath.SourceType.Tools); } protected override IEnumerable getExtraOutputs() { List outputs = new List(); outputs.Add(this.getPdb()); return outputs; } protected override string outputExtension() { return WIN_APP_EXE_EXTN + LinkerVerb.UNTRUSTED_EXE_EXTN; } protected override int getVersion() { return version; } protected override IEnumerable getExtraDependencies() { return new List() { getStandaloneLib() }; } private BuildObject getPdb() { return objFile.makeOutputObject(".pdb"); } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/WorkingDirectory.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; /// /// A directory tree in the local filesystem for a verb to operate upon. /// Verbs should not access files outside of this directory tree. /// public class WorkingDirectory { /// /// Absolute path to this working directory on the local system. /// private string path; /// /// Initializes a new instance of the WorkingDirectory class. /// /// /// Absolute path to the "iron" directory on the local system. /// public WorkingDirectory(string ironroot) { // REVIEW: Have "nutemp" hard-wired here, or passed in? this.path = Path.Combine(ironroot, "nutemp", Path.GetRandomFileName()); Directory.CreateDirectory(this.path); } /// /// Gets the absolute path to the root of this working directory on the local system. /// public string Root { get { return this.path; } } /// /// Gets the absolute path to the given build object in this working directory. /// /// A build object. /// The absolute path to the build object. public string PathTo(BuildObject obj) { return Path.Combine(this.path, obj.getRelativePath()); } /// /// Gets the absolute path corresponding to the given relative path in this working directory. /// /// Relative path to convert. /// The absolute path corresponding to the given relative path. public string PathTo(string relativePath) { return Path.Combine(this.path, relativePath); } /// /// Creates the directory in the local filesystem that corresponds /// to this instance. /// /// A build object. public void CreateDirectoryFor(BuildObject obj) { Directory.CreateDirectory(Path.Combine(this.path, obj.getDirPath())); } /// /// Gets a collection of the build objects in this directory. /// /// /// REVIEW: Return a collection of BuildObjectValuePointers instead? /// /// A collection of build objects. public IEnumerable GetContents() { List contents = new List(); foreach (string fileName in Directory.EnumerateFiles(this.path)) { contents.Add(new BuildObject(fileName)); } return contents; } } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild/XmlFiller.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Xml; /// /// REVIEW: Does this need to be an interface? /// TODO: Rename to IXmlFiller if we need to keep this. /// internal interface XmlFiller { void fillXml(XmlWriter xml); } } ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuild.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0.31101.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NuBuild", "NuBuild\NuBuild.csproj", "{4D7220C0-3CAA-4659-9F16-A564DB3CCC1B}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ItemCacheTool", "ItemCacheTool\ItemCacheTool.csproj", "{9A231EB8-BDA1-4304-93A1-20457C00D7D9}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{43E97C4F-FD2F-49AD-B29A-DEACC270D91B}" ProjectSection(SolutionItems) = preProject Settings.StyleCop = Settings.StyleCop EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CloudExecutionEngine", "CloudExecutionEngine\CloudExecutionEngine.csproj", "{2668E334-0B79-4023-A621-2D1433CE7C9E}" ProjectSection(ProjectDependencies) = postProject {4F3DE22C-CAE9-408B-AA54-10DCD7E12F09} = {4F3DE22C-CAE9-408B-AA54-10DCD7E12F09} EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CloudQueueTool", "CloudQueueTool\CloudQueueTool.csproj", "{DD7B4AD9-1EB0-47BF-B4C2-5BC1CA85D242}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AzureManager", "AzureManager\AzureManager.csproj", "{8ADB4B14-715D-4CE1-BFD2-E7D65007CE5C}" EndProject Project("{CC5FD16D-436D-48AD-A40C-5A424C6E3E79}") = "NuBuildExecutionService", "NuBuildExecutionService\NuBuildExecutionService.ccproj", "{697EA8B8-1846-4628-AB27-066BEC899EC2}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CloudExecutionWorker", "CloudExecutionWorker\CloudExecutionWorker.csproj", "{4F3DE22C-CAE9-408B-AA54-10DCD7E12F09}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {4D7220C0-3CAA-4659-9F16-A564DB3CCC1B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4D7220C0-3CAA-4659-9F16-A564DB3CCC1B}.Debug|Any CPU.Build.0 = Debug|Any CPU {4D7220C0-3CAA-4659-9F16-A564DB3CCC1B}.Release|Any CPU.ActiveCfg = Release|Any CPU {4D7220C0-3CAA-4659-9F16-A564DB3CCC1B}.Release|Any CPU.Build.0 = Release|Any CPU {9A231EB8-BDA1-4304-93A1-20457C00D7D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9A231EB8-BDA1-4304-93A1-20457C00D7D9}.Debug|Any CPU.Build.0 = Debug|Any CPU {9A231EB8-BDA1-4304-93A1-20457C00D7D9}.Release|Any CPU.ActiveCfg = Release|Any CPU {9A231EB8-BDA1-4304-93A1-20457C00D7D9}.Release|Any CPU.Build.0 = Release|Any CPU {2668E334-0B79-4023-A621-2D1433CE7C9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2668E334-0B79-4023-A621-2D1433CE7C9E}.Debug|Any CPU.Build.0 = Debug|Any CPU {2668E334-0B79-4023-A621-2D1433CE7C9E}.Release|Any CPU.ActiveCfg = Release|Any CPU {2668E334-0B79-4023-A621-2D1433CE7C9E}.Release|Any CPU.Build.0 = Release|Any CPU {DD7B4AD9-1EB0-47BF-B4C2-5BC1CA85D242}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {DD7B4AD9-1EB0-47BF-B4C2-5BC1CA85D242}.Debug|Any CPU.Build.0 = Debug|Any CPU {DD7B4AD9-1EB0-47BF-B4C2-5BC1CA85D242}.Release|Any CPU.ActiveCfg = Release|Any CPU {DD7B4AD9-1EB0-47BF-B4C2-5BC1CA85D242}.Release|Any CPU.Build.0 = Release|Any CPU {8ADB4B14-715D-4CE1-BFD2-E7D65007CE5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8ADB4B14-715D-4CE1-BFD2-E7D65007CE5C}.Debug|Any CPU.Build.0 = Debug|Any CPU {8ADB4B14-715D-4CE1-BFD2-E7D65007CE5C}.Release|Any CPU.ActiveCfg = Release|Any CPU {8ADB4B14-715D-4CE1-BFD2-E7D65007CE5C}.Release|Any CPU.Build.0 = Release|Any CPU {697EA8B8-1846-4628-AB27-066BEC899EC2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {697EA8B8-1846-4628-AB27-066BEC899EC2}.Debug|Any CPU.Build.0 = Debug|Any CPU {697EA8B8-1846-4628-AB27-066BEC899EC2}.Release|Any CPU.ActiveCfg = Release|Any CPU {697EA8B8-1846-4628-AB27-066BEC899EC2}.Release|Any CPU.Build.0 = Release|Any CPU {4F3DE22C-CAE9-408B-AA54-10DCD7E12F09}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4F3DE22C-CAE9-408B-AA54-10DCD7E12F09}.Debug|Any CPU.Build.0 = Debug|Any CPU {4F3DE22C-CAE9-408B-AA54-10DCD7E12F09}.Release|Any CPU.ActiveCfg = Release|Any CPU {4F3DE22C-CAE9-408B-AA54-10DCD7E12F09}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuildExecutionService/.gitignore ================================================ *.ccproj.user ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuildExecutionService/CloudExecutionWorkerContent/diagnostics.wadcfg ================================================  ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuildExecutionService/NuBuildExecutionService.ccproj ================================================  Debug AnyCPU 2.5 697ea8b8-1846-4628-ab27-066bec899ec2 Library Properties NuBuildExecutionService NuBuildExecutionService False NuBuildExecutionService True False true full false bin\Debug\ DEBUG;TRACE prompt 4 pdbonly true bin\Release\ TRACE prompt 4 CloudExecutionWorker {4f3de22c-cae9-408b-aa54-10dcd7e12f09} True Worker CloudExecutionWorker True Content 10.0 $(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Windows Azure Tools\2.5\ ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuildExecutionService/ServiceConfiguration.Cloud.cscfg ================================================  ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuildExecutionService/ServiceConfiguration.Local.cscfg ================================================  ================================================ FILE: ironclad-apps/tools/NuBuild/NuBuildExecutionService/ServiceDefinition.csdef ================================================  ================================================ FILE: ironclad-apps/tools/NuBuild/References/Microsoft.Threading.Tasks.xml ================================================ Microsoft.Threading.Tasks Provides extension methods for threading-related types. Cancels the after the specified duration. The CancellationTokenSource. The due time in milliseconds for the source to be canceled. Cancels the after the specified duration. The CancellationTokenSource. The due time for the source to be canceled. Gets an awaiter used to await this . The task to await. An awaiter instance. Gets an awaiter used to await this . Specifies the type of data returned by the task. The task to await. An awaiter instance. Creates and configures an awaitable object for awaiting the specified task. The task to be awaited. true to automatic marshag back to the original call site's current SynchronizationContext or TaskScheduler; otherwise, false. The instance to be awaited. Creates and configures an awaitable object for awaiting the specified task. The task to be awaited. true to automatic marshag back to the original call site's current SynchronizationContext or TaskScheduler; otherwise, false. The instance to be awaited. Event handler for progress reports. Specifies the type of data for the progress report. The sender of the report. The reported value. Provides an IProgress{T} that invokes callbacks for each reported progress value. Specifies the type of the progress report value. Any handler provided to the constructor or event handlers registered with the event are invoked through a instance captured when the instance is constructed. If there is no current SynchronizationContext at the time of construction, the callbacks will be invoked on the ThreadPool. The synchronization context captured upon construction. This will never be null. The handler specified to the constructor. This may be null. A cached delegate used to post invocation to the synchronization context. Initializes the . Initializes the with the specified callback. A handler to invoke for each reported progress value. This handler will be invoked in addition to any delegates registered with the event. The is null (Nothing in Visual Basic). Reports a progress change. The value of the updated progress. Reports a progress change. The value of the updated progress. Invokes the action and event callbacks. The progress value. Raised for each reported progress value. Handlers registered with this event will be invoked on the captured when the instance was constructed. Holds static values for . This avoids one static instance per type T. A default synchronization context that targets the ThreadPool. Throws the exception on the ThreadPool. The exception to propagate. The target context on which to propagate the exception. Null to use the ThreadPool. Copies the exception's stack trace so its stack trace isn't overwritten. The exception to prepare. Provides an awaitable object that allows for configured awaits on . This type is intended for compiler use only. The task being awaited. Initializes the . The awaitable . true to attempt to marshal the continuation back to the original context captured; otherwise, false. Gets an awaiter for this awaitable. The awaiter. Provides an awaiter for a . This type is intended for compiler use only. The task being awaited. Whether to attempt marshaling back to the original context. Initializes the . The to await. true to attempt to marshal the continuation back to the original context captured when BeginAwait is called; otherwise, false. Schedules the continuation onto the associated with this . The action to invoke when the await operation completes. The argument is null (Nothing in Visual Basic). The awaiter was not properly initialized. This method is intended for compiler user rather than use directly in code. Schedules the continuation onto the associated with this . The action to invoke when the await operation completes. The argument is null (Nothing in Visual Basic). The awaiter was not properly initialized. This method is intended for compiler user rather than use directly in code. Ends the await on the completed . The result of the completed . The awaiter was not properly initialized. The task was not yet completed. The task was canceled. The task completed in a Faulted state. Gets whether the task being awaited is completed. This property is intended for compiler user rather than use directly in code. The awaiter was not properly initialized. Provides an awaitable object that allows for configured awaits on . This type is intended for compiler use only. The underlying awaitable on whose logic this awaitable relies. Initializes the . The awaitable . true to attempt to marshal the continuation back to the original context captured; otherwise, false. Gets an awaiter for this awaitable. The awaiter. Provides an awaiter for a . This type is intended for compiler use only. The task being awaited. Whether to attempt marshaling back to the original context. Initializes the . The awaitable . true to attempt to marshal the continuation back to the original context captured; otherwise, false. Schedules the continuation onto the associated with this . The action to invoke when the await operation completes. The argument is null (Nothing in Visual Basic). The awaiter was not properly initialized. This method is intended for compiler user rather than use directly in code. Schedules the continuation onto the associated with this . The action to invoke when the await operation completes. The argument is null (Nothing in Visual Basic). The awaiter was not properly initialized. This method is intended for compiler user rather than use directly in code. Ends the await on the completed . The result of the completed . The awaiter was not properly initialized. The task was not yet completed. The task was canceled. The task completed in a Faulted state. Gets whether the task being awaited is completed. This property is intended for compiler user rather than use directly in code. The awaiter was not properly initialized. Provides an awaiter for awaiting a . This type is intended for compiler use only. The default value to use for continueOnCapturedContext. Error message for GetAwaiter. The task being awaited. Initializes the . The to be awaited. Schedules the continuation onto the associated with this . The action to invoke when the await operation completes. The argument is null (Nothing in Visual Basic). The awaiter was not properly initialized. This method is intended for compiler user rather than use directly in code. Schedules the continuation onto the associated with this . The action to invoke when the await operation completes. The argument is null (Nothing in Visual Basic). The awaiter was not properly initialized. This method is intended for compiler user rather than use directly in code. Ends the await on the completed . The awaiter was not properly initialized. The task was not yet completed. The task was canceled. The task completed in a Faulted state. Fast checks for the end of an await operation to determine whether more needs to be done prior to completing the await. The awaited task. Handles validations on tasks that aren't successfully completed. The awaited task. Throws an exception to handle a task that completed in a state other than RanToCompletion. Schedules the continuation onto the associated with this . The awaited task. The action to invoke when the await operation completes. Whether to capture and marshal back to the current context. The argument is null (Nothing in Visual Basic). The awaiter was not properly initialized. This method is intended for compiler user rather than use directly in code. Invokes the delegate in a try/catch that will propagate the exception asynchronously on the ThreadPool. Copies the exception's stack trace so its stack trace isn't overwritten. The exception to prepare. Gets whether the task being awaited is completed. This property is intended for compiler user rather than use directly in code. The awaiter was not properly initialized. Whether the current thread is appropriate for inlining the await continuation. Provides an awaiter for awaiting a . This type is intended for compiler use only. The task being awaited. Initializes the . The to be awaited. Schedules the continuation onto the associated with this . The action to invoke when the await operation completes. The argument is null (Nothing in Visual Basic). The awaiter was not properly initialized. This method is intended for compiler user rather than use directly in code. Schedules the continuation onto the associated with this . The action to invoke when the await operation completes. The argument is null (Nothing in Visual Basic). The awaiter was not properly initialized. This method is intended for compiler user rather than use directly in code. Ends the await on the completed . The result of the completed . The awaiter was not properly initialized. The task was not yet completed. The task was canceled. The task completed in a Faulted state. Gets whether the task being awaited is completed. This property is intended for compiler user rather than use directly in code. The awaiter was not properly initialized. Provides an awaitable context for switching into a target environment. This type is intended for compiler use only. Gets an awaiter for this . An awaiter for this awaitable. This method is intended for compiler user rather than use directly in code. Provides an awaiter that switches into a target environment. This type is intended for compiler use only. A completed task. Posts the back to the current context. The action to invoke asynchronously. The awaiter was not properly initialized. Posts the back to the current context. The action to invoke asynchronously. The awaiter was not properly initialized. Ends the await operation. Gets whether a yield is not required. This property is intended for compiler user rather than use directly in code. Provides methods for creating and manipulating tasks. Creates a task that runs the specified action. The action to execute asynchronously. A task that represents the completion of the action. The argument is null. Creates a task that runs the specified action. The action to execute. The CancellationToken to use to request cancellation of this task. A task that represents the completion of the action. The argument is null. Creates a task that runs the specified function. The function to execute asynchronously. A task that represents the completion of the action. The argument is null. Creates a task that runs the specified function. The action to execute. The CancellationToken to use to cancel the task. A task that represents the completion of the action. The argument is null. Creates a task that runs the specified function. The action to execute asynchronously. A task that represents the completion of the action. The argument is null. Creates a task that runs the specified function. The function to execute. The CancellationToken to use to request cancellation of this task. A task that represents the completion of the function. The argument is null. Creates a task that runs the specified function. The function to execute asynchronously. A task that represents the completion of the action. The argument is null. Creates a task that runs the specified function. The action to execute. The CancellationToken to use to cancel the task. A task that represents the completion of the action. The argument is null. Starts a Task that will complete after the specified due time. The delay in milliseconds before the returned task completes. The timed Task. The argument must be non-negative or -1 and less than or equal to Int32.MaxValue. Starts a Task that will complete after the specified due time. The delay before the returned task completes. The timed Task. The argument must be non-negative or -1 and less than or equal to Int32.MaxValue. Starts a Task that will complete after the specified due time. The delay before the returned task completes. A CancellationToken that may be used to cancel the task before the due time occurs. The timed Task. The argument must be non-negative or -1 and less than or equal to Int32.MaxValue. Starts a Task that will complete after the specified due time. The delay in milliseconds before the returned task completes. A CancellationToken that may be used to cancel the task before the due time occurs. The timed Task. The argument must be non-negative or -1 and less than or equal to Int32.MaxValue. An already completed task. Creates a Task that will complete only when all of the provided collection of Tasks has completed. The Tasks to monitor for completion. A Task that represents the completion of all of the provided tasks. If any of the provided Tasks faults, the returned Task will also fault, and its Exception will contain information about all of the faulted tasks. If no Tasks fault but one or more Tasks is canceled, the returned Task will also be canceled. The argument is null. The argument contains a null reference. Creates a Task that will complete only when all of the provided collection of Tasks has completed. The Tasks to monitor for completion. A Task that represents the completion of all of the provided tasks. If any of the provided Tasks faults, the returned Task will also fault, and its Exception will contain information about all of the faulted tasks. If no Tasks fault but one or more Tasks is canceled, the returned Task will also be canceled. The argument is null. The argument contains a null reference. Creates a Task that will complete only when all of the provided collection of Tasks has completed. The Tasks to monitor for completion. A Task that represents the completion of all of the provided tasks. If any of the provided Tasks faults, the returned Task will also fault, and its Exception will contain information about all of the faulted tasks. If no Tasks fault but one or more Tasks is canceled, the returned Task will also be canceled. The argument is null. The argument contains a null reference. Creates a Task that will complete only when all of the provided collection of Tasks has completed. The Tasks to monitor for completion. A Task that represents the completion of all of the provided tasks. If any of the provided Tasks faults, the returned Task will also fault, and its Exception will contain information about all of the faulted tasks. If no Tasks fault but one or more Tasks is canceled, the returned Task will also be canceled. The argument is null. The argument contains a null reference. Creates a Task that will complete only when all of the provided collection of Tasks has completed. The Tasks to monitor for completion. A callback invoked when all of the tasks complete successfully in the RanToCompletion state. This callback is responsible for storing the results into the TaskCompletionSource. A Task that represents the completion of all of the provided tasks. The argument is null. The argument contains a null reference. Creates a Task that will complete when any of the tasks in the provided collection completes. The Tasks to be monitored. A Task that represents the completion of any of the provided Tasks. The completed Task is this Task's result. Any Tasks that fault will need to have their exceptions observed elsewhere. The argument is null. The argument contains a null reference. Creates a Task that will complete when any of the tasks in the provided collection completes. The Tasks to be monitored. A Task that represents the completion of any of the provided Tasks. The completed Task is this Task's result. Any Tasks that fault will need to have their exceptions observed elsewhere. The argument is null. The argument contains a null reference. Creates a Task that will complete when any of the tasks in the provided collection completes. The Tasks to be monitored. A Task that represents the completion of any of the provided Tasks. The completed Task is this Task's result. Any Tasks that fault will need to have their exceptions observed elsewhere. The argument is null. The argument contains a null reference. Creates a Task that will complete when any of the tasks in the provided collection completes. The Tasks to be monitored. A Task that represents the completion of any of the provided Tasks. The completed Task is this Task's result. Any Tasks that fault will need to have their exceptions observed elsewhere. The argument is null. The argument contains a null reference. Creates an already completed from the specified result. The result from which to create the completed task. The completed task. Creates an awaitable that asynchronously yields back to the current context when awaited. A context that, when awaited, will asynchronously transition back into the current context. If SynchronizationContext.Current is non-null, that is treated as the current context. Otherwise, TaskScheduler.Current is treated as the current context. Adds the target exception to the list, initializing the list if it's null. The list to which to add the exception and initialize if the list is null. The exception to add, and unwrap if it's an aggregate. Returns a canceled task. The cancellation token. The canceled task. Returns a canceled task. Specifies the type of the result. The cancellation token. The canceled task. Completes the Task if the user state matches the TaskCompletionSource. Specifies the type of data returned by the Task. The TaskCompletionSource. The completion event arguments. Whether we require the tcs to match the e.UserState. A function that gets the result with which to complete the task. An action used to unregister work when the operaiton completes. ================================================ FILE: ironclad-apps/tools/NuBuild/References/Microsoft.WindowsAzure.Common.NetFramework.xml ================================================ Microsoft.WindowsAzure.Common.NetFramework Credentials using a management certificate to authorize requests. Initializes a new instance of the CertificateCloudCredentials class. The Subscription ID. The management certificate. Attempt to create certificate credentials from a collection of settings. The settings to use. CertificateCloudCredentials is created, null otherwise. Initialize a ServiceClient instance to process credentials. Type of ServiceClient. The ServiceClient. This will add a certificate to the shared root WebRequestHandler in the ServiceClient's HttpClient handler pipeline. Apply the credentials to the HTTP request. The HTTP request. Cancellation token. Task that will complete when processing has completed. Gets subscription ID which uniquely identifies Windows Azure subscription. The subscription ID forms part of the URI for every call that you make to the Service Management API. The Windows Azure Service Management API use mutual authentication of management certificates over SSL to ensure that a request made to the service is secure. No anonymous requests are allowed. Cloud credentials provider for .NET Framework clients. Creates a new credentials instance if the appropriate settings for this provider are present and valid. Dictionary of configuration settings. Returns a new instance if the provider supports the provided settings. Computes SHA256 hash from key and data using HMACSHA256. Key to use as hash salt. Data to hash. Hash value. Initializes the settings. Checks whether the given exception represents an exception throws for a missing setting. Exception True for the missing setting exception. Gets a setting with the given name. Setting name. Setting value or null if such setting does not exist. Gets setting's value from the given provider. Provider name. Setting name Method to obtain given setting. Setting value, or null if not found. Gets a configuration setting from the service runtime. Setting name. Setting value or null if not found. Loads and returns the latest available version of the service runtime assembly. Loaded assembly, if any. Gets the setting defined in the Windows Azure configuration file. Setting name. Setting value. Gets an assembly path from the GAC given a partial name. An assembly partial name. May not be null. The assembly path if found; otherwise null; Registers cloud configuration providers with the common runtime that require the .NET framework. A strongly-typed resource class, for looking up localized strings, etc. Returns the cached ResourceManager instance used by this class. Overrides the current thread's CurrentUICulture property for all resource lookups using this strongly typed resource class. Looks up a localized string similar to {0} requires a {1} in its HTTP pipeline to work with client certificates.. ================================================ FILE: ironclad-apps/tools/NuBuild/References/Microsoft.WindowsAzure.Common.xml ================================================ Microsoft.WindowsAzure.Common Helper class used for deserialization of OLEDB Connection Strings. Defines an interface for setting parsers. Parses the setting. Setting to parse. Dictionary representation of the setting. Gets the setting name. Deserializes OLEDB Connection String. OLEDB Connection String. Dictionary representation of the Connection String. Gets the setting name. Class for token based credentials associated with a particular subscription. Base class for credentials associated with a particular subscription. The CloudCredentials class is the base class for providing credentials to access Windows Azure services. Initialize a ServiceClient instance to process credentials. Type of ServiceClient. The ServiceClient. Apply the credentials to the HTTP request. The HTTP request. Cancellation token. Task that will complete when processing has completed. Gets subscription ID which uniquely identifies Windows Azure subscription. The subscription ID forms part of the URI for every call that you make to the Service Management API. Gets an empty subscription Id. Class for token based credentials associated with a particular subscription. Initializes a new instance of the class with subscription ID. The Subscription ID. Valid JSON Web Token (JWT). Initializes a new instance of the class without subscription ID. Valid JSON Web Token (JWT). Attempt to create token credentials from a collection of settings. The settings to use. TokenCloudCredentials is created, null otherwise. Apply the credentials to the HTTP request. The HTTP request. Cancellation token. Task that will complete when processing has completed. Gets subscription ID which uniquely identifies Windows Azure subscription. The subscription ID forms part of the URI for every call that you make to the Service Management API. Gets or sets secure token used to authenticate against Windows Azure API. No anonymous requests are allowed. Representation of the error object from the server. Parsed error message. Parsed error code. Original error body Base class used to describe HTTP requests and responses associated with error conditions. Initializes a new instance of the CloudHttpErrorInfo class. Add the HTTP message headers to the error info. Collection of HTTP header. Gets or sets the contents of the HTTP message. Gets the collection of HTTP headers. Gets or sets the HTTP message version. Describes HTTP requests associated with error conditions. Initializes a new instance of the CloudHttpRequestErrorInfo class. Creates a new CloudHttpRequestErrorInfo from a HttpRequestMessage. The request message. A CloudHttpRequestErrorInfo instance. Creates a new CloudHttpRequestErrorInfo from a HttpRequestMessage. The request message. The request content, which may be passed separately if the request has already been disposed. A CloudHttpRequestErrorInfo instance. Gets or sets the HTTP method used by the HTTP request message. Gets or sets the Uri used for the HTTP request. Gets a set of properties for the HTTP request. Describes HTTP responses associated with error conditions. Initializes a new instance of the CloudHttpResponseErrorInfo class. Creates a new CloudHttpResponseErrorInfo from a HttpResponseMessage. The response message. A CloudHttpResponseErrorInfo instance. Creates a new CloudHttpResponseErrorInfo from a HttpResponseMessage. The response message. The response content, which may be passed separately if the response has already been disposed. A CloudHttpResponseErrorInfo instance. Gets or sets the status code of the HTTP response. Gets or sets the reason phrase which typically is sent by servers together with the status code. Provides cryptography functionality to libraries. Computes a Hash-based Message Authentication Code (HMAC) by using the SHA256 hash function. The key to use in the hash algorithm. The input to compute the hash code for. Returns the computed hash code. Extensions for manipulating HTTP requests and responses. Get the HTTP message content as a string. The HTTP content. The HTTP message content as a string. Get the content headers for an HTTP request. The request message. The content headers. Get the content headers for an HTTP response. The response message. The content headers. Get a standard string representation of an HTTP request. The request message. String representation of the request. Get a standard string representation of an HTTP request. The request message. String representation of the request. Append an HTTP request. The StringBuilder. The request message. Append an HTTP request. The StringBuilder. The request message. Append the components of an HTTP request. The StringBuilder. The request method. The request URI. The request HTTP version. The request headers. The request content headers. The request properties. The request content. Get a standard string representation of an HTTP response. The response message. String representation of the response. Get a standard string representation of an HTTP response. The response message. String representation of the response. Append an HTTP response. The StringBuilder. The response message. Append an HTTP response. The StringBuilder. The response message. Append the components of an HTTP response. The StringBuilder. The response status code. The response reason phrase. The response HTTP version. The response headers. The response content headers. The response content. Append HTTP headers. The StringBuilder. The HTTP headers. Helper class used for deserialization of JSON formatted Connection Strings. Deserializes JSON formatted Connection String. JSON formatted Connection String. Dictionary representation of the Connection String. Gets the setting name. Wrapper class for HttpMessageHandler that prevents InnerHandler from being disposed. Initializes a new instance of the class from HttpMessageHandler. InnerHandler to wrap. Overrides Dispose of the base class to prevent disposal of the InnerHandler. If set to true indicates the method is being called from Dispose(). Parser helper. Checks if content is possibly an XML. String to check. If set to true will validate entire XML for validity otherwise will just check the first character. True is content is possibly an XML otherwise false. Checks if content is possibly a JSON. String to check. If set to true will validate entire JSON for validity otherwise will just check the first character. True is content is possibly an JSON otherwise false. Returns first non whitespace character Text to search in Non whitespace or default char Static type conversion utility methods. Converts an array of 8-bit unsigned integers to its equivalent string representation that is encoded with base-64 digits. An array of 8-bit unsigned integers. The string representation, in base 64, of the contents of value. Decodes all the bytes in the specified byte array into a string. The byte array containing the sequence of bytes to decode. A string that contains the results of decoding the specified sequence of bytes. Converts the specified string, which encodes binary data as base-64 digits, to a UTF8-encoded string. The base 64-encoded string to convert. Returns a string. Uses Uri::TryCreate method to safely attempt to parse a string value and return its Uri representation. Supports relative Uris. The Uri string. Returns a new Uri instance or null. Convert a TimeSpan into an 8601 formatted string. The timespan to convert. The TimeSpan in 8601 format. Convert a string from ISO 8601 format to a TimeSpan instance. Value to parse. The resulting timespan. Concatenates parts of the Uri together ensuring that any duplicate '/' characters are removed. Parts of the Uri to be combined. Concatenated Uri A standard service response including an HTTP status code and request ID. Gets or sets the standard HTTP status code from the REST API operations for the Service Management API. Gets or sets the value that uniquely identifies a request made against the service. The status of the asynchronous request. The asynchronous request is in progress. The asynchronous request succeeded. The asynchronous request failed. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is i progress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request, and also includes error information regarding the failure. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request, and also includes error information regarding the failure. The HTTP status code for the asynchronous request. The request ID of the asynchronous request. This value is returned in the x-ms-request-id response header of the asynchronous request. The status of the asynchronous request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request, and also includes error information regarding the failure. Initializes a new instance of the ErrorDetails class. The management service error code returned if the asynchronous request failed. The management service error message returned if the asynchronous request failed. JSON formatter for PATCH syntax. Value to patch. Implicit operator that converts T to Patchable T. Object to convert. Converted object. Implicit operator that converts Patchable T to T. Object to convert. Converted object. Sets operation to SET and returns instance of the object. Value to patch. Instance of the object. Returns formatted PATCH script. Formatted PATCH script. Gets the patch value. Gets a value indicating whether the value is set. Parameter attribute used with OData filters. Initializes a new instance of the class. Property name to use in the filter. Initializes a new instance of the class. Property name to use in the filter. Format of the value. Property name to use in the filter. Format of the value. Handles OData filter generation. Generates an OData filter from a specified Linq expression. Filter type Entity to use for filter generation Expression visitor class that generates OData style $filter parameter. Visits binary expression !foo. Node to visit. Original node. Visits conditional expression foo == true ? bar : fee. Throws NotSupportedException. Node to visit. Throws NotSupportedException. Visits new object expression like new DateTime(). Node to visit. Original node. Visits constants like 'a' or 123. Node to visit. Original node. Visits object members like p.Foo or dateTime.Hour. Node to visit. Original node. Visits method calls like Contains, StartsWith, etc. Methods that are not supported will throw an exception. Node to visit. Original node. Appends 'eq true' to Boolean unary operators. Helper method to print constant. Object to print. Helper method to generate property name. Property to examine. Property name or value specified in the FilterParameterAttribute. Helper method to retrieve format from the FilterParameterAttribute. Property to examine. Format from FilterParameterAttribute or null. A cloud credentials provider. Creates a new credentials instance if the appropriate settings for this provider are present and valid. Dictionary of configuration settings. Returns a new instance if the provider supports the provided settings. Defines cryptographic methods. Computes SHA256 hash from key and data. Key to use as hash salt. Data to hash. Hash value. Provides tracing utilities that insight into all aspects of client operations via implementations of the ICloudTracingInterceptor interface. All tracing is global. The utilities in the internal Tracing class provide helpers for notifying the active trace listeners of changes. The collection of tracing interceptors to notify. A read-only, thread-safe collection of tracing interceptors. Since List is only thread-safe for reads (and adding/removing tracing interceptors isn't a very common operation), we simply replace the entire collection of interceptors so any enumeration of the list in progress on a different thread will not be affected by the change. Lock used to synchronize mutation of the tracing interceptors. Initializes a new instance of the CloudTracing class. Add a tracing interceptor to be notified of changes. The tracing interceptor. Remove a tracing interceptor from change notifications. The tracing interceptor. True if the tracing interceptor was found and removed; false otherwise. Gets or sets a value indicating whether tracing is enabled. Tracing can be disabled for performance. Gets a sequence of the tracing interceptors to notify of changes. Http retry handler. Initializes a new instance of the class. Sets default retry policty base on Exponential Backoff. Initializes a new instance of the class. Sets the default retry policty base on Exponential Backoff. Inner http handler. Initializes a new instance of the class. Retry policy to use. Inner http handler. Sends an HTTP request to the inner handler to send to the server as an asynchronous operation. Retries request if needed based on Retry Policy. The HTTP request message to send to the server. A cancellation token to cancel operation. Returns System.Threading.Tasks.Task<TResult>. The task object representing the asynchronous operation. Gets or sets retry policy. An instance of a callback delegate that will be invoked whenever a retry condition is encountered. Creates a new credentials instance of type T using the set of registered cloud credentials providers and provided settings. The requested minimum type of cloud credentials for successful credential use. Dictionary of configuration settings. Provides a value indicating whether to throw if the minimum requested credentials type cannot be found. Defaults to true. Returns a new instance of the first provider that supports the provided settings. The base ServiceClient class used to call REST services. Type of the ServiceClient. Gets the Platform's IHttpTransportHandlerProvider which gives the default HttpHandler for sending web requests. A value indicating whether or not the ServiceClient has already been disposed. Reference to the delegated handler of our handler (so we can maintain a proper reference count). Reference to our HTTP handler (which is the start of our HTTP pipeline). Initializes static members of the ServiceClient class. Initializes a new instance of the ServiceClient class. Initializes a new instance of the ServiceClient class. The http client. Initializes HttpClient. Http message handler to use with Http client. Create the HTTP client. The HTTP client. Dispose the ServiceClient. Clone the service client. The client to clone. Clone HttpClient properties. The client to clone. The client to copy into. Extend the ServiceClient with a new handler. The new client that will extend. The handler to extend with. The extended client. Gets the HttpClient used for making HTTP requests. Gets a reference to our HTTP handler (which is the start of our HTTP pipeline). Gets the UserAgent collection which can be augmented with custom user agent strings. Interface used to represent resource groupings of ServiceClient operations. Type of the ServiceClient. Gets a reference to the ServiceClient. The CloudClients class provides a common location for service client discovery. It can be accessed via CloudContext.Clients. The Microsoft.WindowsAzure namespace should be imported when used because CloudClients is intended to be the target of extension methods by each service client. All service client libraries should add CreateXYZClient() extension methods on static classes declared in the Microsoft.WindowsAzure namespace. This will allow any library loaded in a project to be easily discovered via CloudContext.Clients without developers having to figure out which namespaces to import, etc. You may also add extension methods that create This class is used as a static class (internal constructor) but not declared as such so it can be the target of extension methods. Initializes a new instance of the CloudClients class. Utilities for easily retrieving configuration settings across a variety of platform appropriate sources. Initializes static members of the class. Initializes platform-specific cloud configuration and credentials providers. Registers a cloud credentials provider with the configuration runtime. Instance of a cloud credentials provider. Creates a new credentials instance of type T using the set of registered cloud credentials providers. The requested minimum type of cloud credentials for successful credential use. Dictionary of configuration settings. Returns a new instance of the first provider that supports the provided settings. A platform specific configuration provider. There is no standard configuration support in the Portable Class Libraries BCL. Initializes a new instance of the CloudConfiguration class. Get the value of a configuration setting from a platform specific configuration source. The name of the setting. The value of the setting, or null if not found. Get connection info that can be used to instantiate type T by searching for configuration settings of the form Namespace.Type.format. If no connection info is found for the type, we will search for connection info for all of its base types. The type to obtain connection info for. Connection info used to instantiate the given type or null if no connection info is found. You can get insight into the connection info search by checking the tracing output. Get named connection info that can be used to instantiate a type by searching for configuration settings of the format Namespace.Type.Name.format. If no connection info is found for the type, we will search for connection info for all of its base types. The type to obtain connection info for. The name of the connection info. Connection info used to instantiate the given type or null if no connection info is found. You can get insight into the connection info search by checking the tracing output. Get connection info that can be used to instantiate a type by searching for configuration settings of the form Namespace.Type.format. If no connection info is found for the type, we will search for connection info for all of its base types. The type to obtain connection info for. Connection info used to instantiate the given type or null if no connection info is found. You can get insight into the connection info search by checking the tracing output. Get named connection info that can be used to instantiate a type by searching for configuration settings of the format Namespace.Type.Name.format. If no connection info is found for the type, we will search for connection info for all of its base types. The type to obtain connection info for. The name of the connection info. Connection info used to instantiate the given type or null if no connection string is found. You can get insight into the connection info search by checking the tracing output. Get connection info that can be used to instantiate a type by searching for configuration settings of the format Namespace.Type[.Name].format If no settings are found for the type, we will search for connection info for all of its base types. The type to obtain connection info for. Optional value for named settings. Name of the config setting item where the setting was found. Value of the config setting item where the setting was found. Connection info used to instantiate the given type or null if no connection info is found. You can get insight into the connection info search by checking the tracing output. Parse a connection string. The connection string. A dictionary of the setting names and values from the connection string. Parse a JSON settings file. The JSON settings. A dictionary of the setting names and values from the JSON settings. Gets a platform specific configuration provider. There is no standard configuration support in the Portable Class Libraries BCL. Gets the tracing utilities used to provide insight into all aspects of client operations. The CloudContext class is your primary entry point for getting started with Windows Azure client libraries. CloudContext.Clients contains helpful methods to create any of the clients currently referenced in your project (be sure to import the Microsoft.WindowsAzure namespace so you import its extension methods). CloudContext.Configuration allows you to easily retrieve configuration settings across a variety of platform appropriate sources. The CloudContext class is static to make it easier to use, but all other classes should be instances so they can be targeted by extension methods given the layered approach of our client libraries. Initializes static members of the class. Gets an object providing a common location for service client discovery. The Microsoft.WindowsAzure namespace should be imported when used because CloudClients is intended to be the target of extension methods by each service client library. Gets utilities for easily retrieving configuration settings across a variety of platform appropriate sources. Parse connection strings. The following simplified grammar was obtained from the specification "[MS-OLEDBSTR]: OLEDB Connection String Structure". Refer to the spec for full details. We support case-insensitive keys and multiple occurrences of the same key, but not multiple values for keys (i.e., the CompoundValue nonterminal in the spec's grammar). ws := [ \t]* semi := ; eq := = esc-eq := == dq := " sq := ' esc-dq := "" esc-sq := '' key-start: (==)|[^ \t;] key-body: (==)[^;]* key-end: (==)|[^ \t;] lit-start: [^ \t'";=] lit-body: [^;] lit-end: [^ \t;] sq-lit: ''|[^'] dq-lit: ""|[^"] ConnectionString := (ConnectionStringClause semi)* (ConnectionStringClause semi?)? ConnectionStringClause := KeyValuePair | ws KeyValuePair := ws Key ws eq ws Value ws Key := key-start (key-body* key-end)? Value := (lit-start (lit-body* lit-end)?)? | sq sq-lit* sq | dq dq-lit* dq Parses the connection string into a collection of key/value pairs. Connection string. Parsed connection string. Initializes a new instance of the class. Value to parse. Parses the string. A collection of key=value pairs. Generates an invalid connection string exception with the detailed error message. Position of the error. Short error formatting string. Optional arguments for the error string. Exception with the requested message. Skips whitespaces at the current position. Extracts key at the current position. Key. Extracts the string until the given quotation mark. Quotation mark terminating the string. String. Skips specified operator. Operator character. Extracts key's value. Key's value. State of the parser. Wrapper class that provides manual reference count functionality Type to wrap around. Must be disposable. Platform-specific interface enabling cloud configuration support. Registers platform-specific cloud configuration providers with the common runtime. Exception thrown for any invalid response. Initializes a new instance of the CloudException class. The exception message. Initializes a new instance of the CloudException class. The exception message. Inner exception. Create a CloudException from a failed response. The HTTP request. The HTTP request content. The HTTP response. The HTTP response content. Optional inner exception. A CloudException representing the failure. Create a CloudException from a failed response. This method is obsolete. Use Create without defaultTo parameter. The HTTP request. The HTTP request content. The HTTP response. The HTTP response content. The content type to default to if none of the types matches. Optional inner exception. A CloudException representing the failure. Create a CloudException from a failed response sending XML content. This method is obsolete. Use Create without defaultTo parameter. The HTTP request. The HTTP request content. The HTTP response. The HTTP response content. Optional inner exception. A CloudException representing the failure. Create a CloudException from a failed response sending JSON content. This method is obsolete. Use Create without defaultTo parameter. The HTTP request. The HTTP request content. The HTTP response. The HTTP response content. Optional inner exception. A CloudException representing the failure. Parse the response content as either an XML or JSON error message. The response content. An object containing the parsed error code and message. Parse the response content as an XML error message. The response content. An object containing the parsed error code and message. Parse the response content as an JSON error message. The response content. An object containing the parsed error code and message. Gets the error message returned from the server. This is included by default in the Message property. Gets the error code returned from the server. This is included by default in the Message property. Gets the request identifier. Gets the routing request identifier. Gets information about the associated HTTP request. Gets information about the associated HTTP response. Internal extensions. Create an ArgumentException for empty parameters. The parameter name. The ArgumentException. Get the assembly version of a service client. Type of the service client. The service client. The assembly version of the client. Get the HTTP pipeline formed from the ancestors of the starting handler. The starting handler. The HTTP pipeline. Get the HTTP pipeline for the given service client. Type of the service client. The service client. The client's HTTP pipeline. Add a handler to the end of the client's HTTP pipeline. Type of the service client. The service client. The handler to add. Sets retry policy for the client. Service client type. Service client. Retry policy to set. Helper extension methods used by tracing providers. Returns string representation of a HttpRequestMessage. Request to format. Formatted string. Returns string representation of a HttpResponseMessage. Response to format. Formatted string. Converts given dictionary into a log string. The dictionary key type The dictionary value type The dictionary collection object The log string The ICloudTracingInterceptor provides useful information about cloud operations. Interception is global and a tracing interceptor can be added via CloudContext.Configuration.Tracing.AddTracingInterceptor. Trace information. The information to trace. Probe configuration for the value of a setting. The configuration source. The name of the setting. The value of the setting in the source. Enter a method. Method invocation identifier. The instance with the method. Name of the method. Method parameters. Send an HTTP request. Method invocation identifier. The request about to be sent. Receive an HTTP response. Method invocation identifier. The response instance. Raise an error. Method invocation identifier. The error. Exit a method. Note: Exit will not be called in the event of an error. Method invocation identifier. Method return value. A strongly-typed resource class, for looking up localized strings, etc. Returns the cached ResourceManager instance used by this class. Overrides the current thread's CurrentUICulture property for all resource lookups using this strongly typed resource class. Looks up a localized string similar to Value cannot be empty. Parameter name: {0}. Looks up a localized string similar to The specified argument {0} cannot be greater than its ceiling value of {1}.. Looks up a localized string similar to The specified argument {0} cannot be initialized with a negative value.. Looks up a localized string similar to Failed to convert parameter {0} value '{1}' to type {2}.. Looks up a localized string similar to {3} Failed to create {0} from connection settings {1} = "{2}".. Looks up a localized string similar to No connection settings found for type {0}. Enable tracing for more information.. Looks up a localized string similar to No credentials of type '{0}' could be initialized from the provided settings.. Looks up a localized string similar to Parameter {0} is required.. Looks up a localized string similar to Default retry strategy for technology {0}, named '{1}', is not defined.. Looks up a localized string similar to Default retry strategy for technology {0} was not not defined, and there is no overall default strategy.. Looks up a localized string similar to Retry handler is not present in the HttpClient handler stack.. Looks up a localized string similar to The RetryManager is already set.. Looks up a localized string similar to The default RetryManager has not been set. Set it by invoking the RetryManager.SetDefault static method, or if you are using declarative configuration, you can invoke the RetryPolicyFactory.CreateDefault() method to automatically create the retry manager from the configuration file.. Looks up a localized string similar to Response status code indicates server error: {0} ({1}).. Looks up a localized string similar to The action has exceeded its defined retry limit.. Looks up a localized string similar to The retry strategy with name '{0}' cannot be found.. Looks up a localized string similar to The specified string argument {0} must not be empty.. Looks up a localized string similar to The specified argument '{0}' cannot return a null task when invoked.. Looks up a localized string similar to The specified argument '{0}' must return a scheduled task (also known as "hot" task) when invoked.. Handles the execution and retries of the user-initiated task. The result type of the user-initiated task. Provides a wrapper for a non-generic and calls into the pipeline to retry only the generic version of the . Wraps the non-generic into a generic . The task to wrap. A that wraps the non-generic . Default Http error detection strategy based on Http Status Code. Defines an interface that must be implemented by custom components responsible for detecting specific transient conditions. Determines whether the specified exception represents a transient failure that can be compensated by a retry. The exception object to be verified. true if the specified exception is considered as transient; otherwise, false. Returns true if status code in HttpRequestExceptionWithStatus exception is greater than or equal to 500 and not NotImplemented (501) or HttpVersionNotSupported (505). Exception to check against. True if exception is transient otherwise false. A retry strategy with backoff parameters for calculating the exponential delay between retries. Represents a retry strategy that determines the number of retry attempts and the interval between retries. Represents the default number of retry attempts. Represents the default amount of time used when calculating a random delta in the exponential delay between retries. Represents the default maximum amount of time used when calculating the exponential delay between retries. Represents the default minimum amount of time used when calculating the exponential delay between retries. Represents the default interval between retries. Represents the default time increment between retry attempts in the progressive delay policy. Represents the default flag indicating whether the first retry attempt will be made immediately, whereas subsequent retries will remain subject to the retry interval. Initializes a new instance of the class. The name of the retry strategy. true to immediately retry in the first attempt; otherwise, false. The subsequent retries will remain subject to the configured retry interval. Returns the corresponding ShouldRetry delegate. The ShouldRetry delegate. Returns a default policy that performs no retries, but invokes the action only once. Returns a default policy that implements a fixed retry interval configured with the and parameters. The default retry policy treats all caught exceptions as transient errors. Returns a default policy that implements a progressive retry interval configured with the , , and parameters. The default retry policy treats all caught exceptions as transient errors. Returns a default policy that implements a random exponential retry interval configured with the , , , and parameters. The default retry policy treats all caught exceptions as transient errors. Gets or sets a value indicating whether the first retry attempt will be made immediately, whereas subsequent retries will remain subject to the retry interval. Gets the name of the retry strategy. Initializes a new instance of the class. Initializes a new instance of the class with the specified retry settings. The maximum number of retry attempts. The minimum backoff time The maximum backoff time. The value that will be used to calculate a random delta in the exponential delay between retries. Initializes a new instance of the class with the specified name and retry settings. The name of the retry strategy. The maximum number of retry attempts. The minimum backoff time The maximum backoff time. The value that will be used to calculate a random delta in the exponential delay between retries. Initializes a new instance of the class with the specified name, retry settings, and fast retry option. The name of the retry strategy. The maximum number of retry attempts. The minimum backoff time The maximum backoff time. The value that will be used to calculate a random delta in the exponential delay between retries. true to immediately retry in the first attempt; otherwise, false. The subsequent retries will remain subject to the configured retry interval. Returns the corresponding ShouldRetry delegate. The ShouldRetry delegate. Represents a retry strategy with a specified number of retry attempts and a default, fixed time interval between retries. Initializes a new instance of the class. Initializes a new instance of the class with the specified number of retry attempts. The number of retry attempts. Initializes a new instance of the class with the specified number of retry attempts and time interval. The number of retry attempts. The time interval between retries. Initializes a new instance of the class with the specified number of retry attempts, time interval, and retry strategy. The retry strategy name. The number of retry attempts. The time interval between retries. Initializes a new instance of the class with the specified number of retry attempts, time interval, retry strategy, and fast start option. The retry strategy name. The number of retry attempts. The time interval between retries. true to immediately retry in the first attempt; otherwise, false. The subsequent retries will remain subject to the configured retry interval. Returns the corresponding ShouldRetry delegate. The ShouldRetry delegate. Implements the common guard methods. Checks a string argument to ensure that it isn't null or empty. The argument value to check. The name of the argument. The return value should be ignored. It is intended to be used only when validating arguments during instance creation (for example, when calling the base constructor). Checks an argument to ensure that it isn't null. The argument value to check. The name of the argument. The return value should be ignored. It is intended to be used only when validating arguments during instance creation (for example, when calling the base constructor). Checks an argument to ensure that its 32-bit signed value isn't negative. The value of the argument. The name of the argument for diagnostic purposes. Checks an argument to ensure that its 64-bit signed value isn't negative. The value of the argument. The name of the argument for diagnostic purposes. Checks an argument to ensure that its value doesn't exceed the specified ceiling baseline. The value of the argument. The ceiling value of the argument. The name of the argument for diagnostic purposes. Inherits HttpRequestException adding HttpStatusCode to the exception. Initializes a new instance of the class. Initializes a new instance of the class with a specific message that describes the current exception. A message that describes the current exception. Initializes a new instance of the class with a specific message that describes the current exception and an inner exception. A message that describes the current exception. The inner exception. Http status code. A retry strategy with a specified number of retry attempts and an incremental time interval between retries. Initializes a new instance of the class. Initializes a new instance of the class with the specified retry settings. The number of retry attempts. The initial interval that will apply for the first retry. The incremental time value that will be used to calculate the progressive delay between retries. Initializes a new instance of the class with the specified name and retry settings. The retry strategy name. The number of retry attempts. The initial interval that will apply for the first retry. The incremental time value that will be used to calculate the progressive delay between retries. Initializes a new instance of the class with the specified number of retry attempts, time interval, retry strategy, and fast start option. The retry strategy name. The number of retry attempts. The initial interval that will apply for the first retry. The incremental time value that will be used to calculate the progressive delay between retries. true to immediately retry in the first attempt; otherwise, false. The subsequent retries will remain subject to the configured retry interval. Returns the corresponding ShouldRetry delegate. The ShouldRetry delegate. Contains information that is required for the event. Initializes a new instance of the class. The current retry attempt count. The delay that indicates how long the current thread will be suspended before the next iteration is invoked. The exception that caused the retry conditions to occur. Gets the current retry count. Gets the delay that indicates how long the current thread will be suspended before the next iteration is invoked. Gets the exception that caused the retry conditions to occur. The special type of exception that provides managed exit from a retry loop. The user code can use this exception to notify the retry policy that no further retry attempts are required. Initializes a new instance of the class with a default error message. Initializes a new instance of the class with a specified error message. The message that describes the error. Initializes a new instance of the class with a reference to the inner exception that is the cause of this exception. The exception that is the cause of the current exception. Initializes a new instance of the class with a specified error message and inner exception. The message that describes the error. The exception that is the cause of the current exception. Provides the entry point to the retry functionality. Sets the specified retry manager as the default retry manager. The retry manager. true to throw an exception if the manager is already set; otherwise, false. Defaults to . The singleton is already set and is true. Initializes a new instance of the class. The complete set of retry strategies. Initializes a new instance of the class with the specified retry strategies and default retry strategy name. The complete set of retry strategies. The default retry strategy. Initializes a new instance of the class with the specified retry strategies and defaults. The complete set of retry strategies. The default retry strategy. The names of the default strategies for different technologies. Returns a retry policy with the specified error detection strategy and the default retry strategy defined in the configuration. The type that implements the interface that is responsible for detecting transient conditions. A new retry policy with the specified error detection strategy and the default retry strategy defined in the configuration. Returns a retry policy with the specified error detection strategy and retry strategy. The type that implements the interface that is responsible for detecting transient conditions. The retry strategy name, as defined in the configuration. A new retry policy with the specified error detection strategy and the default retry strategy defined in the configuration. Returns the default retry strategy defined in the configuration. The retry strategy that matches the default strategy. Returns the retry strategy that matches the specified name. The retry strategy name. The retry strategy that matches the specified name. Returns the retry strategy for the specified technology. The techonolgy to get the default retry strategy for. The retry strategy for the specified technology. Gets the default for the application. You can update the default retry manager by calling the method. Gets or sets the default retry strategy name. Provides the base implementation of the retry mechanism for unreliable actions and transient conditions. Initializes a new instance of the class with the specified number of retry attempts and parameters defining the progressive delay between retries. The that is responsible for detecting transient conditions. The strategy to use for this retry policy. Initializes a new instance of the class with the specified number of retry attempts and default fixed time interval between retries. The that is responsible for detecting transient conditions. The number of retry attempts. Initializes a new instance of the class with the specified number of retry attempts and fixed time interval between retries. The that is responsible for detecting transient conditions. The number of retry attempts. The interval between retries. Initializes a new instance of the class with the specified number of retry attempts and backoff parameters for calculating the exponential delay between retries. The that is responsible for detecting transient conditions. The number of retry attempts. The minimum backoff time. The maximum backoff time. The time value that will be used to calculate a random delta in the exponential delay between retries. Initializes a new instance of the class with the specified number of retry attempts and parameters defining the progressive delay between retries. The that is responsible for detecting transient conditions. The number of retry attempts. The initial interval that will apply for the first retry. The incremental time value that will be used to calculate the progressive delay between retries. Repetitively executes the specified action while it satisfies the current retry policy. A delegate that represents the executable action that doesn't return any results. Repetitively executes the specified action while it satisfies the current retry policy. The type of result expected from the executable action. A delegate that represents the executable action that returns the result of type . The result from the action. Repetitively executes the specified asynchronous task while it satisfies the current retry policy. A function that returns a started task (also known as "hot" task). A task that will run to completion if the original task completes successfully (either the first time or after retrying transient failures). If the task fails with a non-transient error or the retry limit is reached, the returned task will transition to a faulted state and the exception must be observed. Repetitively executes the specified asynchronous task while it satisfies the current retry policy. A function that returns a started task (also known as "hot" task). The token used to cancel the retry operation. This token does not cancel the execution of the asynchronous task. Returns a task that will run to completion if the original task completes successfully (either the first time or after retrying transient failures). If the task fails with a non-transient error or the retry limit is reached, the returned task will transition to a faulted state and the exception must be observed. Repeatedly executes the specified asynchronous task while it satisfies the current retry policy. A function that returns a started task (also known as "hot" task). Returns a task that will run to completion if the original task completes successfully (either the first time or after retrying transient failures). If the task fails with a non-transient error or the retry limit is reached, the returned task will transition to a faulted state and the exception must be observed. Repeatedly executes the specified asynchronous task while it satisfies the current retry policy. A function that returns a started task (also known as "hot" task). The token used to cancel the retry operation. This token does not cancel the execution of the asynchronous task. Returns a task that will run to completion if the original task completes successfully (either the first time or after retrying transient failures). If the task fails with a non-transient error or the retry limit is reached, the returned task will transition to a faulted state and the exception must be observed. Notifies the subscribers whenever a retry condition is encountered. The current retry attempt count. The exception that caused the retry conditions to occur. The delay that indicates how long the current thread will be suspended before the next iteration is invoked. Returns a default policy that performs no retries, but invokes the action only once. Returns a default policy that implements a fixed retry interval configured with the default retry strategy. The default retry policy treats all caught exceptions as transient errors. Returns a default policy that implements a progressive retry interval configured with the default retry strategy. The default retry policy treats all caught exceptions as transient errors. Returns a default policy that implements a random exponential retry interval configured with the default retry strategy. The default retry policy treats all caught exceptions as transient errors. An instance of a callback delegate that will be invoked whenever a retry condition is encountered. Gets the retry strategy. Gets the instance of the error detection strategy. Implements a strategy that ignores any transient errors. Always returns false. The exception. Always false. Implements a strategy that treats all exceptions as transient errors. Always returns true. The exception. Always true. Provides a generic version of the class. The type that implements the interface that is responsible for detecting transient conditions. Initializes a new instance of the class with the specified number of retry attempts and parameters defining the progressive delay between retries. The strategy to use for this retry policy. Initializes a new instance of the class with the specified number of retry attempts and the default fixed time interval between retries. The number of retry attempts. Initializes a new instance of the class with the specified number of retry attempts and a fixed time interval between retries. The number of retry attempts. The interval between retries. Initializes a new instance of the class with the specified number of retry attempts and backoff parameters for calculating the exponential delay between retries. The number of retry attempts. The minimum backoff time. The maximum backoff time. The time value that will be used to calculate a random delta in the exponential delay between retries. Initializes a new instance of the class with the specified number of retry attempts and parameters defining the progressive delay between retries. The number of retry attempts. The initial interval that will apply for the first retry. The incremental time value that will be used to calculate the progressive delay between retries. Defines a callback delegate that will be invoked whenever a retry condition is encountered. The current retry attempt count. The exception that caused the retry conditions to occur. The delay that indicates how long the current thread will be suspended before the next iteration is invoked. if a retry is allowed; otherwise, . ================================================ FILE: ironclad-apps/tools/NuBuild/References/Microsoft.WindowsAzure.Management.Compute.xml ================================================ Microsoft.WindowsAzure.Management.Compute The Service Management API provides programmatic access to much of the functionality available through the Management Portal. The Service Management API is a REST API. All API operations are performed over SSL, and are mutually authenticated using X.509 v3 certificates. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460799.aspx for more information) The Service Management API provides programmatic access to much of the functionality available through the Management Portal. The Service Management API is a REST API. All API operations are performed over SSL, and are mutually authenticated using X.509 v3 certificates. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460799.aspx for more information) The Get Operation Status operation returns the status of the specified operation. After calling an asynchronous operation, you can call Get Operation Status to determine whether the operation has succeeded, failed, or is still in progress. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460783.aspx for more information) The request ID for the request you wish to track. The request ID is returned in the x-ms-request-id response header for every request. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Gets the API version. Gets the URI used as the base for all cloud service requests. Gets subscription credentials which uniquely identify Microsoft Azure subscription. The subscription ID forms part of the URI for every service call. Gets or sets the initial timeout for Long Running Operations. Gets or sets the retry timeout for Long Running Operations. The Service Management API includes operations for managing the deployments in your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460812.aspx for more information) The Service Management API includes operations for managing the hosted services beneath your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460812.aspx for more information) The Compute Management API includes operations for managing the load balancers for your subscription. Operations for determining the version of the Azure Guest Operating System on which your service is running. (see http://msdn.microsoft.com/en-us/library/windowsazure/ff684169.aspx for more information) Operations for managing service certificates for your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee795178.aspx for more information) The Service Management API includes operations for managing the disks in your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157188.aspx for more information) The Service Management API includes operations for managing the virtual machine extensions in your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157206.aspx for more information) The Service Management API includes operations for managing the virtual machines in your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157206.aspx for more information) The Service Management API includes operations for managing the OS images in your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157175.aspx for more information) The Service Management API includes operations for managing the virtual machine templates in your subscription. Initializes a new instance of the ComputeManagementClient class. Initializes a new instance of the ComputeManagementClient class. Required. Gets subscription credentials which uniquely identify Microsoft Azure subscription. The subscription ID forms part of the URI for every service call. Required. Gets the URI used as the base for all cloud service requests. Initializes a new instance of the ComputeManagementClient class. Required. Gets subscription credentials which uniquely identify Microsoft Azure subscription. The subscription ID forms part of the URI for every service call. Initializes a new instance of the ComputeManagementClient class. The Http client Initializes a new instance of the ComputeManagementClient class. Required. Gets subscription credentials which uniquely identify Microsoft Azure subscription. The subscription ID forms part of the URI for every service call. Required. Gets the URI used as the base for all cloud service requests. The Http client Initializes a new instance of the ComputeManagementClient class. Required. Gets subscription credentials which uniquely identify Microsoft Azure subscription. The subscription ID forms part of the URI for every service call. The Http client Clones properties from current instance to another ComputeManagementClient instance Instance of ComputeManagementClient to clone to The Get Operation Status operation returns the status of the specified operation. After calling an asynchronous operation, you can call Get Operation Status to determine whether the operation has succeeded, failed, or is still in progress. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460783.aspx for more information) Required. The request ID for the request you wish to track. The request ID is returned in the x-ms-request-id response header for every request. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Parse enum values for type CertificateFormat. The value to parse. The enum value. Convert an enum of type CertificateFormat to a string. The value to convert to a string. The enum value as a string. Parse enum values for type LoadBalancerProbeTransportProtocol. The value to parse. The enum value. Convert an enum of type LoadBalancerProbeTransportProtocol to a string. The value to convert to a string. The enum value as a string. Gets the API version. Gets the URI used as the base for all cloud service requests. Gets subscription credentials which uniquely identify Microsoft Azure subscription. The subscription ID forms part of the URI for every service call. Gets or sets the initial timeout for Long Running Operations. Gets or sets the retry timeout for Long Running Operations. The Service Management API includes operations for managing the deployments in your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460812.aspx for more information) The Service Management API includes operations for managing the hosted services beneath your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460812.aspx for more information) The Compute Management API includes operations for managing the load balancers for your subscription. Operations for determining the version of the Azure Guest Operating System on which your service is running. (see http://msdn.microsoft.com/en-us/library/windowsazure/ff684169.aspx for more information) Operations for managing service certificates for your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee795178.aspx for more information) The Service Management API includes operations for managing the disks in your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157188.aspx for more information) The Service Management API includes operations for managing the virtual machine extensions in your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157206.aspx for more information) The Service Management API includes operations for managing the virtual machines in your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157206.aspx for more information) The Service Management API includes operations for managing the OS images in your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157175.aspx for more information) The Service Management API includes operations for managing the virtual machine templates in your subscription. The Service Management API provides programmatic access to much of the functionality available through the Management Portal. The Service Management API is a REST API. All API operations are performed over SSL, and are mutually authenticated using X.509 v3 certificates. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460799.aspx for more information) The Get Operation Status operation returns the status of the specified operation. After calling an asynchronous operation, you can call Get Operation Status to determine whether the operation has succeeded, failed, or is still in progress. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460783.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IComputeManagementClient. Required. The request ID for the request you wish to track. The request ID is returned in the x-ms-request-id response header for every request. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Get Operation Status operation returns the status of the specified operation. After calling an asynchronous operation, you can call Get Operation Status to determine whether the operation has succeeded, failed, or is still in progress. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460783.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IComputeManagementClient. Required. The request ID for the request you wish to track. The request ID is returned in the x-ms-request-id response header for every request. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Service Management API includes operations for managing the deployments in your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460812.aspx for more information) The Service Management API includes operations for managing the deployments in your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460812.aspx for more information) The Begin Changing Deployment Configuration By Name operation initiates a change to the deployment configuration. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460809.aspx for more information) The cloud service to change deployment configuration for. The deployment to change configuration for. Parameters supplied to the Begin Changing Configuration Deployment By Name operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Changing Deployment Configuration By Slot operation initiates a change to the deployment configuration. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460809.aspx for more information) The cloud service to change deployment configuration for. The slot to change deployment configuration for. Parameters supplied to the Begin Changing Configuration Deployment By Slot operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Creating Deployment operation uploads a new service package and creates a new deployment in the staging or production environments. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460813.aspx for more information) The cloud service to create a deployment for. The slot to create a deployment for. Parameters supplied to the Begin Creating Deployment operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Deleting Deployment By Name operation deletes the specified deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460815.aspx for more information) The name of the cloud service. The name of your deployment. Specifies that the source blob for the disk should also be deleted from storage. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Deleting Deployment By Slot operation deletes the specified deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460815.aspx for more information) The name of the cloud service. The deployment slot. Cancellation token. A standard service response including an HTTP status code and request ID. The Delete Role Instances operation deletes a role instance from a deployment in a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469418.aspx for more information) The name of the cloud service. The name of the deployment slot. The parameters to delete the role. Cancellation token. A standard service response including an HTTP status code and request ID. The Delete Role Instances operation deletes a role instance from a deployment in a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469418.aspx for more information) The name of the cloud service. The name of the deployment. The parameters to delete the role. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Rebooting Role Instance By Deployment Name operation requests a reboot of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441298.aspx for more information) The name of the cloud service. The name of your deployment. The name of your role instance. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Rebooting Role Instance By Deployment Slot operation requests a reboot of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441298.aspx for more information) The name of the cloud service. The deployment slot. The name of your role instance. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Reimaging Role Instance By Deployment Name operation requests a reimage of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441292.aspx for more information) The name of the cloud service. The name of your deployment. The name of your role instance. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Reimaging Role Instance By Deployment Slot operation requests a reimage of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441292.aspx for more information) The name of the cloud service. The deployment slot. The name of your role instance. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Swapping Deployment operation initiates a virtual IP address swap between the staging and production deployment environments for a service. If the service is currently running in the staging environment, it will be swapped to the production environment. If it is running in the production environment, it will be swapped to staging. For more information on this type of upgrade, see Performing Virtual IP Swap Upgrades at http://msdn.microsoft.com/en-us/library/windowsazure/ee517253.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460814.aspx for more information) The cloud service to swap deployments for. Parameters supplied to the Begin Swapping Deployment operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Updating Deployment Status By Deployment Name operation initiates a change in the running status of a deployment. The status of a deployment can be running or suspended. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460808.aspx for more information) The cloud service to swap deployments for. The name of your deployment. Parameters supplied to the Begin Updating Deployment Status By Deployment Name operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Updating Deployment Status By Deployment Slot operation initiates a change in the running status of a deployment. The status of a deployment can be running or suspended. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460808.aspx for more information) The cloud service to swap deployments for. The deployment slot. Parameters supplied to the Begin Updating Deployment Status By Deployment Slot operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Upgrading Deployment By Name operation initiates an update of role instances in a deployment using the package and configuration that you specify. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the request has been processed, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. To perform an automatic update of a deployment, call Upgrade Deployment or Change Deployment Configuration with the Mode element set to automatic. The update proceeds from that point without a need for further input. You can call Get Operation Status to determine when the update is complete. To perform a manual update, first call Upgrade Deployment with the Mode element set to manual. Next, call Walk Upgrade Domain to update each domain within the deployment. You should make sure that the operation is complete by calling Get Operation Status before updating the next domain. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. By default, a cloud service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To determine the update domain in which a particular instance is running in Windows Azure, use the UpdateDomain property of the RoleInstance class. See the Azure Managed Library Reference at http://msdn.microsoft.com/en-us/library/windowsazure/dd179380.aspx for more information. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460793.aspx for more information) The cloud service to upgrade. The deployment to upgrade. Parameters supplied to the Begin Upgrading Deployment By Name operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Upgrading Deployment By Slot operation initiates an update of role instances in a deployment using the package and configuration that you specify. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx.This operation is an asynchronous operation. To determine whether the request has been processed, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. To perform an automatic update of a deployment, call Upgrade Deployment or Change Deployment Configuration with the Mode element set to automatic. The update proceeds from that point without a need for further input. You can call Get Operation Status to determine when the update is complete. To perform a manual update, first call Upgrade Deployment with the Mode element set to manual. Next, call Walk Upgrade Domain to update each domain within the deployment. You should make sure that the operation is complete by calling Get Operation Status before updating the next domain. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. By default, a cloud service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To determine the update domain in which a particular instance is running in Windows Azure, use the UpdateDomain property of the RoleInstance class. See the Azure Managed Library Reference at http://msdn.microsoft.com/en-us/library/windowsazure/dd179380.aspx for more information. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460793.aspx for more information) The cloud service to upgrade. The slot to upgrade. Parameters supplied to the Begin Upgrading Deployment By Slot operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Walking Upgrade Domain By Deployment Name operation specifies an update domain in which a role instance must be updated. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. Prior to calling the Walk Upgrade Domain operation you must have called Upgrade Deployment, Change Deployment Configuration, or Rollback Update Or Upgrade. By default, a service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To perform a manual update of your deployment, proceed in this order: Call Upgrade Deployment with the Mode element set to manual. Call Walk Upgrade Domain to update each domain within the deployment. Update domains must be updated in order. For example, begin with domain 0, proceed to domain 1, and so on. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. While an update is in progress, call Get Deployment to determine its status. If the update is in progress, Get Deployment returns an UpgradeStatus element that contains information about the update. If the update is complete, or if no update is in progress, then the UpgradeStatus element is null. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460800.aspx for more information) The name of the cloud service. The name of your deployment. Parameters supplied to the Begin Walking Upgrade Domain By Deployment Name operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Walking Upgrade Domain By Deployment Slot operation specifies an update domain in which a role instance must be updated. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. Prior to calling the Walk Upgrade Domain operation you must have called Upgrade Deployment, Change Deployment Configuration, or Rollback Update Or Upgrade. By default, a service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To perform a manual update of your deployment, proceed in this order: Call Upgrade Deployment with the Mode element set to manual. Call Walk Upgrade Domain to update each domain within the deployment. Update domains must be updated in order. For example, begin with domain 0, proceed to domain 1, and so on. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. While an update is in progress, call Get Deployment to determine its status. If the update is in progress, Get Deployment returns an UpgradeStatus element that contains information about the update. If the update is complete, or if no update is in progress, then the UpgradeStatus element is null. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460800.aspx for more information) The name of the cloud service. The deployment slot. Parameters supplied to the Begin Walking Upgrade Domain By Deployment Slot operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Change Deployment Configuration By Name operation initiates a change to the deployment configuration. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460809.aspx for more information) The cloud service to change deployment configuration for. The deployment to change configuration for. Parameters supplied to the Change ConfigurationDeployment By Name operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Change Deployment Configuration By Slot operation initiates a change to the deployment configuration. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460809.aspx for more information) The cloud service to change deployment configuration for. The slot to change deployment configuration for. Parameters supplied to the Change Configuration Deployment By Slot operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Create Deployment operation uploads a new service package and creates a new deployment in the staging or production environments. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460813.aspx for more information) The cloud service to create a deployment for. The slot to create a deployment for. Parameters supplied to the Create Deployment operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Deployment By Name operation deletes the specified deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460815.aspx for more information) The name of the cloud service. The name of your deployment. Specifies that the source blob for the disk should also be deleted from storage. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Deployment By Slot operation deletes the specified deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460815.aspx for more information) The name of the cloud service. The deployment slot. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Role Instances operation deletes a role instance from a deployment in a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469418.aspx for more information) The name of the cloud service. The name of the deployment. The parameters to delete the role. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Role Instances operation deletes the role instances from a deployment in a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469418.aspx for more information) The name of the cloud service. The name of the deployment slot. The parameters to delete the role. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Get Deployment By Name operation returns configuration information, status, and system properties for a deployment. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460804.aspx for more information) The name of the cloud service. The name of the deployment. Cancellation token. A deployment that exists in the cloud service. The Get Deployment By Slot operation returns configuration information, status, and system properties for a deployment. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460804.aspx for more information) The name of the cloud service. The deployment slot. Cancellation token. A deployment that exists in the cloud service. The Get Package By Name operation retrieves a cloud service package for a deployment and stores the package files in Azure Blob storage. The following package files are placed in storage: the cloud service configuration file (.cscfg), providing configuration settings for the cloud service and individual roles, including the number of role instances; and the service package (.cspkg), containing the application code and the service definition file. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj154121.aspx for more information) The name of the cloud service. The name of your deployment. Parameters supplied to the Get Package By Name operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Get Package By Slot operation retrieves a cloud service package for a deployment and stores the package files in Azure Blob storage. The following package files are placed in storage: the cloud service configuration file (.cscfg), providing configuration settings for the cloud service and individual roles, including the number of role instances; and the service package (.cspkg), containing the application code and the service definition file. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj154121.aspx for more information) The name of the cloud service. The deployment slot. Parameters supplied to the Get Package By Slot operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Reboot Role Instance By Deployment Name operation requests a reboot of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441298.aspx for more information) The name of the cloud service. The name of your deployment. The name of your role instance. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Reboot Role Instance By Deployment Slot operation requests a reboot of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441298.aspx for more information) The name of the cloud service. The deployment slot. The name of your role instance. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Reimage Role Instance By Deployment Name operation requests a reimage of a role instance that is running in a deployment.This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441292.aspx for more information) The name of the cloud service. The name of your deployment. The name of your role instance. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Reimage Role Instance By Deployment Slot operation requests a reimage of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441292.aspx for more information) The name of the cloud service. The deployment slot. The name of your role instance. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Rollback Update Or Upgrade By Deployment Name operation cancels an in-progress configuration update and returns the deployment to its state before the update was started. This operation can only be called when an update is in progress on the deployment. The deployment status can be detected by calling the Get Deployment operation or Get Hosted Service Properties operation and inspecting the RollbackAllowed element. If the value returned is true a rollback can be performed. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh403977.aspx for more information) The cloud service to swap deployments for. The name of your deployment. Parameters supplied to the Rollback Update Or Upgrade By Deployment Name operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Rollback Update Or Upgrade By Deployment Slot operation cancels an in-progress configuration update and returns the deployment to its state before the update was started. This operation can only be called when an update is in progress on the deployment. The deployment status can be detected by calling the Get Deployment operation or Get Hosted Service Properties operation and inspecting the RollbackAllowed element. If the value returned is true a rollback can be performed. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh403977.aspx for more information) The cloud service to swap deployments for. The deployment slot. Parameters supplied to the Rollback Update Or Upgrade By Deployment Slot operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Swap Deployment operation initiates a virtual IP address swap between the staging and production deployment environments for a service. If the service is currently running in the staging environment, it will be swapped to the production environment. If it is running in the production environment, it will be swapped to staging. For more information on this type of upgrade, see Performing Virtual IP Swap Upgrades at http://msdn.microsoft.com/en-us/library/windowsazure/ee517253.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460814.aspx for more information) The cloud service to swap deployments for. Parameters supplied to the Swap Deployment operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Update Deployment Status By Deployment Name operation initiates a change in the running status of a deployment. The status of a deployment can be running or suspended. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460808.aspx for more information) The cloud service to swap deployments for. The name of your deployment. Parameters supplied to the Update Deployment Status By Deployment Name operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Update Deployment Status By Deployment Slot operation initiates a change in the running status of a deployment. The status of a deployment can be running or suspended. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460808.aspx for more information) The cloud service to swap deployments for. The deployment slot. Parameters supplied to the Update Deployment Status By Deployment Slot operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Upgrade Deployment By Name operation initiates an update of role instances in a deployment using the package and configuration that you specify. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the request has been processed, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. To perform an automatic update of a deployment, call Upgrade Deployment or Change Deployment Configuration with the Mode element set to automatic. The update proceeds from that point without a need for further input. You can call Get Operation Status to determine when the update is complete. To perform a manual update, first call Upgrade Deployment with the Mode element set to manual. Next, call Walk Upgrade Domain to update each domain within the deployment. You should make sure that the operation is complete by calling Get Operation Status before updating the next domain. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. By default, a cloud service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To determine the update domain in which a particular instance is running in Windows Azure, use the UpdateDomain property of the RoleInstance class. See the Azure Managed Library Reference at http://msdn.microsoft.com/en-us/library/windowsazure/dd179380.aspx for more information. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460793.aspx for more information) The cloud service to upgrade. The deployment to upgrade. Parameters supplied to the Upgrade Deployment By Name operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Upgrade Deployment By Slot operation initiates an update of role instances in a deployment using the package and configuration that you specify. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the request has been processed, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. To perform an automatic update of a deployment, call Upgrade Deployment or Change Deployment Configuration with the Mode element set to automatic. The update proceeds from that point without a need for further input. You can call Get Operation Status to determine when the update is complete. To perform a manual update, first call Upgrade Deployment with the Mode element set to manual. Next, call Walk Upgrade Domain to update each domain within the deployment. You should make sure that the operation is complete by calling Get Operation Status before updating the next domain. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. By default, a cloud service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To determine the update domain in which a particular instance is running in Windows Azure, use the UpdateDomain property of the RoleInstance class. See the Azure Managed Library Reference at http://msdn.microsoft.com/en-us/library/windowsazure/dd179380.aspx for more information. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460793.aspx for more information) The cloud service to upgrade. The slot to upgrade. Parameters supplied to the Upgrade Deployment By Slot operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Walk Upgrade Domain By Deployment Name operation specifies an update domain in which a role instance must be updated. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. Prior to calling the Walk Upgrade Domain operation you must have called Upgrade Deployment, Change Deployment Configuration, or Rollback Update Or Upgrade. By default, a service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To perform a manual update of your deployment, proceed in this order: Call Upgrade Deployment with the Mode element set to manual. Call Walk Upgrade Domain to update each domain within the deployment. Update domains must be updated in order. For example, begin with domain 0, proceed to domain 1, and so on. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. While an update is in progress, call Get Deployment to determine its status. If the update is in progress, Get Deployment returns an UpgradeStatus element that contains information about the update. If the update is complete, or if no update is in progress, then the UpgradeStatus element is null. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460800.aspx for more information) The name of the cloud service. The name of your deployment. Parameters supplied to the Walk Upgrade Domain By Deployment Name operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Walk Upgrade Domain By Deployment Slot operation specifies an update domain in which a role instance must be updated. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. Prior to calling the Walk Upgrade Domain operation you must have called Upgrade Deployment, Change Deployment Configuration, or Rollback Update Or Upgrade. By default, a service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To perform a manual update of your deployment, proceed in this order: Call Upgrade Deployment with the Mode element set to manual. Call Walk Upgrade Domain to update each domain within the deployment. Update domains must be updated in order. For example, begin with domain 0, proceed to domain 1, and so on. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. While an update is in progress, call Get Deployment to determine its status. If the update is in progress, Get Deployment returns an UpgradeStatus element that contains information about the update. If the update is complete, or if no update is in progress, then the UpgradeStatus element is null. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460800.aspx for more information) The name of the cloud service. The deployment slot. Parameters supplied to the Walk Upgrade Domain By Deployment Slot operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Initializes a new instance of the DeploymentOperations class. Reference to the service client. The Begin Changing Deployment Configuration By Name operation initiates a change to the deployment configuration. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460809.aspx for more information) Required. The cloud service to change deployment configuration for. Required. The deployment to change configuration for. Required. Parameters supplied to the Begin Changing Configuration Deployment By Name operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Changing Deployment Configuration By Slot operation initiates a change to the deployment configuration. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460809.aspx for more information) Required. The cloud service to change deployment configuration for. Required. The slot to change deployment configuration for. Required. Parameters supplied to the Begin Changing Configuration Deployment By Slot operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Creating Deployment operation uploads a new service package and creates a new deployment in the staging or production environments. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460813.aspx for more information) Required. The cloud service to create a deployment for. Required. The slot to create a deployment for. Required. Parameters supplied to the Begin Creating Deployment operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Deleting Deployment By Name operation deletes the specified deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460815.aspx for more information) Required. The name of the cloud service. Required. The name of your deployment. Required. Specifies that the source blob for the disk should also be deleted from storage. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Deleting Deployment By Slot operation deletes the specified deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460815.aspx for more information) Required. The name of the cloud service. Required. The deployment slot. Cancellation token. A standard service response including an HTTP status code and request ID. The Delete Role Instances operation deletes a role instance from a deployment in a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469418.aspx for more information) Required. The name of the cloud service. Required. The name of the deployment slot. Required. The parameters to delete the role. Cancellation token. A standard service response including an HTTP status code and request ID. The Delete Role Instances operation deletes a role instance from a deployment in a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469418.aspx for more information) Required. The name of the cloud service. Required. The name of the deployment. Required. The parameters to delete the role. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Rebooting Role Instance By Deployment Name operation requests a reboot of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441298.aspx for more information) Required. The name of the cloud service. Required. The name of your deployment. Required. The name of your role instance. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Rebooting Role Instance By Deployment Slot operation requests a reboot of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441298.aspx for more information) Required. The name of the cloud service. Required. The deployment slot. Required. The name of your role instance. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Reimaging Role Instance By Deployment Name operation requests a reimage of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441292.aspx for more information) Required. The name of the cloud service. Required. The name of your deployment. Required. The name of your role instance. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Reimaging Role Instance By Deployment Slot operation requests a reimage of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441292.aspx for more information) Required. The name of the cloud service. Required. The deployment slot. Required. The name of your role instance. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Swapping Deployment operation initiates a virtual IP address swap between the staging and production deployment environments for a service. If the service is currently running in the staging environment, it will be swapped to the production environment. If it is running in the production environment, it will be swapped to staging. For more information on this type of upgrade, see Performing Virtual IP Swap Upgrades at http://msdn.microsoft.com/en-us/library/windowsazure/ee517253.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460814.aspx for more information) Required. The cloud service to swap deployments for. Required. Parameters supplied to the Begin Swapping Deployment operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Updating Deployment Status By Deployment Name operation initiates a change in the running status of a deployment. The status of a deployment can be running or suspended. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460808.aspx for more information) Required. The cloud service to swap deployments for. Required. The name of your deployment. Required. Parameters supplied to the Begin Updating Deployment Status By Deployment Name operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Updating Deployment Status By Deployment Slot operation initiates a change in the running status of a deployment. The status of a deployment can be running or suspended. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460808.aspx for more information) Required. The cloud service to swap deployments for. Required. The deployment slot. Required. Parameters supplied to the Begin Updating Deployment Status By Deployment Slot operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Upgrading Deployment By Name operation initiates an update of role instances in a deployment using the package and configuration that you specify. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the request has been processed, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. To perform an automatic update of a deployment, call Upgrade Deployment or Change Deployment Configuration with the Mode element set to automatic. The update proceeds from that point without a need for further input. You can call Get Operation Status to determine when the update is complete. To perform a manual update, first call Upgrade Deployment with the Mode element set to manual. Next, call Walk Upgrade Domain to update each domain within the deployment. You should make sure that the operation is complete by calling Get Operation Status before updating the next domain. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. By default, a cloud service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To determine the update domain in which a particular instance is running in Windows Azure, use the UpdateDomain property of the RoleInstance class. See the Azure Managed Library Reference at http://msdn.microsoft.com/en-us/library/windowsazure/dd179380.aspx for more information. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460793.aspx for more information) Required. The cloud service to upgrade. Required. The deployment to upgrade. Required. Parameters supplied to the Begin Upgrading Deployment By Name operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Upgrading Deployment By Slot operation initiates an update of role instances in a deployment using the package and configuration that you specify. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx.This operation is an asynchronous operation. To determine whether the request has been processed, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. To perform an automatic update of a deployment, call Upgrade Deployment or Change Deployment Configuration with the Mode element set to automatic. The update proceeds from that point without a need for further input. You can call Get Operation Status to determine when the update is complete. To perform a manual update, first call Upgrade Deployment with the Mode element set to manual. Next, call Walk Upgrade Domain to update each domain within the deployment. You should make sure that the operation is complete by calling Get Operation Status before updating the next domain. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. By default, a cloud service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To determine the update domain in which a particular instance is running in Windows Azure, use the UpdateDomain property of the RoleInstance class. See the Azure Managed Library Reference at http://msdn.microsoft.com/en-us/library/windowsazure/dd179380.aspx for more information. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460793.aspx for more information) Required. The cloud service to upgrade. Required. The slot to upgrade. Required. Parameters supplied to the Begin Upgrading Deployment By Slot operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Walking Upgrade Domain By Deployment Name operation specifies an update domain in which a role instance must be updated. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. Prior to calling the Walk Upgrade Domain operation you must have called Upgrade Deployment, Change Deployment Configuration, or Rollback Update Or Upgrade. By default, a service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To perform a manual update of your deployment, proceed in this order: Call Upgrade Deployment with the Mode element set to manual. Call Walk Upgrade Domain to update each domain within the deployment. Update domains must be updated in order. For example, begin with domain 0, proceed to domain 1, and so on. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. While an update is in progress, call Get Deployment to determine its status. If the update is in progress, Get Deployment returns an UpgradeStatus element that contains information about the update. If the update is complete, or if no update is in progress, then the UpgradeStatus element is null. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460800.aspx for more information) Required. The name of the cloud service. Required. The name of your deployment. Required. Parameters supplied to the Begin Walking Upgrade Domain By Deployment Name operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Walking Upgrade Domain By Deployment Slot operation specifies an update domain in which a role instance must be updated. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. Prior to calling the Walk Upgrade Domain operation you must have called Upgrade Deployment, Change Deployment Configuration, or Rollback Update Or Upgrade. By default, a service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To perform a manual update of your deployment, proceed in this order: Call Upgrade Deployment with the Mode element set to manual. Call Walk Upgrade Domain to update each domain within the deployment. Update domains must be updated in order. For example, begin with domain 0, proceed to domain 1, and so on. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. While an update is in progress, call Get Deployment to determine its status. If the update is in progress, Get Deployment returns an UpgradeStatus element that contains information about the update. If the update is complete, or if no update is in progress, then the UpgradeStatus element is null. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460800.aspx for more information) Required. The name of the cloud service. Required. The deployment slot. Required. Parameters supplied to the Begin Walking Upgrade Domain By Deployment Slot operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Change Deployment Configuration By Name operation initiates a change to the deployment configuration. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460809.aspx for more information) Required. The cloud service to change deployment configuration for. Required. The deployment to change configuration for. Required. Parameters supplied to the Change ConfigurationDeployment By Name operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Change Deployment Configuration By Slot operation initiates a change to the deployment configuration. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460809.aspx for more information) Required. The cloud service to change deployment configuration for. Required. The slot to change deployment configuration for. Required. Parameters supplied to the Change Configuration Deployment By Slot operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Create Deployment operation uploads a new service package and creates a new deployment in the staging or production environments. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460813.aspx for more information) Required. The cloud service to create a deployment for. Required. The slot to create a deployment for. Required. Parameters supplied to the Create Deployment operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Deployment By Name operation deletes the specified deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460815.aspx for more information) Required. The name of the cloud service. Required. The name of your deployment. Required. Specifies that the source blob for the disk should also be deleted from storage. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Deployment By Slot operation deletes the specified deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460815.aspx for more information) Required. The name of the cloud service. Required. The deployment slot. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Role Instances operation deletes a role instance from a deployment in a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469418.aspx for more information) Required. The name of the cloud service. Required. The name of the deployment. Required. The parameters to delete the role. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Role Instances operation deletes the role instances from a deployment in a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469418.aspx for more information) Required. The name of the cloud service. Required. The name of the deployment slot. Required. The parameters to delete the role. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Get Deployment By Name operation returns configuration information, status, and system properties for a deployment. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460804.aspx for more information) Required. The name of the cloud service. Required. The name of the deployment. Cancellation token. A deployment that exists in the cloud service. The Get Deployment By Slot operation returns configuration information, status, and system properties for a deployment. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460804.aspx for more information) Required. The name of the cloud service. Required. The deployment slot. Cancellation token. A deployment that exists in the cloud service. The Get Package By Name operation retrieves a cloud service package for a deployment and stores the package files in Azure Blob storage. The following package files are placed in storage: the cloud service configuration file (.cscfg), providing configuration settings for the cloud service and individual roles, including the number of role instances; and the service package (.cspkg), containing the application code and the service definition file. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj154121.aspx for more information) Required. The name of the cloud service. Required. The name of your deployment. Required. Parameters supplied to the Get Package By Name operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Get Package By Slot operation retrieves a cloud service package for a deployment and stores the package files in Azure Blob storage. The following package files are placed in storage: the cloud service configuration file (.cscfg), providing configuration settings for the cloud service and individual roles, including the number of role instances; and the service package (.cspkg), containing the application code and the service definition file. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj154121.aspx for more information) Required. The name of the cloud service. Required. The deployment slot. Required. Parameters supplied to the Get Package By Slot operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Reboot Role Instance By Deployment Name operation requests a reboot of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441298.aspx for more information) Required. The name of the cloud service. Required. The name of your deployment. Required. The name of your role instance. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Reboot Role Instance By Deployment Slot operation requests a reboot of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441298.aspx for more information) Required. The name of the cloud service. Required. The deployment slot. Required. The name of your role instance. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Reimage Role Instance By Deployment Name operation requests a reimage of a role instance that is running in a deployment.This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441292.aspx for more information) Required. The name of the cloud service. Required. The name of your deployment. Required. The name of your role instance. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Reimage Role Instance By Deployment Slot operation requests a reimage of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441292.aspx for more information) Required. The name of the cloud service. Required. The deployment slot. Required. The name of your role instance. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Rollback Update Or Upgrade By Deployment Name operation cancels an in-progress configuration update and returns the deployment to its state before the update was started. This operation can only be called when an update is in progress on the deployment. The deployment status can be detected by calling the Get Deployment operation or Get Hosted Service Properties operation and inspecting the RollbackAllowed element. If the value returned is true a rollback can be performed. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh403977.aspx for more information) Required. The cloud service to swap deployments for. Required. The name of your deployment. Required. Parameters supplied to the Rollback Update Or Upgrade By Deployment Name operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Rollback Update Or Upgrade By Deployment Slot operation cancels an in-progress configuration update and returns the deployment to its state before the update was started. This operation can only be called when an update is in progress on the deployment. The deployment status can be detected by calling the Get Deployment operation or Get Hosted Service Properties operation and inspecting the RollbackAllowed element. If the value returned is true a rollback can be performed. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh403977.aspx for more information) Required. The cloud service to swap deployments for. Required. The deployment slot. Required. Parameters supplied to the Rollback Update Or Upgrade By Deployment Slot operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Swap Deployment operation initiates a virtual IP address swap between the staging and production deployment environments for a service. If the service is currently running in the staging environment, it will be swapped to the production environment. If it is running in the production environment, it will be swapped to staging. For more information on this type of upgrade, see Performing Virtual IP Swap Upgrades at http://msdn.microsoft.com/en-us/library/windowsazure/ee517253.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460814.aspx for more information) Required. The cloud service to swap deployments for. Required. Parameters supplied to the Swap Deployment operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Update Deployment Status By Deployment Name operation initiates a change in the running status of a deployment. The status of a deployment can be running or suspended. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460808.aspx for more information) Required. The cloud service to swap deployments for. Required. The name of your deployment. Required. Parameters supplied to the Update Deployment Status By Deployment Name operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Update Deployment Status By Deployment Slot operation initiates a change in the running status of a deployment. The status of a deployment can be running or suspended. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460808.aspx for more information) Required. The cloud service to swap deployments for. Required. The deployment slot. Required. Parameters supplied to the Update Deployment Status By Deployment Slot operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Upgrade Deployment By Name operation initiates an update of role instances in a deployment using the package and configuration that you specify. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the request has been processed, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. To perform an automatic update of a deployment, call Upgrade Deployment or Change Deployment Configuration with the Mode element set to automatic. The update proceeds from that point without a need for further input. You can call Get Operation Status to determine when the update is complete. To perform a manual update, first call Upgrade Deployment with the Mode element set to manual. Next, call Walk Upgrade Domain to update each domain within the deployment. You should make sure that the operation is complete by calling Get Operation Status before updating the next domain. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. By default, a cloud service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To determine the update domain in which a particular instance is running in Windows Azure, use the UpdateDomain property of the RoleInstance class. See the Azure Managed Library Reference at http://msdn.microsoft.com/en-us/library/windowsazure/dd179380.aspx for more information. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460793.aspx for more information) Required. The cloud service to upgrade. Required. The deployment to upgrade. Required. Parameters supplied to the Upgrade Deployment By Name operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Upgrade Deployment By Slot operation initiates an update of role instances in a deployment using the package and configuration that you specify. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the request has been processed, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. To perform an automatic update of a deployment, call Upgrade Deployment or Change Deployment Configuration with the Mode element set to automatic. The update proceeds from that point without a need for further input. You can call Get Operation Status to determine when the update is complete. To perform a manual update, first call Upgrade Deployment with the Mode element set to manual. Next, call Walk Upgrade Domain to update each domain within the deployment. You should make sure that the operation is complete by calling Get Operation Status before updating the next domain. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. By default, a cloud service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To determine the update domain in which a particular instance is running in Windows Azure, use the UpdateDomain property of the RoleInstance class. See the Azure Managed Library Reference at http://msdn.microsoft.com/en-us/library/windowsazure/dd179380.aspx for more information. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460793.aspx for more information) Required. The cloud service to upgrade. Required. The slot to upgrade. Required. Parameters supplied to the Upgrade Deployment By Slot operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Walk Upgrade Domain By Deployment Name operation specifies an update domain in which a role instance must be updated. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. Prior to calling the Walk Upgrade Domain operation you must have called Upgrade Deployment, Change Deployment Configuration, or Rollback Update Or Upgrade. By default, a service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To perform a manual update of your deployment, proceed in this order: Call Upgrade Deployment with the Mode element set to manual. Call Walk Upgrade Domain to update each domain within the deployment. Update domains must be updated in order. For example, begin with domain 0, proceed to domain 1, and so on. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. While an update is in progress, call Get Deployment to determine its status. If the update is in progress, Get Deployment returns an UpgradeStatus element that contains information about the update. If the update is complete, or if no update is in progress, then the UpgradeStatus element is null. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460800.aspx for more information) Required. The name of the cloud service. Required. The name of your deployment. Required. Parameters supplied to the Walk Upgrade Domain By Deployment Name operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Walk Upgrade Domain By Deployment Slot operation specifies an update domain in which a role instance must be updated. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. Prior to calling the Walk Upgrade Domain operation you must have called Upgrade Deployment, Change Deployment Configuration, or Rollback Update Or Upgrade. By default, a service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To perform a manual update of your deployment, proceed in this order: Call Upgrade Deployment with the Mode element set to manual. Call Walk Upgrade Domain to update each domain within the deployment. Update domains must be updated in order. For example, begin with domain 0, proceed to domain 1, and so on. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. While an update is in progress, call Get Deployment to determine its status. If the update is in progress, Get Deployment returns an UpgradeStatus element that contains information about the update. If the update is complete, or if no update is in progress, then the UpgradeStatus element is null. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460800.aspx for more information) Required. The name of the cloud service. Required. The deployment slot. Required. Parameters supplied to the Walk Upgrade Domain By Deployment Slot operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Gets a reference to the Microsoft.WindowsAzure.Management.Compute.ComputeManagementClient. The Service Management API provides programmatic access to much of the functionality available through the Management Portal. The Service Management API is a REST API. All API operations are performed over SSL, and are mutually authenticated using X.509 v3 certificates. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460799.aspx for more information) The Begin Changing Deployment Configuration By Name operation initiates a change to the deployment configuration. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460809.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to change deployment configuration for. Required. The deployment to change configuration for. Required. Parameters supplied to the Begin Changing Configuration Deployment By Name operation. A standard service response including an HTTP status code and request ID. The Begin Changing Deployment Configuration By Name operation initiates a change to the deployment configuration. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460809.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to change deployment configuration for. Required. The deployment to change configuration for. Required. Parameters supplied to the Begin Changing Configuration Deployment By Name operation. A standard service response including an HTTP status code and request ID. The Begin Changing Deployment Configuration By Slot operation initiates a change to the deployment configuration. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460809.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to change deployment configuration for. Required. The slot to change deployment configuration for. Required. Parameters supplied to the Begin Changing Configuration Deployment By Slot operation. A standard service response including an HTTP status code and request ID. The Begin Changing Deployment Configuration By Slot operation initiates a change to the deployment configuration. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460809.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to change deployment configuration for. Required. The slot to change deployment configuration for. Required. Parameters supplied to the Begin Changing Configuration Deployment By Slot operation. A standard service response including an HTTP status code and request ID. The Begin Creating Deployment operation uploads a new service package and creates a new deployment in the staging or production environments. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460813.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to create a deployment for. Required. The slot to create a deployment for. Required. Parameters supplied to the Begin Creating Deployment operation. A standard service response including an HTTP status code and request ID. The Begin Creating Deployment operation uploads a new service package and creates a new deployment in the staging or production environments. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460813.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to create a deployment for. Required. The slot to create a deployment for. Required. Parameters supplied to the Begin Creating Deployment operation. A standard service response including an HTTP status code and request ID. The Begin Deleting Deployment By Name operation deletes the specified deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460815.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of your deployment. Required. Specifies that the source blob for the disk should also be deleted from storage. A standard service response including an HTTP status code and request ID. The Begin Deleting Deployment By Name operation deletes the specified deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460815.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of your deployment. Required. Specifies that the source blob for the disk should also be deleted from storage. A standard service response including an HTTP status code and request ID. The Begin Deleting Deployment By Slot operation deletes the specified deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460815.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The deployment slot. A standard service response including an HTTP status code and request ID. The Begin Deleting Deployment By Slot operation deletes the specified deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460815.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The deployment slot. A standard service response including an HTTP status code and request ID. The Delete Role Instances operation deletes a role instance from a deployment in a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469418.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of the deployment slot. Required. The parameters to delete the role. A standard service response including an HTTP status code and request ID. The Delete Role Instances operation deletes a role instance from a deployment in a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469418.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of the deployment slot. Required. The parameters to delete the role. A standard service response including an HTTP status code and request ID. The Delete Role Instances operation deletes a role instance from a deployment in a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469418.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of the deployment. Required. The parameters to delete the role. A standard service response including an HTTP status code and request ID. The Delete Role Instances operation deletes a role instance from a deployment in a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469418.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of the deployment. Required. The parameters to delete the role. A standard service response including an HTTP status code and request ID. The Begin Rebooting Role Instance By Deployment Name operation requests a reboot of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441298.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of your deployment. Required. The name of your role instance. A standard service response including an HTTP status code and request ID. The Begin Rebooting Role Instance By Deployment Name operation requests a reboot of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441298.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of your deployment. Required. The name of your role instance. A standard service response including an HTTP status code and request ID. The Begin Rebooting Role Instance By Deployment Slot operation requests a reboot of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441298.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The deployment slot. Required. The name of your role instance. A standard service response including an HTTP status code and request ID. The Begin Rebooting Role Instance By Deployment Slot operation requests a reboot of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441298.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The deployment slot. Required. The name of your role instance. A standard service response including an HTTP status code and request ID. The Begin Reimaging Role Instance By Deployment Name operation requests a reimage of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441292.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of your deployment. Required. The name of your role instance. A standard service response including an HTTP status code and request ID. The Begin Reimaging Role Instance By Deployment Name operation requests a reimage of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441292.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of your deployment. Required. The name of your role instance. A standard service response including an HTTP status code and request ID. The Begin Reimaging Role Instance By Deployment Slot operation requests a reimage of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441292.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The deployment slot. Required. The name of your role instance. A standard service response including an HTTP status code and request ID. The Begin Reimaging Role Instance By Deployment Slot operation requests a reimage of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441292.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The deployment slot. Required. The name of your role instance. A standard service response including an HTTP status code and request ID. The Begin Swapping Deployment operation initiates a virtual IP address swap between the staging and production deployment environments for a service. If the service is currently running in the staging environment, it will be swapped to the production environment. If it is running in the production environment, it will be swapped to staging. For more information on this type of upgrade, see Performing Virtual IP Swap Upgrades at http://msdn.microsoft.com/en-us/library/windowsazure/ee517253.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460814.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to swap deployments for. Required. Parameters supplied to the Begin Swapping Deployment operation. A standard service response including an HTTP status code and request ID. The Begin Swapping Deployment operation initiates a virtual IP address swap between the staging and production deployment environments for a service. If the service is currently running in the staging environment, it will be swapped to the production environment. If it is running in the production environment, it will be swapped to staging. For more information on this type of upgrade, see Performing Virtual IP Swap Upgrades at http://msdn.microsoft.com/en-us/library/windowsazure/ee517253.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460814.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to swap deployments for. Required. Parameters supplied to the Begin Swapping Deployment operation. A standard service response including an HTTP status code and request ID. The Begin Updating Deployment Status By Deployment Name operation initiates a change in the running status of a deployment. The status of a deployment can be running or suspended. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460808.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to swap deployments for. Required. The name of your deployment. Required. Parameters supplied to the Begin Updating Deployment Status By Deployment Name operation. A standard service response including an HTTP status code and request ID. The Begin Updating Deployment Status By Deployment Name operation initiates a change in the running status of a deployment. The status of a deployment can be running or suspended. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460808.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to swap deployments for. Required. The name of your deployment. Required. Parameters supplied to the Begin Updating Deployment Status By Deployment Name operation. A standard service response including an HTTP status code and request ID. The Begin Updating Deployment Status By Deployment Slot operation initiates a change in the running status of a deployment. The status of a deployment can be running or suspended. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460808.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to swap deployments for. Required. The deployment slot. Required. Parameters supplied to the Begin Updating Deployment Status By Deployment Slot operation. A standard service response including an HTTP status code and request ID. The Begin Updating Deployment Status By Deployment Slot operation initiates a change in the running status of a deployment. The status of a deployment can be running or suspended. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460808.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to swap deployments for. Required. The deployment slot. Required. Parameters supplied to the Begin Updating Deployment Status By Deployment Slot operation. A standard service response including an HTTP status code and request ID. The Begin Upgrading Deployment By Name operation initiates an update of role instances in a deployment using the package and configuration that you specify. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the request has been processed, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. To perform an automatic update of a deployment, call Upgrade Deployment or Change Deployment Configuration with the Mode element set to automatic. The update proceeds from that point without a need for further input. You can call Get Operation Status to determine when the update is complete. To perform a manual update, first call Upgrade Deployment with the Mode element set to manual. Next, call Walk Upgrade Domain to update each domain within the deployment. You should make sure that the operation is complete by calling Get Operation Status before updating the next domain. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. By default, a cloud service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To determine the update domain in which a particular instance is running in Windows Azure, use the UpdateDomain property of the RoleInstance class. See the Azure Managed Library Reference at http://msdn.microsoft.com/en-us/library/windowsazure/dd179380.aspx for more information. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460793.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to upgrade. Required. The deployment to upgrade. Required. Parameters supplied to the Begin Upgrading Deployment By Name operation. A standard service response including an HTTP status code and request ID. The Begin Upgrading Deployment By Name operation initiates an update of role instances in a deployment using the package and configuration that you specify. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the request has been processed, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. To perform an automatic update of a deployment, call Upgrade Deployment or Change Deployment Configuration with the Mode element set to automatic. The update proceeds from that point without a need for further input. You can call Get Operation Status to determine when the update is complete. To perform a manual update, first call Upgrade Deployment with the Mode element set to manual. Next, call Walk Upgrade Domain to update each domain within the deployment. You should make sure that the operation is complete by calling Get Operation Status before updating the next domain. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. By default, a cloud service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To determine the update domain in which a particular instance is running in Windows Azure, use the UpdateDomain property of the RoleInstance class. See the Azure Managed Library Reference at http://msdn.microsoft.com/en-us/library/windowsazure/dd179380.aspx for more information. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460793.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to upgrade. Required. The deployment to upgrade. Required. Parameters supplied to the Begin Upgrading Deployment By Name operation. A standard service response including an HTTP status code and request ID. The Begin Upgrading Deployment By Slot operation initiates an update of role instances in a deployment using the package and configuration that you specify. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx.This operation is an asynchronous operation. To determine whether the request has been processed, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. To perform an automatic update of a deployment, call Upgrade Deployment or Change Deployment Configuration with the Mode element set to automatic. The update proceeds from that point without a need for further input. You can call Get Operation Status to determine when the update is complete. To perform a manual update, first call Upgrade Deployment with the Mode element set to manual. Next, call Walk Upgrade Domain to update each domain within the deployment. You should make sure that the operation is complete by calling Get Operation Status before updating the next domain. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. By default, a cloud service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To determine the update domain in which a particular instance is running in Windows Azure, use the UpdateDomain property of the RoleInstance class. See the Azure Managed Library Reference at http://msdn.microsoft.com/en-us/library/windowsazure/dd179380.aspx for more information. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460793.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to upgrade. Required. The slot to upgrade. Required. Parameters supplied to the Begin Upgrading Deployment By Slot operation. A standard service response including an HTTP status code and request ID. The Begin Upgrading Deployment By Slot operation initiates an update of role instances in a deployment using the package and configuration that you specify. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx.This operation is an asynchronous operation. To determine whether the request has been processed, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. To perform an automatic update of a deployment, call Upgrade Deployment or Change Deployment Configuration with the Mode element set to automatic. The update proceeds from that point without a need for further input. You can call Get Operation Status to determine when the update is complete. To perform a manual update, first call Upgrade Deployment with the Mode element set to manual. Next, call Walk Upgrade Domain to update each domain within the deployment. You should make sure that the operation is complete by calling Get Operation Status before updating the next domain. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. By default, a cloud service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To determine the update domain in which a particular instance is running in Windows Azure, use the UpdateDomain property of the RoleInstance class. See the Azure Managed Library Reference at http://msdn.microsoft.com/en-us/library/windowsazure/dd179380.aspx for more information. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460793.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to upgrade. Required. The slot to upgrade. Required. Parameters supplied to the Begin Upgrading Deployment By Slot operation. A standard service response including an HTTP status code and request ID. The Begin Walking Upgrade Domain By Deployment Name operation specifies an update domain in which a role instance must be updated. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. Prior to calling the Walk Upgrade Domain operation you must have called Upgrade Deployment, Change Deployment Configuration, or Rollback Update Or Upgrade. By default, a service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To perform a manual update of your deployment, proceed in this order: Call Upgrade Deployment with the Mode element set to manual. Call Walk Upgrade Domain to update each domain within the deployment. Update domains must be updated in order. For example, begin with domain 0, proceed to domain 1, and so on. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. While an update is in progress, call Get Deployment to determine its status. If the update is in progress, Get Deployment returns an UpgradeStatus element that contains information about the update. If the update is complete, or if no update is in progress, then the UpgradeStatus element is null. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460800.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of your deployment. Required. Parameters supplied to the Begin Walking Upgrade Domain By Deployment Name operation. A standard service response including an HTTP status code and request ID. The Begin Walking Upgrade Domain By Deployment Name operation specifies an update domain in which a role instance must be updated. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. Prior to calling the Walk Upgrade Domain operation you must have called Upgrade Deployment, Change Deployment Configuration, or Rollback Update Or Upgrade. By default, a service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To perform a manual update of your deployment, proceed in this order: Call Upgrade Deployment with the Mode element set to manual. Call Walk Upgrade Domain to update each domain within the deployment. Update domains must be updated in order. For example, begin with domain 0, proceed to domain 1, and so on. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. While an update is in progress, call Get Deployment to determine its status. If the update is in progress, Get Deployment returns an UpgradeStatus element that contains information about the update. If the update is complete, or if no update is in progress, then the UpgradeStatus element is null. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460800.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of your deployment. Required. Parameters supplied to the Begin Walking Upgrade Domain By Deployment Name operation. A standard service response including an HTTP status code and request ID. The Begin Walking Upgrade Domain By Deployment Slot operation specifies an update domain in which a role instance must be updated. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. Prior to calling the Walk Upgrade Domain operation you must have called Upgrade Deployment, Change Deployment Configuration, or Rollback Update Or Upgrade. By default, a service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To perform a manual update of your deployment, proceed in this order: Call Upgrade Deployment with the Mode element set to manual. Call Walk Upgrade Domain to update each domain within the deployment. Update domains must be updated in order. For example, begin with domain 0, proceed to domain 1, and so on. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. While an update is in progress, call Get Deployment to determine its status. If the update is in progress, Get Deployment returns an UpgradeStatus element that contains information about the update. If the update is complete, or if no update is in progress, then the UpgradeStatus element is null. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460800.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The deployment slot. Required. Parameters supplied to the Begin Walking Upgrade Domain By Deployment Slot operation. A standard service response including an HTTP status code and request ID. The Begin Walking Upgrade Domain By Deployment Slot operation specifies an update domain in which a role instance must be updated. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. Prior to calling the Walk Upgrade Domain operation you must have called Upgrade Deployment, Change Deployment Configuration, or Rollback Update Or Upgrade. By default, a service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To perform a manual update of your deployment, proceed in this order: Call Upgrade Deployment with the Mode element set to manual. Call Walk Upgrade Domain to update each domain within the deployment. Update domains must be updated in order. For example, begin with domain 0, proceed to domain 1, and so on. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. While an update is in progress, call Get Deployment to determine its status. If the update is in progress, Get Deployment returns an UpgradeStatus element that contains information about the update. If the update is complete, or if no update is in progress, then the UpgradeStatus element is null. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460800.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The deployment slot. Required. Parameters supplied to the Begin Walking Upgrade Domain By Deployment Slot operation. A standard service response including an HTTP status code and request ID. The Change Deployment Configuration By Name operation initiates a change to the deployment configuration. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460809.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to change deployment configuration for. Required. The deployment to change configuration for. Required. Parameters supplied to the Change ConfigurationDeployment By Name operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Change Deployment Configuration By Name operation initiates a change to the deployment configuration. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460809.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to change deployment configuration for. Required. The deployment to change configuration for. Required. Parameters supplied to the Change ConfigurationDeployment By Name operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Change Deployment Configuration By Slot operation initiates a change to the deployment configuration. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460809.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to change deployment configuration for. Required. The slot to change deployment configuration for. Required. Parameters supplied to the Change Configuration Deployment By Slot operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Change Deployment Configuration By Slot operation initiates a change to the deployment configuration. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460809.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to change deployment configuration for. Required. The slot to change deployment configuration for. Required. Parameters supplied to the Change Configuration Deployment By Slot operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Create Deployment operation uploads a new service package and creates a new deployment in the staging or production environments. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460813.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to create a deployment for. Required. The slot to create a deployment for. Required. Parameters supplied to the Create Deployment operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Create Deployment operation uploads a new service package and creates a new deployment in the staging or production environments. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460813.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to create a deployment for. Required. The slot to create a deployment for. Required. Parameters supplied to the Create Deployment operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Deployment By Name operation deletes the specified deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460815.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of your deployment. Required. Specifies that the source blob for the disk should also be deleted from storage. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Deployment By Name operation deletes the specified deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460815.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of your deployment. Required. Specifies that the source blob for the disk should also be deleted from storage. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Deployment By Slot operation deletes the specified deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460815.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The deployment slot. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Deployment By Slot operation deletes the specified deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460815.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The deployment slot. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Role Instances operation deletes a role instance from a deployment in a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469418.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of the deployment. Required. The parameters to delete the role. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Role Instances operation deletes a role instance from a deployment in a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469418.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of the deployment. Required. The parameters to delete the role. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Role Instances operation deletes the role instances from a deployment in a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469418.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of the deployment slot. Required. The parameters to delete the role. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Role Instances operation deletes the role instances from a deployment in a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469418.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of the deployment slot. Required. The parameters to delete the role. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Get Deployment By Name operation returns configuration information, status, and system properties for a deployment. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460804.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of the deployment. A deployment that exists in the cloud service. The Get Deployment By Name operation returns configuration information, status, and system properties for a deployment. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460804.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of the deployment. A deployment that exists in the cloud service. The Get Deployment By Slot operation returns configuration information, status, and system properties for a deployment. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460804.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The deployment slot. A deployment that exists in the cloud service. The Get Deployment By Slot operation returns configuration information, status, and system properties for a deployment. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460804.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The deployment slot. A deployment that exists in the cloud service. The Get Package By Name operation retrieves a cloud service package for a deployment and stores the package files in Azure Blob storage. The following package files are placed in storage: the cloud service configuration file (.cscfg), providing configuration settings for the cloud service and individual roles, including the number of role instances; and the service package (.cspkg), containing the application code and the service definition file. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj154121.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of your deployment. Required. Parameters supplied to the Get Package By Name operation. A standard service response including an HTTP status code and request ID. The Get Package By Name operation retrieves a cloud service package for a deployment and stores the package files in Azure Blob storage. The following package files are placed in storage: the cloud service configuration file (.cscfg), providing configuration settings for the cloud service and individual roles, including the number of role instances; and the service package (.cspkg), containing the application code and the service definition file. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj154121.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of your deployment. Required. Parameters supplied to the Get Package By Name operation. A standard service response including an HTTP status code and request ID. The Get Package By Slot operation retrieves a cloud service package for a deployment and stores the package files in Azure Blob storage. The following package files are placed in storage: the cloud service configuration file (.cscfg), providing configuration settings for the cloud service and individual roles, including the number of role instances; and the service package (.cspkg), containing the application code and the service definition file. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj154121.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The deployment slot. Required. Parameters supplied to the Get Package By Slot operation. A standard service response including an HTTP status code and request ID. The Get Package By Slot operation retrieves a cloud service package for a deployment and stores the package files in Azure Blob storage. The following package files are placed in storage: the cloud service configuration file (.cscfg), providing configuration settings for the cloud service and individual roles, including the number of role instances; and the service package (.cspkg), containing the application code and the service definition file. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj154121.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The deployment slot. Required. Parameters supplied to the Get Package By Slot operation. A standard service response including an HTTP status code and request ID. The Reboot Role Instance By Deployment Name operation requests a reboot of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441298.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of your deployment. Required. The name of your role instance. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Reboot Role Instance By Deployment Name operation requests a reboot of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441298.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of your deployment. Required. The name of your role instance. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Reboot Role Instance By Deployment Slot operation requests a reboot of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441298.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The deployment slot. Required. The name of your role instance. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Reboot Role Instance By Deployment Slot operation requests a reboot of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441298.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The deployment slot. Required. The name of your role instance. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Reimage Role Instance By Deployment Name operation requests a reimage of a role instance that is running in a deployment.This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441292.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of your deployment. Required. The name of your role instance. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Reimage Role Instance By Deployment Name operation requests a reimage of a role instance that is running in a deployment.This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441292.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of your deployment. Required. The name of your role instance. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Reimage Role Instance By Deployment Slot operation requests a reimage of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441292.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The deployment slot. Required. The name of your role instance. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Reimage Role Instance By Deployment Slot operation requests a reimage of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441292.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The deployment slot. Required. The name of your role instance. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Rollback Update Or Upgrade By Deployment Name operation cancels an in-progress configuration update and returns the deployment to its state before the update was started. This operation can only be called when an update is in progress on the deployment. The deployment status can be detected by calling the Get Deployment operation or Get Hosted Service Properties operation and inspecting the RollbackAllowed element. If the value returned is true a rollback can be performed. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh403977.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to swap deployments for. Required. The name of your deployment. Required. Parameters supplied to the Rollback Update Or Upgrade By Deployment Name operation. A standard service response including an HTTP status code and request ID. The Rollback Update Or Upgrade By Deployment Name operation cancels an in-progress configuration update and returns the deployment to its state before the update was started. This operation can only be called when an update is in progress on the deployment. The deployment status can be detected by calling the Get Deployment operation or Get Hosted Service Properties operation and inspecting the RollbackAllowed element. If the value returned is true a rollback can be performed. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh403977.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to swap deployments for. Required. The name of your deployment. Required. Parameters supplied to the Rollback Update Or Upgrade By Deployment Name operation. A standard service response including an HTTP status code and request ID. The Rollback Update Or Upgrade By Deployment Slot operation cancels an in-progress configuration update and returns the deployment to its state before the update was started. This operation can only be called when an update is in progress on the deployment. The deployment status can be detected by calling the Get Deployment operation or Get Hosted Service Properties operation and inspecting the RollbackAllowed element. If the value returned is true a rollback can be performed. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh403977.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to swap deployments for. Required. The deployment slot. Required. Parameters supplied to the Rollback Update Or Upgrade By Deployment Slot operation. A standard service response including an HTTP status code and request ID. The Rollback Update Or Upgrade By Deployment Slot operation cancels an in-progress configuration update and returns the deployment to its state before the update was started. This operation can only be called when an update is in progress on the deployment. The deployment status can be detected by calling the Get Deployment operation or Get Hosted Service Properties operation and inspecting the RollbackAllowed element. If the value returned is true a rollback can be performed. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh403977.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to swap deployments for. Required. The deployment slot. Required. Parameters supplied to the Rollback Update Or Upgrade By Deployment Slot operation. A standard service response including an HTTP status code and request ID. The Swap Deployment operation initiates a virtual IP address swap between the staging and production deployment environments for a service. If the service is currently running in the staging environment, it will be swapped to the production environment. If it is running in the production environment, it will be swapped to staging. For more information on this type of upgrade, see Performing Virtual IP Swap Upgrades at http://msdn.microsoft.com/en-us/library/windowsazure/ee517253.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460814.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to swap deployments for. Required. Parameters supplied to the Swap Deployment operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Swap Deployment operation initiates a virtual IP address swap between the staging and production deployment environments for a service. If the service is currently running in the staging environment, it will be swapped to the production environment. If it is running in the production environment, it will be swapped to staging. For more information on this type of upgrade, see Performing Virtual IP Swap Upgrades at http://msdn.microsoft.com/en-us/library/windowsazure/ee517253.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460814.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to swap deployments for. Required. Parameters supplied to the Swap Deployment operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Update Deployment Status By Deployment Name operation initiates a change in the running status of a deployment. The status of a deployment can be running or suspended. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460808.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to swap deployments for. Required. The name of your deployment. Required. Parameters supplied to the Update Deployment Status By Deployment Name operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Update Deployment Status By Deployment Name operation initiates a change in the running status of a deployment. The status of a deployment can be running or suspended. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460808.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to swap deployments for. Required. The name of your deployment. Required. Parameters supplied to the Update Deployment Status By Deployment Name operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Update Deployment Status By Deployment Slot operation initiates a change in the running status of a deployment. The status of a deployment can be running or suspended. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460808.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to swap deployments for. Required. The deployment slot. Required. Parameters supplied to the Update Deployment Status By Deployment Slot operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Update Deployment Status By Deployment Slot operation initiates a change in the running status of a deployment. The status of a deployment can be running or suspended. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460808.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to swap deployments for. Required. The deployment slot. Required. Parameters supplied to the Update Deployment Status By Deployment Slot operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Upgrade Deployment By Name operation initiates an update of role instances in a deployment using the package and configuration that you specify. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the request has been processed, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. To perform an automatic update of a deployment, call Upgrade Deployment or Change Deployment Configuration with the Mode element set to automatic. The update proceeds from that point without a need for further input. You can call Get Operation Status to determine when the update is complete. To perform a manual update, first call Upgrade Deployment with the Mode element set to manual. Next, call Walk Upgrade Domain to update each domain within the deployment. You should make sure that the operation is complete by calling Get Operation Status before updating the next domain. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. By default, a cloud service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To determine the update domain in which a particular instance is running in Windows Azure, use the UpdateDomain property of the RoleInstance class. See the Azure Managed Library Reference at http://msdn.microsoft.com/en-us/library/windowsazure/dd179380.aspx for more information. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460793.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to upgrade. Required. The deployment to upgrade. Required. Parameters supplied to the Upgrade Deployment By Name operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Upgrade Deployment By Name operation initiates an update of role instances in a deployment using the package and configuration that you specify. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the request has been processed, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. To perform an automatic update of a deployment, call Upgrade Deployment or Change Deployment Configuration with the Mode element set to automatic. The update proceeds from that point without a need for further input. You can call Get Operation Status to determine when the update is complete. To perform a manual update, first call Upgrade Deployment with the Mode element set to manual. Next, call Walk Upgrade Domain to update each domain within the deployment. You should make sure that the operation is complete by calling Get Operation Status before updating the next domain. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. By default, a cloud service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To determine the update domain in which a particular instance is running in Windows Azure, use the UpdateDomain property of the RoleInstance class. See the Azure Managed Library Reference at http://msdn.microsoft.com/en-us/library/windowsazure/dd179380.aspx for more information. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460793.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to upgrade. Required. The deployment to upgrade. Required. Parameters supplied to the Upgrade Deployment By Name operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Upgrade Deployment By Slot operation initiates an update of role instances in a deployment using the package and configuration that you specify. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the request has been processed, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. To perform an automatic update of a deployment, call Upgrade Deployment or Change Deployment Configuration with the Mode element set to automatic. The update proceeds from that point without a need for further input. You can call Get Operation Status to determine when the update is complete. To perform a manual update, first call Upgrade Deployment with the Mode element set to manual. Next, call Walk Upgrade Domain to update each domain within the deployment. You should make sure that the operation is complete by calling Get Operation Status before updating the next domain. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. By default, a cloud service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To determine the update domain in which a particular instance is running in Windows Azure, use the UpdateDomain property of the RoleInstance class. See the Azure Managed Library Reference at http://msdn.microsoft.com/en-us/library/windowsazure/dd179380.aspx for more information. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460793.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to upgrade. Required. The slot to upgrade. Required. Parameters supplied to the Upgrade Deployment By Slot operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Upgrade Deployment By Slot operation initiates an update of role instances in a deployment using the package and configuration that you specify. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the request has been processed, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. To perform an automatic update of a deployment, call Upgrade Deployment or Change Deployment Configuration with the Mode element set to automatic. The update proceeds from that point without a need for further input. You can call Get Operation Status to determine when the update is complete. To perform a manual update, first call Upgrade Deployment with the Mode element set to manual. Next, call Walk Upgrade Domain to update each domain within the deployment. You should make sure that the operation is complete by calling Get Operation Status before updating the next domain. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. By default, a cloud service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To determine the update domain in which a particular instance is running in Windows Azure, use the UpdateDomain property of the RoleInstance class. See the Azure Managed Library Reference at http://msdn.microsoft.com/en-us/library/windowsazure/dd179380.aspx for more information. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460793.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to upgrade. Required. The slot to upgrade. Required. Parameters supplied to the Upgrade Deployment By Slot operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Walk Upgrade Domain By Deployment Name operation specifies an update domain in which a role instance must be updated. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. Prior to calling the Walk Upgrade Domain operation you must have called Upgrade Deployment, Change Deployment Configuration, or Rollback Update Or Upgrade. By default, a service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To perform a manual update of your deployment, proceed in this order: Call Upgrade Deployment with the Mode element set to manual. Call Walk Upgrade Domain to update each domain within the deployment. Update domains must be updated in order. For example, begin with domain 0, proceed to domain 1, and so on. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. While an update is in progress, call Get Deployment to determine its status. If the update is in progress, Get Deployment returns an UpgradeStatus element that contains information about the update. If the update is complete, or if no update is in progress, then the UpgradeStatus element is null. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460800.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of your deployment. Required. Parameters supplied to the Walk Upgrade Domain By Deployment Name operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Walk Upgrade Domain By Deployment Name operation specifies an update domain in which a role instance must be updated. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. Prior to calling the Walk Upgrade Domain operation you must have called Upgrade Deployment, Change Deployment Configuration, or Rollback Update Or Upgrade. By default, a service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To perform a manual update of your deployment, proceed in this order: Call Upgrade Deployment with the Mode element set to manual. Call Walk Upgrade Domain to update each domain within the deployment. Update domains must be updated in order. For example, begin with domain 0, proceed to domain 1, and so on. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. While an update is in progress, call Get Deployment to determine its status. If the update is in progress, Get Deployment returns an UpgradeStatus element that contains information about the update. If the update is complete, or if no update is in progress, then the UpgradeStatus element is null. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460800.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of your deployment. Required. Parameters supplied to the Walk Upgrade Domain By Deployment Name operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Walk Upgrade Domain By Deployment Slot operation specifies an update domain in which a role instance must be updated. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. Prior to calling the Walk Upgrade Domain operation you must have called Upgrade Deployment, Change Deployment Configuration, or Rollback Update Or Upgrade. By default, a service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To perform a manual update of your deployment, proceed in this order: Call Upgrade Deployment with the Mode element set to manual. Call Walk Upgrade Domain to update each domain within the deployment. Update domains must be updated in order. For example, begin with domain 0, proceed to domain 1, and so on. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. While an update is in progress, call Get Deployment to determine its status. If the update is in progress, Get Deployment returns an UpgradeStatus element that contains information about the update. If the update is complete, or if no update is in progress, then the UpgradeStatus element is null. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460800.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The deployment slot. Required. Parameters supplied to the Walk Upgrade Domain By Deployment Slot operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Walk Upgrade Domain By Deployment Slot operation specifies an update domain in which a role instance must be updated. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. Prior to calling the Walk Upgrade Domain operation you must have called Upgrade Deployment, Change Deployment Configuration, or Rollback Update Or Upgrade. By default, a service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To perform a manual update of your deployment, proceed in this order: Call Upgrade Deployment with the Mode element set to manual. Call Walk Upgrade Domain to update each domain within the deployment. Update domains must be updated in order. For example, begin with domain 0, proceed to domain 1, and so on. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. While an update is in progress, call Get Deployment to determine its status. If the update is in progress, Get Deployment returns an UpgradeStatus element that contains information about the update. If the update is complete, or if no update is in progress, then the UpgradeStatus element is null. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460800.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The deployment slot. Required. Parameters supplied to the Walk Upgrade Domain By Deployment Slot operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Service Management API includes operations for managing the hosted services beneath your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460812.aspx for more information) The Service Management API includes operations for managing the hosted services beneath your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460812.aspx for more information) The Add Extension operation adds an available extension to your cloud service. In Azure, a process can run as an extension of a cloud service. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as extensions to the cloud service. You can find the available extension by using the List Available Extensions operation. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169558.aspx for more information) The name of the cloud service. Parameters supplied to the Add Extension operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Begin Adding Extension operation adds an available extension to your cloud service. In Azure, a process can run as an extension of a cloud service. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as extensions to the cloud service. You can find the available extension by using the List Available Extensions operation. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169558.aspx for more information) The name of the cloud service. Parameters supplied to the Begin Adding Extension operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Deleting All Hosted Service operation deletes the specified cloud service from Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441305.aspx for more information) The name of the cloud service. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Deleting Extension operation deletes the specified extension from a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169560.aspx for more information) The name of the cloud service. The identifier that was assigned to the extension when it was added to the cloud service Cancellation token. A standard service response including an HTTP status code and request ID. The Check Hosted Service Name Availability operation checks for the availability of the specified cloud service name. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj154116.aspx for more information) The cloud service name that you would like to use. Cancellation token. The Check Hosted Service Name Availability operation response. The Create Hosted Service operation creates a new cloud service in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441304.aspx for more information) Parameters supplied to the Create Hosted Service operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Delete Hosted Service operation deletes the specified cloud service from Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441305.aspx for more information) The name of the cloud service. Cancellation token. A standard service response including an HTTP status code and request ID. The Delete All Hosted Service operation deletes the specified cloud service from Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441305.aspx for more information) The name of the cloud service. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Extension operation deletes the specified extension from a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169560.aspx for more information) The name of the cloud service. The identifier that was assigned to the extension when it was added to the cloud service Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Get Hosted Service Properties operation retrieves system properties for the specified cloud service. These properties include the service name and service type; and the name of the affinity group to which the service belongs, or its location if it is not part of an affinity group. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460806.aspx for more information) The name of the cloud service. Cancellation token. The Get Hosted Service operation response. The Get Detailed Hosted Service Properties operation retrieves system properties for the specified cloud service. These properties include the service name and service type; the name of the affinity group to which the service belongs, or its location if it is not part of an affinity group; and information on the deployments of the service. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460806.aspx for more information) The name of the cloud service. Cancellation token. The detailed Get Hosted Service operation response. The Get Extension operation retrieves information about a specified extension that was added to a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169557.aspx for more information) The name of the cloud service. The identifier that was assigned to the extension when it was added to the cloud service Cancellation token. The Get Extension operation response. The List Hosted Services operation lists the cloud services available under the current subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460781.aspx for more information) Cancellation token. The List Hosted Service operation response. The List Available Extensions operation lists the extensions that are available to add to your cloud service. In Windows Azure, a process can run as an extension of a cloud service. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as extensions to the cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169559.aspx for more information) Cancellation token. The List Available Extensions operation response. The List Extensions operation lists all of the extensions that were added to a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169561.aspx for more information) The name of the cloud service. Cancellation token. The List Extensions operation response. The List Extension Versions operation lists the versions of an extension that are available to add to a cloud service. In Azure, a process can run as an extension of a cloud service. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as extensions to the cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn495437.aspx for more information) The provider namespace. The extension type name. Cancellation token. The List Available Extensions operation response. The Update Hosted Service operation can update the label or description of a cloud service in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441303.aspx for more information) The name of the cloud service. Parameters supplied to the Update Hosted Service operation. Cancellation token. A standard service response including an HTTP status code and request ID. Initializes a new instance of the HostedServiceOperations class. Reference to the service client. The Add Extension operation adds an available extension to your cloud service. In Azure, a process can run as an extension of a cloud service. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as extensions to the cloud service. You can find the available extension by using the List Available Extensions operation. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169558.aspx for more information) Required. The name of the cloud service. Required. Parameters supplied to the Add Extension operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Begin Adding Extension operation adds an available extension to your cloud service. In Azure, a process can run as an extension of a cloud service. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as extensions to the cloud service. You can find the available extension by using the List Available Extensions operation. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169558.aspx for more information) Required. The name of the cloud service. Required. Parameters supplied to the Begin Adding Extension operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Deleting All Hosted Service operation deletes the specified cloud service from Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441305.aspx for more information) Required. The name of the cloud service. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Deleting Extension operation deletes the specified extension from a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169560.aspx for more information) Required. The name of the cloud service. Required. The identifier that was assigned to the extension when it was added to the cloud service Cancellation token. A standard service response including an HTTP status code and request ID. The Check Hosted Service Name Availability operation checks for the availability of the specified cloud service name. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj154116.aspx for more information) Required. The cloud service name that you would like to use. Cancellation token. The Check Hosted Service Name Availability operation response. The Create Hosted Service operation creates a new cloud service in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441304.aspx for more information) Required. Parameters supplied to the Create Hosted Service operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Delete Hosted Service operation deletes the specified cloud service from Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441305.aspx for more information) Required. The name of the cloud service. Cancellation token. A standard service response including an HTTP status code and request ID. The Delete All Hosted Service operation deletes the specified cloud service from Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441305.aspx for more information) Required. The name of the cloud service. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Extension operation deletes the specified extension from a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169560.aspx for more information) Required. The name of the cloud service. Required. The identifier that was assigned to the extension when it was added to the cloud service Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Get Hosted Service Properties operation retrieves system properties for the specified cloud service. These properties include the service name and service type; and the name of the affinity group to which the service belongs, or its location if it is not part of an affinity group. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460806.aspx for more information) Required. The name of the cloud service. Cancellation token. The Get Hosted Service operation response. The Get Detailed Hosted Service Properties operation retrieves system properties for the specified cloud service. These properties include the service name and service type; the name of the affinity group to which the service belongs, or its location if it is not part of an affinity group; and information on the deployments of the service. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460806.aspx for more information) Required. The name of the cloud service. Cancellation token. The detailed Get Hosted Service operation response. The Get Extension operation retrieves information about a specified extension that was added to a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169557.aspx for more information) Required. The name of the cloud service. Required. The identifier that was assigned to the extension when it was added to the cloud service Cancellation token. The Get Extension operation response. The List Hosted Services operation lists the cloud services available under the current subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460781.aspx for more information) Cancellation token. The List Hosted Service operation response. The List Available Extensions operation lists the extensions that are available to add to your cloud service. In Windows Azure, a process can run as an extension of a cloud service. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as extensions to the cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169559.aspx for more information) Cancellation token. The List Available Extensions operation response. The List Extensions operation lists all of the extensions that were added to a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169561.aspx for more information) Required. The name of the cloud service. Cancellation token. The List Extensions operation response. The List Extension Versions operation lists the versions of an extension that are available to add to a cloud service. In Azure, a process can run as an extension of a cloud service. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as extensions to the cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn495437.aspx for more information) Required. The provider namespace. Required. The extension type name. Cancellation token. The List Available Extensions operation response. The Update Hosted Service operation can update the label or description of a cloud service in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441303.aspx for more information) Required. The name of the cloud service. Required. Parameters supplied to the Update Hosted Service operation. Cancellation token. A standard service response including an HTTP status code and request ID. Gets a reference to the Microsoft.WindowsAzure.Management.Compute.ComputeManagementClient. The Service Management API provides programmatic access to much of the functionality available through the Management Portal. The Service Management API is a REST API. All API operations are performed over SSL, and are mutually authenticated using X.509 v3 certificates. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460799.aspx for more information) The Add Extension operation adds an available extension to your cloud service. In Azure, a process can run as an extension of a cloud service. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as extensions to the cloud service. You can find the available extension by using the List Available Extensions operation. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169558.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. Required. Parameters supplied to the Add Extension operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Add Extension operation adds an available extension to your cloud service. In Azure, a process can run as an extension of a cloud service. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as extensions to the cloud service. You can find the available extension by using the List Available Extensions operation. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169558.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. Required. Parameters supplied to the Add Extension operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Begin Adding Extension operation adds an available extension to your cloud service. In Azure, a process can run as an extension of a cloud service. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as extensions to the cloud service. You can find the available extension by using the List Available Extensions operation. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169558.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. Required. Parameters supplied to the Begin Adding Extension operation. A standard service response including an HTTP status code and request ID. The Begin Adding Extension operation adds an available extension to your cloud service. In Azure, a process can run as an extension of a cloud service. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as extensions to the cloud service. You can find the available extension by using the List Available Extensions operation. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169558.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. Required. Parameters supplied to the Begin Adding Extension operation. A standard service response including an HTTP status code and request ID. The Begin Deleting All Hosted Service operation deletes the specified cloud service from Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441305.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. A standard service response including an HTTP status code and request ID. The Begin Deleting All Hosted Service operation deletes the specified cloud service from Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441305.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. A standard service response including an HTTP status code and request ID. The Begin Deleting Extension operation deletes the specified extension from a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169560.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. Required. The identifier that was assigned to the extension when it was added to the cloud service A standard service response including an HTTP status code and request ID. The Begin Deleting Extension operation deletes the specified extension from a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169560.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. Required. The identifier that was assigned to the extension when it was added to the cloud service A standard service response including an HTTP status code and request ID. The Check Hosted Service Name Availability operation checks for the availability of the specified cloud service name. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj154116.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The cloud service name that you would like to use. The Check Hosted Service Name Availability operation response. The Check Hosted Service Name Availability operation checks for the availability of the specified cloud service name. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj154116.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The cloud service name that you would like to use. The Check Hosted Service Name Availability operation response. The Create Hosted Service operation creates a new cloud service in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441304.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. Parameters supplied to the Create Hosted Service operation. A standard service response including an HTTP status code and request ID. The Create Hosted Service operation creates a new cloud service in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441304.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. Parameters supplied to the Create Hosted Service operation. A standard service response including an HTTP status code and request ID. The Delete Hosted Service operation deletes the specified cloud service from Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441305.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. A standard service response including an HTTP status code and request ID. The Delete Hosted Service operation deletes the specified cloud service from Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441305.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. A standard service response including an HTTP status code and request ID. The Delete All Hosted Service operation deletes the specified cloud service from Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441305.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete All Hosted Service operation deletes the specified cloud service from Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441305.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Extension operation deletes the specified extension from a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169560.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. Required. The identifier that was assigned to the extension when it was added to the cloud service The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Extension operation deletes the specified extension from a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169560.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. Required. The identifier that was assigned to the extension when it was added to the cloud service The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Get Hosted Service Properties operation retrieves system properties for the specified cloud service. These properties include the service name and service type; and the name of the affinity group to which the service belongs, or its location if it is not part of an affinity group. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460806.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. The Get Hosted Service operation response. The Get Hosted Service Properties operation retrieves system properties for the specified cloud service. These properties include the service name and service type; and the name of the affinity group to which the service belongs, or its location if it is not part of an affinity group. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460806.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. The Get Hosted Service operation response. The Get Detailed Hosted Service Properties operation retrieves system properties for the specified cloud service. These properties include the service name and service type; the name of the affinity group to which the service belongs, or its location if it is not part of an affinity group; and information on the deployments of the service. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460806.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. The detailed Get Hosted Service operation response. The Get Detailed Hosted Service Properties operation retrieves system properties for the specified cloud service. These properties include the service name and service type; the name of the affinity group to which the service belongs, or its location if it is not part of an affinity group; and information on the deployments of the service. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460806.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. The detailed Get Hosted Service operation response. The Get Extension operation retrieves information about a specified extension that was added to a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169557.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. Required. The identifier that was assigned to the extension when it was added to the cloud service The Get Extension operation response. The Get Extension operation retrieves information about a specified extension that was added to a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169557.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. Required. The identifier that was assigned to the extension when it was added to the cloud service The Get Extension operation response. The List Hosted Services operation lists the cloud services available under the current subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460781.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. The List Hosted Service operation response. The List Hosted Services operation lists the cloud services available under the current subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460781.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. The List Hosted Service operation response. The List Available Extensions operation lists the extensions that are available to add to your cloud service. In Windows Azure, a process can run as an extension of a cloud service. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as extensions to the cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169559.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. The List Available Extensions operation response. The List Available Extensions operation lists the extensions that are available to add to your cloud service. In Windows Azure, a process can run as an extension of a cloud service. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as extensions to the cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169559.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. The List Available Extensions operation response. The List Extensions operation lists all of the extensions that were added to a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169561.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. The List Extensions operation response. The List Extensions operation lists all of the extensions that were added to a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169561.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. The List Extensions operation response. The List Extension Versions operation lists the versions of an extension that are available to add to a cloud service. In Azure, a process can run as an extension of a cloud service. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as extensions to the cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn495437.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The provider namespace. Required. The extension type name. The List Available Extensions operation response. The List Extension Versions operation lists the versions of an extension that are available to add to a cloud service. In Azure, a process can run as an extension of a cloud service. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as extensions to the cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn495437.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The provider namespace. Required. The extension type name. The List Available Extensions operation response. The Update Hosted Service operation can update the label or description of a cloud service in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441303.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. Required. Parameters supplied to the Update Hosted Service operation. A standard service response including an HTTP status code and request ID. The Update Hosted Service operation can update the label or description of a cloud service in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441303.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. Required. Parameters supplied to the Update Hosted Service operation. A standard service response including an HTTP status code and request ID. The Compute Management API includes operations for managing the load balancers for your subscription. Add an internal load balancer to a an existing deployment. When used by an input endpoint, the internal load balancer will provide an additional private VIP that can be used for load balancing to the roles in this deployment. The name of the service. The name of the deployment. Parameters supplied to the Create Load Balancer operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Delete an internal load balancer from the deployment. The name of the service. The name of the deployment. The name of the load balancer. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Add an internal load balancer to a an existing deployment. When used by an input endpoint, the internal load balancer will provide an additional private VIP that can be used for load balancing to the roles in this deployment. The name of the service. The name of the deployment. Parameters supplied to the Create Load Balancer operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Delete an internal load balancer from the deployment. The name of the service. The name of the deployment. The name of the load balancer. Cancellation token. A standard service response including an HTTP status code and request ID. Operations for determining the version of the Azure Guest Operating System on which your service is running. (see http://msdn.microsoft.com/en-us/library/windowsazure/ff684169.aspx for more information) The List Operating Systems operation lists the versions of the guest operating system that are currently available in Windows Azure. The 2010-10-28 version of List Operating Systems also indicates what family an operating system version belongs to. Currently Azure supports two operating system families: the Azure guest operating system that is substantially compatible with Windows Server 2008 SP2, and the Azure guest operating system that is substantially compatible with Windows Server 2008 R2. (see http://msdn.microsoft.com/en-us/library/windowsazure/ff684168.aspx for more information) Cancellation token. The List Operating Systems operation response. The List OS Families operation lists the guest operating system families available in Azure, and also lists the operating system versions available for each family. Currently Azure supports two operating system families: the Azure guest operating system that is substantially compatible with Windows Server 2008 SP2, and the Azure guest operating system that is substantially compatible with Windows Server 2008 R2. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441291.aspx for more information) Cancellation token. The List Operating System Families operation response. Operations for managing service certificates for your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee795178.aspx for more information) The Begin Creating Service Certificate operation adds a certificate to a hosted service. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460817.aspx for more information) The DNS prefix name of your service. Parameters supplied to the Begin Creating Service Certificate operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Deleting Service Certificate operation deletes a service certificate from the certificate store of a hosted service. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460803.aspx for more information) Parameters supplied to the Begin Deleting Service Certificate operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Create Service Certificate operation adds a certificate to a hosted service. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460817.aspx for more information) The DNS prefix name of your service. Parameters supplied to the Create Service Certificate operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Service Certificate operation deletes a service certificate from the certificate store of a hosted service. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460803.aspx for more information) Parameters supplied to the Delete Service Certificate operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Get Service Certificate operation returns the public data for the specified X.509 certificate associated with a hosted service. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460792.aspx for more information) Parameters supplied to the Get Service Certificate operation. Cancellation token. The Get Service Certificate operation response. The List Service Certificates operation lists all of the service certificates associated with the specified hosted service. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj154105.aspx for more information) The DNS prefix name of your hosted service. Cancellation token. The List Service Certificates operation response. The Service Management API includes operations for managing the disks in your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157188.aspx for more information) The Begin Deleting Data Disk operation removes the specified data disk from a virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157179.aspx for more information) The name of your service. The name of the deployment. The name of the role to delete the data disk from. The logical unit number of the disk. Specifies that the source blob for the disk should also be deleted from storage. Cancellation token. A standard service response including an HTTP status code and request ID. The Create Data Disk operation adds a data disk to a virtual machine. There are three ways to create the data disk using the Add Data Disk operation. Option 1 - Attach an empty data disk to the role by specifying the disk label and location of the disk image. Do not include the DiskName and SourceMediaLink elements in the request body. Include the MediaLink element and reference a blob that is in the same geographical region as the role. You can also omit the MediaLink element. In this usage, Azure will create the data disk in the storage account configured as default for the role. Option 2 - Attach an existing data disk that is in the image repository. Do not include the DiskName and SourceMediaLink elements in the request body. Specify the data disk to use by including the DiskName element. Note: If included the in the response body, the MediaLink and LogicalDiskSizeInGB elements are ignored. Option 3 - Specify the location of a blob in your storage account that contain a disk image to use. Include the SourceMediaLink element. Note: If the MediaLink element isincluded, it is ignored. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157199.aspx for more information) The name of your service. The name of the deployment. The name of the role to add the data disk to. Parameters supplied to the Create Virtual Machine Data Disk operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Create Disk operation adds a disk to the user image repository. The disk can be an operating system disk or a data disk. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157178.aspx for more information) Parameters supplied to the Create Virtual Machine Disk operation. Cancellation token. A virtual machine disk associated with your subscription. The Delete Data Disk operation removes the specified data disk from a virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157179.aspx for more information) The name of your service. The name of the deployment. The name of the role to delete the data disk from. The logical unit number of the disk. Specifies that the source blob for the disk should also be deleted from storage. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Disk operation deletes the specified data or operating system disk from your image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157200.aspx for more information) The name of the disk to delete. Specifies that the source blob for the disk should also be deleted from storage. Cancellation token. A standard service response including an HTTP status code and request ID. The Get Data Disk operation retrieves the specified data disk from a virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157180.aspx for more information) The name of your service. The name of the deployment. The name of the role. The logical unit number of the disk. Cancellation token. The Get Data Disk operation response. The Get Disk operation retrieves a disk from the user image repository. The disk can be an operating system disk or a data disk. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157178.aspx for more information) The name of the disk. Cancellation token. A virtual machine disk associated with your subscription. The List Disks operation retrieves a list of the disks in your image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157176.aspx for more information) Cancellation token. The List Disks operation response. The Update Data Disk operation updates the specified data disk attached to the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157190.aspx for more information) The name of your service. The name of the deployment. The name of the role to add the data disk to. The logical unit number of the disk. Parameters supplied to the Update Virtual Machine Data Disk operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Add Disk operation adds a disk to the user image repository. The disk can be an operating system disk or a data disk. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157178.aspx for more information) The name of the disk being updated. Parameters supplied to the Update Virtual Machine Disk operation. Cancellation token. A virtual machine disk associated with your subscription. The Service Management API includes operations for managing the virtual machine extensions in your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157206.aspx for more information) The List Resource Extensions operation lists the resource extensions that are available to add to a Virtual Machine. In Azure, a process can run as a resource extension of a Virtual Machine. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as resource extensions to the Virtual Machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn495441.aspx for more information) Cancellation token. The List Resource Extensions operation response. The List Resource Extension Versions operation lists the versions of a resource extension that are available to add to a Virtual Machine. In Azure, a process can run as a resource extension of a Virtual Machine. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as resource extensions to the Virtual Machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn495440.aspx for more information) The name of the publisher. The name of the extension. Cancellation token. The List Resource Extensions operation response. The Service Management API includes operations for managing the virtual machines in your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157206.aspx for more information) The Begin Capturing Role operation creates a copy of the operating system virtual hard disk (VHD) that is deployed in the virtual machine, saves the VHD copy in the same storage location as the operating system VHD, and registers the copy as an image in your image gallery. From the captured image, you can create additional customized virtual machines. For more information about images and disks, see Manage Disks and Images at http://msdn.microsoft.com/en-us/library/windowsazure/jj672979.aspx. For more information about capturing images, see How to Capture an Image of a Virtual Machine Running Windows Server 2008 R2 at http://www.windowsazure.com/en-us/documentation/articles/virtual-machines-capture-image-windows-server/ or How to Capture an Image of a Virtual Machine Running Linux at http://www.windowsazure.com/en-us/documentation/articles/virtual-machines-linux-capture-image/. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157201.aspx for more information) The name of your service. The name of your deployment. The name of the virtual machine to restart. Parameters supplied to the Begin Capturing Virtual Machine operation. Cancellation token. A standard service response including an HTTP status code and request ID. Begin capturing role as VM template. The name of your service. The name of your deployment. The name of the virtual machine to restart. Parameters supplied to the Capture Virtual Machine operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Creating Role operation adds a virtual machine to an existing deployment. You can refer to the OSDisk in the Add Role operation in the following ways: Platform/User Image - Set the SourceImageName to a platform or user image. You can optionally specify the DiskName and MediaLink values as part the operation to control the name and location of target disk. When DiskName and MediaLink are specified in this mode, they must not already exist in the system, otherwise a conflict fault is returned; UserDisk - Set DiskName to a user supplied image in image repository. SourceImageName must be set to NULL. All other properties are ignored; or Blob in a Storage Account - Set MediaLink to a blob containing the image. SourceImageName and DiskName are set to NULL. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157186.aspx for more information) The name of your service. The name of your deployment. Parameters supplied to the Begin Creating Virtual Machine operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Creating Virtual Machine Deployment operation provisions a virtual machine based on the supplied configuration. When you create a deployment of a virtual machine, you should make sure that the cloud service and the disk or image that you use are located in the same region. For example, if the cloud service was created in the West US region, the disk or image that you use should also be located in a storage account in the West US region. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157194.aspx for more information) The name of your service. Parameters supplied to the Begin Creating Virtual Machine Deployment operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Deleting Role operation deletes the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157184.aspx for more information) The name of your service. The name of your deployment. The name of the virtual machine to delete. Specifies that the source blob(s) for the virtual machine should also be deleted from storage. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Restarting role operation restarts the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157197.aspx for more information) The name of your service. The name of your deployment. The name of the virtual machine to restart. Cancellation token. A standard service response including an HTTP status code and request ID. The Shutdown Role operation shuts down the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157195.aspx for more information) The name of your service. The name of your deployment. The name of the virtual machine to shutdown. The parameters for the shutdown vm operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Shutting Down Roles operation stops the specified set of virtual machines. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469421.aspx for more information) The name of your service. The name of your deployment. Parameters to pass to the Begin Shutting Down Roles operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Starting Role operation starts the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157189.aspx for more information) The name of your service. The name of your deployment. The name of the virtual machine to start. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Starting Roles operation starts the specified set of virtual machines. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469419.aspx for more information) The name of your service. The name of your deployment. Parameters to pass to the Begin Starting Roles operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Updating Role operation adds a virtual machine to an existing deployment. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157187.aspx for more information) The name of your service. The name of your deployment. The name of your virtual machine. Parameters supplied to the Begin Updating Virtual Machine operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Updating Load Balanced Endpoint Set operation changes the specified load-balanced InputEndpoints on all the roles of an Infrastructure as a Service deployment. Non-load-balanced endpoints must be changed using UpdateRole. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469417.aspx for more information) The name of your service. The name of your deployment. Parameters supplied to the Begin Updating Load Balanced Endpoint Set operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Capture Role operation creates a copy of the operating system virtual hard disk (VHD) that is deployed in the virtual machine, saves the VHD copy in the same storage location as the operating system VHD, and registers the copy as an image in your image gallery. From the captured image, you can create additional customized virtual machines. For more information about images and disks, see Manage Disks and Images at http://msdn.microsoft.com/en-us/library/windowsazure/jj672979.aspx. For more information about capturing images, see How to Capture an Image of a Virtual Machine Running Windows Server 2008 R2 at http://www.windowsazure.com/en-us/documentation/articles/virtual-machines-capture-image-windows-server/ or How to Capture an Image of a Virtual Machine Running Linux at http://www.windowsazure.com/en-us/documentation/articles/virtual-machines-linux-capture-image/. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157201.aspx for more information) The name of your service. The name of your deployment. The name of the virtual machine to restart. Parameters supplied to the Capture Virtual Machine operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Capture role as VM template. The name of your service. The name of your deployment. The name of the virtual machine to restart. Parameters supplied to the Capture Virtual Machine operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Create Role operation adds a virtual machine to an existing deployment. You can refer to the OSDisk in the Add Role operation in the following ways: Platform/User Image - Set the SourceImageName to a platform or user image. You can optionally specify the DiskName and MediaLink values as part the operation to control the name and location of target disk. When DiskName and MediaLink are specified in this mode, they must not already exist in the system, otherwise a conflict fault is returned; UserDisk - Set DiskName to a user supplied image in image repository. SourceImageName must be set to NULL. All other properties are ignored; or Blob in a Storage Account - Set MediaLink to a blob containing the image. SourceImageName and DiskName are set to NULL. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157186.aspx for more information) The name of your service. The name of your deployment. Parameters supplied to the Create Virtual Machine operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Create Virtual Machine Deployment operation provisions a virtual machine based on the supplied configuration. When you create a deployment of a virtual machine, you should make sure that the cloud service and the disk or image that you use are located in the same region. For example, if the cloud service was created in the West US region, the disk or image that you use should also be located in a storage account in the West US region. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157194.aspx for more information) The name of your service. Parameters supplied to the Create Virtual Machine Deployment operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Role operation deletes the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157184.aspx for more information) The name of your service. The name of your deployment. The name of the virtual machine to delete. Specifies that the source blob(s) for the virtual machine should also be deleted from storage. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Get Role operation retrieves information about the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157193.aspx for more information) The name of your service. The name of your deployment. The name of the virtual machine. Cancellation token. The Get Virtual Machine operation response. The Download RDP file operation retrieves the Remote Desktop Protocol configuration file from the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157183.aspx for more information) The name of your service. The name of your deployment. The name of the virtual machine. Cancellation token. The Download RDP file operation response. The Restart role operation restarts the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157197.aspx for more information) The name of your service. The name of your deployment. The name of the virtual machine to restart. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Shutdown Role operation shuts down the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157195.aspx for more information) The name of your service. The name of your deployment. The name of the virtual machine to shutdown. The parameters for the shutdown virtual machine operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Shutdown Roles operation stops the specified set of virtual machines. The name of your service. The name of your deployment. Parameters to pass to the Shutdown Roles operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Start Role operation starts the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157189.aspx for more information) The name of your service. The name of your deployment. The name of the virtual machine to start. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Start Roles operation starts the specified set of virtual machines. The name of your service. The name of your deployment. Parameters to pass to the Start Roles operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Update Role operation adds a virtual machine to an existing deployment. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157187.aspx for more information) The name of your service. The name of your deployment. The name of your virtual machine. Parameters supplied to the Update Virtual Machine operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Update Load Balanced Endpoint Set operation changes the specified load-balanced InputEndpoints on all the roles of an Infrastructure as a Service deployment. Non-load-balanced endpoints must be changed using UpdateRole. The name of your service. The name of your deployment. Parameters supplied to the Update Load Balanced Endpoint Set operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Service Management API includes operations for managing the OS images in your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157175.aspx for more information) Share an already replicated OS image. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. The name of the virtual machine image to share. The sharing permission: public, msdn, or private. Cancellation token. A standard service response including an HTTP status code and request ID. Unreplicate an OS image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Note: The operation removes the published copies of the user OS Image. It does not remove the actual user OS Image. To remove the actual user OS Image, the publisher will have to call Delete OS Image. The name of the virtual machine image to replicate. Note: The OS Image Name should be the user OS Image, not the published name of the OS Image. Cancellation token. A standard service response including an HTTP status code and request ID. The Create OS Image operation adds an operating system image that is stored in a storage account and is available from the image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157192.aspx for more information) Parameters supplied to the Create Virtual Machine Image operation. Cancellation token. Parameters returned from the Create Virtual Machine Image operation. The Delete OS Image operation deletes the specified OS image from your image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157203.aspx for more information) The name of the image to delete. Specifies that the source blob for the image should also be deleted from storage. Cancellation token. A standard service response including an HTTP status code and request ID. The Get OS Image operation retrieves the details for an operating system image from the image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157191.aspx for more information) The name of the OS image to retrieve. Cancellation token. A virtual machine image associated with your subscription. Gets OS Image's properties and its replication details. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. The name of the virtual machine image to replicate. Cancellation token. The Get Details OS Images operation response. The List OS Images operation retrieves a list of the operating system images from the image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157191.aspx for more information) Cancellation token. The List OS Images operation response. Replicate an OS image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. The name of the virtual machine OS image to replicate. Parameters supplied to the Replicate Virtual Machine Image operation. Cancellation token. The response body contains the published name of the image. Share an already replicated OS image. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. The name of the virtual machine image to share. The sharing permission: public, msdn, or private. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Unreplicate an OS image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Note: The operation removes the published copies of the user OS Image. It does not remove the actual user OS Image. To remove the actual user OS Image, the publisher will have to call Delete OS Image. The name of the virtual machine image to replicate. Note: The OS Image Name should be the user OS Image, not the published name of the OS Image. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Update OS Image operation updates an OS image that in your image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157198.aspx for more information) The name of the virtual machine image to be updated. Parameters supplied to the Update Virtual Machine Image operation. Cancellation token. Parameters returned from the Create Virtual Machine Image operation. The Service Management API includes operations for managing the virtual machine templates in your subscription. The Begin Deleting Virtual Machine Image operation deletes the specified virtual machine image. The name of the virtual machine image to delete. Specifies that the source blob for the image should also be deleted from storage. Cancellation token. A standard service response including an HTTP status code and request ID. Share an already replicated VM image. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. The name of the virtual machine image to share. The sharing permission: public, msdn, or private. Cancellation token. A standard service response including an HTTP status code and request ID. Unreplicate an VM image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Note: The operation removes the published copies of the user VM Image. It does not remove the actual user VM Image. To remove the actual user VM Image, the publisher will have to call Delete VM Image. The name of the virtual machine image to replicate. Note: The VM Image Name should be the user VM Image, not the published name of the VM Image. Cancellation token. A standard service response including an HTTP status code and request ID. The Delete Virtual Machine Image operation deletes the specified virtual machine image. The name of the virtual machine image to delete. Specifies that the source blob for the image should also be deleted from storage. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Gets VMImage's properties and its replication details. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. The name of the virtual machine image to replicate. Cancellation token. The Get Details VM Images operation response. The List Virtual Machine Images operation retrieves a list of the virtual machine images. Cancellation token. The List VM Images operation response. Replicate an VM image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. The name of the virtual machine image to replicate. Parameters supplied to the Replicate Virtual Machine Image operation. Cancellation token. The response body contains the published name of the image. Share an already replicated VM image. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. The name of the virtual machine image to share. The sharing permission: public, msdn, or private. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Unreplicate an VM image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Note: The operation removes the published copies of the user VM Image. It does not remove the actual user VM Image. To remove the actual user VM Image, the publisher will have to call Delete VM Image. The name of the virtual machine image to replicate. Note: The VM Image Name should be the user VM Image, not the published name of the VM Image. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Update VM Image operation updates a VM image that in your image repository. The name of the virtual machine image to be updated. Parameters supplied to the Update Virtual Machine Image operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Compute Management API includes operations for managing the load balancers for your subscription. Initializes a new instance of the LoadBalancerOperations class. Reference to the service client. Add an internal load balancer to a an existing deployment. When used by an input endpoint, the internal load balancer will provide an additional private VIP that can be used for load balancing to the roles in this deployment. Required. The name of the service. Required. The name of the deployment. Required. Parameters supplied to the Create Load Balancer operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Delete an internal load balancer from the deployment. Required. The name of the service. Required. The name of the deployment. Required. The name of the load balancer. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Add an internal load balancer to a an existing deployment. When used by an input endpoint, the internal load balancer will provide an additional private VIP that can be used for load balancing to the roles in this deployment. Required. The name of the service. Required. The name of the deployment. Required. Parameters supplied to the Create Load Balancer operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Delete an internal load balancer from the deployment. Required. The name of the service. Required. The name of the deployment. Required. The name of the load balancer. Cancellation token. A standard service response including an HTTP status code and request ID. Gets a reference to the Microsoft.WindowsAzure.Management.Compute.ComputeManagementClient. The Service Management API provides programmatic access to much of the functionality available through the Management Portal. The Service Management API is a REST API. All API operations are performed over SSL, and are mutually authenticated using X.509 v3 certificates. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460799.aspx for more information) Add an internal load balancer to a an existing deployment. When used by an input endpoint, the internal load balancer will provide an additional private VIP that can be used for load balancing to the roles in this deployment. Reference to the Microsoft.WindowsAzure.Management.Compute.ILoadBalancerOperations. Required. The name of the service. Required. The name of the deployment. Required. Parameters supplied to the Create Load Balancer operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Add an internal load balancer to a an existing deployment. When used by an input endpoint, the internal load balancer will provide an additional private VIP that can be used for load balancing to the roles in this deployment. Reference to the Microsoft.WindowsAzure.Management.Compute.ILoadBalancerOperations. Required. The name of the service. Required. The name of the deployment. Required. Parameters supplied to the Create Load Balancer operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Delete an internal load balancer from the deployment. Reference to the Microsoft.WindowsAzure.Management.Compute.ILoadBalancerOperations. Required. The name of the service. Required. The name of the deployment. Required. The name of the load balancer. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Delete an internal load balancer from the deployment. Reference to the Microsoft.WindowsAzure.Management.Compute.ILoadBalancerOperations. Required. The name of the service. Required. The name of the deployment. Required. The name of the load balancer. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Add an internal load balancer to a an existing deployment. When used by an input endpoint, the internal load balancer will provide an additional private VIP that can be used for load balancing to the roles in this deployment. Reference to the Microsoft.WindowsAzure.Management.Compute.ILoadBalancerOperations. Required. The name of the service. Required. The name of the deployment. Required. Parameters supplied to the Create Load Balancer operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Add an internal load balancer to a an existing deployment. When used by an input endpoint, the internal load balancer will provide an additional private VIP that can be used for load balancing to the roles in this deployment. Reference to the Microsoft.WindowsAzure.Management.Compute.ILoadBalancerOperations. Required. The name of the service. Required. The name of the deployment. Required. Parameters supplied to the Create Load Balancer operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Delete an internal load balancer from the deployment. Reference to the Microsoft.WindowsAzure.Management.Compute.ILoadBalancerOperations. Required. The name of the service. Required. The name of the deployment. Required. The name of the load balancer. A standard service response including an HTTP status code and request ID. Delete an internal load balancer from the deployment. Reference to the Microsoft.WindowsAzure.Management.Compute.ILoadBalancerOperations. Required. The name of the service. Required. The name of the deployment. Required. The name of the load balancer. A standard service response including an HTTP status code and request ID. An access control rule for a public endpoint. Initializes a new instance of the AccessControlListRule class. Optional. The action allowed by this Access Control List Rule. Optional. The description for this Access Control List Rule. Optional. The order of application for this Access Control List Rule. Optional. The remote subnet that is granted access for this Access Control List Rule. The service certificate format. Azure supports the pfx and cer file formats. Algorithm that was used to hash a service certificate. The compute capabilities. Initializes a new instance of the ComputeCapabilities class. Optional. Role sizes support for IaaS deployments. Optional. Role sizes support for PaaS deployments. Objects that provide system or application data. Initializes a new instance of the ConfigurationSet class. Optional. Specifies the string representing the administrator password to use for the virtual machine. If the VM will be created from a 'Specialized' VM image, the password is not required. Optional. Specifies the name that is used to rename the default administrator account. If the VM will be created from a 'Specialized' VM image, the user name is not required. Optional. Specifies the computer name for the virtual machine. If the computer name is not specified, a name is created based on the name of the role. Computer names must be 1 to 15 characters in length. This element is only used with the WindowsProvisioningConfiguration set. Optional. Specifies the configuration type for the configuration set. Optional. Optional. Provides base64 encoded custom data to be passed to VM. Optional. Specifies whether or not SSH authentication is disabled for the password. This element is only used with the LinuxProvisioningConfiguration set. By default this value is set to true. Optional. Contains properties that specify a domain to which the virtual machine will be joined. This element is only used with the WindowsProvisioningConfiguration set. Optional. Specifies whether automatic updates are enabled for the virtual machine. This element is only used with the WindowsProvisioningConfiguration set. The default value is false. Optional. Specifies the host name for the VM. Host names are ASCII character strings 1 to 64 characters in length. This element is only used with the LinuxProvisioningConfiguration set. Optional. Contains a collection of external endpoints for the virtual machine. This element is only used with the NetworkConfigurationSet type. Optional. Optional. A set of public IPs. Currently, only one additional public IP per role is supported in an IaaS deployment. The IP address is in addition to the default VIP for the deployment. Optional. Specifies whether password should be reset the first time the administrator logs in. Optional. Specifies the SSH public keys and key pairs to populate in the image during provisioning. This element is only used with the LinuxProvisioningConfiguration set. Optional. Specifies a Customer Address, i.e. an IP address assigned to a VM in a VNet's SubNet. For example: 10.0.0.4. Optional. Contains a list of service certificates with which to provision to the new role. This element is only used with the WindowsProvisioningConfiguration set. Optional. The list of Virtual Network subnet names that the deployment belongs to. This element is only used with the NetworkConfigurationSet type. Optional. Specifies the time zone for the virtual machine. This element is only used with the WindowsProvisioningConfiguration set. For a complete list of supported time zone entries, you can refer to the values listed in the registry entry HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones on a computer running Windows 7, Windows Server 2008, and Windows Server 2008 R2 or you can use the tzutil command-line tool to list the valid time. The tzutil tool is installed by default on Windows 7, Windows Server 2008, and Windows Server 2008 R2. Optional. Specifies the name of a user to be created in the sudoer group of the virtual machine. User names are ASCII character strings 1 to 32 characters in length. This element is only used with the LinuxProvisioningConfiguration set. Optional. Specifies the password for user name. Passwords are ASCII character strings 6 to 72 characters in length. This element is only used with the LinuxProvisioningConfiguration set. Optional. Configures the Windows Remote Management service on the virtual machine, which enables remote Windows PowerShell. An additional public IP that will be created for the role. The public IP will be an additional IP for the role. The role continues to be addressable via the default deployment VIP. Initializes a new instance of the PublicIP class. Optional. The name of the public IP. Specifies the configuration type for the configuration set. The data disk configuration. Initializes a new instance of the DataDiskConfigurationUpdateParameters class. Optional. Optional. Host caching option for a data disk within the VM Image. 'ReadOnly', 'ReadWrite', or 'None'.If this parameter is specified you must also specify the Name for the DataDiskConfiguration you want to change. Optional. Optional. LUN for the data disk. LUNs must not conflict with other Data Disks in the VM Image. If this parameter is specified you must also specify the Name for the DataDiskConfiguration you want to change. Optional. Optional if not changing any data disk configurations. Name of an existing DataDiskConfiguration. The name cannot be changed, this is just to identify the disk for changing other properties. Objects that are used to create a data disk for a virtual machine. Initializes a new instance of the DataVirtualHardDisk class. Optional. Specifies the platform caching behavior of the data disk blob for read/write efficiency. The default value is ReadOnly. Optional. Specifies the friendly name of the VHD used to create the data disk for the virtual machine. Optional. Specifies the size, in GB, of an empty VHD to be attached to the virtual machine. The VHD can be created as part of an attached disk or created as a virtual machine call by specifying the value for this property. Azure creates the empty VHD based on the size preference and attaches the newly created VHD to the virtual machine. Optional. Specifies the Logical Unit Number (LUN) for the data disk. The LUN specifies the slot in which the data drive appears when mounted for usage by the virtual machine. This element is only listed when more than one data disk is attached to a virtual machine. Optional. Optional. If the disk that is being added is already registered in the subscription or the VHD for the disk already exists in blob storage, this element is ignored. If a VHD file does not exist in blob storage, this element defines the location of the new VHD that is created when the new disk is added.Example: http://example.blob.core.windows.net/disks/mydatadisk.vhd Optional. Specifies the name of the VHD used to create the data disk for the virtual machine. Optional. Optional. If the disk that is being added is already registered in the subscription or the VHD for the disk does not exist in blob storage, this element is ignored. If the VHD file exists in blob storage, this element defines the path to the VHD and a disk is registered from it and attached to the virtual machine. Parameters supplied to the Change Configuration Deployment operation. Initializes a new instance of the DeploymentChangeConfigurationParameters class. Required. The encoded service configuration file for the deployment. Optional. Represents the name of an extended deployment property. Each extended property must have a defined name and a value. You can have a maximum of 25 extended property name/value pairs. The maximum length of the name element is 64 characters, only alphanumeric characters and underscores are valid in the name, and the name must start with a letter. Attempting to use other characters, starting the name with a non-letter character, or entering a name that is identical to that of another extended property owned by the same hosted service will result in a status code 400 (Bad Request) error. Optional. Represents an extension that is added to the cloud service. In Azure, a process can run as an extension of a cloud service. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as extensions to the cloud service. You must add an extension to the cloud service by using Add Extension before it can be added to the deployment. Optional. The Change Configuration Deployment mode. Possible values are: Auto and Manual. If not specified, the default value is Auto. If set to Manual, WalkUpgradeDomain must be called to apply the update. If set to Auto, the update is automatically applied to each update domain for the service. Optional. Indicates whether to treat package validation warnings as errors. The default value is false. If set to true, the Created Deployment operation fails if there are validation warnings on the service package. Parameters supplied to the Create Deployment operation. Initializes a new instance of the DeploymentCreateParameters class. Required. The service configuration file for the deployment. Optional. Represents the name of an extended deployment property. Each extended property must have a defined name and a value. You can have a maximum of 25 extended property name/value pairs. The maximum length of the name element is 64 characters, only alphanumeric characters and underscores are valid in the name, and the name must start with a letter. Attempting to use other characters, starting the name with a non-letter character, or entering a name that is identical to that of another extended property owned by the same hosted service will result in a status code 400 (Bad Request) error. Optional. Represents an extension that is added to the cloud service. In Azure, a process can run as an extension of a cloud service. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as extensions to the cloud service. You must add an extension to the cloud service by using Add Extension before it can be added to the deployment. Required. A name for the hosted service. The name can be up to 100 characters in length. It is recommended that the label be unique within the subscription. The name can be used identify the hosted service for your tracking purposes. Required. The name for the deployment. The deployment name must be unique among other deployments for the cloud service. Required. A URL that refers to the location of the service package in the Blob service. The service package can be located either in a storage account beneath the same subscription or a Shared Access Signature (SAS) URI from any storage account. For more info about Shared Access Signatures, see Delegating Access with a Shared Access Signature (REST API) at http://msdn.microsoft.com/en-us/library/windowsazure/ee395415.aspx. Optional. Indicates whether to start the deployment immediately after it is created. The default value is false. If false, the service model is still deployed to the virtual machines but the code is not run immediately. Instead, the service is Suspended until you call Update Deployment Status and set the status toRunning, at which time the service will be started. A deployed service still incurs charges, even if it is suspended. Optional. Indicates whether to treat package validation warnings as errors. The default value is false. If set to true, the Created Deployment operation fails if there are validation warnings on the service package. Parameters supplied to the delete role instance by deployment name operation. Initializes a new instance of the DeploymentDeleteRoleInstanceParameters class. Optional. Parameters supplied to the Get Package operation. Initializes a new instance of the DeploymentGetPackageParameters class. Required. Specifies the URI of the container to which the packages will be saved. Optional. Specifies whether an existing package in the storage container should be overwritten. A deployment that exists in the cloud service. Initializes a new instance of the DeploymentGetResponse class. Optional. The configuration file of the deployment. Optional. The time that the deployment was created. Optional. The deployment environment in which this deployment is running. Optional. The custom DNS settings that are specified for deployment. Optional. Represents the name of an extended cloud service property. Each extended property must have a defined name and a value. You can have a maximum of 50 extended property name and value pairs. The maximum length of the name element is 64 characters, only alphanumeric characters and underscores are valid in the name, and it must start with a letter. Attempting to use other characters, starting with a non-letter character, or entering a name that is identical to that of another extended property owned by the same service will result in a status code 400 (Bad Request) error. Each extended property value has a maximum length of 255 characters. Optional. Represents an extension that is added to the cloud service. Optional. The user-supplied name of the deployment. This name can be used identify the deployment for tracking purposes. Optional. The last time that the deployment was modified. Optional. Optional. A list of internal load balancers that each provide load balancing on a private VIP. It's created when a name is assigned in the list here. Optional. Indicates whether the deployment is locked for new write operations because an existing operation is updating the deployment. Optional. Optional. Specifies information about when the virtual machine has been started and stopped. Optional. The unique identifier for this deployment. Optional. The name of the Reserved IP that the deployment belongs to. Optional. The list of role instances in the deployment. Optional. The list of roles in the deployment. Optional. Indicates whether the Rollback Update Or Upgrade operation is allowed at this time. Optional. The version of the Azure SDK that was used to generate the .cspkg that created this deployment. The first two numerical components of the returned version represent the version of the SDK used to create the package. Optional. The status of the deployment. Optional. The number of upgrade domains available to this cloud service. Optional. Information about an update occurring on the deployment. Optional. The URL used to access the hosted service. For example, if the service name is MyService you could access the access the service by calling: http://MyService.cloudapp.net. Optional. The virtual IP addresses that are specified for the deployment. Optional. The name of the Virtual Network that the virtual machine connects to. Parameters supplied to the Rollback Update Or Upgrade operation. Initializes a new instance of the DeploymentRollbackUpdateOrUpgradeParameters class. Optional. Specifies whether the rollback should proceed even when it will cause local data to be lost from some role instances. True if the rollback should proceed; otherwise false. Required. Specifies whether the rollback should proceed automatically. The deployment environment in which this deployment is running. The status of the deployment. Parameters supplied to the Swap Deployment operation. Initializes a new instance of the DeploymentSwapParameters class. Optional. The optional name of the production deployment. Required. The name of the source deployment. Parameters supplied to the Update Deployment Status operation. Initializes a new instance of the DeploymentUpdateStatusParameters class. Required. The new status of the deployment. Parameters supplied to the Upgrade Deployment operation. Initializes a new instance of the DeploymentUpgradeParameters class. Required. The service configuration file for the deployment. Optional. Represents the name of an extended deployment property. Each extended property must have a defined name and a value. You can have a maximum of 25 extended property name/value pairs. The maximum length of the name element is 64 characters, only alphanumeric characters and underscores are valid in the name, and the name must start with a letter. Attempting to use other characters, starting the name with a non-letter character, or entering a name that is identical to that of another extended property owned by the same hosted service will result in a status code 400 (Bad Request) error. Optional. Represents an extension that is added to the cloud service. In Azure, a process can run as an extension of a cloud service. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as extensions to the cloud service. You must add an extension to the cloud service by using Add Extension before it can be added to the deployment. Required. Specifies whether the rollback should proceed even when it will cause local data to be lost from some role instances. Required. A name for the hosted service. The name can be up to 100 characters in length. It is recommended that the label be unique within the subscription. The name can be used identify the hosted service for your tracking purposes. Required. The type of update to initiate. Role instances are allocated to update domains when the service is deployed. Updates can be initiated manually in each update domain or initiated automatically in all update domains. Possible values are Auto or Manual. If not specified, the default value is Auto. If set to Manual, WalkUpgradeDomain must be called to apply the update. If set to Auto, the update is automatically applied to each update domain in sequence. Required. A URL that refers to the location of the service package in the Blob service. The service package can be located either in a storage account beneath the same subscription or a Shared Access Signature (SAS) URI from any storage account. For more information about Shared Access Signatures, see Delegating Access with a Shared Access Signature (REST API) at http://msdn.microsoft.com/en-us/library/windowsazure/ee395415.aspx. Optional. The name of the specific role instance to update. The type of the upgrade. Parameters supplied to the Walk Upgrade Domain operation. Initializes a new instance of the DeploymentWalkUpgradeDomainParameters class. Required. An integer value that identifies the update domain to update. Update domains are identified with a zero-based index: the first update domain has an ID of 0, the second has an ID of 1, and so on. Information about a DNS Server in the virtual network. Initializes a new instance of the DnsServer class. Optional. The DNS server address. Optional. The name of the DNS server. The custom DNS settings that are specified for the deployment. Initializes a new instance of the DnsSettings class. Optional. Contains a collection of objects that define the DNS server settings. Specifies the values to use to join the virtual machine to the domain. Initializes a new instance of the DomainJoinCredentials class. Optional. Specifies the name of the domain used to authenticate an account. The value is a fully qualified DNS domain. If the domains name is not specified, Username must specify the user principal name (UPN) format (user@fully-qualified-DNS-domain) or the fully-qualified-DNS-domain\\username format. Example: example.com. Required. Specifies the password to use to join the domain. Required. Specifies a user name in the domain that can be used to join the domain. The configuration needed to provision the machine in the domain. Initializes a new instance of the DomainJoinProvisioning class. Optional. The account info for joining the domain. Contains properties that specify a domain to which the virtual machine will be joined. This element is only used with the WindowsProvisioningConfiguration set. Initializes a new instance of the DomainJoinSettings class. Optional. Specifies the values to use to join the virtual machine to the domain. Optional. Specifies the domain to join. Optional. Specifies the Lightweight Directory Access Protocol (LDAP) X 500-distinguished name of the organizational unit (OU) in which the computer account is created. This account is in Active Directory on a domain controller in the domain to which the computer is being joined. Example: OU=MyOu,OU=MyParentOu,DC=example.com,DC=MyCompany,DC=com. Optional. Additional information for domain join provisioning. The set of access control rules for the endpoint. Initializes a new instance of the EndpointAcl class. Optional. The set of access control rules for the endpoint. Represents an extension that is added to the cloud service. Initializes a new instance of the ExtensionConfiguration class. Optional. Specifies a list of extensions that are applied to all roles in a deployment. Optional. Specifies a list of extensions that are applied to specific roles in a deployment. Represents an extension that is to be deployed to a role in a cloud service. Initializes a new instance of the Extension class. Required. The identifier of the extension. The identifier is created when the extension is added to the cloud service. You can find the ID of an extension that was added to a cloud service by using List Extensions. Specifies a list of extensions that are applied to specific roles in a deployment. Initializes a new instance of the NamedRole class. Required. Represents an extension that is to be deployed to a role in a cloud service. Required. Specifies the name of the role. The configuration for the virtual IP address (VIP) this load balancer provides. Initializes a new instance of the FrontendIPConfiguration class. Optional. If the deployment exists inside a virtual network, a specific address from the load balancer subnet can be specified. The VIP for the load balancer will then be this specific IP address. If a static virtual network IP address is provided, the SubnetName element of the load balancer must be specified as well. If the deployment exists outside of a virtual network, no static virtual network IP address can be specified. Optional. If the deployment exists inside a virtual network, a subnet of that virtual network must be specified for the load balancer. The VIP managed by the load balancer will then be an IP address out of this subnet. If the deployment exists outside of a virtual network, no subnet can be specified and the private VIP will be an IP address from the general private address pool. Optional. The type of the VIP provided by this load balancer. Currently, only 'Private' is supported. This will create load balancing services on a private VIP. The type of the VIP provided by this load balancer. Currently, only 'Private' is supported. This will create load balancing services on a private VIP. This object encapsulates a localized status message from the Guest Agent. Initializes a new instance of the GuestAgentFormattedMessage class. Optional. Language code. Eg. "en-US". Optional. A string containing a message about the status of the Guest Agent or Resource Extension. The guest agent message. Initializes a new instance of the GuestAgentMessage class. Optional. The message resource ID. Optional. The guest agent message parameter list. Optional. This object contains status information of the Guest Agent installed on a RoleInstance. Guest Agent can be installed on a role instance by setting "ProvisionGuestAgent" to true in Create Deployment or Add Role API calls. Version header: Required to be "2014-04-01" or later. Initializes a new instance of the GuestAgentStatus class. Optional. Integer. Status code from the result of applying the GA settings. Optional. This object encapsulates a formatted localized status message from the Guest Agent. Optional. Version of the Guest Agent installed on the role instance. Optional. This object encapsulates a localized status message from the Guest Agent. Optional. Protocol version used by the Guest Agent for status reporting. Optional. The guest agent status, which can be: "Ready" or "NotReady". Optional. UTC time at which the status was reported. The guest agent status, which can be: "Ready" or "NotReady". Parameters supplied to the Add Extension operation. Initializes a new instance of the HostedServiceAddExtensionParameters class. Required. The identifier of the extension. Optional. The private configuration that is defined using the schema returned by the List Available Extensions operation. Optional. The provider namespace of the extension. The provider namespace for Azure extensions is Microsoft.Windows.Azure.Extensions. Optional. The public configuration that is defined using the schema returned by the List Available Extensions operation. Optional. The thumbprint of the certificate that is used to encrypt the configuration specified in PrivateConfiguration. If this element is not specified, a certificate may be automatically generated and added to the cloud service. Optional. The thumbprint algorithm of the certificate that is used to encrypt the configuration specified in PrivateConfiguration. Required. The type of the extension. Optional. Specifies the version of the extension. If this element is not specified or an asterisk (*) is used as the value, the latest version of the extension is used. If the value is specified with a major version number and an asterisk as the minor version number (X.*), the latest minor version of the specified major version is selected. If a major version number and a minor version number are specified (X.Y), the specific extension version is selected. If a version is specified, an auto-upgrade is performed on the role instance. The Check Hosted Service Name Availability operation response. Initializes a new instance of the HostedServiceCheckNameAvailabilityResponse class. Optional. Indicates whether the name is available for you to use. The operation returns false for reserved or profane words. Optional. Describes why the name cannot be used to create the cloud service. Parameters supplied to the Create Hosted Service operation. Initializes a new instance of the HostedServiceCreateParameters class. Optional. The name of an existing affinity group associated with this subscription. Required if Location is not specified. This name is a GUID and can be retrieved by examining the name element of the response body returned by the List Affinity Groups operation. Specify either Location or AffinityGroup, but not both. To list available affinity groups, use the List Affinity Groups operation. Optional. A description for the cloud service. The description can be up to 1024 characters in length. Optional. Represents the name of an extended cloud service property. Each extended property must have a defined name and a value. You can have a maximum of 50 extended property name and value pairs. The maximum length of the name element is 64 characters, only alphanumeric characters and underscores are valid in the name, and it must start with a letter. Attempting to use other characters, starting with a non-letter character, or entering a name that is identical to that of another extended property owned by the same service will result in a status code 400 (Bad Request) error. Each extended property value has a maximum length of 255 characters. Required. A name for the cloud service. The name can be up to 100 characters in length. The name can be used to identify the storage account for your tracking purposes. Optional. The location where the cloud service will be created. Required if AffinityGroup is not specified. Specify either Location or AffinityGroup, but not both. To list available locations, use the List Locations operation. Required. A name for the cloud service that is unique within Azure. This name is the DNS prefix name and can be used to access the service. The detailed Get Hosted Service operation response. The Get Hosted Service operation response. Initializes a new instance of the HostedServiceGetResponse class. Optional. The compute capabilities in this hosted service. Optional. The properties that are assigned to the cloud service. Optional. The name of the cloud service. This name is the DNS prefix name and can be used to access the cloud service. For example, if the cloud service name is MyService you could access the access the cloud service by calling: http://MyService.cloudapp.net. Optional. The Service Management API request URI used to perform Get Hosted Service Properties requests against the cloud service. Initializes a new instance of the HostedServiceGetDetailedResponse class. Optional. The deployments that exist in the cloud service. A deployment that exists in the cloud service. Initializes a new instance of the Deployment class. Optional. The configuration file of the deployment. Optional. The time that the deployment was created. Optional. The deployment environment in which this deployment is running. Optional. The custom DNS settings that are specified for the deployment. Optional. Represents the name of an extended cloud service property. Each extended property must have a defined name and a value. You can have a maximum of 50 extended property name and value pairs. The maximum length of the name element is 64 characters, only alphanumeric characters and underscores are valid in the name, and it must start with a letter. Attempting to use other characters, starting with a non-letter character, or entering a name that is identical to that of another extended property owned by the same service will result in a status code 400 (Bad Request) error. Each extended property value has a maximum length of 255 characters. Optional. The user-supplied name of the deployment. This name can be used identify the deployment for your tracking purposes. Optional. The last time that the deployment was modified. Optional. Indicates whether the deployment is locked for new write operations because an existing operation is updating the deployment. Optional. The name of the deployment. Optional. Specifies information about when the virtual machine has been started and stopped. Optional. The unique identifier for this deployment. Optional. The list of role instances in the deployment. Optional. The list of roles in the deployment. Optional. Indicates whether the Rollback Update Or Upgrade operation is allowed at this time. Optional. The version of the Azure SDK that was used to generate the .cspkg that created this deployment. The first two numerical components of the returned version represent the version of the SDK used to create the package. Optional. The status of the deployment. Optional. The number of upgrade domains available to this cloud service. Optional. Specifies information about an update occurring on the deployment. Optional. The URL used to access the hosted service. For example, if the service name is MyService you could access the access the service by calling: http://MyService.cloudapp.net. Optional. The virtual IP addresses that are specified for thedeployment. Optional. The name of the Virtual Network that the virtual machine connects to. The Get Extension operation response. Initializes a new instance of the HostedServiceGetExtensionResponse class. Optional. The identifier of the extension. Optional. The provider namespace of the extension. The provider namespace for Azure extensions is Microsoft.Windows.Azure.Extensions. Optional. The public configuration that is defined using the schema returned by the List Available Extensions operation. Optional. The thumbprint of the certificate that is used to encrypt the configuration specified in PrivateConfiguration. If this element is not specified, a certificate may be automatically generated and added to the cloud service. Optional. The thumbprint algorithm of the certificate that is used toencrypt the configuration specified in PrivateConfiguration. Required. The type of the extension. Optional. The version of the extension. The List Available Extensions operation response. Initializes a new instance of the HostedServiceListAvailableExtensionsResponse class. Gets the sequence of ExtensionImages. Gets the sequence of ExtensionImages. Optional. The extensions that are available to add to your cloud service. An extension available to add to your cloud service. Initializes a new instance of the ExtensionImage class. Optional. Indicates whether this version of extension blocks the role upon failure. Optional. The description of the extension. Optional. URI string pointing to the EULA (End User License Agreement) of this version of extension. This is optionally specified by the third-party publishing the extension instead of Azure, at the time of extension creation or update. Optional. URI string pointing to the homepage of this version of extension. This is optionally specified by the third-party publishing the extension instead of Azure, at the time of extension creation or update. Optional. The type of resource that supports the extension. This value can be WebRole, WorkerRole, or WebRole|WorkerRole. Optional. Boolean property indicating whether the extension accepts JSON or XML based configuration. If this property is 'true' then the extension accepts JSON based configuration. If this property is 'false' the extension accepts XML based configuration. Optional. The label that is used to identify the extension. Optional. URI string pointing to the privacy document of this version of extension. This is optionally specified by the third-party publishing the extension instead of Azure, at the time of extension creation or update. Optional. The schema of the private configuration. Optional. The provider namespace of the extension. The provider namespace for Azure extensions is Microsoft.Windows.Azure.Extensions. Optional. The schema of the public configuration. Optional. Indicates whether this version of extension has been replicated to all regions or not. If true, then the given extension version can be used in creating or updating deployments. Otherwise, the given extension version might cause failure in creating or updating deployments. The typical time is 20 minutes for a newly-registered or newly-updated extension to replicate completely by Azure. Optional. A sample configuration file for the resource extension. Optional. The thumbprint algorithm of the certificate that is used for encryption. Required. The type of the extension. Optional. The version of the extension. The List Extensions operation response. Initializes a new instance of the HostedServiceListExtensionsResponse class. Gets the sequence of Extensions. Gets the sequence of Extensions. Optional. The extensions that were added to a cloud service. An extension that was added to a cloud service. Initializes a new instance of the Extension class. Optional. The identifier of the extension. Optional. The provider namespace of the extension. The provider namespace for Azure extensions is Microsoft.Windows.Azure.Extensions. Optional. The public configuration that is defined using the schema returned by the List Extensions operation. Optional. The thumbprint of the certificate that is used to encrypt the configuration specified in PrivateConfiguration. If this element is not specified, a certificate may be automatically generated and added to the cloud service. Optional. The thumbprint algorithm of the certificate that is used to encrypt the configuration specified in PrivateConfiguration. Required. The type of the extension. Optional. The version of the extension. The List Hosted Service operation response. Initializes a new instance of the HostedServiceListResponse class. Gets the sequence of HostedServices. Gets the sequence of HostedServices. Optional. The hosted services associated with your subscription. A hosted service associated with your subscription. Initializes a new instance of the HostedService class. Optional. The compute capabilities in this hosted service. Optional. The properties that are assigned to the cloud service. Optional. The name of the cloud service. This name is the DNS prefix name and can be used to access the cloud service. For example, if the cloud service name is MyService you could access the cloud service by calling: http://MyService.cloudapp.net. Optional. The Service Management API request URI used to perform List Hosted Service Properties requests against the cloud service. The properties that are assigned to the cloud service. Initializes a new instance of the HostedServiceProperties class. Optional. The affinity group with which this cloud service is associated, if any. If the service is associated with an affinity group, the Location element is not returned. Optional. The date that the cloud service was created, in [4DigitYear]-[2DigitMonth]-[2DigitDay]T[2DigitHour]:[2DigitMinute]:[2DigitSecond]Z format. The date 2011-05-11T16:15:26Z is an example that could be returned by the DateCreated or DateLastModified elements. Optional. The date that the cloud service was last updated, in [4DigitYear]-[2DigitMonth]-[2DigitDay]T[2DigitHour]:[2DigitMinute]:[2DigitSecond]Z format. The date 2011-05-11T16:15:26Z is an example that could be returned by the DateCreated or DateLastModified elements. Optional. The description for the cloud service. Optional. Represents the name of an extended cloud service property. Each extended property must have a defined name and a value. You can have a maximum of 50 extended property name and value pairs. The maximum length of the name element is 64 characters, only alphanumeric characters and underscores are valid in the name, and it must start with a letter. Attempting to use other characters, starting with a non-letter character, or entering a name that is identical to that of another extended property owned by the same service will result in a status code 400 (Bad Request) error. Each extended property value has a maximum length of 255 characters. Optional. The user-supplied name of the cloud service. This name can be used identify the service for your tracking purposes. Optional. The geo-location of the cloud service in Windows Azure, if the service is not associated with an affinity group. If a location has been specified, the AffinityGroup element is not returned. Optional. The status of the cloud service. The status of the cloud service. Parameters supplied to the Update Hosted Service operation. Initializes a new instance of the HostedServiceUpdateParameters class. Optional. A description for the cloud service. The description may be up to 1024 characters in length. You must specify a value for at least one of Label or Description. Optional. Represents the name of an extended cloud service property. Each extended property must have a defined name and a value. You can have a maximum of 50 extended property name and value pairs. The maximum length of the name element is 64 characters, only alphanumeric characters and underscores are valid in the name, and it must start with a letter. Attempting to use other characters, starting with a non-letter character, or entering a name that is identical to that of another extended property owned by the same service will result in a status code 400 (Bad Request) error. Each extended property value has a maximum length of 255 characters. Optional. A name for the cloud service. The name may be up to 100 characters in length. You must specify a value for at least one of Label or Description. It is recommended that the label be unique within the subscription. The name can be used identify the service for your tracking purposes. Objects that provide input endpoint details. Initializes a new instance of the InputEndpoint class. Optional. Specifies whether direct server return is enabled for the endpoint. Optional. Specifies the list of access control rules for the endpoint. Optional. Specifies a name for a set of load-balanced endpoints. Specifying this name in multiple endpoints adds them all to the set. This element is only listed for Virtual Machine deployments. Optional. Optional. Specify the name of an internal load balancer if this endpoint shall not be exposed on the default load balancer. Optional. Contains properties that specify the endpoint settings which the Azure load balancer uses to monitor the availability of this virtual machine before forwarding traffic to the endpoint. Optional. Specifies the internal port on which the virtual machine is listening to serve the endpoint. This element is only listed for Virtual Machine deployments. Optional. Specifies the name for the external endpoint. This element is only listed for Virtual Machine deployments. Optional. The size of the role instance. Optional. Specifies the transport protocol for the endpoint. Optional. The virtual IP address of the role instance. Specifies the transport protocol for an endpoint. Objects that provide instance endpoint details. Initializes a new instance of the InstanceEndpoint class. Optional. Specifies the internal port on which the virtual machine is listening to serve the endpoint. This element is only listed for Virtual Machine deployments. Optional. Specifies the name for the external endpoint. This element is only listed for Virtual Machine deployments. Optional. The external port of the role instance endpoint. Optional. Specifies the transport protocol for the endpoint. Optional. The Virtual IP of the role endpoint. A list of internal load balancers that each provide load balancing on a private VIP. Initializes a new instance of the LoadBalancer class. Optional. The configuration for the virtual IP address (VIP) this load balancer provides. Optional. The name of the load balancer. Parameters supplied to the Create Load Balancer operation. Initializes a new instance of the LoadBalancerCreateParameters class. Optional. The configuration for the virtual IP address (VIP) this load balancer provides. Optional. Name of the load balancer. Contains properties that specify the endpoint settings which the Azure load balancer uses to monitor the availability of this virtual machine before forwarding traffic to the endpoint. Initializes a new instance of the LoadBalancerProbe class. Optional. Specifies the interval for the load balancer probe in seconds. The minimum value is 5 seconds. If not specified, the default is 15 seconds. Optional. Specifies the relative path name to inspect to determine the virtual machine availability status. If Protocol is set to TCP, this value must be NULL. Optional. Specifies the port to use to inspect the virtual machine availability status. Optional. Specifies the protocol to use to inspect the virtual machine availability status. Optional. Specifies the timeout for the load balancer probe in seconds. The minimum value is 11 seconds. If not specified, the default is 31 seconds. Specifies the protocol to use when inspecting the virtual machine availability status. Describes an operating system family. The List Operating System Families operation response. Initializes a new instance of the OperatingSystemListFamiliesResponse class. Gets the sequence of OperatingSystemFamilies. Gets the sequence of OperatingSystemFamilies. Optional. The operating system families that are valid for your subscription. An operating system that is valid for your subscription. Initializes a new instance of the OperatingSystem class. Optional. Indicates whether this operating system version is currently active for running a service. If an operating system version is active, you can manually configure your service to run on that version. An operating system version may be inactive for one of two reasons: 1. It is not yet active as it is in the process of being rolled out to Azure data centers. If your service is configured to use auto-upgrade, it will be upgraded to the new operating system version during the rollout. If you are manually configuring your operating system version, you can upgrade to the latest version once it becomes active. 2. It is no longer supported for running a service. In this case you will either need to manually configure your service to run on a newer version, or configure your service to use auto-upgrade to manage operating system upgrades. Optional. Indicates whether this operating system version is the default version for a service that has not otherwise specified a particular version. The default operating system version is applied to services that are configured for auto-upgrade. An operating system family has exactly one default operating system version at any given time, for which the IsDefault element is set to true; for all other versions, IsDefault is set to false. Optional. The label of the operating system version. Optional. The operating system version. This value corresponds to the configuration value for specifying that your service is to run on a particular version of the Azure guest operating system. See Configuring Settings for the Windows Azure Guest OS for additional details. An operating system family that is valid for your subscription. Initializes a new instance of the OperatingSystemFamily class. Optional. The label of the operating system family. Optional. Indicates which operating system family this version belongs to. A value of 1 corresponds to the Azure guest operating system that is substantially compatible with Windows Server 2008 SP2. A value of 2 corresponds to the Azure guest operating system that is substantially compatible with Windows Server 2008 R2. Optional. The available operating systems in your subscription belonging to this family. The List Operating Systems operation response. Initializes a new instance of the OperatingSystemListResponse class. Gets the sequence of OperatingSystems. Gets the sequence of OperatingSystems. Optional. The operating systems that are valid for your subscription. An operating system that is valid for your subscription. Initializes a new instance of the OperatingSystem class. Optional. Indicates which operating system family this version belongs to. A value of 1 corresponds to the Azure guest operating system that is substantially compatible with Windows Server 2008 SP2. A value of 2 corresponds to the Azure guest operating system that is substantially compatible with Windows Server 2008 R2. Optional. The label of the operating system family. Optional. Indicates whether this operating system version is currently active for running a service. If an operating system version is active, you can manually configure your service to run on that version. An operating system version may be inactive for one of two reasons: 1. It is not yet active as it is in the process of being rolled out to Azure data centers. If your service is configured to use auto-upgrade, it will be upgraded to the new operating system version during the rollout. If you are manually configuring your operating system version, you can upgrade to the latest version once it becomes active. 2. It is no longer supported for running a service. In this case you will either need to manually configure your service to run on a newer version, or configure your service to use auto-upgrade to manage operating system upgrades. Optional. Indicates whether this operating system version is the default version for a service that has not otherwise specified a particular version. The default operating system version is applied to services that are configured for auto-upgrade. An operating system family has exactly one default operating system version at any given time, for which the IsDefault element is set to true; for all other versions, IsDefault is set to false. Optional. The label of the operating system version. Optional. The operating system version. This value corresponds to the configuration value for specifying that your service is to run on a particular version of the Azure guest operating system. See Configuring Settings for the Windows Azure Guest OS for additional details. The OS disk configuration. Initializes a new instance of the OSDiskConfigurationUpdateParameters class. Optional. Specifies the platform caching behavior of the operating system disk blob for read/write efficiency. The parameters Azure uses to create the operating system disk for the virtual machine. Initializes a new instance of the OSVirtualHardDisk class. Optional. Specifies the platform caching behavior of the operating system disk blob for read/write efficiency. Optional. Specifies the friendly name of an operating system image in the image repository. Optional. Specifies the location of the operating system disk in Azure storage. Optional. Specifies the name of an operating system image in the image repository. Optional. The operating system running in the virtual machine. Optional. Specifies the name of the source image that was used to provision the virtual machine. Contains information about when the virtual machine has been started and stopped. Initializes a new instance of the PersistentVMDowntime class. Optional. The time that the virtual machine was stopped. Optional. The time that the virtual machine was started. Optional. The status of the virtual machine. Specifies the action that is performed after the capture operation finishes. Causes the virtual machine to be deleted after the image has been captured Causes the virtual machine to be redeployed after the image is captured by using the specified information in ProvisioningConfiguration. The status information of the settings passed to the Resource Extension. Initializes a new instance of the ResourceExtensionConfigurationStatus class. Optional. Integer status code from the result of applying the configuration settings. Optional. UTC time at which the configuration was applied. Optional. This object encapsulates a formatted localized status message. Optional. This object encapsulates a localized status message. Optional. Name of the settings passed to the Resource Extension. Optional. Operation executed by the Resource Extension for the settings passed to it. Optional. The status of the resourse extension, containing values like Transitioning, Error, Success, or Warning. Optional. List of substatus objects which contain additional status information reported by the Resource Extension. Optional. UTC time at which the status was reported. The status of the resource extension configuration, containing values like Transitioning, Error, Success, or Warning. Specifies the key, value, and type of the parameter. Initializes a new instance of the ResourceExtensionParameterValue class. Optional. The key of the parameter. Optional. Optional. Public | Private. If this value is set to Private, the parameter will not be returned by Get Deployment. You can only specify one public parameter and one private parameter for a maximum of two parameters. Optional. The value of the parameter. Specifies the properties of a resource extension that should be installed on the Virtual Machine. Initializes a new instance of the ResourceExtensionReference class. Optional. Specifies the name of the resource extension. You can use List Resource Extensions to find the names of available resource extensions. Optional. Specifies the name of the publisher who created the resource extension. You can use List Resource Extensions to find the publisher name of a resource extension. Optional. Specifies the reference name of the resource extension. Optional. Contains a collection of parameters that are passed to the resource extension when it is installed. Optional. Specifies the state of the resource extension.Possible values are: Enable | Disable. The default value is Enable. Optional. Specifies the version of the resource extension. You can use List Resource Extension Versions to find the version of the resource extension. Optional. The status information of a specific Resource Extension. Initializes a new instance of the ResourceExtensionStatus class. Optional. Status code sent by the Resource Extension. Optional. This object encapsulates the extension setting status for the Resource Extension. Optional. This object encapsulates a formatted localized status message from the Resource Extension. Optional. Name of the Resource Extension. Optional. This object encapsulates a localized status message from the Guest Agent. Optional. The resource extension status, which can be "Installing", "Ready", "NotReady", or "Unresponsive". Optional. Version of the Resource Extension. The resource extension status, which can be "Installing", "Ready", "NotReady", or "Unresponsive". A substatus object containing additional status information reported by the Resource Extension. Initializes a new instance of the ResourceExtensionSubStatus class. Optional. Integer status code from the result of applying the substatus settings. Optional. This object encapsulates a formatted localized status message. Optional. This object encapsulates a localized status message. Optional. A name for the substatus. Optional. The resource extension substatus, containing values like Transitioning, Error, Success, or Warning. The resource extension substatus, containing values like Transitioning, Error, Success, or Warning. Details of a role in a deployment. Initializes a new instance of the Role class. Optional. The name of the role. Optional. A collection of values that represents system or application configuration settings. Optional. Contains the parameters Azure uses to create a data disk for a virtual machine. Optional. The read-only thumbprint of the certificate that is used with the HTTPS listener for WinRM. Optional. The friendly name for the role. Optional. Storage location where the VM Image VHDs should be copied, for published VM Images. Optional. The version of the operating system on which the role instances are running. Optional. Contains the parameters Azure uses to create the operating system disk for the virtual machine. Optional. Indicates whether the WindowsAzureGuestAgent service is installed on the Virtual Machine. To run a resource extension in a Virtual Machine, this service must be installed. Optional. Contains a collection of resource extensions that are to be installed on the Virtual Machine. This element is used if ProvisionGuestAgent is set to true. Optional. The name of the role. Optional. The size of the role instance. Optional. Specifies the type of the role. This element is only listed for Virtual Machine deployments, and by default is PersistentVMRole. Optional. Optional. The name of the VMImage from which this Role is to be created. If the OSDisk in the VMImage was Specialized, then no WindowsProvisioningConfigurationSet or LinuxProvisioningConfigurationSet should be provided. No OSVirtualHardDisk or DataVirtualHardDisk should be specified when using this argument. Details of a specific role instance. Initializes a new instance of the RoleInstance class. Optional. Guest Agent Status. Optional. The DNS host name of the service in which the role instance is running. This element is only listed for Virtual Machine deployments. Optional. The list of instance endpoints for the role. Optional. An error code that can be provided to Windows Azure support to assist in resolution of errors. This field will typically be empty. Optional. The fault domain that this role instance belongs to. Role instances that are part of the same fault domain may all be vulnerable to the failure of the same piece of shared hardware. Optional. The name of the specific role instance, if an instance of the role is running. Optional. The size of the role instance. Optional. The instance state, returned as a string that, when present, provides a snapshot of the state of the virtual machine at the time the operation was called. Optional. The current status of this instance. Optional. The update domain that this role instance belongs to. During an Upgrade Deployment, all roles in the same update domain are updated at the same time. Optional. The IP address of the role instance (DIP). Optional. The running state of the role instance. Optional. Optional. A set of public IPs. Currently, only one additional public IP per role is supported in an IaaS deployment. The IP address is in addition to the default VIP for the deployment. Optional. The thumbprint of the RDP server certificate (in Windows) or SSH server certificate (in Linux). The thumbprint is only used for Virtual Machines that have been created from an image. Optional. Resource Extension Status List. Optional. The name of the role. An additional public IP that will be created for the role. The public IP will be an additional IP for the role. The role continues to be addressable via the default deployment VIP. Initializes a new instance of the PublicIP class. Optional. The address of the public IP. Optional. The name of the public IP. The running state of the role instance. The current status of a role instance. The role state is currently unknown. The state should automatically be resolved once the role state is detected, so no action is required. The host agent is currently creating resources for the Virtual Machine. The host agent is starting the Virtual Machine. Azure is creating resources for the role. Azure is starting the role. The role instance has started and is ready to be used. The role instance is unavailable for requests. This state is usually generated while the role is being created or stopped. Azure is stopping the role. The host agent is stopping the Virtual Machine. This status also indicates that the role has already been stopped. The Virtual Machine is being deleted by the host agent. The Virtual Machine is not running. This is the final state of the shutdown process, and no other status messages should be received after StoppedVM. The role has unexpectedly stopped or has failed to start. This status indicates that there is a problem with the role that is causing it to crash or is preventing it from starting, which must be corrected before the role can be started. The InstanceStateDetails and InstanceErrorCode fields can hold information about the role error that caused this state, which may be useful for identifying and debugging the problem. The role has continually crashed after being started by Azure. This status indicates that there is a problem with the role that prevents it from starting, and may be generated after the StartingRole and ReadyRole statuses are received. The problem in the role must be found and corrected before the role can be started. The InstanceStateDetails and InstanceErrorCode fields can hold information about the role error that caused this state, which may be useful for identifying and debugging the problem. The role has continually failed to start. This status indicates that there is a problem with the role that prevents it from starting, and may be generated after the process returns StartingRole. The problem in the role must be found and corrected before the role can be started. The InstanceStateDetails and InstanceErrorCode fields can hold information about the role error that caused this state, which may be useful for identifying and debugging the problem. An Azure or container error is preventing the Virtual Machine from starting. This status is generated by Azure, and does not indicate an error with the role. It may be generated after the StartingRole state. The role has timed out before receiving a status message and is not responding to requests. The rollback proceeds without further user input. You must call the Walk Upgrade Domain operation to apply the rollback to each upgrade domain. Parameters supplied to the Create Service Certificate operation. Initializes a new instance of the ServiceCertificateCreateParameters class. Required. The service certificate format. Azure supports the pfx and cer file formats. Required. The pfx or cer file. Optional. The password for a pfx certificate. A cer certificate does not require a password. Parameters supplied to the Delete Service Certificate operation. Initializes a new instance of the ServiceCertificateDeleteParameters class. Required. The DNS prefix name of your service. Required. The hexadecimal representation of the thumbprint. Required. The algorithm for the certificate's thumbprint. Parameters supplied to the Get Service Certificate operation. Initializes a new instance of the ServiceCertificateGetParameters class. Required. The DNS prefix name of your service. Required. The hexadecimal representation of the thumbprint. Required. The algorithm for the certificate's thumbprint. The Get Service Certificate operation response. Initializes a new instance of the ServiceCertificateGetResponse class. Optional. The public portion of the X.509 service certificate as a form of the cer file. The List Service Certificates operation response. Initializes a new instance of the ServiceCertificateListResponse class. Gets the sequence of Certificates. Gets the sequence of Certificates. Optional. The service certificates that are valid for your subscription. A service certificate that is valid for your subscription. Initializes a new instance of the Certificate class. Optional. The Service Management API request URI used to perform Get Service Certificate requests against the certificate store. Optional. The public part of the service certificate as a cer file. Optional. The X509 certificate thumb print property of the service certificate. Optional. The algorithm that was used to hash the service certificate. Currently SHA-1 is the only supported algorithm. Contains an SSH key pair to be installed on the virtual machine. Initializes a new instance of the SshSettingKeyPair class. Required. Specifies the SHA1 fingerprint of an X509 certificate associated with the hosted service that includes the SSH key pair. Required. Specifies the full path of a file on the virtual machine which stores the SSH private key. The file is overwritten when multiple keys are written to it. The SSH public key is stored in the same directory and has the same name as the private key file with .pub suffix. Example: /home/user/.ssh/id_rsa. Specifies a public key in the SSH settings. Initializes a new instance of the SshSettingPublicKey class. Required. Specifies the SHA1 fingerprint of an X509 certificate associated with the hosted service that includes the SSH public key. Required. Specifies the full path of a file on the virtual machine which stores the SSH public key. If the file already exists, the specified key is appended to the file. Example: /home/user/.ssh/authorized_keys. Specifies the SSH public keys and key pairs to populate in the image during provisioning. This element is only used with the LinuxProvisioningConfiguration set. Initializes a new instance of the SshSettings class. Optional. Specifies the collection of SSH key pairs. Optional. Specifies the collection of SSH public keys. Service certificates with which to provision the new virtual machine. Stored certificate settings reference certificates that already exist in the Azure hosted service. Prior to configuring the stored certificates for the virtual machine, you must call the Add Service Certificate operation or add the certificate via the Azure Management portal. Initializes a new instance of the StoredCertificateSettings class. Required. Specifies the name of the certificate store from which to retrieve certificates. For example, "My". Required. Specifies the thumbprint of the certificate to be provisioned. The thumbprint must specify an existing service certificate. The current state of the upgrade. Contains upgrade details of the deployment. Initializes a new instance of the UpgradeStatus class. Optional. An integer value that identifies the current upgrade domain. Upgrade domains are identified with a zero-based index: the first upgrade domain has an ID of 0, the second has an ID of 1, and so on. Optional. The current state of the upgrade. Possible values are Before and During Optional. The type of the upgrade. Possible values are Auto and Manual. Specifies the platform caching behavior of the data disk blob for read/write efficiency. The virtual IP address of the deployment. Initializes a new instance of the VirtualIPAddress class. Optional. The virtual IP address of the deployment. Optional. Indicates whether the IP address is DNS programmed. Optional. The name of the virtual IP. Parameters supplied to the Capture Virtual Machine operation. Initializes a new instance of the VirtualMachineCaptureOSImageParameters class. Required. Specifies the action that is performed after the capture operation finishes. Possible values are: Delete - this value causes the virtual machine to be deleted after the image has been captured; or Reprovision - this value causes the virtual machine to be redeployed after the image is captured by using the specified information in ProvisioningConfiguration. Optional. Provides information to be used to redeploy the virtual machine after the image has been captured. This element is only used when the PostCaptureAction is set to Reprovision. Required. Specifies the friendly name of the captured image. This is the value that appears in the Name column for the image in the Azure Management Portal. Required. Specifies the image name of the captured image. The Virtual Machine Template Capture Role operation response. Initializes a new instance of the VirtualMachineCaptureVMImageParameters class. Optional. Required. Must be set to CaptureRoleOperation. Optional. Required. The OS state: Generalized | Specialized. Optional. Required. The VM Template Label. Optional. Required. The VM Template Name. Parameters supplied to the Create Virtual Machine Deployment operation. Initializes a new instance of the VirtualMachineCreateDeploymentParameters class. Required. Specifies the environment in which to deploy the virtual machine. Possible values are: Staging or Production. Optional. Contains a list of DNS servers to associate with the machine. Required. A name for the hosted service. The name can be up to 100 characters in length. It is recommended that the label be unique within the subscription. The name can be used identify the hosted service for tracking purposes. Optional. A list of internal load balancers that each provide load balancing on a private VIP. Required. A name for the deployment. The deployment name must be unique among other deployments for the hosted service. Optional. Optional. Specifies the name of an existing reserved IP to which the deployment will belong. Reserved IPs are created by calling the Create Reserved IP operation. Required. Contains the provisioning details for the new virtual machine deployment. Optional. Specifies the name of an existing virtual network to which the deployment will belong. Virtual networks are created by calling the Set Network Configuration operation. Parameters supplied to the Create Virtual Machine operation. Initializes a new instance of the VirtualMachineCreateParameters class. Optional. Specifies the name of an availability set to which to add the virtual machine. This value controls the virtual machine allocation in the Azure environment. Virtual machines specified in the same availability set are allocated to different nodes to maximize availability. Optional. Contains the collection of configuration sets that contain system and application configuration settings. Optional. Contains the parameters Azure used to create the data disk for the virtual machine. Optional. Location where VMImage VHDs should be copied, for published VMImages. Optional. Contains the parameters Azure used to create the operating system disk for the virtual machine. Optional. Indicates whether the WindowsAzureGuestAgent service is installed on the Virtual Machine. To run a resource extension in a Virtual Machine, this service must be installed. Optional. Contains a collection of resource extensions that are to be installed on the Virtual Machine. This element is used if ProvisionGuestAgent is set to true. Required. Specifies the name for the virtual machine. The name must be unique within the deployment. Optional. The size of the virtual machine. Optional. Name of the VMImage from which this Role is to be created. If the OSDisk in the VMImage was Specialized, then no WindowsProvisioningConfigurationSet or LinuxProvisioningConfigurationSet should be provided. No OSVirtualHardDisk or DataVirtualHardDisk should be specified when using this argument. Parameters supplied to the Create Virtual Machine Data Disk operation. Initializes a new instance of the VirtualMachineDataDiskCreateParameters class. Required. Specifies the platform caching behavior of data disk blob for read/write efficiency. The default vault is ReadOnly. Possible values are: None, ReadOnly, or ReadWrite. Warning: Setting this property impacts the consistency of the disk. Optional. Specifies the description of the data disk. When you attach a disk, either by directly referencing a media using the MediaLink element or specifying the target disk size, you can use the DiskLabel element to customize the name property of the target data disk. Optional. Specifies the size, in GB, of an empty disk to be attached to the role. The disk can be created as part of disk attach or create VM role call by specifying the value for this property. Azure creates the empty disk based on size preference and attaches the newly created disk to the Role. Optional. Specifies the Logical Unit Number (LUN) for the disk. The LUN specifies the slot in which the data drive appears when mounted for usage by the virtual machine. Valid LUN values are 0 through 15. Required. Specifies the location of the blob in Azure storage where the media for the disk is located. The blob location must belong to the storage account in the subscription specified by the SubscriptionId value in the operation call. Example: http://example.blob.core.windows.net/disks/mydisk.vhd. Optional. Specifies the name of the disk. Azure uses the specified disk to create the data disk for the machine and populates this field with the disk name. Optional. Specifies the location of a blob in account storage which is mounted as a data disk when the virtual machine is created. The Get Data Disk operation response. Initializes a new instance of the VirtualMachineDataDiskGetResponse class. Optional. The current value of the platform caching behavior of data disk blob for read/write efficiency. Possible values are: None, ReadOnly, or ReadWrite. Optional. The description of the data disk. Optional. The size, in GB, of the data disk. Optional. The Logical Unit Number (LUN) for the disk. The LUN specifies the slot in which the data drive appears when mounted for usage by the virtual machine. Optional. The location of the physical blob backing the data disk. The blob location is in the storage account in the subscription specified by the SubscriptionId value in the operation call. Optional. The name of the data disk. Parameters supplied to the Update Virtual Machine Data Disk operation. Initializes a new instance of the VirtualMachineDataDiskUpdateParameters class. Required. Specifies the platform caching behavior of data disk blob for read/write efficiency. The default vault is ReadOnly. Possible values are: None, ReadOnly, or ReadWrite. Warning: Setting this property impacts the consistency of the disk. Optional. Specifies the description of the data disk. When you attach a disk, either by directly referencing a media using the MediaLink element or specifying the target disk size, you can use the DiskLabel element to customize the name property of the target data disk. Optional. Specifies the size, in GB, of an empty disk to be attached to the role. The disk can be created as part of disk attach or create VM role call by specifying the value for this property. Azure creates the empty disk based on size preference and attaches the newly created disk to the Role. Optional. Specifies the Logical Unit Number (LUN) for the disk. The LUN specifies the slot in which the data drive appears when mounted for usage by the virtual machine. Valid LUN values are 0 through 15. Required. Specifies the location of the blob in Azure blob store where the media for the disk is located. The blob location must belong to the storage account in the subscription specified by the SubscriptionId value in the operation call. Example: http://example.blob.core.windows.net/disks/mydisk.vhd. Optional. Specifies the name of the disk. Azure uses the specified disk to create the data disk for the machine and populates this field with the disk name. Parameters supplied to the Create Virtual Disk Image operation. Initializes a new instance of the VirtualMachineDiskCreateParameters class. Required. Specifies the friendly name of the disk. Required. Specifies the location of the blob in Azure storage. The blob location must belong to a storage account in the subscription specified by the SubscriptionId value in the operation call. Example: http://example.blob.core.windows.net/disks/mydisk.vhd. Required. Specifies a name for the disk. Azure uses the name to identify the disk when creating virtual machines from the disk. Optional. The operating system type of the disk. Possible values are: Linux or Windows. A virtual machine disk associated with your subscription. Initializes a new instance of the VirtualMachineDiskCreateResponse class. Optional. The affinity group in which the disk is located. The AffinityGroup value is derived from storage account that contains the blob in which the media is located. If the storage account does not belong to an affinity group the value is NULL. Optional. Specifies whether the comtained image is a premium image Optional. The friendly name of the disk Optional. The geo-location in which the disk is located. The Location value is derived from storage account that contains the blob in which the disk is located. If the storage account belongs to an affinity group the value is NULL. Optional. The size, in GB, of the disk. Optional. The location of the blob in the blob store in which the media for the disk is located. The blob location belongs to a storage account in the subscription specified by the SubscriptionId value in the operation call. Example: http://example.blob.core.windows.net/disks/mydisk.vhd. Optional. The name of the disk. This is the name that is used when creating one or more virtual machines using the disk. Optional. The Operating System type for the disk. Optional. The name of the OS Image from which the disk was created. This property is populated automatically when a disk is created from an OS image by calling the Add Role, Create Deployment, or Provision Disk operations. Optional. Contains properties that specify a virtual machine that is currently using the disk. A disk cannot be deleted as long as it is attached to a virtual machine. Contains properties that specify a virtual machine that currently using the disk. A disk cannot be deleted as long as it is attached to a virtual machine. Initializes a new instance of the VirtualMachineDiskUsageDetails class. Optional. The deployment in which the disk is being used. Optional. The hosted service in which the disk is being used. Optional. The virtual machine that the disk is attached to. A virtual machine disk associated with your subscription. Initializes a new instance of the VirtualMachineDiskGetResponse class. Optional. The affinity group in which the disk is located. The AffinityGroup value is derived from storage account that contains the blob in which the media is located. If the storage account does not belong to an affinity group the value is NULL. Optional. Specifies whether the disk is known to be corrupt. Optional. Specifies whether or not the disk contains a premium virtual machine image. Optional. The friendly name of the disk. Optional. The geo-location in which the disk is located. The Location value is derived from storage account that contains the blob in which the disk is located. If the storage account belongs to an affinity group the value is NULL. Optional. The size, in GB, of the disk. Optional. The location of the blob in the blob store in which the media for the disk is located. The blob location belongs to a storage account in the subscription specified by the SubscriptionId value in the operation call. Example: http://example.blob.core.windows.net/disks/mydisk.vhd. Optional. The name of the disk. This is the name that is used when creating one or more virtual machines using the disk. Optional. The operating system type of the OS image. Possible Values are: Linux, Windows, or NULL. Optional. The name of the OS Image from which the disk was created. This property is populated automatically when a disk is created from an OS image by calling the Add Role, Create Deployment, or Provision Disk operations. Optional. Contains properties that specify a virtual machine that is currently using the disk. A disk cannot be deleted as long as it is attached to a virtual machine. Contains properties that specify a virtual machine that currently using the disk. A disk cannot be deleted as long as it is attached to a virtual machine. Initializes a new instance of the VirtualMachineDiskUsageDetails class. Optional. The deployment in which the disk is being used. Optional. The hosted service in which the disk is being used. Optional. The virtual machine that the disk is attached to. The List Disks operation response. Initializes a new instance of the VirtualMachineDiskListResponse class. Gets the sequence of Disks. Gets the sequence of Disks. Optional. The virtual machine disks associated with your subscription. A virtual machine disk associated with your subscription. Initializes a new instance of the VirtualMachineDisk class. Optional. The affinity group in which the disk is located. The AffinityGroup value is derived from storage account that contains the blob in which the media is located. If the storage account does not belong to an affinity group the value is NULL. Optional. Specifies thether the disk is known to be corrupt. Optional. Specifies whether or not the disk contains a premium virtual machine image. Optional. The friendly name of the disk. Optional. The geo-location in which the disk is located. The Location value is derived from storage account that contains the blob in which the disk is located. If the storage account belongs to an affinity group the value is NULL. Optional. The size, in GB, of the disk. Optional. The location of the blob in the blob store in which the media for the disk is located. The blob location belongs to a storage account in the subscription specified by the SubscriptionId value in the operation call. Example: http://example.blob.core.windows.net/disks/mydisk.vhd. Optional. The name of the disk. This is the name that is used when creating one or more virtual machines using the disk. Optional. The operating system type of the OS image. Possible Values are: Linux, Windows, or NULL. Optional. The name of the OS Image from which the disk was created. This property is populated automatically when a disk is created from an OS image by calling the Add Role, Create Deployment, or Provision Disk operations. Optional. Contains properties that specify a virtual machine that currently using the disk. A disk cannot be deleted as long as it is attached to a virtual machine. Contains properties that specify a virtual machine that currently using the disk. A disk cannot be deleted as long as it is attached to a virtual machine. Initializes a new instance of the VirtualMachineDiskUsageDetails class. Optional. The deployment in which the disk is being used. Optional. The hosted service in which the disk is being used. Optional. The virtual machine that the disk is attached to. Parameters supplied to the Update Virtual Disk Image operation. Initializes a new instance of the VirtualMachineDiskUpdateParameters class. Optional. Specifies whether the disk contains an operating system. Note: Only a disk with an operating system installed can be mounted as OS Drive. Required. Specifies the friendly name of the disk. Optional. Specifies the location of the blob in Azure storage. The blob location must belong to a storage account in the subscription specified by the SubscriptionId value in the operation call. Example: http://example.blob.core.windows.net/disks/mydisk.vhd. Required. Specifies a name for the disk. Azure uses the name to identify the disk when creating virtual machines from the disk. Optional. The operating system type of the disk. Possible values are: Linux or Windows. A virtual machine disk associated with your subscription. Initializes a new instance of the VirtualMachineDiskUpdateResponse class. Optional. The affinity group in which the disk is located. The AffinityGroup value is derived from storage account that contains the blob in which the media is located. If the storage account does not belong to an affinity group the value is NULL. Optional. Specifies whether the contained image is a premium image. Optional. The friendly name of the disk Optional. The geo-location in which the disk is located. The Location value is derived from storage account that contains the blob in which the disk is located. If the storage account belongs to an affinity group the value is NULL. Optional. The size, in GB, of the disk. Optional. The location of the blob in the blob store in which the media for the disk is located. The blob location belongs to a storage account in the subscription specified by the SubscriptionId value in the operation call. Example: http://example.blob.core.windows.net/disks/mydisk.vhd Optional. The name of the disk. This is the name that is used when creating one or more virtual machines using the disk. Optional. The Operating System type for the disk. The List Resource Extensions operation response. Initializes a new instance of the VirtualMachineExtensionListResponse class. Gets the sequence of ResourceExtensions. Gets the sequence of ResourceExtensions. Optional. The extensions that are available to add to your cloud service. An extension available to add to your virtual machine. Initializes a new instance of the ResourceExtension class. Optional. The description of the extension. Optional. URI string pointing to the EULA (End User License Agreement) of this version of extension. This is optionally specified by the third-party publishing the extension instead of Azure, at the time of extension creation or update. Optional. URI string pointing to the homepage of this version of extension. This is optionally specified by the third-party publishing the extension instead of Azure, at the time of extension creation or update. Optional. Indicates whether the extension accepts JSON or XML based configuration. If this property is 'true' the extension accepts JSON based configuration. If this property is 'false' the extension accepts XML based configuration. Optional. The label that is used to identify the extension. Optional. The name of the extension. Optional. URI string pointing to the privacy document of this version of extension. This is optionally specified by the third-party publishing the extension instead of Azure, at the time of extension creation or update. Optional. The base64-encoded schema of the private configuration. Optional. The base64-encoded schema of the public configuration. Optional. The provider namespace of the extension. The provider namespace for Azure extensions is Microsoft.Compute. Optional. Indicates whether this version of extension has been replicated to all regions or not. If true, then the given extension version can be used in creating or updating deployments. Otherwise, the given extension version might cause failure in creating or updating deployments. The typical time is 20 minutes for a newly-registered or newly-updated extension to replicate completely by Azure. Optional. A sample configuration file for the resource extension. Optional. The version of the extension. The Download RDP file operation response. Initializes a new instance of the VirtualMachineGetRemoteDesktopFileResponse class. Required. A Remote Desktop Protocol (.rdp) file that can be used to establish a remote desktop session to the virtual machine The Get Virtual Machine operation response. Initializes a new instance of the VirtualMachineGetResponse class. Optional. The name of the availability set the virtual machine belongs to. This value controls the virtual machine allocation in the Windows Azure environment. Virtual machines specified in the same availability set are allocated to different nodes to maximize availability. Optional. Contains the collection of configuration sets that contain system and application configuration settings. Optional. Contains the parameters Azure used to create the data disk for the virtual machine. Optional. The read-only thumbprint of the certificate that is used with the HTTPS listener for WinRM. Optional. The version of the operating system on which the role instances are running. Optional. Contains the parameters Azure used to create the operating system disk for the virtual machine. Optional. The name for the virtual machine. The name is unique within Azure. Optional. The size of the virtual machine. Optional. The type of the role for the virtual machine. The only supported value is PersistentVMRole. Parameters supplied to the Create Virtual Machine Image operation. Initializes a new instance of the VirtualMachineOSImageCreateParameters class. Optional. Specifies the description of the OS image. Optional. Specifies the End User License Agreement that is associated with the image. The value for this element is a string, but it is recommended that the value be a URL that points to a EULA. Optional. Specifies the URI to the icon that is displayed for the image in the Management Portal. Optional. Specifies a value that can be used to group OS images. Required. Indicates if the image contains software or associated services that will incur charges above the core price for the virtual machine. Required. Specifies the friendly name of the image. Optional. Specifies the language of the image. The Language element is only available using version 2013-03-01 or higher. Required. Specifies the location of the blob in Azure storage. The blob location must belong to a storage account in the subscription specified by the SubscriptionId value in the operation call. Example: http://example.blob.core.windows.net/disks/mydisk.vhd. Required. Specifies a name that Azure uses to identify the image when creating one or more virtual machines. Required. The operating system type of the OS image. Possible values are: Linux or Windows. Optional. Specifies the URI that points to a document that contains the privacy policy related to the OS image. Optional. Specifies the date when the OS image was added to the image repository. Optional. Specifies the size to use for the virtual machine that is created from the OS image. Required. Specifies whether the image should appear in the image gallery. Optional. Specifies the URI to the small icon that is displayed when the image is presented in the Azure Management Portal. The SmallIconUri element is only available using version 2013-03-01 or higher. Parameters returned from the Create Virtual Machine Image operation. Initializes a new instance of the VirtualMachineOSImageCreateResponse class. Optional. The repository classification of the image. All user images have the category User. Optional. Specifies the description of the OS image. Optional. Specifies the End User License Agreement that is associated with the image. The value for this element is a string, but it is recommended that the value be a URL that points to a EULA. Optional. Specifies the URI to the icon that is displayed for the image in the Management Portal. Optional. Specifies a value that can be used to group OS images. Optional. Indicates if the image contains software or associated services that will incur charges above the core price for the virtual machine. Optional. Specifies the friendly name of the image. Optional. Specifies the language of the image. The Language element is only available using version 2013-03-01 or higher. Optional. The geo-location in which this media is located. The Location value is derived from storage account that contains the blob in which the media is located. If the storage account belongs to an affinity group the value is NULL. If the version is set to 2012-08-01 or later, the locations are returned for platform images; otherwise, this value is NULL for platform images. Optional. The size, in GB, of the image. Optional. Specifies the location of the blob in Azure storage. The blob location must belong to a storage account in the subscription specified by the SubscriptionId value in the operation call. Example: http://example.blob.core.windows.net/disks/mydisk.vhd. Optional. Specifies a name that Azure uses to identify the image when creating one or more virtual machines. Optional. The operating system type of the OS image. Possible values are: Linux or Windows. Optional. Specifies the URI that points to a document that contains the privacy policy related to the OS image. Optional. Specifies the date when the OS image was added to the image repository. Optional. Specifies the name of the publisher of the image. Optional. Specifies the size to use for the virtual machine that is created from the OS image. Optional. Specifies whether the image should appear in the image gallery. Optional. Specifies the URI to the small icon that is displayed when the image is presented in the Azure Management Portal. The SmallIconUri element is only available using version 2013-03-01 or higher. The Get Details OS Images operation response. A virtual machine image associated with your subscription. Initializes a new instance of the VirtualMachineOSImageGetResponse class. Optional. The affinity in which the media is located. The AffinityGroup value is derived from storage account that contains the blob in which the media is located. If the storage account does not belong to an affinity group the value is NULL and the element is not displayed in the response. This value is NULL for platform images. Optional. The repository classification of the image. All user images have the category User. Optional. Specifies the description of the image. Optional. Specifies the End User License Agreement that is associated with the image. The value for this element is a string, but it is recommended that the value be a URL that points to a EULA. Optional. Provides the URI to the icon for this Operating System Image. Optional. Specifies a value that can be used to group images. Optional. Indicates whether the image contains software or associated services that will incur charges above the core price for the virtual machine. For additional details, see the PricingDetailLink element. Optional. An identifier for the image. Optional. Specifies the language of the image. The Language element is only available using version 2013-03-01 or higher. Optional. The geo-location in which this media is located. The Location value is derived from storage account that contains the blob in which the media is located. If the storage account belongs to an affinity group the value is NULL. If the version is set to 2012-08-01 or later, the locations are returned for platform images; otherwise, this value is NULL for platform images. Optional. The size, in GB, of the image. Optional. The location of the blob in Azure storage. The blob location belongs to a storage account in the subscription specified by the SubscriptionId value in the operation call. Example: http://example.blob.core.windows.net/disks/myimage.vhd. Optional. The name of the operating system image. This is the name that is used when creating one or more virtual machines using the image. Optional. The operating system type of the OS image. Possible values are: Linux or Windows. Optional. Specifies the URI that points to a document that contains the privacy policy related to the image. Optional. Specifies the date when the image was added to the image repository. Optional. The name of the publisher of this OS Image in Azure. Optional. Specifies the size to use for the virtual machine that is created from the OS image. Optional. Indicates whether the image should be shown in the Azure portal. Optional. Specifies the URI to the small icon that is displayed when the image is presented in the Azure Management Portal. The SmallIconUri element is only available using version 2013-03-01 or higher. Initializes a new instance of the VirtualMachineOSImageGetDetailsResponse class. Optional. The indicator of whether the image is corrupted or not. Optional. The replication progress information of VM images. The replication progress information of VM images. Initializes a new instance of the ReplicationProgressElement class. Optional. The location of the replication of VM image. Optional. The progress of the replication of VM image. The List OS Images operation response. Initializes a new instance of the VirtualMachineOSImageListResponse class. Gets the sequence of Images. Gets the sequence of Images. Optional. The virtual machine images associated with your subscription. A virtual machine image associated with your subscription. Initializes a new instance of the VirtualMachineOSImage class. Optional. The affinity in which the media is located. The AffinityGroup value is derived from storage account that contains the blob in which the media is located. If the storage account does not belong to an affinity group the value is NULL and the element is not displayed in the response. This value is NULL for platform images. Optional. The repository classification of the image. All user images have the category User. Optional. Specifies the description of the image. Optional. Specifies the End User License Agreement that is associated with the image. The value for this element is a string, but it is recommended that the value be a URL that points to a EULA. Optional. Specifies a value that can be used to group images. Optional. Indicates whether the image contains software or associated services that will incur charges above the core price for the virtual machine. For additional details, see the PricingDetailLink element. Optional. An identifier for the image. Optional. Specifies the language of the image. The Language element is only available using version 2013-03-01 or higher. Optional. The geo-location in which this media is located. The Location value is derived from storage account that contains the blob in which the media is located. If the storage account belongs to an affinity group the value is NULL. If the version is set to 2012-08-01 or later, the locations are returned for platform images; otherwise, this value is NULL for platform images. Optional. The size, in GB, of the image. Optional. The location of the blob in Azure storage. The blob location belongs to a storage account in the subscription specified by the SubscriptionId value in the operation call. Example: http://example.blob.core.windows.net/disks/myimage.vhd Optional. The name of the operating system image. This is the name that is used when creating one or more virtual machines using the image. Optional. The operating system type of the OS image. Possible values are: Linux, Windows. Optional. Specifies a URL for an image with IsPremium set to true, which contains the pricing details for a virtual machine that is created from the image. The PricingDetailLink element is only available using version 2012-12-01 or higher. Optional. Specifies the URI that points to a document that contains the privacy policy related to the image. Optional. Specifies the date when the image was added to the image repository. Optional. The name of the publisher of this OS Image in Azure. Optional. Specifies the size to use for the virtual machine that is created from the OS image. Optional. Specifies the URI to the small icon that is displayed when the image is presented in the Azure Management Portal. The SmallIconUri element is only available using version 2013-03-01 or higher. Known values for the operating system type of the OS in a virtual machine image. Parameters supplied to the Replicate Virtual Machine Image operation. Initializes a new instance of the VirtualMachineOSImageReplicateParameters class. Optional. The replication target regional locations.Note: The regions in the request body are not additive. If an OS Image has already been replicated to Regions A, B, and C, and a request is made to replicate to Regions A and D, the VM Image will remain in Region A, will be replicated in Region D, and will be unreplicated from Regions B and C. The response body contains the published name of the image. Initializes a new instance of the VirtualMachineOSImageReplicateResponse class. Optional. The published name of the image. Specifies the permission type for sharing. Parameters supplied to the Update Virtual Machine Image operation. Initializes a new instance of the VirtualMachineOSImageUpdateParameters class. Optional. Specifies the description of the OS image. Optional. Specifies the End User License Agreement that is associated with the image. The value for this element is a string, but it is recommended that the value be a URL that points to a EULA. Optional. Specifies the URI to the icon that is displayed for the image in the Management Portal. Optional. Specifies a value that can be used to group OS images. Optional. Indicates if the image contains software or associated services that will incur charges above the core price for the virtual machine. Required. Specifies the friendly name of the image to be updated. You cannot use this operation to update images provided by the Azure platform. Optional. Specifies the language of the image. The Language element is only available using version 2013-03-01 or higher. Optional. Specifies the URI that points to a document that contains the privacy policy related to the OS image. Optional. Specifies the date when the OS image was added to the image repository. Optional. Specifies the size to use for the virtual machine that is created from the OS image. Optional. When published, should this image show up in the windows azure image gallery or not. True by default. Optional. Specifies the URI to the small icon that is displayed when the image is presented in the Azure Management Portal. The SmallIconUri element is only available using version 2013-03-01 or higher. Parameters returned from the Create Virtual Machine Image operation. Initializes a new instance of the VirtualMachineOSImageUpdateResponse class. Optional. The repository classification of the image. All user images have the category User. Optional. Specifies the description of the OS image. Optional. Specifies the End User License Agreement that is associated with the image. The value for this element is a string, but it is recommended that the value be a URL that points to a EULA. Optional. Specifies the URI to the icon that is displayed for the image in the Management Portal. Optional. Specifies a value that can be used to group OS images. Optional. Indicates if the image contains software or associated services that will incur charges above the core price for the virtual machine. Optional. Specifies the friendly name of the image. Optional. Specifies the language of the image. The Language element is only available using version 2013-03-01 or higher. Optional. The geo-location in which this media is located. The Location value is derived from storage account that contains the blob in which the media is located. If the storage account belongs to an affinity group the value is NULL. If the version is set to 2012-08-01 or later, the locations are returned for platform images; otherwise, this value is NULL for platform images. Optional. The size, in GB, of the image. Optional. Specifies the location of the blob in Azure storage. The blob location must belong to a storage account in the subscription specified by the SubscriptionId value in the operation call. Example: http://example.blob.core.windows.net/disks/mydisk.vhd. Optional. Specifies a name that Azure uses to identify the image when creating one or more virtual machines. Optional. The operating system type of the OS image. Possible values are: Linux or Windows. Optional. Specifies the URI that points to a document that contains the privacy policy related to the OS image. Optional. Specifies the date when the OS image was added to the image repository. Optional. Specifies the name of the publisher of the image. Optional. Specifies the size to use for the virtual machine that is created from the OS image. Optional. Specifies whether the image should appear in the image gallery. Optional. Specifies the URI to the small icon that is displayed when the image is presented in the Azure Management Portal. The SmallIconUri element is only available using version 2013-03-01 or higher. The size of a virtual machine. The type of the role for the virtual machine. The parameters required for shutting down the virtual machine. Initializes a new instance of the VirtualMachineShutdownParameters class. Optional. The state of the virtual machine after shutdown (Stopped or StoppedDeallocated). Parameters for the shutdown roles operation. Initializes a new instance of the VirtualMachineShutdownRolesParameters class. Optional. The state of the roles after shutdown. Possible values include Stopped or StoppedDeallocated. Optional. The set of roles to shut down. Parameters for the Start Roles operation. Initializes a new instance of the VirtualMachineStartRolesParameters class. Optional. The set of roles to shut down. The set of parameters required to update a load balanced endpoint set. Initializes a new instance of the VirtualMachineUpdateLoadBalancedSetParameters class. Optional. A list of load balanced InputEndpoints to update. The modeled external endpoint for a persistent VM role. Initializes a new instance of the InputEndpoint class. Optional. A Boolean specifying whether this endpoint uses Direct Server Return Required. Specifies whether this endpoint is part of shared LoadBalanced endpoint and served by multiple role instances. If not specified a BadRequest error will be returned. It must also be in use by the deployment (at least one role in the deployment must have an endpoint whose LoadBalancedEndpointSetName matches this) otherwise a BadRequest error will be returned. Optional. Optional. Specify the name of an internal load balancer if this endpoint shall not be exposed on the default load balancer. Optional. This represents an endpoint setting which platform load balancer must monitor to detect the availability of this role before forwarding traffic to this endpoint. If not specified the probe settings (if any) from the existing load balanced endpoint definition will be retained. Optional. Specifies the internal port on which a service running inside the VM is listening to serve this endpoint. WARNING: If specified then ALL the endpoints of this LB set on all the roles will be updated to have THIS local port. To keep unique local ports on each role for a load balanced endpoint specify this as 0 (zero) and if you need to change those use UpdateRole. In case of port conflict with a local port (or probe port) on a role a BadRequestwill be returned. Optional. The name of the InputEndpoint. The name is ignored if specified Optional. An integer specifying the public port for this endpoint. Allowed values are between 1 and 65535 inclusive. A unqiue Port and Protocol combination must be specified for each InputEndpoint in the list. Optional. Specifies the transport protocol for the endpoint. Optional. A collection of access control rules which control the external network traffic reaching to this endpoint. NOTES: (1) To remove the ACLs from a load-balanced endpoint just omit this element. (2) ACLs are set as specified. There is no merge done with existing ACLs. Optional. The virtual IP address of the endpoint. Parameters supplied to the Update Virtual Machine operation. Initializes a new instance of the VirtualMachineUpdateParameters class. Optional. Specifies the name of an availability set to which to add the virtual machine. This value controls the virtual machine allocation in the Azure environment. Virtual machines specified in the same availability set are allocated to different nodes to maximize availability. Optional. Contains the collection of configuration sets that contain system and application configuration settings. Optional. Contains the parameters Azure used to create the data disk for the virtual machine. Optional. Specifies the friendly name for the virtual machine. Required. Contains the parameters Azure used to create the operating system disk for the virtual machine. Optional. Indicates whether the WindowsAzureGuestAgent service is installed on the Virtual Machine. To run a resource extension in a Virtual Machine, this service must be installed. Optional. Contains a collection of resource extensions that are to be installed on the Virtual Machine. This element is used if ProvisionGuestAgent is set to true. Required. Specifies the name for the virtual machine. The name must be unique within the deployment. Optional. The size of the virtual machine. The Get Details VM Images operation response. Initializes a new instance of the VirtualMachineVMImageGetDetailsResponse class. Optional. The affinity group name of the virtual machine image. Optional. The classification of the virtual machine image. Optional. The date when the virtual machine image was created. Optional. The data disk configurations. Optional. The deployment name of the virtual machine image. Optional. The description of the virtual machine image. Optional. Specifies the End User License Agreement that is associated with the image. The value for this element is a string, but it is recommended that the value be a URL that points to a EULA. Optional. Provides the URI to the icon for this Operating System Image. Optional. The image family of the virtual machine image. Optional. The indicator of whether the image is corrupted or not. Optional. The indicator of whether the virtual machine image is premium. Optional. An identifier for the virtual machine image. Optional. The language of the virtual machine image. Optional. The location name of the virtual machine image. Optional. The date when the virtual machine image was created. Optional. The name of the virtual machine image. Optional. The OS disk configuration. Optional. Specifies the URI that points to the pricing detail. Optional. Specifies the URI that points to a document that contains the privacy policy related to the image. Optional. Specifies the date when the image was added to the image repository. Optional. The publisher name of the VM image. Optional. The name of the publisher of this VM Image in Azure. Optional. The recommended size of the virtual machine image. Optional. The replication progress information of VM images. Optional. The role name of the virtual machine image. Optional. The service name of the virtual machine image. Optional. The sharing status of the VM image. Optional. Specifies whether to show in Gui. Optional. Specifies the URI to the small icon that is displayed when the image is presented in the Azure Management Portal. The replication progress information of VM images. Initializes a new instance of the ReplicationProgressElement class. Optional. The location of the replication of VM image. Optional. The progress of the replication of VM image. The List VM Images operation response. Initializes a new instance of the VirtualMachineVMImageListResponse class. Gets the sequence of VMImages. Gets the sequence of VMImages. Optional. The virtual machine images associated with your subscription. The data disk configuration. Initializes a new instance of the DataDiskConfiguration class. Optional. Specifies the platform caching behavior of the data disk blob for read/write efficiency. The default vault is ReadOnly. Optional. Specifies the size, in GB, of an empty VHD to be attached to the virtual machine. The VHD can be created as part of disk attach or create virtual machine calls by specifying the value for this property. Azure creates the empty VHD based on size preference and attaches the newly created VHD to the virtual machine. Optional. Specifies the Logical Unit Number (LUN) for the data disk. The LUN specifies the slot in which the data drive appears when mounted for usage by the virtual machine. This element is only listed when more than one data disk is attached to a virtual machine. Optional. Specifies the location of the disk in Windows Azure storage. Optional. Specifies the name of the VHD to use to create the data disk for the virtual machine. The OS disk configuration. Initializes a new instance of the OSDiskConfiguration class. Optional. Specifies the platform caching behavior of the operating system disk blob for read/write efficiency. Optional. Specifies the size, in GB, of an empty VHD to be attached to the virtual machine. The VHD can be created as part of disk attach or create virtual machine calls by specifying the value for this property. Azure creates the empty VHD based on size preference and attaches the newly created VHD to the virtual machine. Optional. Specifies the location of the disk in Windows Azure storage. Optional. Specifies the name of an operating system image in the image repository. Optional. The operating system running in the virtual machine. Optional. The operating system state in the virtual machine. A virtual machine image associated with your subscription. Initializes a new instance of the VirtualMachineVMImage class. Optional. The affinity group name of the virtual machine image. Optional. The classification of the virtual machine image. Optional. The date when the virtual machine image was created. Optional. The data disk configurations. Optional. The deployment name of the virtual machine image. Optional. The description of the virtual machine image. Optional. Specifies the End User License Agreement that is associated with the image. The value for this element is a string, but it is recommended that the value be a URL that points to a EULA. Optional. Provides the URI to the icon for this Operating System Image. Optional. The image family of the virtual machine image. Optional. The indicator of whether the virtual machine image is premium. Optional. An identifier for the virtual machine image. Optional. The language of the virtual machine image. Optional. The location name of the virtual machine image. Optional. The date when the virtual machine image was created. Optional. The name of the virtual machine image. Optional. The OS disk configuration. Optional. Specifies the URI that points to the pricing detail. Optional. Specifies the URI that points to a document that contains the privacy policy related to the image. Optional. Specifies the date when the image was added to the image repository. Optional. The name of the publisher of this VM Image in Azure. Optional. The recommended size of the virtual machine image. Optional. The role name of the virtual machine image. Optional. The service name of the virtual machine image. Optional. Specifies whether to show in Gui. Optional. Specifies the URI to the small icon that is displayed when the image is presented in the Azure Management Portal. Parameters supplied to the Replicate Virtual Machine Image operation. Initializes a new instance of the VirtualMachineVMImageReplicateParameters class. Optional. The replication target regional locations.Note: The regions in the request body are not additive. If a VM Image has already been replicated to Regions A, B, and C, and a request is made to replicate to Regions A and D, the VM Image will remain in Region A, will be replicated in Region D, and will be unreplicated from Regions B and C. The response body contains the published name of the image. Initializes a new instance of the VirtualMachineVMImageReplicateResponse class. Optional. The published name of the image. Specifies the permission type for sharing. Parameters supplied to the Update Virtual Machine Image operation. Initializes a new instance of the VirtualMachineVMImageUpdateParameters class. Optional. Optional. The Data Disk Configurations. Optional. Specifies the description of the OS image. Optional. Specifies the End User License Agreement that is associated with the image. The value for this element is a string, but it is recommended that the value be a URL that points to a EULA. Optional. Specifies the URI to the icon that is displayed for the image in the Management Portal. Optional. Specifies a value that can be used to group OS images. Required. Specifies the friendly name of the image to be updated. You cannot use this operation to update images provided by the Azure platform. Optional. Specifies the language of the image. Optional. Optional. The OS Disk Configuration. Optional. Specifies the URI that points to a document that contains the privacy policy related to the OS image. Optional. Specifies the date when the OS image was added to the image repository. Optional. Specifies the size to use for the virtual machine that is created from the OS image. Optional. Optional. True or False. Optional. Specifies the URI to the small icon that is displayed when the image is presented in the Azure Management Portal. Specifies the type of listener for enabling remote Windows PowerShell. Contains the type and certificate information for the listener. Initializes a new instance of the WindowsRemoteManagementListener class. Optional. Specifies the certificate thumbprint for the secure connection. If Type is Https then this value is an optional value that is set to the thumbprint of the service certificate that is used to provision the WinRM HTTPS listener. If this value is not specified, a self-signed certificate is generated and used for the virtual machine. Required. Specifies the type of listener. This value can be Http or Https. The value is case sensitive. Configures the Windows Remote Management service on the virtual machine, which enables remote Windows PowerShell. Initializes a new instance of the WindowsRemoteManagementSettings class. Optional. Contains a collection of information for enabling remote Windows PowerShell. Operations for determining the version of the Azure Guest Operating System on which your service is running. (see http://msdn.microsoft.com/en-us/library/windowsazure/ff684169.aspx for more information) Initializes a new instance of the OperatingSystemOperations class. Reference to the service client. The List Operating Systems operation lists the versions of the guest operating system that are currently available in Windows Azure. The 2010-10-28 version of List Operating Systems also indicates what family an operating system version belongs to. Currently Azure supports two operating system families: the Azure guest operating system that is substantially compatible with Windows Server 2008 SP2, and the Azure guest operating system that is substantially compatible with Windows Server 2008 R2. (see http://msdn.microsoft.com/en-us/library/windowsazure/ff684168.aspx for more information) Cancellation token. The List Operating Systems operation response. The List OS Families operation lists the guest operating system families available in Azure, and also lists the operating system versions available for each family. Currently Azure supports two operating system families: the Azure guest operating system that is substantially compatible with Windows Server 2008 SP2, and the Azure guest operating system that is substantially compatible with Windows Server 2008 R2. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441291.aspx for more information) Cancellation token. The List Operating System Families operation response. Gets a reference to the Microsoft.WindowsAzure.Management.Compute.ComputeManagementClient. The Service Management API provides programmatic access to much of the functionality available through the Management Portal. The Service Management API is a REST API. All API operations are performed over SSL, and are mutually authenticated using X.509 v3 certificates. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460799.aspx for more information) The List Operating Systems operation lists the versions of the guest operating system that are currently available in Windows Azure. The 2010-10-28 version of List Operating Systems also indicates what family an operating system version belongs to. Currently Azure supports two operating system families: the Azure guest operating system that is substantially compatible with Windows Server 2008 SP2, and the Azure guest operating system that is substantially compatible with Windows Server 2008 R2. (see http://msdn.microsoft.com/en-us/library/windowsazure/ff684168.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IOperatingSystemOperations. The List Operating Systems operation response. The List Operating Systems operation lists the versions of the guest operating system that are currently available in Windows Azure. The 2010-10-28 version of List Operating Systems also indicates what family an operating system version belongs to. Currently Azure supports two operating system families: the Azure guest operating system that is substantially compatible with Windows Server 2008 SP2, and the Azure guest operating system that is substantially compatible with Windows Server 2008 R2. (see http://msdn.microsoft.com/en-us/library/windowsazure/ff684168.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IOperatingSystemOperations. The List Operating Systems operation response. The List OS Families operation lists the guest operating system families available in Azure, and also lists the operating system versions available for each family. Currently Azure supports two operating system families: the Azure guest operating system that is substantially compatible with Windows Server 2008 SP2, and the Azure guest operating system that is substantially compatible with Windows Server 2008 R2. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441291.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IOperatingSystemOperations. The List Operating System Families operation response. The List OS Families operation lists the guest operating system families available in Azure, and also lists the operating system versions available for each family. Currently Azure supports two operating system families: the Azure guest operating system that is substantially compatible with Windows Server 2008 SP2, and the Azure guest operating system that is substantially compatible with Windows Server 2008 R2. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441291.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IOperatingSystemOperations. The List Operating System Families operation response. Operations for managing service certificates for your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee795178.aspx for more information) Initializes a new instance of the ServiceCertificateOperations class. Reference to the service client. The Begin Creating Service Certificate operation adds a certificate to a hosted service. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460817.aspx for more information) Required. The DNS prefix name of your service. Required. Parameters supplied to the Begin Creating Service Certificate operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Deleting Service Certificate operation deletes a service certificate from the certificate store of a hosted service. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460803.aspx for more information) Required. Parameters supplied to the Begin Deleting Service Certificate operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Create Service Certificate operation adds a certificate to a hosted service. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460817.aspx for more information) Required. The DNS prefix name of your service. Required. Parameters supplied to the Create Service Certificate operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Service Certificate operation deletes a service certificate from the certificate store of a hosted service. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460803.aspx for more information) Required. Parameters supplied to the Delete Service Certificate operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Get Service Certificate operation returns the public data for the specified X.509 certificate associated with a hosted service. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460792.aspx for more information) Required. Parameters supplied to the Get Service Certificate operation. Cancellation token. The Get Service Certificate operation response. The List Service Certificates operation lists all of the service certificates associated with the specified hosted service. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj154105.aspx for more information) Required. The DNS prefix name of your hosted service. Cancellation token. The List Service Certificates operation response. Gets a reference to the Microsoft.WindowsAzure.Management.Compute.ComputeManagementClient. The Service Management API provides programmatic access to much of the functionality available through the Management Portal. The Service Management API is a REST API. All API operations are performed over SSL, and are mutually authenticated using X.509 v3 certificates. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460799.aspx for more information) The Begin Creating Service Certificate operation adds a certificate to a hosted service. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460817.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IServiceCertificateOperations. Required. The DNS prefix name of your service. Required. Parameters supplied to the Begin Creating Service Certificate operation. A standard service response including an HTTP status code and request ID. The Begin Creating Service Certificate operation adds a certificate to a hosted service. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460817.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IServiceCertificateOperations. Required. The DNS prefix name of your service. Required. Parameters supplied to the Begin Creating Service Certificate operation. A standard service response including an HTTP status code and request ID. The Begin Deleting Service Certificate operation deletes a service certificate from the certificate store of a hosted service. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460803.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IServiceCertificateOperations. Required. Parameters supplied to the Begin Deleting Service Certificate operation. A standard service response including an HTTP status code and request ID. The Begin Deleting Service Certificate operation deletes a service certificate from the certificate store of a hosted service. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460803.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IServiceCertificateOperations. Required. Parameters supplied to the Begin Deleting Service Certificate operation. A standard service response including an HTTP status code and request ID. The Create Service Certificate operation adds a certificate to a hosted service. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460817.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IServiceCertificateOperations. Required. The DNS prefix name of your service. Required. Parameters supplied to the Create Service Certificate operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Create Service Certificate operation adds a certificate to a hosted service. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460817.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IServiceCertificateOperations. Required. The DNS prefix name of your service. Required. Parameters supplied to the Create Service Certificate operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Service Certificate operation deletes a service certificate from the certificate store of a hosted service. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460803.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IServiceCertificateOperations. Required. Parameters supplied to the Delete Service Certificate operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Service Certificate operation deletes a service certificate from the certificate store of a hosted service. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460803.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IServiceCertificateOperations. Required. Parameters supplied to the Delete Service Certificate operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Get Service Certificate operation returns the public data for the specified X.509 certificate associated with a hosted service. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460792.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IServiceCertificateOperations. Required. Parameters supplied to the Get Service Certificate operation. The Get Service Certificate operation response. The Get Service Certificate operation returns the public data for the specified X.509 certificate associated with a hosted service. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460792.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IServiceCertificateOperations. Required. Parameters supplied to the Get Service Certificate operation. The Get Service Certificate operation response. The List Service Certificates operation lists all of the service certificates associated with the specified hosted service. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj154105.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IServiceCertificateOperations. Required. The DNS prefix name of your hosted service. The List Service Certificates operation response. The List Service Certificates operation lists all of the service certificates associated with the specified hosted service. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj154105.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IServiceCertificateOperations. Required. The DNS prefix name of your hosted service. The List Service Certificates operation response. The Service Management API includes operations for managing the disks in your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157188.aspx for more information) Initializes a new instance of the VirtualMachineDiskOperations class. Reference to the service client. The Begin Deleting Data Disk operation removes the specified data disk from a virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157179.aspx for more information) Required. The name of your service. Required. The name of the deployment. Required. The name of the role to delete the data disk from. Required. The logical unit number of the disk. Required. Specifies that the source blob for the disk should also be deleted from storage. Cancellation token. A standard service response including an HTTP status code and request ID. The Create Data Disk operation adds a data disk to a virtual machine. There are three ways to create the data disk using the Add Data Disk operation. Option 1 - Attach an empty data disk to the role by specifying the disk label and location of the disk image. Do not include the DiskName and SourceMediaLink elements in the request body. Include the MediaLink element and reference a blob that is in the same geographical region as the role. You can also omit the MediaLink element. In this usage, Azure will create the data disk in the storage account configured as default for the role. Option 2 - Attach an existing data disk that is in the image repository. Do not include the DiskName and SourceMediaLink elements in the request body. Specify the data disk to use by including the DiskName element. Note: If included the in the response body, the MediaLink and LogicalDiskSizeInGB elements are ignored. Option 3 - Specify the location of a blob in your storage account that contain a disk image to use. Include the SourceMediaLink element. Note: If the MediaLink element isincluded, it is ignored. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157199.aspx for more information) Required. The name of your service. Required. The name of the deployment. Required. The name of the role to add the data disk to. Required. Parameters supplied to the Create Virtual Machine Data Disk operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Create Disk operation adds a disk to the user image repository. The disk can be an operating system disk or a data disk. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157178.aspx for more information) Required. Parameters supplied to the Create Virtual Machine Disk operation. Cancellation token. A virtual machine disk associated with your subscription. The Delete Data Disk operation removes the specified data disk from a virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157179.aspx for more information) Required. The name of your service. Required. The name of the deployment. Required. The name of the role to delete the data disk from. Required. The logical unit number of the disk. Required. Specifies that the source blob for the disk should also be deleted from storage. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Disk operation deletes the specified data or operating system disk from your image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157200.aspx for more information) Required. The name of the disk to delete. Required. Specifies that the source blob for the disk should also be deleted from storage. Cancellation token. A standard service response including an HTTP status code and request ID. The Get Data Disk operation retrieves the specified data disk from a virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157180.aspx for more information) Required. The name of your service. Required. The name of the deployment. Required. The name of the role. Required. The logical unit number of the disk. Cancellation token. The Get Data Disk operation response. The Get Disk operation retrieves a disk from the user image repository. The disk can be an operating system disk or a data disk. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157178.aspx for more information) Required. The name of the disk. Cancellation token. A virtual machine disk associated with your subscription. The List Disks operation retrieves a list of the disks in your image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157176.aspx for more information) Cancellation token. The List Disks operation response. The Update Data Disk operation updates the specified data disk attached to the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157190.aspx for more information) Required. The name of your service. Required. The name of the deployment. Required. The name of the role to add the data disk to. Required. The logical unit number of the disk. Required. Parameters supplied to the Update Virtual Machine Data Disk operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Add Disk operation adds a disk to the user image repository. The disk can be an operating system disk or a data disk. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157178.aspx for more information) Required. The name of the disk being updated. Required. Parameters supplied to the Update Virtual Machine Disk operation. Cancellation token. A virtual machine disk associated with your subscription. Gets a reference to the Microsoft.WindowsAzure.Management.Compute.ComputeManagementClient. The Service Management API provides programmatic access to much of the functionality available through the Management Portal. The Service Management API is a REST API. All API operations are performed over SSL, and are mutually authenticated using X.509 v3 certificates. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460799.aspx for more information) The Begin Deleting Data Disk operation removes the specified data disk from a virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157179.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineDiskOperations. Required. The name of your service. Required. The name of the deployment. Required. The name of the role to delete the data disk from. Required. The logical unit number of the disk. Required. Specifies that the source blob for the disk should also be deleted from storage. A standard service response including an HTTP status code and request ID. The Begin Deleting Data Disk operation removes the specified data disk from a virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157179.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineDiskOperations. Required. The name of your service. Required. The name of the deployment. Required. The name of the role to delete the data disk from. Required. The logical unit number of the disk. Required. Specifies that the source blob for the disk should also be deleted from storage. A standard service response including an HTTP status code and request ID. The Create Data Disk operation adds a data disk to a virtual machine. There are three ways to create the data disk using the Add Data Disk operation. Option 1 - Attach an empty data disk to the role by specifying the disk label and location of the disk image. Do not include the DiskName and SourceMediaLink elements in the request body. Include the MediaLink element and reference a blob that is in the same geographical region as the role. You can also omit the MediaLink element. In this usage, Azure will create the data disk in the storage account configured as default for the role. Option 2 - Attach an existing data disk that is in the image repository. Do not include the DiskName and SourceMediaLink elements in the request body. Specify the data disk to use by including the DiskName element. Note: If included the in the response body, the MediaLink and LogicalDiskSizeInGB elements are ignored. Option 3 - Specify the location of a blob in your storage account that contain a disk image to use. Include the SourceMediaLink element. Note: If the MediaLink element isincluded, it is ignored. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157199.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineDiskOperations. Required. The name of your service. Required. The name of the deployment. Required. The name of the role to add the data disk to. Required. Parameters supplied to the Create Virtual Machine Data Disk operation. A standard service response including an HTTP status code and request ID. The Create Data Disk operation adds a data disk to a virtual machine. There are three ways to create the data disk using the Add Data Disk operation. Option 1 - Attach an empty data disk to the role by specifying the disk label and location of the disk image. Do not include the DiskName and SourceMediaLink elements in the request body. Include the MediaLink element and reference a blob that is in the same geographical region as the role. You can also omit the MediaLink element. In this usage, Azure will create the data disk in the storage account configured as default for the role. Option 2 - Attach an existing data disk that is in the image repository. Do not include the DiskName and SourceMediaLink elements in the request body. Specify the data disk to use by including the DiskName element. Note: If included the in the response body, the MediaLink and LogicalDiskSizeInGB elements are ignored. Option 3 - Specify the location of a blob in your storage account that contain a disk image to use. Include the SourceMediaLink element. Note: If the MediaLink element isincluded, it is ignored. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157199.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineDiskOperations. Required. The name of your service. Required. The name of the deployment. Required. The name of the role to add the data disk to. Required. Parameters supplied to the Create Virtual Machine Data Disk operation. A standard service response including an HTTP status code and request ID. The Create Disk operation adds a disk to the user image repository. The disk can be an operating system disk or a data disk. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157178.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineDiskOperations. Required. Parameters supplied to the Create Virtual Machine Disk operation. A virtual machine disk associated with your subscription. The Create Disk operation adds a disk to the user image repository. The disk can be an operating system disk or a data disk. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157178.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineDiskOperations. Required. Parameters supplied to the Create Virtual Machine Disk operation. A virtual machine disk associated with your subscription. The Delete Data Disk operation removes the specified data disk from a virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157179.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineDiskOperations. Required. The name of your service. Required. The name of the deployment. Required. The name of the role to delete the data disk from. Required. The logical unit number of the disk. Required. Specifies that the source blob for the disk should also be deleted from storage. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Data Disk operation removes the specified data disk from a virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157179.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineDiskOperations. Required. The name of your service. Required. The name of the deployment. Required. The name of the role to delete the data disk from. Required. The logical unit number of the disk. Required. Specifies that the source blob for the disk should also be deleted from storage. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Disk operation deletes the specified data or operating system disk from your image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157200.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineDiskOperations. Required. The name of the disk to delete. Required. Specifies that the source blob for the disk should also be deleted from storage. A standard service response including an HTTP status code and request ID. The Delete Disk operation deletes the specified data or operating system disk from your image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157200.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineDiskOperations. Required. The name of the disk to delete. Required. Specifies that the source blob for the disk should also be deleted from storage. A standard service response including an HTTP status code and request ID. The Get Data Disk operation retrieves the specified data disk from a virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157180.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineDiskOperations. Required. The name of your service. Required. The name of the deployment. Required. The name of the role. Required. The logical unit number of the disk. The Get Data Disk operation response. The Get Data Disk operation retrieves the specified data disk from a virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157180.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineDiskOperations. Required. The name of your service. Required. The name of the deployment. Required. The name of the role. Required. The logical unit number of the disk. The Get Data Disk operation response. The Get Disk operation retrieves a disk from the user image repository. The disk can be an operating system disk or a data disk. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157178.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineDiskOperations. Required. The name of the disk. A virtual machine disk associated with your subscription. The Get Disk operation retrieves a disk from the user image repository. The disk can be an operating system disk or a data disk. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157178.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineDiskOperations. Required. The name of the disk. A virtual machine disk associated with your subscription. The List Disks operation retrieves a list of the disks in your image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157176.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineDiskOperations. The List Disks operation response. The List Disks operation retrieves a list of the disks in your image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157176.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineDiskOperations. The List Disks operation response. The Update Data Disk operation updates the specified data disk attached to the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157190.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineDiskOperations. Required. The name of your service. Required. The name of the deployment. Required. The name of the role to add the data disk to. Required. The logical unit number of the disk. Required. Parameters supplied to the Update Virtual Machine Data Disk operation. A standard service response including an HTTP status code and request ID. The Update Data Disk operation updates the specified data disk attached to the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157190.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineDiskOperations. Required. The name of your service. Required. The name of the deployment. Required. The name of the role to add the data disk to. Required. The logical unit number of the disk. Required. Parameters supplied to the Update Virtual Machine Data Disk operation. A standard service response including an HTTP status code and request ID. The Add Disk operation adds a disk to the user image repository. The disk can be an operating system disk or a data disk. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157178.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineDiskOperations. Required. The name of the disk being updated. Required. Parameters supplied to the Update Virtual Machine Disk operation. A virtual machine disk associated with your subscription. The Add Disk operation adds a disk to the user image repository. The disk can be an operating system disk or a data disk. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157178.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineDiskOperations. Required. The name of the disk being updated. Required. Parameters supplied to the Update Virtual Machine Disk operation. A virtual machine disk associated with your subscription. The Service Management API includes operations for managing the virtual machine extensions in your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157206.aspx for more information) Initializes a new instance of the VirtualMachineExtensionOperations class. Reference to the service client. The List Resource Extensions operation lists the resource extensions that are available to add to a Virtual Machine. In Azure, a process can run as a resource extension of a Virtual Machine. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as resource extensions to the Virtual Machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn495441.aspx for more information) Cancellation token. The List Resource Extensions operation response. The List Resource Extension Versions operation lists the versions of a resource extension that are available to add to a Virtual Machine. In Azure, a process can run as a resource extension of a Virtual Machine. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as resource extensions to the Virtual Machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn495440.aspx for more information) Required. The name of the publisher. Required. The name of the extension. Cancellation token. The List Resource Extensions operation response. Gets a reference to the Microsoft.WindowsAzure.Management.Compute.ComputeManagementClient. The Service Management API provides programmatic access to much of the functionality available through the Management Portal. The Service Management API is a REST API. All API operations are performed over SSL, and are mutually authenticated using X.509 v3 certificates. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460799.aspx for more information) The List Resource Extensions operation lists the resource extensions that are available to add to a Virtual Machine. In Azure, a process can run as a resource extension of a Virtual Machine. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as resource extensions to the Virtual Machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn495441.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineExtensionOperations. The List Resource Extensions operation response. The List Resource Extensions operation lists the resource extensions that are available to add to a Virtual Machine. In Azure, a process can run as a resource extension of a Virtual Machine. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as resource extensions to the Virtual Machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn495441.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineExtensionOperations. The List Resource Extensions operation response. The List Resource Extension Versions operation lists the versions of a resource extension that are available to add to a Virtual Machine. In Azure, a process can run as a resource extension of a Virtual Machine. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as resource extensions to the Virtual Machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn495440.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineExtensionOperations. Required. The name of the publisher. Required. The name of the extension. The List Resource Extensions operation response. The List Resource Extension Versions operation lists the versions of a resource extension that are available to add to a Virtual Machine. In Azure, a process can run as a resource extension of a Virtual Machine. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as resource extensions to the Virtual Machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn495440.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineExtensionOperations. Required. The name of the publisher. Required. The name of the extension. The List Resource Extensions operation response. The Service Management API includes operations for managing the virtual machines in your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157206.aspx for more information) Initializes a new instance of the VirtualMachineOperations class. Reference to the service client. The Begin Capturing Role operation creates a copy of the operating system virtual hard disk (VHD) that is deployed in the virtual machine, saves the VHD copy in the same storage location as the operating system VHD, and registers the copy as an image in your image gallery. From the captured image, you can create additional customized virtual machines. For more information about images and disks, see Manage Disks and Images at http://msdn.microsoft.com/en-us/library/windowsazure/jj672979.aspx. For more information about capturing images, see How to Capture an Image of a Virtual Machine Running Windows Server 2008 R2 at http://www.windowsazure.com/en-us/documentation/articles/virtual-machines-capture-image-windows-server/ or How to Capture an Image of a Virtual Machine Running Linux at http://www.windowsazure.com/en-us/documentation/articles/virtual-machines-linux-capture-image/. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157201.aspx for more information) Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to restart. Required. Parameters supplied to the Begin Capturing Virtual Machine operation. Cancellation token. A standard service response including an HTTP status code and request ID. Begin capturing role as VM template. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to restart. Required. Parameters supplied to the Capture Virtual Machine operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Creating Role operation adds a virtual machine to an existing deployment. You can refer to the OSDisk in the Add Role operation in the following ways: Platform/User Image - Set the SourceImageName to a platform or user image. You can optionally specify the DiskName and MediaLink values as part the operation to control the name and location of target disk. When DiskName and MediaLink are specified in this mode, they must not already exist in the system, otherwise a conflict fault is returned; UserDisk - Set DiskName to a user supplied image in image repository. SourceImageName must be set to NULL. All other properties are ignored; or Blob in a Storage Account - Set MediaLink to a blob containing the image. SourceImageName and DiskName are set to NULL. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157186.aspx for more information) Required. The name of your service. Required. The name of your deployment. Required. Parameters supplied to the Begin Creating Virtual Machine operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Creating Virtual Machine Deployment operation provisions a virtual machine based on the supplied configuration. When you create a deployment of a virtual machine, you should make sure that the cloud service and the disk or image that you use are located in the same region. For example, if the cloud service was created in the West US region, the disk or image that you use should also be located in a storage account in the West US region. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157194.aspx for more information) Required. The name of your service. Required. Parameters supplied to the Begin Creating Virtual Machine Deployment operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Deleting Role operation deletes the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157184.aspx for more information) Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to delete. Required. Specifies that the source blob(s) for the virtual machine should also be deleted from storage. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Restarting role operation restarts the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157197.aspx for more information) Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to restart. Cancellation token. A standard service response including an HTTP status code and request ID. The Shutdown Role operation shuts down the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157195.aspx for more information) Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to shutdown. Required. The parameters for the shutdown vm operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Shutting Down Roles operation stops the specified set of virtual machines. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469421.aspx for more information) Required. The name of your service. Required. The name of your deployment. Required. Parameters to pass to the Begin Shutting Down Roles operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Starting Role operation starts the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157189.aspx for more information) Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to start. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Starting Roles operation starts the specified set of virtual machines. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469419.aspx for more information) Required. The name of your service. Required. The name of your deployment. Required. Parameters to pass to the Begin Starting Roles operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Updating Role operation adds a virtual machine to an existing deployment. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157187.aspx for more information) Required. The name of your service. Required. The name of your deployment. Required. The name of your virtual machine. Required. Parameters supplied to the Begin Updating Virtual Machine operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Updating Load Balanced Endpoint Set operation changes the specified load-balanced InputEndpoints on all the roles of an Infrastructure as a Service deployment. Non-load-balanced endpoints must be changed using UpdateRole. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469417.aspx for more information) Required. The name of your service. Required. The name of your deployment. Required. Parameters supplied to the Begin Updating Load Balanced Endpoint Set operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Capture Role operation creates a copy of the operating system virtual hard disk (VHD) that is deployed in the virtual machine, saves the VHD copy in the same storage location as the operating system VHD, and registers the copy as an image in your image gallery. From the captured image, you can create additional customized virtual machines. For more information about images and disks, see Manage Disks and Images at http://msdn.microsoft.com/en-us/library/windowsazure/jj672979.aspx. For more information about capturing images, see How to Capture an Image of a Virtual Machine Running Windows Server 2008 R2 at http://www.windowsazure.com/en-us/documentation/articles/virtual-machines-capture-image-windows-server/ or How to Capture an Image of a Virtual Machine Running Linux at http://www.windowsazure.com/en-us/documentation/articles/virtual-machines-linux-capture-image/. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157201.aspx for more information) Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to restart. Required. Parameters supplied to the Capture Virtual Machine operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Capture role as VM template. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to restart. Required. Parameters supplied to the Capture Virtual Machine operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Create Role operation adds a virtual machine to an existing deployment. You can refer to the OSDisk in the Add Role operation in the following ways: Platform/User Image - Set the SourceImageName to a platform or user image. You can optionally specify the DiskName and MediaLink values as part the operation to control the name and location of target disk. When DiskName and MediaLink are specified in this mode, they must not already exist in the system, otherwise a conflict fault is returned; UserDisk - Set DiskName to a user supplied image in image repository. SourceImageName must be set to NULL. All other properties are ignored; or Blob in a Storage Account - Set MediaLink to a blob containing the image. SourceImageName and DiskName are set to NULL. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157186.aspx for more information) Required. The name of your service. Required. The name of your deployment. Required. Parameters supplied to the Create Virtual Machine operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Create Virtual Machine Deployment operation provisions a virtual machine based on the supplied configuration. When you create a deployment of a virtual machine, you should make sure that the cloud service and the disk or image that you use are located in the same region. For example, if the cloud service was created in the West US region, the disk or image that you use should also be located in a storage account in the West US region. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157194.aspx for more information) Required. The name of your service. Required. Parameters supplied to the Create Virtual Machine Deployment operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Role operation deletes the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157184.aspx for more information) Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to delete. Required. Specifies that the source blob(s) for the virtual machine should also be deleted from storage. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Get Role operation retrieves information about the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157193.aspx for more information) Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine. Cancellation token. The Get Virtual Machine operation response. The Download RDP file operation retrieves the Remote Desktop Protocol configuration file from the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157183.aspx for more information) Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine. Cancellation token. The Download RDP file operation response. The Restart role operation restarts the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157197.aspx for more information) Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to restart. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Shutdown Role operation shuts down the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157195.aspx for more information) Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to shutdown. Required. The parameters for the shutdown virtual machine operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Shutdown Roles operation stops the specified set of virtual machines. Required. The name of your service. Required. The name of your deployment. Required. Parameters to pass to the Shutdown Roles operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Start Role operation starts the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157189.aspx for more information) Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to start. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Start Roles operation starts the specified set of virtual machines. Required. The name of your service. Required. The name of your deployment. Required. Parameters to pass to the Start Roles operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Update Role operation adds a virtual machine to an existing deployment. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157187.aspx for more information) Required. The name of your service. Required. The name of your deployment. Required. The name of your virtual machine. Required. Parameters supplied to the Update Virtual Machine operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Update Load Balanced Endpoint Set operation changes the specified load-balanced InputEndpoints on all the roles of an Infrastructure as a Service deployment. Non-load-balanced endpoints must be changed using UpdateRole. Required. The name of your service. Required. The name of your deployment. Required. Parameters supplied to the Update Load Balanced Endpoint Set operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Gets a reference to the Microsoft.WindowsAzure.Management.Compute.ComputeManagementClient. The Service Management API provides programmatic access to much of the functionality available through the Management Portal. The Service Management API is a REST API. All API operations are performed over SSL, and are mutually authenticated using X.509 v3 certificates. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460799.aspx for more information) The Begin Capturing Role operation creates a copy of the operating system virtual hard disk (VHD) that is deployed in the virtual machine, saves the VHD copy in the same storage location as the operating system VHD, and registers the copy as an image in your image gallery. From the captured image, you can create additional customized virtual machines. For more information about images and disks, see Manage Disks and Images at http://msdn.microsoft.com/en-us/library/windowsazure/jj672979.aspx. For more information about capturing images, see How to Capture an Image of a Virtual Machine Running Windows Server 2008 R2 at http://www.windowsazure.com/en-us/documentation/articles/virtual-machines-capture-image-windows-server/ or How to Capture an Image of a Virtual Machine Running Linux at http://www.windowsazure.com/en-us/documentation/articles/virtual-machines-linux-capture-image/. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157201.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to restart. Required. Parameters supplied to the Begin Capturing Virtual Machine operation. A standard service response including an HTTP status code and request ID. The Begin Capturing Role operation creates a copy of the operating system virtual hard disk (VHD) that is deployed in the virtual machine, saves the VHD copy in the same storage location as the operating system VHD, and registers the copy as an image in your image gallery. From the captured image, you can create additional customized virtual machines. For more information about images and disks, see Manage Disks and Images at http://msdn.microsoft.com/en-us/library/windowsazure/jj672979.aspx. For more information about capturing images, see How to Capture an Image of a Virtual Machine Running Windows Server 2008 R2 at http://www.windowsazure.com/en-us/documentation/articles/virtual-machines-capture-image-windows-server/ or How to Capture an Image of a Virtual Machine Running Linux at http://www.windowsazure.com/en-us/documentation/articles/virtual-machines-linux-capture-image/. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157201.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to restart. Required. Parameters supplied to the Begin Capturing Virtual Machine operation. A standard service response including an HTTP status code and request ID. Begin capturing role as VM template. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to restart. Required. Parameters supplied to the Capture Virtual Machine operation. A standard service response including an HTTP status code and request ID. Begin capturing role as VM template. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to restart. Required. Parameters supplied to the Capture Virtual Machine operation. A standard service response including an HTTP status code and request ID. The Begin Creating Role operation adds a virtual machine to an existing deployment. You can refer to the OSDisk in the Add Role operation in the following ways: Platform/User Image - Set the SourceImageName to a platform or user image. You can optionally specify the DiskName and MediaLink values as part the operation to control the name and location of target disk. When DiskName and MediaLink are specified in this mode, they must not already exist in the system, otherwise a conflict fault is returned; UserDisk - Set DiskName to a user supplied image in image repository. SourceImageName must be set to NULL. All other properties are ignored; or Blob in a Storage Account - Set MediaLink to a blob containing the image. SourceImageName and DiskName are set to NULL. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157186.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. Parameters supplied to the Begin Creating Virtual Machine operation. A standard service response including an HTTP status code and request ID. The Begin Creating Role operation adds a virtual machine to an existing deployment. You can refer to the OSDisk in the Add Role operation in the following ways: Platform/User Image - Set the SourceImageName to a platform or user image. You can optionally specify the DiskName and MediaLink values as part the operation to control the name and location of target disk. When DiskName and MediaLink are specified in this mode, they must not already exist in the system, otherwise a conflict fault is returned; UserDisk - Set DiskName to a user supplied image in image repository. SourceImageName must be set to NULL. All other properties are ignored; or Blob in a Storage Account - Set MediaLink to a blob containing the image. SourceImageName and DiskName are set to NULL. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157186.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. Parameters supplied to the Begin Creating Virtual Machine operation. A standard service response including an HTTP status code and request ID. The Begin Creating Virtual Machine Deployment operation provisions a virtual machine based on the supplied configuration. When you create a deployment of a virtual machine, you should make sure that the cloud service and the disk or image that you use are located in the same region. For example, if the cloud service was created in the West US region, the disk or image that you use should also be located in a storage account in the West US region. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157194.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. Parameters supplied to the Begin Creating Virtual Machine Deployment operation. A standard service response including an HTTP status code and request ID. The Begin Creating Virtual Machine Deployment operation provisions a virtual machine based on the supplied configuration. When you create a deployment of a virtual machine, you should make sure that the cloud service and the disk or image that you use are located in the same region. For example, if the cloud service was created in the West US region, the disk or image that you use should also be located in a storage account in the West US region. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157194.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. Parameters supplied to the Begin Creating Virtual Machine Deployment operation. A standard service response including an HTTP status code and request ID. The Begin Deleting Role operation deletes the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157184.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to delete. Required. Specifies that the source blob(s) for the virtual machine should also be deleted from storage. A standard service response including an HTTP status code and request ID. The Begin Deleting Role operation deletes the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157184.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to delete. Required. Specifies that the source blob(s) for the virtual machine should also be deleted from storage. A standard service response including an HTTP status code and request ID. The Begin Restarting role operation restarts the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157197.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to restart. A standard service response including an HTTP status code and request ID. The Begin Restarting role operation restarts the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157197.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to restart. A standard service response including an HTTP status code and request ID. The Shutdown Role operation shuts down the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157195.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to shutdown. Required. The parameters for the shutdown vm operation. A standard service response including an HTTP status code and request ID. The Shutdown Role operation shuts down the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157195.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to shutdown. Required. The parameters for the shutdown vm operation. A standard service response including an HTTP status code and request ID. The Begin Shutting Down Roles operation stops the specified set of virtual machines. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469421.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. Parameters to pass to the Begin Shutting Down Roles operation. A standard service response including an HTTP status code and request ID. The Begin Shutting Down Roles operation stops the specified set of virtual machines. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469421.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. Parameters to pass to the Begin Shutting Down Roles operation. A standard service response including an HTTP status code and request ID. The Begin Starting Role operation starts the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157189.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to start. A standard service response including an HTTP status code and request ID. The Begin Starting Role operation starts the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157189.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to start. A standard service response including an HTTP status code and request ID. The Begin Starting Roles operation starts the specified set of virtual machines. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469419.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. Parameters to pass to the Begin Starting Roles operation. A standard service response including an HTTP status code and request ID. The Begin Starting Roles operation starts the specified set of virtual machines. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469419.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. Parameters to pass to the Begin Starting Roles operation. A standard service response including an HTTP status code and request ID. The Begin Updating Role operation adds a virtual machine to an existing deployment. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157187.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of your virtual machine. Required. Parameters supplied to the Begin Updating Virtual Machine operation. A standard service response including an HTTP status code and request ID. The Begin Updating Role operation adds a virtual machine to an existing deployment. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157187.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of your virtual machine. Required. Parameters supplied to the Begin Updating Virtual Machine operation. A standard service response including an HTTP status code and request ID. The Begin Updating Load Balanced Endpoint Set operation changes the specified load-balanced InputEndpoints on all the roles of an Infrastructure as a Service deployment. Non-load-balanced endpoints must be changed using UpdateRole. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469417.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. Parameters supplied to the Begin Updating Load Balanced Endpoint Set operation. A standard service response including an HTTP status code and request ID. The Begin Updating Load Balanced Endpoint Set operation changes the specified load-balanced InputEndpoints on all the roles of an Infrastructure as a Service deployment. Non-load-balanced endpoints must be changed using UpdateRole. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469417.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. Parameters supplied to the Begin Updating Load Balanced Endpoint Set operation. A standard service response including an HTTP status code and request ID. The Capture Role operation creates a copy of the operating system virtual hard disk (VHD) that is deployed in the virtual machine, saves the VHD copy in the same storage location as the operating system VHD, and registers the copy as an image in your image gallery. From the captured image, you can create additional customized virtual machines. For more information about images and disks, see Manage Disks and Images at http://msdn.microsoft.com/en-us/library/windowsazure/jj672979.aspx. For more information about capturing images, see How to Capture an Image of a Virtual Machine Running Windows Server 2008 R2 at http://www.windowsazure.com/en-us/documentation/articles/virtual-machines-capture-image-windows-server/ or How to Capture an Image of a Virtual Machine Running Linux at http://www.windowsazure.com/en-us/documentation/articles/virtual-machines-linux-capture-image/. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157201.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to restart. Required. Parameters supplied to the Capture Virtual Machine operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Capture Role operation creates a copy of the operating system virtual hard disk (VHD) that is deployed in the virtual machine, saves the VHD copy in the same storage location as the operating system VHD, and registers the copy as an image in your image gallery. From the captured image, you can create additional customized virtual machines. For more information about images and disks, see Manage Disks and Images at http://msdn.microsoft.com/en-us/library/windowsazure/jj672979.aspx. For more information about capturing images, see How to Capture an Image of a Virtual Machine Running Windows Server 2008 R2 at http://www.windowsazure.com/en-us/documentation/articles/virtual-machines-capture-image-windows-server/ or How to Capture an Image of a Virtual Machine Running Linux at http://www.windowsazure.com/en-us/documentation/articles/virtual-machines-linux-capture-image/. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157201.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to restart. Required. Parameters supplied to the Capture Virtual Machine operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Capture role as VM template. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to restart. Required. Parameters supplied to the Capture Virtual Machine operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Capture role as VM template. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to restart. Required. Parameters supplied to the Capture Virtual Machine operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Create Role operation adds a virtual machine to an existing deployment. You can refer to the OSDisk in the Add Role operation in the following ways: Platform/User Image - Set the SourceImageName to a platform or user image. You can optionally specify the DiskName and MediaLink values as part the operation to control the name and location of target disk. When DiskName and MediaLink are specified in this mode, they must not already exist in the system, otherwise a conflict fault is returned; UserDisk - Set DiskName to a user supplied image in image repository. SourceImageName must be set to NULL. All other properties are ignored; or Blob in a Storage Account - Set MediaLink to a blob containing the image. SourceImageName and DiskName are set to NULL. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157186.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. Parameters supplied to the Create Virtual Machine operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Create Role operation adds a virtual machine to an existing deployment. You can refer to the OSDisk in the Add Role operation in the following ways: Platform/User Image - Set the SourceImageName to a platform or user image. You can optionally specify the DiskName and MediaLink values as part the operation to control the name and location of target disk. When DiskName and MediaLink are specified in this mode, they must not already exist in the system, otherwise a conflict fault is returned; UserDisk - Set DiskName to a user supplied image in image repository. SourceImageName must be set to NULL. All other properties are ignored; or Blob in a Storage Account - Set MediaLink to a blob containing the image. SourceImageName and DiskName are set to NULL. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157186.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. Parameters supplied to the Create Virtual Machine operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Create Virtual Machine Deployment operation provisions a virtual machine based on the supplied configuration. When you create a deployment of a virtual machine, you should make sure that the cloud service and the disk or image that you use are located in the same region. For example, if the cloud service was created in the West US region, the disk or image that you use should also be located in a storage account in the West US region. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157194.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. Parameters supplied to the Create Virtual Machine Deployment operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Create Virtual Machine Deployment operation provisions a virtual machine based on the supplied configuration. When you create a deployment of a virtual machine, you should make sure that the cloud service and the disk or image that you use are located in the same region. For example, if the cloud service was created in the West US region, the disk or image that you use should also be located in a storage account in the West US region. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157194.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. Parameters supplied to the Create Virtual Machine Deployment operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Role operation deletes the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157184.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to delete. Required. Specifies that the source blob(s) for the virtual machine should also be deleted from storage. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Role operation deletes the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157184.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to delete. Required. Specifies that the source blob(s) for the virtual machine should also be deleted from storage. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Get Role operation retrieves information about the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157193.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine. The Get Virtual Machine operation response. The Get Role operation retrieves information about the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157193.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine. The Get Virtual Machine operation response. The Download RDP file operation retrieves the Remote Desktop Protocol configuration file from the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157183.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine. The Download RDP file operation response. The Download RDP file operation retrieves the Remote Desktop Protocol configuration file from the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157183.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine. The Download RDP file operation response. The Restart role operation restarts the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157197.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to restart. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Restart role operation restarts the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157197.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to restart. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Shutdown Role operation shuts down the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157195.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to shutdown. Required. The parameters for the shutdown virtual machine operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Shutdown Role operation shuts down the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157195.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to shutdown. Required. The parameters for the shutdown virtual machine operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Shutdown Roles operation stops the specified set of virtual machines. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. Parameters to pass to the Shutdown Roles operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Shutdown Roles operation stops the specified set of virtual machines. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. Parameters to pass to the Shutdown Roles operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Start Role operation starts the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157189.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to start. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Start Role operation starts the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157189.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to start. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Start Roles operation starts the specified set of virtual machines. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. Parameters to pass to the Start Roles operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Start Roles operation starts the specified set of virtual machines. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. Parameters to pass to the Start Roles operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Update Role operation adds a virtual machine to an existing deployment. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157187.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of your virtual machine. Required. Parameters supplied to the Update Virtual Machine operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Update Role operation adds a virtual machine to an existing deployment. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157187.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of your virtual machine. Required. Parameters supplied to the Update Virtual Machine operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Update Load Balanced Endpoint Set operation changes the specified load-balanced InputEndpoints on all the roles of an Infrastructure as a Service deployment. Non-load-balanced endpoints must be changed using UpdateRole. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. Parameters supplied to the Update Load Balanced Endpoint Set operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Update Load Balanced Endpoint Set operation changes the specified load-balanced InputEndpoints on all the roles of an Infrastructure as a Service deployment. Non-load-balanced endpoints must be changed using UpdateRole. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. Parameters supplied to the Update Load Balanced Endpoint Set operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Service Management API includes operations for managing the OS images in your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157175.aspx for more information) Initializes a new instance of the VirtualMachineOSImageOperations class. Reference to the service client. Share an already replicated OS image. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Required. The name of the virtual machine image to share. Required. The sharing permission: public, msdn, or private. Cancellation token. A standard service response including an HTTP status code and request ID. Unreplicate an OS image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Note: The operation removes the published copies of the user OS Image. It does not remove the actual user OS Image. To remove the actual user OS Image, the publisher will have to call Delete OS Image. Required. The name of the virtual machine image to replicate. Note: The OS Image Name should be the user OS Image, not the published name of the OS Image. Cancellation token. A standard service response including an HTTP status code and request ID. The Create OS Image operation adds an operating system image that is stored in a storage account and is available from the image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157192.aspx for more information) Required. Parameters supplied to the Create Virtual Machine Image operation. Cancellation token. Parameters returned from the Create Virtual Machine Image operation. The Delete OS Image operation deletes the specified OS image from your image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157203.aspx for more information) Required. The name of the image to delete. Required. Specifies that the source blob for the image should also be deleted from storage. Cancellation token. A standard service response including an HTTP status code and request ID. The Get OS Image operation retrieves the details for an operating system image from the image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157191.aspx for more information) Required. The name of the OS image to retrieve. Cancellation token. A virtual machine image associated with your subscription. Gets OS Image's properties and its replication details. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Required. The name of the virtual machine image to replicate. Cancellation token. The Get Details OS Images operation response. The List OS Images operation retrieves a list of the operating system images from the image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157191.aspx for more information) Cancellation token. The List OS Images operation response. Replicate an OS image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Required. The name of the virtual machine OS image to replicate. Required. Parameters supplied to the Replicate Virtual Machine Image operation. Cancellation token. The response body contains the published name of the image. Share an already replicated OS image. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Required. The name of the virtual machine image to share. Required. The sharing permission: public, msdn, or private. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Unreplicate an OS image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Note: The operation removes the published copies of the user OS Image. It does not remove the actual user OS Image. To remove the actual user OS Image, the publisher will have to call Delete OS Image. Required. The name of the virtual machine image to replicate. Note: The OS Image Name should be the user OS Image, not the published name of the OS Image. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Update OS Image operation updates an OS image that in your image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157198.aspx for more information) Required. The name of the virtual machine image to be updated. Required. Parameters supplied to the Update Virtual Machine Image operation. Cancellation token. Parameters returned from the Create Virtual Machine Image operation. Gets a reference to the Microsoft.WindowsAzure.Management.Compute.ComputeManagementClient. The Service Management API provides programmatic access to much of the functionality available through the Management Portal. The Service Management API is a REST API. All API operations are performed over SSL, and are mutually authenticated using X.509 v3 certificates. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460799.aspx for more information) Share an already replicated OS image. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOSImageOperations. Required. The name of the virtual machine image to share. Required. The sharing permission: public, msdn, or private. A standard service response including an HTTP status code and request ID. Share an already replicated OS image. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOSImageOperations. Required. The name of the virtual machine image to share. Required. The sharing permission: public, msdn, or private. A standard service response including an HTTP status code and request ID. Unreplicate an OS image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Note: The operation removes the published copies of the user OS Image. It does not remove the actual user OS Image. To remove the actual user OS Image, the publisher will have to call Delete OS Image. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOSImageOperations. Required. The name of the virtual machine image to replicate. Note: The OS Image Name should be the user OS Image, not the published name of the OS Image. A standard service response including an HTTP status code and request ID. Unreplicate an OS image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Note: The operation removes the published copies of the user OS Image. It does not remove the actual user OS Image. To remove the actual user OS Image, the publisher will have to call Delete OS Image. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOSImageOperations. Required. The name of the virtual machine image to replicate. Note: The OS Image Name should be the user OS Image, not the published name of the OS Image. A standard service response including an HTTP status code and request ID. The Create OS Image operation adds an operating system image that is stored in a storage account and is available from the image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157192.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOSImageOperations. Required. Parameters supplied to the Create Virtual Machine Image operation. Parameters returned from the Create Virtual Machine Image operation. The Create OS Image operation adds an operating system image that is stored in a storage account and is available from the image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157192.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOSImageOperations. Required. Parameters supplied to the Create Virtual Machine Image operation. Parameters returned from the Create Virtual Machine Image operation. The Delete OS Image operation deletes the specified OS image from your image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157203.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOSImageOperations. Required. The name of the image to delete. Required. Specifies that the source blob for the image should also be deleted from storage. A standard service response including an HTTP status code and request ID. The Delete OS Image operation deletes the specified OS image from your image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157203.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOSImageOperations. Required. The name of the image to delete. Required. Specifies that the source blob for the image should also be deleted from storage. A standard service response including an HTTP status code and request ID. The Get OS Image operation retrieves the details for an operating system image from the image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157191.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOSImageOperations. Required. The name of the OS image to retrieve. A virtual machine image associated with your subscription. The Get OS Image operation retrieves the details for an operating system image from the image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157191.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOSImageOperations. Required. The name of the OS image to retrieve. A virtual machine image associated with your subscription. Gets OS Image's properties and its replication details. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOSImageOperations. Required. The name of the virtual machine image to replicate. The Get Details OS Images operation response. Gets OS Image's properties and its replication details. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOSImageOperations. Required. The name of the virtual machine image to replicate. The Get Details OS Images operation response. The List OS Images operation retrieves a list of the operating system images from the image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157191.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOSImageOperations. The List OS Images operation response. The List OS Images operation retrieves a list of the operating system images from the image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157191.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOSImageOperations. The List OS Images operation response. Replicate an OS image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOSImageOperations. Required. The name of the virtual machine OS image to replicate. Required. Parameters supplied to the Replicate Virtual Machine Image operation. The response body contains the published name of the image. Replicate an OS image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOSImageOperations. Required. The name of the virtual machine OS image to replicate. Required. Parameters supplied to the Replicate Virtual Machine Image operation. The response body contains the published name of the image. Share an already replicated OS image. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOSImageOperations. Required. The name of the virtual machine image to share. Required. The sharing permission: public, msdn, or private. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Share an already replicated OS image. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOSImageOperations. Required. The name of the virtual machine image to share. Required. The sharing permission: public, msdn, or private. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Unreplicate an OS image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Note: The operation removes the published copies of the user OS Image. It does not remove the actual user OS Image. To remove the actual user OS Image, the publisher will have to call Delete OS Image. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOSImageOperations. Required. The name of the virtual machine image to replicate. Note: The OS Image Name should be the user OS Image, not the published name of the OS Image. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Unreplicate an OS image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Note: The operation removes the published copies of the user OS Image. It does not remove the actual user OS Image. To remove the actual user OS Image, the publisher will have to call Delete OS Image. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOSImageOperations. Required. The name of the virtual machine image to replicate. Note: The OS Image Name should be the user OS Image, not the published name of the OS Image. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Update OS Image operation updates an OS image that in your image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157198.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOSImageOperations. Required. The name of the virtual machine image to be updated. Required. Parameters supplied to the Update Virtual Machine Image operation. Parameters returned from the Create Virtual Machine Image operation. The Update OS Image operation updates an OS image that in your image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157198.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOSImageOperations. Required. The name of the virtual machine image to be updated. Required. Parameters supplied to the Update Virtual Machine Image operation. Parameters returned from the Create Virtual Machine Image operation. The Service Management API includes operations for managing the virtual machine templates in your subscription. Initializes a new instance of the VirtualMachineVMImageOperations class. Reference to the service client. The Begin Deleting Virtual Machine Image operation deletes the specified virtual machine image. Required. The name of the virtual machine image to delete. Required. Specifies that the source blob for the image should also be deleted from storage. Cancellation token. A standard service response including an HTTP status code and request ID. Share an already replicated VM image. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Required. The name of the virtual machine image to share. Required. The sharing permission: public, msdn, or private. Cancellation token. A standard service response including an HTTP status code and request ID. Unreplicate an VM image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Note: The operation removes the published copies of the user VM Image. It does not remove the actual user VM Image. To remove the actual user VM Image, the publisher will have to call Delete VM Image. Required. The name of the virtual machine image to replicate. Note: The VM Image Name should be the user VM Image, not the published name of the VM Image. Cancellation token. A standard service response including an HTTP status code and request ID. The Delete Virtual Machine Image operation deletes the specified virtual machine image. Required. The name of the virtual machine image to delete. Required. Specifies that the source blob for the image should also be deleted from storage. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Gets VMImage's properties and its replication details. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Required. The name of the virtual machine image to replicate. Cancellation token. The Get Details VM Images operation response. The List Virtual Machine Images operation retrieves a list of the virtual machine images. Cancellation token. The List VM Images operation response. Replicate an VM image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Required. The name of the virtual machine image to replicate. Required. Parameters supplied to the Replicate Virtual Machine Image operation. Cancellation token. The response body contains the published name of the image. Share an already replicated VM image. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Required. The name of the virtual machine image to share. Required. The sharing permission: public, msdn, or private. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Unreplicate an VM image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Note: The operation removes the published copies of the user VM Image. It does not remove the actual user VM Image. To remove the actual user VM Image, the publisher will have to call Delete VM Image. Required. The name of the virtual machine image to replicate. Note: The VM Image Name should be the user VM Image, not the published name of the VM Image. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Update VM Image operation updates a VM image that in your image repository. Required. The name of the virtual machine image to be updated. Required. Parameters supplied to the Update Virtual Machine Image operation. Cancellation token. A standard service response including an HTTP status code and request ID. Gets a reference to the Microsoft.WindowsAzure.Management.Compute.ComputeManagementClient. The Service Management API provides programmatic access to much of the functionality available through the Management Portal. The Service Management API is a REST API. All API operations are performed over SSL, and are mutually authenticated using X.509 v3 certificates. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460799.aspx for more information) The Begin Deleting Virtual Machine Image operation deletes the specified virtual machine image. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineVMImageOperations. Required. The name of the virtual machine image to delete. Required. Specifies that the source blob for the image should also be deleted from storage. A standard service response including an HTTP status code and request ID. The Begin Deleting Virtual Machine Image operation deletes the specified virtual machine image. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineVMImageOperations. Required. The name of the virtual machine image to delete. Required. Specifies that the source blob for the image should also be deleted from storage. A standard service response including an HTTP status code and request ID. Share an already replicated VM image. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineVMImageOperations. Required. The name of the virtual machine image to share. Required. The sharing permission: public, msdn, or private. A standard service response including an HTTP status code and request ID. Share an already replicated VM image. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineVMImageOperations. Required. The name of the virtual machine image to share. Required. The sharing permission: public, msdn, or private. A standard service response including an HTTP status code and request ID. Unreplicate an VM image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Note: The operation removes the published copies of the user VM Image. It does not remove the actual user VM Image. To remove the actual user VM Image, the publisher will have to call Delete VM Image. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineVMImageOperations. Required. The name of the virtual machine image to replicate. Note: The VM Image Name should be the user VM Image, not the published name of the VM Image. A standard service response including an HTTP status code and request ID. Unreplicate an VM image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Note: The operation removes the published copies of the user VM Image. It does not remove the actual user VM Image. To remove the actual user VM Image, the publisher will have to call Delete VM Image. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineVMImageOperations. Required. The name of the virtual machine image to replicate. Note: The VM Image Name should be the user VM Image, not the published name of the VM Image. A standard service response including an HTTP status code and request ID. The Delete Virtual Machine Image operation deletes the specified virtual machine image. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineVMImageOperations. Required. The name of the virtual machine image to delete. Required. Specifies that the source blob for the image should also be deleted from storage. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Virtual Machine Image operation deletes the specified virtual machine image. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineVMImageOperations. Required. The name of the virtual machine image to delete. Required. Specifies that the source blob for the image should also be deleted from storage. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Gets VMImage's properties and its replication details. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineVMImageOperations. Required. The name of the virtual machine image to replicate. The Get Details VM Images operation response. Gets VMImage's properties and its replication details. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineVMImageOperations. Required. The name of the virtual machine image to replicate. The Get Details VM Images operation response. The List Virtual Machine Images operation retrieves a list of the virtual machine images. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineVMImageOperations. The List VM Images operation response. The List Virtual Machine Images operation retrieves a list of the virtual machine images. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineVMImageOperations. The List VM Images operation response. Replicate an VM image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineVMImageOperations. Required. The name of the virtual machine image to replicate. Required. Parameters supplied to the Replicate Virtual Machine Image operation. The response body contains the published name of the image. Replicate an VM image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineVMImageOperations. Required. The name of the virtual machine image to replicate. Required. Parameters supplied to the Replicate Virtual Machine Image operation. The response body contains the published name of the image. Share an already replicated VM image. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineVMImageOperations. Required. The name of the virtual machine image to share. Required. The sharing permission: public, msdn, or private. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Share an already replicated VM image. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineVMImageOperations. Required. The name of the virtual machine image to share. Required. The sharing permission: public, msdn, or private. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Unreplicate an VM image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Note: The operation removes the published copies of the user VM Image. It does not remove the actual user VM Image. To remove the actual user VM Image, the publisher will have to call Delete VM Image. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineVMImageOperations. Required. The name of the virtual machine image to replicate. Note: The VM Image Name should be the user VM Image, not the published name of the VM Image. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Unreplicate an VM image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Note: The operation removes the published copies of the user VM Image. It does not remove the actual user VM Image. To remove the actual user VM Image, the publisher will have to call Delete VM Image. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineVMImageOperations. Required. The name of the virtual machine image to replicate. Note: The VM Image Name should be the user VM Image, not the published name of the VM Image. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Update VM Image operation updates a VM image that in your image repository. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineVMImageOperations. Required. The name of the virtual machine image to be updated. Required. Parameters supplied to the Update Virtual Machine Image operation. A standard service response including an HTTP status code and request ID. The Update VM Image operation updates a VM image that in your image repository. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineVMImageOperations. Required. The name of the virtual machine image to be updated. Required. Parameters supplied to the Update Virtual Machine Image operation. A standard service response including an HTTP status code and request ID. ================================================ FILE: ironclad-apps/tools/NuBuild/References/Microsoft.WindowsAzure.Management.Storage.xml ================================================ Microsoft.WindowsAzure.Management.Storage The Service Management API includes operations for managing the storage accounts beneath your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460790.aspx for more information) The Begin Creating Storage Account operation creates a new storage account in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh264518.aspx for more information) Parameters supplied to the Begin Creating Storage Account operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Check Name Availability operation checks if a storage account name is available for use in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj154125.aspx for more information) The desired storage account name to check for availability. Cancellation token. The response to a storage account check name availability request. The Create Storage Account operation creates a new storage account in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh264518.aspx for more information) Parameters supplied to the Create Storage Account operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Storage Account operation deletes the specified storage account from Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh264517.aspx for more information) The name of the storage account to be deleted. Cancellation token. A standard service response including an HTTP status code and request ID. The Get Storage Account Properties operation returns system properties for the specified storage account. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460802.aspx for more information) Name of the storage account to get properties for. Cancellation token. The Get Storage Account Properties operation response. The Get Storage Keys operation returns the primary and secondary access keys for the specified storage account. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460785.aspx for more information) The name of the desired storage account. Cancellation token. The primary and secondary access keys for a storage account. The List Storage Accounts operation lists the storage accounts available under the current subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460787.aspx for more information) Cancellation token. The List Storage Accounts operation response. The Regenerate Keys operation regenerates the primary or secondary access key for the specified storage account. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460795.aspx for more information) Parameters supplied to the Regenerate Keys operation. Cancellation token. The primary and secondary access keys for a storage account. The Update Storage Account operation updates the label and the description, and enables or disables the geo-replication status for a storage account in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh264516.aspx for more information) Name of the storage account to update. Parameters supplied to the Update Storage Account operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Service Management API provides programmatic access to much of the functionality available through the Management Portal. The Service Management API is a REST API. All API operations are performed over SSL and are mutually authenticated using X.509 v3 certificates. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460799.aspx for more information) The Get Operation Status operation returns the status of the specified operation. After calling an asynchronous operation, you can call Get Operation Status to determine whether the operation has succeeded, failed, or is still in progress. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460783.aspx for more information) The request ID for the request you wish to track. The request ID is returned in the x-ms-request-id response header for every request. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Gets the API version. Gets the URI used as the base for all cloud service requests. Gets subscription credentials which uniquely identify Microsoft Azure subscription. The subscription ID forms part of the URI for every service call. Gets or sets the initial timeout for Long Running Operations. Gets or sets the retry timeout for Long Running Operations. The Service Management API includes operations for managing the storage accounts beneath your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460790.aspx for more information) The response to a storage account check name availability request. Initializes a new instance of the CheckNameAvailabilityResponse class. Optional. The result of the availability request indicating if the name is available. Optional. The reason for unavailability, if the requested name is unavailable. The geographical region in which a storage account exists. Indicates whether the storage region is available. A Storage Service associated with your subscription. Initializes a new instance of the StorageAccount class. Optional. Represents the name of an extended storage account property. Each extended property must have both a defined name and a value. You can have a maximum of 50 extended property name/value pairs. The maximum length of the Name element is 64 characters, only alphanumeric characters and underscores are valid in the Name, and the name must start with a letter. Attempting to use other characters, starting the Name with a non-letter character, or entering a name that is identical to that of another extended property owned by the same storage account, will result in a status code 400 (Bad Request) error. Each extended property value has a maximum length of 255 characters. Optional. The name of the storage account. This name is the DNS prefix name and can be used to access blobs, queues, and tables in the storage account. For example, if the service name is MyStorageAccount, you could access the blob containers by calling: http://MyStorageAccount.blob.core.windows.net/mycontainer/. Optional. Details about the storage account. Optional. The Service Management API request URI used to perform Get Storage Account Properties requests against the storage account. Parameters supplied to the Create Storage Account operation. Initializes a new instance of the StorageAccountCreateParameters class. Optional. The name of an existing affinity group in the specified subscription. Required if Location is not specified. You can include either a Location or AffinityGroup element in the request body, but not both. To list available affinity groups, use the List Affinity Groups operation. Optional. A description for the storage account. The description may be up to 1024 characters in length. Optional. Represents the name of an extended storage account property. Each extended property must have a defined name and a value. You can have a maximum of 50 extended property name/value pairs. The maximum length of the Name element is 64 characters, only alphanumeric characters and underscores are valid in the Name, and the name must start with a letter. Attempting to use other characters, starting the Name with a non-letter character, or entering a name that is identical to that of another extended property owned by the same storage account will result in a status code 400 (Bad Request) error. Each extended property value has a maximum length of 255 characters. Optional. Specifies whether the storage account is created with geo-replication enabled. If the element is not included in the request body, the default value is true. If set to true, the data in the storage account is replicated across more than one geographic location to enable resilience in the face of catastrophic service loss. Required. A name for the storage account, specified as abase64-encoded string. The name may be up to 100 characters in length. The name can be used identify the storage account for your tracking purposes. Optional. The location where the storage account is created. Required if AffinityGroup is not specified. You can include either a Location or AffinityGroup element in the request body, but not both. To list available locations, use the List Locations operation. Required. A name for the storage account, unique within Azure. Storage account names must be between 3 and 24 characters in length, and must use numbers and lower-case letters only. This name is the DNS prefix name and can be used to access blobs, queues, and tables in the storage account. For example: http://ServiceName.blob.core.windows.net/mycontainer/. The primary and secondary access keys for a storage account. Initializes a new instance of the StorageAccountGetKeysResponse class. Optional. The primary access key for the storage account. Optional. The secondary access key for the storage account. Optional. The Service Management API request URI used to perform Get Storage Account Properties requests against the storage account. The Get Storage Account Properties operation response. Initializes a new instance of the StorageAccountGetResponse class. Optional. The requested storage account. The List Storage Accounts operation response. Initializes a new instance of the StorageAccountListResponse class. Gets the sequence of StorageAccounts. Gets the sequence of StorageAccounts. Optional. The requested storage accounts. Details about a storage account. Initializes a new instance of the StorageAccountProperties class. Optional. The affinity group with which this storage account is associated. Optional. The user-supplied description of the storage account. Optional. The URLs that are used to perform a retrieval of a public blob, queue, or table object. Optional. Indicates the primary geographical region in which the storage account exists at this time. Optional. Indicates whether geo-replication is enabled.Geo-replication means data in the storage account is replicated across more than one geographic location so as to enable resilience in the face of catastrophic service loss. Optional. Indicates the geographical region in which the storage account is being replicated. The GeoSecondaryRegion element is not returned if geo-replication is "off" for this account. Optional. The user-supplied name of the storage account, returned as a base-64 encoded string. This name can be used identify the storage account for your tracking purposes. Optional. A timestamp that indicates the most recent instance of a failover to the secondary region. In the case of multiple failovers, only the latest failover date and time is maintained. The format of the returned timestamp is: [4DigitYear]-[2DigitMonth]-[2DigitDay]T[2DigitMinute]:[2DigitSecond]:[7DigitsOfPrecision]Z. LastGeoFailoverTime is not returned if there has not been an instance of a failover. Optional. The geo-location specified when the storage account was created. This property is only returned if the storage account is not associated with an affinity group. Optional. The status of the storage account at the time the operation was called. Optional. Indicates whether the primary storage region is available. Optional. Indicates whether the secondary storage region is available. Parameters supplied to the Regenerate Keys operation. Initializes a new instance of the StorageAccountRegenerateKeysParameters class. Required. Specifies which key to regenerate. Required. The name of the desired storage account. The primary and secondary access keys for a storage account. Initializes a new instance of the StorageAccountRegenerateKeysResponse class. Optional. The primary access key for the storage account. Optional. The secondary access key for the storage account. Optional. The Service Management API request URI used to perform Get Storage Account Properties requests against the storage account. The status of the storage account at the time the operation was called. The Storage Account has been created. The Storage Account is being created. The DNS name for the storage account is being propagated. The Storage Account is being deleted. Parameters supplied to the Update Storage Account operation. Initializes a new instance of the StorageAccountUpdateParameters class. Optional. Optional. Represents the name of an extended storage account property. Each extended property must have a defined name and a value. You can have a maximum of 50 extended property name/value pairs. The maximum length of the Name element is 64 characters, only alphanumeric characters and underscores are valid in the Name, and the name must start with a letter. Attempting to use other characters, starting the Name with a non-letter character, or entering a name that is identical to that of another extended property owned by the same storage account will result in a status code 400 (Bad Request) error. Each extended property value has a maximum length of 255 characters. You can delete an extended property by setting the value to NULL. Optional. Indicates whether geo-replication is enabled on the specified storage account. If set to true, the data in the storage account is replicated across more than one geographic location so as to enable resiliency in the face of catastrophic service loss. If the element is not included in the request body, the current value is left unchanged. Important: If you have enabled geo-replication, you can elect to disable it by setting this element to false. When disabled, your data is no longer replicated to a secondary data center and any data in the secondary location will be removed. Enabling geo-replication once it has been disabled will result in the storage account being billed for replicating the current copy of data to the secondary data center. After the existing copy of the data is replicated to the secondary data center, updates are geo-replicated at no additional charge. Optional. A name for the storage account, base64-encoded. The name may be up to 100 characters in length. The name can be used identify the storage account for your tracking purposes. Describes the type of a storage key. The Service Management API includes operations for managing the storage accounts beneath your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460790.aspx for more information) Initializes a new instance of the StorageAccountOperations class. Reference to the service client. The Begin Creating Storage Account operation creates a new storage account in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh264518.aspx for more information) Required. Parameters supplied to the Begin Creating Storage Account operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Check Name Availability operation checks if a storage account name is available for use in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj154125.aspx for more information) Required. The desired storage account name to check for availability. Cancellation token. The response to a storage account check name availability request. The Create Storage Account operation creates a new storage account in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh264518.aspx for more information) Required. Parameters supplied to the Create Storage Account operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Storage Account operation deletes the specified storage account from Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh264517.aspx for more information) Required. The name of the storage account to be deleted. Cancellation token. A standard service response including an HTTP status code and request ID. The Get Storage Account Properties operation returns system properties for the specified storage account. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460802.aspx for more information) Required. Name of the storage account to get properties for. Cancellation token. The Get Storage Account Properties operation response. The Get Storage Keys operation returns the primary and secondary access keys for the specified storage account. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460785.aspx for more information) Required. The name of the desired storage account. Cancellation token. The primary and secondary access keys for a storage account. The List Storage Accounts operation lists the storage accounts available under the current subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460787.aspx for more information) Cancellation token. The List Storage Accounts operation response. The Regenerate Keys operation regenerates the primary or secondary access key for the specified storage account. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460795.aspx for more information) Required. Parameters supplied to the Regenerate Keys operation. Cancellation token. The primary and secondary access keys for a storage account. The Update Storage Account operation updates the label and the description, and enables or disables the geo-replication status for a storage account in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh264516.aspx for more information) Required. Name of the storage account to update. Required. Parameters supplied to the Update Storage Account operation. Cancellation token. A standard service response including an HTTP status code and request ID. Gets a reference to the Microsoft.WindowsAzure.Management.Storage.StorageManagementClient. The Service Management API provides programmatic access to much of the functionality available through the Management Portal. The Service Management API is a REST API. All API operations are performed over SSL and are mutually authenticated using X.509 v3 certificates. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460799.aspx for more information) The Begin Creating Storage Account operation creates a new storage account in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh264518.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Storage.IStorageAccountOperations. Required. Parameters supplied to the Begin Creating Storage Account operation. A standard service response including an HTTP status code and request ID. The Begin Creating Storage Account operation creates a new storage account in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh264518.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Storage.IStorageAccountOperations. Required. Parameters supplied to the Begin Creating Storage Account operation. A standard service response including an HTTP status code and request ID. The Check Name Availability operation checks if a storage account name is available for use in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj154125.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Storage.IStorageAccountOperations. Required. The desired storage account name to check for availability. The response to a storage account check name availability request. The Check Name Availability operation checks if a storage account name is available for use in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj154125.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Storage.IStorageAccountOperations. Required. The desired storage account name to check for availability. The response to a storage account check name availability request. The Create Storage Account operation creates a new storage account in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh264518.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Storage.IStorageAccountOperations. Required. Parameters supplied to the Create Storage Account operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Create Storage Account operation creates a new storage account in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh264518.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Storage.IStorageAccountOperations. Required. Parameters supplied to the Create Storage Account operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Storage Account operation deletes the specified storage account from Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh264517.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Storage.IStorageAccountOperations. Required. The name of the storage account to be deleted. A standard service response including an HTTP status code and request ID. The Delete Storage Account operation deletes the specified storage account from Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh264517.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Storage.IStorageAccountOperations. Required. The name of the storage account to be deleted. A standard service response including an HTTP status code and request ID. The Get Storage Account Properties operation returns system properties for the specified storage account. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460802.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Storage.IStorageAccountOperations. Required. Name of the storage account to get properties for. The Get Storage Account Properties operation response. The Get Storage Account Properties operation returns system properties for the specified storage account. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460802.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Storage.IStorageAccountOperations. Required. Name of the storage account to get properties for. The Get Storage Account Properties operation response. The Get Storage Keys operation returns the primary and secondary access keys for the specified storage account. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460785.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Storage.IStorageAccountOperations. Required. The name of the desired storage account. The primary and secondary access keys for a storage account. The Get Storage Keys operation returns the primary and secondary access keys for the specified storage account. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460785.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Storage.IStorageAccountOperations. Required. The name of the desired storage account. The primary and secondary access keys for a storage account. The List Storage Accounts operation lists the storage accounts available under the current subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460787.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Storage.IStorageAccountOperations. The List Storage Accounts operation response. The List Storage Accounts operation lists the storage accounts available under the current subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460787.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Storage.IStorageAccountOperations. The List Storage Accounts operation response. The Regenerate Keys operation regenerates the primary or secondary access key for the specified storage account. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460795.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Storage.IStorageAccountOperations. Required. Parameters supplied to the Regenerate Keys operation. The primary and secondary access keys for a storage account. The Regenerate Keys operation regenerates the primary or secondary access key for the specified storage account. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460795.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Storage.IStorageAccountOperations. Required. Parameters supplied to the Regenerate Keys operation. The primary and secondary access keys for a storage account. The Update Storage Account operation updates the label and the description, and enables or disables the geo-replication status for a storage account in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh264516.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Storage.IStorageAccountOperations. Required. Name of the storage account to update. Required. Parameters supplied to the Update Storage Account operation. A standard service response including an HTTP status code and request ID. The Update Storage Account operation updates the label and the description, and enables or disables the geo-replication status for a storage account in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh264516.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Storage.IStorageAccountOperations. Required. Name of the storage account to update. Required. Parameters supplied to the Update Storage Account operation. A standard service response including an HTTP status code and request ID. The Service Management API provides programmatic access to much of the functionality available through the Management Portal. The Service Management API is a REST API. All API operations are performed over SSL and are mutually authenticated using X.509 v3 certificates. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460799.aspx for more information) Initializes a new instance of the StorageManagementClient class. Initializes a new instance of the StorageManagementClient class. Required. Gets subscription credentials which uniquely identify Microsoft Azure subscription. The subscription ID forms part of the URI for every service call. Required. Gets the URI used as the base for all cloud service requests. Initializes a new instance of the StorageManagementClient class. Required. Gets subscription credentials which uniquely identify Microsoft Azure subscription. The subscription ID forms part of the URI for every service call. Initializes a new instance of the StorageManagementClient class. The Http client Initializes a new instance of the StorageManagementClient class. Required. Gets subscription credentials which uniquely identify Microsoft Azure subscription. The subscription ID forms part of the URI for every service call. Required. Gets the URI used as the base for all cloud service requests. The Http client Initializes a new instance of the StorageManagementClient class. Required. Gets subscription credentials which uniquely identify Microsoft Azure subscription. The subscription ID forms part of the URI for every service call. The Http client Clones properties from current instance to another StorageManagementClient instance Instance of StorageManagementClient to clone to The Get Operation Status operation returns the status of the specified operation. After calling an asynchronous operation, you can call Get Operation Status to determine whether the operation has succeeded, failed, or is still in progress. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460783.aspx for more information) Required. The request ID for the request you wish to track. The request ID is returned in the x-ms-request-id response header for every request. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Gets the API version. Gets the URI used as the base for all cloud service requests. Gets subscription credentials which uniquely identify Microsoft Azure subscription. The subscription ID forms part of the URI for every service call. Gets or sets the initial timeout for Long Running Operations. Gets or sets the retry timeout for Long Running Operations. The Service Management API includes operations for managing the storage accounts beneath your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460790.aspx for more information) The Service Management API provides programmatic access to much of the functionality available through the Management Portal. The Service Management API is a REST API. All API operations are performed over SSL and are mutually authenticated using X.509 v3 certificates. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460799.aspx for more information) The Get Operation Status operation returns the status of the specified operation. After calling an asynchronous operation, you can call Get Operation Status to determine whether the operation has succeeded, failed, or is still in progress. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460783.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Storage.IStorageManagementClient. Required. The request ID for the request you wish to track. The request ID is returned in the x-ms-request-id response header for every request. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Get Operation Status operation returns the status of the specified operation. After calling an asynchronous operation, you can call Get Operation Status to determine whether the operation has succeeded, failed, or is still in progress. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460783.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Storage.IStorageManagementClient. Required. The request ID for the request you wish to track. The request ID is returned in the x-ms-request-id response header for every request. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. ================================================ FILE: ironclad-apps/tools/NuBuild/References/Microsoft.WindowsAzure.Storage.xml ================================================ Microsoft.WindowsAzure.Storage Represents the status of an asynchronous operation and provides support for cancellation. Cancels the asynchronous operation. Represents a handler that signs HTTP requests. Signs the specified HTTP request so it can be authenticated by the Windows Azure storage services. The HTTP request to sign. An object for tracking the current operation. Represents a handler that signs HTTP requests with no authentication information. Initializes a new instance of the class. Signs the specified HTTP request with no authentication information. The HTTP request to sign. An object for tracking the current operation. Represents a handler that signs HTTP requests with a shared key. Initializes a new instance of the class. A canonicalizer that converts HTTP request data into a standard form appropriate for signing. A object providing credentials for the request. The name of the storage account that the HTTP request will access. Signs the specified HTTP request with a shared key. The HTTP request to sign. An object for tracking the current operation. Represents a handler that signs HTTP requests with a shared key. Initializes a new instance of the class. A canonicalizer that converts HTTP request data into a standard form appropriate for signing. A object providing credentials for the request. The name of the storage account that the HTTP request will access. Signs the specified HTTP request with a shared key. The HTTP request to sign. An object for tracking the current operation. Initializes a new instance of the BlobReadStreamBase class. Blob reference to read from An object that represents the access conditions for the blob. If null, no condition is used. An object that specifies additional options for the request. An object for tracking the current operation. Sets the position within the current stream. A byte offset relative to the origin parameter. A value of type SeekOrigin indicating the reference point used to obtain the new position. The new position within the current stream. Seeking in a BlobReadStream disables MD5 validation. This operation is not supported in BlobReadStreamBase. Not used. This operation is not supported in BlobReadStreamBase. Not used. Not used. Not used. This operation is a no-op in BlobReadStreamBase. Read as much as we can from the internal buffer The buffer to read the data into. The byte offset in buffer at which to begin writing data read from the stream. The maximum number of bytes to read. Number of bytes read from the stream. Calculates the number of bytes to read from the blob. Number of bytes to read. Updates the blob MD5 with newly downloaded content. The buffer to read the data from. The byte offset in buffer at which to begin reading data. The maximum number of bytes to read. Releases the blob resources used by the Stream. true to release both managed and unmanaged resources; false to release only unmanaged resources. Gets a value indicating whether the current stream supports reading. Gets a value indicating whether the current stream supports seeking. Gets a value indicating whether the current stream supports writing. Gets or sets the position within the current stream. Gets the length in bytes of the stream. The length in bytes of the stream. Initializes a new instance of the BlobReadStream class. Blob reference to read from An object that represents the access conditions for the blob. If null, no condition is used. An object that specifies additional options for the request. An object for tracking the current operation. Reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read. The buffer to read the data into. The byte offset in buffer at which to begin writing data read from the stream. The maximum number of bytes to read. The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero (0) if the end of the stream has been reached. Begins an asynchronous read operation. The buffer to read the data into. The byte offset in buffer at which to begin writing data read from the stream. The maximum number of bytes to read. An optional asynchronous callback, to be called when the read is complete. A user-provided object that distinguishes this particular asynchronous read request from other requests. An IAsyncResult that represents the asynchronous read, which could still be pending. Waits for the pending asynchronous read to complete. The reference to the pending asynchronous request to finish. The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero (0) if the end of the stream has been reached. Dispatches an async read operation that either reads from the cache or makes a call to the server. The reference to the pending asynchronous request to finish. The buffer to read the data into. The byte offset in buffer at which to begin writing data read from the stream. The maximum number of bytes to read. Called when the asynchronous DownloadRangeToStream operation completes. The result of the asynchronous operation. Dispatches a sync read operation that either reads from the cache or makes a call to the server. The buffer to read the data into. The byte offset in buffer at which to begin writing data read from the stream. The maximum number of bytes to read. Number of bytes read from the stream. Represents a stream for writing to a blob. Clears all buffers for this stream, causes any buffered data to be written to the underlying blob, and commits the blob. Begins an asynchronous commit operation. An optional asynchronous callback, to be called when the commit is complete. A user-provided object that distinguishes this particular asynchronous commit request from other requests. An ICancellableAsyncResult that represents the asynchronous commit, which could still be pending. Waits for the pending asynchronous commit to complete. The reference to the pending asynchronous request to finish. Begins an asynchronous flush operation. An optional asynchronous callback, to be called when the flush is complete. A user-provided object that distinguishes this particular asynchronous flush request from other requests. An ICancellableAsyncResult that represents the asynchronous flush, which could still be pending. Waits for the pending asynchronous flush to complete. The reference to the pending asynchronous request to finish. Initializes a new instance of the BlobWriteStreamBase class. The service client. An object that represents the access conditions for the blob. If null, no condition is used. An object that specifies additional options for the request. An object for tracking the current operation. Initializes a new instance of the BlobWriteStreamBase class for a block blob. Blob reference to write to. An object that represents the access conditions for the blob. If null, no condition is used. An object that specifies additional options for the request. An object for tracking the current operation. Initializes a new instance of the BlobWriteStreamBase class for a page blob. Blob reference to write to. Size of the page blob. Use true if the page blob is newly created, false otherwise. An object that represents the access conditions for the blob. If null, no condition is used. An object that specifies additional options for the request. An object for tracking the current operation. This operation is not supported in BlobWriteStreamBase. Not used. Not used. Not used. Calculates the new position within the current stream for a Seek operation. A byte offset relative to the origin parameter. A value of type SeekOrigin indicating the reference point used to obtain the new position. The new position within the current stream. This operation is not supported in BlobWriteStreamBase. Not used. Generates a new block ID to be used for PutBlock. Base64 encoded block ID Releases the blob resources used by the Stream. true to release both managed and unmanaged resources; false to release only unmanaged resources. Gets a value indicating whether the current stream supports reading. Gets a value indicating whether the current stream supports seeking. Gets a value indicating whether the current stream supports writing. Gets the length in bytes of the stream. Gets or sets the position within the current stream. Initializes a new instance of the BlobWriteStream class for a block blob. Blob reference to write to. An object that represents the access conditions for the blob. If null, no condition is used. An object that specifies additional options for the request. An object for tracking the current operation. Initializes a new instance of the BlobWriteStream class for a page blob. Blob reference to write to. Size of the page blob. Use true if the page blob is newly created, false otherwise. An object that represents the access conditions for the blob. If null, no condition is used. An object that specifies additional options for the request. An object for tracking the current operation. Sets the position within the current stream. A byte offset relative to the origin parameter. A value of type SeekOrigin indicating the reference point used to obtain the new position. The new position within the current stream. Writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written. An array of bytes. This method copies count bytes from buffer to the current stream. The zero-based byte offset in buffer at which to begin copying bytes to the current stream. The number of bytes to be written to the current stream. Begins an asynchronous write operation. An array of bytes. This method copies count bytes from buffer to the current stream. The zero-based byte offset in buffer at which to begin copying bytes to the current stream. The number of bytes to be written to the current stream. An optional asynchronous callback, to be called when the write is complete. A user-provided object that distinguishes this particular asynchronous write request from other requests. An IAsyncResult that represents the asynchronous write, which could still be pending. Waits for the pending asynchronous write to complete. The reference to the pending asynchronous request to finish. Clears all buffers for this stream and causes any buffered data to be written to the underlying blob. Begins an asynchronous flush operation. An optional asynchronous callback, to be called when the flush is complete. A user-provided object that distinguishes this particular asynchronous flush request from other requests. An ICancellableAsyncResult that represents the asynchronous flush, which could still be pending. Waits for the pending asynchronous flush to complete. The reference to the pending asynchronous request to finish. Called when noPendingWritesEvent is signalled indicating that there are no outstanding write requests. An object containing information to be used by the callback method each time it executes. true if the WaitHandle timed out; false if it was signaled. Releases the blob resources used by the Stream. true to release both managed and unmanaged resources; false to release only unmanaged resources. Clears all buffers for this stream, causes any buffered data to be written to the underlying blob, and commits the blob. Begins an asynchronous commit operation. An optional asynchronous callback, to be called when the commit is complete. A user-provided object that distinguishes this particular asynchronous commit request from other requests. An ICancellableAsyncResult that represents the asynchronous commit, which could still be pending. Waits for the pending asynchronous commit to complete. The reference to the pending asynchronous request to finish. Called when the pending flush operation completes so that we can continue with the commit. The result of the asynchronous operation. Called when the block blob commit operation completes. The result of the asynchronous operation. Called when the page blob commit operation completes. The result of the asynchronous operation. Dispatches a write operation. The reference to the pending asynchronous request to finish. Starts an asynchronous PutBlock operation as soon as the parallel operation semaphore becomes available. Data to be uploaded Block ID MD5 hash of the data to be uploaded The reference to the pending asynchronous request to finish. Called when the asynchronous PutBlock operation completes. The result of the asynchronous operation. Starts an asynchronous WritePages operation as soon as the parallel operation semaphore becomes available. Data to be uploaded Offset within the page blob MD5 hash of the data to be uploaded The reference to the pending asynchronous request to finish. Called when the asynchronous WritePages operation completes. The result of the asynchronous operation. Provides a client-side logical representation of the Windows Azure Blob service. This client is used to configure and execute requests against the Blob service. The service client encapsulates the base URI for the Blob service. If the service client will be used for authenticated access, it also encapsulates the credentials for accessing the storage account. Provides a client-side logical representation of the Windows Azure Blob service. This client is used to configure and execute requests against the Blob service. The service client encapsulates the base URI for the Blob service. If the service client will be used for authenticated access, it also encapsulates the credentials for accessing the storage account. Returns an enumerable collection of containers whose names begin with the specified prefix and that are retrieved lazily. The container name prefix. A value that indicates whether to return container metadata with the listing. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. An enumerable collection of containers that are retrieved lazily. Returns a result segment containing a collection of objects. A returned by a previous listing operation. A result segment of containers. Returns a result segment containing a collection of objects. The container name prefix. A returned by a previous listing operation. A result segment of containers. Returns a result segment containing a collection of containers whose names begin with the specified prefix. The container name prefix. A value that indicates whether to return container metadata with the listing. A non-negative integer value that indicates the maximum number of results to be returned in the result segment, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A returned by a previous listing operation. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A result segment of containers. Returns a result segment containing a collection of containers whose names begin with the specified prefix. The container name prefix. A value that indicates whether to return container metadata with the listing. A non-negative integer value that indicates the maximum number of results to be returned in the result segment, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A continuation token returned by a previous listing operation. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A result segment of containers. Begins an asynchronous request to return a result segment containing a collection of containers. A continuation token returned by a previous listing operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to return a result segment containing a collection of containers. The container name prefix. A continuation token returned by a previous listing operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to return a result segment containing a collection of containers whose names begin with the specified prefix. The container name prefix. A value that indicates whether to return container metadata with the listing. A non-negative integer value that indicates the maximum number of results to be returned in the result segment, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A continuation token returned by a previous listing operation. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to return a result segment containing a collection of containers. An that references the pending asynchronous operation. A result segment of containers. Returns a task that performs an asynchronous request to return a result segment containing a collection of containers. A continuation token returned by a previous listing operation. A object that represents the current operation. Returns a task that performs an asynchronous request to return a result segment containing a collection of containers. A continuation token returned by a previous listing operation. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous request to return a result segment containing a collection of containers. The container name prefix. A continuation token returned by a previous listing operation. A object that represents the current operation. Returns a task that performs an asynchronous request to return a result segment containing a collection of containers. The container name prefix. A continuation token returned by a previous listing operation. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous request to return a result segment containing a collection of containers. The container name prefix. A value that indicates whether to return container metadata with the listing. A non-negative integer value that indicates the maximum number of results to be returned in the result segment, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A continuation token returned by a previous listing operation. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous request to return a result segment containing a collection of containers. The container name prefix. A value that indicates whether to return container metadata with the listing. A non-negative integer value that indicates the maximum number of results to be returned in the result segment, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A continuation token returned by a previous listing operation. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Returns an enumerable collection of the blobs in the container that are retrieved lazily. The blob name prefix. Specifies whether to list blobs in a flat listing, or whether to list blobs hierarchically, by virtual directory. A enumeration describing which items to include in the listing. A object that specifies additional options for the request. An object that represents the context for the current operation. An enumerable collection of objects that implement and are retrieved lazily. Returns a result segment containing a collection of blob items in the container. The blob name prefix, including the container name. A returned by a previous listing operation. A result segment containing objects that implement . Returns a result segment containing a collection of blob items in the container. The blob name prefix, including the container name. Specifies whether to list blobs in a flat listing, or whether to list blobs hierarchically, by virtual directory. A enumeration describing which items to include in the listing. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A returned by a previous listing operation. A object that specifies additional options for the request. An object that represents the context for the current operation. A result segment containing objects that implement . Begins an asynchronous operation to return a result segment containing a collection of blob items in the container. The blob name prefix, including the container name. A returned by a previous listing operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to return a result segment containing a collection of blob items in the container. The blob name prefix, including the container name. Specifies whether to list blobs in a flat listing, or whether to list blobs hierarchically, by virtual directory. A enumeration describing which items to include in the listing. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A returned by a previous listing operation. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to return a result segment containing a collection of blob items in the container. An that references the pending asynchronous operation. A result segment containing objects that implement . Returns a task that performs an asynchronous operation to return a result segment containing a collection of blob items in the container. The blob name prefix, including the container name. A returned by a previous listing operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to return a result segment containing a collection of blob items in the container. The blob name prefix. A returned by a previous listing operation. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to return a result segment containing a collection of blob items in the container. The blob name prefix. Specifies whether to list blobs in a flat listing, or whether to list blobs hierarchically, by virtual directory. A enumeration describing which items to include in the listing. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A returned by a previous listing operation. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to return a result segment containing a collection of blob items in the container. The blob name prefix. Specifies whether to list blobs in a flat listing, or whether to list blobs hierarchically, by virtual directory. A enumeration describing which items to include in the listing. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A returned by a previous listing operation. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Gets a reference to a blob from the service. The URI of the blob. The service assumes this is the URI for the blob in the primary location. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. An object of type containing a reference to the blob. Gets a reference to a blob from the service. The URI of the blob. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies any additional options for the request. An object that represents the context for the current operation. An object of type containing a reference to the blob. Begins an asynchronous operation to get a reference to a blob from the service. The URI of the blob. The service assumes this is the URI for the blob in the primary location. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to get a reference to a blob from the service. The URI of the blob. The service assumes this is the URI for the blob in the primary location. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to get a reference to a blob from the service. The URI of the blob. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies any additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to get a reference to a blob from the service. An that references the pending asynchronous operation. A reference to the blob. Returns a task that gets a reference to a blob from the service. The URI of the blob. The service assumes this is the URI for the blob in the primary location. A object that represents the current operation. Returns a task that gets a reference to a blob from the service. The URI of the blob. The service assumes this is the URI for the blob in the primary location. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a object that gets a reference to a blob from the service. The URI of the blob. The service assumes this is the URI for the blob in the primary location. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that gets a reference to a blob from the service. The URI of the blob. The service assumes this is the URI for the blob in the primary location. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that gets a reference to a blob from the service. The URI of the blob. An object that represents the access conditions for the container. If null, no condition is used. An object that specifies any additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that gets a reference to a blob from the service. The URI of the blob. An object that represents the access conditions for the container. If null, no condition is used. An object that specifies any additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Core implementation for the ListContainers method. The container prefix. The details included. The continuation token. A non-negative integer value that indicates the maximum number of results to be returned in the result segment, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A object that specifies additional options for the request. A that lists the containers. Implements the FetchAttributes method. The attributes are updated immediately. The URI of the blob. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. A that fetches the attributes. Begins an asynchronous operation to get the properties of the blob service. The callback delegate that will receive notification when the asynchronous operation completes. A user defined object to be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to get the properties of the blob service. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user defined object to be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to get the properties of the blob service. An that references the pending asynchronous operation. The blob service properties. Returns a task that performs an asynchronous operation to get the properties of the blob service. A object that represents the current operation. Returns a task that performs an asynchronous operation to get the properties of the blob service. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to get the properties of the blob service. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to get the properties of the blob service. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Gets the properties of the blob service. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. The blob service properties. Begins an asynchronous operation to set the properties of the blob service. The blob service properties. The callback delegate that will receive notification when the asynchronous operation completes. A user defined object to be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to set the properties of the blob service. The blob service properties. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user defined object to be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to set the properties of the blob service. An that references the pending asynchronous operation. Returns a task that gets the properties of the blob service. The blob service properties. A object that represents the current operation. Returns a task that gets the properties of the blob service. The blob service properties. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that gets the properties of the blob service. The blob service properties. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that gets the properties of the blob service. The blob service properties. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Sets the properties of the blob service. The blob service properties. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. Begins an asynchronous operation to get the stats of the blob service. The callback delegate that will receive notification when the asynchronous operation completes. A user defined object to be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to get the stats of the blob service. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user defined object to be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to get the stats of the blob service. An that references the pending asynchronous operation. The blob service stats. Returns a task that performs an asynchronous operation to get the stats of the blob service. A object that represents the current operation. Returns a task that performs an asynchronous operation to get the stats of the blob service. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to get the stats of the blob service. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to get the stats of the blob service. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Gets the stats of the blob service. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. The blob service stats. Stores the default delimiter. Stores the parallelism factor. Default is 32 MB. The default server and client timeout interval. Max execution time across all potential retries. Initializes a new instance of the class using the specified Blob service endpoint and anonymous credentials. The Blob service endpoint to use to create the client. Initializes a new instance of the class using the specified Blob service endpoint and account credentials. The Blob service endpoint to use to create the client. The account credentials. Initializes a new instance of the class using the specified Blob service endpoint and account credentials. The Blob service endpoint to use to create the client. The account credentials. Returns a reference to the root container for this service client. A reference to the root container. Returns a reference to a object with the specified name. The name of the container, or an absolute URI to the container. A reference to a container. Parses the user prefix. The prefix. Name of the container. The listing prefix. Gets or sets the authentication scheme to use to sign HTTP requests. Gets the authentication handler used to sign HTTP requests. The authentication handler. Gets or sets a buffer manager that implements the interface, specifying a buffer pool for use with operations against the Blob service client. Gets the account credentials used to create the Blob service client. The account credentials. Gets the base URI for the Blob service client, at the primary location. The base URI used to construct the Blob service client, at the primary location. Gets the Blob service endpoints for all locations. An object of type containing Blob service URIs for all locations. Gets or sets the default retry policy for requests made via the Blob service client. The retry policy. Gets or sets the default location mode for requests made via the Blob service client. The location mode. Gets or sets the default server and client timeout for requests made via the Blob service client. The server and client timeout interval. Gets or sets the maximum execution time across all potential retries. The maximum execution time across all potential retries. Gets or sets the default delimiter that may be used to create a virtual directory structure of blobs. The default delimiter. Gets or sets the maximum size of a blob in bytes that may be uploaded as a single blob. The maximum size of a blob, in bytes, that may be uploaded as a single blob, ranging from between 1 and 64 MB inclusive. Gets or sets the number of blocks that may be simultaneously uploaded when uploading a blob that is greater than the value specified by the property in size. The number of parallel operations that may proceed. Gets a value indicating whether the service client is used with Path style or Host style. Is true if use path style URIs; otherwise, false. Represents a container in the Windows Azure Blob service. Containers hold directories, which are encapsulated as objects, and directories hold block blobs and page blobs. Directories can also contain sub-directories. Represents a container in the Windows Azure Blob service. Creates the container. A object that specifies additional options for the request. An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. Creates the container and specifies the level of access to the container's data. An object that specifies whether data in the container may be accessed publicly and what level of access is to be allowed. A object that specifies additional options for the request. An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. Begins an asynchronous operation to create a container. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to create a container. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to create a container and specify the level of access to the container's data. An object that specifies whether data in the container may be accessed publicly and what level of access is to be allowed. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to create a container. An that references the pending asynchronous operation. Returns a task that creates a container. A object that represents the current operation. Returns a task that creates a container. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that creates a container. An object that specifies whether data in the container may be accessed publicly and what level of access is to be allowed. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that creates a container and specifies the level of access to the container's data. An object that specifies whether data in the container may be accessed publicly and what level of access is to be allowed. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Creates the container if it does not already exist. A object that specifies additional options for the request. An object that represents the context for the current operation. true if the container did not already exist and was created; otherwise false. Creates the container if it does not already exist and specifies whether the container or its blobs are publicly accessible. An object that specifies whether data in the container may be accessed publicly and what level of access is to be allowed. A object that specifies additional options for the request. An object that represents the context for the current operation. true if the container did not already exist and was created; otherwise false. Begins an asynchronous request to create the container if it does not already exist. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to create the container if it does not already exist. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to create the container if it does not already exist. An object that specifies whether data in the container may be accessed publicly and the level of access. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Returns the result of an asynchronous request to create the container if it does not already exist. An that references the pending asynchronous operation. true if the container did not already exist and was created; otherwise, false. Returns a task that creates the container if it does not already exist. A object that represents the current operation. Returns a task that creates the container if it does not already exist. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that creates the container if it does not already exist. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that creates the container if it does not already exist. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that creates the container if it does not already exist. An object that specifies whether data in the container may be accessed publicly and the level of access. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that creates the container if it does not already exist. An object that specifies whether data in the container may be accessed publicly and the level of access. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Deletes the container. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to delete a container. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to delete a container. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to delete a container. An that references the pending asynchronous operation. Returns a task that deletes the container. A object that represents the current operation. Returns a task that deletes the container. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that deletes the container. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that deletes the container. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Deletes the container if it already exists. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. true if the container did not already exist and was created; otherwise false. Begins an asynchronous request to delete the container if it already exists. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to delete the container if it already exists. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Returns the result of an asynchronous request to delete the container if it already exists. An that references the pending asynchronous operation. true if the container did not already exist and was created; otherwise, false. Returns a task that deletes the container if it already exists. A object that represents the current operation. Returns a task that deletes the container if it already exists. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that deletes the container if it already exists. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that deletes the container if it already exists. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Gets a reference to a blob in this container. The name of the blob. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A reference to the blob. Begins an asynchronous operation to get a reference to a blob in this container. The name of the blob. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to get a reference to a blob in this container. The name of the blob. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to get a reference to a blob in this container. An that references the pending asynchronous operation. A reference to the blob. Returns a task that gets a reference to a blob in this container. The name of the blob. A object that represents the current operation. Returns a task that gets a reference to a blob in this container. The name of the blob. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that gets a reference to a blob in this container. The name of the blob. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that gets a reference to a blob in this container. The name of the blob. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Returns an enumerable collection of the blobs in the container that are retrieved lazily. The blob name prefix. Specifies whether to list blobs in a flat listing, or whether to list blobs hierarchically, by virtual directory. A enumeration describing which items to include in the listing. A object that specifies additional options for the request. An object that represents the context for the current operation. An enumerable collection of objects that implement and are retrieved lazily. Returns a result segment containing a collection of blob items in the container. A continuation token returned by a previous listing operation. A result segment containing objects that implement . Returns a result segment containing a collection of blob items in the container. The blob name prefix. A continuation token returned by a previous listing operation. A result segment containing objects that implement . Returns a result segment containing a collection of blob items in the container. The blob name prefix. Specifies whether to list blobs in a flat listing, or whether to list blobs hierarchically, by virtual directory. A enumeration describing which items to include in the listing. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A continuation token returned by a previous listing operation. A object that specifies additional options for the request. An object that represents the context for the current operation. A result segment containing objects that implement . Returns a result segment containing a collection of blob items in the container. The blob name prefix. Specifies whether to list blobs in a flat listing, or whether to list blobs hierarchically, by virtual directory. A enumeration describing which items to include in the listing. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A continuation token returned by a previous listing operation. A object that specifies additional options for the request. An object that represents the context for the current operation. A result segment containing objects that implement . Begins an asynchronous operation to return a result segment containing a collection of blob items in the container. A continuation token returned by a previous listing operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to return a result segment containing a collection of blob items in the container. The blob name prefix. A continuation token returned by a previous listing operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to return a result segment containing a collection of blob items in the container. The blob name prefix. Specifies whether to list blobs in a flat listing, or whether to list blobs hierarchically, by virtual directory. A enumeration describing which items to include in the listing. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A continuation token returned by a previous listing operation. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to return a result segment containing a collection of blob items in the container. An that references the pending asynchronous operation. A result segment containing objects that implement . Returns a task that returns a result segment containing a collection of blob items in the container. A continuation token returned by a previous listing operation. Returns a task that returns a result segment containing a collection of blob items in the container. A continuation token returned by a previous listing operation. A to observe while waiting for a task to complete. Returns a task that returns a result segment containing a collection of blob items in the container. The blob name prefix. A continuation token returned by a previous listing operation. Returns a task that returns a result segment containing a collection of blob items in the container. The blob name prefix. A continuation token returned by a previous listing operation. A to observe while waiting for a task to complete. Returns a task that returns a result segment containing a collection of blob items in the container. The blob name prefix. Specifies whether to list blobs in a flat listing, or whether to list blobs hierarchically, by virtual directory. A enumeration describing which items to include in the listing. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A continuation token returned by a previous listing operation. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that returns a result segment containing a collection of blob items in the container. The blob name prefix. Specifies whether to list blobs in a flat listing, or whether to list blobs hierarchically, by virtual directory. A enumeration describing which items to include in the listing. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A continuation token returned by a previous listing operation. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Sets permissions for the container. The permissions to apply to the container. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous request to set permissions for the container. The permissions to apply to the container. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to set permissions for the container. The permissions to apply to the container. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Returns the result of an asynchronous request to set permissions for the container. An that references the pending asynchronous operation. Returns a task that sets permissions for the container. The permissions to apply to the container. A object that represents the current operation. Returns a task that sets permissions for the container. The permissions to apply to the container. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that sets permissions for the container. The permissions to apply to the container. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that sets permissions for the container. The permissions to apply to the container. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Gets the permissions settings for the container. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The container's permissions. Begins an asynchronous request to get the permissions settings for the container. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to get the permissions settings for the container. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Returns the asynchronous result of the request to get the permissions settings for the container. An that references the pending asynchronous operation. The container's permissions. Returns a task that gets the permissions settings for the container. A object that represents the current operation. Returns a task that gets the permissions settings for the container. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that gets the permissions settings for the container. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that gets the permissions settings for the container. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Checks whether the container exists. A object that specifies additional options for the request. An object that represents the context for the current operation. true if the container exists. Checks whether the container exists. If true, the command will be executed against the primary location. A object that specifies additional options for the request. An object that represents the context for the current operation. true if the container exists. Begins an asynchronous request to check whether the container exists. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to check whether the container exists. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to check whether the container exists. If true, the command will be executed against the primary location. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Returns the asynchronous result of the request to check whether the container exists. An that references the pending asynchronous operation. true if the container exists. Returns a task that checks whether the container exists. A object that represents the current operation. Returns a task that checks whether the container exists. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that checks whether the container exists. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that checks whether the container exists. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Retrieves the container's attributes. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to retrieve the container's attributes. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to retrieve the container's attributes. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to retrieve the container's attributes. An that references the pending asynchronous operation. Returns a task that retrieves the container's attributes. A object that represents the current operation. Returns a task that retrieves the container's attributes. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that retrieves the container's attributes. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that retrieves the container's attributes. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Sets the container's user-defined metadata. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to set user-defined metadata on the container. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to set user-defined metadata on the container. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous request operation to set user-defined metadata on the container. An that references the pending asynchronous operation. Returns a task that sets container's user-defined metadata. A object that represents the current operation. Returns a task that sets container's user-defined metadata. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that sets container's user-defined metadata. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that sets container's user-defined metadata. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Acquires a lease on this container. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. If null, an infinite lease will be acquired. If not null, this must be greater than zero. A string representing the proposed lease ID for the new lease, or null if no lease ID is proposed. An object that represents the access conditions for the container. If null, no condition is used. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. The ID of the acquired lease. Begins an asynchronous operation to acquire a lease on this container. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. If null, an infinite lease will be acquired. If not null, this must be greater than zero. A string representing the proposed lease ID for the new lease, or null if no lease ID is proposed. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to acquire a lease on this container. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. If null, an infinite lease will be acquired. If not null, this must be greater than zero. A string representing the proposed lease ID for the new lease, or null if no lease ID is proposed. An object that represents the access conditions for the container. If null, no condition is used. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to acquire a lease on this container. An IAsyncResult that references the pending asynchronous operation. The ID of the acquired lease. Returns a task that acquires a lease on this container. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. If null, an infinite lease will be acquired. If not null, this must be greater than zero. A string representing the proposed lease ID for the new lease, or null if no lease ID is proposed. A object that represents the current operation. Returns a task that acquires a lease on this container. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. If null, an infinite lease will be acquired. If not null, this must be greater than zero. A string representing the proposed lease ID for the new lease, or null if no lease ID is proposed. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that acquires a lease on this container. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. If null, an infinite lease will be acquired. If not null, this must be greater than zero. A string representing the proposed lease ID for the new lease, or null if no lease ID is proposed. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that acquires a lease on this container. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. If null, an infinite lease will be acquired. If not null, this must be greater than zero. A string representing the proposed lease ID for the new lease, or null if no lease ID is proposed. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Renews a lease on this container. An object that represents the access conditions for the container, including a required lease ID. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. Begins an asynchronous operation to renew a lease on this container. An object that represents the access conditions for the container, including a required lease ID. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to renew a lease on this container. An object that represents the access conditions for the container, including a required lease ID. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to renew a lease on this container. An IAsyncResult that references the pending asynchronous operation. Returns a task that renews a lease on this container. An object that represents the access conditions for the container, including a required lease ID. A object that represents the current operation. Returns a task that renews a lease on this container. An object that represents the access conditions for the container, including a required lease ID. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that renews a lease on this container. An object that represents the access conditions for the container, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that renews a lease on this container. An object that represents the access conditions for the container, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Changes the lease ID on this container. A string representing the proposed lease ID for the new lease. This cannot be null. An object that represents the access conditions for the container, including a required lease ID. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. The new lease ID. Begins an asynchronous operation to change the lease on this container. A string representing the proposed lease ID for the new lease. This cannot be null. An object that represents the access conditions for the container, including a required lease ID. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to change the lease on this container. A string representing the proposed lease ID for the new lease. This cannot be null. An object that represents the access conditions for the container, including a required lease ID. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to change the lease on this container. An IAsyncResult that references the pending asynchronous operation. The new lease ID. Returns a task that changes the lease ID on this container. A string representing the proposed lease ID for the new lease. This cannot be null. An object that represents the access conditions for the container, including a required lease ID. A object that represents the current operation. Returns a task that changes the lease ID on this container. A string representing the proposed lease ID for the new lease. This cannot be null. An object that represents the access conditions for the container, including a required lease ID. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that changes the lease ID on this container. A string representing the proposed lease ID for the new lease. This cannot be null. An object that represents the access conditions for the container, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that changes the lease ID on this container. A string representing the proposed lease ID for the new lease. This cannot be null. An object that represents the access conditions for the container, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Releases the lease on this container. An object that represents the access conditions for the container, including a required lease ID. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. Begins an asynchronous operation to release the lease on this container. An object that represents the access conditions for the container, including a required lease ID. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to release the lease on this container. An object that represents the access conditions for the container, including a required lease ID. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to release the lease on this container. An IAsyncResult that references the pending asynchronous operation. Returns a task that releases the lease on this container. An object that represents the access conditions for the container, including a required lease ID. A object that represents the current operation. Returns a task that releases the lease on this container. An object that represents the access conditions for the container, including a required lease ID. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that releases the lease on this container. An object that represents the access conditions for the container, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that releases the lease on this container. An object that represents the access conditions for the container, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Breaks the current lease on this container. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. If null, the break period is the remainder of the current lease, or zero for infinite leases. An object that represents the access conditions for the container. If null, no condition is used. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. A representing the amount of time before the lease ends, to the second. Begins an asynchronous operation to break the current lease on this container. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. If null, the break period is the remainder of the current lease, or zero for infinite leases. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to break the current lease on this container. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. If null, the break period is the remainder of the current lease, or zero for infinite leases. An object that represents the access conditions for the container. If null, no condition is used. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to break the current lease on this container. An IAsyncResult that references the pending asynchronous operation. A representing the amount of time before the lease ends, to the second. Returns a task that breaks the current lease on this container. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. If null, the break period is the remainder of the current lease, or zero for infinite leases. A object that represents the current operation. Returns a task that breaks the current lease on this container. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. If null, the break period is the remainder of the current lease, or zero for infinite leases. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that breaks the current lease on this container. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. If null, the break period is the remainder of the current lease, or zero for infinite leases. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that breaks the current lease on this container. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. If null, the break period is the remainder of the current lease, or zero for infinite leases. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Generates a RESTCommand for acquiring a lease. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. If null, an infinite lease will be acquired. If not null, this must be greater than zero. A string representing the proposed lease ID for the new lease, or null if no lease ID is proposed. An object that represents the access conditions for the container. If null, no condition is used. The options for this operation. This parameter must not be null. A RESTCommand implementing the acquire lease operation. Generates a RESTCommand for renewing a lease. An object that represents the access conditions for the container. If null, no condition is used. The options for this operation, including the current lease ID. This cannot be null. A RESTCommand implementing the renew lease operation. Generates a RESTCommand for changing a lease ID. The proposed new lease ID. An object that represents the access conditions for the container. If null, no condition is used. The options for this operation, including the current lease ID. This cannot be null. A RESTCommand implementing the change lease ID operation. Generates a RESTCommand for releasing a lease. An object that represents the access conditions for the container. If null, no condition is used. The options for this operation, including the current lease ID. This cannot be null. A RESTCommand implementing the release lease operation. Generates a RESTCommand for breaking a lease. The amount of time to allow the lease to remain, rounded down to seconds. If null, the break period is the remainder of the current lease, or zero for infinite leases. An object that represents the access conditions for the container. If null, no condition is used. The options for this operation. Cannot be null. A RESTCommand implementing the break lease operation. Implementation for the Create method. A object that specifies additional options for the request. An object that specifies whether data in the container may be accessed publicly and the level of access. A that creates the container. Implementation for the Delete method. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. A that deletes the container. Implementation for the FetchAttributes method. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. A that fetches the attributes. Implementation for the Exists method. A object that specifies additional options for the request. If true, the command will be executed against the primary location. A that checks existence. Implementation for the SetMetadata method. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. A that sets the metadata. Implementation for the SetPermissions method. The permissions to set. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. A that sets the permissions. Implementation for the GetPermissions method. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. A that gets the permissions. Selects the protocol response. The protocol item. The parsed . Core implementation of the ListBlobs method. The blob prefix. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. Specifies whether to list blobs in a flat listing, or whether to list blobs hierarchically, by virtual directory. A enumeration describing which items to include in the listing. A object that specifies additional options for the request. A continuation token returned by a previous listing operation. A that lists the blobs. Retrieve ETag and LastModified date time from response. The response to parse. Initializes a new instance of the class. The absolute URI to the container. Initializes a new instance of the class. The absolute URI to the container. The account credentials. Initializes a new instance of the class. The absolute URI to the container. The account credentials. Initializes a new instance of the class. The container name. A client object that specifies the endpoint for the Blob service. Initializes a new instance of the class. The properties. The metadata. The container name. The client to be used. Parse URI for SAS (Shared Access Signature) information. The complete Uri. The credentials to use. Returns the canonical name for shared access. The canonical name. Returns a shared access signature for the container. The access policy for the shared access signature. A shared access signature, as a URI query string. The query string returned includes the leading question mark. Returns a shared access signature for the container. The access policy for the shared access signature. A container-level access policy. A shared access signature, as a URI query string. The query string returned includes the leading question mark. Gets a reference to a page blob in this container. The name of the blob. A reference to a page blob. Returns a reference to a page blob in this virtual directory. The name of the page blob. The snapshot timestamp, if the blob is a snapshot. A reference to a page blob. Gets a reference to a block blob in this container. The name of the blob. A reference to a block blob. Gets a reference to a block blob in this container. The name of the blob. The snapshot timestamp, if the blob is a snapshot. A reference to a block blob. Gets a reference to a virtual blob directory beneath this container. The name of the virtual blob directory. A reference to a virtual blob directory. Gets the service client for the container. A client object that specifies the endpoint for the Blob service. Gets the container's URI for the primary location. The absolute URI to the container, at the primary location. Gets the container's URIs for all locations. An object of type containing the container's URIs for all locations. Gets the name of the container. The container's name. Gets the container's metadata. The container's metadata. Gets the container's system properties. The container's properties. Represents a virtual directory of blobs, designated by a delimiter character. Containers, which are encapsulated as objects, hold directories, and directories hold block blobs and page blobs. Directories can also contain sub-directories. Represents a virtual directory of blobs on the client which emulates a hierarchical data store by using delimiter characters. Containers, which are encapsulated as objects, hold directories, and directories hold block blobs and page blobs. Directories can also contain sub-directories. Represents an item that may be returned by a blob listing operation. Gets the URI to the blob item, at the primary location. The blob item's URI. Gets the blob item's URIs for all locations. An object of type containing the blob item's URIs for all locations. Gets the blob item's parent virtual directory. The blob item's parent virtual directory. Gets the blob item's container. The blob item's container. Returns an enumerable collection of the blobs in the virtual directory that are retrieved lazily. Specifies whether to list blobs in a flat listing, or whether to list blobs hierarchically, by virtual directory. A enumeration describing which items to include in the listing. A object that specifies additional options for the request. An object that represents the context for the current operation. An enumerable collection of objects that implement and are retrieved lazily. Returns a result segment containing a collection of blob items in the virtual directory. A continuation token returned by a previous listing operation. A result segment containing objects that implement . Returns a result segment containing a collection of blob items in the virtual directory. Specifies whether to list blobs in a flat listing, or whether to list blobs hierarchically, by virtual directory. A enumeration describing which items to include in the listing. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A continuation token returned by a previous listing operation. A object that specifies additional options for the request. An object that represents the context for the current operation. A result segment containing objects that implement . Begins an asynchronous operation to return a result segment containing a collection of blob items in the virtual directory. A continuation token returned by a previous listing operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to return a result segment containing a collection of blob items in the virtual directory. Specifies whether to list blobs in a flat listing, or whether to list blobs hierarchically, by virtual directory. A enumeration describing which items to include in the listing. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A continuation token returned by a previous listing operation. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to return a result segment containing a collection of blob items in the virtual directory. An that references the pending asynchronous operation. A result segment containing objects that implement . Returns a task that performs an asynchronous operation to return a result segment containing a collection of blob items in the virtual directory. A continuation token returned by a previous listing operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to return a result segment containing a collection of blob items in the virtual directory. A continuation token returned by a previous listing operation. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to return a result segment containing a collection of blob items in the virtual directory. Specifies whether to list blobs in a flat listing, or whether to list blobs hierarchically, by virtual directory. A enumeration describing which items to include in the listing. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A continuation token returned by a previous listing operation. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to return a result segment containing a collection of blob items in the virtual directory. Specifies whether to list blobs in a flat listing, or whether to list blobs hierarchically, by virtual directory. A enumeration describing which items to include in the listing. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A continuation token returned by a previous listing operation. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Stores the parent directory. Initializes a new instance of the class given an address and a client. The blob directory's Uri. The blob directory's prefix. The container for the virtual directory. Gets a reference to a page blob in this virtual directory. The name of the blob. A reference to a page blob. Returns a reference to a page blob in this virtual directory. The name of the page blob. The snapshot timestamp, if the blob is a snapshot. A reference to a page blob. Gets a reference to a block blob in this virtual directory. The name of the blob. A reference to a block blob. Gets a reference to a block blob in this virtual directory. The name of the blob. The snapshot timestamp, if the blob is a snapshot. A reference to a block blob. Returns a virtual subdirectory within this virtual directory. The name of the virtual subdirectory. A object representing the virtual subdirectory. Gets the service client for the virtual directory. A client object that specifies the endpoint for the Windows Azure Blob service. Gets the URI that identifies the virtual directory for the primary location. The URI to the virtual directory, at the primary location. Gets the blob directory's URIs for all locations. An object of type containing the blob directory's URIs for all locations. Gets the container for the virtual directory. The container for the virtual directory. Gets the parent directory for the virtual directory. The virtual directory's parent directory. Gets the prefix. The prefix. Called when the asynchronous operation to commit the blob started by UploadFromStream finishes. The result of the asynchronous operation. Implements getting the stream without specifying a range. The blob. The attributes. The destination stream. The offset. The length. An object that represents the access conditions for the blob. If null, no condition is used. An object that specifies additional options for the request. A that gets the stream. Implements the FetchAttributes method. The attributes are updated immediately. The blob. The attributes. An object that represents the access conditions for the blob. If null, no condition is used. An object that specifies additional options for the request. A that fetches the attributes. Implementation for the Exists method. The blob. The attributes. An object that specifies additional options for the request. If true, the command will be executed against the primary location. A that checks existence. Implementation for the SetMetadata method. The blob. The attributes. An object that represents the access conditions for the blob. If null, no condition is used. An object that specifies additional options for the request. A that sets the metadata. Implementation for the SetProperties method. The blob. The attributes. An object that represents the access conditions for the blob. If null, no condition is used. An object that specifies additional options for the request. A that sets the properties. Implements the DeleteBlob method. The blob. The attributes. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the blob. If null, no condition is used. An object that specifies additional options for the request. A that deletes the blob. Generates a for acquiring a lease. The blob. The attributes. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. If null, an infinite lease will be acquired. If not null, this must be greater than zero. A string representing the proposed lease ID for the new lease, or null if no lease ID is proposed. An object that represents the access conditions for the blob. If null, no condition is used. An object that specifies additional options for the request. A implementing the acquire lease operation. Generates a for renewing a lease. The blob. The attributes. An object that represents the access conditions for the blob. If null, no condition is used. An object that specifies additional options for the request. A implementing the renew lease operation. accessCondition Generates a for changing a lease ID. The blob. The attributes. The proposed new lease ID. An object that represents the access conditions for the blob. If null, no condition is used. An object that specifies additional options for the request. A implementing the change lease ID operation. accessCondition Generates a for releasing a lease. The blob. The attributes. An object that represents the access conditions for the blob. If null, no condition is used. An object that specifies additional options for the request. A implementing the release lease operation. accessCondition Generates a for breaking a lease. The blob. The attributes. The amount of time to allow the lease to remain, rounded down to seconds. If null, the break period is the remainder of the current lease, or zero for infinite leases. An object that represents the access conditions for the blob. If null, no condition is used. An object that specifies additional options for the request. A implementing the break lease operation. Implementation of the StartCopyFromBlob method. Result is a BlobAttributes object derived from the response headers. The blob. The attributes. The URI of the source blob. An object that represents the access conditions for the source blob. If null, no condition is used. An object that represents the access conditions for the destination blob. If null, no condition is used. An object that specifies additional options for the request. A that starts to copy the blob. sourceAccessCondition Implementation of the AbortCopy method. No result is produced. The blob. The attributes. The copy ID of the copy operation to abort. An object that represents the access conditions for the operation. If null, no condition is used. An object that specifies additional options for the request. A that aborts the copy. Updates this blob with the given attributes at the end of a fetch attributes operation. The new attributes. The response. if set to true, blob's MD5 will not be updated. Retrieve ETag, LMT, and Sequence-Number from response. The attributes. The response to parse. Converts the source blob of a copy operation to an appropriate access URI, taking Shared Access Signature credentials into account. The source blob. A URI addressing the source blob, using SAS if appropriate. Represents a blob that is uploaded as a set of blocks. Represents a blob that is uploaded as a set of blocks. An interface required for Windows Azure blob types. The and classes implement the interface. An interface required for Windows Azure blob types. The and classes implement the interface. Opens a stream for reading from the blob. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A stream to be used for reading from the blob. On the object returned by this method, the method must be called exactly once for every call. Failing to end a read process before beginning another read can cause unknown behavior. Begins an asynchronous operation to open a stream for reading from the blob. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to open a stream for reading from the blob. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to open a stream for reading from the blob. An that references the pending asynchronous operation. A stream to be used for reading from the blob. Returns a task that performs an asynchronous operation to open a stream for reading from the blob. A object that represents the current operation. Returns a task that performs an asynchronous operation to open a stream for reading from the blob. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to open a stream for reading from the blob. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to open a stream for reading from the blob. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Uploads a stream to the Windows Azure Blob Service. The stream providing the blob content. Use a seek-able stream for optimal performance. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. Uploads a stream to the Windows Azure Blob Service. The stream providing the blob content. The number of bytes to write from the source stream at its current position. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to upload a stream to a blob. The stream providing the blob content. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to upload a stream to a blob. The stream providing the blob content. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to upload a stream to a block blob. The stream providing the blob content. The number of bytes to write from the source stream at its current position. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to upload a stream to a blob. The stream providing the blob content. The number of bytes to write from the source stream at its current position. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to upload a stream to a blob. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to upload a stream to a blob. The stream providing the blob content. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a stream to a blob. The stream providing the blob content. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a stream to a blob. The stream providing the blob content. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a stream to a blob. The stream providing the blob content. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a stream to a block blob. The stream providing the blob content. The number of bytes to write from the source stream at its current position. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a stream to a block blob. The stream providing the blob content. The number of bytes to write from the source stream at its current position. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a stream to a blob. The stream providing the blob content. The number of bytes to write from the source stream at its current position. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a stream to a blob. The stream providing the blob content. The number of bytes to write from the source stream at its current position. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Uploads a file to the Windows Azure Blob Service. The file providing the blob content. A constant that determines how to open the file. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to upload a file to a blob. The file providing the blob content. A constant that determines how to open the file. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to upload a file to a blob. The file providing the blob content. A constant that determines how to open the file. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to upload a file to a blob. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to upload a file to a blob. The file providing the blob content. A constant that determines how to open the file. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a file to a blob. The file providing the blob content. A constant that determines how to open the file. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a file to a blob. The file providing the blob content. A constant that determines how to open the file. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a file to a blob. The file providing the blob content. A constant that determines how to open the file. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Uploads the contents of a byte array to a blob. An array of bytes. The zero-based byte offset in buffer at which to begin uploading bytes to the blob. The number of bytes to be written to the blob. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to upload the contents of a byte array to a blob. An array of bytes. The zero-based byte offset in buffer at which to begin uploading bytes to the blob. The number of bytes to be written to the blob. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to upload the contents of a byte array to a blob. An array of bytes. The zero-based byte offset in buffer at which to begin uploading bytes to the blob. The number of bytes to be written to the blob. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to upload the contents of a byte array to a blob. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to upload the contents of a byte array to a blob. An array of bytes. The zero-based byte offset in buffer at which to begin uploading bytes to the blob. The number of bytes to be written to the blob. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload the contents of a byte array to a blob. An array of bytes. The zero-based byte offset in buffer at which to begin uploading bytes to the blob. The number of bytes to be written to the blob. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload the contents of a byte array to a blob. An array of bytes. The zero-based byte offset in buffer at which to begin uploading bytes to the blob. The number of bytes to be written to the blob. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload the contents of a byte array to a blob. An array of bytes. The zero-based byte offset in buffer at which to begin uploading bytes to the blob. The number of bytes to be written to the blob. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Downloads the contents of a blob to a stream. The target stream. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to download the contents of a blob to a stream. The target stream. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to download the contents of a blob to a stream. The target stream. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to download the contents of a blob to a stream. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a stream. The target stream. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a stream. The target stream. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a stream. The target stream. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a stream. The target stream. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Downloads the contents of a blob to a file. The target file. A constant that determines how to open or create the file. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to download the contents of a blob to a file. The target file. A constant that determines how to open or create the file. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to download the contents of a blob to a file. The target file. A constant that determines how to open or create the file. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to download the contents of a blob to a file. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a file. The target file. A constant that determines how to open or create the file. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a file. The target file. A constant that determines how to open or create the file. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a file. The target file. A constant that determines how to open or create the file. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a file. The target file. A constant that determines how to open or create the file. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Downloads the contents of a blob to a byte array. The target byte array. The starting offset in the byte array. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The total number of bytes read into the buffer. Begins an asynchronous operation to download the contents of a blob to a byte array. The target byte array. The starting offset in the byte array. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to download the contents of a blob to a byte array. The target byte array. The starting offset in the byte array. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to download the contents of a blob to a byte array. An that references the pending asynchronous operation. The total number of bytes read into the buffer. Returns a task that performs an asynchronous operation to download the contents of a blob to a byte array. The target byte array. The starting offset in the byte array. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a byte array. The target byte array. The starting offset in the byte array. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a byte array. The target byte array. The starting offset in the byte array. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a byte array. The target byte array. The starting offset in the byte array. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Downloads a range of bytes from a blob to a stream. The target stream. The starting offset of the data range, in bytes. The length of the data range, in bytes. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to download a range of bytes from a blob to a stream. The target stream. The starting offset of the data range, in bytes. The length of the data range, in bytes. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to download a range of bytes from a blob to a stream. The target stream. The starting offset of the data range, in bytes. The length of the data range, in bytes. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to download a range of bytes from a blob to a stream. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a stream. The target stream. The starting offset of the data range, in bytes. The length of the data range, in bytes. A object that represents the current operation. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a stream. The target stream. The starting offset of the data range, in bytes. The length of the data range, in bytes. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a stream. The target stream. The starting offset of the data range, in bytes. The length of the data range, in bytes. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a stream. The target stream. The starting offset of the data range, in bytes. The length of the data range, in bytes. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Downloads a range of bytes from a blob to a byte array. The target byte array. The starting offset in the byte array. The starting offset of the data range, in bytes. The length of the data range, in bytes. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The total number of bytes read into the buffer. Begins an asynchronous operation to download a range of bytes from a blob to a byte array. The target byte array. The starting offset in the byte array. The starting offset of the data range, in bytes. The length of the data range, in bytes. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to download a range of bytes from a blob to a byte array. The target byte array. The starting offset in the byte array. The starting offset of the data range, in bytes. The length of the data range, in bytes. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to download a range of bytes from a blob to a byte array. An that references the pending asynchronous operation. The total number of bytes read into the buffer. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a byte array. The target byte array. The starting offset in the byte array. The starting offset of the data range, in bytes. The length of the data range, in bytes. A object that represents the current operation. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a byte array. The target byte array. The starting offset in the byte array. The starting offset of the data range, in bytes. The length of the data range, in bytes. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a byte array. The target byte array. The starting offset in the byte array. The starting offset of the data range, in bytes. The length of the data range, in bytes. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a byte array. The target byte array. The starting offset in the byte array. The starting offset of the data range, in bytes. The length of the data range, in bytes. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Checks existence of the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. true if the blob exists. Begins an asynchronous request to check existence of the blob. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to check existence of the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Returns the asynchronous result of the request to check existence of the blob. An that references the pending asynchronous operation. true if the blob exists. Returns a task that performs an asynchronous request to check existence of the blob. A object that represents the current operation. Returns a task that performs an asynchronous request to check existence of the blob. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous request to check existence of the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous request to check existence of the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Populates a blob's properties and metadata. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to populate the blob's properties and metadata. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to populate the blob's properties and metadata. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to populate the blob's properties and metadata. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to populate the blob's properties and metadata. A object that represents the current operation. Returns a task that performs an asynchronous operation to populate the blob's properties and metadata. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to populate the blob's properties and metadata. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to populate the blob's properties and metadata. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Updates the blob's metadata. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to update the blob's metadata. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to update the blob's metadata. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to update the blob's metadata. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to update the blob's metadata. A object that represents the current operation. Returns a task that performs an asynchronous operation to update the blob's metadata. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to update the blob's metadata. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to update the blob's metadata. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Updates the blob's properties. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to update the blob's properties. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to update the blob's properties. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to update the blob's properties. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to update the blob's properties. A object that represents the current operation. Returns a task that performs an asynchronous operation to update the blob's properties. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to update the blob's properties. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to update the blob's properties. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Deletes the blob. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to delete the blob. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to delete the blob. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to delete the blob. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to delete the blob. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete the blob. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete the blob. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete the blob. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Deletes the blob if it already exists. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the container. A object that specifies additional options for the request. An object that represents the context for the current operation. true if the blob did not already exist and was created; otherwise false. Begins an asynchronous request to delete the blob if it already exists. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to delete the blob if it already exists. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the container. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Returns the result of an asynchronous request to delete the blob if it already exists. An that references the pending asynchronous operation. true if the blob did not already exist and was created; otherwise, false. Returns a task that performs an asynchronous request to delete the blob if it already exists. A object that represents the current operation. Returns a task that performs an asynchronous request to delete the blob if it already exists. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous request to delete the blob if it already exists. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the container. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous request to delete the blob if it already exists. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the container. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Acquires a lease on this blob. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. A string representing the proposed lease ID for the new lease. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The ID of the acquired lease. Begins an asynchronous operation to acquire a lease on this blob. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. A string representing the proposed lease ID for the new lease. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to acquire a lease on this blob. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. A string representing the proposed lease ID for the new lease. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to acquire a lease on this blob. An IAsyncResult that references the pending asynchronous operation. The ID of the acquired lease. Returns a task that performs an asynchronous operation to acquire a lease on this blob. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. A string representing the proposed lease ID for the new lease. A object that represents the current operation. Returns a task that performs an asynchronous operation to acquire a lease on this blob. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. A string representing the proposed lease ID for the new lease. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to acquire a lease on this blob. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. A string representing the proposed lease ID for the new lease. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to acquire a lease on this blob. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. A string representing the proposed lease ID for the new lease. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Renews a lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to renew a lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to renew a lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to renew a lease on this blob. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to renew a lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A object that represents the current operation. Returns a task that performs an asynchronous operation to renew a lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to renew a lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to renew a lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Changes the lease ID on this blob. A string representing the proposed lease ID for the new lease. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. The new lease ID. Begins an asynchronous operation to change the lease on this blob. A string representing the proposed lease ID for the new lease. An object that represents the access conditions for the blob, including a required lease ID. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to change the lease on this blob. A string representing the proposed lease ID for the new lease. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to change the lease on this blob. An that references the pending asynchronous operation. The new lease ID. Returns a task that performs an asynchronous operation to change the lease on this blob. A string representing the proposed lease ID for the new lease. An object that represents the access conditions for the blob, including a required lease ID. A object that represents the current operation. Returns a task that performs an asynchronous operation to change the lease on this blob. A string representing the proposed lease ID for the new lease. An object that represents the access conditions for the blob, including a required lease ID. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to change the lease on this blob. A string representing the proposed lease ID for the new lease. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to change the lease on this blob. A string representing the proposed lease ID for the new lease. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Releases the lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to release the lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to release the lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to release the lease on this blob. An IAsyncResult that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to release the lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A object that represents the current operation. Returns a task that performs an asynchronous operation to release the lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to release the lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to release the lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Breaks the current lease on this blob. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A representing the amount of time before the lease ends, to the second. Begins an asynchronous operation to break the current lease on this blob. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to break the current lease on this blob. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to break the current lease on this blob. An IAsyncResult that references the pending asynchronous operation. A representing the amount of time before the lease ends, to the second. Returns a task that performs an asynchronous operation to break the current lease on this blob. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. A object that represents the current operation. Returns a task that performs an asynchronous operation to break the current lease on this blob. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to break the current lease on this blob. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to break the current lease on this blob. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Requests that the service start to copy a blob's contents, properties, and metadata to a new blob. The URI of a source blob. An object that represents the access conditions for the source blob. An object that represents the access conditions for the destination blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The copy ID associated with the copy operation. Begins an asynchronous operation to request that the service start to copy a blob's contents, properties, and metadata to a new blob. The URI of a source blob. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The URI of a source blob. An object that represents the access conditions for the source blob. An object that represents the access conditions for the destination blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to request that the service start to copy a blob's contents, properties, and metadata to a new blob. An that references the pending asynchronous operation. The copy ID associated with the copy operation. Returns a task that performs an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The URI of a source blob. A object that represents the current operation. Returns a task that performs an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The URI of a source blob. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The URI of a source blob. An object that represents the access conditions for the source blob. An object that represents the access conditions for the destination blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The URI of a source blob. An object that represents the access conditions for the source blob. An object that represents the access conditions for the destination blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Aborts an ongoing blob copy operation. A string identifying the copy operation. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to abort an ongoing blob copy operation. A string identifying the copy operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to abort an ongoing blob copy operation. A string identifying the copy operation. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to abort an ongoing blob copy operation. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to abort an ongoing blob copy operation. A string identifying the copy operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to abort an ongoing blob copy operation. A string identifying the copy operation. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to abort an ongoing blob copy operation. A string identifying the copy operation. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to abort an ongoing blob copy operation. A string identifying the copy operation. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a shared access signature for the blob. The access policy for the shared access signature. A shared access signature, as a URI query string. The query string returned includes the leading question mark. Returns a shared access signature for the blob. The access policy for the shared access signature. A container-level access policy. A shared access signature, as a URI query string. The query string returned includes the leading question mark. Returns a shared access signature for the blob. The access policy for the shared access signature. The optional header values to set for a blob accessed with this SAS. A shared access signature. Returns a shared access signature for the blob. The access policy for the shared access signature. The optional header values to set for a blob returned with this SAS. A stored access policy. A shared access signature. Gets the blob item's name. The blob item's name. Gets the object that represents the Blob service. A client object that specifies the Blob service endpoint. Gets or sets the number of bytes to buffer when writing to a page blob stream or the block size for writing to a block blob. The number of bytes to buffer or the size of a block, in bytes. Gets or sets the minimum number of bytes to buffer when reading from a blob stream. The minimum number of bytes to buffer. Gets the blob's system properties. The blob's properties. Gets the user-defined metadata for the blob. The blob's metadata, as a collection of name-value pairs. Gets the date and time that the blob snapshot was taken, if this blob is a snapshot. The blob's snapshot time if the blob is a snapshot; otherwise, null. If the blob is not a snapshot, the value of this property is null. Gets a value indicating whether this blob is a snapshot. true if this blob is a snapshot; otherwise, false. Gets the absolute URI to the blob, including query string information if the blob is a snapshot, at the primary location. The absolute URI to the blob, including snapshot query information if the blob is a snapshot, at the primary location. Gets the blob's URI for all locations, including query string information if the blob is a snapshot. An object of type containing the blob's URIs for all locations, including snapshot query information if the blob is a snapshot. Gets the state of the most recent or pending copy operation. A object containing the copy state, or null if no copy blob state exists for this blob. Gets the type of the blob. The type of the blob. Opens a stream for reading from the blob. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A stream to be used for reading from the blob. On the object returned by this method, the method must be called exactly once for every call. Failing to end a read process before beginning another read can cause unknown behavior. Begins an asynchronous operation to open a stream for reading from the blob. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to open a stream for reading from the blob. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to open a stream for reading from the blob. An that references the pending asynchronous operation. A stream to be used for reading from the blob. Returns a task that performs an asynchronous operation to open a stream for reading from the blob. A object that represents the current operation. Returns a task that performs an asynchronous operation to open a stream for reading from the blob. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to open a stream for reading from the blob. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to open a stream for reading from the blob. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Opens a stream for writing to the blob. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A stream to be used for writing to the blob. Begins an asynchronous operation to open a stream for writing to the blob. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to open a stream for writing to the blob. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to open a stream for writing to the blob. An that references the pending asynchronous operation. A stream to be used for writing to the blob. Returns a task that performs an asynchronous operation to open a stream for writing to the blob. A object that represents the current operation. Returns a task that performs an asynchronous operation to open a stream for writing to the blob. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to open a stream for writing to the blob. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to open a stream for writing to the blob. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Uploads a stream to a block blob. The stream providing the blob content. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Uploads a stream to a block blob. The stream providing the blob content. The number of bytes to write from the source stream at its current position. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Uploads a stream to a block blob. The stream providing the blob content. The number of bytes to write from the source stream at its current position. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to upload a stream to a block blob. The stream providing the blob content. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to upload a stream to a block blob. The stream providing the blob content. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to upload a stream to a block blob. The stream providing the blob content. The number of bytes to write from the source stream at its current position. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to upload a stream to a block blob. The stream providing the blob content. The number of bytes to write from the source stream at its current position. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to upload a stream to a block blob. The stream providing the blob content. The number of bytes to write from the source stream at its current position. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to upload a stream to a block blob. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to upload a stream to a block blob. The stream providing the blob content. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a stream to a block blob. The stream providing the blob content. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a stream to a block blob. The stream providing the blob content. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a stream to a block blob. The stream providing the blob content. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a stream to a block blob. The stream providing the blob content. The number of bytes to write from the source stream at its current position. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a stream to a block blob. The stream providing the blob content. The number of bytes to write from the source stream at its current position. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a stream to a block blob. The stream providing the blob content. The number of bytes to write from the source stream at its current position. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a stream to a block blob. The stream providing the blob content. The number of bytes to write from the source stream at its current position. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Uploads a file to the Blob service. The file providing the blob content. A constant that determines how to open the file. An object that represents the access conditions for the blob. An object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to upload a file to a blob. The file providing the blob content. A constant that determines how to open the file. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to upload a file to a blob. The file providing the blob content. A constant that determines how to open the file. An object that represents the access conditions for the blob. An object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Called when the asynchronous UploadFromStream operation completes. The result of the asynchronous operation. Ends an asynchronous operation to upload a file to a blob. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to upload a file to a blob. The file providing the blob content. A constant that determines how to open the file. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a file to a blob. The file providing the blob content. A constant that determines how to open the file. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a file to a blob. The file providing the blob content. A constant that determines how to open the file. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a file to a blob. The file providing the blob content. A constant that determines how to open the file. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Uploads the contents of a byte array to a blob. An array of bytes. The zero-based byte offset in buffer at which to begin uploading bytes to the blob. The number of bytes to be written to the blob. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to upload the contents of a byte array to a blob. An array of bytes. The zero-based byte offset in buffer at which to begin uploading bytes to the blob. The number of bytes to be written to the blob. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to upload the contents of a byte array to a blob. An array of bytes. The zero-based byte offset in buffer at which to begin uploading bytes to the blob. The number of bytes to be written to the blob. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to upload the contents of a byte array to a blob. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to upload the contents of a byte array to a blob. An array of bytes. The zero-based byte offset in buffer at which to begin uploading bytes to the blob. The number of bytes to be written to the blob. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload the contents of a byte array to a blob. An array of bytes. The zero-based byte offset in buffer at which to begin uploading bytes to the blob. The number of bytes to be written to the blob. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload the contents of a byte array to a blob. An array of bytes. The zero-based byte offset in buffer at which to begin uploading bytes to the blob. The number of bytes to be written to the blob. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload the contents of a byte array to a blob. An array of bytes. The zero-based byte offset in buffer at which to begin uploading bytes to the blob. The number of bytes to be written to the blob. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Uploads a string of text to a blob. The text to upload. An object that indicates the text encoding to use. If null, UTF-8 will be used. An object that represents the access conditions for the blob. An object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to upload a string of text to a blob. The text to upload. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to upload a string of text to a blob. The text to upload. An object that indicates the text encoding to use. If null, UTF-8 will be used. An object that represents the access conditions for the blob. An object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to upload a string of text to a blob. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to upload a string of text to a blob. The text to upload. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a string of text to a blob. The text to upload. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a string of text to a blob. The text to upload. An object that indicates the text encoding to use. If null, UTF-8 will be used. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a string of text to a blob. The text to upload. An object that indicates the text encoding to use. If null, UTF-8 will be used. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Downloads the contents of a blob to a stream. The target stream. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to download the contents of a blob to a stream. The target stream. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to download the contents of a blob to a stream. The target stream. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to download the contents of a blob to a stream. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a stream. The target stream. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a stream. The target stream. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a stream. The target stream. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a stream. The target stream. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Downloads the contents of a blob to a file. The target file. A constant that determines how to open or create the file. An object that represents the access conditions for the blob. An object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to download the contents of a blob to a file. The target file. A constant that determines how to open or create the file. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to download the contents of a blob to a file. The target file. A constant that determines how to open or create the file. An object that represents the access conditions for the blob. An object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Called when the asynchronous DownloadToStream operation completes. The result of the asynchronous operation. Ends an asynchronous operation to download the contents of a blob to a file. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a file. The target file. A constant that determines how to open or create the file. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a file. The target file. A constant that determines how to open or create the file. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a file. The target file. A constant that determines how to open or create the file. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a file. The target file. A constant that determines how to open or create the file. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Downloads the contents of a blob to a byte array. The target byte array. The starting offset in the byte array. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The total number of bytes read into the buffer. Begins an asynchronous operation to download the contents of a blob to a byte array. The target byte array. The starting offset in the byte array. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to download the contents of a blob to a byte array. The target byte array. The starting offset in the byte array. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to download the contents of a blob to a byte array. An that references the pending asynchronous operation. The total number of bytes read into the buffer. Returns a task that performs an asynchronous operation to download the contents of a blob to a byte array. The target byte array. The starting offset in the byte array. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a byte array. The target byte array. The starting offset in the byte array. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a byte array. The target byte array. The starting offset in the byte array. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a byte array. The target byte array. The starting offset in the byte array. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Downloads the blob's contents as a string. An object that indicates the text encoding to use. An object that represents the access conditions for the blob. An object that specifies additional options for the request. An object that represents the context for the current operation. The contents of the blob, as a string. Begins an asynchronous operation to download the blob's contents as a string. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to download the blob's contents as a string. An object that indicates the text encoding to use. An object that represents the access conditions for the blob. An object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Called when the asynchronous DownloadToStream operation completes. The result of the asynchronous operation. Ends an asynchronous operation to download the blob's contents as a string. An that references the pending asynchronous operation. The contents of the blob, as a string. Returns a task that performs an asynchronous operation to download the blob's contents as a string. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the blob's contents as a string. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the blob's contents as a string. An object that indicates the text encoding to use. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the blob's contents as a string. An object that indicates the text encoding to use. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Downloads a range of bytes from a blob to a stream. The target stream. The offset at which to begin downloading the blob, in bytes. The length of the data to download from the blob, in bytes. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to download a range of bytes from a blob to a stream. The target stream. The offset at which to begin downloading the blob, in bytes. The length of the data to download from the blob, in bytes. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to download a range of bytes from a blob to a stream. The target stream. The offset at which to begin downloading the blob, in bytes. The length of the data to download from the blob, in bytes. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to download a range of bytes from a blob to a stream. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a stream. The target stream. The offset at which to begin downloading the blob, in bytes. The length of the data to download from the blob, in bytes. A object that represents the current operation. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a stream. The target stream. The offset at which to begin downloading the blob, in bytes. The length of the data to download from the blob, in bytes. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a stream. The target stream. The offset at which to begin downloading the blob, in bytes. The length of the data to download from the blob, in bytes. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a stream. The target stream. The offset at which to begin downloading the blob, in bytes. The length of the data to download from the blob, in bytes. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Downloads a range of bytes from a blob to a byte array. The target byte array. The starting offset in the byte array. The starting offset of the data range, in bytes. The length of the data to download from the blob, in bytes. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The total number of bytes read into the buffer. Begins an asynchronous operation to download a range of bytes from a blob to a byte array. The target byte array. The starting offset in the byte array. The starting offset of the data range, in bytes. The length of the data to download from the blob, in bytes. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to download a range of bytes from a blob to a byte array. The target byte array. The starting offset in the byte array. The starting offset of the data range, in bytes. The length of the data to download from the blob, in bytes. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Called when the asynchronous DownloadRangeToStream operation completes. The result of the asynchronous operation. Ends an asynchronous operation to download a range of bytes from a blob to a byte array. An that references the pending asynchronous operation. The total number of bytes read into the buffer. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a byte array. The target byte array. The starting offset in the byte array. The starting offset of the data range, in bytes. The length of the data to download from the blob, in bytes. A object that represents the current operation. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a byte array. The target byte array. The starting offset in the byte array. The starting offset of the data range, in bytes. The length of the data to download from the blob, in bytes. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a byte array. The target byte array. The starting offset in the byte array. The starting offset of the data range, in bytes. The length of the data to download from the blob, in bytes. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a byte array. The target byte array. The starting offset in the byte array. The starting offset of the data range, in bytes. The length of the data to download from the blob, in bytes. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Checks existence of the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. true if the blob exists. Checks existence of the blob. If true, the command will be executed against the primary location. A object that specifies additional options for the request. An object that represents the context for the current operation. true if the blob exists. Begins an asynchronous request to check existence of the blob. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to check existence of the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to check existence of the blob. If true, the command will be executed against the primary location. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Returns the asynchronous result of the request to check existence of the blob. An that references the pending asynchronous operation. true if the blob exists. Returns a task that performs an asynchronous request to check existence of the blob. A object that represents the current operation. Returns a task that performs an asynchronous request to check existence of the blob. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous request to check existence of the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous request to check existence of the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Populates a blob's properties and metadata. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to populate the blob's properties and metadata. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to populate the blob's properties and metadata. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to populate the blob's properties and metadata. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to populate the blob's properties and metadata. A object that represents the current operation. Returns a task that performs an asynchronous operation to populate the blob's properties and metadata. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to populate the blob's properties and metadata. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to populate the blob's properties and metadata. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Updates the blob's metadata. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to update the blob's metadata. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to update the blob's metadata. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to update the blob's metadata. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to update the blob's metadata. A object that represents the current operation. Returns a task that performs an asynchronous operation to update the blob's metadata. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to update the blob's metadata. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to update the blob's metadata. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Updates the blob's properties. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to update the blob's properties. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to update the blob's properties. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to update the blob's properties. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to update the blob's properties. A object that represents the current operation. Returns a task that performs an asynchronous operation to update the blob's properties. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to update the blob's properties. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to update the blob's properties. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Deletes the blob. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to delete the blob. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to delete the blob. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to delete the blob. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to delete the blob. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete the blob. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete the blob. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete the blob. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Deletes the blob if it already exists. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. true if the blob did already exist and was deleted; otherwise false. Begins an asynchronous request to delete the blob if it already exists. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to delete the blob if it already exists. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Returns the result of an asynchronous request to delete the blob if it already exists. An that references the pending asynchronous operation. true if the blob did already exist and was deleted; otherwise, false. Returns a task that performs an asynchronous request to delete the blob if it already exists. A object that represents the current operation. Returns a task that performs an asynchronous request to delete the blob if it already exists. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous request to delete the blob if it already exists. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous request to delete the blob if it already exists. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Creates a snapshot of the blob. A collection of name-value pairs defining the metadata of the snapshot. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request, or null. An object that represents the context for the current operation. A blob snapshot. Begins an asynchronous operation to create a snapshot of the blob. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to create a snapshot of the blob. A collection of name-value pairs defining the metadata of the snapshot. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request, or null. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to create a snapshot of the blob. An that references the pending asynchronous operation. A blob snapshot. Returns a task that performs an asynchronous operation to create a snapshot of the blob. A object that represents the current operation. Returns a task that performs an asynchronous operation to create a snapshot of the blob. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to create a snapshot of the blob. A collection of name-value pairs defining the metadata of the snapshot. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to create a snapshot of the blob. A collection of name-value pairs defining the metadata of the snapshot. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Acquires a lease on this blob. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. If null, an infinite lease will be acquired. If not null, this must be greater than zero. A string representing the proposed lease ID for the new lease, or null if no lease ID is proposed. An object that represents the access conditions for the blob. If null, no condition is used. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. The ID of the acquired lease. Begins an asynchronous operation to acquire a lease on this blob. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. If null, an infinite lease will be acquired. If not null, this must be greater than zero. A string representing the proposed lease ID for the new lease, or null if no lease ID is proposed. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to acquire a lease on this blob. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. If null, an infinite lease will be acquired. If not null, this must be greater than zero. A string representing the proposed lease ID for the new lease, or null if no lease ID is proposed. An object that represents the access conditions for the blob. If null, no condition is used. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to acquire a lease on this blob. An IAsyncResult that references the pending asynchronous operation. The ID of the acquired lease. Returns a task that performs an asynchronous operation to acquire a lease on this blob. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. If null, an infinite lease will be acquired. If not null, this must be greater than zero. A string representing the proposed lease ID for the new lease, or null if no lease ID is proposed. A object that represents the current operation. Returns a task that performs an asynchronous operation to acquire a lease on this blob. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. If null, an infinite lease will be acquired. If not null, this must be greater than zero. A string representing the proposed lease ID for the new lease, or null if no lease ID is proposed. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to acquire a lease on this blob. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. If null, an infinite lease will be acquired. If not null, this must be greater than zero. A string representing the proposed lease ID for the new lease, or null if no lease ID is proposed. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to acquire a lease on this blob. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. If null, an infinite lease will be acquired. If not null, this must be greater than zero. A string representing the proposed lease ID for the new lease, or null if no lease ID is proposed. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Renews a lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. Begins an asynchronous operation to renew a lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to renew a lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to renew a lease on this blob. An IAsyncResult that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to renew a lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A object that represents the current operation. Returns a task that performs an asynchronous operation to renew a lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to renew a lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to renew a lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Changes the lease ID on this blob. A string representing the proposed lease ID for the new lease. This cannot be null. An object that represents the access conditions for the blob, including a required lease ID. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. The new lease ID. Begins an asynchronous operation to change the lease on this blob. A string representing the proposed lease ID for the new lease. This cannot be null. An object that represents the access conditions for the blob, including a required lease ID. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to change the lease on this blob. A string representing the proposed lease ID for the new lease. This cannot be null. An object that represents the access conditions for the blob, including a required lease ID. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to change the lease on this blob. An IAsyncResult that references the pending asynchronous operation. The new lease ID. Returns a task that performs an asynchronous operation to change the lease on this blob. A string representing the proposed lease ID for the new lease. This cannot be null. An object that represents the access conditions for the blob, including a required lease ID. A object that represents the current operation. Returns a task that performs an asynchronous operation to change the lease on this blob. A string representing the proposed lease ID for the new lease. This cannot be null. An object that represents the access conditions for the blob, including a required lease ID. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to change the lease on this blob. A string representing the proposed lease ID for the new lease. This cannot be null. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to change the lease on this blob. A string representing the proposed lease ID for the new lease. This cannot be null. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Releases the lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. Begins an asynchronous operation to release the lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to release the lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to release the lease on this blob. An IAsyncResult that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to release the lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A object that represents the current operation. Returns a task that performs an asynchronous operation to release the lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to release the lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to release the lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Breaks the current lease on this blob. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. If null, the break period is the remainder of the current lease, or zero for infinite leases. An object that represents the access conditions for the blob. If null, no condition is used. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. A representing the amount of time before the lease ends, to the second. Begins an asynchronous operation to break the current lease on this blob. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. If null, the break period is the remainder of the current lease, or zero for infinite leases. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to break the current lease on this blob. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. If null, the break period is the remainder of the current lease, or zero for infinite leases. An object that represents the access conditions for the blob. If null, no condition is used. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to break the current lease on this blob. An IAsyncResult that references the pending asynchronous operation. A representing the amount of time before the lease ends, to the second. Returns a task that performs an asynchronous operation to break the current lease on this blob. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. If null, the break period is the remainder of the current lease, or zero for infinite leases. A object that represents the current operation. Returns a task that performs an asynchronous operation to break the current lease on this blob. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. If null, the break period is the remainder of the current lease, or zero for infinite leases. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to break the current lease on this blob. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. If null, the break period is the remainder of the current lease, or zero for infinite leases. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to break the current lease on this blob. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. If null, the break period is the remainder of the current lease, or zero for infinite leases. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Uploads a single block. A base64-encoded block ID that identifies the block. A stream that provides the data for the block. An optional hash value that will be used to set the property on the blob. May be null or an empty string. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to upload a single block. A base64-encoded block ID that identifies the block. A stream that provides the data for the block. An optional hash value that will be used to set the property on the blob. May be null or an empty string. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to upload a single block. A base64-encoded block ID that identifies the block. A stream that provides the data for the block. An optional hash value that will be used to set the property on the blob. May be null or an empty string. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to upload a single block. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to upload a single block. A base64-encoded block ID that identifies the block. A stream that provides the data for the block. An optional hash value that will be used to set the property on the blob. May be null or an empty string. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a single block. A base64-encoded block ID that identifies the block. A stream that provides the data for the block. An optional hash value that will be used to set the property on the blob. May be null or an empty string. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a single block. A base64-encoded block ID that identifies the block. A stream that provides the data for the block. An optional hash value that will be used to set the property on the blob. May be null or an empty string. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a single block. A base64-encoded block ID that identifies the block. A stream that provides the data for the block. An optional hash value that will be used to set the property on the blob. May be null or an empty string. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Uploads a list of blocks to a new or existing blob. An enumerable collection of block IDs, as base64-encoded strings. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to upload a list of blocks to a new or existing blob. An enumerable collection of block IDs, as base64-encoded strings. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to upload a list of blocks to a new or existing blob. An enumerable collection of block IDs, as base64-encoded strings. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to upload a list of blocks to a new or existing blob. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to upload a list of blocks to a new or existing blob. An enumerable collection of block IDs, as base64-encoded strings. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a list of blocks to a new or existing blob. An enumerable collection of block IDs, as base64-encoded strings. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a list of blocks to a new or existing blob. An enumerable collection of block IDs, as base64-encoded strings. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a list of blocks to a new or existing blob. An enumerable collection of block IDs, as base64-encoded strings. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Returns an enumerable collection of the blob's blocks, using the specified block list filter. One of the enumeration values that indicates whether to return committed blocks, uncommitted blocks, or both. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. An enumerable collection of objects implementing . Begins an asynchronous operation to return an enumerable collection of the blob's blocks, using the specified block list filter. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to return an enumerable collection of the blob's blocks, using the specified block list filter. One of the enumeration values that indicates whether to return committed blocks, uncommitted blocks, or both. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to return an enumerable collection of the blob's blocks, using the specified block list filter. An that references the pending asynchronous operation. An enumerable collection of objects implementing . Returns a task that performs an asynchronous operation to return an enumerable collection of the blob's blocks, using the specified block list filter. A object that represents the current operation. Returns a task that performs an asynchronous operation to return an enumerable collection of the blob's blocks, using the specified block list filter. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to return an enumerable collection of the blob's blocks, using the specified block list filter. One of the enumeration values that indicates whether to return committed blocks, uncommitted blocks, or both. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to return an enumerable collection of the blob's blocks, using the specified block list filter. One of the enumeration values that indicates whether to return committed blocks, uncommitted blocks, or both. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Requests that the service start to copy a blob's contents, properties, and metadata to a new blob. The URI of a source blob. An object that represents the access conditions for the source blob. If null, no condition is used. An object that represents the access conditions for the destination blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The copy ID associated with the copy operation. This method fetches the blob's ETag, last modified time, and part of the copy state. The copy ID and copy status fields are fetched, and the rest of the copy state is cleared. Requests that the service start to copy a blob's contents, properties, and metadata to a new blob. The URI of a source blob. An object that represents the access conditions for the source blob. If null, no condition is used. An object that represents the access conditions for the destination blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The copy ID associated with the copy operation. This method fetches the blob's ETag, last modified time, and part of the copy state. The copy ID and copy status fields are fetched, and the rest of the copy state is cleared. Begins an asynchronous operation to request that the service start to copy a blob's contents, properties, and metadata to a new blob. The URI of a source blob. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to request that the service start to copy a blob's contents, properties, and metadata to a new blob. The source blob. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The URI of a source blob. An object that represents the access conditions for the source blob. If null, no condition is used. An object that represents the access conditions for the destination blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The source blob. An object that represents the access conditions for the source blob. If null, no condition is used. An object that represents the access conditions for the destination blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to request that the service start to copy a blob's contents, properties, and metadata to a new blob. An that references the pending asynchronous operation. The copy ID associated with the copy operation. This method fetches the blob's ETag, last modified time, and part of the copy state. The copy ID and copy status fields are fetched, and the rest of the copy state is cleared. Returns a task that performs an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The URI of a source blob. A object that represents the current operation. Returns a task that performs an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The URI of a source blob. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The source blob. A object that represents the current operation. Returns a task that performs an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The source blob. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The URI of a source blob. An object that represents the access conditions for the source blob. If null, no condition is used. An object that represents the access conditions for the destination blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The URI of a source blob. An object that represents the access conditions for the source blob. If null, no condition is used. An object that represents the access conditions for the destination blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The source blob. An object that represents the access conditions for the source blob. If null, no condition is used. An object that represents the access conditions for the destination blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The source blob. An object that represents the access conditions for the source blob. If null, no condition is used. An object that represents the access conditions for the destination blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Aborts an ongoing blob copy operation. A string identifying the copy operation. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to abort an ongoing blob copy operation. A string identifying the copy operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to abort an ongoing blob copy operation. A string identifying the copy operation. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to abort an ongoing blob copy operation. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to abort an ongoing blob copy operation. A string identifying the copy operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to abort an ongoing blob copy operation. A string identifying the copy operation. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to abort an ongoing blob copy operation. A string identifying the copy operation. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to abort an ongoing blob copy operation. A string identifying the copy operation. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Implementation for the CreateSnapshot method. A collection of name-value pairs defining the metadata of the snapshot, or null. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. A that creates the snapshot. If the metadata parameter is null then no metadata is associated with the request. Uploads the full blob from a seekable stream. The content stream. Must be seekable. Number of bytes to upload from the content stream starting at its current position. The content MD5. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. A that gets the stream. Uploads the block. The source stream. The block ID. The content MD5. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. A that uploads the block. Uploads the block list. The blocks to upload. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. A that uploads the block list. Gets the download block list. The types of blocks. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. A that gets the download block list. Default is 4 MB. Default is 4 MB. Initializes a new instance of the class using an absolute URI to the blob. The absolute URI to the blob. Initializes a new instance of the class using an absolute URI to the blob. The absolute URI to the blob. The account credentials. Initializes a new instance of the class using an absolute URI to the blob. The absolute URI to the blob. The snapshot timestamp, if the blob is a snapshot. The account credentials. Initializes a new instance of the class using an absolute URI to the blob. The absolute URI to the blob. The snapshot timestamp, if the blob is a snapshot. The account credentials. Initializes a new instance of the class using the specified blob name and the parent container reference. If snapshotTime is not null, the blob instance represents a Snapshot. Name of the blob. Snapshot time in case the blob is a snapshot. The reference to the parent container. Initializes a new instance of the class. The attributes. The service client. Stores the that contains this blob. Stores the blob's parent . Stores the blob's attributes. Returns a shared access signature for the blob. The access policy for the shared access signature. A shared access signature, as a URI query string. The query string returned includes the leading question mark. Returns a shared access signature for the blob. The access policy for the shared access signature. A stored access policy. A shared access signature, as a URI query string. The query string returned includes the leading question mark. Returns a shared access signature for the blob. The access policy for the shared access signature. The optional header values to set for a blob accessed with this SAS. A shared access signature. Returns a shared access signature for the blob. The access policy for the shared access signature. The optional header values to set for a blob returned with this SAS. A stored access policy. A shared access signature. Gets the canonical name of the blob, formatted as /<account-name>/<container-name>/<blob-name>. If ignoreSnapshotTime is false and this blob is a snapshot, the canonical name is augmented with a query of the form ?snapshot=<snapshot-time>. This is used by both Shared Access and Copy blob operations. Indicates if the snapshot time is ignored. The canonical name of the blob. Parse URI for SAS (Shared Access Signature) and snapshot information. The complete Uri. The credentials to use. Gets the object that represents the Blob service. A client object that specifies the Blob service endpoint. Gets or sets the block size for writing to a block blob. The size of a block, in bytes, ranging from between 16 KB and 4 MB inclusive. Gets or sets the minimum number of bytes to buffer when reading from a blob stream. The minimum number of bytes to buffer, being at least 16KB. Gets the blob's system properties. The blob's properties. Gets the user-defined metadata for the blob. The blob's metadata, as a collection of name-value pairs. Gets the blob's URI for the primary location. The absolute URI to the blob, at the primary location. Gets the block blob's URIs for all locations. An object of type containing the block blob's URIs for all locations. Gets the date and time that the blob snapshot was taken, if this blob is a snapshot. The blob's snapshot time, if the blob is a snapshot. If the blob is not a snapshot, the value of this property is null. Gets a value indicating whether this blob is a snapshot. true if this blob is a snapshot; otherwise, false. Gets the absolute URI to the blob, including query string information if the blob is a snapshot. The absolute URI to the blob, including snapshot query information if the blob is a snapshot. Gets the block blob's URI for all locations, including query string information if the blob is a snapshot. An object of type containing the block blob's URIs for all locations, including snapshot query information if the blob is a snapshot. Gets the state of the most recent or pending copy operation. A object containing the copy state, or null if no copy blob state exists for this blob. Gets the type of the blob. The type of the blob. Gets the blob's name. The blob's name. Gets a object representing the blob's container. The blob's container. Gets the object representing the virtual parent directory for the blob. The blob's virtual parent directory. Represents a Windows Azure page blob. Represents a Windows Azure page blob. Opens a stream for reading from the blob. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A stream to be used for reading from the blob. On the object returned by this method, the method must be called exactly once for every call. Failing to end a read process before beginning another read can cause unknown behavior. Begins an asynchronous operation to open a stream for reading from the blob. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to open a stream for reading from the blob. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to open a stream for reading from the blob. An that references the pending asynchronous operation. A stream to be used for reading from the blob. Returns a task that performs an asynchronous operation to open a stream for reading from the blob. A object that represents the current operation. Returns a task that performs an asynchronous operation to open a stream for reading from the blob. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to open a stream for reading from the blob. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to open a stream for reading from the blob. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Opens a stream for writing to the blob. The size of the page blob, in bytes. The size must be a multiple of 512. If null, the page blob must already exist. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A stream to be used for writing to the blob. Begins an asynchronous operation to open a stream for writing to the blob. The size of the page blob, in bytes. The size must be a multiple of 512. If null, the page blob must already exist. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to open a stream for writing to the blob. The size of the page blob, in bytes. The size must be a multiple of 512. If null, the page blob must already exist. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to open a stream for writing to the blob. An that references the pending asynchronous operation. A stream to be used for writing to the blob. Returns a task that performs an asynchronous operation to open a stream for writing to the blob. The size of the page blob, in bytes. The size must be a multiple of 512. If null, the page blob must already exist. A object that represents the current operation. Returns a task that performs an asynchronous operation to open a stream for writing to the blob. The size of the page blob, in bytes. The size must be a multiple of 512. If null, the page blob must already exist. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to open a stream for writing to the blob. The size of the page blob, in bytes. The size must be a multiple of 512. If null, the page blob must already exist. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to open a stream for writing to the blob. The size of the page blob, in bytes. The size must be a multiple of 512. If null, the page blob must already exist. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Downloads the contents of a blob to a stream. The target stream. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to download the contents of a blob to a stream. The target stream. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to download the contents of a blob to a stream. The target stream. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to download the contents of a blob to a stream. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a stream. The target stream. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a stream. The target stream. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a stream. The target stream. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a stream. The target stream. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Downloads the contents of a blob to a file. The target file. A constant that determines how to open or create the file. An object that represents the access conditions for the blob. An object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to download the contents of a blob to a file. The target file. A constant that determines how to open or create the file. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to download the contents of a blob to a file. The target file. A constant that determines how to open or create the file. An object that represents the access conditions for the blob. An object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Called when the asynchronous DownloadToStream operation completes. The result of the asynchronous operation. Ends an asynchronous operation to download the contents of a blob to a file. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a file. The target file. A constant that determines how to open or create the file. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a file. The target file. A constant that determines how to open or create the file. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a file. The target file. A constant that determines how to open or create the file. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a file. The target file. A constant that determines how to open or create the file. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Downloads the contents of a blob to a byte array. The target byte array. The starting offset in the byte array. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The total number of bytes read into the buffer. Begins an asynchronous operation to download the contents of a blob to a byte array. The target byte array. The starting offset in the byte array. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to download the contents of a blob to a byte array. The target byte array. The starting offset in the byte array. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to download the contents of a blob to a byte array. An that references the pending asynchronous operation. The total number of bytes read into the buffer. Returns a task that performs an asynchronous operation to download the contents of a blob to a byte array. The target byte array. The starting offset in the byte array. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a byte array. The target byte array. The starting offset in the byte array. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a byte array. The target byte array. The starting offset in the byte array. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a byte array. The target byte array. The starting offset in the byte array. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Downloads a range of bytes from a blob to a stream. The target stream. The offset at which to begin downloading the blob, in bytes. The length of the data to download from the blob, in bytes. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to download a range of bytes from a blob to a stream. The target stream. The offset at which to begin downloading the blob, in bytes. The length of the data to download from the blob, in bytes. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to download a range of bytes from a blob to a stream. The target stream. The offset at which to begin downloading the blob, in bytes. The length of the data to download from the blob, in bytes. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to download a range of bytes from a blob to a stream. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a stream. The target stream. The offset at which to begin downloading the blob, in bytes. The length of the data to download from the blob, in bytes. A object that represents the current operation. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a stream. The target stream. The offset at which to begin downloading the blob, in bytes. The length of the data to download from the blob, in bytes. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a stream. The target stream. The offset at which to begin downloading the blob, in bytes. The length of the data to download from the blob, in bytes. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a stream. The target stream. The offset at which to begin downloading the blob, in bytes. The length of the data to download from the blob, in bytes. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Downloads a range of bytes from a blob to a byte array. The target byte array. The starting offset in the byte array. The starting offset of the data range, in bytes. The length of the data to download from the blob, in bytes. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The total number of bytes read into the buffer. Begins an asynchronous operation to download a range of bytes from a blob to a byte array. The target byte array. The starting offset in the byte array. The starting offset of the data range, in bytes. The length of the data to download from the blob, in bytes. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to download a range of bytes from a blob to a byte array. The target byte array. The starting offset in the byte array. The starting offset of the data range, in bytes. The length of the data to download from the blob, in bytes. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Called when the asynchronous DownloadRangeToStream operation completes. The result of the asynchronous operation. Ends an asynchronous operation to download a range of bytes from a blob to a byte array. An that references the pending asynchronous operation. The total number of bytes read into the buffer. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a byte array. The target byte array. The starting offset in the byte array. The starting offset of the data range, in bytes. The length of the data to download from the blob, in bytes. A object that represents the current operation. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a byte array. The target byte array. The starting offset in the byte array. The starting offset of the data range, in bytes. The length of the data to download from the blob, in bytes. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a byte array. The target byte array. The starting offset in the byte array. The starting offset of the data range, in bytes. The length of the data to download from the blob, in bytes. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a byte array. The target byte array. The starting offset in the byte array. The starting offset of the data range, in bytes. The length of the data to download from the blob, in bytes. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Uploads a stream to a page blob. The stream providing the blob content. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Uploads a stream to a page blob. The stream providing the blob content. The number of bytes to write from the source stream at its current position. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Uploads a stream to a page blob. The stream providing the blob content. The number of bytes to write from the source stream at its current position. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to upload a stream to a page blob. The stream providing the blob content. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to upload a stream to a page blob. The stream providing the blob content. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to upload a stream to a page blob. The stream providing the blob content. Specifies the number of bytes from the Stream source to upload from the start position. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to upload a stream to a page blob. The stream providing the blob content. Specifies the number of bytes from the Stream source to upload from the start position. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to upload a stream to a page blob. The stream providing the blob content. Specifies the number of bytes from the Stream source to upload from the start position. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to upload a stream to a page blob. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to upload a stream to a page blob. The stream providing the blob content. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a stream to a page blob. The stream providing the blob content. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a stream to a page blob. The stream providing the blob content. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a stream to a page blob. The stream providing the blob content. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a stream to a page blob. The stream providing the blob content. The number of bytes to write from the source stream at its current position. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a stream to a page blob. The stream providing the blob content. The number of bytes to write from the source stream at its current position. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a stream to a page blob. The stream providing the blob content. The number of bytes to write from the source stream at its current position. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a stream to a page blob. The stream providing the blob content. The number of bytes to write from the source stream at its current position. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Uploads a file to the Windows Azure Blob Service. The file providing the blob content. A constant that determines how to open the file. An object that represents the access conditions for the blob. An object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to upload a file to a blob. The file providing the blob content. A constant that determines how to open the file. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to upload a file to a blob. The file providing the blob content. A constant that determines how to open the file. An object that represents the access conditions for the blob. An object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Called when the asynchronous UploadFromStream operation completes. The result of the asynchronous operation. Ends an asynchronous operation to upload a file to a blob. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to upload a file to a blob. The file providing the blob content. A constant that determines how to open the file. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a file to a blob. The file providing the blob content. A constant that determines how to open the file. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a file to a blob. The file providing the blob content. A constant that determines how to open the file. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a file to a blob. The file providing the blob content. A constant that determines how to open the file. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Uploads the contents of a byte array to a blob. An array of bytes. The zero-based byte offset in buffer at which to begin uploading bytes to the blob. The number of bytes to be written to the blob. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to upload the contents of a byte array to a blob. An array of bytes. The zero-based byte offset in buffer at which to begin uploading bytes to the blob. The number of bytes to be written to the blob. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to upload the contents of a byte array to a blob. An array of bytes. The zero-based byte offset in buffer at which to begin uploading bytes to the blob. The number of bytes to be written to the blob. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to upload the contents of a byte array to a blob. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to upload the contents of a byte array to a blob. An array of bytes. The zero-based byte offset in buffer at which to begin uploading bytes to the blob. The number of bytes to be written to the blob. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload the contents of a byte array to a blob. An array of bytes. The zero-based byte offset in buffer at which to begin uploading bytes to the blob. The number of bytes to be written to the blob. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload the contents of a byte array to a blob. An array of bytes. The zero-based byte offset in buffer at which to begin uploading bytes to the blob. The number of bytes to be written to the blob. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload the contents of a byte array to a blob. An array of bytes. The zero-based byte offset in buffer at which to begin uploading bytes to the blob. The number of bytes to be written to the blob. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Creates a page blob. The maximum size of the page blob, in bytes. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to create a page blob. The maximum size of the page blob, in bytes. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to create a page blob. The maximum size of the blob, in bytes. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to create a page blob. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to create a page blob. The maximum size of the blob, in bytes. A object that represents the current operation. Returns a task that performs an asynchronous operation to create a page blob. The maximum size of the blob, in bytes. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to create a page blob. The maximum size of the blob, in bytes. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to create a page blob. The maximum size of the blob, in bytes. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Resizes the page blob to the specified size. The size of the page blob, in bytes. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to resize the page blob to the specified size. The size of the page blob, in bytes. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to resize the page blob to the specified size. The size of the blob, in bytes. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to resize the page blob. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to resize the page blob to the specified size. The size of the blob, in bytes. A object that represents the current operation. Returns a task that performs an asynchronous operation to resize the page blob to the specified size. The size of the blob, in bytes. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to resize the page blob to the specified size. The size of the blob, in bytes. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to resize the page blob to the specified size. The size of the blob, in bytes. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Sets the page blob's sequence number. A value of type , indicating the operation to perform on the sequence number. The sequence number. Set this parameter to null if is equal to . An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to set the page blob's sequence number. A value of type , indicating the operation to perform on the sequence number. The sequence number. Set this parameter to null if is equal to . The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to set the page blob's sequence number. A value of type , indicating the operation to perform on the sequence number. The sequence number. Set this parameter to null if is equal to . An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to set the page blob's sequence number. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to set the page blob's sequence number. A value of type , indicating the operation to perform on the sequence number. The sequence number. Set this parameter to null if is equal to . A object that represents the current operation. Returns a task that performs an asynchronous operation to set the page blob's sequence number. A value of type , indicating the operation to perform on the sequence number. The sequence number. Set this parameter to null if is equal to . A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to set the page blob's sequence number. A value of type , indicating the operation to perform on the sequence number. The sequence number. Set this parameter to null if is equal to . An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to set the page blob's sequence number. A value of type , indicating the operation to perform on the sequence number. The sequence number. Set this parameter to null if is equal to . An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Checks existence of the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. true if the blob exists. Checks existence of the blob. If true, the command will be executed against the primary location. A object that specifies additional options for the request. An object that represents the context for the current operation. true if the blob exists. Begins an asynchronous request to check existence of the blob. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to check existence of the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to check existence of the blob. If true, the command will be executed against the primary location. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Returns the asynchronous result of the request to check existence of the blob. An that references the pending asynchronous operation. true if the blob exists. Returns a task that performs an asynchronous request to check existence of the blob. A object that represents the current operation. Returns a task that performs an asynchronous request to check existence of the blob. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous request to check existence of the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous request to check existence of the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Populates a blob's properties and metadata. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to populate the blob's properties and metadata. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to populate the blob's properties and metadata. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to populate the blob's properties and metadata. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to populate the blob's properties and metadata. A object that represents the current operation. Returns a task that performs an asynchronous operation to populate the blob's properties and metadata. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to populate the blob's properties and metadata. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to populate the blob's properties and metadata. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Gets a collection of valid page ranges and their starting and ending bytes. The starting offset of the data range over which to list page ranges, in bytes. Must be a multiple of 512. The length of the data range over which to list page ranges, in bytes. Must be a multiple of 512. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. An enumerable collection of page ranges. Begins an asynchronous operation to return a collection of valid page ranges and their starting and ending bytes. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to return a collection of valid page ranges and their starting and ending bytes. The starting offset of the data range over which to list page ranges, in bytes. Must be a multiple of 512. The length of the data range over which to list page ranges, in bytes. Must be a multiple of 512. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to return a collection of valid page ranges and their starting and ending bytes. An that references the pending asynchronous operation. An enumerable collection of page ranges. Returns a task that performs an asynchronous operation to return a collection of page ranges and their starting and ending bytes. A object that represents the current operation. Returns a task that performs an asynchronous operation to return a collection of page ranges and their starting and ending bytes. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to return a collection of page ranges and their starting and ending bytes. The starting offset of the data range, in bytes. Must be a multiple of 512. The length of the data range, in bytes. Must be a multiple of 512. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to return a collection of page ranges and their starting and ending bytes. The starting offset of the data range, in bytes. Must be a multiple of 512. The length of the data range, in bytes. Must be a multiple of 512. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Updates the blob's metadata. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to update the blob's metadata. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to update the blob's metadata. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to update the blob's metadata. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to update the blob's metadata. A object that represents the current operation. Returns a task that performs an asynchronous operation to update the blob's metadata. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to update the blob's metadata. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to update the blob's metadata. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Updates the blob's properties. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to update the blob's properties. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to update the blob's properties. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to update the blob's properties. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to update the blob's properties. A object that represents the current operation. Returns a task that performs an asynchronous operation to update the blob's properties. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to update the blob's properties. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to update the blob's properties. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Deletes the blob. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to delete the blob. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to delete the blob. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to delete the blob. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to delete the blob. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete the blob. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete the blob. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete the blob. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Deletes the blob if it already exists. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. true if the blob did already exist and was deleted; otherwise false. Begins an asynchronous request to delete the blob if it already exists. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to delete the blob if it already exists. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Returns the result of an asynchronous request to delete the blob if it already exists. An that references the pending asynchronous operation. true if the blob did already exist and was deleted; otherwise, false. Returns a task that performs an asynchronous request to delete the blob if it already exists. A object that represents the current operation. Returns a task that performs an asynchronous request to delete the blob if it already exists. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous request to delete the blob if it already exists. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous request to delete the blob if it already exists. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Creates a snapshot of the blob. A collection of name-value pairs defining the metadata of the snapshot. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request, or null. An object that represents the context for the current operation. A blob snapshot. Begins an asynchronous operation to create a snapshot of the blob. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to create a snapshot of the blob. A collection of name-value pairs defining the metadata of the snapshot. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request, or null. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to create a snapshot of the blob. An that references the pending asynchronous operation. A blob snapshot. Returns a task that performs an asynchronous operation to create a snapshot of the blob. A object that represents the current operation. Returns a task that performs an asynchronous operation to create a snapshot of the blob. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to create a snapshot of the blob. A collection of name-value pairs defining the metadata of the snapshot. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to create a snapshot of the blob. A collection of name-value pairs defining the metadata of the snapshot. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Acquires a lease on this blob. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. If null, an infinite lease will be acquired. If not null, this must be greater than zero. A string representing the proposed lease ID for the new lease, or null if no lease ID is proposed. An object that represents the access conditions for the blob. If null, no condition is used. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. The ID of the acquired lease. Begins an asynchronous operation to acquire a lease on this blob. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. If null, an infinite lease will be acquired. If not null, this must be greater than zero. A string representing the proposed lease ID for the new lease, or null if no lease ID is proposed. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to acquire a lease on this blob. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. If null, an infinite lease will be acquired. If not null, this must be greater than zero. A string representing the proposed lease ID for the new lease, or null if no lease ID is proposed. An object that represents the access conditions for the blob. If null, no condition is used. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to acquire a lease on this blob. An IAsyncResult that references the pending asynchronous operation. The ID of the acquired lease. Returns a task that performs an asynchronous operation to acquire a lease on this blob. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. If null, an infinite lease will be acquired. If not null, this must be greater than zero. A string representing the proposed lease ID for the new lease, or null if no lease ID is proposed. A object that represents the current operation. Returns a task that performs an asynchronous operation to acquire a lease on this blob. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. If null, an infinite lease will be acquired. If not null, this must be greater than zero. A string representing the proposed lease ID for the new lease, or null if no lease ID is proposed. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to acquire a lease on this blob. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. If null, an infinite lease will be acquired. If not null, this must be greater than zero. A string representing the proposed lease ID for the new lease, or null if no lease ID is proposed. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to acquire a lease on this blob. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. If null, an infinite lease will be acquired. If not null, this must be greater than zero. A string representing the proposed lease ID for the new lease, or null if no lease ID is proposed. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Renews a lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. Begins an asynchronous operation to renew a lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to renew a lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to renew a lease on this blob. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to renew a lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A object that represents the current operation. Returns a task that performs an asynchronous operation to renew a lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to renew a lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to renew a lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Changes the lease ID on this blob. A string representing the proposed lease ID for the new lease. This cannot be null. An object that represents the access conditions for the blob, including a required lease ID. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. The new lease ID. Begins an asynchronous operation to change the lease on this blob. A string representing the proposed lease ID for the new lease. This cannot be null. An object that represents the access conditions for the blob, including a required lease ID. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to change the lease on this blob. A string representing the proposed lease ID for the new lease. This cannot be null. An object that represents the access conditions for the blob, including a required lease ID. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to change the lease on this blob. An that references the pending asynchronous operation. The new lease ID. Returns a task that performs an asynchronous operation to change the lease on this blob. A string representing the proposed lease ID for the new lease. This cannot be null. An object that represents the access conditions for the blob, including a required lease ID. A object that represents the current operation. Returns a task that performs an asynchronous operation to change the lease on this blob. A string representing the proposed lease ID for the new lease. This cannot be null. An object that represents the access conditions for the blob, including a required lease ID. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to change the lease on this blob. A string representing the proposed lease ID for the new lease. This cannot be null. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to change the lease on this blob. A string representing the proposed lease ID for the new lease. This cannot be null. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Releases the lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. Begins an asynchronous operation to release the lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to release the lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to release the lease on this blob. An IAsyncResult that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to release the lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A object that represents the current operation. Returns a task that performs an asynchronous operation to release the lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to release the lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to release the lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Breaks the current lease on this blob. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. If null, the break period is the remainder of the current lease, or zero for infinite leases. An object that represents the access conditions for the blob. If null, no condition is used. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. A representing the amount of time before the lease ends, to the second. Begins an asynchronous operation to break the current lease on this blob. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. If null, the break period is the remainder of the current lease, or zero for infinite leases. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to break the current lease on this blob. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. If null, the break period is the remainder of the current lease, or zero for infinite leases. An object that represents the access conditions for the blob. If null, no condition is used. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to break the current lease on this blob. An IAsyncResult that references the pending asynchronous operation. A representing the amount of time before the lease ends, to the second. Returns a task that performs an asynchronous operation to break the current lease on this blob. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. If null, the break period is the remainder of the current lease, or zero for infinite leases. A object that represents the current operation. Returns a task that performs an asynchronous operation to break the current lease on this blob. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. If null, the break period is the remainder of the current lease, or zero for infinite leases. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to break the current lease on this blob. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. If null, the break period is the remainder of the current lease, or zero for infinite leases. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to break the current lease on this blob. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. If null, the break period is the remainder of the current lease, or zero for infinite leases. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Writes pages to a page blob. A stream providing the page data. The offset at which to begin writing, in bytes. The offset must be a multiple of 512. An optional hash value that will be used to set the property on the blob. May be null or an empty string. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to write pages to a page blob. A stream providing the page data. The offset at which to begin writing, in bytes. The offset must be a multiple of 512. An optional hash value that will be used to set the property on the blob. May be null or an empty string. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to write pages to a page blob. A stream providing the page data. The offset at which to begin writing, in bytes. The offset must be a multiple of 512. An optional hash value that will be used to set the property on the blob. May be null or an empty string. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to write pages to a page blob. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to write pages to a page blob. A stream providing the page data. The offset at which to begin writing, in bytes. The offset must be a multiple of 512. An optional hash value that will be used to set the property on the blob. May be null or an empty string. A object that represents the current operation. Returns a task that performs an asynchronous operation to write pages to a page blob. A stream providing the page data. The offset at which to begin writing, in bytes. The offset must be a multiple of 512. An optional hash value that will be used to set the property on the blob. May be null or an empty string. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to write pages to a page blob. A stream providing the page data. The offset at which to begin writing, in bytes. The offset must be a multiple of 512. An optional hash value that will be used to set the property on the blob. May be null or an empty string. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to write pages to a page blob. A stream providing the page data. The offset at which to begin writing, in bytes. The offset must be a multiple of 512. An optional hash value that will be used to set the property on the blob. May be null or an empty string. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Clears pages from a page blob. The offset at which to begin clearing pages, in bytes. The offset must be a multiple of 512. The length of the data range to be cleared, in bytes. The length must be a multiple of 512. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to clear pages from a page blob. The offset at which to begin clearing pages, in bytes. The offset must be a multiple of 512. The length of the data range to be cleared, in bytes. The length must be a multiple of 512. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to clear pages from a page blob. The offset at which to begin clearing pages, in bytes. The offset must be a multiple of 512. The length of the data range to be cleared, in bytes. The length must be a multiple of 512. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to clear pages from a page blob. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to clear pages from a page blob. The offset at which to begin clearing pages, in bytes. The offset must be a multiple of 512. The length of the data range to be cleared, in bytes. The length must be a multiple of 512. A object that represents the current operation. Returns a task that performs an asynchronous operation to clear pages from a page blob. The offset at which to begin clearing pages, in bytes. The offset must be a multiple of 512. The length of the data range to be cleared, in bytes. The length must be a multiple of 512. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to clear pages from a page blob. The offset at which to begin clearing pages, in bytes. The offset must be a multiple of 512. The length of the data range to be cleared, in bytes. The length must be a multiple of 512. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to clear pages from a page blob. The offset at which to begin clearing pages, in bytes. The offset must be a multiple of 512. The length of the data range to be cleared, in bytes. The length must be a multiple of 512. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Requests that the service start to copy a blob's contents, properties, and metadata to a new blob. The URI of a source blob. An object that represents the access conditions for the source blob. If null, no condition is used. An object that represents the access conditions for the destination blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The copy ID associated with the copy operation. This method fetches the blob's ETag, last modified time, and part of the copy state. The copy ID and copy status fields are fetched, and the rest of the copy state is cleared. Requests that the service start to copy a blob's contents, properties, and metadata to a new blob. The URI of a source blob. An object that represents the access conditions for the source blob. If null, no condition is used. An object that represents the access conditions for the destination blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The copy ID associated with the copy operation. This method fetches the blob's ETag, last modified time, and part of the copy state. The copy ID and copy status fields are fetched, and the rest of the copy state is cleared. Begins an asynchronous operation to request that the service start to copy a blob's contents, properties, and metadata to a new blob. The URI of a source blob. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to request that the service start to copy a blob's contents, properties, and metadata to a new blob. The source blob. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The URI of a source blob. An object that represents the access conditions for the source blob. If null, no condition is used. An object that represents the access conditions for the destination blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The source blob. An object that represents the access conditions for the source blob. If null, no condition is used. An object that represents the access conditions for the destination blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to request that the service start to copy a blob's contents, properties, and metadata to a new blob. An that references the pending asynchronous operation. The copy ID associated with the copy operation. This method fetches the blob's ETag, last modified time, and part of the copy state. The copy ID and copy status fields are fetched, and the rest of the copy state is cleared. Returns a task that performs an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The URI of a source blob. A object that represents the current operation. Returns a task that performs an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The URI of a source blob. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The source blob. A object that represents the current operation. Returns a task that performs an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The source blob. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The URI of a source blob. An object that represents the access conditions for the source blob. If null, no condition is used. An object that represents the access conditions for the destination blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The URI of a source blob. An object that represents the access conditions for the source blob. If null, no condition is used. An object that represents the access conditions for the destination blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The source blob. An object that represents the access conditions for the source blob. If null, no condition is used. An object that represents the access conditions for the destination blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The source blob. An object that represents the access conditions for the source blob. If null, no condition is used. An object that represents the access conditions for the destination blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Aborts an ongoing blob copy operation. A string identifying the copy operation. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to abort an ongoing blob copy operation. A string identifying the copy operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to abort an ongoing blob copy operation. A string identifying the copy operation. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to abort an ongoing blob copy operation. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to abort an ongoing blob copy operation. A string identifying the copy operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to abort an ongoing blob copy operation. A string identifying the copy operation. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to abort an ongoing blob copy operation. A string identifying the copy operation. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to abort an ongoing blob copy operation. A string identifying the copy operation. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Implements the Create method. The size in bytes. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. A that creates the blob. Implementation for the Resize method. The size in bytes. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. A that sets the metadata. Implementation for the SetSequenceNumber method. A value of type , indicating the operation to perform on the sequence number. The sequence number. Set this parameter to null if this operation is an increment action. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. A that sets the sequence number. Implementation for the CreateSnapshot method. A collection of name-value pairs defining the metadata of the snapshot, or null. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. A that creates the snapshot. If the metadata parameter is null then no metadata is associated with the request. Gets the page ranges impl. The starting offset of the data range over which to list page ranges, in bytes. Must be a multiple of 512. The length of the data range over which to list page ranges, in bytes. Must be a multiple of 512. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. A for getting the page ranges. Implementation method for the WritePage methods. The page data. The start offset. The content MD5. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. A that writes the pages. Implementation method for the ClearPage methods. The start offset. Must be multiples of 512. Length of the data range to be cleared. Must be multiples of 512. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. A that writes the pages. Default is 4 MB. Default is 4 MB. Initializes a new instance of the class using an absolute URI to the blob. The absolute URI to the blob. Initializes a new instance of the class using an absolute URI to the blob. The absolute URI to the blob. The account credentials. Initializes a new instance of the class using an absolute URI to the blob. The absolute URI to the blob. The snapshot timestamp, if the blob is a snapshot. The account credentials. Initializes a new instance of the class using an absolute URI to the blob. The absolute URI to the blob. The service assumes this is the URI for the blob in the primary location. The snapshot timestamp, if the blob is a snapshot. The account credentials. Initializes a new instance of the class using the specified blob name and the parent container reference. If snapshotTime is not null, the blob instance represents a Snapshot. Name of the blob. Snapshot time in case the blob is a snapshot. The reference to the parent container. Initializes a new instance of the class. The attributes. The service client. Stores the that contains this blob. Stores the blob's parent . Stores the blob's attributes. Returns a shared access signature for the blob. The access policy for the shared access signature. A shared access signature, as a URI query string. The query string returned includes the leading question mark. Returns a shared access signature for the blob. The access policy for the shared access signature. A stored access policy. A shared access signature, as a URI query string. The query string returned includes the leading question mark. Returns a shared access signature for the blob. The access policy for the shared access signature. The optional header values to set for a blob accessed with this SAS. A shared access signature. Returns a shared access signature for the blob. The access policy for the shared access signature. The optional header values to set for a blob returned with this SAS. A stored access policy. A shared access signature. Gets the canonical name of the blob, formatted as /<account-name>/<container-name>/<blob-name>. If ignoreSnapshotTime is false and this blob is a snapshot, the canonical name is augmented with a query of the form ?snapshot=<snapshot-time>. This is used by both Shared Access and Copy blob operations. Indicates if the snapshot time is ignored. The canonical name of the blob. Parse URI for SAS (Shared Access Signature) and snapshot information. The complete Uri. The credentials to use. Gets the object that represents the Blob service. A client object that specifies the Blob service endpoint. Gets or sets the number of bytes to buffer when writing to a page blob stream. The number of bytes to buffer, ranging from between 512 bytes and 4 MB inclusive. Gets or sets the minimum number of bytes to buffer when reading from a blob stream. The minimum number of bytes to buffer, being at least 16KB. Gets the blob's system properties. The blob's properties. Gets the user-defined metadata for the blob. The blob's metadata, as a collection of name-value pairs. Gets the blob's URI for the primary location. The absolute URI to the blob, at the primary location. Gets the page blob's URIs for all locations. An object of type containing the page blob's URIs for all locations. Gets the date and time that the blob snapshot was taken, if this blob is a snapshot. The blob's snapshot time, if the blob is a snapshot. If the blob is not a snapshot, the value of this property is null. Gets a value indicating whether this blob is a snapshot. true if this blob is a snapshot; otherwise, false. Gets the absolute URI to the blob, including query string information if the blob is a snapshot. The absolute URI to the blob, including snapshot query information if the blob is a snapshot. Gets the page blob's URI for all locations, including query string information if the blob is a snapshot. An object of type containing the page blob's URIs for all locations, including snapshot query information if the blob is a snapshot. Gets the state of the most recent or pending copy operation. A object containing the copy state, or null if no copy blob state exists for this blob. Gets the type of the blob. The type of the blob. Gets the blob's name. The blob's name. Gets a object representing the blob's container. The blob's container. Gets the object representing the virtual parent directory for the blob. The blob's virtual parent directory. Provides a set of methods for parsing a response containing blob data from the Blob service. Gets the request ID from the response. The web response. A unique value associated with the request. Gets the blob's properties from the response. The web response. The blob's properties. Extracts the lease status from a web response. The web response. A enumeration from the web response. If the appropriate header is not present, a status of is returned. The header contains an unrecognized value. Extracts the lease state from a web response. The web response. A enumeration from the web response. If the appropriate header is not present, a status of is returned. The header contains an unrecognized value. Extracts the lease duration from a web response. The web response. A enumeration from the web response. If the appropriate header is not present, a status of is returned. The header contains an unrecognized value. Extracts the lease ID header from a web response. The web response. The lease ID. Extracts the remaining lease time from a web response. The web response. The remaining lease time, in seconds. Gets the user-defined metadata. The response from server. A of the metadata. Extracts a object from the headers of a web response. The HTTP web response. A object, or null if the web response does not contain a copy status. Gets the snapshot timestamp from the response. The web response. The snapshot timestamp. Reads service properties from a stream. The stream from which to read the service properties. The service properties stored in the stream. Reads service stats from a stream. The stream from which to read the service stats. The service stats stored in the stream. Gets a from a string. The lease status string. A enumeration. If a null or empty string is supplied, a status of is returned. The string contains an unrecognized value. Gets a from a string. The lease state string. A enumeration. If a null or empty string is supplied, a status of is returned. The string contains an unrecognized value. Gets a from a string. The lease duration string. A enumeration. If a null or empty string is supplied, a status of is returned. The string contains an unrecognized value. Builds a object from the given strings containing formatted copy information. The copy status, as a string. The copy ID. The source URI of the copy, as a string. A string formatted as progressBytes/TotalBytes. The copy completion time, as a string, or null. The copy status description, if any. A object populated from the given strings. A factory class for constructing a web request to manage blobs in the Blob service. Creates a web request to get the properties of the Blob service. The absolute URI to the Blob service. An object of type , containing additional parameters to add to the URI query string. The server timeout interval, in seconds. An object for tracking the current operation. A web request to get the Blob service properties. Creates a web request to set the properties of the Blob service. The absolute URI to the Blob service. An object of type , containing additional parameters to add to the URI query string. The server timeout interval, in seconds. An object for tracking the current operation. A web request to set the Blob service properties. Creates a web request to get the stats of the Blob service. The absolute URI to the Blob service. An object of type , containing additional parameters to add to the URI query string. The server timeout interval, in seconds. An object for tracking the current operation. A web request to get the Blob service stats. Writes Blob service properties to a stream, formatted in XML. The service properties to format and write to the stream. The stream to which the formatted properties are to be written. Constructs a web request to create a new block blob or page blob, or to update the content of an existing block blob. The absolute URI to the blob. The server timeout interval. The properties to set for the blob. The type of the blob. For a page blob, the size of the blob. This parameter is ignored for block blobs. The access condition to apply to the request. An object for tracking the current operation. A web request to use to perform the operation. Adds the snapshot. An object of type that contains additional parameters to add to the URI query string. The snapshot version, if the blob is a snapshot. Constructs a web request to return the list of valid page ranges for a page blob. The absolute URI to the blob. The server timeout interval. The snapshot timestamp, if the blob is a snapshot. The starting offset of the data range over which to list page ranges, in bytes. Must be a multiple of 512. The length of the data range over which to list page ranges, in bytes. Must be a multiple of 512. The access condition to apply to the request. An object for tracking the current operation. A web request to use to perform the operation. Adds the Range Header for Blob Service Operations. Request Starting byte of the range Number of bytes in the range Constructs a web request to return the blob's system properties. The absolute URI to the blob. The server timeout interval. The snapshot timestamp, if the blob is a snapshot. The access condition to apply to the request. An object for tracking the current operation. A web request for performing the operation. Constructs a web request to set system properties for a blob. The absolute URI to the blob. The server timeout interval. The blob's properties. The access condition to apply to the request. An object for tracking the current operation. A web request to use to perform the operation. Constructs a web request to resize a page blob. The absolute URI to the blob. The server timeout interval. The new blob size, if the blob is a page blob. Set this parameter to null to keep the existing blob size. The access condition to apply to the request. An object for tracking the current operation. A web request to use to perform the operation. Constructs a web request to set a page blob's sequence number. The absolute URI to the blob. The server timeout interval. A value of type , indicating the operation to perform on the sequence number. The sequence number. Set this parameter to null if this operation is an increment action. The access condition to apply to the request. An object for tracking the current operation. A web request to use to perform the operation. Constructs a web request to return the user-defined metadata for the blob. The absolute URI to the blob. The server timeout interval. The snapshot timestamp, if the blob is a snapshot. The access condition to apply to the request. An object for tracking the current operation. A web request for performing the operation. Constructs a web request to set user-defined metadata for the blob. The absolute URI to the blob. The server timeout interval. The access condition to apply to the request. An object for tracking the current operation. A web request for performing the operation. Adds user-defined metadata to the request as one or more name-value pairs. The web request. The user-defined metadata. Adds user-defined metadata to the request as a single name-value pair. The web request. The metadata name. The metadata value. Constructs a web request to delete a blob. The absolute URI to the blob. The server timeout interval. The snapshot timestamp, if the blob is a snapshot. A set of options indicating whether to delete only blobs, only snapshots, or both. The access condition to apply to the request. An object for tracking the current operation. A web request to use to perform the operation. Constructs a web request to create a snapshot of a blob. The absolute URI to the blob. The server timeout interval. The access condition to apply to the request. An object for tracking the current operation. A web request to use to perform the operation. Generates a web request to use to acquire, renew, change, release or break the lease for the blob. The absolute URI to the blob. The server timeout interval, in seconds. The lease action to perform. A lease ID to propose for the result of an acquire or change operation, or null if no ID is proposed for an acquire operation. This should be null for renew, release, and break operations. The lease duration, in seconds, for acquire operations. If this is -1 then an infinite duration is specified. This should be null for renew, change, release, and break operations. The amount of time to wait, in seconds, after a break operation before the lease is broken. If this is null then the default time is used. This should be null for acquire, renew, change, and release operations. The access condition to apply to the request. An object for tracking the current operation. A web request to use to perform the operation. Adds a proposed lease id to a request. The request. The proposed lease id. Adds a lease duration to a request. The request. The lease duration. Adds a lease break period to a request. The request. The lease break period. Adds a lease action to a request. The request. The lease action. Constructs a web request to write a block to a block blob. The absolute URI to the blob. The server timeout interval. The block ID for this block. The access condition to apply to the request. An object for tracking the current operation. A web request to use to perform the operation. Constructs a web request to create or update a blob by committing a block list. The absolute URI to the blob. The server timeout interval. The properties to set for the blob. The access condition to apply to the request. An object for tracking the current operation. A web request for performing the operation. Constructs a web request to return the list of blocks for a block blob. The absolute URI to the blob. The server timeout interval. The snapshot timestamp, if the blob is a snapshot. The types of blocks to include in the list: committed, uncommitted, or both. The access condition to apply to the request. An object for tracking the current operation. A web request to use to perform the operation. Constructs a web request to write or clear a range of pages in a page blob. The absolute URI to the blob. The server timeout interval. The page range, defined by an object of type . A value of type , indicating the operation to perform on the page blob. The to apply to the request. An object for tracking the current operation. A web request to use to perform the operation. Generates a web request to copy a blob. The absolute URI to the destination blob. The server timeout interval. The absolute URI to the source blob, including any necessary authentication parameters. The access condition to apply to the source blob. The access condition to apply to the destination blob. An object for tracking the current operation. A web request to use to perform the operation. Generates a web request to abort a copy operation. The absolute URI to the blob. The server timeout interval. The ID string of the copy operation to be aborted. The access condition to apply to the request. Only lease conditions are supported for this operation. An object for tracking the current operation. A web request for performing the operation. Constructs a web request to get the blob's content, properties, and metadata. The absolute URI to the blob. The server timeout interval. The snapshot version, if the blob is a snapshot. The access condition to apply to the request. An object for tracking the current operation. A web request for performing the operation. Constructs a web request to return a specified range of the blob's content, together with its properties and metadata. The absolute URI to the blob. The server timeout interval, in seconds. The snapshot version, if the blob is a snapshot. The byte offset at which to begin returning content. The number of bytes to return, or null to return all bytes through the end of the blob. If set to true, request an MD5 header for the specified range. The access condition to apply to the request. An object for tracking the current operation. A web request to use to perform the operation. Provides a set of methods for parsing container responses from the Blob service. Gets the request ID from the response. The web response. A unique value associated with the request. Gets the container's properties from the response. The web response. The container's attributes. Gets the user-defined metadata. The response from server. A of the metadata. Gets the ACL for the container from the response. The web response. A value indicating the public access level for the container. Reads the share access policies from a stream in XML. The stream of XML policies. The permissions object to which the policies are to be written. Converts the ACL string to a object. The string to convert. The resulting object. A factory class for constructing a web request to manage containers in the Blob service. Constructs a web request to create a new container. The absolute URI to the container. The server timeout interval. An object for tracking the current operation. A web request to use to perform the operation. Constructs a web request to create a new container. The absolute URI to the container. The server timeout interval. An object for tracking the current operation. An object that specifies whether data in the container may be accessed publicly and the level of access. A web request to use to perform the operation. Constructs a web request to delete the container and all of the blobs within it. The absolute URI to the container. The server timeout interval. The access condition to apply to the request. An object for tracking the current operation. A web request to use to perform the operation. Generates a web request to return the user-defined metadata for this container. The absolute URI to the container. The server timeout interval. The access condition to apply to the request. An object for tracking the current operation. A web request to use to perform the operation. Generates a web request to return the properties and user-defined metadata for this container. The absolute URI to the container. The server timeout interval. The access condition to apply to the request. An object for tracking the current operation. A web request to use to perform the operation. Generates a web request to set user-defined metadata for the container. The absolute URI to the container. The server timeout interval. The access condition to apply to the request. An object for tracking the current operation. A web request to use to perform the operation. Generates a web request to use to acquire, renew, change, release or break the lease for the container. The absolute URI to the container. The server timeout interval, in seconds. The lease action to perform. A lease ID to propose for the result of an acquire or change operation, or null if no ID is proposed for an acquire operation. This should be null for renew, release, and break operations. The lease duration, in seconds, for acquire operations. If this is -1 then an infinite duration is specified. This should be null for renew, change, release, and break operations. The amount of time to wait, in seconds, after a break operation before the lease is broken. If this is null then the default time is used. This should be null for acquire, renew, change, and release operations. The access condition to apply to the request. An object for tracking the current operation. A web request to use to perform the operation. Adds user-defined metadata to the request as one or more name-value pairs. The web request. The user-defined metadata. Adds user-defined metadata to the request as a single name-value pair. The web request. The metadata name. The metadata value. Constructs a web request to return a listing of all containers in this storage account. The absolute URI for the account. The server timeout interval. A set of parameters for the listing operation. Additional details to return with the listing. An object for tracking the current operation. A web request for the specified operation. Constructs a web request to return the ACL for a container. The absolute URI to the container. The server timeout interval. The access condition to apply to the request. An object for tracking the current operation. A web request to use to perform the operation. Constructs a web request to set the ACL for a container. The absolute URI to the container. The server timeout interval. The type of public access to allow for the container. The access condition to apply to the request. An object for tracking the current operation. A web request to use to perform the operation. Generates a web request to return a listing of all blobs in the container. The absolute URI to the container. The server timeout interval. A set of parameters for the listing operation. An object for tracking the current operation. A web request to use to perform the operation. Gets the container Uri query builder. A for the container. This class represents a queue in the Windows Azure Queue service. This class represents a queue in the Windows Azure Queue service. Creates the queue. A object that specifies additional options for the request. An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. Begins an asynchronous operation to create a queue. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to create a queue. A object that specifies additional options for the request. An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to create a queue. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to create a queue. A object that represents the current operation. Returns a task that performs an asynchronous operation to create a queue. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to create a queue. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to create a queue. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Creates the queue if it does not already exist. A object that specifies additional options for the request. An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. true if the queue did not already exist and was created; otherwise false. Begins an asynchronous request to create the queue if it does not already exist. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to create the queue if it does not already exist. A object that specifies additional options for the request. An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Returns the result of an asynchronous request to create the queue if it does not already exist. An that references the pending asynchronous operation. true if the queue did not already exist and was created; otherwise, false. Returns a task that performs an asynchronous request to create the queue if it does not already exist. A object that represents the current operation. Returns a task that performs an asynchronous request to create the queue if it does not already exist. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous request to create the queue if it does not already exist. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous request to create the queue if it does not already exist. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Deletes the queue if it already exists. A object that specifies additional options for the request. An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. true if the queue did not already exist and was created; otherwise false. Begins an asynchronous request to delete the queue if it already exists. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to delete the queue if it already exists. A object that specifies additional options for the request. An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Returns the result of an asynchronous request to delete the queue if it already exists. An that references the pending asynchronous operation. true if the queue did not already exist and was created; otherwise, false. Returns a task that performs an asynchronous request to delete the queue if it already exists. A object that represents the current operation. Returns a task that performs an asynchronous request to delete the queue if it already exists. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous request to delete the queue if it already exists. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous request to delete the queue if it already exists. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Deletes the queue. A object that specifies additional options for the request. An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. Begins an asynchronous operation to delete a queue. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to delete a queue. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to delete a queue. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to delete a queue. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete a queue. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete a queue. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete a queue. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Sets permissions for the queue. The permissions to apply to the queue. A object that specifies additional options for the request. An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. Begins an asynchronous request to set permissions for the queue. The permissions to apply to the queue. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to set permissions for the queue. The permissions to apply to the queue. A object that specifies additional options for the request. An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Returns the result of an asynchronous request to set permissions for the queue. An that references the pending asynchronous operation. Returns a task that performs an asynchronous request to set permissions for the queue. The permissions to apply to the queue. A object that represents the current operation. Returns a task that performs an asynchronous request to set permissions for the queue. The permissions to apply to the queue. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous request to set permissions for the queue. The permissions to apply to the queue. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous request to set permissions for the queue. The permissions to apply to the queue. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Gets the permissions settings for the queue. A object that specifies additional options for the request. An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. The queue's permissions. Begins an asynchronous request to get the permissions settings for the queue. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to get the permissions settings for the queue. A object that specifies additional options for the request. An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Returns the asynchronous result of the request to get the permissions settings for the queue. An that references the pending asynchronous operation. The queue's permissions. Returns a task that performs an asynchronous request to get the permissions settings for the queue. A object that represents the current operation. Returns a task that performs an asynchronous request to get the permissions settings for the queue. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous request to get the permissions settings for the queue. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous request to get the permissions settings for the queue. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Checks existence of the queue. A object that specifies additional options for the request. An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. true if the queue exists. Checks existence of the queue. If true, the command will be executed against the primary location. A object that specifies additional options for the request. An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. true if the queue exists. Begins an asynchronous request to check existence of the queue. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to check existence of the queue. A object that specifies additional options for the request. An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to check existence of the queue. If true, the command will be executed against the primary location. A object that specifies additional options for the request. An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Returns the asynchronous result of the request to check existence of the queue. An that references the pending asynchronous operation. true if the queue exists. Returns a task that performs an asynchronous request to check existence of the queue. A object that represents the current operation. Returns a task that performs an asynchronous request to check existence of the queue. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous request to check existence of the queue. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous request to check existence of the queue. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Sets the queue's user-defined metadata. A object that specifies additional options for the request. Specifying null will use the default request options from the associated service client (). An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. Begins an asynchronous operation to set user-defined metadata on the queue. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to set user-defined metadata on the queue. A object that specifies additional options for the request. Specifying null will use the default request options from the associated service client (). An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous request operation to set user-defined metadata on the queue. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to set user-defined metadata on the queue. A object that represents the current operation. Returns a task that performs an asynchronous operation to set user-defined metadata on the queue. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to set user-defined metadata on the queue. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to set user-defined metadata on the queue. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Fetches the queue's attributes. A object that specifies additional options for the request. Specifying null will use the default request options from the associated service client (). An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. Begins an asynchronous operation to fetch the queue's attributes. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to fetch the queue's attributes. A object that specifies additional options for the request. An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to fetch a queue's attributes. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to fetch the queue's attributes. A object that represents the current operation. Returns a task that performs an asynchronous operation to fetch the queue's attributes. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to fetch the queue's attributes. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to fetch the queue's attributes. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Adds a message to the queue. The message to add. The maximum time to allow the message to be in the queue, or null. The length of time from now during which the message will be invisible. If null then the message will be visible immediately. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to add a message to the queue. The message to add. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to add a message to the queue. The message to add. The maximum time to allow the message to be in the queue, or null. The length of time from now during which the message will be invisible. If null then the message will be visible immediately. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to add a message to the queue. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to add a message to the queue. The message to add. A object that represents the current operation. Returns a task that performs an asynchronous operation to add a message to the queue. The message to add. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to add a message to the queue. The message to add. The maximum time to allow the message to be in the queue, or null. The length of time from now during which the message will be invisible. If null then the message will be visible immediately. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to add a message to the queue. The message to add. The maximum time to allow the message to be in the queue, or null. The length of time from now during which the message will be invisible. If null then the message will be visible immediately. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Updates the visibility timeout and optionally the content of a message. The message to update. The visibility timeout interval. Flags of values that specifies which parts of the message are to be updated. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to update the visibility timeout and optionally the content of a message. The message to update. The visibility timeout interval. An EnumSet of values that specifies which parts of the message are to be updated. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to update the visibility timeout and optionally the content of a message. The message to update. The visibility timeout interval. An EnumSet of values that specifies which parts of the message are to be updated. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to add a message to the queue. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to update the visibility timeout and optionally the content of a message. The message to update. The visibility timeout interval. An EnumSet of values that specifies which parts of the message are to be updated. A object that represents the current operation. Returns a task that performs an asynchronous operation to update the visibility timeout and optionally the content of a message. The message to update. The visibility timeout interval. An EnumSet of values that specifies which parts of the message are to be updated. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to update the visibility timeout and optionally the content of a message. The message to update. The visibility timeout interval. An EnumSet of values that specifies which parts of the message are to be updated. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to update the visibility timeout and optionally the content of a message. The message to update. The visibility timeout interval. An EnumSet of values that specifies which parts of the message are to be updated. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Deletes a message. A message. A object that specifies additional options for the request. Specifying null will use the default request options from the associated service client (). An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. Deletes the specified message from the queue. The message ID. The pop receipt value. A object that specifies additional options for the request. Specifying null will use the default request options from the associated service client (). An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. Begins an asynchronous operation to delete a message. A message. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to delete a message. A message. A object that specifies additional options for the request. Specifying null will use the default request options from the associated service client (). An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to delete a message. The message ID. The pop receipt value. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to delete a message. The message ID. The pop receipt value. A object that specifies additional options for the request. Specifying null will use the default request options from the associated service client (). An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to delete a message. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to delete a message. A message. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete a message. A message. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete a message. A message. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete a message. A message. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete a message. The message ID. The pop receipt value. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete a message. The message ID. The pop receipt value. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete a message. The message ID. The pop receipt value. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete a message. The message ID. The pop receipt value. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Gets the specified number of messages from the queue using the specified request options and operation context. This operation marks the retrieved messages as invisible in the queue for the default visibility timeout period. The number of messages to retrieve. The visibility timeout interval. A object that specifies additional options for the request. Specifying null will use the default request options from the associated service client (). An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. An enumerable collection of messages. Begins an asynchronous operation to get messages from the queue. The number of messages to retrieve. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to get the specified number of messages from the queue using the specified request options and operation context. This operation marks the retrieved messages as invisible in the queue for the default visibility timeout period. The number of messages to retrieve. The visibility timeout interval. A object that specifies additional options for the request. Specifying null will use the default request options from the associated service client (). An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to get messages from the queue. An that references the pending asynchronous operation. An enumerable collection of messages. Returns a task that performs an asynchronous operation to get messages from the queue. The number of messages to retrieve. A object that represents the current operation. Returns a task that performs an asynchronous operation to get messages from the queue. The number of messages to retrieve. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to get the specified number of messages from the queue using the specified request options and operation context. This operation marks the retrieved messages as invisible in the queue for the default visibility timeout period. The number of messages to retrieve. The visibility timeout interval. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to get the specified number of messages from the queue using the specified request options and operation context. This operation marks the retrieved messages as invisible in the queue for the default visibility timeout period. The number of messages to retrieve. The visibility timeout interval. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Gets a message from the queue using the default request options. This operation marks the retrieved message as invisible in the queue for the default visibility timeout period. The visibility timeout interval. A object that specifies additional options for the request. Specifying null will use the default request options from the associated service client (). An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. A message. Begins an asynchronous operation to get a single message from the queue. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to get a single message from the queue, and specifies how long the message should be reserved before it becomes visible, and therefore available for deletion. The visibility timeout interval. A object that specifies additional options for the request. Specifying null will use the default request options from the associated service client (). An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to get a single message from the queue. An that references the pending asynchronous operation. A message. Returns a task that performs an asynchronous operation to get a single message from the queue. A object that represents the current operation. Returns a task that performs an asynchronous operation to get a single message from the queue. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to get a single message from the queue, and specifies how long the message should be reserved before it becomes visible, and therefore available for deletion. The visibility timeout interval. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to get a single message from the queue, and specifies how long the message should be reserved before it becomes visible, and therefore available for deletion. The visibility timeout interval. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Peeks a message from the queue, using the specified request options and operation context. A peek request retrieves a message from the queue without changing its visibility. The number of messages to peek. A object that specifies additional options for the request. Specifying null will use the default request options from the associated service client (). An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. An enumerable collection of messages. Begins an asynchronous operation to peek messages from the queue. The number of messages to peek. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to peek messages from the queue. The number of messages to peek. A object that specifies additional options for the request. Specifying null will use the default request options from the associated service client (). An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to peek messages from the queue. An that references the pending asynchronous operation. An enumerable collection of messages. Returns a task that performs an asynchronous operation to peek messages from the queue. The number of messages to peek. A object that represents the current operation. Returns a task that performs an asynchronous operation to peek messages from the queue. The number of messages to peek. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to peek messages from the queue. The number of messages to peek. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to peek messages from the queue. The number of messages to peek. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Peeks a single message from the queue. A peek request retrieves a message from the queue without changing its visibility. A object that specifies additional options for the request. Specifying null will use the default request options from the associated service client (). An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. A message. Begins an asynchronous operation to get a single message from the queue. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to peek a single message from the queue. A object that specifies additional options for the request. Specifying null will use the default request options from the associated service client (). An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to peek a single message from the queue. An that references the pending asynchronous operation. A message. Returns a task that performs an asynchronous operation to get a single message from the queue. A object that represents the current operation. Returns a task that performs an asynchronous operation to get a single message from the queue. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to get a single message from the queue. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to get a single message from the queue. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Clears all messages from the queue. A object that specifies additional options for the request. Specifying null will use the default request options from the associated service client (). An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. Begins an asynchronous operation to clear all messages from the queue. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to clear all messages from the queue. A object that specifies additional options for the request. Specifying null will use the default request options from the associated service client (). An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to clear all messages from the queue. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to clear all messages from the queue. A object that represents the current operation. Returns a task that performs an asynchronous operation to clear all messages from the queue. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to clear all messages from the queue. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to clear all messages from the queue. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Ends an asynchronous operation to clear all messages from the queue. An that references the pending asynchronous operation. Implementation for the ClearMessages method. A object that specifies additional options for the request. A that gets the permissions. Implementation for the Create method. A object that specifies additional options for the request. A that creates the queue. Implementation for the Delete method. A object that specifies additional options for the request. A that deletes the queue. Implementation for the FetchAttributes method. A object that specifies additional options for the request. A that fetches the attributes. Implementation for the Exists method. A object that specifies additional options for the request. If true, the command will be executed against the primary location. A that checks existence. Implementation for the SetMetadata method. A object that specifies additional options for the request. A that sets the metadata. Implementation for the SetPermissions method. The permissions to set. A object that specifies additional options for the request. A that sets the permissions. Implementation for the GetPermissions method. A object that specifies additional options for the request. A that gets the permissions. Implementation for the AddMessageImpl method. A queue message. A value indicating the message time-to-live. The visibility delay for the message. A object that specifies additional options for the request. A that sets the permissions. Implementation for the UpdateMessage method. A queue message. The visibility timeout for the message. Indicates whether to update the visibility delay, message contents, or both. A object that specifies additional options for the request. A that sets the permissions. Implementation for the DeleteMessage method. The message ID. The pop receipt value. A object that specifies additional options for the request. A that deletes the queue. Implementation for the GetPermissions method. The number of messages to retrieve. The visibility timeout interval. A object that specifies additional options for the request. A that gets the permissions. Implementation for the PeekMessages method. The number of messages to retrieve. A object that specifies additional options for the request. A that gets the permissions. Gets the ApproximateMessageCount and metadata from response. The web response. Update the message pop receipt and next visible time. The Cloud Queue Message. The web response. Initializes a new instance of the class. The absolute URI to the queue. Initializes a new instance of the class. The absolute URI to the queue. The account credentials. Initializes a new instance of the class. The absolute URI to the queue. The account credentials. Initializes a new instance of the class. The queue name. A client object that specifies the endpoint for the queue service. Uri for the messages. Gets the Uri for general message operations. Gets the individual message address. The message id. The URI of the message. Parse URI for SAS (Shared Access Signature) information. The complete Uri. The credentials to use. Returns the canonical name for shared access. The canonical name. Selects the get message response. The protocol message. The parsed message. Selects the peek message response. The protocol message. The parsed message. Returns a shared access signature for the queue. The access policy for the shared access signature. A queue-level access policy. A shared access signature, as a URI query string. The query string returned includes the leading question mark. Gets the service client for the queue. A client object that specifies the endpoint for the queue service. Gets the queue's URI for the primary location. The absolute URI to the queue, at the primary location. Gets the queue's URIs for all locations. An object of type containing the queue's URIs for all locations. Gets the name of the queue. The queue's name. Gets the approximate message count for the queue. The approximate message count. Gets or sets a value indicating whether to apply base64 encoding when adding or retrieving messages. True to encode messages; otherwise, false. The default value is true. Gets the queue's metadata. The queue's metadata. Provides a client-side logical representation of the Windows Azure Queue service. This client is used to configure and execute requests against the Queue service. The service client encapsulates the base URI for the Queue service. If the service client will be used for authenticated access, it also encapsulates the credentials for accessing the storage account. Provides a client-side logical representation of the Windows Azure Queue service. This client is used to configure and execute requests against the Queue service. The service client encapsulates the base URI for the Queue service. If the service client will be used for authenticated access, it also encapsulates the credentials for accessing the storage account. Returns an enumerable collection of the queues in the storage account whose names begin with the specified prefix and that are retrieved lazily. The queue name prefix. An enumeration value that indicates which details to include in the listing. An object that specifies additional options for the request. An object that represents the context for the current operation. This object is used to track requests, and to provide additional runtime information about the operation. An enumerable collection of objects that implement and are retrieved lazily. Returns a result segment containing a collection of queues in the storage account. A continuation token returned by a previous listing operation. A result segment containing objects that implement . Returns a result segment containing a collection of queues in the storage account. The queue name prefix. A continuation token returned by a previous listing operation. A result segment containing objects that implement . Returns a result segment containing a collection of queues in the storage account. The queue name prefix. A enumeration describing which items to include in the listing. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A returned by a previous listing operation. An object that specifies additional options for the request. An object that represents the context for the current operation. This object is used to track requests, and to provide additional runtime information about the operation. A result segment containing objects that implement . Returns a result segment containing a collection of queues in the storage account. The queue name prefix. A enumeration describing which items to include in the listing. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A returned by a previous listing operation. An object that specifies additional options for the request. An object that represents the context for the current operation. This object is used to track requests, and to provide additional runtime information about the operation. A result segment. Begins an asynchronous operation to return a result segment containing a collection of queue items. A returned by a previous listing operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to return a result segment containing a collection of queue items. The queue name prefix. A returned by a previous listing operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to return a result segment containing a collection of queue items. The queue name prefix. A enumeration describing which items to include in the listing. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A returned by a previous listing operation. An object that specifies additional options for the request. An object that represents the context for the current operation. This object is used to track requests, and to provide additional runtime information about the operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to return a result segment containing a collection of queue items. An that references the pending asynchronous operation. A queue result segment. Returns a task that performs an asynchronous operation to return a result segment containing a collection of queue items. A returned by a previous listing operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to return a result segment containing a collection of queue items. A returned by a previous listing operation. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to return a result segment containing a collection of queue items. The queue name prefix. A returned by a previous listing operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to return a result segment containing a collection of queue items. The queue name prefix. A returned by a previous listing operation. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to return a result segment containing a collection of queue items. The queue name prefix. A enumeration describing which items to include in the listing. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A returned by a previous listing operation. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to return a result segment containing a collection of queue items. The queue name prefix. A enumeration describing which items to include in the listing. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A returned by a previous listing operation. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Core implementation of the ListQueues method. The queue name prefix. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A enumeration describing which items to include in the listing. An object that specifies additional options for the request. The continuation token. A that lists the queues. Begins an asynchronous operation to get the properties of the queue service. The callback delegate that will receive notification when the asynchronous operation completes. A user defined object to be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to get the properties of the queue service. A object that specifies additional options for the request. Specifying null will use the default request options from the associated service client (). An object that represents the context for the current operation. This object is used to track requests, and to provide additional runtime information about the operation. The callback delegate that will receive notification when the asynchronous operation completes. A user defined object to be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to get the properties of the queue service. The result returned from a prior call to . A object containing the queue service properties. Returns a task that performs an asynchronous operation to get the properties of the queue service. A object that represents the current operation. Returns a task that performs an asynchronous operation to get the properties of the queue service. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to get the properties of the queue service. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to get the properties of the queue service. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Gets the properties of the queue service. A object that specifies additional options for the request. Specifying null will use the default request options from the associated service client (). An object that represents the context for the current operation. This object is used to track requests, and to provide additional runtime information about the operation. The queue service properties. Begins an asynchronous operation to set the properties of the queue service. The queue service properties. The callback delegate that will receive notification when the asynchronous operation completes. A user defined object to be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to set the properties of the queue service. The queue service properties. A object that specifies additional options for the request. Specifying null will use the default request options from the associated service client (). An object that represents the context for the current operation. This object is used to track requests, and to provide additional runtime information about the operation. The callback delegate that will receive notification when the asynchronous operation completes. A user defined object to be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to set the properties of the queue service. The result returned from a prior call to . Returns a task that performs an asynchronous operation to set the properties of the queue service. The queue service properties. A object that represents the current operation. Returns a task that performs an asynchronous operation to set the properties of the queue service. The queue service properties. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to set the properties of the queue service. The queue service properties. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to set the properties of the queue service. The queue service properties. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Sets the properties of the queue service. The queue service properties. A object that specifies additional options for the request. Specifying null will use the default request options from the associated service client (). An object that represents the context for the current operation. This object is used to track requests, and to provide additional runtime information about the operation. Begins an asynchronous operation to get the stats of the queue service. The callback delegate that will receive notification when the asynchronous operation completes. A user defined object to be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to get the stats of the queue service. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user defined object to be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to get the stats of the queue service. An that references the pending asynchronous operation. The queue service stats. Returns a task that performs an asynchronous operation to get the stats of the queue service. A object that represents the current operation. Returns a task that performs an asynchronous operation to get the stats of the queue service. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to get the stats of the queue service. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to get the stats of the queue service. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Gets the stats of the queue service. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. The queue service stats. The default server and client timeout interval. Max execution time across all potential retries. Initializes a new instance of the class using the specified queue service endpoint and anonymous credentials. The queue service endpoint to use to create the client. Initializes a new instance of the class using the specified queue service endpoint and account credentials. The queue service endpoint to use to create the client. The account credentials. Initializes a new instance of the class using the specified Queue service endpoint and account credentials. The Queue service endpoint to use to create the client. The account credentials. Returns a reference to a object with the specified name. The name of the queue, or an absolute URI to the queue. A reference to a queue. Gets or sets the authentication scheme to use to sign HTTP requests. Gets the authentication handler used to sign HTTP requests. The authentication handler. Gets or sets a buffer manager that implements the interface, specifying a buffer pool for use with operations against the Queue service client. Gets the account credentials used to create the queue service client. The account credentials. Gets the base URI for the Queue service client, at the primary location. The base URI used to construct the Queue service client, at the primary location. Gets the Queue service endpoints for all locations. An object of type containing Queue service URIs for all locations. Gets or sets the default retry policy for requests made via the Queue service client. The retry policy. Gets or sets the default location mode for requests made via the Queue service client. The location mode. Gets or sets the default server and client timeout for requests made via the Queue service client. The server and client timeout interval. Gets or sets the maximum execution time across all potential retries. The maximum execution time across all potential retries. Gets a value indicating whether the service client is used with Path style or Host style. Is true if use path style URIs; otherwise, false. Represents a message in the Windows Azure Queue service. Represents a message in the Windows Azure Queue service. The maximum message size in bytes. The maximum number of messages that can be peeked at a time. Initializes a new instance of the class with the given byte array. The content of the message as a byte array. Sets the content of this message. The new message content. The maximum amount of time a message is kept in the queue. Custom UTF8Encoder to throw exception in case of invalid bytes. Initializes a new instance of the class with the given byte array. Initializes a new instance of the class with the given string. The content of the message as a string of text. Initializes a new instance of the class with the given message ID and pop receipt. The message ID. The pop receipt token. Initializes a new instance of the class with the given Base64 encoded string. This method is only used internally. The text string. Whether the string is Base64 encoded. Gets the content of the message for transfer (internal use only). Indicates if the message should be encoded. The message content as a string. Sets the content of this message. The new message content. Gets the maximum message size in bytes. The maximum message size in bytes. Gets the maximum amount of time a message is kept in the queue. The maximum amount of time a message is kept in the queue. Gets the maximum number of messages that can be peeked at a time. The maximum number of messages that can be peeked at a time. Gets the content of the message as a byte array. The content of the message as a byte array. Gets the message ID. The message ID. Gets the message's pop receipt. The pop receipt value. Gets the time that the message was added to the queue. The time that the message was added to the queue. Gets the time that the message expires. The time that the message expires. Gets the time that the message will next be visible. The time that the message will next be visible. Gets the content of the message, as a string. The message content. Gets the number of times this message has been dequeued. The number of times this message has been dequeued. Gets message type that indicates if the RawString is the original message string or Base64 encoding of the original binary data. Gets or sets the original message string or Base64 encoding of the original binary data. The original message string. Provides a set of methods for parsing a response containing queue data from the Queue service. Gets the request ID from the response. The web response. A unique value associated with the request. Gets the approximate message count for the queue. The web response. The approximate count for the queue. Gets the user-defined metadata. The response from server. An object of type containing the metadata. Extracts the pop receipt from a web response header. The web response. The pop receipt stored in the header of the response. Extracts the next visibility time from a web response header. The web response. The time of next visibility stored in the header of the response. Reads service properties from a stream. The stream from which to read the service properties. The service properties stored in the stream. Reads service stats from a stream. The stream from which to read the service stats. The service stats stored in the stream. Reads the share access policies from a stream in XML. The stream of XML policies. The permissions object to which the policies are to be written. A factory class for constructing a web request to manage queues in the Queue service. Creates a web request to get the properties of the Queue service. The absolute URI to the Queue service. An object of type , containing additional parameters to add to the URI query string. The server timeout interval, in seconds. An object for tracking the current operation. A web request to get the Queue service properties. Creates a web request to set the properties of the Queue service. The absolute URI to the Queue service. An object of type , containing additional parameters to add to the URI query string. The server timeout interval, in seconds. An object for tracking the current operation. A web request to set the Queue service properties. Creates a web request to get the stats of the Queue service. The absolute URI to the Queue service. An object of type , containing additional parameters to add to the URI query string. The server timeout interval, in seconds. An object for tracking the current operation. A web request to get the Queue service stats. Writes Queue service properties to a stream, formatted in XML. The service properties to format and write to the stream. The stream to which the formatted properties are to be written. Constructs a web request to create a new queue. The absolute URI to the queue. The server timeout interval. An object for tracking the current operation. A web request to use to perform the operation. Constructs a web request to delete the queue and all of the messages within it. The absolute URI to the queue. The server timeout interval. An object for tracking the current operation. A web request to use to perform the operation. Constructs a web request to clear all messages in the queue. The absolute URI to the queue. The server timeout interval. An object for tracking the current operation. A web request to use to perform the operation. Generates a web request to return the user-defined metadata for this queue. The absolute URI to the queue. The server timeout interval. An object for tracking the current operation. A web request to use to perform the operation. Generates a web request to set user-defined metadata for the queue. The absolute URI to the queue. The server timeout interval. An object for tracking the current operation. A web request to use to perform the operation. Adds user-defined metadata to the request as one or more name-value pairs. The web request. The user-defined metadata. Adds user-defined metadata to the request as a single name-value pair. The web request. The metadata name. The metadata value. Constructs a web request to return a listing of all queues in this storage account. The absolute URI for the account. The server timeout interval. A set of parameters for the listing operation. Additional details to return with the listing. An object for tracking the current operation. A web request for the specified operation. Constructs a web request to return the ACL for a queue. The absolute URI to the queue. The server timeout interval. An object for tracking the current operation. A web request to use to perform the operation. Constructs a web request to set the ACL for a queue. The absolute URI to the queue. The server timeout interval. An object for tracking the current operation. A web request to use to perform the operation. Constructs a web request to add a message for a queue. The absolute URI to the queue. The server timeout interval. The message time-to-live, in seconds. The visibility timeout, in seconds. An object for tracking the current operation. A web request to use to perform the operation. Constructs a web request to update a message. The absolute URI to the message to update. The server timeout interval, in seconds. The pop receipt of the message. The length of time from now during which the message will be invisible, in seconds. An object for tracking the current operation. A web request for the update operation. Constructs a web request to update a message. The absolute URI to the message to update. The server timeout interval, in seconds. The pop receipt of the message. An object for tracking the current operation. A web request for the update operation. Constructs a web request to get messages for a queue. The absolute URI to the queue. The server timeout interval. The number of messages. The visibility timeout. An object for tracking the current operation. A web request to use to perform the operation. Constructs a web request to peeks messages for a queue. The absolute URI to the queue. The server timeout interval. The number of messages. An object for tracking the current operation. A web request to use to perform the operation. Represents a Windows Azure table. Represents a Windows Azure table. Executes the operation on a table, using the specified and . A object that represents the operation to perform. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. A containing the result of executing the operation on the table. Begins an asynchronous table operation. A object that represents the operation to perform. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous table operation using the specified and . A object that represents the operation to perform. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous table operation. An that references the pending asynchronous operation. A containing the result executing the operation on the table. Returns a task that performs an asynchronous table operation using the specified and . A object that represents the operation to perform. A object that represents the current operation. Returns a task that performs an asynchronous table operation using the specified and . A object that represents the operation to perform. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous table operation using the specified and . A object that represents the operation to perform. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. A object that represents the current operation. Returns a task that performs an asynchronous table operation using the specified and . A object that represents the operation to perform. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Executes a batch operation on a table as an atomic operation, using the specified and . The object representing the operations to execute on the table. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. An enumerable collection of objects that contains the results, in order, of each operation in the on the table. Begins an asynchronous operation to execute a batch of operations on a table. The object representing the operations to execute on the table. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to execute a batch of operations on a table, using the specified and . The object representing the operations to execute on the table. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous batch of operations on a table. An that references the pending asynchronous operation. A enumerable collection of type that contains the results, in order, of each operation in the on the table. Returns a task that performs an asynchronous operation to execute a batch of operations on a table, using the specified and . The object representing the operations to execute on the table. A object that represents the current operation. Returns a task that performs an asynchronous operation to execute a batch of operations on a table, using the specified and . The object representing the operations to execute on the table. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to execute a batch of operations on a table, using the specified and . The object representing the operations to execute on the table. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to execute a batch of operations on a table, using the specified and . The object representing the operations to execute on the table. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Executes a query on a table, using the specified and . A representing the query to execute. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. An enumerable collection of objects, representing table entities returned by the query. Executes a query in segmented mode with the specified continuation token, , and . A representing the query to execute. A object representing a continuation token from the server when the operation returns a partial result. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. A object containing the results of executing the query. Begins an asynchronous segmented query operation using the specified continuation token. A representing the query to execute. A object representing a continuation token from the server when the operation returns a partial result. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to query a table in segmented mode using the specified continuation token, , and . A representing the query to execute. A object representing a continuation token from the server when the operation returns a partial result. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous segmented query operation. An that references the pending asynchronous operation. A object containing the results of executing the query. Returns a task that performs an asynchronous operation to query a table in segmented mode using the specified continuation token, , and . A representing the query to execute. A object representing a continuation token from the server when the operation returns a partial result. A object that represents the current operation. Returns a task that performs an asynchronous operation to query a table in segmented mode using the specified continuation token, , and . A representing the query to execute. A object representing a continuation token from the server when the operation returns a partial result. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to query a table in segmented mode using the specified continuation token, , and . A representing the query to execute. A object representing a continuation token from the server when the operation returns a partial result. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to query a table in segmented mode using the specified continuation token, , and . A representing the query to execute. A object representing a continuation token from the server when the operation returns a partial result. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Executes a query on a table, using the specified and , applying the to the result. A representing the query to execute. An instance which creates a projection of the table query result entities into the specified type TResult. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. An enumerable collection, containing the projection into type TResult, of the results of executing the query. Executes a query in segmented mode with the specified continuation token, , and . A representing the query to execute. An instance which creates a projection of the table query result entities into the specified type TResult. A object representing a continuation token from the server when the operation returns a partial result. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. A object containing the results of executing the query. Begins an asynchronous segmented query operation using the specified continuation token. A representing the query to execute. An instance which creates a projection of the table query result entities into the specified type TResult. A object representing a continuation token from the server when the operation returns a partial result. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to execute a query in segmented mode with the specified continuation token, , and , applies the to the results. The type into which the will project the query results. A instance specifying the table to query and the query parameters to use, specialized for a type TElement. An instance which creates a projection of the table query result entities into the specified type TResult. A object representing a continuation token from the server when the operation returns a partial result. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Returns a task that performs an asynchronous operation to execute a query in segmented mode with the specified continuation token, , and , applies the to the results. The type into which the will project the query results. A instance specifying the table to query and the query parameters to use, specialized for a type TElement. An instance which creates a projection of the table query result entities into the specified type TResult. A object representing a continuation token from the server when the operation returns a partial result. A object that represents the current operation. Returns a task that performs an asynchronous operation to execute a query in segmented mode with the specified continuation token, , and , applies the to the results. The type into which the will project the query results. A instance specifying the table to query and the query parameters to use, specialized for a type TElement. An instance which creates a projection of the table query result entities into the specified type TResult. A object representing a continuation token from the server when the operation returns a partial result. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to execute a query in segmented mode with the specified continuation token, , and , applies the to the results. The type into which the will project the query results. A instance specifying the table to query and the query parameters to use, specialized for a type TElement. An instance which creates a projection of the table query result entities into the specified type TResult. A object representing a continuation token from the server when the operation returns a partial result. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to execute a query in segmented mode with the specified continuation token, , and , applies the to the results. The type into which the will project the query results. A instance specifying the table to query and the query parameters to use, specialized for a type TElement. An instance which creates a projection of the table query result entities into the specified type TResult. A object representing a continuation token from the server when the operation returns a partial result. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. A factory method that creates a query that can be modified using LINQ. The query may be subsequently executed using one of the execution methods available for , such as , , or . The entity type of the query. A object, specialized for type TElement, that may subsequently be executed. The namespace includes extension methods for the object, including , , and . To use these methods, include a using statement that references the namespace. Executes a query on a table, using the specified and . The entity type of the query. A TableQuery instance specifying the table to query and the query parameters to use, specialized for a type T implementing TableEntity. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. An enumerable collection, specialized for type TElement, of the results of executing the query. Queries a table in segmented mode using the specified continuation token, , and . The entity type of the query. A instance specifying the table to query and the query parameters to use, specialized for a type TElement. A object representing a continuation token from the server when the operation returns a partial result. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. A , specialized for type TElement, containing the results of executing the query. Begins an asynchronous operation to query a table in segmented mode, using the specified continuation token. The entity type of the query. A instance specifying the table to query and the query parameters to use, specialized for a type TElement. A object representing a continuation token from the server when the operation returns a partial result. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to query a table in segmented mode using the specified continuation token and . The entity type of the query. A instance specifying the table to query and the query parameters to use, specialized for a type TElement. A object representing a continuation token from the server when the operation returns a partial result. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous segmented table query operation. The type of the results to be returned. Can be the entity type specified in the Begin or the result type of the resolver An that references the pending asynchronous operation. A containing the results of executing the query. Returns a task that performs an asynchronous operation to query a table in segmented mode using the specified continuation token and . The entity type of the query. A instance specifying the table to query and the query parameters to use, specialized for a type TElement. A object representing a continuation token from the server when the operation returns a partial result. A object that represents the current operation. Returns a task that performs an asynchronous operation to query a table in segmented mode using the specified continuation token and . The entity type of the query. A instance specifying the table to query and the query parameters to use, specialized for a type TElement. A object representing a continuation token from the server when the operation returns a partial result. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to query a table in segmented mode using the specified continuation token and . The entity type of the query. A instance specifying the table to query and the query parameters to use, specialized for a type TElement. A object representing a continuation token from the server when the operation returns a partial result. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to query a table in segmented mode using the specified continuation token and . The entity type of the query. A instance specifying the table to query and the query parameters to use, specialized for a type TElement. A object representing a continuation token from the server when the operation returns a partial result. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Executes a query, using the specified and , applying the to the result. The entity type of the query. The type into which the will project the query results. A instance specifying the table to query and the query parameters to use, specialized for a type TElement. An instance which creates a projection of the table query result entities into the specified type TResult. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. An enumerable collection, containing the projection into type TResult, of the results of executing the query. Executes a query in segmented mode with the specified continuation token, using the specified and , applying the to the results. The entity type of the query. The type into which the will project the query results. A instance specifying the table to query and the query parameters to use, specialized for a type TElement. An instance which creates a projection of the table query result entities into the specified type TResult. A object representing a continuation token from the server when the operation returns a partial result. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. A containing the projection into type TResult of the results of executing the query. Begins an asynchronous operation to query a table in segmented mode, using the specified and continuation token. The entity type of the query. The type into which the will project the query results. A instance specifying the table to query and the query parameters to use, specialized for a type TElement. An instance which creates a projection of the table query result entities into the specified type TResult. A object representing a continuation token from the server when the operation returns a partial result. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to execute a query in segmented mode with the specified continuation token, , and , applies the to the results. The entity type of the query. The type into which the will project the query results. A instance specifying the table to query and the query parameters to use, specialized for a type TElement. An instance which creates a projection of the table query result entities into the specified type TResult. A object representing a continuation token from the server when the operation returns a partial result. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous segmented table query operation. The entity type of the query. The type into which the will project the query results. An that references the pending asynchronous operation. A containing the projection into type TResult of the results of executing the query. Returns a task that performs an asynchronous operation to execute a query in segmented mode with the specified continuation token, , and , applies the to the results. The entity type of the query. The type into which the will project the query results. A instance specifying the table to query and the query parameters to use, specialized for a type TElement. An instance which creates a projection of the table query result entities into the specified type TResult. A object representing a continuation token from the server when the operation returns a partial result. A object that represents the current operation. Returns a task that performs an asynchronous operation to execute a query in segmented mode with the specified continuation token, , and , applies the to the results. The entity type of the query. The type into which the will project the query results. A instance specifying the table to query and the query parameters to use, specialized for a type TElement. An instance which creates a projection of the table query result entities into the specified type TResult. A object representing a continuation token from the server when the operation returns a partial result. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to execute a query in segmented mode with the specified continuation token, , and , applies the to the results. The entity type of the query. The type into which the will project the query results. A instance specifying the table to query and the query parameters to use, specialized for a type TElement. An instance which creates a projection of the table query result entities into the specified type TResult. A object representing a continuation token from the server when the operation returns a partial result. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to execute a query in segmented mode with the specified continuation token, , and , applies the to the results. The entity type of the query. The type into which the will project the query results. A instance specifying the table to query and the query parameters to use, specialized for a type TElement. An instance which creates a projection of the table query result entities into the specified type TResult. A object representing a continuation token from the server when the operation returns a partial result. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Creates a table. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. Begins an asynchronous operation to create a table. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to create a table. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to create a table. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to create a table. A object that represents the current operation. Returns a task that performs an asynchronous operation to create a table. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to create a table. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to create a table. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Creates the table if it does not already exist. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. true if table was created; otherwise, false. Begins an asynchronous operation to create a table if it does not already exist. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to create a table if it does not already exist. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to determine whether a table exists. An that references the pending asynchronous operation. true if table exists; otherwise, false. Returns a task that performs an asynchronous operation to create a table if it does not already exist. A object that represents the current operation. Returns a task that performs an asynchronous operation to create a table if it does not already exist. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to create a table if it does not already exist. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to create a table if it does not already exist. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Deletes a table. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. Begins an asynchronous operation to delete a table. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to delete a table. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to delete a table. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to delete a table. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete a table. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete a table. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete a table. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Deletes the table if it exists. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. true if the table was deleted; otherwise, false. Begins an asynchronous operation to delete the table if it exists. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to delete the table if it exists. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to delete the table if it exists. An that references the pending asynchronous operation. true if the table was deleted; otherwise, false. Returns a task that performs an asynchronous operation to delete the table if it exists. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete the table if it exists. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete the table if it exists. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete the table if it exists. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Checks whether the table exists. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. true if table exists; otherwise, false. Checks whether the table exists. If true, the command will be executed against the primary location. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. true if table exists; otherwise, false. Begins an asynchronous operation to determine whether a table exists. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to determine whether a table exists. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to determine whether a table exists. If true, the command will be executed against the primary location. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to determine whether a table exists. An that references the pending asynchronous operation. true if table exists; otherwise, false. Returns a task that performs an asynchronous operation to determine whether a table exists. A object that represents the current operation. Returns a task that performs an asynchronous operation to determine whether a table exists. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to determine whether a table exists. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to determine whether a table exists. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Gets the permissions settings for the table. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. The table's permissions. Begins an asynchronous request to get the permissions settings for the table. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to get the permissions settings for the table. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Returns the asynchronous result of the request to get the permissions settings for the table. An that references the pending asynchronous operation. The table's permissions. Returns a task that performs an asynchronous request to get the permissions settings for the table. A object that represents the current operation. Returns a task that performs an asynchronous request to get the permissions settings for the table. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous request to get the permissions settings for the table. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous request to get the permissions settings for the table. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Sets the permissions settings for the table. A object that represents the permissions to set. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. Begins an asynchronous request to set permissions for the table. The permissions to apply to the table. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to set permissions for the table. The permissions to apply to the table. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Returns the asynchronous result of the request to get the permissions settings for the table. An that references the pending asynchronous operation. Returns a task that performs an asynchronous request to set permissions for the table. The permissions to apply to the table. A object that represents the current operation. Returns a task that performs an asynchronous request to set permissions for the table. The permissions to apply to the table. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous request to set permissions for the table. The permissions to apply to the table. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous request to set permissions for the table. The permissions to apply to the table. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Initializes a new instance of the class. The absolute URI to the table. Initializes a new instance of the class. The absolute URI to the table. The account credentials. Initializes a new instance of the class. The absolute URI to the table. The account credentials. Initializes a new instance of the class. The table name. The client. Returns a shared access signature for the table. The access policy for the shared access signature. An access policy identifier. The start partition key, or null. The start row key, or null. The end partition key, or null. The end row key, or null. A shared access signature, as a URI query string. The query string returned includes the leading question mark. Thrown if the current credentials don't support creating a shared access signature. Returns the name of the table. The name of the table. Parse URI for SAS (Shared Access Signature) information. The complete Uri. The credentials to use. Gets the canonical name of the table, formatted as /<account-name>/<table-name>. The canonical name of the table. Gets the object that represents the Table service. A client object that specifies the Table service endpoint. Gets the table name. The table name. Gets the table's URI for the primary location. The absolute URI to the table, at the primary location. Gets the table's URIs for all locations. An object of type containing the table's URIs for all locations. Provides a client-side logical representation of the Windows Azure Table Service. This client is used to configure and execute requests against the Table Service. The service client encapsulates the base URI for the Table service. If the service client will be used for authenticated access, it also encapsulates the credentials for accessing the storage account. Provides a client-side logical representation of the Windows Azure Table service. This client is used to configure and execute requests against the Table service. The CloudTableClient object encapsulates the base URI for the Table service. If the service client will be used for authenticated access, it also encapsulates the credentials for accessing the storage account. Returns an enumerable collection of tables, which are retrieved lazily, that begin with the specified prefix. The table name prefix. A object that specifies additional options for the request. An object that provides information on how the operation executed. An enumerable collection of tables that are retrieved lazily. Returns an enumerable collection of tables in the storage account. A returned by a previous listing operation. An enumerable collection of tables. Returns an enumerable collection of tables, which are retrieved lazily, that begin with the specified prefix. The table name prefix. A returned by a previous listing operation. An enumerable collection of tables that are retrieved lazily. Returns an enumerable collection of tables that begin with the specified prefix and that are retrieved lazily. The table name prefix. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A returned by a previous listing operation. A object that specifies additional options for the request. An object that provides information on how the operation executed. An enumerable collection of tables that are retrieved lazily. Begins an asynchronous operation to return a result segment containing a collection of tables in the storage account. A returned by a previous listing operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to return a result segment containing a collection of tables beginning with the specified prefix. The table name prefix. A returned by a previous listing operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to return a result segment containing a collection of tables beginning with the specified prefix. The table name prefix. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A returned by a previous listing operation. The server timeout, maximum execution time, and retry policies for the operation. An object that provides information on how the operation executed. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to return a result segment containing a collection of tables. An that references the pending asynchronous operation. A result segment containing tables. Returns a task that performs an asynchronous operation to return a result segment containing a collection of tables beginning with the specified prefix. A returned by a previous listing operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to return a result segment containing a collection of tables beginning with the specified prefix. A returned by a previous listing operation. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to return a result segment containing a collection of tables beginning with the specified prefix. The table name prefix. A returned by a previous listing operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to return a result segment containing a collection of tables beginning with the specified prefix. The table name prefix. A returned by a previous listing operation. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to return a result segment containing a collection of tables beginning with the specified prefix. The table name prefix. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A returned by a previous listing operation. The server timeout, maximum execution time, and retry policies for the operation. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to return a result segment containing a collection of tables beginning with the specified prefix. The table name prefix. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A returned by a previous listing operation. The server timeout, maximum execution time, and retry policies for the operation. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Gets the service properties for the Table service. A object that specifies additional options for the request. An object that provides information on how the operation executed. The table service properties as a object. Begins an asynchronous operation to get the service properties of the Table service. The callback delegate that will receive notification when the asynchronous operation completes. A user defined object to be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to get the service properties of the Table service. A object that specifies additional options for the request. An object that provides information on how the operation executed. The callback delegate that will receive notification when the asynchronous operation completes. A user defined object to be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to get the service properties of the Table service. The result returned from a prior call to . The table service properties. Returns a task that performs an asynchronous operation to get the service properties of the Table service. A object that represents the current operation. Returns a task that performs an asynchronous operation to get the service properties of the Table service. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to get the service properties of the Table service. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to get the service properties of the Table service. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Sets the service properties of the Table service. The table service properties. A object that specifies additional options for the request. An object that provides information on how the operation executed. Begins an asynchronous operation to set the service properties of the Table service. The table service properties. The callback delegate that will receive notification when the asynchronous operation completes. A user defined object to be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to set the service properties of the Table service. The table service properties. A object that specifies additional options for the request. An object that provides information on how the operation executed. The callback delegate that will receive notification when the asynchronous operation completes. A user defined object to be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to set the service properties of the Table service. The result returned from a prior call to Returns a task that performs an asynchronous operation to set the service properties of the Table service. The table service properties. A object that represents the current operation. Returns a task that performs an asynchronous operation to set the service properties of the Table service. The table service properties. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to set the service properties of the Table service. The table service properties. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to set the service properties of the Table service. The table service properties. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Begins an asynchronous operation to get the stats of the table service. The callback delegate that will receive notification when the asynchronous operation completes. A user defined object to be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to get the stats of the table service. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user defined object to be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to get the stats of the table service. An that references the pending asynchronous operation. The table service stats. Returns a task that performs an asynchronous operation to get the stats of the table service. A object that represents the current operation. Returns a task that performs an asynchronous operation to get the stats of the table service. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to get the stats of the table service. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to get the stats of the table service. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Gets the stats of the table service. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. The table service stats. Creates a new object for performing operations against the Table service. A service context to use for performing operations against the Table service. The default server and client timeout interval. Max execution time across all potential retries. Initializes a new instance of the class using the specified Table service endpoint and anonymous credentials. The Table service endpoint to use to create the client. Initializes a new instance of the class using the specified Table service endpoint and storage account credentials. The Table service endpoint to use to create the client. The storage account credentials. Initializes a new instance of the class using the specified Blob service endpoint and account credentials. The Table service endpoint to use to create the client. The storage account credentials. Gets a reference to the specified table. The name of the table. A object. Gets or sets the authentication scheme to use to sign HTTP requests. Note that if you are using the legacy Table service API, which is based on WCF Data Services, the authentication scheme used by the TableServiceContext object will always be Shared Key Lite, regardless of the value of this property. Gets the authentication handler used to sign HTTP requests. The authentication handler. Gets or sets a buffer manager that implements the interface, specifying a buffer pool for use with operations against the Table service client. Gets the storage account credentials used to create the Table service client. The storage account credentials. Gets the base URI for the Table service client, at the primary location. The base URI used to construct the Table service client, at the primary location. Gets the Table service endpoints for all locations. An object of type containing Table service URIs for all locations. Gets or sets the default retry policy for requests made via the Table service client. The retry policy. Gets or sets the default location mode for requests made via the Table service client. The location mode. Gets or sets the default server and client timeout for requests. The server and client timeout interval. Gets or sets the maximum execution time across all potential retries. The maximum execution time across all potential retries. Gets and sets the that is used for any table accessed with this object. The TablePayloadFormat to use. Gets a value indicating whether the service client is used with Path style or Host style. Is true if use path style URIs; otherwise, false. Gets the associated account name for the client. The account name. Represents a custom attribute that can be used to ignore entity properties during serialization/de-serialization. Represents a batch operation on a table. Represents a batch operation on a table. A batch operation is a collection of table operations which are executed by the Storage Service REST API as a single atomic operation, by invoking an Entity Group Transaction.A batch operation may contain up to 100 individual table operations, with the requirement that each operation entity must have same partition key. A batch with a retrieve operation cannot contain any other operations. Note that the total payload of a batch operation is limited to 4MB. Inserts a into the batch that retrieves an entity based on its row key and partition key. The entity will be deserialized into the specified class type which extends . The class of type for the entity to retrieve. A string containing the partition key of the entity to retrieve. A string containing the row key of the entity to retrieve. Adds a table operation to retrieve an entity of the specified class type with the specified partition key and row key to the batch operation. The return type which the specified will resolve the given entity to. A string containing the partition key of the entity to retrieve. A string containing the row key of the entity to retrieve. The implementation to project the entity to retrieve as a particular type in the result. Initializes a new instance of the class. Adds a to the that deletes the specified entity from a table. The entity to be deleted from the table. Adds a to the that inserts the specified entity into a table. The entity to be inserted into the table. Adds a object that inserts the specified entity into the table as part of the batch operation. The entity to be inserted into the table. true if the message payload should be returned in the response to the insert operation;otherwise, false. Adds a to the that inserts the specified entity into a table if the entity does not exist; if the entity does exist then its contents are merged with the provided entity. The entity whose contents are being inserted or merged. Adds a to the that inserts the specified entity into a table if the entity does not exist; if the entity does exist then its contents are replaced with the provided entity. The entity whose contents are being inserted or replaced. Adds a to the that merges the contents of the specified entity with the existing entity in a table. The entity whose contents are being merged. Adds a to the that replaces the contents of the specified entity in a table. The entity whose contents are being replaced. Adds a to the that retrieves an entity with the specified partition key and row key. A string containing the partition key of the entity to retrieve. A string containing the row key of the entity to retrieve. Returns the zero-based index of the first occurrence of the specified item, or -1 if the does not contain the item. The item to search for. The zero-based index of the first occurrence of item within the , if found; otherwise, –1. Inserts a into the at the specified index. The index at which to insert the . The item to insert. Removes the at the specified index from the . The index of the to remove from the . Adds the to the . The item to add to the . Clears all objects from the . Returns true if this contains the specified element. The item to search for. true if the item is contained in the ; false, otherwise. Copies all the elements of the to the specified one-dimensional array starting at the specified destination array index. The one-dimensional array that is the destination of the elements copied from the . The index in the destination array at which copying begins. Removes the specified item from the . The item to remove. true if the item was successfully removed; false, otherwise. Returns an for the . An enumerable collection of items. Returns an . An for the . Gets or sets the item at the specified index. The index at which to get or set the item. The item at the specified index. Gets the number of operations in this . The number of operations in the . Gets a value indicating whether the is read-only. true if the is read-only; false, otherwise. Represents a single table operation. Represents a single table operation. Creates a new table operation that retrieves the contents of the given entity in a table. The class of type for the entity to retrieve. A string containing the partition key of the entity to retrieve. A string containing the row key of the entity to retrieve. The object. Creates a new table operation that retrieves the contents of the given entity in a table. The return type which the specified will resolve the given entity to. A string containing the partition key of the entity to retrieve. A string containing the row key of the entity to retrieve. The implementation to project the entity to retrieve as a particular type in the result. The object. Creates a new instance of the class given the entity to operate on and the type of operation that is being performed. The entity on which the operation is being performed. The type of operation. Creates a new table operation that deletes the given entity from a table. The entity to be deleted from the table. The object. Creates a new table operation that inserts the given entity into a table. The entity to be inserted into the table. The object. Creates a new table operation that inserts the given entity into a table. The entity to be inserted into the table. true if the message payload should be returned in the response to the insert operation. false otherwise. The table operation. Creates a new table operation that inserts the given entity into a table if the entity does not exist; if the entity does exist then its contents are merged with the provided entity. The entity whose contents are being inserted or merged. The object. Creates a new table operation that inserts the given entity into a table if the entity does not exist; if the entity does exist then its contents are replaced with the provided entity. The entity whose contents are being inserted or replaced. The object. Creates a new table operation that merges the contents of the given entity with the existing entity in a table. The entity whose contents are being merged. The object. Creates a new table operation that replaces the contents of the given entity in a table. The entity whose contents are being replaced. The object. Creates a new table operation that replaces the contents of the given entity in a table. The partition key of the entity to be replaced. The row key of the entity to be replaced. The object. Gets the entity that is being operated upon. Gets the type of operation. Gets or sets the value that represents whether the message payload should be returned in the response. Represents a query against a Windows Azure table. A class which implements . Represents a query against a specified table. Initializes a new instance of the class. Executes a query on a table, using the specified and . A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. An enumerable collection, specialized for type TElement, of the results of executing the query. Begins an asynchronous operation to execute a query and return the results as a result segment. A continuation token returned by a previous listing operation, can be null. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to execute a query and return the results as a result segment. A continuation token returned by a previous listing operation, can be null. An object for tracking the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An that references the asynchronous operation. Ends an asynchronous operation to execute a query and return the results as a result segment. The reference to the pending asynchronous request to finish. A result segment containing objects of type . Begins an asynchronous operation to execute a query and return the results as a result segment. A continuation token returned by a previous listing operation, can be null. A of object that represents the current operation. Begins an asynchronous operation to execute a query and return the results as a result segment. A continuation token returned by a previous listing operation, can be null./// A to observe while waiting for a task to complete. A of object that represents the current operation. Begins an asynchronous operation to execute a query and return the results as a result segment. A continuation token returned by a previous listing operation, can be null. An object for tracking the current operation. A object that specifies execution options, such as retry policy and timeout settings, for the operation. A of object that represents the current operation. Begins an asynchronous operation to execute a query and return the results as a result segment. A continuation token returned by a previous listing operation, can be null. An object for tracking the current operation. A object that specifies execution options, such as retry policy and timeout settings, for the operation. A to observe while waiting for a task to complete. A of object that represents the current operation. Queries a table in segmented mode using the specified continuation token, , and . A object representing a continuation token from the server when the operation returns a partial result. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. A , specialized for type TElement, containing the results of executing the query. Returns an enumerator that iterates through the . An for the . Generates a property filter condition string for the string value. A string containing the name of the property to compare. A string containing the comparison operator to use. A string containing the value to compare with the property. A string containing the formatted filter condition. Generates a property filter condition string for the boolean value. A string containing the name of the property to compare. A string containing the comparison operator to use. A bool containing the value to compare with the property. A string containing the formatted filter condition. Generates a property filter condition string for the binary value. A string containing the name of the property to compare. A string containing the comparison operator to use. A byte array containing the value to compare with the property. A string containing the formatted filter condition. Generates a property filter condition string for the value. A string containing the name of the property to compare. A string containing the comparison operator to use. A containing the value to compare with the property. A string containing the formatted filter condition. Generates a property filter condition string for the value. A string containing the name of the property to compare. A string containing the comparison operator to use. A containing the value to compare with the property. A string containing the formatted filter condition. Generates a property filter condition string for the value. A string containing the name of the property to compare. A string containing the comparison operator to use. A containing the value to compare with the property. A string containing the formatted filter condition. Generates a property filter condition string for the value. A string containing the name of the property to compare. A string containing the comparison operator to use. A containing the value to compare with the property. A string containing the formatted filter condition. Generates a property filter condition string for the value. A string containing the name of the property to compare. A string containing the comparison operator to use. A containing the value to compare with the property. A string containing the formatted filter condition. Generates a property filter condition string for the value, formatted as the specified . A string containing the name of the property to compare. A string containing the comparison operator to use. A string containing the value to compare with the property. The to format the value as. A string containing the formatted filter condition. Creates a filter condition using the specified logical operator on two filter conditions. A string containing the first formatted filter condition. A string containing Operators.AND or Operators.OR. A string containing the second formatted filter condition. A string containing the combined filter expression. Defines the property names of the table entity properties to return when the table query is executed. The select clause is optional on a table query, used to limit the table properties returned from the server. By default, a query will return all properties from the table entity. A list of string objects containing the property names of the table entity properties to return when the query is executed. A instance set with the table entity properties to return. Defines the upper bound for the number of entities the query returns. The maximum number of entities for the table query to return. A instance set with the number of entities to return. Defines a filter expression for the table query. Only entities that satisfy the specified filter expression will be returned by the query. Setting a filter expression is optional; by default, all entities in the table are returned if no filter expression is specified in the table query. A string containing the filter expression to apply to the table query. A instance set with the filter on entities to return. Gets the type of the element(s) that are returned when the expression tree is executed. Gets the expression tree. Gets the query provider that is associated with this data source. Gets or sets the number of entities the query returns specified in the table query. The maximum number of entities for the table query to return. Gets or sets the filter expression to use in the table query. A string containing the filter expression to use in the query. Gets or sets the property names of the table entity properties to return when the table query is executed. A list of strings containing the property names of the table entity properties to return when the query is executed. Represents a query against a specified table. The class aggregates and encodes the query parameters to pass with the request when the query is executed. To execute the query, call the executeQuery or executeQuerySegmented method of the class. Represents a query against a specified table. A instance aggregates the query parameters to use when the query is executed. One of the executeQuery or executeQuerySegmented methods of must be called to execute the query. The parameters are encoded and passed to the server when the table query is executed. Specifies the names of the entity properties to return when the query is executed against the table. The Project clause is optional on a query, used to limit the properties returned from the server. By default, a query will return all properties from the entity. The entity type of the query. The entity instance to project off of. A list of string objects containing the names of the entity properties to return when the query is executed. A instance set with the entity properties to return. Generates a property filter condition string for the string value. A string containing the name of the property to compare. A string containing the comparison operator to use. A string containing the value to compare with the property. A string containing the formatted filter condition. Generates a property filter condition string for the boolean value. A string containing the name of the property to compare. A string containing the comparison operator to use. A bool containing the value to compare with the property. A string containing the formatted filter condition. Generates a property filter condition string for the binary value. A string containing the name of the property to compare. A string containing the comparison operator to use. A byte array containing the value to compare with the property. A string containing the formatted filter condition. Generates a property filter condition string for the value. A string containing the name of the property to compare. A string containing the comparison operator to use. A containing the value to compare with the property. A string containing the formatted filter condition. Generates a property filter condition string for the value. A string containing the name of the property to compare. A string containing the comparison operator to use. A containing the value to compare with the property. A string containing the formatted filter condition. Generates a property filter condition string for the value. A string containing the name of the property to compare. A string containing the comparison operator to use. A containing the value to compare with the property. A string containing the formatted filter condition. Generates a property filter condition string for the value. A string containing the name of the property to compare. A string containing the comparison operator to use. A containing the value to compare with the property. A string containing the formatted filter condition. Generates a property filter condition string for the value. A string containing the name of the property to compare. A string containing the comparison operator to use. A containing the value to compare with the property. A string containing the formatted filter condition. Generates a property filter condition string for the value, formatted as the specified . A string containing the name of the property to compare. A string containing the comparison operator to use. A string containing the value to compare with the property. The to format the value as. A string containing the formatted filter condition. Creates a filter condition using the specified logical operator on two filter conditions. A string containing the first formatted filter condition. A string containing Operators.AND or Operators.OR. A string containing the second formatted filter condition. A string containing the combined filter expression. Defines the property names of the table entity properties to return when the table query is executed. The select clause is optional on a table query, used to limit the table properties returned from the server. By default, a query will return all properties from the table entity. A list of string objects containing the property names of the table entity properties to return when the query is executed. A instance set with the table entity properties to return. Defines the upper bound for the number of entities the query returns. The maximum number of entities for the table query to return. A instance set with the number of entities to return. Defines a filter expression for the table query. Only entities that satisfy the specified filter expression will be returned by the query. Setting a filter expression is optional; by default, all entities in the table are returned if no filter expression is specified in the table query. A string containing the filter expression to apply to the table query. A instance set with the filter on entities to return. Gets or sets the number of entities the table query will return. The maximum number of entities for the table query to return. Gets or sets the filter expression to use in the table query. A string containing the filter expression to use in the query. Gets or sets the property names of the table entity properties to return when the table query is executed. A list of strings containing the property names of the table entity properties to return when the query is executed. Represents the default EDM entity container for table storage. Initializes a new instance of the EdmEntityContainer class and sets the model and entity set. The name and namespace should not matter since we look for default entity container. Sets the data model that will be used for table transactions. Searches for an entity set with the given name in this entity container and creates a new set if no such set exists. The name of the element being found. The requested element, or the new element created if no such element exists. Represents a data model that will be used by OData for table transactions. Initializes a new instance of the class. Initializes a new instance of the class. Searches for a type with the given name in this model and creates a new type if no such type exists. The qualified name of the type being found. The requested type, or the new type created if no such type exists. Create a new type with the standard set of properties(PK, RK and TimeStamp). Namespace the entity belongs to. Name of the entity. The EdmEntityType created. Searches for a type with the given name in this model. Returns true if such a type is found, otherwise returns false. The qualified name of the type being found. true if the type is found; otherwise, false. Represents a object for use with the Windows Azure Table service. The class does not support concurrent queries or requests. Initializes a new instance of the class. Callback on DataContext object sending request. The sender. The instance containing the event data. Saves changes, using the retry policy specified for the service context. A that represents the result of the operation. Saves changes, using the retry policy specified for the service context. Additional options for saving changes. A that represents the result of the operation. Begins an asynchronous operation to save changes, using the retry policy specified for the service context. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to save changes, using the retry policy specified for the service context. Additional options for saving changes. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to save changes, using the retry policy specified for the service context. Additional options for saving changes. An object for tracking the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to save changes. An that references the pending asynchronous operation. A that represents the result of the operation. Returns a object that performs an asynchronous operation to save changes, using the retry policy specified for the service context. A object that represents the current operation. Returns a object that performs an asynchronous operation to save changes, using the retry policy specified for the service context. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a object that performs an asynchronous operation to save changes, using the retry policy specified for the service context. Additional options for saving changes. A object that represents the current operation. Returns a object that performs an asynchronous operation to save changes, using the retry policy specified for the service context. Additional options for saving changes. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a object that performs an asynchronous operation to save changes, using the retry policy specified for the service context. Additional options for saving changes. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A object that represents the current operation. Returns a object that performs an asynchronous operation to save changes, using the retry policy specified for the service context. Additional options for saving changes. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Releases all resources used by the TableServiceContext. Releases the unmanaged resources used by the TableServiceContext and optionally releases the managed resources. true to release both managed and unmanaged resources; false to release only unmanaged resources. Gets the object that represents the Table service. A client object that specifies the Table service endpoint. Gets the authentication handler used to sign HTTP requests. The authentication handler. Represents an entity in the Windows Azure Table service. Initializes a new instance of the class. The partition key. The row key. Initializes a new instance of the class. Gets or sets the timestamp for the entity. The entity's timestamp. Gets or sets the partition key of a table entity. The partition key. Gets or sets the row key of a table entity. The row key. Provides a set of extensions for the Table service. Converts the query into a object that supports additional operations like retries. The type of the element. The query. A object that represents the runtime context of the Table service. The converted query. A class for constructing a query against the Table service. The type of the element. Initializes a new instance of the class. An object that implements . A object. Expands the specified path. The path to expand. A new query with the expanded path. Returns an enumerator that iterates through the collection. A that can be used to iterate through the collection. Executes the request with any specified options. An object of type . An object for tracking the current operation. An enumerable collection, specialized for type TElement, of the results of executing the query. Executes a segmented query against the Table service. The continuation token. The request options. An object for tracking the current operation. A result segment containing objects of type . Begins an asynchronous operation to execute a query and return the results as a result segment. A continuation token returned by a previous listing operation, can be null. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to execute a query and return the results as a result segment. A continuation token returned by a previous listing operation, can be null. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to execute a query and return the results as a result segment. The reference to the pending asynchronous request to finish. A result segment containing objects of type . Returns a task that performs an asynchronous operation to execute a query and return the results as a result segment. A continuation token returned by a previous listing operation, can be null. A object that represents the current operation. Returns a task that performs an asynchronous operation to execute a query and return the results as a result segment. A continuation token returned by a previous listing operation, can be null. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to execute a query and return the results as a result segment. A continuation token returned by a previous listing operation, can be null. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to execute a query and return the results as a result segment. A continuation token returned by a previous listing operation, can be null. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Gets the table service context. An object of type . Stores the wrapped . Gets the type of the element(s) that are returned when the expression tree associated with this instance of is executed. A that represents the type of the element(s) that are returned when the expression tree associated with this object is executed. Gets the expression tree that is associated with the instance of . The that is associated with this instance of . Gets the query provider that is associated with this data source. The that is associated with this data source. A factory class for constructing a web request to manage tables in the Table service. Creates a web request to get the properties of the Table service. The absolute URI to the Table service. An object of type , containing additional parameters to add to the URI query string. The server timeout interval, in seconds. An object for tracking the current operation. A web request to get the Table service properties. Creates a web request to set the properties of the Table service. The absolute URI to the Table service. An object of type , containing additional parameters to add to the URI query string. The server timeout interval, in seconds. An object for tracking the current operation. A web request to set the Table service properties. Creates a web request to get the stats of the Table service. The absolute URI to the Table service. An object of type , containing additional parameters to add to the URI query string. The server timeout interval, in seconds. An object for tracking the current operation. A web request to get the Table service stats. Writes Table service properties to a stream, formatted in XML. The service properties to format and write to the stream. The stream to which the formatted properties are to be written. Constructs a web request to return the ACL for a table. The absolute URI to the table. An object of type , containing additional parameters to add to the URI query string. The server timeout interval. An object for tracking the current operation. A web request to use to perform the operation. Constructs a web request to set the ACL for a table. The absolute URI to the table. An object of type , containing additional parameters to add to the URI query string. The server timeout interval. An object for tracking the current operation. A web request to use to perform the operation. Provides a set of methods for parsing a response stream from the Table service. Gets the request ID from the response. The web response. A unique value associated with the request. Reads service properties from a stream. The stream from which to read the service properties. The service properties stored in the stream. Reads service stats from a stream. The stream from which to read the service stats. The service stats stored in the stream. Reads the share access policies from a stream in XML. The stream of XML policies. The permissions object to which the policies are to be written. Gets the table continuation from response. The response. The continuation. Translates the data service exception. The exception. The request result. The delegate used to parse the error to get extended error information. The translated exception. Look for an inner exception of type T. The exception. The found exception or null. Applies the continuation to query. The continuation token. The local query. The modified query. Gets the query take count. The type of the element. The query. The default value. The take count of the query, if any. Gets the table continuation from response. The response. The continuation. Copies the headers and properties from a request into a different request. The request to copy into. The request to copy from. Gets an ETag from a response. The web response. A quoted ETag string. Gets the user-defined metadata. The response from server. A of the metadata. Gets the metadata or properties. The response from server. The prefix for all the headers. A of the headers with the prefix. Converts a string to UTC time. The string to convert. A UTC representation of the string. Reads service properties from a stream. The stream from which to read the service properties. The service properties stored in the stream. Reads service stats from a stream. The stream from which to read the service stats. The service stats stored in the stream. Reads a collection of shared access policies from the specified object. A collection of shared access policies to be filled. A policy response object for reading the stream. The type of policy to read. Creates the web request. The HTTP method. The request URI. The timeout. An object of type , containing additional parameters to add to the URI query string. An object for tracking the current operation. A web request for performing the operation. Creates the specified URI. The URI to create. The timeout. The builder. An object for tracking the current operation. A web request for performing the operation. Constructs a web request to return the ACL for a cloud resource. The absolute URI to the resource. The server timeout interval. An optional query builder to use. An object for tracking the current operation. A web request to use to perform the operation. Constructs a web request to set the ACL for a cloud resource. The absolute URI to the resource. The server timeout interval. An optional query builder to use. An object for tracking the current operation. A web request to use to perform the operation. Gets the properties. The URI to query. The timeout. The builder. An object for tracking the current operation. A web request for performing the operation. Gets the metadata. The blob Uri. The timeout. The builder. An object for tracking the current operation. A web request for performing the operation. Sets the metadata. The blob Uri. The timeout. The builder. An object for tracking the current operation. A web request for performing the operation. Adds the metadata. The request. The metadata. Adds the metadata. The request. The metadata name. The metadata value. Deletes the specified URI. The URI of the resource to delete. The timeout. The builder. An object for tracking the current operation. A web request for performing the operation. Creates a web request to get the properties of the service. The absolute URI to the service. An object of type , containing additional parameters to add to the URI query string. The server timeout interval. An object for tracking the current operation. A web request to get the service properties. Creates a web request to set the properties of the service. The absolute URI to the service. The builder. The server timeout interval. An object for tracking the current operation. A web request to set the service properties. Creates a web request to get the stats of the service. The absolute URI to the service. An object of type , containing additional parameters to add to the URI query string. The server timeout interval. An object for tracking the current operation. A web request to get the service stats. Generates a query builder for building service requests. A for building service requests. Adds the lease id. The request. The lease id. Adds an optional header to a request. The web request. The metadata name. The metadata value. Adds an optional header to a request. The web request. The header name. The header value. Adds an optional header to a request. The web request. The header name. The header value. Applies the lease condition to the web request. The request to be modified. Access condition to be added to the request. Applies the sequence number condition to the web request. The request to be modified. Access condition to be added to the request. Applies the condition to the web request. The request to be modified. Access condition to be added to the request. Applies the condition for a source blob to the web request. The request to be modified. Access condition to be added to the request. Creates a well-formatted log entry so that logs can be easily parsed An object that represents the context for the current operation. A composite format string. An object array that contains zero or more objects to format. Log entry that contains common log prefix and a copy of format in which the format items have been replaced by the string representation of the corresponding objects in args. Determines if the current operation context allows for a specific level of log entry. Level of the log entry. An object that represents the context for the current operation. true if the entry should be logged; otherwise false. Represents a canonicalizer that converts HTTP request data into a standard form appropriate for signing. For detailed information on how to authenticate a request, see Authentication for the Windows Azure Storage Services. Converts the specified HTTP request data into a standard form appropriate for signing. The HTTP request that needs to be signed. The name of the storage account that the HTTP request will access. The canonicalized string containing the HTTP request data in a standard form appropriate for signing. Authentication for the Windows Azure Storage Services Gets the authorization scheme used for canonicalization. The authorization scheme used for canonicalization. Authentication for the Windows Azure Storage Services Represents a canonicalizer that converts HTTP request data into a standard form appropriate for signing via the Shared Key authentication scheme for the Blob or Queue service. Authentication for the Windows Azure Storage Services Converts the specified HTTP request data into a standard form appropriate for signing. The HTTP request that needs to be signed. The name of the storage account that the HTTP request will access. The canonicalized string containing the HTTP request data in a standard form appropriate for signing. Authentication for the Windows Azure Storage Services Gets a static instance of the object. The static instance of the class. Authentication for the Windows Azure Storage Services Gets the authorization scheme used for canonicalization. The authorization scheme used for canonicalization. Authentication for the Windows Azure Storage Services Represents a canonicalizer that converts HTTP request data into a standard form appropriate for signing via the Shared Key Lite authentication scheme for the Blob or Queue service. Authentication for the Windows Azure Storage Services Converts the specified HTTP request data into a standard form appropriate for signing. The HTTP request that needs to be signed. The name of the storage account that the HTTP request will access. The canonicalized string containing the HTTP request data in a standard form appropriate for signing. Authentication for the Windows Azure Storage Services Gets a static instance of the object. The static instance of the class. Authentication for the Windows Azure Storage Services Gets the authorization scheme used for canonicalization. The authorization scheme used for canonicalization. Authentication for the Windows Azure Storage Services Represents a canonicalizer that converts HTTP request data into a standard form appropriate for signing via the Shared Key Lite authentication scheme for the Table service. Authentication for the Windows Azure Storage Services Converts the specified HTTP request data into a standard form appropriate for signing. The HTTP request that needs to be signed. The name of the storage account that the HTTP request will access. The canonicalized string containing the HTTP request data in a standard form appropriate for signing. Authentication for the Windows Azure Storage Services Gets a static instance of the object. The static instance of the class. Authentication for the Windows Azure Storage Services Gets the authorization scheme used for canonicalization. The authorization scheme used for canonicalization. Authentication for the Windows Azure Storage Services Represents a canonicalizer that converts HTTP request data into a standard form appropriate for signing via the Shared Key authentication scheme for the Table service. Authentication for the Windows Azure Storage Services Converts the specified HTTP request data into a standard form appropriate for signing. The HTTP request that needs to be signed. The name of the storage account that the HTTP request will access. The canonicalized string containing the HTTP request data in a standard form appropriate for signing. Authentication for the Windows Azure Storage Services Gets a static instance of the object. The static instance of the class. Authentication for the Windows Azure Storage Services Gets the authorization scheme used for canonicalization. The authorization scheme used for canonicalization. Authentication for the Windows Azure Storage Services Helper class to allow an APM Method to be executed with a given timeout in milliseconds Helper class to convert an APM method to a Task method. This class provides asynchronous semaphore functionality (based on Stephen Toub's blog). Creates and initializes a new asynchronous copy operation. The source stream. The destination stream. An ExecutionState used to coordinate copy operation. Size of read and write buffers used to move data. Boolean value indicating whether the MD-5 should be calculated. An object that represents the state for the current operation. Begins a stream copy operation. Callback delegate Number of bytes to copy from source stream to destination stream. Cannot be passed with a value for maxLength. Maximum length of the source stream. Cannot be passed with a value for copyLength. Aborts an ongoing copy operation. Cleans up references. To end a copy operation, use Abort(). Synchronizes Read and Write operations, and handles exceptions. Read/Write operation or null if first run. Helper method for EndOpWithCatch(IAsyncResult). Begins/Ends Read and Write Stream operations. Should only be called by EndOpWithCatch(IAsyncResult) since it assumes we are inside the lock. Read/Write operation or null if first run. Callback for timeout timer. Aborts the AsyncStreamCopier operation if a timeout occurs. AsyncStreamCopier operation. True if the timer has timed out, false otherwise. Aborts the AsyncStreamCopier operation. AsyncStreamCopier operation. True if aborted due to a time out, or false for a general cancellation. Terminates and cleans up the AsyncStreamCopier. Helper method for this.SignalCompletion() Should only be called by this.SignalCompletion() Determines whether the next operation should begin or halt due to an exception or cancellation. True to continue, false to halt. Waits for a read operation to end and updates the AsyncStreamCopier state. Waits for a write operation to end and updates the AsyncStreamCopier state. If a read operation has completed with data, swaps the read/write buffers and resets their corresponding counts. This must be called inside a lock as it could lead to undefined behavior if multiple unsynchronized callers simultaneously called in. Number of bytes to write, or negative if no read operation has completed. Determines the number of bytes that should be read from the source in the next BeginRead operation. Should only be called when no outstanding read operations exist. Number of bytes to read. Determines whether no more data can be read from the source Stream. True if at the end, false otherwise. Determines whether the current read buffer contains data ready to be written. True if read buffer is full, false otherwise. Represents an operation that supports cancellation. Used by ICancellableAsyncResult implementations throughout the library. Also used by AsyncExtensions as a bridge between CancellationToken and the ICancellableAsyncResult returned by an APM method call. The class is provides the helper functions to do FISMA compliant MD5. Cryptographic service provider. Access to the private keys is not required and the user interface can be bypassed. ALG_ID value that identifies the hash algorithm to use. The hash value or message hash for the hash object specified by hashHandle. The address to which the function copies a handle to the new hash object. Has to be released by calling the CryptDestroyHash function after we are finished using the hash object. A handle to a CSP created by a call to CryptAcquireContext. Whether this object has been torn down or not. Initializes a new instance of NativeMD5. Finalizes an instance of the NativeMD5 class, unhooking it from all events. Initializes an implementation of the NativeMD5 class. Routes data written to the object into the hash algorithm for computing the hash. The input to compute the hash code for. The offset into the byte array from which to begin using data. The number of bytes in the byte array to use as data. Finalizes the hash computation after the last data is processed by the cryptographic stream object. The computed hash code. Releases the unmanaged resources used by the NativeMD5. true to release both managed and unmanaged resources; false to release only unmanaged resources. Validates the status returned by all the crypto functions and throws exception per the return code. The boolean status returned by the crypto functions. Represents the async result returned by operations that do not directly call into the Executor. Async operation's result type Represents the async result returned by a storage command. The callback provided by the user. The state for the callback. Indicates whether a task is completed. Indicates whether task completed synchronously. The event for blocking on this task's completion. Initializes a new instance of the StorageCommandAsyncResult class. The callback method to be used on completion. The state for the callback. We implement the dispose only to allow the explicit closing of the event. Releases unmanaged and - optionally - managed resources. Set to true to release both managed and unmanaged resources; false to release only unmanaged resources. Provides the lazy initialization of the WaitHandle (based on Joe Duffy's blog). The WaitHandle to use for waiting on completion. Called on completion of the async operation to notify the user (Based on Joe Duffy's lockless design). Blocks the calling thread until the async operation is completed. Updates the CompletedSynchronously flag with another asynchronous operation result. Set to true if the last operation was completed synchronously; false if it was completed asynchronously. Gets A user-defined object that contains information about the asynchronous operation. Gets a System.Threading.WaitHandle that is used to wait for an asynchronous operation to complete. Gets a value indicating whether the asynchronous operation completed synchronously. Gets a value indicating whether the asynchronous operation has completed. Initializes a new instance of the StorageAsyncResult class. The callback method to be used on completion. The state for the callback. Called on completion of the async operation to notify the user Exception that was caught by the caller. Blocks the calling thread until the async operation is completed and throws any stored exceptions. Represents a set of access conditions to be used for operations against the storage services. Time for IfModifiedSince. Time for IfUnmodifiedSince. Constructs an empty access condition. An empty access condition. Constructs an access condition such that an operation will be performed only if the resource's ETag value matches the specified ETag value. The ETag value that must be matched. An AccessCondition object that represents the If-Match condition. Constructs an access condition such that an operation will be performed only if the resource has been modified since the specified time. The time since which the resource must have been modified in order for the operation to proceed. An AccessCondition object that represents the If-Modified-Since condition. Constructs an access condition such that an operation will be performed only if the resource's ETag value does not match the specified ETag value. The ETag value that must be matched, or "*". An AccessCondition object that represents the If-None-Match condition. If "*" is specified as the parameter then this condition requires that the resource does not exist. Constructs an access condition such that an operation will be performed only if the resource has not been modified since the specified time. The time since which the resource must not have been modified in order for the operation to proceed. An AccessCondition object that represents the If-Unmodified-Since condition. Constructs an access condition such that an operation will be performed only if resource's current sequence number is less than or equal to the specified value. The value that the current sequence number of the resource must be less than or equal to. An AccessCondition object that represents the If-Sequence-Number-LE condition. Constructs an access condition such that an operation will be performed only if resource's current sequence number is less than the specified value. The value that the current sequence number of the resource must be less than. An AccessCondition object that represents the If-Sequence-Number-LT condition. Constructs an access condition such that an operation will be performed only if resource's current sequence number is equal to the specified value. The value that the current sequence number of the resource must be equal to. An AccessCondition object that represents the If-Sequence-Number-EQ condition. Constructs an access condition such that an operation will be performed only if the lease ID on the resource matches the specified lease ID. The lease ID that must match the lease ID of the resource. An AccessCondition object that represents the lease condition. Constructs an access condition such that an operation will be performed only if the resource's ETag value matches the specified ETag value and the lease ID on the resource matches the lease ID specified in the given access condition. An AccessCondition object that represents the lease condition. The ETag value that must be matched. An AccessCondition object that represents the If-Match and the lease conditions. Gets or sets an ETag value that must match the ETag of the specified resource. A string containing an ETag value, or "*" to match any ETag. If null, no condition exists. Gets or sets an ETag value that must not match the ETag of the specified resource. A string containing an ETag value, or "*" to match any ETag. If null, no condition exists. Gets or sets a time that must be before the last modification of a resource. A DateTimeOffset in UTC, or null if no condition exists. Gets or sets a time that must not be before the last modification of a resource. A DateTimeOffset in UTC, or null if no condition exists. Gets or sets a sequence number that the current sequence number of a page blob must be less than or equal to in order for the operation to proceed. A sequence number, or null if no condition exists. This condition only applies to page blobs. Gets or sets a sequence number that the current sequence number of a page blob must be less than in order for the operation to proceed. A sequence number, or null if no condition exists. This condition only applies to page blobs. Gets or sets a sequence number that the current sequence number of a page blob must be equal to in order for the operation to proceed. A sequence number, or null if no condition exists. This condition only applies to page blobs. Gets or sets a lease ID that must match the lease on a resource. A lease ID, or null if no condition exists. Determines whether the access condition is one of the four conditional headers. true if the access condition is a conditional header; otherwise, false. Specifies the authentication scheme used to sign HTTP requests. Signs HTTP requests using the Shared Key Lite authentication scheme. Signs HTTP requests using the Shared Key authentication scheme. Represents a Windows Azure Storage account. The setting name for using the development storage. The setting name for specifying a development storage proxy Uri. The setting name for using the default storage endpoints with the specified protocol. The setting name for the account name. The setting name for the account key name. The setting name for the account key. The setting name for a custom blob storage endpoint. The setting name for a custom queue endpoint. The setting name for a custom table storage endpoint. The setting name for a custom storage endpoint suffix. The setting name for a shared access key. The default account name for the development storage. The default account key for the development storage. The credentials string used to test for the development storage credentials. The suffix appended to account in order to access secondary location for read only access. The default storage service hostname suffix. The default blob storage DNS hostname prefix. The root queue DNS name prefix. The root table storage DNS name prefix. The FISMA compliance default value. Validator for the UseDevelopmentStorage setting. Must be "true". Validator for the DevelopmentStorageProxyUri setting. Must be a valid Uri. Validator for the DefaultEndpointsProtocol setting. Must be either "http" or "https". Validator for the AccountName setting. No restrictions. Validator for the AccountKey setting. No restrictions. Validator for the AccountKey setting. Must be a valid base64 string. Validator for the BlobEndpoint setting. Must be a valid Uri. Validator for the QueueEndpoint setting. Must be a valid Uri. Validator for the TableEndpoint setting. Must be a valid Uri. Validator for the EndpointSuffix setting. Must be a valid Uri. Validator for the SharedAccessSignature setting. No restrictions. Singleton instance for the development storage account. Initializes a new instance of the class using the specified account credentials and service endpoints. The account credentials. The Blob service endpoint. The Queue service endpoint. The Table service endpoint. Initializes a new instance of the class using the specified account credentials and service endpoints. The account credentials. The Blob service endpoint. The Queue service endpoint. The Table service endpoint. Initializes a new instance of the class using the specified account credentials and the default service endpoints. An object of type that specifies the account name and account key for the storage account. True to use HTTPS to connect to storage service endpoints; otherwise, false. Initializes a new instance of the class using the specified account credentials and the default service endpoints. An object of type that specifies the account name and account key for the storage account. The DNS endpoint suffix for all storage services, e.g. "core.windows.net". True to use HTTPS to connect to storage service endpoints; otherwise, false. Parses a connection string and returns a created from the connection string. A valid connection string. Thrown if is null or empty. Thrown if is not a valid connection string. Thrown if cannot be parsed. A object constructed from the values provided in the connection string. Indicates whether a connection string can be parsed to return a object. The connection string to parse. A object to hold the instance returned if the connection string can be parsed. true if the connection string was successfully parsed; otherwise, false. Creates the Table service client. A client object that specifies the Table service endpoint. Creates the Queue service client. A client object that specifies the Queue service endpoint. Creates the Blob service client. A client object that specifies the Blob service endpoint. Returns a connection string for this storage account, without sensitive data. A connection string. Returns a connection string for the storage account, optionally with sensitive data. True to include sensitive data in the string; otherwise, false. A connection string. Returns a with development storage credentials using the specified proxy Uri. The proxy endpoint to use. The new . Internal implementation of Parse/TryParse. The string to parse. The to return. A callback for reporting errors. If true, the parse was successful. Otherwise, false. Tokenizes input and stores name value pairs. The string to parse. Error reporting delegate. Tokenized collection. Encapsulates a validation rule for an enumeration based account setting. The name of the setting. A list of valid values for the setting. An representing the enumeration constraint. Encapsulates a validation rule using a func. The name of the setting. A func that determines if the value is valid. An representing the constraint. Determines whether the specified setting value is a valid base64 string. The setting value. true if the specified setting value is a valid base64 string; otherwise, false. Validation function that validates Uris. Value to validate. true if the specified setting value is a valid Uri; otherwise, false. Validation function that validates a domain name. Value to validate. true if the specified setting value is a valid domain; otherwise, false. Settings filter that requires all specified settings be present and valid. A list of settings that must be present. The remaining settings or null if the filter's requirement is not satisfied. Settings filter that removes optional values. A list of settings that are optional. The remaining settings or null if the filter's requirement is not satisfied. Settings filter that ensures that at least one setting is present. A list of settings of which one must be present. The remaining settings or null if the filter's requirement is not satisfied. Settings filter that ensures that a valid combination of credentials is present. The remaining settings or null if the filter's requirement is not satisfied. Tests to see if a given list of settings matches a set of filters exactly. The settings to check. A list of filters to check. If any filter returns null, false. If there are any settings left over after all filters are processed, false. Otherwise true. Gets a StorageCredentials object corresponding to whatever credentials are supplied in the given settings. The settings to check. The StorageCredentials object specified in the settings. Gets the default blob endpoint using specified settings. The settings to use. The default blob endpoint. Gets the default blob endpoint using the specified protocol and account name. The protocol to use. The name of the storage account. The Endpoint DNS suffix; use null for default. The default blob endpoint. Gets the default queue endpoint using the specified settings. The settings. The default queue endpoint. Gets the default queue endpoint using the specified protocol and account name. The protocol to use. The name of the storage account. The Endpoint DNS suffix; use null for default. The default queue endpoint. Gets the default table endpoint using the specified settings. The settings. The default table endpoint. Gets the default table endpoint using the specified protocol and account name. The protocol to use. The name of the storage account. The Endpoint DNS suffix; use null for default. The default table endpoint. Gets or sets a value indicating whether the FISMA MD5 setting will be used. false to use the FISMA MD5 setting; true to use the .NET default implementation. Gets a object that references the development storage account. A reference to the development storage account. Indicates whether this account is a development storage account. The storage service hostname suffix set by the user, if any. The connection string parsed into settings. True if the user used a constructor that auto-generates endpoints. Gets the primary endpoint for the Blob service, as configured for the storage account. The primary Blob service endpoint. Gets the primary endpoint for the Queue service, as configured for the storage account. The primary Queue service endpoint. Gets the primary endpoint for the Table service, as configured for the storage account. The primary Table service endpoint. Gets the endpoints for the Blob service, as configured for the storage account. An object of type containing the endpoints for the Blob service. Gets the endpoints for the Queue service, as configured for the storage account. An object of type containing the endpoints for the Queue service. Gets the endpoints for the Table service, as configured for the storage account. An object of type containing the endpoints for the Table service. Gets the credentials used to create this object. The credentials used to create the object. Specifies that the method will make one or more requests to the storage service. An interface that allows clients to provide a buffer manager to a given service client. This interface is patterned after the System.ServiceModel.Channels.BufferManager class. Returns a buffer to the pool. A reference to the buffer being returned. Buffer reference cannot be null. Length of buffer does not match the pool's buffer length property. Gets a buffer of at least the specified size from the pool. The size, in bytes, of the requested buffer. The value specified for cannot be less than zero. A byte array that is the requested size of the buffer. Gets the size, in bytes, of the buffers managed by the given pool. Note that the buffer manager must return buffers of the exact size requested by the client. The size, in bytes, of the buffers managed by the given pool. An interface required for continuation token types. The , , and classes implement the interface. Gets the location that the token applies to. The location that the token applies to. An interface required for request option types. The , , and classes implement the interface. Gets or sets the retry policy for the request. The retry policy delegate. Gets or sets the location mode of the request. The location mode of the request. Gets or sets the server timeout for the request. The client and server timeout interval for the request. Gets or sets the maximum execution time across all potential retries. The maximum execution time across all potential retries. Specifies what messages to output to the log. Output no tracing and debugging messages. Output error-handling messages. Output warnings and error-handling messages. Output informational messages, warnings, and error-handling messages. Output all debugging and tracing messages. Represents the context for a request operation against the storage service, and provides additional runtime information about its execution. Initializes a new instance of the class. Gets or sets additional headers on the request, for example, for proxy or logging information. A object containing additional header information. Gets or sets the client request ID. The client request ID. Gets or sets the default logging level to be used for subsequently created instances of the class. A value of type that specifies which events are logged by default by instances of the . Gets or sets the logging level to be used for an instance of the class. A value of type that specifies which events are logged by the . Occurs immediately before a request is signed. Occurs when a response is received from the server. Gets or sets the start time of the operation. The start time of the operation. Gets or sets the end time of the operation. The end time of the operation. Gets or sets the set of request results that the current operation has created. An object that contains objects that represent the request results created by the current operation. Gets the last request result encountered for the operation. A object that represents the last request result. Provides information and event data that is associated with a request event. Initializes a new instance of the class by using the specified parameter. The object. Gets the request information associated with this event. The request information associated with this event. Gets the HTTP request associated with this event. The HTTP request associated with this event. Gets the HTTP response associated with this event. The HTTP response associated with this event. Represents the result of a physical request. Translates the specified message into a object. The message to translate. The translated . Generates a serializable RequestResult from its XML representation. The stream from which the RequestResult is deserialized. Converts a serializable RequestResult into its XML representation. The stream to which the RequestResult is serialized. Gets or sets the HTTP status code for the request. The HTTP status code for the request. Gets the HTTP status message for the request. The HTTP status message for the request. Gets the service request ID for this request. The service request ID for this request. Gets the content-MD5 value for the request. The content-MD5 value for the request. Gets the ETag value of the request. The ETag value of the request. Gets the request date. The request date. Gets the location that the request was sent to. The location that the request was sent to. Gets the extended error information. The extended error information. Gets or sets the exception. The exception. Gets the start time of the operation. The start time of the operation. Gets the end time of the operation. The end time of the operation. Represents a result segment that was retrieved from the total set of possible results. The type of the element. Stores the continuation token used to retrieve the next segment of results. Initializes a new instance of the ResultSegment class. The result. Gets an enumerable collection of results. An enumerable collection of results. Gets a continuation token to use to retrieve the next set of results with a subsequent call to the operation. The continuation token. Represents an exception thrown by the Windows Azure storage service. Initializes a new instance of the class. Initializes a new instance of the class using the specified error message. The message that describes the error. Initializes a new instance of the class with a specified error message and a reference to the inner exception that generated this exception. The exception error message. The inner exception. Initializes a new instance of the class with serialized data. The that contains contextual information about the source or destination. The object that holds serialized object data for the exception being thrown. This constructor is called during de-serialization to reconstitute the exception object transmitted over a stream. Populates a object with the data needed to serialize the target object. The destination context for this serialization. The object to populate with data. Initializes a new instance of the class by using the specified parameters. The request result. The exception message. The inner exception. Translates the specified exception into a . The exception to translate. The request result. The storage exception. An exception of type . Translates the specified exception into a storage exception. The exception to translate. The request result. The delegate used to parse the error to get extended error information. The storage exception. Translates the specified exception into a storage exception. The exception to translate. The request result. The delegate used to parse the error to get extended error information. The error stream that contains the error information. The storage exception. Tries to translate the specified exception into a storage exception. The exception to translate. The request result. The delegate used to parse the error to get extended error information. The storage exception or null. Translates the specified exception into a storage exception. The exception to translate. The request result. The delegate used to parse the error to get extended error information. The storage exception. Populate the RequestResult. The request result. The web response. Represents an exception thrown by the Windows Azure storage client library. A string that represents the exception. Gets the object for this object. The object for this object. Represents extended error information returned by the Windows Azure storage services. Initializes a new instance of the class. Gets the error details from stream. The input stream. The error details. Gets the error details from the stream using OData library. The input stream. The web response. The response Content-Type. The error details. Gets the error details from the stream using OData library. The input stream. The web response headers. The response Content-Type. The error details. Parses the error details from the stream using OData library. The IODataResponseMessage to parse. The error details. Generates a serializable object from its XML representation. The stream from which the object is deserialized. Converts a serializable object into its XML representation. The stream to which the object is serialized. Gets the storage service error code. The storage service error code. Gets the storage service error message. The storage service error message. Gets additional error details. The additional error details. Represents a storage service location. Primary storage service location. Secondary storage service location. Contains the URIs for both the primary and secondary locations of a Windows Azure Storage resource. Initializes a new instance of the class using the primary endpoint for the storage account. The URI for the primary endpoint. Initializes a new instance of the class using the primary and secondary endpoints for the storage account. The URI for the primary endpoint. The URI for the secondary endpoint. Returns the URI for the storage account endpoint at the specified location. The primary or secondary location for the storage account. The of the specified location. Returns a that represents this instance. A that represents this instance. Returns a hash code for this instance. A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. Determines whether the specified is equal to this instance. The to compare with this instance. true if the specified is equal to this instance; otherwise, false. Indicates whether the current object is equal to another object of the same type. An object to compare with this object. true if the current object is equal to the parameter; otherwise, false. The endpoint for the primary location for the storage account. The URI for the primary endpoint. The endpoint for the secondary location for the storage account. The URI for the secondary endpoint. Represents a set of credentials used to authenticate access to a Windows Azure storage account. Initializes a new instance of the class. Initializes a new instance of the class with the specified account name and key value. A string that represents the name of the storage account. A string that represents the Base64-encoded account access key. Initializes a new instance of the class with the specified account name and key value. A string that represents the name of the storage account. An array of bytes that represent the account access key. Initializes a new instance of the class with the specified account name, key value, and key name. A string that represents the name of the storage account. A string that represents the Base64-encoded account access key. A string that represents the name of the key. Initializes a new instance of the class with the specified account name, key value, and key name. A string that represents the name of the storage account. An array of bytes that represent the account access key. A string that represents the name of the key. Initializes a new instance of the class with the specified shared access signature token. A string representing the shared access signature token. Updates the key value for the credentials. The key value, as a Base64-encoded string, to update. Updates the key value for the credentials. The key value, as an array of bytes, to update. Updates the key value and key name for the credentials. The key value, as a Base64-encoded string, to update. The key name to update. Updates the key value and key name for the credentials. The key value, as an array of bytes, to update. The key name to update. Updates the shared access signature (SAS) token value for storage credentials created with a shared access signature. A string that specifies the SAS token value to update. Returns the account key for the credentials. An array of bytes that contains the key. Transforms a resource URI into a shared access signature URI, by appending a shared access token. A object that represents the resource URI to be transformed. A object that represents the signature, including the resource URI and the shared access token. Transforms a resource URI into a shared access signature URI, by appending a shared access token. A object that represents the resource URI to be transformed. A object that represents the signature, including the resource URI and the shared access token. Exports the value of the account access key to a Base64-encoded string. The account access key. Determines whether an other object is equal to this one by comparing their SAS tokens, account names, key names, and key values. The object to compare to this one. true if the two objects are equal; otherwise, false. Gets the associated shared access signature token for the credentials. The shared access signature token. Gets the associated account name for the credentials. The account name. Gets the associated key name for the credentials. The key name. Gets a value indicating whether the credentials are for anonymous access. true if the credentials are for anonymous access; otherwise, false. Gets a value indicating whether the credentials are a shared access signature token. true if the credentials are a shared access signature token; otherwise, false. Gets a value indicating whether the credentials are a shared key. true if the credentials are a shared key; otherwise, false. Represents a canonicalized string used in authenticating a request against the azure service. Stores the internal that holds the canonicalized string. Initializes a new instance of the class. The first canonicalized element to start the string with. Initializes a new instance of the class. The first canonicalized element to start the string with. The starting size of the string. Append additional canonicalized element to the string. An additional canonicalized element to append to the string. Converts the value of this instance to a string. A string whose value is the same as this instance. This class provides MemoryStream-like behavior but uses a list of buffers rather than a single buffer. The default small buffer size. The size of each buffer. The underlying buffer blocks for the stream. The currently used length. The total capacity of the stream. The current position. A reference to the IBufferManager for the stream to use to acquire and return buffers. Initializes a new instance of the MultiBufferMemoryStream class with provided IBufferManager. A reference to the IBufferManager for the stream to use to acquire and return buffers. May be null. The Buffer size to use for each block, default is 64 KB. Note this parameter is disregarded when a IBufferManager is specified. Reads a block of bytes from the current stream and writes the data to a buffer. When this method returns, the buffer contains the specified byte array with the values between offset and (offset + count - 1) replaced by the bytes read from the current source. The zero-based byte offset in buffer at which to begin storing the data read from the current stream. The maximum number of bytes to be read. The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero if the end of the stream has been reached. Begins an asynchronous read operation. When this method returns, the buffer contains the specified byte array with the values between offset and (offset + count - 1) replaced by the bytes read from the current source. The zero-based byte offset in buffer at which to begin storing the data read from the current stream. The maximum number of bytes to be read. An optional asynchronous callback, to be called when the read is complete. A user-provided object that distinguishes this particular asynchronous read request from other requests. An IAsyncResult that represents the asynchronous read, which could still be pending. Waits for the pending asynchronous read to complete. The reference to the pending asynchronous request to finish. The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero if the end of the stream has been reached. Sets the position within the current stream. A byte offset relative to the origin parameter. A value of type System.IO.SeekOrigin indicating the reference point used to obtain the new position. The new position within the current stream. Thrown if is invalid for SeekOrigin. Sets the length of the current stream to the specified value. (pre-allocating the bufferBlocks). The desired length of the current stream in bytes. If the is negative. Writes a block of bytes to the current stream using data read from a buffer. The buffer to write data from. The zero-based byte offset in buffer at which to begin copying bytes to the current stream. The number of bytes to write. Begins an asynchronous write operation. The buffer to write data from. The zero-based byte offset in buffer at which to begin copying bytes to the current stream. The number of bytes to write. An optional asynchronous callback, to be called when the write is complete. A user-provided object that distinguishes this particular asynchronous write request from other requests. An IAsyncResult that represents the asynchronous write, which could still be pending. Ends an asynchronous write operation. The reference to the pending asynchronous request to finish. Does not perform any operation as it's an in-memory stream. Reads the bytes from the current stream and writes them to another stream. However, this method eliminates copying the data into a temporary buffer by directly writing to the destination stream. The stream to which the contents of the current stream will be copied. DateTime indicating the expiry time. Begins an asynchronous fast-copy operation. The stream to which the contents of the current stream will be copied. DateTime indicating the expiry time. An optional asynchronous callback, to be called when the copy is complete. A user-provided object that distinguishes this particular asynchronous copy request from other requests. An IAsyncResult that represents the asynchronous copy, which could still be pending. Initiates a write operation for the next buffer in line. Internal StorageAsyncResult that represents the asynchronous copy. Callback method to be called when the corresponding write operation completes. The result of the asynchronous operation. Ends an asynchronous copy operation. The reference to the pending asynchronous request to finish. Computes the hash value for this stream. String representation of the computed hash value. Ensures that the amount of bufferBlocks is greater than or equal to the required size. Does not trim the size. The required size. If the is negative. Adds another block to the underlying bufferBlocks. Copies the specified amount of data from internal buffers to the buffer and advances the position. An array of bytes. When this method returns, the buffer contains the specified byte array with the values between offset and (offset + count - 1) replaced by the bytes read from the current source. The zero-based byte offset in buffer at which to begin storing the data read from the current stream. The maximum number of bytes to be read from the current stream. The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero (0) if the end of the stream has been reached. Writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written. (Requires the stream to be of sufficient size for writing). An array of bytes. This method copies count bytes from buffer to the current stream. The zero-based byte offset in buffer at which to begin copying bytes to the current stream. The number of bytes to be written to the current stream. Advances the current position of the stream and adjust the offset and remainder based on the amount completed. The current offset in the external buffer. The amount of data left to process. The amount of data processed. Advances the current position of the stream and adjust the remainder based on the amount completed. The amount of data left to process. The amount of data processed. Calculate the block for the current position. Gets a value indicating whether the current stream supports reading. Is true if the stream supports reading; otherwise, false. Gets a value indicating whether the current stream supports seeking. Is true if the stream supports seeking; otherwise, false. Gets a value indicating whether the current stream supports writing. Is true if the stream supports writing; otherwise, false. Gets the currently written length. Represents the current position in the stream. Thrown if position is outside the stream size A NullTaskReturn type. Represents a no-return from a task. Prevents a default instance of the class from being created. Provides a standard set of errors that could be thrown from the client library. This class provides APM Read/Write overrides for memory stream to improve performance. Initializes a new instance of the SyncMemoryStream class with an expandable capacity initialized to zero. Initializes a new non-resizable instance of the SyncMemoryStream class based on the specified byte array. The array of unsigned bytes from which to create the current stream. Initializes a new non-resizable instance of the SyncMemoryStream class based on the specified region (index) of a byte array. The array of unsigned bytes from which to create the current stream. The index into buffer at which the stream begins. Initializes a new non-resizable instance of the SyncMemoryStream class based on the specified region (index) of a byte array. The array of unsigned bytes from which to create the current stream. The index into buffer at which the stream begins. The length of the stream in bytes. Begins an asynchronous read operation. When this method returns, the buffer contains the specified byte array with the values between offset and (offset + count - 1) replaced by the bytes read from the current source. The zero-based byte offset in buffer at which to begin storing the data read from the current stream. The maximum number of bytes to be read. An optional asynchronous callback, to be called when the read is complete. A user-provided object that distinguishes this particular asynchronous read request from other requests. An IAsyncResult that represents the asynchronous read, which could still be pending. Waits for the pending asynchronous read to complete. The reference to the pending asynchronous request to finish. The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero if the end of the stream has been reached. Begins an asynchronous write operation. The buffer to write data from. The zero-based byte offset in buffer at which to begin copying bytes to the current stream. The number of bytes to write. An optional asynchronous callback, to be called when the write is complete. A user-provided object that distinguishes this particular asynchronous write request from other requests. An IAsyncResult that represents the asynchronous write, which could still be pending. Ends an asynchronous write operation. The reference to the pending asynchronous request to finish. A convenience class for constructing URI query strings. Initializes a new instance of the class. Initializes a new instance of the class that contains elements copied from the specified . The whose elements are copied to the new . Stores the query parameters. Add the value with URI escaping. The query name. The query value. Returns a containing the URI. A containing the URI. Adds a query parameter to a URI. The original URI, including any existing query parameters. The URI with the new query parameter appended. Adds a query parameter to a URI. The original URI, including any existing query parameters. The URI with the new query parameter appended. Contains helper methods for implementing shared access signatures. Get the complete query builder for creating the Shared Access Signature query. The shared access policy to hash. The optional header values to set for a blob returned with this SAS. An optional identifier for the policy. Either "b" for blobs or "c" for containers. The signature to use. The name of the key used to create the signature, or null if the key is implicit. The finished query builder. Get the complete query builder for creating the Shared Access Signature query. The shared access policy to hash. An optional identifier for the policy. The signature to use. The name of the key used to create the signature, or null if the key is implicit. The finished query builder. Get the complete query builder for creating the Shared Access Signature query. The shared access policy to hash. The name of the table associated with this shared access signature. An optional identifier for the policy. The start partition key, or null. The start row key, or null. The end partition key, or null. The end row key, or null. The signature to use. The name of the key used to create the signature, or null if the key is implicit. The finished query builder. Converts the specified value to either a string representation or . The value to convert. A string representing the specified value. Converts the specified value to either a string representation or null. The value to convert. A string representing the specified value. Escapes and adds the specified name/value pair to the query builder if it is not null. The builder to add the value to. The name of the pair. The value to be escaped. Parses the query. The query parameters. A boolean that represents whether SignedResource is part of Sas or not. True for blobs, False for Queues and Tables. Get the signature hash embedded inside the Shared Access Signature. The shared access policy to hash. An optional identifier for the policy. The canonical resource string, unescaped. The key value retrieved as an atomic operation used for signing. The signed hash. Get the signature hash embedded inside the Shared Access Signature. The shared access policy to hash. An optional identifier for the policy. The start partition key, or null. The start row key, or null. The end partition key, or null. The end row key, or null. The canonical resource string, unescaped. The key value retrieved as an atomic operation used for signing. The signed hash. Get the signature hash embedded inside the Shared Access Signature. The shared access policy to hash. The optional header values to set for a blob returned with this SAS. An optional identifier for the policy. The canonical resource string, unescaped. The key value retrieved as an atomic operation used for signing. The signed hash. Gets the value of the x-ms-date or Date header. The request where the value is read from. The value of the x-ms-date or Date header. Appends the value of the Content-Length header to the specified canonicalized string. The canonicalized string where the value is appended. The request where the value is read from. Appends the value of the Date header (or, optionally, the x-ms-date header) to the specified canonicalized string. The canonicalized string where the value is appended. The request where the value is read from. true if the value of the x-ms-date header can be used and is preferred; otherwise, false. Appends the values of the x-ms-* headers to the specified canonicalized string. The canonicalized string where the values are appended. The request where the values are read from. Gets the canonicalized header value to use for the specified date/time or null if it does not have a value. The date/time. The canonicalized header value to use for the specified date/time or null if it does not have a value. In case of path style, this method will strip off -secondary from absolute path and replace it with account name. The resource URI. The name of the storage account. Absolute path with no -secondary suffix. Gets the canonicalized resource string for the specified URI. The resource URI. The name of the storage account. true when using the Shared Key Lite authentication scheme or the table service; otherwise, false. The canonicalized resource string. Determines which location can the listing command target by looking at the continuation token. Continuation token Location mode Create an ExecutionState object that can be used for pre-request operations such as buffering user's data. Request options Temporary ExecutionState object Returns the larger of two time spans. The first of two time spans to compare. The second of two time spans to compare. Parameter or , whichever is larger. Gets the first header value or null if no header values exist. The type of header objects contained in the enumerable. An enumerable that contains header values. The first header value or null if no header values exist. Throws an exception if the string is empty or null. The name of the parameter. The value of the parameter. Thrown if value is empty. Thrown if value is null. Throw an exception if the value is null. The name of the parameter. The value of the parameter. Thrown if value is null. Throw an exception indicating argument is out of range. The name of the parameter. The value of the parameter. Throw an exception if the argument is out of bounds. The type of the value. The name of the parameter. The value of the parameter. The minimum value for the parameter. The maximum value for the parameter. Throw an exception if the argument is out of bounds. The type of the value. The name of the parameter. The value of the parameter. The minimum value for the parameter. Checks that the given timeout in within allowed bounds. The timeout to check. The timeout is not within allowed bounds. Combines AssertNotNullOrEmpty and AssertInBounds for convenience. The name of the parameter. Turns on or off null/empty checking. The value of the parameter. The maximum size of value. Rounds up to seconds. The time span. The time rounded to seconds. List of ports used for path style addressing. Determines if a URI requires path style addressing. The URI to check. Returns true if the Uri uses path style addressing; otherwise, false. Read the value of an element in the XML. The name of the element whose value is retrieved. A reader that provides access to XML data. A string representation of the element's value. Returns an enumerable collection of results that is retrieved lazily. The type of ResultSegment like Blob, Container, Queue and Table. The segment generator. >A non-negative integer value that indicates the maximum number of results to be returned in the result segment, up to the per-operation limit of 5000. Applies the request optimizations such as disabling buffering and 100 continue. The request to be modified. The length of the content, -1 if the content length is not settable. Increments the counter by one and thus sets the state of the event to non-signaled, causing threads to block. Decrements the counter by one. If the counter reaches zero, sets the state of the event to signaled, allowing one or more waiting threads to proceed. Blocks the current thread until the CounterEvent is set. Blocks the current thread until the CounterEvent is set, using a 32-bit signed integer to measure the timeout. The number of milliseconds to wait, or Infinite(-1) to wait indefinitely. true if the CounterEvent was set; otherwise, false. Releases all resources used by the current instance of the CounterEvent class. Gets a WaitHandle that is used to wait for the event to be set. A WaitHandle that is used to wait for the event to be set. Provides helper functions for http request/response processing. Parse the http query string. Http query string. Converts the DateTimeOffset object to an Http string of form: Sun, 28 Jan 2008 12:11:37 GMT. The DateTimeOffset object to convert to an Http string. String of form: Sun, 28 Jan 2008 12:11:37 GMT. Try to get the value of the specified header name. The Http web response from which to get the header value. The name of the header whose value is to be retrieved. The default value for the header that is returned if we can't get the actual header value. A string representing the header value. Wrapper class for MD5. Calculates an on-going hash using the input byte array. The input array used for calculating the hash. The offset in the input buffer to calculate from. The number of bytes to use from input. Retrieves the string representation of the hash. (Completes the creation of the hash). String representation of the computed hash value. Contains methods for dealing with navigation. The name of the root container. Used in address parsing. Used in address parsing. Used in address parsing. Used to split string on slash. Used to split hostname. Retrieves the container part of a storage Uri, or "$root" if the container is implicit. The blob address. If set to true use path style Uris. Name of the container. The trailing slash is always removed. GetContainerName(new Uri("http://test.blob.core.windows.net/mycontainer/myfolder/myblob")) will return "mycontainer" GetContainerName(new Uri("http://test.blob.core.windows.net/mycontainer/")) will return "mycontainer" GetContainerName(new Uri("http://test.blob.core.windows.net/myblob")) will return "$root" GetContainerName(new Uri("http://test.blob.core.windows.net/")) will throw ArgumentException Retrieves the blob part of a storage Uri. The blob address. If set to true use path style Uris. The name of the blob. Retrieves the complete container address from a storage Uri Example GetContainerAddress(new Uri("http://test.blob.core.windows.net/mycontainer/myfolder/myblob")) will return http://test.blob.core.windows.net/mycontainer. The blob address. True to use path style Uris. Uri of the container. Retrieves the parent name from a storage Uri. The blob address. The delimiter. If set to true use path style Uris. The name of the parent. Adds the trailing delimiter as the prefix returned by the storage REST api always contains the delimiter. GetParentName(new Uri("http://test.blob.core.windows.net/mycontainer/myfolder/myblob", "/")) will return "/mycontainer/myfolder/" GetParentName(new Uri("http://test.blob.core.windows.net/mycontainer/myfolder|myblob", "|") will return "/mycontainer/myfolder|" GetParentName(new Uri("http://test.blob.core.windows.net/mycontainer/myblob", "/") will return "/mycontainer/" GetParentName(new Uri("http://test.blob.core.windows.net/mycontainer/", "/") will return "/mycontainer/" Gets the service client base address. The address Uri. The use path style Uris. The base address of the client. GetServiceClientBaseAddress("http://testaccount.blob.core.windows.net/testcontainer/blob1") returns "http://testaccount.blob.core.windows.net" Gets the service client base address. The address Uri. The use path style Uris. The base address of the client. GetServiceClientBaseAddress("http://testaccount.blob.core.windows.net/testcontainer/blob1") returns "http://testaccount.blob.core.windows.net" Appends a path to a list of URIs correctly using "/" as separator. The base URI. The relative or absolute URI. The list of appended URIs. Appends a path to a list of URIs correctly using "/" as separator. The base URI. The relative or absolute URI. The separator. The list of appended URIs. Append a relative path to a URI, handling trailing slashes appropriately. The base URI. The relative or absolute URI. The appended Uri. Append a relative path to a URI, handling trailing slashes appropriately. The base URI. The relative or absolute URI. The separator. The appended Uri. Get container name from address for styles of paths Example: http://test.blob.core.windows.net/container/blob => container http://127.0.0.1:10000/test/container/blob => container. The container Uri. If set to true use path style Uris. The container name. Similar to getting container name from Uri. The queue Uri. If set to true use path style Uris. The queue name. Extracts a table name from the table's Uri. The queue Uri. If set to true use path style Uris. The queue name. Retrieve the container address and address. The blob address. True to use path style Uris. Name of the container. The container URI. true when the container is an explicit container. false, otherwise. Retrieve the container name and the blob name from a blob address. The blob address. If set to true use path style Uris. The resulting container name. The resulting blob name. A bool representing whether the blob is in an explicit container or not. Parses the snapshot time. The snapshot time. The parsed snapshot time. Parse Uri for SAS (Shared access signature) information. The complete Uri. The credentials to use. The parsed snapshot. The blob URI without credentials or snapshot info address Validate that no other query parameters are passed in. Any SAS information will be recorded as corresponding credentials instance. If credentials is passed in and it does not match the SAS information found, an exception will be thrown. Otherwise a new client is created based on SAS information or as anonymous credentials. Parse Uri for SAS (Shared access signature) information. The complete Uri. The credentials to use. The parsed snapshot. The blob URI without credentials or snapshot info address Validate that no other query parameters are passed in. Any SAS information will be recorded as corresponding credentials instance. If credentials is passed in and it does not match the SAS information found, an exception will be thrown. Otherwise a new client is created based on SAS information or as anonymous credentials. Parse Uri for SAS (Shared access signature) information. The complete Uri. The credentials to use. Validate that no other query parameters are passed in. Any SAS information will be recorded as corresponding credentials instance. If credentials is passed in and it does not match the SAS information found, an exception will be thrown. Otherwise a new client is created based on SAS information or as anonymous credentials. Parse Uri for SAS (Shared access signature) information. The complete Uri. The credentials to use. Validate that no other query parameters are passed in. Any SAS information will be recorded as corresponding credentials instance. If credentials is passed in and it does not match the SAS information found, an exception will be thrown. Otherwise a new client is created based on SAS information or as anonymous credentials. Represents a canonicalized string used in authenticating a request against the azure service. Provides properties to keep track of Md5 hash / Length of a stream as it is being copied. Provides stream helper methods that allow us to copy streams and measure the stream size. Reads synchronously the specified content of the stream and writes it to the given output stream. The origin stream. The destination stream. Number of bytes to copy from source stream to destination stream. Cannot be passed with a value for maxLength. Maximum length of the stream to write. true to calculate the MD5 hash. A boolean indicating whether the write happens synchronously. An object that stores state of the operation. State of the stream copy. stream Asynchronously reads the entire content of the stream and writes it to the given output stream. The result type of the ExecutionState The origin stream. The destination stream. Number of bytes to copy from source stream to destination stream. Cannot be passed with a value for maxLength. Maximum length of the source stream. Cannot be passed with a value for copyLength. Bool value indicating whether the Md5 should be calculated. An object that stores state of the operation. State of the stream copy. The action taken when the execution is completed. Represents a retry policy that performs a specified number of retries, using a randomized exponential back off scheme to determine the interval between retries. Represents a retry policy. Represents a retry policy. Generates a new retry policy for the current request attempt. An object that represents the retry policy for the current request attempt. Determines whether the operation should be retried and the interval until the next retry. The number of retries for the given operation. A value of zero signifies this is the first error encountered. The status code for the last operation. An object that represents the last exception encountered. The interval to wait until the next retry. An object for tracking the current operation. true if the operation should be retried; otherwise, false. Determines whether the operation should be retried and the interval until the next retry. A object that indicates the number of retries, the results of the last request, and whether the next retry should happen in the primary or secondary location, and specifies the location mode. An object for tracking the current operation. A object that indicates the location mode, and whether the next retry should happen in the primary or secondary location. If null, the operation will not be retried. Initializes a new instance of the class. Initializes a new instance of the class using the specified delta and maximum number of retries. The back off interval between retries. The maximum number of retry attempts. Determines whether the operation should be retried and the interval until the next retry. The number of retries for the given operation. A value of zero signifies this is the first error encountered. The status code for the last operation. An object that represents the last exception encountered. The interval to wait until the next retry. An object for tracking the current operation. true if the operation should be retried; otherwise, false. Determines whether the operation should be retried and the interval until the next retry. A object that indicates the number of retries, the results of the last request, and whether the next retry should happen in the primary or secondary location, and specifies the location mode. An object for tracking the current operation. A object that indicates the location mode, and whether the next retry should happen in the primary or secondary location. If null, the operation will not be retried. Generates a new retry policy for the current request attempt. An object that represents the retry policy for the current request attempt. Represents a retry policy that performs a specified number of retries, using a specified fixed time interval between retries. Initializes a new instance of the class. Initializes a new instance of the class using the specified delta and maximum number of retries. The back off interval between retries. The maximum number of retry attempts. Determines whether the operation should be retried and the interval until the next retry. The number of retries for the given operation. A value of zero signifies this is the first error encountered. The status code for the last operation. An object that represents the last exception encountered. The interval to wait until the next retry. An object for tracking the current operation. true if the operation should be retried; otherwise, false. Determines whether the operation should be retried and the interval until the next retry. A object that indicates the number of retries, the results of the last request, and whether the next retry should happen in the primary or secondary location, and specifies the location mode. An object for tracking the current operation. A object that indicates the location mode, and whether the next retry should happen in the primary or secondary location. If null, the operation will not be retried. Generates a new retry policy for the current request attempt. An object that represents the retry policy for the current request attempt. Specifies the location mode used to decide which location the request should be sent to. Requests should always be sent to the primary location. Requests should always be sent to the primary location first. If the request fails, it should be sent to the secondary location. Requests should always be sent to the secondary location. Requests should always be sent to the secondary location first. If the request fails, it should be sent to the primary location. Represents a retry policy that performs no retries. Initializes a new instance of the class. Determines if the operation should be retried and how long to wait until the next retry. The number of retries for the given operation. A value of zero signifies this is the first error encountered. The status code for the last operation. An object that represents the last exception encountered. The interval to wait until the next retry. An object for tracking the current operation. true if the operation should be retried; otherwise, false. Generates a new retry policy for the current request attempt. An object that represents the retry policy for the current request attempt. Represents the context for one or more retries of a request made against the Windows Azure storage services, including the number of retries made for the request, the results of the last request, and the storage location and location mode for subsequent retries. Returns a string that represents the current instance. A string that represents the current instance. Gets the target location for the next retry. The target location for the next retry. Gets the location mode for subsequent retries. The location mode for subsequent retries. Gets the number of retries for the given operation. The number of retries for the given operation. Gets the results of the last request. A object that represents the results of the last request. Specifies parameters for the next retry of a request to be made against the Windows Azure storage services, including the target location and location mode for the next retry and the interval until the next retry. Initializes a new instance of the class. Initializes a new instance of the class. The object that was passed in to the retry policy. Returns a string that represents the current instance. A string that represents the current instance. Gets or sets the target location for the next retry. The target location for the next retry. Gets or sets the location mode for subsequent retries. The location mode for subsequent retries. Gets the interval until the next retry. The interval until the next retry. Verifies that the blob is not a snapshot. Gets the blob's system properties. The blob's properties. Gets the user-defined metadata for the blob. The blob's metadata, as a collection of name-value pairs. Gets the blob's URI for the primary location. The absolute URI to the blob, at the primary location. Gets the list of URIs for all locations. The list of URIs for all locations. Gets the date and time that the blob snapshot was taken, if this blob is a snapshot. The blob's snapshot time if the blob is a snapshot; otherwise, null. If the blob is not a snapshot, the value of this property is null. Gets the state of the most recent or pending copy operation. A object containing the copy state, or null if no copy blob state exists for this blob. Represents the permissions for a container. Initializes a new instance of the class. Gets or sets the public access setting for the container. The public access setting for the container. Gets the set of shared access policies for the container. The set of shared access policies for the container. Represents the system properties for a container. Gets the ETag value for the container. The container's quoted ETag value. Gets the container's last-modified time. The container's last-modified time. Gets the container's lease status. A object that indicates the container's lease status. Gets the container's lease state. A object that indicates the container's lease state. Gets the container's lease duration. A object that indicates the container's lease duration. Specifies the level of public access that is allowed on the container. No public access. Only the account owner can read resources in this container. Container-level public access. Anonymous clients can read container and blob data. Blob-level public access. Anonymous clients can read blob data within this container, but not container data. Represents a continuation token for listing operations. continuation tokens are used in methods that return a object, such as . Gets an XML representation of an object. An that describes the XML representation of the object that is produced by the method and consumed by the method. Generates a serializable continuation token from its XML representation. The stream from which the continuation token is deserialized. Converts a serializable continuation token into its XML representation. The stream to which the continuation token is serialized. Gets or sets the version for continuing results for enumeration operations. The version. Gets or sets the type element (blob, queue, table) for continuing results for enumeration operations. The type element. Gets or sets the next marker for continuing results for enumeration operations. The next marker. Gets or sets the storage location that the continuation token applies to. The storage location that the continuation token applies to. Specifies which items to include when listing a set of blobs. List only committed blobs, and do not return blob metadata. List committed blobs and blob snapshots. Retrieve blob metadata for each blob returned in the listing. List committed and uncommitted blobs. Include copy properties in the listing. List all available committed blobs, uncommitted blobs, and snapshots, and return all metadata and copy status for those blobs. Represents the system properties for a blob. Initializes a new instance of the class. Initializes a new instance of the class based on an existing instance. The set of properties to clone. Lease-related properties will not be cloned, because a lease associated with the base blob is not copied to the snapshot. Gets or sets the cache-control value stored for the blob. The blob's cache-control value. Gets or sets the content-disposition value stored for the blob. The blob's content-disposition value. If this property has not been set for the blob, it returns null. Gets or sets the content-encoding value stored for the blob. The blob's content-encoding value. If this property has not been set for the blob, it returns null. Gets or sets the content-language value stored for the blob. The blob's content-language value. If this property has not been set for the blob, it returns null. Gets the size of the blob, in bytes. The blob's size in bytes. Gets or sets the content-MD5 value stored for the blob. The blob's content-MD5 hash. Gets or sets the content-type value stored for the blob. The blob's content-type value. If this property has not been set for the blob, it returns null. Gets the blob's ETag value. The blob's ETag value. Gets the the last-modified time for the blob, expressed as a UTC value. The blob's last-modified time, in UTC format. Gets the type of the blob. A object that indicates the type of the blob. Gets the blob's lease status. A object that indicates the blob's lease status. Gets the blob's lease state. A object that indicates the blob's lease state. Gets the blob's lease duration. A object that indicates the blob's lease duration. If the blob is a page blob, gets the blob's current sequence number. The blob's current sequence number. Represents a set of timeout and retry policy options that may be specified for a request against the Blob service. Stores the parallelism factor. Default is 32 MB. Initializes a new instance of the class. Clones an instance of BlobRequestOptions so that we can apply defaults. BlobRequestOptions instance to be cloned. Gets or sets the absolute expiry time across all potential retries for the request. Gets or sets the retry policy. The retry policy. Gets or sets the location mode of the request. The location mode of the request. Gets or sets the server timeout interval for the request. The server timeout interval for the request. Gets or sets the maximum execution time across all potential retries for the request. A representing the maximum execution time for retries for the request. Gets or sets the number of blocks that may be simultaneously uploaded when uploading a blob that is greater than the value specified by the property in size. The number of parallel operations that may proceed. Gets or sets the maximum size of a blob in bytes that may be uploaded as a single blob. The maximum size of a blob, in bytes, that may be uploaded as a single blob, ranging from between 1 and 64 MB inclusive. Gets or sets a value to calculate and send/validate content MD5 for transactions. Use true to calculate and send/validate content MD5 for transactions; otherwise, false. Gets or sets a value to indicate that an MD5 hash will be calculated and stored when uploading a blob. Use true to calculate and store an MD5 hash when uploading a blob; otherwise, false. Gets or sets a value to indicate that MD5 validation will be disabled when downloading blobs. Use true to disable MD5 validation; false to enable MD5 validation. Represents a segment of results, with continuation information for pagination scenarios. Gets an enumerable collection of results. An enumerable collection of results. Gets the continuation token used to retrieve the next segment of results. Returns null if there are no more results. The continuation token. The type of a blob. Not specified. A page blob. A block blob. Indicates whether to list only committed blocks, only uncommitted blocks, or all blocks. Committed blocks. Uncommitted blocks. Both committed and uncommitted blocks. Indicates which block lists should be searched to find a specified block. Search the committed block list only. Search the uncommitted block list only. Search the uncommitted block list first, and if the block is not found there, search the committed block list. Specifies which details to include when listing the containers in this storage account. No additional details. Retrieve container metadata. Retrieve all available details. Represents a segment of results and contains continuation and pagination information. Gets an enumerable collection of results. An enumerable collection of results. Gets the continuation token used to retrieve the next segment of results. The continuation token. Represents the attributes of a copy operation. Gets the ID of the copy operation. A copy ID string. Gets the time the copy operation completed, and indicates whether completion was due to a successful copy, the cancelling of the operation, or a failure. A containing the completion time, or null if the operation has not completed. Gets the status of the copy operation. A enumeration indicating the status of the operation. Gets the source URI of a copy operation. A indicating the source of a copy operation, or null. Gets the number of bytes copied in the operation so far. The number of bytes copied in the operation so far, or null. Gets the total number of bytes in the source of the copy. The number of bytes in the source, or null. Gets the description of the current status, if any. A status description string, or null. Represents the status of a copy blob operation. The copy status is invalid. The copy operation is pending. The copy operation succeeded. The copy operation has been aborted. The copy operation encountered an error. The set of options describing delete operation. Delete blobs but not snapshots. Delete the blob and its snapshots. Delete the blob's snapshots only. Describes actions that can be performed on a lease. Acquire the lease. Renew the lease. Release the lease. Break the lease. Change the lease ID. The lease duration of a resource. The lease duration is not specified. The lease duration is finite. The lease duration is infinite. The lease state of a resource. The lease state is not specified. The lease is in the Available state. The lease is in the Leased state. The lease is in the Expired state. The lease is in the Breaking state. The lease is in the Broken state. The lease status of a resource. The lease status is not specified. The resource is locked. The resource is available to be locked. Represents a block retrieved from the blob's block list. Gets the name of the block. The block name. Gets the size of block in bytes. The block size. Gets a value indicating whether or not the block has been committed. True if the block has been committed; otherwise, false. Represents a range of pages in a page blob. Initializes a new instance of the class. The starting offset. The ending offset. Returns the content of the page range as a string. The content of the page range. Gets the starting offset of the page range. The starting offset. Gets the ending offset of the page range. The ending offset. Describes actions that can be performed on a page blob sequence number. Sets the sequence number to be the higher of the value included with the request and the value currently stored for the blob. Sets the sequence number to the value included with the request. Increments the value of the sequence number by 1. Represents the optional headers that can be returned with blobs accessed using SAS. Initializes a new instance of the class. Initializes a new instance of the class based on an existing instance. The set of to clone. Gets or sets the cache-control header returned with the blob. The cache-control value. Gets or sets the content-disposition header returned with the blob. The content-disposition value. Gets or sets the content-encoding header returned with the blob. The content-encoding value. Gets or sets the content-language header returned with the blob. The content-language value. Gets or sets the content-type header returned with the blob. The content-type value. Specifies the set of possible permissions for a shared access policy. No shared access granted. Read access granted. Write access granted. Delete access granted for blobs. List access granted. Represents the collection of shared access policies defined for a container. Adds the specified key and value to the collection of shared access policies. The key of the value to add. The value to add the collection of shared access policies. Determines whether the collection of shared access policies contains the specified key. The key to locate in the collection of shared access policies. true if the collection of shared access policies contains an element with the specified key; otherwise, false. Removes the value with the specified key from the shared access policies collection. The key of the item to remove. true if the element is successfully found and removed; otherwise, false. This method returns false if the key is not found. Gets the item associated with the specified key. The key of the value to get. The item to get. The item associated with the specified key, if the key is found; otherwise, the default value for the type. Adds the specified key/ value, stored in a , to the collection of shared access policies. The object, containing a key/ value pair, to add to the shared access policies collection. Removes all keys and values from the shared access collection. Determines whether the collection of shared access policies contains the key and value in the specified object. A object containing the key and value to search for. true if the shared access policies collection contains the specified key/value; otherwise, false. Copies each key/ value pair in the shared access policies collection to a compatible one-dimensional array, starting at the specified index of the target array. The one-dimensional array of objects that is the destination of the elements copied from the shared access policies collection. The zero-based index in at which copying begins. Removes the value, specified in the object, from the shared access policies collection. The object, containing a key and value, to remove from the shared access policies collection. true if the item was successfully removed; otherwise, false. Returns an enumerator that iterates through the collection of shared access policies. An of type . Returns an enumerator that iterates through the collection of shared access policies. An object that can be used to iterate through the collection of shared access policies. Gets a collection containing the keys in the shared access policies collection. A collection containing the keys in the of shared access policies collection. Gets a collection containing the values in the shared access policies collection. A collection of items in the shared access policies collection. Gets or sets the item associated with the specified key. The key of the value to get or set. The item associated with the specified key, or null if key is not in the shared access policies collection. Gets the number of key/ value pairs contained in the shared access policies collection. The number of key/ value pairs contained in the shared access policies collection. Gets a value indicating whether the collection of shared access policies is read-only. true if the collection of shared access policies is read-only; otherwise, false. Represents a shared access policy, which specifies the start time, expiry time, and permissions for a shared access signature. Initializes a new instance of the class. Converts the permissions specified for the shared access policy to a string. The shared access permissions. The shared access permissions in string format. Constructs a object from a permissions string. The shared access permissions in string format. A set of shared access permissions. Gets or sets the start time for a shared access signature associated with this shared access policy. The shared access start time. Gets or sets the expiry time for a shared access signature associated with this shared access policy. The shared access expiry time. Gets or sets the permissions for a shared access signature associated with this shared access policy. The permissions. Parses the response XML from an operation to set the access policy for a container. Parses the response XML from an operation to set the access policy for a cloud object. The policy type to be filled. Provides a base class that is used internally to parse XML streams from storage service operations. The type to be parsed. Indicates that all parsable objects have been consumed. This field is reserved and should not be used. Stores any objects that have not yet been parsed. This field is reserved and should not be used. The reader used for parsing. This field is reserved and should not be used. The IEnumerator over the parsed content. Used to make sure that parsing is only done once, since a stream is not re-entrant. Initializes a new instance of the ResponseParsingBase class. The stream to be parsed. Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. Parses the XML response. This method is reserved and should not be used. A collection of enumerable objects. Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources, and optional managed resources. True to release both managed and unmanaged resources; otherwise, false. This method is reserved and should not be used. True when the object is consumable. Parses the XML and close. A list of parsed results. Gets the parsable objects. This method is reserved and should not be used. The objects to parse. Initializes a new instance of the AccessPolicyResponseBase class. The stream to be parsed. Parses the current element. The shared access policy element to parse. The shared access policy. Parses the response XML from a Set Container ACL operation to retrieve container-level access policy data. A list of enumerable key-value pairs. Gets an enumerable collection of container-level access policy identifiers. An enumerable collection of container-level access policy identifiers. Initializes a new instance of the BlobAccessPolicyResponse class. The stream to be parsed. Parses the current element. The shared access policy element to parse. The shared access policy. Represents a container item returned in the XML response for a container listing operation. Initializes a new instance of the class. Gets the user-defined metadata for the container. The container's metadata, as a collection of name-value pairs. Gets the container's system properties. The container's properties. Gets the name of the container. The container's name. Gets the container's URI. The absolute URI to the container. Provides error code strings that are specific to the Blob service. Error code that may be returned when a block ID is invalid. Error code that may be returned when a blob with the specified address cannot be found. Error code that may be returned when a client attempts to create a blob that already exists. Error code that may be returned when the specified block or blob is invalid. Error code that may be returned when a block list is invalid. The specified container was not found. The specified container already exists. The specified container is disabled. The specified container is being deleted. Error code that may be returned when there is currently no lease on the blob. Error code that may be returned when there is currently no lease on the container. Error code that may be returned when a lease ID was specified, but the lease has expired. Error code that may be returned when the lease ID specified did not match the lease ID for the blob. Error code that may be returned when the lease ID specified did not match the lease ID for the container. Error code that may be returned when there is currently a lease on the resource and no lease ID was specified in the request. Error code that may be returned when there is currently no lease on the resource. Error code that may be returned when the lease ID specified did not match the lease ID. Error code that may be returned when there is already a lease present. Error code that may be returned when the lease has already been broken and cannot be broken again. Error code that may be returned when the lease ID matched, but the lease has been broken explicitly and cannot be renewed. Error code that may be returned when the lease ID matched, but the lease is breaking and cannot be acquired. Error code that may be returned when the lease ID matched, but the lease is breaking and cannot be changed. Error code that may be returned when the copy ID specified in an Abort Copy operation does not match the current pending copy ID. Error code that may be returned when an Abort Copy operation is called when there is no pending copy. Error code that may be returned when an attempt to modify the destination of a pending copy is made. Error code that may be returned when the source of a copy cannot be accessed. Error code that may be returned when the destination of a copy operation has a lease of fixed duration. Provides a set of parameters for a blob listing operation. Represents the listing context for enumeration operations. Initializes a new instance of the class. The resource name prefix. The maximum number of resources to return in a single operation, up to the per-operation limit of 5000. Gets or sets the Prefix value. The Prefix value. Gets or sets the MaxResults value. The MaxResults value. Gets or sets the Marker value. The Marker value. Initializes a new instance of the class. The blob prefix. The maximum number of results to return. The blob delimiter. The include parameter. Gets or sets the delimiter for a blob listing operation. The delimiter to use to traverse the virtual hierarchy of blobs. The delimiter parameter enables the caller to traverse the blob namespace by using a user-configured delimiter. Using this parameter, it is possible to traverse a virtual hierarchy of blobs as though it were a file system. Gets or sets the details for the listing operation, which indicates the types of data to include in the response. The details to include in the listing operation. The include parameter specifies that the response should include one or more of the following subsets: snapshots, metadata, uncommitted blobs. Provides a set of helper methods for constructing a request against the Blob service. Converts the date time to snapshot string. The date time. The converted string. Writes a collection of shared access policies to the specified stream in XML format. A collection of shared access policies. An output stream. Writes the body of the block list to the specified stream in XML format. An enumerable collection of objects. The stream to which the block list is written. Provides methods for parsing the response from an operation to return a block list. Initializes a new instance of the class. The stream to be parsed. Reads a block item for block listing. Whether we are currently listing committed blocks or not Block listing entry Parses the XML response returned by an operation to retrieve a list of blocks. An enumerable collection of objects. Gets an enumerable collection of objects from the response. An enumerable collection of objects. Provides methods for parsing the response from an operation to get a range of pages for a page blob. Initializes a new instance of the class. The stream of page ranges to be parsed. Reads a page range. Page range entry Parses the XML response for an operation to get a range of pages for a page blob. An enumerable collection of objects. Gets an enumerable collection of objects from the response. An enumerable collection of objects. Represents an item that may be returned by a blob listing operation. Represents a blob item returned in the XML response for a blob listing operation. Initializes a new instance of the class. The name of the blob. The blob's attributes. Stores the blob item's attributes. Gets the name of the blob item. The name of the blob item. Gets the blob item's system properties. The blob item's properties. Gets the user-defined metadata for the blob item. The blob item's metadata, as a collection of name-value pairs. Gets the blob item's URI. The absolute URI to the blob item. Gets the date and time that the blob snapshot was taken, if this blob is a snapshot. The blob's snapshot time if the blob is a snapshot; otherwise, null. If the blob is not a snapshot, the value of this property is null. Gets the state of the most recent or pending copy operation. A object containing the copy state, or null if no copy blob state exists for this blob. Represents the blob name prefix that is returned in the XML response for a blob listing operation. Gets the blob name prefix. The blob name prefix. Provides methods for parsing the response from a blob listing operation. Stores the blob prefix. Signals when the blob prefix can be consumed. Stores the marker. Signals when the marker can be consumed. Stores the blob delimiter. Signals when the blob delimiter can be consumed. Stores the max results. Signals when the max results can be consumed. Stores the next marker. Signals when the next marker can be consumed. Initializes a new instance of the class. The stream to be parsed. Parses a blob entry in a blob listing response. Blob listing entry Parses a blob prefix entry in a blob listing response. Blob listing entry Parses the response XML for a blob listing operation. An enumerable collection of objects that implement . Gets the listing context from the XML response. A set of parameters for the listing operation. Gets an enumerable collection of objects that implement from the response. An enumerable collection of objects that implement . Gets the Prefix value provided for the listing operation from the XML response. The Prefix value. Gets the Marker value provided for the listing operation from the XML response. The Marker value. Gets the Delimiter value provided for the listing operation from the XML response. The Delimiter value. Gets the MaxResults value provided for the listing operation from the XML response. The MaxResults value. Gets the NextMarker value from the XML response, if the listing was not complete. The NextMarker value. Provides methods for parsing the response from a container listing operation. Stores the container prefix. Signals when the container prefix can be consumed. Stores the marker. Signals when the marker can be consumed. Stores the max results. Signals when the max results can be consumed. Stores the next marker. Signals when the next marker can be consumed. Initializes a new instance of the class. The stream to be parsed. Reads a container entry completely including its properties and metadata. Container listing entry Parses the response XML for a container listing operation. An enumerable collection of objects. Gets the listing context from the XML response. A set of parameters for the listing operation. Gets an enumerable collection of objects from the response. An enumerable collection of objects. Gets the Prefix value provided for the listing operation from the XML response. The Prefix value. Gets the Marker value provided for the listing operation from the XML response. The Marker value. Gets the MaxResults value provided for the listing operation from the XML response. The MaxResults value. Gets the NextMarker value from the XML response, if the listing was not complete. The NextMarker value. Describes actions that may be used for writing to a page blob or clearing a set of pages. Update the page with new data. Clear the page. Represents a block in a block list. Initializes a new instance of the class. The block ID. One of the enumeration values that specifies in which block lists to search for the block. Gets the block ID. The block ID. Gets a value that indicates which block lists to search for the block. One of the enumeration values that specifies in which block lists to search for the block. Enumeration controlling the options for updating queue messages. Update the message visibility timeout. Update the message content. Represents a continuation token returned by the Queue service. continuation tokens are used in methods that return a object, such as . Gets an XML representation of an object. An that describes the XML representation of the object that is produced by the method and consumed by the method. Generates a serializable continuation token from its XML representation. The stream from which the continuation token is deserialized. Converts a serializable continuation token into its XML representation. The stream to which the continuation token is serialized. Gets or sets the version for continuing results for CloudQueue enumeration operations. The version. Gets or sets the type element (blob, queue, table) for continuing results for CloudQueue enumeration operations. The type element. Gets or sets the NextMarker for continuing results for CloudQueue enumeration operations. The next marker. Gets or sets the storage location that the continuation token applies to. The storage location that the continuation token applies to. Enum for Queue message type. Internal use only. Indicates the message object stores the raw text string. Indicates the message object stores the Base64-Encoded representation of the raw data. Represents a set of timeout and retry policy options that may be specified for a request against the Queue service. Initializes a new instance of the class. Clones an instance of QueueRequestOptions so that we can apply defaults. QueueRequestOptions instance to be cloned. Gets or sets the absolute expiry time across all potential retries for the request. Gets or sets the retry policy for the request. The retry policy delegate. Gets or sets the location mode of the request. The location mode of the request. Gets or sets the server timeout for the request. The client and server timeout interval for the request. Gets or sets the maximum execution time across all potential retries for the request. A representing the maximum execution time for retries for the request. Represents a segment of results, with continuation information for pagination scenarios. Gets an enumerable collection of results. An enumerable collection of results. Gets the continuation token used to retrieve the next segment of results. Returns null if there are no more results. The continuation token. Specifies the set of possible permissions for a shared access queue policy. No shared access granted. Permission to peek messages and get queue metadata granted. Permission to add messages granted. Permissions to update messages granted. Permission to get and delete messages granted. Represents the collection of shared access policies defined for a queue. Adds the specified key and value to the collection of shared access policies. The key of the value to add. The value to add the collection of shared access policies. Determines whether the collection of shared access policies contains the specified key. The key to locate in the collection of shared access policies. true if the collection of shared access policies contains an element with the specified key; otherwise, false. Removes the value with the specified key from the shared access policies collection. The key of the item to remove. true if the element is successfully found and removed; otherwise, false. This method returns false if the key is not found. Gets the item associated with the specified key. The key of the value to get. The item to get. The item associated with the specified key, if the key is found; otherwise, the default value for the type. Adds the specified key/ value, stored in a , to the collection of shared access policies. The object, containing a key/ value pair, to add to the shared access policies collection. Removes all keys and values from the shared access collection. Determines whether the collection of shared access policies contains the key and value in the specified object. A object containing the key and value to search for. true if the shared access policies collection contains the specified key/value; otherwise, false. Copies each key/ value pair in the shared access policies collection to a compatible one-dimensional array, starting at the specified index of the target array. The one-dimensional array of objects that is the destination of the elements copied from the shared access policies collection. The zero-based index in at which copying begins. Removes the value, specified in the object, from the shared access policies collection. The object, containing a key and value, to remove from the shared access policies collection. true if the item was successfully removed; otherwise, false. Returns an enumerator that iterates through the collection of shared access policies. An of type . Returns an enumerator that iterates through the collection of shared access policies. An object that can be used to iterate through the collection of shared access policies. Gets a collection containing the keys in the shared access policies collection. A collection containing the keys in the of shared access policies collection. Gets a collection containing the values in the shared access policies collection. A collection of items in the shared access policies collection. Gets or sets the item associated with the specified key. The key of the value to get or set. The item associated with the specified key, or null if key is not in the shared access policies collection. Gets the number of key/ value pairs contained in the shared access policies collection. The number of key/ value pairs contained in the shared access policies collection. Gets a value indicating whether the collection of shared access policies is read-only. true if the collection of shared access policies is read-only; otherwise, false. Represents a shared access policy for a queue, which specifies the start time, expiry time, and permissions for a shared access signature. Initializes a new instance of the SharedAccessQueuePolicy class. Converts the permissions specified for the shared access policy to a string. The shared access permissions. The shared access permissions in string format. Constructs a object from a permissions string. The shared access permissions in string format. A set of shared access permissions. Gets or sets the start time for a shared access signature associated with this shared access policy. The shared access start time. Gets or sets the expiry time for a shared access signature associated with this shared access policy. The shared access expiry time. Gets or sets the permissions for a shared access signature associated with this shared access policy. The permissions. Provides methods for parsing the response from an operation to get messages from a queue. Initializes a new instance of the class. The stream of messages to parse. Parses a message entry in a queue get messages response. Message entry Parses the XML response returned by an operation to get messages from a queue. An enumerable collection of objects. Gets an enumerable collection of objects from the response. An enumerable collection of objects. Provides methods for parsing the response from a queue listing operation. Stores the container prefix. Signals when the container prefix can be consumed. Stores the marker. Signals when the marker can be consumed. Stores the max results. Signals when the max results can be consumed. Stores the next marker. Signals when the next marker can be consumed. Initializes a new instance of the class. The stream to be parsed. Parses a queue entry in a queue listing response. Queue listing entry Parses the response XML for a queue listing operation. An enumerable collection of objects. Gets the listing context from the XML response. A set of parameters for the listing operation. Gets an enumerable collection of objects from the response. An enumerable collection of objects. Gets the Prefix value provided for the listing operation from the XML response. The Prefix value. Gets the Marker value provided for the listing operation from the XML response. The Marker value. Gets the MaxResults value provided for the listing operation from the XML response. The MaxResults value. Gets the NextMarker value from the XML response, if the listing was not complete. The NextMarker value. Parses the response XML from an operation to set the access policy for a queue. Initializes a new instance of the QueueAccessPolicyResponse class. The stream to be parsed. Parses the current element. The shared access policy element to parse. The shared access policy. Represents a queue item returned in the XML response for a queue listing operation. Initializes a new instance of the class. Initializes a new instance of the class. The name of the queue. The Uri of the queue. The queue's metadata. Gets the user-defined metadata for the queue. The queue's metadata, as a collection of name-value pairs. Gets the name of the queue. The queue's name. Gets the queue's URI. The absolute URI to the queue. Provides error code strings that are specific to the Queue service. Error code that may be returned when the specified queue was not found. Error code that may be returned when the specified queue is disabled. Error code that may be returned when the specified queue already exists. Error code that may be returned when the specified queue is not empty. Error code that may be returned when the specified queue is being deleted. Error code that may be returned when the specified pop receipt does not match. Error code that may be returned when one or more request parameters are invalid. Error code that may be returned when the specified message was not found. Error code that may be returned when the specified message is too large. Error code that may be returned when the specified marker is invalid. Provides a set of parameters for a queue listing operation. Initializes a new instance of the class. The queue prefix. The maximum number of results to return. The include parameter. Gets or sets the details for the listing operation, which indicates the types of data to include in the response. The details to include in the listing operation. Specifies which details to include when listing the queues in this storage account. No additional details. Retrieve queue metadata. Retrieve all available details. Represents a message retrieved from a queue. Initializes a new instance of the class. Gets the message expiration time. The message expiration time. Gets the message ID. The message ID. Gets the time the message was added to the queue. The message insertion time. Gets the time the message is next visible. The time the message is next visible. Gets the pop receipt for the message. The message's pop receipt. Gets the text of the message. The message text. Gets the number of times this message has been dequeued. The dequeue count. Represents the permissions for a queue. Initializes a new instance of the class. Gets the set of shared access policies for the queue. The set of shared access policies for the queue. Provides a set of helper methods for constructing a request against the Queue service. Writes a collection of shared access policies to the specified stream in XML format. A collection of shared access policies. An output stream. Writes a message to the specified stream in XML format. The message body. An output stream. Gets or sets the number of entities the table query will return. The maximum number of entities for the table query to return. Gets or sets the filter expression to use in the table query. A string containing the filter expression to use in the query. Gets or sets the property names of the table entity properties to return when the table query is executed. A list of strings containing the property names of the table entity properties to return when the query is executed. Provides a set of extension methods for objects of type . Specifies a set of on the query. The entity type of the query. A query that implements . A object that specifies execution options, such as retry policy and timeout settings, for the operation. A object with the specified request options set. Specifies an for the query. The entity type of the query. A query that implements . An object for tracking the current operation. A object with the specified operation context. Specifies an entity resolver for the query. The entity type of the query. The type of the resolver. A query that implements . The entity resolver, of type . A with the specified resolver. Specifies that a query be returned as a object. The entity type of the query. A query that implements . An object of type . A type which allows callers direct access to the property map of the entity. This class eliminates the use of reflection for serialization and deserialization. An interface required for table entity types. The interface declares getter and setter methods for the mandatory entity properties, and and methods for serialization and de-serialization of all entity properties using a property dictionary. Create classes implementing to customize property storage, retrieval, serialization and de-serialization, and to provide additional custom logic for a table entity. The storage client library includes two implementations of that provide for simple property access and serialization: implements and provides a simple property dictionary to store and retrieve properties. Use a for simple access to entity properties when only a subset of properties are returned (for example, by a select clause in a query), or for scenarios where your query can return multiple entity types with different properties. You can also use this type to perform bulk table updates of heterogeneous entities without losing property information. is an implementation of that uses reflection-based serialization and de-serialization behavior in its and methods. -derived classes with methods that follow a convention for types and naming are serialized and deserialized automatically. -derived classes must also provide a get-able and set-able public property of a type that is supported by the Windows Azure Table service. Populates the entity's properties from the data values in the dictionary. The dictionary of string property names to data values to deserialize and store in this table entity instance. An object used to track the execution of the operation. Serializes the of property names mapped to data values from the entity instance. An object used to track the execution of the operation. A dictionary of property names to data typed values created by serializing this table entity instance. Gets or sets the entity's partition key. The entity's partition key. Gets or sets the entity's row key. The entity's row key. Gets or sets the entity's timestamp. The entity's timestamp. The property is populated by the Windows Azure Table Service. Gets or sets the entity's current ETag. Set this value to '*' in order to blindly overwrite an entity as part of an update operation. The entity's timestamp. Initializes a new instance of the class. Initializes a new instance of the class with the specified partition key and row key. The partition key value for the entity. The row key value for the entity. Initializes a new instance of the class with the entity's partition key, row key, ETag (if available/required), and properties. The entity's partition key. The entity's row key. The entity's current ETag. The entity's properties, indexed by property name. Initializes a new instance of the class with the entity's partition key, row key, timestamp, ETag (if available/required), and properties. The entity's partition key. The entity's row key. The timestamp for this entity as returned by Windows Azure. The entity's current ETag; set to null to ignore the ETag during subsequent update operations. An containing a map of property names to data typed values to store in the new . Deserializes this instance using the specified of property names to values of type . A collection containing the of string property names mapped to values of type to store in this instance. An object used to track the execution of the operation. Serializes the of property names mapped to values of type from this instance. An object used to track the execution of the operation. A collection containing the map of string property names to values of type stored in this instance. Gets or sets the properties in the table entity, indexed by property name. The entity properties. Gets or sets the entity's partition key. The entity partition key. Gets or sets the entity's row key. The entity row key. Gets or sets the entity's timestamp. The entity timestamp. Gets or sets the entity's current ETag. Set this value to '*' to blindly overwrite an entity as part of an update operation. The entity ETag. Gets or sets the entity's property, given the name of the property. The name of the property. The property. Enumeration containing the types of values that can be stored in a table entity property. Represents fixed- or variable-length character data. Represents fixed- or variable-length binary data. Represents the mathematical concept of binary-valued logic. Represents date and time. Represents a floating point number with 15 digits precision that can represent values with approximate range of +/- 2.23e -308 through +/- 1.79e +308. Represents a 16-byte (128-bit) unique identifier value. Represents a signed 32-bit integer value. Represents a signed 64-bit integer value. Class for storing information about a single property in an entity in a table. Creates a new object that represents the specified offset value. The value for the new . A new of the offset type. Creates a new object that represents the specified byte array. The value for the new . A new of the byte array. Creates a new object that represents the specified value. The value for the new . A new of the type. Creates a new object that represents the specified value. The value for the new . A new of the type. Creates a new object that represents the specified value. The value for the new . A new of the type. Creates a new object that represents the specified value. The value for the new . A new of the type. Creates a new object that represents the specified value. The value for the new . A new of the type. Creates a new object that represents the specified value. The value for the new . A new of the type. Initializes a new instance of the class by using the byte array value of the property. The value for the new . Initializes a new instance of the class by using the value of the property. The value for the new . Initializes a new instance of the class by using the value of the property. The value for the new . Initializes a new instance of the class by using the value of the property. The value for the new . Initializes a new instance of the class by using the value of the property. The value for the new . Initializes a new instance of the class by using the value of the property. The value for the new . Initializes a new instance of the class by using the value of the property. The value for the new . Initializes a new instance of the class by using the value of the property. The value for the new . Initializes a new instance of the class by using the value of the property. The value for the new . Initializes a new instance of the EntityProperty class given the EdmType of the property (the value must be set by a public constructor). Compares the given object (which is probably an ) for equality with this object. The other object. true if the objects are equivalent; false otherwise. Compares the given object (which is probably an ) for equality with this object. The other object. true if the objects are equivalent; false otherwise. Gets the hash code for this entity property. The hash code for the entity property. Creates an from the object. The value of the object. The reference to the object created. Ensures that the given type matches the type of this entity property; throws an exception if the types do not match. Gets the as a generic object. Gets the of this object. The of this object. Gets or sets the byte array value of this object. An exception will be thrown if you attempt to set this property to anything other than an byte array. The byte array value of this object. Gets or sets the value of this object. An exception will be thrown if you attempt to set this property to anything other than an Object. The value of this object. Gets or sets the offset value of this object. An exception will be thrown if you attempt to set this property to anything other than a object. The offset value of this object. Gets or sets the value of this object. An exception will be thrown if you attempt to set this property to anything other than a object. The value of this object. Gets or sets the value of this object. An exception will be thrown if you attempt to set this property to anything other than a object. The value of this object. Gets or sets the value of this object. An exception will be thrown if you attempt to set this property to anything other than an Object. The value of this object. Gets or sets the value of this object. An exception will be thrown if you attempt to set this property to anything other than an Object. The value of this object. Gets or sets the value of this object. An exception will be thrown if you attempt to set this property to anything other than a object. The value of this object. Returns a delegate for resolving entities. The type into which the query results are projected. The partition key. The row key. The timestamp. A dictionary of properties. The ETag. Defines the set of comparison operators that may be used for constructing queries. Represents the Equal operator. Represents the Not Equal operator. Represents the Greater Than operator. Represents the Greater Than or Equal operator. Represents the Less Than operator. Represents the Less Than or Equal operator. Specifies the set of possible permissions for a shared access table policy. No shared access granted. Permission to query entities granted. Permission to add entities granted. Permission to modify entities granted. Permission to delete entities granted. Represents the collection of shared access policies defined for a table. Adds the specified key and value to the collection of shared access policies. The key of the value to add. The value to add to the collection of shared access policies. Determines whether the collection of shared access policies contains the specified key. The key to locate in the collection of shared access policies. true if the collection of shared access policies contains an element with the specified key; otherwise, false. Removes the value with the specified key from the shared access policies collection. The key of the item to remove. true if the element is successfully found and removed; otherwise, false. This method returns false if the key is not found. Gets the item associated with the specified key. The key of the value to get. The item to get. The item associated with the specified key, if the key is found; otherwise, the default value for the type. Adds the specified key/ value, stored in a , to the collection of shared access policies. The object, containing a key/ value pair, to add to the shared access policies collection. Removes all keys and values from the shared access collection. Determines whether the collection of shared access policies contains the key and value in the specified object. A object containing the key and value to search for. true if the shared access policies collection contains the specified key/value; otherwise, false. Copies each key/ value pair in the shared access policies collection to a compatible one-dimensional array, starting at the specified index of the target array. The one-dimensional array of objects that is the destination of the elements copied from the shared access policies collection. The zero-based index in at which copying begins. Removes the value, specified in the object, from the shared access policies collection. The object, containing a key and value, to remove from the shared access policies collection. true if the item was successfully removed; otherwise, false. Returns an enumerator that iterates through the collection of shared access policies. An of type . Returns an enumerator that iterates through the collection of shared access policies. An object that can be used to iterate through the collection of shared access policies. Gets a collection containing the keys in the shared access policies collection. A collection containing the keys in the of shared access policies collection. Gets a collection containing the values in the shared access policies collection. A collection of items in the shared access policies collection. Gets or sets the item associated with the specified key. The key of the value to get or set. The item associated with the specified key, or null if key is not in the shared access policies collection. Gets the number of key/ value pairs contained in the shared access policies collection. The number of key/ value pairs contained in the shared access policies collection. Gets a value indicating whether the collection of shared access policies is read-only. true if the collection of shared access policies is read-only; otherwise, false. Represents a shared access policy, which specifies the start time, expiry time, and permissions for a shared access signature. Initializes a new instance of the SharedAccessTablePolicy class. Converts the permissions specified for the shared access policy to a string. The shared access permissions. The shared access permissions in string format. Constructs a object from a permissions string. The shared access permissions in string format. A set of shared access permissions. Gets or sets the start time for a shared access signature associated with this shared access policy. The shared access start time. Gets or sets the expiry time for a shared access signature associated with this shared access policy. The shared access expiry time. Gets or sets the permissions for a shared access signature associated with this shared access policy. The permissions. Represents a continuation token for listing operations. A method that may return a partial set of results via a object also returns a continuation token, which can be used in a subsequent call to return the next set of available results. Gets an XML representation of an object. An that describes the XML representation of the object that is produced by the method and consumed by the method. Generates a serializable continuation token from its XML representation. The stream from which the continuation token is deserialized. Converts a serializable continuation token into its XML representation. The stream to which the continuation token is serialized. Gets or sets the version for continuing results for enumeration operations. The version. Gets or sets the type element (blob, queue, table) for continuing results for enumeration operations. The type element. Gets or sets the next partition key for enumeration operations. The next partition key. Gets or sets the next row key for enumeration operations. The next row key. Gets or sets the next table name for enumeration operations. The name of the next table. Gets or sets the storage location that the continuation token applies to. The storage location that the continuation token applies to. Represents the base object type for a table entity in the Table service. provides a base implementation for the interface that provides and methods that by default serialize and deserialize all properties via reflection. A table entity class may extend this class and override the and methods to provide customized or better performing serialization logic. Initializes a new instance of the class. Initializes a new instance of the class with the specified partition key and row key. The partition key of the to be initialized. The row key of the to be initialized. Deserializes this instance using the specified of property names to data typed values. The map of string property names to data values to deserialize and store in this table entity instance. An object used to track the execution of the operation. Deserializes a custom entity instance using the specified of property names to data typed values. Custom entity instance being deserialized. The map of string property names to data values to deserialize and store in this entity instance. An object used to track the execution of the operation. Serializes the of property names mapped to data values from this instance. An object used to track the execution of the operation. A map of property names to data typed values created by serializing this table entity instance. Create a of objects for all the properties of the specified entity object. The entity object to serialize. An object used to track the execution of the operation. A of objects for all the properties of the specified entity object. Determines if the given property should be skipped based on its name, if it exposes a public getter and setter, and if the IgnoreAttribute is not defined. The PropertyInfo of the property to check An object used to track the execution of the operation. True if the property should be skipped, false otherwise. Compiles a ReadAction for the given type The type to compile for A ReadAction that deserializes the given entity type. Compiles a WriteFunc for the given type The type to compile for A WriteFunc that serializes the given entity type. Generates a Conditional Expression that will retrieve the given entity value by type and set it into the current property. The entity type The property to deserialize into An Expression that represents the entity instance An Expression that represents the current EntityProperty expression Gets the EntityProperty from the dictionary, or returns null. Similar to IDictionary.TryGetValue with logging support. The key value The Dictionary instance The operationContext to log to. Gets or sets the entity's partition key. The partition key of the entity. Gets or sets the entity's row key. The row key of the entity. Gets or sets the entity's timestamp. The timestamp of the entity. Gets or sets the entity's current ETag. Set this value to '*' in order to blindly overwrite an entity as part of an update operation. The ETag of the entity. Disables the ability to dynamically generate read and write lambdas at runtime. Setting this to false will clear out the static cache shared across all type instances that derive from TableEntity. This entities compiled Write Func This entities compiled Read Action Gets or sets the status of the property resolver cache for the . The property resolver cache caches known entity types and their respective property resolver dictionaries when entities are deserialized and the payload does not include JSON metadata. For most scenarios, disabling the property resolver cache is not recommended due to its effect on performance. Enumeration containing the types of operations that can be performed by a . Represents an insert operation. Represents a delete operation. Represents a replace operation. Represents a merge operation. Represents an insert or replace operation. Represents an insert or merge operation. Represents a retrieve operation. Defines the set of Boolean operators for constructing queries. Represents the And operator. Represents the Not operator. Represents the Or operator. Describes the payload formats supported for Tables. Use AtomPub. Use JSON with full metadata. Use JSON with minimal metadata. Use JSON with no metadata. Represents the permissions for a table. Initializes a new instance of the class. Gets the set of shared access policies for the container. The set of shared access policies for the container. Represents a segment of results and contains continuation token information. The type of the result that the segment contains. Stores the continuation token used to retrieve the next segment of results. Initializes a new instance of the class. The result. Returns an enumerator that iterates through the . An enumerator that iterates through the . Gets an enumerable collection of results. An enumerable collection of results. Gets a continuation token to use to retrieve the next set of results with a subsequent call to the operation. The continuation token. Represents a set of timeout and retry policy options that may be specified for a request against the Table service. Initializes a new instance of the class. Initializes a new instance of the class with the specified . The request options used to initialize this instance of the class. Gets or sets the absolute expiry time across all potential retries for the request. Gets or sets the retry policy for the request. The retry policy delegate. Gets or sets the location mode of the request. The location mode of the request. Gets or sets the server timeout for the request. The client and server timeout interval for the request. Gets or sets the maximum execution time for all potential retries for the request. A representing the maximum execution time for retries for the request. Gets or sets the that will be used for the request. The TablePayloadFormat to use. Gets or sets the delegate that is used to get the for an entity property given the partition key, row key, and the property name. Represents the result of a table operation. The class encapsulates the HTTP response and any table entity results returned by the Storage Service REST API operation called for a particular . Gets or sets the result returned by the as an . The result of the table operation as an . Gets or sets the HTTP status code returned by a request. The HTTP status code returned by a request. Gets or sets the ETag returned with the request results. The ETag returned with the request results. Represents a segment of results, with continuation information for pagination scenarios. Initializes a new instance of the class. The result. Stores the continuation token used to retrieve the next segment of results or null if there are no more results. Returns an enumerator that iterates through the segment of results. An enumerator that iterates through the segment of results. Gets an enumerable collection of results. An enumerable collection of results. Gets the continuation token used to retrieve the next segment of results. Returns null if there are no more results. The continuation token. Internal table service entity for creating tables. Stores the table name. Initializes a new instance of the class. Initializes a new instance of the class with the specified name. The name of the table. Determines whether the specified is equal to this instance. The to compare with this instance. Returns true if the specified is equal to this instance; otherwise, false. The parameter is null. Returns a hash code for this instance. A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. Gets or sets the table name. The name of the table. Parses the response XML from an operation to set the access policy for a table. Initializes a new instance of the TableAccessPolicyResponse class. The stream to be parsed. Parses the current element. The shared access policy element to parse. The shared access policy. A set of constants used in operations against the Table service. Stores the header prefix for continuation information. Stores the header suffix for the next partition key. Stores the header suffix for the next row key. Stores the table suffix for the next table name. Stores the maximum results the table service can return. The maximum size of a string property for the table service in bytes. The maximum size of a string property for the table service in bytes. The maximum size of a string property for the table service in chars. The name of the special table used to store tables. The name of the partition key property. The name of the row key property. The name of the Timestamp property. The name of the ETag property. The name of the property that stores the table name. The query filter clause name. The query top clause name. The query select clause name. The minimum DateTime supported. Provides error code strings that are specific to the Windows Azure Table service. The request uses X-HTTP-Method with an HTTP verb other than POST. The specified X-HTTP-Method is invalid. More than one X-HTTP-Method is specified. The specified table has no properties. A property is specified more than once. The specified table has no such property. A duplicate key property was specified. The specified table already exists. The specified table was not found. The specified entity was not found. The specified entity already exists. The partition key was not specified. One or more specified operators are invalid. The specified update condition was not satisfied. All properties must have values. The partition key property cannot be updated. The entity contains more properties than allowed. The entity is larger than the maximum size permitted. The property value is larger than the maximum size permitted. One or more value types are invalid. The specified table is being deleted. The Table service server is out of memory. The type of the primary key property is invalid. The property name exceeds the maximum allowed length. The property name is invalid. Batch operations are not supported for this operation type. JSON format is not supported. The specified method is not allowed. The specified operation is not yet implemented. Provides a set of helper methods for constructing a request against the Table service. Writes a collection of shared access policies to the specified stream in XML format. A collection of shared access policies. An output stream. Contains storage constants. Constant for the max value of ParallelOperationThreadCount for Block Blobs. Maximum number of shared access policy identifiers supported by server. Default Write Block Size used by Blob stream. The maximum size of a blob before it must be separated into blocks. The maximum size of a single block. The maximum size of a range get operation that returns content MD5. The maximum number of blocks. The maximum size of a blob with blocks. Default size of buffer for unknown sized requests. Common name to be used for all loggers. The size of a page in a PageBlob. A constant representing a kilo-byte (Non-SI version). A constant representing a megabyte (Non-SI version). A constant representing a megabyte (Non-SI version). XML element for committed blocks. XML element for uncommitted blocks. XML element for blocks. XML element for names. XML element for sizes. XML element for block lists. XML element for queue message lists. XML element for queue messages. XML element for message IDs. XML element for insertion times. XML element for expiration times. XML element for pop receipts. XML element for the time next visible fields. XML element for message texts. XML element for dequeue counts. XML element for page ranges. XML element for page list elements. XML element for page range start elements. XML element for page range end elements. XML element for delimiters. XML element for blob prefixes. XML element for content type fields. XML element for content type fields. XML element for content encoding fields. XML element for content language fields. XML element for content length fields. XML element for content MD5 fields. XML element for enumeration results. XML element for service endpoint. XML element for container name. XML element for blobs. XML element for prefixes. XML element for maximum results. XML element for markers. XML element for the next marker. XML element for the ETag. XML element for the last modified date. XML element for the Url. XML element for blobs. XML element for copy ID. XML element for copy status. XML element for copy source. XML element for copy progress. XML element for copy completion time. XML element for copy status description. Constant signaling a page blob. Constant signaling a block blob. Constant signaling the blob is locked. Constant signaling the blob is unlocked. Constant signaling the resource is available for leasing. Constant signaling the resource is leased. Constant signaling the resource's lease has expired. Constant signaling the resource's lease is breaking. Constant signaling the resource's lease is broken. Constant signaling the resource's lease is infinite. Constant signaling the resource's lease is fixed (finite). Constant for a pending copy. Constant for a successful copy. Constant for an aborted copy. Constant for a failed copy. Constant for unavailable geo-replication status. Constant for live geo-replication status. Constant for bootstrap geo-replication status. XML element for blob types. XML element for the lease status. XML element for the lease status. XML element for the lease status. XML element for snapshots. XML element for containers. XML element for a container. XML element for queues. Version 2 of the XML element for the queue name. XML element for the queue. XML element for properties. XML element for the metadata. XML element for an invalid metadata name. XML element for maximum results. XML element for committed blocks. XML element for uncommitted blocks. XML element for the latest. XML element for signed identifiers. XML element for a signed identifier. XML element for access policies. XML attribute for IDs. XML element for the start time of an access policy. XML element for the end of an access policy. XML element for the permissions of an access policy. The URI path component to access the messages in a queue. XML element for exception details. XML root element for errors. XML element for error codes. XML element for error codes returned by the preview tenants. XML element for error messages. XML element for error messages. XML element for exception messages. XML element for stack traces. Namespace of the entity container. Name of the entity container. Name of the entity set. Namespace name for primitive types. Default namespace name for Tables. Default name for Tables. Header value to set Accept to XML. Header value to set Accept to AtomPub. Header value to set Accept to JsonLight. Header value to set Accept to JsonFullMetadata. Header value to set Accept to JsonNoMetadata. Header value to set Content-Type to AtomPub. Header value to set Content-Type to JSON. The prefix used in all ETags. Default client side timeout for all service clients. Default server side timeout for all service clients. Maximum Retry Policy back-off Maximum allowed timeout for any request. Constants for HTTP headers. Specifies the value to use for UserAgent header. Specifies the value to use for UserAgent header. Master Windows Azure Storage header prefix. True Header. False Header. Header prefix for properties. Header prefix for metadata. Header that specifies content length. Header that specifies content language. Header that specifies the ETag value for the resource. Header for data ranges. Header for range content MD5. Header for storage version. Header for copy source. Header for the If-Match condition. Header for the If-Modified-Since condition. Header for the If-None-Match condition. Header for the If-Unmodified-Since condition. Header for the If-Sequence-Number-LE condition. Header for the If-Sequence-Number-LT condition. Header for the If-Sequence-Number-EQ condition. Header for the blob type. Header for snapshots. Header to delete snapshots. Header that specifies approximate message count of a queue. Header that specifies blob caching control. Response header that specifies the blob content disposition. Request header that specifies the blob content disposition. Header that specifies blob content encoding. Header that specifies blob content language. Header that specifies blob content MD5. Header that specifies blob content type. Header that specifies blob content length. Header that specifies blob sequence number. Header that specifies sequence number action. Header that specifies lease ID. Header that specifies lease status. Header that specifies lease status. Header that specifies page write mode. Header that specifies the date. Header indicating the request ID. Header indicating the client request ID. Header that specifies public access to blobs. Format string for specifying ranges. Current storage version header value. Every time this version changes, assembly version needs to be updated as well. Specifies the page blob type. Specifies the block blob type. Specifies only snapshots are to be included. Specifies snapshots are to be included. Header that specifies the pop receipt for a message. Header that specifies the next visible time for a message. Header that specifies whether to peek-only. Header that specifies whether data in the container may be accessed publicly and what level of access is to be allowed. Header that specifies the lease action to perform. Header that specifies the proposed lease ID for a leasing operation. Header that specifies the duration of a lease. Header that specifies the break period of a lease. Header that specifies the remaining lease time. Header that specifies the key name for explicit keys. Header that specifies the copy ID. Header that specifies the copy last modified time. Header that specifies the copy status. Header that specifies the copy progress. Header that specifies a copy error message. Header that specifies the copy action. The value of the copy action header that signifies an abort operation. Header that specifies the Accept type for the response payload. Header that specifies the Content type for the request payload. Specifies the value to use for UserAgent header. Specifies the comment to use for UserAgent header. Constants for query strings. Query component for snapshot time. Query component for the signed SAS start time. Query component for the signed SAS expiry time. Query component for the signed SAS resource. Query component for the SAS table name. Query component for the signed SAS permissions. Query component for the SAS start partition key. Query component for the SAS start row key. Query component for the SAS end partition key. Query component for the SAS end row key. Query component for the signed SAS identifier. Query component for the signing SAS key. Query component for the signed SAS version. Query component for SAS signature. Query component for SAS cache control. Query component for SAS content type. Query component for SAS content encoding. Query component for SAS content language. Query component for SAS content disposition. Query component for message time-to-live. Query component for message visibility timeout. Query component for the number of messages. Query component for message pop receipt. Query component for resource type. Query component for the operation (component) to access. Query component for the copy ID. Constants for Result Continuations Top Element for Continuation Tokens XML element for the next marker. XML element for the next partition key. XML element for the next row key. XML element for the next table name. XML element for the target location. XML element for the token version. Stores the current token version value. XML element for the token type. Specifies the blob continuation token type. Specifies the queue continuation token type. Specifies the table continuation token type. HTTP methods that are supported by CORS. Represents no HTTP method in a CORS rule. Represents the GET HTTP method in a CORS rule. Represents the HEAD HTTP method in a CORS rule. Represents the POST HTTP method in a CORS rule. Represents the PUT HTTP method in a CORS rule. Represents the DELETE HTTP method in a CORS rule. Represents the TRACE HTTP method in a CORS rule. Represents the OPTIONS HTTP method in a CORS rule. Represents the CONNECT HTTP method in a CORS rule. Represents the MERGE HTTP method in a CORS rule. Class representing the service properties pertaining to CORS. Constructs a CORS Properties object. Gets or sets CORS rules. The order of the list corresponds to precedence of rules. A collection containing CORS rules, limited to 5. Class representing the service properties pertaining to CORS. Gets or sets domain names allowed via CORS. A collection of strings containing the allowed domain names, limited to 64. Gets or sets response headers that should be exposed to client via CORS. A collection of strings containing exposed headers, limited to 64 defined headers and two prefixed headers. Gets or sets headers allowed to be part of the CORS request. A collection of strings containing allowed headers, limited to 64 defined headers and two prefixed headers. Gets or sets the HTTP methods permitted to execute for this origin. The allowed HTTP methods. Gets or sets the length of time in seconds that a preflight response should be cached by browser. The maximum number of seconds to cache the response. Class representing the geo-replication stats. The name of the status XML element. The name of the last sync time XML element. Initializes a new instance of the GeoReplicationStats class. Gets a from a string. The geo-replication status string. A enumeration. The string contains an unrecognized value. Constructs a GeoReplicationStats object from an XML element. The XML element. A GeoReplicationStats object containing the properties in the element. Gets or sets the status of geo-replication. The status of geo-replication. Gets or sets the last synchronization time. The last synchronization time. All primary writes preceding this value are guaranteed to be available for read operations. Primary writes following this point in time may or may not be available for reads. Enumeration representing the state of geo-replication in a service. Status of geo-replication is unavailable. Geo-replication is live. Data is being bootstrapped from primary to secondary. Enumeration representing the state of logging in a service. Logging is disabled. Log read operations. Log write operations. Log delete operations. Log all operations. Class representing the service properties pertaining to logging. Gets or sets the version of the analytics service. A string identifying the version of the service. Gets or sets the state of logging. A combination of flags describing the operations that are logged. Gets or sets the logging retention policy. The number of days to retain the logs. Enumeration representing the state of metrics collection in a service. Metrics collection is disabled. Service-level metrics collection is enabled. Service-level and API metrics collection are enabled. Class representing the service properties pertaining to metrics. Gets or sets the version of the analytics service. A string identifying the version of the service. Gets or sets the state of metrics collection. A value indicating which metrics to collect, if any. Gets or sets the logging retention policy. The number of days to retain the logs. Writes a collection of shared access policies to the specified stream in XML format. A collection of shared access policies. An output stream. A delegate that writes a policy to an XML writer. The type of policy to write. Gets the request id. The response from server. The request ID. Reads a collection of shared access policies from the specified object. A collection of shared access policies to be filled. A policy response object for reading the stream. The type of policy to read. Parses the metadata. The reader. A of metadata. Precondition: reader at <Metadata> Postcondition: reader after </Metadata> (<Metadata/> consumed) Class representing a set of properties pertaining to a cloud storage service. The name of the root XML element. The name of the logging XML element. The name of the metrics XML element. The name of the CORS XML element. The name of the minute metrics XML element. The name of the version XML element. The name of the delete operation XML element. The name of the read operation XML element. The name of the write operation XML element. The name of the retention policy XML element. The name of the enabled XML element. The name of the days XML element. The name of the include APIs XML element. The name of the default service version XML element. The name of the CORS Rule XML element. The name of the Allowed Origin XML element. The name of the Allowed Method XML element. The name of the Maximum Age XML element. The name of the Exposed Headers XML element. The name of the Allowed Headers XML element. Initializes a new instance of the ServiceProperties class. Constructs a ServiceProperties object from an XML document received from the service. The XML document. A ServiceProperties object containing the properties in the XML document. Converts these properties into XML for communicating with the service. An XML document containing the service properties. Generates XML representing the given retention policy. The number of days to retain, or null if the policy is disabled. An XML retention policy element. Generates XML representing the given metrics properties. The metrics properties. The XML name for these metrics. An XML metrics element. Generates XML representing the given logging properties. The logging properties. An XML logging element. Generates XML representing the given CORS properties. The CORS properties. An XML logging element. Constructs a LoggingProperties object from an XML element. The XML element. A LoggingProperties object containing the properties in the element. Constructs a MetricsProperties object from an XML element. The XML element. A MetricsProperties object containing the properties in the element. Constructs a CorsProperties object from an XML element. The XML element. A CorsProperties object containing the properties in the element. Constructs a retention policy (number of days) from an XML element. The XML element. The number of days to retain, or null if retention is disabled. Writes service properties to a stream, formatted in XML. The stream to which the formatted properties are to be written. Gets or sets the logging properties. The logging properties. Gets or sets the hour metrics properties. The metrics properties. Gets or sets the hour metrics properties. The metrics properties. Gets or sets the Cross Origin Resource Sharing (CORS) properties. The CORS properties. Gets or sets the minute metrics properties. The minute metrics properties. Gets or sets the default service version. The default service version identifier. Class representing a set of stats pertaining to a cloud storage service. The name of the root XML element. The name of the geo-replication XML element. Initializes a new instance of the ServiceStats class. Constructs a ServiceStats object from an XML document received from the service. The XML document. A ServiceStats object containing the properties in the XML document. Gets or sets the geo-replication stats. The geo-replication stats. Provides error code strings that are common to all storage services. The specified HTTP verb is not supported. The Content-Length header is required for this request. A required header was missing. A required XML node was missing. One or more header values are not supported. One or more XML nodes are not supported. One or more header values are invalid. One or more XML node values are invalid. A required query parameter is missing. One or more query parameters is not supported. One or more query parameters are invalid. One or more query parameters are out of range. The URI is invalid. The HTTP verb is invalid. The metadata key is empty. The request body is too large. The specified XML document is invalid. An internal error occurred. Authentication failed. The specified MD5 hash does not match the server value. The specified MD5 hash is invalid. The input is out of range. The input is invalid. The operation timed out. The specified resource was not found. The specified metadata is invalid. The specified metadata is too large. The specified condition was not met. The specified range is invalid. The specified container was not found. The specified container already exists. The specified container is disabled. The specified container is being deleted. The server is busy. ================================================ FILE: ironclad-apps/tools/NuBuild/Settings.StyleCop ================================================ . ================================================ FILE: ironclad-apps/tools/NuBuild/makefile ================================================ MSBUILD=C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe #MSBUILD=C:/Windows/Microsoft.NET/Framework/v4.0.30319/MSBuild.exe #BIN = ../../bin_tools/NuBuild # #NUBUILD_SOURCES = $(wildcard NuBuild/*.cs) NuBuild/NuBuild.csproj # #all: $(BIN)/NuBuild.exe # #$(BIN)/NuBuild.exe: $(NUBUILD_SOURCES) NuBuild.sln # $(MSBUILD) NuBuild.sln all: me me: echo hi $(MSBUILD) NuBuild.sln ================================================ FILE: ironclad-apps/tools/NuBuild2/.gitignore ================================================ *.suo ================================================ FILE: ironclad-apps/tools/NuBuild2/AzureManager/App.config ================================================  ================================================ FILE: ironclad-apps/tools/NuBuild2/AzureManager/AzureAccount.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace AzureManager { using System; using System.Globalization; using System.Security.Cryptography.X509Certificates; using Microsoft.WindowsAzure; using Microsoft.WindowsAzure.Management.Compute; using Microsoft.WindowsAzure.Management.Compute.Models; using Microsoft.WindowsAzure.Management.Storage; using Microsoft.WindowsAzure.Management.Storage.Models; /// /// Representation of an Azure Account Subscription. /// public class AzureAccount { /// /// Credentials associated with this Azure account. /// private SubscriptionCloudCredentials credentials; /// /// ComputeManagementClient for managing Azure compute resources. /// private ComputeManagementClient computeManager; /// /// StorageManagementClient for managing Azure storage resources. /// private StorageManagementClient storageManager; /// /// Initializes a new instance of the AzureAccount class. /// /// Subscription ID of the Azure account. /// X509 certificate used for authentication. public AzureAccount(string subscriptionId, X509Certificate2 cert) { this.credentials = new CertificateCloudCredentials(subscriptionId, cert); this.computeManager = CloudContext.Clients.CreateComputeManagementClient(this.credentials); this.storageManager = CloudContext.Clients.CreateStorageManagementClient(this.credentials); } /// /// Gets the service information for the specified service. /// /// Name of the service to query. /// A HostedServiceGetDetailedResponse object containing the information. public HostedServiceGetDetailedResponse GetServiceInformation(string serviceName) { HostedServiceGetDetailedResponse service; service = this.computeManager.HostedServices.GetDetailed(serviceName); return service; } /// /// Creates a service specification (configuration?) entry in Azure's database. /// This reserves the (Azure-unique) DNS prefix name used to access the service. /// /// /// Note that this does not deploy and start the service. /// /// Name of the cloud service. /// Geographical region where the service should be hosted. public void CreateServiceSpecification(string serviceName, string location) { // Required: Label, ServiceName. // One Required (but not both): AffinityGroup, Location. // Optional: Description, ExtendedProperties, HostedServiceCreateParameters parameters = new HostedServiceCreateParameters(); parameters.Label = serviceName; parameters.ServiceName = serviceName; parameters.Location = location; this.computeManager.HostedServices.Create(parameters); } /// /// Deletes the specified service deployment. /// /// Name of the service /// Environment for this deployment (e.g. Production or Staging). public void DeleteDeployment(string serviceName, DeploymentSlot deploymentSlot) { this.computeManager.Deployments.DeleteBySlot(serviceName, deploymentSlot); } /// /// Deploys a service. /// /// /// Note that the service specification must already have been created. /// /// Name of the service. /// Name of this deployment. /// Environment for this deployment (e.g. Production or Staging). /// Deployment configuration information (i.e. .cscfg file contents). /// URI for blob containing package (i.e. .cspkg) file contents. /// Whether to start the deployment immediately after it is created. public void DeployService( string serviceName, string deploymentName, DeploymentSlot deploymentSlot, string configuration, Uri packageBlob, bool startImmediately = true) { // Required: Configuration, Label, Name, PackageUri. // Optional: ExtendedProperties, ExtensionConfiguration, StartDeployment, TreatWarningsAsError. DeploymentCreateParameters parameters = new DeploymentCreateParameters(); parameters.Configuration = configuration; // Contents of .cscfg file. parameters.Label = serviceName; // Name for hosted service. Does not need to match serviceName. parameters.Name = deploymentName; // Unique name for this particular deployment. parameters.PackageUri = packageBlob; // URI for blob containing .cspkg file. parameters.StartDeployment = startImmediately; // Whether to start the deployment immediately after it is created. this.computeManager.Deployments.Create(serviceName, deploymentSlot, parameters); } /// /// Gets the connection string for the given storage account. /// /// A storage account name. /// The connection string for the given storage account. public string GetConnectionStringForStorageAccount(string storageAccountName) { // This makes a call to the Azure infrastructure to get the keys. // REVIEW: Check status code of the response? StorageAccountGetKeysResponse keys = this.storageManager.StorageAccounts.GetKeys(storageAccountName); string connectionString = string.Format( CultureInfo.InvariantCulture, "DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1}", storageAccountName, keys.PrimaryKey); return connectionString; } /// /// Procedure for testing random things. /// public void TestSomething() { HostedServiceListResponse response; response = this.computeManager.HostedServices.List(); Console.WriteLine("List of hosted services:"); foreach (HostedServiceListResponse.HostedService service in response.HostedServices) { Console.WriteLine("\n{0}\n", service.ServiceName); // Note: The HostedServiceListResponse.HostedService class // contains many of the same properties as the // HostedServiceGetDetailedResponse class. } } /// /// Displays all the deployments in a given service. /// /// /// This is an alternative way to access the deployments. /// HostedServiceGetDetailedResponse.Deployment is another. /// /// The service to query. public void ShowDeployments(string serviceName) { DeploymentGetResponse response; try { response = this.computeManager.Deployments.GetBySlot(serviceName, DeploymentSlot.Production); Console.WriteLine("Production Deployment"); Console.WriteLine("Label = {0}", response.Label); } catch (Microsoft.WindowsAzure.CloudException except) { Console.WriteLine("Show Deployment Exception: {0}", except.ErrorMessage); } } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/AzureManager/AzureManager.csproj ================================================  Debug AnyCPU {8ADB4B14-715D-4CE1-BFD2-E7D65007CE5C} Exe Properties AzureManager AzureManager v4.5 512 AnyCPU true full false ..\..\..\bin_tools\NuBuild\ DEBUG;TRACE prompt 4 AnyCPU pdbonly true bin\Release\ TRACE prompt 4 ..\References\Microsoft.Threading.Tasks.dll ..\References\Microsoft.WindowsAzure.Common.dll ..\References\Microsoft.WindowsAzure.Common.NetFramework.dll False ..\References\Microsoft.WindowsAzure.Management.Compute.dll ..\References\Microsoft.WindowsAzure.Management.Storage.dll False ..\References\Microsoft.WindowsAzure.Storage.dll CustomDictionary.xml ================================================ FILE: ironclad-apps/tools/NuBuild2/AzureManager/Program.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace AzureManager { using System; using System.Collections.Specialized; using System.Configuration; using System.IO; using System.Security.Cryptography.X509Certificates; using Microsoft.WindowsAzure.Management.Compute.Models; using Microsoft.WindowsAzure.Storage; using Microsoft.WindowsAzure.Storage.Blob; /// /// Program to manage Azure cloud resources used by NuBuild. /// public class Program { /// /// Name of our service (hard-wired). /// private const string NuBuildServiceName = "NuBuildExecutionService"; /// /// Name of the deployment package blob we use for the "start" and /// "upload" commands (hard-wired). /// private const string NuBuildServicePackageName = "NuBuildExecutionEngine"; /// /// Default package file name used by "deploy" and "upload" commands. /// Can be overridden by command line argument. /// private const string DefaultPackageFilename = "NuBuildExecutionService.cspkg"; /// /// Default configuration file name used by the "deploy" command /// Can be overridden by command line argument. /// private const string DefaultConfigurationFilename = "ServiceConfiguration.Cloud.cscfg"; /// /// Default number of service instances to "start". /// Can be overridden by command line argument. /// private const int DefaultInstanceCount = 10; /// /// Main program entry point. /// /// The parameter is unused. private static void Main(string[] args) { Console.WriteLine(); // Set some defaults. string packageFilename = DefaultPackageFilename; string configurationFilename = DefaultConfigurationFilename; int instanceCount = DefaultInstanceCount; string command = "status"; // Parse command line arguments. if (args.Length > 0) { command = args[0].ToLower(); if (args.Length > 1) { if (command == "start") { if (!int.TryParse(args[1], out instanceCount)) { Usage(-1); } } else { packageFilename = args[1]; } if (args.Length > 2) { configurationFilename = args[2]; } } } // Get our Azure account information. AzureAccount azureAccount = GetOurAzureAccount(); // Perform user requested action. CloudBlockBlob packageBlob; switch (command) { case "create": azureAccount.CreateServiceSpecification(NuBuildServiceName, "West US"); break; case "deploy": // Upload our package (.cspkg file) to a blob. // We name the blob after the package filename. string blobName = Path.GetFileNameWithoutExtension(packageFilename); packageBlob = GetPackageBlob(azureAccount, blobName); packageBlob.UploadFromFile(packageFilename, System.IO.FileMode.Open); // Create a new deployment using the desired package blob. // TODO: Provide an unique name for each deployment? // REVIEW: Upload to "Staging" slot instead? string configuration = File.ReadAllText(configurationFilename); azureAccount.DeployService(NuBuildServiceName, "Production", DeploymentSlot.Production, configuration, packageBlob.Uri, startImmediately: true); Console.WriteLine("Issued deployment request"); break; case "start": // Create a new deployment using a hard-coded configuration and a previously uploaded blob. ServiceConfiguration config = new ServiceConfiguration( NuBuildServiceName, "4", "*", "2014-06.2.4", "CloudExecutionWorker", instanceCount); packageBlob = GetPackageBlob(azureAccount, NuBuildServicePackageName); azureAccount.DeployService(NuBuildServiceName, "Production", DeploymentSlot.Production, config.ToXml(), packageBlob.Uri, startImmediately: true); Console.WriteLine("Issued deployment request"); break; case "status": HostedServiceGetDetailedResponse serviceInfo = azureAccount.GetServiceInformation(NuBuildServiceName); DisplayServiceInformation(serviceInfo); break; case "stop": // Delete the Azure deployment. // This stops the currently running service, but leaves the // configuration for this service in the Azure database. azureAccount.DeleteDeployment(NuBuildServiceName, DeploymentSlot.Production); break; case "test": ////azureAccount.TestSomething(); ServiceConfiguration testConfig = new ServiceConfiguration(NuBuildServiceName, "4", "*", "2014-06.2.4", "CloudExecutionWorker", 42); Console.WriteLine(testConfig.ToXml()); break; case "upload": // Upload our package (.cspkg file) to a blob. packageBlob = GetPackageBlob(azureAccount, NuBuildServicePackageName); packageBlob.UploadFromFile(packageFilename, System.IO.FileMode.Open); Console.WriteLine("Uploaded package"); break; case "/?": case "help": Usage(0); break; default: Usage(-1); break; } } /// /// Display a (hopefully) helpful usage message to the user, /// and exit the process. /// /// Process exit code to use. private static void Usage(int exitcode) { Console.WriteLine("Usage: AzureManager [create | deploy [package file [config file]] |"); Console.WriteLine(" start [instances] | status | stop |"); Console.WriteLine(" upload [package file]]"); Console.WriteLine(); Console.WriteLine(" where"); Console.WriteLine(" instances Number of service instances to start."); Console.WriteLine(" (default: {0})", DefaultInstanceCount); Console.WriteLine(" package file Package file to deploy."); Console.WriteLine(" (default: .\\{0})", DefaultPackageFilename); Console.WriteLine(" config file Configuration file for deployment."); Console.WriteLine(" (default: .\\{0})", DefaultConfigurationFilename); Console.WriteLine(); Console.WriteLine(" Commands:"); Console.WriteLine(" create Create a new service configuration (using hard-wired info)."); Console.WriteLine(" deploy Deploy using the given package and configuration"); Console.WriteLine(" (overwrites existing hard-wired package blob)."); Console.WriteLine(" start Start the given number of instances of an existing package"); Console.WriteLine(" named '{0}'.", NuBuildServicePackageName); Console.WriteLine(" status Display the current service and deployment status."); Console.WriteLine(" stop Stop the current deployment of the service."); Console.WriteLine(" upload Upload the given package file to hard-wired package blob"); Console.WriteLine(" named '{0}'.", NuBuildServicePackageName); Environment.Exit(exitcode); } /// /// Gets our Azure account. /// /// An Azure account. private static AzureAccount GetOurAzureAccount() { string subscriptionId = null; string certBase64Encoded = null; NameValueCollection appSettings = ConfigurationManager.AppSettings; if (appSettings != null) { subscriptionId = appSettings["Subscription Id"]; certBase64Encoded = appSettings["Certificate (Base 64 Encoded)"]; } if (string.IsNullOrEmpty(subscriptionId)) { throw new ConfigurationException("Subscription Id setting missing from your AzureManager.exe.config file!"); } if (string.IsNullOrEmpty(certBase64Encoded)) { throw new ConfigurationException("Certificate setting missing from your AzureManager.exe.config file!"); } byte[] cert = Convert.FromBase64String(certBase64Encoded); X509Certificate2 x509Cert = new X509Certificate2(cert); AzureAccount azureAccount = new AzureAccount(subscriptionId, x509Cert); return azureAccount; } /// /// Writes selected fields of the give HostedServiceGetDetailedResponse /// object out to the console. /// /// /// The HostedServiceGetDetailedResponse object to display. /// private static void DisplayServiceInformation(HostedServiceGetDetailedResponse service) { Console.WriteLine("Service Name {0}:", service.ServiceName); Console.WriteLine(" Date Created = {0}", service.Properties.DateCreated); Console.WriteLine(" Date Last Modified = {0}", service.Properties.DateLastModified); Console.WriteLine(" Description = {0}", service.Properties.Description); Console.WriteLine(" Label = {0}", service.Properties.Label); Console.WriteLine(" Location = {0}", service.Properties.Location); Console.WriteLine(" Status = {0}", service.Properties.Status); #if false foreach(string size in service.ComputeCapabilities.VirtualMachinesRoleSizes) { Console.WriteLine("VM Role Size = {0}", size); } Console.WriteLine("URI = {0}", service.Uri); #endif if (service.Deployments.Count == 0) { Console.WriteLine(" No current deployments!"); } foreach (HostedServiceGetDetailedResponse.Deployment deployment in service.Deployments) { Console.WriteLine(); Console.WriteLine(" Deployment Name {0}:", deployment.Name); Console.WriteLine(" Created = {0}", deployment.CreatedTime); Console.WriteLine(" Label = {0}", deployment.Label); Console.WriteLine(" Slot = {0}", deployment.DeploymentSlot); Console.WriteLine(" Status = {0}", deployment.Status); Console.WriteLine(" Instances = {0}", deployment.RoleInstances.Count); ////Console.WriteLine(deployment.Configuration); } } /// /// Uploads the given file to the specified Azure blob. /// /// Azure account to use. /// Name of the blob to upload to. /// A reference to the CloudBlockBlob. private static CloudBlockBlob GetPackageBlob(AzureAccount azureAccount, string blobName) { // Get connection string for our storage account. // TODO: Remove hard-coded storage account name. const string StorageAccountName = "ironcladstoretest"; string connectionString = azureAccount.GetConnectionStringForStorageAccount(StorageAccountName); ////Console.WriteLine("Using connection string " + connectionString); // Use our storage account connection string to get our CloudStorageAccount. CloudStorageAccount storageAccount = CloudStorageAccount.Parse(connectionString); ////Console.WriteLine("Storage account URI = {0}", storageAccount.BlobEndpoint.AbsoluteUri); // Use our CloudStorageAccount to create a CloudBlobClient. CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient(); ////Console.WriteLine("Blob base URI = {0}", blobClient.BaseUri); // Find or create our "packages" blob storage container. CloudBlobContainer container = blobClient.GetContainerReference("packages"); container.CreateIfNotExists(BlobContainerPublicAccessType.Container); // Get the package blob we want to deploy. // This is a 'cspkg' file stored as a blob. CloudBlockBlob packageBlob = container.GetBlockBlobReference(blobName); return packageBlob; } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/AzureManager/Properties/AssemblyInfo.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("AzureManager")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("AzureManager")] [assembly: AssemblyCopyright("Copyright © 2015")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("067c0004-c47f-4a37-b93d-009d5718b965")] // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: ironclad-apps/tools/NuBuild2/AzureManager/ServiceConfiguration.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace AzureManager { using System; using System.Diagnostics; using System.Globalization; using System.IO; using System.Text; using System.Xml; /// /// /// Representation of the "service configuration" (.cscfg) file contents /// used for Azure deployments. /// /// /// /// /// Format is defined by the "Azure Service Configuration Schema". /// See . /// This class implements only the small subset of the schema that we use. /// /// /// This is the format of the "Configuration" member of various /// deployment-related classes (DeploymentChangeConfigurationParameters, /// DeploymentCreateParameters, DeploymentUpgradeParameters, /// HostedServiceGetDetailedResponse.Deployment, etc). /// /// /// Note that this is separate from the "Azure Service Definition Schema" /// (.csdef file) used to create the service proper. /// /// public class ServiceConfiguration { /// /// XML namespace for this object. /// public const string XmlNamespace = "http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration"; /// /// XML element name for this object. /// public const string XmlTag = "ServiceConfiguration"; /// /// XML attribute name for our service name field. /// private const string XmlServiceNameAttribute = "serviceName"; /// /// XML attribute name for our OS family field. /// private const string XmlOSFamilyAttribute = "osFamily"; /// /// XML attribute name for our OS version field. /// private const string XmlOSVersionAttribute = "osVersion"; /// /// XML attribute name for our schema version field. /// private const string XmlSchemaVersionAttribute = "schemaVersion"; /// /// XML element name for our role field. /// private const string XmlRoleElement = "Role"; /// /// XML attribute name for our role name field. /// private const string XmlRoleNameAttribute = "name"; // Note we don't currently support the "vmName" attribute. /// /// XML element name for our instances field. /// private const string XmlInstancesElement = "Instances"; /// /// XML element name for our instance count field. /// private const string XmlInstanceCountAttribute = "count"; /// /// XML element name for our configuration settings field. /// /// /// Note we don't currently support any configuration settings. /// private const string XmlConfigurationSettingsElement = "ConfigurationSettings"; // Note we don't currently support any certificates. // Note we don't currently support the NetworkConfiguration element. /// /// Name of the service. /// private string serviceName; /// /// OS Family. /// private string osFamily; /// /// OS Version. /// private string osVersion; /// /// Schema Version. /// private string schemaVersion; /// /// Name of the role. /// private string roleName; /// /// Count of the number of role instances. /// private int instanceCount; /// /// Initializes a new instance of the ServiceConfiguration class. /// /// Name of the cloud service. /// Guest OS that will run on role instances in the cloud service. /// Version of the Guest OS that will run on role instances in the cloud service. /// Version of the Service Configuration schema. /// Name of the role. /// Number of instances to deploy for this role. public ServiceConfiguration( string serviceName, string osFamily, string osVersion, string schemaVersion, string roleName, int instanceCount) { this.serviceName = serviceName; this.osFamily = osFamily; this.osVersion = osVersion; this.schemaVersion = schemaVersion; this.roleName = roleName; this.instanceCount = instanceCount; } /// /// Gets the service name. /// public string ServiceName { get { return this.serviceName; } } /// /// Gets the OS Family. /// public string OsFamily { get { return this.osFamily; } } /// /// Gets the OS Version. /// public string OsVersion { get { return this.osVersion; } } /// /// Gets the Schema Version. /// public string SchemaVersion { get { return this.schemaVersion; } } /// /// Gets the name of the role. /// public string RoleName { get { return this.roleName; } } /// /// Gets the number of instances. /// public int InstanceCount { get { return this.instanceCount; } } /// /// Creates a ServiceConfiguration from an XML representation. /// /// /// A string containing an XML document representing a request. /// /// /// A new request corresponding to the XML representation read. /// public static ServiceConfiguration FromXml(string xs) { XmlReader xr = XmlReader.Create(new StringReader(xs)); while (xr.Read()) { if (xr.NodeType == XmlNodeType.Element) { break; } } return ReadXml(xr); } /// /// Helper function to read an XML element (not a full document) /// representing an Azure Service Configuration. /// /// /// Note that the XmlReader is expected to be positioned in the XML /// document such that the current node is a request element. /// /// The XmlReader object to read from. /// /// A new request corresponding to the XML representation read. /// public static ServiceConfiguration ReadXml(XmlReader xr) { Debug.Assert(xr.Name.Equals(ServiceConfiguration.XmlTag), "Invalid call"); string serviceName = xr.GetAttribute(ServiceConfiguration.XmlServiceNameAttribute); string osFamily = xr.GetAttribute(ServiceConfiguration.XmlOSFamilyAttribute); string osVersion = xr.GetAttribute(ServiceConfiguration.XmlOSVersionAttribute); string schemaVersion = xr.GetAttribute(ServiceConfiguration.XmlSchemaVersionAttribute); string roleName = string.Empty; int instanceCount = 0; while (xr.Read()) { if (xr.NodeType == XmlNodeType.Element) { switch (xr.Name) { case XmlRoleElement: roleName = xr.GetAttribute(ServiceConfiguration.XmlRoleNameAttribute); break; case XmlInstancesElement: string temp = xr.GetAttribute(ServiceConfiguration.XmlInstanceCountAttribute); instanceCount = int.Parse(temp); break; case XmlConfigurationSettingsElement: break; } } else if (xr.NodeType == XmlNodeType.EndElement) { if (xr.Name.Equals(ServiceConfiguration.XmlTag)) { break; // All done. } } } // REVIEW: Sanity check elements here? return new ServiceConfiguration( serviceName, osFamily, osVersion, schemaVersion, roleName, instanceCount); } /// /// Creates an XML document representing this cloud execution request. /// /// /// A string containing an XML document representing this request. /// public string ToXml() { StringBuilder sb = new StringBuilder(); XmlWriterSettings settings = new XmlWriterSettings(); settings.Indent = true; ////settings.OmitXmlDeclaration = true; XmlWriter xw = XmlWriter.Create(sb, settings); xw.WriteStartDocument(); this.WriteXml(xw); xw.Close(); return sb.ToString(); } /// /// Helper function to write an XML element (not a full document) /// representing this result record. /// /// The XmlWriter object to write to. public void WriteXml(XmlWriter xw) { // Start writing the element for this object. xw.WriteStartElement(XmlTag, ServiceConfiguration.XmlNamespace); xw.WriteAttributeString(ServiceConfiguration.XmlServiceNameAttribute, this.serviceName); xw.WriteAttributeString(ServiceConfiguration.XmlOSFamilyAttribute, this.osFamily); xw.WriteAttributeString(ServiceConfiguration.XmlOSVersionAttribute, this.osVersion); xw.WriteAttributeString(ServiceConfiguration.XmlSchemaVersionAttribute, this.schemaVersion); // Start writing the Role element. xw.WriteStartElement(ServiceConfiguration.XmlRoleElement); xw.WriteAttributeString(ServiceConfiguration.XmlRoleNameAttribute, this.roleName); // Write the Instances element. xw.WriteStartElement(ServiceConfiguration.XmlInstancesElement); xw.WriteAttributeString(ServiceConfiguration.XmlInstanceCountAttribute, this.instanceCount.ToString(CultureInfo.InvariantCulture)); xw.WriteEndElement(); // Write the ConfigurationSettings element. xw.WriteElementString(ServiceConfiguration.XmlConfigurationSettingsElement, string.Empty); // Finish writing the Role element. xw.WriteEndElement(); // Finish writing the element for this object. xw.WriteEndElement(); } /// /// Gets a string representation of this instance. /// Primarily intended as a debugging aid. /// /// A string representation of this instance. public override string ToString() { StringBuilder output = new StringBuilder(); output.AppendFormat("Service Name: {0}", this.serviceName); output.AppendLine(); output.AppendFormat("OS Family: {0}", this.osFamily); output.AppendLine(); output.AppendFormat("OS Version: {0}", this.osVersion); output.AppendLine(); output.AppendFormat("Schema Version: {0}", this.schemaVersion); output.AppendLine(); output.AppendFormat("Role Name: {0}", this.roleName); output.AppendLine(); output.AppendFormat("Number of Instances: {0}", this.instanceCount); output.AppendLine(); return output.ToString(); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/CloudExecutionEngine/App.config ================================================  ================================================ FILE: ironclad-apps/tools/NuBuild2/CloudExecutionEngine/CloudExecutionEngine.csproj ================================================  Debug AnyCPU {2668E334-0B79-4023-A621-2D1433CE7C9E} Exe Properties CloudExecutionEngineStandalone CloudExecutionEngine v4.5 512 AnyCPU true full false bin\Debug\ DEBUG;TRACE prompt 4 AnyCPU pdbonly true bin\Release\ TRACE prompt 4 False ..\References\Microsoft.WindowsAzure.Storage.dll {4f3de22c-cae9-408b-aa54-10dcd7e12f09} CloudExecutionWorker ================================================ FILE: ironclad-apps/tools/NuBuild2/CloudExecutionEngine/Program.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace CloudExecutionEngineStandalone { using System; using System.Collections.Generic; using System.IO; using CloudExecutionWorker; /// /// Representation of the Cloud Execution Engine. /// internal class Program { /// /// Run executable requests posted to the requests queue. /// /// The parameter is unused. public static void Main(string[] args) { CloudExecutionEngine engine = new CloudExecutionEngine(); engine.Run(); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/CloudExecutionEngine/Properties/AssemblyInfo.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("CloudExecutionEngine")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("CloudExecutionEngine")] [assembly: AssemblyCopyright("Copyright © 2014")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("5ff7c12f-584f-4104-8e04-8f6f63873a02")] // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: ironclad-apps/tools/NuBuild2/CloudExecutionWorker/CloudExecutionEngine.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace CloudExecutionWorker { using System; using System.Collections.Generic; using System.IO; using NuBuild; /// /// Representation of the Cloud Execution Engine. /// public class CloudExecutionEngine { /// /// Root directory path. /// private string virtualIronRoot; /// /// Cloud implementation of the item cache. /// Used to explicitly store things in the cloud. /// private ItemCacheCloud cloudCache; /// /// Multiplexed cloud/local implementation of the item cache. /// private IItemCache multiplexedItemCache; /// /// Main queue of client execution requests. /// private CloudExecutionQueue mainQueue; /// /// Whether to continue servicing the queue requests. /// private bool keepSwimming; /// /// Initializes a new instance of the CloudExecutionEngine class. /// public CloudExecutionEngine() { // Establish various infrastructure. // TODO: Clean this up. this.virtualIronRoot = Directory.GetCurrentDirectory(); string localCacheDirectory = Path.Combine(this.virtualIronRoot, "nucache"); this.cloudCache = new ItemCacheCloud(); this.multiplexedItemCache = new ItemCacheMultiplexer( new ItemCacheLocal(localCacheDirectory), this.cloudCache, null); Console.WriteLine("Accessing execution queue."); this.mainQueue = new CloudExecutionQueue(); } /// /// Runs the execution engine, which eternally processes execution /// requests posted to the main queue. /// public void Run() { this.keepSwimming = true; while (this.keepSwimming) { // Pull request off queue. Console.WriteLine("Waiting for new work request."); CloudExecutionRequest executionRequest = this.mainQueue.GetRequest(block: true); if (!this.keepSwimming) { // Exit without deleting request from queue. // Request will become visible again after timeout expires. break; } // TODO: For now, we immediately delete the requests we take. // Eventually we'll want to leave the request invisible until // some timeout expires so that other engines can pick it up // if we crash. this.mainQueue.DeleteRequest(executionRequest); Console.WriteLine("Received request with ID {0}.", executionRequest.Identifier); // Make a progress report to soothe nervous users. CloudExecutionReport statusUpdate = new CloudExecutionReport( executionRequest.Identifier, CloudExecutionReport.StatusCode.InProgress, 0, null, null, 0, null); // Submit progress report. this.mainQueue.SubmitReport(statusUpdate, executionRequest.ReportQueue); // Do the requested operation. CloudExecutionReport report = null; switch (executionRequest.RequestedOperation) { case CloudExecutionRequest.Operation.RunExecutable: report = this.RunAnExecutable(executionRequest); break; case CloudExecutionRequest.Operation.CommitSuicide: this.keepSwimming = false; goto case CloudExecutionRequest.Operation.None; case CloudExecutionRequest.Operation.DeleteQueue: this.mainQueue.DeleteQueue(executionRequest.ReportQueue); goto case CloudExecutionRequest.Operation.None; case CloudExecutionRequest.Operation.None: report = new CloudExecutionReport( executionRequest.Identifier, CloudExecutionReport.StatusCode.Completed); break; default: // ToDo: This should probably be treated as an error. goto case CloudExecutionRequest.Operation.None; } // Submit report. this.mainQueue.SubmitReport(report, executionRequest.ReportQueue); } } /// /// Stops the execution engine. /// public void Stop() { this.keepSwimming = false; } /// /// Run the requested executable and produce a report of the results. /// /// The execution request. /// A report of the results. private CloudExecutionReport RunAnExecutable(CloudExecutionRequest executionRequest) { // REVIEW: How/whether to use this. BuildObject diagnosticsBase = new BuildObject(Path.Combine("nuobj", "diagnostics", "process")); // Prep working directory with input files and output dirs. // TODO: The below will throw cache exceptions if something // isn't there (they should all be though). Need to catch // these and fail the execution request when this happens. WorkingDirectory workingDirectory = new WorkingDirectory(this.virtualIronRoot); foreach (BuildObjectValuePointer inputFile in executionRequest.InputFileMappings) { // REVIEW: How to determine cache container here. ItemCacheContainer container = ItemCacheContainer.Sources; if (this.multiplexedItemCache.GetItemSize(container, inputFile.ObjectHash) == -1) { container = ItemCacheContainer.Objects; } // TODO: Move path/directory manipulation code into // WorkingDirectory and/or ItemCache. string inputFilePath = workingDirectory.PathTo(inputFile.RelativePath); Directory.CreateDirectory(Path.GetDirectoryName(inputFilePath)); // REVIEW: Still neeeded? this.multiplexedItemCache.FetchItemToFile( container, inputFile.ObjectHash, inputFilePath); } foreach (BuildObject outputFile in executionRequest.OutputFiles) { workingDirectory.CreateDirectoryFor(outputFile); } // Run executable. ProcessInvoker pinv = new ProcessInvoker( workingDirectory, executionRequest.Executable, new string[] { executionRequest.Arguments }, diagnosticsBase, null, // This is captureStdout. TODO: Should cleanup how this is used in ProcessInvoker. null); // This is dbgText. REVIEW: How/whether to use this. // When ProcessInvoker's constructor returns, the process has // finished running. Console.WriteLine("Request {0} completed in {1} seconds.", executionRequest.Identifier, pinv.CpuTime); // Store output files in the (cloud) item cache, and create a // list of the mappings. List outputFileMappings = new List(); foreach (BuildObject outFile in executionRequest.OutputFiles) { if (File.Exists(workingDirectory.PathTo(outFile))) { string fileHash = Util.hashFilesystemPath(workingDirectory.PathTo(outFile)); Util.Assert(!string.IsNullOrEmpty(fileHash)); // Note we explicitly write to the cloud cache here. this.cloudCache.StoreItemFromFile(ItemCacheContainer.Objects, fileHash, workingDirectory.PathTo(outFile)); outputFileMappings.Add(new BuildObjectValuePointer(fileHash, outFile.getRelativePath())); } } // Collect the results into a report. CloudExecutionReport report = new CloudExecutionReport( executionRequest.Identifier, CloudExecutionReport.StatusCode.Completed, pinv.ExitCode, pinv.GetStdout(), pinv.GetStderr(), pinv.CpuTime, outputFileMappings); return report; } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/CloudExecutionWorker/CloudExecutionWorker.csproj ================================================  Debug AnyCPU 8.0.30703 2.0 {4F3DE22C-CAE9-408B-AA54-10DCD7E12F09} Library Properties CloudExecutionWorker CloudExecutionWorker v4.5 512 Worker true full false bin\Debug\ DEBUG;TRACE prompt 4 pdbonly true bin\Release\ TRACE prompt 4 True False Designer {4d7220c0-3caa-4659-9f16-a564db3ccc1b} NuBuild ================================================ FILE: ironclad-apps/tools/NuBuild2/CloudExecutionWorker/Properties/AssemblyInfo.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("CloudExecutionWorker")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("CloudExecutionWorker")] [assembly: AssemblyCopyright("Copyright © 2015")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("4143a7eb-b9aa-4dfb-87ac-1b961e44a2e7")] // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: ironclad-apps/tools/NuBuild2/CloudExecutionWorker/WorkerRole.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace CloudExecutionWorker { using System; using System.Diagnostics; using System.Net; using Microsoft.WindowsAzure; using Microsoft.WindowsAzure.Diagnostics; using Microsoft.WindowsAzure.ServiceRuntime; /// /// Our worker role. /// This is what Azure knows how to interact with. /// /// /// For information on handling configuration changes /// . /// public class WorkerRole : RoleEntryPoint { /// /// Our CloudExecutionEngine that does the real work. /// private CloudExecutionEngine engine; /// /// Azure calls this method to do the main work. /// If this method returns, Azure will recycle this role instance. /// public override void Run() { Trace.TraceInformation("CloudExecutionWorker entry point called"); this.engine = new CloudExecutionEngine(); // TODO: Multi-thread this. this.engine.Run(); } /// /// Called when this role instance is brought online by Azure. /// /// /// Whether Azure should proceed with calling our Run method. /// public override bool OnStart() { // Set the maximum number of concurrent connections. //// ServicePointManager.DefaultConnectionLimit = 12; return base.OnStart(); } /// /// Called after this role instance has been taken offline by Azure /// but before the process exits. /// public override void OnStop() { this.engine.Stop(); base.OnStop(); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/CloudExecutionWorker/app.config ================================================  ================================================ FILE: ironclad-apps/tools/NuBuild2/CloudQueueTool/App.config ================================================  ================================================ FILE: ironclad-apps/tools/NuBuild2/CloudQueueTool/CloudQueueTool.csproj ================================================  Debug AnyCPU {DD7B4AD9-1EB0-47BF-B4C2-5BC1CA85D242} Exe Properties CloudQueueTool CloudQueueTool v4.5 512 AnyCPU true full false bin\Debug\ DEBUG;TRACE prompt 4 AnyCPU pdbonly true bin\Release\ TRACE prompt 4 False ..\References\Microsoft.WindowsAzure.Storage.dll ================================================ FILE: ironclad-apps/tools/NuBuild2/CloudQueueTool/Program.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace CloudQueueTool { using System; using System.Collections.Generic; using System.Configuration; using System.IO; using Microsoft.WindowsAzure.Storage; using Microsoft.WindowsAzure.Storage.Queue; /// /// Cloud queue management program. /// internal class Program { /// /// Acts upon command line arguments. /// /// Command line arguments. private static void Main(string[] args) { // Create our CloudQueueClient object. // REVIEW: Hard-coded connection string index "Ironclad". string connectionString = null; ConnectionStringSettings settings = ConfigurationManager.ConnectionStrings["Ironclad"]; if (settings != null) { connectionString = settings.ConnectionString; } if (string.IsNullOrEmpty(connectionString)) { throw new ConfigurationException("Azure connection string missing from your .exe.config file!"); } CloudStorageAccount storageAccount = CloudStorageAccount.Parse(connectionString); CloudQueueClient queueClient = storageAccount.CreateCloudQueueClient(); switch (args.Length) { case 0: Status(queueClient.ListQueues()); break; case 2: { CloudQueue queue = queueClient.GetQueueReference(args[1]); if (!queue.Exists()) { Console.WriteLine("No such queue '{0}'", args[1]); return; } queue.FetchAttributes(); switch (args[0]) { case "clear": case "Clear": queue.Clear(); Console.WriteLine("Queue '{0}' cleared.", queue.Name); break; case "peek": case "Peek": int numberToPeekAt = (queue.ApproximateMessageCount != null) ? (int)queue.ApproximateMessageCount : 0; Console.WriteLine("Queue '{0}' contains {1} messages:", queue.Name, numberToPeekAt); if (numberToPeekAt != 0) { // Peek API only allows a maximum of 32 messages to be peeked at. numberToPeekAt = Math.Min(numberToPeekAt, 32); foreach (CloudQueueMessage message in queue.PeekMessages(numberToPeekAt)) { Console.WriteLine( "\t{0} {1} {2}", message.Id, message.InsertionTime, message.ExpirationTime); } } break; case "status": case "Status": Status(new CloudQueue[]{queue}); break; default: Usage(); break; } } break; default: Usage(); break; } } private static void Status(IEnumerable queues) { foreach (CloudQueue queue in queues) { queue.FetchAttributes(); Console.WriteLine("Queue '{0}' contains about {1} messages.", queue.Name, queue.ApproximateMessageCount); } } private static void Usage() { Console.WriteLine("Usage: CloudQueueTool [ ]"); Console.WriteLine("\t = Clear | Peek | Status"); Console.WriteLine("\t = reports | requests"); Console.WriteLine(); Console.WriteLine("If given no arguments, CloudQueueTool returns the status of all queues."); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/CloudQueueTool/Properties/AssemblyInfo.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("CloudQueueTool")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("CloudQueueTool")] [assembly: AssemblyCopyright("Copyright © 2014")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("0321a4d8-87f1-4467-b44a-b5e355a614b9")] // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: ironclad-apps/tools/NuBuild2/CustomDictionary.xml ================================================ asynchronicity cscfg csdef cspkg cpu Dafny filesystem ifc Ironfleet munged nuobj rejectable src obj Nu ================================================ FILE: ironclad-apps/tools/NuBuild2/ItemCacheTool/App.config ================================================  ================================================ FILE: ironclad-apps/tools/NuBuild2/ItemCacheTool/CacheState.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace ItemCacheTool { using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using NuBuild; public class CacheState { private ItemCacheCloud cloudCache; private ItemCacheLocal localCache; public CacheState() { this.cloudCache = new ItemCacheCloud(); this.localCache = new ItemCacheLocal( Path.Combine(GetDefaultIronRoot(), "nucache")); } public ItemCacheCloud GetCloudCache { get { return this.cloudCache; } } public ItemCacheLocal GetLocalCache { get { return this.localCache; } } public IItemCache[] GetAllCaches { get { return new IItemCache[] { this.cloudCache, this.localCache }; } } public ItemCacheContainer[] GetAllContainers { get { return (ItemCacheContainer[])Enum.GetValues(typeof(ItemCacheContainer)); } } public IItemCache[] ParseCacheName(string input) { if (input == "*") { return this.GetAllCaches; } if (string.Equals(input, "cloud", StringComparison.CurrentCultureIgnoreCase)) { return new IItemCache[] { this.cloudCache }; } if (string.Equals(input, "local", StringComparison.CurrentCultureIgnoreCase)) { return new IItemCache[] { this.localCache }; } return null; } public ItemCacheContainer[] ParseContainerName(string input) { ItemCacheContainer container; if (input == "*") { return this.GetAllContainers; } if (Enum.TryParse(input, true, out container)) { if (Enum.IsDefined(typeof(ItemCacheContainer), container)) { return new ItemCacheContainer[] { container }; } } return null; } /// /// Gets the default iron root path. /// /// String containing the default iron root path. private static string GetDefaultIronRoot() { string assyUri = System.Reflection.Assembly.GetExecutingAssembly().CodeBase; string assyPath = new Uri(assyUri).LocalPath; string exepath = Path.GetDirectoryName(assyPath); exepath = Path.GetFullPath(exepath); string[] parts = exepath.Split(new char[] { '\\' }); int ironIndex = Array.IndexOf(parts, "iron"); string rc = string.Join("\\", parts.Take(ironIndex + 1)); return rc; } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/ItemCacheTool/ItemCacheTool.csproj ================================================ Debug AnyCPU {9A231EB8-BDA1-4304-93A1-20457C00D7D9} Exe Properties ItemCacheTool ItemCacheTool v4.5 512 AnyCPU true full false bin\Debug\ DEBUG;TRACE prompt 4 AllRules.ruleset AnyCPU pdbonly true bin\Release\ TRACE prompt 4 False ..\References\Microsoft.WindowsAzure.Storage.dll {4d7220c0-3caa-4659-9f16-a564db3ccc1b} NuBuild CustomDictionary.xml ================================================ FILE: ironclad-apps/tools/NuBuild2/ItemCacheTool/Program.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace ItemCacheTool { using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using Microsoft.WindowsAzure.Storage; using Microsoft.WindowsAzure.Storage.Blob; using NuBuild; /// /// Representation of the ItemCacheTool program. /// public static class Program { /// /// Program entry point. /// /// Command line arguments. private static void Main(string[] args) { CacheState caches = new CacheState(); string query; IItemCache[] queriedCaches; ItemCacheContainer[] queriedContainers; string queriedItems; DateTimeOffset queriedDate; // - // Default values. // This corresponds to "status * *". // - query = "status"; queriedCaches = caches.GetAllCaches; queriedContainers = caches.GetAllContainers; queriedItems = string.Empty; queriedDate = DateTimeOffset.MinValue; // - // Parse arguments. // - if (args.Length != 0) { if (args.Length != 3) { if (args.Length == 4) { if (!DateTimeOffset.TryParse(args[3], out queriedDate)) { queriedItems = args[3]; } } else { Usage(caches); return; } } query = args[0]; queriedCaches = caches.ParseCacheName(args[1]); queriedContainers = caches.ParseContainerName(args[2]); if ((queriedCaches == null) || (queriedContainers == null)) { Usage(caches); return; } } // - // Process request. // - switch (query) { case "list": case "List": { CacheStatus(queriedCaches, queriedContainers, true); break; } case "compare": case "Compare": { if (queriedCaches.Length < 2) { Console.WriteLine("Error: can't compare fewer than two caches!"); Usage(caches); return; } CompareCacheContainers(queriedCaches, queriedContainers); break; } case "status": case "Status": { CacheStatus(queriedCaches, queriedContainers, false); break; } case "delete": case "Delete": { if (args.Length < 4) { Console.WriteLine("Error: missing argument. Need date earlier than or specific item(s) to delete."); Usage(caches); return; } if (queriedDate == DateTimeOffset.MinValue) { DeleteItems(queriedCaches, queriedContainers, queriedItems); } else { DeleteItems(queriedCaches, queriedContainers, queriedDate); } break; } case "check": case "Check": { CheckResults(queriedCaches, false); break; } case "cleanup": case "Cleanup": { CheckResults(queriedCaches, true); break; } case "dump": case "Dump": { DumpItems(queriedCaches, queriedContainers, queriedItems); break; } } } /// /// Prints a user-friendly message explaining how to use the program. /// /// The caches the program is using. private static void Usage(CacheState caches) { string containers = string.Empty; foreach (ItemCacheContainer container in caches.GetAllContainers) { containers += container.ToString() + " | "; } containers += " *"; Console.WriteLine("Usage: ItemCacheTool [ | ]"); Console.WriteLine("\t = Check | Cleanup | Compare | Delete | List | Status"); Console.WriteLine("\t = Cloud | Local | *"); Console.WriteLine("\t = {0}", containers); Console.WriteLine("\t [ | ] = specifies item(s) to delete."); } /// /// Provides a status report of the number of items in the specified /// cache containers, and optionally a list of those items. /// /// Caches to examine. /// Containers in those caches to examine. /// Whether to list the cache contents. private static void CacheStatus( IItemCache[] queriedCaches, ItemCacheContainer[] queriedContainers, bool listContents) { string lineTerminator = "."; if (listContents) { lineTerminator = ":"; } foreach (IItemCache cache in queriedCaches) { foreach (ItemCacheContainer container in queriedContainers) { HashSet items = cache.GetItemsInContainer(container); Console.WriteLine("{0} cache {1} container holds {2} items{3}", cache.Name, container.ToString(), items.Count, lineTerminator); if (listContents) { foreach (string item in items) { ////Console.WriteLine("Item: {0}, Date:{1}", item, cache.GetItemLastModifiedTime(container, item)); Console.WriteLine(item); } Console.WriteLine(); } } Console.WriteLine(); } } /// /// Compares the contents of two caches. /// /// Caches to compare. /// Containers in those caches to compare. private static void CompareCacheContainers( IItemCache[] queriedCaches, ItemCacheContainer[] queriedContainers) { foreach (ItemCacheContainer container in queriedContainers) { IItemCache cacheA = queriedCaches[0]; IItemCache cacheB = queriedCaches[1]; HashSet cacheAItems = cacheA.GetItemsInContainer(container); HashSet cacheBItems = cacheB.GetItemsInContainer(container); Console.WriteLine("There are {0} items in the {1} cache {2} container.", cacheAItems.Count, cacheA.Name, container.ToString()); Console.WriteLine("There are {0} items in the {1} cache {2} container.", cacheBItems.Count, cacheB.Name, container.ToString()); HashSet syncedItems = new HashSet(cacheAItems); syncedItems.IntersectWith(cacheBItems); Console.WriteLine("There are {0} items present in both cache's {1} container.", syncedItems.Count, container); Console.WriteLine(); } } /// /// Deletes the given items from the given caches and containers. /// /// Caches to look in. /// Containers to look in. /// Items to delete. private static void DeleteItems( IItemCache[] queriedCaches, ItemCacheContainer[] queriedContainers, string queriedItems) { if (queriedItems == "*") { if (!DeleteItemsConfirmation()) { return; } } foreach (IItemCache cache in queriedCaches) { foreach (ItemCacheContainer container in queriedContainers) { if (queriedItems == "*") { HashSet items = cache.GetItemsInContainer(container); foreach (string item in items) { cache.DeleteItem(container, item); } } else { cache.DeleteItem(container, queriedItems); } } } } /// /// Deletes the items from the given caches and containers /// that have an earlier last modified time than the given one. /// /// Caches to look in. /// Containers to look in. /// Date to compare against. private static void DeleteItems( IItemCache[] queriedCaches, ItemCacheContainer[] queriedContainers, DateTimeOffset queriedDate) { if (!DeleteItemsConfirmation()) { return; } foreach (IItemCache cache in queriedCaches) { foreach (ItemCacheContainer container in queriedContainers) { HashSet items = cache.GetItemsInContainer(container); foreach (string item in items) { DateTimeOffset? lastModified = cache.GetItemLastModifiedTime(container, item); if (lastModified.HasValue && (lastModified.Value.CompareTo(queriedDate) < 0)) { cache.DeleteItem(container, item); } } } } } /// /// Asks the user for confirmation that deleting a large number of cache items is okay. /// /// True if deletion is okay, false otherwise. private static bool DeleteItemsConfirmation() { string input; string annoyingConfirmationString = "Yes I mean to do this!"; Console.WriteLine("You are about to delete a potentially large number of cache items!"); Console.WriteLine("To proceed, please enter '{0}':", annoyingConfirmationString); input = Console.ReadLine(); if (input != annoyingConfirmationString) { Console.WriteLine("Your input didn't match. Exiting without deleting anything."); return false; } return true; } /// /// Dumps the given items from the given caches and containers. /// /// Caches to look in. /// Containers to look in. /// Items to dump. private static void DumpItems( IItemCache[] queriedCaches, ItemCacheContainer[] queriedContainers, string queriedItems) { foreach (IItemCache cache in queriedCaches) { foreach (ItemCacheContainer container in queriedContainers) { if (queriedItems == "*") { HashSet items = cache.GetItemsInContainer(container); foreach (string item in items) { DumpItem(cache, container, item); } } else { DumpItem(cache, container, queriedItems); } } } } /// /// Dumps the given item from the given cache and container. /// /// Cache to look in. /// Container to look in. /// Item to dump. private static void DumpItem(IItemCache cache, ItemCacheContainer container, string item) { #if true byte[] content = cache.FetchItem(container, item); if (content != null) { BinaryWriter writer = new BinaryWriter(Console.OpenStandardOutput()); writer.Write(content); writer.Close(); } #endif #if false ResultSummaryRecord record = FetchRecord(cache, container, item); if (record != null) { Console.WriteLine(); Console.WriteLine("IsVerificationTimeout = {0}", record.IsVerificationTimeout); Console.WriteLine("IsFailure = {0}", record.IsFailure); } else { Console.WriteLine(); Console.WriteLine("FetchRecord failed for {0}", item); } #endif } /// /// Checks the given cache(s) Results and FailedResults for goodness. /// /// Caches to check. /// Whether to cleanup after bad cache entries. private static void CheckResults( IItemCache[] queriedCaches, bool cleanup) { // We can do this for Local, Cloud, or both. foreach (IItemCache cache in queriedCaches) { // We have one Objects container for objects referenced by // results in both the Results and FailedResults containers. HashSet objects = cache.GetItemsInContainer(ItemCacheContainer.Objects); // Likewise, we have only one Sources container. // REVIEW: Should a "source" ever show up as a verb result? HashSet sources = cache.GetItemsInContainer(ItemCacheContainer.Sources); // We initialize the orphanedObjects set to all objects and // then remove objects from the set when we find them listed // in a result (stored in either Results or FailedResults). HashSet orphanedObjects = cache.GetItemsInContainer(ItemCacheContainer.Objects); // We check both successful and failed results. foreach (ItemCacheContainer resultsContainer in new ItemCacheContainer[] { ItemCacheContainer.Results, ItemCacheContainer.FailedResults }) { HashSet parseErrors = new HashSet(); // Misfiled results (i.e. failures in Results container or // non-failures in FailedResults container). HashSet misfiledResults = new HashSet(); // Results that are missing one or more ouput objects. HashSet resultsMissingOutputs = new HashSet(); HashSet missingOutputHashes = new HashSet(); HashSet missingOutputPaths = new HashSet(); int timeouts = 0; int failures = 0; int missing = 0; HashSet results = cache.GetItemsInContainer(resultsContainer); foreach (string result in results) { ResultSummaryRecord record = FetchRecord(cache, resultsContainer, result); if (record == null) { Console.WriteLine("Parse error in {0}.", result); parseErrors.Add(result); } else { if (record.IsFailure) { if (resultsContainer == ItemCacheContainer.Results) { // We shouldn't have any failures in Results! misfiledResults.Add(result); } if (record.IsVerificationTimeout) { ////Console.WriteLine("Timeout in {0}.", result); timeouts++; } else { ////Console.WriteLine("Failure in {0}.", result); failures++; } } else if (resultsContainer == ItemCacheContainer.FailedResults) { // We should only have failures in FailedResults! misfiledResults.Add(result); } // Verify each output is in the cache. bool hasMissingOuputs = false; foreach (BuildObjectValuePointer output in record.Outputs) { if (objects.Contains(output.ObjectHash)) { // Output present in object cache. // Remove it from orphaned objects list. orphanedObjects.Remove(output.ObjectHash); } else if (sources.Contains(output.ObjectHash)) { // Output present in sources cache. Console.WriteLine("Has 'source' file listed as an output: {0}!", result); } else { // Output missing from both object and sources caches. hasMissingOuputs = true; missingOutputHashes.Add(output.ObjectHash); missingOutputPaths.Add(output.RelativePath); missing++; Console.WriteLine("Missing Output Listed in {0}, Object {1} ({2}).", result, output.ObjectHash, output.RelativePath); } } if (hasMissingOuputs) { resultsMissingOutputs.Add(result); } } } Console.WriteLine(); Console.WriteLine("Checked {0} results in {1} cache {2} container:", results.Count, cache.Name, resultsContainer.ToString()); Console.WriteLine("Corrupted (parsing errors or otherwise unreadable): {0}", parseErrors.Count); Console.WriteLine("Filed in wrong container: {0}", misfiledResults.Count); Console.WriteLine("Timeouts: {0}, Other failures: {1}, Total failures: {2}", timeouts, failures, timeouts + failures); Console.WriteLine("Missing at least one output object: {0}", resultsMissingOutputs.Count); Console.WriteLine("Total missing output objects: {0}, Unique contents: {1}, Unique paths: {2}", missing, missingOutputHashes.Count, missingOutputPaths.Count); Console.WriteLine(); if (cleanup) { if (misfiledResults.Count != 0) { Console.Write("Deleting misfiled results..."); foreach (string misfiledResult in misfiledResults) { cache.DeleteItem(resultsContainer, misfiledResult); } Console.WriteLine("Done."); } if (resultsMissingOutputs.Count != 0) { Console.Write("Deleting results with missing outputs..."); foreach (string resultMissingOutputs in resultsMissingOutputs) { cache.DeleteItem(resultsContainer, resultMissingOutputs); } Console.WriteLine("Done."); } Console.WriteLine(); } } // REVIEW: in at least one instance, we cache an intermediate // object that isn't referenced by a result. That instance is // DafnyIncludes.ExpandDafny(), which is called from // DafnyCompileOneVerb. This is to allow cloud execution of the // process invoke part of the verb's execution (with the dafny // expansion happening in the verb's getWorker() method). Since // ExpandDafny() is a work-around for a Dafny issue, it's not // clear whether we should further accommodate this in the build // system (i.e. by making ExpandDafny its own verb) or not. // At any rate, having orphaned objects is not necessarily bad. Console.WriteLine("Orphaned objects not listed in any result: {0}", orphanedObjects.Count); if (cleanup) { Console.WriteLine(); if (orphanedObjects.Count != 0) { Console.Write("Deleting orphaned objects..."); foreach (string orphanedObject in orphanedObjects) { cache.DeleteItem(ItemCacheContainer.Objects, orphanedObject); } Console.WriteLine("Done."); } } } } /// /// Retrieves the requested result from the given cache. /// /// Cache to query. /// Container to query. /// Result to get. /// The requested ResultSummaryRecord, or null if not found. private static ResultSummaryRecord FetchRecord(IItemCache cache, ItemCacheContainer container, string itemHash) { byte[] result = cache.FetchItem(container, itemHash); if (result != null) { MemoryStream resultStream = new MemoryStream(result); try { using (StreamReader inReader = new StreamReader(resultStream)) { string xmlSummary = inReader.ReadToEnd(); ResultSummaryRecord record = ResultSummaryRecord.FromXml(xmlSummary); if (record == null) { Console.WriteLine("FromXml failed for {0}", itemHash); } return record; } } catch (System.Xml.XmlException ex) { Console.WriteLine("Malformed xml in {0}: {1}", itemHash, ex.ToString()); return null; } finally { resultStream.Dispose(); } } else { Console.WriteLine("FetchItem failed for {0}", itemHash); return null; } } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/ItemCacheTool/Properties/AssemblyInfo.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("ItemCacheTool")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("ItemCacheTool")] [assembly: AssemblyCopyright("Copyright © 2014")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("47dce4f0-18af-4c9e-b177-4ae324563ed6")] // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/.gitignore ================================================ *.user ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/AbstractId.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; internal class AbstractId { private const int MASTER_VERSION = 3; // Bump this to invalidate every verb in all caches. private string verbName; private int version; private string abstractOnly; // PoundDefines should appear in both abstract and concrete descriptions: // abstract because we run one verb with multiple poundDefine configurations, // and concrete because the variation appears only in this parameter to the // verb, not in any input file contents. private PoundDefines poundDefines; private string concrete; public AbstractId(string verbName, int version, string abstractOnly, PoundDefines poundDefines = null, string concrete = null) { this.verbName = verbName; this.version = version + MASTER_VERSION; this.abstractOnly = abstractOnly; this.poundDefines = poundDefines == null ? PoundDefines.empty() : poundDefines; this.concrete = concrete; } public override bool Equals(object obj) { AbstractId other = obj as AbstractId; if (other != null) { return this.verbName == other.verbName && this.version == other.version && this.abstractOnly == other.abstractOnly && this.poundDefines.Equals(other.poundDefines) && this.concrete == other.concrete; } else { return false; } } public override int GetHashCode() { return this.ToString().GetHashCode(); } public override string ToString() { if (this.concrete == null) { return string.Format("{0}(#{1},{2},{3})", this.verbName, this.version, this.abstractOnly, this.poundDefines.getAbstractIdString()); } else { return string.Format("{0}(#{1},{2},{3},{4})", this.verbName, this.version, this.abstractOnly, this.poundDefines.getAbstractIdString(), this.concrete); } } public int CompareTo(object other) { return this.ToString().CompareTo(((AbstractId)other).ToString()); } public string getConcreteId() { // The entire purpose of this class is to avoid encoding the input filename in a verb's concrete identity, // instead encoding it via the input's hash. That enables two verbs to have the same hash when they have // the same configuration, and hence converge -- we can reuse the outputs. // Except that the design is presently flawed: they'd have the same output contents, but not the same // output locations. Until we work that out, I'm neutering this convergence opportunity to preserve // soundness. (--jonh) return this.ToString(); ////if (this.concrete == null) { //// return string.Format("{0}(#{1},{2})", this.verbName, this.version, this.poundDefines); ////} else { //// return string.Format("{0}(#{1},{2},{3})", this.verbName, this.version, this.poundDefines, this.concrete); ////} } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/AnnotationScanner.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Text.RegularExpressions; internal class AnnotationScanner { private BuildObject inputObject; private List annotations; private bool complete; // Constructor for emitting new/code-assembled annotations. public AnnotationScanner() { this.inputObject = null; this.annotations = new List(); this.complete = false; } public AnnotationScanner(BuildObject inputObject) { this.inputObject = inputObject; this.annotations = new List(); Regex re = new Regex("]*)/>"); using (TextReader tr = BuildEngine.theEngine.Repository.OpenRead(inputObject)) { while (true) { string line = tr.ReadLine(); if (line == null) { break; } Match match = re.Match(line); if (match.Success) { string[] arguments = match.Groups[1].ToString().Split(null).Where(s => s.Length > 0).ToArray(); this.annotations.Add(arguments); } } } this.complete = true; } public void addAnnotation(string[] annotation) { Util.Assert(!this.complete); this.annotations.Add(annotation); } public string emit(string commentToken) { this.complete = true; StringBuilder sb = new StringBuilder(); foreach (string[] annotation in this.annotations) { sb.AppendLine(commentToken + ""); } return sb.ToString(); } public IEnumerable getAnnotations(string label) { return this.annotations.Where(sa => sa[0].Equals(label)); } // Look for 0 or 1 instance of a single-valued annotation. public string getTheAnnotation(string label, string defaultValue) { IEnumerable anns = this.getAnnotations(label); if (anns.Count() == 0) { return defaultValue; } string[] ann = anns.First(); if (ann.Length != 2) { throw new SourceConfigurationError( string.Format( "Annotation {0} in file {1} should have exactly one argument", ann[0], this.inputObject.getRelativePath())); } return ann[1]; } internal static void transferAnnotations(WorkingDirectory workingDirectory, BuildObject source, BuildObject dest, string commentToken) { new AnnotationScanner(source).injectAnnotations(workingDirectory, dest, commentToken); } // REVIEW: Make this private? internal void injectAnnotations(WorkingDirectory workingDirectory, BuildObject dest, string commentToken) { string annotations = this.emit(commentToken); // REVIEW: Improve upon this round-about way of prepending to a file? string destStr = File.ReadAllText(workingDirectory.PathTo(dest)); File.Delete(workingDirectory.PathTo(dest)); File.WriteAllText(workingDirectory.PathTo(dest), annotations + destStr); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/App.config ================================================  ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/AsmRewriterVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; internal class AsmRewriterVerb : Verb, IProcessInvokeAsyncVerb, IAsmProducer { public const string WASM_EXTN = ".wasm"; private const int version = 1; private BoogieAsmLinkVerb asmVerb; private AbstractId abstractId; private BuildObject asmFileOut; private BuildObject asmFileIn; private BuildObject pythonScript; public AsmRewriterVerb(BoogieAsmLinkVerb asmVerb) { this.asmVerb = asmVerb; this.asmFileIn = asmVerb.getAsmFile(); this.asmFileOut = this.asmFileIn.makeOutputObject(WASM_EXTN); this.abstractId = new AbstractId(this.GetType().Name, version, this.asmFileOut.ToString()); this.pythonScript = new SourcePath("tools\\scripts\\build-standalone-asm.py", SourcePath.SourceType.Tools); } public override AbstractId getAbstractIdentifier() { return this.abstractId; } public BuildObject getAsmFile() { return this.asmFileOut; } public override IEnumerable getDependencies(out DependencyDisposition ddisp) { ddisp = DependencyDisposition.Complete; return new List() { this.asmFileIn, this.pythonScript }; } public override IEnumerable getVerbs() { return new List() { this.asmVerb }; } public override IEnumerable getOutputs() { return new List() { this.getAsmFile() }; } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { List args = new List() { this.pythonScript.getRelativePath(), this.asmFileIn.getRelativePath() }; string python_exe = @"C:\Python27\pythonw.exe"; if (!File.Exists(python_exe)) { throw new FileNotFoundException("Missing python executable: " + python_exe + ". Try installing from: https://www.python.org/"); } return new ProcessInvokeAsyncWorker( workingDirectory, this, python_exe, args.ToArray(), ProcessExitCodeHandling.NonzeroIsFailure, getDiagnosticsBase(), allowAbsoluteExe: true, captureStdout: this.asmFileOut); } public Disposition Complete(WorkingDirectory workingDirectory, double cpuTimeSeconds, string stdout, string stderr, Disposition disposition) { return disposition; } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/BackgroundWorker.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; /// /// Type of procedure that the background worker thread runs. /// /// Some argument. /// Another argument. public delegate void BackgroundWorkerProcedure(object argument1, object argument2); /// /// Represents a single background worker thread that sequentially performs /// the work added to its queue. /// /// /// This class is not related to System.ComponentModel.BackgroundWorker, /// which provides different functionality. /// public class BackgroundWorker : IDisposable { /// /// Thread that performs the background work. /// private Thread workerThread; /// /// Queue of work for background worker to perform. /// private Queue workQueue; /// /// Lock protecting the work queue. /// private Mutex workQueueLock; /// /// Event that is signalled when new items are placed on the workQueue. /// private AutoResetEvent workQueueHasNewWork; /// /// Count of work items queued to this BackgroundWorker. /// private volatile uint workItemsQueued; /// /// Count of work item procedures performed by this BackgroundWorker. /// private volatile uint workItemsPerformed; /// /// Count of work item procedures known to have failed. /// private volatile uint workItemsFailed; /// /// Flag indicating whether or not the worker thread should exit. /// private volatile bool ourWorkIsNotDone; /// /// Flag indicating whether or not Dispose has already been called. /// private bool disposed; /// /// Initializes a new instance of the BackgroundWorker class. /// public BackgroundWorker() { this.workQueue = new Queue(); this.workQueueLock = new Mutex(); this.workQueueHasNewWork = new AutoResetEvent(false); this.workItemsQueued = 0; this.workItemsPerformed = 0; this.workItemsFailed = 0; this.ourWorkIsNotDone = true; this.disposed = false; this.workerThread = new Thread(new ThreadStart(this.WorkerThreadMain)); // REVIEW: Start worker thread only after the first item is queued? this.workerThread.Start(); } /// /// Gets the count of work items queued to this BackgroundWorker. /// public uint GetWorkItemsQueued { get { return this.workItemsQueued; } } /// /// Gets the count of work item procedures performed by this /// BackgroundWorker. /// public uint GetWorkItemsPerformed { get { return this.workItemsPerformed; } } /// /// Gets the count of work item procedures known to have failed. /// public uint GetWorkItemsFailed { get { return this.workItemsFailed; } } /// /// Adds new work to the background worker's work queue. /// /// /// Procedure the background worker will run. /// /// First argument for procedure. /// Second argument for procedure. public void QueueWork(BackgroundWorkerProcedure procedure, object argument1, object argument2) { BackgroundWorkerQueueItem workItem = new BackgroundWorkerQueueItem(procedure, argument1, argument2); this.workQueueLock.WaitOne(); this.workQueue.Enqueue(workItem); this.workItemsQueued++; this.workQueueLock.ReleaseMutex(); this.workQueueHasNewWork.Set(); } /// /// Tells the worker thread to stop running after completing the /// currently queued work items. /// public void StopWork() { this.QueueWork(this.StopWorkerThread, null, null); } /// /// Wait for the worker thread to exit after a StopWork request. /// /// /// This routine is primarily for making sure the worker thread has /// completed operation before collecting stats from it /// (i.e. calling 'GetWorkItemsPerformed'). Since we don't mark our /// worker thread as a "background" thread, the process will not exit /// until after our thread exits. So this method is not needed for the /// purpose of keeping the main thread and thus process alive until the /// worker thread is done. /// public void WaitForCompletion() { this.workerThread.Join(); } /// /// Releases resources. /// public void Dispose() { this.Dispose(true); GC.SuppressFinalize(this); } /// /// Releases unmanaged and (optionally) managed resources. /// /// Whether or not to release managed resources. protected virtual void Dispose(bool disposing) { if (this.disposed) { return; } if (disposing) { this.workQueueLock.Dispose(); this.workQueueHasNewWork.Dispose(); } this.disposed = true; } /// /// Special BackgroundWorkerProcedure for stopping the worker thread. /// /// /// Note that this procedure ends up being counted in the statistics /// we keep about the number of work items queued/performed. /// /// The parameter is not used. /// The parameter is not used. private void StopWorkerThread( object unused1, object unused2) { this.ourWorkIsNotDone = false; } /// /// Procedure performed by the background worker thread. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "We really do want to catch all exceptions in this case")] private void WorkerThreadMain() { List toDoList = new List(); // - // Run until we're told to stop. // - while (this.ourWorkIsNotDone) { // - // Wait for new work to be added to the queue. // - if (this.workQueueHasNewWork.WaitOne()) { toDoList.Clear(); // - // Pull all queued work items off the global work queue // (while holding the lock), and place them on our // thread-local toDoList. // - this.workQueueLock.WaitOne(); while (this.workQueue.Count > 0) { toDoList.Add(this.workQueue.Dequeue()); } this.workQueueLock.ReleaseMutex(); // - // Do the requested work. // - foreach (BackgroundWorkerQueueItem workItem in toDoList) { try { workItem.Procedure(workItem.Argument1, workItem.Argument2); this.workItemsPerformed++; } catch { // - // Swallow all errors caused by the work item. // But count how often this happens. // - this.workItemsFailed++; } } } } } /// /// Represents a work item on the background worker's work queue. /// private class BackgroundWorkerQueueItem { /// /// The procedure the background worker runs. /// private BackgroundWorkerProcedure procedure; /// /// The first argument to pass to the procedure. /// private object argument1; /// /// The second argument to pass to the procedure. /// private object argument2; /// /// Initializes a new instance of the BackgroundWorkerQueueItem class. /// /// Procedure to run. /// First argument for procedure. /// Second argument for procedure. public BackgroundWorkerQueueItem( BackgroundWorkerProcedure procedure, object argument1, object argument2) { this.procedure = procedure; this.argument1 = argument1; this.argument2 = argument2; } /// /// Gets the procedure the background worker runs. /// public BackgroundWorkerProcedure Procedure { get { return this.procedure; } } /// /// Gets the first argument to pass to the procedure. /// public object Argument1 { get { return this.argument1; } } /// /// Gets the second argument to pass to the procedure. /// public object Argument2 { get { return this.argument2; } } } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/BasmObligationIncludes.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; internal class BasmObligationIncludes : IIncludeFactory { private IIncludePathContext includePathSearcher; private BeatIncludes directIncludes; public BasmObligationIncludes(IIncludePathContext includePathSearcher) { this.includePathSearcher = includePathSearcher; this.directIncludes = new BeatIncludes(includePathSearcher); } public IEnumerable getIncludes(BuildObject beatsrc) { IHasher hasher = BuildEngine.theEngine.getHasher(); OrderPreservingSet includes = new OrderPreservingSet(); BuildObject ifcFile = hasher.search(this.includePathSearcher, beatsrc.getFileNameWithoutExtension(), ModPart.Ifc); BuildObject impFile = hasher.search(this.includePathSearcher, beatsrc.getFileNameWithoutExtension(), ModPart.Imp); Util.Assert(ifcFile.Equals(beatsrc) || impFile.Equals(beatsrc)); includes.AddRange(this.directIncludes.getBasmIncludes(ifcFile)); includes.AddRange(this.directIncludes.getBasmIncludes(impFile)); return includes; } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/BasmTransitiveDepsVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; internal class BasmTransitiveDepsVerb : TransitiveDepsVerb { private IContextGeneratingVerb contextVerb; public BasmTransitiveDepsVerb(IContextGeneratingVerb contextVerb, BuildObject input) : base(input) { this.contextVerb = contextVerb; } protected override TransitiveDepsVerb factory(BuildObject obj) { return new BasmTransitiveDepsVerb(this.contextVerb, obj); } protected override void extendDeps(List deps) { deps.Add(this.contextVerb.getContextOutput()); } protected override IIncludeFactory getIncludeFactory() { ContextContents context = (ContextContents) BuildEngine.theEngine.Repository.FetchVirtual(this.contextVerb.getContextOutput()); return new BasmObligationIncludes(context.Context); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/BatchVerifyVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; using System.Linq; internal class BatchVerifyVerb : Verb, IObligationsProducer { private const string BATCH_EXTN = ".batch"; private const int version = 1; private BuildObject outputObject; private HashSet producers; private AbstractId abstractId; private BatchMode mode; // REVIEW: Never used? private List deps; public BatchVerifyVerb(SourcePath batch_file, BatchMode mode, VerificationRequest verificationRequest, DafnyCCVerb.FramePointerMode useFramePointer) { this.mode = mode; this.producers = new HashSet(); foreach (string line in File.ReadAllLines(IronRootDirectory.PathTo(batch_file))) { if (line.Equals("") || line[0] == '#') { continue; } SourcePath src = new SourcePath(line); switch (mode) { case BatchMode.DAFNY: if (verificationRequest.verifyMode != VerificationRequest.VerifyMode.Verify) { throw new UserError("BatchVerify DAFNY only supports full verification (but maybe we should add selective?)"); } this.producers.Add(new DafnyVerifyTreeVerb(src)); break; case BatchMode.APP: this.producers.Add(new IroncladAppVerb(src, IroncladAppVerb.TARGET.BARE_METAL, useFramePointer, verificationRequest)); break; default: throw new Exception("Unknown batch file type"); } } string parameters = mode.ToString() + "," + verificationRequest.ToString(); this.outputObject = batch_file.makeLabeledOutputObject(parameters, BATCH_EXTN + VerificationObligationList.VOL_EXTN); this.abstractId = new AbstractId(this.GetType().Name, version, batch_file.ToString(), concrete: parameters); } public BatchVerifyVerb(BuildObject batch_label, HashSet producers, BatchMode mode) { this.mode = mode; this.producers = producers; this.outputObject = batch_label.makeOutputObject(BATCH_EXTN + VerificationObligationList.VOL_EXTN); this.abstractId = new AbstractId(this.GetType().Name, version, batch_label.ToString(), concrete: mode.ToString()); } public enum BatchMode { DAFNY, APP } public override AbstractId getAbstractIdentifier() { return this.abstractId; } public BuildObject getObligationSet() { return this.outputObject; } public override IEnumerable getDependencies(out DependencyDisposition ddisp) { if (this.deps == null) { this.deps = new List(); foreach (IObligationsProducer producer in this.producers) { this.deps.Add(producer.getObligationSet()); } } ddisp = DependencyDisposition.Complete; return this.deps; } public override IEnumerable getVerbs() { // Pass this request upstream to expose upstream verbs. HashSet upstreamVerbs = new HashSet(); foreach (IVerb producer in this.producers) { upstreamVerbs.UnionWith(producer.getVerbs()); upstreamVerbs.Add(producer); } return upstreamVerbs; } public override IEnumerable getOutputs() { return new HashSet() { this.outputObject }; } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { // Coallesce the VerificationObligationLists from each producer into a single result set IEnumerable master = new HashSet(); foreach (IObligationsProducer producer in this.producers) { VerificationObligationList vol = VerificationObligationList.fetch(producer.getObligationSet()); master = master.Union(vol.getVerificationObligations()); } VerificationObligationList myVOL = new VerificationObligationList(master); myVOL.store(workingDirectory, this.outputObject); return new VerbSyncWorker(workingDirectory, new Fresh()); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/BeatExtensions.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; public enum ModPart { Ifc, Imp, Unknown } public static class ModPartExtensions { public const string ModPartIfc = ".ifc"; public const string ModPartImp = ".imp"; public const string ModPartUnknown = ".unk"; public static string ExtnStr(this ModPart modPart) { switch (modPart) { case ModPart.Ifc: return ModPartIfc; case ModPart.Imp: return ModPartImp; case ModPart.Unknown: return ModPartUnknown; default: return null; } } } internal class BeatExtensions { public const string BEAT_EXTN = ".beat"; public const string BEATIFC_EXTN = ".ifc.beat"; public const string BEATIMP_EXTN = ".imp.beat"; public static ModPart whichPart(string filenameOrExtn) { string modPartStr = "." + filenameOrExtn.Split('.')[1]; switch (modPartStr) { case ModPartExtensions.ModPartIfc: return ModPart.Ifc; case ModPartExtensions.ModPartImp: return ModPart.Imp; default: return ModPart.Unknown; } } public static BuildObject makeOutputObject(BuildObject input, string typeExtn) { return makeLabeledOutputObject(input, null, typeExtn); } internal static BuildObject makeLabeledOutputObject(BuildObject input, string appLabel, string typeExtn) { ModPart part = whichPart(input); if (part == ModPart.Unknown) { // Input must be a raw boogie file. Util.Assert(input.getExtension().EndsWith(BoogieVerb.BPL_EXTN)); return input.makeLabeledOutputObject(appLabel, typeExtn); } else { return input.makeLabeledOutputObject(appLabel, part.ExtnStr() + typeExtn); } } public static ModPart whichPart(BuildObject obj) { return whichPart(obj.getExtension()); } private static IEnumerable getBeatFlavoredShallowIncludesLabeled( IContextGeneratingVerb contextVerb, BuildObject rootObj) { ContextContents context = (ContextContents) BuildEngine.theEngine.Repository.FetchVirtual(contextVerb.getContextOutput()); BeatIncludes includes = new BeatIncludes(context.Context); OrderPreservingSet result = new OrderPreservingSet( includes.getLabeledIncludes(rootObj)); if (BeatExtensions.whichPart(rootObj) == ModPart.Imp) { BuildObject rootIfc = context.Context.search(rootObj.getFileNameWithoutExtension(), ModPart.Ifc); result.Add(new BeatIncludes.LabeledInclude(BeatIncludes.ImportFilter.ForBeatOrBasm, rootIfc)); } return result; } public static IEnumerable getBeatFlavoredShallowIncludes( IContextGeneratingVerb contextVerb, BuildObject rootObj, BeatIncludes.ImportFilter importFilter) { return getBeatFlavoredShallowIncludesLabeled(contextVerb, rootObj) .Where(li => importFilter == BeatIncludes.ImportFilter.ForBasmOnly || li.importFilter == BeatIncludes.ImportFilter.ForBeatOrBasm) .Select(li => li.buildObject); } public static void propagatePrivateImports( WorkingDirectory workingDirectory, IContextGeneratingVerb contextVerb, BuildObject srcobj, BuildObject dstobj) { // Rewrite basm output to propagate any import statements from the beat file. // TODO this step really should be a beat function, not part of the build system. IEnumerable beatImports = getBeatFlavoredShallowIncludesLabeled(contextVerb, srcobj); StringBuilder sb = new StringBuilder(); foreach (BeatIncludes.LabeledInclude li in beatImports) { sb.Append("//-"); sb.Append(li.importFilter == BeatIncludes.ImportFilter.ForBasmOnly ? "private-basmonly-import" : "private-import"); sb.Append(" "); sb.Append(li.buildObject.getFileNameWithoutExtension()); sb.AppendLine(";"); } // REVIEW: Improve upon this round-about way of prepending to a file? string beatOutput = File.ReadAllText(workingDirectory.PathTo(dstobj)); File.Delete(workingDirectory.PathTo(dstobj)); File.WriteAllText(workingDirectory.PathTo(dstobj), sb.ToString() + beatOutput); } // This used to use a BeatTransitiveDepsVerb, but we're going with shallow dependencies at the moment. // We may want to restore that behavior later, if we can get some sane transitive dep tree worked out for // Verve code. // The returned list belongs to the caller to .Add() to as desired. // TODO this really needs to be factored to supply the actual Beat-flavored references separately // from the auxiliary deps (transitive dep objects and context dep objects), so we don't have // client code trying to filter back out the part it wants. Brittle. public static OrderPreservingSet getBeatFlavoredShallowDependencies( IContextGeneratingVerb contextVerb, BuildObject rootObj, out DependencyDisposition ddisp, BeatIncludes.ImportFilter filter) { OrderPreservingSet result = new OrderPreservingSet(); result.Add(contextVerb.getContextOutput()); try { result.AddRange(getBeatFlavoredShallowIncludes(contextVerb, rootObj, filter)); ddisp = DependencyDisposition.Complete; } catch (ObjectNotReadyException) { ddisp = DependencyDisposition.Incomplete; } catch (ObjectFailedException) { ddisp = DependencyDisposition.Failed; } result.Add(rootObj); // root really needs to go at the end of the list. return result; } public static BasmTransitiveDepsVerb getBasmFlavoredTransitiveDepVerb(IContextGeneratingVerb context, BuildObject rootObj) { return new BasmTransitiveDepsVerb(context, rootObj); } // The list belongs to the caller to .Add() to as desired. public static OrderPreservingSet getBasmFlavoredTransitiveDependencies(IContextGeneratingVerb context, BuildObject rootObj, out DependencyDisposition ddisp) { OrderPreservingSet result = new OrderPreservingSet(); TransitiveDepsVerb depsVerb = getBasmFlavoredTransitiveDepVerb(context, rootObj); result.Add(depsVerb.depsObj()); result.AddRange(depsVerb.getAvailableDeps(out ddisp)); // NB add root object at end of list, to keep it in definition-dependency order. result.Add(rootObj); return result; } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/BeatIncludes.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Text.RegularExpressions; internal class BeatIncludes { private static CachedHash fetchModuleCaches = new CachedHash(delegate(IIncludePathContext context) { return new FetchModuleCache(context); }); private IIncludePathContext includePathSearcher; public BeatIncludes(IIncludePathContext includePathSearcher) { this.includePathSearcher = includePathSearcher; } public enum ImportFilter { ForBeatOrBasm, ForBasmOnly } public static List parseLabeledIncludes(IIncludePathContext context, BuildObject beatsrc) { ////Logger.WriteLine("parseLabeledIncludes " + beatsrc.getRelativePath() + " context " + context.GetHashCode()); List outlist = new List(); ////Regex re = new Regex("^\\s*import\\s*([^\\s,]*(,\\s*[^\\s,]*)*)\\s*;"); // TODO allow commented-out imports until Beat accepts (ignores) them in ifcs files. Regex import_re = new Regex("^[\\s/-]*private-import\\s*([^\\s,]*(,\\s*[^\\s,]*)*)\\s*;"); Regex basmonly_re = new Regex("^[\\s/-]*private-basmonly-import\\s*([^\\s,]*(,\\s*[^\\s,]*)*)\\s*;"); FetchModuleCache fmcache = fetchModuleCaches.get(context); using (TextReader tr = BuildEngine.theEngine.Repository.OpenRead(beatsrc)) { while (true) { string line = tr.ReadLine(); if (line == null) { break; } Match match = import_re.Match(line); if (match.Success) { outlist.Add(new LabeledInclude(ImportFilter.ForBeatOrBasm, fmcache.get(match.Groups[1].ToString()))); } match = basmonly_re.Match(line); if (match.Success) { outlist.Add(new LabeledInclude(ImportFilter.ForBasmOnly, fmcache.get(match.Groups[1].ToString()))); } } ////Logger.WriteLine(string.Format("{0} includes {1} things", dfysource.getFilesystemPath(), outlist.Count)); return outlist; } } public List getLabeledIncludes(BuildObject beatsrc) { ////return caches.get(includePathSearcher).get(beatsrc); return this.computeLabeledIncludes(beatsrc); } public IEnumerable getBasmIncludes(BuildObject beatsrc) { return this.computeLabeledIncludes(beatsrc).Select(li => li.buildObject); } protected List computeLabeledIncludes(BuildObject beatsrc) { return BuildEngine.theEngine.getHasher().getParsedIncludes(this.includePathSearcher, beatsrc); } private BuildObject fetchModule(string module) { ////Logger.WriteLine("fetchmodule " + module + " ctx " + includePathSearcher.GetHashCode()); string includedModule = module.Trim(); BuildObject path = this.includePathSearcher.search(includedModule); if (path == null) { throw new SourceConfigurationError( string.Format( "Cannot find module {0} in search path {1}", includedModule, this.includePathSearcher)); } return path; } public class LabeledInclude { public ImportFilter importFilter; public BuildObject buildObject; public LabeledInclude(ImportFilter importFilter, BuildObject buildObject) { this.importFilter = importFilter; this.buildObject = buildObject; } } private class FetchModuleCache { private CachedHash cache; private BeatIncludes beatIncludes; public FetchModuleCache(IIncludePathContext context) { this.beatIncludes = new BeatIncludes(context); this.cache = new CachedHash(this.fetchModule); } public BuildObject get(string module) { return this.cache.get(module); } private BuildObject fetchModule(string module) { return this.beatIncludes.fetchModule(module); } } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/BeatVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; internal class BeatVerb : Verb, IProcessInvokeAsyncVerb { private const int version = 34; private static NmakeVerb beatBuildExecutableVerb = new NmakeVerb(new SourcePath("tools\\Beat\\makefile", SourcePath.SourceType.Tools)); private IContextGeneratingVerb contextVerb; private BuildObject beatobj; private string appLabel; private AbstractId abstractId; public BeatVerb(IContextGeneratingVerb contextVerb, BuildObject beatobj, string appLabel) { this.contextVerb = contextVerb; this.beatobj = beatobj; this.appLabel = appLabel; this.abstractId = new AbstractId(this.GetType().Name, version, beatobj.ToString(), contextVerb.getPoundDefines(), concrete: appLabel); } public static bool isBeat(BuildObject obj) { return obj.getExtension().Equals(BeatExtensions.BEATIFC_EXTN) || obj.getExtension().Equals(BeatExtensions.BEATIMP_EXTN); } public override IEnumerable getDependencies(out DependencyDisposition ddisp) { OrderPreservingSet deps = BeatExtensions.getBeatFlavoredShallowDependencies( this.contextVerb, this.beatobj, out ddisp, BeatIncludes.ImportFilter.ForBeatOrBasm); deps.Add(this.getBeatExecutable()); return deps; } public override IEnumerable getVerbs() { return new IVerb[] { this.contextVerb, beatBuildExecutableVerb }; } public override IEnumerable getOutputs() { return new BuildObject[] { this.outputFile() }; } public override AbstractId getAbstractIdentifier() { return this.abstractId; } public BuildObject getBeatExecutable() { // Whaaat? Why doesn't beatBuildExecutableVerb.getOutputPath() already end with beat.exe!? Weirdly, // nope, its getOutputPath() is a directory. return new BuildObject(Path.Combine(beatBuildExecutableVerb.getOutputPath().getRelativePath(), "beat.exe")); } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { // "beat $BUILD_DEFS -out $out.tmp -in $in $incls" List args = new List(); args.Add("-in"); args.Add(this.beatobj.getRelativePath()); IEnumerable beatImports = BeatExtensions.getBeatFlavoredShallowIncludes(this.contextVerb, this.beatobj, BeatIncludes.ImportFilter.ForBeatOrBasm); foreach (BuildObject ifcObj in beatImports.Where(obj => !obj.Equals(this.beatobj))) { Util.Assert(!ifcObj.getRelativePath().Contains(".imp")); // Erk, don't feed imp files as includes! args.Add("-i"); args.Add(ifcObj.getRelativePath()); } args.AddRange(this.contextVerb.getPoundDefines().ToDefArgs()); string dbgText = string.Format( "rem verb {0}{1}", this, System.Environment.NewLine); return new ProcessInvokeAsyncWorker( workingDirectory, this, this.getBeatExecutable().getRelativePath(), args.ToArray(), ProcessExitCodeHandling.NonzeroIsFailure, captureStdout: this.outputFile(), failureBase: getDiagnosticsBase(), dbgText: dbgText); } public Disposition Complete(WorkingDirectory workingDirectory, double cpuTimeSeconds, string stdout, string stderr, Disposition disposition) { if (disposition is Fresh) { BeatExtensions.propagatePrivateImports(workingDirectory, this.contextVerb, this.beatobj, this.outputFile()); // And then propagate the NuBuild annotations, too. AnnotationScanner.transferAnnotations( workingDirectory, this.beatobj, this.outputFile(), BoogieAsmDepBase.CommentSymbol); } return disposition; } private BuildObject outputFile() { string outputAppLabel = (this.appLabel == null ? string.Empty : this.appLabel) + this.contextVerb.getPoundDefines().ToString(); string extn = this.beatobj.getExtension().Equals(BeatExtensions.BEATIFC_EXTN) ? BoogieAsmVerifyVerb.BASMIFC_EXTN : BoogieAsmVerifyVerb.BASMIMP_EXTN; return this.beatobj.makeLabeledOutputObject(outputAppLabel, extn); } private string getModuleNameForObj(BuildObject obj) { return obj.getFileNameWithoutExtension(); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/BoogieAsmDepBase.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; internal abstract class BoogieAsmDepBase : Verb { public const string BASM_EXTN = ".basm"; public const string BASMIFC_EXTN = ".ifc.basm"; public const string BASMIMP_EXTN = ".imp.basm"; public const string CommentSymbol = "//"; protected static NmakeVerb boogieAsmBuildExecutableVerb = new NmakeVerb(new SourcePath("tools\\BoogieAsm\\makefile", SourcePath.SourceType.Tools)); protected IContextGeneratingVerb context; protected BuildObject basmInput; protected BuildObject upstreamObj; private const int version = 20; private AbstractId abstractId = null; public BoogieAsmDepBase(IContextGeneratingVerb context, BuildObject input) { this.context = context; this.upstreamObj = input; this.basmInput = computeBasmInput(context.getPoundDefines(), input); } public static bool isBasm(BuildObject obj) { return obj.getExtension().Equals(BASMIFC_EXTN) || obj.getExtension().Equals(BASMIMP_EXTN); } public abstract BuildObject outputFile(); protected abstract int getVersion(); protected abstract bool includeAllImps(); protected virtual string getExtraAbstractID() { return string.Empty; } protected static BuildObject getBoogieasmExecutable() { return new BuildObject(Path.Combine(boogieAsmBuildExecutableVerb.getOutputPath().getRelativePath(), "boogieasm.exe")); } protected virtual IEnumerable getExtraDeps(out DependencyDisposition ddisp) { ddisp = DependencyDisposition.Complete; return new BuildObject[] { }; } public static BuildObject computeBasmInput(PoundDefines poundDefines, BuildObject upstreamObj) { if (BoogieAsmDepBase.isBasm(upstreamObj)) { // We'll be reading upstreamObj directly. Don't makeOutputObject, // because it may well be a source file. return upstreamObj; } return BeatExtensions.makeLabeledOutputObject(upstreamObj, poundDefines.ToString(), BASM_EXTN); } public override IEnumerable getOutputs() { return new BuildObject[] { outputFile() }; } public override AbstractId getAbstractIdentifier() { if (this.abstractId == null) { this.abstractId = new AbstractId(this.GetType().Name, getVersion() + version, this.upstreamObj.ToString(), context.getPoundDefines(), getExtraAbstractID()); } return abstractId; } internal class BasmModuleAccumulator { private IContextGeneratingVerb _contextGenVerb; private HashSet _mutableVerbSet; private OrderPreservingSet _basmModules; // these are the bits we want to pass in as Execute() arguments private HashSet _auxiliaryDeps; // these plus modules are the deps we need to wait on. We need these to get the right .tdeps. private IIncludePathContext context; private DependencyDisposition _ddisp; public IEnumerable verbs { get { return _mutableVerbSet; } } public IEnumerable basmModules { get { return _basmModules; } } public IEnumerable getDeps() { return _auxiliaryDeps.Concat(_basmModules); } public DependencyDisposition ddisp { get { return _ddisp; } } public BasmModuleAccumulator(IContextGeneratingVerb contextGenVerb, BuildObject upstreamObj, bool linkMode) { this._contextGenVerb = contextGenVerb; this._mutableVerbSet = new HashSet(); // NB preserve module definition-dependency order. this._basmModules = new OrderPreservingSet(); this._auxiliaryDeps = new HashSet(); _ddisp = DependencyDisposition.Complete; ////try ////{ _mutableVerbSet.Add(contextGenVerb); _auxiliaryDeps.UnionWith(contextGenVerb.getOutputs()); context = contextGenVerb.fetchIfAvailable(ref _ddisp); if (context != null) { OrderPreservingSet deps; if (!linkMode) { deps = BeatExtensions.getBeatFlavoredShallowDependencies( contextGenVerb, upstreamObj, out _ddisp, BeatIncludes.ImportFilter.ForBasmOnly); } else { deps = BeatExtensions.getBasmFlavoredTransitiveDependencies(contextGenVerb, upstreamObj, out _ddisp); _mutableVerbSet.Add(BeatExtensions.getBasmFlavoredTransitiveDepVerb(_contextGenVerb, upstreamObj)); } // REVIEW: The following two variables are unused. Remove? string targetModName = upstreamObj.getFileNameWithoutExtension(); ModPart targetModPart = BeatExtensions.whichPart(upstreamObj); // NB security policy note: When verifying X.imp, we must be sure to supply X.ifc // to BoogieAsm, so that we know that we're actually verifying the promises // that other modules are relying on when they say "X" (which is how X got on // the verification obligation list). That property happens automatically here, // because we make a list of modules (ignoring ifc/imp part), such as {A,B,X}, // and include *every* .ifc. If we're verifying X.imp, a conditional test // includes it at the time we consider module X. foreach (BuildObject dep in deps) { string depExtn = dep.getExtension(); if (depExtn == null || depExtn.EndsWith(TransitiveDepsVerb.TDEP_EXTN) || depExtn.EndsWith(ContextGeneratingVerb.CONTEXT_EXTN)) { _auxiliaryDeps.Add(dep); } else { Util.Assert(depExtn.Equals(BeatExtensions.BEATIFC_EXTN) || depExtn.Equals(BeatExtensions.BEATIMP_EXTN) || depExtn.Equals(BASMIFC_EXTN) || depExtn.Equals(BASMIMP_EXTN)); // Burned too many times by this silly filter-out strategy. string modName = dep.getFileNameWithoutExtension(); ModPart modPart = BeatExtensions.whichPart(dep); getBasmModule(modName, ModPart.Ifc); if ((dep.Equals(upstreamObj) && modPart == ModPart.Imp) || linkMode) { getBasmModule(modName, ModPart.Imp); } } } } ////} ////catch (ObjNotReadyException) ////{ //// // oh, we don't even have the context object yet. //// _ddisp = DependencyDisposition.Incomplete; ////} ////catch (ObjFailedException) ////{ //// _ddisp = DependencyDisposition.Failed; ////} } private BuildObject maybeBeat(BuildObject obj, HashSet mutableVerbSet) { BuildObject result = obj; if (BeatVerb.isBeat(obj)) { BeatVerb beatVerb = new BeatVerb(_contextGenVerb, obj, appLabel: null); IEnumerable beatOuts = beatVerb.getOutputs(); Util.Assert(beatOuts.Count() == 1); mutableVerbSet.Add(beatVerb); result = beatVerb.getOutputs().First(); } else { // No, this thing should already be ready to consume. ////mutableVerbSet.Add(new BoogieAsmVerifyVerb(context, obj)); } Util.Assert(BoogieAsmVerifyVerb.isBasm(result)); return result; } private void getBasmModule(string modName, ModPart modPart) { ////Logger.WriteLine(string.Format("context {0} modName {1} modPart {2}", context, modName, modPart)); ////BuildObject ifcObj = context.search(modName, modPart); BuildObject ifcObj = BuildEngine.theEngine.getHasher().search(context, modName, modPart); if (ifcObj == null) { Util.Assert(false); // I'm not sure this case even occur anymore, since we guard the foreach on incomplete deps. _ddisp = _ddisp.combine(DependencyDisposition.Incomplete); } else { ifcObj = maybeBeat(ifcObj, _mutableVerbSet); _basmModules.Add(ifcObj); } } } protected IEnumerable getBoogieVerbs(VerificationRequest verificationRequest) { if (verificationRequest.verifyMode == VerificationRequest.VerifyMode.NoVerify) { return new BoogieVerb[] { }; } BoogieAsmDepBase.BasmModuleAccumulator acc = new BoogieAsmDepBase.BasmModuleAccumulator(context, upstreamObj, includeAllImps()); List basmModules = new List(acc.basmModules.Where(mod => !mod.IsTrusted)); OrderPreservingSet normal_Boogie = new OrderPreservingSet(); OrderPreservingSet SymDiff_Boogie = new OrderPreservingSet(); foreach (BuildObject basmModule in basmModules) { if (verificationRequest.verifyMode == VerificationRequest.VerifyMode.SelectiveVerify && !verificationRequest.selectiveVerifyModuleNames.Contains(basmModule.getFileNameWithoutExtension())) { continue; } normal_Boogie.Add(new BoogieVerb(context, basmModule, symdiff: VerificationRequest.SymDiffMode.NoSymDiff)); if (verificationRequest.getSymDiffMode() == VerificationRequest.SymDiffMode.UseSymDiff && BoogieAsmVerifyVerb.needs_symdiff(basmModule)) { SymDiff_Boogie.Add(new BoogieVerb(context, basmModule, symdiff: VerificationRequest.SymDiffMode.UseSymDiff)); } } return SymDiff_Boogie.Union(normal_Boogie); } protected IEnumerable getVerifyishVerbs() { // All the available things that make Beat or Basm ... BasmModuleAccumulator acc = new BasmModuleAccumulator(context, upstreamObj, includeAllImps()); // Plus the transitive deps. IEnumerable extraDeps = new IVerb[] { context, boogieAsmBuildExecutableVerb }; return acc.verbs.Concat(extraDeps).Concat(context.getVerbs()); } public override IEnumerable getDependencies(out DependencyDisposition ddisp) { BasmModuleAccumulator acc = new BasmModuleAccumulator(context, upstreamObj, includeAllImps()); IEnumerable result = acc.getDeps(); DependencyDisposition ddisp_extra; IEnumerable result_extra = getExtraDeps(out ddisp_extra); ddisp = acc.ddisp.combine(ddisp_extra); return result.Concat(result_extra).Concat(new[] { getBoogieasmExecutable() }); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/BoogieAsmLinkVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; internal class BoogieAsmLinkVerb : BoogieAsmWorkerBase, IAsmProducer { public BoogieAsmLinkVerb(IContextGeneratingVerb context, BuildObject input) : base(context, input) { } public BuildObject getAsmFile() { return basmInput.makeOutputObject(MasmVerb.MASM_EXTN); } public override BuildObject outputFile() { return this.getAsmFile(); } public override IEnumerable getVerbs() { // Hey BJP: why do we have BoogieAsmLink here offering boogie verbs? I guess because it's safe and hint-y? // Dunno. Let's try without it. ////return getBoogieVerbs().Concat(getVerifyishVerbs()); return getVerifyishVerbs(); } protected override int getVersion() { return 23; } protected override string getAction() { return "-link"; } protected override bool outFlagWorks() { return false; } protected override bool includeAllImps() { return true; } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/BoogieAsmVerificationObligationListVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Linq; // NB we generate the obligation list in a seperate verb from the actual BoogieAsm -link step // because the latter is quite slow, and the former frees up a bunch of downstream // parallelism. internal class BoogieAsmVerificationObligationListVerb : BoogieAsmDepBase, IObligationsProducer { private BuildObject obligations; private VerificationRequest verificationRequest; public BoogieAsmVerificationObligationListVerb(IContextGeneratingVerb context, BuildObject input, VerificationRequest verificationRequest) : base(context, input) { this.verificationRequest = verificationRequest; obligations = input.makeOutputObject(BASM_EXTN + VerificationObligationList.VOL_EXTN); } public BuildObject getObligationSet() { return obligations; } public override BuildObject outputFile() { return obligations; } public override IEnumerable getVerbs() { IEnumerable result = getVerifyishVerbs(); IEnumerable boogieVerbs = new List(); try { boogieVerbs = getBoogieVerbs(verificationRequest); ////Logger.Out.WriteLine("Successfully retrieved the Boogie verbs."); } catch (ObjectNotReadyException) { ////Logger.Out.WriteLine("Caught an exception: " + e); } return result.Concat(boogieVerbs); } public IEnumerable getObligationSatisfyingVerbs() { return getBoogieVerbs(verificationRequest); } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { IEnumerable verificationResults = getBoogieVerbs(verificationRequest) .Select(boogie_verb => boogie_verb.getOutputFile()); VerificationObligationList vol = new VerificationObligationList(verificationResults); vol.store(workingDirectory, this.obligations); return new VerbSyncWorker(workingDirectory, new Fresh()); } protected override int getVersion() { return 5; } protected override bool includeAllImps() { return true; } protected override string getExtraAbstractID() { return verificationRequest.ToString(); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/BoogieAsmVerifyVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; internal class BoogieAsmVerifyVerb : BoogieAsmWorkerBase { public const string MUTUAL_SUMMARY_EXTN = ".ms"; public const string SYMDIFF_EXTN = ".symdiff"; public const string SYMDIFF_DIR_EXTN = ".dir"; private const string AddBoogieAxiomAnnotation = "AddBoogieAxiom"; private const string BasmEnableSymdiffAnnotation = "BasmEnableSymdiff"; private bool buildSymDiffMutualSummary; private bool enableSymdiff = false; private string dirName; public BoogieAsmVerifyVerb(IContextGeneratingVerb context, BuildObject input, bool buildSymDiffMutualSummary) : base(context, input) { this.buildSymDiffMutualSummary = buildSymDiffMutualSummary; this.enableSymdiff = BoogieAsmVerifyVerb.needs_symdiff(basmInput); } public static bool needs_symdiff(BuildObject basm) { AnnotationScanner annotations = new AnnotationScanner(basm); bool symdiff = false; foreach (string[] ann in annotations.getAnnotations(BasmEnableSymdiffAnnotation)) { if (ann.Length != 2 || !ann[1].Equals("true")) { throw new SourceConfigurationError("Expected " + BasmEnableSymdiffAnnotation + " to have argument 'true'."); } symdiff = true; } return symdiff; } public override BuildObject outputFile() { if (buildSymDiffMutualSummary) { // SymDiff files need to go into their own directory BuildObject normalName = BeatExtensions.makeOutputObject(basmInput, SYMDIFF_EXTN); dirName = normalName.getFileName() + SYMDIFF_DIR_EXTN; BuildObject dirExtendedName = new BuildObject(Path.Combine(normalName.getDirPath(), dirName, normalName.getFileName())); return dirExtendedName; } else { return BeatExtensions.makeOutputObject(basmInput, BoogieVerb.BPL_EXTN); } } public override IEnumerable getVerbs() { // Hey BJP: why do we have BoogieAsmLink here offering boogie verbs? I guess because it's safe and hint-y? return getVerifyishVerbs(); } public BuildObject getMutualSummary() { // SymDiff files need to go into their own directory. BuildObject normalName = BeatExtensions.makeOutputObject(basmInput, MUTUAL_SUMMARY_EXTN); BuildObject dirExtendedName = new BuildObject(Path.Combine(normalName.getDirPath(), dirName, normalName.getFileName())); return dirExtendedName; } public override IEnumerable getOutputs() { List outputs = new List { outputFile() }; if (buildSymDiffMutualSummary) { outputs.Add(getMutualSummary()); } return outputs; } protected override IEnumerable getExtraDeps(out DependencyDisposition ddisp) { try { ddisp = DependencyDisposition.Complete; return getTrustedBoogieAxioms(); } catch (ObjectNotReadyException) { // All the basms aren't here yet, so we can't scan them. Don't sweat it; // those deps are already being called for. ddisp = DependencyDisposition.Incomplete; return new BuildObject[] { }; } catch (ObjectFailedException) { ddisp = DependencyDisposition.Failed; return new BuildObject[] { }; } } protected override void extendArgs(List args) { if (!buildSymDiffMutualSummary && enableSymdiff) { args.Add("-symdiffok"); } else if (buildSymDiffMutualSummary) { args.Add("-symdiffms"); args.Add(getMutualSummary().getRelativePath()); } ////foreach (SourcePath includedAxiom in getTrustedBoogieAxioms(acc.basmModules)) foreach (SourcePath includedAxiom in getTrustedBoogieAxioms()) { if (!includedAxiom.IsTrusted) { throw new SourceConfigurationError(AddBoogieAxiomAnnotation + " annotation points at untrusted file " + includedAxiom.ToString()); } // SECURITY POLICY: you can only include trusted things labeled "_axioms.bpl". if (!includedAxiom.getExtension().Equals(BoogieVerb.BPL_EXTN) || !includedAxiom.getFileNameWithoutExtension().EndsWith("_axioms")) { throw new SourceConfigurationError(AddBoogieAxiomAnnotation + " annotation points at file that isn't a Boogie axioms file: " + includedAxiom.ToString()); } args.Add("/trustedBoogie:" + includedAxiom.getRelativePath()); } } protected override void postprocess(WorkingDirectory workingDirectory) { AnnotationScanner.transferAnnotations(workingDirectory, basmInput, outputFile(), BoogieVerb.CommentSymbol); } protected override int getVersion() { return 20; } protected override string getAction() { return "-verify"; } protected override bool outFlagWorks() { return true; } protected override bool includeAllImps() { return false; } protected override string getExtraAbstractID() { return buildSymDiffMutualSummary ? ", relational" : ", functional"; } private IEnumerable getTrustedBoogieAxioms() { OrderPreservingSet result = new OrderPreservingSet(); AnnotationScanner anns = new AnnotationScanner(basmInput); foreach (string[] annotation in anns.getAnnotations(AddBoogieAxiomAnnotation)) { string module = annotation[1]; SourcePath trustedPath = new SourcePath(Path.Combine( BuildEngine.theEngine.getSrcRoot(), BuildEngine.VerveTrustedSpecDir, module + BoogieVerb.BPL_EXTN)); result.Add(trustedPath); } return result; } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/BoogieAsmWorkerBase.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; internal abstract class BoogieAsmWorkerBase : BoogieAsmDepBase, IProcessInvokeAsyncVerb { public BoogieAsmWorkerBase(IContextGeneratingVerb context, BuildObject input) : base(context, input) { } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { List args = new List(); //// args.add(BUILD_DEFS //// args.add(boogieasm_flags) args.Add(getAction()); BuildObject captureStdout = null; if (outFlagWorks()) { args.Add("-out"); args.Add(outputFile().getRelativePath()); } else { captureStdout = outputFile(); } BasmModuleAccumulator acc = new BasmModuleAccumulator(context, upstreamObj, includeAllImps()); Util.Assert(acc.ddisp == DependencyDisposition.Complete); args.AddRange(acc.basmModules.Select(module => module.getRelativePath())); args.AddRange(context.getPoundDefines().ToDefArgs()); extendArgs(args); return new ProcessInvokeAsyncWorker( workingDirectory, this, getBoogieasmExecutable().getRelativePath(), args.ToArray(), ProcessExitCodeHandling.NonzeroIsFailure, getDiagnosticsBase(), captureStdout: captureStdout); } public Disposition Complete(WorkingDirectory workingDirectory, double cpuTimeSeconds, string stdout, string stderr, Disposition disposition) { postprocess(workingDirectory); return disposition; } protected abstract string getAction(); protected abstract bool outFlagWorks(); // Weird that it works for -verify but not -link! protected virtual void extendArgs(List args) { } protected virtual void postprocess(WorkingDirectory workingDirectory) { } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/BoogieVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; using System.Linq; internal class BoogieVerb : VerificationResultVerb, IProcessInvokeAsyncVerb { public const string BPL_EXTN = ".bpl"; public const string CommentSymbol = "//-"; private const int version = 17; private const string AddBoogieFlagAnnotation = "AddBoogieFlag"; // SECURITY POLICY: we only allow checked files to specify the flags below. // Otherwise, one might thing it reasonable to specify "/noVerify:1" or something. private static readonly string[] validFlagsAnyValue = { "/restartProver", "/timeLimit", "/trace" }; private static readonly string[] validFlagsSpecificValues = { "/proverOpt:OPTIMIZE_FOR_BV=true", "/z3opt:NL_ARITH=false" }; private static SourcePath boogieExecutable; private BuildObject bplInput; private AbstractId abstractId; private IEnumerable upstreamVerbs; private int timeLimit = 300; public BoogieVerb(IContextGeneratingVerb context, BuildObject bplInput, VerificationRequest.SymDiffMode symdiff) { if (bplInput.getExtension().Equals(BPL_EXTN)) { this.bplInput = bplInput; upstreamVerbs = new List(); // TODO this will probably break, since we don't know where this bplInput came from. Maybe that's okay, since the verb had to already exist to reach this point. } else if (symdiff == VerificationRequest.SymDiffMode.NoSymDiff) { IVerb boogieAsmVerb = new BoogieAsmVerifyVerb(context, bplInput, false); this.bplInput = boogieAsmVerb.getOutputs().First(); upstreamVerbs = new IVerb[] { boogieAsmVerb }; } else { IVerb workerVerb; SymDiffEngine.BuildPipeline(context, bplInput, out this.bplInput, out workerVerb); upstreamVerbs = new IVerb[] { workerVerb }; } this.abstractId = new AbstractId( this.GetType().Name, version, bplInput.ToString(), concrete: symdiff.ToString()); } public override IEnumerable getDependencies(out DependencyDisposition ddisp) { ddisp = DependencyDisposition.Complete; List result = new List() { bplInput }; result.Add(getBoogieExecutable()); result.AddRange(getBoogieExecutableDependencies()); return result; } public override IEnumerable getVerbs() { return upstreamVerbs; } public override BuildObject getOutputFile() { return BeatExtensions.makeOutputObject(bplInput, BPL_EXTN + VerificationResultVerb.VERIFICATION_RESULT_EXTN); } public override IEnumerable getOutputs() { return new BuildObject[] { getOutputFile() }; } public override AbstractId getAbstractIdentifier() { return abstractId; } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { if (false) { #pragma warning disable 162 File.WriteAllText(workingDirectory.PathTo(getOutputFile()), "Verification disabled temporarily for debugging"); return new VerbSyncWorker(workingDirectory, new Fresh()); #pragma warning restore 162 } List args = new List(); args.Add("/noinfer"); args.Add("/typeEncoding:m"); args.Add("/z3opt:ARITH_RANDOM_SEED=1"); args.Add("/timeLimit:" + timeLimit); args.AddRange(getFlags()); args.Add(bplInput.getRelativePath()); return new ProcessInvokeAsyncWorker( workingDirectory, this, getBoogieExecutable().getRelativePath(), args.ToArray(), ProcessExitCodeHandling.NonzeroIsOkay, getDiagnosticsBase(), allowCloudExecution: true, returnStandardOut: true, returnStandardError: true); } public Disposition Complete(WorkingDirectory workingDirectory, double cpuTimeSeconds, string stdout, string stderr, Disposition disposition) { VerificationResult vr = new VerificationResult( bplInput.getRelativePath(), cpuTimeSeconds, stdout, stderr, new VerificationResultBoogieParser()); vr.addBasicPresentation(); vr.toXmlFile(workingDirectory.PathTo(getOutputFile())); setWasRejectableFailure(vr.wasOnlyTimeouts()); return disposition; } protected override BuildObject getSource() { return bplInput; } private static SourcePath getBoogieExecutable() { // TODO this should eventually be a BuildObject from *building* the executable. if (BoogieVerb.boogieExecutable == null) { BoogieVerb.boogieExecutable = new SourcePath("tools\\Dafny\\Boogie.exe", SourcePath.SourceType.Tools); } return BoogieVerb.boogieExecutable; } private static IEnumerable getBoogieExecutableDependencies() { List exeDepends = new List(); exeDepends.Add(new SourcePath("tools\\Dafny\\AbsInt.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\BaseTypes.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\CodeContractsExtender.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\Concurrency.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\Core.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\Doomed.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\ExecutionEngine.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\Graph.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\Model.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\msvcp100.dll", SourcePath.SourceType.Tools)); // Needed by z3. exeDepends.Add(new SourcePath("tools\\Dafny\\msvcr100.dll", SourcePath.SourceType.Tools)); // Needed by z3. exeDepends.Add(new SourcePath("tools\\Dafny\\ParserHelper.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\Predication.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\Provers.SMTLib.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\VCExpr.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\VCGeneration.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\vcomp100.dll", SourcePath.SourceType.Tools)); // Needed by z3. exeDepends.Add(new SourcePath("tools\\Dafny\\z3.exe", SourcePath.SourceType.Tools)); return exeDepends; } private IEnumerable getFlags() { List flags = new List(); foreach (string[] ann in new AnnotationScanner(bplInput).getAnnotations(AddBoogieFlagAnnotation)) { if (ann.Count() != 2) { throw new SourceConfigurationError(bplInput + " has malformed annotation: " + string.Join(" ", ann)); } string flag = ann[1]; string[] flagParts = flag.Split(new char[] { ':' }, 2); if (validFlagsAnyValue.Contains(flagParts[0])) { flags.Add(flag); } else if (validFlagsSpecificValues.Contains(flag)) { flags.Add(flag); } else { throw new SourceConfigurationError(bplInput + " contains disallowed flag " + flag); } if (flagParts[0].Equals("/timeLimit")) { Util.Assert(flagParts.Count() == 2); timeLimit = Int32.Parse(flagParts[1]); } } return flags; } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/BootableAppVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; // Needs to: // 1) Build the bootloader into pxeloader // 2) Build two IroncladApps: Loader and specified app // Do this via a Batch // 3) Create a boot.ini internal class BootableAppVerb : Verb { ////public const string BOOT_EXTN = ".ini"; public const string LOADER_DFY = "src\\Dafny\\Apps\\AppLoader\\Main.i.dfy"; private const int version = 4; private SourcePath dfyroot; // REVIEW: Never used? private AbstractId abstractId; private VerificationRequest verificationRequest; // Dependencies ////BuildObject bootloader = new BuildObject("obj\\Trusted\\BootLoader\\pxe-loader"); // TODO: Build this with the NMake verb! private BuildObject bootloader = new SourcePath("obj\\Trusted\\BootLoader\\pxe-loader", SourcePath.SourceType.PrebakedObjExpediency); // Outputs private BuildObject bootIniFile; private BuildObject loaderCopy; private BuildObject bootloaderCopy; private BuildObject appExecutableCopy; // Intermediate verbs private IroncladAppVerb loaderVerb; private IroncladAppVerb appVerb; private BatchVerifyVerb batchVerb; private VerificationResultSummaryVerb batchSummaryVerb; public BootableAppVerb(SourcePath dfyroot, DafnyCCVerb.FramePointerMode useFramePointer, VerificationRequest verificationRequest) { this.dfyroot = dfyroot; this.verificationRequest = verificationRequest; string concreteId = verificationRequest.ToString() + "," + useFramePointer.ToString(); this.abstractId = new AbstractId(this.GetType().Name, version, dfyroot.ToString(), concrete: concreteId); string targetDirectory = Path.Combine( BuildEngine.theEngine.getObjRoot(), dfyroot.getDirPath(), "bootable-" + verificationRequest.ToString()); this.bootIniFile = new BuildObject(Path.Combine(targetDirectory, "safeos\\boot.ini")); // TODO: Create the bootloader verb. this.loaderVerb = new IroncladAppVerb(new SourcePath(LOADER_DFY), IroncladAppVerb.TARGET.BARE_METAL, useFramePointer, verificationRequest); this.appVerb = new IroncladAppVerb(dfyroot, IroncladAppVerb.TARGET.BARE_METAL, useFramePointer, verificationRequest); this.batchVerb = new BatchVerifyVerb(dfyroot, new HashSet() { this.appVerb, this.loaderVerb }, BatchVerifyVerb.BatchMode.APP); this.batchSummaryVerb = new VerificationResultSummaryVerb(this.batchVerb); this.loaderCopy = new BuildObject(Path.Combine(targetDirectory, this.targetExecutableName(this.loaderVerb))); this.bootloaderCopy = new BuildObject(Path.Combine(targetDirectory, this.bootloader.getFileName())); this.appExecutableCopy = new BuildObject(Path.Combine(targetDirectory, this.targetExecutableName(this.appVerb))); } public override IEnumerable getDependencies(out DependencyDisposition ddisp) { List result = new List(); ////result.Add(this.bootloader); // TODO: Replace with the bootloader verbs's output. result.Add(this.loaderVerb.getExe()); result.Add(this.appVerb.getExe()); result.AddRange(this.batchSummaryVerb.getOutputs()); ddisp = DependencyDisposition.Complete; return result; } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { if (this.verificationRequest.isComplete()) { VerificationResult vr = VerificationResult.fromXmlFile(this.batchSummaryVerb.getOutputFile()); if (!vr.pass) { Util.Assert(false); // Should never get here, since Ironclad app should fail before producing a verified exe. return new VerbSyncWorker(workingDirectory, new Failed()); } } // Copy the AppLoader binary and the bootloader into the same directory as the app's binary, so the pxe-loader can find them. // REVIEW: Not clear this is doing the right thing with shift to WorkingDirectory. File.Copy(workingDirectory.PathTo(this.loaderVerb.getExe()), workingDirectory.PathTo(this.loaderCopy), true); File.Copy(workingDirectory.PathTo(this.appVerb.getExe()), workingDirectory.PathTo(this.appExecutableCopy), true); File.Copy(workingDirectory.PathTo(this.bootloader), workingDirectory.PathTo(this.bootloaderCopy), true); this.writeBootFile(workingDirectory); return new VerbSyncWorker(workingDirectory, new Fresh()); } public override IEnumerable getVerbs() { List result = new List(); ////result.Add(bootloaderVerb); // TODO when we're building the bootloader as part of NuBuild. result.Add(this.batchSummaryVerb); result.Add(this.appVerb); result.Add(this.loaderVerb); return result; } public override IEnumerable getOutputs() { return new BuildObject[] { this.bootIniFile, this.loaderCopy, this.bootloaderCopy }; } public override AbstractId getAbstractIdentifier() { return this.abstractId; } public override Presentation getPresentation() { return this.batchSummaryVerb.getPresentation(); } private string targetExecutableName(IroncladAppVerb fromVerb) { // It's okay that we're saving an unverified binary to a .exe extension, because it's // getting placed inside targetDirectory, which is labeled "bootable-unverified." return fromVerb.getAppLabel() + IroncladAppVerb.TRUSTED_EXE_EXTN; } // TODO: Rename obj to something meaningful. Is it a boot file? private string mkBootFileEntry(WorkingDirectory workingDirectory, BuildObject obj) { return string.Format("Size={0} Path=/{1}", new FileInfo(workingDirectory.PathTo(obj)).Length, obj.getFileName()); } private void writeBootFile(WorkingDirectory workingDirectory) { List lines = new List(); lines.Add(this.mkBootFileEntry(workingDirectory, this.loaderCopy)); lines.Add(this.mkBootFileEntry(workingDirectory, this.appExecutableCopy)); File.WriteAllLines(workingDirectory.PathTo(this.bootIniFile), lines); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/BuildEngine.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.IO; internal class BuildEngine { public const string VerveTrustedSpecDir = "Trusted\\Spec"; private static BuildEngine _theEngine = new BuildEngine(); private PathNormalizer pathNormalizer; private SourcePathIncludeContext vervePathContext; private string ironRoot; private Hasher hasher; private Repository repository; private CloudExecutionQueue cloudExecutionQueue; private string cloudReportQueueName; private ItemCacheCloud cloudItemCache; private IItemCache itemCache; private string localCacheLocation = "nucache"; public BuildEngine() { this.pathNormalizer = new PathNormalizer(); this.hasher = new Hasher(); } public static BuildEngine theEngine { get { return _theEngine; } } internal Repository Repository { get { return this.repository; } set { this.repository = value; } } internal CloudExecutionQueue CloudExecutionQueue { get { return this.cloudExecutionQueue; } set { this.cloudExecutionQueue = value; } } internal string CloudReportQueueName { get { return this.cloudReportQueueName; } set { this.cloudReportQueueName = value; } } internal ItemCacheCloud CloudCache { get { return this.cloudItemCache; } set { this.cloudItemCache = value; } } internal IItemCache ItemCache { get { return this.itemCache; } set { this.itemCache = value; } } public SourcePathIncludeContext getVervePathContext() { if (this.vervePathContext == null) { Util.Assert(this.ironRoot != null); this.vervePathContext = new SourcePathIncludeContext(); this.vervePathContext.addDirectory(VerveTrustedSpecDir); this.vervePathContext.addDirectory("Checked\\Nucleus\\Base"); this.vervePathContext.addDirectory("Checked\\Nucleus\\GC"); this.vervePathContext.addDirectory("Checked\\Nucleus\\Devices"); this.vervePathContext.addDirectory("Checked\\Nucleus\\Main"); this.vervePathContext.addDstExtension(BeatExtensions.BEATIFC_EXTN); this.vervePathContext.addDstExtension(BeatExtensions.BEATIMP_EXTN); this.vervePathContext.addDstExtension(BoogieAsmVerifyVerb.BASMIFC_EXTN); this.vervePathContext.addDstExtension(BoogieAsmVerifyVerb.BASMIMP_EXTN); } return this.vervePathContext; } public IContextGeneratingVerb getVerveContextVerb(PoundDefines poundDefines) { return new StaticContextVerb(this.getVervePathContext(), "Verve", poundDefines); } ////public TransitiveIncludesCache getDafnyIncludeCache() ////{ //// return dafnyIncludeCache; ////} ////public TransitiveIncludesCache getBeatIncludeCache(IIncludePathContext context) ////{ //// if (!contextToCache.ContainsKey(context)) //// { //// contextToCache[context] = new TransitiveIncludesCache(new BeatIncludes(context)); //// } //// return contextToCache[context]; ////} public string getIronRoot() { return this.ironRoot; } internal void setIronRoot(string ironRoot) { this.ironRoot = this.pathNormalizer.normalizeAbsolutePath(ironRoot); } // Normalize the case of an ironRoot-relative path to the case present in the filesystem. internal string normalizeIronPath(string ironRelPath) { string abspath = this.pathNormalizer.normalizeAbsolutePath(Path.GetFullPath(Path.Combine(this.ironRoot, ironRelPath))); Util.Assert(abspath.StartsWith(this.ironRoot)); return abspath.Substring(this.ironRoot.Length); } internal string getObjRoot() { return "nuobj"; } internal string getSrcRoot() { return "src"; } internal string getVirtualRoot() { return this.getObjRoot() + "\\virtual"; // Should never exist in filesystem! } internal string getToolsRoot() { return "tools"; } internal string getBinToolsRoot() { return "bin_tools"; } internal void setLocalCache(string path) { this.localCacheLocation = path; } internal string getLocalCache() { return this.localCacheLocation; } internal IHasher getHasher() { return this.hasher; } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/BuildObject.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Diagnostics; using System.IO; using System.Linq; using System.Xml; /// /// An abstract identifier for "nouns" (i.e. the things that verbs operate /// on -- both verb outputs and dependencies are BuildObjects). /// /// /// Note that sometimes the code and/or comments about the code refer to /// BuildObjects as if they are the concrete thing that they identify as /// opposed to just being the abstract identifier for that thing. This is /// probably okay, as there should be just one concrete instance of any /// particular abstract build object during a given run of the system. /// public class BuildObject { /// /// The XML element name for this object. /// public const string XmlTag = "BuildObject"; /// /// Path to this object as stored in the local filesystem, relative to /// the IronRoot (i.e. begins with "src", "obj", etc.). /// /// /// This string is expected to be normalized to have consistent casing. /// protected string path; /// /// Whether this object is considered "trusted" for verification /// purposes. /// private bool isTrusted; /// /// The filename of this object, without the file extension. /// private string filenameWithoutExtension; /// /// The filename extension for this object. /// private string filenameExtension; /// /// Initializes a new instance of the BuildObject class. /// /// /// Relative path to this object in the local filesystem. /// /// /// Whether this object is considered "trusted" for verification /// purposes. /// public BuildObject(string path, bool isTrusted = false) { // ToDo: Fix VSSolutionVerb and/or IronfleetTestDriver.sln to work in "src" tree without hitting below Assert. Then re-instate below Assert. ////Util.Assert(!path.StartsWith(BuildEngine.theEngine.getSrcRoot(), StringComparison.OrdinalIgnoreCase)); this.path = BuildEngine.theEngine.normalizeIronPath(path); this.isTrusted = isTrusted; } /// /// Initializes a new instance of the BuildObject class. /// /// /// Relative path to this object in the local filesystem. /// protected BuildObject(string path) { this.path = BuildEngine.theEngine.normalizeIronPath(path); } /// /// Gets or sets a value indicating whether this object is considered /// "trusted" for verification purposes. /// /// /// REVIEW: Giving build objects properties like this is dangerous, /// as they are supposed to be just abstract ids. Two equivalent /// (per Equals() below) build objects could be created, and should /// reference the same bag of bits, yet have different properties! /// public bool IsTrusted { get { return this.isTrusted; } protected set { this.isTrusted = value; } } /// /// Gets the relative path for this instance. /// /// /// TODO: Replace this with a property ("RelativePath"?) that is /// public get and protected set. And change this.path from /// protected to private. /// /// The relative path for this instance. public string getRelativePath() { return this.path; } /// /// Returns a string that represents this instance. /// /// A string that represents this instance. public override string ToString() { return this.path; } /// /// Gets the directory information for this instance. /// /// The directory information for this instance. public string getDirPath() { return Path.GetDirectoryName(this.path); } /// /// Gets the file name and extension for this instance. /// /// The file name and extension for this instance. public string getFileName() { return Path.GetFileName(this.path); } /// /// Gets the file name (sans extension) for this instance. /// /// The file name (sans extension) for this instance. public string getFileNameWithoutExtension() { this.splitExtension(); return this.filenameWithoutExtension; } /// /// Gets the file extension for this instance. /// /// The file extension for this instance. public string getExtension() { this.splitExtension(); return this.filenameExtension; } /// /// Determines whether this instance and another specified BuildObject /// object have the same value (identity?). Really, the same path. /// /// The object to compare to this instance. /// /// True if the given object is equivalent to this instance, /// false otherwise. /// public override bool Equals(object obj) { BuildObject other = obj as BuildObject; if (other != null) { return this.path.Equals(other.path, StringComparison.Ordinal); } else { return false; } } /// /// Returns the hash code for this instance. /// /// /// Note that equivalent (as in .Equals returns true) instances /// will have the same hash code. /// /// The hash code for this instance. public override int GetHashCode() { return this.path.GetHashCode(); } /// /// Creates a new instance based on this one, but with the given /// extension, and guaranteed to be in the obj directory. /// /// Extension to give new instance. /// A new instance. public BuildObject makeOutputObject(string extension) { return new BuildObject(this.mashedPathname(BuildEngine.theEngine.getObjRoot(), extension)); } /// /// Creates a new instance based on this one, but for the given /// appLabel (REVIEW: what does this mean?), with the given /// extension, and guaranteed to be in the obj directory. /// /// The app label to use. /// Extension to give new instance. /// A new instance. public BuildObject makeLabeledOutputObject(string appLabel, string extension) { string appSpecificPrefix = appLabel == null ? BuildEngine.theEngine.getObjRoot() : Path.Combine(BuildEngine.theEngine.getObjRoot(), appLabel); // REVIEW: Ordinal vs. OrdinalIgnoreCase. if (this.path.StartsWith(appSpecificPrefix, StringComparison.OrdinalIgnoreCase)) { // Input is already in the correct subtree; don't nest subtrees. return this.makeOutputObject(extension); } else { // Input is coming from elsewhere; give it a parallel location under app-specific subtree. return new BuildObject(this.mashedPathname(appSpecificPrefix, extension)); } } /// /// Creates a new VirtualBuildObject based on this instance, but with /// a path modified to be virtual and have the given extension. /// /// /// Filename extension to give the new object. /// /// A new VirtualBuildObject. public BuildObject makeVirtualObject(string extension) { return new VirtualBuildObject(this.mashedPathname(BuildEngine.theEngine.getVirtualRoot(), extension)); } /// /// Helper function to read an XML element (not a full document) /// representing a BuildObject. /// /// /// Note that the XmlReader is expected to be positioned in the XML /// document such that the current node is a BuildObject element. /// /// The XmlReader object to read from. /// /// A new BuildObject corresponding to the XML representation read. /// public static BuildObject ReadXml(XmlReader xr) { Util.Assert(xr.Name.Equals(XmlTag)); string relativePath = xr.ReadElementContentAsString(); return new BuildObject(relativePath); } /// /// Helper function to write an XML element (not a full document) /// representing this BuildObject. /// /// The XmlWriter object to write to. public void WriteXml(XmlWriter xw) { xw.WriteStartElement(XmlTag); xw.WriteString(this.path); xw.WriteEndElement(); } /// /// Splits the filename of this object into its separate base and /// extension components. /// private void splitExtension() { if (this.filenameWithoutExtension == null) { string filename = this.getFileName(); int dot = filename.IndexOf('.'); if (dot < 0) { this.filenameWithoutExtension = filename; this.filenameExtension = null; } else { this.filenameExtension = filename.Substring(dot); // TODO: This is a (possibly brittle) workaround for dfy .s // and .i, which aren't part of the file type, they're part // of the name. Sorta. if (DafnyTransformBaseVerb.DAFNY_LONG_EXTNS.Contains(this.filenameExtension)) { dot += 2; this.filenameExtension = filename.Substring(dot); } this.filenameWithoutExtension = filename.Substring(0, dot); } } } /// /// Combines the provided root path and extension with this /// instance's relative path and munged (for DafnySpec/CC) filename. /// /// The desired root path. /// The desired extension. /// A combined pathname. private string mashedPathname(string root, string extension) { string filename = this.getFileNameWithoutExtension(); // Remap dafny filenames so resulting objects have correctly-parsed extns. filename = Util.dafnySpecMungeName(filename); return Path.Combine(root, this.getDirRelativeToSrcOrObj(), filename + extension); } /// /// Strips off the initial 'src\' or 'obj\' from the path. /// /// /// The directory containing this object, relative to the source or /// object directory. /// private string getDirRelativeToSrcOrObj() { string dirname = this.getDirPath(); int slash = dirname.IndexOf('\\'); Util.Assert(slash >= 0); return dirname.Substring(slash + 1); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/BuildObjectValuePointer.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Xml; /// /// Mapping between a BuildObject (an abstract identifier) and the hash /// value of the build object's contents (concrete identifier) for this run. /// REVIEW: Come up with a better name for this? /// public class BuildObjectValuePointer { /// /// The XML element name for this object. /// public const string XmlTag = "BuildObjectValuePointer"; /// /// The XML attribute name for the ObjectHash value. /// private const string XmlObjectHashAttribute = "ObjectHash"; /// /// The XML attribute name for the RelativePath value. /// private const string XmlRelativePathAttribute = "RelativePath"; /// /// Hash of the contents referenced by the build object. /// private string objectHash; /// /// Path to the build object, relative to the IronRoot. /// private string relativePath; /// /// Initializes a new instance of the BuildObjectValuePointer class. /// /// /// Hash of the contents referenced by the build object. /// /// /// Path to the build object, relative to the IronRoot. /// public BuildObjectValuePointer(string objectHash, string relativePath) { this.objectHash = objectHash; this.relativePath = relativePath; } /// /// Gets the hash of the contents referenced by the build object. /// public string ObjectHash { get { return this.objectHash; } } /// /// Gets the path to the build object, relative to the IronRoot. /// public string RelativePath { get { return this.relativePath; } } /// /// Helper function to read an XML element (not a full document) /// representing a BuildObjectValuePointer. /// /// /// Note that the XmlReader is expected to be positioned in the XML /// document such that the current node is a BuildObjectValuePointer /// element. /// /// The XmlReader object to read from. /// /// A new BuildObjectValuePointer corresponding to the XML /// representation read. /// public static BuildObjectValuePointer ReadXml(XmlReader xr) { Util.Assert(xr.Name.Equals(XmlTag)); string objectHash = xr.GetAttribute(XmlObjectHashAttribute); string relativePath = xr.GetAttribute(XmlRelativePathAttribute); return new BuildObjectValuePointer(objectHash, relativePath); } /// /// Helper function to write an XML element (not a full document) /// representing this BuildObjectValuePointer. /// /// The XmlWriter object to write to. public void WriteXml(XmlWriter xw) { xw.WriteStartElement(XmlTag); xw.WriteAttributeString(XmlObjectHashAttribute, this.objectHash); xw.WriteAttributeString(XmlRelativePathAttribute, this.relativePath); xw.WriteEndElement(); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/CachedHash.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; internal class CachedHash { private Dictionary hashCache; private HashFunc hashFunc; private FailureBehavior failureBehavior; private CachabilityTestFunc cachabilityTest; public CachedHash( HashFunc hashFunc, FailureBehavior failureBehavior = FailureBehavior.AssertFailures, CachabilityTestFunc cachabilityTest = null) { this.hashCache = new Dictionary(); this.hashFunc = hashFunc; this.failureBehavior = failureBehavior; this.cachabilityTest = cachabilityTest; } public delegate ValueType HashFunc(HashedObjectType hashObj); public delegate bool CachabilityTestFunc(ValueType value); public enum FailureBehavior { IgnoreFailures, AssertFailures } public ValueType get(HashedObjectType hashObj) { if (!this.hashCache.ContainsKey(hashObj)) { ValueType value = this.hashFunc(hashObj); if (value == null) { Util.Assert(this.failureBehavior == FailureBehavior.IgnoreFailures); return value; } else if (this.cachabilityTest != null && !this.cachabilityTest(value)) { return value; } else { this.hashCache[hashObj] = value; } } return this.hashCache[hashObj]; } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/CloudExecutionQueue.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Configuration; using System.IO; using System.Threading; using Microsoft.WindowsAzure.Storage; using Microsoft.WindowsAzure.Storage.Queue; /// /// Represents the queue used to make requests of cloud execution engines. /// public class CloudExecutionQueue { // Note that queue names must be all lowercase. // See http://msdn.microsoft.com/en-us/library/dd179349.aspx. /// /// Maximum interval to wait between polls of the request queue. /// In milliseconds. /// /// /// REVIEW: Is 30 seconds a reasonable cap? /// private const int RequestQueuePollIntervalCap = 30000; /// /// Name of the request queue. /// private const string RequestQueueName = "requests"; /// /// Name of the default report queue. /// private const string ReportQueueName = "reports"; /// /// Expiration time for request/report queue entries. /// Most queue entries should be picked up almost immediately, /// this is to prevent orphaned entries from hanging around "forever". /// private readonly TimeSpan queueEntryTtl; /// /// Azure storage account we're using. /// private CloudStorageAccount storageAccount; /// /// Cloud queue client for working with cloud queues. /// private CloudQueueClient queueClient; /// /// Queue to hold execution requests. /// private CloudQueue requestQueue; /// /// Queue to hold execution reports. /// private CloudQueue clientReportQueue; /// /// Cache of current request's report queue. /// private CloudQueue cachedServerReportQueue; /// /// Name of the cached report queue. /// private string cachedServerReportQueueName; /// /// Waiters for execution reports. /// private Dictionary reportWaiters; /// /// Lock for the reportWaiters dictionary. /// private Mutex reportWaitersLock; /// /// Event that is signaled (i.e. set) if we have active waiters for execution reports. /// private ManualResetEvent haveReportWaiters; /// /// Thread that monitors the report queue. /// private Thread monitoringThread; /// /// Initializes a new instance of the CloudExecutionQueue class. /// /// /// This is the constructor for servers. /// public CloudExecutionQueue() { // Work-around for running this code in CloudExecutionEngine. TODO: Clean this up! // The BuildEngine.theEngine.getIronRoot() call needs to work for BuildObject code to function properly. if (BuildEngine.theEngine.getIronRoot() == null) { BuildEngine.theEngine.setIronRoot(Directory.GetCurrentDirectory()); } this.queueEntryTtl = new TimeSpan(0, 30, 0); // 30 minutes. // Create our CloudStorageAccount object. // REVIEW: Hard-coded connection string index "Ironclad". string connectionString = null; ConnectionStringSettings settings = ConfigurationManager.ConnectionStrings["Ironclad"]; if (settings != null) { connectionString = settings.ConnectionString; } if (string.IsNullOrEmpty(connectionString)) { throw new ConfigurationException("Azure connection string missing from your NuBuild.exe.config file!"); } this.storageAccount = CloudStorageAccount.Parse(connectionString); this.queueClient = this.storageAccount.CreateCloudQueueClient(); this.requestQueue = this.queueClient.GetQueueReference(CloudExecutionQueue.RequestQueueName); this.requestQueue.CreateIfNotExists(); } /// /// Initializes a new instance of the CloudExecutionQueue class. /// /// /// This is the constructor for clients (does extra stuff). /// /// Name of the report queue this client is using. public CloudExecutionQueue(string reportQueueName) : this() { if (string.IsNullOrEmpty(reportQueueName)) { // Use default shared report queue if none is specified. reportQueueName = CloudExecutionQueue.ReportQueueName; } else { // Schedule auto-deletion of our private report queue. // We do this by setting the initial invisibility of a delete queue request. // This will auto-clean up our private report queue if we exit unexpectedly. CloudExecutionRequest deleteQueueRequest = new CloudExecutionRequest( reportQueueName, reportQueueName, CloudExecutionRequest.Operation.DeleteQueue, null, null, null, null ); CloudQueueMessage deleteQueueMessage = new CloudQueueMessage(deleteQueueRequest.ToXml()); this.requestQueue.AddMessage(deleteQueueMessage, new TimeSpan(12, 0, 0), new TimeSpan(4, 0, 0)); } this.clientReportQueue = this.queueClient.GetQueueReference(reportQueueName); this.clientReportQueue.CreateIfNotExists(); this.reportWaiters = new Dictionary(); this.reportWaitersLock = new Mutex(); this.haveReportWaiters = new ManualResetEvent(false); this.monitoringThread = new Thread(new ThreadStart(this.MonitorReportQueue)); this.monitoringThread.IsBackground = true; this.monitoringThread.Name = "Report Queue Monitor"; this.monitoringThread.Start(); } /// /// Deletes the specified queue. /// /// Name of the queue to delete. public void DeleteQueue(string queueName) { CloudQueue goner = this.queueClient.GetQueueReference(queueName); goner.DeleteIfExists(); } /// /// Submits a request for cloud execution. /// /// /// The CloudExecutionRequest detailing this request. /// public void SubmitRequest(CloudExecutionRequest request) { CloudQueueMessage message = new CloudQueueMessage(request.ToXml()); this.requestQueue.AddMessage(message, this.queueEntryTtl); } /// /// Gets the next request from the request queue. /// /// Whether to block. /// Next request on the queue. public CloudExecutionRequest GetRequest(bool block = false) { int pollInterval = 1000; // In milliseconds. CloudQueueMessage message = null; while ((message = this.requestQueue.GetMessage()) == null) { if (block) { Thread.Sleep(pollInterval); // Increase poll interval if we're below the cap. if (pollInterval < RequestQueuePollIntervalCap) { // Increase by 1/10th of a second each time. // This will take 14.5s to reach a 2s interval. pollInterval += 100; } continue; } else { return null; } } ////Console.WriteLine(message.AsString); CloudExecutionRequest request = CloudExecutionRequest.FromMessage(message); return request; } /// /// Deletes a request from the queue. /// Used by reader to indicate request completion. /// /// Request to delete. public void DeleteRequest(CloudExecutionRequest request) { CloudQueueMessage message = request.Message; this.requestQueue.DeleteMessage(message); } /// /// Submits a report of cloud execution for processing by the submitter. /// /// Report to submit. /// Name of the report queue to submit to. public void SubmitReport(CloudExecutionReport report, string reportQueueName) { // Check to see if we need to update the cached report queue. if (reportQueueName != this.cachedServerReportQueueName) { this.cachedServerReportQueue = this.queueClient.GetQueueReference(reportQueueName); this.cachedServerReportQueue.CreateIfNotExists(); this.cachedServerReportQueueName = reportQueueName; } CloudQueueMessage message = new CloudQueueMessage(report.ToXml()); this.cachedServerReportQueue.AddMessage(message, this.queueEntryTtl); } /// /// Gets the requested execution report off of the queue. /// /// Report to retrieve. /// Count of remaining waiters after our report arrives. /// The execution report in question. public CloudExecutionReport GetReport(string reportIdentifier, out int numberOfOtherWaiters) { CloudExecutionWaiter waiter = new CloudExecutionWaiter(); // Add the desired report to the dictionary under lock. this.reportWaitersLock.WaitOne(); this.reportWaiters.Add(reportIdentifier, waiter); this.haveReportWaiters.Set(); this.reportWaitersLock.ReleaseMutex(); // Wait for report to arrive, and then return it. return waiter.WaitForReport(out numberOfOtherWaiters); } /// /// Procedure performed by the report queue monitoring thread. /// private void MonitorReportQueue() { const int MaxBatchSize = 32; // Maximum allowed by API. TimeSpan invisibleTime = new TimeSpan(0, 0, 2); // Two seconds. TimeSpan pollInterval = new TimeSpan(0, 0, 1); // One second. List messages; bool anyForUs; while (true) { // Don't bother doing anything if we don't have any active waiters. this.haveReportWaiters.WaitOne(); // Get a new batch of messages. // No other queue readers will see these until the invisibleTime expires. messages = new List(this.clientReportQueue.GetMessages(MaxBatchSize, invisibleTime)); anyForUs = false; foreach (CloudQueueMessage message in messages) { CloudExecutionReport report = CloudExecutionReport.FromMessage(message); // Lookup the waiter for this report under lock. CloudExecutionWaiter waiter; int remainingWaitersCount = 0; this.reportWaitersLock.WaitOne(); bool foundWaiter = this.reportWaiters.TryGetValue(report.Identifier, out waiter); if (foundWaiter && report.Status == CloudExecutionReport.StatusCode.Completed) { this.reportWaiters.Remove(report.Identifier); remainingWaitersCount = this.reportWaiters.Count; if (remainingWaitersCount == 0) { // We don't have anyone else waiting for a report. this.haveReportWaiters.Reset(); } } this.reportWaitersLock.ReleaseMutex(); if (foundWaiter) { // We delete the report from the queue right away, // as nobody else should ever be interested in it. this.clientReportQueue.DeleteMessage(message); anyForUs = true; switch (report.Status) { case CloudExecutionReport.StatusCode.Completed: waiter.GiveReportToWaiter(report, remainingWaitersCount); break; case CloudExecutionReport.StatusCode.InProgress: Console.WriteLine("Node '{0}' reports request '{1}' is in progress.", report.ProcessingNode, report.Identifier); break; default: // REVIEW: Or just Assert here? This should never happen. Console.WriteLine("Node '{0}' reports strange status '{1}' for request '{2}'.", report.ProcessingNode, report.Status, report.Identifier); break; } } } if ((messages.Count != 0) && !anyForUs) { // Give other client(s) a chance to get their messages. Thread.Sleep(invisibleTime + pollInterval + pollInterval); } else { Thread.Sleep(pollInterval); } } } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/CloudExecutionReport.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Text; using System.Xml; using Microsoft.WindowsAzure.Storage.Queue; /// /// Message that is put on the cloud "reports" queue to inform a cloud /// execution engine client of the status of its request. /// public class CloudExecutionReport { /// /// XML element name for this object. /// public const string XmlTag = "CloudExecutionReport"; /// /// Version of this object we create by default. /// private const int Version = 1; /// /// XML element name for our version field. /// private const string XmlVersionAttribute = "Version"; /// /// XML element name for our identifier field. /// private const string XmlIdentifierElement = "Identifier"; /// /// XML element name for our status field. /// private const string XmlStatusElement = "Status"; /// /// XML element name for our processingNode field. /// private const string XmlProcessingNodeElement = "ProcessingNode"; /// /// XML element name for our exitCode field. /// private const string XmlExitCodeElement = "ExitCode"; /// /// XML element name for our standardOutput field. /// private const string XmlStandardOutputElement = "StandardOutput"; /// /// XML element name for our standardError field. /// private const string XmlStandardErrorElement = "StandardError"; /// /// XML element name for our cpuTime field. /// private const string XmlCpuTimeElement = "CpuTime"; /// /// XML element name for our outputFileMappings field. /// private const string XmlOutputFileMappingsElement = "OutputFileMappings"; /// /// Queued message this instance was created from (if it was). /// private CloudQueueMessage message; /// /// Version of this object instance. /// private int version; /// /// Request identifier this report is in response to. /// private string identifier; /// /// Status of request being conveyed by this report. /// private StatusCode status; /// /// Name of the node that produced this report. /// private string processingNode; /// /// Exit code returned from the process after execution. /// private int exitCode; /// /// Standard out from the process. /// private string standardOutput; /// /// Standard error from the process. /// private string standardError; /// /// CPU time used by the process. /// private double cpuTime; /// /// Collection of output files resulting from this execution, /// represented by both their item cache identifier and /// their relative path. /// private List outputFileMappings; /// /// Initializes a new instance of the CloudExecutionReport class. /// /// Unique ID for this instance. /// Status of the request. /// Exit code from the process. /// /// Standard output from the process execution. /// /// /// Standard error from the process execution. /// /// CPU time used by the process. /// /// Output files generated by this process execution. /// public CloudExecutionReport( string identifier, StatusCode status, int exitCode, string standardOutput, string standardError, double cpuTime, List outputFileMappings) : this( CloudExecutionReport.Version, identifier, status, Environment.MachineName, // REVIEW: Probably insecure (from user settable environment variable?). Do we care? exitCode, standardOutput, standardError, cpuTime, outputFileMappings) { } /// /// Initializes a new instance of the CloudExecutionReport class. /// /// Unique ID for this instance. /// Status of the request. public CloudExecutionReport( string identifier, StatusCode status) : this( CloudExecutionReport.Version, identifier, status, Environment.MachineName, 0, null, null, 0, null) { } /// /// Initializes a new instance of the CloudExecutionReport class. /// /// Version of this class instance. /// Unique ID for this instance. /// Status of the request. /// Name of node producing this report. /// Exit code from the process. /// /// Standard output from the process execution. /// /// /// Standard error from the process execution. /// /// CPU time used by the process. /// /// Output files generated by this process execution. /// private CloudExecutionReport( int version, string identifier, StatusCode status, string processingNode, int exitCode, string standardOutput, string standardError, double cpuTime, List outputFileMappings) { this.version = version; this.identifier = identifier; this.status = status; this.processingNode = processingNode; this.exitCode = exitCode; this.standardOutput = standardOutput; this.standardError = standardError; this.cpuTime = cpuTime; this.outputFileMappings = outputFileMappings; } /// /// Definition of Status field values. /// public enum StatusCode : int { /// /// The request was processed to completion and all other fields are meaningful. /// Note: this does NOT mean the request completed successfully. /// Completed, /// /// The request was aborted. /// Aborted, /// /// The request is in progress. /// InProgress } /// /// Gets the CloudQueueMessage this instance was derived from (if any). /// public CloudQueueMessage Message { get { return this.message; } } /// /// Gets the unique identifier for the request this report is in response to. /// public string Identifier { get { return this.identifier; } } /// /// Gets the current status of the request. /// public StatusCode Status { get { return this.status; } } /// /// Gets the name of processing node that produced this report. /// public string ProcessingNode { get { return this.processingNode; } } /// /// Gets the exit code returned from the process after execution. /// public int ExitCode { get { return this.exitCode; } } /// /// Gets the standard output from the process. /// public string StandardOutput { get { return this.standardOutput; } } /// /// Gets the standard error output from the process. /// public string StandardError { get { return this.standardError; } } /// /// Gets the CPU time used by the process execution. /// public double CpuTime { get { return this.cpuTime; } } /// /// Gets the collection of files generated by the process execution. /// public IEnumerable OutputFileMappings { get { return this.outputFileMappings; } } /// /// Creates a CloudExecutionReport from a CloudQueueMessage /// representation. /// /// /// A CloudQueueMessage containing an XML document representing a /// CloudExecutionReport. /// /// /// A new report corresponding to the XML representation contained in /// the message. /// public static CloudExecutionReport FromMessage(CloudQueueMessage message) { CloudExecutionReport report = CloudExecutionReport.FromXml(message.AsString); report.message = message; return report; } /// /// Creates a CloudExecutionReport from an XML representation. /// /// /// A string containing an XML document representing a report. /// /// /// A new report corresponding to the XML representation read. /// public static CloudExecutionReport FromXml(string xs) { XmlReader xr = XmlReader.Create(new StringReader(xs)); while (xr.Read()) { if (xr.NodeType == XmlNodeType.Element) { break; } } return ReadXml(xr); } /// /// Helper function to read an XML element (not a full document) /// representing a cloud execution report. /// /// /// Note that the XmlReader is expected to be positioned in the XML /// document such that the current node is a report element. /// /// The XmlReader object to read from. /// /// A new report corresponding to the XML representation read. /// public static CloudExecutionReport ReadXml(XmlReader xr) { Util.Assert(xr.Name.Equals(CloudExecutionReport.XmlTag)); string versionText = xr.GetAttribute(CloudExecutionReport.XmlVersionAttribute); int version = int.Parse(versionText, CultureInfo.InvariantCulture); string identifier = string.Empty; StatusCode status = StatusCode.Completed; string processingNode = "Unknown Benevolence"; int exitCode = 0; string standardOutput = string.Empty; string standardError = string.Empty; double cpuTime = 0; bool inOutputFileMappings = false; List outputFileMappings = new List(); List outputFiles = new List(); while (xr.Read()) { if (xr.NodeType == XmlNodeType.Element) { switch (xr.Name) { case XmlIdentifierElement: identifier = xr.ReadElementContentAsString(); break; case XmlStatusElement: status = (StatusCode)Enum.Parse(typeof(StatusCode), xr.ReadElementContentAsString()); break; case XmlProcessingNodeElement: processingNode = xr.ReadElementContentAsString(); break; case XmlExitCodeElement: exitCode = xr.ReadElementContentAsInt(); break; case XmlStandardOutputElement: standardOutput = xr.ReadElementContentAsString(); break; case XmlStandardErrorElement: standardError = xr.ReadElementContentAsString(); break; case XmlCpuTimeElement: cpuTime = xr.ReadElementContentAsDouble(); break; case XmlOutputFileMappingsElement: inOutputFileMappings = true; break; case BuildObjectValuePointer.XmlTag: Util.Assert(inOutputFileMappings); outputFileMappings.Add(BuildObjectValuePointer.ReadXml(xr)); break; } } else if (xr.NodeType == XmlNodeType.EndElement) { if (xr.Name.Equals(CloudExecutionReport.XmlTag)) { break; // All done. } switch (xr.Name) { case XmlOutputFileMappingsElement: inOutputFileMappings = false; break; } } } // REVIEW: Require element presence? Sanity check things here? return new CloudExecutionReport( version, identifier, status, processingNode, exitCode, standardOutput, standardError, cpuTime, outputFileMappings); } /// /// Creates an XML document representing this cloud execution report. /// /// /// A string containing an XML document representing this report. /// public string ToXml() { StringBuilder sb = new StringBuilder(); XmlWriterSettings settings = new XmlWriterSettings(); settings.Indent = true; XmlWriter xw = XmlWriter.Create(sb, settings); xw.WriteStartDocument(); this.WriteXml(xw); xw.Close(); return sb.ToString(); } /// /// Helper function to write an XML element (not a full document) /// representing this result record. /// /// The XmlWriter object to write to. public void WriteXml(XmlWriter xw) { // Start writing the element for this object. xw.WriteStartElement(XmlTag); xw.WriteAttributeString(XmlVersionAttribute, this.version.ToString(CultureInfo.InvariantCulture)); // Write the Identifier element. xw.WriteElementString(XmlIdentifierElement, this.identifier); // Write the Status element. xw.WriteElementString(XmlStatusElement, this.status.ToString()); // Write the ProcessingNode element. xw.WriteElementString(XmlProcessingNodeElement, this.processingNode); if (this.status == StatusCode.Completed) { // Write the ExitCode element. xw.WriteElementString(XmlExitCodeElement, this.exitCode.ToString(CultureInfo.InvariantCulture)); // Write the Standard Output element. xw.WriteElementString(XmlStandardOutputElement, this.standardOutput); // Write the Standard Error element. xw.WriteElementString(XmlStandardErrorElement, this.standardError); // Write the CPU Time element. xw.WriteElementString(XmlCpuTimeElement, this.cpuTime.ToString(CultureInfo.InvariantCulture)); // Write the OutputFileMappings element. xw.WriteStartElement(XmlOutputFileMappingsElement); foreach (BuildObjectValuePointer outputFile in this.outputFileMappings) { outputFile.WriteXml(xw); } xw.WriteEndElement(); } // Finish writing the element for this object. xw.WriteEndElement(); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/CloudExecutionRequest.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Text; using System.Xml; using Microsoft.WindowsAzure.Storage.Queue; /// /// Message that is put on the cloud "requests" queue to ask a cloud /// execution engine to do some work on the requester's behalf. /// public class CloudExecutionRequest { /// /// XML element name for this object. /// public const string XmlTag = "CloudExecutionRequest"; /// /// Version of this object we create by default. /// private const int Version = 2; /// /// XML element name for our version field. /// private const string XmlVersionAttribute = "Version"; /// /// XML element name for our reportQueue field. /// private const string XmlReportQueueElement = "ReportQueue"; /// /// XML element name for our identifier field. /// private const string XmlIdentifierElement = "Identifier"; /// /// XML element name for our operation field. /// private const string XmlOperationElement = "Operation"; /// /// XML element name for our executable field. /// private const string XmlExecutableElement = "Executable"; /// /// XML element name for our arguments field. /// private const string XmlArgumentsElement = "Arguments"; /// /// XML element name for our inputFileMappings field. /// private const string XmlInputFileMappingsElement = "InputFileMappings"; /// /// XML element name for our outputFiles field. /// private const string XmlOutputFilesElement = "OutputFiles"; /// /// Queued message this instance was created from (if it was). /// private CloudQueueMessage message; /// /// Version of this object instance. /// private int version; /// /// Queue on which to add the report of the disposition of this request. /// private string reportQueue; /// /// Unique identifier for this request. /// private string identifier; /// /// Operation to perform. /// private Operation operation; /// /// Executable to be run. /// private string executable; /// /// Arguments to the executable. /// private string arguments; /// /// Collection of input files required for this execution, /// represented by both their item cache identifier and /// their relative path. /// private List inputFileMappings; /// /// Collection of expected output files from this execution. /// private IEnumerable outputFiles; /// /// Initializes a new instance of the CloudExecutionRequest class. /// /// /// Queue on which to add the report of the disposition of this request. /// /// Unique ID for this instance. /// Operation to perform. /// Executable to be run. /// Arguments to the executable. /// /// Input files required for this execution. /// /// Expected output files. public CloudExecutionRequest( string reportQueue, string identifier, Operation operation, string executable, string arguments, List inputFileMappings, IEnumerable outputFiles) : this( CloudExecutionRequest.Version, reportQueue, identifier, operation, executable, arguments, inputFileMappings, outputFiles) { // REVIEW: Use different random string generator for identifier? } /// /// Initializes a new instance of the CloudExecutionRequest class. /// /// Version of this class instance. /// /// Queue on which to add the report of the disposition of this request. /// /// Unique ID for this instance. /// Operation to perform. /// Executable to be run. /// Arguments to the executable. /// /// Input files required for this execution. /// /// Expected output files. private CloudExecutionRequest( int version, string reportQueue, string identifier, Operation operation, string executable, string arguments, List inputFileMappings, IEnumerable outputFiles) { this.version = version; this.reportQueue = reportQueue; this.identifier = identifier; this.operation = operation; this.executable = executable; this.arguments = arguments; this.inputFileMappings = inputFileMappings; this.outputFiles = outputFiles; } /// /// Various types of operation that can be requested. /// public enum Operation : int { /// /// Don't do anything (no-op). /// None, /// /// Run the specified executable. /// RunExecutable, /// /// Delete the specified report queue. /// DeleteQueue, /// /// Exit (and thus quit handling requests). /// CommitSuicide, } /// /// Gets the CloudQueueMessage this instance was derived from (if any). /// public CloudQueueMessage Message { get { return this.message; } } /// /// Gets the queue on which to report the disposition of this request. /// public string ReportQueue { get { return this.reportQueue; } } /// /// Gets the unique identifier for this request. /// public string Identifier { get { return this.identifier; } } /// /// Gets the operation to perform. /// public Operation RequestedOperation { get { return this.operation; } } /// /// Gets the executable to run. /// public string Executable { get { return this.executable; } } /// /// Gets the arguments to the executable. /// public string Arguments { get { return this.arguments; } } /// /// Gets the collection of files needed as input to the execution, /// as both BuildObjects and as their cached hash values. /// public IEnumerable InputFileMappings { get { return this.inputFileMappings; } } /// /// Gets the collection of potential output files from this execution, /// as BuildObjects. /// public IEnumerable OutputFiles { get { return this.outputFiles; } } /// /// Creates a CloudExecutionRequest from a CloudQueueMessage /// representation. /// /// /// A CloudQueueMessage containing an XML document representing a /// CloudExecutionRequest. /// /// /// A new request corresponding to the XML representation contained in /// the message. /// public static CloudExecutionRequest FromMessage(CloudQueueMessage message) { CloudExecutionRequest request = CloudExecutionRequest.FromXml(message.AsString); request.message = message; return request; } /// /// Creates a CloudExecutionRequest from an XML representation. /// /// /// A string containing an XML document representing a request. /// /// /// A new request corresponding to the XML representation read. /// public static CloudExecutionRequest FromXml(string xs) { XmlReader xr = XmlReader.Create(new StringReader(xs)); while (xr.Read()) { if (xr.NodeType == XmlNodeType.Element) { break; } } return ReadXml(xr); } /// /// Helper function to read an XML element (not a full document) /// representing a cloud execution request. /// /// /// Note that the XmlReader is expected to be positioned in the XML /// document such that the current node is a request element. /// /// The XmlReader object to read from. /// /// A new request corresponding to the XML representation read. /// public static CloudExecutionRequest ReadXml(XmlReader xr) { Util.Assert(xr.Name.Equals(CloudExecutionRequest.XmlTag)); string versionText = xr.GetAttribute(CloudExecutionRequest.XmlVersionAttribute); int version = int.Parse(versionText, CultureInfo.InvariantCulture); string reportQueue = "reports"; string identifier = string.Empty; Operation operation = Operation.RunExecutable; string executable = string.Empty; string arguments = string.Empty; bool inInputFileMappings = false; List inputFileMappings = new List(); bool inOutputFiles = false; List outputFiles = new List(); while (xr.Read()) { if (xr.NodeType == XmlNodeType.Element) { switch (xr.Name) { case XmlReportQueueElement: reportQueue = xr.ReadElementContentAsString(); break; case XmlIdentifierElement: identifier = xr.ReadElementContentAsString(); break; case XmlOperationElement: operation = (Operation)Enum.Parse(typeof(Operation), xr.ReadElementContentAsString()); break; case XmlExecutableElement: executable = xr.ReadElementContentAsString(); break; case XmlArgumentsElement: arguments = xr.ReadElementContentAsString(); break; case XmlInputFileMappingsElement: inInputFileMappings = true; break; case BuildObjectValuePointer.XmlTag: Util.Assert(inInputFileMappings); inputFileMappings.Add(BuildObjectValuePointer.ReadXml(xr)); break; case XmlOutputFilesElement: inOutputFiles = true; break; case BuildObject.XmlTag: Util.Assert(inOutputFiles); outputFiles.Add(BuildObject.ReadXml(xr)); break; } } else if (xr.NodeType == XmlNodeType.EndElement) { if (xr.Name.Equals(CloudExecutionRequest.XmlTag)) { break; // All done. } switch (xr.Name) { case XmlInputFileMappingsElement: inInputFileMappings = false; break; case XmlOutputFilesElement: inOutputFiles = false; break; } } } // REVIEW: Require presence of (some/all) elements? Sanity check things here? return new CloudExecutionRequest( version, reportQueue, identifier, operation, executable, arguments, inputFileMappings, outputFiles); } /// /// Creates an XML document representing this cloud execution request. /// /// /// A string containing an XML document representing this request. /// public string ToXml() { StringBuilder sb = new StringBuilder(); XmlWriterSettings settings = new XmlWriterSettings(); settings.Indent = true; XmlWriter xw = XmlWriter.Create(sb, settings); xw.WriteStartDocument(); this.WriteXml(xw); xw.Close(); return sb.ToString(); } /// /// Helper function to write an XML element (not a full document) /// representing this result record. /// /// The XmlWriter object to write to. public void WriteXml(XmlWriter xw) { // Start writing the element for this object. xw.WriteStartElement(XmlTag); xw.WriteAttributeString(CloudExecutionRequest.XmlVersionAttribute, this.version.ToString(CultureInfo.InvariantCulture)); // Write the ReportQueue element. xw.WriteElementString(XmlReportQueueElement, this.reportQueue); // Optionally write the Identifier element. if (!string.IsNullOrEmpty(this.identifier)) { xw.WriteElementString(CloudExecutionRequest.XmlIdentifierElement, this.identifier); } // Write the Operation element. xw.WriteElementString(XmlOperationElement, this.operation.ToString()); if (this.operation == Operation.RunExecutable) { // Write the Executable element. xw.WriteElementString(XmlExecutableElement, this.executable); // Write the Arguments element. xw.WriteElementString(XmlArgumentsElement, this.arguments); // Write the InputFileMappings element. xw.WriteStartElement(XmlInputFileMappingsElement); foreach (BuildObjectValuePointer inputFile in this.inputFileMappings) { inputFile.WriteXml(xw); } xw.WriteEndElement(); // Write the OutputFiles element. xw.WriteStartElement(XmlOutputFilesElement); foreach (BuildObject outputFile in this.outputFiles) { outputFile.WriteXml(xw); } xw.WriteEndElement(); } // Finish writing the element for this object. xw.WriteEndElement(); } /// /// Gets a string representation of this instance. /// Primarily intended as a debugging aid. /// /// A string representation of this instance. public override string ToString() { StringBuilder output = new StringBuilder(); output.AppendFormat("Version: {0}", this.version); output.AppendLine(); output.AppendFormat("Report Queue: {0}", this.reportQueue); output.AppendLine(); output.AppendFormat("Identifier: {0}", this.identifier); output.AppendLine(); output.AppendFormat("Operation: {0}", this.operation); output.AppendLine(); output.AppendFormat("Executable: {0}", this.executable); output.AppendLine(); output.AppendFormat("Arguments: {0}", this.arguments); output.AppendLine(); output.AppendFormat("InputFileMappings ({0} files):", this.inputFileMappings.Count); output.AppendLine(); #if false foreach (BuildObjectValuePointer mapping in this.inputFileMappings) { output.AppendFormat("{0} = {1}", mapping.RelativePath, mapping.ObjectHash); output.AppendLine(); } #endif output.AppendLine("OutputFiles:"); foreach (BuildObject file in this.outputFiles) { output.AppendLine(file.getRelativePath()); } return output.ToString(); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/CloudExecutionWaiter.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Threading; /// /// Represents a thread waiting for a particular cloud execution report. /// internal class CloudExecutionWaiter { /// /// Event that is signalled when a new report is ready. /// private AutoResetEvent reportIsReady; /// /// Execution report that just arrived. /// private CloudExecutionReport executionReport; /// /// Count of other waiters. /// private int otherWaitersCount; /// /// Initializes a new instance of the CloudExecutionWaiter class. /// public CloudExecutionWaiter() { this.reportIsReady = new AutoResetEvent(false); } /// /// Wait for an execution report to arrive. /// /// Count of other report waiters. /// An execution report. public CloudExecutionReport WaitForReport(out int numberOfOtherWaiters) { this.reportIsReady.WaitOne(); numberOfOtherWaiters = this.otherWaitersCount; return this.executionReport; } /// /// Give an execution report to this waiter. /// /// The execution report to give. /// Count of other report waiters. public void GiveReportToWaiter(CloudExecutionReport executionReport, int numberOfOtherWaiters) { this.executionReport = executionReport; this.otherWaitersCount = numberOfOtherWaiters; this.reportIsReady.Set(); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/CloudSubmitter.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Text; /// /// Submits requests for verb execution to remote cloud worker pool. /// internal class CloudSubmitter : IProcessInvoker { /// /// Whether to always emit diagnostic output. /// private const bool AlwaysEmitDiagnostics = true; /// /// The CPU time used by the process, in seconds. /// private double cpuTime; /// /// The exit code returned by the process. /// private int exitCode; /// /// Where standard out is collected by default. /// private string stdout; /// /// Where standard error is collected. /// private string stderr; /// /// The private working directory for the process we invoke. /// private WorkingDirectory workingDirectory; /// /// Initializes a new instance of the CloudSubmitter class. /// /// /// Unique identifier for this request. /// /// /// Working directory the process is started in. /// /// /// List of input files expected by the process. /// /// /// List of potential output files generated by the process. /// /// Executable to run. /// /// Command line arguments to provide to the executable. /// /// Not sure what this is -- some debugging/diagnostic thing. /// Where to (optionally) store the captured standard out. /// Debugging text for something or another. public CloudSubmitter( string requestIdentifier, WorkingDirectory workingDirectory, IEnumerable inputFiles, IEnumerable outputFiles, string executable, string[] args, BuildObject failureBase, BuildObject captureStdout = null, string dbgText = null) { // Catch bad verb authors before they hurt themselves. Util.Assert(!executable.Contains(":")); // Hey, this looks like an absolute path! Use .getRelativePath(); it makes your output more stable. foreach (string arg in args) { // Pardon my distasteful heuristic to avoid flagging /flag:value args. Util.Assert(arg.Length < 2 || arg[1] != ':'); // Hey, this looks like an absolute path! Use .getRelativePath() to tolerate crossing machine boundaries. } // Stash away things we'll want to remember later. this.workingDirectory = workingDirectory; // Create list of input file mappings. // REVIEW: We're not running on the main thread at this point. Are below calls all thread-safe? List inputFileMappings = new List(); foreach (BuildObject file in inputFiles) { string fileHash = BuildEngine.theEngine.Repository.GetHash(file); Util.Assert(!string.IsNullOrEmpty(fileHash)); inputFileMappings.Add(new BuildObjectValuePointer(fileHash, file.getRelativePath())); // Ensure that the input files are in the cloud cache. // REVIEW: best way to determine this is a source file? ItemCacheContainer container; if (file is SourcePath) { container = ItemCacheContainer.Sources; } else { container = ItemCacheContainer.Objects; } ItemCacheMultiplexer multiplexedCache = BuildEngine.theEngine.ItemCache as ItemCacheMultiplexer; Util.Assert(multiplexedCache != null); multiplexedCache.SyncItemToCloud(container, fileHash); } // Prepare cloud execution request for submission. string arguments = string.Join(" ", args); CloudExecutionRequest request = new CloudExecutionRequest( BuildEngine.theEngine.CloudReportQueueName, requestIdentifier, CloudExecutionRequest.Operation.RunExecutable, executable, arguments, inputFileMappings, outputFiles); BuildEngine.theEngine.CloudExecutionQueue.SubmitRequest(request); // Wait for remote execution to finish. int requestsOutstanding; Console.WriteLine("Waiting on remote execution report for request '{0}'.", requestIdentifier); CloudExecutionReport executionReport = BuildEngine.theEngine.CloudExecutionQueue.GetReport(requestIdentifier, out requestsOutstanding); Console.WriteLine("Received remote execution report for request '{0}'. {1} others still outstanding.", requestIdentifier, requestsOutstanding); // Record what we got back. this.exitCode = executionReport.ExitCode; this.stdout = executionReport.StandardOutput; this.stderr = executionReport.StandardError; this.cpuTime = executionReport.CpuTime; // Copy output files from cloud cache back to local working dir. // REVIEW: This is just to set things up as expected for the // Scheduler's recordResult routine. Could re-architect this to // be more efficient for the remote execution case. foreach (BuildObjectValuePointer outputFileMapping in executionReport.OutputFileMappings) { BuildEngine.theEngine.CloudCache.FetchItemToFile( ItemCacheContainer.Objects, outputFileMapping.ObjectHash, workingDirectory.PathTo(outputFileMapping.RelativePath)); } } /// /// Gets the exit code returned by the process. /// public int ExitCode { get { return this.exitCode; } } /// /// Gets the CPU time used by the process, in seconds. /// public double CpuTime { get { return this.cpuTime; } } /// /// Gets the process's standard output in the default case. /// Does not return the standard output if it is redirected to a file /// (i.e. if captureStdout is non-null). /// /// The process's standard output. public string GetStdout() { return this.stdout; } /// /// Gets the process's standard error output.. /// /// The process's standard error output. public string GetStderr() { return this.stderr; } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/ConcatContext.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; internal class ConcatContext : IncludePathContext { private List contexts; private string descr; public ConcatContext(IEnumerable contexts) { this.contexts = new List(contexts); this.descr = "Context(" + string.Join(",", this.contexts) + ")"; } public override string ToString() { return this.descr; } public override BuildObject search(string basename, ModPart modPart = ModPart.Ifc) { foreach (IIncludePathContext context in this.contexts) { BuildObject obj = context.search(basename, modPart); if (obj != null) { return obj; } } return null; } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/ConcatContextVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Linq; internal class ConcatContextVerb : ContextGeneratingVerb { private List parents; public ConcatContextVerb(IEnumerable parents, PoundDefines poundDefines) : base("Cat(" + string.Join(",", parents) + ")", poundDefines) { this.parents = new List(parents); } public ConcatContextVerb(IContextGeneratingVerb parentA, IContextGeneratingVerb parentB, PoundDefines poundDefines) : this(new IContextGeneratingVerb[] { parentA, parentB }, poundDefines) { } public ConcatContextVerb(IContextGeneratingVerb parentA, IContextGeneratingVerb parentB, IContextGeneratingVerb parentC, PoundDefines poundDefines) : this(new IContextGeneratingVerb[] { parentA, parentB, parentC }, poundDefines) { } public override IEnumerable getDependencies(out DependencyDisposition ddisp) { ddisp = DependencyDisposition.Complete; return this.parents.Select(parent => parent.getContextOutput()); } public override IEnumerable getVerbs() { return this.parents; } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { IEnumerable contexts = this.parents.Select(parent => ((ContextContents)BuildEngine.theEngine.Repository.FetchVirtual(parent.getContextOutput())).Context); ConcatContext context = new ConcatContext(contexts); ContextContents contents = new ContextContents(context); BuildEngine.theEngine.Repository.StoreVirtual(this.getContextOutput(), new Fresh(), contents); return new VerbSyncWorker(workingDirectory, new Fresh()); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/ContextContents.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; internal class ContextContents : VirtualContents { private IIncludePathContext context; public ContextContents(IIncludePathContext context) { this.context = context; } public IIncludePathContext Context { get { return this.context; } } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/ContextGeneratingVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; internal abstract class ContextGeneratingVerb : Verb, IContextGeneratingVerb { public const string CONTEXT_EXTN = ".ctxt"; // Virtual, so it shouldn't appear in filesystem. private int version = 1; private string nickname; private PoundDefines poundDefines; private BuildObject outputObj; /// NB nickname will need to be unique over a run; it's used as the verb AbstractIdentifier, and /// hence hash identity in caches. public ContextGeneratingVerb(string nickname, PoundDefines poundDefines) { this.nickname = nickname; this.poundDefines = poundDefines; } public PoundDefines getPoundDefines() { return this.poundDefines; } public string getContextIdentifier() { return this.nickname; } public override AbstractId getAbstractIdentifier() { return new AbstractId(this.GetType().Name, this.version, this.getContextIdentifier()); } public override IEnumerable getOutputs() { return new BuildObject[] { this.getContextOutput() }; } public BuildObject getContextOutput() { if (this.outputObj == null) { this.outputObj = new VirtualBuildObject( Path.Combine(BuildEngine.theEngine.getVirtualRoot(), Util.mungeClean(this.getAbstractIdentifier().ToString()) + CONTEXT_EXTN)); } return this.outputObj; } } internal static class ContextGeneratingVerbExtensions { internal static IIncludePathContext fetchIfAvailable(this IContextGeneratingVerb verb, ref DependencyDisposition ddisp) { try { return ((ContextContents) BuildEngine.theEngine.Repository.FetchVirtual(verb.getContextOutput())).Context; } catch (ObjectNotReadyException) { // Oh, we don't even have the context object yet. ddisp = ddisp.combine(DependencyDisposition.Incomplete); } catch (ObjectFailedException) { ddisp = ddisp.combine(DependencyDisposition.Failed); } return null; } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/CustomManifestParser.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; using System.Text; internal class CustomManifestParser { private HashSet dependencies = new HashSet(); private HashSet outputs = new HashSet(); public CustomManifestParser(SourcePath basePath) { this.parseCustomManifest(basePath); } public IEnumerable getDependencies() { return this.dependencies; } public IEnumerable getOutputs() { return this.outputs; } private void parseCustomManifest(SourcePath basePath) { SourcePath manifest = basePath.getNewSourcePath("nubuild-manifest.txt"); this.dependencies.Add(manifest); using (StreamReader stream = new StreamReader(IronRootDirectory.PathTo(manifest))) { string origline; while ((origline = stream.ReadLine()) != null) { string line = origline.Trim(); if (line.Length == 0) { continue; } if (line.Substring(0, 1) == "#") { continue; } string[] parts = line.Split(); if (parts.Length != 2) { throw new UserError(string.Format("{0}: badly formed manifest line {1}", IronRootDirectory.PathTo(manifest), origline)); } if ("output".Equals(parts[0])) { this.outputs.Add(new BuildObject(Path.Combine(basePath.getDirPath(), parts[1]))); } else if ("dependency".Equals(parts[0])) { this.dependencies.Add(basePath.getNewSourcePath(parts[1])); } } } } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/DafnyCCVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; using System.Linq; internal class DafnyCCVerb : DafnyTransformBaseVerb { private AbstractId abstractId; private FramePointerMode useFramePointer; private VSSolutionVerb dafnyCCBuildExecutableVerb; public DafnyCCVerb(SourcePath dfyroot, string appLabel, FramePointerMode useFramePointer) : base(dfyroot, appLabel) { this.useFramePointer = useFramePointer; this.abstractId = new AbstractId(this.GetType().Name, this.getVersion() + version, dfyroot.ToString(), concrete: useFramePointer.ToString()); this.dafnyCCBuildExecutableVerb = new VSSolutionVerb(new SourcePath("tools\\DafnyCC\\DafnyCC.sln", SourcePath.SourceType.Tools)); } public enum FramePointerMode { UseFramePointer, NoFramePointer } public override IEnumerable getVerbs() { return base.getVerbs().Concat(new[] { this.dafnyCCBuildExecutableVerb }); } public override AbstractId getAbstractIdentifier() { return this.abstractId; } // This is merely an assert double-check that we didn't let a spec generated // by DafnyCC slip through to be used in the BoogieAsmVerify step. internal static void AssertSmellsImplementy(BuildObject obj) { string fn = obj.getFileNameWithoutExtension(); Util.Assert(fn.EndsWith("_" + DafnyTransformBaseVerb.DAFNY_I_SUFFIX) || fn.EndsWith("_" + DafnyTransformBaseVerb.DAFNY_C_SUFFIX) || fn.Equals("Checked") || fn.Equals("Heap") || fn.Equals("Seq")); } protected override int getVersion() { return 18; } protected override BuildObject getExecutable() { return new BuildObject(Path.Combine(this.dafnyCCBuildExecutableVerb.getOutputPath().getRelativePath(), "dafnycc.exe")); } protected override IEnumerable getExtraDependencies() { string exePath = this.dafnyCCBuildExecutableVerb.getOutputPath().getRelativePath(); // REVIEW: Should we extract the dafnycc.exe dependencies from the project file instead of listing them manually? // REVIEW: What about Graph.dll? Not needed? return new BuildObject[] { new BuildObject(Path.Combine(exePath, "Basetypes.dll")), new BuildObject(Path.Combine(exePath, "CodeContractsExtender.dll")), new BuildObject(Path.Combine(exePath, "Core.dll")), new BuildObject(Path.Combine(exePath, "DafnyPipeline.dll")), new BuildObject(Path.Combine(exePath, "ParserHelper.dll")), new BuildObject(Path.Combine(exePath, "Provers.SMTLib.dll")), new BuildObject(Path.Combine(exePath, "VCGeneration.dll")), new BuildObject(Path.Combine(exePath, "z3.exe")), getDafnyPrelude() }; } protected override IEnumerable getRootArgs() { DependencyDisposition ddisp; IEnumerable result = getAllDafnyModules(out ddisp); Util.Assert(ddisp == DependencyDisposition.Complete); return result; } protected override IEnumerable getExtraSpecialOutputs() { // Work around some undesirable behavior presently in DafnyCC: // We can't pass DafnyPrelude on the command line (getRootArgs) to DafnyCC, // yet it emits a dafny_DafnyPrelude file that we want to account for in the output. return new string[] { "Checked", "Heap", "Seq" }; ////, "dafny_DafnyPrelude" }; } protected override void addExtraArgs(List args) { args.Add("/relational"); if (this.useFramePointer == FramePointerMode.UseFramePointer) { args.Add("/useFramePointer"); } } protected override IEnumerable getRoots() { return new SourcePath[] { new SourcePath("src\\Trusted\\DafnySpec\\Seq.s.dfy"), new SourcePath("src\\Checked\\Libraries\\DafnyCC\\Seq.dfy"), dfyroot }; } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/DafnyCompileOneVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; /// /// Verb to compile Dafny source code to CSharp target. /// internal class DafnyCompileOneVerb : Verb, IProcessInvokeAsyncVerb { private const int Version = 10; private const string IntermediateSourceFilename = "ExpandedSource.dfy"; private const string CSharpExt = ".cs"; private readonly SourcePath input; private readonly BuildObject output; private readonly AbstractId abstractId; private readonly IVerb[] verbs; private readonly DafnyTransitiveDepsVerb transitiveDepsVerb; private List dependencies; private SourcePath expandedSource; public DafnyCompileOneVerb(SourcePath input) { if (input == null) { throw new ArgumentNullException("input"); } this.abstractId = new AbstractId(GetType().Name, Version, input.ToString()); this.input = input; this.output = input.makeOutputObject(CSharpExt); this.transitiveDepsVerb = new DafnyTransitiveDepsVerb(input); this.verbs = new IVerb[] { this.transitiveDepsVerb }; } public override IEnumerable getDependencies(out DependencyDisposition ddisp) { if (this.dependencies == null) { DependencyDisposition dd; var dependencies = new List(); // This method's implementation is dependent upon transitiveDepsVerb being the only element of verbs. Trace.Assert(this.verbs.Length == 1 && this.verbs[0] is DafnyTransitiveDepsVerb); dependencies.AddRange(this.transitiveDepsVerb.getAvailableDeps(out dd)); dependencies.AddRange(DafnyExecutableDependencies.getDafnyExecutableDependencies()); if (dd != DependencyDisposition.Complete) { ddisp = dd; // Dependency resolution isn't complete yet and we don't want to cache the incomplete list. return dependencies; } this.dependencies = dependencies; } Trace.Assert(this.dependencies != null); ddisp = DependencyDisposition.Complete; return this.dependencies; } public override IEnumerable getVerbs() { return this.verbs; } public override IEnumerable getOutputs() { return new[] { this.output }; } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { // First expand our Dafny source file to inline all its includes. this.expandedSource = this.input.getNewSourcePath("ExpandedSource.dfy"); DafnyIncludes dafnyIncludes = new DafnyIncludes(); dafnyIncludes.ExpandDafny(workingDirectory, this.input, this.expandedSource); // Call Dafny.exe to compile Dafny source to CSharp target. var args = new[] { "/noVerify", "/spillTargetCode:1", "/compile:2", "/ironDafny", this.expandedSource.getRelativePath() }; Console.WriteLine("expanded source: " + this.expandedSource.getRelativePath()); ////Logger.WriteLine("arguments: " + String.Join(" ", args)); return new ProcessInvokeAsyncWorker( workingDirectory, this, DafnyExecutableDependencies.getDafnyExecutable().getRelativePath(), args, ProcessExitCodeHandling.NonzeroIsFailure, getDiagnosticsBase(), returnStandardOut: true, // REVIEW: Doesn't appear to be needed. returnStandardError: true, // REVIEW: Doesn't appear to be needed. allowCloudExecution: true); } public override AbstractId getAbstractIdentifier() { return this.abstractId; } public Disposition Complete(WorkingDirectory workingDirectory, double cpuTimeSeconds, string stdout, string stderr, Disposition disposition) { var dis = disposition; string cSharpPath = Path.ChangeExtension(workingDirectory.PathTo(this.expandedSource), CSharpExt); if (!File.Exists(cSharpPath)) { // Dafny has a bug where compilation fails but result code is still 0. dis = new Failed(); } if (dis is Fresh) { this.RewriteCSharpFile(cSharpPath, workingDirectory.PathTo(this.output)); } return dis; } private void RewriteCSharpFile(string inputPath, string outputPath) { using (TextWriter writer = new StreamWriter(outputPath)) { // Compile a list of namespaces that require edits var namespaces = new Dictionary(); using (TextReader reader = new StreamReader(inputPath)) { string line; System.Text.RegularExpressions.Regex pattern = new System.Text.RegularExpressions.Regex("namespace @_(\\d+)_([\\w_]+) {", System.Text.RegularExpressions.RegexOptions.Compiled); while ((line = reader.ReadLine()) != null) { var result = pattern.Match(line); if (result.Success) { string old_name = "_" + result.Groups[1] + "_" + result.Groups[2]; string new_name = "_" + result.Groups[2]; namespaces.Add(old_name, new_name); } } } using (TextReader reader = new StreamReader(inputPath)) { string line; while ((line = reader.ReadLine()) != null) { line = line.Replace(IntermediateSourceFilename, this.input.getFileName()); line = line.Replace("public class @__default {", "public partial class @__default {"); line = line.Replace("@#", "@"); // Temporary work-around. ToDo: Remove this after Dafny is fixed. line = line.Replace("public class ", "public partial class "); // Another temporary work-around. ToDo: Figure out better solution. line = line.Replace("@_default_Main", "@IronfleetMain"); // Find a more efficient approach? foreach (KeyValuePair entry in namespaces) { line = line.Replace(entry.Key, entry.Value); } writer.WriteLine(line); } } } } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/DafnyExecutableDependencies.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace NuBuild { class DafnyExecutableDependencies { private static SourcePath dafnyExecutable; public static SourcePath getDafnyExecutable() { // TODO this should eventually be a BuildObject from *building* the executable. if (dafnyExecutable == null) { dafnyExecutable = new SourcePath("tools\\Dafny\\Dafny.exe", SourcePath.SourceType.Tools); } return dafnyExecutable; } public static IEnumerable getDafnyExecutableDependencies() { List exeDepends = new List(); exeDepends.Add(getDafnyExecutable()); exeDepends.Add(new SourcePath("tools\\Dafny\\AbsInt.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\BaseTypes.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\CodeContractsExtender.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\Concurrency.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\Core.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\Dafny.exe.config", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\DafnyPipeline.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\DafnyPrelude.bpl", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\Doomed.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\ExecutionEngine.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\Graph.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\Model.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\msvcp100.dll", SourcePath.SourceType.Tools)); // Needed by z3. exeDepends.Add(new SourcePath("tools\\Dafny\\msvcr100.dll", SourcePath.SourceType.Tools)); // Needed by z3. exeDepends.Add(new SourcePath("tools\\Dafny\\ParserHelper.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\Provers.SMTLib.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\VCExpr.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\VCGeneration.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\Dafny\\vcomp100.dll", SourcePath.SourceType.Tools)); // Needed by z3. exeDepends.Add(new SourcePath("tools\\Dafny\\DafnyRuntime.cs", SourcePath.SourceType.Tools)); // Needed for compilation exeDepends.Add(new SourcePath("tools\\Dafny\\z3.exe", SourcePath.SourceType.Tools)); return exeDepends; } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/DafnyExtensions.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Linq; internal class DafnyExtensions { public static HashSet getForestDependencies(IEnumerable roots, out DependencyDisposition ddisp) { HashSet result = new HashSet(); ddisp = DependencyDisposition.Complete; foreach (BuildObject dfysource in roots) { TransitiveDepsVerb depsVerb = new DafnyTransitiveDepsVerb(dfysource); DependencyDisposition localDDisp; result.UnionWith(depsVerb.getAvailableDeps(out localDDisp)); ddisp = ddisp.combine(localDDisp); result.Add(dfysource); // TransitiveDeps *exclude* the root, so we need to add that in, too. } return result; } public static IEnumerable getForestVerbs(IEnumerable roots) { return roots.Select(root => new DafnyTransitiveDepsVerb(root)); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/DafnyIncludes.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; using System.Text.RegularExpressions; /// /// Extractor of Dafny include file names (and related functionality). /// internal class DafnyIncludes : IIncludeFactory { /// /// Regular expression matching Dafny include lines. /// private Regex includeRegex; /// /// Temporary working directory used by ExpandDafny method. /// private WorkingDirectory workingDirectory; /// /// TextWriter used by ExpandDafny method. /// private TextWriter outputWriter; /// /// Set of include files already visited. /// Used by ExpandDafny method. /// private HashSet visited; /// /// Initializes a new instance of the DafnyIncludes class. /// public DafnyIncludes() { this.includeRegex = new Regex("^\\s*include\\s*\"(.*)\""); } /// /// Gets a list of the include files included in the given Dafny source file. /// /// Source file to extract include file names from. /// List of include file BuildObjects. public IEnumerable getIncludes(BuildObject dfysource) { List outlist = new List(); using (TextReader tr = BuildEngine.theEngine.Repository.OpenRead(dfysource)) { while (true) { string line = tr.ReadLine(); if (line == null) { break; } Match match = this.includeRegex.Match(line); int count = 0; while (match.Success) { string includedPath = match.Groups[1].ToString(); string gluedPath = Path.Combine(dfysource.getDirPath(), includedPath); SourcePath sp = new SourcePath(gluedPath); outlist.Add(sp); count += 1; match = match.NextMatch(); // That would be unexpected! } Util.Assert(count <= 1); } } ////Logger.WriteLine(String.Format("{0} includes {1} things", dfysource.getFilesystemPath(), outlist.Count)); return outlist; } /// /// Expand a dafny source file to include all of its includes inline. /// /// Temporary working directory to use. /// Source build object. /// Where to create build object for expanded source file. public void ExpandDafny(WorkingDirectory workingDirectory, SourcePath input, SourcePath output) { // Prepare the output stream. using (TextWriter outWriter = new StreamWriter(workingDirectory.PathTo(output))) { // Stash away a few things for use by our recursive helper function. this.workingDirectory = workingDirectory; this.outputWriter = outWriter; this.visited = new HashSet(); // Recursively expand the initial Dafny source file to inline all of its includes. this.ExpandDafnyRecurse(input); } // Cache the output file in the Repository. BuildEngine.theEngine.Repository.Store(workingDirectory, output, new Fresh()); } /// /// Helper function for ExpandDafny method. /// /// Next include file to visit. /// True if the given file wasn't already included, false otherwise. private bool ExpandDafnyRecurse(SourcePath input) { // Only visit each unique include file once. // Note that SourcePaths (like all BuildObjects) have normalized file paths. string inputPath = input.getRelativePath(); if (this.visited.Contains(inputPath)) { return false; } else { this.visited.Add(inputPath); } using (TextReader reader = new StreamReader(this.workingDirectory.PathTo(input))) { while (true) { string line = reader.ReadLine(); if (line == null) { return true; } Match match = this.includeRegex.Match(line); if (match.Success) { // This is an "include" line. Find the included object. string includedPath = match.Groups[1].ToString(); string gluedPath = Path.Combine(input.getDirPath(), includedPath); SourcePath nextInclude = new SourcePath(gluedPath); string nextPath = nextInclude.getRelativePath(); // Recurse on the new include file. this.outputWriter.WriteLine("//- Begin include {0} (from {1})", nextPath, inputPath); if (!this.ExpandDafnyRecurse(nextInclude)) { this.outputWriter.WriteLine("//- Already included {0}", nextPath); } this.outputWriter.WriteLine("//- End include {0} (from {1})", nextPath, inputPath); } else { // This isn't an "include" line. Write it to our output. this.outputWriter.WriteLine(line); } } } } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/DafnySpecVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; using System.Linq; internal class DafnySpecVerb : DafnyTransformBaseVerb { private AbstractId abstractId; private VSSolutionVerb dafnySpecBuildExecutableVerb; public DafnySpecVerb(SourcePath dfyroot, string appLabel) : base(dfyroot, appLabel) { this.abstractId = new AbstractId(this.GetType().Name, this.getVersion() + version, dfyroot.ToString()); this.dafnySpecBuildExecutableVerb = new VSSolutionVerb(new SourcePath("tools\\DafnySpec\\DafnySpec.sln", SourcePath.SourceType.Tools)); } public override AbstractId getAbstractIdentifier() { return this.abstractId; } public override IEnumerable getVerbs() { return base.getVerbs().Concat(new[] { this.dafnySpecBuildExecutableVerb }); } protected override int getVersion() { return 15; } protected override BuildObject getExecutable() { return new BuildObject(Path.Combine(this.dafnySpecBuildExecutableVerb.getOutputPath().getRelativePath(), "dafnyspec.exe")); } protected override IEnumerable getExtraDependencies() { string exePath = this.dafnySpecBuildExecutableVerb.getOutputPath().getRelativePath(); // REVIEW: Should we extract the dafnyspec.exe dependencies from the project file instead of listing them manually? return new BuildObject[] { new BuildObject(Path.Combine(exePath, "DafnySpecAst.dll")), new BuildObject(Path.Combine(exePath, "Parser.dll")), }; } protected override IEnumerable getRoots() { // TODO why doesn't DafnyCC require DafnyPreludePath? return new SourcePath[] { this.getDafnyPrelude(), this.getSeqSpec(), dfyroot }; } protected override bool transformFilterAccepts(BuildObject dfysource) { string fn = dfysource.getFileNameWithoutExtension(); if (fn.EndsWith("." + DafnyTransformBaseVerb.DAFNY_S_SUFFIX)) { return true; } else { Util.Assert(fn.EndsWith("." + DafnyTransformBaseVerb.DAFNY_I_SUFFIX) || fn.EndsWith("." + DafnyTransformBaseVerb.DAFNY_C_SUFFIX) || dfysource.Equals(this.getDafnyPrelude())); return false; } } protected override IEnumerable getRootArgs() { OrderPreservingSet specFiles = new OrderPreservingSet(); specFiles.Add(this.getDafnyPrelude()); specFiles.Add(this.getSeqSpec()); DependencyDisposition ddisp; foreach (SourcePath src in this.getAllDafnyModules(out ddisp)) { if (this.transformFilterAccepts(src)) { specFiles.Add(src); } } return specFiles; } private SourcePath getSeqSpec() { return new SourcePath("src\\Trusted\\DafnySpec\\Seq.s.dfy"); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/DafnyTransformBaseVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; using System.Linq; internal abstract class DafnyTransformBaseVerb : Verb, IProcessInvokeAsyncVerb { public const char DAFNY_S_SUFFIX = 's'; // a trusted specification file public const char DAFNY_C_SUFFIX = 'c'; // a checked specification file public const char DAFNY_I_SUFFIX = 'i'; // a checked implementation file public static readonly char[] DAFNY_SUFFIXES = { DAFNY_S_SUFFIX, DAFNY_C_SUFFIX, DAFNY_I_SUFFIX }; // REVIEW: Never used? public static readonly string[] DAFNY_LONG_EXTNS = { "." + DAFNY_S_SUFFIX + DafnyVerifyOneVerb.DAFNY_EXTN, "." + DAFNY_C_SUFFIX + DafnyVerifyOneVerb.DAFNY_EXTN, "." + DAFNY_I_SUFFIX + DafnyVerifyOneVerb.DAFNY_EXTN }; protected const int version = 15; protected const string DAFNY_PRELUDE_DIRECTORY = "tools\\DafnySpec"; protected const string DAFNY_PRELUDE_FILENAME = "DafnyPrelude.dfy"; protected SourcePath dfyroot; protected string appLabel; public DafnyTransformBaseVerb(SourcePath dfyroot, string appLabel) { this.dfyroot = dfyroot; this.appLabel = appLabel; // REVIEW: This is never used by anything. Remove? IEnumerable roots = this.getRoots().Select(obj => obj.ToString()); } private delegate void Tacker(BuildObject dfysource, string filename); public override IEnumerable getDependencies(out DependencyDisposition ddisp) { HashSet result = DafnyExtensions.getForestDependencies(this.getRoots(), out ddisp); result.Add(this.getExecutable()); result.UnionWith(this.getExtraDependencies()); return result; } public override IEnumerable getVerbs() { return DafnyExtensions.getForestVerbs(this.getRoots()); } public override IEnumerable getOutputs() { List outputs = new List(); foreach (InOutMapping mapping in this.getInOutMappings()) { if (mapping.dfysource == null || mapping.dfysource.Equals(this.getDafnyPrelude()) || this.transformFilterAccepts(mapping.dfysource)) { outputs.Add(mapping.basmIfc); outputs.Add(mapping.basmImp); } } outputs.Add(new BuildObject(Path.Combine( this.getDestPath(), "dafny_modules.txt"))); return outputs; } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { BuildObject absDestPath = this.getAbsDestPath(); ////Directory.Delete(vfs.ToPath(absDestPath), true); // This verb should be the only one writing here, so let's keep it tidy. Directory.CreateDirectory(workingDirectory.PathTo(absDestPath)); // REVIEW: Shouldn't PrepareForVerb already do this? string dafnyccExecutable = this.getExecutable().getRelativePath(); List args = new List(); args.AddRange(this.getRootArgs().Select(sp => sp.getRelativePath())); args.Add("/outdir:" + this.getDestPath()); this.addExtraArgs(args); return new ProcessInvokeAsyncWorker( workingDirectory, this, dafnyccExecutable, args.ToArray(), ProcessExitCodeHandling.NonzeroIsFailure, getDiagnosticsBase()); } public Disposition Complete(WorkingDirectory workingDirectory, double cpuTimeSeconds, string stdout, string stderr, Disposition disposition) { if (disposition is Failed) { return disposition; } HashSet createdFiles = new HashSet(Directory.GetFiles(workingDirectory.PathTo(this.getAbsDestPath())).Select(path => Path.GetFileName(path))); HashSet expectedFiles = new HashSet(this.getOutputs().Select(obj => obj.getFileName())); // DafnyCC/DafnySpec process a big batch of files together. Did we correctly understand what it did? if (!createdFiles.SetEquals(expectedFiles)) { // REVIEW: These are never used by anything. Remove? bool dummy = createdFiles.SetEquals(expectedFiles); int missing = expectedFiles.Except(createdFiles).Count(); int extra = createdFiles.Except(expectedFiles).Count(); string msg = "Missing files: " + string.Join(",", expectedFiles.Except(createdFiles)) + "\n" + " Extra files: " + string.Join(",", createdFiles.Except(expectedFiles)); return new Failed(msg); } // Propagate the NuBuild annotations. foreach (InOutMapping mapping in this.getInOutMappings()) { if (mapping.dfysource != null && this.transformFilterAccepts(mapping.dfysource)) { AnnotationScanner.transferAnnotations( workingDirectory, mapping.dfysource, mapping.basmIfc, BoogieAsmDepBase.CommentSymbol); AnnotationScanner.transferAnnotations( workingDirectory, mapping.dfysource, mapping.basmImp, BoogieAsmDepBase.CommentSymbol); } } return new Fresh(); } protected abstract int getVersion(); protected abstract BuildObject getExecutable(); // getRoots is the set of dafny files from which we explore to // discover the set of dependencies. We use the same transitive // closure to compute the set of allDafnyModules, which tell // us what output files to expect. protected abstract IEnumerable getRoots(); // roots -> dependencies // roots -> allDafnyModules -> getRootArgs // getRootArgs is the set of dafny files we hand to the executable. // In the DafnyCC case, it's the transitive closure (allDafnyModules), // in the DafnySpec case, it's the roots only. Weird. And there are // weird exceptions in both cases. protected abstract IEnumerable getRootArgs(); protected virtual IEnumerable getExtraDependencies() { return new BuildObject[] { }; } protected virtual IEnumerable getExtraSpecialOutputs() { return new string[] { }; } protected virtual void addExtraArgs(List args) { } protected virtual bool transformFilterAccepts(BuildObject dfysource) { return true; } protected virtual IEnumerable getAllDafnyModules(out DependencyDisposition ddisp) { HashSet result = DafnyExtensions.getForestDependencies(this.getRoots(), out ddisp); // Now we assert that all Dafny inputs are actually SourcePaths. HashSet rc = new HashSet(); foreach (BuildObject obj in result) { if (obj.getExtension().EndsWith(DafnyVerifyOneVerb.DAFNY_EXTN)) { rc.Add((SourcePath)obj); } else { Util.Assert(obj.getExtension().EndsWith(TransitiveDepsVerb.TDEP_EXTN)); // Discard it. } } return rc; } protected SourcePath getDafnyPrelude() { return new SourcePath(Path.Combine(DAFNY_PRELUDE_DIRECTORY, DAFNY_PRELUDE_FILENAME), SourcePath.SourceType.Tools); } private string getDestPath() { // This logic duplicates BuildObject.makeLabeledOutputObject; the interface isn't tidily // factored for reuse yet. string path = this.GetType().Name; if (this.appLabel != null) { path = Path.Combine(this.appLabel, path); } path = Path.Combine(BuildEngine.theEngine.getObjRoot(), path); return path; } private BuildObject basmOutputForDafnyModule(string modulename, string extn) { bool isTrusted = (modulename.EndsWith("_" + DAFNY_S_SUFFIX) || modulename.Equals("Trusted")) && BeatExtensions.whichPart(extn) == ModPart.Imp; return new BuildObject(Path.Combine(this.getDestPath(), modulename + extn), isTrusted: isTrusted); } private BuildObject getAbsDestPath() { return new BuildObject(this.getDestPath()); } private List getInOutMappings() { List mapping = new List(); Tacker tack = delegate(BuildObject dfysource, string filename) { mapping.Add(new InOutMapping( dfysource, this.basmOutputForDafnyModule(filename, BoogieAsmVerifyVerb.BASMIFC_EXTN), this.basmOutputForDafnyModule(filename, BoogieAsmVerifyVerb.BASMIMP_EXTN))); }; DependencyDisposition ddispDummy; foreach (SourcePath dfy in this.getAllDafnyModules(out ddispDummy)) { // Trim off ".dfy" but not ".s" or ".i". string dfyname = dfy.getFileName(); Util.Assert(dfyname.EndsWith(".dfy")); string basename = dfyname.Substring(0, dfyname.Length - 4); Util.Assert(basename.Equals(dfy.getFileNameWithoutExtension())); // TODO delete prior lines. basename = Util.dafnySpecMungeName(basename); if ((this is DafnyCCVerb) && (basename.Equals("Seq") || basename.Equals("Seq_s"))) { // TODO undesirable workaround -- DafnyCC doesn't want 'seq.dfy' in its output list, but DafnySpec does...? continue; } tack(dfy, "dafny_" + basename); } tack(null, "Trusted"); // DafnyCC doesn't really want this, but meh, it emits it, so we account for it. foreach (string basename in this.getExtraSpecialOutputs()) { tack(null, basename); } return mapping; } private class InOutMapping { public readonly BuildObject dfysource; // null --> outputs come from bowels of DafnySpec/DafnyCC. public readonly BuildObject basmIfc; public readonly BuildObject basmImp; public InOutMapping(BuildObject dfysource, BuildObject basmIfc, BuildObject basmImp) { this.dfysource = dfysource; this.basmIfc = basmIfc; this.basmImp = basmImp; } } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/DafnyTransitiveDepsVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; internal class DafnyTransitiveDepsVerb : TransitiveDepsVerb { public DafnyTransitiveDepsVerb(BuildObject input) : base(input) { } protected override TransitiveDepsVerb factory(BuildObject obj) { return new DafnyTransitiveDepsVerb(obj); } protected override IIncludeFactory getIncludeFactory() { return new DafnyIncludes(); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/DafnyVerifyOneVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; internal class DafnyVerifyOneVerb : VerificationResultVerb, IProcessInvokeAsyncVerb { public const string DAFNY_EXTN = ".dfy"; private const int version = 15; private const string ADDDAFNYFLAG_LABEL = "AddDafnyFlag"; private SourcePath dfysource; private AbstractId abstractId; public DafnyVerifyOneVerb(SourcePath dfysource) { this.dfysource = dfysource; this.abstractId = new AbstractId(this.GetType().Name, version, dfysource.ToString()); } public override AbstractId getAbstractIdentifier() { return this.abstractId; } public override IEnumerable getDependencies(out DependencyDisposition ddisp) { TransitiveDepsVerb depsVerb = this.getTransitiveDepsVerb(); HashSet result = depsVerb.getAvailableDeps(out ddisp); result.UnionWith(DafnyExecutableDependencies.getDafnyExecutableDependencies()); return result; } public override IEnumerable getVerbs() { return new IVerb[0]; // All inputs are sources. } public override BuildObject getOutputFile() { return this.dfysource.makeOutputObject(".dfy.v"); } public override IEnumerable getOutputs() { return new[] { this.getOutputFile() }; } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { List arguments = new List(); arguments.Add("/noNLarith"); arguments.Add("/allowGlobals"); arguments.Add("/z3opt:nlsat.randomize=false"); arguments.Add("/z3opt:pi.warnings=true"); arguments.Add("/proverWarnings:1"); arguments.Add("/compile:0"); arguments.Add("/timeLimit:30"); arguments.Add("/noCheating:1"); arguments.Add("/autoTriggers:1"); arguments.Add("/ironDafny"); foreach (string[] ann in new AnnotationScanner(this.dfysource).getAnnotations(ADDDAFNYFLAG_LABEL)) { if (ann.Length != 2) { throw new SourceConfigurationError("Expected exactly 1 argument to " + ADDDAFNYFLAG_LABEL); } arguments.Add(ann[1]); } arguments.Add(this.dfysource.getRelativePath()); Logger.WriteLine("arguments: " + string.Join(" ", arguments)); return new ProcessInvokeAsyncWorker( workingDirectory, this, DafnyExecutableDependencies.getDafnyExecutable().getRelativePath(), arguments.ToArray(), ProcessExitCodeHandling.NonzeroIsOkay, getDiagnosticsBase(), returnStandardOut: true, returnStandardError: true, allowCloudExecution: true); } public Disposition Complete(WorkingDirectory workingDirectory, double cpuTimeSeconds, string stdout, string stderr, Disposition disposition) { VerificationResult vr = new VerificationResult( this.dfysource.getRelativePath(), cpuTimeSeconds, stdout, stderr, new VerificationResultDafnyParser()); vr.addBasicPresentation(); vr.toXmlFile(workingDirectory.PathTo(this.getOutputFile())); this.setWasRejectableFailure(!vr.pass); return disposition; } public IEnumerable getDirectIncludes() { // By the time this method is called by VerbToposorter, // this verb is scheduled for execution, and hence its deps // are complete. So all of these lookups should succeed. // (wait, does that follow?) return this.getTransitiveDepsVerb().getShallowIncludes(); } protected override BuildObject getSource() { return this.dfysource; } private TransitiveDepsVerb getTransitiveDepsVerb() { return new DafnyTransitiveDepsVerb(this.dfysource); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/DafnyVerifyTreeVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Linq; internal class DafnyVerifyTreeVerb : Verb, IObligationsProducer { private const int version = 30; private const string DFYTREE_EXTN = ".dfytree"; private SourcePath displayRoot; // used only in labeling the output private BuildObject obligations; private AbstractId abstractId; public DafnyVerifyTreeVerb(SourcePath root) { this.displayRoot = root; this.obligations = root.makeOutputObject(DFYTREE_EXTN + VerificationObligationList.VOL_EXTN); this.abstractId = new AbstractId(this.GetType().Name, version, root.ToString()); } public override AbstractId getAbstractIdentifier() { return this.abstractId; } public BuildObject getObligationSet() { return this.obligations; } public override IEnumerable getDependencies(out DependencyDisposition ddisp) { HashSet availableDeps = this.getAvailableDeps(out ddisp); List true_deps = new List(); foreach (BuildObject dep in availableDeps) { if (dep.getExtension().EndsWith(DafnyVerifyOneVerb.DAFNY_EXTN)) { true_deps.Add(this.mkVerificationObject(dep)); } else { true_deps.Add(dep); } } return true_deps; } public override IEnumerable getVerbs() { // TODO cast below assumes dafny files are always source files. // That's easy enough to remedy in DafnyVerifyOneVerb ctor, but for // now, we continue assuming it. // This will matter if we ever auto-generate a Dafny file. DependencyDisposition ddispDummy; IEnumerable result = this.getDafnyDependencies(out ddispDummy) .Select(dfysource => new DafnyVerifyOneVerb((SourcePath)dfysource)) .Concat(new List() { new DafnyTransitiveDepsVerb(this.displayRoot) }); return result; } public override IEnumerable getOutputs() { return new HashSet() { this.obligations }; } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { IEnumerable verificationResults = this.getVerbs() .Where(verb => verb is VerificationResultVerb) .Select(dfy_one => ((VerificationResultVerb)dfy_one).getOutputFile()); VerificationObligationList vol = new VerificationObligationList(verificationResults); vol.store(workingDirectory, this.obligations); return new VerbSyncWorker(workingDirectory, new Fresh()); } private BuildObject mkVerificationObject(BuildObject dfysource) { return dfysource.makeOutputObject(DafnyVerifyOneVerb.DAFNY_EXTN + VerificationResultVerb.VERIFICATION_RESULT_EXTN); } private HashSet getAvailableDeps(out DependencyDisposition ddisp) { TransitiveDepsVerb depsVerb = new DafnyTransitiveDepsVerb(this.displayRoot); HashSet availableDeps = depsVerb.getAvailableDeps(out ddisp); availableDeps.Add(this.displayRoot); // TransitiveDeps *exclude* the root, so we need to add that in, too. return availableDeps; } private IEnumerable getDafnyDependencies(out DependencyDisposition ddisp) { HashSet result = this.getAvailableDeps(out ddisp); return result.Where(dep => dep.getExtension().EndsWith(DafnyVerifyOneVerb.DAFNY_EXTN)); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/DbgFileCopySpeedTest.cs ================================================ namespace NuBuild { using System; using System.IO; internal class DbgFileCopySpeedTest { public static void thing() { Directory.SetCurrentDirectory("c:\\users\\howell\\verve2\\iron"); Directory.CreateDirectory("dummy"); Directory.CreateDirectory("dummy\\Results"); Directory.CreateDirectory("dummy\\Objects"); Directory.CreateDirectory("dummy\\Sources"); foreach (string path in Directory.EnumerateFiles("nucache", "*", SearchOption.AllDirectories)) { string fn = path.Substring(path.IndexOf("nucache") + 8); string source = Path.Combine("nucache", fn); string dest = Path.Combine("dummy", fn); ////Logger.WriteLine("Copy " + source + " to " + dest); ////File.Copy(source, dest); File.Delete(dest); using (FileStream outStream = File.OpenWrite(dest)) { bool dummy = File.Exists(source); using (Stream inStream = File.OpenRead(source)) { inStream.CopyTo(outStream); } } } } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/DbgHashSpeedTest.cs ================================================ namespace NuBuild { using System; using System.IO; using System.Linq; internal class DbgHashSpeedTest { public static void thing() { Directory.SetCurrentDirectory("c:\\users\\howell\\verve2\\iron"); string[] theFiles = File.ReadAllLines("hashlist"); Logger.WriteLine("I found " + theFiles.Count() + " files"); foreach (string file in theFiles) { string s = Util.hashFilesystemPath(file); Logger.WriteLine(s); } } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/DbgVerbCounter.cs ================================================ namespace NuBuild { using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; // I used this class to determine how much effort we were wasting // re-computing verb.getDependencies. internal class DbgVerbCounter { public enum DbgVerbCondition { DVWake, DVDepsIncomplete, DVDepsStale, DVDepsNonstale, DVTotal } private Dictionary, int> dbgCounts = new Dictionary, int>(); public void dbgDisplayCounts() { List> keys = new List>(dbgCounts.Keys); keys.Sort(); foreach (Tuple key in keys) { Logger.WriteLine(string.Format("{0:20}: {1}", key, dbgCounts[key])); } } public void consider(IVerb verb, DbgVerbCondition cond) { consider_inner(new Tuple(verb, cond)); consider_inner(new Tuple(verb, DbgVerbCondition.DVTotal)); } private void consider_inner(Tuple key) { if (!dbgCounts.ContainsKey(key)) { dbgCounts[key] = 0; } dbgCounts[key] += 1; } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/DependencyCache.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; internal class DependencyCache { private Dictionary theCache; private int dbgQueries = 0; private int dbgMisses = 0; public DependencyCache() { this.theCache = new Dictionary(); } public IEnumerable getDependencies(IVerb verb, out DependencyDisposition ddisp) { this.dbgQueries += 1; DependencyResult result; bool present = this.theCache.TryGetValue(verb, out result); if (!present) { this.dbgMisses += 1; result = new DependencyResult(); result.deps = verb.getDependencies(out result.ddisp); if (result.ddisp != DependencyDisposition.Incomplete) { // Can't cache incomplete results, since they may change upon // later inspection. this.theCache[verb] = result; } } ddisp = result.ddisp; return result.deps; } public void dbgPrintStats() { Logger.WriteLine(string.Format( "DependencyCache queries {0} misses {1}", this.dbgQueries, this.dbgMisses)); } private class DependencyResult { public IEnumerable deps; public DependencyDisposition ddisp; } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/DependencyDisposition.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; public enum DependencyDisposition { Complete, Incomplete, Failed // Something failed upstream } public static class DependencyDispositionExtensions { public static DependencyDisposition combine(this DependencyDisposition a, DependencyDisposition b) { if (a == DependencyDisposition.Failed || b == DependencyDisposition.Failed) { return DependencyDisposition.Failed; } if (a == DependencyDisposition.Incomplete || b == DependencyDisposition.Incomplete) { return DependencyDisposition.Incomplete; } return DependencyDisposition.Complete; } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/Disposition.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Xml; internal class Disposition { public const string _xml_tag = "Disposition"; private const string _xml_value_attr = "Value"; public static Disposition readXml(XmlReader xr) { Util.Assert(xr.Name.Equals(_xml_tag)); string value = xr.GetAttribute(_xml_value_attr); if (value.Equals(Fresh.Value)) { return new Fresh(); } else if (value.Equals(Failed.Value)) { return Failed.readXml(xr); } else { throw new Exception("Invalid disposition value " + value); } } public virtual IEnumerable getMessages() { return new string[0]; } public virtual void writeXml(XmlWriter xw) { xw.WriteStartElement(_xml_tag); xw.WriteAttributeString(_xml_value_attr, ToString()); this.writeXmlExtend(xw); xw.WriteEndElement(); } protected virtual void writeXmlExtend(XmlWriter xw) { } } internal class Stale : Disposition { public const string Value = "Stale"; public override string ToString() { return Value; } } internal class Fresh : Disposition { public const string Value = "Fresh"; public override string ToString() { return Value; } } /// /// Failed represents a PERMANENT failure. Any non-Stale disposition is recorded /// permanently in the build cache (including the globally-shared build cache!), /// preventing that particular verb from ever being tried again. Only record a /// Failed disposition if repeating the verb is guaranteed to fail again the same way. /// internal class Failed : Disposition { public const string Value = "Failed"; private const string _xml_MessageTag = "Message"; private List messages; public Failed(string msg = null) { this.messages = new List(); if (msg != null) { this.AddError(msg); } } public Failed(IEnumerable messages) { this.messages = new List(messages); } public static new Disposition readXml(XmlReader xr) { List messages = new List(); if (!xr.IsEmptyElement) { while (xr.Read()) { if (xr.NodeType == XmlNodeType.Element) { if (xr.Name.Equals(_xml_MessageTag)) { messages.Add(xr.ReadElementContentAsString()); } else { throw new Exception("Unrecognized Disposition::Failed tag " + xr.Name); } } else if (xr.NodeType == XmlNodeType.EndElement) { Util.Assert(xr.Name.Equals(Disposition._xml_tag)); break; } } } Failed f = new Failed(); f.messages = messages; return f; } public void AddError(string msg) { this.messages.Add(msg); } public override string ToString() { return Failed.Value; } public override IEnumerable getMessages() { return this.messages; } protected override void writeXmlExtend(XmlWriter xw) { foreach (string message in this.messages) { xw.WriteStartElement(_xml_MessageTag); xw.WriteString(message); xw.WriteEndElement(); } } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/EntryStitcherVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; using System.Linq; internal class EntryStitcherVerb : Verb { private const int version = 10; private const string SENTINEL_APP_SPECIFIC_GOES_HERE = "//- SENTINEL_APP_SPECIFIC_GOES_HERE"; private string appLabel; private IContextGeneratingVerb context; // Label our abstractIdentifier private BeatVerb mainBeatVerb; private SourcePath genericStitch; private SourcePath appSpecificStitch; private BuildObject dafnyMainImpInput; private BuildObject dafnyMainIfcInput; private SourcePath entryImpInput; public EntryStitcherVerb(IContextGeneratingVerb context, string appLabel) { this.appLabel = appLabel; this.context = context; this.entryImpInput = new SourcePath("src\\Checked\\Nucleus\\Main\\Entry.imp.beat"); SourcePath mainBeatSrc = new SourcePath("src\\Checked\\Nucleus\\Main\\Main.ifc.beat"); this.mainBeatVerb = new BeatVerb(context, mainBeatSrc, appLabel); this.genericStitch = new SourcePath("src\\Trusted\\Spec\\Entry.ifc.basm.stitch"); this.appSpecificStitch = new SourcePath(string.Format("src\\Trusted\\Spec\\{0}\\AppRequirements.ifc.stitch", appLabel)); } public override AbstractId getAbstractIdentifier() { return new AbstractId(this.GetType().Name, version, this.genericStitch.ToString(), concrete: this.appLabel); } public override IEnumerable getDependencies(out DependencyDisposition ddisp) { ddisp = DependencyDisposition.Complete; OrderPreservingSet deps = new OrderPreservingSet(); // Things we need to stitch the interface: deps.Add(this.genericStitch); deps.Add(this.appSpecificStitch); deps.AddRange(this.mainBeatVerb.getOutputs()); // Things we need to stitch the imports into the imp file: deps.Add(this.entryImpInput); deps.Add(this.context.getContextOutput()); IIncludePathContext pathContext = this.context.fetchIfAvailable(ref ddisp); if (pathContext != null) { this.dafnyMainIfcInput = pathContext.search("dafny_Main_i", ModPart.Ifc); Util.Assert(this.dafnyMainIfcInput != null); deps.Add(this.dafnyMainIfcInput); this.dafnyMainImpInput = pathContext.search("dafny_Main_i", ModPart.Ifc); Util.Assert(this.dafnyMainImpInput != null); deps.Add(this.dafnyMainImpInput); } return deps; } public override IEnumerable getVerbs() { return new IVerb[] { this.mainBeatVerb, this.context }; } public override IEnumerable getOutputs() { return new BuildObject[] { this.getIfcOutput(), this.getEntryImpOutput() }; } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { // Mimic this line from src\Checked\Nucleus\Main\build.ps1: // _cat -out $OBJ\EntryCP_i.bpl -in $OBJ\MainCP_i.bpl,$SPEC_OBJ\EntryCP_i.bpl // TODO: eliminate this special-case workaround. try { // This is the trusted bit, creating the stitched ifc file. ////IEnumerable ifcImports = extractImportStatements(dafnyMainIfcInput); string[] mainLines = File.ReadAllLines(workingDirectory.PathTo(this.mainBeatVerb.getOutputs().First())); string[] entryLines = File.ReadAllLines(workingDirectory.PathTo(this.genericStitch)); int sentinel_index = Array.IndexOf(entryLines, SENTINEL_APP_SPECIFIC_GOES_HERE); if (sentinel_index < 0) { throw new UserError("Sentinel string missing in " + this.genericStitch); } IEnumerable entryPrologue = entryLines.Take(sentinel_index + 1); IEnumerable entryEpilogue = entryLines.Skip(sentinel_index + 1); string[] appSpecificLines = File.ReadAllLines(workingDirectory.PathTo(this.appSpecificStitch)); ////File.WriteAllLines(getIfcOutput().getFilesystemPath(), ifcImports.Concat(mainLines.Concat(entryLines))); File.WriteAllLines( workingDirectory.PathTo(this.getIfcOutput()), mainLines.Concat(entryPrologue).Concat(appSpecificLines).Concat(entryEpilogue)); // Here's some (at least untrusted) workaround, snarfing and repurposing the // import list from dafny_Main_i up to Entry.imp. IEnumerable impImports = extractImportStatements(workingDirectory, this.dafnyMainImpInput); string[] intext = File.ReadAllLines(workingDirectory.PathTo(this.entryImpInput)); File.WriteAllLines(workingDirectory.PathTo(this.getEntryImpOutput()), impImports.Concat(intext)); return new VerbSyncWorker(workingDirectory, new Fresh()); } catch (IOException ex) { return new VerbSyncWorker(workingDirectory, new Failed(ex.ToString())); } } // We also have to stitch the imp, to borrow the private-import list from dafny_Main. internal BuildObject getEntryImpOutput() { return new SourcePath("src\\Checked\\Nucleus\\Main\\EntryStitched.x").makeLabeledOutputObject(this.appLabel, BeatExtensions.BEATIMP_EXTN); } private static IEnumerable extractImportStatements(WorkingDirectory workingDirectory, BuildObject obj) { // Well, it might be nice to use BeatExtensions.propagatePrivateImports, but that requires // a context to interpret the input imports. We don't really want to cons up yet ANOTHER // intermediate context, so here's a temporary workaround. Caution; may be brittle. IEnumerable imports = File.ReadAllLines(workingDirectory.PathTo(obj)) .Where(line => line.Contains("private-import")); // Note that dafny_Main_i didn't really expect us to steal its // imports, so it hasn't conditioned the Checked and Trusted imports to be beat-resistant. imports = imports.Select( line => line.Contains("Checked") || line.Contains("Trusted") ? line.Replace("private-import", "private-basmonly-import") : line); return imports; } private BuildObject getIfcOutput() { // TODO will probably require parameterization per app return new SourcePath("src\\Trusted\\Spec\\EntryStitched.x").makeLabeledOutputObject(this.appLabel, BoogieAsmVerifyVerb.BASMIFC_EXTN); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/Hasher.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; /// /// Strange mixture of hash-related functionality and a /// mapping from build objects to the verbs that created them? /// Actually, looks like everything here would more appropriately be elsewhere. /// DONE: Move outputToVerbMap to Scheduler. /// DONE: Move marshalledFilesystemPaths to Repository. /// TODO: Move contextResolutionCache to boogie/asm something or other. /// TODO: Move parsedIncludesCache to BeatIncludes? /// internal class Hasher : IHasher { private CachedHash, BuildObject> contextResolutionCache; private CachedHash, List> parsedIncludesCache; public Hasher() { this.contextResolutionCache = new CachedHash, BuildObject>( delegate(Tuple key) { return key.Item1.search(key.Item2, key.Item3); }); this.parsedIncludesCache = new CachedHash, List>( delegate(Tuple key) { return BeatIncludes.parseLabeledIncludes(key.Item1, key.Item2); }); } public BuildObject search(IIncludePathContext context, string modName, ModPart modPart) { return this.contextResolutionCache.get(new Tuple(context, modName, modPart)); } public List getParsedIncludes(IIncludePathContext context, BuildObject beatsrc) { return this.parsedIncludesCache.get(new Tuple(context, beatsrc)); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/IAsmProducer.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; internal interface IAsmProducer : IVerb { BuildObject getAsmFile(); } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/IContextGeneratingVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; internal interface IContextGeneratingVerb : IVerb { string getContextIdentifier(); PoundDefines getPoundDefines(); BuildObject getContextOutput(); } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/IHasher.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; /// /// REVIEW: Why is this an interface? /// internal interface IHasher { BuildObject search(IIncludePathContext context, string modName, ModPart modPart); List getParsedIncludes(IIncludePathContext context, BuildObject beatsrc); } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/IIncludeFactory.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; internal interface IIncludeFactory { IEnumerable getIncludes(BuildObject path); } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/IIncludePathContext.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; internal interface IIncludePathContext { BuildObject search(string basename, ModPart modPart = ModPart.Ifc); } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/IItemCache.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; /// /// Enumeration of the containers in the item cache. /// /// /// Important: The names of the values in the enumeration below become the /// actual names of the item cache containers. For the Azure blob backing /// store, this means they must be a valid DNS name (i.e. may ONLY be /// comprised of letters, numbers and the dash ('-') character). /// public enum ItemCacheContainer { /// /// Item cache container for source files. /// Sources = 0, /// /// Item cache container for object files. /// Objects = 1, /// /// Item cache container for (successful) result records. /// Results = 2, /// /// Item cache container for unsuccessful result records. /// FailedResults = 3 } /// /// Definition of the interface to the item cache. /// public interface IItemCache { /// /// Gets a human-readable name for this item cache implementation. /// string Name { get; } /// /// Copies the given item from the cache to a new byte array. /// /// /// Identifier for the cache container holding the item. /// /// /// Hash key for the desired item. /// /// A byte array containing a copy of the item. byte[] FetchItem( ItemCacheContainer container, string itemHash); /// /// Copies the given item from the cache to the given location in the /// local file system. /// /// /// Identifier for the cache container holding the item. /// /// /// Hash key for the desired item. /// /// /// Location in the local file system to copy the item. /// void FetchItemToFile( ItemCacheContainer container, string itemHash, string localFilesystemDestinationPath); /// /// Copies the given byte array to the desired cache item. /// /// /// Identifier for the cache container to hold the item. /// /// /// Hash key for the item. /// /// Byte array containing the item. void StoreItem( ItemCacheContainer container, string itemHash, byte[] contents); /// /// Copies the given file from the local file system into the cache. /// /// /// Identifier for the cache container to hold the item. /// /// /// Hash key for the item. /// /// /// Location in the local file system from which to source the item. /// void StoreItemFromFile( ItemCacheContainer container, string itemHash, string localFilesystemSourcePath); /// /// Deletes an item from the cache. /// /// /// Identifier for the cache container holding the item. /// /// /// Hash key for the desired item. /// void DeleteItem( ItemCacheContainer container, string itemHash); /// /// Gets a HashSet containing the hash keys of all the items in the /// given container. /// /// Identifier for the cache container. /// A HashSet containing the hash keys. HashSet GetItemsInContainer( ItemCacheContainer container); /// /// Gets the size of the item. /// Returns -1 if the item is absent. /// /// /// Identifier for the cache container holding the item. /// /// /// Hash key for the desired item. /// /// Size of the item in bytes, or -1 if item is absent. long GetItemSize( ItemCacheContainer container, string itemHash); /// /// Gets the last-modified time of the item. /// /// /// Identifier for the cache container holding the item. /// /// /// Hash key for the desired item. /// /// A DateTimeOffset containing the item's last-modified time. DateTimeOffset? GetItemLastModifiedTime( ItemCacheContainer container, string itemHash); } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/IObligationsProducer.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; internal interface IObligationsProducer : IVerb { BuildObject getObligationSet(); ////BuildObject getIdentifier(); } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/IProcessInvokeAsyncVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; /// /// Interface that verbs which use ProcessInvokeAsyncWorker as their /// VerbWorker must provide (for callbacks from same). /// internal interface IProcessInvokeAsyncVerb : IVerb { /// /// Records the CPU time used by the async worker process. /// /// The CPU time used. void RecordProcessInvokeCpuTime(double cpuTimeSeconds); /// /// Performs any required post-processing and/or cleanup of the /// results of the async worker process. /// /// /// The private working directory the verb executed in. /// /// /// CPU time used by async process. /// /// /// Standard out from async process (if requested). /// /// /// Standard error from async process (if requested). /// /// /// The disposition of the async process. /// /// /// The ultimate disposition of the worker activity. /// Disposition Complete(WorkingDirectory workingDirectory, double cpuTimeSeconds, string stdout, string stderr, Disposition disposition); } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/IProcessInvoker.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { /// /// Definition of the interface to local and cloud process invokers. /// internal interface IProcessInvoker { /// /// Gets the exit code returned by the process. /// int ExitCode { get; } /// /// Gets the CPU time used by the process, in seconds. /// double CpuTime { get; } /// /// Gets the process's standard output in the default case. /// Does not return the standard output if it is redirected to a file (i.e. if CaptureStdout is non-null). /// /// The process's standard output. string GetStdout(); /// /// Gets the process's standard error output. /// /// The process's standard error output. string GetStderr(); } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/IRejectable.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; internal interface IRejectable { bool resultWasRejectableFailure(); } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/IVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Xml; /// /// Definition of the interface to Verbs. /// internal interface IVerb : IComparable { /// /// Gets a possibly-incomplete list of things we depend on. /// /// /// When the list is complete, it should cover every BuildObject /// this verb can see when running its worker's methods. /// That means that it's not safe, for example, to say /// "I only depend on my .exe and DafnyTransitiveDepsVerb(root).obj()". /// One might think so, since the Freshness of the latter implies that /// every object this verb needs is Fresh, but that doesn't convey /// what BuildObjects need to (potentially) be transmitted remotely for /// running the verb's worker's methods on a remote machine. /// /// It should also cover any buildObjects needed to complete the list. /// That is, if the verb depends on a .tdep, and that .tdep is incomplete, /// the list should include that .tdep's partial dependency list, so /// the scheduler can figure out how to get it done. /// /// The returned DependencyDisposition. /// /// A collection of build objects this verb depends upon. /// IEnumerable getDependencies(out DependencyDisposition ddisp); /// /// Gets a list of the verbs that can build the dependencies visible to /// getDependencies. May return an incomplete list if getDependencies /// is incomplete. /// /// /// A collection of verbs that can build this verb's dependencies. /// IEnumerable getVerbs(); /// /// Gets a list of the build objects this verb generates upon successful /// execution. /// /// /// getOutputs is only meaningful once getDependencies indicates /// a complete disposition. The set of outputs doesn't change. /// /// A collection of build objects built by this verb. IEnumerable getOutputs(); /// /// Gets the list of BuildObjects this verb generates containing /// diagnostic information. Diagnostics are never used as inputs /// by other verbs; they are only for the user's inspection. /// TODO: Rename to getDiagnosticOutputs(). /// /// The collection of diagnostic BuildObjects. IEnumerable getFailureOutputs(); /// /// Gets an identifier that describes the verb up to differences in /// input. /// /// /// This method must always be evaluable. /// Example: /// DafnyVerifyOneVerb(SourcePath("src\\foo\\bar.dfy")) /// /// A unique identifier for the abstract verb. AbstractId getAbstractIdentifier(); /// /// Gets a worker for this verb that performs this verb's work. /// /// /// Working directory to use for this verb's execution. /// /// A worker for this verb instance. IVerbWorker getWorker(WorkingDirectory workingDirectory); /// /// Gets a structured form of output UI for informing the user what /// happened. /// /// Something to present to the user. Presentation getPresentation(); /// /// Gets a structured form of output UI for informing the user what is /// currently happening. /// /// /// The disposition of this verb's worker. /// /// Something to present to the user. Presentation getRealtimePresentation(Disposition disposition); /// /// Writes an XML representation of this verb's CPU usage using the /// provided XmlWriter. /// /// /// The XmlWriter to use to write the XML. /// void writeTimingXml(XmlWriter xmlWriter); /// /// Writes an XML representation of this verb's internal state /// (for debugging purposes) using the provided XmlWriter. /// /// /// The XmlWriter to use to write the XML. /// void writeDebugXml(XmlWriter xmlWriter); } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/IVerbWorker.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { /// /// Enumeration of the verb worker types: synchronous and asynchronous. /// /// /// REVIEW: Couldn't this just be a boolean? /// internal enum VerbWorkerType { /// /// The worker runs synchronously. /// Sync, /// /// The worker runs asynchronously. /// Async } /// /// Enumeration of the ways to treat process exit codes. /// /// /// REVIEW: Couldn't this just be a boolean? /// internal enum ProcessExitCodeHandling { /// /// Treat non-zero return codes as the process reporting a failure. /// NonzeroIsFailure, /// /// Ignore non-zero return codes from the process. /// NonzeroIsOkay } /// /// Definition of the interface to Verb workers. /// /// /// The scheduler's VerbRunner component uses this interface to /// run verbs (both synchronous and asynchronous verbs). /// internal interface IVerbWorker { /// /// Indicates whether this work needs to be scheduled asynchronously. /// If it returns Sync, the runAsync method will not be called. /// /// Sync for synchronous verbs, Async otherwise. VerbWorkerType IsSync(); /// /// Gets the private working directory this verb executes in. /// /// The directory this verb executes in. WorkingDirectory GetWorkingDirectory(); /// /// Performs the slow, asynchronous work. /// /// /// Does not run on the main thread, so should not access caches /// (or do anything else that expects to be synchronous). /// void RunAsync(); /// /// Performs the completion work for Async workers, and is called /// after the runAsync method returns. For Sync workers, it performs /// all the work not done by the getWorker call. /// /// /// This method runs synchronously on the main thread. REVIEW: Not true /// for Async workers! It runs under lock, but on separate thread. /// It can tidy up the state after async work, and store results /// in the Repository. /// This method must not return the Stale Disposition; once completed /// a verb is either Fresh or Failed. /// /// The disposition of this verb's worker's work. Disposition Complete(); } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/IVerificationResultParser.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; internal interface IVerificationResultParser { void parseOutput( string s, out int parseFailures, out int verificationFailures, out int timeouts); } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/IncludePathContext.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; internal abstract class IncludePathContext : IIncludePathContext { public abstract BuildObject search(string basename, ModPart modPart = ModPart.Ifc); public override int GetHashCode() { return ToString().GetHashCode(); } public override bool Equals(object obj) { return ToString().Equals(obj.ToString()); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/IronRootDirectory.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.IO; /// /// A directory tree in the local filesystem to fetch sources from. /// Used to identify and isolate accesses to things under iron root. /// internal static class IronRootDirectory { /// /// Gets the absolute path to the given build object under IronRoot. /// /// A build object. /// The absolute path to the build object. public static string PathTo(BuildObject obj) { return Path.Combine(BuildEngine.theEngine.getIronRoot(), obj.getRelativePath()); } /// /// Gets the absolute path corresponding to the given relative path under IronRoot. /// /// Relative path to convert. /// The absolute path corresponding to the given relative path. public static string PathTo(string relativePath) { return Path.Combine(BuildEngine.theEngine.getIronRoot(), relativePath); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/IroncladAppVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; using System.Linq; internal class IroncladAppVerb : Verb, IObligationsProducer { public const string TRUSTED_EXE_EXTN = ".exe"; public const string UNVERIFIED_SENTINEL_EXTENSION = ".usentinel"; private const int version = 5; ////public enum VerifyMode { Verify, NoVerify }; ////public enum SymDiffMode { UseSymDiff, NoSymDiff }; private SourcePath dfyroot; // REVIEW: Never used? private AbstractId abstractId; private DafnySpecVerb dafnyspecVerb; private DafnyCCVerb dafnyccVerb; private EntryStitcherVerb stitcherVerb; private VerificationResultSummaryVerb verifyResultsVerb; private LinkerVerb linkerVerb; private PoundDefines poundDefines; private VerificationRequest verificationRequest; private string appLabel; private BuildObject srcObject; private BuildObject exeObject; private BuildObject outputObject; public IroncladAppVerb(SourcePath dfyroot, TARGET target, DafnyCCVerb.FramePointerMode framePointerMode, VerificationRequest verificationRequest) { this.dfyroot = dfyroot; // TODO this is the only #define we support just yet, so I'm stuffing it in here. // We'll need to plumb more carefully when we want to add x64. if (dfyroot.getDirPath().Split(Path.DirectorySeparatorChar).Last().Equals("AppLoader")) { this.poundDefines = new PoundDefines(new string[] { "AppLoader" }); } else { this.poundDefines = PoundDefines.empty(); } this.verificationRequest = verificationRequest; this.abstractId = new AbstractId( this.GetType().Name, version, dfyroot.ToString(), this.poundDefines, concrete: string.Format( "{0},{1},{2}", target, framePointerMode.ToString(), verificationRequest.ToString())); this.appLabel = dfyroot.getDirPath().Split(Path.DirectorySeparatorChar).Last(); this.dafnyspecVerb = new DafnySpecVerb(dfyroot, this.appLabel); this.dafnyccVerb = new DafnyCCVerb(dfyroot, this.appLabel, framePointerMode); bool isLoader = dfyroot.getRelativePath().Equals(BootableAppVerb.LOADER_DFY); // NB we keep dafnyccVerb as the lowest-priority context, so that our hand-written // beat impls will override its output. IContextGeneratingVerb contextWithDafny = new ConcatContextVerb( BuildEngine.theEngine.getVerveContextVerb(this.poundDefines), new VerbOutputsContextVerb(this.dafnyspecVerb, false), new VerbOutputsContextVerb(this.dafnyccVerb, true), this.poundDefines); this.stitcherVerb = new EntryStitcherVerb(contextWithDafny, this.appLabel); IContextGeneratingVerb contextWithDafnyAndEntry = new ConcatContextVerb( new VerbOutputsContextVerb(this.stitcherVerb, false), contextWithDafny, this.poundDefines); BuildObject entryImpObj = this.stitcherVerb.getEntryImpOutput(); BoogieAsmLinkVerb entryVerb = new BoogieAsmLinkVerb(contextWithDafnyAndEntry, entryImpObj); if (target == TARGET.BARE_METAL) { MasmVerb masmVerb = new MasmVerb(entryVerb); this.linkerVerb = new LinkerVerb(masmVerb, isLoader); } else if (target == TARGET.WINDOWS) { // Rewrite the asm that comes out of entryVerb before linking it AsmRewriterVerb rewriter = new AsmRewriterVerb(entryVerb); MasmVerb masmVerb = new MasmVerb(rewriter); this.linkerVerb = new WinLinkerVerb(masmVerb, isLoader); } BoogieAsmVerificationObligationListVerb bavolVerb = new BoogieAsmVerificationObligationListVerb(contextWithDafnyAndEntry, entryImpObj, verificationRequest); this.verifyResultsVerb = new VerificationResultSummaryVerb(bavolVerb); this.srcObject = this.linkerVerb.getUntrustedExe(); if (verificationRequest.isComplete()) { this.exeObject = dfyroot.makeOutputObject(TRUSTED_EXE_EXTN); this.outputObject = this.exeObject; } else { this.exeObject = this.srcObject; this.outputObject = dfyroot.makeVirtualObject(UNVERIFIED_SENTINEL_EXTENSION); } } public enum TARGET { BARE_METAL, WINDOWS } public override IEnumerable getDependencies(out DependencyDisposition ddisp) { List result = new List(); result.Add(this.srcObject); result.Add(this.verifyResultsVerb.getOutputFile()); ddisp = DependencyDisposition.Complete; return result; } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { if (this.verificationRequest.isComplete()) { // If the verification succeeded, then we convert the untrusted exe into a trusted exe (via a copy). VerificationResult vr = VerificationResult.fromXmlFile(this.verifyResultsVerb.getOutputFile()); if (!vr.pass) { return new VerbSyncWorker(workingDirectory, new Failed()); } File.Copy(workingDirectory.PathTo(this.srcObject), workingDirectory.PathTo(this.outputObject), true); // True => Overwrite } else { UnverifiedSentinelVirtualContents contents = new UnverifiedSentinelVirtualContents(); BuildEngine.theEngine.Repository.StoreVirtual(this.outputObject, new Fresh(), contents); } return new VerbSyncWorker(workingDirectory, new Fresh()); } public override IEnumerable getVerbs() { List result = new List(); result.Add(this.dafnyccVerb); result.Add(this.stitcherVerb); result.Add(this.linkerVerb); result.Add(this.verifyResultsVerb); result.AddRange(this.verifyResultsVerb.getVerbs()); // Sleazy. return result; } public override IEnumerable getOutputs() { return new BuildObject[] { this.outputObject }; } public BuildObject getObligationSet() { return this.verifyResultsVerb.getObligationSet(); } public override AbstractId getAbstractIdentifier() { return this.abstractId; } public BuildObject getExe() { return this.exeObject; } public override Presentation getPresentation() { return this.verifyResultsVerb.getPresentation(); } public string getAppLabel() { return this.appLabel; } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/IronfleetAppVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; /// /// Verb to build an Ironfleet application. /// This is a top-level verb. /// internal class IronfleetAppVerb : Verb, IObligationsProducer { private const int Version = 7; private const string UnverifiedExeExt = ".unverified.exe"; private const string VerifiedExeExt = ".exe"; private readonly BuildObject input; private readonly BuildObject exeOutput; private readonly List otherOutputs; private readonly AbstractId abstractId; private readonly VerificationResultSummaryVerb verifyVerb; private readonly VSSolutionVerb buildVerb; private readonly IVerb[] verbs; private List dependencies; /// /// Initializes a new instance of the IronfleetAppVerb class. /// /// Main dafny file for the application. public IronfleetAppVerb(SourcePath input, VerificationRequest verificationRequest, bool releaseBuild = false) { if (input == null) { throw new ArgumentNullException("input"); } this.abstractId = new AbstractId(GetType().Name, Version, input.ToString() + verificationRequest.ToString()); this.input = input; this.buildVerb = new VSSolutionVerb(new SourcePath(@"src\IronfleetTestDriver\IronfleetTestDriver.sln"), input, releaseBuild); if (verificationRequest.verifyMode == VerificationRequest.VerifyMode.NoVerify) { this.exeOutput = this.input.makeOutputObject(UnverifiedExeExt); this.verifyVerb = null; this.verbs = new IVerb[] { this.buildVerb }; } else { this.exeOutput = this.input.makeOutputObject(VerifiedExeExt); this.verifyVerb = new VerificationResultSummaryVerb(new DafnyVerifyTreeVerb(input)); this.verbs = new IVerb[] { this.verifyVerb, this.buildVerb }; } this.otherOutputs = new List(); var ohs = this.buildVerb.getOutputs().ToList(); ohs.RemoveAll(o => o.getExtension() == ".exe"); foreach (var o in ohs) { this.otherOutputs.Add(RelocateBuildObjectToExeDirectory(o)); } } private BuildObject RelocateBuildObjectToExeDirectory(BuildObject sourceOb) { return new BuildObject(exeOutput.getDirPath() + "\\" + sourceOb.getFileName()); } public override IEnumerable getDependencies(out DependencyDisposition ddisp) { if (this.dependencies == null) { var dependencies = new List(); // Select and append results returned from verb.getDependencies() to dependencies. // If the dependency disposition is ever reported as not complete, we reflect this through to the caller. dependencies.AddRange(this.verbs.SelectMany(verb => verb.getOutputs())); this.dependencies = dependencies; } Trace.Assert(this.dependencies != null); ddisp = DependencyDisposition.Complete; return this.dependencies; } public override IEnumerable getVerbs() { return this.verbs; } public override IEnumerable getOutputs() { var result = new List { this.exeOutput }; result.AddRange(this.otherOutputs); return result; } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { Disposition disposition = new Fresh(); if (this.verifyVerb != null) { VerificationResult verificationResult = VerificationResult.fromXmlFile(this.verifyVerb.getOutputs().Single()); if (!verificationResult.pass) { disposition = new Failed(); } } if (!(disposition is Failed)) { foreach (var o in this.buildVerb.getOutputs()) { if (o.getExtension() == ".exe") { File.Copy(workingDirectory.PathTo(o), workingDirectory.PathTo(this.exeOutput), overwrite: true); } else { var dest = this.RelocateBuildObjectToExeDirectory(o); File.Copy( workingDirectory.PathTo(o), workingDirectory.PathTo(dest), overwrite: true); } } } return new VerbSyncWorker(workingDirectory, disposition); } public override AbstractId getAbstractIdentifier() { return this.abstractId; } public Disposition Complete(WorkingDirectory workingDirectory, double cpuTimeSeconds, string stdout, string stderr, Disposition disposition) { return disposition; } public BuildObject getObligationSet() { return this.verifyVerb.getObligationSet(); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/ItemCacheCloud.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Configuration; using System.Globalization; using System.IO; using Microsoft.WindowsAzure.Storage; using Microsoft.WindowsAzure.Storage.Blob; /// /// An implementation of the item cache that uses Azure blobs as the /// backing store. /// public class ItemCacheCloud : IItemCache { /// /// Azure storage account we're using. /// private readonly CloudStorageAccount storageAccount; /// /// Blob client object for working with blobs. /// private readonly CloudBlobClient blobClient; /// /// Array of blob containers corresponding to item cache containers. /// private readonly CloudBlobContainer[] cloudContainers; /// /// Initializes a new instance of the ItemCacheCloud class. /// public ItemCacheCloud() { // - // Create our CloudStorageAccount object. // REVIEW: Hard-coded connection string index "Ironclad". // - string connectionString = null; ConnectionStringSettings settings = ConfigurationManager.ConnectionStrings["Ironclad"]; if (settings != null) { connectionString = settings.ConnectionString; } if (string.IsNullOrEmpty(connectionString)) { throw new ConfigurationException("Azure connection string missing from your NuBuild.exe.config file!"); } this.storageAccount = CloudStorageAccount.Parse(connectionString); // - // Create our CloudBlobClient object. // - this.blobClient = this.storageAccount.CreateCloudBlobClient(); // - // Set up the blob storage containers. // - Array containers = Enum.GetValues(typeof(ItemCacheContainer)); this.cloudContainers = new CloudBlobContainer[containers.Length]; foreach (ItemCacheContainer container in containers) { CloudBlobContainer cloudContainer = this.blobClient.GetContainerReference(container.ToString().ToLower(CultureInfo.InvariantCulture)); cloudContainer.CreateIfNotExists(); this.cloudContainers[(int)container] = cloudContainer; } } /// /// Gets a human-readable name for this item cache implementation. /// public string Name { get { return "Cloud"; } } /// /// Copies the given item from the cache to a new byte array. /// /// /// Identifier for the cache container holding the item. /// /// /// Hash key for the desired item. /// /// A byte array containing a copy of the item. public byte[] FetchItem( ItemCacheContainer container, string itemHash) { CloudBlockBlob cloudBlob = this.cloudContainers[(int)container].GetBlockBlobReference(itemHash); if (!cloudBlob.Exists()) { return null; } using (MemoryStream memoryStream = new MemoryStream()) { cloudBlob.DownloadToStream(memoryStream); return memoryStream.ToArray(); } } /// /// Copies the given item from the cache to the given location in the /// local file system. /// /// /// Identifier for the cache container holding the item. /// /// /// Hash key for the desired item. /// /// /// Location in the local file system to copy the item. /// public void FetchItemToFile( ItemCacheContainer container, string itemHash, string localFilesystemDestinationPath) { CloudBlockBlob cloudBlob = this.cloudContainers[(int)container].GetBlockBlobReference(itemHash); try { cloudBlob.DownloadToFile(localFilesystemDestinationPath, FileMode.Create); } catch (Microsoft.WindowsAzure.Storage.StorageException) { throw new ObjectMissingFromCacheException(itemHash, "Item missing from cloud cache."); } } /// /// Copies the given byte array to the desired cache item. /// /// /// Identifier for the cache container to hold the item. /// /// /// Hash key for the item. /// /// /// Byte array containing the item. /// public void StoreItem( ItemCacheContainer container, string itemHash, byte[] contents) { CloudBlockBlob cloudBlob = this.cloudContainers[(int)container].GetBlockBlobReference(itemHash); cloudBlob.UploadFromByteArray(contents, 0, contents.Length); } /// /// Copies the given file from the local file system into the cache. /// /// /// Identifier for the cache container to hold the item. /// /// /// Hash key for the item. /// /// /// Location in the local file system from which to source the item. /// public void StoreItemFromFile( ItemCacheContainer container, string itemHash, string localFilesystemSourcePath) { CloudBlockBlob cloudBlob = this.cloudContainers[(int)container].GetBlockBlobReference(itemHash); cloudBlob.UploadFromFile(localFilesystemSourcePath, FileMode.Open); } /// /// Deletes an item from the cache. /// /// /// Identifier for the cache container holding the item. /// /// /// Hash key for the desired item. /// public void DeleteItem( ItemCacheContainer container, string itemHash) { CloudBlockBlob cloudBlob = this.cloudContainers[(int)container].GetBlockBlobReference(itemHash); cloudBlob.DeleteIfExists(); } /// /// Gets a HashSet containing the hash keys of all the items in the /// given container. /// /// Identifier for the cache container. /// A HashSet containing the hash keys. public HashSet GetItemsInContainer(ItemCacheContainer container) { HashSet itemHashes = new HashSet(); foreach (CloudBlockBlob item in this.cloudContainers[(int)container].ListBlobs(null, true)) { itemHashes.Add(item.Name); } return itemHashes; } /// /// Gets the size of the item. /// Returns -1 if the item is absent. /// /// /// Identifier for the cache container holding the item. /// /// /// Hash key for the desired item. /// /// Size of the item in bytes, or -1 if item is absent. public long GetItemSize( ItemCacheContainer container, string itemHash) { CloudBlockBlob cloudBlob = this.cloudContainers[(int)container].GetBlockBlobReference(itemHash); if (cloudBlob.Exists()) { return cloudBlob.Properties.Length; } return -1; } /// /// Gets the last-modified time of the item. /// /// /// Identifier for the cache container holding the item. /// /// /// Hash key for the desired item. /// /// A DateTimeOffset containing the item's last-modified time. public DateTimeOffset? GetItemLastModifiedTime( ItemCacheContainer container, string itemHash) { CloudBlockBlob cloudBlob = this.cloudContainers[(int)container].GetBlockBlobReference(itemHash); if (cloudBlob.Exists()) { return cloudBlob.Properties.LastModified; } return null; } /// /// Checks whether the specified item exists in the cache. /// /// /// Identifier for the cache container holding the item. /// /// /// Hash key for the desired item. /// /// /// True if the specified item is in the cache, false otherwise. /// public bool ItemExists( ItemCacheContainer container, string itemHash) { CloudBlockBlob cloudBlob = this.cloudContainers[(int)container].GetBlockBlobReference(itemHash); return cloudBlob.Exists(); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/ItemCacheLocal.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; using System.Threading; /// /// An implementation of the item cache that uses the local file system /// as the backing store. /// public class ItemCacheLocal : IItemCache { /// /// Array of local file system paths corresponding to item cache /// containers. /// private readonly string[] localPaths; /// /// Lock protecting local file system state from concurrent accesses. /// private object cacheLock; /// /// Initializes a new instance of the ItemCacheLocal class. /// /// /// Generates local path names corresponding to the various item cache /// containers, and creates local directories for each, if they don't /// already exit. /// /// Root of the local cache. public ItemCacheLocal(string localCacheDirectory) { // - // Set up the local "container" directories and paths to them. // - Array containers = Enum.GetValues(typeof(ItemCacheContainer)); this.localPaths = new string[containers.Length]; foreach (ItemCacheContainer container in containers) { string directory = Path.Combine( localCacheDirectory, container.ToString()); this.localPaths[(int)container] = directory; Directory.CreateDirectory(directory); } this.cacheLock = new object(); } /// /// Gets a human-readable name for this item cache implementation. /// public string Name { get { return "Local"; } } /// /// Copies the given item from the cache to a new byte array. /// /// /// Identifier for the cache container holding the item. /// /// /// Hash key for the desired item. /// /// A byte array containing a copy of the item. public byte[] FetchItem( ItemCacheContainer container, string itemHash) { string itemPath = this.ItemPath(container, itemHash); lock (this.cacheLock) { if (!File.Exists(itemPath)) { return null; } return File.ReadAllBytes(itemPath); } } /// /// Copies the given item from the cache to the given location in the /// local file system. /// /// /// This method is a performance optimization over getting a readable /// stream for the item and copying it to a local file using CopyTo(). /// /// /// Identifier for the cache container holding the item. /// /// /// Hash key for the desired item. /// /// /// Location in the local file system to copy the item. /// public void FetchItemToFile( ItemCacheContainer container, string itemHash, string localFilesystemDestinationPath) { lock (this.cacheLock) { try { Directory.CreateDirectory(Path.GetDirectoryName(localFilesystemDestinationPath)); File.Copy(this.ItemPath(container, itemHash), localFilesystemDestinationPath, true); } catch (FileNotFoundException) { throw new ObjectMissingFromCacheException(itemHash, "Item missing from local cache."); } } } /// /// Copies the given byte array to the desired cache item. /// /// /// Identifier for the cache container to hold the item. /// /// /// Hash key for the item. /// /// /// Byte array containing the item. /// public void StoreItem( ItemCacheContainer container, string itemHash, byte[] contents) { string itemPath = this.ItemPath(container, itemHash); lock (this.cacheLock) { File.Delete(itemPath); File.WriteAllBytes(itemPath, contents); } } /// /// Copies the given file from the local file system into the cache. /// /// /// Identifier for the cache container to hold the item. /// /// /// Hash key for the item. /// /// /// Location in the local file system from which to source the item. /// public void StoreItemFromFile( ItemCacheContainer container, string itemHash, string localFilesystemSourcePath) { string itemPath = this.ItemPath(container, itemHash); lock (this.cacheLock) { File.Delete(itemPath); File.Copy(localFilesystemSourcePath, itemPath); } } /// /// Gets a HashSet containing the hash keys of all the items in the /// given container. /// /// Identifier for the cache container. /// A HashSet containing the hash keys. public HashSet GetItemsInContainer(ItemCacheContainer container) { HashSet itemHashes = new HashSet(); foreach (string filename in Directory.EnumerateFiles(this.localPaths[(int)container])) { itemHashes.Add(Path.GetFileName(filename)); } return itemHashes; } /// /// Deletes an item from the cache. /// /// /// Identifier for the cache container holding the item. /// /// /// Hash key for the desired item. /// public void DeleteItem( ItemCacheContainer container, string itemHash) { lock (this.cacheLock) { File.Delete(this.ItemPath(container, itemHash)); } } /// /// Gets the size of the item. /// Returns -1 if the item is absent. /// /// /// Identifier for the cache container holding the item. /// /// /// Hash key for the desired item. /// /// Size of the item in bytes, or -1 if item is absent. public long GetItemSize( ItemCacheContainer container, string itemHash) { lock (this.cacheLock) { FileInfo fileInfo = new FileInfo(this.ItemPath(container, itemHash)); if (fileInfo.Exists) { return fileInfo.Length; } return -1; } } /// /// Gets the last-modified time of the item. /// /// /// Identifier for the cache container holding the item. /// /// /// Hash key for the desired item. /// /// A DateTimeOffset containing the item's last-modified time. public DateTimeOffset? GetItemLastModifiedTime( ItemCacheContainer container, string itemHash) { lock (this.cacheLock) { FileInfo fileInfo = new FileInfo(this.ItemPath(container, itemHash)); if (fileInfo.Exists) { return fileInfo.CreationTimeUtc; } return null; } } /// /// Gets the local path name for the given item. /// /// /// Identifier for the cache container holding the item. /// /// /// Hash key for the desired item. /// /// Path for the item. private string ItemPath(ItemCacheContainer container, string itemHash) { return Path.Combine( this.localPaths[(int)container], itemHash); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/ItemCacheMultiplexer.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; /// /// An implementation of the item cache that multiplexes two other /// backing store implementations together. /// public class ItemCacheMultiplexer : IItemCache { /// /// The maximum size of items to upload to the cloud. /// private const long MaxUploadSizeThreshold = 50 * (1 << 20); /// /// The underlying local item cache implementation. /// private readonly ItemCacheLocal localCache; /// /// The underlying cloud item cache implementation. /// private readonly ItemCacheCloud cloudCache; /// /// A worker thread and queue for performing background work. /// /// /// While this is currently private to the multiplexer, /// the BackgroundWorker code is generic and could be used /// for other purposes. If that happens, we should move this /// to the main build engine. /// private readonly BackgroundWorker backgroundWorker; /// /// Initializes a new instance of the ItemCacheMultiplexer class. /// /// A local cache instance. /// A cloud cache instance. /// A background worker instance. public ItemCacheMultiplexer( ItemCacheLocal localCache, ItemCacheCloud cloudCache, BackgroundWorker backgroundWorker) { this.localCache = localCache; this.cloudCache = cloudCache; this.backgroundWorker = backgroundWorker; } /// /// Gets a human-readable name for this item cache implementation. /// public string Name { get { return "Multiplexer"; } } /// /// Copies the given item from the cache to a new byte array. /// /// /// Identifier for the cache container holding the item. /// /// /// Hash key for the desired item. /// /// A byte array containing a copy of the item. public byte[] FetchItem( ItemCacheContainer container, string itemHash) { byte[] contents; contents = this.localCache.FetchItem(container, itemHash); if (contents == null) { contents = this.cloudCache.FetchItem(container, itemHash); if (contents == null) { return null; } this.localCache.StoreItem(container, itemHash, contents); } else { // - // Schedule cloud push on successful local read. // REVIEW: Is this rare optimization really worth it? // - this.QueueItemForCloudSync(container, itemHash); } return contents; } /// /// Copies the given item from the cache to the given location in the /// local file system. /// /// /// As with GetReadableStreamForItem, we first try locally and only /// go to the cloud if needed. /// /// /// Identifier for the cache container holding the item. /// /// /// Hash key for the desired item. /// /// /// Location in the local file system to copy the item. /// public void FetchItemToFile( ItemCacheContainer container, string itemHash, string localFilesystemDestinationPath) { try { this.localCache.FetchItemToFile(container, itemHash, localFilesystemDestinationPath); // - // Schedule cloud push on successful local read. // REVIEW: Is this rare optimization really worth it? // - this.QueueItemForCloudSync(container, itemHash); } catch (ObjectMissingFromCacheException) { // - // If it is missing locally, try to retrieve it from the cloud. // Note we stash a copy in the local cache prior to copying it // to the desired local file. // - byte[] temp = this.cloudCache.FetchItem(container, itemHash); if (temp == null) { throw new ObjectMissingFromCacheException(itemHash, "Item missing from multiplexed cache."); } this.localCache.StoreItem(container, itemHash, temp); this.localCache.FetchItemToFile(container, itemHash, localFilesystemDestinationPath); } } /// /// Copies the given byte array to the desired cache item. /// /// /// Identifier for the cache container to hold the item. /// /// /// Hash key for the item. /// /// Byte array containing the item. public void StoreItem( ItemCacheContainer container, string itemHash, byte[] contents) { this.localCache.StoreItem(container, itemHash, contents); this.QueueItemForCloudSync(container, itemHash); } /// /// Copies the given file from the local file system into the cache. /// /// /// Identifier for the cache container to hold the item. /// /// /// Hash key for the item. /// /// /// Location in the local file system from which to source the item. /// public void StoreItemFromFile( ItemCacheContainer container, string itemHash, string localFilesystemSourcePath) { this.localCache.StoreItemFromFile(container, itemHash, localFilesystemSourcePath); this.QueueItemForCloudSync(container, itemHash); } /// /// Deletes an item from the cache. /// /// /// Note that our cache sync code (CheckForAndOrUploadMissingItem) /// will fail if given an item to sync, and that item is subsequently /// deleted from the local cache before the sync code gets around to /// syncing it. This method is really only intended for cache /// management purposes and not for general use. If that changes, /// the cache sync code should change as well. /// /// /// Identifier for the cache container holding the item. /// /// /// Hash key for the desired item. /// public void DeleteItem( ItemCacheContainer container, string itemHash) { this.localCache.DeleteItem(container, itemHash); this.cloudCache.DeleteItem(container, itemHash); } /// /// Gets a HashSet containing the hash keys of all the items in the /// given container. /// /// Identifier for the cache container. /// A HashSet containing the hash keys. public HashSet GetItemsInContainer(ItemCacheContainer container) { // - // REVIEW: What to return here? Both caches contents? Nothing? // - return new HashSet(); } /// /// Gets the size of the item. /// Returns -1 if the item is absent. /// /// /// Identifier for the cache container holding the item. /// /// /// Hash key for the desired item. /// /// Size of the item in bytes, or -1 if item is absent. public long GetItemSize( ItemCacheContainer container, string itemHash) { long size = this.localCache.GetItemSize(container, itemHash); if (size == -1) { size = this.cloudCache.GetItemSize(container, itemHash); } return size; } /// /// Gets the last-modified time of the item. /// /// /// Identifier for the cache container holding the item. /// /// /// Hash key for the desired item. /// /// A DateTimeOffset containing the item's last-modified time. public DateTimeOffset? GetItemLastModifiedTime( ItemCacheContainer container, string itemHash) { DateTimeOffset? modifiedTime = this.localCache.GetItemLastModifiedTime(container, itemHash); if (modifiedTime == null) { modifiedTime = this.cloudCache.GetItemLastModifiedTime(container, itemHash); } return modifiedTime; } /// /// Public API for private CheckForAndOrUploadMissingItem method. /// /// /// Identifier for the item's cache container. /// /// Hash key for the item. public void SyncItemToCloud( ItemCacheContainer container, string itemHash) { this.CheckForAndOrUploadMissingItem(container, itemHash); } /// /// Queue the given item for asynchronous cloud cache synchronization. /// /// /// Identifier for the item's cache container. /// /// Hash key for the item. private void QueueItemForCloudSync( ItemCacheContainer container, string itemHash) { if (this.backgroundWorker != null) { this.backgroundWorker.QueueWork(this.CheckForAndOrUploadMissingItem, container, itemHash); } } /// /// Check if the given item is already present in the cloud cache, /// and if not, upload the local cache item to the cloud. /// /// /// Identifier for the item's cache container. /// /// Hash key for the item. private void CheckForAndOrUploadMissingItem( object containerObject, object itemHashObject) { ItemCacheContainer container = (ItemCacheContainer)containerObject; string itemHash = (string)itemHashObject; if (this.localCache.GetItemSize(container, itemHash) > MaxUploadSizeThreshold) { Logger.WriteLine(string.Format( "Warning: skipping upload of {0} because it's really big. Compress?", itemHash)); return; } // - // Check if the item is already present in the cloud cache. // TODO present doesn't mean we don't want to overwrite it (eg when // replacing a Failed verification result with a succeeding one.) // - if (this.cloudCache.ItemExists(container, itemHash)) { return; } // - // The item is missing from the cloud cache. Upload it. // - byte[] temp = this.localCache.FetchItem(container, itemHash); if (temp == null) { // This should never happen barring a serious logic error. throw new ObjectMissingFromCacheException(itemHash, "Can't upload non-existant cache item!"); } this.cloudCache.StoreItem(container, itemHash, temp); } #if false /// /// A wrapper for a stream that queues up a cloud cache sync after it is /// closed. /// /// /// REVIEW: a lot of boilerplate code just to hook one call. Better way to do this? /// private class MultiplexerWrappedStream : Stream { /// /// Flag indicating whether or not Dispose has already been called. /// private bool disposed; /// /// Stream we are wrapping. /// private Stream stream; /// /// Item cache multiplexer that holds the item behind the stream. /// private ItemCacheMultiplexer multiplexer; /// /// Item cache container for the item behind the stream. /// private ItemCacheContainer container; /// /// Item cache hash for the item behind the stream. /// private string itemHash; /// /// Initializes a new instance of the MultiplexerWrappedStream /// class. /// /// A stream to wrap. /// /// The multiplexer cache instance owning item. /// /// /// The container for the item in the multiplexer cache. /// /// /// The hash for the item in the multiplexer cache. /// public MultiplexerWrappedStream( Stream stream, ItemCacheMultiplexer multiplexer, ItemCacheContainer container, string itemHash) { this.stream = stream; this.multiplexer = multiplexer; this.container = container; this.itemHash = itemHash; } /// /// Gets a value indicating whether the current steam supports /// reading. /// public override bool CanRead { get { return this.stream.CanRead; } } /// /// Gets a value indicating whether the current stream supports /// seeking. /// public override bool CanSeek { get { return this.stream.CanSeek; } } /// /// Gets a value indicating whether the current stream supports /// writing. /// public override bool CanWrite { get { return this.stream.CanWrite; } } /// /// Gets the length in bytes of the stream. /// public override long Length { get { return this.stream.Length; } } /// /// Gets or sets the position within the current stream. /// public override long Position { get { return this.stream.Position; } set { this.stream.Position = value; } } /// /// Reads a sequence of bytes from the current stream and advances /// the position within the stream by the number of bytes read. /// /// /// An array of bytes. When this method returns, the buffer /// contains the specified byte array with the values between /// offset and (offset + count - 1) replaced by the bytes read from /// the current source. /// /// /// The zero-based byte offset in buffer at which to begin storing /// the data read from the current stream. /// /// /// The maximum number of bytes to be read from the current stream. /// /// /// The total number of bytes read into the buffer. This can be /// less than the number of bytes requested if that many bytes are /// not currently available, or zero (0) if the end of the stream /// has been reached. /// public override int Read(byte[] buffer, int offset, int count) { return this.stream.Read(buffer, offset, count); } /// /// Writes a sequence of bytes to the current stream and advances /// the position within this stream by the number of bytes written. /// /// /// An array of bytes. This method copies count bytes from buffer /// to the current stream. /// /// /// The zero-based offset in buffer at which to begin copying bytes /// to the current stream. /// /// /// The number of bytes to be written to the current stream. /// public override void Write(byte[] buffer, int offset, int count) { this.stream.Write(buffer, offset, count); } /// /// Clears all buffers for this stream and causes any buffered data /// to be written to the underlying device. /// public override void Flush() { this.stream.Flush(); } /// /// Sets the position within the current stream. /// /// /// A byte offset relative to the origin parameter. /// /// /// A value of type SeekOrigin indicating the reference point used /// to obtain the new position. /// /// The new position within the public override long Seek(long offset, SeekOrigin origin) { return this.stream.Seek(offset, origin); } /// /// Sets the length of the current stream. /// /// /// Desired length of the current stream in bytes. /// public override void SetLength(long value) { this.stream.SetLength(value); } /// /// Releases unmanaged and (optionally) managed resources. /// /// /// Whether or not to release managed resources. /// protected override void Dispose(bool disposing) { if (this.disposed) { return; } if (disposing) { this.stream.Dispose(); this.multiplexer.QueueItemForCloudSync(this.container, this.itemHash); } this.disposed = true; base.Dispose(disposing); } } #endif } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/Job.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.InteropServices; using Microsoft.Win32.SafeHandles; /// /// Represents a Windows Job Object. /// /// /// This class is only used by ProcessInvoker, so it could be private to that class. /// [SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1121:UseBuiltInTypeAlias", Justification = "UInt* is more appropriate for system programming")] internal class Job : IDisposable { /// /// Handle to the native Windows job object. /// private SafeFileHandle jobObjectHandle; /// /// Flag indicating whether or not Dispose has already been called. /// private bool disposed; /// /// Initializes a new instance of the Job class. /// public Job() { this.jobObjectHandle = NativeMethods.CreateJobObject(IntPtr.Zero, null); if (this.jobObjectHandle.IsInvalid) { // Note that the parameterless Win32Exception constructor calls Marshal.GetLastWin32Error internally. throw new Win32Exception(); } // - // Set up this job object so that any processes assigned to it will // be terminated when it is closed (since this job object will be // closed automatically when the owning process exits, all assigned // processes will also be closed when the owning process exists). // - // Note that to set the JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE flag, // the call to SetInformationJobObject must be of JobObjectInfoClass // ExtendedLimitInformation, even though the flag is in the simpler // BasicLimitInformation structure contained in the former. // - NativeMethods.JOBOBJECT_EXTENDED_LIMIT_INFORMATION info = new NativeMethods.JOBOBJECT_EXTENDED_LIMIT_INFORMATION(); int infoSize = Marshal.SizeOf(typeof(NativeMethods.JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); info.BasicLimitInformation.LimitFlags = NativeMethods.JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; IntPtr infoPtr = Marshal.AllocHGlobal(infoSize); try { Marshal.StructureToPtr(info, infoPtr, false); if (!NativeMethods.SetInformationJobObject( this.jobObjectHandle, NativeMethods.JOBOBJECTINFOCLASS.ExtendedLimitInformation, infoPtr, (UInt32)infoSize)) { // Note that the parameterless Win32Exception constructor calls Marshal.GetLastWin32Error internally. throw new Win32Exception(); } } finally { Marshal.FreeHGlobal(infoPtr); } } /// /// Adds the given process to the job object. /// /// Process to add. /// True if successful, false otherwise. public bool AddProcess(Process process) { return NativeMethods.AssignProcessToJobObject(this.jobObjectHandle, process.Handle); } /// /// Gets the total CPU consumed by all processes associated with this job object. /// /// Total CPU time. public TimeSpan GetCpuTime() { UInt64 totalCpuTime = 0; NativeMethods.JOBOBJECT_BASIC_ACCOUNTING_INFORMATION basicAccountingInfo; basicAccountingInfo = this.GetBasicAccountingInformation(); totalCpuTime = basicAccountingInfo.TotalKernelTime + basicAccountingInfo.TotalUserTime; return new TimeSpan((long)totalCpuTime); } /// /// Terminates all processes currently associated with this job object. /// /// Exit code to be used by all processes and threads. /// True if successful, false otherwise. public bool Terminate(UInt32 exitCode) { return NativeMethods.TerminateJobObject(this.jobObjectHandle, exitCode); } /// /// Closes this Job object. /// public void Close() { this.jobObjectHandle.Close(); } /// /// Releases resources. /// public void Dispose() { this.Dispose(true); GC.SuppressFinalize(this); } /// /// Releases unmanaged and (optionally) managed resources. /// /// Whether or not to release managed resources. private void Dispose(bool disposing) { if (this.disposed) { return; } if (disposing) { this.jobObjectHandle.Dispose(); } this.disposed = true; } /// /// Gets a struct containing the basic accounting information for the job object. /// /// A JOBOBJECT_BASIC_ACCOUNTING_INFORMATION structure. private NativeMethods.JOBOBJECT_BASIC_ACCOUNTING_INFORMATION GetBasicAccountingInformation() { NativeMethods.JOBOBJECT_BASIC_ACCOUNTING_INFORMATION info; int infoSize = Marshal.SizeOf(typeof(NativeMethods.JOBOBJECT_BASIC_ACCOUNTING_INFORMATION)); IntPtr infoPtr = Marshal.AllocHGlobal(infoSize); try { if (!NativeMethods.QueryInformationJobObject( this.jobObjectHandle, NativeMethods.JOBOBJECTINFOCLASS.BasicAccountingInformation, infoPtr, (UInt32)infoSize, IntPtr.Zero)) { // Note that the parameterless Win32Exception constructor calls Marshal.GetLastWin32Error internally. throw new Win32Exception(); } info = (NativeMethods.JOBOBJECT_BASIC_ACCOUNTING_INFORMATION)Marshal.PtrToStructure(infoPtr, typeof(NativeMethods.JOBOBJECT_BASIC_ACCOUNTING_INFORMATION)); } finally { Marshal.FreeHGlobal(infoPtr); } return info; } /// /// Represents the native Windows API for accessing job objects. /// [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1310:FieldNamesMustNotContainUnderscore", Justification = "Part of Windows API")] [SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:ElementsMustBeDocumented", Justification = "Part of Windows API")] [SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1602:EnumerationItemsMustBeDocumented", Justification = "Part of Windows API")] private static class NativeMethods { public const UInt32 JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE = 0x2000; public enum JOBOBJECTINFOCLASS { BasicAccountingInformation = 1, BasicLimitInformation = 2, ExtendedLimitInformation = 9 } [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] public static extern SafeFileHandle CreateJobObject(IntPtr jobAttributes, string name); [DllImport("kernel32.dll")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool AssignProcessToJobObject(SafeHandle jobHandle, IntPtr processHandle); [DllImport("kernel32.dll")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool SetInformationJobObject(SafeHandle jobHandle, JOBOBJECTINFOCLASS infoClass, IntPtr info, UInt32 infoLength); [DllImport("kernel32.dll")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool QueryInformationJobObject(SafeHandle jobHandle, JOBOBJECTINFOCLASS infoClass, IntPtr info, UInt32 infoLength, IntPtr returnLength); [DllImport("kernel32.dll")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool TerminateJobObject(SafeHandle job, UInt32 exitCode); [StructLayout(LayoutKind.Sequential, Pack = 8)] public struct JOBOBJECT_BASIC_LIMIT_INFORMATION { public UInt64 PerProcessUserTimeLimit; public UInt64 PerJobUserTimeLimit; public UInt32 LimitFlags; public UIntPtr MinimumWorkingSetSize; public UIntPtr MaximumWorkingSetSize; public UInt32 ActiveProcessLimit; public UIntPtr Affinity; public UInt32 PriorityClass; public UInt32 SchedulingClass; } [StructLayout(LayoutKind.Sequential)] public struct IO_COUNTERS { public UInt64 ReadOperationCount; public UInt64 WriteOperationCount; public UInt64 OtherOperationCount; public UInt64 ReadTransferCount; public UInt64 WriteTransferCount; public UInt64 OtherTransferCount; } [StructLayout(LayoutKind.Sequential)] public struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION { public JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation; public IO_COUNTERS IoInfo; public UIntPtr ProcessMemoryLimit; public UIntPtr JobMemoryLimit; public UIntPtr PeakProcessMemoryLimit; public UIntPtr PeakJobMemoryUsed; } [StructLayout(LayoutKind.Sequential)] public struct JOBOBJECT_BASIC_ACCOUNTING_INFORMATION { public UInt64 TotalUserTime; public UInt64 TotalKernelTime; public UInt64 ThisPeriodTotalUserTime; public UInt64 ThisPeriodTotalKernelTime; public UInt32 TotalPageFaultCount; public UInt32 TotalProcesses; public UInt32 ActiveProcesses; public UInt32 TotalTerminatedProcesses; } } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/LinkerVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; using System.Linq; internal class LinkerVerb : Verb, IProcessInvokeAsyncVerb { public const string UNTRUSTED_EXE_EXTN = ".uexe"; protected BuildObject outputObject; protected BuildObject objFile; protected long maxExeSize; protected string entryPoint; protected int baseAddr; private const int version = 4; private bool isLoader; private MasmVerb masmVerb; private AbstractId abstractId; public LinkerVerb(MasmVerb masmVerb, bool isLoader) { this.masmVerb = masmVerb; this.isLoader = isLoader; this.objFile = masmVerb.getObj(); this.abstractId = new AbstractId(this.GetType().Name, version + this.getVersion(), this.objFile.ToString(), concrete: isLoader ? "Loader" : "NonLoader"); this.outputObject = this.objFile.makeOutputObject(this.outputExtension()); // Default settings for the apps. this.maxExeSize = 1 * 1024 * 1024; // 1 MB. this.entryPoint = "?AppEntryPoint"; this.baseAddr = 0x340000; if (this.isLoader) { // Override the settings above with loader-specific values. this.maxExeSize = 58 * 1024; // 58 KB this.entryPoint = "?LoaderEntryPoint"; this.baseAddr = 0x300000; } } public override AbstractId getAbstractIdentifier() { return this.abstractId; } public BuildObject getUntrustedExe() { return this.outputObject; } public override IEnumerable getDependencies(out DependencyDisposition ddisp) { ddisp = DependencyDisposition.Complete; List basic = new List() { this.getLinkerExe(), this.objFile }; basic.AddRange(this.getExtraDependencies()); return basic; } public override IEnumerable getVerbs() { return new List() { this.masmVerb }; } public override IEnumerable getOutputs() { return new List() { this.getUntrustedExe() }.Union(this.getExtraOutputs()); } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { List args = new List() { "/LARGEADDRESSAWARE", "/driver", "/fixed", "/subsystem:native", "/nodefaultlib" }; args.Add(this.objFile.getRelativePath()); args.Add("/out:" + this.outputObject.getRelativePath()); args.Add("/entry:" + this.entryPoint); args.Add("/base:" + this.baseAddr); return new ProcessInvokeAsyncWorker( workingDirectory, this, this.getLinkerExe().getRelativePath(), args.ToArray(), ProcessExitCodeHandling.NonzeroIsFailure, this.getDiagnosticsBase()); } public virtual Disposition Complete(WorkingDirectory workingDirectory, double cpuTimeSeconds, string stdout, string stderr, Disposition disposition) { if (!(disposition is Failed)) { // Check that the executable isn't too large. long exeSize = new FileInfo(workingDirectory.PathTo(this.outputObject)).Length; if (exeSize > this.maxExeSize) { return new Failed("Executable too big"); } } return disposition; } protected virtual int getVersion() { // REVIEW: Is this right? There is a private version field in this object. return 0; } protected virtual string outputExtension() { return UNTRUSTED_EXE_EXTN; } protected virtual BuildObject getLinkerExe() { return new SourcePath("tools\\Assembler\\link-base.exe", SourcePath.SourceType.Tools); } protected virtual IEnumerable getExtraDependencies() { List extraDepends = new List(); extraDepends.Add(new SourcePath("tools\\Assembler\\mspdb80.dll", SourcePath.SourceType.Tools)); return extraDepends; } protected virtual IEnumerable getExtraOutputs() { return new List(); } protected virtual bool runLinker(BuildObject asmFile, string linkerExecutable, string entryPoint, int baseAddr, long maxExeSize = -1) { return true; } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/Logger.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.IO; /// /// Utility for writing log messages simultaneously to the console and /// a log file. /// internal class Logger { /// /// The log file. /// private static StreamWriter log; /// /// Writes a message to both the log file and the console. /// /// Message to write. public static void Write(string msg) { OpenLog(); log.Write(msg); log.Flush(); System.Console.Write(msg); } /// /// Writes a message and the newline string to both the log file /// and the console. /// /// Message to write. public static void WriteLine(string msg) { Write(msg + System.Environment.NewLine); } /// /// Opens the log file (if it isn't already open). /// private static void OpenLog() { if (log == null) { log = new StreamWriter("nubuild.log"); } } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/MasmVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; internal class MasmVerb : Verb, IProcessInvokeAsyncVerb { public const string MASM_EXTN = ".asm"; public const string OBJ_EXTN = ".obj"; private const int version = 4; private IAsmProducer asmVerb; private AbstractId abstractId; private BuildObject outputObject; private BuildObject asmFile; public MasmVerb(IAsmProducer asmVerb) { this.asmVerb = asmVerb; this.asmFile = asmVerb.getAsmFile(); this.abstractId = new AbstractId(this.GetType().Name, version, this.asmFile.ToString()); this.outputObject = this.asmFile.makeOutputObject(OBJ_EXTN); } public override AbstractId getAbstractIdentifier() { return this.abstractId; } public BuildObject getObj() { return this.outputObject; } public BuildObject getLis() { return this.asmFile.makeOutputObject(".lis"); } ////public BuildObject getMap() { return this.asmFile.makeOutputObject(".map"); } public override IEnumerable getDependencies(out DependencyDisposition ddisp) { ddisp = DependencyDisposition.Complete; return new List() { this.getMasmExe(), this.asmVerb.getAsmFile() }; } public override IEnumerable getVerbs() { return new List() { this.asmVerb }; } public override IEnumerable getOutputs() { return new List() { this.getObj(), this.getLis(), //// this.getMap() }; } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { List args = new List() { "/Cp", "/c", "/Zd", "/Zf", "/Zi" }; args.Add("/Fo" + this.getObj().getRelativePath()); args.Add("/Fl" + this.getLis().getRelativePath()); ////args.Add("/Fm" + getMap().getRelativePath()); // TODO: "/I$SPEC_INCLUDE_DIR" args.Add(this.asmFile.getRelativePath()); return new ProcessInvokeAsyncWorker( workingDirectory, this, this.getMasmExe().getRelativePath(), args.ToArray(), ProcessExitCodeHandling.NonzeroIsFailure, this.getDiagnosticsBase()); } public Disposition Complete(WorkingDirectory workingDirectory, double cpuTimeSeconds, string stdout, string stderr, Disposition disposition) { return disposition; } private BuildObject getMasmExe() { return new SourcePath("tools\\Assembler\\ml.exe", SourcePath.SourceType.Tools); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/NMakeVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Diagnostics; using System.IO; using System.Linq; internal class NmakeVerb : Verb, IProcessInvokeAsyncVerb { private const int version = 7; private static SourcePath nmakeExecutable; private SourcePath makefile; private CustomManifestParser customManifest; private AbstractId abstractId; private string outputPath; private string outputPathSuffix; public NmakeVerb(SourcePath makefile) { this.makefile = makefile; this.abstractId = new AbstractId(this.GetType().Name, version, this.makefile.ToString()); // Generate output path. this.outputPath = "."; int depth = this.makefile.getDirPath().Split(@"\/".ToCharArray(), StringSplitOptions.RemoveEmptyEntries).Length; for (int i = 0; i < depth; i++) { this.outputPath = Path.Combine(this.outputPath, ".."); } this.outputPathSuffix = Path.Combine(BuildEngine.theEngine.getObjRoot(), this.makefile.getDirPath()); this.outputPath = Path.Combine(this.outputPath, this.outputPathSuffix); this.customManifest = new CustomManifestParser(this.makefile); } public override IEnumerable getDependencies(out DependencyDisposition ddisp) { ddisp = DependencyDisposition.Complete; return this.customManifest.getDependencies().Union(new List() { getNmakeExecutable() }); } public override IEnumerable getVerbs() { return new IVerb[] { }; } public override IEnumerable getOutputs() { return from output in this.customManifest.getOutputs() select new BuildObject(Path.Combine(BuildEngine.theEngine.getObjRoot(), output.getRelativePath())); } public BuildObject getOutputPath() { return new BuildObject(this.outputPathSuffix); } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { // Scrub the "makeflags" environment variable from our environment // so we don't pass it down to our worker process. Some users may // have things there that conflict with our usage. Process myProcess = System.Diagnostics.Process.GetCurrentProcess(); StringDictionary environmentVariables = myProcess.StartInfo.EnvironmentVariables; environmentVariables.Remove("MAKEFLAGS"); List args = new List(); args.Add(string.Format("OBJ={0}\\obj", workingDirectory.PathTo(this.outputPathSuffix))); args.Add(string.Format("BIN={0}", workingDirectory.PathTo(this.outputPathSuffix))); args.Add("-f"); args.Add(workingDirectory.PathTo(this.makefile)); // TODO: Remove reliance on workingDirOverride, which currently hides dependency issues and other problems. return new ProcessInvokeAsyncWorker( workingDirectory, this, getNmakeExecutable().getRelativePath(), ////"c:/Program Files (x86)/Microsoft Visual Studio 12.0/VC/bin/nmake.exe", args.ToArray(), ProcessExitCodeHandling.NonzeroIsFailure, workingDirOverride: IronRootDirectory.PathTo(this.makefile.getDirPath()), failureBase: getDiagnosticsBase(), //allowAbsoluteExe: true, allowAbsoluteArgs: true); } public Disposition Complete(WorkingDirectory workingDirectory, double cpuTimeSeconds, string stdout, string stderr, Disposition disposition) { return disposition; } public override AbstractId getAbstractIdentifier() { return this.abstractId; } private static SourcePath getNmakeExecutable() { // TODO this should eventually be a BuildObject from *building* the executable. if (nmakeExecutable == null) { nmakeExecutable = new SourcePath("tools\\nmake\\nmake.exe", SourcePath.SourceType.Tools); } return nmakeExecutable; } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/NuBuild.csproj ================================================  Debug AnyCPU {4D7220C0-3CAA-4659-9F16-A564DB3CCC1B} Exe Properties NuBuild NuBuild v4.5 512 false publish\ true Disk false Foreground 7 Days false false true 0 1.0.0.%2a false true AnyCPU true full false ..\..\..\bin_tools\NuBuild\ TRACE;DEBUG prompt 4 AllRules.ruleset false AnyCPU pdbonly true bin\Release\ TRACE prompt 4 False ..\References\Microsoft.WindowsAzure.Storage.dll False Code Code False Microsoft .NET Framework 4.5 %28x86 and x64%29 true False .NET Framework 3.5 SP1 Client Profile false False .NET Framework 3.5 SP1 false CustomDictionary.xml ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/ObjectFailedException.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; internal class ObjectFailedException : Exception { public ObjectFailedException(BuildObject obj, Failed failed) : base(obj.ToString() + ": " + failed.ToString()) { } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/ObjectMissingFromCacheException.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; internal class ObjectMissingFromCacheException : Exception { private string itemHash; public ObjectMissingFromCacheException(string itemHash, string msg) : base(string.Format("item {0} missing from cache: {1}", itemHash, msg)) { this.itemHash = itemHash; } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/ObjectNotReadyException.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; internal class ObjectNotReadyException : Exception { public ObjectNotReadyException(BuildObject obj) : base(obj.ToString()) { } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/OrderPreservingSet.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Linq; /// /// Representation of an order-preserving set. /// /// /// Inspired by ICollection example at /// . /// /// Type of objects in the set. internal class OrderPreservingSet : ICollection { private readonly HashSet membership; private readonly List order; public OrderPreservingSet() : this(EqualityComparer.Default) { } public OrderPreservingSet(IEqualityComparer comparer) { this.membership = new HashSet(comparer); this.order = new List(); } public OrderPreservingSet(IEnumerable initialContents) : this() { this.AddRange(initialContents); } public int Count { get { return this.membership.Count(); } } int ICollection.Count { get { return this.membership.Count; } } // TODO I don't know what this property is for. bool ICollection.IsReadOnly { get { return false; } } public void Add(T item) { if (!this.membership.Contains(item)) { this.membership.Add(item); this.order.Add(item); } } void ICollection.Add(T item) { this.Add(item); } public void AddRange(IEnumerable range) { foreach (T obj in range) { this.Add(obj); } } void ICollection.Clear() { this.membership.Clear(); this.order.Clear(); } bool ICollection.Contains(T item) { return this.membership.Contains(item); } void ICollection.CopyTo(T[] array, int arrayIndex) { this.order.CopyTo(array, arrayIndex); } IEnumerator IEnumerable.GetEnumerator() { return this.order.GetEnumerator(); } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return this.order.GetEnumerator(); } bool ICollection.Remove(T item) { this.membership.Remove(item); return this.order.Remove(item); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/PathNormalizer.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; internal class PathNormalizer { private Dictionary cache; private char[] directorySeparators; public PathNormalizer() { this.cache = new Dictionary(); this.directorySeparators = new char[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }; } public static string dbg_normalizePath_nocache(string requestPath, bool presumedDirectory) { return PathNormalizer.normalizePath_nocache(requestPath, presumedDirectory); } // Normalize the case of an absolute path to the case present in the filesystem. public string normalizeAbsolutePath(string absPath) { string dotdotfreepath = this.cleanDotDots(absPath); if (!Path.IsPathRooted(dotdotfreepath)) { throw new ArgumentException("Requires absolute path"); } return this.normalizePath(dotdotfreepath, false); } private static string normalizePath_nocache(string requestPath, bool presumedDirectory) { try { string rc; string childName = Path.GetFileName(requestPath); if (string.IsNullOrEmpty(childName)) { // absPath was a "root" (MSDOS drive letter) // by fiat, drive letters are uppercase. rc = requestPath.ToUpper(CultureInfo.InvariantCulture) + Path.DirectorySeparatorChar; } else { string parentPath = Path.GetDirectoryName(requestPath); // Recurse to handle parent prefix: string normalizedParent = normalizePath_nocache(parentPath, true); DirectoryInfo parentDirectoryInfo = new DirectoryInfo(normalizedParent); FileSystemInfo[] childrenFileSystemInfos = null; string normalizedPath; try { childrenFileSystemInfos = parentDirectoryInfo.GetFileSystemInfos(childName); } catch (System.IO.DirectoryNotFoundException) { // Fall through and assume we're to create it. } if (childrenFileSystemInfos == null || childrenFileSystemInfos.Length == 0) { // Looks like a nonexistent path. I guess the caller gets to decide the // capitalization. NB this is fraught with danger, since we're not actually // creating the path in the filesystem, so someone else might try to create // a path with a different capitalization. However, if we memorize our // results, we should end up canonicalizing to the first capitalization // we see. normalizedPath = Path.Combine(normalizedParent, childName); // Unfortunately, we can't tell whether we should add a path separator here! if (presumedDirectory) { normalizedPath += Path.DirectorySeparatorChar; } } else { FileSystemInfo childFileSystemInfo = childrenFileSystemInfos.First(); // Since we passed a normalized path into DirectoryInfo, we'll get // the normalized path back out, plus the filesystem's idea of the // child name's case. normalizedPath = childFileSystemInfo.FullName; if ((childFileSystemInfo.Attributes & FileAttributes.Directory) == FileAttributes.Directory) { normalizedPath += Path.DirectorySeparatorChar; } } rc = normalizedPath; } ////Logger.WriteLine(string.Format("{0}\n => {1}", requestPath, rc)); return rc; } catch (Exception ex) { Trace.TraceError(ex.Message); throw new ArgumentException("invalid path"); } } // Invariant: input is an absolute path, free of ..s, lowercased, with // normalized path separators. // Based on suggestions in http://stackoverflow.com/questions/1214513/normalize-directory-names-in-c-sharp. private string normalizePath(string requestPath, bool presumedDirectory) { string lowerPath = requestPath.ToLower(CultureInfo.InvariantCulture); if (this.cache.ContainsKey(lowerPath)) { return this.cache[lowerPath]; } string rc = PathNormalizer.normalizePath_nocache(requestPath, presumedDirectory); this.cache[lowerPath] = rc; return rc; } private string cleanDotDots(string path) { string[] parts = path.Split(this.directorySeparators); List outParts = new List(); for (int i = 0; i < parts.Length; i++) { if (parts[i].Equals(string.Empty)) { // Null path segment: foo//bar. continue; } else if (parts[i].Equals(".")) { // Semantically-null segment. continue; } else if (parts[i].Equals("..")) { outParts.RemoveAt(outParts.Count() - 1); } else { outParts.Add(parts[i]); } } return string.Join(Path.DirectorySeparatorChar.ToString(), outParts.ToArray()); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/PoundDefines.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; internal class PoundDefines { private List definedSymbols; private string descr; public PoundDefines(IEnumerable definedSymbols) { this.definedSymbols = new List(definedSymbols); this.definedSymbols.Sort(); // NB the null list gets a *null* ToString, which is interpreted as no appLabel. this.descr = this.definedSymbols.Count == 0 ? null : "#" + string.Join(",", this.definedSymbols); } public override string ToString() { return this.descr; } public string getAbstractIdString() { return this.descr == null ? string.Empty : ", " + this.descr; } public override int GetHashCode() { return this.descr.GetHashCode(); } public override bool Equals(object obj) { PoundDefines other = obj as PoundDefines; if (other != null) { return (this.descr == null && other.descr == null) || (this.descr != null && this.descr.Equals(other.descr)); } else { return false; } } internal static string toAppLabel(PoundDefines poundDefines) { return poundDefines == null ? null : poundDefines.ToString(); } internal static PoundDefines empty() { return new PoundDefines(new string[] { }); } internal IEnumerable ToDefArgs() { List args = new List(); foreach (string symbol in this.definedSymbols) { args.Add("-def"); args.Add(symbol); } return args; } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/Presentater.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Text; /// /// TODO: Rename this (and the file) to IPresentater, or maybe IPresenter. /// REVIEW: These all just emit strings. Wouldn't a simple table suffice? /// internal interface Presentater { void startHeader(); void endHeader(); void startLine(); void endLine(); void startSpacer(); void endSpacer(); void startColor(string colorName); void endColor(); void startBullet(); void endBullet(); void startPre(); void endPre(); void doText(string text); } public class HTMLPresentater : Presentater { private StringBuilder document; public HTMLPresentater() { this.document = new StringBuilder(); this.document.Append("\n\n"); } public override string ToString() { this.document.Append("\n\n"); return this.document.ToString(); } public void startHeader() { this.document.Append("

    "); } public void endHeader() { this.document.Append("

    "); } public void startLine() { this.document.Append("
    "); } public void endLine() { this.document.Append("
    \n"); } public void startSpacer() { this.document.Append("

    \n"); } public void endSpacer() { this.document.Append("

    \n"); } public void startColor(string colorName) { string htmlColor; switch (colorName) { case Presentation.RED: htmlColor = "red"; break; case Presentation.GREEN: htmlColor = "green"; break; default: htmlColor = "black"; break; } this.document.Append(""); } public void endColor() { this.document.Append(""); } public void startBullet() { this.document.Append("
  • "); } public void endBullet() { this.document.Append("
  • \n"); } public void startPre() { this.document.Append("
    ");
            }
    
            public void endPre()
            {
                this.document.Append("
    \n"); } public void doText(string text) { this.document.Append(text); } } /// /// Appears to be a "Presentater" that uses "ANSI escape sequences" to /// produce colored output on console terminals that support it. /// /// /// /// "ANSI escape sequences" is probably the most common name for these /// things, although it is technically a misnomer, as ANSI withdrew the /// ANSI X3.64 spec in 1997. The real spec is ECMA-48, aka ISO/IEC 6429. /// See
    . /// /// /// Windows cmd.exe doesn't implement this spec. So only those folks /// using alternative shells will get easily-readable output from this. /// /// public class ASCIIPresentater : Presentater { // REVIEW: These don't appear to properly follow the ECMA-48 spec. // All of these commands are of type "Select Graphic Rendition" or SGR. // In the spec, this is covered in section 8.3.117. // The 0 code is supposed to cancel the effect of any preceding SGR, // i.e. "\x1b[0m" should cancel everything. Thus the following stop // codes don't just stop what their start codes started (and are overly // verbose). A universal stop code would suffice for this usage. // Notes on codes used below: // 0 = cancel the effect of any preceding SGR. // 1 = bold. // 32 = green display (i.e. text). // 37 = white display (i.e. text). // 39 = default display (i.e. text) color. // 40 = black background. // 41 = red background. // 43 = yellow background. // 49 = default background color. private static ColorEnum Red = new ColorEnum("\x1b[01;41m", "\x1b[0;49m"); private static ColorEnum Green = new ColorEnum("\x1b[01;32m", "\x1b[0;0m"); private static ColorEnum BlackBackground = new ColorEnum("\x1b[01;40m", "\x1b[0;49m"); private static ColorEnum YellowBackground = new ColorEnum("\x1b[01;43m", "\x1b[0;49m"); private static ColorEnum BoldWhite = new ColorEnum("\x1b[01;37m", "\x1b[0;39m"); private static ColorEnum WhiteOnBlack = ColorEnum.join(BlackBackground, BoldWhite); private static ColorEnum Ordinary = new ColorEnum(string.Empty, string.Empty); private StringBuilder document; private ColorEnum colorEnum; public ASCIIPresentater() { this.document = new StringBuilder(); } public override string ToString() { return this.document.ToString(); } public void startHeader() { this.document.Append(WhiteOnBlack.start); } public void endHeader() { this.document.Append(WhiteOnBlack.stop + "\n"); } public void startLine() { } public void endLine() { this.document.Append("\n"); } public void startSpacer() { } public void endSpacer() { this.document.Append("\n"); } public void startColor(string colorName) { Util.Assert(this.colorEnum == null); switch (colorName) { case Presentation.RED: this.colorEnum = Red; break; case Presentation.GREEN: this.colorEnum = Green; break; default: this.colorEnum = Ordinary; break; } this.document.Append(this.colorEnum.start); } public void endColor() { this.document.Append(this.colorEnum.stop); this.colorEnum = null; } public void startBullet() { this.document.Append(" * "); } public void endBullet() { this.document.Append("\n"); } public void startPre() { } public void endPre() { if (!this.document.ToString().EndsWith("\n")) { this.document.Append("\n"); } } public void doText(string text) { this.document.Append(text); } /// /// Definition of the start and stop sequences for a color. /// /// /// REVIEW: This class is not needed, as there is only one stop sequence. /// private class ColorEnum { public string start; public string stop; public ColorEnum(string start, string stop) { this.start = start; this.stop = stop; } public static ColorEnum join(ColorEnum a, ColorEnum b) { return new ColorEnum(a.start + b.start, b.stop + a.stop); } } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/Presentation.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.IO; using System.Text; using System.Xml; internal class Presentation : XmlFiller { // Completed representation. private string xmls; public const string _xml_tag = "Presentation"; public const string HEADER = "Header"; public const string LINE = "Line"; public const string SPACER = "Spacer"; public const string COLOR = "Color"; public const string BULLET = "Bullet"; public const string PRE = "Pre"; public const string RED = "red"; public const string GREEN = "green"; public const string _xml_ColorValue_attr = "Value"; public Presentation(string xmls) { this.xmls = xmls; } public static Presentation fromXml(XmlReader xr) { StringBuilder sb = new StringBuilder(); using (XmlWriter xw = XmlWriter.Create(sb)) { xw.WriteStartDocument(); xw.WriteNode(xr, false); xw.WriteEndDocument(); xw.Close(); } return new Presentation(sb.ToString()); } public void fillXml(XmlWriter xw) { using (XmlReader xr = XmlReader.Create(new StringReader(this.xmls))) { xr.ReadToFollowing(_xml_tag); xw.WriteNode(xr, false); } } public void format(Presentater p) { using (XmlReader xr = XmlReader.Create(new StringReader(this.xmls))) { xr.ReadToFollowing(_xml_tag); while (xr.Read()) { if (xr.NodeType == XmlNodeType.Element) { switch (xr.Name) { case HEADER: p.startHeader(); break; case LINE: p.startLine(); break; case SPACER: p.startSpacer(); break; case COLOR: p.startColor(xr.GetAttribute(_xml_ColorValue_attr)); break; case BULLET: p.startBullet(); break; case PRE: p.startPre(); break; default: Util.Assert(false); break; } } else if (xr.NodeType == XmlNodeType.EndElement) { switch (xr.Name) { case _xml_tag: break; case HEADER: p.endHeader(); break; case LINE: p.endLine(); break; case SPACER: p.endSpacer(); break; case COLOR: p.endColor(); break; case BULLET: p.endBullet(); break; case PRE: p.endPre(); break; default: Util.Assert(false); break; } } else if (xr.NodeType == XmlNodeType.Text) { p.doText(xr.Value); } } } } internal static string abbreviateLines(string m) { StringBuilder sb = new StringBuilder(); int count = 0; const int limit = 20; using (StringReader sr = new StringReader(m)) { string line; while ((line = sr.ReadLine()) != null) { if (count == limit) { sb.AppendLine("[...error messages truncated. See failure log.]"); break; } sb.AppendLine(line); count += 1; } } return sb.ToString(); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/PresentationBuilder.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Text; using System.Xml; internal class PresentationBuilder { // Build-up interface. private StringBuilder sb; private XmlWriter xw; public PresentationBuilder() { this.sb = new StringBuilder(); // Notice no indentation, to avoid mungling text. this.xw = XmlWriter.Create(this.sb); this.xw.WriteStartDocument(); this.xw.WriteStartElement(Presentation._xml_tag); } public Presentation fix() { this.xw.WriteEndElement(); this.xw.WriteEndDocument(); this.xw.Close(); return new Presentation(this.sb.ToString()); } public void text(string s) { this.xw.WriteString(s); } public void color(string color, string s) { this.xw.WriteStartElement(Presentation.COLOR); this.xw.WriteAttributeString(Presentation._xml_ColorValue_attr, color); this.text(s); this.xw.WriteEndElement(); } public void header(string s) { this.simpleTag(Presentation.HEADER, s); } public void line(string s) { this.simpleTag(Presentation.LINE, s); } public void spacer() { this.simpleTag(Presentation.SPACER, string.Empty); } public void bullet(string s) { this.simpleTag(Presentation.BULLET, s); } public void pre(string s) { this.simpleTag(Presentation.PRE, s); } public void startHeader() { this.xw.WriteStartElement(Presentation.HEADER); } public void endHeader() { this.xw.WriteEndElement(); } public void startLine() { this.xw.WriteStartElement(Presentation.LINE); } public void endLine() { this.xw.WriteEndElement(); } public void startBullet() { this.xw.WriteStartElement(Presentation.BULLET); } public void endBullet() { this.xw.WriteEndElement(); } private void simpleTag(string tag, string s) { this.xw.WriteStartElement(tag); this.text(s); this.xw.WriteEndElement(); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/ProcessInvokeAsyncWorker.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; /// /// Representation of an asynchronous verb worker. /// internal class ProcessInvokeAsyncWorker : IVerbWorker { /// /// The private working directory for this worker to work in. /// private WorkingDirectory workingDirectory; /// /// The verb whose worker this is. /// private IProcessInvokeAsyncVerb verb; /// /// The executable to run. /// private string executable; /// /// The command line arguments to provide to the executable. /// private string[] args; /// /// How to handle the exit code from running the executable. /// private ProcessExitCodeHandling exitCodeHandling; /// /// Where to (optionally) collect diagnostics. /// private BuildObject failureBase; /// /// Where to capture standard out (I think). /// private BuildObject captureStdout; /// /// Debugging text for something or another. /// private string dbgText; /// /// Whether to allow an absolute (rather than relative) file path to the executable. /// private bool allowAbsoluteExe; /// /// Whether to allow absolute (rather than relative) file paths as arguments. /// private bool allowAbsoluteArgs; /// /// The working directory to use. /// private string workingDirOverride; /// /// Whether to return the standard output from the process in the Complete call. /// private bool returnStandardOut; /// /// Whether to return the error output from the process in the Complete call. /// private bool returnStandardError; /// /// The IProcessInvoker (either a ProcessInvoker or a CloudSubmitter) instance we use to run this executable (either locally or in the cloud). /// private IProcessInvoker pinv; /// /// Whether to run the executable in the cloud. /// private bool useCloudExecution; /// /// List of input files needed by the executable. /// private List inputFiles; /// /// List of output files produced by the executable. /// private List outputFiles; /// /// Initializes a new instance of the ProcessInvokeAsyncWorker class. /// /// The private working directory for this worker to work in. /// The verb whose worker this is. /// The executable to run. /// The command line arguments to provide to the executable. /// How to handle the return code from running the executable. /// Not sure what this is -- some debugging/diagnostic thing. /// Where to capture standard out (I think). /// Debugging text for something or another. /// Whether to allow an absolute (rather than relative) file path to the executable. /// Whether to allow absolute (rather than relative) file paths as arguments. /// The working directory to use. /// Whether to return the standard output of the process. /// Whether to return the standard error output of the process. /// Whether to allow this worker to run the executable in the cloud. /// /// TODO: executable should be a BuildObject, like every other dependency. /// public ProcessInvokeAsyncWorker( WorkingDirectory workingDirectory, IProcessInvokeAsyncVerb verb, string executable, string[] args, ProcessExitCodeHandling exitCodeHandling, BuildObject failureBase, BuildObject captureStdout = null, string dbgText = null, bool allowAbsoluteExe = false, bool allowAbsoluteArgs = false, string workingDirOverride = null, bool returnStandardOut = false, bool returnStandardError = false, bool allowCloudExecution = false) { this.workingDirectory = workingDirectory; this.verb = verb; this.executable = executable; this.args = args; this.exitCodeHandling = exitCodeHandling; this.failureBase = failureBase; this.captureStdout = captureStdout; this.dbgText = dbgText; this.allowAbsoluteExe = allowAbsoluteExe; this.allowAbsoluteArgs = allowAbsoluteArgs; this.workingDirOverride = workingDirOverride; this.returnStandardOut = returnStandardOut; this.returnStandardError = returnStandardError; if (allowCloudExecution) { // Verbs cannot allow cloud execution if they allow absolute paths to exes or args. Util.Assert(!this.allowAbsoluteExe); Util.Assert(!this.allowAbsoluteArgs); Util.Assert(this.workingDirOverride == null); if (BuildEngine.theEngine.CloudExecutionQueue != null) { // We're good to go for cloud execution. this.useCloudExecution = true; // REVIEW: If there are other things we should do on the main thread prior to CloudSubmitter invocation, we should do them here. this.inputFiles = this.GetInputFiles(); this.outputFiles = new List(this.verb.getOutputs()); this.outputFiles.AddRange(this.verb.getFailureOutputs()); } } } /// /// Indicates whether this work needs to be scheduled asynchronously. /// Since this is the asynchronous implementation, always returns Async. /// /// Always returns Async. public VerbWorkerType IsSync() { return VerbWorkerType.Async; } /// /// Gets the private working directory this verb executes in. /// /// The directory this verb executes in. public WorkingDirectory GetWorkingDirectory() { return this.workingDirectory; } /// /// Performs the slow, asynchronous work. /// /// /// Does not run on the main thread, so should not access caches /// (or do anything else that expects to be synchronous). /// When this returns, the work is expected to have completed. /// public void RunAsync() { if (this.useCloudExecution) { // REVIEW: Would prefer to use the verb's input hash value as the request identifier below. this.pinv = new CloudSubmitter( Path.GetRandomFileName(), this.workingDirectory, this.inputFiles, this.outputFiles, this.executable, this.args, this.failureBase, this.captureStdout, this.dbgText); } else { this.pinv = new ProcessInvoker( this.workingDirectory, this.executable, this.args, this.failureBase, this.captureStdout, this.dbgText, this.allowAbsoluteExe, this.allowAbsoluteArgs, this.workingDirOverride); } } /// /// Performs the completion work for Async workers, and is called /// after the runAsync method returns. Returns the ultimate /// disposition of the activity. /// /// /// This method runs synchronously on the main thread. /// It can tidy up the state after async work, and store results /// in the Repository. /// Thou shalt not return Stale. /// /// The disposition of this verb's worker's work. public Disposition Complete() { this.verb.RecordProcessInvokeCpuTime(this.pinv.CpuTime); string stdout = null; if (this.returnStandardOut) { stdout = this.pinv.GetStdout(); } string stderr = null; if (this.returnStandardError) { stderr = this.pinv.GetStderr(); } Disposition disposition; if (this.exitCodeHandling == ProcessExitCodeHandling.NonzeroIsOkay || this.pinv.ExitCode == 0) { disposition = new Fresh(); } else { // Sheesh. Some tools emit error messages to stdout. // REVIEW: Provide full command line here rather than just executable (like old version did)? Failed f = new Failed(this.pinv.GetStdout() + this.pinv.GetStderr()); f.AddError("Executable: " + this.executable + "\n"); disposition = f; } return this.verb.Complete(this.workingDirectory, this.pinv.CpuTime, stdout, stderr, disposition); } /// /// Gets the input files needed for verb execution. /// /// List of the verb's input files. private List GetInputFiles() { DependencyDisposition ddisp; List inputFiles = new List(); foreach (BuildObject input in this.verb.getDependencies(out ddisp)) { if (!(input is VirtualBuildObject)) { inputFiles.Add(input); } } return inputFiles; } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/ProcessInvoker.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Diagnostics; using System.IO; using System.Text; /// /// Represents the invoker of processes that do the work of a verb worker. /// public class ProcessInvoker : IProcessInvoker { /// /// Whether to always emit diagnostic output. /// private const bool AlwaysEmitDiagnostics = true; /// /// The CPU time used by the process, in seconds. /// private double cpuTime; /// /// The exit code returned by the process. /// private int exitCode; /// /// The stream used to collect standard out to a file (if requested). /// private StreamWriter stdoutFile; /// /// The temporary file in which to store standard out (if requested). /// private BuildObject tmpStdout; /// /// Where standard out is collected by default. /// private StringBuilder stdout; /// /// Where standard error is collected. /// private StringBuilder stderr; /// /// The private working directory for the process we invoke. /// private WorkingDirectory workingDirectory; /// /// Initializes a new instance of the ProcessInvoker class. /// /// The working directory the process is started in. /// The executable to run. /// The command line arguments to provide to the executable. /// Not sure what this is -- some debugging/diagnostic thing. /// Where to (optionally) capture standard out. /// Debugging text for something or another. /// Whether to allow an absolute (rather than relative) file path to the executable. /// Whether to allow absolute (rather than relative) file paths as arguments. /// The working directory to use. public ProcessInvoker( WorkingDirectory workingDirectory, string executable, string[] args, BuildObject failureBase, BuildObject captureStdout = null, string dbgText = null, bool allowAbsoluteExe = false, bool allowAbsoluteArgs = false, string workingDirOverride = null) { // Catch bad verb authors before they hurt themselves. Util.Assert(allowAbsoluteExe || !executable.Contains(":")); // Hey, this looks like an absolute path! Use .getRelativePath(); it makes your output more stable. foreach (string arg in args) { // Pardon my distasteful heuristic to avoid flagging /flag:value args. Util.Assert(allowAbsoluteArgs || arg.Length < 2 || arg[1] != ':'); // Hey, this looks like an absolute path! Use .getRelativePath() to tolerate crossing machine boundaries. } this.workingDirectory = workingDirectory; this.stdout = new StringBuilder(); this.stderr = new StringBuilder(); using (Job job = new Job()) { using (Process proc = new Process()) { if (allowAbsoluteExe) { proc.StartInfo.FileName = executable; } else { // TODO: *All* async verbs need to list their executable (and all the libs it depends upon) as dependencies. proc.StartInfo.FileName = workingDirectory.PathTo(executable); } // TODO Is there a better way to escape the args to avoid problems with spaces? proc.StartInfo.Arguments = string.Join(" ", args); proc.StartInfo.WorkingDirectory = workingDirOverride == null ? workingDirectory.Root : workingDirOverride; proc.StartInfo.RedirectStandardOutput = true; // REVIEW: Maybe we should always capture stdout in a StringBuilder and just write it out to a file afterwards if requested? if (captureStdout != null) { this.tmpStdout = new BuildObject(captureStdout.getRelativePath() + ".tmp"); this.stdoutFile = new StreamWriter(workingDirectory.PathTo(this.tmpStdout)); proc.OutputDataReceived += new DataReceivedEventHandler(this.StdoutRedirectHandler); } else { // Collect stdout here for diagnostics. proc.OutputDataReceived += new DataReceivedEventHandler(this.StdoutHandler); } proc.StartInfo.RedirectStandardError = true; proc.ErrorDataReceived += new DataReceivedEventHandler(this.StderrHandler); proc.StartInfo.UseShellExecute = false; string commandLine = proc.StartInfo.FileName + " " + proc.StartInfo.Arguments; if (failureBase != null && AlwaysEmitDiagnostics) { // In diagnostic mode, we emit the command line twice, once ahead in case Boogie decides // to run away and never come back. BuildObject failureBatObj = failureBase.makeOutputObject(".bat"); workingDirectory.CreateDirectoryFor(failureBatObj); File.WriteAllText(workingDirectory.PathTo(failureBatObj), commandLine); } proc.Start(); job.AddProcess(proc); proc.BeginOutputReadLine(); proc.BeginErrorReadLine(); proc.WaitForExit(); this.cpuTime = job.GetCpuTime().TotalSeconds; this.exitCode = proc.ExitCode; if (this.stdoutFile != null) { this.stdoutFile.Close(); } if (failureBase != null && AlwaysEmitDiagnostics) { workingDirectory.CreateDirectoryFor(failureBase); File.WriteAllText(workingDirectory.PathTo(failureBase.makeOutputObject(".bat")), commandLine); File.WriteAllText(workingDirectory.PathTo(failureBase.makeOutputObject(".txt")), dbgText); File.WriteAllText(workingDirectory.PathTo(failureBase.makeOutputObject(".stdout")), this.GetStdoutString()); File.WriteAllText(workingDirectory.PathTo(failureBase.makeOutputObject(".stderr")), this.GetStderr()); } } } // REVIEW: Add Delete, Exists and Move methods to WorkingDirectory class? if (this.tmpStdout != null && File.Exists(workingDirectory.PathTo(this.tmpStdout))) { // REVIEW: Nothing should be here. Bother with the delete? File.Delete(workingDirectory.PathTo(captureStdout)); File.Move(workingDirectory.PathTo(this.tmpStdout), workingDirectory.PathTo(captureStdout)); this.tmpStdout = null; } } /// /// Gets the exit code returned by the process. /// public int ExitCode { get { return this.exitCode; } } /// /// Gets the CPU time used by the process, in seconds. /// public double CpuTime { get { return this.cpuTime; } } /// /// Gets the process's standard output in the default case. /// Does not return the standard output if it is redirected to a file (i.e. if CaptureStdout is non-null). /// /// The process's standard output. public string GetStdout() { return this.stdout.ToString(); } /// /// Gets the process's standard error output.. /// /// The process's standard error output. public string GetStderr() { return this.stderr.ToString(); } /// /// Gets the process's standard output, regardless of whether it was redirected to a file. /// /// The process's standard output. private string GetStdoutString() { if (this.tmpStdout != null) { return File.ReadAllText(this.workingDirectory.PathTo(this.tmpStdout)); } else { return this.GetStdout(); } } /// /// Alternate handler for the OutputDataReceived event. /// Stores the data in the previously specified file. /// /// The parameter is not used. /// Contains a line of characters read from the process's standard out. private void StdoutRedirectHandler(object sendingProcess, DataReceivedEventArgs dataLine) { this.stdoutFile.WriteLine(dataLine.Data); } /// /// Default handler for the OutputDataReceived event. /// Stores the data in a local StringBuilder instance. /// /// The parameter is not used. /// Contains a line of characters read from the process's standard out. private void StdoutHandler(object sendingProcess, DataReceivedEventArgs dataLine) { // REVIEW: Can't we use AppendLine here instead? this.stdout.Append(dataLine.Data + "\n"); } /// /// Handler for the ErrorDataReceived event. /// Stores the data in a local StringBuilder instance. /// /// The parameter is not used. /// Contains a line of characters read from the process's standard error. private void StderrHandler(object sendingProcess, DataReceivedEventArgs dataLine) { // REVIEW: Can't we use AppendLine here instead? this.stderr.Append(dataLine.Data + "\n"); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/Program.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; internal class Program { private bool useCloudExecution; private bool useCloudCache; private BackgroundWorker backgroundWorker; private string[] args; private VerificationRequest verificationRequest = new VerificationRequest(); public Program() { this.useCloudExecution = false; this.useCloudCache = true; this.backgroundWorker = new BackgroundWorker(); } static void Main(string[] args) { new Program().main(args); ////DbgHashSpeedTest.thing(); ////DbgFileCopySpeedTest.thing(); } void usage(string msg) { Logger.WriteLine(msg); Logger.WriteLine(string.Format( "Usage: {0} [opts] [Verb Target]*", System.AppDomain.CurrentDomain.FriendlyName)); throw new UserError("Invalid options"); } string ironRoot; int jobParallelism = 1; List verbs = new List(); string html_output = null; IroncladAppVerb.TARGET target_platform = IroncladAppVerb.TARGET.BARE_METAL; DafnyCCVerb.FramePointerMode useFramePointer = DafnyCCVerb.FramePointerMode.NoFramePointer; private bool releaseBuild = true; int argi; string takeArg(string expectedThing) { if (argi >= args.Count()) { usage("Expected " + expectedThing); } string rc = args[argi]; argi += 1; return rc; } SourcePath conditionSourcePath(string path) { return new SourcePath(path); } void fixIronRoot() { if (ironRoot == null) { ironRoot = getDefaultIronRoot(); if (ironRoot == null) { usage("--ironRoot not specified and cannot infer ironRoot"); } } BuildEngine.theEngine.setIronRoot(ironRoot); } void parseArgs(string[] args) { this.args = args; argi = 0; while (argi < args.Count()) { string next = takeArg("option or verb"); // Should always succeed due to while condition. if (next.StartsWith("-")) { if (next.Equals("--ironRoot")) { if (this.ironRoot != null) { usage("ironRoot set after use"); } this.ironRoot = takeArg("value for ironRoot"); } else if (next.Equals("-j") || next.Equals("--jobs")) { this.jobParallelism = Int32.Parse(takeArg("value for jobs")); } else if (next.Equals("--localcache")) { BuildEngine.theEngine.setLocalCache(takeArg("path for localcache")); } else if (next.ToLower().Equals("--cloudcache")) { this.useCloudCache = true; } else if (next.ToLower().Equals("--no-cloudcache")) { this.useCloudCache = false; } else if (next.Equals("--cloudexecution")) { this.useCloudExecution = true; } else if (next.ToLower().Equals("--verify")) { this.verificationRequest.verifyMode = VerificationRequest.VerifyMode.Verify; } else if (next.ToLower().Equals("--no-verify")) { this.verificationRequest.verifyMode = VerificationRequest.VerifyMode.NoVerify; } else if (next.ToLower().Equals("--no-symdiff")) { this.verificationRequest.verifyMode = VerificationRequest.VerifyMode.NoSymDiff; } else if (next.ToLower().Equals("--verify-select")) { this.verificationRequest.verifyMode = VerificationRequest.VerifyMode.SelectiveVerify; this.verificationRequest.selectiveVerifyModuleNames.Add(takeArg("filename for selective-verify")); } else if (next.ToLower().Equals("--html")) { this.html_output = takeArg("filename for html report"); } else if (next.ToLower().Equals("--windows")) { this.target_platform = IroncladAppVerb.TARGET.WINDOWS; } else if (next.ToLower().Equals("--useframepointer")) { this.useFramePointer = DafnyCCVerb.FramePointerMode.UseFramePointer; } else if (next.ToLower().Equals("--debug")) { this.releaseBuild = false; } else { usage("unrecognized option " + next); } } else { string verb = next; string target = takeArg("verb-target"); fixIronRoot(); if (verb.Equals("DafnyVerifyTree")) { verbs.Add(new VerificationResultSummaryVerb(new DafnyVerifyTreeVerb(conditionSourcePath(target)))); } else if (verb.Equals("BatchDafny")) { if (!target.EndsWith(".batch")) { usage("Batching expects a .batch file containing a list of .dfy files"); } verbs.Add(new VerificationResultSummaryVerb(new BatchVerifyVerb(conditionSourcePath(target), BatchVerifyVerb.BatchMode.DAFNY, this.verificationRequest, useFramePointer))); } else if (verb.Equals("BatchApps")) { if (!target.EndsWith(".batch")) { usage("Batching expects a .batch file containing a list of .dfy files"); } verbs.Add(new VerificationResultSummaryVerb(new BatchVerifyVerb(conditionSourcePath(target), BatchVerifyVerb.BatchMode.APP, this.verificationRequest, useFramePointer))); } else if (verb.Equals("Beat")) { verbs.Add(new BeatVerb(BuildEngine.theEngine.getVerveContextVerb(PoundDefines.empty()), conditionSourcePath(target), appLabel: null)); } else if (verb.Equals("Boogie")) { verbs.Add(new BoogieVerb(BuildEngine.theEngine.getVerveContextVerb(PoundDefines.empty()), conditionSourcePath(target), symdiff: this.verificationRequest.getSymDiffMode())); } else if (verb.Equals("IroncladApp")) { verbs.Add(new IroncladAppVerb(conditionSourcePath(target), target_platform, this.useFramePointer, this.verificationRequest)); } else if (verb.Equals("IronfleetApp")) { verbs.Add(new IronfleetAppVerb(conditionSourcePath(target), this.verificationRequest, this.releaseBuild)); } else if (verb.Equals("DafnyCompileOne")) { verbs.Add(new DafnyCompileOneVerb(conditionSourcePath(target))); } else if (verb.Equals("VSSolution")) { verbs.Add(new VSSolutionVerb(new SourcePath(target, SourcePath.SourceType.Tools))); } else if (verb.Equals("nmake")) { verbs.Add(new NmakeVerb(new SourcePath(target, SourcePath.SourceType.Tools))); } else if (verb.Equals("BootableApp")) { verbs.Add(new BootableAppVerb(conditionSourcePath(target), this.useFramePointer, this.verificationRequest)); } else { usage("Unknown verb " + verb); } } } fixIronRoot(); } private IItemCache GetItemCache() { string localCacheDirectory = Path.Combine( BuildEngine.theEngine.getIronRoot(), BuildEngine.theEngine.getLocalCache()); if (this.useCloudCache) { try { BuildEngine.theEngine.CloudCache = new ItemCacheCloud(); return new ItemCacheMultiplexer( new ItemCacheLocal(localCacheDirectory), BuildEngine.theEngine.CloudCache, this.backgroundWorker); } catch (Microsoft.WindowsAzure.Storage.StorageException) { // - // This will handle the case of being disconnected // at NuBuild launch time. // - Logger.WriteLine("Failed to create multiplexed cloud cache -- falling back to just local cache."); } } return new ItemCacheLocal(localCacheDirectory); } const string IRONROOT_sentinel = "IRONROOT.sentinel"; string getAssemblyPath() { string assyUri = System.Reflection.Assembly.GetExecutingAssembly().CodeBase; string assyPath = new Uri(assyUri).LocalPath; return assyPath; } string getDefaultIronRoot() { string exepath = Path.GetDirectoryName(getAssemblyPath()); exepath = Path.GetFullPath(exepath); string[] parts = exepath.Split(new char[] { '\\' }); for (int i = parts.Length; i > 0; i--) { string proposal = string.Join("\\", parts.Take(i)); if (File.Exists(Path.Combine(proposal, IRONROOT_sentinel))) { return proposal; } } return null; } void logNubuildInvocation(string[] args) { Logger.WriteLine(string.Format("{0} {1}", getAssemblyPath(), string.Join(" ", args))); } // NB this file is found in the default ironroot, since we // grab it before we parse your --ironroot argument. private const string NUBUILD_CONFIG = "nubuild.config"; private IEnumerable fetchConfigArgs() { string config_path = Path.Combine(getDefaultIronRoot(), NUBUILD_CONFIG); if (!File.Exists(config_path)) { return new string[] { }; } List config_args = new List(); foreach (string line in File.ReadAllLines(config_path)) { foreach (string word in line.Trim().Split(new char[] { ' ' })) { config_args.Add(word); } } return config_args; } void main(string[] cmdline_args) { string[] all_args = fetchConfigArgs().Concat(cmdline_args).ToArray(); logNubuildInvocation(all_args); try { parseArgs(all_args); } catch (UserError err) { usage(err.Message); } BuildEngine.theEngine.ItemCache = GetItemCache(); BuildEngine.theEngine.Repository = new Repository(BuildEngine.theEngine.ItemCache); if (this.useCloudExecution) { if (!this.useCloudCache) { usage("Cloud Execution requires Cloud Cache!"); } BuildEngine.theEngine.CloudReportQueueName = Path.GetRandomFileName().Substring(0, 8); BuildEngine.theEngine.CloudExecutionQueue = new CloudExecutionQueue(BuildEngine.theEngine.CloudReportQueueName); Logger.WriteLine("Using cloud report queue name: " + BuildEngine.theEngine.CloudReportQueueName); } Scheduler scheduler = new Scheduler(jobParallelism); scheduler.addTargetVerbs(verbs); ////try ////{ scheduler.parallelSchedule(); ////} ////catch (Exception ex) ////{ //// scheduler.dbgDisplayCounts(); //// throw; ////} IEnumerable targets = scheduler.getTargets(); BuildObject outputTarget = null; if (targets.Count() > 0) { outputTarget = targets.First(); } else { Logger.WriteLine("No targets requested."); } if (targets.Count() > 1) { // TODO need a better story for relaying failure results. Right now // they get stuck in the results cache, but don't appear where we // can find them. Emit to a log, or to files in nuobj? Logger.WriteLine("Multiple targets build. First result follows."); } if (outputTarget != null) { Disposition d = scheduler.getObjectDisposition(outputTarget); if (d is Fresh) { ASCIIPresentater ascii = new ASCIIPresentater(); IVerb verb = scheduler.getParent(outputTarget); verb.getPresentation().format(ascii); Logger.Write(ascii.ToString()); if (this.html_output != null) { HTMLPresentater html = new HTMLPresentater(); verb.getPresentation().format(html); try { using (StreamWriter sw = new StreamWriter(this.html_output)) { sw.Write(html.ToString()); } } catch (Exception e) { Logger.WriteLine("Failed to write html output to file: " + html_output); Logger.WriteLine("Exception was: " + e); } } } else { Logger.WriteLine("Build failed."); foreach (string msg in d.getMessages()) { Logger.Write(msg); } } } else if (targets.Count() == 0) { Logger.WriteLine("No targets requested."); } else { Logger.WriteLine("Multiple targets built. Look for results in nuobj/."); } // - // We have to explicitly ask the BackgroundWorker thread to exit // as it will prevent the process from exiting until it does. // - this.backgroundWorker.StopWork(); // - // Report what the background worker accomplished during this run. // - this.backgroundWorker.WaitForCompletion(); Logger.WriteLine(string.Format("Background Worker completed {0} work items out of {1} queued.", this.backgroundWorker.GetWorkItemsPerformed, this.backgroundWorker.GetWorkItemsQueued)); if (this.backgroundWorker.GetWorkItemsFailed != 0) { Logger.WriteLine(string.Format( "{0} work item procedures failed (threw an exception).", this.backgroundWorker.GetWorkItemsFailed)); } } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/Properties/AssemblyInfo.cs ================================================ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("NuBuild")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("NuBuild")] [assembly: AssemblyCopyright("Copyright © 2014")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("1855bc44-97d2-41da-89fc-dae901580a54")] // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/Repository.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; /// /// Tracker of BuildObjects, in their various forms. /// For virtual build objects, also provides the content store. /// /// /// There is only one instance of this class in the system. /// This class includes functionality from the old ResultCache and /// NuObjContents classes. /// Old NuObjContents comment: /// This class keeps track of the data we've stored into nuobj/. /// The invariant is that we never read data out of nuobj/ if it's /// not data we put there ourselves this execution (perhaps by /// fetching it from the cache). Data from the cache is safe, /// because it is tracked by concreteIdentifier. But data in /// nuobj/ may be stale, leading us to build the wrong thing. /// (A wrong thing would be correctly labeled, so it won't poison /// the cache, but it wouldn't be the output the user asked for.) /// internal class Repository { /// /// Collection of information about build objects. /// private Dictionary entries; /// /// Record of the verbs for which we've already added the /// output objects resulting from their (cached) execution. /// /// /// This avoids re-adding the entire set if we ask for another object /// in the same verb's output list. Note that this ignores the hash /// value of the verb; it assumes that the hash values don't change /// across a run of this process. /// private HashSet alreadyAddedVerbs; /// /// The item cache we're using. /// private IItemCache itemCache; /// /// Initializes a new instance of the Repository class. /// /// The item cache we're using. public Repository(IItemCache itemCache) { this.itemCache = itemCache; this.entries = new Dictionary(); this.alreadyAddedVerbs = new HashSet(); } /// /// Reads a build object from the local filesystem and stores it in the /// cache. /// /// /// Private directory for verb execution. /// /// The build object to store in the cache. /// /// Disposition of verb which created this object (if known). /// /// A BuildObjectValuePointer describing the object. public BuildObjectValuePointer Store(WorkingDirectory workingDirectory, BuildObject obj, Disposition disposition) { string contentHash = Util.hashFilesystemPath(workingDirectory.PathTo(obj)); this.itemCache.StoreItemFromFile(ItemCacheContainer.Objects, contentHash, workingDirectory.PathTo(obj)); this.Add(obj, disposition, contentHash, null); return new BuildObjectValuePointer(contentHash, obj.getRelativePath()); } /// /// Fetches a build object and stores it in the local filesystem. /// /// /// Directory under which to store the fetched object. /// /// The object to fetch. public void Fetch(WorkingDirectory workingDirectory, BuildObject obj) { RepositoryEntry entry = this.FetchFresh(obj); // REVIEW: best way to determine this is a source file? ItemCacheContainer container; if (obj is SourcePath) { container = ItemCacheContainer.Sources; } else { container = ItemCacheContainer.Objects; } this.itemCache.FetchItemToFile(container, entry.Hash, workingDirectory.PathTo(obj)); } /// /// Gets a readable stream for the given build object contents. /// /// The object in question. /// An open, readable stream to the contents. public TextReader OpenRead(BuildObject obj) { RepositoryEntry entry = this.FetchFresh(obj); // REVIEW: best way to determine this is a source file? ItemCacheContainer container; if (obj is SourcePath) { container = ItemCacheContainer.Sources; } else { container = ItemCacheContainer.Objects; } byte[] contents = this.itemCache.FetchItem(container, entry.Hash); MemoryStream stream = new MemoryStream(contents, false); return new StreamReader(stream); } /// /// Stores a result record in the cache. /// /// /// Item cache hash key to store result under. /// /// The result record to store. public void StoreResult(string inputHash, ResultSummaryRecord result) { ItemCacheContainer container; if (result.IsVerificationTimeout || (result.Disposition is Failed)) { container = ItemCacheContainer.FailedResults; } else { container = ItemCacheContainer.Results; } using (MemoryStream outStream = new MemoryStream()) { using (StreamWriter outWriter = new StreamWriter(outStream)) { outWriter.Write(result.ToXml()); } this.itemCache.StoreItem(container, inputHash, outStream.ToArray()); } } /// /// Fetches a result record from the cache. /// /// /// Item cache hash key the result is stored under. /// /// /// Whether to return cached failures as well as successes. /// /// /// The result record requested if available, otherwise returns a /// summary record with Stale disposition. /// public ResultSummaryRecord FetchResult(string inputHash, bool includeFailedResults = false) { byte[] result = this.itemCache.FetchItem(ItemCacheContainer.Results, inputHash); if ((result == null) && includeFailedResults) { result = this.itemCache.FetchItem(ItemCacheContainer.FailedResults, inputHash); } if (result != null) { MemoryStream resultStream = new MemoryStream(result); try { using (StreamReader inReader = new StreamReader(resultStream)) { string xmlSummary = inReader.ReadToEnd(); return ResultSummaryRecord.FromXml(xmlSummary); } } catch (System.Xml.XmlException ex) { throw new ObjectMissingFromCacheException(inputHash, "Malformed xml: " + ex.ToString()); } finally { resultStream.Dispose(); } } else { return new ResultSummaryRecord(new Stale(), new BuildObjectValuePointer[] { }, false); } } /// /// Add information about a virtual object to the Repository, /// including its contents. /// /// The object in question. /// /// Disposition of the verb which created this object. /// /// Contents of the object. public void StoreVirtual(BuildObject obj, Disposition disposition, VirtualContents contents) { Util.Assert(obj is VirtualBuildObject); this.Add(obj, disposition, null, contents); } /// /// Retrieves the virtual content referenced by the given build object. /// /// The object in question. /// The virtual contents of the object. public VirtualContents FetchVirtual(BuildObject obj) { return this.FetchFresh(obj).VirtualContents; } /// /// Gets the disposition of the verb that generated a build object. /// /// The object in question. /// Disposition of the object. public Disposition GetDisposition(BuildObject obj) { RepositoryEntry value = this.GetValue(obj); if (value != null) { return value.Disposition; } return new Stale(); } /// /// Gets the hash of an object registered with this Repository. /// /// The object in question. /// /// The hash of the object (if known), otherwise null. /// public string GetHash(BuildObject obj) { string hash = null; RepositoryEntry value = this.GetValue(obj); if (value != null) { if (value.Disposition is Failed) { hash = null; } else if (obj is VirtualBuildObject) { hash = "virtual"; } else { hash = value.Hash; } } return hash; } /// /// Adds the output objects from a cached verb execution to the /// repository, and ensures they are present in the item cache. /// /// The verb whose outputs to add. /// /// The result summary record of the verb execution. /// /// /// Call only when output objects are known to be cached /// (i.e. because FetchResult returned non-Stale). /// REVIEW: This function probably shouldn't be in this file. /// It does something similar for cached verb results that /// the scheduler's recordResult method does for new verb /// executions. Move this there and/or refactor? /// public void AddVerbResults(IVerb verb, ResultSummaryRecord resultRecord) { if (this.alreadyAddedVerbs.Contains(verb)) { // We only need to add a cached verb execution's outputs once. return; } Disposition disposition = resultRecord.Disposition; // REVIEW: In the below, some of these IEnumerables should be // HashSets, and the HashSet should be a simple List. // Create a collection of the potential outputs. IEnumerable outputs = verb.getOutputs(); IEnumerable failureOutputs = verb.getFailureOutputs(); outputs = outputs.Concat(failureOutputs); Dictionary potentialOutputs = new Dictionary(); foreach (BuildObject obj in outputs) { potentialOutputs.Add(obj.getRelativePath(), obj); } // Compare the actual outputs with the potential outputs, // and add the actual ones to the repository. HashSet recorded = new HashSet(); foreach (BuildObjectValuePointer actualOutput in resultRecord.Outputs) { if (potentialOutputs.ContainsKey(actualOutput.RelativePath)) { BuildObject obj = potentialOutputs[actualOutput.RelativePath]; // TODO: Verify that the object exists in the item cache! this.AddObject(obj, disposition, actualOutput.ObjectHash); recorded.Add(obj); // Store a copy of this verb output as a file in the real nuobj directory. Util.Assert(actualOutput.RelativePath.StartsWith(BuildEngine.theEngine.getObjRoot(), StringComparison.Ordinal)); this.itemCache.FetchItemToFile(ItemCacheContainer.Objects, actualOutput.ObjectHash, IronRootDirectory.PathTo(actualOutput.RelativePath)); } else { // Complain if we find interloping outputs. throw new Exception("Distressing: some actual verb outputs aren't in the verb's list of potential outputs"); } } // Create a collection of missing outputs. IEnumerable unrecorded = outputs.Except(recorded).Except(failureOutputs); // For non-Failed verb runs, complain if all expected outputs don't // show up in the actual outputs. Util.Assert(unrecorded.Count() == 0 || disposition is Failed); // For cached verb runs with permanent failures (i.e. disposition // is Failed), we want to mark all of the expected outputs as Failed // even if no corresponding actual output was produced during the // failed verb run. foreach (BuildObject obj in unrecorded) { this.AddObject(obj, disposition, null); } // Remember that we've already added this verb's outputs. this.alreadyAddedVerbs.Add(verb); } /// /// Add information about an object to the Repository. /// The object path must be under the object root. /// /// The object in question. /// /// Disposition of the verb which created this object. /// /// Hash of the object's contents. public void AddObject(BuildObject obj, Disposition disposition, string hash) { Util.Assert(obj.getRelativePath().StartsWith(BuildEngine.theEngine.getObjRoot(), StringComparison.Ordinal)); this.Add(obj, disposition, hash, null); } /// /// Gets the number of entries in this repository, for debugging. /// /// Number of objects recorded in this repository. internal int DbgCacheSize() { return this.entries.Count(); } /// /// Fetches information about the given object in this repository. /// /// The object to fetch. /// Information about the object. private RepositoryEntry FetchFresh(BuildObject obj) { RepositoryEntry value = this.GetValue(obj); if (value == null) { throw new ObjectNotReadyException(obj); } if (value.Disposition is Failed) { throw new ObjectFailedException(obj, (Failed)value.Disposition); } Util.Assert(value.Disposition is Fresh); // This isn't really a 'not ready' condition; we shouldn't be here. REVIEW: What is meant by this comment? return value; } /// /// Gets information about an object in this repository. /// Will add missing source objects to the repository as needed. /// /// The object to look up. /// Information about the object. /// /// Returns null if obj isn't in this run's cache. /// Cannot return value.disposition==Stale, I guess? /// private RepositoryEntry GetValue(BuildObject obj) { if (this.entries.ContainsKey(obj)) { return this.entries[obj]; } else { SourcePath src = obj as SourcePath; if (src != null) { // Special case to get local source files into the // repository (and the item cache). // REVIEW: Should we require that source files are explicitly added? try { // Complain if someone uses tabs or non-CRLF line endings in a source file. // Visual Studio is pretty insistent on using tabs in solution (.sln) files, so we let it. if ((src.Type == SourcePath.SourceType.Src) && (src.getExtension() != ".sln")) { if (!Util.CheckSourceFileForBadCharacters(IronRootDirectory.PathTo(obj))) { throw new SourceConfigurationError("Bad characters (tabs?) or non-CRLF line endings in source file " + obj.getRelativePath()); } } string hash = Util.hashFilesystemPath(IronRootDirectory.PathTo(obj)); this.itemCache.StoreItemFromFile(ItemCacheContainer.Sources, hash, IronRootDirectory.PathTo(obj)); this.Add(obj, new Fresh(), hash, null); } catch (IOException) { throw new SourceConfigurationError("Cannot find source path " + obj.getRelativePath()); } return this.entries[obj]; } else { return null; } } } /// /// Add information about an object to the Repository. /// /// The object to add. /// /// Disposition of the verb which created this object. /// /// Hash of the object's contents. /// Contents of the object (if virtual). private void Add(BuildObject obj, Disposition disposition, string hash, VirtualContents contents) { // Every object in the repository should either have a hash value // or virtual contents, but not both. Util.Assert((string.IsNullOrEmpty(hash) && contents != null) || (!string.IsNullOrEmpty(hash) && (contents == null))); // Check to see if the object is already in this repository. if (this.entries.ContainsKey(obj)) { // We shouldn't be adding conflicting information for // the same object during the same build run. RepositoryEntry entry = this.entries[obj]; Util.Assert(entry.Disposition.GetType() == disposition.GetType()); Util.Assert(entry.Hash.Equals(hash, StringComparison.Ordinal)); Util.Assert(entry.VirtualContents == contents); // Don't replace existing entry with equivalent. return; } this.entries[obj] = new RepositoryEntry(disposition, hash, contents); } /// /// Information we keep about build objects in our collection. /// private class RepositoryEntry { /// /// Disposition of the verb that created this object. /// private Disposition disposition; /// /// Hash of the object's contents (if non-virtual). /// private string hash; /// /// For objects not stored in the item cache or the filesystem, /// here's the computed value. /// private VirtualContents virtualContents; /// /// Initializes a new instance of the RepositoryEntry class. /// /// /// Disposition of the verb that created this object. /// /// Hash of the object's contents. /// /// Computed value of the object (if virtual, null otherwise). /// public RepositoryEntry(Disposition disposition, string hash, VirtualContents virtualContents) { this.hash = hash; this.disposition = disposition; this.virtualContents = virtualContents; } /// /// Gets the hash of the object's contents. /// public string Hash { get { return this.hash; } } /// /// Gets the disposition of the verb that created this object. /// public Disposition Disposition { get { return this.disposition; } } /// /// Gets the computed value of the object (if a virtual object, /// returns null otherwise). /// public VirtualContents VirtualContents { get { return this.virtualContents; } } } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/ResultSummaryRecord.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; using System.Text; using System.Xml; /// /// Representation of the result of a particular verb's execution. /// public class ResultSummaryRecord { /// /// The XML element name for this object. /// public const string XmlTag = "ResultSummaryRecord"; /// /// The XML attribute name for the IsVerificationTimeout value. /// public const string XmlIsVerificationTimeoutAttribute = "IsVerificationTimeout"; /// /// The verb whose execution this is the result of. /// private IVerb verb; /// /// The disposition of the verb execution. /// private Disposition disposition; /// /// Whether this result is a rejectable failure. /// private bool isRejectableFailure; /// /// The build objects that were produced by this verb execution. /// private List outputs; /// /// Initializes a new instance of the ResultSummaryRecord class. /// /// /// The verb whose execution this is the result of. /// /// /// The disposition of the verb execution. /// /// /// The build objects that were produced by this verb execution. /// internal ResultSummaryRecord( IVerb verb, Disposition disposition, IEnumerable outputs) : this(verb, disposition, outputs, false) { } /// /// Initializes a new instance of the ResultSummaryRecord class. /// /// /// The disposition of the verb execution. /// /// /// The build objects that were produced by this verb execution. /// /// /// Whether this result is a verification timeout. /// internal ResultSummaryRecord( Disposition disposition, IEnumerable outputs, bool isVerificationTimeout) : this(null, disposition, outputs, isVerificationTimeout) { } /// /// Initializes a new instance of the ResultSummaryRecord class. /// /// /// The verb whose execution this is the result of. /// /// /// The disposition of the verb execution. /// /// /// The build objects that were produced by this verb execution. /// /// /// Whether this result is a rejectable failure. /// internal ResultSummaryRecord( IVerb verb, Disposition disposition, IEnumerable outputs, bool isRejectableFailure) { this.verb = verb; this.disposition = disposition; this.outputs = new List(outputs); this.isRejectableFailure = isRejectableFailure; IRejectable rejectableVerb = verb as IRejectable; if (rejectableVerb != null) { this.isRejectableFailure = rejectableVerb.resultWasRejectableFailure(); } } /// /// Gets a value indicating whether this result is a failure of /// some sort (includes verification timeouts). /// public bool IsFailure { get { return this.isRejectableFailure || (this.disposition is Failed); } } /// /// Gets a value indicating whether this result is a verification /// timeout. /// public bool IsVerificationTimeout { get { return this.isRejectableFailure; } } /// /// Gets the build objects that were produced by this verb execution. /// public IEnumerable Outputs { get { return this.outputs; } } /// /// Gets the disposition of the verb execution. /// internal Disposition Disposition { get { return this.disposition; } } /// /// Creates a result record from an XML representation. /// /// /// A string containing an XML document representing this result record. /// /// /// A new result record corresponding to the XML representation read. /// public static ResultSummaryRecord FromXml(string xs) { XmlReader xr = XmlReader.Create(new StringReader(xs)); while (xr.Read()) { if (xr.NodeType == XmlNodeType.Element) { break; } } return ReadXml(xr); } /// /// Helper function to read an XML element (not a full document) /// representing a result record. /// /// /// Note that the XmlReader is expected to be positioned in the XML /// document such that the current node is a result record element. /// /// The XmlReader object to read from. /// /// A new result record corresponding to the XML representation read. /// public static ResultSummaryRecord ReadXml(XmlReader xr) { Util.Assert(xr.Name.Equals(ResultSummaryRecord.XmlTag)); bool isVerificationTimeout = false; bool.TryParse( xr.GetAttribute(XmlIsVerificationTimeoutAttribute), out isVerificationTimeout); xr.ReadToFollowing(Disposition._xml_tag); Disposition d = Disposition.readXml(xr); List lbovp = new List(); while (xr.Read()) { if (xr.NodeType == XmlNodeType.EndElement) { Util.Assert(xr.Name.Equals(ResultSummaryRecord.XmlTag)); break; } else if (xr.NodeType == XmlNodeType.Element) { if (xr.Name.Equals(BuildObjectValuePointer.XmlTag)) { lbovp.Add(BuildObjectValuePointer.ReadXml(xr)); } else { throw new Exception("Unknown xml tag " + xr.Name); } } } return new ResultSummaryRecord(d, lbovp, isVerificationTimeout); } /// /// Creates an XML document representing this result record. /// /// /// A string containing an XML document representing this result record. /// public string ToXml() { StringBuilder sb = new StringBuilder(); XmlWriterSettings settings = new XmlWriterSettings(); settings.Indent = true; XmlWriter xw = XmlWriter.Create(sb, settings); xw.WriteStartDocument(); this.WriteXml(xw); xw.Close(); return sb.ToString(); } /// /// Helper function to write an XML element (not a full document) /// representing this result record. /// /// The XmlWriter object to write to. public void WriteXml(XmlWriter xw) { xw.WriteStartElement(XmlTag); xw.WriteAttributeString( ResultSummaryRecord.XmlIsVerificationTimeoutAttribute, this.isRejectableFailure.ToString()); if (this.verb != null) { this.verb.writeTimingXml(xw); this.verb.writeDebugXml(xw); } this.disposition.writeXml(xw); foreach (BuildObjectValuePointer bovp in this.outputs) { bovp.WriteXml(xw); } xw.WriteEndElement(); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/Scheduler.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; /// /// Mechanism for determining which verbs need to be run and in what order. /// internal class Scheduler { /// /// Whether to produce conditional debug output in the scheduler and /// some of its components. /// internal const bool Debug = false; /// /// Where to write scheduler progress information (for debugging). /// private const string DbgProgressFileName = "nubuild.progress"; /// /// REVIEW: Not used. Remove? /// private const string DispositionFileExtension = ".disp"; /// /// The second-order verb sorter we use. /// private VerbToposorter verbToposorter; /// /// Collection of initial output targets. /// private HashSet targets; /// /// Waiting verb tracker? /// private WaitIndex waitIndex; /// /// Tracker of build objects. /// private Repository repository; /// /// The component of the scheduler that runs verbs for us. /// private VerbRunner verbRunner; /// /// Count of verbs submitted to the verbRunner for running during /// this round? /// private int submittedCount; /// /// Map of build objects to the verb that creates them. /// private Dictionary outputToVerbMap; /// /// Verbs in the outputToVerbMap. /// REVIEW: These verbs should be equivalent to those in /// outputToVerbMap.Values. Worth keeping this separate HashSet /// for performance reasons? /// private HashSet knownVerbs; /// /// Cache of verb dependencies. /// private DependencyCache depCache; /// /// Verbs that have been submitted for execution or failed, /// and need not be further considered. /// private HashSet resolvedVerbs; /// /// Verbs that have been completed, and hence can't contribute /// to resolving any pending dependencies. /// (If it's resolved and not completed, it must be submitted /// for asynchronous execution.) /// private HashSet completedVerbs; /// /// Our general strategy is to record the outcome of every verb in /// a persistent result cache, and then to evaluate each downstream /// BuildObject by querying that cache. But when one verb fails, /// it may make the downstream verb unable to even compute its input /// set, and hence its concreteIdentifier (the key to a persistent /// cache). If we don't record the outcome somehow, we'll loop /// forever trying to learn the outcome of the downstream failure. /// So we record it here in-process, keyed by abstractIdentifier /// (which is assumed to be stable over a single run of NuBuild). /// Invariant: all values in this dictionary are Faileds. (We store /// them because they might (someday) propagate information about /// what failed for an error message.) /// private Dictionary unrecordableFailures; /// /// Whether to reject cached failures, apparently. /// Value comes from a command-line argument. /// private bool rejectCachedFailures; /// /// Verbs that are (still) required to be run to build our target(s). /// Verbs are removed from this collection as they are completed. /// private HashSet requiredVerbs; /// /// Verbs to look at on next pass through parallelSchedule's main loop? /// Serves as a method for passing a collection of verbs between /// parallelSchedule and disposeCurrentVerbs. /// private HashSet nextVerbs; ////private DbgVerbCounter dbgVerbCounter = new DbgVerbCounter(); /// /// Initializes a new instance of the Scheduler class. /// /// /// Degree of parallel execution to allow. /// /// /// Whether to reject cached failures. /// public Scheduler(int jobParallelism) { this.targets = new HashSet(); this.waitIndex = new WaitIndex(); this.repository = BuildEngine.theEngine.Repository; this.unrecordableFailures = new Dictionary(); this.verbToposorter = new VerbToposorter(); this.verbRunner = new VerbRunner(this.verbToposorter, jobParallelism); this.resolvedVerbs = new HashSet(); this.completedVerbs = new HashSet(); this.outputToVerbMap = new Dictionary(); this.knownVerbs = new HashSet(); this.depCache = new DependencyCache(); this.rejectCachedFailures = true; // this is now permanent. The code path for caching Failure results has rotted. } /// /// Adds one or more build objects to our collection of targets. /// /// /// REVIEW: Make this private (or inline into addVerbTargets)? /// /// Build objects to add. public void addTargets(IEnumerable newTargets) { this.targets.UnionWith(newTargets); } /// /// Schedules the verbs for execution. /// This is the top-level method driving the build. /// public void parallelSchedule() { // Convert our collection of initial targets into a // collection of verbs we need to run to create them. this.requiredVerbs = new HashSet(); foreach (BuildObject target in this.targets) { this.requiredVerbs.Add(this.getParent(target)); } // The set of verbs we're evaluating now. HashSet currentVerbs = new HashSet(this.requiredVerbs); // A set into which we accumulate verbs to evaluate on the next pass. this.nextVerbs = new HashSet(); // Loop until we've run all the verbs we need to run. while (this.requiredVerbs.Count() > 0) { this.disposeCurrentVerbs(currentVerbs); currentVerbs = null; // Just to be obvious. // Okay, now we wait around for some deps to finish, freeing up new targets. while (this.nextVerbs.Count() == 0 && this.requiredVerbs.Count() > 0) { this.Say(string.Format("scheduler waits, having submitted {0} verbs", this.submittedCount)); ////Util.Assert(submittedCount > 0); // False because we might be waiting for other stuff to complete. List taskCompletions; taskCompletions = this.verbRunner.scheduleAndWait(this); this.Say("received " + taskCompletions.Count() + " taskCompletions"); Util.Assert(this.requiredVerbs.Count() == 0 || taskCompletions.Count() > 0); this.processTaskCompletions(taskCompletions); currentVerbs = this.nextVerbs; this.nextVerbs = new HashSet(); if (currentVerbs.Count() > 0 || this.requiredVerbs.Count() == 0) { // Hey, something changed that we could reschedule on, // or we're actually all done. break; } // Hmm, we've got no opportunity to schedule new stuff, // so the VerbRunner better not return empty-handed the // next time through. // We've got an assert taskCompletions.Count()>0 to check // for that. this.Say("Scheduler waiting for more results."); } } } /// /// Display various debugging information. /// public void dbgDisplayCounts() { ////dbgVerbCounter.dbgDisplayCounts(); this.depCache.dbgPrintStats(); } /// /// Display various debugging information. /// internal void dbgDumpWaitIndex() { this.waitIndex.dbgDisplayIndex(this); } /// /// Determine the status of a verb (for debugging purposes). /// /// Verb being examined. /// A string containing the verb's current status. internal string dbgGetVerbStatus(IVerb verb) { if (this.completedVerbs.Contains(verb)) { return "completed"; } if (this.resolvedVerbs.Contains(verb)) { return "submitted"; } return "pending"; } /// /// Adds a verb to the mapping of build objects to the verb which /// creates them. /// /// /// TODO: Make this private. /// /// The verb to add. internal void addVerb(IVerb verb) { if (!this.knownVerbs.Add(verb)) { // We've already added this verb. return; } // Add all verb outputs to the output-to-verb map. foreach (BuildObject obj in verb.getOutputs()) { if (this.outputToVerbMap.ContainsKey(obj)) { Util.Assert(this.outputToVerbMap[obj].Equals(verb)); } else { this.outputToVerbMap[obj] = verb; } } // Recursively add all the verbs this verb is dependent upon, // so that we have a complete index of outputs back to the // verbs that generate them. foreach (IVerb dependentVerb in verb.getVerbs()) { this.addVerb(dependentVerb); } } /// /// Adds a collection of verbs (or rather their outputs) as /// targets for this build. /// /// A list of verbs to run. internal void addTargetVerbs(List verbs) { foreach (IVerb verb in verbs) { this.addVerb(verb); this.addTargets(verb.getOutputs()); } } /// /// Gets a list of target objects for this build. /// /// A list of target objects for this build. internal IEnumerable getTargets() { return this.targets; } /// /// Gets the verb that created the given object. /// /// /// Would like to rename this to "GetCreator" or "GetCreatorVerb" /// as it seems strange to call something a parent when it is a /// completely different object type, but the terminology seems /// to be widely used in the system. /// /// The object in question. /// The verb that creates the given object. internal IVerb getParent(BuildObject obj) { IVerb result; this.outputToVerbMap.TryGetValue(obj, out result); return result; } /// /// Gets the disposition of the verb that created the given object. /// /// The object in question. /// The disposition of the verb that created the given object. internal Disposition getObjectDisposition(BuildObject obj) { return this.repository.GetDisposition(obj); } /// /// Updates the "progress" output file with current status information. /// /// /// Count of verbs currently able to be run. /// /// /// Count of verbs currently running. /// internal void dbgUpdateProgress(int runnableVerbsCount, int runningVerbsCount) { StringBuilder sb = new StringBuilder(); sb.AppendLine("completedVerbs: " + this.completedVerbs.Count()); sb.AppendLine("resolvedVerbs: " + this.resolvedVerbs.Count()); sb.AppendLine("runnableVerbs: " + runnableVerbsCount); sb.AppendLine("runningVerbs: " + runningVerbsCount); sb.AppendLine("waitingVerbs: " + this.waitIndex.Count()); File.WriteAllText(DbgProgressFileName, sb.ToString()); } /// /// Computes a concrete identifier for a verb operation and its /// specific inputs. /// /// The verb to compute the hash for. /// /// Whether to assert if we can't compute the hash. /// /// /// A concrete identifier for a verb operation and its specific inputs. /// private string computeInputHash(IVerb verb, bool assertHashAvailable) { StringBuilder sb = new StringBuilder(); sb.Append(verb.getAbstractIdentifier().getConcreteId()); DependencyDisposition ddisp; foreach (BuildObject obj in this.depCache.getDependencies(verb, out ddisp)) { sb.Append(","); string hash = this.repository.GetHash(obj); Util.Assert(!assertHashAvailable || (hash != null)); sb.Append(hash); } if (ddisp == DependencyDisposition.Failed) { // This happens when we're trying to markFailed, // but the upstream has failed and we can't compute // our dependencies. In that case, markFailed // settles for noting the failure in-process, // but not caching the result. (Okay, since this // failure propagation is cheap to rediscover.) Util.Assert(!assertHashAvailable); return null; } Util.Assert(ddisp == DependencyDisposition.Complete); string rc = Util.hashString(sb.ToString()); return rc; } /// /// Finds some verbs that could possibly complete in the future and help /// resolve one of these dependencies. /// /// A list of unresolved dependencies. /// /// A list of verbs that could possibly create one or more of the /// missing dependencies. /// private List robustDiscoverReadyDeps(IEnumerable staleDeps) { List newParents = new List(); foreach (BuildObject dep in staleDeps) { IVerb parent = this.getParent(dep); if (parent != null) { if (this.completedVerbs.Contains(parent)) { // Wait, if the parent is completed, why is the child a stale dependency? Util.Assert(false); } newParents.Add(parent); } } return newParents; } /// /// Push each potential target somewhere else: replace it with its /// dependencies, or mark its outputs failed, or mark it runnable and /// give it to the verb runner. /// /// Set of verbs to process. private void disposeCurrentVerbs(HashSet currentVerbs) { this.submittedCount = 0; this.Say("disposeCurrentVerbs"); while (currentVerbs.Count() > 0) { foreach (IVerb verb in currentVerbs) { this.Say("disposeCurrentVerbs considering " + verb); ////dbgVerbCounter.consider(verb, DbgVerbCounter.DbgVerbCondition.DVWake); if (this.resolvedVerbs.Contains(verb)) { // Enthusiastic wakeup? continue; } if (this.waitIndex.isWaiting(verb)) { // He's already waiting for something else. continue; } DependencyDisposition ddisp; List knownDeps = new List(this.depCache.getDependencies(verb, out ddisp)); List staleDeps = new List(); List failedDeps = new List(); foreach (BuildObject dep in knownDeps) { Disposition disp = this.repository.GetDisposition(dep); if (disp is Stale) { staleDeps.Add(dep); } else if (disp is Failed) { failedDeps.Add(dep); } } if (staleDeps.Count() > 0 || ddisp == DependencyDisposition.Incomplete) { // Some inputs aren't yet available, so we can prompt one of those verbs // instead, and wake this one up when those are done. Util.Assert(staleDeps.Count() > 0); // REVIEW: Clean this up post SOSP. #if false List newParents = this.robustDiscoverReadyDeps(staleDeps); if (newParents.Count() == 0) { this.reexamineVerb(verb); newParents = this.robustDiscoverReadyDeps(staleDeps); Util.Assert(newParents.Count() > 0); } #else this.reexamineVerb(verb); List newParents = this.robustDiscoverReadyDeps(staleDeps); Util.Assert(newParents.Count() > 0); #endif this.nextVerbs.UnionWith(newParents); this.Say( string.Format( "disposeCurrentVerbs waits {0} dependent on {1} liberating {2}", verb, string.Join(",", staleDeps), string.Join(",", newParents))); this.waitIndex.insert(verb, staleDeps); } else if (ddisp == DependencyDisposition.Failed || failedDeps.Count() > 0) { this.Say(string.Format("disposeCurrentVerbs marks {0} failed", verb)); this.markFailed(verb); this.resolvedVerbs.Add(verb); ////dbgVerbCounter.consider(verb, DbgVerbCounter.DbgVerbCondition.DVDepsNonstale); } else { // All inputs are available, so we can compute concrete identifier // to retrieve from cache... string inputHash = this.computeInputHash(verb, true); Util.Assert(inputHash != null); if (!this.fetchFromCache(verb, inputHash)) { ////if (verb is BoogieAsmVerificationObligationListVerb) { System.Environment.Exit(0); } this.Say(string.Format("disposeCurrentVerbs submits {0}", verb)); // Or if it's not in cache, we can execute. // Verb's inputs are ready, and output is stale: mark verb runnable. ////Say(string.Format(" {0} submitted", verb)); this.verbRunner.submitVerb(verb); this.submittedCount += 1; } this.resolvedVerbs.Add(verb); ////dbgVerbCounter.consider(verb, DbgVerbCounter.DbgVerbCondition.DVDepsNonstale); } } // We've disposed all the current verbs. But maybe we found some more // we can pop loose right now. currentVerbs = this.nextVerbs; this.nextVerbs = new HashSet(); } } /// /// Checks the cache for a previous execution of this verb operating on /// the same inputs; updates our state with the cached results if so. /// /// The verb to check for prior execution. /// /// An identifier for this verb operating on a specific set of inputs. /// /// /// True if usable previous execution was found, false otherwise. /// private bool fetchFromCache(IVerb verb, string inputHash) { try { ResultSummaryRecord summary = this.repository.FetchResult(inputHash); if (summary.Disposition is Stale) { return false; } // REVIEW: Since we aren't asking FetchResult to return failures, // this check is no longer needed. Or at least it won't be once // the "Results" cache is cleared of all existing failure records. if (this.rejectCachedFailures && (summary.Disposition is Failed || summary.IsVerificationTimeout)) { Logger.WriteLine(string.Format( "NOTE: rejecting failure from cache {0}", verb)); return false; } this.Say(string.Format("disposeCurrentVerbs pulls {0} from cache", verb)); // Hey, this verb is already computed! Nothing to do. // Add the verb execution's results to the repository. this.repository.AddVerbResults(verb, summary); this.verbIsComplete(verb, summary.Disposition); return true; } catch (ObjectMissingFromCacheException ex) { Logger.WriteLine(string.Format( "WARNING: expected object {0} missing from cache; discarding cached result {1}", ex, verb)); return false; } } /// /// Reexamines a verb to see if it now knows more regarding what other /// verbs need to run first in order to create its dependencies. /// /// The verb to reexamine. private void reexamineVerb(IVerb verb) { foreach (IVerb parentVerb in verb.getVerbs()) { this.addVerb(parentVerb); } } /// /// Processes task completion messages. /// /// /// A list of task completion messages. /// private void processTaskCompletions(List taskCompletions) { foreach (VerbRunner.TaskCompletion tc in taskCompletions) { // We may record a Failure if the verb didn't output // everything it promised to. Disposition recordedDisposition = this.recordResult(tc); this.Say(string.Format(" {0} completed with disposition {1}", tc.verb, tc.disposition)); } // Waking process may have shaken some verbs loose for us to evaluate next time around. } /// /// Conditionally debug print a message. /// /// The message to print. private void Say(string s) { if (Debug) { #pragma warning disable 162 Logger.WriteLine("[sched] " + s); #pragma warning restore 162 } } /// /// Logs output regarding a verb's execution disposition. /// /// The verb in question. /// Disposition of the verb execution. private void emitRealtimeReport(IVerb verb, Disposition disposition) { Presentation pr = verb.getRealtimePresentation(disposition); ASCIIPresentater ascii = new ASCIIPresentater(); pr.format(ascii); Logger.Write(ascii.ToString()); } /// /// Mark a verb as completed, and adjust our schedule accordingly. /// /// The verb that completed. /// The disposition of the verb's execution. private void verbIsComplete(IVerb verb, Disposition disp) { ////Say(string.Format(" {0} is complete: {1}", verb, dbgDisposition)); ////if (disp is Failed) ////{ //// // Failures can be hard to debug, since they don't leave any //// // output in nuobj/. So report these even if they aren't //// // built this run. //// emitRealtimeReport(verb, disp); ////} // Invariant: all of this verb's objs are non-Stale. foreach (BuildObject obj in verb.getOutputs()) { ////Say(string.Format(" waking {0}", obj)); IEnumerable wokenSet = this.waitIndex.awaken(obj); ////foreach (IVerb wokenVerb in wokenSet) ////{ //// //Say(string.Format(" {0} woken", wokenVerb)); ////} this.nextVerbs.UnionWith(wokenSet); } this.emitRealtimeReport(verb, disp); this.requiredVerbs.Remove(verb); this.completedVerbs.Add(verb); } /// /// Record how each output of a task appeared. /// /// The task completion notification. /// Overall result of the verb execution. private Disposition recordResult(VerbRunner.TaskCompletion completion) { WorkingDirectory workingDirectory = completion.workingDirectory; IVerb verb = completion.verb; Disposition executionDisposition = completion.disposition; List outputs = new List(); List missingOutputs = new List(); IEnumerable expectedOutputs = verb.getOutputs(); if (executionDisposition is Failed) { expectedOutputs = expectedOutputs.Concat(verb.getFailureOutputs()); } bool hasVirtualOutputs = false; foreach (BuildObject outobj in expectedOutputs) { if (!(outobj is VirtualBuildObject)) { // For expected file outputs, check for existence in working directory. // REVIEW: Add method to WorkingDirectory which does this? if (File.Exists(workingDirectory.PathTo(outobj))) { // Try to catch accidental case mismatches that would burn us when we // try to fetch the file back in. ////string fsname = PathNormalizer.dbg_normalizePath_nocache(outobj.deprecatedGetFilesystemPath(), false); ////Util.Assert(Path.GetFileName(fsname).Equals(outobj.getFileName())); // REVIEW: Do we need to worry about case mismatches anymore? See comments above. outputs.Add(this.repository.Store(workingDirectory, outobj, executionDisposition)); // Store a copy of this verb output as a file in the real nuobj directory. Util.Assert(outobj.getRelativePath().StartsWith(BuildEngine.theEngine.getObjRoot(), StringComparison.Ordinal)); string nuobjPath = IronRootDirectory.PathTo(outobj); Directory.CreateDirectory(Path.GetDirectoryName(nuobjPath)); File.Copy(workingDirectory.PathTo(outobj), nuobjPath, true); } else { missingOutputs.Add(string.Format("Missing expected output {0}", outobj.getRelativePath())); } } else { hasVirtualOutputs = true; if (this.repository.GetDisposition(outobj) is Fresh) { // Nothing to cache; virtual objects only survive in the Repository, the in-process store. } else { missingOutputs.Add(string.Format("Missing expected virtual {0}", outobj.getRelativePath())); } } } if (!(executionDisposition is Failed) && missingOutputs.Count() > 0) { executionDisposition = new Failed(missingOutputs); } ResultSummaryRecord summary = new ResultSummaryRecord(verb, executionDisposition, outputs); string inputHash = this.computeInputHash(verb, true); Util.Assert(inputHash != null); if (!hasVirtualOutputs) { this.repository.StoreResult(inputHash, summary); } else { this.Say("Not caching verb persistently: " + verb); } this.verbIsComplete(verb, executionDisposition); return executionDisposition; } /// /// Mark a verb as having failed. /// /// The verb that failed. private void markFailed(IVerb verb) { // At least one of verb's inputs has a permanent failure, so we didn't // even try to execute it. Disposition disposition = new Failed("upstream failure"); ResultSummaryRecord summary = new ResultSummaryRecord(verb, disposition, new BuildObjectValuePointer[] { }); // NB never store upstream failures to the persistent cache, because // they depend on our knowledge this run that the upstream verb failed. // If, in another run, the verb or its inputs are modified, produce the // same outputs, but returns success, we'll be stuck pulling this // upstream failure out of cache but calling this verb a failure. ////string inputHash = computeInputHash(verb, false); ////if (inputHash != null) ////{ //// Util.Assert(false); //// // "Upstream failures" will never have a computable inputHash, because their inputs //// // can't be considered known. Even if the upstream verb wrote something to disk, //// // what if the upstream verb changes to no longer fail but still emit the same thing? //// // We wouldn't want to conclude that, because the inputs hadn't changed, this //// // verb still had an upstream failure. //// repository.StoreResult(inputHash, summary); ////} ////else ////{ this.unrecordableFailures[verb] = disposition; ////} // Mark all the verb's outputs as Failed in the repository. foreach (BuildObject obj in verb.getOutputs()) { if (obj is VirtualBuildObject) { this.repository.StoreVirtual(obj, disposition, null); } else { this.repository.AddObject(obj, disposition, null); } } this.verbIsComplete(verb, disposition); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/SourceConfigurationError.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; internal class SourceConfigurationError : Exception { public SourceConfigurationError(string msg) : base(msg) { } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/SourcePath.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.IO; /// /// Representation of a source BuildObject. /// These are things which we expect to pre-exist, instead of built by us. /// internal class SourcePath : BuildObject { /// /// The type of "source" this is. /// private SourceType sourceType; /// /// Initializes a new instance of the SourcePath class. /// /// /// Relative path to this object in the local filesystem. /// /// /// The type of "source" this is. /// public SourcePath(string inpath, SourceType sourceType = SourceType.Src) : base(inpath) { // Sanity checks. this.checkPrefix(sourceType, SourceType.Src, BuildEngine.theEngine.getSrcRoot()); this.checkPrefix(sourceType, SourceType.Tools, BuildEngine.theEngine.getToolsRoot()); this.checkPrefix(sourceType, SourceType.BinTools, BuildEngine.theEngine.getBinToolsRoot()); this.checkPrefix(sourceType, SourceType.PrebakedObjExpediency, "obj"); // TODO remove. this.sourceType = sourceType; this.IsTrusted = getRelativePath().StartsWith( Path.Combine(BuildEngine.theEngine.getSrcRoot(), BuildEngine.VerveTrustedSpecDir), StringComparison.OrdinalIgnoreCase); } /// /// Various types of "sources". /// public enum SourceType { /// /// Source file. /// Src, /// /// Tools (executables usually) that we don't build ourselves. /// Tools, /// /// Tools that we could build ourselves. /// Probably don't really want this in the long run, /// since we can build these. /// BinTools, /// /// Special purpose expediency. /// Used to point at bootloader, until we can get an nmake verb working. TODO remove. /// PrebakedObjExpediency } /// /// Gets the source type of this instance. /// public SourceType Type { get { return this.sourceType; } } /// /// Creates a new SourcePath, where the source type is the same as this /// SourcePath's, and the path is relative to the directory containing /// this SourcePath. /// /// /// REVIEW: This should be renamed to MakeNewSourcePath to correspond /// with BuildObject /// /// Relative path to the new object. /// The new SourcePath. public SourcePath getNewSourcePath(string inpath) { return new SourcePath(Path.Combine(getDirPath(), inpath), this.sourceType); } /// /// Checks that the path prefix for this object is reasonable for the /// given source type. /// /// The given source type. /// /// Source type the prefix parameter matches. /// /// /// Prefix that paths of the matchType parameter should have. /// private void checkPrefix(SourceType givenType, SourceType matchType, string prefix) { if (givenType == matchType) { if (!path.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) { throw new UserError(string.Format( "Source path {0} should begin with {1}", this.path, prefix)); } } } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/SourcePathIncludeContext.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; using System.Linq; // This context looks for files in a set of source path locations. internal class SourcePathIncludeContext : IncludePathContext { private List directories; private List dstExtensions; private string _descr; public SourcePathIncludeContext() { this.directories = new List(); this.dstExtensions = new List(); } public override string ToString() { if (this._descr == null) { this._descr = "{" + string.Join(",", this.directories.Select(d => d.directory)) + "}; {" + string.Join(",", this.dstExtensions) + "}"; } return this._descr; } // Add a directory path relative to ironRoot. public void addDirectory(string directory) { Util.Assert(this._descr == null); this.directories.Add(new DirectoryRecord(directory)); } public void addDstExtension(string extension) { Util.Assert(this._descr == null); this.dstExtensions.Add(extension); } public override BuildObject search(string basename, ModPart modPart) { List results = new List(); foreach (string extension in this.dstExtensions.Where(extn => BeatExtensions.whichPart(extn) == modPart)) { string filename = basename + extension; foreach (DirectoryRecord directoryRecord in this.directories) { if (directoryRecord.Contains(filename)) { string proposed = Path.Combine( BuildEngine.theEngine.getIronRoot(), BuildEngine.theEngine.getSrcRoot(), directoryRecord.directory, basename + extension); ////Logger.WriteLine("SourcePathIncludeContext Trying " + proposed); ////Util.Assert(File.Exists(proposed)); results.Add(new SourcePath(proposed)); } } } if (results.Count() == 0) { return null; } else if (results.Count() > 1) { throw new SourceConfigurationError(string.Format( "Reference {0} matches {1} paths: {2}", basename, results.Count(), string.Join(",", results))); } else { return results.First(); } } private class DirectoryRecord { private readonly string _directory; private readonly HashSet _files; public DirectoryRecord(string directory) { this._directory = directory; string absDir = Path.Combine( BuildEngine.theEngine.getIronRoot(), BuildEngine.theEngine.getSrcRoot(), this._directory); this._files = new HashSet(Directory.EnumerateFiles(absDir) .Select(path => Path.GetFileName(path))); } public string directory { get { return this._directory; } } public bool Contains(string file) { return this._files.Contains(file); } } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/StaticContextVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; // Recipient needs to accept IContextGeneratingVerbs, but we don't need // any dependencies to produce this (static) context. So this is a simple, // non-dependent verb that just spews a ContextContents. internal class StaticContextVerb : ContextGeneratingVerb { private IIncludePathContext _context; public StaticContextVerb(IIncludePathContext context, string nickname, PoundDefines poundDefines) : base(nickname, poundDefines) { this._context = context; } public override IEnumerable getDependencies(out DependencyDisposition ddisp) { ddisp = DependencyDisposition.Complete; return new BuildObject[] { }; } public override IEnumerable getVerbs() { return new IVerb[] { }; } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { ContextContents contents = new ContextContents(this._context); BuildEngine.theEngine.Repository.StoreVirtual(this.getContextOutput(), new Fresh(), contents); return new VerbSyncWorker(workingDirectory, new Fresh()); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/SymDiffBaseVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Linq; internal abstract class SymDiffBaseVerb : Verb, IProcessInvokeAsyncVerb { private const int version = 10; public abstract IEnumerable getInputFiles(); public abstract BuildObject getOutputFile(); public override IEnumerable getDependencies(out DependencyDisposition ddisp) { ddisp = DependencyDisposition.Complete; List deps = new List(this.getInputFiles()); deps.Add(getSymDiffExecutable()); deps.AddRange(getSymDiffExecutableDependencies()); // REVIEW: Probably need to add SymDiffExecutable's dependencies too. return deps; } public override IEnumerable getOutputs() { return new List() { this.getOutputFile() }; } public virtual void preprocess(WorkingDirectory workingDirectory) { } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { List args = this.getArgs(); preprocess(workingDirectory); // We use workingDirOverride flag here to change the path that the // process starts in to one that is still in our workingDirectory. // So this isn't so bad. It would be better if NuBuild would only // let us supply a relative path here, however. string overrideDir = null; if (this.getWorkingDir() != null) { overrideDir = workingDirectory.PathTo(this.getWorkingDir()); } return new ProcessInvokeAsyncWorker( workingDirectory, this, getSymDiffExecutable().getRelativePath(), args.ToArray(), ProcessExitCodeHandling.NonzeroIsFailure, getDiagnosticsBase(), workingDirOverride: overrideDir, returnStandardOut: true); } public virtual Disposition Complete(WorkingDirectory workingDirectory, double cpuTimeSeconds, string stdout, string stderr, Disposition disposition) { return disposition; } protected static SourcePath getSymDiffExecutable() { return new SourcePath("tools\\SymDiff\\SymDiff.exe", SourcePath.SourceType.Tools); } protected static IEnumerable getSymDiffExecutableDependencies() { List exeDepends = new List(); exeDepends.Add(new SourcePath("tools\\SymDiff\\Basetypes.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\SymDiff\\Core.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\SymDiff\\CodeContractsExtender.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\SymDiff\\Graph.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\SymDiff\\ParserHelper.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\SymDiff\\Provers.SMTLib.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\SymDiff\\VCGeneration.dll", SourcePath.SourceType.Tools)); exeDepends.Add(new SourcePath("tools\\SymDiff\\z3.exe", SourcePath.SourceType.Tools)); return exeDepends; } protected abstract List getArgs(); protected virtual string getWorkingDir() { return getOutputFile().getDirPath(); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/SymDiffCombineVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; internal class SymDiffCombineVerb : SymDiffBaseVerb, IProcessInvokeAsyncVerb { public const string MERGED_FILE_NAME = "mergedProgSingle.bpl"; private const int version = 3; private AbstractId abstractId; private SymDiffExtractVerb left; private SymDiffExtractVerb right; private SymDiffMergeConfigVerb merger; private BuildObject outputFile; public SymDiffCombineVerb(SymDiffExtractVerb left, SymDiffExtractVerb right, SymDiffMergeConfigVerb merger) { this.left = left; this.right = right; this.merger = merger; // Naming one of the files should be sufficient to uniquely identify the combiner. this.abstractId = new AbstractId(this.GetType().Name, version, left.getOutputFile().ToString()); ////abstractId = String.Format("{0}(#{1},{2},{3},{4})", //// this.GetType().Name, //// version, //// left.getOutputFile(), //// right.getOutputFile(), //// merger.getOutputFile()); this.outputFile = this.mkOutputFile(); } public override IEnumerable getInputFiles() { return new List() { this.left.getOutputFile(), this.right.getOutputFile(), this.merger.getOutputFile() }; } public override BuildObject getOutputFile() { return this.outputFile; } public override AbstractId getAbstractIdentifier() { return this.abstractId; } public override IEnumerable getVerbs() { return new List() { this.left, this.right, this.merger }; } public override IEnumerable getOutputs() { return new List() { this.getOutputFile() }; } protected override List getArgs() { List args = new List(); args.Add("-allInOne"); args.Add(this.left.getOutputFile().getFileName()); args.Add(this.right.getOutputFile().getFileName()); args.Add(this.merger.getOutputFile().getFileName()); ////args.Add(left.getOutputFile().getRelativePath()); ////args.Add(right.getOutputFile().getRelativePath()); ////args.Add(merger.getOutputFile().getRelativePath()); List extra_args = new List() { "-asserts", "-freeContracts", "-usemutual", "-sound", "-dontUseHoudiniForMS", "-checkMutualPrecondNonTerminating" }; args.AddRange(extra_args); return args; } private BuildObject mkOutputFile() { // SymDiff always uses the same file name in the working directory. return new BuildObject(Path.Combine(this.left.getOutputFile().getDirPath(), MERGED_FILE_NAME)); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/SymDiffEngine.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; internal class SymDiffEngine { public static void BuildPipeline(IContextGeneratingVerb context, BuildObject input, out BuildObject bplFile, out IVerb workerVerb) { BoogieAsmVerifyVerb basmVerb = new BoogieAsmVerifyVerb(context, input, true); SymDiffExtractVerb left = new SymDiffExtractVerb(basmVerb, SymDiffExtractVerb.Mode.LEFT); SymDiffExtractVerb right = new SymDiffExtractVerb(basmVerb, SymDiffExtractVerb.Mode.RIGHT); SymDiffInferVerb infer = new SymDiffInferVerb(left, right); SymDiffMergeConfigVerb mergeConfig = new SymDiffMergeConfigVerb(basmVerb, infer); SymDiffCombineVerb combiner = new SymDiffCombineVerb(left, right, mergeConfig); SymDiffMergeVerb merger = new SymDiffMergeVerb(basmVerb, combiner); bplFile = merger.getOutputFile(); workerVerb = merger; } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/SymDiffExtractVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; internal class SymDiffExtractVerb : SymDiffBaseVerb { public const string UNROLLED_EXTN = "_u"; public const string LEFT_FILE = "v1"; public const string RIGHT_FILE = "v2"; private const int version = 5; private AbstractId abstractId; private BoogieAsmVerifyVerb basmVerb; private BuildObject basmIn; private Mode mode; public SymDiffExtractVerb(BoogieAsmVerifyVerb basmVerb, Mode mode) { this.basmVerb = basmVerb; this.basmIn = basmVerb.outputFile(); this.mode = mode; this.abstractId = new AbstractId(this.GetType().Name, version, this.basmIn.ToString(), concrete: mode.ToString()); } public enum Mode { LEFT, RIGHT } public override IEnumerable getInputFiles() { return new List() { this.basmIn }; } public string getFileName() { switch (mode) { case Mode.LEFT: return LEFT_FILE; case Mode.RIGHT: return RIGHT_FILE; default: throw new Exception("Unexpected mode for SymDiffExtractVerb"); } } private BuildObject getTmpInputFile() { return new BuildObject(Path.Combine(basmIn.getDirPath(), getFileName() + BoogieVerb.BPL_EXTN)); } public override BuildObject getOutputFile() { return new BuildObject(Path.Combine(this.basmIn.getDirPath(), getFileName() + UNROLLED_EXTN + BoogieVerb.BPL_EXTN)); ////return basmIn.makeOutputObject(extension + BoogieVerb.BPL_EXTN); } public override AbstractId getAbstractIdentifier() { return this.abstractId; } public override IEnumerable getVerbs() { return new List() { this.basmVerb }; } public override IEnumerable getOutputs() { return new List() { this.getOutputFile() }; } public override void preprocess(WorkingDirectory workingDirectory) { base.preprocess(workingDirectory); File.Copy(workingDirectory.PathTo(basmIn), workingDirectory.PathTo(getTmpInputFile()), true); } protected override List getArgs() { List args = new List(); args.Add("-extractLoops"); args.Add(getTmpInputFile().getFileName()); args.Add(getOutputFile().getFileName()); return args; } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/SymDiffInferVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; internal class SymDiffInferVerb : SymDiffBaseVerb, IProcessInvokeAsyncVerb { public const string CONFIG = ".partial_config"; private const int version = 6; private AbstractId abstractId; private SymDiffExtractVerb left; private SymDiffExtractVerb right; public SymDiffInferVerb(SymDiffExtractVerb left, SymDiffExtractVerb right) { this.left = left; this.right = right; this.abstractId = new AbstractId(this.GetType().Name, version, left.getOutputFile().ToString().ToString()); // Left should suffice to uniquely ID. } public override IEnumerable getInputFiles() { return new List() { this.left.getOutputFile(), this.right.getOutputFile() }; } public override BuildObject getOutputFile() { // Choice of left/right doesn't matter here, since we're dropping the extension. return this.left.getOutputFile().makeOutputObject(CONFIG); } public override AbstractId getAbstractIdentifier() { return this.abstractId; } public override IEnumerable getVerbs() { return new List() { this.left, this.right }; } public override IEnumerable getOutputs() { return new List() { this.getOutputFile() }; } public override Disposition Complete(WorkingDirectory workingDirectory, double cpuTimeSeconds, string stdout, string stderr, Disposition disposition) { if (!(disposition is Failed)) { File.WriteAllText(workingDirectory.PathTo(this.getOutputFile()), stdout); } return disposition; } protected override List getArgs() { List args = new List(); args.Add("-inferConfig"); args.Add(this.left.getOutputFile().getFileName()); args.Add(this.right.getOutputFile().getFileName()); return args; } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/SymDiffMergeBaseVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; using System.Linq; internal abstract class SymDiffMergeBaseVerb : Verb, IProcessInvokeAsyncVerb { private const int version = 3; private static NmakeVerb boogieAsmBuildExecutableVerb = new NmakeVerb(new SourcePath("tools\\BoogieAsm\\makefile", SourcePath.SourceType.Tools)); public abstract BuildObject getOutputFile(); public override IEnumerable getDependencies(out DependencyDisposition ddisp) { ddisp = DependencyDisposition.Complete; List deps = new List(this.getInputFiles()); deps.Add(getSymDiffMergeExecutable()); // REVIEW: Probably need to add SymDiffMergeExecutable's dependencies too. return deps; } public override IEnumerable getVerbs() { return new[] { boogieAsmBuildExecutableVerb }; } public override IEnumerable getOutputs() { return new List() { this.getOutputFile() }; } protected string getWorkingDir() { return getOutputFile().getDirPath(); } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { List args = this.getArgs(); // We use workingDirOverride flag here to change the path that the // process starts in to one that is still in our workingDirectory. // So this isn't so bad. It would be better if NuBuild would only // let us supply a relative path here, however. string overrideDir = null; if (this.getWorkingDir() != null) { overrideDir = workingDirectory.PathTo(this.getWorkingDir()); } return new ProcessInvokeAsyncWorker( workingDirectory, this, this.getSymDiffMergeExecutable().getRelativePath(), args.ToArray(), ProcessExitCodeHandling.NonzeroIsFailure, getDiagnosticsBase(), captureStdout: this.getOutputFile(), workingDirOverride:overrideDir); } public Disposition Complete(WorkingDirectory workingDirectory, double cpuTimeSeconds, string stdout, string stderr, Disposition disposition) { return disposition; } protected abstract IEnumerable getInputFiles(); protected abstract List getArgs(); private BuildObject getSymDiffMergeExecutable() { return new BuildObject(Path.Combine(boogieAsmBuildExecutableVerb.getOutputPath().getRelativePath(), "symdiffmerge.exe")); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/SymDiffMergeConfigVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Linq; internal class SymDiffMergeConfigVerb : SymDiffMergeBaseVerb, IProcessInvokeAsyncVerb { public const string CONFIG_EXTN = ".config"; private const int version = 7; private AbstractId abstractId; private BoogieAsmVerifyVerb basmVerb; private BuildObject mutualSummary; private SymDiffInferVerb inferVerb; private BuildObject inferredConfig; private BuildObject output; public SymDiffMergeConfigVerb(BoogieAsmVerifyVerb basmVerb, SymDiffInferVerb inferVerb) { this.basmVerb = basmVerb; this.mutualSummary = basmVerb.getMutualSummary(); this.inferVerb = inferVerb; this.inferredConfig = inferVerb.getOutputFile(); this.abstractId = new AbstractId(this.GetType().Name, version, this.inferredConfig.ToString()); // One should suffice for uniqueness: String.Format("{0},{1}", mutualSummary,inferredConfig)); this.output = this.basmVerb.outputFile().makeOutputObject(CONFIG_EXTN); } public override AbstractId getAbstractIdentifier() { return this.abstractId; } public override BuildObject getOutputFile() { return this.output; } public override IEnumerable getVerbs() { return base.getVerbs().Concat(new List() { this.basmVerb, this.inferVerb }); } protected override IEnumerable getInputFiles() { return new List() { this.mutualSummary, this.inferredConfig }; } protected override List getArgs() { List args = new List(); args.Add("-config"); args.Add(this.mutualSummary.getFileName()); args.Add(this.inferredConfig.getFileName()); return args; } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/SymDiffMergeVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Linq; internal class SymDiffMergeVerb : SymDiffMergeBaseVerb, IProcessInvokeAsyncVerb { public const string MERGED_EXTN = ".merge"; private const int version = 8; private AbstractId abstractId; private BoogieAsmVerifyVerb basmVerb; private BuildObject mutualSummary; private SymDiffCombineVerb combiner; private BuildObject output; public SymDiffMergeVerb(BoogieAsmVerifyVerb basmVerb, SymDiffCombineVerb combiner) { this.basmVerb = basmVerb; this.mutualSummary = basmVerb.getMutualSummary(); this.combiner = combiner; this.abstractId = new AbstractId(this.GetType().Name, version, this.combiner.getOutputFile().ToString()); // String.Format("{0},{1}", One should suffice for uniqueness: mutualSummary, combiner.getOutputFile())); this.output = this.basmVerb.outputFile().makeOutputObject(MERGED_EXTN + BoogieVerb.BPL_EXTN); } public override AbstractId getAbstractIdentifier() { return this.abstractId; } public override BuildObject getOutputFile() { return this.output; } public override IEnumerable getVerbs() { return base.getVerbs().Concat(new List() { this.basmVerb, this.combiner }); } protected override IEnumerable getInputFiles() { return new List() { this.mutualSummary, this.combiner.getOutputFile() }; } protected override List getArgs() { List args = new List(); args.Add("-merge"); args.Add(this.mutualSummary.getFileName()); args.Add(this.combiner.getOutputFile().getFileName()); return args; } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/ToDo.txt ================================================ ** High Level Issues ** - Shared remote execution results queue doesn't work well. Probably should switch this to a different method of returning results to the submitting client. Possibilities include an Azure table or per-client results queues. - Current method of cloud/local item cache synchronization is inefficient. - We need a better story for how we treat verb execution failures. - Pulling results from the cache throws (instead of failing gracefully) if a result is missing a referenced object. Fortunately, this doesn't seem to happen often (ever?). - All async verbs should list their executable (and its dependencies) as verb dependencies. Not clear we're there yet. Comment is in ProcessInvoker.cs. ** Medium Level Issues ** - Azure connection string (and other credentials for AzureManager tool) are hard-coded. Should read these from App Settings in the prescribed manner. - Use of arbitrary working directories is not yet supported by all verbs (for example, NMakeVerb uses workingDirOverride). Some efficiency improvements could be made if arbitrary working directories were universal. - Nothing checks to ensure that the XML representation of the various things we put in Azure queues (CloudExecutionRequest, CloudExecutionReport) don't exceed the maximum size for a queue entry. Unlikely to happen, except for how we currently return stdout & stderr (i.e. inline). - Nothing checks to ensure that we never exceed blob store size limitations. This is extremely unlikely to happen, as we are several orders below that. - ItemCacheMultiplexer treats all item cache entries as immutable -- this is true for objects and sources (since they're named by hashes of their contents) but not for results. This prevented us from overwritting bad results with good ones. Current solution is to cache bad results elsewhere. Good enough? - The "ASCIIPresentater" code for command line output implements ECMA-48 (aka "ANSI Escape Sequences") incorrectly. These also aren't supported by cmd.exe, so only people running NuBuild in alternate shells see the colored output. ** Code Cleanup ** - Cosmetic or non-functional changes: - Rename all methodNames to MethodNames as per StyleCop conventions. - Remove underscores from all private field names as per StyleCop conventions. - BuildObject has getRelativePath method instead of RelativePath property. - Rename IVerb's getFailureOutputs to getDiagnosticOutputs. - Presentater.cs is badly named, for multiple reasons. - Scheduler.cs has an addVerb method which could be private. - XmlFiller.cs should be IXmlFiller.cs (if we keep it at all). - Structural changes: - Fresh, Stale, and Failed are actual types in the type system (Disposition is the base class) rather than just values of Disposition. This causes various problems -- might want to make these just values of Disposition. - Hasher class contains only things that should be elsewhere. - CloudExecutionQueue constructor has lousy work-around for getIronRoot. How we determine the IronRoot (and how we manage progarm-wide state in general) could use some rearchitecting. - ProcessInvokeAsyncWorker takes the executable as a string, rather than a BuildObject (like all the other dependencies are). - Ugly code: - In propagePrivateImports in BeatExtensions.cs, a file is pre-pended to in a very inefficient manner. - DafnyTransformBaseVerb does getFileNameWithoutExtension manually? ** Things Outside of NuBuild's Control ** - Beat (Basm?) should be propagating import statements from the Beat file to the Basm output. - Beat doesn't properly ignore commented-out imports in ifcs files? - Dafny doesn't handle its include files properly, so we have to pull in all the include files ourselves in NuBuild (see DafnyCompileOneVerb). - DafnyCompileOneVerb RewriteCSharpFile does some stuff Dafny itself should. - DafnyTransformBaseVerb has special cases to handle weird differences between DafnyCC and DafnySpec. -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- Other ToDos: - Add source scanning capability to DafnyVerifyOneVerb. - Brittle code in BeatExtensions.cs getBeatFlavoredShallowDependencies. - Scary comment in BoogieVerb constructor. - Various issues with BootableAppVerb.cs: - Does this verb even work currently? Paths have broken? - We should build the pxe-loader, rather than include it. - SourceType.PrebakedObjExpediency is just to support this. - Other comments about bootloader. - We should build Dafny, not include a pre-built binary. - We should build nmake, not include a pre-built binary. - DafnyVerifyTreeVerb assumes all dafny files are source files (i.e. not built by NuBuild). An issue if we ever end up building and verifying intermediate dafny files. - BuildObject splitExtension has some Ironclad project file naming conventions built in. - EntryStitcherVerb contains a major special-case workaround. - IroncladAppVerb has a special case for pound define support. - MasmVerb should call ml.exe with with argument to include SPEC_INCLUDE_DIR? - VSSolutionVerb uses an absolute exe path for MSBuild.exe. - WinLinkerVerb uses absolute paths for various exes and libs. - Visual Studio and Windows SDK files mostly. - Also has two large files of mostly zeros that we wouldn't want to cache. - These don't appear to be listed as actual dependencies. - OrderPreservingSet has a comment by its author about not knowing what one of ICollection's methods (that it implements) is for. ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/TransitiveDepsContents.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; internal class TransitiveDepsContents : VirtualContents { OrderPreservingSet _shallowDeps, _transitiveDeps; public IEnumerable shallowDeps { get { return this._shallowDeps; } } public IEnumerable transitiveDeps { get { return this._transitiveDeps; } } public TransitiveDepsContents(OrderPreservingSet shallowDeps, OrderPreservingSet transitiveDeps) { this._shallowDeps = shallowDeps; this._transitiveDeps = transitiveDeps; } ////public override string getConcreteSummary() ////{ //// return "(" + String.Join(",", transitiveDeps) + ")"; ////} } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/TransitiveDepsVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Linq; internal abstract class TransitiveDepsVerb : Verb { public const string TDEP_EXTN = ".tdep"; private const int version = 3; private BuildObject obj; private BuildObject _depsObj; protected TransitiveDepsVerb(BuildObject obj) { this.obj = obj; this._depsObj = obj.makeVirtualObject(BeatExtensions.whichPart(obj).ExtnStr() + TDEP_EXTN); } public BuildObject depsObj() { return this._depsObj; } public override AbstractId getAbstractIdentifier() { return new AbstractId(this.GetType().Name, version, this.obj.getRelativePath()); } public override IEnumerable getOutputs() { return new BuildObject[] { this.depsObj() }; } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { OrderPreservingSet shallowDeps = new OrderPreservingSet(); OrderPreservingSet transitiveDeps = new OrderPreservingSet(); IEnumerable includes = this.getIncludeFactory().getIncludes(this.obj); foreach (BuildObject child in includes) { shallowDeps.Add(child); transitiveDeps.AddRange(this.factory(child).getTransitiveIncludes()); transitiveDeps.Add(child); } VirtualContents contents = new TransitiveDepsContents(shallowDeps, transitiveDeps); BuildEngine.theEngine.Repository.StoreVirtual(this.depsObj(), new Fresh(), contents); return new VerbSyncWorker(workingDirectory, new Fresh()); } // Available only after this verb is Fresh. // These are called the "transitive includes" because from this point of view, these aren't // dependencies, they're the included files. The caller may be using them to describe // his dependencies, though. public IEnumerable getTransitiveIncludes() { TransitiveDepsContents contents = (TransitiveDepsContents)BuildEngine.theEngine.Repository.FetchVirtual(this.depsObj()); return contents.transitiveDeps; } public IEnumerable getShallowIncludes() { TransitiveDepsContents contents = (TransitiveDepsContents)BuildEngine.theEngine.Repository.FetchVirtual(this.depsObj()); return contents.shallowDeps; } // This is a helper method for the downstream verb's getDependencies(). // It emits this verb's output token so that if this verb is // not yeat Fresh, the scheduler will strive to get this verb Executed, // plus if this verb is Fresh, tacks on all of the deps computed by // this verb. // The returned HashSet belongs to the caller, who is free // to stuff more into it. public HashSet getAvailableDeps(out DependencyDisposition ddisp) { HashSet result = new HashSet(); result.Add(this.depsObj()); try { result.UnionWith(this.getTransitiveIncludes()); result.Add(this.obj); // Add this last, since BoogieAsmLinkVerb appears to depend on this ordering ddisp = DependencyDisposition.Complete; } catch (ObjectNotReadyException) { ddisp = DependencyDisposition.Incomplete; } catch (ObjectFailedException) { ddisp = DependencyDisposition.Failed; } return result; } public override IEnumerable getVerbs() { try { IEnumerable includes = this.getIncludeFactory().getIncludes(this.obj); // NB evaluating eagerly so we can catch the exception here rather // than hide it in a lazy evaluation later. List result = new List(includes.Select(parent => this.factory(parent))); return result; } catch (ObjectNotReadyException) { } catch (SourceConfigurationError except) { throw new SourceConfigurationError(except.Message + " which is included by " + this.obj.getRelativePath()); } return new IVerb[] { }; } public override IEnumerable getDependencies(out DependencyDisposition ddisp) { // NB we'll either return the singleton list {obj} if obj isn't yet available, // or we'll return the entire list of deps on obj's parents. List deps = new List(); this.extendDeps(deps); deps.Add(this.obj); try { IEnumerable includes = this.getIncludeFactory().getIncludes(this.obj); if (includes.Contains(this.obj)) { throw new SourceConfigurationError("Include loop starting at " + this.obj); } deps.AddRange(includes.Select(parent => this.factory(parent).depsObj())); ddisp = DependencyDisposition.Complete; } catch (ObjectNotReadyException) { ddisp = DependencyDisposition.Incomplete; } catch (ObjectFailedException) { ddisp = DependencyDisposition.Failed; } return deps; } protected virtual void extendDeps(List deps) { } protected abstract TransitiveDepsVerb factory(BuildObject obj); protected abstract IIncludeFactory getIncludeFactory(); } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/UnverifiedSentinelVirtualContents.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; internal class UnverifiedSentinelVirtualContents : VirtualContents { } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/UserError.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; internal class UserError : Exception { public UserError(string msg) : base(msg) { } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/Util.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Diagnostics; using System.IO; using System.Runtime.Remoting.Metadata.W3cXsd2001; using System.Security.Cryptography; using System.Text; using System.Threading; /// /// General Utility Functions. /// public class Util { // Win32 MAX_PATH is 260 according to Internets. private const int MAX_MUNGED_LENGTH = 150; public static string hashString(string input) { byte[] buffer = new byte[input.Length * sizeof(char)]; System.Buffer.BlockCopy(input.ToCharArray(), 0, buffer, 0, buffer.Length); SHA256Managed hasher = new SHA256Managed(); byte[] rawHash = hasher.ComputeHash(buffer); return new SoapHexBinary(rawHash).ToString(); } public static string hashFilesystemPath(string filesystemPath) { ////Logger.WriteLine("Hashing " + filesystemPath); using (FileStream stream = File.OpenRead(filesystemPath)) { SHA256 sha = new SHA256Managed(); byte[] rawHash = sha.ComputeHash(stream); string rc = new SoapHexBinary(rawHash).ToString(); ////Logger.WriteLine("fresh hash of " + obj.getFilesystemPath() + " yields " + rc); return rc; } } public static string mungeClean(string s) { StringBuilder sb = new StringBuilder(); bool lastIsLetter = false; foreach (char c in s) { if (char.IsLetter(c) || char.IsNumber(c)) { sb.Append(c); lastIsLetter = true; } else { if (lastIsLetter) { sb.Append('-'); } lastIsLetter = false; } } if (sb.Length > MAX_MUNGED_LENGTH) { string originalPathHash = Util.hashString(sb.ToString()); int additionsLength = originalPathHash.Length + 3; sb.Remove(MAX_MUNGED_LENGTH - additionsLength, sb.Length - (MAX_MUNGED_LENGTH - additionsLength)); sb.Append("..."); sb.Append(originalPathHash); } return sb.ToString(); } // Replace characters in a filename the same way DafnySpec/DafnyCC does. public static string dafnySpecMungeName(string s) { return s.Replace('.', '_').Replace('-', '_'); } // Returns null if s doesn't end with eold. public static string replaceExtension(string s, string eold, string enew) { if (s.EndsWith(eold)) { return s.Substring(0, s.Length - eold.Length) + enew; } else { return null; } } /// /// Check an ASCII encoded file for the presence of bad characters /// and character combinations. What we consider bad: /// - Tab characters. /// - Carraige returns not followed by a line feed. /// - Line feeds not preceeded by a carraige return. /// /// File to check. /// True if no bad characters found. False otherwise. public static bool CheckSourceFileForBadCharacters(string sourcePath) { const int HT = 0x09; // Horizontal tab. const int LF = 0x0a; // Line feed. const int CR = 0x0d; // Carraige return. using (StreamReader reader = new StreamReader(sourcePath)) { int octet; // REVIEW: Sanity check reader.CurrentEncoding here? while ((octet = reader.Read()) > 0) { switch (octet) { case CR: if (reader.Read() != LF) { return false; } break; case LF: case HT: return false; } } } return true; } public static void Assert(bool condition) { if (!condition) { Logger.WriteLine("Assert failure."); Debug.Assert(condition); for (int loop = 10; loop > 0; loop--) { Logger.WriteLine("Something broke in assert. Attach a debugger to debug."); Logger.WriteLine(string.Format("You have {0} seconds to comply.", loop * 10)); Debugger.Break(); Thread.Sleep(10000); } Environment.Exit(-1); } } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/VSProjectParser.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; using System.Xml; /// /// Mechanism for parsing Visual Studio project Files. /// Determines project dependencies and outputs. /// internal class VSProjectParser { private SourcePath projectFile; private HashSet dependencies = new HashSet(); private HashSet outputs = new HashSet(); private string outputType = null; private string assemblyName = null; ////private string outputPath = null; /// /// Initializes a new instance of the VSProjectParser class. /// /// Visual Studio project file to parse. public VSProjectParser(SourcePath projectFile) { this.projectFile = projectFile; this.Parse(); CustomManifestParser cm = new CustomManifestParser(this.projectFile); this.dependencies.UnionWith(cm.getDependencies()); this.outputs.UnionWith(cm.getOutputs()); } public IEnumerable getDependencies() { return this.dependencies; } public IEnumerable getOutputs() { return this.outputs; } private void Parse() { this.dependencies.Add(this.projectFile); using (XmlTextReader reader = new XmlTextReader(IronRootDirectory.PathTo(this.projectFile))) { while (reader.Read()) { if (reader.NodeType == XmlNodeType.Element) { if (string.Compare(reader.Name, "Compile") == 0) { this.dependencies.Add(this.projectFile.getNewSourcePath(reader.GetAttribute("Include"))); } else if (string.Compare(reader.Name, "PropertyGroup") == 0) { this.ParseOutput(reader); } } } reader.Close(); } if (this.outputType != null && this.assemblyName != null) //// && outputPath != null) { string path = Path.Combine(this.projectFile.getDirPath(), string.Format("{0}.{1}", this.assemblyName, this.OutputTypeToExtension(this.outputType))); ////Console.WriteLine("{0}: generating {1}", this.projectFile.getRelativePath(), path); this.outputs.Add(new BuildObject(path)); } else { throw new UserError(string.Format("Project {0} doesn't seem to have output specification in the expected format", this.projectFile.getRelativePath())); } } private void ValidateConsistentOption(string optionName, string oldValue, string newValue) { if (oldValue == null) { return; } if (!oldValue.Equals(newValue)) { throw new UserError( string.Format( "Values for {0} not consistent across all build configurations in {1} ({2} vs {3})", optionName, this.projectFile.getRelativePath(), oldValue, newValue)); } } private void ParseOutput(XmlTextReader reader) { string lastElement = null; while (reader.Read()) { if (reader.NodeType == XmlNodeType.EndElement) { lastElement = null; if ("PropertyGroup".Equals(reader.Name)) { break; } } if (reader.NodeType == XmlNodeType.Element) { lastElement = reader.Name; } if (reader.NodeType == XmlNodeType.Text && lastElement != null) { string val = reader.Value; ////if ("OutputPath".Equals(lastElement)) ////{ //// validateConsistentOption("OutputPath", outputPath, val); //// outputPath = val; ////} if ("AssemblyName".Equals(lastElement)) { this.ValidateConsistentOption("AssemblyName", this.assemblyName, val); this.assemblyName = val; } if ("OutputType".Equals(lastElement)) { this.ValidateConsistentOption("OutputType", this.outputType, val); this.outputType = val; } } } } private string OutputTypeToExtension(string outputType) { switch (outputType) { case "Exe": return "exe"; case "Library": return "dll"; default: throw new SourceConfigurationError("VSProjectParser doesn't know how to canonicalize " + outputType); } } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/VSSolutionParser.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; using System.Text.RegularExpressions; internal class VSSolutionParser { private SourcePath solutionFile; private List dependencies = new List(); private List outputs = new List(); public VSSolutionParser(SourcePath solutionFile) { this.solutionFile = solutionFile; this.Parse(); } public IEnumerable getDependencies() { return this.dependencies; } public IEnumerable getOutputs() { return this.outputs; } private void Parse() { this.dependencies.Add(this.solutionFile); using (StreamReader stream = new StreamReader(IronRootDirectory.PathTo(this.solutionFile))) { Regex regex = new Regex(@"Project\([\S]+\)[\s]+=[\s]+([^$]*)", RegexOptions.IgnoreCase); string line; while ((line = stream.ReadLine()) != null) { MatchCollection matches = regex.Matches(line); if (matches.Count > 0) { SourcePath projFile = this.solutionFile.getNewSourcePath(matches[0].Groups[1].Value.Split("\", ".ToCharArray())[5]); ////Console.WriteLine(String.Format("Found project file {0}", projFile.getFilesystemPath())); VSProjectParser proj = new VSProjectParser(projFile); this.dependencies.AddRange(proj.getDependencies()); this.outputs.AddRange(proj.getOutputs()); } } stream.Close(); } } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/VSSolutionVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; using System.Linq; /// /// Verb to build a Visual Studio solution. /// internal class VSSolutionVerb : Verb, IProcessInvokeAsyncVerb { private const int Version = 5; private readonly SourcePath solutionFile; private readonly AbstractId abstractId; private readonly VSSolutionParser solutionParser; private readonly string outputPathSuffix; private readonly DafnyCompileOneVerb dafnyCompileOneVerb; private readonly bool releaseBuild; /// /// Initializes a new instance of the VSSolutionVerb class. /// /// Solution file to build. /// Optional dafny-derived-CSharp dependency. public VSSolutionVerb(SourcePath solutionFile, SourcePath optionalDafnyInput = null, bool releaseBuild = false) { this.solutionFile = solutionFile; this.abstractId = new AbstractId(this.GetType().Name, VSSolutionVerb.Version, this.solutionFile.ToString()); this.releaseBuild = releaseBuild; // Parse the solution file (and project files contained in the solution). this.solutionParser = new VSSolutionParser(this.solutionFile); this.outputPathSuffix = Path.Combine(BuildEngine.theEngine.getObjRoot(), this.solutionFile.getDirPath()); if (optionalDafnyInput != null) { this.dafnyCompileOneVerb = new DafnyCompileOneVerb(optionalDafnyInput); } } public override IEnumerable getDependencies(out DependencyDisposition ddisp) { ddisp = DependencyDisposition.Complete; List dependencies = new List(this.solutionParser.getDependencies()); if (this.dafnyCompileOneVerb != null) { dependencies.AddRange(this.dafnyCompileOneVerb.getOutputs()); } return dependencies; } public override IEnumerable getVerbs() { return new IVerb[] { this.dafnyCompileOneVerb }; } public override IEnumerable getOutputs() { // Note that since we override the solution output directory in our // getWorker() below, we also need to override the output paths // coming from the solution parser. return from output in this.solutionParser.getOutputs() select new BuildObject(Path.Combine(this.outputPathSuffix, output.getFileName())); } public BuildObject getOutputPath() { return new BuildObject(this.outputPathSuffix); } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { // If we were given an optional dafny input, let this build know about the resulting verb's output. // Note: this is deliberately written to break if someone changes DafnyCompileOneVerb to have multiple outputs. if (this.dafnyCompileOneVerb != null) { File.Copy( workingDirectory.PathTo(this.dafnyCompileOneVerb.getOutputs().Single()), Path.Combine(workingDirectory.PathTo(this.outputPathSuffix), "DafnyDerivedInput.cs")); } List args = new List(); args.Add(string.Format("/p:OutDir={0}", workingDirectory.PathTo(this.outputPathSuffix))); args.Add(string.Format("/p:Configuration={0}", this.releaseBuild ? "Release" : "Debug")); ////args.Add("/fileLogger"); // Uncomment to log MSBuild execution. args.Add(workingDirectory.PathTo(this.solutionFile)); // TODO: Fix absolute path to MSBuild.exe (at least use %SystemRoot%)! return new ProcessInvokeAsyncWorker( workingDirectory, this, "c:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\MSBuild.exe", args.ToArray(), ProcessExitCodeHandling.NonzeroIsFailure, failureBase: getDiagnosticsBase(), allowAbsoluteExe: true, allowAbsoluteArgs: true); } public Disposition Complete(WorkingDirectory workingDirectory, double cpuTimeSeconds, string stdout, string stderr, Disposition disposition) { return disposition; } public override AbstractId getAbstractIdentifier() { return this.abstractId; } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/Verb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; using System.Xml; internal abstract class Verb : IVerb { public override bool Equals(object obj) { IVerb other = obj as IVerb; if (other != null) { return this.getAbstractIdentifier().Equals(other.getAbstractIdentifier()); } else { return false; } } public override int GetHashCode() { return this.getAbstractIdentifier().GetHashCode(); } public override string ToString() { return this.getAbstractIdentifier().ToString(); } public int CompareTo(object other) { return this.getAbstractIdentifier().CompareTo(((IVerb)other).getAbstractIdentifier()); } public abstract IEnumerable getDependencies(out DependencyDisposition ddisp); public abstract IEnumerable getVerbs(); public abstract IEnumerable getOutputs(); public virtual BuildObject getDiagnosticsBase() { return new BuildObject(Path.Combine( BuildEngine.theEngine.getObjRoot(), "diagnostics", Util.mungeClean(this.getAbstractIdentifier().ToString()))); } public virtual IEnumerable getFailureOutputs() { return new BuildObject[] { this.getDiagnosticsBase().makeOutputObject(".bat"), this.getDiagnosticsBase().makeOutputObject(".stdout"), this.getDiagnosticsBase().makeOutputObject(".stderr"), }; } public abstract IVerbWorker getWorker(WorkingDirectory workingDirectory); // Called by tool when this is the top-level output, it has generated a Fresh // result, and we want to print that result on the display. public virtual Presentation getPresentation() { PresentationBuilder pr = new PresentationBuilder(); pr.line("Okay."); return pr.fix(); } // Called by tool when we want a short (one-line) // summary for showing in-progress results. public virtual Presentation getRealtimePresentation(Disposition d) { PresentationBuilder pr = new PresentationBuilder(); pr.startLine(); pr.color( d is Fresh ? Presentation.GREEN : Presentation.RED, this.ToString() + " " + d.ToString()); pr.endLine(); if (d is Failed) { // This isn't a verification failure, a tool itself broke. // Provide that report. foreach (string m in d.getMessages()) { pr.pre(Presentation.abbreviateLines(m)); } } return pr.fix(); } //////////////////////////////////////////////////// // Handy helper for verbs using ProcessInvoker. private bool cpuTimeSecondsValid = false; private double cpuTimeSeconds; public virtual void RecordProcessInvokeCpuTime(double cpuTimeSeconds) { this.cpuTimeSeconds = cpuTimeSeconds; this.cpuTimeSecondsValid = true; } public static string XML_SubprocessTiming = "SubprocessTiming"; public static string XML_SubprocessTiming_Valid_Attr = "Valid"; public static string XML_SubprocessTiming_CPUTimeSeconds_Attr = "CPUTimeSeconds"; public void writeTimingXml(XmlWriter xw) { xw.WriteStartElement(XML_SubprocessTiming); xw.WriteAttributeString(XML_SubprocessTiming_Valid_Attr, this.cpuTimeSecondsValid.ToString()); if (this.cpuTimeSecondsValid) { xw.WriteAttributeString(XML_SubprocessTiming_CPUTimeSeconds_Attr, this.cpuTimeSeconds.ToString()); } xw.WriteEndElement(); } //////////////////////////////////////////////////// public abstract AbstractId getAbstractIdentifier(); public static string XML_DebugVerb = "DebugVerb"; public static string XML_DebugVerb_Value_Attr = "value"; public static string XML_DebugDep = "DebugDep"; public static string XML_DebugDep_Name_Attr = "name"; public static string XML_DebugDep_Hash_Attr = "hash"; public void writeDebugXml(XmlWriter xw) { xw.WriteStartElement(XML_DebugVerb); xw.WriteAttributeString(XML_DebugVerb_Value_Attr, this.getAbstractIdentifier().ToString()); xw.WriteEndElement(); DependencyDisposition ddisp; foreach (BuildObject obj in this.getDependencies(out ddisp)) { xw.WriteStartElement(XML_DebugDep); xw.WriteAttributeString(XML_DebugDep_Name_Attr, obj.getRelativePath()); if (!(obj is VirtualBuildObject)) { string hash = BuildEngine.theEngine.Repository.GetHash(obj); if (string.IsNullOrEmpty(hash)) { // REVIEW: Can this happen? Do something else here? hash = "unknown"; } xw.WriteAttributeString( XML_DebugDep_Hash_Attr, hash); } xw.WriteEndElement(); } Util.Assert(ddisp == DependencyDisposition.Complete); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/VerbOutputsContext.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; internal class VerbOutputsContext : IncludePathContext { private IVerb sourceVerb; private string descr; private HashSet dafnyOutputs; private bool assertSuspiciousDafnyImpls; public VerbOutputsContext(IVerb sourceVerb, bool assertSuspiciousDafnyImpls) { this.sourceVerb = sourceVerb; this.descr = "VerbOutputs(" + sourceVerb + ")"; this.assertSuspiciousDafnyImpls = assertSuspiciousDafnyImpls; } private HashSet DafnyOutputs { get { if (this.dafnyOutputs == null) { this.dafnyOutputs = new HashSet(this.sourceVerb.getOutputs()); } return this.dafnyOutputs; } } public override string ToString() { return this.descr; } public override BuildObject search(string basename, ModPart modPart) { // Kinda linear. ////Logger.WriteLine("Looking for " + basename); foreach (BuildObject obj in this.DafnyOutputs) { if (BeatExtensions.whichPart(obj) != modPart) { continue; } ////Logger.WriteLine(" trying " + obj.getFileNameWithoutExtension() + " from " + obj); if (string.Equals(obj.getFileNameWithoutExtension(), basename, StringComparison.OrdinalIgnoreCase)) { if (this.assertSuspiciousDafnyImpls) { DafnyCCVerb.AssertSmellsImplementy(obj); } return obj; } } return null; } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/VerbOutputsContextVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Linq; /// /// This verb waits for a parent verb to complete, then emits /// a ContextContents that searches the parent verb's results. /// internal class VerbOutputsContextVerb : ContextGeneratingVerb { private IVerb parent; private bool assertSuspiciousDafnyImpls; public VerbOutputsContextVerb(IVerb parent, bool assertSuspiciousDafnyImpls) : base(parent.getAbstractIdentifier().ToString(), null) { this.parent = parent; this.assertSuspiciousDafnyImpls = assertSuspiciousDafnyImpls; } public override IEnumerable getDependencies(out DependencyDisposition ddisp) { ddisp = DependencyDisposition.Complete; // I really don't care how many outputs the parent has; any one will // link me to the parent. IEnumerable result = this.parent.getOutputs(); Util.Assert(result.Count() > 0); return result; } public override IEnumerable getVerbs() { return new IVerb[] { this.parent }; } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { VerbOutputsContext context = new VerbOutputsContext(this.parent, this.assertSuspiciousDafnyImpls); ContextContents contents = new ContextContents(context); BuildEngine.theEngine.Repository.StoreVirtual(this.getContextOutput(), new Fresh(), contents); return new VerbSyncWorker(workingDirectory, new Fresh()); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/VerbRunner.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; /// /// Infrastructure for performing VerbWorker work, possibly asynchronously. /// Conceptually, this is the part of the scheduler that runs verbs. /// /// /// There is only one instance of this class in the system. /// internal class VerbRunner { /// /// Whether or not to run in a special debugging mode where everything /// is run on a single thread (including any 'async' work). /// /// /// Without this, JonH reported problems: "Breaking and examining /// variables on a second thread seems to send VS into fits". /// private const bool DebugOneThread = false; /// /// A sorter of verbs (special case for DafnyVerifyOneVerb only?). /// private VerbToposorter verbToposorter; /// /// Event used to signal the completion of some (possibly asynchronous) /// work. /// private ManualResetEvent completionEvent; /// /// Lock protecting the runnableVerbs and startedVerbs collections. /// private ReaderWriterLock verbStateLock; /// /// Verbs that have been submitted, but have not yet started to run. /// private HashSet runnableVerbs; /// /// Verbs that have started to run (and may or may not have /// completed; once added we never remove them from this collection). /// private HashSet startedVerbs; /// /// Degree of asynchronicity to allow (i.e. number of async threads). /// private int jobParallelism; /// /// Lock protecting the taskCompletions list. /// private ReaderWriterLock taskCompletionsLock; /// /// Tasks that have completed running, but not yet processed. /// private List taskCompletions; /// /// Number of currently running tasks. /// private int runningTasks; /// /// Initializes a new instance of the VerbRunner class. /// /// The verb sorter to use. /// Degree of parallelism to allow. public VerbRunner(VerbToposorter verbToposorter, int jobParallelism) { this.verbToposorter = verbToposorter; this.jobParallelism = jobParallelism; this.completionEvent = new ManualResetEvent(true); this.verbStateLock = new ReaderWriterLock(); this.runnableVerbs = new HashSet(); this.startedVerbs = new HashSet(); this.taskCompletionsLock = new ReaderWriterLock(); this.taskCompletions = new List(); this.runningTasks = 0; } /// /// Submits a verb for execution. /// /// The verb to submit. public void submitVerb(IVerb verb) { this.verbStateLock.AcquireWriterLock(Timeout.Infinite); // If lock contention were an issue, we could accumulate these // on a thread-local collection, then batch them into runnableVerbs // during the lock inside scheduleAndWait. if (!this.startedVerbs.Contains(verb)) { this.runnableVerbs.Add(verb); } this.verbStateLock.ReleaseLock(); } /// /// Called by the scheduler to run the verbs which can be run. /// /// /// The scheduler calling us (for debugging). /// /// A list of tasks (verb runs) that have completed. public List scheduleAndWait(Scheduler dbgScheduler) { while (true) { List taskCompletionBatch; // Loop until something gets done. while (true) { this.dbgUpdateProgress(dbgScheduler); this.taskCompletionsLock.AcquireWriterLock(Timeout.Infinite); taskCompletionBatch = this.taskCompletions; this.taskCompletions = new List(); this.completionEvent.Reset(); this.taskCompletionsLock.ReleaseLock(); bool canProcessCompletedTask = taskCompletionBatch.Count() > 0; bool canStartNewTask = (this.runnableVerbs.Count() > 0) && (this.jobParallelism > this.runningTasks); if (!(canProcessCompletedTask || canStartNewTask)) { // Nothing will change until a running task finishes. Snooze. if (this.runningTasks == 0) { dbgScheduler.dbgDumpWaitIndex(); Util.Assert(false); } this.completionEvent.WaitOne(); continue; } break; } int numCompletedTasks = taskCompletionBatch.Count(); Say(string.Format("marking {0} tasks completing; runningTasks now {1}", numCompletedTasks, this.runningTasks)); this.runningTasks -= numCompletedTasks; int idleTasks = this.jobParallelism - this.runningTasks; if (idleTasks > 0) { this.verbStateLock.AcquireWriterLock(Timeout.Infinite); List runnableVerbsBatch = new List(this.runnableVerbs); Say("AsyncRunner toposorting " + runnableVerbsBatch.Count() + " verbs"); runnableVerbsBatch.Sort(this.verbToposorter); ////Logger.WriteLine(string.Format("verbToposorter({0}) yields:", runnableVerbsBatch.Count)); ////foreach (IVerb verb in runnableVerbsBatch) ////{ //// Logger.WriteLine(" " + verb.ToString() + " @ "+ this.verbToposorter.getDepth(verb)); ////} for (int i = 0; i < idleTasks && i < runnableVerbsBatch.Count(); i++) { IVerb verb = runnableVerbsBatch[i]; this.startTask(verb); this.runnableVerbs.Remove(verb); this.startedVerbs.Add(verb); } this.verbStateLock.ReleaseLock(); } if (taskCompletionBatch.Count() > 0 || this.runningTasks == 0) { // Something actually got done, so the caller could meaningfully schedule more work. return taskCompletionBatch; } } } /// /// Writes debugging output to the logger. /// /// The message to write. private static void Say(string msg) { if (Scheduler.Debug) { #pragma warning disable 162 Logger.WriteLine("[async] " + msg); #pragma warning restore 162 } } /// /// Reports current progress to the scheduler. /// /// The scheduler. private void dbgUpdateProgress(Scheduler dbgScheduler) { dbgScheduler.dbgUpdateProgress(this.runnableVerbs.Count(), this.runningTasks); } /// /// Starts a task (i.e. runs a verb). /// /// The verb to run. private void startTask(IVerb verb) { this.runningTasks += 1; // We execute the verb in a private build tree (WorkingDirectory). WorkingDirectory workingDirectory = new WorkingDirectory(BuildEngine.theEngine.getIronRoot()); // Note that we call PrepareForVerb prior to the verb's getWorker // method as the getWorker call might do some of the work directly. // REVIEW: We might want to change our contract with getWorker to // disallow it from touching files in the working directory (so we // don't have to prep the working dir in the remote execution case). this.PrepareForVerb(workingDirectory, verb); IVerbWorker worker = verb.getWorker(workingDirectory); if (worker.IsSync() == VerbWorkerType.Sync) { this.completeTask(verb, worker); } else { AsyncVerbTask task = new AsyncVerbTask(this, worker, verb); Say(string.Format("scheduling {0}", verb)); #pragma warning disable 162 if (DebugOneThread) { task.Run(); } else { new Thread(new ThreadStart(task.Run)).Start(); } #pragma warning restore 162 } } /// /// Prepares the working directory tree for a verb's execution. /// /// The verb whose execution we're preparing for. private void PrepareForVerb(WorkingDirectory workingDirectory, IVerb verb) { // Debugging aide: write out the abstract id for this verb. File.WriteAllText(workingDirectory.PathTo("Debug.txt"), verb.getAbstractIdentifier().ToString()); Repository repository = BuildEngine.theEngine.Repository; // Copy all verb inputs from the item cache to here. DependencyDisposition ddisp; foreach (BuildObject input in verb.getDependencies(out ddisp)) { if (!(input is VirtualBuildObject)) { workingDirectory.CreateDirectoryFor(input); // REVIEW: No longer needed? repository.Fetch(workingDirectory, input); } } // Ensures that the directory tree for each of the verb's outputs exists. foreach (BuildObject output in verb.getOutputs()) { workingDirectory.CreateDirectoryFor(output); } } /// /// Completes a task (verb run). /// /// /// Note that for Async verb workers, this method runs on a separate thread. /// /// The verb which was run. /// The verb's worker. private void completeTask(IVerb verb, IVerbWorker worker) { this.taskCompletionsLock.AcquireWriterLock(Timeout.Infinite); Disposition disp = worker.Complete(); TaskCompletion tc = new TaskCompletion(worker.GetWorkingDirectory(), verb, disp); this.taskCompletions.Add(tc); this.completionEvent.Set(); this.taskCompletionsLock.ReleaseWriterLock(); } /// /// Represents a completed task. /// Ties a Disposition to the Verb instance which created it. /// /// /// REVIEW: Keep the entire worker instead of just the working dir? /// Might want to run worker.Complete on main thread after pulling this /// off the task completions list instead of on separate thread prior to /// putting it on the task completions list. /// public class TaskCompletion { /// /// The directory the verb executed in. /// public WorkingDirectory workingDirectory; /// /// The verb whose completion this instance describes. /// public IVerb verb; /// /// The disposition of this task. /// public Disposition disposition; /// /// Initializes a new instance of the TaskCompletion class. /// /// /// The private working directory the task executed in. /// /// /// The verb whose completion this instance describes. /// /// /// The disposition of this task. /// public TaskCompletion(WorkingDirectory workingDirectory, IVerb verb, Disposition disposition) { this.workingDirectory = workingDirectory; this.verb = verb; this.disposition = disposition; } } /// /// Representation of an asynchronous task. /// /// /// REVIEW: Do we need this class? It is 1:1 with the worker. /// private class AsyncVerbTask { /// /// The verb-running part of the scheduler. /// private VerbRunner runner; /// /// The worker of this verb task. /// private IVerbWorker worker; /// /// The verb associated with this task/worker. /// /// /// Don't call any methods on this guy while on async thread! /// It's just here to carry back to the TaskCompletion on the main thread. /// private IVerb verb; /// /// Initializes a new instance of the AsyncVerbTask class. /// /// /// The verb running part of the scheduler. /// /// /// The worker of this verb task. /// /// /// The verb associated with this task/worker. /// public AsyncVerbTask(VerbRunner runner, IVerbWorker worker, IVerb verb) { this.runner = runner; this.worker = worker; this.verb = verb; } /// /// Runs the task. /// /// /// Note that this method runs on a separate thread. /// Only make thread-safe calls from here. /// public void Run() { Say(string.Format("launching {0}", this.verb)); Logger.WriteLine(string.Format("{0} launched", this.verb)); this.worker.RunAsync(); this.runner.completeTask(this.verb, this.worker); Say(string.Format("completed {0}", this.verb)); } } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/VerbSyncWorker.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { /// /// Representation of a synchronous verb worker. /// internal class VerbSyncWorker : IVerbWorker { /// /// The private working directory for this worker to work in. /// private WorkingDirectory workingDirectory; /// /// The disposition of this activity. /// private Disposition result; /// /// Initializes a new instance of the VerbSyncWorker class. /// /// /// The private working directory for this worker to work in. /// /// The Disposition to return on complete. public VerbSyncWorker(WorkingDirectory workingDirectory, Disposition result) { this.workingDirectory = workingDirectory; this.result = result; } /// /// Indicates whether this work needs to be scheduled asynchronously. /// Since this is the synchronous implementation, always returns Sync. /// /// Always returns Sync. public virtual VerbWorkerType IsSync() { return VerbWorkerType.Sync; } /// /// Gets the private working directory this verb executes in. /// /// The directory this verb executes in. public WorkingDirectory GetWorkingDirectory() { return this.workingDirectory; } /// /// Performs the asynchronous work for this worker, which for a /// synchronous worker like this one, should not exist. Therefore, /// this implementation just asserts. /// /// /// Shouldn't ever be called, since our IsSync returns Sync. /// public void RunAsync() { Util.Assert(false); } /// /// Performs the work of this synchronous worker (or whatever isn't /// done in the constructor at least). /// Returns the ultimate disposition of the activity. /// /// /// Thou shalt not return Stale. /// /// The disposition of this worker's work. public virtual Disposition Complete() { return this.result; } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/VerbToposorter.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; /// /// Mechanism for ordering verbs topologically. /// Used by the Scheduler and related components. /// internal class VerbToposorter : IComparer { /// /// Mapping of verbs to their verb depth. /// private Dictionary verbDepth; /// /// Initializes a new instance of the /// class. /// public VerbToposorter() { this.verbDepth = new Dictionary(); } /// /// Compares two verbs topologically. /// /// /// This is the IComparer.Compare method. /// /// One verb to compare. /// The other verb to compare. /// /// A signed integer that indicates the relative values of x and y, /// see IComparer.Compare interface. /// public int Compare(IVerb x, IVerb y) { int rc; int c0 = this.GetDepth(x) - this.GetDepth(y); if (c0 != 0) { rc = c0; } else { // Break depth ties alphabetically. rc = x.ToString().CompareTo(y.ToString()); } ////Logger.WriteLine(String.Format("Compare({0},{1})=={2}", x, y, rc)); return rc; } /// /// Gets the "depth" (dependency order) of a verb. /// /// The verb in question. /// The verb depth. private int GetDepth(IVerb verb) { if (this.verbDepth.ContainsKey(verb)) { return this.verbDepth[verb]; } int depth; DafnyVerifyOneVerb vone = verb as DafnyVerifyOneVerb; if (vone != null) { int deepestParent = -1; foreach (SourcePath sourcePath in vone.getDirectIncludes()) { IVerb parent = new DafnyVerifyOneVerb(sourcePath); int parentDepth = this.GetDepth(parent); deepestParent = Math.Max(deepestParent, parentDepth); } depth = deepestParent + 1; } else { // Right now we only care about ordering the DafnyVerifyOneVerbs // wrt one another. Other verbs will be constrained by build // dependency anyway. depth = 0; } this.verbDepth[verb] = depth; return depth; } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/VerificationMessage.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Xml; internal class VerificationMessage { public const string _xml_tag = "VerificationMessage"; private const string _xml_message_sourcefile_attr = "SourceFile"; private string sourceLabel; private string message; public VerificationMessage(string sourceLabel, string message) { this.sourceLabel = sourceLabel; this.message = message; } public string SourceLabel { get { return this.sourceLabel; } } public string Message { get { return this.message; } } public static VerificationMessage ReadXml(XmlReader xr) { Util.Assert(xr.Name.Equals(VerificationMessage._xml_tag)); string relSourcePath = xr.GetAttribute(VerificationMessage._xml_message_sourcefile_attr); string message = xr.ReadElementContentAsString(); return new VerificationMessage(relSourcePath, message); } public void WriteXml(XmlWriter xw) { xw.WriteStartElement(VerificationMessage._xml_tag); xw.WriteAttributeString(VerificationMessage._xml_message_sourcefile_attr, this.sourceLabel); xw.WriteString(this.message); xw.WriteEndElement(); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/VerificationObligationList.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; internal class VerificationObligationList { public const string VOL_EXTN = ".vol"; // VOL = Verification Object List private readonly List verificationObligations; private bool complete; public VerificationObligationList() { this.verificationObligations = new List(); } public VerificationObligationList(IEnumerable data) { this.verificationObligations = new List(data); this.complete = true; } public static VerificationObligationList fetch(BuildObject obj) { VerificationObligationList vol = new VerificationObligationList(); using (TextReader sr = BuildEngine.theEngine.Repository.OpenRead(obj)) { string line; while ((line = sr.ReadLine()) != null) { Util.Assert(!line.StartsWith(BuildEngine.theEngine.getSrcRoot())); // unimplemented Util.Assert(!line.StartsWith(BuildEngine.theEngine.getVirtualRoot())); // nonsense vol.Add(new BuildObject(line)); } } vol.complete = true; return vol; } public void Add(BuildObject obj) { Util.Assert(!this.complete); this.verificationObligations.Add(obj); } public IEnumerable getVerificationObligations() { Util.Assert(this.complete); return this.verificationObligations; } public void store(WorkingDirectory workingDirectory, BuildObject location) { this.complete = true; string[] lines = this.verificationObligations.Select(vo => vo.getRelativePath()).ToArray(); File.WriteAllLines(workingDirectory.PathTo(location), lines); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/VerificationRequest.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; internal class VerificationRequest { public VerifyMode verifyMode; public List selectiveVerifyModuleNames; public VerificationRequest() { this.verifyMode = VerifyMode.Verify; this.selectiveVerifyModuleNames = new List(); } public enum VerifyMode { Verify, NoSymDiff, SelectiveVerify, NoVerify } public enum SymDiffMode { UseSymDiff, NoSymDiff } public bool isComplete() { return this.verifyMode == VerifyMode.Verify; } public override string ToString() { if (this.verifyMode == VerifyMode.SelectiveVerify) { return this.verifyMode.ToString() + "(" + string.Join(",", this.selectiveVerifyModuleNames) + ")"; } else { return this.verifyMode.ToString(); } } public SymDiffMode getSymDiffMode() { return this.verifyMode == VerifyMode.Verify ? SymDiffMode.UseSymDiff : SymDiffMode.NoSymDiff; } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/VerificationResult.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; using System.Text.RegularExpressions; using System.Xml; internal class VerificationResult { public const string _VERIFICATION_RESULT_PLACEHOLDER = "_VERIFICATION_RESULT_PLACEHOLDER"; public const string _xml_tag = "VerificationResult"; private const string _xml_sourcePath_attr = "SourcePath"; private const string _xml_outcome_attr = "Outcome"; private const string _xml_parseFailures_attr = "ParseFailures"; private const string _xml_verificationFailures_attr = "VerificationFailures"; private const string _xml_timeouts_attr = "Timeouts"; private const string _xml_cputime_attr = "CPUTime"; private const string _xml_message_tag = "Message"; private const string _xml_message_sourcefile_attr = "SourceFile"; private const string PASS = "pass"; private const string FAIL = "fail"; private static Regex whitespace = new Regex("^\\s*$"); private string _sourceLabel; private bool _pass; private double _cpuTime; private int _parseFailures; private int _verificationFailures; private int _timeouts; private List messages; private Presentation _presentation; public VerificationResult(string sourceLabel, double cpuTime, string stdout, string stderr, IVerificationResultParser parser) { this._sourceLabel = sourceLabel; this._cpuTime = cpuTime; this.messages = new List(); // REVIEW: Switch from whitespace Regex to string.IsNullOrWhiteSpace()? if (!whitespace.Match(stdout).Success) { this.messages.Add(new VerificationMessage(sourceLabel, stdout)); } if (!whitespace.Match(stderr).Success) { this.messages.Add(new VerificationMessage(sourceLabel, stderr)); } this._parseFailures = 0; this._verificationFailures = 0; this._timeouts = 0; parser.parseOutput(stdout + stderr, out this._parseFailures, out this._verificationFailures, out this._timeouts); this._pass = this._parseFailures == 0 && this._verificationFailures == 0 && this._timeouts == 0; } public VerificationResult(string sourceLabel, bool pass, double cpuTime, int parseFailures, int verificationFailures, int timeouts, IEnumerable messages) { this._sourceLabel = sourceLabel; this._pass = pass; this._cpuTime = cpuTime; this._parseFailures = parseFailures; this._verificationFailures = verificationFailures; this._timeouts = timeouts; this.messages = new List(messages); } private VerificationResult() { } public string sourceLabel { get { return this._sourceLabel; } } public bool pass { get { return this._pass; } } public double cpuTime { get { return this._cpuTime; } } public int parseFailures { get { return this._parseFailures; } } public int verificationFailures { get { return this._verificationFailures; } } public int timeouts { get { return this._timeouts; } } public Presentation presentation { get { return this._presentation; } } public static VerificationResult fromXmlFile(BuildObject obj) { using (TextReader ins = BuildEngine.theEngine.Repository.OpenRead(obj)) { XmlReader xr = XmlReader.Create(ins); while (xr.Read()) { if (xr.NodeType == XmlNodeType.Element) { break; } } return readXml(xr); } } public static VerificationResult readXml(XmlReader xr) { Util.Assert(xr.Name.Equals(_xml_tag)); VerificationResult rc = new VerificationResult(); rc._sourceLabel = xr.GetAttribute(_xml_sourcePath_attr); string outcome = xr.GetAttribute(_xml_outcome_attr); if (outcome.Equals(PASS)) { rc._pass = true; } else if (outcome.Equals(FAIL)) { rc._pass = false; } else { throw new Exception("Invalid outcome value " + outcome); } rc._cpuTime = Double.Parse(xr.GetAttribute(_xml_cputime_attr)); rc._parseFailures = Int32.Parse(xr.GetAttribute(_xml_parseFailures_attr)); rc._verificationFailures = Int32.Parse(xr.GetAttribute(_xml_verificationFailures_attr)); rc._timeouts = Int32.Parse(xr.GetAttribute(_xml_timeouts_attr)); rc.messages = new List(); while (xr.Read()) { if (xr.NodeType == XmlNodeType.EndElement) { Util.Assert(xr.Name.Equals(_xml_tag)); break; } else if (xr.NodeType == XmlNodeType.Element) { if (xr.Name.Equals(VerificationMessage._xml_tag)) { rc.messages.Add(VerificationMessage.ReadXml(xr)); } else if (xr.Name.Equals(Presentation._xml_tag)) { rc._presentation = Presentation.fromXml(xr.ReadSubtree()); } else { throw new Exception("Unknown xml tag " + xr.Name); } } } return rc; } public IEnumerable getMessages() { return this.messages; } public void addXmlFiller(Presentation presentation) { this._presentation = presentation; } public void toXmlFile(string path) { File.Delete(path); using (FileStream s = File.OpenWrite(path)) { XmlWriterSettings settings = new XmlWriterSettings(); settings.Indent = true; XmlWriter xw = XmlWriter.Create(s, settings); xw.WriteStartDocument(); this.writeXml(xw); xw.Close(); } } public void writeXml(XmlWriter xw) { xw.WriteStartElement(_xml_tag); xw.WriteAttributeString(_xml_sourcePath_attr, this._sourceLabel); xw.WriteAttributeString(_xml_outcome_attr, this._pass ? PASS : FAIL); xw.WriteAttributeString(_xml_cputime_attr, this._cpuTime.ToString()); xw.WriteAttributeString(_xml_parseFailures_attr, this._parseFailures.ToString()); xw.WriteAttributeString(_xml_verificationFailures_attr, this._verificationFailures.ToString()); xw.WriteAttributeString(_xml_timeouts_attr, this._timeouts.ToString()); foreach (VerificationMessage message in this.messages) { message.WriteXml(xw); } if (this._presentation != null) { this._presentation.fillXml(xw); // TODO we don't know yet how to parse this stuff back in. } xw.WriteEndElement(); } public void addBasicPresentation() { PresentationBuilder pr = new PresentationBuilder(); int any_failures = this.parseFailures + this.verificationFailures + this.timeouts; string overall_status = any_failures > 0 ? "Fail" : "Success"; pr.pre(_VERIFICATION_RESULT_PLACEHOLDER+"\n"); pr.spacer(); pr.startHeader(); pr.color(any_failures == 0 ? Presentation.GREEN : Presentation.RED, "Overall status: " + overall_status); pr.endHeader(); pr.line( string.Format( "{0} parse failures, {1} verification failures, {2} timeouts", this._parseFailures, this._verificationFailures, this._timeouts)); pr.spacer(); foreach (VerificationMessage message in this.messages) { pr.pre(message.Message); } Presentation pres = pr.fix(); this.addXmlFiller(pres); } internal bool wasOnlyTimeouts() { return this.verificationFailures == 0 && this.timeouts > 0; } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/VerificationResultBoogieParser.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Text.RegularExpressions; internal class VerificationResultBoogieParser : IVerificationResultParser { private static Regex dispositionTimeoutsRegex = new Regex("Boogie program verifier finished with (\\d*) verified, (\\d*) errors*, (\\d) time outs*"); private static Regex dispositionNoTimeoutsRegex = new Regex("Boogie program verifier finished with (\\d*) verified, (\\d*) errors*"); private static Regex dispositionParseErrorRegex = new Regex("Error opening file"); private static Regex dispositionParseError2Regex = new Regex("(\\d*) parse errors detected in"); private static Regex dispositionParseError3Regex = new Regex("(\\d*) type checking errors detected in"); private static Regex dispositionParseError4Regex = new Regex("(\\d*) name resolution errors detected in"); private static Regex dispositionProverDiedRegex = new Regex("Prover error: Prover died"); public void parseOutput(string output, out int parseFailures, out int verificationFailures, out int timeouts) { parseFailures = 0; verificationFailures = 0; timeouts = 0; Match match = dispositionTimeoutsRegex.Match(output); if (match.Success) { ////int succeeding_methods = Int32.Parse(m.Groups[1].ToString()); verificationFailures = Int32.Parse(match.Groups[2].ToString()); timeouts = Int32.Parse(match.Groups[3].ToString()); return; } match = dispositionParseErrorRegex.Match(output); if (match.Success) { parseFailures = 1; return; } match = dispositionParseError2Regex.Match(output); if (match.Success) { parseFailures = Int32.Parse(match.Groups[1].ToString()); return; } match = dispositionParseError3Regex.Match(output); if (match.Success) { parseFailures = Int32.Parse(match.Groups[1].ToString()); return; } match = dispositionParseError4Regex.Match(output); if (match.Success) { parseFailures = Int32.Parse(match.Groups[1].ToString()); return; } match = dispositionProverDiedRegex.Match(output); if (match.Success) { parseFailures = 1; return; } match = dispositionNoTimeoutsRegex.Match(output); if (match.Success) { ////int succeeding_methods = Int32.Parse(m.Groups[1].ToString()); verificationFailures = Int32.Parse(match.Groups[2].ToString()); return; } parseFailures = 1; ////throw new Exception("Unable to parse Dafny output"); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/VerificationResultDafnyParser.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Text.RegularExpressions; internal class VerificationResultDafnyParser : IVerificationResultParser { private static Regex dispositionTimeoutsRegex = new Regex("Dafny program verifier finished with (\\d*) verified, (\\d*) errors*, (\\d) time outs*"); private static Regex dispositionNoTimeoutsRegex = new Regex("Dafny program verifier finished with (\\d*) verified, (\\d*) errors*"); private static Regex dispositionParseErrorRegex = new Regex("Error opening file"); private static Regex dispositionParseError2Regex = new Regex("(\\d*) parse errors detected in"); private static Regex dispositionParseError3Regex = new Regex("(\\d*) resolution/type errors detected in"); private static Regex dispositionProverDiedRegex = new Regex("Prover error: Prover died"); public void parseOutput(string output, out int parseFailures, out int verificationFailures, out int timeouts) { parseFailures = 0; verificationFailures = 0; timeouts = 0; Match match = dispositionTimeoutsRegex.Match(output); if (match.Success) { ////int succeeding_methods = Int32.Parse(m.Groups[1].ToString()); verificationFailures = Int32.Parse(match.Groups[2].ToString()); timeouts = Int32.Parse(match.Groups[3].ToString()); return; } match = dispositionParseErrorRegex.Match(output); if (match.Success) { parseFailures = 1; return; } match = dispositionParseError2Regex.Match(output); if (match.Success) { parseFailures = Int32.Parse(match.Groups[1].ToString()); return; } match = dispositionParseError3Regex.Match(output); if (match.Success) { parseFailures = Int32.Parse(match.Groups[1].ToString()); return; } match = dispositionProverDiedRegex.Match(output); if (match.Success) { parseFailures = 1; return; } match = dispositionNoTimeoutsRegex.Match(output); if (match.Success) { ////int succeeding_methods = Int32.Parse(m.Groups[1].ToString()); verificationFailures = Int32.Parse(match.Groups[2].ToString()); return; } parseFailures = 1; Logger.WriteLine("NuBuild WARNING: unexpected Dafny error message; lumping into parse errors."); ////throw new Exception("Unable to parse Dafny output"); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/VerificationResultSummaryVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; internal class VerificationResultSummaryVerb : VerificationResultVerb ////, IObligationsProducer { private const string SUMMARY_EXTN = ".summary"; private const int version = 4; private BuildObject outputObject; private IObligationsProducer producer; private IEnumerable verificationResults; private AbstractId abstractId; public VerificationResultSummaryVerb(IObligationsProducer producer) { this.producer = producer; BuildObject id = producer.getObligationSet(); ////producer.getIdentifier(); this.outputObject = id.makeOutputObject(id.getExtension() + SUMMARY_EXTN); this.abstractId = new AbstractId(this.GetType().Name, version, id.ToString()); this.verificationResults = null; } public override AbstractId getAbstractIdentifier() { return this.abstractId; } public override IEnumerable getDependencies(out DependencyDisposition ddisp) { BuildObject obligations = this.producer.getObligationSet(); HashSet deps = new HashSet(); deps.Add(obligations); try { VerificationObligationList vol = VerificationObligationList.fetch(obligations); this.verificationResults = vol.getVerificationObligations(); deps.UnionWith(this.verificationResults); ddisp = DependencyDisposition.Complete; } catch (ObjectNotReadyException) { ddisp = DependencyDisposition.Incomplete; } catch (ObjectFailedException) { ddisp = DependencyDisposition.Failed; } return deps; } public override IEnumerable getVerbs() { IEnumerable verbs = new IVerb[] { this.producer }; verbs = verbs.Union(this.producer.getVerbs()); return verbs; // VerificationResultSummaryVerb depends on objects mentioned by producer, // but the necessary verbs haven't been mentioned. Is it sufficient for // the upstream guy (BoogieAsmVerificationObligationList) to ... hopefully ... // mention them? (Hopefully because he might only be incompletely queried, // since he's not actually dependent on the verbs he's advertising.) // Maybe we should provide a way for his complete() method to push the // verbs into the cache. } public override IEnumerable getOutputs() { return new HashSet() { this.outputObject }; } public override BuildObject getOutputFile() { return this.outputObject; } public BuildObject getObligationSet() { return this.producer.getObligationSet(); } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { // Read and aggregate all the input results. int parseFailures = 0; int verificationFailures = 0; int timeouts = 0; int filesWithParseFailures = 0; int filesWithVerificationFailures = 0; int filesWithTimeouts = 0; int passCount = 0; int failCount = 0; double cpuTime = 0; List failMessages = new List(); List results = new List(); // REVIEW: Why pull out the enumerator this way? IEnumerable verificationResultsEnumerator = this.verificationResults; foreach (BuildObject verificationResult in verificationResultsEnumerator) { VerificationResult vr = VerificationResult.fromXmlFile(verificationResult); results.Add(vr); if (vr == null) { return new VerbSyncWorker( workingDirectory, new Failed("Build system broke: missing VerificationResult for " + verificationResult)); } if (vr.pass) { passCount += 1; } else { failCount += 1; failMessages.AddRange(vr.getMessages()); } parseFailures += vr.parseFailures; verificationFailures += vr.verificationFailures; timeouts += vr.timeouts; filesWithParseFailures += vr.parseFailures > 0 ? 1 : 0; filesWithVerificationFailures += vr.verificationFailures > 0 ? 1 : 0; filesWithTimeouts += vr.timeouts > 0 ? 1 : 0; ////Logger.WriteLine("Synthesizing cpuTime from " + verificationResult); cpuTime += vr.cpuTime; } bool allPass = failCount == 0; PresentationBuilder pr = new PresentationBuilder(); int any_failures = parseFailures + verificationFailures + timeouts; string overall_status = any_failures > 0 ? "Fail" : "Success"; pr.pre(VerificationResult._VERIFICATION_RESULT_PLACEHOLDER+"\n"); pr.spacer(); pr.startHeader(); pr.color(this.colorByFailureCount(any_failures), "Overall status: " + overall_status); pr.endHeader(); pr.line("Count of files with failures: " + failCount); pr.startBullet(); pr.color(this.colorByFailureCount(filesWithParseFailures), "Files with parse failures: " + filesWithParseFailures.ToString()); pr.endBullet(); pr.startBullet(); pr.color(this.colorByFailureCount(filesWithVerificationFailures), "Files with verification failures: " + filesWithVerificationFailures.ToString()); pr.endBullet(); pr.startBullet(); pr.color(this.colorByFailureCount(filesWithTimeouts), "Files with timeouts: " + filesWithTimeouts.ToString()); pr.endBullet(); pr.spacer(); pr.header(string.Format("Total processing time: {0:0.0}s {1}", cpuTime, new TimeSpan((long)(cpuTime * 10000000L)))); int top_n = 10; pr.header(string.Format("Slowest {0} verifications:", top_n)); results.Sort(this.ByCpuTimeDecreasing); foreach (VerificationResult slowResult in results.Take(top_n)) { pr.startBullet(); pr.color( this.colorByFailureCount(slowResult.pass ? 0 : 1), string.Format("{0,6:##0.0}s {1}", slowResult.cpuTime, slowResult.sourceLabel)); pr.endBullet(); } foreach (VerificationMessage message in failMessages) { pr.spacer(); pr.header("Failure with " + message.SourceLabel); pr.pre(message.Message); } Presentation pres = pr.fix(); VerificationResult outvr = new VerificationResult("summary", allPass, cpuTime, parseFailures, verificationFailures, timeouts, failMessages); outvr.addXmlFiller(pres); outvr.toXmlFile(workingDirectory.PathTo(this.outputObject)); this.setWasRejectableFailure(!outvr.pass); return new VerbSyncWorker(workingDirectory, new Fresh()); } public override Presentation getRealtimePresentation(Disposition d) { if (d is Failed) { return base.getRealtimePresentation(d); } VerificationResult vr = VerificationResult.fromXmlFile(this.outputObject); PresentationBuilder pr = new PresentationBuilder(); pr.startLine(); pr.color( vr.pass ? Presentation.GREEN : Presentation.RED, string.Format( "{0} {1} {2,1:0.0}s", this.getAbstractIdentifier(), vr.pass ? "Success" : "Fail", vr.cpuTime)); pr.endLine(); if (!vr.pass) { foreach (VerificationMessage msg in vr.getMessages()) { pr.pre(msg.Message); } } return pr.fix(); } public override Presentation getPresentation() { VerificationResult vr = VerificationResult.fromXmlFile(this.outputObject); return vr.presentation; } protected override BuildObject getSource() { return this.producer.getObligationSet(); } private int ByCpuTimeDecreasing(VerificationResult va, VerificationResult vb) { return -(va.cpuTime.CompareTo(vb.cpuTime)); } private string colorByFailureCount(int count) { return count == 0 ? Presentation.GREEN : Presentation.RED; } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/VerificationResultVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; internal abstract class VerificationResultVerb : Verb, IRejectable { public const string VERIFICATION_RESULT_EXTN = ".v"; private bool dbgWasVerificationTimeoutRecorded; private bool wasRejectableFailure; public abstract BuildObject getOutputFile(); public override Presentation getRealtimePresentation(Disposition d) { if (d is Failed) { return base.getRealtimePresentation(d); } VerificationResult vr = VerificationResult.fromXmlFile(this.getOutputFile()); PresentationBuilder pr = new PresentationBuilder(); pr.startLine(); pr.color( vr.pass ? Presentation.GREEN : Presentation.RED, string.Format( "{0} {1} {2,5:0.0}s", ////getSource().getRelativePath(), this.getAbstractIdentifier(), vr.pass ? "Success" : "Fail", vr.cpuTime)); pr.endLine(); if (!vr.pass) { foreach (VerificationMessage msg in vr.getMessages()) { pr.pre(msg.Message); } } return pr.fix(); } public override Presentation getPresentation() { VerificationResult vr = VerificationResult.fromXmlFile(this.getOutputFile()); return vr.presentation; } public bool resultWasRejectableFailure() { Util.Assert(this.dbgWasVerificationTimeoutRecorded); return this.wasRejectableFailure; } protected abstract BuildObject getSource(); protected void setWasRejectableFailure(bool value) { this.dbgWasVerificationTimeoutRecorded = true; this.wasRejectableFailure = value; } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/VirtualBuildObject.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; /// /// Representation of a virtual BuildObject. /// A VirtualBuildObject is never actually stored in the filesystem; /// it is only materialized inside the process. It's used for results /// that are easy to compute, but which still need to be established /// in dependency order. Instances: transitive deps, contexts. /// internal class VirtualBuildObject : BuildObject { /// /// Initializes a new instance of the VirtualBuildObject class. /// /// Virtual path name of the object. public VirtualBuildObject(string inpath) : base(inpath) { Util.Assert(inpath.StartsWith(BuildEngine.theEngine.getVirtualRoot(), StringComparison.OrdinalIgnoreCase)); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/VirtualContents.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; /// /// This class is perfectly named; it contains nothing. /// Serves solely as a base class for other derived classes. /// internal class VirtualContents { } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/WaitIndex.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.Linq; /// /// Used by the Scheduler to track waiting verbs and their dependencies. /// internal class WaitIndex { private Dictionary waitingVerbs; private Dictionary> fwdDeps; public WaitIndex() { this.waitingVerbs = new Dictionary(); this.fwdDeps = new Dictionary>(); } public int Count() { return this.waitingVerbs.Count; } public void dbgDisplayIndex(Scheduler dbgScheduler) { List waitRecords = new List(this.waitingVerbs.Values); for (int i = 0; i < waitRecords.Count(); i++) { WaitRecord wr = waitRecords[i]; List depNums = new List(); List unknownDeps = new List(); List unscheduledDeps = new List(); foreach (BuildObject dep in wr.knownDeps) { IVerb depOnVerb = dbgScheduler.getParent(dep); if (depOnVerb == null) { unknownDeps.Add(dep); } else if (!this.waitingVerbs.ContainsKey(depOnVerb)) { unscheduledDeps.Add( string.Format( "{0} waiting on {1} {2}", dep, depOnVerb, dbgScheduler.dbgGetVerbStatus(depOnVerb))); } else { WaitRecord depWr = this.waitingVerbs[depOnVerb]; depNums.Add(waitRecords.IndexOf(depWr)); } } Logger.WriteLine( string.Format( "{0}. {1} waits on ({2}), {3} unknown, {4} unscheduled", i, wr.verb, string.Join(",", depNums), unknownDeps.Count(), unscheduledDeps.Count())); this.dbgPreview("Unknown", unknownDeps.Select(it => it.ToString()), 3); this.dbgPreview("Unscheduled", unscheduledDeps, 20); } } internal void insert(IVerb verb, IEnumerable knownDeps) { // Insert one fwd pointer for each obj verb is already known to // depend upon. The fact that this verb is waiting implies that // one of these deps is stale here and needs built/fetched. WaitRecord waitRecord = new WaitRecord(verb, knownDeps); foreach (BuildObject dep in knownDeps) { if (!this.fwdDeps.ContainsKey(dep)) { this.fwdDeps.Add(dep, new HashSet()); } this.fwdDeps[dep].Add(waitRecord); } this.waitingVerbs.Add(verb, waitRecord); this.Say("sleeps " + verb); } // Remove any verb with obj in its dependency set. internal IEnumerable awaken(BuildObject obj) { this.Say("awaken " + obj); HashSet wokenRecords; HashSet result = new HashSet(); if (this.fwdDeps.ContainsKey(obj)) { wokenRecords = this.fwdDeps[obj]; this.fwdDeps.Remove(obj); // Remove all the other index pointers for each removed verb. foreach (WaitRecord waitRecord in wokenRecords) { foreach (BuildObject dep in waitRecord.knownDeps) { if (this.fwdDeps.ContainsKey(dep)) { this.fwdDeps[dep].Remove(waitRecord); } } result.Add(waitRecord.verb); this.waitingVerbs.Remove(waitRecord.verb); this.Say(" wakes " + waitRecord.verb); } } else { result = new HashSet(); } return result; } internal bool isWaiting(IVerb verb) { return this.waitingVerbs.ContainsKey(verb); } private void dbgPreview(string s, IEnumerable items, int max) { int i = 0; foreach (string o in items) { Logger.WriteLine( string.Format( " {0} {1}/{2} {3}", s, i, items.Count(), o)); i += 1; if (i == max) { break; } } } private void Say(string msg) { ////Logger.WriteLine("[wtidx] " + msg); } private class WaitRecord { public IVerb verb; public IEnumerable knownDeps; public WaitRecord(IVerb verb, IEnumerable knownDeps) { this.verb = verb; this.knownDeps = knownDeps; } } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/WinLinkerVerb.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; internal class WinLinkerVerb : LinkerVerb { public const string WIN_APP_EXE_EXTN = ".winapp"; private const int version = 6; public WinLinkerVerb(MasmVerb masmVerb, bool isLoader) : base(masmVerb, isLoader) { } public override IVerbWorker getWorker(WorkingDirectory workingDirectory) { // TODO: We shouldn't be using absolute paths to any of these things. // Change this to allow VS and SDKs to be installed anywhere. string linker = @"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin\link.exe"; string vc_lib_dir = @"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\lib"; string sdk_dir = @"C:\Program Files (x86)\Windows Kits\8.1\Lib\winv6.3\um\x86"; string kernel_lib = @"C:\Program Files (x86)\Windows Kits\8.1\Lib\winv6.3\um\x86\kernel32.Lib"; string standalone_support_lib = getStandaloneLib().getRelativePath(); SourcePath zero1 = new SourcePath("tools\\scripts\\zero.obj", SourcePath.SourceType.Tools); SourcePath zero2 = new SourcePath("tools\\scripts\\zero2.obj", SourcePath.SourceType.Tools); // TODO: Fail more gracefully? Or better yet, move these into iron/tools. if (!Directory.Exists(vc_lib_dir)) { throw new FileNotFoundException("Missing Visual C++ library directory: " + vc_lib_dir); } if (!Directory.Exists(sdk_dir) || !File.Exists(kernel_lib)) { throw new FileNotFoundException("Missing Windows SDK libraries: " + sdk_dir + ", " + kernel_lib + @". Try installing the Windows SDK from: \\research\Root\Products\Developers\Windows Driver Kit 8.1"); } // TODO: Unpack/generate these automatically. // TODO: Brian, we're really not going to want to cache these big, empty sources. Or compress? All big (>10MB) files. // are mostly zeros. if (!File.Exists(IronRootDirectory.PathTo(zero1)) || !File.Exists(IronRootDirectory.PathTo(zero2))) { throw new FileNotFoundException("Missing object files of zeroes: " + zero1 + ", " + zero2 + ". Try running: tools\\scripts\\build-standalone-init.sh"); } List args = new List() { "/DEBUG", "/subsystem:console", "/LARGEADDRESSAWARE", "/fixed" }; args.Add(objFile.getRelativePath()); args.Add(zero1.getRelativePath()); args.Add(zero2.getRelativePath()); args.Add(standalone_support_lib); args.Add(@"""" + kernel_lib + @""""); args.Add("\"/libpath:" + vc_lib_dir + '"'); args.Add("\"/libpath:" + sdk_dir + '"'); args.Add("/out:" + outputObject.getRelativePath()); args.Add("/entry:" + this.entryPoint); args.Add("/base:" + this.baseAddr); args.Add("/PDB:" + this.getPdb()); return new ProcessInvokeAsyncWorker( workingDirectory, this, linker, args.ToArray(), ProcessExitCodeHandling.NonzeroIsFailure, getDiagnosticsBase(), allowAbsoluteExe: true, allowAbsoluteArgs: true); } public override Disposition Complete(WorkingDirectory workingDirectory, double cpuTimeSeconds, string stdout, string stderr, Disposition disposition) { // No cleanup to do. return disposition; } // TODO: We should build this! protected static SourcePath getStandaloneLib() { return new SourcePath("tools\\standalone\\Debug\\StandAloneSupport.lib", SourcePath.SourceType.Tools); } protected override IEnumerable getExtraOutputs() { List outputs = new List(); outputs.Add(this.getPdb()); return outputs; } protected override string outputExtension() { return WIN_APP_EXE_EXTN + LinkerVerb.UNTRUSTED_EXE_EXTN; } protected override int getVersion() { return version; } protected override IEnumerable getExtraDependencies() { return new List() { getStandaloneLib() }; } private BuildObject getPdb() { return objFile.makeOutputObject(".pdb"); } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/WorkingDirectory.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Collections.Generic; using System.IO; /// /// A directory tree in the local filesystem for a verb to operate upon. /// Verbs should not access files outside of this directory tree. /// public class WorkingDirectory { /// /// Absolute path to this working directory on the local system. /// private string path; /// /// Initializes a new instance of the WorkingDirectory class. /// /// /// Absolute path to the "iron" directory on the local system. /// public WorkingDirectory(string ironroot) { // REVIEW: Have "nutemp" hard-wired here, or passed in? this.path = Path.Combine(ironroot, "nutemp", Path.GetRandomFileName()); Directory.CreateDirectory(this.path); } /// /// Gets the absolute path to the root of this working directory on the local system. /// public string Root { get { return this.path; } } /// /// Gets the absolute path to the given build object in this working directory. /// /// A build object. /// The absolute path to the build object. public string PathTo(BuildObject obj) { return Path.Combine(this.path, obj.getRelativePath()); } /// /// Gets the absolute path corresponding to the given relative path in this working directory. /// /// Relative path to convert. /// The absolute path corresponding to the given relative path. public string PathTo(string relativePath) { return Path.Combine(this.path, relativePath); } /// /// Creates the directory in the local filesystem that corresponds /// to this instance. /// /// A build object. public void CreateDirectoryFor(BuildObject obj) { Directory.CreateDirectory(Path.Combine(this.path, obj.getDirPath())); } /// /// Gets a collection of the build objects in this directory. /// /// /// REVIEW: Return a collection of BuildObjectValuePointers instead? /// /// A collection of build objects. public IEnumerable GetContents() { List contents = new List(); foreach (string fileName in Directory.EnumerateFiles(this.path)) { contents.Add(new BuildObject(fileName)); } return contents; } } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild/XmlFiller.cs ================================================ //-- // // Copyright (c) Microsoft Corporation. All rights reserved. // //-- namespace NuBuild { using System; using System.Xml; /// /// REVIEW: Does this need to be an interface? /// TODO: Rename to IXmlFiller if we need to keep this. /// internal interface XmlFiller { void fillXml(XmlWriter xml); } } ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuild.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0.31101.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NuBuild", "NuBuild\NuBuild.csproj", "{4D7220C0-3CAA-4659-9F16-A564DB3CCC1B}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ItemCacheTool", "ItemCacheTool\ItemCacheTool.csproj", "{9A231EB8-BDA1-4304-93A1-20457C00D7D9}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{43E97C4F-FD2F-49AD-B29A-DEACC270D91B}" ProjectSection(SolutionItems) = preProject Settings.StyleCop = Settings.StyleCop EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CloudExecutionEngine", "CloudExecutionEngine\CloudExecutionEngine.csproj", "{2668E334-0B79-4023-A621-2D1433CE7C9E}" ProjectSection(ProjectDependencies) = postProject {4F3DE22C-CAE9-408B-AA54-10DCD7E12F09} = {4F3DE22C-CAE9-408B-AA54-10DCD7E12F09} EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CloudQueueTool", "CloudQueueTool\CloudQueueTool.csproj", "{DD7B4AD9-1EB0-47BF-B4C2-5BC1CA85D242}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AzureManager", "AzureManager\AzureManager.csproj", "{8ADB4B14-715D-4CE1-BFD2-E7D65007CE5C}" EndProject Project("{CC5FD16D-436D-48AD-A40C-5A424C6E3E79}") = "NuBuildExecutionService", "NuBuildExecutionService\NuBuildExecutionService.ccproj", "{697EA8B8-1846-4628-AB27-066BEC899EC2}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CloudExecutionWorker", "CloudExecutionWorker\CloudExecutionWorker.csproj", "{4F3DE22C-CAE9-408B-AA54-10DCD7E12F09}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {4D7220C0-3CAA-4659-9F16-A564DB3CCC1B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4D7220C0-3CAA-4659-9F16-A564DB3CCC1B}.Debug|Any CPU.Build.0 = Debug|Any CPU {4D7220C0-3CAA-4659-9F16-A564DB3CCC1B}.Release|Any CPU.ActiveCfg = Release|Any CPU {4D7220C0-3CAA-4659-9F16-A564DB3CCC1B}.Release|Any CPU.Build.0 = Release|Any CPU {9A231EB8-BDA1-4304-93A1-20457C00D7D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9A231EB8-BDA1-4304-93A1-20457C00D7D9}.Debug|Any CPU.Build.0 = Debug|Any CPU {9A231EB8-BDA1-4304-93A1-20457C00D7D9}.Release|Any CPU.ActiveCfg = Release|Any CPU {9A231EB8-BDA1-4304-93A1-20457C00D7D9}.Release|Any CPU.Build.0 = Release|Any CPU {2668E334-0B79-4023-A621-2D1433CE7C9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2668E334-0B79-4023-A621-2D1433CE7C9E}.Debug|Any CPU.Build.0 = Debug|Any CPU {2668E334-0B79-4023-A621-2D1433CE7C9E}.Release|Any CPU.ActiveCfg = Release|Any CPU {2668E334-0B79-4023-A621-2D1433CE7C9E}.Release|Any CPU.Build.0 = Release|Any CPU {DD7B4AD9-1EB0-47BF-B4C2-5BC1CA85D242}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {DD7B4AD9-1EB0-47BF-B4C2-5BC1CA85D242}.Debug|Any CPU.Build.0 = Debug|Any CPU {DD7B4AD9-1EB0-47BF-B4C2-5BC1CA85D242}.Release|Any CPU.ActiveCfg = Release|Any CPU {DD7B4AD9-1EB0-47BF-B4C2-5BC1CA85D242}.Release|Any CPU.Build.0 = Release|Any CPU {8ADB4B14-715D-4CE1-BFD2-E7D65007CE5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {8ADB4B14-715D-4CE1-BFD2-E7D65007CE5C}.Debug|Any CPU.Build.0 = Debug|Any CPU {8ADB4B14-715D-4CE1-BFD2-E7D65007CE5C}.Release|Any CPU.ActiveCfg = Release|Any CPU {8ADB4B14-715D-4CE1-BFD2-E7D65007CE5C}.Release|Any CPU.Build.0 = Release|Any CPU {697EA8B8-1846-4628-AB27-066BEC899EC2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {697EA8B8-1846-4628-AB27-066BEC899EC2}.Debug|Any CPU.Build.0 = Debug|Any CPU {697EA8B8-1846-4628-AB27-066BEC899EC2}.Release|Any CPU.ActiveCfg = Release|Any CPU {697EA8B8-1846-4628-AB27-066BEC899EC2}.Release|Any CPU.Build.0 = Release|Any CPU {4F3DE22C-CAE9-408B-AA54-10DCD7E12F09}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {4F3DE22C-CAE9-408B-AA54-10DCD7E12F09}.Debug|Any CPU.Build.0 = Debug|Any CPU {4F3DE22C-CAE9-408B-AA54-10DCD7E12F09}.Release|Any CPU.ActiveCfg = Release|Any CPU {4F3DE22C-CAE9-408B-AA54-10DCD7E12F09}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuildExecutionService/.gitignore ================================================ *.ccproj.user ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuildExecutionService/CloudExecutionWorkerContent/diagnostics.wadcfg ================================================  ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuildExecutionService/NuBuildExecutionService.ccproj ================================================  Debug AnyCPU 2.5 697ea8b8-1846-4628-ab27-066bec899ec2 Library Properties NuBuildExecutionService NuBuildExecutionService False NuBuildExecutionService True False true full false bin\Debug\ DEBUG;TRACE prompt 4 pdbonly true bin\Release\ TRACE prompt 4 CloudExecutionWorker {4f3de22c-cae9-408b-aa54-10dcd7e12f09} True Worker CloudExecutionWorker True Content 10.0 $(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Windows Azure Tools\2.5\ ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuildExecutionService/ServiceConfiguration.Cloud.cscfg ================================================  ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuildExecutionService/ServiceConfiguration.Local.cscfg ================================================  ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuildExecutionService/ServiceDefinition.csdef ================================================  ================================================ FILE: ironclad-apps/tools/NuBuild2/NuBuildExecutionService/csx/Release/roles/CloudExecutionWorker/base/x64/WaHostBootstrapper.exe.config ================================================  ================================================ FILE: ironclad-apps/tools/NuBuild2/References/Microsoft.Threading.Tasks.xml ================================================ Microsoft.Threading.Tasks Provides extension methods for threading-related types. Cancels the after the specified duration. The CancellationTokenSource. The due time in milliseconds for the source to be canceled. Cancels the after the specified duration. The CancellationTokenSource. The due time for the source to be canceled. Gets an awaiter used to await this . The task to await. An awaiter instance. Gets an awaiter used to await this . Specifies the type of data returned by the task. The task to await. An awaiter instance. Creates and configures an awaitable object for awaiting the specified task. The task to be awaited. true to automatic marshag back to the original call site's current SynchronizationContext or TaskScheduler; otherwise, false. The instance to be awaited. Creates and configures an awaitable object for awaiting the specified task. The task to be awaited. true to automatic marshag back to the original call site's current SynchronizationContext or TaskScheduler; otherwise, false. The instance to be awaited. Event handler for progress reports. Specifies the type of data for the progress report. The sender of the report. The reported value. Provides an IProgress{T} that invokes callbacks for each reported progress value. Specifies the type of the progress report value. Any handler provided to the constructor or event handlers registered with the event are invoked through a instance captured when the instance is constructed. If there is no current SynchronizationContext at the time of construction, the callbacks will be invoked on the ThreadPool. The synchronization context captured upon construction. This will never be null. The handler specified to the constructor. This may be null. A cached delegate used to post invocation to the synchronization context. Initializes the . Initializes the with the specified callback. A handler to invoke for each reported progress value. This handler will be invoked in addition to any delegates registered with the event. The is null (Nothing in Visual Basic). Reports a progress change. The value of the updated progress. Reports a progress change. The value of the updated progress. Invokes the action and event callbacks. The progress value. Raised for each reported progress value. Handlers registered with this event will be invoked on the captured when the instance was constructed. Holds static values for . This avoids one static instance per type T. A default synchronization context that targets the ThreadPool. Throws the exception on the ThreadPool. The exception to propagate. The target context on which to propagate the exception. Null to use the ThreadPool. Copies the exception's stack trace so its stack trace isn't overwritten. The exception to prepare. Provides an awaitable object that allows for configured awaits on . This type is intended for compiler use only. The task being awaited. Initializes the . The awaitable . true to attempt to marshal the continuation back to the original context captured; otherwise, false. Gets an awaiter for this awaitable. The awaiter. Provides an awaiter for a . This type is intended for compiler use only. The task being awaited. Whether to attempt marshaling back to the original context. Initializes the . The to await. true to attempt to marshal the continuation back to the original context captured when BeginAwait is called; otherwise, false. Schedules the continuation onto the associated with this . The action to invoke when the await operation completes. The argument is null (Nothing in Visual Basic). The awaiter was not properly initialized. This method is intended for compiler user rather than use directly in code. Schedules the continuation onto the associated with this . The action to invoke when the await operation completes. The argument is null (Nothing in Visual Basic). The awaiter was not properly initialized. This method is intended for compiler user rather than use directly in code. Ends the await on the completed . The result of the completed . The awaiter was not properly initialized. The task was not yet completed. The task was canceled. The task completed in a Faulted state. Gets whether the task being awaited is completed. This property is intended for compiler user rather than use directly in code. The awaiter was not properly initialized. Provides an awaitable object that allows for configured awaits on . This type is intended for compiler use only. The underlying awaitable on whose logic this awaitable relies. Initializes the . The awaitable . true to attempt to marshal the continuation back to the original context captured; otherwise, false. Gets an awaiter for this awaitable. The awaiter. Provides an awaiter for a . This type is intended for compiler use only. The task being awaited. Whether to attempt marshaling back to the original context. Initializes the . The awaitable . true to attempt to marshal the continuation back to the original context captured; otherwise, false. Schedules the continuation onto the associated with this . The action to invoke when the await operation completes. The argument is null (Nothing in Visual Basic). The awaiter was not properly initialized. This method is intended for compiler user rather than use directly in code. Schedules the continuation onto the associated with this . The action to invoke when the await operation completes. The argument is null (Nothing in Visual Basic). The awaiter was not properly initialized. This method is intended for compiler user rather than use directly in code. Ends the await on the completed . The result of the completed . The awaiter was not properly initialized. The task was not yet completed. The task was canceled. The task completed in a Faulted state. Gets whether the task being awaited is completed. This property is intended for compiler user rather than use directly in code. The awaiter was not properly initialized. Provides an awaiter for awaiting a . This type is intended for compiler use only. The default value to use for continueOnCapturedContext. Error message for GetAwaiter. The task being awaited. Initializes the . The to be awaited. Schedules the continuation onto the associated with this . The action to invoke when the await operation completes. The argument is null (Nothing in Visual Basic). The awaiter was not properly initialized. This method is intended for compiler user rather than use directly in code. Schedules the continuation onto the associated with this . The action to invoke when the await operation completes. The argument is null (Nothing in Visual Basic). The awaiter was not properly initialized. This method is intended for compiler user rather than use directly in code. Ends the await on the completed . The awaiter was not properly initialized. The task was not yet completed. The task was canceled. The task completed in a Faulted state. Fast checks for the end of an await operation to determine whether more needs to be done prior to completing the await. The awaited task. Handles validations on tasks that aren't successfully completed. The awaited task. Throws an exception to handle a task that completed in a state other than RanToCompletion. Schedules the continuation onto the associated with this . The awaited task. The action to invoke when the await operation completes. Whether to capture and marshal back to the current context. The argument is null (Nothing in Visual Basic). The awaiter was not properly initialized. This method is intended for compiler user rather than use directly in code. Invokes the delegate in a try/catch that will propagate the exception asynchronously on the ThreadPool. Copies the exception's stack trace so its stack trace isn't overwritten. The exception to prepare. Gets whether the task being awaited is completed. This property is intended for compiler user rather than use directly in code. The awaiter was not properly initialized. Whether the current thread is appropriate for inlining the await continuation. Provides an awaiter for awaiting a . This type is intended for compiler use only. The task being awaited. Initializes the . The to be awaited. Schedules the continuation onto the associated with this . The action to invoke when the await operation completes. The argument is null (Nothing in Visual Basic). The awaiter was not properly initialized. This method is intended for compiler user rather than use directly in code. Schedules the continuation onto the associated with this . The action to invoke when the await operation completes. The argument is null (Nothing in Visual Basic). The awaiter was not properly initialized. This method is intended for compiler user rather than use directly in code. Ends the await on the completed . The result of the completed . The awaiter was not properly initialized. The task was not yet completed. The task was canceled. The task completed in a Faulted state. Gets whether the task being awaited is completed. This property is intended for compiler user rather than use directly in code. The awaiter was not properly initialized. Provides an awaitable context for switching into a target environment. This type is intended for compiler use only. Gets an awaiter for this . An awaiter for this awaitable. This method is intended for compiler user rather than use directly in code. Provides an awaiter that switches into a target environment. This type is intended for compiler use only. A completed task. Posts the back to the current context. The action to invoke asynchronously. The awaiter was not properly initialized. Posts the back to the current context. The action to invoke asynchronously. The awaiter was not properly initialized. Ends the await operation. Gets whether a yield is not required. This property is intended for compiler user rather than use directly in code. Provides methods for creating and manipulating tasks. Creates a task that runs the specified action. The action to execute asynchronously. A task that represents the completion of the action. The argument is null. Creates a task that runs the specified action. The action to execute. The CancellationToken to use to request cancellation of this task. A task that represents the completion of the action. The argument is null. Creates a task that runs the specified function. The function to execute asynchronously. A task that represents the completion of the action. The argument is null. Creates a task that runs the specified function. The action to execute. The CancellationToken to use to cancel the task. A task that represents the completion of the action. The argument is null. Creates a task that runs the specified function. The action to execute asynchronously. A task that represents the completion of the action. The argument is null. Creates a task that runs the specified function. The function to execute. The CancellationToken to use to request cancellation of this task. A task that represents the completion of the function. The argument is null. Creates a task that runs the specified function. The function to execute asynchronously. A task that represents the completion of the action. The argument is null. Creates a task that runs the specified function. The action to execute. The CancellationToken to use to cancel the task. A task that represents the completion of the action. The argument is null. Starts a Task that will complete after the specified due time. The delay in milliseconds before the returned task completes. The timed Task. The argument must be non-negative or -1 and less than or equal to Int32.MaxValue. Starts a Task that will complete after the specified due time. The delay before the returned task completes. The timed Task. The argument must be non-negative or -1 and less than or equal to Int32.MaxValue. Starts a Task that will complete after the specified due time. The delay before the returned task completes. A CancellationToken that may be used to cancel the task before the due time occurs. The timed Task. The argument must be non-negative or -1 and less than or equal to Int32.MaxValue. Starts a Task that will complete after the specified due time. The delay in milliseconds before the returned task completes. A CancellationToken that may be used to cancel the task before the due time occurs. The timed Task. The argument must be non-negative or -1 and less than or equal to Int32.MaxValue. An already completed task. Creates a Task that will complete only when all of the provided collection of Tasks has completed. The Tasks to monitor for completion. A Task that represents the completion of all of the provided tasks. If any of the provided Tasks faults, the returned Task will also fault, and its Exception will contain information about all of the faulted tasks. If no Tasks fault but one or more Tasks is canceled, the returned Task will also be canceled. The argument is null. The argument contains a null reference. Creates a Task that will complete only when all of the provided collection of Tasks has completed. The Tasks to monitor for completion. A Task that represents the completion of all of the provided tasks. If any of the provided Tasks faults, the returned Task will also fault, and its Exception will contain information about all of the faulted tasks. If no Tasks fault but one or more Tasks is canceled, the returned Task will also be canceled. The argument is null. The argument contains a null reference. Creates a Task that will complete only when all of the provided collection of Tasks has completed. The Tasks to monitor for completion. A Task that represents the completion of all of the provided tasks. If any of the provided Tasks faults, the returned Task will also fault, and its Exception will contain information about all of the faulted tasks. If no Tasks fault but one or more Tasks is canceled, the returned Task will also be canceled. The argument is null. The argument contains a null reference. Creates a Task that will complete only when all of the provided collection of Tasks has completed. The Tasks to monitor for completion. A Task that represents the completion of all of the provided tasks. If any of the provided Tasks faults, the returned Task will also fault, and its Exception will contain information about all of the faulted tasks. If no Tasks fault but one or more Tasks is canceled, the returned Task will also be canceled. The argument is null. The argument contains a null reference. Creates a Task that will complete only when all of the provided collection of Tasks has completed. The Tasks to monitor for completion. A callback invoked when all of the tasks complete successfully in the RanToCompletion state. This callback is responsible for storing the results into the TaskCompletionSource. A Task that represents the completion of all of the provided tasks. The argument is null. The argument contains a null reference. Creates a Task that will complete when any of the tasks in the provided collection completes. The Tasks to be monitored. A Task that represents the completion of any of the provided Tasks. The completed Task is this Task's result. Any Tasks that fault will need to have their exceptions observed elsewhere. The argument is null. The argument contains a null reference. Creates a Task that will complete when any of the tasks in the provided collection completes. The Tasks to be monitored. A Task that represents the completion of any of the provided Tasks. The completed Task is this Task's result. Any Tasks that fault will need to have their exceptions observed elsewhere. The argument is null. The argument contains a null reference. Creates a Task that will complete when any of the tasks in the provided collection completes. The Tasks to be monitored. A Task that represents the completion of any of the provided Tasks. The completed Task is this Task's result. Any Tasks that fault will need to have their exceptions observed elsewhere. The argument is null. The argument contains a null reference. Creates a Task that will complete when any of the tasks in the provided collection completes. The Tasks to be monitored. A Task that represents the completion of any of the provided Tasks. The completed Task is this Task's result. Any Tasks that fault will need to have their exceptions observed elsewhere. The argument is null. The argument contains a null reference. Creates an already completed from the specified result. The result from which to create the completed task. The completed task. Creates an awaitable that asynchronously yields back to the current context when awaited. A context that, when awaited, will asynchronously transition back into the current context. If SynchronizationContext.Current is non-null, that is treated as the current context. Otherwise, TaskScheduler.Current is treated as the current context. Adds the target exception to the list, initializing the list if it's null. The list to which to add the exception and initialize if the list is null. The exception to add, and unwrap if it's an aggregate. Returns a canceled task. The cancellation token. The canceled task. Returns a canceled task. Specifies the type of the result. The cancellation token. The canceled task. Completes the Task if the user state matches the TaskCompletionSource. Specifies the type of data returned by the Task. The TaskCompletionSource. The completion event arguments. Whether we require the tcs to match the e.UserState. A function that gets the result with which to complete the task. An action used to unregister work when the operaiton completes. ================================================ FILE: ironclad-apps/tools/NuBuild2/References/Microsoft.WindowsAzure.Common.NetFramework.xml ================================================ Microsoft.WindowsAzure.Common.NetFramework Credentials using a management certificate to authorize requests. Initializes a new instance of the CertificateCloudCredentials class. The Subscription ID. The management certificate. Attempt to create certificate credentials from a collection of settings. The settings to use. CertificateCloudCredentials is created, null otherwise. Initialize a ServiceClient instance to process credentials. Type of ServiceClient. The ServiceClient. This will add a certificate to the shared root WebRequestHandler in the ServiceClient's HttpClient handler pipeline. Apply the credentials to the HTTP request. The HTTP request. Cancellation token. Task that will complete when processing has completed. Gets subscription ID which uniquely identifies Windows Azure subscription. The subscription ID forms part of the URI for every call that you make to the Service Management API. The Windows Azure Service Management API use mutual authentication of management certificates over SSL to ensure that a request made to the service is secure. No anonymous requests are allowed. Cloud credentials provider for .NET Framework clients. Creates a new credentials instance if the appropriate settings for this provider are present and valid. Dictionary of configuration settings. Returns a new instance if the provider supports the provided settings. Computes SHA256 hash from key and data using HMACSHA256. Key to use as hash salt. Data to hash. Hash value. Initializes the settings. Checks whether the given exception represents an exception throws for a missing setting. Exception True for the missing setting exception. Gets a setting with the given name. Setting name. Setting value or null if such setting does not exist. Gets setting's value from the given provider. Provider name. Setting name Method to obtain given setting. Setting value, or null if not found. Gets a configuration setting from the service runtime. Setting name. Setting value or null if not found. Loads and returns the latest available version of the service runtime assembly. Loaded assembly, if any. Gets the setting defined in the Windows Azure configuration file. Setting name. Setting value. Gets an assembly path from the GAC given a partial name. An assembly partial name. May not be null. The assembly path if found; otherwise null; Registers cloud configuration providers with the common runtime that require the .NET framework. A strongly-typed resource class, for looking up localized strings, etc. Returns the cached ResourceManager instance used by this class. Overrides the current thread's CurrentUICulture property for all resource lookups using this strongly typed resource class. Looks up a localized string similar to {0} requires a {1} in its HTTP pipeline to work with client certificates.. ================================================ FILE: ironclad-apps/tools/NuBuild2/References/Microsoft.WindowsAzure.Common.xml ================================================ Microsoft.WindowsAzure.Common Helper class used for deserialization of OLEDB Connection Strings. Defines an interface for setting parsers. Parses the setting. Setting to parse. Dictionary representation of the setting. Gets the setting name. Deserializes OLEDB Connection String. OLEDB Connection String. Dictionary representation of the Connection String. Gets the setting name. Class for token based credentials associated with a particular subscription. Base class for credentials associated with a particular subscription. The CloudCredentials class is the base class for providing credentials to access Windows Azure services. Initialize a ServiceClient instance to process credentials. Type of ServiceClient. The ServiceClient. Apply the credentials to the HTTP request. The HTTP request. Cancellation token. Task that will complete when processing has completed. Gets subscription ID which uniquely identifies Windows Azure subscription. The subscription ID forms part of the URI for every call that you make to the Service Management API. Gets an empty subscription Id. Class for token based credentials associated with a particular subscription. Initializes a new instance of the class with subscription ID. The Subscription ID. Valid JSON Web Token (JWT). Initializes a new instance of the class without subscription ID. Valid JSON Web Token (JWT). Attempt to create token credentials from a collection of settings. The settings to use. TokenCloudCredentials is created, null otherwise. Apply the credentials to the HTTP request. The HTTP request. Cancellation token. Task that will complete when processing has completed. Gets subscription ID which uniquely identifies Windows Azure subscription. The subscription ID forms part of the URI for every call that you make to the Service Management API. Gets or sets secure token used to authenticate against Windows Azure API. No anonymous requests are allowed. Representation of the error object from the server. Parsed error message. Parsed error code. Original error body Base class used to describe HTTP requests and responses associated with error conditions. Initializes a new instance of the CloudHttpErrorInfo class. Add the HTTP message headers to the error info. Collection of HTTP header. Gets or sets the contents of the HTTP message. Gets the collection of HTTP headers. Gets or sets the HTTP message version. Describes HTTP requests associated with error conditions. Initializes a new instance of the CloudHttpRequestErrorInfo class. Creates a new CloudHttpRequestErrorInfo from a HttpRequestMessage. The request message. A CloudHttpRequestErrorInfo instance. Creates a new CloudHttpRequestErrorInfo from a HttpRequestMessage. The request message. The request content, which may be passed separately if the request has already been disposed. A CloudHttpRequestErrorInfo instance. Gets or sets the HTTP method used by the HTTP request message. Gets or sets the Uri used for the HTTP request. Gets a set of properties for the HTTP request. Describes HTTP responses associated with error conditions. Initializes a new instance of the CloudHttpResponseErrorInfo class. Creates a new CloudHttpResponseErrorInfo from a HttpResponseMessage. The response message. A CloudHttpResponseErrorInfo instance. Creates a new CloudHttpResponseErrorInfo from a HttpResponseMessage. The response message. The response content, which may be passed separately if the response has already been disposed. A CloudHttpResponseErrorInfo instance. Gets or sets the status code of the HTTP response. Gets or sets the reason phrase which typically is sent by servers together with the status code. Provides cryptography functionality to libraries. Computes a Hash-based Message Authentication Code (HMAC) by using the SHA256 hash function. The key to use in the hash algorithm. The input to compute the hash code for. Returns the computed hash code. Extensions for manipulating HTTP requests and responses. Get the HTTP message content as a string. The HTTP content. The HTTP message content as a string. Get the content headers for an HTTP request. The request message. The content headers. Get the content headers for an HTTP response. The response message. The content headers. Get a standard string representation of an HTTP request. The request message. String representation of the request. Get a standard string representation of an HTTP request. The request message. String representation of the request. Append an HTTP request. The StringBuilder. The request message. Append an HTTP request. The StringBuilder. The request message. Append the components of an HTTP request. The StringBuilder. The request method. The request URI. The request HTTP version. The request headers. The request content headers. The request properties. The request content. Get a standard string representation of an HTTP response. The response message. String representation of the response. Get a standard string representation of an HTTP response. The response message. String representation of the response. Append an HTTP response. The StringBuilder. The response message. Append an HTTP response. The StringBuilder. The response message. Append the components of an HTTP response. The StringBuilder. The response status code. The response reason phrase. The response HTTP version. The response headers. The response content headers. The response content. Append HTTP headers. The StringBuilder. The HTTP headers. Helper class used for deserialization of JSON formatted Connection Strings. Deserializes JSON formatted Connection String. JSON formatted Connection String. Dictionary representation of the Connection String. Gets the setting name. Wrapper class for HttpMessageHandler that prevents InnerHandler from being disposed. Initializes a new instance of the class from HttpMessageHandler. InnerHandler to wrap. Overrides Dispose of the base class to prevent disposal of the InnerHandler. If set to true indicates the method is being called from Dispose(). Parser helper. Checks if content is possibly an XML. String to check. If set to true will validate entire XML for validity otherwise will just check the first character. True is content is possibly an XML otherwise false. Checks if content is possibly a JSON. String to check. If set to true will validate entire JSON for validity otherwise will just check the first character. True is content is possibly an JSON otherwise false. Returns first non whitespace character Text to search in Non whitespace or default char Static type conversion utility methods. Converts an array of 8-bit unsigned integers to its equivalent string representation that is encoded with base-64 digits. An array of 8-bit unsigned integers. The string representation, in base 64, of the contents of value. Decodes all the bytes in the specified byte array into a string. The byte array containing the sequence of bytes to decode. A string that contains the results of decoding the specified sequence of bytes. Converts the specified string, which encodes binary data as base-64 digits, to a UTF8-encoded string. The base 64-encoded string to convert. Returns a string. Uses Uri::TryCreate method to safely attempt to parse a string value and return its Uri representation. Supports relative Uris. The Uri string. Returns a new Uri instance or null. Convert a TimeSpan into an 8601 formatted string. The timespan to convert. The TimeSpan in 8601 format. Convert a string from ISO 8601 format to a TimeSpan instance. Value to parse. The resulting timespan. Concatenates parts of the Uri together ensuring that any duplicate '/' characters are removed. Parts of the Uri to be combined. Concatenated Uri A standard service response including an HTTP status code and request ID. Gets or sets the standard HTTP status code from the REST API operations for the Service Management API. Gets or sets the value that uniquely identifies a request made against the service. The status of the asynchronous request. The asynchronous request is in progress. The asynchronous request succeeded. The asynchronous request failed. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is i progress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request, and also includes error information regarding the failure. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request, and also includes error information regarding the failure. The HTTP status code for the asynchronous request. The request ID of the asynchronous request. This value is returned in the x-ms-request-id response header of the asynchronous request. The status of the asynchronous request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request, and also includes error information regarding the failure. Initializes a new instance of the ErrorDetails class. The management service error code returned if the asynchronous request failed. The management service error message returned if the asynchronous request failed. JSON formatter for PATCH syntax. Value to patch. Implicit operator that converts T to Patchable T. Object to convert. Converted object. Implicit operator that converts Patchable T to T. Object to convert. Converted object. Sets operation to SET and returns instance of the object. Value to patch. Instance of the object. Returns formatted PATCH script. Formatted PATCH script. Gets the patch value. Gets a value indicating whether the value is set. Parameter attribute used with OData filters. Initializes a new instance of the class. Property name to use in the filter. Initializes a new instance of the class. Property name to use in the filter. Format of the value. Property name to use in the filter. Format of the value. Handles OData filter generation. Generates an OData filter from a specified Linq expression. Filter type Entity to use for filter generation Expression visitor class that generates OData style $filter parameter. Visits binary expression !foo. Node to visit. Original node. Visits conditional expression foo == true ? bar : fee. Throws NotSupportedException. Node to visit. Throws NotSupportedException. Visits new object expression like new DateTime(). Node to visit. Original node. Visits constants like 'a' or 123. Node to visit. Original node. Visits object members like p.Foo or dateTime.Hour. Node to visit. Original node. Visits method calls like Contains, StartsWith, etc. Methods that are not supported will throw an exception. Node to visit. Original node. Appends 'eq true' to Boolean unary operators. Helper method to print constant. Object to print. Helper method to generate property name. Property to examine. Property name or value specified in the FilterParameterAttribute. Helper method to retrieve format from the FilterParameterAttribute. Property to examine. Format from FilterParameterAttribute or null. A cloud credentials provider. Creates a new credentials instance if the appropriate settings for this provider are present and valid. Dictionary of configuration settings. Returns a new instance if the provider supports the provided settings. Defines cryptographic methods. Computes SHA256 hash from key and data. Key to use as hash salt. Data to hash. Hash value. Provides tracing utilities that insight into all aspects of client operations via implementations of the ICloudTracingInterceptor interface. All tracing is global. The utilities in the internal Tracing class provide helpers for notifying the active trace listeners of changes. The collection of tracing interceptors to notify. A read-only, thread-safe collection of tracing interceptors. Since List is only thread-safe for reads (and adding/removing tracing interceptors isn't a very common operation), we simply replace the entire collection of interceptors so any enumeration of the list in progress on a different thread will not be affected by the change. Lock used to synchronize mutation of the tracing interceptors. Initializes a new instance of the CloudTracing class. Add a tracing interceptor to be notified of changes. The tracing interceptor. Remove a tracing interceptor from change notifications. The tracing interceptor. True if the tracing interceptor was found and removed; false otherwise. Gets or sets a value indicating whether tracing is enabled. Tracing can be disabled for performance. Gets a sequence of the tracing interceptors to notify of changes. Http retry handler. Initializes a new instance of the class. Sets default retry policty base on Exponential Backoff. Initializes a new instance of the class. Sets the default retry policty base on Exponential Backoff. Inner http handler. Initializes a new instance of the class. Retry policy to use. Inner http handler. Sends an HTTP request to the inner handler to send to the server as an asynchronous operation. Retries request if needed based on Retry Policy. The HTTP request message to send to the server. A cancellation token to cancel operation. Returns System.Threading.Tasks.Task<TResult>. The task object representing the asynchronous operation. Gets or sets retry policy. An instance of a callback delegate that will be invoked whenever a retry condition is encountered. Creates a new credentials instance of type T using the set of registered cloud credentials providers and provided settings. The requested minimum type of cloud credentials for successful credential use. Dictionary of configuration settings. Provides a value indicating whether to throw if the minimum requested credentials type cannot be found. Defaults to true. Returns a new instance of the first provider that supports the provided settings. The base ServiceClient class used to call REST services. Type of the ServiceClient. Gets the Platform's IHttpTransportHandlerProvider which gives the default HttpHandler for sending web requests. A value indicating whether or not the ServiceClient has already been disposed. Reference to the delegated handler of our handler (so we can maintain a proper reference count). Reference to our HTTP handler (which is the start of our HTTP pipeline). Initializes static members of the ServiceClient class. Initializes a new instance of the ServiceClient class. Initializes a new instance of the ServiceClient class. The http client. Initializes HttpClient. Http message handler to use with Http client. Create the HTTP client. The HTTP client. Dispose the ServiceClient. Clone the service client. The client to clone. Clone HttpClient properties. The client to clone. The client to copy into. Extend the ServiceClient with a new handler. The new client that will extend. The handler to extend with. The extended client. Gets the HttpClient used for making HTTP requests. Gets a reference to our HTTP handler (which is the start of our HTTP pipeline). Gets the UserAgent collection which can be augmented with custom user agent strings. Interface used to represent resource groupings of ServiceClient operations. Type of the ServiceClient. Gets a reference to the ServiceClient. The CloudClients class provides a common location for service client discovery. It can be accessed via CloudContext.Clients. The Microsoft.WindowsAzure namespace should be imported when used because CloudClients is intended to be the target of extension methods by each service client. All service client libraries should add CreateXYZClient() extension methods on static classes declared in the Microsoft.WindowsAzure namespace. This will allow any library loaded in a project to be easily discovered via CloudContext.Clients without developers having to figure out which namespaces to import, etc. You may also add extension methods that create This class is used as a static class (internal constructor) but not declared as such so it can be the target of extension methods. Initializes a new instance of the CloudClients class. Utilities for easily retrieving configuration settings across a variety of platform appropriate sources. Initializes static members of the class. Initializes platform-specific cloud configuration and credentials providers. Registers a cloud credentials provider with the configuration runtime. Instance of a cloud credentials provider. Creates a new credentials instance of type T using the set of registered cloud credentials providers. The requested minimum type of cloud credentials for successful credential use. Dictionary of configuration settings. Returns a new instance of the first provider that supports the provided settings. A platform specific configuration provider. There is no standard configuration support in the Portable Class Libraries BCL. Initializes a new instance of the CloudConfiguration class. Get the value of a configuration setting from a platform specific configuration source. The name of the setting. The value of the setting, or null if not found. Get connection info that can be used to instantiate type T by searching for configuration settings of the form Namespace.Type.format. If no connection info is found for the type, we will search for connection info for all of its base types. The type to obtain connection info for. Connection info used to instantiate the given type or null if no connection info is found. You can get insight into the connection info search by checking the tracing output. Get named connection info that can be used to instantiate a type by searching for configuration settings of the format Namespace.Type.Name.format. If no connection info is found for the type, we will search for connection info for all of its base types. The type to obtain connection info for. The name of the connection info. Connection info used to instantiate the given type or null if no connection info is found. You can get insight into the connection info search by checking the tracing output. Get connection info that can be used to instantiate a type by searching for configuration settings of the form Namespace.Type.format. If no connection info is found for the type, we will search for connection info for all of its base types. The type to obtain connection info for. Connection info used to instantiate the given type or null if no connection info is found. You can get insight into the connection info search by checking the tracing output. Get named connection info that can be used to instantiate a type by searching for configuration settings of the format Namespace.Type.Name.format. If no connection info is found for the type, we will search for connection info for all of its base types. The type to obtain connection info for. The name of the connection info. Connection info used to instantiate the given type or null if no connection string is found. You can get insight into the connection info search by checking the tracing output. Get connection info that can be used to instantiate a type by searching for configuration settings of the format Namespace.Type[.Name].format If no settings are found for the type, we will search for connection info for all of its base types. The type to obtain connection info for. Optional value for named settings. Name of the config setting item where the setting was found. Value of the config setting item where the setting was found. Connection info used to instantiate the given type or null if no connection info is found. You can get insight into the connection info search by checking the tracing output. Parse a connection string. The connection string. A dictionary of the setting names and values from the connection string. Parse a JSON settings file. The JSON settings. A dictionary of the setting names and values from the JSON settings. Gets a platform specific configuration provider. There is no standard configuration support in the Portable Class Libraries BCL. Gets the tracing utilities used to provide insight into all aspects of client operations. The CloudContext class is your primary entry point for getting started with Windows Azure client libraries. CloudContext.Clients contains helpful methods to create any of the clients currently referenced in your project (be sure to import the Microsoft.WindowsAzure namespace so you import its extension methods). CloudContext.Configuration allows you to easily retrieve configuration settings across a variety of platform appropriate sources. The CloudContext class is static to make it easier to use, but all other classes should be instances so they can be targeted by extension methods given the layered approach of our client libraries. Initializes static members of the class. Gets an object providing a common location for service client discovery. The Microsoft.WindowsAzure namespace should be imported when used because CloudClients is intended to be the target of extension methods by each service client library. Gets utilities for easily retrieving configuration settings across a variety of platform appropriate sources. Parse connection strings. The following simplified grammar was obtained from the specification "[MS-OLEDBSTR]: OLEDB Connection String Structure". Refer to the spec for full details. We support case-insensitive keys and multiple occurrences of the same key, but not multiple values for keys (i.e., the CompoundValue nonterminal in the spec's grammar). ws := [ \t]* semi := ; eq := = esc-eq := == dq := " sq := ' esc-dq := "" esc-sq := '' key-start: (==)|[^ \t;] key-body: (==)[^;]* key-end: (==)|[^ \t;] lit-start: [^ \t'";=] lit-body: [^;] lit-end: [^ \t;] sq-lit: ''|[^'] dq-lit: ""|[^"] ConnectionString := (ConnectionStringClause semi)* (ConnectionStringClause semi?)? ConnectionStringClause := KeyValuePair | ws KeyValuePair := ws Key ws eq ws Value ws Key := key-start (key-body* key-end)? Value := (lit-start (lit-body* lit-end)?)? | sq sq-lit* sq | dq dq-lit* dq Parses the connection string into a collection of key/value pairs. Connection string. Parsed connection string. Initializes a new instance of the class. Value to parse. Parses the string. A collection of key=value pairs. Generates an invalid connection string exception with the detailed error message. Position of the error. Short error formatting string. Optional arguments for the error string. Exception with the requested message. Skips whitespaces at the current position. Extracts key at the current position. Key. Extracts the string until the given quotation mark. Quotation mark terminating the string. String. Skips specified operator. Operator character. Extracts key's value. Key's value. State of the parser. Wrapper class that provides manual reference count functionality Type to wrap around. Must be disposable. Platform-specific interface enabling cloud configuration support. Registers platform-specific cloud configuration providers with the common runtime. Exception thrown for any invalid response. Initializes a new instance of the CloudException class. The exception message. Initializes a new instance of the CloudException class. The exception message. Inner exception. Create a CloudException from a failed response. The HTTP request. The HTTP request content. The HTTP response. The HTTP response content. Optional inner exception. A CloudException representing the failure. Create a CloudException from a failed response. This method is obsolete. Use Create without defaultTo parameter. The HTTP request. The HTTP request content. The HTTP response. The HTTP response content. The content type to default to if none of the types matches. Optional inner exception. A CloudException representing the failure. Create a CloudException from a failed response sending XML content. This method is obsolete. Use Create without defaultTo parameter. The HTTP request. The HTTP request content. The HTTP response. The HTTP response content. Optional inner exception. A CloudException representing the failure. Create a CloudException from a failed response sending JSON content. This method is obsolete. Use Create without defaultTo parameter. The HTTP request. The HTTP request content. The HTTP response. The HTTP response content. Optional inner exception. A CloudException representing the failure. Parse the response content as either an XML or JSON error message. The response content. An object containing the parsed error code and message. Parse the response content as an XML error message. The response content. An object containing the parsed error code and message. Parse the response content as an JSON error message. The response content. An object containing the parsed error code and message. Gets the error message returned from the server. This is included by default in the Message property. Gets the error code returned from the server. This is included by default in the Message property. Gets the request identifier. Gets the routing request identifier. Gets information about the associated HTTP request. Gets information about the associated HTTP response. Internal extensions. Create an ArgumentException for empty parameters. The parameter name. The ArgumentException. Get the assembly version of a service client. Type of the service client. The service client. The assembly version of the client. Get the HTTP pipeline formed from the ancestors of the starting handler. The starting handler. The HTTP pipeline. Get the HTTP pipeline for the given service client. Type of the service client. The service client. The client's HTTP pipeline. Add a handler to the end of the client's HTTP pipeline. Type of the service client. The service client. The handler to add. Sets retry policy for the client. Service client type. Service client. Retry policy to set. Helper extension methods used by tracing providers. Returns string representation of a HttpRequestMessage. Request to format. Formatted string. Returns string representation of a HttpResponseMessage. Response to format. Formatted string. Converts given dictionary into a log string. The dictionary key type The dictionary value type The dictionary collection object The log string The ICloudTracingInterceptor provides useful information about cloud operations. Interception is global and a tracing interceptor can be added via CloudContext.Configuration.Tracing.AddTracingInterceptor. Trace information. The information to trace. Probe configuration for the value of a setting. The configuration source. The name of the setting. The value of the setting in the source. Enter a method. Method invocation identifier. The instance with the method. Name of the method. Method parameters. Send an HTTP request. Method invocation identifier. The request about to be sent. Receive an HTTP response. Method invocation identifier. The response instance. Raise an error. Method invocation identifier. The error. Exit a method. Note: Exit will not be called in the event of an error. Method invocation identifier. Method return value. A strongly-typed resource class, for looking up localized strings, etc. Returns the cached ResourceManager instance used by this class. Overrides the current thread's CurrentUICulture property for all resource lookups using this strongly typed resource class. Looks up a localized string similar to Value cannot be empty. Parameter name: {0}. Looks up a localized string similar to The specified argument {0} cannot be greater than its ceiling value of {1}.. Looks up a localized string similar to The specified argument {0} cannot be initialized with a negative value.. Looks up a localized string similar to Failed to convert parameter {0} value '{1}' to type {2}.. Looks up a localized string similar to {3} Failed to create {0} from connection settings {1} = "{2}".. Looks up a localized string similar to No connection settings found for type {0}. Enable tracing for more information.. Looks up a localized string similar to No credentials of type '{0}' could be initialized from the provided settings.. Looks up a localized string similar to Parameter {0} is required.. Looks up a localized string similar to Default retry strategy for technology {0}, named '{1}', is not defined.. Looks up a localized string similar to Default retry strategy for technology {0} was not not defined, and there is no overall default strategy.. Looks up a localized string similar to Retry handler is not present in the HttpClient handler stack.. Looks up a localized string similar to The RetryManager is already set.. Looks up a localized string similar to The default RetryManager has not been set. Set it by invoking the RetryManager.SetDefault static method, or if you are using declarative configuration, you can invoke the RetryPolicyFactory.CreateDefault() method to automatically create the retry manager from the configuration file.. Looks up a localized string similar to Response status code indicates server error: {0} ({1}).. Looks up a localized string similar to The action has exceeded its defined retry limit.. Looks up a localized string similar to The retry strategy with name '{0}' cannot be found.. Looks up a localized string similar to The specified string argument {0} must not be empty.. Looks up a localized string similar to The specified argument '{0}' cannot return a null task when invoked.. Looks up a localized string similar to The specified argument '{0}' must return a scheduled task (also known as "hot" task) when invoked.. Handles the execution and retries of the user-initiated task. The result type of the user-initiated task. Provides a wrapper for a non-generic and calls into the pipeline to retry only the generic version of the . Wraps the non-generic into a generic . The task to wrap. A that wraps the non-generic . Default Http error detection strategy based on Http Status Code. Defines an interface that must be implemented by custom components responsible for detecting specific transient conditions. Determines whether the specified exception represents a transient failure that can be compensated by a retry. The exception object to be verified. true if the specified exception is considered as transient; otherwise, false. Returns true if status code in HttpRequestExceptionWithStatus exception is greater than or equal to 500 and not NotImplemented (501) or HttpVersionNotSupported (505). Exception to check against. True if exception is transient otherwise false. A retry strategy with backoff parameters for calculating the exponential delay between retries. Represents a retry strategy that determines the number of retry attempts and the interval between retries. Represents the default number of retry attempts. Represents the default amount of time used when calculating a random delta in the exponential delay between retries. Represents the default maximum amount of time used when calculating the exponential delay between retries. Represents the default minimum amount of time used when calculating the exponential delay between retries. Represents the default interval between retries. Represents the default time increment between retry attempts in the progressive delay policy. Represents the default flag indicating whether the first retry attempt will be made immediately, whereas subsequent retries will remain subject to the retry interval. Initializes a new instance of the class. The name of the retry strategy. true to immediately retry in the first attempt; otherwise, false. The subsequent retries will remain subject to the configured retry interval. Returns the corresponding ShouldRetry delegate. The ShouldRetry delegate. Returns a default policy that performs no retries, but invokes the action only once. Returns a default policy that implements a fixed retry interval configured with the and parameters. The default retry policy treats all caught exceptions as transient errors. Returns a default policy that implements a progressive retry interval configured with the , , and parameters. The default retry policy treats all caught exceptions as transient errors. Returns a default policy that implements a random exponential retry interval configured with the , , , and parameters. The default retry policy treats all caught exceptions as transient errors. Gets or sets a value indicating whether the first retry attempt will be made immediately, whereas subsequent retries will remain subject to the retry interval. Gets the name of the retry strategy. Initializes a new instance of the class. Initializes a new instance of the class with the specified retry settings. The maximum number of retry attempts. The minimum backoff time The maximum backoff time. The value that will be used to calculate a random delta in the exponential delay between retries. Initializes a new instance of the class with the specified name and retry settings. The name of the retry strategy. The maximum number of retry attempts. The minimum backoff time The maximum backoff time. The value that will be used to calculate a random delta in the exponential delay between retries. Initializes a new instance of the class with the specified name, retry settings, and fast retry option. The name of the retry strategy. The maximum number of retry attempts. The minimum backoff time The maximum backoff time. The value that will be used to calculate a random delta in the exponential delay between retries. true to immediately retry in the first attempt; otherwise, false. The subsequent retries will remain subject to the configured retry interval. Returns the corresponding ShouldRetry delegate. The ShouldRetry delegate. Represents a retry strategy with a specified number of retry attempts and a default, fixed time interval between retries. Initializes a new instance of the class. Initializes a new instance of the class with the specified number of retry attempts. The number of retry attempts. Initializes a new instance of the class with the specified number of retry attempts and time interval. The number of retry attempts. The time interval between retries. Initializes a new instance of the class with the specified number of retry attempts, time interval, and retry strategy. The retry strategy name. The number of retry attempts. The time interval between retries. Initializes a new instance of the class with the specified number of retry attempts, time interval, retry strategy, and fast start option. The retry strategy name. The number of retry attempts. The time interval between retries. true to immediately retry in the first attempt; otherwise, false. The subsequent retries will remain subject to the configured retry interval. Returns the corresponding ShouldRetry delegate. The ShouldRetry delegate. Implements the common guard methods. Checks a string argument to ensure that it isn't null or empty. The argument value to check. The name of the argument. The return value should be ignored. It is intended to be used only when validating arguments during instance creation (for example, when calling the base constructor). Checks an argument to ensure that it isn't null. The argument value to check. The name of the argument. The return value should be ignored. It is intended to be used only when validating arguments during instance creation (for example, when calling the base constructor). Checks an argument to ensure that its 32-bit signed value isn't negative. The value of the argument. The name of the argument for diagnostic purposes. Checks an argument to ensure that its 64-bit signed value isn't negative. The value of the argument. The name of the argument for diagnostic purposes. Checks an argument to ensure that its value doesn't exceed the specified ceiling baseline. The value of the argument. The ceiling value of the argument. The name of the argument for diagnostic purposes. Inherits HttpRequestException adding HttpStatusCode to the exception. Initializes a new instance of the class. Initializes a new instance of the class with a specific message that describes the current exception. A message that describes the current exception. Initializes a new instance of the class with a specific message that describes the current exception and an inner exception. A message that describes the current exception. The inner exception. Http status code. A retry strategy with a specified number of retry attempts and an incremental time interval between retries. Initializes a new instance of the class. Initializes a new instance of the class with the specified retry settings. The number of retry attempts. The initial interval that will apply for the first retry. The incremental time value that will be used to calculate the progressive delay between retries. Initializes a new instance of the class with the specified name and retry settings. The retry strategy name. The number of retry attempts. The initial interval that will apply for the first retry. The incremental time value that will be used to calculate the progressive delay between retries. Initializes a new instance of the class with the specified number of retry attempts, time interval, retry strategy, and fast start option. The retry strategy name. The number of retry attempts. The initial interval that will apply for the first retry. The incremental time value that will be used to calculate the progressive delay between retries. true to immediately retry in the first attempt; otherwise, false. The subsequent retries will remain subject to the configured retry interval. Returns the corresponding ShouldRetry delegate. The ShouldRetry delegate. Contains information that is required for the event. Initializes a new instance of the class. The current retry attempt count. The delay that indicates how long the current thread will be suspended before the next iteration is invoked. The exception that caused the retry conditions to occur. Gets the current retry count. Gets the delay that indicates how long the current thread will be suspended before the next iteration is invoked. Gets the exception that caused the retry conditions to occur. The special type of exception that provides managed exit from a retry loop. The user code can use this exception to notify the retry policy that no further retry attempts are required. Initializes a new instance of the class with a default error message. Initializes a new instance of the class with a specified error message. The message that describes the error. Initializes a new instance of the class with a reference to the inner exception that is the cause of this exception. The exception that is the cause of the current exception. Initializes a new instance of the class with a specified error message and inner exception. The message that describes the error. The exception that is the cause of the current exception. Provides the entry point to the retry functionality. Sets the specified retry manager as the default retry manager. The retry manager. true to throw an exception if the manager is already set; otherwise, false. Defaults to . The singleton is already set and is true. Initializes a new instance of the class. The complete set of retry strategies. Initializes a new instance of the class with the specified retry strategies and default retry strategy name. The complete set of retry strategies. The default retry strategy. Initializes a new instance of the class with the specified retry strategies and defaults. The complete set of retry strategies. The default retry strategy. The names of the default strategies for different technologies. Returns a retry policy with the specified error detection strategy and the default retry strategy defined in the configuration. The type that implements the interface that is responsible for detecting transient conditions. A new retry policy with the specified error detection strategy and the default retry strategy defined in the configuration. Returns a retry policy with the specified error detection strategy and retry strategy. The type that implements the interface that is responsible for detecting transient conditions. The retry strategy name, as defined in the configuration. A new retry policy with the specified error detection strategy and the default retry strategy defined in the configuration. Returns the default retry strategy defined in the configuration. The retry strategy that matches the default strategy. Returns the retry strategy that matches the specified name. The retry strategy name. The retry strategy that matches the specified name. Returns the retry strategy for the specified technology. The techonolgy to get the default retry strategy for. The retry strategy for the specified technology. Gets the default for the application. You can update the default retry manager by calling the method. Gets or sets the default retry strategy name. Provides the base implementation of the retry mechanism for unreliable actions and transient conditions. Initializes a new instance of the class with the specified number of retry attempts and parameters defining the progressive delay between retries. The that is responsible for detecting transient conditions. The strategy to use for this retry policy. Initializes a new instance of the class with the specified number of retry attempts and default fixed time interval between retries. The that is responsible for detecting transient conditions. The number of retry attempts. Initializes a new instance of the class with the specified number of retry attempts and fixed time interval between retries. The that is responsible for detecting transient conditions. The number of retry attempts. The interval between retries. Initializes a new instance of the class with the specified number of retry attempts and backoff parameters for calculating the exponential delay between retries. The that is responsible for detecting transient conditions. The number of retry attempts. The minimum backoff time. The maximum backoff time. The time value that will be used to calculate a random delta in the exponential delay between retries. Initializes a new instance of the class with the specified number of retry attempts and parameters defining the progressive delay between retries. The that is responsible for detecting transient conditions. The number of retry attempts. The initial interval that will apply for the first retry. The incremental time value that will be used to calculate the progressive delay between retries. Repetitively executes the specified action while it satisfies the current retry policy. A delegate that represents the executable action that doesn't return any results. Repetitively executes the specified action while it satisfies the current retry policy. The type of result expected from the executable action. A delegate that represents the executable action that returns the result of type . The result from the action. Repetitively executes the specified asynchronous task while it satisfies the current retry policy. A function that returns a started task (also known as "hot" task). A task that will run to completion if the original task completes successfully (either the first time or after retrying transient failures). If the task fails with a non-transient error or the retry limit is reached, the returned task will transition to a faulted state and the exception must be observed. Repetitively executes the specified asynchronous task while it satisfies the current retry policy. A function that returns a started task (also known as "hot" task). The token used to cancel the retry operation. This token does not cancel the execution of the asynchronous task. Returns a task that will run to completion if the original task completes successfully (either the first time or after retrying transient failures). If the task fails with a non-transient error or the retry limit is reached, the returned task will transition to a faulted state and the exception must be observed. Repeatedly executes the specified asynchronous task while it satisfies the current retry policy. A function that returns a started task (also known as "hot" task). Returns a task that will run to completion if the original task completes successfully (either the first time or after retrying transient failures). If the task fails with a non-transient error or the retry limit is reached, the returned task will transition to a faulted state and the exception must be observed. Repeatedly executes the specified asynchronous task while it satisfies the current retry policy. A function that returns a started task (also known as "hot" task). The token used to cancel the retry operation. This token does not cancel the execution of the asynchronous task. Returns a task that will run to completion if the original task completes successfully (either the first time or after retrying transient failures). If the task fails with a non-transient error or the retry limit is reached, the returned task will transition to a faulted state and the exception must be observed. Notifies the subscribers whenever a retry condition is encountered. The current retry attempt count. The exception that caused the retry conditions to occur. The delay that indicates how long the current thread will be suspended before the next iteration is invoked. Returns a default policy that performs no retries, but invokes the action only once. Returns a default policy that implements a fixed retry interval configured with the default retry strategy. The default retry policy treats all caught exceptions as transient errors. Returns a default policy that implements a progressive retry interval configured with the default retry strategy. The default retry policy treats all caught exceptions as transient errors. Returns a default policy that implements a random exponential retry interval configured with the default retry strategy. The default retry policy treats all caught exceptions as transient errors. An instance of a callback delegate that will be invoked whenever a retry condition is encountered. Gets the retry strategy. Gets the instance of the error detection strategy. Implements a strategy that ignores any transient errors. Always returns false. The exception. Always false. Implements a strategy that treats all exceptions as transient errors. Always returns true. The exception. Always true. Provides a generic version of the class. The type that implements the interface that is responsible for detecting transient conditions. Initializes a new instance of the class with the specified number of retry attempts and parameters defining the progressive delay between retries. The strategy to use for this retry policy. Initializes a new instance of the class with the specified number of retry attempts and the default fixed time interval between retries. The number of retry attempts. Initializes a new instance of the class with the specified number of retry attempts and a fixed time interval between retries. The number of retry attempts. The interval between retries. Initializes a new instance of the class with the specified number of retry attempts and backoff parameters for calculating the exponential delay between retries. The number of retry attempts. The minimum backoff time. The maximum backoff time. The time value that will be used to calculate a random delta in the exponential delay between retries. Initializes a new instance of the class with the specified number of retry attempts and parameters defining the progressive delay between retries. The number of retry attempts. The initial interval that will apply for the first retry. The incremental time value that will be used to calculate the progressive delay between retries. Defines a callback delegate that will be invoked whenever a retry condition is encountered. The current retry attempt count. The exception that caused the retry conditions to occur. The delay that indicates how long the current thread will be suspended before the next iteration is invoked. if a retry is allowed; otherwise, . ================================================ FILE: ironclad-apps/tools/NuBuild2/References/Microsoft.WindowsAzure.Management.Compute.xml ================================================ Microsoft.WindowsAzure.Management.Compute The Service Management API provides programmatic access to much of the functionality available through the Management Portal. The Service Management API is a REST API. All API operations are performed over SSL, and are mutually authenticated using X.509 v3 certificates. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460799.aspx for more information) The Service Management API provides programmatic access to much of the functionality available through the Management Portal. The Service Management API is a REST API. All API operations are performed over SSL, and are mutually authenticated using X.509 v3 certificates. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460799.aspx for more information) The Get Operation Status operation returns the status of the specified operation. After calling an asynchronous operation, you can call Get Operation Status to determine whether the operation has succeeded, failed, or is still in progress. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460783.aspx for more information) The request ID for the request you wish to track. The request ID is returned in the x-ms-request-id response header for every request. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Gets the API version. Gets the URI used as the base for all cloud service requests. Gets subscription credentials which uniquely identify Microsoft Azure subscription. The subscription ID forms part of the URI for every service call. Gets or sets the initial timeout for Long Running Operations. Gets or sets the retry timeout for Long Running Operations. The Service Management API includes operations for managing the deployments in your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460812.aspx for more information) The Service Management API includes operations for managing the hosted services beneath your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460812.aspx for more information) The Compute Management API includes operations for managing the load balancers for your subscription. Operations for determining the version of the Azure Guest Operating System on which your service is running. (see http://msdn.microsoft.com/en-us/library/windowsazure/ff684169.aspx for more information) Operations for managing service certificates for your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee795178.aspx for more information) The Service Management API includes operations for managing the disks in your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157188.aspx for more information) The Service Management API includes operations for managing the virtual machine extensions in your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157206.aspx for more information) The Service Management API includes operations for managing the virtual machines in your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157206.aspx for more information) The Service Management API includes operations for managing the OS images in your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157175.aspx for more information) The Service Management API includes operations for managing the virtual machine templates in your subscription. Initializes a new instance of the ComputeManagementClient class. Initializes a new instance of the ComputeManagementClient class. Required. Gets subscription credentials which uniquely identify Microsoft Azure subscription. The subscription ID forms part of the URI for every service call. Required. Gets the URI used as the base for all cloud service requests. Initializes a new instance of the ComputeManagementClient class. Required. Gets subscription credentials which uniquely identify Microsoft Azure subscription. The subscription ID forms part of the URI for every service call. Initializes a new instance of the ComputeManagementClient class. The Http client Initializes a new instance of the ComputeManagementClient class. Required. Gets subscription credentials which uniquely identify Microsoft Azure subscription. The subscription ID forms part of the URI for every service call. Required. Gets the URI used as the base for all cloud service requests. The Http client Initializes a new instance of the ComputeManagementClient class. Required. Gets subscription credentials which uniquely identify Microsoft Azure subscription. The subscription ID forms part of the URI for every service call. The Http client Clones properties from current instance to another ComputeManagementClient instance Instance of ComputeManagementClient to clone to The Get Operation Status operation returns the status of the specified operation. After calling an asynchronous operation, you can call Get Operation Status to determine whether the operation has succeeded, failed, or is still in progress. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460783.aspx for more information) Required. The request ID for the request you wish to track. The request ID is returned in the x-ms-request-id response header for every request. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Parse enum values for type CertificateFormat. The value to parse. The enum value. Convert an enum of type CertificateFormat to a string. The value to convert to a string. The enum value as a string. Parse enum values for type LoadBalancerProbeTransportProtocol. The value to parse. The enum value. Convert an enum of type LoadBalancerProbeTransportProtocol to a string. The value to convert to a string. The enum value as a string. Gets the API version. Gets the URI used as the base for all cloud service requests. Gets subscription credentials which uniquely identify Microsoft Azure subscription. The subscription ID forms part of the URI for every service call. Gets or sets the initial timeout for Long Running Operations. Gets or sets the retry timeout for Long Running Operations. The Service Management API includes operations for managing the deployments in your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460812.aspx for more information) The Service Management API includes operations for managing the hosted services beneath your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460812.aspx for more information) The Compute Management API includes operations for managing the load balancers for your subscription. Operations for determining the version of the Azure Guest Operating System on which your service is running. (see http://msdn.microsoft.com/en-us/library/windowsazure/ff684169.aspx for more information) Operations for managing service certificates for your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee795178.aspx for more information) The Service Management API includes operations for managing the disks in your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157188.aspx for more information) The Service Management API includes operations for managing the virtual machine extensions in your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157206.aspx for more information) The Service Management API includes operations for managing the virtual machines in your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157206.aspx for more information) The Service Management API includes operations for managing the OS images in your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157175.aspx for more information) The Service Management API includes operations for managing the virtual machine templates in your subscription. The Service Management API provides programmatic access to much of the functionality available through the Management Portal. The Service Management API is a REST API. All API operations are performed over SSL, and are mutually authenticated using X.509 v3 certificates. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460799.aspx for more information) The Get Operation Status operation returns the status of the specified operation. After calling an asynchronous operation, you can call Get Operation Status to determine whether the operation has succeeded, failed, or is still in progress. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460783.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IComputeManagementClient. Required. The request ID for the request you wish to track. The request ID is returned in the x-ms-request-id response header for every request. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Get Operation Status operation returns the status of the specified operation. After calling an asynchronous operation, you can call Get Operation Status to determine whether the operation has succeeded, failed, or is still in progress. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460783.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IComputeManagementClient. Required. The request ID for the request you wish to track. The request ID is returned in the x-ms-request-id response header for every request. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Service Management API includes operations for managing the deployments in your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460812.aspx for more information) The Service Management API includes operations for managing the deployments in your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460812.aspx for more information) The Begin Changing Deployment Configuration By Name operation initiates a change to the deployment configuration. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460809.aspx for more information) The cloud service to change deployment configuration for. The deployment to change configuration for. Parameters supplied to the Begin Changing Configuration Deployment By Name operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Changing Deployment Configuration By Slot operation initiates a change to the deployment configuration. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460809.aspx for more information) The cloud service to change deployment configuration for. The slot to change deployment configuration for. Parameters supplied to the Begin Changing Configuration Deployment By Slot operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Creating Deployment operation uploads a new service package and creates a new deployment in the staging or production environments. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460813.aspx for more information) The cloud service to create a deployment for. The slot to create a deployment for. Parameters supplied to the Begin Creating Deployment operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Deleting Deployment By Name operation deletes the specified deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460815.aspx for more information) The name of the cloud service. The name of your deployment. Specifies that the source blob for the disk should also be deleted from storage. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Deleting Deployment By Slot operation deletes the specified deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460815.aspx for more information) The name of the cloud service. The deployment slot. Cancellation token. A standard service response including an HTTP status code and request ID. The Delete Role Instances operation deletes a role instance from a deployment in a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469418.aspx for more information) The name of the cloud service. The name of the deployment slot. The parameters to delete the role. Cancellation token. A standard service response including an HTTP status code and request ID. The Delete Role Instances operation deletes a role instance from a deployment in a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469418.aspx for more information) The name of the cloud service. The name of the deployment. The parameters to delete the role. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Rebooting Role Instance By Deployment Name operation requests a reboot of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441298.aspx for more information) The name of the cloud service. The name of your deployment. The name of your role instance. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Rebooting Role Instance By Deployment Slot operation requests a reboot of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441298.aspx for more information) The name of the cloud service. The deployment slot. The name of your role instance. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Reimaging Role Instance By Deployment Name operation requests a reimage of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441292.aspx for more information) The name of the cloud service. The name of your deployment. The name of your role instance. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Reimaging Role Instance By Deployment Slot operation requests a reimage of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441292.aspx for more information) The name of the cloud service. The deployment slot. The name of your role instance. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Swapping Deployment operation initiates a virtual IP address swap between the staging and production deployment environments for a service. If the service is currently running in the staging environment, it will be swapped to the production environment. If it is running in the production environment, it will be swapped to staging. For more information on this type of upgrade, see Performing Virtual IP Swap Upgrades at http://msdn.microsoft.com/en-us/library/windowsazure/ee517253.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460814.aspx for more information) The cloud service to swap deployments for. Parameters supplied to the Begin Swapping Deployment operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Updating Deployment Status By Deployment Name operation initiates a change in the running status of a deployment. The status of a deployment can be running or suspended. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460808.aspx for more information) The cloud service to swap deployments for. The name of your deployment. Parameters supplied to the Begin Updating Deployment Status By Deployment Name operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Updating Deployment Status By Deployment Slot operation initiates a change in the running status of a deployment. The status of a deployment can be running or suspended. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460808.aspx for more information) The cloud service to swap deployments for. The deployment slot. Parameters supplied to the Begin Updating Deployment Status By Deployment Slot operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Upgrading Deployment By Name operation initiates an update of role instances in a deployment using the package and configuration that you specify. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the request has been processed, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. To perform an automatic update of a deployment, call Upgrade Deployment or Change Deployment Configuration with the Mode element set to automatic. The update proceeds from that point without a need for further input. You can call Get Operation Status to determine when the update is complete. To perform a manual update, first call Upgrade Deployment with the Mode element set to manual. Next, call Walk Upgrade Domain to update each domain within the deployment. You should make sure that the operation is complete by calling Get Operation Status before updating the next domain. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. By default, a cloud service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To determine the update domain in which a particular instance is running in Windows Azure, use the UpdateDomain property of the RoleInstance class. See the Azure Managed Library Reference at http://msdn.microsoft.com/en-us/library/windowsazure/dd179380.aspx for more information. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460793.aspx for more information) The cloud service to upgrade. The deployment to upgrade. Parameters supplied to the Begin Upgrading Deployment By Name operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Upgrading Deployment By Slot operation initiates an update of role instances in a deployment using the package and configuration that you specify. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx.This operation is an asynchronous operation. To determine whether the request has been processed, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. To perform an automatic update of a deployment, call Upgrade Deployment or Change Deployment Configuration with the Mode element set to automatic. The update proceeds from that point without a need for further input. You can call Get Operation Status to determine when the update is complete. To perform a manual update, first call Upgrade Deployment with the Mode element set to manual. Next, call Walk Upgrade Domain to update each domain within the deployment. You should make sure that the operation is complete by calling Get Operation Status before updating the next domain. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. By default, a cloud service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To determine the update domain in which a particular instance is running in Windows Azure, use the UpdateDomain property of the RoleInstance class. See the Azure Managed Library Reference at http://msdn.microsoft.com/en-us/library/windowsazure/dd179380.aspx for more information. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460793.aspx for more information) The cloud service to upgrade. The slot to upgrade. Parameters supplied to the Begin Upgrading Deployment By Slot operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Walking Upgrade Domain By Deployment Name operation specifies an update domain in which a role instance must be updated. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. Prior to calling the Walk Upgrade Domain operation you must have called Upgrade Deployment, Change Deployment Configuration, or Rollback Update Or Upgrade. By default, a service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To perform a manual update of your deployment, proceed in this order: Call Upgrade Deployment with the Mode element set to manual. Call Walk Upgrade Domain to update each domain within the deployment. Update domains must be updated in order. For example, begin with domain 0, proceed to domain 1, and so on. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. While an update is in progress, call Get Deployment to determine its status. If the update is in progress, Get Deployment returns an UpgradeStatus element that contains information about the update. If the update is complete, or if no update is in progress, then the UpgradeStatus element is null. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460800.aspx for more information) The name of the cloud service. The name of your deployment. Parameters supplied to the Begin Walking Upgrade Domain By Deployment Name operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Walking Upgrade Domain By Deployment Slot operation specifies an update domain in which a role instance must be updated. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. Prior to calling the Walk Upgrade Domain operation you must have called Upgrade Deployment, Change Deployment Configuration, or Rollback Update Or Upgrade. By default, a service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To perform a manual update of your deployment, proceed in this order: Call Upgrade Deployment with the Mode element set to manual. Call Walk Upgrade Domain to update each domain within the deployment. Update domains must be updated in order. For example, begin with domain 0, proceed to domain 1, and so on. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. While an update is in progress, call Get Deployment to determine its status. If the update is in progress, Get Deployment returns an UpgradeStatus element that contains information about the update. If the update is complete, or if no update is in progress, then the UpgradeStatus element is null. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460800.aspx for more information) The name of the cloud service. The deployment slot. Parameters supplied to the Begin Walking Upgrade Domain By Deployment Slot operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Change Deployment Configuration By Name operation initiates a change to the deployment configuration. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460809.aspx for more information) The cloud service to change deployment configuration for. The deployment to change configuration for. Parameters supplied to the Change ConfigurationDeployment By Name operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Change Deployment Configuration By Slot operation initiates a change to the deployment configuration. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460809.aspx for more information) The cloud service to change deployment configuration for. The slot to change deployment configuration for. Parameters supplied to the Change Configuration Deployment By Slot operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Create Deployment operation uploads a new service package and creates a new deployment in the staging or production environments. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460813.aspx for more information) The cloud service to create a deployment for. The slot to create a deployment for. Parameters supplied to the Create Deployment operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Deployment By Name operation deletes the specified deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460815.aspx for more information) The name of the cloud service. The name of your deployment. Specifies that the source blob for the disk should also be deleted from storage. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Deployment By Slot operation deletes the specified deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460815.aspx for more information) The name of the cloud service. The deployment slot. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Role Instances operation deletes a role instance from a deployment in a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469418.aspx for more information) The name of the cloud service. The name of the deployment. The parameters to delete the role. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Role Instances operation deletes the role instances from a deployment in a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469418.aspx for more information) The name of the cloud service. The name of the deployment slot. The parameters to delete the role. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Get Deployment By Name operation returns configuration information, status, and system properties for a deployment. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460804.aspx for more information) The name of the cloud service. The name of the deployment. Cancellation token. A deployment that exists in the cloud service. The Get Deployment By Slot operation returns configuration information, status, and system properties for a deployment. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460804.aspx for more information) The name of the cloud service. The deployment slot. Cancellation token. A deployment that exists in the cloud service. The Get Package By Name operation retrieves a cloud service package for a deployment and stores the package files in Azure Blob storage. The following package files are placed in storage: the cloud service configuration file (.cscfg), providing configuration settings for the cloud service and individual roles, including the number of role instances; and the service package (.cspkg), containing the application code and the service definition file. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj154121.aspx for more information) The name of the cloud service. The name of your deployment. Parameters supplied to the Get Package By Name operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Get Package By Slot operation retrieves a cloud service package for a deployment and stores the package files in Azure Blob storage. The following package files are placed in storage: the cloud service configuration file (.cscfg), providing configuration settings for the cloud service and individual roles, including the number of role instances; and the service package (.cspkg), containing the application code and the service definition file. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj154121.aspx for more information) The name of the cloud service. The deployment slot. Parameters supplied to the Get Package By Slot operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Reboot Role Instance By Deployment Name operation requests a reboot of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441298.aspx for more information) The name of the cloud service. The name of your deployment. The name of your role instance. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Reboot Role Instance By Deployment Slot operation requests a reboot of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441298.aspx for more information) The name of the cloud service. The deployment slot. The name of your role instance. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Reimage Role Instance By Deployment Name operation requests a reimage of a role instance that is running in a deployment.This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441292.aspx for more information) The name of the cloud service. The name of your deployment. The name of your role instance. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Reimage Role Instance By Deployment Slot operation requests a reimage of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441292.aspx for more information) The name of the cloud service. The deployment slot. The name of your role instance. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Rollback Update Or Upgrade By Deployment Name operation cancels an in-progress configuration update and returns the deployment to its state before the update was started. This operation can only be called when an update is in progress on the deployment. The deployment status can be detected by calling the Get Deployment operation or Get Hosted Service Properties operation and inspecting the RollbackAllowed element. If the value returned is true a rollback can be performed. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh403977.aspx for more information) The cloud service to swap deployments for. The name of your deployment. Parameters supplied to the Rollback Update Or Upgrade By Deployment Name operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Rollback Update Or Upgrade By Deployment Slot operation cancels an in-progress configuration update and returns the deployment to its state before the update was started. This operation can only be called when an update is in progress on the deployment. The deployment status can be detected by calling the Get Deployment operation or Get Hosted Service Properties operation and inspecting the RollbackAllowed element. If the value returned is true a rollback can be performed. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh403977.aspx for more information) The cloud service to swap deployments for. The deployment slot. Parameters supplied to the Rollback Update Or Upgrade By Deployment Slot operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Swap Deployment operation initiates a virtual IP address swap between the staging and production deployment environments for a service. If the service is currently running in the staging environment, it will be swapped to the production environment. If it is running in the production environment, it will be swapped to staging. For more information on this type of upgrade, see Performing Virtual IP Swap Upgrades at http://msdn.microsoft.com/en-us/library/windowsazure/ee517253.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460814.aspx for more information) The cloud service to swap deployments for. Parameters supplied to the Swap Deployment operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Update Deployment Status By Deployment Name operation initiates a change in the running status of a deployment. The status of a deployment can be running or suspended. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460808.aspx for more information) The cloud service to swap deployments for. The name of your deployment. Parameters supplied to the Update Deployment Status By Deployment Name operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Update Deployment Status By Deployment Slot operation initiates a change in the running status of a deployment. The status of a deployment can be running or suspended. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460808.aspx for more information) The cloud service to swap deployments for. The deployment slot. Parameters supplied to the Update Deployment Status By Deployment Slot operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Upgrade Deployment By Name operation initiates an update of role instances in a deployment using the package and configuration that you specify. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the request has been processed, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. To perform an automatic update of a deployment, call Upgrade Deployment or Change Deployment Configuration with the Mode element set to automatic. The update proceeds from that point without a need for further input. You can call Get Operation Status to determine when the update is complete. To perform a manual update, first call Upgrade Deployment with the Mode element set to manual. Next, call Walk Upgrade Domain to update each domain within the deployment. You should make sure that the operation is complete by calling Get Operation Status before updating the next domain. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. By default, a cloud service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To determine the update domain in which a particular instance is running in Windows Azure, use the UpdateDomain property of the RoleInstance class. See the Azure Managed Library Reference at http://msdn.microsoft.com/en-us/library/windowsazure/dd179380.aspx for more information. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460793.aspx for more information) The cloud service to upgrade. The deployment to upgrade. Parameters supplied to the Upgrade Deployment By Name operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Upgrade Deployment By Slot operation initiates an update of role instances in a deployment using the package and configuration that you specify. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the request has been processed, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. To perform an automatic update of a deployment, call Upgrade Deployment or Change Deployment Configuration with the Mode element set to automatic. The update proceeds from that point without a need for further input. You can call Get Operation Status to determine when the update is complete. To perform a manual update, first call Upgrade Deployment with the Mode element set to manual. Next, call Walk Upgrade Domain to update each domain within the deployment. You should make sure that the operation is complete by calling Get Operation Status before updating the next domain. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. By default, a cloud service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To determine the update domain in which a particular instance is running in Windows Azure, use the UpdateDomain property of the RoleInstance class. See the Azure Managed Library Reference at http://msdn.microsoft.com/en-us/library/windowsazure/dd179380.aspx for more information. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460793.aspx for more information) The cloud service to upgrade. The slot to upgrade. Parameters supplied to the Upgrade Deployment By Slot operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Walk Upgrade Domain By Deployment Name operation specifies an update domain in which a role instance must be updated. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. Prior to calling the Walk Upgrade Domain operation you must have called Upgrade Deployment, Change Deployment Configuration, or Rollback Update Or Upgrade. By default, a service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To perform a manual update of your deployment, proceed in this order: Call Upgrade Deployment with the Mode element set to manual. Call Walk Upgrade Domain to update each domain within the deployment. Update domains must be updated in order. For example, begin with domain 0, proceed to domain 1, and so on. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. While an update is in progress, call Get Deployment to determine its status. If the update is in progress, Get Deployment returns an UpgradeStatus element that contains information about the update. If the update is complete, or if no update is in progress, then the UpgradeStatus element is null. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460800.aspx for more information) The name of the cloud service. The name of your deployment. Parameters supplied to the Walk Upgrade Domain By Deployment Name operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Walk Upgrade Domain By Deployment Slot operation specifies an update domain in which a role instance must be updated. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. Prior to calling the Walk Upgrade Domain operation you must have called Upgrade Deployment, Change Deployment Configuration, or Rollback Update Or Upgrade. By default, a service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To perform a manual update of your deployment, proceed in this order: Call Upgrade Deployment with the Mode element set to manual. Call Walk Upgrade Domain to update each domain within the deployment. Update domains must be updated in order. For example, begin with domain 0, proceed to domain 1, and so on. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. While an update is in progress, call Get Deployment to determine its status. If the update is in progress, Get Deployment returns an UpgradeStatus element that contains information about the update. If the update is complete, or if no update is in progress, then the UpgradeStatus element is null. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460800.aspx for more information) The name of the cloud service. The deployment slot. Parameters supplied to the Walk Upgrade Domain By Deployment Slot operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Initializes a new instance of the DeploymentOperations class. Reference to the service client. The Begin Changing Deployment Configuration By Name operation initiates a change to the deployment configuration. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460809.aspx for more information) Required. The cloud service to change deployment configuration for. Required. The deployment to change configuration for. Required. Parameters supplied to the Begin Changing Configuration Deployment By Name operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Changing Deployment Configuration By Slot operation initiates a change to the deployment configuration. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460809.aspx for more information) Required. The cloud service to change deployment configuration for. Required. The slot to change deployment configuration for. Required. Parameters supplied to the Begin Changing Configuration Deployment By Slot operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Creating Deployment operation uploads a new service package and creates a new deployment in the staging or production environments. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460813.aspx for more information) Required. The cloud service to create a deployment for. Required. The slot to create a deployment for. Required. Parameters supplied to the Begin Creating Deployment operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Deleting Deployment By Name operation deletes the specified deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460815.aspx for more information) Required. The name of the cloud service. Required. The name of your deployment. Required. Specifies that the source blob for the disk should also be deleted from storage. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Deleting Deployment By Slot operation deletes the specified deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460815.aspx for more information) Required. The name of the cloud service. Required. The deployment slot. Cancellation token. A standard service response including an HTTP status code and request ID. The Delete Role Instances operation deletes a role instance from a deployment in a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469418.aspx for more information) Required. The name of the cloud service. Required. The name of the deployment slot. Required. The parameters to delete the role. Cancellation token. A standard service response including an HTTP status code and request ID. The Delete Role Instances operation deletes a role instance from a deployment in a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469418.aspx for more information) Required. The name of the cloud service. Required. The name of the deployment. Required. The parameters to delete the role. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Rebooting Role Instance By Deployment Name operation requests a reboot of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441298.aspx for more information) Required. The name of the cloud service. Required. The name of your deployment. Required. The name of your role instance. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Rebooting Role Instance By Deployment Slot operation requests a reboot of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441298.aspx for more information) Required. The name of the cloud service. Required. The deployment slot. Required. The name of your role instance. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Reimaging Role Instance By Deployment Name operation requests a reimage of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441292.aspx for more information) Required. The name of the cloud service. Required. The name of your deployment. Required. The name of your role instance. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Reimaging Role Instance By Deployment Slot operation requests a reimage of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441292.aspx for more information) Required. The name of the cloud service. Required. The deployment slot. Required. The name of your role instance. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Swapping Deployment operation initiates a virtual IP address swap between the staging and production deployment environments for a service. If the service is currently running in the staging environment, it will be swapped to the production environment. If it is running in the production environment, it will be swapped to staging. For more information on this type of upgrade, see Performing Virtual IP Swap Upgrades at http://msdn.microsoft.com/en-us/library/windowsazure/ee517253.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460814.aspx for more information) Required. The cloud service to swap deployments for. Required. Parameters supplied to the Begin Swapping Deployment operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Updating Deployment Status By Deployment Name operation initiates a change in the running status of a deployment. The status of a deployment can be running or suspended. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460808.aspx for more information) Required. The cloud service to swap deployments for. Required. The name of your deployment. Required. Parameters supplied to the Begin Updating Deployment Status By Deployment Name operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Updating Deployment Status By Deployment Slot operation initiates a change in the running status of a deployment. The status of a deployment can be running or suspended. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460808.aspx for more information) Required. The cloud service to swap deployments for. Required. The deployment slot. Required. Parameters supplied to the Begin Updating Deployment Status By Deployment Slot operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Upgrading Deployment By Name operation initiates an update of role instances in a deployment using the package and configuration that you specify. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the request has been processed, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. To perform an automatic update of a deployment, call Upgrade Deployment or Change Deployment Configuration with the Mode element set to automatic. The update proceeds from that point without a need for further input. You can call Get Operation Status to determine when the update is complete. To perform a manual update, first call Upgrade Deployment with the Mode element set to manual. Next, call Walk Upgrade Domain to update each domain within the deployment. You should make sure that the operation is complete by calling Get Operation Status before updating the next domain. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. By default, a cloud service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To determine the update domain in which a particular instance is running in Windows Azure, use the UpdateDomain property of the RoleInstance class. See the Azure Managed Library Reference at http://msdn.microsoft.com/en-us/library/windowsazure/dd179380.aspx for more information. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460793.aspx for more information) Required. The cloud service to upgrade. Required. The deployment to upgrade. Required. Parameters supplied to the Begin Upgrading Deployment By Name operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Upgrading Deployment By Slot operation initiates an update of role instances in a deployment using the package and configuration that you specify. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx.This operation is an asynchronous operation. To determine whether the request has been processed, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. To perform an automatic update of a deployment, call Upgrade Deployment or Change Deployment Configuration with the Mode element set to automatic. The update proceeds from that point without a need for further input. You can call Get Operation Status to determine when the update is complete. To perform a manual update, first call Upgrade Deployment with the Mode element set to manual. Next, call Walk Upgrade Domain to update each domain within the deployment. You should make sure that the operation is complete by calling Get Operation Status before updating the next domain. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. By default, a cloud service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To determine the update domain in which a particular instance is running in Windows Azure, use the UpdateDomain property of the RoleInstance class. See the Azure Managed Library Reference at http://msdn.microsoft.com/en-us/library/windowsazure/dd179380.aspx for more information. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460793.aspx for more information) Required. The cloud service to upgrade. Required. The slot to upgrade. Required. Parameters supplied to the Begin Upgrading Deployment By Slot operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Walking Upgrade Domain By Deployment Name operation specifies an update domain in which a role instance must be updated. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. Prior to calling the Walk Upgrade Domain operation you must have called Upgrade Deployment, Change Deployment Configuration, or Rollback Update Or Upgrade. By default, a service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To perform a manual update of your deployment, proceed in this order: Call Upgrade Deployment with the Mode element set to manual. Call Walk Upgrade Domain to update each domain within the deployment. Update domains must be updated in order. For example, begin with domain 0, proceed to domain 1, and so on. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. While an update is in progress, call Get Deployment to determine its status. If the update is in progress, Get Deployment returns an UpgradeStatus element that contains information about the update. If the update is complete, or if no update is in progress, then the UpgradeStatus element is null. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460800.aspx for more information) Required. The name of the cloud service. Required. The name of your deployment. Required. Parameters supplied to the Begin Walking Upgrade Domain By Deployment Name operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Walking Upgrade Domain By Deployment Slot operation specifies an update domain in which a role instance must be updated. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. Prior to calling the Walk Upgrade Domain operation you must have called Upgrade Deployment, Change Deployment Configuration, or Rollback Update Or Upgrade. By default, a service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To perform a manual update of your deployment, proceed in this order: Call Upgrade Deployment with the Mode element set to manual. Call Walk Upgrade Domain to update each domain within the deployment. Update domains must be updated in order. For example, begin with domain 0, proceed to domain 1, and so on. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. While an update is in progress, call Get Deployment to determine its status. If the update is in progress, Get Deployment returns an UpgradeStatus element that contains information about the update. If the update is complete, or if no update is in progress, then the UpgradeStatus element is null. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460800.aspx for more information) Required. The name of the cloud service. Required. The deployment slot. Required. Parameters supplied to the Begin Walking Upgrade Domain By Deployment Slot operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Change Deployment Configuration By Name operation initiates a change to the deployment configuration. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460809.aspx for more information) Required. The cloud service to change deployment configuration for. Required. The deployment to change configuration for. Required. Parameters supplied to the Change ConfigurationDeployment By Name operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Change Deployment Configuration By Slot operation initiates a change to the deployment configuration. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460809.aspx for more information) Required. The cloud service to change deployment configuration for. Required. The slot to change deployment configuration for. Required. Parameters supplied to the Change Configuration Deployment By Slot operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Create Deployment operation uploads a new service package and creates a new deployment in the staging or production environments. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460813.aspx for more information) Required. The cloud service to create a deployment for. Required. The slot to create a deployment for. Required. Parameters supplied to the Create Deployment operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Deployment By Name operation deletes the specified deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460815.aspx for more information) Required. The name of the cloud service. Required. The name of your deployment. Required. Specifies that the source blob for the disk should also be deleted from storage. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Deployment By Slot operation deletes the specified deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460815.aspx for more information) Required. The name of the cloud service. Required. The deployment slot. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Role Instances operation deletes a role instance from a deployment in a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469418.aspx for more information) Required. The name of the cloud service. Required. The name of the deployment. Required. The parameters to delete the role. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Role Instances operation deletes the role instances from a deployment in a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469418.aspx for more information) Required. The name of the cloud service. Required. The name of the deployment slot. Required. The parameters to delete the role. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Get Deployment By Name operation returns configuration information, status, and system properties for a deployment. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460804.aspx for more information) Required. The name of the cloud service. Required. The name of the deployment. Cancellation token. A deployment that exists in the cloud service. The Get Deployment By Slot operation returns configuration information, status, and system properties for a deployment. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460804.aspx for more information) Required. The name of the cloud service. Required. The deployment slot. Cancellation token. A deployment that exists in the cloud service. The Get Package By Name operation retrieves a cloud service package for a deployment and stores the package files in Azure Blob storage. The following package files are placed in storage: the cloud service configuration file (.cscfg), providing configuration settings for the cloud service and individual roles, including the number of role instances; and the service package (.cspkg), containing the application code and the service definition file. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj154121.aspx for more information) Required. The name of the cloud service. Required. The name of your deployment. Required. Parameters supplied to the Get Package By Name operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Get Package By Slot operation retrieves a cloud service package for a deployment and stores the package files in Azure Blob storage. The following package files are placed in storage: the cloud service configuration file (.cscfg), providing configuration settings for the cloud service and individual roles, including the number of role instances; and the service package (.cspkg), containing the application code and the service definition file. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj154121.aspx for more information) Required. The name of the cloud service. Required. The deployment slot. Required. Parameters supplied to the Get Package By Slot operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Reboot Role Instance By Deployment Name operation requests a reboot of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441298.aspx for more information) Required. The name of the cloud service. Required. The name of your deployment. Required. The name of your role instance. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Reboot Role Instance By Deployment Slot operation requests a reboot of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441298.aspx for more information) Required. The name of the cloud service. Required. The deployment slot. Required. The name of your role instance. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Reimage Role Instance By Deployment Name operation requests a reimage of a role instance that is running in a deployment.This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441292.aspx for more information) Required. The name of the cloud service. Required. The name of your deployment. Required. The name of your role instance. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Reimage Role Instance By Deployment Slot operation requests a reimage of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441292.aspx for more information) Required. The name of the cloud service. Required. The deployment slot. Required. The name of your role instance. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Rollback Update Or Upgrade By Deployment Name operation cancels an in-progress configuration update and returns the deployment to its state before the update was started. This operation can only be called when an update is in progress on the deployment. The deployment status can be detected by calling the Get Deployment operation or Get Hosted Service Properties operation and inspecting the RollbackAllowed element. If the value returned is true a rollback can be performed. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh403977.aspx for more information) Required. The cloud service to swap deployments for. Required. The name of your deployment. Required. Parameters supplied to the Rollback Update Or Upgrade By Deployment Name operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Rollback Update Or Upgrade By Deployment Slot operation cancels an in-progress configuration update and returns the deployment to its state before the update was started. This operation can only be called when an update is in progress on the deployment. The deployment status can be detected by calling the Get Deployment operation or Get Hosted Service Properties operation and inspecting the RollbackAllowed element. If the value returned is true a rollback can be performed. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh403977.aspx for more information) Required. The cloud service to swap deployments for. Required. The deployment slot. Required. Parameters supplied to the Rollback Update Or Upgrade By Deployment Slot operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Swap Deployment operation initiates a virtual IP address swap between the staging and production deployment environments for a service. If the service is currently running in the staging environment, it will be swapped to the production environment. If it is running in the production environment, it will be swapped to staging. For more information on this type of upgrade, see Performing Virtual IP Swap Upgrades at http://msdn.microsoft.com/en-us/library/windowsazure/ee517253.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460814.aspx for more information) Required. The cloud service to swap deployments for. Required. Parameters supplied to the Swap Deployment operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Update Deployment Status By Deployment Name operation initiates a change in the running status of a deployment. The status of a deployment can be running or suspended. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460808.aspx for more information) Required. The cloud service to swap deployments for. Required. The name of your deployment. Required. Parameters supplied to the Update Deployment Status By Deployment Name operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Update Deployment Status By Deployment Slot operation initiates a change in the running status of a deployment. The status of a deployment can be running or suspended. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460808.aspx for more information) Required. The cloud service to swap deployments for. Required. The deployment slot. Required. Parameters supplied to the Update Deployment Status By Deployment Slot operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Upgrade Deployment By Name operation initiates an update of role instances in a deployment using the package and configuration that you specify. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the request has been processed, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. To perform an automatic update of a deployment, call Upgrade Deployment or Change Deployment Configuration with the Mode element set to automatic. The update proceeds from that point without a need for further input. You can call Get Operation Status to determine when the update is complete. To perform a manual update, first call Upgrade Deployment with the Mode element set to manual. Next, call Walk Upgrade Domain to update each domain within the deployment. You should make sure that the operation is complete by calling Get Operation Status before updating the next domain. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. By default, a cloud service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To determine the update domain in which a particular instance is running in Windows Azure, use the UpdateDomain property of the RoleInstance class. See the Azure Managed Library Reference at http://msdn.microsoft.com/en-us/library/windowsazure/dd179380.aspx for more information. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460793.aspx for more information) Required. The cloud service to upgrade. Required. The deployment to upgrade. Required. Parameters supplied to the Upgrade Deployment By Name operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Upgrade Deployment By Slot operation initiates an update of role instances in a deployment using the package and configuration that you specify. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the request has been processed, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. To perform an automatic update of a deployment, call Upgrade Deployment or Change Deployment Configuration with the Mode element set to automatic. The update proceeds from that point without a need for further input. You can call Get Operation Status to determine when the update is complete. To perform a manual update, first call Upgrade Deployment with the Mode element set to manual. Next, call Walk Upgrade Domain to update each domain within the deployment. You should make sure that the operation is complete by calling Get Operation Status before updating the next domain. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. By default, a cloud service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To determine the update domain in which a particular instance is running in Windows Azure, use the UpdateDomain property of the RoleInstance class. See the Azure Managed Library Reference at http://msdn.microsoft.com/en-us/library/windowsazure/dd179380.aspx for more information. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460793.aspx for more information) Required. The cloud service to upgrade. Required. The slot to upgrade. Required. Parameters supplied to the Upgrade Deployment By Slot operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Walk Upgrade Domain By Deployment Name operation specifies an update domain in which a role instance must be updated. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. Prior to calling the Walk Upgrade Domain operation you must have called Upgrade Deployment, Change Deployment Configuration, or Rollback Update Or Upgrade. By default, a service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To perform a manual update of your deployment, proceed in this order: Call Upgrade Deployment with the Mode element set to manual. Call Walk Upgrade Domain to update each domain within the deployment. Update domains must be updated in order. For example, begin with domain 0, proceed to domain 1, and so on. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. While an update is in progress, call Get Deployment to determine its status. If the update is in progress, Get Deployment returns an UpgradeStatus element that contains information about the update. If the update is complete, or if no update is in progress, then the UpgradeStatus element is null. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460800.aspx for more information) Required. The name of the cloud service. Required. The name of your deployment. Required. Parameters supplied to the Walk Upgrade Domain By Deployment Name operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Walk Upgrade Domain By Deployment Slot operation specifies an update domain in which a role instance must be updated. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. Prior to calling the Walk Upgrade Domain operation you must have called Upgrade Deployment, Change Deployment Configuration, or Rollback Update Or Upgrade. By default, a service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To perform a manual update of your deployment, proceed in this order: Call Upgrade Deployment with the Mode element set to manual. Call Walk Upgrade Domain to update each domain within the deployment. Update domains must be updated in order. For example, begin with domain 0, proceed to domain 1, and so on. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. While an update is in progress, call Get Deployment to determine its status. If the update is in progress, Get Deployment returns an UpgradeStatus element that contains information about the update. If the update is complete, or if no update is in progress, then the UpgradeStatus element is null. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460800.aspx for more information) Required. The name of the cloud service. Required. The deployment slot. Required. Parameters supplied to the Walk Upgrade Domain By Deployment Slot operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Gets a reference to the Microsoft.WindowsAzure.Management.Compute.ComputeManagementClient. The Service Management API provides programmatic access to much of the functionality available through the Management Portal. The Service Management API is a REST API. All API operations are performed over SSL, and are mutually authenticated using X.509 v3 certificates. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460799.aspx for more information) The Begin Changing Deployment Configuration By Name operation initiates a change to the deployment configuration. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460809.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to change deployment configuration for. Required. The deployment to change configuration for. Required. Parameters supplied to the Begin Changing Configuration Deployment By Name operation. A standard service response including an HTTP status code and request ID. The Begin Changing Deployment Configuration By Name operation initiates a change to the deployment configuration. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460809.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to change deployment configuration for. Required. The deployment to change configuration for. Required. Parameters supplied to the Begin Changing Configuration Deployment By Name operation. A standard service response including an HTTP status code and request ID. The Begin Changing Deployment Configuration By Slot operation initiates a change to the deployment configuration. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460809.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to change deployment configuration for. Required. The slot to change deployment configuration for. Required. Parameters supplied to the Begin Changing Configuration Deployment By Slot operation. A standard service response including an HTTP status code and request ID. The Begin Changing Deployment Configuration By Slot operation initiates a change to the deployment configuration. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460809.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to change deployment configuration for. Required. The slot to change deployment configuration for. Required. Parameters supplied to the Begin Changing Configuration Deployment By Slot operation. A standard service response including an HTTP status code and request ID. The Begin Creating Deployment operation uploads a new service package and creates a new deployment in the staging or production environments. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460813.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to create a deployment for. Required. The slot to create a deployment for. Required. Parameters supplied to the Begin Creating Deployment operation. A standard service response including an HTTP status code and request ID. The Begin Creating Deployment operation uploads a new service package and creates a new deployment in the staging or production environments. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460813.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to create a deployment for. Required. The slot to create a deployment for. Required. Parameters supplied to the Begin Creating Deployment operation. A standard service response including an HTTP status code and request ID. The Begin Deleting Deployment By Name operation deletes the specified deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460815.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of your deployment. Required. Specifies that the source blob for the disk should also be deleted from storage. A standard service response including an HTTP status code and request ID. The Begin Deleting Deployment By Name operation deletes the specified deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460815.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of your deployment. Required. Specifies that the source blob for the disk should also be deleted from storage. A standard service response including an HTTP status code and request ID. The Begin Deleting Deployment By Slot operation deletes the specified deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460815.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The deployment slot. A standard service response including an HTTP status code and request ID. The Begin Deleting Deployment By Slot operation deletes the specified deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460815.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The deployment slot. A standard service response including an HTTP status code and request ID. The Delete Role Instances operation deletes a role instance from a deployment in a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469418.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of the deployment slot. Required. The parameters to delete the role. A standard service response including an HTTP status code and request ID. The Delete Role Instances operation deletes a role instance from a deployment in a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469418.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of the deployment slot. Required. The parameters to delete the role. A standard service response including an HTTP status code and request ID. The Delete Role Instances operation deletes a role instance from a deployment in a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469418.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of the deployment. Required. The parameters to delete the role. A standard service response including an HTTP status code and request ID. The Delete Role Instances operation deletes a role instance from a deployment in a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469418.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of the deployment. Required. The parameters to delete the role. A standard service response including an HTTP status code and request ID. The Begin Rebooting Role Instance By Deployment Name operation requests a reboot of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441298.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of your deployment. Required. The name of your role instance. A standard service response including an HTTP status code and request ID. The Begin Rebooting Role Instance By Deployment Name operation requests a reboot of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441298.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of your deployment. Required. The name of your role instance. A standard service response including an HTTP status code and request ID. The Begin Rebooting Role Instance By Deployment Slot operation requests a reboot of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441298.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The deployment slot. Required. The name of your role instance. A standard service response including an HTTP status code and request ID. The Begin Rebooting Role Instance By Deployment Slot operation requests a reboot of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441298.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The deployment slot. Required. The name of your role instance. A standard service response including an HTTP status code and request ID. The Begin Reimaging Role Instance By Deployment Name operation requests a reimage of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441292.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of your deployment. Required. The name of your role instance. A standard service response including an HTTP status code and request ID. The Begin Reimaging Role Instance By Deployment Name operation requests a reimage of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441292.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of your deployment. Required. The name of your role instance. A standard service response including an HTTP status code and request ID. The Begin Reimaging Role Instance By Deployment Slot operation requests a reimage of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441292.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The deployment slot. Required. The name of your role instance. A standard service response including an HTTP status code and request ID. The Begin Reimaging Role Instance By Deployment Slot operation requests a reimage of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441292.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The deployment slot. Required. The name of your role instance. A standard service response including an HTTP status code and request ID. The Begin Swapping Deployment operation initiates a virtual IP address swap between the staging and production deployment environments for a service. If the service is currently running in the staging environment, it will be swapped to the production environment. If it is running in the production environment, it will be swapped to staging. For more information on this type of upgrade, see Performing Virtual IP Swap Upgrades at http://msdn.microsoft.com/en-us/library/windowsazure/ee517253.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460814.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to swap deployments for. Required. Parameters supplied to the Begin Swapping Deployment operation. A standard service response including an HTTP status code and request ID. The Begin Swapping Deployment operation initiates a virtual IP address swap between the staging and production deployment environments for a service. If the service is currently running in the staging environment, it will be swapped to the production environment. If it is running in the production environment, it will be swapped to staging. For more information on this type of upgrade, see Performing Virtual IP Swap Upgrades at http://msdn.microsoft.com/en-us/library/windowsazure/ee517253.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460814.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to swap deployments for. Required. Parameters supplied to the Begin Swapping Deployment operation. A standard service response including an HTTP status code and request ID. The Begin Updating Deployment Status By Deployment Name operation initiates a change in the running status of a deployment. The status of a deployment can be running or suspended. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460808.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to swap deployments for. Required. The name of your deployment. Required. Parameters supplied to the Begin Updating Deployment Status By Deployment Name operation. A standard service response including an HTTP status code and request ID. The Begin Updating Deployment Status By Deployment Name operation initiates a change in the running status of a deployment. The status of a deployment can be running or suspended. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460808.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to swap deployments for. Required. The name of your deployment. Required. Parameters supplied to the Begin Updating Deployment Status By Deployment Name operation. A standard service response including an HTTP status code and request ID. The Begin Updating Deployment Status By Deployment Slot operation initiates a change in the running status of a deployment. The status of a deployment can be running or suspended. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460808.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to swap deployments for. Required. The deployment slot. Required. Parameters supplied to the Begin Updating Deployment Status By Deployment Slot operation. A standard service response including an HTTP status code and request ID. The Begin Updating Deployment Status By Deployment Slot operation initiates a change in the running status of a deployment. The status of a deployment can be running or suspended. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460808.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to swap deployments for. Required. The deployment slot. Required. Parameters supplied to the Begin Updating Deployment Status By Deployment Slot operation. A standard service response including an HTTP status code and request ID. The Begin Upgrading Deployment By Name operation initiates an update of role instances in a deployment using the package and configuration that you specify. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the request has been processed, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. To perform an automatic update of a deployment, call Upgrade Deployment or Change Deployment Configuration with the Mode element set to automatic. The update proceeds from that point without a need for further input. You can call Get Operation Status to determine when the update is complete. To perform a manual update, first call Upgrade Deployment with the Mode element set to manual. Next, call Walk Upgrade Domain to update each domain within the deployment. You should make sure that the operation is complete by calling Get Operation Status before updating the next domain. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. By default, a cloud service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To determine the update domain in which a particular instance is running in Windows Azure, use the UpdateDomain property of the RoleInstance class. See the Azure Managed Library Reference at http://msdn.microsoft.com/en-us/library/windowsazure/dd179380.aspx for more information. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460793.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to upgrade. Required. The deployment to upgrade. Required. Parameters supplied to the Begin Upgrading Deployment By Name operation. A standard service response including an HTTP status code and request ID. The Begin Upgrading Deployment By Name operation initiates an update of role instances in a deployment using the package and configuration that you specify. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the request has been processed, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. To perform an automatic update of a deployment, call Upgrade Deployment or Change Deployment Configuration with the Mode element set to automatic. The update proceeds from that point without a need for further input. You can call Get Operation Status to determine when the update is complete. To perform a manual update, first call Upgrade Deployment with the Mode element set to manual. Next, call Walk Upgrade Domain to update each domain within the deployment. You should make sure that the operation is complete by calling Get Operation Status before updating the next domain. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. By default, a cloud service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To determine the update domain in which a particular instance is running in Windows Azure, use the UpdateDomain property of the RoleInstance class. See the Azure Managed Library Reference at http://msdn.microsoft.com/en-us/library/windowsazure/dd179380.aspx for more information. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460793.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to upgrade. Required. The deployment to upgrade. Required. Parameters supplied to the Begin Upgrading Deployment By Name operation. A standard service response including an HTTP status code and request ID. The Begin Upgrading Deployment By Slot operation initiates an update of role instances in a deployment using the package and configuration that you specify. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx.This operation is an asynchronous operation. To determine whether the request has been processed, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. To perform an automatic update of a deployment, call Upgrade Deployment or Change Deployment Configuration with the Mode element set to automatic. The update proceeds from that point without a need for further input. You can call Get Operation Status to determine when the update is complete. To perform a manual update, first call Upgrade Deployment with the Mode element set to manual. Next, call Walk Upgrade Domain to update each domain within the deployment. You should make sure that the operation is complete by calling Get Operation Status before updating the next domain. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. By default, a cloud service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To determine the update domain in which a particular instance is running in Windows Azure, use the UpdateDomain property of the RoleInstance class. See the Azure Managed Library Reference at http://msdn.microsoft.com/en-us/library/windowsazure/dd179380.aspx for more information. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460793.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to upgrade. Required. The slot to upgrade. Required. Parameters supplied to the Begin Upgrading Deployment By Slot operation. A standard service response including an HTTP status code and request ID. The Begin Upgrading Deployment By Slot operation initiates an update of role instances in a deployment using the package and configuration that you specify. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx.This operation is an asynchronous operation. To determine whether the request has been processed, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. To perform an automatic update of a deployment, call Upgrade Deployment or Change Deployment Configuration with the Mode element set to automatic. The update proceeds from that point without a need for further input. You can call Get Operation Status to determine when the update is complete. To perform a manual update, first call Upgrade Deployment with the Mode element set to manual. Next, call Walk Upgrade Domain to update each domain within the deployment. You should make sure that the operation is complete by calling Get Operation Status before updating the next domain. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. By default, a cloud service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To determine the update domain in which a particular instance is running in Windows Azure, use the UpdateDomain property of the RoleInstance class. See the Azure Managed Library Reference at http://msdn.microsoft.com/en-us/library/windowsazure/dd179380.aspx for more information. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460793.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to upgrade. Required. The slot to upgrade. Required. Parameters supplied to the Begin Upgrading Deployment By Slot operation. A standard service response including an HTTP status code and request ID. The Begin Walking Upgrade Domain By Deployment Name operation specifies an update domain in which a role instance must be updated. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. Prior to calling the Walk Upgrade Domain operation you must have called Upgrade Deployment, Change Deployment Configuration, or Rollback Update Or Upgrade. By default, a service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To perform a manual update of your deployment, proceed in this order: Call Upgrade Deployment with the Mode element set to manual. Call Walk Upgrade Domain to update each domain within the deployment. Update domains must be updated in order. For example, begin with domain 0, proceed to domain 1, and so on. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. While an update is in progress, call Get Deployment to determine its status. If the update is in progress, Get Deployment returns an UpgradeStatus element that contains information about the update. If the update is complete, or if no update is in progress, then the UpgradeStatus element is null. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460800.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of your deployment. Required. Parameters supplied to the Begin Walking Upgrade Domain By Deployment Name operation. A standard service response including an HTTP status code and request ID. The Begin Walking Upgrade Domain By Deployment Name operation specifies an update domain in which a role instance must be updated. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. Prior to calling the Walk Upgrade Domain operation you must have called Upgrade Deployment, Change Deployment Configuration, or Rollback Update Or Upgrade. By default, a service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To perform a manual update of your deployment, proceed in this order: Call Upgrade Deployment with the Mode element set to manual. Call Walk Upgrade Domain to update each domain within the deployment. Update domains must be updated in order. For example, begin with domain 0, proceed to domain 1, and so on. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. While an update is in progress, call Get Deployment to determine its status. If the update is in progress, Get Deployment returns an UpgradeStatus element that contains information about the update. If the update is complete, or if no update is in progress, then the UpgradeStatus element is null. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460800.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of your deployment. Required. Parameters supplied to the Begin Walking Upgrade Domain By Deployment Name operation. A standard service response including an HTTP status code and request ID. The Begin Walking Upgrade Domain By Deployment Slot operation specifies an update domain in which a role instance must be updated. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. Prior to calling the Walk Upgrade Domain operation you must have called Upgrade Deployment, Change Deployment Configuration, or Rollback Update Or Upgrade. By default, a service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To perform a manual update of your deployment, proceed in this order: Call Upgrade Deployment with the Mode element set to manual. Call Walk Upgrade Domain to update each domain within the deployment. Update domains must be updated in order. For example, begin with domain 0, proceed to domain 1, and so on. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. While an update is in progress, call Get Deployment to determine its status. If the update is in progress, Get Deployment returns an UpgradeStatus element that contains information about the update. If the update is complete, or if no update is in progress, then the UpgradeStatus element is null. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460800.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The deployment slot. Required. Parameters supplied to the Begin Walking Upgrade Domain By Deployment Slot operation. A standard service response including an HTTP status code and request ID. The Begin Walking Upgrade Domain By Deployment Slot operation specifies an update domain in which a role instance must be updated. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. Prior to calling the Walk Upgrade Domain operation you must have called Upgrade Deployment, Change Deployment Configuration, or Rollback Update Or Upgrade. By default, a service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To perform a manual update of your deployment, proceed in this order: Call Upgrade Deployment with the Mode element set to manual. Call Walk Upgrade Domain to update each domain within the deployment. Update domains must be updated in order. For example, begin with domain 0, proceed to domain 1, and so on. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. While an update is in progress, call Get Deployment to determine its status. If the update is in progress, Get Deployment returns an UpgradeStatus element that contains information about the update. If the update is complete, or if no update is in progress, then the UpgradeStatus element is null. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460800.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The deployment slot. Required. Parameters supplied to the Begin Walking Upgrade Domain By Deployment Slot operation. A standard service response including an HTTP status code and request ID. The Change Deployment Configuration By Name operation initiates a change to the deployment configuration. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460809.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to change deployment configuration for. Required. The deployment to change configuration for. Required. Parameters supplied to the Change ConfigurationDeployment By Name operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Change Deployment Configuration By Name operation initiates a change to the deployment configuration. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460809.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to change deployment configuration for. Required. The deployment to change configuration for. Required. Parameters supplied to the Change ConfigurationDeployment By Name operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Change Deployment Configuration By Slot operation initiates a change to the deployment configuration. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460809.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to change deployment configuration for. Required. The slot to change deployment configuration for. Required. Parameters supplied to the Change Configuration Deployment By Slot operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Change Deployment Configuration By Slot operation initiates a change to the deployment configuration. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460809.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to change deployment configuration for. Required. The slot to change deployment configuration for. Required. Parameters supplied to the Change Configuration Deployment By Slot operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Create Deployment operation uploads a new service package and creates a new deployment in the staging or production environments. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460813.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to create a deployment for. Required. The slot to create a deployment for. Required. Parameters supplied to the Create Deployment operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Create Deployment operation uploads a new service package and creates a new deployment in the staging or production environments. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460813.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to create a deployment for. Required. The slot to create a deployment for. Required. Parameters supplied to the Create Deployment operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Deployment By Name operation deletes the specified deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460815.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of your deployment. Required. Specifies that the source blob for the disk should also be deleted from storage. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Deployment By Name operation deletes the specified deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460815.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of your deployment. Required. Specifies that the source blob for the disk should also be deleted from storage. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Deployment By Slot operation deletes the specified deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460815.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The deployment slot. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Deployment By Slot operation deletes the specified deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460815.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The deployment slot. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Role Instances operation deletes a role instance from a deployment in a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469418.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of the deployment. Required. The parameters to delete the role. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Role Instances operation deletes a role instance from a deployment in a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469418.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of the deployment. Required. The parameters to delete the role. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Role Instances operation deletes the role instances from a deployment in a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469418.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of the deployment slot. Required. The parameters to delete the role. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Role Instances operation deletes the role instances from a deployment in a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469418.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of the deployment slot. Required. The parameters to delete the role. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Get Deployment By Name operation returns configuration information, status, and system properties for a deployment. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460804.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of the deployment. A deployment that exists in the cloud service. The Get Deployment By Name operation returns configuration information, status, and system properties for a deployment. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460804.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of the deployment. A deployment that exists in the cloud service. The Get Deployment By Slot operation returns configuration information, status, and system properties for a deployment. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460804.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The deployment slot. A deployment that exists in the cloud service. The Get Deployment By Slot operation returns configuration information, status, and system properties for a deployment. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460804.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The deployment slot. A deployment that exists in the cloud service. The Get Package By Name operation retrieves a cloud service package for a deployment and stores the package files in Azure Blob storage. The following package files are placed in storage: the cloud service configuration file (.cscfg), providing configuration settings for the cloud service and individual roles, including the number of role instances; and the service package (.cspkg), containing the application code and the service definition file. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj154121.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of your deployment. Required. Parameters supplied to the Get Package By Name operation. A standard service response including an HTTP status code and request ID. The Get Package By Name operation retrieves a cloud service package for a deployment and stores the package files in Azure Blob storage. The following package files are placed in storage: the cloud service configuration file (.cscfg), providing configuration settings for the cloud service and individual roles, including the number of role instances; and the service package (.cspkg), containing the application code and the service definition file. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj154121.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of your deployment. Required. Parameters supplied to the Get Package By Name operation. A standard service response including an HTTP status code and request ID. The Get Package By Slot operation retrieves a cloud service package for a deployment and stores the package files in Azure Blob storage. The following package files are placed in storage: the cloud service configuration file (.cscfg), providing configuration settings for the cloud service and individual roles, including the number of role instances; and the service package (.cspkg), containing the application code and the service definition file. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj154121.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The deployment slot. Required. Parameters supplied to the Get Package By Slot operation. A standard service response including an HTTP status code and request ID. The Get Package By Slot operation retrieves a cloud service package for a deployment and stores the package files in Azure Blob storage. The following package files are placed in storage: the cloud service configuration file (.cscfg), providing configuration settings for the cloud service and individual roles, including the number of role instances; and the service package (.cspkg), containing the application code and the service definition file. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj154121.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The deployment slot. Required. Parameters supplied to the Get Package By Slot operation. A standard service response including an HTTP status code and request ID. The Reboot Role Instance By Deployment Name operation requests a reboot of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441298.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of your deployment. Required. The name of your role instance. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Reboot Role Instance By Deployment Name operation requests a reboot of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441298.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of your deployment. Required. The name of your role instance. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Reboot Role Instance By Deployment Slot operation requests a reboot of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441298.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The deployment slot. Required. The name of your role instance. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Reboot Role Instance By Deployment Slot operation requests a reboot of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441298.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The deployment slot. Required. The name of your role instance. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Reimage Role Instance By Deployment Name operation requests a reimage of a role instance that is running in a deployment.This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441292.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of your deployment. Required. The name of your role instance. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Reimage Role Instance By Deployment Name operation requests a reimage of a role instance that is running in a deployment.This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441292.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of your deployment. Required. The name of your role instance. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Reimage Role Instance By Deployment Slot operation requests a reimage of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441292.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The deployment slot. Required. The name of your role instance. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Reimage Role Instance By Deployment Slot operation requests a reimage of a role instance that is running in a deployment. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441292.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The deployment slot. Required. The name of your role instance. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Rollback Update Or Upgrade By Deployment Name operation cancels an in-progress configuration update and returns the deployment to its state before the update was started. This operation can only be called when an update is in progress on the deployment. The deployment status can be detected by calling the Get Deployment operation or Get Hosted Service Properties operation and inspecting the RollbackAllowed element. If the value returned is true a rollback can be performed. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh403977.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to swap deployments for. Required. The name of your deployment. Required. Parameters supplied to the Rollback Update Or Upgrade By Deployment Name operation. A standard service response including an HTTP status code and request ID. The Rollback Update Or Upgrade By Deployment Name operation cancels an in-progress configuration update and returns the deployment to its state before the update was started. This operation can only be called when an update is in progress on the deployment. The deployment status can be detected by calling the Get Deployment operation or Get Hosted Service Properties operation and inspecting the RollbackAllowed element. If the value returned is true a rollback can be performed. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh403977.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to swap deployments for. Required. The name of your deployment. Required. Parameters supplied to the Rollback Update Or Upgrade By Deployment Name operation. A standard service response including an HTTP status code and request ID. The Rollback Update Or Upgrade By Deployment Slot operation cancels an in-progress configuration update and returns the deployment to its state before the update was started. This operation can only be called when an update is in progress on the deployment. The deployment status can be detected by calling the Get Deployment operation or Get Hosted Service Properties operation and inspecting the RollbackAllowed element. If the value returned is true a rollback can be performed. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh403977.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to swap deployments for. Required. The deployment slot. Required. Parameters supplied to the Rollback Update Or Upgrade By Deployment Slot operation. A standard service response including an HTTP status code and request ID. The Rollback Update Or Upgrade By Deployment Slot operation cancels an in-progress configuration update and returns the deployment to its state before the update was started. This operation can only be called when an update is in progress on the deployment. The deployment status can be detected by calling the Get Deployment operation or Get Hosted Service Properties operation and inspecting the RollbackAllowed element. If the value returned is true a rollback can be performed. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh403977.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to swap deployments for. Required. The deployment slot. Required. Parameters supplied to the Rollback Update Or Upgrade By Deployment Slot operation. A standard service response including an HTTP status code and request ID. The Swap Deployment operation initiates a virtual IP address swap between the staging and production deployment environments for a service. If the service is currently running in the staging environment, it will be swapped to the production environment. If it is running in the production environment, it will be swapped to staging. For more information on this type of upgrade, see Performing Virtual IP Swap Upgrades at http://msdn.microsoft.com/en-us/library/windowsazure/ee517253.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460814.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to swap deployments for. Required. Parameters supplied to the Swap Deployment operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Swap Deployment operation initiates a virtual IP address swap between the staging and production deployment environments for a service. If the service is currently running in the staging environment, it will be swapped to the production environment. If it is running in the production environment, it will be swapped to staging. For more information on this type of upgrade, see Performing Virtual IP Swap Upgrades at http://msdn.microsoft.com/en-us/library/windowsazure/ee517253.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460814.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to swap deployments for. Required. Parameters supplied to the Swap Deployment operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Update Deployment Status By Deployment Name operation initiates a change in the running status of a deployment. The status of a deployment can be running or suspended. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460808.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to swap deployments for. Required. The name of your deployment. Required. Parameters supplied to the Update Deployment Status By Deployment Name operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Update Deployment Status By Deployment Name operation initiates a change in the running status of a deployment. The status of a deployment can be running or suspended. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460808.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to swap deployments for. Required. The name of your deployment. Required. Parameters supplied to the Update Deployment Status By Deployment Name operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Update Deployment Status By Deployment Slot operation initiates a change in the running status of a deployment. The status of a deployment can be running or suspended. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460808.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to swap deployments for. Required. The deployment slot. Required. Parameters supplied to the Update Deployment Status By Deployment Slot operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Update Deployment Status By Deployment Slot operation initiates a change in the running status of a deployment. The status of a deployment can be running or suspended. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460808.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to swap deployments for. Required. The deployment slot. Required. Parameters supplied to the Update Deployment Status By Deployment Slot operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Upgrade Deployment By Name operation initiates an update of role instances in a deployment using the package and configuration that you specify. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the request has been processed, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. To perform an automatic update of a deployment, call Upgrade Deployment or Change Deployment Configuration with the Mode element set to automatic. The update proceeds from that point without a need for further input. You can call Get Operation Status to determine when the update is complete. To perform a manual update, first call Upgrade Deployment with the Mode element set to manual. Next, call Walk Upgrade Domain to update each domain within the deployment. You should make sure that the operation is complete by calling Get Operation Status before updating the next domain. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. By default, a cloud service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To determine the update domain in which a particular instance is running in Windows Azure, use the UpdateDomain property of the RoleInstance class. See the Azure Managed Library Reference at http://msdn.microsoft.com/en-us/library/windowsazure/dd179380.aspx for more information. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460793.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to upgrade. Required. The deployment to upgrade. Required. Parameters supplied to the Upgrade Deployment By Name operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Upgrade Deployment By Name operation initiates an update of role instances in a deployment using the package and configuration that you specify. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the request has been processed, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. To perform an automatic update of a deployment, call Upgrade Deployment or Change Deployment Configuration with the Mode element set to automatic. The update proceeds from that point without a need for further input. You can call Get Operation Status to determine when the update is complete. To perform a manual update, first call Upgrade Deployment with the Mode element set to manual. Next, call Walk Upgrade Domain to update each domain within the deployment. You should make sure that the operation is complete by calling Get Operation Status before updating the next domain. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. By default, a cloud service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To determine the update domain in which a particular instance is running in Windows Azure, use the UpdateDomain property of the RoleInstance class. See the Azure Managed Library Reference at http://msdn.microsoft.com/en-us/library/windowsazure/dd179380.aspx for more information. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460793.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to upgrade. Required. The deployment to upgrade. Required. Parameters supplied to the Upgrade Deployment By Name operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Upgrade Deployment By Slot operation initiates an update of role instances in a deployment using the package and configuration that you specify. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the request has been processed, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. To perform an automatic update of a deployment, call Upgrade Deployment or Change Deployment Configuration with the Mode element set to automatic. The update proceeds from that point without a need for further input. You can call Get Operation Status to determine when the update is complete. To perform a manual update, first call Upgrade Deployment with the Mode element set to manual. Next, call Walk Upgrade Domain to update each domain within the deployment. You should make sure that the operation is complete by calling Get Operation Status before updating the next domain. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. By default, a cloud service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To determine the update domain in which a particular instance is running in Windows Azure, use the UpdateDomain property of the RoleInstance class. See the Azure Managed Library Reference at http://msdn.microsoft.com/en-us/library/windowsazure/dd179380.aspx for more information. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460793.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to upgrade. Required. The slot to upgrade. Required. Parameters supplied to the Upgrade Deployment By Slot operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Upgrade Deployment By Slot operation initiates an update of role instances in a deployment using the package and configuration that you specify. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the request has been processed, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. To perform an automatic update of a deployment, call Upgrade Deployment or Change Deployment Configuration with the Mode element set to automatic. The update proceeds from that point without a need for further input. You can call Get Operation Status to determine when the update is complete. To perform a manual update, first call Upgrade Deployment with the Mode element set to manual. Next, call Walk Upgrade Domain to update each domain within the deployment. You should make sure that the operation is complete by calling Get Operation Status before updating the next domain. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. By default, a cloud service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To determine the update domain in which a particular instance is running in Windows Azure, use the UpdateDomain property of the RoleInstance class. See the Azure Managed Library Reference at http://msdn.microsoft.com/en-us/library/windowsazure/dd179380.aspx for more information. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460793.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The cloud service to upgrade. Required. The slot to upgrade. Required. Parameters supplied to the Upgrade Deployment By Slot operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Walk Upgrade Domain By Deployment Name operation specifies an update domain in which a role instance must be updated. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. Prior to calling the Walk Upgrade Domain operation you must have called Upgrade Deployment, Change Deployment Configuration, or Rollback Update Or Upgrade. By default, a service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To perform a manual update of your deployment, proceed in this order: Call Upgrade Deployment with the Mode element set to manual. Call Walk Upgrade Domain to update each domain within the deployment. Update domains must be updated in order. For example, begin with domain 0, proceed to domain 1, and so on. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. While an update is in progress, call Get Deployment to determine its status. If the update is in progress, Get Deployment returns an UpgradeStatus element that contains information about the update. If the update is complete, or if no update is in progress, then the UpgradeStatus element is null. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460800.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of your deployment. Required. Parameters supplied to the Walk Upgrade Domain By Deployment Name operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Walk Upgrade Domain By Deployment Name operation specifies an update domain in which a role instance must be updated. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. Prior to calling the Walk Upgrade Domain operation you must have called Upgrade Deployment, Change Deployment Configuration, or Rollback Update Or Upgrade. By default, a service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To perform a manual update of your deployment, proceed in this order: Call Upgrade Deployment with the Mode element set to manual. Call Walk Upgrade Domain to update each domain within the deployment. Update domains must be updated in order. For example, begin with domain 0, proceed to domain 1, and so on. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. While an update is in progress, call Get Deployment to determine its status. If the update is in progress, Get Deployment returns an UpgradeStatus element that contains information about the update. If the update is complete, or if no update is in progress, then the UpgradeStatus element is null. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460800.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The name of your deployment. Required. Parameters supplied to the Walk Upgrade Domain By Deployment Name operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Walk Upgrade Domain By Deployment Slot operation specifies an update domain in which a role instance must be updated. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. Prior to calling the Walk Upgrade Domain operation you must have called Upgrade Deployment, Change Deployment Configuration, or Rollback Update Or Upgrade. By default, a service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To perform a manual update of your deployment, proceed in this order: Call Upgrade Deployment with the Mode element set to manual. Call Walk Upgrade Domain to update each domain within the deployment. Update domains must be updated in order. For example, begin with domain 0, proceed to domain 1, and so on. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. While an update is in progress, call Get Deployment to determine its status. If the update is in progress, Get Deployment returns an UpgradeStatus element that contains information about the update. If the update is complete, or if no update is in progress, then the UpgradeStatus element is null. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460800.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The deployment slot. Required. Parameters supplied to the Walk Upgrade Domain By Deployment Slot operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Walk Upgrade Domain By Deployment Slot operation specifies an update domain in which a role instance must be updated. For more information about updating role instances, see Update an Azure Service at http://msdn.microsoft.com/en-us/library/windowsazure/hh472157.aspx. This operation is an asynchronous operation. To determine whether the Management service has finished processing the request, call Get Operation Status. For more information on asynchronous operations, see Tracking Asynchronous Service Management Requests at http://msdn.microsoft.com/en-us/library/windowsazure/ee460791.aspx. Prior to calling the Walk Upgrade Domain operation you must have called Upgrade Deployment, Change Deployment Configuration, or Rollback Update Or Upgrade. By default, a service is deployed with five update domains, which are updated one at a time during an in-place update. For information on modifying the number of update domains in the service definition file, see the Azure Service Definition Schema (.csdef File). To perform a manual update of your deployment, proceed in this order: Call Upgrade Deployment with the Mode element set to manual. Call Walk Upgrade Domain to update each domain within the deployment. Update domains must be updated in order. For example, begin with domain 0, proceed to domain 1, and so on. Important: An update that adds or removes role instances will result in a configuration update to all roles that are deployed in the cloud service. Existing role instances need to be notified of new role instances so that all role instances can communicate together in the cloud service. While an update is in progress, call Get Deployment to determine its status. If the update is in progress, Get Deployment returns an UpgradeStatus element that contains information about the update. If the update is complete, or if no update is in progress, then the UpgradeStatus element is null. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460800.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IDeploymentOperations. Required. The name of the cloud service. Required. The deployment slot. Required. Parameters supplied to the Walk Upgrade Domain By Deployment Slot operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Service Management API includes operations for managing the hosted services beneath your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460812.aspx for more information) The Service Management API includes operations for managing the hosted services beneath your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460812.aspx for more information) The Add Extension operation adds an available extension to your cloud service. In Azure, a process can run as an extension of a cloud service. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as extensions to the cloud service. You can find the available extension by using the List Available Extensions operation. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169558.aspx for more information) The name of the cloud service. Parameters supplied to the Add Extension operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Begin Adding Extension operation adds an available extension to your cloud service. In Azure, a process can run as an extension of a cloud service. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as extensions to the cloud service. You can find the available extension by using the List Available Extensions operation. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169558.aspx for more information) The name of the cloud service. Parameters supplied to the Begin Adding Extension operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Deleting All Hosted Service operation deletes the specified cloud service from Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441305.aspx for more information) The name of the cloud service. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Deleting Extension operation deletes the specified extension from a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169560.aspx for more information) The name of the cloud service. The identifier that was assigned to the extension when it was added to the cloud service Cancellation token. A standard service response including an HTTP status code and request ID. The Check Hosted Service Name Availability operation checks for the availability of the specified cloud service name. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj154116.aspx for more information) The cloud service name that you would like to use. Cancellation token. The Check Hosted Service Name Availability operation response. The Create Hosted Service operation creates a new cloud service in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441304.aspx for more information) Parameters supplied to the Create Hosted Service operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Delete Hosted Service operation deletes the specified cloud service from Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441305.aspx for more information) The name of the cloud service. Cancellation token. A standard service response including an HTTP status code and request ID. The Delete All Hosted Service operation deletes the specified cloud service from Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441305.aspx for more information) The name of the cloud service. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Extension operation deletes the specified extension from a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169560.aspx for more information) The name of the cloud service. The identifier that was assigned to the extension when it was added to the cloud service Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Get Hosted Service Properties operation retrieves system properties for the specified cloud service. These properties include the service name and service type; and the name of the affinity group to which the service belongs, or its location if it is not part of an affinity group. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460806.aspx for more information) The name of the cloud service. Cancellation token. The Get Hosted Service operation response. The Get Detailed Hosted Service Properties operation retrieves system properties for the specified cloud service. These properties include the service name and service type; the name of the affinity group to which the service belongs, or its location if it is not part of an affinity group; and information on the deployments of the service. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460806.aspx for more information) The name of the cloud service. Cancellation token. The detailed Get Hosted Service operation response. The Get Extension operation retrieves information about a specified extension that was added to a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169557.aspx for more information) The name of the cloud service. The identifier that was assigned to the extension when it was added to the cloud service Cancellation token. The Get Extension operation response. The List Hosted Services operation lists the cloud services available under the current subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460781.aspx for more information) Cancellation token. The List Hosted Service operation response. The List Available Extensions operation lists the extensions that are available to add to your cloud service. In Windows Azure, a process can run as an extension of a cloud service. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as extensions to the cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169559.aspx for more information) Cancellation token. The List Available Extensions operation response. The List Extensions operation lists all of the extensions that were added to a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169561.aspx for more information) The name of the cloud service. Cancellation token. The List Extensions operation response. The List Extension Versions operation lists the versions of an extension that are available to add to a cloud service. In Azure, a process can run as an extension of a cloud service. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as extensions to the cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn495437.aspx for more information) The provider namespace. The extension type name. Cancellation token. The List Available Extensions operation response. The Update Hosted Service operation can update the label or description of a cloud service in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441303.aspx for more information) The name of the cloud service. Parameters supplied to the Update Hosted Service operation. Cancellation token. A standard service response including an HTTP status code and request ID. Initializes a new instance of the HostedServiceOperations class. Reference to the service client. The Add Extension operation adds an available extension to your cloud service. In Azure, a process can run as an extension of a cloud service. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as extensions to the cloud service. You can find the available extension by using the List Available Extensions operation. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169558.aspx for more information) Required. The name of the cloud service. Required. Parameters supplied to the Add Extension operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Begin Adding Extension operation adds an available extension to your cloud service. In Azure, a process can run as an extension of a cloud service. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as extensions to the cloud service. You can find the available extension by using the List Available Extensions operation. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169558.aspx for more information) Required. The name of the cloud service. Required. Parameters supplied to the Begin Adding Extension operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Deleting All Hosted Service operation deletes the specified cloud service from Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441305.aspx for more information) Required. The name of the cloud service. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Deleting Extension operation deletes the specified extension from a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169560.aspx for more information) Required. The name of the cloud service. Required. The identifier that was assigned to the extension when it was added to the cloud service Cancellation token. A standard service response including an HTTP status code and request ID. The Check Hosted Service Name Availability operation checks for the availability of the specified cloud service name. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj154116.aspx for more information) Required. The cloud service name that you would like to use. Cancellation token. The Check Hosted Service Name Availability operation response. The Create Hosted Service operation creates a new cloud service in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441304.aspx for more information) Required. Parameters supplied to the Create Hosted Service operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Delete Hosted Service operation deletes the specified cloud service from Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441305.aspx for more information) Required. The name of the cloud service. Cancellation token. A standard service response including an HTTP status code and request ID. The Delete All Hosted Service operation deletes the specified cloud service from Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441305.aspx for more information) Required. The name of the cloud service. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Extension operation deletes the specified extension from a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169560.aspx for more information) Required. The name of the cloud service. Required. The identifier that was assigned to the extension when it was added to the cloud service Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Get Hosted Service Properties operation retrieves system properties for the specified cloud service. These properties include the service name and service type; and the name of the affinity group to which the service belongs, or its location if it is not part of an affinity group. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460806.aspx for more information) Required. The name of the cloud service. Cancellation token. The Get Hosted Service operation response. The Get Detailed Hosted Service Properties operation retrieves system properties for the specified cloud service. These properties include the service name and service type; the name of the affinity group to which the service belongs, or its location if it is not part of an affinity group; and information on the deployments of the service. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460806.aspx for more information) Required. The name of the cloud service. Cancellation token. The detailed Get Hosted Service operation response. The Get Extension operation retrieves information about a specified extension that was added to a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169557.aspx for more information) Required. The name of the cloud service. Required. The identifier that was assigned to the extension when it was added to the cloud service Cancellation token. The Get Extension operation response. The List Hosted Services operation lists the cloud services available under the current subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460781.aspx for more information) Cancellation token. The List Hosted Service operation response. The List Available Extensions operation lists the extensions that are available to add to your cloud service. In Windows Azure, a process can run as an extension of a cloud service. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as extensions to the cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169559.aspx for more information) Cancellation token. The List Available Extensions operation response. The List Extensions operation lists all of the extensions that were added to a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169561.aspx for more information) Required. The name of the cloud service. Cancellation token. The List Extensions operation response. The List Extension Versions operation lists the versions of an extension that are available to add to a cloud service. In Azure, a process can run as an extension of a cloud service. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as extensions to the cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn495437.aspx for more information) Required. The provider namespace. Required. The extension type name. Cancellation token. The List Available Extensions operation response. The Update Hosted Service operation can update the label or description of a cloud service in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441303.aspx for more information) Required. The name of the cloud service. Required. Parameters supplied to the Update Hosted Service operation. Cancellation token. A standard service response including an HTTP status code and request ID. Gets a reference to the Microsoft.WindowsAzure.Management.Compute.ComputeManagementClient. The Service Management API provides programmatic access to much of the functionality available through the Management Portal. The Service Management API is a REST API. All API operations are performed over SSL, and are mutually authenticated using X.509 v3 certificates. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460799.aspx for more information) The Add Extension operation adds an available extension to your cloud service. In Azure, a process can run as an extension of a cloud service. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as extensions to the cloud service. You can find the available extension by using the List Available Extensions operation. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169558.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. Required. Parameters supplied to the Add Extension operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Add Extension operation adds an available extension to your cloud service. In Azure, a process can run as an extension of a cloud service. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as extensions to the cloud service. You can find the available extension by using the List Available Extensions operation. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169558.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. Required. Parameters supplied to the Add Extension operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Begin Adding Extension operation adds an available extension to your cloud service. In Azure, a process can run as an extension of a cloud service. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as extensions to the cloud service. You can find the available extension by using the List Available Extensions operation. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169558.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. Required. Parameters supplied to the Begin Adding Extension operation. A standard service response including an HTTP status code and request ID. The Begin Adding Extension operation adds an available extension to your cloud service. In Azure, a process can run as an extension of a cloud service. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as extensions to the cloud service. You can find the available extension by using the List Available Extensions operation. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169558.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. Required. Parameters supplied to the Begin Adding Extension operation. A standard service response including an HTTP status code and request ID. The Begin Deleting All Hosted Service operation deletes the specified cloud service from Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441305.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. A standard service response including an HTTP status code and request ID. The Begin Deleting All Hosted Service operation deletes the specified cloud service from Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441305.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. A standard service response including an HTTP status code and request ID. The Begin Deleting Extension operation deletes the specified extension from a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169560.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. Required. The identifier that was assigned to the extension when it was added to the cloud service A standard service response including an HTTP status code and request ID. The Begin Deleting Extension operation deletes the specified extension from a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169560.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. Required. The identifier that was assigned to the extension when it was added to the cloud service A standard service response including an HTTP status code and request ID. The Check Hosted Service Name Availability operation checks for the availability of the specified cloud service name. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj154116.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The cloud service name that you would like to use. The Check Hosted Service Name Availability operation response. The Check Hosted Service Name Availability operation checks for the availability of the specified cloud service name. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj154116.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The cloud service name that you would like to use. The Check Hosted Service Name Availability operation response. The Create Hosted Service operation creates a new cloud service in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441304.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. Parameters supplied to the Create Hosted Service operation. A standard service response including an HTTP status code and request ID. The Create Hosted Service operation creates a new cloud service in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441304.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. Parameters supplied to the Create Hosted Service operation. A standard service response including an HTTP status code and request ID. The Delete Hosted Service operation deletes the specified cloud service from Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441305.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. A standard service response including an HTTP status code and request ID. The Delete Hosted Service operation deletes the specified cloud service from Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441305.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. A standard service response including an HTTP status code and request ID. The Delete All Hosted Service operation deletes the specified cloud service from Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441305.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete All Hosted Service operation deletes the specified cloud service from Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441305.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Extension operation deletes the specified extension from a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169560.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. Required. The identifier that was assigned to the extension when it was added to the cloud service The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Extension operation deletes the specified extension from a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169560.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. Required. The identifier that was assigned to the extension when it was added to the cloud service The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Get Hosted Service Properties operation retrieves system properties for the specified cloud service. These properties include the service name and service type; and the name of the affinity group to which the service belongs, or its location if it is not part of an affinity group. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460806.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. The Get Hosted Service operation response. The Get Hosted Service Properties operation retrieves system properties for the specified cloud service. These properties include the service name and service type; and the name of the affinity group to which the service belongs, or its location if it is not part of an affinity group. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460806.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. The Get Hosted Service operation response. The Get Detailed Hosted Service Properties operation retrieves system properties for the specified cloud service. These properties include the service name and service type; the name of the affinity group to which the service belongs, or its location if it is not part of an affinity group; and information on the deployments of the service. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460806.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. The detailed Get Hosted Service operation response. The Get Detailed Hosted Service Properties operation retrieves system properties for the specified cloud service. These properties include the service name and service type; the name of the affinity group to which the service belongs, or its location if it is not part of an affinity group; and information on the deployments of the service. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460806.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. The detailed Get Hosted Service operation response. The Get Extension operation retrieves information about a specified extension that was added to a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169557.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. Required. The identifier that was assigned to the extension when it was added to the cloud service The Get Extension operation response. The Get Extension operation retrieves information about a specified extension that was added to a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169557.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. Required. The identifier that was assigned to the extension when it was added to the cloud service The Get Extension operation response. The List Hosted Services operation lists the cloud services available under the current subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460781.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. The List Hosted Service operation response. The List Hosted Services operation lists the cloud services available under the current subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460781.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. The List Hosted Service operation response. The List Available Extensions operation lists the extensions that are available to add to your cloud service. In Windows Azure, a process can run as an extension of a cloud service. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as extensions to the cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169559.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. The List Available Extensions operation response. The List Available Extensions operation lists the extensions that are available to add to your cloud service. In Windows Azure, a process can run as an extension of a cloud service. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as extensions to the cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169559.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. The List Available Extensions operation response. The List Extensions operation lists all of the extensions that were added to a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169561.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. The List Extensions operation response. The List Extensions operation lists all of the extensions that were added to a cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn169561.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. The List Extensions operation response. The List Extension Versions operation lists the versions of an extension that are available to add to a cloud service. In Azure, a process can run as an extension of a cloud service. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as extensions to the cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn495437.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The provider namespace. Required. The extension type name. The List Available Extensions operation response. The List Extension Versions operation lists the versions of an extension that are available to add to a cloud service. In Azure, a process can run as an extension of a cloud service. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as extensions to the cloud service. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn495437.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The provider namespace. Required. The extension type name. The List Available Extensions operation response. The Update Hosted Service operation can update the label or description of a cloud service in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441303.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. Required. Parameters supplied to the Update Hosted Service operation. A standard service response including an HTTP status code and request ID. The Update Hosted Service operation can update the label or description of a cloud service in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441303.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IHostedServiceOperations. Required. The name of the cloud service. Required. Parameters supplied to the Update Hosted Service operation. A standard service response including an HTTP status code and request ID. The Compute Management API includes operations for managing the load balancers for your subscription. Add an internal load balancer to a an existing deployment. When used by an input endpoint, the internal load balancer will provide an additional private VIP that can be used for load balancing to the roles in this deployment. The name of the service. The name of the deployment. Parameters supplied to the Create Load Balancer operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Delete an internal load balancer from the deployment. The name of the service. The name of the deployment. The name of the load balancer. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Add an internal load balancer to a an existing deployment. When used by an input endpoint, the internal load balancer will provide an additional private VIP that can be used for load balancing to the roles in this deployment. The name of the service. The name of the deployment. Parameters supplied to the Create Load Balancer operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Delete an internal load balancer from the deployment. The name of the service. The name of the deployment. The name of the load balancer. Cancellation token. A standard service response including an HTTP status code and request ID. Operations for determining the version of the Azure Guest Operating System on which your service is running. (see http://msdn.microsoft.com/en-us/library/windowsazure/ff684169.aspx for more information) The List Operating Systems operation lists the versions of the guest operating system that are currently available in Windows Azure. The 2010-10-28 version of List Operating Systems also indicates what family an operating system version belongs to. Currently Azure supports two operating system families: the Azure guest operating system that is substantially compatible with Windows Server 2008 SP2, and the Azure guest operating system that is substantially compatible with Windows Server 2008 R2. (see http://msdn.microsoft.com/en-us/library/windowsazure/ff684168.aspx for more information) Cancellation token. The List Operating Systems operation response. The List OS Families operation lists the guest operating system families available in Azure, and also lists the operating system versions available for each family. Currently Azure supports two operating system families: the Azure guest operating system that is substantially compatible with Windows Server 2008 SP2, and the Azure guest operating system that is substantially compatible with Windows Server 2008 R2. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441291.aspx for more information) Cancellation token. The List Operating System Families operation response. Operations for managing service certificates for your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee795178.aspx for more information) The Begin Creating Service Certificate operation adds a certificate to a hosted service. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460817.aspx for more information) The DNS prefix name of your service. Parameters supplied to the Begin Creating Service Certificate operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Deleting Service Certificate operation deletes a service certificate from the certificate store of a hosted service. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460803.aspx for more information) Parameters supplied to the Begin Deleting Service Certificate operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Create Service Certificate operation adds a certificate to a hosted service. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460817.aspx for more information) The DNS prefix name of your service. Parameters supplied to the Create Service Certificate operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Service Certificate operation deletes a service certificate from the certificate store of a hosted service. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460803.aspx for more information) Parameters supplied to the Delete Service Certificate operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Get Service Certificate operation returns the public data for the specified X.509 certificate associated with a hosted service. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460792.aspx for more information) Parameters supplied to the Get Service Certificate operation. Cancellation token. The Get Service Certificate operation response. The List Service Certificates operation lists all of the service certificates associated with the specified hosted service. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj154105.aspx for more information) The DNS prefix name of your hosted service. Cancellation token. The List Service Certificates operation response. The Service Management API includes operations for managing the disks in your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157188.aspx for more information) The Begin Deleting Data Disk operation removes the specified data disk from a virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157179.aspx for more information) The name of your service. The name of the deployment. The name of the role to delete the data disk from. The logical unit number of the disk. Specifies that the source blob for the disk should also be deleted from storage. Cancellation token. A standard service response including an HTTP status code and request ID. The Create Data Disk operation adds a data disk to a virtual machine. There are three ways to create the data disk using the Add Data Disk operation. Option 1 - Attach an empty data disk to the role by specifying the disk label and location of the disk image. Do not include the DiskName and SourceMediaLink elements in the request body. Include the MediaLink element and reference a blob that is in the same geographical region as the role. You can also omit the MediaLink element. In this usage, Azure will create the data disk in the storage account configured as default for the role. Option 2 - Attach an existing data disk that is in the image repository. Do not include the DiskName and SourceMediaLink elements in the request body. Specify the data disk to use by including the DiskName element. Note: If included the in the response body, the MediaLink and LogicalDiskSizeInGB elements are ignored. Option 3 - Specify the location of a blob in your storage account that contain a disk image to use. Include the SourceMediaLink element. Note: If the MediaLink element isincluded, it is ignored. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157199.aspx for more information) The name of your service. The name of the deployment. The name of the role to add the data disk to. Parameters supplied to the Create Virtual Machine Data Disk operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Create Disk operation adds a disk to the user image repository. The disk can be an operating system disk or a data disk. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157178.aspx for more information) Parameters supplied to the Create Virtual Machine Disk operation. Cancellation token. A virtual machine disk associated with your subscription. The Delete Data Disk operation removes the specified data disk from a virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157179.aspx for more information) The name of your service. The name of the deployment. The name of the role to delete the data disk from. The logical unit number of the disk. Specifies that the source blob for the disk should also be deleted from storage. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Disk operation deletes the specified data or operating system disk from your image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157200.aspx for more information) The name of the disk to delete. Specifies that the source blob for the disk should also be deleted from storage. Cancellation token. A standard service response including an HTTP status code and request ID. The Get Data Disk operation retrieves the specified data disk from a virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157180.aspx for more information) The name of your service. The name of the deployment. The name of the role. The logical unit number of the disk. Cancellation token. The Get Data Disk operation response. The Get Disk operation retrieves a disk from the user image repository. The disk can be an operating system disk or a data disk. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157178.aspx for more information) The name of the disk. Cancellation token. A virtual machine disk associated with your subscription. The List Disks operation retrieves a list of the disks in your image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157176.aspx for more information) Cancellation token. The List Disks operation response. The Update Data Disk operation updates the specified data disk attached to the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157190.aspx for more information) The name of your service. The name of the deployment. The name of the role to add the data disk to. The logical unit number of the disk. Parameters supplied to the Update Virtual Machine Data Disk operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Add Disk operation adds a disk to the user image repository. The disk can be an operating system disk or a data disk. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157178.aspx for more information) The name of the disk being updated. Parameters supplied to the Update Virtual Machine Disk operation. Cancellation token. A virtual machine disk associated with your subscription. The Service Management API includes operations for managing the virtual machine extensions in your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157206.aspx for more information) The List Resource Extensions operation lists the resource extensions that are available to add to a Virtual Machine. In Azure, a process can run as a resource extension of a Virtual Machine. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as resource extensions to the Virtual Machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn495441.aspx for more information) Cancellation token. The List Resource Extensions operation response. The List Resource Extension Versions operation lists the versions of a resource extension that are available to add to a Virtual Machine. In Azure, a process can run as a resource extension of a Virtual Machine. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as resource extensions to the Virtual Machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn495440.aspx for more information) The name of the publisher. The name of the extension. Cancellation token. The List Resource Extensions operation response. The Service Management API includes operations for managing the virtual machines in your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157206.aspx for more information) The Begin Capturing Role operation creates a copy of the operating system virtual hard disk (VHD) that is deployed in the virtual machine, saves the VHD copy in the same storage location as the operating system VHD, and registers the copy as an image in your image gallery. From the captured image, you can create additional customized virtual machines. For more information about images and disks, see Manage Disks and Images at http://msdn.microsoft.com/en-us/library/windowsazure/jj672979.aspx. For more information about capturing images, see How to Capture an Image of a Virtual Machine Running Windows Server 2008 R2 at http://www.windowsazure.com/en-us/documentation/articles/virtual-machines-capture-image-windows-server/ or How to Capture an Image of a Virtual Machine Running Linux at http://www.windowsazure.com/en-us/documentation/articles/virtual-machines-linux-capture-image/. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157201.aspx for more information) The name of your service. The name of your deployment. The name of the virtual machine to restart. Parameters supplied to the Begin Capturing Virtual Machine operation. Cancellation token. A standard service response including an HTTP status code and request ID. Begin capturing role as VM template. The name of your service. The name of your deployment. The name of the virtual machine to restart. Parameters supplied to the Capture Virtual Machine operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Creating Role operation adds a virtual machine to an existing deployment. You can refer to the OSDisk in the Add Role operation in the following ways: Platform/User Image - Set the SourceImageName to a platform or user image. You can optionally specify the DiskName and MediaLink values as part the operation to control the name and location of target disk. When DiskName and MediaLink are specified in this mode, they must not already exist in the system, otherwise a conflict fault is returned; UserDisk - Set DiskName to a user supplied image in image repository. SourceImageName must be set to NULL. All other properties are ignored; or Blob in a Storage Account - Set MediaLink to a blob containing the image. SourceImageName and DiskName are set to NULL. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157186.aspx for more information) The name of your service. The name of your deployment. Parameters supplied to the Begin Creating Virtual Machine operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Creating Virtual Machine Deployment operation provisions a virtual machine based on the supplied configuration. When you create a deployment of a virtual machine, you should make sure that the cloud service and the disk or image that you use are located in the same region. For example, if the cloud service was created in the West US region, the disk or image that you use should also be located in a storage account in the West US region. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157194.aspx for more information) The name of your service. Parameters supplied to the Begin Creating Virtual Machine Deployment operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Deleting Role operation deletes the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157184.aspx for more information) The name of your service. The name of your deployment. The name of the virtual machine to delete. Specifies that the source blob(s) for the virtual machine should also be deleted from storage. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Restarting role operation restarts the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157197.aspx for more information) The name of your service. The name of your deployment. The name of the virtual machine to restart. Cancellation token. A standard service response including an HTTP status code and request ID. The Shutdown Role operation shuts down the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157195.aspx for more information) The name of your service. The name of your deployment. The name of the virtual machine to shutdown. The parameters for the shutdown vm operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Shutting Down Roles operation stops the specified set of virtual machines. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469421.aspx for more information) The name of your service. The name of your deployment. Parameters to pass to the Begin Shutting Down Roles operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Starting Role operation starts the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157189.aspx for more information) The name of your service. The name of your deployment. The name of the virtual machine to start. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Starting Roles operation starts the specified set of virtual machines. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469419.aspx for more information) The name of your service. The name of your deployment. Parameters to pass to the Begin Starting Roles operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Updating Role operation adds a virtual machine to an existing deployment. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157187.aspx for more information) The name of your service. The name of your deployment. The name of your virtual machine. Parameters supplied to the Begin Updating Virtual Machine operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Updating Load Balanced Endpoint Set operation changes the specified load-balanced InputEndpoints on all the roles of an Infrastructure as a Service deployment. Non-load-balanced endpoints must be changed using UpdateRole. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469417.aspx for more information) The name of your service. The name of your deployment. Parameters supplied to the Begin Updating Load Balanced Endpoint Set operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Capture Role operation creates a copy of the operating system virtual hard disk (VHD) that is deployed in the virtual machine, saves the VHD copy in the same storage location as the operating system VHD, and registers the copy as an image in your image gallery. From the captured image, you can create additional customized virtual machines. For more information about images and disks, see Manage Disks and Images at http://msdn.microsoft.com/en-us/library/windowsazure/jj672979.aspx. For more information about capturing images, see How to Capture an Image of a Virtual Machine Running Windows Server 2008 R2 at http://www.windowsazure.com/en-us/documentation/articles/virtual-machines-capture-image-windows-server/ or How to Capture an Image of a Virtual Machine Running Linux at http://www.windowsazure.com/en-us/documentation/articles/virtual-machines-linux-capture-image/. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157201.aspx for more information) The name of your service. The name of your deployment. The name of the virtual machine to restart. Parameters supplied to the Capture Virtual Machine operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Capture role as VM template. The name of your service. The name of your deployment. The name of the virtual machine to restart. Parameters supplied to the Capture Virtual Machine operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Create Role operation adds a virtual machine to an existing deployment. You can refer to the OSDisk in the Add Role operation in the following ways: Platform/User Image - Set the SourceImageName to a platform or user image. You can optionally specify the DiskName and MediaLink values as part the operation to control the name and location of target disk. When DiskName and MediaLink are specified in this mode, they must not already exist in the system, otherwise a conflict fault is returned; UserDisk - Set DiskName to a user supplied image in image repository. SourceImageName must be set to NULL. All other properties are ignored; or Blob in a Storage Account - Set MediaLink to a blob containing the image. SourceImageName and DiskName are set to NULL. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157186.aspx for more information) The name of your service. The name of your deployment. Parameters supplied to the Create Virtual Machine operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Create Virtual Machine Deployment operation provisions a virtual machine based on the supplied configuration. When you create a deployment of a virtual machine, you should make sure that the cloud service and the disk or image that you use are located in the same region. For example, if the cloud service was created in the West US region, the disk or image that you use should also be located in a storage account in the West US region. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157194.aspx for more information) The name of your service. Parameters supplied to the Create Virtual Machine Deployment operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Role operation deletes the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157184.aspx for more information) The name of your service. The name of your deployment. The name of the virtual machine to delete. Specifies that the source blob(s) for the virtual machine should also be deleted from storage. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Get Role operation retrieves information about the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157193.aspx for more information) The name of your service. The name of your deployment. The name of the virtual machine. Cancellation token. The Get Virtual Machine operation response. The Download RDP file operation retrieves the Remote Desktop Protocol configuration file from the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157183.aspx for more information) The name of your service. The name of your deployment. The name of the virtual machine. Cancellation token. The Download RDP file operation response. The Restart role operation restarts the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157197.aspx for more information) The name of your service. The name of your deployment. The name of the virtual machine to restart. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Shutdown Role operation shuts down the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157195.aspx for more information) The name of your service. The name of your deployment. The name of the virtual machine to shutdown. The parameters for the shutdown virtual machine operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Shutdown Roles operation stops the specified set of virtual machines. The name of your service. The name of your deployment. Parameters to pass to the Shutdown Roles operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Start Role operation starts the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157189.aspx for more information) The name of your service. The name of your deployment. The name of the virtual machine to start. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Start Roles operation starts the specified set of virtual machines. The name of your service. The name of your deployment. Parameters to pass to the Start Roles operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Update Role operation adds a virtual machine to an existing deployment. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157187.aspx for more information) The name of your service. The name of your deployment. The name of your virtual machine. Parameters supplied to the Update Virtual Machine operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Update Load Balanced Endpoint Set operation changes the specified load-balanced InputEndpoints on all the roles of an Infrastructure as a Service deployment. Non-load-balanced endpoints must be changed using UpdateRole. The name of your service. The name of your deployment. Parameters supplied to the Update Load Balanced Endpoint Set operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Service Management API includes operations for managing the OS images in your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157175.aspx for more information) Share an already replicated OS image. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. The name of the virtual machine image to share. The sharing permission: public, msdn, or private. Cancellation token. A standard service response including an HTTP status code and request ID. Unreplicate an OS image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Note: The operation removes the published copies of the user OS Image. It does not remove the actual user OS Image. To remove the actual user OS Image, the publisher will have to call Delete OS Image. The name of the virtual machine image to replicate. Note: The OS Image Name should be the user OS Image, not the published name of the OS Image. Cancellation token. A standard service response including an HTTP status code and request ID. The Create OS Image operation adds an operating system image that is stored in a storage account and is available from the image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157192.aspx for more information) Parameters supplied to the Create Virtual Machine Image operation. Cancellation token. Parameters returned from the Create Virtual Machine Image operation. The Delete OS Image operation deletes the specified OS image from your image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157203.aspx for more information) The name of the image to delete. Specifies that the source blob for the image should also be deleted from storage. Cancellation token. A standard service response including an HTTP status code and request ID. The Get OS Image operation retrieves the details for an operating system image from the image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157191.aspx for more information) The name of the OS image to retrieve. Cancellation token. A virtual machine image associated with your subscription. Gets OS Image's properties and its replication details. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. The name of the virtual machine image to replicate. Cancellation token. The Get Details OS Images operation response. The List OS Images operation retrieves a list of the operating system images from the image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157191.aspx for more information) Cancellation token. The List OS Images operation response. Replicate an OS image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. The name of the virtual machine OS image to replicate. Parameters supplied to the Replicate Virtual Machine Image operation. Cancellation token. The response body contains the published name of the image. Share an already replicated OS image. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. The name of the virtual machine image to share. The sharing permission: public, msdn, or private. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Unreplicate an OS image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Note: The operation removes the published copies of the user OS Image. It does not remove the actual user OS Image. To remove the actual user OS Image, the publisher will have to call Delete OS Image. The name of the virtual machine image to replicate. Note: The OS Image Name should be the user OS Image, not the published name of the OS Image. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Update OS Image operation updates an OS image that in your image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157198.aspx for more information) The name of the virtual machine image to be updated. Parameters supplied to the Update Virtual Machine Image operation. Cancellation token. Parameters returned from the Create Virtual Machine Image operation. The Service Management API includes operations for managing the virtual machine templates in your subscription. The Begin Deleting Virtual Machine Image operation deletes the specified virtual machine image. The name of the virtual machine image to delete. Specifies that the source blob for the image should also be deleted from storage. Cancellation token. A standard service response including an HTTP status code and request ID. Share an already replicated VM image. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. The name of the virtual machine image to share. The sharing permission: public, msdn, or private. Cancellation token. A standard service response including an HTTP status code and request ID. Unreplicate an VM image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Note: The operation removes the published copies of the user VM Image. It does not remove the actual user VM Image. To remove the actual user VM Image, the publisher will have to call Delete VM Image. The name of the virtual machine image to replicate. Note: The VM Image Name should be the user VM Image, not the published name of the VM Image. Cancellation token. A standard service response including an HTTP status code and request ID. The Delete Virtual Machine Image operation deletes the specified virtual machine image. The name of the virtual machine image to delete. Specifies that the source blob for the image should also be deleted from storage. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Gets VMImage's properties and its replication details. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. The name of the virtual machine image to replicate. Cancellation token. The Get Details VM Images operation response. The List Virtual Machine Images operation retrieves a list of the virtual machine images. Cancellation token. The List VM Images operation response. Replicate an VM image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. The name of the virtual machine image to replicate. Parameters supplied to the Replicate Virtual Machine Image operation. Cancellation token. The response body contains the published name of the image. Share an already replicated VM image. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. The name of the virtual machine image to share. The sharing permission: public, msdn, or private. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Unreplicate an VM image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Note: The operation removes the published copies of the user VM Image. It does not remove the actual user VM Image. To remove the actual user VM Image, the publisher will have to call Delete VM Image. The name of the virtual machine image to replicate. Note: The VM Image Name should be the user VM Image, not the published name of the VM Image. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Update VM Image operation updates a VM image that in your image repository. The name of the virtual machine image to be updated. Parameters supplied to the Update Virtual Machine Image operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Compute Management API includes operations for managing the load balancers for your subscription. Initializes a new instance of the LoadBalancerOperations class. Reference to the service client. Add an internal load balancer to a an existing deployment. When used by an input endpoint, the internal load balancer will provide an additional private VIP that can be used for load balancing to the roles in this deployment. Required. The name of the service. Required. The name of the deployment. Required. Parameters supplied to the Create Load Balancer operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Delete an internal load balancer from the deployment. Required. The name of the service. Required. The name of the deployment. Required. The name of the load balancer. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Add an internal load balancer to a an existing deployment. When used by an input endpoint, the internal load balancer will provide an additional private VIP that can be used for load balancing to the roles in this deployment. Required. The name of the service. Required. The name of the deployment. Required. Parameters supplied to the Create Load Balancer operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Delete an internal load balancer from the deployment. Required. The name of the service. Required. The name of the deployment. Required. The name of the load balancer. Cancellation token. A standard service response including an HTTP status code and request ID. Gets a reference to the Microsoft.WindowsAzure.Management.Compute.ComputeManagementClient. The Service Management API provides programmatic access to much of the functionality available through the Management Portal. The Service Management API is a REST API. All API operations are performed over SSL, and are mutually authenticated using X.509 v3 certificates. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460799.aspx for more information) Add an internal load balancer to a an existing deployment. When used by an input endpoint, the internal load balancer will provide an additional private VIP that can be used for load balancing to the roles in this deployment. Reference to the Microsoft.WindowsAzure.Management.Compute.ILoadBalancerOperations. Required. The name of the service. Required. The name of the deployment. Required. Parameters supplied to the Create Load Balancer operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Add an internal load balancer to a an existing deployment. When used by an input endpoint, the internal load balancer will provide an additional private VIP that can be used for load balancing to the roles in this deployment. Reference to the Microsoft.WindowsAzure.Management.Compute.ILoadBalancerOperations. Required. The name of the service. Required. The name of the deployment. Required. Parameters supplied to the Create Load Balancer operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Delete an internal load balancer from the deployment. Reference to the Microsoft.WindowsAzure.Management.Compute.ILoadBalancerOperations. Required. The name of the service. Required. The name of the deployment. Required. The name of the load balancer. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Delete an internal load balancer from the deployment. Reference to the Microsoft.WindowsAzure.Management.Compute.ILoadBalancerOperations. Required. The name of the service. Required. The name of the deployment. Required. The name of the load balancer. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Add an internal load balancer to a an existing deployment. When used by an input endpoint, the internal load balancer will provide an additional private VIP that can be used for load balancing to the roles in this deployment. Reference to the Microsoft.WindowsAzure.Management.Compute.ILoadBalancerOperations. Required. The name of the service. Required. The name of the deployment. Required. Parameters supplied to the Create Load Balancer operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Add an internal load balancer to a an existing deployment. When used by an input endpoint, the internal load balancer will provide an additional private VIP that can be used for load balancing to the roles in this deployment. Reference to the Microsoft.WindowsAzure.Management.Compute.ILoadBalancerOperations. Required. The name of the service. Required. The name of the deployment. Required. Parameters supplied to the Create Load Balancer operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Delete an internal load balancer from the deployment. Reference to the Microsoft.WindowsAzure.Management.Compute.ILoadBalancerOperations. Required. The name of the service. Required. The name of the deployment. Required. The name of the load balancer. A standard service response including an HTTP status code and request ID. Delete an internal load balancer from the deployment. Reference to the Microsoft.WindowsAzure.Management.Compute.ILoadBalancerOperations. Required. The name of the service. Required. The name of the deployment. Required. The name of the load balancer. A standard service response including an HTTP status code and request ID. An access control rule for a public endpoint. Initializes a new instance of the AccessControlListRule class. Optional. The action allowed by this Access Control List Rule. Optional. The description for this Access Control List Rule. Optional. The order of application for this Access Control List Rule. Optional. The remote subnet that is granted access for this Access Control List Rule. The service certificate format. Azure supports the pfx and cer file formats. Algorithm that was used to hash a service certificate. The compute capabilities. Initializes a new instance of the ComputeCapabilities class. Optional. Role sizes support for IaaS deployments. Optional. Role sizes support for PaaS deployments. Objects that provide system or application data. Initializes a new instance of the ConfigurationSet class. Optional. Specifies the string representing the administrator password to use for the virtual machine. If the VM will be created from a 'Specialized' VM image, the password is not required. Optional. Specifies the name that is used to rename the default administrator account. If the VM will be created from a 'Specialized' VM image, the user name is not required. Optional. Specifies the computer name for the virtual machine. If the computer name is not specified, a name is created based on the name of the role. Computer names must be 1 to 15 characters in length. This element is only used with the WindowsProvisioningConfiguration set. Optional. Specifies the configuration type for the configuration set. Optional. Optional. Provides base64 encoded custom data to be passed to VM. Optional. Specifies whether or not SSH authentication is disabled for the password. This element is only used with the LinuxProvisioningConfiguration set. By default this value is set to true. Optional. Contains properties that specify a domain to which the virtual machine will be joined. This element is only used with the WindowsProvisioningConfiguration set. Optional. Specifies whether automatic updates are enabled for the virtual machine. This element is only used with the WindowsProvisioningConfiguration set. The default value is false. Optional. Specifies the host name for the VM. Host names are ASCII character strings 1 to 64 characters in length. This element is only used with the LinuxProvisioningConfiguration set. Optional. Contains a collection of external endpoints for the virtual machine. This element is only used with the NetworkConfigurationSet type. Optional. Optional. A set of public IPs. Currently, only one additional public IP per role is supported in an IaaS deployment. The IP address is in addition to the default VIP for the deployment. Optional. Specifies whether password should be reset the first time the administrator logs in. Optional. Specifies the SSH public keys and key pairs to populate in the image during provisioning. This element is only used with the LinuxProvisioningConfiguration set. Optional. Specifies a Customer Address, i.e. an IP address assigned to a VM in a VNet's SubNet. For example: 10.0.0.4. Optional. Contains a list of service certificates with which to provision to the new role. This element is only used with the WindowsProvisioningConfiguration set. Optional. The list of Virtual Network subnet names that the deployment belongs to. This element is only used with the NetworkConfigurationSet type. Optional. Specifies the time zone for the virtual machine. This element is only used with the WindowsProvisioningConfiguration set. For a complete list of supported time zone entries, you can refer to the values listed in the registry entry HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones on a computer running Windows 7, Windows Server 2008, and Windows Server 2008 R2 or you can use the tzutil command-line tool to list the valid time. The tzutil tool is installed by default on Windows 7, Windows Server 2008, and Windows Server 2008 R2. Optional. Specifies the name of a user to be created in the sudoer group of the virtual machine. User names are ASCII character strings 1 to 32 characters in length. This element is only used with the LinuxProvisioningConfiguration set. Optional. Specifies the password for user name. Passwords are ASCII character strings 6 to 72 characters in length. This element is only used with the LinuxProvisioningConfiguration set. Optional. Configures the Windows Remote Management service on the virtual machine, which enables remote Windows PowerShell. An additional public IP that will be created for the role. The public IP will be an additional IP for the role. The role continues to be addressable via the default deployment VIP. Initializes a new instance of the PublicIP class. Optional. The name of the public IP. Specifies the configuration type for the configuration set. The data disk configuration. Initializes a new instance of the DataDiskConfigurationUpdateParameters class. Optional. Optional. Host caching option for a data disk within the VM Image. 'ReadOnly', 'ReadWrite', or 'None'.If this parameter is specified you must also specify the Name for the DataDiskConfiguration you want to change. Optional. Optional. LUN for the data disk. LUNs must not conflict with other Data Disks in the VM Image. If this parameter is specified you must also specify the Name for the DataDiskConfiguration you want to change. Optional. Optional if not changing any data disk configurations. Name of an existing DataDiskConfiguration. The name cannot be changed, this is just to identify the disk for changing other properties. Objects that are used to create a data disk for a virtual machine. Initializes a new instance of the DataVirtualHardDisk class. Optional. Specifies the platform caching behavior of the data disk blob for read/write efficiency. The default value is ReadOnly. Optional. Specifies the friendly name of the VHD used to create the data disk for the virtual machine. Optional. Specifies the size, in GB, of an empty VHD to be attached to the virtual machine. The VHD can be created as part of an attached disk or created as a virtual machine call by specifying the value for this property. Azure creates the empty VHD based on the size preference and attaches the newly created VHD to the virtual machine. Optional. Specifies the Logical Unit Number (LUN) for the data disk. The LUN specifies the slot in which the data drive appears when mounted for usage by the virtual machine. This element is only listed when more than one data disk is attached to a virtual machine. Optional. Optional. If the disk that is being added is already registered in the subscription or the VHD for the disk already exists in blob storage, this element is ignored. If a VHD file does not exist in blob storage, this element defines the location of the new VHD that is created when the new disk is added.Example: http://example.blob.core.windows.net/disks/mydatadisk.vhd Optional. Specifies the name of the VHD used to create the data disk for the virtual machine. Optional. Optional. If the disk that is being added is already registered in the subscription or the VHD for the disk does not exist in blob storage, this element is ignored. If the VHD file exists in blob storage, this element defines the path to the VHD and a disk is registered from it and attached to the virtual machine. Parameters supplied to the Change Configuration Deployment operation. Initializes a new instance of the DeploymentChangeConfigurationParameters class. Required. The encoded service configuration file for the deployment. Optional. Represents the name of an extended deployment property. Each extended property must have a defined name and a value. You can have a maximum of 25 extended property name/value pairs. The maximum length of the name element is 64 characters, only alphanumeric characters and underscores are valid in the name, and the name must start with a letter. Attempting to use other characters, starting the name with a non-letter character, or entering a name that is identical to that of another extended property owned by the same hosted service will result in a status code 400 (Bad Request) error. Optional. Represents an extension that is added to the cloud service. In Azure, a process can run as an extension of a cloud service. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as extensions to the cloud service. You must add an extension to the cloud service by using Add Extension before it can be added to the deployment. Optional. The Change Configuration Deployment mode. Possible values are: Auto and Manual. If not specified, the default value is Auto. If set to Manual, WalkUpgradeDomain must be called to apply the update. If set to Auto, the update is automatically applied to each update domain for the service. Optional. Indicates whether to treat package validation warnings as errors. The default value is false. If set to true, the Created Deployment operation fails if there are validation warnings on the service package. Parameters supplied to the Create Deployment operation. Initializes a new instance of the DeploymentCreateParameters class. Required. The service configuration file for the deployment. Optional. Represents the name of an extended deployment property. Each extended property must have a defined name and a value. You can have a maximum of 25 extended property name/value pairs. The maximum length of the name element is 64 characters, only alphanumeric characters and underscores are valid in the name, and the name must start with a letter. Attempting to use other characters, starting the name with a non-letter character, or entering a name that is identical to that of another extended property owned by the same hosted service will result in a status code 400 (Bad Request) error. Optional. Represents an extension that is added to the cloud service. In Azure, a process can run as an extension of a cloud service. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as extensions to the cloud service. You must add an extension to the cloud service by using Add Extension before it can be added to the deployment. Required. A name for the hosted service. The name can be up to 100 characters in length. It is recommended that the label be unique within the subscription. The name can be used identify the hosted service for your tracking purposes. Required. The name for the deployment. The deployment name must be unique among other deployments for the cloud service. Required. A URL that refers to the location of the service package in the Blob service. The service package can be located either in a storage account beneath the same subscription or a Shared Access Signature (SAS) URI from any storage account. For more info about Shared Access Signatures, see Delegating Access with a Shared Access Signature (REST API) at http://msdn.microsoft.com/en-us/library/windowsazure/ee395415.aspx. Optional. Indicates whether to start the deployment immediately after it is created. The default value is false. If false, the service model is still deployed to the virtual machines but the code is not run immediately. Instead, the service is Suspended until you call Update Deployment Status and set the status toRunning, at which time the service will be started. A deployed service still incurs charges, even if it is suspended. Optional. Indicates whether to treat package validation warnings as errors. The default value is false. If set to true, the Created Deployment operation fails if there are validation warnings on the service package. Parameters supplied to the delete role instance by deployment name operation. Initializes a new instance of the DeploymentDeleteRoleInstanceParameters class. Optional. Parameters supplied to the Get Package operation. Initializes a new instance of the DeploymentGetPackageParameters class. Required. Specifies the URI of the container to which the packages will be saved. Optional. Specifies whether an existing package in the storage container should be overwritten. A deployment that exists in the cloud service. Initializes a new instance of the DeploymentGetResponse class. Optional. The configuration file of the deployment. Optional. The time that the deployment was created. Optional. The deployment environment in which this deployment is running. Optional. The custom DNS settings that are specified for deployment. Optional. Represents the name of an extended cloud service property. Each extended property must have a defined name and a value. You can have a maximum of 50 extended property name and value pairs. The maximum length of the name element is 64 characters, only alphanumeric characters and underscores are valid in the name, and it must start with a letter. Attempting to use other characters, starting with a non-letter character, or entering a name that is identical to that of another extended property owned by the same service will result in a status code 400 (Bad Request) error. Each extended property value has a maximum length of 255 characters. Optional. Represents an extension that is added to the cloud service. Optional. The user-supplied name of the deployment. This name can be used identify the deployment for tracking purposes. Optional. The last time that the deployment was modified. Optional. Optional. A list of internal load balancers that each provide load balancing on a private VIP. It's created when a name is assigned in the list here. Optional. Indicates whether the deployment is locked for new write operations because an existing operation is updating the deployment. Optional. Optional. Specifies information about when the virtual machine has been started and stopped. Optional. The unique identifier for this deployment. Optional. The name of the Reserved IP that the deployment belongs to. Optional. The list of role instances in the deployment. Optional. The list of roles in the deployment. Optional. Indicates whether the Rollback Update Or Upgrade operation is allowed at this time. Optional. The version of the Azure SDK that was used to generate the .cspkg that created this deployment. The first two numerical components of the returned version represent the version of the SDK used to create the package. Optional. The status of the deployment. Optional. The number of upgrade domains available to this cloud service. Optional. Information about an update occurring on the deployment. Optional. The URL used to access the hosted service. For example, if the service name is MyService you could access the access the service by calling: http://MyService.cloudapp.net. Optional. The virtual IP addresses that are specified for the deployment. Optional. The name of the Virtual Network that the virtual machine connects to. Parameters supplied to the Rollback Update Or Upgrade operation. Initializes a new instance of the DeploymentRollbackUpdateOrUpgradeParameters class. Optional. Specifies whether the rollback should proceed even when it will cause local data to be lost from some role instances. True if the rollback should proceed; otherwise false. Required. Specifies whether the rollback should proceed automatically. The deployment environment in which this deployment is running. The status of the deployment. Parameters supplied to the Swap Deployment operation. Initializes a new instance of the DeploymentSwapParameters class. Optional. The optional name of the production deployment. Required. The name of the source deployment. Parameters supplied to the Update Deployment Status operation. Initializes a new instance of the DeploymentUpdateStatusParameters class. Required. The new status of the deployment. Parameters supplied to the Upgrade Deployment operation. Initializes a new instance of the DeploymentUpgradeParameters class. Required. The service configuration file for the deployment. Optional. Represents the name of an extended deployment property. Each extended property must have a defined name and a value. You can have a maximum of 25 extended property name/value pairs. The maximum length of the name element is 64 characters, only alphanumeric characters and underscores are valid in the name, and the name must start with a letter. Attempting to use other characters, starting the name with a non-letter character, or entering a name that is identical to that of another extended property owned by the same hosted service will result in a status code 400 (Bad Request) error. Optional. Represents an extension that is added to the cloud service. In Azure, a process can run as an extension of a cloud service. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as extensions to the cloud service. You must add an extension to the cloud service by using Add Extension before it can be added to the deployment. Required. Specifies whether the rollback should proceed even when it will cause local data to be lost from some role instances. Required. A name for the hosted service. The name can be up to 100 characters in length. It is recommended that the label be unique within the subscription. The name can be used identify the hosted service for your tracking purposes. Required. The type of update to initiate. Role instances are allocated to update domains when the service is deployed. Updates can be initiated manually in each update domain or initiated automatically in all update domains. Possible values are Auto or Manual. If not specified, the default value is Auto. If set to Manual, WalkUpgradeDomain must be called to apply the update. If set to Auto, the update is automatically applied to each update domain in sequence. Required. A URL that refers to the location of the service package in the Blob service. The service package can be located either in a storage account beneath the same subscription or a Shared Access Signature (SAS) URI from any storage account. For more information about Shared Access Signatures, see Delegating Access with a Shared Access Signature (REST API) at http://msdn.microsoft.com/en-us/library/windowsazure/ee395415.aspx. Optional. The name of the specific role instance to update. The type of the upgrade. Parameters supplied to the Walk Upgrade Domain operation. Initializes a new instance of the DeploymentWalkUpgradeDomainParameters class. Required. An integer value that identifies the update domain to update. Update domains are identified with a zero-based index: the first update domain has an ID of 0, the second has an ID of 1, and so on. Information about a DNS Server in the virtual network. Initializes a new instance of the DnsServer class. Optional. The DNS server address. Optional. The name of the DNS server. The custom DNS settings that are specified for the deployment. Initializes a new instance of the DnsSettings class. Optional. Contains a collection of objects that define the DNS server settings. Specifies the values to use to join the virtual machine to the domain. Initializes a new instance of the DomainJoinCredentials class. Optional. Specifies the name of the domain used to authenticate an account. The value is a fully qualified DNS domain. If the domains name is not specified, Username must specify the user principal name (UPN) format (user@fully-qualified-DNS-domain) or the fully-qualified-DNS-domain\\username format. Example: example.com. Required. Specifies the password to use to join the domain. Required. Specifies a user name in the domain that can be used to join the domain. The configuration needed to provision the machine in the domain. Initializes a new instance of the DomainJoinProvisioning class. Optional. The account info for joining the domain. Contains properties that specify a domain to which the virtual machine will be joined. This element is only used with the WindowsProvisioningConfiguration set. Initializes a new instance of the DomainJoinSettings class. Optional. Specifies the values to use to join the virtual machine to the domain. Optional. Specifies the domain to join. Optional. Specifies the Lightweight Directory Access Protocol (LDAP) X 500-distinguished name of the organizational unit (OU) in which the computer account is created. This account is in Active Directory on a domain controller in the domain to which the computer is being joined. Example: OU=MyOu,OU=MyParentOu,DC=example.com,DC=MyCompany,DC=com. Optional. Additional information for domain join provisioning. The set of access control rules for the endpoint. Initializes a new instance of the EndpointAcl class. Optional. The set of access control rules for the endpoint. Represents an extension that is added to the cloud service. Initializes a new instance of the ExtensionConfiguration class. Optional. Specifies a list of extensions that are applied to all roles in a deployment. Optional. Specifies a list of extensions that are applied to specific roles in a deployment. Represents an extension that is to be deployed to a role in a cloud service. Initializes a new instance of the Extension class. Required. The identifier of the extension. The identifier is created when the extension is added to the cloud service. You can find the ID of an extension that was added to a cloud service by using List Extensions. Specifies a list of extensions that are applied to specific roles in a deployment. Initializes a new instance of the NamedRole class. Required. Represents an extension that is to be deployed to a role in a cloud service. Required. Specifies the name of the role. The configuration for the virtual IP address (VIP) this load balancer provides. Initializes a new instance of the FrontendIPConfiguration class. Optional. If the deployment exists inside a virtual network, a specific address from the load balancer subnet can be specified. The VIP for the load balancer will then be this specific IP address. If a static virtual network IP address is provided, the SubnetName element of the load balancer must be specified as well. If the deployment exists outside of a virtual network, no static virtual network IP address can be specified. Optional. If the deployment exists inside a virtual network, a subnet of that virtual network must be specified for the load balancer. The VIP managed by the load balancer will then be an IP address out of this subnet. If the deployment exists outside of a virtual network, no subnet can be specified and the private VIP will be an IP address from the general private address pool. Optional. The type of the VIP provided by this load balancer. Currently, only 'Private' is supported. This will create load balancing services on a private VIP. The type of the VIP provided by this load balancer. Currently, only 'Private' is supported. This will create load balancing services on a private VIP. This object encapsulates a localized status message from the Guest Agent. Initializes a new instance of the GuestAgentFormattedMessage class. Optional. Language code. Eg. "en-US". Optional. A string containing a message about the status of the Guest Agent or Resource Extension. The guest agent message. Initializes a new instance of the GuestAgentMessage class. Optional. The message resource ID. Optional. The guest agent message parameter list. Optional. This object contains status information of the Guest Agent installed on a RoleInstance. Guest Agent can be installed on a role instance by setting "ProvisionGuestAgent" to true in Create Deployment or Add Role API calls. Version header: Required to be "2014-04-01" or later. Initializes a new instance of the GuestAgentStatus class. Optional. Integer. Status code from the result of applying the GA settings. Optional. This object encapsulates a formatted localized status message from the Guest Agent. Optional. Version of the Guest Agent installed on the role instance. Optional. This object encapsulates a localized status message from the Guest Agent. Optional. Protocol version used by the Guest Agent for status reporting. Optional. The guest agent status, which can be: "Ready" or "NotReady". Optional. UTC time at which the status was reported. The guest agent status, which can be: "Ready" or "NotReady". Parameters supplied to the Add Extension operation. Initializes a new instance of the HostedServiceAddExtensionParameters class. Required. The identifier of the extension. Optional. The private configuration that is defined using the schema returned by the List Available Extensions operation. Optional. The provider namespace of the extension. The provider namespace for Azure extensions is Microsoft.Windows.Azure.Extensions. Optional. The public configuration that is defined using the schema returned by the List Available Extensions operation. Optional. The thumbprint of the certificate that is used to encrypt the configuration specified in PrivateConfiguration. If this element is not specified, a certificate may be automatically generated and added to the cloud service. Optional. The thumbprint algorithm of the certificate that is used to encrypt the configuration specified in PrivateConfiguration. Required. The type of the extension. Optional. Specifies the version of the extension. If this element is not specified or an asterisk (*) is used as the value, the latest version of the extension is used. If the value is specified with a major version number and an asterisk as the minor version number (X.*), the latest minor version of the specified major version is selected. If a major version number and a minor version number are specified (X.Y), the specific extension version is selected. If a version is specified, an auto-upgrade is performed on the role instance. The Check Hosted Service Name Availability operation response. Initializes a new instance of the HostedServiceCheckNameAvailabilityResponse class. Optional. Indicates whether the name is available for you to use. The operation returns false for reserved or profane words. Optional. Describes why the name cannot be used to create the cloud service. Parameters supplied to the Create Hosted Service operation. Initializes a new instance of the HostedServiceCreateParameters class. Optional. The name of an existing affinity group associated with this subscription. Required if Location is not specified. This name is a GUID and can be retrieved by examining the name element of the response body returned by the List Affinity Groups operation. Specify either Location or AffinityGroup, but not both. To list available affinity groups, use the List Affinity Groups operation. Optional. A description for the cloud service. The description can be up to 1024 characters in length. Optional. Represents the name of an extended cloud service property. Each extended property must have a defined name and a value. You can have a maximum of 50 extended property name and value pairs. The maximum length of the name element is 64 characters, only alphanumeric characters and underscores are valid in the name, and it must start with a letter. Attempting to use other characters, starting with a non-letter character, or entering a name that is identical to that of another extended property owned by the same service will result in a status code 400 (Bad Request) error. Each extended property value has a maximum length of 255 characters. Required. A name for the cloud service. The name can be up to 100 characters in length. The name can be used to identify the storage account for your tracking purposes. Optional. The location where the cloud service will be created. Required if AffinityGroup is not specified. Specify either Location or AffinityGroup, but not both. To list available locations, use the List Locations operation. Required. A name for the cloud service that is unique within Azure. This name is the DNS prefix name and can be used to access the service. The detailed Get Hosted Service operation response. The Get Hosted Service operation response. Initializes a new instance of the HostedServiceGetResponse class. Optional. The compute capabilities in this hosted service. Optional. The properties that are assigned to the cloud service. Optional. The name of the cloud service. This name is the DNS prefix name and can be used to access the cloud service. For example, if the cloud service name is MyService you could access the access the cloud service by calling: http://MyService.cloudapp.net. Optional. The Service Management API request URI used to perform Get Hosted Service Properties requests against the cloud service. Initializes a new instance of the HostedServiceGetDetailedResponse class. Optional. The deployments that exist in the cloud service. A deployment that exists in the cloud service. Initializes a new instance of the Deployment class. Optional. The configuration file of the deployment. Optional. The time that the deployment was created. Optional. The deployment environment in which this deployment is running. Optional. The custom DNS settings that are specified for the deployment. Optional. Represents the name of an extended cloud service property. Each extended property must have a defined name and a value. You can have a maximum of 50 extended property name and value pairs. The maximum length of the name element is 64 characters, only alphanumeric characters and underscores are valid in the name, and it must start with a letter. Attempting to use other characters, starting with a non-letter character, or entering a name that is identical to that of another extended property owned by the same service will result in a status code 400 (Bad Request) error. Each extended property value has a maximum length of 255 characters. Optional. The user-supplied name of the deployment. This name can be used identify the deployment for your tracking purposes. Optional. The last time that the deployment was modified. Optional. Indicates whether the deployment is locked for new write operations because an existing operation is updating the deployment. Optional. The name of the deployment. Optional. Specifies information about when the virtual machine has been started and stopped. Optional. The unique identifier for this deployment. Optional. The list of role instances in the deployment. Optional. The list of roles in the deployment. Optional. Indicates whether the Rollback Update Or Upgrade operation is allowed at this time. Optional. The version of the Azure SDK that was used to generate the .cspkg that created this deployment. The first two numerical components of the returned version represent the version of the SDK used to create the package. Optional. The status of the deployment. Optional. The number of upgrade domains available to this cloud service. Optional. Specifies information about an update occurring on the deployment. Optional. The URL used to access the hosted service. For example, if the service name is MyService you could access the access the service by calling: http://MyService.cloudapp.net. Optional. The virtual IP addresses that are specified for thedeployment. Optional. The name of the Virtual Network that the virtual machine connects to. The Get Extension operation response. Initializes a new instance of the HostedServiceGetExtensionResponse class. Optional. The identifier of the extension. Optional. The provider namespace of the extension. The provider namespace for Azure extensions is Microsoft.Windows.Azure.Extensions. Optional. The public configuration that is defined using the schema returned by the List Available Extensions operation. Optional. The thumbprint of the certificate that is used to encrypt the configuration specified in PrivateConfiguration. If this element is not specified, a certificate may be automatically generated and added to the cloud service. Optional. The thumbprint algorithm of the certificate that is used toencrypt the configuration specified in PrivateConfiguration. Required. The type of the extension. Optional. The version of the extension. The List Available Extensions operation response. Initializes a new instance of the HostedServiceListAvailableExtensionsResponse class. Gets the sequence of ExtensionImages. Gets the sequence of ExtensionImages. Optional. The extensions that are available to add to your cloud service. An extension available to add to your cloud service. Initializes a new instance of the ExtensionImage class. Optional. Indicates whether this version of extension blocks the role upon failure. Optional. The description of the extension. Optional. URI string pointing to the EULA (End User License Agreement) of this version of extension. This is optionally specified by the third-party publishing the extension instead of Azure, at the time of extension creation or update. Optional. URI string pointing to the homepage of this version of extension. This is optionally specified by the third-party publishing the extension instead of Azure, at the time of extension creation or update. Optional. The type of resource that supports the extension. This value can be WebRole, WorkerRole, or WebRole|WorkerRole. Optional. Boolean property indicating whether the extension accepts JSON or XML based configuration. If this property is 'true' then the extension accepts JSON based configuration. If this property is 'false' the extension accepts XML based configuration. Optional. The label that is used to identify the extension. Optional. URI string pointing to the privacy document of this version of extension. This is optionally specified by the third-party publishing the extension instead of Azure, at the time of extension creation or update. Optional. The schema of the private configuration. Optional. The provider namespace of the extension. The provider namespace for Azure extensions is Microsoft.Windows.Azure.Extensions. Optional. The schema of the public configuration. Optional. Indicates whether this version of extension has been replicated to all regions or not. If true, then the given extension version can be used in creating or updating deployments. Otherwise, the given extension version might cause failure in creating or updating deployments. The typical time is 20 minutes for a newly-registered or newly-updated extension to replicate completely by Azure. Optional. A sample configuration file for the resource extension. Optional. The thumbprint algorithm of the certificate that is used for encryption. Required. The type of the extension. Optional. The version of the extension. The List Extensions operation response. Initializes a new instance of the HostedServiceListExtensionsResponse class. Gets the sequence of Extensions. Gets the sequence of Extensions. Optional. The extensions that were added to a cloud service. An extension that was added to a cloud service. Initializes a new instance of the Extension class. Optional. The identifier of the extension. Optional. The provider namespace of the extension. The provider namespace for Azure extensions is Microsoft.Windows.Azure.Extensions. Optional. The public configuration that is defined using the schema returned by the List Extensions operation. Optional. The thumbprint of the certificate that is used to encrypt the configuration specified in PrivateConfiguration. If this element is not specified, a certificate may be automatically generated and added to the cloud service. Optional. The thumbprint algorithm of the certificate that is used to encrypt the configuration specified in PrivateConfiguration. Required. The type of the extension. Optional. The version of the extension. The List Hosted Service operation response. Initializes a new instance of the HostedServiceListResponse class. Gets the sequence of HostedServices. Gets the sequence of HostedServices. Optional. The hosted services associated with your subscription. A hosted service associated with your subscription. Initializes a new instance of the HostedService class. Optional. The compute capabilities in this hosted service. Optional. The properties that are assigned to the cloud service. Optional. The name of the cloud service. This name is the DNS prefix name and can be used to access the cloud service. For example, if the cloud service name is MyService you could access the cloud service by calling: http://MyService.cloudapp.net. Optional. The Service Management API request URI used to perform List Hosted Service Properties requests against the cloud service. The properties that are assigned to the cloud service. Initializes a new instance of the HostedServiceProperties class. Optional. The affinity group with which this cloud service is associated, if any. If the service is associated with an affinity group, the Location element is not returned. Optional. The date that the cloud service was created, in [4DigitYear]-[2DigitMonth]-[2DigitDay]T[2DigitHour]:[2DigitMinute]:[2DigitSecond]Z format. The date 2011-05-11T16:15:26Z is an example that could be returned by the DateCreated or DateLastModified elements. Optional. The date that the cloud service was last updated, in [4DigitYear]-[2DigitMonth]-[2DigitDay]T[2DigitHour]:[2DigitMinute]:[2DigitSecond]Z format. The date 2011-05-11T16:15:26Z is an example that could be returned by the DateCreated or DateLastModified elements. Optional. The description for the cloud service. Optional. Represents the name of an extended cloud service property. Each extended property must have a defined name and a value. You can have a maximum of 50 extended property name and value pairs. The maximum length of the name element is 64 characters, only alphanumeric characters and underscores are valid in the name, and it must start with a letter. Attempting to use other characters, starting with a non-letter character, or entering a name that is identical to that of another extended property owned by the same service will result in a status code 400 (Bad Request) error. Each extended property value has a maximum length of 255 characters. Optional. The user-supplied name of the cloud service. This name can be used identify the service for your tracking purposes. Optional. The geo-location of the cloud service in Windows Azure, if the service is not associated with an affinity group. If a location has been specified, the AffinityGroup element is not returned. Optional. The status of the cloud service. The status of the cloud service. Parameters supplied to the Update Hosted Service operation. Initializes a new instance of the HostedServiceUpdateParameters class. Optional. A description for the cloud service. The description may be up to 1024 characters in length. You must specify a value for at least one of Label or Description. Optional. Represents the name of an extended cloud service property. Each extended property must have a defined name and a value. You can have a maximum of 50 extended property name and value pairs. The maximum length of the name element is 64 characters, only alphanumeric characters and underscores are valid in the name, and it must start with a letter. Attempting to use other characters, starting with a non-letter character, or entering a name that is identical to that of another extended property owned by the same service will result in a status code 400 (Bad Request) error. Each extended property value has a maximum length of 255 characters. Optional. A name for the cloud service. The name may be up to 100 characters in length. You must specify a value for at least one of Label or Description. It is recommended that the label be unique within the subscription. The name can be used identify the service for your tracking purposes. Objects that provide input endpoint details. Initializes a new instance of the InputEndpoint class. Optional. Specifies whether direct server return is enabled for the endpoint. Optional. Specifies the list of access control rules for the endpoint. Optional. Specifies a name for a set of load-balanced endpoints. Specifying this name in multiple endpoints adds them all to the set. This element is only listed for Virtual Machine deployments. Optional. Optional. Specify the name of an internal load balancer if this endpoint shall not be exposed on the default load balancer. Optional. Contains properties that specify the endpoint settings which the Azure load balancer uses to monitor the availability of this virtual machine before forwarding traffic to the endpoint. Optional. Specifies the internal port on which the virtual machine is listening to serve the endpoint. This element is only listed for Virtual Machine deployments. Optional. Specifies the name for the external endpoint. This element is only listed for Virtual Machine deployments. Optional. The size of the role instance. Optional. Specifies the transport protocol for the endpoint. Optional. The virtual IP address of the role instance. Specifies the transport protocol for an endpoint. Objects that provide instance endpoint details. Initializes a new instance of the InstanceEndpoint class. Optional. Specifies the internal port on which the virtual machine is listening to serve the endpoint. This element is only listed for Virtual Machine deployments. Optional. Specifies the name for the external endpoint. This element is only listed for Virtual Machine deployments. Optional. The external port of the role instance endpoint. Optional. Specifies the transport protocol for the endpoint. Optional. The Virtual IP of the role endpoint. A list of internal load balancers that each provide load balancing on a private VIP. Initializes a new instance of the LoadBalancer class. Optional. The configuration for the virtual IP address (VIP) this load balancer provides. Optional. The name of the load balancer. Parameters supplied to the Create Load Balancer operation. Initializes a new instance of the LoadBalancerCreateParameters class. Optional. The configuration for the virtual IP address (VIP) this load balancer provides. Optional. Name of the load balancer. Contains properties that specify the endpoint settings which the Azure load balancer uses to monitor the availability of this virtual machine before forwarding traffic to the endpoint. Initializes a new instance of the LoadBalancerProbe class. Optional. Specifies the interval for the load balancer probe in seconds. The minimum value is 5 seconds. If not specified, the default is 15 seconds. Optional. Specifies the relative path name to inspect to determine the virtual machine availability status. If Protocol is set to TCP, this value must be NULL. Optional. Specifies the port to use to inspect the virtual machine availability status. Optional. Specifies the protocol to use to inspect the virtual machine availability status. Optional. Specifies the timeout for the load balancer probe in seconds. The minimum value is 11 seconds. If not specified, the default is 31 seconds. Specifies the protocol to use when inspecting the virtual machine availability status. Describes an operating system family. The List Operating System Families operation response. Initializes a new instance of the OperatingSystemListFamiliesResponse class. Gets the sequence of OperatingSystemFamilies. Gets the sequence of OperatingSystemFamilies. Optional. The operating system families that are valid for your subscription. An operating system that is valid for your subscription. Initializes a new instance of the OperatingSystem class. Optional. Indicates whether this operating system version is currently active for running a service. If an operating system version is active, you can manually configure your service to run on that version. An operating system version may be inactive for one of two reasons: 1. It is not yet active as it is in the process of being rolled out to Azure data centers. If your service is configured to use auto-upgrade, it will be upgraded to the new operating system version during the rollout. If you are manually configuring your operating system version, you can upgrade to the latest version once it becomes active. 2. It is no longer supported for running a service. In this case you will either need to manually configure your service to run on a newer version, or configure your service to use auto-upgrade to manage operating system upgrades. Optional. Indicates whether this operating system version is the default version for a service that has not otherwise specified a particular version. The default operating system version is applied to services that are configured for auto-upgrade. An operating system family has exactly one default operating system version at any given time, for which the IsDefault element is set to true; for all other versions, IsDefault is set to false. Optional. The label of the operating system version. Optional. The operating system version. This value corresponds to the configuration value for specifying that your service is to run on a particular version of the Azure guest operating system. See Configuring Settings for the Windows Azure Guest OS for additional details. An operating system family that is valid for your subscription. Initializes a new instance of the OperatingSystemFamily class. Optional. The label of the operating system family. Optional. Indicates which operating system family this version belongs to. A value of 1 corresponds to the Azure guest operating system that is substantially compatible with Windows Server 2008 SP2. A value of 2 corresponds to the Azure guest operating system that is substantially compatible with Windows Server 2008 R2. Optional. The available operating systems in your subscription belonging to this family. The List Operating Systems operation response. Initializes a new instance of the OperatingSystemListResponse class. Gets the sequence of OperatingSystems. Gets the sequence of OperatingSystems. Optional. The operating systems that are valid for your subscription. An operating system that is valid for your subscription. Initializes a new instance of the OperatingSystem class. Optional. Indicates which operating system family this version belongs to. A value of 1 corresponds to the Azure guest operating system that is substantially compatible with Windows Server 2008 SP2. A value of 2 corresponds to the Azure guest operating system that is substantially compatible with Windows Server 2008 R2. Optional. The label of the operating system family. Optional. Indicates whether this operating system version is currently active for running a service. If an operating system version is active, you can manually configure your service to run on that version. An operating system version may be inactive for one of two reasons: 1. It is not yet active as it is in the process of being rolled out to Azure data centers. If your service is configured to use auto-upgrade, it will be upgraded to the new operating system version during the rollout. If you are manually configuring your operating system version, you can upgrade to the latest version once it becomes active. 2. It is no longer supported for running a service. In this case you will either need to manually configure your service to run on a newer version, or configure your service to use auto-upgrade to manage operating system upgrades. Optional. Indicates whether this operating system version is the default version for a service that has not otherwise specified a particular version. The default operating system version is applied to services that are configured for auto-upgrade. An operating system family has exactly one default operating system version at any given time, for which the IsDefault element is set to true; for all other versions, IsDefault is set to false. Optional. The label of the operating system version. Optional. The operating system version. This value corresponds to the configuration value for specifying that your service is to run on a particular version of the Azure guest operating system. See Configuring Settings for the Windows Azure Guest OS for additional details. The OS disk configuration. Initializes a new instance of the OSDiskConfigurationUpdateParameters class. Optional. Specifies the platform caching behavior of the operating system disk blob for read/write efficiency. The parameters Azure uses to create the operating system disk for the virtual machine. Initializes a new instance of the OSVirtualHardDisk class. Optional. Specifies the platform caching behavior of the operating system disk blob for read/write efficiency. Optional. Specifies the friendly name of an operating system image in the image repository. Optional. Specifies the location of the operating system disk in Azure storage. Optional. Specifies the name of an operating system image in the image repository. Optional. The operating system running in the virtual machine. Optional. Specifies the name of the source image that was used to provision the virtual machine. Contains information about when the virtual machine has been started and stopped. Initializes a new instance of the PersistentVMDowntime class. Optional. The time that the virtual machine was stopped. Optional. The time that the virtual machine was started. Optional. The status of the virtual machine. Specifies the action that is performed after the capture operation finishes. Causes the virtual machine to be deleted after the image has been captured Causes the virtual machine to be redeployed after the image is captured by using the specified information in ProvisioningConfiguration. The status information of the settings passed to the Resource Extension. Initializes a new instance of the ResourceExtensionConfigurationStatus class. Optional. Integer status code from the result of applying the configuration settings. Optional. UTC time at which the configuration was applied. Optional. This object encapsulates a formatted localized status message. Optional. This object encapsulates a localized status message. Optional. Name of the settings passed to the Resource Extension. Optional. Operation executed by the Resource Extension for the settings passed to it. Optional. The status of the resourse extension, containing values like Transitioning, Error, Success, or Warning. Optional. List of substatus objects which contain additional status information reported by the Resource Extension. Optional. UTC time at which the status was reported. The status of the resource extension configuration, containing values like Transitioning, Error, Success, or Warning. Specifies the key, value, and type of the parameter. Initializes a new instance of the ResourceExtensionParameterValue class. Optional. The key of the parameter. Optional. Optional. Public | Private. If this value is set to Private, the parameter will not be returned by Get Deployment. You can only specify one public parameter and one private parameter for a maximum of two parameters. Optional. The value of the parameter. Specifies the properties of a resource extension that should be installed on the Virtual Machine. Initializes a new instance of the ResourceExtensionReference class. Optional. Specifies the name of the resource extension. You can use List Resource Extensions to find the names of available resource extensions. Optional. Specifies the name of the publisher who created the resource extension. You can use List Resource Extensions to find the publisher name of a resource extension. Optional. Specifies the reference name of the resource extension. Optional. Contains a collection of parameters that are passed to the resource extension when it is installed. Optional. Specifies the state of the resource extension.Possible values are: Enable | Disable. The default value is Enable. Optional. Specifies the version of the resource extension. You can use List Resource Extension Versions to find the version of the resource extension. Optional. The status information of a specific Resource Extension. Initializes a new instance of the ResourceExtensionStatus class. Optional. Status code sent by the Resource Extension. Optional. This object encapsulates the extension setting status for the Resource Extension. Optional. This object encapsulates a formatted localized status message from the Resource Extension. Optional. Name of the Resource Extension. Optional. This object encapsulates a localized status message from the Guest Agent. Optional. The resource extension status, which can be "Installing", "Ready", "NotReady", or "Unresponsive". Optional. Version of the Resource Extension. The resource extension status, which can be "Installing", "Ready", "NotReady", or "Unresponsive". A substatus object containing additional status information reported by the Resource Extension. Initializes a new instance of the ResourceExtensionSubStatus class. Optional. Integer status code from the result of applying the substatus settings. Optional. This object encapsulates a formatted localized status message. Optional. This object encapsulates a localized status message. Optional. A name for the substatus. Optional. The resource extension substatus, containing values like Transitioning, Error, Success, or Warning. The resource extension substatus, containing values like Transitioning, Error, Success, or Warning. Details of a role in a deployment. Initializes a new instance of the Role class. Optional. The name of the role. Optional. A collection of values that represents system or application configuration settings. Optional. Contains the parameters Azure uses to create a data disk for a virtual machine. Optional. The read-only thumbprint of the certificate that is used with the HTTPS listener for WinRM. Optional. The friendly name for the role. Optional. Storage location where the VM Image VHDs should be copied, for published VM Images. Optional. The version of the operating system on which the role instances are running. Optional. Contains the parameters Azure uses to create the operating system disk for the virtual machine. Optional. Indicates whether the WindowsAzureGuestAgent service is installed on the Virtual Machine. To run a resource extension in a Virtual Machine, this service must be installed. Optional. Contains a collection of resource extensions that are to be installed on the Virtual Machine. This element is used if ProvisionGuestAgent is set to true. Optional. The name of the role. Optional. The size of the role instance. Optional. Specifies the type of the role. This element is only listed for Virtual Machine deployments, and by default is PersistentVMRole. Optional. Optional. The name of the VMImage from which this Role is to be created. If the OSDisk in the VMImage was Specialized, then no WindowsProvisioningConfigurationSet or LinuxProvisioningConfigurationSet should be provided. No OSVirtualHardDisk or DataVirtualHardDisk should be specified when using this argument. Details of a specific role instance. Initializes a new instance of the RoleInstance class. Optional. Guest Agent Status. Optional. The DNS host name of the service in which the role instance is running. This element is only listed for Virtual Machine deployments. Optional. The list of instance endpoints for the role. Optional. An error code that can be provided to Windows Azure support to assist in resolution of errors. This field will typically be empty. Optional. The fault domain that this role instance belongs to. Role instances that are part of the same fault domain may all be vulnerable to the failure of the same piece of shared hardware. Optional. The name of the specific role instance, if an instance of the role is running. Optional. The size of the role instance. Optional. The instance state, returned as a string that, when present, provides a snapshot of the state of the virtual machine at the time the operation was called. Optional. The current status of this instance. Optional. The update domain that this role instance belongs to. During an Upgrade Deployment, all roles in the same update domain are updated at the same time. Optional. The IP address of the role instance (DIP). Optional. The running state of the role instance. Optional. Optional. A set of public IPs. Currently, only one additional public IP per role is supported in an IaaS deployment. The IP address is in addition to the default VIP for the deployment. Optional. The thumbprint of the RDP server certificate (in Windows) or SSH server certificate (in Linux). The thumbprint is only used for Virtual Machines that have been created from an image. Optional. Resource Extension Status List. Optional. The name of the role. An additional public IP that will be created for the role. The public IP will be an additional IP for the role. The role continues to be addressable via the default deployment VIP. Initializes a new instance of the PublicIP class. Optional. The address of the public IP. Optional. The name of the public IP. The running state of the role instance. The current status of a role instance. The role state is currently unknown. The state should automatically be resolved once the role state is detected, so no action is required. The host agent is currently creating resources for the Virtual Machine. The host agent is starting the Virtual Machine. Azure is creating resources for the role. Azure is starting the role. The role instance has started and is ready to be used. The role instance is unavailable for requests. This state is usually generated while the role is being created or stopped. Azure is stopping the role. The host agent is stopping the Virtual Machine. This status also indicates that the role has already been stopped. The Virtual Machine is being deleted by the host agent. The Virtual Machine is not running. This is the final state of the shutdown process, and no other status messages should be received after StoppedVM. The role has unexpectedly stopped or has failed to start. This status indicates that there is a problem with the role that is causing it to crash or is preventing it from starting, which must be corrected before the role can be started. The InstanceStateDetails and InstanceErrorCode fields can hold information about the role error that caused this state, which may be useful for identifying and debugging the problem. The role has continually crashed after being started by Azure. This status indicates that there is a problem with the role that prevents it from starting, and may be generated after the StartingRole and ReadyRole statuses are received. The problem in the role must be found and corrected before the role can be started. The InstanceStateDetails and InstanceErrorCode fields can hold information about the role error that caused this state, which may be useful for identifying and debugging the problem. The role has continually failed to start. This status indicates that there is a problem with the role that prevents it from starting, and may be generated after the process returns StartingRole. The problem in the role must be found and corrected before the role can be started. The InstanceStateDetails and InstanceErrorCode fields can hold information about the role error that caused this state, which may be useful for identifying and debugging the problem. An Azure or container error is preventing the Virtual Machine from starting. This status is generated by Azure, and does not indicate an error with the role. It may be generated after the StartingRole state. The role has timed out before receiving a status message and is not responding to requests. The rollback proceeds without further user input. You must call the Walk Upgrade Domain operation to apply the rollback to each upgrade domain. Parameters supplied to the Create Service Certificate operation. Initializes a new instance of the ServiceCertificateCreateParameters class. Required. The service certificate format. Azure supports the pfx and cer file formats. Required. The pfx or cer file. Optional. The password for a pfx certificate. A cer certificate does not require a password. Parameters supplied to the Delete Service Certificate operation. Initializes a new instance of the ServiceCertificateDeleteParameters class. Required. The DNS prefix name of your service. Required. The hexadecimal representation of the thumbprint. Required. The algorithm for the certificate's thumbprint. Parameters supplied to the Get Service Certificate operation. Initializes a new instance of the ServiceCertificateGetParameters class. Required. The DNS prefix name of your service. Required. The hexadecimal representation of the thumbprint. Required. The algorithm for the certificate's thumbprint. The Get Service Certificate operation response. Initializes a new instance of the ServiceCertificateGetResponse class. Optional. The public portion of the X.509 service certificate as a form of the cer file. The List Service Certificates operation response. Initializes a new instance of the ServiceCertificateListResponse class. Gets the sequence of Certificates. Gets the sequence of Certificates. Optional. The service certificates that are valid for your subscription. A service certificate that is valid for your subscription. Initializes a new instance of the Certificate class. Optional. The Service Management API request URI used to perform Get Service Certificate requests against the certificate store. Optional. The public part of the service certificate as a cer file. Optional. The X509 certificate thumb print property of the service certificate. Optional. The algorithm that was used to hash the service certificate. Currently SHA-1 is the only supported algorithm. Contains an SSH key pair to be installed on the virtual machine. Initializes a new instance of the SshSettingKeyPair class. Required. Specifies the SHA1 fingerprint of an X509 certificate associated with the hosted service that includes the SSH key pair. Required. Specifies the full path of a file on the virtual machine which stores the SSH private key. The file is overwritten when multiple keys are written to it. The SSH public key is stored in the same directory and has the same name as the private key file with .pub suffix. Example: /home/user/.ssh/id_rsa. Specifies a public key in the SSH settings. Initializes a new instance of the SshSettingPublicKey class. Required. Specifies the SHA1 fingerprint of an X509 certificate associated with the hosted service that includes the SSH public key. Required. Specifies the full path of a file on the virtual machine which stores the SSH public key. If the file already exists, the specified key is appended to the file. Example: /home/user/.ssh/authorized_keys. Specifies the SSH public keys and key pairs to populate in the image during provisioning. This element is only used with the LinuxProvisioningConfiguration set. Initializes a new instance of the SshSettings class. Optional. Specifies the collection of SSH key pairs. Optional. Specifies the collection of SSH public keys. Service certificates with which to provision the new virtual machine. Stored certificate settings reference certificates that already exist in the Azure hosted service. Prior to configuring the stored certificates for the virtual machine, you must call the Add Service Certificate operation or add the certificate via the Azure Management portal. Initializes a new instance of the StoredCertificateSettings class. Required. Specifies the name of the certificate store from which to retrieve certificates. For example, "My". Required. Specifies the thumbprint of the certificate to be provisioned. The thumbprint must specify an existing service certificate. The current state of the upgrade. Contains upgrade details of the deployment. Initializes a new instance of the UpgradeStatus class. Optional. An integer value that identifies the current upgrade domain. Upgrade domains are identified with a zero-based index: the first upgrade domain has an ID of 0, the second has an ID of 1, and so on. Optional. The current state of the upgrade. Possible values are Before and During Optional. The type of the upgrade. Possible values are Auto and Manual. Specifies the platform caching behavior of the data disk blob for read/write efficiency. The virtual IP address of the deployment. Initializes a new instance of the VirtualIPAddress class. Optional. The virtual IP address of the deployment. Optional. Indicates whether the IP address is DNS programmed. Optional. The name of the virtual IP. Parameters supplied to the Capture Virtual Machine operation. Initializes a new instance of the VirtualMachineCaptureOSImageParameters class. Required. Specifies the action that is performed after the capture operation finishes. Possible values are: Delete - this value causes the virtual machine to be deleted after the image has been captured; or Reprovision - this value causes the virtual machine to be redeployed after the image is captured by using the specified information in ProvisioningConfiguration. Optional. Provides information to be used to redeploy the virtual machine after the image has been captured. This element is only used when the PostCaptureAction is set to Reprovision. Required. Specifies the friendly name of the captured image. This is the value that appears in the Name column for the image in the Azure Management Portal. Required. Specifies the image name of the captured image. The Virtual Machine Template Capture Role operation response. Initializes a new instance of the VirtualMachineCaptureVMImageParameters class. Optional. Required. Must be set to CaptureRoleOperation. Optional. Required. The OS state: Generalized | Specialized. Optional. Required. The VM Template Label. Optional. Required. The VM Template Name. Parameters supplied to the Create Virtual Machine Deployment operation. Initializes a new instance of the VirtualMachineCreateDeploymentParameters class. Required. Specifies the environment in which to deploy the virtual machine. Possible values are: Staging or Production. Optional. Contains a list of DNS servers to associate with the machine. Required. A name for the hosted service. The name can be up to 100 characters in length. It is recommended that the label be unique within the subscription. The name can be used identify the hosted service for tracking purposes. Optional. A list of internal load balancers that each provide load balancing on a private VIP. Required. A name for the deployment. The deployment name must be unique among other deployments for the hosted service. Optional. Optional. Specifies the name of an existing reserved IP to which the deployment will belong. Reserved IPs are created by calling the Create Reserved IP operation. Required. Contains the provisioning details for the new virtual machine deployment. Optional. Specifies the name of an existing virtual network to which the deployment will belong. Virtual networks are created by calling the Set Network Configuration operation. Parameters supplied to the Create Virtual Machine operation. Initializes a new instance of the VirtualMachineCreateParameters class. Optional. Specifies the name of an availability set to which to add the virtual machine. This value controls the virtual machine allocation in the Azure environment. Virtual machines specified in the same availability set are allocated to different nodes to maximize availability. Optional. Contains the collection of configuration sets that contain system and application configuration settings. Optional. Contains the parameters Azure used to create the data disk for the virtual machine. Optional. Location where VMImage VHDs should be copied, for published VMImages. Optional. Contains the parameters Azure used to create the operating system disk for the virtual machine. Optional. Indicates whether the WindowsAzureGuestAgent service is installed on the Virtual Machine. To run a resource extension in a Virtual Machine, this service must be installed. Optional. Contains a collection of resource extensions that are to be installed on the Virtual Machine. This element is used if ProvisionGuestAgent is set to true. Required. Specifies the name for the virtual machine. The name must be unique within the deployment. Optional. The size of the virtual machine. Optional. Name of the VMImage from which this Role is to be created. If the OSDisk in the VMImage was Specialized, then no WindowsProvisioningConfigurationSet or LinuxProvisioningConfigurationSet should be provided. No OSVirtualHardDisk or DataVirtualHardDisk should be specified when using this argument. Parameters supplied to the Create Virtual Machine Data Disk operation. Initializes a new instance of the VirtualMachineDataDiskCreateParameters class. Required. Specifies the platform caching behavior of data disk blob for read/write efficiency. The default vault is ReadOnly. Possible values are: None, ReadOnly, or ReadWrite. Warning: Setting this property impacts the consistency of the disk. Optional. Specifies the description of the data disk. When you attach a disk, either by directly referencing a media using the MediaLink element or specifying the target disk size, you can use the DiskLabel element to customize the name property of the target data disk. Optional. Specifies the size, in GB, of an empty disk to be attached to the role. The disk can be created as part of disk attach or create VM role call by specifying the value for this property. Azure creates the empty disk based on size preference and attaches the newly created disk to the Role. Optional. Specifies the Logical Unit Number (LUN) for the disk. The LUN specifies the slot in which the data drive appears when mounted for usage by the virtual machine. Valid LUN values are 0 through 15. Required. Specifies the location of the blob in Azure storage where the media for the disk is located. The blob location must belong to the storage account in the subscription specified by the SubscriptionId value in the operation call. Example: http://example.blob.core.windows.net/disks/mydisk.vhd. Optional. Specifies the name of the disk. Azure uses the specified disk to create the data disk for the machine and populates this field with the disk name. Optional. Specifies the location of a blob in account storage which is mounted as a data disk when the virtual machine is created. The Get Data Disk operation response. Initializes a new instance of the VirtualMachineDataDiskGetResponse class. Optional. The current value of the platform caching behavior of data disk blob for read/write efficiency. Possible values are: None, ReadOnly, or ReadWrite. Optional. The description of the data disk. Optional. The size, in GB, of the data disk. Optional. The Logical Unit Number (LUN) for the disk. The LUN specifies the slot in which the data drive appears when mounted for usage by the virtual machine. Optional. The location of the physical blob backing the data disk. The blob location is in the storage account in the subscription specified by the SubscriptionId value in the operation call. Optional. The name of the data disk. Parameters supplied to the Update Virtual Machine Data Disk operation. Initializes a new instance of the VirtualMachineDataDiskUpdateParameters class. Required. Specifies the platform caching behavior of data disk blob for read/write efficiency. The default vault is ReadOnly. Possible values are: None, ReadOnly, or ReadWrite. Warning: Setting this property impacts the consistency of the disk. Optional. Specifies the description of the data disk. When you attach a disk, either by directly referencing a media using the MediaLink element or specifying the target disk size, you can use the DiskLabel element to customize the name property of the target data disk. Optional. Specifies the size, in GB, of an empty disk to be attached to the role. The disk can be created as part of disk attach or create VM role call by specifying the value for this property. Azure creates the empty disk based on size preference and attaches the newly created disk to the Role. Optional. Specifies the Logical Unit Number (LUN) for the disk. The LUN specifies the slot in which the data drive appears when mounted for usage by the virtual machine. Valid LUN values are 0 through 15. Required. Specifies the location of the blob in Azure blob store where the media for the disk is located. The blob location must belong to the storage account in the subscription specified by the SubscriptionId value in the operation call. Example: http://example.blob.core.windows.net/disks/mydisk.vhd. Optional. Specifies the name of the disk. Azure uses the specified disk to create the data disk for the machine and populates this field with the disk name. Parameters supplied to the Create Virtual Disk Image operation. Initializes a new instance of the VirtualMachineDiskCreateParameters class. Required. Specifies the friendly name of the disk. Required. Specifies the location of the blob in Azure storage. The blob location must belong to a storage account in the subscription specified by the SubscriptionId value in the operation call. Example: http://example.blob.core.windows.net/disks/mydisk.vhd. Required. Specifies a name for the disk. Azure uses the name to identify the disk when creating virtual machines from the disk. Optional. The operating system type of the disk. Possible values are: Linux or Windows. A virtual machine disk associated with your subscription. Initializes a new instance of the VirtualMachineDiskCreateResponse class. Optional. The affinity group in which the disk is located. The AffinityGroup value is derived from storage account that contains the blob in which the media is located. If the storage account does not belong to an affinity group the value is NULL. Optional. Specifies whether the comtained image is a premium image Optional. The friendly name of the disk Optional. The geo-location in which the disk is located. The Location value is derived from storage account that contains the blob in which the disk is located. If the storage account belongs to an affinity group the value is NULL. Optional. The size, in GB, of the disk. Optional. The location of the blob in the blob store in which the media for the disk is located. The blob location belongs to a storage account in the subscription specified by the SubscriptionId value in the operation call. Example: http://example.blob.core.windows.net/disks/mydisk.vhd. Optional. The name of the disk. This is the name that is used when creating one or more virtual machines using the disk. Optional. The Operating System type for the disk. Optional. The name of the OS Image from which the disk was created. This property is populated automatically when a disk is created from an OS image by calling the Add Role, Create Deployment, or Provision Disk operations. Optional. Contains properties that specify a virtual machine that is currently using the disk. A disk cannot be deleted as long as it is attached to a virtual machine. Contains properties that specify a virtual machine that currently using the disk. A disk cannot be deleted as long as it is attached to a virtual machine. Initializes a new instance of the VirtualMachineDiskUsageDetails class. Optional. The deployment in which the disk is being used. Optional. The hosted service in which the disk is being used. Optional. The virtual machine that the disk is attached to. A virtual machine disk associated with your subscription. Initializes a new instance of the VirtualMachineDiskGetResponse class. Optional. The affinity group in which the disk is located. The AffinityGroup value is derived from storage account that contains the blob in which the media is located. If the storage account does not belong to an affinity group the value is NULL. Optional. Specifies whether the disk is known to be corrupt. Optional. Specifies whether or not the disk contains a premium virtual machine image. Optional. The friendly name of the disk. Optional. The geo-location in which the disk is located. The Location value is derived from storage account that contains the blob in which the disk is located. If the storage account belongs to an affinity group the value is NULL. Optional. The size, in GB, of the disk. Optional. The location of the blob in the blob store in which the media for the disk is located. The blob location belongs to a storage account in the subscription specified by the SubscriptionId value in the operation call. Example: http://example.blob.core.windows.net/disks/mydisk.vhd. Optional. The name of the disk. This is the name that is used when creating one or more virtual machines using the disk. Optional. The operating system type of the OS image. Possible Values are: Linux, Windows, or NULL. Optional. The name of the OS Image from which the disk was created. This property is populated automatically when a disk is created from an OS image by calling the Add Role, Create Deployment, or Provision Disk operations. Optional. Contains properties that specify a virtual machine that is currently using the disk. A disk cannot be deleted as long as it is attached to a virtual machine. Contains properties that specify a virtual machine that currently using the disk. A disk cannot be deleted as long as it is attached to a virtual machine. Initializes a new instance of the VirtualMachineDiskUsageDetails class. Optional. The deployment in which the disk is being used. Optional. The hosted service in which the disk is being used. Optional. The virtual machine that the disk is attached to. The List Disks operation response. Initializes a new instance of the VirtualMachineDiskListResponse class. Gets the sequence of Disks. Gets the sequence of Disks. Optional. The virtual machine disks associated with your subscription. A virtual machine disk associated with your subscription. Initializes a new instance of the VirtualMachineDisk class. Optional. The affinity group in which the disk is located. The AffinityGroup value is derived from storage account that contains the blob in which the media is located. If the storage account does not belong to an affinity group the value is NULL. Optional. Specifies thether the disk is known to be corrupt. Optional. Specifies whether or not the disk contains a premium virtual machine image. Optional. The friendly name of the disk. Optional. The geo-location in which the disk is located. The Location value is derived from storage account that contains the blob in which the disk is located. If the storage account belongs to an affinity group the value is NULL. Optional. The size, in GB, of the disk. Optional. The location of the blob in the blob store in which the media for the disk is located. The blob location belongs to a storage account in the subscription specified by the SubscriptionId value in the operation call. Example: http://example.blob.core.windows.net/disks/mydisk.vhd. Optional. The name of the disk. This is the name that is used when creating one or more virtual machines using the disk. Optional. The operating system type of the OS image. Possible Values are: Linux, Windows, or NULL. Optional. The name of the OS Image from which the disk was created. This property is populated automatically when a disk is created from an OS image by calling the Add Role, Create Deployment, or Provision Disk operations. Optional. Contains properties that specify a virtual machine that currently using the disk. A disk cannot be deleted as long as it is attached to a virtual machine. Contains properties that specify a virtual machine that currently using the disk. A disk cannot be deleted as long as it is attached to a virtual machine. Initializes a new instance of the VirtualMachineDiskUsageDetails class. Optional. The deployment in which the disk is being used. Optional. The hosted service in which the disk is being used. Optional. The virtual machine that the disk is attached to. Parameters supplied to the Update Virtual Disk Image operation. Initializes a new instance of the VirtualMachineDiskUpdateParameters class. Optional. Specifies whether the disk contains an operating system. Note: Only a disk with an operating system installed can be mounted as OS Drive. Required. Specifies the friendly name of the disk. Optional. Specifies the location of the blob in Azure storage. The blob location must belong to a storage account in the subscription specified by the SubscriptionId value in the operation call. Example: http://example.blob.core.windows.net/disks/mydisk.vhd. Required. Specifies a name for the disk. Azure uses the name to identify the disk when creating virtual machines from the disk. Optional. The operating system type of the disk. Possible values are: Linux or Windows. A virtual machine disk associated with your subscription. Initializes a new instance of the VirtualMachineDiskUpdateResponse class. Optional. The affinity group in which the disk is located. The AffinityGroup value is derived from storage account that contains the blob in which the media is located. If the storage account does not belong to an affinity group the value is NULL. Optional. Specifies whether the contained image is a premium image. Optional. The friendly name of the disk Optional. The geo-location in which the disk is located. The Location value is derived from storage account that contains the blob in which the disk is located. If the storage account belongs to an affinity group the value is NULL. Optional. The size, in GB, of the disk. Optional. The location of the blob in the blob store in which the media for the disk is located. The blob location belongs to a storage account in the subscription specified by the SubscriptionId value in the operation call. Example: http://example.blob.core.windows.net/disks/mydisk.vhd Optional. The name of the disk. This is the name that is used when creating one or more virtual machines using the disk. Optional. The Operating System type for the disk. The List Resource Extensions operation response. Initializes a new instance of the VirtualMachineExtensionListResponse class. Gets the sequence of ResourceExtensions. Gets the sequence of ResourceExtensions. Optional. The extensions that are available to add to your cloud service. An extension available to add to your virtual machine. Initializes a new instance of the ResourceExtension class. Optional. The description of the extension. Optional. URI string pointing to the EULA (End User License Agreement) of this version of extension. This is optionally specified by the third-party publishing the extension instead of Azure, at the time of extension creation or update. Optional. URI string pointing to the homepage of this version of extension. This is optionally specified by the third-party publishing the extension instead of Azure, at the time of extension creation or update. Optional. Indicates whether the extension accepts JSON or XML based configuration. If this property is 'true' the extension accepts JSON based configuration. If this property is 'false' the extension accepts XML based configuration. Optional. The label that is used to identify the extension. Optional. The name of the extension. Optional. URI string pointing to the privacy document of this version of extension. This is optionally specified by the third-party publishing the extension instead of Azure, at the time of extension creation or update. Optional. The base64-encoded schema of the private configuration. Optional. The base64-encoded schema of the public configuration. Optional. The provider namespace of the extension. The provider namespace for Azure extensions is Microsoft.Compute. Optional. Indicates whether this version of extension has been replicated to all regions or not. If true, then the given extension version can be used in creating or updating deployments. Otherwise, the given extension version might cause failure in creating or updating deployments. The typical time is 20 minutes for a newly-registered or newly-updated extension to replicate completely by Azure. Optional. A sample configuration file for the resource extension. Optional. The version of the extension. The Download RDP file operation response. Initializes a new instance of the VirtualMachineGetRemoteDesktopFileResponse class. Required. A Remote Desktop Protocol (.rdp) file that can be used to establish a remote desktop session to the virtual machine The Get Virtual Machine operation response. Initializes a new instance of the VirtualMachineGetResponse class. Optional. The name of the availability set the virtual machine belongs to. This value controls the virtual machine allocation in the Windows Azure environment. Virtual machines specified in the same availability set are allocated to different nodes to maximize availability. Optional. Contains the collection of configuration sets that contain system and application configuration settings. Optional. Contains the parameters Azure used to create the data disk for the virtual machine. Optional. The read-only thumbprint of the certificate that is used with the HTTPS listener for WinRM. Optional. The version of the operating system on which the role instances are running. Optional. Contains the parameters Azure used to create the operating system disk for the virtual machine. Optional. The name for the virtual machine. The name is unique within Azure. Optional. The size of the virtual machine. Optional. The type of the role for the virtual machine. The only supported value is PersistentVMRole. Parameters supplied to the Create Virtual Machine Image operation. Initializes a new instance of the VirtualMachineOSImageCreateParameters class. Optional. Specifies the description of the OS image. Optional. Specifies the End User License Agreement that is associated with the image. The value for this element is a string, but it is recommended that the value be a URL that points to a EULA. Optional. Specifies the URI to the icon that is displayed for the image in the Management Portal. Optional. Specifies a value that can be used to group OS images. Required. Indicates if the image contains software or associated services that will incur charges above the core price for the virtual machine. Required. Specifies the friendly name of the image. Optional. Specifies the language of the image. The Language element is only available using version 2013-03-01 or higher. Required. Specifies the location of the blob in Azure storage. The blob location must belong to a storage account in the subscription specified by the SubscriptionId value in the operation call. Example: http://example.blob.core.windows.net/disks/mydisk.vhd. Required. Specifies a name that Azure uses to identify the image when creating one or more virtual machines. Required. The operating system type of the OS image. Possible values are: Linux or Windows. Optional. Specifies the URI that points to a document that contains the privacy policy related to the OS image. Optional. Specifies the date when the OS image was added to the image repository. Optional. Specifies the size to use for the virtual machine that is created from the OS image. Required. Specifies whether the image should appear in the image gallery. Optional. Specifies the URI to the small icon that is displayed when the image is presented in the Azure Management Portal. The SmallIconUri element is only available using version 2013-03-01 or higher. Parameters returned from the Create Virtual Machine Image operation. Initializes a new instance of the VirtualMachineOSImageCreateResponse class. Optional. The repository classification of the image. All user images have the category User. Optional. Specifies the description of the OS image. Optional. Specifies the End User License Agreement that is associated with the image. The value for this element is a string, but it is recommended that the value be a URL that points to a EULA. Optional. Specifies the URI to the icon that is displayed for the image in the Management Portal. Optional. Specifies a value that can be used to group OS images. Optional. Indicates if the image contains software or associated services that will incur charges above the core price for the virtual machine. Optional. Specifies the friendly name of the image. Optional. Specifies the language of the image. The Language element is only available using version 2013-03-01 or higher. Optional. The geo-location in which this media is located. The Location value is derived from storage account that contains the blob in which the media is located. If the storage account belongs to an affinity group the value is NULL. If the version is set to 2012-08-01 or later, the locations are returned for platform images; otherwise, this value is NULL for platform images. Optional. The size, in GB, of the image. Optional. Specifies the location of the blob in Azure storage. The blob location must belong to a storage account in the subscription specified by the SubscriptionId value in the operation call. Example: http://example.blob.core.windows.net/disks/mydisk.vhd. Optional. Specifies a name that Azure uses to identify the image when creating one or more virtual machines. Optional. The operating system type of the OS image. Possible values are: Linux or Windows. Optional. Specifies the URI that points to a document that contains the privacy policy related to the OS image. Optional. Specifies the date when the OS image was added to the image repository. Optional. Specifies the name of the publisher of the image. Optional. Specifies the size to use for the virtual machine that is created from the OS image. Optional. Specifies whether the image should appear in the image gallery. Optional. Specifies the URI to the small icon that is displayed when the image is presented in the Azure Management Portal. The SmallIconUri element is only available using version 2013-03-01 or higher. The Get Details OS Images operation response. A virtual machine image associated with your subscription. Initializes a new instance of the VirtualMachineOSImageGetResponse class. Optional. The affinity in which the media is located. The AffinityGroup value is derived from storage account that contains the blob in which the media is located. If the storage account does not belong to an affinity group the value is NULL and the element is not displayed in the response. This value is NULL for platform images. Optional. The repository classification of the image. All user images have the category User. Optional. Specifies the description of the image. Optional. Specifies the End User License Agreement that is associated with the image. The value for this element is a string, but it is recommended that the value be a URL that points to a EULA. Optional. Provides the URI to the icon for this Operating System Image. Optional. Specifies a value that can be used to group images. Optional. Indicates whether the image contains software or associated services that will incur charges above the core price for the virtual machine. For additional details, see the PricingDetailLink element. Optional. An identifier for the image. Optional. Specifies the language of the image. The Language element is only available using version 2013-03-01 or higher. Optional. The geo-location in which this media is located. The Location value is derived from storage account that contains the blob in which the media is located. If the storage account belongs to an affinity group the value is NULL. If the version is set to 2012-08-01 or later, the locations are returned for platform images; otherwise, this value is NULL for platform images. Optional. The size, in GB, of the image. Optional. The location of the blob in Azure storage. The blob location belongs to a storage account in the subscription specified by the SubscriptionId value in the operation call. Example: http://example.blob.core.windows.net/disks/myimage.vhd. Optional. The name of the operating system image. This is the name that is used when creating one or more virtual machines using the image. Optional. The operating system type of the OS image. Possible values are: Linux or Windows. Optional. Specifies the URI that points to a document that contains the privacy policy related to the image. Optional. Specifies the date when the image was added to the image repository. Optional. The name of the publisher of this OS Image in Azure. Optional. Specifies the size to use for the virtual machine that is created from the OS image. Optional. Indicates whether the image should be shown in the Azure portal. Optional. Specifies the URI to the small icon that is displayed when the image is presented in the Azure Management Portal. The SmallIconUri element is only available using version 2013-03-01 or higher. Initializes a new instance of the VirtualMachineOSImageGetDetailsResponse class. Optional. The indicator of whether the image is corrupted or not. Optional. The replication progress information of VM images. The replication progress information of VM images. Initializes a new instance of the ReplicationProgressElement class. Optional. The location of the replication of VM image. Optional. The progress of the replication of VM image. The List OS Images operation response. Initializes a new instance of the VirtualMachineOSImageListResponse class. Gets the sequence of Images. Gets the sequence of Images. Optional. The virtual machine images associated with your subscription. A virtual machine image associated with your subscription. Initializes a new instance of the VirtualMachineOSImage class. Optional. The affinity in which the media is located. The AffinityGroup value is derived from storage account that contains the blob in which the media is located. If the storage account does not belong to an affinity group the value is NULL and the element is not displayed in the response. This value is NULL for platform images. Optional. The repository classification of the image. All user images have the category User. Optional. Specifies the description of the image. Optional. Specifies the End User License Agreement that is associated with the image. The value for this element is a string, but it is recommended that the value be a URL that points to a EULA. Optional. Specifies a value that can be used to group images. Optional. Indicates whether the image contains software or associated services that will incur charges above the core price for the virtual machine. For additional details, see the PricingDetailLink element. Optional. An identifier for the image. Optional. Specifies the language of the image. The Language element is only available using version 2013-03-01 or higher. Optional. The geo-location in which this media is located. The Location value is derived from storage account that contains the blob in which the media is located. If the storage account belongs to an affinity group the value is NULL. If the version is set to 2012-08-01 or later, the locations are returned for platform images; otherwise, this value is NULL for platform images. Optional. The size, in GB, of the image. Optional. The location of the blob in Azure storage. The blob location belongs to a storage account in the subscription specified by the SubscriptionId value in the operation call. Example: http://example.blob.core.windows.net/disks/myimage.vhd Optional. The name of the operating system image. This is the name that is used when creating one or more virtual machines using the image. Optional. The operating system type of the OS image. Possible values are: Linux, Windows. Optional. Specifies a URL for an image with IsPremium set to true, which contains the pricing details for a virtual machine that is created from the image. The PricingDetailLink element is only available using version 2012-12-01 or higher. Optional. Specifies the URI that points to a document that contains the privacy policy related to the image. Optional. Specifies the date when the image was added to the image repository. Optional. The name of the publisher of this OS Image in Azure. Optional. Specifies the size to use for the virtual machine that is created from the OS image. Optional. Specifies the URI to the small icon that is displayed when the image is presented in the Azure Management Portal. The SmallIconUri element is only available using version 2013-03-01 or higher. Known values for the operating system type of the OS in a virtual machine image. Parameters supplied to the Replicate Virtual Machine Image operation. Initializes a new instance of the VirtualMachineOSImageReplicateParameters class. Optional. The replication target regional locations.Note: The regions in the request body are not additive. If an OS Image has already been replicated to Regions A, B, and C, and a request is made to replicate to Regions A and D, the VM Image will remain in Region A, will be replicated in Region D, and will be unreplicated from Regions B and C. The response body contains the published name of the image. Initializes a new instance of the VirtualMachineOSImageReplicateResponse class. Optional. The published name of the image. Specifies the permission type for sharing. Parameters supplied to the Update Virtual Machine Image operation. Initializes a new instance of the VirtualMachineOSImageUpdateParameters class. Optional. Specifies the description of the OS image. Optional. Specifies the End User License Agreement that is associated with the image. The value for this element is a string, but it is recommended that the value be a URL that points to a EULA. Optional. Specifies the URI to the icon that is displayed for the image in the Management Portal. Optional. Specifies a value that can be used to group OS images. Optional. Indicates if the image contains software or associated services that will incur charges above the core price for the virtual machine. Required. Specifies the friendly name of the image to be updated. You cannot use this operation to update images provided by the Azure platform. Optional. Specifies the language of the image. The Language element is only available using version 2013-03-01 or higher. Optional. Specifies the URI that points to a document that contains the privacy policy related to the OS image. Optional. Specifies the date when the OS image was added to the image repository. Optional. Specifies the size to use for the virtual machine that is created from the OS image. Optional. When published, should this image show up in the windows azure image gallery or not. True by default. Optional. Specifies the URI to the small icon that is displayed when the image is presented in the Azure Management Portal. The SmallIconUri element is only available using version 2013-03-01 or higher. Parameters returned from the Create Virtual Machine Image operation. Initializes a new instance of the VirtualMachineOSImageUpdateResponse class. Optional. The repository classification of the image. All user images have the category User. Optional. Specifies the description of the OS image. Optional. Specifies the End User License Agreement that is associated with the image. The value for this element is a string, but it is recommended that the value be a URL that points to a EULA. Optional. Specifies the URI to the icon that is displayed for the image in the Management Portal. Optional. Specifies a value that can be used to group OS images. Optional. Indicates if the image contains software or associated services that will incur charges above the core price for the virtual machine. Optional. Specifies the friendly name of the image. Optional. Specifies the language of the image. The Language element is only available using version 2013-03-01 or higher. Optional. The geo-location in which this media is located. The Location value is derived from storage account that contains the blob in which the media is located. If the storage account belongs to an affinity group the value is NULL. If the version is set to 2012-08-01 or later, the locations are returned for platform images; otherwise, this value is NULL for platform images. Optional. The size, in GB, of the image. Optional. Specifies the location of the blob in Azure storage. The blob location must belong to a storage account in the subscription specified by the SubscriptionId value in the operation call. Example: http://example.blob.core.windows.net/disks/mydisk.vhd. Optional. Specifies a name that Azure uses to identify the image when creating one or more virtual machines. Optional. The operating system type of the OS image. Possible values are: Linux or Windows. Optional. Specifies the URI that points to a document that contains the privacy policy related to the OS image. Optional. Specifies the date when the OS image was added to the image repository. Optional. Specifies the name of the publisher of the image. Optional. Specifies the size to use for the virtual machine that is created from the OS image. Optional. Specifies whether the image should appear in the image gallery. Optional. Specifies the URI to the small icon that is displayed when the image is presented in the Azure Management Portal. The SmallIconUri element is only available using version 2013-03-01 or higher. The size of a virtual machine. The type of the role for the virtual machine. The parameters required for shutting down the virtual machine. Initializes a new instance of the VirtualMachineShutdownParameters class. Optional. The state of the virtual machine after shutdown (Stopped or StoppedDeallocated). Parameters for the shutdown roles operation. Initializes a new instance of the VirtualMachineShutdownRolesParameters class. Optional. The state of the roles after shutdown. Possible values include Stopped or StoppedDeallocated. Optional. The set of roles to shut down. Parameters for the Start Roles operation. Initializes a new instance of the VirtualMachineStartRolesParameters class. Optional. The set of roles to shut down. The set of parameters required to update a load balanced endpoint set. Initializes a new instance of the VirtualMachineUpdateLoadBalancedSetParameters class. Optional. A list of load balanced InputEndpoints to update. The modeled external endpoint for a persistent VM role. Initializes a new instance of the InputEndpoint class. Optional. A Boolean specifying whether this endpoint uses Direct Server Return Required. Specifies whether this endpoint is part of shared LoadBalanced endpoint and served by multiple role instances. If not specified a BadRequest error will be returned. It must also be in use by the deployment (at least one role in the deployment must have an endpoint whose LoadBalancedEndpointSetName matches this) otherwise a BadRequest error will be returned. Optional. Optional. Specify the name of an internal load balancer if this endpoint shall not be exposed on the default load balancer. Optional. This represents an endpoint setting which platform load balancer must monitor to detect the availability of this role before forwarding traffic to this endpoint. If not specified the probe settings (if any) from the existing load balanced endpoint definition will be retained. Optional. Specifies the internal port on which a service running inside the VM is listening to serve this endpoint. WARNING: If specified then ALL the endpoints of this LB set on all the roles will be updated to have THIS local port. To keep unique local ports on each role for a load balanced endpoint specify this as 0 (zero) and if you need to change those use UpdateRole. In case of port conflict with a local port (or probe port) on a role a BadRequestwill be returned. Optional. The name of the InputEndpoint. The name is ignored if specified Optional. An integer specifying the public port for this endpoint. Allowed values are between 1 and 65535 inclusive. A unqiue Port and Protocol combination must be specified for each InputEndpoint in the list. Optional. Specifies the transport protocol for the endpoint. Optional. A collection of access control rules which control the external network traffic reaching to this endpoint. NOTES: (1) To remove the ACLs from a load-balanced endpoint just omit this element. (2) ACLs are set as specified. There is no merge done with existing ACLs. Optional. The virtual IP address of the endpoint. Parameters supplied to the Update Virtual Machine operation. Initializes a new instance of the VirtualMachineUpdateParameters class. Optional. Specifies the name of an availability set to which to add the virtual machine. This value controls the virtual machine allocation in the Azure environment. Virtual machines specified in the same availability set are allocated to different nodes to maximize availability. Optional. Contains the collection of configuration sets that contain system and application configuration settings. Optional. Contains the parameters Azure used to create the data disk for the virtual machine. Optional. Specifies the friendly name for the virtual machine. Required. Contains the parameters Azure used to create the operating system disk for the virtual machine. Optional. Indicates whether the WindowsAzureGuestAgent service is installed on the Virtual Machine. To run a resource extension in a Virtual Machine, this service must be installed. Optional. Contains a collection of resource extensions that are to be installed on the Virtual Machine. This element is used if ProvisionGuestAgent is set to true. Required. Specifies the name for the virtual machine. The name must be unique within the deployment. Optional. The size of the virtual machine. The Get Details VM Images operation response. Initializes a new instance of the VirtualMachineVMImageGetDetailsResponse class. Optional. The affinity group name of the virtual machine image. Optional. The classification of the virtual machine image. Optional. The date when the virtual machine image was created. Optional. The data disk configurations. Optional. The deployment name of the virtual machine image. Optional. The description of the virtual machine image. Optional. Specifies the End User License Agreement that is associated with the image. The value for this element is a string, but it is recommended that the value be a URL that points to a EULA. Optional. Provides the URI to the icon for this Operating System Image. Optional. The image family of the virtual machine image. Optional. The indicator of whether the image is corrupted or not. Optional. The indicator of whether the virtual machine image is premium. Optional. An identifier for the virtual machine image. Optional. The language of the virtual machine image. Optional. The location name of the virtual machine image. Optional. The date when the virtual machine image was created. Optional. The name of the virtual machine image. Optional. The OS disk configuration. Optional. Specifies the URI that points to the pricing detail. Optional. Specifies the URI that points to a document that contains the privacy policy related to the image. Optional. Specifies the date when the image was added to the image repository. Optional. The publisher name of the VM image. Optional. The name of the publisher of this VM Image in Azure. Optional. The recommended size of the virtual machine image. Optional. The replication progress information of VM images. Optional. The role name of the virtual machine image. Optional. The service name of the virtual machine image. Optional. The sharing status of the VM image. Optional. Specifies whether to show in Gui. Optional. Specifies the URI to the small icon that is displayed when the image is presented in the Azure Management Portal. The replication progress information of VM images. Initializes a new instance of the ReplicationProgressElement class. Optional. The location of the replication of VM image. Optional. The progress of the replication of VM image. The List VM Images operation response. Initializes a new instance of the VirtualMachineVMImageListResponse class. Gets the sequence of VMImages. Gets the sequence of VMImages. Optional. The virtual machine images associated with your subscription. The data disk configuration. Initializes a new instance of the DataDiskConfiguration class. Optional. Specifies the platform caching behavior of the data disk blob for read/write efficiency. The default vault is ReadOnly. Optional. Specifies the size, in GB, of an empty VHD to be attached to the virtual machine. The VHD can be created as part of disk attach or create virtual machine calls by specifying the value for this property. Azure creates the empty VHD based on size preference and attaches the newly created VHD to the virtual machine. Optional. Specifies the Logical Unit Number (LUN) for the data disk. The LUN specifies the slot in which the data drive appears when mounted for usage by the virtual machine. This element is only listed when more than one data disk is attached to a virtual machine. Optional. Specifies the location of the disk in Windows Azure storage. Optional. Specifies the name of the VHD to use to create the data disk for the virtual machine. The OS disk configuration. Initializes a new instance of the OSDiskConfiguration class. Optional. Specifies the platform caching behavior of the operating system disk blob for read/write efficiency. Optional. Specifies the size, in GB, of an empty VHD to be attached to the virtual machine. The VHD can be created as part of disk attach or create virtual machine calls by specifying the value for this property. Azure creates the empty VHD based on size preference and attaches the newly created VHD to the virtual machine. Optional. Specifies the location of the disk in Windows Azure storage. Optional. Specifies the name of an operating system image in the image repository. Optional. The operating system running in the virtual machine. Optional. The operating system state in the virtual machine. A virtual machine image associated with your subscription. Initializes a new instance of the VirtualMachineVMImage class. Optional. The affinity group name of the virtual machine image. Optional. The classification of the virtual machine image. Optional. The date when the virtual machine image was created. Optional. The data disk configurations. Optional. The deployment name of the virtual machine image. Optional. The description of the virtual machine image. Optional. Specifies the End User License Agreement that is associated with the image. The value for this element is a string, but it is recommended that the value be a URL that points to a EULA. Optional. Provides the URI to the icon for this Operating System Image. Optional. The image family of the virtual machine image. Optional. The indicator of whether the virtual machine image is premium. Optional. An identifier for the virtual machine image. Optional. The language of the virtual machine image. Optional. The location name of the virtual machine image. Optional. The date when the virtual machine image was created. Optional. The name of the virtual machine image. Optional. The OS disk configuration. Optional. Specifies the URI that points to the pricing detail. Optional. Specifies the URI that points to a document that contains the privacy policy related to the image. Optional. Specifies the date when the image was added to the image repository. Optional. The name of the publisher of this VM Image in Azure. Optional. The recommended size of the virtual machine image. Optional. The role name of the virtual machine image. Optional. The service name of the virtual machine image. Optional. Specifies whether to show in Gui. Optional. Specifies the URI to the small icon that is displayed when the image is presented in the Azure Management Portal. Parameters supplied to the Replicate Virtual Machine Image operation. Initializes a new instance of the VirtualMachineVMImageReplicateParameters class. Optional. The replication target regional locations.Note: The regions in the request body are not additive. If a VM Image has already been replicated to Regions A, B, and C, and a request is made to replicate to Regions A and D, the VM Image will remain in Region A, will be replicated in Region D, and will be unreplicated from Regions B and C. The response body contains the published name of the image. Initializes a new instance of the VirtualMachineVMImageReplicateResponse class. Optional. The published name of the image. Specifies the permission type for sharing. Parameters supplied to the Update Virtual Machine Image operation. Initializes a new instance of the VirtualMachineVMImageUpdateParameters class. Optional. Optional. The Data Disk Configurations. Optional. Specifies the description of the OS image. Optional. Specifies the End User License Agreement that is associated with the image. The value for this element is a string, but it is recommended that the value be a URL that points to a EULA. Optional. Specifies the URI to the icon that is displayed for the image in the Management Portal. Optional. Specifies a value that can be used to group OS images. Required. Specifies the friendly name of the image to be updated. You cannot use this operation to update images provided by the Azure platform. Optional. Specifies the language of the image. Optional. Optional. The OS Disk Configuration. Optional. Specifies the URI that points to a document that contains the privacy policy related to the OS image. Optional. Specifies the date when the OS image was added to the image repository. Optional. Specifies the size to use for the virtual machine that is created from the OS image. Optional. Optional. True or False. Optional. Specifies the URI to the small icon that is displayed when the image is presented in the Azure Management Portal. Specifies the type of listener for enabling remote Windows PowerShell. Contains the type and certificate information for the listener. Initializes a new instance of the WindowsRemoteManagementListener class. Optional. Specifies the certificate thumbprint for the secure connection. If Type is Https then this value is an optional value that is set to the thumbprint of the service certificate that is used to provision the WinRM HTTPS listener. If this value is not specified, a self-signed certificate is generated and used for the virtual machine. Required. Specifies the type of listener. This value can be Http or Https. The value is case sensitive. Configures the Windows Remote Management service on the virtual machine, which enables remote Windows PowerShell. Initializes a new instance of the WindowsRemoteManagementSettings class. Optional. Contains a collection of information for enabling remote Windows PowerShell. Operations for determining the version of the Azure Guest Operating System on which your service is running. (see http://msdn.microsoft.com/en-us/library/windowsazure/ff684169.aspx for more information) Initializes a new instance of the OperatingSystemOperations class. Reference to the service client. The List Operating Systems operation lists the versions of the guest operating system that are currently available in Windows Azure. The 2010-10-28 version of List Operating Systems also indicates what family an operating system version belongs to. Currently Azure supports two operating system families: the Azure guest operating system that is substantially compatible with Windows Server 2008 SP2, and the Azure guest operating system that is substantially compatible with Windows Server 2008 R2. (see http://msdn.microsoft.com/en-us/library/windowsazure/ff684168.aspx for more information) Cancellation token. The List Operating Systems operation response. The List OS Families operation lists the guest operating system families available in Azure, and also lists the operating system versions available for each family. Currently Azure supports two operating system families: the Azure guest operating system that is substantially compatible with Windows Server 2008 SP2, and the Azure guest operating system that is substantially compatible with Windows Server 2008 R2. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441291.aspx for more information) Cancellation token. The List Operating System Families operation response. Gets a reference to the Microsoft.WindowsAzure.Management.Compute.ComputeManagementClient. The Service Management API provides programmatic access to much of the functionality available through the Management Portal. The Service Management API is a REST API. All API operations are performed over SSL, and are mutually authenticated using X.509 v3 certificates. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460799.aspx for more information) The List Operating Systems operation lists the versions of the guest operating system that are currently available in Windows Azure. The 2010-10-28 version of List Operating Systems also indicates what family an operating system version belongs to. Currently Azure supports two operating system families: the Azure guest operating system that is substantially compatible with Windows Server 2008 SP2, and the Azure guest operating system that is substantially compatible with Windows Server 2008 R2. (see http://msdn.microsoft.com/en-us/library/windowsazure/ff684168.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IOperatingSystemOperations. The List Operating Systems operation response. The List Operating Systems operation lists the versions of the guest operating system that are currently available in Windows Azure. The 2010-10-28 version of List Operating Systems also indicates what family an operating system version belongs to. Currently Azure supports two operating system families: the Azure guest operating system that is substantially compatible with Windows Server 2008 SP2, and the Azure guest operating system that is substantially compatible with Windows Server 2008 R2. (see http://msdn.microsoft.com/en-us/library/windowsazure/ff684168.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IOperatingSystemOperations. The List Operating Systems operation response. The List OS Families operation lists the guest operating system families available in Azure, and also lists the operating system versions available for each family. Currently Azure supports two operating system families: the Azure guest operating system that is substantially compatible with Windows Server 2008 SP2, and the Azure guest operating system that is substantially compatible with Windows Server 2008 R2. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441291.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IOperatingSystemOperations. The List Operating System Families operation response. The List OS Families operation lists the guest operating system families available in Azure, and also lists the operating system versions available for each family. Currently Azure supports two operating system families: the Azure guest operating system that is substantially compatible with Windows Server 2008 SP2, and the Azure guest operating system that is substantially compatible with Windows Server 2008 R2. (see http://msdn.microsoft.com/en-us/library/windowsazure/gg441291.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IOperatingSystemOperations. The List Operating System Families operation response. Operations for managing service certificates for your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee795178.aspx for more information) Initializes a new instance of the ServiceCertificateOperations class. Reference to the service client. The Begin Creating Service Certificate operation adds a certificate to a hosted service. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460817.aspx for more information) Required. The DNS prefix name of your service. Required. Parameters supplied to the Begin Creating Service Certificate operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Deleting Service Certificate operation deletes a service certificate from the certificate store of a hosted service. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460803.aspx for more information) Required. Parameters supplied to the Begin Deleting Service Certificate operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Create Service Certificate operation adds a certificate to a hosted service. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460817.aspx for more information) Required. The DNS prefix name of your service. Required. Parameters supplied to the Create Service Certificate operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Service Certificate operation deletes a service certificate from the certificate store of a hosted service. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460803.aspx for more information) Required. Parameters supplied to the Delete Service Certificate operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Get Service Certificate operation returns the public data for the specified X.509 certificate associated with a hosted service. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460792.aspx for more information) Required. Parameters supplied to the Get Service Certificate operation. Cancellation token. The Get Service Certificate operation response. The List Service Certificates operation lists all of the service certificates associated with the specified hosted service. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj154105.aspx for more information) Required. The DNS prefix name of your hosted service. Cancellation token. The List Service Certificates operation response. Gets a reference to the Microsoft.WindowsAzure.Management.Compute.ComputeManagementClient. The Service Management API provides programmatic access to much of the functionality available through the Management Portal. The Service Management API is a REST API. All API operations are performed over SSL, and are mutually authenticated using X.509 v3 certificates. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460799.aspx for more information) The Begin Creating Service Certificate operation adds a certificate to a hosted service. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460817.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IServiceCertificateOperations. Required. The DNS prefix name of your service. Required. Parameters supplied to the Begin Creating Service Certificate operation. A standard service response including an HTTP status code and request ID. The Begin Creating Service Certificate operation adds a certificate to a hosted service. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460817.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IServiceCertificateOperations. Required. The DNS prefix name of your service. Required. Parameters supplied to the Begin Creating Service Certificate operation. A standard service response including an HTTP status code and request ID. The Begin Deleting Service Certificate operation deletes a service certificate from the certificate store of a hosted service. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460803.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IServiceCertificateOperations. Required. Parameters supplied to the Begin Deleting Service Certificate operation. A standard service response including an HTTP status code and request ID. The Begin Deleting Service Certificate operation deletes a service certificate from the certificate store of a hosted service. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460803.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IServiceCertificateOperations. Required. Parameters supplied to the Begin Deleting Service Certificate operation. A standard service response including an HTTP status code and request ID. The Create Service Certificate operation adds a certificate to a hosted service. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460817.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IServiceCertificateOperations. Required. The DNS prefix name of your service. Required. Parameters supplied to the Create Service Certificate operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Create Service Certificate operation adds a certificate to a hosted service. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460817.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IServiceCertificateOperations. Required. The DNS prefix name of your service. Required. Parameters supplied to the Create Service Certificate operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Service Certificate operation deletes a service certificate from the certificate store of a hosted service. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460803.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IServiceCertificateOperations. Required. Parameters supplied to the Delete Service Certificate operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Service Certificate operation deletes a service certificate from the certificate store of a hosted service. This operation is an asynchronous operation. To determine whether the management service has finished processing the request, call Get Operation Status. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460803.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IServiceCertificateOperations. Required. Parameters supplied to the Delete Service Certificate operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Get Service Certificate operation returns the public data for the specified X.509 certificate associated with a hosted service. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460792.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IServiceCertificateOperations. Required. Parameters supplied to the Get Service Certificate operation. The Get Service Certificate operation response. The Get Service Certificate operation returns the public data for the specified X.509 certificate associated with a hosted service. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460792.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IServiceCertificateOperations. Required. Parameters supplied to the Get Service Certificate operation. The Get Service Certificate operation response. The List Service Certificates operation lists all of the service certificates associated with the specified hosted service. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj154105.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IServiceCertificateOperations. Required. The DNS prefix name of your hosted service. The List Service Certificates operation response. The List Service Certificates operation lists all of the service certificates associated with the specified hosted service. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj154105.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IServiceCertificateOperations. Required. The DNS prefix name of your hosted service. The List Service Certificates operation response. The Service Management API includes operations for managing the disks in your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157188.aspx for more information) Initializes a new instance of the VirtualMachineDiskOperations class. Reference to the service client. The Begin Deleting Data Disk operation removes the specified data disk from a virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157179.aspx for more information) Required. The name of your service. Required. The name of the deployment. Required. The name of the role to delete the data disk from. Required. The logical unit number of the disk. Required. Specifies that the source blob for the disk should also be deleted from storage. Cancellation token. A standard service response including an HTTP status code and request ID. The Create Data Disk operation adds a data disk to a virtual machine. There are three ways to create the data disk using the Add Data Disk operation. Option 1 - Attach an empty data disk to the role by specifying the disk label and location of the disk image. Do not include the DiskName and SourceMediaLink elements in the request body. Include the MediaLink element and reference a blob that is in the same geographical region as the role. You can also omit the MediaLink element. In this usage, Azure will create the data disk in the storage account configured as default for the role. Option 2 - Attach an existing data disk that is in the image repository. Do not include the DiskName and SourceMediaLink elements in the request body. Specify the data disk to use by including the DiskName element. Note: If included the in the response body, the MediaLink and LogicalDiskSizeInGB elements are ignored. Option 3 - Specify the location of a blob in your storage account that contain a disk image to use. Include the SourceMediaLink element. Note: If the MediaLink element isincluded, it is ignored. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157199.aspx for more information) Required. The name of your service. Required. The name of the deployment. Required. The name of the role to add the data disk to. Required. Parameters supplied to the Create Virtual Machine Data Disk operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Create Disk operation adds a disk to the user image repository. The disk can be an operating system disk or a data disk. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157178.aspx for more information) Required. Parameters supplied to the Create Virtual Machine Disk operation. Cancellation token. A virtual machine disk associated with your subscription. The Delete Data Disk operation removes the specified data disk from a virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157179.aspx for more information) Required. The name of your service. Required. The name of the deployment. Required. The name of the role to delete the data disk from. Required. The logical unit number of the disk. Required. Specifies that the source blob for the disk should also be deleted from storage. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Disk operation deletes the specified data or operating system disk from your image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157200.aspx for more information) Required. The name of the disk to delete. Required. Specifies that the source blob for the disk should also be deleted from storage. Cancellation token. A standard service response including an HTTP status code and request ID. The Get Data Disk operation retrieves the specified data disk from a virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157180.aspx for more information) Required. The name of your service. Required. The name of the deployment. Required. The name of the role. Required. The logical unit number of the disk. Cancellation token. The Get Data Disk operation response. The Get Disk operation retrieves a disk from the user image repository. The disk can be an operating system disk or a data disk. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157178.aspx for more information) Required. The name of the disk. Cancellation token. A virtual machine disk associated with your subscription. The List Disks operation retrieves a list of the disks in your image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157176.aspx for more information) Cancellation token. The List Disks operation response. The Update Data Disk operation updates the specified data disk attached to the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157190.aspx for more information) Required. The name of your service. Required. The name of the deployment. Required. The name of the role to add the data disk to. Required. The logical unit number of the disk. Required. Parameters supplied to the Update Virtual Machine Data Disk operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Add Disk operation adds a disk to the user image repository. The disk can be an operating system disk or a data disk. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157178.aspx for more information) Required. The name of the disk being updated. Required. Parameters supplied to the Update Virtual Machine Disk operation. Cancellation token. A virtual machine disk associated with your subscription. Gets a reference to the Microsoft.WindowsAzure.Management.Compute.ComputeManagementClient. The Service Management API provides programmatic access to much of the functionality available through the Management Portal. The Service Management API is a REST API. All API operations are performed over SSL, and are mutually authenticated using X.509 v3 certificates. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460799.aspx for more information) The Begin Deleting Data Disk operation removes the specified data disk from a virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157179.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineDiskOperations. Required. The name of your service. Required. The name of the deployment. Required. The name of the role to delete the data disk from. Required. The logical unit number of the disk. Required. Specifies that the source blob for the disk should also be deleted from storage. A standard service response including an HTTP status code and request ID. The Begin Deleting Data Disk operation removes the specified data disk from a virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157179.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineDiskOperations. Required. The name of your service. Required. The name of the deployment. Required. The name of the role to delete the data disk from. Required. The logical unit number of the disk. Required. Specifies that the source blob for the disk should also be deleted from storage. A standard service response including an HTTP status code and request ID. The Create Data Disk operation adds a data disk to a virtual machine. There are three ways to create the data disk using the Add Data Disk operation. Option 1 - Attach an empty data disk to the role by specifying the disk label and location of the disk image. Do not include the DiskName and SourceMediaLink elements in the request body. Include the MediaLink element and reference a blob that is in the same geographical region as the role. You can also omit the MediaLink element. In this usage, Azure will create the data disk in the storage account configured as default for the role. Option 2 - Attach an existing data disk that is in the image repository. Do not include the DiskName and SourceMediaLink elements in the request body. Specify the data disk to use by including the DiskName element. Note: If included the in the response body, the MediaLink and LogicalDiskSizeInGB elements are ignored. Option 3 - Specify the location of a blob in your storage account that contain a disk image to use. Include the SourceMediaLink element. Note: If the MediaLink element isincluded, it is ignored. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157199.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineDiskOperations. Required. The name of your service. Required. The name of the deployment. Required. The name of the role to add the data disk to. Required. Parameters supplied to the Create Virtual Machine Data Disk operation. A standard service response including an HTTP status code and request ID. The Create Data Disk operation adds a data disk to a virtual machine. There are three ways to create the data disk using the Add Data Disk operation. Option 1 - Attach an empty data disk to the role by specifying the disk label and location of the disk image. Do not include the DiskName and SourceMediaLink elements in the request body. Include the MediaLink element and reference a blob that is in the same geographical region as the role. You can also omit the MediaLink element. In this usage, Azure will create the data disk in the storage account configured as default for the role. Option 2 - Attach an existing data disk that is in the image repository. Do not include the DiskName and SourceMediaLink elements in the request body. Specify the data disk to use by including the DiskName element. Note: If included the in the response body, the MediaLink and LogicalDiskSizeInGB elements are ignored. Option 3 - Specify the location of a blob in your storage account that contain a disk image to use. Include the SourceMediaLink element. Note: If the MediaLink element isincluded, it is ignored. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157199.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineDiskOperations. Required. The name of your service. Required. The name of the deployment. Required. The name of the role to add the data disk to. Required. Parameters supplied to the Create Virtual Machine Data Disk operation. A standard service response including an HTTP status code and request ID. The Create Disk operation adds a disk to the user image repository. The disk can be an operating system disk or a data disk. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157178.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineDiskOperations. Required. Parameters supplied to the Create Virtual Machine Disk operation. A virtual machine disk associated with your subscription. The Create Disk operation adds a disk to the user image repository. The disk can be an operating system disk or a data disk. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157178.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineDiskOperations. Required. Parameters supplied to the Create Virtual Machine Disk operation. A virtual machine disk associated with your subscription. The Delete Data Disk operation removes the specified data disk from a virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157179.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineDiskOperations. Required. The name of your service. Required. The name of the deployment. Required. The name of the role to delete the data disk from. Required. The logical unit number of the disk. Required. Specifies that the source blob for the disk should also be deleted from storage. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Data Disk operation removes the specified data disk from a virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157179.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineDiskOperations. Required. The name of your service. Required. The name of the deployment. Required. The name of the role to delete the data disk from. Required. The logical unit number of the disk. Required. Specifies that the source blob for the disk should also be deleted from storage. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Disk operation deletes the specified data or operating system disk from your image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157200.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineDiskOperations. Required. The name of the disk to delete. Required. Specifies that the source blob for the disk should also be deleted from storage. A standard service response including an HTTP status code and request ID. The Delete Disk operation deletes the specified data or operating system disk from your image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157200.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineDiskOperations. Required. The name of the disk to delete. Required. Specifies that the source blob for the disk should also be deleted from storage. A standard service response including an HTTP status code and request ID. The Get Data Disk operation retrieves the specified data disk from a virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157180.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineDiskOperations. Required. The name of your service. Required. The name of the deployment. Required. The name of the role. Required. The logical unit number of the disk. The Get Data Disk operation response. The Get Data Disk operation retrieves the specified data disk from a virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157180.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineDiskOperations. Required. The name of your service. Required. The name of the deployment. Required. The name of the role. Required. The logical unit number of the disk. The Get Data Disk operation response. The Get Disk operation retrieves a disk from the user image repository. The disk can be an operating system disk or a data disk. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157178.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineDiskOperations. Required. The name of the disk. A virtual machine disk associated with your subscription. The Get Disk operation retrieves a disk from the user image repository. The disk can be an operating system disk or a data disk. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157178.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineDiskOperations. Required. The name of the disk. A virtual machine disk associated with your subscription. The List Disks operation retrieves a list of the disks in your image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157176.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineDiskOperations. The List Disks operation response. The List Disks operation retrieves a list of the disks in your image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157176.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineDiskOperations. The List Disks operation response. The Update Data Disk operation updates the specified data disk attached to the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157190.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineDiskOperations. Required. The name of your service. Required. The name of the deployment. Required. The name of the role to add the data disk to. Required. The logical unit number of the disk. Required. Parameters supplied to the Update Virtual Machine Data Disk operation. A standard service response including an HTTP status code and request ID. The Update Data Disk operation updates the specified data disk attached to the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157190.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineDiskOperations. Required. The name of your service. Required. The name of the deployment. Required. The name of the role to add the data disk to. Required. The logical unit number of the disk. Required. Parameters supplied to the Update Virtual Machine Data Disk operation. A standard service response including an HTTP status code and request ID. The Add Disk operation adds a disk to the user image repository. The disk can be an operating system disk or a data disk. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157178.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineDiskOperations. Required. The name of the disk being updated. Required. Parameters supplied to the Update Virtual Machine Disk operation. A virtual machine disk associated with your subscription. The Add Disk operation adds a disk to the user image repository. The disk can be an operating system disk or a data disk. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157178.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineDiskOperations. Required. The name of the disk being updated. Required. Parameters supplied to the Update Virtual Machine Disk operation. A virtual machine disk associated with your subscription. The Service Management API includes operations for managing the virtual machine extensions in your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157206.aspx for more information) Initializes a new instance of the VirtualMachineExtensionOperations class. Reference to the service client. The List Resource Extensions operation lists the resource extensions that are available to add to a Virtual Machine. In Azure, a process can run as a resource extension of a Virtual Machine. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as resource extensions to the Virtual Machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn495441.aspx for more information) Cancellation token. The List Resource Extensions operation response. The List Resource Extension Versions operation lists the versions of a resource extension that are available to add to a Virtual Machine. In Azure, a process can run as a resource extension of a Virtual Machine. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as resource extensions to the Virtual Machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn495440.aspx for more information) Required. The name of the publisher. Required. The name of the extension. Cancellation token. The List Resource Extensions operation response. Gets a reference to the Microsoft.WindowsAzure.Management.Compute.ComputeManagementClient. The Service Management API provides programmatic access to much of the functionality available through the Management Portal. The Service Management API is a REST API. All API operations are performed over SSL, and are mutually authenticated using X.509 v3 certificates. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460799.aspx for more information) The List Resource Extensions operation lists the resource extensions that are available to add to a Virtual Machine. In Azure, a process can run as a resource extension of a Virtual Machine. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as resource extensions to the Virtual Machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn495441.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineExtensionOperations. The List Resource Extensions operation response. The List Resource Extensions operation lists the resource extensions that are available to add to a Virtual Machine. In Azure, a process can run as a resource extension of a Virtual Machine. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as resource extensions to the Virtual Machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn495441.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineExtensionOperations. The List Resource Extensions operation response. The List Resource Extension Versions operation lists the versions of a resource extension that are available to add to a Virtual Machine. In Azure, a process can run as a resource extension of a Virtual Machine. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as resource extensions to the Virtual Machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn495440.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineExtensionOperations. Required. The name of the publisher. Required. The name of the extension. The List Resource Extensions operation response. The List Resource Extension Versions operation lists the versions of a resource extension that are available to add to a Virtual Machine. In Azure, a process can run as a resource extension of a Virtual Machine. For example, Remote Desktop Access or the Azure Diagnostics Agent can run as resource extensions to the Virtual Machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn495440.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineExtensionOperations. Required. The name of the publisher. Required. The name of the extension. The List Resource Extensions operation response. The Service Management API includes operations for managing the virtual machines in your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157206.aspx for more information) Initializes a new instance of the VirtualMachineOperations class. Reference to the service client. The Begin Capturing Role operation creates a copy of the operating system virtual hard disk (VHD) that is deployed in the virtual machine, saves the VHD copy in the same storage location as the operating system VHD, and registers the copy as an image in your image gallery. From the captured image, you can create additional customized virtual machines. For more information about images and disks, see Manage Disks and Images at http://msdn.microsoft.com/en-us/library/windowsazure/jj672979.aspx. For more information about capturing images, see How to Capture an Image of a Virtual Machine Running Windows Server 2008 R2 at http://www.windowsazure.com/en-us/documentation/articles/virtual-machines-capture-image-windows-server/ or How to Capture an Image of a Virtual Machine Running Linux at http://www.windowsazure.com/en-us/documentation/articles/virtual-machines-linux-capture-image/. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157201.aspx for more information) Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to restart. Required. Parameters supplied to the Begin Capturing Virtual Machine operation. Cancellation token. A standard service response including an HTTP status code and request ID. Begin capturing role as VM template. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to restart. Required. Parameters supplied to the Capture Virtual Machine operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Creating Role operation adds a virtual machine to an existing deployment. You can refer to the OSDisk in the Add Role operation in the following ways: Platform/User Image - Set the SourceImageName to a platform or user image. You can optionally specify the DiskName and MediaLink values as part the operation to control the name and location of target disk. When DiskName and MediaLink are specified in this mode, they must not already exist in the system, otherwise a conflict fault is returned; UserDisk - Set DiskName to a user supplied image in image repository. SourceImageName must be set to NULL. All other properties are ignored; or Blob in a Storage Account - Set MediaLink to a blob containing the image. SourceImageName and DiskName are set to NULL. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157186.aspx for more information) Required. The name of your service. Required. The name of your deployment. Required. Parameters supplied to the Begin Creating Virtual Machine operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Creating Virtual Machine Deployment operation provisions a virtual machine based on the supplied configuration. When you create a deployment of a virtual machine, you should make sure that the cloud service and the disk or image that you use are located in the same region. For example, if the cloud service was created in the West US region, the disk or image that you use should also be located in a storage account in the West US region. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157194.aspx for more information) Required. The name of your service. Required. Parameters supplied to the Begin Creating Virtual Machine Deployment operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Deleting Role operation deletes the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157184.aspx for more information) Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to delete. Required. Specifies that the source blob(s) for the virtual machine should also be deleted from storage. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Restarting role operation restarts the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157197.aspx for more information) Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to restart. Cancellation token. A standard service response including an HTTP status code and request ID. The Shutdown Role operation shuts down the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157195.aspx for more information) Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to shutdown. Required. The parameters for the shutdown vm operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Shutting Down Roles operation stops the specified set of virtual machines. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469421.aspx for more information) Required. The name of your service. Required. The name of your deployment. Required. Parameters to pass to the Begin Shutting Down Roles operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Starting Role operation starts the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157189.aspx for more information) Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to start. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Starting Roles operation starts the specified set of virtual machines. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469419.aspx for more information) Required. The name of your service. Required. The name of your deployment. Required. Parameters to pass to the Begin Starting Roles operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Updating Role operation adds a virtual machine to an existing deployment. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157187.aspx for more information) Required. The name of your service. Required. The name of your deployment. Required. The name of your virtual machine. Required. Parameters supplied to the Begin Updating Virtual Machine operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Begin Updating Load Balanced Endpoint Set operation changes the specified load-balanced InputEndpoints on all the roles of an Infrastructure as a Service deployment. Non-load-balanced endpoints must be changed using UpdateRole. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469417.aspx for more information) Required. The name of your service. Required. The name of your deployment. Required. Parameters supplied to the Begin Updating Load Balanced Endpoint Set operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Capture Role operation creates a copy of the operating system virtual hard disk (VHD) that is deployed in the virtual machine, saves the VHD copy in the same storage location as the operating system VHD, and registers the copy as an image in your image gallery. From the captured image, you can create additional customized virtual machines. For more information about images and disks, see Manage Disks and Images at http://msdn.microsoft.com/en-us/library/windowsazure/jj672979.aspx. For more information about capturing images, see How to Capture an Image of a Virtual Machine Running Windows Server 2008 R2 at http://www.windowsazure.com/en-us/documentation/articles/virtual-machines-capture-image-windows-server/ or How to Capture an Image of a Virtual Machine Running Linux at http://www.windowsazure.com/en-us/documentation/articles/virtual-machines-linux-capture-image/. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157201.aspx for more information) Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to restart. Required. Parameters supplied to the Capture Virtual Machine operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Capture role as VM template. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to restart. Required. Parameters supplied to the Capture Virtual Machine operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Create Role operation adds a virtual machine to an existing deployment. You can refer to the OSDisk in the Add Role operation in the following ways: Platform/User Image - Set the SourceImageName to a platform or user image. You can optionally specify the DiskName and MediaLink values as part the operation to control the name and location of target disk. When DiskName and MediaLink are specified in this mode, they must not already exist in the system, otherwise a conflict fault is returned; UserDisk - Set DiskName to a user supplied image in image repository. SourceImageName must be set to NULL. All other properties are ignored; or Blob in a Storage Account - Set MediaLink to a blob containing the image. SourceImageName and DiskName are set to NULL. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157186.aspx for more information) Required. The name of your service. Required. The name of your deployment. Required. Parameters supplied to the Create Virtual Machine operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Create Virtual Machine Deployment operation provisions a virtual machine based on the supplied configuration. When you create a deployment of a virtual machine, you should make sure that the cloud service and the disk or image that you use are located in the same region. For example, if the cloud service was created in the West US region, the disk or image that you use should also be located in a storage account in the West US region. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157194.aspx for more information) Required. The name of your service. Required. Parameters supplied to the Create Virtual Machine Deployment operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Role operation deletes the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157184.aspx for more information) Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to delete. Required. Specifies that the source blob(s) for the virtual machine should also be deleted from storage. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Get Role operation retrieves information about the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157193.aspx for more information) Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine. Cancellation token. The Get Virtual Machine operation response. The Download RDP file operation retrieves the Remote Desktop Protocol configuration file from the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157183.aspx for more information) Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine. Cancellation token. The Download RDP file operation response. The Restart role operation restarts the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157197.aspx for more information) Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to restart. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Shutdown Role operation shuts down the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157195.aspx for more information) Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to shutdown. Required. The parameters for the shutdown virtual machine operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Shutdown Roles operation stops the specified set of virtual machines. Required. The name of your service. Required. The name of your deployment. Required. Parameters to pass to the Shutdown Roles operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Start Role operation starts the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157189.aspx for more information) Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to start. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Start Roles operation starts the specified set of virtual machines. Required. The name of your service. Required. The name of your deployment. Required. Parameters to pass to the Start Roles operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Update Role operation adds a virtual machine to an existing deployment. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157187.aspx for more information) Required. The name of your service. Required. The name of your deployment. Required. The name of your virtual machine. Required. Parameters supplied to the Update Virtual Machine operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Update Load Balanced Endpoint Set operation changes the specified load-balanced InputEndpoints on all the roles of an Infrastructure as a Service deployment. Non-load-balanced endpoints must be changed using UpdateRole. Required. The name of your service. Required. The name of your deployment. Required. Parameters supplied to the Update Load Balanced Endpoint Set operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Gets a reference to the Microsoft.WindowsAzure.Management.Compute.ComputeManagementClient. The Service Management API provides programmatic access to much of the functionality available through the Management Portal. The Service Management API is a REST API. All API operations are performed over SSL, and are mutually authenticated using X.509 v3 certificates. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460799.aspx for more information) The Begin Capturing Role operation creates a copy of the operating system virtual hard disk (VHD) that is deployed in the virtual machine, saves the VHD copy in the same storage location as the operating system VHD, and registers the copy as an image in your image gallery. From the captured image, you can create additional customized virtual machines. For more information about images and disks, see Manage Disks and Images at http://msdn.microsoft.com/en-us/library/windowsazure/jj672979.aspx. For more information about capturing images, see How to Capture an Image of a Virtual Machine Running Windows Server 2008 R2 at http://www.windowsazure.com/en-us/documentation/articles/virtual-machines-capture-image-windows-server/ or How to Capture an Image of a Virtual Machine Running Linux at http://www.windowsazure.com/en-us/documentation/articles/virtual-machines-linux-capture-image/. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157201.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to restart. Required. Parameters supplied to the Begin Capturing Virtual Machine operation. A standard service response including an HTTP status code and request ID. The Begin Capturing Role operation creates a copy of the operating system virtual hard disk (VHD) that is deployed in the virtual machine, saves the VHD copy in the same storage location as the operating system VHD, and registers the copy as an image in your image gallery. From the captured image, you can create additional customized virtual machines. For more information about images and disks, see Manage Disks and Images at http://msdn.microsoft.com/en-us/library/windowsazure/jj672979.aspx. For more information about capturing images, see How to Capture an Image of a Virtual Machine Running Windows Server 2008 R2 at http://www.windowsazure.com/en-us/documentation/articles/virtual-machines-capture-image-windows-server/ or How to Capture an Image of a Virtual Machine Running Linux at http://www.windowsazure.com/en-us/documentation/articles/virtual-machines-linux-capture-image/. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157201.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to restart. Required. Parameters supplied to the Begin Capturing Virtual Machine operation. A standard service response including an HTTP status code and request ID. Begin capturing role as VM template. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to restart. Required. Parameters supplied to the Capture Virtual Machine operation. A standard service response including an HTTP status code and request ID. Begin capturing role as VM template. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to restart. Required. Parameters supplied to the Capture Virtual Machine operation. A standard service response including an HTTP status code and request ID. The Begin Creating Role operation adds a virtual machine to an existing deployment. You can refer to the OSDisk in the Add Role operation in the following ways: Platform/User Image - Set the SourceImageName to a platform or user image. You can optionally specify the DiskName and MediaLink values as part the operation to control the name and location of target disk. When DiskName and MediaLink are specified in this mode, they must not already exist in the system, otherwise a conflict fault is returned; UserDisk - Set DiskName to a user supplied image in image repository. SourceImageName must be set to NULL. All other properties are ignored; or Blob in a Storage Account - Set MediaLink to a blob containing the image. SourceImageName and DiskName are set to NULL. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157186.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. Parameters supplied to the Begin Creating Virtual Machine operation. A standard service response including an HTTP status code and request ID. The Begin Creating Role operation adds a virtual machine to an existing deployment. You can refer to the OSDisk in the Add Role operation in the following ways: Platform/User Image - Set the SourceImageName to a platform or user image. You can optionally specify the DiskName and MediaLink values as part the operation to control the name and location of target disk. When DiskName and MediaLink are specified in this mode, they must not already exist in the system, otherwise a conflict fault is returned; UserDisk - Set DiskName to a user supplied image in image repository. SourceImageName must be set to NULL. All other properties are ignored; or Blob in a Storage Account - Set MediaLink to a blob containing the image. SourceImageName and DiskName are set to NULL. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157186.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. Parameters supplied to the Begin Creating Virtual Machine operation. A standard service response including an HTTP status code and request ID. The Begin Creating Virtual Machine Deployment operation provisions a virtual machine based on the supplied configuration. When you create a deployment of a virtual machine, you should make sure that the cloud service and the disk or image that you use are located in the same region. For example, if the cloud service was created in the West US region, the disk or image that you use should also be located in a storage account in the West US region. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157194.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. Parameters supplied to the Begin Creating Virtual Machine Deployment operation. A standard service response including an HTTP status code and request ID. The Begin Creating Virtual Machine Deployment operation provisions a virtual machine based on the supplied configuration. When you create a deployment of a virtual machine, you should make sure that the cloud service and the disk or image that you use are located in the same region. For example, if the cloud service was created in the West US region, the disk or image that you use should also be located in a storage account in the West US region. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157194.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. Parameters supplied to the Begin Creating Virtual Machine Deployment operation. A standard service response including an HTTP status code and request ID. The Begin Deleting Role operation deletes the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157184.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to delete. Required. Specifies that the source blob(s) for the virtual machine should also be deleted from storage. A standard service response including an HTTP status code and request ID. The Begin Deleting Role operation deletes the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157184.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to delete. Required. Specifies that the source blob(s) for the virtual machine should also be deleted from storage. A standard service response including an HTTP status code and request ID. The Begin Restarting role operation restarts the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157197.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to restart. A standard service response including an HTTP status code and request ID. The Begin Restarting role operation restarts the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157197.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to restart. A standard service response including an HTTP status code and request ID. The Shutdown Role operation shuts down the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157195.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to shutdown. Required. The parameters for the shutdown vm operation. A standard service response including an HTTP status code and request ID. The Shutdown Role operation shuts down the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157195.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to shutdown. Required. The parameters for the shutdown vm operation. A standard service response including an HTTP status code and request ID. The Begin Shutting Down Roles operation stops the specified set of virtual machines. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469421.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. Parameters to pass to the Begin Shutting Down Roles operation. A standard service response including an HTTP status code and request ID. The Begin Shutting Down Roles operation stops the specified set of virtual machines. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469421.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. Parameters to pass to the Begin Shutting Down Roles operation. A standard service response including an HTTP status code and request ID. The Begin Starting Role operation starts the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157189.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to start. A standard service response including an HTTP status code and request ID. The Begin Starting Role operation starts the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157189.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to start. A standard service response including an HTTP status code and request ID. The Begin Starting Roles operation starts the specified set of virtual machines. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469419.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. Parameters to pass to the Begin Starting Roles operation. A standard service response including an HTTP status code and request ID. The Begin Starting Roles operation starts the specified set of virtual machines. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469419.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. Parameters to pass to the Begin Starting Roles operation. A standard service response including an HTTP status code and request ID. The Begin Updating Role operation adds a virtual machine to an existing deployment. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157187.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of your virtual machine. Required. Parameters supplied to the Begin Updating Virtual Machine operation. A standard service response including an HTTP status code and request ID. The Begin Updating Role operation adds a virtual machine to an existing deployment. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157187.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of your virtual machine. Required. Parameters supplied to the Begin Updating Virtual Machine operation. A standard service response including an HTTP status code and request ID. The Begin Updating Load Balanced Endpoint Set operation changes the specified load-balanced InputEndpoints on all the roles of an Infrastructure as a Service deployment. Non-load-balanced endpoints must be changed using UpdateRole. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469417.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. Parameters supplied to the Begin Updating Load Balanced Endpoint Set operation. A standard service response including an HTTP status code and request ID. The Begin Updating Load Balanced Endpoint Set operation changes the specified load-balanced InputEndpoints on all the roles of an Infrastructure as a Service deployment. Non-load-balanced endpoints must be changed using UpdateRole. (see http://msdn.microsoft.com/en-us/library/windowsazure/dn469417.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. Parameters supplied to the Begin Updating Load Balanced Endpoint Set operation. A standard service response including an HTTP status code and request ID. The Capture Role operation creates a copy of the operating system virtual hard disk (VHD) that is deployed in the virtual machine, saves the VHD copy in the same storage location as the operating system VHD, and registers the copy as an image in your image gallery. From the captured image, you can create additional customized virtual machines. For more information about images and disks, see Manage Disks and Images at http://msdn.microsoft.com/en-us/library/windowsazure/jj672979.aspx. For more information about capturing images, see How to Capture an Image of a Virtual Machine Running Windows Server 2008 R2 at http://www.windowsazure.com/en-us/documentation/articles/virtual-machines-capture-image-windows-server/ or How to Capture an Image of a Virtual Machine Running Linux at http://www.windowsazure.com/en-us/documentation/articles/virtual-machines-linux-capture-image/. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157201.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to restart. Required. Parameters supplied to the Capture Virtual Machine operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Capture Role operation creates a copy of the operating system virtual hard disk (VHD) that is deployed in the virtual machine, saves the VHD copy in the same storage location as the operating system VHD, and registers the copy as an image in your image gallery. From the captured image, you can create additional customized virtual machines. For more information about images and disks, see Manage Disks and Images at http://msdn.microsoft.com/en-us/library/windowsazure/jj672979.aspx. For more information about capturing images, see How to Capture an Image of a Virtual Machine Running Windows Server 2008 R2 at http://www.windowsazure.com/en-us/documentation/articles/virtual-machines-capture-image-windows-server/ or How to Capture an Image of a Virtual Machine Running Linux at http://www.windowsazure.com/en-us/documentation/articles/virtual-machines-linux-capture-image/. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157201.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to restart. Required. Parameters supplied to the Capture Virtual Machine operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Capture role as VM template. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to restart. Required. Parameters supplied to the Capture Virtual Machine operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Capture role as VM template. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to restart. Required. Parameters supplied to the Capture Virtual Machine operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Create Role operation adds a virtual machine to an existing deployment. You can refer to the OSDisk in the Add Role operation in the following ways: Platform/User Image - Set the SourceImageName to a platform or user image. You can optionally specify the DiskName and MediaLink values as part the operation to control the name and location of target disk. When DiskName and MediaLink are specified in this mode, they must not already exist in the system, otherwise a conflict fault is returned; UserDisk - Set DiskName to a user supplied image in image repository. SourceImageName must be set to NULL. All other properties are ignored; or Blob in a Storage Account - Set MediaLink to a blob containing the image. SourceImageName and DiskName are set to NULL. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157186.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. Parameters supplied to the Create Virtual Machine operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Create Role operation adds a virtual machine to an existing deployment. You can refer to the OSDisk in the Add Role operation in the following ways: Platform/User Image - Set the SourceImageName to a platform or user image. You can optionally specify the DiskName and MediaLink values as part the operation to control the name and location of target disk. When DiskName and MediaLink are specified in this mode, they must not already exist in the system, otherwise a conflict fault is returned; UserDisk - Set DiskName to a user supplied image in image repository. SourceImageName must be set to NULL. All other properties are ignored; or Blob in a Storage Account - Set MediaLink to a blob containing the image. SourceImageName and DiskName are set to NULL. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157186.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. Parameters supplied to the Create Virtual Machine operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Create Virtual Machine Deployment operation provisions a virtual machine based on the supplied configuration. When you create a deployment of a virtual machine, you should make sure that the cloud service and the disk or image that you use are located in the same region. For example, if the cloud service was created in the West US region, the disk or image that you use should also be located in a storage account in the West US region. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157194.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. Parameters supplied to the Create Virtual Machine Deployment operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Create Virtual Machine Deployment operation provisions a virtual machine based on the supplied configuration. When you create a deployment of a virtual machine, you should make sure that the cloud service and the disk or image that you use are located in the same region. For example, if the cloud service was created in the West US region, the disk or image that you use should also be located in a storage account in the West US region. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157194.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. Parameters supplied to the Create Virtual Machine Deployment operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Role operation deletes the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157184.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to delete. Required. Specifies that the source blob(s) for the virtual machine should also be deleted from storage. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Role operation deletes the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157184.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to delete. Required. Specifies that the source blob(s) for the virtual machine should also be deleted from storage. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Get Role operation retrieves information about the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157193.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine. The Get Virtual Machine operation response. The Get Role operation retrieves information about the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157193.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine. The Get Virtual Machine operation response. The Download RDP file operation retrieves the Remote Desktop Protocol configuration file from the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157183.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine. The Download RDP file operation response. The Download RDP file operation retrieves the Remote Desktop Protocol configuration file from the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157183.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine. The Download RDP file operation response. The Restart role operation restarts the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157197.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to restart. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Restart role operation restarts the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157197.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to restart. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Shutdown Role operation shuts down the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157195.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to shutdown. Required. The parameters for the shutdown virtual machine operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Shutdown Role operation shuts down the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157195.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to shutdown. Required. The parameters for the shutdown virtual machine operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Shutdown Roles operation stops the specified set of virtual machines. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. Parameters to pass to the Shutdown Roles operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Shutdown Roles operation stops the specified set of virtual machines. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. Parameters to pass to the Shutdown Roles operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Start Role operation starts the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157189.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to start. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Start Role operation starts the specified virtual machine. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157189.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of the virtual machine to start. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Start Roles operation starts the specified set of virtual machines. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. Parameters to pass to the Start Roles operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Start Roles operation starts the specified set of virtual machines. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. Parameters to pass to the Start Roles operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Update Role operation adds a virtual machine to an existing deployment. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157187.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of your virtual machine. Required. Parameters supplied to the Update Virtual Machine operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Update Role operation adds a virtual machine to an existing deployment. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157187.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. The name of your virtual machine. Required. Parameters supplied to the Update Virtual Machine operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Update Load Balanced Endpoint Set operation changes the specified load-balanced InputEndpoints on all the roles of an Infrastructure as a Service deployment. Non-load-balanced endpoints must be changed using UpdateRole. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. Parameters supplied to the Update Load Balanced Endpoint Set operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Update Load Balanced Endpoint Set operation changes the specified load-balanced InputEndpoints on all the roles of an Infrastructure as a Service deployment. Non-load-balanced endpoints must be changed using UpdateRole. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOperations. Required. The name of your service. Required. The name of your deployment. Required. Parameters supplied to the Update Load Balanced Endpoint Set operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Service Management API includes operations for managing the OS images in your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157175.aspx for more information) Initializes a new instance of the VirtualMachineOSImageOperations class. Reference to the service client. Share an already replicated OS image. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Required. The name of the virtual machine image to share. Required. The sharing permission: public, msdn, or private. Cancellation token. A standard service response including an HTTP status code and request ID. Unreplicate an OS image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Note: The operation removes the published copies of the user OS Image. It does not remove the actual user OS Image. To remove the actual user OS Image, the publisher will have to call Delete OS Image. Required. The name of the virtual machine image to replicate. Note: The OS Image Name should be the user OS Image, not the published name of the OS Image. Cancellation token. A standard service response including an HTTP status code and request ID. The Create OS Image operation adds an operating system image that is stored in a storage account and is available from the image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157192.aspx for more information) Required. Parameters supplied to the Create Virtual Machine Image operation. Cancellation token. Parameters returned from the Create Virtual Machine Image operation. The Delete OS Image operation deletes the specified OS image from your image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157203.aspx for more information) Required. The name of the image to delete. Required. Specifies that the source blob for the image should also be deleted from storage. Cancellation token. A standard service response including an HTTP status code and request ID. The Get OS Image operation retrieves the details for an operating system image from the image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157191.aspx for more information) Required. The name of the OS image to retrieve. Cancellation token. A virtual machine image associated with your subscription. Gets OS Image's properties and its replication details. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Required. The name of the virtual machine image to replicate. Cancellation token. The Get Details OS Images operation response. The List OS Images operation retrieves a list of the operating system images from the image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157191.aspx for more information) Cancellation token. The List OS Images operation response. Replicate an OS image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Required. The name of the virtual machine OS image to replicate. Required. Parameters supplied to the Replicate Virtual Machine Image operation. Cancellation token. The response body contains the published name of the image. Share an already replicated OS image. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Required. The name of the virtual machine image to share. Required. The sharing permission: public, msdn, or private. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Unreplicate an OS image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Note: The operation removes the published copies of the user OS Image. It does not remove the actual user OS Image. To remove the actual user OS Image, the publisher will have to call Delete OS Image. Required. The name of the virtual machine image to replicate. Note: The OS Image Name should be the user OS Image, not the published name of the OS Image. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Update OS Image operation updates an OS image that in your image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157198.aspx for more information) Required. The name of the virtual machine image to be updated. Required. Parameters supplied to the Update Virtual Machine Image operation. Cancellation token. Parameters returned from the Create Virtual Machine Image operation. Gets a reference to the Microsoft.WindowsAzure.Management.Compute.ComputeManagementClient. The Service Management API provides programmatic access to much of the functionality available through the Management Portal. The Service Management API is a REST API. All API operations are performed over SSL, and are mutually authenticated using X.509 v3 certificates. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460799.aspx for more information) Share an already replicated OS image. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOSImageOperations. Required. The name of the virtual machine image to share. Required. The sharing permission: public, msdn, or private. A standard service response including an HTTP status code and request ID. Share an already replicated OS image. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOSImageOperations. Required. The name of the virtual machine image to share. Required. The sharing permission: public, msdn, or private. A standard service response including an HTTP status code and request ID. Unreplicate an OS image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Note: The operation removes the published copies of the user OS Image. It does not remove the actual user OS Image. To remove the actual user OS Image, the publisher will have to call Delete OS Image. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOSImageOperations. Required. The name of the virtual machine image to replicate. Note: The OS Image Name should be the user OS Image, not the published name of the OS Image. A standard service response including an HTTP status code and request ID. Unreplicate an OS image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Note: The operation removes the published copies of the user OS Image. It does not remove the actual user OS Image. To remove the actual user OS Image, the publisher will have to call Delete OS Image. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOSImageOperations. Required. The name of the virtual machine image to replicate. Note: The OS Image Name should be the user OS Image, not the published name of the OS Image. A standard service response including an HTTP status code and request ID. The Create OS Image operation adds an operating system image that is stored in a storage account and is available from the image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157192.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOSImageOperations. Required. Parameters supplied to the Create Virtual Machine Image operation. Parameters returned from the Create Virtual Machine Image operation. The Create OS Image operation adds an operating system image that is stored in a storage account and is available from the image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157192.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOSImageOperations. Required. Parameters supplied to the Create Virtual Machine Image operation. Parameters returned from the Create Virtual Machine Image operation. The Delete OS Image operation deletes the specified OS image from your image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157203.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOSImageOperations. Required. The name of the image to delete. Required. Specifies that the source blob for the image should also be deleted from storage. A standard service response including an HTTP status code and request ID. The Delete OS Image operation deletes the specified OS image from your image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157203.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOSImageOperations. Required. The name of the image to delete. Required. Specifies that the source blob for the image should also be deleted from storage. A standard service response including an HTTP status code and request ID. The Get OS Image operation retrieves the details for an operating system image from the image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157191.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOSImageOperations. Required. The name of the OS image to retrieve. A virtual machine image associated with your subscription. The Get OS Image operation retrieves the details for an operating system image from the image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157191.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOSImageOperations. Required. The name of the OS image to retrieve. A virtual machine image associated with your subscription. Gets OS Image's properties and its replication details. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOSImageOperations. Required. The name of the virtual machine image to replicate. The Get Details OS Images operation response. Gets OS Image's properties and its replication details. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOSImageOperations. Required. The name of the virtual machine image to replicate. The Get Details OS Images operation response. The List OS Images operation retrieves a list of the operating system images from the image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157191.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOSImageOperations. The List OS Images operation response. The List OS Images operation retrieves a list of the operating system images from the image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157191.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOSImageOperations. The List OS Images operation response. Replicate an OS image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOSImageOperations. Required. The name of the virtual machine OS image to replicate. Required. Parameters supplied to the Replicate Virtual Machine Image operation. The response body contains the published name of the image. Replicate an OS image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOSImageOperations. Required. The name of the virtual machine OS image to replicate. Required. Parameters supplied to the Replicate Virtual Machine Image operation. The response body contains the published name of the image. Share an already replicated OS image. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOSImageOperations. Required. The name of the virtual machine image to share. Required. The sharing permission: public, msdn, or private. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Share an already replicated OS image. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOSImageOperations. Required. The name of the virtual machine image to share. Required. The sharing permission: public, msdn, or private. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Unreplicate an OS image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Note: The operation removes the published copies of the user OS Image. It does not remove the actual user OS Image. To remove the actual user OS Image, the publisher will have to call Delete OS Image. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOSImageOperations. Required. The name of the virtual machine image to replicate. Note: The OS Image Name should be the user OS Image, not the published name of the OS Image. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Unreplicate an OS image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Note: The operation removes the published copies of the user OS Image. It does not remove the actual user OS Image. To remove the actual user OS Image, the publisher will have to call Delete OS Image. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOSImageOperations. Required. The name of the virtual machine image to replicate. Note: The OS Image Name should be the user OS Image, not the published name of the OS Image. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Update OS Image operation updates an OS image that in your image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157198.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOSImageOperations. Required. The name of the virtual machine image to be updated. Required. Parameters supplied to the Update Virtual Machine Image operation. Parameters returned from the Create Virtual Machine Image operation. The Update OS Image operation updates an OS image that in your image repository. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj157198.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineOSImageOperations. Required. The name of the virtual machine image to be updated. Required. Parameters supplied to the Update Virtual Machine Image operation. Parameters returned from the Create Virtual Machine Image operation. The Service Management API includes operations for managing the virtual machine templates in your subscription. Initializes a new instance of the VirtualMachineVMImageOperations class. Reference to the service client. The Begin Deleting Virtual Machine Image operation deletes the specified virtual machine image. Required. The name of the virtual machine image to delete. Required. Specifies that the source blob for the image should also be deleted from storage. Cancellation token. A standard service response including an HTTP status code and request ID. Share an already replicated VM image. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Required. The name of the virtual machine image to share. Required. The sharing permission: public, msdn, or private. Cancellation token. A standard service response including an HTTP status code and request ID. Unreplicate an VM image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Note: The operation removes the published copies of the user VM Image. It does not remove the actual user VM Image. To remove the actual user VM Image, the publisher will have to call Delete VM Image. Required. The name of the virtual machine image to replicate. Note: The VM Image Name should be the user VM Image, not the published name of the VM Image. Cancellation token. A standard service response including an HTTP status code and request ID. The Delete Virtual Machine Image operation deletes the specified virtual machine image. Required. The name of the virtual machine image to delete. Required. Specifies that the source blob for the image should also be deleted from storage. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Gets VMImage's properties and its replication details. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Required. The name of the virtual machine image to replicate. Cancellation token. The Get Details VM Images operation response. The List Virtual Machine Images operation retrieves a list of the virtual machine images. Cancellation token. The List VM Images operation response. Replicate an VM image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Required. The name of the virtual machine image to replicate. Required. Parameters supplied to the Replicate Virtual Machine Image operation. Cancellation token. The response body contains the published name of the image. Share an already replicated VM image. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Required. The name of the virtual machine image to share. Required. The sharing permission: public, msdn, or private. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Unreplicate an VM image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Note: The operation removes the published copies of the user VM Image. It does not remove the actual user VM Image. To remove the actual user VM Image, the publisher will have to call Delete VM Image. Required. The name of the virtual machine image to replicate. Note: The VM Image Name should be the user VM Image, not the published name of the VM Image. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Update VM Image operation updates a VM image that in your image repository. Required. The name of the virtual machine image to be updated. Required. Parameters supplied to the Update Virtual Machine Image operation. Cancellation token. A standard service response including an HTTP status code and request ID. Gets a reference to the Microsoft.WindowsAzure.Management.Compute.ComputeManagementClient. The Service Management API provides programmatic access to much of the functionality available through the Management Portal. The Service Management API is a REST API. All API operations are performed over SSL, and are mutually authenticated using X.509 v3 certificates. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460799.aspx for more information) The Begin Deleting Virtual Machine Image operation deletes the specified virtual machine image. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineVMImageOperations. Required. The name of the virtual machine image to delete. Required. Specifies that the source blob for the image should also be deleted from storage. A standard service response including an HTTP status code and request ID. The Begin Deleting Virtual Machine Image operation deletes the specified virtual machine image. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineVMImageOperations. Required. The name of the virtual machine image to delete. Required. Specifies that the source blob for the image should also be deleted from storage. A standard service response including an HTTP status code and request ID. Share an already replicated VM image. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineVMImageOperations. Required. The name of the virtual machine image to share. Required. The sharing permission: public, msdn, or private. A standard service response including an HTTP status code and request ID. Share an already replicated VM image. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineVMImageOperations. Required. The name of the virtual machine image to share. Required. The sharing permission: public, msdn, or private. A standard service response including an HTTP status code and request ID. Unreplicate an VM image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Note: The operation removes the published copies of the user VM Image. It does not remove the actual user VM Image. To remove the actual user VM Image, the publisher will have to call Delete VM Image. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineVMImageOperations. Required. The name of the virtual machine image to replicate. Note: The VM Image Name should be the user VM Image, not the published name of the VM Image. A standard service response including an HTTP status code and request ID. Unreplicate an VM image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Note: The operation removes the published copies of the user VM Image. It does not remove the actual user VM Image. To remove the actual user VM Image, the publisher will have to call Delete VM Image. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineVMImageOperations. Required. The name of the virtual machine image to replicate. Note: The VM Image Name should be the user VM Image, not the published name of the VM Image. A standard service response including an HTTP status code and request ID. The Delete Virtual Machine Image operation deletes the specified virtual machine image. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineVMImageOperations. Required. The name of the virtual machine image to delete. Required. Specifies that the source blob for the image should also be deleted from storage. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Virtual Machine Image operation deletes the specified virtual machine image. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineVMImageOperations. Required. The name of the virtual machine image to delete. Required. Specifies that the source blob for the image should also be deleted from storage. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Gets VMImage's properties and its replication details. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineVMImageOperations. Required. The name of the virtual machine image to replicate. The Get Details VM Images operation response. Gets VMImage's properties and its replication details. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineVMImageOperations. Required. The name of the virtual machine image to replicate. The Get Details VM Images operation response. The List Virtual Machine Images operation retrieves a list of the virtual machine images. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineVMImageOperations. The List VM Images operation response. The List Virtual Machine Images operation retrieves a list of the virtual machine images. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineVMImageOperations. The List VM Images operation response. Replicate an VM image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineVMImageOperations. Required. The name of the virtual machine image to replicate. Required. Parameters supplied to the Replicate Virtual Machine Image operation. The response body contains the published name of the image. Replicate an VM image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineVMImageOperations. Required. The name of the virtual machine image to replicate. Required. Parameters supplied to the Replicate Virtual Machine Image operation. The response body contains the published name of the image. Share an already replicated VM image. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineVMImageOperations. Required. The name of the virtual machine image to share. Required. The sharing permission: public, msdn, or private. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Share an already replicated VM image. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineVMImageOperations. Required. The name of the virtual machine image to share. Required. The sharing permission: public, msdn, or private. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Unreplicate an VM image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Note: The operation removes the published copies of the user VM Image. It does not remove the actual user VM Image. To remove the actual user VM Image, the publisher will have to call Delete VM Image. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineVMImageOperations. Required. The name of the virtual machine image to replicate. Note: The VM Image Name should be the user VM Image, not the published name of the VM Image. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Unreplicate an VM image to multiple target locations. This operation is only for publishers. You have to be registered as image publisher with Windows Azure to be able to call this. Note: The operation removes the published copies of the user VM Image. It does not remove the actual user VM Image. To remove the actual user VM Image, the publisher will have to call Delete VM Image. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineVMImageOperations. Required. The name of the virtual machine image to replicate. Note: The VM Image Name should be the user VM Image, not the published name of the VM Image. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Update VM Image operation updates a VM image that in your image repository. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineVMImageOperations. Required. The name of the virtual machine image to be updated. Required. Parameters supplied to the Update Virtual Machine Image operation. A standard service response including an HTTP status code and request ID. The Update VM Image operation updates a VM image that in your image repository. Reference to the Microsoft.WindowsAzure.Management.Compute.IVirtualMachineVMImageOperations. Required. The name of the virtual machine image to be updated. Required. Parameters supplied to the Update Virtual Machine Image operation. A standard service response including an HTTP status code and request ID. ================================================ FILE: ironclad-apps/tools/NuBuild2/References/Microsoft.WindowsAzure.Management.Storage.xml ================================================ Microsoft.WindowsAzure.Management.Storage The Service Management API includes operations for managing the storage accounts beneath your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460790.aspx for more information) The Begin Creating Storage Account operation creates a new storage account in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh264518.aspx for more information) Parameters supplied to the Begin Creating Storage Account operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Check Name Availability operation checks if a storage account name is available for use in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj154125.aspx for more information) The desired storage account name to check for availability. Cancellation token. The response to a storage account check name availability request. The Create Storage Account operation creates a new storage account in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh264518.aspx for more information) Parameters supplied to the Create Storage Account operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Storage Account operation deletes the specified storage account from Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh264517.aspx for more information) The name of the storage account to be deleted. Cancellation token. A standard service response including an HTTP status code and request ID. The Get Storage Account Properties operation returns system properties for the specified storage account. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460802.aspx for more information) Name of the storage account to get properties for. Cancellation token. The Get Storage Account Properties operation response. The Get Storage Keys operation returns the primary and secondary access keys for the specified storage account. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460785.aspx for more information) The name of the desired storage account. Cancellation token. The primary and secondary access keys for a storage account. The List Storage Accounts operation lists the storage accounts available under the current subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460787.aspx for more information) Cancellation token. The List Storage Accounts operation response. The Regenerate Keys operation regenerates the primary or secondary access key for the specified storage account. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460795.aspx for more information) Parameters supplied to the Regenerate Keys operation. Cancellation token. The primary and secondary access keys for a storage account. The Update Storage Account operation updates the label and the description, and enables or disables the geo-replication status for a storage account in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh264516.aspx for more information) Name of the storage account to update. Parameters supplied to the Update Storage Account operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Service Management API provides programmatic access to much of the functionality available through the Management Portal. The Service Management API is a REST API. All API operations are performed over SSL and are mutually authenticated using X.509 v3 certificates. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460799.aspx for more information) The Get Operation Status operation returns the status of the specified operation. After calling an asynchronous operation, you can call Get Operation Status to determine whether the operation has succeeded, failed, or is still in progress. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460783.aspx for more information) The request ID for the request you wish to track. The request ID is returned in the x-ms-request-id response header for every request. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Gets the API version. Gets the URI used as the base for all cloud service requests. Gets subscription credentials which uniquely identify Microsoft Azure subscription. The subscription ID forms part of the URI for every service call. Gets or sets the initial timeout for Long Running Operations. Gets or sets the retry timeout for Long Running Operations. The Service Management API includes operations for managing the storage accounts beneath your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460790.aspx for more information) The response to a storage account check name availability request. Initializes a new instance of the CheckNameAvailabilityResponse class. Optional. The result of the availability request indicating if the name is available. Optional. The reason for unavailability, if the requested name is unavailable. The geographical region in which a storage account exists. Indicates whether the storage region is available. A Storage Service associated with your subscription. Initializes a new instance of the StorageAccount class. Optional. Represents the name of an extended storage account property. Each extended property must have both a defined name and a value. You can have a maximum of 50 extended property name/value pairs. The maximum length of the Name element is 64 characters, only alphanumeric characters and underscores are valid in the Name, and the name must start with a letter. Attempting to use other characters, starting the Name with a non-letter character, or entering a name that is identical to that of another extended property owned by the same storage account, will result in a status code 400 (Bad Request) error. Each extended property value has a maximum length of 255 characters. Optional. The name of the storage account. This name is the DNS prefix name and can be used to access blobs, queues, and tables in the storage account. For example, if the service name is MyStorageAccount, you could access the blob containers by calling: http://MyStorageAccount.blob.core.windows.net/mycontainer/. Optional. Details about the storage account. Optional. The Service Management API request URI used to perform Get Storage Account Properties requests against the storage account. Parameters supplied to the Create Storage Account operation. Initializes a new instance of the StorageAccountCreateParameters class. Optional. The name of an existing affinity group in the specified subscription. Required if Location is not specified. You can include either a Location or AffinityGroup element in the request body, but not both. To list available affinity groups, use the List Affinity Groups operation. Optional. A description for the storage account. The description may be up to 1024 characters in length. Optional. Represents the name of an extended storage account property. Each extended property must have a defined name and a value. You can have a maximum of 50 extended property name/value pairs. The maximum length of the Name element is 64 characters, only alphanumeric characters and underscores are valid in the Name, and the name must start with a letter. Attempting to use other characters, starting the Name with a non-letter character, or entering a name that is identical to that of another extended property owned by the same storage account will result in a status code 400 (Bad Request) error. Each extended property value has a maximum length of 255 characters. Optional. Specifies whether the storage account is created with geo-replication enabled. If the element is not included in the request body, the default value is true. If set to true, the data in the storage account is replicated across more than one geographic location to enable resilience in the face of catastrophic service loss. Required. A name for the storage account, specified as abase64-encoded string. The name may be up to 100 characters in length. The name can be used identify the storage account for your tracking purposes. Optional. The location where the storage account is created. Required if AffinityGroup is not specified. You can include either a Location or AffinityGroup element in the request body, but not both. To list available locations, use the List Locations operation. Required. A name for the storage account, unique within Azure. Storage account names must be between 3 and 24 characters in length, and must use numbers and lower-case letters only. This name is the DNS prefix name and can be used to access blobs, queues, and tables in the storage account. For example: http://ServiceName.blob.core.windows.net/mycontainer/. The primary and secondary access keys for a storage account. Initializes a new instance of the StorageAccountGetKeysResponse class. Optional. The primary access key for the storage account. Optional. The secondary access key for the storage account. Optional. The Service Management API request URI used to perform Get Storage Account Properties requests against the storage account. The Get Storage Account Properties operation response. Initializes a new instance of the StorageAccountGetResponse class. Optional. The requested storage account. The List Storage Accounts operation response. Initializes a new instance of the StorageAccountListResponse class. Gets the sequence of StorageAccounts. Gets the sequence of StorageAccounts. Optional. The requested storage accounts. Details about a storage account. Initializes a new instance of the StorageAccountProperties class. Optional. The affinity group with which this storage account is associated. Optional. The user-supplied description of the storage account. Optional. The URLs that are used to perform a retrieval of a public blob, queue, or table object. Optional. Indicates the primary geographical region in which the storage account exists at this time. Optional. Indicates whether geo-replication is enabled.Geo-replication means data in the storage account is replicated across more than one geographic location so as to enable resilience in the face of catastrophic service loss. Optional. Indicates the geographical region in which the storage account is being replicated. The GeoSecondaryRegion element is not returned if geo-replication is "off" for this account. Optional. The user-supplied name of the storage account, returned as a base-64 encoded string. This name can be used identify the storage account for your tracking purposes. Optional. A timestamp that indicates the most recent instance of a failover to the secondary region. In the case of multiple failovers, only the latest failover date and time is maintained. The format of the returned timestamp is: [4DigitYear]-[2DigitMonth]-[2DigitDay]T[2DigitMinute]:[2DigitSecond]:[7DigitsOfPrecision]Z. LastGeoFailoverTime is not returned if there has not been an instance of a failover. Optional. The geo-location specified when the storage account was created. This property is only returned if the storage account is not associated with an affinity group. Optional. The status of the storage account at the time the operation was called. Optional. Indicates whether the primary storage region is available. Optional. Indicates whether the secondary storage region is available. Parameters supplied to the Regenerate Keys operation. Initializes a new instance of the StorageAccountRegenerateKeysParameters class. Required. Specifies which key to regenerate. Required. The name of the desired storage account. The primary and secondary access keys for a storage account. Initializes a new instance of the StorageAccountRegenerateKeysResponse class. Optional. The primary access key for the storage account. Optional. The secondary access key for the storage account. Optional. The Service Management API request URI used to perform Get Storage Account Properties requests against the storage account. The status of the storage account at the time the operation was called. The Storage Account has been created. The Storage Account is being created. The DNS name for the storage account is being propagated. The Storage Account is being deleted. Parameters supplied to the Update Storage Account operation. Initializes a new instance of the StorageAccountUpdateParameters class. Optional. Optional. Represents the name of an extended storage account property. Each extended property must have a defined name and a value. You can have a maximum of 50 extended property name/value pairs. The maximum length of the Name element is 64 characters, only alphanumeric characters and underscores are valid in the Name, and the name must start with a letter. Attempting to use other characters, starting the Name with a non-letter character, or entering a name that is identical to that of another extended property owned by the same storage account will result in a status code 400 (Bad Request) error. Each extended property value has a maximum length of 255 characters. You can delete an extended property by setting the value to NULL. Optional. Indicates whether geo-replication is enabled on the specified storage account. If set to true, the data in the storage account is replicated across more than one geographic location so as to enable resiliency in the face of catastrophic service loss. If the element is not included in the request body, the current value is left unchanged. Important: If you have enabled geo-replication, you can elect to disable it by setting this element to false. When disabled, your data is no longer replicated to a secondary data center and any data in the secondary location will be removed. Enabling geo-replication once it has been disabled will result in the storage account being billed for replicating the current copy of data to the secondary data center. After the existing copy of the data is replicated to the secondary data center, updates are geo-replicated at no additional charge. Optional. A name for the storage account, base64-encoded. The name may be up to 100 characters in length. The name can be used identify the storage account for your tracking purposes. Describes the type of a storage key. The Service Management API includes operations for managing the storage accounts beneath your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460790.aspx for more information) Initializes a new instance of the StorageAccountOperations class. Reference to the service client. The Begin Creating Storage Account operation creates a new storage account in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh264518.aspx for more information) Required. Parameters supplied to the Begin Creating Storage Account operation. Cancellation token. A standard service response including an HTTP status code and request ID. The Check Name Availability operation checks if a storage account name is available for use in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj154125.aspx for more information) Required. The desired storage account name to check for availability. Cancellation token. The response to a storage account check name availability request. The Create Storage Account operation creates a new storage account in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh264518.aspx for more information) Required. Parameters supplied to the Create Storage Account operation. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Storage Account operation deletes the specified storage account from Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh264517.aspx for more information) Required. The name of the storage account to be deleted. Cancellation token. A standard service response including an HTTP status code and request ID. The Get Storage Account Properties operation returns system properties for the specified storage account. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460802.aspx for more information) Required. Name of the storage account to get properties for. Cancellation token. The Get Storage Account Properties operation response. The Get Storage Keys operation returns the primary and secondary access keys for the specified storage account. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460785.aspx for more information) Required. The name of the desired storage account. Cancellation token. The primary and secondary access keys for a storage account. The List Storage Accounts operation lists the storage accounts available under the current subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460787.aspx for more information) Cancellation token. The List Storage Accounts operation response. The Regenerate Keys operation regenerates the primary or secondary access key for the specified storage account. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460795.aspx for more information) Required. Parameters supplied to the Regenerate Keys operation. Cancellation token. The primary and secondary access keys for a storage account. The Update Storage Account operation updates the label and the description, and enables or disables the geo-replication status for a storage account in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh264516.aspx for more information) Required. Name of the storage account to update. Required. Parameters supplied to the Update Storage Account operation. Cancellation token. A standard service response including an HTTP status code and request ID. Gets a reference to the Microsoft.WindowsAzure.Management.Storage.StorageManagementClient. The Service Management API provides programmatic access to much of the functionality available through the Management Portal. The Service Management API is a REST API. All API operations are performed over SSL and are mutually authenticated using X.509 v3 certificates. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460799.aspx for more information) The Begin Creating Storage Account operation creates a new storage account in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh264518.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Storage.IStorageAccountOperations. Required. Parameters supplied to the Begin Creating Storage Account operation. A standard service response including an HTTP status code and request ID. The Begin Creating Storage Account operation creates a new storage account in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh264518.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Storage.IStorageAccountOperations. Required. Parameters supplied to the Begin Creating Storage Account operation. A standard service response including an HTTP status code and request ID. The Check Name Availability operation checks if a storage account name is available for use in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj154125.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Storage.IStorageAccountOperations. Required. The desired storage account name to check for availability. The response to a storage account check name availability request. The Check Name Availability operation checks if a storage account name is available for use in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/jj154125.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Storage.IStorageAccountOperations. Required. The desired storage account name to check for availability. The response to a storage account check name availability request. The Create Storage Account operation creates a new storage account in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh264518.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Storage.IStorageAccountOperations. Required. Parameters supplied to the Create Storage Account operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Create Storage Account operation creates a new storage account in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh264518.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Storage.IStorageAccountOperations. Required. Parameters supplied to the Create Storage Account operation. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Delete Storage Account operation deletes the specified storage account from Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh264517.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Storage.IStorageAccountOperations. Required. The name of the storage account to be deleted. A standard service response including an HTTP status code and request ID. The Delete Storage Account operation deletes the specified storage account from Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh264517.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Storage.IStorageAccountOperations. Required. The name of the storage account to be deleted. A standard service response including an HTTP status code and request ID. The Get Storage Account Properties operation returns system properties for the specified storage account. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460802.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Storage.IStorageAccountOperations. Required. Name of the storage account to get properties for. The Get Storage Account Properties operation response. The Get Storage Account Properties operation returns system properties for the specified storage account. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460802.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Storage.IStorageAccountOperations. Required. Name of the storage account to get properties for. The Get Storage Account Properties operation response. The Get Storage Keys operation returns the primary and secondary access keys for the specified storage account. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460785.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Storage.IStorageAccountOperations. Required. The name of the desired storage account. The primary and secondary access keys for a storage account. The Get Storage Keys operation returns the primary and secondary access keys for the specified storage account. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460785.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Storage.IStorageAccountOperations. Required. The name of the desired storage account. The primary and secondary access keys for a storage account. The List Storage Accounts operation lists the storage accounts available under the current subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460787.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Storage.IStorageAccountOperations. The List Storage Accounts operation response. The List Storage Accounts operation lists the storage accounts available under the current subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460787.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Storage.IStorageAccountOperations. The List Storage Accounts operation response. The Regenerate Keys operation regenerates the primary or secondary access key for the specified storage account. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460795.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Storage.IStorageAccountOperations. Required. Parameters supplied to the Regenerate Keys operation. The primary and secondary access keys for a storage account. The Regenerate Keys operation regenerates the primary or secondary access key for the specified storage account. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460795.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Storage.IStorageAccountOperations. Required. Parameters supplied to the Regenerate Keys operation. The primary and secondary access keys for a storage account. The Update Storage Account operation updates the label and the description, and enables or disables the geo-replication status for a storage account in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh264516.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Storage.IStorageAccountOperations. Required. Name of the storage account to update. Required. Parameters supplied to the Update Storage Account operation. A standard service response including an HTTP status code and request ID. The Update Storage Account operation updates the label and the description, and enables or disables the geo-replication status for a storage account in Azure. (see http://msdn.microsoft.com/en-us/library/windowsazure/hh264516.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Storage.IStorageAccountOperations. Required. Name of the storage account to update. Required. Parameters supplied to the Update Storage Account operation. A standard service response including an HTTP status code and request ID. The Service Management API provides programmatic access to much of the functionality available through the Management Portal. The Service Management API is a REST API. All API operations are performed over SSL and are mutually authenticated using X.509 v3 certificates. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460799.aspx for more information) Initializes a new instance of the StorageManagementClient class. Initializes a new instance of the StorageManagementClient class. Required. Gets subscription credentials which uniquely identify Microsoft Azure subscription. The subscription ID forms part of the URI for every service call. Required. Gets the URI used as the base for all cloud service requests. Initializes a new instance of the StorageManagementClient class. Required. Gets subscription credentials which uniquely identify Microsoft Azure subscription. The subscription ID forms part of the URI for every service call. Initializes a new instance of the StorageManagementClient class. The Http client Initializes a new instance of the StorageManagementClient class. Required. Gets subscription credentials which uniquely identify Microsoft Azure subscription. The subscription ID forms part of the URI for every service call. Required. Gets the URI used as the base for all cloud service requests. The Http client Initializes a new instance of the StorageManagementClient class. Required. Gets subscription credentials which uniquely identify Microsoft Azure subscription. The subscription ID forms part of the URI for every service call. The Http client Clones properties from current instance to another StorageManagementClient instance Instance of StorageManagementClient to clone to The Get Operation Status operation returns the status of the specified operation. After calling an asynchronous operation, you can call Get Operation Status to determine whether the operation has succeeded, failed, or is still in progress. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460783.aspx for more information) Required. The request ID for the request you wish to track. The request ID is returned in the x-ms-request-id response header for every request. Cancellation token. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. Gets the API version. Gets the URI used as the base for all cloud service requests. Gets subscription credentials which uniquely identify Microsoft Azure subscription. The subscription ID forms part of the URI for every service call. Gets or sets the initial timeout for Long Running Operations. Gets or sets the retry timeout for Long Running Operations. The Service Management API includes operations for managing the storage accounts beneath your subscription. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460790.aspx for more information) The Service Management API provides programmatic access to much of the functionality available through the Management Portal. The Service Management API is a REST API. All API operations are performed over SSL and are mutually authenticated using X.509 v3 certificates. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460799.aspx for more information) The Get Operation Status operation returns the status of the specified operation. After calling an asynchronous operation, you can call Get Operation Status to determine whether the operation has succeeded, failed, or is still in progress. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460783.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Storage.IStorageManagementClient. Required. The request ID for the request you wish to track. The request ID is returned in the x-ms-request-id response header for every request. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. The Get Operation Status operation returns the status of the specified operation. After calling an asynchronous operation, you can call Get Operation Status to determine whether the operation has succeeded, failed, or is still in progress. (see http://msdn.microsoft.com/en-us/library/windowsazure/ee460783.aspx for more information) Reference to the Microsoft.WindowsAzure.Management.Storage.IStorageManagementClient. Required. The request ID for the request you wish to track. The request ID is returned in the x-ms-request-id response header for every request. The response body contains the status of the specified asynchronous operation, indicating whether it has succeeded, is inprogress, or has failed. Note that this status is distinct from the HTTP status code returned for the Get Operation Status operation itself. If the asynchronous operation succeeded, the response body includes the HTTP status code for the successful request. If the asynchronous operation failed, the response body includes the HTTP status code for the failed request and error information regarding the failure. ================================================ FILE: ironclad-apps/tools/NuBuild2/References/Microsoft.WindowsAzure.Storage.xml ================================================ Microsoft.WindowsAzure.Storage Represents the status of an asynchronous operation and provides support for cancellation. Cancels the asynchronous operation. Represents a handler that signs HTTP requests. Signs the specified HTTP request so it can be authenticated by the Windows Azure storage services. The HTTP request to sign. An object for tracking the current operation. Represents a handler that signs HTTP requests with no authentication information. Initializes a new instance of the class. Signs the specified HTTP request with no authentication information. The HTTP request to sign. An object for tracking the current operation. Represents a handler that signs HTTP requests with a shared key. Initializes a new instance of the class. A canonicalizer that converts HTTP request data into a standard form appropriate for signing. A object providing credentials for the request. The name of the storage account that the HTTP request will access. Signs the specified HTTP request with a shared key. The HTTP request to sign. An object for tracking the current operation. Represents a handler that signs HTTP requests with a shared key. Initializes a new instance of the class. A canonicalizer that converts HTTP request data into a standard form appropriate for signing. A object providing credentials for the request. The name of the storage account that the HTTP request will access. Signs the specified HTTP request with a shared key. The HTTP request to sign. An object for tracking the current operation. Initializes a new instance of the BlobReadStreamBase class. Blob reference to read from An object that represents the access conditions for the blob. If null, no condition is used. An object that specifies additional options for the request. An object for tracking the current operation. Sets the position within the current stream. A byte offset relative to the origin parameter. A value of type SeekOrigin indicating the reference point used to obtain the new position. The new position within the current stream. Seeking in a BlobReadStream disables MD5 validation. This operation is not supported in BlobReadStreamBase. Not used. This operation is not supported in BlobReadStreamBase. Not used. Not used. Not used. This operation is a no-op in BlobReadStreamBase. Read as much as we can from the internal buffer The buffer to read the data into. The byte offset in buffer at which to begin writing data read from the stream. The maximum number of bytes to read. Number of bytes read from the stream. Calculates the number of bytes to read from the blob. Number of bytes to read. Updates the blob MD5 with newly downloaded content. The buffer to read the data from. The byte offset in buffer at which to begin reading data. The maximum number of bytes to read. Releases the blob resources used by the Stream. true to release both managed and unmanaged resources; false to release only unmanaged resources. Gets a value indicating whether the current stream supports reading. Gets a value indicating whether the current stream supports seeking. Gets a value indicating whether the current stream supports writing. Gets or sets the position within the current stream. Gets the length in bytes of the stream. The length in bytes of the stream. Initializes a new instance of the BlobReadStream class. Blob reference to read from An object that represents the access conditions for the blob. If null, no condition is used. An object that specifies additional options for the request. An object for tracking the current operation. Reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read. The buffer to read the data into. The byte offset in buffer at which to begin writing data read from the stream. The maximum number of bytes to read. The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero (0) if the end of the stream has been reached. Begins an asynchronous read operation. The buffer to read the data into. The byte offset in buffer at which to begin writing data read from the stream. The maximum number of bytes to read. An optional asynchronous callback, to be called when the read is complete. A user-provided object that distinguishes this particular asynchronous read request from other requests. An IAsyncResult that represents the asynchronous read, which could still be pending. Waits for the pending asynchronous read to complete. The reference to the pending asynchronous request to finish. The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero (0) if the end of the stream has been reached. Dispatches an async read operation that either reads from the cache or makes a call to the server. The reference to the pending asynchronous request to finish. The buffer to read the data into. The byte offset in buffer at which to begin writing data read from the stream. The maximum number of bytes to read. Called when the asynchronous DownloadRangeToStream operation completes. The result of the asynchronous operation. Dispatches a sync read operation that either reads from the cache or makes a call to the server. The buffer to read the data into. The byte offset in buffer at which to begin writing data read from the stream. The maximum number of bytes to read. Number of bytes read from the stream. Represents a stream for writing to a blob. Clears all buffers for this stream, causes any buffered data to be written to the underlying blob, and commits the blob. Begins an asynchronous commit operation. An optional asynchronous callback, to be called when the commit is complete. A user-provided object that distinguishes this particular asynchronous commit request from other requests. An ICancellableAsyncResult that represents the asynchronous commit, which could still be pending. Waits for the pending asynchronous commit to complete. The reference to the pending asynchronous request to finish. Begins an asynchronous flush operation. An optional asynchronous callback, to be called when the flush is complete. A user-provided object that distinguishes this particular asynchronous flush request from other requests. An ICancellableAsyncResult that represents the asynchronous flush, which could still be pending. Waits for the pending asynchronous flush to complete. The reference to the pending asynchronous request to finish. Initializes a new instance of the BlobWriteStreamBase class. The service client. An object that represents the access conditions for the blob. If null, no condition is used. An object that specifies additional options for the request. An object for tracking the current operation. Initializes a new instance of the BlobWriteStreamBase class for a block blob. Blob reference to write to. An object that represents the access conditions for the blob. If null, no condition is used. An object that specifies additional options for the request. An object for tracking the current operation. Initializes a new instance of the BlobWriteStreamBase class for a page blob. Blob reference to write to. Size of the page blob. Use true if the page blob is newly created, false otherwise. An object that represents the access conditions for the blob. If null, no condition is used. An object that specifies additional options for the request. An object for tracking the current operation. This operation is not supported in BlobWriteStreamBase. Not used. Not used. Not used. Calculates the new position within the current stream for a Seek operation. A byte offset relative to the origin parameter. A value of type SeekOrigin indicating the reference point used to obtain the new position. The new position within the current stream. This operation is not supported in BlobWriteStreamBase. Not used. Generates a new block ID to be used for PutBlock. Base64 encoded block ID Releases the blob resources used by the Stream. true to release both managed and unmanaged resources; false to release only unmanaged resources. Gets a value indicating whether the current stream supports reading. Gets a value indicating whether the current stream supports seeking. Gets a value indicating whether the current stream supports writing. Gets the length in bytes of the stream. Gets or sets the position within the current stream. Initializes a new instance of the BlobWriteStream class for a block blob. Blob reference to write to. An object that represents the access conditions for the blob. If null, no condition is used. An object that specifies additional options for the request. An object for tracking the current operation. Initializes a new instance of the BlobWriteStream class for a page blob. Blob reference to write to. Size of the page blob. Use true if the page blob is newly created, false otherwise. An object that represents the access conditions for the blob. If null, no condition is used. An object that specifies additional options for the request. An object for tracking the current operation. Sets the position within the current stream. A byte offset relative to the origin parameter. A value of type SeekOrigin indicating the reference point used to obtain the new position. The new position within the current stream. Writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written. An array of bytes. This method copies count bytes from buffer to the current stream. The zero-based byte offset in buffer at which to begin copying bytes to the current stream. The number of bytes to be written to the current stream. Begins an asynchronous write operation. An array of bytes. This method copies count bytes from buffer to the current stream. The zero-based byte offset in buffer at which to begin copying bytes to the current stream. The number of bytes to be written to the current stream. An optional asynchronous callback, to be called when the write is complete. A user-provided object that distinguishes this particular asynchronous write request from other requests. An IAsyncResult that represents the asynchronous write, which could still be pending. Waits for the pending asynchronous write to complete. The reference to the pending asynchronous request to finish. Clears all buffers for this stream and causes any buffered data to be written to the underlying blob. Begins an asynchronous flush operation. An optional asynchronous callback, to be called when the flush is complete. A user-provided object that distinguishes this particular asynchronous flush request from other requests. An ICancellableAsyncResult that represents the asynchronous flush, which could still be pending. Waits for the pending asynchronous flush to complete. The reference to the pending asynchronous request to finish. Called when noPendingWritesEvent is signalled indicating that there are no outstanding write requests. An object containing information to be used by the callback method each time it executes. true if the WaitHandle timed out; false if it was signaled. Releases the blob resources used by the Stream. true to release both managed and unmanaged resources; false to release only unmanaged resources. Clears all buffers for this stream, causes any buffered data to be written to the underlying blob, and commits the blob. Begins an asynchronous commit operation. An optional asynchronous callback, to be called when the commit is complete. A user-provided object that distinguishes this particular asynchronous commit request from other requests. An ICancellableAsyncResult that represents the asynchronous commit, which could still be pending. Waits for the pending asynchronous commit to complete. The reference to the pending asynchronous request to finish. Called when the pending flush operation completes so that we can continue with the commit. The result of the asynchronous operation. Called when the block blob commit operation completes. The result of the asynchronous operation. Called when the page blob commit operation completes. The result of the asynchronous operation. Dispatches a write operation. The reference to the pending asynchronous request to finish. Starts an asynchronous PutBlock operation as soon as the parallel operation semaphore becomes available. Data to be uploaded Block ID MD5 hash of the data to be uploaded The reference to the pending asynchronous request to finish. Called when the asynchronous PutBlock operation completes. The result of the asynchronous operation. Starts an asynchronous WritePages operation as soon as the parallel operation semaphore becomes available. Data to be uploaded Offset within the page blob MD5 hash of the data to be uploaded The reference to the pending asynchronous request to finish. Called when the asynchronous WritePages operation completes. The result of the asynchronous operation. Provides a client-side logical representation of the Windows Azure Blob service. This client is used to configure and execute requests against the Blob service. The service client encapsulates the base URI for the Blob service. If the service client will be used for authenticated access, it also encapsulates the credentials for accessing the storage account. Provides a client-side logical representation of the Windows Azure Blob service. This client is used to configure and execute requests against the Blob service. The service client encapsulates the base URI for the Blob service. If the service client will be used for authenticated access, it also encapsulates the credentials for accessing the storage account. Returns an enumerable collection of containers whose names begin with the specified prefix and that are retrieved lazily. The container name prefix. A value that indicates whether to return container metadata with the listing. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. An enumerable collection of containers that are retrieved lazily. Returns a result segment containing a collection of objects. A returned by a previous listing operation. A result segment of containers. Returns a result segment containing a collection of objects. The container name prefix. A returned by a previous listing operation. A result segment of containers. Returns a result segment containing a collection of containers whose names begin with the specified prefix. The container name prefix. A value that indicates whether to return container metadata with the listing. A non-negative integer value that indicates the maximum number of results to be returned in the result segment, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A returned by a previous listing operation. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A result segment of containers. Returns a result segment containing a collection of containers whose names begin with the specified prefix. The container name prefix. A value that indicates whether to return container metadata with the listing. A non-negative integer value that indicates the maximum number of results to be returned in the result segment, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A continuation token returned by a previous listing operation. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A result segment of containers. Begins an asynchronous request to return a result segment containing a collection of containers. A continuation token returned by a previous listing operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to return a result segment containing a collection of containers. The container name prefix. A continuation token returned by a previous listing operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to return a result segment containing a collection of containers whose names begin with the specified prefix. The container name prefix. A value that indicates whether to return container metadata with the listing. A non-negative integer value that indicates the maximum number of results to be returned in the result segment, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A continuation token returned by a previous listing operation. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to return a result segment containing a collection of containers. An that references the pending asynchronous operation. A result segment of containers. Returns a task that performs an asynchronous request to return a result segment containing a collection of containers. A continuation token returned by a previous listing operation. A object that represents the current operation. Returns a task that performs an asynchronous request to return a result segment containing a collection of containers. A continuation token returned by a previous listing operation. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous request to return a result segment containing a collection of containers. The container name prefix. A continuation token returned by a previous listing operation. A object that represents the current operation. Returns a task that performs an asynchronous request to return a result segment containing a collection of containers. The container name prefix. A continuation token returned by a previous listing operation. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous request to return a result segment containing a collection of containers. The container name prefix. A value that indicates whether to return container metadata with the listing. A non-negative integer value that indicates the maximum number of results to be returned in the result segment, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A continuation token returned by a previous listing operation. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous request to return a result segment containing a collection of containers. The container name prefix. A value that indicates whether to return container metadata with the listing. A non-negative integer value that indicates the maximum number of results to be returned in the result segment, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A continuation token returned by a previous listing operation. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Returns an enumerable collection of the blobs in the container that are retrieved lazily. The blob name prefix. Specifies whether to list blobs in a flat listing, or whether to list blobs hierarchically, by virtual directory. A enumeration describing which items to include in the listing. A object that specifies additional options for the request. An object that represents the context for the current operation. An enumerable collection of objects that implement and are retrieved lazily. Returns a result segment containing a collection of blob items in the container. The blob name prefix, including the container name. A returned by a previous listing operation. A result segment containing objects that implement . Returns a result segment containing a collection of blob items in the container. The blob name prefix, including the container name. Specifies whether to list blobs in a flat listing, or whether to list blobs hierarchically, by virtual directory. A enumeration describing which items to include in the listing. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A returned by a previous listing operation. A object that specifies additional options for the request. An object that represents the context for the current operation. A result segment containing objects that implement . Begins an asynchronous operation to return a result segment containing a collection of blob items in the container. The blob name prefix, including the container name. A returned by a previous listing operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to return a result segment containing a collection of blob items in the container. The blob name prefix, including the container name. Specifies whether to list blobs in a flat listing, or whether to list blobs hierarchically, by virtual directory. A enumeration describing which items to include in the listing. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A returned by a previous listing operation. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to return a result segment containing a collection of blob items in the container. An that references the pending asynchronous operation. A result segment containing objects that implement . Returns a task that performs an asynchronous operation to return a result segment containing a collection of blob items in the container. The blob name prefix, including the container name. A returned by a previous listing operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to return a result segment containing a collection of blob items in the container. The blob name prefix. A returned by a previous listing operation. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to return a result segment containing a collection of blob items in the container. The blob name prefix. Specifies whether to list blobs in a flat listing, or whether to list blobs hierarchically, by virtual directory. A enumeration describing which items to include in the listing. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A returned by a previous listing operation. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to return a result segment containing a collection of blob items in the container. The blob name prefix. Specifies whether to list blobs in a flat listing, or whether to list blobs hierarchically, by virtual directory. A enumeration describing which items to include in the listing. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A returned by a previous listing operation. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Gets a reference to a blob from the service. The URI of the blob. The service assumes this is the URI for the blob in the primary location. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. An object of type containing a reference to the blob. Gets a reference to a blob from the service. The URI of the blob. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies any additional options for the request. An object that represents the context for the current operation. An object of type containing a reference to the blob. Begins an asynchronous operation to get a reference to a blob from the service. The URI of the blob. The service assumes this is the URI for the blob in the primary location. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to get a reference to a blob from the service. The URI of the blob. The service assumes this is the URI for the blob in the primary location. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to get a reference to a blob from the service. The URI of the blob. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies any additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to get a reference to a blob from the service. An that references the pending asynchronous operation. A reference to the blob. Returns a task that gets a reference to a blob from the service. The URI of the blob. The service assumes this is the URI for the blob in the primary location. A object that represents the current operation. Returns a task that gets a reference to a blob from the service. The URI of the blob. The service assumes this is the URI for the blob in the primary location. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a object that gets a reference to a blob from the service. The URI of the blob. The service assumes this is the URI for the blob in the primary location. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that gets a reference to a blob from the service. The URI of the blob. The service assumes this is the URI for the blob in the primary location. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that gets a reference to a blob from the service. The URI of the blob. An object that represents the access conditions for the container. If null, no condition is used. An object that specifies any additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that gets a reference to a blob from the service. The URI of the blob. An object that represents the access conditions for the container. If null, no condition is used. An object that specifies any additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Core implementation for the ListContainers method. The container prefix. The details included. The continuation token. A non-negative integer value that indicates the maximum number of results to be returned in the result segment, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A object that specifies additional options for the request. A that lists the containers. Implements the FetchAttributes method. The attributes are updated immediately. The URI of the blob. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. A that fetches the attributes. Begins an asynchronous operation to get the properties of the blob service. The callback delegate that will receive notification when the asynchronous operation completes. A user defined object to be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to get the properties of the blob service. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user defined object to be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to get the properties of the blob service. An that references the pending asynchronous operation. The blob service properties. Returns a task that performs an asynchronous operation to get the properties of the blob service. A object that represents the current operation. Returns a task that performs an asynchronous operation to get the properties of the blob service. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to get the properties of the blob service. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to get the properties of the blob service. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Gets the properties of the blob service. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. The blob service properties. Begins an asynchronous operation to set the properties of the blob service. The blob service properties. The callback delegate that will receive notification when the asynchronous operation completes. A user defined object to be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to set the properties of the blob service. The blob service properties. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user defined object to be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to set the properties of the blob service. An that references the pending asynchronous operation. Returns a task that gets the properties of the blob service. The blob service properties. A object that represents the current operation. Returns a task that gets the properties of the blob service. The blob service properties. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that gets the properties of the blob service. The blob service properties. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that gets the properties of the blob service. The blob service properties. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Sets the properties of the blob service. The blob service properties. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. Begins an asynchronous operation to get the stats of the blob service. The callback delegate that will receive notification when the asynchronous operation completes. A user defined object to be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to get the stats of the blob service. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user defined object to be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to get the stats of the blob service. An that references the pending asynchronous operation. The blob service stats. Returns a task that performs an asynchronous operation to get the stats of the blob service. A object that represents the current operation. Returns a task that performs an asynchronous operation to get the stats of the blob service. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to get the stats of the blob service. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to get the stats of the blob service. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Gets the stats of the blob service. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. The blob service stats. Stores the default delimiter. Stores the parallelism factor. Default is 32 MB. The default server and client timeout interval. Max execution time across all potential retries. Initializes a new instance of the class using the specified Blob service endpoint and anonymous credentials. The Blob service endpoint to use to create the client. Initializes a new instance of the class using the specified Blob service endpoint and account credentials. The Blob service endpoint to use to create the client. The account credentials. Initializes a new instance of the class using the specified Blob service endpoint and account credentials. The Blob service endpoint to use to create the client. The account credentials. Returns a reference to the root container for this service client. A reference to the root container. Returns a reference to a object with the specified name. The name of the container, or an absolute URI to the container. A reference to a container. Parses the user prefix. The prefix. Name of the container. The listing prefix. Gets or sets the authentication scheme to use to sign HTTP requests. Gets the authentication handler used to sign HTTP requests. The authentication handler. Gets or sets a buffer manager that implements the interface, specifying a buffer pool for use with operations against the Blob service client. Gets the account credentials used to create the Blob service client. The account credentials. Gets the base URI for the Blob service client, at the primary location. The base URI used to construct the Blob service client, at the primary location. Gets the Blob service endpoints for all locations. An object of type containing Blob service URIs for all locations. Gets or sets the default retry policy for requests made via the Blob service client. The retry policy. Gets or sets the default location mode for requests made via the Blob service client. The location mode. Gets or sets the default server and client timeout for requests made via the Blob service client. The server and client timeout interval. Gets or sets the maximum execution time across all potential retries. The maximum execution time across all potential retries. Gets or sets the default delimiter that may be used to create a virtual directory structure of blobs. The default delimiter. Gets or sets the maximum size of a blob in bytes that may be uploaded as a single blob. The maximum size of a blob, in bytes, that may be uploaded as a single blob, ranging from between 1 and 64 MB inclusive. Gets or sets the number of blocks that may be simultaneously uploaded when uploading a blob that is greater than the value specified by the property in size. The number of parallel operations that may proceed. Gets a value indicating whether the service client is used with Path style or Host style. Is true if use path style URIs; otherwise, false. Represents a container in the Windows Azure Blob service. Containers hold directories, which are encapsulated as objects, and directories hold block blobs and page blobs. Directories can also contain sub-directories. Represents a container in the Windows Azure Blob service. Creates the container. A object that specifies additional options for the request. An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. Creates the container and specifies the level of access to the container's data. An object that specifies whether data in the container may be accessed publicly and what level of access is to be allowed. A object that specifies additional options for the request. An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. Begins an asynchronous operation to create a container. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to create a container. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to create a container and specify the level of access to the container's data. An object that specifies whether data in the container may be accessed publicly and what level of access is to be allowed. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to create a container. An that references the pending asynchronous operation. Returns a task that creates a container. A object that represents the current operation. Returns a task that creates a container. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that creates a container. An object that specifies whether data in the container may be accessed publicly and what level of access is to be allowed. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that creates a container and specifies the level of access to the container's data. An object that specifies whether data in the container may be accessed publicly and what level of access is to be allowed. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Creates the container if it does not already exist. A object that specifies additional options for the request. An object that represents the context for the current operation. true if the container did not already exist and was created; otherwise false. Creates the container if it does not already exist and specifies whether the container or its blobs are publicly accessible. An object that specifies whether data in the container may be accessed publicly and what level of access is to be allowed. A object that specifies additional options for the request. An object that represents the context for the current operation. true if the container did not already exist and was created; otherwise false. Begins an asynchronous request to create the container if it does not already exist. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to create the container if it does not already exist. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to create the container if it does not already exist. An object that specifies whether data in the container may be accessed publicly and the level of access. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Returns the result of an asynchronous request to create the container if it does not already exist. An that references the pending asynchronous operation. true if the container did not already exist and was created; otherwise, false. Returns a task that creates the container if it does not already exist. A object that represents the current operation. Returns a task that creates the container if it does not already exist. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that creates the container if it does not already exist. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that creates the container if it does not already exist. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that creates the container if it does not already exist. An object that specifies whether data in the container may be accessed publicly and the level of access. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that creates the container if it does not already exist. An object that specifies whether data in the container may be accessed publicly and the level of access. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Deletes the container. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to delete a container. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to delete a container. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to delete a container. An that references the pending asynchronous operation. Returns a task that deletes the container. A object that represents the current operation. Returns a task that deletes the container. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that deletes the container. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that deletes the container. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Deletes the container if it already exists. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. true if the container did not already exist and was created; otherwise false. Begins an asynchronous request to delete the container if it already exists. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to delete the container if it already exists. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Returns the result of an asynchronous request to delete the container if it already exists. An that references the pending asynchronous operation. true if the container did not already exist and was created; otherwise, false. Returns a task that deletes the container if it already exists. A object that represents the current operation. Returns a task that deletes the container if it already exists. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that deletes the container if it already exists. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that deletes the container if it already exists. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Gets a reference to a blob in this container. The name of the blob. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A reference to the blob. Begins an asynchronous operation to get a reference to a blob in this container. The name of the blob. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to get a reference to a blob in this container. The name of the blob. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to get a reference to a blob in this container. An that references the pending asynchronous operation. A reference to the blob. Returns a task that gets a reference to a blob in this container. The name of the blob. A object that represents the current operation. Returns a task that gets a reference to a blob in this container. The name of the blob. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that gets a reference to a blob in this container. The name of the blob. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that gets a reference to a blob in this container. The name of the blob. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Returns an enumerable collection of the blobs in the container that are retrieved lazily. The blob name prefix. Specifies whether to list blobs in a flat listing, or whether to list blobs hierarchically, by virtual directory. A enumeration describing which items to include in the listing. A object that specifies additional options for the request. An object that represents the context for the current operation. An enumerable collection of objects that implement and are retrieved lazily. Returns a result segment containing a collection of blob items in the container. A continuation token returned by a previous listing operation. A result segment containing objects that implement . Returns a result segment containing a collection of blob items in the container. The blob name prefix. A continuation token returned by a previous listing operation. A result segment containing objects that implement . Returns a result segment containing a collection of blob items in the container. The blob name prefix. Specifies whether to list blobs in a flat listing, or whether to list blobs hierarchically, by virtual directory. A enumeration describing which items to include in the listing. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A continuation token returned by a previous listing operation. A object that specifies additional options for the request. An object that represents the context for the current operation. A result segment containing objects that implement . Returns a result segment containing a collection of blob items in the container. The blob name prefix. Specifies whether to list blobs in a flat listing, or whether to list blobs hierarchically, by virtual directory. A enumeration describing which items to include in the listing. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A continuation token returned by a previous listing operation. A object that specifies additional options for the request. An object that represents the context for the current operation. A result segment containing objects that implement . Begins an asynchronous operation to return a result segment containing a collection of blob items in the container. A continuation token returned by a previous listing operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to return a result segment containing a collection of blob items in the container. The blob name prefix. A continuation token returned by a previous listing operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to return a result segment containing a collection of blob items in the container. The blob name prefix. Specifies whether to list blobs in a flat listing, or whether to list blobs hierarchically, by virtual directory. A enumeration describing which items to include in the listing. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A continuation token returned by a previous listing operation. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to return a result segment containing a collection of blob items in the container. An that references the pending asynchronous operation. A result segment containing objects that implement . Returns a task that returns a result segment containing a collection of blob items in the container. A continuation token returned by a previous listing operation. Returns a task that returns a result segment containing a collection of blob items in the container. A continuation token returned by a previous listing operation. A to observe while waiting for a task to complete. Returns a task that returns a result segment containing a collection of blob items in the container. The blob name prefix. A continuation token returned by a previous listing operation. Returns a task that returns a result segment containing a collection of blob items in the container. The blob name prefix. A continuation token returned by a previous listing operation. A to observe while waiting for a task to complete. Returns a task that returns a result segment containing a collection of blob items in the container. The blob name prefix. Specifies whether to list blobs in a flat listing, or whether to list blobs hierarchically, by virtual directory. A enumeration describing which items to include in the listing. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A continuation token returned by a previous listing operation. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that returns a result segment containing a collection of blob items in the container. The blob name prefix. Specifies whether to list blobs in a flat listing, or whether to list blobs hierarchically, by virtual directory. A enumeration describing which items to include in the listing. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A continuation token returned by a previous listing operation. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Sets permissions for the container. The permissions to apply to the container. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous request to set permissions for the container. The permissions to apply to the container. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to set permissions for the container. The permissions to apply to the container. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Returns the result of an asynchronous request to set permissions for the container. An that references the pending asynchronous operation. Returns a task that sets permissions for the container. The permissions to apply to the container. A object that represents the current operation. Returns a task that sets permissions for the container. The permissions to apply to the container. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that sets permissions for the container. The permissions to apply to the container. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that sets permissions for the container. The permissions to apply to the container. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Gets the permissions settings for the container. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The container's permissions. Begins an asynchronous request to get the permissions settings for the container. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to get the permissions settings for the container. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Returns the asynchronous result of the request to get the permissions settings for the container. An that references the pending asynchronous operation. The container's permissions. Returns a task that gets the permissions settings for the container. A object that represents the current operation. Returns a task that gets the permissions settings for the container. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that gets the permissions settings for the container. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that gets the permissions settings for the container. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Checks whether the container exists. A object that specifies additional options for the request. An object that represents the context for the current operation. true if the container exists. Checks whether the container exists. If true, the command will be executed against the primary location. A object that specifies additional options for the request. An object that represents the context for the current operation. true if the container exists. Begins an asynchronous request to check whether the container exists. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to check whether the container exists. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to check whether the container exists. If true, the command will be executed against the primary location. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Returns the asynchronous result of the request to check whether the container exists. An that references the pending asynchronous operation. true if the container exists. Returns a task that checks whether the container exists. A object that represents the current operation. Returns a task that checks whether the container exists. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that checks whether the container exists. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that checks whether the container exists. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Retrieves the container's attributes. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to retrieve the container's attributes. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to retrieve the container's attributes. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to retrieve the container's attributes. An that references the pending asynchronous operation. Returns a task that retrieves the container's attributes. A object that represents the current operation. Returns a task that retrieves the container's attributes. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that retrieves the container's attributes. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that retrieves the container's attributes. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Sets the container's user-defined metadata. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to set user-defined metadata on the container. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to set user-defined metadata on the container. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous request operation to set user-defined metadata on the container. An that references the pending asynchronous operation. Returns a task that sets container's user-defined metadata. A object that represents the current operation. Returns a task that sets container's user-defined metadata. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that sets container's user-defined metadata. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that sets container's user-defined metadata. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Acquires a lease on this container. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. If null, an infinite lease will be acquired. If not null, this must be greater than zero. A string representing the proposed lease ID for the new lease, or null if no lease ID is proposed. An object that represents the access conditions for the container. If null, no condition is used. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. The ID of the acquired lease. Begins an asynchronous operation to acquire a lease on this container. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. If null, an infinite lease will be acquired. If not null, this must be greater than zero. A string representing the proposed lease ID for the new lease, or null if no lease ID is proposed. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to acquire a lease on this container. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. If null, an infinite lease will be acquired. If not null, this must be greater than zero. A string representing the proposed lease ID for the new lease, or null if no lease ID is proposed. An object that represents the access conditions for the container. If null, no condition is used. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to acquire a lease on this container. An IAsyncResult that references the pending asynchronous operation. The ID of the acquired lease. Returns a task that acquires a lease on this container. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. If null, an infinite lease will be acquired. If not null, this must be greater than zero. A string representing the proposed lease ID for the new lease, or null if no lease ID is proposed. A object that represents the current operation. Returns a task that acquires a lease on this container. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. If null, an infinite lease will be acquired. If not null, this must be greater than zero. A string representing the proposed lease ID for the new lease, or null if no lease ID is proposed. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that acquires a lease on this container. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. If null, an infinite lease will be acquired. If not null, this must be greater than zero. A string representing the proposed lease ID for the new lease, or null if no lease ID is proposed. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that acquires a lease on this container. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. If null, an infinite lease will be acquired. If not null, this must be greater than zero. A string representing the proposed lease ID for the new lease, or null if no lease ID is proposed. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Renews a lease on this container. An object that represents the access conditions for the container, including a required lease ID. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. Begins an asynchronous operation to renew a lease on this container. An object that represents the access conditions for the container, including a required lease ID. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to renew a lease on this container. An object that represents the access conditions for the container, including a required lease ID. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to renew a lease on this container. An IAsyncResult that references the pending asynchronous operation. Returns a task that renews a lease on this container. An object that represents the access conditions for the container, including a required lease ID. A object that represents the current operation. Returns a task that renews a lease on this container. An object that represents the access conditions for the container, including a required lease ID. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that renews a lease on this container. An object that represents the access conditions for the container, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that renews a lease on this container. An object that represents the access conditions for the container, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Changes the lease ID on this container. A string representing the proposed lease ID for the new lease. This cannot be null. An object that represents the access conditions for the container, including a required lease ID. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. The new lease ID. Begins an asynchronous operation to change the lease on this container. A string representing the proposed lease ID for the new lease. This cannot be null. An object that represents the access conditions for the container, including a required lease ID. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to change the lease on this container. A string representing the proposed lease ID for the new lease. This cannot be null. An object that represents the access conditions for the container, including a required lease ID. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to change the lease on this container. An IAsyncResult that references the pending asynchronous operation. The new lease ID. Returns a task that changes the lease ID on this container. A string representing the proposed lease ID for the new lease. This cannot be null. An object that represents the access conditions for the container, including a required lease ID. A object that represents the current operation. Returns a task that changes the lease ID on this container. A string representing the proposed lease ID for the new lease. This cannot be null. An object that represents the access conditions for the container, including a required lease ID. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that changes the lease ID on this container. A string representing the proposed lease ID for the new lease. This cannot be null. An object that represents the access conditions for the container, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that changes the lease ID on this container. A string representing the proposed lease ID for the new lease. This cannot be null. An object that represents the access conditions for the container, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Releases the lease on this container. An object that represents the access conditions for the container, including a required lease ID. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. Begins an asynchronous operation to release the lease on this container. An object that represents the access conditions for the container, including a required lease ID. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to release the lease on this container. An object that represents the access conditions for the container, including a required lease ID. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to release the lease on this container. An IAsyncResult that references the pending asynchronous operation. Returns a task that releases the lease on this container. An object that represents the access conditions for the container, including a required lease ID. A object that represents the current operation. Returns a task that releases the lease on this container. An object that represents the access conditions for the container, including a required lease ID. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that releases the lease on this container. An object that represents the access conditions for the container, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that releases the lease on this container. An object that represents the access conditions for the container, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Breaks the current lease on this container. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. If null, the break period is the remainder of the current lease, or zero for infinite leases. An object that represents the access conditions for the container. If null, no condition is used. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. A representing the amount of time before the lease ends, to the second. Begins an asynchronous operation to break the current lease on this container. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. If null, the break period is the remainder of the current lease, or zero for infinite leases. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to break the current lease on this container. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. If null, the break period is the remainder of the current lease, or zero for infinite leases. An object that represents the access conditions for the container. If null, no condition is used. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to break the current lease on this container. An IAsyncResult that references the pending asynchronous operation. A representing the amount of time before the lease ends, to the second. Returns a task that breaks the current lease on this container. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. If null, the break period is the remainder of the current lease, or zero for infinite leases. A object that represents the current operation. Returns a task that breaks the current lease on this container. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. If null, the break period is the remainder of the current lease, or zero for infinite leases. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that breaks the current lease on this container. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. If null, the break period is the remainder of the current lease, or zero for infinite leases. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that breaks the current lease on this container. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. If null, the break period is the remainder of the current lease, or zero for infinite leases. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Generates a RESTCommand for acquiring a lease. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. If null, an infinite lease will be acquired. If not null, this must be greater than zero. A string representing the proposed lease ID for the new lease, or null if no lease ID is proposed. An object that represents the access conditions for the container. If null, no condition is used. The options for this operation. This parameter must not be null. A RESTCommand implementing the acquire lease operation. Generates a RESTCommand for renewing a lease. An object that represents the access conditions for the container. If null, no condition is used. The options for this operation, including the current lease ID. This cannot be null. A RESTCommand implementing the renew lease operation. Generates a RESTCommand for changing a lease ID. The proposed new lease ID. An object that represents the access conditions for the container. If null, no condition is used. The options for this operation, including the current lease ID. This cannot be null. A RESTCommand implementing the change lease ID operation. Generates a RESTCommand for releasing a lease. An object that represents the access conditions for the container. If null, no condition is used. The options for this operation, including the current lease ID. This cannot be null. A RESTCommand implementing the release lease operation. Generates a RESTCommand for breaking a lease. The amount of time to allow the lease to remain, rounded down to seconds. If null, the break period is the remainder of the current lease, or zero for infinite leases. An object that represents the access conditions for the container. If null, no condition is used. The options for this operation. Cannot be null. A RESTCommand implementing the break lease operation. Implementation for the Create method. A object that specifies additional options for the request. An object that specifies whether data in the container may be accessed publicly and the level of access. A that creates the container. Implementation for the Delete method. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. A that deletes the container. Implementation for the FetchAttributes method. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. A that fetches the attributes. Implementation for the Exists method. A object that specifies additional options for the request. If true, the command will be executed against the primary location. A that checks existence. Implementation for the SetMetadata method. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. A that sets the metadata. Implementation for the SetPermissions method. The permissions to set. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. A that sets the permissions. Implementation for the GetPermissions method. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. A that gets the permissions. Selects the protocol response. The protocol item. The parsed . Core implementation of the ListBlobs method. The blob prefix. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. Specifies whether to list blobs in a flat listing, or whether to list blobs hierarchically, by virtual directory. A enumeration describing which items to include in the listing. A object that specifies additional options for the request. A continuation token returned by a previous listing operation. A that lists the blobs. Retrieve ETag and LastModified date time from response. The response to parse. Initializes a new instance of the class. The absolute URI to the container. Initializes a new instance of the class. The absolute URI to the container. The account credentials. Initializes a new instance of the class. The absolute URI to the container. The account credentials. Initializes a new instance of the class. The container name. A client object that specifies the endpoint for the Blob service. Initializes a new instance of the class. The properties. The metadata. The container name. The client to be used. Parse URI for SAS (Shared Access Signature) information. The complete Uri. The credentials to use. Returns the canonical name for shared access. The canonical name. Returns a shared access signature for the container. The access policy for the shared access signature. A shared access signature, as a URI query string. The query string returned includes the leading question mark. Returns a shared access signature for the container. The access policy for the shared access signature. A container-level access policy. A shared access signature, as a URI query string. The query string returned includes the leading question mark. Gets a reference to a page blob in this container. The name of the blob. A reference to a page blob. Returns a reference to a page blob in this virtual directory. The name of the page blob. The snapshot timestamp, if the blob is a snapshot. A reference to a page blob. Gets a reference to a block blob in this container. The name of the blob. A reference to a block blob. Gets a reference to a block blob in this container. The name of the blob. The snapshot timestamp, if the blob is a snapshot. A reference to a block blob. Gets a reference to a virtual blob directory beneath this container. The name of the virtual blob directory. A reference to a virtual blob directory. Gets the service client for the container. A client object that specifies the endpoint for the Blob service. Gets the container's URI for the primary location. The absolute URI to the container, at the primary location. Gets the container's URIs for all locations. An object of type containing the container's URIs for all locations. Gets the name of the container. The container's name. Gets the container's metadata. The container's metadata. Gets the container's system properties. The container's properties. Represents a virtual directory of blobs, designated by a delimiter character. Containers, which are encapsulated as objects, hold directories, and directories hold block blobs and page blobs. Directories can also contain sub-directories. Represents a virtual directory of blobs on the client which emulates a hierarchical data store by using delimiter characters. Containers, which are encapsulated as objects, hold directories, and directories hold block blobs and page blobs. Directories can also contain sub-directories. Represents an item that may be returned by a blob listing operation. Gets the URI to the blob item, at the primary location. The blob item's URI. Gets the blob item's URIs for all locations. An object of type containing the blob item's URIs for all locations. Gets the blob item's parent virtual directory. The blob item's parent virtual directory. Gets the blob item's container. The blob item's container. Returns an enumerable collection of the blobs in the virtual directory that are retrieved lazily. Specifies whether to list blobs in a flat listing, or whether to list blobs hierarchically, by virtual directory. A enumeration describing which items to include in the listing. A object that specifies additional options for the request. An object that represents the context for the current operation. An enumerable collection of objects that implement and are retrieved lazily. Returns a result segment containing a collection of blob items in the virtual directory. A continuation token returned by a previous listing operation. A result segment containing objects that implement . Returns a result segment containing a collection of blob items in the virtual directory. Specifies whether to list blobs in a flat listing, or whether to list blobs hierarchically, by virtual directory. A enumeration describing which items to include in the listing. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A continuation token returned by a previous listing operation. A object that specifies additional options for the request. An object that represents the context for the current operation. A result segment containing objects that implement . Begins an asynchronous operation to return a result segment containing a collection of blob items in the virtual directory. A continuation token returned by a previous listing operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to return a result segment containing a collection of blob items in the virtual directory. Specifies whether to list blobs in a flat listing, or whether to list blobs hierarchically, by virtual directory. A enumeration describing which items to include in the listing. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A continuation token returned by a previous listing operation. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to return a result segment containing a collection of blob items in the virtual directory. An that references the pending asynchronous operation. A result segment containing objects that implement . Returns a task that performs an asynchronous operation to return a result segment containing a collection of blob items in the virtual directory. A continuation token returned by a previous listing operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to return a result segment containing a collection of blob items in the virtual directory. A continuation token returned by a previous listing operation. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to return a result segment containing a collection of blob items in the virtual directory. Specifies whether to list blobs in a flat listing, or whether to list blobs hierarchically, by virtual directory. A enumeration describing which items to include in the listing. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A continuation token returned by a previous listing operation. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to return a result segment containing a collection of blob items in the virtual directory. Specifies whether to list blobs in a flat listing, or whether to list blobs hierarchically, by virtual directory. A enumeration describing which items to include in the listing. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A continuation token returned by a previous listing operation. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Stores the parent directory. Initializes a new instance of the class given an address and a client. The blob directory's Uri. The blob directory's prefix. The container for the virtual directory. Gets a reference to a page blob in this virtual directory. The name of the blob. A reference to a page blob. Returns a reference to a page blob in this virtual directory. The name of the page blob. The snapshot timestamp, if the blob is a snapshot. A reference to a page blob. Gets a reference to a block blob in this virtual directory. The name of the blob. A reference to a block blob. Gets a reference to a block blob in this virtual directory. The name of the blob. The snapshot timestamp, if the blob is a snapshot. A reference to a block blob. Returns a virtual subdirectory within this virtual directory. The name of the virtual subdirectory. A object representing the virtual subdirectory. Gets the service client for the virtual directory. A client object that specifies the endpoint for the Windows Azure Blob service. Gets the URI that identifies the virtual directory for the primary location. The URI to the virtual directory, at the primary location. Gets the blob directory's URIs for all locations. An object of type containing the blob directory's URIs for all locations. Gets the container for the virtual directory. The container for the virtual directory. Gets the parent directory for the virtual directory. The virtual directory's parent directory. Gets the prefix. The prefix. Called when the asynchronous operation to commit the blob started by UploadFromStream finishes. The result of the asynchronous operation. Implements getting the stream without specifying a range. The blob. The attributes. The destination stream. The offset. The length. An object that represents the access conditions for the blob. If null, no condition is used. An object that specifies additional options for the request. A that gets the stream. Implements the FetchAttributes method. The attributes are updated immediately. The blob. The attributes. An object that represents the access conditions for the blob. If null, no condition is used. An object that specifies additional options for the request. A that fetches the attributes. Implementation for the Exists method. The blob. The attributes. An object that specifies additional options for the request. If true, the command will be executed against the primary location. A that checks existence. Implementation for the SetMetadata method. The blob. The attributes. An object that represents the access conditions for the blob. If null, no condition is used. An object that specifies additional options for the request. A that sets the metadata. Implementation for the SetProperties method. The blob. The attributes. An object that represents the access conditions for the blob. If null, no condition is used. An object that specifies additional options for the request. A that sets the properties. Implements the DeleteBlob method. The blob. The attributes. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the blob. If null, no condition is used. An object that specifies additional options for the request. A that deletes the blob. Generates a for acquiring a lease. The blob. The attributes. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. If null, an infinite lease will be acquired. If not null, this must be greater than zero. A string representing the proposed lease ID for the new lease, or null if no lease ID is proposed. An object that represents the access conditions for the blob. If null, no condition is used. An object that specifies additional options for the request. A implementing the acquire lease operation. Generates a for renewing a lease. The blob. The attributes. An object that represents the access conditions for the blob. If null, no condition is used. An object that specifies additional options for the request. A implementing the renew lease operation. accessCondition Generates a for changing a lease ID. The blob. The attributes. The proposed new lease ID. An object that represents the access conditions for the blob. If null, no condition is used. An object that specifies additional options for the request. A implementing the change lease ID operation. accessCondition Generates a for releasing a lease. The blob. The attributes. An object that represents the access conditions for the blob. If null, no condition is used. An object that specifies additional options for the request. A implementing the release lease operation. accessCondition Generates a for breaking a lease. The blob. The attributes. The amount of time to allow the lease to remain, rounded down to seconds. If null, the break period is the remainder of the current lease, or zero for infinite leases. An object that represents the access conditions for the blob. If null, no condition is used. An object that specifies additional options for the request. A implementing the break lease operation. Implementation of the StartCopyFromBlob method. Result is a BlobAttributes object derived from the response headers. The blob. The attributes. The URI of the source blob. An object that represents the access conditions for the source blob. If null, no condition is used. An object that represents the access conditions for the destination blob. If null, no condition is used. An object that specifies additional options for the request. A that starts to copy the blob. sourceAccessCondition Implementation of the AbortCopy method. No result is produced. The blob. The attributes. The copy ID of the copy operation to abort. An object that represents the access conditions for the operation. If null, no condition is used. An object that specifies additional options for the request. A that aborts the copy. Updates this blob with the given attributes at the end of a fetch attributes operation. The new attributes. The response. if set to true, blob's MD5 will not be updated. Retrieve ETag, LMT, and Sequence-Number from response. The attributes. The response to parse. Converts the source blob of a copy operation to an appropriate access URI, taking Shared Access Signature credentials into account. The source blob. A URI addressing the source blob, using SAS if appropriate. Represents a blob that is uploaded as a set of blocks. Represents a blob that is uploaded as a set of blocks. An interface required for Windows Azure blob types. The and classes implement the interface. An interface required for Windows Azure blob types. The and classes implement the interface. Opens a stream for reading from the blob. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A stream to be used for reading from the blob. On the object returned by this method, the method must be called exactly once for every call. Failing to end a read process before beginning another read can cause unknown behavior. Begins an asynchronous operation to open a stream for reading from the blob. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to open a stream for reading from the blob. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to open a stream for reading from the blob. An that references the pending asynchronous operation. A stream to be used for reading from the blob. Returns a task that performs an asynchronous operation to open a stream for reading from the blob. A object that represents the current operation. Returns a task that performs an asynchronous operation to open a stream for reading from the blob. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to open a stream for reading from the blob. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to open a stream for reading from the blob. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Uploads a stream to the Windows Azure Blob Service. The stream providing the blob content. Use a seek-able stream for optimal performance. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. Uploads a stream to the Windows Azure Blob Service. The stream providing the blob content. The number of bytes to write from the source stream at its current position. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to upload a stream to a blob. The stream providing the blob content. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to upload a stream to a blob. The stream providing the blob content. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to upload a stream to a block blob. The stream providing the blob content. The number of bytes to write from the source stream at its current position. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to upload a stream to a blob. The stream providing the blob content. The number of bytes to write from the source stream at its current position. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to upload a stream to a blob. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to upload a stream to a blob. The stream providing the blob content. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a stream to a blob. The stream providing the blob content. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a stream to a blob. The stream providing the blob content. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a stream to a blob. The stream providing the blob content. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a stream to a block blob. The stream providing the blob content. The number of bytes to write from the source stream at its current position. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a stream to a block blob. The stream providing the blob content. The number of bytes to write from the source stream at its current position. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a stream to a blob. The stream providing the blob content. The number of bytes to write from the source stream at its current position. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a stream to a blob. The stream providing the blob content. The number of bytes to write from the source stream at its current position. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Uploads a file to the Windows Azure Blob Service. The file providing the blob content. A constant that determines how to open the file. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to upload a file to a blob. The file providing the blob content. A constant that determines how to open the file. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to upload a file to a blob. The file providing the blob content. A constant that determines how to open the file. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to upload a file to a blob. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to upload a file to a blob. The file providing the blob content. A constant that determines how to open the file. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a file to a blob. The file providing the blob content. A constant that determines how to open the file. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a file to a blob. The file providing the blob content. A constant that determines how to open the file. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a file to a blob. The file providing the blob content. A constant that determines how to open the file. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Uploads the contents of a byte array to a blob. An array of bytes. The zero-based byte offset in buffer at which to begin uploading bytes to the blob. The number of bytes to be written to the blob. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to upload the contents of a byte array to a blob. An array of bytes. The zero-based byte offset in buffer at which to begin uploading bytes to the blob. The number of bytes to be written to the blob. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to upload the contents of a byte array to a blob. An array of bytes. The zero-based byte offset in buffer at which to begin uploading bytes to the blob. The number of bytes to be written to the blob. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to upload the contents of a byte array to a blob. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to upload the contents of a byte array to a blob. An array of bytes. The zero-based byte offset in buffer at which to begin uploading bytes to the blob. The number of bytes to be written to the blob. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload the contents of a byte array to a blob. An array of bytes. The zero-based byte offset in buffer at which to begin uploading bytes to the blob. The number of bytes to be written to the blob. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload the contents of a byte array to a blob. An array of bytes. The zero-based byte offset in buffer at which to begin uploading bytes to the blob. The number of bytes to be written to the blob. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload the contents of a byte array to a blob. An array of bytes. The zero-based byte offset in buffer at which to begin uploading bytes to the blob. The number of bytes to be written to the blob. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Downloads the contents of a blob to a stream. The target stream. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to download the contents of a blob to a stream. The target stream. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to download the contents of a blob to a stream. The target stream. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to download the contents of a blob to a stream. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a stream. The target stream. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a stream. The target stream. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a stream. The target stream. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a stream. The target stream. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Downloads the contents of a blob to a file. The target file. A constant that determines how to open or create the file. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to download the contents of a blob to a file. The target file. A constant that determines how to open or create the file. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to download the contents of a blob to a file. The target file. A constant that determines how to open or create the file. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to download the contents of a blob to a file. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a file. The target file. A constant that determines how to open or create the file. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a file. The target file. A constant that determines how to open or create the file. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a file. The target file. A constant that determines how to open or create the file. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a file. The target file. A constant that determines how to open or create the file. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Downloads the contents of a blob to a byte array. The target byte array. The starting offset in the byte array. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The total number of bytes read into the buffer. Begins an asynchronous operation to download the contents of a blob to a byte array. The target byte array. The starting offset in the byte array. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to download the contents of a blob to a byte array. The target byte array. The starting offset in the byte array. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to download the contents of a blob to a byte array. An that references the pending asynchronous operation. The total number of bytes read into the buffer. Returns a task that performs an asynchronous operation to download the contents of a blob to a byte array. The target byte array. The starting offset in the byte array. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a byte array. The target byte array. The starting offset in the byte array. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a byte array. The target byte array. The starting offset in the byte array. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a byte array. The target byte array. The starting offset in the byte array. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Downloads a range of bytes from a blob to a stream. The target stream. The starting offset of the data range, in bytes. The length of the data range, in bytes. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to download a range of bytes from a blob to a stream. The target stream. The starting offset of the data range, in bytes. The length of the data range, in bytes. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to download a range of bytes from a blob to a stream. The target stream. The starting offset of the data range, in bytes. The length of the data range, in bytes. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to download a range of bytes from a blob to a stream. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a stream. The target stream. The starting offset of the data range, in bytes. The length of the data range, in bytes. A object that represents the current operation. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a stream. The target stream. The starting offset of the data range, in bytes. The length of the data range, in bytes. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a stream. The target stream. The starting offset of the data range, in bytes. The length of the data range, in bytes. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a stream. The target stream. The starting offset of the data range, in bytes. The length of the data range, in bytes. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Downloads a range of bytes from a blob to a byte array. The target byte array. The starting offset in the byte array. The starting offset of the data range, in bytes. The length of the data range, in bytes. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The total number of bytes read into the buffer. Begins an asynchronous operation to download a range of bytes from a blob to a byte array. The target byte array. The starting offset in the byte array. The starting offset of the data range, in bytes. The length of the data range, in bytes. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to download a range of bytes from a blob to a byte array. The target byte array. The starting offset in the byte array. The starting offset of the data range, in bytes. The length of the data range, in bytes. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to download a range of bytes from a blob to a byte array. An that references the pending asynchronous operation. The total number of bytes read into the buffer. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a byte array. The target byte array. The starting offset in the byte array. The starting offset of the data range, in bytes. The length of the data range, in bytes. A object that represents the current operation. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a byte array. The target byte array. The starting offset in the byte array. The starting offset of the data range, in bytes. The length of the data range, in bytes. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a byte array. The target byte array. The starting offset in the byte array. The starting offset of the data range, in bytes. The length of the data range, in bytes. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a byte array. The target byte array. The starting offset in the byte array. The starting offset of the data range, in bytes. The length of the data range, in bytes. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Checks existence of the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. true if the blob exists. Begins an asynchronous request to check existence of the blob. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to check existence of the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Returns the asynchronous result of the request to check existence of the blob. An that references the pending asynchronous operation. true if the blob exists. Returns a task that performs an asynchronous request to check existence of the blob. A object that represents the current operation. Returns a task that performs an asynchronous request to check existence of the blob. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous request to check existence of the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous request to check existence of the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Populates a blob's properties and metadata. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to populate the blob's properties and metadata. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to populate the blob's properties and metadata. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to populate the blob's properties and metadata. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to populate the blob's properties and metadata. A object that represents the current operation. Returns a task that performs an asynchronous operation to populate the blob's properties and metadata. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to populate the blob's properties and metadata. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to populate the blob's properties and metadata. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Updates the blob's metadata. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to update the blob's metadata. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to update the blob's metadata. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to update the blob's metadata. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to update the blob's metadata. A object that represents the current operation. Returns a task that performs an asynchronous operation to update the blob's metadata. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to update the blob's metadata. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to update the blob's metadata. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Updates the blob's properties. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to update the blob's properties. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to update the blob's properties. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to update the blob's properties. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to update the blob's properties. A object that represents the current operation. Returns a task that performs an asynchronous operation to update the blob's properties. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to update the blob's properties. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to update the blob's properties. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Deletes the blob. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to delete the blob. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to delete the blob. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to delete the blob. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to delete the blob. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete the blob. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete the blob. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete the blob. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Deletes the blob if it already exists. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the container. A object that specifies additional options for the request. An object that represents the context for the current operation. true if the blob did not already exist and was created; otherwise false. Begins an asynchronous request to delete the blob if it already exists. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to delete the blob if it already exists. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the container. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Returns the result of an asynchronous request to delete the blob if it already exists. An that references the pending asynchronous operation. true if the blob did not already exist and was created; otherwise, false. Returns a task that performs an asynchronous request to delete the blob if it already exists. A object that represents the current operation. Returns a task that performs an asynchronous request to delete the blob if it already exists. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous request to delete the blob if it already exists. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the container. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous request to delete the blob if it already exists. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the container. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Acquires a lease on this blob. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. A string representing the proposed lease ID for the new lease. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The ID of the acquired lease. Begins an asynchronous operation to acquire a lease on this blob. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. A string representing the proposed lease ID for the new lease. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to acquire a lease on this blob. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. A string representing the proposed lease ID for the new lease. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to acquire a lease on this blob. An IAsyncResult that references the pending asynchronous operation. The ID of the acquired lease. Returns a task that performs an asynchronous operation to acquire a lease on this blob. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. A string representing the proposed lease ID for the new lease. A object that represents the current operation. Returns a task that performs an asynchronous operation to acquire a lease on this blob. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. A string representing the proposed lease ID for the new lease. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to acquire a lease on this blob. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. A string representing the proposed lease ID for the new lease. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to acquire a lease on this blob. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. A string representing the proposed lease ID for the new lease. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Renews a lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to renew a lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to renew a lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to renew a lease on this blob. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to renew a lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A object that represents the current operation. Returns a task that performs an asynchronous operation to renew a lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to renew a lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to renew a lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Changes the lease ID on this blob. A string representing the proposed lease ID for the new lease. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. The new lease ID. Begins an asynchronous operation to change the lease on this blob. A string representing the proposed lease ID for the new lease. An object that represents the access conditions for the blob, including a required lease ID. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to change the lease on this blob. A string representing the proposed lease ID for the new lease. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to change the lease on this blob. An that references the pending asynchronous operation. The new lease ID. Returns a task that performs an asynchronous operation to change the lease on this blob. A string representing the proposed lease ID for the new lease. An object that represents the access conditions for the blob, including a required lease ID. A object that represents the current operation. Returns a task that performs an asynchronous operation to change the lease on this blob. A string representing the proposed lease ID for the new lease. An object that represents the access conditions for the blob, including a required lease ID. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to change the lease on this blob. A string representing the proposed lease ID for the new lease. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to change the lease on this blob. A string representing the proposed lease ID for the new lease. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Releases the lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to release the lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to release the lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to release the lease on this blob. An IAsyncResult that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to release the lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A object that represents the current operation. Returns a task that performs an asynchronous operation to release the lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to release the lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to release the lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Breaks the current lease on this blob. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A representing the amount of time before the lease ends, to the second. Begins an asynchronous operation to break the current lease on this blob. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to break the current lease on this blob. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to break the current lease on this blob. An IAsyncResult that references the pending asynchronous operation. A representing the amount of time before the lease ends, to the second. Returns a task that performs an asynchronous operation to break the current lease on this blob. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. A object that represents the current operation. Returns a task that performs an asynchronous operation to break the current lease on this blob. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to break the current lease on this blob. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to break the current lease on this blob. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Requests that the service start to copy a blob's contents, properties, and metadata to a new blob. The URI of a source blob. An object that represents the access conditions for the source blob. An object that represents the access conditions for the destination blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The copy ID associated with the copy operation. Begins an asynchronous operation to request that the service start to copy a blob's contents, properties, and metadata to a new blob. The URI of a source blob. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The URI of a source blob. An object that represents the access conditions for the source blob. An object that represents the access conditions for the destination blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to request that the service start to copy a blob's contents, properties, and metadata to a new blob. An that references the pending asynchronous operation. The copy ID associated with the copy operation. Returns a task that performs an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The URI of a source blob. A object that represents the current operation. Returns a task that performs an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The URI of a source blob. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The URI of a source blob. An object that represents the access conditions for the source blob. An object that represents the access conditions for the destination blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The URI of a source blob. An object that represents the access conditions for the source blob. An object that represents the access conditions for the destination blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Aborts an ongoing blob copy operation. A string identifying the copy operation. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to abort an ongoing blob copy operation. A string identifying the copy operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to abort an ongoing blob copy operation. A string identifying the copy operation. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to abort an ongoing blob copy operation. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to abort an ongoing blob copy operation. A string identifying the copy operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to abort an ongoing blob copy operation. A string identifying the copy operation. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to abort an ongoing blob copy operation. A string identifying the copy operation. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to abort an ongoing blob copy operation. A string identifying the copy operation. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a shared access signature for the blob. The access policy for the shared access signature. A shared access signature, as a URI query string. The query string returned includes the leading question mark. Returns a shared access signature for the blob. The access policy for the shared access signature. A container-level access policy. A shared access signature, as a URI query string. The query string returned includes the leading question mark. Returns a shared access signature for the blob. The access policy for the shared access signature. The optional header values to set for a blob accessed with this SAS. A shared access signature. Returns a shared access signature for the blob. The access policy for the shared access signature. The optional header values to set for a blob returned with this SAS. A stored access policy. A shared access signature. Gets the blob item's name. The blob item's name. Gets the object that represents the Blob service. A client object that specifies the Blob service endpoint. Gets or sets the number of bytes to buffer when writing to a page blob stream or the block size for writing to a block blob. The number of bytes to buffer or the size of a block, in bytes. Gets or sets the minimum number of bytes to buffer when reading from a blob stream. The minimum number of bytes to buffer. Gets the blob's system properties. The blob's properties. Gets the user-defined metadata for the blob. The blob's metadata, as a collection of name-value pairs. Gets the date and time that the blob snapshot was taken, if this blob is a snapshot. The blob's snapshot time if the blob is a snapshot; otherwise, null. If the blob is not a snapshot, the value of this property is null. Gets a value indicating whether this blob is a snapshot. true if this blob is a snapshot; otherwise, false. Gets the absolute URI to the blob, including query string information if the blob is a snapshot, at the primary location. The absolute URI to the blob, including snapshot query information if the blob is a snapshot, at the primary location. Gets the blob's URI for all locations, including query string information if the blob is a snapshot. An object of type containing the blob's URIs for all locations, including snapshot query information if the blob is a snapshot. Gets the state of the most recent or pending copy operation. A object containing the copy state, or null if no copy blob state exists for this blob. Gets the type of the blob. The type of the blob. Opens a stream for reading from the blob. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A stream to be used for reading from the blob. On the object returned by this method, the method must be called exactly once for every call. Failing to end a read process before beginning another read can cause unknown behavior. Begins an asynchronous operation to open a stream for reading from the blob. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to open a stream for reading from the blob. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to open a stream for reading from the blob. An that references the pending asynchronous operation. A stream to be used for reading from the blob. Returns a task that performs an asynchronous operation to open a stream for reading from the blob. A object that represents the current operation. Returns a task that performs an asynchronous operation to open a stream for reading from the blob. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to open a stream for reading from the blob. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to open a stream for reading from the blob. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Opens a stream for writing to the blob. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A stream to be used for writing to the blob. Begins an asynchronous operation to open a stream for writing to the blob. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to open a stream for writing to the blob. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to open a stream for writing to the blob. An that references the pending asynchronous operation. A stream to be used for writing to the blob. Returns a task that performs an asynchronous operation to open a stream for writing to the blob. A object that represents the current operation. Returns a task that performs an asynchronous operation to open a stream for writing to the blob. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to open a stream for writing to the blob. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to open a stream for writing to the blob. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Uploads a stream to a block blob. The stream providing the blob content. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Uploads a stream to a block blob. The stream providing the blob content. The number of bytes to write from the source stream at its current position. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Uploads a stream to a block blob. The stream providing the blob content. The number of bytes to write from the source stream at its current position. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to upload a stream to a block blob. The stream providing the blob content. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to upload a stream to a block blob. The stream providing the blob content. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to upload a stream to a block blob. The stream providing the blob content. The number of bytes to write from the source stream at its current position. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to upload a stream to a block blob. The stream providing the blob content. The number of bytes to write from the source stream at its current position. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to upload a stream to a block blob. The stream providing the blob content. The number of bytes to write from the source stream at its current position. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to upload a stream to a block blob. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to upload a stream to a block blob. The stream providing the blob content. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a stream to a block blob. The stream providing the blob content. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a stream to a block blob. The stream providing the blob content. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a stream to a block blob. The stream providing the blob content. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a stream to a block blob. The stream providing the blob content. The number of bytes to write from the source stream at its current position. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a stream to a block blob. The stream providing the blob content. The number of bytes to write from the source stream at its current position. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a stream to a block blob. The stream providing the blob content. The number of bytes to write from the source stream at its current position. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a stream to a block blob. The stream providing the blob content. The number of bytes to write from the source stream at its current position. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Uploads a file to the Blob service. The file providing the blob content. A constant that determines how to open the file. An object that represents the access conditions for the blob. An object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to upload a file to a blob. The file providing the blob content. A constant that determines how to open the file. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to upload a file to a blob. The file providing the blob content. A constant that determines how to open the file. An object that represents the access conditions for the blob. An object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Called when the asynchronous UploadFromStream operation completes. The result of the asynchronous operation. Ends an asynchronous operation to upload a file to a blob. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to upload a file to a blob. The file providing the blob content. A constant that determines how to open the file. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a file to a blob. The file providing the blob content. A constant that determines how to open the file. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a file to a blob. The file providing the blob content. A constant that determines how to open the file. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a file to a blob. The file providing the blob content. A constant that determines how to open the file. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Uploads the contents of a byte array to a blob. An array of bytes. The zero-based byte offset in buffer at which to begin uploading bytes to the blob. The number of bytes to be written to the blob. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to upload the contents of a byte array to a blob. An array of bytes. The zero-based byte offset in buffer at which to begin uploading bytes to the blob. The number of bytes to be written to the blob. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to upload the contents of a byte array to a blob. An array of bytes. The zero-based byte offset in buffer at which to begin uploading bytes to the blob. The number of bytes to be written to the blob. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to upload the contents of a byte array to a blob. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to upload the contents of a byte array to a blob. An array of bytes. The zero-based byte offset in buffer at which to begin uploading bytes to the blob. The number of bytes to be written to the blob. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload the contents of a byte array to a blob. An array of bytes. The zero-based byte offset in buffer at which to begin uploading bytes to the blob. The number of bytes to be written to the blob. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload the contents of a byte array to a blob. An array of bytes. The zero-based byte offset in buffer at which to begin uploading bytes to the blob. The number of bytes to be written to the blob. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload the contents of a byte array to a blob. An array of bytes. The zero-based byte offset in buffer at which to begin uploading bytes to the blob. The number of bytes to be written to the blob. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Uploads a string of text to a blob. The text to upload. An object that indicates the text encoding to use. If null, UTF-8 will be used. An object that represents the access conditions for the blob. An object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to upload a string of text to a blob. The text to upload. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to upload a string of text to a blob. The text to upload. An object that indicates the text encoding to use. If null, UTF-8 will be used. An object that represents the access conditions for the blob. An object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to upload a string of text to a blob. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to upload a string of text to a blob. The text to upload. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a string of text to a blob. The text to upload. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a string of text to a blob. The text to upload. An object that indicates the text encoding to use. If null, UTF-8 will be used. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a string of text to a blob. The text to upload. An object that indicates the text encoding to use. If null, UTF-8 will be used. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Downloads the contents of a blob to a stream. The target stream. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to download the contents of a blob to a stream. The target stream. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to download the contents of a blob to a stream. The target stream. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to download the contents of a blob to a stream. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a stream. The target stream. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a stream. The target stream. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a stream. The target stream. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a stream. The target stream. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Downloads the contents of a blob to a file. The target file. A constant that determines how to open or create the file. An object that represents the access conditions for the blob. An object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to download the contents of a blob to a file. The target file. A constant that determines how to open or create the file. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to download the contents of a blob to a file. The target file. A constant that determines how to open or create the file. An object that represents the access conditions for the blob. An object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Called when the asynchronous DownloadToStream operation completes. The result of the asynchronous operation. Ends an asynchronous operation to download the contents of a blob to a file. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a file. The target file. A constant that determines how to open or create the file. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a file. The target file. A constant that determines how to open or create the file. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a file. The target file. A constant that determines how to open or create the file. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a file. The target file. A constant that determines how to open or create the file. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Downloads the contents of a blob to a byte array. The target byte array. The starting offset in the byte array. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The total number of bytes read into the buffer. Begins an asynchronous operation to download the contents of a blob to a byte array. The target byte array. The starting offset in the byte array. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to download the contents of a blob to a byte array. The target byte array. The starting offset in the byte array. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to download the contents of a blob to a byte array. An that references the pending asynchronous operation. The total number of bytes read into the buffer. Returns a task that performs an asynchronous operation to download the contents of a blob to a byte array. The target byte array. The starting offset in the byte array. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a byte array. The target byte array. The starting offset in the byte array. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a byte array. The target byte array. The starting offset in the byte array. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a byte array. The target byte array. The starting offset in the byte array. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Downloads the blob's contents as a string. An object that indicates the text encoding to use. An object that represents the access conditions for the blob. An object that specifies additional options for the request. An object that represents the context for the current operation. The contents of the blob, as a string. Begins an asynchronous operation to download the blob's contents as a string. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to download the blob's contents as a string. An object that indicates the text encoding to use. An object that represents the access conditions for the blob. An object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Called when the asynchronous DownloadToStream operation completes. The result of the asynchronous operation. Ends an asynchronous operation to download the blob's contents as a string. An that references the pending asynchronous operation. The contents of the blob, as a string. Returns a task that performs an asynchronous operation to download the blob's contents as a string. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the blob's contents as a string. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the blob's contents as a string. An object that indicates the text encoding to use. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the blob's contents as a string. An object that indicates the text encoding to use. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Downloads a range of bytes from a blob to a stream. The target stream. The offset at which to begin downloading the blob, in bytes. The length of the data to download from the blob, in bytes. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to download a range of bytes from a blob to a stream. The target stream. The offset at which to begin downloading the blob, in bytes. The length of the data to download from the blob, in bytes. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to download a range of bytes from a blob to a stream. The target stream. The offset at which to begin downloading the blob, in bytes. The length of the data to download from the blob, in bytes. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to download a range of bytes from a blob to a stream. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a stream. The target stream. The offset at which to begin downloading the blob, in bytes. The length of the data to download from the blob, in bytes. A object that represents the current operation. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a stream. The target stream. The offset at which to begin downloading the blob, in bytes. The length of the data to download from the blob, in bytes. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a stream. The target stream. The offset at which to begin downloading the blob, in bytes. The length of the data to download from the blob, in bytes. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a stream. The target stream. The offset at which to begin downloading the blob, in bytes. The length of the data to download from the blob, in bytes. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Downloads a range of bytes from a blob to a byte array. The target byte array. The starting offset in the byte array. The starting offset of the data range, in bytes. The length of the data to download from the blob, in bytes. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The total number of bytes read into the buffer. Begins an asynchronous operation to download a range of bytes from a blob to a byte array. The target byte array. The starting offset in the byte array. The starting offset of the data range, in bytes. The length of the data to download from the blob, in bytes. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to download a range of bytes from a blob to a byte array. The target byte array. The starting offset in the byte array. The starting offset of the data range, in bytes. The length of the data to download from the blob, in bytes. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Called when the asynchronous DownloadRangeToStream operation completes. The result of the asynchronous operation. Ends an asynchronous operation to download a range of bytes from a blob to a byte array. An that references the pending asynchronous operation. The total number of bytes read into the buffer. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a byte array. The target byte array. The starting offset in the byte array. The starting offset of the data range, in bytes. The length of the data to download from the blob, in bytes. A object that represents the current operation. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a byte array. The target byte array. The starting offset in the byte array. The starting offset of the data range, in bytes. The length of the data to download from the blob, in bytes. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a byte array. The target byte array. The starting offset in the byte array. The starting offset of the data range, in bytes. The length of the data to download from the blob, in bytes. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a byte array. The target byte array. The starting offset in the byte array. The starting offset of the data range, in bytes. The length of the data to download from the blob, in bytes. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Checks existence of the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. true if the blob exists. Checks existence of the blob. If true, the command will be executed against the primary location. A object that specifies additional options for the request. An object that represents the context for the current operation. true if the blob exists. Begins an asynchronous request to check existence of the blob. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to check existence of the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to check existence of the blob. If true, the command will be executed against the primary location. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Returns the asynchronous result of the request to check existence of the blob. An that references the pending asynchronous operation. true if the blob exists. Returns a task that performs an asynchronous request to check existence of the blob. A object that represents the current operation. Returns a task that performs an asynchronous request to check existence of the blob. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous request to check existence of the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous request to check existence of the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Populates a blob's properties and metadata. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to populate the blob's properties and metadata. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to populate the blob's properties and metadata. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to populate the blob's properties and metadata. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to populate the blob's properties and metadata. A object that represents the current operation. Returns a task that performs an asynchronous operation to populate the blob's properties and metadata. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to populate the blob's properties and metadata. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to populate the blob's properties and metadata. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Updates the blob's metadata. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to update the blob's metadata. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to update the blob's metadata. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to update the blob's metadata. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to update the blob's metadata. A object that represents the current operation. Returns a task that performs an asynchronous operation to update the blob's metadata. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to update the blob's metadata. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to update the blob's metadata. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Updates the blob's properties. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to update the blob's properties. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to update the blob's properties. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to update the blob's properties. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to update the blob's properties. A object that represents the current operation. Returns a task that performs an asynchronous operation to update the blob's properties. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to update the blob's properties. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to update the blob's properties. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Deletes the blob. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to delete the blob. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to delete the blob. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to delete the blob. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to delete the blob. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete the blob. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete the blob. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete the blob. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Deletes the blob if it already exists. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. true if the blob did already exist and was deleted; otherwise false. Begins an asynchronous request to delete the blob if it already exists. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to delete the blob if it already exists. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Returns the result of an asynchronous request to delete the blob if it already exists. An that references the pending asynchronous operation. true if the blob did already exist and was deleted; otherwise, false. Returns a task that performs an asynchronous request to delete the blob if it already exists. A object that represents the current operation. Returns a task that performs an asynchronous request to delete the blob if it already exists. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous request to delete the blob if it already exists. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous request to delete the blob if it already exists. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Creates a snapshot of the blob. A collection of name-value pairs defining the metadata of the snapshot. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request, or null. An object that represents the context for the current operation. A blob snapshot. Begins an asynchronous operation to create a snapshot of the blob. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to create a snapshot of the blob. A collection of name-value pairs defining the metadata of the snapshot. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request, or null. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to create a snapshot of the blob. An that references the pending asynchronous operation. A blob snapshot. Returns a task that performs an asynchronous operation to create a snapshot of the blob. A object that represents the current operation. Returns a task that performs an asynchronous operation to create a snapshot of the blob. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to create a snapshot of the blob. A collection of name-value pairs defining the metadata of the snapshot. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to create a snapshot of the blob. A collection of name-value pairs defining the metadata of the snapshot. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Acquires a lease on this blob. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. If null, an infinite lease will be acquired. If not null, this must be greater than zero. A string representing the proposed lease ID for the new lease, or null if no lease ID is proposed. An object that represents the access conditions for the blob. If null, no condition is used. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. The ID of the acquired lease. Begins an asynchronous operation to acquire a lease on this blob. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. If null, an infinite lease will be acquired. If not null, this must be greater than zero. A string representing the proposed lease ID for the new lease, or null if no lease ID is proposed. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to acquire a lease on this blob. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. If null, an infinite lease will be acquired. If not null, this must be greater than zero. A string representing the proposed lease ID for the new lease, or null if no lease ID is proposed. An object that represents the access conditions for the blob. If null, no condition is used. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to acquire a lease on this blob. An IAsyncResult that references the pending asynchronous operation. The ID of the acquired lease. Returns a task that performs an asynchronous operation to acquire a lease on this blob. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. If null, an infinite lease will be acquired. If not null, this must be greater than zero. A string representing the proposed lease ID for the new lease, or null if no lease ID is proposed. A object that represents the current operation. Returns a task that performs an asynchronous operation to acquire a lease on this blob. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. If null, an infinite lease will be acquired. If not null, this must be greater than zero. A string representing the proposed lease ID for the new lease, or null if no lease ID is proposed. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to acquire a lease on this blob. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. If null, an infinite lease will be acquired. If not null, this must be greater than zero. A string representing the proposed lease ID for the new lease, or null if no lease ID is proposed. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to acquire a lease on this blob. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. If null, an infinite lease will be acquired. If not null, this must be greater than zero. A string representing the proposed lease ID for the new lease, or null if no lease ID is proposed. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Renews a lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. Begins an asynchronous operation to renew a lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to renew a lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to renew a lease on this blob. An IAsyncResult that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to renew a lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A object that represents the current operation. Returns a task that performs an asynchronous operation to renew a lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to renew a lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to renew a lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Changes the lease ID on this blob. A string representing the proposed lease ID for the new lease. This cannot be null. An object that represents the access conditions for the blob, including a required lease ID. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. The new lease ID. Begins an asynchronous operation to change the lease on this blob. A string representing the proposed lease ID for the new lease. This cannot be null. An object that represents the access conditions for the blob, including a required lease ID. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to change the lease on this blob. A string representing the proposed lease ID for the new lease. This cannot be null. An object that represents the access conditions for the blob, including a required lease ID. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to change the lease on this blob. An IAsyncResult that references the pending asynchronous operation. The new lease ID. Returns a task that performs an asynchronous operation to change the lease on this blob. A string representing the proposed lease ID for the new lease. This cannot be null. An object that represents the access conditions for the blob, including a required lease ID. A object that represents the current operation. Returns a task that performs an asynchronous operation to change the lease on this blob. A string representing the proposed lease ID for the new lease. This cannot be null. An object that represents the access conditions for the blob, including a required lease ID. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to change the lease on this blob. A string representing the proposed lease ID for the new lease. This cannot be null. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to change the lease on this blob. A string representing the proposed lease ID for the new lease. This cannot be null. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Releases the lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. Begins an asynchronous operation to release the lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to release the lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to release the lease on this blob. An IAsyncResult that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to release the lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A object that represents the current operation. Returns a task that performs an asynchronous operation to release the lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to release the lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to release the lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Breaks the current lease on this blob. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. If null, the break period is the remainder of the current lease, or zero for infinite leases. An object that represents the access conditions for the blob. If null, no condition is used. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. A representing the amount of time before the lease ends, to the second. Begins an asynchronous operation to break the current lease on this blob. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. If null, the break period is the remainder of the current lease, or zero for infinite leases. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to break the current lease on this blob. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. If null, the break period is the remainder of the current lease, or zero for infinite leases. An object that represents the access conditions for the blob. If null, no condition is used. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to break the current lease on this blob. An IAsyncResult that references the pending asynchronous operation. A representing the amount of time before the lease ends, to the second. Returns a task that performs an asynchronous operation to break the current lease on this blob. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. If null, the break period is the remainder of the current lease, or zero for infinite leases. A object that represents the current operation. Returns a task that performs an asynchronous operation to break the current lease on this blob. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. If null, the break period is the remainder of the current lease, or zero for infinite leases. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to break the current lease on this blob. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. If null, the break period is the remainder of the current lease, or zero for infinite leases. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to break the current lease on this blob. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. If null, the break period is the remainder of the current lease, or zero for infinite leases. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Uploads a single block. A base64-encoded block ID that identifies the block. A stream that provides the data for the block. An optional hash value that will be used to set the property on the blob. May be null or an empty string. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to upload a single block. A base64-encoded block ID that identifies the block. A stream that provides the data for the block. An optional hash value that will be used to set the property on the blob. May be null or an empty string. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to upload a single block. A base64-encoded block ID that identifies the block. A stream that provides the data for the block. An optional hash value that will be used to set the property on the blob. May be null or an empty string. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to upload a single block. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to upload a single block. A base64-encoded block ID that identifies the block. A stream that provides the data for the block. An optional hash value that will be used to set the property on the blob. May be null or an empty string. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a single block. A base64-encoded block ID that identifies the block. A stream that provides the data for the block. An optional hash value that will be used to set the property on the blob. May be null or an empty string. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a single block. A base64-encoded block ID that identifies the block. A stream that provides the data for the block. An optional hash value that will be used to set the property on the blob. May be null or an empty string. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a single block. A base64-encoded block ID that identifies the block. A stream that provides the data for the block. An optional hash value that will be used to set the property on the blob. May be null or an empty string. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Uploads a list of blocks to a new or existing blob. An enumerable collection of block IDs, as base64-encoded strings. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to upload a list of blocks to a new or existing blob. An enumerable collection of block IDs, as base64-encoded strings. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to upload a list of blocks to a new or existing blob. An enumerable collection of block IDs, as base64-encoded strings. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to upload a list of blocks to a new or existing blob. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to upload a list of blocks to a new or existing blob. An enumerable collection of block IDs, as base64-encoded strings. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a list of blocks to a new or existing blob. An enumerable collection of block IDs, as base64-encoded strings. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a list of blocks to a new or existing blob. An enumerable collection of block IDs, as base64-encoded strings. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a list of blocks to a new or existing blob. An enumerable collection of block IDs, as base64-encoded strings. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Returns an enumerable collection of the blob's blocks, using the specified block list filter. One of the enumeration values that indicates whether to return committed blocks, uncommitted blocks, or both. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. An enumerable collection of objects implementing . Begins an asynchronous operation to return an enumerable collection of the blob's blocks, using the specified block list filter. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to return an enumerable collection of the blob's blocks, using the specified block list filter. One of the enumeration values that indicates whether to return committed blocks, uncommitted blocks, or both. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to return an enumerable collection of the blob's blocks, using the specified block list filter. An that references the pending asynchronous operation. An enumerable collection of objects implementing . Returns a task that performs an asynchronous operation to return an enumerable collection of the blob's blocks, using the specified block list filter. A object that represents the current operation. Returns a task that performs an asynchronous operation to return an enumerable collection of the blob's blocks, using the specified block list filter. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to return an enumerable collection of the blob's blocks, using the specified block list filter. One of the enumeration values that indicates whether to return committed blocks, uncommitted blocks, or both. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to return an enumerable collection of the blob's blocks, using the specified block list filter. One of the enumeration values that indicates whether to return committed blocks, uncommitted blocks, or both. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Requests that the service start to copy a blob's contents, properties, and metadata to a new blob. The URI of a source blob. An object that represents the access conditions for the source blob. If null, no condition is used. An object that represents the access conditions for the destination blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The copy ID associated with the copy operation. This method fetches the blob's ETag, last modified time, and part of the copy state. The copy ID and copy status fields are fetched, and the rest of the copy state is cleared. Requests that the service start to copy a blob's contents, properties, and metadata to a new blob. The URI of a source blob. An object that represents the access conditions for the source blob. If null, no condition is used. An object that represents the access conditions for the destination blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The copy ID associated with the copy operation. This method fetches the blob's ETag, last modified time, and part of the copy state. The copy ID and copy status fields are fetched, and the rest of the copy state is cleared. Begins an asynchronous operation to request that the service start to copy a blob's contents, properties, and metadata to a new blob. The URI of a source blob. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to request that the service start to copy a blob's contents, properties, and metadata to a new blob. The source blob. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The URI of a source blob. An object that represents the access conditions for the source blob. If null, no condition is used. An object that represents the access conditions for the destination blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The source blob. An object that represents the access conditions for the source blob. If null, no condition is used. An object that represents the access conditions for the destination blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to request that the service start to copy a blob's contents, properties, and metadata to a new blob. An that references the pending asynchronous operation. The copy ID associated with the copy operation. This method fetches the blob's ETag, last modified time, and part of the copy state. The copy ID and copy status fields are fetched, and the rest of the copy state is cleared. Returns a task that performs an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The URI of a source blob. A object that represents the current operation. Returns a task that performs an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The URI of a source blob. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The source blob. A object that represents the current operation. Returns a task that performs an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The source blob. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The URI of a source blob. An object that represents the access conditions for the source blob. If null, no condition is used. An object that represents the access conditions for the destination blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The URI of a source blob. An object that represents the access conditions for the source blob. If null, no condition is used. An object that represents the access conditions for the destination blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The source blob. An object that represents the access conditions for the source blob. If null, no condition is used. An object that represents the access conditions for the destination blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The source blob. An object that represents the access conditions for the source blob. If null, no condition is used. An object that represents the access conditions for the destination blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Aborts an ongoing blob copy operation. A string identifying the copy operation. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to abort an ongoing blob copy operation. A string identifying the copy operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to abort an ongoing blob copy operation. A string identifying the copy operation. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to abort an ongoing blob copy operation. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to abort an ongoing blob copy operation. A string identifying the copy operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to abort an ongoing blob copy operation. A string identifying the copy operation. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to abort an ongoing blob copy operation. A string identifying the copy operation. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to abort an ongoing blob copy operation. A string identifying the copy operation. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Implementation for the CreateSnapshot method. A collection of name-value pairs defining the metadata of the snapshot, or null. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. A that creates the snapshot. If the metadata parameter is null then no metadata is associated with the request. Uploads the full blob from a seekable stream. The content stream. Must be seekable. Number of bytes to upload from the content stream starting at its current position. The content MD5. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. A that gets the stream. Uploads the block. The source stream. The block ID. The content MD5. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. A that uploads the block. Uploads the block list. The blocks to upload. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. A that uploads the block list. Gets the download block list. The types of blocks. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. A that gets the download block list. Default is 4 MB. Default is 4 MB. Initializes a new instance of the class using an absolute URI to the blob. The absolute URI to the blob. Initializes a new instance of the class using an absolute URI to the blob. The absolute URI to the blob. The account credentials. Initializes a new instance of the class using an absolute URI to the blob. The absolute URI to the blob. The snapshot timestamp, if the blob is a snapshot. The account credentials. Initializes a new instance of the class using an absolute URI to the blob. The absolute URI to the blob. The snapshot timestamp, if the blob is a snapshot. The account credentials. Initializes a new instance of the class using the specified blob name and the parent container reference. If snapshotTime is not null, the blob instance represents a Snapshot. Name of the blob. Snapshot time in case the blob is a snapshot. The reference to the parent container. Initializes a new instance of the class. The attributes. The service client. Stores the that contains this blob. Stores the blob's parent . Stores the blob's attributes. Returns a shared access signature for the blob. The access policy for the shared access signature. A shared access signature, as a URI query string. The query string returned includes the leading question mark. Returns a shared access signature for the blob. The access policy for the shared access signature. A stored access policy. A shared access signature, as a URI query string. The query string returned includes the leading question mark. Returns a shared access signature for the blob. The access policy for the shared access signature. The optional header values to set for a blob accessed with this SAS. A shared access signature. Returns a shared access signature for the blob. The access policy for the shared access signature. The optional header values to set for a blob returned with this SAS. A stored access policy. A shared access signature. Gets the canonical name of the blob, formatted as /<account-name>/<container-name>/<blob-name>. If ignoreSnapshotTime is false and this blob is a snapshot, the canonical name is augmented with a query of the form ?snapshot=<snapshot-time>. This is used by both Shared Access and Copy blob operations. Indicates if the snapshot time is ignored. The canonical name of the blob. Parse URI for SAS (Shared Access Signature) and snapshot information. The complete Uri. The credentials to use. Gets the object that represents the Blob service. A client object that specifies the Blob service endpoint. Gets or sets the block size for writing to a block blob. The size of a block, in bytes, ranging from between 16 KB and 4 MB inclusive. Gets or sets the minimum number of bytes to buffer when reading from a blob stream. The minimum number of bytes to buffer, being at least 16KB. Gets the blob's system properties. The blob's properties. Gets the user-defined metadata for the blob. The blob's metadata, as a collection of name-value pairs. Gets the blob's URI for the primary location. The absolute URI to the blob, at the primary location. Gets the block blob's URIs for all locations. An object of type containing the block blob's URIs for all locations. Gets the date and time that the blob snapshot was taken, if this blob is a snapshot. The blob's snapshot time, if the blob is a snapshot. If the blob is not a snapshot, the value of this property is null. Gets a value indicating whether this blob is a snapshot. true if this blob is a snapshot; otherwise, false. Gets the absolute URI to the blob, including query string information if the blob is a snapshot. The absolute URI to the blob, including snapshot query information if the blob is a snapshot. Gets the block blob's URI for all locations, including query string information if the blob is a snapshot. An object of type containing the block blob's URIs for all locations, including snapshot query information if the blob is a snapshot. Gets the state of the most recent or pending copy operation. A object containing the copy state, or null if no copy blob state exists for this blob. Gets the type of the blob. The type of the blob. Gets the blob's name. The blob's name. Gets a object representing the blob's container. The blob's container. Gets the object representing the virtual parent directory for the blob. The blob's virtual parent directory. Represents a Windows Azure page blob. Represents a Windows Azure page blob. Opens a stream for reading from the blob. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A stream to be used for reading from the blob. On the object returned by this method, the method must be called exactly once for every call. Failing to end a read process before beginning another read can cause unknown behavior. Begins an asynchronous operation to open a stream for reading from the blob. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to open a stream for reading from the blob. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to open a stream for reading from the blob. An that references the pending asynchronous operation. A stream to be used for reading from the blob. Returns a task that performs an asynchronous operation to open a stream for reading from the blob. A object that represents the current operation. Returns a task that performs an asynchronous operation to open a stream for reading from the blob. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to open a stream for reading from the blob. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to open a stream for reading from the blob. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Opens a stream for writing to the blob. The size of the page blob, in bytes. The size must be a multiple of 512. If null, the page blob must already exist. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A stream to be used for writing to the blob. Begins an asynchronous operation to open a stream for writing to the blob. The size of the page blob, in bytes. The size must be a multiple of 512. If null, the page blob must already exist. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to open a stream for writing to the blob. The size of the page blob, in bytes. The size must be a multiple of 512. If null, the page blob must already exist. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to open a stream for writing to the blob. An that references the pending asynchronous operation. A stream to be used for writing to the blob. Returns a task that performs an asynchronous operation to open a stream for writing to the blob. The size of the page blob, in bytes. The size must be a multiple of 512. If null, the page blob must already exist. A object that represents the current operation. Returns a task that performs an asynchronous operation to open a stream for writing to the blob. The size of the page blob, in bytes. The size must be a multiple of 512. If null, the page blob must already exist. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to open a stream for writing to the blob. The size of the page blob, in bytes. The size must be a multiple of 512. If null, the page blob must already exist. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to open a stream for writing to the blob. The size of the page blob, in bytes. The size must be a multiple of 512. If null, the page blob must already exist. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Downloads the contents of a blob to a stream. The target stream. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to download the contents of a blob to a stream. The target stream. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to download the contents of a blob to a stream. The target stream. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to download the contents of a blob to a stream. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a stream. The target stream. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a stream. The target stream. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a stream. The target stream. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a stream. The target stream. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Downloads the contents of a blob to a file. The target file. A constant that determines how to open or create the file. An object that represents the access conditions for the blob. An object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to download the contents of a blob to a file. The target file. A constant that determines how to open or create the file. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to download the contents of a blob to a file. The target file. A constant that determines how to open or create the file. An object that represents the access conditions for the blob. An object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Called when the asynchronous DownloadToStream operation completes. The result of the asynchronous operation. Ends an asynchronous operation to download the contents of a blob to a file. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a file. The target file. A constant that determines how to open or create the file. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a file. The target file. A constant that determines how to open or create the file. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a file. The target file. A constant that determines how to open or create the file. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a file. The target file. A constant that determines how to open or create the file. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Downloads the contents of a blob to a byte array. The target byte array. The starting offset in the byte array. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The total number of bytes read into the buffer. Begins an asynchronous operation to download the contents of a blob to a byte array. The target byte array. The starting offset in the byte array. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to download the contents of a blob to a byte array. The target byte array. The starting offset in the byte array. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to download the contents of a blob to a byte array. An that references the pending asynchronous operation. The total number of bytes read into the buffer. Returns a task that performs an asynchronous operation to download the contents of a blob to a byte array. The target byte array. The starting offset in the byte array. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a byte array. The target byte array. The starting offset in the byte array. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a byte array. The target byte array. The starting offset in the byte array. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to download the contents of a blob to a byte array. The target byte array. The starting offset in the byte array. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Downloads a range of bytes from a blob to a stream. The target stream. The offset at which to begin downloading the blob, in bytes. The length of the data to download from the blob, in bytes. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to download a range of bytes from a blob to a stream. The target stream. The offset at which to begin downloading the blob, in bytes. The length of the data to download from the blob, in bytes. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to download a range of bytes from a blob to a stream. The target stream. The offset at which to begin downloading the blob, in bytes. The length of the data to download from the blob, in bytes. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to download a range of bytes from a blob to a stream. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a stream. The target stream. The offset at which to begin downloading the blob, in bytes. The length of the data to download from the blob, in bytes. A object that represents the current operation. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a stream. The target stream. The offset at which to begin downloading the blob, in bytes. The length of the data to download from the blob, in bytes. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a stream. The target stream. The offset at which to begin downloading the blob, in bytes. The length of the data to download from the blob, in bytes. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a stream. The target stream. The offset at which to begin downloading the blob, in bytes. The length of the data to download from the blob, in bytes. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Downloads a range of bytes from a blob to a byte array. The target byte array. The starting offset in the byte array. The starting offset of the data range, in bytes. The length of the data to download from the blob, in bytes. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The total number of bytes read into the buffer. Begins an asynchronous operation to download a range of bytes from a blob to a byte array. The target byte array. The starting offset in the byte array. The starting offset of the data range, in bytes. The length of the data to download from the blob, in bytes. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to download a range of bytes from a blob to a byte array. The target byte array. The starting offset in the byte array. The starting offset of the data range, in bytes. The length of the data to download from the blob, in bytes. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Called when the asynchronous DownloadRangeToStream operation completes. The result of the asynchronous operation. Ends an asynchronous operation to download a range of bytes from a blob to a byte array. An that references the pending asynchronous operation. The total number of bytes read into the buffer. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a byte array. The target byte array. The starting offset in the byte array. The starting offset of the data range, in bytes. The length of the data to download from the blob, in bytes. A object that represents the current operation. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a byte array. The target byte array. The starting offset in the byte array. The starting offset of the data range, in bytes. The length of the data to download from the blob, in bytes. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a byte array. The target byte array. The starting offset in the byte array. The starting offset of the data range, in bytes. The length of the data to download from the blob, in bytes. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to download a range of bytes from a blob to a byte array. The target byte array. The starting offset in the byte array. The starting offset of the data range, in bytes. The length of the data to download from the blob, in bytes. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Uploads a stream to a page blob. The stream providing the blob content. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Uploads a stream to a page blob. The stream providing the blob content. The number of bytes to write from the source stream at its current position. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Uploads a stream to a page blob. The stream providing the blob content. The number of bytes to write from the source stream at its current position. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to upload a stream to a page blob. The stream providing the blob content. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to upload a stream to a page blob. The stream providing the blob content. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to upload a stream to a page blob. The stream providing the blob content. Specifies the number of bytes from the Stream source to upload from the start position. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to upload a stream to a page blob. The stream providing the blob content. Specifies the number of bytes from the Stream source to upload from the start position. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to upload a stream to a page blob. The stream providing the blob content. Specifies the number of bytes from the Stream source to upload from the start position. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to upload a stream to a page blob. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to upload a stream to a page blob. The stream providing the blob content. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a stream to a page blob. The stream providing the blob content. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a stream to a page blob. The stream providing the blob content. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a stream to a page blob. The stream providing the blob content. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a stream to a page blob. The stream providing the blob content. The number of bytes to write from the source stream at its current position. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a stream to a page blob. The stream providing the blob content. The number of bytes to write from the source stream at its current position. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a stream to a page blob. The stream providing the blob content. The number of bytes to write from the source stream at its current position. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a stream to a page blob. The stream providing the blob content. The number of bytes to write from the source stream at its current position. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Uploads a file to the Windows Azure Blob Service. The file providing the blob content. A constant that determines how to open the file. An object that represents the access conditions for the blob. An object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to upload a file to a blob. The file providing the blob content. A constant that determines how to open the file. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to upload a file to a blob. The file providing the blob content. A constant that determines how to open the file. An object that represents the access conditions for the blob. An object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Called when the asynchronous UploadFromStream operation completes. The result of the asynchronous operation. Ends an asynchronous operation to upload a file to a blob. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to upload a file to a blob. The file providing the blob content. A constant that determines how to open the file. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a file to a blob. The file providing the blob content. A constant that determines how to open the file. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a file to a blob. The file providing the blob content. A constant that determines how to open the file. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload a file to a blob. The file providing the blob content. A constant that determines how to open the file. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Uploads the contents of a byte array to a blob. An array of bytes. The zero-based byte offset in buffer at which to begin uploading bytes to the blob. The number of bytes to be written to the blob. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to upload the contents of a byte array to a blob. An array of bytes. The zero-based byte offset in buffer at which to begin uploading bytes to the blob. The number of bytes to be written to the blob. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to upload the contents of a byte array to a blob. An array of bytes. The zero-based byte offset in buffer at which to begin uploading bytes to the blob. The number of bytes to be written to the blob. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to upload the contents of a byte array to a blob. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to upload the contents of a byte array to a blob. An array of bytes. The zero-based byte offset in buffer at which to begin uploading bytes to the blob. The number of bytes to be written to the blob. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload the contents of a byte array to a blob. An array of bytes. The zero-based byte offset in buffer at which to begin uploading bytes to the blob. The number of bytes to be written to the blob. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload the contents of a byte array to a blob. An array of bytes. The zero-based byte offset in buffer at which to begin uploading bytes to the blob. The number of bytes to be written to the blob. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to upload the contents of a byte array to a blob. An array of bytes. The zero-based byte offset in buffer at which to begin uploading bytes to the blob. The number of bytes to be written to the blob. An object that represents the access conditions for the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Creates a page blob. The maximum size of the page blob, in bytes. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to create a page blob. The maximum size of the page blob, in bytes. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to create a page blob. The maximum size of the blob, in bytes. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to create a page blob. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to create a page blob. The maximum size of the blob, in bytes. A object that represents the current operation. Returns a task that performs an asynchronous operation to create a page blob. The maximum size of the blob, in bytes. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to create a page blob. The maximum size of the blob, in bytes. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to create a page blob. The maximum size of the blob, in bytes. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Resizes the page blob to the specified size. The size of the page blob, in bytes. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to resize the page blob to the specified size. The size of the page blob, in bytes. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to resize the page blob to the specified size. The size of the blob, in bytes. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to resize the page blob. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to resize the page blob to the specified size. The size of the blob, in bytes. A object that represents the current operation. Returns a task that performs an asynchronous operation to resize the page blob to the specified size. The size of the blob, in bytes. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to resize the page blob to the specified size. The size of the blob, in bytes. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to resize the page blob to the specified size. The size of the blob, in bytes. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Sets the page blob's sequence number. A value of type , indicating the operation to perform on the sequence number. The sequence number. Set this parameter to null if is equal to . An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to set the page blob's sequence number. A value of type , indicating the operation to perform on the sequence number. The sequence number. Set this parameter to null if is equal to . The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to set the page blob's sequence number. A value of type , indicating the operation to perform on the sequence number. The sequence number. Set this parameter to null if is equal to . An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to set the page blob's sequence number. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to set the page blob's sequence number. A value of type , indicating the operation to perform on the sequence number. The sequence number. Set this parameter to null if is equal to . A object that represents the current operation. Returns a task that performs an asynchronous operation to set the page blob's sequence number. A value of type , indicating the operation to perform on the sequence number. The sequence number. Set this parameter to null if is equal to . A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to set the page blob's sequence number. A value of type , indicating the operation to perform on the sequence number. The sequence number. Set this parameter to null if is equal to . An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to set the page blob's sequence number. A value of type , indicating the operation to perform on the sequence number. The sequence number. Set this parameter to null if is equal to . An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Checks existence of the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. true if the blob exists. Checks existence of the blob. If true, the command will be executed against the primary location. A object that specifies additional options for the request. An object that represents the context for the current operation. true if the blob exists. Begins an asynchronous request to check existence of the blob. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to check existence of the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to check existence of the blob. If true, the command will be executed against the primary location. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Returns the asynchronous result of the request to check existence of the blob. An that references the pending asynchronous operation. true if the blob exists. Returns a task that performs an asynchronous request to check existence of the blob. A object that represents the current operation. Returns a task that performs an asynchronous request to check existence of the blob. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous request to check existence of the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous request to check existence of the blob. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Populates a blob's properties and metadata. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to populate the blob's properties and metadata. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to populate the blob's properties and metadata. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to populate the blob's properties and metadata. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to populate the blob's properties and metadata. A object that represents the current operation. Returns a task that performs an asynchronous operation to populate the blob's properties and metadata. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to populate the blob's properties and metadata. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to populate the blob's properties and metadata. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Gets a collection of valid page ranges and their starting and ending bytes. The starting offset of the data range over which to list page ranges, in bytes. Must be a multiple of 512. The length of the data range over which to list page ranges, in bytes. Must be a multiple of 512. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. An enumerable collection of page ranges. Begins an asynchronous operation to return a collection of valid page ranges and their starting and ending bytes. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to return a collection of valid page ranges and their starting and ending bytes. The starting offset of the data range over which to list page ranges, in bytes. Must be a multiple of 512. The length of the data range over which to list page ranges, in bytes. Must be a multiple of 512. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to return a collection of valid page ranges and their starting and ending bytes. An that references the pending asynchronous operation. An enumerable collection of page ranges. Returns a task that performs an asynchronous operation to return a collection of page ranges and their starting and ending bytes. A object that represents the current operation. Returns a task that performs an asynchronous operation to return a collection of page ranges and their starting and ending bytes. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to return a collection of page ranges and their starting and ending bytes. The starting offset of the data range, in bytes. Must be a multiple of 512. The length of the data range, in bytes. Must be a multiple of 512. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to return a collection of page ranges and their starting and ending bytes. The starting offset of the data range, in bytes. Must be a multiple of 512. The length of the data range, in bytes. Must be a multiple of 512. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Updates the blob's metadata. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to update the blob's metadata. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to update the blob's metadata. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to update the blob's metadata. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to update the blob's metadata. A object that represents the current operation. Returns a task that performs an asynchronous operation to update the blob's metadata. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to update the blob's metadata. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to update the blob's metadata. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Updates the blob's properties. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to update the blob's properties. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to update the blob's properties. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to update the blob's properties. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to update the blob's properties. A object that represents the current operation. Returns a task that performs an asynchronous operation to update the blob's properties. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to update the blob's properties. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to update the blob's properties. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Deletes the blob. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to delete the blob. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to delete the blob. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to delete the blob. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to delete the blob. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete the blob. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete the blob. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete the blob. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Deletes the blob if it already exists. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. true if the blob did already exist and was deleted; otherwise false. Begins an asynchronous request to delete the blob if it already exists. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to delete the blob if it already exists. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Returns the result of an asynchronous request to delete the blob if it already exists. An that references the pending asynchronous operation. true if the blob did already exist and was deleted; otherwise, false. Returns a task that performs an asynchronous request to delete the blob if it already exists. A object that represents the current operation. Returns a task that performs an asynchronous request to delete the blob if it already exists. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous request to delete the blob if it already exists. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous request to delete the blob if it already exists. Whether to only delete the blob, to delete the blob and all snapshots, or to only delete the snapshots. An object that represents the access conditions for the container. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Creates a snapshot of the blob. A collection of name-value pairs defining the metadata of the snapshot. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request, or null. An object that represents the context for the current operation. A blob snapshot. Begins an asynchronous operation to create a snapshot of the blob. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to create a snapshot of the blob. A collection of name-value pairs defining the metadata of the snapshot. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request, or null. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to create a snapshot of the blob. An that references the pending asynchronous operation. A blob snapshot. Returns a task that performs an asynchronous operation to create a snapshot of the blob. A object that represents the current operation. Returns a task that performs an asynchronous operation to create a snapshot of the blob. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to create a snapshot of the blob. A collection of name-value pairs defining the metadata of the snapshot. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to create a snapshot of the blob. A collection of name-value pairs defining the metadata of the snapshot. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Acquires a lease on this blob. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. If null, an infinite lease will be acquired. If not null, this must be greater than zero. A string representing the proposed lease ID for the new lease, or null if no lease ID is proposed. An object that represents the access conditions for the blob. If null, no condition is used. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. The ID of the acquired lease. Begins an asynchronous operation to acquire a lease on this blob. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. If null, an infinite lease will be acquired. If not null, this must be greater than zero. A string representing the proposed lease ID for the new lease, or null if no lease ID is proposed. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to acquire a lease on this blob. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. If null, an infinite lease will be acquired. If not null, this must be greater than zero. A string representing the proposed lease ID for the new lease, or null if no lease ID is proposed. An object that represents the access conditions for the blob. If null, no condition is used. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to acquire a lease on this blob. An IAsyncResult that references the pending asynchronous operation. The ID of the acquired lease. Returns a task that performs an asynchronous operation to acquire a lease on this blob. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. If null, an infinite lease will be acquired. If not null, this must be greater than zero. A string representing the proposed lease ID for the new lease, or null if no lease ID is proposed. A object that represents the current operation. Returns a task that performs an asynchronous operation to acquire a lease on this blob. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. If null, an infinite lease will be acquired. If not null, this must be greater than zero. A string representing the proposed lease ID for the new lease, or null if no lease ID is proposed. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to acquire a lease on this blob. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. If null, an infinite lease will be acquired. If not null, this must be greater than zero. A string representing the proposed lease ID for the new lease, or null if no lease ID is proposed. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to acquire a lease on this blob. A representing the span of time for which to acquire the lease, which will be rounded down to seconds. If null, an infinite lease will be acquired. If not null, this must be greater than zero. A string representing the proposed lease ID for the new lease, or null if no lease ID is proposed. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Renews a lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. Begins an asynchronous operation to renew a lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to renew a lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to renew a lease on this blob. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to renew a lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A object that represents the current operation. Returns a task that performs an asynchronous operation to renew a lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to renew a lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to renew a lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Changes the lease ID on this blob. A string representing the proposed lease ID for the new lease. This cannot be null. An object that represents the access conditions for the blob, including a required lease ID. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. The new lease ID. Begins an asynchronous operation to change the lease on this blob. A string representing the proposed lease ID for the new lease. This cannot be null. An object that represents the access conditions for the blob, including a required lease ID. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to change the lease on this blob. A string representing the proposed lease ID for the new lease. This cannot be null. An object that represents the access conditions for the blob, including a required lease ID. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to change the lease on this blob. An that references the pending asynchronous operation. The new lease ID. Returns a task that performs an asynchronous operation to change the lease on this blob. A string representing the proposed lease ID for the new lease. This cannot be null. An object that represents the access conditions for the blob, including a required lease ID. A object that represents the current operation. Returns a task that performs an asynchronous operation to change the lease on this blob. A string representing the proposed lease ID for the new lease. This cannot be null. An object that represents the access conditions for the blob, including a required lease ID. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to change the lease on this blob. A string representing the proposed lease ID for the new lease. This cannot be null. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to change the lease on this blob. A string representing the proposed lease ID for the new lease. This cannot be null. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Releases the lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. Begins an asynchronous operation to release the lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to release the lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to release the lease on this blob. An IAsyncResult that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to release the lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A object that represents the current operation. Returns a task that performs an asynchronous operation to release the lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to release the lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to release the lease on this blob. An object that represents the access conditions for the blob, including a required lease ID. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Breaks the current lease on this blob. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. If null, the break period is the remainder of the current lease, or zero for infinite leases. An object that represents the access conditions for the blob. If null, no condition is used. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. A representing the amount of time before the lease ends, to the second. Begins an asynchronous operation to break the current lease on this blob. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. If null, the break period is the remainder of the current lease, or zero for infinite leases. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to break the current lease on this blob. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. If null, the break period is the remainder of the current lease, or zero for infinite leases. An object that represents the access conditions for the blob. If null, no condition is used. The options for this operation. If null, default options will be used. An object that represents the context for the current operation. An optional callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to break the current lease on this blob. An IAsyncResult that references the pending asynchronous operation. A representing the amount of time before the lease ends, to the second. Returns a task that performs an asynchronous operation to break the current lease on this blob. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. If null, the break period is the remainder of the current lease, or zero for infinite leases. A object that represents the current operation. Returns a task that performs an asynchronous operation to break the current lease on this blob. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. If null, the break period is the remainder of the current lease, or zero for infinite leases. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to break the current lease on this blob. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. If null, the break period is the remainder of the current lease, or zero for infinite leases. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to break the current lease on this blob. A representing the amount of time to allow the lease to remain, which will be rounded down to seconds. If null, the break period is the remainder of the current lease, or zero for infinite leases. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Writes pages to a page blob. A stream providing the page data. The offset at which to begin writing, in bytes. The offset must be a multiple of 512. An optional hash value that will be used to set the property on the blob. May be null or an empty string. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to write pages to a page blob. A stream providing the page data. The offset at which to begin writing, in bytes. The offset must be a multiple of 512. An optional hash value that will be used to set the property on the blob. May be null or an empty string. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to write pages to a page blob. A stream providing the page data. The offset at which to begin writing, in bytes. The offset must be a multiple of 512. An optional hash value that will be used to set the property on the blob. May be null or an empty string. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to write pages to a page blob. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to write pages to a page blob. A stream providing the page data. The offset at which to begin writing, in bytes. The offset must be a multiple of 512. An optional hash value that will be used to set the property on the blob. May be null or an empty string. A object that represents the current operation. Returns a task that performs an asynchronous operation to write pages to a page blob. A stream providing the page data. The offset at which to begin writing, in bytes. The offset must be a multiple of 512. An optional hash value that will be used to set the property on the blob. May be null or an empty string. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to write pages to a page blob. A stream providing the page data. The offset at which to begin writing, in bytes. The offset must be a multiple of 512. An optional hash value that will be used to set the property on the blob. May be null or an empty string. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to write pages to a page blob. A stream providing the page data. The offset at which to begin writing, in bytes. The offset must be a multiple of 512. An optional hash value that will be used to set the property on the blob. May be null or an empty string. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Clears pages from a page blob. The offset at which to begin clearing pages, in bytes. The offset must be a multiple of 512. The length of the data range to be cleared, in bytes. The length must be a multiple of 512. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to clear pages from a page blob. The offset at which to begin clearing pages, in bytes. The offset must be a multiple of 512. The length of the data range to be cleared, in bytes. The length must be a multiple of 512. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to clear pages from a page blob. The offset at which to begin clearing pages, in bytes. The offset must be a multiple of 512. The length of the data range to be cleared, in bytes. The length must be a multiple of 512. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to clear pages from a page blob. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to clear pages from a page blob. The offset at which to begin clearing pages, in bytes. The offset must be a multiple of 512. The length of the data range to be cleared, in bytes. The length must be a multiple of 512. A object that represents the current operation. Returns a task that performs an asynchronous operation to clear pages from a page blob. The offset at which to begin clearing pages, in bytes. The offset must be a multiple of 512. The length of the data range to be cleared, in bytes. The length must be a multiple of 512. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to clear pages from a page blob. The offset at which to begin clearing pages, in bytes. The offset must be a multiple of 512. The length of the data range to be cleared, in bytes. The length must be a multiple of 512. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to clear pages from a page blob. The offset at which to begin clearing pages, in bytes. The offset must be a multiple of 512. The length of the data range to be cleared, in bytes. The length must be a multiple of 512. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Requests that the service start to copy a blob's contents, properties, and metadata to a new blob. The URI of a source blob. An object that represents the access conditions for the source blob. If null, no condition is used. An object that represents the access conditions for the destination blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The copy ID associated with the copy operation. This method fetches the blob's ETag, last modified time, and part of the copy state. The copy ID and copy status fields are fetched, and the rest of the copy state is cleared. Requests that the service start to copy a blob's contents, properties, and metadata to a new blob. The URI of a source blob. An object that represents the access conditions for the source blob. If null, no condition is used. An object that represents the access conditions for the destination blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The copy ID associated with the copy operation. This method fetches the blob's ETag, last modified time, and part of the copy state. The copy ID and copy status fields are fetched, and the rest of the copy state is cleared. Begins an asynchronous operation to request that the service start to copy a blob's contents, properties, and metadata to a new blob. The URI of a source blob. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to request that the service start to copy a blob's contents, properties, and metadata to a new blob. The source blob. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The URI of a source blob. An object that represents the access conditions for the source blob. If null, no condition is used. An object that represents the access conditions for the destination blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The source blob. An object that represents the access conditions for the source blob. If null, no condition is used. An object that represents the access conditions for the destination blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to request that the service start to copy a blob's contents, properties, and metadata to a new blob. An that references the pending asynchronous operation. The copy ID associated with the copy operation. This method fetches the blob's ETag, last modified time, and part of the copy state. The copy ID and copy status fields are fetched, and the rest of the copy state is cleared. Returns a task that performs an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The URI of a source blob. A object that represents the current operation. Returns a task that performs an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The URI of a source blob. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The source blob. A object that represents the current operation. Returns a task that performs an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The source blob. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The URI of a source blob. An object that represents the access conditions for the source blob. If null, no condition is used. An object that represents the access conditions for the destination blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The URI of a source blob. An object that represents the access conditions for the source blob. If null, no condition is used. An object that represents the access conditions for the destination blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The source blob. An object that represents the access conditions for the source blob. If null, no condition is used. An object that represents the access conditions for the destination blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to request that the service start to copy another blob's contents, properties, and metadata to the blob referenced by this object. The source blob. An object that represents the access conditions for the source blob. If null, no condition is used. An object that represents the access conditions for the destination blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Aborts an ongoing blob copy operation. A string identifying the copy operation. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to abort an ongoing blob copy operation. A string identifying the copy operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to abort an ongoing blob copy operation. A string identifying the copy operation. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to abort an ongoing blob copy operation. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to abort an ongoing blob copy operation. A string identifying the copy operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to abort an ongoing blob copy operation. A string identifying the copy operation. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to abort an ongoing blob copy operation. A string identifying the copy operation. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to abort an ongoing blob copy operation. A string identifying the copy operation. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Implements the Create method. The size in bytes. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. A that creates the blob. Implementation for the Resize method. The size in bytes. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. A that sets the metadata. Implementation for the SetSequenceNumber method. A value of type , indicating the operation to perform on the sequence number. The sequence number. Set this parameter to null if this operation is an increment action. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. A that sets the sequence number. Implementation for the CreateSnapshot method. A collection of name-value pairs defining the metadata of the snapshot, or null. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. A that creates the snapshot. If the metadata parameter is null then no metadata is associated with the request. Gets the page ranges impl. The starting offset of the data range over which to list page ranges, in bytes. Must be a multiple of 512. The length of the data range over which to list page ranges, in bytes. Must be a multiple of 512. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. A for getting the page ranges. Implementation method for the WritePage methods. The page data. The start offset. The content MD5. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. A that writes the pages. Implementation method for the ClearPage methods. The start offset. Must be multiples of 512. Length of the data range to be cleared. Must be multiples of 512. An object that represents the access conditions for the blob. If null, no condition is used. A object that specifies additional options for the request. A that writes the pages. Default is 4 MB. Default is 4 MB. Initializes a new instance of the class using an absolute URI to the blob. The absolute URI to the blob. Initializes a new instance of the class using an absolute URI to the blob. The absolute URI to the blob. The account credentials. Initializes a new instance of the class using an absolute URI to the blob. The absolute URI to the blob. The snapshot timestamp, if the blob is a snapshot. The account credentials. Initializes a new instance of the class using an absolute URI to the blob. The absolute URI to the blob. The service assumes this is the URI for the blob in the primary location. The snapshot timestamp, if the blob is a snapshot. The account credentials. Initializes a new instance of the class using the specified blob name and the parent container reference. If snapshotTime is not null, the blob instance represents a Snapshot. Name of the blob. Snapshot time in case the blob is a snapshot. The reference to the parent container. Initializes a new instance of the class. The attributes. The service client. Stores the that contains this blob. Stores the blob's parent . Stores the blob's attributes. Returns a shared access signature for the blob. The access policy for the shared access signature. A shared access signature, as a URI query string. The query string returned includes the leading question mark. Returns a shared access signature for the blob. The access policy for the shared access signature. A stored access policy. A shared access signature, as a URI query string. The query string returned includes the leading question mark. Returns a shared access signature for the blob. The access policy for the shared access signature. The optional header values to set for a blob accessed with this SAS. A shared access signature. Returns a shared access signature for the blob. The access policy for the shared access signature. The optional header values to set for a blob returned with this SAS. A stored access policy. A shared access signature. Gets the canonical name of the blob, formatted as /<account-name>/<container-name>/<blob-name>. If ignoreSnapshotTime is false and this blob is a snapshot, the canonical name is augmented with a query of the form ?snapshot=<snapshot-time>. This is used by both Shared Access and Copy blob operations. Indicates if the snapshot time is ignored. The canonical name of the blob. Parse URI for SAS (Shared Access Signature) and snapshot information. The complete Uri. The credentials to use. Gets the object that represents the Blob service. A client object that specifies the Blob service endpoint. Gets or sets the number of bytes to buffer when writing to a page blob stream. The number of bytes to buffer, ranging from between 512 bytes and 4 MB inclusive. Gets or sets the minimum number of bytes to buffer when reading from a blob stream. The minimum number of bytes to buffer, being at least 16KB. Gets the blob's system properties. The blob's properties. Gets the user-defined metadata for the blob. The blob's metadata, as a collection of name-value pairs. Gets the blob's URI for the primary location. The absolute URI to the blob, at the primary location. Gets the page blob's URIs for all locations. An object of type containing the page blob's URIs for all locations. Gets the date and time that the blob snapshot was taken, if this blob is a snapshot. The blob's snapshot time, if the blob is a snapshot. If the blob is not a snapshot, the value of this property is null. Gets a value indicating whether this blob is a snapshot. true if this blob is a snapshot; otherwise, false. Gets the absolute URI to the blob, including query string information if the blob is a snapshot. The absolute URI to the blob, including snapshot query information if the blob is a snapshot. Gets the page blob's URI for all locations, including query string information if the blob is a snapshot. An object of type containing the page blob's URIs for all locations, including snapshot query information if the blob is a snapshot. Gets the state of the most recent or pending copy operation. A object containing the copy state, or null if no copy blob state exists for this blob. Gets the type of the blob. The type of the blob. Gets the blob's name. The blob's name. Gets a object representing the blob's container. The blob's container. Gets the object representing the virtual parent directory for the blob. The blob's virtual parent directory. Provides a set of methods for parsing a response containing blob data from the Blob service. Gets the request ID from the response. The web response. A unique value associated with the request. Gets the blob's properties from the response. The web response. The blob's properties. Extracts the lease status from a web response. The web response. A enumeration from the web response. If the appropriate header is not present, a status of is returned. The header contains an unrecognized value. Extracts the lease state from a web response. The web response. A enumeration from the web response. If the appropriate header is not present, a status of is returned. The header contains an unrecognized value. Extracts the lease duration from a web response. The web response. A enumeration from the web response. If the appropriate header is not present, a status of is returned. The header contains an unrecognized value. Extracts the lease ID header from a web response. The web response. The lease ID. Extracts the remaining lease time from a web response. The web response. The remaining lease time, in seconds. Gets the user-defined metadata. The response from server. A of the metadata. Extracts a object from the headers of a web response. The HTTP web response. A object, or null if the web response does not contain a copy status. Gets the snapshot timestamp from the response. The web response. The snapshot timestamp. Reads service properties from a stream. The stream from which to read the service properties. The service properties stored in the stream. Reads service stats from a stream. The stream from which to read the service stats. The service stats stored in the stream. Gets a from a string. The lease status string. A enumeration. If a null or empty string is supplied, a status of is returned. The string contains an unrecognized value. Gets a from a string. The lease state string. A enumeration. If a null or empty string is supplied, a status of is returned. The string contains an unrecognized value. Gets a from a string. The lease duration string. A enumeration. If a null or empty string is supplied, a status of is returned. The string contains an unrecognized value. Builds a object from the given strings containing formatted copy information. The copy status, as a string. The copy ID. The source URI of the copy, as a string. A string formatted as progressBytes/TotalBytes. The copy completion time, as a string, or null. The copy status description, if any. A object populated from the given strings. A factory class for constructing a web request to manage blobs in the Blob service. Creates a web request to get the properties of the Blob service. The absolute URI to the Blob service. An object of type , containing additional parameters to add to the URI query string. The server timeout interval, in seconds. An object for tracking the current operation. A web request to get the Blob service properties. Creates a web request to set the properties of the Blob service. The absolute URI to the Blob service. An object of type , containing additional parameters to add to the URI query string. The server timeout interval, in seconds. An object for tracking the current operation. A web request to set the Blob service properties. Creates a web request to get the stats of the Blob service. The absolute URI to the Blob service. An object of type , containing additional parameters to add to the URI query string. The server timeout interval, in seconds. An object for tracking the current operation. A web request to get the Blob service stats. Writes Blob service properties to a stream, formatted in XML. The service properties to format and write to the stream. The stream to which the formatted properties are to be written. Constructs a web request to create a new block blob or page blob, or to update the content of an existing block blob. The absolute URI to the blob. The server timeout interval. The properties to set for the blob. The type of the blob. For a page blob, the size of the blob. This parameter is ignored for block blobs. The access condition to apply to the request. An object for tracking the current operation. A web request to use to perform the operation. Adds the snapshot. An object of type that contains additional parameters to add to the URI query string. The snapshot version, if the blob is a snapshot. Constructs a web request to return the list of valid page ranges for a page blob. The absolute URI to the blob. The server timeout interval. The snapshot timestamp, if the blob is a snapshot. The starting offset of the data range over which to list page ranges, in bytes. Must be a multiple of 512. The length of the data range over which to list page ranges, in bytes. Must be a multiple of 512. The access condition to apply to the request. An object for tracking the current operation. A web request to use to perform the operation. Adds the Range Header for Blob Service Operations. Request Starting byte of the range Number of bytes in the range Constructs a web request to return the blob's system properties. The absolute URI to the blob. The server timeout interval. The snapshot timestamp, if the blob is a snapshot. The access condition to apply to the request. An object for tracking the current operation. A web request for performing the operation. Constructs a web request to set system properties for a blob. The absolute URI to the blob. The server timeout interval. The blob's properties. The access condition to apply to the request. An object for tracking the current operation. A web request to use to perform the operation. Constructs a web request to resize a page blob. The absolute URI to the blob. The server timeout interval. The new blob size, if the blob is a page blob. Set this parameter to null to keep the existing blob size. The access condition to apply to the request. An object for tracking the current operation. A web request to use to perform the operation. Constructs a web request to set a page blob's sequence number. The absolute URI to the blob. The server timeout interval. A value of type , indicating the operation to perform on the sequence number. The sequence number. Set this parameter to null if this operation is an increment action. The access condition to apply to the request. An object for tracking the current operation. A web request to use to perform the operation. Constructs a web request to return the user-defined metadata for the blob. The absolute URI to the blob. The server timeout interval. The snapshot timestamp, if the blob is a snapshot. The access condition to apply to the request. An object for tracking the current operation. A web request for performing the operation. Constructs a web request to set user-defined metadata for the blob. The absolute URI to the blob. The server timeout interval. The access condition to apply to the request. An object for tracking the current operation. A web request for performing the operation. Adds user-defined metadata to the request as one or more name-value pairs. The web request. The user-defined metadata. Adds user-defined metadata to the request as a single name-value pair. The web request. The metadata name. The metadata value. Constructs a web request to delete a blob. The absolute URI to the blob. The server timeout interval. The snapshot timestamp, if the blob is a snapshot. A set of options indicating whether to delete only blobs, only snapshots, or both. The access condition to apply to the request. An object for tracking the current operation. A web request to use to perform the operation. Constructs a web request to create a snapshot of a blob. The absolute URI to the blob. The server timeout interval. The access condition to apply to the request. An object for tracking the current operation. A web request to use to perform the operation. Generates a web request to use to acquire, renew, change, release or break the lease for the blob. The absolute URI to the blob. The server timeout interval, in seconds. The lease action to perform. A lease ID to propose for the result of an acquire or change operation, or null if no ID is proposed for an acquire operation. This should be null for renew, release, and break operations. The lease duration, in seconds, for acquire operations. If this is -1 then an infinite duration is specified. This should be null for renew, change, release, and break operations. The amount of time to wait, in seconds, after a break operation before the lease is broken. If this is null then the default time is used. This should be null for acquire, renew, change, and release operations. The access condition to apply to the request. An object for tracking the current operation. A web request to use to perform the operation. Adds a proposed lease id to a request. The request. The proposed lease id. Adds a lease duration to a request. The request. The lease duration. Adds a lease break period to a request. The request. The lease break period. Adds a lease action to a request. The request. The lease action. Constructs a web request to write a block to a block blob. The absolute URI to the blob. The server timeout interval. The block ID for this block. The access condition to apply to the request. An object for tracking the current operation. A web request to use to perform the operation. Constructs a web request to create or update a blob by committing a block list. The absolute URI to the blob. The server timeout interval. The properties to set for the blob. The access condition to apply to the request. An object for tracking the current operation. A web request for performing the operation. Constructs a web request to return the list of blocks for a block blob. The absolute URI to the blob. The server timeout interval. The snapshot timestamp, if the blob is a snapshot. The types of blocks to include in the list: committed, uncommitted, or both. The access condition to apply to the request. An object for tracking the current operation. A web request to use to perform the operation. Constructs a web request to write or clear a range of pages in a page blob. The absolute URI to the blob. The server timeout interval. The page range, defined by an object of type . A value of type , indicating the operation to perform on the page blob. The to apply to the request. An object for tracking the current operation. A web request to use to perform the operation. Generates a web request to copy a blob. The absolute URI to the destination blob. The server timeout interval. The absolute URI to the source blob, including any necessary authentication parameters. The access condition to apply to the source blob. The access condition to apply to the destination blob. An object for tracking the current operation. A web request to use to perform the operation. Generates a web request to abort a copy operation. The absolute URI to the blob. The server timeout interval. The ID string of the copy operation to be aborted. The access condition to apply to the request. Only lease conditions are supported for this operation. An object for tracking the current operation. A web request for performing the operation. Constructs a web request to get the blob's content, properties, and metadata. The absolute URI to the blob. The server timeout interval. The snapshot version, if the blob is a snapshot. The access condition to apply to the request. An object for tracking the current operation. A web request for performing the operation. Constructs a web request to return a specified range of the blob's content, together with its properties and metadata. The absolute URI to the blob. The server timeout interval, in seconds. The snapshot version, if the blob is a snapshot. The byte offset at which to begin returning content. The number of bytes to return, or null to return all bytes through the end of the blob. If set to true, request an MD5 header for the specified range. The access condition to apply to the request. An object for tracking the current operation. A web request to use to perform the operation. Provides a set of methods for parsing container responses from the Blob service. Gets the request ID from the response. The web response. A unique value associated with the request. Gets the container's properties from the response. The web response. The container's attributes. Gets the user-defined metadata. The response from server. A of the metadata. Gets the ACL for the container from the response. The web response. A value indicating the public access level for the container. Reads the share access policies from a stream in XML. The stream of XML policies. The permissions object to which the policies are to be written. Converts the ACL string to a object. The string to convert. The resulting object. A factory class for constructing a web request to manage containers in the Blob service. Constructs a web request to create a new container. The absolute URI to the container. The server timeout interval. An object for tracking the current operation. A web request to use to perform the operation. Constructs a web request to create a new container. The absolute URI to the container. The server timeout interval. An object for tracking the current operation. An object that specifies whether data in the container may be accessed publicly and the level of access. A web request to use to perform the operation. Constructs a web request to delete the container and all of the blobs within it. The absolute URI to the container. The server timeout interval. The access condition to apply to the request. An object for tracking the current operation. A web request to use to perform the operation. Generates a web request to return the user-defined metadata for this container. The absolute URI to the container. The server timeout interval. The access condition to apply to the request. An object for tracking the current operation. A web request to use to perform the operation. Generates a web request to return the properties and user-defined metadata for this container. The absolute URI to the container. The server timeout interval. The access condition to apply to the request. An object for tracking the current operation. A web request to use to perform the operation. Generates a web request to set user-defined metadata for the container. The absolute URI to the container. The server timeout interval. The access condition to apply to the request. An object for tracking the current operation. A web request to use to perform the operation. Generates a web request to use to acquire, renew, change, release or break the lease for the container. The absolute URI to the container. The server timeout interval, in seconds. The lease action to perform. A lease ID to propose for the result of an acquire or change operation, or null if no ID is proposed for an acquire operation. This should be null for renew, release, and break operations. The lease duration, in seconds, for acquire operations. If this is -1 then an infinite duration is specified. This should be null for renew, change, release, and break operations. The amount of time to wait, in seconds, after a break operation before the lease is broken. If this is null then the default time is used. This should be null for acquire, renew, change, and release operations. The access condition to apply to the request. An object for tracking the current operation. A web request to use to perform the operation. Adds user-defined metadata to the request as one or more name-value pairs. The web request. The user-defined metadata. Adds user-defined metadata to the request as a single name-value pair. The web request. The metadata name. The metadata value. Constructs a web request to return a listing of all containers in this storage account. The absolute URI for the account. The server timeout interval. A set of parameters for the listing operation. Additional details to return with the listing. An object for tracking the current operation. A web request for the specified operation. Constructs a web request to return the ACL for a container. The absolute URI to the container. The server timeout interval. The access condition to apply to the request. An object for tracking the current operation. A web request to use to perform the operation. Constructs a web request to set the ACL for a container. The absolute URI to the container. The server timeout interval. The type of public access to allow for the container. The access condition to apply to the request. An object for tracking the current operation. A web request to use to perform the operation. Generates a web request to return a listing of all blobs in the container. The absolute URI to the container. The server timeout interval. A set of parameters for the listing operation. An object for tracking the current operation. A web request to use to perform the operation. Gets the container Uri query builder. A for the container. This class represents a queue in the Windows Azure Queue service. This class represents a queue in the Windows Azure Queue service. Creates the queue. A object that specifies additional options for the request. An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. Begins an asynchronous operation to create a queue. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to create a queue. A object that specifies additional options for the request. An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to create a queue. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to create a queue. A object that represents the current operation. Returns a task that performs an asynchronous operation to create a queue. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to create a queue. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to create a queue. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Creates the queue if it does not already exist. A object that specifies additional options for the request. An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. true if the queue did not already exist and was created; otherwise false. Begins an asynchronous request to create the queue if it does not already exist. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to create the queue if it does not already exist. A object that specifies additional options for the request. An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Returns the result of an asynchronous request to create the queue if it does not already exist. An that references the pending asynchronous operation. true if the queue did not already exist and was created; otherwise, false. Returns a task that performs an asynchronous request to create the queue if it does not already exist. A object that represents the current operation. Returns a task that performs an asynchronous request to create the queue if it does not already exist. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous request to create the queue if it does not already exist. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous request to create the queue if it does not already exist. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Deletes the queue if it already exists. A object that specifies additional options for the request. An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. true if the queue did not already exist and was created; otherwise false. Begins an asynchronous request to delete the queue if it already exists. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to delete the queue if it already exists. A object that specifies additional options for the request. An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Returns the result of an asynchronous request to delete the queue if it already exists. An that references the pending asynchronous operation. true if the queue did not already exist and was created; otherwise, false. Returns a task that performs an asynchronous request to delete the queue if it already exists. A object that represents the current operation. Returns a task that performs an asynchronous request to delete the queue if it already exists. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous request to delete the queue if it already exists. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous request to delete the queue if it already exists. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Deletes the queue. A object that specifies additional options for the request. An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. Begins an asynchronous operation to delete a queue. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to delete a queue. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to delete a queue. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to delete a queue. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete a queue. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete a queue. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete a queue. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Sets permissions for the queue. The permissions to apply to the queue. A object that specifies additional options for the request. An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. Begins an asynchronous request to set permissions for the queue. The permissions to apply to the queue. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to set permissions for the queue. The permissions to apply to the queue. A object that specifies additional options for the request. An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Returns the result of an asynchronous request to set permissions for the queue. An that references the pending asynchronous operation. Returns a task that performs an asynchronous request to set permissions for the queue. The permissions to apply to the queue. A object that represents the current operation. Returns a task that performs an asynchronous request to set permissions for the queue. The permissions to apply to the queue. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous request to set permissions for the queue. The permissions to apply to the queue. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous request to set permissions for the queue. The permissions to apply to the queue. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Gets the permissions settings for the queue. A object that specifies additional options for the request. An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. The queue's permissions. Begins an asynchronous request to get the permissions settings for the queue. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to get the permissions settings for the queue. A object that specifies additional options for the request. An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Returns the asynchronous result of the request to get the permissions settings for the queue. An that references the pending asynchronous operation. The queue's permissions. Returns a task that performs an asynchronous request to get the permissions settings for the queue. A object that represents the current operation. Returns a task that performs an asynchronous request to get the permissions settings for the queue. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous request to get the permissions settings for the queue. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous request to get the permissions settings for the queue. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Checks existence of the queue. A object that specifies additional options for the request. An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. true if the queue exists. Checks existence of the queue. If true, the command will be executed against the primary location. A object that specifies additional options for the request. An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. true if the queue exists. Begins an asynchronous request to check existence of the queue. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to check existence of the queue. A object that specifies additional options for the request. An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to check existence of the queue. If true, the command will be executed against the primary location. A object that specifies additional options for the request. An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Returns the asynchronous result of the request to check existence of the queue. An that references the pending asynchronous operation. true if the queue exists. Returns a task that performs an asynchronous request to check existence of the queue. A object that represents the current operation. Returns a task that performs an asynchronous request to check existence of the queue. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous request to check existence of the queue. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous request to check existence of the queue. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Sets the queue's user-defined metadata. A object that specifies additional options for the request. Specifying null will use the default request options from the associated service client (). An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. Begins an asynchronous operation to set user-defined metadata on the queue. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to set user-defined metadata on the queue. A object that specifies additional options for the request. Specifying null will use the default request options from the associated service client (). An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous request operation to set user-defined metadata on the queue. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to set user-defined metadata on the queue. A object that represents the current operation. Returns a task that performs an asynchronous operation to set user-defined metadata on the queue. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to set user-defined metadata on the queue. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to set user-defined metadata on the queue. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Fetches the queue's attributes. A object that specifies additional options for the request. Specifying null will use the default request options from the associated service client (). An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. Begins an asynchronous operation to fetch the queue's attributes. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to fetch the queue's attributes. A object that specifies additional options for the request. An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to fetch a queue's attributes. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to fetch the queue's attributes. A object that represents the current operation. Returns a task that performs an asynchronous operation to fetch the queue's attributes. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to fetch the queue's attributes. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to fetch the queue's attributes. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Adds a message to the queue. The message to add. The maximum time to allow the message to be in the queue, or null. The length of time from now during which the message will be invisible. If null then the message will be visible immediately. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to add a message to the queue. The message to add. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to add a message to the queue. The message to add. The maximum time to allow the message to be in the queue, or null. The length of time from now during which the message will be invisible. If null then the message will be visible immediately. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to add a message to the queue. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to add a message to the queue. The message to add. A object that represents the current operation. Returns a task that performs an asynchronous operation to add a message to the queue. The message to add. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to add a message to the queue. The message to add. The maximum time to allow the message to be in the queue, or null. The length of time from now during which the message will be invisible. If null then the message will be visible immediately. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to add a message to the queue. The message to add. The maximum time to allow the message to be in the queue, or null. The length of time from now during which the message will be invisible. If null then the message will be visible immediately. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Updates the visibility timeout and optionally the content of a message. The message to update. The visibility timeout interval. Flags of values that specifies which parts of the message are to be updated. A object that specifies additional options for the request. An object that represents the context for the current operation. Begins an asynchronous operation to update the visibility timeout and optionally the content of a message. The message to update. The visibility timeout interval. An EnumSet of values that specifies which parts of the message are to be updated. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to update the visibility timeout and optionally the content of a message. The message to update. The visibility timeout interval. An EnumSet of values that specifies which parts of the message are to be updated. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to add a message to the queue. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to update the visibility timeout and optionally the content of a message. The message to update. The visibility timeout interval. An EnumSet of values that specifies which parts of the message are to be updated. A object that represents the current operation. Returns a task that performs an asynchronous operation to update the visibility timeout and optionally the content of a message. The message to update. The visibility timeout interval. An EnumSet of values that specifies which parts of the message are to be updated. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to update the visibility timeout and optionally the content of a message. The message to update. The visibility timeout interval. An EnumSet of values that specifies which parts of the message are to be updated. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to update the visibility timeout and optionally the content of a message. The message to update. The visibility timeout interval. An EnumSet of values that specifies which parts of the message are to be updated. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Deletes a message. A message. A object that specifies additional options for the request. Specifying null will use the default request options from the associated service client (). An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. Deletes the specified message from the queue. The message ID. The pop receipt value. A object that specifies additional options for the request. Specifying null will use the default request options from the associated service client (). An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. Begins an asynchronous operation to delete a message. A message. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to delete a message. A message. A object that specifies additional options for the request. Specifying null will use the default request options from the associated service client (). An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to delete a message. The message ID. The pop receipt value. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to delete a message. The message ID. The pop receipt value. A object that specifies additional options for the request. Specifying null will use the default request options from the associated service client (). An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to delete a message. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to delete a message. A message. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete a message. A message. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete a message. A message. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete a message. A message. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete a message. The message ID. The pop receipt value. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete a message. The message ID. The pop receipt value. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete a message. The message ID. The pop receipt value. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete a message. The message ID. The pop receipt value. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Gets the specified number of messages from the queue using the specified request options and operation context. This operation marks the retrieved messages as invisible in the queue for the default visibility timeout period. The number of messages to retrieve. The visibility timeout interval. A object that specifies additional options for the request. Specifying null will use the default request options from the associated service client (). An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. An enumerable collection of messages. Begins an asynchronous operation to get messages from the queue. The number of messages to retrieve. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to get the specified number of messages from the queue using the specified request options and operation context. This operation marks the retrieved messages as invisible in the queue for the default visibility timeout period. The number of messages to retrieve. The visibility timeout interval. A object that specifies additional options for the request. Specifying null will use the default request options from the associated service client (). An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to get messages from the queue. An that references the pending asynchronous operation. An enumerable collection of messages. Returns a task that performs an asynchronous operation to get messages from the queue. The number of messages to retrieve. A object that represents the current operation. Returns a task that performs an asynchronous operation to get messages from the queue. The number of messages to retrieve. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to get the specified number of messages from the queue using the specified request options and operation context. This operation marks the retrieved messages as invisible in the queue for the default visibility timeout period. The number of messages to retrieve. The visibility timeout interval. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to get the specified number of messages from the queue using the specified request options and operation context. This operation marks the retrieved messages as invisible in the queue for the default visibility timeout period. The number of messages to retrieve. The visibility timeout interval. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Gets a message from the queue using the default request options. This operation marks the retrieved message as invisible in the queue for the default visibility timeout period. The visibility timeout interval. A object that specifies additional options for the request. Specifying null will use the default request options from the associated service client (). An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. A message. Begins an asynchronous operation to get a single message from the queue. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to get a single message from the queue, and specifies how long the message should be reserved before it becomes visible, and therefore available for deletion. The visibility timeout interval. A object that specifies additional options for the request. Specifying null will use the default request options from the associated service client (). An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to get a single message from the queue. An that references the pending asynchronous operation. A message. Returns a task that performs an asynchronous operation to get a single message from the queue. A object that represents the current operation. Returns a task that performs an asynchronous operation to get a single message from the queue. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to get a single message from the queue, and specifies how long the message should be reserved before it becomes visible, and therefore available for deletion. The visibility timeout interval. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to get a single message from the queue, and specifies how long the message should be reserved before it becomes visible, and therefore available for deletion. The visibility timeout interval. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Peeks a message from the queue, using the specified request options and operation context. A peek request retrieves a message from the queue without changing its visibility. The number of messages to peek. A object that specifies additional options for the request. Specifying null will use the default request options from the associated service client (). An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. An enumerable collection of messages. Begins an asynchronous operation to peek messages from the queue. The number of messages to peek. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to peek messages from the queue. The number of messages to peek. A object that specifies additional options for the request. Specifying null will use the default request options from the associated service client (). An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to peek messages from the queue. An that references the pending asynchronous operation. An enumerable collection of messages. Returns a task that performs an asynchronous operation to peek messages from the queue. The number of messages to peek. A object that represents the current operation. Returns a task that performs an asynchronous operation to peek messages from the queue. The number of messages to peek. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to peek messages from the queue. The number of messages to peek. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to peek messages from the queue. The number of messages to peek. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Peeks a single message from the queue. A peek request retrieves a message from the queue without changing its visibility. A object that specifies additional options for the request. Specifying null will use the default request options from the associated service client (). An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. A message. Begins an asynchronous operation to get a single message from the queue. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to peek a single message from the queue. A object that specifies additional options for the request. Specifying null will use the default request options from the associated service client (). An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to peek a single message from the queue. An that references the pending asynchronous operation. A message. Returns a task that performs an asynchronous operation to get a single message from the queue. A object that represents the current operation. Returns a task that performs an asynchronous operation to get a single message from the queue. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to get a single message from the queue. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to get a single message from the queue. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Clears all messages from the queue. A object that specifies additional options for the request. Specifying null will use the default request options from the associated service client (). An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. Begins an asynchronous operation to clear all messages from the queue. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to clear all messages from the queue. A object that specifies additional options for the request. Specifying null will use the default request options from the associated service client (). An object that represents the context for the current operation. This object is used to track requests to the storage service, and to provide additional runtime information about the operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to clear all messages from the queue. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to clear all messages from the queue. A object that represents the current operation. Returns a task that performs an asynchronous operation to clear all messages from the queue. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to clear all messages from the queue. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to clear all messages from the queue. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Ends an asynchronous operation to clear all messages from the queue. An that references the pending asynchronous operation. Implementation for the ClearMessages method. A object that specifies additional options for the request. A that gets the permissions. Implementation for the Create method. A object that specifies additional options for the request. A that creates the queue. Implementation for the Delete method. A object that specifies additional options for the request. A that deletes the queue. Implementation for the FetchAttributes method. A object that specifies additional options for the request. A that fetches the attributes. Implementation for the Exists method. A object that specifies additional options for the request. If true, the command will be executed against the primary location. A that checks existence. Implementation for the SetMetadata method. A object that specifies additional options for the request. A that sets the metadata. Implementation for the SetPermissions method. The permissions to set. A object that specifies additional options for the request. A that sets the permissions. Implementation for the GetPermissions method. A object that specifies additional options for the request. A that gets the permissions. Implementation for the AddMessageImpl method. A queue message. A value indicating the message time-to-live. The visibility delay for the message. A object that specifies additional options for the request. A that sets the permissions. Implementation for the UpdateMessage method. A queue message. The visibility timeout for the message. Indicates whether to update the visibility delay, message contents, or both. A object that specifies additional options for the request. A that sets the permissions. Implementation for the DeleteMessage method. The message ID. The pop receipt value. A object that specifies additional options for the request. A that deletes the queue. Implementation for the GetPermissions method. The number of messages to retrieve. The visibility timeout interval. A object that specifies additional options for the request. A that gets the permissions. Implementation for the PeekMessages method. The number of messages to retrieve. A object that specifies additional options for the request. A that gets the permissions. Gets the ApproximateMessageCount and metadata from response. The web response. Update the message pop receipt and next visible time. The Cloud Queue Message. The web response. Initializes a new instance of the class. The absolute URI to the queue. Initializes a new instance of the class. The absolute URI to the queue. The account credentials. Initializes a new instance of the class. The absolute URI to the queue. The account credentials. Initializes a new instance of the class. The queue name. A client object that specifies the endpoint for the queue service. Uri for the messages. Gets the Uri for general message operations. Gets the individual message address. The message id. The URI of the message. Parse URI for SAS (Shared Access Signature) information. The complete Uri. The credentials to use. Returns the canonical name for shared access. The canonical name. Selects the get message response. The protocol message. The parsed message. Selects the peek message response. The protocol message. The parsed message. Returns a shared access signature for the queue. The access policy for the shared access signature. A queue-level access policy. A shared access signature, as a URI query string. The query string returned includes the leading question mark. Gets the service client for the queue. A client object that specifies the endpoint for the queue service. Gets the queue's URI for the primary location. The absolute URI to the queue, at the primary location. Gets the queue's URIs for all locations. An object of type containing the queue's URIs for all locations. Gets the name of the queue. The queue's name. Gets the approximate message count for the queue. The approximate message count. Gets or sets a value indicating whether to apply base64 encoding when adding or retrieving messages. True to encode messages; otherwise, false. The default value is true. Gets the queue's metadata. The queue's metadata. Provides a client-side logical representation of the Windows Azure Queue service. This client is used to configure and execute requests against the Queue service. The service client encapsulates the base URI for the Queue service. If the service client will be used for authenticated access, it also encapsulates the credentials for accessing the storage account. Provides a client-side logical representation of the Windows Azure Queue service. This client is used to configure and execute requests against the Queue service. The service client encapsulates the base URI for the Queue service. If the service client will be used for authenticated access, it also encapsulates the credentials for accessing the storage account. Returns an enumerable collection of the queues in the storage account whose names begin with the specified prefix and that are retrieved lazily. The queue name prefix. An enumeration value that indicates which details to include in the listing. An object that specifies additional options for the request. An object that represents the context for the current operation. This object is used to track requests, and to provide additional runtime information about the operation. An enumerable collection of objects that implement and are retrieved lazily. Returns a result segment containing a collection of queues in the storage account. A continuation token returned by a previous listing operation. A result segment containing objects that implement . Returns a result segment containing a collection of queues in the storage account. The queue name prefix. A continuation token returned by a previous listing operation. A result segment containing objects that implement . Returns a result segment containing a collection of queues in the storage account. The queue name prefix. A enumeration describing which items to include in the listing. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A returned by a previous listing operation. An object that specifies additional options for the request. An object that represents the context for the current operation. This object is used to track requests, and to provide additional runtime information about the operation. A result segment containing objects that implement . Returns a result segment containing a collection of queues in the storage account. The queue name prefix. A enumeration describing which items to include in the listing. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A returned by a previous listing operation. An object that specifies additional options for the request. An object that represents the context for the current operation. This object is used to track requests, and to provide additional runtime information about the operation. A result segment. Begins an asynchronous operation to return a result segment containing a collection of queue items. A returned by a previous listing operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to return a result segment containing a collection of queue items. The queue name prefix. A returned by a previous listing operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to return a result segment containing a collection of queue items. The queue name prefix. A enumeration describing which items to include in the listing. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A returned by a previous listing operation. An object that specifies additional options for the request. An object that represents the context for the current operation. This object is used to track requests, and to provide additional runtime information about the operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to return a result segment containing a collection of queue items. An that references the pending asynchronous operation. A queue result segment. Returns a task that performs an asynchronous operation to return a result segment containing a collection of queue items. A returned by a previous listing operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to return a result segment containing a collection of queue items. A returned by a previous listing operation. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to return a result segment containing a collection of queue items. The queue name prefix. A returned by a previous listing operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to return a result segment containing a collection of queue items. The queue name prefix. A returned by a previous listing operation. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to return a result segment containing a collection of queue items. The queue name prefix. A enumeration describing which items to include in the listing. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A returned by a previous listing operation. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to return a result segment containing a collection of queue items. The queue name prefix. A enumeration describing which items to include in the listing. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A returned by a previous listing operation. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Core implementation of the ListQueues method. The queue name prefix. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A enumeration describing which items to include in the listing. An object that specifies additional options for the request. The continuation token. A that lists the queues. Begins an asynchronous operation to get the properties of the queue service. The callback delegate that will receive notification when the asynchronous operation completes. A user defined object to be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to get the properties of the queue service. A object that specifies additional options for the request. Specifying null will use the default request options from the associated service client (). An object that represents the context for the current operation. This object is used to track requests, and to provide additional runtime information about the operation. The callback delegate that will receive notification when the asynchronous operation completes. A user defined object to be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to get the properties of the queue service. The result returned from a prior call to . A object containing the queue service properties. Returns a task that performs an asynchronous operation to get the properties of the queue service. A object that represents the current operation. Returns a task that performs an asynchronous operation to get the properties of the queue service. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to get the properties of the queue service. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to get the properties of the queue service. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Gets the properties of the queue service. A object that specifies additional options for the request. Specifying null will use the default request options from the associated service client (). An object that represents the context for the current operation. This object is used to track requests, and to provide additional runtime information about the operation. The queue service properties. Begins an asynchronous operation to set the properties of the queue service. The queue service properties. The callback delegate that will receive notification when the asynchronous operation completes. A user defined object to be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to set the properties of the queue service. The queue service properties. A object that specifies additional options for the request. Specifying null will use the default request options from the associated service client (). An object that represents the context for the current operation. This object is used to track requests, and to provide additional runtime information about the operation. The callback delegate that will receive notification when the asynchronous operation completes. A user defined object to be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to set the properties of the queue service. The result returned from a prior call to . Returns a task that performs an asynchronous operation to set the properties of the queue service. The queue service properties. A object that represents the current operation. Returns a task that performs an asynchronous operation to set the properties of the queue service. The queue service properties. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to set the properties of the queue service. The queue service properties. A object that specifies additional options for the request. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to set the properties of the queue service. The queue service properties. A object that specifies additional options for the request. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Sets the properties of the queue service. The queue service properties. A object that specifies additional options for the request. Specifying null will use the default request options from the associated service client (). An object that represents the context for the current operation. This object is used to track requests, and to provide additional runtime information about the operation. Begins an asynchronous operation to get the stats of the queue service. The callback delegate that will receive notification when the asynchronous operation completes. A user defined object to be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to get the stats of the queue service. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user defined object to be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to get the stats of the queue service. An that references the pending asynchronous operation. The queue service stats. Returns a task that performs an asynchronous operation to get the stats of the queue service. A object that represents the current operation. Returns a task that performs an asynchronous operation to get the stats of the queue service. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to get the stats of the queue service. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to get the stats of the queue service. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Gets the stats of the queue service. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. The queue service stats. The default server and client timeout interval. Max execution time across all potential retries. Initializes a new instance of the class using the specified queue service endpoint and anonymous credentials. The queue service endpoint to use to create the client. Initializes a new instance of the class using the specified queue service endpoint and account credentials. The queue service endpoint to use to create the client. The account credentials. Initializes a new instance of the class using the specified Queue service endpoint and account credentials. The Queue service endpoint to use to create the client. The account credentials. Returns a reference to a object with the specified name. The name of the queue, or an absolute URI to the queue. A reference to a queue. Gets or sets the authentication scheme to use to sign HTTP requests. Gets the authentication handler used to sign HTTP requests. The authentication handler. Gets or sets a buffer manager that implements the interface, specifying a buffer pool for use with operations against the Queue service client. Gets the account credentials used to create the queue service client. The account credentials. Gets the base URI for the Queue service client, at the primary location. The base URI used to construct the Queue service client, at the primary location. Gets the Queue service endpoints for all locations. An object of type containing Queue service URIs for all locations. Gets or sets the default retry policy for requests made via the Queue service client. The retry policy. Gets or sets the default location mode for requests made via the Queue service client. The location mode. Gets or sets the default server and client timeout for requests made via the Queue service client. The server and client timeout interval. Gets or sets the maximum execution time across all potential retries. The maximum execution time across all potential retries. Gets a value indicating whether the service client is used with Path style or Host style. Is true if use path style URIs; otherwise, false. Represents a message in the Windows Azure Queue service. Represents a message in the Windows Azure Queue service. The maximum message size in bytes. The maximum number of messages that can be peeked at a time. Initializes a new instance of the class with the given byte array. The content of the message as a byte array. Sets the content of this message. The new message content. The maximum amount of time a message is kept in the queue. Custom UTF8Encoder to throw exception in case of invalid bytes. Initializes a new instance of the class with the given byte array. Initializes a new instance of the class with the given string. The content of the message as a string of text. Initializes a new instance of the class with the given message ID and pop receipt. The message ID. The pop receipt token. Initializes a new instance of the class with the given Base64 encoded string. This method is only used internally. The text string. Whether the string is Base64 encoded. Gets the content of the message for transfer (internal use only). Indicates if the message should be encoded. The message content as a string. Sets the content of this message. The new message content. Gets the maximum message size in bytes. The maximum message size in bytes. Gets the maximum amount of time a message is kept in the queue. The maximum amount of time a message is kept in the queue. Gets the maximum number of messages that can be peeked at a time. The maximum number of messages that can be peeked at a time. Gets the content of the message as a byte array. The content of the message as a byte array. Gets the message ID. The message ID. Gets the message's pop receipt. The pop receipt value. Gets the time that the message was added to the queue. The time that the message was added to the queue. Gets the time that the message expires. The time that the message expires. Gets the time that the message will next be visible. The time that the message will next be visible. Gets the content of the message, as a string. The message content. Gets the number of times this message has been dequeued. The number of times this message has been dequeued. Gets message type that indicates if the RawString is the original message string or Base64 encoding of the original binary data. Gets or sets the original message string or Base64 encoding of the original binary data. The original message string. Provides a set of methods for parsing a response containing queue data from the Queue service. Gets the request ID from the response. The web response. A unique value associated with the request. Gets the approximate message count for the queue. The web response. The approximate count for the queue. Gets the user-defined metadata. The response from server. An object of type containing the metadata. Extracts the pop receipt from a web response header. The web response. The pop receipt stored in the header of the response. Extracts the next visibility time from a web response header. The web response. The time of next visibility stored in the header of the response. Reads service properties from a stream. The stream from which to read the service properties. The service properties stored in the stream. Reads service stats from a stream. The stream from which to read the service stats. The service stats stored in the stream. Reads the share access policies from a stream in XML. The stream of XML policies. The permissions object to which the policies are to be written. A factory class for constructing a web request to manage queues in the Queue service. Creates a web request to get the properties of the Queue service. The absolute URI to the Queue service. An object of type , containing additional parameters to add to the URI query string. The server timeout interval, in seconds. An object for tracking the current operation. A web request to get the Queue service properties. Creates a web request to set the properties of the Queue service. The absolute URI to the Queue service. An object of type , containing additional parameters to add to the URI query string. The server timeout interval, in seconds. An object for tracking the current operation. A web request to set the Queue service properties. Creates a web request to get the stats of the Queue service. The absolute URI to the Queue service. An object of type , containing additional parameters to add to the URI query string. The server timeout interval, in seconds. An object for tracking the current operation. A web request to get the Queue service stats. Writes Queue service properties to a stream, formatted in XML. The service properties to format and write to the stream. The stream to which the formatted properties are to be written. Constructs a web request to create a new queue. The absolute URI to the queue. The server timeout interval. An object for tracking the current operation. A web request to use to perform the operation. Constructs a web request to delete the queue and all of the messages within it. The absolute URI to the queue. The server timeout interval. An object for tracking the current operation. A web request to use to perform the operation. Constructs a web request to clear all messages in the queue. The absolute URI to the queue. The server timeout interval. An object for tracking the current operation. A web request to use to perform the operation. Generates a web request to return the user-defined metadata for this queue. The absolute URI to the queue. The server timeout interval. An object for tracking the current operation. A web request to use to perform the operation. Generates a web request to set user-defined metadata for the queue. The absolute URI to the queue. The server timeout interval. An object for tracking the current operation. A web request to use to perform the operation. Adds user-defined metadata to the request as one or more name-value pairs. The web request. The user-defined metadata. Adds user-defined metadata to the request as a single name-value pair. The web request. The metadata name. The metadata value. Constructs a web request to return a listing of all queues in this storage account. The absolute URI for the account. The server timeout interval. A set of parameters for the listing operation. Additional details to return with the listing. An object for tracking the current operation. A web request for the specified operation. Constructs a web request to return the ACL for a queue. The absolute URI to the queue. The server timeout interval. An object for tracking the current operation. A web request to use to perform the operation. Constructs a web request to set the ACL for a queue. The absolute URI to the queue. The server timeout interval. An object for tracking the current operation. A web request to use to perform the operation. Constructs a web request to add a message for a queue. The absolute URI to the queue. The server timeout interval. The message time-to-live, in seconds. The visibility timeout, in seconds. An object for tracking the current operation. A web request to use to perform the operation. Constructs a web request to update a message. The absolute URI to the message to update. The server timeout interval, in seconds. The pop receipt of the message. The length of time from now during which the message will be invisible, in seconds. An object for tracking the current operation. A web request for the update operation. Constructs a web request to update a message. The absolute URI to the message to update. The server timeout interval, in seconds. The pop receipt of the message. An object for tracking the current operation. A web request for the update operation. Constructs a web request to get messages for a queue. The absolute URI to the queue. The server timeout interval. The number of messages. The visibility timeout. An object for tracking the current operation. A web request to use to perform the operation. Constructs a web request to peeks messages for a queue. The absolute URI to the queue. The server timeout interval. The number of messages. An object for tracking the current operation. A web request to use to perform the operation. Represents a Windows Azure table. Represents a Windows Azure table. Executes the operation on a table, using the specified and . A object that represents the operation to perform. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. A containing the result of executing the operation on the table. Begins an asynchronous table operation. A object that represents the operation to perform. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous table operation using the specified and . A object that represents the operation to perform. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous table operation. An that references the pending asynchronous operation. A containing the result executing the operation on the table. Returns a task that performs an asynchronous table operation using the specified and . A object that represents the operation to perform. A object that represents the current operation. Returns a task that performs an asynchronous table operation using the specified and . A object that represents the operation to perform. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous table operation using the specified and . A object that represents the operation to perform. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. A object that represents the current operation. Returns a task that performs an asynchronous table operation using the specified and . A object that represents the operation to perform. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Executes a batch operation on a table as an atomic operation, using the specified and . The object representing the operations to execute on the table. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. An enumerable collection of objects that contains the results, in order, of each operation in the on the table. Begins an asynchronous operation to execute a batch of operations on a table. The object representing the operations to execute on the table. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to execute a batch of operations on a table, using the specified and . The object representing the operations to execute on the table. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous batch of operations on a table. An that references the pending asynchronous operation. A enumerable collection of type that contains the results, in order, of each operation in the on the table. Returns a task that performs an asynchronous operation to execute a batch of operations on a table, using the specified and . The object representing the operations to execute on the table. A object that represents the current operation. Returns a task that performs an asynchronous operation to execute a batch of operations on a table, using the specified and . The object representing the operations to execute on the table. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to execute a batch of operations on a table, using the specified and . The object representing the operations to execute on the table. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to execute a batch of operations on a table, using the specified and . The object representing the operations to execute on the table. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Executes a query on a table, using the specified and . A representing the query to execute. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. An enumerable collection of objects, representing table entities returned by the query. Executes a query in segmented mode with the specified continuation token, , and . A representing the query to execute. A object representing a continuation token from the server when the operation returns a partial result. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. A object containing the results of executing the query. Begins an asynchronous segmented query operation using the specified continuation token. A representing the query to execute. A object representing a continuation token from the server when the operation returns a partial result. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to query a table in segmented mode using the specified continuation token, , and . A representing the query to execute. A object representing a continuation token from the server when the operation returns a partial result. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous segmented query operation. An that references the pending asynchronous operation. A object containing the results of executing the query. Returns a task that performs an asynchronous operation to query a table in segmented mode using the specified continuation token, , and . A representing the query to execute. A object representing a continuation token from the server when the operation returns a partial result. A object that represents the current operation. Returns a task that performs an asynchronous operation to query a table in segmented mode using the specified continuation token, , and . A representing the query to execute. A object representing a continuation token from the server when the operation returns a partial result. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to query a table in segmented mode using the specified continuation token, , and . A representing the query to execute. A object representing a continuation token from the server when the operation returns a partial result. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to query a table in segmented mode using the specified continuation token, , and . A representing the query to execute. A object representing a continuation token from the server when the operation returns a partial result. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Executes a query on a table, using the specified and , applying the to the result. A representing the query to execute. An instance which creates a projection of the table query result entities into the specified type TResult. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. An enumerable collection, containing the projection into type TResult, of the results of executing the query. Executes a query in segmented mode with the specified continuation token, , and . A representing the query to execute. An instance which creates a projection of the table query result entities into the specified type TResult. A object representing a continuation token from the server when the operation returns a partial result. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. A object containing the results of executing the query. Begins an asynchronous segmented query operation using the specified continuation token. A representing the query to execute. An instance which creates a projection of the table query result entities into the specified type TResult. A object representing a continuation token from the server when the operation returns a partial result. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to execute a query in segmented mode with the specified continuation token, , and , applies the to the results. The type into which the will project the query results. A instance specifying the table to query and the query parameters to use, specialized for a type TElement. An instance which creates a projection of the table query result entities into the specified type TResult. A object representing a continuation token from the server when the operation returns a partial result. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Returns a task that performs an asynchronous operation to execute a query in segmented mode with the specified continuation token, , and , applies the to the results. The type into which the will project the query results. A instance specifying the table to query and the query parameters to use, specialized for a type TElement. An instance which creates a projection of the table query result entities into the specified type TResult. A object representing a continuation token from the server when the operation returns a partial result. A object that represents the current operation. Returns a task that performs an asynchronous operation to execute a query in segmented mode with the specified continuation token, , and , applies the to the results. The type into which the will project the query results. A instance specifying the table to query and the query parameters to use, specialized for a type TElement. An instance which creates a projection of the table query result entities into the specified type TResult. A object representing a continuation token from the server when the operation returns a partial result. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to execute a query in segmented mode with the specified continuation token, , and , applies the to the results. The type into which the will project the query results. A instance specifying the table to query and the query parameters to use, specialized for a type TElement. An instance which creates a projection of the table query result entities into the specified type TResult. A object representing a continuation token from the server when the operation returns a partial result. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to execute a query in segmented mode with the specified continuation token, , and , applies the to the results. The type into which the will project the query results. A instance specifying the table to query and the query parameters to use, specialized for a type TElement. An instance which creates a projection of the table query result entities into the specified type TResult. A object representing a continuation token from the server when the operation returns a partial result. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. A factory method that creates a query that can be modified using LINQ. The query may be subsequently executed using one of the execution methods available for , such as , , or . The entity type of the query. A object, specialized for type TElement, that may subsequently be executed. The namespace includes extension methods for the object, including , , and . To use these methods, include a using statement that references the namespace. Executes a query on a table, using the specified and . The entity type of the query. A TableQuery instance specifying the table to query and the query parameters to use, specialized for a type T implementing TableEntity. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. An enumerable collection, specialized for type TElement, of the results of executing the query. Queries a table in segmented mode using the specified continuation token, , and . The entity type of the query. A instance specifying the table to query and the query parameters to use, specialized for a type TElement. A object representing a continuation token from the server when the operation returns a partial result. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. A , specialized for type TElement, containing the results of executing the query. Begins an asynchronous operation to query a table in segmented mode, using the specified continuation token. The entity type of the query. A instance specifying the table to query and the query parameters to use, specialized for a type TElement. A object representing a continuation token from the server when the operation returns a partial result. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to query a table in segmented mode using the specified continuation token and . The entity type of the query. A instance specifying the table to query and the query parameters to use, specialized for a type TElement. A object representing a continuation token from the server when the operation returns a partial result. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous segmented table query operation. The type of the results to be returned. Can be the entity type specified in the Begin or the result type of the resolver An that references the pending asynchronous operation. A containing the results of executing the query. Returns a task that performs an asynchronous operation to query a table in segmented mode using the specified continuation token and . The entity type of the query. A instance specifying the table to query and the query parameters to use, specialized for a type TElement. A object representing a continuation token from the server when the operation returns a partial result. A object that represents the current operation. Returns a task that performs an asynchronous operation to query a table in segmented mode using the specified continuation token and . The entity type of the query. A instance specifying the table to query and the query parameters to use, specialized for a type TElement. A object representing a continuation token from the server when the operation returns a partial result. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to query a table in segmented mode using the specified continuation token and . The entity type of the query. A instance specifying the table to query and the query parameters to use, specialized for a type TElement. A object representing a continuation token from the server when the operation returns a partial result. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to query a table in segmented mode using the specified continuation token and . The entity type of the query. A instance specifying the table to query and the query parameters to use, specialized for a type TElement. A object representing a continuation token from the server when the operation returns a partial result. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Executes a query, using the specified and , applying the to the result. The entity type of the query. The type into which the will project the query results. A instance specifying the table to query and the query parameters to use, specialized for a type TElement. An instance which creates a projection of the table query result entities into the specified type TResult. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. An enumerable collection, containing the projection into type TResult, of the results of executing the query. Executes a query in segmented mode with the specified continuation token, using the specified and , applying the to the results. The entity type of the query. The type into which the will project the query results. A instance specifying the table to query and the query parameters to use, specialized for a type TElement. An instance which creates a projection of the table query result entities into the specified type TResult. A object representing a continuation token from the server when the operation returns a partial result. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. A containing the projection into type TResult of the results of executing the query. Begins an asynchronous operation to query a table in segmented mode, using the specified and continuation token. The entity type of the query. The type into which the will project the query results. A instance specifying the table to query and the query parameters to use, specialized for a type TElement. An instance which creates a projection of the table query result entities into the specified type TResult. A object representing a continuation token from the server when the operation returns a partial result. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to execute a query in segmented mode with the specified continuation token, , and , applies the to the results. The entity type of the query. The type into which the will project the query results. A instance specifying the table to query and the query parameters to use, specialized for a type TElement. An instance which creates a projection of the table query result entities into the specified type TResult. A object representing a continuation token from the server when the operation returns a partial result. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous segmented table query operation. The entity type of the query. The type into which the will project the query results. An that references the pending asynchronous operation. A containing the projection into type TResult of the results of executing the query. Returns a task that performs an asynchronous operation to execute a query in segmented mode with the specified continuation token, , and , applies the to the results. The entity type of the query. The type into which the will project the query results. A instance specifying the table to query and the query parameters to use, specialized for a type TElement. An instance which creates a projection of the table query result entities into the specified type TResult. A object representing a continuation token from the server when the operation returns a partial result. A object that represents the current operation. Returns a task that performs an asynchronous operation to execute a query in segmented mode with the specified continuation token, , and , applies the to the results. The entity type of the query. The type into which the will project the query results. A instance specifying the table to query and the query parameters to use, specialized for a type TElement. An instance which creates a projection of the table query result entities into the specified type TResult. A object representing a continuation token from the server when the operation returns a partial result. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to execute a query in segmented mode with the specified continuation token, , and , applies the to the results. The entity type of the query. The type into which the will project the query results. A instance specifying the table to query and the query parameters to use, specialized for a type TElement. An instance which creates a projection of the table query result entities into the specified type TResult. A object representing a continuation token from the server when the operation returns a partial result. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to execute a query in segmented mode with the specified continuation token, , and , applies the to the results. The entity type of the query. The type into which the will project the query results. A instance specifying the table to query and the query parameters to use, specialized for a type TElement. An instance which creates a projection of the table query result entities into the specified type TResult. A object representing a continuation token from the server when the operation returns a partial result. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Creates a table. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. Begins an asynchronous operation to create a table. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to create a table. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to create a table. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to create a table. A object that represents the current operation. Returns a task that performs an asynchronous operation to create a table. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to create a table. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to create a table. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Creates the table if it does not already exist. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. true if table was created; otherwise, false. Begins an asynchronous operation to create a table if it does not already exist. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to create a table if it does not already exist. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to determine whether a table exists. An that references the pending asynchronous operation. true if table exists; otherwise, false. Returns a task that performs an asynchronous operation to create a table if it does not already exist. A object that represents the current operation. Returns a task that performs an asynchronous operation to create a table if it does not already exist. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to create a table if it does not already exist. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to create a table if it does not already exist. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Deletes a table. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. Begins an asynchronous operation to delete a table. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to delete a table. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to delete a table. An that references the pending asynchronous operation. Returns a task that performs an asynchronous operation to delete a table. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete a table. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete a table. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete a table. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Deletes the table if it exists. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. true if the table was deleted; otherwise, false. Begins an asynchronous operation to delete the table if it exists. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to delete the table if it exists. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to delete the table if it exists. An that references the pending asynchronous operation. true if the table was deleted; otherwise, false. Returns a task that performs an asynchronous operation to delete the table if it exists. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete the table if it exists. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete the table if it exists. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to delete the table if it exists. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Checks whether the table exists. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. true if table exists; otherwise, false. Checks whether the table exists. If true, the command will be executed against the primary location. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. true if table exists; otherwise, false. Begins an asynchronous operation to determine whether a table exists. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to determine whether a table exists. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to determine whether a table exists. If true, the command will be executed against the primary location. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to determine whether a table exists. An that references the pending asynchronous operation. true if table exists; otherwise, false. Returns a task that performs an asynchronous operation to determine whether a table exists. A object that represents the current operation. Returns a task that performs an asynchronous operation to determine whether a table exists. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to determine whether a table exists. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to determine whether a table exists. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Gets the permissions settings for the table. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. The table's permissions. Begins an asynchronous request to get the permissions settings for the table. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to get the permissions settings for the table. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Returns the asynchronous result of the request to get the permissions settings for the table. An that references the pending asynchronous operation. The table's permissions. Returns a task that performs an asynchronous request to get the permissions settings for the table. A object that represents the current operation. Returns a task that performs an asynchronous request to get the permissions settings for the table. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous request to get the permissions settings for the table. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous request to get the permissions settings for the table. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Sets the permissions settings for the table. A object that represents the permissions to set. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. Begins an asynchronous request to set permissions for the table. The permissions to apply to the table. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous request to set permissions for the table. The permissions to apply to the table. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Returns the asynchronous result of the request to get the permissions settings for the table. An that references the pending asynchronous operation. Returns a task that performs an asynchronous request to set permissions for the table. The permissions to apply to the table. A object that represents the current operation. Returns a task that performs an asynchronous request to set permissions for the table. The permissions to apply to the table. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous request to set permissions for the table. The permissions to apply to the table. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous request to set permissions for the table. The permissions to apply to the table. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Initializes a new instance of the class. The absolute URI to the table. Initializes a new instance of the class. The absolute URI to the table. The account credentials. Initializes a new instance of the class. The absolute URI to the table. The account credentials. Initializes a new instance of the class. The table name. The client. Returns a shared access signature for the table. The access policy for the shared access signature. An access policy identifier. The start partition key, or null. The start row key, or null. The end partition key, or null. The end row key, or null. A shared access signature, as a URI query string. The query string returned includes the leading question mark. Thrown if the current credentials don't support creating a shared access signature. Returns the name of the table. The name of the table. Parse URI for SAS (Shared Access Signature) information. The complete Uri. The credentials to use. Gets the canonical name of the table, formatted as /<account-name>/<table-name>. The canonical name of the table. Gets the object that represents the Table service. A client object that specifies the Table service endpoint. Gets the table name. The table name. Gets the table's URI for the primary location. The absolute URI to the table, at the primary location. Gets the table's URIs for all locations. An object of type containing the table's URIs for all locations. Provides a client-side logical representation of the Windows Azure Table Service. This client is used to configure and execute requests against the Table Service. The service client encapsulates the base URI for the Table service. If the service client will be used for authenticated access, it also encapsulates the credentials for accessing the storage account. Provides a client-side logical representation of the Windows Azure Table service. This client is used to configure and execute requests against the Table service. The CloudTableClient object encapsulates the base URI for the Table service. If the service client will be used for authenticated access, it also encapsulates the credentials for accessing the storage account. Returns an enumerable collection of tables, which are retrieved lazily, that begin with the specified prefix. The table name prefix. A object that specifies additional options for the request. An object that provides information on how the operation executed. An enumerable collection of tables that are retrieved lazily. Returns an enumerable collection of tables in the storage account. A returned by a previous listing operation. An enumerable collection of tables. Returns an enumerable collection of tables, which are retrieved lazily, that begin with the specified prefix. The table name prefix. A returned by a previous listing operation. An enumerable collection of tables that are retrieved lazily. Returns an enumerable collection of tables that begin with the specified prefix and that are retrieved lazily. The table name prefix. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A returned by a previous listing operation. A object that specifies additional options for the request. An object that provides information on how the operation executed. An enumerable collection of tables that are retrieved lazily. Begins an asynchronous operation to return a result segment containing a collection of tables in the storage account. A returned by a previous listing operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to return a result segment containing a collection of tables beginning with the specified prefix. The table name prefix. A returned by a previous listing operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to return a result segment containing a collection of tables beginning with the specified prefix. The table name prefix. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A returned by a previous listing operation. The server timeout, maximum execution time, and retry policies for the operation. An object that provides information on how the operation executed. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to return a result segment containing a collection of tables. An that references the pending asynchronous operation. A result segment containing tables. Returns a task that performs an asynchronous operation to return a result segment containing a collection of tables beginning with the specified prefix. A returned by a previous listing operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to return a result segment containing a collection of tables beginning with the specified prefix. A returned by a previous listing operation. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to return a result segment containing a collection of tables beginning with the specified prefix. The table name prefix. A returned by a previous listing operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to return a result segment containing a collection of tables beginning with the specified prefix. The table name prefix. A returned by a previous listing operation. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to return a result segment containing a collection of tables beginning with the specified prefix. The table name prefix. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A returned by a previous listing operation. The server timeout, maximum execution time, and retry policies for the operation. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to return a result segment containing a collection of tables beginning with the specified prefix. The table name prefix. A non-negative integer value that indicates the maximum number of results to be returned at a time, up to the per-operation limit of 5000. If this value is null, the maximum possible number of results will be returned, up to 5000. A returned by a previous listing operation. The server timeout, maximum execution time, and retry policies for the operation. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Gets the service properties for the Table service. A object that specifies additional options for the request. An object that provides information on how the operation executed. The table service properties as a object. Begins an asynchronous operation to get the service properties of the Table service. The callback delegate that will receive notification when the asynchronous operation completes. A user defined object to be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to get the service properties of the Table service. A object that specifies additional options for the request. An object that provides information on how the operation executed. The callback delegate that will receive notification when the asynchronous operation completes. A user defined object to be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to get the service properties of the Table service. The result returned from a prior call to . The table service properties. Returns a task that performs an asynchronous operation to get the service properties of the Table service. A object that represents the current operation. Returns a task that performs an asynchronous operation to get the service properties of the Table service. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to get the service properties of the Table service. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to get the service properties of the Table service. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Sets the service properties of the Table service. The table service properties. A object that specifies additional options for the request. An object that provides information on how the operation executed. Begins an asynchronous operation to set the service properties of the Table service. The table service properties. The callback delegate that will receive notification when the asynchronous operation completes. A user defined object to be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to set the service properties of the Table service. The table service properties. A object that specifies additional options for the request. An object that provides information on how the operation executed. The callback delegate that will receive notification when the asynchronous operation completes. A user defined object to be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to set the service properties of the Table service. The result returned from a prior call to Returns a task that performs an asynchronous operation to set the service properties of the Table service. The table service properties. A object that represents the current operation. Returns a task that performs an asynchronous operation to set the service properties of the Table service. The table service properties. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to set the service properties of the Table service. The table service properties. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to set the service properties of the Table service. The table service properties. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Begins an asynchronous operation to get the stats of the table service. The callback delegate that will receive notification when the asynchronous operation completes. A user defined object to be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to get the stats of the table service. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user defined object to be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to get the stats of the table service. An that references the pending asynchronous operation. The table service stats. Returns a task that performs an asynchronous operation to get the stats of the table service. A object that represents the current operation. Returns a task that performs an asynchronous operation to get the stats of the table service. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to get the stats of the table service. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to get the stats of the table service. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Gets the stats of the table service. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. The table service stats. Creates a new object for performing operations against the Table service. A service context to use for performing operations against the Table service. The default server and client timeout interval. Max execution time across all potential retries. Initializes a new instance of the class using the specified Table service endpoint and anonymous credentials. The Table service endpoint to use to create the client. Initializes a new instance of the class using the specified Table service endpoint and storage account credentials. The Table service endpoint to use to create the client. The storage account credentials. Initializes a new instance of the class using the specified Blob service endpoint and account credentials. The Table service endpoint to use to create the client. The storage account credentials. Gets a reference to the specified table. The name of the table. A object. Gets or sets the authentication scheme to use to sign HTTP requests. Note that if you are using the legacy Table service API, which is based on WCF Data Services, the authentication scheme used by the TableServiceContext object will always be Shared Key Lite, regardless of the value of this property. Gets the authentication handler used to sign HTTP requests. The authentication handler. Gets or sets a buffer manager that implements the interface, specifying a buffer pool for use with operations against the Table service client. Gets the storage account credentials used to create the Table service client. The storage account credentials. Gets the base URI for the Table service client, at the primary location. The base URI used to construct the Table service client, at the primary location. Gets the Table service endpoints for all locations. An object of type containing Table service URIs for all locations. Gets or sets the default retry policy for requests made via the Table service client. The retry policy. Gets or sets the default location mode for requests made via the Table service client. The location mode. Gets or sets the default server and client timeout for requests. The server and client timeout interval. Gets or sets the maximum execution time across all potential retries. The maximum execution time across all potential retries. Gets and sets the that is used for any table accessed with this object. The TablePayloadFormat to use. Gets a value indicating whether the service client is used with Path style or Host style. Is true if use path style URIs; otherwise, false. Gets the associated account name for the client. The account name. Represents a custom attribute that can be used to ignore entity properties during serialization/de-serialization. Represents a batch operation on a table. Represents a batch operation on a table. A batch operation is a collection of table operations which are executed by the Storage Service REST API as a single atomic operation, by invoking an Entity Group Transaction.A batch operation may contain up to 100 individual table operations, with the requirement that each operation entity must have same partition key. A batch with a retrieve operation cannot contain any other operations. Note that the total payload of a batch operation is limited to 4MB. Inserts a into the batch that retrieves an entity based on its row key and partition key. The entity will be deserialized into the specified class type which extends . The class of type for the entity to retrieve. A string containing the partition key of the entity to retrieve. A string containing the row key of the entity to retrieve. Adds a table operation to retrieve an entity of the specified class type with the specified partition key and row key to the batch operation. The return type which the specified will resolve the given entity to. A string containing the partition key of the entity to retrieve. A string containing the row key of the entity to retrieve. The implementation to project the entity to retrieve as a particular type in the result. Initializes a new instance of the class. Adds a to the that deletes the specified entity from a table. The entity to be deleted from the table. Adds a to the that inserts the specified entity into a table. The entity to be inserted into the table. Adds a object that inserts the specified entity into the table as part of the batch operation. The entity to be inserted into the table. true if the message payload should be returned in the response to the insert operation;otherwise, false. Adds a to the that inserts the specified entity into a table if the entity does not exist; if the entity does exist then its contents are merged with the provided entity. The entity whose contents are being inserted or merged. Adds a to the that inserts the specified entity into a table if the entity does not exist; if the entity does exist then its contents are replaced with the provided entity. The entity whose contents are being inserted or replaced. Adds a to the that merges the contents of the specified entity with the existing entity in a table. The entity whose contents are being merged. Adds a to the that replaces the contents of the specified entity in a table. The entity whose contents are being replaced. Adds a to the that retrieves an entity with the specified partition key and row key. A string containing the partition key of the entity to retrieve. A string containing the row key of the entity to retrieve. Returns the zero-based index of the first occurrence of the specified item, or -1 if the does not contain the item. The item to search for. The zero-based index of the first occurrence of item within the , if found; otherwise, –1. Inserts a into the at the specified index. The index at which to insert the . The item to insert. Removes the at the specified index from the . The index of the to remove from the . Adds the to the . The item to add to the . Clears all objects from the . Returns true if this contains the specified element. The item to search for. true if the item is contained in the ; false, otherwise. Copies all the elements of the to the specified one-dimensional array starting at the specified destination array index. The one-dimensional array that is the destination of the elements copied from the . The index in the destination array at which copying begins. Removes the specified item from the . The item to remove. true if the item was successfully removed; false, otherwise. Returns an for the . An enumerable collection of items. Returns an . An for the . Gets or sets the item at the specified index. The index at which to get or set the item. The item at the specified index. Gets the number of operations in this . The number of operations in the . Gets a value indicating whether the is read-only. true if the is read-only; false, otherwise. Represents a single table operation. Represents a single table operation. Creates a new table operation that retrieves the contents of the given entity in a table. The class of type for the entity to retrieve. A string containing the partition key of the entity to retrieve. A string containing the row key of the entity to retrieve. The object. Creates a new table operation that retrieves the contents of the given entity in a table. The return type which the specified will resolve the given entity to. A string containing the partition key of the entity to retrieve. A string containing the row key of the entity to retrieve. The implementation to project the entity to retrieve as a particular type in the result. The object. Creates a new instance of the class given the entity to operate on and the type of operation that is being performed. The entity on which the operation is being performed. The type of operation. Creates a new table operation that deletes the given entity from a table. The entity to be deleted from the table. The object. Creates a new table operation that inserts the given entity into a table. The entity to be inserted into the table. The object. Creates a new table operation that inserts the given entity into a table. The entity to be inserted into the table. true if the message payload should be returned in the response to the insert operation. false otherwise. The table operation. Creates a new table operation that inserts the given entity into a table if the entity does not exist; if the entity does exist then its contents are merged with the provided entity. The entity whose contents are being inserted or merged. The object. Creates a new table operation that inserts the given entity into a table if the entity does not exist; if the entity does exist then its contents are replaced with the provided entity. The entity whose contents are being inserted or replaced. The object. Creates a new table operation that merges the contents of the given entity with the existing entity in a table. The entity whose contents are being merged. The object. Creates a new table operation that replaces the contents of the given entity in a table. The entity whose contents are being replaced. The object. Creates a new table operation that replaces the contents of the given entity in a table. The partition key of the entity to be replaced. The row key of the entity to be replaced. The object. Gets the entity that is being operated upon. Gets the type of operation. Gets or sets the value that represents whether the message payload should be returned in the response. Represents a query against a Windows Azure table. A class which implements . Represents a query against a specified table. Initializes a new instance of the class. Executes a query on a table, using the specified and . A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. An enumerable collection, specialized for type TElement, of the results of executing the query. Begins an asynchronous operation to execute a query and return the results as a result segment. A continuation token returned by a previous listing operation, can be null. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to execute a query and return the results as a result segment. A continuation token returned by a previous listing operation, can be null. An object for tracking the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An that references the asynchronous operation. Ends an asynchronous operation to execute a query and return the results as a result segment. The reference to the pending asynchronous request to finish. A result segment containing objects of type . Begins an asynchronous operation to execute a query and return the results as a result segment. A continuation token returned by a previous listing operation, can be null. A of object that represents the current operation. Begins an asynchronous operation to execute a query and return the results as a result segment. A continuation token returned by a previous listing operation, can be null./// A to observe while waiting for a task to complete. A of object that represents the current operation. Begins an asynchronous operation to execute a query and return the results as a result segment. A continuation token returned by a previous listing operation, can be null. An object for tracking the current operation. A object that specifies execution options, such as retry policy and timeout settings, for the operation. A of object that represents the current operation. Begins an asynchronous operation to execute a query and return the results as a result segment. A continuation token returned by a previous listing operation, can be null. An object for tracking the current operation. A object that specifies execution options, such as retry policy and timeout settings, for the operation. A to observe while waiting for a task to complete. A of object that represents the current operation. Queries a table in segmented mode using the specified continuation token, , and . A object representing a continuation token from the server when the operation returns a partial result. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object for tracking the current operation. A , specialized for type TElement, containing the results of executing the query. Returns an enumerator that iterates through the . An for the . Generates a property filter condition string for the string value. A string containing the name of the property to compare. A string containing the comparison operator to use. A string containing the value to compare with the property. A string containing the formatted filter condition. Generates a property filter condition string for the boolean value. A string containing the name of the property to compare. A string containing the comparison operator to use. A bool containing the value to compare with the property. A string containing the formatted filter condition. Generates a property filter condition string for the binary value. A string containing the name of the property to compare. A string containing the comparison operator to use. A byte array containing the value to compare with the property. A string containing the formatted filter condition. Generates a property filter condition string for the value. A string containing the name of the property to compare. A string containing the comparison operator to use. A containing the value to compare with the property. A string containing the formatted filter condition. Generates a property filter condition string for the value. A string containing the name of the property to compare. A string containing the comparison operator to use. A containing the value to compare with the property. A string containing the formatted filter condition. Generates a property filter condition string for the value. A string containing the name of the property to compare. A string containing the comparison operator to use. A containing the value to compare with the property. A string containing the formatted filter condition. Generates a property filter condition string for the value. A string containing the name of the property to compare. A string containing the comparison operator to use. A containing the value to compare with the property. A string containing the formatted filter condition. Generates a property filter condition string for the value. A string containing the name of the property to compare. A string containing the comparison operator to use. A containing the value to compare with the property. A string containing the formatted filter condition. Generates a property filter condition string for the value, formatted as the specified . A string containing the name of the property to compare. A string containing the comparison operator to use. A string containing the value to compare with the property. The to format the value as. A string containing the formatted filter condition. Creates a filter condition using the specified logical operator on two filter conditions. A string containing the first formatted filter condition. A string containing Operators.AND or Operators.OR. A string containing the second formatted filter condition. A string containing the combined filter expression. Defines the property names of the table entity properties to return when the table query is executed. The select clause is optional on a table query, used to limit the table properties returned from the server. By default, a query will return all properties from the table entity. A list of string objects containing the property names of the table entity properties to return when the query is executed. A instance set with the table entity properties to return. Defines the upper bound for the number of entities the query returns. The maximum number of entities for the table query to return. A instance set with the number of entities to return. Defines a filter expression for the table query. Only entities that satisfy the specified filter expression will be returned by the query. Setting a filter expression is optional; by default, all entities in the table are returned if no filter expression is specified in the table query. A string containing the filter expression to apply to the table query. A instance set with the filter on entities to return. Gets the type of the element(s) that are returned when the expression tree is executed. Gets the expression tree. Gets the query provider that is associated with this data source. Gets or sets the number of entities the query returns specified in the table query. The maximum number of entities for the table query to return. Gets or sets the filter expression to use in the table query. A string containing the filter expression to use in the query. Gets or sets the property names of the table entity properties to return when the table query is executed. A list of strings containing the property names of the table entity properties to return when the query is executed. Represents a query against a specified table. The class aggregates and encodes the query parameters to pass with the request when the query is executed. To execute the query, call the executeQuery or executeQuerySegmented method of the class. Represents a query against a specified table. A instance aggregates the query parameters to use when the query is executed. One of the executeQuery or executeQuerySegmented methods of must be called to execute the query. The parameters are encoded and passed to the server when the table query is executed. Specifies the names of the entity properties to return when the query is executed against the table. The Project clause is optional on a query, used to limit the properties returned from the server. By default, a query will return all properties from the entity. The entity type of the query. The entity instance to project off of. A list of string objects containing the names of the entity properties to return when the query is executed. A instance set with the entity properties to return. Generates a property filter condition string for the string value. A string containing the name of the property to compare. A string containing the comparison operator to use. A string containing the value to compare with the property. A string containing the formatted filter condition. Generates a property filter condition string for the boolean value. A string containing the name of the property to compare. A string containing the comparison operator to use. A bool containing the value to compare with the property. A string containing the formatted filter condition. Generates a property filter condition string for the binary value. A string containing the name of the property to compare. A string containing the comparison operator to use. A byte array containing the value to compare with the property. A string containing the formatted filter condition. Generates a property filter condition string for the value. A string containing the name of the property to compare. A string containing the comparison operator to use. A containing the value to compare with the property. A string containing the formatted filter condition. Generates a property filter condition string for the value. A string containing the name of the property to compare. A string containing the comparison operator to use. A containing the value to compare with the property. A string containing the formatted filter condition. Generates a property filter condition string for the value. A string containing the name of the property to compare. A string containing the comparison operator to use. A containing the value to compare with the property. A string containing the formatted filter condition. Generates a property filter condition string for the value. A string containing the name of the property to compare. A string containing the comparison operator to use. A containing the value to compare with the property. A string containing the formatted filter condition. Generates a property filter condition string for the value. A string containing the name of the property to compare. A string containing the comparison operator to use. A containing the value to compare with the property. A string containing the formatted filter condition. Generates a property filter condition string for the value, formatted as the specified . A string containing the name of the property to compare. A string containing the comparison operator to use. A string containing the value to compare with the property. The to format the value as. A string containing the formatted filter condition. Creates a filter condition using the specified logical operator on two filter conditions. A string containing the first formatted filter condition. A string containing Operators.AND or Operators.OR. A string containing the second formatted filter condition. A string containing the combined filter expression. Defines the property names of the table entity properties to return when the table query is executed. The select clause is optional on a table query, used to limit the table properties returned from the server. By default, a query will return all properties from the table entity. A list of string objects containing the property names of the table entity properties to return when the query is executed. A instance set with the table entity properties to return. Defines the upper bound for the number of entities the query returns. The maximum number of entities for the table query to return. A instance set with the number of entities to return. Defines a filter expression for the table query. Only entities that satisfy the specified filter expression will be returned by the query. Setting a filter expression is optional; by default, all entities in the table are returned if no filter expression is specified in the table query. A string containing the filter expression to apply to the table query. A instance set with the filter on entities to return. Gets or sets the number of entities the table query will return. The maximum number of entities for the table query to return. Gets or sets the filter expression to use in the table query. A string containing the filter expression to use in the query. Gets or sets the property names of the table entity properties to return when the table query is executed. A list of strings containing the property names of the table entity properties to return when the query is executed. Represents the default EDM entity container for table storage. Initializes a new instance of the EdmEntityContainer class and sets the model and entity set. The name and namespace should not matter since we look for default entity container. Sets the data model that will be used for table transactions. Searches for an entity set with the given name in this entity container and creates a new set if no such set exists. The name of the element being found. The requested element, or the new element created if no such element exists. Represents a data model that will be used by OData for table transactions. Initializes a new instance of the class. Initializes a new instance of the class. Searches for a type with the given name in this model and creates a new type if no such type exists. The qualified name of the type being found. The requested type, or the new type created if no such type exists. Create a new type with the standard set of properties(PK, RK and TimeStamp). Namespace the entity belongs to. Name of the entity. The EdmEntityType created. Searches for a type with the given name in this model. Returns true if such a type is found, otherwise returns false. The qualified name of the type being found. true if the type is found; otherwise, false. Represents a object for use with the Windows Azure Table service. The class does not support concurrent queries or requests. Initializes a new instance of the class. Callback on DataContext object sending request. The sender. The instance containing the event data. Saves changes, using the retry policy specified for the service context. A that represents the result of the operation. Saves changes, using the retry policy specified for the service context. Additional options for saving changes. A that represents the result of the operation. Begins an asynchronous operation to save changes, using the retry policy specified for the service context. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to save changes, using the retry policy specified for the service context. Additional options for saving changes. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to save changes, using the retry policy specified for the service context. Additional options for saving changes. An object for tracking the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to save changes. An that references the pending asynchronous operation. A that represents the result of the operation. Returns a object that performs an asynchronous operation to save changes, using the retry policy specified for the service context. A object that represents the current operation. Returns a object that performs an asynchronous operation to save changes, using the retry policy specified for the service context. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a object that performs an asynchronous operation to save changes, using the retry policy specified for the service context. Additional options for saving changes. A object that represents the current operation. Returns a object that performs an asynchronous operation to save changes, using the retry policy specified for the service context. Additional options for saving changes. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a object that performs an asynchronous operation to save changes, using the retry policy specified for the service context. Additional options for saving changes. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A object that represents the current operation. Returns a object that performs an asynchronous operation to save changes, using the retry policy specified for the service context. Additional options for saving changes. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Releases all resources used by the TableServiceContext. Releases the unmanaged resources used by the TableServiceContext and optionally releases the managed resources. true to release both managed and unmanaged resources; false to release only unmanaged resources. Gets the object that represents the Table service. A client object that specifies the Table service endpoint. Gets the authentication handler used to sign HTTP requests. The authentication handler. Represents an entity in the Windows Azure Table service. Initializes a new instance of the class. The partition key. The row key. Initializes a new instance of the class. Gets or sets the timestamp for the entity. The entity's timestamp. Gets or sets the partition key of a table entity. The partition key. Gets or sets the row key of a table entity. The row key. Provides a set of extensions for the Table service. Converts the query into a object that supports additional operations like retries. The type of the element. The query. A object that represents the runtime context of the Table service. The converted query. A class for constructing a query against the Table service. The type of the element. Initializes a new instance of the class. An object that implements . A object. Expands the specified path. The path to expand. A new query with the expanded path. Returns an enumerator that iterates through the collection. A that can be used to iterate through the collection. Executes the request with any specified options. An object of type . An object for tracking the current operation. An enumerable collection, specialized for type TElement, of the results of executing the query. Executes a segmented query against the Table service. The continuation token. The request options. An object for tracking the current operation. A result segment containing objects of type . Begins an asynchronous operation to execute a query and return the results as a result segment. A continuation token returned by a previous listing operation, can be null. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Begins an asynchronous operation to execute a query and return the results as a result segment. A continuation token returned by a previous listing operation, can be null. A object that specifies additional options for the request. An object that represents the context for the current operation. The callback delegate that will receive notification when the asynchronous operation completes. A user-defined object that will be passed to the callback delegate. An that references the asynchronous operation. Ends an asynchronous operation to execute a query and return the results as a result segment. The reference to the pending asynchronous request to finish. A result segment containing objects of type . Returns a task that performs an asynchronous operation to execute a query and return the results as a result segment. A continuation token returned by a previous listing operation, can be null. A object that represents the current operation. Returns a task that performs an asynchronous operation to execute a query and return the results as a result segment. A continuation token returned by a previous listing operation, can be null. A to observe while waiting for a task to complete. A object that represents the current operation. Returns a task that performs an asynchronous operation to execute a query and return the results as a result segment. A continuation token returned by a previous listing operation, can be null. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A object that represents the current operation. Returns a task that performs an asynchronous operation to execute a query and return the results as a result segment. A continuation token returned by a previous listing operation, can be null. A object that specifies execution options, such as retry policy and timeout settings, for the operation. An object that represents the context for the current operation. A to observe while waiting for a task to complete. A object that represents the current operation. Gets the table service context. An object of type . Stores the wrapped . Gets the type of the element(s) that are returned when the expression tree associated with this instance of is executed. A that represents the type of the element(s) that are returned when the expression tree associated with this object is executed. Gets the expression tree that is associated with the instance of . The that is associated with this instance of . Gets the query provider that is associated with this data source. The that is associated with this data source. A factory class for constructing a web request to manage tables in the Table service. Creates a web request to get the properties of the Table service. The absolute URI to the Table service. An object of type , containing additional parameters to add to the URI query string. The server timeout interval, in seconds. An object for tracking the current operation. A web request to get the Table service properties. Creates a web request to set the properties of the Table service. The absolute URI to the Table service. An object of type , containing additional parameters to add to the URI query string. The server timeout interval, in seconds. An object for tracking the current operation. A web request to set the Table service properties. Creates a web request to get the stats of the Table service. The absolute URI to the Table service. An object of type , containing additional parameters to add to the URI query string. The server timeout interval, in seconds. An object for tracking the current operation. A web request to get the Table service stats. Writes Table service properties to a stream, formatted in XML. The service properties to format and write to the stream. The stream to which the formatted properties are to be written. Constructs a web request to return the ACL for a table. The absolute URI to the table. An object of type , containing additional parameters to add to the URI query string. The server timeout interval. An object for tracking the current operation. A web request to use to perform the operation. Constructs a web request to set the ACL for a table. The absolute URI to the table. An object of type , containing additional parameters to add to the URI query string. The server timeout interval. An object for tracking the current operation. A web request to use to perform the operation. Provides a set of methods for parsing a response stream from the Table service. Gets the request ID from the response. The web response. A unique value associated with the request. Reads service properties from a stream. The stream from which to read the service properties. The service properties stored in the stream. Reads service stats from a stream. The stream from which to read the service stats. The service stats stored in the stream. Reads the share access policies from a stream in XML. The stream of XML policies. The permissions object to which the policies are to be written. Gets the table continuation from response. The response. The continuation. Translates the data service exception. The exception. The request result. The delegate used to parse the error to get extended error information. The translated exception. Look for an inner exception of type T. The exception. The found exception or null. Applies the continuation to query. The continuation token. The local query. The modified query. Gets the query take count. The type of the element. The query. The default value. The take count of the query, if any. Gets the table continuation from response. The response. The continuation. Copies the headers and properties from a request into a different request. The request to copy into. The request to copy from. Gets an ETag from a response. The web response. A quoted ETag string. Gets the user-defined metadata. The response from server. A of the metadata. Gets the metadata or properties. The response from server. The prefix for all the headers. A of the headers with the prefix. Converts a string to UTC time. The string to convert. A UTC representation of the string. Reads service properties from a stream. The stream from which to read the service properties. The service properties stored in the stream. Reads service stats from a stream. The stream from which to read the service stats. The service stats stored in the stream. Reads a collection of shared access policies from the specified object. A collection of shared access policies to be filled. A policy response object for reading the stream. The type of policy to read. Creates the web request. The HTTP method. The request URI. The timeout. An object of type , containing additional parameters to add to the URI query string. An object for tracking the current operation. A web request for performing the operation. Creates the specified URI. The URI to create. The timeout. The builder. An object for tracking the current operation. A web request for performing the operation. Constructs a web request to return the ACL for a cloud resource. The absolute URI to the resource. The server timeout interval. An optional query builder to use. An object for tracking the current operation. A web request to use to perform the operation. Constructs a web request to set the ACL for a cloud resource. The absolute URI to the resource. The server timeout interval. An optional query builder to use. An object for tracking the current operation. A web request to use to perform the operation. Gets the properties. The URI to query. The timeout. The builder. An object for tracking the current operation. A web request for performing the operation. Gets the metadata. The blob Uri. The timeout. The builder. An object for tracking the current operation. A web request for performing the operation. Sets the metadata. The blob Uri. The timeout. The builder. An object for tracking the current operation. A web request for performing the operation. Adds the metadata. The request. The metadata. Adds the metadata. The request. The metadata name. The metadata value. Deletes the specified URI. The URI of the resource to delete. The timeout. The builder. An object for tracking the current operation. A web request for performing the operation. Creates a web request to get the properties of the service. The absolute URI to the service. An object of type , containing additional parameters to add to the URI query string. The server timeout interval. An object for tracking the current operation. A web request to get the service properties. Creates a web request to set the properties of the service. The absolute URI to the service. The builder. The server timeout interval. An object for tracking the current operation. A web request to set the service properties. Creates a web request to get the stats of the service. The absolute URI to the service. An object of type , containing additional parameters to add to the URI query string. The server timeout interval. An object for tracking the current operation. A web request to get the service stats. Generates a query builder for building service requests. A for building service requests. Adds the lease id. The request. The lease id. Adds an optional header to a request. The web request. The metadata name. The metadata value. Adds an optional header to a request. The web request. The header name. The header value. Adds an optional header to a request. The web request. The header name. The header value. Applies the lease condition to the web request. The request to be modified. Access condition to be added to the request. Applies the sequence number condition to the web request. The request to be modified. Access condition to be added to the request. Applies the condition to the web request. The request to be modified. Access condition to be added to the request. Applies the condition for a source blob to the web request. The request to be modified. Access condition to be added to the request. Creates a well-formatted log entry so that logs can be easily parsed An object that represents the context for the current operation. A composite format string. An object array that contains zero or more objects to format. Log entry that contains common log prefix and a copy of format in which the format items have been replaced by the string representation of the corresponding objects in args. Determines if the current operation context allows for a specific level of log entry. Level of the log entry. An object that represents the context for the current operation. true if the entry should be logged; otherwise false. Represents a canonicalizer that converts HTTP request data into a standard form appropriate for signing. For detailed information on how to authenticate a request, see Authentication for the Windows Azure Storage Services. Converts the specified HTTP request data into a standard form appropriate for signing. The HTTP request that needs to be signed. The name of the storage account that the HTTP request will access. The canonicalized string containing the HTTP request data in a standard form appropriate for signing. Authentication for the Windows Azure Storage Services Gets the authorization scheme used for canonicalization. The authorization scheme used for canonicalization. Authentication for the Windows Azure Storage Services Represents a canonicalizer that converts HTTP request data into a standard form appropriate for signing via the Shared Key authentication scheme for the Blob or Queue service. Authentication for the Windows Azure Storage Services Converts the specified HTTP request data into a standard form appropriate for signing. The HTTP request that needs to be signed. The name of the storage account that the HTTP request will access. The canonicalized string containing the HTTP request data in a standard form appropriate for signing. Authentication for the Windows Azure Storage Services Gets a static instance of the object. The static instance of the class. Authentication for the Windows Azure Storage Services Gets the authorization scheme used for canonicalization. The authorization scheme used for canonicalization. Authentication for the Windows Azure Storage Services Represents a canonicalizer that converts HTTP request data into a standard form appropriate for signing via the Shared Key Lite authentication scheme for the Blob or Queue service. Authentication for the Windows Azure Storage Services Converts the specified HTTP request data into a standard form appropriate for signing. The HTTP request that needs to be signed. The name of the storage account that the HTTP request will access. The canonicalized string containing the HTTP request data in a standard form appropriate for signing. Authentication for the Windows Azure Storage Services Gets a static instance of the object. The static instance of the class. Authentication for the Windows Azure Storage Services Gets the authorization scheme used for canonicalization. The authorization scheme used for canonicalization. Authentication for the Windows Azure Storage Services Represents a canonicalizer that converts HTTP request data into a standard form appropriate for signing via the Shared Key Lite authentication scheme for the Table service. Authentication for the Windows Azure Storage Services Converts the specified HTTP request data into a standard form appropriate for signing. The HTTP request that needs to be signed. The name of the storage account that the HTTP request will access. The canonicalized string containing the HTTP request data in a standard form appropriate for signing. Authentication for the Windows Azure Storage Services Gets a static instance of the object. The static instance of the class. Authentication for the Windows Azure Storage Services Gets the authorization scheme used for canonicalization. The authorization scheme used for canonicalization. Authentication for the Windows Azure Storage Services Represents a canonicalizer that converts HTTP request data into a standard form appropriate for signing via the Shared Key authentication scheme for the Table service. Authentication for the Windows Azure Storage Services Converts the specified HTTP request data into a standard form appropriate for signing. The HTTP request that needs to be signed. The name of the storage account that the HTTP request will access. The canonicalized string containing the HTTP request data in a standard form appropriate for signing. Authentication for the Windows Azure Storage Services Gets a static instance of the object. The static instance of the class. Authentication for the Windows Azure Storage Services Gets the authorization scheme used for canonicalization. The authorization scheme used for canonicalization. Authentication for the Windows Azure Storage Services Helper class to allow an APM Method to be executed with a given timeout in milliseconds Helper class to convert an APM method to a Task method. This class provides asynchronous semaphore functionality (based on Stephen Toub's blog). Creates and initializes a new asynchronous copy operation. The source stream. The destination stream. An ExecutionState used to coordinate copy operation. Size of read and write buffers used to move data. Boolean value indicating whether the MD-5 should be calculated. An object that represents the state for the current operation. Begins a stream copy operation. Callback delegate Number of bytes to copy from source stream to destination stream. Cannot be passed with a value for maxLength. Maximum length of the source stream. Cannot be passed with a value for copyLength. Aborts an ongoing copy operation. Cleans up references. To end a copy operation, use Abort(). Synchronizes Read and Write operations, and handles exceptions. Read/Write operation or null if first run. Helper method for EndOpWithCatch(IAsyncResult). Begins/Ends Read and Write Stream operations. Should only be called by EndOpWithCatch(IAsyncResult) since it assumes we are inside the lock. Read/Write operation or null if first run. Callback for timeout timer. Aborts the AsyncStreamCopier operation if a timeout occurs. AsyncStreamCopier operation. True if the timer has timed out, false otherwise. Aborts the AsyncStreamCopier operation. AsyncStreamCopier operation. True if aborted due to a time out, or false for a general cancellation. Terminates and cleans up the AsyncStreamCopier. Helper method for this.SignalCompletion() Should only be called by this.SignalCompletion() Determines whether the next operation should begin or halt due to an exception or cancellation. True to continue, false to halt. Waits for a read operation to end and updates the AsyncStreamCopier state. Waits for a write operation to end and updates the AsyncStreamCopier state. If a read operation has completed with data, swaps the read/write buffers and resets their corresponding counts. This must be called inside a lock as it could lead to undefined behavior if multiple unsynchronized callers simultaneously called in. Number of bytes to write, or negative if no read operation has completed. Determines the number of bytes that should be read from the source in the next BeginRead operation. Should only be called when no outstanding read operations exist. Number of bytes to read. Determines whether no more data can be read from the source Stream. True if at the end, false otherwise. Determines whether the current read buffer contains data ready to be written. True if read buffer is full, false otherwise. Represents an operation that supports cancellation. Used by ICancellableAsyncResult implementations throughout the library. Also used by AsyncExtensions as a bridge between CancellationToken and the ICancellableAsyncResult returned by an APM method call. The class is provides the helper functions to do FISMA compliant MD5. Cryptographic service provider. Access to the private keys is not required and the user interface can be bypassed. ALG_ID value that identifies the hash algorithm to use. The hash value or message hash for the hash object specified by hashHandle. The address to which the function copies a handle to the new hash object. Has to be released by calling the CryptDestroyHash function after we are finished using the hash object. A handle to a CSP created by a call to CryptAcquireContext. Whether this object has been torn down or not. Initializes a new instance of NativeMD5. Finalizes an instance of the NativeMD5 class, unhooking it from all events. Initializes an implementation of the NativeMD5 class. Routes data written to the object into the hash algorithm for computing the hash. The input to compute the hash code for. The offset into the byte array from which to begin using data. The number of bytes in the byte array to use as data. Finalizes the hash computation after the last data is processed by the cryptographic stream object. The computed hash code. Releases the unmanaged resources used by the NativeMD5. true to release both managed and unmanaged resources; false to release only unmanaged resources. Validates the status returned by all the crypto functions and throws exception per the return code. The boolean status returned by the crypto functions. Represents the async result returned by operations that do not directly call into the Executor. Async operation's result type Represents the async result returned by a storage command. The callback provided by the user. The state for the callback. Indicates whether a task is completed. Indicates whether task completed synchronously. The event for blocking on this task's completion. Initializes a new instance of the StorageCommandAsyncResult class. The callback method to be used on completion. The state for the callback. We implement the dispose only to allow the explicit closing of the event. Releases unmanaged and - optionally - managed resources. Set to true to release both managed and unmanaged resources; false to release only unmanaged resources. Provides the lazy initialization of the WaitHandle (based on Joe Duffy's blog). The WaitHandle to use for waiting on completion. Called on completion of the async operation to notify the user (Based on Joe Duffy's lockless design). Blocks the calling thread until the async operation is completed. Updates the CompletedSynchronously flag with another asynchronous operation result. Set to true if the last operation was completed synchronously; false if it was completed asynchronously. Gets A user-defined object that contains information about the asynchronous operation. Gets a System.Threading.WaitHandle that is used to wait for an asynchronous operation to complete. Gets a value indicating whether the asynchronous operation completed synchronously. Gets a value indicating whether the asynchronous operation has completed. Initializes a new instance of the StorageAsyncResult class. The callback method to be used on completion. The state for the callback. Called on completion of the async operation to notify the user Exception that was caught by the caller. Blocks the calling thread until the async operation is completed and throws any stored exceptions. Represents a set of access conditions to be used for operations against the storage services. Time for IfModifiedSince. Time for IfUnmodifiedSince. Constructs an empty access condition. An empty access condition. Constructs an access condition such that an operation will be performed only if the resource's ETag value matches the specified ETag value. The ETag value that must be matched. An AccessCondition object that represents the If-Match condition. Constructs an access condition such that an operation will be performed only if the resource has been modified since the specified time. The time since which the resource must have been modified in order for the operation to proceed. An AccessCondition object that represents the If-Modified-Since condition. Constructs an access condition such that an operation will be performed only if the resource's ETag value does not match the specified ETag value. The ETag value that must be matched, or "*". An AccessCondition object that represents the If-None-Match condition. If "*" is specified as the parameter then this condition requires that the resource does not exist. Constructs an access condition such that an operation will be performed only if the resource has not been modified since the specified time. The time since which the resource must not have been modified in order for the operation to proceed. An AccessCondition object that represents the If-Unmodified-Since condition. Constructs an access condition such that an operation will be performed only if resource's current sequence number is less than or equal to the specified value. The value that the current sequence number of the resource must be less than or equal to. An AccessCondition object that represents the If-Sequence-Number-LE condition. Constructs an access condition such that an operation will be performed only if resource's current sequence number is less than the specified value. The value that the current sequence number of the resource must be less than. An AccessCondition object that represents the If-Sequence-Number-LT condition. Constructs an access condition such that an operation will be performed only if resource's current sequence number is equal to the specified value. The value that the current sequence number of the resource must be equal to. An AccessCondition object that represents the If-Sequence-Number-EQ condition. Constructs an access condition such that an operation will be performed only if the lease ID on the resource matches the specified lease ID. The lease ID that must match the lease ID of the resource. An AccessCondition object that represents the lease condition. Constructs an access condition such that an operation will be performed only if the resource's ETag value matches the specified ETag value and the lease ID on the resource matches the lease ID specified in the given access condition. An AccessCondition object that represents the lease condition. The ETag value that must be matched. An AccessCondition object that represents the If-Match and the lease conditions. Gets or sets an ETag value that must match the ETag of the specified resource. A string containing an ETag value, or "*" to match any ETag. If null, no condition exists. Gets or sets an ETag value that must not match the ETag of the specified resource. A string containing an ETag value, or "*" to match any ETag. If null, no condition exists. Gets or sets a time that must be before the last modification of a resource. A DateTimeOffset in UTC, or null if no condition exists. Gets or sets a time that must not be before the last modification of a resource. A DateTimeOffset in UTC, or null if no condition exists. Gets or sets a sequence number that the current sequence number of a page blob must be less than or equal to in order for the operation to proceed. A sequence number, or null if no condition exists. This condition only applies to page blobs. Gets or sets a sequence number that the current sequence number of a page blob must be less than in order for the operation to proceed. A sequence number, or null if no condition exists. This condition only applies to page blobs. Gets or sets a sequence number that the current sequence number of a page blob must be equal to in order for the operation to proceed. A sequence number, or null if no condition exists. This condition only applies to page blobs. Gets or sets a lease ID that must match the lease on a resource. A lease ID, or null if no condition exists. Determines whether the access condition is one of the four conditional headers. true if the access condition is a conditional header; otherwise, false. Specifies the authentication scheme used to sign HTTP requests. Signs HTTP requests using the Shared Key Lite authentication scheme. Signs HTTP requests using the Shared Key authentication scheme. Represents a Windows Azure Storage account. The setting name for using the development storage. The setting name for specifying a development storage proxy Uri. The setting name for using the default storage endpoints with the specified protocol. The setting name for the account name. The setting name for the account key name. The setting name for the account key. The setting name for a custom blob storage endpoint. The setting name for a custom queue endpoint. The setting name for a custom table storage endpoint. The setting name for a custom storage endpoint suffix. The setting name for a shared access key. The default account name for the development storage. The default account key for the development storage. The credentials string used to test for the development storage credentials. The suffix appended to account in order to access secondary location for read only access. The default storage service hostname suffix. The default blob storage DNS hostname prefix. The root queue DNS name prefix. The root table storage DNS name prefix. The FISMA compliance default value. Validator for the UseDevelopmentStorage setting. Must be "true". Validator for the DevelopmentStorageProxyUri setting. Must be a valid Uri. Validator for the DefaultEndpointsProtocol setting. Must be either "http" or "https". Validator for the AccountName setting. No restrictions. Validator for the AccountKey setting. No restrictions. Validator for the AccountKey setting. Must be a valid base64 string. Validator for the BlobEndpoint setting. Must be a valid Uri. Validator for the QueueEndpoint setting. Must be a valid Uri. Validator for the TableEndpoint setting. Must be a valid Uri. Validator for the EndpointSuffix setting. Must be a valid Uri. Validator for the SharedAccessSignature setting. No restrictions. Singleton instance for the development storage account. Initializes a new instance of the class using the specified account credentials and service endpoints. The account credentials. The Blob service endpoint. The Queue service endpoint. The Table service endpoint. Initializes a new instance of the class using the specified account credentials and service endpoints. The account credentials. The Blob service endpoint. The Queue service endpoint. The Table service endpoint. Initializes a new instance of the class using the specified account credentials and the default service endpoints. An object of type that specifies the account name and account key for the storage account. True to use HTTPS to connect to storage service endpoints; otherwise, false. Initializes a new instance of the class using the specified account credentials and the default service endpoints. An object of type that specifies the account name and account key for the storage account. The DNS endpoint suffix for all storage services, e.g. "core.windows.net". True to use HTTPS to connect to storage service endpoints; otherwise, false. Parses a connection string and returns a created from the connection string. A valid connection string. Thrown if is null or empty. Thrown if is not a valid connection string. Thrown if cannot be parsed. A object constructed from the values provided in the connection string. Indicates whether a connection string can be parsed to return a object. The connection string to parse. A object to hold the instance returned if the connection string can be parsed. true if the connection string was successfully parsed; otherwise, false. Creates the Table service client. A client object that specifies the Table service endpoint. Creates the Queue service client. A client object that specifies the Queue service endpoint. Creates the Blob service client. A client object that specifies the Blob service endpoint. Returns a connection string for this storage account, without sensitive data. A connection string. Returns a connection string for the storage account, optionally with sensitive data. True to include sensitive data in the string; otherwise, false. A connection string. Returns a with development storage credentials using the specified proxy Uri. The proxy endpoint to use. The new . Internal implementation of Parse/TryParse. The string to parse. The to return. A callback for reporting errors. If true, the parse was successful. Otherwise, false. Tokenizes input and stores name value pairs. The string to parse. Error reporting delegate. Tokenized collection. Encapsulates a validation rule for an enumeration based account setting. The name of the setting. A list of valid values for the setting. An representing the enumeration constraint. Encapsulates a validation rule using a func. The name of the setting. A func that determines if the value is valid. An representing the constraint. Determines whether the specified setting value is a valid base64 string. The setting value. true if the specified setting value is a valid base64 string; otherwise, false. Validation function that validates Uris. Value to validate. true if the specified setting value is a valid Uri; otherwise, false. Validation function that validates a domain name. Value to validate. true if the specified setting value is a valid domain; otherwise, false. Settings filter that requires all specified settings be present and valid. A list of settings that must be present. The remaining settings or null if the filter's requirement is not satisfied. Settings filter that removes optional values. A list of settings that are optional. The remaining settings or null if the filter's requirement is not satisfied. Settings filter that ensures that at least one setting is present. A list of settings of which one must be present. The remaining settings or null if the filter's requirement is not satisfied. Settings filter that ensures that a valid combination of credentials is present. The remaining settings or null if the filter's requirement is not satisfied. Tests to see if a given list of settings matches a set of filters exactly. The settings to check. A list of filters to check. If any filter returns null, false. If there are any settings left over after all filters are processed, false. Otherwise true. Gets a StorageCredentials object corresponding to whatever credentials are supplied in the given settings. The settings to check. The StorageCredentials object specified in the settings. Gets the default blob endpoint using specified settings. The settings to use. The default blob endpoint. Gets the default blob endpoint using the specified protocol and account name. The protocol to use. The name of the storage account. The Endpoint DNS suffix; use null for default. The default blob endpoint. Gets the default queue endpoint using the specified settings. The settings. The default queue endpoint. Gets the default queue endpoint using the specified protocol and account name. The protocol to use. The name of the storage account. The Endpoint DNS suffix; use null for default. The default queue endpoint. Gets the default table endpoint using the specified settings. The settings. The default table endpoint. Gets the default table endpoint using the specified protocol and account name. The protocol to use. The name of the storage account. The Endpoint DNS suffix; use null for default. The default table endpoint. Gets or sets a value indicating whether the FISMA MD5 setting will be used. false to use the FISMA MD5 setting; true to use the .NET default implementation. Gets a object that references the development storage account. A reference to the development storage account. Indicates whether this account is a development storage account. The storage service hostname suffix set by the user, if any. The connection string parsed into settings. True if the user used a constructor that auto-generates endpoints. Gets the primary endpoint for the Blob service, as configured for the storage account. The primary Blob service endpoint. Gets the primary endpoint for the Queue service, as configured for the storage account. The primary Queue service endpoint. Gets the primary endpoint for the Table service, as configured for the storage account. The primary Table service endpoint. Gets the endpoints for the Blob service, as configured for the storage account. An object of type containing the endpoints for the Blob service. Gets the endpoints for the Queue service, as configured for the storage account. An object of type containing the endpoints for the Queue service. Gets the endpoints for the Table service, as configured for the storage account. An object of type containing the endpoints for the Table service. Gets the credentials used to create this object. The credentials used to create the object. Specifies that the method will make one or more requests to the storage service. An interface that allows clients to provide a buffer manager to a given service client. This interface is patterned after the System.ServiceModel.Channels.BufferManager class. Returns a buffer to the pool. A reference to the buffer being returned. Buffer reference cannot be null. Length of buffer does not match the pool's buffer length property. Gets a buffer of at least the specified size from the pool. The size, in bytes, of the requested buffer. The value specified for cannot be less than zero. A byte array that is the requested size of the buffer. Gets the size, in bytes, of the buffers managed by the given pool. Note that the buffer manager must return buffers of the exact size requested by the client. The size, in bytes, of the buffers managed by the given pool. An interface required for continuation token types. The , , and classes implement the interface. Gets the location that the token applies to. The location that the token applies to. An interface required for request option types. The , , and classes implement the interface. Gets or sets the retry policy for the request. The retry policy delegate. Gets or sets the location mode of the request. The location mode of the request. Gets or sets the server timeout for the request. The client and server timeout interval for the request. Gets or sets the maximum execution time across all potential retries. The maximum execution time across all potential retries. Specifies what messages to output to the log. Output no tracing and debugging messages. Output error-handling messages. Output warnings and error-handling messages. Output informational messages, warnings, and error-handling messages. Output all debugging and tracing messages. Represents the context for a request operation against the storage service, and provides additional runtime information about its execution. Initializes a new instance of the class. Gets or sets additional headers on the request, for example, for proxy or logging information. A object containing additional header information. Gets or sets the client request ID. The client request ID. Gets or sets the default logging level to be used for subsequently created instances of the class. A value of type that specifies which events are logged by default by instances of the . Gets or sets the logging level to be used for an instance of the class. A value of type that specifies which events are logged by the . Occurs immediately before a request is signed. Occurs when a response is received from the server. Gets or sets the start time of the operation. The start time of the operation. Gets or sets the end time of the operation. The end time of the operation. Gets or sets the set of request results that the current operation has created. An object that contains objects that represent the request results created by the current operation. Gets the last request result encountered for the operation. A object that represents the last request result. Provides information and event data that is associated with a request event. Initializes a new instance of the class by using the specified parameter. The object. Gets the request information associated with this event. The request information associated with this event. Gets the HTTP request associated with this event. The HTTP request associated with this event. Gets the HTTP response associated with this event. The HTTP response associated with this event. Represents the result of a physical request. Translates the specified message into a object. The message to translate. The translated . Generates a serializable RequestResult from its XML representation. The stream from which the RequestResult is deserialized. Converts a serializable RequestResult into its XML representation. The stream to which the RequestResult is serialized. Gets or sets the HTTP status code for the request. The HTTP status code for the request. Gets the HTTP status message for the request. The HTTP status message for the request. Gets the service request ID for this request. The service request ID for this request. Gets the content-MD5 value for the request. The content-MD5 value for the request. Gets the ETag value of the request. The ETag value of the request. Gets the request date. The request date. Gets the location that the request was sent to. The location that the request was sent to. Gets the extended error information. The extended error information. Gets or sets the exception. The exception. Gets the start time of the operation. The start time of the operation. Gets the end time of the operation. The end time of the operation. Represents a result segment that was retrieved from the total set of possible results. The type of the element. Stores the continuation token used to retrieve the next segment of results. Initializes a new instance of the ResultSegment class. The result. Gets an enumerable collection of results. An enumerable collection of results. Gets a continuation token to use to retrieve the next set of results with a subsequent call to the operation. The continuation token. Represents an exception thrown by the Windows Azure storage service. Initializes a new instance of the class. Initializes a new instance of the class using the specified error message. The message that describes the error. Initializes a new instance of the class with a specified error message and a reference to the inner exception that generated this exception. The exception error message. The inner exception. Initializes a new instance of the class with serialized data. The that contains contextual information about the source or destination. The object that holds serialized object data for the exception being thrown. This constructor is called during de-serialization to reconstitute the exception object transmitted over a stream. Populates a object with the data needed to serialize the target object. The destination context for this serialization. The object to populate with data. Initializes a new instance of the class by using the specified parameters. The request result. The exception message. The inner exception. Translates the specified exception into a . The exception to translate. The request result. The storage exception. An exception of type . Translates the specified exception into a storage exception. The exception to translate. The request result. The delegate used to parse the error to get extended error information. The storage exception. Translates the specified exception into a storage exception. The exception to translate. The request result. The delegate used to parse the error to get extended error information. The error stream that contains the error information. The storage exception. Tries to translate the specified exception into a storage exception. The exception to translate. The request result. The delegate used to parse the error to get extended error information. The storage exception or null. Translates the specified exception into a storage exception. The exception to translate. The request result. The delegate used to parse the error to get extended error information. The storage exception. Populate the RequestResult. The request result. The web response. Represents an exception thrown by the Windows Azure storage client library. A string that represents the exception. Gets the object for this object. The object for this object. Represents extended error information returned by the Windows Azure storage services. Initializes a new instance of the class. Gets the error details from stream. The input stream. The error details. Gets the error details from the stream using OData library. The input stream. The web response. The response Content-Type. The error details. Gets the error details from the stream using OData library. The input stream. The web response headers. The response Content-Type. The error details. Parses the error details from the stream using OData library. The IODataResponseMessage to parse. The error details. Generates a serializable object from its XML representation. The stream from which the object is deserialized. Converts a serializable object into its XML representation. The stream to which the object is serialized. Gets the storage service error code. The storage service error code. Gets the storage service error message. The storage service error message. Gets additional error details. The additional error details. Represents a storage service location. Primary storage service location. Secondary storage service location. Contains the URIs for both the primary and secondary locations of a Windows Azure Storage resource. Initializes a new instance of the class using the primary endpoint for the storage account. The URI for the primary endpoint. Initializes a new instance of the class using the primary and secondary endpoints for the storage account. The URI for the primary endpoint. The URI for the secondary endpoint. Returns the URI for the storage account endpoint at the specified location. The primary or secondary location for the storage account. The of the specified location. Returns a that represents this instance. A that represents this instance. Returns a hash code for this instance. A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. Determines whether the specified is equal to this instance. The to compare with this instance. true if the specified is equal to this instance; otherwise, false. Indicates whether the current object is equal to another object of the same type. An object to compare with this object. true if the current object is equal to the parameter; otherwise, false. The endpoint for the primary location for the storage account. The URI for the primary endpoint. The endpoint for the secondary location for the storage account. The URI for the secondary endpoint. Represents a set of credentials used to authenticate access to a Windows Azure storage account. Initializes a new instance of the class. Initializes a new instance of the class with the specified account name and key value. A string that represents the name of the storage account. A string that represents the Base64-encoded account access key. Initializes a new instance of the class with the specified account name and key value. A string that represents the name of the storage account. An array of bytes that represent the account access key. Initializes a new instance of the class with the specified account name, key value, and key name. A string that represents the name of the storage account. A string that represents the Base64-encoded account access key. A string that represents the name of the key. Initializes a new instance of the class with the specified account name, key value, and key name. A string that represents the name of the storage account. An array of bytes that represent the account access key. A string that represents the name of the key. Initializes a new instance of the class with the specified shared access signature token. A string representing the shared access signature token. Updates the key value for the credentials. The key value, as a Base64-encoded string, to update. Updates the key value for the credentials. The key value, as an array of bytes, to update. Updates the key value and key name for the credentials. The key value, as a Base64-encoded string, to update. The key name to update. Updates the key value and key name for the credentials. The key value, as an array of bytes, to update. The key name to update. Updates the shared access signature (SAS) token value for storage credentials created with a shared access signature. A string that specifies the SAS token value to update. Returns the account key for the credentials. An array of bytes that contains the key. Transforms a resource URI into a shared access signature URI, by appending a shared access token. A object that represents the resource URI to be transformed. A object that represents the signature, including the resource URI and the shared access token. Transforms a resource URI into a shared access signature URI, by appending a shared access token. A object that represents the resource URI to be transformed. A object that represents the signature, including the resource URI and the shared access token. Exports the value of the account access key to a Base64-encoded string. The account access key. Determines whether an other object is equal to this one by comparing their SAS tokens, account names, key names, and key values. The object to compare to this one. true if the two objects are equal; otherwise, false. Gets the associated shared access signature token for the credentials. The shared access signature token. Gets the associated account name for the credentials. The account name. Gets the associated key name for the credentials. The key name. Gets a value indicating whether the credentials are for anonymous access. true if the credentials are for anonymous access; otherwise, false. Gets a value indicating whether the credentials are a shared access signature token. true if the credentials are a shared access signature token; otherwise, false. Gets a value indicating whether the credentials are a shared key. true if the credentials are a shared key; otherwise, false. Represents a canonicalized string used in authenticating a request against the azure service. Stores the internal that holds the canonicalized string. Initializes a new instance of the class. The first canonicalized element to start the string with. Initializes a new instance of the class. The first canonicalized element to start the string with. The starting size of the string. Append additional canonicalized element to the string. An additional canonicalized element to append to the string. Converts the value of this instance to a string. A string whose value is the same as this instance. This class provides MemoryStream-like behavior but uses a list of buffers rather than a single buffer. The default small buffer size. The size of each buffer. The underlying buffer blocks for the stream. The currently used length. The total capacity of the stream. The current position. A reference to the IBufferManager for the stream to use to acquire and return buffers. Initializes a new instance of the MultiBufferMemoryStream class with provided IBufferManager. A reference to the IBufferManager for the stream to use to acquire and return buffers. May be null. The Buffer size to use for each block, default is 64 KB. Note this parameter is disregarded when a IBufferManager is specified. Reads a block of bytes from the current stream and writes the data to a buffer. When this method returns, the buffer contains the specified byte array with the values between offset and (offset + count - 1) replaced by the bytes read from the current source. The zero-based byte offset in buffer at which to begin storing the data read from the current stream. The maximum number of bytes to be read. The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero if the end of the stream has been reached. Begins an asynchronous read operation. When this method returns, the buffer contains the specified byte array with the values between offset and (offset + count - 1) replaced by the bytes read from the current source. The zero-based byte offset in buffer at which to begin storing the data read from the current stream. The maximum number of bytes to be read. An optional asynchronous callback, to be called when the read is complete. A user-provided object that distinguishes this particular asynchronous read request from other requests. An IAsyncResult that represents the asynchronous read, which could still be pending. Waits for the pending asynchronous read to complete. The reference to the pending asynchronous request to finish. The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero if the end of the stream has been reached. Sets the position within the current stream. A byte offset relative to the origin parameter. A value of type System.IO.SeekOrigin indicating the reference point used to obtain the new position. The new position within the current stream. Thrown if is invalid for SeekOrigin. Sets the length of the current stream to the specified value. (pre-allocating the bufferBlocks). The desired length of the current stream in bytes. If the is negative. Writes a block of bytes to the current stream using data read from a buffer. The buffer to write data from. The zero-based byte offset in buffer at which to begin copying bytes to the current stream. The number of bytes to write. Begins an asynchronous write operation. The buffer to write data from. The zero-based byte offset in buffer at which to begin copying bytes to the current stream. The number of bytes to write. An optional asynchronous callback, to be called when the write is complete. A user-provided object that distinguishes this particular asynchronous write request from other requests. An IAsyncResult that represents the asynchronous write, which could still be pending. Ends an asynchronous write operation. The reference to the pending asynchronous request to finish. Does not perform any operation as it's an in-memory stream. Reads the bytes from the current stream and writes them to another stream. However, this method eliminates copying the data into a temporary buffer by directly writing to the destination stream. The stream to which the contents of the current stream will be copied. DateTime indicating the expiry time. Begins an asynchronous fast-copy operation. The stream to which the contents of the current stream will be copied. DateTime indicating the expiry time. An optional asynchronous callback, to be called when the copy is complete. A user-provided object that distinguishes this particular asynchronous copy request from other requests. An IAsyncResult that represents the asynchronous copy, which could still be pending. Initiates a write operation for the next buffer in line. Internal StorageAsyncResult that represents the asynchronous copy. Callback method to be called when the corresponding write operation completes. The result of the asynchronous operation. Ends an asynchronous copy operation. The reference to the pending asynchronous request to finish. Computes the hash value for this stream. String representation of the computed hash value. Ensures that the amount of bufferBlocks is greater than or equal to the required size. Does not trim the size. The required size. If the is negative. Adds another block to the underlying bufferBlocks. Copies the specified amount of data from internal buffers to the buffer and advances the position. An array of bytes. When this method returns, the buffer contains the specified byte array with the values between offset and (offset + count - 1) replaced by the bytes read from the current source. The zero-based byte offset in buffer at which to begin storing the data read from the current stream. The maximum number of bytes to be read from the current stream. The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero (0) if the end of the stream has been reached. Writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written. (Requires the stream to be of sufficient size for writing). An array of bytes. This method copies count bytes from buffer to the current stream. The zero-based byte offset in buffer at which to begin copying bytes to the current stream. The number of bytes to be written to the current stream. Advances the current position of the stream and adjust the offset and remainder based on the amount completed. The current offset in the external buffer. The amount of data left to process. The amount of data processed. Advances the current position of the stream and adjust the remainder based on the amount completed. The amount of data left to process. The amount of data processed. Calculate the block for the current position. Gets a value indicating whether the current stream supports reading. Is true if the stream supports reading; otherwise, false. Gets a value indicating whether the current stream supports seeking. Is true if the stream supports seeking; otherwise, false. Gets a value indicating whether the current stream supports writing. Is true if the stream supports writing; otherwise, false. Gets the currently written length. Represents the current position in the stream. Thrown if position is outside the stream size A NullTaskReturn type. Represents a no-return from a task. Prevents a default instance of the class from being created. Provides a standard set of errors that could be thrown from the client library. This class provides APM Read/Write overrides for memory stream to improve performance. Initializes a new instance of the SyncMemoryStream class with an expandable capacity initialized to zero. Initializes a new non-resizable instance of the SyncMemoryStream class based on the specified byte array. The array of unsigned bytes from which to create the current stream. Initializes a new non-resizable instance of the SyncMemoryStream class based on the specified region (index) of a byte array. The array of unsigned bytes from which to create the current stream. The index into buffer at which the stream begins. Initializes a new non-resizable instance of the SyncMemoryStream class based on the specified region (index) of a byte array. The array of unsigned bytes from which to create the current stream. The index into buffer at which the stream begins. The length of the stream in bytes. Begins an asynchronous read operation. When this method returns, the buffer contains the specified byte array with the values between offset and (offset + count - 1) replaced by the bytes read from the current source. The zero-based byte offset in buffer at which to begin storing the data read from the current stream. The maximum number of bytes to be read. An optional asynchronous callback, to be called when the read is complete. A user-provided object that distinguishes this particular asynchronous read request from other requests. An IAsyncResult that represents the asynchronous read, which could still be pending. Waits for the pending asynchronous read to complete. The reference to the pending asynchronous request to finish. The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero if the end of the stream has been reached. Begins an asynchronous write operation. The buffer to write data from. The zero-based byte offset in buffer at which to begin copying bytes to the current stream. The number of bytes to write. An optional asynchronous callback, to be called when the write is complete. A user-provided object that distinguishes this particular asynchronous write request from other requests. An IAsyncResult that represents the asynchronous write, which could still be pending. Ends an asynchronous write operation. The reference to the pending asynchronous request to finish. A convenience class for constructing URI query strings. Initializes a new instance of the class. Initializes a new instance of the class that contains elements copied from the specified . The whose elements are copied to the new . Stores the query parameters. Add the value with URI escaping. The query name. The query value. Returns a containing the URI. A containing the URI. Adds a query parameter to a URI. The original URI, including any existing query parameters. The URI with the new query parameter appended. Adds a query parameter to a URI. The original URI, including any existing query parameters. The URI with the new query parameter appended. Contains helper methods for implementing shared access signatures. Get the complete query builder for creating the Shared Access Signature query. The shared access policy to hash. The optional header values to set for a blob returned with this SAS. An optional identifier for the policy. Either "b" for blobs or "c" for containers. The signature to use. The name of the key used to create the signature, or null if the key is implicit. The finished query builder. Get the complete query builder for creating the Shared Access Signature query. The shared access policy to hash. An optional identifier for the policy. The signature to use. The name of the key used to create the signature, or null if the key is implicit. The finished query builder. Get the complete query builder for creating the Shared Access Signature query. The shared access policy to hash. The name of the table associated with this shared access signature. An optional identifier for the policy. The start partition key, or null. The start row key, or null. The end partition key, or null. The end row key, or null. The signature to use. The name of the key used to create the signature, or null if the key is implicit. The finished query builder. Converts the specified value to either a string representation or . The value to convert. A string representing the specified value. Converts the specified value to either a string representation or null. The value to convert. A string representing the specified value. Escapes and adds the specified name/value pair to the query builder if it is not null. The builder to add the value to. The name of the pair. The value to be escaped. Parses the query. The query parameters. A boolean that represents whether SignedResource is part of Sas or not. True for blobs, False for Queues and Tables. Get the signature hash embedded inside the Shared Access Signature. The shared access policy to hash. An optional identifier for the policy. The canonical resource string, unescaped. The key value retrieved as an atomic operation used for signing. The signed hash. Get the signature hash embedded inside the Shared Access Signature. The shared access policy to hash. An optional identifier for the policy. The start partition key, or null. The start row key, or null. The end partition key, or null. The end row key, or null. The canonical resource string, unescaped. The key value retrieved as an atomic operation used for signing. The signed hash. Get the signature hash embedded inside the Shared Access Signature. The shared access policy to hash. The optional header values to set for a blob returned with this SAS. An optional identifier for the policy. The canonical resource string, unescaped. The key value retrieved as an atomic operation used for signing. The signed hash. Gets the value of the x-ms-date or Date header. The request where the value is read from. The value of the x-ms-date or Date header. Appends the value of the Content-Length header to the specified canonicalized string. The canonicalized string where the value is appended. The request where the value is read from. Appends the value of the Date header (or, optionally, the x-ms-date header) to the specified canonicalized string. The canonicalized string where the value is appended. The request where the value is read from. true if the value of the x-ms-date header can be used and is preferred; otherwise, false. Appends the values of the x-ms-* headers to the specified canonicalized string. The canonicalized string where the values are appended. The request where the values are read from. Gets the canonicalized header value to use for the specified date/time or null if it does not have a value. The date/time. The canonicalized header value to use for the specified date/time or null if it does not have a value. In case of path style, this method will strip off -secondary from absolute path and replace it with account name. The resource URI. The name of the storage account. Absolute path with no -secondary suffix. Gets the canonicalized resource string for the specified URI. The resource URI. The name of the storage account. true when using the Shared Key Lite authentication scheme or the table service; otherwise, false. The canonicalized resource string. Determines which location can the listing command target by looking at the continuation token. Continuation token Location mode Create an ExecutionState object that can be used for pre-request operations such as buffering user's data. Request options Temporary ExecutionState object Returns the larger of two time spans. The first of two time spans to compare. The second of two time spans to compare. Parameter or , whichever is larger. Gets the first header value or null if no header values exist. The type of header objects contained in the enumerable. An enumerable that contains header values. The first header value or null if no header values exist. Throws an exception if the string is empty or null. The name of the parameter. The value of the parameter. Thrown if value is empty. Thrown if value is null. Throw an exception if the value is null. The name of the parameter. The value of the parameter. Thrown if value is null. Throw an exception indicating argument is out of range. The name of the parameter. The value of the parameter. Throw an exception if the argument is out of bounds. The type of the value. The name of the parameter. The value of the parameter. The minimum value for the parameter. The maximum value for the parameter. Throw an exception if the argument is out of bounds. The type of the value. The name of the parameter. The value of the parameter. The minimum value for the parameter. Checks that the given timeout in within allowed bounds. The timeout to check. The timeout is not within allowed bounds. Combines AssertNotNullOrEmpty and AssertInBounds for convenience. The name of the parameter. Turns on or off null/empty checking. The value of the parameter. The maximum size of value. Rounds up to seconds. The time span. The time rounded to seconds. List of ports used for path style addressing. Determines if a URI requires path style addressing. The URI to check. Returns true if the Uri uses path style addressing; otherwise, false. Read the value of an element in the XML. The name of the element whose value is retrieved. A reader that provides access to XML data. A string representation of the element's value. Returns an enumerable collection of results that is retrieved lazily. The type of ResultSegment like Blob, Container, Queue and Table. The segment generator. >A non-negative integer value that indicates the maximum number of results to be returned in the result segment, up to the per-operation limit of 5000. Applies the request optimizations such as disabling buffering and 100 continue. The request to be modified. The length of the content, -1 if the content length is not settable. Increments the counter by one and thus sets the state of the event to non-signaled, causing threads to block. Decrements the counter by one. If the counter reaches zero, sets the state of the event to signaled, allowing one or more waiting threads to proceed. Blocks the current thread until the CounterEvent is set. Blocks the current thread until the CounterEvent is set, using a 32-bit signed integer to measure the timeout. The number of milliseconds to wait, or Infinite(-1) to wait indefinitely. true if the CounterEvent was set; otherwise, false. Releases all resources used by the current instance of the CounterEvent class. Gets a WaitHandle that is used to wait for the event to be set. A WaitHandle that is used to wait for the event to be set. Provides helper functions for http request/response processing. Parse the http query string. Http query string. Converts the DateTimeOffset object to an Http string of form: Sun, 28 Jan 2008 12:11:37 GMT. The DateTimeOffset object to convert to an Http string. String of form: Sun, 28 Jan 2008 12:11:37 GMT. Try to get the value of the specified header name. The Http web response from which to get the header value. The name of the header whose value is to be retrieved. The default value for the header that is returned if we can't get the actual header value. A string representing the header value. Wrapper class for MD5. Calculates an on-going hash using the input byte array. The input array used for calculating the hash. The offset in the input buffer to calculate from. The number of bytes to use from input. Retrieves the string representation of the hash. (Completes the creation of the hash). String representation of the computed hash value. Contains methods for dealing with navigation. The name of the root container. Used in address parsing. Used in address parsing. Used in address parsing. Used to split string on slash. Used to split hostname. Retrieves the container part of a storage Uri, or "$root" if the container is implicit. The blob address. If set to true use path style Uris. Name of the container. The trailing slash is always removed. GetContainerName(new Uri("http://test.blob.core.windows.net/mycontainer/myfolder/myblob")) will return "mycontainer" GetContainerName(new Uri("http://test.blob.core.windows.net/mycontainer/")) will return "mycontainer" GetContainerName(new Uri("http://test.blob.core.windows.net/myblob")) will return "$root" GetContainerName(new Uri("http://test.blob.core.windows.net/")) will throw ArgumentException Retrieves the blob part of a storage Uri. The blob address. If set to true use path style Uris. The name of the blob. Retrieves the complete container address from a storage Uri Example GetContainerAddress(new Uri("http://test.blob.core.windows.net/mycontainer/myfolder/myblob")) will return http://test.blob.core.windows.net/mycontainer. The blob address. True to use path style Uris. Uri of the container. Retrieves the parent name from a storage Uri. The blob address. The delimiter. If set to true use path style Uris. The name of the parent. Adds the trailing delimiter as the prefix returned by the storage REST api always contains the delimiter. GetParentName(new Uri("http://test.blob.core.windows.net/mycontainer/myfolder/myblob", "/")) will return "/mycontainer/myfolder/" GetParentName(new Uri("http://test.blob.core.windows.net/mycontainer/myfolder|myblob", "|") will return "/mycontainer/myfolder|" GetParentName(new Uri("http://test.blob.core.windows.net/mycontainer/myblob", "/") will return "/mycontainer/" GetParentName(new Uri("http://test.blob.core.windows.net/mycontainer/", "/") will return "/mycontainer/" Gets the service client base address. The address Uri. The use path style Uris. The base address of the client. GetServiceClientBaseAddress("http://testaccount.blob.core.windows.net/testcontainer/blob1") returns "http://testaccount.blob.core.windows.net" Gets the service client base address. The address Uri. The use path style Uris. The base address of the client. GetServiceClientBaseAddress("http://testaccount.blob.core.windows.net/testcontainer/blob1") returns "http://testaccount.blob.core.windows.net" Appends a path to a list of URIs correctly using "/" as separator. The base URI. The relative or absolute URI. The list of appended URIs. Appends a path to a list of URIs correctly using "/" as separator. The base URI. The relative or absolute URI. The separator. The list of appended URIs. Append a relative path to a URI, handling trailing slashes appropriately. The base URI. The relative or absolute URI. The appended Uri. Append a relative path to a URI, handling trailing slashes appropriately. The base URI. The relative or absolute URI. The separator. The appended Uri. Get container name from address for styles of paths Example: http://test.blob.core.windows.net/container/blob => container http://127.0.0.1:10000/test/container/blob => container. The container Uri. If set to true use path style Uris. The container name. Similar to getting container name from Uri. The queue Uri. If set to true use path style Uris. The queue name. Extracts a table name from the table's Uri. The queue Uri. If set to true use path style Uris. The queue name. Retrieve the container address and address. The blob address. True to use path style Uris. Name of the container. The container URI. true when the container is an explicit container. false, otherwise. Retrieve the container name and the blob name from a blob address. The blob address. If set to true use path style Uris. The resulting container name. The resulting blob name. A bool representing whether the blob is in an explicit container or not. Parses the snapshot time. The snapshot time. The parsed snapshot time. Parse Uri for SAS (Shared access signature) information. The complete Uri. The credentials to use. The parsed snapshot. The blob URI without credentials or snapshot info address Validate that no other query parameters are passed in. Any SAS information will be recorded as corresponding credentials instance. If credentials is passed in and it does not match the SAS information found, an exception will be thrown. Otherwise a new client is created based on SAS information or as anonymous credentials. Parse Uri for SAS (Shared access signature) information. The complete Uri. The credentials to use. The parsed snapshot. The blob URI without credentials or snapshot info address Validate that no other query parameters are passed in. Any SAS information will be recorded as corresponding credentials instance. If credentials is passed in and it does not match the SAS information found, an exception will be thrown. Otherwise a new client is created based on SAS information or as anonymous credentials. Parse Uri for SAS (Shared access signature) information. The complete Uri. The credentials to use. Validate that no other query parameters are passed in. Any SAS information will be recorded as corresponding credentials instance. If credentials is passed in and it does not match the SAS information found, an exception will be thrown. Otherwise a new client is created based on SAS information or as anonymous credentials. Parse Uri for SAS (Shared access signature) information. The complete Uri. The credentials to use. Validate that no other query parameters are passed in. Any SAS information will be recorded as corresponding credentials instance. If credentials is passed in and it does not match the SAS information found, an exception will be thrown. Otherwise a new client is created based on SAS information or as anonymous credentials. Represents a canonicalized string used in authenticating a request against the azure service. Provides properties to keep track of Md5 hash / Length of a stream as it is being copied. Provides stream helper methods that allow us to copy streams and measure the stream size. Reads synchronously the specified content of the stream and writes it to the given output stream. The origin stream. The destination stream. Number of bytes to copy from source stream to destination stream. Cannot be passed with a value for maxLength. Maximum length of the stream to write. true to calculate the MD5 hash. A boolean indicating whether the write happens synchronously. An object that stores state of the operation. State of the stream copy. stream Asynchronously reads the entire content of the stream and writes it to the given output stream. The result type of the ExecutionState The origin stream. The destination stream. Number of bytes to copy from source stream to destination stream. Cannot be passed with a value for maxLength. Maximum length of the source stream. Cannot be passed with a value for copyLength. Bool value indicating whether the Md5 should be calculated. An object that stores state of the operation. State of the stream copy. The action taken when the execution is completed. Represents a retry policy that performs a specified number of retries, using a randomized exponential back off scheme to determine the interval between retries. Represents a retry policy. Represents a retry policy. Generates a new retry policy for the current request attempt. An object that represents the retry policy for the current request attempt. Determines whether the operation should be retried and the interval until the next retry. The number of retries for the given operation. A value of zero signifies this is the first error encountered. The status code for the last operation. An object that represents the last exception encountered. The interval to wait until the next retry. An object for tracking the current operation. true if the operation should be retried; otherwise, false. Determines whether the operation should be retried and the interval until the next retry. A object that indicates the number of retries, the results of the last request, and whether the next retry should happen in the primary or secondary location, and specifies the location mode. An object for tracking the current operation. A object that indicates the location mode, and whether the next retry should happen in the primary or secondary location. If null, the operation will not be retried. Initializes a new instance of the class. Initializes a new instance of the class using the specified delta and maximum number of retries. The back off interval between retries. The maximum number of retry attempts. Determines whether the operation should be retried and the interval until the next retry. The number of retries for the given operation. A value of zero signifies this is the first error encountered. The status code for the last operation. An object that represents the last exception encountered. The interval to wait until the next retry. An object for tracking the current operation. true if the operation should be retried; otherwise, false. Determines whether the operation should be retried and the interval until the next retry. A object that indicates the number of retries, the results of the last request, and whether the next retry should happen in the primary or secondary location, and specifies the location mode. An object for tracking the current operation. A object that indicates the location mode, and whether the next retry should happen in the primary or secondary location. If null, the operation will not be retried. Generates a new retry policy for the current request attempt. An object that represents the retry policy for the current request attempt. Represents a retry policy that performs a specified number of retries, using a specified fixed time interval between retries. Initializes a new instance of the class. Initializes a new instance of the class using the specified delta and maximum number of retries. The back off interval between retries. The maximum number of retry attempts. Determines whether the operation should be retried and the interval until the next retry. The number of retries for the given operation. A value of zero signifies this is the first error encountered. The status code for the last operation. An object that represents the last exception encountered. The interval to wait until the next retry. An object for tracking the current operation. true if the operation should be retried; otherwise, false. Determines whether the operation should be retried and the interval until the next retry. A object that indicates the number of retries, the results of the last request, and whether the next retry should happen in the primary or secondary location, and specifies the location mode. An object for tracking the current operation. A object that indicates the location mode, and whether the next retry should happen in the primary or secondary location. If null, the operation will not be retried. Generates a new retry policy for the current request attempt. An object that represents the retry policy for the current request attempt. Specifies the location mode used to decide which location the request should be sent to. Requests should always be sent to the primary location. Requests should always be sent to the primary location first. If the request fails, it should be sent to the secondary location. Requests should always be sent to the secondary location. Requests should always be sent to the secondary location first. If the request fails, it should be sent to the primary location. Represents a retry policy that performs no retries. Initializes a new instance of the class. Determines if the operation should be retried and how long to wait until the next retry. The number of retries for the given operation. A value of zero signifies this is the first error encountered. The status code for the last operation. An object that represents the last exception encountered. The interval to wait until the next retry. An object for tracking the current operation. true if the operation should be retried; otherwise, false. Generates a new retry policy for the current request attempt. An object that represents the retry policy for the current request attempt. Represents the context for one or more retries of a request made against the Windows Azure storage services, including the number of retries made for the request, the results of the last request, and the storage location and location mode for subsequent retries. Returns a string that represents the current instance. A string that represents the current instance. Gets the target location for the next retry. The target location for the next retry. Gets the location mode for subsequent retries. The location mode for subsequent retries. Gets the number of retries for the given operation. The number of retries for the given operation. Gets the results of the last request. A object that represents the results of the last request. Specifies parameters for the next retry of a request to be made against the Windows Azure storage services, including the target location and location mode for the next retry and the interval until the next retry. Initializes a new instance of the class. Initializes a new instance of the class. The object that was passed in to the retry policy. Returns a string that represents the current instance. A string that represents the current instance. Gets or sets the target location for the next retry. The target location for the next retry. Gets or sets the location mode for subsequent retries. The location mode for subsequent retries. Gets the interval until the next retry. The interval until the next retry. Verifies that the blob is not a snapshot. Gets the blob's system properties. The blob's properties. Gets the user-defined metadata for the blob. The blob's metadata, as a collection of name-value pairs. Gets the blob's URI for the primary location. The absolute URI to the blob, at the primary location. Gets the list of URIs for all locations. The list of URIs for all locations. Gets the date and time that the blob snapshot was taken, if this blob is a snapshot. The blob's snapshot time if the blob is a snapshot; otherwise, null. If the blob is not a snapshot, the value of this property is null. Gets the state of the most recent or pending copy operation. A object containing the copy state, or null if no copy blob state exists for this blob. Represents the permissions for a container. Initializes a new instance of the class. Gets or sets the public access setting for the container. The public access setting for the container. Gets the set of shared access policies for the container. The set of shared access policies for the container. Represents the system properties for a container. Gets the ETag value for the container. The container's quoted ETag value. Gets the container's last-modified time. The container's last-modified time. Gets the container's lease status. A object that indicates the container's lease status. Gets the container's lease state. A object that indicates the container's lease state. Gets the container's lease duration. A object that indicates the container's lease duration. Specifies the level of public access that is allowed on the container. No public access. Only the account owner can read resources in this container. Container-level public access. Anonymous clients can read container and blob data. Blob-level public access. Anonymous clients can read blob data within this container, but not container data. Represents a continuation token for listing operations. continuation tokens are used in methods that return a object, such as . Gets an XML representation of an object. An that describes the XML representation of the object that is produced by the method and consumed by the method. Generates a serializable continuation token from its XML representation. The stream from which the continuation token is deserialized. Converts a serializable continuation token into its XML representation. The stream to which the continuation token is serialized. Gets or sets the version for continuing results for enumeration operations. The version. Gets or sets the type element (blob, queue, table) for continuing results for enumeration operations. The type element. Gets or sets the next marker for continuing results for enumeration operations. The next marker. Gets or sets the storage location that the continuation token applies to. The storage location that the continuation token applies to. Specifies which items to include when listing a set of blobs. List only committed blobs, and do not return blob metadata. List committed blobs and blob snapshots. Retrieve blob metadata for each blob returned in the listing. List committed and uncommitted blobs. Include copy properties in the listing. List all available committed blobs, uncommitted blobs, and snapshots, and return all metadata and copy status for those blobs. Represents the system properties for a blob. Initializes a new instance of the class. Initializes a new instance of the class based on an existing instance. The set of properties to clone. Lease-related properties will not be cloned, because a lease associated with the base blob is not copied to the snapshot. Gets or sets the cache-control value stored for the blob. The blob's cache-control value. Gets or sets the content-disposition value stored for the blob. The blob's content-disposition value. If this property has not been set for the blob, it returns null. Gets or sets the content-encoding value stored for the blob. The blob's content-encoding value. If this property has not been set for the blob, it returns null. Gets or sets the content-language value stored for the blob. The blob's content-language value. If this property has not been set for the blob, it returns null. Gets the size of the blob, in bytes. The blob's size in bytes. Gets or sets the content-MD5 value stored for the blob. The blob's content-MD5 hash. Gets or sets the content-type value stored for the blob. The blob's content-type value. If this property has not been set for the blob, it returns null. Gets the blob's ETag value. The blob's ETag value. Gets the the last-modified time for the blob, expressed as a UTC value. The blob's last-modified time, in UTC format. Gets the type of the blob. A object that indicates the type of the blob. Gets the blob's lease status. A object that indicates the blob's lease status. Gets the blob's lease state. A object that indicates the blob's lease state. Gets the blob's lease duration. A object that indicates the blob's lease duration. If the blob is a page blob, gets the blob's current sequence number. The blob's current sequence number. Represents a set of timeout and retry policy options that may be specified for a request against the Blob service. Stores the parallelism factor. Default is 32 MB. Initializes a new instance of the class. Clones an instance of BlobRequestOptions so that we can apply defaults. BlobRequestOptions instance to be cloned. Gets or sets the absolute expiry time across all potential retries for the request. Gets or sets the retry policy. The retry policy. Gets or sets the location mode of the request. The location mode of the request. Gets or sets the server timeout interval for the request. The server timeout interval for the request. Gets or sets the maximum execution time across all potential retries for the request. A representing the maximum execution time for retries for the request. Gets or sets the number of blocks that may be simultaneously uploaded when uploading a blob that is greater than the value specified by the property in size. The number of parallel operations that may proceed. Gets or sets the maximum size of a blob in bytes that may be uploaded as a single blob. The maximum size of a blob, in bytes, that may be uploaded as a single blob, ranging from between 1 and 64 MB inclusive. Gets or sets a value to calculate and send/validate content MD5 for transactions. Use true to calculate and send/validate content MD5 for transactions; otherwise, false. Gets or sets a value to indicate that an MD5 hash will be calculated and stored when uploading a blob. Use true to calculate and store an MD5 hash when uploading a blob; otherwise, false. Gets or sets a value to indicate that MD5 validation will be disabled when downloading blobs. Use true to disable MD5 validation; false to enable MD5 validation. Represents a segment of results, with continuation information for pagination scenarios. Gets an enumerable collection of results. An enumerable collection of results. Gets the continuation token used to retrieve the next segment of results. Returns null if there are no more results. The continuation token. The type of a blob. Not specified. A page blob. A block blob. Indicates whether to list only committed blocks, only uncommitted blocks, or all blocks. Committed blocks. Uncommitted blocks. Both committed and uncommitted blocks. Indicates which block lists should be searched to find a specified block. Search the committed block list only. Search the uncommitted block list only. Search the uncommitted block list first, and if the block is not found there, search the committed block list. Specifies which details to include when listing the containers in this storage account. No additional details. Retrieve container metadata. Retrieve all available details. Represents a segment of results and contains continuation and pagination information. Gets an enumerable collection of results. An enumerable collection of results. Gets the continuation token used to retrieve the next segment of results. The continuation token. Represents the attributes of a copy operation. Gets the ID of the copy operation. A copy ID string. Gets the time the copy operation completed, and indicates whether completion was due to a successful copy, the cancelling of the operation, or a failure. A containing the completion time, or null if the operation has not completed. Gets the status of the copy operation. A enumeration indicating the status of the operation. Gets the source URI of a copy operation. A indicating the source of a copy operation, or null. Gets the number of bytes copied in the operation so far. The number of bytes copied in the operation so far, or null. Gets the total number of bytes in the source of the copy. The number of bytes in the source, or null. Gets the description of the current status, if any. A status description string, or null. Represents the status of a copy blob operation. The copy status is invalid. The copy operation is pending. The copy operation succeeded. The copy operation has been aborted. The copy operation encountered an error. The set of options describing delete operation. Delete blobs but not snapshots. Delete the blob and its snapshots. Delete the blob's snapshots only. Describes actions that can be performed on a lease. Acquire the lease. Renew the lease. Release the lease. Break the lease. Change the lease ID. The lease duration of a resource. The lease duration is not specified. The lease duration is finite. The lease duration is infinite. The lease state of a resource. The lease state is not specified. The lease is in the Available state. The lease is in the Leased state. The lease is in the Expired state. The lease is in the Breaking state. The lease is in the Broken state. The lease status of a resource. The lease status is not specified. The resource is locked. The resource is available to be locked. Represents a block retrieved from the blob's block list. Gets the name of the block. The block name. Gets the size of block in bytes. The block size. Gets a value indicating whether or not the block has been committed. True if the block has been committed; otherwise, false. Represents a range of pages in a page blob. Initializes a new instance of the class. The starting offset. The ending offset. Returns the content of the page range as a string. The content of the page range. Gets the starting offset of the page range. The starting offset. Gets the ending offset of the page range. The ending offset. Describes actions that can be performed on a page blob sequence number. Sets the sequence number to be the higher of the value included with the request and the value currently stored for the blob. Sets the sequence number to the value included with the request. Increments the value of the sequence number by 1. Represents the optional headers that can be returned with blobs accessed using SAS. Initializes a new instance of the class. Initializes a new instance of the class based on an existing instance. The set of to clone. Gets or sets the cache-control header returned with the blob. The cache-control value. Gets or sets the content-disposition header returned with the blob. The content-disposition value. Gets or sets the content-encoding header returned with the blob. The content-encoding value. Gets or sets the content-language header returned with the blob. The content-language value. Gets or sets the content-type header returned with the blob. The content-type value. Specifies the set of possible permissions for a shared access policy. No shared access granted. Read access granted. Write access granted. Delete access granted for blobs. List access granted. Represents the collection of shared access policies defined for a container. Adds the specified key and value to the collection of shared access policies. The key of the value to add. The value to add the collection of shared access policies. Determines whether the collection of shared access policies contains the specified key. The key to locate in the collection of shared access policies. true if the collection of shared access policies contains an element with the specified key; otherwise, false. Removes the value with the specified key from the shared access policies collection. The key of the item to remove. true if the element is successfully found and removed; otherwise, false. This method returns false if the key is not found. Gets the item associated with the specified key. The key of the value to get. The item to get. The item associated with the specified key, if the key is found; otherwise, the default value for the type. Adds the specified key/ value, stored in a , to the collection of shared access policies. The object, containing a key/ value pair, to add to the shared access policies collection. Removes all keys and values from the shared access collection. Determines whether the collection of shared access policies contains the key and value in the specified object. A object containing the key and value to search for. true if the shared access policies collection contains the specified key/value; otherwise, false. Copies each key/ value pair in the shared access policies collection to a compatible one-dimensional array, starting at the specified index of the target array. The one-dimensional array of objects that is the destination of the elements copied from the shared access policies collection. The zero-based index in at which copying begins. Removes the value, specified in the object, from the shared access policies collection. The object, containing a key and value, to remove from the shared access policies collection. true if the item was successfully removed; otherwise, false. Returns an enumerator that iterates through the collection of shared access policies. An of type . Returns an enumerator that iterates through the collection of shared access policies. An object that can be used to iterate through the collection of shared access policies. Gets a collection containing the keys in the shared access policies collection. A collection containing the keys in the of shared access policies collection. Gets a collection containing the values in the shared access policies collection. A collection of items in the shared access policies collection. Gets or sets the item associated with the specified key. The key of the value to get or set. The item associated with the specified key, or null if key is not in the shared access policies collection. Gets the number of key/ value pairs contained in the shared access policies collection. The number of key/ value pairs contained in the shared access policies collection. Gets a value indicating whether the collection of shared access policies is read-only. true if the collection of shared access policies is read-only; otherwise, false. Represents a shared access policy, which specifies the start time, expiry time, and permissions for a shared access signature. Initializes a new instance of the class. Converts the permissions specified for the shared access policy to a string. The shared access permissions. The shared access permissions in string format. Constructs a object from a permissions string. The shared access permissions in string format. A set of shared access permissions. Gets or sets the start time for a shared access signature associated with this shared access policy. The shared access start time. Gets or sets the expiry time for a shared access signature associated with this shared access policy. The shared access expiry time. Gets or sets the permissions for a shared access signature associated with this shared access policy. The permissions. Parses the response XML from an operation to set the access policy for a container. Parses the response XML from an operation to set the access policy for a cloud object. The policy type to be filled. Provides a base class that is used internally to parse XML streams from storage service operations. The type to be parsed. Indicates that all parsable objects have been consumed. This field is reserved and should not be used. Stores any objects that have not yet been parsed. This field is reserved and should not be used. The reader used for parsing. This field is reserved and should not be used. The IEnumerator over the parsed content. Used to make sure that parsing is only done once, since a stream is not re-entrant. Initializes a new instance of the ResponseParsingBase class. The stream to be parsed. Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. Parses the XML response. This method is reserved and should not be used. A collection of enumerable objects. Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources, and optional managed resources. True to release both managed and unmanaged resources; otherwise, false. This method is reserved and should not be used. True when the object is consumable. Parses the XML and close. A list of parsed results. Gets the parsable objects. This method is reserved and should not be used. The objects to parse. Initializes a new instance of the AccessPolicyResponseBase class. The stream to be parsed. Parses the current element. The shared access policy element to parse. The shared access policy. Parses the response XML from a Set Container ACL operation to retrieve container-level access policy data. A list of enumerable key-value pairs. Gets an enumerable collection of container-level access policy identifiers. An enumerable collection of container-level access policy identifiers. Initializes a new instance of the BlobAccessPolicyResponse class. The stream to be parsed. Parses the current element. The shared access policy element to parse. The shared access policy. Represents a container item returned in the XML response for a container listing operation. Initializes a new instance of the class. Gets the user-defined metadata for the container. The container's metadata, as a collection of name-value pairs. Gets the container's system properties. The container's properties. Gets the name of the container. The container's name. Gets the container's URI. The absolute URI to the container. Provides error code strings that are specific to the Blob service. Error code that may be returned when a block ID is invalid. Error code that may be returned when a blob with the specified address cannot be found. Error code that may be returned when a client attempts to create a blob that already exists. Error code that may be returned when the specified block or blob is invalid. Error code that may be returned when a block list is invalid. The specified container was not found. The specified container already exists. The specified container is disabled. The specified container is being deleted. Error code that may be returned when there is currently no lease on the blob. Error code that may be returned when there is currently no lease on the container. Error code that may be returned when a lease ID was specified, but the lease has expired. Error code that may be returned when the lease ID specified did not match the lease ID for the blob. Error code that may be returned when the lease ID specified did not match the lease ID for the container. Error code that may be returned when there is currently a lease on the resource and no lease ID was specified in the request. Error code that may be returned when there is currently no lease on the resource. Error code that may be returned when the lease ID specified did not match the lease ID. Error code that may be returned when there is already a lease present. Error code that may be returned when the lease has already been broken and cannot be broken again. Error code that may be returned when the lease ID matched, but the lease has been broken explicitly and cannot be renewed. Error code that may be returned when the lease ID matched, but the lease is breaking and cannot be acquired. Error code that may be returned when the lease ID matched, but the lease is breaking and cannot be changed. Error code that may be returned when the copy ID specified in an Abort Copy operation does not match the current pending copy ID. Error code that may be returned when an Abort Copy operation is called when there is no pending copy. Error code that may be returned when an attempt to modify the destination of a pending copy is made. Error code that may be returned when the source of a copy cannot be accessed. Error code that may be returned when the destination of a copy operation has a lease of fixed duration. Provides a set of parameters for a blob listing operation. Represents the listing context for enumeration operations. Initializes a new instance of the class. The resource name prefix. The maximum number of resources to return in a single operation, up to the per-operation limit of 5000. Gets or sets the Prefix value. The Prefix value. Gets or sets the MaxResults value. The MaxResults value. Gets or sets the Marker value. The Marker value. Initializes a new instance of the class. The blob prefix. The maximum number of results to return. The blob delimiter. The include parameter. Gets or sets the delimiter for a blob listing operation. The delimiter to use to traverse the virtual hierarchy of blobs. The delimiter parameter enables the caller to traverse the blob namespace by using a user-configured delimiter. Using this parameter, it is possible to traverse a virtual hierarchy of blobs as though it were a file system. Gets or sets the details for the listing operation, which indicates the types of data to include in the response. The details to include in the listing operation. The include parameter specifies that the response should include one or more of the following subsets: snapshots, metadata, uncommitted blobs. Provides a set of helper methods for constructing a request against the Blob service. Converts the date time to snapshot string. The date time. The converted string. Writes a collection of shared access policies to the specified stream in XML format. A collection of shared access policies. An output stream. Writes the body of the block list to the specified stream in XML format. An enumerable collection of objects. The stream to which the block list is written. Provides methods for parsing the response from an operation to return a block list. Initializes a new instance of the class. The stream to be parsed. Reads a block item for block listing. Whether we are currently listing committed blocks or not Block listing entry Parses the XML response returned by an operation to retrieve a list of blocks. An enumerable collection of objects. Gets an enumerable collection of objects from the response. An enumerable collection of objects. Provides methods for parsing the response from an operation to get a range of pages for a page blob. Initializes a new instance of the class. The stream of page ranges to be parsed. Reads a page range. Page range entry Parses the XML response for an operation to get a range of pages for a page blob. An enumerable collection of objects. Gets an enumerable collection of objects from the response. An enumerable collection of objects. Represents an item that may be returned by a blob listing operation. Represents a blob item returned in the XML response for a blob listing operation. Initializes a new instance of the class. The name of the blob. The blob's attributes. Stores the blob item's attributes. Gets the name of the blob item. The name of the blob item. Gets the blob item's system properties. The blob item's properties. Gets the user-defined metadata for the blob item. The blob item's metadata, as a collection of name-value pairs. Gets the blob item's URI. The absolute URI to the blob item. Gets the date and time that the blob snapshot was taken, if this blob is a snapshot. The blob's snapshot time if the blob is a snapshot; otherwise, null. If the blob is not a snapshot, the value of this property is null. Gets the state of the most recent or pending copy operation. A object containing the copy state, or null if no copy blob state exists for this blob. Represents the blob name prefix that is returned in the XML response for a blob listing operation. Gets the blob name prefix. The blob name prefix. Provides methods for parsing the response from a blob listing operation. Stores the blob prefix. Signals when the blob prefix can be consumed. Stores the marker. Signals when the marker can be consumed. Stores the blob delimiter. Signals when the blob delimiter can be consumed. Stores the max results. Signals when the max results can be consumed. Stores the next marker. Signals when the next marker can be consumed. Initializes a new instance of the class. The stream to be parsed. Parses a blob entry in a blob listing response. Blob listing entry Parses a blob prefix entry in a blob listing response. Blob listing entry Parses the response XML for a blob listing operation. An enumerable collection of objects that implement . Gets the listing context from the XML response. A set of parameters for the listing operation. Gets an enumerable collection of objects that implement from the response. An enumerable collection of objects that implement . Gets the Prefix value provided for the listing operation from the XML response. The Prefix value. Gets the Marker value provided for the listing operation from the XML response. The Marker value. Gets the Delimiter value provided for the listing operation from the XML response. The Delimiter value. Gets the MaxResults value provided for the listing operation from the XML response. The MaxResults value. Gets the NextMarker value from the XML response, if the listing was not complete. The NextMarker value. Provides methods for parsing the response from a container listing operation. Stores the container prefix. Signals when the container prefix can be consumed. Stores the marker. Signals when the marker can be consumed. Stores the max results. Signals when the max results can be consumed. Stores the next marker. Signals when the next marker can be consumed. Initializes a new instance of the class. The stream to be parsed. Reads a container entry completely including its properties and metadata. Container listing entry Parses the response XML for a container listing operation. An enumerable collection of objects. Gets the listing context from the XML response. A set of parameters for the listing operation. Gets an enumerable collection of objects from the response. An enumerable collection of objects. Gets the Prefix value provided for the listing operation from the XML response. The Prefix value. Gets the Marker value provided for the listing operation from the XML response. The Marker value. Gets the MaxResults value provided for the listing operation from the XML response. The MaxResults value. Gets the NextMarker value from the XML response, if the listing was not complete. The NextMarker value. Describes actions that may be used for writing to a page blob or clearing a set of pages. Update the page with new data. Clear the page. Represents a block in a block list. Initializes a new instance of the class. The block ID. One of the enumeration values that specifies in which block lists to search for the block. Gets the block ID. The block ID. Gets a value that indicates which block lists to search for the block. One of the enumeration values that specifies in which block lists to search for the block. Enumeration controlling the options for updating queue messages. Update the message visibility timeout. Update the message content. Represents a continuation token returned by the Queue service. continuation tokens are used in methods that return a object, such as . Gets an XML representation of an object. An that describes the XML representation of the object that is produced by the method and consumed by the method. Generates a serializable continuation token from its XML representation. The stream from which the continuation token is deserialized. Converts a serializable continuation token into its XML representation. The stream to which the continuation token is serialized. Gets or sets the version for continuing results for CloudQueue enumeration operations. The version. Gets or sets the type element (blob, queue, table) for continuing results for CloudQueue enumeration operations. The type element. Gets or sets the NextMarker for continuing results for CloudQueue enumeration operations. The next marker. Gets or sets the storage location that the continuation token applies to. The storage location that the continuation token applies to. Enum for Queue message type. Internal use only. Indicates the message object stores the raw text string. Indicates the message object stores the Base64-Encoded representation of the raw data. Represents a set of timeout and retry policy options that may be specified for a request against the Queue service. Initializes a new instance of the class. Clones an instance of QueueRequestOptions so that we can apply defaults. QueueRequestOptions instance to be cloned. Gets or sets the absolute expiry time across all potential retries for the request. Gets or sets the retry policy for the request. The retry policy delegate. Gets or sets the location mode of the request. The location mode of the request. Gets or sets the server timeout for the request. The client and server timeout interval for the request. Gets or sets the maximum execution time across all potential retries for the request. A representing the maximum execution time for retries for the request. Represents a segment of results, with continuation information for pagination scenarios. Gets an enumerable collection of results. An enumerable collection of results. Gets the continuation token used to retrieve the next segment of results. Returns null if there are no more results. The continuation token. Specifies the set of possible permissions for a shared access queue policy. No shared access granted. Permission to peek messages and get queue metadata granted. Permission to add messages granted. Permissions to update messages granted. Permission to get and delete messages granted. Represents the collection of shared access policies defined for a queue. Adds the specified key and value to the collection of shared access policies. The key of the value to add. The value to add the collection of shared access policies. Determines whether the collection of shared access policies contains the specified key. The key to locate in the collection of shared access policies. true if the collection of shared access policies contains an element with the specified key; otherwise, false. Removes the value with the specified key from the shared access policies collection. The key of the item to remove. true if the element is successfully found and removed; otherwise, false. This method returns false if the key is not found. Gets the item associated with the specified key. The key of the value to get. The item to get. The item associated with the specified key, if the key is found; otherwise, the default value for the type. Adds the specified key/ value, stored in a , to the collection of shared access policies. The object, containing a key/ value pair, to add to the shared access policies collection. Removes all keys and values from the shared access collection. Determines whether the collection of shared access policies contains the key and value in the specified object. A object containing the key and value to search for. true if the shared access policies collection contains the specified key/value; otherwise, false. Copies each key/ value pair in the shared access policies collection to a compatible one-dimensional array, starting at the specified index of the target array. The one-dimensional array of objects that is the destination of the elements copied from the shared access policies collection. The zero-based index in at which copying begins. Removes the value, specified in the object, from the shared access policies collection. The object, containing a key and value, to remove from the shared access policies collection. true if the item was successfully removed; otherwise, false. Returns an enumerator that iterates through the collection of shared access policies. An of type . Returns an enumerator that iterates through the collection of shared access policies. An object that can be used to iterate through the collection of shared access policies. Gets a collection containing the keys in the shared access policies collection. A collection containing the keys in the of shared access policies collection. Gets a collection containing the values in the shared access policies collection. A collection of items in the shared access policies collection. Gets or sets the item associated with the specified key. The key of the value to get or set. The item associated with the specified key, or null if key is not in the shared access policies collection. Gets the number of key/ value pairs contained in the shared access policies collection. The number of key/ value pairs contained in the shared access policies collection. Gets a value indicating whether the collection of shared access policies is read-only. true if the collection of shared access policies is read-only; otherwise, false. Represents a shared access policy for a queue, which specifies the start time, expiry time, and permissions for a shared access signature. Initializes a new instance of the SharedAccessQueuePolicy class. Converts the permissions specified for the shared access policy to a string. The shared access permissions. The shared access permissions in string format. Constructs a object from a permissions string. The shared access permissions in string format. A set of shared access permissions. Gets or sets the start time for a shared access signature associated with this shared access policy. The shared access start time. Gets or sets the expiry time for a shared access signature associated with this shared access policy. The shared access expiry time. Gets or sets the permissions for a shared access signature associated with this shared access policy. The permissions. Provides methods for parsing the response from an operation to get messages from a queue. Initializes a new instance of the class. The stream of messages to parse. Parses a message entry in a queue get messages response. Message entry Parses the XML response returned by an operation to get messages from a queue. An enumerable collection of objects. Gets an enumerable collection of objects from the response. An enumerable collection of objects. Provides methods for parsing the response from a queue listing operation. Stores the container prefix. Signals when the container prefix can be consumed. Stores the marker. Signals when the marker can be consumed. Stores the max results. Signals when the max results can be consumed. Stores the next marker. Signals when the next marker can be consumed. Initializes a new instance of the class. The stream to be parsed. Parses a queue entry in a queue listing response. Queue listing entry Parses the response XML for a queue listing operation. An enumerable collection of objects. Gets the listing context from the XML response. A set of parameters for the listing operation. Gets an enumerable collection of objects from the response. An enumerable collection of objects. Gets the Prefix value provided for the listing operation from the XML response. The Prefix value. Gets the Marker value provided for the listing operation from the XML response. The Marker value. Gets the MaxResults value provided for the listing operation from the XML response. The MaxResults value. Gets the NextMarker value from the XML response, if the listing was not complete. The NextMarker value. Parses the response XML from an operation to set the access policy for a queue. Initializes a new instance of the QueueAccessPolicyResponse class. The stream to be parsed. Parses the current element. The shared access policy element to parse. The shared access policy. Represents a queue item returned in the XML response for a queue listing operation. Initializes a new instance of the class. Initializes a new instance of the class. The name of the queue. The Uri of the queue. The queue's metadata. Gets the user-defined metadata for the queue. The queue's metadata, as a collection of name-value pairs. Gets the name of the queue. The queue's name. Gets the queue's URI. The absolute URI to the queue. Provides error code strings that are specific to the Queue service. Error code that may be returned when the specified queue was not found. Error code that may be returned when the specified queue is disabled. Error code that may be returned when the specified queue already exists. Error code that may be returned when the specified queue is not empty. Error code that may be returned when the specified queue is being deleted. Error code that may be returned when the specified pop receipt does not match. Error code that may be returned when one or more request parameters are invalid. Error code that may be returned when the specified message was not found. Error code that may be returned when the specified message is too large. Error code that may be returned when the specified marker is invalid. Provides a set of parameters for a queue listing operation. Initializes a new instance of the class. The queue prefix. The maximum number of results to return. The include parameter. Gets or sets the details for the listing operation, which indicates the types of data to include in the response. The details to include in the listing operation. Specifies which details to include when listing the queues in this storage account. No additional details. Retrieve queue metadata. Retrieve all available details. Represents a message retrieved from a queue. Initializes a new instance of the class. Gets the message expiration time. The message expiration time. Gets the message ID. The message ID. Gets the time the message was added to the queue. The message insertion time. Gets the time the message is next visible. The time the message is next visible. Gets the pop receipt for the message. The message's pop receipt. Gets the text of the message. The message text. Gets the number of times this message has been dequeued. The dequeue count. Represents the permissions for a queue. Initializes a new instance of the class. Gets the set of shared access policies for the queue. The set of shared access policies for the queue. Provides a set of helper methods for constructing a request against the Queue service. Writes a collection of shared access policies to the specified stream in XML format. A collection of shared access policies. An output stream. Writes a message to the specified stream in XML format. The message body. An output stream. Gets or sets the number of entities the table query will return. The maximum number of entities for the table query to return. Gets or sets the filter expression to use in the table query. A string containing the filter expression to use in the query. Gets or sets the property names of the table entity properties to return when the table query is executed. A list of strings containing the property names of the table entity properties to return when the query is executed. Provides a set of extension methods for objects of type . Specifies a set of on the query. The entity type of the query. A query that implements . A object that specifies execution options, such as retry policy and timeout settings, for the operation. A object with the specified request options set. Specifies an for the query. The entity type of the query. A query that implements . An object for tracking the current operation. A object with the specified operation context. Specifies an entity resolver for the query. The entity type of the query. The type of the resolver. A query that implements . The entity resolver, of type . A with the specified resolver. Specifies that a query be returned as a object. The entity type of the query. A query that implements . An object of type . A type which allows callers direct access to the property map of the entity. This class eliminates the use of reflection for serialization and deserialization. An interface required for table entity types. The interface declares getter and setter methods for the mandatory entity properties, and and methods for serialization and de-serialization of all entity properties using a property dictionary. Create classes implementing to customize property storage, retrieval, serialization and de-serialization, and to provide additional custom logic for a table entity. The storage client library includes two implementations of that provide for simple property access and serialization: implements and provides a simple property dictionary to store and retrieve properties. Use a for simple access to entity properties when only a subset of properties are returned (for example, by a select clause in a query), or for scenarios where your query can return multiple entity types with different properties. You can also use this type to perform bulk table updates of heterogeneous entities without losing property information. is an implementation of that uses reflection-based serialization and de-serialization behavior in its and methods. -derived classes with methods that follow a convention for types and naming are serialized and deserialized automatically. -derived classes must also provide a get-able and set-able public property of a type that is supported by the Windows Azure Table service. Populates the entity's properties from the data values in the dictionary. The dictionary of string property names to data values to deserialize and store in this table entity instance. An object used to track the execution of the operation. Serializes the of property names mapped to data values from the entity instance. An object used to track the execution of the operation. A dictionary of property names to data typed values created by serializing this table entity instance. Gets or sets the entity's partition key. The entity's partition key. Gets or sets the entity's row key. The entity's row key. Gets or sets the entity's timestamp. The entity's timestamp. The property is populated by the Windows Azure Table Service. Gets or sets the entity's current ETag. Set this value to '*' in order to blindly overwrite an entity as part of an update operation. The entity's timestamp. Initializes a new instance of the class. Initializes a new instance of the class with the specified partition key and row key. The partition key value for the entity. The row key value for the entity. Initializes a new instance of the class with the entity's partition key, row key, ETag (if available/required), and properties. The entity's partition key. The entity's row key. The entity's current ETag. The entity's properties, indexed by property name. Initializes a new instance of the class with the entity's partition key, row key, timestamp, ETag (if available/required), and properties. The entity's partition key. The entity's row key. The timestamp for this entity as returned by Windows Azure. The entity's current ETag; set to null to ignore the ETag during subsequent update operations. An containing a map of property names to data typed values to store in the new . Deserializes this instance using the specified of property names to values of type . A collection containing the of string property names mapped to values of type to store in this instance. An object used to track the execution of the operation. Serializes the of property names mapped to values of type from this instance. An object used to track the execution of the operation. A collection containing the map of string property names to values of type stored in this instance. Gets or sets the properties in the table entity, indexed by property name. The entity properties. Gets or sets the entity's partition key. The entity partition key. Gets or sets the entity's row key. The entity row key. Gets or sets the entity's timestamp. The entity timestamp. Gets or sets the entity's current ETag. Set this value to '*' to blindly overwrite an entity as part of an update operation. The entity ETag. Gets or sets the entity's property, given the name of the property. The name of the property. The property. Enumeration containing the types of values that can be stored in a table entity property. Represents fixed- or variable-length character data. Represents fixed- or variable-length binary data. Represents the mathematical concept of binary-valued logic. Represents date and time. Represents a floating point number with 15 digits precision that can represent values with approximate range of +/- 2.23e -308 through +/- 1.79e +308. Represents a 16-byte (128-bit) unique identifier value. Represents a signed 32-bit integer value. Represents a signed 64-bit integer value. Class for storing information about a single property in an entity in a table. Creates a new object that represents the specified offset value. The value for the new . A new of the offset type. Creates a new object that represents the specified byte array. The value for the new . A new of the byte array. Creates a new object that represents the specified value. The value for the new . A new of the type. Creates a new object that represents the specified value. The value for the new . A new of the type. Creates a new object that represents the specified value. The value for the new . A new of the type. Creates a new object that represents the specified value. The value for the new . A new of the type. Creates a new object that represents the specified value. The value for the new . A new of the type. Creates a new object that represents the specified value. The value for the new . A new of the type. Initializes a new instance of the class by using the byte array value of the property. The value for the new . Initializes a new instance of the class by using the value of the property. The value for the new . Initializes a new instance of the class by using the value of the property. The value for the new . Initializes a new instance of the class by using the value of the property. The value for the new . Initializes a new instance of the class by using the value of the property. The value for the new . Initializes a new instance of the class by using the value of the property. The value for the new . Initializes a new instance of the class by using the value of the property. The value for the new . Initializes a new instance of the class by using the value of the property. The value for the new . Initializes a new instance of the class by using the value of the property. The value for the new . Initializes a new instance of the EntityProperty class given the EdmType of the property (the value must be set by a public constructor). Compares the given object (which is probably an ) for equality with this object. The other object. true if the objects are equivalent; false otherwise. Compares the given object (which is probably an ) for equality with this object. The other object. true if the objects are equivalent; false otherwise. Gets the hash code for this entity property. The hash code for the entity property. Creates an from the object. The value of the object. The reference to the object created. Ensures that the given type matches the type of this entity property; throws an exception if the types do not match. Gets the as a generic object. Gets the of this object. The of this object. Gets or sets the byte array value of this object. An exception will be thrown if you attempt to set this property to anything other than an byte array. The byte array value of this object. Gets or sets the value of this object. An exception will be thrown if you attempt to set this property to anything other than an Object. The value of this object. Gets or sets the offset value of this object. An exception will be thrown if you attempt to set this property to anything other than a object. The offset value of this object. Gets or sets the value of this object. An exception will be thrown if you attempt to set this property to anything other than a object. The value of this object. Gets or sets the value of this object. An exception will be thrown if you attempt to set this property to anything other than a object. The value of this object. Gets or sets the value of this object. An exception will be thrown if you attempt to set this property to anything other than an Object. The value of this object. Gets or sets the value of this object. An exception will be thrown if you attempt to set this property to anything other than an Object. The value of this object. Gets or sets the value of this object. An exception will be thrown if you attempt to set this property to anything other than a object. The value of this object. Returns a delegate for resolving entities. The type into which the query results are projected. The partition key. The row key. The timestamp. A dictionary of properties. The ETag. Defines the set of comparison operators that may be used for constructing queries. Represents the Equal operator. Represents the Not Equal operator. Represents the Greater Than operator. Represents the Greater Than or Equal operator. Represents the Less Than operator. Represents the Less Than or Equal operator. Specifies the set of possible permissions for a shared access table policy. No shared access granted. Permission to query entities granted. Permission to add entities granted. Permission to modify entities granted. Permission to delete entities granted. Represents the collection of shared access policies defined for a table. Adds the specified key and value to the collection of shared access policies. The key of the value to add. The value to add to the collection of shared access policies. Determines whether the collection of shared access policies contains the specified key. The key to locate in the collection of shared access policies. true if the collection of shared access policies contains an element with the specified key; otherwise, false. Removes the value with the specified key from the shared access policies collection. The key of the item to remove. true if the element is successfully found and removed; otherwise, false. This method returns false if the key is not found. Gets the item associated with the specified key. The key of the value to get. The item to get. The item associated with the specified key, if the key is found; otherwise, the default value for the type. Adds the specified key/ value, stored in a , to the collection of shared access policies. The object, containing a key/ value pair, to add to the shared access policies collection. Removes all keys and values from the shared access collection. Determines whether the collection of shared access policies contains the key and value in the specified object. A object containing the key and value to search for. true if the shared access policies collection contains the specified key/value; otherwise, false. Copies each key/ value pair in the shared access policies collection to a compatible one-dimensional array, starting at the specified index of the target array. The one-dimensional array of objects that is the destination of the elements copied from the shared access policies collection. The zero-based index in at which copying begins. Removes the value, specified in the object, from the shared access policies collection. The object, containing a key and value, to remove from the shared access policies collection. true if the item was successfully removed; otherwise, false. Returns an enumerator that iterates through the collection of shared access policies. An of type . Returns an enumerator that iterates through the collection of shared access policies. An object that can be used to iterate through the collection of shared access policies. Gets a collection containing the keys in the shared access policies collection. A collection containing the keys in the of shared access policies collection. Gets a collection containing the values in the shared access policies collection. A collection of items in the shared access policies collection. Gets or sets the item associated with the specified key. The key of the value to get or set. The item associated with the specified key, or null if key is not in the shared access policies collection. Gets the number of key/ value pairs contained in the shared access policies collection. The number of key/ value pairs contained in the shared access policies collection. Gets a value indicating whether the collection of shared access policies is read-only. true if the collection of shared access policies is read-only; otherwise, false. Represents a shared access policy, which specifies the start time, expiry time, and permissions for a shared access signature. Initializes a new instance of the SharedAccessTablePolicy class. Converts the permissions specified for the shared access policy to a string. The shared access permissions. The shared access permissions in string format. Constructs a object from a permissions string. The shared access permissions in string format. A set of shared access permissions. Gets or sets the start time for a shared access signature associated with this shared access policy. The shared access start time. Gets or sets the expiry time for a shared access signature associated with this shared access policy. The shared access expiry time. Gets or sets the permissions for a shared access signature associated with this shared access policy. The permissions. Represents a continuation token for listing operations. A method that may return a partial set of results via a object also returns a continuation token, which can be used in a subsequent call to return the next set of available results. Gets an XML representation of an object. An that describes the XML representation of the object that is produced by the method and consumed by the method. Generates a serializable continuation token from its XML representation. The stream from which the continuation token is deserialized. Converts a serializable continuation token into its XML representation. The stream to which the continuation token is serialized. Gets or sets the version for continuing results for enumeration operations. The version. Gets or sets the type element (blob, queue, table) for continuing results for enumeration operations. The type element. Gets or sets the next partition key for enumeration operations. The next partition key. Gets or sets the next row key for enumeration operations. The next row key. Gets or sets the next table name for enumeration operations. The name of the next table. Gets or sets the storage location that the continuation token applies to. The storage location that the continuation token applies to. Represents the base object type for a table entity in the Table service. provides a base implementation for the interface that provides and methods that by default serialize and deserialize all properties via reflection. A table entity class may extend this class and override the and methods to provide customized or better performing serialization logic. Initializes a new instance of the class. Initializes a new instance of the class with the specified partition key and row key. The partition key of the to be initialized. The row key of the to be initialized. Deserializes this instance using the specified of property names to data typed values. The map of string property names to data values to deserialize and store in this table entity instance. An object used to track the execution of the operation. Deserializes a custom entity instance using the specified of property names to data typed values. Custom entity instance being deserialized. The map of string property names to data values to deserialize and store in this entity instance. An object used to track the execution of the operation. Serializes the of property names mapped to data values from this instance. An object used to track the execution of the operation. A map of property names to data typed values created by serializing this table entity instance. Create a of objects for all the properties of the specified entity object. The entity object to serialize. An object used to track the execution of the operation. A of objects for all the properties of the specified entity object. Determines if the given property should be skipped based on its name, if it exposes a public getter and setter, and if the IgnoreAttribute is not defined. The PropertyInfo of the property to check An object used to track the execution of the operation. True if the property should be skipped, false otherwise. Compiles a ReadAction for the given type The type to compile for A ReadAction that deserializes the given entity type. Compiles a WriteFunc for the given type The type to compile for A WriteFunc that serializes the given entity type. Generates a Conditional Expression that will retrieve the given entity value by type and set it into the current property. The entity type The property to deserialize into An Expression that represents the entity instance An Expression that represents the current EntityProperty expression Gets the EntityProperty from the dictionary, or returns null. Similar to IDictionary.TryGetValue with logging support. The key value The Dictionary instance The operationContext to log to. Gets or sets the entity's partition key. The partition key of the entity. Gets or sets the entity's row key. The row key of the entity. Gets or sets the entity's timestamp. The timestamp of the entity. Gets or sets the entity's current ETag. Set this value to '*' in order to blindly overwrite an entity as part of an update operation. The ETag of the entity. Disables the ability to dynamically generate read and write lambdas at runtime. Setting this to false will clear out the static cache shared across all type instances that derive from TableEntity. This entities compiled Write Func This entities compiled Read Action Gets or sets the status of the property resolver cache for the . The property resolver cache caches known entity types and their respective property resolver dictionaries when entities are deserialized and the payload does not include JSON metadata. For most scenarios, disabling the property resolver cache is not recommended due to its effect on performance. Enumeration containing the types of operations that can be performed by a . Represents an insert operation. Represents a delete operation. Represents a replace operation. Represents a merge operation. Represents an insert or replace operation. Represents an insert or merge operation. Represents a retrieve operation. Defines the set of Boolean operators for constructing queries. Represents the And operator. Represents the Not operator. Represents the Or operator. Describes the payload formats supported for Tables. Use AtomPub. Use JSON with full metadata. Use JSON with minimal metadata. Use JSON with no metadata. Represents the permissions for a table. Initializes a new instance of the class. Gets the set of shared access policies for the container. The set of shared access policies for the container. Represents a segment of results and contains continuation token information. The type of the result that the segment contains. Stores the continuation token used to retrieve the next segment of results. Initializes a new instance of the class. The result. Returns an enumerator that iterates through the . An enumerator that iterates through the . Gets an enumerable collection of results. An enumerable collection of results. Gets a continuation token to use to retrieve the next set of results with a subsequent call to the operation. The continuation token. Represents a set of timeout and retry policy options that may be specified for a request against the Table service. Initializes a new instance of the class. Initializes a new instance of the class with the specified . The request options used to initialize this instance of the class. Gets or sets the absolute expiry time across all potential retries for the request. Gets or sets the retry policy for the request. The retry policy delegate. Gets or sets the location mode of the request. The location mode of the request. Gets or sets the server timeout for the request. The client and server timeout interval for the request. Gets or sets the maximum execution time for all potential retries for the request. A representing the maximum execution time for retries for the request. Gets or sets the that will be used for the request. The TablePayloadFormat to use. Gets or sets the delegate that is used to get the for an entity property given the partition key, row key, and the property name. Represents the result of a table operation. The class encapsulates the HTTP response and any table entity results returned by the Storage Service REST API operation called for a particular . Gets or sets the result returned by the as an . The result of the table operation as an . Gets or sets the HTTP status code returned by a request. The HTTP status code returned by a request. Gets or sets the ETag returned with the request results. The ETag returned with the request results. Represents a segment of results, with continuation information for pagination scenarios. Initializes a new instance of the class. The result. Stores the continuation token used to retrieve the next segment of results or null if there are no more results. Returns an enumerator that iterates through the segment of results. An enumerator that iterates through the segment of results. Gets an enumerable collection of results. An enumerable collection of results. Gets the continuation token used to retrieve the next segment of results. Returns null if there are no more results. The continuation token. Internal table service entity for creating tables. Stores the table name. Initializes a new instance of the class. Initializes a new instance of the class with the specified name. The name of the table. Determines whether the specified is equal to this instance. The to compare with this instance. Returns true if the specified is equal to this instance; otherwise, false. The parameter is null. Returns a hash code for this instance. A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. Gets or sets the table name. The name of the table. Parses the response XML from an operation to set the access policy for a table. Initializes a new instance of the TableAccessPolicyResponse class. The stream to be parsed. Parses the current element. The shared access policy element to parse. The shared access policy. A set of constants used in operations against the Table service. Stores the header prefix for continuation information. Stores the header suffix for the next partition key. Stores the header suffix for the next row key. Stores the table suffix for the next table name. Stores the maximum results the table service can return. The maximum size of a string property for the table service in bytes. The maximum size of a string property for the table service in bytes. The maximum size of a string property for the table service in chars. The name of the special table used to store tables. The name of the partition key property. The name of the row key property. The name of the Timestamp property. The name of the ETag property. The name of the property that stores the table name. The query filter clause name. The query top clause name. The query select clause name. The minimum DateTime supported. Provides error code strings that are specific to the Windows Azure Table service. The request uses X-HTTP-Method with an HTTP verb other than POST. The specified X-HTTP-Method is invalid. More than one X-HTTP-Method is specified. The specified table has no properties. A property is specified more than once. The specified table has no such property. A duplicate key property was specified. The specified table already exists. The specified table was not found. The specified entity was not found. The specified entity already exists. The partition key was not specified. One or more specified operators are invalid. The specified update condition was not satisfied. All properties must have values. The partition key property cannot be updated. The entity contains more properties than allowed. The entity is larger than the maximum size permitted. The property value is larger than the maximum size permitted. One or more value types are invalid. The specified table is being deleted. The Table service server is out of memory. The type of the primary key property is invalid. The property name exceeds the maximum allowed length. The property name is invalid. Batch operations are not supported for this operation type. JSON format is not supported. The specified method is not allowed. The specified operation is not yet implemented. Provides a set of helper methods for constructing a request against the Table service. Writes a collection of shared access policies to the specified stream in XML format. A collection of shared access policies. An output stream. Contains storage constants. Constant for the max value of ParallelOperationThreadCount for Block Blobs. Maximum number of shared access policy identifiers supported by server. Default Write Block Size used by Blob stream. The maximum size of a blob before it must be separated into blocks. The maximum size of a single block. The maximum size of a range get operation that returns content MD5. The maximum number of blocks. The maximum size of a blob with blocks. Default size of buffer for unknown sized requests. Common name to be used for all loggers. The size of a page in a PageBlob. A constant representing a kilo-byte (Non-SI version). A constant representing a megabyte (Non-SI version). A constant representing a megabyte (Non-SI version). XML element for committed blocks. XML element for uncommitted blocks. XML element for blocks. XML element for names. XML element for sizes. XML element for block lists. XML element for queue message lists. XML element for queue messages. XML element for message IDs. XML element for insertion times. XML element for expiration times. XML element for pop receipts. XML element for the time next visible fields. XML element for message texts. XML element for dequeue counts. XML element for page ranges. XML element for page list elements. XML element for page range start elements. XML element for page range end elements. XML element for delimiters. XML element for blob prefixes. XML element for content type fields. XML element for content type fields. XML element for content encoding fields. XML element for content language fields. XML element for content length fields. XML element for content MD5 fields. XML element for enumeration results. XML element for service endpoint. XML element for container name. XML element for blobs. XML element for prefixes. XML element for maximum results. XML element for markers. XML element for the next marker. XML element for the ETag. XML element for the last modified date. XML element for the Url. XML element for blobs. XML element for copy ID. XML element for copy status. XML element for copy source. XML element for copy progress. XML element for copy completion time. XML element for copy status description. Constant signaling a page blob. Constant signaling a block blob. Constant signaling the blob is locked. Constant signaling the blob is unlocked. Constant signaling the resource is available for leasing. Constant signaling the resource is leased. Constant signaling the resource's lease has expired. Constant signaling the resource's lease is breaking. Constant signaling the resource's lease is broken. Constant signaling the resource's lease is infinite. Constant signaling the resource's lease is fixed (finite). Constant for a pending copy. Constant for a successful copy. Constant for an aborted copy. Constant for a failed copy. Constant for unavailable geo-replication status. Constant for live geo-replication status. Constant for bootstrap geo-replication status. XML element for blob types. XML element for the lease status. XML element for the lease status. XML element for the lease status. XML element for snapshots. XML element for containers. XML element for a container. XML element for queues. Version 2 of the XML element for the queue name. XML element for the queue. XML element for properties. XML element for the metadata. XML element for an invalid metadata name. XML element for maximum results. XML element for committed blocks. XML element for uncommitted blocks. XML element for the latest. XML element for signed identifiers. XML element for a signed identifier. XML element for access policies. XML attribute for IDs. XML element for the start time of an access policy. XML element for the end of an access policy. XML element for the permissions of an access policy. The URI path component to access the messages in a queue. XML element for exception details. XML root element for errors. XML element for error codes. XML element for error codes returned by the preview tenants. XML element for error messages. XML element for error messages. XML element for exception messages. XML element for stack traces. Namespace of the entity container. Name of the entity container. Name of the entity set. Namespace name for primitive types. Default namespace name for Tables. Default name for Tables. Header value to set Accept to XML. Header value to set Accept to AtomPub. Header value to set Accept to JsonLight. Header value to set Accept to JsonFullMetadata. Header value to set Accept to JsonNoMetadata. Header value to set Content-Type to AtomPub. Header value to set Content-Type to JSON. The prefix used in all ETags. Default client side timeout for all service clients. Default server side timeout for all service clients. Maximum Retry Policy back-off Maximum allowed timeout for any request. Constants for HTTP headers. Specifies the value to use for UserAgent header. Specifies the value to use for UserAgent header. Master Windows Azure Storage header prefix. True Header. False Header. Header prefix for properties. Header prefix for metadata. Header that specifies content length. Header that specifies content language. Header that specifies the ETag value for the resource. Header for data ranges. Header for range content MD5. Header for storage version. Header for copy source. Header for the If-Match condition. Header for the If-Modified-Since condition. Header for the If-None-Match condition. Header for the If-Unmodified-Since condition. Header for the If-Sequence-Number-LE condition. Header for the If-Sequence-Number-LT condition. Header for the If-Sequence-Number-EQ condition. Header for the blob type. Header for snapshots. Header to delete snapshots. Header that specifies approximate message count of a queue. Header that specifies blob caching control. Response header that specifies the blob content disposition. Request header that specifies the blob content disposition. Header that specifies blob content encoding. Header that specifies blob content language. Header that specifies blob content MD5. Header that specifies blob content type. Header that specifies blob content length. Header that specifies blob sequence number. Header that specifies sequence number action. Header that specifies lease ID. Header that specifies lease status. Header that specifies lease status. Header that specifies page write mode. Header that specifies the date. Header indicating the request ID. Header indicating the client request ID. Header that specifies public access to blobs. Format string for specifying ranges. Current storage version header value. Every time this version changes, assembly version needs to be updated as well. Specifies the page blob type. Specifies the block blob type. Specifies only snapshots are to be included. Specifies snapshots are to be included. Header that specifies the pop receipt for a message. Header that specifies the next visible time for a message. Header that specifies whether to peek-only. Header that specifies whether data in the container may be accessed publicly and what level of access is to be allowed. Header that specifies the lease action to perform. Header that specifies the proposed lease ID for a leasing operation. Header that specifies the duration of a lease. Header that specifies the break period of a lease. Header that specifies the remaining lease time. Header that specifies the key name for explicit keys. Header that specifies the copy ID. Header that specifies the copy last modified time. Header that specifies the copy status. Header that specifies the copy progress. Header that specifies a copy error message. Header that specifies the copy action. The value of the copy action header that signifies an abort operation. Header that specifies the Accept type for the response payload. Header that specifies the Content type for the request payload. Specifies the value to use for UserAgent header. Specifies the comment to use for UserAgent header. Constants for query strings. Query component for snapshot time. Query component for the signed SAS start time. Query component for the signed SAS expiry time. Query component for the signed SAS resource. Query component for the SAS table name. Query component for the signed SAS permissions. Query component for the SAS start partition key. Query component for the SAS start row key. Query component for the SAS end partition key. Query component for the SAS end row key. Query component for the signed SAS identifier. Query component for the signing SAS key. Query component for the signed SAS version. Query component for SAS signature. Query component for SAS cache control. Query component for SAS content type. Query component for SAS content encoding. Query component for SAS content language. Query component for SAS content disposition. Query component for message time-to-live. Query component for message visibility timeout. Query component for the number of messages. Query component for message pop receipt. Query component for resource type. Query component for the operation (component) to access. Query component for the copy ID. Constants for Result Continuations Top Element for Continuation Tokens XML element for the next marker. XML element for the next partition key. XML element for the next row key. XML element for the next table name. XML element for the target location. XML element for the token version. Stores the current token version value. XML element for the token type. Specifies the blob continuation token type. Specifies the queue continuation token type. Specifies the table continuation token type. HTTP methods that are supported by CORS. Represents no HTTP method in a CORS rule. Represents the GET HTTP method in a CORS rule. Represents the HEAD HTTP method in a CORS rule. Represents the POST HTTP method in a CORS rule. Represents the PUT HTTP method in a CORS rule. Represents the DELETE HTTP method in a CORS rule. Represents the TRACE HTTP method in a CORS rule. Represents the OPTIONS HTTP method in a CORS rule. Represents the CONNECT HTTP method in a CORS rule. Represents the MERGE HTTP method in a CORS rule. Class representing the service properties pertaining to CORS. Constructs a CORS Properties object. Gets or sets CORS rules. The order of the list corresponds to precedence of rules. A collection containing CORS rules, limited to 5. Class representing the service properties pertaining to CORS. Gets or sets domain names allowed via CORS. A collection of strings containing the allowed domain names, limited to 64. Gets or sets response headers that should be exposed to client via CORS. A collection of strings containing exposed headers, limited to 64 defined headers and two prefixed headers. Gets or sets headers allowed to be part of the CORS request. A collection of strings containing allowed headers, limited to 64 defined headers and two prefixed headers. Gets or sets the HTTP methods permitted to execute for this origin. The allowed HTTP methods. Gets or sets the length of time in seconds that a preflight response should be cached by browser. The maximum number of seconds to cache the response. Class representing the geo-replication stats. The name of the status XML element. The name of the last sync time XML element. Initializes a new instance of the GeoReplicationStats class. Gets a from a string. The geo-replication status string. A enumeration. The string contains an unrecognized value. Constructs a GeoReplicationStats object from an XML element. The XML element. A GeoReplicationStats object containing the properties in the element. Gets or sets the status of geo-replication. The status of geo-replication. Gets or sets the last synchronization time. The last synchronization time. All primary writes preceding this value are guaranteed to be available for read operations. Primary writes following this point in time may or may not be available for reads. Enumeration representing the state of geo-replication in a service. Status of geo-replication is unavailable. Geo-replication is live. Data is being bootstrapped from primary to secondary. Enumeration representing the state of logging in a service. Logging is disabled. Log read operations. Log write operations. Log delete operations. Log all operations. Class representing the service properties pertaining to logging. Gets or sets the version of the analytics service. A string identifying the version of the service. Gets or sets the state of logging. A combination of flags describing the operations that are logged. Gets or sets the logging retention policy. The number of days to retain the logs. Enumeration representing the state of metrics collection in a service. Metrics collection is disabled. Service-level metrics collection is enabled. Service-level and API metrics collection are enabled. Class representing the service properties pertaining to metrics. Gets or sets the version of the analytics service. A string identifying the version of the service. Gets or sets the state of metrics collection. A value indicating which metrics to collect, if any. Gets or sets the logging retention policy. The number of days to retain the logs. Writes a collection of shared access policies to the specified stream in XML format. A collection of shared access policies. An output stream. A delegate that writes a policy to an XML writer. The type of policy to write. Gets the request id. The response from server. The request ID. Reads a collection of shared access policies from the specified object. A collection of shared access policies to be filled. A policy response object for reading the stream. The type of policy to read. Parses the metadata. The reader. A of metadata. Precondition: reader at <Metadata> Postcondition: reader after </Metadata> (<Metadata/> consumed) Class representing a set of properties pertaining to a cloud storage service. The name of the root XML element. The name of the logging XML element. The name of the metrics XML element. The name of the CORS XML element. The name of the minute metrics XML element. The name of the version XML element. The name of the delete operation XML element. The name of the read operation XML element. The name of the write operation XML element. The name of the retention policy XML element. The name of the enabled XML element. The name of the days XML element. The name of the include APIs XML element. The name of the default service version XML element. The name of the CORS Rule XML element. The name of the Allowed Origin XML element. The name of the Allowed Method XML element. The name of the Maximum Age XML element. The name of the Exposed Headers XML element. The name of the Allowed Headers XML element. Initializes a new instance of the ServiceProperties class. Constructs a ServiceProperties object from an XML document received from the service. The XML document. A ServiceProperties object containing the properties in the XML document. Converts these properties into XML for communicating with the service. An XML document containing the service properties. Generates XML representing the given retention policy. The number of days to retain, or null if the policy is disabled. An XML retention policy element. Generates XML representing the given metrics properties. The metrics properties. The XML name for these metrics. An XML metrics element. Generates XML representing the given logging properties. The logging properties. An XML logging element. Generates XML representing the given CORS properties. The CORS properties. An XML logging element. Constructs a LoggingProperties object from an XML element. The XML element. A LoggingProperties object containing the properties in the element. Constructs a MetricsProperties object from an XML element. The XML element. A MetricsProperties object containing the properties in the element. Constructs a CorsProperties object from an XML element. The XML element. A CorsProperties object containing the properties in the element. Constructs a retention policy (number of days) from an XML element. The XML element. The number of days to retain, or null if retention is disabled. Writes service properties to a stream, formatted in XML. The stream to which the formatted properties are to be written. Gets or sets the logging properties. The logging properties. Gets or sets the hour metrics properties. The metrics properties. Gets or sets the hour metrics properties. The metrics properties. Gets or sets the Cross Origin Resource Sharing (CORS) properties. The CORS properties. Gets or sets the minute metrics properties. The minute metrics properties. Gets or sets the default service version. The default service version identifier. Class representing a set of stats pertaining to a cloud storage service. The name of the root XML element. The name of the geo-replication XML element. Initializes a new instance of the ServiceStats class. Constructs a ServiceStats object from an XML document received from the service. The XML document. A ServiceStats object containing the properties in the XML document. Gets or sets the geo-replication stats. The geo-replication stats. Provides error code strings that are common to all storage services. The specified HTTP verb is not supported. The Content-Length header is required for this request. A required header was missing. A required XML node was missing. One or more header values are not supported. One or more XML nodes are not supported. One or more header values are invalid. One or more XML node values are invalid. A required query parameter is missing. One or more query parameters is not supported. One or more query parameters are invalid. One or more query parameters are out of range. The URI is invalid. The HTTP verb is invalid. The metadata key is empty. The request body is too large. The specified XML document is invalid. An internal error occurred. Authentication failed. The specified MD5 hash does not match the server value. The specified MD5 hash is invalid. The input is out of range. The input is invalid. The operation timed out. The specified resource was not found. The specified metadata is invalid. The specified metadata is too large. The specified condition was not met. The specified range is invalid. The specified container was not found. The specified container already exists. The specified container is disabled. The specified container is being deleted. The server is busy. ================================================ FILE: ironclad-apps/tools/NuBuild2/Settings.StyleCop ================================================ . ================================================ FILE: ironclad-apps/tools/NuBuild2/makefile ================================================ MSBUILD=C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe #MSBUILD=C:/Windows/Microsoft.NET/Framework/v4.0.30319/MSBuild.exe #BIN = ../../bin_tools/NuBuild # #NUBUILD_SOURCES = $(wildcard NuBuild/*.cs) NuBuild/NuBuild.csproj # #all: $(BIN)/NuBuild.exe # #$(BIN)/NuBuild.exe: $(NUBUILD_SOURCES) NuBuild.sln # $(MSBUILD) NuBuild.sln all: me me: echo hi $(MSBUILD) NuBuild.sln ================================================ FILE: ironclad-apps/tools/NuBuild2/modules.log ================================================ beat -out ..\..\..\..\obj\Checked\Nucleus\Base\Partition_i.bpl.tmp -in Partition_i.beat beat -out ..\..\..\..\obj\Checked\Nucleus\Base\Partition.bpl.tmp -in Partition.beat -i Partition_i.beat beat -out ..\..\..\..\obj\Checked\Nucleus\Base\Core_i.bpl.tmp -in Core_i.beat -i ..\..\..\..\src\Trusted\Spec\Base_i.bpl -i ..\..\..\..\src\Trusted\Spec\Memory_i.bpl -i ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl -i ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl -i ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl -i ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl -i ..\..\..\..\src\Trusted\Spec\Io_i.bpl -i Partition_i.beat beat -out ..\..\..\..\obj\Checked\Nucleus\Base\Core.bpl.tmp -in Core.beat -i ..\..\..\..\src\Trusted\Spec\Base_i.bpl -i ..\..\..\..\src\Trusted\Spec\Memory_i.bpl -i ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl -i ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl -i ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl -i ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl -i ..\..\..\..\src\Trusted\Spec\Io_i.bpl -i Partition_i.beat -i core_i.beat beat -out ..\..\..\..\obj\Checked\Nucleus\Base\LogicalAddressing_i.bpl.tmp -in LogicalAddressing_i.beat -i ..\..\..\..\src\Trusted\Spec\Base_i.bpl -i ..\..\..\..\src\Trusted\Spec\Memory_i.bpl -i ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl -i ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl -i ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl -i ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl -i ..\..\..\..\src\Trusted\Spec\Io_i.bpl -i Partition_i.beat -i Core_i.beat -i Separation_i.beat beat -out ..\..\..\..\obj\Checked\Nucleus\Base\LogicalAddressing.bpl.tmp -in LogicalAddressing.beat -i ..\..\..\..\src\Trusted\Spec\Base_i.bpl -i ..\..\..\..\src\Trusted\Spec\Memory_i.bpl -i ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl -i ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl -i ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl -i ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl -i ..\..\..\..\src\Trusted\Spec\Io_i.bpl -i Partition_i.beat -i Core_i.beat -i Separation_i.beat -i LogicalAddressing_i.beat beat -out ..\..\..\..\obj\Checked\Nucleus\Base\Stacks_i.bpl.tmp -in Stacks_i.beat -i ..\..\..\..\src\Trusted\Spec\Base_i.bpl -i ..\..\..\..\src\Trusted\Spec\Memory_i.bpl -i ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl -i ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl -i ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl -i ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl -i ..\..\..\..\src\Trusted\Spec\Io_i.bpl -i Separation_i.beat beat -out ..\..\..\..\obj\Checked\Nucleus\Base\Stacks.bpl.tmp -in Stacks.beat -i ..\..\..\..\src\Trusted\Spec\Base_i.bpl -i ..\..\..\..\src\Trusted\Spec\Memory_i.bpl -i ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl -i ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl -i ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl -i ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl -i ..\..\..\..\src\Trusted\Spec\Io_i.bpl -i Separation_i.beat -i Stacks_i.beat beat -out ..\..\..\..\obj\Checked\Nucleus\Base\Separation_i.bpl.tmp -in Separation_i.beat -i ..\..\..\..\src\Trusted\Spec\Base_i.bpl -i ..\..\..\..\src\Trusted\Spec\Memory_i.bpl -i ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl -i ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl -i ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl -i ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl -i ..\..\..\..\src\Trusted\Spec\Io_i.bpl -i Partition_i.beat -i Core_i.beat -i LogicalAddressing_i.beat beat -out ..\..\..\..\obj\Checked\Nucleus\Base\Separation.bpl.tmp -in Separation.beat -i ..\..\..\..\src\Trusted\Spec\Base_i.bpl -i ..\..\..\..\src\Trusted\Spec\Memory_i.bpl -i ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl -i ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl -i ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl -i ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl -i ..\..\..\..\src\Trusted\Spec\Io_i.bpl -i Partition_i.beat -i Core_i.beat -i Separation_i.beat -i Util_i.beat -i LogicalAddressing_i.beat beat -out ..\..\..\..\obj\Checked\Nucleus\Base\Overflow.bpl.tmp -in Overflow.beat -i ..\..\..\..\src\Trusted\Spec\Base_i.bpl -i ..\..\..\..\src\Trusted\Spec\Memory_i.bpl -i ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl -i ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl -i ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl -i ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl -i ..\..\..\..\src\Trusted\Spec\Io_i.bpl -i Util_i.beat -i ..\..\..\..\src\Trusted\Spec\Overflow_i.bpl -i Separation_i.beat beat -out ..\..\..\..\obj\Checked\Nucleus\Base\BitVectorLemmasBase_i.bpl.tmp -in BitVectorLemmasBase_i.beat beat -out ..\..\..\..\obj\Checked\Nucleus\Base\BitVectorLemmasBase.bpl.tmp -in BitVectorLemmasBase.beat -i BitVectorLemmasBase_i.beat beat -out ..\..\..\..\obj\Checked\Nucleus\Base\IntLemmasBase_i.bpl.tmp -in IntLemmasBase_i.beat beat -out ..\..\..\..\obj\Checked\Nucleus\Base\IntLemmasBase.bpl.tmp -in IntLemmasBase.beat -i BitVectorLemmasBase_i.beat -i IntLemmasBase_i.beat beat -out ..\..\..\..\obj\Checked\Nucleus\Base\Util_i.bpl.tmp -in Util_i.beat -i ..\..\..\..\src\Trusted\Spec\Base_i.bpl -i ..\..\..\..\src\Trusted\Spec\Memory_i.bpl -i ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl -i ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl -i ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl -i ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl -i ..\..\..\..\src\Trusted\Spec\Io_i.bpl -i Separation_i.beat beat -out ..\..\..\..\obj\Checked\Nucleus\Base\Util.bpl.tmp -in Util.beat -i ..\..\..\..\src\Trusted\Spec\Base_i.bpl -i ..\..\..\..\src\Trusted\Spec\Memory_i.bpl -i ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl -i ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl -i ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl -i ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl -i ..\..\..\..\src\Trusted\Spec\Io_i.bpl -i Separation_i.beat -i Util_i.beat -i IntLemmasBase_i.beat boogie /proverOpt:OPTIMIZE_FOR_BV=true ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\BitVectorSpec_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\BitVectorLemmasBase_i.bpl boogie /restartProver /proverOpt:OPTIMIZE_FOR_BV=true ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\BitVectorSpec_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\BitVectorLemmasBase_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\Word_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\IntSpec_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Base\BitVectorLemmasBase.bpl boogie ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\Assembly_axioms.bpl ..\..\..\..\src\Trusted\Spec\IntSpec_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\BitVectorLemmasBase_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\IntLemmasBase_i.bpl boogie ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\Assembly_axioms.bpl ..\..\..\..\src\Trusted\Spec\IntSpec_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\BitVectorLemmasBase_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\IntLemmasBase_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\Word_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\IntSpec_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Base\IntLemmasBase.bpl boogie ..\..\..\..\src\Trusted\Spec\Base_i.bpl ..\..\..\..\src\Trusted\Spec\Memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Partition_i.bpl boogie ..\..\..\..\src\Trusted\Spec\Base_i.bpl ..\..\..\..\src\Trusted\Spec\Memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Partition.bpl boogie ..\..\..\..\src\Trusted\Spec\Base_i.bpl ..\..\..\..\src\Trusted\Spec\Memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Core_i.bpl boogie ..\..\..\..\src\Trusted\Spec\Base_i.bpl ..\..\..\..\src\Trusted\Spec\Memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Core_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Core.bpl boogie ..\..\..\..\src\Trusted\Spec\Base_i.bpl ..\..\..\..\src\Trusted\Spec\Memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Base\IntLemmasBase_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Core_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\LogicalAddressing_i.bpl boogie ..\..\..\..\src\Trusted\Spec\Base_i.bpl ..\..\..\..\src\Trusted\Spec\Memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\word_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Base\IntLemmasBase_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Core_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\LogicalAddressing_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\LogicalAddressing.bpl boogie ..\..\..\..\src\Trusted\Spec\Base_i.bpl ..\..\..\..\src\Trusted\Spec\Memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Core_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\LogicalAddressing_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Util_i.bpl boogie ..\..\..\..\src\Trusted\Spec\Base_i.bpl ..\..\..\..\src\Trusted\Spec\Memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\word_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Core_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\IntLemmasBase_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\LogicalAddressing_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Util_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Util.bpl boogie ..\..\..\..\src\Trusted\Spec\Base_i.bpl ..\..\..\..\src\Trusted\Spec\Memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Core_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Util_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\LogicalAddressing_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Stacks_i.bpl boogie ..\..\..\..\src\Trusted\Spec\Base_i.bpl ..\..\..\..\src\Trusted\Spec\Memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Core_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Util_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\LogicalAddressing_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Stacks_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\word_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Stacks.bpl boogie ..\..\..\..\src\Trusted\Spec\Base_i.bpl ..\..\..\..\src\Trusted\Spec\Memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Core_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Util_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\LogicalAddressing_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Stacks_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Separation_i.bpl boogie ..\..\..\..\src\Trusted\Spec\Base_i.bpl ..\..\..\..\src\Trusted\Spec\Memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Core_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Util_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\LogicalAddressing_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Stacks_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Separation_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\word_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Separation.bpl boogie ..\..\..\..\src\Trusted\Spec\Base_i.bpl ..\..\..\..\src\Trusted\Spec\Memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Core_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\LogicalAddressing_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Stacks_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Separation_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Util_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Overflow_i.bpl boogie ..\..\..\..\src\Trusted\Spec\Base_i.bpl ..\..\..\..\src\Trusted\Spec\Memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Core_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\LogicalAddressing_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Stacks_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Separation_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Util_i.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Overflow_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\word_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Base\Overflow.bpl beat -out ..\..\..\..\obj\Checked\Nucleus\GC\BitVectorLemmasGc_i.bpl.tmp -in BitVectorLemmasGc_i.beat beat -out ..\..\..\..\obj\Checked\Nucleus\GC\BitVectorLemmasGc.bpl.tmp -in BitVectorLemmasGc.beat -i BitVectorLemmasGc_i.beat beat -out ..\..\..\..\obj\Checked\Nucleus\GC\IntLemmasGc_i.bpl.tmp -in IntLemmasGc_i.beat beat -out ..\..\..\..\obj\Checked\Nucleus\GC\IntLemmasGc.bpl.tmp -in IntLemmasGc.beat -i BitVectorLemmasGc_i.beat -i IntLemmasGc_i.beat beat -out ..\..\..\..\obj\Checked\Nucleus\GC\SimpleGcMemory_i.bpl.tmp -in SimpleGcMemory_i.beat beat -out ..\..\..\..\obj\Checked\Nucleus\GC\SimpleGcMemory.bpl.tmp -in SimpleGcMemory.beat -i SimpleGcMemory_i.beat beat -out ..\..\..\..\obj\Checked\Nucleus\GC\SimpleCommon_i.bpl.tmp -in SimpleCommon_i.beat -i ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl -i ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl -i ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl -i ..\Base\partition_i.beat -i ..\Base\core_i.beat -i ..\Base\separation_i.beat -i SimpleGcMemory_i.beat beat -out ..\..\..\..\obj\Checked\Nucleus\GC\SimpleCommon.bpl.tmp -in SimpleCommon.beat -i ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl -i ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl -i ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl -i ..\Base\partition_i.beat -i ..\Base\core_i.beat -i ..\Base\separation_i.beat -i ..\Base\LogicalAddressing_i.beat -i SimpleGcMemory_i.beat -i SimpleCommon_i.beat beat -out ..\..\..\..\obj\Checked\Nucleus\GC\SimpleCollector_i.bpl.tmp -in ..\..\..\..\obj\Checked\Nucleus\GC\SimpleCollector_i.beat -i ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl -i ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl -i ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl -i ..\Base\partition_i.beat -i ..\Base\core_i.beat -i ..\Base\LogicalAddressing_i.beat -i ..\Base\separation_i.beat -i SimpleGcMemory_i.beat -i SimpleCommon_i.beat -i IntLemmasGc_i.beat beat -out ..\..\..\..\obj\Checked\Nucleus\GC\SimpleCollector.bpl.tmp -in SimpleCollector.beat -i ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl -i ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl -i ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl -i ..\Base\partition_i.beat -i ..\Base\core_i.beat -i ..\Base\LogicalAddressing_i.beat -i ..\Base\separation_i.beat -i ..\Base\Util_i.beat -i ..\Base\Stacks_i.beat -i SimpleGcMemory_i.beat -i SimpleCommon_i.beat -i ..\..\..\..\obj\Checked\Nucleus\GC\SimpleCollector_i.beat -i IntLemmasGc_i.beat boogie /proverOpt:OPTIMIZE_FOR_BV=true ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\BitVectorSpec_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\BitVectorLemmasGc_i.bpl boogie /restartProver /proverOpt:OPTIMIZE_FOR_BV=true ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\BitVectorSpec_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\BitVectorLemmasGc_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\Word_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\IntSpec_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\GC\BitVectorLemmasGc.bpl boogie ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl ..\..\..\..\src\Trusted\Spec\IntSpec_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\IntLemmasGc_i.bpl boogie ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl ..\..\..\..\src\Trusted\Spec\IntSpec_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\BitVectorLemmasGc_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\Word_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\IntSpec_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\GC\IntLemmasGc_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\IntLemmasGc.bpl boogie ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\Word_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\GC\..\Base\core_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\..\Base\LogicalAddressing_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\..\Base\overflow_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\..\Base\util_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\..\Base\stacks_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\..\Base\partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\..\Base\separation_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\SimpleGcMemory_i.bpl boogie ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\Word_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\GC\..\Base\core_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\..\Base\LogicalAddressing_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\..\Base\overflow_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\..\Base\util_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\..\Base\stacks_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\..\Base\partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\..\Base\separation_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\SimpleGcMemory_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\SimpleGcMemory.bpl boogie ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\Word_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\GC\..\Base\core_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\..\Base\LogicalAddressing_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\..\Base\overflow_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\..\Base\util_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\..\Base\stacks_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\..\Base\partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\..\Base\separation_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\IntLemmasGc_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\SimpleGcMemory_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\SimpleCommon_i.bpl boogie ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\Word_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\GC\..\Base\core_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\..\Base\LogicalAddressing_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\..\Base\overflow_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\..\Base\util_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\..\Base\stacks_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\..\Base\partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\..\Base\separation_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\IntLemmasGc_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\SimpleGcMemory_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\SimpleCommon_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\SimpleCommon.bpl boogie ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\Word_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\GC\..\Base\core_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\..\Base\LogicalAddressing_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\..\Base\overflow_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\..\Base\util_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\..\Base\stacks_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\..\Base\partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\..\Base\separation_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\IntLemmasGc_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\SimpleGcMemory_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\SimpleCommon_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\SimpleCollector_i.bpl boogie ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\Word_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\GC\..\Base\core_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\..\Base\LogicalAddressing_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\..\Base\overflow_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\..\Base\util_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\..\Base\stacks_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\..\Base\partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\..\Base\separation_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\IntLemmasGc_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\SimpleGcMemory_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\SimpleCommon_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\SimpleCollector_i.bpl ..\..\..\..\obj\Checked\Nucleus\GC\SimpleCollector.bpl beat -out ..\..\..\..\obj\Checked\Nucleus\Devices\BitVectorLemmasDevices_i.bpl.tmp -in BitVectorLemmasDevices_i.beat beat -out ..\..\..\..\obj\Checked\Nucleus\Devices\BitVectorLemmasDevices.bpl.tmp -in BitVectorLemmasDevices.beat -i BitVectorLemmasDevices_i.beat beat -out ..\..\..\..\obj\Checked\Nucleus\Devices\IntLemmasDevices_i.bpl.tmp -in IntLemmasDevices_i.beat beat -out ..\..\..\..\obj\Checked\Nucleus\Devices\IntLemmasDevices.bpl.tmp -in IntLemmasDevices.beat -i BitVectorLemmasDevices_i.beat -i IntLemmasDevices_i.beat beat -out ..\..\..\..\obj\Checked\Nucleus\Devices\IoMainCP_i.bpl.tmp -in IoMain_i.beat -i ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl -i ..\..\..\..\src\Trusted\Spec\Io_i.bpl -i ..\Base\Partition_i.beat -i ..\Base\Core_i.beat -i ..\Base\Separation_i.beat -i ..\..\..\..\obj\Checked\Nucleus\Devices\..\GC\SimpleCollector_i.beat beat -out ..\..\..\..\obj\Checked\Nucleus\Devices\PCICP_i.bpl.tmp -in PCI_i.beat -i ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl -i ..\..\..\..\src\Trusted\Spec\Io_i.bpl -i ..\Base\Partition_i.beat -i ..\Base\Core_i.beat -i ..\Base\Separation_i.beat -i ..\..\..\..\obj\Checked\Nucleus\Devices\..\GC\SimpleCollector_i.beat -i IntLemmasDevices_i.beat -i IoMain_i.beat beat -out ..\..\..\..\obj\Checked\Nucleus\Devices\IntelNICCP_i.bpl.tmp -in IntelNIC_i.beat -i ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl -i ..\..\..\..\src\Trusted\Spec\Io_i.bpl -i ..\Base\Partition_i.beat -i ..\Base\Core_i.beat -i ..\Base\Separation_i.beat -i ..\..\..\..\obj\Checked\Nucleus\Devices\..\GC\SimpleCollector_i.beat beat -out ..\..\..\..\obj\Checked\Nucleus\Devices\IoMainCP.bpl.tmp -in IoMain.beat -i ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl -i ..\..\..\..\src\Trusted\Spec\Io_i.bpl -i ..\Base\Partition_i.beat -i ..\Base\Core_i.beat -i ..\Base\Separation_i.beat -i ..\..\..\..\obj\Checked\Nucleus\Devices\..\GC\SimpleCollector_i.beat -i ..\Base\LogicalAddressing_i.beat -i ..\Base\Util_i.beat -i ..\GC\SimpleGcMemory_i.beat -i ..\GC\SimpleCommon_i.beat -i ..\Base\IntLemmasBase_i.beat -i ..\GC\IntLemmasGc_i.beat -i IoMain_i.beat -i PCI_i.beat -i IntLemmasDevices_i.beat beat -out ..\..\..\..\obj\Checked\Nucleus\Devices\PCICP.bpl.tmp -in PCI.beat -i ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl -i ..\..\..\..\src\Trusted\Spec\Io_i.bpl -i ..\Base\Partition_i.beat -i ..\Base\Core_i.beat -i ..\Base\Separation_i.beat -i ..\..\..\..\obj\Checked\Nucleus\Devices\..\GC\SimpleCollector_i.beat -i ..\Base\LogicalAddressing_i.beat -i ..\Base\Util_i.beat -i ..\GC\SimpleGcMemory_i.beat -i ..\GC\SimpleCommon_i.beat -i PCI_i.beat beat -out ..\..\..\..\obj\Checked\Nucleus\Devices\IntelNICCP.bpl.tmp -in IntelNIC.beat -i ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl -i ..\..\..\..\src\Trusted\Spec\Io_i.bpl -i ..\Base\Partition_i.beat -i ..\Base\Core_i.beat -i ..\Base\Separation_i.beat -i ..\..\..\..\obj\Checked\Nucleus\Devices\..\GC\SimpleCollector_i.beat -i ..\Base\LogicalAddressing_i.beat -i ..\Base\Util_i.beat -i ..\GC\SimpleGcMemory_i.beat -i ..\GC\SimpleCommon_i.beat -i IntLemmasDevices_i.beat -i PCI_i.beat -i IntelNIC_i.beat boogie /proverOpt:OPTIMIZE_FOR_BV=true ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\BitVectorSpec_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\BitVectorLemmasDevices_i.bpl boogie ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl ..\..\..\..\src\Trusted\Spec\IntSpec_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\BitVectorLemmasDevices_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\IntLemmasDevices_i.bpl boogie ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl ..\..\..\..\src\Trusted\Spec\IntSpec_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\BitVectorLemmasDevices_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\IntLemmasDevices_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\Word_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\IntSpec_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\IntLemmasDevices.bpl boogie ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\word_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\Io_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\Base\core_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\Base\LogicalAddressing_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\Base\overflow_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\Base\util_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\Base\stacks_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\Base\partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\Base\separation_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\Base\IntLemmasBase_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\GC\IntLemmasGc_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\GC\SimpleGcMemory_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\GC\SimpleCommon_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\GC\SimpleCollector_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\PCICP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\PCICP.bpl boogie ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\word_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\Io_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\Base\core_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\Base\LogicalAddressing_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\Base\overflow_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\Base\util_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\Base\stacks_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\Base\partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\Base\separation_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\Base\IntLemmasBase_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\GC\IntLemmasGc_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\GC\SimpleGcMemory_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\GC\SimpleCommon_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\GC\SimpleCollector_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\IoMainCP_i.bpl boogie ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\word_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\Io_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\Base\core_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\Base\LogicalAddressing_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\Base\overflow_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\Base\util_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\Base\stacks_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\Base\partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\Base\separation_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\Base\IntLemmasBase_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\GC\IntLemmasGc_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\GC\SimpleGcMemory_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\GC\SimpleCommon_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\GC\SimpleCollector_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\IntLemmasDevices_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\PCICP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\IoMainCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\IoMainCP.bpl boogie ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\word_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\Io_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\Base\core_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\Base\LogicalAddressing_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\Base\overflow_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\Base\util_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\Base\stacks_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\Base\partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\Base\separation_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\Base\IntLemmasBase_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\GC\IntLemmasGc_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\GC\SimpleGcMemory_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\GC\SimpleCommon_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\GC\SimpleCollector_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\IntLemmasDevices_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\PCICP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\IntelNICCP_i.bpl boogie ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\word_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\Io_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\Base\core_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\Base\LogicalAddressing_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\Base\overflow_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\Base\util_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\Base\stacks_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\Base\partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\Base\separation_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\Base\IntLemmasBase_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\GC\IntLemmasGc_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\GC\SimpleGcMemory_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\GC\SimpleCommon_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\..\GC\SimpleCollector_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\IntLemmasDevices_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\PCICP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\IntelNICCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Devices\IntelNICCP.bpl beat -out ..\..\..\..\obj\Checked\Nucleus\Main\dafny_assembly_i_tmp.bpl.tmp -in dafny_assembly_i.beat -i ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl -i ..\Base\partition_i.beat -i ..\Base\core_i.beat -i ..\Base\LogicalAddressing_i.beat -i ..\Base\separation_i.beat -i ..\Base\Util_i.beat -i ..\GC\SimpleGcMemory_i.beat -i ..\GC\SimpleCommon_i.beat -i ..\GC\SimpleCollector_i.beat -i ..\Devices\IoMain_i.beat -i DafnyAssembly_i.beat -i ..\..\..\..\obj\Checked\Nucleus\Main\dafny_assembly_i_i.bpl beat -out ..\..\..\..\obj\Checked\Nucleus\Main\dafny_bit_vector_lemmas_i_tmp.bpl.tmp -in dafny_bit_vector_lemmas_i.beat -i ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl -i ..\Base\partition_i.beat -i ..\Base\core_i.beat -i ..\Base\LogicalAddressing_i.beat -i ..\Base\separation_i.beat -i ..\Base\Util_i.beat -i ..\GC\SimpleGcMemory_i.beat -i ..\GC\SimpleCommon_i.beat -i ..\GC\SimpleCollector_i.beat -i ..\Devices\IoMain_i.beat -i ..\..\..\..\obj\Checked\Nucleus\Main\dafny_bit_vector_lemmas_i_i.bpl beat -out ..\..\..\..\obj\Checked\Nucleus\Main\BitVectorLemmasMain_i.bpl.tmp -in BitVectorLemmasMain_i.beat beat -out ..\..\..\..\obj\Checked\Nucleus\Main\BitVectorLemmasMain.bpl.tmp -in BitVectorLemmasMain.beat -i BitVectorLemmasMain_i.beat beat -out ..\..\..\..\obj\Checked\Nucleus\Main\IntLemmasMain_i.bpl.tmp -in IntLemmasMain_i.beat beat -out ..\..\..\..\obj\Checked\Nucleus\Main\IntLemmasMain.bpl.tmp -in IntLemmasMain.beat -i BitVectorLemmasMain_i.beat -i IntLemmasMain_i.beat beat -out ..\..\..\..\obj\Checked\Nucleus\Main\DafnyAssembly_i.bpl.tmp -in DafnyAssembly_i.beat -i ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl -i ..\Base\partition_i.beat -i ..\Base\core_i.beat -i ..\Base\LogicalAddressing_i.beat -i ..\Base\separation_i.beat -i ..\Base\Util_i.beat -i ..\GC\SimpleGcMemory_i.beat -i ..\GC\SimpleCommon_i.beat -i ..\GC\SimpleCollector_i.beat -i ..\Devices\IoMain_i.beat beat -out ..\..\..\..\obj\Checked\Nucleus\Main\DafnyAssembly.bpl.tmp -in DafnyAssembly.beat -i ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl -i ..\Base\partition_i.beat -i ..\Base\core_i.beat -i ..\Base\LogicalAddressing_i.beat -i ..\Base\separation_i.beat -i ..\Base\Util_i.beat -i ..\GC\SimpleGcMemory_i.beat -i ..\GC\SimpleCommon_i.beat -i ..\GC\SimpleCollector_i.beat -i ..\Devices\IoMain_i.beat -i DafnyAssembly_i.beat beat -out ..\..\..\..\obj\Checked\Nucleus\Main\MainCP_i.bpl.tmp -in Main_i.beat -i ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl -i ..\Base\partition_i.beat -i ..\Base\core_i.beat -i ..\Base\LogicalAddressing_i.beat -i ..\Base\separation_i.beat -i ..\Base\Util_i.beat -i ..\GC\SimpleGcMemory_i.beat -i ..\GC\SimpleCommon_i.beat -i ..\GC\SimpleCollector_i.beat -i ..\Devices\IoMain_i.beat beat -out ..\..\..\..\obj\Checked\Nucleus\Main\EntryCP_tmp.bpl.tmp -in Entry.beat -i ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl -i ..\Base\partition_i.beat -i ..\Base\core_i.beat -i ..\Base\LogicalAddressing_i.beat -i ..\Base\separation_i.beat -i ..\Base\Util_i.beat -i ..\GC\SimpleGcMemory_i.beat -i ..\GC\SimpleCommon_i.beat -i ..\GC\SimpleCollector_i.beat -i ..\Devices\IoMain_i.beat -i Main_i.beat -i ..\..\..\..\obj\Checked\Nucleus\Main\EntryImport.beat -i ..\..\..\..\obj\Checked\Nucleus\Main\EntryCP_i.bpl -i ..\..\..\..\obj\Checked\Nucleus\Main\HeapCP_i.bpl -i ..\..\..\..\obj\Checked\Nucleus\Main\dafny_Cube_i.bpl boogie /proverOpt:OPTIMIZE_FOR_BV=true ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\BitVectorSpec_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\BitVectorLemmasMain_i.bpl boogie /restartProver /proverOpt:OPTIMIZE_FOR_BV=true ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\BitVectorSpec_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\BitVectorLemmasMain_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\Word_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\IntSpec_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Main\BitVectorLemmasMain.bpl boogie ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl ..\..\..\..\src\Trusted\Spec\IntSpec_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\BitVectorLemmasMain_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\IntLemmasMain_i.bpl boogie ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl ..\..\..\..\src\Trusted\Spec\IntSpec_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\BitVectorLemmasMain_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\IntLemmasMain_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\Word_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\IntSpec_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Main\IntLemmasMain.bpl boogie /timeLimit:30 ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\word_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\Io_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\core_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\LogicalAddressing_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\overflow_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\util_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\stacks_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\separation_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\IntLemmasBase_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\IntLemmasGc_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleGcMemory_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCommon_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCollector_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Devices\IoMainCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Trusted_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_DafnyPrelude_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_base_s_i.bpl boogie /timeLimit:30 ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\word_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\Io_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\core_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\LogicalAddressing_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\overflow_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\util_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\stacks_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\separation_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\IntLemmasBase_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\IntLemmasGc_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleGcMemory_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCommon_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCollector_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Devices\IoMainCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\IntLemmasMain_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Trusted_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Checked_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\HeapCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Seq_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_DafnyPrelude_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\DafnyAssembly_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_base_s_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_Base_i.bpl boogie /timeLimit:300 /trace /z3opt:NL_ARITH=false ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\word_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\Io_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\core_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\LogicalAddressing_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\overflow_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\util_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\stacks_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\separation_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\IntLemmasBase_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\IntLemmasGc_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleGcMemory_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCommon_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCollector_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Devices\IoMainCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\IntLemmasMain_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Trusted_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Checked_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\HeapCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Seq_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_DafnyPrelude_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\DafnyAssembly_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_base_s_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_Base_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_Base.bpl boogie /timeLimit:30 ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\word_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\Io_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\core_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\LogicalAddressing_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\overflow_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\util_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\stacks_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\separation_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\IntLemmasBase_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\IntLemmasGc_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleGcMemory_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCommon_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCollector_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Devices\IoMainCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Trusted_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_DafnyPrelude_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_relational_s_i.bpl boogie /timeLimit:30 ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\word_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\Io_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\core_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\LogicalAddressing_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\overflow_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\util_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\stacks_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\separation_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\IntLemmasBase_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\IntLemmasGc_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleGcMemory_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCommon_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCollector_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Devices\IoMainCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Trusted_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_DafnyPrelude_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_base_s_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_power2_s_i.bpl boogie /timeLimit:30 ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\word_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\Io_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\core_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\LogicalAddressing_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\overflow_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\util_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\stacks_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\separation_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\IntLemmasBase_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\IntLemmasGc_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleGcMemory_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCommon_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCollector_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Devices\IoMainCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\IntLemmasMain_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Trusted_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Checked_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\HeapCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Seq_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_DafnyPrelude_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\DafnyAssembly_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_mul_nonlinear_i_i.bpl boogie /timeLimit:300 /trace /z3opt:NL_ARITH=false /z3opt:NL_ARITH=true ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\word_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\Io_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\core_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\LogicalAddressing_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\overflow_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\util_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\stacks_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\separation_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\IntLemmasBase_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\IntLemmasGc_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleGcMemory_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCommon_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCollector_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Devices\IoMainCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\IntLemmasMain_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Trusted_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Checked_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\HeapCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Seq_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_DafnyPrelude_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\DafnyAssembly_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_mul_nonlinear_i_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_mul_nonlinear_i.bpl boogie /timeLimit:30 ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\word_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\Io_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\core_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\LogicalAddressing_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\overflow_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\util_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\stacks_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\separation_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\IntLemmasBase_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\IntLemmasGc_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleGcMemory_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCommon_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCollector_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Devices\IoMainCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\IntLemmasMain_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Trusted_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Checked_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\HeapCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Seq_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_DafnyPrelude_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\DafnyAssembly_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_mul_nonlinear_i_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_mul_i_i.bpl boogie /timeLimit:300 /trace /z3opt:NL_ARITH=false ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\word_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\Io_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\core_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\LogicalAddressing_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\overflow_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\util_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\stacks_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\separation_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\IntLemmasBase_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\IntLemmasGc_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleGcMemory_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCommon_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCollector_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Devices\IoMainCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\IntLemmasMain_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Trusted_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Checked_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\HeapCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Seq_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_DafnyPrelude_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\DafnyAssembly_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_mul_nonlinear_i_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_mul_i_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_mul_i.bpl boogie /timeLimit:30 ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\word_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\Io_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\core_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\LogicalAddressing_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\overflow_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\util_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\stacks_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\separation_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\IntLemmasBase_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\IntLemmasGc_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleGcMemory_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCommon_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCollector_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Devices\IoMainCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\IntLemmasMain_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Trusted_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Checked_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\HeapCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Seq_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_DafnyPrelude_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\DafnyAssembly_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_base_s_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_relational_s_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_assembly_i_i.bpl boogie /timeLimit:300 /trace /z3opt:NL_ARITH=false ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\word_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\Io_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\core_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\LogicalAddressing_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\overflow_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\util_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\stacks_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\separation_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\IntLemmasBase_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\IntLemmasGc_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleGcMemory_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCommon_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCollector_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Devices\IoMainCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\IntLemmasMain_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Trusted_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Checked_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\HeapCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Seq_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_DafnyPrelude_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\DafnyAssembly_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_base_s_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_relational_s_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_assembly_i_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_assembly_i.bpl boogie /timeLimit:30 ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\word_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\Io_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\core_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\LogicalAddressing_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\overflow_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\util_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\stacks_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\separation_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\IntLemmasBase_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\IntLemmasGc_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleGcMemory_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCommon_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCollector_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Devices\IoMainCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\IntLemmasMain_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Trusted_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Checked_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\HeapCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Seq_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_DafnyPrelude_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\DafnyAssembly_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_base_s_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_relational_s_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_assembly_i_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_bit_vector_lemmas_i_i.bpl boogie /timeLimit:300 /trace /z3opt:NL_ARITH=false ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\word_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\Io_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\core_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\LogicalAddressing_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\overflow_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\util_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\stacks_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\separation_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\IntLemmasBase_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\IntLemmasGc_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleGcMemory_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCommon_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCollector_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Devices\IoMainCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\IntLemmasMain_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Trusted_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Checked_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\HeapCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Seq_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_DafnyPrelude_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\DafnyAssembly_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_base_s_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_relational_s_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_assembly_i_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_bit_vector_lemmas_i_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_bit_vector_lemmas_i.bpl boogie /timeLimit:30 ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\word_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\Io_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\core_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\LogicalAddressing_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\overflow_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\util_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\stacks_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\separation_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\IntLemmasBase_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\IntLemmasGc_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleGcMemory_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCommon_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCollector_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Devices\IoMainCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\IntLemmasMain_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Trusted_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Checked_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\HeapCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Seq_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_DafnyPrelude_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\DafnyAssembly_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_relational_s_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_base_s_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_power2_s_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_mul_nonlinear_i_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_mul_i_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_assembly_i_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_bit_vector_lemmas_i_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_Cube_i.bpl boogie /timeLimit:300 /trace /z3opt:NL_ARITH=false ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\word_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\Io_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\core_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\LogicalAddressing_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\overflow_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\util_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\stacks_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\separation_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\IntLemmasBase_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\IntLemmasGc_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleGcMemory_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCommon_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCollector_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Devices\IoMainCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\IntLemmasMain_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Trusted_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Checked_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\HeapCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Seq_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_DafnyPrelude_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\DafnyAssembly_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_relational_s_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_base_s_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_power2_s_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_mul_nonlinear_i_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_mul_i_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_assembly_i_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_bit_vector_lemmas_i_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_Cube_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_Cube.bpl boogie ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\word_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\Io_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\core_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\LogicalAddressing_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\overflow_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\util_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\stacks_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\separation_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\IntLemmasBase_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\IntLemmasGc_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleGcMemory_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCommon_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCollector_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Devices\IoMainCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Trusted_i.bpl boogie ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\word_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\Io_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\core_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\LogicalAddressing_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\overflow_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\util_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\stacks_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\separation_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\IntLemmasBase_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\IntLemmasGc_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleGcMemory_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCommon_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCollector_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Devices\IoMainCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\IntLemmasMain_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Trusted_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Checked_i.bpl boogie ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\word_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\Io_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\core_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\LogicalAddressing_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\overflow_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\util_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\stacks_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\separation_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\IntLemmasBase_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\IntLemmasGc_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleGcMemory_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCommon_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCollector_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Devices\IoMainCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\IntLemmasMain_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Trusted_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Checked_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Checked.bpl boogie ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\word_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\Io_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\core_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\LogicalAddressing_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\overflow_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\util_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\stacks_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\separation_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\IntLemmasBase_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\IntLemmasGc_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleGcMemory_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCommon_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCollector_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Devices\IoMainCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\IntLemmasMain_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Trusted_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Checked_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\HeapCP_i.bpl boogie ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\word_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\Io_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\core_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\LogicalAddressing_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\overflow_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\util_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\stacks_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\separation_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\IntLemmasBase_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\IntLemmasGc_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleGcMemory_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCommon_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCollector_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Devices\IoMainCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\IntLemmasMain_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Trusted_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Checked_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\HeapCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\HeapCP.bpl boogie ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\word_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\Io_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\core_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\LogicalAddressing_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\overflow_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\util_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\stacks_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\separation_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\IntLemmasBase_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\IntLemmasGc_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleGcMemory_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCommon_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCollector_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Devices\IoMainCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\IntLemmasMain_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Trusted_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Checked_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\HeapCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Seq_i.bpl boogie ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\word_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\Io_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\core_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\LogicalAddressing_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\overflow_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\util_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\stacks_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\separation_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\IntLemmasBase_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\IntLemmasGc_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleGcMemory_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCommon_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCollector_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Devices\IoMainCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\IntLemmasMain_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Trusted_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Checked_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\HeapCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Seq_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Seq.bpl boogie ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\word_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\Io_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\core_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\LogicalAddressing_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\overflow_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\util_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\stacks_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\separation_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\IntLemmasBase_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\IntLemmasGc_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleGcMemory_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCommon_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCollector_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Devices\IoMainCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Trusted_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_DafnyPrelude_i.bpl boogie ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\word_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\Io_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\core_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\LogicalAddressing_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\overflow_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\util_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\stacks_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\separation_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\IntLemmasBase_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\IntLemmasGc_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleGcMemory_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCommon_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCollector_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Devices\IoMainCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\IntLemmasMain_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Trusted_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Checked_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\HeapCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Seq_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_DafnyPrelude_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\DafnyAssembly_i.bpl boogie ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\word_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\Io_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\core_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\LogicalAddressing_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\overflow_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\util_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\stacks_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\separation_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\IntLemmasBase_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\IntLemmasGc_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleGcMemory_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCommon_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCollector_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Devices\IoMainCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\IntLemmasMain_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Trusted_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Checked_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\HeapCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Seq_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_DafnyPrelude_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\DafnyAssembly_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\DafnyAssembly.bpl boogie ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\word_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\Io_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\core_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\LogicalAddressing_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\overflow_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\util_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\stacks_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\separation_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\IntLemmasBase_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\IntLemmasGc_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleGcMemory_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCommon_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCollector_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Devices\IoMainCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\IntLemmasMain_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Trusted_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Checked_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\HeapCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Seq_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_DafnyPrelude_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\DafnyAssembly_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\\dafny_relational_s_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\\dafny_base_s_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\\dafny_power2_s_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\\dafny_mul_nonlinear_i_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\\dafny_mul_i_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\\dafny_assembly_i_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\\dafny_bit_vector_lemmas_i_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\\dafny_Cube_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\EntryCP_i.bpl boogie ..\..\..\..\src\Trusted\Spec\base_i.bpl ..\..\..\..\src\Trusted\Spec\memory_i.bpl ..\..\..\..\src\Trusted\Spec\Io_types_i.bpl ..\..\..\..\src\Trusted\Spec\MachineState_i.bpl ..\..\..\..\src\Trusted\Spec\Assembly_i.bpl ..\..\..\..\src\Trusted\Spec\Interrupts_i.bpl ..\..\..\..\src\Trusted\Spec\Io_i.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\base_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\word_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\memory_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\assembly_axioms.bpl /trustedBoogie:..\..\..\..\src\Trusted\Spec\Io_axioms.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\core_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\LogicalAddressing_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\overflow_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\util_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\stacks_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\partition_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\separation_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Base\IntLemmasBase_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\IntLemmasGc_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleGcMemory_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCommon_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\GC\SimpleCollector_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\..\Devices\IoMainCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\IntLemmasMain_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Trusted_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Checked_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\HeapCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\Seq_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\dafny_DafnyPrelude_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\DafnyAssembly_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\\dafny_relational_s_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\\dafny_base_s_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\\dafny_power2_s_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\\dafny_mul_nonlinear_i_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\\dafny_mul_i_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\\dafny_assembly_i_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\\dafny_bit_vector_lemmas_i_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\\dafny_Cube_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\EntryCP_i.bpl ..\..\..\..\obj\Checked\Nucleus\Main\EntryCP.bpl ================================================ FILE: ironclad-apps/tools/NuBuild2/modules.result ================================================ Can't resolve target Separation.ifc. Loop? Can't resolve target LogicalAddressing.ifc. Loop? Io_types.ifc imports Interrupts.ifc imports PCICP.ifc imports base.ifc imports Assembly.ifc imports Io.ifc imports IntSpec.ifc imports MachineState.ifc imports memory.ifc imports # EntryImport.imp imports * Partition.ifc imports Io.ifc,Io_types.ifc,MachineState.ifc,Memory.ifc,Assembly.ifc,Interrupts.ifc,Base.ifc * IntLemmasGc.ifc imports base.ifc,memory.ifc,IntSpec.ifc * BitVectorLemmasGc.ifc imports base.ifc,memory.ifc * BitVectorLemmasBase.ifc imports base.ifc,memory.ifc * BitVectorLemmasMain.ifc imports base.ifc,memory.ifc * BitVectorLemmasDevices.ifc imports base.ifc,memory.ifc * Partition.imp imports Partition.ifc * Core.ifc imports Partition.ifc # BitVectorLemmasBase.imp imports BitVectorLemmasBase.ifc * IntLemmasBase.ifc imports Io_types.ifc,BitVectorLemmasBase.ifc,Assembly.ifc,MachineState.ifc,IntSpec.ifc # BitVectorLemmasMain.imp imports BitVectorLemmasMain.ifc # BitVectorLemmasGc.imp imports BitVectorLemmasGc.ifc # IntLemmasGc.imp imports BitVectorLemmasGc.ifc,IntLemmasGc.ifc # BitVectorLemmasDevices.imp imports BitVectorLemmasDevices.ifc IntLemmasDevices.ifc imports Io_types.ifc,BitVectorLemmasDevices.ifc,Assembly.ifc,MachineState.ifc,IntSpec.ifc * IntLemmasMain.ifc imports BitVectorLemmasMain.ifc,IntSpec.ifc # IntLemmasDevices.imp imports IntLemmasDevices.ifc # Core.imp imports core.ifc * LogicalAddressing.ifc imports IntLemmasBase.ifc,Core.ifc * Separation.ifc imports Core.ifc # IntLemmasBase.imp imports IntLemmasBase.ifc # IntLemmasMain.imp imports IntLemmasMain.ifc * Util.ifc imports LogicalAddressing.ifc # LogicalAddressing.imp imports LogicalAddressing.ifc * Stacks.ifc imports Util.ifc # Util.imp imports LogicalAddressing.ifc,Util.ifc # Separation.imp imports Stacks.ifc Overflow.ifc imports Stacks.ifc # Stacks.imp imports Stacks.ifc # SimpleGcMemory.ifc imports overflow.ifc # Overflow.imp imports Overflow.ifc # SimpleGcMemory.imp imports SimpleGcMemory.ifc * SimpleCommon.ifc imports SimpleGcMemory.ifc,IntLemmasGc.ifc * SimpleCollector.ifc imports SimpleCommon.ifc # SimpleCommon.imp imports SimpleCommon.ifc * IntelNICCP.ifc imports PCICP.ifc,SimpleCollector.ifc,IntLemmasDevices.ifc,LogicalAddressing.ifc # PCICP.imp imports SimpleCollector.ifc,PCICP.ifc,LogicalAddressing.ifc # SimpleCollector.imp imports SimpleCollector.ifc * IoMainCP.ifc imports SimpleCollector.ifc,LogicalAddressing.ifc IntelNIC.ifc imports SimpleCollector.ifc * IoMain.ifc imports SimpleCollector.ifc Trusted.ifc imports IoMainCP.ifc * Main.ifc imports SimpleCollector.ifc,IoMain.ifc # IoMainCP.imp imports PCICP.ifc,IntLemmasDevices.ifc,IoMainCP.ifc * PCI.ifc imports IoMain.ifc,IntLemmasDevices.ifc # IntelNICCP.imp imports IntelNICCP.ifc # IoMain.imp imports PCI.ifc,SimpleCollector.ifc,LogicalAddressing.ifc # PCI.imp imports PCI.ifc,SimpleCollector.ifc Checked.ifc imports Trusted.ifc,IntLemmasMain.ifc dafny_DafnyPrelude.ifc imports Trusted.ifc # IntelNIC.imp imports IntelNIC.ifc,PCI.ifc,SimpleCollector.ifc dafny_base_s.ifc imports dafny_DafnyPrelude.ifc # Checked.imp imports Checked.ifc * HeapCP.ifc imports Checked.ifc dafny_relational_s.ifc imports dafny_DafnyPrelude.ifc # HeapCP.imp imports HeapCP.ifc Seq.ifc imports HeapCP.ifc dafny_power2_s.ifc imports dafny_base_s.ifc * DafnyAssembly.ifc imports dafny_DafnyPrelude.ifc,IoMain.ifc,Seq.ifc # Seq.imp imports Seq.ifc dafny_Base.ifc imports DafnyAssembly.ifc,dafny_base_s.ifc dafny_assembly_i.ifc imports DafnyAssembly.ifc,dafny_relational_s.ifc,dafny_base_s.ifc dafny_mul_nonlinear_i.ifc imports DafnyAssembly.ifc # DafnyAssembly.imp imports DafnyAssembly.ifc # dafny_Base.imp imports dafny_Base.ifc dafny_assembly.ifc imports dafny_assembly_i.ifc,IoMain.ifc dafny_mul_nonlinear.ifc imports dafny_mul_nonlinear_i.ifc * dafny_bit_vector_lemmas_i.ifc imports dafny_assembly_i.ifc dafny_mul_i.ifc imports dafny_mul_nonlinear_i.ifc dafny_mul.ifc imports dafny_mul_i.ifc dafny_bit_vector_lemmas.ifc imports IoMain.ifc,dafny_bit_vector_lemmas_i.ifc dafny_Cube.ifc imports dafny_mul_i.ifc,dafny_power2_s.ifc,dafny_bit_vector_lemmas_i.ifc EntryCP.ifc imports dafny_Cube.ifc # dafny_Cube.imp imports dafny_Cube.ifc # EntryCP.imp imports EntryCP.ifc # Entry.imp imports EntryCP.ifc,Main.ifc,EntryImport.imp ================================================ FILE: ironclad-apps/tools/SymDiff/SymDiff.exe.config ================================================ ================================================ FILE: ironclad-apps/tools/SymDiff/SymDiff.vshost.exe.config ================================================ ================================================ FILE: ironclad-apps/tools/SymDiff/SymDiff.vshost.exe.manifest ================================================  ================================================ FILE: ironclad-apps/tools/SymDiff/TypedUnivBackPred2.sx ================================================ ; ------------------------------------------------------------------------- ; Boogie 2 universal background predicate for Z3 (Simplify notation with types) ; Copyright (c) 2004-2009, Microsoft Corp. (DEFTYPE $int :BUILTIN Int) (DEFTYPE $bool :BUILTIN bool) (DEFTYPE U) (DEFTYPE T) (DEFOP <: U U $bool) ; used for translation with type premisses (DEFOP <:: T U U $bool) ; used for translation with type arguments (BG_PUSH (AND ; false is not true (DISTINCT |@false| |@true|) ; we assume type correctness of the operations here ; a-l>=0 ==> (v ++ w:l)[a:b] = v[a-l:b-l] (FORALL (v lv w lw lvw a b) (QID bv:e:c1) (PATS ($bv_extract ($bv_concat v lv w lw) lvw a b)) (IMPLIES (>= (- a lw) 0) (EQ ($bv_extract ($bv_concat v lv w lw) lvw a b) ($bv_extract v lv (- a lw) (- b lw))))) ; b<=l ==> (v ++ w:l)[a:b] = w[a:b] (FORALL (v lv w lw lvw a b) (QID bv:e:c2) (PATS ($bv_extract ($bv_concat v lv w lw) lvw a b)) (IMPLIES (<= b lw) (EQ ($bv_extract ($bv_concat v lv w lw) lvw a b) ($bv_extract w lw a b)))) ; v:l ; a>=x || b<=y ==> (v[x:l] ++ w ++ v[0:y])[a:b] = v[a:b] (FORALL (v lv x lxv w lw lwy y a b) (QID bv:e:c3) (PATS ($bv_extract ($bv_concat ($bv_extract v lv x lv) lxv ($bv_concat w lw ($bv_extract v lv 0 y) y) lwy) lv a b)) (IMPLIES (AND (EQ lw (- x y)) (EQ lxv (- lv x)) (EQ lwy (+ w y)) (OR (>= a x) (<= b y))) (EQ ($bv_extract ($bv_concat ($bv_extract v lv x lv) lxv ($bv_concat w lw ($bv_extract v lv 0 y) y) lwy) lv a b) ($bv_extract v lv a b)))) ; a>=x ==> (v[x:l] ++ w)[a:b] = v[a:b] (FORALL (v lv x lxv w a b) (QID bv:e:c4) (PATS ($bv_extract ($bv_concat ($bv_extract v lv x lv) lxv w x) lv a b)) (IMPLIES (AND (EQ lxv (- lv x)) (>= a x)) (EQ ($bv_extract ($bv_concat ($bv_extract v lv x lv) lxv w x) lv a b) ($bv_extract v lv a b)))) (FORALL (v l) (QID bv:e:0) (PATS ($bv_extract v l 0 l)) (EQ ($bv_extract v l 0 l) v)) (FORALL (n) (QID bv:pow) (PATS ($pow2 n)) (IMPLIES (> n 0) (EQ ($pow2 n) (* 2 ($pow2 (- n 1)))))) (EQ ($pow2 0) 1) ; 0 <= v < 2^Y ==> 0bvX ++ v[0:Y] == v (FORALL (v l a b) (QID bv:e:pow) (PATS ($bv_concat 0 b ($bv_extract v l 0 a) a)) (IMPLIES (AND (<= 0 v) (< v ($pow2 a)) (EQ l (+ a b))) (EQ ($bv_concat 0 b ($bv_extract v l 0 a) a) v))) ; X > 0 ==> 0bvX ++ v >= 0 (FORALL (v a b) (QID bv:e:pos) (PATS ($bv_concat 0 b v a)) (IMPLIES (> b 0) (>= ($bv_concat 0 b v a) 0))) ;; unsound? ; (FORALL (lv w lw) ; (QID bv:c:0) ; (PATS ($bv_concat 0 lv w lw)) ; (EQ ($bv_concat 0 lv w lw) w)) ;; matching loop ; (FORALL (v l1 a b l2 c d) ; (QID bv:e:e) ; (PATS ($bv_extract ($bv_extract v l1 a b) l2 c d)) ; (EQ ($bv_extract ($bv_extract v l1 a b) l2 c d) ($bv_extract v l1 (+ c a) (+ d a)))) ; Reflect plus (FORALL (a b) (PATS (Reflect$Add a b)) (EQ (Reflect$Add a b) (+ a b))) )) ;; AND, BG_PUSH ; End Boogie universal background predicate ; ------------------------------------------------------------------------- ================================================ FILE: ironclad-apps/tools/SymDiff/UnivBackPred2.smt ================================================ ; ------------------------------------------------------------------------- ; Boogie universal background predicate ; Copyright (c) 2004-2006, Microsoft Corp. :logic AUFLIA :category { industrial } :extrasorts ( boogieU ) :extrasorts ( boogieT ) :extrasorts ( TermBool ) :extrafuns (( boolTrue TermBool )) :extrafuns (( boolFalse TermBool )) :extrafuns (( boolIff TermBool TermBool TermBool )) :extrafuns (( boolImplies TermBool TermBool TermBool )) :extrafuns (( boolAnd TermBool TermBool TermBool )) :extrafuns (( boolOr TermBool TermBool TermBool )) :extrafuns (( boolNot TermBool TermBool )) :extrafuns (( UEqual boogieU boogieU TermBool )) :extrafuns (( TEqual boogieT boogieT TermBool )) :extrafuns (( IntEqual Int Int TermBool )) :extrafuns (( intLess Int Int TermBool )) :extrafuns (( intAtMost Int Int TermBool )) :extrafuns (( intGreater Int Int TermBool )) :extrafuns (( intAtLeast Int Int TermBool )) :extrafuns (( boogieIntMod Int Int Int )) :extrafuns (( boogieIntDiv Int Int Int )) ; used for translation with type premisses :extrapreds (( UOrdering2 boogieU boogieU )) ; used for translation with type arguments :extrapreds (( UOrdering3 boogieT boogieU boogieU )) ; used for translation with type premisses :extrafuns (( TermUOrdering2 boogieU boogieU TermBool )) ; used for translation with type arguments :extrafuns (( TermUOrdering3 boogieT boogieU boogieU TermBool )) ; formula/term axioms :assumption (forall (?x TermBool) (?y TermBool) (iff (= (boolIff ?x ?y) boolTrue) (iff (= ?x boolTrue) (= ?y boolTrue)))) :assumption (forall (?x TermBool) (?y TermBool) (iff (= (boolImplies ?x ?y) boolTrue) (implies (= ?x boolTrue) (= ?y boolTrue)))) :assumption (forall (?x TermBool) (?y TermBool) (iff (= (boolAnd ?x ?y) boolTrue) (and (= ?x boolTrue) (= ?y boolTrue)))) :assumption (forall (?x TermBool) (?y TermBool) (iff (= (boolOr ?x ?y) boolTrue) (or (= ?x boolTrue) (= ?y boolTrue)))) :assumption (forall (?x TermBool) (iff (= (boolNot ?x) boolTrue) (not (= ?x boolTrue))) :pat { (boolNot ?x) } ) :assumption (forall (?x boogieU) (?y boogieU) (iff (= (UEqual ?x ?y) boolTrue) (= ?x ?y))) :assumption (forall (?x boogieT) (?y boogieT) (iff (= (TEqual ?x ?y) boolTrue) (= ?x ?y))) :assumption (forall (?x Int) (?y Int) (iff (= (IntEqual ?x ?y) boolTrue) (= ?x ?y))) :assumption (forall (?x Int) (?y Int) (iff (= (intLess ?x ?y) boolTrue) (< ?x ?y))) :assumption (forall (?x Int) (?y Int) (iff (= (intAtMost ?x ?y) boolTrue) (<= ?x ?y))) :assumption (forall (?x Int) (?y Int) (iff (= (intAtLeast ?x ?y) boolTrue) (>= ?x ?y))) :assumption (forall (?x Int) (?y Int) (iff (= (intGreater ?x ?y) boolTrue) (> ?x ?y))) ; false is not true :assumption (distinct boolFalse boolTrue) :assumption (forall (?x boogieU) (?y boogieU) (iff (= (TermUOrdering2 ?x ?y) boolTrue) (UOrdering2 ?x ?y))) :assumption (forall (?x boogieT) (?y boogieU) (?z boogieU) (iff (= (TermUOrdering3 ?x ?y ?z) boolTrue) (UOrdering3 ?x ?y ?z))) ; End Boogie universal background predicate ; ------------------------------------------------------------------------- ================================================ FILE: ironclad-apps/tools/SymDiff/UnivBackPred2.smt2 ================================================ ; Boogie universal background predicate ; Copyright (c) 2004-2010, Microsoft Corp. (set-info :category "industrial") (declare-sort |T@U| 0) (declare-sort |T@T| 0) (declare-fun int_div (Int Int) Int) (declare-fun int_mod (Int Int) Int) (declare-fun UOrdering2 (|T@U| |T@U|) Bool) (declare-fun UOrdering3 (|T@T| |T@U| |T@U|) Bool) (declare-fun tickleBool (Bool) Bool) (assert (and (tickleBool true) (tickleBool false))) ================================================ FILE: ironclad-apps/tools/SymDiff/UnivBackPred2.sx ================================================ ; ------------------------------------------------------------------------- ; Boogie 2 universal background predicate ; Copyright (c) 2004-2008, Microsoft Corp. (DEFPRED (<: t u)) ; used for translation with type premisses (DEFPRED (<:: s t u)) ; used for translation with type arguments (BG_PUSH (AND ; formula/term axioms (FORALL (x y) (IFF (EQ (boolIff x y) |@true|) (IFF (EQ x |@true|) (EQ y |@true|)))) (FORALL (x y) (IFF (EQ (boolImplies x y) |@true|) (IMPLIES (EQ x |@true|) (EQ y |@true|)))) (FORALL (x y) (IFF (EQ (boolAnd x y) |@true|) (AND (EQ x |@true|) (EQ y |@true|)))) (FORALL (x y) (IFF (EQ (boolOr x y) |@true|) (OR (EQ x |@true|) (EQ y |@true|)))) (FORALL (x) (PATS (boolNot x)) (IFF (EQ (boolNot x) |@true|) (NEQ x |@true|))) (FORALL (x y) (IFF (EQ (anyEqual x y) |@true|) (EQ x y))) (FORALL (x y) (PATS (anyNeq x y)) (IFF (EQ (anyNeq x y) |@true|) (NEQ x y))) (FORALL (x y) (IFF (EQ (intLess x y) |@true|) (< x y))) (FORALL (x y) (IFF (EQ (intAtMost x y) |@true|) (<= x y))) (FORALL (x y) (IFF (EQ (intAtLeast x y) |@true|) (>= x y))) (FORALL (x y) (IFF (EQ (intGreater x y) |@true|) (> x y))) ; false is not true (DISTINCT |@false| |@true|) ;; The following axiom gives a way to typed produce verification conditions, ;; that is, verification conditions where the terms are typable. To use these, ;; the VCExpressionGenerator.{CastTo,CastFrom} methods must be overridden. ;; Look for USE_SORTED_LOGIC in VCGeneration/VCExpr.ssc. ; (FORALL (val T U) ; (PATS (TypeConvert (TypeConvert val T U) U T)) ; (EQ (TypeConvert (TypeConvert val T U) U T) val)) ; Reflect plus (FORALL (a b) (PATS (Reflect$Add a b)) (EQ (Reflect$Add a b) (+ a b))) )) ;; AND, BG_PUSH ; End Boogie universal background predicate ; ------------------------------------------------------------------------- ================================================ FILE: ironclad-apps/tools/build/x86_x86/cl.exe.config ================================================ ================================================ FILE: ironclad-apps/tools/build/x86_x86/link.exe.config ================================================ ================================================ FILE: ironclad-apps/tools/fsharp/FSharp.Compiler.CodeDom.xml ================================================ FSharp.Compiler.CodeDom The total number of elements in the set Remove the given element from the set Apply the given function to each binding in the hash table Apply the given function to the set threading the accumulating parameter through the sequence of function applications Create a new empty mutable hash set with key hash/equality based on the F# structural "hash" and (=) functions Create a new empty mutable hash set with an internal bucket array of the given approximate size and with key hash/equality based on the F# structural "hash" and (=) functions Create a new empty mutable hash set with an internal bucket array of the given approximate size and with the given key hash/equality functions Create a new mutable hash set containing elements drawn from the given sequence Make a shallow copy of the set Test if the set contains the given element Clear all elements from the set Add an element to the collection Create a new empty mutable hash set with key hash/equality based on the F# structural "hash" and (=) functions Create a new empty mutable hash set with an internal bucket array of the given approximate size and with key hash/equality based on the F# structural "hash" and (=) functions Create a new empty mutable hash set with an internal bucket array of the given approximate size and with the given key hash/equality functions Create a new mutable hash set containing elements drawn from the given sequence Mutable hash sets based by default on F# structural "hash" and (=) functions. Implemented via a hash table and/or Dictionary. The default location of FSharp.Core.dll and fsc.exe based on the version of fsc.exe that is running Implementation of the CodeDomProvider for the F# language. This is specialized version that can be used with ASP.NET. Implementation of the CodeDomProvider for the F# language. If you intend to use CodeDom with ASP.NET you should use FSharpAspNetCodeProvider instead. Where are we generating member? Generates code for binary operator using function for left and right operand Process collection - keeps context through the whole processing calls 'f' for every element in sequence and 'fs' between every two elements as a separator Call specified function only on elements of specified type. (performs dynamic type test using x.GetType()) Process collection - keeps context through the whole processing calls 'f' for every element in sequence and 'fs' between every two elements as a separator. This is a variant that works on typed collections. Returns F# conversion function for the specified type (or empty string) Create context using specified text writer and options Create closure to do the counting (this is usend when we need indexing during collection processing) Call function, but give it context as an argument Generate array initializer. Checks generator options for ASP.NET workaround. Generates expression which is casted to the inferred type using "(unbox (box e))" this is useful if the environment where it is used specifies the type explicitly for example in array initializers Generates method code, adds OverloadID attribute when index isn't "-1" Generates comments and than calls 'generatMethod' Generate code for compile unit (file) Generate expression - with unkonw type Generates expression, but generates "this" if the expression is null (used in field reference etc. because some CodeDOM generators do this though I believe it is a mistake) fields Abstract method in the interface Abstract property in the interface Generates a main method. By default all CodeDOM generated methods are 'virtual' which means that we have to generate "abstract and default" (unless we're in struct or we're implementing an interface, or the method is overriden) (NOTE: the same logic isn't properly implemented for properties) Generate code for namespace without compilation unit Generates namespace code - takes output from 'preprocessNamespace' Generate value of primitive expression Generate type arguments using context Generate code for type declaration (not included in namespace) Generate type reference using context (this is most commonly used method) Get type reference, but don't rename .NET types to F# types (this is only needed when calling static methods on the type) Generates type reference (not for arrays) Generate type reference with empty context Get full type reference using information from context Get full type reference string using empty context Identity function Are both types numerical types where numeric conversion function can be applied? Perform map and filter operations in one Output string as a valid F# identifier Append specified string without line-break Function composition operator Break-line and append specified string Returns CodeNamespace, list of classes with scope (which includes class names of containing classes and sequence of class renames) Preprocess collection with type parameters Returns array to be used with usingTyParams and function to be called to generate < ... > code Print object converted to string Tries to resolve type of a variable and adds it to the Context dictionary Tries to resolve type of an expression using a few tricks: * Fields of current type may have known type * Properties of current type as well * We can also try to resolve other properties (sometimes it helps) * Resolve type for local variables or argument reference Get System.Type of know type (either standard type or resolved) Tries to resolve if type is an array, so we can generate appropriate code (it can be either indexer or array, but we need to generate .Item call for indexers (no overloading is supported by .[]). Returns: "None" - can't resolve, "Some" resovled (true/false - is it an array?) Print unique id using: "+> uniqid" Record specified type parameters in the context, call generating function and then restore the original type parameters (this works if someone uses nested type parameters with the same name) Matches array or indexer expression and corrects it if the generated CodeDOM is incorrect Tries to find .NET type for specified type name This is used when we need to know type in order to generate something correctly, but it's just a fallback case Walks through the CodeDom tree and keeps current "scope" and the result. The result is collected through entire tree, but the modified scope is passed only to sub-nodes of the current node. First argument is a function that is called for nodes and has a function as a first argument, scope and result as a second and current node as a third. The function argument can be used to walk deeper in the tree if wanted. Search for members and return flat list of selected members Function given as an argument returns tuple - first item specifies if the current element should be included in the result, the second specifies if we should walk through child members of the current object ================================================ FILE: ironclad-apps/tools/fsharp/FSharp.Core.xml ================================================ FSharp.Core Gets the tail of the list, which is a list containing all the elements of the list, excluding the first element Gets the number of items contained in the list Get the element of the list at the given position. Note lists are represented as linked lists so this is an O(n) operation. Gets a value indicating if the list contains no entries Gets the first element of the list Returns an empty list of a particular type Returns a list with head as its first element and tail as its subsequent elements The type of immutable singly-linked lists. Use the constructors [] and :: (infix) to create values of this type, or the notation [1;2;3]. Use the values in the List module to manipulate values of this type, or pattern match against the values directly. An abbreviation for the type of immutable singly-linked lists. Lookup an element in the map. Raise KeyNotFoundException if no binding exists in the map. Return true if there are no bindings in the map. The empty map The number of bindings in the map Lookup an element in the map, returning a Some value if the element is in the domain of the map and None if not. Remove an element from the domain of the map. No exception is raised if the element is not present. Test if an element is in the domain of the map Return a new map with the binding added to the given map. Build a map that contains the bindings of the given IEnumerable Immutable maps. Keys are ordered by F# generic comparison. Maps based on generic comparison are efficient for small keys. They are not a suitable choice if keys are recursive data structures or if keys require bespoke comparison semantics. An abbreviation for the .NET type System.Collections.Generic.List<_> Return a new set with the elements of the second set removed from the first. Compute the union of the two sets. Returns the lowest element in the set according to the ordering being used for the set Returns the highest element in the set according to the ordering being used for the set A useful shortcut for Set.isEmpty. See the Set module for further operations on sets. The empty set for the type 'T. The number of elements in the set Return a new set with the elements of the second set removed from the first. A useful shortcut for Set.remove. Note this operation produces a new set and does not mutate the original set. The new set will share many storage nodes with the original. See the Set module for further operations on sets. Evaluates to "true" if all elements of the first set are in the second Evaluates to "true" if all elements of the second set are in the first Returns the greatest element in the set that is less than the given key according to the ordering being used for the set Returns the least element in the set that is greater than the given key according to the ordering being used for the set A useful shortcut for Set.contains. See the Set module for further operations on sets. A useful shortcut for Set.add. Note this operation produces a new set and does not mutate the original set. The new set will share many storage nodes with the original. See the Set module for further operations on sets. Create a set containing elements drawn from the given sequence. Immutable sets based on binary trees, where comparison is the F# structural comparison function, potentially using implementations of the IComparable interface on key values. See the Set module for further operations on sets. These sets can be used with elements of any type, but you should check that structural hashing and equality on the element type are correct for your type. An abbreviation for the type of immutable singly-linked lists. Use the constructors [] and :: (infix) to create values of this type, or the notation [1;2;3]. Use the values in the List module to manipulate values of this type, or pattern match against the values directly. An abbreviation for the .NET type System.Collections.Generic.IEnumerable<_> Fetch the base-index for the first dimension of the array. See notes on the Array2D module re. zero-basing. Fetch the base-index for the second dimension of the array. See notes on the Array2D module re. zero-basing. Read a range of elements from the first array and write them into the second. Build a new array whose elements are the same as the input array. For non-zero-based arrays the basing on an input array will be propogated to the output array. Create an array whose elements are all initially the given value Create a based array whose elements are all initially the given value Fetch an element from a 2D array. You can also use the syntax 'array.[index1,index2]' Create an array given the dimensions and a generator function to compute the elements. Create a based array given the dimensions and a generator function to compute the elements. Apply the given function to each element of the array. Apply the given function to each element of the array. The integer indicies passed to the function indicates the index of element. Return the length of an array in the first dimension Return the length of an array in the second dimension Build a new array whose elements are the results of applying the given function to each of the elements of the array. For non-zero-based arrays the basing on an input array will be propogated to the output array. Build a new array whose elements are the results of applying the given function to each of the elements of the array. The integer indices passed to the function indicates the element being transformed. For non-zero-based arrays the basing on an input array will be propogated to the output array. Build a new array whose elements are the same as the input array but where a non-zero-based input array generates a corresponding zero-based output array. Set the value of an element in an array. You can also use the syntax 'array.[index1,index2] <- value' Create an array where the entries are initially Unchecked.defaultof<'T>. Create a based array where the entries are initially Unchecked.defaultof<'T>. Basic operations on 2-dimensional arrays. F# and .NET multi-dimensional arrays are typically zero-based. However, .NET multi-dimensional arrays used in conjunction with external libraries (e.g. libraries associated with Visual Basic) be non-zero based, using a potentially different base for each dimension. The operations in this module will accept such arrays, and the basing on an input array will be propogated to a matching output array on the Array2D.map and Array2D.mapi operations. Non-zero-based arrays can also be created using Array2D.zero_create_based, Array2D.create_based and Array2D.init_based. Create an array whose elements are all initially the given value Fetch an element from a 3D array. You can also use the syntax 'array.[index1,index2,index3]' Create an array given the dimensions and a generator function to compute the elements. Apply the given function to each element of the array. Apply the given function to each element of the array. The integer indicies passed to the function indicates the index of element. Return the length of an array in the first dimension Return the length of an array in the second dimension Return the length of an array in the third dimension Build a new array whose elements are the results of applying the given function to each of the elements of the array. For non-zero-based arrays the basing on an input array will be propogated to the output array. Build a new array whose elements are the results of applying the given function to each of the elements of the array. The integer indices passed to the function indicates the element being transformed. For non-zero-based arrays the basing on an input array will be propogated to the output array. Set the value of an element in an array. You can also use the syntax 'array.[index1,index2,index3] <- value'. Create an array where the entries are initially the "default" value. Basic operations on rank 3 arrays. Create an array whose elements are all initially the given value Fetch an element from a 4D array. You can also use the syntax 'array.[index1,index2,index3,index4]' Create an array given the dimensions and a generator function to compute the elements. Return the length of an array in the first dimension Return the length of an array in the second dimension Return the length of an array in the third dimension Return the length of an array in the fourth dimension Set the value of an element in an array. You can also use the syntax 'array.[index1,index2,index3,index4] <- value'. Create an array where the entries are initially the "default" value. Basic operations on rank 4 arrays. Build a new array that contains the elements of the first array followed by the elements of the second array Return the average of the elements in the array. If the array is empty an ArgumentException is thrown. Return the average of the elements generated by applying the function to each element of the array. If the array is empty an ArgumentException is thrown. Read a range of elements from the first array and write them into the second. Apply the given function to each element of the array. Return the array comprised of the results "x" for each element where the function returns Some(x) For each element of the array, apply the given function. Concatenate all the results and return the combined array. Build a new array that contains the elements of each of the given sequence of arrays Build a new array that contains the elements of the given array Create an array whose elements are all initially the given value. Return an empty array of the given type Test if any element of the array satisfies the given predicate. The predicate is applied to the elements of the input array. If any application returns true then the overall result is true and no further elements are tested. Otherwise, false is returned. Test if any pair of corresponding elements of the arrays satisfies the given predicate. The predicate is applied to matching elements in the two collections up to the lesser of the two lengths of the collections. If any application returns true then the overall result is true and no further elements are tested. Otherwise, if one collections is longer than the other then the ArgumentException exception is raised. Otherwise, false is returned. Fill a range of elements of the array with the given value. Return a new collection containing only the elements of the collection for which the given predicate returns "true" Return the first element for which the given function returns 'true'. Raise KeyNotFoundException if no such element exists. Return the index of the first element in the array that satisfies the given predicate. Raise KeyNotFoundException if none of the elements satisy the predicate. Apply a function to each element of the collection, threading an accumulator argument through the computation. If the input function is f and the elements are i0...iN then computes f (... (f s i0)...) iN Apply a function to pairs of elements drawn from the two collections, left-to-right, threading an accumulator argument through the computation. The two input arrays must have the same lengths, otherwise an ArgumentException is raised. Apply a function to each element of the array, threading an accumulator argument through the computation. If the input function is f and the elements are i0...iN then computes f i0 (...(f iN s)) Apply a function to pairs of elements drawn from the two collections, right-to-left, threading an accumulator argument through the computation. The two input arrays must have the same lengths, otherwise an ArgumentException is raised. Apply a function to pairs of elements drawn from the two collections, left-to-right, threading an accumulator argument through the computation. The two input arrays must have the same lengths, otherwise an ArgumentException is raised. Apply a function to each element of the array, threading an accumulator argument through the computation. If the input function is f and the elements are i0...iN then computes f i0 (...(f iN s)) Test if all elements of the array satisfy the given predicate. The predicate is applied to the elements of the input collection. If any application returns false then the overall result is false and no further elements are tested. Otherwise, true is returned. Test if all corresponding elements of the array satisfy the given predicate pairwise. The predicate is applied to matching elements in the two collections up to the lesser of the two lengths of the collections. If any application returns false then the overall result is false and no further elements are tested. Otherwise, if one collection is longer than the other then the ArgumentException exception is raised. Otherwise, true is returned. Get an element from an array Create an array given the dimension and a generator function to compute the elements. Return true if the given array is empty, otherwise false Apply the given function to each element of the array. Apply the given function to pair of elements drawn from matching indices in two arrays. The two arrays must have the same lengths, otherwise an ArgumentException is raised. Apply the given function to each element of the array. The integer passed to the function indicates the index of element. Apply the given function to pair of elements drawn from matching indices in two arrays, also passing the index of the elements. The two arrays must have the same lengths, otherwise an ArgumentException is raised. Return the length of an array. You can also use property arr.Length. Build a new array whose elements are the results of applying the given function to each of the elements of the array. Build a new collection whose elements are the results of applying the given function to the corresponding elements of the two collections pairwise. The two input arrays must have the same lengths, otherwise an ArgumentException is raised. Build a new array whose elements are the results of applying the given function to each of the elements of the array. The integer index passed to the function indicates the index of element being transformed. Build a new collection whose elements are the results of applying the given function to the corresponding elements of the two collections pairwise, also passing the index of the elements. The two input arrays must have the same lengths, otherwise an ArgumentException is raised. Return the greatest of all elements of the array, compared via Operators.max on the function result Return the greatest of all elements of the array, compared via Operators.max on the function result Return the lowest of all elements of the array, compared via Operators.min Return the lowest of all elements of the array, compared via Operators.min on the function result Build an array from the given list Build a new array from the given enumerable object Split the collection into two collections, containing the elements for which the given predicate returns "true" and "false" respectively Returns an array with all elements permuted according to the specified permutation Apply the given function to successive elements, returning the first result where function returns Some(x) for some x. If the function never returns Some(x) then KeyNotFoundException is raised. Apply a function to each element of the array, threading an accumulator argument through the computation. If the input function is f and the elements are i0...iN then computes f (... (f i0 i1)...) iN. Raises ArgumentException if the array has size zero. Apply a function to each element of the array, threading an accumulator argument through the computation. If the input function is f and the elements are i0...iN then computes f i0 (...(f iN-1 iN)). Raises ArgumentException if the array has size zero. Return a new array with the elements in reverse order Like fold_left, but return the intermediary and final results Like fold_right, but return both the intermediary and final results Set an element of an array Sort the elements of an array, returning a new array. Elements are compared using Operators.compare. Sort the elements of an array, using the given projection for the keys and returning a new array. Elements are compared using Operators.compare. Sort the elements of an array by mutating the array in-place, using the given comparison function. Elements are compared using Operators.compare. Sort the elements of an array by mutating the array in-place, using the given projection for the keys. Elements are compared using Operators.compare. Sort the elements of an array by mutating the array in-place, using the given comparison function as the order Sort the elements of an array, using the given comparison function as the order, returning a new array Sort the elements of an array, using the given projection for the keys. Elements are compared using Operators.compare. Build a new array that contains the given subrange specified by starting index and length. Return the sum of the elements in the array Return the sum of the results generated by applying the function to each element of the array. Build a list from the given array View the given array as a sequence Return the first element for which the given function returns true. Return None if no such element exists. Return the index of the first element in the array that satisfies the given predicate. Apply the given function to successive elements, returning the first result where function returns Some(x) for some x. If the function never returns Some(x) then None is returned. Split an array of pairs into two arrays Split an array of triples into three arrays Create an array where the entries are initially the default value Unchecked.defaultof<'T>. Create an array where the entries are initially the default value Unchecked.defaultof<'T>. Combine the two arrays into an array of pairs. The two arrays must have equal lengths, otherwise an ArgumentException is raised. Combine three arrays into an array of pairs. The three arrays must have equal lengths, otherwise an ArgumentException is raised. Basic operations on arrays Compare using the given comparer function Convert an existing IComparer object into a comparison function with a fast entry point If comparer was originally built using ComparisonIdentity.FromFunction then the original function will be returned Convert an existing IComparer object into a comparison function with a fast entry point Structural comparison. Compare using Operators.compare. Common notions of comparison identity used with sorted data structures. Hash using the given hashing and equality functions Physical hashing (hash on reference identity of objects, and the contents of value types). Hash using LanguagePrimitives.PhysicalEquality and LanguagePrimitives.PhysicalHash, That is, for value types use GetHashCode and Object.Equals (if no other optimization available), and for reference types use System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode and reference equality. Structural hashing. Hash using Operators.(=) and Operators.hash. Common notions of value identity used with hash tables. Return a new list that contains the elements of the first list followed by elements of the second Return the average of the elements in the list. If the list is empty an ArgumentException is thrown. Return the average of the elements generated by applying the function to each element of the list. If the list is empty an ArgumentException is thrown. Apply the given function to each element of the list. Return the list comprised of the results x for each element where the function returns Some(x) For each element of the list, apply the given function. Concatenate all the results and return the combined list. Return a new list that contains the elements of each the lists in order Return an empty list of the given type Test if any element of the list satisfies the given predicate. The predicate is applied to the elements of the input list. If any application returns true then the overall result is true and no further elements are tested. Otherwise, false is returned. Test if any pair of corresponding elements of the lists satisfies the given predicate. The predicate is applied to matching elements in the two collections up to the lesser of the two lengths of the collections. If any application returns true then the overall result is true and no further elements are tested. Otherwise, if one collections is longer than the other then the ArgumentException exception is raised. Otherwise, false is returned. Return a new collection containing only the elements of the collection for which the given predicate returns "true" Return the first element for which the given function returns true. Raise KeyNotFoundException if no such element exists. Return the index of the first element in the list that satisfies the given predicate. Raise KeyNotFoundException if no such element exists. Apply a function to each element of the collection, threading an accumulator argument through the computation. Take the second argument, and apply the function to it and the first element of the list. Then feed this result into the function along with the second element and so on. Return the final result. If the input function is f and the elements are i0...iN then computes f (... (f s i0) i1 ...) iN Apply a function to corresponding elements of two collections, threading an accumulator argument through the computation. The collections must have identical sizes. If the input function is f and the elements are i0...iN and j0...jN then computes f (... (f s i0 j0)...) iN jN. Apply a function to each element of the collection, threading an accumulator argument through the computation. If the input function is f and the elements are i0...iN then computes f i0 (...(f iN s)). Apply a function to corresponding elements of two collections, threading an accumulator argument through the computation. The collections must have identical sizes. If the input function is f and the elements are i0...iN and j0...jN then computes f i0 j0 (...(f iN jN s)). Test if all elements of the collection satisfy the given predicate. The predicate is applied to the elements of the input list. If any application returns false then the overall result is false and no further elements are tested. Otherwise, true is returned. Test if all corresponding elements of the collection satisfy the given predicate pairwise. The predicate is applied to matching elements in the two collections up to the lesser of the two lengths of the collections. If any application returns false then the overall result is false and no further elements are tested. Otherwise, if one collection is longer than the other then the ArgumentException exception is raised. Otherwise, true is returned. Return the first element of the list. Raise (Invalid_argument "hd") if undefined. Create a list by calling the given generator on each index Return true if the list contains no elements, false otherwise Apply the given function to each element of the collection. Apply the given function to two collections simultaneously. The collections must have identical size. Apply the given function to each element of the collection. The integer passed to the function indicates the index of element. Apply the given function to two collections simultaneously. The collections must have identical size. The integer passed to the function indicates the index of element. Return the length of the list Build a new collection whose elements are the results of applying the given function to each of the elements of the collection. Build a new collection whose elements are the results of applying the given function to the corresponding elements of the two collections pairwise. Build a new collection whose elements are the results of applying the given function to the corresponding elements of the three collections simultaneously. Build a new collection whose elements are the results of applying the given function to each of the elements of the collection. The integer index passed to the function indicates the index (from 0) of element being transformed. Like mapi, but mapping corresponding elements from two lists of equal length. Return the greatest of all elements of the list, compared via Operators.max Return the greatest of all elements of the array, compared via Operators.max on the function result Return the lowest of all elements of the list, compared via Operators.min Return the lowest of all elements of the array, compared via Operators.min on the function result Index into the list. The first element has index 0. Build a collection from the given array Build a new collection from the given enumerable object Split the collection into two collections, containing the elements for which the given predicate returns true and false respectively Returns a list with all elements permuted according to the specified permutation Apply the given function to successive elements, returning the first result where function returns Some(x) for some x. If no such element exists then raise System.Collections.Generic.KeyNotFoundException Apply a function to each element of the collection, threading an accumulator argument through the computation. Apply the function to the first two elements of the list. Then feed this result into the function along with the third element and so on. Return the final result. If the input function is f and the elements are i0...iN then computes f (... (f i0 i1) i2 ...) iN. Raises ArgumentException if the list has no elements. Apply a function to each element of the collection, threading an accumulator argument through the computation. If the input function is f and the elements are i0...iN then computes f i0 (...(f iN-1 iN)). Raises ArgumentException if the list has no elements. Create a list by calling the given generator on each index Return a new list with the elements in reverse order Apply a function to each element of the collection, threading an accumulator argument through the computation. Take the second argument, and apply the function to it and the first element of the list. Then feed this result into the function along with the second element and so on. Return the list of intermediate results and the final result. Like foldBack, but return both the intermediary and final results Sort the given list using the given comparison function Sort the given list using keys given by the given projection. Keys are compared using Operators.compare. Sort the given list using the given comparison function Return the sum of the elements in the list Return the sum of the results generated by applying the function to each element of the list. Return the tail of the list. Raise (Invalid_argument "tl") if undefined. Build an array from the given collection Build a new collection from the given enumerable object Return the first element for which the given function returns true. Return None if no such element exists. Return the index of the first element in the list that satisfies the given predicate. Return None if no such element exists. Apply the given function to successive elements, returning Some(x) the first result where function returns Some(x) for some x. If no such element exists then return None Split a list of pairs into two lists Split a list of triples into three lists Combine the two lists into a list of pairs. The two lists must have equal lengths. Combine the three lists into a list of triples. The lists must have equal lengths. Basic operations on lists. Return a new map with the binding added to the given map. Test is an element is in the domain of the map The empty map Return true if the given predicate returns true for one of the bindings in the map. Build a new map containing only the bindings for which the given predicate returns 'true' Lookup an element in the map, raising KeyNotFoundException if no binding exists in the map. Evaluates the function on each mapping in the collection. Returns the key for the first mapping where the function returns 'true'. Raise KeyNotFoundException if no such element exists. Search the map looking for the first element where the given function returns a Some value Fold over the bindings in the map Fold over the bindings in the map Return true if the given predicate returns true for all of the bindings in the map. Is the map empty? Apply the given function to each binding in the dictionary Build a new collection whose elements are the results of applying the given function to each of the elements of the collection. The index passed to the function indicates the index of element being transformed. Return a new map made from the given bindings Return a new map made from the given bindings Return a new map made from the given bindings Build two new maps, one containing the bindings for which the given predicate returns 'true', and the other the remaining bindings. Search the map looking for the first element where the given function returns a Some value Remove an element from the domain of the map. No exception is raised if the element is not present. Returns an array of all key-value pairs in the mappinng Returns a list of all key-value pairs in the mappinng View the collection as an enumerable sequence. This collection type is also directly compatible with 'seq<KeyValuePair<_,_> >'. Note this function returns a sequence of tuples, whereas the collection itself is compatible with the logically equivalent sequence of KeyValuePairs. Using sequences of tuples tends to be more convenient in F#, however the collection itself must enumerate KeyValuePairs to conform to the .NET design guidelines and the IDictionary interface. Lookup an element in the map, returning a Some value if the element is in the domain of the map and None if not. Return the key of the first mapping in the collection that satisfies the given predicate. Return 'None' if no such element exists. Search the map looking for the first element where the given function returns a Some value Functional programming operators related to the Map<_,_> type. Wrap the two given enumeration-of-enumerations as a single concatenated enumeration. The returned sequence may be passed between threads safely. However, individual IEnumerator values generated from the returned sequence should not be accessed concurrently. Return the average of the elements in the sequence The elements are averaged using the '+' operator, 'DivideByInt' method and 'Zero' property associated with the element type. Return the average of the results generated by applying the function to each element of the sequence. The elements are averaged using the '+' operator, 'DivideByInt' method and 'Zero' property associated with the generated type. Return a sequence that corresponds to a cached version of the input sequence. This result sequence will have the same elements as the input sequence. The result can be enumerated multiple times. The input sequence will be enumerated at most once and only as far as is necessary. Enumeration of the result sequence is thread safe in the sense that multiple independent IEnumerator values may be used simultaneously from different threads (accesses to the internal lookaside table are thread safe). Each individual IEnumerator is not typically thread safe and should not be accessed concurrently. Note, once enumeration of the input sequence has started, it's enumerator will be kept live by this object until the enumeration has completed. At that point, the enumerator will be disposed. The enumerator may be disposed and underlying cache storage released by converting the returned sequence object to type IDisposable, and calling the Dispose method on this object. The sequence object may then be re-enumerated and a fresh enumerator will be used. Wrap a loosely-typed System.Collections sequence as a typed sequence. The use of this function usually requires a type annotation. An incorrect type annotation may result in runtime type errors. Individual IEnumerator values generated from the returned sequence should not be accessed concurrently. Apply the given function to each element of the list. Return the list comprised of the results "x" for each element where the function returns Some(x) The returned sequence may be passed between threads safely. However, individual IEnumerator values generated from the returned sequence should not be accessed concurrently. Remember sequence is lazy, effects are delayed until it is enumerated. For each element of the enumeration apply the given function and concatenate all the results. Remember sequence is lazy, effects are delayed until it is enumerated. Compare two sequence's using generic comparison, element by element. Compare two sequence's using the given comparison function, element by element. Wrap the given enumeration-of-enumerations as a single concatenated enumeration. The returned sequence may be passed between threads safely. However, individual IEnumerator values generated from the returned sequence should not be accessed concurrently. Apply a key-generating function to each element of a sequence and return a sequence yielding unique keys and their number of occurences in the original sequence. Note that this function returns a sequence that digests the whole initial sequence as soon as that sequence is iterated. As a result this function should not be used with large or infinite sequences. The function makes no assumption on the ordering of the original sequence. Return a sequence that is built from the given delayed specification of an Seq. The input function is evaluated each time an IEnumerator for the sequence is requested. Return a sequence that contains no duplicate entries according to generic hash and equality comparisons on the entries. If an element occurs multiple times in the sequence then the later occurrences are discarded. Return a sequence that contains no duplicate entries according to the generic hash and equality comparisons on the keys returned by the given key-generating function. If an element occurs multiple times in the sequence then the later occurrences are discarded. Create an empty sequence Test if any element of the sequence satisfies the given predicate. The predicate is applied to the elements of the input sequence. If any application returns true then the overall result is true and no further elements are tested. Otherwise, false is returned. Test if any pair of corresponding elements of the input sequences satisfies the given predicate. The predicate is applied to matching elements in the two sequences up to the lesser of the two lengths of the collections. If any application returns true then the overall result is true and no further elements are tested. Otherwise, false is returned. If one sequence is shorter than the other then the remaining elements of the longer sequence are ignored. Return a new collection containing only the elements of the collection for which the given predicate returns "true" The returned sequence may be passed between threads safely. However, individual IEnumerator values generated from the returned sequence should not be accessed concurrently. Remember sequence is lazy, effects are delayed until it is enumerated. Return the first element for which the given function returns true. Raise KeyNotFoundException if no such element exists. Return the index of the first element in the sequence of pairs that satisfies the given predicate. Raise KeyNotFoundException if no such element exists. Apply a function to each element of the collection, threading an accumulator argument through the computation. If the input function is f and the elements are i0...iN then computes f (... (f s i0)...) iN Test if all elements of the sequence satisfy the given predicate. The predicate is applied to the elements of the input sequence. If any application returns false then the overall result is false and no further elements are tested. Otherwise, true is returned. Test the all pairs of elements drawn from the two sequences satisfies the given predicate. If one sequence is shorter than the other then the remaining elements of the longer sequence are ignored Apply a key-generating function to each element of a sequence and yields a sequence of unique keys. Each unique key has also contains a sequence of all elements that match to this key. Note that this function returns a sequence that digests the whole initial sequence as soon as that sequence is iterated. As a result this function should not be used with large or infinite sequences. The function makes no assumption on the ordering of the original sequence. Return the first element of the sequence. Generate a new sequence which, when iterated, will return successive elements by calling the given function, up to the given count. The results of calling the function will not be saved, i.e. the function will be reapplied as necessary to regenerate the elements. The function is passed the index of the item being generated. The returned sequence may be passed between threads safely. However, individual IEnumerator values generated from the returned sequence should not be accessed concurrently. Generate a new sequence which, when iterated, will return successive elements by calling the given function. The results of calling the function will not be saved, i.e. the function will be reapplied as necessary to regenerate the elements. The function is passed the index of the item being generated The returned sequence may be passed between threads safely. However, individual IEnumerator values generated from the returned sequence should not be accessed concurrently. Return true if the sequence contains no elements, false otherwise Apply the given function to each element of the collection. Apply the given function to two collections simultaneously. If one sequence is shorter than the other then the remaining elements of the longer sequence are ignored. Apply the given function to each element of the collection. The integer passed to the function indicates the index of element. Return the length of the sequence Build a new collection whose elements are the results of applying the given function to each of the elements of the collection. The given function will be applied as elements are demanded using the 'MoveNext' method on enumerators retrieved from the object. The returned sequence may be passed between threads safely. However, individual IEnumerator values generated from the returned sequence should not be accessed concurrently. Build a new collection whose elements are the results of applying the given function to the corresponding pairs of elements from the two sequences. If one input sequence is shorter than the other then the remaining elements of the longer sequence are ignored. Build a new collection whose elements are the results of applying the given function to each of the elements of the collection. The integer index passed to the function indicates the index (from 0) of element being transformed. Return the greatest of all elements of the sequence, compared via Operators.max Return the greatest of all elements of the array, compared via Operators.max on the function result Return the lowest of all elements of the sequence, compared via Operators.min Return the lowest of all elements of the array, compared via Operators.min on the function result Compute the nth element in the collection. Build a collection from the given array Build a collection from the given array Return a sequence of each element in the input sequence and its predecessor, with the exception of the first element which is only returned as the predecessor of the second element. Apply the given function to successive elements, returning the first 'x' where the function returns "Some(x)". Build a new sequence object that delegates to the given sequence object. This ensures the original sequence can't be rediscovered and mutated by a type cast. For example, if given an array the returned sequence will return the elements of the array, but you can't cast the returned sequence object to an array. Apply a function to each element of the sequence, threading an accumulator argument through the computation. Begin by applying the function to the first two elements. Then feed this result into the function along with the third element and so on. Return the final result. Raises ArgumentException if the sequence has no elements. Like fold, but compute on-demand and return the sequence of intermediary and final results Return a sequence that yields one item only. Return a sequence that skips N elements of the underlying sequence and then yields the remaining elements of the sequence Return a sequence that, when iterated, skips elements of the underlying sequence while the given predicate returns 'true', and then yields the remaining elements of the sequence Yield a sequence ordered by keys. Note that this function returns a sequence that digests the whole initial sequence as soon as that sequence is iterated. As a result this function should not be used with large or infinite sequences. The function makes no assumption on the ordering of the original sequence. Apply a key-generating function to each element of a sequence and yield a sequence ordered by keys. The keys are compared using generic comparison as implemented by Operators.compare. Note that this function returns a sequence that digests the whole initial sequence as soon as that sequence is iterated. As a result this function should not be used with large or infinite sequences. The function makes no assumption on the ordering of the original sequence. Return the sum of the elements in the sequence. The elements are summed using the '+' operator and 'Zero' property associated with the generated type. Return the sum of the results generated by applying the function to each element of the sequence. The generated elements are summed using the '+' operator and 'Zero' property associated with the generated type. Return the first N elements of the sequence. Return a sequence that, when iterated, yields elements of the underlying sequence while the given predicate returns 'true', and returns no further elements Build an array from the given collection Build a list from the given collection Return a sequence that when enumerated returns at most N elements. Return the first element for which the given function returns true. Return None if no such element exists. Return the index of the first element in the sequence that satisfies the given predicate. Return 'None' if no such element exists. Apply the given function to successive elements, returning the first result where the function returns "Some(x)". Return a sequence that contains the elements generated by the given computation. The given initial 'state' argument is passed to the element generator. For each IEnumerator elements in the stream are generated on-demand by applying the element generator, until a None value is returned by the element generator. Each call to the element generator returns a new residual 'state'. Note the stream will be recomputed each time an IEnumerator is requested and iterated for the Seq. The returned sequence may be passed between threads safely. However, individual IEnumerator values generated from the returned sequence should not be accessed concurrently. Return a sequence that yields 'sliding windows' of containing elements drawn from the input sequence. Each window is returned as a fresh array. Combine the two sequences into a list of pairs. The two sequences need not have equal lengths: when one sequence is exhausted any remaining elements in the other sequence are ignored. Combine the three sequences into a list of triples. The two sequences need not have equal lengths: when one sequence is exhausted any remaining elements in the other sequence are ignored. Basic operations on IEnumerables. The F# compiler emits implementations of this method for compiled sequence expressions The F# compiler emits implementations of this method for compiled sequence expressions The F# compiler emits implementations of this method for compiled sequence expressions The F# compiler emits implementations of this method for compiled sequence expressions The F# compiler emits implementations of this method for compiled sequence expressions The F# compiler emits implementations of this method for compiled sequence expressions The F# compiler emits implementations of this type for compiled sequence expressions The F# compiler emits calls to this function to implement the compiler-intrinsic conversions from untyped System.Collections.IEnumerable sequences to typed sequences The F# compiler emits calls to this function to implement the 'try/finally' operator for F# sequence expressions The F# compiler emits calls to this function to implement the 'use' operator for F# sequence expressions The F# compiler emits calls to this function to implement the 'while' operator for F# sequence expressions A group of functions used as part of the compiled representation of F# sequence expressions Return a new set with an element added to the set. No exception is raised if the set already contains the given element. Returns the minimum element of the set Evaluates to "true" if the given element is in the given set Return the number of elements in the set. Same as size Return a new set with the elements of the second set removed from the first. The empty set for the type 'T . Test if any element of the collection satisfies the given predicate. If the input function is f and the elements are i0...iN then computes p i0 or ... or p iN. Return a new collection containing only the elements of the collection for which the given predicate returns true Apply the given accumulating function to all the elements of the set Apply the given accumulating function to all the elements of the set Test if all elements of the collection satisfy the given predicate. If the input function is f and the elements are i0...iN and "j0...jN" then computes p i0 && ... && p iN. Compute the intersection of the two sets. Compute the intersection of a sequence of sets. The sequence must be non-empty Return "true" if the set is empty Apply the given function to each element of the set, in order according to the comparison function Return a new collection containing the results of applying the given function to each element of the input set Evaluates to "true" if the given element is in the given set Build a set that contains the same elements as the given array Build a set that contains the same elements as the given list Build a new collection from the given enumerable object Split the set into two sets containing the elements for which the given predicate returns true and false respectively Return a new set with the given element removed. No exception is raised in the set doesn't contain the given element. The set containing the given one element. Evaluates to "true" if all elements of the second set are in the first Build an array that contains the elements of the set in order Build a list that contains the elements of the set in order Return a view of the collection as an enumerable object Compute the union of the two sets. Compute the union of a sequence of sets. Functional programming operators related to the Set<_> type. Get the default group for executing asynchronous computations Specify an asynchronous computation that, when run, executes computation, If p is effectively cancelled before its termination then the process f exn is executed. Specify an asynchronous computation that, when run, queues a CPU-intensive work in the thread pool item that runs its continutation. Specify an asynchronous computation that, when run, creates a new thread and runs its continutation in that thread Specify an asynchronous computation that, when run, runs its continuation using syncContext.Post. If syncContext is null then the asynchronous computation is equivalent to SwitchToThreadPool(). Start a child computation within an asynchronous workflow. This allows multiple asynchronous computations to be executed simultaneously. This method should normally be used as the immediate right-hand-side of a 'let!' binding in an F# asynchronous workflow, i.e., async { ... let! completor1 = childComputation1 |> Async.StartChild let! completor2 = childComputation2 |> Async.StartChild ... let! result1 = completor1 let! result2 = completor2 ... } When used in this way, each use of StartChild starts an instance of childComputation and returns a completor object representing a computation to wait for the completion of the operation. When executed, the completor awaits the completion of childComputation. Start the asynchronous computation in the thread pool. Do not await its result. Run as part of the default AsyncGroup Run an asynchronous computation, initially as a work item. Run as part of the default AsyncGroup Run the asynchronous computation and await its result. If an exception occurs in the asynchronous computation then an exception is re-raised by this function. Run as part of the default AsyncGroup Specify an asynchronous computation that, when run, executes the given callback. The callback must eventually call either the continuation, the exception continuation or the cancel exception. Specify an asynchronous computation that, when run, executese the three asynchronous computations, starting each in the thread pool. If any raise an exception then the overall computation will raise an exception, and attempt to cancel the others. All the sub-computations belong to an AsyncGroup that is a subsidiary of the AsyncGroup of the outer computations. Specify an asynchronous computation that, when run, executes the two asynchronous computations, starting each in the thread pool. If any raise an exception then the overall computation will raise an exception, and attempt to cancel the others. All the sub-computations belong to an AsyncGroup that is a subsidiary of the AsyncGroup of the outer computations. Specify an asynchronous computation that, when run, executes all the given asynchronous computations, initially queueing each as work items and using a fork/join pattern. If any raise an exception then the overall computation will raise the first detected exception, and attempt to cancel the others. All the sub-computations belong to an AsyncGroup that is a subsidiary of the AsyncGroup of the outer computations. Generate a scoped, cooperative cancellation handler for use within an asynchronous workflow. async { use! holder = Async.OnCancel f ... } generates an asynchronous computation where, if a cancellation happens any time during the execution of the asynchronous computation in the scope of 'holder', then action 'f' is executed on the thread that is performing the cancellation. You can use this to arrange for your own computation to be asynchronously notified that a cancellation has occurred, e.g. by setting a flag, or deregistering a pending I/O action. Specify an asynchronous computation that, when run, runs 'p', ignoring the result and returning the result '()'. Get the default group for executing asynchronous computations Raise the cancellation condition for the most recent set of Async computations started without any specific AsyncGroup. Replace the global group with a new global group for any asynchronous computations created after this point without any specific AsyncGroup. Specify an asynchronous computation in terms of a Begin/End pair of actions in the style used in .NET APIs where the overall operation is not qualified by any arguments. For example, Async.BuildPrimitive(ws.BeginGetWeather,ws.EndGetWeather) When the computation is run, the 'Begin' half of the operation is executed, and an asynchronous computation is returned that, when run, awaits the completion of the computation and fetches its overall result using the 'End' operation. Specify an asynchronous computation in terms of a Begin/End pair of actions in the style used in .NET APIs where the overall operation is qualified by one argument. For example, Async.BuildPrimitive(place,ws.BeginGetWeather,ws.EndGetWeather) When the computation is run, the 'Begin' half of the operation is executed, and an asynchronous computation is returned that, when run, awaits the completion of the computation and fetches its overall result using the 'End' operation. Specify an asynchronous computation in terms of a Begin/End pair of actions in the style used in .NET APIs where the overall operation is qualified by two arguments. For example, Async.BuildPrimitive(arg1,arg2,ws.BeginGetWeather,ws.EndGetWeather) When the computation is run, the 'Begin' half of the operation is executed, and an asynchronous computation is returned that, when run, awaits the completion of the computation and fetches its overall result using the 'End' operation. Specify an asynchronous computation in terms of a Begin/End pair of actions in the style used in .NET APIs where the overall operation is qualified by three arguments. For example, Async.BuildPrimitive(arg1,arg2,arg3,ws.BeginGetWeather,ws.EndGetWeather) When the computation is run, the 'Begin' half of the operation is executed, and an asynchronous computation is returned that, when run, awaits the completion of the computation and fetches its overall result using the 'End' operation. This static class holds members for creating and manipulating asynchronous computations Specify an asynchronous computation that, when run, just returns '()' Specify an asynchronous computation that, when run, runs 'p' repeatedly until 'gd()' becomes false. Specify an asynchronous computation that, when run, runs 'f(resource)'. The action 'resource.Dispose()' is executed as this computation yields its result or if the asynchronous computation exits by an exception or by cancellation. Specify an asynchronous computation that, when run, runs 'p' and returns its result. If an exception happens then 'f(exn)' is called and the resulting computation executed instead. Specify an asynchronous computation that, when run, runs 'p'. The action 'f' is executed after 'p' completes, whether 'p' exits normally or by an exception. If 'f' raises an exception itself the original exception is discarded and the new exception becomes the overall result of the computation. Specify an asynchronous computation that, when run, returns the result 'v' Specify an asynchronous computation that, when run, enumerates the sequence 'seq' on demand and runs 'f' for each element. Specify an asynchronous computation that, when run, runs 'f()' Specify an asynchronous computation that, when run, first runs 'p1' and then runs 'p2', returning the result of 'p2'. Specify an asynchronous computation that, when run, runs 'p', and when 'p' generates a result 'T', runs 'f res'. Generate an object used to build asynchronous computations using F# computation expressions. The value 'async' is a pre-defined instance of this type. The type of the 'async' operator, used to build workflows for asynchronous computations. Wait for the completion of the operation and get its result Raise the cancellation condition for this group of computations Start the asynchronous computation as a work item. Do not await its result. Start the asynchronous computation as a work item. Return a handle to the computation as an AsyncFuture. Run the asynchronous computation and await its result. If an exception occurs in the asynchronous computation then an exception is re-raised by this function. Generate a new asynchronous group A handle to a capability to cancel a set of asynchronous computations. Send a reply to a PostAndReply message A handle to a capability to reply to a PostAndReply message An asynchronous computation, which, when run, will eventually produce a value of the given type, or else raise an exception. The value and/or exception is not returned to the caller immediately, but is rather passed to a success continuation, exception continuation or cancellation continuation. Asynchronous computations are normally specified using the F# 'workflow' syntax for building computations. When run, asynchronous computations can normally be thought of as running run in one of two modes: 'work item mode' or 'waiting mode'. - 'work item mode' indicates that the computation is executing as a work item, e.g. in the .NET Thread Pool via ThreadPool.QueueUserWorkItem, or is running a brief event-response action on the GUI thread. - 'waiting mode' indicates the computations a waiting for asynchronous I/O completions, typically suspended as thunks using ThreadPool.RegisterWaitForSingleObject. Asynchronous computations running as 'work items' should not generally perform blocking operations, e.g. long running synchronous loops. However, some asynchronous computations may, out of necessity, need to execute blocking I/O operations: these should be run on new threads or a user-managed pool of threads specifically dedicated to resolving blocking conditions. For example, System.IO.OpenFile is, by design, a blocking operation. However frequently it is important to code as if this is asynchronous. This can be done by executing Async.SwitchToNewThread as part of the workflow. When run, asynchronous computations belong to an AsyncGroup. This can usually be specified when the async computation is started. The only action on an AsyncGroup is to raise a cancellation condition for the AsyncGroup. Async values check the cancellation condition for their AsyncGroup regularly, though synchronous computations within an asynchronous computation will not automatically check this condition. This gives a user-level cooperative cancellation protocol. Publish the event as a first class event value Trigger the event using the given parameters Create an event object suitable for implementing an arbitrary type of delegate Event implementations for an arbitrary type of delegate Publish the event as a first class event value Trigger the event using the given parameters Create an event object suitable for implementing for the IEvent<_> type Event implementations for the IEvent<_> type Publish the event as a first class event value Trigger the event using the given sender object and parameters. The sender object may be null. Create an event object suitable for delegate types following the standard .NET Framework convention of a first 'sender' argument Event implementations for a delegate types following the standard .NET Framework convention of a first 'sender' argument A delegate type associated with the F# event type IEvent<_> Remove a listener delegate from an event listener store Connect a handler delegate object to the event. A handler can be later removed using RemoveHandler. The listener will be invoked when the event is fired. F# gives special status to non-virtual instance member properties compatible with type IDelegateEvent, generating approriate .NET metadata to make the member appear to other .NET languages as a .NET event. First-class listening points (i.e. objects that permit you to register a 'callback' activated when the event is triggered). See the module Event for functions to create events. Connect a listener function to the event. The listener will be invoked when the event is fired. The family of first class event values for delegate types that satisfy the F# delegate constraint. Force the execution of this value and return its result. Same as Value. Mutual exclusion is used to prevent other threads also computing the value. Indicates if the lazy value has been successfully computed Indicates if the lazy value is being computed or the computation raised an exception Indicates if the lazy value has yet to be computed Same as Force, except no lock is taken. Same as Force Force the execution of this value and return its result. Same as Value. Mutual exclusion is used to prevent other threads also computing the value. If the value is re-forced during its own computation the Undefined exception is raised. Create a lazy computation that evaluates to the given value when forced Create a lazy computation that evaluates to the result of the given function when forced The type of delayed computations. Use the values in the Lazy module to manipulate values of this type, and the notation 'lazy expr' to create values of this type. Raise a timeout exception if a message not received in this amount of time. Default infinite. Raise a timeout exception if a message not received in this amount of time. Default infinite. Return an asynchronous computation which will look through messages in arrival order until 'scanner' returns a Some value. No thread is blocked while waiting for further messages. Return None if the timeout is exceeded. Return an asynchronous computation which will consume the first message in arrival order. No thread is blocked while waiting for further messages. Return None if the timeout is exceeded. Like PostAndReply, but return None if no reply within the timeout period. Create and start an instance of a MailboxProcessor. The asynchronous computation executed by the processor is the one returned by the 'initial' function. Start the MailboxProcessor Return an asynchronous computation which will look through messages in arrival order until 'scanner' returns a Some value. No thread is blocked while waiting for further messages. Raise a TimeoutException if the timeout is exceeded. Return an asynchronous computation which will consume the first message in arrival order. No thread is blocked while waiting for further messages. Raise a TimeoutException if the timeout is exceeded. Post a message to the message queue of the MailboxProcessor and await a reply on the channel synchronously. The message is produced by a single call to the first function which must build a message containing the reply channel. The receiving MailboxProcessor must process this message and invoke the Reply method on the reply channel precisly once. Post a message to the message queue of the MailboxProcessor, asynchronously Like AsyncPostAndReply, but return None if no reply within the timeout period. Post a message to the message queue of the MailboxProcessor and await a reply on the channel asynchronously. The message is produced by a single call to the first function which must build a message containing the reply channel. The receiving MailboxProcessor must process this message and invoke the Reply method on the reply channel precisly once. Create an instance of a MailboxProcessor. The asynchronous computation executed by the processor is the one returned by the 'initial' function. This function is not executed until 'Start' is called. A MailboxProcessor is a message-processing agent defined using an asynchronous workflow. The agent encapsulates a message queue that supports multiple-writers and the single reader agent. Writers send messages to the agent by using the Post, PostAndReply or AsyncPostAndReply methods. The reader agent is specified when creating the MailboxProcessor. The agent is usually an asychronous workflow that waits for messages by using the Receive or TryReceive methods. A MailboxProcessor may also scan through all available messages by using the Scan or TryScan method. The encapsulated message queue only supports a single active reader, thus at most one concurrent call to Receive, TryReceive, Scan and/or TryScan may be active at any one time. The type of delayed computations. Use the values in the Lazy module to manipulate values of this type, and the notation 'lazy expr' to create values of this type. An exeption type raised when the evaluation of a lazy value recursively depend upon itself A module of extension members that provide asynchronous operations for some basic .NET types related to concurrency and I/O. Return a new event which fires on a selection of messages from the original event. The selection function takes an original message to an optional new message. Create an IEvent with no initial listeners. Two items are returned: a function to invoke (trigger) the event, and the event that clients can plug listeners into. Return a new event that listens to the original event and triggers the resulting event only when the argument to the event passes the given function Run the given function each time the given event is triggered. Return a new event that passes values transformed by the given function Fire the output event when either of the input events fire Return a new event that triggers on the second and subsequent triggerings of the input event. The Nth triggering of the input event passes the arguments from the N-1th and Nth triggering as a pair. The argument passed to the N-1th triggering is held in hidden internal state until the Nth triggering occurs. You should ensure that the contents of the values being sent down the event are not mutable. Note that many EventArgs types are mutable, e.g. MouseEventArgs, and each firing of an event using this argument type may reuse the same physical argument obejct with different values. In this case you should extract the necessary information from the argument before using this combinator. Return a new event that listens to the original event and triggers the first resulting event if the application of the predicate to the event arguments returned true, and the second event if it returned false Return a new event consisting of the results of applying the given accumulating function to successive values triggered on the input event. An item of internal state records the current value of the state parameter. The internal state is not locked during the execution of the accumulation function, so care should be taken that the input IEvent not triggered by multiple threads simultaneously. Return a new event that listens to the original event and triggers the first resulting event if the application of the function to the event arguments returned a Choice1Of2, and the second event if it returns a Choice2Of2 Basic operations on first class event objects. Create an instance of the attribute Adding this attribute to class definition makes it abstract, which means it need not implement all its methods. Instances of abstract classes may not be constructed directly. Indicates the namespace or module to be automatically opened when an assembly is referenced or an enclosing module opened. Create an attribute used to mark a module as 'automatically opened' when the enclosing namespace is opened Create an attribute used to mark a namespace or module path to be 'automatically opened' when an assembly is referenced This attribute is used for two purposes. When applied to an assembly, it must be given a string argument, and this argument must indicate a valid module or namespace in that assembly. Source code files compiled with a reference to this assembly are processed in an environment where the given path is automatically oepned. When applied to a module within an assembly, then the attribute must not be given any arguments. When the enclosing namespace is opened in user source code, the module is also implicitly opened. The value of the attribute, indicating whether the type is automatically marked serializable or not Create an instance of the attribute Adding this attribute to a type with value 'false' disables the behaviour where F# makes the type Serializable by default. Create an instance of the attribute Adding this attribute to a property with event type causes it to be compiled with as a .NET Common Language Infrastructure metadata event, through a syntactic translation to a pair of 'add_EventName' and 'remove_EventName' methods. Helper types for active patterns with 2 choices. Helper types for active patterns with 3 choices. Helper types for active patterns with 4 choices. Helper types for active patterns with 5 choices. Helper types for active patterns with 6 choices. Helper types for active patterns with 7 choices. Create an instance of the attribute Adding this attribute to a type causes it to be represented using a .NET class. Indicates the variant number of the entity, if any, in a linear sequence of elements with F# source code Indicates the relationship between the compiled entity and F# source code Indicates the sequence number of the entity, if any, in a linear sequence of elements with F# source code Create an instance of the attribute Create an instance of the attribute Create an instance of the attribute This attribute is inserted automatically by the F# compiler to tag types and methods in the gneerated .NET code with flags indicating the correspondence with original source constructs. It is used by the functions in the Microsoft.FSharp.Reflection library to reverse-map compiled constructs to their original forms. It is not intended for use from use code. Indicates one or more adjustments to the compiled representation of an F# type or member Create an instance of the attribute This attribute is used to adjust the runtime representation for a type. For example, it may be used to note that the null representation may be used for a type. This affects how some constructs are compiled. Indicates one or more adjustments to the compiled representation of an F# type or member The value of the attribute, indicating whether the type has a default augmentation or not Create an instance of the attribute Adding this attribute to a discriminated union with value false turns off the generation of standard helper member tester, constructor and accessor members for the generated .NET class for that type. Indicates if a constraint is asserted that the field type supports 'null' Create an instance of the attribute Create an instance of the attribute Adding this attribute to a field declaration means that the field is not initialized. During type checking a constraint is asserted that the field type supports 'null'. If the 'check' value is false then the constraint is not asserted. Create an instance of the attribute Adding this attribute to a function indicates it is the entrypoint for an application. If this absent is not speficied for an EXE then the initialization implicit in the module bindings in the last file in the compilation sequence are used as the entrypoint. Indicates the warning message to be emitted when F# source code uses this construct Create an instance of the attribute This attribute is used to tag values that are part of an experimental library feature The release number of the F# version associated with the attribute The minor version number of the F# version associated with the attribute The major version number of the F# version associated with the attribute Create an instance of the attribute This attribute is added to generated assemblies to indicate the version of the data schema used to encode additional F# specific information in the resource attached to compiled F# libraries. Convert an F# first class function value to a value of type System.Converter Convert an value of type System.Converter to a F# first class function value Convert an F# first class function value to a value of type System.Converter Invoke an F# first class function value with five curried arguments. In some cases this will result in a more efficient application than applying the arguments successively. Invoke an F# first class function value with four curried arguments. In some cases this will result in a more efficient application than applying the arguments successively. Invoke an F# first class function value with three curried arguments. In some cases this will result in a more efficient application than applying the arguments successively. Invoke an F# first class function value with two curried arguments. In some cases this will result in a more efficient application than applying the arguments successively. Invoke an F# first class function value with one argument Convert an value of type System.Converter to a F# first class function value Construct an instance of an F# first class function value The .NET type used to represent F# function values. This type is not typically used directly, though may be used from other .NET languages. Convert the given Action delegate object to an F# function value Convert the given Converter delegate object to an F# function value A utility funcion to convert function values from tupled to curried form A utility funcion to convert function values from tupled to curried form A utility funcion to convert function values from tupled to curried form A utility funcion to convert function values from tupled to curried form A utility funcion to convert function values from tupled to curried form Helper functions for converting F# first class function values to and from .NET representaions of functions using delegates. Create an instance of the attribute Adding this attribute to a non-function value with generic parameters indicates that uses of the construct can give rise to generic code through type inference. Create an instance of the attribute Adding this attribute to a type causes it to be represented using a .NET interface. Create an instance of the attribute Adding this attribute to a value causes it to be compiled as a .NET constant literal. Create an instance of the attribute Adding this attribute to a type causes it to be interpreted as a refined type, currently limited to measure-parameterized types. This may only be used under very limited conditions. Create an instance of the attribute Adding this attribute to a type causes it to be interpreted as a unit of measure. This may only be used under very limited conditions. Create an instance of the attribute This attribute is used to tag values that may not be dynamically invoked at runtime. This is typically added to inlined functions whose implementations include unverifiable code. It causes the method body emitted for the inlined function to raise an exception if dynamically invoked, rather than including the unverifiable code in the generated assembly. Indicates the warning message to be emitted when F# source code uses this construct Create an instance of the attribute Create an instance of the attribute This attribute is used to tag values, modules and types that are only present in F# to permit a degree of code-compatibility and cross-compilation with other implementations of ML-familty languages, in particular OCaml. The use of the construct will give a warning unless the --ml-compatibility flag is specified. Get the value of a 'Some' option. A NullReferenceException is raised if the option is 'None'. Create an option value that is a 'None' value. Return 'true' if the option is a 'Some' value. Return 'true' if the option is a 'None' value. Create an option value that is a 'Some' value. The type of optional values. When used from other .NET languages the empty option is the null value. Use the constructors Some and None to create values of this type. Use the values in the Option module to manipulate values of this type, or pattern match against the values directly. None values will appear as the value null to other .NET languages. Instance methods on this type will appear as static methods to other .NET languages due to the use of null as a value representation. Create an instance of the attribute This attribute is added automatically for all optional arguments A unique identifier for this overloaded member within a given overload set Create an instance of the attribute Adding the OverloadID attribute to a member permits it to be part of a group overloaded by the same name and arity. The string must be a unique name amongst those in the overload set. Overrides of this method, if permitted, must be given the same OverloadID, and the OverloadID must be specified in both signature and implementation files if signature files are used. The current value of the reference cell The current value of the reference cell The type of mutable references. Use the functions [:=] and [!] to get and set values of this type. Create an instance of the attribute Create an instance of the attribute Adding this attribute to a record or union type disables the automatic generation of overrides for 'System.Object.Equals(obj)', 'System.Object.GetHashCode()' and 'System.IComparable' for the type. The type will by default use reference equality. This is identical to adding attributes StructuralEquality(false) and StructuralComparison(false). Create an instance of the attribute Adding this attribute to the let-binding for the definition of a top-level value makes the quotation expression that implements the value available for use at runtime. Create an instance of the attribute This attribute is used to indicate that references to a the elements of a module, record or union type require explicit qualified access. Create an instance of the attribute Adding this attribute to a type, value or member requires that uses of the construct must explicitly instantiate any generic type parameters. The value of the attribute, indicating whether the type is sealed or not Create an instance of the attribute Create an instance of the attribute Adding this attribute to class definition makes it sealed, which means it may not be extended or implemented. Indicates the relationship between a compiled entity in a CLI binary and an element in F# source code Create an instance of the attribute Adding this attribute to a type causes it to be represented using a .NET struct. The value of the attribute, indicating whether the type uses structural comparison or not Create an instance of the attribute Create an instance of the attribute Adding this attribute to a record, union or struct type with value 'false' disables the automatic generation of implementations for 'System.IComparable' for the type. The value of the attribute, indicating whether the type uses structural equality or not Create an instance of the attribute Create an instance of the attribute Adding this attribute to a record, union or struct type with value 'false' confirms the automatic generation of overrides for 'System.Object.Equals(obj)' and 'System.Object.GetHashCode()' for the type. This attribute is usually used in conjunction with StructuralComparison(false) to generate a type that supports structural equality but not structural comparison. Indicates the text to display by default when objects of this type are displayed using '%A' printf formatting patterns and other two-dimensional text-based display layouts. Create an instance of the attribute This attribute is used to mark how a type is displayed by default when using '%A' printf formatting patterns and other two-dimensional text-based display layouts. In this version of F# the only valid values are of the form PreText {PropertyName} PostText. The property name indicates a property to evaluate and to display instead of the object itself. Compiled versions of F# tuple types. These are not used directly, though these compiled forms are seen by other .NET languages. Specialize the type function at a given type Construct an instance of an F# first class type function value The .NET type used to represent F# first-class type function values. This type is for use by compiled F# code. The type 'unit', which has only one value "()". This value is special and always uses the representation 'null'. Create an instance of the attribute This attribute is used to tag values whose use will result in the generation of unverifiable code. These values are inevitably marked 'inline' to ensure that the unverifiable constructs are not present in the actual code for the F# library, but are rather copied to the source code of the caller. Four dimensional arrays, typically zero-based. Non-zero-based arrays can be created using methods on the System.Array type. Use the values in the Array4D module to manipulate values of this type, or the notation 'arr.[x1,x2,x3,x4]' to get and set array values. Three dimensional arrays, typically zero-based. Non-zero-based arrays can be created using methods on the System.Array type. Use the values in the Array3D module to manipulate values of this type, or the notation 'arr.[x1,x2,x3]' to get and set array values. Two dimensional arrays, typically zero-based. Use the values in the Array2D module to manipulate values of this type, or the notation 'arr.[x,y]' to get/set array values. Non-zero-based arrays can also be created using methods on the System.Array type. Single dimensional, zero-based arrays, written 'int[]', 'string[]' etc. Use the values in the Array module to manipulate values of this type, or the notation 'arr.[x]' to get/set array values. Single dimensional, zero-based arrays, written 'int[]', 'string[]' etc. Use the values in the Array module to manipulate values of this type, or the notation 'arr.[x]' to get/set array values. An abbreviation for the type Microsoft.FSharp.Math.BigInt An abbreviation for the .NET type System.Boolean Represents a managed pointer in F# code. An abbreviation for the .NET type System.Byte An abbreviation for the .NET type System.Char An abbreviation for the .NET type System.Decimal The type of decimal numbers, annotated with a unit of measure. The unit of measure is erased in compiled code and when values of this type are analyzed using reflection. The type is representationally equivalent to System.Decimal. An abbreviation for the .NET type System.Double An abbreviation for the .NET type System.Exception An abbreviation for the .NET type System.Double An abbreviation for the .NET type System.Single The type of floating point numbers, annotated with a unit of measure. The unit of measure is erased in compiled code and when values of this type are analyzed using reflection. The type is representationally equivalent to System.Single. The type of floating point numbers, annotated with a unit of measure. The unit of measure is erased in compiled code and when values of this type are analyzed using reflection. The type is representationally equivalent to System.Double. This type is for internal use by the F# code generator An abbreviation for the .NET type System.Int32 An abbreviation for the .NET type System.Int16 The type of 16-bit signed integer numbers, annotated with a unit of measure. The unit of measure is erased in compiled code and when values of this type are analyzed using reflection. The type is representationally equivalent to System.Int16. An abbreviation for the .NET type System.Int32 An abbreviation for the .NET type System.Int64 The type of 64-bit signed integer numbers, annotated with a unit of measure. The unit of measure is erased in compiled code and when values of this type are analyzed using reflection. The type is representationally equivalent to System.Int64. An abbreviation for the .NET type System.SByte The type of 8-bit signed integer numbers, annotated with a unit of measure. The unit of measure is erased in compiled code and when values of this type are analyzed using reflection. The type is representationally equivalent to System.SByte. The type of 32-bit signed integer numbers, annotated with a unit of measure. The unit of measure is erased in compiled code and when values of this type are analyzed using reflection. The type is representationally equivalent to System.Int32. An abbreviation for the .NET type System.IntPtr Represents an unmanaged pointer in F# code. This type should only be used when writing F# code that interoperates with native code. Use of this type in F# code may result in unverifiable code being generated. Conversions to and from the nativeint type may be required. Values of this type can be generated by the functions in the NativeInterop.NativePtr module. An abbreviation for the .NET type System.Object The type of optional values. When used from other .NET languages the empty option is the null value. Use the constructors Some and None to create values of this type. Use the values in the Option module to manipulate values of this type, or pattern match against the values directly. 'None' values will appear as the value null to other .NET languages. Instance methods on this type will appear as static methods to other .NET languages due to the use of null as a value representation. The type of mutable references. Use the functions [:=] and [!] to get and set values of this type. An abbreviation for the .NET type System.SByte An abbreviation for the .NET type System.Single An abbreviation for the .NET type System.String An abbreviation for the .NET type System.UInt16 An abbreviation for the .NET type System.UInt32 An abbreviation for the .NET type System.UInt64 An abbreviation for the .NET type System.Byte An abbreviation for the .NET type System.UIntPtr The type 'unit', which has only one value "()". This value is special and always uses the representation 'null'. Dynamic invocations of functions marked with the NoDynamicInvocationAttribute attribute raise this exception This exception is raised by 'failwith' Non-exhaustive match failures will raise the MatchFailure exception Build an aysnchronous workflow using computation expression syntax Builds a lookup table from a sequence of key/value pairs. The key objects are indexed using generic hashing and equality. Print to stderr using the given format Print to stderr using the given format, and add a newline Print to a string buffer and raise an exception with the given result. Helper printers must return strings. Print to a file using the given format Print to a file using the given format, and add a newline Special prefix operator for splicing typed expressions into quotation holes Special prefix operator for splicing untyped expressions into quotation holes Print to stdout using the given format Print to stdout using the given format, and add a newline Builds a sequence using sequence expression syntax Builds a set from a sequence of objects. The key objects are indexed using generic comparison Print to a string using the given format An active pattern to force the execution of values of type Lazy<_> Pervasives: Additional bindings available at the top level A compiler intrinsic that implements dynamic invocations to the '+' operator A compiler intrinsic that implements dynamic invocations to the checked '+' operator A compiler intrinsic that implements dynamic invocations to the checked '+' operator Generate a null value for reference types. Divide a floating point value by an integer A compiler intrinsic that implements dynamic invocations for the DivideByInt primitive Build an enum value from an underlying value Get the underlying value for an enum value A static F# comparer object Return an F# comparer object suitable for hashing and equality. This hashing behaviour of the returned comparer is not limited by an overall node count when hashing F# records, lists and union types. Make an F# comparer object for the given type Make an F# hash/equality object for the given type Make an F# hash/equality object for the given type using node-limited hashing when hashing F# records, lists and union types. Compare two values Compare two values. May be called as a recursive case from an implementation of System.IComparable to ensure consistent NaN comparison semantics. Compare two values for equality Compare two values for equality Compare two values Compare two values Hash a value according to its structure. This hash is not limited by an overall node count when hashing F# records, lists and union types. Recursively hash a part of a value according to its structure. Compare two values Compare two values Hash a value according to its structure. Use the given limit to restrict the hash when hashing F# records, lists and union types. Take the maximum of two values structurally according to the order given by GenericComparison Take the minimum of two values structurally according to the order given by GenericComparison Resolves to the one value for any primitive numeric type or any type with a static member called 'One' Resolves to the zero value for any primitive numeric type or any type with a static member called 'Zero' Resolves to the zero value for any primitive numeric type or any type with a static member called 'Zero' Resolves to the zero value for any primitive numeric type or any type with a static member called 'Zero' A compiler intrinsic that implements dynamic invocations to the '+' operator Parse an int32 according to the rules used by the overloaded 'int32' conversion operator when applied to strings Parse an int64 according to the rules used by the overloaded 'int64' conversion operator when applied to strings Parse an uint32 according to the rules used by the overloaded 'uint32' conversion operator when applied to strings Parse an uint64 according to the rules used by the overloaded 'uint64' conversion operator when applied to strings Reference/physical equality. True if boxed versions of the inputs are reference-equal, OR if both are primitive numeric types and the implementation of Object.Equals for the type of the first argument returns true on the boxed versions of the inputs. The physical hash. Hashes on the object identity, except for value types, where we hash on the contents. A primitive entry point used by the F# compiler for optimization purposes. A primitive entry point used by the F# compiler for optimization purposes. A primitive entry point used by the F# compiler for optimization purposes. A primitive entry point used by the F# compiler for optimization purposes. A primitive entry point used by the F# compiler for optimization purposes. A primitive entry point used by the F# compiler for optimization purposes. A primitive entry point used by the F# compiler for optimization purposes. A primitive entry point used by the F# compiler for optimization purposes. A primitive entry point used by the F# compiler for optimization purposes. A primitive entry point used by the F# compiler for optimization purposes. A primitive entry point used by the F# compiler for optimization purposes. A primitive entry point used by the F# compiler for optimization purposes. A primitive entry point used by the F# compiler for optimization purposes. A primitive entry point used by the F# compiler for optimization purposes. A primitive entry point used by the F# compiler for optimization purposes. A primitive entry point used by the F# compiler for optimization purposes. A primitive entry point used by the F# compiler for optimization purposes. A primitive entry point used by the F# compiler for optimization purposes. A primitive entry point used by the F# compiler for optimization purposes. A primitive entry point used by the F# compiler for optimization purposes. A primitive entry point used by the F# compiler for optimization purposes. A primitive entry point used by the F# compiler for optimization purposes. A primitive entry point used by the F# compiler for optimization purposes. A primitive entry point used by the F# compiler for optimization purposes. The F# compiler emits calls to some of the functions in this module as part of the compiled form of some language constructs This function implements calls to default constructors acccessed by 'new' constraints. A compiler intrinsic for the efficeint compilation of sequence expressions The standard overloaded associative (indexed) lookup operator The standard overloaded associative (2-indexed) lookup operator The standard overloaded associative (3-indexed) lookup operator The standard overloaded associative (4-indexed) lookup operator Primitive used by pattern match compilation This function implements parsing of decimal constants The standard overloaded associative (indexed) mutation operator The standard overloaded associative (2-indexed) mutation operator The standard overloaded associative (3-indexed) mutation operator The standard overloaded associative (4-indexed) mutation operator A compiler intrinsic that implements the ':?' operator A compiler intrinsic that implements the ':?' operator A compiler intrinsic that implements the ':?>' operator A compiler intrinsic that implements the ':?>' operator The F# compiler emits calls to some of the functions in this module as part of the compiled form of some language constructs Address-of. Uses of this value may result in the generation of unverifiable code. Binary 'and'. When used as a binary operator the right hand value is evaluated only on demand Binary 'and'. When used as a binary operator the right hand value is evaluated only on demand Binary 'or'. When used as a binary operator the right hand value is evaluated only on demand Address-of. Uses of this value may result in the generation of unverifiable code. Binary 'or'. When used as a binary operator the right hand value is evaluated only on demand The F# compiler emits calls to some of the functions in this module as part of the compiled form of some language constructs Language primitives associated with the F# language Provides a default implementations of F# numeric literal syntax for literals fo the form 'dddI' Provides a default implementations of F# numeric literal syntax for literals fo the form 'dddI' Provides a default implementations of F# numeric literal syntax for literals fo the form 'dddI' Provides a default implementations of F# numeric literal syntax for literals fo the form 'dddI' Provides a default implementations of F# numeric literal syntax for literals fo the form 'dddI' Provides a default implementations of F# numeric literal syntax for literals fo the form 'dddI' Provide a default implementation of the F# numeric literal syntax 'dddN' Provides a default implementations of F# numeric literal syntax for literals fo the form 'dddI' Absolute value of the given number Inverse cosine of the given number Inverse sine of the given number Inverse tangent of the given number Inverse tangent of x/y where x and y are specified separately Boxes a strongly typed value. Converts the argument to byte. This is a direct conversion for all primitive numeric types. For strings, the input is converted using Byte.Parse() on strings and otherwise requires a ToByte method on the input type Ceiling of the given number Converts the argument to character. Numeric inputs are converted according to the UTF-16 encoding for characters. String inputs must be exactly one character long. For other types a static member ToChar must exist on the type. Generic comparison Cosine of the given number Hyperbolic cosine of the given number Converts the argument to System.Decimal using a direct conversion for all primitive numeric types and requiring a ToDecimal method otherwise Decrement a mutable reference cell containing an integer Used to specify a default value for an optional argument in the implementation of a function Converts the argument to 64-bit float. This is a direct conversion for all primitive numeric types. For strings, the input is converted using Double.Parse() with InvariantCulture settings. Otherwise the operation requires and invokes a ToDouble method on the input type Converts the argument to a particular enum type. Exit the current hardware isolated process, if security settings permit, otherwise raise an exception. Calls System.Environment.Exit. Exponential of the given number Throw a FailureException exception Converts the argument to 64-bit float. This is a direct conversion for all primitive numeric types. For strings, the input is converted using Double.Parse() with InvariantCulture settings. Otherwise the operation requires and invokes a ToDouble method on the input type Converts the argument to 32-bit float. This is a direct conversion for all primitive numeric types. For strings, the input is converted using Single.Parse() with InvariantCulture settings. Otherwise the operation requires and invokes a ToSingle method on the input type Floor of the given number Return the first element of a tuple, fst (a,b) = a. A generic hash function, designed to return equal hash values for items that are equal according to the "=" operator. By default it will use structural hashing for F# union, record and tuple types, hashing the complete contents of the type. The exact behaviour of the function can be adjusted on a type-by-type basis by implementing GetHashCode for each type. The identity function Ignore the passed value. This is often used to throw away results of a computation. Increment a mutable reference cell containing an integer Equivalent to System.Double.PositiveInfinity Equivalent to System.Single.PositiveInfinity Converts the argument to signed 32-bit integer. This is a direct conversion for all primitive numeric types. For strings, the input is converted using Int32.Parse() with InvariantCulture settings. Otherwise the operation requires and invokes a ToInt32 method on the input type Converts the argument to signed 16-bit integer. This is a direct conversion for all primitive numeric types. For strings, the input is converted using Int16.Parse() with InvariantCulture settings. Otherwise the operation requires and invokes a ToInt16 method on the input type Converts the argument to signed 32-bit integer. This is a direct conversion for all primitive numeric types. For strings, the input is converted using Int32.Parse() with InvariantCulture settings. Otherwise the operation requires and invokes a ToInt32 method on the input type Converts the argument to signed 64-bit integer. This is a direct conversion for all primitive numeric types. For strings, the input is converted using Int64.Parse() with InvariantCulture settings. Otherwise the operation requires and invokes a ToInt64 method on the input type Throw an ArgumentException exception Throw an InvalidOperationException exception A generic hash function. This function has the same behaviour as 'hash', however the default structural hashing for F# union, record and tuple types stops when the given limit of nodes is reached. The exact behaviour of the function can be adjusted on a type-by-type basis by implementing GetHashCode for each type. Execute the function as a mutual-exlcusion region using the input value as a lock. Natural logarithm of the given number Logarithm to base 10 of the given number Maximum based on generic comparison Minimum based on generic comparison Equivalent to System.Double.NaN Equivalent to System.Single.NaN Converts the argument to signed native integer. This is a direct conversion for all primitive numeric types and ToIntPtr method otherwise) Negate a logical value. not true equals false and not false equals true Throw an KeyNotFoundException exception Throw an ArgumentNullException exception Overloaded addition operator Concatenate two lists. Apply a function to three values, the values being a triple on the left, the function on the right Apply a function to two values, the values being a pair on the left, the function on the right Overloaded logical-AND operator Overloaded logical-OR operator Assign to a mutable reference cell Compose two functions, the function on the right being applied first Compose two functions, the function on the left being applied first Concatenate two strings. The overlaoded operator '+' may also be used. Dereference a mutable reference cell Overloaded division operator Structural equality Overloaded logical-XOR operator Overloaded power operator. Structural greater-than Structural greater-than-or-equal Overloaded byte-shift left operator by a specified number of bits Apply a function to two values, the values being a pair on the right, the function on the left Apply a function to three values, the values being a triple on the right, the function on the left Structural inequality Structural less-than comparison Structural less-than-or-equal comparison Overloaded logical-NOT operator Overloaded modulo operator Overloaded multiplication operator Apply a function to a value, the value being on the right, the function on the left Apply a function to a value, the value being on the left, the function on the right The standard overloaded range operator, e.g. [n..m] for lists, seq {n..m} for sequences The standard overloaded skip range operator, e.g. [n..skip..m] for lists, seq {n..skip..m} for sequences Overloaded byte-shift right operator by a specified number of bits Overloaded subtraction operator Overloaded unary negation. Overloaded prefix=plus operator Overloaded power operator. If n > 0 then equivalent to x*...*x for n occurrences of x. Raises an exception Create a mutable reference cell Rethrows an exception. This should only be used when handling an exception Round the given number Converts the argument to signed byte. This is a direct conversion for all primitive numeric types. For strings, the input is converted using SByte.Parse() with InvariantCulture settings. Otherwise the operation requires and invokes a ToSByte method on the input type Sign of the given number Sine of the given number Converts the argument to 32-bit float. This is a direct conversion for all primitive numeric types. For strings, the input is converted using Single.Parse() with InvariantCulture settings. Otherwise the operation requires and invokes a ToSingle method on the input type Hyperbolic sine of the given number Returns the internal size of a type in bytes. For example, sizeof<int> returns 4. Return the second element of a tuple, snd (a,b) = b. Square root of the given number Reads the value of the property System.Console.Error. Reads the value of the property System.Console.In. Reads the value of the property System.Console.Out. Converts the argument to a string using ToString. For standard integer and floating point values the ToString conversion uses CultureInfo.InvariantCulture. Note, native integer ToString does not support specifying CultureInfo. Tangent of the given number Hyperbolic tangent of the given number Overloaded truncate operator. Generate a System.Type representation for a type definition. If the input type is a generic type instantiation then return the generic type definition associated with all such instantiations. Generate a System.Type runtime represenation of a static type. The static type is still maintained on the value returned. Converts the argument to unsigned 16-bit integer. This is a direct conversion for all primitive numeric types. For strings, the input is converted using UInt16.Parse() with InvariantCulture settings. Otherwise the operation requires and invokes a ToUInt16 method on the input type Converts the argument to unsigned 32-bit integer. This is a direct conversion for all primitive numeric types. For strings, the input is converted using UInt32.Parse() with InvariantCulture settings. Otherwise the operation requires and invokes a ToUInt32 method on the input type Converts the argument to unsigned 64-bit integer. This is a direct conversion for all primitive numeric types. For strings, the input is converted using UInt64.Parse() with InvariantCulture settings. Otherwise the operation requires and invokes a ToUInt64 method on the input type Converts the argument to unsigned native integer using a direct conversion for all primitive numeric types and requiring a ToUintPtr method otherwise Unboxes a strongly typed value. This is the inverse of box, unbox<t>(box<t> a) equals a. Clean up resources associated with the input object after the completion of the given function. Cleanup occurs even when an exception is raised by the protected code. An active pattern to match values of type System.Collections.Generic.KeyValuePair Converts the argument to byte. This is a direct conversion for all primitive numeric types and ToByte method otherwise) Converts the argument to unicode character based on UTF16 encoding (a direct conversion for all primitive numeric types and ToUIntPtr method otherwise) Converts the argument to signed 32-bit integer. This is a direct conversion for all primitive numeric types and ToInt32 method otherwise) Converts the argument to signed 16-bit integer. This is a direct conversion for all primitive numeric types and ToInt16 method otherwise) Converts the argument to signed 32-bit integer. This is a direct conversion for all primitive numeric types and ToInt32 method otherwise) Converts the argument to signed 64-bit integer. This is a direct conversion for all primitive numeric types and ToInt64 method otherwise) Converts the argument to signed native integer. This is a direct conversion for all primitive numeric types and ToIntPtr method otherwise) Overloaded addition operator (checks for overflow) Overloaded multiplication operator (checks for overflow) Overloaded subtraction operator (checks for overflow) Overloaded unary negation (checks for overflow) Converts the argument to signed byte. This is a direct conversion for all primitive numeric types and ToSByte method otherwise) Converts the argument to unsigned 16-bit integer. This is a direct conversion for all primitive numeric types and ToUInt16 method otherwise) Converts the argument to unsigned 32-bit integer. This is a direct conversion for all primitive numeric types and ToUInt32 method otherwise) Converts the argument to unsigned 64-bit integer. This is a direct conversion for all primitive numeric types and ToUInt64 method otherwise) Converts the argument to unsigned native integer. This is a direct conversion for all primitive numeric types and ToUIntPtr method otherwise) This module contains the basic arithmetic operations with overflow checks. Get a slice of an array Get a slice of an array Get a slice of an array Get a slice of an array Get a slice from a string This is a library intrinsic. Calls to this function may be generated by uses of the generic 'pown' operator on values of type 'byte' This is a library intrinsic. Calls to this function may be generated by uses of the generic 'pown' operator on values of type 'decimal' This is a library intrinsic. Calls to this function may be generated by uses of the generic 'pown' operator on values of type 'float' This is a library intrinsic. Calls to this function may be generated by uses of the generic 'pown' operator This is a library intrinsic. Calls to this function may be generated by uses of the generic 'pown' operator on values of type 'int16' This is a library intrinsic. Calls to this function may be generated by uses of the generic 'pown' operator on values of type 'int32' This is a library intrinsic. Calls to this function may be generated by uses of the generic 'pown' operator on values of type 'int64' This is a library intrinsic. Calls to this function may be generated by uses of the generic 'pown' operator on values of type 'nativeint' This is a library intrinsic. Calls to this function may be generated by uses of the generic 'pown' operator on values of type 'sbyte' This is a library intrinsic. Calls to this function may be generated by uses of the generic 'pown' operator on values of type 'float32' This is a library intrinsic. Calls to this function may be generated by uses of the generic 'pown' operator on values of type 'uint16' This is a library intrinsic. Calls to this function may be generated by uses of the generic 'pown' operator on values of type 'uint32' This is a library intrinsic. Calls to this function may be generated by uses of the generic 'pown' operator on values of type 'uint64' This is a library intrinsic. Calls to this function may be generated by uses of the generic 'pown' operator on values of type 'unativeint' Generate a range of byte values Generate a range of char values Generate a range of float values Generate a range of values using the given zero, add, start, step and stop values Generate a range of int16 values Generate a range of integers Generate a range of int64 values Generate a range of nativeint values Generate a range of sbyte values Generate a range of float32 values Generate a range of values using the given zero, add, start, step and stop values Generate a range of uint16 values Generate a range of uint32 values Generate a range of uint64 values Generate a range of unativeint values Set a slice of an array Set a slice of an array Set a slice of an array Set a slice of an array A module of compiler intrinsic functions for efficient implementations of F# integer ranges and dynamic invocations of other F# operators Generate a defult value for any type. This is null for reference types, For structs, this is struct value where all fields have the default value. This function is unsafe in the sense that some F# values do not have proper null values. This module contains basic operations which do not apply runtime and/or static checks Basic F# Operators. This module is automatically opened in all F# code. Invoke the optimized function value with two curried arguments Adapt an F# first class function value to be an optimized function value that can accept two curried arguments without intervening execution. Construct an optimized function value that can accept two curried arguments without intervening execution. The .NET type used to represent F# function values that accept two iterated (curried) arguments without intervening execution. This type should not typically used directly from either F# code or from other .NET languages. Invoke an F# first class function value that accepts three curried arguments without intervening execution Adapt an F# first class function value to be an optimized function value that can accept three curried arguments without intervening execution. Construct an optimized function value that can accept three curried arguments without intervening execution. The .NET type used to represent F# function values that accept three iterated (curried) arguments without intervening execution. This type should not typically used directly from either F# code or from other .NET languages. Invoke an F# first class function value that accepts four curried arguments without intervening execution Adapt an F# first class function value to be an optimized function value that can accept four curried arguments without intervening execution. Construct an optimized function value that can accept four curried arguments without intervening execution. The .NET type used to represent F# function values that accept four iterated (curried) arguments without intervening execution. This type should not typically used directly from either F# code or from other .NET languages. Invoke an F# first class function value that accepts five curried arguments without intervening execution Adapt an F# first class function value to be an optimized function value that can accept five curried arguments without intervening execution. Construct an optimized function value that can accept five curried arguments without intervening execution. The .NET type used to represent F# function values that accept five iterated (curried) arguments without intervening execution. This type should not typically used directly from either F# code or from other .NET languages. An implementation module used to hold some private implementations of function value invocation. bind f inp evaluates to match inp with None -> None | Some x -> f x length inp evaluates to match inp with None -> 0 | Some _ -> 1 exists p inp evaluates to match inp with None -> false | Some x -> p x filter p inp evaluates to match inp with None -> None | Some x -> if p x then inp else None fold_left f s inp evaluates to match inp with None -> s | Some x -> f s x fold_right f inp s evaluates to "match inp with None -> s | Some x -> f x s" forall p inp" evaluates to "match inp with None -> true | Some x -> p x Gets the value associated with the option. If the option is None then raises ArgumentException Returns true if the option is None Returns true if the option is not None iter f inp executes match inp with None -> () | Some x -> f x filter p inp evaluates to match inp with None -> None | Some x -> if p x then inp else None map f inp evaluates to match inp with None -> None | Some x -> Some (f x) partition p inp evaluates to match inp with None -> None,None | Some x -> if p x then inp,None else None,inp Convert the option to an array of length 0 or 1 Convert the option to a list of length 0 or 1 Basic operations on options. Build a new string whose characters are the results of applying the function mapping to each of the characters of the input string and concatenating the resulting strings. Return a new string made by concatenating the given strings with separator 'sep', i.e. 'a1 + sep + ... + sep + aN' Test if any character of the string satisfies the given predicate. Test if all characters in the string satisfy the given predicate. Build a new string whose characters are the results of applying the function mapping to each index from 0 to count-1 and concatenating the resulting strings. Apply the function action to each character in the string. Apply the function action to the index of each character in the string and the character itself. Return the length of the string. Build a new string whose characters are the results of applying the function mapping to each of the characters of the input string. Build a new string whose characters are the results of applying the function mapping to each character in the string and the character itself. Return a string by concatenating count instances of str. Functional programming operators for string processing. Further string operations are available via the member functions on strings and other functionality in System.String and System.Text.RegularExpressions types. Return the given big integer Return the negation of a big integer Return the difference of big integers Generate a range of big integers, with a step Generate a range of big integers Return the product of big integers Return the modulus of big integers This operator is for use from other .NET languages This operator is for use from other .NET languages This operator is for use from other .NET languages This operator is for use from other .NET languages This operator is for use from other .NET languages This operator is for use from other .NET languages Return the ratio of big integers Return the sum of two big integers Get the big integer for zero Return the sign of a big integer: 0, +1 or -1 Get the big integer for one Return true if a big integer is 'zero' Return true if a big integer is 'one' Convert a big integer to a 64-bit signed integer Convert a big integer to a 32-bit signed integer Convert a big integer to a floating point number Return n^m for two big integers Parse a big integer from a string format Return the greatest common divisor of two big integers Compute the factorial function as a big integer Compute the ratio and remainder of two big integers Compute the absolute value of a big integer Construct a BigInt value for the given integer Construct a BigInt value for the given 64-bit integer The type of arbitrary-sized integers Abstract internal type Return a typed native pointer by adding index * sizeof<'T> to the given input pointer Dereference the typed native pointer computed by adding index * sizeof<'T> to the given input pointer Get the address of an element of a pinned array Get the address of an element of a pinned 2-dimensional array Return a typed native pointer for a given machine address Dereference the given typed native pointer Assign the value into the memory location referenced by the typed native pointer computed by adding index * sizeof<'T> to the given input pointer Return a machine address for a given typed native pointer Assign the value into the memory location referenced by the given typed native pointer Contains operations on native pointers. Use of these operators may result in the generation of unverifiable code. Returns type of an expression Returns the custom attributes of an expression Build an expression that represents a while loop Build an expression that represents setting a mutable variable Build an expression that represents a variable Build an expression that represents a constant value of a particular type Build an expression that represents a constant value Build an expression that represents a test of a value is of a particular union case Build an expression that represents a type test Build an expression that represents getting a field of a tuple Build an expression that represents a try/with construct for exception filtering and catching Try and find a stored reflection definition for the given method. Stored reflection definitions are added to an F# assembly through the use of the [<ReflectedDefinition>] attribute. Build an expression that represents a try/finally construct Substitute through the given expression using the given functions to map variables to new values. The functions must give consistent results at each application. Variable renaming may occur on the target expression if variable capture occurs. Build an expression that represents the sequential execution of one expression followed by another Permit interactive environments such as F# Interactive to explicitly register new pickled resources that represent persisted top level definitions. The string indicates a unique name for the resources being added. The format for the bytes is the encoding generated by the F# compiler. Build an expression that represents a nested quotation literal Build an expression that represents writing to a property of an object Build an expression that represents writing to a static property Build an expression that represents reading a property of an object Build an expression that represents reading a static property Build an expression that represents the creation of a union case value Build an expression that represents the creation of an F# tuple value Build record-construction expressions Build an expression that represents the invocation of an object constructor Build an expression that represents the creation of a delegate value for the given type Build an expression that represents the creation of an array value initialized with the given elements Build recursives expressions associated with 'let rec' constructs Build expressions associated with 'let' constructs Build an expression that represents the constrution of an F# function value Build 'if ... then ... else' expressions Fetch or create a new variable with the given name and type from a global pool of shared variables indexed by name and type. The type is given by the expicit or inferred type parameter Get the free expression variables of an expression as a list Build a 'for i = ... to ... do ...' expression that represent loops over integer ranges Build an expression that represents writing to a static field Build an expression that represents writing to a field of an object Build an expression that represents the access of a static field Build an expression that represents the access of a field of an object This function is called automatically when quotation syntax (<@ @>) and related typed-expression quotations are used. The bytes are a pickled binary representation of an unlinked form of the qutoed expression, and the System.Type argument is any type in the assembly where the quoted expression occurs, i.e. it helps scope the interpretation of the cross-assembly references in the bytes. Build an expression that represents the invocation of a default object constructor Build an expression that represents the coercion of an expression to a type Return a new typed expression given an underlying runtime-typed expression. A type annotation is usually required to use this function, and using an incorrect type annotation may result in a later runtime exception. Build an expression that represents a call to an static method or module-bound function Build an expression that represents a call to an instance method associated with an object Build an expression that represents the application of a first class function value to multiple arguments Build an expression that represents the application of a first class function value to a single argument Build an expression that represents setting the value held at a particular address Build an expression that represents getting the address of a value Quoted expressions annotated with System.Type values. Get the raw expression associated with this type-carrying expression Type-carrying quoted expressions. Expressions are generated either by quotations in source text or programatically The type associated with the variable The declared name of the variable Indicates if the variable represents a mutable storage location Fetch or create a new variable with the given name and type from a global pool of shared variables indexed by name and type Create a new variable with the given name, type and mutability Information at the binding site of a variable An active pattern to recognize expressions of the form a && b An active pattern to recognize expressions that represent the application of a (possibly curried or tupled) first class function value An active pattern to recognize constant boolean expressions An active pattern to recognize constant byte expressions An active pattern to recognize constant unicode character expressions An active pattern to recognize constant 64-bit floating point number expressions An active pattern to recognize constant int16 expressions An active pattern to recognize constant int32 expressions An active pattern to recognize constant int64 expressions An active pattern to recognize expressions that represent a (possibly curried or tupled) first class function value An active pattern to recognize methods that have an associated ReflectedDefinition An active pattern to recognize expressions of the form a || b An active pattern to recognize property getters or values in modules that have an associated ReflectedDefinition An active pattern to recognize property setters that have an associated ReflectedDefinition An active pattern to recognize constant signed byte expressions An active pattern to recognize constant 32-bit floating point number expressions A parameterized active pattern to recognize calls to a specified function or method An active pattern to recognize constant string expressions An active pattern to recognize constant unsigned int16 expressions An active pattern to recognize constant unsigned int32 expressions An active pattern to recognize constant unsigned int64 expressions An active pattern to recognize () constant expressions Contains a set of derived F# active patterns to analyze F# expression objects Re-build combination expressions. The first parameter should be an object returned by the ShapeCombination case of the active pattern in this module. An active pattern that performs a complete decomposition viewing the expression tree as a binding structure Active patterns for traversing, visiting, rebuilding and tranforming expressions in a generic way An active pattern to recognize expressions that represent getting the address of a value An active pattern to recognize expressions that represent setting the value held at an address An active pattern to recognize expressions that represent applications of first class function values An active pattern to recognize expressions that represent calls to static and instance methods, and functions defined in modules An active pattern to recognize expressions that represent coercions from one type to another An active pattern to recognize expressions that represent invocations of a default constructor of a struct An active pattern to recognize expressions that represent getting a static or instance field An active pattern to recognize expressions that represent setting a static or instance field An active pattern to recognize expressions that represent loops over integer ranges An active pattern to recognize expressions that represent conditionals An active pattern to recognize expressions that represent first class function values An active pattern to recognize expressions that represent recursive let bindings of one or more variables An active pattern to recognize expressions that represent let bindings An active pattern to recognize expressions that represent the construction of arrays An active pattern to recognize expressions that represent construction of delegate values An active pattern to recognize expressions that represent invocation of object constructors An active pattern to recognize expressions that represent construction of record values An active pattern to recognize expressions that represent construction of tuple values An active pattern to recognize expressions that represent construction of particular union case values An active pattern to recognize expressions that represent the read of a static or instance property, or a non-function value declared in a module An active pattern to recognize expressions that represent setting a static or instance property, or a non-function value declared in a module An active pattern to recognize expressions that represent a nested quotation literal An active pattern to recognize expressions that represent sequential exeuction of one expression followed by another An active pattern to recognize expressions that represent a try/finally construct An active pattern to recognize expressions that represent a try/with construct for exception filtering and catching An active pattern to recognize expressions that represent getting a tuple field An active pattern to recognize expressions that represent a dynamic type test An active pattern to recognize expressions that represent a test if a value is of a particular union case An active pattern to recognize expressions that represent a constant value An active pattern to recognize expressions that represent setting a mutable variable An active pattern to recognize expressions that represent a variable An active pattern to recognize expressions that represent while loops Contains a set of primitive F# active patterns to analyze F# expression objects Return a System.Type representing an F# tuple type with the given element types Return a System.Type representing the F# function type with the given domain and range Return true if the typ is a representation of an F# union type or the runtime type of a value of that type Return true if the typ is a representation of an F# tuple type Return true if the typ is a representation of an F# record type Return true if the typ is a System.Type value corresponding to the compiled form of an F# module Return true if the typ is a representation of an F# function type or the runtime type of a closure implementing an F# function type Return true if the typ is a representation of an F# exception declaration Get the cases of a union type. Assumes the given type is a union type. If not, ArgumentException is raised during pre-computation. Get the tuple elements from the representation of an F# tuple type Read all the fields from a record value, in declaration order Assumes the given input is a record value. If not, ArgumentException is raised. Get the domain and range types from an F# function type or from the runtime type of a closure implementing an F# type Read all the fields from an F# exception declaration, in declaration order Assumes exceptionType is an exception representation type. If not, ArgumentException is raised. Contains operations associated with constructing and analyzing F# types such as records, unions and tuples Assumes the given type is a union type. If not, ArgumentException is raised during pre-computation. Using the computed function is more efficient than calling GetUnionCase because the path executed by the computed function is optimized given the knowledge that it will be used to read values of the given type. Precompute a property or static method for reading an integer representing the case tag of a union type. Precompute a function for reading all the fields for a particular discriminator case of a union type Using the computed function will typically be faster than executing a corresponding call to GetFields A method that constructs objects of the given case Precompute a function for constructing a discriminated union value for a particular union case. Precompute a function for reading the values of a particular tuple type Assumes the given type is a TupleType. If not, ArgumentException is raised during pre-computation. Get information that indicates how to read a field of a tuple Get a method that constructs objects of the given tuple type. For small tuples, no additional typoe will be returned. For large tuples, an additional type is returned indicating that a nested encoding has been used for the tuple type. In this case the suffix portion of the tuple type has the given type and an object of this type must be created and passed as the last argument to the ConstructorInfo. A recursive call to PreComputeTupleConstructorInfo can be used to determine the constructor for that the suffix type. Precompute a function for reading the values of a particular tuple type Assumes the given type is a TupleType. If not, ArgumentException is raised during pre-computation. Precompute a function for reading all the fields from a record. The fields are returned in the same order as the fields reported by a call to Microsoft.FSharp.Reflection.Type.GetInfo for this type. Assumes the given type is a RecordType. If not, ArgumentException is raised during pre-computation. Using the computed function will typically be faster than executing a corresponding call to Value.GetInfo because the path executed by the computed function is optimized given the knowledge that it will be used to read values of the given type. Precompute a function for reading a particular field from a record. Assumes the given type is a RecordType with a field of the given name. If not, ArgumentException is raised during pre-computation. Using the computed function will typically be faster than executing a corresponding call to Value.GetInfo because the path executed by the computed function is optimized given the knowledge that it will be used to read values of the given type. Get a ConstructorInfo for a record type Precompute a function for constructing a record value. Assumes the given type is a RecordType. If not, ArgumentException is raised during pre-computation. Create a union case value Create an instance of a tuple type Assumes at least one element is given. If not, ArgumentException is raised. Create an instance of a record type Assumes the given input is a record type. If not, ArgumentException is raised. Build a typed function from object from a dynamic function implementation Identify the union case and its fields for an object Assumes the given input is a union case value. If not, ArgumentException is raised. If the type is not given, then the runtime type of the input object is used to identify the relevant union type. The type should always be given if the input object may be null. For example, option values may be represented using the 'null'. Read all fields from a tuple Assumes the given input is a tuple value. If not, ArgumentException is raised. Read a field from a tuple value Assumes the given input is a tuple value. If not, ArgumentException is raised. Read all the fields from a record value Assumes the given input is a record value. If not, ArgumentException is raised. Read a field from a record value Assumes the given input is a record value. If not, ArgumentException is raised. Read all the fields from a value built using an instance of an F# exception declaration Assumes the given input is an F# exception value. If not, ArgumentException is raised. Contains operations associated with constructing and analyzing values associated with F# types such as records, unions and tuples The integer tag for the case The name of the case The type in which the case occurs The fields associated with the case, represented by PropertyInfo Return the custom attributes associated with the case Return the custom attributes associated with the case matching the given attribute type Represents a case of a discriminated union type Type of a formatting expression 'Printer : function type generated by printf 'State: type argument passed to %a formatters 'Residue: value generated by the overall printf action (e.g. sprint generates a string) 'Result: value generated after post processing (e.g. failwithf generates a string internally then raises an exception) Type of a formatting expression 'Printer : function type generated by printf 'State: type argument passed to %a formatters 'Residue: value generated by the overall printf action (e.g. sprint generates a string) 'Result: value generated after post processing (e.g. failwithf generates a string internally then raises an exception) 'Tuple: tuple of values generated by scan or match The raw text of the format string Construct a format string Type of a formatting expression. 'Printer : function type generated by printf 'State: type argument passed to %a formatters 'Residue: value generated by the overall printf action (e.g. sprint generates a string) 'Result: value generated after post processing (e.g. failwithf generates a string internally then raises an exception) Construct a format string Type of a formatting expression. 'Printer : function type generated by printf 'State: type argument passed to %a formatters 'Residue: value generated by the overall printf action (e.g. sprint generates a string) 'Result: value generated after post processing (e.g. failwithf generates a string internally then raises an exception) 'Tuple: tuple of values generated by scan or match Represents a statically-analyzed format associated with writing to a System.Text.StringBuilder. The type parameter indicates the arguments and return type of the format operation. Represents a statically-analyzed format associated with writing to a System.Text.StringBuilder. The first type parameter indicates the arguments of the format operation and the last the overall return type. Represents a statically-analyzed format when formatting builds a string. The type parameter indicates the arguments and return type of the format operation. Represents a statically-analyzed format when formatting builds a string. The first type parameter indicates the arguments of the format operation and the last the overall return type. Represents a statically-analyzed format associated with writing to a System.IO.TextWriter. The type parameter indicates the arguments and return type of the format operation. Represents a statically-analyzed format associated with writing to a System.IO.TextWriter. The first type parameter indicates the arguments of the format operation and the last the overall return type. Print to a System.Text.StringBuilder Formatted printing to stderr Formatted printing to stderr, adding a newline Print to a string buffer and raise an exception with the given result. Helper printers must return strings. Print to a text writer or an OCaml-compatible channel Print to a text writer or an OCaml-compatible channel, adding a newline bprintf, but call the given 'final' function to generate the result. See kprintf. fprintf, but call the given 'final' function to generate the result. See kprintf. printf, but call the given 'final' function to generate the result. For example, these let the printing force a flush after all output has been entered onto the channel, but not before. sprintf, but call the given 'final' function to generate the result. See kprintf. twprintf, but call the given 'final' function to generate the result. See kprintf. Formatted printing to stdout Formatted printing to stdout, adding a newline Print to a string via an internal string buffer and return the result as a string. Helper printers must return strings. Print to any subtype of the .NET type System.IO.TextWriter Print to any subtype of the .NET type System.IO.TextWriter, and add a newline Extensible printf-style formatting for numbers and other datatypes Format specifications are strings with "%" markers indicating format placeholders. Format placeholders consist of: %[flags][width][.precision][type] where the type is interpreted as follows: %b: bool, formatted as "true" or "false" %s: string, formatted as its unescaped contents %d, %i: any basic integer type formatted as a decimal integer, signed if the basic integer type is signed. %u: any basic integer type formatted as an unsigned decimal integer %x, %X, %o: any basic integer type formatted as an unsigned hexadecimal (a-f)/Hexadecimal (A-F)/Octal integer %e, %E, %f, %F, %g, %G: any basic floating point type (float,float32) formatted using a C-style floating point format specifications, i.e %e, %E: Signed value having the form [-]d.dddde[sign]ddd where d is a single decimal digit, dddd is one or more decimal digits, ddd is exactly three decimal digits, and sign is + or - %f: Signed value having the form [-]dddd.dddd, where dddd is one or more decimal digits. The number of digits before the decimal point depends on the magnitude of the number, and the number of digits after the decimal point depends on the requested precision. %g, %G: Signed value printed in f or e format, whichever is more compact for the given value and precision. %M: System.Decimal value %O: Any value, printed by boxing the object and using it's ToString method(s) %A: Any value, printed by using Microsoft.FSharp.Text.StructuredPrintfImpl.Display.any_to_string with the default layout settings %a: A general format specifier, requires two arguments: (1) a function which accepts two arguments: (a) a context parameter of the appropriate type for the given formatting function (e.g. an #System.IO.TextWriter) (b) a value to print and which either outputs or returns appropriate text. (2) the particular value to print %t: A general format specifier, requires one argument: (1) a function which accepts a context parameter of the appropriate type for the given formatting function (e.g. an System.IO.TextWriter)and which either outputs or returns appropriate text. Basic integer types are: byte,sbyte,int16,uint16,int32,uint32,int64,uint64,nativeint,unativeint Basic floating point types are: float, float32 The following format patterns are accepted but a warning is printed: %h(d|u|x|X|o) %l(d|u|x|X|o) The following format patterns are now deprecated: %Ld, %Li, %Lu, %Lx, %LX, %Lo: same, but an int64 %nd, %ni, %nu, %nx, %nX, %no: same, but a nativeint %Ud, %Ui, %Uu, %Ux, %UX, %Uo: same, but an unsigned int32 (uint32) %ULd, %ULi, %ULu, %ULx, %ULX, %ULo: same, but an unsigned int64 (uint64) %Und, %Uni, %Unu, %Unx, %UnX, %Uno: same, but an unsigned nativeint (unativeint) The optional width is an integer indicating the minimal width of the result. For instance, %6d prints an integer, prefixing it with spaces to fill at least 6 characters. If width is '*', then an extra integer argument is taken to specify the corresponding width. any number '*': Valid flags are: 0: add zeros instead of spaces to make up the required width '-': left justify the result within the width specified '+': add a '+' character if the number is positive (to match a '-' sign for negatives) ' ': add an extra space if the number is positive (to match a '-' sign for negatives) The printf '#' flag is invalid and a compile-time error will be reported if it is used. A record of options to control structural formatting. For F# Interactive properties matching those of this value can be accessed via the 'fsi' value. Floating Point format given in the same format accepted by System.Double.ToString, e.g. f6 or g15. If ShowProperties is set the printing process will evaluate properties of the values being displayed. This may cause additional computation. The ShowIEnumerable is set the printing process will force the evalution of IEnumerable objects to a small, finite depth, as determined by the printing parameters. This may lead to additional computation being performed during printing. From F# Interactive the default settings can be adjusted using, for example,
       open Microsoft.FSharp.Compiler.Interactive.Settings;;
       setPrintWidth 120;;
     
    Data representing structured layouts of terms. Convert any value to a string using a standard formatter Data is typically formatted in a structured format, e.g. lists are formatted using the "[1;2]" notation. The details of the format are not specified and may change from version to version and according to the flags given to the F# compiler. The format is intended to be human-readable, not machine readable. If alternative generic formats are required you should develop your own formatter, using the code in the implementation of this file as a starting point. Data from other .NET languages is formatted using a virtual call to Object.ToString() on the boxed version of the input. Convert any value to a layout using the given formatting options. The layout can then be processed using formatting display engines such as those in the LayoutOps module. any_to_string and output_any are built using any_to_layout with default format options. Ouput any value to a channel using the same set of formatting rules as any_to_string Layout two vertically. Layout list vertically. Wrap braces around layout. Wrap round brackets around Layout. Join layouts into a comma separated list. The empty layout Is it the empty layout? An string which is left parenthesis (no space on the right). Layout like an F# list. An uninterpreted leaf, to be interpreted into a string by the layout engine. This allows leaf layouts for numbers, strings and other atoms to be customized according to culture. Join broken with ident=0 Join broken with ident=1 Join broken with ident=2 Join, unbreakable. Join, possible break with indent=1 Join, possible break with indent=2 Join, possible break with indent=0 Layout like an F# option. An string which is right parenthesis (no space on it's left). Join layouts into a semi-colon separated list. An string which requires no spaces either side. Join layouts into a list separated using the given Layout. Join layouts into a space separated list. Wrap square brackets around layout. See tagL Form tuple of layouts. For limitting layout of list-like sequences (lists,arrays,etc). unfold a list of items using (project and z) making layout list via itemL. If reach maxLength (before exhausting) then truncate. An string leaf A layout is a sequence of strings which have been joined together. The strings are classified as words, separators and left and right parenthesis. This classification determines where spaces are inserted. A joint is either unbreakable, breakable or broken. If a joint is broken the RHS layout occurs on the next line with optional indentation. A layout can be squashed to for given width which forces breaks as required.
    ================================================ FILE: ironclad-apps/tools/fsharp/FSharp.PowerPack.Build.Tasks.xml ================================================ FSharp.PowerPack.Build.Tasks The default location of FSharp.Core.dll and fsc.exe based on the version of fsc.exe that is running ================================================ FILE: ironclad-apps/tools/fsharp/FSharp.PowerPack.Linq.xml ================================================ FSharp.PowerPack.Linq When used in queries, this operator corresponds to the LINQ Min operator and the query convertor recognises it as such It differs in return type from Seq.min_by When used in queries, this operator corresponds to the LINQ Join operator and the query convertor recognises it as such This join operator implements the LINQ GroupJoin operator and the query convertor recognises it as such When used in queries, this operator corresponds to the LINQ Join operator and the query convertor recognises it as such This join operator implements the LINQ GroupJoin operator and the query convertor recognises it as such This join operator corresponds to the LINQ Join operator and the query convertor recognises it as such When used in queries, this operator corresponds to the LINQ Max operator and the query convertor recognises it as such It differs in return type from Seq.max_by When used in queries, this operator corresponds to the LINQ Max operator and the query convertor recognises it as such It differs in return type from Seq.max_by When used in queries, this operator corresponds to the LINQ Min operator and the query convertor recognises it as such It differs in return type from Seq.min_by When used in queries, this operator corresponds to the LINQ Min operator and the query convertor recognises it as such It differs in return type from Seq.min_by Evaluate the quotation expression by first converting to a LINQ expression tree making use of IQueryable operators and then executing expression tree Exceptions: InvalidArgumentException will be raised if the input expression is not in the subset that can be converted to a LINQ expression tree This function should not be called directly. A set of types used for implementing quotation conversions. These are public only because targets of Linq Lambda expressions require them to be so This module provides Compile and Eval extension members for F# quotation values, implemented by translating to LINQ expression trees and using the LINQ dynamic compiler. ================================================ FILE: ironclad-apps/tools/fsharp/FSharp.PowerPack.Metadata.xml ================================================ FSharp.PowerPack.Metadata Return the System.Reflection.Assembly object for the assembly Holds the full qualified assembly name Get the object representing the F# core library (FSharp.Core.dll) for the running program A handle to the full specification of the contents of the module contained in this Assembly A hint as to where does the code for the CCU live (e.g what was the tcConfig.implicitIncludeDir at compilation time for this DLL?) Return the System.Reflection.Assembly object for the assembly This is one way of starting the loading process off. This is one way of starting the loading process off. Dependencies are automatically resolved by calling System.Reflection.Assembly.Load. The declared documentation for the type or module Indicates the type prefers the "tycon<a,b>" syntax for display etc. The cases of a discriminated union The fields of the class, struct or enum The declaration location for the type constructor Get the fully qualified name of the type or module The name of the type, possibly with `n mangling Properties, methods etc. with implementations, also values in a module Indicates the type is a struct Indicates the entity is an F# module definition Indicates the entity is a measure definition If true, then this is a reference to something in some .NET assembly from another .NET language Indicates an F# exception declaration Indicates the type is a measure, type or exception abbreviation Interface implementations - boolean indicates compiler-generated Indicates that a module is compiled to a class with the given mangled name. The mangling is reversed during lookup Indicates the type is implemented through a mapping to IL assembly code. THis is only true for types in FSharp.Core.dll Get the generic parameters, possibly including unit-of-measure parameters Base type, if any The declared attributes for the type Return the System.Type for the type Raises InvalidOperationException if the type is an abbreviation or has an assembly code representation. Return the FSharpEntity corresponding to a .NET type The documentation for the type parameter. Is this a ^a type variable Is this a measure variable The declared attributes of the type parameter. An F# discriminated union, as an object model XML documentation attached to a value. The full type of the member or value when used as a first class value Is this an F# type function Is this a mutable value Is this a module or member value Is this an implicit constructor? Is this an extension member? Is this a compiler generated value Is this a must-inline value The typars of the member or value The member name in compiled code Custom attributes attached to the value. These contain references to other values (i.e. constructors in types). Mutable to fixup these value references after copying a colelction of values. Documentation for the field The type of the field, w.r.t. the generic parameters of the enclosing type constructor Declaration-location of the field Attributes attached to generated property Name of the field Indicates a static field Is the field declared in F#? Indicates a compiler generated field, not visible to Intellisense or name resolution Attributes attached to generated field Get the named entity for a type constructed using a named entity Indicates the type is a tuple type. The GenericArguments property returns the elements of the tuple type. Indicates the type is constructed using a named entity Indicates the type is a variable type, whether declared, generalized or an inference type parameter Indicates the type is a function type. The GenericArguments property returns the domain and range of the function type. Get the index for a generic parameter type Get the generic parameter data for a generic parameter type Get the generic arguments for a tuple type, a function type or a type constructed using a named entity Documentation for the case Return type constructed by the case. Normally exactly the type of the enclosing type, sometimes an abbreviation of it Range of the name of the case Name of the case Data carried by the case. Name of the case in generated IL code Attributes, attached to the generated static method to make instances of the case Calling conventions. These are used in method pointer types. Global state: table of all assembly references keyed by AssemblyRefData The explicit offset in bytes when explicit layout is used. Index table by name and arity. This is used to store event, property and field maps. Review: this is not such a great data structure. keyed first on namespace then on type name. The namespace is often a unique key for a given type map. A little ugly, but the idea is that if a data structure does not contain lazy values then we don't add laziness. So if the thing to map is already evaluated then immediately apply the function. Global State. All namespace splits Like Fixup but loader may return None, in which case there is no fixup. Used when generating the secret paths used by FSI file generation The characters that are allowed to be in an identifier. Is this character a part of a long identifier Used when generating the secret paths used by FSI file generation Used when generating the secret paths used by FSI file generation Try to chop "get_" or "set_" from a string Attrib(kind,unnamedArgs,propVals) We keep both source expression and evaluated expression around to help intellisense and signature printing AttribNamedArg(name,type,isField,value) The result of attempting to resolve an assembly name to a full ccu. UnresolvedCcu will contain the name of the assembly that could not be resolved. Ensure the ccu is derefable in advance. Supply a path to attach to any resulting error message. A relinkable handle to the contents of a compilation unit. Relinking is performed by mutation. The information ILXGEN needs about the location of an item Specifies the compiled representations of type and exception definitions. Computed and cached by later phases (never computed type checking). Cached at type and exception definitions. Not pickled. Constants in expressions Decision trees. Pattern matching has been compiled down to a decision tree by this point. The right-hand-sides (actions) of the decision tree are labelled by integers that are unique for that particular tree. A target of a decision tree. Can be thought of as a little function, though is compiled as a local block. From TAST TyconRef to IL ILTypeRef A named module-or-namespace-fragment definition The module_typ is a binder. However it is not used in the ModuleOrNamespaceExpr: it is only referenced from the 'outside' The contents of a module-or-namespace-fragment definition A type for a module-or-namespace-fragment and the actual definition of the module-or-namespace-fragment note: ModuleOrNamespaceRef and TyconRef are type equivalent Namespace or module-compiled-as-type? Values, including members in F# types in this module-or-namespace-fragment. Type, mapping mangled name to Tycon, e.g. Lookup tables keyed the way various clients expect them to be keyed. We attach them here so we don't need to store lookup tables via any other technique Mutation used during compilation of FSharp.Core.dll Non-local references indirect via a CCU The lookup into the CCU is a NonLocalPath, which is a series of strings We cache the result of dereferencing Index into the namespace/module structure of a particular CCU A representation of a method in an object expression. Note: Methods associated with types are represented as val declarations Note: We should probably use val_specs for object expressions, as then the treatment of members in object expressions could be more unified with the treatment of members in types A public path records where a construct lives within the global namespace of a CCU. This ModuleOrNamespace that represents the compilation of a module as a class. The same set of tycons etc. are bound in the ModuleOrNamespace as in the ModuleOrNamespaceExpr This is the body of the module/namespace The extra metadata stored about typars for top-level definitions. Any information here is propagated from signature through to the compiled code. The extra metadata stored about typars for top-level definitions. Any information here is propagated from signature through to the compiled code. The specification of a member constraint that must be solved The ILX data structure representing the discriminated union. The type of the value. May be a Type_forall for a generic value. May be a type variable or type containing type variables during type inference. A unique stamp within the context of this invocation of the compiler process The place where the value was defined. What is the public path to the value, if any? Should be set if and only if IsMemberOrModuleBinding is set. Is this a member, if so some more data about the member. Note, the value may still be (a) an extension member or (b) and abtract slot without a true body. The internal name the value. Was the value inferred to be a method or function that definitely makes no critical tailcalls? The value of a value or member marked with [<LiteralAttribute>] Is this a member definition or module definition? Is this represented as a "top level" static binding (i.e. a static field, static member, instance member), rather than an "inner" binding that may result in a closure. This is implied by IsMemberOrModuleBinding, however not vice versa, for two reasons. Some optimizations mutate this value when they decide to change the representation of a binding to be IsCompiledAsTopLevel. Second, even immediately after type checking we expect some non-module, non-member bindings to be marked IsCompiledAsTopLevel, e.g. 'y' in 'let x = let y = 1 in y + y' (NOTE: check this, don't take it as gospel) Range of the definition (implementation) of the value, used by Visual Studio Updated by mutation when the implementation is matched against the signature. The parent type or module, if any (None for expression bindings and parameters) References are either local or nonlocal The big type of expressions. The algebra of types Unique name generator for stamps attached to lambdas and object expressions Create a module Tycon based on an existing one using the function 'f'. We require that we be given the parent for the new module. We pass the new module to 'f' in case it needs to reparent the contents of the module. Create a tycon based on an existing one using the function 'f'. We require that we be given the new parent for the new tycon. We pass the new tycon to 'f' in case it needs to reparent the contents of the tycon. Create a Val based on an existing one using the function 'f'. We require that we be given the parent for the new Val. Given (newPath,oldPath) replace oldPath by newPath in the TAccess. Equality on CCUs, implemented as reference equality Combine module types when multiple namespace fragments contribute to the same namespace, making new module specs as we go. Identical to tcref.Deref and deref_tycon, just used to help distinguish what kind of entity we expect here Compiler-internal references to items in fslib are generated as Ref_nonlocal even when compiling fslib Unique name generator for stamps attached to to val_specs, tycon_specs etc. This predicate tests if non-local resolution paths are definitely known to resolve to different entities. All references with different named paths always resolve to different entities. Two references with the same named paths may resolve to the same entities even if they reference through different CCUs, because one reference may be forwarded to another via a .NET TypeForwarder. See nlpath_definitely_not_eq Equality on type varialbes, implemented as reference equality verboseStamps: print #stamp on each id -- very verbose - but sometimes useful. Turn on using '--stamps' Equality on value specs, implemented as reference equality Metadata on values (names of arguments etc. The default location of FSharp.Core.dll and fsc.exe based on the version of fsc.exe that is running ================================================ FILE: ironclad-apps/tools/fsharp/FSharp.PowerPack.xml ================================================ FSharp.PowerPack Lookup or set the given element in the table. Set replaces all existing bindings for a value with a single bindings. Raise KeyNotFoundException if the element is not found. Lookup or set the given element in the table. Set replaces all existing bindings for a value with a single bindings. Raise KeyNotFoundException if the element is not found. The total number of keys in the hash table Lookup the given element in the table, returning the result as an Option Replace the latest binding (if any) for the given element. Remove the latest binding (if any) for the given element from the table Apply the given function to each binding in the hash table Apply the given function to each element in the collection threading the accumulating parameter through the sequence of function applications Find all bindings for the given element in the table, if any Make a shallow copy of the collection Test if the collection contains any bindings for the given element Test if the collection contains any bindings for the given element Clear all elements from the collection Add a binding for the element to the table Create a new empty mutable HashMultiMap with key hash/equality based on the F# structural "hash" and (=) functions. Create a new empty mutable HashMultiMap with an internal bucket array of the given approximate size and with key hash/equality based on the F# structural "hash" and (=) functions Create a new empty mutable HashMultiMap with an internal bucket array of the given approximate size and with the given key hash/equality functions Build a map that contains the bindings of the given IEnumerable Hash tables, by default based on F# structural "hash" and (=) functions. The table may map a single key to multiple bindings. The total number of elements in the set Remove the given element from the set Apply the given function to each binding in the hash table Apply the given function to the set threading the accumulating parameter through the sequence of function applications Create a new empty mutable hash set with key hash/equality based on the F# structural "hash" and (=) functions Create a new empty mutable hash set with an internal bucket array of the given approximate size and with key hash/equality based on the F# structural "hash" and (=) functions Create a new empty mutable hash set with an internal bucket array of the given approximate size and with the given key hash/equality functions Create a new mutable hash set containing elements drawn from the given sequence Make a shallow copy of the set Test if the set contains the given element Clear all elements from the set Add an element to the collection Create a new empty mutable hash set with key hash/equality based on the F# structural "hash" and (=) functions Create a new empty mutable hash set with an internal bucket array of the given approximate size and with key hash/equality based on the F# structural "hash" and (=) functions Create a new empty mutable hash set with an internal bucket array of the given approximate size and with the given key hash/equality functions Create a new mutable hash set containing elements drawn from the given sequence Mutable hash sets based by default on F# structural "hash" and (=) functions. Implemented via a hash table and/or Dictionary. LazyLists are possibly-infinite, cached sequences. See also IEnumerable/Seq for uncached sequences. Calling "get" on the same lazy list value you will keep getting the same (cached) result. LazyLists normally involve delayed computations without side-effects, and calling "get" may cause these computations to be executed. The results of these computations are cached - evaluations will be performed only once for each element of the lazy list. This is different to IEnumerable/Seq where recomputation happens each time an enumerator is created and the sequence traversed. LazyLists can represent cached potentially-infinite computations. Because they are cached they may cause memory leaks if some part of your code maintains a live reference to the head of an infinite or very large lazy list while iterating it, or if a reference is maintained after the list is no longer required. Although lazy lists are an abstract type you may pattern match against them using the LazyList.Cons and LazyList.Nil active patterns. These may force the computation of elements of the list. Return the stream which contains on demand the elements of the first stream followed by the elements of the second list Return the stream which contains on demand the pair of elements of the first and second list Return the stream which contains on demand the list of elements of the list of lazy lists. Return a new stream which contains on demand the given item followed by the given stream. Return a new stream which contains on demand the given item followed by the stream returned by the given computation. The computation is not executed until the elements of the stream are consumed. The computation is only executed once. Return a stream that is in effect the stream returned by the given computation. The given computation is not executed until the first element on the stream is consumed. Return the stream without the first 'n' elements of the given stream. Does not force the evaluation of any cells in the stream. Evaluates to the stream that contains no items Return a new collection which on consumption will consist of only the elements of the collection for which the given predicate returns "true" Return the first element for which the given function returns true. Raise KeyNotFoundException if no such element exists. Apply the given function to successive elements of the list, returning the first result where function returns Some(x) for some x. If the function never returns true, 'None' is returned. Return a new stream consisting of the results of applying the given accumulating function to successive elements of the stream Get the first cell of the stream. Return the first element of the stream. Raise 'Invalid_argument "hd"' if the stream is empty. Forces the evaluation of the first cell of the stream if it is not already evaluated. Build a new collection whose elements are the results of applying the given function to each of the elements of the collection. Build a new collection whose elements are the results of applying the given function to the corresponding elements of the two collections pairwise. Test if a stream contains at least one element. Forces the evaluation of the first element of the stream if it is not already evaluated. Build a collection from the given array. This function will eagerly evaluate all of the stream (and thus may not terminate). Build a collection from the given list. This function will eagerly evaluate all of the stream (and thus may not terminate). Build a new collection from the given enumerable object Return the stream which on consumption will consist of an infinite sequence of the given item Return the stream which on consumption will consist of at most 'n' elements of the given stream. Does not force the evaluation of any cells in the stream. Return the stream corresponding to the remaining items in the sequence. Raise 'Invalid_argument "tl"' if the stream is empty. Forces the evaluation of the first cell of the stream if it is not already evaluated. Build an array from the given collection Build a list from the given collection This function will eagerly evaluate all of the stream (and thus may not terminate). Return a view of the collection as an enumerable object Return a stream that contains the elements returned by the given computation. The given computation is not executed until the first element on the stream is consumed. The given argument is passed to the computation. Subsequent elements in the stream are generated by again applying the residual 'b to the computation. Build a new array that contains the elements of the first array followed by the elements of the second array Read a range of elements from the first array and write them into the second. Apply the given function to each element of the array. Return the array comprised of the results "x" for each element where the function returns Some(x) Combine the two arrays into an array of pairs. The two arrays must have equal lengths. Build a new array that contains the elements of each of the given list of arrays Build a new array that contains the elements of the given array Create an array whose elements are all initially the given value. Test if any element of the array satisfies the given predicate. If the input function is f and the elements are i0...iN then computes p i0 or ... or p iN. Test elements of the two arrays pairwise to see if any pair of element satisfies the given predicate. Raise ArgumentException if the arrays have different lengths. Fill a range of the collection with the given element Return a new collection containing only the elements of the collection for which the given predicate returns true Return the first element for which the given function returns true. Raise KeyNotFoundException if no such element exists. Return the index of the first element in the array that satisfies the given predicate. Raise KeyNotFoundException if none of the elements satisy the predicate. Return the index of the first element in the array that satisfies the given predicate. Raise KeyNotFoundException if none of the elements satisy the predicate. Apply the given function to successive elements, returning the first result where function returns "Some(x)" for some x. Apply a function to each element of the collection, threading an accumulator argument through the computation. If the input function is f and the elements are i0...iN then computes f (... (f s i0)...) iN Apply a function to pairs of elements drawn from the two collections, left-to-right, threading an accumulator argument through the computation. The two input arrays must have the same lengths, otherwise an ArgumentException is raised. Apply a function to each element of the array, threading an accumulator argument through the computation. If the input function is f and the elements are i0...iN then computes f i0 (...(f iN s)). Apply a function to pairs of elements drawn from the two collections, right-to-left, threading an accumulator argument through the computation. The two input arrays must have the same lengths, otherwise an ArgumentException is raised. Test if all elements of the array satisfy the given predicate. If the input function is f and the elements are i0...iN and "j0...jN" then computes p i0 && ... && p iN. Test elements of the two arrays pairwise to see if all pairs of elements satisfy the given predicate. Raise ArgumentException if the arrays have different lengths. Fetch an element from the collection. You can also use the syntax arr.[idx]. Create an array by calling the given generator on each index. Return true if the given array is empty, otherwise false Apply the given function to each element of the array. Apply the given function to two arrays simultaneously. The two arrays must have the same lengths, otherwise an Invalid_argument exception is raised. Apply the given function to each element of the array. The integer passed to the function indicates the index of element. Apply the given function to pair of elements drawn from matching indices in two arrays, also passing the index of the elements. The two arrays must have the same lengths, otherwise an ArgumentException is raised. Return the length of the collection. You can also use property arr.Length. Build a new array whose elements are the results of applying the given function to each of the elements of the array. Build a new collection whose elements are the results of applying the given function to the corresponding elements of the two collections pairwise. The two input arrays must have the same lengths. Build a new array whose elements are the results of applying the given function to each of the elements of the array. The integer index passed to the function indicates the index of element being transformed. Build a new collection whose elements are the results of applying the given function to the corresponding elements of the two collections pairwise. The two input arrays must have the same lengths, otherwise an ArgumentException is raised. Build an array from the given list Split the collection into two collections, containing the elements for which the given predicate returns true and false respectively Apply a function to each element of the array, threading an accumulator argument through the computation. If the input function is f and the elements are i0...iN then computes f (... (f i0 i1)...) iN. Raises ArgumentException if the array has size zero. Apply a function to each element of the array, threading an accumulator argument through the computation. If the input function is f and the elements are i0...iN then computes f i0 (...(f iN-1 iN)). Raises ArgumentException if the array has size zero. Return a new array with the elements in reverse order Like fold_left, but return the intermediary and final results Like fold_right, but return both the intermediary and final results Set the value of an element in the collection. You can also use the syntax arr.[idx] <- e. Return an array containing the given element Sort the elements using the given comparison function Sort the elements using the key extractor and generic comparison on the keys Split a list of pairs into two lists Build a new array that contains the given subrange specified by starting index and length. Build a list from the given array Return a view of the array as an enumerable object Return the first element for which the given function returns true. Return None if no such element exists. Return the index of the first element in the array that satisfies the given predicate. Return the index of the first element in the array that satisfies the given predicate. Split an array of pairs into two arrays Combine the two arrays into an array of pairs. The two arrays must have equal lengths, otherwise an ArgumentException is raised.. Generic operations on the type System.Collections.Generic.List, which is called ResizeArray in the F# libraries. Lookup or set the given element in the table. Raise KeyNotFoundException if the element is not found. Lookup or set the given element in the table. Raise KeyNotFoundException if the element is not found. The number of bindings in the hash table Lookup the given element in the table, returning the result as an Option Replace the latest binding (if any) for the given element. Remove the latest binding (if any) for the given element from the table Apply the given function to each binding in the hash table Apply the given function to each element in the collection threading the accumulating parameter through the sequence of function applications Find all bindings for the given element in the table, if any Create a new empty mutable hash table with an internal bucket array of the given approximate size and with the given key hash/equality functions Make a shallow copy of the collection Test if the collection contains any bindings for the given element Test if the collection contains any bindings for the given element Clear all elements from the collection Add a binding for the element to the table HashMultiMap, but where a constraint tag tracks information about the hash/equality functions used for the hashing. When the tag is Tags.StructuralHash this is identical to HashMultiMap. The number of elements in the set Remove the given element from the set Apply the given function to each binding in the hash table Apply the given function to the set threading the accumulating parameter through the sequence of function applications Create a new empty mutable hash set with an internal bucket array of the given approximate size and with the given key hash/equality functions Make a shallow copy of the set Test if the set contains the given element Clear all elements from the set Add an element to the collection Mutable hash sets based on F# structural "hash" and (=) functions. Implemented via a hash table and/or Dictionary. Mutable hash sets where a constraint tag tracks information about the hash/equality functions used for the hashing. When the tag is Tags.StructuralHash this is identical to HashSet. Immutable maps. Keys are ordered by construction function specified when creating empty maps or by F# structural comparison if no construction function is specified. Maps based on structural comparison are efficient for small keys. They are not a suitable choice if keys are recursive data structures or require non-structural comparison semantics. Lookup an element in the map. Raise KeyNotFoundException if no binding exists in the map. Return true if there are no bindings in the map. The number of bindings in the map Lookup an element in the map, returning a Some value if the element is in the domain of the map and None if not. The elements of the set as a list. The elements of the set as an array Remove an element from the domain of the map. No exception is raised if the element is not present. Build two new maps, one containing the bindings for which the given predicate returns 'true', and the other the remaining bindings. Build a new collection whose elements are the results of applying the given function to each of the elements of the collection. Build a new collection whose elements are the results of applying the given function to each of the elements of the collection. The index passed to the function indicates the index of element being transformed. Apply the given function to each binding in the dictionary Return true if the given predicate returns true for all of the bindings in the map. Always returns true if the map is empty. Given the start and end points of a key range, Fold over the bindings in the map that are in the range, and the end points are included if present (the range is considered a closed interval). Fold over the bindings in the map. Fold over the bindings in the map. Search the map looking for the first element where the given function returns a Some value Build a new map containing the bindings for which the given predicate returns 'true'. Return true if the given predicate returns true for one of the bindings in the map. Always returns false if the map is empty. The empty map, and use the given comparer comparison function for all operations associated with any maps built from this map. Build a map that contains the bindings of the given IEnumerable and where comparison of elements is based on the given comparison function Test is an element is in the domain of the map Return a new map with the binding added to the given map. Immutable maps. A constraint tag carries information about the class of key-comparers being used. Immutable sets based on binary trees, default tag Return a new set with the elements of the second set removed from the first. Compute the union of the two sets. Returns the lowest element in the set according to the ordering being used for the set Returns the highest element in the set according to the ordering being used for the set A useful shortcut for Set.is_empty. See the Set module for further operations on sets. Return the number of elements in the set The number of elements in the set Compute the union of the two sets. The elements of the set as a list. The elements of the set as an array. A singleton set based on the given comparison operator A useful shortcut for Set.remove. Note this operation produces a new set and does not mutate the original set. The new set will share many storage nodes with the original. See the Set module for further operations on sets. Build two new sets, one containing the elements for which the given predicate returns 'true', and the other the remaining elements. Apply the given function to each binding in the collection Evaluates to "true" if all elements of the first set are in the second Evaluates to "true" if all elements of the second set are in the first Compute the intersection of the two sets. Test if all elements of the collection satisfy the given predicate. If the input function is f and the elements are i0...iN and j0...jN then computes p i0 && ... && p iN. Apply the given accumulating function to all the elements of the set Return a new collection containing only the elements of the collection for which the given predicate returns "true" Test if any element of the collection satisfies the given predicate. If the input function is f and the elements are i0...iN then computes p i0 or ... or p iN. Compares two sets and returns true if they are equal or false otherwise The empty set based on the given comparer Return a new set with the elements of the second set removed from the first. A set based on the given comparer containing the given initial elements A useful shortcut for Set.mem. See the Set module for further operations on sets. Compares a and b and returns 1 if a > b, -1 if b < a and 0 if a = b A useful shortcut for Set.add. Note this operation prodcues a new set and does not mutate the original set. The new set will share many storage nodes with the original. See the Set module for further operations on sets. Immutable sets where a constraint tag carries information about the class of key-comparer being used. The spec value describes the action of the argument, and whether it expects a following parameter. "parse specs f use" parses the arguments given by Sys.argv according to the argument processing specifications "specs". Arguments begin with "-". Non-arguments are passed to "f" in order. "use" is printed as part of the usage line if an error occurs. Permitted arguments are specified using triples: (arg, action, help). Actions are: Unit(f): call f, no subseq. arg Set(br): set ref to 'true', no subseq. arg. Clear(br): set ref to 'false, no subseq. arg. String(f): pass the subseq. arg to f Int(f): pass the subseq. arg to f Float(f): pass the subseq. arg to f Rest(f): pass all subseq. args to f in order "usage specs use" prints the help for each argument. A simple command-line argument processor. Is an element in the array, uses (=) equality. Create a jagged 2 dimensional array. This member is primarily provided for compatibility with implementations of ML. F# also supports non-jagged 2D arrays - see the Array2D module and types such as "int[,]". Create a jagged 2 dimensional array. Synonym for create. This member is primarily provided for compatibility with implementations of ML. F# also supports non-jagged 2D arrays - see the Array2D module and types such as "int[,]". Return true if the list is not empty. Pin the given array for the duration of a single call to the given function. A native pointer to the first element in the array is passed to the given function. Cleanup the GCHandle associated with the pin when the function completes, even if an exception is raised. As for Array.pin, except that the caller is responsible for calling Free on the returned GCHandle in order to release the pin. Like reduce, but return both the intermediary and final results Like reduceBack, but return both the intermediary and final results Compatibility operations on arrays. Pin the given array for the duration of a single call to the given function. A native pointer to the first element in the array is passed to the given function. Cleanup the GCHandle associated with the pin when the function completes, even if an exception is raised. As for Array2D.pin, except that the caller is responsible for calling Free on the returned GCHandle in order to release the pin. Returns the sum of a and b Compares a and b and returns 1 if a > b, -1 if b < a and 0 if a = b Returns a divided by b Combines the binary representation of a and b by bitwise and Returns the bitwise logical negation of a Combines the binary representation of a and b by bitwise or Combines the binary representation of a and b by bitwise xor Returns a multiplied by b Converts a char to a byte Converts a 32-bit integer to a byte Converts a 32-bit integer to a byte Converts a string to a byte Converts a 16-bit integer to a byte Converts an unsigned 32-bit integer to a byte The value one as a System.Byte Returns the predeccessor of the argument wrapped around 0uy Returns the remainder of a divided by b Shifts the binary representation a by n bits to the left Shifts the binary representation a by n bits to the right Returns a minus b Returns the successor of the argument wrapped around 255uy Converts a byte to a char Converts a byte to a 32-bit integer Converts a byte to a 32-bit integer Converts a byte to a string Converts a byte to a 16-bit integer Converts a byte to an unsigned 32-bit integer The value zero as a System.Byte Byte (8-bit) operations. Apply a function to each element of the collection, threading an accumulator argument through the computation. If the input function is f and the elements are i0...iN then computes f (... (f s i0)...) iN Apply a function to each element of the collection, threading an accumulator argument through the computation. If the input function is f and the elements are i0...iN then computes f i0 (...(f iN s)). Apply the given function to each element of the collection. Apply the given function to each element of the collection. The integer passed to the function indicates the index of element. Build a new collection whose elements are the results of applying the given function to each of the elements of the collection. Build a new collection whose elements are the results of applying the given function to each of the elements of the collection. The integer index passed to the function indicates the index of element being transformed. Build a collection from the given list Build a list from the given collection Byte arrays. Arrays of bytes type-compatible with the C# byte[] type Converts the value of the specified 32-bit signed integer to its equivalent Unicode character Converts the value of the specified Unicode character to the equivalent 32-bit signed integer Compares a and b and returns 1 if a > b, -1 if b < a and 0 if a = b Converts the value of a Unicode character to its lowercase equivalent Converts the value of a Unicode character to its uppercase equivalent Unicode characters, i.e. the System.Char type. see also the operations in System.Char and the System.Text.Encoding interfaces if necessary. Combine enum values using 'logical or'. The relevant enumeration type is inferred from context. Convert an integer to an enumeration value. The result type is inferred from context. Test if an enumeration value has a particular flag set, using 'logical and'. The relevant enumeration type is inferred from context. Convert an enumeration value to an integer. The argument type is inferred from context. Simple operations to convert between .NET enuemration types and integers Returns the sum of a and b Compares a and b and returns 1 if a > b, -1 if b < a and 0 if a = b Returns a divided by b Returns a multiplied by b Returns -a Converts a raw 32-bit representation to a 32-bit float Converts a 64-bit float to a 32-bit float Converts a 32-bit integer to a 32-bit float Converts a 32-bit integer to a 32-bit float Converts a 64-bit integer to a 32-bit float Converts a string to a 32-bit float Returns a minus b Converts a 32-bit float to raw 32-bit representation Converts a 32-bit float to a 64-bit float Converts a 32-bit float to a 32-bit integer Converts a 32-bit float to a 32-bit integer Converts a 32-bit float to a 64-bit integer Converts a 32-bit float to a string ML-like operations on 32-bit System.Single floating point numbers. Returns the sum of a and b Compares a and b and returns 1 if a > b, -1 if b < a and 0 if a = b Returns a divided by b Returns a multiplied by b Returns -a Converts a raw 64-bit representation to a 64-bit float Converts a 32-bit float to a 64-bit float Converts a 32-bit integer to a 64-bit float Converts a 32-bit integer to a 64-bit float Converts a 64-bit integer to a 64-bit float Converts a string to a 64-bit float Returns a minus b Converts a 64-bit float to raw 64-bit representation Converts a 64-bit float to a 32-bit float Converts a 64-bit float to a 32-bit integer Converts a 64-bit float to a 32-bit integer Converts a 64-bit float to a 64-bit integer Converts a 64-bit float to a string ML-like operations on 64-bit System.Double floating point numbers. Returns the absolute value of the argument Returns the sum of a and b Converts a 64-bit float to a raw 32-bit representation Converts a 32-bit float to a raw 32-bit representation Compares a and b and returns 1 if a > b, -1 if b < a and 0 if a = b Returns a divided by b Converts a raw 32-bit representation to a 32-bit float Converts a raw 32-bit representation to a 64-bit float Combines the binary representation of a and b by bitwise and Returns the bitwise logical negation of a Combines the binary representation of a and b by bitwise or Combines the binary representation of a and b by bitwise xor Returns the largest 32-bit signed integer Returns the smallest 32-bit signed integer The value minus one as a System.Int32 Returns a multiplied by b Returns -a Converts a 64-bit float to a 32-bit integer Converts a 32-bit float to a 32-bit integer Converts a 32-bit integer to a 32-bit integer (included for ML compatability) Converts a 64-bit unsigned integer to a 32-bit integer Converts a 32-bit unsigned integer to a 32-bit integer Converts a string to a 32-bit integer Converts a 32-bit unsigned integer to a 32-bit integer The value one as a System.Int32 Returns the predeccessor of the argument Returns the remainder of a divided by b Shifts the binary representation a by n bits to the left Shifts the binary representation a by n bits to the right; high-order empty bits are set to the sign bit Shifts the binary representation a by n bits to the right; high-order bits are zero-filled Returns a minus b Returns the successor of the argument Converts a 32-bit integer to a 64-bit float Converts a 32-bit integer to a 32-bit float Converts a 32-bit integer to a 32-bit integer (included for ML compatability) Converts a 32-bit unsigned integer to a 64-bit integer Converts a 32-bit unsigned integer to a 32-bit integer Converts a 32-bit integer to a string Converts a 32-bit integer to a 32-bit unsigned integer The value zero as a System.Int32 Basic operations on 32-bit integers. The type int32 is identical to System.Int32. Returns the absolute value of the argument Returns the sum of a and b Converts a 64-bit float to a raw 64-bit representation Compares a and b and returns 1 if a > b, -1 if b < a and 0 if a = b Returns a divided by b Converts a raw 64-bit representation to a 64-bit float Combines the binary representation of a and b by bitwise and Returns the bitwise logical negation of a Combines the binary representation of a and b by bitwise or Combines the binary representation of a and b by bitwise xor Returns the largest 64-bit signed integer Returns the smallest 64-bit signed integer The value minus one as a System.Int64 Returns a multiplied by b Returns -a Converts a 64-bit float to a 64-bit integer Converts a 32-bit float to a 64-bit integer Converts a 32-bit integer to a 64-bit integer Converts a 32-bit integer to a 64-bit integer Converts a native integer to a 64-bit integer Converts a string to a 64-bit integer Converts an unsigned 64-bit integer to a 64-bit integer The value one as a System.Int64 Returns the predeccessor of the argument Returns the remainder of a divided by b Shifts the binary representation a by n bits to the left Shifts the binary representation a by n bits to the right; high-order empty bits are set to the sign bit Shifts the binary representation a by n bits to the right; high-order bits are zero-filled Returns a minus b Returns the successor of the argument Converts a 64-bit integer to a 64-bit float Converts a 64-bit integer to a 32-bit float Converts a 64-bit integer to a 32-bit integer Converts a 64-bit integer to a 32-bit integer Converts a 64-bit integer to a native integer Converts a 64-bit integer to a string Converts a 64-bit integer to an unsigned 64-bit integer The value zero as a System.Int64 Basic operations on 64-bit integers. The type int64 is identical to System.Int64. Build a lazy (delayed) value from the given computation See Lazy.Force See Lazy.Force. See Lazy.SynchronizedForce. See Lazy.UnsynchronizedForce Build a lazy (delayed) value from the given computation Build a lazy (delayed) value from the given pre-computed value. Check if a lazy (delayed) value has already been computed Lookup key's data in association list, uses (=) equality. Raise System.IndexOutOfRangeException exception if key not found, in which case you should typically use try_assoc instead. See assoc, but uses the physical equality operator (==) for equality tests Is an element in the list. Elements are compared using generic equality. Is an element in the list. Elements are compared using generic equality. Does the key have pair in the association list? See mem_assoc, but uses the physical equality operator (==) for equality tests. See mem, but uses the physical equality operator (==) for equality tests. Return true if the list is not empty. Remove pair for key from the association list (if it's there). See remove_assoc, but uses the physical equality operator (==) for equality tests. "rev_append l1 l2" evaluates to "append (rev l1) l2" "rev_map f l1" evaluates to "map f (rev l1)" "rev_map2 f l1 l2" evaluates to "map2 f (rev l1) (rev l2)" Like reduce_left, but return both the intermediary and final results Like reduce_right, but return both the intermediary and final results Lookup key's data in association list, uses (=) equality, returning "Some data" or "None". See try_assoc, but uses the physical equality operator (==) for equality tests. Compatibility operations on lists. A collection of operations for creating and using maps based on a particular comparison function. The 'Tag type parameter is used to track information about the comparison function. For use when not opening the Map module, e.g. Map.t A functor to build a collection of operations for creating and using maps based on the given comparison function. This returns a record that contains the functions you use to create and manipulate maps of this kind. The returned value is much like an ML module. Language restrictions related to polymorphism may mean you have to create a new instantiation of for each toplevel key/value type pair. To use this function you need to define a new named class that implements IComparer and pass an instance of that class as the first argument. For example: type MyComparer = new() = { } interface IComparer<string> with member self.Compare(x,y) = ... let MyStringMapProvider : Map.Provider < string,int > = Map.MakeTagged(new MyComparer()) Fold over the bindings in the map Extension functionality for maps using structural comparison Big_int compatability module for arbitrary sized integers. Add second buffer to the first. Read the given number of bytes as ASCII and add the resulting string to the buffer. Warning: this assumes an ASCII encoding for the I/O channel, i.e. it uses Pervasives.really_input and then use ascii_to_string to produce the string to add. Add character to the buffer. Add string to the buffer. Given a string, start position and length add that substring to the buffer. Clears the buffer. Gets the string built from the buffer. Create a buffer with suggested size. Number of characters in the buffer. Clears the buffer (same as Buffer.clear). Imperative buffers for building strings, a shallow interface to System.Text.StringBuilder "dirname" and "basename" decompose a filename into a directory name and a filename, i.e. "concat (dirname s) (basename s) = s" "check_suffix f s" returns true if filename "f" ends in suffix "s", e.g. check_suffix "abc.fs" ".fs" returns true. "chop_extension f" removes the extension from the given filename. Raises ArgumentException if no extension is present. Assuming "check_suffix f s" holds, "chop_suffix f s" returns the filename "f" with the suffix "s" removed. "concat a b" returns System.IO.Path.Combine(a,b), i.e. the two names conjoined by the appropriate directory separator character for this architecture. The name used for the current directory on this OS. "dirname" and "basename" decompose a filename into a directory name and a filename, i.e. "concat (dirname s) (basename s) = s" Return true if the filename has a "." extension Returns true if the path is relative to the current directory but does not begin with an explicit "." or ".." Is the path is relative to the current directory or absolute. "parent_dir_name" returns the name for the directory above the current directory on this OS. "quote s" is designed for use to quote a filename when using it for a system command. It returns ("\'" ^ s ^ "\'"). "temp_file f s" returns a hitherto unused new file name. "f" and "s" are hints as to a suitable file name and suffix for the file. Common filename operations. This module is included to make it possible to cross-compile code with other ML compilers. See also System.IO.Path A collection of operations for creating and using hash tables based on particular type-tracked hash/equality functions. Generated by the Hashtbl.Make and Hashtbl.MakeTagged functors. This type is for use when you wish to specify a comparison function once and carry around an object that is a provider of (i.e. a factory for) hashtables that utilize that comparison function. The 'Tag' type parameter is used to track information about the comparison function, which helps ensure that you don't mixup maps created with different comparison functions OCaml compatible type name, for use when not opening module, e.g. Hashtbl.t Build a collection of operations for creating and using hashtables based on the given hash/equality functions. This returns a record that contains the functions you use to create and manipulate tables of this kind. The returned value is much like an ML module. You should call Make once for each new pair of key/value types. You may need to constrain the result to be an instantiation of Provider. let MyStringHashProvider : Provider<string,int> = Hashtbl.Make(myStringHash,myStringEq) Same as Make, except track the comparison function being used through an additional type parameter. To use this function accurately you need to define a new named class that implements IEqualityComparer and pass an instance of that class as the first argument. For example: type MyHasher = class new() = { } interface IEqualityComparer<string> with member self.GetHashCode(x) = ... member self.Equals(x,y) = ... end end let MyStringHashProvider : Hashtbl.Provider<string,int> = Hashtbl.MakeTagged(new MyStringHasher()) Add key and data to the table. Empty the table. Create a copy of the table. Remember they are imperative and get mutated. Create a hash table with the suggested initial size. Inlined to enable generation of efficient hash routines for the key type in the common case. Lookup key's data in the table. Raises exception is key not in table, if this could happen you should be using tryfind. Return all bindings for the given key Fold over all bindings Hash on the structure of a value according to the F# structural hashing conventions. See Pervasives.hash Hash on the identity of an object. See Pervasives.hashq. Apply the given function to each binding in the hash table Test for the existence of any bindings for the given key Create a hash table using the given data Create hash table using the given data Inlined to enable generation of efficient hash routines for the key type in the common case. Remove the latest binding for the given key Replace the latest binding for the given key Lookup the key's data in the table Multi-entry hash tables using the structural "hash" and "equals" functions. These tables can be used with keys of any type, but you should check that structural hashing and equality are correct for your key type. Structural hashing is efficient but not a suitable choice in all circumstances, e.g. may not hash efficiently on non-reference types and deeply-structured types. Better efficiency is typically achieved if key types are F#-generated types. These hash tables may map items to multiple keys (see find_all). The implementations are not safe for concurrent reading/writing, and so users of these tables should take an appropriate lock before reading/writing if used in a concurrent setting. ASCII LexBuffers The type "lexbuf" is opaque, but has an internal position information field that can be updated by setting "lexbuf.EndPos", for example if you wish to update the other fields in that position data before or during lexing. You will need to do this if you wish to maintain accurate line-count information. If you do this and wish to maintain strict cross-compiling compatibility with OCamlLex and other tools you may need code to conditionally use lexbuf_set_curr_p when compiling F# code. Remove all input, though don't discard the except the current lexeme Fuel a lexer using the given BinaryReader. Fuel a lexer from an array of bytes Fuel a lexer using the given in_channel. The bytes are read using Pervasives.input. If the in_channel is a textual channel the bytes are presented to the lexer by decoding the characters using System.Text.Encoding.ASCII. Fuel a lexer from function that fills an array of bytes up to the given length, returning the number of bytes filled. Fuel a lexer from a string, converted to ascii using System.Text.Encoding.ASCII.GetBytes Fuel a lexer using the given TextReader or StreamReader. The characters read are decoded to bytes using the given encoding (e.g. System.Text.Encoding.ASCII) and the bytes presented to the lexer. The encoding used to decode the characters is associated with the expectations of the lexer (e.g. a lexer may be constructed to accept only ASCII or pseudo-UTF8 bytes) and will typically be different to the encoding used to decode the file. same as lexeme_end_p Return the matched string Return the bytes for the matched string Return a character from the matched string, innterpreting the bytes using an ASCII encoding Return absolute positions into the entire stream of characters Return the positions stored in the lexbuf for the matched string Return absolute positions into the entire stream of characters Return the positions stored in the lexbuf for the matched string Return the matched string interpreting the bytes using the given Unicode text encoding Lexing: ML-like lexing support This file maintains rough compatibility for lexbuffers used by some ML laxer generators. The lexbuf carries an associated pair of positions. Beware that only the "cnum" (absolute character number) field is automatically updated as each lexeme is matched. Upon each successful match the prior end position is transferred to be the start position and a new start position is allocated with an updated pos_cnum field. See Microsoft.FSharp.Core.LanguagePrimitives.PhysicalEquality Negation of Obj.eq (i.e. reference/physical inequality) See Microsoft.FSharp.Core.Operators.unbox See Microsoft.FSharp.Core.Operators.box You can initialize error recovery by raising the Parse_error exception. Parsing: parser support for parsers produced by fsyacc. Parsers generated by fsyacc provide location information within parser actions. However that information is not available globally, but rather is accessed via the functions available on the following local variable which is available in all parser actions: parseState : 'a Microsoft.FSharp.Text.Parsing.IParseState However, this is not compatible with the parser specifications used with ocamlyacc and similar tools, which make a single parser state available globally. If you wish to use a global parser state (e.g. so your code will cross-compile with OCaml) then you can use the functions in this file. You will need to either generate the parser with '--ml-compatibility' option or add the code Parsing.set_parse_state parseState; at the start of each action of your grammar. The functions below simply report the results of corresponding calls to the latest object specified by a call to set_parse_state. Note that there could be unprotected multi-threaded concurrent access for the parser information, so you should not in general use these functions if there may be more than one parser active, and should instead use the functions directly available from the parseState object. A pseudo-abstraction over binary and textual input channels. OCaml-compatible channels conflate binary and text IO, and for this reasons their use from F# is somewhat deprecated (direct use of System.IO StreamReader, TextReader and BinaryReader objects is preferred, e.g. see System.IO.File.OpenText). Well-written OCaml-compatible code that simply opens either a channel in text or binary mode and then does text or binary I/O using the OCaml-compatible functions below will work, though care must be taken with regard to end-of-line characters (see input_char below). This library pretends that an in_channel is just a System.IO.TextReader. Channel values created using open_in_bin maintain a private System.IO.BinaryReader, which will be used whenever you do I/O using this channel. InChannel.of_BinaryReader and InChannel.of_StreamReader allow you to build input channels out of the corresponding .NET abstractions. This type is present primarily for compatibility with other versions of ML. When not cross-compiling we recommend using the .NET I/O libraries An pseudo-abstraction over binary and textual output channels. OCaml-compatible channels conflate binary and text IO, and for this reasons their use from F# is somewhat deprecated The direct use of System.IO StreamWriter, TextWriter and BinaryWriter objects is preferred, e.g. see System.IO.File.CreateText). Well-written OCaml code that simply opens either a channel in text or binary mode and then does text or binary I/O using the OCaml functions will work, though care must be taken with regard to end-of-line characters (see output_char below). This library pretends that an out_channel is just a System.IO.TextWriter. Channels created using open_out_bin maintain a private System.IO.BinaryWriter, which will be used whenever do I/O using this channel. The exception thrown by invalid_arg and misues of F# library functions Close the channel Close the given output channel This value is present primarily for compatibility with other versions of ML The smallest value that when added to 1.0 gives a different value to 1.0 Flush all pending output on the channel to the physical output device. Return the length of the input channel Attempt to input the given number of bytes from the channel, writing them into the buffer at the given start position. Does not block if the bytes are not available. The use of this function with a channel performing byte-to-character translation (e.g. one created with open_in, open_in_utf8 or open_in_encoded, or one or built from a StreamReader or TextReader) is not recommended. Instead, open the channel using open_in_bin or InChannel.of_BinaryReader. If used with a StreamReader channel, i.e. one created using open_in, open_in_utf8 or open_in_encoded, or one or built from a StreamReader, this function reads bytes directly from the underlying BaseStream. This may not be appropriate if any other input techniques are being used on the channel. If used with a TextReader channel (e.g. stdin), this function reads characters from the stream and then fills some of the byte array with the decoding of these into bytes, where the decoding is performed using the System.Text.Encoding.Default encoding Raise End_of_file (= System.IO.EndOfStreamException) if end of file reached. Input a binary integer from a binary channel. Compatible with output_binary_int. Input a single byte. For text channels this only accepts characters with a UTF16 encoding that fits in a byte, e.g. ASCII. Raise End_of_file (= System.IO.EndOfStreamException) if end of file reached. Input a single character. Raise End_of_file (= System.IO.EndOfStreamException) if end of file reached. Attempt to input characters from a channel. Does not block if inpout is not available. Raise End_of_file (= System.IO.EndOfStreamException) if end of file reached. No CRLF translation is done on input, even in text mode. That is, if an input file has '\r\n' (CRLF) line terminators both characters will be seen in the input. Input a single line. Raise End_of_file (= System.IO.EndOfStreamException) if end of file reached. Input a single serialized value from a binary stream. Raise End_of_file (= System.IO.EndOfStreamException) if end of file reached. Negation on integers of the 'int' type Throw an Invalid_argument exception This value is present primarily for compatibility with other versions of ML The highest representable positive value in the 'float' type The highest representable value in the 'int' type This value is present primarily for compatibility with other versions of ML The lowest non-denormalized positive IEEE64 float The lowest representable value in the 'int' type This value is present primarily for compatibility with other versions of ML This value is present primarily for compatibility with other versions of ML This value is present primarily for compatibility with other versions of ML 1D Array element set-accessor ('setter') 1D Array element get-accessor ('getter') Negation of the '==' operator, see also Obj.eq This value is present primarily for compatibility with other versions of ML. In F# the overloaded operators may be used. Reference/physical equality. True if boxed versions of the inputs are reference-equal, OR if both are value types and the implementation of Object.Equals for the type of the first argument returns true on the boxed versions of the inputs. In normal use on reference types or non-mutable value types this function has the following properties: - returns 'true' for two F# values where mutation of data in mutable fields of one affects mutation of data in the other - will return 'true' if (=) returns true - hashq will return equal hashes if (==) returns 'true' The use on mutable value types is not recommended. This value is present primarily for compatibility with other versions of ML. In F# the overloaded operators may be used. This value is present primarily for compatibility with other versions of ML This value is present primarily for compatibility with other versions of ML. In F# the overloaded operators may be used. This value is present primarily for compatibility with other versions of ML. In F# the overloaded operators may be used. This value is present primarily for compatibility with other versions of ML. In F# the overloaded operators may be used. Open the given file to read. In the absence of an explicit encoding (e.g. using Open_encoding) open_in uses the default text encoding (System.Text.Encoding.Default). If you want to read a file regardless of encoding then you should use binary modes. Note that .NET's "new StreamReader" function defaults to use a utf8 encoding, and also attempts to determine an automatic encoding by looking for "byteorder-marks" at the head of a text file. This function does not do this. No CR-LF translation is done on input. Open the given file to read in binary-mode Open the given file in the mode specified by the given flags Open the given file to read in text-mode using the UTF8 encoding Open the given file to write in text-mode using the System.Text.Encoding.Default encoding See output_char for a description of CR-LF translation done on output. Open the given file to write in binary-mode Open the given file to write in text-mode using the given encoding Open the given file to write in the mode according to the specified flags Open the given file to write in text-mode using the UTF8 encoding Return the length of the output channel. Raise an exception if not an app Write the given range of bytes to the output channel. Write the given integer to the output channel in binary format. Only valid on binary channels. Write the given byte to the output channel. No CRLF translation is performed. Write all the given bytes to the output channel. No CRLF translation is performed. Write the given Unicode character to the output channel. If the output channel is a binary stream and the UTF-16 value of the Unicode character is greater than 255 then ArgumentException is thrown. No CRLF translation is done on output. That is, if the output character is '\n' (LF) characters they will not be written as '\r\n' (CRLF) characters, regardless of whether the underlying operating system or output stream uses CRLF as the default line-feed character. Write the given Unicode string to the output channel. See output_char for the treatment of '\n' characters within the string. Serialize the given value to the output channel. Report the current position in the input channel Return the current position in the output channel, measured from the start of the channel. Not valid on all channels. n-1 (no overflow checking) Print a character to the stderr stream Read a floating point number from the console. Read an integer from the console. Read a line from the console, without the end-of-line character. Reads bytes from the channel. Blocks if the bytes are not available. See 'input' for treatment of text channels. Raise End_of_file (= System.IO.EndOfStreamException) if end of file reached. Reads bytes from the channel. Blocks if the bytes are not available. For text channels this only accepts UTF-16 bytes with an encoding less than 256. Raise End_of_file (= System.IO.EndOfStreamException) if end of file reached. Set the current position in the output channel, measured from the start of the channel. Set the binary mode to true or false. If the binary mode is changed from "true" to "false" then a StreamReader is created to read the binary stream. The StreamReader uses the default text encoding System.Text.Encoding.Default Set the binary mode. If the binary mode is changed from "true" to "false" then a StreamWriter is created to write the binary stream. The StreamWriter uses the default text encoding System.Text.Encoding.Default. n+1 (no overflow checking) The exception thrown by 'assert' failures. A future release of F# may map this exception to a corresponding .NET exception. Non-exhaustive match failures will raise Match failures A future release of F# may map this exception to a corresponding .NET exception. Link .NET IO with the out_channel/in_channel model Wrap a stream by creating a StreamReader for the stream and then wrapping is as an input channel. A text encoding must be given, e.g. System.Text.Encoding.UTF8 Link .NET IO with the out_channel/in_channel model Link .NET IO with the out_channel/in_channel model Access the underlying stream-based objects for the channel Link .NET IO with the out_channel/in_channel model Access the underlying stream-based objects for the channel Access the underlying stream-based objects for the channel Link .NET IO with the out_channel/in_channel model Wrap a stream by creating a StreamWriter for the stream and then wrapping is as an output channel. A text encoding must be given, e.g. System.Text.Encoding.UTF8 Link .NET IO with the out_channel/in_channel model Link .NET IO with the out_channel/in_channel model Access the underlying stream-based objects for the channel Access the underlying stream-based objects for the channel Access the underlying stream-based objects for the channel Access the underlying stream-based objects for the channel The type of simple immutable lists The type of None/Some options The type of pointers to mutable reference cells Absolute value of the given integer Structural comparison Decrement a mutable reference cell containing an integer Exit the current hardware isolated process, if security settings permit, otherwise raise an exception. Calls System.Environment.Exit. Throw a 'Failure' exception The "hash" function is a structural hash function. It is designed to return equal hash values for items that are equal according to the polymorphic equality function Pervasives.(=) (i.e. the standard "=" operator). Increment a mutable reference cell containing an integer Maximum based on structural comparison Minimum based on structural comparison Concatenate two lists. Assign to a mutable reference cell Concatenate two strings. The overlaoded operator '+' may also be used. Dereference a mutable reference cell Structural equality Structural greater-than Structural greater-than-or-equal Structural inequality Structural less-than comparison Structural less-than-or-equal comparison Throw an exception Create a mutable reference cell The exception thrown by failure and many other F# functions A future release of F# may map this exception to a corresponding .NET exception. Pervasives: Additional OCaml-compatible bindings Compatibility module to display data about exceptions. The array of command line options. Gives the command line arguments as returned by System.Environment.GetCommandLineArgs. Sets the current working directory for the process using System.IO.Directory.SetCurrentDirectory Run the command and return it's exit code. Warning: 'command' currently attempts to execute the string using the 'cmd.exe' shell processor. If it is not present on the system then the operation will fail. Use System.Diagnostics.Process directly to run commands in a portable way, which involves specifying the program to run and the arguments independently. Path of the current executable, using System.IO.Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory,System.AppDomain.CurrentDomain.FriendlyName) Returns true if a file currently exists, using System.IO.File.Exists(s). Returns the current working directory for the process using System.IO.Directory.GetCurrentDirectory Call System.Environment.GetEnvironmentVariable. Raise KeyNotFoundException if the variable is not defined. Deletes a file using System.IO.File.Delete. Rename a file on disk using System.IO.File.Move Time consumed by the main thread. (for approximate timings). Generally returns only the processor time used by the main thread of the application. The number of bits in the "int" type. Sys: Basic system operations (for ML compatibility) This module is only included to make it possible to cross-compile code with other ML compilers. It may be deprecated and/or removed in a future release. You may wish to use .NET functions directly instead. The identity permutation over any size Create a permutation by specifying the result of permuting [| 0 .. n-1 |]. For example, Permutation.of_array [| 1;2;0 |] specifies a permutation that rotates all elements right one place. Create a permutation by specifying (source,destination) index pairs. For example, Permutation(3,[ (0,2);(1,0); (2,1) ]) specifies a permutation that rotates all elements left one place. Not all elements need be given, e.g. Permutation(5,[ (1,2);(2,1) |]) specifies a permutation that swaps elements at indexes 1 and 2. Return a permutation that, when applied, maps index 0 to size-1, size-1 to 0 etc. Return a permutation that rotates right by the given distance. If the distance is negative then a left rotation results. Return a swaps the given two elements over any size Simple operations on signed bytes A synonym for Seq.zip Return an IEnumerable that when iterated yields the given item followed by the items in the given sequence Return true if the IEnumerable is not empty. A collection of operations for creating and using sets based on a particular comparison function. The 'Tag' type parameter is used to track information about the comparison function. For use when not opening the Set module, e.g. Set.t Build a collection of operations for creating and using maps based on a single consistent comparison function. This returns a record that contains the functions you use to create and manipulate maps all of which use this comparison function. The returned value is much like an ML module. Use MakeTagged if you want additional type safety that guarantees that two sets based on different comparison functions can never be combined in inconsistent ways. A functor to build a collection of operations for creating and using sets based on the given comparison function. This returns a record that contains the functions you use to create and manipulate maps of this kind. The returned value is much like an ML module. To use this function you need to define a new named class that implements IComparer and pass an instance of that class as the first argument. For example: type MyComparer() = interface IComparer<string> with member self.Compare(x,y) = ... let MyStringSetProvider = Set.MakeTagged(new MyComparer()) The elements of the set as a list. Compute the intersection of the two sets. Immutable sets implemented via binary trees Return a string with the first character converted to uppercase. Compare the given strings using ordinal comparison Return true is the given string contains the given character Return true is the given string contains the given character in the range specified by the given start index and the given length Return true is the given string contains the given character in the range from the given start index to the end of the string. Returns the character at the specified position in the string Return the first index of the given character in the string. Raise KeyNotFoundException if the string does not contain the given character. Return the first index of the given character in the range from the given start position to the end of the string. Raise KeyNotFoundException if the string does not contain the given character. Return a new string with all characters converted to lowercase Return a string of the given length containing repetitions of the given character Return s string of length 1 containing the given character Return true if the string contains the given character prior to the given index Return the index of the first occurrence of the given character from the end of the string proceeding backwards Return the index of the first occurrence of the given character starting from the given index proceeding backwards. Split the string using the given list of separator characters. Trimming is also performed at both ends of the string and any empty strings that result from the split are discarded. Return a substring of length 'length' starting index 'start'. Removes all occurrences of a set of characters specified in a list from the beginning and end of this instance. Return a string with the first character converted to lowercase. Return a string with all characters converted to uppercase. Compatibility module for string processing. Richer string operations are available via the member functions on strings and other functionality in the System.String type and the System.Text.RegularExpressions namespace. UInt32: ML-like operations on 32-bit System.UInt32 numbers. UInt64: basic operations on 64-bit System.UInt64 numbers. Wait for the result and commit it Record the result in the AsyncResultCell. Subsequent sets of the result are ignored. This can happen, e.g. for a race between a cancellation and a success. Create a new result cell A helper type to store a single result from an asynchronous computation and asynchronously access its result. When using .NET 4.0 you can often use Task<'T> instead of this type Return an asynchronous computation that, when run, either returns a value, raises an exception of cancels according to the value of the asynchronous result. Represents the reified result of an asynchronous computation Extensions to the F# Microsoft.FSharp.Control.Async module The type of floating-point matrices. See Microsoft.FSharp.Math The type of floating-point row vectors. See Microsoft.FSharp.Math The type of floating-point vectors. See Microsoft.FSharp.Math Constructs a complex number from both the real and imaginary part. Builds a matrix from a sequence of sequence of floats. Builds a (row) vector from a sequence of floats. Builds a (column) vector from a sequence of floats. Return the given rational number Return the negation of a rational number Return the difference of two rational numbers Return the product of two rational numbers This operator is for use from other .NET languages This operator is for use from other .NET languages This operator is for use from other .NET languages This operator is for use from other .NET languages This operator is for use from other .NET languages This operator is for use from other .NET languages Return the ratio of two rational numbers Return the sum of two rational numbers Get zero as a rational number Return the sign of a rational number; 0, +1 or -1 Get one as a rational number Return the numerator of the normalized rational number Return a boolean indicating if this rational number is strictly positive Return a boolean indicating if this rational number is strictly negative Return the denominator of the normalized rational number Return the result of converting the given rational number to an integer Return the result of converting the given rational number to a floating point number Return the result of converting the given rational number to a big integer Return the result of raising the given rational number to the given power Return the result of converting the string to a rational number Return the result of converting the given integer to a rational number Return the result of converting the given big integer to a rational number Return the absolute value of a rational number The type of arbitrary-sized rational numbers Unary negation of a complex number Subtract one complex number from another Multiply two complex numbers Multiply a scalar by a complex number Multiply a complex number by a scalar Complex division of two complex numbers Add two complex numbers The real part of a complex number The imaginary part of a complex number The complex number 0+0i The real part of a complex number The polar-coordinate phase of a complex number The complex number 0+1i The complex number 1+0i The polar-coordinate magnitude of a complex number The imaginary part of a complex number The conjugate of a complex number, i.e. x-yi Create a complex number using magnitude/phase polar coordinates Create a complex number x+ij using rectangular coordinates Computes the absolute value of a complex number: e.g. Abs x+iy = sqrt(x**2.0 + y**2.0.) Note: Complex.Abs(z) is the same as z.Magnitude The type of complex numbers stored as pairs of 64-bit floating point numbers in rectangular coordinates Get the item at the given position in the matrix Prefix '+' operator. A nop. Matrix negation. Point-wise subtraction of two matrices. An InvalidArgument exception will be raised if the dimensions do not match. Matrix multiplication. An InvalidArgument exception will be raised if the dimensions do not match. Matrix-vector multiplication. Multiply each element of a matrix by the given scalar value Multiply each element of a matrix by the given scalar value Pointwise matrix multiplication. An InvalidArgument exception will be raised if the dimensions do not match. Point-wise addition of two matrices. An InvalidArgument exception will be raised if the dimensions do not match. Get the transpose of the matrix. Get the number of rows in the matrix Get the number of columns in the matrix Returns sqrt(sum(norm(x)*(norm(x))) of all the elements of a matrix. The element type of the matrix must have an associated instance of INormFloat<'T> (see GlobalAssociations) ((else NotSupportedException)). Return the non-zero entries of a sparse or dense matrix Get the item at the given position in the matrix Indicates if the matrix uses the sparse representation. Indicates if the matrix uses the dense representation. Get the internal array of values for a sparse matrix. This property should only be used when interoperating with other matrix libraries. Get the internal array of row offsets for a sparse matrix. This property should only be used when interoperating with other matrix libraries. Get the internal array of column values for a sparse matrix. This property should only be used when interoperating with other matrix libraries. Get the internal array of values for a dense matrix. This property should only be used when interoperating with other matrix libraries. Retrieve the dictionary of numeric operations associated with the element type of this matrix. Accessing the property may raise an NotSupportedException if the element type doesn't support any numeric operations. The object returned may support additional numeric operations such as IFractional: this can be determined by a dynamic type test against the object returned. Get the number of (rows,columns) in the matrix Get the main diagonal of a matrix, as a vector Convert the matrix to a column vector Convert the matrix to a row vector Return a new array containing the elements of the given matrix Supports the slicing syntax 'A.[idx1..idx2,idx1..idx2] <- B' Select a range of rows from a matrix Select a row from a matrix Select a region from a matrix Permutes the rows of the matrix. Permutes the columns of the matrix. Supports the slicing syntax 'A.[idx1..idx2,idx1..idx2]' Return the nth diagonal of a matrix, as a vector. Diagonal 0 is the primary diagonal, positive diagonals are further to the upper-right of the matrix. Create a new matrix that is a copy of the given array Select a range of columns from a matrix Select a column from a matrix The type of matrices. The arithmetic operations on the element type are determined by inspection on the element type itself. Two representations are supported: sparse and dense. Get the transpose of the row vector. Get the underlying internal array of values for the vector. This property should only be used when interoperating with other matrix libraries. Return a new array containing a copy of the elements of the given vector Supports the slicing syntax 'rv.[idx1..idx2] <- rv2' Permute the elements of the row vector. Supports the slicing syntax 'rv.[idx1..idx2]' Create a new matrix that is a copy of the given array The type of row vectors. Gets an item from the the vector Return the input vector Negate a vector Subtract two vectors, pointwise Multiply each element of a vector by the given scalar value. Multiply a column vector and a row vector to produce a matrix Multiply a vector by a scalar Pointwise multiplication of two vectors. Add two vectors, pointwise Get the transpose of the vector. Gets the number of rows in the vector Computes the 2-norm of a vector: sqrt(x.Transpose*x). Gets the number of entries in the vector Gets an item from the the vector Get the underlying internal array of values for the vector. This property should only be used when interoperating with other matrix libraries. Gets the element operations for the element type of the vector, if any Return a new array containing a copy of the elements of the given vector Supports the slicing syntax 'v.[idx1..idx2] <- v2' Permute the elements of the vector. Supports the slicing syntax 'v.[idx1..idx2]' Create a new matrix that is a copy of the given array The type of column vectors. The arithmetic operations on the element type are determined by inspection on the element type itself The type of complex numbers The type of floating point matrices The type of floating point row vectors The type of floating point column vectors Add two complex numbers A complex of magnitude 1 and the given phase and , i.e. cis x = mkPolar 1.0 x The conjugate of a complex number, i.e. x-yi Cosine Complex division of two complex numbers exp(x) = e^x The imaginary part of a complex number log(x) is natural log (base e) The polar-coordinate magnitude of a complex number Create a complex number using magnitude/phase polar coordinates Multiply two complex numbers Multiply a complex number by a scalar Unary negation of a complex number The complex number 1+0i The complex number 0+1i The polar-coordinate phase of a complex number pi The real part of a complex number Sine Multiply a scalar by a complex number sqrt(x) and 0 <= phase(x) < pi Subtract one complex number from another Tagent The complex number 0+0i Attempt to determine a numeric association for the given type, i.e. a registered dictionary of numeric operations. The interface can be queried dynamically for additional functionality in the numerics hierarchy. Record an AppDomain-wide association between the given type and the given dictionary of numeric operations. Raise an error if an existing association already exists. Associations are a way of associating dictionaries of operations with given types at runtime. Associations are global to a .NET application domain. Once specified an association may not be deleted or modified. In this release the system of associations is simply limited to a registry of types that support dictionaries (i.e. interface objects) of numeric operations. The following types are pre-registered with associated numeric operations: float, int32, int64, bigint, float32, Complex, bignum. Other types must be registered explicitly by user code. Add two matrices (operator +) Create a new matrix that is a copy of the given array Point-wise maximum element of two matrices Point-wise minimum element of two matrices Pointwise exponential of a matrix. Create a matrix with all entries the given constant Dot product Check if a predicate holds for at least one element of a matrix Check if a predicate holds for at least one element of a matrix Fold the given function over all elements of a matrix Fold the given function down each column of a matrix Fold the given function along each row of a matrix Fold the given function along a particular column of a matrix Fold the given function down a particular row of a matrix Fold the given function over all elements of a matrix Check if a predicate holds for all elements of a matrix Check if a predicate holds for all elements of a matrix Get an element of a matrix Create a square matrix with the constant 1.0 lying on diagonal Create a dense representation matrix with the given entries. Create a square matrix with the given vector lying on diagonal Create a sparse representation matrix with the given entries. Not all operations are available for sparse matrices, and mutation is not permitted. If an operation on sparse matrices raises a runtime exception then consider converting to a dense matrix using to_dense. In-place addition mutates first matrix argument. In-place subtraction mutates first matrix argument. Map the given function over each element of the matrix, producing a new matrix Map the given indexed function over each element of the matrix, producing a new matrix sqrt(sum(x*x)) of all the elements of a matrix Multiply all the elements of the matrix Generate a new matrix of the same size as the input with random entries drawn from the range 0..aij. Random numbers are generated using a globally shared System.Random instance with the initial seed 99. Set an element of a matrix Sum all the elements of a matrix Ensure that a matrix uses dense representation. See init_sparse Sum of the diagonal elements of the matrix Transpose of a matrix. Use also m.Transpose Create a matrix with all entries zero Create a new matrix that is a copy of the given array Take the pointwise maximum of two matrices Take the pointwise maximum of two matrices Create a matrix containing the given value at every element. Sum of the point-wise multiple of the two matrices. The element type of the matrix must have an associated instance of INumeric<'T> (see GlobalAssociations) ((else NotSupportedException)). Get an element from a matrix. The indexes are given in row/column order. Create a square matrix with the one for the element type lying on diagonal The element type of the matrix must have an associated instance of INumeric<'T> (see GlobalAssociations) ((else NotSupportedException)). Create a matrix using the given function to compute the item at each index. Create a matrix containing the given vector along the diagonal. The element type of the matrix must have an associated instance of INumeric<'T> (see GlobalAssociations) ((else NotSupportedException)). Create a matrix using the given function to compute the item at each index. The element type of the matrix must have an associated instance of INumeric<'T> (see GlobalAssociations) ((else NotSupportedException)). The function is passed the dictionary of associated operations in addition to the index pair. Returns sqrt(sum(norm(x)*(norm(x))) of all the elements of a matrix. The element type of the matrix must have an associated instance of INormFloat<'T> (see GlobalAssociations) ((else NotSupportedException)). Create a matrix from the given (usually constant) data Create a matrix from the given (usually constant) data Create a 1x1 matrix containing the given value Set an element in a matrix. The indexes are given in row/column order. Return a new array containing the elements of the given matrix Return a new matrix which is the transpose of the input matrix Create a matrix containing the zero element at each index. The element type of the matrix must have an associated instance of INumeric<'T> (see GlobalAssociations) ((else NotSupportedException)). Operations to manipulate matrix types carrying arbitrary element types. The names and types of the operations match those in the containing module Math.Matrix. The numeric operations on the element type (add, zero etc.) are inferred from the type argument itself. That is, for some operations the element type of the matrix must have an associated instance of INumeric<'T> or some more specific numeric association (see GlobalAssociations) ((else NotSupportedException)). Operations to manipulate floating point matrices. The submodule Matrix.Generic contains a matching set of operations to manipulate matrix types carrying arbitrary element types. Faraday constant Newtonian constant of gravitation Conductance quantum 2e^2/h Avogadro constant Magnetic flux quantum h/2e Molar gas constant Rydberg constant Fine-structure constant speed of light in vacuum Elementary charge Electron volt electric constant = 1/(mu0 c^2) Planck constant Dirac constant, also known as the reduced Planck constant = h/2pi Boltzmann constant R/N_A Electron mass Proton mass magnetic constant Stefan-Boltzmann constant Unified atomic mass unit Fundamental physical constants, with units-of-measure Create by constant initialization Get an element of a column vector Create by comprehension Get the dimensions (number of rows) of a column rowvec. Create a vector from an array of double precision floats Create a vector from a list of numbers Set an element of a column rowvec Return a new array containing a copy of the elements of the given vector Return a vector of the given length where every entry is zero. Create by constant initialization Get an element from a column vector. Create by comprehension Get the number of rows in a column vector. Create a row vector from an array of elements Create a row vector from a list of elements Create a row vector from a sequence of elements Set an element in a column vector. Return a new array containing a copy of the elements of the given vector Transpose the row vector Return a vector of the given length where every entry is zero. Operations to manipulate row vectors types carrying arbitrary element types. Operations to manipulate floating point row vectors. These are included for completeness and are nearly always transposed to column vectors. ampere, SI unit of electric current becquerel, SI unit of activity referred to a radionuclide coulomb, SI unit of electric charge, amount of electricity farad, SI unit of capacitance gray, SI unit of absorbed dose henry, SI unit of inductance hertz, SI unit of frequency joule, SI unit of energy, work, amount of heat kelvin, SI unit of thermodynamic temperature newton, SI unit of force pascal, SI unit of pressure, stress siemens, SI unit of electric conductance sievert, SI unit of does equivalent tesla, SI unit of magnetic flux density volt, SI unit of electric potential difference, electromotive force watt, SI unit of power, radiant flux weber, SI unit of magnetic flux candela, SI unit of luminous intensity katal, SI unit of catalytic activity kilogram, SI unit of mass lumen, SI unit of luminous flux lux, SI unit of illuminance metre (or meter), SI unit of length mole, SI unit of amount of substance ohm, SI unit of electric resistance second, SI unit of time The International System of Units (SI) Pointwise exponential of a vector. Generate a vector of the given length where each entry contains the given value Dot product Get an element of a column vector Get the dimensions (number of rows) of a column vector. Identical to nrows Computes the 2-norm of a vector: sqrt(x.Transpose*x). Create a vector from an array of double precision floats Create a vector from a list of numbers Create a 1-element vector Multiply all the elements of the matrix Create a vector that represents a integral mesh over the given range e.g. range 1 5 = vector [ 1.;2.;3.;4.;5. ] Create a vector that represents a mesh over the given range e.g. rangef (-1.0) 0.5 1.0 = vector [ -1.0; -0.5; 0.0; 0.5; 1.0] Set an element of a column vector Sum all the elements of a vector Return a new array containing a copy of the elements of the given vector Transpose of a matrix. Use also m.Transpose Return a vector of the given length where every entry is zero. Add two vectors (operator +) Take the pointwise maximum of two vectors Take the pointwise minimum of two vectors Point-wise multiplication of two vectors (operator .*) Generate a vector of the given length where each entry contains the given value Dot product Get an element of a column vector Creation: general Creation: useful when the element type has associated operations. Get the dimensions (number of rows) of a column vector. Identical to nrows Negation of the vector (each element is negated) (unary operator -) Computes the 2-norm of a vector: sqrt(x.Transpose*x). Create a vector from an array of elements Create a vector from a list of numbers Create a 1-element vector Create a vector from a sequence of numbers Multiply all the elements of the matrix Pointwise multiplication of a matrix by a scalar Set an element of a column vector Subtract one vector from another (operator -) Sum all the elements of a vector Return a new array containing a copy of the elements of the given vector Transpose of a matrix. Use also m.Transpose Return a vector of the given length where every entry is zero. Operations to manipulate column vectors carrying arbitrary element types. Operations to manipulate floating point column vectors. The submodule VectorOps.Generic contains a matching set of operations to manipulate column vectors carrying arbitrary element types. See NativeArray2 WARNING: use of this function may lead to unverifiable or invalid code View a FortranMatrix as a CMatrix. Doesn't actually allocate a new matirx - just gives a different label to the same bits, and swaps the row/column count information associated with the bits. WARNING: use of this function may lead to unverifiable or invalid code This type wraps a pointer to a blob of unmanaged memory assumed to contain a Fortran-style column major two-dimensional matrix of items compatible with the (presumably blittable) type 'T. The blob of memory must be allocated and managed externally, e.g. by a computation routine written in C. All operations on this type are marked inlined because the code used to implement the operations is not verifiable. Any code that uses these operations will be unverifiable and may cause memory corruption if not used with extreme care. WARNING: use of this function may lead to unverifiable or invalid code Pointer to the C-style row major two-dimensional array Number of rows of the native array Number of columns of the native array View a CMatrix as a FortranMatrix. Doesn't actually allocate a new matirx - just gives a different label to the same bits, and swaps the row/column count information associated with the bits. WARNING: use of this function may lead to unverifiable or invalid code Creates a C-style row major two-dimensional array from a native pointer, the number of rows and the number of columns. Nothing is actually copied. This type wraps a pointer to a blob of unmanaged memory assumed to contain a C-style row major two-dimensional matrix of items compatible with the (presumably blittable) type 'T. The blob of memory must be allocated and managed externally, e.g. by a computation routine written in C. All operations on this type are marked inlined because the code used to implement the operations is not verifiable. Any code that uses these operations will be unverifiable and may cause memory corruption if not used with extreme care. WARNING: use of this function may lead to unverifiable or invalid code Pointer to the C-style one-dimensional array Length of the C-style one-dimensional array WARNING: use of this function may lead to unverifiable or invalid code Creates a C-style one dimensional array from a native pointer and the length of the array Nothing is actually copied. This type wraps a pointer to a blob of unmanaged memory assumed to contain a C-style one-dimensional array of items compatible with the (presumably blittable) type 'T. The blob of memory must be allocated and managed externally, e.g. by a computation routine written in C. All operations on this type are marked inlined because the code used to implement the operations is not verifiable. Any code that uses these operations will be unverifiable and may cause memory corruption if not used with extreme care. For native interop. Pin the given object Represents a pinned handle to a structure with an underlying 2D array, i.e. an underlying NativeArray2. Used when interfacing with native code math libraries such as LAPACK. For native interop. Pin the given object Represents a pinned handle to a structure with an underlying 1D array, i.e. an underlying NativeArray. Used when interfacing with native code math libraries such as LAPACK. Pin the given ref for the duration of a single call to the given function. A native pointer to the contents of the ref is passed to the given function. Cleanup the GCHandle associated with the pin when the function completes, even if an exception is raised. This function should only be used if 'T is a simple blittable type such as "int" that does not contain any further heap references. WARNING: use of this function may lead to unverifiable or invalid code Interpret tables for an ascii lexer generated by fslex. Interpret tables for an ascii lexer generated by fslex, processing input asynchronously The type of tables for an ascii lexer generated by fslex. The start position for the lexeme True if the refill of the buffer ever failed , or if explicitly set to true. The end position for the lexeme The start position for the lexeme The length of the matched string The matched string True if the refill of the buffer ever failed , or if explicitly set to true. The end position for the lexeme Dynamically typed, non-lexically scoped parameter table Fast helper to turn the matched characters into a string, avoiding an intermediate array Fetch a particular character in the matched string Adjust the start position associated with the lexbuf Remove all input, though don't discard the current lexeme Return absolute offset of the start of the line marked by the position The line number in the input stream, assuming fresh positions have been updated using AsNewLinePos() and by modifying the EndPos property of the LexBuffer. The file name associated with the input stream. Get an arbitrary position, with the empty string as filename, and Return the column number marked by the position, i.e. the difference between the AbsoluteOffset and the StartOfLineAbsoluteOffset The character number in the input stream Gives a position shifted by specified number of characters Get a position corresponding to the first line (line number 1) in a given file Given a position at the start of a token of length n, return a position just beyond the end of the token Position information stored for lexing tokens Interpret tables for a unicode lexer generated by fslex. Interpret tables for a unicode lexer generated by fslex, processing input asynchronously The type of tables for an unicode lexer generated by fslex. Parsers generated by FsPars provide information from within parser actions. This is accessed via the functions available on the local variable parseState within parser actions Tables generated by fsyacc A record of options to control structural formatting. For F# Interactive properties matching those of this value can be accessed via the 'fsi' value. Floating Point format given in the same format accepted by System.Double.ToString, e.g. f6 or g15. If ShowProperties is set the printing process will evaluate properties of the values being displayed. This may cause additional computation. The ShowIEnumerable is set the printing process will force the evalution of IEnumerable objects to a small, finite depth, as determined by the printing parameters. This may lead to additional computation being performed during printing. From F# Interactive the default settings can be adjusted using, for example,
       open Microsoft.FSharp.Compiler.Interactive.Settings;;
       setPrintWidth 120;;
     
    The maximum number of rows for which to generate layout for table-like structures. -1 if no maximum. The maximum number of elements for which to generate layout for list-like structures, or columns in table-like structures. -1 if no maximum. Return to the layout-generation environment to layout any otherwise uninterpreted object Data representing structured layouts of terms. Convert any value to a string using a standard formatter Data is typically formatted in a structured format, e.g. lists are formatted using the "[1;2]" notation. The details of the format are not specified and may change from version to version and according to the flags given to the F# compiler. The format is intended to be human-readable, not machine readable. If alternative generic formats are required you should develop your own formatter, using the code in the implementation of this file as a starting point. Data from other .NET languages is formatted using a virtual call to Object.ToString() on the boxed version of the input. Convert any value to a layout using the given formatting options. The layout can then be processed using formatting display engines such as those in the LayoutOps module. any_to_string and output_any are built using any_to_layout with default format options. Ouput any value to a channel using the same set of formatting rules as any_to_string Layout two vertically. Layout list vertically. Wrap braces around layout. Wrap round brackets around Layout. Join layouts into a comma separated list. The empty layout Is it the empty layout? An string which is left parenthesis (no space on the right). Layout like an F# list. An uninterpreted leaf, to be interpreted into a string by the layout engine. This allows leaf layouts for numbers, strings and other atoms to be customized according to culture. Join broken with ident=0 Join broken with ident=1 Join broken with ident=2 Join, unbreakable. Join, possible break with indent=1 Join, possible break with indent=2 Join, possible break with indent=0 Layout like an F# option. An string which is right parenthesis (no space on it's left). Join layouts into a semi-colon separated list. An string which requires no spaces either side. Join layouts into a list separated using the given Layout. Join layouts into a space separated list. Wrap square brackets around layout. See tagL Form tuple of layouts. For limitting layout of list-like sequences (lists,arrays,etc). unfold a list of items using (project and z) making layout list via itemL. If reach maxLength (before exhausting) then truncate. An string leaf A layout is a sequence of strings which have been joined together. The strings are classified as words, separators and left and right parenthesis. This classification determines where spaces are inserted. A joint is either unbreakable, breakable or broken. If a joint is broken the RHS layout occurs on the next line with optional indentation. A layout can be squashed to for given width which forces breaks as required.
    ================================================ FILE: ironclad-apps/tools/scripts/.gitignore ================================================ *.pyc *.obj ================================================ FILE: ironclad-apps/tools/scripts/binary_to_c_symbols.py ================================================ #!/usr/bin/python import sys binaryfile = sys.argv[1] symbolname = sys.argv[2] hfile = sys.argv[3] cfile = sys.argv[4] ifp = open(binaryfile, "rb") binaryBytes = ifp.read() ifp.close() ofp = open(hfile, "w") ofp.write("#pragma once\n extern char %s[%d];\n" %(symbolname, len(binaryBytes))) ofp.close() ofp = open(cfile, "w") ofp.write("char %s[%d] = {\n" %(symbolname, len(binaryBytes))) for b in binaryBytes: ofp.write("0x%02x, \n" % ord(b)) ofp.write("};\n") ofp.close() ================================================ FILE: ironclad-apps/tools/scripts/build-standalone-asm.py ================================================ #!/usr/bin/python import sys import re import os # Remove in and out instructions def banned(line): tline = line.strip() result = False # Don't wait on the serial port result = result or (tline.startswith("je") and "waitForSerialPort" in tline) # Ban VgaDebugStore lines (very brittle :( ) result = result or ("edx + 753664" in tline) # Ban IO instructions result = result or (tline.startswith("in ") or tline.startswith("out ")) return result def munge(filename): establish_locality_in_progress = False; with open(filename) as f: for line in f: line = line.rstrip() # Tack an extern declaration on to the header if line == ".model flat": print line print 'EXTERN ?c_debug_print@@YAXHH@Z : proc' print 'EXTERN ?fixup_stack@@YAXXZ : proc' print 'EXTERN ?c_exit@@YAXXZ : proc' continue # Neuter Proc_establish_locality (TPM initialization) if line.startswith("_?Proc_establish__locality proc"): establish_locality_in_progress = True print line print "\tret" if line.startswith("_?Proc_establish__locality endp"): establish_locality_in_progress = False # Replace the jump that conditions on the contents of eax with # an unconditional jump. But first, fixup Windows notion of where our stack will be if 'je AppEntryPoint$__L1' in line: print '\tcall ?fixup_stack@@YAXXZ' print '\tjmp AppEntryPoint$__L1' continue # Replace calls to TPM-based random with calls to non-TPM random if line.strip() == 'call _?Proc_get__random': print '\tcall _?Proc_insecure__get__random' continue # Replace calls to Dafny's debug print with the C version if line.strip() == 'call _?Proc_debug__print': print '\tcall ?c_debug_print@@YAXHH@Z' continue # Replace the infinite loop with an exit if line.strip() == 'jmp AppEntryPoint$myInfLoop': print '\tcall ?c_exit@@YAXXZ' continue if (establish_locality_in_progress): pass elif banned(line): pass else: print line # Extra memory spacing #Spacer SEGMENT DWORD MEMORY FLAT READ WRITE #REPEAT 100000;8388608 #QWORD ? #ENDM #REPEAT 100000;8388608 #QWORD ? #ENDM #REPEAT 100000;8388608 #QWORD ? #ENDM #REPEAT 100000;8388608 #QWORD ? #ENDM #Spacer ENDS # try: arg = sys.argv[1] except: sys.stderr.write("Usage: %s \n" % sys.argv[0]) sys.exit(-1) munge(arg) ================================================ FILE: ironclad-apps/tools/scripts/build-standalone-init.sh ================================================ #!/bin/bash tar xvjf zero-obj.bz2 cp zero.obj zero2.obj ================================================ FILE: ironclad-apps/tools/scripts/zero.asm ================================================ .686p .model flat SoloSpacer SEGMENT DWORD MEMORY FLAT READ WRITE REPEAT 8388608 QWORD ? ENDM SoloSpacer ENDS end ================================================ FILE: ironclad-apps/tools/standalone/.gitignore ================================================ Debug/ DbgExec/ *sdf *.user *.suo ================================================ FILE: ironclad-apps/tools/standalone/StandAloneSupport.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0.30110.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "StandAloneSupport", "StandAloneSupport.vcxproj", "{D5413EFA-3A5F-4DD7-9AA3-C42871DD40CE}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution DbgExec|Win32 = DbgExec|Win32 Debug|Win32 = Debug|Win32 Release|Win32 = Release|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {D5413EFA-3A5F-4DD7-9AA3-C42871DD40CE}.DbgExec|Win32.ActiveCfg = DbgExec|Win32 {D5413EFA-3A5F-4DD7-9AA3-C42871DD40CE}.DbgExec|Win32.Build.0 = DbgExec|Win32 {D5413EFA-3A5F-4DD7-9AA3-C42871DD40CE}.Debug|Win32.ActiveCfg = Debug|Win32 {D5413EFA-3A5F-4DD7-9AA3-C42871DD40CE}.Debug|Win32.Build.0 = Debug|Win32 {D5413EFA-3A5F-4DD7-9AA3-C42871DD40CE}.Release|Win32.ActiveCfg = Release|Win32 {D5413EFA-3A5F-4DD7-9AA3-C42871DD40CE}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: ironclad-apps/tools/standalone/StandAloneSupport.vcxproj ================================================  DbgExec Win32 Debug Win32 Release Win32 {D5413EFA-3A5F-4DD7-9AA3-C42871DD40CE} Win32Proj StandAloneSupport StaticLibrary true v120 Unicode Application true v120 Unicode Application false v120 true Unicode true true false Level3 Disabled WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) Console true Level3 Disabled WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) Console true Level3 MaxSpeed true true WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) Console true true true ================================================ FILE: ironclad-apps/tools/standalone/StandAloneSupport.vcxproj.filters ================================================  {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;hm;inl;inc;xsd {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms Source Files ================================================ FILE: ironclad-apps/tools/standalone/support.cpp ================================================ #include #include #include #include #include #include #include #include #include using namespace std; void hello() { printf("Hello world\n"); } void c_debug_print(int x, int y) { printf("%#2x, %#8x\n", x, y); } void c_exit() { exit(0); } void fixup_stack() { unsigned int* teb = (unsigned int*)NtCurrentTeb(); NT_TIB* tib = (NT_TIB*)teb; tib->StackBase = (void*)0xffffffff; tib->StackLimit = (void*)0; // //*(teb + 4) = 0x44F000; //*(teb + 8) = 0x44F400; // ////*(teb + 4) = 0x44F400; ////*(teb + 8) = 0x44F000; } #define LOOP_COUNT (1<<25) int total = 0; void function5(int x) { for (int i = 0; i < LOOP_COUNT; i++) { total += i; } } void function4(int x) { for (int i = 0; i < LOOP_COUNT; i++) { total += i; if (i % 100000 == 0) { function5(x); } } } void function3(int x) { for (int i = 0; i < LOOP_COUNT; i++) { total += i; if (i % 100000 == 0) { function4(x); } } } void function2(int x) { for (int i = 0; i < LOOP_COUNT; i++) { total += i; if (i % 100000 == 0) { function3(x); } } } void function1(int x) { for (int i = 0; i < LOOP_COUNT; i++) { total += i; if (i % 100000 == 0) { function2(x); } } } void main() { hello(); function1(24); hello(); } ================================================ FILE: ironfleet/.gitignore ================================================ codeplex obj/ obj-*/ bin-*/ bin/ bin_tools/ obj_tools/ src/Clients/*/bin/ *-disabled nucache/ nuobj/ nutemp/ nubuild.config nubuild.cloud-credentials nubuild.log nubuild.progress Experiments/ *.csproj.user /nubuild.progress *.log *.pdb *.pyc *.aux StyleCop.Cache tmp/ *.swp *.dlg flycheck_* *.vim nohup.out *.vdfy *.tmp .sconsign.dblite *.suo *~ port* certs/ ================================================ FILE: ironfleet/CODE.md ================================================ # Code Layout Here is a brief overview of the files of interest in this repository. One central convention is that all trusted specification files end in `.s.dfy`. Everything else should be a `.i.dfy` file and will be verified for correctness. - `SConstruct` SCons build file for verifying and compiling everything - `src` + `IronLockServer` C# solution and project files for building the lock server. + `IronRSLKVServer` C# solution and project files for building a key-value store replica that uses IronRSL to coordinate with other replicas. This directory includes the file `Service.cs` defining the key-value service. + `IronRSLKVClient` Unverified C# client for the key-value service replicated by IronRSL. + `IronRSLCounterServer` C# solution and project files for building a counter service replica that uses IronRSL to coordinate with other replicas. This directory includes the file `Service.cs` defining the counter service. + `IronRSLCounterClient` Unverified C# client for the counter service replicated by IronRSL. + `IronSHTServer` C# solution and project files for building the IronSHT (sharded hash table) server. + `IronSHTClient` Unverified C# client for IronSHT. + `Dafny` - `Libraries` Basic library support for various tasks, particularly for dealing with non-linear operations that Z3 struggles with. These libraries were inherited from the [IroncladApps](http://research.microsoft.com/apps/pubs/default.aspx?id=230123) project. - `Distributed` The core IronFleet code + `Common` Code shared across our services for various core taskes - `Collections` Useful definitions, lemmas, and methods for dealing with Sets, Maps, and Sequences. - `Framework` This is the trusted framework that forms the core portion of each service's specification. Each service further adds service-specific specifications in `src/Dafny/Distributed/Services`. - `Logic` Our encoding of TLA in Dafny. - `Native` Our trusted interface to C# for networking, time, command-line arguments and other functionality that Dafny does not expose. + `Impl` - `Common` Useful libraries shared across services. Includes command-line parsing, generic marshalling and parsing, end-point identities, and a UDP client. - `RSL` The core implementation of IronRSL. These files define concrete versions of the types specified by the protocol. For each role, e.g., the Acceptor, we have a file `AcceptorState.i.dfy` which defines the basic datatype and predicates on it, and a file `AcceptorModel.i.dfy` which defines the actions that can be performed on the data type. ReplicaModel is the top-level role that combines all of the others, and ReplicaImpl interfaces with the external world to send and receive packets. ReplicaModel and ReplicaImpl are split into multiple files to increase the file-level parallelism of our build tool. - `SHT` The core implementation of IronSHT (sharded hash table). - `LiveSHT` SHT's scheduler and functionality for sending and receiving packets. - `Lock` The core implementation for IronLock. This includes the command line parser, the message definitions, parsing and marshalling, a simple scheduler, etc. + `Protocol` - `Common` Common files shared by all of our protocols - `RSL` Defines the protocol layer of our RSL system + `RefinementProof` Proof of safety, in the form of a proof that the implementation refines the specification given that it refines the protocol. + `LivenessProof` Proof of liveness, specifically that if a client submits a request repeatedly he eventually receives a reply. It requires various assumptions codified in Assumptions.i.dfy, e.g., a quorum of replicas is live and the network eventually delivers packets among the client and the live quorum in bounded time. The ultimate liveness proof, in LivenessProof.i.dfy, is a proof by contradiction: if those assumptions hold and the client never gets a reply, then `false`. - `SHT` Defines the protocol layer of our SHT system + `RefinementProof` Proof of safety, in the form of a proof that the implementation refines the specification given that it refines the protocol. - `LiveSHT` Defines a small additional layer that adds a scheduler to SHT and maps the low level Environment to SHT's notion of a Network. + `RefinementProof` Proof that LiveSHT is a refinement of SHT + `LivenessProof` Proof of liveness of the reliable-delivery layer, specifically that if a message is submitted to the reliable-delivery component then its intended recipient eventually receives it and queues it for processing. This proof requires various assumptions codified in `Assumptions.i.dfy`, e.g., a message sent infinitely often is eventually delivered. The ultimate liveness proof is in `LivenessProof.i.dfy`. - `Lock` Defines the protocol layer of our Lock service + `RefinementProof` Proof that the implementation refines the specification. The proof uses two intermediate layers of states beyond the implementation and the specification. The `LS_State` layer represents the protocol states, while the `GLS_State` layer augments each protocol state with a history variable, which is used to prove refinement to the high-level specification. + `Services` These directories tie the implementation, protocol, and specifications together. Each service has a directory with `.s.dfy` files that define the service-specific specifications (e.g. that RSL should be a state machine or that SHT should be a hash table). The file `Main.i.dfy` in each directory instantiates the abstract host with the concrete implementation and supplies a proof that refinement holds from the implementation all the way up to the abstract specification. See `src/Dafny/Distributed/Common/Framework` for the guarantees this provides. ================================================ FILE: ironfleet/CONTRIBUTING.md ================================================ # Legal To contribute, you will need to complete a Contributor License Agreement (CLA). Briefly, this agreement testifies that you are granting us permission to use the submitted change according to the terms of the project's license, and that the work being submitted is under appropriate copyright. Please submit a Contributor License Agreement (CLA) before submitting a pull request. You may visit https://cla.microsoft.com to sign digitally. Alternatively, download the agreement [Microsoft Contribution License Agreement.docx](https://www.codeplex.com/Download?ProjectName=typescript&DownloadId=822190) or [Microsoft Contribution License Agreement.pdf](https://www.codeplex.com/Download?ProjectName=typescript&DownloadId=921298)), sign, scan, and email it back to [cla@microsoft.com](mailto:cla@microsoft.com). Be sure to include your github user name along with the agreement. Once we have received the signed CLA, we'll review the request. # Code of Conduct This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. # Housekeeping Your pull request should: - Include a description of what your change intends to do - Be a child commit of a reasonably recent commit in the master branch - Requests need not be a single commit, but should be a linear sequence of commits (i.e. no merge commits in your private repository). - It is desirable, but not necessary, for the full BatchDafny verification to succeed at each commit (see the [README](./README.md) for instructions on running BatchDafny), but it must succeed for the final commit. - Have clear commit messages e.g. "Refactor feature" or "Fix issue" - Follow the code conventions described in the [STYLE](./STYLE.md) guidelines ================================================ FILE: ironfleet/IRONROOT.sentinel ================================================ This file marks the top of the Ironclad source repository. Its presence is used by the NuBuild system to orient itself to the src/, nuobj/, and nucache/ directories. ================================================ FILE: ironfleet/LICENSE ================================================ Ironclad 1.0 Copyright (c) Microsoft Corporation All rights reserved. MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ""Software""), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: ironfleet/README.md ================================================ # About This directory contains experimental verified IronFleet code, as described in: > [_IronFleet: Proving Practical Distributed Systems Correct_](https://www.microsoft.com/en-us/research/publication/ironfleet-proving-practical-distributed-systems-correct/) > Chris Hawblitzel, Jon Howell, Manos Kapritsos, Jacob R. Lorch, > Bryan Parno, Michael L. Roberts, Srinath Setty, and Brian Zill. > In Proceedings of the ACM Symposium on Operating Systems Principles (SOSP). > October 5, 2015. > [_IronFleet: Proving Safety and Liveness of Practical Distributed Systems_](https://www.microsoft.com/en-us/research/publication/ironfleet-proving-safety-liveness-practical-distributed-systems/) > Chris Hawblitzel, Jon Howell, Manos Kapritsos, Jacob R. Lorch, > Bryan Parno, Michael L. Roberts, Srinath Setty, and Brian Zill. > Communications of the ACM (CACM) 60(7), July 2017. As a brief summary, we are motivated by the fact that distributed systems are notorious for harboring subtle bugs. Verification can, in principle, eliminate these bugs a priori, but verification has historically been difficult to apply at full-program scale, much less distributed-system scale. We developed a methodology for building practical and provably correct distributed systems based on a unique blend of TLA-style state-machine refinement and Hoare-logic verification. In this code release, we demonstrate the methodology on a complex implementation of a Paxos-based replicated state machine library (IronRSL) and a lease-based sharded key-value store (IronKV). We prove that each obeys a concise safety specification, as well as desirable liveness requirements. Each implementation achieves performance competitive with a reference system. With our methodology and lessons learned, we aim to raise the standard for distributed systems from "tested" to "correct." See https://research.microsoft.com/ironclad for more details. # License IronFleet is licensed under the MIT license included in the [LICENSE](./LICENSE) file. # Setup To use Ironfleet, you'll need the following tools: * .NET 6.0 SDK (available at `https://dotnet.microsoft.com/download`) * Dafny v3.4.0 (verifier, available at `https://github.com/dafny-lang/dafny`) * python 2 or 3 (needed for running scons) * scons (installable by running `pip install scons`) The instructions below have been tested using Windows 10 and 11, macOS Catalina, and Ubuntu 20.04. They should also work for other platforms Dafny and .NET support, such as Ubuntu 16.04 and Debian. On Windows, they work with at least the following shells: Command Prompt, Windows PowerShell, Cygwin mintty, and Ubuntu 20.04 on Windows Subsystem for Linux. # Verification and Compilation To build and verify the contents of this repo, use: `scons --dafny-path=/path/to/directory/with/dafny/` To use `` threads in parallel, add `-j ` to this command. Expect this to take up to several hours, depending on your machine and how many cores you have available. Also note that the prover's time limits are based on wall clock time, so if you run the verification on a slow machine, you may see a few timeouts not present in our build. If that happens, try using a longer time limit for each verification; for example, using `--time-limit=120` makes the time limit 120 seconds instead of the default 60 seconds. Running scons will produce the following executables: ``` bin/CreateIronServiceCerts.dll bin/TestIoFramework.dll bin/IronLockServer.dll bin/IronRSLCounterServer.dll bin/IronRSLCounterClient.dll bin/IronRSLKVServer.dll bin/IronRSLKVClient.dll bin/IronSHTServer.dll bin/IronSHTClient.dll ``` To produce these executables without performing verification, use `--no-verify`. # Running ## Creating certificates Ironfleet servers identify themselves using certificates. So, before running any Ironfleet services, you need to generate certificates for the service by running `CreateIronServiceCerts`. On the command line you'll specify the name and type of the service and, for each server, its public address and port. Each such address can be a hostname like `www.myservice.com` or an IP address like `127.0.0.1` or `2001:db8:3333:4444:CCCC:DDDD:EEEE:FFFF`. For instance, you can run the following command: ``` dotnet bin/CreateIronServiceCerts.dll outputdir=certs name=MyService type=TestService addr1=server1.com port1=6000 addr2=server2.com port2=7000 ``` This will create three files in the directory `certs`. Two of these files, `MyService.TestService.server1.private.txt` and `MyService.TestService.server2.private.txt`, are the private key files for the two servers. The third, `MyService.TestService.service.txt`, contains the service identity, including the public keys of the two servers. You'll distribute the service file to all servers and all clients. But, you should only copy a private key file to the server corresponding to that private key, and after copying it you should delete your local copy. So, in this example, you'd copy `MyService.TestService.server1.private.txt` only to server1.com. ## IronLock IronLock is the simplest of the protocols we've verified, so it may be a good starting point. It consists of N processes passing around a lock. To run it, make sure your firewall isn't blocking the TCP ports you use. Here's an example configuration with three processes: Create the service with: ``` dotnet bin/CreateIronServiceCerts.dll outputdir=certs name=MyLock type=IronLock addr1=127.0.0.1 port1=4001 addr2=127.0.0.1 port2=4002 addr3=127.0.0.1 port3=4003 ``` Run the service by executing the following three commands in three different windows: ``` dotnet bin/IronLockServer.dll certs/MyLock.IronLock.service.txt certs/MyLock.IronLock.server2.private.txt dotnet bin/IronLockServer.dll certs/MyLock.IronLock.service.txt certs/MyLock.IronLock.server3.private.txt dotnet bin/IronLockServer.dll certs/MyLock.IronLock.service.txt certs/MyLock.IronLock.server1.private.txt ``` It's important that you start the "first" process last (as in the above example), as it initially holds the lock and will immediately start passing it around. As this is a toy example, message retransmission isn't implemented. Therefore, if the other processes aren't running by the time the first process sends a grant message, the message will be lost and the protocol will stop. If started properly, the processes will pass the lock among them as fast as they can, printing a message everytime they accept or grant the lock. ## IronRSL - Counter To run the counter service replicated with IronRSL, you should ideally use four different machines, but in a pinch you can use four separate windows on the same machine. The client has reasonable defaults that you can override with key=value command-line arguments. Run the client with no arguments to get detailed usage information. Make sure your firewall isn't blocking the TCP ports you use. To test the IronRSL counter on a single machine, you can do the following. First, create certificates with: ``` dotnet bin/CreateIronServiceCerts.dll outputdir=certs name=MyCounter type=IronRSLCounter addr1=127.0.0.1 port1=4001 addr2=127.0.0.1 port2=4002 addr3=127.0.0.1 port3=4003 ``` Then, run each of the following three server commands, each in a different window. ``` dotnet bin/IronRSLCounterServer.dll certs/MyCounter.IronRSLCounter.service.txt certs/MyCounter.IronRSLCounter.server1.private.txt dotnet bin/IronRSLCounterServer.dll certs/MyCounter.IronRSLCounter.service.txt certs/MyCounter.IronRSLCounter.server2.private.txt dotnet bin/IronRSLCounterServer.dll certs/MyCounter.IronRSLCounter.service.txt certs/MyCounter.IronRSLCounter.server3.private.txt ``` Finally, run this client command in yet another window: ``` dotnet bin/IronRSLCounterClient.dll certs/MyCounter.IronRSLCounter.service.txt nthreads=10 duration=30 print=true ``` If you don't want the client to print the counter values it receives in replies, remove `print=true` from the client command. In that case, its output will primarily consist of reports of the form `#req `. You can run the client as many times as you want. But, you can only run each server once since we haven't implemented crash recovery. To prevent you from accidentally running a server multiple times, the server program deletes its private key file right after reading it. Fortunately, `IronRSLCounter` can deal with the failure of fewer than half its servers. But, if half of them or more fail, you'll have to create a new service. That is, you'll have to start over by running `CreateIronServiceCerts`, and that new service's counter will start at 0. Note that the servers use non-blocking network receives, so they may be slow to respond to Ctrl-C. ## IronRSL - Key-Value Store To run the key-value service replicated with IronRSL, you should ideally use four different machines, but in a pinch you can use four separate windows on the same machine. The client has reasonable defaults that you can override with key=value command-line arguments. Run the client with no arguments to get detailed usage information. Make sure your firewall isn't blocking the TCP ports you use. To test the IronRSL key-value store on a single machine, you can do the following. First, create certificates with: ``` dotnet bin/CreateIronServiceCerts.dll outputdir=certs name=MyKV type=IronRSLKV addr1=127.0.0.1 port1=4001 addr2=127.0.0.1 port2=4002 addr3=127.0.0.1 port3=4003 ``` Then, run each of the following three server commands, each in a different window: ``` dotnet bin/IronRSLKVServer.dll certs/MyKV.IronRSLKV.service.txt certs/MyKV.IronRSLKV.server1.private.txt dotnet bin/IronRSLKVServer.dll certs/MyKV.IronRSLKV.service.txt certs/MyKV.IronRSLKV.server2.private.txt dotnet bin/IronRSLKVServer.dll certs/MyKV.IronRSLKV.service.txt certs/MyKV.IronRSLKV.server3.private.txt ``` Finally, run this client command in yet another window: ``` dotnet bin/IronRSLKVClient.dll certs/MyKV.IronRSLKV.service.txt nthreads=10 duration=30 setfraction=0.25 deletefraction=0.05 print=true ``` If you don't want the client to print the requests it sends and the replies it receives, remove `print=true` from the client command. In that case, its output will primarily consist of reports of the form `#req `. You can run the client as many times as you want. But, you can only run each server once since we haven't implemented crash recovery. To prevent you from accidentally running a server multiple times, the server program deletes its private key file right after reading it. Fortunately, `IronRSLKV` can deal with the failure of fewer than half its servers. But, if half of them or more fail, you'll have to create a new service. That is, you'll have to start over by running `CreateIronServiceCerts`, and that new service's key-value store will start out empty. Note that the servers use non-blocking network receives, so they may be slow to respond to Ctrl-C. ## IronSHT To run IronSHT (our sharded hash table), you should ideally use multiple different machines, but in a pinch you can use separate windows on the same machine. The client has reasonable defaults that you can override with key=value command-line arguments. Run the client with no arguments to get detailed usage information. Make sure your firewall isn't blocking the TCP ports you use. To test the IronSHT sharded hash table on a single machine, you can do the following. First, create certificates with: ``` dotnet bin/CreateIronServiceCerts.dll outputdir=certs name=MySHT type=IronSHT addr1=127.0.0.1 port1=4001 addr2=127.0.0.1 port2=4002 addr3=127.0.0.1 port3=4003 ``` Then, run each of the following three server commands, each in a different window: ``` dotnet bin/IronSHTServer.dll certs/MySHT.IronSHT.service.txt certs/MySHT.IronSHT.server1.private.txt dotnet bin/IronSHTServer.dll certs/MySHT.IronSHT.service.txt certs/MySHT.IronSHT.server2.private.txt dotnet bin/IronSHTServer.dll certs/MySHT.IronSHT.service.txt certs/MySHT.IronSHT.server3.private.txt ``` Finally, run this client command in yet another window: ``` dotnet bin/IronSHTClient.dll certs/MySHT.IronSHT.service.txt nthreads=10 duration=30 workload=g numkeys=1000 ``` The client's output will primarily consist of reports of the form `#req `. This output won't start for several seconds since the client has a lot of setup to do. We haven't implemented crash recovery, so if you restart a server its state will be empty. # Custom Replicated Services IronRSL-Counter and IronRSL-KV are examples showing how to write a service in C# and replicate it using IronRSL. If you want to replicate a different C# service, it's fairly easy to do by just following the examples in `src/IronRSLCounterServer/IronRSLCounterServer.sln`, `src/IronRSLKVServer/IronRSLKVServer.sln`, `src/IronRSLCounterClient/IronRSLCounterClient.sln`, and `src/IronRSLKVClient/IronRSLKVClient.sln`. Your service implementation, like in `src/IronRSLCounterServer/Service.cs`, must look like this: ``` namespace IronRSL { public class Service { public static string Name { get { ... } } public static Service Initialize() { ... } public byte[] Serialize() { ... } public static Service Deserialize(byte[] buf) { ... } public byte[] HandleRequest(byte[] request) { ... } } } ``` where you fill out the ellipses to provide: * a static property to provide the service name, * a static method to initialize the service state, * a method to serialize the service state, * a static method to deserialize the service state, and * a method to handle a request and return a reply. Your client implementation, like in `src/IronRSLKVClient/Client.cs`, will create a connection to the replicated service with: ``` var serviceIdentity = ServiceIdentity.ReadFromFile(serviceFileName); RSLClient rslClient = new RSLClient(serviceIdentity, serviceName); ``` and submit requests to that replicated service with: ``` byte[] reply = rslClient.SubmitRequest(request); ``` # Code Layout See the [CODE](./CODE.md) file for more details on the various files in the repository. # Contributing See the [CONTRIBUTING](./CONTRIBUTING.md) file for more details. # Version History - v0.1: Initial code release - v0.2: Compatibility with Dafny 3.0.0 and .NET Core 5 ================================================ FILE: ironfleet/SConstruct ================================================ # -*- python -*- import atexit import os, os.path import re import shutil import subprocess import sys import SCons.Util import threading Import("*") env = Environment(ENV=os.environ) # Retrieve tool-specific command overrides passed in by the user AddOption('--dafny-path', dest='dafny_path', type='string', default=None, action='store', help='Specify the path to Dafny tool binaries') AddOption('--no-verify', dest='no_verify', default=False, action='store_true', help="Don't verify, just build executables") AddOption('--time-limit', dest='time_limit', type='int', default=60, action='store', help='Specify the time limit to use for each verification') dafny_path = GetOption('dafny_path') if dafny_path is None: sys.stderr.write("ERROR: Missing --dafny-path on command line\n") exit(-1) if sys.platform == "win32" or sys.platform == "cygwin": dafny_exe = os.path.join(dafny_path, 'Dafny.exe') if not os.path.exists(dafny_exe): print("ERROR: Could not find Dafny executable in " + dafny_path) exit(-1) dafny_invocation = [dafny_exe] else: dafny_exe = os.path.join(dafny_path, 'Dafny.dll') if not os.path.exists(dafny_exe): dafny_exe = os.path.join(dafny_path, 'dafny.dll') if not os.path.exists(dafny_exe): print("ERROR: Could not find Dafny executable in " + dafny_path) exit(-1) dafny_invocation = ["dotnet", dafny_exe] # Useful Dafny command lines dafny_basic_args = ['/compile:0', '/timeLimit:' + str(GetOption('time_limit')), '/trace'] dafny_default_args = dafny_basic_args + ['/arith:5', '/noCheating:1'] dafny_args_nlarith = dafny_basic_args + ['/arith:2', '/noCheating:1'] dafny_spec_args = dafny_basic_args #################################################################### # # General routines # #################################################################### def recursive_glob(env, pattern, strings=False): matches = [] split = os.path.split(pattern) # [0] is the directory, [1] is the actual pattern platform_directory = split[0] #os.path.normpath(split[0]) for d in os.listdir(platform_directory): if os.path.isdir(os.path.join(platform_directory, d)): newpattern = os.path.join(split[0], d, split[1]) matches.append(recursive_glob(env, newpattern, strings)) files = env.Glob(pattern, strings=strings) matches.append(files) return Flatten(matches) #################################################################### # # Make table of special cases requiring non-default arguments # #################################################################### source_to_args = [ ('src/Dafny/Distributed/Protocol/Lock/RefinementProof/RefinementProof\.i\.dfy', dafny_default_args + ['/noNLarith']), ('.*nonlinear\.i\.dfy', dafny_args_nlarith), ('.*\.s\.dfy', dafny_spec_args), ('.*\.dfy', dafny_default_args), ] #################################################################### # # Dafny-specific utilities # #################################################################### dafny_include_re = re.compile(r'include\s+"(\S+)"', re.M) single_line_comments_re = re.compile(r'//.*\n') multiline_comments_re = re.compile(r'/\*(([^/\*])|(\*[^/])|(/[^\*]))*\*/') def remove_dafny_comments(contents): # Strip out multi-line comments, using a loop to deal with nested comments while True: (contents, substitutions_made) = re.subn(multiline_comments_re, ' ', contents) if substitutions_made == 0: break # Strip out single-line comments contents = re.sub(single_line_comments_re, '\n', contents) return contents # helper to look up Dafny command-line arguments matching a srcpath, from the # source_to_args[] dictionary, dealing with POSIX and Windows pathnames, and # falling back on a default if no specific override is present. def get_dafny_command_line_args(srcpath): srcpath = os.path.normpath(srcpath) # normalize the path, which, on Windows, switches to \\ separators srcpath = srcpath.replace('\\', '/') # switch to posix path separators for entry in source_to_args: pattern, args = entry if re.search(pattern, srcpath, flags=re.IGNORECASE): return args return dafny_default_args dependencies_by_file = dict() already_verified_files = set() already_printed_files = set() # Scan a .dfy file to discover its transitive dependencies, and store a # list of them in dependencies_by_file[fullpath]. def recursively_scan_for_dependencies(fullpath, depth): if fullpath in dependencies_by_file: return contents = File(fullpath).get_text_contents() dirname = os.path.dirname(fullpath) filename = os.path.basename(fullpath) contents = remove_dafny_comments(contents) includes = dafny_include_re.findall(contents) extra_files = [os.path.abspath(os.path.join(dirname, i)) for i in includes] transitive_dependencies = set(extra_files) for srcpath in extra_files: recursively_scan_for_dependencies(srcpath, depth + 1) transitive_dependencies.update(dependencies_by_file[srcpath]) all_dependencies = sorted(list(transitive_dependencies)) dependencies_by_file[fullpath] = all_dependencies # Scan a .dfy file to discover its dependencies, and add .vdfy targets for each. def scan_for_more_targets(target, source, env): node = source[0] fullpath = str(node) recursively_scan_for_dependencies(fullpath, 0) dependencies = dependencies_by_file[fullpath] for srcpath in dependencies: if srcpath not in already_verified_files: f = os.path.splitext(srcpath)[0] + '.vdfy' env.DafnyVerify(f, [srcpath, dafny_exe]) already_verified_files.add(srcpath) return target, source + dependencies #################################################################### # # Dafny routines # #################################################################### def check_dafny(lines): for line in lines: if re.search("[Oo]ut of resource", line): sys.stderr.write("Dafny reported an out-of-resource error\n") raise Exception() if re.search("proof obligations\]\s+errors", line): sys.stderr.write("Dafny reported errors not in summary\n") raise Exception() def check_and_print_tail(filename): with open(filename, 'r') as fh: lines = fh.readlines() check_dafny(lines) sys.stdout.write(lines[-1]) sys.stdout.write('Full check of Dafny output succeeded\n') CheckAndPrintTail = SCons.Action.ActionFactory(check_and_print_tail, lambda x: "Checking " + x) def generate_dafny_verifier_actions(source, target, env, for_signature): abs_source = File(source[0]).abspath abs_target = File(target[0]).abspath source_name = str(source[0]) temp_target_file = re.sub(r'\.dfy$', '.tmp', source_name) args = get_dafny_command_line_args(abs_source) return [ dafny_invocation + args + [source_name, ">", temp_target_file], CheckAndPrintTail(temp_target_file), Move(abs_target, temp_target_file) ] # Add env.DafnyVerify(), to generate Dafny verifier actions def add_dafny_verifier_builder(env): dafny_verifier = Builder(generator = generate_dafny_verifier_actions, suffix = '.vdfy', src_suffix = '.dfy', chdir=0, emitter = scan_for_more_targets, ) env.Append(BUILDERS = {'DafnyVerify' : dafny_verifier}) # Verify a set of Dafny files by creating verification targets for each, # which in turn causes a dependency scan to verify all of their dependencies. def verify_dafny_files(env, files): for f in files: target = os.path.splitext(f)[0] + '.vdfy' env.DafnyVerify(target, [f, dafny_exe]) # Verify *.dfy files in a list of directories. This enumerates # all files in those trees, and creates verification targets for each, # which in turn causes a dependency scan to verify all of their dependencies. def verify_files_in(env, directories): for d in directories: files = recursive_glob(env, d+'/*.dfy', strings=True) verify_dafny_files(env, files) def verify_dafny_file(source): if GetOption('no_verify'): return target = re.sub(r"\.dfy$", ".vdfy", source) env.DafnyVerify(target, [source, dafny_exe]) #################################################################### # # Dafny compilation # #################################################################### def generate_dafny_compile_actions(source, target, env, for_signature): return [ dafny_invocation + ['/compile:0', '/spillTargetCode:3', '/noVerify', str(source[0])], ] def get_dafny_compile_dependencies(target, source, env): source_name = str(source[0]) recursively_scan_for_dependencies(source_name, 0) verification_dependencies = dependencies_by_file[source_name] extra_dependencies = verification_dependencies if not GetOption('no_verify'): extra_dependencies.extend([re.sub('\.dfy$', '.vdfy', f) for f in verification_dependencies if re.search('\.dfy$', f)]) return target, source + extra_dependencies # Add env.DafnyCompile(), to generate dafny_compile build actions def add_dafny_compiler_builder(env): client_builder = Builder(generator = generate_dafny_compile_actions, chdir=0, emitter=get_dafny_compile_dependencies) env.Append(BUILDERS = {'DafnyCompile' : client_builder}) #################################################################### # # .NET binaries # #################################################################### def generate_dotnet_actions(source, target, env, for_signature): target_dir = os.path.dirname(str(target[0])) return [ ["dotnet", "build", "--configuration", "Release", "--output", target_dir, str(source[0])] ] def get_dotnet_dependencies(target, source, env): csproj_file = str(source[0]) source_dir = os.path.dirname(csproj_file) extra_dependencies = [os.path.join(source_dir, f) for f in os.listdir(source_dir) if re.search('\.cs$', f)] with open(csproj_file, 'r') as fh: for line in fh.readlines(): m = re.search(r'', line) if m: raw_file_name = re.sub(r'\\', '/', m.group(1)) file_name = os.path.normpath(os.path.join(source_dir, raw_file_name)) extra_dependencies.append(file_name) return target, source + extra_dependencies # Add env.DotnetBuild(), to generate dotnet build actions def add_dotnet_builder(env): client_builder = Builder(generator = generate_dotnet_actions, chdir=0, emitter=get_dotnet_dependencies) env.Append(BUILDERS = {'DotnetBuild' : client_builder}) #################################################################### # # Extract verification failure information # #################################################################### # extract a string filename out of a build failure def bf_to_filename(bf): import SCons.Errors if bf is None: # unknown targets product None in list return '(unknown tgt)' elif isinstance(bf, SCons.Errors.StopError): return str(bf) elif bf.node: return str(bf.node) elif bf.filename: return bf.filename return '(unknown failure)' def report_verification_failures(): from SCons.Script import GetBuildFailures bf = GetBuildFailures() if bf: # bf is normally a list of build failures; if an element is None, # it's because of a target that scons doesn't know anything about. for x in bf: if x is not None: filename = bf_to_filename(x) if filename.endswith('.vdfy'): file_to_print = os.path.splitext(filename)[0] + '.tmp' if os.path.isfile(file_to_print): sys.stdout.write('\n##### Verification error. Printing contents of ' + file_to_print + ' #####\n\n') with open (file_to_print, 'r') as myfile: sys.stdout.write(myfile.read()) else: print("ERROR: Verification error, but cannot print output since file %s doesn't exist" % (file_to_print)) else: print("Build failure for %s" % (filename)) def display_build_status(): report_verification_failures() #################################################################### # # Put it all together # #################################################################### add_dafny_verifier_builder(env) add_dafny_compiler_builder(env) add_dotnet_builder(env) env.AddMethod(verify_files_in, "VerifyFilesIn") env.AddMethod(verify_dafny_files, "VerifyDafnyFiles") atexit.register(display_build_status) #################################################################### # # Create dependencies # #################################################################### verify_dafny_file('src/Dafny/Distributed/Services/Lock/Main.i.dfy') verify_dafny_file('src/Dafny/Distributed/Services/SHT/Main.i.dfy') verify_dafny_file('src/Dafny/Distributed/Services/RSL/Main.i.dfy') verify_dafny_file('src/Dafny/Distributed/Protocol/RSL/LivenessProof/LivenessProof.i.dfy') verify_dafny_file('src/Dafny/Distributed/Protocol/LiveSHT/LivenessProof/LivenessProof.i.dfy') env.DafnyCompile('src/Dafny/Distributed/Services/RSL/Main.i.cs', 'src/Dafny/Distributed/Services/RSL/Main.i.dfy') env.DotnetBuild('bin/IronRSLCounterServer.dll', 'src/IronRSLCounterServer/IronRSLCounterServer.csproj') env.DotnetBuild('bin/IronRSLCounterClient.dll', 'src/IronRSLCounterClient/IronRSLCounterClient.csproj') env.DotnetBuild('bin/IronRSLKVServer.dll', 'src/IronRSLKVServer/IronRSLKVServer.csproj') env.DotnetBuild('bin/IronRSLKVClient.dll', 'src/IronRSLKVClient/IronRSLKVClient.csproj') env.DafnyCompile('src/Dafny/Distributed/Services/SHT/Main.i.cs', 'src/Dafny/Distributed/Services/SHT/Main.i.dfy') env.DotnetBuild('bin/IronSHTServer.dll', 'src/IronSHTServer/IronSHTServer.csproj') env.DotnetBuild('bin/IronSHTClient.dll', 'src/IronSHTClient/IronSHTClient.csproj') env.DafnyCompile('src/Dafny/Distributed/Services/Lock/Main.i.cs', 'src/Dafny/Distributed/Services/Lock/Main.i.dfy') env.DotnetBuild('bin/IronLockServer.dll', 'src/IronLockServer/IronLockServer.csproj') env.DotnetBuild('bin/CreateIronServiceCerts.dll', 'src/CreateIronServiceCerts/CreateIronServiceCerts.csproj') env.DotnetBuild('bin/TestIoFramework.dll', 'src/TestIoFramework/TestIoFramework.csproj') ================================================ FILE: ironfleet/STYLE.md ================================================ # Style Guide These are the conventions we aspire to follow. Note that not all of the current code has been brought into line yet. - Use spaces, not tabs. 4 spaces per "tab" - Files should use Windows-style newlines (CRLF) - We sort functions/methods within a file topologically, so that everything method M depends on should be above M in the file - We use the lemma keyword to indicate ghost methods used for proof purposes, and we prefix the method's name with "lemma_" - In the implementation, given a concrete type, e.g., `CPacket`, we define the following: + `function AbstractifyCPacket(pkt:CPacket) : Packet` + Which in turn requires: `predicate CPacketIsAbstractable(pkt:CPacket)` which should be the minimum necessary to call `AbstractifyCPacket` + We also define: `predicate CPacketIsValid(pkt:CPacket)` which should imply `CPacketIsAbstractable` and include any additional requirements necessary at the implementation level (e.g., that it fits with 2^64 bytes) - For method, lemma, class, and datatype names, we use camel case + Note that acronyms only capitalize the first letter (e.g., `TpmIsValid` instead of `TPMIsValid`) + Method names are capitalized + Lemmas begin with "lemma_" - Variables: + Initially lower case + Underscores instead of camel case - Braces: + If/else open on same line + Calc open on same line - Operator or tab, then hint + While loops are matched + Methods, predicates, functions: matched unless single line - Use `predicate` instead of `function foo():bool` ================================================ FILE: ironfleet/src/CreateIronServiceCerts/.gitignore ================================================ .vs Properties/ ================================================ FILE: ironfleet/src/CreateIronServiceCerts/CreateIronServiceCerts.csproj ================================================  Exe net6.0 1701;1702;162;164;168;183;219;436;1717;1718 CreateIronServiceCerts.Program ================================================ FILE: ironfleet/src/CreateIronServiceCerts/CreateIronServiceCerts.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.31005.135 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CreateIronServiceCerts", "CreateIronServiceCerts.csproj", "{80249939-7D35-43CA-891A-F4C73EC6D959}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {80249939-7D35-43CA-891A-F4C73EC6D959}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {80249939-7D35-43CA-891A-F4C73EC6D959}.Debug|Any CPU.Build.0 = Debug|Any CPU {80249939-7D35-43CA-891A-F4C73EC6D959}.Release|Any CPU.ActiveCfg = Release|Any CPU {80249939-7D35-43CA-891A-F4C73EC6D959}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {3EDDD386-2BE8-48A4-8188-FFDA2034F16D} EndGlobalSection EndGlobal ================================================ FILE: ironfleet/src/CreateIronServiceCerts/Params.cs ================================================ using System; using System.Collections.Generic; using System.IO; using System.Net; using System.Text.RegularExpressions; namespace CreateIronServiceCerts { public class Params { private static int MAX_SERVER_COUNT = 1000; private string serviceName; private string serviceType; private int maxServerIndex; private string outputDir; private Dictionary serverAddrs; private Dictionary serverPorts; private bool verbose; private bool useSsl; public Params() { serviceName = "MyIronfleetService"; serviceType = "IronRSLKV"; maxServerIndex = 0; outputDir = "."; serverAddrs = new Dictionary(); serverPorts = new Dictionary(); verbose = false; useSsl = true; } public int MaxServerIndex { get { return maxServerIndex; } } public string ServiceName { get { return serviceName; } } public string ServiceType { get { return serviceType; } } public string OutputDir { get { return outputDir; } } public bool Verbose { get { return verbose; } } public bool UseSsl { get { return useSsl; } } public bool GetServerData (int serverIndex, out string addr, out int port) { addr = ""; port = 0; if (!serverAddrs.TryGetValue(serverIndex, out addr)) { return false; } if (!serverPorts.TryGetValue(serverIndex, out port)) { return false; } return true; } public bool UseServerIndex(int serverIndex) { if (serverIndex >= MAX_SERVER_COUNT) { Console.WriteLine("ERROR - Server #{0} too big -- must be less than {1}", serverIndex, MAX_SERVER_COUNT); return false; } if (serverIndex == 0) { Console.WriteLine("ERROR - Server indices should start at 1, not 0. So, don't use addr0 or port0."); return false; } maxServerIndex = Math.Max(maxServerIndex, serverIndex); return true; } public bool Validate() { if (maxServerIndex == 0) { Console.WriteLine("ERROR - No server data supplied. You need to provide at least addr1 and port1."); return false; } for (int serverIndex = 1; serverIndex <= maxServerIndex; ++serverIndex) { if (!serverAddrs.ContainsKey(serverIndex)) { Console.WriteLine("ERROR - Missing addr{0}", serverIndex); return false; } if (!serverPorts.ContainsKey(serverIndex)) { Console.WriteLine("ERROR - Missing port{0}", serverIndex); return false; } } return true; } public bool ProcessCommandLineArgument(string arg) { var pos = arg.IndexOf("="); if (pos < 0) { Console.WriteLine("ERROR - Invalid argument {0}", arg); return false; } var key = arg.Substring(0, pos).ToLower(); var value = arg.Substring(pos + 1); return SetValue(key, value); } private bool SetValue(string key, string value) { if (key == "name") { serviceName = value; return true; } if (key == "type") { serviceType = value; return true; } if (key == "verbose") { if (value == "false") { verbose = false; return true; } if (value == "true") { verbose = true; return true; } Console.WriteLine("ERROR - Invalid verbose value {0} - should be false or true", value); return false; } if (key == "usessl") { if (value == "false") { useSsl = false; return true; } if (value == "true") { useSsl = true; return true; } Console.WriteLine("ERROR - Invalid useSSL value {0} - should be false or true", value); return false; } if (key == "outputdir") { outputDir = value; try { Directory.CreateDirectory(outputDir); } catch (Exception e) { Console.WriteLine("ERROR - Can't create requested output directory {0}", outputDir); return false; } return true; } Match m = Regex.Match(key, @"^addr(\d+)$"); if (m.Success) { if (value.Length == 0) { Console.WriteLine("ERROR - Address {0} cannot be empty", key); return false; } int serverIndex = Convert.ToInt32(m.Groups[1].Value); if (!UseServerIndex(serverIndex)) { return false; } serverAddrs[serverIndex] = value; maxServerIndex = Math.Max(maxServerIndex, serverIndex); return true; } m = Regex.Match(key, @"^port(\d+)$"); if (m.Success) { int port; try { port = Convert.ToInt32(value); } catch (Exception e) { Console.WriteLine("ERROR - Invalid port number {0} given for key {1}", value, key); return false; } if (port == 0 || port > 65535) { Console.WriteLine("ERROR - Invalid port number {0} given for key {1}", value, key); return false; } int serverIndex = Convert.ToInt32(m.Groups[1].Value); if (!UseServerIndex(serverIndex)) { return false; } serverPorts[serverIndex] = port; return true; } Console.WriteLine("ERROR - Invalid argument key {0}", key); return false; } } } ================================================ FILE: ironfleet/src/CreateIronServiceCerts/Program.cs ================================================ using IronfleetIoFramework; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Numerics; using System.Threading; namespace CreateIronServiceCerts { class Program { static void usage() { Console.Write(@" Usage: dotnet CreateIronServiceCerts.dll [key=value]... Allowed keys: name - friendly name of the service (default ""MyIronfleetService"") type - service type (default ""IronRSLKV"") outputdir - directory to write certificates into (default ""."") addr - public address (host name or IP) of server # port - public port of server # verbose - print verbose output (false or true, default false) useSSL - whether to use SSL (default: true) "); } static void Main(string[] args) { Params ps = new Params(); foreach (var arg in args) { if (!ps.ProcessCommandLineArgument(arg)) { usage(); return; } } if (!ps.Validate()) { return; } List serverPublicIdentities = new List(); for (int serverIndex = 1; serverIndex <= ps.MaxServerIndex; ++serverIndex) { string addr; int port; if (!ps.GetServerData(serverIndex, out addr, out port)) { Console.WriteLine("ERROR - Missing data for server #{0}", serverIndex); return; } PublicIdentity publicIdentity; PrivateIdentity privateIdentity; string serverName = string.Format("{0}.{1}.server{2}", ps.ServiceName, ps.ServiceType, serverIndex); IronfleetCrypto.CreateNewIdentity(serverName, addr, port, out publicIdentity, out privateIdentity); var privateKeyFileName = Path.Join(ps.OutputDir, string.Format("{0}.private.txt", serverName)); if (!privateIdentity.WriteToFile(privateKeyFileName)) { return; } Console.WriteLine("Successfully wrote private key for server {0} to {1}", serverIndex, privateKeyFileName); serverPublicIdentities.Add(publicIdentity); } var serviceIdentity = new ServiceIdentity { FriendlyName = ps.ServiceName, ServiceType = ps.ServiceType, Servers = serverPublicIdentities, UseSsl = ps.UseSsl }; var serviceFileName = Path.Join(ps.OutputDir, string.Format("{0}.{1}.service.txt", ps.ServiceName, ps.ServiceType)); if (!serviceIdentity.WriteToFile(serviceFileName)) { return; } Console.WriteLine("Successfully wrote service description to {0}", serviceFileName); Console.WriteLine("DONE - SUCCESS"); } } } ================================================ FILE: ironfleet/src/Dafny/.gitignore ================================================ *.bpl *.log ================================================ FILE: ironfleet/src/Dafny/Distributed/Common/.gitignore ================================================ *.i.dll ================================================ FILE: ironfleet/src/Dafny/Distributed/Common/Collections/CountMatches.i.dfy ================================================ module Collections__CountMatches_i { function CountMatchesInSeq(s:seq, f:T-->bool):int reads f.reads requires forall x :: f.requires(x) { if |s| == 0 then 0 else CountMatchesInSeq(s[1..], f) + if f(s[0]) then 1 else 0 } function CountMatchesInMultiset(m:multiset, f:T-->bool):int reads f.reads requires forall x :: f.requires(x) { if |m| == 0 then 0 else var x :| x in m; CountMatchesInMultiset(m - multiset{x}, f) + if f(x) then 1 else 0 } lemma Lemma_RemovingElementAffectsCount(m:multiset, f:T-->bool, x:T) requires forall u :: f.requires(u) requires x in m ensures CountMatchesInMultiset(m, f) - CountMatchesInMultiset(m - multiset{x}, f) == if f(x) then 1 else 0 { if |m| > 0 { var x' :| x' in m && CountMatchesInMultiset(m, f) - CountMatchesInMultiset(m - multiset{x'}, f) == if f(x') then 1 else 0; if x' != x { Lemma_RemovingElementAffectsCount(m - multiset{x'}, f, x); assert m - multiset{x'} - multiset{x} == m - multiset{x} - multiset{x'}; Lemma_RemovingElementAffectsCount(m - multiset{x}, f, x'); } } } lemma Lemma_MatchCountInSeqIsMatchCountInMultiset(s:seq, m:multiset, f:T-->bool) requires forall x :: f.requires(x) requires m == multiset(s) ensures CountMatchesInSeq(s, f) == CountMatchesInMultiset(m, f) { if |s| > 0 { assert s == [s[0]] + s[1..]; var m' := multiset(s[1..]); assert m' == m - multiset {s[0]}; Lemma_RemovingElementAffectsCount(m, f, s[0]); Lemma_MatchCountInSeqIsMatchCountInMultiset(s[1..], m', f); } } predicate IsNthHighestValueInSequence(v:int, s:seq, n:int) { && 0 < n <= |s| && v in s && CountMatchesInSeq(s, x => x > v) < n && CountMatchesInSeq(s, x => x >= v) >= n } predicate IsNthHighestValueInMultiset(v:int, m:multiset, n:int) { && 0 < n <= |m| && v in m && CountMatchesInMultiset(m, x => x > v) < n && CountMatchesInMultiset(m, x => x >= v) >= n } lemma Lemma_SequenceToMultisetPreservesIsNthHighestValue(v:int, s:seq, m:multiset, n:int) requires m == multiset(s) ensures IsNthHighestValueInSequence(v, s, n) <==> IsNthHighestValueInMultiset(v, m, n) { Lemma_MatchCountInSeqIsMatchCountInMultiset(s, m, x => x > v); Lemma_MatchCountInSeqIsMatchCountInMultiset(s, m, x => x >= v); } lemma Lemma_CountMatchesInSeqSameForSameFunctions(s:seq, f1:T-->bool, f2:T-->bool) requires forall x :: f1.requires(x) requires forall x :: f2.requires(x) requires forall x :: f1(x) == f2(x) ensures CountMatchesInSeq(s, f1) == CountMatchesInSeq(s, f2) { } lemma Lemma_CountMatchesInSeqBounds(s:seq, f:T-->bool) requires forall x :: f.requires(x) ensures 0 <= CountMatchesInSeq(s, f) <= |s| { } lemma Lemma_CountMatchesInSeqAll(s:seq, f:T-->bool) requires forall x :: f.requires(x) requires forall x :: x in s ==> f(x) ensures CountMatchesInSeq(s, f) == |s| { } lemma Lemma_CountMatchesInSeqCorrespondence(s1:seq, f1:T1-->bool, s2:seq, f2:T2-->bool) requires forall x :: f1.requires(x) requires forall x :: f2.requires(x) requires |s1| == |s2| requires forall i :: 0 <= i < |s1| ==> f1(s1[i]) == f2(s2[i]) ensures CountMatchesInSeq(s1, f1) == CountMatchesInSeq(s2, f2) { } function{:opaque} EnumerateMatchesInSeq(s:seq, f:T-->bool):seq reads f.reads requires forall x :: f.requires(x) ensures forall x :: (x in s && f(x)) <==> x in EnumerateMatchesInSeq(s, f) ensures |EnumerateMatchesInSeq(s, f)| == CountMatchesInSeq(s, f) { if |s| == 0 then [] else if f(s[0]) then [s[0]] + EnumerateMatchesInSeq(s[1..], f) else EnumerateMatchesInSeq(s[1..], f) } function EnumerateIndicesOfMatchesInSeq_Helper(s:seq, f:T-->bool, offset:int):seq reads f.reads requires forall x :: f.requires(x) ensures forall i :: i in EnumerateIndicesOfMatchesInSeq_Helper(s, f, offset) ==> offset <= i < offset + |s| ensures forall i :: (0 <= i < |s| && f(s[i])) <==> i+offset in EnumerateIndicesOfMatchesInSeq_Helper(s, f, offset) ensures offset == 0 ==> forall i :: (0 <= i < |s| && f(s[i])) <==> i in EnumerateIndicesOfMatchesInSeq_Helper(s, f, offset) ensures |EnumerateIndicesOfMatchesInSeq_Helper(s, f, offset)| == CountMatchesInSeq(s, f) { if |s| == 0 then [] else if f(s[0]) then [offset] + EnumerateIndicesOfMatchesInSeq_Helper(s[1..], f, offset + 1) else EnumerateIndicesOfMatchesInSeq_Helper(s[1..], f, offset + 1) } function{:opaque} EnumerateIndicesOfMatchesInSeq(s:seq, f:T-->bool):seq reads f.reads requires forall x :: f.requires(x) ensures forall i :: (0 <= i < |s| && f(s[i])) <==> i in EnumerateIndicesOfMatchesInSeq(s, f) ensures |EnumerateIndicesOfMatchesInSeq(s, f)| == CountMatchesInSeq(s, f) { EnumerateIndicesOfMatchesInSeq_Helper(s, f, 0) } function SetOfIndicesOfMatchesInSeq_Helper(s:seq, f:T-->bool, offset:int):set reads f.reads requires forall x :: f.requires(x) ensures forall i :: i in SetOfIndicesOfMatchesInSeq_Helper(s, f, offset) ==> offset <= i < offset + |s| ensures forall i :: (0 <= i < |s| && f(s[i])) <==> i+offset in SetOfIndicesOfMatchesInSeq_Helper(s, f, offset) ensures offset == 0 ==> forall i :: (0 <= i < |s| && f(s[i])) <==> i in SetOfIndicesOfMatchesInSeq_Helper(s, f, offset) ensures |SetOfIndicesOfMatchesInSeq_Helper(s, f, offset)| == CountMatchesInSeq(s, f) { if |s| == 0 then {} else if f(s[0]) then {offset} + SetOfIndicesOfMatchesInSeq_Helper(s[1..], f, offset + 1) else SetOfIndicesOfMatchesInSeq_Helper(s[1..], f, offset + 1) } function{:opaque} SetOfIndicesOfMatchesInSeq(s:seq, f:T-->bool):set reads f.reads requires forall x :: f.requires(x) ensures forall i :: (0 <= i < |s| && f(s[i])) <==> i in SetOfIndicesOfMatchesInSeq(s, f) ensures |SetOfIndicesOfMatchesInSeq(s, f)| == CountMatchesInSeq(s, f) { SetOfIndicesOfMatchesInSeq_Helper(s, f, 0) } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Common/Collections/Maps.i.dfy ================================================ module Collections__Maps_i { // TODO_MODULE: module Collections__Maps_i { predicate eq_map(x:map, y:map) ensures eq_map(x, y) ==> x == y; { && (forall a :: a in x <==> a in y) && (forall a :: a in x ==> x[a] == y[a]) } function method domain(m: map): set ensures forall i :: i in domain(m) <==> i in m; { set s | s in m } function union(m: map, m': map): map requires m.Keys !! m'.Keys ensures forall i :: i in union(m, m') <==> i in m || i in m' ensures forall i :: i in m ==> union(m, m')[i] == m[i] ensures forall i :: i in m' ==> union(m, m')[i] == m'[i] { map i{:auto_trigger} | i in (domain(m) + domain(m')) :: if i in m then m[i] else m'[i] } function method RemoveElt(m:map, elt:U) : map requires elt in m decreases |m| ensures |RemoveElt(m, elt)| == |m| - 1 ensures !(elt in RemoveElt(m, elt)) ensures forall elt' :: elt' in RemoveElt(m, elt) <==> elt' in m && elt' != elt { var m' := map elt' | elt' in m && elt' != elt :: m[elt']; lemma_map_remove_one(m, m', elt); m' } lemma lemma_non_empty_map_has_elements(m:map) requires |m| > 0 ensures exists x :: x in m { var dom := domain(m); var empty_map:map := map []; assert m.Keys !! empty_map.Keys; assert m.Keys != empty_map.Keys; assert |dom| > 0; } lemma lemma_MapSizeIsDomainSize(dom:set, m:map) requires dom == domain(m) ensures |m| == |dom| { if |m| == 0 { assert |dom| == 0; } else { lemma_non_empty_map_has_elements(m); var x :| x in m; assert x in m; assert x in dom; var m' := map y | y in m && y != x :: m[y]; var dom' := dom - { x }; lemma_MapSizeIsDomainSize(dom', m'); assert |dom'| == |m'|; assert |dom| == |dom'| + 1; assert m == m'[x := m[x]]; assert |m| == |m'| + 1; } } lemma lemma_maps_decrease(before:map, after:map, item_removed:S) requires item_removed in before requires after == map s | s in before && s != item_removed :: before[s] ensures |after| < |before| { assert !(item_removed in after); forall i | i in after ensures i in before; { assert i in before; } var domain_before := set s | s in before; var domain_after := set s | s in after; lemma_MapSizeIsDomainSize(domain_before, before); lemma_MapSizeIsDomainSize(domain_after, after); if |after| == |before| { if domain_before == domain_after { assert !(item_removed in domain_after); assert false; } else { assert |domain_after| == |domain_before|; var diff := domain_after - domain_before; assert forall i :: i in domain_after ==> i in domain_before; assert |diff| == 0; var diff2 := domain_before - domain_after; assert item_removed in diff2; assert |diff2| >= 1; assert false; } } else if |after| > |before|{ //var extra :| extra in domain_after && !(extra in domain_before); var diff := domain_after - domain_before; assert |domain_after| > |domain_before|; if |diff| == 0 { assert |diff| == |domain_after| - |domain_after*domain_before|; assert |domain_after*domain_before| <= |domain_before|; assert |domain_after| == |domain_after*domain_before|; assert |domain_after| <= |domain_before|; assert false; } else { assert |diff| >= 1; var diff_item :| diff_item in diff; assert diff_item in domain_after; assert !(diff_item in domain_before); assert false; } assert false; } } lemma lemma_map_remove_one(before:map, after:map, item_removed:S) requires item_removed in before requires after == map s | s in before && s != item_removed :: before[s] ensures |after| + 1 == |before| { lemma_maps_decrease(before, after, item_removed); var domain_before := domain(before); var domain_after := domain(after); lemma_MapSizeIsDomainSize(domain_before, before); lemma_MapSizeIsDomainSize(domain_after, after); assert domain_after + { item_removed } == domain_before; } // TODO_MODULE: } import opened Collections__Maps_i_ = Collections__Maps_i } ================================================ FILE: ironfleet/src/Dafny/Distributed/Common/Collections/Maps2.i.dfy ================================================ include "Maps2.s.dfy" // TODO eliminate redundancy between these two libraries we've accreted. module Collections__Maps2_i { import opened Collections__Maps2_s function maprange(m:map) : set { set k | k in m :: m[k] } type imap2 = imap> predicate imap2total(m:imap2) { imaptotal(m) && forall k1 :: imaptotal(m[k1]) } predicate imaptotal_(f:imap) { imaptotal(f) } // TODO: remove hack when opaque/generic bug is fixed predicate monotonic(f:imap) { forall i1, i2 :: i1 in f && i2 in f && i1 <= i2 ==> f[i1] <= f[i2] } predicate monotonic_from(start:int, f:imap) { forall i1, i2 :: i1 in f && i2 in f && start <= i1 <= i2 ==> f[i1] <= f[i2] } predicate behaviorMonotonic(b:imap, f:imap) requires imaptotal(b) requires imaptotal(f) { forall i1, i2 :: i1 <= i2 ==> f[b[i1]] <= f[b[i2]] } // TODO_MODULE: module Collections__Maps2_i { // TODO_MODULE: import opened Collections__Maps2_s lemma Lemma_EqualityConditionForMapsWithSameDomain(m1:map, m2:map) requires mapdomain(m1) == mapdomain(m2) requires forall s :: s in m1 && s in m2 ==> m1[s] == m2[s] ensures m1 == m2 { forall s | s in m1 ensures s in m2; { assert s in mapdomain(m1); assert s in mapdomain(m2); } forall s | s in m2 ensures s in m1; { assert s in mapdomain(m2); assert s in mapdomain(m1); } } lemma Lemma_imap2equiv(f:imap2, g:imap2) requires forall k1 :: k1 in f <==> k1 in g requires forall k1 :: k1 in f ==> f[k1] == g[k1] ensures f == g { } predicate TLe(i:int, j:int) { i <= j } lemma Lemma_imapInductionRange(start:int, end:int, f:imap) requires TLe(start, end) requires forall i :: TLe(start, i) && TLe(i, end) ==> i in f requires forall i :: TLe(start, i) && TLe(i + 1, end) && f[i] ==> f[i + 1] requires f[start] ensures f[end] decreases end - start { if (start != end) { assert TLe(start, start) && TLe(start + 1, end); forall i | TLe(start + 1, i) && TLe(i + 1, end) ensures f[i] ==> f[i+1]; { assert TLe(start, i) && TLe(i + 1, end); } Lemma_imapInductionRange(start + 1, end, f); } } // TODO_MODULE: } import opened Collections__Maps2_i_ = Collections__Maps2_i } ================================================ FILE: ironfleet/src/Dafny/Distributed/Common/Collections/Maps2.s.dfy ================================================ // TODO eliminate redundancy between these two libraries we've accreted. module Collections__Maps2_s { function mapdomain(m:map) : set { set k | k in m :: k } function mapremove(m:map, k:KT) : map { map ki | ki in m && ki != k :: m[ki] } predicate imaptotal(m:imap) { forall k {:trigger m[k]}{:trigger k in m} :: k in m } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Common/Collections/Multisets.s.dfy ================================================ module Collections__Multisets_s { function RestrictMultiset(m:multiset, f:S->bool):multiset reads f.reads requires forall x :: f.requires(x) ensures RestrictMultiset(m, f) <= m ensures forall x :: RestrictMultiset(m, f)[x] == if f(x) then m[x] else 0 { if |m| == 0 then multiset{} else var x :| x in m; var m_without_x := m[x := 0]; if f(x) then RestrictMultiset(m_without_x, f)[x := m[x]] else RestrictMultiset(m_without_x, f) } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Common/Collections/Seqs.i.dfy ================================================ include "Seqs.s.dfy" module Collections__Seqs_i { import opened Collections__Seqs_s lemma SeqAdditionIsAssociative(a:seq, b:seq, c:seq) ensures a+(b+c) == (a+b)+c; { } predicate ItemAtPositionInSeq(s:seq, v:T, idx:int) { 0 <= idx < |s| && s[idx] == v } lemma Lemma_ItemInSeqAtASomePosition(s:seq, v:T) requires v in s ensures exists idx :: ItemAtPositionInSeq(s, v, idx) { var idx :| 0 <= idx < |s| && s[idx] == v; assert ItemAtPositionInSeq(s, v, idx); } function FindIndexInSeq(s:seq, v:T):int ensures var idx := FindIndexInSeq(s, v); if idx >= 0 then idx < |s| && s[idx] == v else v !in s { if v in s then Lemma_ItemInSeqAtASomePosition(s, v); var idx :| ItemAtPositionInSeq(s, v, idx); idx else -1 } lemma Lemma_IdenticalSingletonSequencesHaveIdenticalElement(x:T, y:T) requires [x] == [y] ensures x == y { calc { x; [x][0]; [y][0]; y; } } ////////////////////////////////////////////////////////// // Combining sequences of sequences ////////////////////////////////////////////////////////// function SeqCat(seqs:seq>) : seq { if |seqs| == 0 then [] else seqs[0] + SeqCat(seqs[1..]) } function SeqCatRev(seqs:seq>) : seq { if |seqs| == 0 then [] else SeqCatRev(all_but_last(seqs)) + last(seqs) } lemma lemma_SeqCat_adds(A:seq>, B:seq>) ensures SeqCat(A + B) == SeqCat(A) + SeqCat(B) { if |A| == 0 { assert A+B == B; } else { calc { SeqCat(A + B); { assert (A + B)[0] == A[0]; assert (A + B)[1..] == A[1..] + B; } A[0] + SeqCat(A[1..] + B); A[0] + SeqCat(A[1..]) + SeqCat(B); SeqCat(A) + SeqCat(B); } } } lemma lemma_SeqCatRev_adds(A:seq>, B:seq>) ensures SeqCatRev(A + B) == SeqCatRev(A) + SeqCatRev(B) { if |B| == 0 { assert SeqCatRev(B) == []; assert A+B == A; } else { calc { SeqCatRev(A + B); { assert last(A + B) == last(B); assert all_but_last(A + B) == A + all_but_last(B); } SeqCatRev(A + all_but_last(B)) + last(B); SeqCatRev(A) + SeqCatRev(all_but_last(B)) + last(B); SeqCatRev(A) + SeqCatRev(B); } } } lemma lemma_SeqCat_equivalent(seqs:seq>) ensures SeqCat(seqs) == SeqCatRev(seqs) { if |seqs| == 0 { } else { calc { SeqCatRev(seqs); SeqCatRev(all_but_last(seqs)) + last(seqs); { lemma_SeqCat_equivalent(all_but_last(seqs)); } SeqCat(all_but_last(seqs)) + last(seqs); SeqCat(all_but_last(seqs)) + SeqCat([last(seqs)]); { lemma_SeqCat_adds(all_but_last(seqs), [last(seqs)]); assert seqs == all_but_last(seqs) + [last(seqs)]; } SeqCat(seqs); } } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Common/Collections/Seqs.s.dfy ================================================ module Collections__Seqs_s { function last(s:seq):T requires |s| > 0 { s[|s|-1] } function all_but_last(s:seq):seq requires |s| > 0 ensures |all_but_last(s)| == |s| - 1 { s[..|s|-1] } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Common/Collections/Sets.i.dfy ================================================ module Collections__Sets_i { lemma ThingsIKnowAboutSubset(x:set, y:set) requires x(x:set, y:set) ensures x |x|<|y| ensures x<=y ==> |x|<=|y| { if (x(foo:set, x:T) requires foo=={x} ensures |foo|==1 { } lemma ThingsIKnowAboutASingletonSet(foo:set, x:T, y:T) requires |foo|==1 requires x in foo requires y in foo ensures x==y { if (x!=y) { assert {x} < foo; ThingsIKnowAboutSubset({x}, foo); assert |{x}| < |foo|; assert |foo|>1; assert false; } } predicate Injective(f:X-->Y) reads f.reads requires forall x :: f.requires(x) { forall x1, x2 :: f(x1) == f(x2) ==> x1 == x2 } predicate InjectiveOver(xs:set, ys:set, f:X-->Y) reads f.reads requires forall x :: x in xs ==> f.requires(x) { forall x1, x2 :: x1 in xs && x2 in xs && f(x1) in ys && f(x2) in ys && f(x1) == f(x2) ==> x1 == x2 } predicate InjectiveOverSeq(xs:seq, ys:set, f:X-->Y) reads f.reads requires forall x :: x in xs ==> f.requires(x) { forall x1, x2 :: x1 in xs && x2 in xs && f(x1) in ys && f(x2) in ys && f(x1) == f(x2) ==> x1 == x2 } lemma lemma_MapSetCardinality(xs:set, ys:set, f:X-->Y) requires forall x :: f.requires(x) requires Injective(f) requires forall x :: x in xs <==> f(x) in ys requires forall y :: y in ys ==> exists x :: x in xs && y == f(x) ensures |xs| == |ys| { if (xs != {}) { var x :| x in xs; var xs' := xs - {x}; var ys' := ys - {f(x)}; lemma_MapSetCardinality(xs', ys', f); } } lemma lemma_MapSetCardinalityOver(xs:set, ys:set, f:X-->Y) requires forall x :: x in xs ==> f.requires(x) requires InjectiveOver(xs, ys, f) requires forall x :: x in xs ==> f(x) in ys requires forall y :: y in ys ==> exists x :: x in xs && y == f(x) ensures |xs| == |ys| { if (xs != {}) { var x :| x in xs; var xs' := xs - {x}; var ys' := ys - {f(x)}; lemma_MapSetCardinalityOver(xs', ys', f); } } lemma lemma_MapSubsetCardinalityOver(xs:set, ys:set, f:X-->Y) requires forall x :: x in xs ==> f.requires(x) requires InjectiveOver(xs, ys, f) requires forall x :: x in xs ==> f(x) in ys ensures |xs| <= |ys| { if (xs != {}) { var x :| x in xs; var xs' := xs - {x}; var ys' := ys - {f(x)}; lemma_MapSubsetCardinalityOver(xs', ys', f); } } lemma lemma_MapSubseqCardinalityOver(xs:seq, ys:set, f:X-->Y) requires forall x :: x in xs ==> f.requires(x) requires forall i, j :: 0 <= i < |xs| && 0 <= j < |xs| && i != j ==> xs[i] != xs[j] requires InjectiveOverSeq(xs, ys, f) requires forall x :: x in xs ==> f(x) in ys ensures |xs| <= |ys| { if (xs != []) { var x := xs[0]; var xs' := xs[1..]; var ys' := ys - {f(x)}; forall x' | x' in xs' ensures f(x') in ys' { assert x' in xs; assert f(x') in ys; if f(x') == f(x) { assert x in xs && x' in xs && f(x) in ys && f(x') in ys && f(x') == f(x); assert x' == x; } } forall x1, x2 | x1 in xs' && x2 in xs' && f(x1) in ys' && f(x2) in ys' && f(x1) == f(x2) ensures x1 == x2 { assert x1 in xs && x2 in xs && f(x1) in ys && f(x2) in ys'; } lemma_MapSubseqCardinalityOver(xs', ys', f); } } function/*TODO:{:opaque}*/ MapSetToSet(xs:set, f:X-->Y):set reads f.reads requires forall x :: f.requires(x) requires Injective(f) ensures forall x :: x in xs <==> f(x) in MapSetToSet(xs, f) ensures |xs| == |MapSetToSet(xs, f)| { var ys := set x | x in xs :: f(x); lemma_MapSetCardinality(xs, ys, f); ys } function/*TODO:{:opaque}*/ MapSetToSetOver(xs:set, f:X-->Y):set reads f.reads requires forall x :: x in xs ==> f.requires(x) requires InjectiveOver(xs, set x | x in xs :: f(x), f) ensures forall x :: x in xs ==> f(x) in MapSetToSetOver(xs, f) ensures |xs| == |MapSetToSetOver(xs, f)| { var ys := set x | x in xs :: f(x); lemma_MapSetCardinalityOver(xs, ys, f); ys } function/*TODO:{:opaque}*/ MapSeqToSet(xs:seq, f:X-->Y):set reads f.reads requires forall x :: f.requires(x) requires Injective(f) ensures forall x :: x in xs <==> f(x) in MapSeqToSet(xs, f) { set x | x in xs :: f(x) } function SeqToSet(xs:seq):set { set x | x in xs } lemma lemma_SubsetCardinality(xs:set, ys:set, f:X-->bool) requires forall x :: x in xs ==> f.requires(x) requires forall x :: x in ys ==> x in xs && f(x) ensures |ys| <= |xs| { if (ys != {}) { var y :| y in ys; var xs' := xs - {y}; var ys' := ys - {y}; lemma_SubsetCardinality(xs', ys', f); } } function/*TODO:{:opaque}*/ MakeSubset(xs:set, f:X->bool):set reads f.reads requires forall x :: x in xs ==> f.requires(x) ensures forall x :: x in MakeSubset(xs, f) <==> x in xs && f(x) ensures |MakeSubset(xs, f)| <= |xs| { var ys := set x | x in xs && f(x); lemma_SubsetCardinality(xs, ys, f); ys } /* examples: function{:opaque} setAdd1(xs:set):set ensures forall x :: x in xs <==> x + 1 in setAdd1(xs) ensures |xs| == |setAdd1(xs)| { MapSetToSet(xs, x => x + 1) } function{:opaque} setPos(xs:set):set ensures forall x :: x in setPos(xs) <==> x in xs && x > 0 { MakeSubset(xs, x => x > 0) } */ lemma lemma_UnionCardinality(xs:set, ys:set, us:set) requires us==xs+ys ensures |us| >= |xs| decreases ys { if (ys=={}) { } else { var y :| y in ys; if (y in xs) { var xr := xs - {y}; var yr := ys - {y}; var ur := us - {y}; lemma_UnionCardinality(xr, yr, ur); } else { var ur := us - {y}; var yr := ys - {y}; lemma_UnionCardinality(xs, yr, ur); } } } function SetOfNumbersInRightExclusiveRange(a:int, b:int):set requires a <= b ensures forall opn :: a <= opn < b ==> opn in SetOfNumbersInRightExclusiveRange(a, b) ensures forall opn :: opn in SetOfNumbersInRightExclusiveRange(a, b) ==> a <= opn < b ensures |SetOfNumbersInRightExclusiveRange(a, b)| == b-a decreases b-a { if a == b then {} else {a} + SetOfNumbersInRightExclusiveRange(a+1, b) } lemma lemma_CardinalityOfBoundedSet(s:set, a:int, b:int) requires forall opn :: opn in s ==> a <= opn < b requires a <= b ensures |s| <= b-a { var range := SetOfNumbersInRightExclusiveRange(a, b); forall i | i in s ensures i in range; { } assert s <= range; SubsetCardinality(s, range); } function intsetmax(s:set):int requires |s| > 0 ensures var m := intsetmax(s); m in s && forall i :: i in s ==> m >= i { var x :| x in s; if |s| == 1 then assert |s - {x}| == 0; x else var sy := s - {x}; var y := intsetmax(sy); assert forall i :: i in s ==> i in sy || i == x; if x > y then x else y } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Common/Framework/AbstractService.s.dfy ================================================ //- The high-level spec is written in the form of a state-machine //- The states and transition functions are instantiated on a per-service basis include "../Native/Io.s.dfy" include "Environment.s.dfy" abstract module AbstractService_s { import opened Native__Io_s import opened Environment_s import opened Native__NativeTypes_s type ServiceState predicate Service_Init(s:ServiceState, serverAddresses:set) predicate Service_Next(s:ServiceState, s':ServiceState) predicate Service_Correspondence(concretePkts:set>>, serviceState:ServiceState) } ================================================ FILE: ironfleet/src/Dafny/Distributed/Common/Framework/DistributedSystem.s.dfy ================================================ include "Host.s.dfy" include "../Collections/Maps2.s.dfy" abstract module DistributedSystem_s { import H_s : Host_s import opened Collections__Maps2_s import opened Native__Io_s import opened Environment_s import opened Native__NativeTypes_s ///////////////////////////////////////// // PHYSICAL ENVIRONMENT ///////////////////////////////////////// predicate ValidPhysicalEnvironmentStep(step:LEnvStep>) { step.LEnvStepHostIos? ==> forall io{:trigger io in step.ios}{:trigger ValidPhysicalIo(io)} :: io in step.ios ==> ValidPhysicalIo(io) } ///////////////////////////////////////// // DS_State ///////////////////////////////////////// datatype DS_State = DS_State( config:H_s.ConcreteConfiguration, environment:LEnvironment>, servers:map ) predicate DS_Init(s:DS_State, config:H_s.ConcreteConfiguration) reads * { && s.config == config && H_s.ConcreteConfigToServers(s.config) == mapdomain(s.servers) && H_s.ConcreteConfigInit(s.config) && LEnvironment_Init(s.environment) && (forall id :: id in s.servers ==> H_s.HostInit(s.servers[id], config, id)) } predicate DS_NextOneServer(s:DS_State, s':DS_State, id:EndPoint, ios:seq>>) requires id in s.servers reads * { && id in s'.servers && H_s.HostNext(s.servers[id], s'.servers[id], ios) && s'.servers == s.servers[id := s'.servers[id]] } predicate DS_Next(s:DS_State, s':DS_State) reads * { && s'.config == s.config && LEnvironment_Next(s.environment, s'.environment) && ValidPhysicalEnvironmentStep(s.environment.nextStep) && if s.environment.nextStep.LEnvStepHostIos? && s.environment.nextStep.actor in s.servers then DS_NextOneServer(s, s', s.environment.nextStep.actor, s.environment.nextStep.ios) else s'.servers == s.servers } // ///////////////////////////////////////////////////////////////////// // // Relationship with the abstract service's state machine // function DS_AbstractState(s:DS_State) : SpecState // function DS_AbstractConfig(s:ConcreteConfiguration) : SpecConfiguration // // predicate IsAbstractStateAbstractionSequenceOf(s:seq, start:SpecState, end:SpecState) // { // && |s| > 0 // && s[0] == start // && s[|s|-1] == end // && (forall i :: 0 <= i < |s|-1 ==> Spec_Next(s[i], s[i+1])) // } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Common/Framework/Environment.s.dfy ================================================ include "../Collections/Maps2.s.dfy" include "../Logic/Temporal/Temporal.s.dfy" module Environment_s { import opened Collections__Maps2_s import opened Temporal__Temporal_s datatype LPacket = LPacket(dst:IdType, src:IdType, msg:MessageType) datatype LIoOp = LIoOpSend(s:LPacket) | LIoOpReceive(r:LPacket) | LIoOpTimeoutReceive() | LIoOpReadClock(t:int) datatype LEnvStep = LEnvStepHostIos(actor:IdType, ios:seq>) | LEnvStepDeliverPacket(p:LPacket) | LEnvStepAdvanceTime() | LEnvStepStutter() datatype LHostInfo = LHostInfo(queue:seq>) datatype LEnvironment = LEnvironment(time:int, sentPackets:set>, hostInfo:map>, nextStep:LEnvStep) predicate IsValidLIoOp(io:LIoOp, actor:IdType, e:LEnvironment) { match io case LIoOpSend(s) => s.src == actor case LIoOpReceive(r) => r.dst == actor case LIoOpTimeoutReceive => true case LIoOpReadClock(t) => true } predicate LIoOpOrderingOKForAction( io1:LIoOp, io2:LIoOp ) { io1.LIoOpReceive? || io2.LIoOpSend? } predicate LIoOpSeqCompatibleWithReduction( ios:seq> ) { forall i {:trigger ios[i], ios[i+1]} :: 0 <= i < |ios| - 1 ==> LIoOpOrderingOKForAction(ios[i], ios[i+1]) } predicate IsValidLEnvStep(e:LEnvironment, step:LEnvStep) { match step case LEnvStepHostIos(actor, ios) => && (forall io :: io in ios ==> IsValidLIoOp(io, actor, e)) && LIoOpSeqCompatibleWithReduction(ios) case LEnvStepDeliverPacket(p) => p in e.sentPackets case LEnvStepAdvanceTime => true case LEnvStepStutter => true } predicate LEnvironment_Init( e:LEnvironment ) { && |e.sentPackets| == 0 && e.time >= 0 } predicate LEnvironment_PerformIos( e:LEnvironment, e':LEnvironment, actor:IdType, ios:seq> ) { && e'.sentPackets == e.sentPackets + (set io | io in ios && io.LIoOpSend? :: io.s) && (forall io :: io in ios && io.LIoOpReceive? ==> io.r in e.sentPackets) && e'.time == e.time } predicate LEnvironment_AdvanceTime( e:LEnvironment, e':LEnvironment ) { && e'.time > e.time // UNCHANGED && e'.sentPackets == e.sentPackets } predicate LEnvironment_Stutter( e:LEnvironment, e':LEnvironment ) { && e'.time == e.time && e'.sentPackets == e.sentPackets } predicate LEnvironment_Next( e:LEnvironment, e':LEnvironment ) { && IsValidLEnvStep(e, e.nextStep) && match e.nextStep case LEnvStepHostIos(actor, ios) => LEnvironment_PerformIos(e, e', actor, ios) case LEnvStepDeliverPacket(p) => LEnvironment_Stutter(e, e') // this is only relevant for synchrony case LEnvStepAdvanceTime => LEnvironment_AdvanceTime(e, e') case LEnvStepStutter => LEnvironment_Stutter(e, e') } function{:opaque} EnvironmentNextTemporal(b:Behavior>):temporal requires imaptotal(b) ensures forall i {:trigger sat(i, EnvironmentNextTemporal(b))} :: sat(i, EnvironmentNextTemporal(b)) <==> LEnvironment_Next(b[i], b[nextstep(i)]) { stepmap(imap i :: LEnvironment_Next(b[i], b[nextstep(i)])) } predicate LEnvironment_BehaviorSatisfiesSpec( b:Behavior> ) { && imaptotal(b) && LEnvironment_Init(b[0]) && sat(0, always(EnvironmentNextTemporal(b))) } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Common/Framework/EnvironmentSynchrony.s.dfy ================================================ include "Environment.s.dfy" include "../Logic/Temporal/Temporal.s.dfy" include "../Logic/Temporal/Time.s.dfy" include "../Collections/Multisets.s.dfy" module EnvironmentSynchrony_s { import opened Environment_s import opened Temporal__Temporal_s import opened Temporal__Time_s import opened Collections__Maps2_s import opened Collections__Multisets_s function{:opaque} BehaviorToTimeMap( b:Behavior> ):imap requires imaptotal(b) ensures imaptotal(BehaviorToTimeMap(b)) ensures forall i {:trigger BehaviorToTimeMap(b)[i]} :: BehaviorToTimeMap(b)[i] == b[i].time { imap i :: b[i].time } /////////////////////////// // HOST QUEUES /////////////////////////// predicate HostQueue_PerformIos( hostQueue:seq>, hostQueue':seq>, ios:seq> ) { if |ios| == 0 then hostQueue' == hostQueue else if ios[0].LIoOpReceive? then && |hostQueue| > 0 && ios[0] == LIoOpReceive(hostQueue[0]) && HostQueue_PerformIos(hostQueue[1..], hostQueue', ios[1..]) else if ios[0].LIoOpTimeoutReceive? then hostQueue' == hostQueue == [] else hostQueue' == hostQueue } predicate HostQueues_Init( e:LEnvironment ) { && (forall id :: id in e.hostInfo ==> e.hostInfo[id] == LHostInfo([])) && e.time >= 0 } predicate HostQueues_Next( e:LEnvironment, e':LEnvironment ) { match e.nextStep case LEnvStepHostIos(actor, ios) => && actor in e.hostInfo && actor in e'.hostInfo && e'.hostInfo == e.hostInfo[actor := e'.hostInfo[actor]] && LIoOpSeqCompatibleWithReduction(ios) && HostQueue_PerformIos(e.hostInfo[actor].queue, e'.hostInfo[actor].queue, ios) case LEnvStepDeliverPacket(p) => && p in e.sentPackets && p.dst in e.hostInfo && e'.hostInfo == e.hostInfo[p.dst := LHostInfo(e.hostInfo[p.dst].queue + [p])] case LEnvStepAdvanceTime => e'.hostInfo == e.hostInfo case LEnvStepStutter => e'.hostInfo == e.hostInfo } function{:opaque} HostQueuesNextTemporal( b:Behavior> ):temporal requires imaptotal(b) ensures forall i{:trigger sat(i, HostQueuesNextTemporal(b))} :: sat(i, HostQueuesNextTemporal(b)) == HostQueues_Next(b[i], b[nextstep(i)]) { stepmap(imap i :: HostQueues_Next(b[i], b[nextstep(i)])) } predicate HostQueuesLive( b:Behavior> ) requires imaptotal(b) { && HostQueues_Init(b[0]) && sat(0, always(HostQueuesNextTemporal(b))) } /////////////////////////// // SYNCHRONOUS NETWORK /////////////////////////// function{:opaque} PacketDeliveredTemporal( b:Behavior>, p:LPacket ):temporal requires imaptotal(b) ensures forall i {:trigger sat(i, PacketDeliveredTemporal(b, p))} :: sat(i, PacketDeliveredTemporal(b, p)) <==> b[i].nextStep == LEnvStepDeliverPacket(p); { stepmap(imap i :: b[i].nextStep == LEnvStepDeliverPacket(p)) } predicate PacketSentBetweenHosts( e:LEnvironment, p:LPacket, sources:set, destinations:set ) { && e.nextStep.LEnvStepHostIos? && LIoOpSend(p) in e.nextStep.ios && (p.src in sources || e.nextStep.actor in sources) && p.dst in destinations } predicate PacketsSynchronousForHosts( b:Behavior>, i:int, latency_bound:int, sources:set, destinations:set ) requires imaptotal(b) { forall p {:trigger PacketSentBetweenHosts(b[i], p, sources, destinations)} :: p in b[i+1].sentPackets && PacketSentBetweenHosts(b[i], p, sources, destinations) ==> sat(i, next(eventuallynextwithin(PacketDeliveredTemporal(b, p), latency_bound, BehaviorToTimeMap(b)))) } function{:opaque} PacketsSynchronousForHostsTemporal( b:Behavior>, latency_bound:int, sources:set, destinations:set ):temporal requires imaptotal(b) ensures forall i {:trigger sat(i, PacketsSynchronousForHostsTemporal(b, latency_bound, sources, destinations))} :: sat(i, PacketsSynchronousForHostsTemporal(b, latency_bound, sources, destinations)) <==> PacketsSynchronousForHosts(b, i, latency_bound, sources, destinations) { stepmap(imap i :: PacketsSynchronousForHosts(b, i, latency_bound, sources, destinations)) } predicate NetworkSynchronousForHosts( b:Behavior>, start_step:int, latency_bound:int, sources:set, destinations:set ) requires imaptotal(b) { sat(start_step, always(PacketsSynchronousForHostsTemporal(b, latency_bound, sources, destinations))) } /////////////////////////// // TIME NEVER STOPS /////////////////////////// function{:opaque} TimeReachesTemporal( b:Behavior>, t:int ):temporal requires imaptotal(b) ensures forall i {:trigger sat(i, TimeReachesTemporal(b, t))} :: sat(i, TimeReachesTemporal(b, t)) <==> b[i].time >= t { stepmap(imap i :: b[i].time >= t) } predicate NoZenoBehavior( b:Behavior> ) requires imaptotal(b) { forall t :: sat(0, eventual(TimeReachesTemporal(b, t))) } ////////////////////////////// // CLOCK AMBIGUITY LIMITED ////////////////////////////// predicate ClockAmbiguityLimitedForHostsInStep( e:LEnvironment, max_clock_ambiguity:int, hosts:set ) { e.nextStep.LEnvStepHostIos? && e.nextStep.actor in hosts ==> (forall io :: io in e.nextStep.ios && io.LIoOpReadClock? ==> e.time - max_clock_ambiguity <= io.t <= e.time + max_clock_ambiguity) } function{:opaque} ClockAmbiguityLimitedForHostsTemporal( b:Behavior>, max_clock_ambiguity:int, hosts:set ):temporal requires imaptotal(b) ensures forall i{:trigger sat(i, ClockAmbiguityLimitedForHostsTemporal(b, max_clock_ambiguity, hosts))} :: sat(i, ClockAmbiguityLimitedForHostsTemporal(b, max_clock_ambiguity, hosts)) == ClockAmbiguityLimitedForHostsInStep(b[i], max_clock_ambiguity, hosts) { stepmap(imap i :: ClockAmbiguityLimitedForHostsInStep(b[i], max_clock_ambiguity, hosts)) } predicate ClockAmbiguityLimitedForHosts( b:Behavior>, start_step:int, max_clock_ambiguity:int, hosts:set ) requires imaptotal(b) { sat(start_step, always(ClockAmbiguityLimitedForHostsTemporal(b, max_clock_ambiguity, hosts))) } ////////////////////////////// // RATE-LIMITED HOSTS ////////////////////////////// function{:opaque} PacketDeliveredToHostTemporal(b:Behavior>, host:IdType):temporal requires imaptotal(b) ensures forall i {:trigger sat(i, PacketDeliveredToHostTemporal(b, host))} :: sat(i, PacketDeliveredToHostTemporal(b, host)) <==> b[i].nextStep.LEnvStepDeliverPacket? && b[i].nextStep.p.dst == host { stepmap(imap i :: b[i].nextStep.LEnvStepDeliverPacket? && b[i].nextStep.p.dst == host) } function{:opaque} NetworkDeliveryRateForHostBoundedSinceTemporal( b:Behavior>, i:int, burst_size:int, host:IdType ):temporal requires imaptotal(b) ensures forall j{:trigger sat(j, NetworkDeliveryRateForHostBoundedSinceTemporal(b, i, burst_size, host))} :: sat(j, NetworkDeliveryRateForHostBoundedSinceTemporal(b, i, burst_size, host)) <==> countWithin(i, j, PacketDeliveredToHostTemporal(b, host)) <= burst_size { stepmap(imap j :: countWithin(i, j, PacketDeliveredToHostTemporal(b, host)) <= burst_size) } function{:opaque} NetworkDeliveryRateForHostBoundedTemporal( b:Behavior>, burst_size:int, burst_period:int, host:IdType ):temporal requires imaptotal(b) ensures forall i {:trigger sat(i, NetworkDeliveryRateForHostBoundedTemporal(b, burst_size, burst_period, host))} :: sat(i, NetworkDeliveryRateForHostBoundedTemporal(b, burst_size, burst_period, host)) <==> sat(i, alwayswithin(NetworkDeliveryRateForHostBoundedSinceTemporal(b, i, burst_size, host), burst_period, BehaviorToTimeMap(b))) { stepmap(imap i :: sat(i, alwayswithin(NetworkDeliveryRateForHostBoundedSinceTemporal(b, i, burst_size, host), burst_period, BehaviorToTimeMap(b)))) } predicate NetworkDeliveryRateBoundedForHosts( b:Behavior>, start_step:int, burst_size:int, burst_period:int, hosts:set ) requires imaptotal(b) { forall host :: host in hosts ==> sat(start_step, always(NetworkDeliveryRateForHostBoundedTemporal(b, burst_size, burst_period, host))) } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Common/Framework/EnvironmentSynchronyLemmas.i.dfy ================================================ include "EnvironmentSynchrony.s.dfy" include "HostQueueLemmas.i.dfy" include "../Logic/Temporal/Heuristics.i.dfy" include "../Logic/Temporal/Rules.i.dfy" include "../Logic/Temporal/Induction.i.dfy" include "../Logic/Temporal/Time.i.dfy" include "../../../Libraries/Math/mul_auto.i.dfy" include "../Collections/Sets.i.dfy" module Liveness__EnvironmentSynchronyLemmas_i { import opened Environment_s import opened EnvironmentSynchrony_s import opened Liveness__HostQueueLemmas_i import opened Temporal__Temporal_s import opened Temporal__Heuristics_i import opened Temporal__Monotonicity_i import opened Temporal__Rules_i import opened Temporal__Induction_i import opened Temporal__Time_s import opened Temporal__Time_i import opened Collections__Sets_i import opened Collections__Maps2_s import opened Collections__Maps2_i import opened Math__mul_auto_i import opened Math__mul_i function{:opaque} HostQueueEmptyTemporal( b:Behavior>, host:IdType ):temporal requires imaptotal(b) ensures forall i {:trigger sat(i, HostQueueEmptyTemporal(b, host))} :: sat(i, HostQueueEmptyTemporal(b, host)) <==> (host in b[i].hostInfo ==> |b[i].hostInfo[host].queue| == 0) { stepmap(imap i :: host in b[i].hostInfo ==> |b[i].hostInfo[host].queue| == 0) } function{:opaque} PacketInHostQueueTemporal( b:Behavior>, p:LPacket ):temporal requires imaptotal(b) ensures forall i {:trigger sat(i, PacketInHostQueueTemporal(b, p))} :: sat(i, PacketInHostQueueTemporal(b, p)) <==> (p.dst in b[i].hostInfo && p in b[i].hostInfo[p.dst].queue) { stepmap(imap i :: p.dst in b[i].hostInfo && p in b[i].hostInfo[p.dst].queue) } predicate PacketReceivedDuringAction( e:LEnvironment, p:LPacket ) { e.nextStep.LEnvStepHostIos? && LIoOpReceive(p) in e.nextStep.ios } function{:opaque} PacketReceivedTemporal( b:Behavior>, p:LPacket ):temporal requires imaptotal(b) ensures forall i {:trigger sat(i, PacketReceivedTemporal(b, p))} :: sat(i, PacketReceivedTemporal(b, p)) <==> PacketReceivedDuringAction(b[i], p) { stepmap(imap i :: PacketReceivedDuringAction(b[i], p)) } predicate AllPacketsReceivedWithin( b:Behavior>, i:int, receive_period:int, sources:set, destinations:set ) requires imaptotal(b) { forall p {:trigger PacketSentBetweenHosts(b[i], p, sources, destinations)} :: PacketSentBetweenHosts(b[i], p, sources, destinations) ==> sat(i, next(eventuallynextwithin(PacketReceivedTemporal(b, p), receive_period, BehaviorToTimeMap(b)))) } function{:opaque} AllPacketsReceivedWithinTemporal( b:Behavior>, receive_period:int, sources:set, destinations:set ):temporal requires imaptotal(b) ensures forall i {:trigger sat(i, AllPacketsReceivedWithinTemporal(b, receive_period, sources, destinations))} :: sat(i, AllPacketsReceivedWithinTemporal(b, receive_period, sources, destinations)) <==> AllPacketsReceivedWithin(b, i, receive_period, sources, destinations) { stepmap(imap i :: AllPacketsReceivedWithin(b, i, receive_period, sources, destinations)) } predicate ReceiveAttemptedInStep( e:LEnvironment, host:IdType ) { && e.nextStep.LEnvStepHostIos? && e.nextStep.actor == host && |e.nextStep.ios| > 0 && (e.nextStep.ios[0].LIoOpTimeoutReceive? || e.nextStep.ios[0].LIoOpReceive?) } function{:opaque} ReceiveAttemptedTemporal( b:Behavior>, host:IdType ):temporal requires imaptotal(b) ensures forall i {:trigger sat(i, ReceiveAttemptedTemporal(b, host))} :: sat(i, ReceiveAttemptedTemporal(b, host)) <==> ReceiveAttemptedInStep(b[i], host) { stepmap(imap i :: ReceiveAttemptedInStep(b[i], host)) } lemma Lemma_TimeOnlyAdvancesBetweenSteps( b:Behavior>, i:int, j:int ) requires LEnvironment_BehaviorSatisfiesSpec(b) requires 0 <= i <= j ensures b[i].time <= b[j].time decreases j - i { if j > i { Lemma_TimeOnlyAdvancesBetweenSteps(b, i, j-1); TemporalDeduceFromAlways(0, j-1, EnvironmentNextTemporal(b)); } } lemma Lemma_EstablishMonotonicFromOpaque( b:Behavior>, start:int ) requires LEnvironment_BehaviorSatisfiesSpec(b) requires 0 <= start ensures monotonic_from_opaque(start, BehaviorToTimeMap(b)) { var f := BehaviorToTimeMap(b); forall i1, i2 | i1 in f && i2 in f && start <= i1 <= i2 ensures f[i1] <= f[i2] { Lemma_TimeOnlyAdvancesBetweenSteps(b, i1, i2); } reveal monotonic_from_opaque(); } lemma Lemma_IfOpSeqIsCompatibleWithReductionAndFirstIsntReceiveThenNoneAreReceives2( ios:seq> ) requires LIoOpSeqCompatibleWithReduction(ios) ensures |ios| > 0 && !ios[0].LIoOpReceive? && !ios[0].LIoOpTimeoutReceive? ==> (forall io :: io in ios ==> !io.LIoOpReceive? && !io.LIoOpTimeoutReceive?) { if |ios| > 1 && !ios[0].LIoOpReceive? && !ios[0].LIoOpTimeoutReceive? { var i := 0; assert 0 <= i < |ios| - 1; assert LIoOpOrderingOKForAction(ios[i], ios[i+1]); assert ios[1].LIoOpSend?; Lemma_IfOpSeqIsCompatibleWithReductionThenSoIsSuffix(ios, 1); Lemma_IfOpSeqIsCompatibleWithReductionAndFirstIsntReceiveThenNoneAreReceives2(ios[1..]); } } lemma Lemma_ReceiveMakesHostQueueSmaller2( q:seq>, q':seq>, ios:seq>, io:LIoOp ) requires HostQueue_PerformIos(q, q', ios) requires LIoOpSeqCompatibleWithReduction(ios) requires io.LIoOpTimeoutReceive? || io.LIoOpReceive? ensures |q'| <= |q| ensures io in ios ==> |q| == 0 || |q'| < |q| decreases |ios| { if (|ios| == 0) { assert q == q'; assert io !in ios; return; } var io0 := ios[0]; assert ios == [io0] + ios[1..]; if (io0.LIoOpTimeoutReceive?) { assert |q| == 0; } else if (io0.LIoOpReceive?) { Lemma_IfOpSeqIsCompatibleWithReductionThenSoIsSuffix(ios, 1); Lemma_ReceiveMakesHostQueueSmaller2(q[1..], q', ios[1..], io); } else { Lemma_IfOpSeqIsCompatibleWithReductionAndFirstIsntReceiveThenNoneAreReceives2(ios); } } function{:opaque} QueuePosition(q:seq>, p:LPacket):int requires p in q ensures 0 <= QueuePosition(q, p) < |q| { if q[0] == p then 0 else 1 + QueuePosition(q[1..], p) } lemma Lemma_QueuePosition(q:seq>, p:LPacket) requires p in q ensures QueuePosition(q, p) > 0 ==> |q| > 0 && p in q[1..] && QueuePosition(q[1..], p) < QueuePosition(q, p) { reveal QueuePosition(); } lemma Lemma_QueuePositionTail( q:seq>, p:LPacket, q':seq> ) requires p in q ensures QueuePosition(q, p) == QueuePosition(q + q', p) { reveal QueuePosition(); if (q[0] == p) { assert QueuePosition(q, p) == QueuePosition(q + q', p); } else { Lemma_QueuePositionTail(q[1..], p, q'); assert q[1..] + q' == (q + q')[1..]; } } lemma Lemma_DeliverIsInstantaneous( b:Behavior>, i:int, host:IdType ) requires LEnvironment_BehaviorSatisfiesSpec(b) requires 0 <= i ensures sat(i, always(ActionIsInstantaneousTemporal(PacketDeliveredToHostTemporal(b, host), BehaviorToTimeMap(b)))) { var x := PacketDeliveredToHostTemporal(b, host); var f := BehaviorToTimeMap(b); forall j | i <= j ensures sat(j, ActionIsInstantaneousTemporal(x, f)) { if sat(j, x) { TemporalDeduceFromAlways(0, j, EnvironmentNextTemporal(b)); assert f[j] == f[j+1]; } } TemporalAlways(i, ActionIsInstantaneousTemporal(x, f)); } lemma Lemma_ReceiveIsInstantaneous( b:Behavior>, i:int, host:IdType ) requires LEnvironment_BehaviorSatisfiesSpec(b) requires 0 <= i ensures sat(i, always(ActionIsInstantaneousTemporal(ReceiveAttemptedTemporal(b, host), BehaviorToTimeMap(b)))) { var x := ReceiveAttemptedTemporal(b, host); var f := BehaviorToTimeMap(b); forall j | i <= j ensures sat(j, ActionIsInstantaneousTemporal(x, f)); { if sat(j, x) { TemporalDeduceFromAlways(0, j, EnvironmentNextTemporal(b)); assert f[j] == f[j+1]; } } TemporalAlways(i, ActionIsInstantaneousTemporal(x, f)); } lemma Lemma_DeliverIncrReceiveDecr( i1:int, i2:int, b:Behavior>, host:IdType, d:imap ) requires imaptotal(b) requires imaptotal(d) requires LEnvironment_BehaviorSatisfiesSpec(b) requires HostQueuesLive(b) requires TLe(0, i1) requires TLe(i1, i2) requires d[i1] >= 0 requires d[i2] >= 1 requires d == imap i :: if host in b[i].hostInfo then |b[i].hostInfo[host].queue| else 0 ensures || (sat(i2, PacketDeliveredToHostTemporal(b, host)) && !sat(i2, ReceiveAttemptedTemporal(b, host)) && d[i2 + 1] == d[i2] + 1) || (!sat(i2, PacketDeliveredToHostTemporal(b, host)) && sat(i2, ReceiveAttemptedTemporal(b, host)) && d[i2 + 1] < d[i2]) || (!sat(i2, PacketDeliveredToHostTemporal(b, host)) && !sat(i2, ReceiveAttemptedTemporal(b, host)) && d[i2 + 1] == d[i2]) { TemporalAssist(); assert TLe(i1, i1); var incr := PacketDeliveredToHostTemporal(b, host); var decr := ReceiveAttemptedTemporal(b, host); assert TLe(0, i2); assert i2 == i1 || TLe(i1, i2 - 1); assert sat(i2, EnvironmentNextTemporal(b)); var e := b[i2]; var e' := b[i2 + 1]; assert LEnvironment_Next(e, e'); assert HostQueues_Next(e, e'); assert 0 < d[i2]; assert host in e.hostInfo; var q := e.hostInfo[host].queue; if e.nextStep.LEnvStepHostIos? { if e.nextStep.actor != host { assert d[i2 + 1] == d[i2]; } else if ReceiveAttemptedInStep(e, host) { var actor := e.nextStep.actor; var ios := e.nextStep.ios; var io := e.nextStep.ios[0]; var q' := e'.hostInfo[host].queue; Lemma_ReceiveMakesHostQueueSmaller2(q, q', ios, io); assert d[i2 + 1] < d[i2]; } else { assert d[i2+1] == d[i2]; } } else if e.nextStep.LEnvStepDeliverPacket? { var p := e.nextStep.p; if (p.dst == host) { assert d[i2 + 1] == d[i2] + 1; } } } // TODO: merge with Lemma_DeliverIncrReceiveDecr lemma Lemma_DeliverIncr( i1:int, i2:int, b:Behavior>, host:IdType, d:imap ) requires imaptotal(b) requires imaptotal(d) requires LEnvironment_BehaviorSatisfiesSpec(b) requires HostQueuesLive(b) requires TLe(0, i1) requires TLe(i1, i2) requires d[i1] >= 0 requires d == imap i :: if host in b[i].hostInfo then |b[i].hostInfo[host].queue| else 0 ensures || (sat(i2, PacketDeliveredToHostTemporal(b, host)) && d[i2 + 1] == d[i2] + 1) || (!sat(i2, PacketDeliveredToHostTemporal(b, host)) && d[i2 + 1] <= d[i2]) { TemporalAssist(); assert TLe(i1, i1); var incr := PacketDeliveredToHostTemporal(b, host); var decr := ReceiveAttemptedTemporal(b, host); assert TLe(0, i2); assert i2 == i1 || TLe(i1, i2 - 1); assert sat(i2, EnvironmentNextTemporal(b)); var e := b[i2]; var e' := b[i2 + 1]; assert LEnvironment_Next(e, e'); assert HostQueues_Next(e, e'); if (sat(i2, decr)) { if (host in e.hostInfo) { var ios := e.nextStep.ios; var io := e.nextStep.ios[0]; var q := e.hostInfo[host].queue; var q' := e'.hostInfo[host].queue; Lemma_ReceiveMakesHostQueueSmaller2(q, q', ios, io); assert d[i2 + 1] <= d[i2]; } } else if e.nextStep.LEnvStepDeliverPacket? { var p := e.nextStep.p; if (p.dst == host) { assert d[i2 + 1] == d[i2] + 1; } } else if e.nextStep.LEnvStepAdvanceTime? { assert d[i2 + 1] == d[i2]; } else if e.nextStep.LEnvStepHostIos? { assert !sat(i2, PacketDeliveredToHostTemporal(b, host)); var actor := e.nextStep.actor; var ios := e.nextStep.ios; if (host == actor) { if (!sat(i2+1, decr) && |ios| != 0) { if (ios[0].LIoOpReceive?) { assert ReceiveAttemptedInStep(e, host); } } } } } lemma Lemma_HostQueueEmptiesAgain( latency_bound:int, host:IdType, b:Behavior>, i1:int, burst_size:int, receive_period:int ) returns(i2:int) requires imaptotal(b) requires LEnvironment_BehaviorSatisfiesSpec(b) requires HostQueuesLive(b) requires TLe(0, i1) requires 1 <= receive_period requires 1 <= burst_size requires sat(i1, HostQueueEmptyTemporal(b, host)) requires sat(i1, always(eventuallynextwithin(ReceiveAttemptedTemporal(b, host), receive_period, BehaviorToTimeMap(b)))) requires sat(i1, always(NetworkDeliveryRateForHostBoundedTemporal(b, burst_size, burst_size * receive_period + 1, host))) ensures sat(i2, HostQueueEmptyTemporal(b, host)) ensures i1 < i2 ensures forall i :: i1 <= i <= i2 && host in b[i].hostInfo ==> |b[i].hostInfo[host].queue| <= burst_size { var timefun := BehaviorToTimeMap(b); var goal := HostQueueEmptyTemporal(b, host); var d := imap i :: if host in b[i].hostInfo then |b[i].hostInfo[host].queue| else 0; var bs := burst_size; var r := receive_period; var p := bs * r; var incr := PacketDeliveredToHostTemporal(b, host); var decr := ReceiveAttemptedTemporal(b, host); var nIncr:int := bs; var nDecr:int := bs; TemporalAssist(); Lemma_EstablishMonotonicFromOpaque(b, i1); Lemma_DeliverIsInstantaneous(b, i1, host); Lemma_ReceiveIsInstantaneous(b, i1, host); forall ensures 1 <= p { lemma_mul_increases(bs, r); } assert TLe(i1, i1); forall ensures sat(i1, countWithinGe(nDecr, decr, p, timefun)) { Lemma_CountWithinGeOne(i1, decr, r, timefun); Lemma_CountWithinGeMultiple(i1, bs, 1, decr, r, timefun); } forall ensures sat(i1, countWithinLe(nIncr, incr, p, timefun)) { lemma_mul_is_commutative(bs, r); assert sat(i1, always(NetworkDeliveryRateForHostBoundedTemporal(b, burst_size, burst_size * receive_period + 1, host))); assert sat(i1, always(countWithinLe(bs, incr, p + 1, timefun))); assert sat(i1, always(countWithinLe(bs, incr, p, timefun))); } if (d[i1 + 1] == 0) { i2 := i1 + 1; return; } assert sat(i1, PacketDeliveredToHostTemporal(b, host)); assert sat(i1, ActionIsInstantaneousTemporal(PacketDeliveredToHostTemporal(b, host), timefun)); assert timefun[i1] == timefun[i1+1]; if (forall i :: TLe(i1, i) && i1 != i && timefun[i] <= timefun[i1] + p ==> d[i] > 0) { assert TLe(i1, i1); forall i {:trigger TLe(i1, i)} | TLe(i1, i) && i1 != i && timefun[i] <= timefun[i1] + p ensures || (sat(i, incr) && !sat(i, decr) && d[i + 1] == d[i] + 1) || (!sat(i, incr) && sat(i, decr) && d[i + 1] < d[i]) || (!sat(i, incr) && !sat(i, decr) && d[i + 1] == d[i]) { Lemma_DeliverIncrReceiveDecr(i1, i, b, host, d); } forall ensures sat(i1, incr) && !sat(i1, decr) && d[i1 + 1] == d[i1] + 1 { if (!(host in b[i1].hostInfo)) { assert !(host in b[i1 + 1].hostInfo); } if (sat(i1, decr)) { if (host in b[i1].hostInfo) { var ios := b[i1].nextStep.ios; var io := ios[0]; Lemma_ReceiveMakesHostQueueSmaller2(b[i1].hostInfo[host].queue, b[i1 + 1].hostInfo[host].queue, ios, io); } else { } assert false; // proof by contradiction } } i2 := Lemma_CountIncrDecr(i1, d, nIncr, nDecr, incr, decr, p, timefun); var f1 := imap i :: d[i] <= d[i1] + nIncr - nDecr; assert TLe(i1, i2) && sat(i2, stepmap(f1)) && timefun[i2] <= timefun[i1] + p; assert d[i2] <= d[i1]; assert TLe(i1, i2); assert i1 != i2; assert timefun[i2] <= timefun[i1] + p; assert false; // proof by contradiction } i2 :| i1 < i2 && timefun[i2] <= timefun[i1] + p && d[i2] == 0; forall i {:trigger TLe(i1, i)} | TLe(i1, i) && timefun[i] <= timefun[i1] + p ensures || (sat(i, incr) && d[i + 1] == d[i] + 1) || (!sat(i, incr) && d[i + 1] <= d[i]) { Lemma_DeliverIncr(i1, i, b, host, d); } Lemma_CountIncr(i1, d, nIncr, incr, p, timefun); var f2 := imap i :: d[i] <= d[i1] + nIncr; assert sat(i1, alwayswithin(stepmap(f2), p, timefun)); forall i | i1 <= i <= i2 && host in b[i].hostInfo ensures |b[i].hostInfo[host].queue| <= burst_size { Lemma_TimeOnlyAdvancesBetweenSteps(b, i, i2); TemporalDeduceFromAlways(i1, i, untilabsolutetime(stepmap(f2), timefun[i1] + p, timefun)); assert sat(i, stepmap(f2)); } } lemma Lemma_ReceiveAttemptNoDecr( i2:int, i3:int, i4:int, b:Behavior>, p:LPacket, d:imap, r:int, timefun:imap ) requires imaptotal(b) requires imaptotal(timefun) requires LEnvironment_BehaviorSatisfiesSpec(b) requires HostQueuesLive(b) requires TLe(0, i2) requires TLe(i2 + 1, i3) ensures TLe(i3, i4) requires sat(i3, eventuallynextwithin(ReceiveAttemptedTemporal(b, p.dst), r, timefun)) requires d == imap i :: (if TLe(i2, i) && p.dst in b[i].hostInfo && p in b[i].hostInfo[p.dst].queue then 1 + QueuePosition(b[i].hostInfo[p.dst].queue, p) else 0) requires monotonic_from(i3, timefun) requires i4 == earliestActionWithin(i3, ReceiveAttemptedTemporal(b, p.dst), r, timefun) requires d[i3] >= 1 ensures d[i4] == d[i3] decreases i4 - i3 { TemporalAssist(); if (i3 < i4) { assert TLe(0, i3); var e := b[i3]; var e' := b[i3 + 1]; var q := e.hostInfo[p.dst].queue; assert !sat(i3, ReceiveAttemptedTemporal(b, p.dst)); assert LEnvironment_Next(e, e'); assert HostQueues_Next(e, e'); if e.nextStep.LEnvStepDeliverPacket? { var q' := e'.hostInfo[p.dst].queue; if (q != q') { var p' :| q' == q + [p']; Lemma_QueuePositionTail(q, p, [p']); assert d[i3] == d[i3 + 1]; } assert d[i3] == d[i3 + 1]; } else if e.nextStep.LEnvStepAdvanceTime? { assert d[i3] == d[i3 + 1]; } else if e.nextStep.LEnvStepHostIos? { var actor := e.nextStep.actor; var ios := e.nextStep.ios; if (actor == p.dst) { var q' := e'.hostInfo[p.dst].queue; assert HostQueue_PerformIos(q, q', ios); if (|ios| > 0 && ios[0].LIoOpReceive?) { var io := ios[0]; assert ReceiveAttemptedInStep(e, p.dst); } } } assert d[i3] == d[i3 + 1]; var k := TemporalDeduceFromEventual(i3, nextbefore(ReceiveAttemptedTemporal(b, p.dst), timefun[i3] + r, timefun)); assert k != i3; TemporalEventually(i3 + 1, k, nextbefore(ReceiveAttemptedTemporal(b, p.dst), timefun[i3] + r, timefun)); Lemma_ReceiveAttemptNoDecr(i2, i3 + 1, i4, b, p, d, r, timefun); } } lemma Lemma_PromoteInQueue( q:seq>, q':seq>, p:LPacket, ios:seq> ) requires p in q requires HostQueue_PerformIos(q, q', ios) requires (forall i :: 0 <= i < |ios| && ios[i].LIoOpReceive? ==> ios[i].r != p) ensures p in q' ensures QueuePosition(q', p) <= QueuePosition(q, p) ensures |ios| >= 1 && ios[0].LIoOpReceive? ==> QueuePosition(q', p) < QueuePosition(q, p) decreases ios { reveal QueuePosition(); if (|ios| > 0) { var io := ios[0]; if (io.LIoOpReceive?) { Lemma_QueuePosition(q, p); Lemma_PromoteInQueue(q[1..], q', p, ios[1..]); } } } lemma Lemma_ReceiveAttemptDecr( i2:int, i3:int, b:Behavior>, p:LPacket, d:imap, r:int, timefun:imap ) returns(i4:int) requires imaptotal(b) requires imaptotal(timefun) requires LEnvironment_BehaviorSatisfiesSpec(b) requires HostQueuesLive(b) requires TLe(0, i2) requires TLe(i2 + 1, i3) requires monotonic_from(i3, timefun) requires sat(i3, eventuallynextwithin(ReceiveAttemptedTemporal(b, p.dst), r, timefun)) requires d == imap i :: (if TLe(i2, i) && p.dst in b[i].hostInfo && p in b[i].hostInfo[p.dst].queue then 1 + QueuePosition(b[i].hostInfo[p.dst].queue, p) else 0) ensures TLe(i3, i4) ensures sat(i3, actionGoalDecreaseWithin(PacketReceivedTemporal(b, p), d, r, timefun)) { TemporalAssist(); var goal := PacketReceivedTemporal(b, p); i4 := earliestActionWithin(i3, ReceiveAttemptedTemporal(b, p.dst), r, timefun); if (d[i3] != 0) { assert d[i3] == (if TLe(i2, i3) && p.dst in b[i3].hostInfo && p in b[i3].hostInfo[p.dst].queue then 1 + QueuePosition(b[i3].hostInfo[p.dst].queue, p) else 0); assert d[i3] > 0; Lemma_ReceiveAttemptNoDecr(i2, i3, i4, b, p, d, r, timefun); assert d[i3] == d[i4]; assert d[i4] > 0; TemporalDeduceFromAlways(0, i4, HostQueuesNextTemporal(b)); var e := b[i4]; var e' := b[i4 + 1]; var ios := b[i4].nextStep.ios; var io := ios[0]; var q := e.hostInfo[p.dst].queue; Lemma_IfOpSeqIsCompatibleWithReductionAndFirstIsntReceiveThenNoneAreReceives2(ios); assert io.LIoOpTimeoutReceive? || io.LIoOpReceive?; if (ios[0].LIoOpTimeoutReceive?) { assert |q| == 0; } if (ios[0].LIoOpReceive?) { assert p.dst in e'.hostInfo; var q' := e'.hostInfo[p.dst].queue; assert HostQueue_PerformIos(q, q', ios); if (exists i :: 0 <= i < |ios| && ios[i].LIoOpReceive? && ios[i].r == p) { assert sat(i4, goal); } else { Lemma_PromoteInQueue(q, q', p, ios); assert p in q' && QueuePosition(q', p) < QueuePosition(q, p); assert (0 < d[i4 + 1] && d[i4 + 1] < d[i3]); } } assert (0 < d[i4 + 1] && d[i4 + 1] < d[i3]) || sat(i4, goal); assert sat(i3, actionGoalDecreaseWithin(PacketReceivedTemporal(b, p), d, r, timefun)); } } lemma Lemma_HostQueueSizeBoundedAfterEmptyHelper( latency_bound:int, host:IdType, b:Behavior>, i1:int, i2:int, burst_size:int, receive_period:int ) requires imaptotal(b) requires LEnvironment_BehaviorSatisfiesSpec(b) requires HostQueuesLive(b) requires TLe(0, i1) requires TLe(i1, i2) requires 1 <= receive_period requires 1 <= burst_size requires sat(i1, HostQueueEmptyTemporal(b, host)) requires sat(i1, always(eventuallynextwithin(ReceiveAttemptedTemporal(b, host), receive_period, BehaviorToTimeMap(b)))) requires sat(i1, always(NetworkDeliveryRateForHostBoundedTemporal(b, burst_size, burst_size * receive_period + 1, host))) ensures forall i :: i1 <= i <= i2 && host in b[i].hostInfo ==> |b[i].hostInfo[host].queue| <= burst_size decreases i2 - i1 { TemporalAssist(); Lemma_EstablishMonotonicFromOpaque(b, 0); var i1' := Lemma_HostQueueEmptiesAgain(latency_bound, host, b, i1, burst_size, receive_period); if (i1' < i2) { Lemma_HostQueueSizeBoundedAfterEmptyHelper(latency_bound, host, b, i1', i2, burst_size, receive_period); } } function{:opaque} QueueBounded(b:Behavior>, host:IdType, burst_size:int):temporal requires imaptotal(b) ensures forall i{:trigger sat(i, QueueBounded(b, host, burst_size))} :: sat(i, QueueBounded(b, host, burst_size)) <==> (host in b[i].hostInfo ==> |b[i].hostInfo[host].queue| <= burst_size) { stepmap(imap i :: host in b[i].hostInfo ==> |b[i].hostInfo[host].queue| <= burst_size) } lemma Lemma_HostQueueSizeBoundedAfterEmpty( latency_bound:int, host:IdType, b:Behavior>, i1:int, burst_size:int, receive_period:int ) requires imaptotal(b) requires LEnvironment_BehaviorSatisfiesSpec(b) requires HostQueuesLive(b) requires TLe(0, i1) requires 1 <= receive_period requires 1 <= burst_size requires sat(i1, HostQueueEmptyTemporal(b, host)) requires sat(i1, always(eventuallynextwithin(ReceiveAttemptedTemporal(b, host), receive_period, BehaviorToTimeMap(b)))) requires sat(i1, always(NetworkDeliveryRateForHostBoundedTemporal(b, burst_size, burst_size * receive_period + 1, host))) ensures sat(i1, always(QueueBounded(b, host, burst_size))) { TemporalAssist(); forall i2 | TLe(i1, i2) ensures sat(i2, QueueBounded(b, host, burst_size)) { if (host in b[i2].hostInfo) { Lemma_HostQueueSizeBoundedAfterEmptyHelper(latency_bound, host, b, i1, i2, burst_size, receive_period); assert |b[i2].hostInfo[host].queue| <= burst_size; } assert host in b[i2].hostInfo ==> |b[i2].hostInfo[host].queue| <= burst_size; assert sat(i2, stepmap(imap i :: host in b[i].hostInfo ==> |b[i].hostInfo[host].queue| <= burst_size)); assert sat(i2, QueueBounded(b, host, burst_size)); } assert sat(i1, always(QueueBounded(b, host, burst_size))); } lemma Lemma_EventuallyEachHostQueueEmpties( latency_bound:int, destinations:set, b:Behavior>, synchrony_start:int, burst_size:int, receive_period:int ) requires imaptotal(b) requires LEnvironment_BehaviorSatisfiesSpec(b) requires HostQueuesLive(b) requires TLe(0, synchrony_start) requires 1 <= receive_period requires 1 <= burst_size // Starting from the synchrony point, each host attempts to receive a packet at least once every receive_period. // That is, it performs an I/O that's either a Receive or a TimeoutReceive. requires forall host :: host in destinations ==> sat(synchrony_start, always(eventuallynextwithin(ReceiveAttemptedTemporal(b, host), receive_period, BehaviorToTimeMap(b)))) // Starting from the synchrony point, the network stops overwhelming each host with // delivered packets. That is, there are at most burst_size packets delivered to any host during any period // of length <= burst_size * receive_period + 1 requires forall host :: host in destinations ==> sat(synchrony_start, always(NetworkDeliveryRateForHostBoundedTemporal(b, burst_size, burst_size * receive_period + 1, host))) // At some point after the synchrony point, possibly different for each host, that host's queue becomes empty. ensures forall host:: host in destinations ==> sat(synchrony_start, eventual(HostQueueEmptyTemporal(b, host))) { var timefun := BehaviorToTimeMap(b); forall host | host in destinations ensures sat(synchrony_start, eventual(HostQueueEmptyTemporal(b, host))) { // If []t :: <>(goal || d' < d[t]') // and [](0 <= d) // then []<>(goal) // goal = (|Q| == 0) // d = |Q| var i0 := synchrony_start; var goal := HostQueueEmptyTemporal(b, host); var d := imap i :: if host in b[i].hostInfo then |b[i].hostInfo[host].queue| else 0; TemporalAssist(); var start := i0; forall i1 | TLe(i0, i1) ensures sat(i1, nextOrDecrease(goal, d)) { if (!sat(i1, eventual(or(goal, nextDecrease(i1, d))))) { assert forall i :: TLe(i1, i) ==> !sat(i, goal); assert forall i :: TLe(i1, i) ==> !sat(i, nextDecrease(i1, d)); assert forall i :: TLe(i1, i) ==> d[i + 1] >= d[i1]; assert TLe(i1, i1); assert !sat(i1, HostQueueEmptyTemporal(b, host)); assert !(host in b[i1].hostInfo ==> |b[i1].hostInfo[host].queue| == 0); assert d[i1] > 0; Lemma_EstablishMonotonicFromOpaque(b, i1); var bs := burst_size; var r := receive_period; var p := bs * r; forall ensures 1 <= p { lemma_mul_increases(bs, r); } forall ensures 0 <= p * (p + 1) { lemma_mul_nonnegative(p, p + 1); } forall ensures p * (p + 1) == (p + 1) * p { lemma_mul_auto(); } forall ensures bs * p < bs * (p + 1) { lemma_mul_auto(); } // In time p * (p + 1), we'll deliver >= bs * (p + 1) messages // In time (p + 1) * p, we'll receive <= bs * p messages // So in time p * (p + 1) == (p + 1) * p, we'll decrease d by bs // use d >= 1 to prove that delivery decrements // define decr_action as d' = d - 1 // define incr_action as d' = d + 1 // p * (p + 1): |decr_action| >= bs * (p + 1) // p: |decr_action| >= bs // r: |decr_action| >= 1 // (p * 1) * p: |incr_action| <= bs * p // p + 1: |incr_action| <= bs // d' = d + |incr_action| - |decr_action| var incr := PacketDeliveredToHostTemporal(b, host); var decr := ReceiveAttemptedTemporal(b, host); assert TLe(i1, i1); forall ensures sat(i1, countWithinGe(bs * (p + 1), decr, p * (p + 1), timefun)) { Lemma_CountWithinGeOne(i1, decr, r, timefun); Lemma_CountWithinGeMultiple(i1, bs, 1, decr, r, timefun); Lemma_CountWithinGeMultiple(i1, p + 1, bs, decr, p, timefun); } forall ensures sat(i1, countWithinLe(bs * p, incr, p * (p + 1), timefun)) { assert sat(synchrony_start, always(NetworkDeliveryRateForHostBoundedTemporal(b, burst_size, burst_size * receive_period + 1, host))); assert sat(i1, always(NetworkDeliveryRateForHostBoundedTemporal(b, burst_size, burst_size * receive_period + 1, host))); assert sat(i1, always(countWithinLe(bs, incr, p + 1, timefun))); Lemma_DeliverIsInstantaneous(b, i1, host); Lemma_CountWithinLeMultiple(i1, p, bs, incr, p + 1, timefun); } var nIncr:int := bs * p; var nDecr:int := bs * (p + 1); var span := p * (p + 1); assert sat(i1, countWithinLe(nIncr, incr, span, timefun)); assert sat(i1, countWithinGe(nDecr, decr, span, timefun)); forall i2 {:trigger TLe(i1, i2)} | TLe(i1, i2) ensures || (sat(i2, PacketDeliveredToHostTemporal(b, host)) && !sat(i2, ReceiveAttemptedTemporal(b, host)) && d[i2 + 1] == d[i2] + 1) || (!sat(i2, PacketDeliveredToHostTemporal(b, host)) && sat(i2, ReceiveAttemptedTemporal(b, host)) && d[i2 + 1] < d[i2]) || (!sat(i2, PacketDeliveredToHostTemporal(b, host)) && !sat(i2, ReceiveAttemptedTemporal(b, host)) && d[i2 + 1] == d[i2]); { Lemma_DeliverIncrReceiveDecr(i1, i2, b, host, d); } var i2 := Lemma_CountIncrDecr(i1, d, nIncr, nDecr, incr, decr, span, timefun); assert nDecr > 0; assert TLe(i1, i2 - 1); assert nIncr < nDecr; assert d[i2] < d[i1]; assert sat(i2, stepDecrease(i1, d)); assert i2 - 1 + 1 == i2; assert sat(i2 - 1 + 1, stepDecrease(i1, d)); assert sat(i2 - 1, nextDecrease(i1, d)); assert !sat(i2 - 1, nextDecrease(i1, d)); assert false; // proof by contradiction } var i2 :| TLe(i1, i2) && sat(i2, or(goal, nextDecrease(i1, d))); assert sat(i1, eventual(or(goal, nextDecrease(i1, d)))); } assert imaptotal(d); assert forall i :: start <= i ==> 0 <= d[i]; assert sat(start, always(nextOrDecrease(goal, d))); Lemma_EventuallyNext(i0, d, goal); assert sat(start, always(eventual(goal))); } } lemma Lemma_EventuallyAllPacketsAlwaysReceivedInTimeHelper3( synchrony_start:int, latency_bound:int, sources:set, destinations:set, b:Behavior>, burst_size:int, receive_period:int ) returns (processing_bound:int) requires imaptotal(b) requires LEnvironment_BehaviorSatisfiesSpec(b) requires HostQueuesLive(b) requires TLe(0, synchrony_start) requires 1 <= receive_period requires 1 <= burst_size // Eventually we reach a point where packets sent between these hosts are delivered within latency_bound. requires sat(synchrony_start, always(PacketsSynchronousForHostsTemporal(b, latency_bound, sources, destinations))) // Each of the destinations eventually reaches a point where it attempts to receive a packet at least once every receive_period. // That is, it performs an I/O that's either a Receive or a TimeoutReceive. requires forall host :: host in destinations ==> sat(synchrony_start, always(eventuallynextwithin(ReceiveAttemptedTemporal(b, host), receive_period, BehaviorToTimeMap(b)))) requires forall host :: host in destinations ==> sat(synchrony_start, always(QueueBounded(b, host, burst_size))); // Eventually we reach a point where any packet sent between these hosts is received within burst_size * // receive_period after it is sent. ensures sat(synchrony_start, always(AllPacketsReceivedWithinTemporal(b, latency_bound + burst_size * receive_period, sources, destinations))) ensures processing_bound == latency_bound + burst_size * receive_period { forall i1 | TLe(synchrony_start, i1) ensures sat(i1, AllPacketsReceivedWithinTemporal(b, latency_bound + burst_size * receive_period, sources, destinations)) { forall p {:trigger PacketSentBetweenHosts(b[i1], p, sources, destinations)} | PacketSentBetweenHosts(b[i1], p, sources, destinations) ensures sat(i1, next(eventuallynextwithin(PacketReceivedTemporal(b, p), latency_bound + burst_size * receive_period, BehaviorToTimeMap(b)))) { var timefun := BehaviorToTimeMap(b); var bs := burst_size; var r := receive_period; var lb := latency_bound; var goal := PacketReceivedTemporal(b, p); assert p.dst in destinations; forall ensures (exists i2 :: TLe(i1, i2) && sat(i2, PacketDeliveredTemporal(b, p)) && timefun[i2 + 1] <= timefun[i1+1] + lb) { TemporalDeduceFromAlways(synchrony_start, i1, PacketsSynchronousForHostsTemporal(b, latency_bound, sources, destinations)); TemporalDeduceFromAlways(0, i1, EnvironmentNextTemporal(b)); assert p in b[i1 + 1].sentPackets; var i2 := TemporalDeduceFromEventual(i1 + 1, nextbefore(PacketDeliveredTemporal(b, p), timefun[i1 + 1] + lb, timefun)); Lemma_TimeOnlyAdvancesBetweenSteps(b, i2, i2 + 1); } var i2 :| TLe(i1, i2) && sat(i2, PacketDeliveredTemporal(b, p)) && timefun[i2 + 1] <= timefun[i1+1] + lb; TemporalDeduceFromAlways(0, i2, HostQueuesNextTemporal(b)); var d := imap i :: (if TLe(i2, i) && p.dst in b[i].hostInfo && p in b[i].hostInfo[p.dst].queue then 1 + QueuePosition(b[i].hostInfo[p.dst].queue, p) else 0); forall ensures sat(i2 + 1, eventuallynextwithin(goal, r * bs, timefun)) { assert p in b[i2 + 1].hostInfo[p.dst].queue; assert TLe(synchrony_start, i2 + 1); forall i | TLe(synchrony_start, i) && p.dst in b[i].hostInfo ensures |b[i].hostInfo[p.dst].queue| <= bs { TemporalAssist(); assert TLe(synchrony_start, i); TemporalDeduceFromAlways(synchrony_start, i, QueueBounded(b, p.dst, bs)); assert |b[i].hostInfo[p.dst].queue| <= bs; } forall i3 | TLe(i2 + 1, i3) ensures sat(i3, actionGoalDecreaseWithin(goal, d, r, timefun)) { TemporalAssist(); assert TLe(synchrony_start, i3); assert sat(i3, eventuallynextwithin(ReceiveAttemptedTemporal(b, p.dst), r, timefun)); Lemma_EstablishMonotonicFromOpaque(b, i3); reveal monotonic_from_opaque(); var i4 := Lemma_ReceiveAttemptDecr(i2, i3, b, p, d, r, timefun); assert sat(i3, actionGoalDecreaseWithin(goal, d, r, timefun)); } forall ensures sat(i2 + 1, eventuallynextwithinspans(d, goal, r, timefun)) { forall ensures sat(i2 + 1, always(actionGoalDecreaseWithin(goal, d, r, timefun))) { TemporalAssist(); assert forall i3 :: TLe(i2 + 1, i3) ==> sat(i3, actionGoalDecreaseWithin(goal, d, r, timefun)); assert sat(i2 + 1, always(actionGoalDecreaseWithin(goal, d, r, timefun))); } Lemma_EventuallyNextGoalSpans(i2 + 1, d, goal, r, timefun); } forall ensures sat(i2 + 1, eventuallynextwithin(goal, r * bs, timefun)) { TemporalAssist(); assert sat(i2 + 1, eventuallynextwithinspans(d, goal, r, timefun)); assert sat(i2 + 1, eventuallynextwithin(goal, r * d[i2 + 1], timefun)); assert d[i2 + 1] <= bs; forall ensures r * d[i2 + 1] <= r * bs { lemma_mul_inequality_forall(); lemma_mul_auto(); } assert sat(i2 + 1, eventuallynextwithin(goal, r * bs, timefun)); } } forall ensures sat(i1, next(eventuallynextwithin(goal, lb + bs * r, timefun))) { var i3 := TemporalDeduceFromEventual(i2 + 1, nextbefore(goal, timefun[i2 + 1] + (r * bs), timefun)); calc { timefun[i3 + 1]; <= timefun[i2 + 1] + (r * bs); == { lemma_mul_auto(); } timefun[i2 + 1] + (bs * r); <= { assert timefun[i2 + 1] <= timefun[i1 + 1] + lb; } (timefun[i1 + 1] + lb) + (bs * r); == timefun[i1 + 1] + (lb + (bs * r)); } TemporalEventually(i1 + 1, i3, nextbefore(goal, timefun[i1 + 1] + (lb + bs * r), timefun)); } } } forall ensures sat(synchrony_start, always(AllPacketsReceivedWithinTemporal(b, latency_bound + burst_size * receive_period, sources, destinations))) { TemporalAssist(); } processing_bound := latency_bound + burst_size * receive_period; } lemma Lemma_EventuallyAllPacketsAlwaysReceivedInTimeHelper2( synchrony_start:int, i1:int, latency_bound:int, sources:set, destinations:set, b:Behavior>, burst_size:int, receive_period:int ) returns ( processing_sync_start:int, processing_bound:int ) requires imaptotal(b) requires LEnvironment_BehaviorSatisfiesSpec(b) requires HostQueuesLive(b) requires TLe(0, synchrony_start) requires TLe(synchrony_start, i1) requires 1 <= receive_period requires 1 <= burst_size // Eventually we reach a point where packets sent between these hosts are delivered within latency_bound. requires sat(synchrony_start, always(PacketsSynchronousForHostsTemporal(b, latency_bound, sources, destinations))) // Each of the destinations eventually reaches a point where it attempts to receive a packet at least once every receive_period. // That is, it performs an I/O that's either a Receive or a TimeoutReceive. requires forall host :: host in destinations ==> sat(synchrony_start, always(eventuallynextwithin(ReceiveAttemptedTemporal(b, host), receive_period, BehaviorToTimeMap(b)))) // Each of the destinations eventually reaches a point after which the network stops overwhelming it with // delivered packets. That is, there are at most burst_size packets delivered to it during any period // of length <= burst_size * receive_period + 1 requires forall host :: host in destinations ==> sat(synchrony_start, always(NetworkDeliveryRateForHostBoundedTemporal(b, burst_size, burst_size * receive_period + 1, host))) requires forall host :: host in destinations ==> sat(i1, always(QueueBounded(b, host, burst_size))) // Eventually we reach a point where any packet sent between these hosts is received within burst_size * // receive_period after it is sent. ensures synchrony_start <= processing_sync_start ensures processing_bound == latency_bound + burst_size * receive_period ensures sat(processing_sync_start, always(AllPacketsReceivedWithinTemporal(b, latency_bound + burst_size * receive_period, sources, destinations))) { Lemma_AlwaysImpliesLaterAlways(synchrony_start, i1, PacketsSynchronousForHostsTemporal(b, latency_bound, sources, destinations)); forall host | host in destinations ensures sat(i1, always(eventuallynextwithin(ReceiveAttemptedTemporal(b, host), receive_period, BehaviorToTimeMap(b)))) ensures sat(i1, always(NetworkDeliveryRateForHostBoundedTemporal(b, burst_size, burst_size * receive_period + 1, host))) { Lemma_AlwaysImpliesLaterAlways(synchrony_start, i1, eventuallynextwithin(ReceiveAttemptedTemporal(b, host), receive_period, BehaviorToTimeMap(b))); Lemma_AlwaysImpliesLaterAlways(synchrony_start, i1, NetworkDeliveryRateForHostBoundedTemporal(b, burst_size, burst_size * receive_period + 1, host)); } processing_bound := Lemma_EventuallyAllPacketsAlwaysReceivedInTimeHelper3(i1, latency_bound, sources, destinations, b, burst_size, receive_period); processing_sync_start := i1; } lemma Lemma_EventuallyAllPacketsAlwaysReceivedInTime( synchrony_start:int, latency_bound:int, sources:set, destinations:set, b:Behavior>, burst_size:int, receive_period:int ) returns ( processing_sync_start:int, processing_bound:int ) requires imaptotal(b) requires LEnvironment_BehaviorSatisfiesSpec(b) requires HostQueuesLive(b) requires TLe(0, synchrony_start) requires 1 <= receive_period requires 1 <= burst_size // All packets sent between these hosts are delivered within latency_bound. requires NetworkSynchronousForHosts(b, synchrony_start, latency_bound, sources, destinations) // The network does not overwhelm any of the destinations with delivered packets. That is, // there are at most burst_size packets delivered to it during any period of // length <= burst_size * receive_period + 1. requires NetworkDeliveryRateBoundedForHosts(b, synchrony_start, burst_size, burst_size * receive_period + 1, destinations) // Each of the destinations attempts to receive a packet at least once every receive_period. // That is, it performs an I/O that's either a Receive or a TimeoutReceive. requires forall host :: host in destinations ==> sat(synchrony_start, always(eventuallynextwithin(ReceiveAttemptedTemporal(b, host), receive_period, BehaviorToTimeMap(b)))) // Any packet sent between these hosts is received within burst_size * receive_period after it is sent. ensures synchrony_start <= processing_sync_start ensures processing_bound == latency_bound + burst_size * receive_period ensures sat(processing_sync_start, always(AllPacketsReceivedWithinTemporal(b, latency_bound + burst_size * receive_period, sources, destinations))) { Lemma_EventuallyEachHostQueueEmpties(latency_bound, destinations, b, synchrony_start, burst_size, receive_period); forall host | host in destinations ensures exists i0a :: TLe(synchrony_start, i0a) && sat(i0a, always(QueueBounded(b, host, burst_size))) { TemporalAssist(); var i0a :| TLe(synchrony_start, i0a) && sat(i0a, HostQueueEmptyTemporal(b, host)); Lemma_HostQueueSizeBoundedAfterEmpty(latency_bound, host, b, i0a, burst_size, receive_period); } var i0as := set host | host in destinations :: (var i0a :| TLe(synchrony_start, i0a) && sat(i0a, always(QueueBounded(b, host, burst_size))); i0a); var i0s := {synchrony_start} + i0as; var i1 := intsetmax(i0s); assert synchrony_start <= i1; assert forall i :: i in i0as ==> i <= i1; forall host | host in destinations ensures sat(i1, always(QueueBounded(b, host, burst_size))) { var i0a :| i0a in i0as && sat(i0a, always(QueueBounded(b, host, burst_size))); assert i0a <= i1; TemporalAssist(); } processing_sync_start, processing_bound := Lemma_EventuallyAllPacketsAlwaysReceivedInTimeHelper2(synchrony_start, i1, latency_bound, sources, destinations, b, burst_size, receive_period); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Common/Framework/Host.s.dfy ================================================ include "../Native/Io.s.dfy" include "Environment.s.dfy" abstract module Host_s { import opened Native__Io_s import opened Environment_s import opened Native__NativeTypes_s type HostState type ConcreteConfiguration predicate HostInit(host_state:HostState, config:ConcreteConfiguration, id:EndPoint) reads * predicate HostNext(host_state:HostState, host_state':HostState, ios:seq>>) reads * predicate ConcreteConfigInit(config:ConcreteConfiguration) function ConcreteConfigToServers(config:ConcreteConfiguration) : set predicate HostStateInvariants(host_state:HostState, env:HostEnvironment) reads * function ParseCommandLineConfiguration(args:seq>) : ConcreteConfiguration predicate ArbitraryObject(o:object) { true } method HostInitImpl(ghost env:HostEnvironment, netc:NetClient, args:seq>) returns ( ok:bool, host_state:HostState ) requires env.Valid() requires env.ok.ok() requires netc.IsOpen() requires netc.env == env requires ValidPhysicalAddress(EndPoint(netc.MyPublicKey())) modifies set x:object | ArbitraryObject(x) // Everything! ensures ok ==> env.Valid() && env.ok.ok() ensures ok ==> HostStateInvariants(host_state, env) ensures ok ==> var id := EndPoint(netc.MyPublicKey()); var config := ParseCommandLineConfiguration(args); && id in ConcreteConfigToServers(config) && ConcreteConfigInit(config) && HostInit(host_state, config, id) ensures env.net.history() == old(env.net.history()) // Prohibit HostInitImpl from sending (and receiving) packets method HostNextImpl(ghost env:HostEnvironment, host_state:HostState) returns ( ok:bool, host_state':HostState, ghost recvs:seq, ghost clocks:seq, ghost sends:seq, ghost ios:seq>> ) requires env.Valid() && env.ok.ok() requires HostStateInvariants(host_state, env) modifies set x:object | ArbitraryObject(x) // Everything! ensures ok <==> env.Valid() && env.ok.ok() ensures ok ==> HostStateInvariants(host_state', env) ensures ok ==> HostNext(host_state, host_state', ios) // Connect the low-level IO events to the spec-level IO events ensures ok ==> recvs + clocks + sends == ios // These obligations enable us to apply reduction // Even when !ok, if sent is non-empty, we need to return valid set of sent packets too ensures (ok || |sends| > 0) ==> env.net.history() == old(env.net.history()) + (recvs + clocks + sends) ensures forall e :: && (e in recvs ==> e.LIoOpReceive?) && (e in clocks ==> e.LIoOpReadClock? || e.LIoOpTimeoutReceive?) && (e in sends ==> e.LIoOpSend?) ensures |clocks| <= 1 } ================================================ FILE: ironfleet/src/Dafny/Distributed/Common/Framework/HostQueueLemmas.i.dfy ================================================ include "Environment.s.dfy" include "EnvironmentSynchrony.s.dfy" include "../Logic/Temporal/Heuristics.i.dfy" include "../Logic/Temporal/Rules.i.dfy" include "../Logic/Temporal/Induction.i.dfy" module Liveness__HostQueueLemmas_i { import opened Environment_s import opened EnvironmentSynchrony_s import opened Temporal__Heuristics_i import opened Temporal__Rules_i import opened Temporal__Induction_i import opened Collections__Maps2_s predicate LEnvironmentInvariant( e:LEnvironment ) { forall p, id :: id in e.hostInfo && p in e.hostInfo[id].queue ==> p in e.sentPackets } lemma Lemma_LEnvironmentInitEstablishesInvariant( e:LEnvironment ) requires LEnvironment_Init(e) requires HostQueues_Init(e) ensures LEnvironmentInvariant(e) { } lemma Lemma_HostQueuePerformIosProducesTail( hostQueue:seq>, hostQueue':seq>, ios:seq> ) returns (i:int) requires HostQueue_PerformIos(hostQueue, hostQueue', ios) ensures 0 <= i <= |hostQueue| ensures hostQueue' == hostQueue[i..] { if |ios| > 0 && ios[0].LIoOpReceive? { var j := Lemma_HostQueuePerformIosProducesTail(hostQueue[1..], hostQueue', ios[1..]); i := j + 1; } else { i := 0; } } lemma Lemma_LEnvironmentNextPreservesInvariant( e:LEnvironment, e':LEnvironment ) requires LEnvironmentInvariant(e) requires LEnvironment_Next(e, e') requires HostQueues_Next(e, e') ensures LEnvironmentInvariant(e') { if e.nextStep.LEnvStepHostIos? { var actor := e.nextStep.actor; var ios := e.nextStep.ios; forall p, id | id in e'.hostInfo && p in e'.hostInfo[id].queue ensures p in e'.sentPackets { assert id in mapdomain(e'.hostInfo); assert id in e.hostInfo; if (id == actor) { assert HostQueue_PerformIos(e.hostInfo[id].queue, e'.hostInfo[id].queue, ios); var i := Lemma_HostQueuePerformIosProducesTail(e.hostInfo[id].queue, e'.hostInfo[id].queue, ios); assert p in e'.hostInfo[id].queue ==> p in e.hostInfo[id].queue; assert p in e'.sentPackets; } else { assert e'.hostInfo[id].queue == e.hostInfo[id].queue; assert p in e'.sentPackets; } } } } lemma Lemma_IfOpSeqIsCompatibleWithReductionThenSoIsSuffix( ios:seq>, j:int ) requires LIoOpSeqCompatibleWithReduction(ios) requires 0 <= j <= |ios| ensures LIoOpSeqCompatibleWithReduction(ios[j..]) { forall i | 0 <= i < |ios[j..]| - 1 ensures LIoOpOrderingOKForAction(ios[j..][i], ios[j..][i+1]) { assert ios[j..][i] == ios[j+i]; assert ios[j..][i+1] == ios[j+i+1]; } } lemma Lemma_IfOpSeqIsCompatibleWithReductionAndFirstIsntReceiveThenNoneAreReceives( ios:seq> ) requires LIoOpSeqCompatibleWithReduction(ios) ensures |ios| > 0 && !ios[0].LIoOpReceive? ==> (forall io :: io in ios ==> !io.LIoOpReceive?) { if |ios| > 1 && !ios[0].LIoOpReceive? { var i := 0; assert 0 <= i < |ios| - 1; assert LIoOpOrderingOKForAction(ios[i], ios[i+1]); assert ios[1].LIoOpSend?; Lemma_IfOpSeqIsCompatibleWithReductionThenSoIsSuffix(ios, 1); Lemma_IfOpSeqIsCompatibleWithReductionAndFirstIsntReceiveThenNoneAreReceives(ios[1..]); } } predicate HostQueueDecomposition( hostQueue:seq>, hostQueue':seq>, s1:seq>, s2:seq>, p:LPacket ) { hostQueue == s1 + [p] + s2 + hostQueue' } lemma Lemma_ReceiveRemovesPacketFromHostQueue( hostQueue:seq>, hostQueue':seq>, ios:seq>, p:LPacket ) requires HostQueue_PerformIos(hostQueue, hostQueue', ios) requires LIoOpReceive(p) in ios requires LIoOpSeqCompatibleWithReduction(ios) ensures exists s1, s2 :: HostQueueDecomposition(hostQueue, hostQueue', s1, s2, p) { if (!ios[0].LIoOpReceive?) { Lemma_IfOpSeqIsCompatibleWithReductionAndFirstIsntReceiveThenNoneAreReceives(ios); assert false; } if ios[0].r == p { assert hostQueue[0] == p; var j := Lemma_HostQueuePerformIosProducesTail(hostQueue[1..], hostQueue', ios[1..]); assert 0 <= j <= |hostQueue[1..]| && hostQueue' == hostQueue[1..][j..]; var s1 := []; var s2 := hostQueue[1..j+1]; calc { hostQueue; [hostQueue[0]] + hostQueue[1..]; [hostQueue[0]] + hostQueue[1..j+1] + hostQueue[j+1..]; [hostQueue[0]] + hostQueue[1..j+1] + hostQueue[1..][j..]; } assert HostQueueDecomposition(hostQueue, hostQueue', s1, s2, p); return; } Lemma_IfOpSeqIsCompatibleWithReductionThenSoIsSuffix(ios, 1); Lemma_ReceiveRemovesPacketFromHostQueue(hostQueue[1..], hostQueue', ios[1..], p); var s1', s2 :| hostQueue[1..] == s1' + [p] + s2 + hostQueue'; var j := Lemma_HostQueuePerformIosProducesTail(hostQueue[1..], hostQueue', ios[1..]); assert 0 <= j <= |hostQueue[1..]| && hostQueue' == hostQueue[1..][j..]; calc { hostQueue; [hostQueue[0]] + hostQueue[1..]; [hostQueue[0]] + s1' + [p] + s2 + hostQueue'; } var s1 := [hostQueue[0]] + s1'; assert HostQueueDecomposition(hostQueue, hostQueue', s1, s2, p); } lemma Lemma_RemovePacketFromHostQueueImpliesReceive( hostQueue:seq>, hostQueue':seq>, ios:seq>, p:LPacket ) requires HostQueue_PerformIos(hostQueue, hostQueue', ios) requires exists s1, s2 :: HostQueueDecomposition(hostQueue, hostQueue', s1, s2, p) requires LIoOpSeqCompatibleWithReduction(ios) ensures LIoOpReceive(p) in ios { var s1, s2 :| HostQueueDecomposition(hostQueue, hostQueue', s1, s2, p); if |s1| > 0 { if (!ios[0].LIoOpReceive?) { Lemma_IfOpSeqIsCompatibleWithReductionAndFirstIsntReceiveThenNoneAreReceives(ios); assert false; } assert HostQueue_PerformIos(hostQueue[1..], hostQueue', ios[1..]); assert HostQueueDecomposition(hostQueue[1..], hostQueue', s1[1..], s2, p); Lemma_IfOpSeqIsCompatibleWithReductionThenSoIsSuffix(ios, 1); Lemma_RemovePacketFromHostQueueImpliesReceive(hostQueue[1..], hostQueue', ios[1..], p); } } lemma Lemma_ReceiveMakesHostQueueSmaller( hostQueue:seq>, hostQueue':seq>, ios:seq>, p:LPacket ) requires HostQueue_PerformIos(hostQueue, hostQueue', ios) requires LIoOpReceive(p) in ios requires LIoOpSeqCompatibleWithReduction(ios) ensures |hostQueue'| < |hostQueue| { Lemma_ReceiveRemovesPacketFromHostQueue(hostQueue, hostQueue', ios, p); } lemma Lemma_HostQueuePerformIosReceivesFromHostQueue( hostQueue:seq>, hostQueue':seq>, ios:seq> ) requires HostQueue_PerformIos(hostQueue, hostQueue', ios) requires LIoOpSeqCompatibleWithReduction(ios) ensures forall io :: io in ios && io.LIoOpReceive? ==> io.r in hostQueue decreases |ios| { if |ios| == 0 { } else if ios[0].LIoOpReceive? { assert ios[0].r in hostQueue; Lemma_IfOpSeqIsCompatibleWithReductionThenSoIsSuffix(ios, 1); Lemma_HostQueuePerformIosReceivesFromHostQueue(hostQueue[1..], hostQueue', ios[1..]); } else { Lemma_IfOpSeqIsCompatibleWithReductionAndFirstIsntReceiveThenNoneAreReceives(ios); } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Common/Framework/Main.s.dfy ================================================ include "../../Common/Native/Io.s.dfy" include "DistributedSystem.s.dfy" include "AbstractService.s.dfy" include "../Collections/Seqs.s.dfy" abstract module Main_s { import opened Native__Io_s import opened Native__NativeTypes_s import opened DS_s : DistributedSystem_s import opened AS_s : AbstractService_s import opened Collections__Seqs_s method IronfleetMain(ghost env:HostEnvironment, netc:NetClient, args:seq>) requires env.Valid() && env.ok.ok() requires env.net.history() == [] requires netc.IsOpen() requires netc.env == env requires ValidPhysicalAddress(EndPoint(netc.MyPublicKey())) modifies set x:object | DS_s.H_s.ArbitraryObject(x) // Everything! decreases * { var ok, host_state := DS_s.H_s.HostInitImpl(env, netc, args); var config := DS_s.H_s.ParseCommandLineConfiguration(args); var id := EndPoint(netc.MyPublicKey()); assert ok ==> DS_s.H_s.HostInit(host_state, config, id); while (ok) invariant ok ==> DS_s.H_s.HostStateInvariants(host_state, env) invariant ok ==> env.Valid() && env.ok.ok() decreases * { ghost var old_net_history := env.net.history(); ghost var old_state := host_state; ghost var recvs, clocks, sends, ios; ok, host_state, recvs, clocks, sends, ios := DS_s.H_s.HostNextImpl(env, host_state); if ok { // Correctly executed one action assert DS_s.H_s.HostNext(old_state, host_state, ios); // Connect the low-level IO events to the spec-level IO events assert recvs + clocks + sends == ios; // These obligations enable us to apply reduction assert env.net.history() == old_net_history + recvs + clocks + sends; assert forall e :: && (e in recvs ==> e.LIoOpReceive?) && (e in clocks ==> e.LIoOpReadClock? || e.LIoOpTimeoutReceive?) && (e in sends ==> e.LIoOpSend?); assert |clocks| <= 1; } } } lemma RefinementProof(config:DS_s.H_s.ConcreteConfiguration, db:seq) returns (sb:seq) requires |db| > 0 requires DS_Init(db[0], config) requires forall i {:trigger DS_Next(db[i], db[i+1])} :: 0 <= i < |db| - 1 ==> DS_Next(db[i], db[i+1]) ensures |db| == |sb| ensures Service_Init(sb[0], Collections__Maps2_s.mapdomain(db[0].servers)) ensures forall i {:trigger Service_Next(sb[i], sb[i+1])} :: 0 <= i < |sb| - 1 ==> sb[i] == sb[i+1] || Service_Next(sb[i], sb[i+1]) ensures forall i :: 0 <= i < |db| ==> Service_Correspondence(db[i].environment.sentPackets, sb[i]) } ================================================ FILE: ironfleet/src/Dafny/Distributed/Common/Logic/Option.i.dfy ================================================ module Logic__Option_i { datatype Option = Some(v:T) | None } ================================================ FILE: ironfleet/src/Dafny/Distributed/Common/Logic/Temporal/Heuristics.i.dfy ================================================ include "Temporal.s.dfy" include "../../Collections/Maps2.i.dfy" module Temporal__Heuristics_i { import opened Temporal__Temporal_s import opened Collections__Maps2_i //////////////////// // DEFINITIONS //////////////////// function TBlast(i:int):bool { true } //////////////////// // LEMMAS //////////////////// // Conservative heuristics; not complete // (e.g. won't prove <>[]A ==> []<>A) lemma TemporalAssist() ensures forall i:int, x:temporal {:trigger sat(i, always(x))} :: sat(i, always(x)) == (forall j:int :: TLe(i, j) ==> sat(j, x)) ensures forall i:int, x:temporal {:trigger sat(i, eventual(x))} :: sat(i, eventual(x)) == (exists j:int :: TLe(i, j) && sat(j, x)) ensures TLe(0, 0) { forall i:int, x:temporal {:trigger sat(i, always(x))} ensures sat(i, always(x)) == (forall j:int :: TLe(i, j) ==> sat(j, x)) { reveal always(); var f := imap ii{:trigger sat(ii, always(x))} :: forall j {:trigger sat(j, x)} :: ii <= j ==> sat(j, x); calc { sat(i, always(x)); sat(i, stepmap(f)); f[i]; } } forall i:int, x:temporal {:trigger sat(i, eventual(x))} ensures sat(i, eventual(x)) == (exists j:int :: TLe(i, j) && sat(j, x)) { reveal eventual(); } } // Moderately aggressive heuristics lemma TemporalBlast() ensures forall i:int, x:temporal {:trigger sat(i, always(x))} :: sat(i, always(x)) == (forall j:int :: TLe(i, j) ==> sat(j, x)) ensures forall i:int, x:temporal {:trigger sat(i, eventual(x))} :: sat(i, eventual(x)) == (exists j:int :: TLe(i, j) && sat(j, x)) ensures forall i:int, j1:int, j2:int {:trigger TLe(i, j1), TLe(i, j2)} :: TLe(j1, j2) || TLe(j2, j1) ensures TLe(0, 0) { forall i:int, x:temporal {:trigger sat(i, always(x))} ensures sat(i, always(x)) == (forall j:int :: TLe(i, j) ==> sat(j, x)) { reveal always(); var f := imap ii{:trigger sat(ii, always(x))} :: forall j {:trigger sat(j, x)} :: ii <= j ==> sat(j, x); calc { sat(i, always(x)); sat(i, stepmap(f)); f[i]; } } forall i:int, x:temporal {:trigger sat(i, eventual(x))} ensures sat(i, eventual(x)) == (exists j:int :: TLe(i, j) && sat(j, x)) { reveal eventual(); } } // Most aggressive heuristics; might not terminate // (e.g. won't terminate on invalid formula <>[](A || B) ==> <>[]A || <>[]B) lemma TemporalFullBlast() ensures forall i:int, x:temporal {:trigger sat(i, always(x))} :: sat(i, always(x)) == (forall j:int {:trigger sat(j, x)}{:trigger TBlast(j)} :: TBlast(j) ==> i <= j ==> sat(j, x)) ensures forall i:int, x:temporal {:trigger sat(i, eventual(x))} :: sat(i, eventual(x)) == (exists j:int {:trigger sat(j, x)}{:trigger TBlast(j)} :: TBlast(j) && i <= j && sat(j, x)) ensures TBlast(0) { forall i:int, x:temporal {:trigger sat(i, always(x))} ensures sat(i, always(x)) == (forall j:int :: TLe(i, j) ==> sat(j, x)) { reveal always(); var f := imap ii{:trigger sat(ii, always(x))} :: forall j {:trigger sat(j, x)} :: ii <= j ==> sat(j, x); calc { sat(i, always(x)); sat(i, stepmap(f)); f[i]; } } forall i:int, x:temporal {:trigger sat(i, eventual(x))} ensures sat(i, eventual(x)) == (exists j:int :: TLe(i, j) && sat(j, x)) { reveal eventual(); } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Common/Logic/Temporal/Induction.i.dfy ================================================ include "Temporal.s.dfy" include "Heuristics.i.dfy" include "Rules.i.dfy" module Temporal__Induction_i { import opened Temporal__Temporal_s import opened Temporal__Heuristics_i import opened Temporal__Rules_i lemma TemporalInductionNextPartial(i1:int, i2:int, x:temporal) requires sat(i1, x) requires forall j :: i1 <= j ==> sat(j, imply(x, next(x))) ensures forall j :: i1 <= j <= i2 ==> sat(j, x) decreases i2 - i1 { TemporalAssist(); if (i1 < i2) { assert sat(i1, always(imply(x, next(x)))); assert sat(i1, imply(x, next(x))); TemporalInductionNextPartial(nextstep(i1), i2, x); } } lemma TemporalInductionNext(i:int, x:temporal) requires sat(i, x) requires forall j :: i <= j ==> sat(j, imply(x, next(x))) ensures sat(i, always(x)) { TemporalAssist(); forall k | i <= k ensures sat(k, x) { reveal imply(); reveal next(); TemporalInductionNextPartial(i, k, x); } assert sat(i, always(x)); } lemma TemporalInductionPartial(i1:int, i2:int, x:temporal) requires sat(i1, x) requires sat(i1, always(stepmap(imap j :: sat(j, x) ==> sat(nextstep(j), x)))) ensures forall j :: i1 <= j <= i2 ==> sat(j, x) decreases i2 - i1 { TemporalAssist(); if (i1 < i2) { assert sat(i1, stepmap(imap j :: sat(j, x) ==> sat(nextstep(j), x))); TemporalInductionPartial(nextstep(i1), i2, x); } } // A && [](A ==> ()A) ==> []A lemma TemporalInduction(i:int, x:temporal) requires sat(i, x) requires sat(i, always(stepmap(imap j :: sat(j, x) ==> sat(nextstep(j), x)))) ensures sat(i, always(x)) { assert sat(i, always(stepmap(imap j :: sat(j, x) ==> sat(nextstep(j), x)))); TemporalAssist(); forall j | i <= j ensures sat(j, x) { TemporalInductionPartial(i, j, x); } } lemma TemporalInductionNextWithInvariantPartial(i1:int, i2:int, x:temporal, inv:temporal) requires sat(i1, x) requires sat(i1, always(inv)) requires sat(i1, always(imply(and(x, inv), next(x)))) ensures forall j :: i1 <= j <= i2 ==> sat(j, x) decreases i2 - i1 { TemporalAssist(); if (i1 < i2) { assert sat(i1, always(imply(and(x, inv), next(x)))); assert sat(i1, imply(and(x, inv), next(x))); assert sat(i1, imply(x, next(x))); TemporalInductionNextWithInvariantPartial(nextstep(i1), i2, x, inv); } } lemma TemporalInductionNextWithInvariant(i:int, x:temporal, inv:temporal) requires sat(i, x) requires sat(i, always(inv)) requires sat(i, always(imply(and(x, inv), next(x)))) ensures sat(i, always(x)) { assert sat(i, always(imply(and(x, inv), next(x)))); TemporalAssist(); forall j | i <= j ensures sat(j, x) { TemporalInductionNextWithInvariantPartial(i, j, x, inv); } assert sat(i, always(x)); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Common/Logic/Temporal/LeadsTo.i.dfy ================================================ include "Heuristics.i.dfy" include "Rules.i.dfy" include "Time.i.dfy" include "../../../../Libraries/Math/mul.i.dfy" module Temporal__LeadsTo_i { import opened Temporal__Temporal_s import opened Temporal__Heuristics_i import opened Temporal__Rules_i import opened Temporal__Time_s import opened Temporal__Time_i import opened Collections__Maps2_s import opened Collections__Maps2_i import opened Math__mul_i ////////////////// // DEFINITIONS ////////////////// function leadsto(x:temporal, y:temporal):temporal { always(imply(x, eventual(y))) } function leadstowithin(x:temporal, y:temporal, t:int, timefun:imap):temporal requires imaptotal(timefun) { always(imply(x, eventuallywithin(y, t, timefun))) } function leadstonextwithin(x:temporal, action:temporal, t:int, timefun:imap):temporal requires imaptotal(timefun) { always(imply(x, eventuallynextwithin(action, t, timefun))) } function leadstonextwithinnext(x:temporal, action:temporal, t:int, timefun:imap):temporal requires imaptotal(timefun) { always(imply(x, next(eventuallynextwithin(action, t, timefun)))) } ////////////////// // LEMMAS ////////////////// lemma TransitivityOfLeadsTo(i:int, x:temporal, y:temporal, z:temporal) requires sat(i, leadsto(x, y)) requires sat(i, leadsto(y, z)) ensures sat(i, leadsto(x, z)) { forall j | TLe(i, j) ensures sat(j, imply(x, eventual(z))) { if sat(j, x) { TemporalDeduceFromAlways(i, j, imply(x, eventual(y))); var k := TemporalDeduceFromEventual(j, y); TemporalDeduceFromAlways(i, k, imply(y, eventual(z))); var m := TemporalDeduceFromEventual(k, z); TemporalEventually(j, m, z); } } TemporalAlways(i, imply(x, eventual(z))); } lemma TransitivityOfLeadsToGeneral() ensures forall i:int, x:temporal, y:temporal, z:temporal :: sat(i, leadsto(x, y)) && sat(i, leadsto(y, z)) ==> sat(i, leadsto(x, z)) { forall i:int, x:temporal, y:temporal, z:temporal | sat(i, leadsto(x, y)) && sat(i, leadsto(y, z)) { TransitivityOfLeadsTo(i, x, y, z); } } lemma TransitivityOfLeadsToWithin(i:int, x:temporal, y:temporal, z:temporal, t1:int, t2:int, timefun:imap) requires imaptotal(timefun) requires sat(i, leadstowithin(x, y, t1, timefun)) requires sat(i, leadstowithin(y, z, t2, timefun)) ensures sat(i, leadstowithin(x, z, t1 + t2, timefun)) { TemporalAssist(); forall j | TLe(i, j) && sat(j, x) ensures sat(j, eventuallywithin(z, t1 + t2, timefun)) { assert sat(j, eventuallywithin(y, t1, timefun)); assert sat(j, eventual(beforeabsolutetime(y, timefun[j] + t1, timefun))); var k :| TLe(j, k) && sat(k, beforeabsolutetime(y, timefun[j] + t1, timefun)); assert TLe(i, k); assert sat(k, eventuallywithin(z, t2, timefun)); assert sat(k, eventual(beforeabsolutetime(z, timefun[j] + t1 + t2, timefun))); var l :| TLe(k, l) && sat(l, beforeabsolutetime(z, timefun[j] + t1 + t2, timefun)); assert TLe(j, l); assert sat(j, eventuallywithin(z, t1 + t2, timefun)); } } lemma LeadsToDistributesOverOr(i:int, x:temporal, y:temporal, z:temporal) requires sat(i, leadsto(x, z)) requires sat(i, leadsto(y, z)) ensures sat(i, leadsto(or(x, y), z)) { TemporalAssist(); } lemma Lemma_EventuallyXMeansEventuallyY(i:int, x:temporal, y:temporal) requires sat(i, eventual(x)) requires sat(i, leadsto(x, y)) ensures sat(i, eventual(y)) { TemporalAssist(); } lemma Lemma_AlwaysEventuallyXAndXLeadsToYMeansAlwaysEventuallyY(i:int, x:temporal, y:temporal) requires sat(i, always(eventual(x))) requires sat(i, leadsto(x, y)) ensures sat(i, always(eventual(y))) { TemporalAssist(); forall j | TLe(i, j) ensures sat(j, eventual(y)) { Lemma_EventuallyXMeansEventuallyY(j, x, y); } } lemma Lemma_LeadsToNextWithinImpliesLeadsToOtherNextWithin( i:int, x:temporal, action1:temporal, action2:temporal, t:int, timefun:imap ) requires imaptotal(timefun) requires sat(i, leadstonextwithin(x, action1, t, timefun)) requires sat(i, always(imply(action1, action2))) ensures sat(i, leadstonextwithin(x, action2, t, timefun)) { TemporalAssist(); forall j | TLe(i, j) && sat(j, x) ensures sat(j, eventuallynextwithin(action2, t, timefun)) { var k :| TLe(j, k) && sat(k, nextbefore(action1, timefun[j] + t, timefun)); assert TLe(i, k); } } lemma Lemma_LeadsToNextWithinNextImpliesLeadsToOtherNextWithinNext( i:int, x:temporal, action1:temporal, action2:temporal, t:int, timefun:imap ) requires imaptotal(timefun) requires sat(i, leadstonextwithinnext(x, action1, t, timefun)) requires sat(i, always(imply(action1, action2))) ensures sat(i, leadstonextwithinnext(x, action2, t, timefun)) { TemporalAssist(); forall j | TLe(i, j) && sat(j, x) ensures sat(j, next(eventuallynextwithin(action2, t, timefun))); { var k :| TLe(nextstep(j), k) && sat(k, nextbefore(action1, timefun[nextstep(j)] + t, timefun)); assert TLe(i, k); } } lemma Lemma_LeadsToTwoWays(i:int, x:temporal, y:temporal, z:temporal) requires sat(i, leadsto(x, or(y, z))) requires sat(i, leadsto(y, z)) ensures sat(i, leadsto(x, z)) { TemporalAssist(); TransitivityOfLeadsTo(i, x, or(y, z), z); } lemma Lemma_LeadsToWithinPossiblyImmediate(i:int, x:temporal, y:temporal, t:int, timefun:imap) requires imaptotal(timefun) requires sat(i, leadstowithin(x, y, t, timefun)) requires t >= 0 ensures sat(i, leadstowithin(or(x, y), y, t, timefun)) { TemporalAssist(); forall j | TLe(i, j) ensures sat(j, imply(or(x, y), eventuallywithin(y, t, timefun))) { if sat(j, y) { TemporalEventually(j, j, beforeabsolutetime(y, timefun[j] + t, timefun)); } } } lemma Lemma_LeadsToWithinImpliesLeadsToConsequenceWithin(i:int, x:temporal, y:temporal, z:temporal, t:int, timefun:imap) requires imaptotal(timefun) requires sat(i, leadstowithin(x, y, t, timefun)) requires sat(i, always(imply(y, z))) ensures sat(i, leadstowithin(x, z, t, timefun)) { TemporalAssist(); forall j | TLe(i, j) && sat(j, x) ensures sat(j, eventuallywithin(z, t, timefun)) { var k :| TLe(j, k) && sat(k, beforeabsolutetime(y, timefun[j] + t, timefun)); assert TLe(i, k); } } lemma Lemma_LeadsToWithinTwoWays(i:int, x:temporal, y:temporal, z:temporal, t1:int, t2:int, timefun:imap) requires imaptotal(timefun) requires sat(i, leadstowithin(x, or(y, z), t1, timefun)) requires sat(i, leadstowithin(y, z, t2, timefun)) requires t2 >= 0 ensures sat(i, leadstowithin(x, z, t1+t2, timefun)) { Lemma_LeadsToWithinPossiblyImmediate(i, y, z, t2, timefun); TransitivityOfLeadsToWithin(i, x, or(y, z), z, t1, t2, timefun); } lemma Lemma_LeadsToTwoPossibilitiesWithin(i:int, w:temporal, x:temporal, y:temporal, z:temporal, t1:int, t2:int, timefun:imap) requires imaptotal(timefun) requires sat(i, leadstowithin(w, or(x, z), t1, timefun)) requires sat(i, leadstowithin(x, or(y, z), t2, timefun)) requires t2 >= 0 ensures sat(i, leadstowithin(w, or(y, z), t1+t2, timefun)) { forall j | i <= j ensures sat(j, imply(or(x, z), or(x, or(y, z)))); { } TemporalAlways(i, imply(or(x, z), or(x, or(y, z)))); Lemma_LeadsToWithinImpliesLeadsToConsequenceWithin(i, w, or(x, z), or(x, or(y, z)), t1, timefun); Lemma_LeadsToWithinPossiblyImmediate(i, x, or(y, z), t2, timefun); TransitivityOfLeadsToWithin(i, w, or(x, or(y, z)), or(y, z), t1, t2, timefun); } lemma Lemma_LeadsToTwoPossibilitiesWithinWithFirstStepAnAction(i:int, w:temporal, x:temporal, y:temporal, z:temporal, t1:int, t2:int, timefun:imap) requires imaptotal(timefun) requires sat(i, always(imply(w, or(eventuallynextwithin(x, t1, timefun), eventuallywithin(z, t1, timefun))))) requires sat(i, always(imply(x, next(eventuallywithin(or(y, z), t2, timefun))))) requires t2 >= 0 ensures sat(i, leadstowithin(w, or(y, z), t1 + t2, timefun)) { TemporalAssist(); forall j | TLe(i, j) ensures sat(j, imply(w, eventuallywithin(or(y, z), t1 + t2, timefun))) { if sat(j, w) { TemporalDeduceFromAlways(i, j, imply(w, or(eventuallynextwithin(x, t1, timefun), eventuallywithin(z, t1, timefun)))); assert sat(j, imply(w, or(eventuallynextwithin(x, t1, timefun), eventuallywithin(z, t1, timefun)))); if sat(j, eventuallynextwithin(x, t1, timefun)) { var k :| TLe(j, k) && sat(k, nextbefore(x, timefun[j] + t1, timefun)); TemporalDeduceFromAlways(i, k, imply(x, next(eventuallywithin(or(y, z), t2, timefun)))); assert sat(nextstep(k), eventuallywithin(or(y, z), t2, timefun)); var m :| TLe(nextstep(k), m) && sat(m, beforeabsolutetime(or(y, z), timefun[k+1] + t2, timefun)); assert TLe(j, m); assert sat(j, eventuallywithin(or(y, z), t1 + t2, timefun)); } else { assert sat(j, eventuallywithin(z, t1, timefun)); assert sat(j, eventuallywithin(or(y, z), t1, timefun)); assert sat(j, eventuallywithin(or(y, z), t1 + t2, timefun)); } } } } lemma Lemma_LeadsToWithinLeadsToTransition(i:int, x:temporal, y:temporal, t:int, timefun:imap) requires imaptotal(timefun) requires sat(i, leadstowithin(x, y, t, timefun)) requires sat(i, always(imply(x, not(y)))) requires monotonic_from(i, timefun) ensures sat(i, leadstonextwithin(x, and(not(y), next(y)), t, timefun)) { TemporalAssist(); forall j | i <= j ensures sat(j, imply(x, eventuallynextwithin(and(not(y), next(y)), t, timefun))) { if sat(j, x) { TemporalDeduceFromAlways(i, j, imply(x, eventuallywithin(y, t, timefun))); var k := TemporalDeduceFromEventual(j, beforeabsolutetime(y, timefun[j] + t, timefun)); var m := earliestStep(j, y); TemporalDeduceFromAlways(i, j, imply(x, not(y))); assert j != m; var prev := m-1; assert j <= prev < m; assert !sat(prev, y); assert sat(prev, and(not(y), next(y))); TemporalEventually(j, prev, nextbefore(and(not(y), next(y)), timefun[j] + t, timefun)); } } } lemma Lemma_LeadsToWithinOrSomethingLeadsToTransitionOrSomething(i:int, x:temporal, y:temporal, z:temporal, t:int, timefun:imap) requires imaptotal(timefun) requires sat(i, leadstowithin(x, or(y, z), t, timefun)) requires sat(i, always(imply(x, not(y)))) requires monotonic_from(i, timefun) ensures sat(i, always(imply(x, or(eventuallynextwithin(and(not(y), next(y)), t, timefun), eventuallywithin(z, t, timefun))))) { TemporalAssist(); forall j | i <= j ensures sat(j, imply(x, or(eventuallynextwithin(and(not(y), next(y)), t, timefun), eventuallywithin(z, t, timefun)))) { if sat(j, x) { TemporalDeduceFromAlways(i, j, imply(x, eventuallywithin(or(y, z), t, timefun))); var k :| j <= k && sat(k, beforeabsolutetime(or(y, z), timefun[j] + t, timefun)); if sat(k, z) { assert sat(k, beforeabsolutetime(z, timefun[j] + t, timefun)); assert sat(j, eventuallywithin(z, t, timefun)); } else { var m := earliestStep(j, y); var prev := m-1; TemporalDeduceFromAlways(i, j, imply(x, not(y))); assert !sat(prev, y); assert sat(prev, and(not(y), next(y))); TemporalEventually(j, prev, nextbefore(and(not(y), next(y)), timefun[j] + t, timefun)); assert sat(j, eventuallynextwithin(and(not(y), next(y)), t, timefun)); } } } } lemma TemporalDeduceFromLeadsToWithin(i:int, j:int, x:temporal, y:temporal, t:int, timefun:imap) returns (step:int) requires imaptotal(timefun) requires sat(i, leadstowithin(x, y, t, timefun)) requires i <= j requires sat(j, x) ensures j <= step ensures timefun[step] <= timefun[j] + t ensures sat(step, y) { TemporalDeduceFromAlways(i, j, imply(x, eventuallywithin(y, t, timefun))); step := TemporalDeduceFromEventuallyWithin(j, y, t, timefun); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Common/Logic/Temporal/Monotonicity.i.dfy ================================================ include "Heuristics.i.dfy" module Temporal__Monotonicity_i { import opened Temporal__Heuristics_i import opened Temporal__Temporal_s import opened Collections__Maps2_s import opened Collections__Maps2_i ////////////////// // DEFINITIONS ////////////////// function{:opaque} stepDecrease(start:int, d:imap):temporal requires imaptotal(d) ensures forall i {:trigger sat(i, stepDecrease(start, d))} :: sat(i, stepDecrease(start, d)) <==> d[i] < d[start] { TemporalAssist(); stepmap(imap i :: d[i] < d[start]) } function nextDecrease(start:int, d:imap):temporal requires imaptotal(d) { next(stepDecrease(start, d)) } function{:opaque} nextOrDecrease(goal:temporal, d:imap):temporal requires imaptotal(d) ensures forall i {:trigger sat(i, nextOrDecrease(goal, d))} :: sat(i, nextOrDecrease(goal, d)) <==> sat(i, eventual(or(goal, nextDecrease(i, d)))) { TemporalAssist(); stepmap(imap i :: sat(i, eventual(or(goal, nextDecrease(i, d))))) } ////////////////// // LEMMAS ////////////////// // If d decreases unless A, then <>A. lemma TemporalInductionOfEventuallyFromDecreasingFunction(i:int, x:temporal, d:imap) requires imaptotal(d) requires forall j {:trigger sat(j, x)} :: i <= j ==> sat(j, x) || d[nextstep(j)] < d[j] requires forall j :: d[j] >= 0 ensures sat(i, eventual(x)) decreases d[i] { TemporalAssist(); if (!sat(i, x)) { TemporalInductionOfEventuallyFromDecreasingFunction(i + 1, x, d); } } lemma Lemma_MonotonicStepsLeadToMonotonicBehaviorPartial(i:int, f:imap, j:int, k:int) requires imaptotal(f) requires sat(i, always(stepmap(imap u :: f[u] <= f[nextstep(u)]))) requires i <= j <= k ensures f[j] <= f[k] decreases k - j { TemporalAssist(); if (k > j) { Lemma_MonotonicStepsLeadToMonotonicBehaviorPartial(i, f, j, k-1); assert TLe(i, k-1); assert sat(k-1, stepmap(imap a :: f[a] <= f[nextstep(a)])); } } // If f monotonically increases at each step, then it monotonically increases // across any pair of steps lemma Lemma_MonotonicStepsLeadToMonotonicBehavior(i:int, f:imap) requires imaptotal(f) requires sat(i, always(stepmap(imap j :: f[j] <= f[nextstep(j)]))) ensures forall j, k :: i <= j <= k ==> f[j] <= f[k] { forall j, k | i <= j <= k ensures f[j] <= f[k] { Lemma_MonotonicStepsLeadToMonotonicBehaviorPartial(i, f, j, k); } } lemma Lemma_EventuallyNextHelper(start:int, start':int, d:imap, goal:temporal) requires imaptotal(d) requires TLe(start, start') requires forall i :: start <= i ==> 0 <= d[i] requires sat(start, always(nextOrDecrease(goal, d))) ensures sat(start', eventual(goal)) decreases d[start'] { TemporalAssist(); assert sat(start', nextOrDecrease(goal, d)); var n1 {:trigger TLe(start', n1)} :| TLe(start', n1) && sat(n1, or(goal, nextDecrease(start', d))); if (!sat(n1, goal)) { Lemma_EventuallyNextHelper(start, n1 + 1, d, goal); } } // If []t :: <>(goal || d' < d[t]') // and [](0 <= d) // then []<>(goal) lemma Lemma_EventuallyNext(start:int, d:imap, goal:temporal) requires imaptotal(d) requires forall i :: start <= i ==> 0 <= d[i] requires sat(start, always(nextOrDecrease(goal, d))) ensures sat(start, always(eventual(goal))) { TemporalAssist(); forall start' | TLe(start, start') ensures sat(start', eventual(goal)) { Lemma_EventuallyNextHelper(start, start', d, goal); } } lemma Lemma_MonotonicFromImpliesMonotonicFromLater(start1:int, start2:int, f:imap) requires imaptotal(f) requires monotonic_from(start1, f) requires start1 <= start2 ensures monotonic_from(start2, f) { forall i1, i2 | start2 <= i1 <= i2 ensures f[i1] <= f[i2] { assert start1 <= i1 <= i2; } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Common/Logic/Temporal/Rules.i.dfy ================================================ include "Heuristics.i.dfy" module Temporal__Rules_i { import opened Temporal__Heuristics_i import opened Temporal__Temporal_s import opened Collections__Maps2_i /////////////////// // DEFINITIONS /////////////////// function{:opaque} eventualStep(start:int, x:temporal):(step:int) requires sat(start, eventual(x)) ensures sat(step, x) ensures TLe(start, step) { TemporalAssist(); var end :| TLe(start, end) && sat(end, x); end } function{:opaque} earliestStepBetween(start:int, end:int, x:temporal):(pos:int) requires sat(end, x) requires TLe(start, end) ensures sat(pos, x) ensures TLe(start, pos) ensures TLe(pos, end) ensures forall i :: start <= i < pos ==> !sat(i, x) decreases end - start { if (sat(start, x)) then start else earliestStepBetween(start + 1, end, x) } function{:opaque} earliestStep(start:int, x:temporal):(step:int) requires sat(start, eventual(x)) ensures sat(step, x) ensures TLe(start, step) ensures forall i :: start <= i < step ==> !sat(i, x) { earliestStepBetween(start, eventualStep(start, x), x) } /////////////////// // LEMMAS /////////////////// // []A ==> A // <>A <== A lemma TemporalNow(i:int, x:temporal) ensures sat(i, always(x)) ==> sat(i, x) ensures sat(i, eventual(x)) <== sat(i, x) { TemporalAssist(); } // [][]A = []A // <><>A = <>A lemma TemporalIdempotent(i:int, x:temporal) ensures sat(i, always(always(x))) == sat(i, always(x)) ensures sat(i, eventual(eventual(x))) == sat(i, eventual(x)) { TemporalAssist(); reveal always(); reveal eventual(); } // <>[]A ==> []<>A lemma TemporalEventuallyAlwaysImpliesAlwaysEventually(i:int, x:temporal) ensures sat(i, eventual(always(x))) ==> sat(i, always(eventual(x))) { TemporalBlast(); } // <>!A = ![]A // []!A = !<>A lemma TemporalNot(i:int, x:temporal) ensures sat(i, eventual(not(x))) <==> !sat(i, always(x)) ensures sat(i, always(not(x))) <==> !sat(i, eventual(x)) { TemporalAssist(); reveal eventual(); reveal always(); } // [](A&&B) = []A && []B // <>(A&&B) ==> <>A && <>B // <>(A&&B) <== []A && <>B // <>(A&&B) <== <>A && []B lemma TemporalAnd(i:int, x:temporal, y:temporal) ensures sat(i, always(and(x, y))) <==> sat(i, always(x)) && sat(i, always(y)) ensures sat(i, eventual(and(x, y))) ==> sat(i, eventual(x)) && sat(i, eventual(y)) ensures sat(i, eventual(and(x, y))) <== sat(i, always(x)) && sat(i, eventual(y)) ensures sat(i, eventual(and(x, y))) <== sat(i, eventual(x)) && sat(i, always(y)) { TemporalAssist(); reveal eventual(); reveal always(); } // [](A||B) <== []A || []B // [](A||B) ==> []A || <>B // [](A||B) ==> <>A || []B // <>(A||B) = <>A || <>B lemma TemporalOr(i:int, x:temporal, y:temporal) ensures sat(i, always(or(x, y))) <== sat(i, always(x)) || sat(i, always(y)) ensures sat(i, always(or(x, y))) ==> sat(i, always(x)) || sat(i, eventual(y)) ensures sat(i, always(or(x, y))) ==> sat(i, eventual(x)) || sat(i, always(y)) ensures sat(i, eventual(or(x, y))) <==> sat(i, eventual(x)) || sat(i, eventual(y)) { TemporalAssist(); reveal eventual(); reveal always(); } // [](A==>B) ==> ([]A ==> []B) // [](A==>B) ==> (<>A ==> <>B) // [](A==>B) <== (<>A ==> []B) // <>(A==>B) = ([]A ==> <>B) lemma TemporalImply(i:int, x:temporal, y:temporal) ensures sat(i, always(imply(x, y))) ==> (sat(i, always(x)) ==> sat(i, always(y))) ensures sat(i, always(imply(x, y))) ==> (sat(i, eventual(x)) ==> sat(i, eventual(y))) ensures sat(i, always(imply(x, y))) <== (sat(i, eventual(x)) ==> sat(i, always(y))) ensures sat(i, eventual(imply(x, y))) <==> (sat(i, always(x)) ==> sat(i, eventual(y))) { TemporalAssist(); reveal eventual(); reveal always(); } lemma TemporalAlways(i:int, x:temporal) requires forall j :: i <= j ==> sat(j, x) ensures sat(i, always(x)) { TemporalAssist(); assert forall j :: TLe(i, j) ==> sat(j, x); } lemma TemporalEventually(i1:int, i2:int, x:temporal) requires i1 <= i2 requires sat(i2, x) ensures sat(i1, eventual(x)) { TemporalAssist(); } lemma ValidAlways(i:int, x:temporal) requires (forall j:int :: sat(j, x)) ensures sat(i, always(x)) { TemporalAssist(); } lemma ValidImply(i:int, x:temporal, y:temporal) requires forall j:int :: sat(j, x) ==> sat(j, y) ensures sat(i, always(x)) ==> sat(i, always(y)) ensures sat(i, eventual(x)) ==> sat(i, eventual(y)) { TemporalAssist(); } lemma ValidEquiv(i:int, x:temporal, y:temporal) requires forall j:int :: sat(j, x) <==> sat(j, y) ensures sat(i, always(x)) <==> sat(i, always(y)) ensures sat(i, eventual(x)) <==> sat(i, eventual(y)) { TemporalAssist(); reveal eventual(); reveal always(); } lemma TemporalDeduceFromAlways(i:int, j:int, x:temporal) requires i <= j requires sat(i, always(x)) ensures sat(j, x) { TemporalAssist(); assert TLe(i, j); } lemma TemporalDeduceFromEventual(i:int, x:temporal) returns (j:int) requires sat(i, eventual(x)) ensures i <= j ensures sat(j, x) { TemporalAssist(); j :| TLe(i, j) && sat(j, x); } lemma Lemma_EventuallyAlwaysImpliesLaterEventuallyAlways( i:int, j:int, x:temporal ) requires i <= j requires sat(i, eventual(always(x))) ensures sat(j, eventual(always(x))) { TemporalAssist(); var k :| TLe(i, k) && sat(k, always(x)); var l := if k > j then k else j; assert TLe(k, l) && TLe(j, l); } lemma Lemma_AlwaysImpliesLaterAlways( i:int, j:int, x:temporal ) requires i <= j ensures sat(i, always(x)) ==> sat(j, always(x)) { TemporalAssist(); assert TLe(i, j); } lemma Lemma_EventuallyNowButNotNextMeansNow(x:temporal, i:int) ensures sat(i, eventual(x)) && !sat(i+1, eventual(x)) ==> sat(i, x) { TemporalAssist(); } lemma Lemma_EventuallyImpliesEarlierEventually( i:int, j:int, x:temporal ) requires i <= j ensures sat(j, eventual(x)) ==> sat(i, eventual(x)) { TemporalAssist(); assert TLe(i, j); } lemma TemporalAlwaysEventualImpliesAlwaysEventualWithDifferentStartPoint(i:int, j:int, x:temporal) ensures sat(i, always(eventual(x))) ==> sat(j, always(eventual(x))) { TemporalAssist(); if sat(i, always(eventual(x))) && i > j { assert sat(i, eventual(x)); } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Common/Logic/Temporal/Sets.i.dfy ================================================ include "Heuristics.i.dfy" include "Rules.i.dfy" include "Time.s.dfy" include "LeadsTo.i.dfy" include "../../Collections/Sets.i.dfy" module Temporal__Sets_i { import opened Temporal__Heuristics_i import opened Temporal__Rules_i import opened Temporal__Time_s import opened Temporal__LeadsTo_i import opened Temporal__Temporal_s import opened Collections__Maps2_s import opened Collections__Maps2_i import opened Collections__Sets_i ///////////////////////// // DEFINITIONS ///////////////////////// function{:opaque} andset(xs:set):temporal ensures forall i{:trigger sat(i, andset(xs))} :: sat(i, andset(xs)) <==> (forall x :: x in xs ==> sat(i, x)) { stepmap(imap i{:trigger sat(i, andset(xs))} :: (forall x :: x in xs ==> sat(i, x))) } function{:opaque} orset(xs:set):temporal ensures forall i{:trigger sat(i, orset(xs))} :: sat(i, orset(xs)) <==> (exists x :: x in xs && sat(i, x)) { stepmap(imap i{:trigger sat(i, orset(xs))} :: (exists x :: x in xs && sat(i, x))) } ///////////////////////// // LEMMAS ///////////////////////// lemma Lemma_EventuallyAlwaysEachImpliesEventuallyAlwaysAll( i:int, xs:set ) requires forall x :: x in xs ==> sat(i, eventual(always(x))) ensures sat(i, eventual(always(andset(xs)))) decreases |xs| { TemporalAssist(); if |xs| == 0 { assert sat(i, always(andset(xs))); } else { var x :| x in xs; var xs' := xs - {x}; Lemma_EventuallyAlwaysEachImpliesEventuallyAlwaysAll(i, xs'); var j := eventualStep(i, always(andset(xs'))); var k := eventualStep(i, always(x)); var m := if j > k then j else k; Lemma_AlwaysImpliesLaterAlways(j, m, andset(xs')); Lemma_AlwaysImpliesLaterAlways(k, m, x); reveal andset(); assert sat(m, always(andset(xs))); } } lemma Lemma_EventuallyAlwaysWithinEachImpliesEventuallyAlwaysWithinAll( i:int, xs:set, span:int, timefun:imap ) requires imaptotal(timefun) requires span >= 0 || |xs| > 0 requires forall x :: x in xs ==> sat(i, eventuallywithin(always(x), span, timefun)) ensures sat(i, eventuallywithin(always(andset(xs)), span, timefun)) decreases |xs| { TemporalAssist(); if |xs| == 0 { assert sat(i, always(andset(xs))); assert sat(i, beforeabsolutetime(always(andset(xs)), timefun[i] + span, timefun)); } else { var x :| x in xs; if |xs| == 1 { var j := eventualStep(i, beforeabsolutetime(always(x), timefun[i] + span, timefun)); assert sat(j, beforeabsolutetime(always(x), timefun[i] + span, timefun)); forall k | TLe(j, k) ensures sat(k, imply(x, andset(xs))) { forall x' | x' in xs ensures x' == x { ThingsIKnowAboutASingletonSet(xs, x, x'); } reveal andset(); } assert sat(j, beforeabsolutetime(always(andset(xs)), timefun[i] + span, timefun)); } else { var xs' := xs - {x}; Lemma_EventuallyAlwaysWithinEachImpliesEventuallyAlwaysWithinAll(i, xs', span, timefun); var j := eventualStep(i, beforeabsolutetime(always(andset(xs')), timefun[i] + span, timefun)); var k := eventualStep(i, beforeabsolutetime(always(x), timefun[i] + span, timefun)); var m := if j > k then j else k; Lemma_AlwaysImpliesLaterAlways(j, m, andset(xs')); Lemma_AlwaysImpliesLaterAlways(k, m, x); forall ensures sat(m, always(imply(and(andset(xs'), x), andset(xs)))) { assert forall x' :: x' in xs ==> x' in xs' || x' in {x}; reveal andset(); } assert sat(m, always(andset(xs))); } } } lemma Lemma_LeadsToAlwaysEachWithinImpliesLeadsToAlwaysAllWithin( i:int, x:temporal, ys:set, span:int, timefun:imap ) requires imaptotal(timefun) requires span >= 0 || |ys| > 0 requires forall y :: y in ys ==> sat(i, leadstowithin(x, always(y), span, timefun)) ensures sat(i, leadstowithin(x, always(andset(ys)), span, timefun)) { TemporalAssist(); forall j | TLe(i, j) ensures sat(j, imply(x, eventuallywithin(always(andset(ys)), span, timefun))) { if sat(j, x) { Lemma_EventuallyAlwaysWithinEachImpliesEventuallyAlwaysWithinAll(j, ys, span, timefun); } } } lemma Lemma_EventuallyAlwaysWithinEachOrAlternativeImpliesEventuallyAlwaysWithinAllOrAlternative( i:int, xs:set, y:temporal, span:int, timefun:imap ) requires imaptotal(timefun) requires span >= 0 || |xs| > 0 requires forall x :: x in xs ==> sat(i, eventuallywithin(or(always(x), y), span, timefun)) ensures sat(i, eventuallywithin(or(always(andset(xs)), y), span, timefun)) decreases |xs| { TemporalAssist(); if |xs| == 0 { assert sat(i, or(always(andset(xs)), y)); assert sat(i, beforeabsolutetime(or(always(andset(xs)), y), timefun[i] + span, timefun)); } else { var x :| x in xs; if |xs| == 1 { var j := eventualStep(i, beforeabsolutetime(or(always(x), y), timefun[i] + span, timefun)); forall k | TLe(j, k) ensures sat(k, imply(x, andset(xs))) { forall x' | x' in xs ensures x' == x { ThingsIKnowAboutASingletonSet(xs, x, x'); } reveal andset(); } assert sat(j, beforeabsolutetime(or(always(andset(xs)), y), timefun[i] + span, timefun)); } else { var xs' := xs - {x}; Lemma_EventuallyAlwaysWithinEachOrAlternativeImpliesEventuallyAlwaysWithinAllOrAlternative(i, xs', y, span, timefun); var j := eventualStep(i, beforeabsolutetime(or(always(andset(xs')), y), timefun[i] + span, timefun)); var k := eventualStep(i, beforeabsolutetime(or(always(x), y), timefun[i] + span, timefun)); if sat(j, y) { assert sat(j, or(always(andset(xs)), y)); } else if sat(k, y) { assert sat(k, or(always(andset(xs)), y)); } else { var m := if j > k then j else k; Lemma_AlwaysImpliesLaterAlways(j, m, andset(xs')); Lemma_AlwaysImpliesLaterAlways(k, m, x); forall ensures sat(m, always(imply(and(andset(xs'), x), andset(xs)))) { assert forall x' :: x' in xs ==> x' in xs' || x' in {x}; reveal andset(); } assert sat(m, or(always(andset(xs)), y)); } } } } lemma Lemma_LeadsToAlwaysEachOrAlternativeWithinImpliesLeadsToAlwaysAllOrAlternativeWithin( i:int, x:temporal, ys:set, z:temporal, span:int, timefun:imap ) requires imaptotal(timefun) requires span >= 0 || |ys| > 0 requires forall y :: y in ys ==> sat(i, leadstowithin(x, or(always(y), z), span, timefun)) ensures sat(i, leadstowithin(x, or(always(andset(ys)), z), span, timefun)) { TemporalAssist(); forall j | TLe(i, j) ensures sat(j, imply(x, eventuallywithin(or(always(andset(ys)), z), span, timefun))) { if sat(j, x) { Lemma_EventuallyAlwaysWithinEachOrAlternativeImpliesEventuallyAlwaysWithinAllOrAlternative(j, ys, z, span, timefun); } } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Common/Logic/Temporal/Temporal.s.dfy ================================================ include "../../Collections/Maps2.s.dfy" module Temporal__Temporal_s { import opened Collections__Maps2_s // TODO_MODULE: module Logic__Temporal_s { // TODO_MODULE: import opened Collections__Maps2_s //// TODO_MODULE: module TemporalLogic //{ type temporal = imap type Behavior = imap function stepmap(f:imap):temporal ensures forall i:int :: i in f ==> sat(i, stepmap(f)) == f[i] { f } predicate sat(s:int, t:temporal) { s in t && t[s] } function{:opaque} and(x:temporal, y:temporal):temporal ensures forall i:int {:trigger sat(i, and(x, y))} :: sat(i, and(x, y)) == (sat(i, x) && sat(i, y)) { stepmap(imap i :: sat(i, x) && sat(i, y)) } function{:opaque} or(x:temporal, y:temporal):temporal ensures forall i:int {:trigger sat(i, or(x, y))} :: sat(i, or(x, y)) == (sat(i, x) || sat(i, y)) { stepmap(imap i :: sat(i, x) || sat(i, y)) } function{:opaque} imply(x:temporal, y:temporal):temporal ensures forall i:int {:trigger sat(i, imply(x, y))} :: sat(i, imply(x, y)) == (sat(i, x) ==> sat(i, y)) { stepmap(imap i :: sat(i, x) ==> sat(i, y)) } function{:opaque} equiv(x:temporal, y:temporal):temporal ensures forall i:int {:trigger sat(i, equiv(x, y))} :: sat(i, equiv(x, y)) == (sat(i, x) <==> sat(i, y)) { stepmap(imap i :: sat(i, x) <==> sat(i, y)) } function{:opaque} not(x:temporal):temporal ensures forall i:int {:trigger sat(i, not(x))} :: sat(i, not(x)) == !sat(i, x) { stepmap(imap i :: !sat(i, x)) } function nextstep(i:int):int { i+1 } function{:opaque} next(x:temporal):temporal ensures forall i:int {:trigger sat(i, next(x))} :: sat(i, next(x)) == sat(nextstep(i), x) { stepmap(imap i :: sat(nextstep(i), x)) } function{:opaque} always(x:temporal):temporal { stepmap(imap i {:trigger sat(i, always(x))} :: forall j {:trigger sat(j, x)} :: i <= j ==> sat(j, x)) } function{:opaque} eventual(x:temporal):temporal { stepmap(imap i {:trigger sat(i, eventual(x))} :: exists j :: i <= j && sat(j, x)) } //} // TODO_MODULE: } import opened Logic__Temporal_s_ = Logic__Temporal_s } ================================================ FILE: ironfleet/src/Dafny/Distributed/Common/Logic/Temporal/Time.i.dfy ================================================ include "Time.s.dfy" include "Heuristics.i.dfy" include "Rules.i.dfy" include "Monotonicity.i.dfy" include "../../../../Libraries/Math/mul.i.dfy" module Temporal__Time_i { import opened Temporal__Time_s import opened Temporal__Heuristics_i import opened Temporal__Rules_i import opened Temporal__Monotonicity_i import opened Math__mul_i import opened Temporal__Temporal_s import opened Collections__Maps2_s import opened Collections__Maps2_i import opened Math__mul_auto_i ///////////////////////// // DEFINITIONS ///////////////////////// function{:opaque} earliestStepWithin(start:int, x:temporal, span:int, timefun:imap):int requires imaptotal(timefun) requires monotonic_from(start, timefun) requires sat(start, eventuallywithin(x, span, timefun)) ensures sat(earliestStepWithin(start, x, span, timefun), beforeabsolutetime(x, timefun[start] + span, timefun)) ensures start <= earliestStepWithin(start, x, span, timefun) ensures forall i :: start <= i < earliestStepWithin(start, x, span, timefun) ==> !sat(i, x) { TemporalAssist(); var i1 := earliestStep(start, x); var i2 := earliestStep(start, beforeabsolutetime(x, timefun[start] + span, timefun)); assert TLe(i1, i2); i1 } function{:opaque} earliestActionWithin(start:int, x:temporal, span:int, timefun:imap):int requires imaptotal(timefun) requires monotonic_from(start, timefun) requires sat(start, eventuallynextwithin(x, span, timefun)) ensures sat(earliestActionWithin(start, x, span, timefun), and(x, next(before(timefun[start] + span, timefun)))) ensures start <= earliestActionWithin(start, x, span, timefun) ensures forall i :: start <= i < earliestActionWithin(start, x, span, timefun) ==> !sat(i, x) { TemporalAssist(); var i1 := earliestStep(start, x); var i2 := earliestStep(start, and(x, next(before(timefun[start] + span, timefun)))); assert TLe(i1, i2); i1 } function{:opaque} goalOrDecrease(goal:temporal, d:imap, span:int, timefun:imap):temporal requires imaptotal(d) requires imaptotal(timefun) ensures forall i {:trigger sat(i, goalOrDecrease(goal, d, span, timefun))} :: sat(i, goalOrDecrease(goal, d, span, timefun)) <==> sat(i, eventuallywithin(or(goal, stepDecrease(i, d)), span, timefun)) { TemporalAssist(); stepmap(imap i :: sat(i, eventuallywithin(or(goal, stepDecrease(i, d)), span, timefun))) } function{:opaque} nextOrDecreaseWithin(goal:temporal, d:imap, span:int, timefun:imap):temporal requires imaptotal(d) requires imaptotal(timefun) ensures forall i {:trigger sat(i, nextOrDecreaseWithin(goal, d, span, timefun))} :: sat(i, nextOrDecreaseWithin(goal, d, span, timefun)) <==> sat(i, eventuallynextwithin(or(goal, nextDecrease(i, d)), span, timefun)); { TemporalAssist(); stepmap(imap i :: sat(i, eventuallynextwithin(or(goal, nextDecrease(i, d)), span, timefun))) } function{:opaque} eventuallywithinspans(d:imap, goal:temporal, span:int, timefun:imap):temporal requires imaptotal(d) requires imaptotal(timefun) ensures forall i {:trigger sat(i, eventuallywithinspans(d, goal, span, timefun))} :: sat(i, eventuallywithinspans(d, goal, span, timefun)) <==> sat(i, eventuallywithin(goal, span * d[i], timefun)); { TemporalAssist(); stepmap(imap i :: sat(i, eventuallywithin(goal, span * d[i], timefun))) } function{:opaque} eventuallynextwithinspans(d:imap, goal:temporal, span:int, timefun:imap):temporal requires imaptotal(d) requires imaptotal(timefun) ensures forall i {:trigger sat(i, eventuallynextwithinspans(d, goal, span, timefun))} :: sat(i, eventuallynextwithinspans(d, goal, span, timefun)) <==> sat(i, eventuallynextwithin(goal, span * d[i], timefun)); { TemporalAssist(); stepmap(imap i :: sat(i, eventuallynextwithin(goal, span * d[i], timefun))) } function stepattimeboundary(i:int, j:int, t:int, timefun:imap):int requires imaptotal(timefun) requires monotonic_from(i, timefun) requires timefun[i] <= t requires timefun[j] >= t requires i <= j ensures var k := stepattimeboundary(i, j, t, timefun); && timefun[k] <= t && i <= k <= j && forall m :: m > k ==> timefun[m] >= t decreases j-i { if i == j then i else if timefun[j-1] <= t then j-1 else stepattimeboundary(i, j-1, t, timefun) } predicate TimeNotZeno(timefun:imap) requires imaptotal(timefun) { forall t :: sat(0, eventual(after(t, timefun))) } ///////////////////////// // LEMMAS ///////////////////////// lemma TemporalEventuallyWithin(i:int, j:int, x:temporal, span:int, timefun:imap) requires imaptotal(timefun) requires i <= j requires sat(j, beforeabsolutetime(x, timefun[i] + span, timefun)) ensures sat(i, eventuallywithin(x, span, timefun)) { TemporalAssist(); } lemma TemporalEventuallyNextWithin(i:int, j:int, x:temporal, span:int, timefun:imap) requires imaptotal(timefun) requires i <= j requires sat(j, x) requires sat(j+1, before(timefun[i] + span, timefun)) ensures sat(i, eventuallynextwithin(x, span, timefun)) { TemporalEventually(i, j, nextbefore(x, timefun[i] + span, timefun)); } lemma Lemma_EventuallyWithinSpansHelper(start:int, start':int, d:imap, goal:temporal, span:int, timefun:imap) requires imaptotal(d) requires imaptotal(timefun) requires 1 <= span requires TLe(start, start') requires forall i :: start <= i ==> 1 <= d[i] requires sat(start, always(goalOrDecrease(goal, d, span, timefun))) ensures sat(start', eventuallywithin(goal, span * d[start'], timefun)) decreases d[start'] { TemporalAssist(); assert sat(start', goalOrDecrease(goal, d, span, timefun)); var n1 {:trigger TLe(start', n1)} :| TLe(start', n1) && sat(n1, beforeabsolutetime(or(goal, stepDecrease(start', d)), timefun[start'] + span, timefun)); if (sat(n1, goal)) { calc { 1 <= d[start']; { lemma_mul_inequality(1, d[start'], span); } span * 1 <= span * d[start']; } } else { Lemma_EventuallyWithinSpansHelper(start, n1, d, goal, span, timefun); var n2 {:trigger TLe(n1, n2)} :| TLe(n1, n2) && sat(n2, beforeabsolutetime(goal, timefun[n1] + span * d[n1], timefun)); calc { d[n1] + 1 <= d[start']; { lemma_mul_inequality_forall(); lemma_mul_is_commutative_forall(); } span * (d[n1] + 1) <= span * d[start']; { lemma_mul_is_distributive_forall(); } span * d[n1] + span <= span * d[start']; } assert sat(n2, beforeabsolutetime(goal, timefun[start'] + span * d[start'], timefun)); } } // If []t :: (goal || d < d[t]) // and [](0 <= d) // then [](goal) lemma Lemma_EventuallyWithinSpans(start:int, d:imap, goal:temporal, span:int, timefun:imap) requires imaptotal(d) requires imaptotal(timefun) requires 1 <= span requires forall i :: start <= i ==> 1 <= d[i] requires sat(start, always(goalOrDecrease(goal, d, span, timefun))) ensures sat(start, always(eventuallywithinspans(d, goal, span, timefun))) { TemporalAssist(); forall start' | TLe(start, start') ensures sat(start', eventuallywithin(goal, span * d[start'], timefun)) { Lemma_EventuallyWithinSpansHelper(start, start', d, goal, span, timefun); } } // If [](goal) // and [](d <= n) // then [](goal) lemma Lemma_EventuallyWithinBound(start:int, d:imap, n:int, goal:temporal, span:int, timefun:imap) requires imaptotal(d) requires imaptotal(timefun) requires forall i :: d[i] <= n requires 0 <= span requires sat(start, always(eventuallywithinspans(d, goal, span, timefun))) ensures sat(start, always(eventuallywithin(goal, span * n, timefun))) { TemporalAssist(); forall i1 | TLe(start, i1) ensures sat(i1, eventuallywithin(goal, span * n, timefun)) { lemma_mul_inequality_forall(); lemma_mul_is_commutative_forall(); assert span * d[i1] <= span * n; } } lemma Lemma_EventuallynextWithinSpansHelper(start:int, start':int, d:imap, goal:temporal, span:int, timefun:imap) requires imaptotal(d) requires imaptotal(timefun) requires 1 <= span requires TLe(start, start') requires forall i :: start <= i ==> 1 <= d[i] requires sat(start, always(nextOrDecreaseWithin(goal, d, span, timefun))) ensures sat(start', eventuallynextwithin(goal, span * d[start'], timefun)) decreases d[start'] { TemporalAssist(); assert sat(start', nextOrDecreaseWithin(goal, d, span, timefun)); var n1 {:trigger TLe(start', n1)} :| TLe(start', n1) && sat(n1, and(or(goal, nextDecrease(start', d)), next(before(timefun[start'] + span, timefun)))); if (sat(n1, goal)) { calc { 1 <= d[start']; { lemma_mul_inequality(1, d[start'], span); } span * 1 <= span * d[start']; } } else { Lemma_EventuallynextWithinSpansHelper(start, n1 + 1, d, goal, span, timefun); var n2 {:trigger TLe(n1 + 1, n2)} :| TLe(n1 + 1, n2) && sat(n2, and(goal, next(before(timefun[n1 + 1] + span * d[n1 + 1], timefun)))); calc { d[n1 + 1] + 1 <= d[start']; { lemma_mul_inequality_forall(); lemma_mul_is_commutative_forall(); } span * (d[n1 + 1] + 1) <= span * d[start']; { lemma_mul_is_distributive_forall(); } span * d[n1 + 1] + span <= span * d[start']; } assert sat(n2, nextbefore(goal, timefun[start'] + span * d[start'], timefun)); assert sat(n2, and(goal, next(before(timefun[start'] + span * d[start'], timefun)))); } } // If []t :: (goal || d' < d[t]') // and [](1 <= d) // then [](goal) lemma Lemma_EventuallynextWithinSpans(start:int, d:imap, goal:temporal, span:int, timefun:imap) requires imaptotal(d) requires imaptotal(timefun) requires 1 <= span requires forall i :: start <= i ==> 1 <= d[i] requires sat(start, always(nextOrDecreaseWithin(goal, d, span, timefun))) ensures sat(start, always(eventuallynextwithinspans(d, goal, span, timefun))) { TemporalAssist(); forall start' | TLe(start, start') ensures sat(start', eventuallynextwithin(goal, span * d[start'], timefun)) { Lemma_EventuallynextWithinSpansHelper(start, start', d, goal, span, timefun); } } // If [](goal) // and [](d <= n) // then [](goal) lemma Lemma_EventuallynextWithinBound(start:int, d:imap, n:int, goal:temporal, span:int, timefun:imap) requires imaptotal(d) requires imaptotal(timefun) requires forall i :: d[i] <= n requires 0 <= span requires sat(start, always(eventuallynextwithinspans(d, goal, span, timefun))) ensures sat(start, always(eventuallynextwithin(goal, span * n, timefun))) { TemporalAssist(); forall i1 | TLe(start, i1) ensures sat(i1, eventuallynextwithin(goal, span * n, timefun)) { lemma_mul_inequality_forall(); lemma_mul_is_commutative_forall(); assert span * d[i1] <= span * n; } } lemma Lemma_EventuallynextWithinImpliesEventuallynext(i:int, x:temporal, span:int, timefun:imap) requires imaptotal(timefun) requires sat(i, eventuallynextwithin(x, span, timefun)) ensures sat(i, eventual(x)) { TemporalAssist(); } lemma Lemma_AlwaysEventuallyWithinMeansAlwaysEventuallyWithinAfter(i:int, action:temporal, wait:int, span:int, timefun:imap) returns (step:int) requires imaptotal(timefun) requires monotonic_from(0, timefun) requires wait >= 0 requires span >= 0 requires TimeNotZeno(timefun) requires sat(i, always(eventuallynextwithin(action, span, timefun))) requires 0 <= i ensures i <= step ensures sat(step, and(nextbefore(action, timefun[i] + wait + span, timefun), next(after(timefun[i] + wait, timefun)))) ensures sat(i, eventual(and(nextbefore(action, timefun[i] + wait + span, timefun), next(after(timefun[i] + wait, timefun))))) { var rt1 := timefun[i] + wait; var rt2 := timefun[i] + wait + span; var j := eventualStep(0, after(rt1, timefun)); Lemma_MonotonicFromImpliesMonotonicFromLater(0, i, timefun); if (j < i) { j := i; } var k := stepattimeboundary(i, j, rt1, timefun); TemporalDeduceFromAlways(i, k, eventuallynextwithin(action, span, timefun)); step := eventualStep(k, nextbefore(action, timefun[k] + span, timefun)); TemporalEventually(i, step, and(nextbefore(action, rt2, timefun), next(after(rt1, timefun)))); } lemma Lemma_AlwaysEventuallyWithinImpliesAfter(i:int, j:int, action:temporal, span:int, timefun:imap, rt:int) returns (step:int) requires imaptotal(timefun) requires monotonic_from(0, timefun) requires span >= 0 requires TimeNotZeno(timefun) requires sat(i, always(eventuallynextwithin(action, span, timefun))) requires 0 <= i <= j ensures j <= step ensures sat(step, action) ensures rt <= timefun[step+1] { assert sat(0, eventual(after(rt, timefun))); var k := TemporalDeduceFromEventual(0, after(rt, timefun)); if k < j { assert rt <= timefun[k] <= timefun[j]; k := j; } TemporalDeduceFromAlways(i, k, eventuallynextwithin(action, span, timefun)); step := TemporalDeduceFromEventual(k, nextbefore(action, timefun[k] + span, timefun)); } lemma Lemma_UntilAbsoluteTimeImpliesUntilEarlierTime(i:int, x:temporal, t1:int, t2:int, timefun:imap) requires imaptotal(timefun) requires monotonic_from(i, timefun) requires sat(i, untilabsolutetime(x, t1, timefun)) requires t2 <= t1 ensures sat(i, untilabsolutetime(x, t2, timefun)) { TemporalAssist(); } lemma Lemma_AlwaysUntilAbsoluteTimeImpliesAlwaysUntilEarlierTime(i:int, x:temporal, t1:int, t2:int, timefun:imap) requires imaptotal(timefun) requires monotonic_from(i, timefun) requires sat(i, always(untilabsolutetime(x, t1, timefun))) requires t2 <= t1 ensures sat(i, always(untilabsolutetime(x, t2, timefun))) { TemporalAssist(); } lemma TemporalDeduceFromEventuallyWithin(i:int, x:temporal, span:int, timefun:imap) returns (step:int) requires imaptotal(timefun) requires sat(i, eventuallywithin(x, span, timefun)) ensures i <= step ensures sat(step, beforeabsolutetime(x, timefun[i] + span, timefun)) { step := TemporalDeduceFromEventual(i, beforeabsolutetime(x, timefun[i] + span, timefun)); } lemma TemporalDeduceFromEventuallyNextWithin(i:int, x:temporal, span:int, timefun:imap) returns (step:int) requires imaptotal(timefun) requires sat(i, eventuallynextwithin(x, span, timefun)) ensures i <= step ensures sat(step, nextbefore(x, timefun[i] + span, timefun)) { step := TemporalDeduceFromEventual(i, nextbefore(x, timefun[i] + span, timefun)); } lemma TemporalDeduceFromAlwaysWithin(i:int, j:int, x:temporal, span:int, timefun:imap) requires imaptotal(timefun) requires sat(i, alwayswithin(x, span, timefun)) requires i <= j requires sat(j, before(timefun[i] + span, timefun)) ensures sat(j, x) { TemporalDeduceFromAlways(i, j, untilabsolutetime(x, timefun[i] + span, timefun)); } predicate{:opaque} monotonic_from_opaque(start:int, f:imap) { forall i1, i2 {:trigger f[i1], f[i2]} :: i1 in f && i2 in f && start <= i1 <= i2 ==> f[i1] <= f[i2] } function{:opaque} actionGoalDecrease(i1:int, goal:temporal, d:imap):temporal requires imaptotal(d) ensures forall i {:trigger sat(i, actionGoalDecrease(i1, goal, d))} :: sat(i, actionGoalDecrease(i1, goal, d)) <==> (0 < d[i + 1] && d[i + 1] < d[i1]) || sat(i, goal) || (d[i1] == 0) { TemporalAssist(); stepmap(imap i :: (0 < d[i + 1] && d[i + 1] < d[i1]) || sat(i, goal) || (d[i1] == 0)) } function{:opaque} actionGoalDecreaseWithin(goal:temporal, d:imap, span:int, timefun:imap):temporal requires imaptotal(d) requires imaptotal(timefun) ensures forall i {:trigger sat(i, actionGoalDecreaseWithin(goal, d, span, timefun))} :: sat(i, actionGoalDecreaseWithin(goal, d, span, timefun)) <==> sat(i, eventuallynextwithin(actionGoalDecrease(i, goal, d), span, timefun)) { TemporalAssist(); stepmap(imap i :: sat(i, eventuallynextwithin(actionGoalDecrease(i, goal, d), span, timefun))) } // If []t :: ((0 < d' < d[t]') || goal || (d[t]' == 0)) // and [](0 <= d) // and 1 <= d // then (goal) lemma Lemma_EventuallyNextGoalSpans(start:int, d:imap, goal:temporal, span:int, timefun:imap) requires imaptotal(d) requires imaptotal(timefun) requires 1 <= span requires 1 <= d[start] requires forall i :: start <= i ==> 0 <= d[i] requires sat(start, always(actionGoalDecreaseWithin(goal, d, span, timefun))) ensures sat(start, eventuallynextwithinspans(d, goal, span, timefun)) decreases d[start] { TemporalAssist(); assert sat(start, actionGoalDecreaseWithin(goal, d, span, timefun)); var i1 {:trigger TLe(start, i1)} :| TLe(start, i1) && sat(i1, actionGoalDecrease(start, goal, d)) && timefun[i1 + 1] <= timefun[start] + span; if (sat(i1, goal)) { calc { 1 <= d[start]; { lemma_mul_inequality(1, d[start], span); } span * 1 <= span * d[start]; } assert sat(start, eventuallynextwithinspans(d, goal, span, timefun)); } else { Lemma_EventuallyNextGoalSpans(i1 + 1, d, goal, span, timefun); var i2 {:trigger TLe(i1 + 1, i2)} :| TLe(i1 + 1, i2) && sat(i2, and(goal, next(before(timefun[i1 + 1] + span * d[i1 + 1], timefun)))); calc { d[i1 + 1] + 1 <= d[start]; { lemma_mul_inequality_forall(); lemma_mul_is_commutative_forall(); } span * (d[i1 + 1] + 1) <= span * d[start]; { lemma_mul_is_distributive_forall(); } span * d[i1 + 1] + span <= span * d[start]; } assert sat(i2, nextbefore(goal, timefun[start] + span * d[start], timefun)); assert sat(i2, and(goal, next(before(timefun[start] + span * d[start], timefun)))); } } function {:opaque} ActionIsInstantaneousTemporal(x:temporal, timefun:imap):temporal requires imaptotal(timefun) ensures forall i {:trigger sat(i, ActionIsInstantaneousTemporal(x, timefun))} :: sat(i, ActionIsInstantaneousTemporal(x, timefun)) <==> (sat(i, x) ==> timefun[i] == timefun[i+1]) { stepmap(imap i :: sat(i, x) ==> timefun[i] == timefun[i+1]) } // "x" happens at most "count" times in all periods no longer than "span" function{:opaque} countWithinLe(count:int, x:temporal, span:int, timefun:imap):temporal requires imaptotal(timefun) ensures forall i1 {:trigger sat(i1, countWithinLe(count, x, span, timefun))} :: sat(i1, countWithinLe(count, x, span, timefun)) <==> (forall i2 :: TLe(i1, i2) && timefun[i2] <= timefun[i1] + span ==> countWithin(i1, i2, x) <= count) { TemporalAssist(); stepmap(imap i1 :: forall i2 :: TLe(i1, i2) && timefun[i2] <= timefun[i1] + span ==> countWithin(i1, i2, x) <= count) } // "x" happens at least "count" times in a period no longer than "span" function{:opaque} countWithinGe(count:int, x:temporal, span:int, timefun:imap):temporal requires imaptotal(timefun) ensures forall i1 {:trigger sat(i1, countWithinGe(count, x, span, timefun))} :: sat(i1, countWithinGe(count, x, span, timefun)) <==> (exists i2 :: TLe(i1, i2) && timefun[i2] <= timefun[i1] + span && countWithin(i1, i2, x) >= count) { TemporalAssist(); stepmap(imap i1 :: exists i2 :: TLe(i1, i2) && timefun[i2] <= timefun[i1] + span && countWithin(i1, i2, x) >= count) } lemma Lemma_CountWithinLeMultiple(start:int, n:nat, count:int, x:temporal, span:int, timefun:imap) requires imaptotal(timefun) requires monotonic_from_opaque(start, timefun) requires 1 <= n requires 0 <= span requires sat(start, always(ActionIsInstantaneousTemporal(x, timefun))) requires sat(start, always(countWithinLe(count, x, span, timefun))) ensures sat(start, always(countWithinLe(count * n, x, span * n, timefun))) decreases n { TemporalAssist(); reveal monotonic_from_opaque(); forall i1 | TLe(start, i1) ensures sat(i1, countWithinLe(count * n, x, span * n, timefun)) { if (n > 1) { forall i3 | TLe(i1, i3) && timefun[i3] <= timefun[i1] + span * n ensures countWithin(i1, i3, x) <= count * n { Lemma_CountWithinLeMultiple(i1, n - 1, count, x, span, timefun); assert sat(i1, countWithinLe(count * (n - 1), x, span * (n - 1), timefun)); assert forall i2 :: TLe(i1, i2) && timefun[i2] <= timefun[i1] + span * (n - 1) ==> countWithin(i1, i2, x) <= count * (n - 1); if (exists i2' :: TLe(i1, i2') && TLe(i2', i3) && timefun[i2'] > timefun[i1] + span * (n - 1)) { var f := imap i2' :: TLe(i2', i3) && timefun[i2'] > timefun[i1] + span * (n - 1); var i2' := earliestStep(i1, stepmap(f)); lemma_mul_nonnegative(span, n-1); var i2 := i2' - 1; assert !sat(i2, stepmap(f)); TemporalDeduceFromAlways(i1, i2, ActionIsInstantaneousTemporal(x, timefun)); assert !sat(i2, x); forall ensures 0 <= span * (n - 1) { lemma_mul_nonnegative(span, n - 1); } assert TLe(i1, i2'); assert TLe(i1, i2); assert TLe(i2, i3); assert forall i :: i1 <= i <= i2 ==> !sat(i, stepmap(f)); assert forall i :: sat(i, stepmap(f)) == (TLe(i, i3) && timefun[i] > timefun[i1] + span * (n - 1)); assert forall i :: i1 <= i <= i2 ==> !(TLe(i, i3) && timefun[i] > timefun[i1] + span * (n - 1)); assert !(TLe(i2, i3) && timefun[i2] > timefun[i1] + span * (n - 1)); assert countWithin(i1, i2, x) <= count * (n - 1); assert sat(i2', countWithinLe(count, x, span, timefun)); assert TLe(i2', i3) && timefun[i3] <= timefun[i2'] + span ==> countWithin(i2', i3, x) <= count; forall ensures span + span * (n - 1) == span * n ensures count + count * (n - 1) == count * n { lemma_mul_auto(); } assert countWithin(i2', i3, x) <= count; assert actionsWithin(i1, i3, x) == actionsWithin(i1, i2, x) + actionsWithin(i2', i3, x); assert |actionsWithin(i1, i3, x)| >= |actionsWithin(i1, i2, x)| + |actionsWithin(i2', i3, x)|; } else { assert forall i2' :: TLe(i1, i2') && TLe(i2', i3) ==> timefun[i2'] <= timefun[i1] + span * (n - 1); assert timefun[i3] <= timefun[i1] + span * (n - 1); assert countWithin(i1, i3, x) <= count * (n - 1); forall ensures count * (n - 1) <= count * n { lemma_mul_auto(); } } } } } } lemma Lemma_CountWithinGeMultiple(start:int, n:nat, count:int, x:temporal, span:int, timefun:imap) requires imaptotal(timefun) requires monotonic_from_opaque(start, timefun) requires 1 <= n requires 0 <= span requires sat(start, always(countWithinGe(count, x, span, timefun))) ensures sat(start, always(countWithinGe(count * n, x, span * n, timefun))) decreases n { TemporalAssist(); reveal monotonic_from_opaque(); forall i1 | TLe(start, i1) ensures sat(i1, countWithinGe(count * n, x, span * n, timefun)) { if (n > 1) { assert sat(i1, countWithinGe(count, x, span, timefun)); var i2 :| TLe(i1, i2) && timefun[i2] <= timefun[i1] + span && countWithin(i1, i2, x) >= count; Lemma_CountWithinGeMultiple(i2, n - 1, count, x, span, timefun); assert sat(i2, always(countWithinGe(count * (n - 1), x, span * (n - 1), timefun))); assert sat(i2, countWithinGe(count * (n - 1), x, span * (n - 1), timefun)); var i3 :| TLe(i2, i3) && timefun[i3] <= timefun[i2] + span * (n - 1) && countWithin(i2, i3, x) >= count * (n - 1); assert TLe(i1, i3); assert actionsWithin(i1, i3, x) == actionsWithin(i1, i2, x) + actionsWithin(i2, i3, x); assert |actionsWithin(i1, i3, x)| >= |actionsWithin(i1, i2, x)| + |actionsWithin(i2, i3, x)|; forall ensures span + span * (n - 1) == span * n ensures count + count * (n - 1) == count * n { lemma_mul_auto(); } } } } lemma Lemma_CountWithinGeOne(start:int, x:temporal, span:int, timefun:imap) requires imaptotal(timefun) requires 0 <= span requires sat(start, always(eventuallynextwithin(x, span, timefun))) ensures sat(start, always(countWithinGe(1, x, span, timefun))) { TemporalAssist(); forall i1 | TLe(start, i1) ensures sat(i1, countWithinGe(1, x, span, timefun)) { var i2 :| TLe(i1, i2) && sat(i2, nextbefore(x, timefun[i1] + span, timefun)); var i2' := i2 + 1; assert i2 in actionsWithin(i1, i2', x); assert countWithin(i1, i2', x) >= 1; } } lemma{:timeLimitMultiplier 2} Lemma_CountIncrDecrHelper(i1:int, i2:int, d:imap, nIncr:int, nDecr:int, incr:temporal, decr:temporal) requires imaptotal(d) requires i1 <= i2 requires countWithin(i1, i2, decr) >= nDecr requires countWithin(i1, i2, incr) <= nIncr requires forall i {:trigger TLe(i1, i)}{:trigger sat(i, incr)}{:trigger sat(i, decr)} :: TLe(i1, i) && TLe(i, i2) ==> || (sat(i, incr) && !sat(i, decr) && d[i + 1] == d[i] + 1) || (!sat(i, incr) && sat(i, decr) && d[i + 1] < d[i]) || (!sat(i, incr) && !sat(i, decr) && d[i + 1] == d[i]) ensures d[i2] <= d[i1] + nIncr - nDecr decreases i2 - i1 { if (i1 == i2) { assert forall i :: i !in actionsWithin(i1, i2, decr); assert actionsWithin(i1, i2, decr) == {}; assert countWithin(i1, i2, decr) == 0; } else { assert actionsWithin(i1, i2, incr) == actionsWithin(i1, i1 + 1, incr) + actionsWithin(i1 + 1, i2, incr); assert actionsWithin(i1, i2, decr) == actionsWithin(i1, i1 + 1, decr) + actionsWithin(i1 + 1, i2, decr); if (sat(i1, incr)) { assert i1 in actionsWithin(i1, i2, incr); Lemma_CountIncrDecrHelper(i1 + 1, i2, d, nIncr - 1, nDecr, incr, decr); } else if (sat(i1, decr)) { forall j | i1 <= j < i1 + 1 && sat(j, decr) ensures j == i1 { } assert i1 in actionsWithin(i1, i1 + 1, decr); assert actionsWithin(i1, i1 + 1, decr) <= {i1}; assert actionsWithin(i1, i1 + 1, decr) == {i1}; Lemma_CountIncrDecrHelper(i1 + 1, i2, d, nIncr, nDecr - 1, incr, decr); } else { Lemma_CountIncrDecrHelper(i1 + 1, i2, d, nIncr, nDecr, incr, decr); } } } lemma Lemma_CountIncrDecr(i1:int, d:imap, nIncr:int, nDecr:int, incr:temporal, decr:temporal, span:int, timefun:imap) returns (i2:int) // |decr| >= nDecr // |incr| <= nIncr requires imaptotal(d) requires imaptotal(timefun) requires monotonic_from_opaque(i1, timefun) requires 0 <= span requires sat(i1, countWithinLe(nIncr, incr, span, timefun)) requires sat(i1, countWithinGe(nDecr, decr, span, timefun)) requires forall i {:trigger TLe(i1, i)} :: TLe(i1, i) && timefun[i] <= timefun[i1] + span ==> || (sat(i, incr) && !sat(i, decr) && d[i + 1] == d[i] + 1) || (!sat(i, incr) && sat(i, decr) && d[i + 1] < d[i]) || (!sat(i, incr) && !sat(i, decr) && d[i + 1] == d[i]); ensures timefun[i2] <= timefun[i1] + span ensures sat(i2, stepmap(imap i :: d[i] <= d[i1] + nIncr - nDecr)) ensures sat(i1, alwayswithin(stepmap(imap i :: d[i] <= d[i1] + nIncr), span, timefun)) ensures nDecr > 0 ==> i2 > i1 { TemporalAssist(); reveal monotonic_from_opaque(); i2 :| TLe(i1, i2) && timefun[i2] <= timefun[i1] + span && countWithin(i1, i2, decr) >= nDecr; assert TLe(i1, i2) && timefun[i2] <= timefun[i1] + span ==> countWithin(i1, i2, incr) <= nIncr; assert countWithin(i1, i2, decr) >= nDecr; assert countWithin(i1, i2, incr) <= nIncr; Lemma_CountIncrDecrHelper(i1, i2, d, nIncr, nDecr, incr, decr); assert d[i2] <= d[i1] + nIncr - nDecr; var f1 := imap i :: d[i] <= d[i1] + nIncr - nDecr; assert sat(i2, stepmap(f1)); assert sat(i1, eventuallywithin(stepmap(f1), span, timefun)); var f2 := imap i :: d[i] <= d[i1] + nIncr; forall i | TLe(i1, i) && timefun[i] <= timefun[i1] + span ensures f2[i] { Lemma_CountIncrDecrHelper(i1, i, d, nIncr, countWithin(i1, i, decr), incr, decr); assert d[i] <= d[i1] + nIncr; } assert sat(i1, alwayswithin(stepmap(f2), span, timefun)); } lemma Lemma_CountIncrHelper(i1:int, i2:int, d:imap, nIncr:int, incr:temporal) requires imaptotal(d) requires i1 <= i2 requires countWithin(i1, i2, incr) <= nIncr requires forall i {:trigger TLe(i1, i)}{:trigger sat(i, incr)} :: TLe(i1, i) && TLe(i, i2) ==> || (sat(i, incr) && d[i + 1] == d[i] + 1) || (!sat(i, incr) && d[i + 1] <= d[i]) ensures d[i2] <= d[i1] + nIncr decreases i2 - i1 { if (i1 != i2) { assert actionsWithin(i1, i2, incr) == actionsWithin(i1, i1 + 1, incr) + actionsWithin(i1 + 1, i2, incr); if (sat(i1, incr)) { assert i1 in actionsWithin(i1, i2, incr); Lemma_CountIncrHelper(i1 + 1, i2, d, nIncr - 1, incr); } else { Lemma_CountIncrHelper(i1 + 1, i2, d, nIncr, incr); } } } lemma Lemma_CountIncr(i1:int, d:imap, nIncr:int, incr:temporal, span:int, timefun:imap) // |incr| <= nIncr requires imaptotal(d) requires imaptotal(timefun) requires monotonic_from_opaque(i1, timefun) requires 0 <= span requires sat(i1, countWithinLe(nIncr, incr, span, timefun)) requires forall i {:trigger TLe(i1, i)} :: TLe(i1, i) && timefun[i] <= timefun[i1] + span ==> || (sat(i, incr) && d[i + 1] == d[i] + 1) || (!sat(i, incr) && d[i + 1] <= d[i]) ensures sat(i1, alwayswithin(stepmap(imap i :: d[i] <= d[i1] + nIncr), span, timefun)) { TemporalAssist(); reveal monotonic_from_opaque(); var f2 := imap i :: d[i] <= d[i1] + nIncr; forall i | TLe(i1, i) && timefun[i] <= timefun[i1] + span ensures f2[i] { Lemma_CountIncrHelper(i1, i, d, nIncr, incr); assert d[i] <= d[i1] + nIncr; } assert sat(i1, alwayswithin(stepmap(f2), span, timefun)); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Common/Logic/Temporal/Time.s.dfy ================================================ include "Temporal.s.dfy" module Temporal__Time_s { import opened Temporal__Temporal_s import opened Collections__Maps2_s function{:opaque} eventuallywithin(x:temporal, span:int, timefun:imap):temporal requires imaptotal(timefun) ensures forall i {:trigger sat(i, eventuallywithin(x, span, timefun))} :: sat(i, eventuallywithin(x, span, timefun)) <==> sat(i, eventual(beforeabsolutetime(x, timefun[i] + span, timefun))) { stepmap(imap j :: sat(j, eventual(beforeabsolutetime(x, timefun[j] + span, timefun)))) } function{:opaque} alwayswithin(x:temporal, span:int, timefun:imap):temporal requires imaptotal(timefun) ensures forall i {:trigger sat(i, alwayswithin(x, span, timefun))} :: sat(i, alwayswithin(x, span, timefun)) <==> sat(i, always(untilabsolutetime(x, timefun[i] + span, timefun))) { stepmap(imap j :: sat(j, always(untilabsolutetime(x, timefun[j] + span, timefun)))) } function{:opaque} before(t:int, timefun:imap):temporal requires imaptotal(timefun) ensures forall i {:trigger sat(i, before(t, timefun))} :: sat(i, before(t, timefun)) <==> timefun[i] <= t { stepmap(imap i :: timefun[i] <= t) } function{:opaque} after(t:int, timefun:imap):temporal requires imaptotal(timefun) ensures forall i{:trigger sat(i, after(t, timefun))} :: sat(i, after(t, timefun)) <==> (timefun[i] >= t) { stepmap(imap i :: timefun[i] >= t) } function nextbefore(action:temporal, t:int, timefun:imap):temporal requires imaptotal(timefun) { and(action, next(before(t, timefun))) } function nextafter(action:temporal, t:int, timefun:imap):temporal requires imaptotal(timefun) { and(action, next(after(t, timefun))) } function{:opaque} eventuallynextwithin(action:temporal, span:int, timefun:imap):temporal requires imaptotal(timefun) ensures forall i {:trigger sat(i, eventuallynextwithin(action, span, timefun))} :: sat(i, eventuallynextwithin(action, span, timefun)) <==> sat(i, eventual(nextbefore(action, timefun[i] + span, timefun))) { stepmap(imap i :: sat(i, eventual(nextbefore(action, timefun[i] + span, timefun)))) } function{:opaque} beforeabsolutetime(x:temporal, t:int, timefun:imap):temporal requires imaptotal(timefun) ensures forall i {:trigger sat(i, beforeabsolutetime(x, t, timefun))} :: sat(i, beforeabsolutetime(x, t, timefun)) <==> sat(i, x) && timefun[i] <= t { and(x, before(t, timefun)) } function{:opaque} untilabsolutetime(x:temporal, t:int, timefun:imap):temporal requires imaptotal(timefun) ensures forall i {:trigger sat(i, untilabsolutetime(x, t, timefun))} :: sat(i, untilabsolutetime(x, t, timefun)) <==> timefun[i] <= t ==> sat(i, x) { imply(before(t, timefun), x) } function actionsWithin(i1:int, i2:int, x:temporal):set { set i | i1 <= i < i2 && sat(i, x) } function countWithin(i1:int, i2:int, x:temporal):int { |actionsWithin(i1, i2, x)| } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Common/Logic/Temporal/WF1.i.dfy ================================================ include "Temporal.s.dfy" include "Heuristics.i.dfy" include "Rules.i.dfy" include "LeadsTo.i.dfy" include "Induction.i.dfy" include "Time.i.dfy" module Temporal__WF1_i { import opened Temporal__Temporal_s import opened Temporal__Heuristics_i import opened Temporal__Rules_i import opened Temporal__LeadsTo_i import opened Temporal__Induction_i import opened Temporal__Time_s import opened Temporal__Time_i import opened Collections__Maps2_s import opened Collections__Maps2_i ///////////////////// // DEFINITIONS ///////////////////// function TemporalWF1Req1(P:temporal, Q:temporal):temporal { imply(P, or(Q, next(or(P, Q)))) } function TemporalWF1Req2(P:temporal, Q:temporal, Action:temporal):temporal { imply(and(P, Action), or(Q, next(Q))) } function TemporalWF1RealTimeDelayedReq2(P:temporal, Q:temporal, Action:temporal, rt:int, timefun:imap):temporal requires imaptotal(timefun) { imply(and(P, nextafter(Action, rt, timefun)), or(Q, next(Q))) } function TemporalWF1RealTimeDelayedImmediateQReq2(P:temporal, Q:temporal, Action:temporal, rt:int, timefun:imap):temporal requires imaptotal(timefun) { imply(and(P, nextafter(Action, rt, timefun)), Q) } ///////////////////// // LEMMAS ///////////////////// lemma TemporalWF1(i:int, P:temporal, Q:temporal, Action:temporal) requires sat(i, always(imply(P, or(Q, next(or(P, Q)))))) requires sat(i, always(imply(and(P, Action), or(Q, next(Q))))) requires sat(i, always(eventual(Action))) ensures sat(i, leadsto(P, Q)) { if !sat(i, leadsto(P, Q)) { TemporalDeduceFromAlways(i, i, imply(P, or(Q, next(or(P, Q))))); TemporalNot(i, imply(P, eventual(Q))); var j := TemporalDeduceFromEventual(i, not(imply(P, eventual(Q)))); assert TLe(i, j) && sat(j, and(P, not(eventual(Q)))); TemporalNot(j, Q); assert sat(j, always(not(Q))); TemporalDeduceFromAlways(i, j, eventual(Action)); var k := TemporalDeduceFromEventual(j, Action); var m := j; while m < k invariant j <= m <= k invariant sat(m, P) { TemporalDeduceFromAlways(i, m, imply(P, or(Q, next(or(P, Q))))); TemporalDeduceFromAlways(j, m, not(Q)); assert sat(m, next(or(P, Q))); TemporalDeduceFromAlways(j, m + 1, not(Q)); m := m + 1; } assert sat(k, P); TemporalDeduceFromAlways(i, k, imply(and(P, Action), or(Q, next(Q)))); TemporalDeduceFromAlways(j, k, not(Q)); TemporalDeduceFromAlways(j, k + 1, not(Q)); assert false; } } lemma TemporalWF1Specific(i:int, action_step:int, P:temporal, Q:temporal) returns (q_step:int) requires i <= action_step requires forall j :: i <= j ==> sat(j, TemporalWF1Req1(P, Q)) requires sat(i, P) requires sat(action_step, imply(P, or(Q, next(Q)))) ensures i <= q_step <= action_step + 1 ensures sat(q_step, Q) { if sat(action_step, P) { assert sat(i, TemporalWF1Req1(P, Q)); q_step := if sat(action_step, Q) then action_step else action_step + 1; return; } var first_non_p_step := earliestStepBetween(i, action_step, not(P)); assert sat(first_non_p_step, not(P)); var transition_step := first_non_p_step - 1; assert first_non_p_step != i; assert sat(transition_step, TemporalWF1Req1(P, Q)); assert !sat(transition_step, not(P)); if sat(transition_step, Q) { q_step := transition_step; } else { assert sat(transition_step, next(or(P, Q))); q_step := first_non_p_step; } } lemma TemporalWF1RealTime(i:int, P:temporal, Q:temporal, action:temporal, span:int, timefun:imap) requires imaptotal(timefun) requires monotonic_from(i, timefun) requires sat(i, always(imply(P, or(Q, next(or(P, Q)))))) requires sat(i, always(imply(and(P, action), or(Q, next(Q))))) requires sat(i, always(eventuallynextwithin(action, span, timefun))) ensures sat(i, leadstowithin(P, Q, span, timefun)) { forall j | TLe(i, j) && sat(j, P) ensures sat(j, eventuallywithin(Q, span, timefun)); { TemporalDeduceFromAlways(i, j, eventuallynextwithin(action, span, timefun)); var k := TemporalDeduceFromEventual(j, nextbefore(action, timefun[j] + span, timefun)); assert TLe(j, k) && sat(k, nextbefore(action, timefun[j] + span, timefun)); assert timefun[nextstep(k)] <= timefun[j] + span; if !sat(j, eventuallywithin(Q, span, timefun)) { assert !sat(j, eventual(beforeabsolutetime(Q, timefun[j] + span, timefun))); TemporalNot(j, beforeabsolutetime(Q, timefun[j] + span, timefun)); assert sat(j, always(not(beforeabsolutetime(Q, timefun[j] + span, timefun)))); TemporalDeduceFromAlways(j, nextstep(k), not(beforeabsolutetime(Q, timefun[j] + span, timefun))); assert !sat(nextstep(k), Q); var a := j; while a < k invariant j <= a <= k invariant sat(a, P) { assert timefun[a] <= timefun[nextstep(a)] <= timefun[k] <= timefun[j] + span; TemporalDeduceFromAlways(j, a, not(beforeabsolutetime(Q, timefun[j] + span, timefun))); TemporalDeduceFromAlways(i, a, imply(P, or(Q, next(or(P, Q))))); TemporalDeduceFromAlways(j, nextstep(a), not(beforeabsolutetime(Q, timefun[j] + span, timefun))); a := a + 1; } assert sat(k, P); TemporalDeduceFromAlways(i, k, imply(and(P, action), or(Q, next(Q)))); assert sat(k, or(Q, next(Q))); if sat(k, Q) { assert i <= k <= k + 0 + 1; // saying "k + 1" triggers too many facts assert timefun[k] <= timefun[nextstep(k)]; assert sat(k, beforeabsolutetime(Q, timefun[j] + span, timefun)); TemporalDeduceFromAlways(j, k, not(beforeabsolutetime(Q, timefun[j] + span, timefun))); } else { assert sat(k, next(Q)); assert false; } } } TemporalAlways(i, imply(P, eventuallywithin(Q, span, timefun))); assert sat(i, leadstowithin(P, Q, span, timefun)); } lemma TemporalWF1RealTimeDelayed(i:int, P:temporal, Q:temporal, action:temporal, span:int, rt:int, timefun:imap) returns (step:int) requires imaptotal(timefun) requires monotonic_from(0, timefun) requires TimeNotZeno(timefun) requires 0 <= span requires 0 <= i requires sat(i, P) requires sat(i, always(imply(P, or(Q, next(or(P, Q)))))) requires sat(i, always(imply(and(P, nextafter(action, rt, timefun)), or(Q, next(Q))))) requires sat(i, always(eventuallynextwithin(action, span, timefun))) ensures i <= step ensures sat(step, Q) ensures timefun[step] <= (if rt >= timefun[i] then rt else timefun[i]) + span { var wait := if rt >= timefun[i] then rt - timefun[i] else 0; reveal after(); var j := Lemma_AlwaysEventuallyWithinMeansAlwaysEventuallyWithinAfter(i, action, wait, span, timefun); assert timefun[j+1] <= (if rt >= timefun[i] then rt else timefun[i]) + span; if sat(i, always(P)) { TemporalDeduceFromAlways(i, j, P); TemporalDeduceFromAlways(i, j, imply(and(P, nextafter(action, rt, timefun)), or(Q, next(Q)))); step := if sat(j, Q) then j else j + 1; } else { TemporalNot(i, P); var k := earliestStep(i, not(P)); assert k != i; assert sat(k-1, not(not(P))); assert sat(k, not(P)); if k > j + 1 { assert i <= j + 1 < k ==> !sat(j, not(P)); TemporalDeduceFromAlways(i, j, imply(and(P, nextafter(action, rt, timefun)), or(Q, next(Q)))); step := if sat(j, Q) then j else j + 1; } else { assert i < k; TemporalDeduceFromAlways(i, k-1, imply(P, or(Q, next(or(P, Q))))); if sat(k-1, Q) { step := k - 1; } else { assert sat(k-1, next(or(P, Q))); assert sat(k, or(P, Q)) by { assert nextstep(k-1) == k; } step := k; } } } } lemma TemporalWF1RealTimeDelayedImmediateQ(i:int, P:temporal, Q:temporal, action:temporal, span:int, rt:int, timefun:imap) returns (step:int) requires imaptotal(timefun) requires monotonic_from(0, timefun) requires TimeNotZeno(timefun) requires 0 <= span requires 0 <= i requires sat(i, P) requires sat(i, always(imply(P, or(Q, next(P))))) requires sat(i, always(imply(and(P, nextafter(action, rt, timefun)), Q))) requires sat(i, always(eventuallynextwithin(action, span, timefun))) ensures i <= step ensures sat(step, Q) ensures timefun[step+1] <= (if rt >= timefun[i] then rt else timefun[i]) + span { var wait := if rt >= timefun[i] then rt - timefun[i] else 0; reveal after(); var j := Lemma_AlwaysEventuallyWithinMeansAlwaysEventuallyWithinAfter(i, action, wait, span, timefun); assert timefun[j+1] <= (if rt >= timefun[i] then rt else timefun[i]) + span; if sat(i, always(P)) { TemporalDeduceFromAlways(i, j, P); TemporalDeduceFromAlways(i, j, imply(and(P, nextafter(action, rt, timefun)), Q)); step := j; } else { TemporalNot(i, P); var k := earliestStep(i, not(P)); assert k != i; assert sat(k-1, not(not(P))); assert sat(k, not(P)); if k > j + 1 { assert i <= j + 1 < k ==> !sat(j, not(P)); TemporalDeduceFromAlways(i, j, imply(and(P, nextafter(action, rt, timefun)), Q)); step := j; } else { assert i < k; TemporalDeduceFromAlways(i, k-1, imply(P, or(Q, next(P)))); assert !sat(k-1, next(P)); assert sat(k-1, Q); step := k - 1; } } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Common/Native/Io.s.dfy ================================================ include "NativeTypes.s.dfy" include "../Framework/Environment.s.dfy" module Native__Io_s { import opened Native__NativeTypes_s import opened Environment_s class HostEnvironment { ghost var ok:OkState; ghost var now:NowState; ghost var net:NetState; ghost var files:FileSystemState; constructor{:axiom} () requires false predicate Valid() reads this { true } } ////////////////////////////////////////////////////////////////////////////// // Failure ////////////////////////////////////////////////////////////////////////////// // not failed; IO operations only allowed when ok() == true class OkState { constructor{:axiom} () requires false function{:axiom} ok():bool reads this } ////////////////////////////////////////////////////////////////////////////// // Print parameters ////////////////////////////////////////////////////////////////////////////// class PrintParams { constructor{:axiom} () requires false static function method{:axiom} ShouldPrintProfilingInfo() : bool static function method{:axiom} ShouldPrintProgress() : bool } ////////////////////////////////////////////////////////////////////////////// // Time ////////////////////////////////////////////////////////////////////////////// // current local real time in milliseconds // (current actually means "current as of last waiting operation or call to GetTime") class NowState { constructor{:axiom} () requires false function{:axiom} now():int reads this } // maximum assumed time taken by any non-waiting code (in milliseconds) function{:axiom} realTimeBound():int predicate AdvanceTime(oldTime:int, newTime:int, delay:int) { oldTime <= newTime < oldTime + delay + realTimeBound() } class Time { static method{:axiom} GetTime(ghost env:HostEnvironment) returns(t:uint64) requires env.Valid() modifies env.now // To avoid contradiction, GetTime must advance time, because successive calls to GetTime can return different values modifies env.net ensures t as int == env.now.now() ensures AdvanceTime(old(env.now.now()), env.now.now(), 0) ensures env.net.history() == old(env.net.history()) + [LIoOpReadClock(t as int)] // Used for performance debugging static method{:axiom} GetDebugTimeTicks() returns(t:uint64) static method{:axiom} RecordTiming(name:array, time:uint64) } ////////////////////////////////////////////////////////////////////////////// // Networking ////////////////////////////////////////////////////////////////////////////// datatype EndPoint = EndPoint(public_key:seq) // NetPacket_ctor has silly name to ferret out backwards calls type NetPacket = LPacket> type NetEvent = LIoOp> function MaxPacketSize() : int { 0xFFFF_FFFF_FFFF_FFFF } predicate ValidPhysicalAddress(endPoint:EndPoint) { |endPoint.public_key| < 0x10_0000 // < 1 MB } predicate ValidPhysicalPacket(p:LPacket>) { && ValidPhysicalAddress(p.src) && ValidPhysicalAddress(p.dst) && |p.msg| <= MaxPacketSize() } predicate ValidPhysicalIo(io:LIoOp>) { && (io.LIoOpReceive? ==> ValidPhysicalPacket(io.r)) && (io.LIoOpSend? ==> ValidPhysicalPacket(io.s)) } class NetState { constructor{:axiom} () requires false function{:axiom} history():seq reads this } class NetClient { ghost var env:HostEnvironment function method{:axiom} MyPublicKey():seq reads this function{:axiom} IsOpen():bool reads this constructor{:axiom} () requires false method{:axiom} Close() returns(ok:bool) requires env.Valid() requires env.ok.ok() requires this.IsOpen() modifies this modifies env.ok ensures env == old(env) ensures env.ok.ok() == ok method{:axiom} Receive(timeLimit:int32) returns(ok:bool, timedOut:bool, remote:seq, buffer:array) requires env.Valid() requires env.ok.ok() requires IsOpen() requires timeLimit >= 0 requires (timeLimit as int) * 1000 < 0x80000000 // only needed when the underlying implementation uses Socket.Poll instead of Task.Wait modifies this modifies env.ok modifies env.now modifies env.net ensures env == old(env) ensures env.ok.ok() == ok ensures AdvanceTime(old(env.now.now()), env.now.now(), timeLimit as int) ensures MyPublicKey() == old(MyPublicKey()) ensures ok ==> IsOpen() ensures ok ==> timedOut ==> env.net.history() == old(env.net.history()) + [LIoOpTimeoutReceive()] ensures ok ==> !timedOut ==> && fresh(buffer) && env.net.history() == old(env.net.history()) + [LIoOpReceive(LPacket(EndPoint(MyPublicKey()), EndPoint(remote), buffer[..]))] && ValidPhysicalAddress(EndPoint(remote)) && buffer.Length <= MaxPacketSize() method{:axiom} Send(remote:seq, buffer:array) returns(ok:bool) requires env.Valid() requires env.ok.ok() requires IsOpen() requires buffer.Length <= MaxPacketSize() modifies this modifies env.ok modifies env.net ensures env == old(env) ensures env.ok.ok() == ok ensures MyPublicKey() == old(MyPublicKey()) ensures ok ==> IsOpen() ensures ok ==> env.net.history() == old(env.net.history()) + [LIoOpSend(LPacket(EndPoint(remote), EndPoint(MyPublicKey()), buffer[..]))] } // jonh temporarily neutered this because the opaque type can't be compiled class FileSystemState { } class MutableSet { static function method {:axiom} SetOf(s:MutableSet) : set reads s static method {:axiom} EmptySet() returns (s:MutableSet) ensures SetOf(s) == {} ensures fresh(s); constructor{:axiom} () requires false method {:axiom} Size() returns (size:int) ensures size == |SetOf(this)| method {:axiom} SizeModest() returns (size:uint64) requires |SetOf(this)| < 0x1_0000_0000_0000_0000 ensures size as int == |SetOf(this)| method {:axiom} Contains(x:T) returns (contains:bool) ensures contains == (x in SetOf(this)) method {:axiom} Add(x:T) modifies this ensures SetOf(this) == old(SetOf(this)) + {x} method {:axiom} AddSet(s:MutableSet) modifies this ensures SetOf(this) == old(SetOf(this)) + old(SetOf(s)) method {:axiom} TransferSet(s:MutableSet) modifies this modifies s ensures SetOf(this) == old(SetOf(s)) ensures SetOf(s) == {} method {:axiom} Remove(x:T) modifies this ensures SetOf(this) == old(SetOf(this)) - {x} method {:axiom} RemoveAll() modifies this ensures SetOf(this) == {} } function KVTupleSeqToMap(kvs: seq<(K, V)>) : (m: map) ensures forall k, v :: (k, v) in kvs ==> k in m ensures forall k :: k in m ==> (k, m[k]) in kvs { if |kvs| == 0 then map [] else var kvs_prefix := kvs[..|kvs|-1]; var m_prefix := KVTupleSeqToMap(kvs_prefix); var kv_last := kvs[|kvs|-1]; m_prefix[kv_last.0 := kv_last.1] } class MutableMap { static function method {:axiom} MapOf(m:MutableMap) : map reads m static method {:axiom} EmptyMap() returns (m:MutableMap) ensures MapOf(m) == map [] ensures fresh(m); static method {:axiom} FromMap(dafny_map:map) returns (m:MutableMap) ensures MapOf(m) == dafny_map ensures fresh(m) static method {:axiom} FromKVTuples(kvs:seq<(K, V)>) returns (m:MutableMap) ensures MapOf(m) == KVTupleSeqToMap(kvs) constructor{:axiom} () requires false function method {:axiom} Size() : int reads this ensures this.Size() == |MapOf(this)| method {:axiom} SizeModest() returns (size:uint64) requires |MapOf(this)| < 0x1_0000_0000_0000_0000 ensures size as int == |MapOf(this)| method {:axiom} Contains(key:K) returns (contains:bool) ensures contains == (key in MapOf(this)) method {:axiom} TryGetValue(key:K) returns (contains:bool, val:V) ensures contains == (key in MapOf(this)) ensures contains ==> val == MapOf(this)[key] method {:axiom} Set(key:K, val:V) modifies this ensures MapOf(this) == old(MapOf(this))[key := val] method {:axiom} Remove(key:K) modifies this ensures MapOf(this) == old(MapOf(this)) - { key } method {:axiom} AsKVTuples() returns (kvs:seq<(K, V)>) ensures |kvs| == |MapOf(this).Keys| ensures forall k :: k in MapOf(this) ==> (k, MapOf(this)[k]) in kvs ensures forall k, v :: (k, v) in kvs ==> k in MapOf(this) && MapOf(this)[k] == v } // Leverage .NET's ability to perform copies faster than one element at a time class Arrays { static method{:axiom} CopySeqIntoArray(src:seq, srcIndex:uint64, dst:array, dstIndex:uint64, len:uint64) requires (srcIndex as int) + (len as int) <= |src| requires (dstIndex as int) + (len as int) <= dst.Length modifies dst ensures forall i :: 0 <= i < dst.Length ==> dst[i] == ( if dstIndex as int <= i < (dstIndex as int) + (len as int) then src[i - (dstIndex as int) + (srcIndex as int)] else old(dst[..])[i]) ensures forall i :: srcIndex as int <= i < (srcIndex as int) + (len as int) ==> src[i] == dst[i - (srcIndex as int) + (dstIndex as int)] } /* ////////////////////////////////////////////////////////////////////////////// // File System ////////////////////////////////////////////////////////////////////////////// type FileSystem datatype FileOp = FileRead(fileReadOffset:int, fileReadBytes:seq) | FileWrite(fileWriteOffset:int, fileWriteBytes:seq) | FileFlush class FileSystemState { constructor{:axiom} () requires false; function{:axiom} state():FileSystem reads this; } function{:axiom} FileOpRequires(fs:FileSystem, fileName:string, op:FileOp):bool function{:axiom} FileOpEnsures(fsOld:FileSystem, fsNew:FileSystem, fileName:string, op:FileOp):bool class FileStream { ghost var env:HostEnvironment; function{:axiom} Name():string reads this; function{:axiom} IsOpen():bool reads this; constructor{:axiom} () requires false; static method{:axiom} Open(name:array, ghost env:HostEnvironment) returns(ok:bool, f:FileStream) requires env.Valid(); requires env.ok.ok(); requires name != null; modifies env.ok; ensures env.ok.ok() == ok; ensures ok ==> f != null && fresh(f) && f.env == env && f.IsOpen() && f.Name() == name[..]; method{:axiom} Close() returns(ok:bool) requires env.Valid(); requires env.ok.ok(); requires IsOpen(); modifies this; modifies env.ok; ensures env == old(env); ensures env.ok.ok() == ok; method{:axiom} Read(fileOffset:nat32, buffer:array, start:int32, end:int32) returns(ok:bool) requires env.Valid(); requires env.ok.ok(); requires IsOpen(); requires buffer != null; requires 0 <= start as int <= end as int <= buffer.Length; requires FileOpRequires(env.files.state(), Name(), FileRead(fileOffset as int, buffer[start..end])); modifies this; modifies env.ok; modifies env.files; modifies buffer; ensures env == old(env); ensures env.ok.ok() == ok; ensures Name() == old(Name()); ensures forall i:int :: 0 <= i < buffer.Length && !(start as int <= i < end as int) ==> buffer[i] == old(buffer[i]); ensures ok ==> IsOpen(); ensures ok ==> FileOpEnsures(old(env.files.state()), env.files.state(), Name(), FileRead(fileOffset as int, buffer[start..end])); method{:axiom} Write(fileOffset:nat32, buffer:array, start:int32, end:int32) returns(ok:bool) requires env.Valid(); requires env.ok.ok(); requires IsOpen(); requires buffer != null; requires 0 <= start as int <= end as int <= buffer.Length; requires FileOpRequires(env.files.state(), Name(), FileWrite(fileOffset as int, buffer[start..end])); modifies this; modifies env.ok; modifies env.files; ensures env == old(env); ensures env.ok.ok() == ok; ensures Name() == old(Name()); ensures ok ==> IsOpen(); ensures ok ==> FileOpEnsures(old(env.files.state()), env.files.state(), Name(), FileWrite(fileOffset as int, buffer[start..end])); method{:axiom} Flush() returns(ok:bool) requires env.Valid(); requires env.ok.ok(); requires IsOpen(); requires FileOpRequires(env.files.state(), Name(), FileFlush); modifies this; modifies env.ok; modifies env.files; ensures env == old(env); ensures env.ok.ok() == ok; ensures Name() == old(Name()); ensures ok ==> IsOpen(); ensures ok ==> FileOpEnsures(old(env.files.state()), env.files.state(), Name(), FileFlush); } */ } ================================================ FILE: ironfleet/src/Dafny/Distributed/Common/Native/IoFramework.cs ================================================ using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Net.Security; using System.Net.Sockets; using System.Text; using System.Text.Json; using System.Threading; using System.Threading.Tasks.Dataflow; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; namespace IronfleetIoFramework { public class PrivateIdentity { public string FriendlyName { get; set; } public byte[] Pkcs12 { get; set; } public string HostNameOrAddress { get; set; } public int Port { get; set; } public bool WriteToFile (string fileName) { string json; try { json = JsonSerializer.Serialize(this); } catch (Exception e) { Console.Error.WriteLine("Could not serialize private key data for {0}. Exception:\n{1}", FriendlyName, e); return false; } try { File.WriteAllText(fileName, json); } catch (Exception e) { Console.Error.WriteLine("Could not create file {0}. Exception:\n{1}", fileName, e); return false; } return true; } public static PrivateIdentity ReadFromFile(string fileName) { string json; try { json = File.ReadAllText(fileName); } catch (Exception) { Console.Error.WriteLine("ERROR - Could not read contents of private key file {0}", fileName); return null; } PrivateIdentity privateIdentity; try { privateIdentity = JsonSerializer.Deserialize(json); } catch (Exception e) { Console.Error.WriteLine("Could not deserialize contents of private key file {0}. Exception:\n{1}", fileName, e); return null; } return privateIdentity; } } public class PublicIdentity { public string FriendlyName { get; set; } public byte[] PublicKey { get; set; } public string HostNameOrAddress { get; set; } public int Port { get; set; } } public class ServiceIdentity { public string FriendlyName { get; set; } public string ServiceType { get; set; } public List Servers { get; set; } public bool UseSsl { get; set; } public bool WriteToFile(string fileName) { string json; try { json = JsonSerializer.Serialize(this); } catch (Exception e) { Console.Error.WriteLine("Could not serialize service identity. Exception:\n{0}", e); return false; } try { File.WriteAllText(fileName, json); } catch (Exception e) { Console.Error.WriteLine("Could not write service identity to file {0}. Exception:\n{1}", fileName, e); return false; } return true; } public static ServiceIdentity ReadFromFile(string fileName) { string json; try { json = File.ReadAllText(fileName); } catch (Exception) { Console.Error.WriteLine("ERROR - Could not read contents of service file {0}", fileName); return null; } ServiceIdentity serviceIdentity; try { serviceIdentity = JsonSerializer.Deserialize(json); } catch (Exception e) { Console.Error.WriteLine("Could not deserialize contents of service file {0}. Exception:\n{1}", fileName, e); return null; } return serviceIdentity; } } public class ByteArrayComparer : IEqualityComparer { private static ByteArrayComparer staticDefault; public static ByteArrayComparer Default() { if (staticDefault == null) { staticDefault = new ByteArrayComparer(); } return staticDefault; } public bool Equals (byte[] a1, byte[] a2) { return StructuralComparisons.StructuralEqualityComparer.Equals(a1, a2); } public int GetHashCode(byte[] a) { return StructuralComparisons.StructuralEqualityComparer.GetHashCode(a); } } public class IronfleetCrypto { public static void CreateNewIdentity(string friendlyName, string hostNameOrAddress, int port, out PublicIdentity publicIdentity, out PrivateIdentity privateIdentity) { var key = RSA.Create(4096); var subject = string.Format("CN = {0}", friendlyName); var req = new CertificateRequest(subject, key, HashAlgorithmName.SHA256, RSASignaturePadding.Pss); var now = DateTime.Now; var expiry = now.AddYears(10); var cert = req.CreateSelfSigned(now, expiry); var pkcs12 = cert.Export(X509ContentType.Pkcs12, "" /* empty password */); publicIdentity = new PublicIdentity { FriendlyName = friendlyName, PublicKey = IoScheduler.GetCertificatePublicKey(cert), HostNameOrAddress = hostNameOrAddress, Port = port }; privateIdentity = new PrivateIdentity { FriendlyName = friendlyName, Pkcs12 = pkcs12, HostNameOrAddress = hostNameOrAddress, Port = port }; } public static X509Certificate2 CreateTransientClientIdentity () { var key = RSA.Create(2048); var req = new CertificateRequest("CN = client", key, HashAlgorithmName.SHA256, RSASignaturePadding.Pss); var now = DateTime.Now; var expiry = now.AddYears(1); var cert = req.CreateSelfSigned(now, expiry); // On Linux, it's OK to just return cert. But on Windows, we need the following // code to allow it to be used to authenticate a client. return new X509Certificate2(cert.Export(X509ContentType.Pkcs12)); } } public class IoEncoder { private static int MAX_IO_SIZE = 0x80_0000 /* 8 MB */; public static bool ReadBytes(Stream stream, byte[] buf, int offset, UInt64 byteCount) { UInt64 bytesRead = 0; while (bytesRead < byteCount) { int bytesToRead = (byteCount - bytesRead > (UInt64)(MAX_IO_SIZE)) ? MAX_IO_SIZE : (int)(byteCount - bytesRead); int additionalBytesRead = stream.Read(buf, offset + (int)bytesRead, bytesToRead); if (additionalBytesRead == 0) { return false; } bytesRead += (UInt64)additionalBytesRead; } return true; } public static void WriteBytes(Stream stream, byte[] buf, int offset, UInt64 byteCount) { UInt64 bytesWritten = 0; while (bytesWritten < byteCount) { int bytesToWrite = (byteCount - bytesWritten > (UInt64)(MAX_IO_SIZE)) ? MAX_IO_SIZE : (int)(byteCount - bytesWritten); stream.Write(buf, offset + (int)bytesWritten, bytesToWrite); bytesWritten += (UInt64)(bytesToWrite); } } public static UInt64 ExtractUInt64(byte[] bytes, int offset) { byte[] extractedBytes = bytes.Skip(offset).Take(8).ToArray(); if (BitConverter.IsLittleEndian) { Array.Reverse(extractedBytes); } return BitConverter.ToUInt64(extractedBytes, 0); } public static UInt32 ExtractUInt32(byte[] bytes, int offset) { byte[] extractedBytes = bytes.Skip(offset).Take(4).ToArray(); if (BitConverter.IsLittleEndian) { Array.Reverse(extractedBytes); } return BitConverter.ToUInt32(extractedBytes, 0); } public static Int32 ExtractInt32(byte[] bytes, int offset) { byte[] extractedBytes = bytes.Skip(offset).Take(4).ToArray(); if (BitConverter.IsLittleEndian) { Array.Reverse(extractedBytes); } return BitConverter.ToInt32(extractedBytes, 0); } public static void WriteUInt64(Stream stream, UInt64 value) { var bytes = BitConverter.GetBytes(value); if (BitConverter.IsLittleEndian) { Array.Reverse(bytes); } WriteBytes(stream, bytes, 0, 8); } public static void WriteUInt32(Stream stream, UInt32 value) { var bytes = BitConverter.GetBytes(value); if (BitConverter.IsLittleEndian) { Array.Reverse(bytes); } WriteBytes(stream, bytes, 0, 4); } public static void WriteInt32(Stream stream, Int32 value) { var bytes = BitConverter.GetBytes(value); if (BitConverter.IsLittleEndian) { Array.Reverse(bytes); } WriteBytes(stream, bytes, 0, 4); } public static bool ReadUInt64(Stream stream, out UInt64 value) { byte[] buf8 = new byte[8]; bool success = ReadBytes(stream, buf8, 0, 8); if (success) { if (BitConverter.IsLittleEndian) { Array.Reverse(buf8); } value = BitConverter.ToUInt64(buf8); } else { value = 0; } return success; } public static bool ReadUInt32(Stream stream, out UInt32 value) { byte[] buf4 = new byte[4]; bool success = ReadBytes(stream, buf4, 0, 4); if (success) { if (BitConverter.IsLittleEndian) { Array.Reverse(buf4); } value = BitConverter.ToUInt32(buf4); } else { value = 0; } return success; } public static bool ReadInt32(Stream stream, out Int32 value) { byte[] buf4 = new byte[4]; bool success = ReadBytes(stream, buf4, 0, 4); if (success) { if (BitConverter.IsLittleEndian) { Array.Reverse(buf4); } value = BitConverter.ToInt32(buf4); } else { value = 0; } return success; } } public class ReceivedPacket { public byte[] senderKeyHash { get; } public byte[] message { get; } public ReceivedPacket(byte[] i_senderKeyHash, byte[] i_message) { senderKeyHash = i_senderKeyHash; message = i_message; } } public class SendTask { public byte[] destinationPublicKeyHash { get; } public byte[] message { get; } private int numTriesSoFar; public SendTask(byte[] i_destinationPublicKeyHash, byte[] i_message) { destinationPublicKeyHash = i_destinationPublicKeyHash; message = i_message; numTriesSoFar = 0; } public int IncrementNumTriesSoFar() { numTriesSoFar++; return numTriesSoFar; } } public class CertificateValidator { private IoScheduler scheduler; private PublicIdentity expectedPublicIdentity; public CertificateValidator(IoScheduler i_scheduler, PublicIdentity i_expectedPublicIdentity = null) { scheduler = i_scheduler; expectedPublicIdentity = i_expectedPublicIdentity; } public bool ValidateSSLCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { const SslPolicyErrors ignoredErrors = SslPolicyErrors.RemoteCertificateChainErrors; if ((sslPolicyErrors & ~ignoredErrors) != SslPolicyErrors.None) { Console.Error.WriteLine("Could not validate SSL certificate for {0} due to errors {1}", IoScheduler.GetCertificatePublicKey(certificate as X509Certificate2), sslPolicyErrors & ~ignoredErrors); return false; } var cert2 = certificate as X509Certificate2; // If we were expecting a specific public identity, check that // the key in the certificate matches what we were expecting. if (expectedPublicIdentity != null) { if (!ByteArrayComparer.Default().Equals(IoScheduler.GetCertificatePublicKey(cert2), expectedPublicIdentity.PublicKey)) { Console.Error.WriteLine("Connected to {0} expecting public key {1} but found public key {2}, so disconnecting.", IoScheduler.PublicIdentityToString(expectedPublicIdentity), IoScheduler.PublicKeyToString(expectedPublicIdentity.PublicKey), IoScheduler.PublicKeyToString(IoScheduler.GetCertificatePublicKey(cert2))); return false; } if (cert2.SubjectName.Name != "CN=" + expectedPublicIdentity.FriendlyName) { Console.Error.WriteLine("Connected to {0} expecting subject CN={1} but found {2}, so disconnecting.", IoScheduler.PublicIdentityToString(expectedPublicIdentity), expectedPublicIdentity.FriendlyName, cert2.SubjectName.Name); return false; } } else { // If we weren't expecting any particular public identity, // consider the expected public identity to be the known one // matching the public key in the certificate we got. If // there is no known one, then this is just an anonymous // client, which is fine. Otherwise, check that the subject // matches what we expect. This is just a paranoid check; it // should never fail. expectedPublicIdentity = scheduler.LookupPublicKeyHash(scheduler.HashPublicKey(IoScheduler.GetCertificatePublicKey(cert2))); if (expectedPublicIdentity != null) { if (cert2.SubjectName.Name != "CN=" + expectedPublicIdentity.FriendlyName) { Console.Error.WriteLine("Received a certificate we expected to have subject CN={1} but found {2}, so disconnecting.", IoScheduler.PublicIdentityToString(expectedPublicIdentity), expectedPublicIdentity.FriendlyName, cert2.SubjectName.Name); return false; } } } return true; } } public class ReceiverThread { private IoScheduler scheduler; private Stream stream; private byte[] remoteKeyHash; private ReceiverThread(IoScheduler i_scheduler, byte[] i_remoteKeyHash, Stream i_stream) { scheduler = i_scheduler; stream = i_stream; remoteKeyHash = i_remoteKeyHash; } public void Run() { try { ReceiveLoop(); } catch (Exception e) { scheduler.ReportException(e, "receiving from " + scheduler.LookupPublicKeyHashAsString(remoteKeyHash)); } } public static ReceiverThread Create(IoScheduler scheduler, byte[] remoteKeyHash, Stream stream) { ReceiverThread receiverThread = new ReceiverThread(scheduler, remoteKeyHash, stream); Thread t = new Thread(receiverThread.Run); t.Start(); return receiverThread; } private void ReceiveLoop() { bool success; if (scheduler.Verbose) { Console.WriteLine("Starting receive loop with remote identified as {0}", scheduler.LookupPublicKeyHashAsString(remoteKeyHash)); } while (true) { // Read the next message's size. UInt64 messageSize; success = IoEncoder.ReadUInt64(stream, out messageSize); if (!success) { if (scheduler.Verbose) { Console.Error.WriteLine("Failed to receive message size from {0}", scheduler.LookupPublicKeyHashAsString(remoteKeyHash)); } return; } if (scheduler.Verbose) { Console.WriteLine("Received message size {0} from {1}", messageSize, scheduler.LookupPublicKeyHashAsString(remoteKeyHash)); } byte[] messageBuf = new byte[messageSize]; success = IoEncoder.ReadBytes(stream, messageBuf, 0, messageSize); if (!success) { if (scheduler.Verbose) { Console.Error.WriteLine("Failed to receive message of size {0} from {1}", messageSize, scheduler.LookupPublicKeyHashAsString(remoteKeyHash)); } return; } if (scheduler.Verbose) { Console.WriteLine("Received message of size {0} from {1}", messageSize, scheduler.LookupPublicKeyHashAsString(remoteKeyHash)); } ReceivedPacket packet = new ReceivedPacket(remoteKeyHash, messageBuf); scheduler.NoteReceivedPacket(packet); } } } public abstract class SenderThread { protected IoScheduler scheduler; protected byte[] destinationPublicKeyHash; protected Stream stream; private BufferBlock sendQueue; private SendTask currentSendTask; protected SenderThread(IoScheduler i_scheduler, byte[] i_destinationPublicKeyHash, Stream i_stream) { scheduler = i_scheduler; destinationPublicKeyHash = i_destinationPublicKeyHash; stream = i_stream; sendQueue = new BufferBlock(); currentSendTask = null; } protected string EndpointDescription() { return scheduler.LookupPublicKeyHashAsString(destinationPublicKeyHash); } protected abstract bool Connect(); public void Start() { scheduler.RegisterSender(destinationPublicKeyHash, this); Thread t = new Thread(this.Run); t.Start(); } private void Run() { try { if (Connect()) { SendLoop(); } } catch (Exception e) { scheduler.ReportException(e, "sending to " + EndpointDescription()); } scheduler.UnregisterSender(destinationPublicKeyHash, this); // If we crashed in the middle of sending a packet, re-queue it // for sending by another sender thread. if (currentSendTask != null) { scheduler.ResendPacket(currentSendTask); currentSendTask = null; } // If there are packets queued for us to send, re-queue them // for sending by another sender thread. while (sendQueue.TryReceive(out currentSendTask)) { scheduler.ResendPacket(currentSendTask); currentSendTask = null; } } private void SendLoop() { if (scheduler.Verbose) { Console.WriteLine("Starting send loop with {0}", EndpointDescription()); } while (true) { // Wait for there to be a packet to send. currentSendTask = sendQueue.Receive(); // Send its length as an 8-byte value. UInt64 messageSize = (UInt64)currentSendTask.message.Length; IoEncoder.WriteUInt64(stream, messageSize); if (scheduler.Verbose) { Console.WriteLine("Sent message size {0} to {1}", messageSize, EndpointDescription()); } // Send its contents. IoEncoder.WriteBytes(stream, currentSendTask.message, 0, messageSize); if (scheduler.Verbose) { Console.WriteLine("Sent message of size {0} to {1}", messageSize, EndpointDescription()); } // Set the currentSendTask to null so we know we don't have to // resend it if the connection fails. currentSendTask = null; } } public void EnqueueSendTask(SendTask sendTask) { sendQueue.Post(sendTask); } } public class ServerSenderThread : SenderThread { private ServerSenderThread(IoScheduler i_scheduler, byte[] i_destinationPublicKeyHash, Stream i_stream) : base(i_scheduler, i_destinationPublicKeyHash, i_stream) { } public static ServerSenderThread Create(IoScheduler scheduler, byte[] destinationPublicKeyHash, Stream stream) { if (scheduler.Verbose) { Console.WriteLine("Creating sender thread to send to remote {0}", scheduler.LookupPublicKeyHashAsString(destinationPublicKeyHash)); } ServerSenderThread senderThread = new ServerSenderThread(scheduler, destinationPublicKeyHash, stream); senderThread.Start(); return senderThread; } protected override bool Connect() { // There's nothing to do since server sender threads start out connected. return true; } } public class ClientSenderThread : SenderThread { protected bool useSsl; private ClientSenderThread(IoScheduler i_scheduler, byte[] i_destinationPublicKeyHash, bool i_useSsl) : base(i_scheduler, i_destinationPublicKeyHash, null) { useSsl = i_useSsl; } public static ClientSenderThread Create(IoScheduler scheduler, byte[] destinationPublicKeyHash, bool useSsl) { if (scheduler.Verbose) { Console.WriteLine("Creating sender thread to send to remote {0}", scheduler.LookupPublicKeyHashAsString(destinationPublicKeyHash)); } ClientSenderThread senderThread = new ClientSenderThread(scheduler, destinationPublicKeyHash, useSsl); senderThread.Start(); return senderThread; } protected override bool Connect() { var destinationPublicIdentity = scheduler.LookupPublicKeyHash(destinationPublicKeyHash); if (destinationPublicIdentity == null) { if (scheduler.Verbose) { Console.Error.WriteLine("Could not connect to destination public key hash {0} because we don't know its address.", System.Convert.ToBase64String(destinationPublicKeyHash)); } return false; } if (scheduler.Verbose) { Console.WriteLine("Starting connection to {0}", IoScheduler.PublicIdentityToString(destinationPublicIdentity)); } TcpClient client; try { client = new TcpClient(destinationPublicIdentity.HostNameOrAddress, destinationPublicIdentity.Port); } catch (Exception e) { scheduler.ReportException(e, "connecting to " + IoScheduler.PublicIdentityToString(destinationPublicIdentity)); return false; } if (useSsl) { var myCertificateCollection = new X509CertificateCollection(); myCertificateCollection.Add(scheduler.MyCert); var myValidator = new CertificateValidator(scheduler, destinationPublicIdentity); SslStream s; try { s = new SslStream(client.GetStream(), leaveInnerStreamOpen: false, myValidator.ValidateSSLCertificate); s.AuthenticateAsClient(destinationPublicIdentity.FriendlyName, myCertificateCollection, checkCertificateRevocation: false); } catch (Exception e) { scheduler.ReportException(e, "authenticating connection to " + IoScheduler.PublicIdentityToString(destinationPublicIdentity)); return false; } var remoteCert = s.RemoteCertificate as X509Certificate2; if (!ByteArrayComparer.Default().Equals(IoScheduler.GetCertificatePublicKey(remoteCert), destinationPublicIdentity.PublicKey)) { Console.Error.WriteLine("Connected to {0} expecting public key {1} but found public key {2}, so disconnecting.", IoScheduler.PublicIdentityToString(destinationPublicIdentity), IoScheduler.PublicKeyToString(destinationPublicIdentity.PublicKey), IoScheduler.PublicKeyToString(IoScheduler.GetCertificatePublicKey(remoteCert))); return false; } if (scheduler.Verbose) { Console.WriteLine("Successfully connected to {0} and got certificate identifying it as {1}", IoScheduler.PublicIdentityToString(destinationPublicIdentity), IoScheduler.CertificateToString(remoteCert)); } stream = (Stream) s; } else { stream = client.GetStream(); var myKey = IoScheduler.GetCertificatePublicKey(scheduler.MyCert); if (scheduler.Verbose) { Console.WriteLine("Sending my public key {0} to {1}", IoScheduler.PublicKeyToString(myKey), scheduler.LookupPublicKeyHashAsString(destinationPublicKeyHash)); } IoEncoder.WriteUInt64(stream, (ulong) myKey.Length); IoEncoder.WriteBytes(stream, myKey, 0, (ulong) myKey.Length); if (scheduler.Verbose) { Console.WriteLine("Successfully connected to {0} without certificate", IoScheduler.PublicIdentityToString(destinationPublicIdentity)); } } // Now that the connection is successful, create a thread to // receive packets on it. ReceiverThread receiverThread = ReceiverThread.Create(scheduler, destinationPublicKeyHash, stream); return true; } } public class ListenerThread { private IoScheduler scheduler; private TcpListener listener; private IPEndPoint myEndpoint; private bool useSsl; public ListenerThread(IoScheduler i_scheduler, IPEndPoint i_myEndpoint, bool i_useSsl) { scheduler = i_scheduler; myEndpoint = i_myEndpoint; useSsl = i_useSsl; } public void Run() { while (true) { try { ListenLoop(); } catch (Exception e) { Console.Error.WriteLine("Listener thread caught the following exception, so restarting:\n{0}", e); } } } private void ListenLoop() { if (scheduler.Verbose) { Console.WriteLine("Starting to listen on {0}", myEndpoint); } listener = new TcpListener(myEndpoint); listener.ExclusiveAddressUse = true; listener.Start(); while (true) { if (scheduler.Verbose) { Console.WriteLine("Waiting for the next incoming connection"); } TcpClient client = listener.AcceptTcpClient(); Stream stream = client.GetStream(); byte[] remoteKeyHash; if (useSsl) { CertificateValidator myValidator = new CertificateValidator(scheduler); SslStream sslStream = new SslStream(stream, leaveInnerStreamOpen: false, myValidator.ValidateSSLCertificate); sslStream.AuthenticateAsServer(scheduler.MyCert, clientCertificateRequired: true, checkCertificateRevocation: false); var remoteCert = sslStream.RemoteCertificate as X509Certificate2; stream = (Stream) sslStream; var key = IoScheduler.GetCertificatePublicKey(remoteCert); remoteKeyHash = scheduler.HashPublicKey(key); //Hash the key } else { UInt64 len; bool success; success = IoEncoder.ReadUInt64(stream, out len); if (!success) { Console.WriteLine("Failed to receive the length of public key from {0}", client.Client.RemoteEndPoint.ToString()); continue; } byte[] remoteKey = new byte[len]; success = IoEncoder.ReadBytes(stream, remoteKey, 0, len); remoteKeyHash = scheduler.HashPublicKey(remoteKey); //Hash the key if (!success) { Console.WriteLine("Failed to receive public key from {0}", client.Client.RemoteEndPoint.ToString()); continue; } } if (scheduler.Verbose) { Console.WriteLine("Received an incoming connection from remote identity as {0}", scheduler.LookupPublicKeyHashAsString(remoteKeyHash)); } ReceiverThread.Create(scheduler, remoteKeyHash, stream); ServerSenderThread.Create(scheduler, remoteKeyHash, stream); } } } public class SendDispatchThread { private IoScheduler scheduler; private bool useSsl; private BufferBlock sendQueue; public SendDispatchThread(IoScheduler i_scheduler, bool i_useSsl) { scheduler = i_scheduler; useSsl = i_useSsl; sendQueue = new BufferBlock(); } public void Run() { while (true) { try { SendDispatchLoop(); } catch (Exception e) { Console.Error.WriteLine("Send dispatch thread caught the following exception, so restarting:\n{0}", e); } } } private void SendDispatchLoop() { while (true) { if (scheduler.Verbose) { Console.WriteLine("Waiting for the next send to dispatch"); } SendTask sendTask = sendQueue.Receive(); if (scheduler.Verbose) { Console.WriteLine("Dispatching send of message of size {0} to {1}", sendTask.message.Length, scheduler.LookupPublicKeyHashAsString(sendTask.destinationPublicKeyHash)); } SenderThread senderThread = scheduler.FindSenderForDestinationPublicKeyHash(sendTask.destinationPublicKeyHash); if (senderThread == null) { senderThread = ClientSenderThread.Create(scheduler, sendTask.destinationPublicKeyHash, useSsl); } senderThread.EnqueueSendTask(sendTask); } } public void EnqueueSendTask(SendTask sendTask) { sendQueue.Post(sendTask); } } public class IoScheduler { private X509Certificate2 myCert; private bool onlyClient; private bool verbose; private bool useSsl; private int maxSendTries; private BufferBlock receiveQueue; private Dictionary> destinationPublicKeyHashToSenderThreadMap; private Dictionary publicKeyHashToPublicIdentityMap; private ListenerThread listenerThread; private SendDispatchThread sendDispatchThread; private SHA256 hasher; private IoScheduler(PrivateIdentity myIdentity, string localHostNameOrAddress, int localPort, List knownIdentities, bool i_verbose, bool i_useSsl, int i_maxSendTries = 3) { verbose = i_verbose; useSsl = i_useSsl; maxSendTries = i_maxSendTries; receiveQueue = new BufferBlock(); destinationPublicKeyHashToSenderThreadMap = new Dictionary>(ByteArrayComparer.Default()); publicKeyHashToPublicIdentityMap = new Dictionary(ByteArrayComparer.Default()); hasher = SHA256.Create(); foreach (var knownIdentity in knownIdentities) { publicKeyHashToPublicIdentityMap[HashPublicKey(knownIdentity.PublicKey)] = knownIdentity; } if (myIdentity == null) { StartClient(); } else { StartServer(myIdentity, localHostNameOrAddress, localPort); } } public static IoScheduler CreateServer(PrivateIdentity myIdentity, string localHostNameOrAddress, int localPort, List knownIdentities, bool verbose, bool useSsl, int maxSendTries = 3) { return new IoScheduler(myIdentity, localHostNameOrAddress, localPort, knownIdentities, verbose, useSsl, maxSendTries); } public static IoScheduler CreateClient(List serverIdentities, bool verbose, bool useSsl, bool connectToAllServers = true, int maxSendTries = 3) { var scheduler = new IoScheduler(null, null, 0, serverIdentities, verbose, useSsl, maxSendTries); if (connectToAllServers) { foreach (var serverIdentity in serverIdentities) { scheduler.Connect(scheduler.HashPublicKey(serverIdentity.PublicKey)); } } return scheduler; } private void StartServer(PrivateIdentity myIdentity, string localHostNameOrAddress, int localPort) { onlyClient = false; try { myCert = new X509Certificate2(myIdentity.Pkcs12, "" /* empty password */, X509KeyStorageFlags.Exportable); } catch (Exception e) { Console.Error.WriteLine("Could not import private key. Exception:{0}", e); throw new Exception("Can't start server because private key not decryptable"); } // The `local` parameters override the parameters in // `myIdentity`, unless they're empty or zero. if (localHostNameOrAddress == null || localHostNameOrAddress.Length == 0) { localHostNameOrAddress = myIdentity.HostNameOrAddress; } if (localPort == 0) { localPort = myIdentity.Port; } var address = LookupHostNameOrAddress(localHostNameOrAddress); if (address == null) { Console.Error.WriteLine("ERROR: Could not find any addresses when resolving {0}, which I'm supposed to bind to."); throw new Exception("Can't resolve binding address"); } var myEndpoint = new IPEndPoint(address, localPort); if (verbose) { Console.WriteLine("Starting I/O scheduler as server listening to {0} certified as {1}", myEndpoint, IoScheduler.CertificateToString(myCert)); } sendDispatchThread = new SendDispatchThread(this, useSsl); Thread st = new Thread(sendDispatchThread.Run); st.Start(); // Start a thread to listen on my binding endpoint. listenerThread = new ListenerThread(this, myEndpoint, useSsl); Thread lt = new Thread(listenerThread.Run); lt.Start(); } private void StartClient() { onlyClient = true; myCert = IronfleetCrypto.CreateTransientClientIdentity(); if (verbose) { Console.WriteLine("Starting I/O scheduler as client with certificate {0}", IoScheduler.CertificateToString(myCert)); } sendDispatchThread = new SendDispatchThread(this, useSsl); Thread st = new Thread(sendDispatchThread.Run); st.Start(); } private static IPAddress LookupHostNameOrAddress(string hostNameOrAddress) { var addresses = Dns.GetHostAddresses(hostNameOrAddress); if (addresses.Length < 1) { return null; } // Return the first IPv4 address in the list. foreach (var address in addresses) { if (address.AddressFamily == AddressFamily.InterNetwork) { return address; } } // If there was no IPv4 address, return the first address in the // list. return addresses[0]; } public bool Verbose { get { return verbose; } } public bool OnlyClient { get { return onlyClient; } } public X509Certificate2 MyCert { get { return myCert; } } ///////////////////////////////////// // SENDING ///////////////////////////////////// public void RegisterSender(byte[] destinationPublicKeyHash, SenderThread senderThread) { lock (destinationPublicKeyHashToSenderThreadMap) { if (destinationPublicKeyHashToSenderThreadMap.ContainsKey(destinationPublicKeyHash)) { destinationPublicKeyHashToSenderThreadMap[destinationPublicKeyHash].Insert(0, senderThread); } else { destinationPublicKeyHashToSenderThreadMap[destinationPublicKeyHash] = new List { senderThread }; } } } public void UnregisterSender(byte[] destinationPublicKeyHash, SenderThread senderThread) { lock (destinationPublicKeyHashToSenderThreadMap) { destinationPublicKeyHashToSenderThreadMap[destinationPublicKeyHash].Remove(senderThread); } } public SenderThread FindSenderForDestinationPublicKeyHash(byte[] destinationPublicKeyHash) { lock (destinationPublicKeyHashToSenderThreadMap) { if (destinationPublicKeyHashToSenderThreadMap.ContainsKey(destinationPublicKeyHash) && destinationPublicKeyHashToSenderThreadMap[destinationPublicKeyHash].Count > 0) { return destinationPublicKeyHashToSenderThreadMap[destinationPublicKeyHash][0]; } } return null; } ///////////////////////////////////// // RECEIVING ///////////////////////////////////// public void NoteReceivedPacket(ReceivedPacket packet) { receiveQueue.Post(packet); } ///////////////////////////////////// // UTILITY METHODS ///////////////////////////////////// public static byte[] GetCertificatePublicKey(X509Certificate2 cert) { return cert.PublicKey.EncodedKeyValue.RawData; } public byte[] HashPublicKey(byte[] publicKey) { return hasher.ComputeHash(publicKey); } public static string PublicKeyToString(byte[] destinationPublicKey) { return System.Convert.ToBase64String(destinationPublicKey).Substring(12, 8); } public static string PublicIdentityToString(PublicIdentity id) { return string.Format("{0} (key {1}) @ {2}:{3}", id.FriendlyName, PublicKeyToString(id.PublicKey), id.HostNameOrAddress, id.Port); } public static string CertificateToString(X509Certificate2 cert) { return string.Format("{0} (key {1})", cert.SubjectName.Name, PublicKeyToString(IoScheduler.GetCertificatePublicKey(cert))); } public PublicIdentity LookupPublicKeyHash(byte[] publicKeyHash) { PublicIdentity publicIdentity; if (!publicKeyHashToPublicIdentityMap.TryGetValue(publicKeyHash, out publicIdentity)) { return null; } else { return publicIdentity; } } public string LookupPublicKeyHashAsString(byte[] destinationPublicKeyHash) { var publicIdentity = LookupPublicKeyHash(destinationPublicKeyHash); if (publicIdentity == null) { return System.Convert.ToBase64String(destinationPublicKeyHash); } else { return PublicIdentityToString(publicIdentity); } } public void ReportException(Exception e, string activity) { if (e is IOException ioe) { e = ioe.InnerException; } if (e is SocketException se) { if (se.SocketErrorCode == SocketError.ConnectionReset) { if (verbose) { Console.WriteLine("Stopped {0} because of a connection reset. Will try again later if necessary.", activity); } return; } if (se.SocketErrorCode == SocketError.ConnectionRefused) { if (verbose) { Console.WriteLine("Stopped {0} because the connection was refused. Will try again later if necessary.", activity); } return; } if (se.SocketErrorCode == SocketError.Shutdown) { if (verbose) { Console.WriteLine("Stopped {0} because the connection was shut down. Will try again later if necessary.", activity); } return; } } Console.WriteLine("Stopped {0} because of the following exception, but will try again later if necessary:\n{1}", activity, e); } /////////////////////////////////// // API for IoNative.cs /////////////////////////////////// public void ReceivePacket(Int32 timeLimit, out bool ok, out bool timedOut, out byte[] remotePublicKeyHash, out byte[] message) { ReceivedPacket packet; try { if (timeLimit == 0) { timedOut = !receiveQueue.TryReceive(out packet); } else { TimeSpan timeSpan = TimeSpan.FromMilliseconds(timeLimit); packet = receiveQueue.Receive(timeSpan); timedOut = false; } ok = true; if (timedOut) { remotePublicKeyHash = null; message = null; } else { remotePublicKeyHash = packet.senderKeyHash; message = packet.message; if (verbose) { Console.WriteLine("Dequeueing a packet of size {0} from {1}", message.Length, LookupPublicKeyHashAsString(remotePublicKeyHash)); } } } catch (TimeoutException) { remotePublicKeyHash = null; message = null; ok = true; timedOut = true; } catch (Exception e) { Console.Error.WriteLine("Unexpected error trying to read packet from packet queue. Exception:\n{0}", e); remotePublicKeyHash = null; message = null; ok = false; timedOut = false; } } public bool SendPacket(byte[] remotePublicKeyHash, byte[] message) { try { byte[] messageCopy = new byte[message.Length]; Array.Copy(message, messageCopy, message.Length); byte[] remotePublicKeyHashCopy = new byte[remotePublicKeyHash.Length]; Array.Copy(remotePublicKeyHash, remotePublicKeyHashCopy, remotePublicKeyHash.Length); SendTask sendTask = new SendTask(remotePublicKeyHashCopy, messageCopy); if (verbose) { Console.WriteLine("Enqueueing send of a message of size {0} to {1}", message.Length, LookupPublicKeyHashAsString(remotePublicKeyHash)); } sendDispatchThread.EnqueueSendTask(sendTask); return true; } catch (Exception e) { Console.Error.WriteLine("Unexpected error when trying to send a message. Exception:\n{0}", e); return false; } } public void ResendPacket(SendTask sendTask) { if (sendTask.IncrementNumTriesSoFar() < maxSendTries) { sendDispatchThread.EnqueueSendTask(sendTask); } } /////////////////////////////////// // Extra API calls for client /////////////////////////////////// public void Connect(byte[] destinationPublicKeyHash) { SenderThread senderThread = FindSenderForDestinationPublicKeyHash(destinationPublicKeyHash); if (senderThread == null) { senderThread = ClientSenderThread.Create(this, destinationPublicKeyHash, useSsl); } } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Common/Native/IoLemmas.i.dfy ================================================ include "Io.s.dfy" module Native__IoLemmas_i { import opened Native__NativeTypes_s import opened Native__Io_s lemma lemma_KVTupleSeqToMapCantIncreaseNumKeys(kvs: seq<(K, V)>) ensures |KVTupleSeqToMap(kvs)| <= |kvs| { if |kvs| == 0 { return; } var kvs_prefix := kvs[..|kvs|-1]; lemma_KVTupleSeqToMapCantIncreaseNumKeys(kvs_prefix); } lemma lemma_SetOfSequenceElementsNoBiggerThanSeq(s: seq) ensures |(set x | x in s)| <= |s| { if |s| == 0 { return; } lemma_SetOfSequenceElementsNoBiggerThanSeq(s[1..]); assert (set x | x in s) == {s[0]} + (set x | x in s[1..]); } lemma lemma_AsKVTuplesEnsuresKeysDistinct(m: map, kvs: seq<(K, V)>) requires |kvs| == |m.Keys| requires forall k :: k in m ==> (k, m[k]) in kvs requires forall k, v :: (k, v) in kvs ==> k in m && m[k] == v requires |kvs| > 0 ensures kvs[|kvs|-1] !in kvs[..|kvs|-1] { forall kv | kv in kvs ensures kv in m.Items { var (k, v) := kv; assert k in m && m[k] == v; assert kv in m.Items; } forall kv | kv in m.Items ensures kv in kvs { var (k, v) := kv; assert k in m && m[k] == v; assert (k, m[k]) in kvs; } var kv_last := kvs[|kvs|-1]; var kvs_prefix := kvs[..|kvs|-1]; if kv_last in kvs_prefix { var s'' := set kv | kv in kvs_prefix; assert s'' == m.Items; lemma_SetOfSequenceElementsNoBiggerThanSeq(kvs_prefix); assert |s''| <= |kvs_prefix| < |kvs|; assert false; } } lemma lemma_AsKVTuplesThenKVTupleSeqToMapIsIdentity(m: map, kvs: seq<(K, V)>) requires |kvs| == |m.Keys| requires forall k :: k in m ==> (k, m[k]) in kvs requires forall k, v :: (k, v) in kvs ==> k in m && m[k] == v ensures KVTupleSeqToMap(kvs) == m { if |kvs| == 0 { return; } var kvs_prefix := kvs[..|kvs|-1]; var kv_last := kvs[|kvs|-1]; var m_prefix := m - {kv_last.0}; assert kv_last !in kvs_prefix by { lemma_AsKVTuplesEnsuresKeysDistinct(m, kvs); } lemma_AsKVTuplesThenKVTupleSeqToMapIsIdentity(m_prefix, kvs_prefix); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Common/Native/IoNative.cs ================================================ using IronfleetIoFramework; using System; using System.Net.Sockets; using System.Numerics; using System.Diagnostics; using System.Threading; using System.Collections.Concurrent; using System.Collections.Generic; using FStream = System.IO.FileStream; namespace Native____Io__s_Compile { public partial class PrintParams { internal static bool shouldPrintProfilingInfo = false; internal static bool shouldPrintProgress = false; public static bool ShouldPrintProfilingInfo() { return shouldPrintProfilingInfo; } public static bool ShouldPrintProgress() { return shouldPrintProgress; } public static void SetParameters(bool i_shouldPrintProfilingInfo, bool i_shouldPrintProgress) { shouldPrintProfilingInfo = i_shouldPrintProfilingInfo; shouldPrintProgress = i_shouldPrintProgress; } } public partial class NetClient { internal IoScheduler scheduler; Dafny.ISequence myPublicKeyHash; internal NetClient(IoScheduler i_scheduler, byte[] publicKey) { scheduler = i_scheduler; myPublicKeyHash = Dafny.Sequence.FromArray(scheduler.HashPublicKey(publicKey)); } public static int MaxPublicKeySize { get { return 0xFFFFF; } } public Dafny.ISequence MyPublicKey() { return myPublicKeyHash; } public static NetClient Create(PrivateIdentity myIdentity, string localHostNameOrAddress, int localPort, List knownIdentities, bool verbose, bool useSsl, int maxSendRetries = 3) { try { var scheduler = IoScheduler.CreateServer(myIdentity, localHostNameOrAddress, localPort, knownIdentities, verbose, useSsl, maxSendRetries); var myPublicKey = IoScheduler.GetCertificatePublicKey(scheduler.MyCert); if (myPublicKey.Length > MaxPublicKeySize) { System.Console.Error.WriteLine("ERROR: The provided public key for my identity is too big ({0} > {1} bytes)", myPublicKey.Length, MaxPublicKeySize); return null; } return new NetClient(scheduler, myPublicKey); } catch (Exception e) { System.Console.Error.WriteLine(e); return null; } } public void Receive(int timeLimit, out bool ok, out bool timedOut, out Dafny.ISequence remote, out byte[] buffer) { byte[] remoteBytes; scheduler.ReceivePacket(timeLimit, out ok, out timedOut, out remoteBytes, out buffer); if (ok && !timedOut && remoteBytes != null && remoteBytes.Length > MaxPublicKeySize) { timedOut = true; } if (ok && !timedOut) { remote = Dafny.Sequence.FromArray(remoteBytes); } else { remote = Dafny.Sequence.Empty; } } public bool Send(Dafny.ISequence remote, byte[] buffer) { return scheduler.SendPacket(remote.Elements, buffer); } public byte[] HashPublicKey(byte[] key) { return scheduler.HashPublicKey(key); } } public partial class FileStream { internal FStream fstream; internal FileStream(FStream fstream) { this.fstream = fstream; } public static void Open(char[] name, out bool ok, out FileStream f) { try { f = new FileStream(new FStream(new string(name), System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.ReadWrite)); ok = true; } catch (Exception e) { System.Console.Error.WriteLine(e); f = null; ok = false; } } public void Close(out bool ok) { try { fstream.Close(); ok = true; } catch (Exception e) { System.Console.Error.WriteLine(e); ok = false; } } public void Read(int fileOffset, byte[] buffer, int start, int end, out bool ok) { try { fstream.Seek(fileOffset, System.IO.SeekOrigin.Begin); fstream.Read(buffer, start, end - start); ok = true; } catch (Exception e) { System.Console.Error.WriteLine(e); ok = false; } } public void Write(int fileOffset, byte[] buffer, int start, int end, out bool ok) { try { fstream.Seek(fileOffset, System.IO.SeekOrigin.Begin); fstream.Write(buffer, start, end - start); ok = true; } catch (Exception e) { System.Console.Error.WriteLine(e); ok = false; } } public void Flush(out bool ok) { try { fstream.Flush(); ok = true; } catch (Exception e) { System.Console.Error.WriteLine(e); ok = false; } } } public partial class Time { static Stopwatch watch; public static void Initialize() { watch = new Stopwatch(); watch.Start(); } public static ulong GetTime() { return (ulong) (DateTime.Now.Ticks / 10000); } public static ulong GetDebugTimeTicks() { return (ulong) watch.ElapsedTicks; } public static void RecordTiming(char[] name, ulong time) { var str = new string(name); IronfleetCommon.Profiler.Record(str, (long)time); } } public partial class MutableSet { private HashSet setImpl; public MutableSet() { this.setImpl = new HashSet(); } public static Dafny.Set SetOf(MutableSet s) { return Dafny.Set.FromCollection(s.setImpl); } public static MutableSet EmptySet(Dafny.TypeDescriptor typeDescriptor) { return new MutableSet(); } public BigInteger Size() { return new BigInteger(this.setImpl.Count); } public ulong SizeModest() { return (ulong)this.setImpl.Count; } public bool Contains(T x) { return this.setImpl.Contains(x); } public void Add(T x) { this.setImpl.Add(x); } public void AddSet(MutableSet s) { this.setImpl.UnionWith(s.setImpl); } public void TransferSet(MutableSet s) { this.setImpl = s.setImpl; s.setImpl = new HashSet(); } public void Remove(T x) { this.setImpl.Remove(x); } public void RemoveAll() { this.setImpl.Clear(); } } public partial class MutableMap { private Dictionary mapImpl; // TODO: This is pretty inefficient. Should change Dafny's interface to allow us to // pass in an enumerable or an ImmutableDictionary public static Dafny.Map MapOf(MutableMap s) { List> pairs = new List>(); foreach (var pair in s.mapImpl) { pairs.Add(new Dafny.Pair(pair.Key, pair.Value)); } return Dafny.Map.FromCollection(pairs); } public static MutableMap EmptyMap() { var m = new MutableMap(); m.mapImpl = new Dictionary(); return m; } public static MutableMap FromMap(Dafny.IMap m) { var new_m = new MutableMap(); new_m.mapImpl = new Dictionary(); foreach (var kv in m.ItemEnumerable) { new_m.mapImpl.Add(kv.Car, kv.Cdr); } return new_m; } public BigInteger Size() { return new BigInteger(this.mapImpl.Count); } public ulong SizeModest() { return (ulong)this.mapImpl.Count; } public bool Contains(K key) { return this.mapImpl.ContainsKey(key); } public void TryGetValue(K key, out bool contains, out V val) { contains = this.mapImpl.TryGetValue(key, out val); } public void Set(K key, V val) { this.mapImpl[key] = val; } //public void AddMap(MutableMap s) { this.mapImpl.} public void Remove(K key) { this.mapImpl.Remove(key); } } public partial class @Arrays { public static void @CopySeqIntoArray(Dafny.ISequence src, ulong srcIndex, A[] dst, ulong dstIndex, ulong len) { System.Array.Copy(src.Elements, (long)srcIndex, dst, (long)dstIndex, (long)len); } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Common/Native/NativeTypes.i.dfy ================================================ include "NativeTypes.s.dfy" module Native__NativeTypes_i { import opened Native__NativeTypes_s function method Uint64Size() : uint64 { 8 } function method Uint32Size() : uint64 { 4 } function method Uint16Size() : uint64 { 2 } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Common/Native/NativeTypes.s.dfy ================================================ module Native__NativeTypes_s { newtype{:nativeType "sbyte"} sbyte = i:int | -0x80 <= i < 0x80 newtype{:nativeType "byte"} byte = i:int | 0 <= i < 0x100 newtype{:nativeType "short"} int16 = i:int | -0x8000 <= i < 0x8000 newtype{:nativeType "ushort"} uint16 = i:int | 0 <= i < 0x10000 newtype{:nativeType "int"} int32 = i:int | -0x80000000 <= i < 0x80000000 newtype{:nativeType "uint"} uint32 = i:int | 0 <= i < 0x100000000 newtype{:nativeType "long"} int64 = i:int | -0x8000000000000000 <= i < 0x8000000000000000 newtype{:nativeType "ulong"} uint64 = i:int | 0 <= i < 0x10000000000000000 newtype{:nativeType "sbyte"} nat8 = i:int | 0 <= i < 0x80 newtype{:nativeType "short"} nat16 = i:int | 0 <= i < 0x8000 newtype{:nativeType "int"} nat32 = i:int | 0 <= i < 0x80000000 newtype{:nativeType "long"} nat64 = i:int | 0 <= i < 0x8000000000000000 } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/Common/CmdLineParser.i.dfy ================================================ include "../../Common/Native/Io.s.dfy" include "../../../Libraries/Math/power.i.dfy" include "SeqIsUniqueDef.i.dfy" include "NetClient.i.dfy" module CmdLineParser_i { import opened Native__Io_s import opened Native__NativeTypes_s import opened Math__power_s import opened Common__SeqIsUniqueDef_i import opened Common__NetClient_i function method parse_end_point(public_key:seq) : (bool, EndPoint) ensures var tuple := parse_end_point(public_key); var ok, ep := tuple.0, tuple.1; ok ==> EndPointIsValidPublicKey(ep) { if |public_key| < 0x10_0000 then (true, EndPoint(public_key)) else (false, EndPoint(public_key)) } method test_unique(endpoints:seq) returns (unique:bool) ensures unique <==> SeqIsUnique(endpoints) { unique := true; var i := 0; while i < |endpoints| invariant 0 <= i <= |endpoints| invariant forall j,k :: 0 <= j < |endpoints| && 0 <= k < i && j != k ==> endpoints[j] != endpoints[k] { var j := 0; while j < |endpoints| invariant 0 <= j <= |endpoints| invariant forall k :: 0 <= k < j && k != i ==> endpoints[i] != endpoints[k] { if i != j && endpoints[i] == endpoints[j] { unique := false; reveal_SeqIsUnique(); return; } j := j + 1; } i := i + 1; } reveal SeqIsUnique(); } function method parse_end_points(args:seq>) : (bool, seq) ensures var (ok, endpoints) := parse_end_points(args); ok ==> (forall e :: e in endpoints ==> EndPointIsValidPublicKey(e)) { if |args| == 0 then (true, []) else var (ok1, ep) := parse_end_point(args[0]); var (ok2, rest) := parse_end_points(args[1..]); if !(ok1 && ok2) then (false, []) else (true, [ep] + rest) } method GetHostIndex(host:EndPoint, hosts:seq) returns (found:bool, index:uint64) requires EndPointIsValidPublicKey(host) requires SeqIsUnique(hosts) requires |hosts| < 0x1_0000_0000_0000_0000 requires forall h :: h in hosts ==> EndPointIsValidPublicKey(h) ensures found ==> 0 <= index as int < |hosts| && hosts[index] == host ensures !found ==> !(host in hosts) { var i:uint64 := 0; while i < (|hosts| as uint64) invariant i as int <= |hosts|; invariant forall j :: 0 <= j < i ==> hosts[j] != host; { if host == hosts[i] { found := true; index := i; calc ==> { true; { reveal_SeqIsUnique(); } forall j :: 0 <= j < |hosts| && j != i as int ==> hosts[j] != host; } return; } if i == (|hosts| as uint64) - 1 { found := false; return; } i := i + 1; } found := false; } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/Common/GenericMarshalling.i.dfy ================================================ include "../../Common/Native/NativeTypes.s.dfy" include "../../Common/Collections/Maps.i.dfy" include "../../Common/Collections/Seqs.i.dfy" include "../../Common/Logic/Option.i.dfy" include "Util.i.dfy" include "MarshallInt.i.dfy" module Common__GenericMarshalling_i { import opened Native__Io_s import opened Native__NativeTypes_s import opened Native__NativeTypes_i import opened Collections__Maps_i import opened Collections__Seqs_i import opened Logic__Option_i import opened Common__Util_i import opened Common__MarshallInt_i import opened Math__power2_i datatype G = GUint64 | GArray(elt:G) | GTuple(t:seq) | GByteArray | GTaggedUnion(cases:seq) datatype V = VUint64(u:uint64) | VArray(a:seq) | VTuple(t:seq) | VByteArray(b:seq) | VCase(c:uint64, val:V) predicate ValInGrammar(val:V, grammar:G) { match val case VUint64(_) => grammar.GUint64? case VArray(a) => grammar.GArray? && forall v :: v in a ==> ValInGrammar(v, grammar.elt) case VTuple(t) => grammar.GTuple? && |t| == |grammar.t| && (forall i :: 0 <= i < |t| ==> ValInGrammar(t[i], grammar.t[i])) case VByteArray(b) => grammar.GByteArray? case VCase(c, v) => grammar.GTaggedUnion? && c as int < |grammar.cases| && ValInGrammar(v, grammar.cases[c]) } // We only support reasonably sized grammars predicate ValidGrammar(grammar:G) { match grammar case GUint64 => true case GArray(elt) => ValidGrammar(elt) case GTuple(t) => |t| < 0x1_0000_0000_0000_0000 && (forall g :: g in t ==> ValidGrammar(g)) case GByteArray => true case GTaggedUnion(cases) => |cases| < 0x1_0000_0000_0000_0000 && (forall g :: g in cases ==> ValidGrammar(g)) } // We can't encode values that are not valid predicate ValidVal(val:V) { match val case VUint64(_) => true case VArray(a) => |a| < 0x1_0000_0000_0000_0000 && forall v :: v in a ==> ValidVal(v) case VTuple(t) => |t| < 0x1_0000_0000_0000_0000 && forall v :: v in t ==> ValidVal(v) case VByteArray(b) => |b| < 0x1_0000_0000_0000_0000 case VCase(c, v) => ValidVal(v) } function {:opaque} SeqSum(t:seq) : int ensures SeqSum(t) >= 0 { if |t| == 0 then 0 else SizeOfV(t[0]) + SeqSum(t[1..]) } function SizeOfV(val:V) : int ensures SizeOfV(val) >= 0 { match val case VUint64(_) => 8 case VArray(a) => 8 + SeqSum(a) // 8 bytes for length case VTuple(t) => SeqSum(t) case VByteArray(b) => 8 + |b| // 8 bytes for a length field case VCase(c, v) => 8 + SizeOfV(v) // 8 bytes for the case identifier } predicate Trigger(i:int) { true } function method parse_Uint64(data:seq) : (Option, seq) requires |data| < 0x1_0000_0000_0000_0000 ensures if |data| >= 8 then |parse_Uint64(data).1| == |data| - 8 else |parse_Uint64(data).1| == 0 { if |data| as uint64 >= Uint64Size() then (Some(VUint64(SeqByteToUint64(data[..Uint64Size()]))), data[Uint64Size()..]) else (None, []) } method ParseUint64(data:array, index:uint64) returns (success:bool, v:V, rest_index:uint64) requires index as int <= data.Length requires data.Length < 0x1_0000_0000_0000_0000 ensures rest_index as int <= data.Length ensures var (v', rest') := parse_Uint64(data[index..]); var v_opt := if success then Some(v) else None(); v_opt == v' && data[rest_index..] == rest' { lemma_2toX(); if data.Length as uint64 >= 8 && index <= (data.Length as uint64) - 8 { // Avoids overflow and equvalent to: if index + 8 < (data.Length as uint64) { var result := (data[index as int] as uint64) * 0x1_00_0000_0000_0000 + (data[index as int + 1] as uint64) * 0x1_00_0000_0000_00 + (data[index as int + 2] as uint64) * 0x1_00_0000_0000 + (data[index as int + 3] as uint64) * 0x1_00_0000_00 + (data[index as int + 4] as uint64) * 0x1_00_0000 + (data[index as int + 5] as uint64) * 0x1_00_00 + (data[index as int + 6] as uint64) * 0x1_00 + (data[index as int + 7] as uint64); success := true; v := VUint64(result); rest_index := index + Uint64Size(); } else { success := false; rest_index := data.Length as uint64; } } function method {:opaque} parse_Array_contents(data:seq, eltType:G, len:uint64) : (Option>, seq) requires |data| < 0x1_0000_0000_0000_0000 requires ValidGrammar(eltType) decreases eltType, 1, len ensures var (opt_seq, rest) := parse_Array_contents(data, eltType, len); |rest| <= |data| && (opt_seq.Some? ==> forall i :: 0 <= i < |opt_seq.v| ==> ValInGrammar(opt_seq.v[i], eltType)) { if len == 0 then (Some([]), data) else var (val, rest1) := parse_Val(data, eltType); var (others, rest2) := parse_Array_contents(rest1, eltType, len - 1); if !val.None? && !others.None? then (Some([val.v] + others.v), rest2) else (None, []) } datatype ContentsTraceStep = ContentsTraceStep(data:seq, val:Option) lemma lemma_ArrayContents_helper(data:seq, eltType:G, len:uint64, v:seq, trace:seq) requires |data| < 0x1_0000_0000_0000_0000 requires ValidGrammar(eltType) requires |trace| == (len as int) + 1 requires |v| == len as int requires forall j :: 0 <= j < |trace| ==> |trace[j].data| < 0x1_0000_0000_0000_0000 requires trace[0].data == data requires forall j :: 0 < j < (len as int) + 1 ==> && trace[j].val == parse_Val(trace[j-1].data, eltType).0 && trace[j].data == parse_Val(trace[j-1].data, eltType).1 requires forall j :: 0 < j < |trace| ==> trace[j].val.Some?; requires forall j :: 0 < j < |trace| ==> v[j-1] == trace[j].val.v; //requires v == ExtractValues(trace[1..]) decreases len; ensures var (v', rest') := parse_Array_contents(data, eltType, len); var v_opt := Some(v); v_opt == v' && trace[|trace|-1].data == rest' { reveal parse_Array_contents(); if len == 0 { } else { var tuple := parse_Val(data, eltType); var val, rest1 := tuple.0, tuple.1; assert trace[1].data == rest1; assert val.Some?; assert trace[1].val == val; lemma_ArrayContents_helper(rest1, eltType, len-1, v[1..], trace[1..]); var tuple'' := parse_Array_contents(rest1, eltType, len-1); var v'', rest'' := tuple''.0, tuple''.1; var v_opt'' := Some(v[1..]); assert v_opt'' == v'' && trace[1..][|trace[1..]|-1].data == rest''; var tuple' := parse_Array_contents(data, eltType, len); var v', rest' := tuple'.0, tuple'.1; calc { v'; Some([val.v] + v''.v); Some([val.v] + v[1..]); Some([v[0]] + v[1..]); { assert v == [v[0]] + v[1..]; } Some(v); } assert rest' == rest''; } } lemma lemma_ArrayContents_helper_bailout(data:seq, eltType:G, len:uint64, trace:seq) requires |data| < 0x1_0000_0000_0000_0000 requires ValidGrammar(eltType) requires 1 < |trace| <= (len as int) + 1 //requires |v| == len as int requires forall j :: 0 <= j < |trace| ==> |trace[j].data| < 0x1_0000_0000_0000_0000 requires trace[0].data == data requires forall j :: 0 < j < |trace| ==> && trace[j].val == parse_Val(trace[j-1].data, eltType).0 && trace[j].data == parse_Val(trace[j-1].data, eltType).1 requires forall j :: 0 < j < |trace| - 1 ==> trace[j].val.Some?; //requires forall j :: 0 < j < |trace| - 1 ==> v[j-1] == trace[j].val.v requires trace[|trace|-1].val.None? //requires v == ExtractValues(trace[1..]) decreases len ensures var (v', rest') := parse_Array_contents(data, eltType, len); v'.None? && rest' == [] { reveal parse_Array_contents(); var tuple := parse_Val(data, eltType); var val, rest1 := tuple.0, tuple.1; if |trace| == 2 { assert val.None?; var tuple' := parse_Array_contents(data, eltType, len); var v', rest' := tuple'.0, tuple'.1; assert v'.None?; assert rest' == []; } else { lemma_ArrayContents_helper_bailout(rest1, eltType, len-1, trace[1..]); } } method{:timeLimitMultiplier 2} ParseArrayContents(data:array, index:uint64, eltType:G, len:uint64) returns (success:bool, v:seq, rest_index:uint64) requires index as int <= data.Length requires data.Length < 0x1_0000_0000_0000_0000 requires ValidGrammar(eltType) decreases eltType, 1, len ensures rest_index as int <= data.Length ensures var (v', rest') := parse_Array_contents(data[index..], eltType, len); var v_opt := if success then Some(v) else None(); v_opt == v' && data[rest_index..] == rest' ensures success ==> ValidVal(VArray(v)) { reveal parse_Array_contents(); var vArr := new V[len]; ghost var g_v := []; success := true; var i:uint64 := 0; var next_val_index:uint64 := index; ghost var trace := [ContentsTraceStep(data[index..], None())]; while i < len invariant 0 <= i <= len invariant index <= next_val_index <= data.Length as uint64 invariant |trace| == (i as int) + 1 invariant |g_v| == i as int invariant vArr[..i] == g_v invariant trace[0].data == data[index..] invariant forall j :: 0 <= j < (i as int)+1 ==> |trace[j].data| < 0x1_0000_0000_0000_0000 invariant trace[i].data == data[next_val_index..] invariant forall j :: 0 < j <= i ==> trace[j].val.Some? invariant forall j :: 0 < j <= i ==> g_v[j-1] == trace[j].val.v invariant forall j :: 0 < j < (i as int)+1 ==> && trace[j].val == parse_Val(trace[j-1].data, eltType).0 && trace[j].data == parse_Val(trace[j-1].data, eltType).1 invariant ValidVal(VArray(vArr[..i])) { var some1, val, rest1 := ParseVal(data, next_val_index, eltType); ghost var step := ContentsTraceStep(data[rest1..], if some1 then Some(val) else None()); ghost var old_trace := trace; trace := trace + [step]; if !some1 { success := false; rest_index := data.Length as uint64; lemma_ArrayContents_helper_bailout(data[index..], eltType, len, trace); return; } g_v := g_v + [val]; vArr[i] := val; next_val_index := rest1; i := i + 1; } success := true; rest_index := next_val_index; v := vArr[..]; lemma_ArrayContents_helper(data[index..], eltType, len, v, trace); } function method parse_Array(data:seq, eltType:G) : (Option, seq) requires ValidGrammar(eltType) requires |data| < 0x1_0000_0000_0000_0000 decreases eltType ensures var (opt_val, rest) := parse_Array(data, eltType); |rest| <= |data| && (opt_val.Some? ==> ValInGrammar(opt_val.v, GArray(eltType))) { var (len, rest) := parse_Uint64(data); if !len.None? then var (contents, remainder) := parse_Array_contents(rest, eltType, len.v.u); if !contents.None? then (Some(VArray(contents.v)), remainder) else (None, []) else (None, []) } method ParseArray(data:array, index:uint64, eltType:G) returns (success:bool, v:V, rest_index:uint64) requires index as int <= data.Length requires data.Length < 0x1_0000_0000_0000_0000 requires ValidGrammar(eltType) decreases eltType ensures rest_index as int <= data.Length ensures var (v', rest') := parse_Array(data[index..], eltType); var v_opt := if success then Some(v) else None(); v_opt == v' && data[rest_index..] == rest' ensures success ==> ValidVal(v); { var some1, len, rest := ParseUint64(data, index); if some1 { var some2, contents, remainder := ParseArrayContents(data, rest, eltType, len.u); if some2 { success := true; v := VArray(contents); rest_index := remainder; } else { success := false; rest_index := data.Length as uint64; } } else { success := false; rest_index := data.Length as uint64; } } function method {:opaque} parse_Tuple_contents(data:seq, eltTypes:seq) : (Option>, seq) requires |data| < 0x1_0000_0000_0000_0000 requires |eltTypes| < 0x1_0000_0000_0000_0000 requires forall elt :: elt in eltTypes ==> ValidGrammar(elt) decreases eltTypes, 0 ensures var (opt_val, rest) := parse_Tuple_contents(data, eltTypes); |rest| <= |data| && (opt_val.Some? ==> (|opt_val.v| == |eltTypes| && forall i :: 0 <= i < |opt_val.v| ==> ValInGrammar(opt_val.v[i], eltTypes[i]))) { if eltTypes == [] then (Some([]), data) else var (val, rest1) := parse_Val(data, eltTypes[0]); assert |rest1| <= |data|; var (contents, rest2) := parse_Tuple_contents(rest1, eltTypes[1..]); if !val.None? && !contents.None? then (Some([val.v] + contents.v), rest2) else (None, []) } lemma lemma_TupleContents_helper(data:seq, eltTypes:seq, v:seq, trace:seq) requires |data| < 0x1_0000_0000_0000_0000 requires |eltTypes| < 0x1_0000_0000_0000_0000 requires forall elt :: elt in eltTypes ==> ValidGrammar(elt) requires |trace| == |eltTypes| + 1 requires |v| == |eltTypes| as int requires forall j :: 0 <= j < |trace| ==> |trace[j].data| < 0x1_0000_0000_0000_0000 requires trace[0].data == data requires forall j :: 0 < j < (|eltTypes| as int)+1 ==> && trace[j].val == parse_Val(trace[j-1].data, eltTypes[j-1]).0 && trace[j].data == parse_Val(trace[j-1].data, eltTypes[j-1]).1 requires forall j :: 0 < j < |trace| ==> trace[j].val.Some? requires forall j :: 0 < j < |trace| ==> v[j-1] == trace[j].val.v //requires v == ExtractValues(trace[1..]) decreases |eltTypes| ensures var (v', rest') := parse_Tuple_contents(data, eltTypes); var v_opt := Some(v); v_opt == v' && trace[|trace|-1].data == rest' { reveal parse_Tuple_contents(); if |eltTypes| == 0 { } else { var tuple := parse_Val(data, eltTypes[0]); var val, rest1 := tuple.0, tuple.1; assert trace[1].data == rest1; assert val.Some?; assert trace[1].val == val; lemma_TupleContents_helper(rest1, eltTypes[1..], v[1..], trace[1..]); var tuple'' := parse_Tuple_contents(rest1, eltTypes[1..]); var v'', rest'' := tuple''.0, tuple''.1; var v_opt'' := Some(v[1..]); assert v_opt'' == v'' && trace[1..][|trace[1..]|-1].data == rest''; var tuple' := parse_Tuple_contents(data, eltTypes); var v', rest' := tuple'.0, tuple'.1; calc { v'; Some([val.v] + v''.v); Some([val.v] + v[1..]); Some([v[0]] + v[1..]); { assert v == [v[0]] + v[1..]; } Some(v); } assert rest' == rest''; } } lemma lemma_TupleContents_helper_bailout(data:seq, eltTypes:seq, trace:seq) requires |data| < 0x1_0000_0000_0000_0000 requires |eltTypes| < 0x1_0000_0000_0000_0000 requires forall elt :: elt in eltTypes ==> ValidGrammar(elt) requires 1 < |trace| <= (|eltTypes| as int) + 1 requires forall j :: 0 <= j < |trace| ==> |trace[j].data| < 0x1_0000_0000_0000_0000 requires trace[0].data == data requires forall j :: 0 < j < |trace| ==> && trace[j].val == parse_Val(trace[j-1].data, eltTypes[j-1]).0 && trace[j].data == parse_Val(trace[j-1].data, eltTypes[j-1]).1 requires forall j :: 0 < j < |trace| - 1 ==> trace[j].val.Some? //requires forall j :: 0 < j < |trace| - 1 ==> v[j-1] == trace[j].val.v requires trace[|trace|-1].val.None? //requires v == ExtractValues(trace[1..]) decreases |eltTypes| ensures var (v', rest') := parse_Tuple_contents(data, eltTypes); v'.None? && rest' == [] { reveal parse_Tuple_contents(); var tuple := parse_Val(data, eltTypes[0]); var val, rest1 := tuple.0, tuple.1; if |trace| == 2 { assert val.None?; var tuple' := parse_Tuple_contents(data, eltTypes); var v', rest' := tuple'.0, tuple'.1; assert v'.None?; assert rest' == []; } else { lemma_TupleContents_helper_bailout(rest1, eltTypes[1..], trace[1..]); } } method{:timeLimitMultiplier 2} ParseTupleContents(data:array, index:uint64, eltTypes:seq) returns (success:bool, v:seq, rest_index:uint64) requires index as int <= data.Length requires data.Length < 0x1_0000_0000_0000_0000 requires |eltTypes| < 0x1_0000_0000_0000_0000 requires forall elt :: elt in eltTypes ==> ValidGrammar(elt) decreases eltTypes, 0 ensures rest_index as int <= data.Length ensures var (v', rest') := parse_Tuple_contents(data[index..], eltTypes); var v_opt := if success then Some(v) else None(); v_opt == v' && data[rest_index..] == rest' ensures success ==> ValidVal(VTuple(v)) { reveal parse_Tuple_contents(); var vArr := new V[|eltTypes|]; ghost var g_v := []; success := true; var i:int := 0; var next_val_index:uint64 := index; ghost var trace := [ContentsTraceStep(data[index..], None())]; while i < |eltTypes| invariant 0 <= i <= |eltTypes| invariant index <= next_val_index <= data.Length as uint64 invariant |trace| == i + 1 invariant |g_v| == i invariant vArr[..i] == g_v invariant trace[0].data == data[index..] invariant forall j :: 0 <= j < i+1 ==> |trace[j].data| < 0x1_0000_0000_0000_0000 invariant trace[i].data == data[next_val_index..] invariant forall j :: 0 < j <= i ==> trace[j].val.Some? invariant forall j :: 0 < j <= i ==> g_v[j-1] == trace[j].val.v invariant forall j :: 0 < j < i+1 ==> && trace[j].val == parse_Val(trace[j-1].data, eltTypes[j-1]).0 && trace[j].data == parse_Val(trace[j-1].data, eltTypes[j-1]).1 invariant ValidVal(VTuple(vArr[..i])) { var some1, val, rest1 := ParseVal(data, next_val_index, eltTypes[i]); ghost var step := ContentsTraceStep(data[rest1..], if some1 then Some(val) else None()); ghost var old_trace := trace; trace := trace + [step]; if !some1 { success := false; rest_index := data.Length as uint64; lemma_TupleContents_helper_bailout(data[index..], eltTypes, trace); return; } g_v := g_v + [val]; vArr[i] := val; next_val_index := rest1; i := i + 1; } success := true; rest_index := next_val_index; v := vArr[..]; lemma_TupleContents_helper(data[index..], eltTypes, v, trace); } function method parse_Tuple(data:seq, eltTypes:seq) : (Option, seq) requires |data| < 0x1_0000_0000_0000_0000 requires |eltTypes| < 0x1_0000_0000_0000_0000 requires forall elt :: elt in eltTypes ==> ValidGrammar(elt) decreases eltTypes, 1 ensures var (opt_val, rest) := parse_Tuple(data, eltTypes); |rest| <= |data| && (opt_val.Some? ==> ValInGrammar(opt_val.v, GTuple(eltTypes))) { var (contents, rest) := parse_Tuple_contents(data, eltTypes); if !contents.None? then (Some(VTuple(contents.v)), rest) else (None, []) } method ParseTuple(data:array, index:uint64, eltTypes:seq) returns (success:bool, v:V, rest_index:uint64) requires index as int <= data.Length requires data.Length < 0x1_0000_0000_0000_0000 requires |eltTypes| < 0x1_0000_0000_0000_0000 requires forall elt :: elt in eltTypes ==> ValidGrammar(elt) decreases eltTypes, 1 ensures rest_index as int <= data.Length ensures var (v', rest') := parse_Tuple(data[index..], eltTypes); var v_opt := if success then Some(v) else None(); v_opt == v' && data[rest_index..] == rest' ensures success ==> ValidVal(v); { var some, contents, rest := ParseTupleContents(data, index, eltTypes); if some { success := true; v := VTuple(contents); rest_index := rest; } else { success := false; rest_index := data.Length as uint64; } } function method parse_ByteArray(data:seq) : (Option, seq) requires |data| < 0x1_0000_0000_0000_0000 { var (len, rest) := parse_Uint64(data); if !len.None? && len.v.u <= |rest| as uint64 then (Some(VByteArray(rest[0..len.v.u])), rest[len.v.u..]) else (None, []) } method ParseByteArray(data:array, index:uint64) returns (success:bool, v:V, rest_index:uint64) requires index as int <= data.Length requires data.Length < 0x1_0000_0000_0000_0000 ensures rest_index as int <= data.Length ensures var (v', rest') := parse_ByteArray(data[index..]); var v_opt := if success then Some(v) else None(); v_opt == v' && data[rest_index..] == rest' { var some, len, rest := ParseUint64(data, index); if some && len.u <= data.Length as uint64 - rest { var rest_seq := data[rest..]; assert len.u <= |rest_seq| as uint64; calc { rest_seq[0..len.u]; data[rest..rest + len.u]; } success := true; v := VByteArray(data[rest..rest + len.u]); rest_index := rest + len.u; } else { success := false; rest_index := data.Length as uint64; } } function method parse_Case(data:seq, cases:seq) : (Option, seq) requires |data| < 0x1_0000_0000_0000_0000 requires |cases| < 0x1_0000_0000_0000_0000 requires forall elt :: elt in cases ==> ValidGrammar(elt) decreases cases ensures var (opt_val, rest) := parse_Case(data, cases); |rest| <= |data| && (opt_val.Some? ==> ValInGrammar(opt_val.v, GTaggedUnion(cases))) { var (caseID, rest1) := parse_Uint64(data); if !caseID.None? && caseID.v.u < |cases| as uint64 then var (val, rest2) := parse_Val(rest1, cases[caseID.v.u]); if !val.None? then (Some(VCase(caseID.v.u, val.v)), rest2) else (None, []) else (None, []) } method ParseCase(data:array, index:uint64, cases:seq) returns (success:bool, v:V, rest_index:uint64) requires index as int <= data.Length requires data.Length < 0x1_0000_0000_0000_0000 requires |cases| < 0x1_0000_0000_0000_0000 requires forall elt :: elt in cases ==> ValidGrammar(elt) decreases cases ensures rest_index as int <= data.Length ensures var (v', rest') := parse_Case(data[index..], cases); var v_opt := if success then Some(v) else None(); v_opt == v' && data[rest_index..] == rest' ensures success ==> ValidVal(v) { var some1, caseID, rest1 := ParseUint64(data, index); if some1 && caseID.u < |cases| as uint64 { var some2, val, rest2 := ParseVal(data, rest1, cases[caseID.u]); if some2 { success := true; v := VCase(caseID.u, val); rest_index := rest2; } else { success := false; rest_index := data.Length as uint64; } } else { success := false; rest_index := data.Length as uint64; } } function method {:opaque} parse_Val(data:seq, grammar:G) : (Option, seq) requires |data| < 0x1_0000_0000_0000_0000 requires ValidGrammar(grammar) decreases grammar, 0 ensures var (val, rest) := parse_Val(data, grammar); |rest| <= |data| && (!val.None? ==> ValInGrammar(val.v, grammar)) { match grammar case GUint64 => parse_Uint64(data) case GArray(elt) => parse_Array(data, elt) case GTuple(t) => parse_Tuple(data, t) case GByteArray => parse_ByteArray(data) case GTaggedUnion(cases) => parse_Case(data, cases) } method ParseVal(data:array, index:uint64, grammar:G) returns (success:bool, v:V, rest_index:uint64) requires index as int <= data.Length requires data.Length < 0x1_0000_0000_0000_0000 requires ValidGrammar(grammar) decreases grammar, 0 ensures rest_index as int <= data.Length ensures var (v', rest') := parse_Val(data[index..], grammar); var v_opt := if success then Some(v) else None(); v_opt == v' && data[rest_index..] == rest' ensures success ==> ValidVal(v); { reveal parse_Val(); match grammar { case GUint64 => success, v, rest_index := ParseUint64(data, index); case GArray(elt) => success, v, rest_index := ParseArray(data, index, elt); case GTuple(t) => success, v, rest_index := ParseTuple(data, index, t); case GByteArray => success, v, rest_index := ParseByteArray(data, index); case GTaggedUnion(cases) => success, v, rest_index := ParseCase(data, index, cases); } } predicate Demarshallable(data:seq, grammar:G) { && |data| < 0x1_0000_0000_0000_0000 && ValidGrammar(grammar) && !parse_Val(data, grammar).0.None? && ValidVal(parse_Val(data, grammar).0.v) && parse_Val(data, grammar).1 == [] } function DemarshallFunc(data:seq, grammar:G) : V requires Demarshallable(data, grammar) decreases grammar, 0 ensures var (val, rest) := parse_Val(data, grammar); !val.None? && ValInGrammar(val.v, grammar) { parse_Val(data, grammar).0.v } method Demarshall(data:array, grammar:G) returns (success:bool, v:V) requires data.Length < 0x1_0000_0000_0000_0000 requires ValidGrammar(grammar) ensures success == Demarshallable(data[..], grammar) ensures success ==> v == DemarshallFunc(data[..], grammar) { var rest:uint64; success, v, rest := ParseVal(data, 0, grammar); if success && rest == data.Length as uint64 { assert v == parse_Val(data[..], grammar).0.v; assert Demarshallable(data[..], grammar); assert v == DemarshallFunc(data[..], grammar); } else { success := false; assert !Demarshallable(data[..], grammar); } } lemma lemma_parse_Val_view_ByteArray(data:seq, v:V, grammar:G, index:int) requires |data| < 0x1_0000_0000_0000_0000 requires ValInGrammar(v, grammar) requires ValidGrammar(grammar) requires grammar.GByteArray? requires 0 <= index <= |data| requires 0 <= index + SizeOfV(v) <= |data| ensures forall bound :: Trigger(bound) ==> (index+SizeOfV(v) <= bound <= |data| ==> ((parse_ByteArray(data[index..bound]).0 == Some(v)) <==> (parse_ByteArray(data[index..index+SizeOfV(v)]).0 == Some(v)))) ensures forall bound :: index+SizeOfV(v) <= bound <= |data| ==> parse_ByteArray(data[index..bound]).0 == Some(v) ==> parse_ByteArray(data[index..bound]).1 == data[index+SizeOfV(v)..bound] { forall bound {:trigger Trigger(bound)} | Trigger(bound) ensures index+SizeOfV(v) <= bound <= |data| ==> ((parse_ByteArray(data[index..bound]).0 == Some(v)) <==> (parse_ByteArray(data[index..index+SizeOfV(v)]).0 == Some(v))) { if index+SizeOfV(v) <= bound <= |data| { var narrow_tuple := parse_ByteArray(data[index..index+SizeOfV(v)]); var bound_tuple := parse_ByteArray(data[index..bound]); var narrow_len_tuple := parse_Uint64(data[index..index+SizeOfV(v)]); var bound_len_tuple := parse_Uint64(data[index..bound]); assert narrow_len_tuple.0 == bound_len_tuple.0; if bound_tuple.0 == Some(v) { assert bound_len_tuple.1[0..bound_len_tuple.0.v.u] == narrow_len_tuple.1[0..bound_len_tuple.0.v.u]; // OBSERVE } if narrow_tuple.0 == Some(v) { assert bound_len_tuple.1[0..bound_len_tuple.0.v.u] == narrow_len_tuple.1[0..bound_len_tuple.0.v.u]; // OBSERVE } assert ((parse_ByteArray(data[index..bound]).0 == Some(v)) <==> (parse_ByteArray(data[index..index+SizeOfV(v)]).0 == Some(v))); } assert index+SizeOfV(v) <= bound <= |data| ==> ((parse_ByteArray(data[index..bound]).0 == Some(v)) <==> (parse_ByteArray(data[index..index+SizeOfV(v)]).0 == Some(v))); } assert forall bound :: Trigger(bound) ==> (index+SizeOfV(v) <= bound <= |data| ==> ((parse_ByteArray(data[index..bound]).0 == Some(v)) <==> (parse_ByteArray(data[index..index+SizeOfV(v)]).0 == Some(v)))); assert forall bound :: index+SizeOfV(v) <= bound <= |data| ==> parse_ByteArray(data[index..bound]).0 == Some(v) ==> parse_ByteArray(data[index..bound]).1 == data[index+SizeOfV(v)..bound]; } lemma lemma_SeqSum_prefix(s:seq, v:V) ensures SeqSum(s + [v]) == SeqSum(s) + SizeOfV(v) { reveal SeqSum(); if |s| == 0 { } else { calc { SeqSum(s + [v]); { assert (s + [v])[0] == s[0]; assert (s + [v])[1..] == s[1..]+[v]; } SizeOfV(s[0]) + SeqSum(s[1..] + [v]); { lemma_SeqSum_prefix(s[1..], v); } SizeOfV(s[0]) + SeqSum(s[1..]) + SizeOfV(v); SeqSum(s) + SizeOfV(v); } } } lemma lemma_SeqSum_bound(s:seq, bound:int) requires SeqSum(s) < bound ensures forall v :: v in s ==> SizeOfV(v) < bound { reveal SeqSum(); if |s| == 0 { } else { assert SizeOfV(s[0]) + SeqSum(s[1..]) < bound; assert SizeOfV(s[0]) < bound; lemma_SeqSum_bound(s[1..], bound); } } lemma lemma_SeqSum_bound_prefix(s:seq, prefix:seq, index:int) requires 0 <= index <= |s| requires prefix == s[..index] ensures SeqSum(prefix) <= SeqSum(s) { reveal SeqSum(); if |prefix| == 0 { } else { lemma_SeqSum_bound_prefix(s[1..], prefix[1..], index - 1); } } lemma lemma_parse_Array_contents_len(data:seq, eltType:G, len:uint64) requires |data| < 0x1_0000_0000_0000_0000 requires ValidGrammar(eltType) requires len >= 0 requires !parse_Array_contents(data, eltType, len).0.None? decreases len ensures len as int == |parse_Array_contents(data, eltType, len).0.v| { reveal parse_Array_contents(); if len == 0 { } else { var tuple1 := parse_Val(data, eltType); var val := tuple1.0; var rest1 := tuple1.1; var tuple2 := parse_Array_contents(rest1, eltType, len - 1); var others := tuple2.0; var rest2 := tuple2.1; assert !val.None? && !others.None?; lemma_parse_Array_contents_len(rest1, eltType, len - 1); } } lemma lemma_parse_Val_view_Array_contents(data:seq, vs:seq, grammar:G, index:int, bound:int, len:uint64) requires |data| < 0x1_0000_0000_0000_0000 requires forall v :: v in vs ==> ValInGrammar(v, grammar) requires ValidGrammar(grammar) requires len as int == |vs| requires 0 <= index <= |data| requires 0 <= index + SeqSum(vs) <= |data| requires index+SeqSum(vs) <= bound <= |data| decreases grammar, 1, len //decreases |vs| ensures (parse_Array_contents(data[index..bound], grammar, len).0 == Some(vs)) <==> (parse_Array_contents(data[index..index+SeqSum(vs)], grammar, len).0 == Some(vs)) ensures parse_Array_contents(data[index..bound], grammar, len).0 == Some(vs) ==> parse_Array_contents(data[index..bound], grammar, len).1 == data[index+SeqSum(vs)..bound] { reveal parse_Array_contents(); if len == 0 { reveal SeqSum(); } else { var narrow_tuple := parse_Array_contents(data[index..index+SeqSum(vs)], grammar, len); var bound_tuple := parse_Array_contents(data[index..bound], grammar, len); var narrow_val_tuple := parse_Val(data[index..index+SeqSum(vs)], grammar); var bound_val_tuple := parse_Val(data[index..bound], grammar); var narrow_contents_tuple := parse_Array_contents(narrow_val_tuple.1, grammar, len - 1); var bound_contents_tuple := parse_Array_contents(bound_val_tuple.1, grammar, len - 1); if narrow_tuple.0 == Some(vs) { assert !narrow_val_tuple.0.None? && !narrow_contents_tuple.0.None?; calc { index + SeqSum(vs) <= |data|; SeqSum(vs) <= |data| - index; SeqSum(vs) < |data| - index + 1; } lemma_SeqSum_bound(vs, |data| - index + 1); lemma_parse_Val_view(data, vs[0], grammar, index); lemma_SeqSum_bound(vs, SeqSum(vs) + 1); assert index+SizeOfV(vs[0]) <= bound <= |data|; assert (parse_Val(data[index..index+SeqSum(vs)], grammar).0 == Some(vs[0])) <==> (parse_Val(data[index..index+SizeOfV(vs[0])], grammar).0 == Some(vs[0])); lemma_SeqSum_bound(vs, bound - index + 1); assert index+SizeOfV(vs[0]) <= bound <= |data|; // OBSERVE (trigger on forall?) assert (parse_Val(data[index..bound], grammar).0 == Some(vs[0])) <==> (parse_Val(data[index..index+SizeOfV(vs[0])], grammar).0 == Some(vs[0])); assert narrow_val_tuple.0.v == vs[0] == bound_val_tuple.0.v; var new_index := index + SizeOfV(narrow_val_tuple.0.v); calc { SizeOfV(narrow_val_tuple.0.v) + SeqSum(vs[1..]); { reveal SeqSum(); } SeqSum(vs); } assert new_index+SeqSum(vs[1..]) <= bound; lemma_parse_Val_view_Array_contents(data, vs[1..], grammar, new_index, bound, len - 1); assert (parse_Array_contents(data[new_index..bound], grammar, len - 1).0 == Some(vs[1..])) <==> (parse_Array_contents(data[new_index..new_index+SeqSum(vs[1..])], grammar, len - 1).0 == Some(vs[1..])); assert data[new_index..new_index+SeqSum(vs[1..])] == narrow_val_tuple.1; assert data[new_index..bound] == bound_val_tuple.1; assert bound_tuple.0 == Some([vs[0]] + vs[1..]) == Some(vs); } else if bound_tuple.0 == Some(vs) { assert !bound_val_tuple.0.None? && !bound_contents_tuple.0.None?; lemma_SeqSum_bound(vs, |data| - index + 1); lemma_parse_Val_view(data, vs[0], grammar, index); // This is exactly the ensures of the lemma above assert forall bound' :: index+SizeOfV(vs[0]) <= bound' <= |data| ==> ((parse_Val(data[index..bound'], grammar).0 == Some(vs[0])) <==> (parse_Val(data[index..index+SizeOfV(vs[0])], grammar).0 == Some(vs[0]))); lemma_SeqSum_bound(vs, bound - index + 1); lemma_SeqSum_bound(vs, SeqSum(vs) + 1); assert index+SizeOfV(vs[0]) <= index+SeqSum(vs) <= |data|; assert (parse_Val(data[index..index+SeqSum(vs)], grammar).0 == Some(vs[0])) <==> (parse_Val(data[index..index+SizeOfV(vs[0])], grammar).0 == Some(vs[0])); assert (parse_Val(data[index..bound], grammar).0 == Some(vs[0])) <==> (parse_Val(data[index..index+SizeOfV(vs[0])], grammar).0 == Some(vs[0])); assert narrow_val_tuple.0.v == vs[0] == bound_val_tuple.0.v; var new_index := index + SizeOfV(narrow_val_tuple.0.v); calc { SizeOfV(narrow_val_tuple.0.v) + SeqSum(vs[1..]); { reveal SeqSum(); } SeqSum(vs); } assert new_index+SeqSum(vs[1..]) <= bound; lemma_parse_Val_view_Array_contents(data, vs[1..], grammar, new_index, bound, len - 1); assert (parse_Array_contents(data[new_index..bound], grammar, len - 1).0 == Some(vs[1..])) <==> (parse_Array_contents(data[new_index..new_index+SeqSum(vs[1..])], grammar, len - 1).0 == Some(vs[1..])); assert data[new_index..new_index+SeqSum(vs[1..])] == narrow_val_tuple.1; assert data[new_index..bound] == bound_val_tuple.1; assert narrow_tuple.0 == Some([vs[0]] + vs[1..]) == Some(vs); } else { // Doesn't matter for our ensures clause } } } lemma lemma_parse_Val_view_Array(data:seq, v:V, grammar:G, index:int, bound:int) requires |data| < 0x1_0000_0000_0000_0000 requires ValInGrammar(v, grammar) requires ValidGrammar(grammar) requires grammar.GArray? requires 0 <= index <= |data| requires 0 <= index + SizeOfV(v) <= |data| requires index+SizeOfV(v) <= bound <= |data| decreases grammar, -1 ensures (parse_Array(data[index..bound], grammar.elt).0 == Some(v)) <==> (parse_Array(data[index..index+SizeOfV(v)], grammar.elt).0 == Some(v)) ensures parse_Array(data[index..bound], grammar.elt).0 == Some(v) ==> parse_Array(data[index..bound], grammar.elt).1 == data[index+SizeOfV(v)..bound] { var narrow_tuple := parse_Array(data[index..index+SizeOfV(v)], grammar.elt); var bound_tuple := parse_Array(data[index..bound], grammar.elt); var narrow_len_tuple := parse_Uint64(data[index..index+SizeOfV(v)]); var bound_len_tuple := parse_Uint64(data[index..bound]); var narrow_contents_tuple := parse_Array_contents(narrow_len_tuple.1, grammar.elt, narrow_len_tuple.0.v.u); var bound_contents_tuple := parse_Array_contents(bound_len_tuple.1, grammar.elt, bound_len_tuple.0.v.u); assert narrow_len_tuple.0 == bound_len_tuple.0; if bound_tuple.0 == Some(v) { assert parse_Array_contents(bound_len_tuple.1, grammar.elt, bound_len_tuple.0.v.u).0 == Some(v.a); // OBSERVE lemma_parse_Array_contents_len(bound_len_tuple.1, grammar.elt, narrow_len_tuple.0.v.u); lemma_parse_Val_view_Array_contents(data, v.a, grammar.elt, index+8, bound, narrow_len_tuple.0.v.u); } if narrow_tuple.0 == Some(v) { assert parse_Array_contents(narrow_len_tuple.1, grammar.elt, narrow_len_tuple.0.v.u).0 == Some(v.a); // OBSERVE lemma_parse_Array_contents_len(narrow_len_tuple.1, grammar.elt, narrow_len_tuple.0.v.u); lemma_parse_Val_view_Array_contents(data, v.a, grammar.elt, index+8, bound, narrow_len_tuple.0.v.u); } } lemma lemma_parse_Val_view_Tuple_contents(data:seq, vs:seq, grammar:seq, index:int, bound:int) requires |data| < 0x1_0000_0000_0000_0000 requires |vs| == |grammar| requires forall i :: 0 <= i < |vs| ==> ValInGrammar(vs[i], grammar[i]) requires |grammar| < 0x1_0000_0000_0000_0000 requires forall g :: g in grammar ==> ValidGrammar(g) requires 0 <= index <= |data| requires 0 <= index + SeqSum(vs) <= |data| requires index+SeqSum(vs) <= bound <= |data| decreases grammar, -1, vs ensures (parse_Tuple_contents(data[index..bound], grammar).0 == Some(vs)) <==> (parse_Tuple_contents(data[index..index+SeqSum(vs)], grammar).0 == Some(vs)) ensures parse_Tuple_contents(data[index..bound], grammar).0 == Some(vs) ==> parse_Tuple_contents(data[index..bound], grammar).1 == data[index+SeqSum(vs)..bound] { reveal parse_Tuple_contents(); if grammar == [] { reveal SeqSum(); } else { var narrow_tuple := parse_Tuple_contents(data[index..index+SeqSum(vs)], grammar); var bound_tuple := parse_Tuple_contents(data[index..bound], grammar); var narrow_val_tuple := parse_Val(data[index..index+SeqSum(vs)], grammar[0]); var bound_val_tuple := parse_Val(data[index..bound], grammar[0]); var narrow_contents_tuple := parse_Tuple_contents(narrow_val_tuple.1, grammar[1..]); var bound_contents_tuple := parse_Tuple_contents(bound_val_tuple.1, grammar[1..]); if narrow_tuple.0 == Some(vs) { assert !narrow_val_tuple.0.None? && !narrow_contents_tuple.0.None?; calc { index + SeqSum(vs) <= |data|; SeqSum(vs) <= |data| - index; SeqSum(vs) < |data| - index + 1; } lemma_SeqSum_bound(vs, |data| - index + 1); lemma_parse_Val_view(data, vs[0], grammar[0], index); lemma_SeqSum_bound(vs, SeqSum(vs) + 1); assert index+SizeOfV(vs[0]) <= bound <= |data|; assert (parse_Val(data[index..index+SeqSum(vs)], grammar[0]).0 == Some(vs[0])) <==> (parse_Val(data[index..index+SizeOfV(vs[0])], grammar[0]).0 == Some(vs[0])); lemma_SeqSum_bound(vs, bound - index + 1); assert index+SizeOfV(vs[0]) <= bound <= |data|; // OBSERVE (trigger on forall?) assert (parse_Val(data[index..bound], grammar[0]).0 == Some(vs[0])) <==> (parse_Val(data[index..index+SizeOfV(vs[0])], grammar[0]).0 == Some(vs[0])); assert narrow_val_tuple.0.v == vs[0] == bound_val_tuple.0.v; var new_index := index + SizeOfV(narrow_val_tuple.0.v); calc { SizeOfV(narrow_val_tuple.0.v) + SeqSum(vs[1..]); { reveal SeqSum(); } SeqSum(vs); } assert new_index+SeqSum(vs[1..]) <= bound; lemma_parse_Val_view_Tuple_contents(data, vs[1..], grammar[1..], new_index, bound); assert (parse_Tuple_contents(data[new_index..bound], grammar[1..]).0 == Some(vs[1..])) <==> (parse_Tuple_contents(data[new_index..new_index+SeqSum(vs[1..])], grammar[1..]).0 == Some(vs[1..])); assert data[new_index..new_index+SeqSum(vs[1..])] == narrow_val_tuple.1; assert data[new_index..bound] == bound_val_tuple.1; assert bound_tuple.0 == Some([vs[0]] + vs[1..]) == Some(vs); } else if bound_tuple.0 == Some(vs) { assert !bound_val_tuple.0.None? && !bound_contents_tuple.0.None?; lemma_SeqSum_bound(vs, |data| - index + 1); lemma_parse_Val_view(data, vs[0], grammar[0], index); // This is exactly the ensures of the lemma above assert forall bound' :: index+SizeOfV(vs[0]) <= bound' <= |data| ==> ((parse_Val(data[index..bound'], grammar[0]).0 == Some(vs[0])) <==> (parse_Val(data[index..index+SizeOfV(vs[0])], grammar[0]).0 == Some(vs[0]))); lemma_SeqSum_bound(vs, bound - index + 1); lemma_SeqSum_bound(vs, SeqSum(vs) + 1); assert index+SizeOfV(vs[0]) <= index+SeqSum(vs) <= |data|; assert (parse_Val(data[index..index+SeqSum(vs)], grammar[0]).0 == Some(vs[0])) <==> (parse_Val(data[index..index+SizeOfV(vs[0])], grammar[0]).0 == Some(vs[0])); assert (parse_Val(data[index..bound], grammar[0]).0 == Some(vs[0])) <==> (parse_Val(data[index..index+SizeOfV(vs[0])], grammar[0]).0 == Some(vs[0])); assert narrow_val_tuple.0.v == vs[0] == bound_val_tuple.0.v; var new_index := index + SizeOfV(narrow_val_tuple.0.v); calc { SizeOfV(narrow_val_tuple.0.v) + SeqSum(vs[1..]); { reveal SeqSum(); } SeqSum(vs); } assert new_index+SeqSum(vs[1..]) <= bound; lemma_parse_Val_view_Tuple_contents(data, vs[1..], grammar[1..], new_index, bound); assert (parse_Tuple_contents(data[new_index..bound], grammar[1..]).0 == Some(vs[1..])) <==> (parse_Tuple_contents(data[new_index..new_index+SeqSum(vs[1..])], grammar[1..]).0 == Some(vs[1..])); assert data[new_index..new_index+SeqSum(vs[1..])] == narrow_val_tuple.1; assert data[new_index..bound] == bound_val_tuple.1; assert narrow_tuple.0 == Some([vs[0]] + vs[1..]) == Some(vs); } else { // Doesn't matter for our ensures clause } } } lemma lemma_parse_Val_view_Tuple(data:seq, v:V, grammar:seq, index:int, bound:int) requires |data| < 0x1_0000_0000_0000_0000 requires v.VTuple? requires |v.t| == |grammar| requires forall i :: 0 <= i < |v.t| ==> ValInGrammar(v.t[i], grammar[i]) requires |grammar| < 0x1_0000_0000_0000_0000 requires forall g :: g in grammar ==> ValidGrammar(g) requires 0 <= index <= |data| requires 0 <= index + SizeOfV(v) <= |data| requires index+SizeOfV(v) <= bound <= |data| decreases grammar, -1, v ensures (parse_Tuple(data[index..bound], grammar).0 == Some(v)) <==> (parse_Tuple(data[index..index+SizeOfV(v)], grammar).0 == Some(v)) ensures parse_Tuple(data[index..bound], grammar).0 == Some(v) ==> parse_Tuple(data[index..bound], grammar).1 == data[index+SizeOfV(v)..bound] { var bound_tuple := parse_Tuple(data[index..bound], grammar); var bound_contents := bound_tuple.0; var bound_rest := bound_tuple.1; var narrow_tuple := parse_Tuple(data[index..index+SizeOfV(v)], grammar); var narrow_contents := narrow_tuple.0; var narrow_rest := narrow_tuple.1; if parse_Tuple(data[index..bound], grammar).0 == Some(v) { assert !bound_contents.None?; lemma_parse_Val_view_Tuple_contents(data, v.t, grammar, index, bound); assert (parse_Tuple_contents(data[index..bound], grammar).0 == Some(v.t)) <==> (parse_Tuple_contents(data[index..index+SeqSum(v.t)], grammar).0 == Some(v.t)); // OBSERVE } else if parse_Tuple(data[index..index+SizeOfV(v)], grammar).0 == Some(v) { assert !narrow_contents.None?; lemma_parse_Val_view_Tuple_contents(data, v.t, grammar, index, bound); assert (parse_Tuple_contents(data[index..bound], grammar).0 == Some(v.t)) <==> (parse_Tuple_contents(data[index..index+SeqSum(v.t)], grammar).0 == Some(v.t)); // OBSERVE } else { // Don't care } } lemma lemma_parse_Val_view_Union(data:seq, v:V, grammar:G, index:int, bound:int) requires |data| < 0x1_0000_0000_0000_0000 requires ValInGrammar(v, grammar) requires ValidGrammar(grammar) requires grammar.GTaggedUnion? requires 0 <= index <= |data| requires 0 <= index + SizeOfV(v) <= |data| requires index+SizeOfV(v) <= bound <= |data| decreases grammar, -1 ensures (parse_Case(data[index..bound], grammar.cases).0 == Some(v)) <==> (parse_Case(data[index..index+SizeOfV(v)], grammar.cases).0 == Some(v)) ensures parse_Case(data[index..bound], grammar.cases).0 == Some(v) ==> parse_Case(data[index..bound], grammar.cases).1 == data[index+SizeOfV(v)..bound] { var narrow_tuple := parse_Case(data[index..index+SizeOfV(v)], grammar.cases); var bound_tuple := parse_Case(data[index..bound], grammar.cases); var narrow_caseID_tuple := parse_Uint64(data[index..index+SizeOfV(v)]); var bound_caseID_tuple := parse_Uint64(data[index..bound]); // assert narrow_caseID_tuple.0.v == bound_caseID_tuple.0.v; if parse_Case(data[index..bound], grammar.cases).0 == Some(v) { var narrow_val_tuple := parse_Val(narrow_caseID_tuple.1, grammar.cases[narrow_caseID_tuple.0.v.u]); var bound_val_tuple := parse_Val(bound_caseID_tuple.1, grammar.cases[bound_caseID_tuple.0.v.u]); // assert ValInGrammar(v.val, grammar.cases[narrow_caseID_tuple.0.v.u]); if (ValInGrammar(v.val, grammar.cases[narrow_caseID_tuple.0.v.u])){ lemma_parse_Val_view(data, v.val, grammar.cases[narrow_caseID_tuple.0.v.u], index + 8); assert index+SizeOfV(v.val) <= bound <= |data|; assert (parse_Val(data[index+8..bound], grammar.cases[narrow_caseID_tuple.0.v.u]).0 == Some(v.val)) <==> (parse_Val(data[index+8..index+8+SizeOfV(v.val)], grammar.cases[narrow_caseID_tuple.0.v.u]).0 == Some(v.val)); } } else if parse_Case(data[index..index+SizeOfV(v)], grammar.cases).0 == Some(v) { var narrow_val_tuple := parse_Val(narrow_caseID_tuple.1, grammar.cases[narrow_caseID_tuple.0.v.u]); // var bound_val_tuple := parse_Val(bound_caseID_tuple.1, grammar.cases[bound_caseID_tuple.0.v.u]); lemma_parse_Val_view(data, v.val, grammar.cases[narrow_caseID_tuple.0.v.u], index + 8); assert (parse_Val(data[index+8..bound], grammar.cases[narrow_caseID_tuple.0.v.u]).0 == Some(v.val)) <==> (parse_Val(data[index+8..index+8+SizeOfV(v.val)], grammar.cases[narrow_caseID_tuple.0.v.u]).0 == Some(v.val)); assert index + SizeOfV(v) == bound; } else { // Doesn't matter } } lemma lemma_parse_Val_view(data:seq, v:V, grammar:G, index:int) requires |data| < 0x1_0000_0000_0000_0000 requires ValInGrammar(v, grammar) requires ValidGrammar(grammar) requires 0 <= index <= |data| requires 0 <= index + SizeOfV(v) <= |data| decreases grammar, 0 ensures forall bound :: index+SizeOfV(v) <= bound <= |data| ==> ((parse_Val(data[index..bound], grammar).0 == Some(v)) <==> (parse_Val(data[index..index+SizeOfV(v)], grammar).0 == Some(v))) ensures forall bound :: index+SizeOfV(v) <= bound <= |data| ==> (parse_Val(data[index..bound], grammar).0 == Some(v)) ==> parse_Val(data[index..bound], grammar).1 == data[index+SizeOfV(v)..bound] { forall bound | index+SizeOfV(v) <= bound <= |data| ensures (parse_Val(data[index..bound], grammar).0 == Some(v)) <==> (parse_Val(data[index..index+SizeOfV(v)], grammar).0 == Some(v)) ensures (parse_Val(data[index..bound], grammar).0 == Some(v)) ==> parse_Val(data[index..bound], grammar).1 == data[index+SizeOfV(v)..bound] { reveal parse_Val(); match grammar case GUint64 => assert (parse_Val(data[index..bound], grammar).0 == Some(v)) <==> (parse_Val(data[index..index+SizeOfV(v)], grammar).0 == Some(v)); case GArray(elt) => lemma_parse_Val_view_Array(data, v, grammar, index, bound); assert (parse_Val(data[index..bound], grammar).0 == Some(v)) <==> (parse_Val(data[index..index+SizeOfV(v)], grammar).0 == Some(v)); case GTuple(t) => lemma_parse_Val_view_Tuple(data, v, t, index, bound); assert (parse_Val(data[index..bound], grammar).0 == Some(v)) <==> (parse_Val(data[index..index+SizeOfV(v)], grammar).0 == Some(v)); case GByteArray => lemma_parse_Val_view_ByteArray(data, v, grammar, index); assert (parse_Val(data[index..bound], grammar).0 == Some(v)) <==> (parse_Val(data[index..index+SizeOfV(v)], grammar).0 == Some(v)); case GTaggedUnion(cases) => lemma_parse_Val_view_Union(data, v, grammar, index, bound); assert (parse_Val(data[index..bound], grammar).0 == Some(v)) <==> (parse_Val(data[index..index+SizeOfV(v)], grammar).0 == Some(v)); } } lemma lemma_parse_Val_view_specific(data:seq, v:V, grammar:G, index:int, bound:int) requires |data| < 0x1_0000_0000_0000_0000 requires ValInGrammar(v, grammar) requires ValidGrammar(grammar) requires 0 <= index <= |data| requires 0 <= index + SizeOfV(v) <= |data| requires index+SizeOfV(v) <= bound <= |data|; requires parse_Val(data[index..index+SizeOfV(v)], grammar).0 == Some(v) decreases grammar, 0 ensures parse_Val(data[index..bound], grammar).0 == Some(v) ensures parse_Val(data[index..bound], grammar).1 == data[index+SizeOfV(v)..bound] { lemma_parse_Val_view(data, v, grammar, index); } lemma lemma_parse_Val_view_specific_size(data:seq, v:V, grammar:G, index:int, bound:int) requires |data| < 0x1_0000_0000_0000_0000 requires ValInGrammar(v, grammar) requires ValidGrammar(grammar) requires 0 <= index <= |data| requires 0 <= index + SizeOfV(v) <= |data| requires index+SizeOfV(v) <= bound <= |data| requires parse_Val(data[index..bound], grammar).0 == Some(v) decreases grammar, 0 ensures parse_Val(data[index..index+SizeOfV(v)], grammar).0 == Some(v) ensures parse_Val(data[index..bound], grammar).1 == data[index+SizeOfV(v)..bound] { lemma_parse_Val_view(data, v, grammar, index); } method ComputeSeqSum(s:seq) returns (size:uint64) requires |s| < 0x1_0000_0000_0000_0000 requires 0 <= SeqSum(s) < 0x1_0000_0000_0000_0000 requires forall v :: v in s ==> ValidVal(v) ensures size as int == SeqSum(s) { reveal SeqSum(); if |s| as uint64 == 0 { size := 0; } else { var v_size := ComputeSizeOf(s[0]); var rest_size := ComputeSeqSum(s[1..]); size := v_size + rest_size; } } method ComputeSizeOf(val:V) returns (size:uint64) requires 0 <= SizeOfV(val) < 0x1_0000_0000_0000_0000 requires ValidVal(val) ensures size as int == SizeOfV(val) { match val case VUint64(_) => size := 8; case VArray(a) => var v := ComputeSeqSum(a); if v == 0 { size := 8; } else { size := 8 + v; } case VTuple(t) => size := ComputeSeqSum(t); case VByteArray(b) => size := 8 + (|b| as uint64); case VCase(c, v) => var vs := ComputeSizeOf(v); size := 8 + vs; } method MarshallUint64(n:uint64, data:array, index:uint64) requires (index as int) + (Uint64Size() as int) <= data.Length requires 0 <= (index as int) + (Uint64Size() as int) < 0x1_0000_0000_0000_0000 // Needed to prevent overflow below requires data.Length < 0x1_0000_0000_0000_0000 modifies data ensures SeqByteToUint64(data[index..index+Uint64Size()]) == n ensures !parse_Uint64(data[index .. index+Uint64Size()]).0.None? ensures !parse_Uint64(data[index .. ]).0.None? ensures var tuple := parse_Uint64(data[index .. index+Uint64Size()]); tuple.0.v.u == n && tuple.1 == [] ensures var tuple := parse_Uint64(data[index .. ]); tuple.0.v.u == n && tuple.1 == data[index+Uint64Size()..] ensures data[0..index] == old(data[0..index]) ensures data[index+Uint64Size()..] == old(data[index+Uint64Size()..]) ensures forall i :: 0 <= i < index ==> data[i] == old(data[i]) ensures forall i :: (index as int) + (Uint64Size() as int) <= i < data.Length ==> data[i] == old(data[i]) { MarshallUint64_guts(n, data, index); calc { parse_Uint64(data[index .. index+Uint64Size()]).0.v.u; (Some(VUint64(SeqByteToUint64(data[index .. index+Uint64Size()][..Uint64Size()]))), data[Uint64Size()..]).0.v.u; SeqByteToUint64(data[index .. index+Uint64Size()][..Uint64Size()]); SeqByteToUint64(data[index .. index+Uint64Size()]); SeqByteToUint64(data[index .. index+(Uint64Size() as uint64)]); n; } calc { parse_Uint64(data[index..]).0.v.u; (Some(VUint64(SeqByteToUint64(data[index..][..Uint64Size()]))), data[Uint64Size()..]).0.v.u; SeqByteToUint64(data[index..][..Uint64Size()]); SeqByteToUint64(data[index .. index+Uint64Size()]); SeqByteToUint64(data[index .. index+(Uint64Size() as uint64)]); n; } } lemma lemma_marshall_array_contents(contents:seq, eltType:G, marshalled_bytes:seq, trace:seq>) requires forall v :: v in contents ==> ValInGrammar(v, eltType) requires forall v :: v in contents ==> ValidVal(v) requires ValidGrammar(eltType) requires |marshalled_bytes| < 0x1_0000_0000_0000_0000 requires |contents| < 0x1_0000_0000_0000_0000 requires |contents| == |trace| requires |marshalled_bytes| == SeqSum(contents) requires marshalled_bytes == SeqCatRev(trace) requires forall j :: 0 <= j < |trace| ==> SizeOfV(contents[j]) == |trace[j]| < 0x1_0000_0000_0000_0000 requires forall j :: 0 <= j < |trace| ==> var (val, rest) := parse_Val(trace[j], eltType); val.Some? && val.v == contents[j]; ensures parse_Array_contents(marshalled_bytes, eltType, |contents| as uint64).0.Some? ensures parse_Array_contents(marshalled_bytes, eltType, |contents| as uint64).0.v == contents { if |contents| == 0 { reveal parse_Array_contents(); } else { var val_tuple := parse_Val(marshalled_bytes, eltType); var val, rest1 := val_tuple.0, val_tuple.1; var rest_tuple := parse_Array_contents(rest1, eltType, |contents| as uint64-1); var others, rest2 := rest_tuple.0, rest_tuple.1; var target := parse_Array_contents(marshalled_bytes, eltType, |contents| as uint64).0; calc { target; { reveal parse_Array_contents(); } if !val.None? && !others.None? then Some([val.v] + others.v) else None; } calc { SeqCatRev(trace); { lemma_SeqCat_equivalent(trace); } SeqCat(trace); } assert marshalled_bytes[0..SizeOfV(contents[0])] == trace[0]; assert parse_Val(trace[0], eltType).0.Some?; assert parse_Val(trace[0], eltType).0.v == contents[0]; lemma_parse_Val_view_specific(marshalled_bytes, contents[0], eltType, 0, |marshalled_bytes|); assert parse_Val(marshalled_bytes[0..|marshalled_bytes|], eltType).0 == Some(contents[0]); assert marshalled_bytes[0..|marshalled_bytes|] == marshalled_bytes; // OBSERVE assert val.Some? && val.v == contents[0]; assert rest1 == marshalled_bytes[SizeOfV(contents[0])..]; // Prove a requires for the recursive call calc { marshalled_bytes[SizeOfV(contents[0])..]; calc { marshalled_bytes; SeqCatRev(trace); { lemma_SeqCat_equivalent(trace); } SeqCat(trace); trace[0] + SeqCat(trace[1..]); { lemma_SeqCat_equivalent(trace[1..]); } trace[0] + SeqCatRev(trace[1..]); } (trace[0] + SeqCatRev(trace[1..]))[SizeOfV(contents[0])..]; { assert |trace[0]| == SizeOfV(contents[0]); } SeqCatRev(trace[1..]); } // Prove a requires for the recursive call calc { SeqSum(contents); { reveal SeqSum(); } SizeOfV(contents[0]) + SeqSum(contents[1..]); } lemma_marshall_array_contents(contents[1..], eltType, marshalled_bytes[SizeOfV(contents[0])..], trace[1..]); assert others.Some?; assert others.v == contents[1..]; assert contents == [contents[0]] + contents[1..]; } } method{:timeLimitMultiplier 4} MarshallArrayContents(contents:seq, eltType:G, data:array, index:uint64) returns (size:uint64) requires forall v :: v in contents ==> ValInGrammar(v, eltType) requires forall v :: v in contents ==> ValidVal(v) requires ValidGrammar(eltType) requires (index as int) + SeqSum(contents) <= data.Length requires 0 <= (index as int) + SeqSum(contents) < 0x1_0000_0000_0000_0000 requires data.Length < 0x1_0000_0000_0000_0000 requires |contents| < 0x1_0000_0000_0000_0000 decreases eltType, 1, |contents| modifies data ensures parse_Array_contents(data[index..(index as int) + SeqSum(contents)], eltType, |contents| as uint64).0.Some? ensures parse_Array_contents(data[index..(index as int) + SeqSum(contents)], eltType, |contents| as uint64).0.v == contents ensures forall i :: 0 <= i < index ==> data[i] == old(data[i]) ensures forall i :: (index as int) + SeqSum(contents) <= i < data.Length ==> data[i] == old(data[i]) ensures size as int == SeqSum(contents) { var i:int := 0; var cur_index := index; reveal SeqSum(); reveal parse_Array_contents(); ghost var trace := []; ghost var marshalled_bytes := []; while i < |contents| invariant 0 <= i <= |contents| invariant 0 <= index as int <= (index as int) + SeqSum(contents[..i]) <= data.Length invariant cur_index as int == (index as int) + SeqSum(contents[..i]) invariant forall j :: 0 <= j < index ==> data[j] == old(data[j]) invariant forall j :: (index as int) + SeqSum(contents) <= j < data.Length ==> data[j] == old(data[j]) invariant marshalled_bytes == data[index..cur_index] invariant marshalled_bytes == SeqCatRev(trace) invariant |trace| == i invariant forall j :: 0 <= j < |trace| ==> SizeOfV(contents[j]) == |trace[j]| < 0x1_0000_0000_0000_0000 invariant forall j :: 0 <= j < |trace| ==> var (val, rest) := parse_Val(trace[j], eltType); val.Some? && val.v == contents[j] { lemma_SeqSum_bound(contents, 0x1_0000_0000_0000_0000); // Prove we meet MarshallVal's length requirement calc <= { (cur_index as int) + SizeOfV(contents[i]); (index as int) + SeqSum(contents[..i]) + SizeOfV(contents[i]); { lemma_SeqSum_prefix(contents[..i], contents[i]); assert contents[..i] + [contents[i]] == contents[..i+1]; } (index as int) + SeqSum(contents[..i+1]); { lemma_SeqSum_bound_prefix(contents, contents[..i+1], i+1); } //{ lemma_SeqSum_bound(contents, data.Length - (index as int) + 1); } (index as int) + SeqSum(contents); //data.Length; } var item_size := MarshallVal(contents[i], eltType, data, cur_index); //var item_size := ComputeSizeOf(contents[i as uint64]); ghost var fresh_bytes := data[cur_index..cur_index + item_size]; marshalled_bytes := marshalled_bytes + fresh_bytes; forall ensures var (val, rest) := parse_Val(fresh_bytes, eltType); val.Some? && val.v == contents[i] { assert SizeOfV(contents[i]) <= |fresh_bytes|; // OBSERVE lemma_parse_Val_view(fresh_bytes, contents[i], eltType, 0); } ghost var old_trace := trace; trace := trace + [fresh_bytes]; ghost var old_cur_index := cur_index; cur_index := cur_index + item_size; i := i + 1; // Prove the invariant that we stay within bounds calc <= { (index as int) + SeqSum(contents[..i]); calc { SeqSum(contents[..i]); <= { lemma_SeqSum_bound_prefix(contents, contents[..i], i); } SeqSum(contents); } (index as int) + SeqSum(contents); data.Length; } assert {:split_here} true; assert marshalled_bytes == data[index..cur_index]; // Prove the invariant about our index tracking correctly calc { cur_index as int; (old_cur_index as int) + SizeOfV(contents[i-1]); (index as int) + SeqSum(contents[..i-1]) + SizeOfV(contents[i-1]); { lemma_SeqSum_prefix(contents[..i-1], contents[i-1]); assert contents[..i-1] + [contents[i-1]] == contents[..i]; } (index as int) + SeqSum(contents[..i]); } assert cur_index as int == (index as int) + SeqSum(contents[..i]); assert marshalled_bytes == data[index..cur_index]; } // Prove that parsing will produce the correct result // After the while loop, we know: assert contents[..i] == contents; // OBSERVE assert cur_index as int == (index as int) + SeqSum(contents); assert marshalled_bytes == data[index..(index as int)+SeqSum(contents)]; //assert marshalled_bytes == SeqCatRev(trace); //assert |trace| == |contents|; lemma_marshall_array_contents(contents, eltType, marshalled_bytes, trace); size := cur_index - index; } method MarshallArray(val:V, grammar:G, data:array, index:uint64) returns (size:uint64) requires val.VArray? requires ValInGrammar(val, grammar) requires ValidGrammar(grammar) requires ValidVal(val) requires (index as int) + SizeOfV(val) <= data.Length requires 0 <= (index as int) + SizeOfV(val) < 0x1_0000_0000_0000_0000 // Needed to prevent overflow below requires data.Length < 0x1_0000_0000_0000_0000 modifies data decreases grammar, -1 ensures parse_Val(data[index..(index as int) + SizeOfV(val)], grammar).0.Some? && parse_Val(data[index..(index as int) + SizeOfV(val)], grammar).0.v == val ensures forall i :: 0 <= i < index ==> data[i] == old(data[i]) ensures forall i :: (index as int) + SizeOfV(val) <= i < data.Length ==> data[i] == old(data[i]) ensures (size as int) == SizeOfV(val) { //assert{:split_here} true; reveal parse_Val(); MarshallUint64(|val.a| as uint64, data, index); ghost var tuple := parse_Uint64(data[index..(index as int) + SizeOfV(val)]); ghost var len := tuple.0; ghost var rest := tuple.1; assert !len.None?; var contents_size := MarshallArrayContents(val.a, grammar.elt, data, index + Uint64Size()); tuple := parse_Uint64(data[index..(index as int) + SizeOfV(val)]); assert {:split_here} true; len := tuple.0; rest := tuple.1; assert !len.None?; ghost var contents_tuple := parse_Array_contents(rest, grammar.elt, len.v.u); ghost var contents := contents_tuple.0; ghost var remainder := contents_tuple.1; assert !contents.None?; size := 8 + contents_size; } lemma lemma_marshall_tuple_contents(contents:seq, eltTypes:seq, marshalled_bytes:seq, trace:seq>) requires |contents| == |eltTypes| requires forall i :: 0 <= i < |contents| ==> ValInGrammar(contents[i], eltTypes[i]) requires forall g :: g in eltTypes ==> ValidGrammar(g) requires |eltTypes| < 0x1_0000_0000_0000_0000 requires forall i :: 0 <= i < |contents| ==> ValidVal(contents[i]) requires |marshalled_bytes| < 0x1_0000_0000_0000_0000 requires |contents| < 0x1_0000_0000_0000_0000 requires |contents| == |trace| requires |marshalled_bytes| == SeqSum(contents) requires marshalled_bytes == SeqCatRev(trace) requires forall j :: 0 <= j < |trace| ==> SizeOfV(contents[j]) == |trace[j]| < 0x1_0000_0000_0000_0000 requires forall j :: 0 <= j < |trace| ==> var (val, rest) := parse_Val(trace[j], eltTypes[j]); val.Some? && val.v == contents[j]; ensures parse_Tuple_contents(marshalled_bytes, eltTypes).0.Some? ensures parse_Tuple_contents(marshalled_bytes, eltTypes).0.v == contents { if |contents| == 0 { reveal parse_Tuple_contents(); } else { var val_tuple := parse_Val(marshalled_bytes, eltTypes[0]); var val, rest1 := val_tuple.0, val_tuple.1; var rest_tuple := parse_Tuple_contents(rest1, eltTypes[1..]); var others, rest2 := rest_tuple.0, rest_tuple.1; var target := parse_Tuple_contents(marshalled_bytes, eltTypes).0; calc { target; { reveal parse_Tuple_contents(); } if !val.None? && !others.None? then Some([val.v] + others.v) else None; } calc { SeqCatRev(trace); { lemma_SeqCat_equivalent(trace); } SeqCat(trace); } assert marshalled_bytes[0..SizeOfV(contents[0])] == trace[0]; assert parse_Val(trace[0], eltTypes[0]).0.Some?; assert parse_Val(trace[0], eltTypes[0]).0.v == contents[0]; lemma_parse_Val_view_specific(marshalled_bytes, contents[0], eltTypes[0], 0, |marshalled_bytes|); assert parse_Val(marshalled_bytes[0..|marshalled_bytes|], eltTypes[0]).0 == Some(contents[0]); assert marshalled_bytes[0..|marshalled_bytes|] == marshalled_bytes; // OBSERVE assert val.Some? && val.v == contents[0]; assert rest1 == marshalled_bytes[SizeOfV(contents[0])..]; // Prove a requires for the recursive call calc { marshalled_bytes[SizeOfV(contents[0])..]; calc { marshalled_bytes; SeqCatRev(trace); { lemma_SeqCat_equivalent(trace); } SeqCat(trace); trace[0] + SeqCat(trace[1..]); { lemma_SeqCat_equivalent(trace[1..]); } trace[0] + SeqCatRev(trace[1..]); } (trace[0] + SeqCatRev(trace[1..]))[SizeOfV(contents[0])..]; { assert |trace[0]| == SizeOfV(contents[0]); } SeqCatRev(trace[1..]); } // Prove a requires for the recursive call calc { SeqSum(contents); { reveal SeqSum(); } SizeOfV(contents[0]) + SeqSum(contents[1..]); } lemma_marshall_tuple_contents(contents[1..], eltTypes[1..], marshalled_bytes[SizeOfV(contents[0])..], trace[1..]); assert others.Some?; assert others.v == contents[1..]; assert contents == [contents[0]] + contents[1..]; } } method{:timeLimitMultiplier 2} MarshallTupleContents(contents:seq, eltTypes:seq, data:array, index:uint64) returns (size:uint64) requires |contents| == |eltTypes| requires forall i :: 0 <= i < |contents| ==> ValInGrammar(contents[i], eltTypes[i]) requires forall g :: g in eltTypes ==> ValidGrammar(g) requires |eltTypes| < 0x1_0000_0000_0000_0000 requires forall i :: 0 <= i < |contents| ==> ValidVal(contents[i]) requires (index as int) + SeqSum(contents) <= data.Length requires 0 <= (index as int) + SeqSum(contents) < 0x1_0000_0000_0000_0000 requires data.Length < 0x1_0000_0000_0000_0000 requires |contents| < 0x1_0000_0000_0000_0000 decreases eltTypes, 1, |contents| modifies data ensures parse_Tuple_contents(data[index..(index as int) + SeqSum(contents)], eltTypes).0.Some? ensures parse_Tuple_contents(data[index..(index as int) + SeqSum(contents)], eltTypes).0.v == contents ensures forall i :: 0 <= i < index ==> data[i] == old(data[i]) ensures forall i :: (index as int) + SeqSum(contents) <= i < data.Length ==> data[i] == old(data[i]) ensures size as int == SeqSum(contents) { var i:int := 0; var cur_index := index; reveal SeqSum(); reveal parse_Tuple_contents(); ghost var trace := []; ghost var marshalled_bytes := []; while i < |contents| invariant 0 <= i <= |contents| invariant 0 <= index as int <= (index as int) + SeqSum(contents[..i]) <= data.Length invariant cur_index as int == (index as int) + SeqSum(contents[..i]) invariant forall j :: 0 <= j < index ==> data[j] == old(data[j]) invariant forall j :: (index as int) + SeqSum(contents) <= j < data.Length ==> data[j] == old(data[j]) invariant marshalled_bytes == data[index..cur_index] invariant marshalled_bytes == SeqCatRev(trace) invariant |trace| == i invariant forall j :: 0 <= j < |trace| ==> SizeOfV(contents[j]) == |trace[j]| < 0x1_0000_0000_0000_0000 invariant forall j :: 0 <= j < |trace| ==> var (val, rest) := parse_Val(trace[j], eltTypes[j]); val.Some? && val.v == contents[j] { lemma_SeqSum_bound(contents, 0x1_0000_0000_0000_0000); ghost var old_marshalled_bytes := marshalled_bytes; ghost var old_data := data[index..cur_index]; assert old_marshalled_bytes == old_data; // Prove we meet MarshallVal's length requirement calc <= { (cur_index as int) + SizeOfV(contents[i]); (index as int) + SeqSum(contents[..i]) + SizeOfV(contents[i]); { lemma_SeqSum_prefix(contents[..i], contents[i]); assert contents[..i] + [contents[i]] == contents[..i+1]; } (index as int) + SeqSum(contents[..i+1]); { lemma_SeqSum_bound_prefix(contents, contents[..i+1], i+1); } //{ lemma_SeqSum_bound(contents, data.Length - (index as int) + 1); } (index as int) + SeqSum(contents); //data.Length; } var item_size := MarshallVal(contents[i], eltTypes[i], data, cur_index); //var item_size := ComputeSizeOf(contents[i]); ghost var fresh_bytes := data[cur_index..cur_index + item_size]; marshalled_bytes := marshalled_bytes + fresh_bytes; forall ensures var (val, rest) := parse_Val(fresh_bytes, eltTypes[i]); val.Some? && val.v == contents[i]; { assert SizeOfV(contents[i]) <= |fresh_bytes|; // OBSERVE lemma_parse_Val_view(fresh_bytes, contents[i], eltTypes[i], 0); } ghost var old_trace := trace; trace := trace + [fresh_bytes]; ghost var old_cur_index := cur_index; cur_index := cur_index + item_size; i := i + 1; assert {:split_here} true; // Prove the invariant about marshalled_bytes' contents calc { marshalled_bytes; old_marshalled_bytes + fresh_bytes; old_data + fresh_bytes; data[index..old_cur_index] + fresh_bytes; data[index..old_cur_index] + data[old_cur_index..cur_index]; data[index..cur_index]; } // Prove the invariant that we stay within bounds calc <= { (index as int) + SeqSum(contents[..i]); calc { SeqSum(contents[..i]); <= { lemma_SeqSum_bound_prefix(contents, contents[..i], i); } SeqSum(contents); } (index as int) + SeqSum(contents); data.Length; } // Prove the invariant about our index tracking correctly calc { cur_index as int; (old_cur_index as int) + SizeOfV(contents[i-1]); (index as int) + SeqSum(contents[..i-1]) + SizeOfV(contents[i-1]); { lemma_SeqSum_prefix(contents[..i-1], contents[i-1]); assert contents[..i-1] + [contents[i-1]] == contents[..i]; } (index as int) + SeqSum(contents[..i]); } assert cur_index as int == (index as int) + SeqSum(contents[..i]); } // Prove that parsing will produce the correct result // After the while loop, we know: assert contents[..i] == contents; // OBSERVE assert cur_index as int == (index as int) + SeqSum(contents); assert marshalled_bytes == data[index..(index as int)+SeqSum(contents)]; //assert marshalled_bytes == SeqCatRev(trace); //assert |trace| == |contents|; lemma_marshall_tuple_contents(contents, eltTypes, marshalled_bytes, trace); size := cur_index - index; } method MarshallTuple(val:V, grammar:G, data:array, index:uint64) returns (size:uint64) requires val.VTuple? requires ValidVal(val) requires ValidGrammar(grammar) requires ValInGrammar(val, grammar) requires (index as int) + SizeOfV(val) <= data.Length requires 0 <= (index as int) + SizeOfV(val) < 0x1_0000_0000_0000_0000 // Needed to prevent overflow below requires data.Length < 0x1_0000_0000_0000_0000 modifies data decreases grammar, -1 ensures parse_Val(data[index..(index as int) + SizeOfV(val)], grammar).0.Some? && parse_Val(data[index..(index as int) + SizeOfV(val)], grammar).0.v == val ensures forall i :: 0 <= i < index ==> data[i] == old(data[i]) ensures forall i :: (index as int) + SizeOfV(val) <= i < data.Length ==> data[i] == old(data[i]) ensures size as int == SizeOfV(val) { size := MarshallTupleContents(val.t, grammar.t, data, index); calc { parse_Val(data[index..(index as int) + SizeOfV(val)], grammar); { reveal parse_Val(); } parse_Tuple(data[index..(index as int) + SizeOfV(val)], grammar.t); } } method MarshallBytes(bytes:seq, data:array, index:uint64) requires (index as int) + |bytes| <= data.Length requires 0 <= (index as int) + |bytes| < 0x1_0000_0000_0000_0000 // Needed to prevent overflow below requires data.Length < 0x1_0000_0000_0000_0000 modifies data ensures forall i :: 0 <= i < index ==> data[i] == old(data[i]) ensures forall i :: (index as int) <= i < (index as int) + |bytes| ==> data[i] == bytes[i - (index as int)] ensures forall i :: (index as int) + |bytes| <= i < data.Length ==> data[i] == old(data[i]) { Arrays.CopySeqIntoArray(bytes, 0, data, index, |bytes| as uint64); /* var j:uint64 := 0; while (j < |bytes| as uint64) invariant 0 <= j as int <= |bytes| invariant forall i:int :: 0 <= i < (index as int) ==> data[i] == old(data[i]) invariant forall i:int :: index as int <= i < (index as int) + (j as int) ==> data[i] == bytes[i-(index as int)] invariant forall i:int :: (index as int) + |bytes| <= i < data.Length ==> data[i] == old(data[i]) { data[index + j] := bytes[j]; j := j + 1; } */ } method MarshallByteArray(val:V, grammar:G, data:array, index:uint64) returns (size:uint64) requires val.VByteArray? requires ValidGrammar(grammar) requires ValInGrammar(val, grammar) requires ValidVal(val) requires (index as int) + SizeOfV(val) <= data.Length requires 0 <= (index as int) + SizeOfV(val) < 0x1_0000_0000_0000_0000 // Needed to prevent overflow below requires data.Length < 0x1_0000_0000_0000_0000 modifies data decreases grammar ensures parse_Val(data[index..(index as int) + SizeOfV(val)], grammar).0.Some? && parse_Val(data[index..(index as int) + SizeOfV(val)], grammar).0.v == val ensures forall i :: 0 <= i < index ==> data[i] == old(data[i]); ensures forall i :: (index as int) + SizeOfV(val) <= i < data.Length ==> data[i] == old(data[i]) ensures size as int == SizeOfV(val) { MarshallUint64(|val.b| as uint64, data, index); assert SeqByteToUint64(data[index..index+Uint64Size()]) == (|val.b| as uint64); MarshallBytes(val.b, data, index + 8); calc { parse_Val(data[index..(index as int) + SizeOfV(val)], grammar); { reveal parse_Val(); } parse_ByteArray(data[index..(index as int) + SizeOfV(val)]); } ghost var data_seq := data[index..(index as int) + SizeOfV(val)]; ghost var tuple := parse_Uint64(data_seq); ghost var len := tuple.0; ghost var rest := tuple.1; assert{:split_here} true; assert len.v.u == |val.b| as uint64; assert rest == data[index + 8..(index as int) + SizeOfV(val)] == val.b; assert !len.None? && (len.v.u as int) <= |rest|; assert rest[0..len.v.u] == val.b; // OBSERVE size := 8 + (|val.b| as uint64); } method MarshallCase(val:V, grammar:G, data:array, index:uint64) returns (size:uint64) requires val.VCase? requires ValidGrammar(grammar) requires ValInGrammar(val, grammar) requires ValidVal(val) requires (index as int) + SizeOfV(val) <= data.Length requires 0 <= (index as int) + SizeOfV(val) < 0x1_0000_0000_0000_0000 // Needed to prevent overflow below requires data.Length < 0x1_0000_0000_0000_0000 modifies data decreases grammar, -1 ensures parse_Val(data[index..(index as int) + SizeOfV(val)], grammar).0.Some? && parse_Val(data[index..(index as int) + SizeOfV(val)], grammar).0.v == val ensures forall i :: 0 <= i < index ==> data[i] == old(data[i]) ensures forall i :: (index as int) + SizeOfV(val) <= i < data.Length ==> data[i] == old(data[i]) ensures size as int == SizeOfV(val) { MarshallUint64(val.c, data, index); ghost var int_bytes := data[index..index+Uint64Size()]; ghost var tuple0 := parse_Uint64(int_bytes); ghost var caseID0 := tuple0.0; ghost var rest10 := tuple0.1; assert !caseID0.None?; assert caseID0.v.u == val.c; var val_size := MarshallVal(val.val, grammar.cases[val.c], data, index + 8); ghost var new_int_bytes := data[index..index+Uint64Size()]; assert forall i {:auto_trigger} :: 0 <= i < Uint64Size() ==> int_bytes[i] == new_int_bytes[i]; assert int_bytes == new_int_bytes; assert val.VCase?; assert grammar.GTaggedUnion?; assert val.c as int < |grammar.cases|; ghost var bytes := data[index..(index as int) + SizeOfV(val)]; assert bytes[..8] == new_int_bytes; calc { parse_Val(bytes, grammar); { reveal parse_Val(); } parse_Case(bytes, grammar.cases); } assert{:split_here} true; ghost var tuple1 := parse_Uint64(bytes); ghost var caseID := tuple1.0; ghost var rest1 := tuple1.1; assert !caseID.None?; assert caseID.v.u == val.c; assert (caseID.v.u as int) < |grammar.cases|; ghost var tuple2 := parse_Val(rest1, grammar.cases[caseID.v.u]); ghost var v:= tuple2.0; ghost var rest2 := tuple2.1; assert !v.None?; size := 8 + val_size; } method MarshallVUint64(val:V, grammar:G, data:array, index:uint64) returns (size:uint64) requires val.VUint64? requires ValidGrammar(grammar) requires ValInGrammar(val, grammar) requires (index as int) + SizeOfV(val) <= data.Length requires 0 <= (index as int) + SizeOfV(val) < 0x1_0000_0000_0000_0000 // Needed to prevent overflow below requires data.Length < 0x1_0000_0000_0000_0000 modifies data decreases grammar ensures parse_Val(data[index..(index as int) + SizeOfV(val)], grammar).0.Some? && parse_Val(data[index..(index as int) + SizeOfV(val)], grammar).0.v == val ensures forall i :: 0 <= i < index ==> data[i] == old(data[i]) ensures forall i :: (index as int) + SizeOfV(val) <= i < data.Length ==> data[i] == old(data[i]) ensures size as int == SizeOfV(val) { MarshallUint64(val.u, data, index); calc { parse_Val(data[index..(index as int) + SizeOfV(val)], grammar); { reveal parse_Val(); } parse_Uint64(data[index..(index as int) + SizeOfV(val)]); } return 8; } method MarshallVal(val:V, grammar:G, data:array, index:uint64) returns (size:uint64) requires ValidGrammar(grammar) requires ValInGrammar(val, grammar) requires ValidVal(val) requires 0 <= SizeOfV(val) < 0x1_0000_0000_0000_0000 requires (index as int) + SizeOfV(val) <= data.Length requires data.Length < 0x1_0000_0000_0000_0000 modifies data decreases grammar, 0 ensures parse_Val(data[index..(index as int) + SizeOfV(val)], grammar).0.Some? && parse_Val(data[index..(index as int) + SizeOfV(val)], grammar).0.v == val ensures forall i :: 0 <= i < index ==> data[i] == old(data[i]) ensures forall i :: (index as int) + SizeOfV(val) <= i < data.Length ==> data[i] == old(data[i]) ensures size as int == SizeOfV(val) { match val case VUint64(_) => size := MarshallVUint64(val, grammar, data, index); case VArray(_) => size := MarshallArray(val, grammar, data, index); case VTuple(_) => size := MarshallTuple(val, grammar, data, index); case VByteArray(_) => size := MarshallByteArray(val, grammar, data, index); case VCase(_,_) => size := MarshallCase(val, grammar, data, index); } method Marshall(val:V, grammar:G) returns (data:array) requires ValidGrammar(grammar) requires ValInGrammar(val, grammar) requires ValidVal(val) requires 0 <= SizeOfV(val) < 0x1_0000_0000_0000_0000 ensures fresh(data) ensures Demarshallable(data[..], grammar) ensures parse_Val(data[..], grammar).0.Some? && parse_Val(data[..], grammar).0.v == val ensures parse_Val(data[..], grammar).1 == [] ensures |data[..]| == SizeOfV(val) { var size := ComputeSizeOf(val); data := new byte[size]; var computed_size := MarshallVal(val, grammar, data, 0); assert data[0..0 + SizeOfV(val)] == data[0..0 + size] == data[..]; // OBSERVE lemma_parse_Val_view_specific(data[..], val, grammar, 0, size as int); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/Common/GenericRefinement.i.dfy ================================================ include "../../Common/Native/NativeTypes.s.dfy" include "../../Common/Collections/Maps.i.dfy" include "../../Common/Collections/Sets.i.dfy" module GenericRefinement_i { import opened Native__NativeTypes_s import opened Collections__Maps_i import opened Collections__Sets_i // Useful to give this cast a name, so it can be used as a higher-order function function uint64_to_int(u:uint64) : int { u as int } ////////////////////////////////////////////////////////////////////////////// // Generic seq-to-seq refinement function {:opaque} MapSeqToSeq(s:seq, refine_func:T~>U) : seq reads refine_func.reads requires forall i :: refine_func.reads(i) == {} requires forall i :: 0 <= i < |s| ==> refine_func.requires(s[i]) ensures |MapSeqToSeq(s, refine_func)| == |s| ensures forall i :: 0 <= i < |s| ==> refine_func(s[i]) == MapSeqToSeq(s,refine_func)[i] { if |s| == 0 then [] else [refine_func(s[0])] + MapSeqToSeq(s[1..], refine_func) } ///////////////////////////////////////////////////////// // Generic map refinement from concrete to abstract ///////////////////////////////////////////////////////// predicate MapIsAbstractable(m:map, RefineKey:CKT~>KT, RefineValue:CVT~>VT, ReverseKey:KT~>CKT) reads RefineKey.reads, RefineValue.reads, ReverseKey.reads { && (forall ck :: ck in m ==> RefineKey.requires(ck) && RefineValue.requires(m[ck])) && (forall ck :: ck in m ==> ReverseKey.requires(RefineKey(ck)) && ReverseKey(RefineKey(ck)) == ck) } function {:opaque} AbstractifyMap(m:map, RefineKey:CKT~>KT, RefineValue:CVT~>VT, ReverseKey:KT~>CKT) : map reads RefineKey.reads, RefineValue.reads, ReverseKey.reads requires forall ck :: ck in m ==> RefineKey.requires(ck) && RefineValue.requires(m[ck]) requires forall ck :: ck in m ==> ReverseKey.requires(RefineKey(ck)) && ReverseKey(RefineKey(ck)) == ck ensures var rm := AbstractifyMap(m,RefineKey,RefineValue,ReverseKey); forall k :: k in rm ==> (exists ck :: ck in m && RefineKey(ck) == k) { // var new_domain := set ck | ck in m :: RefineKey(ck); // map k | k in new_domain :: RefineValue(m[ReverseKey(k)]) map k | k in (set ck | ck in m :: RefineKey(ck)) :: RefineValue(m[ReverseKey(k)]) } lemma Lemma_AbstractifyMap_basic_properties(m:map, RefineKey:CKT~>KT, RefineValue:CVT~>VT, ReverseKey:KT~>CKT) requires MapIsAbstractable(m, RefineKey, RefineValue, ReverseKey) // Injectivity requires forall ck1, ck2 :: RefineKey.requires(ck1) && RefineKey.requires(ck2) && RefineKey(ck1) == RefineKey(ck2) ==> ck1 == ck2 ensures m == map [] ==> AbstractifyMap(m, RefineKey, RefineValue, ReverseKey) == map [] ensures forall ck :: ck in m <==> RefineKey.requires(ck) && RefineKey(ck) in AbstractifyMap(m, RefineKey, RefineValue, ReverseKey) ensures forall ck :: ck in m ==> AbstractifyMap(m, RefineKey, RefineValue, ReverseKey)[RefineKey(ck)] == RefineValue(m[ck]) { reveal AbstractifyMap(); } lemma Lemma_AbstractifyMap_preimage(cm:map, RefineKey:CKT~>KT, RefineValue:CVT~>VT, ReverseKey:KT~>CKT) requires MapIsAbstractable(cm, RefineKey, RefineValue, ReverseKey) // Injectivity requires forall ck1, ck2 :: RefineKey.requires(ck1) && RefineKey.requires(ck2) && RefineKey(ck1) == RefineKey(ck2) ==> ck1 == ck2 ensures var rm := AbstractifyMap(cm, RefineKey, RefineValue, ReverseKey); forall k :: k in rm ==> (exists ck :: ck in cm && RefineKey(ck) == k) { var rm := AbstractifyMap(cm, RefineKey, RefineValue, ReverseKey); Lemma_AbstractifyMap_basic_properties(cm, RefineKey, RefineValue, ReverseKey); forall k | k in rm ensures (exists ck :: ck in cm && RefineKey(ck) == k) { reveal AbstractifyMap(); } } lemma Lemma_AbstractifyMap_append(cm:map, RefineKey:CKT~>KT, RefineValue:CVT~>VT, ReverseKey:KT~>CKT, ck:CKT, cval:CVT) requires MapIsAbstractable(cm, RefineKey, RefineValue, ReverseKey) // Injectivity requires forall ck1, ck2 :: RefineKey.requires(ck1) && RefineKey.requires(ck2) && RefineKey(ck1) == RefineKey(ck2) ==> ck1 == ck2 requires RefineKey.requires(ck) requires RefineValue.requires(cval) requires ReverseKey.requires(RefineKey(ck)) && ReverseKey(RefineKey(ck)) == ck ensures var rm := AbstractifyMap(cm, RefineKey, RefineValue, ReverseKey); var rm' := AbstractifyMap(cm[ck := cval], RefineKey, RefineValue, ReverseKey); rm' == AbstractifyMap(cm, RefineKey, RefineValue, ReverseKey)[RefineKey(ck) := RefineValue(cval)] { var rm := AbstractifyMap(cm, RefineKey, RefineValue, ReverseKey); var cm' := cm[ck := cval]; var rm' := AbstractifyMap(cm', RefineKey, RefineValue, ReverseKey); var r_cm' := AbstractifyMap(cm, RefineKey, RefineValue, ReverseKey)[RefineKey(ck) := RefineValue(cval)]; forall rk | rk in rm' ensures rk in r_cm' ensures r_cm'[rk] == rm'[rk] { Lemma_AbstractifyMap_basic_properties(cm', RefineKey, RefineValue, ReverseKey); Lemma_AbstractifyMap_preimage(cm', RefineKey, RefineValue, ReverseKey); if (exists p :: p in cm' && RefineKey(p) == rk){ var preimage :| preimage in cm' && RefineKey(preimage) == rk; if preimage in cm { Lemma_AbstractifyMap_basic_properties(cm, RefineKey, RefineValue, ReverseKey); calc ==> { true; { Lemma_AbstractifyMap_preimage(cm, RefineKey, RefineValue, ReverseKey); } RefineKey(preimage) in rm; RefineKey(preimage) in rm'; rk in r_cm'; } } else { assert preimage == ck; assert RefineKey(preimage) in r_cm'; } } reveal AbstractifyMap(); } forall rk | rk in r_cm' ensures rk in rm' { Lemma_AbstractifyMap_basic_properties(cm, RefineKey, RefineValue, ReverseKey); Lemma_AbstractifyMap_preimage(cm, RefineKey, RefineValue, ReverseKey); Lemma_AbstractifyMap_basic_properties(cm', RefineKey, RefineValue, ReverseKey); if rk in rm { if(exists p :: p in cm && RefineKey(p) == rk){ var preimage :| preimage in cm && RefineKey(preimage) == rk; assert rk in rm'; } } else { assert rk == RefineKey(ck); } reveal AbstractifyMap(); } assert r_cm' == rm'; } lemma Lemma_AbstractifyMap_remove( cm:map, RefineKey:CKT~>KT, RefineValue:CVT~>VT, ReverseKey:KT~>CKT, ck:CKT) requires MapIsAbstractable(cm, RefineKey, RefineValue, ReverseKey) // Injectivity requires forall ck1, ck2 :: RefineKey.requires(ck1) && RefineKey.requires(ck2) && RefineKey(ck1) == RefineKey(ck2) ==> ck1 == ck2 requires RefineKey.requires(ck) requires ReverseKey.requires(RefineKey(ck)) && ReverseKey(RefineKey(ck)) == ck requires ck in cm ensures var rm := AbstractifyMap(cm, RefineKey, RefineValue, ReverseKey); var rm' := AbstractifyMap(RemoveElt(cm, ck), RefineKey, RefineValue, ReverseKey); RefineKey(ck) in rm && rm' == RemoveElt(rm, RefineKey(ck)) { Lemma_AbstractifyMap_basic_properties(cm, RefineKey, RefineValue, ReverseKey); var rm := AbstractifyMap(cm, RefineKey, RefineValue, ReverseKey); var smaller_cm := RemoveElt(cm, ck); var rm' := AbstractifyMap(smaller_cm, RefineKey, RefineValue, ReverseKey); var smaller_rm := RemoveElt(rm, RefineKey(ck)); Lemma_AbstractifyMap_basic_properties(smaller_cm, RefineKey, RefineValue, ReverseKey); forall o | o in rm' ensures o in smaller_rm && rm'[o] == smaller_rm[o]; { if (exists c :: c in smaller_cm && RefineKey(c) == o){ var co :| co in smaller_cm && RefineKey(co) == o; assert co != ck; assert RefineKey(co) != RefineKey(ck); } reveal AbstractifyMap(); } forall o | o in smaller_rm ensures o in rm' && rm'[o] == smaller_rm[o] { Lemma_AbstractifyMap_preimage(cm, RefineKey, RefineValue, ReverseKey); // var co :| co in cm && co != ck && RefineKey(co) == o; reveal AbstractifyMap(); } assert forall o :: (o in rm' <==> o in smaller_rm) && (o in rm' ==> rm'[o] == smaller_rm[o]); assert rm' == smaller_rm; } lemma lemma_AbstractifyMap_properties( cm:map, RefineKey:CKT~>KT, RefineValue:CVT~>VT, ReverseKey:KT~>CKT) requires MapIsAbstractable(cm, RefineKey, RefineValue, ReverseKey) // Injectivity requires forall ck1, ck2 :: RefineKey.requires(ck1) && RefineKey.requires(ck2) && RefineKey(ck1) == RefineKey(ck2) ==> ck1 == ck2 ensures cm == map [] ==> AbstractifyMap(cm, RefineKey, RefineValue, ReverseKey) == map [] ensures forall ck :: ck in cm <==> RefineKey.requires(ck) && RefineKey(ck) in AbstractifyMap(cm, RefineKey, RefineValue, ReverseKey) ensures forall ck :: ck in cm ==> AbstractifyMap(cm, RefineKey, RefineValue, ReverseKey)[RefineKey(ck)] == RefineValue(cm[ck]) ensures forall ck :: ck !in cm && RefineKey.requires(ck) ==> RefineKey(ck) !in AbstractifyMap(cm, RefineKey, RefineValue, ReverseKey) ensures var rm := AbstractifyMap(cm, RefineKey, RefineValue, ReverseKey); forall k :: k in rm ==> (exists ck :: ck in cm && RefineKey(ck) == k) ensures forall ck, cval {:trigger cm[ck := cval]} {:trigger RefineKey(ck), RefineValue(cval)} :: (RefineKey.requires(ck) && RefineValue.requires(cval) && ReverseKey.requires(RefineKey(ck)) && ReverseKey(RefineKey(ck)) == ck) ==> var rm := AbstractifyMap(cm, RefineKey, RefineValue, ReverseKey); var rm' := AbstractifyMap(cm[ck := cval], RefineKey, RefineValue, ReverseKey); rm' == AbstractifyMap(cm, RefineKey, RefineValue, ReverseKey)[RefineKey(ck) := RefineValue(cval)] ensures forall ck {:trigger RemoveElt(AbstractifyMap(cm, RefineKey, RefineValue, ReverseKey), RefineKey(ck)) } :: (RefineKey.requires(ck) && ReverseKey.requires(RefineKey(ck)) && ReverseKey(RefineKey(ck)) == ck && ck in cm) ==> var rm := AbstractifyMap(cm, RefineKey, RefineValue, ReverseKey); var rm' := AbstractifyMap(RemoveElt(cm, ck), RefineKey, RefineValue, ReverseKey); rm' == RemoveElt(rm, RefineKey(ck)) { Lemma_AbstractifyMap_basic_properties(cm, RefineKey, RefineValue, ReverseKey); Lemma_AbstractifyMap_preimage(cm, RefineKey, RefineValue, ReverseKey); forall ck, cval | RefineKey.requires(ck) && RefineValue.requires(cval) && ReverseKey.requires(RefineKey(ck)) && ReverseKey(RefineKey(ck)) == ck ensures var rm := AbstractifyMap(cm, RefineKey, RefineValue, ReverseKey); var rm' := AbstractifyMap(cm[ck := cval], RefineKey, RefineValue, ReverseKey); rm' == AbstractifyMap(cm, RefineKey, RefineValue, ReverseKey)[RefineKey(ck) := RefineValue(cval)] { Lemma_AbstractifyMap_append(cm, RefineKey, RefineValue, ReverseKey, ck, cval); } forall ck | RefineKey.requires(ck) && ReverseKey.requires(RefineKey(ck)) && ReverseKey(RefineKey(ck)) == ck && ck in cm ensures var rm := AbstractifyMap(cm, RefineKey, RefineValue, ReverseKey); var rm' := AbstractifyMap(RemoveElt(cm, ck), RefineKey, RefineValue, ReverseKey); rm' == RemoveElt(rm, RefineKey(ck)) { Lemma_AbstractifyMap_remove(cm, RefineKey, RefineValue, ReverseKey, ck); } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/Common/MarshallInt.i.dfy ================================================ include "../../Common/Native/NativeTypes.s.dfy" include "Util.i.dfy" module Common__MarshallInt_i { import opened Native__NativeTypes_s import opened Native__NativeTypes_i import opened Common__Util_i import opened Math__power2_i /* Doesn't appear to be in use at present method MarshallUint32_guts(n:uint32, data:array, index:uint64) requires data != null requires (index as int) + (Uint32Size() as int) <= data.Length requires 0 <= (index as int) + (Uint32Size() as int) < 0x1_0000_0000_0000_0000 // Needed to prevent overflow on the next line requires data.Length < 0x1_0000_0000_0000_0000 modifies data ensures BEByteSeqToUint32(data[index .. index + Uint32Size() as uint64]) == n ensures data[0..index] == old(data[0..index]) ensures data[index + Uint32Size() as uint64 ..] == old(data[index + Uint32Size() as uint64..]) { data[index ] := ( n/0x1000000) as byte; data[index+1] := ((n/ 0x10000)%0x100) as byte; data[index+2] := ((n/ 0x100)%0x100) as byte; data[index+3] := ( n %0x100) as byte; ghost var i := n as int; ghost var bs := [ i / 16777216, (i / 65536) % 256, (i / 256) % 256, i % 256 ]; assert SeqByteToByteSeq(data[index..index+4]) == bs; lemma_2toX(); BEWordToByte_literal(n as int, bs); } */ method MarshallUint64_guts(n:uint64, data:array, index:uint64) requires (index as int) + (Uint64Size() as int) <= data.Length requires 0 <= (index as int) + (Uint64Size() as int) < 0x1_0000_0000_0000_0000 // Needed to prevent overflow on the next line requires data.Length < 0x1_0000_0000_0000_0000 modifies data ensures SeqByteToUint64(data[index..index+(Uint64Size() as uint64)]) == n ensures data[0..index] == old(data[0..index]) ensures data[index+(Uint64Size() as uint64)..] == old(data[index+(Uint64Size() as uint64)..]) { data[index ] := (n/0x1000000_00000000) as byte; data[index+1] := ((n/ 0x10000_00000000)%0x100) as byte; data[index+2] := ((n/ 0x100_00000000)%0x100) as byte; data[index+3] := ((n/ 0x1_00000000)%0x100) as byte; data[index+4] := ((n/ 0x1000000)%0x100) as byte; data[index+5] := ((n/ 0x10000)%0x100) as byte; data[index+6] := ((n/ 0x100)%0x100) as byte; data[index+7] := ( n %0x100) as byte; lemma_2toX(); assert data[index..index+(Uint64Size() as uint64)] == Uint64ToSeqByte(n); lemma_BEUintToSeqByte_invertability(data[index..index+(Uint64Size() as uint64)], n as int, 8); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/Common/NetClient.i.dfy ================================================ include "../../Common/Native/Io.s.dfy" module Common__NetClient_i { import opened Native__Io_s ////////////////////////////////////////////////////////////////////////////// // Things that probably belong in "../../../Common/Native/Io.i.dfy" function Workaround_CastHostEnvironmentToObject(env:HostEnvironment) : object {env} function Workaround_CastOkStateToObject(okState:OkState) : object {okState} function Workaround_CastNowStateToObject(nowState:NowState) : object {nowState} function Workaround_CastNetStateToObject(netState:NetState) : object {netState} function Workaround_CastNetClientToObject(netc:NetClient?) : object? {netc} function HostEnvironmentDefaultFrame(env:HostEnvironment) : set reads env reads {env.now} reads {env.ok} reads {env.net} reads {env} { {Workaround_CastOkStateToObject(env.ok), Workaround_CastNowStateToObject(env.now), Workaround_CastNetStateToObject(env.net)} } function NetClientRepr(netc:NetClient?) : set reads netc reads if netc != null then HostEnvironmentDefaultFrame.reads(netc.env) else {} { {Workaround_CastNetClientToObject(netc)} + (if netc != null then HostEnvironmentDefaultFrame(netc.env) else {}) } predicate HostEnvironmentIsValid(env:HostEnvironment) reads env reads env.Valid.reads() reads env.ok.ok.reads() { && env.Valid() && env.ok.ok() } predicate NetClientOk(netc:NetClient?) reads netc reads if netc != null then HostEnvironmentDefaultFrame.reads(netc.env) else {} { && netc != null && netc.env.ok.ok() } function method EndPointIsValidPublicKey(endPoint:EndPoint) : bool { && |endPoint.public_key| < 0x10_0000 // < 1 MB } predicate NetClientIsValid(netc:NetClient?) reads NetClientRepr(netc) reads if netc != null then HostEnvironmentIsValid.reads(netc.env) else {} { && netc != null && netc.IsOpen() && HostEnvironmentIsValid(netc.env) && EndPointIsValidPublicKey(EndPoint(netc.MyPublicKey())) } predicate EndPointsAreValidPublicKeys(eps:seq) { forall i :: 0 <= i < |eps| ==> EndPointIsValidPublicKey(eps[i]) } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/Common/NodeIdentity.i.dfy ================================================ include "Util.i.dfy" include "NetClient.i.dfy" include "SeqIsUnique.i.dfy" include "../../Protocol/Common/NodeIdentity.i.dfy" include "GenericRefinement.i.dfy" include "../../Common/Collections/Sets.i.dfy" module Common__NodeIdentity_i { import opened Native__NativeTypes_s import opened Native__Io_s import opened Common__Util_i import opened Common__NetClient_i import opened Common__SeqIsUniqueDef_i import opened Common__SeqIsUnique_i import opened Concrete_NodeIdentity_i import opened GenericRefinement_i import opened Collections__Sets_i import opened Math__power2_s import opened Math__power2_i ////////////////////////////////////////////////////////////////////////////// // Useful for EndPoint index to node index conversions function {:opaque} AbstractifySeqOfUint64sToSeqOfInts(s:seq) : seq ensures |AbstractifySeqOfUint64sToSeqOfInts(s)| == |s| ensures forall i :: 0 <= i < |s| ==> s[i] as int == AbstractifySeqOfUint64sToSeqOfInts(s)[i] { MapSeqToSeq(s, uint64_to_int) } function {:opaque} AbstractifySeqOfUint64sToSetOfInts(s:seq) : set requires SeqIsUnique(s) ensures forall x :: x in s ==> (x as int in AbstractifySeqOfUint64sToSetOfInts(s)) { var unique_set := UniqueSeqToSet(s); set i | i in unique_set :: i as int } lemma lemma_AbstractifySeqOfUint64sToSetOfInts_properties(s:seq) requires SeqIsUnique(s) ensures |AbstractifySeqOfUint64sToSetOfInts(s)| == |s| ensures forall i {:auto_trigger} :: (i in s <==> i as int in AbstractifySeqOfUint64sToSetOfInts(s)) { var unique_set := UniqueSeqToSet(s); var r_s := AbstractifySeqOfUint64sToSetOfInts(s); reveal AbstractifySeqOfUint64sToSetOfInts(); lemma_MapSetCardinality(unique_set, r_s, uint64_to_int); lemma_seqs_set_cardinality(s, unique_set); lemma_seqs_set_membership(s, unique_set); } lemma lemma_AbstractifySeqOfUint64sToSetOfInts_append(original_seq:seq, new_index:uint64) requires SeqIsUnique(original_seq) ensures var r_original_set := AbstractifySeqOfUint64sToSetOfInts(original_seq); AbstractifySeqOfUint64sToSetOfInts(AppendToUniqueSeqMaybe(original_seq, new_index)) == r_original_set + {new_index as int} { var appended_seq := AppendToUniqueSeqMaybe(original_seq, new_index); var r_set := AbstractifySeqOfUint64sToSetOfInts(appended_seq); var r_original_set := AbstractifySeqOfUint64sToSetOfInts(original_seq); var new_set := r_original_set + {new_index as int}; assert new_index in appended_seq; assert new_index as int in r_set; assert forall x :: x in original_seq ==> x as int in r_original_set; assert forall x :: x in original_seq ==> x in appended_seq; forall rId | rId in r_set ensures rId in new_set { lemma_AbstractifySeqOfUint64sToSetOfInts_properties(appended_seq); lemma_AbstractifySeqOfUint64sToSetOfInts_properties(original_seq); reveal AbstractifySeqOfUint64sToSetOfInts(); } forall rId | rId in new_set ensures rId in r_set { lemma_AbstractifySeqOfUint64sToSetOfInts_properties(appended_seq); lemma_AbstractifySeqOfUint64sToSetOfInts_properties(original_seq); reveal AbstractifySeqOfUint64sToSetOfInts(); } } ////////////////////////////////////////////////////////////////////////////// // NodeIdentity predicate EndPointIsAbstractable(endpoint:EndPoint) { true } function AbstractifyEndPointToNodeIdentity(endpoint:EndPoint) : NodeIdentity { endpoint } predicate SeqOfEndPointsIsAbstractable(endPoints:seq) { forall e :: e in endPoints ==> EndPointIsAbstractable(e) } function {:opaque} AbstractifyEndPointsToNodeIdentities(endPoints:seq) : seq requires forall e :: e in endPoints ==> EndPointIsAbstractable(e) ensures |AbstractifyEndPointsToNodeIdentities(endPoints)| == |endPoints| ensures forall i :: 0<=i<|endPoints| ==> AbstractifyEndPointToNodeIdentity(endPoints[i]) == AbstractifyEndPointsToNodeIdentities(endPoints)[i] { if |endPoints| == 0 then [] else [AbstractifyEndPointToNodeIdentity(endPoints[0])] + AbstractifyEndPointsToNodeIdentities(endPoints[1..]) } lemma lemma_AbstractifyEndPointToNodeIdentity_injective(e1:EndPoint, e2:EndPoint) requires AbstractifyEndPointToNodeIdentity(e1) == AbstractifyEndPointToNodeIdentity(e2) ensures e1==e2 { } lemma lemma_AbstractifyEndPointToNodeIdentity_injective_forall() ensures forall e1, e2 {:trigger AbstractifyEndPointToNodeIdentity(e1),AbstractifyEndPointToNodeIdentity(e2)} :: AbstractifyEndPointToNodeIdentity(e1) == AbstractifyEndPointToNodeIdentity(e2) ==> e1 == e2; { forall e1, e2 | AbstractifyEndPointToNodeIdentity(e1) == AbstractifyEndPointToNodeIdentity(e2) ensures e1 == e2 { lemma_AbstractifyEndPointToNodeIdentity_injective(e1, e2); } } lemma lemma_seqs_set_cardinality_EndPoint(Q:seq, S:set) requires SeqIsUnique(Q) requires S == set e | e in Q ensures |Q| == |S| decreases |Q| { lemma_seqs_set_cardinality(Q, S); } lemma lemma_sets_cardinality_EndPoint(S:set, T:set) requires forall e :: e in S ==> EndPointIsAbstractable(e) requires T == set e | e in S :: AbstractifyEndPointToNodeIdentity(e) ensures |S| == |T| decreases |S| { if (S=={}) { return; } var s0 :| s0 in S; var Sr := S - {s0}; var Tr := T - {AbstractifyEndPointToNodeIdentity(s0)}; assert |S| == |Sr| + 1; assert |T| == |Tr| + 1; lemma_AbstractifyEndPointToNodeIdentity_injective_forall(); lemma_sets_cardinality_EndPoint(Sr, Tr); } lemma lemma_AbstractifyEndPointsToNodeIdentities_properties(endpoints:seq) requires SeqIsUnique(endpoints) requires SeqOfEndPointsIsAbstractable(endpoints) ensures |AbstractifyEndPointsToNodeIdentities(endpoints)| == |endpoints| ensures forall e :: e in endpoints ==> AbstractifyEndPointToNodeIdentity(e) in AbstractifyEndPointsToNodeIdentities(endpoints) ensures forall e :: EndPointIsAbstractable(e) ==> (e in endpoints <==> AbstractifyEndPointToNodeIdentity(e) in AbstractifyEndPointsToNodeIdentities(endpoints)) { forall e | EndPointIsAbstractable(e) ensures e in endpoints <==> AbstractifyEndPointToNodeIdentity(e) in AbstractifyEndPointsToNodeIdentities(endpoints) { if e in endpoints { assert AbstractifyEndPointToNodeIdentity(e) in AbstractifyEndPointsToNodeIdentities(endpoints); } if AbstractifyEndPointToNodeIdentity(e) in AbstractifyEndPointsToNodeIdentities(endpoints) { lemma_AbstractifyEndPointToNodeIdentity_injective_forall(); assert e in endpoints; } } } lemma lemma_AbstractifyEndPointsToNodeIdentities_injective_elements(s1:seq, s2:seq) requires forall e :: e in s1 ==> EndPointIsAbstractable(e) requires forall e :: e in s2 ==> EndPointIsAbstractable(e) requires AbstractifyEndPointsToNodeIdentities(s1) == AbstractifyEndPointsToNodeIdentities(s2) ensures forall e :: e in s1 <==> e in s2 { reveal AbstractifyEndPointsToNodeIdentities(); lemma_AbstractifyEndPointToNodeIdentity_injective_forall(); } lemma lemma_AbstractifyEndPointsToNodeIdentities_injective(s1:seq, s2:seq) requires forall e :: e in s1 ==> EndPointIsAbstractable(e) requires forall e :: e in s2 ==> EndPointIsAbstractable(e) requires AbstractifyEndPointsToNodeIdentities(s1) == AbstractifyEndPointsToNodeIdentities(s2) ensures s1 == s2; { reveal AbstractifyEndPointsToNodeIdentities(); lemma_AbstractifyEndPointToNodeIdentity_injective_forall(); } ////////////////////////////////////////////////////////// // Reversing the process of refining a node identity ////////////////////////////////////////////////////////// predicate NodeIdentityIsRefinable(id:NodeIdentity) { true } // Give Dafny a symbol handle for this choose (:|) expression function{:opaque} RefineNodeIdentityToEndPoint(id:NodeIdentity) : EndPoint ensures NodeIdentityIsRefinable(id) ==> EndPointIsAbstractable(RefineNodeIdentityToEndPoint(id)) ensures NodeIdentityIsRefinable(id) ==> AbstractifyEndPointToNodeIdentity(RefineNodeIdentityToEndPoint(id)) == id { id } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/Common/SeqIsUnique.i.dfy ================================================ include "SeqIsUniqueDef.i.dfy" include "../../Common/Native/NativeTypes.i.dfy" module Common__SeqIsUnique_i { import opened Common__SeqIsUniqueDef_i import opened Native__NativeTypes_i function UniqueSeqToSet(xs:seq) : set requires SeqIsUnique(xs) ensures forall x :: x in xs ==> x in UniqueSeqToSet(xs) { set x | x in xs } function{:timeLimitMultiplier 3}{:opaque} SetToUniqueSeq(s:set):seq ensures forall x :: x in SetToUniqueSeq(s) <==> x in s ensures SeqIsUnique(SetToUniqueSeq(s)) ensures |SetToUniqueSeq(s)| == |s| { if s == {} then ( var xs:seq := []; calc ==> {true; { reveal SeqIsUnique(); } SeqIsUnique(xs);} xs ) else ( var x :| x in s; var s' := s - {x}; var xs' := SetToUniqueSeq(s'); calc ==> {true; { reveal SeqIsUnique(); } SeqIsUnique(xs' + [x]);} xs' + [x] ) } function/*TODO:{:opaque}*/ Subsequence(xs:seq, f:X->bool):seq reads f.reads requires forall x :: x in xs ==> f.requires(x) ensures forall x :: x in Subsequence(xs, f) <==> x in xs && f(x) // TODO: ensures |Subsequence(xs, f)| <= |xs| { var s := set x | x in xs && f(x); SetToUniqueSeq(s) } method SeqToSetConstruct(xs:seq) returns(s:set) ensures forall x :: x in s <==> x in xs ensures SeqIsUnique(xs) ==> |s| == |xs| && s == UniqueSeqToSet(xs) { reveal SeqIsUnique(); s := {}; var i := 0; while (i < |xs|) invariant 0 <= i <= |xs| invariant forall x :: x in s <==> x in xs[..i] invariant SeqIsUnique(xs[..i]) ==> |s| == i { s := s + {xs[i]}; i := i + 1; } } method{:timeLimitMultiplier 5} SetToUniqueSeqConstruct(s:set) returns (xs:seq) ensures SeqIsUnique(xs) ensures UniqueSeqToSet(xs) == s ensures forall x :: x in xs <==> x in s ensures |xs| == |s| { var arr := new X[|s|]; var s1 := s; ghost var s2 := {}; ghost var i := 0; forall ensures SeqIsUnique(arr[..i]) { reveal SeqIsUnique(); } while (|s1| != 0) invariant 0 <= i <= |s| invariant s1 + s2 == s invariant s1 !! s2 invariant |s1| == |s| - i invariant |s2| == i invariant SeqIsUnique(arr[..i]) invariant forall x :: x in arr[..i] <==> x in s2 { reveal SeqIsUnique(); ghost var old_seq := arr[..i]; var x :| x in s1; assert x !in old_seq; assert forall y {:trigger y in s2}{:trigger y in old_seq} :: y in s2 + {x} ==> y in old_seq + [x]; arr[|s| - |s1|] := x; s1 := s1 - {x}; s2 := s2 + {x}; i := i + 1; assert arr[..i] == old_seq + [x]; } xs := arr[..]; assert xs == arr[..i]; } method SubsequenceConstruct(xs:seq, f:X->bool) returns(xs':seq) requires forall x :: x in xs ==> f.requires(x) ensures forall x {:trigger x in xs}{:trigger x in xs'} :: x in xs' <==> x in xs && f(x) ensures SeqIsUnique(xs) ==> SeqIsUnique(xs') { reveal SeqIsUnique(); var arr := new X[|xs|]; var i := 0; var j := 0; while (i < |xs|) invariant 0 <= i <= |xs| invariant 0 <= j <= i invariant forall x {:trigger x in xs[..i]}{:trigger x in arr[..j]} :: x in arr[..j] <==> x in xs[..i] && f(x) invariant SeqIsUnique(xs) ==> SeqIsUnique(arr[..j]) { ghost var old_xs := xs[..i]; ghost var old_xs' := arr[..j]; if (f(xs[i])) { if (SeqIsUnique(xs)) { reveal SeqIsUnique(); assert forall k :: 0 <= k < i ==> xs[k] != xs[i]; assert forall k :: 0 <= k < i ==> xs[..i][k] != xs[i]; assert xs[i] !in arr[..j]; } arr[j] := xs[i]; j := j + 1; assert arr[..j] == old_xs' + [xs[i]]; } i := i + 1; assert xs[..i] == old_xs + [xs[i - 1]]; } xs' := arr[..j]; } method UniqueSubsequenceConstruct(xs:seq, f:X->bool) returns(xs':seq) requires forall x :: x in xs ==> f.requires(x) ensures forall x {:trigger x in xs}{:trigger x in xs'} :: x in xs' <==> x in xs && f(x) ensures SeqIsUnique(xs') { var s := set x | x in xs && f(x); xs' := SetToUniqueSeqConstruct(s); } lemma EstablishAppendToUniqueSeq(xs:seq, x:X, xs':seq) requires SeqIsUnique(xs) requires x !in xs requires xs' == xs + [x] ensures SeqIsUnique(xs') ensures x in xs' { var xs'' := xs + [x]; reveal SeqIsUnique(); assert SeqIsUnique(xs''); } function method AppendToUniqueSeq(xs:seq, x:X):seq requires SeqIsUnique(xs) requires x !in xs ensures SeqIsUnique(AppendToUniqueSeq(xs, x)) ensures x in AppendToUniqueSeq(xs, x) { reveal SeqIsUnique(); var xs' := xs + [x]; EstablishAppendToUniqueSeq(xs, x, xs'); xs' } function method AppendToUniqueSeqMaybe(xs:seq, x:X):seq requires SeqIsUnique(xs) ensures SeqIsUnique(AppendToUniqueSeqMaybe(xs, x)) ensures x in AppendToUniqueSeqMaybe(xs, x) { reveal SeqIsUnique(); if x in xs then xs else ( var xs' := xs + [x]; EstablishAppendToUniqueSeq(xs, x, xs'); xs' ) } lemma lemma_UniqueSeq_SubSeqsUnique(whole:seq, left:seq, right:seq) requires SeqIsUnique(whole) requires whole == left + right ensures SeqIsUnique(left) ensures SeqIsUnique(right) { reveal SeqIsUnique(); assert SeqIsUnique(whole[..|left|]); } lemma lemma_seqs_set_cardinality(Q:seq, S:set) requires SeqIsUnique(Q) requires S == UniqueSeqToSet(Q) ensures |Q| == |S| { reveal SeqIsUnique(); if (Q==[]) { return; } var q0 := Q[0]; var Qr := Q[1..]; var Sr := UniqueSeqToSet(Qr); forall s | s in Sr + {q0} ensures s in S; { if (s in Sr) { var idx :| 0<=idx<|Qr| && Qr[idx]==s; assert Q[idx+1]==s; assert Q[idx+1] in Q; assert s in S; } else { assert s == q0; assert Q[0] == s; assert Q[0] in Q; assert s in S; } } forall s | s in S ensures s in Sr + {q0}; { var idx :| 0<=idx<|Q| && Q[idx]==s; if (idx==0) { assert Q[0] == q0; } else { assert s == Qr[idx-1]; assert Qr[idx-1] in Qr; assert s in Qr; assert s in Sr; } assert s in Sr + {q0}; } assert S == Sr + {q0}; lemma_seqs_set_cardinality(Qr, Sr); } lemma lemma_seqs_set_membership(Q:seq, S:set) requires SeqIsUnique(Q) requires S == UniqueSeqToSet(Q) ensures forall i :: (i in Q <==> i in S) { reveal SeqIsUnique(); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/Common/SeqIsUniqueDef.i.dfy ================================================ module Common__SeqIsUniqueDef_i { predicate {:opaque} SeqIsUnique(xs:seq) { forall i,j :: 0 <= i < |xs| && 0 <= j < |xs| && xs[i] == xs[j] ==> i == j } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/Common/UpperBound.i.dfy ================================================ include "../../Common/Native/NativeTypes.s.dfy" include "../../Protocol/Common/UpperBound.s.dfy" module Common__UpperBound_i { import opened Native__NativeTypes_s import opened Common__UpperBound_s method UpperBoundedAdditionImpl(x:uint64, y:uint64, u:uint64) returns (sum:uint64) ensures sum as int == UpperBoundedAddition(x as int, y as int, UpperBoundFinite(u as int)); { if y >= u { sum := u; } else if x >= u - y { sum := u; } else { sum := x + y; } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/Common/Util.i.dfy ================================================ include "../../Common/Native/NativeTypes.i.dfy" include "../../Common/Native/Io.s.dfy" include "../../../Libraries/Math/power2.i.dfy" module Common__Util_i { import opened Native__Io_s import opened Native__NativeTypes_s import opened Native__NativeTypes_i import opened Math__power2_s import opened Math__power2_i import opened Math__div_i // Uses BigIntegers. If you can, consider using the Opt versions below method seqToArray_slow(s:seq) returns(a:array) ensures a[..] == s { var len := |s|; a := new A[len]; var i := 0; while (i < len) invariant 0 <= i <= len invariant a[..i] == s[..i] { a[i] := s[i]; i := i + 1; } } // Uses BigIntegers. If you can, consider using the Opt versions below /* method seqIntoArray_slow(s:seq, a:array, index:nat) requires a != null requires index + |s| <= a.Length modifies a ensures a[..] == old(a[0..index]) + s + old(a[index + |s|..]) { var i := index; while (i < index + |s|) invariant index <= i <= index + |s| <= a.Length invariant a[..] == old(a[0..index]) + s[0..(i-index)] + old(a[i..]) { a[i] := s[i - index]; i := i + 1; assert a[..] == old(a[0..index]) + s[0..(i-index)] + old(a[i..]); } } */ method seqIntoArrayOpt(s:seq, a:array) requires |s| == a.Length requires |s| < 0x1_0000_0000_0000_0000 modifies a ensures a[..] == s { var i:uint64 := 0; while i < |s| as uint64 invariant 0 <= i as int <= a.Length invariant a[..] == s[0..i] + old(a[i..]) { a[i] := s[i]; i := i + 1; } } method seqToArrayOpt(s:seq) returns(a:array) requires |s| < 0x1_0000_0000_0000_0000 ensures a[..] == s ensures fresh(a) { a := new A[|s| as uint64]; seqIntoArrayOpt(s, a); } method seqIntoArrayChar(s:seq, a:array) requires |s| == a.Length requires |s| < 0x1_0000_0000_0000_0000 modifies a ensures a[..] == s { var i:uint64 := 0; while i < |s| as uint64 invariant 0 <= i as int <= a.Length invariant a[..] == s[0..i] + old(a[i..]) { a[i] := s[i]; i := i + 1; } } method RecordTimingSeq(name:seq, start:uint64, end:uint64) requires 0 < |name| < 0x1_0000_0000_0000_0000 { if PrintParams.ShouldPrintProfilingInfo() { var name_array := new char[|name|]; seqIntoArrayChar(name, name_array); var time:uint64; if start <= end { time := end - start; } else { time := 0xFFFF_FFFF_FFFF_FFFF; } Time.RecordTiming(name_array, time); } } function BEByteSeqToInt(bytes:seq) : int decreases |bytes| { if bytes == [] then 0 else BEByteSeqToInt(bytes[..|bytes|-1]) * 256 + (bytes[|bytes|-1] as int) } lemma lemma_BEByteSeqToInt_bound(bytes:seq) ensures 0 <= BEByteSeqToInt(bytes) ensures BEByteSeqToInt(bytes) < power2(8*|bytes|) { lemma_2toX(); if bytes == [] { } else { calc { BEByteSeqToInt(bytes[..|bytes|-1]) + 1; <= power2(8*(|bytes|-1)); } calc { BEByteSeqToInt(bytes); BEByteSeqToInt(bytes[..|bytes|-1]) * 256 + (bytes[|bytes|-1] as int); < BEByteSeqToInt(bytes[..|bytes|-1]) * 256 + 256; BEByteSeqToInt(bytes[..|bytes|-1]) * 256 + 1 * 256; (BEByteSeqToInt(bytes[..|bytes|-1]) + 1) * 256; <= power2(8*(|bytes|-1)) * 256; power2(8*(|bytes|-1)) * power2(8); { lemma_power2_adds(8*(|bytes|-1), 8); } power2(8*|bytes|); } } } /* Doesn't appear to be in use at present lemma lemma_BEByteSeqToUint32_properties(bs:seq) requires |bs| == Uint32Size() as int ensures var ret := uint32(bs[0]) * 256*256*256 + uint32(bs[1]) * 256*256 + uint32(bs[2]) * 256 + uint32(bs[3]); ret as int == BEByteSeqToInt(bs) { lemma_2toX(); lemma_BEByteSeqToInt_bound(bs); var ret := uint32(bs[0]) * 256*256*256 + uint32(bs[1]) * 256*256 + uint32(bs[2]) * 256 + uint32(bs[3]); calc { BEByteSeqToInt(bs); BEByteSeqToInt(bs[..|bs|-1]) * 256 + (bs[|bs|-1] as int); { assert bs[..|bs|-1][..|bs[..|bs|-1]|-1] == bs[..|bs|-2]; } (BEByteSeqToInt(bs[..|bs|-2]) * 256 + (bs[|bs|-2] as int)) * 256 + (bs[|bs|-1] as int); ((BEByteSeqToInt(bs[..|bs|-3]) * 256 + (bs[|bs|-3] as int)) * 256 + (bs[|bs|-2] as int)) * 256 + (bs[|bs|-1] as int); (((BEByteSeqToInt(bs[..|bs|-4]) * 256 + (bs[|bs|-4] as int)) * 256 + (bs[|bs|-3] as int)) * 256 + (bs[|bs|-2] as int)) * 256 + (bs[|bs|-1] as int); ret as int; } } */ lemma lemma_BEByteSeqToUint64_properties(bs:seq) requires |bs| == Uint64Size() as int ensures var ret := (bs[0] as uint64) * 256*256*256*0x100000000 + (bs[1] as uint64) * 256*256*0x100000000 + (bs[2] as uint64) * 256*0x100000000 + (bs[3] as uint64) * 0x100000000 + (bs[4] as uint64) * 256*256*256 + (bs[5] as uint64) * 256*256 + (bs[6] as uint64) * 256 + (bs[7] as uint64); ret as int == BEByteSeqToInt(bs) { lemma_2toX(); var ret := (bs[0] as uint64) * 256*256*256*0x100000000 + (bs[1] as uint64) * 256*256*0x100000000 + (bs[2] as uint64) * 256*0x100000000 + (bs[3] as uint64) * 0x100000000 + (bs[4] as uint64) * 256*256*256 + (bs[5] as uint64) * 256*256 + (bs[6] as uint64) * 256 + (bs[7] as uint64); var byteSeq := bs; calc { BEByteSeqToInt(bs); BEByteSeqToInt(bs[..|bs|-1]) * 256 + (bs[|bs|-1] as int); { assert bs[..|bs|-1][..|bs[..|bs|-1]|-1] == bs[..|bs|-2]; } (BEByteSeqToInt(bs[..|bs|-2]) * 256 + (bs[|bs|-2] as int)) * 256 + (bs[|bs|-1] as int); { assert bs[..|bs|-2][..|bs[..|bs|-2]|-1] == bs[..|bs|-3]; } ((BEByteSeqToInt(bs[..|bs|-3]) * 256 + (bs[|bs|-3] as int)) * 256 + (bs[|bs|-2] as int)) * 256 + (bs[|bs|-1] as int); { assert bs[..|bs|-3][..|bs[..|bs|-3]|-1] == bs[..|bs|-4]; } (((BEByteSeqToInt(bs[..|bs|-4]) * 256 + (bs[|bs|-4] as int)) * 256 + (bs[|bs|-3] as int)) * 256 + (bs[|bs|-2] as int)) * 256 + (bs[|bs|-1] as int); { assert bs[..|bs|-4][..|bs[..|bs|-4]|-1] == bs[..|bs|-5]; } ((((BEByteSeqToInt(bs[..|bs|-5]) * 256 + (bs[|bs|-5] as int)) * 256 + (bs[|bs|-4] as int)) * 256 + (bs[|bs|-3] as int)) * 256 + (bs[|bs|-2] as int)) * 256 + (bs[|bs|-1] as int); { assert bs[..|bs|-5][..|bs[..|bs|-5]|-1] == bs[..|bs|-6]; } (((((BEByteSeqToInt(bs[..|bs|-6]) * 256 + (bs[|bs|-6] as int)) * 256 + (bs[|bs|-5] as int)) * 256 + (bs[|bs|-4] as int)) * 256 + (bs[|bs|-3] as int)) * 256 + (bs[|bs|-2] as int)) * 256 + (bs[|bs|-1] as int); { assert bs[..|bs|-6][..|bs[..|bs|-6]|-1] == bs[..|bs|-7]; } ((((((BEByteSeqToInt(bs[..|bs|-7]) * 256 + (bs[|bs|-7] as int)) * 256 + (bs[|bs|-6] as int)) * 256 + (bs[|bs|-5] as int)) * 256 + (bs[|bs|-4] as int)) * 256 + (bs[|bs|-3] as int)) * 256 + (bs[|bs|-2] as int)) * 256 + (bs[|bs|-1] as int); (((((((BEByteSeqToInt(bs[..|bs|-8]) * 256 + (bs[|bs|-8] as int)) * 256 + (bs[|bs|-7] as int)) * 256 + (bs[|bs|-6] as int)) * 256 + (bs[|bs|-5] as int)) * 256 + (bs[|bs|-4] as int)) * 256 + (bs[|bs|-3] as int)) * 256 + (bs[|bs|-2] as int)) * 256 + (bs[|bs|-1] as int); ret as int; } } /* Doesn't appear to be in use at present function method BEByteSeqToUint32(bs:seq) : uint32 requires |bs| == Uint32Size() as int ensures 0 <= BEByteSeqToInt(SeqByteToByteSeq(bs)) < 0x100000000 // Need for the cast on the next line ensures BEByteSeqToUint32(bs) == BEByteSeqToInt(SeqByteToByteSeq(bs)) as uint32 { lemma_2toX(); //byteIsUint32_forall(); //byteIsUint32(bs[0]); byteIsUint32(bs[1]); byteIsUint32(bs[2]); byteIsUint32(bs[3]); //byteIsByte(bs[0]); byteIsByte(bs[1]); byteIsByte(bs[2]); byteIsByte(bs[3]); //byteTimes0x100IsWord(bs[2]); byteTimes0x10000IsWord(bs[1]); byteTimes0x1000000IsWord(bs[0]); lemma_BEByteSeqToUint32_properties(bs); uint32(bs[0]) * 256*256*256 + uint32(bs[1]) * 256*256 + uint32(bs[2]) * 256 + uint32(bs[3]) } */ // renamed from BEByteSeqToUint64 to SeqByteToUint64 // "BEByteSeq" is a seq with a byte precondition constraint, to // access the generic pv library. // So let's have SeqByte be a Dafny seq. function method SeqByteToUint64(bs:seq) : uint64 requires |bs| == Uint64Size() as int ensures 0 <= BEByteSeqToInt(bs) < 0x10000000000000000 // Need for the cast on the next line ensures SeqByteToUint64(bs) == BEByteSeqToInt(bs) as uint64 { lemma_2toX(); lemma_BEByteSeqToUint64_properties(bs); (bs[0] as uint64) * 256*256*256*0x100000000 + (bs[1] as uint64) * 256*256*0x100000000 + (bs[2] as uint64) * 256*0x100000000 + (bs[3] as uint64) * 0x100000000 + (bs[4] as uint64) * 256*256*256 + (bs[5] as uint64) * 256*256 + (bs[6] as uint64) * 256 + (bs[7] as uint64) } function BEUintToSeqByte(v:int, width:int) : seq ensures width >= 0 && v >= 0 ==> |BEUintToSeqByte(v, width)| == width { if width > 0 && v >= 0 then BEUintToSeqByte(v/0x100, width - 1) + [ (v % 0x100) as byte ] else [] } lemma lemma_BEUintToSeqByte_invertability(bytes:seq, val:int, width:nat) requires bytes == BEUintToSeqByte(val, width) requires 0 <= val < power2(8*width) requires |bytes| == width ensures BEByteSeqToInt(bytes) == val { lemma_2toX32(); if width == 0 { assert BEUintToSeqByte(val, width) == []; assert power2(width) == 1; assert val == 0; } else { calc { val / 0x100; < { lemma_power2_adds(8*width-8, 8); lemma_div_by_multiple_is_strongly_ordered(val, power2(8*width), power2(8*width-8), power2(8)); } power2(8*width) / 0x100; power2(8*width) / power2(8); { lemma_power2_div_is_sub(8, 8*width); } power2(8*(width - 1)); } calc { BEByteSeqToInt(bytes); BEByteSeqToInt(bytes[..|bytes|-1]) * 256 + (bytes[|bytes|-1] as int); { lemma_BEUintToSeqByte_invertability(bytes[..|bytes|-1], val / 0x100, width - 1); } (val / 0x100) * 256 + (bytes[|bytes|-1] as int); val; } } } lemma lemma_BEByteSeqToInt_invertability(bytes:seq, val:int, width:nat) requires BEByteSeqToInt(bytes) == val requires 0 <= val < power2(8*width) requires |bytes| == width ensures bytes == BEUintToSeqByte(val, width) { lemma_2toX32(); if width == 0 { assert BEUintToSeqByte(val, width) == []; assert power2(width) == 1; assert val == 0; } else { calc { val / 0x100; < { lemma_power2_adds(8*width-8, 8); lemma_div_by_multiple_is_strongly_ordered(val, power2(8*width), power2(8*width-8), power2(8)); } power2(8*width) / 0x100; power2(8*width) / power2(8); { lemma_power2_div_is_sub(8, 8*width); } power2(8*(width - 1)); } calc { BEUintToSeqByte(val, width); BEUintToSeqByte(val/0x100, width - 1) + [ (val % 0x100) as byte ]; { lemma_BEByteSeqToInt_invertability(bytes[..|bytes|-1], val / 0x100, width - 1); } bytes[..|bytes|-1] + [ (val % 0x100) as byte ]; bytes[..|bytes|-1] + [ bytes[|bytes|-1] ]; bytes; } } } lemma lemma_BEByteSeqToInt_BEUintToSeqByte_invertability() ensures forall bytes:seq, width:nat :: |bytes| == width ==> bytes == BEUintToSeqByte(BEByteSeqToInt(bytes), width) ensures forall val:int, width:nat :: 0 <= val < power2(8*width) ==> val == BEByteSeqToInt(BEUintToSeqByte(val, width)) { forall bytes:seq, width:nat | |bytes| == width ensures bytes == BEUintToSeqByte(BEByteSeqToInt(bytes), width) { lemma_BEByteSeqToInt_bound(bytes); lemma_BEByteSeqToInt_invertability(bytes, BEByteSeqToInt(bytes), width); } forall val:int, width:nat | 0 <= val < power2(8*width) ensures val == BEByteSeqToInt(BEUintToSeqByte(val, width)) { lemma_BEUintToSeqByte_invertability(BEUintToSeqByte(val, width), val, width); } } function method Uint64ToSeqByte(u:uint64) : seq ensures Uint64ToSeqByte(u) == BEUintToSeqByte(u as int, 8) { ghost var pv := 256; var bs := [ (u/0x100000000000000) as byte, ((u/ 0x1000000000000) % 0x100) as byte, ((u/ 0x10000000000) % 0x100) as byte, ((u/ 0x100000000) % 0x100) as byte, ((u/ 0x1000000) % 0x100) as byte, ((u/ 0x10000) % 0x100) as byte, ((u/ 0x100) % 0x100) as byte, ((u ) % 0x100) as byte ]; lemma_2toX(); var u_int := u as int; calc { BEUintToSeqByte(u_int, 8); BEUintToSeqByte(u_int/0x100, 7) + [ (u_int % 0x100) as byte ]; BEUintToSeqByte((u_int/0x100/0x100), 6) + [ ((u_int/0x100) % 0x100) as byte ] + [ (u_int % 0x100) as byte ]; { lemma_div_denominator(u_int as int, 0x100, 0x100); } BEUintToSeqByte((u_int/0x10000), 6) + [ ((u_int/0x100) % 0x100) as byte ] + [ (u_int % 0x100) as byte ]; { lemma_div_denominator(u_int as int, 0x10000, 0x100); } BEUintToSeqByte(u_int/0x1000000, 5) + [ ((u_int / 0x10000) % 0x100) as byte ] + [ ((u_int/0x100) % 0x100) as byte ] + [ (u_int % 0x100) as byte ]; { lemma_div_denominator(u_int as int, 0x1000000, 0x100); } BEUintToSeqByte(u_int/0x100000000, 4) + [ ((u_int / 0x1000000) % 0x100) as byte ] + [ ((u_int / 0x10000) % 0x100) as byte ] + [ ((u_int/0x100) % 0x100) as byte ] + [ (u_int % 0x100) as byte ]; { lemma_div_denominator(u_int as int, 0x100000000, 0x100); } BEUintToSeqByte(u_int/0x10000000000, 3) + [ ((u_int / 0x100000000) % 0x100) as byte ] + [ ((u_int / 0x1000000) % 0x100) as byte ] + [ ((u_int / 0x10000) % 0x100) as byte ] + [ ((u_int/0x100) % 0x100) as byte ] + [ (u_int % 0x100) as byte ]; { lemma_div_denominator(u_int as int, 0x10000000000, 0x100); } BEUintToSeqByte(u_int/0x1000000000000, 2) + [ ((u_int / 0x10000000000) % 0x100) as byte ] + [ ((u_int / 0x100000000) % 0x100) as byte ] + [ ((u_int / 0x1000000) % 0x100) as byte ] + [ ((u_int / 0x10000) % 0x100) as byte ] + [ ((u_int/0x100) % 0x100) as byte ] + [ (u_int % 0x100) as byte ]; { lemma_div_denominator(u_int as int, 0x1000000000000, 0x100); } BEUintToSeqByte(u_int/0x100000000000000, 1) + [ ((u_int / 0x1000000000000) % 0x100) as byte ] + [ ((u_int / 0x10000000000) % 0x100) as byte ] + [ ((u_int / 0x100000000) % 0x100) as byte ] + [ ((u_int / 0x1000000) % 0x100) as byte ] + [ ((u_int / 0x10000) % 0x100) as byte ] + [ ((u_int/0x100) % 0x100) as byte ] + [ (u_int % 0x100) as byte ]; { lemma_div_denominator(u_int as int, 0x100000000000000, 0x100); } BEUintToSeqByte(u_int/0x10000000000000000, 0) + [ ((u_int / 0x100000000000000) % 0x100) as byte ] + [ ((u_int / 0x1000000000000) % 0x100) as byte ] + [ ((u_int / 0x10000000000) % 0x100) as byte ] + [ ((u_int / 0x100000000) % 0x100) as byte ] + [ ((u_int / 0x1000000) % 0x100) as byte ] + [ ((u_int / 0x10000) % 0x100) as byte ] + [ ((u_int/0x100) % 0x100) as byte ] + [ (u_int % 0x100) as byte ]; } bs } function method SeqByteToUint16(bs:seq) : uint16 requires |bs| == Uint16Size() as int ensures 0 <= BEByteSeqToInt(bs) < 0x10000000000000000 // Need for the cast on the next line ensures BEByteSeqToInt(bs) < 0x10000 ensures SeqByteToUint16(bs) == BEByteSeqToInt(bs) as uint16 { lemma_2toX(); lemma_BEByteSeqToInt_bound(bs); (bs[0] as uint16) * 256 + (bs[1] as uint16) } function method Uint16ToSeqByte(u:uint16) : seq ensures Uint16ToSeqByte(u) == BEUintToSeqByte(u as int, 2) { ghost var pv := 256; var s := [ ((u/0x100) % 0x100) as byte, ((u ) % 0x100) as byte ]; lemma_2toX(); var u_int := u as int; calc { BEUintToSeqByte(u_int, 2); BEUintToSeqByte(u_int/0x100, 1) + [ (u_int % 0x100) as byte ]; BEUintToSeqByte((u_int/0x100/0x100), 0) + [ ((u_int/0x100) % 0x100) as byte ] + [ (u_int % 0x100) as byte ]; { lemma_div_denominator(u_int as int, 0x100, 0x100); } BEUintToSeqByte((u_int/0x10000), 0) + [ ((u_int/0x100) % 0x100) as byte ] + [ (u_int % 0x100) as byte ]; } s } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/LiveSHT/CmdLineParser.i.dfy ================================================ include "../Common/CmdLineParser.i.dfy" include "../SHT/ConstantsState.i.dfy" module ShtCmdLineParser_i { import opened Native__NativeTypes_s import opened Native__Io_s import opened CmdLineParser_i import opened SHT__ConstantsState_i import opened Impl_Parameters_i import opened Common__NetClient_i import opened Common__SeqIsUniqueDef_i import opened Common__NodeIdentity_i function EndPointNull () : EndPoint { EndPoint([]) } function ConstantsStateNull () : ConstantsState { ConstantsState(EndPointNull(), [], StaticParams()) } function sht_cmd_line_parsing(args:seq>) : ConstantsState { var (ok, endpoints) := parse_end_points(args); if !ok then ConstantsStateNull() else ConstantsState(if |endpoints| > 0 then endpoints[0] else EndPointNull(), // Root is the first endpoint in the list endpoints, StaticParams()) } function sht_parse_id(arg:seq) : EndPoint { var (ok, ep) := parse_end_point(arg); ep } method GetHostIndex(host:EndPoint, hosts:seq) returns (found:bool, index:uint64) requires EndPointIsValidPublicKey(host) requires SeqIsUnique(hosts) requires |hosts| < 0x1_0000_0000_0000_0000 requires forall h :: h in hosts ==> EndPointIsValidPublicKey(h) ensures found ==> 0 <= index as int < |hosts| && hosts[index] == host ensures !found ==> !(host in hosts) ensures !found ==> !(AbstractifyEndPointToNodeIdentity(host) in AbstractifyEndPointsToNodeIdentities(hosts)) { var i:uint64 := 0; lemma_AbstractifyEndPointsToNodeIdentities_properties(hosts); while i < |hosts| as uint64 invariant i as int <= |hosts|; invariant forall j :: 0 <= j < i ==> hosts[j] != host; { if host == hosts[i] { found := true; index := i; calc ==> { true; { reveal_SeqIsUnique(); } forall j :: 0 <= j < |hosts| && j != i as int ==> hosts[j] != host; } return; } if i == |hosts| as uint64 - 1 { found := false; return; } i := i + 1; } found := false; } method parse_cmd_line(id:EndPoint, args:seq>) returns (ok:bool, config:ConstantsState, my_index:uint64) requires EndPointIsValidPublicKey(id) ensures ok ==> && ConstantsStateIsValid(config) && 0 <= my_index as int < |config.hostIds| && config == sht_cmd_line_parsing(args) && config.hostIds[my_index] == id { var tuple1 := parse_end_points(args); ok := tuple1.0; var endpoints := tuple1.1; if !ok || |endpoints| >= 0xffff_ffff_ffff_ffff { ok := false; return; } var unique := test_unique(endpoints); if !unique { ok := false; return; } ok, my_index := GetHostIndex(id, endpoints); if !ok { return; } var root_identity := endpoints[0]; config := ConstantsState(root_identity, endpoints, StaticParams()); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/LiveSHT/Host.i.dfy ================================================ include "../../Common/Framework/Host.s.dfy" include "SchedulerImpl.i.dfy" include "CmdLineParser.i.dfy" module Host_i refines Host_s { import opened Collections__Sets_i import opened Common__NodeIdentity_i import opened Impl_Parameters_i import opened SHT__ConstantsState_i import opened LiveSHT__Environment_i import opened LiveSHT__Scheduler_i import opened LiveSHT__SchedulerImpl_i import opened LiveSHT__NetSHT_i import opened LiveSHT__Unsendable_i import opened CmdLineParser_i import opened ShtCmdLineParser_i export Spec provides Native__Io_s, Environment_s, Native__NativeTypes_s provides HostState provides ConcreteConfiguration provides HostInit, HostNext, ConcreteConfigInit, HostStateInvariants, ConcreteConfigToServers provides ParseCommandLineConfiguration, ArbitraryObject provides HostInitImpl, HostNextImpl export All reveals * datatype CScheduler = CScheduler(ghost sched:LScheduler, scheduler_impl:SchedulerImpl?) type HostState = CScheduler type ConcreteConfiguration = ConstantsState predicate HostStateInvariants(host_state:HostState, env:HostEnvironment) { host_state.scheduler_impl != null && host_state.scheduler_impl.Valid() && host_state.scheduler_impl.Env() == env && host_state.sched == host_state.scheduler_impl.AbstractifyToLScheduler() } predicate HostInit(host_state:HostState, config:ConcreteConfiguration, id:EndPoint) { host_state.scheduler_impl != null && host_state.scheduler_impl.Valid() && host_state.scheduler_impl.host.constants == config && host_state.scheduler_impl.host.me == id && LScheduler_Init(host_state.sched, AbstractifyEndPointToNodeIdentity(host_state.scheduler_impl.host.me), AbstractifyEndPointToNodeIdentity(config.rootIdentity), AbstractifyEndPointsToNodeIdentities(config.hostIds), AbstractifyCParametersToParameters(config.params)) } predicate HostNext(host_state:HostState, host_state':HostState, ios:seq>>) { NetEventLogIsAbstractable(ios) && OnlySentMarshallableData(ios) && ( LScheduler_Next(host_state.sched, host_state'.sched, AbstractifyRawLogToIos(ios)) || HostNextIgnoreUnsendable(host_state.sched, host_state'.sched, ios)) } predicate ConcreteConfigInit(config:ConcreteConfiguration) { ConstantsStateIsValid(config) && config.rootIdentity in config.hostIds //&& (forall i :: 0 <= i < |config.hostIds| ==> c } function ConcreteConfigToServers(config:ConcreteConfiguration) : set { MapSeqToSet(config.hostIds, x=>x) } function ParseCommandLineConfiguration(args:seq>) : ConcreteConfiguration { sht_cmd_line_parsing(args) } method {:timeLimitMultiplier 4} HostInitImpl( ghost env:HostEnvironment, netc:NetClient, args:seq> ) returns ( ok:bool, host_state:HostState ) { var config:ConstantsState, my_index:uint64; var id := EndPoint(netc.MyPublicKey()); ok, config, my_index := parse_cmd_line(id, args); if !ok { return; } assert config.hostIds[my_index] in config.hostIds; var scheduler := new SchedulerImpl(); // calc { // constants.myIndex as int; // { reveal_SeqIsUnique(); } // my_index as int; // } assert env.Valid() && env.ok.ok(); ok := scheduler.Host_Init_Impl(config, my_index, id, netc, env); if !ok { return; } host_state := CScheduler(scheduler.AbstractifyToLScheduler(), scheduler); assert ConcreteConfigInit(config); assert HostInit(host_state, config, id); } predicate EventsConsistent(recvs:seq, clocks:seq, sends:seq) { forall e :: (e in recvs ==> e.LIoOpReceive?) && (e in clocks ==> e.LIoOpReadClock? || e.LIoOpTimeoutReceive?) && (e in sends ==> e.LIoOpSend?) } ghost method RemoveRecvs(events:seq) returns (recvs:seq, rest:seq) ensures forall e :: e in recvs ==> e.LIoOpReceive?; ensures events == recvs + rest; ensures rest != [] ==> !rest[0].LIoOpReceive?; { recvs := []; rest := []; var i := 0; while i < |events| invariant 0 <= i <= |events|; invariant forall e :: e in recvs ==> e.LIoOpReceive?; //invariant events == recvs + events[i..]; invariant recvs == events[0..i]; { if !events[i].LIoOpReceive? { rest := events[i..]; return; } recvs := recvs + [events[i]]; i := i + 1; } } predicate NetEventsReductionCompatible(events:seq) { forall i :: 0 <= i < |events| - 1 ==> events[i].LIoOpReceive? || events[i+1].LIoOpSend? } lemma RemainingEventsAreSends(events:seq) requires NetEventsReductionCompatible(events); requires |events| > 0; requires !events[0].LIoOpReceive?; ensures forall e :: e in events[1..] ==> e.LIoOpSend?; { if |events| == 1 { } else { assert events[1].LIoOpSend?; RemainingEventsAreSends(events[1..]); } } ghost method PartitionEvents(events:seq) returns (recvs:seq, clocks:seq, sends:seq) requires NetEventsReductionCompatible(events); ensures events == recvs + clocks + sends; ensures EventsConsistent(recvs, clocks, sends); ensures |clocks| <= 1; { var rest; recvs, rest := RemoveRecvs(events); assert events[|recvs|..] == rest; if |rest| > 0 && (rest[0].LIoOpReadClock? || rest[0].LIoOpTimeoutReceive?) { clocks := [rest[0]]; sends := rest[1..]; RemainingEventsAreSends(rest); } else { clocks := []; sends := rest; if |rest| > 0 { RemainingEventsAreSends(rest); } } } /*lemma ProtocolIosRespectReduction(s:LScheduler, s':LScheduler, ios:seq) requires LScheduler_Next(s, s', ios); ensures LIoOpSeqCompatibleWithReduction(ios); { }*/ lemma NetEventsRespectReduction(s:LScheduler, s':LScheduler, ios:seq, events:seq) requires LIoOpSeqCompatibleWithReduction(ios); requires RawIoConsistentWithSpecIO(events, ios); ensures NetEventsReductionCompatible(events); { lemma_AbstractifyRawLogToIos_properties(events, ios); assert NetEventsReductionCompatible(events); } method {:timeLimitMultiplier 3} HostNextImpl(ghost env:HostEnvironment, host_state:HostState) returns (ok:bool, host_state':HostState, ghost recvs:seq, ghost clocks:seq, ghost sends:seq, ghost ios:seq>>) { var okay, netEventLog, abstract_ios := host_state.scheduler_impl.Host_Next_main(); if okay { // calc { // Q_LScheduler_Next(host_state.sched, host_state.replica_impl.AbstractifyToLScheduler(), abstract_ios); // { reveal_Q_LScheduler_Next(); } // LScheduler_Next(host_state.sched, host_state.replica_impl.AbstractifyToLScheduler(), abstract_ios); // } assert AbstractifyRawLogToIos(netEventLog) == abstract_ios; if LScheduler_Next(host_state.sched, host_state.scheduler_impl.AbstractifyToLScheduler(), abstract_ios) { //ProtocolIosRespectReduction(host_state.sched, host_state.scheduler_impl.AbstractifyToLScheduler(), abstract_ios); assert LIoOpSeqCompatibleWithReduction(abstract_ios); } NetEventsRespectReduction(host_state.sched, host_state.scheduler_impl.AbstractifyToLScheduler(), abstract_ios, netEventLog); recvs, clocks, sends := PartitionEvents(netEventLog); ios := recvs + clocks + sends; //abstract_ios; assert ios == netEventLog; host_state' := CScheduler(host_state.scheduler_impl.AbstractifyToLScheduler(), host_state.scheduler_impl); } else { recvs := []; clocks := []; sends := []; } ok := okay; } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/LiveSHT/NetSHT.i.dfy ================================================ include "../Common/NetClient.i.dfy" include "../SHT/PacketParsing.i.dfy" include "../../Protocol/LiveSHT/RefinementProof/Environment.i.dfy" include "../SHT/SHTConcreteConfiguration.i.dfy" include "../SHT/CMessage.i.dfy" module LiveSHT__NetSHT_i { import opened Native__NativeTypes_s import opened Native__Io_s import opened Environment_s import opened Common__Util_i import opened Common__NetClient_i import opened Common__NodeIdentity_i import opened SHT__PacketParsing_i import opened LiveSHT__Environment_i import opened SHT__SHTConcreteConfiguration_i import opened SHT__CMessage_i predicate NetEventIsAbstractable(evt:NetEvent) { match evt case LIoOpSend(s) => NetPacketIsAbstractable(s) case LIoOpReceive(r) => NetPacketIsAbstractable(r) case LIoOpTimeoutReceive => true case LIoOpReadClock(t) => true } function AbstractifyNetEventToLSHTIo(evt:NetEvent) : LSHTIo requires NetEventIsAbstractable(evt); { match evt case LIoOpSend(s) => LIoOpSend(AbstractifyNetPacketToLSHTPacket(s)) case LIoOpReceive(r) => LIoOpReceive(AbstractifyNetPacketToLSHTPacket(r)) case LIoOpTimeoutReceive => LIoOpTimeoutReceive() case LIoOpReadClock(t) => LIoOpReadClock(t as int) } predicate NetEventLogIsAbstractable(rawlog:seq) { forall i :: 0<=i<|rawlog| ==> NetEventIsAbstractable(rawlog[i]) } function {:opaque} AbstractifyRawLogToIos(rawlog:seq) : seq requires NetEventLogIsAbstractable(rawlog); ensures |AbstractifyRawLogToIos(rawlog)| == |rawlog|; ensures forall i {:trigger AbstractifyNetEventToLSHTIo(rawlog[i])} {:trigger AbstractifyRawLogToIos(rawlog)[i]} :: 0<=i<|rawlog| ==> AbstractifyRawLogToIos(rawlog)[i] == AbstractifyNetEventToLSHTIo(rawlog[i]); { if (rawlog==[]) then [] else [AbstractifyNetEventToLSHTIo(rawlog[0])] + AbstractifyRawLogToIos(rawlog[1..]) } lemma lemma_AbstractifyRawLogToIos_properties(rawlog:seq, ios:seq) requires NetEventLogIsAbstractable(rawlog); requires |rawlog| == |ios|; requires forall i :: 0<=i<|rawlog| ==> ios[i] == AbstractifyNetEventToLSHTIo(rawlog[i]); ensures AbstractifyRawLogToIos(rawlog) == ios; { reveal_AbstractifyRawLogToIos(); } predicate RawIoConsistentWithSpecIO(rawlog:seq, ios:seq) { NetEventLogIsAbstractable(rawlog) && AbstractifyRawLogToIos(rawlog) == ios } predicate OnlySentMarshallableData(rawlog:seq) { forall io :: io in rawlog && io.LIoOpSend? ==> NetPacketBound(io.s.msg) && CSingleMessageMarshallable(SHTDemarshallData(io.s.msg)) } ////////////////////////////////////////////////////////////////////////////// // These methods wrap the raw NetClient interface // datatype ReceiveResult = RRFail() | RRTimeout() | RRPacket(cpacket:CPacket) method Receive(netClient:NetClient, localAddr:EndPoint) returns (rr:ReceiveResult, ghost netEvent:NetEvent) requires NetClientIsValid(netClient); requires EndPoint(netClient.MyPublicKey()) == localAddr; //requires KnownSendersMatchConfig(config); //requires SHTConcreteConfigurationIsValid(config); modifies NetClientRepr(netClient); ensures netClient.env == old(netClient.env); ensures netClient.MyPublicKey() == old(netClient.MyPublicKey()); ensures NetClientOk(netClient) <==> !rr.RRFail?; ensures old(NetClientRepr(netClient)) == NetClientRepr(netClient); ensures !rr.RRFail? ==> netClient.IsOpen() && old(netClient.env.net.history()) + [netEvent] == netClient.env.net.history(); ensures rr.RRTimeout? ==> netEvent.LIoOpTimeoutReceive?; ensures rr.RRPacket? ==> netEvent.LIoOpReceive? && NetPacketIsAbstractable(netEvent.r) && CPacketIsAbstractable(rr.cpacket) && EndPointIsValidPublicKey(rr.cpacket.src) && AbstractifyCPacketToShtPacket(rr.cpacket) == AbstractifyNetPacketToShtPacket(netEvent.r) && rr.cpacket.msg == SHTDemarshallData(netEvent.r.msg) && (rr.cpacket.dst == localAddr) { var timeout := 0; var ok, timedOut, remote, buffer := netClient.Receive(timeout); if (!ok) { rr := RRFail(); return; } if (timedOut) { rr := RRTimeout(); netEvent := LIoOpTimeoutReceive(); return; } else { var start_time := Time.GetDebugTimeTicks(); var cmessage := SHTDemarshallDataMethod(buffer); var end_time := Time.GetDebugTimeTicks(); var srcEp := EndPoint(remote); var cpacket := CPacket(localAddr, srcEp, cmessage); rr := RRPacket(cpacket); netEvent := LIoOpReceive(LPacket(EndPoint(netClient.MyPublicKey()), srcEp, buffer[..])); forall () ensures AbstractifyCPacketToShtPacket(rr.cpacket) == AbstractifyNetPacketToShtPacket(netEvent.r); //ensures SHTEndPointIsValid(rr.cpacket.src, config); { // Uint64EndPointRelationships(); // assert ConvertEndPointToUint64(srcEp) == rr.cpacket.src; // OBSERVE trigger assert EndPointIsValidPublicKey(EndPoint(netClient.MyPublicKey())); // OBSERVE trigger } } } /* method ReadClock(netClient:NetClient) returns (clock:CBoundedClock, ghost clockEvent:NetEvent) requires NetClientIsValid(netClient); modifies NetClientRepr(netClient); ensures old(NetClientRepr(netClient)) == NetClientRepr(netClient); ensures NetClientIsValid(netClient); ensures netClient.env == old(netClient.env); ensures old(netClient.env.net.history()) + [clockEvent] == netClient.env.net.history(); ensures clockEvent.NetGetTime?; ensures clock.min as int <= clockEvent.time as int <= clock.max as int; ensures NetClientIsValid(netClient); ensures NetEventIsAbstractable(clockEvent); ensures netClient.MyPublicKey() == old(netClient.MyPublicKey()); ensures clock.min==clock.max==clockEvent.time; // silly // ensures clockEvent.ClockEvent(clock_min, clock_max); // TODO we're going to call GetTime, which returns a single value. // Add/subtract the margin of error to make a CBoundedClock. // TODO Jay: if I pretend the margin is 0, how will the verification fail? { var t := Time.GetTime(netClient.env); var u := t as uint64; clockEvent := NetGetTime(t); clock := CBoundedClock(t,t); } */ predicate SendLogEntryReflectsPacket(event:NetEvent, cpacket:CPacket) { event.LIoOpSend? && NetPacketIsAbstractable(event.s) && CPacketIsAbstractable(cpacket) && AbstractifyCPacketToShtPacket(cpacket) == AbstractifyNetPacketToShtPacket(event.s) } predicate SendLogReflectsPacket(netEventLog:seq, packets:seq) { |netEventLog| == |packets| && (forall i :: 0 <= i < |packets| ==> SendLogEntryReflectsPacket(netEventLog[i], packets[i])) } /* predicate SendLogMatchesRefinement(netEventLog:seq, broadcast:CBroadcast, index:int) requires CBroadcastIsAbstractable(broadcast); requires broadcast.CBroadcast?; requires 0<=|netEventLog|<=|broadcast.dsts| requires 0 <= index < |netEventLog|; { netEventLog[index].NetSendEvent? && NetPacketIsAbstractable(netEventLog[index].sendPacket) && AbstractifyCBroadcastToRlsPacketSeq(broadcast)[index] == AbstractifyCPacketToShtPacket(netEventLog[index].sendPacket) } predicate SendLogReflectsBroadcastPrefix(netEventLog:seq, broadcast:CBroadcast) requires CBroadcastIsAbstractable(broadcast); requires broadcast.CBroadcast?; { 0<=|netEventLog|<=|broadcast.dsts| && forall i :: 0<=i<|netEventLog| ==> SendLogMatchesRefinement(netEventLog, broadcast, i) } */ /* predicate SendLogReflectsBroadcast(netEventLog:seq, broadcast:CBroadcast) requires CBroadcastIsAbstractable(broadcast); { if broadcast.CBroadcastNop? then netEventLog == [] else SendLogReflectsBroadcastPrefix(netEventLog, broadcast) && |netEventLog| == |broadcast.dsts| } lemma lemma_NetEventLogAppend(broadcast:CBroadcast, netEventLog:seq, netEvent:NetEvent) requires broadcast.CBroadcast?; requires CBroadcastIsValid(broadcast); requires SendLogReflectsBroadcastPrefix(netEventLog, broadcast); requires |netEventLog| < |broadcast.dsts|; requires netEvent.NetSendEvent?; requires NetPacketIsAbstractable(netEvent.sendPacket); requires CMessageIsAbstractable(PaxosDemarshallData(netEvent.sendPacket.data)); requires netEvent.sendPacket.dst == broadcast.dsts[|netEventLog|]; requires netEvent.sendPacket.src == broadcast.src; requires BufferRefinementAgreesWithMessageRefinement(broadcast.msg, netEvent.sendPacket.data); ensures SendLogReflectsBroadcastPrefix(netEventLog + [netEvent], broadcast); { var i := |netEventLog|; calc { AbstractifyCBroadcastToRlsPacketSeq(broadcast)[i]; BuildLBroadcast(AbstractifyEndPointToNodeIdentity(broadcast.src), AbstractifyEndPointsToNodeIdentities(broadcast.dsts), AbstractifyCMessageToRslMessage(broadcast.msg))[i]; LPacket(AbstractifyEndPointsToNodeIdentities(broadcast.dsts)[i], AbstractifyEndPointToNodeIdentity(broadcast.src), AbstractifyCMessageToRslMessage(broadcast.msg)); LPacket(AbstractifyEndPointToNodeIdentity(netEvent.sendPacket.dst), AbstractifyEndPointToNodeIdentity(netEvent.sendPacket.src), AbstractifyCMessageToRslMessage(PaxosDemarshallData(netEvent.sendPacket.data))); AbstractifyCPacketToShtPacket(netEvent.sendPacket); } var new_log := netEventLog + [netEvent]; forall i | 0 <= i < |new_log| ensures SendLogMatchesRefinement(new_log, broadcast, i); { if i < |netEventLog| { assert new_log[i] == netEventLog[i]; assert SendLogMatchesRefinement(netEventLog, broadcast, i); assert SendLogMatchesRefinement(new_log, broadcast, i); } else { assert new_log[i] == netEvent; assert SendLogMatchesRefinement(new_log, broadcast, i); } } calc ==> { true; forall i :: 0 <= i < |new_log| ==> SendLogMatchesRefinement(new_log, broadcast, i); SendLogReflectsBroadcastPrefix(new_log, broadcast); SendLogReflectsBroadcastPrefix(netEventLog + [netEvent], broadcast); } } */ /* method SendBroadcast(netClient:NetClient, broadcast:CBroadcast, ghost localAddr_:EndPoint) returns (ok:bool, ghost netEventLog:seq) requires NetClientIsValid(netClient); requires CBroadcastIsValid(broadcast); requires EndPoint(netClient.MyPublicKey()) == localAddr_; requires broadcast.CBroadcast? ==> broadcast.src == localAddr_; modifies NetClientRepr(netClient); ensures old(NetClientRepr(netClient)) == NetClientRepr(netClient); ensures netClient.env == old(netClient.env); ensures netClient.MyPublicKey() == old(netClient.MyPublicKey()); ensures NetClientOk(netClient) <==> ok; ensures ok ==> ( NetClientIsValid(netClient) && netClient.IsOpen() && old(netClient.env.net.history()) + netEventLog == netClient.env.net.history() && SendLogReflectsBroadcast(netEventLog, broadcast)); { ok := true; netEventLog := []; if broadcast.CBroadcastNop? { // No work to do! } else { // Do the marshalling work once assert CMessageIsAbstractable(broadcast.msg); assert Marshallable(broadcast.msg); var buffer := PaxosMarshall(broadcast.msg); assert PaxosDemarshallable(buffer[..]); calc ==> { true; CBroadcastIsValid(broadcast); CBroadcastIsAbstractable(broadcast); CMessageIsAbstractable(broadcast.msg); } lemma_PaxosDemarshallableImpliesRefinable(buffer[..]); var i:uint64 := 0; while i < |broadcast.dsts| as uint64 invariant 0 <= i as int <= |broadcast.dsts|; invariant |netEventLog| == i as int; invariant NetClientRepr(netClient) == old(NetClientRepr(netClient)); invariant netClient.env == old(netClient.env); invariant netClient.MyPublicKey() == old(netClient.MyPublicKey()); invariant NetClientIsValid(netClient); invariant NetClientOk(netClient); invariant old(netClient.env.net.history()) + netEventLog == netClient.env.net.history(); invariant PaxosDemarshallable(buffer[..]); invariant BufferRefinementAgreesWithMessageRefinement(broadcast.msg, buffer[..]); invariant SendLogReflectsBroadcastPrefix(netEventLog, broadcast); invariant CMessageIsAbstractable(PaxosDemarshallData(buffer[..])); { ghost var netEventLog_old := netEventLog; // Construct the remote address -- TODO: Only do this once per replica! var dstEp:EndPoint := broadcast.dsts[i]; var dstAddrAry := seqToArrayOpt(dstEp.addr); var remote; ok, remote := CryptoEndPoint.Construct(dstAddrAry, dstEp.port, netClient.env); if (!ok) { return; } ok := netClient.Send(remote, buffer); if (!ok) { return; } ghost var netEvent := NetSendEvent(NetPacket_ctor(remote.EP(), EndPoint(netClient.MyPublicKey()), buffer[..])); netEventLog := netEventLog + [netEvent]; lemma_NetEventLogAppend(broadcast, netEventLog_old, netEvent); i := i + 1; } } } */ method SendPacketSeq(netClient:NetClient, cpackets:seq, ghost localAddr_:EndPoint) returns (ok:bool, ghost netEventLog:seq) requires NetClientIsValid(netClient); requires OutboundPacketsSeqIsValid(cpackets); requires EndPoint(netClient.MyPublicKey()) == localAddr_; requires OutboundPacketsSeqHasCorrectSrc(cpackets, localAddr_); modifies NetClientRepr(netClient); ensures old(NetClientRepr(netClient)) == NetClientRepr(netClient); ensures netClient.env == old(netClient.env); ensures netClient.MyPublicKey() == old(netClient.MyPublicKey()); ensures NetClientOk(netClient) <==> ok; ensures ok ==> ( NetClientIsValid(netClient) && netClient.IsOpen()); ensures ok ==> old(netClient.env.net.history()) + netEventLog == netClient.env.net.history(); ensures ok ==> SendLogReflectsPacket(netEventLog, cpackets) && OnlySentMarshallableData(netEventLog); { var j:uint64 := 0; netEventLog := []; ok := true; ghost var netEventLog_old := netEventLog; ghost var netClientEnvHistory_old := old(netClient.env.net.history()); var i := 0; while (i < |cpackets|) invariant old(NetClientRepr(netClient)) == NetClientRepr(netClient); invariant netClient.env == old(netClient.env); invariant netClient.MyPublicKey() == old(netClient.MyPublicKey()); invariant NetClientOk(netClient) <==> ok; invariant ok ==> ( NetClientIsValid(netClient) && netClient.IsOpen()); invariant ok ==> netClientEnvHistory_old + netEventLog == netClient.env.net.history(); invariant ok ==> OnlySentMarshallableData(netEventLog); invariant (i == 0) ==> |netEventLog| == 0; invariant (0 < i < |cpackets|) ==> |netEventLog| == |cpackets[0..i]|; invariant (0 < i < |cpackets|) ==> SendLogReflectsPacket(netEventLog, cpackets[0..i]); invariant (i >= |cpackets|) ==> SendLogReflectsPacket(netEventLog, cpackets); { var cpacket := cpackets[i]; // Construct the remote address var dstEp:EndPoint := cpacket.dst; assert cpacket in cpackets; assert OutboundPacketsIsValid(cpacket); assert CSingleMessageIsAbstractable(cpacket.msg); assert CSingleMessageMarshallable(cpacket.msg); var buffer := SHTMarshall(cpacket.msg); ghost var data := buffer[..]; assert BufferRefinementAgreesWithMessageRefinement(cpacket.msg, data); ok := netClient.Send(dstEp.public_key, buffer); if (!ok) { return; } ghost var netEvent := LIoOpSend(LPacket(dstEp, EndPoint(netClient.MyPublicKey()), buffer[..])); ghost var net := netEvent.s; calc { AbstractifyCPacketToLSHTPacket(cpacket); LPacket(AbstractifyEndPointToNodeIdentity(cpacket.dst), AbstractifyEndPointToNodeIdentity(cpacket.src), AbstractifyCSingleMessageToSingleMessage(cpacket.msg)); LPacket(AbstractifyEndPointToNodeIdentity(net.dst), AbstractifyEndPointToNodeIdentity(net.src), AbstractifyCSingleMessageToSingleMessage(cpacket.msg)); AbstractifyBufferToLSHTPacket(net.src, net.dst, data); AbstractifyBufferToLSHTPacket(net.src, net.dst, net.msg); AbstractifyNetPacketToLSHTPacket(netEvent.s); } assert SendLogEntryReflectsPacket(netEvent, cpacket); assert OnlySentMarshallableData(netEventLog); assert NetPacketBound(netEvent.s.msg) && CSingleMessageMarshallable(SHTDemarshallData(netEvent.s.msg)); netEventLog := netEventLog + [netEvent]; assert cpackets[0..(i+1)] == cpackets[0..i] + [cpacket]; assert SendLogReflectsPacket(netEventLog, cpackets[0..(i+1)]); assert OnlySentMarshallableData(netEventLog); i := i + 1; } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/LiveSHT/SchedulerImpl.i.dfy ================================================ include "../SHT/HostModel.i.dfy" include "../../Protocol/LiveSHT/Scheduler.i.dfy" include "../../Common/Collections/Seqs.i.dfy" include "../../../Libraries/Math/mod_auto.i.dfy" include "../../Protocol/SHT/Host.i.dfy" include "NetSHT.i.dfy" include "SchedulerModel.i.dfy" include "Unsendable.i.dfy" //include "CBoundedClock.i.dfy" module LiveSHT__SchedulerImpl_i { import opened Native__NativeTypes_s import opened Native__Io_s import opened Logic__Option_i import opened Math__mod_auto_i import opened Collections__Seqs_i import opened Environment_s import opened SHT__Host_i import opened SHT__HostModel_i import opened SHT__HostState_i import opened SHT__CMessage_i import opened SHT__ConstantsState_i import opened SHT__Network_i import opened SHT__PacketParsing_i import opened SHT__SingleDeliveryState_i import opened SHT__SingleDelivery_i import opened Impl_Parameters_i import opened LiveSHT__Scheduler_i import opened LiveSHT__NetSHT_i import opened LiveSHT__SchedulerModel_i import opened LiveSHT__Unsendable_i import opened LiveSHT__Environment_i import opened Common__GenericMarshalling_i import opened Common__NetClient_i import opened Common__NodeIdentity_i import opened Common__Util_i class SchedulerImpl { var host:HostState; var nextActionIndex:uint64; var resendCount:uint64; var netClient:NetClient?; var localAddr:EndPoint; ghost var Repr : set; constructor() { } predicate Valid() reads this; reads NetClientIsValid.reads(netClient); { HostStateIsValid(host) && HostStateIsAbstractable(host) && (0 <= nextActionIndex as int < LHost_NumActions()) && (0 <= resendCount as int < 100000000) && NetClientIsValid(netClient) && EndPoint(netClient.MyPublicKey()) == localAddr && EndPoint(netClient.MyPublicKey()) == host.me && HostStateIsValid(host) && Repr == { this } + NetClientRepr(netClient) && CSingleDeliveryAccountIsValid(host.sd, host.constants.params) } function Env() : HostEnvironment? reads this, NetClientIsValid.reads(netClient); { if netClient!=null then netClient.env else null } function AbstractifyToHost() : Host reads this; requires HostStateIsAbstractable(host); { AbstractifyHostStateToHost(host) } function AbstractifyToLScheduler() : LScheduler reads this; requires HostStateIsAbstractable(host); { LScheduler( AbstractifyToHost(), nextActionIndex as int, resendCount as int) } method {:timeLimitMultiplier 2} Host_Init_Impl( constants:ConstantsState, my_index:uint64, me:EndPoint, nc:NetClient, ghost env_:HostEnvironment ) returns ( ok:bool ) requires env_.Valid() && env_.ok.ok() requires ConstantsStateIsValid(constants) requires EndPointIsValidPublicKey(me) requires NetClientIsValid(nc) requires EndPoint(nc.MyPublicKey()) == me requires 0 <= my_index as int < |constants.hostIds| requires EndPoint(nc.MyPublicKey()) == constants.hostIds[my_index] requires nc.env == env_ modifies this ensures ok ==> Valid() && Env() == env_ && LScheduler_Init(AbstractifyToLScheduler(), AbstractifyEndPointToNodeIdentity(me), AbstractifyEndPointToNodeIdentity(constants.rootIdentity), AbstractifyEndPointsToNodeIdentities(constants.hostIds), AbstractifyCParametersToParameters(constants.params)) && host.constants == constants { netClient := nc; host := InitHostState(constants, me); nextActionIndex := 0; resendCount := 0; localAddr := host.me; Repr := { this } + NetClientRepr(netClient); ok := true; } static method rollActionIndex(a:uint64) returns (a':uint64) requires 0 <= a as int < 3; ensures a' as int == (a as int + 1) % LHost_NumActions(); { lemma_mod_auto(3); if (a >= 2) { a' := 0; } else { a' := (a + 1); } } static method rollResendCount(a:uint64) returns (a':uint64) requires 0 <= a as int < 100000000; ensures a' as int == (a as int + 1) % 100000000; { lemma_mod_auto(100000000); if (a >= 100000000-1) { a' := 0; } else { a' := (a + 1); } } static lemma lemma_ExtractSentPacketsFromIos(ios:seq) requires AllIosAreSends(ios); ensures |ExtractSentPacketsFromIos(ios)| == |ios|; ensures forall i {:auto_trigger} :: 0 <= i < |ios| ==> ExtractSentPacketsFromIos(ios)[i] == ios[i].s; { reveal_ExtractSentPacketsFromIos(); } method DeliverPacketSeq(packets:seq) returns (ok:bool, ghost netEventLog:seq, ghost ios:seq) requires Valid(); requires OutboundPacketsSeqIsValid(packets); requires OutboundPacketsSeqHasCorrectSrc(packets, host.me); modifies Repr; ensures Repr == old(Repr); ensures Env() == old(Env()); ensures ok == NetClientOk(netClient); ensures ok ==> ( Valid() && host == old(host) && nextActionIndex == old(nextActionIndex) && resendCount == old(resendCount) && AllIosAreSends(ios) && AbstractifyOutboundPacketsToSeqOfLSHTPackets(packets) == ExtractSentPacketsFromIos(ios) && RawIoConsistentWithSpecIO(netEventLog, ios) && OnlySentMarshallableData(netEventLog) && old(Env().net.history()) + netEventLog == Env().net.history()); { var start_time := Time.GetDebugTimeTicks(); ok, netEventLog := SendPacketSeq(netClient, packets, localAddr); if (!ok) { return; } ios := MapSentPacketSeqToIos(packets); MapSentPacketSeqToIos_ExtractSentPacketsFromIos_equivalence(packets, ios); var end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("DeliverPacketSeq", start_time, end_time); } method DeliverOutboundPackets(packets:seq) returns (ok:bool, ghost netEventLog:seq, ghost ios:seq) requires Valid(); requires OutboundPacketsSeqIsValid(packets); requires OutboundPacketsSeqHasCorrectSrc(packets, host.me); modifies Repr; ensures Repr == old(Repr); ensures Env() == old(Env()); ensures ok == NetClientOk(netClient); ensures ok ==> ( Valid() && host == old(host) && nextActionIndex == old(nextActionIndex) && resendCount == old(resendCount) && AllIosAreSends(ios) && AbstractifyOutboundPacketsToSeqOfLSHTPackets(packets) == ExtractSentPacketsFromIos(ios) && RawIoConsistentWithSpecIO(netEventLog, ios) && OnlySentMarshallableData(netEventLog) && old(Env().net.history()) + netEventLog == Env().net.history()); { ok, netEventLog, ios := DeliverPacketSeq(packets); } predicate ReceivedPacketProperties(cpacket:CPacket, netEvent0:NetEvent, io0:LSHTIo) reads this; //requires SHTConcreteConfigurationIsValid(host.constants.all.config); { CPacketIsSendable(cpacket) && EndPointIsValidPublicKey(host.me) && io0.LIoOpReceive? && NetEventIsAbstractable(netEvent0) && io0 == AbstractifyNetEventToLSHTIo(netEvent0) && NetEventIsAbstractable(netEvent0) && netEvent0.LIoOpReceive? && AbstractifyCPacketToShtPacket(cpacket) == AbstractifyNetPacketToShtPacket(netEvent0.r) } static lemma ExtractSentPacketsFromIos_DoesNotMindSomeClutter(ios_head:seq, ios_tail:seq) requires forall i :: 0<=i<|ios_head| ==> !ios_head[i].LIoOpSend?; ensures ExtractSentPacketsFromIos(ios_tail) == ExtractSentPacketsFromIos(ios_head + ios_tail); { if |ios_head| == 0 { assert ios_head + ios_tail == ios_tail; } else { assert !ios_head[0].LIoOpSend?; ghost var ios := [ios_head[0]] + ios_head[1..] + ios_tail; calc { ExtractSentPacketsFromIos(ios_head + ios_tail); { assert ios_head == [ios_head[0]] + ios_head[1..]; } ExtractSentPacketsFromIos([ios_head[0]] + ios_head[1..] + ios_tail); ExtractSentPacketsFromIos(ios); { assert ios[0] == ios_head[0]; assert ios[1..] == ios_head[1..] + ios_tail; reveal_ExtractSentPacketsFromIos(); } ExtractSentPacketsFromIos(ios_head[1..] + ios_tail); { ExtractSentPacketsFromIos_DoesNotMindSomeClutter(ios_head[1..], ios_tail); } ExtractSentPacketsFromIos(ios_tail); } } } method Host_NoReceive_NoClock_Next() returns (ok:bool, ghost netEventLog:seq, ghost ios:seq) requires nextActionIndex == 2; requires Valid(); modifies Repr; ensures Repr == old(Repr); ensures Env() == old(Env()); ensures ok == NetClientOk(netClient); ensures ok ==> ( Valid() && nextActionIndex == old(nextActionIndex) && resendCount == old(resendCount) && LHost_NoReceive_Next(old(AbstractifyToHost()), AbstractifyToHost(), ios) && RawIoConsistentWithSpecIO(netEventLog, ios) && OnlySentMarshallableData(netEventLog) && LIoOpSeqCompatibleWithReduction(ios) && old(Env().net.history()) + netEventLog == Env().net.history()); { var sent_packets; host,sent_packets := HostModelSpontaneouslyRetransmit(host); ok, netEventLog, ios := DeliverOutboundPackets(sent_packets); if (!ok) { return; } assert old(Env().net.history()) + netEventLog == Env().net.history(); // deleteme // The following loop takes the forall that's stated in terms of io indices and turns // it into a forall in terms of ios. In other words, it takes // forall idx {:trigger 0 <= idx < |ios|} :: 0 <= idx < |ios| ==> ios[idx].LIoOpSend? // and turns it into // forall io {:trigger io in ios} :: io in ios ==> io.LIoOpSend? forall io | io in ios ensures io.LIoOpSend?; { var pos :| 0 <= pos < |ios| && io == ios[pos]; assert ios[pos].LIoOpSend?; } assert AbstractifyOutboundPacketsToSeqOfLSHTPackets(sent_packets) == ExtractSentPacketsFromIos(ios); assert Env() == old(Env()); assert RawIoConsistentWithSpecIO(netEventLog, ios); reveal_AbstractifyOutboundPacketsToSeqOfLSHTPackets(); assert ExtractPacketsFromLSHTPackets(ExtractSentPacketsFromIos(ios)) == UnAckedMessages(AbstractifyToHost().sd, AbstractifyToHost().me); assert SpontaneouslyRetransmit(old(AbstractifyToHost()), AbstractifyToHost(), ExtractPacketsFromLSHTPackets(ExtractSentPacketsFromIos(ios))); assert LHost_NoReceive_Next(old(AbstractifyToHost()), AbstractifyToHost(), ios); } static lemma SingletonSeqPrependSilly(log_head:seq, log_tail:seq, log:seq) requires |log_head|==1; requires log == log_head + log_tail; ensures log_tail == log[1..]; { } static lemma Combine_AbstractifyNetEventToLSHTIo(ios_head:seq, ios_tail:seq, ios:seq, log_head:seq, log_tail:seq, log:seq) requires |log_head| == |ios_head|; requires forall i :: 0<=i<|log_head| ==> NetEventIsAbstractable(log_head[i]) && ios_head[i] == AbstractifyNetEventToLSHTIo(log_head[i]); requires |log_tail| == |ios_tail|; requires forall i :: 0<=i<|log_tail| ==> NetEventIsAbstractable(log_tail[i]) && ios_tail[i] == AbstractifyNetEventToLSHTIo(log_tail[i]); requires ios == ios_head+ios_tail; requires log == log_head+log_tail; ensures forall i :: 0<=i<|log| ==> ios[i] == AbstractifyNetEventToLSHTIo(log[i]); { } static lemma NetEventLogIsAbstractable_Extend(log_head:seq, log_tail:seq, log:seq) requires log == log_head+log_tail; requires NetEventLogIsAbstractable(log_head); requires NetEventLogIsAbstractable(log_tail); ensures NetEventLogIsAbstractable(log); { } static lemma EstablishCombineIos(ios_head:seq, ios_tail:seq, ios:seq) requires ios == ios_head+ios_tail; requires |ios_head| == 1; requires forall i :: 0<=i<|ios_tail| ==> ios_tail[i].LIoOpSend?; ensures forall io :: io in ios[1..] ==> io.LIoOpSend?; { } static lemma SingletonSeqSilly(packets:seq, p:CPacket) requires packets == [p]; requires |packets| == 1; ensures forall p' :: p' in packets ==> p' == p { } method{:timeLimitMultiplier 8} HostNextReceivePacket(ghost netEventLogOld:seq, rr:ReceiveResult, ghost receive_event:NetEvent) returns (ok:bool, ghost netEventLog:seq, ghost ios:seq) requires nextActionIndex == 0; requires Valid(); requires Env().net.history() == netEventLogOld + [receive_event]; requires rr.RRPacket?; requires receive_event.LIoOpReceive?; requires CPacketIsAbstractable(rr.cpacket); requires ValidPhysicalAddress(rr.cpacket.src); requires NetPacketIsAbstractable(receive_event.r); //requires CSingleMessageMarshallable(rr.cpacket.msg); requires !rr.cpacket.msg.CInvalidMessage? && CSingleMessageIs64Bit(rr.cpacket.msg); requires AbstractifyCPacketToLSHTPacket(rr.cpacket) == AbstractifyNetPacketToLSHTPacket(receive_event.r); //requires CPacketIsSendable(rr.cpacket); requires rr.cpacket.dst == host.me; modifies Repr; ensures Repr == old(Repr); ensures ok == NetClientOk(netClient); ensures Env() == old(Env()); ensures ok ==> ( Valid() && nextActionIndex == old(nextActionIndex) && resendCount == old(resendCount) && LHost_ReceivePacket_Next(old(AbstractifyToHost()), AbstractifyToHost(), ios) && OnlySentMarshallableData(netEventLog) && RawIoConsistentWithSpecIO(netEventLog, ios) && LIoOpSeqCompatibleWithReduction(ios) && netEventLogOld + netEventLog == Env().net.history()); { var cpacket := rr.cpacket; var sent_packets, ack; host, sent_packets, ack := HostModelReceivePacket(host, cpacket); assert Valid(); assert ReceivePacket(old(AbstractifyToHost()), AbstractifyToHost(), AbstractifyCPacketToShtPacket(cpacket), AbstractifySeqOfCPacketsToSetOfShtPackets(sent_packets), AbstractifyCPacketToShtPacket(ack)); ghost var io0 := LIoOpReceive(AbstractifyNetPacketToLSHTPacket(receive_event.r)); ghost var log_head, log_tail, ios_head, ios_tail; ios_head := [io0]; log_head := [receive_event]; ghost var preDeliveryHistory := Env().net.history(); assert Env() == old(Env()); assert Valid(); assert EndPoint(netClient.MyPublicKey()) == host.me; ok, log_tail, ios_tail := DeliverOutboundPackets(sent_packets); if (!ok) { return; } ios := ios_head + ios_tail; netEventLog := log_head + log_tail; calc { netEventLogOld + netEventLog; netEventLogOld + (log_head + log_tail); { SeqAdditionIsAssociative(netEventLogOld, log_head, log_tail); } (netEventLogOld + log_head) + log_tail; preDeliveryHistory + log_tail; { SingletonSeqPrependSilly(log_head, log_tail, netEventLog); } preDeliveryHistory + netEventLog[1..]; preDeliveryHistory + log_tail; Env().net.history(); } reveal_AbstractifyOutboundPacketsToSeqOfLSHTPackets(); assert Env() == old(Env()); assert io0 == AbstractifyNetEventToLSHTIo(receive_event); forall i | 0<=i<|log_head| ensures NetEventIsAbstractable(log_head[i]) && ios_head[i] == AbstractifyNetEventToLSHTIo(log_head[i]); { assert log_head[i] == receive_event; assert ios_head[i] == io0; } ExtractSentPacketsFromIos_DoesNotMindSomeClutter(ios_head, ios_tail); assert ios_tail == ios[1..]; assert AllIosAreSends(ios_tail); assert forall i{:trigger ios_tail[i].LIoOpSend?} :: 0<=i<|ios_tail| ==> ios_tail[i].LIoOpSend?; Combine_AbstractifyNetEventToLSHTIo(ios_head, ios_tail, ios, log_head, log_tail, netEventLog); assert AbstractifyOutboundPacketsToSeqOfLSHTPackets(sent_packets) == ExtractSentPacketsFromIos(ios); NetEventLogIsAbstractable_Extend(log_head, log_tail, netEventLog); assert NetEventLogIsAbstractable(netEventLog); lemma_AbstractifyRawLogToIos_properties(netEventLog, ios); assert RawIoConsistentWithSpecIO(netEventLog, ios); ExtractSentPacketsFromIos_DoesNotMindSomeClutter(ios_head, ios_tail); assert ios[0] == io0; assert AbstractifyCPacketToShtPacket(cpacket) == Packet(ios[0].r.dst, ios[0].r.src, ios[0].r.msg); assert AbstractifySeqOfCPacketsToSetOfShtPackets(sent_packets) == ExtractPacketsFromLSHTPackets(ExtractSentPacketsFromIos(ios)); assert ReceivePacket_Wrapper(old(AbstractifyToHost()), AbstractifyToHost(), AbstractifyCPacketToShtPacket(cpacket), AbstractifySeqOfCPacketsToSetOfShtPackets(sent_packets)); assert LHost_ReceivePacketWithoutReadingClock(old(AbstractifyToHost()), AbstractifyToHost(), ios); forall i | 1<=i<|ios| ensures ios[i].LIoOpSend?; { SingletonSeqPrependSilly2(ios_head, ios_tail, ios, i); // Help stabilize the next line assert ios[i] == ios_tail[i-1]; var j := i-1; assert 0 <= j < |ios_tail|; assert ios_tail[j].LIoOpSend?; } assert LHost_ReceivePacket_Next(old(AbstractifyToHost()), AbstractifyToHost(), ios); } method Host_ReceivePacket_Next() returns (ok:bool, ghost netEventLog:seq, ghost ios:seq) requires nextActionIndex == 0; requires Valid(); modifies Repr; ensures Repr == old(Repr); ensures ok == NetClientOk(netClient); ensures Env() == old(Env()); ensures ok ==> ( Valid() && nextActionIndex == old(nextActionIndex) && resendCount == old(resendCount) && ( LHost_ReceivePacket_Next(old(AbstractifyToHost()), AbstractifyToHost(), ios) || ( IosReflectIgnoringUnDemarshallable(netEventLog) && old(AbstractifyToHost()) == AbstractifyToHost()) ) && RawIoConsistentWithSpecIO(netEventLog, ios) && OnlySentMarshallableData(netEventLog) && LIoOpSeqCompatibleWithReduction(ios) && old(Env().net.history()) + netEventLog == Env().net.history()); { var start_time := Time.GetDebugTimeTicks(); var rr; ghost var netEvent0; rr, netEvent0 := Receive(netClient, localAddr); ghost var midHistory := Env().net.history(); assert Env()==old(Env()); if (rr.RRFail?) { ok := false; var end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("Host_Next_ProcessPacket_fail", start_time, end_time); return; } else if (rr.RRTimeout?) { ok := true; ios := [ LIoOpTimeoutReceive() ]; netEventLog := [ netEvent0 ]; var end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("Host_Next_ProcessPacket_timeout", start_time, end_time); return; } else { ok := true; var cpacket := rr.cpacket; //assert Valid(); //var marshallable := IsCSingleMessageMarshallable(cpacket.msg); //assert Valid(); if cpacket.msg.CInvalidMessage? { ok := true; netEventLog := [netEvent0]; ghost var receive_io := LIoOpReceive(AbstractifyNetPacketToLSHTPacket(netEvent0.r)); ios := [receive_io]; assert IosReflectIgnoringUnDemarshallable(netEventLog); } else { //assert CPacketIsAbstractable(cpacket) && CSingleMessageMarshallable(cpacket.msg); ok, netEventLog, ios := HostNextReceivePacket(old(Env().net.history()), rr, netEvent0); /* host, sent_packets, ack := HostModelReceivePacket(host, cpacket); assert Valid(); assert ReceivePacket(old(AbstractifyToHost()), AbstractifyToHost(), AbstractifyCPacketToShtPacket(cpacket), AbstractifySeqOfCPacketsToSetOfShtPackets(sent_packets), AbstractifyCPacketToShtPacket(ack)); ghost var io0 := LIoOpReceive(AbstractifyNetPacketToLSHTPacket(netEvent0.r)); ghost var log_head, log_tail, ios_head, ios_tail; ios_head := [io0]; log_head := [netEvent0]; ghost var preDeliveryHistory := Env().net.history(); calc { old(Env().net.history()) + log_head; old(Env().net.history()) + [netEvent0]; preDeliveryHistory; } assert Env() == old(Env()); assert Valid(); assert EndPoint(netClient.MyPublicKey()) == host.me; ok, log_tail, ios_tail := DeliverOutboundPackets(sent_packets); if (!ok) { return; } ios := ios_head + ios_tail; netEventLog := log_head + log_tail; calc { old(Env().net.history()) + netEventLog; old(Env().net.history()) + (log_head + log_tail); { SeqAdditionIsAssociative(old(Env().net.history()), log_head, log_tail); } (old(Env().net.history()) + log_head) + log_tail; preDeliveryHistory + log_tail; { SingletonSeqPrependSilly(log_head, log_tail, netEventLog); } preDeliveryHistory + netEventLog[1..]; preDeliveryHistory + log_tail; Env().net.history(); } reveal_AbstractifyOutboundPacketsToSeqOfLSHTPackets(); assert Env() == old(Env()); assert io0 == AbstractifyNetEventToLSHTIo(netEvent0); forall i | 0<=i<|log_head| ensures NetEventIsAbstractable(log_head[i]) && ios_head[i] == AbstractifyNetEventToLSHTIo(log_head[i]); { assert log_head[i] == netEvent0; assert ios_head[i] == io0; } ExtractSentPacketsFromIos_DoesNotMindSomeClutter(ios_head, ios_tail); assert ios_tail == ios[1..]; assert AllIosAreSends(ios_tail); assert forall i{:trigger ios_tail[i].LIoOpSend?} :: 0<=i<|ios_tail| ==> ios_tail[i].LIoOpSend?; Combine_AbstractifyNetEventToLSHTIo(ios_head, ios_tail, ios, log_head, log_tail, netEventLog); assert AbstractifyOutboundPacketsToSeqOfLSHTPackets(sent_packets) == ExtractSentPacketsFromIos(ios); NetEventLogIsAbstractable_Extend(log_head, log_tail, netEventLog); assert NetEventLogIsAbstractable(netEventLog); lemma_AbstractifyRawLogToIos_properties(netEventLog, ios); assert RawIoConsistentWithSpecIO(netEventLog, ios); ExtractSentPacketsFromIos_DoesNotMindSomeClutter(ios_head, ios_tail); // assert LHost_ReceivePacketWithoutReadingClock(old(AbstractifyToHost()), AbstractifyToHost(), ios); forall i | 1<=i<|ios| ensures ios[i].LIoOpSend?; { SingletonSeqPrependSilly2(ios_head, ios_tail, ios, i); // Help stabilize the next line assert ios[i] == ios_tail[i-1]; var j := i-1; assert 0 <= j < |ios_tail|; assert ios_tail[j].LIoOpSend?; } assert LHost_ReceivePacket_Next(old(AbstractifyToHost()), AbstractifyToHost(), ios); */ } } } static lemma SingletonSeqPrependSilly2(log_head:seq, log_tail:seq, log:seq, index:int) requires |log_head|==1; requires log == log_head + log_tail; requires 1 <= index < |log|; ensures log_tail[index-1] == log[index]; { } method{:timeLimitMultiplier 2} Host_ProcessReceivedPacket_Next() returns (ok:bool, ghost netEventLog:seq, ghost ios:seq) requires nextActionIndex == 1; requires Valid(); modifies Repr; ensures Repr == old(Repr); ensures Env() == old(Env()); ensures ok == NetClientOk(netClient); ensures ok ==> ( Valid() && nextActionIndex == old(nextActionIndex) && resendCount == old(resendCount) && (LHost_ProcessReceivedPacket_Next(old(AbstractifyToHost()), AbstractifyToHost(), ios) || HostNextIgnoreUnsendableProcess(old(AbstractifyToLScheduler()), AbstractifyToLScheduler().(nextActionIndex := 2), netEventLog)) && old(AbstractifyToHost()).me == AbstractifyToHost().me && RawIoConsistentWithSpecIO(netEventLog, ios) && OnlySentMarshallableData(netEventLog) && LIoOpSeqCompatibleWithReduction(ios) && old(AbstractifyToLScheduler()).host.constants == AbstractifyToLScheduler().host.constants && old(Env().net.history()) + netEventLog == Env().net.history()); { var sent_packets := []; var b; if (host.receivedPacket.Some?) { b := ShouldProcessReceivedMessageImpl(host); if (b) { var cpacket := host.receivedPacket.v; if (cpacket.msg.CSingleMessage?) { assert |host.delegationMap.lows| < 0xFFFF_FFFF_FFFF_FFFF - 2; host, sent_packets := HostModelNextReceiveMessage(host, cpacket); } else { host := host.(receivedPacket := None); sent_packets := []; assert false; } } else { //host := host.(receivedPacket := None); sent_packets := []; //assert false; } } else { sent_packets := []; } ok, netEventLog, ios := DeliverOutboundPackets(sent_packets); if (!ok) { return; } assert old(Env().net.history()) + netEventLog == Env().net.history(); // deleteme lemma_ExtractSentPacketsFromIos(ios); // ==> assert |sent_packets| == 0 ==> |ios| == 0; // The following loop takes the forall that's stated in terms of io indices and turns // it into a forall in terms of ios. In other words, it takes // forall idx {:trigger 0 <= idx < |ios|} :: 0 <= idx < |ios| ==> ios[idx].LIoOpSend? // and turns it into // forall io {:trigger io in ios} :: io.LIoOpSend? forall io | io in ios ensures io.LIoOpSend?; { var pos :| 0 <= pos < |ios| && io == ios[pos]; assert ios[pos].LIoOpSend?; } if (old(AbstractifyToHost()).receivedPacket.Some?) { if (b) { assert AbstractifyOutboundPacketsToSeqOfLSHTPackets(sent_packets) == ExtractSentPacketsFromIos(ios); assert Env() == old(Env()); assert RawIoConsistentWithSpecIO(netEventLog, ios); reveal_AbstractifyOutboundPacketsToSeqOfLSHTPackets(); ghost var packet := old(AbstractifyToHost()).receivedPacket.v; if packet.msg.SingleMessage? { assert Process_Message(old(AbstractifyToHost()), AbstractifyToHost(), AbstractifySeqOfCPacketsToSetOfShtPackets(sent_packets)) || HostIgnoringUnParseable(old(AbstractifyToHost()), AbstractifyToHost(), AbstractifySeqOfCPacketsToSetOfShtPackets(sent_packets)); } else { assert false; } assert AbstractifySeqOfCPacketsToSetOfShtPackets(sent_packets) == ExtractPacketsFromLSHTPackets(ExtractSentPacketsFromIos(ios)); assert ProcessReceivedPacket(old(AbstractifyToHost()), AbstractifyToHost(), ExtractPacketsFromLSHTPackets(ExtractSentPacketsFromIos(ios))) || HostIgnoringUnParseable(old(AbstractifyToHost()), AbstractifyToHost(), AbstractifySeqOfCPacketsToSetOfShtPackets(sent_packets)); if ProcessReceivedPacket(old(AbstractifyToHost()), AbstractifyToHost(), ExtractPacketsFromLSHTPackets(ExtractSentPacketsFromIos(ios))) { assert LHost_ProcessReceivedPacket_Next(old(AbstractifyToHost()), AbstractifyToHost(), ios); } if HostIgnoringUnParseable(old(AbstractifyToHost()), AbstractifyToHost(), AbstractifySeqOfCPacketsToSetOfShtPackets(sent_packets)) { assert HostNextIgnoreUnsendableProcess(old(AbstractifyToLScheduler()), AbstractifyToLScheduler().(nextActionIndex := 2), netEventLog); } assert LHost_ProcessReceivedPacket_Next(old(AbstractifyToHost()), AbstractifyToHost(), ios) || HostNextIgnoreUnsendableProcess(old(AbstractifyToLScheduler()), AbstractifyToLScheduler().(nextActionIndex := 2), netEventLog); } else { assert AbstractifyOutboundPacketsToSeqOfLSHTPackets(sent_packets) == ExtractSentPacketsFromIos(ios); assert Env() == old(Env()); assert RawIoConsistentWithSpecIO(netEventLog, ios); reveal_AbstractifyOutboundPacketsToSeqOfLSHTPackets(); assert !ShouldProcessReceivedMessage(old(AbstractifyToHost())); assert ProcessReceivedPacket(old(AbstractifyToHost()), AbstractifyToHost(), ExtractPacketsFromLSHTPackets(ExtractSentPacketsFromIos(ios))); assert LHost_ProcessReceivedPacket_Next(old(AbstractifyToHost()), AbstractifyToHost(), ios); } } else { assert AbstractifyOutboundPacketsToSeqOfLSHTPackets(sent_packets) == ExtractSentPacketsFromIos(ios); assert Env() == old(Env()); assert RawIoConsistentWithSpecIO(netEventLog, ios); reveal_AbstractifyOutboundPacketsToSeqOfLSHTPackets(); assert host.receivedPacket.Some? == false; assert old(AbstractifyToHost()).receivedPacket.Some? == false; assert ProcessReceivedPacket(old(AbstractifyToHost()), AbstractifyToHost(), ExtractPacketsFromLSHTPackets(ExtractSentPacketsFromIos(ios))); assert LHost_ProcessReceivedPacket_Next(old(AbstractifyToHost()), AbstractifyToHost(), ios); } } method {:timeLimitMultiplier 2} Host_Next_main() returns (ok:bool, ghost netEventLog:seq, ghost ios:seq) requires Valid(); modifies Repr; ensures Repr == old(Repr); ensures ok <==> Env() != null && Env().Valid() && Env().ok.ok(); ensures Env() == old(Env()); ensures ok ==> ( Valid() && ( LScheduler_Next(old(AbstractifyToLScheduler()), AbstractifyToLScheduler(), ios) || HostNextIgnoreUnsendable(old(AbstractifyToLScheduler()), AbstractifyToLScheduler(), netEventLog)) && LIoOpSeqCompatibleWithReduction(ios) && RawIoConsistentWithSpecIO(netEventLog, ios) && OnlySentMarshallableData(netEventLog) && old(Env().net.history()) + netEventLog == Env().net.history() ); { var curActionIndex := nextActionIndex; var nextActionIndex' := rollActionIndex(nextActionIndex); var curResendCount; var nextResendCount; ghost var host_old := old(AbstractifyToHost()); ghost var scheduler_old := old(AbstractifyToLScheduler()); ghost var host; ghost var scheduler; //print ("Host_Next_main Enter\n"); assert scheduler_old.host == host_old; if (curActionIndex == 0) { ok, netEventLog, ios := Host_ReceivePacket_Next(); if (!ok) { return; } } else if (curActionIndex == 1) { ok, netEventLog, ios := Host_ProcessReceivedPacket_Next(); if (!ok) { return; } } else if (curActionIndex == 2) { curResendCount := resendCount; nextResendCount := rollResendCount(curResendCount); resendCount := nextResendCount; if (nextResendCount == 0) { ok, netEventLog, ios := Host_NoReceive_NoClock_Next(); if (!ok) { return; } } else { ok := true; netEventLog := []; ios := []; } } else { assert false; } host := AbstractifyToHost(); nextActionIndex := nextActionIndex'; scheduler := AbstractifyToLScheduler(); calc { scheduler.nextActionIndex; nextActionIndex as int; nextActionIndex' as int; (curActionIndex+1) as int % LHost_NumActions(); (scheduler_old.nextActionIndex+1)%LHost_NumActions(); } if (curActionIndex == 2) { calc { scheduler.resendCount; resendCount as int; nextResendCount as int; (curResendCount+1) as int % 100000000; (scheduler_old.resendCount+1)%100000000; } if (nextResendCount == 0) { assert LHost_NoReceive_Next(old(AbstractifyToLScheduler()).host, AbstractifyToLScheduler().host, ios); } else { assert scheduler == scheduler_old.(resendCount := scheduler.resendCount, nextActionIndex := scheduler.nextActionIndex); } } //assert LHost_ReceivePacket_Next(old(AbstractifyToLScheduler()).host, AbstractifyToLScheduler().host, ios) || LHost_ProcessReceivedPacket_Next(old(AbstractifyToLScheduler()).host, AbstractifyToLScheduler().host, ios) || LHost_NoReceive_Next(old(AbstractifyToLScheduler()).host, AbstractifyToLScheduler().host, ios); assert NetClientIsValid(netClient); assert old(AbstractifyToLScheduler()).host.constants == AbstractifyToLScheduler().host.constants; assert {:split_here} true; if (curActionIndex == 0) { assert old(AbstractifyToLScheduler()).nextActionIndex == 0; calc { AbstractifyToLScheduler().nextActionIndex; (curActionIndex+1) as int % LHost_NumActions(); (curActionIndex+1) as int % 3; 1 % 3; 1; } assert LScheduler_Next(old(AbstractifyToLScheduler()), AbstractifyToLScheduler(), ios) || HostNextIgnoreUnsendable(old(AbstractifyToLScheduler()), AbstractifyToLScheduler(), netEventLog); } else if (curActionIndex == 1) { assert LScheduler_Next(old(AbstractifyToLScheduler()), AbstractifyToLScheduler(), ios) || HostNextIgnoreUnsendable(old(AbstractifyToLScheduler()), AbstractifyToLScheduler(), netEventLog); } else if (curActionIndex == 2) { assert LScheduler_Next(old(AbstractifyToLScheduler()), AbstractifyToLScheduler(), ios); } } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/LiveSHT/SchedulerModel.i.dfy ================================================ include "../SHT/HostModel.i.dfy" include "../../Protocol/LiveSHT/Scheduler.i.dfy" include "../../Common/Collections/Seqs.i.dfy" include "../../../Libraries/Math/mod_auto.i.dfy" include "../../Protocol/SHT/Host.i.dfy" include "NetSHT.i.dfy" //include "CBoundedClock.i.dfy" module LiveSHT__SchedulerModel_i { import opened Environment_s import opened SHT__Host_i import opened SHT__HostModel_i import opened SHT__CMessage_i import opened SHT__PacketParsing_i import opened LiveSHT__Scheduler_i import opened LiveSHT__NetSHT_i import opened LiveSHT__Environment_i import opened Common__NodeIdentity_i predicate AllIosAreSends(ios:seq) { forall i :: 0<=i<|ios| ==> ios[i].LIoOpSend? } lemma MapSentPacketToIos_ExtractSentPacketsFromIos_equivalence(sent_packet:CPacket, ios:seq) requires OutboundPacketsIsValid(sent_packet); requires ios == MapSentPacketToIos(sent_packet); ensures [AbstractifyOutboundPacketsToLSHTPacket(sent_packet)] == ExtractSentPacketsFromIos(ios); { reveal_ExtractSentPacketsFromIos(); } lemma MapSentPacketSeqToIos_ExtractSentPacketsFromIos_equivalence(sent_packets:seq, ios:seq) requires OutboundPacketsSeqIsValid(sent_packets); //requires forall i :: 0 <= i < |sent_packets| ==> CPacketIsSendable(sent_packets[i]) && sent_packets[i].msg.CSingleMessage? && CSingleMessageMarshallable(sent_packets[i].msg); requires ios == MapSentPacketSeqToIos(sent_packets); ensures AbstractifyOutboundPacketsToSeqOfLSHTPackets(sent_packets) == ExtractSentPacketsFromIos(ios); { reveal_ExtractSentPacketsFromIos(); reveal_MapSentPacketSeqToIos(); reveal_AbstractifyOutboundPacketsToSeqOfLSHTPackets(); var x := AbstractifyOutboundPacketsToSeqOfLSHTPackets(sent_packets); var y := ExtractSentPacketsFromIos(ios); if (|x| > 0) { MapSentPacketSeqToIos_ExtractSentPacketsFromIos_equivalence(sent_packets[1..], ios[1..]); } } function MapSentPacketToIos(sent_packet:CPacket) : seq requires OutboundPacketsIsValid(sent_packet); { [LIoOpSend(AbstractifyCPacketToLSHTPacket(sent_packet))] } function {:opaque} MapSentPacketSeqToIos(sent_packets:seq) : seq requires OutboundPacketsSeqIsValid(sent_packets); //requires forall i :: 0 <= i < |sent_packets| ==> CPacketIsSendable(sent_packets[i]) && sent_packets[i].msg.CSingleMessage? && CSingleMessageMarshallable(sent_packets[i].msg) ensures |MapSentPacketSeqToIos(sent_packets)| == |sent_packets|; ensures forall i :: 0 <= i < |sent_packets| ==> MapSentPacketSeqToIos(sent_packets)[i] == LIoOpSend(AbstractifyCPacketToLSHTPacket(sent_packets[i])); ensures (forall io :: io in MapSentPacketSeqToIos(sent_packets) ==> io.LIoOpSend?); { //lemma_MapSentPacketSeqToIos(sent_packets); if |sent_packets| == 0 then [] else if |sent_packets| == 1 then [LIoOpSend(AbstractifyCPacketToLSHTPacket(sent_packets[0]))] else [LIoOpSend(AbstractifyCPacketToLSHTPacket(sent_packets[0]))] + MapSentPacketSeqToIos(sent_packets[1..]) } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/LiveSHT/Unsendable.i.dfy ================================================ include "../../Protocol/LiveSHT/Scheduler.i.dfy" include "../SHT/PacketParsing.i.dfy" module LiveSHT__Unsendable_i { import opened Native__NativeTypes_s import opened Native__Io_s import opened Logic__Option_i import opened Environment_s import opened LiveSHT__Scheduler_i import opened SHT__PacketParsing_i import opened SHT__Host_i import opened SHT__Keys_i import opened Common__GenericMarshalling_i predicate IosReflectIgnoringUnDemarshallable(ios:seq>>) { |ios| == 1 && ios[0].LIoOpReceive? // && !Demarshallable(ios[0].r.msg, CSingleMessage_grammar()) && SHTDemarshallData(ios[0].r.msg).CInvalidMessage? } predicate IosReflectIgnoringUnParseable(s:LScheduler, ios:seq>>) { ios == [] && ( s.host.receivedPacket.Some? && s.host.receivedPacket.v.msg.SingleMessage? && s.host.receivedPacket.v.msg.m.Delegate? && var msg := s.host.receivedPacket.v.msg.m; !(ValidKeyRange(msg.range) && ValidHashtable(msg.h) && !EmptyKeyRange(msg.range) && ValidPhysicalAddress(s.host.receivedPacket.v.msg.dst))) } predicate HostNextIgnoreUnsendableReceive(s:LScheduler, s':LScheduler, ios:seq>>) { s.nextActionIndex == 0 && s' == s.(nextActionIndex := 1) && IosReflectIgnoringUnDemarshallable(ios) } predicate IgnoreSchedulerUpdate(s:LScheduler, s':LScheduler) { if ShouldProcessReceivedMessage(s.host) then s' == s.(nextActionIndex := 2, host := s.host.(receivedPacket := None)) else s' == s.(nextActionIndex := 2) } predicate HostNextIgnoreUnsendableProcess(s:LScheduler, s':LScheduler, ios:seq>>) { s.nextActionIndex == 1 && IgnoreSchedulerUpdate(s, s') && IosReflectIgnoringUnParseable(s, ios) } predicate HostNextIgnoreUnsendable(s:LScheduler, s':LScheduler, ios:seq>>) { HostNextIgnoreUnsendableReceive(s, s', ios) || HostNextIgnoreUnsendableProcess(s, s', ios) } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/Lock/CmdLineParser.i.dfy ================================================ include "../Common/CmdLineParser.i.dfy" module LockCmdLineParser_i { import opened Native__NativeTypes_s import opened Native__Io_s import opened Environment_s import opened CmdLineParser_i import opened Common__NetClient_i import opened Common__SeqIsUniqueDef_i function lock_config_parsing(args:seq>) : seq { parse_end_points(args).1 } method ParseCmdLine(id:EndPoint, args:seq>) returns (ok:bool, host_ids:seq, my_index:uint64) requires EndPointIsValidPublicKey(id) ensures ok ==> && 0 <= my_index as int < |host_ids| < 0x1_0000_0000_0000_0000 && host_ids == lock_config_parsing(args) && host_ids[my_index] == id && SeqIsUnique(host_ids) && (forall h :: h in host_ids ==> EndPointIsValidPublicKey(h)) { var tuple1 := parse_end_points(args); ok := tuple1.0; if !ok { return; } host_ids := tuple1.1; if |host_ids| == 0 || |host_ids| >= 0x1_0000_0000_0000_0000 { ok := false; return; } var unique := test_unique(host_ids); if !unique { ok := false; return; } ok, my_index := GetHostIndex(id, host_ids); if !ok { return; } ghost var ghost_host_ids := lock_config_parsing(args); assert host_ids == ghost_host_ids; } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/Lock/Host.i.dfy ================================================ include "../../Common/Framework/Host.s.dfy" include "../../Common/Collections/Sets.i.dfy" include "NodeImpl.i.dfy" include "CmdLineParser.i.dfy" module Host_i refines Host_s { import opened Collections__Sets_i import opened Protocol_Node_i import opened NodeImpl_i import opened CmdLineParser_i import opened LockCmdLineParser_i import opened Types_i import opened Impl_Node_i import opened NetLock_i export Spec provides Native__Io_s, Environment_s, Native__NativeTypes_s provides HostState provides ConcreteConfiguration provides HostInit, HostNext, ConcreteConfigInit, HostStateInvariants provides ConcreteConfigToServers, ParseCommandLineConfiguration, ArbitraryObject provides HostInitImpl, HostNextImpl export All reveals * datatype CScheduler = CScheduler(ghost node:Node, node_impl:NodeImpl) type HostState = CScheduler type ConcreteConfiguration = Config predicate HostStateInvariants(host_state:HostState, env:HostEnvironment) { && host_state.node_impl.Valid() && host_state.node_impl.Env() == env && host_state.node == AbstractifyCNode(host_state.node_impl.node) } predicate HostInit(host_state:HostState, config:ConcreteConfiguration, id:EndPoint) { && host_state.node_impl.Valid() && host_state.node_impl.node.config == config && host_state.node_impl.node.config[host_state.node_impl.node.my_index] == id && NodeInit(host_state.node, host_state.node_impl.node.my_index as int, config) } predicate {:opaque} HostNext(host_state:HostState, host_state':HostState, ios:seq>>) { && NodeNext(host_state.node, host_state'.node, AbstractifyRawLogToIos(ios)) && OnlySentMarshallableData(ios) } predicate ConcreteConfigInit(config:ConcreteConfiguration) { ValidConfig(config) } function ConcreteConfigToServers(config:ConcreteConfiguration) : set { MapSeqToSet(config, x=>x) } function ParseCommandLineConfiguration(args:seq>) : ConcreteConfiguration { lock_config_parsing(args) } method HostInitImpl( ghost env:HostEnvironment, netc:NetClient, args:seq> ) returns ( ok:bool, host_state:HostState ) { var my_index; var node_impl := new NodeImpl(); host_state := CScheduler(AbstractifyCNode(node_impl.node), node_impl); var id := EndPoint(netc.MyPublicKey()); var config; ok, config, my_index := ParseCmdLine(id, args); if !ok { return; } assert id in config; ok := node_impl.InitNode(config, my_index, netc, env); if !ok { return; } host_state := CScheduler(AbstractifyCNode(node_impl.node), node_impl); } predicate EventsConsistent(recvs:seq, clocks:seq, sends:seq) { forall e :: (e in recvs ==> e.LIoOpReceive?) && (e in clocks ==> e.LIoOpReadClock? || e.LIoOpTimeoutReceive?) && (e in sends ==> e.LIoOpSend?) } ghost method RemoveRecvs(events:seq) returns (recvs:seq, rest:seq) ensures forall e :: e in recvs ==> e.LIoOpReceive?; ensures events == recvs + rest; ensures rest != [] ==> !rest[0].LIoOpReceive?; { recvs := []; rest := []; var i := 0; while i < |events| invariant 0 <= i <= |events|; invariant forall e :: e in recvs ==> e.LIoOpReceive?; invariant recvs == events[0..i]; { if !events[i].LIoOpReceive? { rest := events[i..]; return; } recvs := recvs + [events[i]]; i := i + 1; } } predicate NetEventsReductionCompatible(events:seq) { forall i :: 0 <= i < |events| - 1 ==> events[i].LIoOpReceive? || events[i+1].LIoOpSend? } lemma RemainingEventsAreSends(events:seq) requires NetEventsReductionCompatible(events); requires |events| > 0; requires !events[0].LIoOpReceive?; ensures forall e :: e in events[1..] ==> e.LIoOpSend?; { if |events| == 1 { } else { assert events[1].LIoOpSend?; RemainingEventsAreSends(events[1..]); } } ghost method PartitionEvents(events:seq) returns (recvs:seq, clocks:seq, sends:seq) requires NetEventsReductionCompatible(events); ensures events == recvs + clocks + sends; ensures EventsConsistent(recvs, clocks, sends); ensures |clocks| <= 1; { var rest; recvs, rest := RemoveRecvs(events); assert events[|recvs|..] == rest; if |rest| > 0 && (rest[0].LIoOpReadClock? || rest[0].LIoOpTimeoutReceive?) { clocks := [rest[0]]; sends := rest[1..]; RemainingEventsAreSends(rest); } else { clocks := []; sends := rest; if |rest| > 0 { RemainingEventsAreSends(rest); } } } lemma NetEventsRespectReduction(s:Node, s':Node, ios:seq, events:seq) requires LIoOpSeqCompatibleWithReduction(ios); requires AbstractifyRawLogToIos(events) == ios; ensures NetEventsReductionCompatible(events); { //reveal_AbstractifyRawLogToIos(); assert AbstractifyRawLogToIos(events) == ios; forall i | 0 <= i < |events| - 1 ensures events[i].LIoOpReceive? || events[i+1].LIoOpSend?; { assert AbstractifyRawLogToIos(events)[i] == ios[i]; assert AbstractifyRawLogToIos(events)[i+1] == ios[i+1]; } } method HostNextImpl(ghost env:HostEnvironment, host_state:HostState) returns (ok:bool, host_state':HostState, ghost recvs:seq, ghost clocks:seq, ghost sends:seq, ghost ios:seq>>) { var okay, netEventLog, abstract_ios := host_state.node_impl.HostNextMain(); if okay { NetEventsRespectReduction(host_state.node, AbstractifyCNode(host_state.node_impl.node), abstract_ios, netEventLog); recvs, clocks, sends := PartitionEvents(netEventLog); ios := recvs + clocks + sends; assert ios == netEventLog; host_state' := CScheduler(AbstractifyCNode(host_state.node_impl.node), host_state.node_impl); } else { recvs := []; clocks := []; sends := []; host_state' := host_state; } ok := okay; reveal_HostNext(); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/Lock/Message.i.dfy ================================================ include "../../Protocol/Lock/Types.i.dfy" module Message_i { import opened Native__NativeTypes_s import opened Native__Io_s import opened Environment_s import opened Types_i datatype CMessage = CTransfer(transfer_epoch:uint64) | CLocked(locked_epoch:uint64) | CInvalid function AbstractifyCMessage(cmsg:CMessage) : LockMessage { match cmsg { case CTransfer(epoch) => Transfer(epoch as int) case CLocked(epoch) => Locked(epoch as int) case CInvalid => Invalid() } } type CLockPacket = LPacket function AbstractifyCLockPacket(p:CLockPacket) : LockPacket { LPacket(p.dst, p.src, AbstractifyCMessage(p.msg)) } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/Lock/NetLock.i.dfy ================================================ include "../Common/NetClient.i.dfy" include "PacketParsing.i.dfy" module NetLock_i { import opened Native__Io_s import opened Logic__Option_i import opened Environment_s import opened Types_i import opened Message_i import opened Common__Util_i import opened Common__NetClient_i import opened Common__GenericMarshalling_i import opened PacketParsing_i ////////////////////////////////////////////////////////////////////////////// // These functions relate IO events with bytes to those with LockMessages // function AstractifyNetEventToLockIo(evt:NetEvent) : LockIo { match evt case LIoOpSend(s) => LIoOpSend(AbstractifyNetPacket(s)) case LIoOpReceive(r) => LIoOpReceive(AbstractifyNetPacket(r)) case LIoOpTimeoutReceive => LIoOpTimeoutReceive() case LIoOpReadClock(t) => LIoOpReadClock(t as int) } function {:opaque} AbstractifyRawLogToIos(rawlog:seq) : seq ensures |AbstractifyRawLogToIos(rawlog)| == |rawlog|; ensures forall i {:trigger AstractifyNetEventToLockIo(rawlog[i])} {:trigger AbstractifyRawLogToIos(rawlog)[i]} :: 0 <= i < |rawlog| ==> AbstractifyRawLogToIos(rawlog)[i] == AstractifyNetEventToLockIo(rawlog[i]); { if (rawlog==[]) then [] else [AstractifyNetEventToLockIo(rawlog[0])] + AbstractifyRawLogToIos(rawlog[1..]) } lemma lemma_EstablishAbstractifyRawLogToIos(rawlog:seq, ios:seq) requires |rawlog| == |ios|; requires forall i :: 0<=i<|rawlog| ==> ios[i] == AstractifyNetEventToLockIo(rawlog[i]); ensures AbstractifyRawLogToIos(rawlog) == ios; { reveal_AbstractifyRawLogToIos(); } predicate OnlySentMarshallableData(rawlog:seq) { forall io :: io in rawlog && io.LIoOpSend? ==> NetPacketBound(io.s.msg) && Demarshallable(io.s.msg, CMessageGrammar()) } ////////////////////////////////////////////////////////////////////////////// // These methods wrap the raw NetClient interface // datatype ReceiveResult = RRFail() | RRTimeout() | RRPacket(cpacket:CLockPacket) method Receive(netClient:NetClient, localAddr:EndPoint) returns (rr:ReceiveResult, ghost netEvent:NetEvent) requires NetClientIsValid(netClient); requires EndPoint(netClient.MyPublicKey()) == localAddr; modifies NetClientRepr(netClient); ensures netClient.env == old(netClient.env); ensures netClient.MyPublicKey() == old(netClient.MyPublicKey()); ensures NetClientOk(netClient) <==> !rr.RRFail?; ensures old(NetClientRepr(netClient)) == NetClientRepr(netClient); ensures !rr.RRFail? ==> netClient.IsOpen() && old(netClient.env.net.history()) + [netEvent] == netClient.env.net.history(); ensures rr.RRTimeout? ==> netEvent.LIoOpTimeoutReceive?; ensures rr.RRPacket? ==> netEvent.LIoOpReceive? && EndPointIsValidPublicKey(rr.cpacket.src) && AbstractifyCLockPacket(rr.cpacket) == AbstractifyNetPacket(netEvent.r) && rr.cpacket.msg == DemarshallData(netEvent.r.msg) { var timeout := 0; ghost var old_net_history := netClient.env.net.history(); var ok, timedOut, remote, buffer := netClient.Receive(timeout); if (!ok) { rr := RRFail(); return; } if (timedOut) { rr := RRTimeout(); netEvent := LIoOpTimeoutReceive(); return; } var remoteEp:EndPoint := EndPoint(remote); netEvent := LIoOpReceive(LPacket(EndPoint(netClient.MyPublicKey()), remoteEp, buffer[..])); var cmessage := DemarshallDataMethod(buffer); var cpacket := LPacket(localAddr, remoteEp, cmessage); rr := RRPacket(cpacket); } predicate SendLogEntryReflectsPacket(event:NetEvent, cpacket:CLockPacket) { event.LIoOpSend? && AbstractifyCLockPacket(cpacket) == AbstractifyNetPacket(event.s) } predicate SendLogReflectsPacket(netEventLog:seq, packet:Option) { match packet { case Some(p) => |netEventLog| == 1 && SendLogEntryReflectsPacket(netEventLog[0], p) case None => netEventLog == [] } } method SendPacket(netClient:NetClient, opt_packet:Option, ghost localAddr:EndPoint) returns (ok:bool, ghost netEventLog:seq) requires NetClientIsValid(netClient); requires EndPoint(netClient.MyPublicKey()) == localAddr; requires OptionCLockPacketValid(opt_packet); requires opt_packet.Some? ==> opt_packet.v.src == localAddr; modifies NetClientRepr(netClient); ensures old(NetClientRepr(netClient)) == NetClientRepr(netClient); ensures netClient.env == old(netClient.env); ensures netClient.MyPublicKey() == old(netClient.MyPublicKey()); ensures NetClientOk(netClient) <==> ok; ensures ok ==> ( NetClientIsValid(netClient) && netClient.IsOpen() && old(netClient.env.net.history()) + netEventLog == netClient.env.net.history() && OnlySentMarshallableData(netEventLog) && SendLogReflectsPacket(netEventLog, opt_packet)); { netEventLog := []; ok := true; if opt_packet.None? { } else { var cpacket := opt_packet.v; // Construct the remote address var dstEp:EndPoint := cpacket.dst; // Marshall the message var buffer := MarshallLockMessage(cpacket.msg); // Send the packet off ok := netClient.Send(dstEp.public_key, buffer); if (!ok) { return; } ghost var netEvent := LIoOpSend(LPacket(dstEp, EndPoint(netClient.MyPublicKey()), buffer[..])); netEventLog := [netEvent]; } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/Lock/Node.i.dfy ================================================ include "../../Protocol/Lock/Node.i.dfy" include "Message.i.dfy" include "../Common/NetClient.i.dfy" include "../../Common/Logic/Option.i.dfy" include "PacketParsing.i.dfy" include "../Common/SeqIsUniqueDef.i.dfy" module Impl_Node_i { import opened Native__NativeTypes_s import opened Environment_s import opened Protocol_Node_i import opened Types_i import opened Message_i import opened Common__NetClient_i import opened Logic__Option_i import opened PacketParsing_i import opened Common__SeqIsUniqueDef_i datatype CNode = CNode(held:bool, epoch:uint64, my_index:uint64, config:Config) predicate ValidConfig(c:Config) { 0 < |c| < 0x1_0000_0000_0000_0000 && (forall e :: e in c ==> EndPointIsValidPublicKey(e)) && SeqIsUnique(c) } predicate ValidConfigIndex(c:Config, index:uint64) { 0 <= index as int < |c| } predicate CNodeValid(c:CNode) { ValidConfig(c.config) && ValidConfigIndex(c.config, c.my_index) } function AbstractifyCNode(n:CNode) : Node { Node(n.held, n.epoch as int, n.my_index as int, n.config) } method NodeInitImpl(my_index:uint64, config:Config) returns (node:CNode) requires 0 < |config| < 0x1_0000_0000_0000_0000; requires 0 <= my_index as int < |config|; requires ValidConfig(config); ensures CNodeValid(node); ensures NodeInit(AbstractifyCNode(node), my_index as int, config); ensures node.my_index == my_index; ensures node.config == config; { node := CNode(my_index == 0, if my_index == 0 then 1 else 0, my_index, config); if node.held { print "I start holding the lock\n"; } } method NodeGrantImpl(s:CNode) returns (s':CNode, packet:Option, ghost ios:seq) requires CNodeValid(s); ensures NodeGrant(AbstractifyCNode(s), AbstractifyCNode(s'), ios); ensures s'.my_index == s.my_index && s'.config == s.config; ensures |ios| == 0 || |ios| == 1; ensures packet.Some? ==> |ios| == 1 && ios[0].LIoOpSend? && ios[0].s == AbstractifyCLockPacket(packet.v); ensures OptionCLockPacketValid(packet) && (packet.Some? ==> packet.v.src == s.config[s.my_index]); ensures packet.None? ==> ios == [] && s' == s; ensures CNodeValid(s'); { if s.held && s.epoch < 0xFFFF_FFFF_FFFF_FFFF { var ssss := CNode(false, s.epoch, s.my_index, s.config); s' := ssss; var dst_index := (s.my_index + 1) % (|s.config| as uint64); packet := Some(LPacket(s.config[dst_index], s.config[s.my_index], CTransfer(s.epoch + 1))); ios := [LIoOpSend(AbstractifyCLockPacket(packet.v))]; print "I grant the lock ", s.epoch, "\n"; } else { s' := s; ios := []; packet := None(); } } method NodeAcceptImpl(s:CNode, transfer_packet:CLockPacket) returns (s':CNode, locked_packet:Option, ghost ios:seq) requires CNodeValid(s); ensures NodeAccept(AbstractifyCNode(s), AbstractifyCNode(s'), ios); ensures s'.my_index == s.my_index && s'.config == s.config; ensures |ios| == 1 || |ios| == 2; ensures locked_packet.None? ==> |ios| == 1 && ios[0].LIoOpReceive? && ios[0].r == AbstractifyCLockPacket(transfer_packet); ensures locked_packet.Some? ==> |ios| == 2 && ios == [LIoOpReceive(AbstractifyCLockPacket(transfer_packet)), LIoOpSend(AbstractifyCLockPacket(locked_packet.v))]; ensures OptionCLockPacketValid(locked_packet) && (locked_packet.Some? ==> locked_packet.v.src == s.config[s.my_index]); ensures CNodeValid(s'); { ios := [LIoOpReceive(AbstractifyCLockPacket(transfer_packet))]; if !s.held && transfer_packet.src in s.config && transfer_packet.msg.CTransfer? && transfer_packet.msg.transfer_epoch > s.epoch { var ssss := CNode(true, transfer_packet.msg.transfer_epoch, s.my_index, s.config); s' := ssss; locked_packet := Some(LPacket(transfer_packet.src, s.config[s.my_index], CLocked(transfer_packet.msg.transfer_epoch))); ios := ios + [LIoOpSend(AbstractifyCLockPacket(locked_packet.v))]; print "I hold the lock!\n"; } else { s' := s; locked_packet := None(); } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/Lock/NodeImpl.i.dfy ================================================ include "Node.i.dfy" include "NetLock.i.dfy" module NodeImpl_i { import opened Native__NativeTypes_s import opened Native__Io_s import opened Environment_s import opened Types_i import opened Message_i import opened Impl_Node_i import opened NetLock_i import opened Protocol_Node_i import opened Common__Util_i import opened Common__NetClient_i class NodeImpl { var node:CNode; var netClient:NetClient?; var localAddr:EndPoint; ghost var Repr : set; constructor () { netClient := null; } predicate Valid() reads this; reads NetClientIsValid.reads(netClient); { CNodeValid(node) && NetClientIsValid(netClient) && EndPoint(netClient.MyPublicKey()) == localAddr && localAddr == node.config[node.my_index] && Repr == { this } + NetClientRepr(netClient) } function Env() : HostEnvironment? reads this, NetClientIsValid.reads(netClient); { if netClient!=null then netClient.env else null } method InitNode(config:Config, my_index:uint64, nc:NetClient, ghost env_:HostEnvironment) returns (ok:bool) requires env_.Valid() && env_.ok.ok() requires ValidConfig(config) && ValidConfigIndex(config, my_index) requires NetClientIsValid(nc) requires EndPoint(nc.MyPublicKey()) == config[my_index] requires nc.env == env_ modifies this ensures ok ==> Valid() && Env() == env_ && NodeInit(AbstractifyCNode(node), my_index as int, config) && node.config == config && node.my_index == my_index { netClient := nc; node := NodeInitImpl(my_index, config); assert node.my_index == my_index; localAddr := node.config[my_index]; Repr := { this } + NetClientRepr(netClient); ok := true; } method NodeNextGrant() returns (ok:bool, ghost netEventLog:seq, ghost ios:seq) requires Valid(); modifies Repr; ensures Repr == old(Repr); ensures ok == NetClientOk(netClient); ensures Env() == old(Env()); ensures ok ==> ( Valid() && NodeGrant(old(AbstractifyCNode(node)), AbstractifyCNode(node), ios) && AbstractifyRawLogToIos(netEventLog) == ios && OnlySentMarshallableData(netEventLog) && old(Env().net.history()) + netEventLog == Env().net.history()); { var transfer_packet; node, transfer_packet, ios := NodeGrantImpl(node); ok := true; if transfer_packet.Some? { ghost var sendEventLog; ok, sendEventLog := SendPacket(netClient, transfer_packet, localAddr); netEventLog := sendEventLog; } else { netEventLog := []; assert AbstractifyRawLogToIos(netEventLog) == ios; } } method NodeNextAccept() returns (ok:bool, ghost netEventLog:seq, ghost ios:seq) requires Valid(); modifies Repr; ensures Repr == old(Repr); ensures ok == NetClientOk(netClient); ensures Env() == old(Env()); ensures ok ==> ( Valid() && NodeAccept(old(AbstractifyCNode(node)), AbstractifyCNode(node), ios) && AbstractifyRawLogToIos(netEventLog) == ios && OnlySentMarshallableData(netEventLog) && old(Env().net.history()) + netEventLog == Env().net.history()); { var rr; ghost var receiveEvent; rr, receiveEvent := Receive(netClient, localAddr); netEventLog := [ receiveEvent ]; if (rr.RRFail?) { ok := false; return; } else if (rr.RRTimeout?) { ok := true; ios := [ LIoOpTimeoutReceive() ]; return; } else { ok := true; var locked_packet; node, locked_packet, ios := NodeAcceptImpl(node, rr.cpacket); if locked_packet.Some? { ghost var sendEventLog; ok, sendEventLog := SendPacket(netClient, locked_packet, localAddr); netEventLog := netEventLog + sendEventLog; } } } method HostNextMain() returns (ok:bool, ghost netEventLog:seq, ghost ios:seq) requires Valid(); modifies Repr; ensures Repr == old(Repr); ensures ok <==> Env() != null && Env().Valid() && Env().ok.ok(); ensures Env() == old(Env()); ensures ok ==> ( Valid() && NodeNext(old(AbstractifyCNode(node)), AbstractifyCNode(node), ios) && AbstractifyRawLogToIos(netEventLog) == ios && OnlySentMarshallableData(netEventLog) && old(Env().net.history()) + netEventLog == Env().net.history() ); { if node.held { ok, netEventLog, ios := NodeNextGrant(); } else { ok, netEventLog, ios := NodeNextAccept(); } } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/Lock/PacketParsing.i.dfy ================================================ include "../Common/GenericMarshalling.i.dfy" include "../Common/NetClient.i.dfy" include "Message.i.dfy" module PacketParsing_i { import opened Native__NativeTypes_s import opened Native__Io_s import opened Logic__Option_i import opened Environment_s import opened Common__GenericMarshalling_i import opened Common__NetClient_i import opened Types_i import opened Message_i predicate NetPacketBound(data:seq) { |data| < MaxPacketSize() } //////////////////////////////////////////////////////////////////// // Grammars for the Lock messages //////////////////////////////////////////////////////////////////// function method CMessageTransferGrammar() : G { GUint64 } function method CMessageLockedGrammar() : G { GUint64 } function method CMessageGrammar() : G { GTaggedUnion([CMessageTransferGrammar(), CMessageLockedGrammar()]) } //////////////////////////////////////////////////////////////////// // Parsing //////////////////////////////////////////////////////////////////// function method ParseCMessageTransfer(val:V) : CMessage requires ValInGrammar(val, CMessageTransferGrammar()); { CTransfer(val.u) } function method ParseCMessageLocked(val:V) : CMessage requires ValInGrammar(val, CMessageLockedGrammar()); { CLocked(val.u) } function method ParseCMessage(val:V) : CMessage requires ValInGrammar(val, CMessageGrammar()); { if val.c == 0 then ParseCMessageTransfer(val.val) else ParseCMessageLocked(val.val) } function DemarshallData(data:seq) : CMessage { if Demarshallable(data, CMessageGrammar()) then var val := DemarshallFunc(data, CMessageGrammar()); ParseCMessage(val) else CInvalid() } method DemarshallDataMethod(data:array) returns (msg:CMessage) requires data.Length < 0x1_0000_0000_0000_0000; ensures msg == DemarshallData(data[..]); // ensures if Demarshallable(data[..], msg_grammar) then // msg == PaxosDemarshallData(data[..]) // else msg.CMessage_Invalid?; // ensures CMessageIs64Bit(msg); { var success, val := Demarshall(data, CMessageGrammar()); if success { //assert ValInGrammar(val, msg_grammar); msg := ParseCMessage(val); assert !msg.CInvalid?; } else { msg := CInvalid(); } } //////////////////////////////////////////////////////////////////// // Marshalling //////////////////////////////////////////////////////////////////// method MarshallMessageTransfer(c:CMessage) returns (val:V) requires c.CTransfer?; ensures ValInGrammar(val, CMessageTransferGrammar()); ensures ValidVal(val); ensures ParseCMessageTransfer(val) == c; ensures SizeOfV(val) < MaxPacketSize(); { val := VUint64(c.transfer_epoch); } method MarshallMessageLocked(c:CMessage) returns (val:V) requires c.CLocked?; ensures ValInGrammar(val, CMessageLockedGrammar()); ensures ValidVal(val); ensures ParseCMessageLocked(val) == c; ensures SizeOfV(val) < MaxPacketSize(); { val := VUint64(c.locked_epoch); } method MarshallMessage(c:CMessage) returns (val:V) requires !c.CInvalid?; ensures ValInGrammar(val, CMessageGrammar()); ensures ValidVal(val); ensures ParseCMessage(val) == c; ensures SizeOfV(val) < MaxPacketSize(); { if c.CTransfer? { var msg := MarshallMessageTransfer(c); val := VCase(0, msg); } else if c.CLocked? { var msg := MarshallMessageLocked(c); val := VCase(1, msg); } else { assert false; // Provably will not reach here } } method MarshallLockMessage(msg:CMessage) returns (data:array) requires !msg.CInvalid?; ensures fresh(data); ensures NetPacketBound(data[..]); ensures DemarshallData(data[..]) == msg; { var val := MarshallMessage(msg); data := Marshall(val, CMessageGrammar()); } //////////////////////////////////////////////////////////////////// // Packet translation //////////////////////////////////////////////////////////////////// function AbstractifyNetPacket(net:NetPacket) : LockPacket { LPacket(net.dst, net.src, AbstractifyCMessage(DemarshallData(net.msg))) } predicate CLockPacketValid(p:CLockPacket) { EndPointIsValidPublicKey(p.src) && EndPointIsValidPublicKey(p.dst) && !p.msg.CInvalid? } predicate OptionCLockPacketValid(opt_packet:Option) { opt_packet.Some? ==> CLockPacketValid(opt_packet.v) } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/RSL/AcceptorModel.i.dfy ================================================ include "AcceptorState.i.dfy" include "Broadcast.i.dfy" include "../Common/Util.i.dfy" module LiveRSL__AcceptorModel_i { import opened Native__Io_s import opened Native__NativeTypes_s import opened LiveRSL__Acceptor_i import opened LiveRSL__AcceptorState_i import opened LiveRSL__CLastCheckpointedMap_i import opened LiveRSL__CMessage_i import opened LiveRSL__CMessageRefinements_i import opened LiveRSL__Configuration_i import opened LiveRSL__CPaxosConfiguration_i import opened LiveRSL__CTypes_i import opened LiveRSL__Environment_i import opened LiveRSL__Message_i import opened LiveRSL__PacketParsing_i import opened LiveRSL__ParametersState_i import opened LiveRSL__ReplicaConstantsState_i import opened LiveRSL__Types_i import opened Impl__LiveRSL__Broadcast_i import opened Collections__Maps_i import opened Collections__Maps2_s import opened Collections__Sets_i import opened Common__NodeIdentity_i import opened Common__UpperBound_s import opened Common__UpperBound_i import opened Common__Util_i import opened Environment_s method CreateSeq(len:int, init_int:uint64) returns (s:seq) requires len >= 0 ensures |s| == len && forall i :: 0 <= i < |s| ==> s[i] == COperationNumber(init_int) { if len == 0 { s := []; } else { var rest := CreateSeq(len - 1, init_int); s := [COperationNumber(init_int)] + rest; } } method DummyInitLastCheckpointedOperation(config:CPaxosConfiguration) returns (ilco:CLastCheckpointedMap) requires CPaxosConfigurationIsValid(config) requires CPaxosConfigurationIsAbstractable(config) ensures CLastCheckpointedMapIsAbstractable(ilco) ensures LMinQuorumSize(AbstractifyCPaxosConfigurationToConfiguration(config)) <= |ilco| ensures |config.replica_ids| == |ilco| ensures forall i :: 0 <= i < |ilco| ==> ilco[i] == COperationNumber(0) { ilco := CreateSeq(|config.replica_ids|, 0); ghost var rlco := AbstractifyCLastCheckpointedMapToOperationNumberSequence(ilco); // TRIGGER reveal AbstractifyCLastCheckpointedMapToOperationNumberSequence(); } method {:timeLimitMultiplier 2} InitAcceptorState(rcs:ReplicaConstantsState) returns (acceptor:AcceptorState) requires ReplicaConstantsState_IsValid(rcs) ensures NextAcceptorState_InitPostconditions(acceptor, rcs) { reveal AbstractifyCVotesToVotes(); var max_ballot := CBallot(0, 0); var votes := CVotes(map []); var last_checkpointed_operation := DummyInitLastCheckpointedOperation(rcs.all.config); var log_truncation_point := COperationNumber(0); var min_voted_opn := COperationNumber(0); acceptor := AcceptorState( rcs, max_ballot, votes, last_checkpointed_operation, log_truncation_point, min_voted_opn); assert LAcceptorInit(AbstractifyAcceptorStateToAcceptor(acceptor), AbstractifyReplicaConstantsStateToLReplicaConstants(rcs)); } method NextAcceptorState_Phase1(acceptor:AcceptorState, in_msg:CMessage, sender:EndPoint) returns (acceptor':AcceptorState, packets_sent:CBroadcast) requires NextAcceptorState_Phase1Preconditions(acceptor, in_msg, sender) ensures NextAcceptorState_Phase1Postconditions(acceptor, acceptor', in_msg, sender, packets_sent) { //print("NextAcceptorState_Phase1: Responding to an 1a message\n"); packets_sent := CBroadcastNop; var ballot := in_msg.bal_1a; lemma_AbstractifyEndPointsToNodeIdentities_properties(acceptor.constants.all.config.replica_ids); // if the ballot is not greater if (!CBallotIsLessThan(acceptor.maxBallot, ballot)) { //print("NextAcceptorState_Phase1: Ignoring the 1a message because I'm in ", acceptor.maxBallot.seqno, acceptor.maxBallot.proposer_id, " but the ballot is ", ballot.seqno, ballot.proposer_id, "\n"); acceptor' := acceptor; return; } if (sender !in acceptor.constants.all.config.replica_ids) { //print("NextAcceptorState_Phase1: Ignoring the 1a message because it's from a non-replica ", sender.addr, sender.port, "\n"); acceptor' := acceptor; return; } //print("NextAcceptorState_Phase1: Sending a 1b message for ballot ", ballot, "\n"); var outMsg := CMessage_1b(ballot, acceptor.log_truncation_point, acceptor.votes); packets_sent := CBroadcast(acceptor.constants.all.config.replica_ids[acceptor.constants.my_index], [sender], outMsg); acceptor' := acceptor.(maxBallot := ballot); ghost var r_packet := AbstractifyCMessageToRslPacket(acceptor.constants.all.config.replica_ids[acceptor.constants.my_index], sender, in_msg); ghost var r_constants := AbstractifyReplicaConstantsStateToLReplicaConstants(acceptor.constants); ghost var dsts := [acceptor.constants.all.config.replica_ids[acceptor.constants.my_index]]; calc { AbstractifyCBroadcastToRlsPacketSeq(packets_sent); [ LPacket(AbstractifyEndPointToNodeIdentity(sender), AbstractifyEndPointsToNodeIdentities(dsts)[0], AbstractifyCMessageToRslMessage(outMsg)) ]; [ LPacket(AbstractifyEndPointToNodeIdentity(sender), AbstractifyEndPointToNodeIdentity(acceptor.constants.all.config.replica_ids[acceptor.constants.my_index]), AbstractifyCMessageToRslMessage(outMsg)) ]; [ LPacket(r_packet.src, r_constants.all.config.replica_ids[r_constants.my_index], AbstractifyCMessageToRslMessage(outMsg)) ]; [ LPacket(r_packet.src, r_constants.all.config.replica_ids[r_constants.my_index], RslMessage_1b(r_packet.msg.bal_1a, AbstractifyCOperationNumberToOperationNumber(acceptor.log_truncation_point), AbstractifyCVotesToVotes(acceptor.votes))) ]; } assert NextAcceptorState_Phase1Postconditions(acceptor, acceptor', in_msg, sender, packets_sent); } lemma lemma_AcceptorVotesSizeIsBoundedByLogLength( votes:CVotes, log_truncation_point:COperationNumber, params:ParametersState ) requires params.max_log_length > 0 requires forall opn :: opn in votes.v ==> AbstractifyCOperationNumberToOperationNumber(log_truncation_point) <= AbstractifyCOperationNumberToOperationNumber(opn) <= UpperBoundedAddition(AbstractifyCOperationNumberToOperationNumber(log_truncation_point), (params.max_log_length-1) as int, UpperBoundFinite(params.max_integer_val as int)) ensures |votes.v| <= params.max_log_length as int { var copns := mapdomain(votes.v); var opns := AbstractifyCOperationNumbersToOperationNumbers(copns); lemma_AbstractifyCOperationNumbersToOperationNumbers_maintainsSize(copns); lemma_CardinalityOfBoundedSet(opns, AbstractifyCOperationNumberToOperationNumber(log_truncation_point), AbstractifyCOperationNumberToOperationNumber(log_truncation_point) + (params.max_log_length as int)); lemma_MapSizeIsDomainSize(mapdomain(votes.v), votes.v); } method AddVoteAndRemoveOldOnesImpl(acceptor:AcceptorState, votes:CVotes, new_opn:COperationNumber, new_vote:CVote, newLogTruncationPoint:COperationNumber, minVotedOpn:COperationNumber, ghost oldLogTruncationPoint:COperationNumber, ghost params:ParametersState) returns (votes':CVotes, newMinVotedOpn:COperationNumber) requires CVotesIsAbstractable(votes) requires COperationNumberIsAbstractable(new_opn) requires CVoteIsAbstractable(new_vote) requires COperationNumberIsAbstractable(newLogTruncationPoint) requires newLogTruncationPoint.n <= params.max_integer_val requires new_opn.n <= params.max_integer_val requires newLogTruncationPoint.n <= new_opn.n requires params.max_integer_val > params.max_log_length > 0 requires newLogTruncationPoint.n >= oldLogTruncationPoint.n requires params.max_log_length as int < max_votes_len() requires AbstractifyCOperationNumberToOperationNumber(new_opn) <= AbstractifyCOperationNumberToOperationNumber(newLogTruncationPoint) + ((params.max_log_length-1) as int) requires forall opn :: opn in votes.v ==> AbstractifyCOperationNumberToOperationNumber(oldLogTruncationPoint) <= AbstractifyCOperationNumberToOperationNumber(opn) <= UpperBoundedAddition(AbstractifyCOperationNumberToOperationNumber(oldLogTruncationPoint), (params.max_log_length-1) as int, UpperBoundFinite(params.max_integer_val as int)) requires ValidVotes(votes) requires ValidVote(new_vote) requires AcceptorIsValid(acceptor) requires votes == acceptor.votes requires minVotedOpn == acceptor.minVotedOpn ensures forall opn :: opn in votes'.v ==> AbstractifyCOperationNumberToOperationNumber(newLogTruncationPoint) <= AbstractifyCOperationNumberToOperationNumber(opn) <= UpperBoundedAddition(AbstractifyCOperationNumberToOperationNumber(newLogTruncationPoint), (params.max_log_length-1) as int, UpperBoundFinite(params.max_integer_val as int)) ensures CVotesIsAbstractable(votes') ensures ValidVotes(votes') ensures LAddVoteAndRemoveOldOnes(AbstractifyCVotesToVotes(votes), AbstractifyCVotesToVotes(votes'), AbstractifyCOperationNumberToOperationNumber(new_opn), AbstractifyCVoteToVote(new_vote), AbstractifyCOperationNumberToOperationNumber(newLogTruncationPoint)) ensures forall v :: v in votes'.v ==> v.n >= newMinVotedOpn.n { reveal AbstractifyCVotesToVotes(); var updated_votes := votes.v[new_opn := new_vote]; var new_votes; if (newLogTruncationPoint.n > minVotedOpn.n) { //print("Creating new table, going to ",newLogTruncationPoint.n," up from ",minVotedOpn.n,"\n"); new_votes := (map op | op in updated_votes && op.n >= newLogTruncationPoint.n :: updated_votes[op]); newMinVotedOpn := newLogTruncationPoint; } else { new_votes := updated_votes; if( new_opn.n < minVotedOpn.n) { newMinVotedOpn := new_opn; } else { newMinVotedOpn := minVotedOpn; } } votes' := CVotes(new_votes); lemma_MapSizeIsDomainSize(domain(updated_votes), updated_votes); lemma_MapSizeIsDomainSize(domain(new_votes), new_votes); SubsetCardinality(domain(new_votes),domain(votes'.v)); forall opn | opn in votes'.v ensures AbstractifyCOperationNumberToOperationNumber(newLogTruncationPoint) <= AbstractifyCOperationNumberToOperationNumber(opn) <= UpperBoundedAddition(AbstractifyCOperationNumberToOperationNumber(newLogTruncationPoint), (params.max_log_length-1) as int, UpperBoundFinite(params.max_integer_val as int)) { if opn == new_opn { assert AbstractifyCOperationNumberToOperationNumber(opn) <= UpperBoundedAddition(AbstractifyCOperationNumberToOperationNumber(newLogTruncationPoint), (params.max_log_length-1) as int, UpperBoundFinite(params.max_integer_val as int)); } } lemma_AcceptorVotesSizeIsBoundedByLogLength(votes', newLogTruncationPoint, params); assert |votes'.v| < 0x1_0000_0000; } method {:timeLimitMultiplier 2} NextAcceptorState_Phase2(acceptor:AcceptorState, in_msg:CMessage, sender:EndPoint) returns (acceptor':AcceptorState, packets_sent:CBroadcast) requires NextAcceptorState_Phase2Preconditions(acceptor, in_msg, sender) ensures NextAcceptorState_Phase2Postconditions(acceptor, acceptor', in_msg, sender, packets_sent) { var start_time := Time.GetDebugTimeTicks(); // reveal AbstractifyCVotesToVotes(); packets_sent := CBroadcastNop; acceptor' := acceptor; var ballot := in_msg.bal_2a; //print("Acceptor receiving 2a message about operation", in_msg.opn_2a.n, "in ballot", in_msg.bal_2a, "\n"); assert acceptor.constants.all.params.max_integer_val > acceptor.constants.all.params.max_log_length > 0; var maxLogLengthMinus1:uint64 := acceptor.constants.all.params.max_log_length - 1; var newLogTruncationPoint := acceptor.log_truncation_point; if in_msg.opn_2a.n >= maxLogLengthMinus1 { var potentialNewTruncationPoint:uint64 := in_msg.opn_2a.n - maxLogLengthMinus1; if potentialNewTruncationPoint > acceptor.log_truncation_point.n { newLogTruncationPoint := COperationNumber(potentialNewTruncationPoint); } } assert AbstractifyCOperationNumberToOperationNumber(newLogTruncationPoint) == if AbstractifyCOperationNumberToOperationNumber(in_msg.opn_2a) - (acceptor.constants.all.params.max_log_length as int) + 1 > AbstractifyCOperationNumberToOperationNumber(acceptor.log_truncation_point) then AbstractifyCOperationNumberToOperationNumber(in_msg.opn_2a) - (acceptor.constants.all.params.max_log_length as int) + 1 else AbstractifyCOperationNumberToOperationNumber(acceptor.log_truncation_point); var addition := UpperBoundedAdditionImpl(acceptor.log_truncation_point.n, acceptor.constants.all.params.max_log_length, acceptor.constants.all.params.max_integer_val); assert AbstractifyCOperationNumberToOperationNumber(in_msg.opn_2a) <= UpperBoundedAddition(AbstractifyCOperationNumberToOperationNumber(newLogTruncationPoint), (acceptor.constants.all.params.max_log_length-1) as int, UpperBoundFinite(acceptor.constants.all.params.max_integer_val as int)); var opn := in_msg.opn_2a; var value := in_msg.val_2a; var newVote := CVote(ballot, value); var votes', newMinVotedOpn; if(acceptor.log_truncation_point.n <= in_msg.opn_2a.n) { votes', newMinVotedOpn := AddVoteAndRemoveOldOnesImpl(acceptor, acceptor.votes, opn, newVote, newLogTruncationPoint, acceptor.minVotedOpn, acceptor.log_truncation_point /* ghost */, acceptor.constants.all.params /* ghost */); } else { votes' := acceptor.votes; newMinVotedOpn := acceptor.minVotedOpn; } var outMsg := CMessage_2b(ballot, opn, value); acceptor' := acceptor.( votes := votes', maxBallot := ballot, log_truncation_point := newLogTruncationPoint, minVotedOpn := newMinVotedOpn); packets_sent := BuildBroadcastToEveryone(acceptor.constants.all.config, acceptor.constants.my_index, outMsg); assert NextAcceptorState_Phase2Postconditions(acceptor, acceptor', in_msg, sender, packets_sent); var end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("NextAcceptorState_Phase2", start_time, end_time); } method {:timeLimitMultiplier 1} NextAcceptorState_ProcessHeartbeat(acceptor:AcceptorState, in_msg:CMessage, sender:EndPoint) returns (acceptor':AcceptorState) requires NextAcceptorState_ProcessHeartbeatPreconditions(acceptor, in_msg, sender) ensures NextAcceptorState_ProcessHeartbeatPostconditions(acceptor, acceptor', in_msg, sender) { acceptor' := acceptor; lemma_AbstractifyEndPointsToNodeIdentities_properties(acceptor.constants.all.config.replica_ids); lemma_AbstractifyEndPointToNodeIdentity_injective_forall(); var found:bool, index:uint64 := CGetReplicaIndex(sender, acceptor.constants.all.config); if (!found) { //print("Acceptor ignoring heartbeat from", sender, "\n"); return; } ///assert AbstractifyEndPointToNodeIdentity(sender) in AbstractifyCLastCheckpointedMapToOperationNumberSequence(acceptor.last_checkpointed_operation); assert 0 <= index as int < |acceptor.constants.all.config.replica_ids|; if (in_msg.opn_ckpt.n <= acceptor.last_checkpointed_operation[index].n) { return; } //print("Acceptor updating last checkpointed operation for", sender, "to", in_msg.opn_ckpt.n, "\n"); var LCO := acceptor.last_checkpointed_operation; var newLCO := acceptor.last_checkpointed_operation[index as int := in_msg.opn_ckpt]; acceptor' := acceptor.(last_checkpointed_operation:= newLCO); } method {:timeLimitMultiplier 1} NextAcceptorState_TruncateLog(acceptor:AcceptorState, opn:COperationNumber) returns (acceptor':AcceptorState) requires NextAcceptorState_TruncateLogPreconditions(acceptor, opn) ensures NextAcceptorState_TruncateLogPostconditions(acceptor, acceptor', opn) { //print("Acceptor truncating log to", opn, "\n"); if (opn.n > acceptor.log_truncation_point.n) { assert AbstractifyCOperationNumberToOperationNumber(opn) > AbstractifyCOperationNumberToOperationNumber(acceptor.log_truncation_point); reveal AbstractifyCVotesToVotes(); var truncatedVotes:map := (map op | op in acceptor.votes.v && op.n >= opn.n :: acceptor.votes.v[op]); acceptor' := acceptor.(log_truncation_point := opn, votes := acceptor.votes.(v := truncatedVotes)); lemma_MapSizeIsDomainSize(domain(truncatedVotes), truncatedVotes); lemma_MapSizeIsDomainSize(domain(acceptor.votes.v), acceptor.votes.v); SubsetCardinality(domain(truncatedVotes),domain(acceptor.votes.v)); } else { acceptor' := acceptor; } } method AcceptorModel_GetNthHighestValueAmongReportedCheckpoints(acceptor:AcceptorState, minQuorumSize:uint64) returns (opn:COperationNumber) requires AcceptorIsValid(acceptor) requires AcceptorIsAbstractable(acceptor) requires minQuorumSize > 0 requires minQuorumSize as int <= |acceptor.last_checkpointed_operation| requires LMinQuorumSize(AbstractifyAcceptorStateToAcceptor(acceptor).constants.all.config) == minQuorumSize as int ensures IsLogTruncationPointValid(AbstractifyCOperationNumberToOperationNumber(opn), AbstractifyAcceptorStateToAcceptor(acceptor).last_checkpointed_operation, AbstractifyAcceptorStateToAcceptor(acceptor).constants.all.config) { opn := ComputeNthHighestValue(acceptor.last_checkpointed_operation, minQuorumSize); //print("Acceptor computes nth highest value as", opn, "\n"); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/RSL/AcceptorState.i.dfy ================================================ include "../../Protocol/RSL/Acceptor.i.dfy" include "PacketParsing.i.dfy" include "ReplicaConstantsState.i.dfy" include "CLastCheckpointedMap.i.dfy" module LiveRSL__AcceptorState_i { import opened Native__Io_s import opened Native__NativeTypes_s import opened LiveRSL__Acceptor_i import opened LiveRSL__Broadcast_i import opened LiveRSL__CLastCheckpointedMap_i import opened LiveRSL__CMessage_i import opened LiveRSL__CMessageRefinements_i import opened LiveRSL__Configuration_i import opened LiveRSL__CPaxosConfiguration_i import opened LiveRSL__CTypes_i import opened LiveRSL__PacketParsing_i import opened LiveRSL__ReplicaConstantsState_i import opened Common__UpperBound_s datatype AcceptorState = AcceptorState( constants:ReplicaConstantsState, maxBallot:CBallot, votes:CVotes, last_checkpointed_operation:CLastCheckpointedMap, log_truncation_point:COperationNumber, minVotedOpn:COperationNumber ) predicate AcceptorIsAbstractable(acceptor:AcceptorState) { && ReplicaConstantsStateIsAbstractable(acceptor.constants) && CBallotIsAbstractable(acceptor.maxBallot) && CVotesIsAbstractable(acceptor.votes) && CLastCheckpointedMapIsAbstractable(acceptor.last_checkpointed_operation) && COperationNumberIsAbstractable(acceptor.log_truncation_point) && ReplicaConstantsStateIsAbstractable(acceptor.constants) } function AbstractifyAcceptorStateToAcceptor(acceptor:AcceptorState) : LAcceptor requires AcceptorIsAbstractable(acceptor); { LAcceptor( // AbstractifyEndPointToNodeIdentity(acceptor.constants.me), AbstractifyReplicaConstantsStateToLReplicaConstants(acceptor.constants), AbstractifyCBallotToBallot(acceptor.maxBallot), AbstractifyCVotesToVotes(acceptor.votes), AbstractifyCLastCheckpointedMapToOperationNumberSequence(acceptor.last_checkpointed_operation), AbstractifyCOperationNumberToOperationNumber(acceptor.log_truncation_point)) } predicate VotedMinimum(acceptor:AcceptorState) { forall v :: v in acceptor.votes.v ==> v.n >= acceptor.minVotedOpn.n } predicate AcceptorIsValid(acceptor:AcceptorState) { && ReplicaConstantsState_IsValid(acceptor.constants) && acceptor.constants.all.config.replica_ids == acceptor.constants.all.config.replica_ids && ValidVotes(acceptor.votes) && acceptor.constants.all.params.max_integer_val > acceptor.constants.all.params.max_log_length > 0 && (forall opn :: opn in acceptor.votes.v ==> AbstractifyCOperationNumberToOperationNumber(acceptor.log_truncation_point) <= AbstractifyCOperationNumberToOperationNumber(opn) <= UpperBoundedAddition(AbstractifyCOperationNumberToOperationNumber(acceptor.log_truncation_point), (acceptor.constants.all.params.max_log_length-1) as int, UpperBoundFinite(acceptor.constants.all.params.max_integer_val as int))) && AcceptorIsAbstractable(acceptor) && LMinQuorumSize(AbstractifyAcceptorStateToAcceptor(acceptor).constants.all.config) <= |acceptor.last_checkpointed_operation| && VotedMinimum(acceptor) && |acceptor.last_checkpointed_operation| == |acceptor.constants.all.config.replica_ids| } predicate NextAcceptorState_InitPostconditions(acceptor:AcceptorState, rcs:ReplicaConstantsState) requires ReplicaConstantsState_IsValid(rcs) { && AcceptorIsValid(acceptor) && AcceptorIsAbstractable(acceptor) && acceptor.constants == rcs && LAcceptorInit(AbstractifyAcceptorStateToAcceptor(acceptor), AbstractifyReplicaConstantsStateToLReplicaConstants(rcs)) } predicate ConstantsStayConstant(acceptor:AcceptorState, acceptor':AcceptorState) // requires AcceptorIsAbstractable(acceptor) // requires AcceptorIsAbstractable(acceptor') // requires ReplicaConstantsStateIsAbstractable(acceptor.constants) // requires ReplicaConstantsStateIsAbstractable(acceptor'.constants) { // AbstractifyAcceptorStateToAcceptor(acceptor).constants == AbstractifyAcceptorStateToAcceptor(acceptor').constants acceptor.constants == acceptor'.constants } predicate CommonAcceptorPreconditions(acceptor:AcceptorState, in_msg:CMessage, sender:EndPoint) { && AcceptorIsValid(acceptor) && AcceptorIsAbstractable(acceptor) && ReplicaConstantsState_IsValid(acceptor.constants) && CMessageIsValid(in_msg) && CMessageIsAbstractable(in_msg) && PaxosEndPointIsValid(sender, acceptor.constants.all.config) } predicate CommonAcceptorPostconditions(acceptor:AcceptorState, acceptor':AcceptorState, packets_sent:CBroadcast) requires AcceptorIsValid(acceptor) requires AcceptorIsAbstractable(acceptor) { && AcceptorIsValid(acceptor') && AcceptorIsAbstractable(acceptor') && ConstantsStayConstant(acceptor, acceptor') && CBroadcastIsValid(packets_sent) && (packets_sent.CBroadcast? ==> packets_sent.src == acceptor.constants.all.config.replica_ids[acceptor.constants.my_index]) } predicate NextAcceptorState_Phase1Preconditions(acceptor:AcceptorState, in_msg:CMessage, sender:EndPoint) { && CommonAcceptorPreconditions(acceptor, in_msg, sender) && in_msg.CMessage_1a? } predicate NextAcceptorState_Phase1Postconditions(acceptor:AcceptorState, acceptor':AcceptorState, in_msg:CMessage, sender:EndPoint, packets_sent:CBroadcast) { && NextAcceptorState_Phase1Preconditions(acceptor, in_msg, sender) && CommonAcceptorPostconditions(acceptor, acceptor', packets_sent) && LAcceptorProcess1a( AbstractifyAcceptorStateToAcceptor(acceptor), AbstractifyAcceptorStateToAcceptor(acceptor'), AbstractifyCMessageToRslPacket(acceptor.constants.all.config.replica_ids[acceptor.constants.my_index], sender, in_msg), AbstractifyCBroadcastToRlsPacketSeq(packets_sent)) } predicate NextAcceptorState_Phase2Preconditions_AlwaysEnabled(acceptor:AcceptorState, in_msg:CMessage, sender:EndPoint) { && CommonAcceptorPreconditions(acceptor, in_msg, sender) && in_msg.CMessage_2a? && CPaxosConfigurationIsAbstractable(acceptor.constants.all.config) } predicate NextAcceptorState_Phase2Preconditions(acceptor:AcceptorState, in_msg:CMessage, sender:EndPoint) { && NextAcceptorState_Phase2Preconditions_AlwaysEnabled(acceptor, in_msg, sender) && CBallotIsNotGreaterThan(acceptor.maxBallot, in_msg.bal_2a) //&& AbstractifyCOperationNumberToOperationNumber(acceptor.log_truncation_point) <= && AbstractifyCOperationNumberToOperationNumber(in_msg.opn_2a) <= acceptor.constants.all.params.max_integer_val as int && sender in acceptor.constants.all.config.replica_ids } predicate NextAcceptorState_Phase2Postconditions(acceptor:AcceptorState, acceptor':AcceptorState, in_msg:CMessage, sender:EndPoint, packets_sent:CBroadcast) { && NextAcceptorState_Phase2Preconditions(acceptor, in_msg, sender) && CommonAcceptorPostconditions(acceptor, acceptor', packets_sent) && LAcceptorProcess2a( AbstractifyAcceptorStateToAcceptor(acceptor), AbstractifyAcceptorStateToAcceptor(acceptor'), AbstractifyCMessageToRslPacket(acceptor.constants.all.config.replica_ids[acceptor.constants.my_index], sender, in_msg), AbstractifyCBroadcastToRlsPacketSeq(packets_sent)) } predicate NextAcceptorState_ProcessHeartbeatPreconditions(acceptor:AcceptorState, in_msg:CMessage, sender:EndPoint) { && CommonAcceptorPreconditions(acceptor, in_msg, sender) && in_msg.CMessage_Heartbeat? && CPaxosConfigurationIsAbstractable(acceptor.constants.all.config) } predicate NextAcceptorState_ProcessHeartbeatPostconditions(acceptor:AcceptorState, acceptor':AcceptorState, in_msg:CMessage, sender:EndPoint) { && NextAcceptorState_ProcessHeartbeatPreconditions(acceptor, in_msg, sender) && AcceptorIsValid(acceptor') && AcceptorIsAbstractable(acceptor') && ConstantsStayConstant(acceptor, acceptor') && LAcceptorProcessHeartbeat( AbstractifyAcceptorStateToAcceptor(acceptor), AbstractifyAcceptorStateToAcceptor(acceptor'), AbstractifyCMessageToRslPacket(acceptor.constants.all.config.replica_ids[acceptor.constants.my_index], sender, in_msg)) } predicate NextAcceptorState_TruncateLogPreconditions(acceptor:AcceptorState, opn:COperationNumber) { && AcceptorIsValid(acceptor) && AcceptorIsAbstractable(acceptor) //&& opn.n > acceptor.log_truncation_point.n } predicate NextAcceptorState_TruncateLogPostconditions(acceptor:AcceptorState, acceptor':AcceptorState, opn:COperationNumber) { && NextAcceptorState_TruncateLogPreconditions(acceptor, opn) && AcceptorIsValid(acceptor') && AcceptorIsAbstractable(acceptor') && ConstantsStayConstant(acceptor, acceptor') && LAcceptorTruncateLog( AbstractifyAcceptorStateToAcceptor(acceptor), AbstractifyAcceptorStateToAcceptor(acceptor'), AbstractifyCOperationNumberToOperationNumber(opn)) } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/RSL/AppInterface.i.dfy ================================================ include "../../Common/Collections/Maps.i.dfy" include "../../Protocol/RSL/Configuration.i.dfy" include "../../Protocol/RSL/Message.i.dfy" include "../../Protocol/RSL/Types.i.dfy" include "../Common/GenericMarshalling.i.dfy" include "../Common/NodeIdentity.i.dfy" include "../../Services/RSL/AppStateMachine.s.dfy" module LiveRSL__AppInterface_i { import opened Native__Io_s import opened Native__NativeTypes_s import opened Collections__Maps_i import opened LiveRSL__Configuration_i import opened LiveRSL__Message_i import opened LiveRSL__Types_i import opened Common__GenericMarshalling_i import opened Common__NodeIdentity_i import opened AppStateMachine_s import opened Math__mul_nonlinear_i import opened Math__mul_i ////////////////////////////////////////////////////////////////////////////// // CAppRequest // // Currently, this is just the same as an AppRequest. Someday, we // might want it to be something more efficient, like an array. ///////////////////////////////////////////////////////////////////////////// type CAppRequest = Bytes predicate method CAppRequestIsAbstractable(request:CAppRequest) { true } function method AbstractifyCAppRequestToAppRequest(request:CAppRequest) : AppRequest { request } predicate method CAppRequestMarshallable(request:CAppRequest) { |request| <= MaxAppRequestSize() } function method MarshallCAppRequest(request:CAppRequest) : V { VByteArray(request) } ////////////////////////////////////////////////////////////////////////////// // CAppReply // // Currently, this is just the same as an AppReply. Someday, we // might want it to be something more efficient, like an array. ///////////////////////////////////////////////////////////////////////////// type CAppReply = Bytes predicate method CAppReplyIsAbstractable(reply:CAppReply) { true } function method AbstractifyCAppReplyToAppReply(reply:CAppReply) : AppReply { reply } predicate method CAppReplyMarshallable(reply:CAppReply) { |reply| <= MaxAppReplySize() } function method MarshallCAppReply(reply:CAppReply) : V { VByteArray(reply) } ////////////////////////////////////////////////////////////////////////////// // CAppState // // Currently, this is just the same as an AppState. Someday, we // might want it to be something more efficient, like an array. ///////////////////////////////////////////////////////////////////////////// type CAppState = Bytes predicate method CAppStateIsAbstractable(state:CAppState) { true } function method AbstractifyCAppStateToAppState(state:CAppState) : AppState { state } predicate method CAppStateMarshallable(state:CAppState) { |state| <= MaxAppStateSize() } function method MarshallCAppState(state:CAppState) : V { VByteArray(state) } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/RSL/Broadcast.i.dfy ================================================ include "../../Protocol/RSL/Broadcast.i.dfy" include "ReplicaConstantsState.i.dfy" module Impl__LiveRSL__Broadcast_i { import opened Native__NativeTypes_s import opened LiveRSL__Broadcast_i import opened LiveRSL__CMessageRefinements_i import opened LiveRSL__CPaxosConfiguration_i import opened LiveRSL__CMessage_i import opened LiveRSL__PacketParsing_i import opened LiveRSL__ReplicaConstantsState_i method BuildBroadcastToEveryone(config:CPaxosConfiguration, my_index:uint64, msg:CMessage) returns (broadcast:CBroadcast) requires CPaxosConfigurationIsValid(config) requires ReplicaIndexValid(my_index, config) requires CMessageIsAbstractable(msg) requires Marshallable(msg) ensures CBroadcastIsValid(broadcast) ensures OutboundPacketsHasCorrectSrc(Broadcast(broadcast), config.replica_ids[my_index]) ensures LBroadcastToEveryone(AbstractifyCPaxosConfigurationToConfiguration(config), my_index as int, AbstractifyCMessageToRslMessage(msg), AbstractifyCBroadcastToRlsPacketSeq(broadcast)) { broadcast := CBroadcast(config.replica_ids[my_index], config.replica_ids, msg); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/RSL/CClockReading.i.dfy ================================================ include "../../Common/Native/NativeTypes.s.dfy" include "../../Protocol/RSL/ClockReading.i.dfy" module LiveRSL__CClockReading_i { import opened Native__NativeTypes_s import opened LiveRSL__ClockReading_i datatype CClockReading = CClockReading(t:uint64) function AbstractifyCClockReadingToClockReading(cclock:CClockReading) : ClockReading { ClockReading(cclock.t as int) } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/RSL/CLastCheckpointedMap.i.dfy ================================================ include "CPaxosConfiguration.i.dfy" include "../../Common/Native/Io.s.dfy" include "../../Common/Collections/CountMatches.i.dfy" include "CTypes.i.dfy" include "../../Protocol/RSL/Acceptor.i.dfy" include "COperationNumberSort.i.dfy" module LiveRSL__CLastCheckpointedMap_i { import opened Native__Io_s import opened Native__NativeTypes_s import opened LiveRSL__Acceptor_i import opened LiveRSL__CPaxosConfiguration_i import opened LiveRSL__CTypes_i import opened LiveRSL__COperationNumberSort_i import opened LiveRSL__Types_i import opened Collections__CountMatches_i type CLastCheckpointedMap = seq //////////////////////////////////////////////////////////// // Refining a CLastCheckpointedMap //////////////////////////////////////////////////////////// predicate CLastCheckpointedMapIsAbstractable(s:CLastCheckpointedMap) { forall ep :: ep in s ==> COperationNumberIsAbstractable(ep) } function {:opaque} AbstractifyCLastCheckpointedMapToOperationNumberSequence(s:CLastCheckpointedMap) : seq ensures |AbstractifyCLastCheckpointedMapToOperationNumberSequence(s)| == |s| ensures forall i :: 0 <= i < |s| ==> AbstractifyCOperationNumberToOperationNumber(s[i]) == AbstractifyCLastCheckpointedMapToOperationNumberSequence(s)[i] { if |s| == 0 then [] else [AbstractifyCOperationNumberToOperationNumber(s[0])] + AbstractifyCLastCheckpointedMapToOperationNumberSequence(s[1..]) } ////////////////////////////////////////////////////////////////////////// // Finding the nth highest operation number ////////////////////////////////////////////////////////////////////////// method SeqToArray(s:seq) returns (a:array) ensures fresh(a) ensures a.Length == |s| ensures forall i :: 0 <= i < |s| ==> s[i] == a[i] ensures a[..] == s ensures fresh(a) { a := new T[|s|]; var i := 0; while i < |s| invariant 0 <= i <= |s| invariant forall j :: 0 <= j < i ==> s[j] == a[j] { a[i] := s[i]; i := i + 1; } } predicate IsNthHighestValueInSequenceOfCOperationNumbers(v:COperationNumber, s:seq, n:uint64) { && 0 < n as int <= |s| && v in s && CountMatchesInSeq(s, (x:COperationNumber) => x.n > v.n) < n as int && CountMatchesInSeq(s, (x:COperationNumber) => x.n >= v.n) >= n as int } predicate IsNthHighestValueInMultisetOfCOperationNumbers(v:COperationNumber, m:multiset, n:uint64) { && 0 < n as int <= |m| && v in m && CountMatchesInMultiset(m, (x:COperationNumber) => x.n > v.n) < n as int && CountMatchesInMultiset(m, (x:COperationNumber) => x.n >= v.n) >= n as int } lemma lemma_SequenceToMultisetPreservesIsNthHighestValueForCOperationNumbers(v:COperationNumber, s:seq, m:multiset, n:uint64) requires m == multiset(s) ensures IsNthHighestValueInSequenceOfCOperationNumbers(v, s, n) <==> IsNthHighestValueInMultisetOfCOperationNumbers(v, m, n) { Lemma_MatchCountInSeqIsMatchCountInMultiset(s, m, (x:COperationNumber) => x.n > v.n); Lemma_MatchCountInSeqIsMatchCountInMultiset(s, m, (x:COperationNumber) => x.n >= v.n); } lemma lemma_SortedSequenceMatchCount(s:seq, k:int) requires |s| > 0 requires 0 < k <= |s| requires forall i, j :: 0 <= i < j < |s| ==> s[i].n <= s[j].n ensures CountMatchesInSeq(s, (x:COperationNumber) => x.n > s[|s|-k].n) < k ensures CountMatchesInSeq(s, (x:COperationNumber) => x.n >= s[|s|-k].n) >= k { var s' := s[1..]; var f1 := (x:COperationNumber) => x.n > s[|s|-k].n; var f2 := (x:COperationNumber) => x.n >= s[|s|-k].n; if k == |s| { calc { CountMatchesInSeq(s, f1); CountMatchesInSeq(s', f1); < { Lemma_CountMatchesInSeqBounds(s', f1); } k; } Lemma_CountMatchesInSeqAll(s, f2); } else { var f1' := (x:COperationNumber) => x.n > s'[|s'|-k].n; var f2' := (x:COperationNumber) => x.n >= s'[|s'|-k].n; lemma_SortedSequenceMatchCount(s', k); assert s'[|s'|-k] == s[|s|-k]; calc { CountMatchesInSeq(s, f1); CountMatchesInSeq(s', f1); { Lemma_CountMatchesInSeqSameForSameFunctions(s', f1, f1'); } CountMatchesInSeq(s', f1'); < k; } calc { CountMatchesInSeq(s, f2); >= CountMatchesInSeq(s', f2); { Lemma_CountMatchesInSeqSameForSameFunctions(s', f2, f2'); } CountMatchesInSeq(s', f2'); >= k; } } } lemma lemma_AbstractionOfCOperationNumberIsNthHighestValueInSequence(opn:COperationNumber, cm:CLastCheckpointedMap, n:uint64) requires IsNthHighestValueInSequenceOfCOperationNumbers(opn, cm, n) ensures IsNthHighestValueInSequence(AbstractifyCOperationNumberToOperationNumber(opn), AbstractifyCLastCheckpointedMapToOperationNumberSequence(cm), n as int) { var f1 := (x:COperationNumber) => x.n > opn.n; var f2 := x => x > AbstractifyCOperationNumberToOperationNumber(opn); Lemma_CountMatchesInSeqCorrespondence(cm, f1, AbstractifyCLastCheckpointedMapToOperationNumberSequence(cm), f2); var f1' := (x:COperationNumber) => x.n >= opn.n; var f2' := x => x >= AbstractifyCOperationNumberToOperationNumber(opn); Lemma_CountMatchesInSeqCorrespondence(cm, f1', AbstractifyCLastCheckpointedMapToOperationNumberSequence(cm), f2'); } method ComputeNthHighestValue(cm:CLastCheckpointedMap, n:uint64) returns (opn:COperationNumber) requires CLastCheckpointedMapIsAbstractable(cm) requires 0 < n as int <= |cm| requires |cm| < 0xffff_ffff_ffff_ffff ensures IsNthHighestValueInSequence(AbstractifyCOperationNumberToOperationNumber(opn), AbstractifyCLastCheckpointedMapToOperationNumberSequence(cm), n as int) { var a := SeqToArray(cm); assert multiset(a[..]) == multiset(cm); InsertionSortCOperationNumbers(a); ghost var s := a[..]; assert multiset(s) == multiset(cm); forall i, j | 0 <= i < j < |s| ensures s[i].n <= s[j].n { assert a[i].n <= a[j].n; } opn := a[a.Length-(n as int)]; assert opn == s[|s|-(n as int)]; ghost var f1 := (x:COperationNumber) => x.n > s[|s|-(n as int)].n; ghost var f2 := (x:COperationNumber) => x.n > opn.n; Lemma_CountMatchesInSeqSameForSameFunctions(s, f1, f2); ghost var f1' := (x:COperationNumber) => x.n >= s[|s|-(n as int)].n; ghost var f2' := (x:COperationNumber) => x.n >= opn.n; Lemma_CountMatchesInSeqSameForSameFunctions(s, f1', f2'); lemma_SortedSequenceMatchCount(s, n as int); assert IsNthHighestValueInSequenceOfCOperationNumbers(opn, s, n); lemma_SequenceToMultisetPreservesIsNthHighestValueForCOperationNumbers(opn, s, multiset(cm), n); lemma_SequenceToMultisetPreservesIsNthHighestValueForCOperationNumbers(opn, cm, multiset(cm), n); lemma_AbstractionOfCOperationNumberIsNthHighestValueInSequence(opn, cm, n); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/RSL/CMessage.i.dfy ================================================ include "CTypes.i.dfy" module LiveRSL__CMessage_i { import opened LiveRSL__CTypes_i import opened Native__Io_s import opened Native__NativeTypes_s import opened LiveRSL__AppInterface_i import opened Logic__Option_i datatype CMessage = CMessage_Invalid() | CMessage_Request(seqno:uint64, val:CAppRequest) | CMessage_1a(bal_1a:CBallot) | CMessage_1b(bal_1b:CBallot, log_truncation_point:COperationNumber, votes:CVotes) | CMessage_2a(bal_2a:CBallot, opn_2a:COperationNumber, val_2a:CRequestBatch) | CMessage_2b(bal_2b:CBallot, opn_2b:COperationNumber, val_2b:CRequestBatch) | CMessage_Heartbeat(bal_heartbeat:CBallot, suspicious:bool, opn_ckpt:COperationNumber) | CMessage_Reply(seqno_reply:uint64, reply:CAppReply) | CMessage_AppStateRequest(bal_state_req:CBallot, opn_state_req:COperationNumber) | CMessage_AppStateSupply(bal_state_supply:CBallot, opn_state_supply:COperationNumber, app_state:CAppState) | CMessage_StartingPhase2(bal_2:CBallot, logTruncationPoint_2:COperationNumber) datatype CPacket = CPacket(dst:EndPoint, src:EndPoint, msg:CMessage) datatype CBroadcast = CBroadcast(src:EndPoint, dsts:seq, msg:CMessage) | CBroadcastNop datatype OutboundPackets = Broadcast(broadcast:CBroadcast) | OutboundPacket(p:Option) | PacketSequence(s:seq) } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/RSL/CMessageRefinements.i.dfy ================================================ include "../../Protocol/RSL/Message.i.dfy" include "../../Protocol/RSL/Environment.i.dfy" include "../../Protocol/RSL/Broadcast.i.dfy" include "../Common/NodeIdentity.i.dfy" include "CMessage.i.dfy" include "AppInterface.i.dfy" module LiveRSL__CMessageRefinements_i { import opened Native__Io_s import opened Native__NativeTypes_i import opened Concrete_NodeIdentity_i import opened LiveRSL__AppInterface_i import opened LiveRSL__CMessage_i import opened LiveRSL__CTypes_i import opened LiveRSL__Message_i import opened LiveRSL__Environment_i import opened LiveRSL__Broadcast_i import opened Common__NodeIdentity_i import opened Common__NetClient_i import opened Environment_s import opened Collections__Sets_i predicate CMessageIsAbstractable(msg:CMessage) { match msg case CMessage_Invalid => true case CMessage_Request(seqno, value) => CAppRequestIsAbstractable(value) case CMessage_1a(ballot) => CBallotIsAbstractable(ballot) case CMessage_1b(ballot, log_truncation_point, votes) => CBallotIsAbstractable(ballot) && COperationNumberIsAbstractable(log_truncation_point) && CVotesIsAbstractable(votes) case CMessage_2a(ballot, opn, value) => CBallotIsAbstractable(ballot) && COperationNumberIsAbstractable(opn) && CRequestBatchIsAbstractable(value) case CMessage_2b(ballot, opn, value) => CBallotIsAbstractable(ballot) && COperationNumberIsAbstractable(opn) && CRequestBatchIsAbstractable(value) case CMessage_Heartbeat(bal_heartbeat, suspicious, opn_ckpt) => CBallotIsAbstractable(bal_heartbeat) && COperationNumberIsAbstractable(opn_ckpt) case CMessage_Reply(seqno, reply) => CAppReplyIsAbstractable(reply) case CMessage_AppStateRequest(bal_state_req, opn_state_req) => CBallotIsAbstractable(bal_state_req) && COperationNumberIsAbstractable(opn_state_req) case CMessage_AppStateSupply(bal_state_supply, opn_state_supply, app_state) => CBallotIsAbstractable(bal_state_supply) && COperationNumberIsAbstractable(opn_state_supply) && CAppStateIsAbstractable(app_state) case CMessage_StartingPhase2(bal_2, logTruncationPoint_2) => CBallotIsAbstractable(bal_2) && COperationNumberIsAbstractable(logTruncationPoint_2) } function AbstractifyCMessageToRslMessage(msg:CMessage) : RslMessage requires CMessageIsAbstractable(msg) { match msg case CMessage_Invalid => RslMessage_Invalid() case CMessage_Request(seqno, value) => RslMessage_Request(seqno as int, AbstractifyCAppRequestToAppRequest(value)) case CMessage_1a(ballot) => RslMessage_1a(AbstractifyCBallotToBallot(ballot)) case CMessage_1b(ballot, log_truncation_point, votes) => RslMessage_1b(AbstractifyCBallotToBallot(ballot), AbstractifyCOperationNumberToOperationNumber(log_truncation_point), AbstractifyCVotesToVotes(votes)) case CMessage_2a(ballot, opn, value) => RslMessage_2a(AbstractifyCBallotToBallot(ballot), AbstractifyCOperationNumberToOperationNumber(opn), AbstractifyCRequestBatchToRequestBatch(value)) case CMessage_2b(ballot, opn, value) => RslMessage_2b(AbstractifyCBallotToBallot(ballot), AbstractifyCOperationNumberToOperationNumber(opn), AbstractifyCRequestBatchToRequestBatch(value)) case CMessage_Heartbeat(bal_heartbeat, suspicious, opn_ckpt) => RslMessage_Heartbeat(AbstractifyCBallotToBallot(bal_heartbeat), suspicious, AbstractifyCOperationNumberToOperationNumber(opn_ckpt)) case CMessage_Reply(seqno, reply) => RslMessage_Reply(seqno as int, AbstractifyCAppReplyToAppReply(reply)) case CMessage_AppStateRequest(bal_state_req, opn_state_req) => RslMessage_AppStateRequest(AbstractifyCBallotToBallot(bal_state_req), AbstractifyCOperationNumberToOperationNumber(opn_state_req)) case CMessage_AppStateSupply(bal_state_supply, opn_state_supply, app_state) => RslMessage_AppStateSupply(AbstractifyCBallotToBallot(bal_state_supply), AbstractifyCOperationNumberToOperationNumber(opn_state_supply), AbstractifyCAppStateToAppState(app_state)) case CMessage_StartingPhase2(bal_2, logTruncationPoint_2) => RslMessage_StartingPhase2(AbstractifyCBallotToBallot(bal_2), AbstractifyCOperationNumberToOperationNumber(logTruncationPoint_2)) } function AbstractifyCMessageToRslPacket(sentTo:EndPoint, sentFrom:EndPoint, msg:CMessage) : RslPacket requires CMessageIsAbstractable(msg) requires EndPointIsValidPublicKey(sentTo) requires EndPointIsValidPublicKey(sentFrom) { LPacket(AbstractifyEndPointToNodeIdentity(sentTo), AbstractifyEndPointToNodeIdentity(sentFrom), AbstractifyCMessageToRslMessage(msg)) } predicate CPacketIsAbstractable(cp:CPacket) { && CMessageIsAbstractable(cp.msg) && EndPointIsValidPublicKey(cp.src) && EndPointIsValidPublicKey(cp.dst) } predicate CPacketsIsAbstractable(cps:set) { forall cp :: cp in cps ==> CPacketIsAbstractable(cp) } function AbstractifyCPacketToRslPacket(cp: CPacket): RslPacket ensures CPacketIsAbstractable(cp) ==> AbstractifyCPacketToRslPacket(cp) == LPacket(AbstractifyEndPointToNodeIdentity(cp.dst), AbstractifyEndPointToNodeIdentity(cp.src), AbstractifyCMessageToRslMessage(cp.msg)) { if (CPacketIsAbstractable(cp)) then LPacket(AbstractifyEndPointToNodeIdentity(cp.dst), AbstractifyEndPointToNodeIdentity(cp.src), AbstractifyCMessageToRslMessage(cp.msg)) else var x:RslPacket :| (true); x } function AbstractifySetOfCPacketsToSetOfRslPackets_transparent(cps:set) : set requires CPacketsIsAbstractable(cps) { set cp | cp in cps :: AbstractifyCPacketToRslPacket(cp) } function {:opaque} AbstractifySetOfCPacketsToSetOfRslPackets(cps:set) : set requires CPacketsIsAbstractable(cps) //ensures forall p :: p in cps ==> AbstractifyCPacketToRslPacket(p) in AbstractifySetOfCPacketsToSetOfRslPackets(cps) // Still too trigger happy { // set netp | netp in netps :: // var net := AbstractifyCPacketToShtPacket(netp); net AbstractifySetOfCPacketsToSetOfRslPackets_transparent(cps) } predicate CPacketSeqIsAbstractable(cps:seq) { forall i :: 0 <= i < |cps| ==> CPacketIsAbstractable(cps[i]) } function {:opaque} AbstractifySeqOfCPacketsToSeqOfRslPackets(cps:seq) : seq requires CPacketSeqIsAbstractable(cps) ensures |cps| == |AbstractifySeqOfCPacketsToSeqOfRslPackets(cps)| ensures forall i :: 0 <= i < |cps| ==> AbstractifySeqOfCPacketsToSeqOfRslPackets(cps)[i] == AbstractifyCPacketToRslPacket(cps[i]) { if |cps| == 0 then [] else [AbstractifyCPacketToRslPacket(cps[0])] + AbstractifySeqOfCPacketsToSeqOfRslPackets(cps[1..]) } predicate CPacketSeqHasCorrectSrc(sent_packets:seq, me:EndPoint) { forall p :: p in sent_packets ==> p.src == me } predicate CMessageIsInjectiveType(m:CMessage) { && CMessageIsAbstractable(m) && (m.CMessage_1b? || m.CMessage_2b?) } lemma lemma_AbstractifyCMessageToRslMessage_isInjective(m1:CMessage, m2:CMessage) requires CMessageIsInjectiveType(m1) && CMessageIsInjectiveType(m2) requires AbstractifyCMessageToRslMessage(m1) == AbstractifyCMessageToRslMessage(m2) ensures m1 == m2 { lemma_AbstractifyCRequestBatchToRequestBatch_isInjective(); if (m1.CMessage_1b?) { lemma_BallotInjective(m1.bal_1b, m2.bal_1b); lemma_VotesInjective(m1.votes, m2.votes); assert m1 == m2; } else if (m1.CMessage_2b?) { lemma_BallotInjective(m1.bal_2b, m2.bal_2b); assert AbstractifyCRequestBatchToRequestBatch(m1.val_2b) == AbstractifyCRequestBatchToRequestBatch(m2.val_2b); assert m1 == m2; } } predicate CPacketIsInjectiveType(p:CPacket) { CPacketIsAbstractable(p) && CMessageIsInjectiveType(p.msg) } lemma lemma_AbstractifyCPacketToRslPacket_isInjective() ensures forall p1, p2 :: && CPacketIsInjectiveType(p1) && CPacketIsInjectiveType(p2) && AbstractifyCPacketToRslPacket(p1) == AbstractifyCPacketToRslPacket(p2) ==> p1 == p2 { forall p1, p2 | && CPacketIsInjectiveType(p1) && CPacketIsInjectiveType(p2) && AbstractifyCPacketToRslPacket(p1) == AbstractifyCPacketToRslPacket(p2) ensures p1 == p2 { lemma_AbstractifyEndPointToNodeIdentity_injective_forall(); lemma_AbstractifyCMessageToRslMessage_isInjective(p1.msg, p2.msg); } } predicate SetOfInjectiveTypeCPackets(s:set) { forall p :: p in s ==> CPacketIsInjectiveType(p) } predicate SetOfInjectiveTypeCPacketsIsInjective(s:set) { && SetOfInjectiveTypeCPackets(s) && (forall p1, p2 :: p1 in s && p2 in s && AbstractifyCPacketToRslPacket(p1) == AbstractifyCPacketToRslPacket(p2) ==> p1 == p2) } lemma lemma_SetOfInjectiveTypeCPacketsIsInjective(s:set) requires SetOfInjectiveTypeCPackets(s) ensures SetOfInjectiveTypeCPacketsIsInjective(s) { lemma_AbstractifyCPacketToRslPacket_isInjective(); } lemma lemma_AbstractifySetOfCPacketsToSetOfRslPackets_isInjective(cps1:set, cps2:set) requires CPacketsIsAbstractable(cps1) requires CPacketsIsAbstractable(cps2) requires SetOfInjectiveTypeCPackets(cps1) requires SetOfInjectiveTypeCPackets(cps2) requires AbstractifySetOfCPacketsToSetOfRslPackets(cps1) == AbstractifySetOfCPacketsToSetOfRslPackets(cps2) ensures cps1 == cps2 { reveal AbstractifySetOfCPacketsToSetOfRslPackets(); lemma_AbstractifyCPacketToRslPacket_isInjective(); forall cp1 | cp1 in cps1 ensures cp1 in cps2 { var p := AbstractifyCPacketToRslPacket(cp1); assert p in AbstractifySetOfCPacketsToSetOfRslPackets(cps2); } forall cp2 | cp2 in cps2 ensures cp2 in cps1 { var p := AbstractifyCPacketToRslPacket(cp2); assert p in AbstractifySetOfCPacketsToSetOfRslPackets(cps1); } } lemma lemma_AbstractifySetOfCPacketsToSetOfRslPackets_cardinality(cps:set) requires CPacketsIsAbstractable(cps) requires SetOfInjectiveTypeCPackets(cps) ensures |cps| == |AbstractifySetOfCPacketsToSetOfRslPackets(cps)| { lemma_SetOfInjectiveTypeCPacketsIsInjective(cps); var rps := AbstractifySetOfCPacketsToSetOfRslPackets(cps); forall y | y in rps ensures exists x :: x in cps && y == AbstractifyCPacketToRslPacket(x) { reveal AbstractifySetOfCPacketsToSetOfRslPackets(); } forall x | x in cps ensures AbstractifyCPacketToRslPacket(x) in rps { reveal AbstractifySetOfCPacketsToSetOfRslPackets(); } lemma_MapSetCardinalityOver(cps, rps, AbstractifyCPacketToRslPacket); } lemma lemma_AbstractifySetOfCPacketsToSetOfRslPackets_properties(cps:set) requires CPacketsIsAbstractable(cps) ensures SetOfInjectiveTypeCPackets(cps) ==> |cps| == |AbstractifySetOfCPacketsToSetOfRslPackets(cps)| ensures AbstractifySetOfCPacketsToSetOfRslPackets({}) == {} { if SetOfInjectiveTypeCPackets(cps) { lemma_AbstractifySetOfCPacketsToSetOfRslPackets_cardinality(cps); } reveal AbstractifySetOfCPacketsToSetOfRslPackets(); } lemma lemma_AbstractifyCPacketToRslPacket_src(cps:set, src:EndPoint) requires CPacketsIsAbstractable(cps) requires EndPointIsValidPublicKey(src) requires forall p :: p in AbstractifySetOfCPacketsToSetOfRslPackets(cps) ==> p.src == AbstractifyEndPointToNodeIdentity(src) ensures forall cp :: cp in cps ==> cp.src == src { reveal AbstractifySetOfCPacketsToSetOfRslPackets(); lemma_AbstractifyEndPointToNodeIdentity_injective_forall(); forall cp | cp in cps ensures cp.src == src { assert AbstractifyCPacketToRslPacket(cp).src == AbstractifyEndPointToNodeIdentity(src); assert cp.src == src; } } lemma lemma_AbstractifySetOfCPacketsToSetOfRslPackets_srcMembershipNeg(cps:set, src:EndPoint) requires CPacketsIsAbstractable(cps) requires EndPointIsValidPublicKey(src) requires !(forall p :: p in cps ==> p.src != src) ensures !(forall p :: p in AbstractifySetOfCPacketsToSetOfRslPackets(cps) ==> p.src != AbstractifyEndPointToNodeIdentity(src)) { assert exists p :: p in cps && p.src == src; var cp :| cp in cps && cp.src == src; var p := AbstractifyCPacketToRslPacket(cp); reveal AbstractifySetOfCPacketsToSetOfRslPackets(); assert p in AbstractifySetOfCPacketsToSetOfRslPackets(cps); lemma_AbstractifyEndPointToNodeIdentity_injective_forall(); } lemma lemma_AbstractifySetOfCPacketsToSetOfRslPackets_srcMembershipPos(cps:set, src:EndPoint) requires CPacketsIsAbstractable(cps) requires EndPointIsValidPublicKey(src) requires forall p :: p in cps ==> p.src != src ensures forall p :: p in AbstractifySetOfCPacketsToSetOfRslPackets(cps) ==> p.src != AbstractifyEndPointToNodeIdentity(src) { forall p | p in AbstractifySetOfCPacketsToSetOfRslPackets(cps) ensures p.src != AbstractifyEndPointToNodeIdentity(src) { reveal AbstractifySetOfCPacketsToSetOfRslPackets(); var cp :| cp in cps && AbstractifyCPacketToRslPacket(cp) == p; assert p.src == AbstractifyEndPointToNodeIdentity(cp.src); assert cp.src != src; lemma_AbstractifyEndPointToNodeIdentity_injective_forall(); } } lemma lemma_AbstractifySetOfCPacketsToSetOfRslPackets_srcMembership(cps:set, src:EndPoint) requires CPacketsIsAbstractable(cps) requires EndPointIsValidPublicKey(src) ensures (forall p :: p in cps ==> p.src != src) <==> (forall p :: p in AbstractifySetOfCPacketsToSetOfRslPackets(cps) ==> p.src != AbstractifyEndPointToNodeIdentity(src)) { var b := (forall p :: p in cps ==> p.src != src); if b { lemma_AbstractifySetOfCPacketsToSetOfRslPackets_srcMembershipPos(cps, src); } else { lemma_AbstractifySetOfCPacketsToSetOfRslPackets_srcMembershipNeg(cps, src); } } function {:opaque} BuildLBroadcast(src:NodeIdentity, dsts:seq, m:RslMessage):seq ensures |BuildLBroadcast(src, dsts, m)| == |dsts| ensures forall i :: 0 <= i < |dsts| ==> BuildLBroadcast(src, dsts, m)[i] == LPacket(dsts[i], src, m) { if |dsts| == 0 then [] else [LPacket(dsts[0], src, m)] + BuildLBroadcast(src, dsts[1..], m) } predicate CBroadcastIsAbstractable(broadcast:CBroadcast) { || broadcast.CBroadcastNop? || (&& broadcast.CBroadcast? && EndPointIsValidPublicKey(broadcast.src) && (forall i :: 0 <= i < |broadcast.dsts| ==> EndPointIsValidPublicKey(broadcast.dsts[i])) && CMessageIsAbstractable(broadcast.msg)) } function AbstractifyCBroadcastToRlsPacketSeq(broadcast:CBroadcast) : seq requires CBroadcastIsAbstractable(broadcast) { match broadcast case CBroadcast(_,_,_) => BuildLBroadcast(AbstractifyEndPointToNodeIdentity(broadcast.src), AbstractifyEndPointsToNodeIdentities(broadcast.dsts), AbstractifyCMessageToRslMessage(broadcast.msg)) case CBroadcastNop => [] } predicate OutboundPacketsIsAbstractable(out:OutboundPackets) { match out case Broadcast(broadcast) => CBroadcastIsAbstractable(broadcast) case OutboundPacket(Some(p)) => CPacketIsAbstractable(p) case OutboundPacket(None()) => true case PacketSequence(s) => CPacketSeqIsAbstractable(s) } function AbstractifyOutboundCPacketsToSeqOfRslPackets(out:OutboundPackets) : seq requires OutboundPacketsIsAbstractable(out) { match out case Broadcast(broadcast) => AbstractifyCBroadcastToRlsPacketSeq(broadcast) case OutboundPacket(Some(p)) => [AbstractifyCPacketToRslPacket(p)] case OutboundPacket(None()) => [] case PacketSequence(s) => AbstractifySeqOfCPacketsToSeqOfRslPackets(s) } predicate OutboundPacketsHasCorrectSrc(out:OutboundPackets, me:EndPoint) { match out case Broadcast(CBroadcast(src, _, _)) => src == me case Broadcast(CBroadcastNop()) => true case OutboundPacket(p) => p.Some? ==> p.v.src == me case PacketSequence(s) => (forall p :: p in s ==> p.src == me) // case OutboundPacket(Some(p)) => p.src == me // case OutboundPacket(None()) => true } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/RSL/COperationNumberSort.i.dfy ================================================ include "../../Common/Native/Io.s.dfy" include "CTypes.i.dfy" // This file is adapted from // https://dafny.codeplex.com/SourceControl/latest#Test/dafny3/GenericSort.dfy // and modified to apply only to COperationNumbers and to use uint64s as indices. module LiveRSL__COperationNumberSort_i { import opened Native__NativeTypes_s import opened LiveRSL__CTypes_i // In the insertion sort routine below, it's more convenient to keep track of only that // neighboring elements of the array are sorted... predicate NeighborSorted_COperationNumber(a: array, low: uint64, high: uint64) requires a.Length < 0xFFFFFFFFFFFFFFFF requires 0 <= low <= high <= a.Length as uint64 reads a { forall i {:trigger a[i-1].n, a[i].n} :: low < i < high ==> a[i-1].n <= a[i].n } predicate Sorted_COperationNumber(a: array, low: uint64, high: uint64) requires a.Length < 0xFFFFFFFFFFFFFFFF requires 0 <= low <= high <= a.Length as uint64 reads a { forall i, j :: low <= i < j < high ==> a[i].n <= a[j].n } // ...but we show that property to imply all pairs to be sorted. The proof of this // lemma uses the transitivity property. lemma lemma_NeighborSortedImpliesSortedCOperationNumber(a: array, low: uint64, high: uint64) requires a.Length < 0xFFFFFFFFFFFFFFFF requires 0 <= low <= high <= a.Length as uint64 requires NeighborSorted_COperationNumber(a, low, high) ensures Sorted_COperationNumber(a, low, high) decreases high - low { if low != high { lemma_NeighborSortedImpliesSortedCOperationNumber(a, low+1, high); forall j | low < j < high ensures a[low].n <= a[j].n { var i := low+1; if(i == j) { assert a[j-1].n <= a[j].n; } else { assert a[i-1].n <= a[i].n; assert a[i].n <= a[j].n; assert a[low].n <= a[j].n; } } } } // Standard insertion sort method method InsertionSortCOperationNumbers(a: array) modifies a requires a.Length < 0xFFFFFFFFFFFFFFFF ensures Sorted_COperationNumber(a, 0, a.Length as uint64) ensures multiset(a[..]) == old(multiset(a[..])) { if a.Length as uint64 == 0 { return; } var i:uint64 := 1; while i < a.Length as uint64 invariant 0 < i <= a.Length as uint64 invariant NeighborSorted_COperationNumber(a, 0, i) invariant multiset(a[..]) == old(multiset(a[..])) { var j:uint64 := i; while 0 < j && a[j-1].n > a[j].n invariant 0 <= j <= i invariant NeighborSorted_COperationNumber(a, 0, j) invariant NeighborSorted_COperationNumber(a, j, i+1) invariant 0 < j < i ==> a[j-1].n <= a[j+1].n invariant multiset(a[..]) == old(multiset(a[..])) { // The proof of correctness uses the totality property here. // It implies that if two elements are not previously in // sorted order, they will be after swapping them. a[j], a[j-1] := a[j-1], a[j]; j := j - 1; } i := i + 1; } lemma_NeighborSortedImpliesSortedCOperationNumber(a, 0, a.Length as uint64); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/RSL/CPaxosConfiguration.i.dfy ================================================ include "../../Protocol/RSL/Constants.i.dfy" include "../Common/NodeIdentity.i.dfy" include "PacketParsing.i.dfy" include "ParametersState.i.dfy" module LiveRSL__CPaxosConfiguration_i { import opened Native__Io_s import opened Native__NativeTypes_s import opened LiveRSL__Constants_i import opened LiveRSL__Configuration_i import opened LiveRSL__PacketParsing_i import opened LiveRSL__ParametersState_i import opened Common__NodeIdentity_i import opened Common__SeqIsUniqueDef_i import opened Common__NetClient_i import opened Collections__Seqs_i datatype CPaxosConfiguration = CPaxosConfiguration(replica_ids:seq) predicate CPaxosConfigurationIsAbstractable(config:CPaxosConfiguration) { && (forall e :: e in config.replica_ids ==> EndPointIsValidPublicKey(e)) && SeqIsUnique(config.replica_ids) } predicate CPaxosConfigurationIsValid(config:CPaxosConfiguration) ensures CPaxosConfigurationIsValid(config) ==> SeqIsUnique(config.replica_ids) { && 0 < |config.replica_ids| < 0xffff_ffff_ffff_ffff && CPaxosConfigurationIsAbstractable(config) && LMinQuorumSize(AbstractifyCPaxosConfigurationToConfiguration(config)) <= |config.replica_ids| } function method PaxosEndPointIsValid(endPoint:EndPoint, config:CPaxosConfiguration) : bool requires CPaxosConfigurationIsValid(config) { EndPointIsValidPublicKey(endPoint) } function AbstractifyCPaxosConfigurationToConfiguration(config:CPaxosConfiguration) : LConfiguration requires CPaxosConfigurationIsAbstractable(config) { LConfiguration({}, AbstractifyEndPointsToNodeIdentities(config.replica_ids)) } predicate ReplicaIndexValid(index:uint64, config:CPaxosConfiguration) { 0 <= index as int < |config.replica_ids| } predicate ReplicaIndicesValid(indices:seq, config:CPaxosConfiguration) { forall i :: 0 <= i < |indices| ==> ReplicaIndexValid(indices[i], config) } lemma lemma_WFCPaxosConfiguration(config:CPaxosConfiguration) ensures && CPaxosConfigurationIsAbstractable(config) && 0 < |config.replica_ids| ==> && CPaxosConfigurationIsAbstractable(config) && WellFormedLConfiguration(AbstractifyCPaxosConfigurationToConfiguration(config)); { if CPaxosConfigurationIsAbstractable(config) && 0 < |config.replica_ids| { //lemma_CardinalityNonEmpty(config.replica_ids); var e := config.replica_ids[0]; assert AbstractifyEndPointToNodeIdentity(e) in AbstractifyCPaxosConfigurationToConfiguration(config).replica_ids; assert 0 < |AbstractifyCPaxosConfigurationToConfiguration(config).replica_ids|; var r_replicaIds := AbstractifyCPaxosConfigurationToConfiguration(config).replica_ids; forall i, j | 0 <= i < |r_replicaIds| && 0 <= j < |r_replicaIds| ensures r_replicaIds[i] == r_replicaIds[j] ==> i == j { if r_replicaIds[i] == r_replicaIds[j] { if i != j { assert r_replicaIds[i] == AbstractifyEndPointToNodeIdentity(config.replica_ids[i]); assert r_replicaIds[j] == AbstractifyEndPointToNodeIdentity(config.replica_ids[j]); lemma_AbstractifyEndPointToNodeIdentity_injective(config.replica_ids[i], config.replica_ids[j]); assert config.replica_ids[i] == config.replica_ids[j]; reveal_SeqIsUnique(); assert i == j; assert false; } } } } } predicate WFCPaxosConfiguration(config:CPaxosConfiguration) ensures WFCPaxosConfiguration(config) ==> && CPaxosConfigurationIsAbstractable(config) && WellFormedLConfiguration(AbstractifyCPaxosConfigurationToConfiguration(config)) { lemma_WFCPaxosConfiguration(config); && CPaxosConfigurationIsAbstractable(config) && 0 < |config.replica_ids| } lemma lemma_MinQuorumSizeLessThanReplicaCount(config:CPaxosConfiguration) requires CPaxosConfigurationIsAbstractable(config) requires |config.replica_ids| > 0 requires SeqIsUnique(config.replica_ids) ensures LMinQuorumSize(AbstractifyCPaxosConfigurationToConfiguration(config)) <= |config.replica_ids| { assert |config.replica_ids| > 0; var h_config := AbstractifyCPaxosConfigurationToConfiguration(config); lemma_AbstractifyEndPointsToNodeIdentities_properties(config.replica_ids); assert |h_config.replica_ids| == |config.replica_ids|; assert |h_config.replica_ids| > 0; } method CGetReplicaIndex(replica:EndPoint, config:CPaxosConfiguration) returns (found:bool, index:uint64) requires CPaxosConfigurationIsValid(config) requires EndPointIsValidPublicKey(replica) ensures found ==> ReplicaIndexValid(index, config) && config.replica_ids[index] == replica ensures found ==> GetReplicaIndex(AbstractifyEndPointToNodeIdentity(replica), AbstractifyCPaxosConfigurationToConfiguration(config)) == index as int ensures !found ==> !(replica in config.replica_ids) ensures !found ==> !(AbstractifyEndPointToNodeIdentity(replica) in AbstractifyEndPointsToNodeIdentities(config.replica_ids)) { var i:uint64 := 0; lemma_AbstractifyEndPointsToNodeIdentities_properties(config.replica_ids); while i < |config.replica_ids| as uint64 invariant i < |config.replica_ids| as uint64 invariant forall j :: 0 <= j < i ==> config.replica_ids[j] != replica { if replica == config.replica_ids[i] { found := true; index := i; ghost var r_replica := AbstractifyEndPointToNodeIdentity(replica); ghost var r_replicas := AbstractifyCPaxosConfigurationToConfiguration(config).replica_ids; assert r_replica == r_replicas[index]; assert ItemAtPositionInSeq(r_replicas, r_replica, index as int); calc ==> { true; { reveal_SeqIsUnique(); } forall j :: 0 <= j < |config.replica_ids| && j != i as int ==> config.replica_ids[j] != replica; } if exists j :: 0 <= j < |r_replicas| && j != index as int && ItemAtPositionInSeq(r_replicas, r_replica, j) { ghost var j :| 0 <= j < |r_replicas| && j != index as int && ItemAtPositionInSeq(r_replicas, r_replica, j); assert r_replicas[j] == r_replica; assert AbstractifyEndPointToNodeIdentity(config.replica_ids[j]) == r_replica; lemma_AbstractifyEndPointToNodeIdentity_injective(config.replica_ids[i], config.replica_ids[j]); assert false; } assert forall j :: 0 <= j < |r_replicas| && j != index as int ==> !ItemAtPositionInSeq(r_replicas, r_replica, j); assert FindIndexInSeq(r_replicas, r_replica) == index as int; return; } if i == (|config.replica_ids| as uint64) - 1 { found := false; return; } i := i + 1; } found := false; } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/RSL/CTypes.i.dfy ================================================ include "../../Protocol/RSL/Types.i.dfy" include "../Common/NodeIdentity.i.dfy" include "../../Common/Native/NativeTypes.i.dfy" include "../Common/Util.i.dfy" include "../Common/GenericRefinement.i.dfy" include "../../Common/Collections/Sets.i.dfy" include "AppInterface.i.dfy" module LiveRSL__CTypes_i { import opened AppStateMachine_s import opened Native__Io_s import opened Native__NativeTypes_s import opened Native__NativeTypes_i import opened LiveRSL__AppInterface_i import opened LiveRSL__Types_i import opened Common__NodeIdentity_i import opened Common__NetClient_i import opened Common__Util_i import opened Collections__Maps_i import opened Collections__Sets_i import opened GenericRefinement_i import opened Concrete_NodeIdentity_i ////////////////////////////////////////////////////////////////////////////// // Ballot // Note: proposer_id is now an index into the shared configuration, not a Uint64 representation of an EndPoint datatype CBallot = CBallot(seqno:uint64, proposer_id:uint64) function method BallotSize() : uint64 { Uint64Size() + Uint64Size() } function method CBallotIsLessThan(lhs:CBallot, rhs:CBallot) : bool { || lhs.seqno < rhs.seqno || (lhs.seqno == rhs.seqno && lhs.proposer_id < rhs.proposer_id) } function method CBallotIsNotGreaterThan(lhs:CBallot, rhs:CBallot) : bool { || lhs.seqno < rhs.seqno || (lhs.seqno == rhs.seqno && lhs.proposer_id <= rhs.proposer_id) } predicate CBallotIsAbstractable(ballot:CBallot) { && ballot.CBallot? // OBSERVE: Always true, but seems necessary to avoid errors below && ballot.proposer_id <= 0xFFFF_FFFF_FFFF_FFFF // We don't support more than 2^64-1 replicas. Such is life. //&& EndPointUint64Representation(ballot.proposer_id) } function AbstractifyCBallotToBallot(ballot:CBallot) : Ballot // the specification of the ballot does not account for a null state. requires CBallotIsAbstractable(ballot) { //Ballot(int(ballot.seqno), AbstractifyUint64ToNodeIdentity(ballot.proposer_id)) Ballot(ballot.seqno as int, ballot.proposer_id as int) } predicate CCBalLeq(ba:CBallot, bb:CBallot) requires CBallotIsAbstractable(ba) && CBallotIsAbstractable(bb) { BalLeq(AbstractifyCBallotToBallot(ba), AbstractifyCBallotToBallot(bb)) } predicate CCBalLt(ba:CBallot, bb:CBallot) requires CBallotIsAbstractable(ba) && CBallotIsAbstractable(bb) { BalLt(AbstractifyCBallotToBallot(ba), AbstractifyCBallotToBallot(bb)) } method CBalLeq(ba:CBallot, bb:CBallot) returns (b:bool) requires CBallotIsAbstractable(ba) && CBallotIsAbstractable(bb) ensures b == BalLeq(AbstractifyCBallotToBallot(ba), AbstractifyCBallotToBallot(bb)) ensures b == CCBalLeq(ba, bb) { if (ba.seqno < bb.seqno || (ba.seqno == bb.seqno && ba.proposer_id <= bb.proposer_id)) { b := true; } else { b := false; } } method CBalLt(ba:CBallot, bb:CBallot) returns (b:bool) requires CBallotIsAbstractable(ba) && CBallotIsAbstractable(bb) ensures b == BalLt(AbstractifyCBallotToBallot(ba), AbstractifyCBallotToBallot(bb)) ensures b == CCBalLt(ba, bb) { if (ba.seqno < bb.seqno || (ba.seqno == bb.seqno && ba.proposer_id < bb.proposer_id)) { b := true; } else { b := false; } } lemma lemma_BallotInjective(b1:CBallot, b2:CBallot) requires CBallotIsAbstractable(b1) requires CBallotIsAbstractable(b2) requires AbstractifyCBallotToBallot(b1) == AbstractifyCBallotToBallot(b2) ensures b1 == b2 { } ////////////////////////////////////////////////////////////////////////////// // OperationNumber datatype COperationNumber = COperationNumber(n:uint64) function method OpNumSize() : uint64 { Uint64Size() } predicate COperationNumberIsAbstractable(opn:COperationNumber) { opn.COperationNumber? // OBSERVE: Always true, but seems necessary to avoid errors below } function AbstractifyCOperationNumberToOperationNumber(opn:COperationNumber) : OperationNumber // requires COperationNumberIsAbstractable(opn) ensures COperationNumberIsAbstractable(opn) ==> (0 <= AbstractifyCOperationNumberToOperationNumber(opn) <= 0xffff_ffff_ffff_ffff) { opn.n as int } lemma lemma_AbstractifyCOperationNumberToOperationNumber_isInjective() ensures forall opn1, opn2 {:trigger AbstractifyCOperationNumberToOperationNumber(opn1), AbstractifyCOperationNumberToOperationNumber(opn2)} :: COperationNumberIsAbstractable(opn1) && COperationNumberIsAbstractable(opn2) && AbstractifyCOperationNumberToOperationNumber(opn1) == AbstractifyCOperationNumberToOperationNumber(opn2) ==> opn1 == opn2 { } function AbstractifyCOperationNumbersToOperationNumbers(copns:set):set requires forall opn :: opn in copns ==> COperationNumberIsAbstractable(opn) { set copn | copn in copns :: AbstractifyCOperationNumberToOperationNumber(copn) } lemma lemma_AbstractifyCOperationNumbersToOperationNumbers_maintainsSize(copns:set) requires forall opn :: opn in copns ==> COperationNumberIsAbstractable(opn) ensures |copns| == |AbstractifyCOperationNumbersToOperationNumbers(copns)| { var opns := AbstractifyCOperationNumbersToOperationNumbers(copns); lemma_AbstractifyCOperationNumberToOperationNumber_isInjective(); var f := AbstractifyCOperationNumberToOperationNumber; assert forall x :: x in copns ==> f(x) in opns; forall opn1, opn2 | f(opn1) == f(opn2) ensures opn1 == opn2 { } assert forall x :: f(x) in opns ==> x in copns; lemma_MapSetCardinality(copns, opns, f); } //////////////////////////////////////////////// // CRequest //////////////////////////////////////////////// datatype CRequest = CRequest(client:EndPoint, seqno:uint64, request:CAppRequest) predicate method ValidRequest(c:CRequest) { c.CRequest? ==> EndPointIsValidPublicKey(c.client) && CAppRequestMarshallable(c.request) } predicate CRequestIsAbstractable(c:CRequest) { EndPointIsAbstractable(c.client) && CAppRequestIsAbstractable(c.request) } function AbstractifyCRequestToRequest(c:CRequest) : Request requires CRequestIsAbstractable(c) { Request(AbstractifyEndPointToNodeIdentity(c.client), c.seqno as int, AbstractifyCAppRequestToAppRequest(c.request)) } lemma lemma_AbstractifyCRequestToRequest_isInjective() ensures forall v1, v2 :: CRequestIsAbstractable(v1) && CRequestIsAbstractable(v2) && AbstractifyCRequestToRequest(v1) == AbstractifyCRequestToRequest(v2) ==> v1 == v2 { // assert forall u1:uint64, u2:uint64 :: u1 as int == u2 as int ==> u1 == u2; lemma_AbstractifyEndPointToNodeIdentity_injective_forall(); } predicate CRequestsSeqIsAbstractable(cvals:seq) { forall cval :: cval in cvals ==> CRequestIsAbstractable(cval) } function {:opaque} AbstractifyCRequestsSeqToRequestsSeq(cvals:seq) : seq requires CRequestsSeqIsAbstractable(cvals) ensures |cvals| == |AbstractifyCRequestsSeqToRequestsSeq(cvals)| ensures forall i {:trigger AbstractifyCRequestsSeqToRequestsSeq(cvals)[i]} :: 0 <= i < |cvals| ==> AbstractifyCRequestToRequest(cvals[i]) == AbstractifyCRequestsSeqToRequestsSeq(cvals)[i] ensures forall c :: CRequestIsAbstractable(c) ==> (c in cvals <==> AbstractifyCRequestToRequest(c) in AbstractifyCRequestsSeqToRequestsSeq(cvals)) { lemma_AbstractifyCRequestToRequest_isInjective(); if |cvals| == 0 then [] else [AbstractifyCRequestToRequest(cvals[0])] + AbstractifyCRequestsSeqToRequestsSeq(cvals[1..]) } lemma lemma_SequenceIndexing(s:seq, s':seq, index:int) requires |s| <= index < |s| + |s'| ensures (s + s')[index] == s'[index - |s|] { } lemma lemma_AbstractifyCRequestsSeqToRequestsSeq_concat(r1:seq, r2:seq) requires CRequestsSeqIsAbstractable(r1) requires CRequestsSeqIsAbstractable(r2) ensures AbstractifyCRequestsSeqToRequestsSeq(r1) + AbstractifyCRequestsSeqToRequestsSeq(r2) == AbstractifyCRequestsSeqToRequestsSeq(r1 + r2) ensures CRequestsSeqIsAbstractable(r1 + r2) { if |r1| == 0 { } else { var r_cat := AbstractifyCRequestsSeqToRequestsSeq(r1) + AbstractifyCRequestsSeqToRequestsSeq(r2); forall i | 0 <= i < |AbstractifyCRequestsSeqToRequestsSeq(r1 + r2)| ensures (r_cat)[i] == AbstractifyCRequestsSeqToRequestsSeq(r1 + r2)[i] { assert AbstractifyCRequestsSeqToRequestsSeq(r1 + r2)[i] == AbstractifyCRequestToRequest((r1+r2)[i]); if i < |r1| { assert (r1+r2)[i] == r1[i]; } else { lemma_SequenceIndexing(r1, r2, i); assert (r1+r2)[i] == r2[i-|r1|]; } } } } lemma lemma_AbstractifyCRequestsSeqToRequestsSeq_suffix(r:seq, n:int) requires 0 <= n <= |r| requires CRequestsSeqIsAbstractable(r) ensures AbstractifyCRequestsSeqToRequestsSeq(r[n..]) == AbstractifyCRequestsSeqToRequestsSeq(r)[n..] ensures AbstractifyCRequestsSeqToRequestsSeq(r[..n]) == AbstractifyCRequestsSeqToRequestsSeq(r)[..n] { } //////////////////////////////////////////////// // CRequestBatch //////////////////////////////////////////////// type CRequestBatch = seq function method RequestBatchSizeLimit() : int { 100 } //{ 0xFFFF } predicate ValidRequestBatch(c:CRequestBatch) { (forall cr :: cr in c ==> ValidRequest(cr)) && |c| <= RequestBatchSizeLimit() } predicate CRequestBatchIsAbstractable(c:CRequestBatch) { CRequestsSeqIsAbstractable(c) } predicate CRequestBatchSeqIsAbstractable(s:seq) { forall cval :: cval in s ==> CRequestBatchIsAbstractable(cval) } function {:opaque} AbstractifyCRequestBatchToRequestBatch(cvals:CRequestBatch) : RequestBatch requires CRequestsSeqIsAbstractable(cvals) ensures |cvals| == |AbstractifyCRequestBatchToRequestBatch(cvals)| ensures forall i :: 0 <= i < |cvals| ==> AbstractifyCRequestToRequest(cvals[i]) == AbstractifyCRequestBatchToRequestBatch(cvals)[i] ensures forall c :: CRequestIsAbstractable(c) ==> (c in cvals <==> AbstractifyCRequestToRequest(c) in AbstractifyCRequestBatchToRequestBatch(cvals)) { AbstractifyCRequestsSeqToRequestsSeq(cvals) } lemma lemma_AbstractifyCRequestBatchToRequestBatch_isInjective() ensures forall v1, v2 :: CRequestBatchIsAbstractable(v1) && CRequestBatchIsAbstractable(v2) && AbstractifyCRequestBatchToRequestBatch(v1) == AbstractifyCRequestBatchToRequestBatch(v2) ==> v1 == v2 { forall v1, v2 | CRequestBatchIsAbstractable(v1) && CRequestBatchIsAbstractable(v2) && AbstractifyCRequestBatchToRequestBatch(v1) == AbstractifyCRequestBatchToRequestBatch(v2) ensures v1 == v2 { assert |v1| == |AbstractifyCRequestBatchToRequestBatch(v1)|; assert |v1| == |v2|; forall i | 0 <= i < |v1| ensures v1[i] == v2[i] { assert AbstractifyCRequestBatchToRequestBatch(v1)[i] == AbstractifyCRequestBatchToRequestBatch(v2)[i]; lemma_AbstractifyCRequestToRequest_isInjective(); } reveal AbstractifyCRequestBatchToRequestBatch(); } } //////////////////////////////////////////////// // CReply (Almost identical to CRequest) //////////////////////////////////////////////// // Not yet in use. Will be needed for the reply cache. datatype CReply = CReply (client:EndPoint, seqno:uint64, reply:CAppReply) predicate method ValidReply(c:CReply) { c.CReply? ==> EndPointIsValidPublicKey(c.client) && CAppReplyMarshallable(c.reply) } predicate CReplyIsAbstractable(c:CReply) { EndPointIsAbstractable(c.client) && CAppReplyIsAbstractable(c.reply) } function AbstractifyCReplyToReply(c:CReply) : Reply requires CReplyIsAbstractable(c) { Reply(AbstractifyEndPointToNodeIdentity(c.client), c.seqno as int, AbstractifyCAppReplyToAppReply(c.reply)) } lemma lemma_AbstractifyCReplyToReply_isInjective() ensures forall v1, v2 :: CReplyIsAbstractable(v1) && CReplyIsAbstractable(v2) && AbstractifyCReplyToReply(v1) == AbstractifyCReplyToReply(v2) ==> v1 == v2 { // assert forall u1:uint64, u2:uint64 :: u1 as int == u2 as int ==> u1 == u2; lemma_AbstractifyEndPointToNodeIdentity_injective_forall(); } predicate CReplySeqIsAbstractable(creplies:seq) { forall creply :: creply in creplies ==> CReplyIsAbstractable(creply) } function {:opaque} AbstractifyCReplySeqToReplySeq(s:seq) : seq requires CReplySeqIsAbstractable(s) ensures |AbstractifyCReplySeqToReplySeq(s)| == |s| ensures forall i :: 0 <= i < |AbstractifyCReplySeqToReplySeq(s)| ==> AbstractifyCReplySeqToReplySeq(s)[i] == AbstractifyCReplyToReply(s[i]) { if |s| == 0 then [] else [AbstractifyCReplyToReply(s[0])] + AbstractifyCReplySeqToReplySeq(s[1..]) } ////////////////////////////////////////////////////////////////////////////// // ReplyCache type CReplyCache = map predicate CReplyCacheIsAbstractable(m:CReplyCache) { forall e {:trigger EndPointIsValidPublicKey(e)} :: e in m ==> EndPointIsValidPublicKey(e) && CReplyIsAbstractable(m[e]) } function max_reply_cache_size() : int { 256 } // 0x1_0000_0000 predicate ValidReplyCache(m:CReplyCache) { && CReplyCacheIsAbstractable(m) && |m| < max_reply_cache_size() && (forall e {:trigger ValidReply(m[e])} :: e in m ==> ValidReply(m[e])) } function {:opaque} AbstractifyCReplyCacheToReplyCache(m:CReplyCache) : ReplyCache requires CReplyCacheIsAbstractable(m) { assert forall e :: e in m ==> EndPointIsValidPublicKey(e); lemma_AbstractifyEndPointToNodeIdentity_injective_forall(); // var test:CReply->Reply := (AbstractifyCReplyToReply as CReply->Reply); AbstractifyMap(m, AbstractifyEndPointToNodeIdentity, AbstractifyCReplyToReply, RefineNodeIdentityToEndPoint) } lemma lemma_AbstractifyCReplyCacheToReplyCache_properties(m:CReplyCache) requires CReplyCacheIsAbstractable(m) ensures m == map [] ==> AbstractifyCReplyCacheToReplyCache(m) == map [] ensures forall e {:trigger e in m}{:trigger e in AbstractifyCReplyCacheToReplyCache(m)} :: (e in m <==> EndPointIsValidPublicKey(e) && e in AbstractifyCReplyCacheToReplyCache(m)) ensures forall e {:trigger e in m, EndPointIsValidPublicKey(e)}{:trigger e in AbstractifyCReplyCacheToReplyCache(m)} :: (e !in m && EndPointIsValidPublicKey(e) ==> e !in AbstractifyCReplyCacheToReplyCache(m)) ensures forall e {:trigger AbstractifyCReplyToReply(m[e])}{:trigger AbstractifyCReplyCacheToReplyCache(m)[e]} :: e in m ==> AbstractifyCReplyCacheToReplyCache(m)[e] == AbstractifyCReplyToReply(m[e]) ensures forall re :: re in AbstractifyCReplyCacheToReplyCache(m) ==> re in m ensures forall e, r {:trigger EndPointIsValidPublicKey(e), ValidReply(r)} :: EndPointIsValidPublicKey(e) && ValidReply(r) ==> var rm := AbstractifyCReplyCacheToReplyCache(m); var rm' := AbstractifyCReplyCacheToReplyCache(m[e := r]); rm' == AbstractifyCReplyCacheToReplyCache(m)[AbstractifyEndPointToNodeIdentity(e) := AbstractifyCReplyToReply(r)] ensures forall e {:trigger RemoveElt(m,e)} :: (EndPointIsValidPublicKey(e) && NodeIdentityIsRefinable(AbstractifyEndPointToNodeIdentity(e)) && RefineNodeIdentityToEndPoint(AbstractifyEndPointToNodeIdentity(e)) == e && e in m) ==> var rm := AbstractifyCReplyCacheToReplyCache(m); var rm' := AbstractifyCReplyCacheToReplyCache(RemoveElt(m, e)); rm' == RemoveElt(rm, e) { assert forall e :: e in m ==> EndPointIsValidPublicKey(e); reveal AbstractifyCReplyCacheToReplyCache(); lemma_AbstractifyMap_properties(m, AbstractifyEndPointToNodeIdentity, AbstractifyCReplyToReply, RefineNodeIdentityToEndPoint); } ////////////////////////////////////////////////////////////////////////////// // MapOfSeqNums predicate MapOfSeqNumsIsAbstractable(m:map) { forall e :: e in m ==> EndPointIsValidPublicKey(e) } function {:opaque} AbstractifyMapOfSeqNums(m:map) : map requires MapOfSeqNumsIsAbstractable(m) { lemma_AbstractifyEndPointToNodeIdentity_injective_forall(); AbstractifyMap(m, AbstractifyEndPointToNodeIdentity, uint64_to_int, RefineNodeIdentityToEndPoint) } lemma lemma_AbstractifyMapOfSeqNums_properties(m:map) requires MapOfSeqNumsIsAbstractable(m) ensures m == map [] ==> AbstractifyMapOfSeqNums(m) == map [] ensures forall e :: (e in m <==> EndPointIsValidPublicKey(e) && AbstractifyEndPointToNodeIdentity(e) in AbstractifyMapOfSeqNums(m)) ensures forall e :: (e !in m && EndPointIsValidPublicKey(e) ==> AbstractifyEndPointToNodeIdentity(e) !in AbstractifyMapOfSeqNums(m)) ensures forall e :: e in m ==> AbstractifyMapOfSeqNums(m)[AbstractifyEndPointToNodeIdentity(e)] == m[e] as int ensures forall e, u {:trigger AbstractifyMapOfSeqNums(m[e := u])} :: EndPointIsValidPublicKey(e) ==> var rm := AbstractifyMapOfSeqNums(m); var rm' := AbstractifyMapOfSeqNums(m[e := u]); rm' == AbstractifyMapOfSeqNums(m)[AbstractifyEndPointToNodeIdentity(e) := u as int] { lemma_AbstractifyEndPointToNodeIdentity_injective_forall(); assert forall ck1, ck2 :: EndPointIsValidPublicKey(ck1) && EndPointIsValidPublicKey(ck2) && AbstractifyEndPointToNodeIdentity(ck1) == AbstractifyEndPointToNodeIdentity(ck2) ==> ck1 == ck2; assert forall ck1, ck2 :: AbstractifyEndPointToNodeIdentity.requires(ck1) && AbstractifyEndPointToNodeIdentity.requires(ck2) && AbstractifyEndPointToNodeIdentity(ck1) == AbstractifyEndPointToNodeIdentity(ck2) ==> ck1 == ck2; reveal AbstractifyMapOfSeqNums(); lemma_AbstractifyMap_properties(m, AbstractifyEndPointToNodeIdentity, uint64_to_int, RefineNodeIdentityToEndPoint); } ////////////////////////////////////////////////////////////////////////////// // Vote datatype CVote = CVote(max_value_bal:CBallot, max_val:CRequestBatch) datatype CVotes = CVotes(v:map) function ValidVote(vote:CVote) : bool { ValidRequestBatch(vote.max_val) } function method max_votes_len() : int { 8 } // previously 0x10_0000 function ValidVotes(votes:CVotes) : bool { && |votes.v| < max_votes_len() && (forall o :: o in votes.v ==> ValidVote(votes.v[o])) } predicate CVoteIsAbstractable(vote:CVote) { && vote.CVote? // OBSERVE: Always true, but seems necessary to avoid errors below && CBallotIsAbstractable(vote.max_value_bal) && CRequestBatchIsAbstractable(vote.max_val) } function AbstractifyCVoteToVote(vote:CVote) : Vote requires CVoteIsAbstractable(vote) { Vote(AbstractifyCBallotToBallot(vote.max_value_bal), AbstractifyCRequestBatchToRequestBatch(vote.max_val)) } predicate CVotesIsAbstractable(votes:CVotes) { forall i :: i in votes.v ==> COperationNumberIsAbstractable(i) && CVoteIsAbstractable(votes.v[i]) } lemma lemma_AbstractifyMapOfThings(m:map, newDomain:set) requires newDomain == set i | i in m :: AbstractifyCOperationNumberToOperationNumber(i) ensures forall o :: o in newDomain ==> 0<=o<0x10000000000000000 ensures forall o :: o in newDomain ==> COperationNumber(o as uint64) in m { forall o | o in newDomain ensures 0<=o<0x10000000000000000 ensures COperationNumber(o as uint64) in m { var i :| i in m && o==AbstractifyCOperationNumberToOperationNumber(i); assert 0 <= i.n as int < 0x10000000000000000; } } function {:opaque} AbstractifyCVotesToVotes(votes:CVotes) : Votes requires CVotesIsAbstractable(votes) { // var newDomain := set i | i in votes.v :: AbstractifyCOperationNumberToOperationNumber(i); lemma_AbstractifyMapOfThings(votes.v, set i | i in votes.v :: AbstractifyCOperationNumberToOperationNumber(i)); // map i | i in newDomain :: AbstractifyCVoteToVote(votes.v[COperationNumber(i as uint64)]) map j {:trigger votes.v[COperationNumber(j as uint64)]} | j in (set i | i in votes.v :: AbstractifyCOperationNumberToOperationNumber(i)) :: AbstractifyCVoteToVote(votes.v[COperationNumber(j as uint64)]) } lemma lemma_VotesInjective(v1:CVotes, v2:CVotes) requires CVotesIsAbstractable(v1) requires CVotesIsAbstractable(v2) requires AbstractifyCVotesToVotes(v1) == AbstractifyCVotesToVotes(v2) ensures v1 == v2 { reveal AbstractifyCVotesToVotes(); forall k | k in v1.v ensures k in v2.v { assert AbstractifyCOperationNumberToOperationNumber(k) in AbstractifyCVotesToVotes(v1); assert AbstractifyCOperationNumberToOperationNumber(k) in AbstractifyCVotesToVotes(v2); assert k in v2.v; } forall k | k in v2.v ensures k in v1.v { assert AbstractifyCOperationNumberToOperationNumber(k) in AbstractifyCVotesToVotes(v2); assert AbstractifyCOperationNumberToOperationNumber(k) in AbstractifyCVotesToVotes(v1); assert k in v1.v; } assert domain(v1.v)==domain(v2.v); forall k | k in domain(v1.v) ensures v1.v[k] == v2.v[k]; { assert AbstractifyCVoteToVote(v1.v[k]) == AbstractifyCVotesToVotes(v1)[AbstractifyCOperationNumberToOperationNumber(k)]; // OBSERVER trigger map assert AbstractifyCVoteToVote(v2.v[k]) == AbstractifyCVotesToVotes(v2)[AbstractifyCOperationNumberToOperationNumber(k)]; // OBSERVER trigger map assert AbstractifyCBallotToBallot(v1.v[k].max_value_bal) == AbstractifyCBallotToBallot(v2.v[k].max_value_bal); // assert v1.v[k].max_value_bal.seqno == v2.v[k].max_value_bal.seqno; lemma_BallotInjective(v1.v[k].max_value_bal, v2.v[k].max_value_bal); assert AbstractifyCRequestBatchToRequestBatch(v1.v[k].max_val) == AbstractifyCRequestBatchToRequestBatch(v2.v[k].max_val); lemma_AbstractifyCRequestBatchToRequestBatch_isInjective(); assert v1.v[k].max_val == v2.v[k].max_val; } assert v1.v==v2.v; assert v1==v2; } ///////////////////// // LearnerDecidableOpn datatype OptionOpn = ExistsOperation(opn:COperationNumber) | NotExistsOperation() } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/RSL/CmdLineParser.i.dfy ================================================ include "../Common/CmdLineParser.i.dfy" include "CPaxosConfiguration.i.dfy" module PaxosCmdLineParser_i { import opened Native__Io_s import opened Native__NativeTypes_s import opened CmdLineParser_i import opened Common__NetClient_i import opened LiveRSL__CPaxosConfiguration_i function paxos_config_parsing(args:seq>) : CPaxosConfiguration { var (_, endpoints) := parse_end_points(args); CPaxosConfiguration(endpoints) } function paxos_parse_id(arg:seq) : EndPoint { var (_, ep) := parse_end_point(arg); ep } method parse_cmd_line(id:EndPoint, args:seq>) returns (ok:bool, config:CPaxosConfiguration, my_index:uint64) requires EndPointIsValidPublicKey(id) ensures ok ==> && CPaxosConfigurationIsValid(config) && |config.replica_ids| > 0 && 0 <= my_index as int < |config.replica_ids| && config == paxos_config_parsing(args) && config.replica_ids[my_index] == id { var tuple1 := parse_end_points(args); ok := tuple1.0; if !ok { print "Error encountered while processing command-line arguments"; return; } var endpoints := tuple1.1; if |endpoints| < 1 { print "Must have at least one replica.\n"; ok := false; return; } if |endpoints| >= 0xffff_ffff_ffff_ffff { print "Internal error: impossibly many endpoints.\n"; ok := false; return; } var unique := test_unique(endpoints); if !unique { print "Error: Each endpoint must be unique.\n"; ok := false; return; } config := CPaxosConfiguration(endpoints); lemma_MinQuorumSizeLessThanReplicaCount(config); ok, my_index := CGetReplicaIndex(id, config); if !ok { print "Error: Could not find local endpoint (last command-line endpoint) in list of preceding endpoints\n"; return; } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/RSL/ConstantsState.i.dfy ================================================ include "CPaxosConfiguration.i.dfy" module LiveRSL__ConstantsState_i { import opened LiveRSL__Constants_i import opened LiveRSL__CPaxosConfiguration_i import opened LiveRSL__CTypes_i import opened LiveRSL__ParametersState_i datatype ConstantsState = ConstantsState( config:CPaxosConfiguration, params:ParametersState ) predicate ConstantsStateIsAbstractable(constants:ConstantsState) { CPaxosConfigurationIsAbstractable(constants.config) } predicate WFConstantsState(constants:ConstantsState) { && WFCPaxosConfiguration(constants.config) && WFParametersState(constants.params) } predicate ConstantsStateIsValid(cs:ConstantsState) { && CPaxosConfigurationIsValid(cs.config) && ConstantsStateIsAbstractable(cs) && WFConstantsState(cs) && cs.params.max_integer_val > cs.params.max_log_length > 0 && cs.params.max_log_length as int < max_votes_len() && cs.params.max_integer_val < 0x8000_0000_0000_0000 && 0 <= cs.params.heartbeat_period < cs.params.max_integer_val && 0 < cs.params.max_batch_size as int <= RequestBatchSizeLimit() } function AbstractifyConstantsStateToLConstants(constants:ConstantsState) : LConstants requires ConstantsStateIsAbstractable(constants) { LConstants( AbstractifyCPaxosConfigurationToConfiguration(constants.config), AbstractifyParametersStateToLParameters(constants.params)) } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/RSL/ElectionModel.i.dfy ================================================ include "ElectionState.i.dfy" include "../Common/NodeIdentity.i.dfy" include "MinCQuorumSize.i.dfy" include "../Common/Util.i.dfy" include "../Common/UpperBound.i.dfy" module LiveRSL__ElectionModel_i { import opened Native__Io_s import opened Native__NativeTypes_s import opened LiveRSL__CMessage_i import opened LiveRSL__CMessageRefinements_i import opened LiveRSL__Configuration_i import opened LiveRSL__ConstantsState_i import opened LiveRSL__CPaxosConfiguration_i import opened LiveRSL__CTypes_i import opened LiveRSL__Election_i import opened LiveRSL__ElectionState_i import opened LiveRSL__MinCQuorumSize_i import opened LiveRSL__ReplicaConstantsState_i import opened LiveRSL__Types_i import opened Common__NodeIdentity_i import opened Common__SeqIsUnique_i import opened Common__SeqIsUniqueDef_i import opened Common__UpperBound_s import opened Common__UpperBound_i import opened Common__Util_i import opened Collections__Seqs_s import opened Collections__Sets_i // Same as x == y, but triggers extensional equality on fields and provides better error diagnostics predicate Eq_ElectionState(x:ElectionState, y:ElectionState) { && x.constants == y.constants && x.current_view == y.current_view && x.current_view_suspectors == y.current_view_suspectors && x.epoch_end_time == y.epoch_end_time && x.epoch_length == y.epoch_length && x.requests_received_this_epoch == y.requests_received_this_epoch && x.requests_received_prev_epochs == y.requests_received_prev_epochs } ////////////////////// // BALLOT MATH ////////////////////// method CComputeSuccessorView(cb:CBallot, constants:ConstantsState) returns(cb':CBallot) requires CBallotIsAbstractable(cb) requires ConstantsStateIsAbstractable(constants) requires CPaxosConfigurationIsValid(constants.config) requires cb.seqno < 0xFFFF_FFFF_FFFF_FFFF ensures CBallotIsAbstractable(cb') ensures ComputeSuccessorView(AbstractifyCBallotToBallot(cb), AbstractifyConstantsStateToLConstants(constants)) == AbstractifyCBallotToBallot(cb') { ghost var b := AbstractifyCBallotToBallot(cb); if cb.proposer_id < (|constants.config.replica_ids| as uint64) - 1 { cb' := CBallot(cb.seqno, cb.proposer_id + 1); } else { cb' := CBallot(cb.seqno + 1, 0); } } function ElectionStateUpdateValueSetsToReflectNextEpoch(es:ElectionState):ElectionState { es.(requests_received_this_epoch := [], requests_received_prev_epochs := es.requests_received_prev_epochs + es.requests_received_this_epoch) } //function method CElectionStateValueSetsReflectNewView(es:CElectionState):CElectionState // requires CElectionStateIsAbstractable(es) // ensures CElectionStateIsAbstractable(CElectionStateValueSetsReflectNewView(es)) // ensures ElectionStateUpdateValueSetsToReflectNextEpoch(AbstractifyCElectionStateToElectionState(es)) // == AbstractifyCElectionStateToElectionState(CElectionStateValueSetsReflectNewView(es)) //{ // lemma_AbstractifyCRequestsSeqToRequestsSeq_concat(es.requests_received_prev_epochs, es.requests_received_this_epoch); // es[requests_received_this_epoch := []] // [requests_received_prev_epochs := es.requests_received_prev_epochs + es.requests_received_this_epoch] //} ////////////////////// // SEQUENCE MATH ////////////////////// function method BoundCRequestSequence(s:seq, lengthBound:uint64):(bool,seq) requires |s| < 0x1_0000_0000_0000_0000 { if 0 <= lengthBound < (|s| as uint64) then (true, s[..lengthBound]) else (false,s) } lemma lemma_BoundCRequestSequence(s:seq, lengthBound:uint64) requires |s| < 0x1_0000_0000_0000_0000 requires CRequestsSeqIsAbstractable(s) ensures BoundRequestSequence(AbstractifyCRequestsSeqToRequestsSeq(s), UpperBoundFinite(lengthBound as int)) == AbstractifyCRequestsSeqToRequestsSeq(BoundCRequestSequence(s, lengthBound).1) ensures |BoundCRequestSequence(s, lengthBound).1| <= lengthBound as int { } lemma FindMatchingRequest(s:seq, headers:set, header:CRequestHeader) returns (index:int) requires HeadersMatch(s, headers) requires header in headers requires |s| >= 1 ensures 0 <= index < |s| ensures CRequestHeader(s[index].client, s[index].seqno) == header { if |s| == 1 { assert CRequestHeader(s[0].client, s[0].seqno) in headers; assert |headers| == 1; ThingsIKnowAboutASingletonSet(headers, CRequestHeader(s[0].client, s[0].seqno), header); return 0; } else { var head := CRequestHeader(s[0].client, s[0].seqno); if head == header { return 0; } else { var new_set := headers - { head }; forall r | r in s[1..] ensures CRequestHeader(r.client, r.seqno) in new_set; { if CRequestHeader(r.client, r.seqno) != head { assert CRequestHeader(r.client, r.seqno) in new_set; } else { var j :| 0 <= j < |s[1..]| && s[1..][j] == r; assert s[j+1] == s[1..][j] == r; assert CRequestsMatch(s[0], s[j+1]); assert j+1 == 0; assert false; } } index := FindMatchingRequest(s[1..], new_set, header); index := index + 1; } } } // This is inefficient, but we never expect to call it in practice, since we shouldn't exceed lengthBound method BoundCRequestHeaders(s:seq, ghost headers:set, lengthBound:uint64, cur_req_set:MutableSet) returns (ghost new_headers:set) requires |s| < 0x1_0000_0000_0000_0000 requires HeadersMatch(s, headers) requires |s| > lengthBound as int modifies cur_req_set ensures HeadersMatch(BoundCRequestSequence(s, lengthBound).1, new_headers) ensures forall h :: h in new_headers ==> h in headers ensures MutableSet.SetOf(cur_req_set) == new_headers { var i := 0; new_headers := {}; cur_req_set.RemoveAll(); while i < lengthBound as int invariant 0 <= i <= lengthBound as int; invariant HeadersMatch(s[..i], new_headers) invariant forall h :: h in new_headers ==> h in headers invariant MutableSet.SetOf(cur_req_set) == new_headers { var new_header := CRequestHeader(s[i].client, s[i].seqno); if new_header in new_headers { var j := FindMatchingRequest(s[..i], new_headers, new_header); assert CRequestsMatch(s[j], s[i]); assert false; } new_headers := new_headers + { new_header }; cur_req_set.Add(new_header); i := i + 1; } } ////////////////////// // REQUESTS ////////////////////// function {:fuel 5,6} RemoveAllSatisfiedCRequestsInSequence(s:seq, r:CRequest):seq ensures forall r' :: r' in RemoveAllSatisfiedCRequestsInSequence(s, r) ==> r' in s { if |s| == 0 then [] else if CRequestSatisfiedBy(s[0], r) then RemoveAllSatisfiedCRequestsInSequence(s[1..], r) else [s[0]] + RemoveAllSatisfiedCRequestsInSequence(s[1..], r) } function {:fuel 5,6} RemoveAllSatisfiedCRequestsInSequenceAlt(s:seq, r:CRequest):seq { if |s| == 0 then [] else if CRequestSatisfiedBy(last(s), r) then RemoveAllSatisfiedCRequestsInSequence(all_but_last(s), r) else RemoveAllSatisfiedCRequestsInSequence(all_but_last(s), r) + [last(s)] } lemma lemma_RemoveAllSatisfiedCRequestsInSequenceAltEquivalent(s:seq, r:CRequest) ensures RemoveAllSatisfiedCRequestsInSequence(s, r) == RemoveAllSatisfiedCRequestsInSequenceAlt(s, r) { if |s| == 0 || |s| == 1 { return; } lemma_RemoveAllSatisfiedCRequestsInSequenceAltEquivalent(s[1..], r); lemma_RemoveAllSatisfiedCRequestsInSequenceAltEquivalent(all_but_last(s[1..]), r); assert all_but_last(s)[0] == s[0]; assert all_but_last(s)[1..] == all_but_last(s[1..]); } lemma lemma_RemoveAllSatisfiedCRequestsInSequenceUpdate(s:seq, r:CRequest, i:int) requires 0 <= i < |s| ensures RemoveAllSatisfiedCRequestsInSequence(s[..i+1], r) == RemoveAllSatisfiedCRequestsInSequence(s[..i], r) + if CRequestSatisfiedBy(s[i], r) then [] else [s[i]] { var s' := s[..i+1]; assert last(s') == s[i]; assert all_but_last(s') == s[..i]; lemma_RemoveAllSatisfiedCRequestsInSequenceAltEquivalent(s', r); } function HeadersFromPrefix(s:seq, i:int):set requires 0 <= i <= |s| { set j | 0 <= j < i :: CRequestHeader(s[j].client, s[j].seqno) } lemma lemma_HeadersFromPrefixIncrease(s:seq, i:int) requires 0 <= i requires i+1 <= |s| ensures HeadersFromPrefix(s, i+1) == HeadersFromPrefix(s, i) + { CRequestHeader(s[i].client, s[i].seqno) } { } lemma lemma_EmptyHeadersMatch( s:seq, headers:set ) requires s == [] requires headers == {} ensures HeadersMatch(s, headers) { } lemma lemma_HeadersMatchImpliesEveryHeaderHasACorrespondingEntry( requests:seq, headers:set, header:CRequestHeader ) returns ( i:int ) requires HeadersMatch(requests, headers) requires header in headers ensures 0 <= i < |requests| ensures header.client == requests[i].client ensures header.seqno == requests[i].seqno { if |requests| == 0 { return; } var num_requests := |requests|; var last_header := CRequestHeader(requests[num_requests-1].client, requests[num_requests-1].seqno); assert last_header in headers; if header == last_header { i := num_requests - 1; return; } var requests' := requests[..num_requests-1]; var headers' := headers - { last_header }; forall r' | r' in requests' ensures CRequestHeader(r'.client, r'.seqno) in headers' { var j :| 0 <= j < |requests|-1 && r' == requests[j]; var k := |requests| - 1; assert !CRequestsMatch(requests[j], requests[k]); } i := lemma_HeadersMatchImpliesEveryHeaderHasACorrespondingEntry(requests[..num_requests - 1], headers - { last_header }, header); } lemma lemma_AddingOneHeaderPreservesMatch( s:seq, headers:set, r:CRequest, s':seq, headers':set ) requires s' == s + [r] requires headers' == headers + { CRequestHeader(r.client, r.seqno) } requires HeadersMatch(s, headers) requires forall r' :: r' in s ==> !CRequestsMatch(r', r) ensures HeadersMatch(s', headers') { var new_header := CRequestHeader(r.client, r.seqno); if new_header in headers { var i := lemma_HeadersMatchImpliesEveryHeaderHasACorrespondingEntry(s, headers, new_header); assert CRequestsMatch(s[i], r); assert false; } calc { |s'|; |s| + 1; |headers| + 1; |headers'|; } assert forall r' :: r' in s' ==> CRequestHeader(r'.client, r'.seqno) in headers'; } lemma lemma_HeadersMatchImpliesHeadersFromPrefix(requests:seq, headers:set) requires HeadersMatch(requests, headers) ensures headers == HeadersFromPrefix(requests, |requests|) { var headers' := HeadersFromPrefix(requests, |requests|); forall h | h in headers ensures h in headers' { var i := lemma_HeadersMatchImpliesEveryHeaderHasACorrespondingEntry(requests, headers, h); } forall h | h in headers' ensures h in headers { var i :| 0 <= i < |requests| && h == CRequestHeader(requests[i].client, requests[i].seqno); } } method{:timeLimitMultiplier 2} RemoveAllSatisfiedCRequestsInSequenceIter( requests:seq, ghost headers:set, cur_req_set:MutableSet, r:CRequest ) returns ( requests':seq, ghost headers':set ) requires |requests| < 0x1_0000_0000_0000_0000 requires HeadersMatch(requests, headers) requires MutableSet.SetOf(cur_req_set) == headers modifies cur_req_set ensures requests' == RemoveAllSatisfiedCRequestsInSequence(requests, r) ensures HeadersMatch(requests', headers') // ensures headers' == headers <==> requests' == requests ensures MutableSet.SetOf(cur_req_set) == headers' { var i:uint64 := 0; var len := |requests| as uint64; ghost var removed_headers:set := {}; headers' := {}; requests' := []; i := 0; lemma_EmptyHeadersMatch(requests', headers'); while i < len invariant 0 <= i <= len invariant HeadersMatch(requests', headers') invariant forall r' :: r' in requests' ==> r' in requests[..i] invariant requests' == RemoveAllSatisfiedCRequestsInSequence(requests[..i], r) invariant MutableSet.SetOf(cur_req_set) == headers - removed_headers invariant headers' + removed_headers == HeadersFromPrefix(requests, i as int) invariant removed_headers * headers' == {} { ghost var old_requests' := requests'; ghost var old_headers' := headers'; lemma_RemoveAllSatisfiedCRequestsInSequenceUpdate(requests, r, i as int); var h := CRequestHeader(requests[i].client, requests[i].seqno); if h in removed_headers || h in headers' { var j :| 0 <= j < i && h == CRequestHeader(requests[j].client, requests[j].seqno); assert CRequestsMatch(requests[j], requests[i]); assert false; } if CRequestSatisfiedBy(requests[i], r) { cur_req_set.Remove(h); removed_headers := removed_headers + {h}; } else { headers' := headers' + {h}; requests' := requests' + [requests[i]]; lemma_AddingOneHeaderPreservesMatch(old_requests', old_headers', requests[i], requests', headers'); } lemma_HeadersFromPrefixIncrease(requests, i as int); i := i + 1; } assert requests[..i] == requests; lemma_HeadersMatchImpliesHeadersFromPrefix(requests, headers); } lemma lemma_RemoveAllSatisfiedCRequestsProducesCRequestSubset(requests:seq, r:CRequest) ensures forall r' :: r' in RemoveAllSatisfiedCRequestsInSequence(requests, r) ==> r' in requests { } lemma lemma_RemoveAllSatisfiedCRequestsProducesHeaderSubset( requests:seq, headers:set, requests':seq, headers':set, r:CRequest ) requires HeadersMatch(requests, headers) requires HeadersMatch(requests', headers') requires requests' == RemoveAllSatisfiedCRequestsInSequence(requests, r) ensures headers' <= headers { forall h | h in headers' ensures h in headers { var i := lemma_HeadersMatchImpliesEveryHeaderHasACorrespondingEntry(requests', headers', h); lemma_RemoveAllSatisfiedCRequestsProducesCRequestSubset(requests, r); assert requests'[i] in requests; } } lemma lemma_RemoveAllSatisfiedPreservesHeaderMatches(requests1:seq, headers1:set, requests2:seq, headers2:set, requests1':seq, headers1':set, requests2':seq, headers2':set, r:CRequest) requires HeadersMatch(requests1, headers1) requires HeadersMatch(requests2, headers2) requires HeadersMatch(requests1 + requests2, headers1 + headers2) requires HeadersMatch(requests1', headers1') requires HeadersMatch(requests2', headers2') requires requests1' == RemoveAllSatisfiedCRequestsInSequence(requests1, r) requires requests2' == RemoveAllSatisfiedCRequestsInSequence(requests2, r) ensures HeadersMatch(requests1' + requests2', headers1' + headers2') { var requests3 := requests1 + requests2; var requests3' := requests1' + requests2'; var headers3' := headers1' + headers2'; lemma_RemoveAllSatisfiedCRequestsProducesHeaderSubset(requests1, headers1, requests1', headers1', r); lemma_RemoveAllSatisfiedCRequestsProducesHeaderSubset(requests2, headers2, requests2', headers2', r); forall h | h in headers1' && h in headers2' ensures false { assert h in headers1 && h in headers2; var i := lemma_HeadersMatchImpliesEveryHeaderHasACorrespondingEntry(requests1, headers1, h); var j := lemma_HeadersMatchImpliesEveryHeaderHasACorrespondingEntry(requests2, headers2, h); assert CRequestsMatch(requests3[i], requests3[j + |requests1|]); } assert headers1' * headers2' == {}; assert |requests3'| == |headers3'|; } lemma lemma_RemoveAllSatisfiedCRequestsInSequenceAbstractable(s:seq, r:CRequest) requires CRequestsSeqIsAbstractable(s) requires CRequestIsAbstractable(r) ensures CRequestsSeqIsAbstractable(RemoveAllSatisfiedCRequestsInSequence(s, r)) { } lemma lemma_CRequestsMatch() ensures forall r1:CRequest, r2:CRequest :: CRequestIsAbstractable(r1) && CRequestIsAbstractable(r2) ==> CRequestsMatch(r1, r2) == RequestsMatch(AbstractifyCRequestToRequest(r1), AbstractifyCRequestToRequest(r2)) { forall r1:CRequest, r2:CRequest | CRequestIsAbstractable(r1) && CRequestIsAbstractable(r2) ensures CRequestsMatch(r1, r2) == RequestsMatch(AbstractifyCRequestToRequest(r1), AbstractifyCRequestToRequest(r2)) { lemma_AbstractifyCRequestToRequest_isInjective(); lemma_AbstractifyEndPointToNodeIdentity_injective_forall(); } } lemma lemma_SequenceDots(s:seq, start:int) requires 0 <= start <= |s| ensures s[start..] == s[start..|s|] {} lemma lemma_RemoveAllSatisfiedCRequestsInSequenceProperties(s:seq, r:CRequest) requires CRequestsSeqIsAbstractable(s) requires CRequestIsAbstractable(r) ensures CRequestsSeqIsAbstractable(RemoveAllSatisfiedCRequestsInSequence(s, r)) ensures AbstractifyCRequestsSeqToRequestsSeq(RemoveAllSatisfiedCRequestsInSequence(s, r)) == RemoveAllSatisfiedRequestsInSequence(AbstractifyCRequestsSeqToRequestsSeq(s), AbstractifyCRequestToRequest(r)) ensures |RemoveAllSatisfiedCRequestsInSequence(s, r)| <= |s| ensures ElectionRequestQueueValid(s) ==> ElectionRequestQueueValid(RemoveAllSatisfiedCRequestsInSequence(s, r)) { lemma_RemoveAllSatisfiedCRequestsInSequenceAbstractable(s, r); reveal AbstractifyCRequestsSeqToRequestsSeq(); if |s| == 0 { return; } if AbstractifyCRequestToRequest(s[0]).client == AbstractifyCRequestToRequest(r).client { lemma_AbstractifyEndPointToNodeIdentity_injective(s[0].client, r.client); } lemma_RemoveAllSatisfiedCRequestsInSequenceProperties(s[1..], r); } ////////////////////// // ACTIONS ////////////////////// method InitElectionState(constants:ReplicaConstantsState) returns (election:CElectionState, cur_req_set:MutableSet, prev_req_set:MutableSet) requires ReplicaConstantsStateIsAbstractable(constants) requires ReplicaConstantsState_IsValid(constants) requires CPaxosConfigurationIsValid(constants.all.config) ensures CElectionStateIsAbstractable(election) ensures WellFormedLConfiguration(AbstractifyReplicaConstantsStateToLReplicaConstants(constants).all.config) ensures ElectionStateInit(AbstractifyCElectionStateToElectionState(election), AbstractifyReplicaConstantsStateToLReplicaConstants(constants)) ensures CElectionStateIsValid(election) ensures fresh(cur_req_set) && fresh(prev_req_set) && cur_req_set != prev_req_set ensures MutableSet.SetOf(cur_req_set) == election.cur_req_set ensures MutableSet.SetOf(prev_req_set) == election.prev_req_set { election := CElectionState(constants, CBallot(1, 0), [], 0, constants.all.params.baseline_view_timeout_period, [], {}, [], {}); cur_req_set := MutableSet.EmptySet(); prev_req_set := MutableSet.EmptySet(); calc ==> { true; { reveal SeqIsUnique(); } SeqIsUnique(election.current_view_suspectors); } // Some subset of below is an OBSERVE ghost var es := AbstractifyCElectionStateToElectionState(election); ghost var c := AbstractifyReplicaConstantsStateToLReplicaConstants(constants); assert es.constants == c; assert es.current_view == Ballot(1, 0); ghost var empty_set := {}; calc { es.current_view_suspectors; { reveal AbstractifySeqOfUint64sToSetOfInts(); } empty_set; } assert es.epoch_end_time == 0; assert es.epoch_length == c.all.params.baseline_view_timeout_period; } method {:timeLimitMultiplier 3} ElectionProcessHeartbeat(ces:CElectionState, cp:CPacket, clock:uint64, cur_req_set:MutableSet, prev_req_set:MutableSet) returns (ces':CElectionState) requires CElectionStateIsValid(ces) requires CPacketIsAbstractable(cp) requires cp.msg.CMessage_Heartbeat? requires MutableSet.SetOf(cur_req_set) == ces.cur_req_set requires MutableSet.SetOf(prev_req_set) == ces.prev_req_set modifies cur_req_set, prev_req_set ensures CElectionStateIsValid(ces') ensures ElectionStateProcessHeartbeat(AbstractifyCElectionStateToElectionState(ces), AbstractifyCElectionStateToElectionState(ces'), AbstractifyCPacketToRslPacket(cp), clock as int) ensures MutableSet.SetOf(cur_req_set) == ces'.cur_req_set ensures MutableSet.SetOf(prev_req_set) == ces'.prev_req_set { var src_ep := cp.src; var found:bool, index:uint64 := CGetReplicaIndex(src_ep, ces.constants.all.config); ghost var es := AbstractifyCElectionStateToElectionState(ces); ghost var es':ElectionState; lemma_AbstractifySeqOfUint64sToSetOfInts_properties(ces.current_view_suspectors); if !found { es' := es; ces' := ces; } else { ghost var p := AbstractifyCPacketToRslPacket(cp); ghost var sender_index := GetReplicaIndex(p.src, es.constants.all.config); if cp.msg.bal_heartbeat == ces.current_view && cp.msg.suspicious { es' := es.(current_view_suspectors := es.current_view_suspectors + {sender_index}); ces' := ces.(current_view_suspectors := AppendToUniqueSeqMaybe(ces.current_view_suspectors, index)); lemma_AbstractifySeqOfUint64sToSetOfInts_append(ces.current_view_suspectors, index); assert Eq_ElectionState(es', AbstractifyCElectionStateToElectionState(ces')); } else { var cmp := CBalLt(ces.current_view, cp.msg.bal_heartbeat); if cmp { ghost var new_epoch_length := UpperBoundedAddition(es.epoch_length, es.epoch_length, es.constants.all.params.max_integer_val); es' := es.(current_view := p.msg.bal_heartbeat, current_view_suspectors := (if p.msg.suspicious then {sender_index} else {}), epoch_length := new_epoch_length, epoch_end_time := UpperBoundedAddition(clock as int, new_epoch_length, es.constants.all.params.max_integer_val), requests_received_prev_epochs := BoundRequestSequence(es.requests_received_prev_epochs + es.requests_received_this_epoch, es.constants.all.params.max_integer_val), requests_received_this_epoch := []); var cnewEpochLength := UpperBoundedAdditionImpl(ces.epoch_length, ces.epoch_length, ces.constants.all.params.max_integer_val); var cnewEpochEndTime := UpperBoundedAdditionImpl(clock, cnewEpochLength, ces.constants.all.params.max_integer_val); var new_seq := ces.requests_received_prev_epochs + ces.requests_received_this_epoch; ghost var new_set := ces.prev_req_set + ces.cur_req_set; prev_req_set.AddSet(cur_req_set); cur_req_set.RemoveAll(); assert HeadersMatch(new_seq, new_set); var tuple := BoundCRequestSequence(new_seq, ces.constants.all.params.max_integer_val); var bounded, bounded_seq := tuple.0, tuple.1; if bounded { // Should never happen new_set := BoundCRequestHeaders(new_seq, new_set, ces.constants.all.params.max_integer_val, prev_req_set); } ces' := ces.( //CElectionStateValueSetsReflectNewView(ces) current_view := cp.msg.bal_heartbeat, current_view_suspectors := (if cp.msg.suspicious then [index] else []), epoch_length := cnewEpochLength, epoch_end_time := cnewEpochEndTime, requests_received_prev_epochs := bounded_seq, requests_received_this_epoch := [], cur_req_set := {}, prev_req_set := new_set); lemma_AbstractifyCRequestsSeqToRequestsSeq_concat(ces.requests_received_prev_epochs, ces.requests_received_this_epoch); lemma_BoundCRequestSequence(ces.requests_received_prev_epochs + ces.requests_received_this_epoch, ces.constants.all.params.max_integer_val); forall ensures SeqIsUnique(ces'.current_view_suspectors) { reveal SeqIsUnique(); } calc { AbstractifySeqOfUint64sToSetOfInts(ces'.current_view_suspectors); { assert index as int == sender_index; reveal AbstractifySeqOfUint64sToSetOfInts(); lemma_AbstractifySeqOfUint64sToSetOfInts_properties(ces'.current_view_suspectors); } es'.current_view_suspectors; } assert Eq_ElectionState(es', AbstractifyCElectionStateToElectionState(ces')); } else { es' := es; ces' := ces; } } reveal AbstractifyEndPointsToNodeIdentities(); } assert Eq_ElectionState(es', AbstractifyCElectionStateToElectionState(ces')); } method {:timeLimitMultiplier 3} ElectionCheckForViewTimeout(ces:CElectionState, clock:uint64, cur_req_set:MutableSet, prev_req_set:MutableSet) returns (ces':CElectionState) requires CElectionStateIsValid(ces) requires MutableSet.SetOf(cur_req_set) == ces.cur_req_set requires MutableSet.SetOf(prev_req_set) == ces.prev_req_set modifies cur_req_set, prev_req_set ensures CElectionStateIsValid(ces') ensures ElectionStateCheckForViewTimeout(AbstractifyCElectionStateToElectionState(ces), AbstractifyCElectionStateToElectionState(ces'), clock as int) ensures MutableSet.SetOf(cur_req_set) == ces'.cur_req_set ensures MutableSet.SetOf(prev_req_set) == ces'.prev_req_set { var start_time := Time.GetDebugTimeTicks(); ghost var es := AbstractifyCElectionStateToElectionState(ces); ghost var es':ElectionState; lemma_AbstractifySeqOfUint64sToSetOfInts_properties(ces.current_view_suspectors); if clock < ces.epoch_end_time { es' := es; ces' := ces; var end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("ElectionCheckForViewTimeout_nada", start_time, end_time); assert Eq_ElectionState(es', AbstractifyCElectionStateToElectionState(ces')); } else if |ces.requests_received_prev_epochs| == 0 { ghost var new_epoch_length := es.constants.all.params.baseline_view_timeout_period; es' := es.(epoch_length := new_epoch_length, epoch_end_time := UpperBoundedAddition(clock as int, new_epoch_length, es.constants.all.params.max_integer_val), requests_received_prev_epochs := es.requests_received_this_epoch, requests_received_this_epoch := []); var cnewEpochLength := ces.constants.all.params.baseline_view_timeout_period; var cnewEpochEndTime := UpperBoundedAdditionImpl(clock, cnewEpochLength, ces.constants.all.params.max_integer_val); ces' := ces.(epoch_length := cnewEpochLength, epoch_end_time := cnewEpochEndTime, requests_received_prev_epochs := ces.requests_received_this_epoch, requests_received_this_epoch := [], cur_req_set := {}, prev_req_set := ces.cur_req_set); prev_req_set.TransferSet(cur_req_set); assert Eq_ElectionState(es', AbstractifyCElectionStateToElectionState(ces')); var end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("ElectionCheckForViewTimeout_noprev", start_time, end_time); } else { es' := es.(current_view_suspectors := es.current_view_suspectors + {es.constants.my_index}, epoch_end_time := UpperBoundedAddition(clock as int, es.epoch_length, es.constants.all.params.max_integer_val), requests_received_prev_epochs := BoundRequestSequence(es.requests_received_prev_epochs + es.requests_received_this_epoch, es.constants.all.params.max_integer_val), requests_received_this_epoch := []); var cnewEpochEndTime := UpperBoundedAdditionImpl(clock, ces.epoch_length, ces.constants.all.params.max_integer_val); var new_seq := ces.requests_received_prev_epochs + ces.requests_received_this_epoch; ghost var new_set := ces.prev_req_set + ces.cur_req_set; prev_req_set.AddSet(cur_req_set); cur_req_set.RemoveAll(); assert HeadersMatch(new_seq, new_set); var tuple := BoundCRequestSequence(new_seq, ces.constants.all.params.max_integer_val); var bounded, bounded_seq := tuple.0, tuple.1; if bounded { // Should never happen new_set := BoundCRequestHeaders(new_seq, new_set, ces.constants.all.params.max_integer_val, prev_req_set); } ces' := ces.(current_view_suspectors := AppendToUniqueSeqMaybe(ces.current_view_suspectors, ces.constants.my_index), epoch_end_time := cnewEpochEndTime, requests_received_prev_epochs := bounded_seq, requests_received_this_epoch := [], cur_req_set := {}, prev_req_set := new_set); lemma_AbstractifyCRequestsSeqToRequestsSeq_concat(ces.requests_received_prev_epochs, ces.requests_received_this_epoch); lemma_BoundCRequestSequence(ces.requests_received_prev_epochs + ces.requests_received_this_epoch, ces.constants.all.params.max_integer_val); calc { AbstractifySeqOfUint64sToSetOfInts(AppendToUniqueSeqMaybe(ces.current_view_suspectors, ces.constants.my_index)); { lemma_AbstractifySeqOfUint64sToSetOfInts_append(ces.current_view_suspectors, ces.constants.my_index); } es.current_view_suspectors + {es.constants.my_index}; } assert Eq_ElectionState(es', AbstractifyCElectionStateToElectionState(ces')); var end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("ElectionCheckForViewTimeout_timeout", start_time, end_time); } assert Eq_ElectionState(es', AbstractifyCElectionStateToElectionState(ces')); } method {:timeLimitMultiplier 3} ElectionCheckForQuorumOfViewSuspicions(ces:CElectionState, clock:uint64, cur_req_set:MutableSet, prev_req_set:MutableSet) returns(ces':CElectionState) requires CElectionStateIsValid(ces) requires MutableSet.SetOf(cur_req_set) == ces.cur_req_set requires MutableSet.SetOf(prev_req_set) == ces.prev_req_set modifies cur_req_set, prev_req_set ensures CElectionStateIsValid(ces') ensures ElectionStateCheckForQuorumOfViewSuspicions(AbstractifyCElectionStateToElectionState(ces), AbstractifyCElectionStateToElectionState(ces'), clock as int) ensures MutableSet.SetOf(cur_req_set) == ces'.cur_req_set ensures MutableSet.SetOf(prev_req_set) == ces'.prev_req_set { reveal SeqIsUnique(); ghost var es := AbstractifyCElectionStateToElectionState(ces); ghost var es':ElectionState; lemma_AbstractifySeqOfUint64sToSetOfInts_properties(ces.current_view_suspectors); lemma_AbstractifyEndPointsToNodeIdentities_properties(ces.constants.all.config.replica_ids); var minq := MinCQuorumSize(ces.constants.all.config); if |ces.current_view_suspectors| < minq as int || ces.current_view.seqno >= ces.constants.all.params.max_integer_val { //|| |ces.constants.all.config.replica_ids| == 0 { es' := es; ces' := ces; } else { ghost var new_epoch_length := UpperBoundedAddition(es.epoch_length, es.epoch_length, es.constants.all.params.max_integer_val); es' := es.( current_view := ComputeSuccessorView(es.current_view, es.constants.all), current_view_suspectors := {}, epoch_length := new_epoch_length, epoch_end_time := UpperBoundedAddition(clock as int, new_epoch_length, es.constants.all.params.max_integer_val), requests_received_prev_epochs := BoundRequestSequence(es.requests_received_prev_epochs + es.requests_received_this_epoch, es.constants.all.params.max_integer_val), requests_received_this_epoch := []); var cview := CComputeSuccessorView(ces.current_view, ces.constants.all); var cnewEpochLength := UpperBoundedAdditionImpl(ces.epoch_length, ces.epoch_length, ces.constants.all.params.max_integer_val); var cnewEpochEndTime := UpperBoundedAdditionImpl(clock, cnewEpochLength, ces.constants.all.params.max_integer_val); var new_seq := ces.requests_received_prev_epochs + ces.requests_received_this_epoch; ghost var new_set := ces.prev_req_set + ces.cur_req_set; prev_req_set.AddSet(cur_req_set); cur_req_set.RemoveAll(); assert HeadersMatch(new_seq, new_set); var tuple := BoundCRequestSequence(new_seq, ces.constants.all.params.max_integer_val); var bounded, bounded_seq := tuple.0, tuple.1; if bounded { // Should never happen new_set := BoundCRequestHeaders(new_seq, new_set, ces.constants.all.params.max_integer_val, prev_req_set); } ces' := ces.( current_view := cview, current_view_suspectors := [], epoch_length := cnewEpochLength, epoch_end_time := cnewEpochEndTime, requests_received_prev_epochs := bounded_seq, requests_received_this_epoch := [], cur_req_set := {}, prev_req_set := new_set); lemma_AbstractifyCRequestsSeqToRequestsSeq_concat(ces.requests_received_prev_epochs, ces.requests_received_this_epoch); lemma_BoundCRequestSequence(ces.requests_received_prev_epochs + ces.requests_received_this_epoch, ces.constants.all.params.max_integer_val); } reveal AbstractifyEndPointsToNodeIdentities(); lemma_AbstractifySeqOfUint64sToSetOfInts_properties([]); assert Eq_ElectionState(es', AbstractifyCElectionStateToElectionState(ces')); } /* method FindEarlierRequest(r1:seq, r2:seq, target:CRequest) returns (b:bool) requires CRequestsSeqIsAbstractable(r1) requires CRequestsSeqIsAbstractable(r2) requires CRequestIsAbstractable(target) requires |r1| < 0x1_0000_0000_0000_0000 requires |r2| < 0x1_0000_0000_0000_0000 ensures b == exists earlier_req :: (earlier_req in r1 || earlier_req in r2) && CRequestsMatch(earlier_req, target) ensures b == exists earlier_req :: (earlier_req in AbstractifyCRequestsSeqToRequestsSeq(r1) || earlier_req in AbstractifyCRequestsSeqToRequestsSeq(r2)) && RequestsMatch(earlier_req, AbstractifyCRequestToRequest(target)) { lemma_CRequestsMatch(); var i:uint64 := 0; while i < |r1| as uint64 invariant 0 <= i as int <= |r1| invariant forall j :: 0 <= j < i ==> !CRequestsMatch(r1[j], target) { if CRequestsMatch(r1[i], target) { b := true; return; } i := i + 1; } i := 0; while i < |r2| as uint64 invariant 0 <= i as int <= |r2| invariant forall j :: 0 <= j < i ==> !CRequestsMatch(r2[j], target) { if CRequestsMatch(r2[i], target) { b := true; return; } i := i + 1; } b := false; } */ method FindEarlierRequestSets(ces:CElectionState, target:CRequest, cur_req_set:MutableSet, prev_req_set:MutableSet) returns (b:bool) requires CElectionStateIsValid(ces) requires CRequestIsAbstractable(target) requires MutableSet.SetOf(cur_req_set) == ces.cur_req_set requires MutableSet.SetOf(prev_req_set) == ces.prev_req_set ensures b == exists earlier_req :: (earlier_req in ces.requests_received_prev_epochs || earlier_req in ces.requests_received_this_epoch) && CRequestsMatch(earlier_req, target) ensures b == exists earlier_req :: (earlier_req in AbstractifyCRequestsSeqToRequestsSeq(ces.requests_received_prev_epochs) || earlier_req in AbstractifyCRequestsSeqToRequestsSeq(ces.requests_received_this_epoch)) && RequestsMatch(earlier_req, AbstractifyCRequestToRequest(target)) { var header := CRequestHeader(target.client, target.seqno); var b1 := cur_req_set.Contains(header); if b1 { b := true; } else { var b2 := prev_req_set.Contains(header); b := b2; } assert b == (header in ces.cur_req_set) || (header in ces.prev_req_set); lemma_CRequestsMatch(); if b { ghost var requests := ces.requests_received_prev_epochs + ces.requests_received_this_epoch; ghost var i := FindMatchingRequest(requests, ces.prev_req_set + ces.cur_req_set, header); // Lots of OBSERVE below to satisfy the existential in the ensures clause if i < |ces.requests_received_prev_epochs| { assert requests[i] == ces.requests_received_prev_epochs[i]; ghost var r_req := AbstractifyCRequestToRequest(ces.requests_received_prev_epochs[i]); assert r_req in AbstractifyCRequestsSeqToRequestsSeq(ces.requests_received_prev_epochs); assert RequestsMatch(r_req, AbstractifyCRequestToRequest(target)); } else { assert requests[i] == ces.requests_received_this_epoch[i - |ces.requests_received_prev_epochs|]; ghost var r_req := AbstractifyCRequestToRequest(ces.requests_received_this_epoch[i - |ces.requests_received_prev_epochs|]); assert r_req in AbstractifyCRequestsSeqToRequestsSeq(ces.requests_received_this_epoch); assert RequestsMatch(r_req, AbstractifyCRequestToRequest(target)); } } } lemma lemma_HeadersMatchAddition(requests:seq, headers:set, req:CRequest) requires HeadersMatch(requests, headers) requires !(exists earlier_req :: earlier_req in requests && CRequestsMatch(earlier_req, req)) ensures HeadersMatch(requests + [req], headers + { CRequestHeader(req.client, req.seqno) }) { var header := CRequestHeader(req.client, req.seqno); if header in headers { ghost var i := FindMatchingRequest(requests, headers, header); assert requests[i] in requests && CRequestsMatch(requests[i], req); } assert !(header in headers); } function ExtractHeader(req:CRequest) : CRequestHeader { CRequestHeader(req.client, req.seqno) } lemma lemma_AddNewReqPreservesHeaderMatches(s1:seq, headers1:set, s2:seq, headers2:set, s1':seq, headers1':set, s2':seq, headers2':set, r:CRequest) requires HeadersMatch(s1, headers1) requires HeadersMatch(s2, headers2) requires HeadersMatch(s1 + s2, headers1 + headers2) requires HeadersMatch(s1', headers1') requires HeadersMatch(s2', headers2') requires headers1' == headers1; requires s1' == s1 requires forall req :: req in s2' && !CRequestsMatch(req, r) ==> req in s2 requires forall h :: h in headers2' && h != CRequestHeader(r.client, r.seqno) ==> h in headers2 requires forall other_r :: other_r in s1 || other_r in s2 ==> !CRequestsMatch(other_r, r) ensures HeadersMatch(s1' + s2', headers1' + headers2') { var total_s := s1' + s2'; var total_h := headers1' + headers2'; forall i,j | 0 <= i < j < |total_s| && CRequestsMatch(total_s[i], total_s[j]) ensures i == j { if j < |s1'| { assert total_s[i] in s1 && total_s[j] in s1; assert i == j; } else if i >= |s1'| { assert total_s[i] in s2 && total_s[j] in s2; assert i == j; } else { assert i < |s1'| && j >= |s1'|; assert total_s[i] in s1 && total_s[j] in s2; var tot_s := s1 + s2; assert total_s[i] in tot_s && total_s[j] in tot_s; var i' :| 0 <= i' < |tot_s| && total_s[i] == tot_s[i']; var j' :| 0 <= j' < |tot_s| && total_s[j] == tot_s[j']; assert HeadersMatch(tot_s, headers1 + headers2); if (i' < j') { assert CRequestsMatch(tot_s[i'], tot_s[j']); } else if (i' > j') { assert CRequestsMatch(tot_s[j'], tot_s[i']); } assert i' == j'; assert total_s[i] == total_s[j]; if (total_s[j] in s1) { i' :| 0 <= i' < |s1| && total_s[j] == s1[i']; j' :| 0 <= j' < |s2| && total_s[j] == s2[j']; assert total_s[j] == tot_s[i']; assert total_s[j] == tot_s[|s1| + j']; } assert total_s[j] !in s1; assert i == j; } } var header_seq := []; var i := 0; while i < |total_s| invariant 0 <= i <= |total_s| invariant |header_seq| == i invariant forall j :: 0 <= j < i ==> header_seq[j] == ExtractHeader(total_s[j]) { header_seq := header_seq + [ExtractHeader(total_s[i])]; i := i + 1; } forall i', j' | 0 <= i' < |header_seq| && 0 <= j' < |header_seq| && header_seq[i'] == header_seq[j'] ensures i' == j' { assert header_seq[i'] == ExtractHeader(total_s[i']); assert header_seq[j'] == ExtractHeader(total_s[j']); if i' < j' { assert CRequestsMatch(total_s[i'], total_s[j']); // OBSERVE } else if j' < i' { assert CRequestsMatch(total_s[j'], total_s[i']); // OBSERVE } } forall ensures SeqIsUnique(header_seq) { reveal SeqIsUnique(); } //var headers := set r | r in total_s :: ExtractHeader(r); var header_set := UniqueSeqToSet(header_seq); lemma_seqs_set_cardinality(header_seq, header_set); forall h | h in header_set ensures h in total_h { } forall h | h in total_h ensures h in header_set { if h in headers1' { var j := FindMatchingRequest(s1', headers1', h); assert total_s[j] == s1'[j]; assert header_seq[j] == ExtractHeader(total_s[j]); assert header_seq[j] == h; assert header_seq[j] in header_seq; assert header_seq[j] in header_set; } else { assert h in headers2'; var j := FindMatchingRequest(s2', headers2', h); var j_offset := j + |s1'|; assert total_s[j_offset] == s2'[j]; assert header_seq[j_offset] == ExtractHeader(total_s[j_offset]); assert header_seq[j_offset] == h; assert header_seq[j_offset] in header_seq; assert header_seq[j_offset] in header_set; } } lemma_MapSetCardinalityOver(total_h, header_set, h => h); assert |total_h| == |header_set|; // OBSERVE } method {:timeLimitMultiplier 10} ElectionReflectReceivedRequest(ces:CElectionState, creq:CRequest, cur_req_set:MutableSet, prev_req_set:MutableSet) returns (ces':CElectionState) requires CElectionStateIsValid(ces) requires CRequestIsAbstractable(creq) requires ValidRequest(creq) requires prev_req_set != cur_req_set requires MutableSet.SetOf(cur_req_set) == ces.cur_req_set requires MutableSet.SetOf(prev_req_set) == ces.prev_req_set modifies cur_req_set ensures CElectionStateIsValid(ces') ensures ElectionStateReflectReceivedRequest(AbstractifyCElectionStateToElectionState(ces), AbstractifyCElectionStateToElectionState(ces'), AbstractifyCRequestToRequest(creq)) ensures MutableSet.SetOf(cur_req_set) == ces'.cur_req_set ensures MutableSet.SetOf(prev_req_set) == ces'.prev_req_set { ghost var req := AbstractifyCRequestToRequest(creq); ghost var es := AbstractifyCElectionStateToElectionState(ces); ghost var es':ElectionState; //var earlier_start_time := Time.GetDebugTimeTicks(); //var earlier:bool := FindEarlierRequest(ces.requests_received_this_epoch, ces.requests_received_prev_epochs, creq); var earlier:bool := FindEarlierRequestSets(ces, creq, cur_req_set, prev_req_set); //var earlier_end_time := Time.GetDebugTimeTicks(); //RecordTimingSeq("ElectionReflectReceivedRequest_FindEarlier", earlier_start_time, earlier_end_time); if earlier { es' := es; ces' := ces; } else { //var update_start_time := Time.GetDebugTimeTicks(); es' := es.(requests_received_this_epoch := BoundRequestSequence(es.requests_received_this_epoch + [req], es.constants.all.params.max_integer_val)); var new_seq := ces.requests_received_this_epoch + [creq]; var header := CRequestHeader(creq.client, creq.seqno); ghost var new_set := ces.cur_req_set + { header }; cur_req_set.Add(header); lemma_HeadersMatchAddition(ces.requests_received_this_epoch, ces.cur_req_set, creq); assert HeadersMatch(new_seq, new_set); var tuple := BoundCRequestSequence(new_seq, ces.constants.all.params.max_integer_val); var bounded, bounded_seq := tuple.0, tuple.1; if bounded { // Should never happen new_set := BoundCRequestHeaders(new_seq, new_set, ces.constants.all.params.max_integer_val, cur_req_set); } ces' := ces.(requests_received_this_epoch := bounded_seq, cur_req_set := new_set); lemma_AddNewReqPreservesHeaderMatches(ces.requests_received_prev_epochs, ces.prev_req_set, ces.requests_received_this_epoch, ces.cur_req_set, ces.requests_received_prev_epochs, ces.prev_req_set, bounded_seq, new_set, creq); lemma_AbstractifyCRequestsSeqToRequestsSeq_concat(ces.requests_received_this_epoch, [creq]); lemma_BoundCRequestSequence(bounded_seq, ces.constants.all.params.max_integer_val); assert {:split_here} true; assert Eq_ElectionState(es', AbstractifyCElectionStateToElectionState(ces')); } } lemma lemma_SequenceRemoveAllSatisfied(rseq:seq, batch:RequestBatch, i:int, rseq':seq, rseq'':seq) requires 0 <= i < |batch| requires rseq' == RemoveExecutedRequestBatch(rseq, batch[..i]) requires rseq'' == RemoveAllSatisfiedRequestsInSequence(rseq', batch[i]) ensures rseq'' == RemoveExecutedRequestBatch(rseq, batch[..i+1]) decreases i { if i > 0 { assert batch[1..][..i-1] == batch[1..i]; assert batch[1..][..i] == batch[1..i+1]; var rseqalt := RemoveAllSatisfiedRequestsInSequence(rseq, batch[0]); var rseqalt' := RemoveExecutedRequestBatch(rseqalt, batch[1..i]); var rseqalt'' := RemoveAllSatisfiedRequestsInSequence(rseqalt', batch[i]); lemma_SequenceRemoveAllSatisfied(rseqalt, batch[1..], i-1, rseqalt', rseqalt''); } } method {:timeLimitMultiplier 3} ElectionReflectExecutedRequestBatch(ces:CElectionState, creqb:CRequestBatch, cur_req_set:MutableSet, prev_req_set:MutableSet) returns (ces':CElectionState) requires CElectionStateIsValid(ces) requires CRequestBatchIsAbstractable(creqb) requires ValidRequestBatch(creqb) requires cur_req_set != prev_req_set requires MutableSet.SetOf(cur_req_set) == ces.cur_req_set requires MutableSet.SetOf(prev_req_set) == ces.prev_req_set modifies cur_req_set, prev_req_set ensures CElectionStateIsValid(ces') ensures ElectionStateReflectExecutedRequestBatch(AbstractifyCElectionStateToElectionState(ces), AbstractifyCElectionStateToElectionState(ces'), AbstractifyCRequestBatchToRequestBatch(creqb)) ensures MutableSet.SetOf(cur_req_set) == ces'.cur_req_set ensures MutableSet.SetOf(prev_req_set) == ces'.prev_req_set decreases |creqb| { ghost var es := AbstractifyCElectionStateToElectionState(ces); var i:uint64 := 0; assert AbstractifyCRequestBatchToRequestBatch(creqb[..i]) == []; var tempces' := ces; while i < |creqb| as uint64 invariant 0 <= i as int <= |creqb| invariant CElectionStateIsAbstractable(tempces') invariant CElectionStateIsValid(tempces') invariant ElectionStateReflectExecutedRequestBatch(es, AbstractifyCElectionStateToElectionState(tempces'), AbstractifyCRequestBatchToRequestBatch(creqb[..i])) invariant MutableSet.SetOf(cur_req_set) == tempces'.cur_req_set invariant MutableSet.SetOf(prev_req_set) == tempces'.prev_req_set { var creq := creqb[i]; ghost var req := AbstractifyCRequestToRequest(creq); ghost var es':ElectionState := AbstractifyCElectionStateToElectionState(tempces'); lemma_RemoveAllSatisfiedCRequestsInSequenceProperties(tempces'.requests_received_prev_epochs, creq); lemma_RemoveAllSatisfiedCRequestsInSequenceProperties(tempces'.requests_received_this_epoch, creq); assert ElectionStateReflectExecutedRequestBatch(es, AbstractifyCElectionStateToElectionState(tempces'), AbstractifyCRequestBatchToRequestBatch(creqb[..i])); ghost var es'' := es'.(requests_received_prev_epochs := RemoveAllSatisfiedRequestsInSequence(es'.requests_received_prev_epochs, req), requests_received_this_epoch := RemoveAllSatisfiedRequestsInSequence(es'.requests_received_this_epoch, req)); var prevEpoch; ghost var prevEpochSet; prevEpoch, prevEpochSet := RemoveAllSatisfiedCRequestsInSequenceIter(tempces'.requests_received_prev_epochs, tempces'.prev_req_set, prev_req_set, creq); var thisEpoch; ghost var thisEpochSet; thisEpoch, thisEpochSet := RemoveAllSatisfiedCRequestsInSequenceIter(tempces'.requests_received_this_epoch, tempces'.cur_req_set, cur_req_set, creq); lemma_RemoveAllSatisfiedPreservesHeaderMatches(tempces'.requests_received_prev_epochs, tempces'.prev_req_set, tempces'.requests_received_this_epoch, tempces'.cur_req_set, prevEpoch, prevEpochSet, thisEpoch, thisEpochSet, creq); tempces' := tempces'.(requests_received_prev_epochs := prevEpoch, requests_received_this_epoch := thisEpoch, cur_req_set := thisEpochSet, prev_req_set := prevEpochSet); assert {:split_here} true; assert AbstractifyCRequestBatchToRequestBatch(creqb[..i]) == AbstractifyCRequestBatchToRequestBatch(creqb)[..i]; assert AbstractifyCRequestBatchToRequestBatch(creqb[..i+1]) == AbstractifyCRequestBatchToRequestBatch(creqb)[..i+1]; lemma_SequenceRemoveAllSatisfied(es.requests_received_prev_epochs, AbstractifyCRequestBatchToRequestBatch(creqb), i as int, es'.requests_received_prev_epochs, es''.requests_received_prev_epochs); lemma_SequenceRemoveAllSatisfied(es.requests_received_this_epoch, AbstractifyCRequestBatchToRequestBatch(creqb), i as int, es'.requests_received_this_epoch, es''.requests_received_this_epoch); i := i + 1; } assert creqb[..i] == creqb; ces' := tempces'; } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/RSL/ElectionState.i.dfy ================================================ include "../../Protocol/RSL/Election.i.dfy" include "CTypes.i.dfy" include "ReplicaConstantsState.i.dfy" module LiveRSL__ElectionState_i { import opened Native__Io_s import opened Native__NativeTypes_s import opened LiveRSL__CPaxosConfiguration_i import opened LiveRSL__CTypes_i import opened LiveRSL__Election_i import opened LiveRSL__ReplicaConstantsState_i import opened Common__SeqIsUniqueDef_i import opened Common__NodeIdentity_i datatype CRequestHeader = CRequestHeader(client:EndPoint, seqno:uint64) datatype CElectionState = CElectionState( constants:ReplicaConstantsState, // The replica constants, duplicated here for convenience current_view:CBallot, // The last view I think has won a leader election current_view_suspectors:seq, // The set of nodes who suspect current_view. When this constitutes // a quorum, I'll elect the next view. epoch_end_time:uint64, // When the next view-test epoch will end. epoch_length:uint64, // How long the current view-test epoch length is. When we enter a new view, // we double this. requests_received_this_epoch:seq, // The set of requests we've received this epoch but haven't executed this epoch yet // and didn't execute in the previous epoch. ghost cur_req_set:set, // Duplicates the sequence above for faster lookups requests_received_prev_epochs:seq, // The set of requests we received in the previous epoch but haven't executed in // the current epoch, the previous epoch, or the epoch before that. ghost prev_req_set:set // Duplicates the sequence above for faster lookups ) predicate ElectionRequestQueueValid(queue:seq) { forall i :: 0 <= i < |queue| ==> ValidRequest(queue[i]) } predicate CElectionStateIsAbstractable(election:CElectionState) { && ReplicaConstantsStateIsAbstractable(election.constants) && CBallotIsAbstractable(election.current_view) && SeqIsUnique(election.current_view_suspectors) && CRequestsSeqIsAbstractable(election.requests_received_this_epoch) && CRequestsSeqIsAbstractable(election.requests_received_prev_epochs) } function AbstractifyCElectionStateToElectionState(election:CElectionState) : ElectionState requires CElectionStateIsAbstractable(election) { ElectionState(AbstractifyReplicaConstantsStateToLReplicaConstants(election.constants), AbstractifyCBallotToBallot(election.current_view), AbstractifySeqOfUint64sToSetOfInts(election.current_view_suspectors), election.epoch_end_time as int, election.epoch_length as int, AbstractifyCRequestsSeqToRequestsSeq(election.requests_received_this_epoch), AbstractifyCRequestsSeqToRequestsSeq(election.requests_received_prev_epochs)) } predicate method CRequestsMatch(r1:CRequest, r2:CRequest) { r1.client == r2.client && r1.seqno == r2.seqno } predicate method CRequestSatisfiedBy(r1:CRequest, r2:CRequest) { r1.client == r2.client && r1.seqno <= r2.seqno } predicate HeadersMatch(requests:seq, headers:set) { && |requests| == |headers| && (forall r :: r in requests ==> CRequestHeader(r.client, r.seqno) in headers) && (forall i,j {:trigger CRequestsMatch(requests[i], requests[j])} :: 0 <= i < j < |requests| && CRequestsMatch(requests[i], requests[j]) ==> i == j) } predicate CElectionStateIsValid(election:CElectionState) { && CElectionStateIsAbstractable(election) && ReplicaConstantsState_IsValid(election.constants) && ReplicaIndicesValid(election.current_view_suspectors, election.constants.all.config) && |election.requests_received_this_epoch| < 0x8000_0000_0000_0000 && |election.requests_received_prev_epochs| < 0x8000_0000_0000_0000 && ElectionRequestQueueValid(election.requests_received_this_epoch) && ElectionRequestQueueValid(election.requests_received_prev_epochs) && HeadersMatch(election.requests_received_this_epoch, election.cur_req_set) && HeadersMatch(election.requests_received_prev_epochs, election.prev_req_set) && HeadersMatch(election.requests_received_prev_epochs + election.requests_received_this_epoch, election.prev_req_set + election.cur_req_set) } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/RSL/ExecutorModel.i.dfy ================================================ include "AppInterface.i.dfy" include "ExecutorState.i.dfy" include "Broadcast.i.dfy" include "../Common/Util.i.dfy" include "../../Common/Native/IoLemmas.i.dfy" module LiveRSL__ExecutorModel_i { import opened Native__Io_s import opened Native__IoLemmas_i import opened Native__NativeTypes_s import opened LiveRSL__AppInterface_i import opened LiveRSL__CMessage_i import opened LiveRSL__CMessageRefinements_i import opened LiveRSL__CTypes_i import opened LiveRSL__CPaxosConfiguration_i import opened LiveRSL__Environment_i import opened LiveRSL__Executor_i import opened LiveRSL__ExecutorState_i import opened LiveRSL__Message_i import opened LiveRSL__PacketParsing_i import opened LiveRSL__ReplicaConstantsState_i import opened LiveRSL__StateMachine_i import opened LiveRSL__Types_i import opened Impl__LiveRSL__Broadcast_i import opened Common__NodeIdentity_i import opened Common__NetClient_i import opened Common__UpperBound_s import opened Common__UpperBound_i import opened Common__Util_i import opened Concrete_NodeIdentity_i import opened Collections__Maps_i import opened Logic__Option_i import opened Environment_s import opened AppStateMachine_s import opened Temporal__Temporal_s predicate ClientIndexMatches(req_idx:int, client:EndPoint, newReplyCache:CReplyCache, batch:CRequestBatch, replies:seq) requires |batch| == |replies| requires client in newReplyCache { 0 <= req_idx < |batch| && replies[req_idx].client == client && newReplyCache[client] == replies[req_idx] } predicate ReplyCacheUpdated(client:EndPoint, oldReplyCache:CReplyCache, newReplyCache:CReplyCache, batch:CRequestBatch, replies:seq) requires client in newReplyCache requires |batch| == |replies| { || (client in oldReplyCache && newReplyCache[client] == oldReplyCache[client]) || (exists req_idx :: ClientIndexMatches(req_idx, client, newReplyCache, batch, replies)) } lemma lemma_CReplyCacheUpdate(batch:CRequestBatch, reply_cache:CReplyCache, replies:seq, newReplyCache:CReplyCache) requires |batch| == |replies| requires ValidReplyCache(reply_cache) requires ValidReplyCache(newReplyCache) requires CReplyCacheIsAbstractable(reply_cache) requires CReplyCacheIsAbstractable(newReplyCache) requires CReplySeqIsAbstractable(replies); requires forall client :: client in newReplyCache ==> ReplyCacheUpdated(client, reply_cache, newReplyCache, batch, replies) ensures var r_newReplyCache := AbstractifyCReplyCacheToReplyCache(newReplyCache); var r_replyCache := AbstractifyCReplyCacheToReplyCache(reply_cache); forall client :: client in r_newReplyCache ==> (|| (client in r_replyCache && r_newReplyCache[client] == r_replyCache[client]) || ExistsReqIdx(|batch|, replies, reply_cache, newReplyCache, client)) { ghost var r_newReplyCache := AbstractifyCReplyCacheToReplyCache(newReplyCache); ghost var r_replyCache := AbstractifyCReplyCacheToReplyCache(reply_cache); forall r_client | r_client in r_newReplyCache ensures || (r_client in r_replyCache && r_newReplyCache[r_client] == r_replyCache[r_client]) || ExistsReqIdx(|batch|, replies, reply_cache, newReplyCache, r_client) { lemma_AbstractifyCReplyCacheToReplyCache_properties(reply_cache); lemma_AbstractifyCReplyCacheToReplyCache_properties(newReplyCache); assert exists e :: e in newReplyCache && r_client == AbstractifyEndPointToNodeIdentity(e); var client :| client in newReplyCache && AbstractifyEndPointToNodeIdentity(client) == r_client; assert EndPointIsValidPublicKey(client); if client in reply_cache && newReplyCache[client] == reply_cache[client] { lemma_AbstractifyEndPointToNodeIdentity_injective_forall(); assert r_client in r_replyCache; calc { r_newReplyCache[r_client]; AbstractifyCReplyToReply(newReplyCache[client]); AbstractifyCReplyToReply(reply_cache[client]); r_replyCache[r_client]; } } else { lemma_AbstractifyEndPointToNodeIdentity_injective_forall(); ghost var req_idx :| ClientIndexMatches(req_idx, client, newReplyCache, batch, replies); assert 0 <= req_idx < |batch| && AbstractifyCReplySeqToReplySeq(replies)[req_idx].client == r_client && r_newReplyCache[r_client] == AbstractifyCReplySeqToReplySeq(replies)[req_idx]; assert ExistsReqIdx(|batch|, replies, reply_cache, newReplyCache, r_client); } } } method {:timeLimitMultiplier 2} HandleRequestBatchImpl( state:AppStateMachine, batch:CRequestBatch, ghost reply_cache:CReplyCache, reply_cache_mutable:MutableMap ) returns ( replies_seq:seq, ghost newReplyCache:CReplyCache, ghost g_states:seq, ghost g_replies:seq ) requires ValidReplyCache(reply_cache) requires ValidRequestBatch(batch) requires CReplyCacheIsAbstractable(reply_cache) requires forall req :: req in batch ==> EndPointIsValidPublicKey(req.client) requires MutableMap.MapOf(reply_cache_mutable) == reply_cache modifies reply_cache_mutable modifies state ensures (g_states, g_replies) == HandleRequestBatch(old(state.Abstractify()), AbstractifyCRequestBatchToRequestBatch(batch)); ensures |replies_seq| == |batch| ensures forall i :: 0 <= i < |batch| ==> HelperPredicateHRBI(i, batch, replies_seq, g_states) ensures g_states[0] == old(state.Abstractify()) ensures g_states[|g_states|-1] == state.Abstractify() ensures CReplySeqIsAbstractable(replies_seq) ensures AbstractifyCReplySeqToReplySeq(replies_seq) == g_replies ensures ValidReplyCache(newReplyCache) ensures CReplyCacheIsAbstractable(newReplyCache) ensures forall client :: client in newReplyCache ==> ReplyCacheUpdated(client, reply_cache, newReplyCache, batch, replies_seq); ensures var r_newReplyCache := AbstractifyCReplyCacheToReplyCache(newReplyCache); var r_replyCache := AbstractifyCReplyCacheToReplyCache(reply_cache); forall client :: client in r_newReplyCache ==> (|| (client in r_replyCache && r_newReplyCache[client] == r_replyCache[client]) || ExistsReqIdx(|batch|, replies_seq, reply_cache, newReplyCache, client)) ensures newReplyCache == MutableMap.MapOf(reply_cache_mutable); ensures forall r :: r in replies_seq ==> ValidReply(r) && CReplyIsAbstractable(r) { ghost var g_state0 := state.Abstractify(); ghost var g_batch := AbstractifyCRequestBatchToRequestBatch(batch); ghost var tuple := HandleRequestBatch(g_state0, g_batch); g_states := tuple.0; g_replies := tuple.1; assert tuple == HandleRequestBatchHidden(g_state0, g_batch); lemma_HandleRequestBatchHidden(g_state0, g_batch, g_states, g_replies); var i:uint64 := 0; ghost var replies := []; var repliesArr := new CReply[|batch| as uint64]; newReplyCache := reply_cache; while i < |batch| as uint64 invariant 0 <= i as int <= |batch| invariant |replies| == i as int invariant forall j :: 0 <= j < i as int ==> HelperPredicateHRBI(j, batch, replies, g_states) invariant ValidReplyCache(newReplyCache) invariant CReplyCacheIsAbstractable(newReplyCache) invariant forall r :: r in replies ==> ValidReply(r) && CReplyIsAbstractable(r) invariant AbstractifyCReplySeqToReplySeq(replies) == g_replies[..i] invariant repliesArr[..i] == replies invariant g_states[0] == g_state0 invariant g_states[i] == state.Abstractify() invariant forall client {:trigger ReplyCacheUpdated(client, reply_cache, newReplyCache, batch[..i], replies)} :: client in newReplyCache ==> ReplyCacheUpdated(client, reply_cache, newReplyCache, batch[..i], replies) invariant MutableMap.MapOf(reply_cache_mutable) == newReplyCache { ghost var old_replies := replies; ghost var old_newReplyCache := newReplyCache; var old_state := state.Abstractify(); var reply := state.HandleRequest(batch[i].request); var newReply := CReply(batch[i].client, batch[i].seqno, reply); assert ValidReply(newReply); replies := replies + [newReply]; repliesArr[i] := newReply; newReplyCache := UpdateReplyCache(newReplyCache, reply_cache_mutable, batch[i].client, newReply, reply, i, batch, replies); i := i + 1; // Prove the invariant about HelperPredicateHRBI(j, batch, states, replies, g_states) forall j | 0 <= j < i as int ensures HelperPredicateHRBI(j, batch, replies, g_states) { if j < (i as int) - 1 { assert HelperPredicateHRBI(j, batch, old_replies, g_states); // From the loop invariant assert HelperPredicateHRBI(j, batch, replies, g_states); } } // Prove: AbstractifyCReplySeqToReplySeq(replies) == g_replies_prefix; ghost var g_replies_prefix := g_replies[..i]; forall k | 0 <= k < |replies| ensures AbstractifyCReplySeqToReplySeq(replies)[k] == g_replies_prefix[k] { if k < |replies| - 1 { assert AbstractifyCReplySeqToReplySeq(old_replies) == g_replies[..i-1]; } else { assert k == (i as int) - 1; ghost var reply' := AppHandleRequest(g_states[i-1], AbstractifyCAppRequestToAppRequest(batch[i-1].request)).1; calc { AbstractifyCReplySeqToReplySeq(replies)[k]; AbstractifyCReplyToReply(replies[k]); Reply(AbstractifyEndPointToNodeIdentity(batch[i-1].client), batch[i-1].seqno as int, reply'); Reply(g_batch[i-1].client, g_batch[i-1].seqno, AppHandleRequest(g_states[i-1], g_batch[i-1].request).1); { lemma_HandleBatchRequestProperties(g_state0, g_batch, g_states, g_replies, (i as int)-1); } g_replies_prefix[k]; } } } assert AbstractifyCReplySeqToReplySeq(replies) == g_replies_prefix; // Prove the invariant about cache updates forall client | client in newReplyCache ensures ReplyCacheUpdated(client, reply_cache, newReplyCache, batch[..i], replies) { assert ReplyCacheUpdated(client, old_newReplyCache, newReplyCache, batch[..i], replies); assert || (client in old_newReplyCache && newReplyCache[client] == old_newReplyCache[client]) || (exists req_idx :: ClientIndexMatches(req_idx, client, newReplyCache, batch[..i], replies)); if client in old_newReplyCache { assert ReplyCacheUpdated(client, reply_cache, old_newReplyCache, batch[..i-1], old_replies); // assert || (client in reply_cache && old_newReplyCache[client] == reply_cache[client]) // || (exists req_idx :: ClientIndexMatches(req_idx, client, old_newReplyCache, batch[..i-1], old_replies)); if client in reply_cache && old_newReplyCache[client] == reply_cache[client] { if client in old_newReplyCache && newReplyCache[client] == old_newReplyCache[client] { assert client in reply_cache && newReplyCache[client] == reply_cache[client]; assert ReplyCacheUpdated(client, reply_cache, newReplyCache, batch[..i], replies); } else { ghost var req_idx :| ClientIndexMatches(req_idx, client, newReplyCache, batch[..i], replies); assert ReplyCacheUpdated(client, reply_cache, newReplyCache, batch[..i], replies); } } else { ghost var req_idx :| ClientIndexMatches(req_idx, client, old_newReplyCache, batch[..i-1], old_replies); assert && 0 <= req_idx < |batch[..i-1]| && replies[req_idx].client == client && old_newReplyCache[client] == replies[req_idx]; if client in old_newReplyCache && newReplyCache[client] == old_newReplyCache[client] { assert ClientIndexMatches(req_idx, client, newReplyCache, batch[..i], replies); } else { ghost var req_idx' :| ClientIndexMatches(req_idx', client, newReplyCache, batch[..i], replies); } assert ReplyCacheUpdated(client, reply_cache, newReplyCache, batch[..i], replies); } } assert || (client in reply_cache && newReplyCache[client] == reply_cache[client]) || (exists req_idx :: ClientIndexMatches(req_idx, client, newReplyCache, batch[..i], replies)); } } replies_seq := repliesArr[..]; // Connect the while-loop invariant to the ensures forall client | client in newReplyCache ensures replies_seq == replies ensures ReplyCacheUpdated(client, reply_cache, newReplyCache, batch, replies) { assert ReplyCacheUpdated(client, reply_cache, newReplyCache, batch[..i], replies); assert i as int == |batch|; assert batch[..i] == batch; } assert replies_seq == replies; assert forall j :: 0 <= j < |batch| ==> j < |replies_seq| && HelperPredicateHRBI(j, batch, replies_seq, g_states); lemma_CReplyCacheUpdate(batch, reply_cache, replies, newReplyCache); } method {:timeLimitMultiplier 6} UpdateReplyCache(ghost reply_cache:CReplyCache, reply_cache_mutable:MutableMap, ep:EndPoint, newReply:CReply, reply:CAppReply, i:uint64, batch:CRequestBatch, ghost replies:seq) returns (ghost newReplyCache:CReplyCache) requires EndPointIsValidPublicKey(ep) requires ValidReply(newReply) requires CReplyIsAbstractable(newReply) requires 0 <= i as int < |batch| requires |replies| == |batch[..(i as int)+1]| requires replies[i] == newReply requires newReply.client == ep requires ValidReplyCache(reply_cache) requires CReplyCacheIsAbstractable(reply_cache) requires forall r :: r in replies ==> CReplyIsAbstractable(r) requires newReply == CReply(batch[i].client, batch[i].seqno, reply) requires MutableMap.MapOf(reply_cache_mutable) == reply_cache modifies reply_cache_mutable ensures ValidReplyCache(newReplyCache) ensures CReplyCacheIsAbstractable(newReplyCache) ensures forall client :: client in newReplyCache ==> ReplyCacheUpdated(client, reply_cache, newReplyCache, batch[..(i as int)+1], replies) ensures forall client :: client in newReplyCache ==> (|| (client in reply_cache && newReplyCache[client] == reply_cache[client]) || ExistsReqIdxConcrete((i as int)+1, replies, reply_cache, newReplyCache, client)) ensures var r_newReplyCache := AbstractifyCReplyCacheToReplyCache(newReplyCache); var r_replyCache := AbstractifyCReplyCacheToReplyCache(reply_cache); forall client :: client in r_newReplyCache ==> (|| (client in r_replyCache && r_newReplyCache[client] == r_replyCache[client]) || ExistsReqIdx((i as int)+1, replies, reply_cache, newReplyCache, client)) ensures newReplyCache == MutableMap.MapOf(reply_cache_mutable) { lemma_AbstractifyCReplyCacheToReplyCache_properties(reply_cache); ghost var slimReplyCache:CReplyCache; var staleEntry; var cache_size := reply_cache_mutable.SizeModest(); if cache_size == 255 as uint64 { // max_reply_cache_size() staleEntry :| staleEntry in MutableMap.MapOf(reply_cache_mutable); // TODO: Choose based on age // TODO: This is very inefficient. Optimize value selection. slimReplyCache := RemoveElt(reply_cache, staleEntry); reply_cache_mutable.Remove(staleEntry); } else { slimReplyCache := reply_cache; } lemma_AbstractifyCReplyCacheToReplyCache_properties(slimReplyCache); assert ValidReplyCache(slimReplyCache); forall e {:trigger EndPointIsValidPublicKey(e)} | e in slimReplyCache ensures EndPointIsValidPublicKey(e) && CReplyIsAbstractable(slimReplyCache[e]) { } newReplyCache := slimReplyCache[ep := newReply]; reply_cache_mutable.Set(ep, newReply); forall e {:trigger EndPointIsValidPublicKey(e)} | e in newReplyCache ensures EndPointIsValidPublicKey(e) && CReplyIsAbstractable(newReplyCache[e]) { if (e == ep) { } } // assert forall e {:trigger EndPointIsValidPublicKey(e)} :: e in newReplyCache ==> EndPointIsValidPublicKey(e) && CReplyIsAbstractable(newReplyCache[e]); assert CReplyCacheIsAbstractable(newReplyCache); lemma_AbstractifyCReplyCacheToReplyCache_properties(newReplyCache); assert ep in newReplyCache; assert EndPointIsValidPublicKey(ep); assert CReplyCacheIsAbstractable(newReplyCache); assert ValidReplyCache(newReplyCache); ghost var r_newReplyCache := AbstractifyCReplyCacheToReplyCache(newReplyCache); ghost var r_replyCache := AbstractifyCReplyCacheToReplyCache(reply_cache); forall client | client in r_newReplyCache ensures || (client in r_replyCache && r_newReplyCache[client] == r_replyCache[client]) || ExistsReqIdx((i as int)+1, replies, reply_cache, newReplyCache, client) ensures ReplyCacheUpdated(RefineNodeIdentityToEndPoint(client), reply_cache, newReplyCache, batch[..i+1], replies) { var e := RefineNodeIdentityToEndPoint(client); if e == ep { assert AbstractifyCReplySeqToReplySeq(replies)[i].client == AbstractifyCReplyToReply(replies[i]).client; assert AbstractifyCReplySeqToReplySeq(replies)[i].client == client && r_newReplyCache[client] == AbstractifyCReplySeqToReplySeq(replies)[i]; assert ExistsReqIdx((i as int)+1, replies, reply_cache, newReplyCache, client); assert ClientIndexMatches(i as int, e, newReplyCache, batch[..(i as int)+1], replies); assert ReplyCacheUpdated(RefineNodeIdentityToEndPoint(client), reply_cache, newReplyCache, batch[..(i as int)+1], replies); } else { assert e in reply_cache; if e == staleEntry && |reply_cache| == 0x1_0000_0000 - 1 { assert e !in slimReplyCache; assert e !in newReplyCache; assert AbstractifyEndPointToNodeIdentity(e) !in r_newReplyCache; assert false; } else { assert e in slimReplyCache; } assert e in slimReplyCache; assert newReplyCache[e] == reply_cache[e]; assert AbstractifyCReplyCacheToReplyCache(newReplyCache)[AbstractifyEndPointToNodeIdentity(e)] == AbstractifyCReplyToReply(newReplyCache[e]); assert AbstractifyCReplyCacheToReplyCache(reply_cache)[AbstractifyEndPointToNodeIdentity(e)] == AbstractifyCReplyToReply(reply_cache[e]); assert ReplyCacheUpdated(RefineNodeIdentityToEndPoint(client), reply_cache, newReplyCache, batch[..(i as int)+1], replies); } } forall client | client in newReplyCache ensures ReplyCacheUpdated(client, reply_cache, newReplyCache, batch[..i+1], replies) { assert EndPointIsValidPublicKey(client); // OBSERVE: Needed b/c someone put an oddly strict trigger on lemma_AbstractifyCReplyCacheToReplyCache_properties lemma_AbstractifyCReplyCacheToReplyCache_properties(newReplyCache); assert AbstractifyEndPointToNodeIdentity(client) in r_newReplyCache; lemma_AbstractifyEndPointToNodeIdentity_injective_forall(); assert client == RefineNodeIdentityToEndPoint(AbstractifyEndPointToNodeIdentity(client)); } } lemma lemma_HelperPredicateHRBI(j:int, batch:CRequestBatch, replies:seq, g_states:seq) requires 0 <= j < |batch| requires 0 <= j < |g_states|-1 requires 0 <= j < |replies| requires HelperPredicateHRBI(j, batch, replies, g_states) ensures replies[j].CReply? ensures (g_states[j+1], AbstractifyCAppReplyToAppReply(replies[j].reply)) == AppHandleRequest(g_states[j], AbstractifyCAppRequestToAppRequest(batch[j].request)) ensures replies[j].client == batch[j].client ensures replies[j].seqno == batch[j].seqno { } predicate HelperPredicateHRBI(j:int, batch:CRequestBatch, replies:seq, g_states:seq) requires 0 <= j < |batch| requires 0 <= j < |g_states|-1 requires 0 <= j < |replies| { && replies[j].CReply? && ((g_states[j+1], AbstractifyCAppReplyToAppReply(replies[j].reply)) == AppHandleRequest(g_states[j], AbstractifyCAppRequestToAppRequest(batch[j].request))) && replies[j].client == batch[j].client && replies[j].seqno == batch[j].seqno } // Same as x == y, but triggers extensional equality on fields and provides better error diagnostics predicate Eq_ExecutorState(x:LExecutor, y:LExecutor) { && x.constants == y.constants && x.app == y.app && x.ops_complete == y.ops_complete && x.next_op_to_execute == y.next_op_to_execute } method ExecutorInit(ccons:ReplicaConstantsState) returns(cs:ExecutorState, reply_cache_mutable:MutableMap) requires ReplicaConstantsState_IsValid(ccons) ensures ExecutorState_IsValid(cs) ensures LExecutorInit(AbstractifyExecutorStateToLExecutor(cs), AbstractifyReplicaConstantsStateToLReplicaConstants(ccons)) ensures cs.constants == ccons ensures fresh(reply_cache_mutable) ensures cs.reply_cache == MutableMap.MapOf(reply_cache_mutable) { ghost var c := AbstractifyReplicaConstantsStateToLReplicaConstants(ccons); ghost var s := LExecutor( c, AppInitialize(), 0, Ballot(0, 0), OutstandingOpUnknown(), map[]); var app_state := AppStateMachine.Initialize(); cs := ExecutorState( ccons, app_state, COperationNumber(0), CBallot(0, 0), COutstandingOpUnknown(), map[]); reply_cache_mutable := MutableMap.EmptyMap(); lemma_AbstractifyCReplyCacheToReplyCache_properties(cs.reply_cache); assert Eq_ExecutorState(s, AbstractifyExecutorStateToLExecutor(cs)); } method ExecutorGetDecision(cs:ExecutorState, cbal:CBallot, copn:COperationNumber, ca:CRequestBatch) returns(cs':ExecutorState) requires ExecutorState_IsValid(cs) requires ValidRequestBatch(ca) requires CBallotIsAbstractable(cbal) requires copn == cs.ops_complete requires cs.next_op_to_execute.COutstandingOpUnknown? ensures ExecutorState_IsValid(cs') ensures LExecutorGetDecision(AbstractifyExecutorStateToLExecutor(cs), AbstractifyExecutorStateToLExecutor(cs'), AbstractifyCBallotToBallot(cbal), AbstractifyCOperationNumberToOperationNumber(copn), AbstractifyCRequestBatchToRequestBatch(ca)) ensures cs.constants == cs'.constants ensures cs'.reply_cache == cs.reply_cache { ghost var s := AbstractifyExecutorStateToLExecutor(cs); ghost var v := AbstractifyCRequestBatchToRequestBatch(ca); ghost var opn := AbstractifyCOperationNumberToOperationNumber(copn); ghost var bal := AbstractifyCBallotToBallot(cbal); ghost var s' := s.(next_op_to_execute := OutstandingOpKnown(v, bal)); cs' := cs.(next_op_to_execute := COutstandingOpKnown(ca, cbal)); assert Eq_ExecutorState(s', AbstractifyExecutorStateToLExecutor(cs')); } predicate ExistsReqIdx(len:int, replies:seq, reply_cache:CReplyCache, newReplyCache:CReplyCache, client:NodeIdentity) requires CReplyCacheIsAbstractable(reply_cache) requires CReplyCacheIsAbstractable(newReplyCache) requires client in AbstractifyCReplyCacheToReplyCache(newReplyCache) requires |replies| == len requires (forall i :: i in replies ==> CReplyIsAbstractable(i)) { var r_newReplyCache := AbstractifyCReplyCacheToReplyCache(newReplyCache); var r_replyCache := AbstractifyCReplyCacheToReplyCache(reply_cache ); exists req_idx :: 0 <= req_idx < len && AbstractifyCReplySeqToReplySeq(replies)[req_idx].client == client && r_newReplyCache[client] == AbstractifyCReplySeqToReplySeq(replies)[req_idx] } predicate ExistsReqIdxConcrete(len:int, replies:seq, reply_cache:CReplyCache, newReplyCache:CReplyCache, client:EndPoint) requires client in newReplyCache requires |replies| == len requires (forall i :: i in replies ==> CReplyIsAbstractable(i)) { exists req_idx :: 0 <= req_idx < len && replies[req_idx].client == client && newReplyCache[client] == replies[req_idx] } /* lemma lemma_BatchEquivalence(cv:CRequestBatch, cstates:seq, creplies:seq, v:RequestBatch, states:seq, replies:seq) requires var temp := HandleRequestBatch(s.app, v) { } */ lemma lemma_ExistsReqIdx(len:int, replies:seq, reply_cache:CReplyCache, newReplyCache:CReplyCache, client:NodeIdentity) requires CReplyCacheIsAbstractable(reply_cache) requires CReplyCacheIsAbstractable(newReplyCache) requires client in AbstractifyCReplyCacheToReplyCache(newReplyCache) requires |replies| == len requires (forall i :: i in replies ==> CReplyIsAbstractable(i)) requires ExistsReqIdx(len, replies, reply_cache, newReplyCache, client) ensures exists req_idx :: 0 <= req_idx < len && AbstractifyCReplySeqToReplySeq(replies)[req_idx].client == client && AbstractifyCReplyCacheToReplyCache(newReplyCache)[client] == AbstractifyCReplySeqToReplySeq(replies)[req_idx] { } method GetPacketsFromRepliesImpl(me:EndPoint, requests:CRequestBatch, replies:seq) returns (cout_seq:seq) requires |requests| == |replies| < 0x1_0000_0000_0000_0000 requires forall r :: r in requests ==> ValidRequest(r) requires forall r :: r in replies ==> ValidReply(r) && CReplyIsAbstractable(r) requires EndPointIsValidPublicKey(me) ensures CPacketSeqIsAbstractable(cout_seq) ensures |cout_seq| == |replies| ensures forall p :: p in cout_seq ==> p.src == me && p.msg.CMessage_Reply? && CPacketIsSendable(p) ensures AbstractifySeqOfCPacketsToSeqOfRslPackets(cout_seq) == GetPacketsFromReplies(AbstractifyEndPointToNodeIdentity(me), AbstractifyCRequestsSeqToRequestsSeq(requests), AbstractifyCReplySeqToReplySeq(replies)) { var i:uint64 := 0; ghost var cout := []; var coutArr := new CPacket[|replies| as uint64]; while i < |replies| as uint64 invariant 0 <= i as int <= |replies| invariant |cout| == i as int invariant coutArr[..i] == cout invariant CPacketSeqIsAbstractable(cout) invariant forall p :: p in cout ==> p.src == me && p.msg.CMessage_Reply? && CPacketIsSendable(p) invariant forall j :: 0 <= j < i ==> cout[j] == CPacket(requests[j].client, me, CMessage_Reply(requests[j].seqno, replies[j].reply)) { assert ValidRequest(requests[i]) && ValidReply(replies[i]); var cmsg := CMessage_Reply(requests[i].seqno, replies[i].reply); if PrintParams.ShouldPrintProgress() { print("Sending reply to client "); print(requests[i].client); print(" with sequence number "); print(requests[i].seqno); print("\n"); } var cp := CPacket(requests[i].client, me, cmsg); cout := cout + [cp]; coutArr[i] := cp; i := i + 1; } // Prove the final ensures clause ghost var r_cout := AbstractifySeqOfCPacketsToSeqOfRslPackets(cout); ghost var r_me := AbstractifyEndPointToNodeIdentity(me); ghost var r_requests := AbstractifyCRequestsSeqToRequestsSeq(requests); ghost var r_replies := AbstractifyCReplySeqToReplySeq(replies); ghost var r_cout' := GetPacketsFromReplies(r_me, r_requests, r_replies); calc { |r_cout|; |cout|; |replies|; |AbstractifyCReplySeqToReplySeq(replies)|; { lemma_SizeOfGetPacketsFromReplies(r_me, r_requests, r_replies, r_cout'); } |r_cout'|; } forall j | 0 <= j < |r_cout| ensures r_cout[j] == r_cout'[j] { calc { r_cout[j]; AbstractifyCPacketToRslPacket(cout[j]); AbstractifyCPacketToRslPacket(CPacket(requests[j].client, me, CMessage_Reply(requests[j].seqno, replies[j].reply))); LPacket(r_requests[j].client, r_me, RslMessage_Reply(r_requests[j].seqno, r_replies[j].reply)); { lemma_SpecificPacketInGetPacketsFromReplies(r_me, r_requests, r_replies, r_cout', j); } r_cout'[j]; } } cout_seq := coutArr[..]; } lemma lemma_OutboundPackets(cout:OutboundPackets, me:EndPoint) requires cout.PacketSequence? requires forall p :: p in cout.s ==> CPacketIsSendable(p) && p.src == me requires CPacketSeqIsAbstractable(cout.s) requires |cout.s| < 0xFFFF_FFFF_FFFF_FFFF ensures OutboundPacketsIsValid(cout) ensures OutboundPacketsHasCorrectSrc(cout, me) ensures OutboundPacketsIsAbstractable(cout) ensures AbstractifyOutboundCPacketsToSeqOfRslPackets(cout) == AbstractifySeqOfCPacketsToSeqOfRslPackets(cout.s) { } method {:timeLimitMultiplier 4} ExecutorExecute(cs:ExecutorState, reply_cache_mutable:MutableMap) returns(cs':ExecutorState, cout:OutboundPackets) requires ExecutorState_IsValid(cs) requires cs.ops_complete.n < cs.constants.all.params.max_integer_val requires cs.next_op_to_execute.COutstandingOpKnown? requires MutableMap.MapOf(reply_cache_mutable) == cs.reply_cache modifies cs.app modifies reply_cache_mutable ensures ExecutorState_IsValid(cs') ensures OutboundPacketsIsValid(cout) ensures OutboundPacketsHasCorrectSrc(cout, cs.constants.all.config.replica_ids[cs.constants.my_index]) ensures OutboundPacketsIsAbstractable(cout) ensures LtUpperBound(AbstractifyExecutorStateToLExecutor(cs).ops_complete, AbstractifyExecutorStateToLExecutor(cs).constants.all.params.max_integer_val) ensures LExecutorExecute(old(AbstractifyExecutorStateToLExecutor(cs)), AbstractifyExecutorStateToLExecutor(cs'), AbstractifyOutboundCPacketsToSeqOfRslPackets(cout)) ensures cs.constants == cs'.constants ensures cs'.reply_cache == MutableMap.MapOf(reply_cache_mutable) { var cv := cs.next_op_to_execute.v; //var start_time := Time.GetDebugTimeTicks(); ghost var s := AbstractifyExecutorStateToLExecutor(cs); ghost var v := AbstractifyCRequestBatchToRequestBatch(cv); assert AbstractifyCRequestBatchToRequestBatch(cv) == AbstractifyExecutorStateToLExecutor(cs).next_op_to_execute.v; assert AbstractifyCAppStateToAppState(cs.app.Abstractify()) == AbstractifyExecutorStateToLExecutor(cs).app; ghost var g_tuple := HandleRequestBatch(s.app, v); lemma_AbstractifyCReplyCacheToReplyCache_properties(cs.reply_cache); var creplies; ghost var states, replies, newReplyCache; var start_time_request_batch := Time.GetDebugTimeTicks(); creplies, newReplyCache, states, replies := HandleRequestBatchImpl(cs.app, cv, cs.reply_cache, reply_cache_mutable); var end_time_request_batch := Time.GetDebugTimeTicks(); RecordTimingSeq("ExecutorExecute_HandleRequestBatch", start_time_request_batch, end_time_request_batch); assert replies == AbstractifyCReplySeqToReplySeq(creplies); ghost var new_state := states[|states|-1]; assert forall i :: 0 <= i < |cv| ==> AbstractifyCRequestToRequest(cv[i]) == v[i]; //var end_time_app := Time.GetDebugTimeTicks(); lemma_AbstractifyCReplyCacheToReplyCache_properties(newReplyCache); assert forall client :: client in newReplyCache ==> (|| (client in cs.reply_cache && newReplyCache[client] == cs.reply_cache[client]) || (exists req_idx :: 0 <= req_idx < |cv| && creplies[req_idx].client == client && newReplyCache[client] == creplies[req_idx])); var newMaxBalReflected := (if CBallotIsNotGreaterThan(cs.max_bal_reflected, cs.next_op_to_execute.bal) then cs.next_op_to_execute.bal else cs.max_bal_reflected); cs' := cs.(ops_complete := COperationNumber(cs.ops_complete.n + 1), max_bal_reflected := newMaxBalReflected, next_op_to_execute := COutstandingOpUnknown(), reply_cache := newReplyCache); assert cs'.ops_complete.COperationNumber?; assert COperationNumberIsAbstractable(cs'.ops_complete); ghost var s' := AbstractifyExecutorStateToLExecutor(cs'); assert s'.reply_cache == AbstractifyCReplyCacheToReplyCache(newReplyCache); assert AbstractifyExecutorStateToLExecutor(cs).reply_cache == AbstractifyCReplyCacheToReplyCache(cs.reply_cache); assert s.reply_cache == AbstractifyCReplyCacheToReplyCache(cs.reply_cache); var i := |cv|-1; if |cv| > 0 { assert 0 <= i < |cv|; } else { assert nextstep(i) == 0; } calc { nextstep(i); |cv|-1+1; |cv|; |states|-1; } assert AbstractifyExecutorStateToLExecutor(cs').app == new_state; var cme := cs.constants.all.config.replica_ids[cs.constants.my_index]; assert forall r :: r in creplies ==> ValidReply(r) && CReplyIsAbstractable(r); assert cme == cs.constants.all.config.replica_ids[cs.constants.my_index]; lemma_InSequence(cs.constants.all.config.replica_ids, cme, cs.constants.my_index); assert cme in cs.constants.all.config.replica_ids; assert ReplicaConstantsState_IsValid(cs.constants); assert CPaxosConfigurationIsValid(cs.constants.all.config); assert forall r :: r in cs.constants.all.config.replica_ids ==> EndPointIsValidPublicKey(r); assert EndPointIsValidPublicKey(cme); var start_time_get_packets := Time.GetDebugTimeTicks(); var packets := GetPacketsFromRepliesImpl(cme, cv, creplies); cout := PacketSequence(packets); var end_time_get_packets := Time.GetDebugTimeTicks(); RecordTimingSeq("ExecutorExecute_GetPackets", start_time_get_packets, end_time_get_packets); assert forall p :: p in packets ==> CPacketIsSendable(p); assert cout.PacketSequence?; assert forall p :: p in cout.s ==> CPacketIsSendable(p); lemma_OutboundPackets(cout, cme); assert OutboundPacketsIsValid(cout); assert OutboundPacketsHasCorrectSrc(cout, cme); ghost var out := AbstractifyOutboundCPacketsToSeqOfRslPackets(cout); ghost var refinedSeq := AbstractifySeqOfCPacketsToSeqOfRslPackets(cout.s); assert out == refinedSeq; assert refinedSeq == GetPacketsFromReplies(AbstractifyEndPointToNodeIdentity(cme), AbstractifyCRequestsSeqToRequestsSeq(cv), AbstractifyCReplySeqToReplySeq(creplies)); lemma_BatchAndRequestSeqEquivalence(cv); assert AbstractifyCRequestsSeqToRequestsSeq(cv) == AbstractifyCRequestBatchToRequestBatch(cv); assert refinedSeq == GetPacketsFromReplies(AbstractifyEndPointToNodeIdentity(cme), AbstractifyCRequestBatchToRequestBatch(cv), AbstractifyCReplySeqToReplySeq(creplies)); assert AbstractifyEndPointToNodeIdentity(cme) == s.constants.all.config.replica_ids[s.constants.my_index]; assert AbstractifyCRequestBatchToRequestBatch(cv) == AbstractifyExecutorStateToLExecutor(cs).next_op_to_execute.v; assert s.next_op_to_execute.v == AbstractifyCRequestBatchToRequestBatch(cv); assert replies == HandleRequestBatch(s.app, s.next_op_to_execute.v).1; assert replies == AbstractifyCReplySeqToReplySeq(creplies); assert refinedSeq == GetPacketsFromReplies(s.constants.all.config.replica_ids[s.constants.my_index], s.next_op_to_execute.v, replies); calc { out; refinedSeq; GetPacketsFromReplies(s.constants.all.config.replica_ids[s.constants.my_index], s.next_op_to_execute.v, replies); } assert out == GetPacketsFromReplies(s.constants.all.config.replica_ids[s.constants.my_index], s.next_op_to_execute.v, replies); assert AbstractifyExecutorStateToLExecutor(cs').ops_complete == AbstractifyExecutorStateToLExecutor(cs).ops_complete + 1; } lemma lemma_BatchAndRequestSeqEquivalence(s:seq) requires CRequestsSeqIsAbstractable(s) ensures AbstractifyCRequestsSeqToRequestsSeq(s) == AbstractifyCRequestBatchToRequestBatch(s) { reveal AbstractifyCRequestBatchToRequestBatch(); } lemma lemma_InSequence(s:seq, p:T, i:uint64) requires 0 <= i as int < |s| requires s[i] == p ensures p in s { } method ExecutorProcessAppStateSupply(cs:ExecutorState, cinp:CPacket) returns(cs':ExecutorState) requires ExecutorState_IsValid(cs) requires CPacketIsAbstractable(cinp) requires cinp.msg.CMessage_AppStateSupply? requires CAppStateMarshallable(cinp.msg.app_state) requires cinp.src in cs.constants.all.config.replica_ids requires cinp.msg.opn_state_supply.n > cs.ops_complete.n ensures ExecutorState_IsValid(cs') ensures AbstractifyCPacketToRslPacket(cinp).msg.RslMessage_AppStateSupply? ensures AbstractifyCPacketToRslPacket(cinp).src in AbstractifyExecutorStateToLExecutor(cs).constants.all.config.replica_ids ensures AbstractifyCPacketToRslPacket(cinp).msg.opn_state_supply > AbstractifyExecutorStateToLExecutor(cs).ops_complete ensures LExecutorProcessAppStateSupply(AbstractifyExecutorStateToLExecutor(cs), AbstractifyExecutorStateToLExecutor(cs'), AbstractifyCPacketToRslPacket(cinp)) ensures cs.constants == cs'.constants ensures cs'.reply_cache == cs.reply_cache { ghost var s := AbstractifyExecutorStateToLExecutor(cs); ghost var inp := AbstractifyCPacketToRslPacket(cinp); ghost var m := inp.msg; ghost var s' := s.( app := m.app_state, ops_complete := m.opn_state_supply, max_bal_reflected := m.bal_state_supply, next_op_to_execute := OutstandingOpUnknown()); var cm := cinp.msg; var app_state := AppStateMachine.Deserialize(cm.app_state); cs' := cs.( app := app_state, ops_complete := cm.opn_state_supply, max_bal_reflected := cm.bal_state_supply, next_op_to_execute := COutstandingOpUnknown()); assert Eq_ExecutorState(s', AbstractifyExecutorStateToLExecutor(cs')); } method ExecutorProcessAppStateRequest(cs:ExecutorState, cinp:CPacket, reply_cache_mutable:MutableMap) returns(cs':ExecutorState, cout:OutboundPackets) requires ExecutorState_IsValid(cs) requires CPacketIsAbstractable(cinp) requires cinp.msg.CMessage_AppStateRequest? requires MutableMap.MapOf(reply_cache_mutable) == cs.reply_cache ensures ExecutorState_IsValid(cs') ensures OutboundPacketsIsValid(cout) ensures AbstractifyCPacketToRslPacket(cinp).msg.RslMessage_AppStateRequest? ensures OutboundPacketsHasCorrectSrc(cout, cs.constants.all.config.replica_ids[cs.constants.my_index]) ensures OutboundPacketsIsAbstractable(cout) ensures LExecutorProcessAppStateRequest(AbstractifyExecutorStateToLExecutor(cs), AbstractifyExecutorStateToLExecutor(cs'), AbstractifyCPacketToRslPacket(cinp), AbstractifyOutboundCPacketsToSeqOfRslPackets(cout)) ensures cs == cs' { ghost var s := AbstractifyExecutorStateToLExecutor(cs); ghost var inp := AbstractifyCPacketToRslPacket(cinp); ghost var m := inp.msg; ghost var s' := s; ghost var out:seq; cs' := cs; reveal AbstractifySetOfCPacketsToSetOfRslPackets(); lemma_AbstractifyEndPointsToNodeIdentities_properties(cs.constants.all.config.replica_ids); if cinp.src in cs.constants.all.config.replica_ids && CBallotIsNotGreaterThan(cs.max_bal_reflected, cinp.msg.bal_state_req) && cs.ops_complete.n >= cinp.msg.opn_state_req.n { ghost var me := s.constants.all.config.replica_ids[s.constants.my_index]; var cme := cs.constants.all.config.replica_ids[cs.constants.my_index]; var reply_cache := MutableMap.MapOf(reply_cache_mutable); var app_state := cs.app.Serialize(); out := [ LPacket(inp.src, me, RslMessage_AppStateSupply(s.max_bal_reflected, s.ops_complete, s.app)) ]; cout := OutboundPacket(Some(CPacket(cinp.src, cme, CMessage_AppStateSupply(cs.max_bal_reflected, cs.ops_complete, app_state)))); } else { out := []; cout := OutboundPacket(None()); } assert AbstractifyOutboundCPacketsToSeqOfRslPackets(cout) == out; } method ExecutorProcessStartingPhase2(cs:ExecutorState, cinp:CPacket) returns(cs':ExecutorState, cout:CBroadcast) requires ExecutorState_IsValid(cs) requires CPacketIsAbstractable(cinp) requires cinp.msg.CMessage_StartingPhase2? ensures ExecutorState_IsValid(cs') ensures CBroadcastIsValid(cout) ensures OutboundPacketsHasCorrectSrc(Broadcast(cout), cs.constants.all.config.replica_ids[cs.constants.my_index]) ensures AbstractifyCPacketToRslPacket(cinp).msg.RslMessage_StartingPhase2? ensures LExecutorProcessStartingPhase2(AbstractifyExecutorStateToLExecutor(cs), AbstractifyExecutorStateToLExecutor(cs'), AbstractifyCPacketToRslPacket(cinp), AbstractifyCBroadcastToRlsPacketSeq(cout)) ensures cs == cs' ensures OutboundPacketsHasCorrectSrc(Broadcast(cout), cs'.constants.all.config.replica_ids[cs'.constants.my_index]) { var start_time := Time.GetDebugTimeTicks(); ghost var s := AbstractifyExecutorStateToLExecutor(cs); ghost var inp := AbstractifyCPacketToRslPacket(cinp); ghost var opn := inp.msg.logTruncationPoint_2; ghost var s' := s; ghost var out:seq; var copn := cinp.msg.logTruncationPoint_2; cs' := cs; reveal AbstractifySetOfCPacketsToSetOfRslPackets(); lemma_AbstractifyEndPointsToNodeIdentities_properties(cs.constants.all.config.replica_ids); if cinp.src in cs.constants.all.config.replica_ids && copn.n > cs.ops_complete.n { ghost var msg := RslMessage_AppStateRequest(inp.msg.bal_2, opn); var cmsg := CMessage_AppStateRequest(cinp.msg.bal_2, copn); out := BuildLBroadcast(s.constants.all.config.replica_ids[s.constants.my_index], s.constants.all.config.replica_ids, msg); cout := BuildBroadcastToEveryone(cs.constants.all.config, cs.constants.my_index, cmsg); var end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("ExecutorProcessStartingPhase2_request", start_time, end_time); } else { out := []; cout := CBroadcastNop; var end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("ExecutorProcessStartingPhase2_nada", start_time, end_time); } } method ExecutorProcessRequest(cs:ExecutorState, cinp:CPacket, cachedReply:CReply, reply_cache_mutable:MutableMap) returns(cout:OutboundPackets) requires ExecutorState_IsValid(cs) requires CPacketIsAbstractable(cinp) requires cinp.msg.CMessage_Request? requires cinp.src in cs.reply_cache requires cachedReply == cs.reply_cache[cinp.src] requires cachedReply.CReply? requires cinp.msg.seqno <= cachedReply.seqno requires MutableMap.MapOf(reply_cache_mutable) == cs.reply_cache ensures OutboundPacketsIsValid(cout) ensures OutboundPacketsHasCorrectSrc(cout, cs.constants.all.config.replica_ids[cs.constants.my_index]) ensures OutboundPacketsIsAbstractable(cout) ensures AbstractifyCPacketToRslPacket(cinp).msg.RslMessage_Request? ensures AbstractifyCPacketToRslPacket(cinp).src in AbstractifyExecutorStateToLExecutor(cs).reply_cache ensures AbstractifyExecutorStateToLExecutor(cs).reply_cache[AbstractifyCPacketToRslPacket(cinp).src].Reply? ensures AbstractifyCPacketToRslPacket(cinp).msg.seqno_req <= AbstractifyExecutorStateToLExecutor(cs).reply_cache[AbstractifyCPacketToRslPacket(cinp).src].seqno ensures LExecutorProcessRequest(AbstractifyExecutorStateToLExecutor(cs), AbstractifyCPacketToRslPacket(cinp), AbstractifyOutboundCPacketsToSeqOfRslPackets(cout)) ensures OutboundPacketsHasCorrectSrc(cout, cs.constants.all.config.replica_ids[cs.constants.my_index]) { //ghost var s := AbstractifyExecutorStateToLExecutor(cs); ghost var inp := AbstractifyCPacketToRslPacket(cinp); lemma_AbstractifyCReplyCacheToReplyCache_properties(cs.reply_cache); ghost var out:seq; // the assert below is the trigger needed since we added an explicit trigger in the corresponding ensures in lemma_AbstractifyCReplyCacheToReplyCache_properties assert AbstractifyCReplyCacheToReplyCache(cs.reply_cache)[AbstractifyEndPointToNodeIdentity(cinp.src)] == AbstractifyCReplyToReply(cs.reply_cache[cinp.src]); assert cinp.msg.seqno <= cachedReply.seqno; var cr := cachedReply; var msg := CMessage_Reply(cr.seqno, cr.reply); if PrintParams.ShouldPrintProgress() { print("Sending cached reply to client "); print(cr.client); print(" with sequence number "); print(cr.seqno); print("\n"); } cout := OutboundPacket(Some(CPacket(cr.client, cs.constants.all.config.replica_ids[cs.constants.my_index], msg))); assert cinp.src in cs.reply_cache; assert ValidReply(cs.reply_cache[cinp.src]); assert CAppReplyMarshallable(cr.reply); assert OutboundPacketsIsValid(cout); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/RSL/ExecutorState.i.dfy ================================================ include "../../Protocol/RSL/Executor.i.dfy" include "PacketParsing.i.dfy" include "ReplicaConstantsState.i.dfy" module LiveRSL__ExecutorState_i { import opened Native__NativeTypes_s import opened LiveRSL__CTypes_i import opened LiveRSL__Executor_i import opened LiveRSL__PacketParsing_i import opened LiveRSL__ReplicaConstantsState_i import opened AppStateMachine_s /////////////////////////// // COutstandingOperation /////////////////////////// datatype COutstandingOperation = COutstandingOpKnown(v:CRequestBatch,bal:CBallot) | COutstandingOpUnknown() predicate COutstandingOperationIsAbstractable(op:COutstandingOperation) { || op.COutstandingOpUnknown? || (CRequestBatchIsAbstractable(op.v) && CBallotIsAbstractable(op.bal)) } function AbstractifyCOutstandingOperationToOutstandingOperation(op:COutstandingOperation):OutstandingOperation requires COutstandingOperationIsAbstractable(op) { match op case COutstandingOpKnown(v,bal) => OutstandingOpKnown(AbstractifyCRequestBatchToRequestBatch(v),AbstractifyCBallotToBallot(bal)) case COutstandingOpUnknown => OutstandingOpUnknown() } /////////////////////////// // ExecutorState /////////////////////////// datatype ExecutorState = ExecutorState( constants:ReplicaConstantsState, app:AppStateMachine, ops_complete:COperationNumber, max_bal_reflected:CBallot, next_op_to_execute:COutstandingOperation, ghost reply_cache:CReplyCache) predicate ExecutorState_IsAbstractable(executor:ExecutorState) { && ReplicaConstantsStateIsAbstractable(executor.constants) && COperationNumberIsAbstractable(executor.ops_complete) && CBallotIsAbstractable(executor.max_bal_reflected) && COutstandingOperationIsAbstractable(executor.next_op_to_execute) && CReplyCacheIsAbstractable(executor.reply_cache) } function AbstractifyExecutorStateToLExecutor(executor:ExecutorState) : LExecutor reads executor.app requires ExecutorState_IsAbstractable(executor) { LExecutor( AbstractifyReplicaConstantsStateToLReplicaConstants(executor.constants), executor.app.Abstractify(), AbstractifyCOperationNumberToOperationNumber(executor.ops_complete), AbstractifyCBallotToBallot(executor.max_bal_reflected), AbstractifyCOutstandingOperationToOutstandingOperation(executor.next_op_to_execute), AbstractifyCReplyCacheToReplyCache(executor.reply_cache)) } predicate ExecutorState_IsValid(executor:ExecutorState) { && ExecutorState_IsAbstractable(executor) && ReplicaConstantsState_IsValid(executor.constants) && ValidReplyCache(executor.reply_cache) && (executor.next_op_to_execute.COutstandingOpKnown? ==> ValidRequestBatch(executor.next_op_to_execute.v)) } predicate ExecutorState_CommonPreconditions(executor:ExecutorState) { && ExecutorState_IsValid(executor) && ExecutorState_IsAbstractable(executor) // Can I have this too? } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/RSL/Host.i.dfy ================================================ include "../../Common/Framework/Host.s.dfy" include "ReplicaImplMain.i.dfy" include "CmdLineParser.i.dfy" include "Unsendable.i.dfy" module Host_i refines Host_s { import opened LiveRSL__Configuration_i import opened LiveRSL__ConstantsState_i import opened LiveRSL__CPaxosConfiguration_i import opened LiveRSL__Environment_i import opened LiveRSL__ParametersState_i import opened LiveRSL__QRelations_i import opened LiveRSL__Replica_i import opened LiveRSL__ReplicaConstantsState_i import opened LiveRSL__ReplicaImplClass_i import opened LiveRSL__ReplicaImplMain_i import opened LiveRSL__NetRSL_i import opened LiveRSL__Unsendable_i import opened CmdLineParser_i import opened PaxosCmdLineParser_i import opened Collections__Sets_i import opened Common__NodeIdentity_i import opened Common__SeqIsUnique_i import opened Common__SeqIsUniqueDef_i datatype CScheduler = CScheduler(ghost sched:LScheduler, replica_impl:ReplicaImpl) type HostState = CScheduler type ConcreteConfiguration = ConstantsState predicate ConcreteConfigInit(config:ConcreteConfiguration) { ConstantsStateIsValid(config) } function ConcreteConfigToServers(config:ConcreteConfiguration) : set { MapSeqToSet(config.config.replica_ids, x=>x) } predicate HostStateInvariants(host_state:HostState, env:HostEnvironment) { && host_state.replica_impl.Valid() && host_state.replica_impl.Env() == env && host_state.sched == host_state.replica_impl.AbstractifyToLScheduler() } predicate HostInit(host_state:HostState, config:ConcreteConfiguration, id:EndPoint) { && host_state.replica_impl.Valid() && host_state.replica_impl.replica.constants.all == config && config.config.replica_ids[host_state.replica_impl.replica.constants.my_index] == id && LSchedulerInit(host_state.sched, AbstractifyReplicaConstantsStateToLReplicaConstants(host_state.replica_impl.replica.constants)) } predicate HostNext(host_state:HostState, host_state':HostState, ios:seq>>) { && NetEventLogIsAbstractable(ios) && OnlySentMarshallableData(ios) && (|| LSchedulerNext(host_state.sched, host_state'.sched, AbstractifyRawLogToIos(ios)) || HostNextIgnoreUnsendable(host_state.sched, host_state'.sched, ios)) } function ParseCommandLineConfiguration(args:seq>) : ConcreteConfiguration { var paxos_config := paxos_config_parsing(args); var params := StaticParams(); ConstantsState(paxos_config, params) } method {:timeLimitMultiplier 4} HostInitImpl( ghost env:HostEnvironment, netc:NetClient, args:seq> ) returns ( ok:bool, host_state:HostState ) { var pconfig:CPaxosConfiguration, my_index; var id := EndPoint(netc.MyPublicKey()); ok, pconfig, my_index := parse_cmd_line(id, args); var lschedule:LScheduler; var repImpl:ReplicaImpl := new ReplicaImpl(); host_state := CScheduler(lschedule,repImpl); if !ok { return; } assert id == pconfig.replica_ids[my_index]; var scheduler := new ReplicaImpl(); var constants := InitReplicaConstantsState(id, pconfig); //SystemConfiguration(me_ep); assert constants.all.config == pconfig; assert constants.all.config.replica_ids[constants.my_index] == id; calc { constants.my_index as int; { reveal SeqIsUnique(); } my_index as int; } assert env.Valid() && env.ok.ok(); assert ReplicaConstantsState_IsValid(constants); assert WellFormedLConfiguration(AbstractifyReplicaConstantsStateToLReplicaConstants(constants).all.config); ok := scheduler.Replica_Init(constants, netc, env); if !ok { return; } host_state := CScheduler(scheduler.AbstractifyToLScheduler(), scheduler); } predicate EventsConsistent(recvs:seq, clocks:seq, sends:seq) { forall e :: && (e in recvs ==> e.LIoOpReceive?) && (e in clocks ==> e.LIoOpReadClock? || e.LIoOpTimeoutReceive?) && (e in sends ==> e.LIoOpSend?) } ghost method RemoveRecvs(events:seq) returns (recvs:seq, rest:seq) ensures forall e :: e in recvs ==> e.LIoOpReceive? ensures events == recvs + rest ensures rest != [] ==> !rest[0].LIoOpReceive? ensures NetEventsReductionCompatible(events) ==> NetEventsReductionCompatible(rest); { recvs := []; rest := []; var i := 0; while i < |events| invariant 0 <= i <= |events| invariant forall e :: e in recvs ==> e.LIoOpReceive? //invariant events == recvs + events[i..] invariant recvs == events[0..i] { if !events[i].LIoOpReceive? { rest := events[i..]; return; } recvs := recvs + [events[i]]; i := i + 1; } } predicate NetEventsReductionCompatible(events:seq) { forall i :: 0 <= i < |events| - 1 ==> events[i].LIoOpReceive? || events[i+1].LIoOpSend? } lemma lemma_RemainingEventsAreSends(events:seq) requires NetEventsReductionCompatible(events) requires |events| > 0 requires !events[0].LIoOpReceive? ensures forall e :: e in events[1..] ==> e.LIoOpSend? { if |events| == 1 { } else { assert events[1].LIoOpSend?; lemma_RemainingEventsAreSends(events[1..]); } } ghost method PartitionEvents(events:seq) returns (recvs:seq, clocks:seq, sends:seq) requires NetEventsReductionCompatible(events) ensures events == recvs + clocks + sends ensures EventsConsistent(recvs, clocks, sends) ensures |clocks| <= 1 { var rest; recvs, rest := RemoveRecvs(events); assert NetEventsReductionCompatible(rest); if |rest| > 0 && (rest[0].LIoOpReadClock? || rest[0].LIoOpTimeoutReceive?) { clocks := [rest[0]]; sends := rest[1..]; lemma_RemainingEventsAreSends(rest); } else { clocks := []; sends := rest; if |rest| > 0 { lemma_RemainingEventsAreSends(rest); } } } lemma lemma_ProtocolIosRespectReduction(s:LScheduler, s':LScheduler, ios:seq) requires Q_LScheduler_Next(s, s', ios) ensures LIoOpSeqCompatibleWithReduction(ios) { reveal Q_LScheduler_Next(); } lemma lemma_NetEventsRespectReduction(s:LScheduler, s':LScheduler, ios:seq, events:seq) requires LIoOpSeqCompatibleWithReduction(ios) requires RawIoConsistentWithSpecIO(events, ios) ensures NetEventsReductionCompatible(events) { forall i | 0 <= i < |events| - 1 ensures events[i].LIoOpReceive? || events[i+1].LIoOpSend? { assert LIoOpOrderingOKForAction(ios[i], ios[i+1]); reveal AbstractifyRawLogToIos(); assert AbstractifyRawLogToIos(events)[i] == AbstractifyNetEventToRslIo(events[i]) == ios[i]; } } method {:timeLimitMultiplier 3} HostNextImpl(ghost env:HostEnvironment, host_state:HostState) returns (ok:bool, host_state':HostState, ghost recvs:seq, ghost clocks:seq, ghost sends:seq, ghost ios:seq>>) { var lschedule:LScheduler; var repImpl:ReplicaImpl := new ReplicaImpl(); host_state' := CScheduler(lschedule,repImpl); var okay, netEventLog, abstract_ios := Replica_Next_main(host_state.replica_impl); if okay { calc { Q_LScheduler_Next(host_state.sched, host_state.replica_impl.AbstractifyToLScheduler(), abstract_ios); { reveal Q_LScheduler_Next(); } LSchedulerNext(host_state.sched, host_state.replica_impl.AbstractifyToLScheduler(), abstract_ios); } assert AbstractifyRawLogToIos(netEventLog) == abstract_ios; if LSchedulerNext(host_state.sched, host_state.replica_impl.AbstractifyToLScheduler(), abstract_ios) { lemma_ProtocolIosRespectReduction(host_state.sched, host_state.replica_impl.AbstractifyToLScheduler(), abstract_ios); } lemma_NetEventsRespectReduction(host_state.sched, host_state.replica_impl.AbstractifyToLScheduler(), abstract_ios, netEventLog); recvs, clocks, sends := PartitionEvents(netEventLog); ios := recvs + clocks + sends; //abstract_ios; assert ios == netEventLog; host_state' := CScheduler(host_state.replica_impl.AbstractifyToLScheduler(), host_state.replica_impl); } else { recvs := []; clocks := []; sends := []; } ok := okay; reveal Q_LScheduler_Next(); assert host_state.replica_impl.Env() == env; } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/RSL/LearnerModel.i.dfy ================================================ include "AppInterface.i.dfy" include "LearnerState.i.dfy" module LiveRSL__LearnerModel_i { import opened Native__Io_s import opened Native__NativeTypes_s import opened LiveRSL__AppInterface_i import opened LiveRSL__CMessage_i import opened LiveRSL__CMessageRefinements_i import opened LiveRSL__CTypes_i import opened LiveRSL__Environment_i import opened LiveRSL__ExecutorState_i import opened LiveRSL__Learner_i import opened LiveRSL__LearnerState_i import opened LiveRSL__Message_i import opened LiveRSL__PacketParsing_i import opened LiveRSL__ReplicaConstantsState_i import opened LiveRSL__Types_i import opened Collections__Maps_i import opened Collections__Sets_i import opened Common__NodeIdentity_i import opened Common__SeqIsUnique_i import opened Common__SeqIsUniqueDef_i import opened Common__NetClient_i import opened Concrete_NodeIdentity_i lemma lemma_Received2bPacketsSameSizeAsAbstraction(l_learner_tuple:CLearnerTuple, h_learner_tuple:LearnerTuple) requires LearnerTupleIsAbstractable(l_learner_tuple) requires h_learner_tuple == AbstractifyCLearnerTupleToLearnerTuple(l_learner_tuple) requires SeqIsUnique(l_learner_tuple.received_2b_message_senders) ensures |l_learner_tuple.received_2b_message_senders| == |h_learner_tuple.received_2b_message_senders| decreases |l_learner_tuple.received_2b_message_senders| { forall i1, i2 ensures 0 <= i1 < |l_learner_tuple.received_2b_message_senders| && 0 <= i2 < |l_learner_tuple.received_2b_message_senders| && i1 != i2 ==> l_learner_tuple.received_2b_message_senders[i1] != l_learner_tuple.received_2b_message_senders[i2] { reveal SeqIsUnique(); } if |l_learner_tuple.received_2b_message_senders| > 0 { var src := l_learner_tuple.received_2b_message_senders[0]; var l_received_2b_message_senders' := l_learner_tuple.received_2b_message_senders[1..]; var l_learner_tuple' := CLearnerTuple(l_received_2b_message_senders', l_learner_tuple.candidate_learned_value); var h_learner_tuple' := AbstractifyCLearnerTupleToLearnerTuple(l_learner_tuple'); assert src in l_learner_tuple.received_2b_message_senders; forall x | x in l_received_2b_message_senders' ensures AbstractifyEndPointToNodeIdentity(x) in h_learner_tuple'.received_2b_message_senders { var idx :| 0 <= idx < |l_received_2b_message_senders'| && x == l_received_2b_message_senders'[idx]; assert x == l_learner_tuple.received_2b_message_senders[idx+1]; assert x in l_learner_tuple.received_2b_message_senders[1..]; assert AbstractifyEndPointToNodeIdentity(x) in AbstractifyEndPointsToNodeIdentities(l_learner_tuple.received_2b_message_senders[1..]); assert AbstractifyEndPointToNodeIdentity(x) in SeqToSet(AbstractifyEndPointsToNodeIdentities(l_learner_tuple.received_2b_message_senders[1..])); } forall x | EndPointIsValidPublicKey(x) && AbstractifyEndPointToNodeIdentity(x) in h_learner_tuple'.received_2b_message_senders ensures x in l_received_2b_message_senders' { var idx :| 0 <= idx < |l_learner_tuple'.received_2b_message_senders| && AbstractifyEndPointToNodeIdentity(x) == AbstractifyEndPointToNodeIdentity(l_learner_tuple'.received_2b_message_senders[idx]); lemma_AbstractifyEndPointToNodeIdentity_injective(x, l_learner_tuple'.received_2b_message_senders[idx]); assert x == l_learner_tuple'.received_2b_message_senders[idx]; assert l_learner_tuple.received_2b_message_senders[idx+1] == l_learner_tuple'.received_2b_message_senders[idx]; assert x == l_learner_tuple.received_2b_message_senders[idx+1]; } assert forall x :: x in h_learner_tuple.received_2b_message_senders ==> x in h_learner_tuple'.received_2b_message_senders || x == AbstractifyEndPointToNodeIdentity(src); forall x | x in h_learner_tuple'.received_2b_message_senders || x == AbstractifyEndPointToNodeIdentity(src) ensures x in h_learner_tuple.received_2b_message_senders { if x == AbstractifyEndPointToNodeIdentity(src) { assert src in l_learner_tuple.received_2b_message_senders; assert x in AbstractifyEndPointsToNodeIdentities(l_learner_tuple.received_2b_message_senders); assert x in SeqToSet(AbstractifyEndPointsToNodeIdentities(l_learner_tuple.received_2b_message_senders)); assert x in h_learner_tuple.received_2b_message_senders; } else { assert x in h_learner_tuple.received_2b_message_senders; var idx :| 0 <= idx < |l_learner_tuple'.received_2b_message_senders| && x == AbstractifyEndPointToNodeIdentity(l_learner_tuple'.received_2b_message_senders[idx]); assert l_learner_tuple.received_2b_message_senders[idx+1] == l_learner_tuple'.received_2b_message_senders[idx]; assert x == AbstractifyEndPointToNodeIdentity(l_learner_tuple.received_2b_message_senders[idx+1]); } } assert h_learner_tuple.received_2b_message_senders == h_learner_tuple'.received_2b_message_senders + {AbstractifyEndPointToNodeIdentity(src)}; reveal SeqIsUnique(); lemma_Received2bPacketsSameSizeAsAbstraction(l_learner_tuple', h_learner_tuple'); } } lemma lemma_AbstractifyCLearnerTupleOfOneSource(l_tup:CLearnerTuple, h_tup:LearnerTuple, src:EndPoint) requires l_tup.received_2b_message_senders == [src] requires EndPointIsValidPublicKey(src) requires LearnerTupleIsAbstractable(l_tup) requires h_tup.received_2b_message_senders == {AbstractifyEndPointToNodeIdentity(src)} requires h_tup.candidate_learned_value == AbstractifyCRequestBatchToRequestBatch(l_tup.candidate_learned_value) ensures h_tup == AbstractifyCLearnerTupleToLearnerTuple(l_tup) { var s := AbstractifyCLearnerTupleToLearnerTuple(l_tup).received_2b_message_senders; forall x ensures x in s <==> x in h_tup.received_2b_message_senders { if x in s { assert x == AbstractifyEndPointToNodeIdentity(src); assert x in h_tup.received_2b_message_senders; } if x in h_tup.received_2b_message_senders { assert src in [src] && x == AbstractifyEndPointToNodeIdentity(src); assert x in AbstractifyEndPointsToNodeIdentities([src]); assert x in s; } } assert s == h_tup.received_2b_message_senders; } lemma lemma_AddingSourceToSequenceAddsToSet(source:EndPoint, sseq1:seq, sset1:set, sseq2:seq, sset2:set) requires EndPointIsValidPublicKey(source) requires SeqOfEndPointsIsAbstractable(sseq1) requires SeqOfEndPointsIsAbstractable(sseq2) requires sset1 == SeqToSet(AbstractifyEndPointsToNodeIdentities(sseq1)) requires sset2 == sset1 + {AbstractifyEndPointToNodeIdentity(source)} requires sseq2 == sseq1 + [source] ensures sset2 == SeqToSet(AbstractifyEndPointsToNodeIdentities(sseq2)) { var sset2_alt := SeqToSet(AbstractifyEndPointsToNodeIdentities(sseq2)); forall x ensures x in sset2 <==> x in sset2_alt { if x in sset2 { if x in sset1 { assert x in SeqToSet(AbstractifyEndPointsToNodeIdentities(sseq1)); assert x in AbstractifyEndPointsToNodeIdentities(sseq1); var src :| src in sseq1 && x == AbstractifyEndPointToNodeIdentity(src); assert src in sseq2; assert AbstractifyEndPointToNodeIdentity(src) in AbstractifyEndPointsToNodeIdentities(sseq2); assert AbstractifyEndPointToNodeIdentity(src) in sset2_alt; assert x in sset2_alt; } else { assert x == AbstractifyEndPointToNodeIdentity(source); assert source in sseq2; assert AbstractifyEndPointToNodeIdentity(source) in AbstractifyEndPointsToNodeIdentities(sseq2); assert AbstractifyEndPointToNodeIdentity(source) in sset2_alt; assert x in sset2_alt; } } if x in sset2_alt { assert x in AbstractifyEndPointsToNodeIdentities(sseq2); var src :| src in sseq2 && x == AbstractifyEndPointToNodeIdentity(src); if src in sseq1 { assert AbstractifyEndPointToNodeIdentity(src) in AbstractifyEndPointsToNodeIdentities(sseq1); assert x in AbstractifyEndPointsToNodeIdentities(sseq1); assert x in SeqToSet(AbstractifyEndPointsToNodeIdentities(sseq1)); assert x in sset1; assert x in sset2; } else { assert src == source; lemma_AbstractifyEndPointToNodeIdentity_injective(src, source); assert x in sset2; } } } } predicate Eq_LLearner(x:LLearner, y:LLearner) { && x.constants == y.constants && x.max_ballot_seen == y.max_ballot_seen && x.unexecuted_learner_state == y.unexecuted_learner_state } method {:timeLimitMultiplier 2} LearnerModel_Process2b(learner:CLearnerState, executor:ExecutorState, packet:CPacket) returns (learner':CLearnerState) requires LearnerState_Process2b__Preconditions(learner, executor, packet) requires Marshallable_2b(packet.msg) ensures LearnerState_Process2b__Postconditions(learner, executor, packet, learner') { lemma_AbstractifyEndPointsToNodeIdentities_properties(learner.rcs.all.config.replica_ids); lemma_AbstractifyCOperationNumberToOperationNumber_isInjective(); var msg := packet.msg; var src := packet.src; var opn := msg.opn_2b; var isBalLt1 := CBalLt(msg.bal_2b, learner.max_ballot_seen); var isBalLt2 := CBalLt(learner.max_ballot_seen, msg.bal_2b); var srcIsReplica := src in learner.rcs.all.config.replica_ids; ghost var r_learner := AbstractifyLearnerStateToLLearner(learner); ghost var r_packet := AbstractifyCPacketToRslPacket(packet); ghost var r_opn := AbstractifyCOperationNumberToOperationNumber(opn); assert srcIsReplica <==> AbstractifyCPacketToRslPacket(packet).src in AbstractifyReplicaConstantsStateToLReplicaConstants(learner.rcs).all.config.replica_ids; lemma_AbstractifyCLearnerTuplesToLearnerTuples_properties(learner.unexecuted_ops); if opn in learner.unexecuted_ops { assert CLearnerTupleIsValid(learner.unexecuted_ops[opn]); lemma_AbstractifyEndPointsToNodeIdentities_properties(learner.unexecuted_ops[opn].received_2b_message_senders); } if (!srcIsReplica || isBalLt1) { learner' := learner; } else if (isBalLt2) { var tup' := CLearnerTuple([packet.src], msg.val_2b); learner' := learner.( max_ballot_seen := msg.bal_2b, unexecuted_ops := map[opn := tup']); ghost var r_learner' := AbstractifyLearnerStateToLLearner(learner'); lemma_AbstractifyCLearnerTuplesToLearnerTuples_properties(learner'.unexecuted_ops); lemma_AbstractifyCLearnerTuplesToLearnerTuples_properties(map []); ghost var r_tup' := LearnerTuple({r_packet.src}, r_packet.msg.val_2b); ghost var r'_learner := r_learner.(max_ballot_seen := r_packet.msg.bal_2b, unexecuted_learner_state := map[r_opn := r_tup']); lemma_AbstractifyCLearnerTupleOfOneSource(tup', r_tup', packet.src); assert r_tup'.received_2b_message_senders == AbstractifyCLearnerTupleToLearnerTuple(tup').received_2b_message_senders; assert r_tup'.candidate_learned_value == AbstractifyCLearnerTupleToLearnerTuple(tup').candidate_learned_value; assert r_tup' == AbstractifyCLearnerTupleToLearnerTuple(tup'); assert Eq_LLearner(r_learner', r'_learner); forall ensures CLearnerTupleIsValid(tup') { reveal SeqIsUnique(); } } else if (opn !in learner.unexecuted_ops) { assert AbstractifyCOperationNumberToOperationNumber(opn) !in AbstractifyLearnerStateToLLearner(learner).unexecuted_learner_state; var tup' := CLearnerTuple([packet.src], msg.val_2b); learner' := learner.(unexecuted_ops := learner.unexecuted_ops[opn := tup']); ghost var r_learner' := AbstractifyLearnerStateToLLearner(learner'); ghost var r_tup' := LearnerTuple({r_packet.src}, r_packet.msg.val_2b); ghost var r'_learner := r_learner.(unexecuted_learner_state := r_learner.unexecuted_learner_state[r_opn := r_tup']); lemma_AbstractifyCLearnerTupleOfOneSource(tup', r_tup', packet.src); assert r_tup'.received_2b_message_senders == AbstractifyCLearnerTupleToLearnerTuple(tup').received_2b_message_senders; assert r_tup'.candidate_learned_value == AbstractifyCLearnerTupleToLearnerTuple(tup').candidate_learned_value; assert r_tup' == AbstractifyCLearnerTupleToLearnerTuple(tup'); assert Eq_LLearner(r_learner', r'_learner); forall ensures CLearnerTupleIsValid(tup') { reveal SeqIsUnique(); } } else if packet.src in learner.unexecuted_ops[opn].received_2b_message_senders { learner' := learner; } else { var tup := learner.unexecuted_ops[opn]; var tup' := tup.(received_2b_message_senders := tup.received_2b_message_senders + [packet.src]); learner' := learner.(unexecuted_ops := learner.unexecuted_ops[opn := tup']); ghost var r_learner' := AbstractifyLearnerStateToLLearner(learner'); ghost var r_tup := r_learner.unexecuted_learner_state[r_opn]; ghost var r_tup' := r_tup.(received_2b_message_senders := r_tup.received_2b_message_senders + {r_packet.src}); ghost var r'_learner := r_learner.(unexecuted_learner_state := r_learner.unexecuted_learner_state[r_opn := r_tup']); lemma_AddingSourceToSequenceAddsToSet(packet.src, tup.received_2b_message_senders, r_tup.received_2b_message_senders, tup'.received_2b_message_senders, r_tup'.received_2b_message_senders); assert r_tup'.received_2b_message_senders == AbstractifyCLearnerTupleToLearnerTuple(tup').received_2b_message_senders; assert r_tup'.candidate_learned_value == AbstractifyCLearnerTupleToLearnerTuple(tup').candidate_learned_value; assert r_tup' == AbstractifyCLearnerTupleToLearnerTuple(tup'); assert Eq_LLearner(r_learner', r'_learner); EstablishAppendToUniqueSeq(tup.received_2b_message_senders, packet.src, tup'.received_2b_message_senders); } } method LearnerModel_ForgetDecision(learner:CLearnerState, opn:COperationNumber) returns (learner':CLearnerState) requires LearnerState_ForgetDecision__Preconditions(learner, opn) ensures LearnerState_ForgetDecision__Postconditions(learner, opn, learner') { lemma_AbstractifyCLearnerTuplesToLearnerTuples_properties(learner.unexecuted_ops); if (opn in learner.unexecuted_ops) { learner' := learner.(unexecuted_ops := RemoveElt(learner.unexecuted_ops, opn)); lemma_map_remove_one(learner.unexecuted_ops, learner'.unexecuted_ops, opn); //assert AbstractifyCOperationNumberToOperationNumber(opn) in AbstractifyCLearnerTuplesToLearnerTuples(learner.unexecuted_ops); lemma_AbstractifyCLearnerTuplesToLearnerTuples_properties(learner'.unexecuted_ops); //lemma_map_remove_one(AbstractifyCLearnerTuplesToLearnerTuples(learner.unexecuted_ops), AbstractifyCLearnerTuplesToLearnerTuples(learner'.unexecuted_ops), AbstractifyCOperationNumberToOperationNumber(opn)); } else { learner' := learner; } } lemma lemma_MapEquality(m1:map, m2:map) requires forall u :: (u in m1 <==> u in m2) requires forall u :: u in m1 ==> m1[u] == m2[u] ensures m1 == m2 { } lemma lemma_ForgetOperationsBeforeMap(m_before:map, m_after:map, ops_complete:COperationNumber) requires m_after == map op | op in m_before && op.n >= ops_complete.n :: m_before[op] requires CLearnerTuplesAreAbstractable(m_before) ensures var rm := AbstractifyCLearnerTuplesToLearnerTuples(m_before); var rm_new := map op | op in rm && op >= AbstractifyCOperationNumberToOperationNumber(ops_complete) :: rm[op]; rm_new == AbstractifyCLearnerTuplesToLearnerTuples(m_after) { lemma_AbstractifyCLearnerTuplesToLearnerTuples_properties(m_before); lemma_AbstractifyCLearnerTuplesToLearnerTuples_properties(m_after); var r_before := AbstractifyCLearnerTuplesToLearnerTuples(m_before); var r_after := AbstractifyCLearnerTuplesToLearnerTuples(m_after); var r_op := AbstractifyCOperationNumberToOperationNumber(ops_complete); var rm_new := map op | op in r_before && op >= r_op :: r_before[op]; forall o | o in r_after ensures o in rm_new && rm_new[o] == r_after[o] { var co :| co in m_after && AbstractifyCOperationNumberToOperationNumber(co) == o; assert co in m_before && co.n >= ops_complete.n; var r_co := AbstractifyCOperationNumberToOperationNumber(co); assert r_co in r_before; assert r_co >= r_op; assert r_co in rm_new; } forall o | o in rm_new ensures o in r_after && rm_new[o] == r_after[o] { } lemma_MapEquality(rm_new, r_after); } lemma lemma_LearnerStateForgetOperationsBeforePostconditions(learner:CLearnerState, ops_complete:COperationNumber, learner':CLearnerState) requires LearnerState_ForgetOperationsBefore__Preconditions(learner, ops_complete) requires LearnerState_CommonPostconditions(learner, learner') requires learner'.max_ballot_seen == learner.max_ballot_seen requires learner'.unexecuted_ops == map op | op in learner.unexecuted_ops && op.n >= ops_complete.n :: learner.unexecuted_ops[op] //requires forall opn :: opn in learner'.unexecuted_ops ==> opn in learner.unexecuted_ops ensures LearnerState_ForgetOperationsBefore__Postconditions(learner, ops_complete, learner') { ghost var r_learner := AbstractifyLearnerStateToLLearner(learner); ghost var r_learner' := AbstractifyLearnerStateToLLearner(learner'); // var r_unexecutedOps := r_learner.unexecuted_learner_state; // var r_unexecutedOps' := r_learner'.unexecuted_learner_state; var r_opsComplete := AbstractifyCOperationNumberToOperationNumber(ops_complete); var r'_learner := r_learner.(unexecuted_learner_state := (map op | op in r_learner.unexecuted_learner_state && op >= r_opsComplete :: r_learner.unexecuted_learner_state[op])); /* assert forall o :: (o in r'_learner.unexecuted_learner_state <==> o in r_learner'.unexecuted_learner_state); assert forall o :: o in r'_learner.unexecuted_learner_state ==> r'_learner.unexecuted_learner_state[o] == r_learner'.unexecuted_learner_state[o]; ghost var m1 := r'_learner.unexecuted_learner_state; ghost var m2 := r_learner'.unexecuted_learner_state; assert forall o :: (o in m1 <==> o in m2); assert forall o :: o in m1 ==> m1[o] == m2[o]; assert (forall o :: (o in m1 <==> o in m2)) && (forall o :: o in m1 ==> m1[o] == m2[o]); lemma_MapEquality(m1, m2); assert m1 == m2; */ lemma_ForgetOperationsBeforeMap(learner.unexecuted_ops, learner'.unexecuted_ops, ops_complete); assert r'_learner.unexecuted_learner_state == r_learner'.unexecuted_learner_state; assert Eq_LLearner(r'_learner, r_learner'); /* lemma_AbstractifyCLearnerTuplesToLearnerTuples_properties(learner.unexecuted_ops); var rOpnComplete := AbstractifyCOperationNumberToOperationNumber(ops_complete); var r1 := AbstractifyLearnerStateToLLearner(learner).unexecuted_learner_state; var r2 := AbstractifyCLearnerTuplesToLearnerTuples(learner.unexecuted_ops); assert r1 == r2; var r1' := AbstractifyLearnerStateToLLearner(learner').unexecuted_learner_state; var r2' := AbstractifyCLearnerTuplesToLearnerTuples(learner'.unexecuted_ops); assert r1' == r2'; var setO := set o | o in r1 && o >= rOpnComplete; forall o | o in domain(r1') ensures o in setO { assert o in r1 && o >= rOpnComplete; } forall o | o in setO ensures o in domain(r1') {} assert domain(r1') == set o | o in r1 && o >= rOpnComplete; assert forall o :: o in domain(r1') ==> r1'[o] == r1[o]; assert r1' == map o | o in r1 && o >= rOpnComplete :: r1[o]; assert AbstractifyLearnerStateToLLearner(learner').constants == AbstractifyLearnerStateToLLearner(learner).constants; assert learner'.max_ballot_seen == learner.max_ballot_seen; assert AbstractifyLearnerStateToLLearner(learner').max_ballot_seen == AbstractifyLearnerStateToLLearner(learner).max_ballot_seen; assert AbstractifyLearnerStateToLLearner(learner').learnerState == AbstractifyLearnerStateToLLearner(learner).learnerState; assert AbstractifyLearnerStateToLLearner(learner') == AbstractifyLearnerStateToLLearner(learner')[unexecuted_learner_state := r1']; var s := AbstractifyLearnerStateToLLearner(learner); var s' := AbstractifyLearnerStateToLLearner(learner'); assert s' == s[unexecuted_learner_state := r1']; assert r1' == (map op | op in s.unexecuted_learner_state && op >= rOpnComplete :: s.unexecuted_learner_state[op]); assert s' == s[unexecuted_learner_state := (map op | op in s.unexecuted_learner_state && op >= rOpnComplete :: s.unexecuted_learner_state[op])]; assert LLearnerForgetOperationsBefore(AbstractifyLearnerStateToLLearner(learner), AbstractifyLearnerStateToLLearner(learner'), AbstractifyCOperationNumberToOperationNumber(ops_complete)); */ } method LearnerModel_ForgetOperationsBefore(learner:CLearnerState, ops_complete:COperationNumber) returns (learner':CLearnerState) requires LearnerState_ForgetOperationsBefore__Preconditions(learner, ops_complete) ensures LearnerState_ForgetOperationsBefore__Postconditions(learner, ops_complete, learner') { var unexecuted_ops' := (map op | op in learner.unexecuted_ops && op.n >= ops_complete.n :: learner.unexecuted_ops[op]); learner' := learner.(unexecuted_ops := unexecuted_ops'); lemma_LearnerStateForgetOperationsBeforePostconditions(learner, ops_complete, learner'); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/RSL/LearnerState.i.dfy ================================================ include "../../Protocol/RSL/Learner.i.dfy" include "ReplicaConstantsState.i.dfy" include "ExecutorState.i.dfy" module LiveRSL__LearnerState_i { import opened Native__Io_s import opened Native__NativeTypes_s import opened LiveRSL__AppInterface_i import opened LiveRSL__CMessage_i import opened LiveRSL__CMessageRefinements_i import opened LiveRSL__CPaxosConfiguration_i import opened LiveRSL__CTypes_i import opened LiveRSL__ExecutorState_i import opened LiveRSL__Learner_i import opened LiveRSL__ReplicaConstantsState_i import opened LiveRSL__Types_i import opened Common__NodeIdentity_i import opened Common__SeqIsUniqueDef_i import opened Collections__Sets_i import opened Collections__Maps_i import opened GenericRefinement_i datatype CLearnerTuple = CLearnerTuple( received_2b_message_senders:seq, candidate_learned_value:seq) datatype CLearnerState = CLearnerState( rcs:ReplicaConstantsState, max_ballot_seen:CBallot, unexecuted_ops:map, sendDecision:bool, opn:COperationNumber, recv2b:bool, recvCp:CPacket) predicate CLearnerTupleIsValid(tuple:CLearnerTuple) { && SeqIsUnique(tuple.received_2b_message_senders) && ValidRequestBatch(tuple.candidate_learned_value) } predicate LearnerState_IsValid(learner:CLearnerState) { && LearnerState_IsAbstractable(learner) && (forall o :: o in learner.unexecuted_ops ==> CLearnerTupleIsValid(learner.unexecuted_ops[o])) && ReplicaConstantsState_IsValid(learner.rcs) && ReplicaConstantsStateIsAbstractable(learner.rcs) } predicate LearnerTupleIsAbstractable(tuple:CLearnerTuple) { && SeqOfEndPointsIsAbstractable(tuple.received_2b_message_senders) && CRequestBatchIsAbstractable(tuple.candidate_learned_value) } function AbstractifyCLearnerTupleToLearnerTuple(tuple:CLearnerTuple) : LearnerTuple ensures LearnerTupleIsAbstractable(tuple) ==> AbstractifyCLearnerTupleToLearnerTuple(tuple) == LearnerTuple(SeqToSet(AbstractifyEndPointsToNodeIdentities(tuple.received_2b_message_senders)), AbstractifyCRequestBatchToRequestBatch(tuple.candidate_learned_value)) { if (LearnerTupleIsAbstractable(tuple)) then var pkts := AbstractifyEndPointsToNodeIdentities(tuple.received_2b_message_senders); var value := AbstractifyCRequestBatchToRequestBatch(tuple.candidate_learned_value); LearnerTuple(SeqToSet(pkts), value) else var lt:LearnerTuple :| (true); lt } predicate CLearnerTuplesAreAbstractable(tuples:map) { && (forall opn :: opn in tuples ==> COperationNumberIsAbstractable(opn)) && (forall opn :: opn in tuples ==> LearnerTupleIsAbstractable(tuples[opn])) } function RefineOperationNumberToCOperationNumber(o:OperationNumber) : COperationNumber // requires 0 <= o < 0x1_0000_0000_0000_0000 ensures (0 <= o < 0x1_0000_0000_0000_0000) ==> RefineOperationNumberToCOperationNumber(o) == COperationNumber(o as uint64) { if (0 <= o && o < 0x1_0000_0000_0000_0000) then COperationNumber(o as uint64) else var co:COperationNumber :| (true); co } function {:opaque} AbstractifyCLearnerTuplesToLearnerTuples(m:map) : map requires CLearnerTuplesAreAbstractable(m) ensures var rm := AbstractifyCLearnerTuplesToLearnerTuples(m); forall k :: k in rm ==> (exists ck :: ck in m && AbstractifyCOperationNumberToOperationNumber(ck) == k) { AbstractifyMap(m, AbstractifyCOperationNumberToOperationNumber, AbstractifyCLearnerTupleToLearnerTuple, RefineOperationNumberToCOperationNumber) } lemma lemma_AbstractifyCLearnerTuplesToLearnerTuples_properties(m:map) requires CLearnerTuplesAreAbstractable(m) ensures m == map [] ==> AbstractifyCLearnerTuplesToLearnerTuples(m) == map [] ensures forall o :: (o in m <==> AbstractifyCOperationNumberToOperationNumber(o) in AbstractifyCLearnerTuplesToLearnerTuples(m)) ensures forall o :: (o !in m ==> AbstractifyCOperationNumberToOperationNumber(o) !in AbstractifyCLearnerTuplesToLearnerTuples(m)) ensures forall o :: o in m ==> AbstractifyCLearnerTuplesToLearnerTuples(m)[AbstractifyCOperationNumberToOperationNumber(o)] == AbstractifyCLearnerTupleToLearnerTuple(m[o]) ensures var rm := AbstractifyCLearnerTuplesToLearnerTuples(m); forall k :: k in rm ==> (exists ck :: ck in m && AbstractifyCOperationNumberToOperationNumber(ck) == k) ensures forall o, t {:trigger AbstractifyCOperationNumberToOperationNumber(o), AbstractifyCLearnerTupleToLearnerTuple(t)} {:trigger m[o := t]} :: LearnerTupleIsAbstractable(t) ==> var rm := AbstractifyCLearnerTuplesToLearnerTuples(m); var rm' := AbstractifyCLearnerTuplesToLearnerTuples(m[o := t]); rm' == AbstractifyCLearnerTuplesToLearnerTuples(m)[AbstractifyCOperationNumberToOperationNumber(o) := AbstractifyCLearnerTupleToLearnerTuple(t)] ensures forall o {:trigger RemoveElt(m,o)} :: o in m ==> var rm := AbstractifyCLearnerTuplesToLearnerTuples(m); var rm' := AbstractifyCLearnerTuplesToLearnerTuples(RemoveElt(m, o)); rm' == RemoveElt(AbstractifyCLearnerTuplesToLearnerTuples(m), AbstractifyCOperationNumberToOperationNumber(o)) { var rm := AbstractifyCLearnerTuplesToLearnerTuples(m); reveal AbstractifyCLearnerTuplesToLearnerTuples(); lemma_AbstractifyMap_properties(m, AbstractifyCOperationNumberToOperationNumber, AbstractifyCLearnerTupleToLearnerTuple, RefineOperationNumberToCOperationNumber); } predicate LearnerState_IsAbstractable(learner:CLearnerState) { && CBallotIsAbstractable(learner.max_ballot_seen) && ReplicaConstantsStateIsAbstractable(learner.rcs) && CLearnerTuplesAreAbstractable(learner.unexecuted_ops) } function AbstractifyLearnerStateToLLearner(learner:CLearnerState) : LLearner requires LearnerState_IsAbstractable(learner) { var rcs := AbstractifyReplicaConstantsStateToLReplicaConstants(learner.rcs); var ballot := AbstractifyCBallotToBallot(learner.max_ballot_seen); var unexecuted_ops := AbstractifyCLearnerTuplesToLearnerTuples(learner.unexecuted_ops); LLearner(rcs, ballot, unexecuted_ops) } function LearnerState_EndPoint(learner:CLearnerState) : EndPoint requires LearnerState_IsValid(learner) { learner.rcs.all.config.replica_ids[learner.rcs.my_index] } function LearnerState_Config(learner:CLearnerState) : CPaxosConfiguration requires LearnerState_IsValid(learner) { learner.rcs.all.config } method LearnerState_Init(rcs:ReplicaConstantsState) returns (learner:CLearnerState) requires ReplicaConstantsStateIsAbstractable(rcs) requires ReplicaConstantsState_IsValid(rcs) ensures learner.rcs == rcs ensures LearnerState_IsValid(learner) ensures LLearnerInit(AbstractifyLearnerStateToLLearner(learner), AbstractifyReplicaConstantsStateToLReplicaConstants(learner.rcs)) { var endPoint := rcs.all.config.replica_ids[rcs.my_index]; learner := CLearnerState( rcs, CBallot(0, 0), map[], false, // sendDecision COperationNumber(0), false, // recv2b CPacket( endPoint, endPoint, CMessage_2b( CBallot(0,0), COperationNumber(0), []))); lemma_AbstractifyCLearnerTuplesToLearnerTuples_properties(learner.unexecuted_ops); assert LLearnerInit(AbstractifyLearnerStateToLLearner(learner), AbstractifyReplicaConstantsStateToLReplicaConstants(learner.rcs)); } predicate LearnerState_CommonPreconditions(learner:CLearnerState) { LearnerState_IsValid(learner) } predicate LearnerState_CommonPostconditions(learner:CLearnerState, learner':CLearnerState) { && LearnerState_CommonPreconditions(learner) && LearnerState_IsValid(learner') && learner.rcs == learner'.rcs } predicate LearnerState_Process2b__Preconditions(learner:CLearnerState, executor:ExecutorState, packet:CPacket) { && LearnerState_CommonPreconditions(learner) && ExecutorState_CommonPreconditions(executor) && CPacketIsAbstractable(packet) && packet.msg.CMessage_2b? } predicate LearnerState_Process2b__Postconditions(learner:CLearnerState, executor:ExecutorState, packet:CPacket, learner':CLearnerState) { && LearnerState_Process2b__Preconditions(learner, executor, packet) && LearnerState_CommonPostconditions(learner, learner') && LLearnerProcess2b(AbstractifyLearnerStateToLLearner(learner), AbstractifyLearnerStateToLLearner(learner'), AbstractifyCPacketToRslPacket(packet)) } predicate LearnerState_ForgetDecision__Preconditions(learner:CLearnerState, opn:COperationNumber) { && LearnerState_CommonPreconditions(learner) && COperationNumberIsAbstractable(opn) } predicate LearnerState_ForgetDecision__Postconditions(learner:CLearnerState, opn:COperationNumber, learner':CLearnerState) { && LearnerState_ForgetDecision__Preconditions(learner, opn) && LearnerState_CommonPostconditions(learner, learner') && LLearnerForgetDecision(AbstractifyLearnerStateToLLearner(learner), AbstractifyLearnerStateToLLearner(learner'), AbstractifyCOperationNumberToOperationNumber(opn)) } predicate LearnerState_ForgetOperationsBefore__Preconditions(learner:CLearnerState, opn:COperationNumber) { && LearnerState_CommonPreconditions(learner) && COperationNumberIsAbstractable(opn) } predicate LearnerState_ForgetOperationsBefore__Postconditions(learner:CLearnerState, opn:COperationNumber, learner':CLearnerState) { && LearnerState_ForgetOperationsBefore__Preconditions(learner, opn) && LearnerState_CommonPostconditions(learner, learner') && LLearnerForgetOperationsBefore(AbstractifyLearnerStateToLLearner(learner), AbstractifyLearnerStateToLLearner(learner'), AbstractifyCOperationNumberToOperationNumber(opn)) } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/RSL/MinCQuorumSize.i.dfy ================================================ include "../Common/NodeIdentity.i.dfy" include "CTypes.i.dfy" include "ReplicaConstantsState.i.dfy" module LiveRSL__MinCQuorumSize_i { import opened Native__NativeTypes_s import opened Common__NodeIdentity_i import opened Common__NetClient_i import opened LiveRSL__Configuration_i import opened LiveRSL__CPaxosConfiguration_i import opened LiveRSL__CTypes_i import opened LiveRSL__ReplicaConstantsState_i import opened Math__div_i method MinCQuorumSize(config:CPaxosConfiguration) returns (quorumSize:uint64) requires CPaxosConfigurationIsValid(config) ensures quorumSize as int == LMinQuorumSize(AbstractifyCPaxosConfigurationToConfiguration(config)) ensures quorumSize >= 0 { lemma_div_basics_forall(); // Needed to prove the operation below is within uint64 bounds quorumSize := (|config.replica_ids| as uint64)/2+1; ghost var c := AbstractifyCPaxosConfigurationToConfiguration(config); assert EndPointsAreValidPublicKeys(config.replica_ids); forall ep1, ep2 | ep1 in config.replica_ids && ep2 in config.replica_ids //&& EndPointIsValidPublicKey(ep1) && EndPointIsValidPublicKey(ep2) && AbstractifyEndPointToNodeIdentity(ep1) == AbstractifyEndPointToNodeIdentity(ep2) ensures ep1 == ep2 { lemma_AbstractifyEndPointToNodeIdentity_injective(ep1, ep2); } /* var s := set p | p in config.replica_ids; lemma_SeqsSetCardinalityEndPoint(config.replica_ids, s); ghost var t := set e | e in s :: AbstractifyEndPointToNodeIdentity(e); reveal AbstractifyEndPointsToNodeIdentities(); assert t == c.replica_ids; lemma_SetsCardinalityEndPoint(s, c.replica_ids); */ assert |config.replica_ids| == |c.replica_ids|; assert quorumSize as int == (LMinQuorumSize(AbstractifyCPaxosConfigurationToConfiguration(config))); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/RSL/NetRSL.i.dfy ================================================ include "../Common/NetClient.i.dfy" include "PacketParsing.i.dfy" include "CPaxosConfiguration.i.dfy" include "CClockReading.i.dfy" include "Broadcast.i.dfy" module LiveRSL__NetRSL_i { import opened Native__Io_s import opened Native__NativeTypes_s import opened Common__GenericMarshalling_i import opened Common__NodeIdentity_i import opened Common__NetClient_i import opened Common__Util_i import opened LiveRSL__CClockReading_i import opened LiveRSL__CMessage_i import opened LiveRSL__CMessageRefinements_i import opened LiveRSL__CPaxosConfiguration_i import opened LiveRSL__Environment_i import opened LiveRSL__PacketParsing_i import opened Impl__LiveRSL__Broadcast_i import opened Logic__Option_i import opened Environment_s ////////////////////////////////////////////////////////////////////////////// // These functions relate NetEvent to LiveRSL's LIoOps. // predicate NetEventIsAbstractable(evt:NetEvent) { match evt case LIoOpSend(s) => NetPacketIsAbstractable(s) case LIoOpReceive(r) => NetPacketIsAbstractable(r) case LIoOpTimeoutReceive => true case LIoOpReadClock(t) => true } function AbstractifyNetEventToRslIo(evt:NetEvent) : RslIo requires NetEventIsAbstractable(evt) { match evt case LIoOpSend(s) => LIoOpSend(AbstractifyNetPacketToRslPacket(s)) case LIoOpReceive(r) => LIoOpReceive(AbstractifyNetPacketToRslPacket(r)) case LIoOpTimeoutReceive => LIoOpTimeoutReceive() case LIoOpReadClock(t) => LIoOpReadClock(t as int) } predicate NetEventLogIsAbstractable(rawlog:seq) { forall i :: 0<=i<|rawlog| ==> NetEventIsAbstractable(rawlog[i]) } function {:opaque} AbstractifyRawLogToIos(rawlog:seq) : seq requires NetEventLogIsAbstractable(rawlog) ensures |AbstractifyRawLogToIos(rawlog)| == |rawlog| ensures forall i {:trigger AbstractifyNetEventToRslIo(rawlog[i])} {:trigger AbstractifyRawLogToIos(rawlog)[i]} :: 0<=i<|rawlog| ==> AbstractifyRawLogToIos(rawlog)[i] == AbstractifyNetEventToRslIo(rawlog[i]) { if (rawlog==[]) then [] else [AbstractifyNetEventToRslIo(rawlog[0])] + AbstractifyRawLogToIos(rawlog[1..]) } lemma lemma_EstablishAbstractifyRawLogToIos(rawlog:seq, ios:seq) requires NetEventLogIsAbstractable(rawlog) requires |rawlog| == |ios| requires forall i :: 0<=i<|rawlog| ==> ios[i] == AbstractifyNetEventToRslIo(rawlog[i]) ensures AbstractifyRawLogToIos(rawlog) == ios { reveal AbstractifyRawLogToIos(); } predicate RawIoConsistentWithSpecIO(rawlog:seq, ios:seq) { && NetEventLogIsAbstractable(rawlog) && AbstractifyRawLogToIos(rawlog) == ios } predicate OnlySentMarshallableData(rawlog:seq) { forall io :: io in rawlog && io.LIoOpSend? ==> NetPacketBound(io.s.msg) && Marshallable(PaxosDemarshallData(io.s.msg)) } ////////////////////////////////////////////////////////////////////////////// // These methods wrap the raw NetClient interface // datatype ReceiveResult = RRFail() | RRTimeout() | RRPacket(cpacket:CPacket) method{:timeLimitMultiplier 2} Receive(netClient:NetClient, localAddr:EndPoint, config:CPaxosConfiguration, msg_grammar:G) returns (rr:ReceiveResult, ghost netEvent:NetEvent) requires NetClientIsValid(netClient) requires EndPoint(netClient.MyPublicKey()) == localAddr //requires KnownSendersMatchConfig(config) requires CPaxosConfigurationIsValid(config) requires msg_grammar == CMessage_grammar() modifies NetClientRepr(netClient) ensures netClient.env == old(netClient.env) ensures netClient.MyPublicKey() == old(netClient.MyPublicKey()) ensures NetClientOk(netClient) <==> !rr.RRFail? ensures old(NetClientRepr(netClient)) == NetClientRepr(netClient) ensures !rr.RRFail? ==> && netClient.IsOpen() && old(netClient.env.net.history()) + [netEvent] == netClient.env.net.history() ensures rr.RRTimeout? ==> netEvent.LIoOpTimeoutReceive?; ensures rr.RRPacket? ==> && netEvent.LIoOpReceive? && NetPacketIsAbstractable(netEvent.r) && CPacketIsAbstractable(rr.cpacket) && CMessageIs64Bit(rr.cpacket.msg) && EndPointIsValidPublicKey(rr.cpacket.src) && AbstractifyCPacketToRslPacket(rr.cpacket) == AbstractifyNetPacketToRslPacket(netEvent.r) && rr.cpacket.msg == PaxosDemarshallData(netEvent.r.msg) && PaxosEndPointIsValid(rr.cpacket.src, config) { var timeout := 0; ghost var old_net_history := netClient.env.net.history(); var ok, timedOut, remote, buffer := netClient.Receive(timeout); if (!ok) { rr := RRFail(); return; } if (timedOut) { rr := RRTimeout(); netEvent := LIoOpTimeoutReceive(); return; } var srcEp:EndPoint := EndPoint(remote); netEvent := LIoOpReceive(LPacket(EndPoint(netClient.MyPublicKey()), srcEp, buffer[..])); assert netClient.env.net.history() == old_net_history + [netEvent]; var start_time := Time.GetDebugTimeTicks(); lemma_CMessageGrammarValid(); var cmessage := PaxosDemarshallDataMethod(buffer, msg_grammar); var end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("PaxosDemarshallDataMethod", start_time, end_time); var cpacket := CPacket(localAddr, srcEp, cmessage); rr := RRPacket(cpacket); assert netClient.env.net.history() == old_net_history + [netEvent]; if cmessage.CMessage_Invalid? { RecordTimingSeq("DemarshallMessage_Invalid", start_time, end_time); } else if cmessage.CMessage_Request? { RecordTimingSeq("DemarshallMessage_Request", start_time, end_time); } else if cmessage.CMessage_1a? { RecordTimingSeq("DemarshallMessage_1a", start_time, end_time); } else if cmessage.CMessage_1b? { RecordTimingSeq("DemarshallMessage_1b", start_time, end_time); } else if cmessage.CMessage_2a? { RecordTimingSeq("DemarshallMessage_2a", start_time, end_time); } else if cmessage.CMessage_2b? { RecordTimingSeq("DemarshallMessage_2b", start_time, end_time); } else if cmessage.CMessage_Heartbeat? { RecordTimingSeq("DemarshallMessage_Heartbeat", start_time, end_time); } else if cmessage.CMessage_Reply? { RecordTimingSeq("DemarshallMessage_Reply", start_time, end_time); } else if cmessage.CMessage_AppStateRequest? { RecordTimingSeq("DemarshallMessage_AppStateRequest", start_time, end_time); } else if cmessage.CMessage_AppStateSupply? { RecordTimingSeq("DemarshallMessage_AppStateSupply", start_time, end_time); } else if cmessage.CMessage_StartingPhase2? { RecordTimingSeq("DemarshallMessage_StartingPhase2", start_time, end_time); } assert EndPointIsValidPublicKey(EndPoint(netClient.MyPublicKey())); assert PaxosEndPointIsValid(rr.cpacket.src, config); assert AbstractifyCPacketToRslPacket(rr.cpacket) == AbstractifyNetPacketToRslPacket(netEvent.r); /* forall () ensures AbstractifyCPacketToRslPacket(rr.cpacket) == AbstractifyNetPacketToRslPacket(netEvent.r) ensures PaxosEndPointIsValid(rr.cpacket.src, config) { // lemma_Uint64EndPointRelationships(); // assert ConvertEndPointToUint64(srcEp) == rr.cpacket.src; // OBSERVE trigger assert EndPointIsValidPublicKey(netClient.LocalEndPoint()); // OBSERVE trigger } */ } method ReadClock(netClient:NetClient) returns (clock:CClockReading, ghost clockEvent:NetEvent) requires NetClientIsValid(netClient) modifies NetClientRepr(netClient) ensures old(NetClientRepr(netClient)) == NetClientRepr(netClient) ensures NetClientIsValid(netClient) ensures netClient.env == old(netClient.env) ensures old(netClient.env.net.history()) + [clockEvent] == netClient.env.net.history() ensures clockEvent.LIoOpReadClock? ensures clock.t as int == clockEvent.t ensures NetClientIsValid(netClient) ensures NetEventIsAbstractable(clockEvent) ensures netClient.MyPublicKey() == old(netClient.MyPublicKey()) // TODO we're going to call GetTime, which returns a single value. { var t := Time.GetTime(netClient.env); clockEvent := LIoOpReadClock(t as int); clock := CClockReading(t); } predicate SendLogEntryReflectsPacket(event:NetEvent, cpacket:CPacket) { && event.LIoOpSend? && NetPacketIsAbstractable(event.s) && CPacketIsAbstractable(cpacket) && AbstractifyCPacketToRslPacket(cpacket) == AbstractifyNetPacketToRslPacket(event.s) } predicate SendLogReflectsPacket(netEventLog:seq, packet:Option) { match packet { case Some(p) => |netEventLog| == 1 && SendLogEntryReflectsPacket(netEventLog[0], p) case None => netEventLog == [] } } predicate SendLogReflectsPacketSeq(netEventLog:seq, packets:seq) { && |netEventLog| == |packets| && (forall i :: 0 <= i < |packets| ==> SendLogEntryReflectsPacket(netEventLog[i], packets[i])) } predicate SendLogMatchesRefinement(netEventLog:seq, broadcast:CBroadcast, index:int) requires CBroadcastIsAbstractable(broadcast) requires broadcast.CBroadcast? requires 0<=|netEventLog|<=|broadcast.dsts| requires 0 <= index < |netEventLog| { && netEventLog[index].LIoOpSend? && NetPacketIsAbstractable(netEventLog[index].s) && AbstractifyCBroadcastToRlsPacketSeq(broadcast)[index] == AbstractifyNetPacketToRslPacket(netEventLog[index].s) } predicate SendLogReflectsBroadcastPrefix(netEventLog:seq, broadcast:CBroadcast) requires CBroadcastIsAbstractable(broadcast) requires broadcast.CBroadcast? { && 0<=|netEventLog|<=|broadcast.dsts| && forall i :: 0<=i<|netEventLog| ==> SendLogMatchesRefinement(netEventLog, broadcast, i) } predicate SendLogReflectsBroadcast(netEventLog:seq, broadcast:CBroadcast) requires CBroadcastIsAbstractable(broadcast) { if broadcast.CBroadcastNop? then netEventLog == [] else && SendLogReflectsBroadcastPrefix(netEventLog, broadcast) && |netEventLog| == |broadcast.dsts| } lemma lemma_NetEventLogAppend(broadcast:CBroadcast, netEventLog:seq, netEvent:NetEvent) requires broadcast.CBroadcast? requires CBroadcastIsValid(broadcast) requires SendLogReflectsBroadcastPrefix(netEventLog, broadcast) requires |netEventLog| < |broadcast.dsts| requires netEvent.LIoOpSend? requires NetPacketIsAbstractable(netEvent.s) requires CMessageIsAbstractable(PaxosDemarshallData(netEvent.s.msg)) requires netEvent.s.dst == broadcast.dsts[|netEventLog|] requires netEvent.s.src == broadcast.src requires BufferRefinementAgreesWithMessageRefinement(broadcast.msg, netEvent.s.msg) ensures SendLogReflectsBroadcastPrefix(netEventLog + [netEvent], broadcast) { var i := |netEventLog|; calc { AbstractifyCBroadcastToRlsPacketSeq(broadcast)[i]; BuildLBroadcast(AbstractifyEndPointToNodeIdentity(broadcast.src), AbstractifyEndPointsToNodeIdentities(broadcast.dsts), AbstractifyCMessageToRslMessage(broadcast.msg))[i]; LPacket(AbstractifyEndPointsToNodeIdentities(broadcast.dsts)[i], AbstractifyEndPointToNodeIdentity(broadcast.src), AbstractifyCMessageToRslMessage(broadcast.msg)); LPacket(AbstractifyEndPointToNodeIdentity(netEvent.s.dst), AbstractifyEndPointToNodeIdentity(netEvent.s.src), AbstractifyCMessageToRslMessage(PaxosDemarshallData(netEvent.s.msg))); AbstractifyNetPacketToRslPacket(netEvent.s); } var new_log := netEventLog + [netEvent]; forall i' | 0 <= i' < |new_log| ensures SendLogMatchesRefinement(new_log, broadcast, i') { if i' < |netEventLog| { assert new_log[i'] == netEventLog[i']; assert SendLogMatchesRefinement(netEventLog, broadcast, i'); assert SendLogMatchesRefinement(new_log, broadcast, i'); } else { assert new_log[i'] == netEvent; assert SendLogMatchesRefinement(new_log, broadcast, i'); } } calc ==> { true; forall i' :: 0 <= i' < |new_log| ==> SendLogMatchesRefinement(new_log, broadcast, i'); SendLogReflectsBroadcastPrefix(new_log, broadcast); SendLogReflectsBroadcastPrefix(netEventLog + [netEvent], broadcast); } } method SendBroadcast(netClient:NetClient, broadcast:CBroadcast, ghost localAddr_:EndPoint) returns (ok:bool, ghost netEventLog:seq) requires NetClientIsValid(netClient) requires CBroadcastIsValid(broadcast) requires EndPoint(netClient.MyPublicKey()) == localAddr_ requires broadcast.CBroadcast? ==> broadcast.src == localAddr_ modifies NetClientRepr(netClient) ensures old(NetClientRepr(netClient)) == NetClientRepr(netClient) ensures netClient.env == old(netClient.env) ensures netClient.MyPublicKey() == old(netClient.MyPublicKey()) ensures NetClientOk(netClient) <==> ok ensures ok ==> && NetClientIsValid(netClient) && netClient.IsOpen() && old(netClient.env.net.history()) + netEventLog == netClient.env.net.history() && OnlySentMarshallableData(netEventLog) && SendLogReflectsBroadcast(netEventLog, broadcast) { ok := true; netEventLog := []; if broadcast.CBroadcastNop? { // No work to do! } else { // Do the marshalling work once assert CMessageIsAbstractable(broadcast.msg); assert Marshallable(broadcast.msg); //var marshall_start_time := Time.GetDebugTimeTicks(); var buffer := PaxosMarshall(broadcast.msg); //var marshall_end_time := Time.GetDebugTimeTicks(); //RecordTimingSeq("SendBroadcast_PaxosMarshall", marshall_start_time, marshall_end_time); assert NetPacketBound(buffer[..]); calc ==> { true; CBroadcastIsValid(broadcast); CBroadcastIsAbstractable(broadcast); CMessageIsAbstractable(broadcast.msg); } var i:uint64 := 0; while i < |broadcast.dsts| as uint64 invariant 0 <= i as int <= |broadcast.dsts| invariant |netEventLog| == i as int invariant NetClientRepr(netClient) == old(NetClientRepr(netClient)) invariant netClient.env == old(netClient.env) invariant netClient.MyPublicKey() == old(netClient.MyPublicKey()) invariant NetClientIsValid(netClient) invariant NetClientOk(netClient) invariant old(netClient.env.net.history()) + netEventLog == netClient.env.net.history() invariant NetPacketBound(buffer[..]) invariant Marshallable(PaxosDemarshallData(buffer[..])) invariant BufferRefinementAgreesWithMessageRefinement(broadcast.msg, buffer[..]) invariant SendLogReflectsBroadcastPrefix(netEventLog, broadcast) invariant CMessageIsAbstractable(PaxosDemarshallData(buffer[..])) invariant OnlySentMarshallableData(netEventLog) { ghost var netEventLog_old := netEventLog; // Construct the remote address -- TODO: Only do this once per replica! var dstEp:EndPoint := broadcast.dsts[i]; //var construct_start_time := Time.GetDebugTimeTicks(); //RecordTimingSeq("SendBroadcast", construct_start_time, construct_end_time); //var send_start_time := Time.GetDebugTimeTicks(); ok := netClient.Send(dstEp.public_key, buffer); if (!ok) { return; } //var send_end_time := Time.GetDebugTimeTicks(); //RecordTimingSeq("SendBroadcast_Send", send_start_time, send_end_time); ghost var netEvent := LIoOpSend(LPacket(dstEp, EndPoint(netClient.MyPublicKey()), buffer[..])); netEventLog := netEventLog + [netEvent]; lemma_NetEventLogAppend(broadcast, netEventLog_old, netEvent); i := i + 1; } } } method SendPacket(netClient:NetClient, packets:OutboundPackets, ghost localAddr_:EndPoint) returns (ok:bool, ghost netEventLog:seq) requires NetClientIsValid(netClient) requires packets.OutboundPacket? requires OutboundPacketsIsValid(packets) requires EndPoint(netClient.MyPublicKey()) == localAddr_ requires OutboundPacketsHasCorrectSrc(packets, localAddr_) modifies NetClientRepr(netClient) ensures old(NetClientRepr(netClient)) == NetClientRepr(netClient) ensures netClient.env == old(netClient.env) ensures netClient.MyPublicKey() == old(netClient.MyPublicKey()) ensures NetClientOk(netClient) <==> ok ensures ok ==> && NetClientIsValid(netClient) && netClient.IsOpen() && old(netClient.env.net.history()) + netEventLog == netClient.env.net.history() && OnlySentMarshallableData(netEventLog) && SendLogReflectsPacket(netEventLog, packets.p) { var j:uint64 := 0; netEventLog := []; ok := true; var opt_packet := packets.p; if opt_packet.None? { } else { var cpacket := opt_packet.v; ghost var netEventLog_old := netEventLog; // Construct the remote address var dstEp:EndPoint := cpacket.dst; assert CMessageIsAbstractable(cpacket.msg); assert Marshallable(cpacket.msg); var marshall_start_time := Time.GetDebugTimeTicks(); var buffer := PaxosMarshall(cpacket.msg); var marshall_end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("SendBatch_PaxosMarshall", marshall_start_time, marshall_end_time); ghost var data := buffer[..]; assert BufferRefinementAgreesWithMessageRefinement(cpacket.msg, data); ok := netClient.Send(dstEp.public_key, buffer); if (!ok) { return; } ghost var netEvent := LIoOpSend(LPacket(dstEp, EndPoint(netClient.MyPublicKey()), buffer[..])); ghost var net := netEvent.s; calc { AbstractifyCPacketToRslPacket(cpacket); LPacket(AbstractifyEndPointToNodeIdentity(cpacket.dst), AbstractifyEndPointToNodeIdentity(cpacket.src), AbstractifyCMessageToRslMessage(cpacket.msg)); LPacket(AbstractifyEndPointToNodeIdentity(net.dst), AbstractifyEndPointToNodeIdentity(net.src), AbstractifyCMessageToRslMessage(cpacket.msg)); AbstractifyBufferToRslPacket(net.src, net.dst, data); AbstractifyBufferToRslPacket(net.src, net.dst, net.msg); AbstractifyNetPacketToRslPacket(netEvent.s); } assert SendLogEntryReflectsPacket(netEvent, cpacket); netEventLog := [netEvent]; } } method{:timeLimitMultiplier 2} SendPacketSequence(netClient:NetClient, packets:OutboundPackets, ghost localAddr_:EndPoint) returns (ok:bool, ghost netEventLog:seq) requires NetClientIsValid(netClient) requires OutboundPacketsIsValid(packets) requires packets.PacketSequence? requires EndPoint(netClient.MyPublicKey()) == localAddr_ requires OutboundPacketsHasCorrectSrc(packets, localAddr_) modifies NetClientRepr(netClient) ensures old(NetClientRepr(netClient)) == NetClientRepr(netClient) ensures netClient.env == old(netClient.env) ensures netClient.MyPublicKey() == old(netClient.MyPublicKey()) ensures NetClientOk(netClient) <==> ok ensures ok ==> && NetClientIsValid(netClient) && netClient.IsOpen() && old(netClient.env.net.history()) + netEventLog == netClient.env.net.history() && OnlySentMarshallableData(netEventLog) && SendLogReflectsPacketSeq(netEventLog, packets.s) { var cpackets := packets.s; var j:uint64 := 0; netEventLog := []; ok := true; ghost var netEventLog_old := netEventLog; ghost var netClientEnvHistory_old := old(netClient.env.net.history()); var i:uint64 := 0; while i < |cpackets| as uint64 invariant old(NetClientRepr(netClient)) == NetClientRepr(netClient) invariant netClient.env == old(netClient.env) invariant netClient.MyPublicKey() == old(netClient.MyPublicKey()) invariant NetClientOk(netClient) <==> ok invariant ok ==> ( NetClientIsValid(netClient) && netClient.IsOpen()) invariant ok ==> netClientEnvHistory_old + netEventLog == netClient.env.net.history() invariant (i == 0) ==> |netEventLog| == 0 invariant (0 < i as int < |cpackets|) ==> |netEventLog| == |cpackets[0..i]| invariant (0 < i as int < |cpackets|) ==> SendLogReflectsPacketSeq(netEventLog, cpackets[0..i]); invariant (i as int >= |cpackets|) ==> SendLogReflectsPacketSeq(netEventLog, cpackets); invariant OnlySentMarshallableData(netEventLog) { var cpacket := cpackets[i]; // Construct the remote address var dstEp:EndPoint := cpacket.dst; assert cpacket in cpackets; assert OutboundPacketsIsValid(packets); assert CMessageIsAbstractable(cpacket.msg); assert Marshallable(cpacket.msg); var buffer := PaxosMarshall(cpacket.msg); ghost var data := buffer[..]; assert BufferRefinementAgreesWithMessageRefinement(cpacket.msg, data); ok := netClient.Send(dstEp.public_key, buffer); if (!ok) { return; } ghost var netEvent := LIoOpSend(LPacket(dstEp, EndPoint(netClient.MyPublicKey()), buffer[..])); ghost var net := netEvent.s; calc { AbstractifyCPacketToRslPacket(cpacket); LPacket(AbstractifyEndPointToNodeIdentity(cpacket.dst), AbstractifyEndPointToNodeIdentity(cpacket.src), AbstractifyCMessageToRslMessage(cpacket.msg)); LPacket(AbstractifyEndPointToNodeIdentity(net.dst), AbstractifyEndPointToNodeIdentity(net.src), AbstractifyCMessageToRslMessage(cpacket.msg)); AbstractifyBufferToRslPacket(net.src, net.dst, data); AbstractifyBufferToRslPacket(net.src, net.dst, net.msg); AbstractifyNetPacketToRslPacket(netEvent.s); } assert SendLogEntryReflectsPacket(netEvent, cpacket); netEventLog := netEventLog + [netEvent]; assert cpackets[0..(i as int+1)] == cpackets[0..i as int] + [cpacket]; assert SendLogReflectsPacketSeq(netEventLog, cpackets[0..(i as int+1)]); i := i + 1; } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/RSL/PacketParsing.i.dfy ================================================ include "../../Common/Collections/Maps.i.dfy" include "../../Protocol/RSL/Configuration.i.dfy" include "../../Protocol/RSL/Message.i.dfy" include "../../Protocol/RSL/Types.i.dfy" include "../Common/GenericMarshalling.i.dfy" include "CTypes.i.dfy" include "CMessage.i.dfy" include "CMessageRefinements.i.dfy" module LiveRSL__PacketParsing_i { import opened Native__Io_s import opened Native__NativeTypes_s import opened Collections__Maps_i import opened LiveRSL__AppInterface_i import opened LiveRSL__CMessage_i import opened LiveRSL__CMessageRefinements_i import opened LiveRSL__Configuration_i import opened LiveRSL__CTypes_i import opened LiveRSL__Environment_i import opened LiveRSL__Message_i import opened LiveRSL__Types_i import opened Common__GenericMarshalling_i import opened Common__NodeIdentity_i import opened Common__NetClient_i import opened Common__Util_i import opened AppStateMachine_s import opened Environment_s import opened Math__mul_i import opened Math__mul_nonlinear_i //////////////////////////////////////////////////////////////////// // Grammars for the Paxos types //////////////////////////////////////////////////////////////////// function method EndPoint_grammar() : G { GByteArray } function method CRequest_grammar() : G { GTuple([EndPoint_grammar(), GUint64, GByteArray]) } function method CRequestBatch_grammar() : G { GArray(CRequest_grammar()) } function method CReply_grammar() : G { GTuple([EndPoint_grammar(), GUint64, GByteArray]) } function method CBallot_grammar() : G { GTuple([GUint64, GUint64]) } function method COperationNumber_grammar() : G { GUint64 } function method CVote_grammar() : G { GTuple([CBallot_grammar(), CRequestBatch_grammar()])} function method CMap_grammar(key:G, val:G) : G { GArray(GTuple([key, val])) } function method CVotes_grammar() : G { GArray(GTuple([COperationNumber_grammar(), CVote_grammar()])) } //////////////////////////////////////////////////////////////////// // Grammars for the Paxos messages //////////////////////////////////////////////////////////////////// function method CMessage_Request_grammar() : G { GTuple([GUint64, GByteArray]) } function method CMessage_1a_grammar() : G { CBallot_grammar() } function method CMessage_1b_grammar() : G { GTuple([CBallot_grammar(), COperationNumber_grammar(), CVotes_grammar()]) } function method CMessage_2a_grammar() : G { GTuple([CBallot_grammar(), COperationNumber_grammar(), CRequestBatch_grammar()]) } function method CMessage_2b_grammar() : G { GTuple([CBallot_grammar(), COperationNumber_grammar(), CRequestBatch_grammar()]) } function method CMessage_Heartbeat_grammar() : G { GTuple([CBallot_grammar(), GUint64, COperationNumber_grammar()]) } function method CMessage_Reply_grammar() : G { GTuple( [GUint64, GByteArray] ) } function method CMessage_AppStateRequest_grammar() : G { GTuple([CBallot_grammar(), COperationNumber_grammar()]) } function method CMessage_AppStateSupply_grammar() : G { GTuple([CBallot_grammar(), COperationNumber_grammar(), GByteArray]) } function method CMessage_StartingPhase2_grammar() : G { GTuple([CBallot_grammar(), COperationNumber_grammar()]) } function method CMessage_grammar() : G { GTaggedUnion([ CMessage_Request_grammar(), CMessage_1a_grammar(), CMessage_1b_grammar(), CMessage_2a_grammar(), CMessage_2b_grammar(), CMessage_Heartbeat_grammar(), CMessage_Reply_grammar(), CMessage_AppStateRequest_grammar(), CMessage_AppStateSupply_grammar(), CMessage_StartingPhase2_grammar() ]) } predicate NetPacketBound(data:seq) { |data| < MaxPacketSize() } //////////////////////////////////////////////////////////////////// // 64-bit Limits //////////////////////////////////////////////////////////////////// predicate CRequestBatchIs64Bit(batch:CRequestBatch) { |batch| < 0x1_0000_0000_0000_0000 } predicate CVoteIs64Bit(vote:CVote) { CRequestBatchIs64Bit(vote.max_val) } predicate CVotesIs64Bit(votes:CVotes) { && |votes.v| < 0x1_0000_0000_0000_0000 && (forall opn :: opn in votes.v ==> CVoteIs64Bit(votes.v[opn])) } predicate CMessageIs64Bit(msg:CMessage) { match msg case CMessage_Invalid => true case CMessage_Request(seqno, val) => true case CMessage_1a(bal) => true case CMessage_1b(bal, log_truncation_point, votes) => CVotesIs64Bit(votes) case CMessage_2a(bal, opn, batch) => CRequestBatchIs64Bit(batch) case CMessage_2b(bal, opn, batch) => CRequestBatchIs64Bit(batch) case CMessage_Heartbeat(bal, suspicious, opn) => true case CMessage_Reply(seqno, reply) => true case CMessage_AppStateRequest(bal, opn) => true case CMessage_AppStateSupply(bal, opn, app) => true case CMessage_StartingPhase2(bal, log_truncation_point) => true } //////////////////////////////////////////////////////////////////// // Parsing //////////////////////////////////////////////////////////////////// function method parse_EndPoint(val:V) : EndPoint requires ValInGrammar(val, EndPoint_grammar()) ensures EndPointIsAbstractable(parse_EndPoint(val)) { EndPoint(val.b) } function method parse_Request(val:V) : CRequest requires ValInGrammar(val, CRequest_grammar()) ensures CRequestIsAbstractable(parse_Request(val)) { assert ValInGrammar(val.t[0], CRequest_grammar().t[0]); // OBSERVE assert ValInGrammar(val.t[1], CRequest_grammar().t[1]); // OBSERVE assert ValInGrammar(val.t[2], CRequest_grammar().t[2]); // OBSERVE var ep := parse_EndPoint(val.t[0]); CRequest(ep, val.t[1].u, val.t[2].b) } function parse_RequestBatch(val:V) : CRequestBatch requires ValInGrammar(val, CRequestBatch_grammar()) ensures |parse_RequestBatch(val)| == |val.a| ensures forall i :: 0 <= i < |parse_RequestBatch(val)| ==> parse_RequestBatch(val)[i] == parse_Request(val.a[i]) ensures CRequestBatchIsAbstractable(parse_RequestBatch(val)) ensures ValidVal(val) ==> CRequestBatchIs64Bit(parse_RequestBatch(val)) decreases |val.a| { if |val.a| == 0 then [] else var req := parse_Request(val.a[0]); var restVal:V := VArray(val.a[1..]); var rest := parse_RequestBatch(restVal); [req] + rest } /* method parse_RequestBatchIter(val:V) returns (batch:CRequestBatch) requires ValInGrammar(val, CRequestBatch_grammar()) requires ValidVal(val) ensures |batch| == |val.a| ensures forall i :: 0 <= i < |batch| ==> batch[i] == parse_Request(val.a[i]) { batch := []; var i:uint64 := 0; while i < |val.a| as uint64 invariant 0 <= int(i) <= |val.a| invariant int(i) == |batch| invariant forall j :: 0 <= j < int(i) ==> batch[j] == parse_Request(val.a[j]) { var req := parse_Request(val.a[i]); batch := batch + [req]; i := i + 1; } } */ method Parse_RequestBatch(val:V) returns (batch:CRequestBatch) requires ValInGrammar(val, CRequestBatch_grammar()) requires ValidVal(val) ensures |batch| == |val.a| ensures CRequestBatchIs64Bit(batch) ensures forall i :: 0 <= i < |batch| ==> batch[i] == parse_Request(val.a[i]) ensures batch == parse_RequestBatch(val) ensures CRequestBatchIsAbstractable(batch) { var batchArr := new CRequest[|val.a| as uint64]; var i:uint64 := 0; while i < |val.a| as uint64 invariant 0 <= i as int <= |val.a| invariant forall j :: 0 <= j < i as int ==> batchArr[j] == parse_Request(val.a[j]) { var req := parse_Request(val.a[i]); batchArr[i] := req; i := i + 1; } batch := batchArr[..]; } function method parse_Reply(val:V) : CReply requires ValInGrammar(val, CReply_grammar()) ensures CReplyIsAbstractable(parse_Reply(val)) { assert ValInGrammar(val.t[0], CReply_grammar().t[0]); // OBSERVE assert ValInGrammar(val.t[1], CReply_grammar().t[1]); // OBSERVE assert ValInGrammar(val.t[2], CReply_grammar().t[2]); // OBSERVE var ep := parse_EndPoint(val.t[0]); CReply(ep, val.t[1].u, val.t[2].b) } function method parse_Ballot(val:V) : CBallot requires ValInGrammar(val, CBallot_grammar()) ensures CBallotIsAbstractable(parse_Ballot(val)) { assert ValInGrammar(val.t[0], CBallot_grammar().t[0]); // OBSERVE assert ValInGrammar(val.t[1], CBallot_grammar().t[1]); // OBSERVE CBallot(val.t[0].u, val.t[1].u) } function method parse_OperationNumber(val:V) : COperationNumber requires ValInGrammar(val, COperationNumber_grammar()) ensures COperationNumberIsAbstractable(parse_OperationNumber(val)) { COperationNumber(val.u) } function parse_Vote(val:V) : CVote requires ValInGrammar(val, CVote_grammar()) ensures CVoteIsAbstractable(parse_Vote(val)) ensures ValidVal(val) ==> CVoteIs64Bit(parse_Vote(val)) { CVote(parse_Ballot(val.t[0]), parse_RequestBatch(val.t[1])) } method Parse_Vote(val:V) returns (vote:CVote) requires ValInGrammar(val, CVote_grammar()) requires ValidVal(val) ensures parse_Vote(val) == vote ensures CVoteIs64Bit(vote) { var batch := Parse_RequestBatch(val.t[1]); vote := CVote(parse_Ballot(val.t[0]), batch); } // Abandoned for now, since the marshalling side is all methods, so we can't easily make it higher order // //function method parse_Map(val:V, parse_key:V->KT, parse_val:V->VT, key_grammar:G, val_grammar:G) : map // requires ValInGrammar(val, CMap_grammar(key_grammar, val_grammar)) // requires forall v :: parse_key.requires(v) && parse_val.requires(v) // reads parse_key.reads, parse_val.reads; // decreases |val.a| //{ // if |val.a| == 0 then // map [] // else // var tuple := val.a[0]; // assert ValInGrammar(tuple, CMap_grammar(key_grammar, val_grammar).elt); // assert ValInGrammar(tuple.t[0], CMap_grammar(key_grammar, val_grammar).elt.t[0]); // OBSERVE // assert ValInGrammar(tuple.t[1], CMap_grammar(key_grammar, val_grammar).elt.t[1]); // OBSERVE // var k := parse_key(tuple.t[0]); // var v := parse_val(tuple.t[1]); // var others := parse_Map(VArray(val.a[1..]), parse_key, parse_val, key_grammar, val_grammar); // var m := others[k := v]; // m //} function parse_Votes(val:V) : CVotes requires ValInGrammar(val, CVotes_grammar()) ensures CVotesIsAbstractable(parse_Votes(val)) ensures |parse_Votes(val).v| <= |val.a| ensures ValidVal(val) ==> CVotesIs64Bit(parse_Votes(val)) decreases |val.a| { if |val.a| == 0 then CVotes(map []) else var tuple := val.a[0]; assert ValInGrammar(tuple, CVotes_grammar().elt); assert ValInGrammar(tuple.t[0], CVotes_grammar().elt.t[0]); // OBSERVE assert ValInGrammar(tuple.t[1], CVotes_grammar().elt.t[1]); // OBSERVE var op := parse_OperationNumber(tuple.t[0]); var vote := parse_Vote(tuple.t[1]); var others := parse_Votes(VArray(val.a[1..])); calc { ValidVal(val); ==> { assert val.a[0] in val.a; } ValidVal(val.a[0]); ==> ValidVal(tuple); ==> { assert tuple.t[1] in tuple.t; } ValidVal(tuple.t[1]); ==> CVoteIs64Bit(vote); } var m := others.v[op := vote]; assert COperationNumberIsAbstractable(op); CVotes(m) } method Parse_Votes(val:V) returns (votes:CVotes) requires ValInGrammar(val, CVotes_grammar()) requires ValidVal(val) ensures CVotesIsAbstractable(votes) ensures CVotesIs64Bit(votes) decreases |val.a| ensures votes == parse_Votes(val) { if |val.a| as uint64 == 0 { votes := CVotes(map []); } else { var tuple := val.a[0]; assert ValInGrammar(tuple, CVotes_grammar().elt); assert ValInGrammar(tuple.t[0], CVotes_grammar().elt.t[0]); // OBSERVE assert ValInGrammar(tuple.t[1], CVotes_grammar().elt.t[1]); // OBSERVE calc ==> { ValidVal(val); ValidVal(tuple); ValidVal(tuple.t[1]); } var op := parse_OperationNumber(tuple.t[0]); var vote := Parse_Vote(tuple.t[1]); var others := Parse_Votes(VArray(val.a[1..])); var m := others.v[op := vote]; votes := CVotes(m); } } function method parse_Message_Request(val:V) : CMessage requires ValInGrammar(val, CMessage_Request_grammar()) ensures CMessageIsAbstractable(parse_Message_Request(val)) ensures ValidVal(val) ==> CMessageIs64Bit(parse_Message_Request(val)) { assert ValInGrammar(val.t[0], CMessage_Request_grammar().t[0]); // OBSERVE assert ValInGrammar(val.t[1], CMessage_Request_grammar().t[1]); // OBSERVE CMessage_Request(val.t[0].u, val.t[1].b) } function method parse_Message_1a(val:V) : CMessage requires ValInGrammar(val, CMessage_1a_grammar()) ensures CMessageIsAbstractable(parse_Message_1a(val)) ensures ValidVal(val) ==> CMessageIs64Bit(parse_Message_1a(val)) { CMessage_1a(parse_Ballot(val)) } function parse_Message_1b(val:V) : CMessage requires ValInGrammar(val, CMessage_1b_grammar()) ensures CMessageIsAbstractable(parse_Message_1b(val)) ensures ValidVal(val) ==> CMessageIs64Bit(parse_Message_1b(val)) { CMessage_1b(parse_Ballot(val.t[0]), parse_OperationNumber(val.t[1]), parse_Votes(val.t[2])) } method Parse_Message_1b(val:V) returns (msg:CMessage) requires ValInGrammar(val, CMessage_1b_grammar()) requires ValidVal(val) ensures msg == parse_Message_1b(val) ensures CMessageIsAbstractable(msg) ensures CMessageIs64Bit(msg) { var votes := Parse_Votes(val.t[2]); msg := CMessage_1b(parse_Ballot(val.t[0]), parse_OperationNumber(val.t[1]), votes); } function parse_Message_2a(val:V) : CMessage requires ValInGrammar(val, CMessage_2a_grammar()) ensures CMessageIsAbstractable(parse_Message_2a(val)) ensures ValidVal(val) ==> CMessageIs64Bit(parse_Message_2a(val)) { CMessage_2a(parse_Ballot(val.t[0]), parse_OperationNumber(val.t[1]), parse_RequestBatch(val.t[2])) } method Parse_Message_2a(val:V) returns (msg:CMessage) requires ValInGrammar(val, CMessage_2a_grammar()) requires ValidVal(val) ensures msg == parse_Message_2a(val) ensures CMessageIsAbstractable(msg) ensures CMessageIs64Bit(msg) { var batch := Parse_RequestBatch(val.t[2]); msg := CMessage_2a(parse_Ballot(val.t[0]), parse_OperationNumber(val.t[1]), batch); } function parse_Message_2b(val:V) : CMessage requires ValInGrammar(val, CMessage_2b_grammar()) ensures ValidVal(val) ==> CMessageIs64Bit(parse_Message_2b(val)) { CMessage_2b(parse_Ballot(val.t[0]), parse_OperationNumber(val.t[1]), parse_RequestBatch(val.t[2])) } method Parse_Message_2b(val:V) returns (msg:CMessage) requires ValInGrammar(val, CMessage_2b_grammar()) requires ValidVal(val) ensures msg == parse_Message_2b(val) ensures CMessageIsAbstractable(msg) ensures CMessageIs64Bit(msg) { var batch := Parse_RequestBatch(val.t[2]); msg := CMessage_2b(parse_Ballot(val.t[0]), parse_OperationNumber(val.t[1]), batch); } function method parse_Message_Heartbeat(val:V) : CMessage requires ValInGrammar(val, CMessage_Heartbeat_grammar()) ensures CMessageIsAbstractable(parse_Message_Heartbeat(val)) ensures ValidVal(val) ==> CMessageIs64Bit(parse_Message_Heartbeat(val)) { assert ValInGrammar(val.t[1], CMessage_Heartbeat_grammar().t[1]); // OBSERVE CMessage_Heartbeat(parse_Ballot(val.t[0]), val.t[1].u != 0, parse_OperationNumber(val.t[2])) } function method parse_Message_Reply(val:V) : CMessage requires ValInGrammar(val, CMessage_Reply_grammar()) ensures CMessageIsAbstractable(parse_Message_Reply(val)) ensures ValidVal(val) ==> CMessageIs64Bit(parse_Message_Reply(val)) { assert ValInGrammar(val.t[0], CMessage_Reply_grammar().t[0]); // OBSERVE assert ValInGrammar(val.t[1], CMessage_Reply_grammar().t[1]); // OBSERVE CMessage_Reply(val.t[0].u, val.t[1].b) } function method parse_Message_AppStateRequest(val:V) : CMessage requires ValInGrammar(val, CMessage_AppStateRequest_grammar()) ensures CMessageIsAbstractable(parse_Message_AppStateRequest(val)) ensures ValidVal(val) ==> CMessageIs64Bit(parse_Message_AppStateRequest(val)) { CMessage_AppStateRequest(parse_Ballot(val.t[0]), parse_OperationNumber(val.t[1])) } function method parse_Message_AppStateSupply(val:V) : CMessage requires ValInGrammar(val, CMessage_AppStateSupply_grammar()) ensures CMessageIsAbstractable(parse_Message_AppStateSupply(val)) ensures ValidVal(val) ==> CMessageIs64Bit(parse_Message_AppStateSupply(val)) { assert ValInGrammar(val.t[2], GByteArray); CMessage_AppStateSupply(parse_Ballot(val.t[0]), parse_OperationNumber(val.t[1]), val.t[2].b) } function method parse_Message_StartingPhase2(val:V) : CMessage requires ValInGrammar(val, CMessage_StartingPhase2_grammar()) ensures CMessageIsAbstractable(parse_Message_StartingPhase2(val)) ensures ValidVal(val) ==> CMessageIs64Bit(parse_Message_StartingPhase2(val)) { CMessage_StartingPhase2(parse_Ballot(val.t[0]), parse_OperationNumber(val.t[1])) } function parse_Message(val:V) : CMessage requires ValInGrammar(val, CMessage_grammar()) ensures CMessageIsAbstractable(parse_Message(val)) ensures ValidVal(val) ==> CMessageIs64Bit(parse_Message(val)) { if val.c == 0 then parse_Message_Request(val.val) else if val.c == 1 then parse_Message_1a(val.val) else if val.c == 2 then parse_Message_1b(val.val) else if val.c == 3 then parse_Message_2a(val.val) else if val.c == 4 then parse_Message_2b(val.val) else if val.c == 5 then parse_Message_Heartbeat(val.val) else if val.c == 6 then parse_Message_Reply(val.val) else if val.c == 7 then parse_Message_AppStateRequest(val.val) else if val.c == 8 then parse_Message_AppStateSupply(val.val) else if val.c == 9 then parse_Message_StartingPhase2(val.val) else assert false; // Should never get here parse_Message_Request(val) } method Parse_Message(val:V) returns (msg:CMessage) requires ValInGrammar(val, CMessage_grammar()) requires ValidVal(val) ensures msg == parse_Message(val) ensures !msg.CMessage_Invalid? ensures CMessageIsAbstractable(msg) ensures CMessageIs64Bit(msg) { if val.c == 0 { msg := parse_Message_Request(val.val); } else if val.c == 1 { msg := parse_Message_1a(val.val); } else if val.c == 2 { msg := Parse_Message_1b(val.val); } else if val.c == 3 { msg := Parse_Message_2a(val.val); } else if val.c == 4 { msg := Parse_Message_2b(val.val); } else if val.c == 5 { msg := parse_Message_Heartbeat(val.val); } else if val.c == 6 { msg := parse_Message_Reply(val.val); } else if val.c == 7 { msg := parse_Message_AppStateRequest(val.val); } else if val.c == 8 { msg := parse_Message_AppStateSupply(val.val); } else if val.c == 9 { msg := parse_Message_StartingPhase2(val.val); } else { assert false; // Should never get here msg := parse_Message_Request(val); } } function PaxosDemarshallData(data:seq) : CMessage ensures CMessageIsAbstractable(PaxosDemarshallData(data)) { if Demarshallable(data, CMessage_grammar()) then var val := DemarshallFunc(data, CMessage_grammar()); parse_Message(val) else CMessage_Invalid() } method PaxosDemarshallDataMethod(data:array, msg_grammar:G) returns (msg:CMessage) requires data.Length < 0x1_0000_0000_0000_0000 requires msg_grammar == CMessage_grammar() requires ValidGrammar(msg_grammar) ensures CMessageIsAbstractable(msg) ensures if Demarshallable(data[..], msg_grammar) then msg == PaxosDemarshallData(data[..]) else msg.CMessage_Invalid? ensures CMessageIs64Bit(msg) { var success, val := Demarshall(data, msg_grammar); if success { assert ValInGrammar(val, msg_grammar); msg := Parse_Message(val); assert !msg.CMessage_Invalid?; } else { msg := CMessage_Invalid(); } } //////////////////////////////////////////////////////////////////// // Can a value be marshalled? //////////////////////////////////////////////////////////////////// function Marshallable_2a(msg:CMessage) : bool { && msg.CMessage_2a? && ValidRequestBatch(msg.val_2a) } function Marshallable_2b(msg:CMessage) : bool { && msg.CMessage_2b? && ValidRequestBatch(msg.val_2b) } function Marshallable(msg:CMessage) : bool { && (!msg.CMessage_Invalid?) && (msg.CMessage_Request? ==> CAppRequestMarshallable(msg.val)) && (msg.CMessage_1a? ==> true) && (msg.CMessage_1b? ==> ValidVotes(msg.votes)) && (msg.CMessage_2a? ==> Marshallable_2a(msg)) && (msg.CMessage_2b? ==> Marshallable_2b(msg)) && (msg.CMessage_Heartbeat? ==> true) && (msg.CMessage_Reply? ==> CAppReplyMarshallable(msg.reply)) && (msg.CMessage_AppStateRequest? ==> true) && (msg.CMessage_AppStateSupply? ==> CAppStateMarshallable(msg.app_state)) && (msg.CMessage_StartingPhase2? ==> true) } function CMessageIsValid(msg:CMessage) : bool { Marshallable(msg) } predicate CPacketsIsMarshallable(cps:set) { forall cp :: cp in cps ==> Marshallable(cp.msg) } method DetermineIfValidVote(vote:CVote) returns (b:bool) requires CVoteIsAbstractable(vote) requires CVoteIs64Bit(vote) ensures b == ValidVote(vote) { var num_votes:uint64 := |vote.max_val| as uint64; if num_votes > 100 { // RequestBatchSizeLimit b := false; return; } var pos:uint64 := 0; while pos < num_votes invariant 0 <= pos <= num_votes invariant forall i :: 0 <= i < pos ==> ValidRequest(vote.max_val[i]) { var c := vote.max_val[pos]; if !CAppRequestMarshallable(c.request) || !EndPointIsValidPublicKey(c.client) { assert !ValidRequest(c); assert !ValidRequestBatch(vote.max_val); b := false; return; } pos := pos + 1; } b := true; } method DetermineIfValidVotes(votes:CVotes) returns (b:bool) requires CVotesIsAbstractable(votes) requires CVotesIs64Bit(votes) ensures b == ValidVotes(votes) { b := (|votes.v| as uint64) < 8; // max_votes_len if !b { return; } var keys := domain(votes.v); lemma_MapSizeIsDomainSize(keys, votes.v); while |keys| > 0 invariant |keys| < max_votes_len() invariant forall opn :: opn in keys ==> opn in votes.v invariant forall opn :: opn in votes.v ==> opn in keys || ValidVote(votes.v[opn]) decreases |keys| { var opn :| opn in keys; keys := keys - {opn}; b := DetermineIfValidVote(votes.v[opn]); if !b { return; } } } method DetermineIfValidRequestBatch(c:CRequestBatch) returns (b:bool) requires CRequestBatchIsAbstractable(c) requires CRequestBatchIs64Bit(c) ensures b == ValidRequestBatch(c) { var n := |c| as uint64; b := n <= 100; if !b { return; } var pos: uint64 := 0; while pos < n invariant 0 <= pos <= n invariant forall i :: 0 <= i < pos ==> ValidRequest(c[i]) { var cr := c[pos]; if !ValidRequest(c[pos]) { b := false; return; } pos := pos + 1; } } method DetermineIfMessageMarshallable(msg:CMessage) returns (b:bool) requires CMessageIsAbstractable(msg) requires CMessageIs64Bit(msg) ensures b == Marshallable(msg) { if msg.CMessage_Invalid? { b := false; } else if msg.CMessage_Request? { b := CAppRequestMarshallable(msg.val); } else if msg.CMessage_1a? { b := true; } else if msg.CMessage_1b? { b := DetermineIfValidVotes(msg.votes); } else if msg.CMessage_2a? { b := DetermineIfValidRequestBatch(msg.val_2a); } else if msg.CMessage_2b? { b := DetermineIfValidRequestBatch(msg.val_2b); } else if msg.CMessage_Heartbeat? { b := true; } else if msg.CMessage_Reply? { b := CAppReplyMarshallable(msg.reply); } else if msg.CMessage_AppStateRequest? { b := true; } else if msg.CMessage_AppStateSupply? { b := CAppStateMarshallable(msg.app_state); } else if msg.CMessage_StartingPhase2? { b := true; } else { assert false; } } //////////////////////////////////////////////////////////////////// // Marshalling //////////////////////////////////////////////////////////////////// method MarshallEndPoint(c:EndPoint) returns (val:V) requires EndPointIsValidPublicKey(c) ensures ValInGrammar(val, EndPoint_grammar()) ensures ValidVal(val) ensures parse_EndPoint(val) == c { val := VByteArray(c.public_key); } method MarshallRequest(c:CRequest) returns (val:V) requires ValidRequest(c) ensures ValInGrammar(val, CRequest_grammar()) ensures ValidVal(val) ensures parse_Request(val) == c { var marshalled_app_message := MarshallCAppRequest(c.request); var marshalled_ep := MarshallEndPoint(c.client); val := VTuple([marshalled_ep, VUint64(c.seqno), marshalled_app_message]); assert ValInGrammar(val.t[0], CRequest_grammar().t[0]); // OBSERVE assert ValInGrammar(val.t[1], CRequest_grammar().t[1]); // OBSERVE assert ValInGrammar(val.t[2], CRequest_grammar().t[2]); // OBSERVE calc { ValidVal(val); ValidVal(val.t[0]) && ValidVal(val.t[1]) && ValidVal(val.t[2]); } } method MarshallRequestBatch(c:CRequestBatch) returns (val:V) requires ValidRequestBatch(c) ensures ValInGrammar(val, CRequestBatch_grammar()) ensures ValidVal(val) ensures parse_RequestBatch(val) == c { var reqs := new V[|c| as uint64]; var i:uint64 := 0; while i < |c| as uint64 invariant 0 <= i as int <= |c| invariant forall j :: 0 <= j < i ==> ValInGrammar(reqs[j], CRequest_grammar()) invariant forall j :: 0 <= j < i ==> ValidVal(reqs[j]) invariant forall j :: 0 <= j < i ==> parse_Request(reqs[j]) == c[j] { var single := MarshallRequest(c[i]); assert ValInGrammar(single, CRequest_grammar()); reqs[i] := single; i := i + 1; } val := VArray(reqs[..]); } method MarshallReply(c:CReply) returns (val:V) requires ValidReply(c) ensures ValInGrammar(val, CReply_grammar()) ensures ValidVal(val) ensures parse_Reply(val) == c { var marshalled_app_message := MarshallCAppReply(c.reply); var marshalled_ep := MarshallEndPoint(c.client); val := VTuple([marshalled_ep, VUint64(c.seqno), marshalled_app_message]); assert ValInGrammar(val.t[0], CReply_grammar().t[0]); // OBSERVE assert ValInGrammar(val.t[1], CReply_grammar().t[1]); // OBSERVE assert ValInGrammar(val.t[2], CReply_grammar().t[2]); // OBSERVE calc { ValidVal(val); ValidVal(val.t[0]) && ValidVal(val.t[1]) && ValidVal(val.t[2]); } } method MarshallBallot(c:CBallot) returns (val:V) ensures ValInGrammar(val, CBallot_grammar()) ensures ValidVal(val) ensures parse_Ballot(val) == c { val := VTuple([VUint64(c.seqno), VUint64(c.proposer_id)]); } method MarshallOperationNumber(c:COperationNumber) returns (val:V) ensures ValInGrammar(val, COperationNumber_grammar()) ensures ValidVal(val) ensures parse_OperationNumber(val) == c { val := VUint64(c.n); } method MarshallVote(c:CVote) returns (val:V) requires ValidVote(c) ensures ValInGrammar(val, CVote_grammar()) ensures ValidVal(val) ensures parse_Vote(val) == c { var bal := MarshallBallot(c.max_value_bal); var v := MarshallRequestBatch(c.max_val); val := VTuple([bal, v]); } method{:timeLimitMultiplier 3} MarshallVotes(c:CVotes) returns (val:V) requires ValidVotes(c) decreases |c.v| ensures ValInGrammar(val, CVotes_grammar()) ensures |val.a| == |c.v| ensures ValidVal(val) ensures parse_Votes(val) == c //ensures val == fun_MarshallVotes(c) ensures SeqSum(val.a) <= |c.v| * (8 + (8 + 8) + (8 + (0x10_0018 + MaxAppRequestSize())*RequestBatchSizeLimit())) { if |c.v| == 0 { val := VArray([]); reveal SeqSum(); } else { lemma_non_empty_map_has_elements(c.v); var op :| op in c.v; var marshalled_op := MarshallOperationNumber(op); var marshalled_vote := MarshallVote(c.v[op]); var remainder := RemoveElt(c.v, op); var marshalled_remainder := MarshallVotes(CVotes(remainder)); assert parse_Votes(marshalled_remainder) == CVotes(remainder); val := VArray([VTuple([marshalled_op, marshalled_vote])] + marshalled_remainder.a); // OBSERVE (everything below; not sure which bit is critical to proving the final ensures ghost var tuple := val.a[0]; ghost var rest := val.a[1..]; assert ValInGrammar(tuple, CVotes_grammar().elt); assert ValInGrammar(tuple.t[0], CVotes_grammar().elt.t[0]); assert ValInGrammar(tuple.t[1], CVotes_grammar().elt.t[1]); ghost var op' := parse_OperationNumber(tuple.t[0]); ghost var vote' := parse_Vote(tuple.t[1]); ghost var others' := parse_Votes(VArray(val.a[1..])); ghost var m' := others'.v[op' := vote']; assert op' == op; assert vote' == c.v[op]; assert others' == CVotes(remainder); assert m' == c.v; // Prove the SeqSum ensure calc { SeqSum(val.a); { reveal SeqSum(); } SizeOfV(val.a[0]) + SeqSum(val.a[1..]); <= SizeOfV(val.a[0]) + |remainder| * (8 + (8 + 8) + (8 + ((0x10_0018 + MaxAppRequestSize())*RequestBatchSizeLimit()))); //SizeOfV(val.a[0]) + |remainder| * (8 + (8 + 8) + (0x10_0018 + MaxAppRequestSize())); { lemma_SeqSum2(val.a[0]); } SizeOfV(val.a[0].t[0]) + SizeOfV(val.a[0].t[1]) + |remainder| * (8 + (8 + 8) + (8 + ((0x10_0018 + MaxAppRequestSize())*RequestBatchSizeLimit()))); <= { lemma_VoteValValid(c.v[op], val.a[0].t[1]); lemma_VoteBound(c.v[op], val.a[0].t[1]); } 8 + (8 + 8) + 8 + ((0x10_0018 + MaxAppRequestSize())*|val.a[0].t[1].t[1].a|) + |remainder| * (8 + (8 + 8) + (8 + ((0x10_0018 + MaxAppRequestSize())*RequestBatchSizeLimit()))); <= { assert |val.a[0].t[1].t[1].a| <= RequestBatchSizeLimit(); lemma_mul_upper_bound(0x10_0018 + MaxAppRequestSize(), 0x10_0018 + MaxAppRequestSize(), |val.a[0].t[1].t[1].a|, RequestBatchSizeLimit());} 8 + (8 + 8) + 8 + ((0x10_0018 + MaxAppRequestSize())*RequestBatchSizeLimit()) + |remainder| * (8 + (8 + 8) + (8 + ((0x10_0018 + MaxAppRequestSize())*RequestBatchSizeLimit()))); 1*(8 + (8 + 8) + (8 + ((0x10_0018 + MaxAppRequestSize())*RequestBatchSizeLimit()))) + |remainder| * (8 + (8 + 8) + (8 + ((0x10_0018 + MaxAppRequestSize())*RequestBatchSizeLimit()))); { lemma_mul_is_distributive((8 + (8 + 8) + (8 + ((0x10_0018 + MaxAppRequestSize())*RequestBatchSizeLimit()))), 1, |remainder|); } (1+|remainder|) * (8 + (8 + 8) + (8 + ((0x10_0018 + MaxAppRequestSize())*RequestBatchSizeLimit()))); |c.v| * (8 + (8 + 8) + (8 + ((0x10_0018 + MaxAppRequestSize())*RequestBatchSizeLimit()))); } } } method MarshallMessage_Request(c:CMessage) returns (val:V) requires c.CMessage_Request? requires Marshallable(c) ensures ValInGrammar(val, CMessage_Request_grammar()) ensures ValidVal(val) ensures parse_Message_Request(val) == c { var v := MarshallCAppRequest(c.val); val := VTuple([VUint64(c.seqno), v]); } method MarshallMessage_1a(c:CMessage) returns (val:V) requires c.CMessage_1a? requires Marshallable(c) ensures ValInGrammar(val, CMessage_1a_grammar()) ensures ValidVal(val) ensures parse_Message_1a(val) == c { val := MarshallBallot(c.bal_1a); } method MarshallMessage_1b(c:CMessage) returns (val:V) requires c.CMessage_1b? requires Marshallable(c) ensures ValInGrammar(val, CMessage_1b_grammar()) ensures ValidVal(val) ensures parse_Message_1b(val) == c ensures 0 <= SizeOfV(val) < MaxPacketSize() - 8 { var bal := MarshallBallot(c.bal_1b); var log_truncation_point := MarshallOperationNumber(c.log_truncation_point); var votes := MarshallVotes(c.votes); val := VTuple([bal, log_truncation_point, votes]); // Prove the bound on SizeOfV(val) lemma_SeqSum3(val); assert ValInGrammar(val.t[0], CBallot_grammar()); // OBSERVE lemma_BallotBound(c.bal_1b, val.t[0]); assert ValInGrammar(val.t[1], COperationNumber_grammar()); // OBSERVE assert ValInGrammar(val.t[2], CVotes_grammar()); // OBSERVE calc { SizeOfV(val); 16 + 8 + SizeOfV(val.t[2]); <= 16 + 8 + 8 + (|c.votes.v| * (8 + (8 + 8) + (8 + (0x10_0018 + MaxAppRequestSize())*RequestBatchSizeLimit()))); 32 + (|c.votes.v| * (32 + (0x10_0018 + MaxAppRequestSize()) * 100)); < { lemma_mul_strict_inequality(|c.votes.v|, 8, (32 + (0x10_0018 + MaxAppRequestSize()) * 100)); } 32 + (8 * (32 + (0x10_0018 + MaxAppRequestSize()) * 100)); < MaxPacketSize() - 8; } } method MarshallMessage_2a(c:CMessage) returns (val:V) requires c.CMessage_2a? requires Marshallable_2a(c) ensures ValInGrammar(val, CMessage_2a_grammar()) ensures ValidVal(val) ensures parse_Message_2a(val) == c { var bal := MarshallBallot(c.bal_2a); var op := MarshallOperationNumber(c.opn_2a); var v := MarshallRequestBatch(c.val_2a); val := VTuple([bal, op, v]); assert forall u :: u in val.t ==> ValidVal(u); // OBSERVE assert ValInGrammar(bal, CMessage_2a_grammar().t[0]); // OBSERVE assert ValInGrammar(op, CMessage_2a_grammar().t[1]); // OBSERVE assert ValInGrammar(v, CMessage_2a_grammar().t[2]); // OBSERVE assert ValInGrammar(val, CMessage_2a_grammar()); // OBSERVE assert ValidVal(val); } method MarshallMessage_2b(c:CMessage) returns (val:V) requires c.CMessage_2b? requires Marshallable_2b(c) ensures ValInGrammar(val, CMessage_2b_grammar()) ensures ValidVal(val) ensures parse_Message_2b(val) == c { var bal := MarshallBallot(c.bal_2b); var op := MarshallOperationNumber(c.opn_2b); var v := MarshallRequestBatch(c.val_2b); val := VTuple([bal, op, v]); assert ValInGrammar(bal, CBallot_grammar()); // OBSERVE assert ValInGrammar(op, COperationNumber_grammar()); // OBSERVE assert ValInGrammar(v, CRequestBatch_grammar()); // OBSERVE assert ValInGrammar(val, CMessage_2b_grammar()); // OBSERVE } method MarshallMessage_Heartbeat(c:CMessage) returns (val:V) requires c.CMessage_Heartbeat? requires Marshallable(c) ensures ValInGrammar(val, CMessage_Heartbeat_grammar()) ensures ValidVal(val) ensures parse_Message_Heartbeat(val) == c { var ballot := MarshallBallot(c.bal_heartbeat); var op := MarshallOperationNumber(c.opn_ckpt); val := VTuple([ballot, VUint64(if c.suspicious then 1 else 0), op]); } method MarshallMessage_Reply(c:CMessage) returns (val:V) requires c.CMessage_Reply? requires Marshallable(c) ensures ValInGrammar(val, CMessage_Reply_grammar()) ensures ValidVal(val) ensures parse_Message_Reply(val) == c { var app_val := MarshallCAppReply(c.reply); val := VTuple([VUint64(c.seqno_reply), app_val]); } method MarshallMessage_AppStateRequest(c:CMessage) returns (val:V) requires c.CMessage_AppStateRequest? requires Marshallable(c) ensures ValInGrammar(val, CMessage_AppStateRequest_grammar()) ensures ValidVal(val) ensures parse_Message_AppStateRequest(val) == c { var ballot := MarshallBallot(c.bal_state_req); var opn := MarshallOperationNumber(c.opn_state_req); val := VTuple([ballot, opn]); } method MarshallMessage_AppStateSupply(c:CMessage) returns (val:V) requires c.CMessage_AppStateSupply? requires Marshallable(c) ensures ValInGrammar(val, CMessage_AppStateSupply_grammar()) ensures ValidVal(val) ensures parse_Message_AppStateSupply(val) == c ensures 0 <= SizeOfV(val) < MaxPacketSize() - 8 { var ballot := MarshallBallot(c.bal_state_supply); var opn_state_supply := MarshallOperationNumber(c.opn_state_supply); var app_state := MarshallCAppState(c.app_state); val := VTuple([ballot, opn_state_supply, app_state]); // Prove the bound on SizeOfV(val) lemma_SeqSum3(val); assert ValInGrammar(val.t[0], CBallot_grammar()); // OBSERVE lemma_BallotBound(c.bal_state_supply, val.t[0]); assert ValInGrammar(val.t[1], COperationNumber_grammar()); // OBSERVE assert ValInGrammar(val.t[2], GByteArray); // OBSERVE calc { SizeOfV(val); SizeOfV(val.t[0]) + SizeOfV(val.t[1]) + SizeOfV(val.t[2]); <= 16 + 16 + MaxAppStateSize(); < MaxPacketSize() - 8; } } method MarshallMessage_StartingPhase2(c:CMessage) returns (val:V) requires c.CMessage_StartingPhase2? requires Marshallable(c) ensures ValInGrammar(val, CMessage_StartingPhase2_grammar()) ensures ValidVal(val) ensures parse_Message_StartingPhase2(val) == c { var bal := MarshallBallot(c.bal_2); var op := MarshallOperationNumber(c.logTruncationPoint_2); val := VTuple([bal, op]); } method {:timeLimitMultiplier 2} MarshallMessage(c:CMessage) returns (val:V) requires Marshallable(c) ensures ValInGrammar(val, CMessage_grammar()) ensures ValidVal(val) ensures parse_Message(val) == c ensures c.CMessage_1b? ==> 0 <= SizeOfV(val) < MaxPacketSize() ensures c.CMessage_AppStateSupply? ==> 0 <= SizeOfV(val) < MaxPacketSize() { var start_time := Time.GetDebugTimeTicks(); assert !c.CMessage_Invalid?; if c.CMessage_Request? { var msg := MarshallMessage_Request(c); val := VCase(0, msg); var end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("MarshallMessage_Request", start_time, end_time); } else if c.CMessage_1a? { var msg := MarshallMessage_1a(c); val := VCase(1, msg); var end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("MarshallMessage_1a", start_time, end_time); } else if c.CMessage_1b? { var msg := MarshallMessage_1b(c); val := VCase(2, msg); var end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("MarshallMessage_1b", start_time, end_time); } else if c.CMessage_2a? { var msg := MarshallMessage_2a(c); val := VCase(3, msg); var end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("MarshallMessage_2a", start_time, end_time); } else if c.CMessage_2b? { var msg := MarshallMessage_2b(c); val := VCase(4, msg); var end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("MarshallMessage_2b", start_time, end_time); } else if c.CMessage_Heartbeat? { var msg := MarshallMessage_Heartbeat(c); val := VCase(5, msg); var end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("MarshallMessage_Heartbeat", start_time, end_time); } else if c.CMessage_Reply? { var msg := MarshallMessage_Reply(c); val := VCase(6, msg); assert CMessage_grammar().cases[6] == CMessage_Reply_grammar(); var end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("MarshallMessage_Reply", start_time, end_time); } else if c.CMessage_AppStateRequest? { var msg := MarshallMessage_AppStateRequest(c); val := VCase(7, msg); var end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("MarshallMessage_AppStateRequest", start_time, end_time); } else if c.CMessage_AppStateSupply? { var msg := MarshallMessage_AppStateSupply(c); val := VCase(8, msg); var end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("MarshallMessage_AppStateSupply", start_time, end_time); } else if c.CMessage_StartingPhase2? { var msg := MarshallMessage_StartingPhase2(c); val := VCase(9, msg); var end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("MarshallMessage_StartingPhase2", start_time, end_time); } // The following should work just as well as above, but it doesn't. Not sure why. // var msg:V; // match c // case CMessage_Request(_,_) => msg := MarshallMessage_Request(c); // case CMessage_1a(_) => msg := MarshallMessage_1a(c); assert ValInGrammar(msg, CMessage_1a_grammar()); // case CMessage_1b(_,_) => msg := MarshallMessage_1b(c); // case CMessage_2a(_,_,_) => msg := MarshallMessage_2a(c); // case CMessage_2b(_,_,_) => msg := MarshallMessage_2b(c); // case CMessage_Decision(_,_)=> msg := MarshallMessage_Decision(c); // // assert CMessage_grammar().cases[1] == CMessage_1a_grammar(); // // match c // case CMessage_Request(_,_) => val := VCase(0, msg); // case CMessage_1a(_) => val := VCase(1, msg); // case CMessage_1b(_,_) => val := VCase(2, msg); // case CMessage_2a(_,_,_) => val := VCase(3, msg); // case CMessage_2b(_,_,_) => val := VCase(4, msg); // case CMessage_Decision(_,_)=> val := VCase(5, msg); // } } lemma lemma_SeqSum2(val:V) requires val.VTuple? requires |val.t| == 2 ensures SizeOfV(val) == SizeOfV(val.t[0]) + SizeOfV(val.t[1]) { calc { SeqSum(val.t); { reveal SeqSum(); } SizeOfV(val.t[0]) + SeqSum(val.t[1..]); { reveal SeqSum(); } SizeOfV(val.t[0]) + SizeOfV(val.t[1]) + SeqSum(val.t[2..]); { assert val.t[2..] == []; } // OBSERVE SizeOfV(val.t[0]) + SizeOfV(val.t[1]) + SeqSum([]); { reveal SeqSum(); } SizeOfV(val.t[0]) + SizeOfV(val.t[1]); } } lemma lemma_SeqSum3(val:V) requires val.VTuple? requires |val.t| == 3 ensures SizeOfV(val) == SizeOfV(val.t[0]) + SizeOfV(val.t[1]) + SizeOfV(val.t[2]) { calc { SeqSum(val.t); { reveal SeqSum(); } SizeOfV(val.t[0]) + SeqSum(val.t[1..]); { reveal SeqSum(); } SizeOfV(val.t[0]) + SizeOfV(val.t[1]) + SeqSum(val.t[2..]); { reveal SeqSum(); } SizeOfV(val.t[0]) + SizeOfV(val.t[1]) + SizeOfV(val.t[2]) + SeqSum(val.t[3..]); { assert val.t[3..] == []; } // OBSERVE SizeOfV(val.t[0]) + SizeOfV(val.t[1]) + SizeOfV(val.t[2]) + SeqSum([]); { reveal SeqSum(); } SizeOfV(val.t[0]) + SizeOfV(val.t[1]) + SizeOfV(val.t[2]); } } lemma lemma_SeqSum4(val:V) requires val.VTuple? requires |val.t| == 4 ensures SizeOfV(val) == SizeOfV(val.t[0]) + SizeOfV(val.t[1]) + SizeOfV(val.t[2]) + SizeOfV(val.t[3]) { calc { SeqSum(val.t); { reveal SeqSum(); } SizeOfV(val.t[0]) + SeqSum(val.t[1..]); { reveal SeqSum(); } SizeOfV(val.t[0]) + SizeOfV(val.t[1]) + SeqSum(val.t[2..]); { reveal SeqSum(); } SizeOfV(val.t[0]) + SizeOfV(val.t[1]) + SizeOfV(val.t[2]) + SeqSum(val.t[3..]); { reveal SeqSum(); } SizeOfV(val.t[0]) + SizeOfV(val.t[1]) + SizeOfV(val.t[2]) + SizeOfV(val.t[3]) + SeqSum(val.t[4..]); { assert val.t[4..] == []; } // OBSERVE SizeOfV(val.t[0]) + SizeOfV(val.t[1]) + SizeOfV(val.t[2]) + SizeOfV(val.t[3]) + SeqSum([]); { reveal SeqSum(); } SizeOfV(val.t[0]) + SizeOfV(val.t[1]) + SizeOfV(val.t[2]) + SizeOfV(val.t[3]); } } lemma lemma_BallotBound(c:CBallot, val:V) requires ValInGrammar(val, CBallot_grammar()) requires ValidVal(val) requires parse_Ballot(val) == c ensures SizeOfV(val) == 16 { assert |val.t| == |CBallot_grammar().t| == 2; assert ValInGrammar(val.t[0], GUint64); assert ValInGrammar(val.t[1], GUint64); lemma_SeqSum2(val); assert SeqSum(val.t) == 16; } lemma lemma_CRequestBound(c:CRequest, val:V) requires ValInGrammar(val, CRequest_grammar()) requires ValidRequest(c) requires parse_Request(val) == c ensures SizeOfV(val) <= 0x10_0018 + MaxAppRequestSize() { ghost var gtuple := GTuple([EndPoint_grammar(), GUint64, GByteArray]); assert ValInGrammar(val, gtuple); lemma_SeqSum3(val); assert ValInGrammar(val.t[0], gtuple.t[0]); assert ValInGrammar(val.t[1], gtuple.t[1]); assert SizeOfV(val.t[0]) <= 0x10_0008; assert SizeOfV(val.t[1]) == 8; assert SizeOfV(val.t[2]) <= 8 + MaxAppRequestSize(); } lemma lemma_CRequestBatchBound(c:CRequestBatch, val:V) requires ValInGrammar(val, CRequestBatch_grammar()) requires ValidRequestBatch(c) requires parse_RequestBatch(val) == c decreases |c| ensures SeqSum(val.a) <= (0x10_0018 + MaxAppRequestSize())*|val.a| { //ghost var gtuple := GTuple([EndPoint_grammar(), GUint64, GByteArray]); ghost var garray := GArray(CRequest_grammar()); assert ValInGrammar(val, garray); reveal SeqSum(); if |val.a| == 0 { assert SeqSum(val.a) <= (0x10_0018 + MaxAppRequestSize())*|val.a|; } else { var req := parse_Request(val.a[0]); var restVal:V := VArray(val.a[1..]); var rest := parse_RequestBatch(restVal); assert c == [req] + rest; var x := 0x10_0018 + MaxAppRequestSize(); var N := |val.a|; lemma_CRequestBatchBound(rest, restVal); assert SeqSum(val.a[1..]) <= (x)*(N-1); lemma_CRequestBound(req, val.a[0]); assert SizeOfV(val.a[0]) <= x; assert SeqSum(val.a) == SizeOfV(val.a[0]) + SeqSum(val.a[1..]); assert |val.a| == |val.a[1..]| + 1; lemma_mul_is_distributive(x, N-1, 1); assert SeqSum(val.a) <= (x)*N; } } lemma lemma_ReplyBound(c:CReply, val:V) requires ValInGrammar(val, CReply_grammar()) requires ValidReply(c) requires parse_Reply(val) == c ensures SizeOfV(val) <= 0x10_0018 + MaxAppRequestSize() { ghost var gtuple := GTuple([EndPoint_grammar(), GUint64, GByteArray]); assert ValInGrammar(val, gtuple); lemma_SeqSum3(val); assert ValInGrammar(val.t[0], gtuple.t[0]); assert ValInGrammar(val.t[1], gtuple.t[1]); assert SizeOfV(val.t[0]) <= 0x10_0008; assert SizeOfV(val.t[1]) == 8; assert SizeOfV(val.t[2]) <= 8 + MaxAppRequestSize(); } lemma lemma_ReplyValValid(c:CReply, val:V) requires ValInGrammar(val, CReply_grammar()) requires ValidReply(c) requires parse_Reply(val) == c ensures ValidVal(val) { lemma_SeqSum3(val); assert ValInGrammar(val.t[0], EndPoint_grammar()); // OBSERVE assert ValInGrammar(val.t[1], GUint64); // OBSERVE assert ValInGrammar(val.t[2], GByteArray); // OBSERVE // Lots of OBSERVE below ghost var gtuple := GTuple([EndPoint_grammar(), GUint64, GByteArray]); assert ValInGrammar(val, gtuple); assert ValInGrammar(val.t[0], gtuple.t[0]); assert ValInGrammar(val.t[1], gtuple.t[1]); assert ValInGrammar(val.t[2], gtuple.t[2]); assert ValidVal(val.t[0]); assert ValidVal(val.t[1]); assert ValidVal(val.t[2]); } lemma {:timeLimitMultiplier 2} lemma_VoteValValid(c:CVote, val:V) requires ValInGrammar(val, CVote_grammar()) requires ValidVote(c) requires parse_Vote(val) == c ensures ValidVal(val) { lemma_SeqSum2(val); assert ValInGrammar(val.t[0], CBallot_grammar()); // OBSERVE assert ValInGrammar(val.t[1], CRequestBatch_grammar()); // OBSERVE lemma_BallotBound(c.max_value_bal, val.t[0]); lemma_CRequestBatchBound(c.max_val, val.t[1]); ghost var garray := GArray(CRequest_grammar()); assert ValInGrammar(val.t[1], garray); ghost var gtuple := GTuple([EndPoint_grammar(), GUint64, GByteArray]); forall i, v | 0 <= i < |val.t[1].a| && v == val.t[1].a[i] ensures ValidVal(v) { assert c.max_val[i] in c.max_val; // OBSERVE antecedent to determine that ValidRequest(c.max_val[i]) assert ValidRequest(c.max_val[i]); assert ValInGrammar(v, gtuple); assert ValInGrammar(v.t[0], gtuple.t[0]); assert ValInGrammar(v.t[1], gtuple.t[1]); assert ValInGrammar(v.t[2], gtuple.t[2]); assert |v.t[0].b| < 0x1_0000_0000_0000_0000; assert ValidVal(v.t[0]); assert ValidVal(v.t[1]); assert ValidVal(v.t[2]); assert ValidVal(v); } assert |val.t[1].a| == |c.max_val|; assert ValidVote(c); assert ValidRequestBatch(c.max_val); assert |c.max_val| < 0x1_0000_0000; assert |val.t[1].a| < 0x1_0000_0000_0000_0000; assert forall v :: v in val.t[1].a ==> ValidVal(v); calc ==> { true; ValidVal(val.t[0]); ValidVal(val.t[0]) && ValidVal(val.t[1]); ValidVal(val); } } lemma lemma_VoteBound(c:CVote, val:V) requires ValInGrammar(val, CVote_grammar()) requires ValInGrammar(val.t[1], CRequestBatch_grammar()) requires ValidVal(val) requires ValidVote(c) requires parse_Vote(val) == c ensures SizeOfV(val) <= (8 + 8) + 8 + ((0x10_0018 + MaxAppRequestSize())*|val.t[1].a|) { lemma_SeqSum2(val); assert ValInGrammar(val.t[0], CBallot_grammar()); // OBSERVE assert ValInGrammar(val.t[1], CRequestBatch_grammar()); // OBSERVE lemma_BallotBound(c.max_value_bal, val.t[0]); lemma_CRequestBatchBound(c.max_val, val.t[1]); } lemma lemma_MarshallableBound(c:CMessage, val:V) requires Marshallable(c) requires ValInGrammar(val, CMessage_grammar()) requires ValidVal(val) requires parse_Message(val) == c ensures !c.CMessage_1b? && !c.CMessage_AppStateSupply? ==> 0 <= SizeOfV(val) < MaxPacketSize() { assert !c.CMessage_Invalid?; if c.CMessage_Request? { lemma_SeqSum2(val.val); assert ValInGrammar(val.val.t[0], GUint64); // OBSERVE assert ValInGrammar(val.val.t[1], GByteArray); // OBSERVE } else if c.CMessage_1a? { assert ValInGrammar(val.val, CMessage_1a_grammar()); // OBSERVE assert ValInGrammar(val.val, CBallot_grammar()); // OBSERVE lemma_BallotBound(c.bal_1a, val.val); assert SizeOfV(val) == 24; /* We prove this case during marshalling } else if c.CMessage_1b? { */ } else if c.CMessage_2a? { lemma_SeqSum3(val.val); lemma_BallotBound(c.bal_2a, val.val.t[0]); assert SizeOfV(val.val.t[0]) == 16; assert ValInGrammar(val.val.t[1], GUint64); // OBSERVE assert SizeOfV(val.val.t[1]) == 8; assert ValInGrammar(val.val.t[2], CRequestBatch_grammar()); // OBSERVE //assert SizeOfV(val.val.t[2]) == 8 + |val.val.t[2].b| == 8 + |c.val_2a.v|; lemma_CRequestBatchBound(c.val_2a, val.val.t[2]); assert |val.val.t[2].a| == |c.val_2a|; assert |c.val_2a| <= RequestBatchSizeLimit(); calc { SizeOfV(val.val.t[2]); 8 + SeqSum(val.val.t[2].a); <= 8 + (0x10_0018 + MaxAppRequestSize())*|val.val.t[2].a|; <= { lemma_mul_is_commutative(|val.val.t[2].a|, RequestBatchSizeLimit()); lemma_mul_is_commutative(|val.val.t[2].a|, 0x10_0018 + MaxAppRequestSize()); lemma_mul_inequality(|val.val.t[2].a|, RequestBatchSizeLimit(), 0x10_0018 + MaxAppRequestSize()); } 8 + (0x10_0018 + MaxAppRequestSize())*RequestBatchSizeLimit(); } } else if c.CMessage_2b? { lemma_SeqSum3(val.val); lemma_BallotBound(c.bal_2b, val.val.t[0]); assert SizeOfV(val.val.t[0]) == 16; assert ValInGrammar(val.val.t[1], GUint64); // OBSERVE assert SizeOfV(val.val.t[1]) == 8; assert ValInGrammar(val.val.t[2], CRequestBatch_grammar()); // OBSERVE //assert SizeOfV(val.val.t[2]) == 8 + |val.val.t[2].b| == 8 + |c.val_2b.v|; lemma_CRequestBatchBound(c.val_2b, val.val.t[2]); calc { SizeOfV(val.val.t[2]); 8 + SeqSum(val.val.t[2].a); <= 8 + (0x10_0018 + MaxAppRequestSize())*|val.val.t[2].a|; <= { lemma_mul_is_commutative(|val.val.t[2].a|, RequestBatchSizeLimit()); lemma_mul_is_commutative(|val.val.t[2].a|, 0x10_0018 + MaxAppRequestSize()); lemma_mul_inequality(|val.val.t[2].a|, RequestBatchSizeLimit(), 0x10_0018 + MaxAppRequestSize()); } 8 + (0x10_0018 + MaxAppRequestSize())*RequestBatchSizeLimit(); } } else if c.CMessage_Heartbeat? { lemma_SeqSum3(val.val); assert ValInGrammar(val.val.t[0], CBallot_grammar()); // OBSERVE assert ValInGrammar(val.val.t[1], GUint64); // OBSERVE assert ValInGrammar(val.val.t[2], COperationNumber_grammar()); // OBSERVE lemma_BallotBound(c.bal_heartbeat, val.val.t[0]); } else if c.CMessage_Reply? { lemma_SeqSum2(val.val); assert ValInGrammar(val.val.t[0], GUint64); // OBSERVE assert ValInGrammar(val.val.t[1], GByteArray); // OBSERVE } else if c.CMessage_AppStateRequest? { lemma_SeqSum2(val.val); assert ValInGrammar(val.val.t[0], CBallot_grammar()); // OBSERVE assert ValInGrammar(val.val.t[1], COperationNumber_grammar()); // OBSERVE lemma_BallotBound(c.bal_state_req, val.val.t[0]); assert 0 <= SizeOfV(val) < MaxPacketSize(); // assert SizeOfV(val.val.t[0]) == 8; /* We prove this case during marshalling } else if c.CMessage_AppStateSupply? { */ } else if c.CMessage_StartingPhase2? { lemma_SeqSum2(val.val); assert ValInGrammar(val.val.t[0], CBallot_grammar()); // OBSERVE assert ValInGrammar(val.val.t[1], COperationNumber_grammar()); // OBSERVE lemma_BallotBound(c.bal_2, val.val.t[0]); } } //////////////////////////////////////////////////////////////////////// // These functions need to be here, rather than CMessageRefinements.i.dfy, // since they depend on PaxosDemarshallData //////////////////////////////////////////////////////////////////////// function AbstractifyBufferToRslPacket(src:EndPoint, dst:EndPoint, data:seq) : RslPacket requires EndPointIsValidPublicKey(src) requires EndPointIsValidPublicKey(dst) { LPacket(AbstractifyEndPointToNodeIdentity(dst), AbstractifyEndPointToNodeIdentity(src), AbstractifyCMessageToRslMessage(PaxosDemarshallData(data))) } predicate BufferRefinementAgreesWithMessageRefinement(msg:CMessage, marshalled:seq) requires CMessageIsAbstractable(msg) requires CMessageIsAbstractable(msg) { forall src, dst :: (EndPointIsValidPublicKey(src) && EndPointIsValidPublicKey(dst)) ==> (AbstractifyBufferToRslPacket(src, dst, marshalled) == LPacket(AbstractifyEndPointToNodeIdentity(dst), AbstractifyEndPointToNodeIdentity(src), AbstractifyCMessageToRslMessage(msg))) } function AbstractifyNetPacketToRslPacket(net:NetPacket) : RslPacket requires NetPacketIsAbstractable(net) { AbstractifyBufferToRslPacket(net.src, net.dst, net.msg) } predicate NetPacketIsAbstractable(net:NetPacket) { && EndPointIsValidPublicKey(net.src) && EndPointIsValidPublicKey(net.dst) } predicate NetPacketsIsAbstractable(netps:set) { forall p :: p in netps ==> NetPacketIsAbstractable(p) } lemma lemma_CMessageGrammarValid() ensures ValidGrammar(CMessage_grammar()) { var g := CMessage_grammar(); assert |g.cases| < 0x1_0000_0000_0000_0000; assert ValidGrammar(CMessage_Request_grammar()); assert ValidGrammar(CMessage_1a_grammar()); assert ValidGrammar(CMessage_1b_grammar()); assert ValidGrammar(CMessage_2a_grammar()); assert ValidGrammar(CMessage_2b_grammar()); assert ValidGrammar(CMessage_Heartbeat_grammar()); assert ValidGrammar(CMessage_Reply_grammar()); assert ValidGrammar(CMessage_AppStateRequest_grammar()); assert ValidGrammar(CMessage_AppStateSupply_grammar()); assert ValidGrammar(CMessage_StartingPhase2_grammar()); } method PaxosMarshall(msg:CMessage) returns (data:array) requires CMessageIsAbstractable(msg) requires Marshallable(msg) ensures fresh(data) ensures NetPacketBound(data[..]) ensures Marshallable(PaxosDemarshallData(data[..])) ensures BufferRefinementAgreesWithMessageRefinement(msg, data[..]) { var marshall_start_time := Time.GetDebugTimeTicks(); var val := MarshallMessage(msg); var marshall_end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("PaxosMarshall_MarshallMessage", marshall_start_time, marshall_end_time); lemma_MarshallableBound(msg, val); lemma_CMessageGrammarValid(); var generic_marshall_start_time := Time.GetDebugTimeTicks(); data := Marshall(val, CMessage_grammar()); var generic_marshall_end_time := Time.GetDebugTimeTicks(); assert !msg.CMessage_Invalid?; if msg.CMessage_Request? { RecordTimingSeq("GenericMarshallMessage_Request", generic_marshall_start_time, generic_marshall_end_time); } else if msg.CMessage_1a? { RecordTimingSeq("GenericMarshallMessage_1a", generic_marshall_start_time, generic_marshall_end_time); } else if msg.CMessage_1b? { RecordTimingSeq("GenericMarshallMessage_1b", generic_marshall_start_time, generic_marshall_end_time); } else if msg.CMessage_2a? { RecordTimingSeq("GenericMarshallMessage_2a", generic_marshall_start_time, generic_marshall_end_time); } else if msg.CMessage_2b? { RecordTimingSeq("GenericMarshallMessage_2b", generic_marshall_start_time, generic_marshall_end_time); } else if msg.CMessage_Heartbeat? { RecordTimingSeq("GenericMarshallMessage_Heartbeat", generic_marshall_start_time, generic_marshall_end_time); } else if msg.CMessage_Reply? { RecordTimingSeq("GenericMarshallMessage_Reply", generic_marshall_start_time, generic_marshall_end_time); } else if msg.CMessage_AppStateRequest? { RecordTimingSeq("GenericMarshallMessage_AppStateRequest", generic_marshall_start_time, generic_marshall_end_time); } else if msg.CMessage_AppStateSupply? { RecordTimingSeq("GenericMarshallMessage_AppStateSupply", generic_marshall_start_time, generic_marshall_end_time); } else if msg.CMessage_StartingPhase2? { RecordTimingSeq("GenericMarshallMessage_StartingPhase2", generic_marshall_start_time, generic_marshall_end_time); } forall src, dst | EndPointIsValidPublicKey(src) && EndPointIsValidPublicKey(dst) ensures AbstractifyBufferToRslPacket(src, dst, data[..]) == LPacket(AbstractifyEndPointToNodeIdentity(dst), AbstractifyEndPointToNodeIdentity(src), AbstractifyCMessageToRslMessage(msg)); { calc { AbstractifyBufferToRslPacket(src, dst, data[..]); LPacket(AbstractifyEndPointToNodeIdentity(dst), AbstractifyEndPointToNodeIdentity(src), AbstractifyCMessageToRslMessage(PaxosDemarshallData(data[..]))); LPacket(AbstractifyEndPointToNodeIdentity(dst), AbstractifyEndPointToNodeIdentity(src), AbstractifyCMessageToRslMessage(PaxosDemarshallData(data[..]))); LPacket(AbstractifyEndPointToNodeIdentity(dst), AbstractifyEndPointToNodeIdentity(src), AbstractifyCMessageToRslMessage(msg)); } } } ////////////////////////////////////////////////////////////////////////////// // Sendable predicates predicate CPacketIsSendable(cpacket:CPacket) { && CMessageIsValid(cpacket.msg) && CPacketIsAbstractable(cpacket) && EndPointIsValidPublicKey(cpacket.src) } predicate CPacketSetIsSendable(cps:set) { forall p :: p in cps ==> CPacketIsSendable(p) } predicate CPacketSeqIsValid(cps:seq) { && CPacketSeqIsAbstractable(cps) && |cps| < 0xFFFF_FFFF_FFFF_FFFF && forall i :: 0<=i<|cps| ==> CPacketIsSendable(cps[i]) } predicate CBroadcastIsValid(broadcast:CBroadcast) { && CBroadcastIsAbstractable(broadcast) && (broadcast.CBroadcast? ==> && Marshallable(broadcast.msg) && 0 <= |broadcast.dsts| < 0xFFFF_FFFF_FFFF_FFFF) } predicate OutboundPacketsIsValid(out:OutboundPackets) { match out case Broadcast(broadcast) => CBroadcastIsValid(broadcast) case OutboundPacket(p) => p.Some? ==> CPacketIsSendable(p.v) case PacketSequence(s) => |s| < 0xFFFF_FFFF_FFFF_FFFF && (forall p :: p in s ==> CPacketIsSendable(p)) // case OutboundPacket(Some(p)) => CPacketIsSendable(p) // case OutboundPacket(None) => true } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/RSL/ParametersState.i.dfy ================================================ include "../../Common/Native/NativeTypes.s.dfy" include "../../Protocol/RSL/Parameters.i.dfy" include "../Common/UpperBound.i.dfy" module LiveRSL__ParametersState_i { import opened Native__NativeTypes_s import opened LiveRSL__Parameters_i import opened Common__UpperBound_i import opened Common__UpperBound_s datatype ParametersState = ParametersState( max_log_length:uint64, baseline_view_timeout_period:uint64, heartbeat_period:uint64, max_integer_val:uint64, max_batch_size:uint64, max_batch_delay:uint64) function AbstractifyParametersStateToLParameters(params:ParametersState) : LParameters { LParameters(params.max_log_length as int, params.baseline_view_timeout_period as int, params.heartbeat_period as int, UpperBoundFinite(params.max_integer_val as int), params.max_batch_size as int, params.max_batch_delay as int) } function method StaticParams() : ParametersState { ParametersState(7, // max log length 1000, // baseline view timeout period (1000 ms = 1 sec) 100, // heartbeat period (100 ms) 0x8000_0000_0000_0000 - 1, // Max integer value: 2^63 - 1 32, // max_batch_size 10) // max_batch_delay (10 ms) } predicate WFParametersState(params:ParametersState) { && params.max_integer_val > params.max_log_length > 0 && params.max_integer_val > params.max_batch_delay && params.max_integer_val < 0x8000_0000_0000_0000 && params.baseline_view_timeout_period > 0 && params.heartbeat_period > 0 && params.max_batch_size > 0 } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/RSL/PaxosWorldState.i.dfy ================================================ include "CPaxosConfiguration.i.dfy" module LiveRSL__PaxosWorldState_i { import opened LiveRSL__CPaxosConfiguration_i import opened Native__NativeTypes_s ////////////////////////////////////////////////////////////////////////////// // World // TODO jonh thinks this object should be deprecated. datatype ActionStatus = Ok | Ignore | Fail function method f_max_uint64() : uint64 { 0xffff_ffff_ffff_ffff } datatype PaxosWorldState = PaxosWorldState(good:bool, config:CPaxosConfiguration) predicate PaxosWorldIsValid(world:PaxosWorldState) { && world.good && CPaxosConfigurationIsValid(world.config) } method UpdatePaxosWorld(world:PaxosWorldState, status:ActionStatus) returns (world':PaxosWorldState) ensures !status.Fail? ==> world' == world { if (status.Fail?) { world' := world.(good := false); } else { world' := world; } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/RSL/ProposerLemmas.i.dfy ================================================ include "ProposerState.i.dfy" module LiveRSL__ProposerLemmas_i { import opened Native__Io_s import opened LiveRSL__CMessage_i import opened LiveRSL__CMessageRefinements_i import opened LiveRSL__CTypes_i import opened LiveRSL__Proposer_i import opened LiveRSL__ProposerState_i import opened Collections__Sets_i import opened Common__SeqIsUnique_i predicate SetOfMessage1b(S:set) { forall p :: p in S ==> p.msg.CMessage_1b? } predicate SetOfMessage1bAboutBallot(S:set, b:CBallot) { && SetOfMessage1b(S) && (forall p :: p in S ==> p.msg.bal_1b == b) } predicate IsAfterLogTruncationPoint(opn:COperationNumber, received_1b_packets:set) { forall p :: p in received_1b_packets && p.msg.CMessage_1b? ==> p.msg.log_truncation_point.n <= opn.n } predicate AllAcceptorsHadNoProposal(S:set, opn:COperationNumber) requires SetOfMessage1b(S) { forall p :: p in S ==> !(opn in p.msg.votes.v) } lemma lemma_AbstractifySetOfCPacketsToSetOfRslPackets_propertiesProposer(cps:set) requires CPacketsIsAbstractable(cps) ensures SetOfInjectiveTypeCPackets(cps) ==> |cps| == |AbstractifySetOfCPacketsToSetOfRslPackets(cps)| ensures AbstractifySetOfCPacketsToSetOfRslPackets({}) == {} ensures SetOfMessage1b(cps) ==> LSetOfMessage1b(AbstractifySetOfCPacketsToSetOfRslPackets(cps)) ensures forall bal :: CBallotIsAbstractable(bal) ==> SetOfMessage1bAboutBallot(cps, bal) ==> LSetOfMessage1bAboutBallot(AbstractifySetOfCPacketsToSetOfRslPackets(cps), AbstractifyCBallotToBallot(bal)) ensures forall opn {:trigger LIsAfterLogTruncationPoint(AbstractifyCOperationNumberToOperationNumber(opn), AbstractifySetOfCPacketsToSetOfRslPackets(cps))}{:trigger IsAfterLogTruncationPoint(opn, cps)} :: COperationNumberIsAbstractable(opn) ==> IsAfterLogTruncationPoint(opn, cps) == LIsAfterLogTruncationPoint(AbstractifyCOperationNumberToOperationNumber(opn), AbstractifySetOfCPacketsToSetOfRslPackets(cps)) ensures SetOfMessage1b(cps) ==> (forall opn {:trigger LAllAcceptorsHadNoProposal(AbstractifySetOfCPacketsToSetOfRslPackets(cps), AbstractifyCOperationNumberToOperationNumber(opn))}{:trigger AllAcceptorsHadNoProposal(cps, opn)} :: COperationNumberIsAbstractable(opn) ==> AllAcceptorsHadNoProposal(cps, opn) == LAllAcceptorsHadNoProposal(AbstractifySetOfCPacketsToSetOfRslPackets(cps), AbstractifyCOperationNumberToOperationNumber(opn))) { lemma_AbstractifySetOfCPacketsToSetOfRslPackets_properties(cps); if SetOfInjectiveTypeCPackets(cps) { lemma_AbstractifySetOfCPacketsToSetOfRslPackets_cardinality(cps); } reveal AbstractifySetOfCPacketsToSetOfRslPackets(); forall opn | COperationNumberIsAbstractable(opn) ensures !IsAfterLogTruncationPoint(opn, cps) ==> !LIsAfterLogTruncationPoint(AbstractifyCOperationNumberToOperationNumber(opn), AbstractifySetOfCPacketsToSetOfRslPackets(cps)) { if !IsAfterLogTruncationPoint(opn, cps) { //if |cps| > 0 && (exists p :: p in cps && p.msg.CMessage_1b?) var p :| p in cps && p.msg.CMessage_1b? && p.msg.log_truncation_point.n > opn.n; var ref_p := AbstractifyCPacketToRslPacket(p); assert ref_p in AbstractifySetOfCPacketsToSetOfRslPackets(cps); assert ref_p.msg.RslMessage_1b?; assert ref_p.msg.log_truncation_point > AbstractifyCOperationNumberToOperationNumber(opn); } } if SetOfMessage1b(cps) { var ref_cps := AbstractifySetOfCPacketsToSetOfRslPackets(cps); forall opn | COperationNumberIsAbstractable(opn) ensures AllAcceptorsHadNoProposal(cps, opn) ==> LAllAcceptorsHadNoProposal(ref_cps, AbstractifyCOperationNumberToOperationNumber(opn)) { var ref_opn := AbstractifyCOperationNumberToOperationNumber(opn); if AllAcceptorsHadNoProposal(cps, opn) { forall rp | rp in ref_cps ensures !(ref_opn in rp.msg.votes) { reveal AbstractifyCVotesToVotes(); var p :| p in cps && rp == AbstractifyCPacketToRslPacket(p); if ref_opn in rp.msg.votes { assert opn in p.msg.votes.v; assert false; } } } } forall opn | COperationNumberIsAbstractable(opn) ensures !AllAcceptorsHadNoProposal(cps, opn) ==> !LAllAcceptorsHadNoProposal(ref_cps, AbstractifyCOperationNumberToOperationNumber(opn)) { var ref_opn := AbstractifyCOperationNumberToOperationNumber(opn); if !AllAcceptorsHadNoProposal(cps, opn) { assert !(forall p :: p in cps ==> !(opn in p.msg.votes.v)); var p :| p in cps && opn in p.msg.votes.v; var ref_p := AbstractifyCPacketToRslPacket(p); reveal AbstractifyCVotesToVotes(); assert ref_p in ref_cps; } } } // calc ==> { // SetOfMessage1b(cps); // { reveal AbstractifySetOfCPacketsToSetOfRslPackets(); } // LSetOfMessage1b(AbstractifySetOfCPacketsToSetOfRslPackets(cps)); // } // calc ==> { // true; // { reveal AbstractifySetOfCPacketsToSetOfRslPackets(); } // AbstractifySetOfCPacketsToSetOfRslPackets({}) == {}; // } } // Name this accessor for the proof below function PacketSrc(pkt:CPacket) : EndPoint { pkt.src } lemma lemma_Received1bBound(proposer:ProposerState) requires ProposerIsValid(proposer) ensures |proposer.received_1b_packets| < 0xFFFF_FFFF_FFFF_FFFF { var srcs := set pkt | pkt in proposer.received_1b_packets :: PacketSrc(pkt); reveal Received1bProperties(); lemma_MapSetCardinalityOver(proposer.received_1b_packets, srcs, PacketSrc); assert |srcs| == |proposer.received_1b_packets|; var replicas := UniqueSeqToSet(proposer.constants.all.config.replica_ids); lemma_seqs_set_cardinality(proposer.constants.all.config.replica_ids, replicas); SubsetCardinality(srcs, replicas); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/RSL/ProposerModel.i.dfy ================================================ include "AppInterface.i.dfy" include "ProposerState.i.dfy" include "ElectionModel.i.dfy" include "Broadcast.i.dfy" include "MinCQuorumSize.i.dfy" include "ProposerLemmas.i.dfy" include "../Common/Util.i.dfy" include "../../Common/Collections/Sets.i.dfy" module LiveRSL__ProposerModel_i { import opened Native__Io_s import opened Native__NativeTypes_s import opened LiveRSL__AppInterface_i import opened LiveRSL__Broadcast_i import opened LiveRSL__CMessage_i import opened LiveRSL__CMessageRefinements_i import opened LiveRSL__Configuration_i import opened LiveRSL__ConstantsState_i import opened LiveRSL__CPaxosConfiguration_i import opened LiveRSL__CTypes_i import opened LiveRSL__Election_i import opened LiveRSL__ElectionModel_i import opened LiveRSL__ElectionState_i import opened LiveRSL__Message_i import opened LiveRSL__MinCQuorumSize_i import opened LiveRSL__PacketParsing_i import opened LiveRSL__Proposer_i import opened LiveRSL__ProposerLemmas_i import opened LiveRSL__ProposerState_i import opened LiveRSL__ReplicaConstantsState_i import opened LiveRSL__Types_i import opened Impl__LiveRSL__Broadcast_i import opened Collections__Maps_i import opened Collections__Sets_i import opened Common__NodeIdentity_i import opened Common__SeqIsUnique_i import opened Common__SeqIsUniqueDef_i import opened Common__NetClient_i import opened Common__UpperBound_s import opened Common__UpperBound_i import opened Common__Util_i import opened AppStateMachine_s // Same as x == y, but triggers extensional equality on fields and provides better error diagnostics predicate Eq_LProposer(x:LProposer, y:LProposer) { && x.constants == y.constants && x.current_state == y.current_state && x.request_queue == y.request_queue && x.max_ballot_i_sent_1a == y.max_ballot_i_sent_1a && x.next_operation_number_to_propose == y.next_operation_number_to_propose && x.received_1b_packets == y.received_1b_packets && x.highest_seqno_requested_by_client_this_view == y.highest_seqno_requested_by_client_this_view && x.election_state == y.election_state } method InitProposerState(constants:ReplicaConstantsState) returns (proposer:ProposerState, cur_req_set:MutableSet, prev_req_set:MutableSet) requires ReplicaConstantsState_IsValid(constants) ensures ProposerIsAbstractable(proposer) ensures WellFormedLConfiguration(AbstractifyReplicaConstantsStateToLReplicaConstants(constants).all.config) ensures ProposerIsValid(proposer) ensures LProposerInit(AbstractifyProposerStateToLProposer(proposer), AbstractifyReplicaConstantsStateToLReplicaConstants(constants)) ensures proposer.constants == constants ensures fresh(cur_req_set) && fresh(prev_req_set) && cur_req_set != prev_req_set ensures MutableSet.SetOf(cur_req_set) == proposer.election_state.cur_req_set ensures MutableSet.SetOf(prev_req_set) == proposer.election_state.prev_req_set { var election; election, cur_req_set, prev_req_set := InitElectionState(constants); proposer := ProposerState(constants, 0, [], CBallot(0, constants.my_index), 0, {}, map [], CIncompleteBatchTimerOff(), election, COperationNumber(0), COperationNumber(0)); ghost var ref_proposer := AbstractifyProposerStateToLProposer(proposer); ghost var ref_constants := AbstractifyReplicaConstantsStateToLReplicaConstants(constants); forall ensures SeqIsUnique(proposer.request_queue) { reveal SeqIsUnique(); } forall ensures Received1bProperties(proposer.received_1b_packets, proposer.constants) { reveal Received1bProperties(); } lemma_AbstractifySetOfCPacketsToSetOfRslPackets_propertiesProposer(proposer.received_1b_packets); // Some subset of below is an OBSERVE? assert ref_proposer.constants == ref_constants; assert ref_proposer.current_state == 0; assert ref_proposer.request_queue == []; assert ref_proposer.max_ballot_i_sent_1a == Ballot(0, ref_constants.my_index); assert ref_proposer.next_operation_number_to_propose == 0; assert ref_proposer.received_1b_packets == {}; lemma_AbstractifyMapOfSeqNums_properties(proposer.highest_seqno_requested_by_client_this_view); assert ElectionStateInit(ref_proposer.election_state, ref_constants); } //function method maprange_impl(m:map) : set //{ // set k | k in m :: m[k] //} method {:timeLimitMultiplier 2} ProposerProcessRequest(proposer:ProposerState, packet:CPacket, cur_req_set:MutableSet, prev_req_set:MutableSet) returns (proposer':ProposerState) requires ProposerIsValid(proposer) requires CPacketIsAbstractable(packet) requires packet.msg.CMessage_Request? requires CAppRequestMarshallable(packet.msg.val) requires cur_req_set != prev_req_set requires MutableSet.SetOf(cur_req_set) == proposer.election_state.cur_req_set requires MutableSet.SetOf(prev_req_set) == proposer.election_state.prev_req_set modifies cur_req_set ensures ProposerIsValid(proposer') ensures LProposerProcessRequest(AbstractifyProposerStateToLProposer(proposer), AbstractifyProposerStateToLProposer(proposer'), AbstractifyCPacketToRslPacket(packet)) ensures proposer.constants == proposer'.constants ensures MutableSet.SetOf(cur_req_set) == proposer'.election_state.cur_req_set ensures MutableSet.SetOf(prev_req_set) == proposer'.election_state.prev_req_set { ghost var ref_proposer := AbstractifyProposerStateToLProposer(proposer); ghost var r_proposer; ghost var r_packet := AbstractifyCPacketToRslPacket(packet); var val := CRequest(packet.src, packet.msg.seqno, packet.msg.val); //var election_start_time := Time.GetDebugTimeTicks(); var newElectionState := ElectionReflectReceivedRequest(proposer.election_state, val, cur_req_set, prev_req_set); //var election_end_time := Time.GetDebugTimeTicks(); //RecordTimingSeq("ProposerProcessRequest_Election", election_start_time, election_end_time); ghost var ref_val := AbstractifyCRequestToRequest(val); ghost var ref_myOutstandingProposedValues := AbstractifyMapOfSeqNums(proposer.highest_seqno_requested_by_client_this_view); lemma_AbstractifyMapOfSeqNums_properties(proposer.highest_seqno_requested_by_client_this_view); assert forall e :: (e !in proposer.highest_seqno_requested_by_client_this_view && EndPointIsValidPublicKey(e) ==> AbstractifyEndPointToNodeIdentity(e) !in AbstractifyMapOfSeqNums(proposer.highest_seqno_requested_by_client_this_view)); assert EndPointIsValidPublicKey(packet.src); assert packet.src !in proposer.highest_seqno_requested_by_client_this_view ==> AbstractifyEndPointToNodeIdentity(packet.src) !in AbstractifyMapOfSeqNums(proposer.highest_seqno_requested_by_client_this_view); assert packet.src in proposer.highest_seqno_requested_by_client_this_view ==> (packet.msg.seqno > proposer.highest_seqno_requested_by_client_this_view[packet.src] <==> r_packet.msg.seqno_req > ref_proposer.highest_seqno_requested_by_client_this_view[r_packet.src]); //var lookup_start_time := Time.GetDebugTimeTicks(); if proposer.current_state != 0 && (packet.src !in proposer.highest_seqno_requested_by_client_this_view || packet.msg.seqno > proposer.highest_seqno_requested_by_client_this_view[packet.src]) { // var lookup_end_time := Time.GetDebugTimeTicks(); // RecordTimingSeq("ProposerProcessRequest_Lookup", lookup_start_time, lookup_end_time); //print("Processing request with seqno ", packet.msg.seqno, ". Inside if .\n"); assert r_packet.src !in ref_proposer.highest_seqno_requested_by_client_this_view || r_packet.msg.seqno_req > ref_proposer.highest_seqno_requested_by_client_this_view[r_packet.src]; //var map_update_start_time := Time.GetDebugTimeTicks(); var new_seqno_map := proposer.highest_seqno_requested_by_client_this_view[packet.src := packet.msg.seqno]; //var map_update_end_time := Time.GetDebugTimeTicks(); //RecordTimingSeq("ProposerProcessRequest_MapUpdate", map_update_start_time, map_update_end_time); //var proposer_update_start_time := Time.GetDebugTimeTicks(); proposer' := proposer.(election_state := newElectionState, request_queue := proposer.request_queue + [val], highest_seqno_requested_by_client_this_view := new_seqno_map); //var proposer_update_end_time := Time.GetDebugTimeTicks(); lemma_AbstractifyMapOfSeqNums_properties(new_seqno_map); r_proposer := ref_proposer.(election_state := AbstractifyCElectionStateToElectionState(newElectionState), request_queue := ref_proposer.request_queue + [ref_val], highest_seqno_requested_by_client_this_view := ref_proposer.highest_seqno_requested_by_client_this_view [r_packet.src := r_packet.msg.seqno_req]); ghost var ref_proposer' := AbstractifyProposerStateToLProposer(proposer'); assert Eq_LProposer(r_proposer, ref_proposer'); assert LProposerProcessRequest(ref_proposer, r_proposer, r_packet); //RecordTimingSeq("ProposerProcessRequest_ProposerUpdate", proposer_update_start_time, proposer_update_end_time); } else { //var lookup_end_time := Time.GetDebugTimeTicks(); //RecordTimingSeq("ProposerProcessRequest_Lookup", lookup_start_time, lookup_end_time); //print("Processing request with seqno ", packet.msg.seqno, ". Inside else.\n"); proposer' := proposer.(election_state := newElectionState); r_proposer := ref_proposer.(election_state := AbstractifyCElectionStateToElectionState(newElectionState)); ghost var ref_proposer' := AbstractifyProposerStateToLProposer(proposer'); assert Eq_LProposer(r_proposer, ref_proposer'); assert LProposerProcessRequest(ref_proposer, r_proposer, r_packet); } } method ProposerMaybeEnterNewViewAndSend1a(proposer:ProposerState) returns (proposer':ProposerState, sent_packets:CBroadcast) requires ProposerIsValid(proposer) ensures ProposerIsValid(proposer') ensures CBroadcastIsValid(sent_packets) ensures OutboundPacketsHasCorrectSrc(Broadcast(sent_packets), proposer.constants.all.config.replica_ids[proposer.constants.my_index]) ensures LProposerMaybeEnterNewViewAndSend1a(AbstractifyProposerStateToLProposer(proposer), AbstractifyProposerStateToLProposer(proposer'), AbstractifyCBroadcastToRlsPacketSeq(sent_packets)) ensures proposer.constants == proposer'.constants ensures proposer'.election_state.cur_req_set == proposer.election_state.cur_req_set ensures proposer'.election_state.prev_req_set == proposer.election_state.prev_req_set { var start_time := Time.GetDebugTimeTicks(); ghost var ref_proposer := AbstractifyProposerStateToLProposer(proposer); //lemma_ProposerId(proposer); var lt := CBalLt(proposer.max_ballot_i_sent_1a, proposer.election_state.current_view); if proposer.election_state.current_view.proposer_id == proposer.constants.my_index && lt { //print "Proposer becoming leader of ballot ", proposer.election_state.current_view, "\n"; lemma_AbstractifyCRequestsSeqToRequestsSeq_concat(proposer.election_state.requests_received_prev_epochs, proposer.election_state.requests_received_this_epoch); assert RequestQueueValid(proposer.election_state.requests_received_prev_epochs); assert RequestQueueValid(proposer.election_state.requests_received_this_epoch); var new_requestQueue := proposer.election_state.requests_received_prev_epochs + proposer.election_state.requests_received_this_epoch; assert |new_requestQueue| == |proposer.election_state.requests_received_prev_epochs| + |proposer.election_state.requests_received_this_epoch|; proposer' := proposer.(current_state := 1, max_ballot_i_sent_1a := proposer.election_state.current_view, received_1b_packets := {}, highest_seqno_requested_by_client_this_view := map[], request_queue := new_requestQueue); forall ensures Received1bProperties(proposer'.received_1b_packets, proposer.constants) { reveal Received1bProperties(); } var msg := CMessage_1a(proposer.election_state.current_view); assert Marshallable(msg); assert CPaxosConfigurationIsValid(proposer.constants.all.config); sent_packets := BuildBroadcastToEveryone(proposer.constants.all.config, proposer.constants.my_index, msg); lemma_AbstractifySetOfCPacketsToSetOfRslPackets_propertiesProposer(proposer.received_1b_packets); // Some subset of the below is an OBSERVE ghost var ref_proposer' := AbstractifyProposerStateToLProposer(proposer'); assert ref_proposer'.current_state == 1; assert ref_proposer'.max_ballot_i_sent_1a == ref_proposer.election_state.current_view; assert ref_proposer'.received_1b_packets == {}; lemma_AbstractifyMapOfSeqNums_properties(proposer'.highest_seqno_requested_by_client_this_view); assert LBroadcastToEveryone(ref_proposer.constants.all.config, ref_proposer.constants.my_index, RslMessage_1a(ref_proposer.election_state.current_view), AbstractifyCBroadcastToRlsPacketSeq(sent_packets)); var end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("ProposerMaybeEnterNewViewAndSend1a_work", start_time, end_time); } else { proposer' := proposer; sent_packets := CBroadcastNop; var end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("ProposerMaybeEnterNewViewAndSend1a_nada", start_time, end_time); } } method ProposerProcess1b(proposer:ProposerState, packet:CPacket) returns (proposer':ProposerState) requires ProposerIsValid(proposer) requires proposer.current_state == 1 requires EndPointIsValidPublicKey(packet.src) requires packet.src in proposer.constants.all.config.replica_ids requires packet.msg.CMessage_1b? requires packet.msg.bal_1b == proposer.max_ballot_i_sent_1a requires ValidVotes(packet.msg.votes) requires CPacketIsAbstractable(packet) requires forall other_packet :: other_packet in proposer.received_1b_packets ==> other_packet.src != packet.src ensures ProposerIsValid(proposer') ensures forall other_packet :: other_packet in AbstractifyProposerStateToLProposer(proposer).received_1b_packets ==> other_packet.src != AbstractifyCPacketToRslPacket(packet).src ensures LProposerProcess1b(AbstractifyProposerStateToLProposer(proposer), AbstractifyProposerStateToLProposer(proposer'), AbstractifyCPacketToRslPacket(packet)) ensures proposer.constants == proposer'.constants ensures proposer'.election_state.cur_req_set == proposer.election_state.cur_req_set ensures proposer'.election_state.prev_req_set == proposer.election_state.prev_req_set { //print("Proposer processing a 1b message about ballot", packet.msg.bal_1b, "\n"); proposer' := proposer.(received_1b_packets := proposer.received_1b_packets + { packet }); // Prove Received1bProperties reveal Received1bProperties(); forall p | p in proposer'.received_1b_packets ensures p.src in proposer.constants.all.config.replica_ids { if p in proposer.received_1b_packets { assert p.src in proposer.constants.all.config.replica_ids; } else { assert p == packet && packet.src in proposer.constants.all.config.replica_ids; } } forall p1,p2 | p1 in proposer'.received_1b_packets && p2 in proposer'.received_1b_packets && p1.src == p2.src ensures p1 == p2 { if p1 in proposer.received_1b_packets && p2 in proposer.received_1b_packets { assert p1 == p2; } else if p1 in proposer.received_1b_packets { assert p2 == packet; assert p2.src != p1.src; assert false; } else if p2 in proposer.received_1b_packets { assert p1 == packet; assert p2.src != p1.src; assert false; } else { assert p1 == packet == p2; } } ghost var ref_proposer := AbstractifyProposerStateToLProposer(proposer); ghost var ref_proposer' := AbstractifyProposerStateToLProposer(proposer'); ghost var ref_packet := AbstractifyCPacketToRslPacket(packet); calc { ref_proposer'.received_1b_packets; { reveal AbstractifySetOfCPacketsToSetOfRslPackets(); } ref_proposer.received_1b_packets + { ref_packet }; } //assert ref_proposer'.received_1b_packets == ref_proposer.received_1b_packets + { ref_packet }; lemma_AbstractifySetOfCPacketsToSetOfRslPackets_srcMembership(proposer.received_1b_packets, packet.src); } lemma lemma_MapSingleton(m:map, elm:T) requires |m| == 1 requires elm in m ensures forall x :: x in m ==> x == elm { var empty := RemoveElt(m, elm); } method getMaxOpnWithProposalFromSingleton(m:map) returns (maxOpn:COperationNumber) requires |m| > 0 ensures forall opn :: opn in m ==> opn.n <= maxOpn.n { if |m| == 1 { var opn :| opn in m; lemma_MapSingleton(m, opn); assert forall op :: op in m ==> op == opn; maxOpn := opn; } else { var opn :| opn in m; var rest := RemoveElt(m, opn); var restMax:COperationNumber; restMax := getMaxOpnWithProposalFromSingleton(rest); if (restMax.n > opn.n) { maxOpn := restMax; } else { maxOpn := opn; } } } method getMaxOpnWithProposalFromSet(s:set) returns (maxOpn:COperationNumber, foundNonEmpty:bool) requires forall p :: p in s ==> p.msg.CMessage_1b? && ValidVotes(p.msg.votes) requires |s| > 0 ensures forall p :: p in s ==> (forall opn :: opn in p.msg.votes.v ==> opn.n <= maxOpn.n) ensures foundNonEmpty <==> exists p :: p in s && |p.msg.votes.v| > 0 { if |s| == 1 { var p :| p in s; assert p.msg.CMessage_1b?; forall q | q in s ensures q == p { ThingsIKnowAboutASingletonSet(s, q, p); } if (|p.msg.votes.v| > 0) { maxOpn := getMaxOpnWithProposalFromSingleton(p.msg.votes.v); foundNonEmpty := true; } else { maxOpn := COperationNumber(0); foundNonEmpty := false; } } else { var p :| p in s; var rest := s - {p}; var candidateOpn; var foundLocal:bool; if (|p.msg.votes.v| > 0) { candidateOpn := getMaxOpnWithProposalFromSingleton(p.msg.votes.v); foundLocal := true; assert forall opn :: opn in p.msg.votes.v ==> opn.n <= candidateOpn.n; } else { candidateOpn := COperationNumber(0); foundLocal := false; } forall x | x in rest ensures x.msg.CMessage_1b? && ValidVotes(x.msg.votes) { assert x in s; assert forall q :: q in s ==> q.msg.CMessage_1b? && ValidVotes(q.msg.votes); } var restMaxOpn, foundTemp := getMaxOpnWithProposalFromSet(rest); if (foundTemp || foundLocal) { foundNonEmpty := true; } else { foundNonEmpty := false; } if candidateOpn.n > restMaxOpn.n { maxOpn := candidateOpn; } else { maxOpn := restMaxOpn; } } } method getMaxLogTruncationPoint(s:set) returns (maxLogTruncationPoint:COperationNumber) requires forall p :: p in s ==> p.msg.CMessage_1b? requires |s| > 0 ensures forall p :: p in s ==> p.msg.log_truncation_point.n <= maxLogTruncationPoint.n { if |s| == 1 { var p :| p in s; assert p.msg.CMessage_1b?; forall q | q in s ensures q == p { ThingsIKnowAboutASingletonSet(s, q, p); } maxLogTruncationPoint := p.msg.log_truncation_point; } else { var p :| p in s; var rest := s - {p}; var candidateOpn := p.msg.log_truncation_point; forall x | x in rest ensures x.msg.CMessage_1b? { assert x in s; assert forall q :: q in s ==> q.msg.CMessage_1b?; } var restMaxOpn := getMaxLogTruncationPoint(rest); if candidateOpn.n > restMaxOpn.n { maxLogTruncationPoint := candidateOpn; } else { maxLogTruncationPoint := restMaxOpn; } } } method {:timeLimitMultiplier 8} ProposerMaybeEnterPhase2(proposer:ProposerState,log_truncation_point:COperationNumber) returns (proposer':ProposerState, sent_packets:CBroadcast) requires ProposerIsValid(proposer) requires COperationNumberIsAbstractable(log_truncation_point) ensures ProposerIsValid(proposer') ensures CBroadcastIsValid(sent_packets) ensures OutboundPacketsHasCorrectSrc(Broadcast(sent_packets), proposer.constants.all.config.replica_ids[proposer.constants.my_index]) ensures LProposerMaybeEnterPhase2(AbstractifyProposerStateToLProposer(proposer), AbstractifyProposerStateToLProposer(proposer'), AbstractifyCOperationNumberToOperationNumber(log_truncation_point), AbstractifyCBroadcastToRlsPacketSeq(sent_packets)) ensures proposer.constants == proposer'.constants ensures proposer'.election_state.cur_req_set == proposer.election_state.cur_req_set ensures proposer'.election_state.prev_req_set == proposer.election_state.prev_req_set { var start_time := Time.GetDebugTimeTicks(); assert SetOfInjectiveTypeCPackets(proposer.received_1b_packets); ghost var ref_proposer := AbstractifyProposerStateToLProposer(proposer); lemma_AbstractifySetOfCPacketsToSetOfRslPackets_propertiesProposer(proposer.received_1b_packets); assert |proposer.received_1b_packets| == |AbstractifySetOfCPacketsToSetOfRslPackets(proposer.received_1b_packets)|; var quorum_size := MinCQuorumSize(proposer.constants.all.config); // The following is already true thanks to our IsValid invariant: // assert LSet(ref_proposer.received_1b_packets, ref_proposer.max_ballot_i_sent_1a); lemma_Received1bBound(proposer); if |proposer.received_1b_packets| as uint64 >= quorum_size && proposer.current_state == 1 { assert |ref_proposer.received_1b_packets| >= LMinQuorumSize(ref_proposer.constants.all.config); assert LSetOfMessage1bAboutBallot(ref_proposer.received_1b_packets, ref_proposer.max_ballot_i_sent_1a); assert ref_proposer.current_state == 1; var maxOpn, foundNonEmpty := getMaxOpnWithProposalFromSet(proposer.received_1b_packets); if !foundNonEmpty { maxOpn := COperationNumber(0); } else if (maxOpn.n < 0xffff_ffff_ffff_ffff) { maxOpn := COperationNumber(maxOpn.n + 1); } var maxLogTP := getMaxLogTruncationPoint(proposer.received_1b_packets); //print("Proposer starting phase 2 for ballot", proposer.max_ballot_i_sent_1a, ". Setting maxOpnWithProposal to ", maxOpn, " and maxLogTruncationPoint to", maxLogTP, "\n"); proposer' := proposer.(current_state := 2, next_operation_number_to_propose := log_truncation_point.n, maxOpnWithProposal := maxOpn, maxLogTruncationPoint := maxLogTP); var msg := CMessage_StartingPhase2(proposer.max_ballot_i_sent_1a, log_truncation_point); assert Marshallable(msg); sent_packets := BuildBroadcastToEveryone(proposer.constants.all.config, proposer.constants.my_index, msg); var end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("ProposerMaybeEnterPhase2_work", start_time, end_time); } else { proposer' := proposer; sent_packets := CBroadcastNop; lemma_AbstractifySetOfCPacketsToSetOfRslPackets_propertiesProposer({}); var end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("ProposerMaybeEnterPhase2_nada", start_time, end_time); } ghost var ref_proposer' := AbstractifyProposerStateToLProposer(proposer'); ghost var ref_logTruncationPoint := AbstractifyCOperationNumberToOperationNumber(log_truncation_point); } predicate Proposer_CanNominateUsingOperationNumber(s:ProposerState, log_truncation_point:COperationNumber, opn:COperationNumber) requires ConstantsStateIsAbstractable(s.constants.all) { && s.election_state.current_view == s.max_ballot_i_sent_1a && s.current_state == 2 && |s.received_1b_packets| >= LMinQuorumSize(AbstractifyCPaxosConfigurationToConfiguration(s.constants.all.config)) && SetOfMessage1bAboutBallot(s.received_1b_packets, s.max_ballot_i_sent_1a) // Don't try to nominate for an operation that's already been truncated into history: && IsAfterLogTruncationPoint(opn, s.received_1b_packets) // Don't try to nominate in an operation that's too far in the future; that would grow the log too much. && opn.n as int < UpperBoundedAddition(log_truncation_point.n as int, s.constants.all.params.max_log_length as int, UpperBoundFinite(s.constants.all.params.max_integer_val as int)) // Disallow negative operations && opn.n >= 0 } lemma lemma_ProposerCanNominateUsingOperationNumberAbstractifies(s:ProposerState, log_truncation_point:COperationNumber, opn:COperationNumber) requires ProposerIsValid(s) requires COperationNumberIsAbstractable(log_truncation_point) requires Proposer_CanNominateUsingOperationNumber(s, log_truncation_point, opn) ensures LProposerCanNominateUsingOperationNumber(AbstractifyProposerStateToLProposer(s), AbstractifyCOperationNumberToOperationNumber(log_truncation_point), AbstractifyCOperationNumberToOperationNumber(opn)) { lemma_AbstractifySetOfCPacketsToSetOfRslPackets_propertiesProposer(s.received_1b_packets); reveal AbstractifyCVotesToVotes(); } lemma {:timeLimitMultiplier 4} lemma_NotProposerCanNominateUsingOperationNumberAbstractifies(s:ProposerState, log_truncation_point:COperationNumber, opn:COperationNumber) requires ProposerIsValid(s) requires COperationNumberIsAbstractable(log_truncation_point) requires !Proposer_CanNominateUsingOperationNumber(s, log_truncation_point, opn) ensures !LProposerCanNominateUsingOperationNumber(AbstractifyProposerStateToLProposer(s), AbstractifyCOperationNumberToOperationNumber(log_truncation_point), AbstractifyCOperationNumberToOperationNumber(opn)) { lemma_AbstractifySetOfCPacketsToSetOfRslPackets_propertiesProposer(s.received_1b_packets); if !(s.election_state.current_view == s.max_ballot_i_sent_1a) { } else if !(s.current_state == 2) { } else if !(|s.received_1b_packets| >= LMinQuorumSize(AbstractifyCPaxosConfigurationToConfiguration(s.constants.all.config))) { } else if !(SetOfMessage1bAboutBallot(s.received_1b_packets, s.max_ballot_i_sent_1a)) { } else if !(IsAfterLogTruncationPoint(opn, s.received_1b_packets)) { lemma_AbstractifySetOfCPacketsToSetOfRslPackets_propertiesProposer(s.received_1b_packets); } else if !(opn.n as int < UpperBoundedAddition(log_truncation_point.n as int, s.constants.all.params.max_log_length as int, UpperBoundFinite(s.constants.all.params.max_integer_val as int))) { } else if (!(opn.n >= 0)) { } else { assert false; } } lemma lemma_AllAcceptorsHadNoProposalAbstractifies(S:set, opn:COperationNumber) requires CPacketsIsAbstractable(S) requires COperationNumberIsAbstractable(opn) requires SetOfMessage1b(S) requires AllAcceptorsHadNoProposal(S, opn) ensures LSetOfMessage1b(AbstractifySetOfCPacketsToSetOfRslPackets(S)) ensures LAllAcceptorsHadNoProposal(AbstractifySetOfCPacketsToSetOfRslPackets(S), AbstractifyCOperationNumberToOperationNumber(opn)) { lemma_AbstractifySetOfCPacketsToSetOfRslPackets_propertiesProposer(S); } lemma lemma_NotAllAcceptorsHadNoProposalAbstractifies(S:set, opn:COperationNumber) requires CPacketsIsAbstractable(S) requires SetOfMessage1b(S) requires COperationNumberIsAbstractable(opn) requires !AllAcceptorsHadNoProposal(S, opn) ensures LSetOfMessage1b(AbstractifySetOfCPacketsToSetOfRslPackets(S)) ensures !LAllAcceptorsHadNoProposal(AbstractifySetOfCPacketsToSetOfRslPackets(S), AbstractifyCOperationNumberToOperationNumber(opn)) { lemma_AbstractifySetOfCPacketsToSetOfRslPackets_propertiesProposer(S); reveal AbstractifySetOfCPacketsToSetOfRslPackets(); var p :| p in S && opn in p.msg.votes.v; assert AbstractifyCPacketToRslPacket(p) in AbstractifySetOfCPacketsToSetOfRslPackets(S); //assert !(AbstractifyCOperationNumberToOperationNumber(opn) in AbstractifyCPacketToRslPacket(p).msg.votes); reveal AbstractifyCVotesToVotes(); } //lemma lemma_SequenceSuffix(s:seq, t:seq, n:int) // requires s == t method {:timeLimitMultiplier 7} ProposerNominateNewValueAndSend2a(proposer:ProposerState, clock:uint64, log_truncation_point:COperationNumber) returns (proposer':ProposerState, sent_packets:CBroadcast) requires ProposerIsValid(proposer) requires COperationNumberIsAbstractable(log_truncation_point) requires Proposer_CanNominateUsingOperationNumber(proposer, log_truncation_point, COperationNumber(proposer.next_operation_number_to_propose)) requires AllAcceptorsHadNoProposal(proposer.received_1b_packets, COperationNumber(proposer.next_operation_number_to_propose)) //requires |proposer.request_queue| > 0 ensures ProposerIsValid(proposer') ensures CBroadcastIsValid(sent_packets) ensures LProposerCanNominateUsingOperationNumber(AbstractifyProposerStateToLProposer(proposer), AbstractifyCOperationNumberToOperationNumber(log_truncation_point), proposer.next_operation_number_to_propose as int) ensures LAllAcceptorsHadNoProposal(AbstractifyProposerStateToLProposer(proposer).received_1b_packets, AbstractifyProposerStateToLProposer(proposer).next_operation_number_to_propose) ensures LProposerNominateNewValueAndSend2a(AbstractifyProposerStateToLProposer(proposer), AbstractifyProposerStateToLProposer(proposer'), clock as int, AbstractifyCOperationNumberToOperationNumber(log_truncation_point), AbstractifyCBroadcastToRlsPacketSeq(sent_packets)) ensures proposer.constants == proposer'.constants ensures OutboundPacketsHasCorrectSrc(Broadcast(sent_packets), proposer.constants.all.config.replica_ids[proposer.constants.my_index]) ensures proposer'.election_state.cur_req_set == proposer.election_state.cur_req_set ensures proposer'.election_state.prev_req_set == proposer.election_state.prev_req_set { var batchSize := if |proposer.request_queue| <= proposer.constants.all.params.max_batch_size as int || proposer.constants.all.params.max_batch_size < 0 then |proposer.request_queue| else proposer.constants.all.params.max_batch_size as int; var v := proposer.request_queue[..batchSize]; var opn := proposer.next_operation_number_to_propose; var opn_op := COperationNumber(proposer.next_operation_number_to_propose); //var sum := LCappedAdditionImpl(opn, 1, proposer.constants.all.params); var clock_sum := UpperBoundedAdditionImpl(clock, proposer.constants.all.params.max_batch_delay, proposer.constants.all.params.max_integer_val); var newTimer:CIncompleteBatchTimer := if |proposer.request_queue| > batchSize as int then CIncompleteBatchTimerOn(clock_sum) else CIncompleteBatchTimerOff(); //print("Proposer sending 2a about new value in ballot", proposer.max_ballot_i_sent_1a, "operation", opn_op, "value", v, "\n"); proposer' := proposer.(request_queue := proposer.request_queue[batchSize..], next_operation_number_to_propose := opn + 1, incomplete_batch_timer := newTimer); var msg := CMessage_2a(proposer.max_ballot_i_sent_1a, opn_op, v); assert Marshallable(msg); sent_packets := BuildBroadcastToEveryone(proposer.constants.all.config, proposer.constants.my_index, msg); lemma_ProposerCanNominateUsingOperationNumberAbstractifies(proposer, log_truncation_point, COperationNumber(proposer.next_operation_number_to_propose)); lemma_AbstractifySetOfCPacketsToSetOfRslPackets_propertiesProposer(proposer.received_1b_packets); ghost var ref_proposer := AbstractifyProposerStateToLProposer(proposer); ghost var ref_proposer' := AbstractifyProposerStateToLProposer(proposer'); ghost var ref_logTruncationPoint := AbstractifyCOperationNumberToOperationNumber(log_truncation_point); ghost var batchSizeGhost := if |ref_proposer.request_queue| <= ref_proposer.constants.all.params.max_batch_size || ref_proposer.constants.all.params.max_batch_size < 0 then |ref_proposer.request_queue| else ref_proposer.constants.all.params.max_batch_size; assert batchSizeGhost == batchSize; assert {:split_here} true; ghost var vGhost := ref_proposer.request_queue[..batchSizeGhost]; ghost var opnGhost := ref_proposer.next_operation_number_to_propose; ghost var s' := ref_proposer'; ghost var s := ref_proposer; assert vGhost == AbstractifyCRequestBatchToRequestBatch(v); assert s'.request_queue == s.request_queue[batchSize..]; assert s'.next_operation_number_to_propose == s.next_operation_number_to_propose + 1; assert s'.incomplete_batch_timer == if |s.request_queue| > batchSize then IncompleteBatchTimerOn(UpperBoundedAddition(clock as int, s.constants.all.params.max_batch_delay, s.constants.all.params.max_integer_val)) else IncompleteBatchTimerOff(); assert LBroadcastToEveryone(AbstractifyCPaxosConfigurationToConfiguration(proposer.constants.all.config), proposer.constants.my_index as int, AbstractifyCMessageToRslMessage(msg), AbstractifyCBroadcastToRlsPacketSeq(sent_packets)); assert AbstractifyCMessageToRslMessage(msg) == RslMessage_2a(AbstractifyProposerStateToLProposer(proposer).max_ballot_i_sent_1a, AbstractifyCOperationNumberToOperationNumber(opn_op), AbstractifyCRequestBatchToRequestBatch(v)); assert vGhost == AbstractifyCRequestBatchToRequestBatch(v); assert LBroadcastToEveryone(ref_proposer.constants.all.config, ref_proposer.constants.my_index, RslMessage_2a(ref_proposer.max_ballot_i_sent_1a, opnGhost, vGhost), AbstractifyCBroadcastToRlsPacketSeq(sent_packets)); assert {:split_here} true; assert 0 <= batchSize <= |proposer.request_queue|; lemma_AbstractifyCRequestsSeqToRequestsSeq_suffix(proposer.request_queue, batchSize); assert AbstractifyCRequestsSeqToRequestsSeq(proposer.request_queue[batchSize..]) == AbstractifyCRequestsSeqToRequestsSeq(proposer.request_queue)[batchSize..]; assert AbstractifyCRequestsSeqToRequestsSeq(proposer.request_queue[..batchSize]) == AbstractifyCRequestsSeqToRequestsSeq(proposer.request_queue)[..batchSize]; assert proposer'.request_queue == proposer.request_queue[batchSize..]; assert ref_proposer'.request_queue == ref_proposer.request_queue[batchSize..]; assert ref_proposer'.next_operation_number_to_propose == UpperBoundedAddition(ref_proposer.next_operation_number_to_propose, 1, ref_proposer.constants.all.params.max_integer_val); assert ref_proposer'.incomplete_batch_timer == AbstractifyCIncompleteBatchTimerToIncompleteBatchTimer(newTimer); assert ProposerIsValid(proposer'); assert CBroadcastIsValid(sent_packets); assert LProposerCanNominateUsingOperationNumber(AbstractifyProposerStateToLProposer(proposer), AbstractifyCOperationNumberToOperationNumber(log_truncation_point), proposer.next_operation_number_to_propose as int); assert LAllAcceptorsHadNoProposal(AbstractifyProposerStateToLProposer(proposer).received_1b_packets, AbstractifyProposerStateToLProposer(proposer).next_operation_number_to_propose); assert {:split_here} true; assert LProposerNominateNewValueAndSend2a(AbstractifyProposerStateToLProposer(proposer), AbstractifyProposerStateToLProposer(proposer'), clock as int, AbstractifyCOperationNumberToOperationNumber(log_truncation_point), AbstractifyCBroadcastToRlsPacketSeq(sent_packets)); assert proposer.constants == proposer'.constants; assert OutboundPacketsHasCorrectSrc(Broadcast(sent_packets), proposer.constants.all.config.replica_ids[proposer.constants.my_index]); } predicate ExistsCBallotInS(v:CRequestBatch, c:CBallot, S:set, opn:COperationNumber) // requires CRequestIsAbstractable(v) && COperationNumberIsAbstractable(opn) && CBallotIsAbstractable(c) // requires CPacketsIsAbstractable(S) requires SetOfMessage1b(S) { exists p :: && p in S && opn in p.msg.votes.v && p.msg.votes.v[opn].max_value_bal==c && p.msg.votes.v[opn].max_val==v } predicate CValIsHighestNumberedProposalAtBallot(v:CRequestBatch, c:CBallot, S:set, opn:COperationNumber) requires CBallotIsAbstractable(c) && CPacketsIsAbstractable(S) && COperationNumberIsAbstractable(opn) requires SetOfMessage1b(S) { lemma_AbstractifySetOfCPacketsToSetOfRslPackets_propertiesProposer(S); && LMaxBallotInS(AbstractifyCBallotToBallot(c), AbstractifySetOfCPacketsToSetOfRslPackets(S), AbstractifyCOperationNumberToOperationNumber(opn)) && ExistsCBallotInS(v, c, S, opn) } predicate CValIsHighestNumberedProposal(v:CRequestBatch, S:set, opn:COperationNumber) requires CRequestBatchIsAbstractable(v) && COperationNumberIsAbstractable(opn) requires CPacketsIsAbstractable(S) requires SetOfMessage1b(S) { exists c :: CBallotIsAbstractable(c) && CValIsHighestNumberedProposalAtBallot(v, c, S, opn) } lemma lemma_CValIsHighestNumberedProposalAbstractifies(v:CRequestBatch, bal:CBallot, S:set, opn:COperationNumber) requires CRequestBatchIsAbstractable(v) && CBallotIsAbstractable(bal) && CPacketsIsAbstractable(S) && COperationNumberIsAbstractable(opn) requires SetOfMessage1b(S) requires CValIsHighestNumberedProposal(v, S, opn) requires CValIsHighestNumberedProposalAtBallot(v, bal, S, opn) ensures LSetOfMessage1b(AbstractifySetOfCPacketsToSetOfRslPackets(S)) ensures LValIsHighestNumberedProposal(AbstractifyCRequestBatchToRequestBatch(v), AbstractifySetOfCPacketsToSetOfRslPackets(S), AbstractifyCOperationNumberToOperationNumber(opn)) ensures LValIsHighestNumberedProposalAtBallot(AbstractifyCRequestBatchToRequestBatch(v), AbstractifyCBallotToBallot(bal), AbstractifySetOfCPacketsToSetOfRslPackets(S), AbstractifyCOperationNumberToOperationNumber(opn)) { reveal AbstractifyCVotesToVotes(); var c :| CBallotIsAbstractable(c) && CValIsHighestNumberedProposalAtBallot(v, c, S, opn); var ref_c := AbstractifyCBallotToBallot(c); var ref_v := AbstractifyCRequestBatchToRequestBatch(v); var ref_S := AbstractifySetOfCPacketsToSetOfRslPackets(S); var ref_opn := AbstractifyCOperationNumberToOperationNumber(opn); forall ensures LMaxBallotInS(ref_c, ref_S, ref_opn) { lemma_AbstractifySetOfCPacketsToSetOfRslPackets_propertiesProposer(S); } assert ExistsCBallotInS(v, c, S, opn); var p :| && p in S && opn in p.msg.votes.v && p.msg.votes.v[opn].max_value_bal==c && p.msg.votes.v[opn].max_val==v; var ref_p := AbstractifyCPacketToRslPacket(p); forall ensures ref_p in ref_S { reveal AbstractifySetOfCPacketsToSetOfRslPackets(); } assert ref_opn in ref_p.msg.votes; assert ref_p.msg.votes[ref_opn].max_value_bal == ref_c; assert ref_p.msg.votes[ref_opn].max_val == ref_v; assert LExistsBallotInS(ref_v, ref_c, ref_S, ref_opn); assert LValIsHighestNumberedProposalAtBallot(ref_v, ref_c, ref_S, ref_opn); assert LValIsHighestNumberedProposal(ref_v, ref_S, ref_opn); var ref_bal := AbstractifyCBallotToBallot(bal); assert ExistsCBallotInS(v, bal, S, opn); var p' :| && p' in S && opn in p'.msg.votes.v && p'.msg.votes.v[opn].max_value_bal==bal && p'.msg.votes.v[opn].max_val==v; assert AbstractifyCRequestBatchToRequestBatch(p'.msg.votes.v[opn].max_val) == AbstractifyCRequestBatchToRequestBatch(v); var ref_p' := AbstractifyCPacketToRslPacket(p'); forall ensures ref_p' in ref_S { reveal AbstractifySetOfCPacketsToSetOfRslPackets(); } assert ref_opn in ref_p'.msg.votes; assert ref_p'.msg.votes[ref_opn].max_value_bal == ref_bal; assert ref_p'.msg.votes[ref_opn].max_val == ref_v; assert LExistsBallotInS(ref_v, ref_bal, ref_S, ref_opn); assert LValIsHighestNumberedProposalAtBallot(AbstractifyCRequestBatchToRequestBatch(v), AbstractifyCBallotToBallot(bal), AbstractifySetOfCPacketsToSetOfRslPackets(S), AbstractifyCOperationNumberToOperationNumber(opn)); } method {:timeLimitMultiplier 5} FindValWithHighestNumberedProposal(received_1b_packets:set, opn:COperationNumber) returns (v:CRequestBatch) requires received_1b_packets != {} requires COperationNumberIsAbstractable(opn) requires SetOfMessage1b(received_1b_packets) requires CPacketsIsAbstractable(received_1b_packets) requires !AllAcceptorsHadNoProposal(received_1b_packets, opn) requires forall p :: p in received_1b_packets ==> ValidVotes(p.msg.votes) ensures CRequestBatchIsAbstractable(v) ensures ValidRequestBatch(v) ensures LSetOfMessage1b(AbstractifySetOfCPacketsToSetOfRslPackets(received_1b_packets)) ensures LValIsHighestNumberedProposal(AbstractifyCRequestBatchToRequestBatch(v), AbstractifySetOfCPacketsToSetOfRslPackets(received_1b_packets), AbstractifyCOperationNumberToOperationNumber(opn)) { var packets:set; ghost var processedPackets:set; packets := received_1b_packets; var pkt :| pkt in packets && opn in pkt.msg.votes.v; v := pkt.msg.votes.v[opn].max_val; var bal := pkt.msg.votes.v[opn].max_value_bal; var p_bal := pkt; packets := packets - {pkt}; processedPackets := {pkt}; reveal AbstractifySetOfCPacketsToSetOfRslPackets(); reveal AbstractifyCVotesToVotes(); ghost var p := AbstractifyCPacketToRslPacket(pkt); ghost var S := AbstractifySetOfCPacketsToSetOfRslPackets(processedPackets); ghost var opn_s := AbstractifyCOperationNumberToOperationNumber(opn); while (packets != {}) decreases packets invariant packets + processedPackets == received_1b_packets invariant processedPackets == received_1b_packets - packets invariant CRequestBatchIsAbstractable(v) && CBallotIsAbstractable(bal) && CPacketIsAbstractable(p_bal) && p_bal in processedPackets && opn in p_bal.msg.votes.v && v == p_bal.msg.votes.v[opn].max_val && bal == p_bal.msg.votes.v[opn].max_value_bal invariant forall q :: q in processedPackets && opn in q.msg.votes.v ==> CCBalLeq(q.msg.votes.v[opn].max_value_bal, p_bal.msg.votes.v[opn].max_value_bal) invariant p_bal in processedPackets invariant opn in p_bal.msg.votes.v invariant p_bal.msg.votes.v[opn].max_value_bal==bal invariant p_bal.msg.votes.v[opn].max_val==v invariant ExistsCBallotInS(v, bal, processedPackets, opn) invariant CValIsHighestNumberedProposalAtBallot(v, bal, processedPackets, opn) invariant CValIsHighestNumberedProposal(v, processedPackets, opn) invariant ValidRequestBatch(v) { pkt :| pkt in packets; if (opn in pkt.msg.votes.v) { var foundHigherBallot := CBalLeq(bal, pkt.msg.votes.v[opn].max_value_bal); if (foundHigherBallot) { p_bal := pkt; v := pkt.msg.votes.v[opn].max_val; bal := pkt.msg.votes.v[opn].max_value_bal; } } packets := packets - {pkt}; processedPackets := processedPackets + {pkt}; reveal AbstractifyCVotesToVotes(); } assert processedPackets == received_1b_packets; p := AbstractifyCPacketToRslPacket(p_bal); assert CValIsHighestNumberedProposal(v, received_1b_packets, opn); lemma_CValIsHighestNumberedProposalAbstractifies(v, bal, received_1b_packets, opn); assert LValIsHighestNumberedProposalAtBallot(AbstractifyCRequestBatchToRequestBatch(v), AbstractifyCBallotToBallot(bal), AbstractifySetOfCPacketsToSetOfRslPackets(received_1b_packets), AbstractifyCOperationNumberToOperationNumber(opn)); } method ProposerNominateOldValueAndSend2a(proposer:ProposerState,log_truncation_point:COperationNumber) returns (proposer':ProposerState, sent_packets:CBroadcast) requires ProposerIsValid(proposer) requires COperationNumberIsAbstractable(log_truncation_point) requires Proposer_CanNominateUsingOperationNumber(proposer, log_truncation_point, COperationNumber(proposer.next_operation_number_to_propose)) requires !AllAcceptorsHadNoProposal(proposer.received_1b_packets, COperationNumber(proposer.next_operation_number_to_propose)) ensures ProposerIsValid(proposer') ensures CBroadcastIsValid(sent_packets) ensures LProposerCanNominateUsingOperationNumber(AbstractifyProposerStateToLProposer(proposer), AbstractifyCOperationNumberToOperationNumber(log_truncation_point), proposer.next_operation_number_to_propose as int) ensures LSetOfMessage1b(AbstractifySetOfCPacketsToSetOfRslPackets(proposer.received_1b_packets)) ensures !LAllAcceptorsHadNoProposal(AbstractifyProposerStateToLProposer(proposer).received_1b_packets, AbstractifyProposerStateToLProposer(proposer).next_operation_number_to_propose) ensures LProposerNominateOldValueAndSend2a(AbstractifyProposerStateToLProposer(proposer), AbstractifyProposerStateToLProposer(proposer'), AbstractifyCOperationNumberToOperationNumber(log_truncation_point), AbstractifyCBroadcastToRlsPacketSeq(sent_packets)) ensures proposer.constants == proposer'.constants ensures OutboundPacketsHasCorrectSrc(Broadcast(sent_packets), proposer.constants.all.config.replica_ids[proposer.constants.my_index]) ensures proposer'.election_state.cur_req_set == proposer.election_state.cur_req_set ensures proposer'.election_state.prev_req_set == proposer.election_state.prev_req_set { ghost var r_proposer := AbstractifyProposerStateToLProposer(proposer); var opn := proposer.next_operation_number_to_propose; var opn_op := COperationNumber(proposer.next_operation_number_to_propose); var val := FindValWithHighestNumberedProposal(proposer.received_1b_packets, opn_op); assert LValIsHighestNumberedProposal(AbstractifyCRequestBatchToRequestBatch(val), AbstractifySetOfCPacketsToSetOfRslPackets(proposer.received_1b_packets), AbstractifyCOperationNumberToOperationNumber(opn_op)); var sum := opn + 1; //print("Proposer sending 2a about old value in ballot", proposer.max_ballot_i_sent_1a, "operation", opn_op, "value", val, "\n"); proposer' := proposer.(next_operation_number_to_propose := sum); // Update the protocol version too ghost var L_opn := r_proposer.next_operation_number_to_propose; ghost var r_proposer' := r_proposer.(next_operation_number_to_propose := UpperBoundedAddition(r_proposer.next_operation_number_to_propose, 1, r_proposer.constants.all.params.max_integer_val)); var msg := CMessage_2a(proposer.max_ballot_i_sent_1a, opn_op, val); assert Marshallable(msg); sent_packets := BuildBroadcastToEveryone(proposer.constants.all.config, proposer.constants.my_index, msg); lemma_ProposerCanNominateUsingOperationNumberAbstractifies(proposer, log_truncation_point, COperationNumber(proposer.next_operation_number_to_propose)); lemma_NotAllAcceptorsHadNoProposalAbstractifies(proposer.received_1b_packets, opn_op); lemma_AbstractifySetOfCPacketsToSetOfRslPackets_propertiesProposer(proposer.received_1b_packets); reveal AbstractifyCVotesToVotes(); assert Eq_LProposer(r_proposer', AbstractifyProposerStateToLProposer(proposer')); } /* method ProposerNominateNoOpValueAndSend2a(proposer:ProposerState,log_truncation_point:COperationNumber) returns (proposer':ProposerState, sent_packets:CBroadcast) requires ProposerIsValid(proposer) requires COperationNumberIsAbstractable(log_truncation_point) requires Proposer_CanNominateUsingOperationNumber(proposer, log_truncation_point, COperationNumber(proposer.next_operation_number_to_propose)) requires AllAcceptorsHadNoProposal(proposer.received_1b_packets, COperationNumber(proposer.next_operation_number_to_propose)) requires exists opn:COperationNumber :: opn.n > proposer.next_operation_number_to_propose && !AllAcceptorsHadNoProposal(proposer.received_1b_packets, opn) ensures ProposerIsValid(proposer') ensures CBroadcastIsValid(sent_packets) ensures LProposerCanNominateUsingOperationNumber(AbstractifyProposerStateToLProposer(proposer), AbstractifyCOperationNumberToOperationNumber(log_truncation_point), proposer.next_operation_number_to_propose as int) ensures LSetOfMessage1b(AbstractifyProposerStateToLProposer(proposer).received_1b_packets) ensures LAllAcceptorsHadNoProposal(AbstractifyProposerStateToLProposer(proposer).received_1b_packets, AbstractifyProposerStateToLProposer(proposer).next_operation_number_to_propose) ensures exists l_opn :: l_opn > AbstractifyProposerStateToLProposer(proposer).next_operation_number_to_propose && !LAllAcceptorsHadNoProposal(AbstractifyProposerStateToLProposer(proposer).received_1b_packets, l_opn) ensures LProposerNominateNewValueAndSend2a(AbstractifyProposerStateToLProposer(proposer), AbstractifyProposerStateToLProposer(proposer'), AbstractifyCOperationNumberToOperationNumber(log_truncation_point), AbstractifyCBroadcastToRlsPacketSeq(sent_packets)) ensures proposer.constants == proposer'.constants ensures OutboundPacketsHasCorrectSrc(Broadcast(sent_packets), proposer.constants.all.config.replica_ids[proposer.constants.my_index]) { var v := []; var opn := proposer.next_operation_number_to_propose; var opn_op := COperationNumber(proposer.next_operation_number_to_propose); var sum := LCappedAdditionImpl(opn, 1, proposer.constants.all.params); ghost var ref_op := AbstractifyCOperationNumberToOperationNumber(opn_op); ghost var ref_v := AbstractifyCRequestBatchToRequestBatch(v); //print("Proposer sending 2a about no-op in ballot", proposer.max_ballot_i_sent_1a, "operation", opn_op, "value", v, "\n"); proposer' := proposer[next_operation_number_to_propose := sum]; var msg := CMessage_2a(proposer.max_ballot_i_sent_1a, opn_op, v); sent_packets := BuildBroadcastToEveryone(proposer.constants.all.config, proposer.constants.my_index, msg); ghost var ref_proposer := AbstractifyProposerStateToLProposer(proposer); lemma_ProposerCanNominateUsingOperationNumberAbstractifies(proposer, log_truncation_point, COperationNumber(proposer.next_operation_number_to_propose)); lemma_AllAcceptorsHadNoProposalAbstractifies(proposer.received_1b_packets, opn_op); ghost var e_opn:COperationNumber :| e_opn.n > proposer.next_operation_number_to_propose && !AllAcceptorsHadNoProposal(proposer.received_1b_packets, e_opn); ghost var ref_e_opn := AbstractifyCOperationNumberToOperationNumber(e_opn); lemma_NotAllAcceptorsHadNoProposalAbstractifies(proposer.received_1b_packets, e_opn); assert ref_e_opn > ref_proposer.next_operation_number_to_propose && !LAllAcceptorsHadNoProposal(ref_proposer.received_1b_packets, ref_e_opn); lemma_AbstractifySetOfCPacketsToSetOfRslPackets_propertiesProposer(proposer.received_1b_packets); reveal AbstractifyCVotesToVotes(); ghost var ref_proposer' := AbstractifyProposerStateToLProposer(proposer'); ghost var ref_logTruncationPoint := AbstractifyCOperationNumberToOperationNumber(log_truncation_point); assert ref_proposer'.next_operation_number_to_propose == LCappedAddition(ref_proposer.next_operation_number_to_propose, 1, ref_proposer.constants.all.params); } */ method IsAfterLogTruncationPointImpl(opn:COperationNumber, received_1b_packets:set) returns (b:bool) requires COperationNumberIsAbstractable(opn) && CPacketsIsAbstractable(received_1b_packets) ensures b == IsAfterLogTruncationPoint(opn, received_1b_packets) ensures b == LIsAfterLogTruncationPoint(AbstractifyCOperationNumberToOperationNumber(opn), AbstractifySetOfCPacketsToSetOfRslPackets(received_1b_packets)) { reveal AbstractifySetOfCPacketsToSetOfRslPackets(); lemma_AbstractifyCPacketToRslPacket_isInjective(); assert forall p :: CPacketIsAbstractable(p) && AbstractifyCPacketToRslPacket(p).msg.RslMessage_1b? ==> CPacketIsInjectiveType(p); b := (forall p :: p in received_1b_packets && p.msg.CMessage_1b? ==> p.msg.log_truncation_point.n <= opn.n); } method Proposer_CanNominateUsingOperationNumberImpl(proposer:ProposerState,log_truncation_point:COperationNumber) returns (b:bool) requires ProposerIsValid(proposer) requires COperationNumberIsAbstractable(log_truncation_point) ensures b == Proposer_CanNominateUsingOperationNumber(proposer, log_truncation_point, COperationNumber(proposer.next_operation_number_to_propose)) ensures b == LProposerCanNominateUsingOperationNumber(AbstractifyProposerStateToLProposer(proposer), AbstractifyCOperationNumberToOperationNumber(log_truncation_point), AbstractifyProposerStateToLProposer(proposer).next_operation_number_to_propose) { if (proposer.current_state == 2) { var opn := COperationNumber(proposer.next_operation_number_to_propose); var quorum_size := MinCQuorumSize(proposer.constants.all.config); var after_trunk; if (opn.n >= proposer.maxLogTruncationPoint.n) { after_trunk := true; } else { after_trunk := IsAfterLogTruncationPointImpl(opn, proposer.received_1b_packets); } var sum := UpperBoundedAdditionImpl(log_truncation_point.n, proposer.constants.all.params.max_log_length, proposer.constants.all.params.max_integer_val); assert SetOfMessage1bAboutBallot(proposer.received_1b_packets, proposer.max_ballot_i_sent_1a); lemma_Received1bBound(proposer); b := && proposer.election_state.current_view == proposer.max_ballot_i_sent_1a && proposer.current_state == 2 && |proposer.received_1b_packets| as uint64 >= quorum_size // Should come for free from ProposerIsValid //&& SetOfMessage1bAboutBallot(proposer.received_1b_packets, proposer.max_ballot_i_sent_1a) && after_trunk && opn.n < sum && opn.n >=0; assert b == Proposer_CanNominateUsingOperationNumber(proposer, log_truncation_point, COperationNumber(proposer.next_operation_number_to_propose)); if b { lemma_ProposerCanNominateUsingOperationNumberAbstractifies(proposer, log_truncation_point, COperationNumber(proposer.next_operation_number_to_propose)); } else { lemma_NotProposerCanNominateUsingOperationNumberAbstractifies(proposer, log_truncation_point, COperationNumber(proposer.next_operation_number_to_propose)); } } else { b := false; } } method {:timeLimitMultiplier 6} AllAcceptorsHadNoProposalImpl(proposer:ProposerState) returns (b:bool) requires ProposerIsValid(proposer) requires proposer.current_state == 2 ensures LSetOfMessage1b(AbstractifyProposerStateToLProposer(proposer).received_1b_packets) ensures b == AllAcceptorsHadNoProposal(proposer.received_1b_packets, COperationNumber(proposer.next_operation_number_to_propose)) ensures b == LAllAcceptorsHadNoProposal(AbstractifyProposerStateToLProposer(proposer).received_1b_packets, AbstractifyProposerStateToLProposer(proposer).next_operation_number_to_propose) { reveal AbstractifySetOfCPacketsToSetOfRslPackets(); reveal AbstractifyCVotesToVotes(); lemma_AbstractifyCPacketToRslPacket_isInjective(); lemma_AbstractifyCOperationNumberToOperationNumber_isInjective(); assert forall p :: p in proposer.received_1b_packets ==> CPacketIsInjectiveType(p); var start_time := Time.GetDebugTimeTicks(); var end_time; if(proposer.next_operation_number_to_propose < proposer.maxOpnWithProposal.n || proposer.maxOpnWithProposal.n == 0xffff_ffff_ffff_ffff) { var opn := COperationNumber(proposer.next_operation_number_to_propose); b := (forall p :: p in proposer.received_1b_packets ==> !(opn in p.msg.votes.v)); end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("AllAcceptorsHadNoProposalImpl_full", start_time, end_time); //print("AllAcceptorsHadNoProposalImpl_full: Doing full search, nextOpnToPropose = ", proposer.next_operation_number_to_propose, " and maxOpnWithProposal = ", proposer.maxOpnWithProposal.n, "\n"); } else { b := true; end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("AllAcceptorsHadNoProposalImpl_memoized", start_time, end_time); //print("AllAcceptorsHadNoProposalImpl_memoized: Memoized, nextOpnToPropose = ", proposer.next_operation_number_to_propose, " and maxOpnWithProposal = ", proposer.maxOpnWithProposal.n, "\n"); } lemma_AbstractifySetOfCPacketsToSetOfRslPackets_propertiesProposer(proposer.received_1b_packets); } lemma {:timeLimitMultiplier 6} lemma_AllAcceptorsHadNoProposalImpl(proposer:ProposerState) requires ProposerIsValid(proposer) requires proposer.current_state == 2 requires proposer.maxOpnWithProposal.n < 0xffff_ffff_ffff_ffff requires proposer.next_operation_number_to_propose >= proposer.maxOpnWithProposal.n ensures LSetOfMessage1b(AbstractifyProposerStateToLProposer(proposer).received_1b_packets) ensures AllAcceptorsHadNoProposal(proposer.received_1b_packets, COperationNumber(proposer.next_operation_number_to_propose)) ensures LAllAcceptorsHadNoProposal(AbstractifyProposerStateToLProposer(proposer).received_1b_packets, AbstractifyProposerStateToLProposer(proposer).next_operation_number_to_propose) { reveal AbstractifySetOfCPacketsToSetOfRslPackets(); reveal AbstractifyCVotesToVotes(); lemma_AbstractifyCPacketToRslPacket_isInjective(); lemma_AbstractifyCOperationNumberToOperationNumber_isInjective(); assert forall p :: p in proposer.received_1b_packets ==> CPacketIsInjectiveType(p); lemma_AbstractifySetOfCPacketsToSetOfRslPackets_propertiesProposer(proposer.received_1b_packets); } predicate ExistsPred(proposer:ProposerState, ref_proposer:LProposer, existsOpn:bool) requires ProposerIsAbstractable(proposer) requires ref_proposer == AbstractifyProposerStateToLProposer(proposer) requires LSetOfMessage1b(ref_proposer.received_1b_packets) requires ProposerIsValid(proposer) { existsOpn <==> (exists opn :: && opn > ref_proposer.next_operation_number_to_propose && LSetOfMessage1b(ref_proposer.received_1b_packets) && !LAllAcceptorsHadNoProposal(ref_proposer.received_1b_packets, opn)) } predicate AnAcceptorHadProposal(ref_proposer:LProposer, opn:OperationNumber) requires LSetOfMessage1b(ref_proposer.received_1b_packets) { opn > ref_proposer.next_operation_number_to_propose && !LAllAcceptorsHadNoProposal(ref_proposer.received_1b_packets, opn) } method DidSomeAcceptorHaveProposal(proposer:ProposerState) returns (b:bool) //, opn:COperationNumber) requires ProposerIsValid(proposer) requires proposer.current_state == 2 ensures LSetOfMessage1b(AbstractifyProposerStateToLProposer(proposer).received_1b_packets) ensures b <==> (exists opn:COperationNumber :: opn.n > proposer.next_operation_number_to_propose && !AllAcceptorsHadNoProposal(proposer.received_1b_packets, opn)) ensures b == var ref_proposer := AbstractifyProposerStateToLProposer(proposer); (exists opn :: opn > ref_proposer.next_operation_number_to_propose && !LAllAcceptorsHadNoProposal(ref_proposer.received_1b_packets, opn)) { reveal AbstractifyCVotesToVotes(); lemma_AbstractifyCPacketToRslPacket_isInjective(); lemma_AbstractifyCOperationNumberToOperationNumber_isInjective(); lemma_AbstractifySetOfCPacketsToSetOfRslPackets_propertiesProposer(proposer.received_1b_packets); assert forall p :: p in proposer.received_1b_packets ==> CPacketIsInjectiveType(p); if proposer.next_operation_number_to_propose >= proposer.maxOpnWithProposal.n { b := false; } else { b := (exists p :: p in proposer.received_1b_packets && (exists opn:COperationNumber :: opn in p.msg.votes.v && opn.n > proposer.next_operation_number_to_propose)); } // The "exists opn" needs a trigger that relates to "opn.n > ...": ghost var gt := (i:int, j:int) => i > j; assert b <==> (exists p :: p in proposer.received_1b_packets && (exists opn:COperationNumber :: opn in p.msg.votes.v && gt(AbstractifyCOperationNumberToOperationNumber(opn), proposer.next_operation_number_to_propose as int))); ghost var ref_proposer := AbstractifyProposerStateToLProposer(proposer); if ((exists opn :: gt(opn, ref_proposer.next_operation_number_to_propose) && !LAllAcceptorsHadNoProposal(ref_proposer.received_1b_packets, opn))) { var ref_opn :| gt(ref_opn, ref_proposer.next_operation_number_to_propose) && !LAllAcceptorsHadNoProposal(ref_proposer.received_1b_packets, ref_opn); var ref_p :| ref_p in ref_proposer.received_1b_packets && ref_opn in ref_p.msg.votes; forall ensures exists p :: p in proposer.received_1b_packets && ref_p == AbstractifyCPacketToRslPacket(p) { reveal AbstractifySetOfCPacketsToSetOfRslPackets(); } var p :| p in proposer.received_1b_packets && ref_p == AbstractifyCPacketToRslPacket(p); //assert exists o :: o in p.msg.votes.v && AbstractifyCOperationNumberToOperationNumber(o) == ref_opn; assert b; } assert b <==> (exists opn :: gt(opn, ref_proposer.next_operation_number_to_propose) && !LAllAcceptorsHadNoProposal(ref_proposer.received_1b_packets, opn)); } lemma lemma_DidSomeAcceptorHaveProposal(proposer:ProposerState) //, opn:COperationNumber) requires ProposerIsValid(proposer) requires proposer.current_state == 2 requires proposer.next_operation_number_to_propose >= proposer.maxOpnWithProposal.n ensures LSetOfMessage1b(AbstractifyProposerStateToLProposer(proposer).received_1b_packets) ensures !(exists opn:COperationNumber :: opn.n > proposer.next_operation_number_to_propose && !AllAcceptorsHadNoProposal(proposer.received_1b_packets, opn)) ensures !var ref_proposer := AbstractifyProposerStateToLProposer(proposer); (exists opn :: opn > ref_proposer.next_operation_number_to_propose && !LAllAcceptorsHadNoProposal(ref_proposer.received_1b_packets, opn)) { reveal AbstractifyCVotesToVotes(); lemma_AbstractifyCPacketToRslPacket_isInjective(); lemma_AbstractifyCOperationNumberToOperationNumber_isInjective(); lemma_AbstractifySetOfCPacketsToSetOfRslPackets_propertiesProposer(proposer.received_1b_packets); assert forall p :: p in proposer.received_1b_packets ==> CPacketIsInjectiveType(p); var b := false; // The "exists opn" needs a trigger that relates to "opn.n > ...": ghost var gt := (i:int, j:int) => i > j; assert b <==> (exists p :: p in proposer.received_1b_packets && (exists opn:COperationNumber :: opn in p.msg.votes.v && gt(AbstractifyCOperationNumberToOperationNumber(opn), proposer.next_operation_number_to_propose as int))); ghost var ref_proposer := AbstractifyProposerStateToLProposer(proposer); if ((exists opn :: gt(opn, ref_proposer.next_operation_number_to_propose) && !LAllAcceptorsHadNoProposal(ref_proposer.received_1b_packets, opn))) { var ref_opn :| gt(ref_opn, ref_proposer.next_operation_number_to_propose) && !LAllAcceptorsHadNoProposal(ref_proposer.received_1b_packets, ref_opn); var ref_p :| ref_p in ref_proposer.received_1b_packets && ref_opn in ref_p.msg.votes; forall ensures exists p :: p in proposer.received_1b_packets && ref_p == AbstractifyCPacketToRslPacket(p) { reveal AbstractifySetOfCPacketsToSetOfRslPackets(); } var p :| p in proposer.received_1b_packets && ref_p == AbstractifyCPacketToRslPacket(p); //assert exists o :: o in p.msg.votes.v && AbstractifyCOperationNumberToOperationNumber(o) == ref_opn; assert b; } assert b <==> (exists opn :: gt(opn, ref_proposer.next_operation_number_to_propose) && !LAllAcceptorsHadNoProposal(ref_proposer.received_1b_packets, opn)); } method {:timeLimitMultiplier 12} ProposerMaybeNominateValueAndSend2a(proposer:ProposerState, clock:uint64, log_truncation_point:COperationNumber) returns (proposer':ProposerState, sent_packets:CBroadcast) requires ProposerIsValid(proposer) requires COperationNumberIsAbstractable(log_truncation_point) ensures ProposerIsValid(proposer') ensures CBroadcastIsValid(sent_packets) ensures OutboundPacketsHasCorrectSrc(Broadcast(sent_packets), proposer.constants.all.config.replica_ids[proposer.constants.my_index]) ensures LProposerMaybeNominateValueAndSend2a(AbstractifyProposerStateToLProposer(proposer), AbstractifyProposerStateToLProposer(proposer'), clock as int, AbstractifyCOperationNumberToOperationNumber(log_truncation_point), AbstractifyCBroadcastToRlsPacketSeq(sent_packets)) ensures proposer.constants == proposer'.constants ensures proposer'.election_state.cur_req_set == proposer.election_state.cur_req_set ensures proposer'.election_state.prev_req_set == proposer.election_state.prev_req_set { //var start_time := Time.GetDebugTimeTicks(); var canNominate := Proposer_CanNominateUsingOperationNumberImpl(proposer, log_truncation_point); //var end_time:= Time.GetDebugTimeTicks(); //RecordTimingSeq("ProposerMaybeNominateValueAndSend2a_preamble_Proposer_CanNominateUsingOperationNumberImpl", start_time, end_time); /* //start_time := Time.GetDebugTimeTicks(); end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("ProposerMaybeNominateValueAndSend2a_preamble_AllAcceptorsHadNoProposalImpl", start_time, end_time); //start_time := Time.GetDebugTimeTicks(); end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("ProposerMaybeNominateValueAndSend2a_preamble", start_time, end_time); */ //print("ProposerMaybeNominateValueAndSend2a: proposer.next_operation_number_to_propose = ", proposer.next_operation_number_to_propose, ", canNominate = ", canNominate, "\n"); if !canNominate { proposer' := proposer; sent_packets := CBroadcastNop; //lemma_AbstractifySetOfCPacketsToSetOfRslPackets_propertiesProposer(sent_packets); //var end_timeNotCanNominate:= Time.GetDebugTimeTicks(); //RecordTimingSeq("ProposerMaybeNominateValueAndSend2a_unable", start_time, end_timeNotCanNominate); } else { if (proposer.next_operation_number_to_propose >= proposer.maxOpnWithProposal.n && |proposer.request_queue| == 0 && proposer.maxOpnWithProposal.n < 0xffff_ffff_ffff_ffff) { lemma_DidSomeAcceptorHaveProposal(proposer); lemma_AllAcceptorsHadNoProposalImpl(proposer); //start_time := Time.GetDebugTimeTicks(); proposer' := proposer; sent_packets := CBroadcastNop; //lemma_AbstractifySetOfCPacketsToSetOfRslPackets_propertiesProposer(sent_packets); //var end_time4 := Time.GetDebugTimeTicks(); //RecordTimingSeq("ProposerMaybeNominateValueAndSend2a_nada", start_time, end_time4); //print("ProposerMaybeNominateValueAndSend2a: proposer.next_operation_number_to_propose = ", proposer.next_operation_number_to_propose, ". NADA\n"); } else { var noProposal := AllAcceptorsHadNoProposalImpl(proposer); //var end_time2 := Time.GetDebugTimeTicks(); //RecordTimingSeq("ProposerMaybeNominateValueAndSend2a_AllAcceptorsHadNoProposalImpl", start_time, end_time2); //print("ProposerMaybeNominateValueAndSend2a: proposer.next_operation_number_to_propose = ", proposer.next_operation_number_to_propose, ", AllAcceptorsHadNoProposalImpl = ", noProposal, "\n"); if !noProposal { proposer', sent_packets := ProposerNominateOldValueAndSend2a(proposer, log_truncation_point); assert OutboundPacketsHasCorrectSrc(Broadcast(sent_packets), proposer.constants.all.config.replica_ids[proposer.constants.my_index]); //OBSERVE //var end_timeNotNoProposal := Time.GetDebugTimeTicks(); //RecordTimingSeq("ProposerMaybeNominateValueAndSend2a_old", end_time2, end_timeNotNoProposal); //print("ProposerMaybeNominateValueAndSend2a: Nominating old value at proposer.next_operation_number_to_propose = ", proposer.next_operation_number_to_propose, "\n"); } else { var queueSize := |proposer.request_queue|; var existsOpn := DidSomeAcceptorHaveProposal(proposer); ghost var ref_proposer := AbstractifyProposerStateToLProposer(proposer); assert existsOpn ==> (exists opn :: opn > ref_proposer.next_operation_number_to_propose && !LAllAcceptorsHadNoProposal(ref_proposer.received_1b_packets, opn)); assert ExistsPred(proposer, ref_proposer, existsOpn); //var end_time3 := Time.GetDebugTimeTicks(); //var ref_proposer := AbstractifyProposerStateToLProposer(proposer); // (exists opn :: opn > ref_proposer.next_operation_number_to_propose && // !LAllAcceptorsHadNoProposal(ref_proposer.received_1b_packets, opn)); if existsOpn { assert ExistsPred(proposer, ref_proposer, existsOpn); assert existsOpn ==> (exists opn :: opn > ref_proposer.next_operation_number_to_propose && !LAllAcceptorsHadNoProposal(ref_proposer.received_1b_packets, opn)); assert exists opn :: opn > ref_proposer.next_operation_number_to_propose && !LAllAcceptorsHadNoProposal(ref_proposer.received_1b_packets, opn); //ghost var opn :| opn > ref_proposer.next_operation_number_to_propose && // !LAllAcceptorsHadNoProposal(ref_proposer.received_1b_packets, opn); } else { assert forall opn :: !(opn > ref_proposer.next_operation_number_to_propose && !LAllAcceptorsHadNoProposal(ref_proposer.received_1b_packets, opn)); } //assert existsOpn <==> var ref_proposer := AbstractifyProposerStateToLProposer(proposer);(exists opn :: opn > ref_proposer.next_operation_number_to_propose && // !LAllAcceptorsHadNoProposal(ref_proposer.received_1b_packets, opn)); // ;var ref_proposer := AbstractifyProposerStateToLProposer(proposer); // (exists opn :: opn > ref_proposer.next_operation_number_to_propose && // !LAllAcceptorsHadNoProposal(ref_proposer.received_1b_packets, opn)); if (|| (queueSize > 0 && proposer.incomplete_batch_timer.CIncompleteBatchTimerOn? && clock >= proposer.incomplete_batch_timer.when) || (queueSize >= proposer.constants.all.params.max_batch_size as int) || existsOpn) { if existsOpn { assert ExistsPred(proposer, ref_proposer, existsOpn); assert existsOpn ==> (exists opn :: opn > ref_proposer.next_operation_number_to_propose && !LAllAcceptorsHadNoProposal(ref_proposer.received_1b_packets, opn)); assert exists opn :: opn > ref_proposer.next_operation_number_to_propose && !LAllAcceptorsHadNoProposal(ref_proposer.received_1b_packets, opn); //ghost var opn :| opn > ref_proposer.next_operation_number_to_propose && // !LAllAcceptorsHadNoProposal(ref_proposer.received_1b_packets, opn); } else if (queueSize >= proposer.constants.all.params.max_batch_size as int) { assert |ref_proposer.request_queue| >= ref_proposer.constants.all.params.max_batch_size; } else if (queueSize > 0 && proposer.incomplete_batch_timer.CIncompleteBatchTimerOn? && clock >= proposer.incomplete_batch_timer.when) { assert (|ref_proposer.request_queue| > 0 && ref_proposer.incomplete_batch_timer.IncompleteBatchTimerOn? && clock as int >= ref_proposer.incomplete_batch_timer.when); } //assert existsOpn <==> // (exists opn:OperationNumber :: // (opn > AbstractifyProposerStateToLProposer(proposer).next_operation_number_to_propose // && !LAllAcceptorsHadNoProposal(AbstractifyProposerStateToLProposer(proposer).received_1b_packets, opn)) // ); proposer', sent_packets := ProposerNominateNewValueAndSend2a(proposer, clock, log_truncation_point); assert OutboundPacketsHasCorrectSrc(Broadcast(sent_packets), proposer.constants.all.config.replica_ids[proposer.constants.my_index]); //OBSERVE //var end_timeNominateNew := Time.GetDebugTimeTicks(); //RecordTimingSeq("ProposerMaybeNominateValueAndSend2a_new_or_noop", end_time2, end_timeNominateNew); //print("ProposerMaybeNominateValueAndSend2a: |proposer.request_queue| > 0. Nominating new value at ", proposer.next_operation_number_to_propose, "\n"); } else { if ( queueSize > 0 && proposer.incomplete_batch_timer.CIncompleteBatchTimerOff? ) { var sum := UpperBoundedAdditionImpl(clock, proposer.constants.all.params.max_batch_delay, proposer.constants.all.params.max_integer_val); proposer' := proposer.(incomplete_batch_timer := CIncompleteBatchTimerOn(sum)); sent_packets := CBroadcastNop; } else { proposer' := proposer; sent_packets := CBroadcastNop; //RecordTimingSeq("ProposerMaybeNominateValueAndSend2a_DidSomeAcceptorHaveProposal", end_time2, end_time3); //if existsOpn { // proposer', sent_packets := ProposerNominateNewValueAndSend2a(proposer, clock, log_truncation_point); // assert OutboundPacketsHasCorrectSrc(Broadcast(sent_packets), proposer.constants.all.config.replica_ids[proposer.constants.my_index]); //OBSERVE // var end_timeNoOp := Time.GetDebugTimeTicks(); // RecordTimingSeq("ProposerMaybeNominateValueAndSend2a_noop", start_time, end_timeNoOp); // //print("ProposerMaybeNominateValueAndSend2a: proposer.next_operation_number_to_propose = ", proposer.next_operation_number_to_propose, ", DidSomeAcceptorHaveProposal = ", existsOpn, "\n"); //} else { // //assert proposer.next_operation_number_to_propose == proposer.maxOpnWithProposal.n; // //start_time := Time.GetDebugTimeTicks(); // proposer' := proposer; // sent_packets := CBroadcastNop; // //lemma_AbstractifySetOfCPacketsToSetOfRslPackets_propertiesProposer(sent_packets); // var end_time4 := Time.GetDebugTimeTicks(); // RecordTimingSeq("ProposerMaybeNominateValueAndSend2a_nada_shouldneverhappen", start_time, end_time4); // //print("ProposerMaybeNominateValueAndSend2a: proposer.next_operation_number_to_propose = ", proposer.next_operation_number_to_propose, ". NADA\n"); //} } } } } } } method ProposerProcessHeartbeat(proposer:ProposerState, packet:CPacket, clock:uint64, cur_req_set:MutableSet, prev_req_set:MutableSet) returns (proposer':ProposerState) requires ProposerIsValid(proposer) requires CPacketIsAbstractable(packet) requires packet.msg.CMessage_Heartbeat? requires MutableSet.SetOf(cur_req_set) == proposer.election_state.cur_req_set requires MutableSet.SetOf(prev_req_set) == proposer.election_state.prev_req_set modifies cur_req_set, prev_req_set ensures ProposerIsValid(proposer') ensures LProposerProcessHeartbeat(AbstractifyProposerStateToLProposer(proposer), AbstractifyProposerStateToLProposer(proposer'), AbstractifyCPacketToRslPacket(packet), clock as int) ensures proposer.constants == proposer'.constants ensures MutableSet.SetOf(cur_req_set) == proposer'.election_state.cur_req_set ensures MutableSet.SetOf(prev_req_set) == proposer'.election_state.prev_req_set { var election_state' := ElectionProcessHeartbeat(proposer.election_state, packet, clock, cur_req_set, prev_req_set); var current_state' := 0; var request_queue' := []; var lt := CBalLt(proposer.election_state.current_view, election_state'.current_view); if lt { //assert AbstractifyCBallotToBallot(election_state'.current_view) > AbstractifyCBallotToBallot(proposer.election_state.current_view); current_state' := 0; request_queue' := []; } else { current_state' := proposer.current_state; request_queue' := proposer.request_queue; } proposer' := proposer.(election_state := election_state', current_state := current_state', request_queue := request_queue'); } method ProposerCheckForViewTimeout(proposer:ProposerState, clock:uint64, cur_req_set:MutableSet, prev_req_set:MutableSet) returns (proposer':ProposerState) requires ProposerIsValid(proposer) requires MutableSet.SetOf(cur_req_set) == proposer.election_state.cur_req_set requires MutableSet.SetOf(prev_req_set) == proposer.election_state.prev_req_set modifies cur_req_set, prev_req_set ensures ProposerIsValid(proposer') ensures LProposerCheckForViewTimeout(AbstractifyProposerStateToLProposer(proposer), AbstractifyProposerStateToLProposer(proposer'), clock as int) ensures proposer.constants == proposer'.constants ensures MutableSet.SetOf(cur_req_set) == proposer'.election_state.cur_req_set ensures MutableSet.SetOf(prev_req_set) == proposer'.election_state.prev_req_set { var election_state' := ElectionCheckForViewTimeout(proposer.election_state, clock, cur_req_set, prev_req_set); proposer' := proposer.(election_state := election_state'); } method ProposerCheckForQuorumOfViewSuspicions(proposer:ProposerState, clock:uint64, cur_req_set:MutableSet, prev_req_set:MutableSet) returns (proposer':ProposerState) requires ProposerIsValid(proposer) requires MutableSet.SetOf(cur_req_set) == proposer.election_state.cur_req_set requires MutableSet.SetOf(prev_req_set) == proposer.election_state.prev_req_set modifies cur_req_set, prev_req_set ensures ProposerIsValid(proposer') ensures LProposerCheckForQuorumOfViewSuspicions(AbstractifyProposerStateToLProposer(proposer), AbstractifyProposerStateToLProposer(proposer'), clock as int) ensures proposer.constants == proposer'.constants ensures MutableSet.SetOf(cur_req_set) == proposer'.election_state.cur_req_set ensures MutableSet.SetOf(prev_req_set) == proposer'.election_state.prev_req_set { var start_time := Time.GetDebugTimeTicks(); var election_state' := ElectionCheckForQuorumOfViewSuspicions(proposer.election_state, clock, cur_req_set, prev_req_set); var current_state' := 0; var request_queue' := []; var lt := CBalLt(proposer.election_state.current_view, election_state'.current_view); if lt { current_state' := 0; request_queue' := []; } else { current_state' := proposer.current_state; request_queue' := proposer.request_queue; } proposer' := proposer.(election_state := election_state', current_state := current_state', request_queue := request_queue'); var end_time := Time.GetDebugTimeTicks(); if lt { RecordTimingSeq("ProposerCheckForQuorumOfViewSuspicions_changed", start_time, end_time); } else { RecordTimingSeq("ProposerCheckForQuorumOfViewSuspicions_nada", start_time, end_time); } } method ProposerResetViewTimerDueToExecution(proposer:ProposerState, val:CRequestBatch, cur_req_set:MutableSet, prev_req_set:MutableSet) returns (proposer':ProposerState) requires ProposerIsValid(proposer) requires CRequestBatchIsAbstractable(val) requires ValidRequestBatch(val) requires cur_req_set != prev_req_set requires MutableSet.SetOf(cur_req_set) == proposer.election_state.cur_req_set requires MutableSet.SetOf(prev_req_set) == proposer.election_state.prev_req_set modifies cur_req_set, prev_req_set ensures ProposerIsValid(proposer') ensures LProposerResetViewTimerDueToExecution(AbstractifyProposerStateToLProposer(proposer), AbstractifyProposerStateToLProposer(proposer'), AbstractifyCRequestBatchToRequestBatch(val)) ensures proposer.constants == proposer'.constants ensures MutableSet.SetOf(cur_req_set) == proposer'.election_state.cur_req_set ensures MutableSet.SetOf(prev_req_set) == proposer'.election_state.prev_req_set { var election_state' := ElectionReflectExecutedRequestBatch(proposer.election_state, val, cur_req_set, prev_req_set); proposer' := proposer.(election_state := election_state'); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/RSL/ProposerState.i.dfy ================================================ include "../../Protocol/RSL/Proposer.i.dfy" include "ElectionState.i.dfy" include "ReplicaConstantsState.i.dfy" module LiveRSL__ProposerState_i { import opened Native__Io_s import opened Native__NativeTypes_s import opened LiveRSL__CMessage_i import opened LiveRSL__CMessageRefinements_i import opened LiveRSL__CTypes_i import opened LiveRSL__ElectionState_i import opened LiveRSL__Proposer_i import opened LiveRSL__ReplicaConstantsState_i datatype CIncompleteBatchTimer = CIncompleteBatchTimerOn(when:uint64) | CIncompleteBatchTimerOff() datatype ProposerState = ProposerState( constants:ReplicaConstantsState, current_state:byte, // What state the proposer is in: // 0 = not leader // 1 = leader in phase 1 // 2 = leader in phase 2 request_queue:seq, // Values that clients have requested that I need to eventually // propose, in the order I should propose them max_ballot_i_sent_1a:CBallot, // The maximum ballot I've sent a 1a message for next_operation_number_to_propose:uint64, // The next operation number I should propose received_1b_packets:set, // The set of 1b messages I've received concerning max_ballot_i_sent_1a highest_seqno_requested_by_client_this_view:map, // For each client, the highest sequence number for a request // I proposed in max_ballot_i_sent_1a incomplete_batch_timer:CIncompleteBatchTimer, // If the incomplete batch timer is set, it indicates when I should // give up on trying to amass a full-size batch and just propose // whatever I have. If it's not set, I shouldn't propose an // incomplete batch. election_state:CElectionState, maxOpnWithProposal:COperationNumber, maxLogTruncationPoint:COperationNumber ) // Implied by Received1bPacketsIsModest //predicate Received1bPacketsIsModest(proposer:ProposerState) //{ // |proposer.received_1b_packets| < 0xffffffff_ffffffff //} predicate ProposerIsAbstractable(proposer:ProposerState) { && ReplicaConstantsStateIsAbstractable(proposer.constants) && CRequestsSeqIsAbstractable(proposer.request_queue) && CBallotIsAbstractable(proposer.max_ballot_i_sent_1a) && CPacketsIsAbstractable(proposer.received_1b_packets) && MapOfSeqNumsIsAbstractable(proposer.highest_seqno_requested_by_client_this_view) && CElectionStateIsAbstractable(proposer.election_state) } function AbstractifyCIncompleteBatchTimerToIncompleteBatchTimer(timer:CIncompleteBatchTimer) : IncompleteBatchTimer { match timer { case CIncompleteBatchTimerOn(when) => IncompleteBatchTimerOn(when as int) case CIncompleteBatchTimerOff => IncompleteBatchTimerOff() } } function AbstractifyProposerStateToLProposer(proposer:ProposerState) : LProposer requires ProposerIsAbstractable(proposer) { LProposer(AbstractifyReplicaConstantsStateToLReplicaConstants(proposer.constants), proposer.current_state as int, AbstractifyCRequestsSeqToRequestsSeq(proposer.request_queue), AbstractifyCBallotToBallot(proposer.max_ballot_i_sent_1a), proposer.next_operation_number_to_propose as int, AbstractifySetOfCPacketsToSetOfRslPackets(proposer.received_1b_packets), AbstractifyMapOfSeqNums(proposer.highest_seqno_requested_by_client_this_view), AbstractifyCIncompleteBatchTimerToIncompleteBatchTimer(proposer.incomplete_batch_timer), AbstractifyCElectionStateToElectionState(proposer.election_state)) } predicate RequestQueueValid(queue:seq) { forall i :: 0 <= i < |queue| ==> ValidRequest(queue[i]) } predicate MaxOpnWithProposalInVotes(proposer:ProposerState) { forall p :: p in proposer.received_1b_packets && p.msg.CMessage_1b? ==> MaxOpnWithProposal(proposer, p.msg.votes) } predicate MaxOpnWithProposal(proposer:ProposerState, votes:CVotes) { forall opn :: opn in votes.v ==> opn.n < proposer.maxOpnWithProposal.n } predicate MaxLogTruncationPoint(proposer:ProposerState) { forall p :: p in proposer.received_1b_packets && p.msg.CMessage_1b? ==> p.msg.log_truncation_point.n <= proposer.maxLogTruncationPoint.n } predicate {:opaque} Received1bProperties(received_1b_packets:set, constants:ReplicaConstantsState) { && (forall p :: p in received_1b_packets ==> p.src in constants.all.config.replica_ids) && (forall p1,p2 :: p1 in received_1b_packets && p2 in received_1b_packets && p1.src == p2.src ==> p1 == p2) } predicate ProposerIsValid(proposer:ProposerState) { && ProposerIsAbstractable(proposer) && ReplicaConstantsState_IsValid(proposer.constants) && CElectionStateIsValid(proposer.election_state) && (forall p :: p in proposer.received_1b_packets ==> && p.msg.CMessage_1b? && p.msg.bal_1b == proposer.max_ballot_i_sent_1a // Useful invariant to simplify MaybeEnterPhase2 && ValidVotes(p.msg.votes)) && Received1bProperties(proposer.received_1b_packets, proposer.constants) && RequestQueueValid(proposer.request_queue) && (proposer.current_state == 2 ==> (proposer.maxOpnWithProposal.n < 0xffff_ffff_ffff_ffff ==> MaxOpnWithProposalInVotes(proposer))) && (proposer.current_state == 2 ==> MaxLogTruncationPoint(proposer)) } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/RSL/QRelations.i.dfy ================================================ include "../../Protocol/RSL/Replica.i.dfy" module LiveRSL__QRelations_i { import opened LiveRSL__ClockReading_i import opened LiveRSL__Environment_i import opened LiveRSL__Replica_i // This file defines opaque (Q_*) versions of high-level protocol relations // to reduce the definition space available to combinatorially-challenged // methods in ReplicaImpl. predicate AllIosAreSends(ios:seq) { forall i :: 0<=i<|ios| ==> ios[i].LIoOpSend? } ////////////////////////////////////////////////////////////////////////////// predicate {:opaque} Q_LReplica_Next_Process_Invalid(replica:LReplica, replica':LReplica, lpacket:RslPacket, sent_packets:seq) { lpacket.msg.RslMessage_Invalid? && LReplicaNextProcessInvalid(replica, replica', lpacket, sent_packets) } predicate {:opaque} Q_LReplica_Next_Process_Request(replica:LReplica, replica':LReplica, lpacket:RslPacket, sent_packets:seq) { lpacket.msg.RslMessage_Request? && LReplicaNextProcessRequest(replica, replica', lpacket, sent_packets) } predicate {:opaque} Q_LReplica_Next_Process_1a(replica:LReplica, replica':LReplica, lpacket:RslPacket, sent_packets:seq) { lpacket.msg.RslMessage_1a? && LReplicaNextProcess1a(replica, replica', lpacket, sent_packets) } predicate {:opaque} Q_LReplica_Next_Process_1b(replica:LReplica, replica':LReplica, lpacket:RslPacket, sent_packets:seq) { lpacket.msg.RslMessage_1b? && LReplicaNextProcess1b(replica, replica', lpacket, sent_packets) } predicate {:opaque} Q_LReplica_Next_Process_StartingPhase2(replica:LReplica, replica':LReplica, lpacket:RslPacket, sent_packets:seq) { lpacket.msg.RslMessage_StartingPhase2? && LReplicaNextProcessStartingPhase2(replica, replica', lpacket, sent_packets) } predicate {:opaque} Q_LReplica_Next_Process_2a(replica:LReplica, replica':LReplica, lpacket:RslPacket, sent_packets:seq) { lpacket.msg.RslMessage_2a? && LReplicaNextProcess2a(replica, replica', lpacket, sent_packets) } predicate {:opaque} Q_LReplica_Next_Process_2b(replica:LReplica, replica':LReplica, lpacket:RslPacket, sent_packets:seq) { lpacket.msg.RslMessage_2b? && LReplicaNextProcess2b(replica, replica', lpacket, sent_packets) } // TODO move this definition into Replica.i predicate {:opaque} Q_LReplica_Next_Process_Reply(replica:LReplica, replica':LReplica, lpacket:RslPacket, sent_packets:seq) { lpacket.msg.RslMessage_Reply? && LReplicaNextProcessReply(replica, replica', lpacket, sent_packets) } predicate {:opaque} Q_LReplica_Next_Process_AppStateRequest(replica:LReplica, replica':LReplica, lpacket:RslPacket, sent_packets:seq) { lpacket.msg.RslMessage_AppStateRequest? && LReplicaNextProcessAppStateRequest(replica, replica', lpacket, sent_packets) } predicate {:opaque} Q_LReplica_Next_Process_AppStateSupply(replica:LReplica, replica':LReplica, lpacket:RslPacket, sent_packets:seq) { lpacket.msg.RslMessage_AppStateSupply? && LReplicaNextProcessAppStateSupply(replica, replica', lpacket, sent_packets) } predicate LReplica_Next_ProcessPacketWithoutReadingClock_preconditions(ios:seq) { && |ios| >= 1 && ios[0].LIoOpReceive? && !ios[0].r.msg.RslMessage_Heartbeat? } predicate {:opaque} Q_LReplica_Next_ProcessPacketWithoutReadingClock(replica:LReplica, replica':LReplica, ios:seq) { && LReplica_Next_ProcessPacketWithoutReadingClock_preconditions(ios) && LReplicaNextProcessPacketWithoutReadingClock(replica, replica', ios) } predicate Establish_Q_LReplica_Next_ProcessPacketWithoutReadingClock_preconditions(replica:LReplica, replica':LReplica, lpacket:RslPacket, sent_packets:seq, ios:seq) { && sent_packets == ExtractSentPacketsFromIos(ios) // && clock == SpontaneousClock(ios) && (|| (lpacket.msg.RslMessage_Request? && Q_LReplica_Next_Process_Request(replica, replica', lpacket, sent_packets)) || (lpacket.msg.RslMessage_1a? && Q_LReplica_Next_Process_1a(replica, replica', lpacket, sent_packets)) || (lpacket.msg.RslMessage_1b? && Q_LReplica_Next_Process_1b(replica, replica', lpacket, sent_packets)) || (lpacket.msg.RslMessage_StartingPhase2? && Q_LReplica_Next_Process_StartingPhase2(replica, replica', lpacket, sent_packets)) || (lpacket.msg.RslMessage_2a? && Q_LReplica_Next_Process_2a(replica, replica', lpacket, sent_packets)) || (lpacket.msg.RslMessage_2b? && Q_LReplica_Next_Process_2b(replica, replica', lpacket, sent_packets)) || (lpacket.msg.RslMessage_Reply? && Q_LReplica_Next_Process_Reply(replica, replica', lpacket, sent_packets)) || (lpacket.msg.RslMessage_AppStateRequest? && Q_LReplica_Next_Process_AppStateRequest(replica, replica', lpacket, sent_packets)) || (lpacket.msg.RslMessage_AppStateSupply? && Q_LReplica_Next_Process_AppStateSupply(replica, replica', lpacket, sent_packets))) && sent_packets == ExtractSentPacketsFromIos(ios) } lemma lemma_EstablishQLReplicaNextProcessPacketWithoutReadingClock(replica:LReplica, replica':LReplica, lpacket:RslPacket, sent_packets:seq, ios:seq) requires |ios| >= 1 requires ios[0].LIoOpReceive? requires !ios[0].r.msg.RslMessage_Heartbeat? requires lpacket == ios[0].r requires AllIosAreSends(ios[1..]) requires sent_packets == ExtractSentPacketsFromIos(ios) requires Establish_Q_LReplica_Next_ProcessPacketWithoutReadingClock_preconditions(replica, replica', lpacket, sent_packets, ios) ensures Q_LReplica_Next_ProcessPacketWithoutReadingClock(replica, replica', ios) { reveal Q_LReplica_Next_Process_Invalid(); reveal Q_LReplica_Next_Process_Request(); reveal Q_LReplica_Next_Process_1a(); reveal Q_LReplica_Next_Process_1b(); reveal Q_LReplica_Next_Process_StartingPhase2(); reveal Q_LReplica_Next_Process_2a(); reveal Q_LReplica_Next_Process_2b(); reveal Q_LReplica_Next_Process_Reply(); reveal Q_LReplica_Next_Process_AppStateRequest(); reveal Q_LReplica_Next_Process_AppStateSupply(); reveal Q_LReplica_Next_ProcessPacketWithoutReadingClock(); } ////////////////////////////////////////////////////////////////////////////// predicate {:opaque} Q_LReplica_Next_Spontaneous_MaybeEnterNewViewAndSend1a(replica:LReplica, replica':LReplica, sent_packets:seq) { LReplicaNextSpontaneousMaybeEnterNewViewAndSend1a(replica, replica', sent_packets) } predicate {:opaque} Q_LReplica_Next_Spontaneous_MaybeEnterPhase2(replica:LReplica, replica':LReplica, sent_packets:seq) { LReplicaNextSpontaneousMaybeEnterPhase2(replica, replica', sent_packets) } predicate {:opaque} Q_LReplica_Next_Spontaneous_TruncateLogBasedOnCheckpoints(replica:LReplica, replica':LReplica, sent_packets:seq) { LReplicaNextSpontaneousTruncateLogBasedOnCheckpoints(replica, replica', sent_packets) } predicate {:opaque} Q_LReplica_Next_Spontaneous_MaybeMakeDecision(replica:LReplica, replica':LReplica, sent_packets:seq) { LReplicaNextSpontaneousMaybeMakeDecision(replica, replica', sent_packets) } predicate {:opaque} Q_LReplica_Next_Spontaneous_MaybeExecute(replica:LReplica, replica':LReplica, sent_packets:seq) { LReplicaNextSpontaneousMaybeExecute(replica, replica', sent_packets) } lemma lemma_EstablishQLReplicaNoReceiveNextFromNoClock(replica:LReplica, replica':LReplica, sent_packets:seq, nextActionIndex:int, ios:seq) requires sent_packets == ExtractSentPacketsFromIos(ios) requires SpontaneousIos(ios, 0) requires || (nextActionIndex==1 && Q_LReplica_Next_Spontaneous_MaybeEnterNewViewAndSend1a(replica, replica', sent_packets)) || (nextActionIndex==2 && Q_LReplica_Next_Spontaneous_MaybeEnterPhase2(replica, replica', sent_packets)) // || (nextActionIndex==4 && Q_LReplica_Next_Spontaneous_TruncateLogBasedOnCheckpoints(replica, replica', sent_packets)) || (nextActionIndex==5 && Q_LReplica_Next_Spontaneous_MaybeMakeDecision(replica, replica', sent_packets)) || (nextActionIndex==6 && Q_LReplica_Next_Spontaneous_MaybeExecute(replica, replica', sent_packets)); ensures Q_LReplica_NoReceive_Next(replica, nextActionIndex as int, replica', ios) { reveal Q_LReplica_Next_Spontaneous_MaybeEnterNewViewAndSend1a(); reveal Q_LReplica_Next_Spontaneous_MaybeEnterPhase2(); //reveal Q_LReplica_Next_Spontaneous_MaybeNominateValueAndSend2a(); reveal Q_LReplica_Next_Spontaneous_TruncateLogBasedOnCheckpoints(); reveal Q_LReplica_Next_Spontaneous_MaybeMakeDecision(); reveal Q_LReplica_Next_Spontaneous_MaybeExecute(); assert LReplicaNoReceiveNext(replica, nextActionIndex as int, replica', ios); reveal Q_LReplica_NoReceive_Next(); assert Q_LReplica_NoReceive_Next(replica, nextActionIndex as int, replica', ios); } ////////////////////////////////////////////////////////////////////////////// predicate {:opaque} Q_LReplica_Next_ReadClock_MaybeNominateValueAndSend2a(replica:LReplica, replica':LReplica, clock:ClockReading, sent_packets:seq) { LReplicaNextReadClockMaybeNominateValueAndSend2a(replica, replica', clock, sent_packets) } predicate {:opaque} Q_LReplica_Next_ReadClock_CheckForViewTimeout(replica:LReplica, replica':LReplica, clock:ClockReading, sent_packets:seq) { LReplicaNextReadClockCheckForViewTimeout(replica, replica', clock, sent_packets) } predicate {:opaque} Q_LReplica_Next_ReadClock_CheckForQuorumOfViewSuspicions(replica:LReplica, replica':LReplica, clock:ClockReading, sent_packets:seq) { LReplicaNextReadClockCheckForQuorumOfViewSuspicions(replica, replica', clock, sent_packets) } predicate {:opaque} Q_LReplica_Next_ReadClock_MaybeSendHeartbeat(replica:LReplica, replica':LReplica, clock:ClockReading, sent_packets:seq) { LReplicaNextReadClockMaybeSendHeartbeat(replica, replica', clock, sent_packets) } predicate {:opaque} Q_LReplica_NoReceive_Next(replica:LReplica, nextActionIndex:int, replica':LReplica, ios:seq) { LReplicaNoReceiveNext(replica, nextActionIndex, replica', ios) } predicate {:opaque} Q_LReplica_Next_ProcessPacket(replica:LReplica, replica':LReplica, ios:seq) { LReplicaNextProcessPacket(replica, replica', ios) } lemma lemma_EstablishQLReplicaNextProcessPacket(replica:LReplica, replica':LReplica, ios:seq) requires Q_LReplica_Next_ProcessPacketWithoutReadingClock(replica, replica', ios) ensures Q_LReplica_Next_ProcessPacket(replica, replica', ios) { reveal Q_LReplica_Next_ProcessPacketWithoutReadingClock(); reveal Q_LReplica_Next_ProcessPacket(); } lemma lemma_EstablishQLReplicaNextProcessPacketFromTimeout(replica:LReplica, replica':LReplica, ios:seq) requires |ios|==1 requires ios[0].LIoOpTimeoutReceive? requires replica==replica' ensures Q_LReplica_Next_ProcessPacket(replica, replica', ios) { reveal Q_LReplica_Next_ProcessPacket(); } predicate {:opaque} Q_LScheduler_Next(s:LScheduler, s':LScheduler, ios:seq) { LSchedulerNext(s, s', ios) } predicate Establish_Q_LReplica_NoReceive_Next_preconditions(replica:LReplica, replica':LReplica, clock:ClockReading, sent_packets:seq, nextActionIndex:int, ios:seq) { && SpontaneousIos(ios, 1) && sent_packets == ExtractSentPacketsFromIos(ios) && clock == SpontaneousClock(ios) && (|| (nextActionIndex==3 && Q_LReplica_Next_ReadClock_MaybeNominateValueAndSend2a(replica, replica', clock, sent_packets)) || (nextActionIndex==7 && Q_LReplica_Next_ReadClock_CheckForViewTimeout(replica, replica', clock, sent_packets)) || (nextActionIndex==8 && Q_LReplica_Next_ReadClock_CheckForQuorumOfViewSuspicions(replica, replica', clock, sent_packets)) || (nextActionIndex==9 && Q_LReplica_Next_ReadClock_MaybeSendHeartbeat(replica, replica', clock, sent_packets))) && sent_packets == ExtractSentPacketsFromIos(ios) } lemma lemma_EstablishQLReplicaNoReceiveNextFromReadClock(replica:LReplica, replica':LReplica, clock:ClockReading, sent_packets:seq, nextActionIndex:int, ios:seq) requires Establish_Q_LReplica_NoReceive_Next_preconditions(replica, replica', clock, sent_packets, nextActionIndex, ios) ensures Q_LReplica_NoReceive_Next(replica, nextActionIndex, replica', ios) { reveal Q_LReplica_Next_ReadClock_CheckForViewTimeout(); reveal Q_LReplica_Next_ReadClock_CheckForQuorumOfViewSuspicions(); reveal Q_LReplica_Next_ReadClock_MaybeSendHeartbeat(); reveal Q_LReplica_Next_ReadClock_MaybeNominateValueAndSend2a(); reveal Q_LReplica_NoReceive_Next(); // if (nextActionIndex==7) // { // assert SpontaneousIos(ios, 1); // assert LReplicaNextReadClockCheckForViewTimeout(replica, replica', clock, sent_packets); // assert LReplicaNoReceiveNext(replica, nextActionIndex, replica', ios); // } // if (nextActionIndex==8) // { // assert SpontaneousIos(ios, 1); // assert LReplicaNextReadClockCheckForQuorumOfViewSuspicions(replica, replica', clock, sent_packets); // assert LReplicaNoReceiveNext(replica, nextActionIndex, replica', ios); // } // if (nextActionIndex==9) // { // assert SpontaneousIos(ios, 1); // assert LReplicaNextReadClockMaybeSendHeartbeat(replica, replica', clock, sent_packets); // assert LReplicaNoReceiveNext(replica, nextActionIndex, replica', ios); // } } lemma lemma_EstablishQLSchedulerNext(replica:LReplica, replica':LReplica, ios:seq, s:LScheduler, s':LScheduler) requires 0<=s.nextActionIndex<=9 requires 0==s.nextActionIndex ==> Q_LReplica_Next_ProcessPacket(replica, replica', ios) requires 0< s.nextActionIndex<=6 ==> Q_LReplica_NoReceive_Next(replica, s.nextActionIndex, replica', ios) requires 6< s.nextActionIndex<=9 ==> Q_LReplica_NoReceive_Next(replica, s.nextActionIndex, replica', ios) requires s.replica == replica requires s'.replica == replica' requires s'.nextActionIndex == (s.nextActionIndex+1)%LReplicaNumActions() ensures Q_LScheduler_Next(s, s', ios) { reveal Q_LReplica_Next_ProcessPacket(); reveal Q_LReplica_NoReceive_Next(); // if (0==s.nextActionIndex) { // assert LReplicaNextProcessPacket(s.replica, s'.replica, ios); // assert LSchedulerNext(s, s', ios); // } else { // if (0< s.nextActionIndex<=6) { // assert Q_LReplica_NoReceive_Next(replica, s.nextActionIndex, replica', ios); // assert LReplicaNoReceiveNext(replica, s.nextActionIndex, replica', ios); // assert LSchedulerNext(s, s', ios); // } else if (6< s.nextActionIndex<=9) { // assert Q_LReplica_NoReceive_Next(replica, s.nextActionIndex, replica', ios); // assert LReplicaNoReceiveNext(replica, s.nextActionIndex, replica', ios); // assert LSchedulerNext(s, s', ios); // } else { // assert false; // } // } // assert LSchedulerNext(s, s', ios); reveal Q_LScheduler_Next(); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/RSL/ReplicaConstantsState.i.dfy ================================================ include "ConstantsState.i.dfy" include "PaxosWorldState.i.dfy" // For those that still depend on it; should be deprecated away. module LiveRSL__ReplicaConstantsState_i { import opened LiveRSL__Constants_i import opened LiveRSL__ConstantsState_i import opened LiveRSL__CPaxosConfiguration_i import opened LiveRSL__ParametersState_i import opened LiveRSL__PaxosWorldState_i import opened Native__Io_s import opened Native__NativeTypes_s datatype ReplicaConstantsState = ReplicaConstantsState( my_index:uint64, all:ConstantsState) predicate ReplicaConstantsStateIsAbstractable(rc:ReplicaConstantsState) { && ConstantsStateIsAbstractable(rc.all) && ReplicaIndexValid(rc.my_index, rc.all.config) } function AbstractifyReplicaConstantsStateToLReplicaConstants(rc:ReplicaConstantsState) : LReplicaConstants requires ReplicaConstantsStateIsAbstractable(rc) { LReplicaConstants(rc.my_index as int, AbstractifyConstantsStateToLConstants(rc.all)) } predicate ReplicaConstantsState_IsValid(rcs:ReplicaConstantsState) { && ConstantsStateIsValid(rcs.all) && ReplicaConstantsStateIsAbstractable(rcs) } method InitReplicaConstantsState(endPoint:EndPoint, config:CPaxosConfiguration) returns (rc:ReplicaConstantsState) requires CPaxosConfigurationIsValid(config) requires PaxosEndPointIsValid(endPoint, config) requires endPoint in config.replica_ids // To satisfy WFReplicaConstantsState ensures ReplicaConstantsState_IsValid(rc) ensures rc.all.config.replica_ids[rc.my_index] == endPoint ensures rc.all.config == config ensures rc.all.params.max_integer_val > rc.all.params.max_log_length > 0 ensures rc.all.params.max_log_length < 10000 ensures rc.all.params == StaticParams() { var params := StaticParams(); //var config := CPaxosConfiguration(world.config.replica_ids); var constants := ConstantsState(config, params); var found, index := CGetReplicaIndex(endPoint, config); rc := ReplicaConstantsState(index, constants); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/RSL/ReplicaImplClass.i.dfy ================================================ include "../../Common/Collections/Seqs.i.dfy" include "../../../Libraries/Math/mod_auto.i.dfy" include "../../Protocol/RSL/Replica.i.dfy" include "ReplicaModel.i.dfy" include "ReplicaImplLemmas.i.dfy" include "NetRSL.i.dfy" include "CClockReading.i.dfy" module LiveRSL__ReplicaImplClass_i { import opened Native__Io_s import opened Native__NativeTypes_s import opened Collections__Seqs_i import opened Math__mod_auto_i import opened LiveRSL__AcceptorState_i import opened LiveRSL__AppInterface_i import opened LiveRSL__CClockReading_i import opened LiveRSL__CLastCheckpointedMap_i import opened LiveRSL__CMessage_i import opened LiveRSL__CMessageRefinements_i import opened LiveRSL__ConstantsState_i import opened LiveRSL__CPaxosConfiguration_i import opened LiveRSL__Configuration_i import opened LiveRSL__CTypes_i import opened LiveRSL__ElectionState_i import opened LiveRSL__Environment_i import opened LiveRSL__ExecutorState_i import opened LiveRSL__LearnerState_i import opened LiveRSL__PacketParsing_i import opened LiveRSL__ParametersState_i import opened LiveRSL__ProposerState_i import opened LiveRSL__Replica_i import opened LiveRSL__ReplicaConstantsState_i import opened LiveRSL__ReplicaModel_i import opened LiveRSL__ReplicaModel_Part1_i import opened LiveRSL__ReplicaState_i import opened LiveRSL__ReplicaImplLemmas_i import opened LiveRSL__Types_i import opened LiveRSL__NetRSL_i import opened Common__GenericMarshalling_i import opened Common__NetClient_i import opened Common__Util_i import opened AppStateMachine_s class ReplicaImpl { var replica:ReplicaState; var nextActionIndex:uint64; var netClient:NetClient?; var localAddr:EndPoint; // Optimized mutable sets for ElectionState var cur_req_set:MutableSet; var prev_req_set:MutableSet; var reply_cache_mutable:MutableMap; var msg_grammar:G; ghost var Repr : set; constructor() { netClient := null; var empty_MutableMap:MutableMap := MutableMap.EmptyMap(); reply_cache_mutable := empty_MutableMap; var empty_MutableSet:MutableSet := MutableSet.EmptySet(); cur_req_set := empty_MutableSet; prev_req_set := empty_MutableSet; var rcs := ReplicaConstantsState(0, ConstantsState(CPaxosConfiguration([]), ParametersState(0, 0, 0, 0, 0, 0))); var election_state := CElectionState(rcs, CBallot(0, 0), [], 0, 0, [], {}, [], {}); var proposer_state := ProposerState(rcs, 0, [], CBallot(0, 0), 0, {}, map [], CIncompleteBatchTimerOff(), election_state, COperationNumber(0), COperationNumber(0)); var acceptor_state := AcceptorState(rcs, CBallot(0, 0), CVotes(map []), [], COperationNumber(0), COperationNumber(0)); var ep := EndPoint([]); var learner_state := CLearnerState(rcs, CBallot(0, 0), map [], false, COperationNumber(0), false, CPacket(ep, ep, CMessage_Invalid())); var app_state := AppStateMachine.Initialize(); var executor_state := ExecutorState(rcs, app_state, COperationNumber(0), CBallot(0, 0), COutstandingOpUnknown(), map[]); replica := ReplicaState(rcs, 0, proposer_state, acceptor_state, learner_state, executor_state); } predicate Valid() reads this reads this.replica.executor.app reads this.cur_req_set reads this.prev_req_set reads this.reply_cache_mutable reads if netClient != null then NetClientIsValid.reads(netClient) else {} { && ReplicaStateIsAbstractable(replica) && (0 <= nextActionIndex as int < 10) && netClient != null && NetClientIsValid(netClient) && EndPoint(netClient.MyPublicKey()) == localAddr && EndPoint(netClient.MyPublicKey()) == replica.constants.all.config.replica_ids[replica.constants.my_index] && ReplicaStateIsValid(replica) && Repr == { this } + NetClientRepr(netClient) && cur_req_set != prev_req_set && MutableSet.SetOf(cur_req_set) == replica.proposer.election_state.cur_req_set && MutableSet.SetOf(prev_req_set) == replica.proposer.election_state.prev_req_set && MutableMap.MapOf(reply_cache_mutable) == replica.executor.reply_cache && msg_grammar == CMessage_grammar() } function Env() : HostEnvironment requires netClient != null reads this, NetClientIsValid.reads(netClient) { netClient.env } function AbstractifyToLReplica() : LReplica reads this reads this.replica.executor.app requires ReplicaStateIsAbstractable(replica) { AbstractifyReplicaStateToLReplica(replica) } function AbstractifyToLScheduler() : LScheduler reads this reads this.replica.executor.app requires ReplicaStateIsAbstractable(replica) { LScheduler( AbstractifyReplicaStateToLReplica(replica), nextActionIndex as int) } method Replica_Init( constants:ReplicaConstantsState, nc:NetClient, ghost env_:HostEnvironment ) returns ( ok:bool ) requires env_.Valid() && env_.ok.ok() requires ReplicaConstantsState_IsValid(constants) requires WellFormedLConfiguration(AbstractifyReplicaConstantsStateToLReplicaConstants(constants).all.config) requires NetClientIsValid(nc) requires EndPoint(nc.MyPublicKey()) == constants.all.config.replica_ids[constants.my_index] requires nc.env == env_ //requires KnownSendersMatchConfig(constants.all.config) modifies this ensures ok ==> && Valid() && Env() == env_ && this.replica.constants == constants && LSchedulerInit(AbstractifyToLScheduler(), AbstractifyReplicaConstantsStateToLReplicaConstants(constants)) { netClient := nc; replica, cur_req_set, prev_req_set, reply_cache_mutable := InitReplicaState(constants); nextActionIndex := 0; localAddr := replica.constants.all.config.replica_ids[replica.constants.my_index]; Repr := { this } + NetClientRepr(netClient); this.msg_grammar := CMessage_grammar(); ok := true; } predicate ReceivedPacketProperties(cpacket:CPacket, netEvent0:NetEvent, io0:RslIo) reads this requires CPaxosConfigurationIsValid(replica.constants.all.config) { && CPacketIsSendable(cpacket) && PaxosEndPointIsValid(cpacket.src, replica.constants.all.config) && io0.LIoOpReceive? && NetEventIsAbstractable(netEvent0) && io0 == AbstractifyNetEventToRslIo(netEvent0) && NetEventIsAbstractable(netEvent0) && netEvent0.LIoOpReceive? && AbstractifyCPacketToRslPacket(cpacket) == AbstractifyNetPacketToRslPacket(netEvent0.r) } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/RSL/ReplicaImplDelivery.i.dfy ================================================ include "../../Common/Collections/Seqs.i.dfy" include "../../../Libraries/Math/mod_auto.i.dfy" include "../../Protocol/RSL/Replica.i.dfy" include "ReplicaModel.i.dfy" include "ReplicaImplLemmas.i.dfy" include "ReplicaImplClass.i.dfy" include "NetRSL.i.dfy" include "CClockReading.i.dfy" module LiveRSL__ReplicaImplDelivery_i { import opened Native__Io_s import opened Native__NativeTypes_s import opened Collections__Seqs_i import opened Math__mod_auto_i import opened LiveRSL__CClockReading_i import opened LiveRSL__CMessage_i import opened LiveRSL__CMessageRefinements_i import opened LiveRSL__CTypes_i import opened LiveRSL__Environment_i import opened LiveRSL__PacketParsing_i import opened LiveRSL__Replica_i import opened LiveRSL__ReplicaModel_i import opened LiveRSL__ReplicaImplLemmas_i import opened LiveRSL__ReplicaImplClass_i import opened LiveRSL__QRelations_i import opened LiveRSL__Types_i import opened LiveRSL__NetRSL_i import opened Common__NodeIdentity_i import opened Common__NetClient_i import opened Common__Util_i import opened Environment_s method DeliverPacket(r:ReplicaImpl, packets:OutboundPackets) returns (ok:bool, ghost netEventLog:seq, ghost ios:seq) requires r.Valid() requires packets.OutboundPacket? requires OutboundPacketsIsValid(packets) requires OutboundPacketsHasCorrectSrc(packets, r.replica.constants.all.config.replica_ids[r.replica.constants.my_index]) modifies r.Repr ensures r.Repr == old(r.Repr) ensures r.netClient != null ensures ok == NetClientOk(r.netClient) ensures r.Env() == old(r.Env()) ensures r.replica == old(r.replica) ensures ok ==> && r.Valid() && r.nextActionIndex == old(r.nextActionIndex) && AllIosAreSends(ios) && AbstractifyOutboundCPacketsToSeqOfRslPackets(packets) == ExtractSentPacketsFromIos(ios) && OnlySentMarshallableData(netEventLog) && RawIoConsistentWithSpecIO(netEventLog, ios) && old(r.Env().net.history()) + netEventLog == r.Env().net.history() { var start_time := Time.GetDebugTimeTicks(); ok, netEventLog := SendPacket(r.netClient, packets, r.localAddr); if (!ok) { return; } ios := MapSentPacketToIos(packets.p); lemma_MapSentPacketToIosExtractSentPacketsFromIosEquivalence(packets.p, ios); var end_time := Time.GetDebugTimeTicks(); if packets.p.None? { RecordTimingSeq("DeliverPacketEmpty", start_time, end_time); } else { RecordTimingSeq("DeliverPacketSingleton", start_time, end_time); } } method {:timeLimitMultiplier 2} DeliverPacketSequence(r:ReplicaImpl, packets:OutboundPackets) returns (ok:bool, ghost netEventLog:seq, ghost ios:seq) requires r.Valid() requires packets.PacketSequence? requires OutboundPacketsIsValid(packets) requires OutboundPacketsIsAbstractable(packets) requires OutboundPacketsHasCorrectSrc(packets, r.replica.constants.all.config.replica_ids[r.replica.constants.my_index]) modifies r.Repr ensures r.Repr == old(r.Repr) ensures r.netClient != null ensures ok == NetClientOk(r.netClient) ensures r.Env() == old(r.Env()) ensures r.replica == old(r.replica) ensures ok ==> && r.Valid() && r.nextActionIndex == old(r.nextActionIndex) && AllIosAreSends(ios) && AbstractifyOutboundCPacketsToSeqOfRslPackets(packets) == ExtractSentPacketsFromIos(ios) && OnlySentMarshallableData(netEventLog) && RawIoConsistentWithSpecIO(netEventLog, ios) && old(r.Env().net.history()) + netEventLog == r.Env().net.history() { var start_time := Time.GetDebugTimeTicks(); ok, netEventLog := SendPacketSequence(r.netClient, packets, r.localAddr); if (!ok) { return; } ios := MapSentPacketSeqToIos(packets.s); lemma_MapSentPacketSeqToIosExtractSentPacketsFromIosEquivalence(packets, ios); var end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("DeliverPacketSequence", start_time, end_time); } method{:timeLimitMultiplier 2} DeliverBroadcast(r:ReplicaImpl, broadcast:CBroadcast) returns (ok:bool, ghost netEventLog:seq, ghost ios:seq) requires r.Valid() requires CBroadcastIsValid(broadcast) requires broadcast.CBroadcast? ==> broadcast.src == r.replica.constants.all.config.replica_ids[r.replica.constants.my_index]; modifies r.Repr ensures r.Repr == old(r.Repr) ensures r.netClient != null ensures ok == NetClientOk(r.netClient) ensures r.Env() == old(r.Env()) ensures r.replica == old(r.replica) ensures ok ==> && r.Valid() && r.nextActionIndex == old(r.nextActionIndex) && AllIosAreSends(ios) && AbstractifyCBroadcastToRlsPacketSeq(broadcast) == ExtractSentPacketsFromIos(ios) && OnlySentMarshallableData(netEventLog) && RawIoConsistentWithSpecIO(netEventLog, ios) && old(r.Env().net.history()) + netEventLog == r.Env().net.history() { var start_time := Time.GetDebugTimeTicks(); ok, netEventLog := SendBroadcast(r.netClient, broadcast, r.localAddr); if (!ok) { return; } ios := MapBroadcastToIos(broadcast); lemma_MapBroadcastToIosExtractSentPacketsFromIosEquivalence(broadcast, ios); lemma_NetEventLogToBroadcastRefinable(netEventLog, broadcast); assert NetEventLogIsAbstractable(netEventLog); if broadcast.CBroadcastNop? { assert RawIoConsistentWithSpecIO(netEventLog, ios); } else { ghost var broadcast_ios := BuildBroadcastIos(AbstractifyEndPointToNodeIdentity(broadcast.src), AbstractifyEndPointsToNodeIdentities(broadcast.dsts), AbstractifyCMessageToRslMessage(broadcast.msg)); calc { AbstractifyRawLogToIos(netEventLog); { forall i | 0 <= i < |AbstractifyRawLogToIos(netEventLog)| ensures AbstractifyRawLogToIos(netEventLog)[i] == LIoOpSend(LPacket(AbstractifyEndPointsToNodeIdentities(broadcast.dsts)[i], AbstractifyEndPointToNodeIdentity(broadcast.src), AbstractifyCMessageToRslMessage(broadcast.msg))) { calc { AbstractifyRawLogToIos(netEventLog)[i]; AbstractifyNetEventToRslIo(netEventLog[i]); { lemma_NetEventLogToBroadcast(netEventLog, broadcast, i); } LIoOpSend(AbstractifyCBroadcastToRlsPacketSeq(broadcast)[i]); LIoOpSend(BuildLBroadcast(AbstractifyEndPointToNodeIdentity(broadcast.src), AbstractifyEndPointsToNodeIdentities(broadcast.dsts), AbstractifyCMessageToRslMessage(broadcast.msg))[i]); LIoOpSend(LPacket(AbstractifyEndPointsToNodeIdentities(broadcast.dsts)[i], AbstractifyEndPointToNodeIdentity(broadcast.src), AbstractifyCMessageToRslMessage(broadcast.msg))); } } forall i | 0 <= i < |broadcast_ios| ensures broadcast_ios[i] == LIoOpSend(LPacket(AbstractifyEndPointsToNodeIdentities(broadcast.dsts)[i], AbstractifyEndPointToNodeIdentity(broadcast.src), AbstractifyCMessageToRslMessage(broadcast.msg))) { calc { LIoOpSend(LPacket(AbstractifyEndPointsToNodeIdentities(broadcast.dsts)[i], AbstractifyEndPointToNodeIdentity(broadcast.src), AbstractifyCMessageToRslMessage(broadcast.msg))); BuildBroadcastIos(AbstractifyEndPointToNodeIdentity(broadcast.src), AbstractifyEndPointsToNodeIdentities(broadcast.dsts), AbstractifyCMessageToRslMessage(broadcast.msg))[i]; broadcast_ios[i]; } } } broadcast_ios; BuildBroadcastIos(AbstractifyEndPointToNodeIdentity(broadcast.src), AbstractifyEndPointsToNodeIdentities(broadcast.dsts), AbstractifyCMessageToRslMessage(broadcast.msg)); MapBroadcastToIos(broadcast); ios; } assert RawIoConsistentWithSpecIO(netEventLog, ios); } var end_time := Time.GetDebugTimeTicks(); if broadcast.CBroadcastNop? || (broadcast.CBroadcast? && |broadcast.dsts| as uint64 == 0) { RecordTimingSeq("DeliverBroadcastEmpty", start_time, end_time); } else if broadcast.CBroadcast? && |broadcast.dsts| as uint64 == 1 { RecordTimingSeq("DeliverBroadcastSingleton", start_time, end_time); } else { RecordTimingSeq("DeliverBroadcastMany", start_time, end_time); } } method DeliverOutboundPackets(r:ReplicaImpl, packets:OutboundPackets) returns (ok:bool, ghost netEventLog:seq, ghost ios:seq) requires r.Valid() requires OutboundPacketsIsValid(packets) requires OutboundPacketsIsAbstractable(packets) requires OutboundPacketsHasCorrectSrc(packets, r.replica.constants.all.config.replica_ids[r.replica.constants.my_index]); modifies r.Repr ensures r.Repr == old(r.Repr) ensures r.netClient != null ensures ok == NetClientOk(r.netClient) ensures r.Env() == old(r.Env()) ensures r.replica == old(r.replica) ensures ok ==> && r.Valid() && r.nextActionIndex == old(r.nextActionIndex) && AllIosAreSends(ios) && AbstractifyOutboundCPacketsToSeqOfRslPackets(packets) == ExtractSentPacketsFromIos(ios) && OnlySentMarshallableData(netEventLog) && RawIoConsistentWithSpecIO(netEventLog, ios) && OnlySentMarshallableData(netEventLog) && old(r.Env().net.history()) + netEventLog == r.Env().net.history() { match packets { case Broadcast(broadcast) => ok, netEventLog, ios := DeliverBroadcast(r, broadcast); case OutboundPacket(p) => ok, netEventLog, ios := DeliverPacket(r, packets); case PacketSequence(s) => ok, netEventLog, ios := DeliverPacketSequence(r, packets); } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/RSL/ReplicaImplLemmas.i.dfy ================================================ include "../../Common/Collections/Seqs.i.dfy" include "../../Common/Framework/Environment.s.dfy" include "../../../Libraries/Math/mod_auto.i.dfy" include "../../Protocol/RSL/Replica.i.dfy" include "ReplicaModel.i.dfy" include "NetRSL.i.dfy" include "CClockReading.i.dfy" include "QRelations.i.dfy" module LiveRSL__ReplicaImplLemmas_i { import opened Native__Io_s import opened Native__NativeTypes_s import opened Collections__Seqs_i import opened Math__mod_auto_i import opened LiveRSL__CClockReading_i import opened LiveRSL__ClockReading_i import opened LiveRSL__CMessage_i import opened LiveRSL__CMessageRefinements_i import opened LiveRSL__Environment_i import opened LiveRSL__Message_i import opened LiveRSL__PacketParsing_i import opened LiveRSL__QRelations_i import opened LiveRSL__Replica_i import opened LiveRSL__ReplicaModel_i import opened LiveRSL__ReplicaState_i import opened LiveRSL__NetRSL_i import opened Common__NodeIdentity_i import opened Concrete_NodeIdentity_i import opened Logic__Option_i import opened Environment_s function MapSentPacketToIos(sent_packet:Option) : seq requires OutboundPacketsIsValid(OutboundPacket(sent_packet)) { match sent_packet { case Some(p) => [LIoOpSend(AbstractifyCPacketToRslPacket(p))] case None => [] } } function {:opaque} MapSentPacketSeqToIos(sent_packets:seq) : seq requires OutboundPacketsIsValid(PacketSequence(sent_packets)) requires OutboundPacketsIsAbstractable(PacketSequence(sent_packets)) ensures |MapSentPacketSeqToIos(sent_packets)| == |sent_packets| ensures forall i :: 0 <= i < |sent_packets| ==> MapSentPacketSeqToIos(sent_packets)[i] == LIoOpSend(AbstractifyCPacketToRslPacket(sent_packets[i])) { //lemma_MapSentPacketSeqToIos(sent_packets); if |sent_packets| == 0 then [] else if |sent_packets| == 1 then [LIoOpSend(AbstractifyCPacketToRslPacket(sent_packets[0]))] else [LIoOpSend(AbstractifyCPacketToRslPacket(sent_packets[0]))] + MapSentPacketSeqToIos(sent_packets[1..]) } lemma {:timeLimitMultiplier 3} lemma_MapSentPacketSeqToIosExtractSentPacketsFromIosEquivalence(sent_packets:OutboundPackets, ios:seq) requires sent_packets.PacketSequence? requires OutboundPacketsIsValid(sent_packets) requires OutboundPacketsIsAbstractable(sent_packets) requires ios == MapSentPacketSeqToIos(sent_packets.s) requires forall i :: 0 <= i < |sent_packets.s| ==> CPacketIsSendable(sent_packets.s[i]) ensures AbstractifyOutboundCPacketsToSeqOfRslPackets(sent_packets) == ExtractSentPacketsFromIos(ios) decreases |ios| { assert AbstractifyOutboundCPacketsToSeqOfRslPackets(sent_packets) == AbstractifySeqOfCPacketsToSeqOfRslPackets(sent_packets.s); reveal ExtractSentPacketsFromIos(); //assert |AbstractifyOutboundCPacketsToSeqOfRslPackets(sent_packets)| == |ExtractSentPacketsFromIos(ios)|; reveal MapSentPacketSeqToIos(); if (|ios| == 0) { assert AbstractifyOutboundCPacketsToSeqOfRslPackets(sent_packets) == ExtractSentPacketsFromIos(ios); } else if (|ios| == 1) { assert AbstractifyOutboundCPacketsToSeqOfRslPackets(sent_packets) == ExtractSentPacketsFromIos(ios); } else { if (ios[0].LIoOpSend?) { var one := ios[0]; var rest := PacketSequence(sent_packets.s[1..]); assert ExtractSentPacketsFromIos(ios) == [ios[0].s] + ExtractSentPacketsFromIos(ios[1..]); lemma_MapSentPacketSeqToIosExtractSentPacketsFromIosEquivalence(rest, ios[1..]); reveal AbstractifySeqOfCPacketsToSeqOfRslPackets(); assert {:split_here} true; calc { AbstractifyOutboundCPacketsToSeqOfRslPackets(sent_packets); AbstractifySeqOfCPacketsToSeqOfRslPackets(sent_packets.s); [ios[0].s] + AbstractifyOutboundCPacketsToSeqOfRslPackets(rest); [ios[0].s] + ExtractSentPacketsFromIos(ios[1..]); ExtractSentPacketsFromIos(ios); } } else { assert AbstractifyOutboundCPacketsToSeqOfRslPackets(sent_packets) == ExtractSentPacketsFromIos(ios); } assert AbstractifyOutboundCPacketsToSeqOfRslPackets(sent_packets) == ExtractSentPacketsFromIos(ios); } //forall i | 0 <= i < |AbstractifyOutboundCPacketsToSeqOfRslPackets(sent_packets)| // ensures AbstractifyOutboundCPacketsToSeqOfRslPackets(sent_packets)[i] == ExtractSentPacketsFromIos(ios)[i]; //{ //} assert AbstractifyOutboundCPacketsToSeqOfRslPackets(sent_packets) == ExtractSentPacketsFromIos(ios); } function {:opaque} BuildBroadcastIos(src:NodeIdentity, dsts:seq, msg:RslMessage) : seq ensures |BuildBroadcastIos(src, dsts, msg)| == |dsts| ensures forall i :: 0<=i<|dsts| ==> BuildBroadcastIos(src, dsts, msg)[i] == LIoOpSend(LPacket(dsts[i], src, msg)) { if |dsts| == 0 then [] else [ LIoOpSend(LPacket(dsts[0], src, msg)) ] + BuildBroadcastIos(src, dsts[1..], msg) } function MapBroadcastToIos(broadcast:CBroadcast) : seq requires CBroadcastIsAbstractable(broadcast) { match broadcast case CBroadcast(_,_,_) => BuildBroadcastIos(AbstractifyEndPointToNodeIdentity(broadcast.src), AbstractifyEndPointsToNodeIdentities(broadcast.dsts), AbstractifyCMessageToRslMessage(broadcast.msg)) case CBroadcastNop => [] } predicate LReplica_Next_ReadClockAndProcessPacket_preconditions(ios:seq) { && |ios| >= 1 && ios[0].LIoOpReceive? && ios[0].r.msg.RslMessage_Heartbeat? } lemma lemma_MapSentPacketToIosExtractSentPacketsFromIosEquivalence(sent_packet:Option, ios:seq) requires OutboundPacketsIsValid(OutboundPacket(sent_packet)) requires ios == MapSentPacketToIos(sent_packet) ensures AbstractifyOutboundCPacketsToSeqOfRslPackets(OutboundPacket(sent_packet)) == ExtractSentPacketsFromIos(ios) { reveal ExtractSentPacketsFromIos(); } lemma lemma_ExtractSentPacketsFromIos(ios:seq) requires AllIosAreSends(ios) ensures |ExtractSentPacketsFromIos(ios)| == |ios| ensures forall i {:auto_trigger} :: 0 <= i < |ios| ==> ExtractSentPacketsFromIos(ios)[i] == ios[i].s { reveal ExtractSentPacketsFromIos(); } lemma lemma_MapBroadcastToIosExtractSentPacketsFromIosEquivalence(broadcast:CBroadcast, ios:seq) requires CBroadcastIsAbstractable(broadcast) requires ios == MapBroadcastToIos(broadcast) requires AllIosAreSends(ios) ensures AbstractifyCBroadcastToRlsPacketSeq(broadcast) == ExtractSentPacketsFromIos(ios) { reveal ExtractSentPacketsFromIos(); if broadcast.CBroadcastNop? { } else { forall i | 0 <= i < |broadcast.dsts| ensures AbstractifyCBroadcastToRlsPacketSeq(broadcast)[i] == ExtractSentPacketsFromIos(ios)[i] { calc { AbstractifyCBroadcastToRlsPacketSeq(broadcast)[i]; BuildLBroadcast(AbstractifyEndPointToNodeIdentity(broadcast.src), AbstractifyEndPointsToNodeIdentities(broadcast.dsts), AbstractifyCMessageToRslMessage(broadcast.msg))[i]; LPacket(AbstractifyEndPointsToNodeIdentities(broadcast.dsts)[i], AbstractifyEndPointToNodeIdentity(broadcast.src), AbstractifyCMessageToRslMessage(broadcast.msg)); calc { LIoOpSend(LPacket(AbstractifyEndPointsToNodeIdentities(broadcast.dsts)[i], AbstractifyEndPointToNodeIdentity(broadcast.src), AbstractifyCMessageToRslMessage(broadcast.msg))); BuildBroadcastIos(AbstractifyEndPointToNodeIdentity(broadcast.src), AbstractifyEndPointsToNodeIdentities(broadcast.dsts), AbstractifyCMessageToRslMessage(broadcast.msg))[i]; } { lemma_ExtractSentPacketsFromIos(ios); } ExtractSentPacketsFromIos(BuildBroadcastIos(AbstractifyEndPointToNodeIdentity(broadcast.src), AbstractifyEndPointsToNodeIdentities(broadcast.dsts), AbstractifyCMessageToRslMessage(broadcast.msg)))[i]; ExtractSentPacketsFromIos(ios)[i]; } } calc { |AbstractifyCBroadcastToRlsPacketSeq(broadcast)|; |broadcast.dsts|; |ios|; { lemma_ExtractSentPacketsFromIos(ios); } |ExtractSentPacketsFromIos(ios)|; } } } lemma lemma_NetEventLogToBroadcast(netEventLog:seq, broadcast:CBroadcast, index:int) requires CBroadcastIsValid(broadcast) requires broadcast.CBroadcast? requires 0 <= index < |netEventLog| requires SendLogReflectsBroadcast(netEventLog, broadcast) ensures netEventLog[index].LIoOpSend? ensures NetPacketIsAbstractable(netEventLog[index].s) ensures AbstractifyNetPacketToRslPacket(netEventLog[index].s) == AbstractifyCBroadcastToRlsPacketSeq(broadcast)[index] { calc ==> { true; SendLogReflectsBroadcast(netEventLog, broadcast); SendLogReflectsBroadcastPrefix(netEventLog, broadcast); SendLogMatchesRefinement(netEventLog, broadcast, index); netEventLog[index].LIoOpSend? && NetPacketIsAbstractable(netEventLog[index].s) && AbstractifyCBroadcastToRlsPacketSeq(broadcast)[index] == AbstractifyNetPacketToRslPacket(netEventLog[index].s); } } lemma lemma_NetEventLogToBroadcastRefinable(netEventLog:seq, broadcast:CBroadcast) requires CBroadcastIsValid(broadcast) requires SendLogReflectsBroadcast(netEventLog, broadcast) ensures NetEventLogIsAbstractable(netEventLog) { if broadcast.CBroadcastNop? { assert netEventLog == []; } else { forall i | 0 <= i < |netEventLog| ensures NetEventIsAbstractable(netEventLog[i]) { lemma_NetEventLogToBroadcast(netEventLog, broadcast, i); } } } lemma lemma_ExtractSentPacketsFromIosDoesNotMindSomeClutter(ios_head:seq, ios_tail:seq) requires forall i :: 0<=i<|ios_head| ==> !ios_head[i].LIoOpSend? ensures ExtractSentPacketsFromIos(ios_tail) == ExtractSentPacketsFromIos(ios_head + ios_tail) { if |ios_head| == 0 { assert ios_head + ios_tail == ios_tail; } else { assert !ios_head[0].LIoOpSend?; ghost var ios := [ios_head[0]] + ios_head[1..] + ios_tail; calc { ExtractSentPacketsFromIos(ios_head + ios_tail); { assert ios_head == [ios_head[0]] + ios_head[1..]; } ExtractSentPacketsFromIos([ios_head[0]] + ios_head[1..] + ios_tail); ExtractSentPacketsFromIos(ios); { assert ios[0] == ios_head[0]; assert ios[1..] == ios_head[1..] + ios_tail; reveal ExtractSentPacketsFromIos(); } ExtractSentPacketsFromIos(ios_head[1..] + ios_tail); { lemma_ExtractSentPacketsFromIosDoesNotMindSomeClutter(ios_head[1..], ios_tail); } ExtractSentPacketsFromIos(ios_tail); } } } predicate NoClockMessage(msg:CMessage) { || msg.CMessage_Request? || msg.CMessage_1a? || msg.CMessage_1b? || msg.CMessage_StartingPhase2? || msg.CMessage_2a? || msg.CMessage_2b? || msg.CMessage_Reply? || msg.CMessage_AppStateRequest? || msg.CMessage_AppStateSupply? } lemma lemma_YesWeHaveNoPackets() ensures AbstractifyOutboundCPacketsToSeqOfRslPackets(Broadcast(CBroadcastNop)) == [] { } lemma {:timeLimitMultiplier 3} lemma_ReplicaNextProcessPacketWithoutReadingClockHelper( replica:LReplica, replica':ReplicaState, cpacket:CPacket, sent_packets:OutboundPackets, ios:seq, io0:RslIo, ios_head:seq, ios_tail:seq, netEvent0:NetEvent, log_head:seq, log_tail:seq, netEventLog:seq) // From Receive: requires netEvent0.LIoOpReceive? requires CPacketIsAbstractable(cpacket) requires NetEventIsAbstractable(netEvent0) requires AbstractifyCPacketToRslPacket(cpacket) == AbstractifyNetPacketToRslPacket(netEvent0.r) requires io0 == LIoOpReceive(AbstractifyNetPacketToRslPacket(netEvent0.r)) // From downcalls: requires ReplicaCommonPostconditions(replica, replica', sent_packets) requires Establish_Q_LReplica_Next_ProcessPacketWithoutReadingClock_preconditions(replica, AbstractifyReplicaStateToLReplica(replica'), AbstractifyCPacketToRslPacket(cpacket), AbstractifyOutboundCPacketsToSeqOfRslPackets(sent_packets), ios) // From DeliverOutboundPackets: requires AllIosAreSends(ios_tail) requires AbstractifyOutboundCPacketsToSeqOfRslPackets(sent_packets) == ExtractSentPacketsFromIos(ios_tail) requires RawIoConsistentWithSpecIO(log_tail, ios_tail) requires ios_head == [io0] requires log_head == [netEvent0] requires ios == ios_head+ios_tail requires netEventLog == log_head+log_tail // ensures AllIosAreSends(ios); // bad idea //ensures Establish_Q_LReplica_NoReceive_Next_preconditions(replica, replica', clock, sent_packets, nextActionIndex, ios); ensures RawIoConsistentWithSpecIO(netEventLog, ios) ensures Q_LReplica_Next_ProcessPacketWithoutReadingClock(replica, AbstractifyReplicaStateToLReplica(replica'), ios) ensures RawIoConsistentWithSpecIO(netEventLog, ios) ensures forall io :: io in ios[1..] ==> io.LIoOpSend? { forall io | io in ios[1..] ensures io.LIoOpSend? { var idx :| 0<=idx<|ios[1..]| && io==ios[1..][idx]; // because spec uses 'in seq' instead of indexing assert io == ios_tail[idx]; assert AllIosAreSends(ios_tail); assert io.LIoOpSend?; } forall i | 0<=i<|netEventLog| ensures NetEventIsAbstractable(netEventLog[i]) ensures ios[i] == AbstractifyNetEventToRslIo(netEventLog[i]) { if (i==0) { assert netEventLog[i]==netEvent0; assert NetEventIsAbstractable(netEventLog[i]); assert ios[i] == AbstractifyNetEventToRslIo(netEventLog[i]); } else { calc { netEventLog[i]; ([netEvent0] + log_tail)[i]; log_tail[i-1]; } assert netEventLog[i]==log_tail[i-1]; assert NetEventIsAbstractable(netEventLog[i]); assert ios[i] == AbstractifyNetEventToRslIo(netEventLog[i]); } } assert NetEventLogIsAbstractable(netEventLog); assert AbstractifyRawLogToIos(netEventLog) == ios; lemma_ExtractSentPacketsFromIosDoesNotMindSomeClutter(ios_head, ios_tail); lemma_EstablishQLReplicaNextProcessPacketWithoutReadingClock(replica, AbstractifyReplicaStateToLReplica(replica'), AbstractifyCPacketToRslPacket(cpacket), AbstractifyOutboundCPacketsToSeqOfRslPackets(sent_packets), ios); assert RawIoConsistentWithSpecIO(netEventLog, ios); } lemma lemma_CombineAbstractifyNetEventToRslIo(ios_head:seq, ios_tail:seq, ios:seq, log_head:seq, log_tail:seq, log:seq) requires |log_head| == |ios_head| requires forall i :: 0<=i<|log_head| ==> NetEventIsAbstractable(log_head[i]) && ios_head[i] == AbstractifyNetEventToRslIo(log_head[i]) requires |log_tail| == |ios_tail| requires forall i :: 0<=i<|log_tail| ==> NetEventIsAbstractable(log_tail[i]) && ios_tail[i] == AbstractifyNetEventToRslIo(log_tail[i]) requires ios == ios_head+ios_tail requires log == log_head+log_tail ensures forall i :: 0<=i<|log| ==> ios[i] == AbstractifyNetEventToRslIo(log[i]) { } lemma lemma_NetEventLogIsAbstractableExtend(log_head:seq, log_tail:seq, log:seq) requires log == log_head+log_tail requires NetEventLogIsAbstractable(log_head) requires NetEventLogIsAbstractable(log_tail) ensures NetEventLogIsAbstractable(log) { } lemma lemma_ReplicaNoReceiveReadClockNextHelper( replica:LReplica, replica':ReplicaState, clock:CClockReading, sent_packets:OutboundPackets, nextActionIndex:int, ios:seq, io0:RslIo, ios_head:seq, ios_tail:seq, netEvent0:NetEvent, log_head:seq, log_tail:seq, netEventLog:seq) // From ReadClock: requires netEvent0.LIoOpReadClock? requires clock.t as int == netEvent0.t requires NetEventIsAbstractable(netEvent0) requires io0 == LIoOpReadClock(clock.t as int) // From downcalls: requires ReplicaCommonPostconditions(replica, replica', sent_packets) requires var lreplica' := AbstractifyReplicaStateToLReplica(replica'); var lclock := AbstractifyCClockReadingToClockReading(clock); var lsent_packets := AbstractifyOutboundCPacketsToSeqOfRslPackets(sent_packets); && (nextActionIndex == 3 || 7 <= nextActionIndex <= 9) && (nextActionIndex==3 ==> Q_LReplica_Next_ReadClock_MaybeNominateValueAndSend2a(replica, lreplica', lclock, lsent_packets)) && (nextActionIndex==7 ==> Q_LReplica_Next_ReadClock_CheckForViewTimeout(replica, lreplica', lclock, lsent_packets)) && (nextActionIndex==8 ==> Q_LReplica_Next_ReadClock_CheckForQuorumOfViewSuspicions(replica, lreplica', lclock, lsent_packets)) && (nextActionIndex==9 ==> Q_LReplica_Next_ReadClock_MaybeSendHeartbeat(replica, lreplica', lclock, lsent_packets)) // From DeliverOutboundPackets: requires AllIosAreSends(ios_tail) requires AbstractifyOutboundCPacketsToSeqOfRslPackets(sent_packets) == ExtractSentPacketsFromIos(ios_tail) requires RawIoConsistentWithSpecIO(log_tail, ios_tail) requires ios_head == [io0] requires log_head == [netEvent0] requires ios == ios_head+ios_tail requires netEventLog == log_head+log_tail // ensures AllIosAreSends(ios); // bad idea //ensures Establish_Q_LReplica_NoReceive_Next_preconditions(replica, replica', clock, sent_packets, nextActionIndex, ios); ensures RawIoConsistentWithSpecIO(netEventLog, ios) ensures Q_LReplica_NoReceive_Next(replica, nextActionIndex as int, AbstractifyReplicaStateToLReplica(replica'), ios) ensures forall io :: io in ios[1..] ==> io.LIoOpSend? { var lreplica' := AbstractifyReplicaStateToLReplica(replica'); var lclock := AbstractifyCClockReadingToClockReading(clock); var lsent_packets := AbstractifyOutboundCPacketsToSeqOfRslPackets(sent_packets); forall io | io in ios[1..] ensures io.LIoOpSend? { var idx :| 0<=idx<|ios[1..]| && io==ios[1..][idx]; // because spec uses 'in seq' instead of indexing assert io == ios_tail[idx]; assert AllIosAreSends(ios_tail); assert io.LIoOpSend?; } // forall io | io in ios ensures io.LIoOpSend? // { // var i :| 0<=i<|ios| && io==ios[i]; // } // assert AllIosAreSends(ios); assert io0 == AbstractifyNetEventToRslIo(netEvent0); forall i | 0<=i<|log_head| ensures NetEventIsAbstractable(log_head[i]) && ios_head[i] == AbstractifyNetEventToRslIo(log_head[i]) { assert log_head[i] == netEvent0; assert ios_head[i] == io0; } lemma_ExtractSentPacketsFromIosDoesNotMindSomeClutter(ios_head, ios_tail); assert forall io :: io in ios[1..] ==> io.LIoOpSend?; // OBSERVE trigger ghost var log_head := [netEvent0]; lemma_CombineAbstractifyNetEventToRslIo(ios_head, ios_tail, ios, log_head, log_tail, netEventLog); assert AbstractifyOutboundCPacketsToSeqOfRslPackets(sent_packets) == ExtractSentPacketsFromIos(ios); lemma_NetEventLogIsAbstractableExtend(log_head, log_tail, netEventLog); assert NetEventLogIsAbstractable(netEventLog); lemma_EstablishAbstractifyRawLogToIos(netEventLog, ios); assert AbstractifyRawLogToIos(netEventLog) == ios; assert RawIoConsistentWithSpecIO(netEventLog, ios); assert SpontaneousIos(ios, 1); assert AbstractifyCClockReadingToClockReading(clock) == ClockReading(ios[0].t); assert AbstractifyCClockReadingToClockReading(clock) == SpontaneousClock(ios); lemma_EstablishQLReplicaNoReceiveNextFromReadClock(replica, lreplica', lclock, lsent_packets, nextActionIndex as int, ios); } lemma lemma_SingletonSeqPrependSilly(log_head:seq, log_tail:seq, log:seq) requires |log_head|==1 requires log == log_head + log_tail ensures log_tail == log[1..] { } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/RSL/ReplicaImplMain.i.dfy ================================================ include "../../Common/Collections/Seqs.i.dfy" include "../../../Libraries/Math/mod_auto.i.dfy" include "../../Protocol/RSL/Replica.i.dfy" include "ReplicaModel.i.dfy" include "ReplicaImplLemmas.i.dfy" include "ReplicaImplClass.i.dfy" include "ReplicaImplProcessPacketX.i.dfy" include "ReplicaImplNoReceiveNoClock.i.dfy" include "ReplicaImplNoReceiveClock.i.dfy" include "NetRSL.i.dfy" include "CClockReading.i.dfy" module LiveRSL__ReplicaImplMain_i { import opened Native__Io_s import opened Native__NativeTypes_s import opened Collections__Seqs_i import opened Math__mod_auto_i import opened LiveRSL__CClockReading_i import opened LiveRSL__Environment_i import opened LiveRSL__QRelations_i import opened LiveRSL__Replica_i import opened LiveRSL__ReplicaImplClass_i import opened LiveRSL__ReplicaImplLemmas_i import opened LiveRSL__ReplicaImplNoReceiveClock_i import opened LiveRSL__ReplicaImplNoReceiveNoClock_i import opened LiveRSL__ReplicaImplProcessPacketX_i import opened LiveRSL__ReplicaModel_i import opened LiveRSL__NetRSL_i import opened LiveRSL__Unsendable_i import opened Common__NetClient_i method rollActionIndex(a:uint64) returns (a':uint64) requires 0 <= a as int < 10 ensures a' as int == ((a as int) + 1) % LReplicaNumActions() { lemma_mod_auto(10); if (a >= 9) { a' := 0; } else { a' := (a + 1); } } method {:timeLimitMultiplier 2} ReplicaNextMainProcessPacketX(r:ReplicaImpl) returns (ok:bool, ghost netEventLog:seq, ghost ios:seq) requires r.Valid() requires r.nextActionIndex == 0 modifies r.Repr, r.cur_req_set, r.prev_req_set, r.reply_cache_mutable ensures r.Repr == old(r.Repr) ensures r.netClient != null ensures r.Env().Valid() && r.Env().ok.ok() ==> ok ensures r.Env() == old(r.Env()); ensures ok ==> && r.Valid() && (|| Q_LScheduler_Next(old(r.AbstractifyToLScheduler()), r.AbstractifyToLScheduler(), ios) || HostNextIgnoreUnsendable(old(r.AbstractifyToLScheduler()), r.AbstractifyToLScheduler(), netEventLog)) && RawIoConsistentWithSpecIO(netEventLog, ios) && OnlySentMarshallableData(netEventLog) && old(r.Env().net.history()) + netEventLog == r.Env().net.history() { ghost var replica_old := old(r.AbstractifyToLReplica()); ghost var scheduler_old := old(r.AbstractifyToLScheduler()); assert scheduler_old.nextActionIndex == 0; //print ("Replica_Next_main Enter\n"); assert scheduler_old.replica == replica_old; ok, netEventLog, ios := Replica_Next_ProcessPacketX(r); if (!ok) { return; } assert r.Valid(); // Mention unchanged predicates over mutable state in the old heap. ghost var net_client_old := r.netClient; ghost var net_addr_old := r.netClient.MyPublicKey(); assert NetClientIsValid(net_client_old); ghost var replica := r.AbstractifyToLReplica(); r.nextActionIndex := 1; ghost var scheduler := r.AbstractifyToLScheduler(); // Mention unchanged predicates over mutable state in the new heap. assert net_client_old == r.netClient; assert NetClientIsValid(r.netClient); assert net_addr_old == r.netClient.MyPublicKey(); assert r.Valid(); calc { scheduler.nextActionIndex; r.nextActionIndex as int; 1; { lemma_mod_auto(LReplicaNumActions()); } (1)%LReplicaNumActions(); (scheduler_old.nextActionIndex+1)%LReplicaNumActions(); } if Q_LReplica_Next_ProcessPacket(old(r.AbstractifyToLReplica()), r.AbstractifyToLReplica(), ios) { lemma_EstablishQLSchedulerNext(replica_old, replica, ios, scheduler_old, scheduler); assert Q_LScheduler_Next(old(r.AbstractifyToLScheduler()), r.AbstractifyToLScheduler(), ios); } else { assert IosReflectIgnoringUnsendable(netEventLog); assert old(r.AbstractifyToLReplica()) == r.AbstractifyToLReplica(); assert HostNextIgnoreUnsendable(old(r.AbstractifyToLScheduler()), r.AbstractifyToLScheduler(), netEventLog); } } method ReplicaNextMainNoClock(r:ReplicaImpl) returns (ok:bool, ghost netEventLog:seq, ghost ios:seq) requires r.Valid() requires r.nextActionIndex == 1 || r.nextActionIndex == 2 || r.nextActionIndex == 4 || r.nextActionIndex == 5 || r.nextActionIndex == 6 modifies r.replica.executor.app, r.Repr, r.cur_req_set, r.prev_req_set, r.reply_cache_mutable ensures r.Repr == old(r.Repr) ensures r.netClient != null ensures r.Env().Valid() && r.Env().ok.ok() ==> ok ensures r.Env() == old(r.Env()); ensures ok ==> && r.Valid() && Q_LScheduler_Next(old(r.AbstractifyToLScheduler()), r.AbstractifyToLScheduler(), ios) && RawIoConsistentWithSpecIO(netEventLog, ios) && OnlySentMarshallableData(netEventLog) && old(r.Env().net.history()) + netEventLog == r.Env().net.history() { var curActionIndex := r.nextActionIndex; ghost var replica_old := old(r.AbstractifyToLReplica()); ghost var scheduler_old := old(r.AbstractifyToLScheduler()); assert scheduler_old.replica == replica_old; ok, netEventLog, ios := Replica_NoReceive_NoClock_Next(r); if (!ok) { return; } assert r.Valid(); // Mention unchanged predicates over mutable state in the old heap. ghost var net_client_old := r.netClient; ghost var net_addr_old := r.netClient.MyPublicKey(); assert NetClientIsValid(net_client_old); ghost var replica := r.AbstractifyToLReplica(); var nextActionIndex' := r.nextActionIndex + 1; // rollActionIndex(r.nextActionIndex); r.nextActionIndex := nextActionIndex'; ghost var scheduler := r.AbstractifyToLScheduler(); // Mention unchanged predicates over mutable state in the new heap. assert net_client_old == r.netClient; assert NetClientIsValid(r.netClient); assert net_addr_old == r.netClient.MyPublicKey(); assert r.Valid(); calc { scheduler.nextActionIndex; r.nextActionIndex as int; nextActionIndex' as int; { lemma_mod_auto(LReplicaNumActions()); } ((curActionIndex+1) as int)%LReplicaNumActions(); (scheduler_old.nextActionIndex+1)%LReplicaNumActions(); } lemma_EstablishQLSchedulerNext(replica_old, replica, ios, scheduler_old, scheduler); assert Q_LScheduler_Next(old(r.AbstractifyToLScheduler()), r.AbstractifyToLScheduler(), ios); } method ReplicaNextMainReadClock(r:ReplicaImpl) returns (ok:bool, ghost netEventLog:seq, ghost ios:seq) requires r.Valid() requires r.nextActionIndex == 3 || r.nextActionIndex == 7 || r.nextActionIndex == 8 || r.nextActionIndex == 9 modifies r.Repr, r.cur_req_set, r.prev_req_set, r.reply_cache_mutable ensures r.Repr == old(r.Repr) ensures r.netClient != null ensures r.Env().Valid() && r.Env().ok.ok() ==> ok ensures r.Env() == old(r.Env()); ensures ok ==> && r.Valid() && Q_LScheduler_Next(old(r.AbstractifyToLScheduler()), r.AbstractifyToLScheduler(), ios) && RawIoConsistentWithSpecIO(netEventLog, ios) && OnlySentMarshallableData(netEventLog) && old(r.Env().net.history()) + netEventLog == r.Env().net.history() { var curActionIndex := r.nextActionIndex; ghost var replica_old := old(r.AbstractifyToLReplica()); ghost var scheduler_old := old(r.AbstractifyToLScheduler()); assert scheduler_old.replica == replica_old; ok, netEventLog, ios := Replica_NoReceive_ReadClock_Next(r); if (!ok) { return; } assert r.Valid(); // Mention unchanged predicates over mutable state in the old heap. ghost var net_client_old := r.netClient; ghost var net_addr_old := r.netClient.MyPublicKey(); assert NetClientIsValid(net_client_old); ghost var replica := r.AbstractifyToLReplica(); var nextActionIndex' := rollActionIndex(r.nextActionIndex); r.nextActionIndex := nextActionIndex'; ghost var scheduler := r.AbstractifyToLScheduler(); // Mention unchanged predicates over mutable state in the new heap. assert net_client_old == r.netClient; assert NetClientIsValid(r.netClient); assert net_addr_old == r.netClient.MyPublicKey(); assert r.Valid(); calc { scheduler.nextActionIndex; r.nextActionIndex as int; nextActionIndex' as int; ((curActionIndex+1) as int)%LReplicaNumActions(); (scheduler_old.nextActionIndex+1)%LReplicaNumActions(); } lemma_EstablishQLSchedulerNext(replica_old, replica, ios, scheduler_old, scheduler); assert Q_LScheduler_Next(old(r.AbstractifyToLScheduler()), r.AbstractifyToLScheduler(), ios); } method Replica_Next_main(r:ReplicaImpl) returns (ok:bool, ghost netEventLog:seq, ghost ios:seq) requires r.Valid() modifies r.replica.executor.app, r.Repr, r.cur_req_set, r.prev_req_set, r.reply_cache_mutable ensures r.Repr == old(r.Repr) ensures r.netClient != null ensures r.Env().Valid() && r.Env().ok.ok() ==> ok ensures r.Env() == old(r.Env()); ensures ok ==> && r.Valid() && (|| Q_LScheduler_Next(old(r.AbstractifyToLScheduler()), r.AbstractifyToLScheduler(), ios) || HostNextIgnoreUnsendable(old(r.AbstractifyToLScheduler()), r.AbstractifyToLScheduler(), netEventLog)) && RawIoConsistentWithSpecIO(netEventLog, ios) && OnlySentMarshallableData(netEventLog) && old(r.Env().net.history()) + netEventLog == r.Env().net.history() { //print ("Replica_Next_main Enter\n"); if r.nextActionIndex == 0 { ok, netEventLog, ios := ReplicaNextMainProcessPacketX(r); } else if r.nextActionIndex == 1 || r.nextActionIndex == 2 || r.nextActionIndex == 4 || r.nextActionIndex == 5 || r.nextActionIndex == 6 { ok, netEventLog, ios := ReplicaNextMainNoClock(r); } else if (r.nextActionIndex == 3 || 7 <= r.nextActionIndex <= 9) { ok, netEventLog, ios := ReplicaNextMainReadClock(r); } //print ("Replica_Next_main Exit\n"); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/RSL/ReplicaImplNoReceiveClock.i.dfy ================================================ include "../../Common/Collections/Seqs.i.dfy" include "../../../Libraries/Math/mod_auto.i.dfy" include "../../Protocol/RSL/Replica.i.dfy" include "ReplicaModel.i.dfy" include "ReplicaImplLemmas.i.dfy" include "ReplicaImplClass.i.dfy" include "ReplicaImplDelivery.i.dfy" include "NetRSL.i.dfy" include "CClockReading.i.dfy" module LiveRSL__ReplicaImplNoReceiveClock_i { import opened Native__Io_s import opened Native__NativeTypes_s import opened Collections__Seqs_i import opened Math__mod_auto_i import opened LiveRSL__CClockReading_i import opened LiveRSL__CMessage_i import opened LiveRSL__CMessageRefinements_i import opened LiveRSL__CTypes_i import opened LiveRSL__Environment_i import opened LiveRSL__QRelations_i import opened LiveRSL__Replica_i import opened LiveRSL__ReplicaModel_i import opened LiveRSL__ReplicaModel_Part3_i import opened LiveRSL__ReplicaModel_Part4_i import opened LiveRSL__ReplicaModel_Part5_i import opened LiveRSL__ReplicaState_i import opened LiveRSL__ReplicaImplLemmas_i import opened LiveRSL__ReplicaImplClass_i import opened LiveRSL__ReplicaImplDelivery_i import opened LiveRSL__Types_i import opened LiveRSL__NetRSL_i import opened Common__NetClient_i import opened Environment_s lemma lemma_ReplicaNoReceiveReadClockNextHelper2( oldHistory:seq, preDeliveryHistory:seq, finalHistory:seq, log_head:seq, log_tail:seq, log_head_and_tail:seq ) requires preDeliveryHistory == oldHistory + log_head requires finalHistory == preDeliveryHistory + log_tail requires log_head_and_tail == log_head + log_tail requires forall io :: io in log_head ==> !io.LIoOpSend? requires OnlySentMarshallableData(log_tail) ensures finalHistory == oldHistory + log_head_and_tail ensures OnlySentMarshallableData(log_head_and_tail) { } lemma lemma_RevealQFromReplicaNextMaybeNominateValueAndSend2aPostconditions( replica:LReplica, replica':ReplicaState, clock:CClockReading, packets_sent:OutboundPackets ) requires Replica_Next_ReadClock_MaybeNominateValueAndSend2a_Postconditions(replica, replica', clock, packets_sent) ensures Q_LReplica_Next_ReadClock_MaybeNominateValueAndSend2a(replica, AbstractifyReplicaStateToLReplica(replica'), AbstractifyCClockReadingToClockReading(clock), AbstractifyOutboundCPacketsToSeqOfRslPackets(packets_sent)) { reveal Q_LReplica_Next_ReadClock_MaybeNominateValueAndSend2a(); } method {:fuel ReplicaStateIsValid,0,0}{:timeLimitMultiplier 3} ReplicaNoReceiveReadClockNextMaybeNominateValueAndSend2a( r:ReplicaImpl ) returns ( ok:bool, ghost netEventLog:seq, ghost ios:seq ) requires r.nextActionIndex == 3 requires r.Valid() modifies r.Repr ensures r.Repr == old(r.Repr) ensures r.netClient != null ensures ok == NetClientOk(r.netClient) ensures r.Env() == old(r.Env()); ensures ok ==> && r.Valid() && r.Env() == old(r.Env()) && r.nextActionIndex == old(r.nextActionIndex) && Q_LReplica_NoReceive_Next(old(r.AbstractifyToLReplica()), r.nextActionIndex as int, r.AbstractifyToLReplica(), ios) && OnlySentMarshallableData(netEventLog) && RawIoConsistentWithSpecIO(netEventLog, ios) && old(r.Env().net.history()) + netEventLog == r.Env().net.history() { ghost var replica_old := AbstractifyReplicaStateToLReplica(r.replica); var clock,netEvent0 := ReadClock(r.netClient); ghost var io0 := LIoOpReadClock(clock.t as int); var sent_packets; r.replica,sent_packets := Replica_Next_Spontaneous_MaybeNominateValueAndSend2a(r.replica, clock); lemma_RevealQFromReplicaNextMaybeNominateValueAndSend2aPostconditions(replica_old, r.replica, clock, sent_packets); assert r.Valid(); ghost var preDeliveryHistory := r.Env().net.history(); ghost var log_tail, ios_tail; ok, log_tail, ios_tail := DeliverOutboundPackets(r, sent_packets); if (!ok) { return; } ghost var ios_head := [io0]; ghost var log_head := [netEvent0]; ios := ios_head + ios_tail; netEventLog := log_head + log_tail; lemma_ReplicaNoReceiveReadClockNextHelper2(old(r.Env().net.history()), preDeliveryHistory, r.Env().net.history(), log_head, log_tail, netEventLog); lemma_ReplicaNoReceiveReadClockNextHelper( replica_old, r.replica, clock, sent_packets, r.nextActionIndex as int, ios, io0, ios_head, ios_tail, netEvent0, log_head, log_tail, netEventLog); } lemma lemma_RevealQFromReplicaNextCheckForViewTimeoutPostconditions( replica:LReplica, replica':ReplicaState, clock:CClockReading, packets_sent:OutboundPackets ) requires Replica_Next_ReadClock_CheckForViewTimeout_Postconditions(replica, replica', clock, packets_sent) ensures Q_LReplica_Next_ReadClock_CheckForViewTimeout(replica, AbstractifyReplicaStateToLReplica(replica'), AbstractifyCClockReadingToClockReading(clock), AbstractifyOutboundCPacketsToSeqOfRslPackets(packets_sent)) { reveal Q_LReplica_Next_ReadClock_CheckForViewTimeout(); } method {:fuel ReplicaStateIsValid,0,0}{:timeLimitMultiplier 3} ReplicaNoReceiveReadClockNextCheckForViewTimeout( r:ReplicaImpl ) returns ( ok:bool, ghost netEventLog:seq, ghost ios:seq ) requires r.nextActionIndex == 7 requires r.Valid() modifies r.Repr, r.cur_req_set, r.prev_req_set //, r.reply_cache_mutable; ensures r.Repr == old(r.Repr) ensures r.netClient != null ensures ok == NetClientOk(r.netClient) ensures r.Env() == old(r.Env()) ensures ok ==> && r.Valid() && r.Env() == old(r.Env()) && r.nextActionIndex == old(r.nextActionIndex) && Q_LReplica_NoReceive_Next(old(r.AbstractifyToLReplica()), r.nextActionIndex as int, r.AbstractifyToLReplica(), ios) && OnlySentMarshallableData(netEventLog) && RawIoConsistentWithSpecIO(netEventLog, ios) && old(r.Env().net.history()) + netEventLog == r.Env().net.history() { ghost var replica_old := AbstractifyReplicaStateToLReplica(r.replica); var clock,netEvent0 := ReadClock(r.netClient); ghost var io0 := LIoOpReadClock(clock.t as int); var sent_packets; r.replica,sent_packets := Replica_Next_ReadClock_CheckForViewTimeout(r.replica, clock, r.cur_req_set, r.prev_req_set); lemma_RevealQFromReplicaNextCheckForViewTimeoutPostconditions(replica_old, r.replica, clock, sent_packets); assert r.Valid(); ghost var preDeliveryHistory := r.Env().net.history(); ghost var log_tail, ios_tail; ok, log_tail, ios_tail := DeliverOutboundPackets(r, sent_packets); if (!ok) { return; } ghost var ios_head := [io0]; ghost var log_head := [netEvent0]; ios := ios_head + ios_tail; netEventLog := log_head + log_tail; lemma_ReplicaNoReceiveReadClockNextHelper2(old(r.Env().net.history()), preDeliveryHistory, r.Env().net.history(), log_head, log_tail, netEventLog); lemma_ReplicaNoReceiveReadClockNextHelper( replica_old, r.replica, clock, sent_packets, r.nextActionIndex as int, ios, io0, ios_head, ios_tail, netEvent0, log_head, log_tail, netEventLog); } lemma lemma_RevealQFromReplicaNextCheckForQuorumOfViewSuspicionsPostconditions( replica:LReplica, replica':ReplicaState, clock:CClockReading, packets_sent:OutboundPackets ) requires Replica_Next_ReadClock_CheckForQuorumOfViewSuspicions_Postconditions(replica, replica', clock, packets_sent) ensures Q_LReplica_Next_ReadClock_CheckForQuorumOfViewSuspicions(replica, AbstractifyReplicaStateToLReplica(replica'), AbstractifyCClockReadingToClockReading(clock), AbstractifyOutboundCPacketsToSeqOfRslPackets(packets_sent)) { reveal Q_LReplica_Next_ReadClock_CheckForQuorumOfViewSuspicions(); } method {:fuel ReplicaStateIsValid,0,0}{:timeLimitMultiplier 3} ReplicaNoReceiveReadClockNextCheckForQuorumOfViewSuspicions( r:ReplicaImpl ) returns ( ok:bool, ghost netEventLog:seq, ghost ios:seq ) requires r.nextActionIndex == 8 requires r.Valid() modifies r.Repr, r.cur_req_set, r.prev_req_set //, r.reply_cache_mutable ensures r.Repr == old(r.Repr) ensures r.netClient != null ensures ok == NetClientOk(r.netClient) ensures r.Env() == old(r.Env()) ensures ok ==> && r.Valid() && r.Env() == old(r.Env()) && r.nextActionIndex == old(r.nextActionIndex) && Q_LReplica_NoReceive_Next(old(r.AbstractifyToLReplica()), r.nextActionIndex as int, r.AbstractifyToLReplica(), ios) && OnlySentMarshallableData(netEventLog) && RawIoConsistentWithSpecIO(netEventLog, ios) && old(r.Env().net.history()) + netEventLog == r.Env().net.history() { ghost var replica_old := AbstractifyReplicaStateToLReplica(r.replica); var clock,netEvent0 := ReadClock(r.netClient); ghost var io0 := LIoOpReadClock(clock.t as int); var sent_packets; r.replica,sent_packets := Replica_Next_ReadClock_CheckForQuorumOfViewSuspicions(r.replica, clock, r.cur_req_set, r.prev_req_set); lemma_RevealQFromReplicaNextCheckForQuorumOfViewSuspicionsPostconditions(replica_old, r.replica, clock, sent_packets); assert r.Valid(); ghost var preDeliveryHistory := r.Env().net.history(); ghost var log_tail, ios_tail; ok, log_tail, ios_tail := DeliverOutboundPackets(r, sent_packets); if (!ok) { return; } ghost var ios_head := [io0]; ghost var log_head := [netEvent0]; ios := ios_head + ios_tail; netEventLog := log_head + log_tail; lemma_ReplicaNoReceiveReadClockNextHelper2(old(r.Env().net.history()), preDeliveryHistory, r.Env().net.history(), log_head, log_tail, netEventLog); lemma_ReplicaNoReceiveReadClockNextHelper( replica_old, r.replica, clock, sent_packets, r.nextActionIndex as int, ios, io0, ios_head, ios_tail, netEvent0, log_head, log_tail, netEventLog); } lemma lemma_RevealQFromReplicaNextMaybeSendHeartbeatPostconditions( replica:LReplica, replica':ReplicaState, clock:CClockReading, packets_sent:OutboundPackets ) requires Replica_Next_ReadClock_MaybeSendHeartbeat_Postconditions(replica, replica', clock, packets_sent) ensures Q_LReplica_Next_ReadClock_MaybeSendHeartbeat(replica, AbstractifyReplicaStateToLReplica(replica'), AbstractifyCClockReadingToClockReading(clock), AbstractifyOutboundCPacketsToSeqOfRslPackets(packets_sent)) { reveal Q_LReplica_Next_ReadClock_MaybeSendHeartbeat(); } method {:fuel ReplicaStateIsValid,0,0}{:timeLimitMultiplier 3} ReplicaNoReceiveReadClockNextMaybeSendHeartbat( r:ReplicaImpl ) returns ( ok:bool, ghost netEventLog:seq, ghost ios:seq ) requires r.nextActionIndex == 9 requires r.Valid() modifies r.Repr ensures r.Repr == old(r.Repr) ensures r.netClient != null ensures ok == NetClientOk(r.netClient) ensures r.Env() == old(r.Env()) ensures ok ==> && r.Valid() && r.Env() == old(r.Env()) && r.nextActionIndex == old(r.nextActionIndex) && Q_LReplica_NoReceive_Next(old(r.AbstractifyToLReplica()), r.nextActionIndex as int, r.AbstractifyToLReplica(), ios) && OnlySentMarshallableData(netEventLog) && RawIoConsistentWithSpecIO(netEventLog, ios) && old(r.Env().net.history()) + netEventLog == r.Env().net.history() { ghost var replica_old := AbstractifyReplicaStateToLReplica(r.replica); var clock,netEvent0 := ReadClock(r.netClient); ghost var io0 := LIoOpReadClock(clock.t as int); var sent_packets; r.replica,sent_packets := Replica_Next_ReadClock_MaybeSendHeartbeat(r.replica, clock); lemma_RevealQFromReplicaNextMaybeSendHeartbeatPostconditions(replica_old, r.replica, clock, sent_packets); assert r.Valid(); ghost var preDeliveryHistory := r.Env().net.history(); ghost var log_tail, ios_tail; ok, log_tail, ios_tail := DeliverOutboundPackets(r, sent_packets); if (!ok) { return; } ghost var ios_head := [io0]; ghost var log_head := [netEvent0]; ios := ios_head + ios_tail; netEventLog := log_head + log_tail; lemma_ReplicaNoReceiveReadClockNextHelper2(old(r.Env().net.history()), preDeliveryHistory, r.Env().net.history(), log_head, log_tail, netEventLog); lemma_ReplicaNoReceiveReadClockNextHelper( replica_old, r.replica, clock, sent_packets, r.nextActionIndex as int, ios, io0, ios_head, ios_tail, netEvent0, log_head, log_tail, netEventLog); } method {:fuel ReplicaStateIsValid,0,0} Replica_NoReceive_ReadClock_Next( r:ReplicaImpl ) returns ( ok:bool, ghost netEventLog:seq, ghost ios:seq ) requires r.nextActionIndex == 3 || 7<=r.nextActionIndex<=9 requires r.Valid() modifies r.Repr, r.cur_req_set, r.prev_req_set //, r.reply_cache_mutable; ensures r.Repr == old(r.Repr) ensures r.netClient != null ensures ok == NetClientOk(r.netClient) ensures r.Env() == old(r.Env()) ensures ok ==> && r.Valid() && r.Env() == old(r.Env()) && r.nextActionIndex == old(r.nextActionIndex) && Q_LReplica_NoReceive_Next(old(r.AbstractifyToLReplica()), r.nextActionIndex as int, r.AbstractifyToLReplica(), ios) && OnlySentMarshallableData(netEventLog) && RawIoConsistentWithSpecIO(netEventLog, ios) && old(r.Env().net.history()) + netEventLog == r.Env().net.history() { if r.nextActionIndex == 3 { ok, netEventLog, ios := ReplicaNoReceiveReadClockNextMaybeNominateValueAndSend2a(r); } else if r.nextActionIndex == 7 { ok, netEventLog, ios := ReplicaNoReceiveReadClockNextCheckForViewTimeout(r); } else if r.nextActionIndex == 8 { ok, netEventLog, ios := ReplicaNoReceiveReadClockNextCheckForQuorumOfViewSuspicions(r); } else if r.nextActionIndex == 9 { ok, netEventLog, ios := ReplicaNoReceiveReadClockNextMaybeSendHeartbat(r); } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/RSL/ReplicaImplNoReceiveNoClock.i.dfy ================================================ include "../../Common/Collections/Seqs.i.dfy" include "../../../Libraries/Math/mod_auto.i.dfy" include "../../Protocol/RSL/Replica.i.dfy" include "ReplicaModel.i.dfy" include "ReplicaImplLemmas.i.dfy" include "ReplicaImplClass.i.dfy" include "ReplicaImplDelivery.i.dfy" include "NetRSL.i.dfy" include "CClockReading.i.dfy" module LiveRSL__ReplicaImplNoReceiveNoClock_i { import opened Native__Io_s import opened Native__NativeTypes_s import opened Collections__Seqs_i import opened Math__mod_auto_i import opened LiveRSL__CClockReading_i import opened LiveRSL__CMessage_i import opened LiveRSL__CMessageRefinements_i import opened LiveRSL__CTypes_i import opened LiveRSL__Environment_i import opened LiveRSL__QRelations_i import opened LiveRSL__Replica_i import opened LiveRSL__ReplicaImplLemmas_i import opened LiveRSL__ReplicaImplClass_i import opened LiveRSL__ReplicaImplDelivery_i import opened LiveRSL__ReplicaModel_i import opened LiveRSL__ReplicaModel_Part3_i import opened LiveRSL__ReplicaModel_Part5_i import opened LiveRSL__ReplicaState_i import opened LiveRSL__Types_i import opened LiveRSL__NetRSL_i import opened Common__NetClient_i import opened Environment_s lemma lemma_RevealQFromReplicaNextSpontaneousMaybeEnterNewViewAndSend1aPostconditions( replica:LReplica, replica':ReplicaState, packets_sent:OutboundPackets ) requires Replica_Next_MaybeEnterNewViewAndSend1a_Postconditions(replica, replica', packets_sent) ensures Q_LReplica_Next_Spontaneous_MaybeEnterNewViewAndSend1a(replica, AbstractifyReplicaStateToLReplica(replica'), AbstractifyOutboundCPacketsToSeqOfRslPackets(packets_sent)) { reveal Q_LReplica_Next_Spontaneous_MaybeEnterNewViewAndSend1a(); } method ReplicaNoReceiveNoClockNextSpontaneousMaybeEnterNewViewAndSend1a(r:ReplicaImpl) returns (ok:bool, ghost netEventLog:seq, ghost ios:seq) requires r.nextActionIndex==1 requires r.Valid() modifies r.Repr ensures r.Repr == old(r.Repr) ensures r.netClient != null ensures ok == NetClientOk(r.netClient) ensures r.Env() == old(r.Env()); ensures ok ==> && r.Valid() && r.nextActionIndex == old(r.nextActionIndex) && Q_LReplica_NoReceive_Next(old(r.AbstractifyToLReplica()), r.nextActionIndex as int, r.AbstractifyToLReplica(), ios) && RawIoConsistentWithSpecIO(netEventLog, ios) && OnlySentMarshallableData(netEventLog) && old(r.Env().net.history()) + netEventLog == r.Env().net.history() { ghost var replica_old := AbstractifyReplicaStateToLReplica(r.replica); var sent_packets; r.replica,sent_packets := Replica_Next_Spontaneous_MaybeEnterNewViewAndSend1a(r.replica); lemma_RevealQFromReplicaNextSpontaneousMaybeEnterNewViewAndSend1aPostconditions(replica_old, r.replica, sent_packets); ok, netEventLog, ios := DeliverOutboundPackets(r, sent_packets); if (!ok) { return; } assert old(r.Env().net.history()) + netEventLog == r.Env().net.history(); // deleteme assert SpontaneousIos(ios, 0); assert AbstractifyOutboundCPacketsToSeqOfRslPackets(sent_packets) == ExtractSentPacketsFromIos(ios); assert r.Env() == old(r.Env()); assert RawIoConsistentWithSpecIO(netEventLog, ios); lemma_EstablishQLReplicaNoReceiveNextFromNoClock(replica_old, r.AbstractifyToLReplica(), AbstractifyOutboundCPacketsToSeqOfRslPackets(sent_packets), r.nextActionIndex as int, ios); } lemma lemma_RevealQFromReplicaNextSpontaneousMaybeEnterPhase2Postconditions( replica:LReplica, replica':ReplicaState, packets_sent:OutboundPackets ) requires Replica_Next_MaybeEnterPhase2_Postconditions(replica, replica', packets_sent) ensures Q_LReplica_Next_Spontaneous_MaybeEnterPhase2(replica, AbstractifyReplicaStateToLReplica(replica'), AbstractifyOutboundCPacketsToSeqOfRslPackets(packets_sent)) { reveal Q_LReplica_Next_Spontaneous_MaybeEnterPhase2(); } method ReplicaNoReceiveNoClockNextSpontaneousMaybeEnterPhase2(r:ReplicaImpl) returns (ok:bool, ghost netEventLog:seq, ghost ios:seq) requires r.nextActionIndex==2 requires r.Valid() modifies r.Repr ensures r.Repr == old(r.Repr) ensures r.netClient != null ensures ok == NetClientOk(r.netClient) ensures r.Env() == old(r.Env()); ensures ok ==> && r.Valid() && r.nextActionIndex == old(r.nextActionIndex) && Q_LReplica_NoReceive_Next(old(r.AbstractifyToLReplica()), r.nextActionIndex as int, r.AbstractifyToLReplica(), ios) && RawIoConsistentWithSpecIO(netEventLog, ios) && OnlySentMarshallableData(netEventLog) && old(r.Env().net.history()) + netEventLog == r.Env().net.history() { ghost var replica_old := AbstractifyReplicaStateToLReplica(r.replica); var sent_packets; r.replica,sent_packets := Replica_Next_Spontaneous_MaybeEnterPhase2(r.replica); lemma_RevealQFromReplicaNextSpontaneousMaybeEnterPhase2Postconditions(replica_old, r.replica, sent_packets); ok, netEventLog, ios := DeliverOutboundPackets(r, sent_packets); if (!ok) { return; } assert old(r.Env().net.history()) + netEventLog == r.Env().net.history(); // deleteme assert SpontaneousIos(ios, 0); assert AbstractifyOutboundCPacketsToSeqOfRslPackets(sent_packets) == ExtractSentPacketsFromIos(ios); assert r.Env() == old(r.Env()); assert RawIoConsistentWithSpecIO(netEventLog, ios); lemma_EstablishQLReplicaNoReceiveNextFromNoClock(replica_old, r.AbstractifyToLReplica(), AbstractifyOutboundCPacketsToSeqOfRslPackets(sent_packets), r.nextActionIndex as int, ios); } lemma lemma_RevealQFromReplicaNextSpontaneousTruncateLogBasedOnCheckpointsPostconditions( replica:LReplica, replica':ReplicaState, packets_sent:OutboundPackets ) requires Replica_Next_Spontaneous_TruncateLogBasedOnCheckpoints_Postconditions(replica, replica', packets_sent) ensures Q_LReplica_Next_Spontaneous_TruncateLogBasedOnCheckpoints(replica, AbstractifyReplicaStateToLReplica(replica'), AbstractifyOutboundCPacketsToSeqOfRslPackets(packets_sent)); { reveal Q_LReplica_Next_Spontaneous_TruncateLogBasedOnCheckpoints(); } method ReplicaNoReceiveNoClockNextSpontaneousTruncateLogBasedOnCheckpoints(r:ReplicaImpl) returns (ok:bool, ghost netEventLog:seq, ghost ios:seq) requires r.nextActionIndex==4 requires r.Valid() modifies r.Repr ensures r.Repr == old(r.Repr) ensures r.netClient != null ensures ok == NetClientOk(r.netClient) ensures r.Env() == old(r.Env()); ensures ok ==> && r.Valid() && r.nextActionIndex == old(r.nextActionIndex) && Q_LReplica_NoReceive_Next(old(r.AbstractifyToLReplica()), r.nextActionIndex as int, r.AbstractifyToLReplica(), ios) && RawIoConsistentWithSpecIO(netEventLog, ios) && OnlySentMarshallableData(netEventLog) && old(r.Env().net.history()) + netEventLog == r.Env().net.history() { ghost var replica_old := AbstractifyReplicaStateToLReplica(r.replica); var sent_packets; r.replica,sent_packets := Replica_Next_Spontaneous_TruncateLogBasedOnCheckpoints(r.replica); lemma_RevealQFromReplicaNextSpontaneousTruncateLogBasedOnCheckpointsPostconditions(replica_old, r.replica, sent_packets); ok, netEventLog, ios := DeliverOutboundPackets(r, sent_packets); if (!ok) { return; } assert old(r.Env().net.history()) + netEventLog == r.Env().net.history(); // deleteme assert SpontaneousIos(ios, 0); assert AbstractifyOutboundCPacketsToSeqOfRslPackets(sent_packets) == ExtractSentPacketsFromIos(ios); assert r.Env() == old(r.Env()); assert RawIoConsistentWithSpecIO(netEventLog, ios); lemma_EstablishQLReplicaNoReceiveNextFromNoClock(replica_old, r.AbstractifyToLReplica(), AbstractifyOutboundCPacketsToSeqOfRslPackets(sent_packets), r.nextActionIndex as int, ios); } lemma lemma_RevealQFromReplicaNextSpontaneousMaybeMakeDecisionPostconditions( replica:LReplica, replica':ReplicaState, packets_sent:OutboundPackets ) requires Replica_Next_Spontaneous_MaybeMakeDecision_Postconditions(replica, replica', packets_sent) ensures Q_LReplica_Next_Spontaneous_MaybeMakeDecision(replica, AbstractifyReplicaStateToLReplica(replica'), AbstractifyOutboundCPacketsToSeqOfRslPackets(packets_sent)) { reveal Q_LReplica_Next_Spontaneous_MaybeMakeDecision(); } method{:timeLimitMultiplier 2} ReplicaNoReceiveNoClockNextSpontaneousMaybeMakeDecision(r:ReplicaImpl) returns (ok:bool, ghost netEventLog:seq, ghost ios:seq) requires r.nextActionIndex==5 requires r.Valid() modifies r.Repr ensures r.Repr == old(r.Repr) ensures r.netClient != null ensures ok == NetClientOk(r.netClient) ensures r.Env() == old(r.Env()); ensures ok ==> && r.Valid() && r.nextActionIndex == old(r.nextActionIndex) && Q_LReplica_NoReceive_Next(old(r.AbstractifyToLReplica()), r.nextActionIndex as int, r.AbstractifyToLReplica(), ios) && RawIoConsistentWithSpecIO(netEventLog, ios) && OnlySentMarshallableData(netEventLog) && old(r.Env().net.history()) + netEventLog == r.Env().net.history() { ghost var replica_old := AbstractifyReplicaStateToLReplica(r.replica); var sent_packets; r.replica,sent_packets := Replica_Next_Spontaneous_MaybeMakeDecision(r.replica); lemma_RevealQFromReplicaNextSpontaneousMaybeMakeDecisionPostconditions(replica_old, r.replica, sent_packets); ok, netEventLog, ios := DeliverOutboundPackets(r, sent_packets); if (!ok) { return; } assert old(r.Env().net.history()) + netEventLog == r.Env().net.history(); // deleteme assert SpontaneousIos(ios, 0); assert AbstractifyOutboundCPacketsToSeqOfRslPackets(sent_packets) == ExtractSentPacketsFromIos(ios); assert r.Env() == old(r.Env()); assert RawIoConsistentWithSpecIO(netEventLog, ios); lemma_EstablishQLReplicaNoReceiveNextFromNoClock(replica_old, r.AbstractifyToLReplica(), AbstractifyOutboundCPacketsToSeqOfRslPackets(sent_packets), r.nextActionIndex as int, ios); } lemma lemma_RevealQFromReplicaNextSpontaneousMaybeExecutePostconditions( replica:LReplica, replica':ReplicaState, packets_sent:OutboundPackets ) requires Replica_Next_Spontaneous_MaybeExecute_Postconditions(replica, replica', packets_sent) ensures Q_LReplica_Next_Spontaneous_MaybeExecute(replica, AbstractifyReplicaStateToLReplica(replica'), AbstractifyOutboundCPacketsToSeqOfRslPackets(packets_sent)); { reveal Q_LReplica_Next_Spontaneous_MaybeExecute(); } method ReplicaNoReceiveNoClockNextSpontaneousMaybeExecute(r:ReplicaImpl) returns (ok:bool, ghost netEventLog:seq, ghost ios:seq) requires r.nextActionIndex==6 requires r.Valid() modifies r.replica.executor.app, r.Repr, r.cur_req_set, r.prev_req_set, r.reply_cache_mutable ensures r.Repr == old(r.Repr) ensures r.netClient != null ensures ok == NetClientOk(r.netClient) ensures r.Env() == old(r.Env()); ensures ok ==> && r.Valid() && r.nextActionIndex == old(r.nextActionIndex) && Q_LReplica_NoReceive_Next(old(r.AbstractifyToLReplica()), r.nextActionIndex as int, r.AbstractifyToLReplica(), ios) && RawIoConsistentWithSpecIO(netEventLog, ios) && OnlySentMarshallableData(netEventLog) && old(r.Env().net.history()) + netEventLog == r.Env().net.history() { ghost var replica_old := AbstractifyReplicaStateToLReplica(r.replica); var sent_packets; r.replica,sent_packets := Replica_Next_Spontaneous_MaybeExecute(r.replica, r.cur_req_set, r.prev_req_set, r.reply_cache_mutable); lemma_RevealQFromReplicaNextSpontaneousMaybeExecutePostconditions(replica_old, r.replica, sent_packets); ok, netEventLog, ios := DeliverOutboundPackets(r, sent_packets); if (!ok) { return; } assert old(r.Env().net.history()) + netEventLog == r.Env().net.history(); // deleteme assert SpontaneousIos(ios, 0); assert AbstractifyOutboundCPacketsToSeqOfRslPackets(sent_packets) == ExtractSentPacketsFromIos(ios); assert r.Env() == old(r.Env()); assert RawIoConsistentWithSpecIO(netEventLog, ios); assert Q_LReplica_Next_Spontaneous_MaybeExecute(replica_old, r.AbstractifyToLReplica(), AbstractifyOutboundCPacketsToSeqOfRslPackets(sent_packets)); lemma_EstablishQLReplicaNoReceiveNextFromNoClock(replica_old, r.AbstractifyToLReplica(), AbstractifyOutboundCPacketsToSeqOfRslPackets(sent_packets), r.nextActionIndex as int, ios); } method Replica_NoReceive_NoClock_Next(r:ReplicaImpl) returns (ok:bool, ghost netEventLog:seq, ghost ios:seq) requires r.nextActionIndex==1 || r.nextActionIndex==2 || r.nextActionIndex==4 || r.nextActionIndex==5 || r.nextActionIndex==6 requires r.Valid() modifies r.replica.executor.app, r.Repr, r.cur_req_set, r.prev_req_set, r.reply_cache_mutable ensures r.Repr == old(r.Repr) ensures r.netClient != null ensures ok == NetClientOk(r.netClient) ensures r.Env() == old(r.Env()); ensures ok ==> && r.Valid() && r.nextActionIndex == old(r.nextActionIndex) && Q_LReplica_NoReceive_Next(old(r.AbstractifyToLReplica()), r.nextActionIndex as int, r.AbstractifyToLReplica(), ios) && RawIoConsistentWithSpecIO(netEventLog, ios) && OnlySentMarshallableData(netEventLog) && old(r.Env().net.history()) + netEventLog == r.Env().net.history() { if r.nextActionIndex == 1 { ok, netEventLog, ios := ReplicaNoReceiveNoClockNextSpontaneousMaybeEnterNewViewAndSend1a(r); } else if r.nextActionIndex == 2 { ok, netEventLog, ios := ReplicaNoReceiveNoClockNextSpontaneousMaybeEnterPhase2(r); } else if r.nextActionIndex == 4 { ok, netEventLog, ios := ReplicaNoReceiveNoClockNextSpontaneousTruncateLogBasedOnCheckpoints(r); } else if r.nextActionIndex == 5 { ok, netEventLog, ios := ReplicaNoReceiveNoClockNextSpontaneousMaybeMakeDecision(r); } else if r.nextActionIndex == 6 { ok, netEventLog, ios := ReplicaNoReceiveNoClockNextSpontaneousMaybeExecute(r); } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/RSL/ReplicaImplProcessPacketNoClock.i.dfy ================================================ include "../../Common/Collections/Seqs.i.dfy" include "../../../Libraries/Math/mod_auto.i.dfy" include "../../Protocol/RSL/Replica.i.dfy" include "ReplicaModel.i.dfy" include "ReplicaImplLemmas.i.dfy" include "ReplicaImplClass.i.dfy" include "ReplicaImplDelivery.i.dfy" include "NetRSL.i.dfy" include "CClockReading.i.dfy" module LiveRSL__ReplicaImplProcessPacketNoClock_i { import opened Native__Io_s import opened Native__NativeTypes_s import opened Collections__Seqs_i import opened Math__mod_auto_i import opened LiveRSL__AppInterface_i import opened LiveRSL__CClockReading_i import opened LiveRSL__CMessage_i import opened LiveRSL__CMessageRefinements_i import opened LiveRSL__CPaxosConfiguration_i import opened LiveRSL__Environment_i import opened LiveRSL__PacketParsing_i import opened LiveRSL__QRelations_i import opened LiveRSL__Replica_i import opened LiveRSL__ReplicaConstantsState_i import opened LiveRSL__ReplicaImplLemmas_i import opened LiveRSL__ReplicaImplClass_i import opened LiveRSL__ReplicaImplDelivery_i import opened LiveRSL__ReplicaModel_i import opened LiveRSL__ReplicaModel_Part1_i import opened LiveRSL__ReplicaModel_Part2_i import opened LiveRSL__ReplicaModel_Part3_i import opened LiveRSL__ReplicaModel_Part4_i import opened LiveRSL__ReplicaModel_Part5_i import opened LiveRSL__ReplicaState_i import opened LiveRSL__Types_i import opened LiveRSL__NetRSL_i import opened Common__NetClient_i import opened Environment_s import opened Logic__Option_i import opened Common__Util_i lemma lemma_ReplicaNextProcessPacketWithoutReadingClockHelper( cpacket:CPacket, sent_packets:OutboundPackets, old_net_history:seq, post_receive_net_history:seq, current_net_history:seq, receive_event:NetEvent, send_events:seq, receive_io:RslIo, send_ios:seq ) returns ( netEventLog:seq, ios:seq ) requires post_receive_net_history == old_net_history + [receive_event] requires current_net_history == post_receive_net_history + send_events // From Receive: requires receive_event.LIoOpReceive? requires !cpacket.msg.CMessage_Heartbeat? requires CPacketIsAbstractable(cpacket) requires NetEventIsAbstractable(receive_event) requires AbstractifyCPacketToRslPacket(cpacket) == AbstractifyNetPacketToRslPacket(receive_event.r) requires receive_io == AbstractifyNetEventToRslIo(receive_event) // From DeliverOutboundPackets: requires AllIosAreSends(send_ios) requires OutboundPacketsIsAbstractable(sent_packets) requires AbstractifyOutboundCPacketsToSeqOfRslPackets(sent_packets) == ExtractSentPacketsFromIos(send_ios) requires RawIoConsistentWithSpecIO(send_events, send_ios) requires OnlySentMarshallableData(send_events) ensures RawIoConsistentWithSpecIO(netEventLog, ios) ensures |ios| >= 1 ensures ios[0] == receive_io ensures AllIosAreSends(ios[1..]) ensures current_net_history == old_net_history + netEventLog ensures AbstractifyOutboundCPacketsToSeqOfRslPackets(sent_packets) == ExtractSentPacketsFromIos(ios) ensures OnlySentMarshallableData(netEventLog) { var ios_head := [receive_io]; ios := ios_head + send_ios; netEventLog := [receive_event] + send_events; calc { AbstractifyOutboundCPacketsToSeqOfRslPackets(sent_packets); ExtractSentPacketsFromIos(send_ios); { lemma_ExtractSentPacketsFromIosDoesNotMindSomeClutter(ios_head, send_ios); } ExtractSentPacketsFromIos(ios_head + send_ios); ExtractSentPacketsFromIos(ios); } forall io | io in ios[1..] ensures io.LIoOpSend? { var idx :| 0<=idx<|ios[1..]| && io==ios[1..][idx]; // because spec uses 'in seq' instead of indexing assert io == send_ios[idx]; assert AllIosAreSends(send_ios); assert io.LIoOpSend?; } assert NetEventLogIsAbstractable(netEventLog); assert AbstractifyRawLogToIos(netEventLog) == ios; lemma_ExtractSentPacketsFromIosDoesNotMindSomeClutter(ios_head, send_ios); } method {:fuel AbstractifyReplicaStateToLReplica,0,0} {:fuel ReplicaStateIsValid,0,0} ReplicaNextProcessPacketInvalid( r:ReplicaImpl, cpacket:CPacket, ghost old_net_history:seq, ghost receive_event:NetEvent, ghost receive_io:RslIo ) returns ( ghost netEventLog:seq, ghost ios:seq ) requires r.Valid() requires old_net_history + [receive_event] == r.Env().net.history() requires CPaxosConfigurationIsValid(r.replica.constants.all.config) requires r.ReceivedPacketProperties(cpacket, receive_event, receive_io) requires cpacket.msg.CMessage_Invalid? requires LReplica_Next_ProcessPacketWithoutReadingClock_preconditions([receive_io]) ensures LReplica_Next_ProcessPacketWithoutReadingClock_preconditions(ios) ensures Q_LReplica_Next_ProcessPacketWithoutReadingClock(old(r.AbstractifyToLReplica()), r.AbstractifyToLReplica(), ios) ensures RawIoConsistentWithSpecIO(netEventLog, ios) ensures old_net_history + netEventLog == r.Env().net.history() ensures OnlySentMarshallableData(netEventLog) { //print ("Replica_Next_ProcessPacketWithoutReadingClock_body: Enter\n"); ghost var replica_old := AbstractifyReplicaStateToLReplica(r.replica); ghost var rreplica := AbstractifyReplicaStateToLReplica(r.replica); ghost var lpacket := AbstractifyCPacketToRslPacket(cpacket); //print ("Replica_Next_ProcessPacketWithoutReadingClock_body: Processing a CMessage_Invalid\n"); var sent_packets := OutboundPacket(None()); assert AbstractifyOutboundCPacketsToSeqOfRslPackets(sent_packets) == []; assert Q_LReplica_Next_Process_Invalid(rreplica, r.AbstractifyToLReplica(), lpacket, AbstractifyOutboundCPacketsToSeqOfRslPackets(sent_packets)); ghost var send_events := []; ghost var send_ios := []; netEventLog, ios := lemma_ReplicaNextProcessPacketWithoutReadingClockHelper(cpacket, sent_packets, old_net_history, old(r.Env().net.history()), r.Env().net.history(), receive_event, send_events, receive_io, send_ios); lemma_EstablishQLReplicaNextProcessPacketWithoutReadingClock(rreplica, AbstractifyReplicaStateToLReplica(r.replica), lpacket, AbstractifyOutboundCPacketsToSeqOfRslPackets(sent_packets), ios); //print ("Replica_Next_ProcessPacketWithoutReadingClock_body: Exit\n"); } lemma lemma_RevealQFromReplicaNextProcessRequestPostconditions( replica:LReplica, replica':ReplicaState, inp:CPacket, packets_sent:OutboundPackets ) requires Replica_Next_Process_Request_Postconditions(replica, replica', inp, packets_sent) ensures Q_LReplica_Next_Process_Request(replica, AbstractifyReplicaStateToLReplica(replica'), AbstractifyCPacketToRslPacket(inp), AbstractifyOutboundCPacketsToSeqOfRslPackets(packets_sent)); { reveal Q_LReplica_Next_Process_Request(); } method {:fuel AbstractifyReplicaStateToLReplica,0,0} {:fuel ReplicaStateIsValid,0,0} {:timeLimitMultiplier 2} ReplicaNextProcessPacketRequest( r:ReplicaImpl, cpacket:CPacket, ghost old_net_history:seq, ghost receive_event:NetEvent, ghost receive_io:RslIo ) returns ( ok:bool, ghost netEventLog:seq, ghost ios:seq ) requires r.Valid() requires old_net_history + [receive_event] == r.Env().net.history() requires CPaxosConfigurationIsValid(r.replica.constants.all.config) requires r.ReceivedPacketProperties(cpacket, receive_event, receive_io) requires cpacket.msg.CMessage_Request? requires LReplica_Next_ProcessPacketWithoutReadingClock_preconditions([receive_io]) requires Replica_Next_Process_Request_Preconditions(r.replica, cpacket) modifies r.Repr, r.cur_req_set, r.prev_req_set, r.reply_cache_mutable ensures r.Repr==old(r.Repr) ensures r.netClient != null ensures ok == NetClientOk(r.netClient) ensures r.Env() == old(r.Env()); ensures ok ==> && r.Valid() && r.nextActionIndex == old(r.nextActionIndex) && LReplica_Next_ProcessPacketWithoutReadingClock_preconditions(ios) && Q_LReplica_Next_ProcessPacketWithoutReadingClock(old(r.AbstractifyToLReplica()), r.AbstractifyToLReplica(), ios) && OnlySentMarshallableData(netEventLog) && RawIoConsistentWithSpecIO(netEventLog, ios) && r.Env() == old(r.Env()) && old_net_history + netEventLog == r.Env().net.history() { if PrintParams.ShouldPrintProgress() { print("Received request from client "); print(cpacket.src); print(" with sequence number "); print(cpacket.msg.seqno); print("\n"); } //print ("Replica_Next_ProcessPacketWithoutReadingClock_body: Enter\n"); ghost var replica_old := AbstractifyReplicaStateToLReplica(r.replica); ghost var lpacket := AbstractifyCPacketToRslPacket(cpacket); //print ("Replica_Next_ProcessPacketWithoutReadingClock_body: Processing a CMessage_Request\n"); // Mention unchanged predicates over mutable state in the old heap. ghost var net_client_old := r.netClient; ghost var net_addr_old := r.netClient.MyPublicKey(); assert NetClientIsValid(net_client_old); var sent_packets; r.replica, sent_packets := Replica_Next_Process_Request(r.replica, cpacket, r.cur_req_set, r.prev_req_set, r.reply_cache_mutable); // Mention unchanged predicates over mutable state in the new heap. assert net_client_old == r.netClient; assert NetClientIsValid(r.netClient); assert net_addr_old == r.netClient.MyPublicKey(); lemma_RevealQFromReplicaNextProcessRequestPostconditions(replica_old, r.replica, cpacket, sent_packets); assert OutboundPacketsHasCorrectSrc(sent_packets, r.replica.constants.all.config.replica_ids[r.replica.constants.my_index]); ghost var send_events, send_ios; assert r.Valid(); ok, send_events, send_ios := DeliverOutboundPackets(r, sent_packets); if (!ok) { return; } netEventLog, ios := lemma_ReplicaNextProcessPacketWithoutReadingClockHelper(cpacket, sent_packets, old_net_history, old(r.Env().net.history()), r.Env().net.history(), receive_event, send_events, receive_io, send_ios); lemma_EstablishQLReplicaNextProcessPacketWithoutReadingClock(replica_old, AbstractifyReplicaStateToLReplica(r.replica), lpacket, AbstractifyOutboundCPacketsToSeqOfRslPackets(sent_packets), ios); //print ("Replica_Next_ProcessPacketWithoutReadingClock_body: Exit\n"); } lemma lemma_RevealQFromReplicaNextProcess1aPostconditions( replica:LReplica, replica':ReplicaState, inp:CPacket, packets_sent:OutboundPackets ) requires Replica_Next_Process_1a_Postconditions(replica, replica', inp, packets_sent) ensures Q_LReplica_Next_Process_1a(replica, AbstractifyReplicaStateToLReplica(replica'), AbstractifyCPacketToRslPacket(inp), AbstractifyOutboundCPacketsToSeqOfRslPackets(packets_sent)); { reveal Q_LReplica_Next_Process_1a(); } method {:fuel AbstractifyReplicaStateToLReplica,0,0} {:fuel ReplicaStateIsValid,0,0} {:timeLimitMultiplier 2} ReplicaNextProcessPacket1a( r:ReplicaImpl, cpacket:CPacket, ghost old_net_history:seq, ghost receive_event:NetEvent, ghost receive_io:RslIo ) returns ( ok:bool, ghost netEventLog:seq, ghost ios:seq ) requires r.Valid() requires old_net_history + [receive_event] == r.Env().net.history() requires CPaxosConfigurationIsValid(r.replica.constants.all.config) requires r.ReceivedPacketProperties(cpacket, receive_event, receive_io) requires cpacket.msg.CMessage_1a? requires LReplica_Next_ProcessPacketWithoutReadingClock_preconditions([receive_io]) requires Replica_Next_Process_1a_Preconditions(r.replica, cpacket) modifies r.Repr ensures r.Repr==old(r.Repr) ensures r.netClient != null ensures ok == NetClientOk(r.netClient) ensures r.Env() == old(r.Env()); ensures ok ==> && r.Valid() && r.nextActionIndex == old(r.nextActionIndex) && LReplica_Next_ProcessPacketWithoutReadingClock_preconditions(ios) && Q_LReplica_Next_ProcessPacketWithoutReadingClock(old(r.AbstractifyToLReplica()), r.AbstractifyToLReplica(), ios) && RawIoConsistentWithSpecIO(netEventLog, ios) && OnlySentMarshallableData(netEventLog) && r.Env() == old(r.Env()) && old_net_history + netEventLog == r.Env().net.history() { //print ("Replica_Next_ProcessPacketWithoutReadingClock_body: Enter\n"); ghost var replica_old := AbstractifyReplicaStateToLReplica(r.replica); ghost var lpacket := AbstractifyCPacketToRslPacket(cpacket); //print ("Replica_Next_ProcessPacketWithoutReadingClock_body: Processing a CMessage_1a\n"); // Mention unchanged predicates over mutable state in the old heap. ghost var net_client_old := r.netClient; ghost var net_addr_old := r.netClient.MyPublicKey(); assert NetClientIsValid(net_client_old); var sent_packets; r.replica, sent_packets := Replica_Next_Process_1a(r.replica, cpacket); // Mention unchanged predicates over mutable state in the new heap. assert net_client_old == r.netClient; assert NetClientIsValid(r.netClient); assert net_addr_old == r.netClient.MyPublicKey(); lemma_RevealQFromReplicaNextProcess1aPostconditions(replica_old, r.replica, cpacket, sent_packets); assert OutboundPacketsHasCorrectSrc(sent_packets, r.replica.constants.all.config.replica_ids[r.replica.constants.my_index]); ghost var send_events, send_ios; assert r.Valid(); ok, send_events, send_ios := DeliverOutboundPackets(r, sent_packets); if (!ok) { return; } netEventLog, ios := lemma_ReplicaNextProcessPacketWithoutReadingClockHelper(cpacket, sent_packets, old_net_history, old(r.Env().net.history()), r.Env().net.history(), receive_event, send_events, receive_io, send_ios); lemma_EstablishQLReplicaNextProcessPacketWithoutReadingClock(replica_old, AbstractifyReplicaStateToLReplica(r.replica), lpacket, AbstractifyOutboundCPacketsToSeqOfRslPackets(sent_packets), ios); //print ("Replica_Next_ProcessPacketWithoutReadingClock_body: Exit\n"); } lemma lemma_RevealQFromReplicaNextProcess1bPostconditions( replica:LReplica, replica':ReplicaState, inp:CPacket, packets_sent:OutboundPackets ) requires Replica_Next_Process_1b_Postconditions(replica, replica', inp, packets_sent) ensures Q_LReplica_Next_Process_1b(replica, AbstractifyReplicaStateToLReplica(replica'), AbstractifyCPacketToRslPacket(inp), AbstractifyOutboundCPacketsToSeqOfRslPackets(packets_sent)); { reveal Q_LReplica_Next_Process_1b(); } method {:fuel AbstractifyReplicaStateToLReplica,0,0} {:fuel ReplicaStateIsValid,0,0} {:timeLimitMultiplier 2} ReplicaNextProcessPacket1b( r:ReplicaImpl, cpacket:CPacket, ghost old_net_history:seq, ghost receive_event:NetEvent, ghost receive_io:RslIo ) returns ( ok:bool, ghost netEventLog:seq, ghost ios:seq ) requires r.Valid() requires old_net_history + [receive_event] == r.Env().net.history() requires CPaxosConfigurationIsValid(r.replica.constants.all.config) requires r.ReceivedPacketProperties(cpacket, receive_event, receive_io) requires cpacket.msg.CMessage_1b? requires LReplica_Next_ProcessPacketWithoutReadingClock_preconditions([receive_io]) requires Replica_Next_Process_1b_Preconditions(r.replica,cpacket) modifies r.Repr ensures r.Repr==old(r.Repr) ensures r.netClient != null ensures ok == NetClientOk(r.netClient) ensures r.Env() == old(r.Env()); ensures ok ==> && r.Valid() && r.nextActionIndex == old(r.nextActionIndex) && LReplica_Next_ProcessPacketWithoutReadingClock_preconditions(ios) && Q_LReplica_Next_ProcessPacketWithoutReadingClock(old(r.AbstractifyToLReplica()), r.AbstractifyToLReplica(), ios) && RawIoConsistentWithSpecIO(netEventLog, ios) && OnlySentMarshallableData(netEventLog) && r.Env() == old(r.Env()) && old_net_history + netEventLog == r.Env().net.history() { //print ("Replica_Next_ProcessPacketWithoutReadingClock_body: Enter\n"); ghost var replica_old := AbstractifyReplicaStateToLReplica(r.replica); ghost var lpacket := AbstractifyCPacketToRslPacket(cpacket); //print ("Replica_Next_ProcessPacketWithoutReadingClock_body: Processing a CMessage_1b\n"); // Mention unchanged predicates over mutable state in the old heap. ghost var net_client_old := r.netClient; ghost var net_addr_old := r.netClient.MyPublicKey(); assert NetClientIsValid(net_client_old); var sent_packets; r.replica, sent_packets := Replica_Next_Process_1b(r.replica, cpacket); // Mention unchanged predicates over mutable state in the new heap. assert net_client_old == r.netClient; assert NetClientIsValid(r.netClient); assert net_addr_old == r.netClient.MyPublicKey(); lemma_RevealQFromReplicaNextProcess1bPostconditions(replica_old, r.replica, cpacket, sent_packets); assert OutboundPacketsHasCorrectSrc(sent_packets, r.replica.constants.all.config.replica_ids[r.replica.constants.my_index]); ghost var send_events, send_ios; assert r.Valid(); ok, send_events, send_ios := DeliverOutboundPackets(r, sent_packets); if (!ok) { return; } netEventLog, ios := lemma_ReplicaNextProcessPacketWithoutReadingClockHelper(cpacket, sent_packets, old_net_history, old(r.Env().net.history()), r.Env().net.history(), receive_event, send_events, receive_io, send_ios); lemma_EstablishQLReplicaNextProcessPacketWithoutReadingClock(replica_old, AbstractifyReplicaStateToLReplica(r.replica), lpacket, AbstractifyOutboundCPacketsToSeqOfRslPackets(sent_packets), ios); //print ("Replica_Next_ProcessPacketWithoutReadingClock_body: Exit\n"); } lemma lemma_RevealQFromReplicaNextProcessStartingPhase2Postconditions( replica:LReplica, replica':ReplicaState, inp:CPacket, packets_sent:OutboundPackets ) requires Replica_Next_Process_StartingPhase2_Postconditions(replica, replica', inp, packets_sent) ensures Q_LReplica_Next_Process_StartingPhase2(replica, AbstractifyReplicaStateToLReplica(replica'), AbstractifyCPacketToRslPacket(inp), AbstractifyOutboundCPacketsToSeqOfRslPackets(packets_sent)) { reveal Q_LReplica_Next_Process_StartingPhase2(); } method {:fuel AbstractifyReplicaStateToLReplica,0,0} {:fuel ReplicaStateIsValid,0,0} {:timeLimitMultiplier 5} ReplicaNextProcessPacketStartingPhase2( r:ReplicaImpl, cpacket:CPacket, ghost old_net_history:seq, ghost receive_event:NetEvent, ghost receive_io:RslIo ) returns ( ok:bool, ghost netEventLog:seq, ghost ios:seq ) requires r.Valid() requires old_net_history + [receive_event] == r.Env().net.history() requires CPaxosConfigurationIsValid(r.replica.constants.all.config) requires r.ReceivedPacketProperties(cpacket, receive_event, receive_io) requires cpacket.msg.CMessage_StartingPhase2? requires LReplica_Next_ProcessPacketWithoutReadingClock_preconditions([receive_io]) modifies r.Repr ensures r.Repr==old(r.Repr) ensures r.netClient != null ensures ok == NetClientOk(r.netClient) ensures r.Env() == old(r.Env()); ensures ok ==> && r.Valid() && r.nextActionIndex == old(r.nextActionIndex) && LReplica_Next_ProcessPacketWithoutReadingClock_preconditions(ios) && Q_LReplica_Next_ProcessPacketWithoutReadingClock(old(r.AbstractifyToLReplica()), r.AbstractifyToLReplica(), ios) && RawIoConsistentWithSpecIO(netEventLog, ios) && OnlySentMarshallableData(netEventLog) && r.Env() == old(r.Env()) && old_net_history + netEventLog == r.Env().net.history() { //print ("Replica_Next_ProcessPacketWithoutReadingClock_body: Enter\n"); ghost var replica_old := AbstractifyReplicaStateToLReplica(r.replica); ghost var lpacket := AbstractifyCPacketToRslPacket(cpacket); //print ("Replica_Next_ProcessPacketWithoutReadingClock_body: Processing a CMessage_StartingPhase2\n"); // Mention unchanged predicates over mutable state in the old heap. ghost var net_client_old := r.netClient; ghost var net_addr_old := r.netClient.MyPublicKey(); assert NetClientIsValid(net_client_old); var sent_packets; r.replica, sent_packets := Replica_Next_Process_StartingPhase2(r.replica, cpacket); // Mention unchanged predicates over mutable state in the new heap. assert net_client_old == r.netClient; assert NetClientIsValid(r.netClient); assert net_addr_old == r.netClient.MyPublicKey(); lemma_RevealQFromReplicaNextProcessStartingPhase2Postconditions(replica_old, r.replica, cpacket, sent_packets); assert OutboundPacketsHasCorrectSrc(sent_packets, r.replica.constants.all.config.replica_ids[r.replica.constants.my_index]); ghost var send_events, send_ios; assert r.Valid(); ok, send_events, send_ios := DeliverOutboundPackets(r, sent_packets); if (!ok) { return; } netEventLog, ios := lemma_ReplicaNextProcessPacketWithoutReadingClockHelper(cpacket, sent_packets, old_net_history, old(r.Env().net.history()), r.Env().net.history(), receive_event, send_events, receive_io, send_ios); lemma_EstablishQLReplicaNextProcessPacketWithoutReadingClock(replica_old, AbstractifyReplicaStateToLReplica(r.replica), lpacket, AbstractifyOutboundCPacketsToSeqOfRslPackets(sent_packets), ios); //print ("Replica_Next_ProcessPacketWithoutReadingClock_body: Exit\n"); } lemma lemma_RevealQFromReplicaNextProcess2aPostconditions( replica:LReplica, replica':ReplicaState, inp:CPacket, packets_sent:OutboundPackets ) requires Replica_Next_Process_2a_Postconditions(replica, replica', inp, packets_sent) ensures Q_LReplica_Next_Process_2a(replica, AbstractifyReplicaStateToLReplica(replica'), AbstractifyCPacketToRslPacket(inp), AbstractifyOutboundCPacketsToSeqOfRslPackets(packets_sent)); { reveal Q_LReplica_Next_Process_2a(); } method {:fuel AbstractifyReplicaStateToLReplica,0,0} {:fuel ReplicaStateIsValid,0,0} {:timeLimitMultiplier 2} ReplicaNextProcessPacket2a( r:ReplicaImpl, cpacket:CPacket, ghost old_net_history:seq, ghost receive_event:NetEvent, ghost receive_io:RslIo ) returns ( ok:bool, ghost netEventLog:seq, ghost ios:seq ) requires r.Valid() requires old_net_history + [receive_event] == r.Env().net.history() requires CPaxosConfigurationIsValid(r.replica.constants.all.config) requires r.ReceivedPacketProperties(cpacket, receive_event, receive_io) requires cpacket.msg.CMessage_2a? requires LReplica_Next_ProcessPacketWithoutReadingClock_preconditions([receive_io]) requires Replica_Next_Process_2a_Preconditions(r.replica,cpacket) modifies r.Repr ensures r.Repr==old(r.Repr) ensures r.netClient != null ensures ok == NetClientOk(r.netClient) ensures r.Env() == old(r.Env()); ensures ok ==> && r.Valid() && r.nextActionIndex == old(r.nextActionIndex) && LReplica_Next_ProcessPacketWithoutReadingClock_preconditions(ios) && Q_LReplica_Next_ProcessPacketWithoutReadingClock(old(r.AbstractifyToLReplica()), r.AbstractifyToLReplica(), ios) && RawIoConsistentWithSpecIO(netEventLog, ios) && OnlySentMarshallableData(netEventLog) && r.Env() == old(r.Env()) && old_net_history + netEventLog == r.Env().net.history() { //print ("Replica_Next_ProcessPacketWithoutReadingClock_body: Enter\n"); ghost var replica_old := AbstractifyReplicaStateToLReplica(r.replica); ghost var lpacket := AbstractifyCPacketToRslPacket(cpacket); //print ("Replica_Next_ProcessPacketWithoutReadingClock_body: Processing a CMessage_2a\n"); // Mention unchanged predicates over mutable state in the old heap. ghost var net_client_old := r.netClient; ghost var net_addr_old := r.netClient.MyPublicKey(); assert NetClientIsValid(net_client_old); var sent_packets; r.replica, sent_packets := Replica_Next_Process_2a(r.replica, cpacket); // Mention unchanged predicates over mutable state in the new heap. assert net_client_old == r.netClient; assert NetClientIsValid(r.netClient); assert net_addr_old == r.netClient.MyPublicKey(); lemma_RevealQFromReplicaNextProcess2aPostconditions(replica_old, r.replica, cpacket, sent_packets); assert OutboundPacketsHasCorrectSrc(sent_packets, r.replica.constants.all.config.replica_ids[r.replica.constants.my_index]); ghost var send_events, send_ios; assert r.Valid(); ok, send_events, send_ios := DeliverOutboundPackets(r, sent_packets); if (!ok) { return; } netEventLog, ios := lemma_ReplicaNextProcessPacketWithoutReadingClockHelper(cpacket, sent_packets, old_net_history, old(r.Env().net.history()), r.Env().net.history(), receive_event, send_events, receive_io, send_ios); lemma_EstablishQLReplicaNextProcessPacketWithoutReadingClock(replica_old, AbstractifyReplicaStateToLReplica(r.replica), lpacket, AbstractifyOutboundCPacketsToSeqOfRslPackets(sent_packets), ios); //print ("Replica_Next_ProcessPacketWithoutReadingClock_body: Exit\n"); } lemma lemma_RevealQFromReplicaNextProcess2bPostconditions( replica:LReplica, replica':ReplicaState, inp:CPacket, packets_sent:OutboundPackets ) requires Replica_Next_Process_2b_Postconditions(replica, replica', inp, packets_sent) ensures Q_LReplica_Next_Process_2b(replica, AbstractifyReplicaStateToLReplica(replica'), AbstractifyCPacketToRslPacket(inp), AbstractifyOutboundCPacketsToSeqOfRslPackets(packets_sent)); { reveal Q_LReplica_Next_Process_2b(); } method {:fuel AbstractifyReplicaStateToLReplica,0,0} {:fuel ReplicaStateIsValid,0,0} {:timeLimitMultiplier 2} ReplicaNextProcessPacket2b( r:ReplicaImpl, cpacket:CPacket, ghost old_net_history:seq, ghost receive_event:NetEvent, ghost receive_io:RslIo ) returns ( ok:bool, ghost netEventLog:seq, ghost ios:seq ) requires r.Valid() requires old_net_history + [receive_event] == r.Env().net.history() requires CPaxosConfigurationIsValid(r.replica.constants.all.config) requires r.ReceivedPacketProperties(cpacket, receive_event, receive_io) requires cpacket.msg.CMessage_2b? requires LReplica_Next_ProcessPacketWithoutReadingClock_preconditions([receive_io]) requires Replica_Next_Process_2b_Preconditions(r.replica,cpacket) modifies r.Repr ensures r.Repr==old(r.Repr) ensures r.netClient != null ensures ok == NetClientOk(r.netClient) ensures r.Env() == old(r.Env()); ensures ok ==> && r.Valid() && r.nextActionIndex == old(r.nextActionIndex) && LReplica_Next_ProcessPacketWithoutReadingClock_preconditions(ios) && Q_LReplica_Next_ProcessPacketWithoutReadingClock(old(r.AbstractifyToLReplica()), r.AbstractifyToLReplica(), ios) && RawIoConsistentWithSpecIO(netEventLog, ios) && OnlySentMarshallableData(netEventLog) && r.Env() == old(r.Env()) && old_net_history + netEventLog == r.Env().net.history() { //print ("Replica_Next_ProcessPacketWithoutReadingClock_body: Enter\n"); ghost var replica_old := AbstractifyReplicaStateToLReplica(r.replica); ghost var lpacket := AbstractifyCPacketToRslPacket(cpacket); //print ("Replica_Next_ProcessPacketWithoutReadingClock_body: Processing a CMessage_2b\n"); // Mention unchanged predicates over mutable state in the old heap. ghost var net_client_old := r.netClient; ghost var net_addr_old := r.netClient.MyPublicKey(); assert NetClientIsValid(net_client_old); var sent_packets; r.replica, sent_packets := Replica_Next_Process_2b(r.replica, cpacket); // Mention unchanged predicates over mutable state in the new heap. assert net_client_old == r.netClient; assert NetClientIsValid(r.netClient); assert net_addr_old == r.netClient.MyPublicKey(); lemma_RevealQFromReplicaNextProcess2bPostconditions(replica_old, r.replica, cpacket, sent_packets); assert OutboundPacketsHasCorrectSrc(sent_packets, r.replica.constants.all.config.replica_ids[r.replica.constants.my_index]); ghost var send_events, send_ios; assert r.Valid(); ok, send_events, send_ios := DeliverOutboundPackets(r, sent_packets); if (!ok) { return; } netEventLog, ios := lemma_ReplicaNextProcessPacketWithoutReadingClockHelper(cpacket, sent_packets, old_net_history, old(r.Env().net.history()), r.Env().net.history(), receive_event, send_events, receive_io, send_ios); lemma_EstablishQLReplicaNextProcessPacketWithoutReadingClock(replica_old, AbstractifyReplicaStateToLReplica(r.replica), lpacket, AbstractifyOutboundCPacketsToSeqOfRslPackets(sent_packets), ios); //print ("Replica_Next_ProcessPacketWithoutReadingClock_body: Exit\n"); } method {:fuel AbstractifyReplicaStateToLReplica,0,0} {:fuel ReplicaStateIsValid,0,0} ReplicaNextProcessPacketReply( r:ReplicaImpl, cpacket:CPacket, ghost old_net_history:seq, ghost receive_event:NetEvent, ghost receive_io:RslIo ) returns ( ghost netEventLog:seq, ghost ios:seq ) requires r.Valid() requires old_net_history + [receive_event] == r.Env().net.history() requires CPaxosConfigurationIsValid(r.replica.constants.all.config) requires r.ReceivedPacketProperties(cpacket, receive_event, receive_io) requires cpacket.msg.CMessage_Reply? requires LReplica_Next_ProcessPacketWithoutReadingClock_preconditions([receive_io]) ensures LReplica_Next_ProcessPacketWithoutReadingClock_preconditions(ios) ensures Q_LReplica_Next_ProcessPacketWithoutReadingClock(old(r.AbstractifyToLReplica()), r.AbstractifyToLReplica(), ios) ensures RawIoConsistentWithSpecIO(netEventLog, ios) ensures OnlySentMarshallableData(netEventLog) ensures old_net_history + netEventLog == r.Env().net.history() { //print ("Replica_Next_ProcessPacketWithoutReadingClock_body: Enter\n"); ghost var replica_old := AbstractifyReplicaStateToLReplica(r.replica); ghost var lpacket := AbstractifyCPacketToRslPacket(cpacket); //print ("Replica_Next_ProcessPacketWithoutReadingClock_body: Processing a CMessage_Reply\n"); var sent_packets := Broadcast(CBroadcastNop); lemma_YesWeHaveNoPackets(); reveal Q_LReplica_Next_Process_Reply(); assert Q_LReplica_Next_Process_Reply(replica_old, r.AbstractifyToLReplica(), lpacket, AbstractifyOutboundCPacketsToSeqOfRslPackets(sent_packets)); ghost var send_events := []; ghost var send_ios := []; calc { ExtractSentPacketsFromIos(send_ios); { reveal ExtractSentPacketsFromIos(); } []; } netEventLog, ios := lemma_ReplicaNextProcessPacketWithoutReadingClockHelper(cpacket, sent_packets, old_net_history, old(r.Env().net.history()), r.Env().net.history(), receive_event, send_events, receive_io, send_ios); lemma_EstablishQLReplicaNextProcessPacketWithoutReadingClock(replica_old, AbstractifyReplicaStateToLReplica(r.replica), lpacket, AbstractifyOutboundCPacketsToSeqOfRslPackets(sent_packets), ios); //print ("Replica_Next_ProcessPacketWithoutReadingClock_body: Exit\n"); } lemma lemma_RevealQFromReplicaNextProcessAppStateRequestPostconditions( replica:LReplica, replica':ReplicaState, inp:CPacket, packets_sent:OutboundPackets ) requires Replica_Next_Process_AppStateRequest_Postconditions(replica, replica', inp, packets_sent) ensures Q_LReplica_Next_Process_AppStateRequest(replica, AbstractifyReplicaStateToLReplica(replica'), AbstractifyCPacketToRslPacket(inp), AbstractifyOutboundCPacketsToSeqOfRslPackets(packets_sent)) { reveal Q_LReplica_Next_Process_AppStateRequest(); } method {:fuel AbstractifyReplicaStateToLReplica,0,0} {:fuel ReplicaStateIsValid,0,0} {:timeLimitMultiplier 2} ReplicaNextProcessPacketAppStateRequest( r:ReplicaImpl, cpacket:CPacket, ghost old_net_history:seq, ghost receive_event:NetEvent, ghost receive_io:RslIo ) returns ( ok:bool, ghost netEventLog:seq, ghost ios:seq ) requires r.Valid() requires old_net_history + [receive_event] == r.Env().net.history() requires CPaxosConfigurationIsValid(r.replica.constants.all.config) requires r.ReceivedPacketProperties(cpacket, receive_event, receive_io) requires cpacket.msg.CMessage_AppStateRequest? requires LReplica_Next_ProcessPacketWithoutReadingClock_preconditions([receive_io]) modifies r.Repr, r.reply_cache_mutable ensures r.Repr==old(r.Repr) ensures r.netClient != null ensures ok == NetClientOk(r.netClient) ensures r.Env() == old(r.Env()); ensures ok ==> && r.Valid() && r.nextActionIndex == old(r.nextActionIndex) && LReplica_Next_ProcessPacketWithoutReadingClock_preconditions(ios) && Q_LReplica_Next_ProcessPacketWithoutReadingClock(old(r.AbstractifyToLReplica()), r.AbstractifyToLReplica(), ios) && RawIoConsistentWithSpecIO(netEventLog, ios) && OnlySentMarshallableData(netEventLog) && r.Env() == old(r.Env()) && old_net_history + netEventLog == r.Env().net.history() { //print ("Replica_Next_ProcessPacketWithoutReadingClock_body: Enter\n"); ghost var replica_old := AbstractifyReplicaStateToLReplica(r.replica); ghost var lpacket := AbstractifyCPacketToRslPacket(cpacket); //print ("Replica_Next_ProcessPacketWithoutReadingClock_body: Processing a CMessage_AppStateRequest\n"); // Mention unchanged predicates over mutable state in the old heap. ghost var net_client_old := r.netClient; ghost var net_addr_old := r.netClient.MyPublicKey(); assert NetClientIsValid(net_client_old); var sent_packets; r.replica, sent_packets := Replica_Next_Process_AppStateRequest(r.replica, cpacket, r.reply_cache_mutable); // Mention unchanged predicates over mutable state in the new heap. assert net_client_old == r.netClient; assert NetClientIsValid(r.netClient); assert net_addr_old == r.netClient.MyPublicKey(); lemma_RevealQFromReplicaNextProcessAppStateRequestPostconditions(replica_old, r.replica, cpacket, sent_packets); assert OutboundPacketsHasCorrectSrc(sent_packets, r.replica.constants.all.config.replica_ids[r.replica.constants.my_index]); ghost var send_events, send_ios; assert r.Valid(); ok, send_events, send_ios := DeliverOutboundPackets(r, sent_packets); if (!ok) { return; } netEventLog, ios := lemma_ReplicaNextProcessPacketWithoutReadingClockHelper(cpacket, sent_packets, old_net_history, old(r.Env().net.history()), r.Env().net.history(), receive_event, send_events, receive_io, send_ios); lemma_EstablishQLReplicaNextProcessPacketWithoutReadingClock(replica_old, AbstractifyReplicaStateToLReplica(r.replica), lpacket, AbstractifyOutboundCPacketsToSeqOfRslPackets(sent_packets), ios); //print ("Replica_Next_ProcessPacketWithoutReadingClock_body: Exit\n"); } lemma lemma_RevealQFromReplicaNextProcessAppStateSupplyPostconditions( replica:LReplica, replica':ReplicaState, inp:CPacket, packets_sent:OutboundPackets ) requires Replica_Next_Process_AppStateSupply_Postconditions(replica, replica', inp, packets_sent) ensures Q_LReplica_Next_Process_AppStateSupply(replica, AbstractifyReplicaStateToLReplica(replica'), AbstractifyCPacketToRslPacket(inp), AbstractifyOutboundCPacketsToSeqOfRslPackets(packets_sent)) { reveal Q_LReplica_Next_Process_AppStateSupply(); } method {:fuel AbstractifyReplicaStateToLReplica,0,0} {:fuel ReplicaStateIsValid,0,0} {:timeLimitMultiplier 5} ReplicaNextProcessPacketAppStateSupply( r:ReplicaImpl, cpacket:CPacket, ghost old_net_history:seq, ghost receive_event:NetEvent, ghost receive_io:RslIo ) returns ( ok:bool, ghost netEventLog:seq, ghost ios:seq ) requires r.Valid() requires old_net_history + [receive_event] == r.Env().net.history() requires CPaxosConfigurationIsValid(r.replica.constants.all.config) requires r.ReceivedPacketProperties(cpacket, receive_event, receive_io) requires cpacket.msg.CMessage_AppStateSupply? requires LReplica_Next_ProcessPacketWithoutReadingClock_preconditions([receive_io]) requires Replica_Next_Process_AppStateSupply_Preconditions(r.replica,cpacket) modifies r.Repr ensures r.Repr==old(r.Repr) ensures r.netClient != null ensures ok == NetClientOk(r.netClient) ensures r.Env() == old(r.Env()); ensures ok ==> && r.Valid() && r.nextActionIndex == old(r.nextActionIndex) && LReplica_Next_ProcessPacketWithoutReadingClock_preconditions(ios) && Q_LReplica_Next_ProcessPacketWithoutReadingClock(old(r.AbstractifyToLReplica()), r.AbstractifyToLReplica(), ios) && RawIoConsistentWithSpecIO(netEventLog, ios) && OnlySentMarshallableData(netEventLog) && r.Env() == old(r.Env()) && old_net_history + netEventLog == r.Env().net.history() { //print ("Replica_Next_ProcessPacketWithoutReadingClock_body: Enter\n"); ghost var replica_old := AbstractifyReplicaStateToLReplica(r.replica); ghost var lpacket := AbstractifyCPacketToRslPacket(cpacket); //print ("Replica_Next_ProcessPacketWithoutReadingClock_body: Processing a CMessage_AppStateSupply\n"); // Mention unchanged predicates over mutable state in the old heap. ghost var net_client_old := r.netClient; ghost var net_addr_old := r.netClient.MyPublicKey(); assert NetClientIsValid(net_client_old); var sent_packets, replicaChanged; r.replica, sent_packets, replicaChanged := Replica_Next_Process_AppStateSupply(r.replica, cpacket); // Mention unchanged predicates over mutable state in the new heap. assert net_client_old == r.netClient; assert NetClientIsValid(r.netClient); assert net_addr_old == r.netClient.MyPublicKey(); lemma_RevealQFromReplicaNextProcessAppStateSupplyPostconditions(replica_old, r.replica, cpacket, sent_packets); assert OutboundPacketsHasCorrectSrc(sent_packets, r.replica.constants.all.config.replica_ids[r.replica.constants.my_index]); ghost var send_events, send_ios; assert r.Valid(); ok, send_events, send_ios := DeliverOutboundPackets(r, sent_packets); if (!ok) { return; } netEventLog, ios := lemma_ReplicaNextProcessPacketWithoutReadingClockHelper(cpacket, sent_packets, old_net_history, old(r.Env().net.history()), r.Env().net.history(), receive_event, send_events, receive_io, send_ios); lemma_EstablishQLReplicaNextProcessPacketWithoutReadingClock(replica_old, AbstractifyReplicaStateToLReplica(r.replica), lpacket, AbstractifyOutboundCPacketsToSeqOfRslPackets(sent_packets), ios); //print ("Replica_Next_ProcessPacketWithoutReadingClock_body: Exit\n"); } method {:fuel AbstractifyReplicaStateToLReplica,0,0} {:fuel ReplicaStateIsValid,0,0} Replica_Next_ProcessPacketWithoutReadingClock_body( r:ReplicaImpl, cpacket:CPacket, ghost old_net_history:seq, ghost receive_event:NetEvent, ghost receive_io:RslIo ) returns ( ok:bool, ghost netEventLog:seq, ghost ios:seq ) requires r.Valid() requires old_net_history + [receive_event] == r.Env().net.history() requires CPaxosConfigurationIsValid(r.replica.constants.all.config) requires r.ReceivedPacketProperties(cpacket, receive_event, receive_io) requires NoClockMessage(cpacket.msg) requires LReplica_Next_ProcessPacketWithoutReadingClock_preconditions([receive_io]) requires cpacket.msg.CMessage_AppStateRequest? ==> Replica_Next_Process_AppStateRequest_Preconditions(r.replica,cpacket) requires cpacket.msg.CMessage_AppStateSupply? ==> Replica_Next_Process_AppStateSupply_Preconditions(r.replica,cpacket) requires cpacket.msg.CMessage_2b? ==> Replica_Next_Process_2b_Preconditions(r.replica,cpacket) requires cpacket.msg.CMessage_2a? ==> Replica_Next_Process_2a_Preconditions(r.replica,cpacket) requires cpacket.msg.CMessage_1a? ==> Replica_Next_Process_1a_Preconditions(r.replica,cpacket) requires cpacket.msg.CMessage_1b? ==> Replica_Next_Process_1b_Preconditions(r.replica,cpacket) requires cpacket.msg.CMessage_Request? ==> Replica_Next_Process_Request_Preconditions(r.replica,cpacket) // requires Replica_Next_Process_AppStateSupply_Preconditions(r.replica,cpacket) modifies r.Repr, r.cur_req_set, r.prev_req_set, r.reply_cache_mutable ensures r.Repr==old(r.Repr) ensures r.netClient != null ensures ok == NetClientOk(r.netClient) ensures r.Env() == old(r.Env()); ensures ok ==> && r.Valid() && r.nextActionIndex == old(r.nextActionIndex) && LReplica_Next_ProcessPacketWithoutReadingClock_preconditions(ios) && Q_LReplica_Next_ProcessPacketWithoutReadingClock(old(r.AbstractifyToLReplica()), r.AbstractifyToLReplica(), ios) && RawIoConsistentWithSpecIO(netEventLog, ios) && OnlySentMarshallableData(netEventLog) && r.Env() == old(r.Env()) && old_net_history + netEventLog == r.Env().net.history() { if (cpacket.msg.CMessage_Invalid?) { ok := true; netEventLog, ios := ReplicaNextProcessPacketInvalid(r, cpacket, old_net_history, receive_event, receive_io); } else if (cpacket.msg.CMessage_Request?) { ok, netEventLog, ios := ReplicaNextProcessPacketRequest(r, cpacket, old_net_history, receive_event, receive_io); } else if (cpacket.msg.CMessage_1a?) { ok, netEventLog, ios := ReplicaNextProcessPacket1a(r, cpacket, old_net_history, receive_event, receive_io); } else if (cpacket.msg.CMessage_1b?) { ok, netEventLog, ios := ReplicaNextProcessPacket1b(r, cpacket, old_net_history, receive_event, receive_io); } else if (cpacket.msg.CMessage_StartingPhase2?) { ok, netEventLog, ios := ReplicaNextProcessPacketStartingPhase2(r, cpacket, old_net_history, receive_event, receive_io); } else if (cpacket.msg.CMessage_2a?) { ok, netEventLog, ios := ReplicaNextProcessPacket2a(r, cpacket, old_net_history, receive_event, receive_io); } else if (cpacket.msg.CMessage_2b?) { ok, netEventLog, ios := ReplicaNextProcessPacket2b(r, cpacket, old_net_history, receive_event, receive_io); } else if (cpacket.msg.CMessage_Reply?) { ok := true; netEventLog, ios := ReplicaNextProcessPacketReply(r, cpacket, old_net_history, receive_event, receive_io); } else if (cpacket.msg.CMessage_AppStateRequest?) { ok, netEventLog, ios := ReplicaNextProcessPacketAppStateRequest(r, cpacket, old_net_history, receive_event, receive_io); } else if (cpacket.msg.CMessage_AppStateSupply?) { ok, netEventLog, ios := ReplicaNextProcessPacketAppStateSupply(r, cpacket, old_net_history, receive_event, receive_io); } else { assert false; } //print ("Replica_Next_ProcessPacketWithoutReadingClock_body: Exit\n"); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/RSL/ReplicaImplProcessPacketX.i.dfy ================================================ include "../../Common/Collections/Seqs.i.dfy" include "../../../Libraries/Math/mod_auto.i.dfy" include "../../Protocol/RSL/Replica.i.dfy" include "ReplicaModel.i.dfy" include "ReplicaImplLemmas.i.dfy" include "ReplicaImplClass.i.dfy" include "ReplicaImplReadClock.i.dfy" include "ReplicaImplProcessPacketNoClock.i.dfy" include "NetRSL.i.dfy" include "CClockReading.i.dfy" include "Unsendable.i.dfy" module LiveRSL__ReplicaImplProcessPacketX_i { import opened Native__Io_s import opened Native__NativeTypes_s import opened Collections__Seqs_i import opened Math__mod_auto_i import opened LiveRSL__CClockReading_i import opened LiveRSL__CMessage_i import opened LiveRSL__CMessageRefinements_i import opened LiveRSL__CPaxosConfiguration_i import opened LiveRSL__Environment_i import opened LiveRSL__PacketParsing_i import opened LiveRSL__QRelations_i import opened LiveRSL__Replica_i import opened LiveRSL__ReplicaImplLemmas_i import opened LiveRSL__ReplicaImplClass_i import opened LiveRSL__ReplicaImplReadClock_i import opened LiveRSL__ReplicaImplProcessPacketNoClock_i import opened LiveRSL__ReplicaModel_i import opened LiveRSL__ReplicaState_i import opened LiveRSL__Types_i import opened LiveRSL__NetRSL_i import opened LiveRSL__Unsendable_i import opened Common__NetClient_i import opened Environment_s method ReplicaNextProcessPacketTimeout(r:ReplicaImpl, ghost old_net_history:seq, ghost timeout_event:NetEvent) returns (ghost netEventLog:seq, ghost ios:seq) requires r.Valid() requires r.Env().net.history() == old_net_history + [ timeout_event ] requires timeout_event.LIoOpTimeoutReceive? ensures Q_LReplica_Next_ProcessPacket(old(r.AbstractifyToLReplica()), r.AbstractifyToLReplica(), ios) ensures RawIoConsistentWithSpecIO(netEventLog, ios) ensures old_net_history + netEventLog == r.Env().net.history() ensures OnlySentMarshallableData(netEventLog) { ios := [ LIoOpTimeoutReceive() ]; netEventLog := [ timeout_event ]; lemma_EstablishQLReplicaNextProcessPacketFromTimeout(old(r.AbstractifyToLReplica()), r.AbstractifyToLReplica(), ios); } method ReplicaNextProcessPacketUnmarshallable( r:ReplicaImpl, ghost old_net_history:seq, rr:ReceiveResult, ghost receive_event:NetEvent ) returns ( ghost netEventLog:seq, ghost ios:seq ) requires r.Valid() requires r.Env().net.history() == old_net_history + [receive_event] requires rr.RRPacket? requires receive_event.LIoOpReceive? requires !Marshallable(rr.cpacket.msg) requires NetPacketIsAbstractable(receive_event.r) requires CPacketIsAbstractable(rr.cpacket) requires AbstractifyCPacketToRslPacket(rr.cpacket) == AbstractifyNetPacketToRslPacket(receive_event.r) requires PaxosEndPointIsValid(rr.cpacket.src, r.replica.constants.all.config) requires rr.cpacket.msg == PaxosDemarshallData(receive_event.r.msg) ensures IosReflectIgnoringUnsendable(netEventLog) ensures RawIoConsistentWithSpecIO(netEventLog, ios) ensures old_net_history + netEventLog == r.Env().net.history() ensures OnlySentMarshallableData(netEventLog) { ghost var receive_io := LIoOpReceive(AbstractifyNetPacketToRslPacket(receive_event.r)); netEventLog := [receive_event]; ios := [receive_io]; } method ReplicaNextProcessPacketHeartbeat( r:ReplicaImpl, ghost old_net_history:seq, rr:ReceiveResult, ghost receive_event:NetEvent ) returns ( ok:bool, ghost netEventLog:seq, ghost ios:seq ) requires r.Valid() requires r.Env().net.history() == old_net_history + [receive_event] requires rr.RRPacket? requires receive_event.LIoOpReceive? requires rr.cpacket.msg.CMessage_Heartbeat? requires NetPacketIsAbstractable(receive_event.r) requires CPacketIsSendable(rr.cpacket) requires AbstractifyCPacketToRslPacket(rr.cpacket) == AbstractifyNetPacketToRslPacket(receive_event.r) requires PaxosEndPointIsValid(rr.cpacket.src, r.replica.constants.all.config) modifies r.Repr, r.cur_req_set, r.prev_req_set, r.reply_cache_mutable ensures r.Repr == old(r.Repr) ensures r.netClient != null ensures ok == NetClientOk(r.netClient) ensures r.Env().Valid() && r.Env().ok.ok() ==> ok ensures r.Env() == old(r.Env()); ensures ok ==> && r.Valid() && r.nextActionIndex == old(r.nextActionIndex) && Q_LReplica_Next_ProcessPacket(old(r.AbstractifyToLReplica()), r.AbstractifyToLReplica(), ios) && RawIoConsistentWithSpecIO(netEventLog, ios) && OnlySentMarshallableData(netEventLog) && old_net_history + netEventLog == r.Env().net.history() { ok := true; //var process_start_time := Time.GetDebugTimeTicks(); ghost var receive_io := LIoOpReceive(AbstractifyNetPacketToRslPacket(receive_event.r)); assert r.ReceivedPacketProperties(rr.cpacket, receive_event, receive_io); //print ("Replica_Next_ProcessPacket: Received a Hearbeat message\n"); ghost var midEnv := r.Env(); assert midEnv == old(r.Env()); ok, netEventLog, ios := Replica_Next_ReadClockAndProcessPacket(r, rr.cpacket, old_net_history, receive_event, receive_io); assert ok ==> (r.Env()==midEnv==old(r.Env())); if (ok) { assert Q_LReplica_Next_ProcessPacket(old(r.AbstractifyToLReplica()), r.AbstractifyToLReplica(), ios); } //var end_time := Time.GetDebugTimeTicks(); //RecordTimingSeq("Replica_Next_ProcessPacket_work", process_start_time, end_time); reveal Q_LReplica_Next_ProcessPacket(); } method ReplicaNextProcessPacketNonHeartbeat( r:ReplicaImpl, ghost old_net_history:seq, rr:ReceiveResult, ghost receive_event:NetEvent ) returns ( ok:bool, ghost netEventLog:seq, ghost ios:seq ) requires r.Valid() requires r.Env().net.history() == old_net_history + [receive_event] requires rr.RRPacket? requires receive_event.LIoOpReceive? requires !rr.cpacket.msg.CMessage_Heartbeat? requires NetPacketIsAbstractable(receive_event.r) requires CPaxosConfigurationIsValid(r.replica.constants.all.config) // requires Replica_Next_Process_AppStateSupply_Preconditions(r.replica,rr.cpacket) requires CPacketIsSendable(rr.cpacket) requires AbstractifyCPacketToRslPacket(rr.cpacket) == AbstractifyNetPacketToRslPacket(receive_event.r) requires PaxosEndPointIsValid(rr.cpacket.src, r.replica.constants.all.config) modifies r.Repr, r.cur_req_set, r.prev_req_set, r.reply_cache_mutable ensures r.Repr == old(r.Repr) ensures r.netClient != null ensures ok == NetClientOk(r.netClient) ensures r.Env().Valid() && r.Env().ok.ok() ==> ok ensures r.Env() == old(r.Env()); ensures ok ==> && r.Valid() && r.nextActionIndex == old(r.nextActionIndex) && Q_LReplica_Next_ProcessPacket(old(r.AbstractifyToLReplica()), r.AbstractifyToLReplica(), ios) && RawIoConsistentWithSpecIO(netEventLog, ios) && OnlySentMarshallableData(netEventLog) && old_net_history + netEventLog == r.Env().net.history() { ok := true; //var process_start_time := Time.GetDebugTimeTicks(); ghost var receive_io := LIoOpReceive(AbstractifyNetPacketToRslPacket(receive_event.r)); assert r.ReceivedPacketProperties(rr.cpacket, receive_event, receive_io); //print ("Replica_Next_ProcessPacket: Received a Hearbeat message\n"); ghost var midEnv := r.Env(); assert midEnv == old(r.Env()); ok, netEventLog, ios := Replica_Next_ProcessPacketWithoutReadingClock_body(r, rr.cpacket, old_net_history, receive_event, receive_io); assert ok ==> (r.Env()==midEnv==old(r.Env())); if (ok) { lemma_EstablishQLReplicaNextProcessPacket(old(r.AbstractifyToLReplica()), r.AbstractifyToLReplica(), ios); } //var end_time := Time.GetDebugTimeTicks(); //RecordTimingSeq("Replica_Next_ProcessPacket_work", process_start_time, end_time); } method Replica_Next_ProcessPacketX(r:ReplicaImpl) returns (ok:bool, ghost netEventLog:seq, ghost ios:seq) requires r.Valid() requires CPaxosConfigurationIsValid(r.replica.constants.all.config) // requires Replica_Next_Process_AppStateSupply_Preconditions(r.replica,r.cpacket) modifies r.Repr, r.cur_req_set, r.prev_req_set, r.reply_cache_mutable ensures r.Repr == old(r.Repr) ensures r.netClient != null ensures ok == NetClientOk(r.netClient) ensures r.Env().Valid() && r.Env().ok.ok() ==> ok ensures r.Env() == old(r.Env()); ensures ok ==> && r.Valid() && r.nextActionIndex == old(r.nextActionIndex) && (|| Q_LReplica_Next_ProcessPacket(old(r.AbstractifyToLReplica()), r.AbstractifyToLReplica(), ios) || (&& IosReflectIgnoringUnsendable(netEventLog) && old(r.AbstractifyToLReplica()) == r.AbstractifyToLReplica())) && RawIoConsistentWithSpecIO(netEventLog, ios) && OnlySentMarshallableData(netEventLog) && old(r.Env().net.history()) + netEventLog == r.Env().net.history() { ghost var old_net_history := r.Env().net.history(); //var start_time := Time.GetDebugTimeTicks(); var rr; ghost var receive_event; //print ("Replica_Next_ProcessPacket: Enter\n"); //print ("Replica_Next_ProcessPacket: Calling Receive for a packet\n"); rr, receive_event := Receive(r.netClient, r.localAddr, r.replica.constants.all.config, r.msg_grammar); //var receive_packet_time := Time.GetDebugTimeTicks(); //RecordTimingSeq("Replica_Next_Receive", start_time, receive_packet_time); assert r.Env()==old(r.Env()); if (rr.RRFail?) { ok := false; //var end_time := Time.GetDebugTimeTicks(); //RecordTimingSeq("Replica_Next_ProcessPacket_fail", start_time, end_time); return; } else if (rr.RRTimeout?) { ok := true; netEventLog, ios := ReplicaNextProcessPacketTimeout(r, old_net_history, receive_event); //var end_time := Time.GetDebugTimeTicks(); //RecordTimingSeq("Replica_Next_ProcessPacket_timeout", start_time, end_time); } else { var marshallable := DetermineIfMessageMarshallable(rr.cpacket.msg); if !marshallable { ok := true; netEventLog, ios := ReplicaNextProcessPacketUnmarshallable(r, old_net_history, rr, receive_event); } else if (rr.cpacket.msg.CMessage_Heartbeat?) { ok, netEventLog, ios := ReplicaNextProcessPacketHeartbeat(r, old_net_history, rr, receive_event); } else { ok, netEventLog, ios := ReplicaNextProcessPacketNonHeartbeat(r, old_net_history, rr, receive_event); } } //print ("Replica_Next_ProcessPacket: Exit\n"); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/RSL/ReplicaImplReadClock.i.dfy ================================================ include "../../Common/Collections/Seqs.i.dfy" include "../../../Libraries/Math/mod_auto.i.dfy" include "../../Protocol/RSL/Replica.i.dfy" include "ReplicaModel.i.dfy" include "ReplicaImplLemmas.i.dfy" include "ReplicaImplClass.i.dfy" include "ReplicaImplDelivery.i.dfy" include "NetRSL.i.dfy" include "CClockReading.i.dfy" module LiveRSL__ReplicaImplReadClock_i { import opened Native__Io_s import opened Native__NativeTypes_s import opened Collections__Seqs_i import opened Math__mod_auto_i import opened LiveRSL__CClockReading_i import opened LiveRSL__CMessage_i import opened LiveRSL__CMessageRefinements_i import opened LiveRSL__CPaxosConfiguration_i import opened LiveRSL__CTypes_i import opened LiveRSL__Environment_i import opened LiveRSL__PacketParsing_i import opened LiveRSL__QRelations_i import opened LiveRSL__Replica_i import opened LiveRSL__ReplicaModel_i import opened LiveRSL__ReplicaModel_Part4_i import opened LiveRSL__ReplicaImplLemmas_i import opened LiveRSL__ReplicaImplClass_i import opened LiveRSL__ReplicaImplDelivery_i import opened LiveRSL__ReplicaState_i import opened LiveRSL__Types_i import opened LiveRSL__NetRSL_i import opened Environment_s import opened Common__NetClient_i lemma {:timeLimitMultiplier 2} lemma_ReplicaNextReadClockAndProcessPacketHelper( old_history:seq, pre_clock_history:seq, pre_delivery_history:seq, final_history:seq, receive_event:NetEvent, clock_event:NetEvent, send_events:seq, all_events:seq, receive_io:RslIo, clock_io:RslIo, send_ios:seq, ios_head:seq, all_ios:seq ) requires pre_clock_history == old_history + [receive_event] requires pre_delivery_history == pre_clock_history + [clock_event] requires final_history == pre_delivery_history + send_events requires all_events == [receive_event, clock_event] + send_events requires NetEventIsAbstractable(receive_event) requires receive_io == AbstractifyNetEventToRslIo(receive_event) requires NetEventIsAbstractable(clock_event) requires clock_io == AbstractifyNetEventToRslIo(clock_event) requires RawIoConsistentWithSpecIO(send_events, send_ios) requires all_events == [receive_event, clock_event] + send_events requires ios_head == [receive_io, clock_io] requires all_ios == ios_head + send_ios requires receive_io.LIoOpReceive? requires clock_io.LIoOpReadClock? requires AllIosAreSends(send_ios) requires OnlySentMarshallableData(send_events) ensures final_history == old_history + all_events ensures RawIoConsistentWithSpecIO(all_events, all_ios) ensures ExtractSentPacketsFromIos(all_ios) == ExtractSentPacketsFromIos(send_ios) ensures forall io :: io in all_ios[2..] ==> io.LIoOpSend? ensures OnlySentMarshallableData(all_events) { lemma_EstablishAbstractifyRawLogToIos(all_events, all_ios); lemma_ExtractSentPacketsFromIosDoesNotMindSomeClutter(ios_head, send_ios); assert all_ios[2..] == send_ios; forall io | io in send_ios ensures io.LIoOpSend? { var i :| 0 <= i < |send_ios| && io == send_ios[i]; // OBSERVE trigger } assert AbstractifyRawLogToIos(all_events) == all_ios; calc { final_history; pre_delivery_history + send_events; pre_clock_history + [clock_event] + send_events; old_history + [receive_event] + [clock_event] + send_events; old_history + ([receive_event] + [clock_event]) + send_events; old_history + [receive_event, clock_event] + send_events; { assert [receive_event] + [clock_event] == [receive_event, clock_event]; } old_history + ([receive_event, clock_event] + send_events); { assert ([receive_event, clock_event] + send_events) == all_events; } old_history + all_events; } forall io | io in all_events && io.LIoOpSend? ensures NetPacketBound(io.s.msg) ensures Marshallable(PaxosDemarshallData(io.s.msg)) { assert io in send_events; } } method {:fuel ReplicaStateIsValid,0,0} {:timeLimitMultiplier 3} Replica_Next_ReadClockAndProcessPacket( r:ReplicaImpl, cpacket:CPacket, ghost old_net_history:seq, ghost receive_event:NetEvent, ghost receive_io:RslIo ) returns ( ok:bool, ghost net_event_log:seq, ghost ios:seq ) requires r.Valid() requires CPaxosConfigurationIsValid(r.replica.constants.all.config) requires r.ReceivedPacketProperties(cpacket, receive_event, receive_io) requires r.Env().net.history() == old_net_history + [receive_event] requires cpacket.msg.CMessage_Heartbeat? requires Replica_Next_Process_Heartbeat_Preconditions(r.replica, cpacket) modifies r.Repr, r.cur_req_set, r.prev_req_set ensures r.Repr==old(r.Repr) ensures r.netClient != null ensures ok == NetClientOk(r.netClient) ensures r.Env() == old(r.Env()); ensures ok ==> && r.Valid() && r.nextActionIndex == old(r.nextActionIndex) && LReplica_Next_ReadClockAndProcessPacket_preconditions(ios) && ios[0] == receive_io && Q_LReplica_Next_ProcessPacket(old(r.AbstractifyToLReplica()), r.AbstractifyToLReplica(), ios) && RawIoConsistentWithSpecIO(net_event_log, ios) && OnlySentMarshallableData(net_event_log) && old_net_history + net_event_log == r.Env().net.history() { var old_r_AbstractifyToLReplica := old(r.AbstractifyToLReplica()); var clock, clock_event := ReadClock(r.netClient); ghost var clock_io := LIoOpReadClock(clock.t as int); assert clock.t as int == clock_event.t; // OBSERVE uint64 assert clock_io == AbstractifyNetEventToRslIo(clock_event); var sent_packets; r.replica, sent_packets := Replica_Next_Process_Heartbeat(r.replica, cpacket, clock.t, r.cur_req_set, r.prev_req_set); ghost var send_events, send_ios; ghost var pre_delivery_history := r.Env().net.history(); ok, send_events, send_ios := DeliverOutboundPackets(r, sent_packets); if (!ok) { return; } ghost var ios_head := [receive_io, clock_io]; ios := ios_head + send_ios; net_event_log := [receive_event, clock_event] + send_events; lemma_ReplicaNextReadClockAndProcessPacketHelper(old_net_history, old(r.Env().net.history()), pre_delivery_history, r.Env().net.history(), receive_event, clock_event, send_events, net_event_log, receive_io, clock_io, send_ios, ios_head, ios); assert LReplica_Next_ReadClockAndProcessPacket_preconditions(ios); assert LReplicaNextReadClockAndProcessPacket(old(r.AbstractifyToLReplica()), r.AbstractifyToLReplica(), ios); assert LReplicaNextProcessPacket(old(r.AbstractifyToLReplica()), r.AbstractifyToLReplica(), ios); assert Q_LReplica_Next_ProcessPacket(old_r_AbstractifyToLReplica, r.AbstractifyToLReplica(), ios) by { reveal Q_LReplica_Next_ProcessPacket(); } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/RSL/ReplicaModel-Part1.i.dfy ================================================ include "AppInterface.i.dfy" include "ReplicaState.i.dfy" include "ProposerModel.i.dfy" include "AcceptorModel.i.dfy" include "LearnerModel.i.dfy" include "ExecutorModel.i.dfy" include "../Common/Util.i.dfy" module LiveRSL__ReplicaModel_Part1_i { import opened AppStateMachine_s import opened Native__Io_s import opened Native__NativeTypes_s import opened LiveRSL__AcceptorState_i import opened LiveRSL__AcceptorModel_i import opened LiveRSL__AppInterface_i import opened LiveRSL__CMessage_i import opened LiveRSL__CMessageRefinements_i import opened LiveRSL__CTypes_i import opened LiveRSL__ElectionState_i import opened LiveRSL__ExecutorModel_i import opened LiveRSL__LearnerState_i import opened LiveRSL__LearnerModel_i import opened LiveRSL__PacketParsing_i import opened LiveRSL__Proposer_i import opened LiveRSL__ProposerState_i import opened LiveRSL__ProposerModel_i import opened LiveRSL__Replica_i import opened LiveRSL__ReplicaConstantsState_i import opened LiveRSL__ReplicaState_i import opened LiveRSL__Types_i import opened Logic__Option_i method InitReplicaState(constants:ReplicaConstantsState) returns (replica:ReplicaState, cur_req_set:MutableSet, prev_req_set:MutableSet, reply_cache_mutable:MutableMap) requires ReplicaConstantsState_IsValid(constants) ensures ReplicaStateIsValid(replica) ensures replica.constants == constants ensures LReplicaInit(AbstractifyReplicaStateToLReplica(replica), AbstractifyReplicaConstantsStateToLReplicaConstants(constants)) ensures MutableSet.SetOf(cur_req_set) == replica.proposer.election_state.cur_req_set ensures MutableSet.SetOf(prev_req_set) == replica.proposer.election_state.prev_req_set ensures fresh(cur_req_set) && fresh(prev_req_set) && cur_req_set != prev_req_set ensures fresh(reply_cache_mutable) ensures replica.executor.reply_cache == MutableMap.MapOf(reply_cache_mutable) { var proposer; proposer, cur_req_set, prev_req_set := InitProposerState(constants); var acceptor := InitAcceptorState(constants); var learner := LearnerState_Init(constants); var executor; executor, reply_cache_mutable := ExecutorInit(constants); replica := ReplicaState( constants, 0, proposer, acceptor, learner, executor ); assert AbstractifyReplicaStateToLReplica(replica).constants == AbstractifyReplicaConstantsStateToLReplicaConstants(constants); } method ReplicaNextProcessRequestImplCaseInvalid( replica:ReplicaState, inp:CPacket, cur_req_set:MutableSet, prev_req_set:MutableSet, reply_cache_mutable:MutableMap ) returns ( replica':ReplicaState, packets_sent:OutboundPackets ) requires Replica_Next_Process_Request_Preconditions(replica, inp) requires !CAppRequestMarshallable(inp.msg.val) requires cur_req_set != prev_req_set requires MutableSet.SetOf(cur_req_set) == replica.proposer.election_state.cur_req_set requires MutableSet.SetOf(prev_req_set) == replica.proposer.election_state.prev_req_set requires replica.executor.reply_cache == MutableMap.MapOf(reply_cache_mutable) modifies cur_req_set, prev_req_set, reply_cache_mutable ensures Replica_Next_Process_Request_Postconditions(old(AbstractifyReplicaStateToLReplica(replica)), replica', inp, packets_sent) ensures MutableSet.SetOf(cur_req_set) == replica'.proposer.election_state.cur_req_set ensures MutableSet.SetOf(prev_req_set) == replica'.proposer.election_state.prev_req_set ensures replica'.executor.reply_cache == MutableMap.MapOf(reply_cache_mutable) { replica' := replica; packets_sent := PacketSequence([]); } method ReplicaNextProcessRequestImplCaseUncached( replica:ReplicaState, inp:CPacket, cur_req_set:MutableSet, prev_req_set:MutableSet, reply_cache_mutable:MutableMap ) returns ( replica':ReplicaState, packets_sent:OutboundPackets ) requires Replica_Next_Process_Request_Preconditions(replica, inp) requires CAppRequestMarshallable(inp.msg.val) requires cur_req_set != prev_req_set requires MutableSet.SetOf(cur_req_set) == replica.proposer.election_state.cur_req_set requires MutableSet.SetOf(prev_req_set) == replica.proposer.election_state.prev_req_set requires replica.executor.reply_cache == MutableMap.MapOf(reply_cache_mutable) requires inp.src !in MutableMap.MapOf(reply_cache_mutable) modifies cur_req_set, prev_req_set, reply_cache_mutable ensures Replica_Next_Process_Request_Postconditions(old(AbstractifyReplicaStateToLReplica(replica)), replica', inp, packets_sent) ensures MutableSet.SetOf(cur_req_set) == replica'.proposer.election_state.cur_req_set ensures MutableSet.SetOf(prev_req_set) == replica'.proposer.election_state.prev_req_set ensures replica'.executor.reply_cache == MutableMap.MapOf(reply_cache_mutable) { //var start_time := Time.GetDebugTimeTicks(); lemma_AbstractifyCReplyCacheToReplyCache_properties(replica.executor.reply_cache); ghost var s := AbstractifyReplicaStateToLReplica(replica); ghost var received_packet := AbstractifyCPacketToRslPacket(inp); assert received_packet.src !in s.executor.reply_cache; var newProposer := ProposerProcessRequest(replica.proposer, inp, cur_req_set, prev_req_set); replica' := replica.(proposer := newProposer); ghost var s' := AbstractifyReplicaStateToLReplica(replica'); packets_sent := Broadcast(CBroadcastNop); assert OutboundPacketsIsValid(packets_sent); var notCachedTime := Time.GetDebugTimeTicks(); //RecordTimingSeq("Replica_Next_Process_Request_isNotCached_ProposerProcessRequest", start_time, notCachedTime); assert LProposerProcessRequest(s.proposer, s'.proposer, received_packet); assert Replica_Next_Process_Request_Postconditions(s, replica', inp, packets_sent); } method ReplicaNextProcessRequestImplCaseCachedNonReply( replica:ReplicaState, inp:CPacket, cur_req_set:MutableSet, prev_req_set:MutableSet, reply_cache_mutable:MutableMap, cached_reply:CReply ) returns ( replica':ReplicaState, packets_sent:OutboundPackets ) requires Replica_Next_Process_Request_Preconditions(replica, inp) requires CAppRequestMarshallable(inp.msg.val) requires cur_req_set != prev_req_set requires MutableSet.SetOf(cur_req_set) == replica.proposer.election_state.cur_req_set requires MutableSet.SetOf(prev_req_set) == replica.proposer.election_state.prev_req_set requires replica.executor.reply_cache == MutableMap.MapOf(reply_cache_mutable) requires inp.src in MutableMap.MapOf(reply_cache_mutable) requires cached_reply == MutableMap.MapOf(reply_cache_mutable)[inp.src] requires !cached_reply.CReply? modifies cur_req_set, prev_req_set, reply_cache_mutable ensures Replica_Next_Process_Request_Postconditions(old(AbstractifyReplicaStateToLReplica(replica)), replica', inp, packets_sent) ensures MutableSet.SetOf(cur_req_set) == replica'.proposer.election_state.cur_req_set ensures MutableSet.SetOf(prev_req_set) == replica'.proposer.election_state.prev_req_set ensures replica'.executor.reply_cache == MutableMap.MapOf(reply_cache_mutable) { //var start_time := Time.GetDebugTimeTicks(); lemma_AbstractifyCReplyCacheToReplyCache_properties(replica.executor.reply_cache); ghost var s := AbstractifyReplicaStateToLReplica(replica); ghost var received_packet := AbstractifyCPacketToRslPacket(inp); assert !s.executor.reply_cache[received_packet.src].Reply?; var newProposer := ProposerProcessRequest(replica.proposer, inp, cur_req_set, prev_req_set); replica' := replica.(proposer := newProposer); packets_sent := Broadcast(CBroadcastNop); assert OutboundPacketsIsValid(packets_sent); var notReplyTime := Time.GetDebugTimeTicks(); //RecordTimingSeq("Replica_Next_Process_Request_isNotReply_ProposerProcessRequest", start_time, notReplyTime); assert Replica_Next_Process_Request_Postconditions(s, replica', inp, packets_sent); } method ReplicaNextProcessRequestImplCaseCachedOld( replica:ReplicaState, inp:CPacket, cur_req_set:MutableSet, prev_req_set:MutableSet ) returns ( replica':ReplicaState, packets_sent:OutboundPackets ) requires Replica_Next_Process_Request_Preconditions(replica, inp) requires CAppRequestMarshallable(inp.msg.val) requires cur_req_set != prev_req_set requires MutableSet.SetOf(cur_req_set) == replica.proposer.election_state.cur_req_set requires MutableSet.SetOf(prev_req_set) == replica.proposer.election_state.prev_req_set modifies cur_req_set, prev_req_set ensures Replica_Next_Process_Request_Postconditions(old(AbstractifyReplicaStateToLReplica(replica)), replica', inp, packets_sent) ensures MutableSet.SetOf(cur_req_set) == replica'.proposer.election_state.cur_req_set ensures MutableSet.SetOf(prev_req_set) == replica'.proposer.election_state.prev_req_set ensures replica'.executor.reply_cache == replica.executor.reply_cache { //var start_time := Time.GetDebugTimeTicks(); lemma_AbstractifyCReplyCacheToReplyCache_properties(replica.executor.reply_cache); ghost var s := AbstractifyReplicaStateToLReplica(replica); ghost var received_packet := AbstractifyCPacketToRslPacket(inp); var newProposer := ProposerProcessRequest(replica.proposer, inp, cur_req_set, prev_req_set); replica' := replica.(proposer := newProposer); packets_sent := OutboundPacket(None()); assert OutboundPacketsIsValid(packets_sent); var seqnoIsBeyondTime := Time.GetDebugTimeTicks(); //RecordTimingSeq("Replica_Next_Process_Request_seqnoIsBeyond_ProposerProcessRequest", start_time, seqnoIsBeyondTime); assert LProposerProcessRequest(AbstractifyReplicaStateToLReplica(replica).proposer, AbstractifyReplicaStateToLReplica(replica').proposer, received_packet); assert Replica_Next_Process_Request_Postconditions(s, replica', inp, packets_sent); } method ReplicaNextProcessRequestImplCaseCachedMatchingOrLaterSeqNo( replica:ReplicaState, inp:CPacket, reply_cache_mutable:MutableMap, cached_reply:CReply ) returns ( replica':ReplicaState, packets_sent:OutboundPackets ) requires Replica_Next_Process_Request_Preconditions(replica, inp) requires CAppRequestMarshallable(inp.msg.val) requires replica.executor.reply_cache == MutableMap.MapOf(reply_cache_mutable) requires inp.src in MutableMap.MapOf(reply_cache_mutable) requires cached_reply == MutableMap.MapOf(reply_cache_mutable)[inp.src] requires cached_reply.CReply? requires inp.msg.seqno <= cached_reply.seqno ensures Replica_Next_Process_Request_Postconditions(old(AbstractifyReplicaStateToLReplica(replica)), replica', inp, packets_sent) ensures replica' == replica { //var start_time := Time.GetDebugTimeTicks(); lemma_AbstractifyCReplyCacheToReplyCache_properties(replica.executor.reply_cache); ghost var s := AbstractifyReplicaStateToLReplica(replica); ghost var received_packet := AbstractifyCPacketToRslPacket(inp); assert AbstractifyCReplyToReply(replica.executor.reply_cache[inp.src]) == AbstractifyReplicaStateToLReplica(replica).executor.reply_cache[received_packet.src]; packets_sent := ExecutorProcessRequest(replica.executor, inp, cached_reply, reply_cache_mutable); assert OutboundPacketsIsValid(packets_sent); replica' := replica; var isCachedTime := Time.GetDebugTimeTicks(); //RecordTimingSeq("Replica_Next_Process_Request_isCached_ExecutorProcessRequest", start_time, isCachedTime); assert Replica_Next_Process_Request_Postconditions(s, replica', inp, packets_sent); } method Replica_Next_Process_Request( replica:ReplicaState, inp:CPacket, cur_req_set:MutableSet, prev_req_set:MutableSet, reply_cache_mutable:MutableMap ) returns ( replica':ReplicaState, packets_sent:OutboundPackets ) requires Replica_Next_Process_Request_Preconditions(replica, inp) requires cur_req_set != prev_req_set requires MutableSet.SetOf(cur_req_set) == replica.proposer.election_state.cur_req_set requires MutableSet.SetOf(prev_req_set) == replica.proposer.election_state.prev_req_set requires replica.executor.reply_cache == MutableMap.MapOf(reply_cache_mutable) modifies cur_req_set, prev_req_set, reply_cache_mutable ensures Replica_Next_Process_Request_Postconditions(old(AbstractifyReplicaStateToLReplica(replica)), replica', inp, packets_sent) ensures MutableSet.SetOf(cur_req_set) == replica'.proposer.election_state.cur_req_set ensures MutableSet.SetOf(prev_req_set) == replica'.proposer.election_state.prev_req_set ensures replica'.executor.reply_cache == MutableMap.MapOf(reply_cache_mutable) { //var start_time := Time.GetDebugTimeTicks(); //var afterCheck_time := Time.GetDebugTimeTicks(); //RecordTimingSeq("Replica_Next_Process_Request_checkIsValid", start_time, afterCheck_time); var request_valid := |inp.msg.val| <= MaxAppRequestSize(); if !request_valid { replica', packets_sent := ReplicaNextProcessRequestImplCaseInvalid(replica, inp, cur_req_set, prev_req_set, reply_cache_mutable); } else { var cached, cached_reply := reply_cache_mutable.TryGetValue(inp.src); if !cached { // ==> inp.src !in replica.executor.reply_cache { replica', packets_sent := ReplicaNextProcessRequestImplCaseUncached(replica, inp, cur_req_set, prev_req_set, reply_cache_mutable); } else if (!cached_reply.CReply?){ replica', packets_sent := ReplicaNextProcessRequestImplCaseCachedNonReply(replica, inp, cur_req_set, prev_req_set, reply_cache_mutable, cached_reply); } else if (inp.msg.seqno <= cached_reply.seqno && (cached_reply.seqno < 10 || inp.msg.seqno > cached_reply.seqno - 10)) { replica', packets_sent := ReplicaNextProcessRequestImplCaseCachedMatchingOrLaterSeqNo(replica, inp, reply_cache_mutable, cached_reply); } else { replica', packets_sent := ReplicaNextProcessRequestImplCaseCachedOld(replica, inp, cur_req_set, prev_req_set); } } assert OutboundPacketsIsValid(packets_sent); //var end_time := Time.GetDebugTimeTicks(); //RecordTimingSeq("Replica_Next_Process_Request", start_time, end_time); } method Replica_Next_Process_1a(replica:ReplicaState, inp:CPacket) returns (replica':ReplicaState, packets_sent:OutboundPackets) requires Replica_Next_Process_1a_Preconditions(replica, inp) ensures Replica_Next_Process_1a_Postconditions(old(AbstractifyReplicaStateToLReplica(replica)), replica', inp, packets_sent) ensures replica'.proposer.election_state.cur_req_set == replica.proposer.election_state.cur_req_set ensures replica'.proposer.election_state.prev_req_set == replica.proposer.election_state.prev_req_set ensures replica'.executor.reply_cache == replica.executor.reply_cache { //print("Replica_Next_Process_1a: Calling NextAcceptorState_Phase1\n"); //var start_time := Time.GetDebugTimeTicks(); var newAcceptor, packets := NextAcceptorState_Phase1(replica.acceptor, inp.msg, inp.src); replica' := replica.(acceptor := newAcceptor); assert ConstantsStayConstant(replica.acceptor, newAcceptor); assert AbstractifyAcceptorStateToAcceptor(replica.acceptor).constants == AbstractifyAcceptorStateToAcceptor(newAcceptor).constants; assert AbstractifyAcceptorStateToAcceptor(replica.acceptor).constants == AbstractifyAcceptorStateToAcceptor(replica'.acceptor).constants; packets_sent := Broadcast(packets); //var end_time := Time.GetDebugTimeTicks(); //RecordTimingSeq("Replica_Next_Process_1a", start_time, end_time); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/RSL/ReplicaModel-Part2.i.dfy ================================================ include "AppInterface.i.dfy" include "ReplicaState.i.dfy" include "ProposerModel.i.dfy" include "AcceptorModel.i.dfy" include "LearnerModel.i.dfy" include "ExecutorModel.i.dfy" include "../Common/Util.i.dfy" module LiveRSL__ReplicaModel_Part2_i { import opened Native__Io_s import opened Native__NativeTypes_s import opened LiveRSL__AcceptorState_i import opened LiveRSL__AcceptorModel_i import opened LiveRSL__AppInterface_i import opened LiveRSL__CMessage_i import opened LiveRSL__CMessageRefinements_i import opened LiveRSL__CTypes_i import opened LiveRSL__ExecutorState_i import opened LiveRSL__ExecutorModel_i import opened LiveRSL__LearnerState_i import opened LiveRSL__LearnerModel_i import opened LiveRSL__PacketParsing_i import opened LiveRSL__Proposer_i import opened LiveRSL__ProposerState_i import opened LiveRSL__ProposerModel_i import opened LiveRSL__ReplicaConstantsState_i import opened LiveRSL__ReplicaState_i import opened LiveRSL__Types_i import opened Common__NodeIdentity_i import opened Common__Util_i method ProposerSrcNotPresent(proposer:ProposerState, packet:CPacket) returns (b:bool) requires ProposerIsValid(proposer) ensures b == forall other_packet :: other_packet in proposer.received_1b_packets ==> other_packet.src != packet.src { b := forall other_packet :: other_packet in proposer.received_1b_packets ==> other_packet.src != packet.src; } method ReplicaNextProcess1bIgnore(replica:ReplicaState, inp:CPacket) returns (replica':ReplicaState, packets_sent:OutboundPackets) requires Replica_Next_Process_1b_Preconditions(replica, inp) requires || inp.src !in replica.proposer.constants.all.config.replica_ids || inp.msg.bal_1b != replica.proposer.max_ballot_i_sent_1a || replica.proposer.current_state != 1 ensures Replica_Next_Process_1b_Postconditions(old(AbstractifyReplicaStateToLReplica(replica)), replica', inp, packets_sent) ensures replica' == replica { /* if (AbstractifyCPacketToRslPacket(inp).src in AbstractifyReplicaStateToLReplica(replica).proposer.constants.all.config.replica_ids) { var hi1 := AbstractifyCPacketToRslPacket(inp).src; reveal_AbstractifyEndPointsToNodeIdentities(); var ep1 :| ep1 in replica.proposer.constants.all.config.replica_ids && AbstractifyEndPointToNodeIdentity(ep1) == hi1; var ep2 := inp.src; lemma_AbstractifyEndPointToNodeIdentity_injective(ep1, ep2); assert ep1 == ep2; assert false; } assert !(AbstractifyCPacketToRslPacket(inp).src in AbstractifyReplicaStateToLReplica(replica).proposer.constants.all.config.replica_ids); */ replica' := replica; packets_sent := Broadcast(CBroadcastNop); } method ReplicaNextProcess1bAlreadyHave1bFromSource( replica:ReplicaState, inp:CPacket ) returns ( replica':ReplicaState, packets_sent:OutboundPackets ) requires Replica_Next_Process_1b_Preconditions(replica, inp) requires !(forall other_packet :: other_packet in replica.proposer.received_1b_packets ==> other_packet.src != inp.src) ensures Replica_Next_Process_1b_Postconditions(old(AbstractifyReplicaStateToLReplica(replica)), replica', inp, packets_sent) ensures replica' == replica { lemma_AbstractifyEndPointsToNodeIdentities_properties(replica.constants.all.config.replica_ids); lemma_AbstractifySetOfCPacketsToSetOfRslPackets_srcMembership(replica.proposer.received_1b_packets, inp.src); replica' := replica; packets_sent := Broadcast(CBroadcastNop); } method ReplicaNextProcess1bActual(replica:ReplicaState, inp:CPacket) returns (replica':ReplicaState, packets_sent:OutboundPackets) requires Replica_Next_Process_1b_Preconditions(replica, inp) requires inp.src in replica.proposer.constants.all.config.replica_ids requires inp.msg.bal_1b == replica.proposer.max_ballot_i_sent_1a requires replica.proposer.current_state == 1 requires forall other_packet :: other_packet in replica.proposer.received_1b_packets ==> other_packet.src != inp.src ensures Replica_Next_Process_1b_Postconditions(old(AbstractifyReplicaStateToLReplica(replica)), replica', inp, packets_sent) ensures replica'.proposer.election_state.cur_req_set == replica.proposer.election_state.cur_req_set ensures replica'.proposer.election_state.prev_req_set == replica.proposer.election_state.prev_req_set ensures replica'.executor.reply_cache == replica.executor.reply_cache { lemma_AbstractifyEndPointsToNodeIdentities_properties(replica.constants.all.config.replica_ids); lemma_AbstractifySetOfCPacketsToSetOfRslPackets_srcMembership(replica.proposer.received_1b_packets, inp.src); packets_sent := Broadcast(CBroadcastNop); lemma_AbstractifyEndPointsToNodeIdentities_properties(replica.constants.all.config.replica_ids); //lemma_AbstractifySetOfCPacketsToSetOfRslPackets_properties(packets_sent); lemma_AbstractifySetOfCPacketsToSetOfRslPackets_srcMembership(replica.proposer.received_1b_packets, inp.src); var newProposer := ProposerProcess1b(replica.proposer, inp); var newAcceptor:= NextAcceptorState_TruncateLog(replica.acceptor, inp.msg.log_truncation_point); replica' := replica.(proposer := newProposer, acceptor := newAcceptor); assert LProposerProcess1b(AbstractifyReplicaStateToLReplica(replica).proposer, AbstractifyReplicaStateToLReplica(replica').proposer, AbstractifyCPacketToRslPacket(inp)); } method Replica_Next_Process_1b(replica:ReplicaState, inp:CPacket) returns (replica':ReplicaState, packets_sent:OutboundPackets) requires Replica_Next_Process_1b_Preconditions(replica, inp) ensures Replica_Next_Process_1b_Postconditions(old(AbstractifyReplicaStateToLReplica(replica)), replica', inp, packets_sent) ensures replica'.proposer.election_state.cur_req_set == replica.proposer.election_state.cur_req_set ensures replica'.proposer.election_state.prev_req_set == replica.proposer.election_state.prev_req_set ensures replica'.executor.reply_cache == replica.executor.reply_cache { var start_time := Time.GetDebugTimeTicks(); if || inp.src !in replica.proposer.constants.all.config.replica_ids || inp.msg.bal_1b != replica.proposer.max_ballot_i_sent_1a || replica.proposer.current_state != 1 { replica', packets_sent := ReplicaNextProcess1bIgnore(replica, inp); var end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("Replica_Next_Process_1b_discard", start_time, end_time); } else { var srcNotPresent := ProposerSrcNotPresent(replica.proposer, inp); if srcNotPresent { replica', packets_sent := ReplicaNextProcess1bActual(replica, inp); var end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("Replica_Next_Process_1b_use", start_time, end_time); } else { replica', packets_sent := ReplicaNextProcess1bAlreadyHave1bFromSource(replica, inp); var end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("Replica_Next_Process_1b_discard", start_time, end_time); } } } method Replica_Next_Process_StartingPhase2(replica:ReplicaState, inp:CPacket) returns (replica':ReplicaState, packets_sent:OutboundPackets) requires Replica_Next_Process_StartingPhase2_Preconditions(replica, inp) ensures Replica_Next_Process_StartingPhase2_Postconditions(old(AbstractifyReplicaStateToLReplica(replica)), replica', inp, packets_sent) ensures replica'.proposer.election_state.cur_req_set == replica.proposer.election_state.cur_req_set ensures replica'.proposer.election_state.prev_req_set == replica.proposer.election_state.prev_req_set ensures replica'.executor.reply_cache == replica.executor.reply_cache { var start_time := Time.GetDebugTimeTicks(); var newExecutor, packets := ExecutorProcessStartingPhase2(replica.executor, inp); replica' := replica.(executor := newExecutor); packets_sent := Broadcast(packets); //lemma_AbstractifySetOfCPacketsToSetOfRslPackets_properties(packets_sent); //lemma_AbstractifyCPacketToRslPacket_src(packets_sent, replica.constants.all.config.replica_ids[replica.constants.my_index]); var end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("Replica_Next_Process_StartingPhase2", start_time, end_time); } method ReplicaNextProcess2aIgnore(replica:ReplicaState, inp:CPacket) returns (replica':ReplicaState, packets_sent:OutboundPackets) requires Replica_Next_Process_2a_Preconditions(replica, inp) requires || inp.src !in replica.acceptor.constants.all.config.replica_ids || !BalLeq(AbstractifyCBallotToBallot(replica.acceptor.maxBallot), AbstractifyCBallotToBallot(inp.msg.bal_2a)) || inp.msg.opn_2a.n > replica.acceptor.constants.all.params.max_integer_val ensures Replica_Next_Process_2a_Postconditions(old(AbstractifyReplicaStateToLReplica(replica)), replica', inp, packets_sent) ensures replica' == replica { replica' := replica; packets_sent := Broadcast(CBroadcastNop); } method ReplicaNextProcess2aActual(replica:ReplicaState, inp:CPacket) returns (replica':ReplicaState, packets_sent:OutboundPackets) requires Replica_Next_Process_2a_Preconditions(replica, inp) requires inp.src in replica.acceptor.constants.all.config.replica_ids requires BalLeq(AbstractifyCBallotToBallot(replica.acceptor.maxBallot), AbstractifyCBallotToBallot(inp.msg.bal_2a)) requires inp.msg.opn_2a.n <= replica.acceptor.constants.all.params.max_integer_val ensures Replica_Next_Process_2a_Postconditions(old(AbstractifyReplicaStateToLReplica(replica)), replica', inp, packets_sent) ensures replica'.proposer.election_state.cur_req_set == replica.proposer.election_state.cur_req_set ensures replica'.proposer.election_state.prev_req_set == replica.proposer.election_state.prev_req_set ensures replica'.executor.reply_cache == replica.executor.reply_cache { assert replica.constants.all.params.max_integer_val > replica.constants.all.params.max_log_length > 0; var maxLogLengthMinus1:uint64 := replica.acceptor.constants.all.params.max_log_length - 1; var newLogTruncationPoint := replica.acceptor.log_truncation_point.n; //if (inp.msg.opn_2a.n - newLogTruncationPoint > maxLogLengthMinus1) { // newLogTruncationPoint := inp.msg.opn_2a.n - replica.acceptor.constants.all.params.max_log_length + 1; //} var newAcceptor, packets := NextAcceptorState_Phase2(replica.acceptor, inp.msg, inp.src); replica' := replica.(acceptor := newAcceptor); packets_sent := Broadcast(packets); } method Replica_Next_Process_2a(replica:ReplicaState, inp:CPacket) returns (replica':ReplicaState, packets_sent:OutboundPackets) requires Replica_Next_Process_2a_Preconditions(replica, inp) ensures Replica_Next_Process_2a_Postconditions(old(AbstractifyReplicaStateToLReplica(replica)), replica', inp, packets_sent) ensures replica'.proposer.election_state.cur_req_set == replica.proposer.election_state.cur_req_set ensures replica'.proposer.election_state.prev_req_set == replica.proposer.election_state.prev_req_set ensures replica'.executor.reply_cache == replica.executor.reply_cache { var start_time := Time.GetDebugTimeTicks(); // lemma_AbstractifyEndPointsToNodeIdentities_properties(replica.constants.all.config.replica_ids); var ballot_leq := CBalLeq(replica.acceptor.maxBallot, inp.msg.bal_2a); if (&& inp.src in replica.acceptor.constants.all.config.replica_ids && ballot_leq //&& replica.acceptor.log_truncation_point.n <= inp.msg.opn_2a.n && inp.msg.opn_2a.n <= replica.acceptor.constants.all.params.max_integer_val) { replica', packets_sent := ReplicaNextProcess2aActual(replica, inp); var end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("Replica_Next_Process_2a_use", start_time, end_time); } else { replica', packets_sent := ReplicaNextProcess2aIgnore(replica, inp); var end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("Replica_Next_Process_2a_discard", start_time, end_time); } //lemma_AbstractifySetOfCPacketsToSetOfRslPackets_properties(packets_sent); //lemma_AbstractifyCPacketToRslPacket_src(packets_sent, replica.constants.all.config.replica_ids[replica.constants.my_index]); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/RSL/ReplicaModel-Part3.i.dfy ================================================ include "AppInterface.i.dfy" include "ReplicaState.i.dfy" include "ProposerModel.i.dfy" include "AcceptorModel.i.dfy" include "LearnerModel.i.dfy" include "ExecutorModel.i.dfy" include "../Common/Util.i.dfy" module LiveRSL__ReplicaModel_Part3_i { import opened Native__Io_s import opened Native__NativeTypes_s import opened LiveRSL__AppInterface_i import opened LiveRSL__AcceptorModel_i import opened LiveRSL__AcceptorState_i import opened LiveRSL__CClockReading_i import opened LiveRSL__CMessage_i import opened LiveRSL__CMessageRefinements_i import opened LiveRSL__CTypes_i import opened LiveRSL__ExecutorModel_i import opened LiveRSL__ExecutorState_i import opened LiveRSL__LearnerModel_i import opened LiveRSL__LearnerState_i import opened LiveRSL__PacketParsing_i import opened LiveRSL__ProposerModel_i import opened LiveRSL__ProposerState_i import opened LiveRSL__ReplicaState_i import opened LiveRSL__Types_i import opened Common__NodeIdentity_i import opened Common__Util_i method Replica_Next_Process_2b(replica:ReplicaState, inp:CPacket) returns (replica':ReplicaState, packets_sent:OutboundPackets) requires Replica_Next_Process_2b_Preconditions(replica, inp) ensures Replica_Next_Process_2b_Postconditions(old(AbstractifyReplicaStateToLReplica(replica)), replica', inp, packets_sent) ensures replica'.proposer.election_state.cur_req_set == replica.proposer.election_state.cur_req_set ensures replica'.proposer.election_state.prev_req_set == replica.proposer.election_state.prev_req_set ensures replica'.executor.reply_cache == replica.executor.reply_cache { var start_time := Time.GetDebugTimeTicks(); ghost var r_replica := AbstractifyReplicaStateToLReplica(replica); ghost var opn := AbstractifyCPacketToRslPacket(inp).msg.opn_2b; ghost var op_learnable := r_replica.executor.ops_complete < opn || (r_replica.executor.ops_complete == opn && r_replica.executor.next_op_to_execute.OutstandingOpUnknown?); var copn := inp.msg.opn_2b; var cop_learnable := replica.executor.ops_complete.n < copn.n || (replica.executor.ops_complete.n == copn.n && replica.executor.next_op_to_execute.COutstandingOpUnknown?); assert op_learnable <==> cop_learnable; if cop_learnable { var newLearner := LearnerModel_Process2b(replica.learner, replica.executor, inp); replica' := replica.(learner := newLearner); } else { replica' := replica; } packets_sent := Broadcast(CBroadcastNop); var end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("Replica_Next_Process_2b", start_time, end_time); } method Replica_Next_Spontaneous_MaybeEnterNewViewAndSend1a(replica:ReplicaState) returns (replica':ReplicaState, packets_sent:OutboundPackets) requires Replica_Next_MaybeEnterNewViewAndSend1a_Preconditions(replica) ensures Replica_Next_MaybeEnterNewViewAndSend1a_Postconditions(old(AbstractifyReplicaStateToLReplica(replica)), replica', packets_sent) ensures replica'.proposer.election_state.cur_req_set == replica.proposer.election_state.cur_req_set ensures replica'.proposer.election_state.prev_req_set == replica.proposer.election_state.prev_req_set ensures replica'.executor.reply_cache == replica.executor.reply_cache { var start_time := Time.GetDebugTimeTicks(); var newProposer, packets := ProposerMaybeEnterNewViewAndSend1a(replica.proposer); replica' := replica.(proposer := newProposer); packets_sent := Broadcast(packets); //lemma_AbstractifySetOfCPacketsToSetOfRslPackets_properties(packets_sent); //lemma_AbstractifyCPacketToRslPacket_src(packets_sent, replica.constants.all.config.replica_ids[replica.constants.my_index]); var end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("Replica_Next_Spontaneous_MaybeEnterNewViewAndSend1a", start_time, end_time); } method Replica_Next_Spontaneous_MaybeEnterPhase2(replica:ReplicaState) returns (replica':ReplicaState, packets_sent:OutboundPackets) requires Replica_Next_MaybeEnterPhase2_Preconditions(replica) ensures Replica_Next_MaybeEnterPhase2_Postconditions(old(AbstractifyReplicaStateToLReplica(replica)), replica', packets_sent) ensures replica'.proposer.election_state.cur_req_set == replica.proposer.election_state.cur_req_set ensures replica'.proposer.election_state.prev_req_set == replica.proposer.election_state.prev_req_set ensures replica'.executor.reply_cache == replica.executor.reply_cache { var start_time := Time.GetDebugTimeTicks(); var newProposer, packets := ProposerMaybeEnterPhase2(replica.proposer, replica.acceptor.log_truncation_point); replica' := replica.(proposer := newProposer); packets_sent := Broadcast(packets); //lemma_AbstractifySetOfCPacketsToSetOfRslPackets_properties(packets_sent); //lemma_AbstractifyCPacketToRslPacket_src(packets_sent, replica.constants.all.config.replica_ids[replica.constants.my_index]); var end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("Replica_Next_Spontaneous_MaybeEnterPhase2", start_time, end_time); } method Replica_Next_Spontaneous_MaybeNominateValueAndSend2a(replica:ReplicaState, clock:CClockReading) returns (replica':ReplicaState, packets_sent:OutboundPackets) requires Replica_Next_ReadClock_MaybeNominateValueAndSend2a_Preconditions(replica) ensures Replica_Next_ReadClock_MaybeNominateValueAndSend2a_Postconditions(old(AbstractifyReplicaStateToLReplica(replica)), replica', clock, packets_sent) ensures replica'.proposer.election_state.cur_req_set == replica.proposer.election_state.cur_req_set ensures replica'.proposer.election_state.prev_req_set == replica.proposer.election_state.prev_req_set ensures replica'.executor.reply_cache == replica.executor.reply_cache { var start_time := Time.GetDebugTimeTicks(); var newProposer, packets := ProposerMaybeNominateValueAndSend2a(replica.proposer, clock.t, replica.acceptor.log_truncation_point); replica' := replica.(proposer := newProposer); packets_sent := Broadcast(packets); //lemma_AbstractifySetOfCPacketsToSetOfRslPackets_properties(packets_sent); //lemma_AbstractifyCPacketToRslPacket_src(packets_sent, replica.constants.all.config.replica_ids[replica.constants.my_index]); var end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("Replica_Next_Spontaneous_MaybeNominateValueAndSend2a", start_time, end_time); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/RSL/ReplicaModel-Part4.i.dfy ================================================ include "AppInterface.i.dfy" include "ReplicaState.i.dfy" include "ProposerModel.i.dfy" include "AcceptorModel.i.dfy" include "LearnerModel.i.dfy" include "ExecutorModel.i.dfy" include "../Common/Util.i.dfy" module LiveRSL__ReplicaModel_Part4_i { import opened Native__Io_s import opened Native__NativeTypes_s import opened LiveRSL__Acceptor_i import opened LiveRSL__AcceptorModel_i import opened LiveRSL__AcceptorState_i import opened LiveRSL__AppInterface_i import opened LiveRSL__CClockReading_i import opened LiveRSL__CMessage_i import opened LiveRSL__CMessageRefinements_i import opened LiveRSL__CTypes_i import opened LiveRSL__ElectionState_i import opened LiveRSL__Executor_i import opened LiveRSL__ExecutorModel_i import opened LiveRSL__ExecutorState_i import opened LiveRSL__LearnerModel_i import opened LiveRSL__LearnerState_i import opened LiveRSL__PacketParsing_i import opened LiveRSL__Proposer_i import opened LiveRSL__ProposerModel_i import opened LiveRSL__ProposerState_i import opened LiveRSL__Replica_i import opened LiveRSL__ReplicaState_i import opened LiveRSL__Types_i import opened Common__NodeIdentity_i import opened Common__Util_i method Replica_Next_Process_AppStateRequest( replica:ReplicaState, inp:CPacket, reply_cache_mutable:MutableMap ) returns ( replica':ReplicaState, packets_sent:OutboundPackets ) requires Replica_Next_Process_AppStateRequest_Preconditions(replica, inp) requires replica.executor.reply_cache == MutableMap.MapOf(reply_cache_mutable) ensures Replica_Next_Process_AppStateRequest_Postconditions(old(AbstractifyReplicaStateToLReplica(replica)), replica', inp, packets_sent) ensures replica'.proposer.election_state.cur_req_set == replica.proposer.election_state.cur_req_set ensures replica'.proposer.election_state.prev_req_set == replica.proposer.election_state.prev_req_set ensures replica'.executor == replica.executor { var start_time := Time.GetDebugTimeTicks(); var newExecutor, packets := ExecutorProcessAppStateRequest(replica.executor, inp, reply_cache_mutable); replica' := replica.(executor := newExecutor); packets_sent := packets; //lemma_AbstractifySetOfCPacketsToSetOfRslPackets_properties(packets_sent); //lemma_AbstractifyCPacketToRslPacket_src(packets_sent, replica.constants.all.config.replica_ids[replica.constants.my_index]); var end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("Replica_Next_Process_AppStateRequest", start_time, end_time); ghost var s := AbstractifyReplicaStateToLReplica(replica); ghost var s' := AbstractifyReplicaStateToLReplica(replica'); ghost var received_packet := AbstractifyCPacketToRslPacket(inp); ghost var sent_packets := AbstractifyOutboundCPacketsToSeqOfRslPackets(packets_sent); assert LExecutorProcessAppStateRequest(s.executor, s'.executor, received_packet, sent_packets); assert LReplicaNextProcessAppStateRequest(s, s', received_packet, sent_packets); } method Replica_Next_Process_Heartbeat( replica:ReplicaState, inp:CPacket, clock:uint64, cur_req_set:MutableSet, prev_req_set:MutableSet ) returns ( replica':ReplicaState, packets_sent:OutboundPackets ) requires Replica_Next_Process_Heartbeat_Preconditions(replica, inp) requires cur_req_set != prev_req_set requires MutableSet.SetOf(cur_req_set) == replica.proposer.election_state.cur_req_set requires MutableSet.SetOf(prev_req_set) == replica.proposer.election_state.prev_req_set modifies cur_req_set, prev_req_set ensures Replica_Next_Process_Heartbeat_Postconditions(old(AbstractifyReplicaStateToLReplica(replica)), replica', inp, clock, packets_sent) ensures MutableSet.SetOf(cur_req_set) == replica'.proposer.election_state.cur_req_set ensures MutableSet.SetOf(prev_req_set) == replica'.proposer.election_state.prev_req_set ensures replica'.executor.reply_cache == replica.executor.reply_cache { var start_time := Time.GetDebugTimeTicks(); packets_sent := Broadcast(CBroadcastNop); assert OutboundPacketsIsValid(packets_sent); var newProposer := ProposerProcessHeartbeat(replica.proposer, inp, clock, cur_req_set, prev_req_set); var newAcceptor := NextAcceptorState_ProcessHeartbeat(replica.acceptor, inp.msg, inp.src); replica' := replica.(proposer := newProposer, acceptor := newAcceptor); var end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("Replica_Next_Process_Heartbeat", start_time, end_time); ghost var s := AbstractifyReplicaStateToLReplica(replica); ghost var s' := AbstractifyReplicaStateToLReplica(replica'); ghost var received_packet := AbstractifyCPacketToRslPacket(inp); ghost var sent_packets := AbstractifyOutboundCPacketsToSeqOfRslPackets(packets_sent); assert LProposerProcessHeartbeat(s.proposer, s'.proposer, received_packet, clock as int); assert LAcceptorProcessHeartbeat(s.acceptor, s'.acceptor, received_packet); assert LReplicaNextProcessHeartbeat(s, s', received_packet, clock as int, sent_packets); } method {:timeLimitMultiplier 2} Replica_Next_ReadClock_CheckForViewTimeout( replica:ReplicaState, clock:CClockReading, cur_req_set:MutableSet, prev_req_set:MutableSet ) returns ( replica':ReplicaState, packets_sent:OutboundPackets ) requires Replica_Next_ReadClock_CheckForViewTimeout_Preconditions(replica) requires cur_req_set != prev_req_set requires MutableSet.SetOf(cur_req_set) == replica.proposer.election_state.cur_req_set requires MutableSet.SetOf(prev_req_set) == replica.proposer.election_state.prev_req_set modifies cur_req_set, prev_req_set ensures Replica_Next_ReadClock_CheckForViewTimeout_Postconditions(old(AbstractifyReplicaStateToLReplica(replica)), replica', clock, packets_sent) ensures MutableSet.SetOf(cur_req_set) == replica'.proposer.election_state.cur_req_set ensures MutableSet.SetOf(prev_req_set) == replica'.proposer.election_state.prev_req_set ensures replica'.executor.reply_cache == replica.executor.reply_cache { var start_time := Time.GetDebugTimeTicks(); var newProposer := ProposerCheckForViewTimeout(replica.proposer, clock.t, cur_req_set, prev_req_set); replica' := replica.(proposer := newProposer); packets_sent := Broadcast(CBroadcastNop); assert OutboundPacketsIsValid(packets_sent); assert OutboundPacketsHasCorrectSrc(packets_sent, replica.constants.all.config.replica_ids[replica.constants.my_index]); //lemma_AbstractifySetOfCPacketsToSetOfRslPackets_properties(packets_sent); var end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("Replica_Next_ReadClock_CheckForViewTimeout", start_time, end_time); ghost var s := AbstractifyReplicaStateToLReplica(replica); ghost var s' := AbstractifyReplicaStateToLReplica(replica'); ghost var sent_packets := AbstractifyOutboundCPacketsToSeqOfRslPackets(packets_sent); assert LProposerCheckForViewTimeout(s.proposer, s'.proposer, clock.t as int); assert LReplicaNextReadClockCheckForViewTimeout(s, s', AbstractifyCClockReadingToClockReading(clock), sent_packets); } method {:timeLimitMultiplier 2} Replica_Next_ReadClock_CheckForQuorumOfViewSuspicions( replica:ReplicaState, clock:CClockReading, cur_req_set:MutableSet, prev_req_set:MutableSet ) returns ( replica':ReplicaState, packets_sent:OutboundPackets ) requires Replica_Next_ReadClock_CheckForQuorumOfViewSuspicions_Preconditions(replica) requires cur_req_set != prev_req_set requires MutableSet.SetOf(cur_req_set) == replica.proposer.election_state.cur_req_set requires MutableSet.SetOf(prev_req_set) == replica.proposer.election_state.prev_req_set modifies cur_req_set, prev_req_set ensures Replica_Next_ReadClock_CheckForQuorumOfViewSuspicions_Postconditions(old(AbstractifyReplicaStateToLReplica(replica)), replica', clock, packets_sent) ensures MutableSet.SetOf(cur_req_set) == replica'.proposer.election_state.cur_req_set ensures MutableSet.SetOf(prev_req_set) == replica'.proposer.election_state.prev_req_set ensures replica'.executor.reply_cache == replica.executor.reply_cache { var start_time := Time.GetDebugTimeTicks(); var newProposer := ProposerCheckForQuorumOfViewSuspicions(replica.proposer, clock.t, cur_req_set, prev_req_set); replica' := replica.(proposer := newProposer); packets_sent := Broadcast(CBroadcastNop); assert OutboundPacketsIsValid(packets_sent); assert OutboundPacketsHasCorrectSrc(packets_sent, replica.constants.all.config.replica_ids[replica.constants.my_index]); //lemma_AbstractifySetOfCPacketsToSetOfRslPackets_properties(packets_sent); var end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("Replica_Next_ReadClock_CheckForQuorumOfViewSuspicions", start_time, end_time); ghost var s := AbstractifyReplicaStateToLReplica(replica); ghost var s' := AbstractifyReplicaStateToLReplica(replica'); ghost var sent_packets := AbstractifyOutboundCPacketsToSeqOfRslPackets(packets_sent); assert LProposerCheckForQuorumOfViewSuspicions(s.proposer, s'.proposer, clock.t as int); assert LReplicaNextReadClockCheckForQuorumOfViewSuspicions(s, s', AbstractifyCClockReadingToClockReading(clock), sent_packets); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/RSL/ReplicaModel-Part5.i.dfy ================================================ include "AppInterface.i.dfy" include "ReplicaState.i.dfy" include "ProposerModel.i.dfy" include "AcceptorModel.i.dfy" include "LearnerModel.i.dfy" include "ExecutorModel.i.dfy" include "../Common/Util.i.dfy" module LiveRSL__ReplicaModel_Part5_i { import opened Native__Io_s import opened Native__NativeTypes_s import opened LiveRSL__Acceptor_i import opened LiveRSL__AcceptorModel_i import opened LiveRSL__AcceptorState_i import opened LiveRSL__AppInterface_i import opened LiveRSL__CClockReading_i import opened LiveRSL__CMessage_i import opened LiveRSL__CMessageRefinements_i import opened LiveRSL__Configuration_i import opened LiveRSL__CPaxosConfiguration_i import opened LiveRSL__CTypes_i import opened LiveRSL__ElectionState_i import opened LiveRSL__Executor_i import opened LiveRSL__ExecutorModel_i import opened LiveRSL__ExecutorState_i import opened LiveRSL__Learner_i import opened LiveRSL__LearnerModel_i import opened LiveRSL__LearnerState_i import opened LiveRSL__MinCQuorumSize_i import opened LiveRSL__Proposer_i import opened LiveRSL__ProposerModel_i import opened LiveRSL__ProposerState_i import opened LiveRSL__Replica_i import opened LiveRSL__ReplicaState_i import opened LiveRSL__Types_i import opened Common__NodeIdentity_i import opened Common__UpperBound_s import opened Common__UpperBound_i import opened Common__Util_i import opened Logic__Option_i import opened Impl__LiveRSL__Broadcast_i method ReplicaNextProcessAppStateSupplyIgnore(replica:ReplicaState, inp:CPacket) returns (replica':ReplicaState, packets_sent:OutboundPackets) requires Replica_Next_Process_AppStateSupply_Preconditions(replica, inp) requires || inp.src !in replica.executor.constants.all.config.replica_ids || inp.msg.opn_state_supply.n <= replica.executor.ops_complete.n ensures Replica_Next_Process_AppStateSupply_Postconditions(old(AbstractifyReplicaStateToLReplica(replica)), replica', inp, packets_sent) ensures replica' == replica { replica' := replica; packets_sent := Broadcast(CBroadcastNop); } method ReplicaNextProcessAppStateSupplyActual( replica:ReplicaState, inp:CPacket ) returns ( replica':ReplicaState, packets_sent:OutboundPackets ) requires Replica_Next_Process_AppStateSupply_Preconditions(replica, inp) requires inp.src in replica.executor.constants.all.config.replica_ids requires inp.msg.opn_state_supply.n > replica.executor.ops_complete.n ensures Replica_Next_Process_AppStateSupply_Postconditions(old(AbstractifyReplicaStateToLReplica(replica)), replica', inp, packets_sent) ensures replica'.proposer.election_state.cur_req_set == replica.proposer.election_state.cur_req_set ensures replica'.proposer.election_state.prev_req_set == replica.proposer.election_state.prev_req_set ensures replica'.executor.reply_cache == replica.executor.reply_cache { var newLearner := LearnerModel_ForgetOperationsBefore(replica.learner, inp.msg.opn_state_supply); var newExecutor; newExecutor := ExecutorProcessAppStateSupply(replica.executor, inp); replica' := replica.(learner := newLearner, executor := newExecutor); packets_sent := Broadcast(CBroadcastNop); } method Replica_Next_Process_AppStateSupply( replica:ReplicaState, inp:CPacket ) returns ( replica':ReplicaState, packets_sent:OutboundPackets, replicaChanged:bool ) requires Replica_Next_Process_AppStateSupply_Preconditions(replica, inp) ensures Replica_Next_Process_AppStateSupply_Postconditions(old(AbstractifyReplicaStateToLReplica(replica)), replica', inp, packets_sent) ensures replica'.proposer.election_state.cur_req_set == replica.proposer.election_state.cur_req_set ensures replica'.proposer.election_state.prev_req_set == replica.proposer.election_state.prev_req_set ensures replicaChanged ==> replica'.executor.reply_cache == replica.executor.reply_cache ensures !replicaChanged ==> replica' == replica { var empty_Mutable_Map:MutableMap := MutableMap.EmptyMap(); var start_time := Time.GetDebugTimeTicks(); // lemma_AbstractifyEndPointsToNodeIdentities_properties(replica.executor.constants.all.config.replica_ids); if (&& inp.src in replica.executor.constants.all.config.replica_ids && inp.msg.opn_state_supply.n > replica.executor.ops_complete.n) { replica', packets_sent := ReplicaNextProcessAppStateSupplyActual(replica, inp); var end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("Replica_Next_Process_AppStateSupply_work", start_time, end_time); replicaChanged := true; } else { replica', packets_sent := ReplicaNextProcessAppStateSupplyIgnore(replica, inp); var end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("Replica_Next_Process_AppStateSupply_nada", start_time, end_time); replicaChanged := false; } //lemma_AbstractifySetOfCPacketsToSetOfRslPackets_properties(packets_sent); } method ReplicaNextSpontaneousMaybeExecuteIgnore(replica:ReplicaState) returns (replica':ReplicaState, packets_sent:OutboundPackets) requires Replica_Next_Spontaneous_MaybeExecute_Preconditions(replica); requires || !replica.executor.next_op_to_execute.COutstandingOpKnown? || replica.executor.ops_complete.n >= replica.executor.constants.all.params.max_integer_val ensures Replica_Next_Spontaneous_MaybeExecute_Postconditions(old(AbstractifyReplicaStateToLReplica(replica)), replica', packets_sent); ensures replica' == replica; { replica' := replica; packets_sent := OutboundPacket(None); } method ReplicaNextSpontaneousMaybeExecuteActual( replica:ReplicaState, cur_req_set:MutableSet, prev_req_set:MutableSet, reply_cache_mutable:MutableMap ) returns ( replica':ReplicaState, packets_sent:OutboundPackets ) requires Replica_Next_Spontaneous_MaybeExecute_Preconditions(replica) requires cur_req_set != prev_req_set requires MutableSet.SetOf(cur_req_set) == replica.proposer.election_state.cur_req_set requires MutableSet.SetOf(prev_req_set) == replica.proposer.election_state.prev_req_set requires replica.executor.reply_cache == MutableMap.MapOf(reply_cache_mutable) requires replica.executor.next_op_to_execute.COutstandingOpKnown? requires replica.executor.ops_complete.n < replica.executor.constants.all.params.max_integer_val modifies replica.executor.app modifies cur_req_set, prev_req_set, reply_cache_mutable ensures Replica_Next_Spontaneous_MaybeExecute_Postconditions(old(AbstractifyReplicaStateToLReplica(replica)), replica', packets_sent) ensures MutableSet.SetOf(cur_req_set) == replica'.proposer.election_state.cur_req_set ensures MutableSet.SetOf(prev_req_set) == replica'.proposer.election_state.prev_req_set ensures replica'.executor.reply_cache == MutableMap.MapOf(reply_cache_mutable) { ghost var s := AbstractifyReplicaStateToLReplica(replica); var val := replica.executor.next_op_to_execute.v; var newLearner := LearnerModel_ForgetDecision(replica.learner, replica.executor.ops_complete); assert LLearnerForgetDecision(AbstractifyLearnerStateToLLearner(replica.learner), AbstractifyLearnerStateToLLearner(newLearner), AbstractifyCOperationNumberToOperationNumber(replica.executor.ops_complete)); var oldExecutor := AbstractifyExecutorStateToLExecutor(replica.executor); var newExecutor, packets := ExecutorExecute(replica.executor, reply_cache_mutable); assert LExecutorExecute(oldExecutor, AbstractifyExecutorStateToLExecutor(newExecutor), AbstractifyOutboundCPacketsToSeqOfRslPackets(packets)); var oldProposer := AbstractifyProposerStateToLProposer(replica.proposer); var newProposer := ProposerResetViewTimerDueToExecution(replica.proposer, val, cur_req_set, prev_req_set); assert LProposerResetViewTimerDueToExecution(oldProposer, AbstractifyProposerStateToLProposer(newProposer), AbstractifyCRequestBatchToRequestBatch(val)); assert MutableSet.SetOf(cur_req_set) == newProposer.election_state.cur_req_set; assert MutableSet.SetOf(prev_req_set) == newProposer.election_state.prev_req_set; replica' := replica.(proposer := newProposer, learner := newLearner, executor := newExecutor); packets_sent := packets; ghost var s' := AbstractifyReplicaStateToLReplica(replica'); ghost var sent_packets := AbstractifyOutboundCPacketsToSeqOfRslPackets(packets_sent); assert LProposerResetViewTimerDueToExecution(s.proposer, s'.proposer, AbstractifyCRequestBatchToRequestBatch(val)); assert LLearnerForgetDecision(s.learner, s'.learner, AbstractifyCOperationNumberToOperationNumber(replica.executor.ops_complete)); assert LExecutorExecute(s.executor, s'.executor, sent_packets); assert LReplicaNextSpontaneousMaybeExecute(s, s', sent_packets); } method Replica_Next_Spontaneous_MaybeExecute( replica:ReplicaState, cur_req_set:MutableSet, prev_req_set:MutableSet, reply_cache_mutable:MutableMap ) returns ( replica':ReplicaState, packets_sent:OutboundPackets ) requires Replica_Next_Spontaneous_MaybeExecute_Preconditions(replica) requires cur_req_set != prev_req_set requires MutableSet.SetOf(cur_req_set) == replica.proposer.election_state.cur_req_set requires MutableSet.SetOf(prev_req_set) == replica.proposer.election_state.prev_req_set requires replica.executor.reply_cache == MutableMap.MapOf(reply_cache_mutable) modifies replica.executor.app modifies cur_req_set, prev_req_set, reply_cache_mutable ensures Replica_Next_Spontaneous_MaybeExecute_Postconditions(old(AbstractifyReplicaStateToLReplica(replica)), replica', packets_sent) ensures MutableSet.SetOf(cur_req_set) == replica'.proposer.election_state.cur_req_set ensures MutableSet.SetOf(prev_req_set) == replica'.proposer.election_state.prev_req_set ensures replica'.executor.reply_cache == MutableMap.MapOf(reply_cache_mutable) { //var start_time := Time.GetDebugTimeTicks(); if (&& replica.executor.next_op_to_execute.COutstandingOpKnown? && replica.executor.ops_complete.n < replica.executor.constants.all.params.max_integer_val) { replica', packets_sent := ReplicaNextSpontaneousMaybeExecuteActual(replica, cur_req_set, prev_req_set, reply_cache_mutable); //var end_time := Time.GetDebugTimeTicks(); // RecordTimingSeq("Replica_Next_Spontaneous_MaybeExecute_work", start_time, end_time); // RecordTimingSeq("Replica_Next_Spontaneous_MaybeExecute_work_proposer", start_time, end_time_proposer); // RecordTimingSeq("Replica_Next_Spontaneous_MaybeExecute_work_learner", start_time_learner, end_time_learner); // RecordTimingSeq("Replica_Next_Spontaneous_MaybeExecute_work_execute", start_time_executor, end_time_executor); } else { replica', packets_sent := ReplicaNextSpontaneousMaybeExecuteIgnore(replica); //var end_time := Time.GetDebugTimeTicks(); // RecordTimingSeq("Replica_Next_Spontaneous_MaybeExecute_nada", start_time, end_time); } //lemma_AbstractifyCPacketToRslPacket_src(packets_sent, replica.constants.all.config.replica_ids[replica.constants.my_index]); } method ReplicaNextReadClockMaybeSendHeartbeatSkip( replica:ReplicaState, clock:CClockReading ) returns ( replica':ReplicaState, packets_sent:OutboundPackets ) requires Replica_Next_ReadClock_MaybeSendHeartbeat_Preconditions(replica) requires clock.t < replica.nextHeartbeatTime ensures Replica_Next_ReadClock_MaybeSendHeartbeat_Postconditions(old(AbstractifyReplicaStateToLReplica(replica)), replica', clock, packets_sent) ensures replica'.proposer.election_state.cur_req_set == replica.proposer.election_state.cur_req_set ensures replica'.proposer.election_state.prev_req_set == replica.proposer.election_state.prev_req_set ensures replica'.executor.reply_cache == replica.executor.reply_cache { replica' := replica; packets_sent := Broadcast(CBroadcastNop); //lemma_AbstractifySetOfCPacketsToSetOfRslPackets_properties(packets_sent); } method ReplicaNextReadClockMaybeSendHeartbeatActual( replica:ReplicaState, clock:CClockReading ) returns ( replica':ReplicaState, packets_sent:OutboundPackets ) requires Replica_Next_ReadClock_MaybeSendHeartbeat_Preconditions(replica) requires clock.t >= replica.nextHeartbeatTime ensures Replica_Next_ReadClock_MaybeSendHeartbeat_Postconditions(old(AbstractifyReplicaStateToLReplica(replica)), replica', clock, packets_sent) ensures replica'.proposer.election_state.cur_req_set == replica.proposer.election_state.cur_req_set ensures replica'.proposer.election_state.prev_req_set == replica.proposer.election_state.prev_req_set ensures replica'.executor.reply_cache == replica.executor.reply_cache { var heartbeat := UpperBoundedAdditionImpl(clock.t, replica.constants.all.params.heartbeat_period, replica.constants.all.params.max_integer_val); replica' := replica.(nextHeartbeatTime := heartbeat); var flag := (replica.constants.my_index in replica.proposer.election_state.current_view_suspectors); var msg := CMessage_Heartbeat(replica.proposer.election_state.current_view, flag, replica.executor.ops_complete); var packets := BuildBroadcastToEveryone(replica.constants.all.config, replica.constants.my_index, msg); lemma_AbstractifySeqOfUint64sToSetOfInts_properties(replica.proposer.election_state.current_view_suspectors); packets_sent := Broadcast(packets); //lemma_AbstractifySetOfCPacketsToSetOfRslPackets_properties(packets_sent); } method Replica_Next_ReadClock_MaybeSendHeartbeat( replica:ReplicaState, clock:CClockReading ) returns ( replica':ReplicaState, packets_sent:OutboundPackets ) requires Replica_Next_ReadClock_MaybeSendHeartbeat_Preconditions(replica) ensures Replica_Next_ReadClock_MaybeSendHeartbeat_Postconditions(old(AbstractifyReplicaStateToLReplica(replica)), replica', clock, packets_sent) ensures replica'.proposer.election_state.cur_req_set == replica.proposer.election_state.cur_req_set ensures replica'.proposer.election_state.prev_req_set == replica.proposer.election_state.prev_req_set ensures replica'.executor.reply_cache == replica.executor.reply_cache { var start_time := Time.GetDebugTimeTicks(); if (clock.t >= replica.nextHeartbeatTime) { replica', packets_sent := ReplicaNextReadClockMaybeSendHeartbeatActual(replica, clock); var end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("Replica_Next_ReadClock_MaybeSendHeartbeat_work", start_time, end_time); } else { replica', packets_sent := ReplicaNextReadClockMaybeSendHeartbeatSkip(replica, clock); var end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("Replica_Next_ReadClock_MaybeSendHeartbeat_nada", start_time, end_time); } //lemma_AbstractifyCPacketToRslPacket_src(packets_sent, replica.constants.all.config.replica_ids[replica.constants.my_index]); } method ReplicaNextSpontaneousMaybeMakeDecisionSkip(replica:ReplicaState) returns (replica':ReplicaState, packets_sent:OutboundPackets) requires Replica_Next_Spontaneous_MaybeMakeDecision_Preconditions(replica) requires var opn := replica.executor.ops_complete; || !replica.executor.next_op_to_execute.COutstandingOpUnknown? || opn !in replica.learner.unexecuted_ops || |replica.learner.unexecuted_ops[opn].received_2b_message_senders| < LMinQuorumSize(AbstractifyCPaxosConfigurationToConfiguration(replica.learner.rcs.all.config)) ensures Replica_Next_Spontaneous_MaybeMakeDecision_Postconditions(old(AbstractifyReplicaStateToLReplica(replica)), replica', packets_sent) ensures replica' == replica { replica' := replica; packets_sent := Broadcast(CBroadcastNop); lemma_AbstractifyCOperationNumberToOperationNumber_isInjective(); lemma_AbstractifyCLearnerTuplesToLearnerTuples_properties(replica.learner.unexecuted_ops); ghost var s := AbstractifyReplicaStateToLReplica(replica); ghost var opn := replica.executor.ops_complete; if replica.executor.next_op_to_execute.COutstandingOpUnknown? && opn in replica.learner.unexecuted_ops { assert AbstractifyCOperationNumberToOperationNumber(opn) in s.learner.unexecuted_learner_state; calc { |s.learner.unexecuted_learner_state[AbstractifyCOperationNumberToOperationNumber(opn)].received_2b_message_senders|; { lemma_Received2bPacketsSameSizeAsAbstraction(replica.learner.unexecuted_ops[opn], AbstractifyCLearnerTupleToLearnerTuple(replica.learner.unexecuted_ops[opn])); } |replica.learner.unexecuted_ops[opn].received_2b_message_senders|; < LMinQuorumSize(AbstractifyCPaxosConfigurationToConfiguration(replica.learner.rcs.all.config)); LMinQuorumSize(s.learner.constants.all.config); } } } method ReplicaNextSpontaneousMaybeMakeDecisionActual(replica:ReplicaState) returns (replica':ReplicaState, packets_sent:OutboundPackets) requires Replica_Next_Spontaneous_MaybeMakeDecision_Preconditions(replica) requires replica.executor.next_op_to_execute.COutstandingOpUnknown? requires replica.executor.ops_complete in replica.learner.unexecuted_ops requires |replica.learner.unexecuted_ops[replica.executor.ops_complete].received_2b_message_senders| >= LMinQuorumSize(AbstractifyCPaxosConfigurationToConfiguration(replica.learner.rcs.all.config)) ensures Replica_Next_Spontaneous_MaybeMakeDecision_Postconditions(old(AbstractifyReplicaStateToLReplica(replica)), replica', packets_sent) ensures replica'.proposer.election_state.cur_req_set == replica.proposer.election_state.cur_req_set ensures replica'.proposer.election_state.prev_req_set == replica.proposer.election_state.prev_req_set ensures replica'.executor.reply_cache == replica.executor.reply_cache { lemma_AbstractifyCOperationNumberToOperationNumber_isInjective(); lemma_AbstractifyCRequestToRequest_isInjective(); lemma_AbstractifyCLearnerTuplesToLearnerTuples_properties(replica.learner.unexecuted_ops); var opn := replica.executor.ops_complete; lemma_Received2bPacketsSameSizeAsAbstraction(replica.learner.unexecuted_ops[opn], AbstractifyCLearnerTupleToLearnerTuple(replica.learner.unexecuted_ops[opn])); var candValue:CRequestBatch := replica.learner.unexecuted_ops[opn].candidate_learned_value; assert CLearnerTupleIsValid(replica.learner.unexecuted_ops[opn]); assert ValidRequestBatch(replica.learner.unexecuted_ops[opn].candidate_learned_value); var newExecutor := ExecutorGetDecision(replica.executor, replica.learner.max_ballot_seen, opn, candValue); replica' := replica.(executor := newExecutor); packets_sent := Broadcast(CBroadcastNop); lemma_AbstractifyCRequestToRequest_isInjective(); ghost var s := AbstractifyReplicaStateToLReplica(replica); ghost var s' := AbstractifyReplicaStateToLReplica(replica'); ghost var sent_packets := AbstractifyOutboundCPacketsToSeqOfRslPackets(packets_sent); assert LExecutorGetDecision(s.executor, s'.executor, AbstractifyCBallotToBallot(replica.learner.max_ballot_seen), AbstractifyCOperationNumberToOperationNumber(opn), AbstractifyCRequestBatchToRequestBatch(candValue)); assert LReplicaNextSpontaneousMaybeMakeDecision(s, s', sent_packets); } method Replica_Next_Spontaneous_MaybeMakeDecision(replica:ReplicaState) returns (replica':ReplicaState, packets_sent:OutboundPackets) requires Replica_Next_Spontaneous_MaybeMakeDecision_Preconditions(replica) ensures Replica_Next_Spontaneous_MaybeMakeDecision_Postconditions(old(AbstractifyReplicaStateToLReplica(replica)), replica', packets_sent) ensures replica'.proposer.election_state.cur_req_set == replica.proposer.election_state.cur_req_set ensures replica'.proposer.election_state.prev_req_set == replica.proposer.election_state.prev_req_set ensures replica'.executor.reply_cache == replica.executor.reply_cache { var start_time := Time.GetDebugTimeTicks(); var opn := replica.executor.ops_complete; var minCQS := MinCQuorumSize(replica.learner.rcs.all.config); if (&& replica.executor.next_op_to_execute.COutstandingOpUnknown? && opn in replica.learner.unexecuted_ops && (|replica.learner.unexecuted_ops[opn].received_2b_message_senders|) >= minCQS as int) { replica', packets_sent := ReplicaNextSpontaneousMaybeMakeDecisionActual(replica); var end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("Replica_Next_Spontaneous_MaybeMakeDecision_work", start_time, end_time); } else { replica', packets_sent := ReplicaNextSpontaneousMaybeMakeDecisionSkip(replica); var end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("Replica_Next_Spontaneous_MaybeMakeDecision_nada", start_time, end_time); } } method ReplicaNextSpontaneousTruncateLogBasedOnCheckpointsSkip( replica:ReplicaState, newLogTruncationPoint:COperationNumber ) returns ( replica':ReplicaState, packets_sent:OutboundPackets ) requires Replica_Next_Spontaneous_TruncateLogBasedOnCheckpoints_Preconditions(replica) requires IsLogTruncationPointValid(AbstractifyCOperationNumberToOperationNumber(newLogTruncationPoint), AbstractifyReplicaStateToLReplica(replica).acceptor.last_checkpointed_operation, AbstractifyReplicaStateToLReplica(replica).acceptor.constants.all.config) requires newLogTruncationPoint.n <= replica.acceptor.log_truncation_point.n ensures Replica_Next_Spontaneous_TruncateLogBasedOnCheckpoints_Postconditions(old(AbstractifyReplicaStateToLReplica(replica)), replica', packets_sent) ensures replica' == replica { replica' := replica; packets_sent := Broadcast(CBroadcastNop); } method ReplicaNextSpontaneousTruncateLogBasedOnCheckpointsActual( replica:ReplicaState, newLogTruncationPoint:COperationNumber ) returns ( replica':ReplicaState, packets_sent:OutboundPackets ) requires Replica_Next_Spontaneous_TruncateLogBasedOnCheckpoints_Preconditions(replica) requires IsLogTruncationPointValid(AbstractifyCOperationNumberToOperationNumber(newLogTruncationPoint), AbstractifyReplicaStateToLReplica(replica).acceptor.last_checkpointed_operation, AbstractifyReplicaStateToLReplica(replica).acceptor.constants.all.config) requires newLogTruncationPoint.n > replica.acceptor.log_truncation_point.n ensures Replica_Next_Spontaneous_TruncateLogBasedOnCheckpoints_Postconditions(old(AbstractifyReplicaStateToLReplica(replica)), replica', packets_sent) ensures replica'.proposer.election_state.cur_req_set == replica.proposer.election_state.cur_req_set ensures replica'.proposer.election_state.prev_req_set == replica.proposer.election_state.prev_req_set ensures replica'.executor.reply_cache == replica.executor.reply_cache { assert AbstractifyCOperationNumberToOperationNumber(newLogTruncationPoint) > AbstractifyAcceptorStateToAcceptor(replica.acceptor).log_truncation_point; var newAcceptor := NextAcceptorState_TruncateLog(replica.acceptor, newLogTruncationPoint); replica' := replica.(acceptor := newAcceptor); packets_sent := Broadcast(CBroadcastNop); //lemma_AbstractifySetOfCPacketsToSetOfRslPackets_properties(packets_sent); } method Replica_Next_Spontaneous_TruncateLogBasedOnCheckpoints(replica:ReplicaState) returns (replica':ReplicaState, packets_sent:OutboundPackets) requires Replica_Next_Spontaneous_TruncateLogBasedOnCheckpoints_Preconditions(replica) ensures Replica_Next_Spontaneous_TruncateLogBasedOnCheckpoints_Postconditions(old(AbstractifyReplicaStateToLReplica(replica)), replica', packets_sent) ensures replica'.proposer.election_state.cur_req_set == replica.proposer.election_state.cur_req_set ensures replica'.proposer.election_state.prev_req_set == replica.proposer.election_state.prev_req_set ensures replica'.executor.reply_cache == replica.executor.reply_cache { var start_time := Time.GetDebugTimeTicks(); var minCQS := MinCQuorumSize(replica.acceptor.constants.all.config); var newLogTruncationPoint := AcceptorModel_GetNthHighestValueAmongReportedCheckpoints(replica.acceptor, minCQS); if newLogTruncationPoint.n > replica.acceptor.log_truncation_point.n { replica', packets_sent := ReplicaNextSpontaneousTruncateLogBasedOnCheckpointsActual(replica, newLogTruncationPoint); var end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("Replica_Next_Spontaneous_TruncateLogBasedOnCheckpoints_work", start_time, end_time); } else { replica', packets_sent := ReplicaNextSpontaneousTruncateLogBasedOnCheckpointsSkip(replica, newLogTruncationPoint); var end_time := Time.GetDebugTimeTicks(); RecordTimingSeq("Replica_Next_Spontaneous_TruncateLogBasedOnCheckpoints_nada", start_time, end_time); } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/RSL/ReplicaModel.i.dfy ================================================ include "ReplicaModel-Part1.i.dfy" include "ReplicaModel-Part2.i.dfy" include "ReplicaModel-Part3.i.dfy" include "ReplicaModel-Part4.i.dfy" include "ReplicaModel-Part5.i.dfy" module LiveRSL__ReplicaModel_i { import opened LiveRSL__ReplicaModel_Part1_i import opened LiveRSL__ReplicaModel_Part2_i import opened LiveRSL__ReplicaModel_Part3_i import opened LiveRSL__ReplicaModel_Part4_i import opened LiveRSL__ReplicaModel_Part5_i } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/RSL/ReplicaState.i.dfy ================================================ include "../../Protocol/RSL/Replica.i.dfy" include "ReplicaConstantsState.i.dfy" include "ProposerState.i.dfy" include "AcceptorState.i.dfy" include "LearnerState.i.dfy" include "ExecutorState.i.dfy" include "CClockReading.i.dfy" module LiveRSL__ReplicaState_i { import opened Native__Io_s import opened Native__NativeTypes_s import opened LiveRSL__AcceptorState_i import opened LiveRSL__AppInterface_i import opened LiveRSL__CClockReading_i import opened LiveRSL__CMessage_i import opened LiveRSL__CMessageRefinements_i import opened LiveRSL__CPaxosConfiguration_i import opened LiveRSL__CTypes_i import opened LiveRSL__ExecutorState_i import opened LiveRSL__LearnerState_i import opened LiveRSL__PacketParsing_i import opened LiveRSL__ProposerState_i import opened LiveRSL__Replica_i import opened LiveRSL__ReplicaConstantsState_i datatype ReplicaState = ReplicaState( constants:ReplicaConstantsState, nextHeartbeatTime:uint64, proposer:ProposerState, acceptor:AcceptorState, learner:CLearnerState, executor:ExecutorState ) predicate ReplicaStateIsAbstractable(replica:ReplicaState) { && ReplicaConstantsStateIsAbstractable(replica.constants) && ProposerIsAbstractable(replica.proposer) && AcceptorIsAbstractable(replica.acceptor) && LearnerState_IsAbstractable(replica.learner) && ExecutorState_IsAbstractable(replica.executor) } function AbstractifyReplicaStateToLReplica(replica:ReplicaState) : (lreplica:LReplica) reads replica.executor.app requires ReplicaStateIsAbstractable(replica) ensures lreplica.constants == AbstractifyReplicaConstantsStateToLReplicaConstants(replica.constants) { LReplica( AbstractifyReplicaConstantsStateToLReplicaConstants(replica.constants), replica.nextHeartbeatTime as int, AbstractifyProposerStateToLProposer(replica.proposer), AbstractifyAcceptorStateToAcceptor(replica.acceptor), AbstractifyLearnerStateToLLearner(replica.learner), AbstractifyExecutorStateToLExecutor(replica.executor)) } ////////////////////////////////////////////////////////////////////////////// predicate ReplicaCommonPreconditions(replica:ReplicaState) { ReplicaStateIsValid(replica) } predicate ReplicaReceivePreconditions(replica:ReplicaState, cpacket:CPacket) { && ReplicaCommonPreconditions(replica) && CPacketIsSendable(cpacket) && PaxosEndPointIsValid(cpacket.src, replica.constants.all.config) } predicate ReplicaCommonPostconditions(replica:LReplica, replica':ReplicaState, sent_packets:OutboundPackets) { && ReplicaConstantsState_IsValid(replica'.constants) && AbstractifyReplicaConstantsStateToLReplicaConstants(replica'.constants) == replica.constants && ReplicaStateIsAbstractable(replica') && OutboundPacketsIsValid(sent_packets) && OutboundPacketsIsAbstractable(sent_packets) && ReplicaStateIsValid(replica') && OutboundPacketsHasCorrectSrc(sent_packets, replica'.constants.all.config.replica_ids[replica'.constants.my_index]) } // ////////////////////////////////////////////////////////////////////////////// predicate ReplicaStateIsValid(replica:ReplicaState) { && ProposerIsValid(replica.proposer) && AcceptorIsValid(replica.acceptor) && LearnerState_IsValid(replica.learner) && ExecutorState_IsValid(replica.executor) && ReplicaStateIsAbstractable(replica) && ReplicaConstantsState_IsValid(replica.constants) && replica.constants == replica.proposer.constants && replica.constants == replica.acceptor.constants && replica.constants == replica.learner.rcs && replica.constants == replica.executor.constants } predicate ConstantsStayConstant_Replica(replica:LReplica, replica':ReplicaState) requires ReplicaConstantsStateIsAbstractable(replica'.constants) { && AbstractifyReplicaConstantsStateToLReplicaConstants(replica'.constants) == replica.constants && replica.constants == replica.proposer.constants && replica.constants == replica.acceptor.constants && replica.constants == replica.learner.constants && replica.constants == replica.executor.constants && replica'.constants == replica'.proposer.constants && replica'.constants == replica'.acceptor.constants && replica'.constants == replica'.learner.rcs && replica'.constants == replica'.executor.constants } predicate Replica_Common_Preconditions(replica:ReplicaState, inp:CPacket) { && ReplicaStateIsValid(replica) && CPacketIsSendable(inp) && PaxosEndPointIsValid(inp.src, replica.constants.all.config) } predicate Replica_Common_Postconditions(replica:LReplica, replica':ReplicaState, inp:CPacket, packets_sent:OutboundPackets) { && ReplicaConstantsState_IsValid(replica'.constants) && CPacketIsSendable(inp) && PaxosEndPointIsValid(inp.src, replica'.constants.all.config) && ReplicaStateIsAbstractable(replica') && ConstantsStayConstant_Replica(replica, replica') && ReplicaStateIsValid(replica') && OutboundPacketsIsValid(packets_sent) && OutboundPacketsHasCorrectSrc(packets_sent, replica'.constants.all.config.replica_ids[replica'.constants.my_index]) && OutboundPacketsIsAbstractable(packets_sent) } predicate Replica_Common_Postconditions_NoPacket(replica:LReplica, replica':ReplicaState, packets_sent:OutboundPackets) { && ReplicaConstantsState_IsValid(replica'.constants) && ReplicaStateIsAbstractable(replica') && ConstantsStayConstant_Replica(replica, replica') && ReplicaStateIsValid(replica') && OutboundPacketsIsValid(packets_sent) && OutboundPacketsHasCorrectSrc(packets_sent, replica'.constants.all.config.replica_ids[replica'.constants.my_index]) && OutboundPacketsIsAbstractable(packets_sent) } predicate Replica_Next_Process_Request_Preconditions(replica:ReplicaState, inp:CPacket) { && Replica_Common_Preconditions(replica, inp) && ProposerIsValid(replica.proposer) && CPacketIsAbstractable(inp) && inp.msg.CMessage_Request? } predicate Replica_Next_Process_Request_Postconditions(replica:LReplica, replica':ReplicaState, inp:CPacket, packets_sent:OutboundPackets) reads replica'.executor.app { && CPacketIsAbstractable(inp) && inp.msg.CMessage_Request? && Replica_Common_Postconditions(replica, replica', inp, packets_sent) && LReplicaNextProcessRequest( replica, AbstractifyReplicaStateToLReplica(replica'), AbstractifyCPacketToRslPacket(inp), AbstractifyOutboundCPacketsToSeqOfRslPackets(packets_sent)) } predicate Replica_Next_Process_1a_Preconditions(replica:ReplicaState, inp:CPacket) { && Replica_Common_Preconditions(replica, inp) && NextAcceptorState_Phase1Preconditions(replica.acceptor, inp.msg, inp.src) } predicate Replica_Next_Process_1a_Postconditions(replica:LReplica, replica':ReplicaState, inp:CPacket, packets_sent:OutboundPackets) reads replica'.executor.app { && CPacketIsAbstractable(inp) && inp.msg.CMessage_1a? && Replica_Common_Postconditions(replica, replica', inp, packets_sent) && LReplicaNextProcess1a( replica, AbstractifyReplicaStateToLReplica(replica'), AbstractifyCPacketToRslPacket(inp), AbstractifyOutboundCPacketsToSeqOfRslPackets(packets_sent)) } predicate Replica_Next_Process_1b_Preconditions(replica:ReplicaState, inp:CPacket) { && Replica_Common_Preconditions(replica, inp) && ProposerIsValid(replica.proposer) && CPacketIsAbstractable(inp) // && replica.proposer.current_state == 1 // && ConvertUint64ToEndPoint(inp.src) in replica.proposer.constants.all.config.replica_ids && inp.msg.CMessage_1b? // && inp.msg.bal_1b == replica.proposer.max_ballot_i_sent_1a } predicate Replica_Next_Process_1b_Postconditions(replica:LReplica, replica':ReplicaState, inp:CPacket, packets_sent:OutboundPackets) reads replica'.executor.app { && CPacketIsAbstractable(inp) && inp.msg.CMessage_1b? && Replica_Common_Postconditions(replica, replica', inp, packets_sent) && LReplicaNextProcess1b( replica, AbstractifyReplicaStateToLReplica(replica'), AbstractifyCPacketToRslPacket(inp), AbstractifyOutboundCPacketsToSeqOfRslPackets(packets_sent)) } predicate Replica_Next_Process_StartingPhase2_Preconditions(replica:ReplicaState, inp:CPacket) { && Replica_Common_Preconditions(replica, inp) && CPacketIsAbstractable(inp) && inp.msg.CMessage_StartingPhase2? } predicate Replica_Next_Process_StartingPhase2_Postconditions(replica:LReplica, replica':ReplicaState, inp:CPacket, packets_sent:OutboundPackets) reads replica'.executor.app { && CPacketIsAbstractable(inp) && inp.msg.CMessage_StartingPhase2? && Replica_Common_Postconditions(replica, replica', inp, packets_sent) && LReplicaNextProcessStartingPhase2( replica, AbstractifyReplicaStateToLReplica(replica'), AbstractifyCPacketToRslPacket(inp), AbstractifyOutboundCPacketsToSeqOfRslPackets(packets_sent)) } predicate Replica_Next_Process_2a_Preconditions(replica:ReplicaState, inp:CPacket) { && Replica_Common_Preconditions(replica, inp) && NextAcceptorState_Phase2Preconditions_AlwaysEnabled(replica.acceptor, inp.msg, inp.src) } predicate Replica_Next_Process_2a_Postconditions(replica:LReplica, replica':ReplicaState, inp:CPacket, packets_sent:OutboundPackets) reads replica'.executor.app { && CPacketIsAbstractable(inp) && inp.msg.CMessage_2a? && Replica_Common_Postconditions(replica, replica', inp, packets_sent) && LReplicaNextProcess2a( replica, AbstractifyReplicaStateToLReplica(replica'), AbstractifyCPacketToRslPacket(inp), AbstractifyOutboundCPacketsToSeqOfRslPackets(packets_sent)) } predicate Replica_Next_Process_2b_Preconditions(replica:ReplicaState, inp:CPacket) { && Replica_Common_Preconditions(replica, inp) && LearnerState_Process2b__Preconditions(replica.learner, replica.executor, inp) } predicate Replica_Next_Process_2b_Postconditions(replica:LReplica, replica':ReplicaState, inp:CPacket, packets_sent:OutboundPackets) reads replica'.executor.app { && CPacketIsAbstractable(inp) && inp.msg.CMessage_2b? && Replica_Common_Postconditions(replica, replica', inp, packets_sent) && LReplicaNextProcess2b( replica, AbstractifyReplicaStateToLReplica(replica'), AbstractifyCPacketToRslPacket(inp), AbstractifyOutboundCPacketsToSeqOfRslPackets(packets_sent)) } predicate Replica_Next_MaybeEnterNewViewAndSend1a_Preconditions(replica:ReplicaState) { ReplicaStateIsValid(replica) } predicate Replica_Next_MaybeEnterNewViewAndSend1a_Postconditions(replica:LReplica, replica':ReplicaState, packets_sent:OutboundPackets) reads replica'.executor.app { && Replica_Common_Postconditions_NoPacket(replica, replica', packets_sent) && LReplicaNextSpontaneousMaybeEnterNewViewAndSend1a( replica, AbstractifyReplicaStateToLReplica(replica'), AbstractifyOutboundCPacketsToSeqOfRslPackets(packets_sent)) } predicate Replica_Next_MaybeEnterPhase2_Preconditions(replica:ReplicaState) { ReplicaStateIsValid(replica) } predicate Replica_Next_MaybeEnterPhase2_Postconditions(replica:LReplica, replica':ReplicaState, packets_sent:OutboundPackets) reads replica'.executor.app { && Replica_Common_Postconditions_NoPacket(replica, replica', packets_sent) && LReplicaNextSpontaneousMaybeEnterPhase2( replica, AbstractifyReplicaStateToLReplica(replica'), AbstractifyOutboundCPacketsToSeqOfRslPackets(packets_sent)) } predicate Replica_Next_ReadClock_MaybeNominateValueAndSend2a_Preconditions(replica:ReplicaState) { ReplicaStateIsValid(replica) } predicate Replica_Next_ReadClock_MaybeNominateValueAndSend2a_Postconditions( replica:LReplica, replica':ReplicaState, clock:CClockReading, packets_sent:OutboundPackets ) reads replica'.executor.app { && Replica_Common_Postconditions_NoPacket(replica, replica', packets_sent) && LReplicaNextReadClockMaybeNominateValueAndSend2a( replica, AbstractifyReplicaStateToLReplica(replica'), AbstractifyCClockReadingToClockReading(clock), AbstractifyOutboundCPacketsToSeqOfRslPackets(packets_sent)) } predicate Replica_Next_Process_AppStateRequest_Preconditions(replica:ReplicaState, inp:CPacket) { && Replica_Common_Preconditions(replica, inp) && CPacketIsAbstractable(inp) && inp.msg.CMessage_AppStateRequest? } predicate Replica_Next_Process_AppStateRequest_Postconditions(replica:LReplica, replica':ReplicaState, inp:CPacket, packets_sent:OutboundPackets) reads replica'.executor.app { && CPacketIsAbstractable(inp) && inp.msg.CMessage_AppStateRequest? && Replica_Common_Postconditions(replica, replica', inp, packets_sent) && LReplicaNextProcessAppStateRequest( replica, AbstractifyReplicaStateToLReplica(replica'), AbstractifyCPacketToRslPacket(inp), AbstractifyOutboundCPacketsToSeqOfRslPackets(packets_sent)) } predicate Replica_Next_Process_Heartbeat_Preconditions(replica:ReplicaState, inp:CPacket) { && Replica_Common_Preconditions(replica, inp) && NextAcceptorState_ProcessHeartbeatPreconditions(replica.acceptor, inp.msg, inp.src) && CPacketIsAbstractable(inp) && inp.msg.CMessage_Heartbeat? } predicate Replica_Next_Process_Heartbeat_Postconditions(replica:LReplica, replica':ReplicaState, inp:CPacket, clock:uint64, packets_sent:OutboundPackets) reads replica'.executor.app { && CPacketIsAbstractable(inp) && inp.msg.CMessage_Heartbeat? && Replica_Common_Postconditions(replica, replica', inp, packets_sent) && LReplicaNextProcessHeartbeat( replica, AbstractifyReplicaStateToLReplica(replica'), AbstractifyCPacketToRslPacket(inp), clock as int, AbstractifyOutboundCPacketsToSeqOfRslPackets(packets_sent)) } predicate Replica_Next_ReadClock_CheckForViewTimeout_Preconditions(replica:ReplicaState) { ReplicaStateIsValid(replica) } predicate Replica_Next_ReadClock_CheckForViewTimeout_Postconditions( replica:LReplica, replica':ReplicaState, clock:CClockReading, packets_sent:OutboundPackets ) reads replica'.executor.app { && Replica_Common_Postconditions_NoPacket(replica, replica', packets_sent) && LReplicaNextReadClockCheckForViewTimeout( replica, AbstractifyReplicaStateToLReplica(replica'), AbstractifyCClockReadingToClockReading(clock), AbstractifyOutboundCPacketsToSeqOfRslPackets(packets_sent)) } predicate Replica_Next_ReadClock_CheckForQuorumOfViewSuspicions_Preconditions(replica:ReplicaState) { ReplicaStateIsValid(replica) } predicate Replica_Next_ReadClock_CheckForQuorumOfViewSuspicions_Postconditions( replica:LReplica, replica':ReplicaState, clock:CClockReading, packets_sent:OutboundPackets ) reads replica'.executor.app { && Replica_Common_Postconditions_NoPacket(replica, replica', packets_sent) && LReplicaNextReadClockCheckForQuorumOfViewSuspicions( replica, AbstractifyReplicaStateToLReplica(replica'), AbstractifyCClockReadingToClockReading(clock), AbstractifyOutboundCPacketsToSeqOfRslPackets(packets_sent)) } predicate Replica_Next_Process_AppStateSupply_Preconditions(replica:ReplicaState, inp:CPacket) { && Replica_Common_Preconditions(replica, inp) && inp.msg.CMessage_AppStateSupply? && LearnerState_ForgetOperationsBefore__Preconditions(replica.learner, inp.msg.opn_state_supply) } predicate Replica_Next_Process_AppStateSupply_Postconditions(replica:LReplica, replica':ReplicaState, inp:CPacket, packets_sent:OutboundPackets) reads replica'.executor.app { && CPacketIsAbstractable(inp) && inp.msg.CMessage_AppStateSupply? && Replica_Common_Postconditions(replica, replica', inp, packets_sent) && LReplicaNextProcessAppStateSupply( replica, AbstractifyReplicaStateToLReplica(replica'), AbstractifyCPacketToRslPacket(inp), AbstractifyOutboundCPacketsToSeqOfRslPackets(packets_sent)) } predicate Replica_Next_Spontaneous_MaybeExecute_Preconditions(replica:ReplicaState) { ReplicaStateIsValid(replica) } predicate Replica_Next_Spontaneous_MaybeExecute_Postconditions(replica:LReplica, replica':ReplicaState, packets_sent:OutboundPackets) reads replica'.executor.app { && Replica_Common_Postconditions_NoPacket(replica, replica', packets_sent) && LReplicaNextSpontaneousMaybeExecute( replica, AbstractifyReplicaStateToLReplica(replica'), AbstractifyOutboundCPacketsToSeqOfRslPackets(packets_sent)) } predicate Replica_Next_ReadClock_MaybeSendHeartbeat_Preconditions(replica:ReplicaState) { ReplicaStateIsValid(replica) } predicate Replica_Next_ReadClock_MaybeSendHeartbeat_Postconditions( replica:LReplica, replica':ReplicaState, clock:CClockReading, packets_sent:OutboundPackets ) reads replica'.executor.app { && Replica_Common_Postconditions_NoPacket(replica, replica', packets_sent) && LReplicaNextReadClockMaybeSendHeartbeat( replica, AbstractifyReplicaStateToLReplica(replica'), AbstractifyCClockReadingToClockReading(clock), AbstractifyOutboundCPacketsToSeqOfRslPackets(packets_sent)) } predicate Replica_Next_Spontaneous_MaybeMakeDecision_Preconditions(replica:ReplicaState) { ReplicaStateIsValid(replica) } predicate Replica_Next_Spontaneous_MaybeMakeDecision_Postconditions( replica:LReplica, replica':ReplicaState, packets_sent:OutboundPackets ) reads replica'.executor.app { && Replica_Common_Postconditions_NoPacket(replica, replica', packets_sent) && LReplicaNextSpontaneousMaybeMakeDecision( replica, AbstractifyReplicaStateToLReplica(replica'), AbstractifyOutboundCPacketsToSeqOfRslPackets(packets_sent)) } predicate Replica_Next_Spontaneous_TruncateLogBasedOnCheckpoints_Preconditions(replica:ReplicaState) { ReplicaStateIsValid(replica) } predicate Replica_Next_Spontaneous_TruncateLogBasedOnCheckpoints_Postconditions( replica:LReplica, replica':ReplicaState, packets_sent:OutboundPackets ) reads replica'.executor.app { && Replica_Common_Postconditions_NoPacket(replica, replica', packets_sent) && LReplicaNextSpontaneousTruncateLogBasedOnCheckpoints( replica, AbstractifyReplicaStateToLReplica(replica'), AbstractifyOutboundCPacketsToSeqOfRslPackets(packets_sent)) } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/RSL/Unsendable.i.dfy ================================================ include "../../Protocol/RSL/Replica.i.dfy" include "PacketParsing.i.dfy" module LiveRSL__Unsendable_i { import opened Native__Io_s import opened Native__NativeTypes_s import opened LiveRSL__Replica_i import opened LiveRSL__PacketParsing_i import opened Common__GenericMarshalling_i import opened Environment_s predicate IosReflectIgnoringUnsendable(ios:seq>>) { && |ios| == 1 && ios[0].LIoOpReceive? && (|| !Demarshallable(ios[0].r.msg, CMessage_grammar()) || !Marshallable(parse_Message(DemarshallFunc(ios[0].r.msg, CMessage_grammar())))) } predicate HostNextIgnoreUnsendable(s:LScheduler, s':LScheduler, ios:seq>>) { && s.nextActionIndex == 0 && s' == s.(nextActionIndex := 1) && IosReflectIgnoringUnsendable(ios) } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/SHT/AppInterface.i.dfy ================================================ include "../Common/GenericMarshalling.i.dfy" include "../../Protocol/SHT/Keys.i.dfy" abstract module Impl__AppInterface_i { import opened Common__GenericMarshalling_i import opened SHT__Keys_i import opened AppInterface_i`All ////////////////////////////////////////////////////////////////////////////////// // The application's implementation supplies these functions, lemmas, etc. ////////////////////////////////////////////////////////////////////////////////// function method Key_grammar() : G function method Value_grammar() : G function method parse_Key(val:V) : Key requires ValInGrammar(val, Key_grammar()); function method parse_Value(val:V) : Value requires ValInGrammar(val, Value_grammar()); method MarshallKey(c:Key) returns (val:V) requires ValidKey(c); ensures ValInGrammar(val, Key_grammar()); ensures ValidVal(val); ensures parse_Key(val) == c; ensures 0 <= SizeOfV(val) < 8 + max_key_len(); method MarshallValue(c:Value) returns (val:V) requires ValidValue(c); ensures ValInGrammar(val, Value_grammar()); ensures ValidVal(val); ensures parse_Value(val) == c; ensures 0 <= SizeOfV(val) < 8 + max_val_len(); method IsKeyValid(key:Key) returns (b:bool) ensures b == ValidKey(key); method IsValueValid(val:Value) returns (b:bool) ensures b == ValidValue(val); method IsKeyLt(k:Key, k':Key) returns (b:bool) ensures b == KeyLt(k, k'); lemma lemma_ValidKey_grammer() ensures ValidGrammar(Key_grammar()); lemma lemma_ValidValue_grammer() ensures ValidGrammar(Value_grammar()); //function method KeyRangeSize(kr:KeyRange) : uint64 } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/SHT/AppInterfaceConcrete.i.dfy ================================================ include "AppInterface.i.dfy" module Impl__AppInterfaceConcrete_i refines Impl__AppInterface_i { export Spec provides Common__GenericMarshalling_i, AppInterface_i provides Key_grammar, Value_grammar provides parse_Key, parse_Value provides MarshallKey, MarshallValue, IsKeyValid, IsValueValid, IsKeyLt provides lemma_ValidKey_grammer, lemma_ValidValue_grammer export All reveals * function method Key_grammar() : G { GUint64 } function method Value_grammar() : G { GByteArray } function method parse_Key(val:V) : Key { val.u } function method parse_Value(val:V) : Value { val.b } method MarshallKey(c:Key) returns (val:V) { val := VUint64(c); } method MarshallValue(c:Value) returns (val:V) { val := VByteArray(c); } method IsKeyValid(key:Key) returns (b:bool) { b := true; } method IsValueValid(val:Value) returns (b:bool) { b := |val| < 1024; } method IsKeyLt(k:Key, k':Key) returns (b:bool) { b := k < k'; } lemma lemma_ValidKey_grammer() { } lemma lemma_ValidValue_grammer() { } //function method KeyRangeSize(kr:KeyRange) : uint64 //{ // if KeyPlusLe(kr.khi, kr.klo) then 0 // else // KeyPlusAntisymmetry(kr.khi, kr.klo); // assert !kr.khi.KeyZero?; // assert !kr.klo.KeyInf?; // var upper := if kr.khi.KeyInf? then 0xFFFF_FFFF_FFFF_FFFF else kr.khi.k; // var lower := if kr.klo.KeyZero? then 0 else kr.klo.k; // assert lower <= upper; // upper - lower //} } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/SHT/CMessage.i.dfy ================================================ include "../../Protocol/SHT/Message.i.dfy" include "../Common/NodeIdentity.i.dfy" include "../../Protocol/SHT/Network.i.dfy" include "Parameters.i.dfy" include "../../Common/Logic/Option.i.dfy" module SHT__CMessage_i { import opened Native__NativeTypes_s import opened Native__Io_s import opened SHT__Message_i import opened Common__NodeIdentity_i import opened SHT__Network_i import opened Impl_Parameters_i import opened Logic__Option_i import opened AppInterface_i`Spec import opened SHT__HT_s import opened SHT__SingleMessage_i import opened SHT__Keys_i import opened GenericRefinement_i // For now, we use the same keys and values the app's spec does // Someday, we may want to introduce a split between the app's // high-level view of keys and values, and its low-level implementation datatype CMessage = CGetRequest(k_getrequest:Key) | CSetRequest(k_setrequest:Key, v_setrequest:OptionalValue) | CReply(k_reply:Key, v:OptionalValue) | CRedirect(k_redirect:Key, id:EndPoint) | CShard(kr:KeyRange, recipient:EndPoint) | CDelegate(range:KeyRange, h:Hashtable) datatype CSingleMessage = CSingleMessage(seqno:uint64, dst:EndPoint, m:CMessage) | CAck(ack_seqno:uint64) // I got everything up to and including seqno | CInvalidMessage() type CPMsg = CSingleMessage datatype CPacket = CPacket(dst:EndPoint, src:EndPoint, msg:CPMsg) predicate CMessageIsAbstractable(cmsg:CMessage) { (cmsg.CRedirect? ==> EndPointIsAbstractable(cmsg.id)) && (cmsg.CShard? ==> EndPointIsAbstractable(cmsg.recipient)) } function AbstractifyCMessageToRslMessage(cmsg:CMessage) : Message requires CMessageIsAbstractable(cmsg); { match cmsg case CGetRequest(k) => GetRequest(k) case CSetRequest(k, v) => SetRequest(k, v) case CReply(k, v) => Reply(k, v) case CRedirect(k, id) => Redirect(k, AbstractifyEndPointToNodeIdentity(id)) case CShard(kr, recipient) => Shard(kr, AbstractifyEndPointToNodeIdentity(recipient)) case CDelegate(range, h) => Delegate(range, h) } predicate CSingleMessageIsAbstractable(smsg:CSingleMessage) { match smsg case CSingleMessage(seqno, dst, m) => EndPointIsAbstractable(dst) && CMessageIsAbstractable(m) case CAck(_) => true case CInvalidMessage => true } function AbstractifyCSingleMessageToSingleMessage(smsg:CSingleMessage) : SingleMessage requires CSingleMessageIsAbstractable(smsg); { match smsg case CSingleMessage(seqno, dst, m) => SingleMessage(seqno as int, AbstractifyEndPointToNodeIdentity(dst), AbstractifyCMessageToRslMessage(m)) case CAck(seqno) => Ack(seqno as int) case CInvalidMessage => InvalidMessage() } predicate CSingleMessageIsValid(smsg:CSingleMessage, params:CParameters) { match smsg case CSingleMessage(seqno, _, _) => seqno < params.max_seqno case CAck(seqno) => seqno < params.max_seqno case CInvalidMessage => false } predicate CSingleMessageSeqIsAbstractable(cs:seq) { forall i :: 0 <= i < |cs| ==> CSingleMessageIsAbstractable(cs[i]) } function AbstractifySeqOfCSingleMessageToSeqOfSingleMessage(cs:seq) : seq> requires CSingleMessageSeqIsAbstractable(cs); { MapSeqToSeq(cs, AbstractifyCSingleMessageToSingleMessage) } ////////////////////////////////////////////////////////////////////////////// predicate CPacketIsAbstractable(cpacket:CPacket) { EndPointIsAbstractable(cpacket.dst) && EndPointIsAbstractable(cpacket.src) && CSingleMessageIsAbstractable(cpacket.msg) } function AbstractifyCPacketToShtPacket(cpacket:CPacket) : Packet requires CPacketIsAbstractable(cpacket); { Packet(AbstractifyEndPointToNodeIdentity(cpacket.dst), AbstractifyEndPointToNodeIdentity(cpacket.src), AbstractifyCSingleMessageToSingleMessage(cpacket.msg)) } predicate CPacketsIsAbstractable(cps:set) { forall p :: p in cps ==> CPacketIsAbstractable(p) } function {:opaque} AbstractifyCPacketsToPackets(cps:set) : set requires CPacketsIsAbstractable(cps); ensures forall p :: p in cps ==> AbstractifyCPacketToShtPacket(p) in AbstractifyCPacketsToPackets(cps); { set p | p in cps :: AbstractifyCPacketToShtPacket(p) } predicate CPacketSeqIsAbstractable(cps:seq) { forall p :: p in cps ==> CPacketIsAbstractable(p) } function {:opaque} AbstractifySeqOfCPacketsToSetOfShtPackets(cps:seq) : set requires CPacketSeqIsAbstractable(cps); ensures forall p :: p in cps ==> AbstractifyCPacketToShtPacket(p) in AbstractifySeqOfCPacketsToSetOfShtPackets(cps); { set p | p in cps :: AbstractifyCPacketToShtPacket(p) } predicate OptionCPacketIsAbstractable(cp:Option) { match cp { case Some(p) => CPacketIsAbstractable(p) case None => true } } function AbstractifyOptionCPacketToOptionShtPacket(cp:Option) : Option requires OptionCPacketIsAbstractable(cp); { match cp { case Some(p) => Some(AbstractifyCPacketToShtPacket(p)) case None => None() } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/SHT/ConstantsState.i.dfy ================================================ include "../../Protocol/SHT/Host.i.dfy" include "../Common/NodeIdentity.i.dfy" include "Parameters.i.dfy" module SHT__ConstantsState_i { import opened Common__SeqIsUniqueDef_i import opened Native__Io_s import opened SHT__Host_i import opened Common__NodeIdentity_i import opened Impl_Parameters_i datatype ConstantsState = ConstantsState( rootIdentity:EndPoint, hostIds:seq, params:CParameters) predicate ConstantsStateIsAbstractable(constants:ConstantsState) { EndPointIsAbstractable(constants.rootIdentity) && SeqOfEndPointsIsAbstractable(constants.hostIds) } function AbstractifyToConstants(constants:ConstantsState) : Constants requires ConstantsStateIsAbstractable(constants); { Constants(AbstractifyEndPointToNodeIdentity(constants.rootIdentity), AbstractifyEndPointsToNodeIdentities(constants.hostIds), AbstractifyCParametersToParameters(constants.params)) } predicate ConstantsStateIsValid(constants:ConstantsState) { ConstantsStateIsAbstractable(constants) && CParametersIsValid(constants.params) && SeqIsUnique(constants.hostIds) && ValidPhysicalAddress(constants.rootIdentity) } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/SHT/DelegationLookup.i.dfy ================================================ include "Delegations.i.dfy" module DelegationLookup_i { import opened Native__NativeTypes_s import opened Native__Io_s import opened Impl__Delegations_i import opened SHT__Keys_i import opened Common__NodeIdentity_i import opened AppInterface_i`Spec import opened SHT__Delegations_i function min(x:int, y:int) : int { if x < y then x else y } predicate InBounds(i:int, low:int, high:int, len:int) { low <= i < min(high, len) } lemma lemma_CDM_NoLowsAreInfinite(m:CDelegationMap) requires CDelegationMapIsValid(m); ensures forall i :: 0 <= i < |m.lows| ==> !m.lows[i].klo.KeyInf?; { forall i | 0 <= i < |m.lows| ensures !m.lows[i].klo.KeyInf?; { if m.lows[i].klo.KeyInf? { CDelegationMapIsSortedExtension(m); var last := |m.lows| - 1; if i == last { assert KeyPlusLt(m.lows[i].klo, KeyInf()); } else { assert KeyPlusLt(m.lows[i].klo, m.lows[last].klo); KeyPlusTransitivity(m.lows[i].klo, m.lows[last].klo, KeyInf()); } KeyPlusAntisymmetry(m.lows[i].klo, KeyInf()); assert false; } } } lemma CDM_IndexForKey_Ordering_specific(m:CDelegationMap, k1:KeyPlus, k2:KeyPlus) requires CDelegationMapIsValid(m); requires KeyPlusLe(k1, k2); ensures CDM_IndexForKey(m, k1) <= CDM_IndexForKey(m, k2); { CDM_IndexForKey_Ordering(m); } method DelegateForKeyRangeIsHostImpl(m:CDelegationMap, kr:KeyRange, id:EndPoint) returns (b:bool) requires CDelegationMapIsValid(m); requires EndPointIsAbstractable(id); ensures b == DelegateForKeyRangeIsHost(AbstractifyCDelegationMapToDelegationMap(m), kr, AbstractifyEndPointToNodeIdentity(id)); { if EmptyKeyRange(kr) { b := true; forall k | KeyRangeContains(kr, KeyPlus(k)) ensures false; { assert KeyPlusLe(kr.klo, KeyPlus(k)); assert KeyPlusLt(KeyPlus(k), kr.khi); assert KeyPlusLe(kr.khi, kr.klo); KeyPlusTransitivity(kr.klo, KeyPlus(k), kr.khi); assert KeyPlusLt(kr.klo, kr.khi); KeyPlusAntisymmetry(kr.klo, kr.khi); } return; } var k_min := KeyMin(); if kr.klo.KeyZero? && kr.khi == KeyPlus(k_min) { forall k | KeyRangeContains(kr, KeyPlus(k)) ensures false; { assert KeyPlusLe(kr.khi, KeyPlus(k)); KeyPlusAntisymmetry(kr.khi, KeyPlus(k)); } return true; } var m' := CDM_Defragment(m); var lo_index := CDM_IndexForKey(m', kr.klo); var hi_index := CDM_IndexForKey(m', kr.khi); forall () ensures lo_index <= hi_index; { KeyPlusAntisymmetry(kr.klo, kr.khi); CDM_IndexForKey_Ordering_specific(m', kr.klo, kr.khi); } var index := lo_index; ghost var witness_key := kr.klo; assert KeyPlusLe(kr.klo, witness_key); KeyPlusAntisymmetry(kr.klo, kr.khi); // ==> assert KeyPlusLt(witness_key, kr.khi); while index <= hi_index invariant lo_index <= index <= hi_index + 1; invariant forall i {:trigger InBounds(i, lo_index as int, index as int, |m'.lows|)} :: InBounds(i, lo_index as int, index as int, |m'.lows|) ==> m'.lows[i].id == id; invariant !witness_key.KeyInf?; invariant KeyRangeContains(kr, witness_key); invariant index <= hi_index ==> CDM_IndexForKey(m', witness_key) == index; { if m'.lows[index].id != id { b := false; forall () ensures AbstractifyEndPointToNodeIdentity(m'.lows[index].id) != AbstractifyEndPointToNodeIdentity(id) { if AbstractifyEndPointToNodeIdentity(m'.lows[index].id) == AbstractifyEndPointToNodeIdentity(id) { lemma_AbstractifyEndPointToNodeIdentity_injective(m'.lows[index].id, id); assert false; } } if !witness_key.KeyZero? { assert !DelegateForKeyRangeIsHost(AbstractifyCDelegationMapToDelegationMap(m'), kr, AbstractifyEndPointToNodeIdentity(id)); } else { assert kr.klo.KeyZero?; assert !kr.khi.KeyZero? && kr.khi != KeyPlus(k_min); forall () ensures index == 0; { assert KeyRangeContains(CDM_IndexToKeyRange(m', 0), witness_key); CDM_Partitioned(m', witness_key, 0); if index != 0 { assert CDM_IndexForKey(m', witness_key) != 0; assert KeyRangeContains(CDM_IndexToKeyRange(m', index as int), witness_key); assert false; } assert index == 0; // Because witness_key is 0, it can only be contained from below by the 0th mapping } if |m'.lows| == 1 { assert KeyRangeContains(kr, KeyPlus(k_min)); assert AbstractifyCDelegationMapToDelegationMap(m')[k_min] != AbstractifyEndPointToNodeIdentity(id); } else { assert m'.lows[1].klo != KeyPlus(k_min); assert KeyPlusLt(KeyPlus(k_min), m'.lows[1].klo); assert KeyRangeContains(kr, KeyPlus(k_min)); assert KeyRangeContains(CDM_IndexToKeyRange(m', 0), KeyPlus(k_min)); calc ==> { true; { CDM_Partitioned(m', KeyPlus(k_min), 0); } CDM_IndexForKey(m', KeyPlus(k_min)) == 0; } assert AbstractifyCDelegationMapToDelegationMap(m')[k_min] != AbstractifyEndPointToNodeIdentity(id); } assert b == DelegateForKeyRangeIsHost(AbstractifyCDelegationMapToDelegationMap(m'), kr, AbstractifyEndPointToNodeIdentity(id)); } return; } ghost var old_index := index; index := index + 1; if index <= hi_index { ghost var old_witness := witness_key; witness_key := m'.lows[index].klo; lemma_CDM_NoLowsAreInfinite(m'); //CDM_IndexForKey_Ordering_specific(m'); assert KeyPlusLe(kr.klo, old_witness); assert CDM_IndexForKey(m', old_witness) == old_index; assert KeyPlusLt(old_witness, m'.lows[old_index + 1].klo); assert KeyPlusLe(m'.lows[old_index+1].klo, witness_key); KeyPlusTransitivity(kr.klo, old_witness, m'.lows[old_index + 1].klo); KeyPlusTransitivity(kr.klo, m'.lows[old_index + 1].klo, witness_key); assert KeyPlusLe(kr.klo, witness_key); if index < hi_index { assert KeyPlusLt(witness_key, CDM_IndexToKeyRange(m', index as int).khi); CDM_KeyRangesAreOrdered(m', index as int, hi_index as int); KeyPlusTransitivity(witness_key, CDM_IndexToKeyRange(m', index as int).khi, m'.lows[hi_index].klo); assert KeyPlusLt(witness_key, m'.lows[hi_index].klo); assert KeyPlusLe(m'.lows[hi_index].klo, kr.khi); KeyPlusTransitivity(witness_key, m'.lows[hi_index].klo, kr.khi); assert KeyPlusLt(witness_key, kr.khi); assert KeyRangeContains(kr, witness_key); } else { if kr.khi != m'.lows[index].klo { assert KeyRangeContains(kr, witness_key); } else { forall k | KeyRangeContains(kr, KeyPlus(k)) ensures AbstractifyCDelegationMapToDelegationMap(m')[k] == AbstractifyEndPointToNodeIdentity(id); { assert KeyPlusLe(kr.klo, KeyPlus(k)); assert KeyPlusLt(KeyPlus(k), kr.khi); assert KeyPlusLe(KeyPlus(k), kr.khi); ghost var k_index := CDM_IndexForKey(m', KeyPlus(k)); CDM_IndexForKey_Ordering_specific(m', kr.klo, KeyPlus(k)); CDM_IndexForKey_Ordering_specific(m', KeyPlus(k), kr.khi); assert lo_index as int <= k_index as int <= hi_index as int < |m'.lows|; if k_index == hi_index { assert KeyPlusLe(kr.khi, KeyPlus(k)); KeyPlusAntisymmetry(kr.khi, KeyPlus(k)); assert false; } assert InBounds(k_index as int, lo_index as int, hi_index as int, |m'.lows|); if k_index < old_index { assert InBounds(k_index as int, lo_index as int, old_index as int, |m'.lows|); assert m'.lows[k_index].id == id; } else { assert m'.lows[k_index].id == id; } } return true; } } assert KeyRangeContains(CDM_IndexToKeyRange(m', index as int), witness_key); CDM_Partitioned(m', witness_key, index as int); assert CDM_IndexForKey(m', witness_key) == index; } forall i {:trigger InBounds(i, lo_index as int, index as int, |m'.lows|)} | InBounds(i, lo_index as int, index as int, |m'.lows|) ensures m'.lows[i].id == id; { if i < old_index as int { assert InBounds(i, lo_index as int, old_index as int, |m'.lows|) ==> m'.lows[i].id == id; } else { } } } forall k | KeyRangeContains(kr, KeyPlus(k)) ensures AbstractifyCDelegationMapToDelegationMap(m')[k] == AbstractifyEndPointToNodeIdentity(id); { assert KeyPlusLe(kr.klo, KeyPlus(k)); assert KeyPlusLt(KeyPlus(k), kr.khi); assert KeyPlusLe(KeyPlus(k), kr.khi); ghost var k_index := CDM_IndexForKey(m', KeyPlus(k)); CDM_IndexForKey_Ordering_specific(m', kr.klo, KeyPlus(k)); CDM_IndexForKey_Ordering_specific(m', KeyPlus(k), kr.khi); assert lo_index as int <= k_index as int <= hi_index as int < |m'.lows|; assert InBounds(k_index as int, lo_index as int, index as int, |m'.lows|); assert m'.lows[k_index].id == id; } b := true; return; } lemma lemma_CDM_Defragment_equivalence(m:CDelegationMap, m':CDelegationMap) requires CDelegationMapIsValid(m); requires CDelegationMapIsValid(m'); requires forall k:Key :: true ==> m.lows[CDM_IndexForKey(m,KeyPlus(k))].id == m'.lows[CDM_IndexForKey(m',KeyPlus(k))].id; ensures AbstractifyCDelegationMapToDelegationMap(m) == AbstractifyCDelegationMapToDelegationMap(m'); { } // TODO: Call this from update, not lookup (and add the last ensures to IsValid) // TODO: Defragment more aggressively method CDM_Defragment(m:CDelegationMap) returns (m':CDelegationMap) requires CDelegationMapIsValid(m); ensures CDelegationMapIsValid(m'); ensures AbstractifyCDelegationMapToDelegationMap(m) == AbstractifyCDelegationMapToDelegationMap(m'); ensures |m'.lows| >= 2 && m'.lows[1].klo.KeyPlus? ==> m'.lows[1].klo.k != KeyMin(); { if |m.lows| as uint64 < 2 || m.lows[1].klo != KeyPlus(KeyMin()) { return m; } if |m.lows| >= 3 { CDelegationMapIsSortedExtension_recursive(m, 1, 2); KeyPlusAntisymmetry(m.lows[1].klo, m.lows[2].klo); assert m.lows[2].klo != KeyPlus(KeyMin()); } var new_lows := [Mapping(KeyZero(), m.lows[1].id)] + m.lows[2..]; m' := CDelegationMap(new_lows); // Prove the third ensures lemma_CDM_NoLowsAreInfinite(m); // Prove sorted to prove IsValid assert CDelegationMapBoundedSize(m'); forall i | 0 <= i < |m'.lows| - 1 ensures KeyPlusLt(m'.lows[i].klo, m'.lows[i+1].klo); { if i == 0 { assert KeyPlusLt(m.lows[0].klo, m.lows[1].klo); } else { assert m'.lows[i] == m.lows[2..][i-1] == m.lows[1+i]; assert m'.lows[i+1] == m.lows[2..][i] == m.lows[2+i]; CDelegationMapIsSortedExtension_recursive(m, 1+i, 2+i); assert KeyPlusLt(m.lows[1+i].klo, m.lows[2+i].klo); } } assert KeyPlusLt(m'.lows[|m'.lows|-1].klo, KeyInf()); assert CDelegationMapIsSorted(m'); // Prove equivalent refinements forall k:Key ensures m.lows[CDM_IndexForKey(m,KeyPlus(k))].id == m'.lows[CDM_IndexForKey(m',KeyPlus(k))].id; { ghost var kp := KeyPlus(k); ghost var k_index := CDM_IndexForKey(m, kp) as int; ghost var k_index' := CDM_IndexForKey(m', kp) as int; if KeyRangeContains(CDM_IndexToKeyRange(m, 0), kp) { assert KeyPlusLt(kp, m.lows[1].klo); assert KeyPlusLt(kp, KeyPlus(KeyMin())); KeyPlusAntisymmetry(kp, KeyPlus(KeyMin())); assert false; } assert k_index >= 1; if k_index' == 0 { if k_index == 1 { assert m'.lows[0].id == m.lows[1].id; } else { assert KeyPlusLt(kp, m'.lows[1].klo); assert KeyPlusLt(kp, m.lows[2].klo); if 2 < k_index { CDelegationMapIsSortedExtension_recursive(m, 2, k_index); } assert KeyPlusLe(m.lows[2].klo, m.lows[k_index].klo); KeyPlusTransitivity(kp, m.lows[2].klo, m.lows[k_index].klo); // ==> kp < m.lows[k_index] // But we also know: assert KeyPlusLe(m.lows[k_index].klo, kp); KeyPlusAntisymmetry(m.lows[k_index].klo, kp); // Contradiction! assert false; } } else { if k_index == k_index' + 1 { assert m'.lows[k_index'] == m.lows[k_index]; } else { assert m'.lows[k_index'] == m.lows[k_index' + 1]; assert KeyRangeContains(CDM_IndexToKeyRange(m, k_index), kp); assert KeyRangeContains(CDM_IndexToKeyRange(m, k_index' + 1), kp); CDM_Partitioned(m, kp, k_index); assert false; } } } lemma_CDM_Defragment_equivalence(m, m'); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/SHT/Delegations.i.dfy ================================================ include "../../Protocol/SHT/Delegations.i.dfy" include "../Common/NodeIdentity.i.dfy" module Impl__Delegations_i { import opened Native__NativeTypes_s import opened Native__Io_s import opened SHT__Delegations_i import opened Common__NodeIdentity_i import opened AppInterface_i`Spec import opened Concrete_NodeIdentity_i`Spec import opened SHT__Keys_i import opened Common__NetClient_i // To enable efficient lookups of which host owns a given key, // we maintain a list of mappings. Each mapping indicates that // its host owns all of the keys from the mapping's klo up until // the next mapping's klo (or KeyInf, if it's the last in the sequence) // TODO: change the name of the second field from "id" to "ep" datatype Mapping = Mapping(klo:KeyPlus, id:EndPoint) datatype CDelegationMap = CDelegationMap(lows:seq) predicate CDelegationMapBoundedSize(m:CDelegationMap) { 0 < |m.lows| < 0x1_0000_0000_0000_0000 - 1 } predicate CDelegationMapIsSorted_Helper(m:CDelegationMap) requires CDelegationMapBoundedSize(m) { forall i {:trigger KeyPlusLt(m.lows[i].klo, m.lows[i+1].klo)} :: 0<=i<|m.lows|-1 ==> KeyPlusLt(m.lows[i].klo, m.lows[i+1].klo) } predicate CDelegationMapIsSorted(m:CDelegationMap) { CDelegationMapBoundedSize(m) && CDelegationMapIsSorted_Helper(m) && KeyPlusLt(m.lows[|m.lows|-1].klo, KeyInf()) } lemma CDelegationMapIsSortedExtension_recursive(m:CDelegationMap, i:int, j:int) requires 0<=i KeyPlusLt(m.lows[i].klo, m.lows[j].klo); { forall i,j | 0<=i) { forall m :: m in lows ==> EndPointIsValidPublicKey(m.id) } predicate CDelegationMapIsValid(m:CDelegationMap) { CDelegationMapHasValidEndPoints(m.lows) && CDelegationMapIsComplete(m) } function CDM_IndexToNextKeyBoundary(m:CDelegationMap, i:int) : KeyPlus requires 0 <= i < |m.lows|; { if i < |m.lows| - 1 then m.lows[i+1].klo else KeyInf() } // Key range from the i-th to the j-th key boundary function CDM_IndexRangeToKeyRange(m:CDelegationMap, i:int, j:int) : KeyRange requires 0<=i<=j<|m.lows|; { KeyRange(m.lows[i].klo, CDM_IndexToNextKeyBoundary(m, j)) } // Key range from i-th key boundary to the next key boundary function CDM_IndexToKeyRange(m:CDelegationMap, idx:int) : KeyRange requires 0<=idx<|m.lows|; { CDM_IndexRangeToKeyRange(m, idx, idx) } function KeyRangesFromCDelegationMap(m:CDelegationMap) : set { set i | 0<=i<|m.lows| :: CDM_IndexToKeyRange(m, i) } function method {:opaque} CDM_IndexForKey_helper(m:CDelegationMap, k:KeyPlus, index:uint64) : uint64 requires CDelegationMapIsAbstractable(m); requires forall i :: 0 <= i <= index as int && i < |m.lows| ==> KeyPlusLe(m.lows[i].klo, k); decreases |m.lows| - index as int; ensures 0 <= CDM_IndexForKey_helper(m, k, index) as int < |m.lows|; ensures !k.KeyInf? ==> KeyRangeContains(CDM_IndexToKeyRange(m, CDM_IndexForKey_helper(m, k, index) as int), k); ensures k.KeyInf? ==> CDM_IndexForKey_helper(m, k, index) as int == |m.lows| - 1; { CDelegationMapIsSortedExtension(m); if index >= (|m.lows| as uint64 - 1) as uint64 then (|m.lows| as uint64 - 1) as uint64 else if KeyPlusLt(k, m.lows[index + 1].klo) then index else KeyPlusAntisymmetry(k, m.lows[index+1].klo); CDM_IndexForKey_helper(m, k, index + 1) } lemma CDM_Partitioned(m:CDelegationMap, k:KeyPlus, index:int) requires CDelegationMapIsValid(m); requires 0 <= index < |m.lows|; requires KeyRangeContains(CDM_IndexToKeyRange(m, index), k); ensures forall i :: 0 <= i < |m.lows| && i != index ==> !KeyRangeContains(CDM_IndexToKeyRange(m, i), k); { CDelegationMapIsSortedExtension(m); var real_kr := CDM_IndexToKeyRange(m, index); forall i | 0 <= i < |m.lows| && i != index ensures !KeyRangeContains(CDM_IndexToKeyRange(m, i), k); { if KeyRangeContains(CDM_IndexToKeyRange(m, i), k) { // Proof by contradiction var kr := CDM_IndexToKeyRange(m, i); if i < index { assert KeyPlusLt(k, kr.khi); CDM_KeyRangesAreOrdered(m, i, index); assert KeyPlusLe(kr.khi, real_kr.klo); KeyPlusTransitivity(k, kr.khi, real_kr.klo); KeyPlusAntisymmetry(k, real_kr.klo); assert false; } else { assert KeyPlusLe(kr.klo, k); assert KeyPlusLt(k, real_kr.khi); CDM_KeyRangesAreOrdered(m, index, i); assert KeyPlusLe(real_kr.khi, kr.klo); KeyPlusTransitivity(real_kr.khi, kr.klo, k); KeyPlusAntisymmetry(real_kr.khi, k); assert false; } } } } function method CDM_IndexForKey(m:CDelegationMap, k:KeyPlus) : uint64 requires 0<|m.lows|; requires CDelegationMapIsAbstractable(m) ensures 0 <= CDM_IndexForKey(m, k) as int < |m.lows|; ensures !k.KeyInf? ==> KeyRangeContains(CDM_IndexToKeyRange(m, CDM_IndexForKey(m, k) as int), k); ensures k.KeyInf? ==> CDM_IndexForKey(m, k) as int == |m.lows| - 1; { //IndexForKeyAccurate(m, k, 0); CDM_IndexForKey_helper(m, k, 0) } // Explicitly naming this :| so Dafny will cooperate: function CDM_IndexForKeyRange(m:CDelegationMap, kr:KeyRange) : uint64 requires CDelegationMapIsAbstractable(m); requires kr in KeyRangesFromCDelegationMap(m); ensures 0 <= CDM_IndexForKeyRange(m, kr) as int < |m.lows|; { var idx :| 0<=idx<|m.lows| && kr==CDM_IndexToKeyRange(m,idx); idx as uint64 } predicate CDelegationMapIsAbstractable(m:CDelegationMap) { && (forall low :: low in m.lows ==> EndPointIsAbstractable(low.id)) && CDelegationMapIsComplete(m) } function RefineToDelegationMapEntry(m:CDelegationMap, k:Key) : NodeIdentity requires CDelegationMapIsAbstractable(m); requires forall low :: low in m.lows ==> EndPointIsAbstractable(low.id); { AbstractifyEndPointToNodeIdentity(m.lows[CDM_IndexForKey(m,KeyPlus(k))].id) } function AbstractifyCDelegationMapToDelegationMap(m:CDelegationMap) : DelegationMap requires CDelegationMapIsAbstractable(m); requires forall low :: low in m.lows ==> EndPointIsAbstractable(low.id); { imap k:Key {:trigger CDM_IndexForKey(m,KeyPlus(k))} :: RefineToDelegationMapEntry(m, k) } lemma CDM_KeyRangesAreOrdered(m:CDelegationMap, i1:int, i2:int) requires CDelegationMapIsSorted(m); requires 0<=i1 i1==i2; { forall i1,i2 | 0<=i1<|m.lows| && CDM_IndexToKeyRange(m, i1)==kr && 0<=i2<|m.lows| && CDM_IndexToKeyRange(m, i2)==kr ensures i1==i2; { if (i1 KeyPlusLt(sm.lows[i].klo, sm.lows[i+1].klo); assert sm.lows == m.lows[lo..hi]; assert KeyPlusLt(m.lows[|m.lows|-1].klo, KeyInf()); assert sm.lows[|sm.lows|-1] == m.lows[hi-1]; assert CDelegationMapIsSorted(m); if (hi-1 == |m.lows|-1) { assert KeyPlusLe(m.lows[hi-1].klo, m.lows[|m.lows|-1].klo); } else if (hi-1 < |m.lows|-1) { var j := hi; var l := hi-1; assert KeyPlusLe(m.lows[l].klo, m.lows[l+1].klo); while (j < |m.lows|-1) invariant hi <= j <= |m.lows| - 1; invariant forall k :: l <= k <= j ==> KeyPlusLe(m.lows[l].klo, m.lows[k].klo); { var k' := j-1; assert KeyPlusLe(m.lows[l].klo, m.lows[k'].klo); assert KeyPlusLe(m.lows[k'].klo, m.lows[k'+1].klo); assert KeyPlusLe(m.lows[j].klo, m.lows[j+1].klo); j := j+ 1; } } else { assert false; } assert KeyPlusLe(m.lows[hi-1].klo, m.lows[|m.lows|-1].klo); assert KeyPlusLe(sm.lows[|sm.lows|-1].klo, m.lows[|m.lows|-1].klo); assert KeyPlusLt(sm.lows[|sm.lows|-1].klo, KeyInf()); } ////////////////////////////////////////////////////////////////////////////// function CDelegationMapDelegate(m:CDelegationMap, k:Key) : NodeIdentity requires CDelegationMapIsAbstractable(m); { AbstractifyCDelegationMapToDelegationMap(m)[k] } predicate CDM_PrefixAgrees(m:CDelegationMap, dm:DelegationMap, klim:KeyPlus) requires CDelegationMapIsAbstractable(m); requires DelegationMapComplete(dm); { forall k:Key :: KeyPlusLt(KeyPlus(k), klim) ==> CDelegationMapDelegate(m,k)==dm[k] } lemma CDM_IndexForKey_Ordering(m:CDelegationMap) requires CDelegationMapIsValid(m); ensures forall k1, k2 :: KeyPlusLe(k1, k2) ==> CDM_IndexForKey(m, k1) <= CDM_IndexForKey(m, k2); { forall k1, k2 | KeyPlusLe(k1, k2) ensures CDM_IndexForKey(m, k1) <= CDM_IndexForKey(m, k2); { var index1 := CDM_IndexForKey(m, k1) as int; var index2 := CDM_IndexForKey(m, k2) as int; CDelegationMapIsSortedExtension(m); KeyPlusAntisymmetry(k1, k2); if k1.KeyInf? { assert k2.KeyInf?; assert index1 == |m.lows|-1 == index2; } else if k2.KeyInf? { assert index2 == |m.lows|-1; assert index1 <= |m.lows|-1; } else { if index2 < index1 { // Suppose... var kr1 := CDM_IndexToKeyRange(m, index1); var kr2 := CDM_IndexToKeyRange(m, index2); assert KeyPlusLt(kr2.klo, kr1.klo); assert KeyPlusLe(kr1.klo, k1); assert KeyPlusLt(k1, kr1.khi); assert KeyPlusLe(kr2.klo, k2); assert KeyPlusLt(k2, kr2.khi); assert KeyPlusLe(kr2.khi, kr1.klo); KeyPlusTransitivity(k2, kr2.khi, kr1.klo); assert KeyPlusLe(k2, kr1.klo); KeyPlusTransitivity(k2, kr1.klo, k1); assert KeyPlusLe(k2, k1); assert false; } assert index1 <= index2; } } } lemma lemma_UpdateCDelegationMap_Part2_Helper(m:CDelegationMap, m':CDelegationMap, newkr:KeyRange, id:EndPoint) requires CDelegationMapIsValid(m); requires CDelegationMapIsValid(m'); requires EndPointIsValidPublicKey(id); requires !EmptyKeyRange(newkr); requires forall k:Key :: k in AbstractifyCDelegationMapToDelegationMap(m') <==> k in UpdateDelegationMap(AbstractifyCDelegationMapToDelegationMap(m), newkr, AbstractifyEndPointToNodeIdentity(id)); requires forall k:Key :: true ==> AbstractifyCDelegationMapToDelegationMap(m')[k] == UpdateDelegationMap(AbstractifyCDelegationMapToDelegationMap(m), newkr, AbstractifyEndPointToNodeIdentity(id))[k]; ensures AbstractifyCDelegationMapToDelegationMap(m') == UpdateDelegationMap(AbstractifyCDelegationMapToDelegationMap(m), newkr, AbstractifyEndPointToNodeIdentity(id)); { } lemma {:timeLimitMultiplier 4} {:induction false} UpdateCDelegationMap_Part2(m:CDelegationMap, newkr:KeyRange, id:EndPoint, m':CDelegationMap, left_index:int, right_index:int, new_left:seq, new_right:seq) requires CDelegationMapIsValid(m); requires EndPointIsValidPublicKey(id); requires !EmptyKeyRange(newkr); requires left_index == CDM_IndexForKey(m, newkr.klo) as int; requires right_index == CDM_IndexForKey(m, newkr.khi) as int; requires new_left == m.lows[..left_index]; requires m.lows[left_index].klo == newkr.klo; requires !(left_index == 0 && !newkr.klo.KeyZero?); // left_index != 0 || newkr.klo.KeyZero requires new_right == if newkr.khi.KeyInf? then [] else [Mapping(newkr.khi, m.lows[right_index].id)] + m.lows[right_index+1..]; requires m' == CDelegationMap(new_left + [Mapping(newkr.klo, id)] + new_right); requires CDelegationMapIsValid(m'); ensures AbstractifyCDelegationMapToDelegationMap(m') == UpdateDelegationMap(AbstractifyCDelegationMapToDelegationMap(m), newkr, AbstractifyEndPointToNodeIdentity(id)); { var rm := AbstractifyCDelegationMapToDelegationMap(m); var rm' := AbstractifyCDelegationMapToDelegationMap(m'); var updated_rm := UpdateDelegationMap(rm, newkr, AbstractifyEndPointToNodeIdentity(id)); forall k:Key ensures k in rm' <==> k in updated_rm; { } forall k:Key ensures rm'[k] == updated_rm[k]; { CDelegationMapIsSortedExtension(m); CDelegationMapIsSortedExtension(m'); var k_index := CDM_IndexForKey(m', KeyPlus(k)) as int; if KeyRangeContains(newkr, KeyPlus(k)) { if newkr.klo.KeyZero? { assert KeyPlusLe(newkr.klo, m.lows[0].klo); if |m.lows| > 1 { assert KeyPlusLt(newkr.klo, m.lows[1].klo); } CDM_Partitioned(m, newkr.klo, 0); assert new_left == []; CDM_Partitioned(m', KeyPlus(k), 0); assert k_index == 0; assert rm'[k] == AbstractifyEndPointToNodeIdentity(id); assert rm'[k] == updated_rm[k]; } else { assert m'.lows[left_index] == Mapping(newkr.klo, id); assert KeyRangeContains(CDM_IndexToKeyRange(m', left_index), KeyPlus(k)); CDM_Partitioned(m', KeyPlus(k), left_index); assert rm'[k] == AbstractifyEndPointToNodeIdentity(id); assert rm'[k] == updated_rm[k]; } } else { KeyPlusAntisymmetry(KeyPlus(k), newkr.khi); assert !KeyPlusLt(KeyPlus(k), newkr.khi) ==> KeyPlusLe(newkr.khi, KeyPlus(k)); KeyPlusAntisymmetry(newkr.klo, KeyPlus(k)); assert !KeyPlusLe(newkr.klo, KeyPlus(k)) ==> KeyPlusLt(KeyPlus(k), newkr.klo); assert KeyPlusLt(KeyPlus(k), newkr.klo) || KeyPlusLe(newkr.khi, KeyPlus(k)); // From !KeyRangeContains(newkr, k) assert m'.lows[left_index] == Mapping(newkr.klo, id); if k_index < left_index { assert m'.lows[k_index] == m.lows[..left_index][k_index] == m.lows[k_index]; if k_index < left_index - 1 { assert KeyRangeContains(CDM_IndexToKeyRange(m', k_index), KeyPlus(k)); CDM_Partitioned(m', KeyPlus(k), k_index); assert KeyRangeContains(CDM_IndexToKeyRange(m, k_index), KeyPlus(k)); CDM_Partitioned(m, KeyPlus(k), k_index); assert rm'[k] == updated_rm[k]; } else { // k_index == left_index - 1 assert KeyRangeContains(CDM_IndexToKeyRange(m', k_index), KeyPlus(k)); //CDM_Partitioned(m', KeyPlus(k), k_index); // ==> m.lows[k_index].klo <= k < newkr.klo assert KeyPlusLe(m.lows[k_index].klo, KeyPlus(k)); assert KeyPlusLt(KeyPlus(k), newkr.klo); assert KeyPlusLt(KeyPlus(k), m.lows[left_index].klo); var range := CDM_IndexToKeyRange(m, k_index); assert range == CDM_IndexRangeToKeyRange(m, k_index, k_index); assert range == KeyRange(m.lows[k_index].klo, CDM_IndexToNextKeyBoundary(m, k_index)); assert range == KeyRange(m.lows[k_index].klo, if k_index < |m.lows| - 1 then m.lows[k_index+1].klo else KeyInf()); assert range == KeyRange(m.lows[k_index].klo, m.lows[k_index+1].klo); assert k_index == left_index - 1; assert KeyPlusLt(KeyPlus(k), m.lows[left_index].klo); assert left_index == k_index + 1; assert KeyPlusLt(KeyPlus(k), m.lows[k_index+1].klo); assert KeyPlusLe(range.klo, KeyPlus(k)); assert KeyPlusLt(KeyPlus(k), range.khi); assert KeyRangeContains(range, KeyPlus(k)); CDM_Partitioned(m, KeyPlus(k), k_index); assert CDM_IndexForKey(m, KeyPlus(k)) as int == k_index; assert rm'[k] == AbstractifyEndPointToNodeIdentity(m.lows[k_index].id); assert rm'[k] == updated_rm[k]; } } else { var new_index := left_index; // Index of the new mapping, Mapping(newkr.klo, id) assert k_index > new_index; UpdateCDelegationMap_RHS(m, newkr, id, m', left_index, right_index, new_left, new_right, k, left_index); assert rm'[k] == updated_rm[k]; } } } lemma_UpdateCDelegationMap_Part2_Helper(m, m', newkr, id); assert AbstractifyCDelegationMapToDelegationMap(m') == UpdateDelegationMap(AbstractifyCDelegationMapToDelegationMap(m), newkr, AbstractifyEndPointToNodeIdentity(id)); } lemma SequenceIndexingHelper(a:seq, b:seq, c:seq, d:seq, combined:seq, index:int) requires combined == a + b + c + d; requires index >= |a + b + c|; requires 0 <= index < |combined| ensures combined[index] == d[index - |a + b + c|]; { } lemma UpdateCDelegationMap_RHS_Helper(m:CDelegationMap, newkr:KeyRange, id:EndPoint, m':CDelegationMap, left_index:int, right_index:int, new_left:seq, new_right:seq, k:Key, new_index:int) requires CDelegationMapIsValid(m); requires EndPointIsValidPublicKey(id); requires !EmptyKeyRange(newkr); requires !KeyRangeContains(newkr, KeyPlus(k)); requires left_index == CDM_IndexForKey(m, newkr.klo) as int; requires right_index == CDM_IndexForKey(m, newkr.khi) as int; requires 0 <= new_index <= |m.lows|; requires |new_left| == new_index; requires new_left == m.lows[..new_index]; requires new_right == if newkr.khi.KeyInf? then [] else [Mapping(newkr.khi, m.lows[right_index].id)] + m.lows[right_index+1..]; requires m' == CDelegationMap(new_left + [Mapping(newkr.klo, id)] + new_right); requires CDelegationMapIsValid(m'); requires var k_index := CDM_IndexForKey(m', KeyPlus(k)) as int; k_index > new_index + 1; ensures AbstractifyCDelegationMapToDelegationMap(m')[k] == UpdateDelegationMap(AbstractifyCDelegationMapToDelegationMap(m), newkr, AbstractifyEndPointToNodeIdentity(id))[k]; { var rm := AbstractifyCDelegationMapToDelegationMap(m); var rm' := AbstractifyCDelegationMapToDelegationMap(m'); var updated_rm := UpdateDelegationMap(rm, newkr, AbstractifyEndPointToNodeIdentity(id)); var k_index := CDM_IndexForKey(m', KeyPlus(k)) as int; CDelegationMapIsSortedExtension(m); CDelegationMapIsSortedExtension(m'); assert !newkr.khi.KeyInf?; var cr := CDM_IndexToKeyRange(m', k_index as int); assert KeyRangeContains(cr, KeyPlus(k)); assert m'.lows == m.lows[..new_index] + [Mapping(newkr.klo, id)] + [Mapping(newkr.khi, m.lows[right_index].id)] + m.lows[right_index+1..]; assert {:split_here} true; assert |m.lows[..new_index]| == new_index == new_index; assert |m.lows[..new_index] + [Mapping(newkr.klo, id)] + [Mapping(newkr.khi, m.lows[right_index].id)]| == new_index + 2; if |m.lows[right_index+1..]| > k_index as int - new_index - 2 { assert {:split_here} true; SequenceIndexingHelper(m.lows[..new_index], [Mapping(newkr.klo, id)], [Mapping(newkr.khi, m.lows[right_index].id)], m.lows[right_index+1..], m'.lows, k_index); assert m'.lows[k_index] == m.lows[right_index+1..][k_index-new_index - 2]; } else { assert false; } assert cr.klo == m'.lows[k_index].klo == m.lows[right_index+1..][k_index-new_index-2].klo; var offset_index := right_index+1 + k_index-new_index-2; calc { m'.lows[k_index]; m.lows[right_index+1..|m.lows|][k_index-new_index-2]; { assert m.lows[right_index+1..|m.lows|][k_index-new_index-2] == m.lows[right_index+1 + k_index-new_index-2];} m.lows[right_index+1 + k_index-new_index-2]; m.lows[offset_index]; } assert KeyPlusLe(m.lows[offset_index].klo, KeyPlus(k)); var offplusone := offset_index + 1; if offplusone < |m.lows| { assert offplusone < |m.lows|; assert KeyPlusLt(KeyPlus(k), m.lows[offplusone].klo); } CDM_Partitioned(m, KeyPlus(k), offset_index); assert CDM_IndexForKey(m, KeyPlus(k)) as int == offset_index; //var i :| 0 <= i < |m.lows| && m.lows[i].klo == cr.klo; assert rm'[k] == rm[k]; } lemma {:timeLimitMultiplier 4} UpdateCDelegationMap_RHS(m:CDelegationMap, newkr:KeyRange, id:EndPoint, m':CDelegationMap, left_index:int, right_index:int, new_left:seq, new_right:seq, k:Key, new_index:int) requires CDelegationMapIsValid(m); requires EndPointIsValidPublicKey(id); requires !EmptyKeyRange(newkr); requires !KeyRangeContains(newkr, KeyPlus(k)); requires left_index == CDM_IndexForKey(m, newkr.klo) as int; requires right_index == CDM_IndexForKey(m, newkr.khi) as int; requires 0 <= new_index <= |m.lows|; requires |new_left| == new_index; requires new_left == m.lows[..new_index]; requires new_right == if newkr.khi.KeyInf? then [] else [Mapping(newkr.khi, m.lows[right_index].id)] + m.lows[right_index+1..]; requires m' == CDelegationMap(new_left + [Mapping(newkr.klo, id)] + new_right); requires CDelegationMapIsValid(m'); requires var k_index := CDM_IndexForKey(m', KeyPlus(k)) as int; k_index > new_index; ensures AbstractifyCDelegationMapToDelegationMap(m')[k] == UpdateDelegationMap(AbstractifyCDelegationMapToDelegationMap(m), newkr, AbstractifyEndPointToNodeIdentity(id))[k]; { var rm := AbstractifyCDelegationMapToDelegationMap(m); var rm' := AbstractifyCDelegationMapToDelegationMap(m'); var updated_rm := UpdateDelegationMap(rm, newkr, AbstractifyEndPointToNodeIdentity(id)); var k_index := CDM_IndexForKey(m', KeyPlus(k)) as int; CDelegationMapIsSortedExtension(m); CDelegationMapIsSortedExtension(m'); assert !newkr.khi.KeyInf?; if k_index == new_index + 1 { assert CDM_IndexToKeyRange(m', k_index as int).klo == newkr.khi; assert rm'[k] == AbstractifyEndPointToNodeIdentity(m.lows[right_index].id); assert KeyPlusLe(m.lows[right_index].klo, newkr.khi); assert KeyPlusLe(newkr.khi, KeyPlus(k)); KeyPlusTransitivity(m.lows[right_index].klo, newkr.khi, KeyPlus(k)); assert KeyPlusLe(m.lows[right_index].klo, KeyPlus(k)); if |m.lows| > right_index + 1 { assert KeyPlusLt(KeyPlus(k), m.lows[right_index+1].klo); assert KeyRangeContains(CDM_IndexToKeyRange(m, right_index), KeyPlus(k)); CDM_Partitioned(m, KeyPlus(k), right_index); } else if |m.lows| == right_index + 1 { assert rm'[k] == AbstractifyEndPointToNodeIdentity(m.lows[right_index].id); assert KeyPlusLe(m.lows[right_index].klo, newkr.khi); assert KeyPlusLe(newkr.khi, KeyPlus(k)); KeyPlusTransitivity(m.lows[right_index].klo, newkr.khi, KeyPlus(k));// ==> m.lows[right_index] <= k assert KeyRangeContains(CDM_IndexToKeyRange(m, right_index), KeyPlus(k)); CDM_Partitioned(m, KeyPlus(k), right_index); assert rm[k] == AbstractifyEndPointToNodeIdentity(m.lows[right_index].id); assert rm'[k] == rm[k]; } else { assert false; } } else { assert k_index > new_index + 1; UpdateCDelegationMap_RHS_Helper(m, newkr, id, m', left_index, right_index, new_left, new_right, k, new_index); } assert AbstractifyCDelegationMapToDelegationMap(m')[k] == UpdateDelegationMap(AbstractifyCDelegationMapToDelegationMap(m), newkr, AbstractifyEndPointToNodeIdentity(id))[k]; } lemma {:timeLimitMultiplier 2} UpdateCDelegationMap_Part1( m:CDelegationMap, newkr:KeyRange, id:EndPoint, m':CDelegationMap, left_index:int, right_index:int, new_left:seq, new_right:seq ) requires CDelegationMapIsValid(m); requires EndPointIsValidPublicKey(id); requires !EmptyKeyRange(newkr); requires left_index == CDM_IndexForKey(m, newkr.klo) as int; requires right_index == CDM_IndexForKey(m, newkr.khi) as int; requires m.lows[left_index].klo != newkr.klo; requires new_left == m.lows[..left_index+1]; requires new_right == if newkr.khi.KeyInf? then [] else [Mapping(newkr.khi, m.lows[right_index].id)] + m.lows[right_index+1..]; requires m' == CDelegationMap(new_left + [Mapping(newkr.klo, id)] + new_right); requires CDelegationMapIsValid(m'); ensures AbstractifyCDelegationMapToDelegationMap(m') == UpdateDelegationMap(AbstractifyCDelegationMapToDelegationMap(m), newkr, AbstractifyEndPointToNodeIdentity(id)); //ensures |m'.lows| as uint64 <= |m.lows| as uint64 + 1 { var rm := AbstractifyCDelegationMapToDelegationMap(m); var rm' := AbstractifyCDelegationMapToDelegationMap(m'); var updated_rm := UpdateDelegationMap(rm, newkr, AbstractifyEndPointToNodeIdentity(id)); forall k:Key ensures k in rm' <==> k in updated_rm; { } forall k:Key ensures rm'[k] == updated_rm[k]; { CDelegationMapIsSortedExtension(m); CDelegationMapIsSortedExtension(m'); if KeyRangeContains(newkr, KeyPlus(k)) { //var k_index := CDM_IndexForKey(m', KeyPlus(k)) as int; var index := left_index + 1; assert m'.lows[index] == Mapping(newkr.klo, id); assert KeyRangeContains(CDM_IndexToKeyRange(m', index), KeyPlus(k)); CDM_Partitioned(m', KeyPlus(k), index); assert CDM_IndexForKey(m', KeyPlus(k)) as int == index; assert rm'[k] == AbstractifyEndPointToNodeIdentity(id); } else { KeyPlusAntisymmetry(KeyPlus(k), newkr.khi); assert !KeyPlusLt(KeyPlus(k), newkr.khi) ==> KeyPlusLe(newkr.khi, KeyPlus(k)); KeyPlusAntisymmetry(newkr.klo, KeyPlus(k)); assert !KeyPlusLe(newkr.klo, KeyPlus(k)) ==> KeyPlusLt(KeyPlus(k), newkr.klo); assert KeyPlusLt(KeyPlus(k), newkr.klo) || KeyPlusLe(newkr.khi, KeyPlus(k)); // From !KeyRangeContains(newkr, k) var k_index := CDM_IndexForKey(m', KeyPlus(k)) as int; var new_index := left_index+1; // Index of the new mapping, Mapping(newkr.klo, id) assert k_index != new_index; if k_index < new_index { var kr := CDM_IndexToKeyRange(m', k_index); if k_index == left_index { assert KeyPlusLe(m.lows[left_index].klo, KeyPlus(k)); KeyPlusTransitivity(m.lows[left_index].klo, KeyPlus(k), newkr.klo); assert KeyRangeContains(CDM_IndexToKeyRange(m', left_index), KeyPlus(k)); CDM_Partitioned(m', KeyPlus(k), left_index); assert m'.lows[CDM_IndexForKey(m',KeyPlus(k))].id == m'.lows[k_index].id; assert !newkr.klo.KeyInf?; assert KeyRangeContains(CDM_IndexToKeyRange(m, left_index), newkr.klo); //assert KeyPlusLt(newkr.klo, CDM_IndexToKeyRange(m, left_index).khi); assert KeyPlusLt(newkr.klo, CDM_IndexToNextKeyBoundary(m, k_index)); KeyPlusTransitivity(KeyPlus(k), newkr.klo, CDM_IndexToNextKeyBoundary(m, k_index)); CDM_Partitioned(m, KeyPlus(k), k_index); assert rm'[k] == rm[k]; } else { assert k_index < left_index; //assert CDM_IndexToKeyRange(m, k_index) == CDM_IndexToKeyRange(m', k_index); CDM_Partitioned(m, KeyPlus(k), k_index); assert m.lows[k_index] == m'.lows[k_index]; assert m.lows[CDM_IndexForKey(m,KeyPlus(k))] == m'.lows[CDM_IndexForKey(m',KeyPlus(k))]; assert rm'[k] == rm[k]; } // assert KeyRangeContains(kr.klo, KeyPlus(k)); // CDM_Partitioned(m', KeyPlus(k), k_index); // assert CDM_IndexForKey(m', KeyPlus(k)) as int == k_index; /* assert KeyPlusLt(KeyPlus(k), newkr.klo); if |m.lows| > 1 { assert KeyPlusLt(newkr.klo, m.lows[1].klo); KeyPlusTransitivity(KeyPlus(k), newkr.klo, m.lows[1].klo); assert KeyRangeContains(CDM_IndexToKeyRange(m, 0), KeyPlus(k)); CDM_Partitioned(m, KeyPlus(k), 0); assert CDM_IndexForKey(m, KeyPlus(k)) as int == 0; } calc { rm'[k]; m.lows[0].id; rm[k]; } */ } else { assert k_index > new_index; UpdateCDelegationMap_RHS(m, newkr, id, m', left_index, right_index, new_left, new_right, k, left_index+1); } assert rm'[k] == rm[k]; calc { rm'[k]; rm[k]; updated_rm[k]; } } } lemma_UpdateCDelegationMap_Part2_Helper(m, m', newkr, id); } // After the update, every key in newkr should point at id // TODO: Need to convert ok check into an invariant that we don't grow too large! method {:induction false} {:timeLimitMultiplier 4} UpdateCDelegationMap(m:CDelegationMap, newkr:KeyRange, id:EndPoint) returns (ok:bool, m':CDelegationMap) requires CDelegationMapIsValid(m); requires EndPointIsValidPublicKey(id); requires !EmptyKeyRange(newkr); ensures |m.lows| as uint64 < 0xFFFF_FFFF_FFFF_FFFF - 2 ==> ok == true; ensures ok ==> CDelegationMapIsValid(m'); ensures ok ==> AbstractifyCDelegationMapToDelegationMap(m') == UpdateDelegationMap(AbstractifyCDelegationMapToDelegationMap(m), newkr, AbstractifyEndPointToNodeIdentity(id)); ensures ok ==> (|m.lows| as uint64 < 0xFFFF_FFFF_FFFF_FFFF - 2) && (|m'.lows| as uint64 <= |m.lows| as uint64 + 2); { if |m.lows| as uint64 >= 0xFFFF_FFFF_FFFF_FFFF - 2 { ok := false; return; } ok := true; // !Empty implies: assert !newkr.klo.KeyInf?; assert !newkr.khi.KeyZero?; var left_index := CDM_IndexForKey(m, newkr.klo); var right_index := CDM_IndexForKey(m, newkr.khi); CDM_IndexForKey_Ordering(m); KeyPlusAntisymmetry(newkr.klo, newkr.khi); assert left_index <= right_index; var new_left := m.lows[..left_index]; if m.lows[left_index].klo != newkr.klo { // We need to keep the left_index-th mapping, since it contains the bottom of the range, before we get to newkr.klo new_left := m.lows[..left_index+1]; } var new_right; if newkr.khi.KeyInf? { // We're taking all of the keys from newkr.klo onwards new_right := []; } else { // We still need to map the portion of the range above newkr.khi but inside m.lows[right_index] new_right := [Mapping(newkr.khi, m.lows[right_index].id)] + m.lows[right_index+1..]; assert KeyPlusLt(newkr.klo, newkr.khi); if right_index as int + 1 < |m.lows| { assert KeyPlusLt(newkr.khi, m.lows[right_index+1].klo); } } m' := CDelegationMap( new_left + [Mapping(newkr.klo, id)] + new_right); CDelegationMapIsSortedExtension(m); assert {:split_here} true; forall i | 0 <= i < |m'.lows|-1 ensures KeyPlusLt(m'.lows[i].klo, m'.lows[i+1].klo); { if i < |new_left| { assert m'.lows[i] == new_left[i]; if i == |new_left| - 1 { assert m'.lows[i+1].klo == Mapping(newkr.klo, id).klo; if m.lows[left_index].klo != newkr.klo { assert KeyPlusLt(m'.lows[i].klo, m'.lows[i+1].klo); } else { assert i == left_index as int - 1; assert m'.lows[i].klo == m.lows[i].klo; assert KeyPlusLe(m.lows[i + 1].klo, newkr.klo); assert KeyPlusLt(m.lows[i].klo, m.lows[i + 1].klo); KeyPlusTransitivity(m.lows[i].klo, m.lows[i+1].klo, newkr.klo); assert KeyPlusLt(m'.lows[i].klo, Mapping(newkr.klo, id).klo); assert KeyPlusLt(m'.lows[i].klo, m'.lows[i+1].klo); } } else { assert KeyPlusLt(m'.lows[i].klo, m'.lows[i+1].klo); } } else if i == |new_left| { assert m'.lows[i].klo == newkr.klo; assert KeyPlusLt(m'.lows[i].klo, m'.lows[i+1].klo); } else { if newkr.khi.KeyInf? { } else { if i == |new_left| + 1 { assert m'.lows[i] == Mapping(newkr.khi, m.lows[right_index].id); assert m'.lows[i].klo == newkr.khi; assert m'.lows[i+1].klo == m.lows[right_index+1].klo; } else { SequenceIndexingHelper(new_left, [Mapping(newkr.klo, id)], [Mapping(newkr.khi, m.lows[right_index].id)], m.lows[right_index+1..], m'.lows, i); } } //assert KeyPlusLt(m'.lows[i].klo, m'.lows[i+1].klo); } } assert CDelegationMapIsSorted(m); assert KeyPlusLt(m.lows[|m.lows|-1].klo, KeyInf()); assert KeyPlusLt(m'.lows[|m'.lows|-1].klo, KeyInf()); assert CDelegationMapIsSorted(m'); if left_index > 0 { assert |m'.lows| > 0; assert m'.lows[0].klo == KeyZero(); //assert AbstractifyCDelegationMapToDelegationMap(m') == UpdateDelegationMap(AbstractifyCDelegationMapToDelegationMap(m), newkr, id); } else { assert m.lows[0].klo == KeyZero(); if newkr.klo != KeyZero() { assert new_left == m.lows[..1]; assert m'.lows[0].klo == m.lows[0].klo; } else { assert m'.lows[0].klo == newkr.klo; } assert m'.lows[0].klo == KeyZero(); //assert AbstractifyCDelegationMapToDelegationMap(m') == UpdateDelegationMap(AbstractifyCDelegationMapToDelegationMap(m), newkr, id); } if m.lows[left_index].klo != newkr.klo { UpdateCDelegationMap_Part1(m, newkr, id, m', left_index as int, right_index as int, new_left, new_right); } else { UpdateCDelegationMap_Part2(m, newkr, id, m', left_index as int, right_index as int, new_left, new_right); } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/SHT/HostModel.i.dfy ================================================ include "HostState.i.dfy" include "SingleDeliveryModel.i.dfy" include "PacketParsing.i.dfy" include "DelegationLookup.i.dfy" module SHT__HostModel_i { import opened Native__NativeTypes_s import opened Native__Io_s import opened SHT__HostState_i import opened SHT__SingleDeliveryModel_i import opened SHT__PacketParsing_i import opened DelegationLookup_i import opened Environment_s import opened SHT__Host_i import opened SHT__SingleDeliveryState_i import opened Impl__Delegations_i import opened SHT__ConstantsState_i import opened SHT__HT_s import opened Logic__Option_i import opened AbstractServiceSHT_s`All import opened SHT__CMessage_i import opened Common__NetClient_i import opened AppInterface_i`Spec import opened Common__NodeIdentity_i import opened Impl_Parameters_i import opened SHT__Keys_i import opened SHT__Network_i import opened SHT__Delegations_i import opened SHT__Message_i import opened SHT__SingleMessage_i import opened SHT__SingleDelivery_i function method mapremove(m:map, k:KT) : map { map ki | ki in m && ki != k :: m[ki] } function method mapdomain(m:map) : set { set k | k in m :: k } function method BulkUpdateDomain(h:Hashtable, kr:KeyRange, u:Hashtable) : set { set k | k in mapdomain(h)+mapdomain(u) && (KeyRangeContains(kr, KeyPlus(k)) ==> k in u) } function method BulkUpdateHashtable(h:Hashtable, kr:KeyRange, u:Hashtable) : Hashtable { map k {:auto_trigger} | k in BulkUpdateDomain(h, kr, u) :: if (k in u) then u[k] else h[k] } function method BulkRemoveHashtable(h:Hashtable, kr:KeyRange) : Hashtable { map k | (k in h && !KeyRangeContains(kr, KeyPlus(k))) :: h[k] } function method ExtractRange(h:Hashtable, kr:KeyRange) : Hashtable requires ValidKeyRange(kr); requires forall k :: k in h ==> ValidKey(k) && ValidValue(h[k]); ensures forall k :: k in ExtractRange(h, kr) ==> k in h && ExtractRange(h, kr)[k] == h[k]; ensures (forall k :: k in ExtractRange(h, kr) ==> ValidKey(k) && ValidValue(ExtractRange(h, kr)[k])) //ensures ValidHashtable(ExtractRange(h, kr)); { map k | (k in h && KeyRangeContains(kr, KeyPlus(k))) :: h[k] } method InitHostState(constants:ConstantsState, me:EndPoint) returns (host:HostState) requires ConstantsStateIsValid(constants); requires EndPointIsAbstractable(me); ensures InitHostStatePostconditions(constants, host); ensures host.me == me; ensures host.constants == constants; { var sd := CSingleDeliveryAcctInit(constants.params); var delegationMap := CDelegationMap([Mapping(KeyZero(), constants.rootIdentity)]); //host := HostState(constants, me, delegationMap, map[], sd, None(), |delegationMap.lows| as uint64); host := HostState(constants, me, delegationMap, map[], sd, None(), |delegationMap.lows| as uint64, []); assert AbstractifyCDelegationMapToDelegationMap(delegationMap) == DelegationMap_Init(AbstractifyEndPointToNodeIdentity(constants.rootIdentity)); assert Host_Init(AbstractifyHostStateToHost(host), AbstractifyEndPointToNodeIdentity(me), AbstractifyEndPointToNodeIdentity(constants.rootIdentity), AbstractifyEndPointsToNodeIdentities(constants.hostIds), AbstractifyCParametersToParameters(constants.params)); } // TODO: move this method to Delegations.i.dfy once it stabilizes method DelegateForKeyImpl(m:CDelegationMap, k:Key) returns (ep:EndPoint) requires 0<|m.lows|; requires CDelegationMapIsValid(m); ensures EndPointIsValidPublicKey(ep); ensures AbstractifyCDelegationMapToDelegationMap(m)[k] == AbstractifyEndPointToNodeIdentity(ep); ensures AbstractifyEndPointToNodeIdentity(ep) == DelegateForKey(AbstractifyCDelegationMapToDelegationMap(m), k); { ep := m.lows[CDM_IndexForKey(m,KeyPlus(k))].id; } method {:timeLimitMultiplier 2} HostModelNextGetRequest(host:HostState, cpacket:CPacket) returns (host':HostState, sent_packets:seq) requires NextGetRequestPreconditions(host, cpacket); ensures NextGetRequestPostconditions(host, cpacket, host', sent_packets); { var k := cpacket.msg.m.k_getrequest; var owner := DelegateForKeyImpl(host.delegationMap, k); var m; ghost var receivedRequest := AppGetRequest(cpacket.msg.seqno as int, k); ghost var newReceivedRequests:seq; if (owner == host.me) { m := CReply(k, HashtableLookup(host.h, k)); newReceivedRequests := host.receivedRequests + [receivedRequest]; } else { m := CRedirect(k, owner); newReceivedRequests := host.receivedRequests; } assert MessageMarshallable(m); var sd', sm, shouldSend := SendSingleCMessage(host.sd, m, cpacket.src, host.constants.params); host' := host.(sd := sd', receivedPacket := None); var p := CPacket(cpacket.src, host.me, sm); if shouldSend { host' := host.(sd := sd', receivedPacket := None, receivedRequests := newReceivedRequests); sent_packets := [p]; } else { host' := host.(receivedPacket := None); sent_packets := []; } ghost var s := AbstractifyHostStateToHost(host); ghost var s' := AbstractifyHostStateToHost(host'); ghost var g_m := AbstractifyCMessageToRslMessage(m); ghost var g_sm := AbstractifyCSingleMessageToSingleMessage(sm); ghost var g_src := AbstractifyEndPointToNodeIdentity(cpacket.src); ghost var g_out := AbstractifySeqOfCPacketsToSetOfShtPackets(sent_packets); lemma_AbstractifyEndPointToNodeIdentity_injective_forall(); reveal_AbstractifySeqOfCPacketsToSetOfShtPackets(); assert AbstractifyCPacketToShtPacket(p) == Packet(g_src, s.me, g_sm); // OBSERVE assert NextGetRequest_Reply(s, s', g_src, cpacket.msg.seqno as int, cpacket.msg.m.k_getrequest, g_sm, g_m, g_out, shouldSend); } method {:timeLimitMultiplier 2} HostModelNextSetRequest(host:HostState, cpacket:CPacket) returns (host':HostState, sent_packets:seq) requires NextSetRequestPreconditions(host, cpacket); ensures NextSetRequestPostconditions(host, cpacket, host', sent_packets); { var k := cpacket.msg.m.k_setrequest; var ov := cpacket.msg.m.v_setrequest; var owner := DelegateForKeyImpl(host.delegationMap, k); var m; var h'; var marshallable := IsMessageMarshallable(cpacket.msg.m); if !marshallable { assert !ValidKey(k) || !ValidOptionalValue(ov); host' := host.(receivedPacket := None); sent_packets := []; ghost var s := AbstractifyHostStateToHost(host); ghost var s' := AbstractifyHostStateToHost(host'); reveal_AbstractifySeqOfCPacketsToSetOfShtPackets(); assert AbstractifySeqOfCPacketsToSetOfShtPackets(sent_packets) == {}; assert NextSetRequest_Complete(s, s', AbstractifyCPacketToShtPacket(cpacket).src, AbstractifyCPacketToShtPacket(cpacket).msg.seqno, AbstractifyCPacketToShtPacket(cpacket).msg.m, Ack(0), Reply(k, ov), {}, true); // ^ ^ // Because we're in the else clause of SetRequest_Complete | | // these arguments don't matter ------------------------------------------ return; } if (owner == host.me) { /*if ov.ValueAbsent? { h' := mapremove(host.h, k); } else { h' := host.h[k:=ov.v]; }*/ m := CReply(k, ov); } else { //h' := host.h; m := CRedirect(k, owner); } var sd', sm, shouldSend := SendSingleCMessage(host.sd, m, cpacket.src, host.constants.params); ghost var receivedRequest := AppSetRequest(cpacket.msg.seqno as int, k, ov); ghost var newReceivedRequests:seq; if (shouldSend) { if (owner == host.me) { if ov.ValueAbsent? { h' := mapremove(host.h, k); } else { h' := host.h[k:=ov.v]; } newReceivedRequests := host.receivedRequests + [receivedRequest]; } else { h' := host.h; newReceivedRequests := host.receivedRequests; } host' := host.(h := h', sd := sd', receivedPacket := None, receivedRequests := newReceivedRequests); } else { host' := host.(receivedPacket := None); } var p := CPacket(cpacket.src, host.me, sm); if shouldSend { sent_packets := [p]; } else { sent_packets := []; } ghost var s := AbstractifyHostStateToHost(host); ghost var s' := AbstractifyHostStateToHost(host'); ghost var g_m := AbstractifyCMessageToRslMessage(m); ghost var g_sm := AbstractifyCSingleMessageToSingleMessage(sm); ghost var g_src := AbstractifyEndPointToNodeIdentity(cpacket.src); ghost var g_seqno := cpacket.msg.seqno as int; ghost var g_out := AbstractifySeqOfCPacketsToSetOfShtPackets(sent_packets); lemma_AbstractifyEndPointToNodeIdentity_injective_forall(); reveal_AbstractifySeqOfCPacketsToSetOfShtPackets(); assert AbstractifyCPacketToShtPacket(p) == Packet(g_src, s.me, g_sm); // OBSERVE assert NextSetRequest_Complete(s, s', g_src, g_seqno, AbstractifyCMessageToRslMessage(cpacket.msg.m), g_sm, g_m, g_out, shouldSend); } predicate HostIgnoringUnParseable(host:Host, host':Host, packets:set) { packets == {} && host' == host.(receivedPacket := None) && host.receivedPacket.Some? && host.receivedPacket.v.msg.SingleMessage? && host.receivedPacket.v.msg.m.Delegate? && var msg := host.receivedPacket.v.msg.m; !(ValidKeyRange(msg.range) && ValidHashtable(msg.h) && !EmptyKeyRange(msg.range) && ValidPhysicalAddress(host.receivedPacket.v.msg.dst)) } method {:timeLimitMultiplier 4} HostModelNextDelegate(host:HostState, cpacket:CPacket) returns (host':HostState, sent_packets:seq) requires NextDelegatePreconditions(host, cpacket); requires CSingleMessageIs64Bit(cpacket.msg); requires host.receivedPacket.Some? && host.receivedPacket.v == cpacket; requires host.numDelegations < host.constants.params.max_delegations - 2; ensures NextDelegatePostconditions(host, cpacket, host', sent_packets); ensures NextDelegate(AbstractifyHostStateToHost(host), AbstractifyHostStateToHost(host'), AbstractifyCPacketToShtPacket(cpacket), AbstractifySeqOfCPacketsToSetOfShtPackets(sent_packets)) || HostIgnoringUnParseable(AbstractifyHostStateToHost(host), AbstractifyHostStateToHost(host'), AbstractifySeqOfCPacketsToSetOfShtPackets(sent_packets)); { sent_packets := []; reveal_AbstractifySeqOfCPacketsToSetOfShtPackets(); var marshallable := IsCSingleMessageMarshallable(cpacket.msg); if !marshallable { host' := host.(receivedPacket := None); assert HostIgnoringUnParseable(AbstractifyHostStateToHost(host), AbstractifyHostStateToHost(host'), AbstractifySeqOfCPacketsToSetOfShtPackets(sent_packets)); return; } if cpacket.src in host.constants.hostIds { var ok, delegationMap' := UpdateCDelegationMap(host.delegationMap, cpacket.msg.m.range, host.me); var h' := BulkUpdateHashtable(host.h, cpacket.msg.m.range, cpacket.msg.m.h); host' := host.(h := h', delegationMap := delegationMap', receivedPacket := None, numDelegations := host.numDelegations + 1); } else { host' := host.(receivedPacket := None); } lemma_AbstractifyEndPointToNodeIdentity_injective_forall(); //reveal_AbstractifySeqOfCPacketsToSetOfShtPackets(); } method {:timeLimitMultiplier 4} HostModelNextShard(host:HostState, cpacket:CPacket) returns (host':HostState, sent_packets:seq) requires NextShardPreconditions(host, cpacket); requires host.numDelegations < host.constants.params.max_delegations - 2; ensures NextShardPostconditions(host, cpacket, host', sent_packets); { var recipient := cpacket.msg.m.recipient; var kr := cpacket.msg.m.kr; sent_packets := []; host' := host.(receivedPacket := None); lemma_AbstractifyEndPointToNodeIdentity_injective_forall(); reveal_AbstractifySeqOfCPacketsToSetOfShtPackets(); var marshallable := IsMessageMarshallable(cpacket.msg.m); if (!marshallable || cpacket.msg.m.recipient == host.me || cpacket.msg.m.recipient !in host.constants.hostIds) { assert EndPointIsAbstractable(cpacket.msg.m.recipient); return; } var b:= DelegateForKeyRangeIsHostImpl(host.delegationMap, cpacket.msg.m.kr, host.me); if (!b) { assert !DelegateForKeyRangeIsHost(AbstractifyCDelegationMapToDelegationMap(host.delegationMap), cpacket.msg.m.kr, AbstractifyEndPointToNodeIdentity(host.me)); return; } var h := ExtractRange(host.h, cpacket.msg.m.kr); if (|h| >= 62) { // max_hashtable_size() return; } var m := CDelegate(kr, ExtractRange(host.h, kr)); var sd', sm, shouldSend := SendSingleCMessage(host.sd, m, recipient, host.constants.params); var p; if shouldSend { var ok, delegationMap' := UpdateCDelegationMap(host.delegationMap, kr, recipient); var h' := BulkRemoveHashtable(host.h, kr); host' := host.(h := h', delegationMap := delegationMap', sd := sd', receivedPacket := None, numDelegations := host.numDelegations + 1); p := CPacket(recipient, host.me, sm); sent_packets := [p]; } else { host' := host.(receivedPacket := None, numDelegations := host.numDelegations + 1); sent_packets := []; } ghost var s := AbstractifyHostStateToHost(host); ghost var s' := AbstractifyHostStateToHost(host'); ghost var g_sm := AbstractifyCSingleMessageToSingleMessage(sm); ghost var g_out := AbstractifySeqOfCPacketsToSetOfShtPackets(sent_packets); ghost var g_pkt := AbstractifyCPacketToShtPacket(cpacket); if shouldSend { assert AbstractifyCPacketToShtPacket(p) == Packet(AbstractifyEndPointToNodeIdentity(recipient), s.me, g_sm); // OBSERVE //assert g_out == { Packet(recipient, s.me, sm) } } assert NextShard(s, s', g_out, g_pkt.msg.m.kr, g_pkt.msg.m.recipient, g_sm, shouldSend); } method {:timeLimitMultiplier 2} HostModelNextReceiveMessage(host:HostState, cpacket:CPacket) returns (host':HostState, sent_packets:seq) requires cpacket.msg.CSingleMessage?; requires CSingleDeliveryAccountIsValid(host.sd, host.constants.params) requires CPacketIsAbstractable(cpacket); requires CSingleMessageIs64Bit(cpacket.msg); requires host.receivedPacket.Some? && host.receivedPacket.v == cpacket; requires HostState_common_preconditions(host, cpacket); requires cpacket.msg.m.CGetRequest? ==> NextGetRequestPreconditions(host, cpacket); requires cpacket.msg.m.CSetRequest? ==> NextSetRequestPreconditions(host, cpacket) requires cpacket.msg.m.CDelegate? ==> NextDelegatePreconditions(host, cpacket) && (host.numDelegations < host.constants.params.max_delegations - 2); requires cpacket.msg.m.CShard? ==> NextShardPreconditions(host, cpacket) && (host.numDelegations < host.constants.params.max_delegations - 2); ensures HostStateIsAbstractable(host'); ensures CPacketSeqIsAbstractable(sent_packets); ensures HostState_common_postconditions(host, cpacket, host', sent_packets) ensures Process_Message(AbstractifyHostStateToHost(host), AbstractifyHostStateToHost(host'), AbstractifySeqOfCPacketsToSetOfShtPackets(sent_packets)) || HostIgnoringUnParseable(AbstractifyHostStateToHost(host), AbstractifyHostStateToHost(host'), AbstractifySeqOfCPacketsToSetOfShtPackets(sent_packets)); ensures AbstractifySeqOfCPacketsToSetOfShtPackets(sent_packets) == ExtractPacketsFromLSHTPackets(AbstractifyOutboundPacketsToSeqOfLSHTPackets(sent_packets)); ensures host'.receivedPacket.None? { if (cpacket.msg.CInvalidMessage?) { host' := host; sent_packets := []; } else if (cpacket.msg.m.CGetRequest?) { host', sent_packets := HostModelNextGetRequest(host, cpacket); assert NextGetRequest(AbstractifyHostStateToHost(host), AbstractifyHostStateToHost(host'), AbstractifyCPacketToShtPacket(cpacket), AbstractifySeqOfCPacketsToSetOfShtPackets(sent_packets)); } else if (cpacket.msg.m.CSetRequest?) { host', sent_packets := HostModelNextSetRequest(host, cpacket); } else if (cpacket.msg.m.CDelegate?) { host', sent_packets := HostModelNextDelegate(host, cpacket); } else if (cpacket.msg.m.CShard?) { host', sent_packets := HostModelNextShard(host, cpacket); } else if (cpacket.msg.m.CReply? || cpacket.msg.m.CRedirect?) { host' := host.(receivedPacket := None); sent_packets := []; assert |sent_packets| == 0; reveal_AbstractifySeqOfCPacketsToSetOfShtPackets(); assert |AbstractifySeqOfCPacketsToSetOfShtPackets(sent_packets)| == |sent_packets|; assert AbstractifySeqOfCPacketsToSetOfShtPackets(sent_packets) == {}; } else { assert false; } } method ShouldProcessReceivedMessageImpl(s:HostState) returns (b:bool) requires HostStateIsValid(s) ensures b == ShouldProcessReceivedMessage(AbstractifyHostStateToHost(s)) { if ( s.receivedPacket.Some? && s.receivedPacket.v.msg.CSingleMessage? && ((s.receivedPacket.v.msg.m.CDelegate? || s.receivedPacket.v.msg.m.CShard?) ==> s.numDelegations < s.constants.params.max_delegations - 2)) { b := true; } else { b := false; } } method HostModelReceivePacket(host:HostState, cpacket:CPacket) returns (host':HostState, sent_packets:seq, ack:CPacket) requires HostStateIsValid(host) requires CSingleDeliveryAccountIsValid(host.sd, host.constants.params) requires CPacketIsAbstractable(cpacket) && CSingleMessageIs64Bit(cpacket.msg) && !cpacket.msg.CInvalidMessage?; // CSingleMessageMarshallable(pkt.msg); requires !cpacket.msg.CInvalidMessage?; requires HostState_common_preconditions(host, cpacket); requires cpacket.dst == host.me; ensures HostStateIsValid(host'); ensures HostStateIsValid(host') && OutboundPacketsSeqIsValid(sent_packets) ensures CPacketIsAbstractable(ack); ensures ReceivePacket(AbstractifyHostStateToHost(host), AbstractifyHostStateToHost(host'), AbstractifyCPacketToShtPacket(cpacket), AbstractifySeqOfCPacketsToSetOfShtPackets(sent_packets), AbstractifyCPacketToShtPacket(ack)) ensures OutboundPacketsSeqIsValid(sent_packets); ensures HostState_common_postconditions(host, cpacket, host', sent_packets); ensures |sent_packets| >= 1 ==> sent_packets == [ack]; ensures sent_packets == [] ==> ack == cpacket; { sent_packets := []; reveal_AbstractifySeqOfCPacketsToSetOfShtPackets(); if (host.receivedPacket.None?) { var b, sd'; b, sd', ack := ReceiveSingleMessageImpl(host.sd, cpacket, host.constants.params); if (b) { var b' := NewSingleMessageImpl(host.sd, cpacket, host.constants.params); sent_packets := [ack]; if (b') { host' := host.(receivedPacket := Some(cpacket), sd := sd'); } else { host' := host.(receivedPacket := None, sd := sd'); } } else { host' := host.(sd := sd'); ack := cpacket; sent_packets := []; } } else { host' := host; ack := cpacket; } } method {:timeLimitMultiplier 2} HostModelSpontaneouslyRetransmit(host:HostState) returns (host':HostState, sent_packets:seq) requires SpontaneouslyRetransmitPreconditions(host); ensures SpontaneouslyRetransmitPostconditions(host, host', sent_packets); ensures UnAckedMessages(AbstractifyHostStateToHost(host).sd, AbstractifyHostStateToHost(host).me) == ExtractPacketsFromLSHTPackets(AbstractifyOutboundPacketsToSeqOfLSHTPackets(sent_packets)); { host' := host; sent_packets := RetransmitUnAckedPackets(host.sd, host.me, host.constants.params); assert AbstractifySeqOfCPacketsToSetOfShtPackets(sent_packets) == UnAckedMessages(AbstractifyHostStateToHost(host).sd, AbstractifyHostStateToHost(host).me); reveal_AbstractifySeqOfCPacketsToSetOfShtPackets(); assert forall p :: p in sent_packets ==> AbstractifyCPacketToShtPacket(p) in AbstractifySeqOfCPacketsToSetOfShtPackets(sent_packets); assert forall p :: p in sent_packets ==> AbstractifyCPacketToShtPacket(p) in ExtractPacketsFromLSHTPackets(AbstractifyOutboundPacketsToSeqOfLSHTPackets(sent_packets)); ghost var sent_packets' := AbstractifyOutboundPacketsToSeqOfLSHTPackets(sent_packets); lemma_AbstractifyEndPointToNodeIdentity_injective_forall(); assert forall p :: p in sent_packets ==> CPacketIsAbstractable(p) && EndPointIsAbstractable(p.dst) && EndPointIsAbstractable(p.src); assert forall p :: p in sent_packets ==> LPacket(AbstractifyEndPointToNodeIdentity(p.dst), AbstractifyEndPointToNodeIdentity(p.src), AbstractifyCSingleMessageToSingleMessage(p.msg)) in sent_packets'; assert forall p':: p' in sent_packets' ==> exists p :: p in sent_packets && LPacket(AbstractifyEndPointToNodeIdentity(p.dst), AbstractifyEndPointToNodeIdentity(p.src), AbstractifyCSingleMessageToSingleMessage(p.msg)) == p'; assert AbstractifySeqOfCPacketsToSetOfShtPackets(sent_packets) == ExtractPacketsFromLSHTPackets(sent_packets'); assert UnAckedMessages(AbstractifyHostStateToHost(host).sd, AbstractifyHostStateToHost(host).me) == ExtractPacketsFromLSHTPackets(AbstractifyOutboundPacketsToSeqOfLSHTPackets(sent_packets)); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/SHT/HostState.i.dfy ================================================ include "../../Protocol/SHT/Host.i.dfy" include "Delegations.i.dfy" include "SingleDeliveryState.i.dfy" include "ConstantsState.i.dfy" include "PacketParsing.i.dfy" include "../../Common/Logic/Option.i.dfy" module SHT__HostState_i { import opened Native__NativeTypes_s import opened Native__Io_s import opened SHT__Host_i import opened SHT__SingleDeliveryState_i import opened Impl__Delegations_i import opened SHT__ConstantsState_i import opened SHT__PacketParsing_i import opened SHT__HT_s import opened Logic__Option_i import opened AbstractServiceSHT_s`All import opened SHT__CMessage_i import opened Common__NetClient_i import opened AppInterface_i`Spec import opened Common__NodeIdentity_i import opened Impl_Parameters_i datatype HostState = HostState( constants:ConstantsState, me:EndPoint, delegationMap:CDelegationMap, h:Hashtable, sd:CSingleDeliveryAcct, receivedPacket:Option, numDelegations:uint64, ghost receivedRequests:seq ) predicate HostStateIsAbstractable(host:HostState) { ConstantsStateIsAbstractable(host.constants) && EndPointIsAbstractable(host.me) && CDelegationMapIsAbstractable(host.delegationMap) && true // hashtable goes straight across && CSingleDeliveryAcctIsAbstractable(host.sd) && OptionCPacketIsAbstractable(host.receivedPacket) } function AbstractifyHostStateToHost(host:HostState) : Host requires HostStateIsAbstractable(host) { Host(AbstractifyToConstants(host.constants), AbstractifyEndPointToNodeIdentity(host.me), AbstractifyCDelegationMapToDelegationMap(host.delegationMap), host.h, AbstractifyCSingleDeliveryAcctToSingleDeliveryAcct(host.sd), AbstractifyOptionCPacketToOptionShtPacket(host.receivedPacket), host.numDelegations as int, host.receivedRequests) } predicate HostStateIsValid(host:HostState) { HostStateIsAbstractable(host) && CDelegationMapIsValid(host.delegationMap) && (forall k :: k in host.h ==> ValidKey(k)) && (forall k :: k in host.h ==> ValidValue(host.h[k])) && CSingleDeliveryAccountIsValid(host.sd, host.constants.params) && (host.receivedPacket.Some? ==> CPacketIsAbstractable(host.receivedPacket.v) && host.receivedPacket.v.msg.CSingleMessage? && !host.receivedPacket.v.msg.CInvalidMessage? && CSingleMessageIs64Bit(host.receivedPacket.v.msg) && host.receivedPacket.v.dst == host.me) && ConstantsStateIsValid(host.constants) && host.numDelegations < host.constants.params.max_delegations && |host.delegationMap.lows| <= 2 * host.numDelegations as int && (host.receivedPacket.Some? ==> ValidPhysicalAddress(host.receivedPacket.v.src)) } predicate InitHostStatePostconditions(constants:ConstantsState, host:HostState) { ConstantsStateIsAbstractable(constants) && HostStateIsAbstractable(host) && Host_Init(AbstractifyHostStateToHost(host), AbstractifyEndPointToNodeIdentity(host.me), AbstractifyEndPointToNodeIdentity(constants.rootIdentity), AbstractifyEndPointsToNodeIdentities(constants.hostIds), AbstractifyCParametersToParameters(constants.params)) && host.constants == constants && CSingleDeliveryAccountIsValid(host.sd, host.constants.params) && HostStateIsValid(host) } predicate HostState_common_preconditions(host:HostState, cpacket:CPacket) { HostStateIsAbstractable(host) && CPacketIsAbstractable(cpacket) && HostStateIsValid(host) && ValidPhysicalAddress(cpacket.src) } predicate HostState_common_postconditions(host:HostState, cpacket:CPacket, host':HostState, sent_packets:seq) { HostState_common_preconditions(host, cpacket) && HostStateIsAbstractable(host') && host'.constants == host.constants && host'.me == host.me && CPacketSeqIsAbstractable(sent_packets) && HostStateIsValid(host') && OutboundPacketsSeqIsValid(sent_packets) && OutboundPacketsSeqHasCorrectSrc(sent_packets, host.me) && (forall p :: p in sent_packets ==> p.msg.CSingleMessage? || p.msg.CAck?) && AbstractifySeqOfCPacketsToSetOfShtPackets(sent_packets) == ExtractPacketsFromLSHTPackets(AbstractifyOutboundPacketsToSeqOfLSHTPackets(sent_packets)) } predicate NextGetRequestPreconditions(host:HostState, cpacket:CPacket) { HostStateIsAbstractable(host) && CPacketIsAbstractable(cpacket) && cpacket.msg.CSingleMessage? && cpacket.msg.m.CGetRequest? && EndPointIsValidPublicKey(cpacket.src) //&& ValidKey(cpacket.msg.m.k_getrequest) //&& CSingleMessageMarshallable(cpacket.msg) && CSingleDeliveryAccountIsValid(host.sd, host.constants.params) && HostState_common_preconditions(host, cpacket) } predicate NextGetRequestPostconditions(host:HostState, cpacket:CPacket, host':HostState, sent_packets:seq) { NextGetRequestPreconditions(host, cpacket) && HostStateIsAbstractable(host') && CPacketSeqIsAbstractable(sent_packets) && NextGetRequest(AbstractifyHostStateToHost(host), AbstractifyHostStateToHost(host'), AbstractifyCPacketToShtPacket(cpacket), AbstractifySeqOfCPacketsToSetOfShtPackets(sent_packets)) && HostState_common_postconditions(host, cpacket, host', sent_packets) && host'.receivedPacket == None } predicate NextSetRequestPreconditions(host:HostState, cpacket:CPacket) { HostStateIsAbstractable(host) && CPacketIsAbstractable(cpacket) && cpacket.msg.CSingleMessage? && cpacket.msg.m.CSetRequest? && CSingleDeliveryAccountIsValid(host.sd, host.constants.params) //&& ValidKey(cpacket.msg.m.k_setrequest) //&& ValidOptionalValue(cpacket.msg.m.v_setrequest) //&& CSingleMessageMarshallable(cpacket.msg) && HostState_common_preconditions(host, cpacket) } predicate NextSetRequestPostconditions(host:HostState, cpacket:CPacket, host':HostState, sent_packets:seq) { NextSetRequestPreconditions(host, cpacket) && HostStateIsAbstractable(host') && CPacketSeqIsAbstractable(sent_packets) && NextSetRequest(AbstractifyHostStateToHost(host), AbstractifyHostStateToHost(host'), AbstractifyCPacketToShtPacket(cpacket), AbstractifySeqOfCPacketsToSetOfShtPackets(sent_packets)) && HostState_common_postconditions(host, cpacket, host', sent_packets) && host'.receivedPacket == None } predicate NextDelegatePreconditions(host:HostState, cpacket:CPacket) { HostStateIsAbstractable(host) && CPacketIsAbstractable(cpacket) && cpacket.msg.CSingleMessage? && cpacket.msg.m.CDelegate? && CSingleDeliveryAccountIsValid(host.sd, host.constants.params) //&& |host.delegationMap.lows| < 0xFFFF_FFFF_FFFF_FFFF - 2 //&& !EmptyKeyRange(cpacket.msg.m.range) /*&& ValidKeyRange(cpacket.msg.m.range) && (forall k :: k in cpacket.msg.m.h ==> ValidKey(k)) && (forall k :: k in cpacket.msg.m.h ==> ValidValue(cpacket.msg.m.h[k]))*/ //&& CSingleMessageMarshallable(cpacket.msg) && HostState_common_preconditions(host, cpacket) && ValidPhysicalAddress(host.me) //&& host.numDelegations < host.constants.params.max_delegations - 2 } predicate NextDelegatePostconditions(host:HostState, cpacket:CPacket, host':HostState, sent_packets:seq) { NextDelegatePreconditions(host, cpacket) && HostStateIsAbstractable(host') && CPacketSeqIsAbstractable(sent_packets) && HostState_common_postconditions(host, cpacket, host', sent_packets) && host'.receivedPacket == None } predicate NextShardPreconditions(host:HostState, cpacket:CPacket) { HostStateIsAbstractable(host) && CPacketIsAbstractable(cpacket) && HostState_common_preconditions(host, cpacket) && cpacket.msg.CSingleMessage? && cpacket.msg.m.CShard? && CSingleDeliveryAccountIsValid(host.sd, host.constants.params) //&& cpacket.msg.m.recipient != host.constants.me //&& cpacket.msg.m.recipient in host.constants.hostIds //&& DelegateForKeyRangeIsHost(AbstractifyCDelegationMapToDelegationMap(host.delegationMap), cpacket.msg.m.kr, AbstractifyEndPointToNodeIdentity(host.constants.me)) && |host.delegationMap.lows| < 0xFFFF_FFFF_FFFF_FFFF - 2 //&& !EmptyKeyRange(cpacket.msg.m.kr) /*&& ValidKeyRange(cpacket.msg.m.kr)*/ //&& |ExtractRange(host.h, cpacket.msg.m.kr)| < 0x1_0000_0000 //&& CSingleMessageMarshallable(cpacket.msg) && HostState_common_preconditions(host, cpacket) //&& host.numDelegations < host.constants.params.max_delegations - 2 } predicate NextShardPostconditions(host:HostState, cpacket:CPacket, host':HostState, sent_packets:seq) { NextShardPreconditions(host, cpacket) && HostStateIsAbstractable(host') && CPacketSeqIsAbstractable(sent_packets) && NextShard_Wrapper(AbstractifyHostStateToHost(host), AbstractifyHostStateToHost(host'), AbstractifyCPacketToShtPacket(cpacket), AbstractifySeqOfCPacketsToSetOfShtPackets(sent_packets)) && HostState_common_postconditions(host, cpacket, host', sent_packets) && host'.receivedPacket == None } predicate SpontaneouslyRetransmitPreconditions(host:HostState) { HostStateIsAbstractable(host) && CSingleDeliveryAccountIsValid(host.sd, host.constants.params) && HostStateIsValid(host) } predicate SpontaneouslyRetransmitPostconditions(host:HostState, host':HostState, sent_packets:seq) { SpontaneouslyRetransmitPreconditions(host) && host' == host && HostStateIsAbstractable(host') && CPacketSeqIsAbstractable(sent_packets) && SpontaneouslyRetransmit(AbstractifyHostStateToHost(host), AbstractifyHostStateToHost(host'), AbstractifySeqOfCPacketsToSetOfShtPackets(sent_packets)) && (forall i :: 0 <= i < |sent_packets| ==> CPacketIsSendable(sent_packets[i]) && sent_packets[i].msg.CSingleMessage? && CSingleMessageMarshallable(sent_packets[i].msg) && sent_packets[i].src == host.me) && (forall i :: 0 <= i < |sent_packets| ==> sent_packets[i].src == host.me) && HostStateIsValid(host') } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/SHT/PacketParsing.i.dfy ================================================ include "CMessage.i.dfy" include "AppInterfaceConcrete.i.dfy" include "../Common/NodeIdentity.i.dfy" include "../Common/GenericMarshalling.i.dfy" include "../../Protocol/LiveSHT/RefinementProof/Environment.i.dfy" include "../../Protocol/SHT/Host.i.dfy" module {:fuel ValInGrammar,4} SHT__PacketParsing_i { import opened Native__NativeTypes_s import opened Native__Io_s import opened Collections__Maps_i import opened Math__mul_i import opened Environment_s import opened Impl__AppInterfaceConcrete_i`Spec import opened Common__GenericMarshalling_i import opened Common__NodeIdentity_i import opened LiveSHT__Environment_i import opened SHT__HT_s import opened SHT__Keys_i import opened SHT__CMessage_i import opened SHT__Network_i import opened SHT__Host_i import opened Impl_Parameters_i import opened AppInterface_i`All import opened Common__NetClient_i //////////////////////////////////////////////////////////////////// // Grammars for the basic types //////////////////////////////////////////////////////////////////// function method OptionalValue_grammar() : G { GTaggedUnion([Value_grammar(), GTuple([])]) } function method KeyPlus_grammar() : G { GTaggedUnion([Key_grammar(), GUint64]) } function method KeyRange_grammar() : G { GTuple([KeyPlus_grammar(), KeyPlus_grammar()]) } function method Hashtable_grammar() : G { GArray(GTuple([Key_grammar(), Value_grammar()])) } function method EndPoint_grammar() : G { GByteArray } //////////////////////////////////////////////////////////////////// // Grammars for the SHT messages //////////////////////////////////////////////////////////////////// function method CMessage_GetRequest_grammar() : G { Key_grammar() } function method CMessage_SetRequest_grammar() : G { GTuple([Key_grammar(), OptionalValue_grammar()]) } function method CMessage_Reply_grammar() : G { GTuple([Key_grammar(), OptionalValue_grammar()]) } function method CMessage_Redirect_grammar() : G { GTuple([Key_grammar(), EndPoint_grammar()]) } function method CMessage_Shard_grammar() : G { GTuple([KeyRange_grammar(), EndPoint_grammar()]) } function method CMessage_Delegate_grammar() : G { GTuple([KeyRange_grammar(), Hashtable_grammar()]) } function method CMessage_grammar() : G { GTaggedUnion([ CMessage_GetRequest_grammar(), CMessage_SetRequest_grammar(), CMessage_Reply_grammar(), CMessage_Redirect_grammar(), CMessage_Shard_grammar(), CMessage_Delegate_grammar() ]) } function method CSingleMessage_grammar() : G { GTaggedUnion( [ GTuple([GUint64, EndPoint_grammar(), CMessage_grammar()]), // CSingleMessage GUint64]) // Ack } predicate NetPacketBound(data:seq) { |data| < MaxPacketSize() } lemma lemma_CMessageGrammarValid() ensures ValidGrammar(CMessage_grammar()); { var g := CMessage_grammar(); assert |g.cases| < 0x1_0000_0000_0000_0000; lemma_ValidKey_grammer(); lemma_ValidValue_grammer(); assert ValidGrammar(CMessage_GetRequest_grammar()); assert ValidGrammar(CMessage_SetRequest_grammar()); assert ValidGrammar(CMessage_Reply_grammar()); assert ValidGrammar(CMessage_Redirect_grammar()); assert ValidGrammar(CMessage_Shard_grammar()); assert ValidGrammar(CMessage_Delegate_grammar()); } //function {:opaque} SHTDemarshallable(data:seq) : bool //{ // |data| < 0x1_0000_0000_0000_0000 // && Demarshallable(data, CSingleMessage_grammar()) // && !parse_Val(data, CSingleMessage_grammar()).0.None? // && (var v := DemarshallFunc(data, CSingleMessage_grammar()); // CSingleMessageIsAbstractable(parse_CSingleMessage(v)) && CSingleMessageMarshallable(parse_CSingleMessage(v))) //} //////////////////////////////////////////////////////////////////// // Parsing //////////////////////////////////////////////////////////////////// function method parse_OptionalValue(val:V) : OptionalValue requires ValInGrammar(val, OptionalValue_grammar()); { if val.c == 0 then ValuePresent(parse_Value(val.val)) else ValueAbsent() } function method parse_KeyPlus(val:V) : KeyPlus requires ValInGrammar(val, KeyPlus_grammar()); { if val.c == 0 then KeyPlus(parse_Key(val.val)) else if val.c == 1 then if val.val.u == 0 then KeyZero() else KeyInf() else assert false; // Should never get here KeyInf() } function method parse_KeyRange(val:V) : KeyRange requires ValInGrammar(val, KeyRange_grammar()); { KeyRange(parse_KeyPlus(val.t[0]), parse_KeyPlus(val.t[1])) } function method parse_Hashtable(val:V) : Hashtable requires ValInGrammar(val, Hashtable_grammar()); ensures |parse_Hashtable(val)| <= |val.a|; ensures ValidVal(val) ==> HashtableIs64Bit(parse_Hashtable(val)); decreases |val.a|; { if |val.a| == 0 then map [] else var tuple := val.a[0]; assert ValInGrammar(tuple, Hashtable_grammar().elt); // OBSERVE: Still needed despite fuel boost. Odd. var key := parse_Key(tuple.t[0]); var value := parse_Value(tuple.t[1]); var others := parse_Hashtable(VArray(val.a[1..])); var m := others[key := value]; m } function method parse_EndPoint(val:V) : EndPoint requires ValInGrammar(val, EndPoint_grammar()); ensures EndPointIsAbstractable(parse_EndPoint(val)); { EndPoint(val.b) } function method parse_Message_GetRequest(val:V) : CMessage requires ValInGrammar(val, CMessage_GetRequest_grammar()); ensures CMessageIsAbstractable(parse_Message_GetRequest(val)); { CGetRequest(parse_Key(val)) } function method parse_Message_SetRequest(val:V) : CMessage requires ValInGrammar(val, CMessage_SetRequest_grammar()); ensures CMessageIsAbstractable(parse_Message_SetRequest(val)); { CSetRequest(parse_Key(val.t[0]), parse_OptionalValue(val.t[1])) } function method parse_Message_Reply(val:V) : CMessage requires ValInGrammar(val, CMessage_Reply_grammar()); ensures CMessageIsAbstractable(parse_Message_Reply(val)); { CReply(parse_Key(val.t[0]), parse_OptionalValue(val.t[1])) } function method parse_Message_Redirect(val:V) : CMessage requires ValInGrammar(val, CMessage_Redirect_grammar()); ensures CMessageIsAbstractable(parse_Message_Redirect(val)); { CRedirect(parse_Key(val.t[0]), parse_EndPoint(val.t[1])) } function method parse_Message_Shard(val:V) : CMessage requires ValInGrammar(val, CMessage_Shard_grammar()); ensures CMessageIsAbstractable(parse_Message_Shard(val)); { CShard(parse_KeyRange(val.t[0]), parse_EndPoint(val.t[1])) } function method parse_Message_Delegate(val:V) : CMessage requires ValInGrammar(val, CMessage_Delegate_grammar()); ensures CMessageIsAbstractable(parse_Message_Delegate(val)); ensures parse_Message_Delegate(val).CDelegate?; ensures ValidVal(val) ==> HashtableIs64Bit(parse_Message_Delegate(val).h); { CDelegate(parse_KeyRange(val.t[0]), parse_Hashtable(val.t[1])) } function method parse_Message(val:V) : CMessage requires ValInGrammar(val, CMessage_grammar()); ensures CMessageIsAbstractable(parse_Message(val)); ensures ValidVal(val) ==> CMessageIs64Bit(parse_Message(val)); { if val.c == 0 then parse_Message_GetRequest(val.val) else if val.c == 1 then parse_Message_SetRequest(val.val) else if val.c == 2 then parse_Message_Reply(val.val) else if val.c == 3 then parse_Message_Redirect(val.val) else if val.c == 4 then parse_Message_Shard(val.val) else if val.c == 5 then parse_Message_Delegate(val.val) else assert false; // Should never get here parse_Message_GetRequest(val.val) } function method {:fuel ValidVal,2} parse_CSingleMessage(val:V) : CSingleMessage requires ValInGrammar(val, CSingleMessage_grammar()); ensures CSingleMessageIsAbstractable(parse_CSingleMessage(val)); ensures ValidVal(val) ==> CSingleMessageIs64Bit(parse_CSingleMessage(val)); { if val.c == 0 then CSingleMessage(val.val.t[0].u, parse_EndPoint(val.val.t[1]), parse_Message(val.val.t[2])) else CAck(val.val.u) } function SHTDemarshallData(data:seq) : (result:CSingleMessage) ensures result.CSingleMessage? ==> EndPointIsValidPublicKey(result.dst) { if Demarshallable(data, CSingleMessage_grammar()) then var val := DemarshallFunc(data, CSingleMessage_grammar()); var result := parse_CSingleMessage(val); if result.CSingleMessage? && !EndPointIsValidPublicKey(result.dst) then CInvalidMessage() else result else CInvalidMessage() } method SHTDemarshallDataMethod(data:array) returns (msg:CSingleMessage) requires data.Length < 0x1_0000_0000_0000_0000; ensures CSingleMessageIs64Bit(msg); ensures if Demarshallable(data[..], CSingleMessage_grammar()) then msg == SHTDemarshallData(data[..]) else msg.CInvalidMessage?; { lemma_CSingleMessage_grammar_valid(); var success, val := Demarshall(data, CSingleMessage_grammar()); if success { assert ValInGrammar(val, CSingleMessage_grammar()); msg := parse_CSingleMessage(val); if msg.CSingleMessage? && !EndPointIsValidPublicKey(msg.dst) { msg := CInvalidMessage(); } } else { msg := CInvalidMessage(); } } /////////////////////////////////////////////////////////////////// // 64-bit Limits //////////////////////////////////////////////////////////////////// predicate HashtableIs64Bit(h:Hashtable) { |h| < 0x1_0000_0000_0000_0000 } predicate CMessageIs64Bit(m:CMessage) { m.CDelegate? ==> HashtableIs64Bit(m.h) } predicate CSingleMessageIs64Bit(msg:CSingleMessage) { msg.CSingleMessage? ==> CMessageIs64Bit(msg.m) } //////////////////////////////////////////////////////////////////// // Marshalling //////////////////////////////////////////////////////////////////// predicate ValidHashtable(h:Hashtable) { |h| < max_hashtable_size() && (forall k :: k in h ==> ValidKey(k) && ValidValue(h[k])) } predicate MessageMarshallable(msg:CMessage) { match msg case CGetRequest(k) => ValidKey(k) case CSetRequest(k, v) => ValidKey(k) && ValidOptionalValue(v) case CReply(k, v) => ValidKey(k) && ValidOptionalValue(v) case CRedirect(k, id) => ValidKey(k) && EndPointIsValidPublicKey(id) case CShard(kr, id) => ValidKeyRange(kr) && EndPointIsValidPublicKey(id) && !EmptyKeyRange(msg.kr) case CDelegate(kr, h) => ValidKeyRange(kr) && ValidHashtable(h) && !EmptyKeyRange(msg.range) } predicate CSingleMessageMarshallable(msg:CSingleMessage) { msg.CAck? || (msg.CSingleMessage? && EndPointIsValidPublicKey(msg.dst) && MessageMarshallable(msg.m)) } method IsValidKeyPlus(kp:KeyPlus) returns (b:bool) ensures b == ValidKeyPlus(kp); { if kp.KeyZero? || kp.KeyInf? { b := true; } else { b := IsKeyValid(kp.k); } } method IsValidKeyRange(kr:KeyRange) returns (b:bool) ensures b == ValidKeyRange(kr); { b := IsValidKeyPlus(kr.klo); if b { b := IsValidKeyPlus(kr.khi); } } method IsEmptyKeyRange(kr:KeyRange) returns (b:bool) ensures b == EmptyKeyRange(kr); { if kr.khi == kr.klo { b := true; } else { match kr.khi { case KeyZero => b := true; case KeyInf => b := false; case KeyPlus(k) => match kr.klo { case KeyZero => b := false; case KeyInf => b := true; case KeyPlus(k') => b := IsKeyLt(k, k'); } } } } method IsValidHashtable(h:Hashtable) returns (b:bool) requires HashtableIs64Bit(h); ensures b == ValidHashtable(h); { b := |h| as uint64 < 62; // max_hashtable_size if !b { return; } var keys := domain(h); lemma_MapSizeIsDomainSize(keys, h); while |keys| as uint64 > 0 invariant |keys| < max_hashtable_size(); invariant forall k :: k in keys ==> k in h; invariant forall k :: k in h ==> k in keys || (ValidKey(k) && ValidValue(h[k])); decreases |keys|; { var k :| k in keys; keys := keys - {k}; b := IsKeyValid(k); if !b { return; } b := IsValueValid(h[k]); if !b { return; } } } method IsMessageMarshallable(msg:CMessage) returns (b:bool) requires CMessageIs64Bit(msg); requires CMessageIsAbstractable(msg); ensures b == MessageMarshallable(msg); { match msg case CGetRequest(k) => b := IsKeyValid(k); case CSetRequest(k, v) => b := IsKeyValid(k); if b && v.ValuePresent? { b := IsValueValid(v.v); } case CReply(k, v) => b := IsKeyValid(k); if b && v.ValuePresent? { b := IsValueValid(v.v); } case CRedirect(k, id) => b := IsKeyValid(k); b := b && (|id.public_key| < 0x10_0000); case CShard(kr, id) => b := IsValidKeyRange(kr); b := b && (|id.public_key| < 0x10_0000); if b { b := IsEmptyKeyRange(kr); b := !b; } case CDelegate(kr, h) => b := IsValidKeyRange(kr); if b { b := IsValidHashtable(h); if b { b := IsEmptyKeyRange(kr); b := !b; } } } method IsCSingleMessageMarshallable(msg:CSingleMessage) returns (b:bool) requires CSingleMessageIsAbstractable(msg); requires CSingleMessageIs64Bit(msg); ensures b == CSingleMessageMarshallable(msg); { if msg.CAck? { b := true; } else if msg.CInvalidMessage? { b := false; } else { assert msg.CSingleMessage?; if !(|msg.dst.public_key| < 0x10_0000) { b := false; return; } b := IsMessageMarshallable(msg.m); } } function CMessageIsValid(msg:CMessage) : bool { MessageMarshallable(msg) } predicate CPacketIsMarshallable(cp:CPacket) { EndPointIsAbstractable(cp.src) && EndPointIsAbstractable(cp.dst) && CSingleMessageMarshallable(cp.msg) && (cp.msg.CSingleMessage? && cp.msg.m.CShard? ==> cp.msg.m.recipient != cp.dst) } predicate CPacketsIsMarshallable(cps:set) { forall cp :: cp in cps ==> CPacketIsMarshallable(cp) } method MarshallOptionalValue(c:OptionalValue) returns (val:V) requires ValidOptionalValue(c); ensures ValInGrammar(val, OptionalValue_grammar()); ensures ValidVal(val); ensures parse_OptionalValue(val) == c; ensures 0 <= SizeOfV(val) < 16 + max_val_len(); { if c.ValuePresent? { var v := MarshallValue(c.v); val := VCase(0, v); } else { reveal_SeqSum(); val := VCase(1, VTuple([])); } } method MarshallKeyPlus(c:KeyPlus) returns (val:V) requires ValidKeyPlus(c); ensures ValInGrammar(val, KeyPlus_grammar()); ensures ValidVal(val); ensures parse_KeyPlus(val) == c; ensures 0 <= SizeOfV(val) < 16 + max_key_len(); { if c.KeyPlus? { var key := MarshallKey(c.k); val := VCase(0, key); } else if c.KeyZero? { val := VCase(1, VUint64(0)); } else { val := VCase(1, VUint64(42)); } } method MarshallKeyRange(c:KeyRange) returns (val:V) requires ValidKeyRange(c); ensures ValInGrammar(val, KeyRange_grammar()); ensures ValidVal(val); ensures parse_KeyRange(val) == c; ensures 0 <= SizeOfV(val) < (16 + max_key_len()) + (16 + max_key_len()); { var klo := MarshallKeyPlus(c.klo); var khi := MarshallKeyPlus(c.khi); val := VTuple([klo, khi]); lemma_SeqSum_2(val); } // TODO: Refactor this and Paxos' version to put them in a common location lemma lemma_SeqSum_2(val:V) requires val.VTuple?; requires |val.t| == 2; ensures SizeOfV(val) == SizeOfV(val.t[0]) + SizeOfV(val.t[1]); { calc { SeqSum(val.t); { reveal_SeqSum(); } SizeOfV(val.t[0]) + SeqSum(val.t[1..]); { reveal_SeqSum(); } SizeOfV(val.t[0]) + SizeOfV(val.t[1]) + SeqSum(val.t[2..]); { assert val.t[2..] == []; } // OBSERVE SizeOfV(val.t[0]) + SizeOfV(val.t[1]) + SeqSum([]); { reveal_SeqSum(); } SizeOfV(val.t[0]) + SizeOfV(val.t[1]); } } lemma lemma_SeqSum_3(val:V) requires val.VTuple?; requires |val.t| == 3; ensures SizeOfV(val) == SizeOfV(val.t[0]) + SizeOfV(val.t[1]) + SizeOfV(val.t[2]); { calc { SeqSum(val.t); { reveal_SeqSum(); } SizeOfV(val.t[0]) + SeqSum(val.t[1..]); { reveal_SeqSum(); } SizeOfV(val.t[0]) + SizeOfV(val.t[1]) + SeqSum(val.t[2..]); { reveal_SeqSum(); } SizeOfV(val.t[0]) + SizeOfV(val.t[1]) + SizeOfV(val.t[2]) + SeqSum(val.t[3..]); { assert val.t[3..] == []; } // OBSERVE SizeOfV(val.t[0]) + SizeOfV(val.t[1]) + SizeOfV(val.t[2]) + SeqSum([]); { reveal_SeqSum(); } SizeOfV(val.t[0]) + SizeOfV(val.t[1]) + SizeOfV(val.t[2]); } } method MarshallHashtable(c:Hashtable) returns (val:V) requires ValidHashtable(c); ensures ValInGrammar(val, Hashtable_grammar()); ensures ValidVal(val); ensures parse_Hashtable(val) == c; ensures |c| == |val.a|; ensures SeqSum(val.a) <= |c| * ((8 + max_key_len()) + (8 + max_val_len())); { if |c| == 0 { val := VArray([]); reveal_SeqSum(); } else { lemma_non_empty_map_has_elements(c); var key := 0; key :| key in c; var marshalled_key := MarshallKey(key); var marshalled_value := MarshallValue(c[key]); var remainder := RemoveElt(c, key); var marshalled_remainder := MarshallHashtable(remainder); assert parse_Hashtable(marshalled_remainder) == remainder; val := VArray([VTuple([marshalled_key, marshalled_value])] + marshalled_remainder.a); // OBSERVE (everything below; not sure which bit is critical to proving the final ensures) ghost var tuple := val.a[0]; ghost var rest := val.a[1..]; ghost var key' := parse_Key(tuple.t[0]); ghost var value' := parse_Value(tuple.t[1]); ghost var others' := parse_Hashtable(VArray(val.a[1..])); ghost var m' := others'[key' := value']; assert key' == key; assert value' == c[key]; assert others' == remainder; assert m' == c; // Prove the SeqSum ensures calc { SeqSum(val.a); { reveal_SeqSum(); } SizeOfV(val.a[0]) + SeqSum(val.a[1..]); <= SizeOfV(val.a[0]) + |remainder| * ((8 + max_key_len()) + (8 + max_val_len())); { lemma_SeqSum_2(val.a[0]); } SizeOfV(val.a[0].t[0]) + SizeOfV(val.a[0].t[1]) + |remainder| * ((8 + max_key_len()) + (8 + max_val_len())); < //{ lemma_Vote_Val_Valid(c[op], val.a[0].t[1]); lemma_Vote_bound(c[op], val.a[0].t[1]); } ((8 + max_key_len()) + (8 + max_val_len())) + |remainder| * ((8 + max_key_len()) + (8 + max_val_len())); 1*((8 + max_key_len()) + (8 + max_val_len())) + |remainder| * ((8 + max_key_len()) + (8 + max_val_len())); { lemma_mul_is_distributive(((8 + max_key_len()) + (8 + max_val_len())), 1, |remainder|); } (1+|remainder|) * ((8 + max_key_len()) + (8 + max_val_len())); |c| * ((8 + max_key_len()) + (8 + max_val_len())); } } } method MarshallEndPoint(c:EndPoint) returns (val:V) requires EndPointIsValidPublicKey(c) ensures ValInGrammar(val, EndPoint_grammar()) ensures ValidVal(val) ensures parse_EndPoint(val) == c ensures 0 <= SizeOfV(val) < 0x10_0008 { val := VByteArray(c.public_key); } method MarshallMessage_GetRequest(c:CMessage) returns (val:V) requires MessageMarshallable(c); requires c.CGetRequest?; ensures ValInGrammar(val, CMessage_GetRequest_grammar()); ensures ValidVal(val); ensures parse_Message_GetRequest(val) == c; ensures 0 <= SizeOfV(val) < MaxPacketSize() - 0x10_0020; { val := MarshallKey(c.k_getrequest); } method MarshallMessage_SetRequest(c:CMessage) returns (val:V) requires MessageMarshallable(c); requires c.CSetRequest?; ensures ValInGrammar(val, CMessage_SetRequest_grammar()); ensures ValidVal(val); ensures parse_Message_SetRequest(val) == c; ensures 0 <= SizeOfV(val) < MaxPacketSize() - 0x10_0020; { var k_setrequest := MarshallKey(c.k_setrequest); var v_setrequest := MarshallOptionalValue(c.v_setrequest); val := VTuple([k_setrequest, v_setrequest]); lemma_SeqSum_2(val); } method MarshallMessage_Reply(c:CMessage) returns (val:V) requires MessageMarshallable(c); requires c.CReply?; ensures ValInGrammar(val, CMessage_Reply_grammar()); ensures ValidVal(val); ensures parse_Message_Reply(val) == c; ensures 0 <= SizeOfV(val) < MaxPacketSize() - 0x10_0020; { var k_reply := MarshallKey(c.k_reply); var v := MarshallOptionalValue(c.v); val := VTuple([k_reply, v]); lemma_SeqSum_2(val); } method MarshallMessage_Redirect(c:CMessage) returns (val:V) requires MessageMarshallable(c); requires c.CRedirect?; ensures ValInGrammar(val, CMessage_Redirect_grammar()); ensures ValidVal(val); ensures parse_Message_Redirect(val) == c; ensures 0 <= SizeOfV(val) < MaxPacketSize() - 0x10_0020; { var k_redirect := MarshallKey(c.k_redirect); var ep := MarshallEndPoint(c.id); val := VTuple([k_redirect, ep]); lemma_SeqSum_2(val); } method MarshallMessage_Shard(c:CMessage) returns (val:V) requires MessageMarshallable(c); requires c.CShard?; ensures ValInGrammar(val, CMessage_Shard_grammar()); ensures ValidVal(val); ensures parse_Message_Shard(val) == c; ensures 0 <= SizeOfV(val) < MaxPacketSize() - 0x10_0020; { var k_redirect := MarshallKeyRange(c.kr); var ep := MarshallEndPoint(c.recipient); val := VTuple([k_redirect, ep]); lemma_SeqSum_2(val); } method MarshallMessage_Delegate(c:CMessage) returns (val:V) requires MessageMarshallable(c); requires c.CDelegate?; ensures ValInGrammar(val, CMessage_Delegate_grammar()); ensures ValidVal(val); ensures parse_Message_Delegate(val) == c; ensures 0 <= SizeOfV(val) < MaxPacketSize() - 0x10_0020; { var range := MarshallKeyRange(c.range); var h := MarshallHashtable(c.h); val := VTuple([range, h]); calc { SizeOfV(val); { lemma_SeqSum_2(val); } SizeOfV(val.t[0]) + SizeOfV(val.t[1]); < (16 + max_key_len()) + (16 + max_key_len()) + SizeOfV(val.t[1]); <= (16 + max_key_len()) + (16 + max_key_len()) + 8 + |c.h| * ((8 + max_key_len()) + (8 + max_val_len())); { lemma_mul_is_distributive_add_forall(); } (16 + max_key_len()) + (16 + max_key_len()) + 8 + |c.h| * (8 + max_key_len()) + |c.h| * (8 + max_val_len()); { lemma_mul_is_distributive_add_forall(); } (16 + max_key_len()) + (16 + max_key_len()) + 8 + |c.h| * 8 + |c.h| * max_key_len() + |c.h| * 8 + |c.h| * max_val_len(); < MaxPacketSize() - 0x10_0020; } } method MarshallMessage(c:CMessage) returns (val:V) requires MessageMarshallable(c); ensures ValInGrammar(val, CMessage_grammar()); ensures ValidVal(val); ensures parse_Message(val) == c; ensures 0 <= SizeOfV(val) < MaxPacketSize() - 0x10_0018; { if c.CGetRequest? { var msg := MarshallMessage_GetRequest(c); val := VCase(0, msg); } else if c.CSetRequest? { var msg := MarshallMessage_SetRequest(c); val := VCase(1, msg); } else if c.CReply? { var msg := MarshallMessage_Reply(c); val := VCase(2, msg); } else if c.CRedirect? { var msg := MarshallMessage_Redirect(c); val := VCase(3, msg); } else if c.CShard? { var msg := MarshallMessage_Shard(c); val := VCase(4, msg); } else if c.CDelegate? { var msg := MarshallMessage_Delegate(c); val := VCase(5, msg); } else { assert false; } } method MarshallCSingleMessage(c:CSingleMessage) returns (val:V) requires CSingleMessageMarshallable(c); ensures ValInGrammar(val, CSingleMessage_grammar()); ensures ValidVal(val); ensures parse_CSingleMessage(val) == c; ensures 0 <= SizeOfV(val) < MaxPacketSize(); { if c.CSingleMessage? { var ep := MarshallEndPoint(c.dst); var msg := MarshallMessage(c.m); var tuple := VTuple([VUint64(c.seqno), ep, msg]); lemma_SeqSum_3(tuple); assert ValidVal(tuple); // OBSERVE val := VCase(0, tuple); } else { val := VCase(1, VUint64(c.ack_seqno)); } } //////////////////////////////////////////////////////////////////////// // These functions need to be here, rather than CMessageRefinements.i.dfy, // since they depend on SHTDemarshallData //////////////////////////////////////////////////////////////////////// function AbstractifyBufferToLSHTPacket(src:EndPoint, dst:EndPoint, data:seq) : LSHTPacket { LPacket(AbstractifyEndPointToNodeIdentity(dst), AbstractifyEndPointToNodeIdentity(src), AbstractifyCSingleMessageToSingleMessage(SHTDemarshallData(data))) } predicate BufferRefinementAgreesWithMessageRefinement(msg:CSingleMessage, marshalled:seq) requires CSingleMessageIsAbstractable(msg); requires CSingleMessageIsAbstractable(msg); { forall src, dst :: (EndPointIsValidPublicKey(src) && EndPointIsValidPublicKey(dst)) ==> (AbstractifyBufferToLSHTPacket(src, dst, marshalled) == LPacket(AbstractifyEndPointToNodeIdentity(dst), AbstractifyEndPointToNodeIdentity(src), AbstractifyCSingleMessageToSingleMessage(msg))) } function AbstractifyCPacketToLSHTPacket(cp:CPacket) : LSHTPacket requires CPacketIsAbstractable(cp); { LPacket(AbstractifyEndPointToNodeIdentity(cp.dst), AbstractifyEndPointToNodeIdentity(cp.src), AbstractifyCSingleMessageToSingleMessage(cp.msg)) } function AbstractifyNetPacketToLSHTPacket(net:NetPacket) : LSHTPacket requires NetPacketIsAbstractable(net); { AbstractifyBufferToLSHTPacket(net.src, net.dst, net.msg) } function AbstractifyNetPacketToShtPacket(net:NetPacket) : Packet requires NetPacketIsAbstractable(net); { var lp:= AbstractifyNetPacketToLSHTPacket(net); Packet(lp.dst, lp.src, lp.msg) } predicate NetPacketIsAbstractable(net:NetPacket) { EndPointIsAbstractable(net.src) && EndPointIsAbstractable(net.dst) } predicate NetPacketsIsAbstractable(netps:set) { forall p :: p in netps ==> NetPacketIsAbstractable(p) } lemma lemma_CSingleMessage_grammar_valid() ensures ValidGrammar(CSingleMessage_grammar()); { var g := CSingleMessage_grammar(); assert |g.cases| < 0x1_0000_0000_0000_0000; lemma_ValidKey_grammer(); lemma_ValidValue_grammer(); assert ValidGrammar(Key_grammar()); assert ValidGrammar(Value_grammar()); assert ValidGrammar(OptionalValue_grammar()); assert ValidGrammar(CMessage_GetRequest_grammar()); assert ValidGrammar(CMessage_SetRequest_grammar()); assert ValidGrammar(CMessage_Reply_grammar()); assert ValidGrammar(CMessage_Redirect_grammar()); assert ValidGrammar(CMessage_Shard_grammar()); assert ValidGrammar(CMessage_Delegate_grammar()); } method SHTMarshall(msg:CSingleMessage) returns (data:array) requires CSingleMessageIsAbstractable(msg); requires CSingleMessageMarshallable(msg); ensures fresh(data); ensures NetPacketBound(data[..]); ensures BufferRefinementAgreesWithMessageRefinement(msg, data[..]); { var val := MarshallCSingleMessage(msg); lemma_CSingleMessage_grammar_valid(); data := Marshall(val, CSingleMessage_grammar()); forall src, dst | EndPointIsValidPublicKey(src) && EndPointIsValidPublicKey(dst) ensures AbstractifyBufferToLSHTPacket(src, dst, data[..]) == LPacket(AbstractifyEndPointToNodeIdentity(dst), AbstractifyEndPointToNodeIdentity(src), AbstractifyCSingleMessageToSingleMessage(msg)); { calc { AbstractifyBufferToLSHTPacket(src, dst, data[..]); LPacket(AbstractifyEndPointToNodeIdentity(dst), AbstractifyEndPointToNodeIdentity(src), AbstractifyCSingleMessageToSingleMessage(SHTDemarshallData(data[..]))); //{ lemma_NodeIdentityToEndPoint(dst); lemma_NodeIdentityToEndPoint(src); } LPacket(AbstractifyEndPointToNodeIdentity(dst), AbstractifyEndPointToNodeIdentity(src), AbstractifyCSingleMessageToSingleMessage(SHTDemarshallData(data[..]))); LPacket(AbstractifyEndPointToNodeIdentity(dst), AbstractifyEndPointToNodeIdentity(src), AbstractifyCSingleMessageToSingleMessage(msg)); } } } ////////////////////////////////////////////////////////////////////////////// // Sendable predicates predicate CPacketIsValid(cpacket:CPacket, params:CParameters) { CPacketIsAbstractable(cpacket) && CSingleMessageIsValid(cpacket.msg, params) && CSingleMessageMarshallable(cpacket.msg) } predicate CPacketIsSendable(cpacket:CPacket) { CPacketIsAbstractable(cpacket) && CSingleMessageMarshallable(cpacket.msg) } predicate CPacketSetIsSendable(cps:set) { forall p :: p in cps ==> CPacketIsSendable(p) } predicate CPacketSeqIsSendable(cps:seq) { forall i :: 0<=i<|cps| ==> CPacketIsSendable(cps[i]) } predicate OutboundPacketsIsValid(out:CPacket) { CPacketIsSendable(out) && (out.msg.CSingleMessage? || out.msg.CAck?) && CSingleMessageMarshallable(out.msg) } predicate OutboundPacketsSeqIsValid(cpackets:seq) { forall i :: 0 <= i < |cpackets| ==> OutboundPacketsIsValid(cpackets[i]) } predicate OutboundPacketsIsAbstractable(out:CPacket) { CPacketIsAbstractable(out) } function AbstractifyOutboundPacketsToLSHTPacket(out:CPacket) : LSHTPacket requires OutboundPacketsIsAbstractable(out); { AbstractifyCPacketToLSHTPacket(out) } function {:opaque} AbstractifyOutboundPacketsToSeqOfLSHTPackets(out:seq) : seq requires forall i :: 0 <= i < |out| ==> CPacketIsAbstractable(out[i]); ensures |AbstractifyOutboundPacketsToSeqOfLSHTPackets(out)| == |out|; ensures forall i :: 0 <= i < |out| ==> AbstractifyOutboundPacketsToSeqOfLSHTPackets(out)[i] == AbstractifyCPacketToLSHTPacket(out[i]); { if out == [] then [] else if |out| == 1 then [AbstractifyCPacketToLSHTPacket(out[0])] else [AbstractifyCPacketToLSHTPacket(out[0])] + AbstractifyOutboundPacketsToSeqOfLSHTPackets(out[1..]) } predicate OutboundPacketsHasCorrectSrc(out:CPacket, me:EndPoint) { out.src == me } predicate OutboundPacketsSeqHasCorrectSrc(cpackets:seq, me:EndPoint) { forall cpacket :: cpacket in cpackets ==> OutboundPacketsHasCorrectSrc(cpacket, me) } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/SHT/Parameters.i.dfy ================================================ include "../../Protocol/SHT/Parameters.i.dfy" include "../../Common/Native/NativeTypes.s.dfy" module Impl_Parameters_i { import opened Protocol_Parameters_i import opened Native__NativeTypes_s datatype CParameters = CParameters(max_seqno:uint64, max_delegations:uint64) function AbstractifyCParametersToParameters(params:CParameters) : Parameters { Parameters(params.max_seqno as int, params.max_delegations as int) } predicate CParametersIsValid(params:CParameters) { params.max_seqno == 0xFFFF_FFFF_FFFF_FFFF && 3 < params.max_delegations < 0x8000_0000_0000_0000 } function method StaticParams() : CParameters { CParameters(0xffff_ffff_ffff_ffff, // max seqno = 2^64-1 0x7FFF_FFFF_FFFF_FFFF) // max delegations = 2^63-1 } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/SHT/SHTConcreteConfiguration.i.dfy ================================================ include "../../Protocol/SHT/Configuration.i.dfy" include "../../Protocol/LiveSHT/RefinementProof/SHTRefinement.i.dfy" include "../Common/NodeIdentity.i.dfy" include "PacketParsing.i.dfy" module SHT__SHTConcreteConfiguration_i { import opened Native__NativeTypes_s import opened Native__Io_s import opened SHT__Configuration_i import opened Common__NodeIdentity_i import opened SHT__PacketParsing_i import opened LiveSHT__SHTRefinement_i import opened Impl_Parameters_i import opened Common__NetClient_i import opened Common__SeqIsUniqueDef_i import opened Collections__Seqs_i datatype SHTConcreteConfiguration = SHTConcreteConfiguration( hostIds:seq, rootIdentity:EndPoint, params:CParameters) predicate SHTConcreteConfigurationIsAbstractable(config:SHTConcreteConfiguration) { (forall e :: e in config.hostIds ==> EndPointIsAbstractable(e)) && EndPointIsAbstractable(config.rootIdentity) } predicate SHTConcreteConfigurationIsValid(config:SHTConcreteConfiguration) { 0 < |config.hostIds| < 0xffff_ffff_ffff_ffff && SHTConcreteConfigurationIsAbstractable(config) && SeqIsUnique(config.hostIds) && CParametersIsValid(config.params) } function method SHTEndPointIsValid(endPoint:EndPoint, config:SHTConcreteConfiguration) : bool requires SHTConcreteConfigurationIsValid(config); { EndPointIsValidPublicKey(endPoint) } function AbstractifyToConfiguration(config:SHTConcreteConfiguration) : SHTConfiguration requires SHTConcreteConfigurationIsAbstractable(config); { SHTConfiguration([], AbstractifyEndPointsToNodeIdentities(config.hostIds), AbstractifyEndPointToNodeIdentity(config.rootIdentity), AbstractifyCParametersToParameters(config.params)) } predicate ReplicaIndexValid(index:uint64, config:SHTConcreteConfiguration) { 0 <= index as int < |config.hostIds| } predicate ReplicaIndicesValid(indices:seq, config:SHTConcreteConfiguration) { forall i :: 0 <= i < |indices| ==> ReplicaIndexValid(indices[i], config) } lemma lemma_WFSHTConcreteConfiguration(config:SHTConcreteConfiguration) ensures SHTConcreteConfigurationIsAbstractable(config) && 0 < |config.hostIds| && SeqIsUnique(config.hostIds) && config.rootIdentity in config.hostIds ==> SHTConcreteConfigurationIsAbstractable(config) && WFSHTConfiguration(AbstractifyToConfiguration(config)); { if (SHTConcreteConfigurationIsAbstractable(config) && 0 < |config.hostIds| && SeqIsUnique(config.hostIds)) { //lemma_CardinalityNonEmpty(config.hostIds); var e := config.hostIds[0]; assert AbstractifyEndPointToNodeIdentity(e) in AbstractifyToConfiguration(config).hostIds; assert 0 < |AbstractifyToConfiguration(config).hostIds|; var r_hostIds := AbstractifyToConfiguration(config).hostIds; forall i, j | 0 <= i < |r_hostIds| && 0 <= j < |r_hostIds| ensures r_hostIds[i] == r_hostIds[j] ==> i == j; { if r_hostIds[i] == r_hostIds[j] { if i != j { assert r_hostIds[i] == AbstractifyEndPointToNodeIdentity(config.hostIds[i]); assert r_hostIds[j] == AbstractifyEndPointToNodeIdentity(config.hostIds[j]); lemma_AbstractifyEndPointToNodeIdentity_injective(config.hostIds[i], config.hostIds[j]); assert config.hostIds[i] == config.hostIds[j]; reveal_SeqIsUnique(); assert i == j; assert false; } } } } } predicate WFSHTConcreteConfiguration(config:SHTConcreteConfiguration) ensures WFSHTConcreteConfiguration(config) ==> SHTConcreteConfigurationIsAbstractable(config) && WFSHTConfiguration(AbstractifyToConfiguration(config)); { lemma_WFSHTConcreteConfiguration(config); SHTConcreteConfigurationIsAbstractable(config) && 0 < |config.hostIds| && SeqIsUnique(config.hostIds) && config.rootIdentity in config.hostIds } method CGetReplicaIndex(replica:EndPoint, config:SHTConcreteConfiguration) returns (found:bool, index:uint64) requires SHTConcreteConfigurationIsValid(config); requires EndPointIsValidPublicKey(replica); ensures found ==> ReplicaIndexValid(index, config) && config.hostIds[index] == replica; ensures found ==> GetHostIndex(AbstractifyEndPointToNodeIdentity(replica), AbstractifyToConfiguration(config)) == index as int; ensures !found ==> !(replica in config.hostIds); ensures !found ==> !(AbstractifyEndPointToNodeIdentity(replica) in AbstractifyEndPointsToNodeIdentities(config.hostIds)); { var i:uint64 := 0; lemma_AbstractifyEndPointsToNodeIdentities_properties(config.hostIds); while i < |config.hostIds| as uint64 invariant i < |config.hostIds| as uint64; invariant forall j :: 0 <= j < i ==> config.hostIds[j] != replica; { if replica == config.hostIds[i] { found := true; index := i; ghost var r_replica := AbstractifyEndPointToNodeIdentity(replica); ghost var r_replicas := AbstractifyToConfiguration(config).hostIds; assert r_replica == r_replicas[index]; assert ItemAtPositionInSeq(r_replicas, r_replica, index as int); calc ==> { true; { reveal_SeqIsUnique(); } forall j :: 0 <= j < |config.hostIds| && j != i as int ==> config.hostIds[j] != replica; } if exists j :: 0 <= j < |r_replicas| && j != index as int && ItemAtPositionInSeq(r_replicas, r_replica, j) { ghost var j :| 0 <= j < |r_replicas| && j != index as int && ItemAtPositionInSeq(r_replicas, r_replica, j); assert r_replicas[j] == r_replica; assert AbstractifyEndPointToNodeIdentity(config.hostIds[j]) == r_replica; lemma_AbstractifyEndPointToNodeIdentity_injective(config.hostIds[i], config.hostIds[j]); assert false; } assert forall j :: 0 <= j < |r_replicas| && j != index as int ==> !ItemAtPositionInSeq(r_replicas, r_replica, j); assert FindIndexInSeq(r_replicas, r_replica) == index as int; return; } if i == |config.hostIds| as uint64 - 1 { found := false; return; } i := i + 1; } found := false; } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/SHT/SingleDeliveryModel.i.dfy ================================================ include "SingleDeliveryState.i.dfy" include "Parameters.i.dfy" include "../../Protocol/SHT/RefinementProof/InvProof.i.dfy" include "PacketParsing.i.dfy" module SHT__SingleDeliveryModel_i { import opened Native__NativeTypes_s import opened Native__Io_s import opened SHT__Network_i import opened SHT__CMessage_i import opened SHT__SingleDeliveryState_i import opened Impl_Parameters_i import opened SHT__InvProof_i import opened SHT__PacketParsing_i import opened Common__SeqIsUnique_i import opened Common__NodeIdentity_i import opened GenericRefinement_i import opened SHT__SingleDelivery_i method CTombstoneTableLookup(src:EndPoint, t:CTombstoneTable) returns (last_seqno:uint64) requires EndPointIsAbstractable(src); requires CTombstoneTableIsAbstractable(t); ensures last_seqno as int == TombstoneTableLookup(AbstractifyEndPointToNodeIdentity(src), AbstractifyCTombstoneTableToTombstoneTable(t)); { lemma_AbstractifyEndPointToNodeIdentity_injective_forall(); lemma_AbstractifyMap_properties(t, AbstractifyEndPointToNodeIdentity, uint64_to_nat_t, RefineNodeIdentityToEndPoint); if src in t { last_seqno := t[src]; } else { last_seqno := 0; } } method CAckStateLookup(src:EndPoint, sendState:CSendState, ghost params:CParameters) returns (ackState:CAckState) requires EndPointIsAbstractable(src); requires CSendStateIsAbstractable(sendState); requires CSendStateIsValid(sendState, params); ensures CAckStateIsAbstractable(ackState); ensures CAckStateIsValid(ackState, src, params); ensures AbstractifyCAskStateToAckState(ackState) == AckStateLookup(AbstractifyEndPointToNodeIdentity(src), AbstractifyCSendStateToSendState(sendState)); { lemma_AbstractifyEndPointToNodeIdentity_injective_forall(); lemma_AbstractifyMap_properties(sendState, AbstractifyEndPointToNodeIdentity, AbstractifyCAskStateToAckState, RefineNodeIdentityToEndPoint); if src in sendState { ackState := sendState[src]; } else { ackState := CAckState(0, []); } } method CSingleDeliveryAcctInit(ghost params:CParameters) returns (acct:CSingleDeliveryAcct) ensures CSingleDeliveryAccountIsValid(acct, params); ensures SingleDelivery_Init() == AbstractifyCSingleDeliveryAcctToSingleDeliveryAcct(acct); { acct := CSingleDeliveryAcct(map[], map[]); lemma_AbstractifyEndPointToNodeIdentity_injective_forall(); lemma_AbstractifyMap_properties(acct.receiveState, AbstractifyEndPointToNodeIdentity, uint64_to_nat_t, RefineNodeIdentityToEndPoint); lemma_AbstractifyMap_properties(acct.sendState, AbstractifyEndPointToNodeIdentity, AbstractifyCAskStateToAckState, RefineNodeIdentityToEndPoint); } method MessageNotReceivedImpl(acct:CSingleDeliveryAcct, src:EndPoint, sm:CSingleMessage, ghost params:CParameters) returns (b:bool) requires CSingleDeliveryAccountIsValid(acct, params); requires EndPointIsAbstractable(src); requires CSingleMessageIsAbstractable(sm); ensures b == MessageNotReceived(AbstractifyCSingleDeliveryAcctToSingleDeliveryAcct(acct), AbstractifyEndPointToNodeIdentity(src), AbstractifyCSingleMessageToSingleMessage(sm)); { var last_seqno := CTombstoneTableLookup(src, acct.receiveState); b := sm.CSingleMessage? && sm.seqno > last_seqno; } method NewSingleMessageImpl(acct:CSingleDeliveryAcct, pkt:CPacket, ghost params:CParameters) returns (b:bool) requires CSingleDeliveryAccountIsValid(acct, params); requires CPacketIsAbstractable(pkt) && CSingleMessageIs64Bit(pkt.msg) && !pkt.msg.CInvalidMessage?; // CSingleMessageMarshallable(pkt.msg); ensures b == NewSingleMessage(AbstractifyCSingleDeliveryAcctToSingleDeliveryAcct(acct), AbstractifyCPacketToShtPacket(pkt)); { if pkt.msg.CSingleMessage? { var last_seqno := CTombstoneTableLookup(pkt.src, acct.receiveState); b := if pkt.msg.seqno > 0 then pkt.msg.seqno - 1 == last_seqno else false; } else { b := false; } } method TruncateUnAckListImpl(unAcked:seq, seqnoAcked:uint64, e:EndPoint, ghost old_seqno:int, ghost bound:int) returns (truncated:seq) requires CSingleMessageSeqIsAbstractable(unAcked); requires CUnAckedListValidForDst(unAcked, e); requires UnAckedListSequential(unAcked); requires (|unAcked| > 0 ==> unAcked[0].seqno as int == old_seqno + 1); requires old_seqno <= seqnoAcked as int <= bound; requires |unAcked| + old_seqno <= bound; ensures CSingleMessageSeqIsAbstractable(truncated); ensures CUnAckedListValidForDst(truncated, e); ensures UnAckedListSequential(truncated); ensures AbstractifySeqOfCSingleMessageToSeqOfSingleMessage(truncated) == TruncateUnAckList(AbstractifySeqOfCSingleMessageToSeqOfSingleMessage(unAcked), seqnoAcked as int); ensures (|truncated| > 0 ==> truncated[0].seqno as int == seqnoAcked as int + 1) ensures |truncated| + seqnoAcked as int <= bound; { if |unAcked| > 0 && unAcked[0].CSingleMessage? && unAcked[0].seqno <= seqnoAcked { assert AbstractifySeqOfCSingleMessageToSeqOfSingleMessage(unAcked[1..]) == AbstractifySeqOfCSingleMessageToSeqOfSingleMessage(unAcked)[1..]; // OBSERVE truncated := TruncateUnAckListImpl(unAcked[1..], seqnoAcked, e, old_seqno + 1, bound); } else { truncated := unAcked; } } method ReceiveAckImpl(acct:CSingleDeliveryAcct, pkt:CPacket, ghost params:CParameters) returns (acct':CSingleDeliveryAcct) requires CSingleDeliveryAccountIsValid(acct, params); requires CPacketIsAbstractable(pkt) && CSingleMessageMarshallable(pkt.msg); requires pkt.msg.CAck?; requires CParametersIsValid(params); ensures CSingleDeliveryAccountIsValid(acct', params); ensures ReceiveAck(AbstractifyCSingleDeliveryAcctToSingleDeliveryAcct(acct), AbstractifyCSingleDeliveryAcctToSingleDeliveryAcct(acct'), AbstractifyCPacketToShtPacket(pkt), {}); { var oldAckState := CAckStateLookup(pkt.src, acct.sendState, params); assert CUnAckedListValidForDst(oldAckState.unAcked, pkt.src); assert CUnAckedListValid(oldAckState.unAcked); if pkt.msg.ack_seqno > oldAckState.numPacketsAcked { var newUnAcked := TruncateUnAckListImpl(oldAckState.unAcked, pkt.msg.ack_seqno, pkt.src, oldAckState.numPacketsAcked as int, params.max_seqno as int); assert CUnAckedListValidForDst(newUnAcked, pkt.src); var newAckState := oldAckState.(numPacketsAcked := pkt.msg.ack_seqno, unAcked := newUnAcked); lemma_AbstractifyEndPointToNodeIdentity_injective_forall(); lemma_AbstractifyMap_properties(acct.sendState, AbstractifyEndPointToNodeIdentity, AbstractifyCAskStateToAckState, RefineNodeIdentityToEndPoint); assert AbstractifyCAskStateToAckState(newAckState) == AbstractifyCAskStateToAckState(oldAckState).(numPacketsAcked := AbstractifyCPacketToShtPacket(pkt).msg.ack_seqno, unAcked := AbstractifySeqOfCSingleMessageToSeqOfSingleMessage(newUnAcked)); // if newAckState.unAcked == [] { // assert pkt.msg.ack_seqno as int < params.max_seqno as int; // assert newAckState.numPacketsAcked as int + |newAckState.unAcked| <= params.max_seqno as int; // } else { // assert newAckState.numPacketsAcked as int + |newAckState.unAcked| <= params.max_seqno as int; // } acct' := acct.(sendState := acct.sendState[pkt.src := newAckState]); } else { acct' := acct; } } method ShouldAckSingleMessageImpl(acct:CSingleDeliveryAcct, pkt:CPacket, ghost params:CParameters) returns (b:bool) requires CSingleDeliveryAccountIsValid(acct, params); requires CPacketIsAbstractable(pkt); ensures b == ShouldAckSingleMessage(AbstractifyCSingleDeliveryAcctToSingleDeliveryAcct(acct), AbstractifyCPacketToShtPacket(pkt)); { var last_seqno := CTombstoneTableLookup(pkt.src, acct.receiveState); b := pkt.msg.CSingleMessage? && pkt.msg.seqno <= last_seqno; } method SendAckImpl(acct:CSingleDeliveryAcct, pkt:CPacket, ghost params:CParameters) returns (ack:CPacket) requires CSingleDeliveryAccountIsValid(acct, params); requires CPacketIsAbstractable(pkt); requires pkt.msg.CSingleMessage?; requires ShouldAckSingleMessage(AbstractifyCSingleDeliveryAcctToSingleDeliveryAcct(acct), AbstractifyCPacketToShtPacket(pkt)); ensures CPacketIsAbstractable(ack); ensures SendAck(AbstractifyCSingleDeliveryAcctToSingleDeliveryAcct(acct), AbstractifyCPacketToShtPacket(pkt), AbstractifyCPacketToShtPacket(ack), { AbstractifyCPacketToShtPacket(ack) }); ensures ack.src == pkt.dst && ack.dst == pkt.src; { ack := CPacket(pkt.src, pkt.dst, CAck(pkt.msg.seqno)); } method MaybeAckPacketImpl(acct:CSingleDeliveryAcct, pkt:CPacket, ghost params:CParameters) returns (b:bool, ack:CPacket) requires CSingleDeliveryAccountIsValid(acct, params); requires CPacketIsAbstractable(pkt); ensures CPacketIsAbstractable(ack); ensures MaybeAckPacket(AbstractifyCSingleDeliveryAcctToSingleDeliveryAcct(acct), AbstractifyCPacketToShtPacket(pkt), AbstractifyCPacketToShtPacket(ack), if b then { AbstractifyCPacketToShtPacket(ack) } else {}); ensures b ==> ack.src == pkt.dst && ack.dst == pkt.src; { var should_ack := ShouldAckSingleMessageImpl(acct, pkt, params); if should_ack { b := true; ack := SendAckImpl(acct, pkt, params); } else { b := false; ack := pkt; } } method ReceiveRealPacketImpl(acct:CSingleDeliveryAcct, pkt:CPacket, ghost params:CParameters) returns (acct':CSingleDeliveryAcct) requires CSingleDeliveryAccountIsValid(acct, params); requires CPacketIsAbstractable(pkt) && CSingleMessageIs64Bit(pkt.msg) && !pkt.msg.CInvalidMessage?; // CSingleMessageMarshallable(pkt.msg); requires pkt.msg.CSingleMessage?; ensures CSingleDeliveryAccountIsValid(acct', params); ensures ReceiveRealPacket(AbstractifyCSingleDeliveryAcctToSingleDeliveryAcct(acct), AbstractifyCSingleDeliveryAcctToSingleDeliveryAcct(acct'), AbstractifyCPacketToShtPacket(pkt)); { var b := NewSingleMessageImpl(acct, pkt, params); if b { var last_seqno := CTombstoneTableLookup(pkt.src, acct.receiveState); acct' := acct.(receiveState := acct.receiveState[pkt.src := last_seqno + 1]); lemma_AbstractifyEndPointToNodeIdentity_injective_forall(); lemma_AbstractifyMap_properties(acct.receiveState, AbstractifyEndPointToNodeIdentity, uint64_to_nat_t, RefineNodeIdentityToEndPoint); } else { acct' := acct; } } method ReceiveSingleMessageImpl(acct:CSingleDeliveryAcct, pkt:CPacket, ghost params:CParameters) returns (b:bool, acct':CSingleDeliveryAcct, ack:CPacket) requires CSingleDeliveryAccountIsValid(acct, params); requires CPacketIsAbstractable(pkt) && CSingleMessageIs64Bit(pkt.msg) && !pkt.msg.CInvalidMessage?; // CSingleMessageMarshallable(pkt.msg); requires CParametersIsValid(params); ensures CSingleDeliveryAccountIsValid(acct', params); ensures CPacketIsAbstractable(ack); ensures ReceiveSingleMessage(AbstractifyCSingleDeliveryAcctToSingleDeliveryAcct(acct), AbstractifyCSingleDeliveryAcctToSingleDeliveryAcct(acct'), AbstractifyCPacketToShtPacket(pkt), AbstractifyCPacketToShtPacket(ack), if b then { AbstractifyCPacketToShtPacket(ack) } else {}); ensures b ==> ack.src == pkt.dst && ack.dst == pkt.src; { if pkt.msg.CAck? { acct' := ReceiveAckImpl(acct, pkt, params); b := false; } else if pkt.msg.CSingleMessage? { acct' := ReceiveRealPacketImpl(acct, pkt, params); b, ack := MaybeAckPacketImpl(acct', pkt, params); } else { assert pkt.msg.CInvalidMessage?; b := false; acct' := acct; } if !b { ack := pkt; // Ensures ack is refinable } } method {:timeLimitMultiplier 3} SendSingleCMessage(acct:CSingleDeliveryAcct, m:CMessage, dst:EndPoint, params:CParameters) returns (acct':CSingleDeliveryAcct, sm:CSingleMessage, shouldSend:bool) requires CSingleDeliveryAccountIsValid(acct, params); requires CMessageIsAbstractable(m); requires MessageMarshallable(m); requires ValidPhysicalAddress(dst); requires CParametersIsValid(params); ensures CSingleDeliveryAccountIsValid(acct', params); ensures CSingleMessageIsAbstractable(sm); ensures sm.CSingleMessage? ==> sm.dst == dst; ensures SendSingleMessage(AbstractifyCSingleDeliveryAcctToSingleDeliveryAcct(acct), AbstractifyCSingleDeliveryAcctToSingleDeliveryAcct(acct'), AbstractifyCMessageToRslMessage(m), AbstractifyCSingleMessageToSingleMessage(sm), AbstractifyCParametersToParameters(params), shouldSend); { lemma_AbstractifyEndPointToNodeIdentity_injective_forall(); lemma_AbstractifyMap_properties(acct.sendState, AbstractifyEndPointToNodeIdentity, AbstractifyCAskStateToAckState, RefineNodeIdentityToEndPoint); var oldAckState := CAckStateLookup(dst, acct.sendState, params); assert CAckStateIsValid(oldAckState, dst, params); assert oldAckState.numPacketsAcked as int + |oldAckState.unAcked| <= params.max_seqno as int; if oldAckState.numPacketsAcked + |oldAckState.unAcked| as uint64 == params.max_seqno { shouldSend := false; acct' := acct; sm := CSingleMessage(0, dst, m); // Dummy message to simplify postconditions } else { var sm_new := CSingleMessage((oldAckState.numPacketsAcked + |oldAckState.unAcked| as uint64 + 1) as uint64, dst, m); //assert CSingleMessageMarshallable(sm); assert MapSeqToSeq(oldAckState.unAcked + [sm_new], AbstractifyCSingleMessageToSingleMessage) == MapSeqToSeq(oldAckState.unAcked, AbstractifyCSingleMessageToSingleMessage) + [AbstractifyCSingleMessageToSingleMessage(sm_new)]; var newAckState := oldAckState.(unAcked := oldAckState.unAcked + [sm_new]); var acctInt := acct.sendState[dst := newAckState]; acct' := acct.(sendState := acctInt); sm := sm_new; shouldSend := true; UnAckedListFinalEntry(AbstractifySeqOfCSingleMessageToSeqOfSingleMessage(oldAckState.unAcked), oldAckState.numPacketsAcked as int); } } predicate CombinedPreImage(seqs:seq>, combined:seq, index:int) requires 0 <= index < |combined|; { exists j, k {:trigger seqs[j][k]} :: 0 <= j < |seqs| && 0 <= k < |seqs[j]| && seqs[j][k] == combined[index] } method ConcatenateSeqs(seqs:seq>) returns (combined:seq) ensures forall j, k :: 0 <= j < |seqs| && 0 <= k < |seqs[j]| ==> seqs[j][k] in combined; ensures forall m :: 0 <= m < |combined| ==> CombinedPreImage(seqs, combined, m); { combined := []; var i := 0; while i < |seqs| invariant 0 <= i <= |seqs|; invariant forall j, k :: 0 <= j < i && 0 <= k < |seqs[j]| ==> seqs[j][k] in combined; invariant forall m :: 0 <= m < |combined| ==> CombinedPreImage(seqs, combined, m); { ghost var old_combined := combined; combined := combined + seqs[i]; i := i + 1; forall m | 0 <= m < |combined| ensures CombinedPreImage(seqs, combined, m); { if m < |old_combined| { // Loop invariant should cover this assert CombinedPreImage(seqs, old_combined, m); } else { var m_offset := m - |old_combined|; assert seqs[i - 1][m_offset] == combined[m]; assert CombinedPreImage(seqs, combined, m); } } } } lemma lemma_AbstractifyCPacketsToPackets_reverse(cps:set, p:Packet) returns (cp:CPacket) requires CPacketsIsAbstractable(cps); requires p in AbstractifyCPacketsToPackets(cps); ensures CPacketIsAbstractable(cp); ensures AbstractifyCPacketToShtPacket(cp) == p ensures cp in cps; { reveal_AbstractifyCPacketsToPackets(); cp :| cp in cps && CPacketIsAbstractable(cp) && AbstractifyCPacketToShtPacket(cp) == p; } lemma lemma_AbstractifySeqOfCPacketsToSetOfShtPackets_reverse(cps:seq, p:Packet) returns (cp:CPacket) requires CPacketSeqIsAbstractable(cps); requires p in AbstractifySeqOfCPacketsToSetOfShtPackets(cps); ensures CPacketIsAbstractable(cp); ensures AbstractifyCPacketToShtPacket(cp) == p ensures cp in cps; { reveal_AbstractifySeqOfCPacketsToSetOfShtPackets(); cp :| cp in cps && CPacketIsAbstractable(cp) && AbstractifyCPacketToShtPacket(cp) == p; } method RetransmitUnAckedPackets(acct:CSingleDeliveryAcct, src:EndPoint, ghost params:CParameters) returns (pkts:seq) requires CSingleDeliveryAccountIsValid(acct, params); requires EndPointIsAbstractable(src); ensures CPacketSeqIsAbstractable(pkts); ensures AbstractifySeqOfCPacketsToSetOfShtPackets(pkts) == UnAckedMessages(AbstractifyCSingleDeliveryAcctToSingleDeliveryAcct(acct), AbstractifyEndPointToNodeIdentity(src)); ensures (forall p :: p in pkts ==> p.src == src && p.msg.CSingleMessage? && CSingleMessageMarshallable(p.msg)); ensures (forall i :: 0 <= i < |pkts| ==> CPacketIsSendable(pkts[i])); ensures (forall i :: 0 <= i < |pkts| ==> pkts[i].msg.CSingleMessage?); ensures (forall i :: 0 <= i < |pkts| ==> CSingleMessageMarshallable(pkts[i].msg)); { var pkt_set := set dst, i | dst in acct.sendState && 0 <= i < |acct.sendState[dst].unAcked| && acct.sendState[dst].unAcked[i].CSingleMessage? :: var sm := acct.sendState[dst].unAcked[i]; CPacket(sm.dst, src, sm); pkts := SetToUniqueSeqConstruct(pkt_set); // Prove that everything behaves as expected lemma_AbstractifyEndPointToNodeIdentity_injective_forall(); lemma_AbstractifyMap_properties(acct.sendState, AbstractifyEndPointToNodeIdentity, AbstractifyCAskStateToAckState, RefineNodeIdentityToEndPoint); ghost var r_pkt_set := AbstractifyCPacketsToPackets(pkt_set); ghost var r_acct := AbstractifyCSingleDeliveryAcctToSingleDeliveryAcct(acct); ghost var r_src := AbstractifyEndPointToNodeIdentity(src); ghost var g_set := UnAckedMessages(r_acct, r_src); forall p | p in g_set ensures p in r_pkt_set; { var dst, i :| dst in r_acct.sendState && 0 <= i < |r_acct.sendState[dst].unAcked| && r_acct.sendState[dst].unAcked[i].SingleMessage? && (var sm := r_acct.sendState[dst].unAcked[i]; p.dst == sm.dst && p.src == r_src && p.msg == sm); // Needed for the OBSERVE on the next line assert AckStateLookup(dst, r_acct.sendState) == r_acct.sendState[dst]; // OBSERVE assert UnAckedMsgForDst(r_acct, p.msg, p.dst); // OBSERVE var c_dst :| c_dst in acct.sendState && AbstractifyEndPointToNodeIdentity(c_dst) == dst; var c_sm := acct.sendState[c_dst].unAcked[i]; var cp := CPacket(c_sm.dst, src, c_sm); assert c_sm.CSingleMessage?; assert CSingleMessageMarshallable(c_sm); assert cp in pkt_set; // OBSERVE } forall p | p in r_pkt_set ensures p in g_set; { var c_p := lemma_AbstractifyCPacketsToPackets_reverse(pkt_set, p); var dst, i :| dst in acct.sendState && 0 <= i < |acct.sendState[dst].unAcked| && acct.sendState[dst].unAcked[i].CSingleMessage? && (var sm := acct.sendState[dst].unAcked[i]; c_p.dst == sm.dst && c_p.src == src && c_p.msg == sm); // Needed for the OBSERVE below var r_dst := AbstractifyEndPointToNodeIdentity(dst); var r_sm := r_acct.sendState[r_dst].unAcked[i]; assert Packet(r_sm.dst, r_src, r_sm) in g_set; // OBSERVE } assert r_pkt_set == g_set; ghost var r_pkt_set' := AbstractifySeqOfCPacketsToSetOfShtPackets(pkts); forall p | p in r_pkt_set ensures p in r_pkt_set'; { var c_p := lemma_AbstractifyCPacketsToPackets_reverse(pkt_set, p); assert c_p in pkt_set; assert c_p in pkts; // OBSERVE } forall p | p in r_pkt_set' ensures p in r_pkt_set; { var c_p := lemma_AbstractifySeqOfCPacketsToSetOfShtPackets_reverse(pkts, p); assert c_p in pkts; assert c_p in pkt_set; // OBSERVE } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Impl/SHT/SingleDeliveryState.i.dfy ================================================ include "../Common/NodeIdentity.i.dfy" include "../Common/GenericRefinement.i.dfy" include "../../Protocol/SHT/SingleDelivery.i.dfy" include "CMessage.i.dfy" include "Parameters.i.dfy" include "PacketParsing.i.dfy" module SHT__SingleDeliveryState_i { import opened Native__NativeTypes_s import opened Native__Io_s import opened Common__NodeIdentity_i import opened SHT__SingleDelivery_i import opened GenericRefinement_i import opened SHT__CMessage_i import opened Impl_Parameters_i import opened SHT__PacketParsing_i import opened SHT__Message_i // Highest sequence number we have received from each node type CTombstoneTable = map // State about packets we've sent to each node datatype CAckState = CAckState(numPacketsAcked:uint64, unAcked:seq) type CSendState = map datatype CSingleDeliveryAcct = CSingleDeliveryAcct(receiveState:CTombstoneTable, sendState:CSendState) ////////////////////////////////////////////////////////////////////////////// // Useful to give this cast a name, so it can be used as a higher-order function function uint64_to_nat_t(u:uint64) : nat_t { u as nat_t } predicate CTombstoneTableIsAbstractable(ts:CTombstoneTable) { forall e :: e in ts ==> EndPointIsAbstractable(e) } function AbstractifyCTombstoneTableToTombstoneTable(ts:CTombstoneTable) : TombstoneTable requires CTombstoneTableIsAbstractable(ts); { lemma_AbstractifyEndPointToNodeIdentity_injective_forall(); AbstractifyMap(ts, AbstractifyEndPointToNodeIdentity, uint64_to_nat_t, RefineNodeIdentityToEndPoint) } ////////////////////////////////////////////////////////////////////////////// // Unacked list predicate CAckStateIsAbstractable(cas:CAckState) { CSingleMessageSeqIsAbstractable(cas.unAcked) } function AbstractifyCAskStateToAckState(cas:CAckState) : AckState requires CAckStateIsAbstractable(cas); { AckState(cas.numPacketsAcked as int, AbstractifySeqOfCSingleMessageToSeqOfSingleMessage(cas.unAcked)) } predicate NoAcksInUnAcked(list:seq) { forall i :: 0 <= i < |list| ==> list[i].CSingleMessage? } predicate UnAckedListSequential(list:seq) requires NoAcksInUnAcked(list); { forall i, j :: 0 <= i && j == i + 1 && j < |list| ==> list[i].seqno as int + 1 == list[j].seqno as int } predicate CUnAckedValid(msg:CSingleMessage) { msg.CSingleMessage? && CSingleMessageIsAbstractable(msg) && CSingleMessageMarshallable(msg) } predicate CUnAckedListValid(list:seq) { (forall i :: 0 <= i < |list| ==> CUnAckedValid(list[i])) && UnAckedListSequential(list) } predicate CUnAckedListValidForDst(list:seq, dst:EndPoint) { CUnAckedListValid(list) && (forall i :: 0 <= i < |list| ==> list[i].dst == dst) } predicate CAckStateIsValid(cas:CAckState, dst:EndPoint, params:CParameters) { CAckStateIsAbstractable(cas) && CUnAckedListValidForDst(cas.unAcked, dst) && cas.numPacketsAcked as int + |cas.unAcked| <= params.max_seqno as int && (|cas.unAcked| > 0 ==> cas.unAcked[0].seqno as int == cas.numPacketsAcked as int + 1) } ////////////////////////////////////////////////////////////////////////////// predicate CSendStateIsAbstractable(sendState:CSendState) { MapIsAbstractable(sendState, AbstractifyEndPointToNodeIdentity, AbstractifyCAskStateToAckState, RefineNodeIdentityToEndPoint) } function AbstractifyCSendStateToSendState(sendState:CSendState) : SendState requires CSendStateIsAbstractable(sendState); { AbstractifyMap(sendState, AbstractifyEndPointToNodeIdentity, AbstractifyCAskStateToAckState, RefineNodeIdentityToEndPoint) } predicate CSendStateIsValid(sendState:CSendState, params:CParameters) { CSendStateIsAbstractable(sendState) && forall e :: e in sendState ==> CAckStateIsValid(sendState[e], e, params) } ////////////////////////////////////////////////////////////////////////////// predicate CSingleDeliveryAcctIsAbstractable(acct:CSingleDeliveryAcct) { CTombstoneTableIsAbstractable(acct.receiveState) && CSendStateIsAbstractable(acct.sendState) } function AbstractifyCSingleDeliveryAcctToSingleDeliveryAcct(acct:CSingleDeliveryAcct) : SingleDeliveryAcct requires CSingleDeliveryAcctIsAbstractable(acct); { SingleDeliveryAcct(AbstractifyCTombstoneTableToTombstoneTable(acct.receiveState), AbstractifyCSendStateToSendState(acct.sendState)) } predicate CSingleDeliveryAccountIsValid(acct:CSingleDeliveryAcct, params:CParameters) { CSingleDeliveryAcctIsAbstractable(acct) && CSendStateIsValid(acct.sendState, params) } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/Common/Liveness/RTSchedule.i.dfy ================================================ include "../../../Common/Collections/Maps2.i.dfy" include "../../../Common/Logic/Temporal/Temporal.s.dfy" include "../../../Common/Logic/Temporal/Heuristics.i.dfy" include "../../../Common/Logic/Temporal/Rules.i.dfy" include "../../../Common/Logic/Temporal/Time.i.dfy" include "../../../Common/Logic/Temporal/Induction.i.dfy" include "../../../Common/Logic/Temporal/WF1.i.dfy" include "../../../../Libraries/Math/mul_auto.i.dfy" include "../../../../Libraries/Math/mod_auto.i.dfy" module Liveness__RTSchedule_i { import opened Collections__Maps2_i import opened Temporal__Temporal_s import opened Temporal__Heuristics_i import opened Temporal__Monotonicity_i import opened Temporal__Rules_i import opened Temporal__Time_s import opened Temporal__Time_i import opened Temporal__Induction_i import opened Temporal__WF1_i import opened Math__mul_auto_i import opened Math__mod_auto_i import opened Collections__Maps2_s // NOTE: This round-robin scheduler assumes that all actions in the schedule are always enabled. // This assumption can make the spec be not machine-closed, in Lamport's terminology. // In other words, it can make the actions impossible to implement. So, unless you // want your spec to be unimplementable, make sure that every action is always enabled, // e.g., by letting it stutter if there's nothing to do. An action A is enabled if // forall s :: exists s' :: apply(A, (s, s')). lemma Lemma_RoundRobinSchedulerTimelyForAllActionsTemporal( behavior:Behavior, // The behavior we'll prove it for next_action_type_fun:imap, // A function that takes a step and computes which action type has priority real_time_fun:imap, // A function that takes a step and computes at what real time it happened scheduler_action:temporal, // The subaction of 'next' that executes the scheduler schedule:seq, // The schedule the scheduler follows start_step:int, // The step at which the scheduler starts executing regularly interval:int // The maximum interval between scheduler actions during the regular-execution period ) requires imaptotal(behavior) requires imaptotal(next_action_type_fun) requires imaptotal(real_time_fun) // The priority starts as a valid value. Note that this also implies the schedule has at least one action. requires 0 <= next_action_type_fun[0] < |schedule| // The regular-execution period is sensible. requires 0 <= start_step requires interval > 0 // Every step either invokes the scheduler or leaves the action priority unchanged. requires sat(0, always(SchedulerActsOrNextActionTypeUnchangedTemporal(behavior, next_action_type_fun, scheduler_action))) // If the scheduler takes a step, it takes an action of the prioritized type, then gives // priority to the next action type in round-robin order. requires forall i {:trigger sat(i, scheduler_action)} :: 0 <= i && sat(i, scheduler_action) ==> var action_type_index := next_action_type_fun[i]; && (0 <= action_type_index < |schedule| ==> sat(i, schedule[action_type_index])) && next_action_type_fun[i+1] == (action_type_index + 1) % |schedule| // Time moves forward. requires monotonic_from(0, real_time_fun) // The scheduler takes at least one step every interval during the epoch during which it's regularly scheduled. requires sat(start_step, always(eventuallynextwithin(scheduler_action, interval, real_time_fun))) // For each action type, an action of that type will happen in any period of duration (schedule-size * interval) // that is within the regular-execution period. ensures forall action_type_index :: 0 <= action_type_index < |schedule| ==> sat(start_step, always(eventuallynextwithin(schedule[action_type_index], interval * |schedule|, real_time_fun))) { var b := behavior; var span := interval; var i0 := start_step; var naf := next_action_type_fun; var n := |schedule|; var timefun := real_time_fun; var next_action := SchedulerActsOrNextActionTypeUnchangedTemporal(behavior, next_action_type_fun, scheduler_action); assert sat(0, always(next_action)); forall ensures forall i {:trigger naf[i]} :: TLe(i0, i) ==> 0 <= naf[i] < n { TemporalAssist(); var x := stepmap(imap i :: 0 <= naf[i] < n); assert sat(0, x); forall i | TLe(0, i) ensures sat(i, imply(x, next(x))) { } TemporalInductionNext(0, x); assert sat(i0, always(stepmap(imap i :: 0 <= naf[i] < n))); } forall a0 | 0 <= a0 < n ensures sat(i0, always(eventuallynextwithin(schedule[a0], span * n, timefun))) { var d := imap i :: 1 + ((a0 - naf[i]) % n); var goal := schedule[a0]; forall ensures sat(i0, always(nextOrDecreaseWithin(goal, d, span, timefun))) { TemporalAssist(); forall i1 {:trigger TLe(i0, i1)} | TLe(i0, i1) ensures sat(i1, nextOrDecreaseWithin(goal, d, span, timefun)) { var i2 := earliestActionWithin(i1, scheduler_action, span, timefun); assert TLe(i1, i2); assert forall i :: TLe(i1, i) && TLe(i, i2 - 1) ==> sat(i, not(scheduler_action)); var a2 := naf[i2]; if (a2 != a0) { forall ensures d[i2 + 1] < d[i1] { forall ensures naf[i1] == a2 { var indF := imap i :: naf[i1] == naf[i]; forall i | TLe(i1, i) && TLe(i + 1, i2) && indF[i] ensures indF[i + 1] { assert sat(i, next_action); } Lemma_imapInductionRange(i1, i2, indF); } Lemma_mod_incr_decreases(a0, a2, n); } } assert sat(i1, eventuallynextwithin(or(goal, nextDecrease(i1, d)), span, timefun)); } assert sat(i0, always(nextOrDecreaseWithin(goal, d, span, timefun))); } Lemma_EventuallynextWithinSpans(i0, d, goal, span, timefun); Lemma_EventuallynextWithinBound(i0, d, n, goal, span, timefun); assert sat(i0, always(eventuallynextwithin(schedule[a0], span * n, timefun))); } } lemma Lemma_mod_incr_decreases(x:int, y:int, n:int) requires 0 <= x < n requires 0 <= y < n requires x != y ensures (x - ((y + 1) % n)) % n < (x - y) % n { lemma_mod_auto(n); } function{:opaque} SchedulerActsOrNextActionTypeUnchangedTemporal( behavior:Behavior, next_action_type_fun:imap, scheduler_action:temporal ):temporal requires forall i :: i in behavior // TODO: Replace with imaptotal requires imaptotal(next_action_type_fun) ensures forall i {:trigger sat(i, SchedulerActsOrNextActionTypeUnchangedTemporal(behavior, next_action_type_fun, scheduler_action))} :: sat(i, SchedulerActsOrNextActionTypeUnchangedTemporal(behavior, next_action_type_fun, scheduler_action)) <==> (sat(i, scheduler_action) || next_action_type_fun[i] == next_action_type_fun[i+1]) { stepmap(imap i :: sat(i, scheduler_action) || next_action_type_fun[i] == next_action_type_fun[i+1]) } lemma Lemma_RoundRobinSchedulerEventuallyPerformsNextAction( behavior:Behavior, next_action_type_fun:imap, scheduler_action:temporal, schedule:seq, start_step:int, earliest_step:int, action_type:int ) returns (action_step:int) requires imaptotal(behavior) requires imaptotal(next_action_type_fun) requires 0 <= start_step <= earliest_step requires 0 <= action_type < |schedule| requires next_action_type_fun[earliest_step] == action_type requires sat(0, always(SchedulerActsOrNextActionTypeUnchangedTemporal(behavior, next_action_type_fun, scheduler_action))) requires forall i {:trigger sat(i, scheduler_action)} :: 0 <= i && sat(i, scheduler_action) ==> var action_type_index := next_action_type_fun[i]; && (0 <= action_type_index < |schedule| ==> sat(i, schedule[action_type_index])) && next_action_type_fun[i+1] == (action_type_index + 1) % |schedule| requires sat(start_step, always(eventual(scheduler_action))) ensures earliest_step <= action_step ensures sat(action_step, schedule[action_type]) ensures next_action_type_fun[action_step+1] == (action_type + 1) % |schedule| { TemporalDeduceFromAlways(start_step, earliest_step, eventual(scheduler_action)); var later_action_step := TemporalDeduceFromEventual(earliest_step, scheduler_action); var P := stepmap(imap i :: next_action_type_fun[i] == action_type); var Q := and(schedule[action_type], next(stepmap(imap i :: next_action_type_fun[i] == (action_type + 1) % |schedule|))); forall j | earliest_step <= j ensures sat(j, TemporalWF1Req1(P, Q)) { TemporalDeduceFromAlways(0, j, SchedulerActsOrNextActionTypeUnchangedTemporal(behavior, next_action_type_fun, scheduler_action)); } action_step := TemporalWF1Specific(earliest_step, later_action_step, P, Q); } lemma Lemma_RoundRobinSchedulerEventuallyPerformsCertainNextAction( behavior:Behavior, next_action_type_fun:imap, scheduler_action:temporal, schedule:seq, start_step:int, earliest_step:int, next_action_type:int, action_type:int ) returns (action_step:int) requires imaptotal(behavior) requires imaptotal(next_action_type_fun) requires 0 <= start_step <= earliest_step requires 0 <= next_action_type < |schedule| requires 0 <= action_type < |schedule| requires next_action_type_fun[earliest_step] == next_action_type requires sat(0, always(SchedulerActsOrNextActionTypeUnchangedTemporal(behavior, next_action_type_fun, scheduler_action))) requires forall i {:trigger sat(i, scheduler_action)} :: 0 <= i && sat(i, scheduler_action) ==> var action_type_index := next_action_type_fun[i]; && (0 <= action_type_index < |schedule| ==> sat(i, schedule[action_type_index])) && next_action_type_fun[i+1] == (action_type_index + 1) % |schedule| requires sat(start_step, always(eventual(scheduler_action))) ensures earliest_step <= action_step ensures sat(action_step, schedule[action_type]) ensures next_action_type_fun[action_step+1] == (action_type + 1) % |schedule| decreases (|schedule| + action_type - next_action_type) % |schedule| { if action_type == next_action_type { action_step := Lemma_RoundRobinSchedulerEventuallyPerformsNextAction(behavior, next_action_type_fun, scheduler_action, schedule, start_step, earliest_step, action_type); return; } var earlier_action_step := Lemma_RoundRobinSchedulerEventuallyPerformsNextAction(behavior, next_action_type_fun, scheduler_action, schedule, start_step, earliest_step, next_action_type); lemma_mod_auto(|schedule|); action_step := Lemma_RoundRobinSchedulerEventuallyPerformsCertainNextAction(behavior, next_action_type_fun, scheduler_action, schedule, start_step, earlier_action_step + 1, (next_action_type + 1) % |schedule|, action_type); } lemma Lemma_RoundRobinSchedulerEventuallyPerformsSpecificAction( behavior:Behavior, // The behavior we'll prove it for next_action_type_fun:imap, // A function that takes a step and computes which action type has priority scheduler_action:temporal, // The subaction of 'next' that executes the scheduler schedule:seq, // The schedule the scheduler follows start_step:int, // The step at which the scheduler starts executing regularly earliest_step:int, // The step from which we need to find a subsequent step that takes the action action_type:int // The action type to find an action for ) returns (action_step:int) requires imaptotal(behavior) requires imaptotal(next_action_type_fun) // The priority starts as a valid value. Note that this also implies the schedule has at least one action. requires 0 <= next_action_type_fun[0] < |schedule| // The regular-execution period is sensible. requires 0 <= start_step // The requested parameters are sensible. requires start_step <= earliest_step requires 0 <= action_type < |schedule| // Every step either invokes the scheduler or leaves the action priority unchanged. requires sat(0, always(SchedulerActsOrNextActionTypeUnchangedTemporal(behavior, next_action_type_fun, scheduler_action))) // If the scheduler takes a step, it takes an action of the prioritized type, then gives // priority to the next action type in round-robin order. requires forall i {:trigger sat(i, scheduler_action)} :: 0 <= i && sat(i, scheduler_action) ==> var action_type_index := next_action_type_fun[i]; && (0 <= action_type_index < |schedule| ==> sat(i, schedule[action_type_index])) && next_action_type_fun[i+1] == (action_type_index + 1) % |schedule| // The scheduler takes at least one step every interval during the epoch during which it's regularly scheduled. requires sat(start_step, always(eventual(scheduler_action))) ensures earliest_step <= action_step ensures sat(action_step, schedule[action_type]) { var x := stepmap(imap i :: 0 <= next_action_type_fun[i] < |schedule|); forall i | 0 <= i ensures sat(i, imply(x, next(x))) { reveal imply(); reveal next(); TemporalDeduceFromAlways(0, i, SchedulerActsOrNextActionTypeUnchangedTemporal(behavior, next_action_type_fun, scheduler_action)); } TemporalInductionNext(0, x); TemporalDeduceFromAlways(0, earliest_step, x); var next_action_type := next_action_type_fun[earliest_step]; action_step := Lemma_RoundRobinSchedulerEventuallyPerformsCertainNextAction(behavior, next_action_type_fun, scheduler_action, schedule, start_step, earliest_step, next_action_type, action_type); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/Common/NodeIdentity.i.dfy ================================================ include "NodeIdentity.s.dfy" include "../../Common/Native/Io.s.dfy" module Concrete_NodeIdentity_i refines Common__NodeIdentity_s { import opened Native__Io_s export Spec provides NodeIdentity export reveals * type NodeIdentity = EndPoint } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/Common/NodeIdentity.s.dfy ================================================ abstract module Common__NodeIdentity_s { type NodeIdentity(==) } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/Common/UpperBound.s.dfy ================================================ module Common__UpperBound_s { datatype UpperBound = UpperBoundFinite(n:int) | UpperBoundInfinite() predicate LeqUpperBound(x:int, u:UpperBound) { match u case UpperBoundFinite(n) => x <= n case UpperBoundInfinite => true } predicate LtUpperBound(x:int, u:UpperBound) { match u case UpperBoundFinite(n) => x < n case UpperBoundInfinite => true } function UpperBoundedAddition(x:int, y:int, u:UpperBound):int { if LeqUpperBound(x + y, u) then x + y else u.n } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/LiveSHT/LivenessProof/Acks.i.dfy ================================================ include "Constants.i.dfy" include "Actions.i.dfy" include "PacketSending.i.dfy" module LivenessProof__Acks_i { import opened Concrete_NodeIdentity_i import opened Environment_s import opened LivenessProof__Actions_i import opened LivenessProof__Assumptions_i import opened LivenessProof__Constants_i import opened LivenessProof__PacketSending_i import opened LiveSHT__Environment_i import opened LiveSHT__SHT_i import opened LiveSHT__SHTRefinement_i import opened SHT__Configuration_i import opened SHT__SingleDelivery_i import opened Temporal__Temporal_s lemma Lemma_RecipientSequenceNumberMonotonicOneStep( b:Behavior, c:SHTConfiguration, i:int, sender:NodeIdentity, recipient_idx:int ) requires IsValidBehaviorPrefix(b, c, i+1); requires 0 <= i; requires 0 <= recipient_idx < |c.hostIds|; ensures 0 <= recipient_idx < |b[i].hosts|; ensures 0 <= recipient_idx < |b[i+1].hosts|; ensures TombstoneTableLookup(sender, b[i+1].hosts[recipient_idx].host.sd.receiveState) >= TombstoneTableLookup(sender, b[i].hosts[recipient_idx].host.sd.receiveState); { Lemma_ConstantsAllConsistent(b, c, i); Lemma_ConstantsAllConsistent(b, c, i+1); Lemma_AssumptionsMakeValidTransition(b, c, i); if b[i+1].hosts[recipient_idx] == b[i].hosts[recipient_idx] { return; } var ap := Lemma_ActionThatChangesHostIsThatHostsAction(b, c, i, recipient_idx); } lemma Lemma_RecipientSequenceNumberMonotonic( b:Behavior, c:SHTConfiguration, i:int, j:int, sender:NodeIdentity, recipient_idx:int ) requires IsValidBehaviorPrefix(b, c, j); requires 0 <= i <= j; requires 0 <= recipient_idx < |c.hostIds|; ensures 0 <= recipient_idx < |b[i].hosts|; ensures 0 <= recipient_idx < |b[j].hosts|; ensures TombstoneTableLookup(sender, b[j].hosts[recipient_idx].host.sd.receiveState) >= TombstoneTableLookup(sender, b[i].hosts[recipient_idx].host.sd.receiveState); { if i == j { Lemma_ConstantsAllConsistent(b, c, i); return; } Lemma_RecipientSequenceNumberMonotonic(b, c, i, j-1, sender, recipient_idx); Lemma_RecipientSequenceNumberMonotonicOneStep(b, c, j-1, sender, recipient_idx); } lemma Lemma_SenderSequenceNumberMonotonicOneStep( b:Behavior, c:SHTConfiguration, i:int, recipient:NodeIdentity, sender_idx:int ) requires IsValidBehaviorPrefix(b, c, i+1); requires 0 <= i; requires 0 <= sender_idx < |c.hostIds|; ensures 0 <= sender_idx < |b[i].hosts|; ensures 0 <= sender_idx < |b[i+1].hosts|; ensures AckStateLookup(recipient, b[i+1].hosts[sender_idx].host.sd.sendState).numPacketsAcked >= AckStateLookup(recipient, b[i].hosts[sender_idx].host.sd.sendState).numPacketsAcked; { Lemma_ConstantsAllConsistent(b, c, i); Lemma_ConstantsAllConsistent(b, c, i+1); Lemma_AssumptionsMakeValidTransition(b, c, i); if b[i+1].hosts[sender_idx] == b[i].hosts[sender_idx] { return; } var ap := Lemma_ActionThatChangesHostIsThatHostsAction(b, c, i, sender_idx); } lemma Lemma_SenderSequenceNumberMonotonic( b:Behavior, c:SHTConfiguration, i:int, j:int, recipient:NodeIdentity, sender_idx:int ) requires IsValidBehaviorPrefix(b, c, j); requires 0 <= i <= j; requires 0 <= sender_idx < |c.hostIds|; ensures 0 <= sender_idx < |b[i].hosts|; ensures 0 <= sender_idx < |b[j].hosts|; ensures AckStateLookup(recipient, b[j].hosts[sender_idx].host.sd.sendState).numPacketsAcked >= AckStateLookup(recipient, b[i].hosts[sender_idx].host.sd.sendState).numPacketsAcked; { if i == j { Lemma_ConstantsAllConsistent(b, c, i); return; } Lemma_SenderSequenceNumberMonotonic(b, c, i, j-1, recipient, sender_idx); Lemma_SenderSequenceNumberMonotonicOneStep(b, c, j-1, recipient, sender_idx); } lemma Lemma_AckPacketBeforeSenderSequenceNumber( b:Behavior, c:SHTConfiguration, i:int, src_idx:int, dst_idx:int, p:LSHTPacket ) requires IsValidBehaviorPrefix(b, c, i); requires 0 <= i; requires p in b[i].environment.sentPackets; requires p.msg.Ack?; requires 0 <= src_idx < |c.hostIds|; requires 0 <= dst_idx < |c.hostIds|; requires p.src == c.hostIds[dst_idx]; requires p.dst == c.hostIds[src_idx]; ensures 0 <= dst_idx < |b[i].hosts|; ensures TombstoneTableLookup(c.hostIds[src_idx], b[i].hosts[dst_idx].host.sd.receiveState) >= p.msg.ack_seqno; { if i == 0 { return; } Lemma_AssumptionsMakeValidTransition(b, c, i-1); Lemma_ConstantsAllConsistent(b, c, i-1); if p in b[i-1].environment.sentPackets { Lemma_AckPacketBeforeSenderSequenceNumber(b, c, i-1, src_idx, dst_idx, p); Lemma_RecipientSequenceNumberMonotonicOneStep(b, c, i-1, c.hostIds[src_idx], dst_idx); return; } var ap := Lemma_ActionThatSendsPacketIsActionOfSource(b, c, i-1, p); Lemma_GetHostIndexIsUnique(c, src_idx); Lemma_GetHostIndexIsUnique(c, dst_idx); } lemma Lemma_NumPacketsAckedBeforeRecipientSequenceNumber( b:Behavior, c:SHTConfiguration, i:int, src_idx:int, dst_idx:int ) requires IsValidBehaviorPrefix(b, c, i); requires 0 <= i; requires 0 <= src_idx < |c.hostIds|; requires 0 <= dst_idx < |c.hostIds|; ensures 0 <= src_idx < |b[i].hosts|; ensures 0 <= dst_idx < |b[i].hosts|; ensures TombstoneTableLookup(c.hostIds[src_idx], b[i].hosts[dst_idx].host.sd.receiveState) >= AckStateLookup(c.hostIds[dst_idx], b[i].hosts[src_idx].host.sd.sendState).numPacketsAcked; { if i == 0 { return; } Lemma_AssumptionsMakeValidTransition(b, c, i-1); Lemma_ConstantsAllConsistent(b, c, i-1); var src := c.hostIds[src_idx]; var dst := c.hostIds[dst_idx]; var host := b[i-1].hosts[src_idx].host; var host' := b[i].hosts[src_idx].host; Lemma_NumPacketsAckedBeforeRecipientSequenceNumber(b, c, i-1, src_idx, dst_idx); Lemma_RecipientSequenceNumberMonotonicOneStep(b, c, i-1, c.hostIds[src_idx], dst_idx); Lemma_GetHostIndexIsUnique(c, src_idx); Lemma_GetHostIndexIsUnique(c, dst_idx); if AckStateLookup(dst, host.sd.sendState).numPacketsAcked == AckStateLookup(dst, host'.sd.sendState).numPacketsAcked { return; } var ap := Lemma_ActionThatChangesHostIsThatHostsAction(b, c, i-1, src_idx); assert ap.nextActionIndex == 0; assert ap.ios[0].LIoOpReceive?; assert IsValidLIoOp(ap.ios[0], src, b[i-1].environment); Lemma_AckPacketBeforeSenderSequenceNumber(b, c, i, src_idx, dst_idx, ap.ios[0].r); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/LiveSHT/LivenessProof/Actions.i.dfy ================================================ include "Constants.i.dfy" include "../RefinementProof/SHTRefinement.i.dfy" module LivenessProof__Actions_i { import opened Collections__Maps2_s import opened Environment_s import opened LivenessProof__Assumptions_i import opened LivenessProof__Constants_i import opened LiveSHT__Environment_i import opened LiveSHT__EnvironmentRefinement_i import opened LiveSHT__Scheduler_i import opened LiveSHT__SHT_i import opened LiveSHT__SHTRefinement_i import opened SHT__Configuration_i import opened SHT__Host_i import opened SHT__Network_i import opened Temporal__Temporal_s predicate PacketProcessedViaIos( ps:LSHT_State, ps':LSHT_State, p:LSHTPacket, idx:int, ios:seq ) { |ios| > 0 && LIoOpReceive(p) == ios[0] && 0 <= idx < |ps.config.hostIds| && p.dst == ps.config.hostIds[idx] && ps.environment.nextStep == LEnvStepHostIos(p.dst, ios) && LSHT_NextOneHost(ps, ps', idx, ios) && LHost_ReceivePacket_Next(ps.hosts[idx].host, ps'.hosts[idx].host, ios) } predicate PacketProcessedDuringAction( ps:LSHT_State, p:LSHTPacket ) { ps.environment.nextStep.LEnvStepHostIos? && LIoOpReceive(p) in ps.environment.nextStep.ios } function{:opaque} PacketProcessedTemporal( b:Behavior, p:LSHTPacket ):temporal requires imaptotal(b); ensures forall i {:trigger sat(i, PacketProcessedTemporal(b, p))} :: sat(i, PacketProcessedTemporal(b, p)) <==> PacketProcessedDuringAction(b[i], p); { stepmap(imap i :: PacketProcessedDuringAction(b[i], p)) } predicate PacketSentDuringAction( ps:LSHT_State, p:LSHTPacket ) { ps.environment.nextStep.LEnvStepHostIos? && LIoOpSend(p) in ps.environment.nextStep.ios } function{:opaque} PacketSentTemporal( b:Behavior, p:LSHTPacket ):temporal requires imaptotal(b); ensures forall i {:trigger sat(i, PacketSentTemporal(b, p))} :: sat(i, PacketSentTemporal(b, p)) <==> PacketSentDuringAction(b[i], p); { stepmap(imap i :: PacketSentDuringAction(b[i], p)) } datatype SHTActionParams = SHTActionParams(idx:int, ios:seq, host:Host, host':Host, recv:set, out:set, nextActionIndex:int, resendCount:int, pkt:Packet, ack:Packet) predicate SHTActionOccurred(ss:LSHT_State, ss':LSHT_State, ap:SHTActionParams) { 0 <= ap.idx < |ss.hosts| && 0 <= ap.idx < |ss.config.hostIds| && 0 <= ap.idx < |ss'.hosts| && ss.environment.nextStep.LEnvStepHostIos? && ss.environment.nextStep.actor == ss.config.hostIds[ap.idx] && ss.environment.nextStep.ios == ap.ios && ap.host == ss.hosts[ap.idx].host && ap.host' == ss'.hosts[ap.idx].host && ap.recv == PacketsTo(LSHTEnvironment_Refine(ss.environment), ap.host.me) && ap.out == ExtractPacketsFromLSHTPackets(ExtractSentPacketsFromIos(ap.ios)) && ap.nextActionIndex == ss.hosts[ap.idx].nextActionIndex && ap.resendCount == ss'.hosts[ap.idx].resendCount && LScheduler_Next(ss.hosts[ap.idx], ss'.hosts[ap.idx], ap.ios) && GetHostIndex(ss.config.hostIds[ap.idx], ss.config) == ap.idx && ( ( ap.nextActionIndex == 0 && |ap.ios| == 1 && ap.ios[0].LIoOpTimeoutReceive? && ap.host == ap.host') || ( ap.nextActionIndex == 0 && |ap.ios| > 0 && ap.ios[0].LIoOpReceive? && (forall i{:trigger ap.ios[i].LIoOpSend?} :: 1 <= i < |ap.ios| ==> ap.ios[i].LIoOpSend?) && ap.pkt == LSHTPacketToPacket(ap.ios[0].r) && LSHT_NextOneHost(ss, ss', ap.idx, ap.ios) && Host_Next(ap.host, ap.host', ap.recv, ap.out) && ReceivePacket(ap.host, ap.host', ap.pkt, ap.out, ap.ack)) || ( ap.nextActionIndex == 1 && (forall io{:trigger io in ap.ios} :: io in ap.ios ==> io.LIoOpSend?) && LSHT_NextOneHost(ss, ss', ap.idx, ap.ios) && Host_Next(ap.host, ap.host', ap.recv, ap.out) && ProcessReceivedPacket(ap.host, ap.host', ap.out)) || ( ap.nextActionIndex == 2 && (forall io{:trigger io in ap.ios} :: io in ap.ios ==> io.LIoOpSend?) && LSHT_NextOneHost(ss, ss', ap.idx, ap.ios) && (if ap.resendCount != 0 then ap.host == ap.host' else Host_Next(ap.host, ap.host', ap.recv, ap.out) && SpontaneouslyRetransmit(ap.host, ap.host', ap.out)))) } lemma Lemma_NextActionIndexAlwaysWithinRange( b:Behavior, c:SHTConfiguration, i:int, idx:int ) requires IsValidBehaviorPrefix(b, c, i); requires 0 <= i; requires 0 <= idx < |b[i].hosts|; ensures 0 <= b[i].hosts[idx].nextActionIndex < 3; { if i == 0 { return; } Lemma_AssumptionsMakeValidTransition(b, c, i-1); Lemma_ConstantsAllConsistent(b, c, i-1); Lemma_ConstantsAllConsistent(b, c, i); Lemma_NextActionIndexAlwaysWithinRange(b, c, i-1, idx); } /////////////////////////////// // ACTION REFINEMENT /////////////////////////////// lemma Lemma_GetParametersOfAction0( b:Behavior, c:SHTConfiguration, i:int, idx:int ) returns (ap:SHTActionParams) requires IsValidBehaviorPrefix(b, c, i+1); requires 0 <= i; requires 0 <= idx < |b[i].hosts|; requires 0 <= idx < |c.hostIds|; requires b[i].environment.nextStep.LEnvStepHostIos?; requires b[i].environment.nextStep.actor == c.hostIds[idx]; requires b[i].hosts[idx].nextActionIndex == 0; ensures SHTActionOccurred(b[i], b[i+1], ap); ensures ap.idx == idx; ensures ap.nextActionIndex == 0; { Lemma_AssumptionsMakeValidTransition(b, c, i); Lemma_ConstantsAllConsistent(b, c, i); Lemma_ConstantsAllConsistent(b, c, i+1); var scheduler := b[i].hosts[idx]; var scheduler' := b[i+1].hosts[idx]; var host := scheduler.host; var host' := scheduler'.host; var recv := PacketsTo(LSHTEnvironment_Refine(b[i].environment), host.me); var resendCount := scheduler'.resendCount; Lemma_GetHostIndexIsUnique(b[i].config, idx); assert LSHT_Next(b[i], b[i+1]); //assert !LSHT_NextEnvironment(b[i], b[i+1]); assert !(exists idx, ios :: LSHT_NextExternal(b[i], b[i+1], idx, ios)); assert exists idx, ios :: LSHT_NextOneHost(b[i], b[i+1], idx, ios); var other_idx:int, ios:seq :| LSHT_NextOneHost(b[i], b[i+1], other_idx, ios); assert HostsDistinct(c.hostIds, idx, other_idx); var out := ExtractPacketsFromLSHTPackets(ExtractSentPacketsFromIos(ios)); assert out == ExtractPacketsFromLSHTPackets(ExtractSentPacketsFromIos(ios)); var pkt:Packet, ack:Packet; if ios[0].LIoOpTimeoutReceive? { } else { assert IsValidLIoOp(ios[0], host.me, b[i].environment); assert LHost_ReceivePacketWithoutReadingClock(host, host', ios); pkt := LSHTPacketToPacket(ios[0].r); ack :| ReceivePacket(host, host', pkt, out, ack); } ap := SHTActionParams(idx, ios, host, host', recv, out, 0, resendCount, pkt, ack); } lemma Lemma_GetParametersOfAction1( b:Behavior, c:SHTConfiguration, i:int, idx:int ) returns (ap:SHTActionParams) requires IsValidBehaviorPrefix(b, c, i+1); requires 0 <= i; requires 0 <= idx < |b[i].hosts|; requires 0 <= idx < |c.hostIds|; requires b[i].environment.nextStep.LEnvStepHostIos?; requires b[i].environment.nextStep.actor == c.hostIds[idx]; requires b[i].hosts[idx].nextActionIndex == 1; ensures SHTActionOccurred(b[i], b[i+1], ap); ensures ap.idx == idx; ensures ap.nextActionIndex == 1; { Lemma_AssumptionsMakeValidTransition(b, c, i); Lemma_ConstantsAllConsistent(b, c, i); Lemma_ConstantsAllConsistent(b, c, i+1); var scheduler := b[i].hosts[idx]; var scheduler' := b[i+1].hosts[idx]; var host := scheduler.host; var host' := scheduler'.host; var recv := PacketsTo(LSHTEnvironment_Refine(b[i].environment), host.me); var resendCount := scheduler'.resendCount; var pkt:Packet, ack:Packet; Lemma_GetHostIndexIsUnique(b[i].config, idx); var other_idx, ios :| LSHT_NextOneHost(b[i], b[i+1], other_idx, ios); assert HostsDistinct(c.hostIds, idx, other_idx); var out := LSHTIoSeq_RefineAsSends(ios); assert out == ExtractPacketsFromLSHTPackets(ExtractSentPacketsFromIos(ios)); ap := SHTActionParams(idx, ios, host, host', recv, out, 1, resendCount, pkt, ack); } lemma Lemma_GetParametersOfAction2( b:Behavior, c:SHTConfiguration, i:int, idx:int ) returns (ap:SHTActionParams) requires IsValidBehaviorPrefix(b, c, i+1); requires 0 <= i; requires 0 <= idx < |b[i].hosts|; requires 0 <= idx < |c.hostIds|; requires b[i].environment.nextStep.LEnvStepHostIos?; requires b[i].environment.nextStep.actor == c.hostIds[idx]; requires b[i].hosts[idx].nextActionIndex == 2; ensures SHTActionOccurred(b[i], b[i+1], ap); ensures ap.idx == idx; ensures ap.nextActionIndex == 2; { Lemma_AssumptionsMakeValidTransition(b, c, i); Lemma_ConstantsAllConsistent(b, c, i); Lemma_ConstantsAllConsistent(b, c, i+1); var scheduler := b[i].hosts[idx]; var scheduler' := b[i+1].hosts[idx]; var host := scheduler.host; var host' := scheduler'.host; var recv := PacketsTo(LSHTEnvironment_Refine(b[i].environment), host.me); var resendCount := scheduler'.resendCount; var pkt:Packet, ack:Packet; Lemma_GetHostIndexIsUnique(b[i].config, idx); var other_idx, ios :| LSHT_NextOneHost(b[i], b[i+1], other_idx, ios); assert HostsDistinct(c.hostIds, idx, other_idx); var out := LSHTIoSeq_RefineAsSends(ios); assert out == ExtractPacketsFromLSHTPackets(ExtractSentPacketsFromIos(ios)); ap := SHTActionParams(idx, ios, host, host', recv, out, 2, resendCount, pkt, ack); assert ap.nextActionIndex == 2; if ap.resendCount != 0 { assert ap.host == ap.host'; } else { assert SpontaneouslyRetransmit(ap.host, ap.host', ap.out); } } lemma Lemma_GetParametersOfAction( b:Behavior, c:SHTConfiguration, i:int ) returns (ap:SHTActionParams) requires IsValidBehaviorPrefix(b, c, i+1); requires 0 <= i; requires b[i].environment.nextStep.LEnvStepHostIos?; requires b[i].environment.nextStep.actor in b[i].config.hostIds; ensures SHTActionOccurred(b[i], b[i+1], ap); { Lemma_AssumptionsMakeValidTransition(b, c, i); Lemma_ConstantsAllConsistent(b, c, i); Lemma_ConstantsAllConsistent(b, c, i+1); var idx, ios :| LSHT_NextOneHost(b[i], b[i+1], idx, ios); Lemma_GetHostIndexIsUnique(b[i].config, idx); var scheduler := b[i].hosts[idx]; var nextActionIndex := scheduler.nextActionIndex; Lemma_NextActionIndexAlwaysWithinRange(b, c, i, idx); if nextActionIndex == 0 { ap := Lemma_GetParametersOfAction0(b, c, i, idx); } else if nextActionIndex == 1 { ap := Lemma_GetParametersOfAction1(b, c, i, idx); } else if nextActionIndex == 2 { ap := Lemma_GetParametersOfAction2(b, c, i, idx); } else { assert false; } } lemma Lemma_ActionThatChangesHostIsThatHostsAction( b:Behavior, c:SHTConfiguration, i:int, host_index:int ) returns (ap:SHTActionParams) requires IsValidBehaviorPrefix(b, c, i+1); requires 0 <= i; requires 0 <= host_index < |b[i].hosts|; requires 0 <= host_index < |b[i+1].hosts|; requires b[i+1].hosts[host_index] != b[i].hosts[host_index]; ensures SHTActionOccurred(b[i], b[i+1], ap); ensures ap.idx == host_index; ensures LSHT_Next(b[i], b[i+1]); ensures LSHT_NextOneHost(b[i], b[i+1], host_index, ap.ios); { Lemma_AssumptionsMakeValidTransition(b, c, i); Lemma_ConstantsAllConsistent(b, c, i); ap := Lemma_GetParametersOfAction(b, c, i); Lemma_GetHostIndexIsUnique(c, host_index); } lemma Lemma_PacketProcessedImpliesPacketSent( ps:LSHT_State, ps':LSHT_State, idx:int, ios:seq, inp:LSHTPacket ) requires LSHT_NextOneHost(ps, ps', idx, ios); requires LIoOpReceive(inp) in ios; ensures inp in ps.environment.sentPackets; { var id := ps.config.hostIds[idx]; var e := ps.environment; var e' := ps'.environment; assert IsValidLIoOp(LIoOpReceive(inp), id, ps.environment); assert inp in e.sentPackets; } lemma Lemma_PacketProcessedImpliesPacketSentAlt( b:Behavior, c:SHTConfiguration, i:int, idx:int, inp:LSHTPacket ) requires IsValidBehaviorPrefix(b, c, i+1); requires 0 <= i; requires 0 <= idx < |c.hostIds|; requires b[i].environment.nextStep.LEnvStepHostIos?; requires b[i].environment.nextStep.actor == c.hostIds[idx]; requires LIoOpReceive(inp) in b[i].environment.nextStep.ios; ensures inp in b[i].environment.sentPackets; { var ps := b[i]; var ps' := b[i+1]; Lemma_AssumptionsMakeValidTransition(b, c, i); Lemma_ConstantsAllConsistent(b, c, i); var id := ps.config.hostIds[idx]; var e := ps.environment; var e' := ps'.environment; assert IsValidLIoOp(LIoOpReceive(inp), id, ps.environment); assert inp in e.sentPackets; } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/LiveSHT/LivenessProof/Assumptions.i.dfy ================================================ include "../RefinementProof/SHT.i.dfy" include "../../../Common/Framework/EnvironmentSynchrony.s.dfy" module LivenessProof__Assumptions_i { import opened Concrete_NodeIdentity_i import opened Environment_s import opened EnvironmentSynchrony_s import opened LiveSHT__Environment_i import opened LiveSHT__Scheduler_i import opened LiveSHT__SHT_i import opened SHT__Configuration_i import opened SHT__Message_i import opened SHT__SingleMessage_i import opened Temporal__Temporal_s import opened Collections__Maps2_s /////////////////////// // TYPES /////////////////////// type LSHTMessage = SingleMessage datatype AssumptionParameters = AssumptionParameters(c:SHTConfiguration) /////////////////////// // HELPERS /////////////////////// function{:opaque} RestrictBehaviorToEnvironment( b:Behavior ):Behavior> requires imaptotal(b); ensures imaptotal(RestrictBehaviorToEnvironment(b)); ensures forall i {:trigger RestrictBehaviorToEnvironment(b)[i]} :: RestrictBehaviorToEnvironment(b)[i] == b[i].environment; { imap i :: b[i].environment } predicate IsValidBehaviorPrefix( b:Behavior, c:SHTConfiguration, i:int ) { imaptotal(b) && LSHT_Init(c, b[0]) && (forall j {:trigger LSHT_Next(b[j], b[j+1])} :: 0 <= j < i ==> LSHT_Next(b[j], b[j+1])) } predicate IsValidBehavior( b:Behavior, c:SHTConfiguration ) { imaptotal(b) && LSHT_Init(c, b[0]) && (forall i {:trigger LSHT_Next(b[i], b[i+1])} :: i >= 0 ==> LSHT_Next(b[i], b[i+1])) } predicate LSHTHostTakesAction( ps:LSHT_State, ps':LSHT_State, host_index:int ) { ps.environment.nextStep.LEnvStepHostIos? && 0 <= host_index < |ps.config.hostIds| && ps.environment.nextStep.actor == ps.config.hostIds[host_index] && var ios := ps.environment.nextStep.ios; LSHT_NextOneHost(ps, ps', host_index, ios) && LScheduler_Next(ps.hosts[host_index], ps'.hosts[host_index], ios) } function{:opaque} LSHTHostTakesActionTemporal( b:Behavior, host_index:int ):temporal requires imaptotal(b); ensures forall i {:trigger sat(i, LSHTHostTakesActionTemporal(b, host_index))} :: sat(i, LSHTHostTakesActionTemporal(b, host_index)) <==> LSHTHostTakesAction(b[i], b[i+1], host_index); { stepmap(imap i :: LSHTHostTakesAction(b[i], b[i+1], host_index)) } function AllShardPacketsSent(packets:set):set { set p | p in packets && p.msg.SingleMessage? && p.msg.m.Shard? } /////////////////////// // ASSUMPTIONS /////////////////////// function{:opaque} PacketSentBetweenHostsTemporal( b:Behavior>, p:LPacket, sources:set, destinations:set ):temporal requires imaptotal(b); ensures forall i {:trigger sat(i, PacketSentBetweenHostsTemporal(b, p, sources, destinations))} :: sat(i, PacketSentBetweenHostsTemporal(b, p, sources, destinations)) <==> PacketSentBetweenHosts(b[i], p, sources, destinations); { stepmap(imap i :: PacketSentBetweenHosts(b[i], p, sources, destinations)) } function SeqToSet(xs:seq) : set { set x | x in xs } predicate NetworkWeaklyFair( b:Behavior>, hosts:seq ) requires imaptotal(b); { var host_set := SeqToSet(hosts); forall p :: sat(0, always(imply(always(eventual(PacketSentBetweenHostsTemporal(b, p, host_set, host_set))), eventual(PacketDeliveredTemporal(b, p))))) } /////////////////////////// // TOP-LEVEL ASSUMPTIONS /////////////////////////// predicate LivenessAssumptions( b:Behavior, asp:AssumptionParameters ) { IsValidBehavior(b, asp.c) && var eb := RestrictBehaviorToEnvironment(b); HostQueuesLive(eb) // Each host executes its scheduler infinitely often && (forall host_index :: 0 <= host_index < |asp.c.hostIds| ==> sat(0, always(eventual(LSHTHostTakesActionTemporal(b, host_index))))) // Admin doesn't send too many shard requests && (forall step :: 0 <= step ==> |AllShardPacketsSent(b[step].environment.sentPackets)| < asp.c.params.max_delegations - 4) // Messages sent infinitely often are delivered infinitely often //&& sat(0, always(NetworkWeaklyFairTemporal(eb, asp.c.hostIds))) && NetworkWeaklyFair(eb, asp.c.hostIds) } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/LiveSHT/LivenessProof/Constants.i.dfy ================================================ include "../../../Common/Logic/Temporal/Rules.i.dfy" include "Assumptions.i.dfy" module LivenessProof__Constants_i { import opened LivenessProof__Assumptions_i import opened LiveSHT__SHT_i import opened SHT__Configuration_i import opened Temporal__Rules_i import opened Temporal__Temporal_s /////////////////////////////// // INVARIANT LEMMAS /////////////////////////////// lemma Lemma_AssumptionsMakeValidTransition( b:Behavior, c:SHTConfiguration, i:int ) requires IsValidBehaviorPrefix(b, c, i+1); requires 0 <= i; ensures LSHT_Next(b[i], b[i+1]); { } lemma Lemma_HostConstantsAllConsistent( b:Behavior, c:SHTConfiguration, i:int, idx:int ) requires IsValidBehaviorPrefix(b, c, i); requires 0 <= i; requires 0 <= idx < |b[i].hosts| || 0 <= idx < |c.hostIds| || 0 <= idx < |b[i].config.hostIds|; ensures b[i].config == c; ensures |b[i].config.hostIds| == |b[i].hosts|; ensures var s := b[i].hosts[idx].host; s.me == c.hostIds[idx] && s.constants.rootIdentity == c.rootIdentity && s.constants.hostIds == c.hostIds && s.constants.params == c.params { if i > 0 { Lemma_AssumptionsMakeValidTransition(b, c, i - 1); Lemma_HostConstantsAllConsistent(b, c, i-1, idx); } } lemma Lemma_ConstantsAllConsistent( b:Behavior, c:SHTConfiguration, i:int ) requires IsValidBehaviorPrefix(b, c, i); requires 0 <= i; ensures b[i].config == c; ensures |b[i].config.hostIds| == |b[i].hosts|; ensures forall idx :: 0 <= idx < |c.hostIds| ==> var s := b[i].hosts[idx].host; s.me == c.hostIds[idx] && s.constants.rootIdentity == c.rootIdentity && s.constants.hostIds == c.hostIds && s.constants.params == c.params; { if i > 0 { Lemma_AssumptionsMakeValidTransition(b, c, i - 1); Lemma_ConstantsAllConsistent(b, c, i-1); } forall idx | 0 <= idx < |c.hostIds| ensures var s := b[i].hosts[idx].host; s.me == c.hostIds[idx] && s.constants.rootIdentity == c.rootIdentity && s.constants.hostIds == c.hostIds && s.constants.params == c.params; { Lemma_HostConstantsAllConsistent(b, c, i, idx); } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/LiveSHT/LivenessProof/Environment.i.dfy ================================================ include "Invariants.i.dfy" include "RoundRobin.i.dfy" include "Constants.i.dfy" include "RefinementInvariants.i.dfy" include "../../../Common/Logic/Temporal/WF1.i.dfy" module LivenessProof__Environment_i { import opened Environment_s import opened EnvironmentSynchrony_s import opened LivenessProof__Assumptions_i import opened LivenessProof__Constants_i import opened LivenessProof__Invariants_i import opened LivenessProof__RefinementInvariants_i import opened LivenessProof__RoundRobin_i import opened LiveSHT__Environment_i import opened LiveSHT__SHT_i import opened SHT__Configuration_i import opened Temporal__Rules_i import opened Temporal__Temporal_s import opened Temporal__WF1_i lemma Lemma_AssumptionsMakeValidEnvironmentBehavior( b:Behavior, c:SHTConfiguration ) requires IsValidBehavior(b, c); ensures LEnvironment_BehaviorSatisfiesSpec(RestrictBehaviorToEnvironment(b)); { var eb := RestrictBehaviorToEnvironment(b); var x := EnvironmentNextTemporal(eb); forall i | i >= 0 ensures sat(i, x); { Lemma_AssumptionsMakeValidTransition(b, c, i); assert LEnvironment_Next(eb[i], eb[i+1]); } TemporalAlways(0, x); assert LEnvironment_Init(eb[0]); assert LEnvironment_BehaviorSatisfiesSpec(eb); } lemma Lemma_PacketStaysInSentPackets( b:Behavior, c:SHTConfiguration, i:int, j:int, p:LSHTPacket ) requires IsValidBehaviorPrefix(b, c, j); requires 0 <= i <= j; requires p in b[i].environment.sentPackets; ensures p in b[j].environment.sentPackets; { if j == i { } else { Lemma_PacketStaysInSentPackets(b, c, i, j-1, p); Lemma_AssumptionsMakeValidTransition(b, c, j-1); } } lemma Lemma_PositionOfPacketInHostQueueEventuallyDecreasesByOne( b:Behavior, asp:AssumptionParameters, current_step:int, host_idx:int, p:LSHTPacket, pos:int ) returns (next_step:int) requires LivenessAssumptions(b, asp); requires 0 <= current_step; requires 0 <= host_idx < |asp.c.hostIds|; requires asp.c.hostIds[host_idx] in b[current_step].environment.hostInfo; requires 1 <= pos < |b[current_step].environment.hostInfo[asp.c.hostIds[host_idx]].queue|; requires p == b[current_step].environment.hostInfo[asp.c.hostIds[host_idx]].queue[pos]; ensures current_step <= next_step; ensures asp.c.hostIds[host_idx] in b[next_step].environment.hostInfo; ensures pos-1 < |b[next_step].environment.hostInfo[asp.c.hostIds[host_idx]].queue|; ensures p == b[next_step].environment.hostInfo[asp.c.hostIds[host_idx]].queue[pos-1]; { var host := asp.c.hostIds[host_idx]; var P := stepmap(imap i :: host in b[i].environment.hostInfo && |b[i].environment.hostInfo[host].queue| > pos && p == b[i].environment.hostInfo[host].queue[pos]); var Q := stepmap(imap i :: host in b[i].environment.hostInfo && |b[i].environment.hostInfo[host].queue| > pos-1 && p == b[i].environment.hostInfo[host].queue[pos-1]); var action_step := Lemma_HostNextPerformsSubactionEventually(b, asp, host_idx, current_step, 0); forall j | current_step <= j ensures sat(j, TemporalWF1Req1(P, Q)); { Lemma_EffectOfNextOnHostQueue(b, asp, j, host_idx); } forall ensures sat(action_step, imply(P, or(Q, next(Q)))) { if sat(action_step, P) { Lemma_ConstantsAllConsistent(b, asp.c, action_step); var ios := b[action_step].environment.nextStep.ios; var hostQueue := if host in b[action_step].environment.hostInfo then b[action_step].environment.hostInfo[host].queue else []; var hostQueue' := if host in b[action_step+1].environment.hostInfo then b[action_step+1].environment.hostInfo[host].queue else []; Lemma_HostQueuesNext(b, asp, action_step); assert HostQueue_PerformIos(hostQueue, hostQueue', ios); assert |ios| > 0; if ios[0].LIoOpTimeoutReceive? { assert false; } else { assert ios[0].LIoOpReceive?; assert |ios| == 1 || (ios[1] in ios /* trigger */ && !ios[1].LIoOpReceive?); assert HostQueue_PerformIos(hostQueue[1..], hostQueue', ios[1..]); assert hostQueue[1..] == hostQueue'; } assert sat(action_step+1, Q); } } next_step := TemporalWF1Specific(current_step, action_step, P, Q); } lemma Lemma_PositionOfPacketInHostQueueEventuallyDecreasesToZero( b:Behavior, asp:AssumptionParameters, current_step:int, host_idx:int, p:LSHTPacket, pos:int ) returns (next_step:int) requires LivenessAssumptions(b, asp); requires 0 <= current_step; requires 0 <= host_idx < |asp.c.hostIds|; requires asp.c.hostIds[host_idx] in b[current_step].environment.hostInfo; requires 0 <= pos < |b[current_step].environment.hostInfo[asp.c.hostIds[host_idx]].queue|; requires p == b[current_step].environment.hostInfo[asp.c.hostIds[host_idx]].queue[pos]; ensures current_step <= next_step; ensures asp.c.hostIds[host_idx] in b[next_step].environment.hostInfo; ensures 0 < |b[next_step].environment.hostInfo[asp.c.hostIds[host_idx]].queue|; ensures p == b[next_step].environment.hostInfo[asp.c.hostIds[host_idx]].queue[0]; decreases pos; { if pos == 0 { next_step := current_step; } else { var intermediate_step := Lemma_PositionOfPacketInHostQueueEventuallyDecreasesByOne(b, asp, current_step, host_idx, p, pos); next_step := Lemma_PositionOfPacketInHostQueueEventuallyDecreasesToZero(b, asp, intermediate_step, host_idx, p, pos-1); } } lemma Lemma_PacketInHostQueueEventuallyAtFrontOfHostQueue( b:Behavior, asp:AssumptionParameters, current_step:int, host_idx:int, p:LSHTPacket ) returns (next_step:int) requires LivenessAssumptions(b, asp); requires 0 <= current_step; requires 0 <= host_idx < |asp.c.hostIds|; requires asp.c.hostIds[host_idx] in b[current_step].environment.hostInfo; requires p in b[current_step].environment.hostInfo[asp.c.hostIds[host_idx]].queue; ensures current_step <= next_step; ensures asp.c.hostIds[host_idx] in b[next_step].environment.hostInfo; ensures 0 < |b[next_step].environment.hostInfo[asp.c.hostIds[host_idx]].queue|; ensures p == b[next_step].environment.hostInfo[asp.c.hostIds[host_idx]].queue[0]; { var host := asp.c.hostIds[host_idx]; var queue := b[current_step].environment.hostInfo[host].queue; var pos :| 0 <= pos < |queue| && queue[pos] == p; next_step := Lemma_PositionOfPacketInHostQueueEventuallyDecreasesToZero(b, asp, current_step, host_idx, p, pos); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/LiveSHT/LivenessProof/InfiniteSends.i.dfy ================================================ include "PacketReceipt.i.dfy" include "Acks.i.dfy" include "RefinementInvariants.i.dfy" module LivenessProof__InfiniteSends_i { import opened Collections__Maps2_s import opened Environment_s import opened LivenessProof__Acks_i import opened LivenessProof__Actions_i import opened LivenessProof__Assumptions_i import opened LivenessProof__Constants_i import opened LivenessProof__PacketReceipt_i import opened LivenessProof__RefinementInvariants_i import opened LivenessProof__RoundRobin_i import opened LiveSHT__Scheduler_i import opened LiveSHT__SHT_i import opened LiveSHT__SHTRefinement_i import opened Math__mod_auto_i import opened SHT__Configuration_i import opened SHT__Host_i import opened SHT__Message_i import opened SHT__Network_i import opened SHT__SingleDelivery_i import opened SHT__SingleMessage_i import opened Temporal__Rules_i import opened Temporal__Temporal_s import opened Temporal__WF1_i predicate RecipientSequenceNumberBelow( ss:LSHT_State, src_idx:int, dst_idx:int, seqno:int ) { 0 <= src_idx < |ss.config.hostIds| && 0 <= dst_idx < |ss.config.hostIds| && 0 <= dst_idx < |ss.hosts| && TombstoneTableLookup(ss.config.hostIds[src_idx], ss.hosts[dst_idx].host.sd.receiveState) < seqno } function RecipientSequenceNumberBelowTemporal( b:Behavior, src_idx:int, dst_idx:int, seqno:int ):temporal requires imaptotal(b); ensures forall i{:trigger sat(i, RecipientSequenceNumberBelowTemporal(b, src_idx, dst_idx, seqno))} :: sat(i, RecipientSequenceNumberBelowTemporal(b, src_idx, dst_idx, seqno)) <==> RecipientSequenceNumberBelow(b[i], src_idx, dst_idx, seqno); { stepmap(imap i :: RecipientSequenceNumberBelow(b[i], src_idx, dst_idx, seqno)) } lemma Lemma_TruncateUnAckListDoesntRemoveHigherSeqno( unAcked:seq>, seqnoAcked:nat, unAcked':seq>, m:SingleMessage ) requires unAcked' == TruncateUnAckList(unAcked, seqnoAcked); requires m in unAcked; requires m.SingleMessage?; requires m.seqno > seqnoAcked; ensures m in unAcked'; { if |unAcked| > 0 && unAcked[0].SingleMessage? && unAcked[0].seqno <= seqnoAcked { assert m != unAcked[0]; assert m in unAcked[1..]; Lemma_TruncateUnAckListDoesntRemoveHigherSeqno(unAcked[1..], seqnoAcked, unAcked', m); } } lemma Lemma_IfRecipientSequenceNumberNeverBeyondThenPacketStaysInSendStateOneStep( b:Behavior, asp:AssumptionParameters, i:int, src_idx:int, dst_idx:int, m:SingleMessage ) requires LivenessAssumptions(b, asp); requires 0 <= src_idx < |asp.c.hostIds|; requires 0 <= dst_idx < |asp.c.hostIds|; requires 0 <= src_idx < |b[i].hosts|; requires 0 <= i; requires m.SingleMessage?; requires m.dst == asp.c.hostIds[dst_idx]; requires sat(i, always(RecipientSequenceNumberBelowTemporal(b, src_idx, dst_idx, m.seqno))); requires m.dst in b[i].hosts[src_idx].host.sd.sendState; requires m in b[i].hosts[src_idx].host.sd.sendState[m.dst].unAcked; ensures 0 <= src_idx < |b[i+1].hosts|; ensures m.dst in b[i+1].hosts[src_idx].host.sd.sendState; ensures m in b[i+1].hosts[src_idx].host.sd.sendState[m.dst].unAcked; { Lemma_AssumptionsMakeValidTransition(b, asp.c, i); Lemma_ConstantsAllConsistent(b, asp.c, i); var src := asp.c.hostIds[src_idx]; var dst := asp.c.hostIds[dst_idx]; Lemma_GetHostIndexIsUnique(asp.c, src_idx); Lemma_GetHostIndexIsUnique(asp.c, dst_idx); var host := b[i].hosts[src_idx].host; var host' := b[i+1].hosts[src_idx].host; TemporalDeduceFromAlways(i, i, RecipientSequenceNumberBelowTemporal(b, src_idx, dst_idx, m.seqno)); Lemma_NumPacketsAckedBeforeRecipientSequenceNumber(b, asp.c, i, src_idx, dst_idx); assert AckStateLookup(dst, host.sd.sendState).numPacketsAcked < m.seqno; TemporalDeduceFromAlways(i, i+1, RecipientSequenceNumberBelowTemporal(b, src_idx, dst_idx, m.seqno)); Lemma_NumPacketsAckedBeforeRecipientSequenceNumber(b, asp.c, i+1, src_idx, dst_idx); assert AckStateLookup(dst, host'.sd.sendState).numPacketsAcked < m.seqno; assert dst in host'.sd.sendState; if m in host'.sd.sendState[dst].unAcked { return; } var ap := Lemma_ActionThatChangesHostIsThatHostsAction(b, asp.c, i, src_idx); var pos :| 0 <= pos < |host.sd.sendState[dst].unAcked| && m == host.sd.sendState[dst].unAcked[pos]; assert ap.nextActionIndex == 0; assert ap.ios[0].LIoOpReceive?; assert ap.ios[0].r.msg.Ack?; assert ReceiveAck(host.sd, host'.sd, ap.pkt, ap.out); assert host'.sd.sendState[dst].unAcked == TruncateUnAckList(host.sd.sendState[dst].unAcked, host'.sd.sendState[dst].numPacketsAcked); Lemma_TruncateUnAckListDoesntRemoveHigherSeqno(host.sd.sendState[dst].unAcked, host'.sd.sendState[dst].numPacketsAcked, host'.sd.sendState[dst].unAcked, m); } lemma Lemma_IfRecipientSequenceNumberNeverBeyondThenPacketStaysInSendState( b:Behavior, asp:AssumptionParameters, i:int, j:int, src_idx:int, dst_idx:int, m:SingleMessage ) requires LivenessAssumptions(b, asp); requires 0 <= src_idx < |asp.c.hostIds|; requires 0 <= dst_idx < |asp.c.hostIds|; requires 0 <= src_idx < |b[i].hosts|; requires 0 <= i <= j; requires m.SingleMessage?; requires m.dst == asp.c.hostIds[dst_idx]; requires sat(i, always(RecipientSequenceNumberBelowTemporal(b, src_idx, dst_idx, m.seqno))); requires m.dst in b[i].hosts[src_idx].host.sd.sendState; requires m in b[i].hosts[src_idx].host.sd.sendState[m.dst].unAcked; ensures 0 <= src_idx < |b[j].hosts|; ensures m.dst in b[j].hosts[src_idx].host.sd.sendState; ensures m in b[j].hosts[src_idx].host.sd.sendState[m.dst].unAcked; { if i == j { return; } Lemma_IfRecipientSequenceNumberNeverBeyondThenPacketStaysInSendState(b, asp, i, j-1, src_idx, dst_idx, m); Lemma_AlwaysImpliesLaterAlways(i, j-1, RecipientSequenceNumberBelowTemporal(b, src_idx, dst_idx, m.seqno)); Lemma_IfRecipientSequenceNumberNeverBeyondThenPacketStaysInSendStateOneStep(b, asp, j-1, src_idx, dst_idx, m); } lemma Lemma_ResendCountAlwaysWithinRange( b:Behavior, c:SHTConfiguration, i:int, idx:int ) requires IsValidBehaviorPrefix(b, c, i); requires 0 <= i; requires 0 <= idx < |c.hostIds|; ensures 0 <= idx < |b[i].hosts|; ensures 0 <= b[i].hosts[idx].resendCount < 100000000; { if i == 0 { return; } Lemma_AssumptionsMakeValidTransition(b, c, i-1); Lemma_ConstantsAllConsistent(b, c, i-1); Lemma_ConstantsAllConsistent(b, c, i); Lemma_ResendCountAlwaysWithinRange(b, c, i-1, idx); var s := b[i-1].hosts[idx]; var s' := b[i].hosts[idx]; if s'.resendCount == s.resendCount { return; } var ap := Lemma_ActionThatChangesHostIsThatHostsAction(b, c, i-1, idx); assert LScheduler_Next(b[i-1].hosts[idx], b[i].hosts[idx], ap.ios); assert s'.resendCount == (s.resendCount + 1) % 100000000; lemma_mod_auto(100000000); } lemma Lemma_HostPerformsMaybeResendPacketsEventually( b:Behavior, asp:AssumptionParameters, current_step:int, idx:int, resendCount:int ) returns (resend_step:int, ap:SHTActionParams) requires LivenessAssumptions(b, asp); requires 0 <= current_step; requires 0 <= idx < |asp.c.hostIds|; requires 0 <= idx < |b[current_step].hosts|; requires b[current_step].hosts[idx].resendCount == resendCount; requires 0 <= resendCount < 100000000; ensures current_step <= resend_step; ensures SHTActionOccurred(b[resend_step], b[resend_step+1], ap); ensures ap.idx == idx; ensures ap.nextActionIndex == 2; ensures ap.resendCount == (resendCount + 1) % 100000000; { var id := asp.c.hostIds[idx]; Lemma_GetHostIndexIsUnique(asp.c, idx); var action_step := Lemma_HostNextPerformsSubactionEventually(b, asp, idx, current_step, 2); var P := stepmap(imap i :: 0 <= idx < |b[i].hosts| && b[i].hosts[idx].resendCount == resendCount); var Q := stepmap(imap i :: 0 <= idx < |b[i].hosts| && b[i].environment.nextStep.LEnvStepHostIos? && b[i].environment.nextStep.actor == id && b[i].hosts[idx].nextActionIndex == 2 && b[i].hosts[idx].resendCount == resendCount); if sat(action_step, P) { var ap_local := Lemma_GetParametersOfAction(b, asp.c, action_step); Lemma_ConstantsAllConsistent(b, asp.c, action_step); assert sat(action_step, Q); } assert sat(action_step, imply(P, or(Q, next(Q)))); forall j | current_step <= j ensures sat(j, TemporalWF1Req1(P, Q)); { Lemma_ConstantsAllConsistent(b, asp.c, j); Lemma_ConstantsAllConsistent(b, asp.c, j+1); if sat(j, P) && !sat(j+1, P) && !sat(j, Q) { var ap_local := Lemma_ActionThatChangesHostIsThatHostsAction(b, asp.c, j, idx); assert false; } } resend_step := TemporalWF1Specific(current_step, action_step, P, Q); Lemma_ConstantsAllConsistent(b, asp.c, resend_step); ap := Lemma_GetParametersOfAction(b, asp.c, resend_step); } lemma Lemma_HostPerformsResendPacketsEventually( b:Behavior, asp:AssumptionParameters, current_step:int, idx:int ) returns (resend_step:int, ap:SHTActionParams) requires LivenessAssumptions(b, asp); requires 0 <= current_step; requires 0 <= idx < |asp.c.hostIds|; ensures current_step <= resend_step; ensures SHTActionOccurred(b[resend_step], b[resend_step+1], ap); ensures ap.idx == idx; ensures ap.nextActionIndex == 2; ensures ap.resendCount == 0; decreases 100000000 - (if 0 <= idx < |b[current_step].hosts| then b[current_step].hosts[idx].resendCount else 0); { Lemma_ConstantsAllConsistent(b, asp.c, current_step); var resendCount := b[current_step].hosts[idx].resendCount; Lemma_ResendCountAlwaysWithinRange(b, asp.c, current_step, idx); if resendCount == 100000000-1 { resend_step, ap := Lemma_HostPerformsMaybeResendPacketsEventually(b, asp, current_step, idx, resendCount); } else { var try_resend_step, try_ap := Lemma_HostPerformsMaybeResendPacketsEventually(b, asp, current_step, idx, resendCount); lemma_mod_auto(100000000); resend_step, ap := Lemma_HostPerformsResendPacketsEventually(b, asp, try_resend_step + 1, idx); } } lemma Lemma_IfRecipientSequenceNumberNeverBeyondThenPacketEventuallySent( b:Behavior, asp:AssumptionParameters, current_step:int, src_idx:int, dst_idx:int, m:SingleMessage ) returns (resend_step:int, ap:SHTActionParams) requires LivenessAssumptions(b, asp); requires 0 <= src_idx < |asp.c.hostIds|; requires 0 <= dst_idx < |asp.c.hostIds|; requires 0 <= src_idx < |b[current_step].hosts|; requires 0 <= current_step; requires m.SingleMessage?; requires m.dst == asp.c.hostIds[dst_idx]; requires sat(current_step, always(RecipientSequenceNumberBelowTemporal(b, src_idx, dst_idx, m.seqno))); requires m.dst in b[current_step].hosts[src_idx].host.sd.sendState; requires m in b[current_step].hosts[src_idx].host.sd.sendState[m.dst].unAcked; ensures current_step <= resend_step; ensures SHTActionOccurred(b[resend_step], b[resend_step+1], ap); ensures LIoOpSend(LPacket(m.dst, asp.c.hostIds[src_idx], m)) in ap.ios; { resend_step, ap := Lemma_HostPerformsResendPacketsEventually(b, asp, current_step, src_idx); Lemma_GetHostIndexIsUnique(asp.c, ap.idx); Lemma_GetHostIndexIsUnique(asp.c, src_idx); Lemma_IfRecipientSequenceNumberNeverBeyondThenPacketStaysInSendState(b, asp, current_step, resend_step, src_idx, dst_idx, m); assert SpontaneouslyRetransmit(ap.host, ap.host', ap.out); assert ap.out == UnAckedMessages(ap.host.sd, ap.host.me); var pos :| 0 <= pos < |ap.host.sd.sendState[m.dst].unAcked| && ap.host.sd.sendState[m.dst].unAcked[pos] == m; assert Packet(m.dst, ap.host.me, m) in ap.out; Lemma_HostConstantsMeHasAppropriateValue(b, asp.c, resend_step, src_idx); } lemma Lemma_IfRecipientSequenceNumberNeverBeyondThenPacketSentInfinitelyOften( b:Behavior, asp:AssumptionParameters, current_step:int, src_idx:int, dst_idx:int, m:SingleMessage ) requires LivenessAssumptions(b, asp); requires 0 <= src_idx < |asp.c.hostIds|; requires 0 <= dst_idx < |asp.c.hostIds|; requires 0 <= src_idx < |b[current_step].hosts|; requires 0 <= current_step; requires m.SingleMessage?; requires m.dst == asp.c.hostIds[dst_idx]; requires sat(current_step, always(RecipientSequenceNumberBelowTemporal(b, src_idx, dst_idx, m.seqno))); requires m.dst in b[current_step].hosts[src_idx].host.sd.sendState; requires m in b[current_step].hosts[src_idx].host.sd.sendState[m.dst].unAcked; ensures sat(current_step, always(eventual(SHTPacketSentTemporal(b, LPacket(m.dst, asp.c.hostIds[src_idx], m))))); { var p := LPacket(m.dst, asp.c.hostIds[src_idx], m); forall later_step | current_step <= later_step ensures sat(later_step, eventual(SHTPacketSentTemporal(b, p))); { Lemma_ConstantsAllConsistent(b, asp.c, later_step); Lemma_AlwaysImpliesLaterAlways(current_step, later_step, RecipientSequenceNumberBelowTemporal(b, src_idx, dst_idx, m.seqno)); Lemma_IfRecipientSequenceNumberNeverBeyondThenPacketStaysInSendState(b, asp, current_step, later_step, src_idx, dst_idx, m); var resend_step, ap := Lemma_IfRecipientSequenceNumberNeverBeyondThenPacketEventuallySent(b, asp, later_step, src_idx, dst_idx, m); Lemma_ConstantsAllConsistent(b, asp.c, resend_step); assert SHTPacketSent(b[resend_step], p); TemporalEventually(later_step, resend_step, SHTPacketSentTemporal(b, p)); } TemporalAlways(current_step, eventual(SHTPacketSentTemporal(b, p))); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/LiveSHT/LivenessProof/Invariants.i.dfy ================================================ include "Assumptions.i.dfy" include "../../../Common/Framework/HostQueueLemmas.i.dfy" include "Constants.i.dfy" include "RefinementInvariants.i.dfy" include "../../../Common/Collections/Seqs.s.dfy" module LivenessProof__Invariants_i { import opened Collections__Seqs_s import opened EnvironmentSynchrony_s import opened LivenessProof__Assumptions_i import opened Liveness__HostQueueLemmas_i import opened LivenessProof__Actions_i import opened LivenessProof__Constants_i import opened LivenessProof__RefinementInvariants_i import opened LiveSHT__SHT_i import opened SHT__Configuration_i import opened Temporal__Rules_i import opened Temporal__Temporal_s lemma Lemma_HostQueuesNext( b:Behavior, asp:AssumptionParameters, i:int ) requires LivenessAssumptions(b, asp); requires 0 <= i; ensures HostQueues_Next(b[i].environment, b[i+1].environment); { TemporalDeduceFromAlways(0, i, HostQueuesNextTemporal(RestrictBehaviorToEnvironment(b))); } lemma Lemma_LEnvironmentInvariantHolds( b:Behavior, asp:AssumptionParameters, i:int ) requires LivenessAssumptions(b, asp); requires 0 <= i; ensures LEnvironmentInvariant(b[i].environment); { if i == 0 { Lemma_LEnvironmentInitEstablishesInvariant(b[i].environment); } else { Lemma_LEnvironmentInvariantHolds(b, asp, i-1); Lemma_AssumptionsMakeValidTransition(b, asp.c, i-1); Lemma_HostQueuesNext(b, asp, i-1); Lemma_LEnvironmentNextPreservesInvariant(b[i-1].environment, b[i].environment); } } lemma Lemma_EffectOfNextOnHostQueue( b:Behavior, asp:AssumptionParameters, i:int, host_idx:int ) requires LivenessAssumptions(b, asp); requires 0 <= i; requires 0 <= host_idx < |asp.c.hostIds|; ensures var host := asp.c.hostIds[host_idx]; var hostQueue := if host in b[i].environment.hostInfo then b[i].environment.hostInfo[host].queue else []; var hostQueue' := if host in b[i+1].environment.hostInfo then b[i+1].environment.hostInfo[host].queue else []; (hostQueue' == hostQueue) || (|hostQueue'| > 0 && all_but_last(hostQueue') == hostQueue) || (|hostQueue| > 0 && hostQueue' == hostQueue[1..]); { Lemma_AssumptionsMakeValidTransition(b, asp.c, i); Lemma_HostQueuesNext(b, asp, i); Lemma_ConstantsAllConsistent(b, asp.c, i); Lemma_ConstantsAllConsistent(b, asp.c, i+1); var host := asp.c.hostIds[host_idx]; var hostQueue := if host in b[i].environment.hostInfo then b[i].environment.hostInfo[host].queue else []; var hostQueue' := if host in b[i+1].environment.hostInfo then b[i+1].environment.hostInfo[host].queue else []; if b[i].environment.nextStep.LEnvStepHostIos? { if b[i].environment.nextStep.actor in b[i].config.hostIds { var ap := Lemma_GetParametersOfAction(b, asp.c, i); var id := asp.c.hostIds[ap.idx]; if ap.idx != host_idx { assert HostsDistinct(asp.c.hostIds, ap.idx, host_idx); } else { assert HostQueue_PerformIos(hostQueue, hostQueue', ap.ios); if ap.nextActionIndex == 0 { if ap.ios[0].LIoOpTimeoutReceive? { assert hostQueue' == hostQueue; } else { assert ap.ios[0].LIoOpReceive?; assert |ap.ios| == 1 || (ap.ios[1] in ap.ios /* trigger */ && !ap.ios[1].LIoOpReceive?); assert HostQueue_PerformIos(hostQueue[1..], hostQueue', ap.ios[1..]); assert hostQueue[1..] == hostQueue'; } } else if ap.nextActionIndex == 1 { assert |ap.ios| == 0 || (ap.ios[0] in ap.ios /* trigger */ && ap.ios[0].LIoOpSend?); assert hostQueue' == hostQueue; } else { assert |ap.ios| == 0 || (ap.ios[0] in ap.ios /* trigger */ && ap.ios[0].LIoOpSend?); assert hostQueue' == hostQueue; } } } else { // NextExternal } } else { assert LSHT_NextEnvironment(b[i], b[i+1]); } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/LiveSHT/LivenessProof/LivenessProof.i.dfy ================================================ include "Seqno.i.dfy" module LivenessProof__LivenessProof_i { import opened Environment_s import opened LivenessProof__Actions_i import opened LivenessProof__Assumptions_i import opened LivenessProof__Constants_i import opened LivenessProof__Environment_i import opened LivenessProof__RefinementInvariants_i import opened LivenessProof__Seqno_i import opened LiveSHT__Environment_i import opened LiveSHT__SHT_i import opened LiveSHT__SHTRefinement_i import opened Logic__Option_i import opened Protocol_Parameters_i import opened SHT__Network_i import opened SHT__SingleDelivery_i import opened SHT__SingleMessage_i import opened Temporal__Temporal_s predicate SendSingleValid(s:SingleDeliveryAcct, s':SingleDeliveryAcct, sm:SingleMessage, params:Parameters) { sm.SingleMessage? && SendSingleMessage(s, s', sm.m, sm, params, true) && var oldAckState := AckStateLookup(sm.dst, s.sendState); var new_seqno := oldAckState.numPacketsAcked + |oldAckState.unAcked| + 1; new_seqno <= params.max_seqno } lemma Lemma_PacketSentEventuallyReceivedAndNotDiscarded( b:Behavior, asp:AssumptionParameters, src_idx:int, send_step:int, msg:LSHTMessage ) returns (dst_idx:int, received_step:int) requires LivenessAssumptions(b, asp); requires 0 <= send_step; requires 0 <= src_idx < |b[send_step].hosts| == |asp.c.hostIds|; requires 0 <= src_idx < |b[send_step + 1].hosts|; requires SendSingleValid(b[send_step].hosts[src_idx].host.sd, b[send_step + 1].hosts[src_idx].host.sd, msg, asp.c.params); requires msg.dst in asp.c.hostIds; requires b[send_step].environment.nextStep.LEnvStepHostIos?; requires b[send_step].environment.nextStep.actor == asp.c.hostIds[src_idx]; requires LIoOpSend(LPacket(msg.dst, asp.c.hostIds[src_idx], msg)) in b[send_step].environment.nextStep.ios; ensures send_step <= received_step; ensures 0 <= dst_idx < |asp.c.hostIds| == |b[received_step].hosts|; ensures msg.dst == asp.c.hostIds[dst_idx]; ensures 0 <= src_idx < |asp.c.hostIds|; ensures b[received_step].hosts[dst_idx].host.receivedPacket == Some(Packet(msg.dst, asp.c.hostIds[src_idx], msg)); { Lemma_ConstantsAllConsistent(b, asp.c, send_step); Lemma_ConstantsAllConsistent(b, asp.c, send_step+1); dst_idx := GetHostIndex(msg.dst, asp.c); var src := asp.c.hostIds[src_idx]; Lemma_GetHostIndexIsUnique(asp.c, src_idx); Lemma_GetHostIndexIsUnique(asp.c, dst_idx); Lemma_AssumptionsMakeValidTransition(b, asp.c, send_step); var p1 := LPacket(msg.dst, asp.c.hostIds[src_idx], msg); assert p1 in b[send_step+1].environment.sentPackets; var ap1 := Lemma_ActionThatChangesHostIsThatHostsAction(b, asp.c, send_step, src_idx); var reached_step := Lemma_IfTheresAnUnackedPacketThenRecipientSequenceNumberReachesItsSequenceNumber(b, asp, send_step+1, src_idx, dst_idx, msg); Lemma_ConstantsAllConsistent(b, asp.c, reached_step); Lemma_ReceiverHasCanceledNoUnsentSeqno(b, asp.c, send_step, src_idx, dst_idx); var prev_step, ap2 := Lemma_GetReceiveStepForSequenceNumber(b, asp.c, send_step, reached_step, src_idx, dst_idx, msg.seqno); Lemma_ConstantsAllConsistent(b, asp.c, prev_step); var p2 := ap2.ios[0].r; Lemma_PacketStaysInSentPackets(b, asp.c, send_step+1, prev_step, p1); Lemma_PacketsHaveSenderUniqueSeqnos(b, asp.c, prev_step, p1, p2); received_step := prev_step + 1; } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/LiveSHT/LivenessProof/PacketReceipt.i.dfy ================================================ include "Assumptions.i.dfy" include "Environment.i.dfy" include "Acks.i.dfy" include "PacketSending.i.dfy" module LivenessProof__PacketReceipt_i { import opened Collections__Maps2_s import opened Collections__Sets_i import opened Concrete_NodeIdentity_i import opened Environment_s import opened EnvironmentSynchrony_s import opened LivenessProof__Acks_i import opened LivenessProof__Actions_i import opened LivenessProof__Assumptions_i import opened LivenessProof__Constants_i import opened LivenessProof__Environment_i import opened LivenessProof__Invariants_i import opened LivenessProof__PacketSending_i import opened LivenessProof__RefinementInvariants_i import opened LivenessProof__RoundRobin_i import opened LiveSHT__Environment_i import opened LiveSHT__SHT_i import opened LiveSHT__SHTRefinement_i import opened SHT__Configuration_i import opened SHT__SingleDelivery_i import opened Temporal__Rules_i import opened Temporal__Temporal_s import opened Temporal__WF1_i predicate SHTPacketSent(ss:LSHT_State, p:LSHTPacket) { ss.environment.nextStep.LEnvStepHostIos? && LIoOpSend(p) in ss.environment.nextStep.ios } function{:opaque} SHTPacketSentTemporal(b:Behavior, p:LSHTPacket):temporal requires imaptotal(b); ensures forall i{:trigger sat(i, SHTPacketSentTemporal(b, p))} :: sat(i, SHTPacketSentTemporal(b, p)) <==> SHTPacketSent(b[i], p); { stepmap(imap i :: SHTPacketSent(b[i], p)) } predicate IsDelegateStep( ps:LSHT_State, ps':LSHT_State, idx:int ) { 0 <= idx < |ps.hosts| && 0 <= idx < |ps.config.hostIds| && 0 <= idx < |ps'.hosts| && ps.environment.nextStep.LEnvStepHostIos? && ps.environment.nextStep.actor == ps.config.hostIds[idx] && ps.hosts[idx].nextActionIndex == 1 && ps.hosts[idx].host.receivedPacket.Some? && ps.hosts[idx].host.receivedPacket.v.src in ps.config.hostIds && ps.hosts[idx].host.receivedPacket.v.dst == ps.config.hostIds[idx] && ps.hosts[idx].host.receivedPacket.v.msg.SingleMessage? && ps.hosts[idx].host.receivedPacket.v.msg.m.Delegate? && ps'.hosts[idx].host.receivedPacket.None? } predicate IsShardStepOfHost( ps:LSHT_State, ps':LSHT_State, idx:int ) { 0 <= idx < |ps.hosts| && 0 <= idx < |ps.config.hostIds| && 0 <= idx < |ps'.hosts| && ps.environment.nextStep.LEnvStepHostIos? && ps.environment.nextStep.actor == ps.config.hostIds[idx] && ps.hosts[idx].nextActionIndex == 1 && ps.hosts[idx].host.receivedPacket.Some? && ps.hosts[idx].host.receivedPacket.v.dst == ps.config.hostIds[idx] && ps.hosts[idx].host.receivedPacket.v.msg.SingleMessage? && ps.hosts[idx].host.receivedPacket.v.msg.m.Shard? && ps'.hosts[idx].host.receivedPacket.None? } predicate IsShardStepOfOtherHost( ps:LSHT_State, ps':LSHT_State, idx:int ) { exists other_idx :: other_idx != idx && IsShardStepOfHost(ps, ps', other_idx) } function AllDelegatePacketsToHost(b:Behavior, i:int, dst:NodeIdentity):set requires imaptotal(b); { set p | p in b[i].environment.sentPackets && p.src in b[i].config.hostIds && p.msg.SingleMessage? && p.msg.m.Delegate? && p.dst == dst } lemma Lemma_ReceivedPacketAlwaysSingleMessageToProperDestination( b:Behavior, c:SHTConfiguration, i:int, idx:int ) requires IsValidBehaviorPrefix(b, c, i); requires 0 <= i; requires 0 <= idx < |c.hostIds|; ensures 0 <= idx < |b[i].hosts|; ensures var p := b[i].hosts[idx].host.receivedPacket; p.Some? ==> p.v.msg.SingleMessage? && p.v.dst == c.hostIds[idx]; { if i == 0 { return; } Lemma_AssumptionsMakeValidTransition(b, c, i-1); Lemma_ConstantsAllConsistent(b, c, i-1); Lemma_ReceivedPacketAlwaysSingleMessageToProperDestination(b, c, i-1, idx); if b[i].hosts[idx].host.receivedPacket == b[i-1].hosts[idx].host.receivedPacket { return; } var ap := Lemma_ActionThatChangesHostIsThatHostsAction(b, c, i-1, idx); } lemma Lemma_ReceivedPacketInTombstoneTable( b:Behavior, c:SHTConfiguration, i:int, idx:int ) requires IsValidBehaviorPrefix(b, c, i); requires 0 <= i; requires 0 <= idx < |b[i].hosts|; requires b[i].hosts[idx].host.receivedPacket.Some?; requires b[i].hosts[idx].host.receivedPacket.v.msg.SingleMessage?; ensures var host := b[i].hosts[idx].host; TombstoneTableLookup(host.receivedPacket.v.src, host.sd.receiveState) >= host.receivedPacket.v.msg.seqno; { if i == 0 { return; } Lemma_AssumptionsMakeValidTransition(b, c, i-1); Lemma_ConstantsAllConsistent(b, c, i-1); Lemma_ConstantsAllConsistent(b, c, i); var host := b[i-1].hosts[idx].host; var host' := b[i].hosts[idx].host; var src := host'.receivedPacket.v.src; if host'.receivedPacket == host.receivedPacket { Lemma_ReceivedPacketInTombstoneTable(b, c, i-1, idx); Lemma_RecipientSequenceNumberMonotonicOneStep(b, c, i-1, src, idx); return; } var ap := Lemma_ActionThatChangesHostIsThatHostsAction(b, c, i-1, idx); } lemma Lemma_PacketsProcessedInDifferentStepsHaveDifferentSourcesOrSequenceNumbers( b:Behavior, c:SHTConfiguration, i:int, j:int, idx:int ) requires IsValidBehaviorPrefix(b, c, j); requires 0 <= i < j; requires 0 <= idx < |b[i].hosts| == |b[i+1].hosts| == |b[j].hosts| == |c.hostIds|; requires b[i].environment.nextStep.LEnvStepHostIos?; requires b[i].environment.nextStep.actor == c.hostIds[idx]; requires b[i].hosts[idx].host.receivedPacket.Some?; requires b[i+1].hosts[idx].host.receivedPacket.None?; requires b[j].environment.nextStep.LEnvStepHostIos?; requires b[j].environment.nextStep.actor == c.hostIds[idx]; requires b[j].hosts[idx].host.receivedPacket.Some?; ensures b[i].hosts[idx].host.receivedPacket.v.msg.SingleMessage?; ensures b[j].hosts[idx].host.receivedPacket.v.msg.SingleMessage?; ensures var p1 := b[i].hosts[idx].host.receivedPacket.v; var p2 := b[j].hosts[idx].host.receivedPacket.v; p1.src != p2.src || p1.msg.seqno < p2.msg.seqno; { Lemma_ReceivedPacketAlwaysSingleMessageToProperDestination(b, c, i, idx); Lemma_ReceivedPacketAlwaysSingleMessageToProperDestination(b, c, j, idx); var p1 := b[i].hosts[idx].host.receivedPacket.v; var p2 := b[j].hosts[idx].host.receivedPacket.v; if p1.src != p2.src { return; } Lemma_ReceivedPacketInTombstoneTable(b, c, i, idx); var x := stepmap(imap k :: 0 <= idx < |b[k].hosts| && b[k].hosts[idx].host.receivedPacket.Some? && b[k].hosts[idx].host.receivedPacket.v == p2); assert !sat(i+1, x); assert sat(j, x); var transition_step := earliestStepBetween(i+1, j, x) - 1; assert i+1 <= transition_step < j; assert !sat(transition_step, x); Lemma_ConstantsAllConsistent(b, c, transition_step); var ap := Lemma_ActionThatChangesHostIsThatHostsAction(b, c, transition_step, idx); Lemma_RecipientSequenceNumberMonotonic(b, c, i, transition_step, p2.src, idx); } lemma Lemma_GetPacketsFromShardStepsOfHost( b:Behavior, c:SHTConfiguration, i:int, host_idx:int, shard_steps:set ) returns (shard_packets:set) requires IsValidBehaviorPrefix(b, c, i); requires 0 <= i; requires 0 <= host_idx < |c.hostIds|; requires forall step :: step in shard_steps ==> 0 <= step < i && IsShardStepOfHost(b[step], b[step+1], host_idx); ensures forall shard_packet :: shard_packet in shard_packets ==> shard_packet.dst == c.hostIds[host_idx]; ensures shard_packets <= AllShardPacketsSent(b[i].environment.sentPackets); ensures |shard_steps| == |shard_packets|; { Lemma_ConstantsAllConsistent(b, c, i); var f := ((step:int) requires step in shard_steps && IsShardStepOfHost(b[step], b[step+1], host_idx) => PacketToLSHTPacket(b[step].hosts[host_idx].host.receivedPacket.v)); shard_packets := set step | step in shard_steps :: f(step); assert forall step :: step in shard_steps ==> f(step) in shard_packets; forall shard_packet | shard_packet in shard_packets ensures shard_packet.dst == c.hostIds[host_idx]; { var step :| step in shard_steps && shard_packet == f(step); Lemma_ConstantsAllConsistent(b, c, step); } forall step1, step2 | step1 in shard_steps && step2 in shard_steps && f(step1) in shard_packets && f(step2) in shard_packets && f(step1) == f(step2) && step1 != step2 ensures false; { Lemma_ConstantsAllConsistent(b, c, step1); Lemma_ConstantsAllConsistent(b, c, step2); var p1 := b[step1].hosts[host_idx].host.receivedPacket.v; var p2 := b[step2].hosts[host_idx].host.receivedPacket.v; Lemma_ReceivedPacketWasSent(b, c, step1, host_idx); Lemma_ReceivedPacketWasSent(b, c, step2, host_idx); assert p1.src == p2.src; if step1 < step2 { Lemma_ConstantsAllConsistent(b, c, step1+1); Lemma_PacketsProcessedInDifferentStepsHaveDifferentSourcesOrSequenceNumbers(b, c, step1, step2, host_idx); } else { Lemma_ConstantsAllConsistent(b, c, step2+1); Lemma_PacketsProcessedInDifferentStepsHaveDifferentSourcesOrSequenceNumbers(b, c, step2, step1, host_idx); } assert p1.msg.seqno != p2.msg.seqno; assert false; } lemma_MapSetCardinalityOver(shard_steps, shard_packets, f); var all_shard_packets := AllShardPacketsSent(b[i].environment.sentPackets); forall shard_packet | shard_packet in shard_packets ensures shard_packet in all_shard_packets; { var step :| step in shard_steps && shard_packet == f(step); Lemma_ReceivedPacketWasSent(b, c, step, host_idx); Lemma_PacketStaysInSentPackets(b, c, step, i, shard_packet); } assert shard_packets <= all_shard_packets; } lemma Lemma_GetPacketsFromShardStepsOfOtherHost( b:Behavior, c:SHTConfiguration, i:int, host_idx:int, shard_steps:set ) returns (shard_packets:set) requires IsValidBehaviorPrefix(b, c, i); requires 0 <= i; requires 0 <= host_idx < |c.hostIds|; requires forall step :: step in shard_steps ==> 0 <= step < i && IsShardStepOfOtherHost(b[step], b[step+1], host_idx); ensures forall shard_packet :: shard_packet in shard_packets ==> shard_packet.dst != c.hostIds[host_idx]; ensures shard_packets <= AllShardPacketsSent(b[i].environment.sentPackets); ensures |shard_steps| == |shard_packets|; { Lemma_ConstantsAllConsistent(b, c, i); var f := ((step:int) requires step in shard_steps && IsShardStepOfOtherHost(b[step], b[step+1], host_idx) => var other_idx :| other_idx != host_idx && IsShardStepOfHost(b[step], b[step+1], other_idx); PacketToLSHTPacket(b[step].hosts[other_idx].host.receivedPacket.v)); shard_packets := set step | step in shard_steps :: f(step); assert forall step :: step in shard_steps ==> f(step) in shard_packets; forall shard_packet | shard_packet in shard_packets ensures shard_packet.dst != c.hostIds[host_idx]; { var step :| step in shard_steps && shard_packet == f(step); var other_idx :| other_idx != host_idx && IsShardStepOfHost(b[step], b[step+1], other_idx); Lemma_ConstantsAllConsistent(b, c, step); assert HostsDistinct(c.hostIds, host_idx, other_idx); } forall step1, step2 | step1 in shard_steps && step2 in shard_steps && f(step1) in shard_packets && f(step2) in shard_packets && f(step1) == f(step2) && step1 != step2 ensures false; { Lemma_ConstantsAllConsistent(b, c, step1); Lemma_ConstantsAllConsistent(b, c, step2); var other_idx1 :| other_idx1 != host_idx && IsShardStepOfHost(b[step1], b[step1+1], other_idx1) && f(step1) == PacketToLSHTPacket(b[step1].hosts[other_idx1].host.receivedPacket.v); var other_idx2 :| other_idx2 != host_idx && IsShardStepOfHost(b[step2], b[step2+1], other_idx2) && f(step2) == PacketToLSHTPacket(b[step2].hosts[other_idx2].host.receivedPacket.v); var p1 := b[step1].hosts[other_idx1].host.receivedPacket.v; var p2 := b[step2].hosts[other_idx2].host.receivedPacket.v; Lemma_ReceivedPacketWasSent(b, c, step1, other_idx1); Lemma_ReceivedPacketWasSent(b, c, step2, other_idx2); assert HostsDistinct(c.hostIds, other_idx1, other_idx2); if step1 < step2 { Lemma_ConstantsAllConsistent(b, c, step1+1); Lemma_PacketsProcessedInDifferentStepsHaveDifferentSourcesOrSequenceNumbers(b, c, step1, step2, other_idx1); } else { Lemma_ConstantsAllConsistent(b, c, step2+1); Lemma_PacketsProcessedInDifferentStepsHaveDifferentSourcesOrSequenceNumbers(b, c, step2, step1, other_idx2); } assert p1.msg.seqno != p2.msg.seqno; assert false; } lemma_MapSetCardinalityOver(shard_steps, shard_packets, f); var all_shard_packets := AllShardPacketsSent(b[i].environment.sentPackets); forall shard_packet | shard_packet in shard_packets ensures shard_packet in all_shard_packets; { var step :| step in shard_steps && shard_packet == f(step); var other_idx :| other_idx != host_idx && IsShardStepOfHost(b[step], b[step+1], other_idx) && shard_packet == PacketToLSHTPacket(b[step].hosts[other_idx].host.receivedPacket.v); Lemma_ReceivedPacketWasSent(b, c, step, other_idx); Lemma_PacketStaysInSentPackets(b, c, step, i, shard_packet); } assert shard_packets <= all_shard_packets; } lemma {:timeLimitMultiplier 3} Lemma_GetShardStepsLeadingToDelegateMessages( b:Behavior, c:SHTConfiguration, i:int, host_idx:int ) returns (shard_steps:set) requires IsValidBehaviorPrefix(b, c, i); requires 0 <= i; requires 0 <= host_idx < |c.hostIds|; ensures 0 <= host_idx < |b[i].hosts|; ensures |shard_steps| == |AllDelegatePacketsToHost(b, i, c.hostIds[host_idx])|; ensures forall step :: step in shard_steps ==> 0 <= step < i && IsShardStepOfOtherHost(b[step], b[step+1], host_idx); { if i == 0 { shard_steps := {}; return; } Lemma_AssumptionsMakeValidTransition(b, c, i-1); Lemma_ConstantsAllConsistent(b, c, i-1); Lemma_ConstantsAllConsistent(b, c, i); shard_steps := Lemma_GetShardStepsLeadingToDelegateMessages(b, c, i-1, host_idx); var dst := c.hostIds[host_idx]; var s := b[i-1].hosts[host_idx].host; var s' := b[i].hosts[host_idx].host; if AllDelegatePacketsToHost(b, i, dst) == AllDelegatePacketsToHost(b, i-1, dst) { return; } var p :| p in b[i].environment.sentPackets && p !in b[i-1].environment.sentPackets && p.src in b[i].config.hostIds && p.msg.SingleMessage? && p.msg.m.Delegate? && p.dst == dst; var ap := Lemma_ActionThatSendsPacketIsActionOfSource(b, c, i-1, p); Lemma_ActionThatSendsFreshPacketIsNotResend(b, c, i-1, ap, p); assert ap.nextActionIndex == 1; assert ap.idx != host_idx; Lemma_ReceivedPacketAlwaysSingleMessageToProperDestination(b, c, i-1, ap.idx); assert IsShardStepOfHost(b[i-1], b[i], ap.idx); shard_steps := shard_steps + {i-1}; assert AllDelegatePacketsToHost(b, i, dst) == AllDelegatePacketsToHost(b, i-1, dst) + {p}; } lemma Lemma_GetPacketsFromDelegateSteps( b:Behavior, c:SHTConfiguration, i:int, host_idx:int, delegate_steps:set ) returns (delegate_packets:set) requires IsValidBehaviorPrefix(b, c, i); requires 0 <= i; requires 0 <= host_idx < |c.hostIds|; requires forall step :: step in delegate_steps ==> 0 <= step < i && IsDelegateStep(b[step], b[step+1], host_idx); ensures delegate_packets <= AllDelegatePacketsToHost(b, i, c.hostIds[host_idx]); ensures |delegate_steps| == |delegate_packets|; { Lemma_ConstantsAllConsistent(b, c, i); var dst := c.hostIds[host_idx]; var f := ((step:int) requires step in delegate_steps && IsDelegateStep(b[step], b[step+1], host_idx) => PacketToLSHTPacket(b[step].hosts[host_idx].host.receivedPacket.v)); delegate_packets := set step | step in delegate_steps :: f(step); assert forall step :: step in delegate_steps ==> f(step) in delegate_packets; forall step1, step2 | step1 in delegate_steps && step2 in delegate_steps && f(step1) in delegate_packets && f(step2) in delegate_packets && f(step1) == f(step2) && step1 != step2 ensures false; { Lemma_ConstantsAllConsistent(b, c, step1); Lemma_ConstantsAllConsistent(b, c, step2); var p1 := b[step1].hosts[host_idx].host.receivedPacket.v; var p2 := b[step2].hosts[host_idx].host.receivedPacket.v; Lemma_ReceivedPacketWasSent(b, c, step1, host_idx); Lemma_ReceivedPacketWasSent(b, c, step2, host_idx); assert p1.src == p2.src; if step1 < step2 { Lemma_ConstantsAllConsistent(b, c, step1+1); Lemma_PacketsProcessedInDifferentStepsHaveDifferentSourcesOrSequenceNumbers(b, c, step1, step2, host_idx); } else { Lemma_ConstantsAllConsistent(b, c, step2+1); Lemma_PacketsProcessedInDifferentStepsHaveDifferentSourcesOrSequenceNumbers(b, c, step2, step1, host_idx); } assert p1.msg.seqno != p2.msg.seqno; assert false; } lemma_MapSetCardinalityOver(delegate_steps, delegate_packets, f); var all_delegate_packets := AllDelegatePacketsToHost(b, i, dst); forall delegate_packet | delegate_packet in delegate_packets ensures delegate_packet in all_delegate_packets; { var step :| step in delegate_steps && delegate_packet == f(step); Lemma_ConstantsAllConsistent(b, c, step); Lemma_ReceivedPacketWasSent(b, c, step, host_idx); Lemma_PacketStaysInSentPackets(b, c, step, i, delegate_packet); assert delegate_packet.dst == dst; } assert delegate_packets <= all_delegate_packets; } lemma Lemma_GetDelegateAndShardStepsLeadingToNumDelegations( b:Behavior, c:SHTConfiguration, i:int, host_idx:int ) returns (delegate_steps:set, shard_steps:set) requires IsValidBehaviorPrefix(b, c, i); requires 0 <= i; requires 0 <= host_idx < |c.hostIds|; ensures 0 <= host_idx < |b[i].hosts|; ensures |delegate_steps| + |shard_steps| + 1 == b[i].hosts[host_idx].host.numDelegations; ensures forall step :: step in delegate_steps ==> 0 <= step < i && IsDelegateStep(b[step], b[step+1], host_idx); ensures forall step :: step in shard_steps ==> 0 <= step < i && IsShardStepOfHost(b[step], b[step+1], host_idx); { if i == 0 { delegate_steps := {}; shard_steps := {}; return; } Lemma_AssumptionsMakeValidTransition(b, c, i-1); Lemma_ConstantsAllConsistent(b, c, i-1); Lemma_ConstantsAllConsistent(b, c, i); delegate_steps, shard_steps := Lemma_GetDelegateAndShardStepsLeadingToNumDelegations(b, c, i-1, host_idx); var s := b[i-1].hosts[host_idx].host; var s' := b[i].hosts[host_idx].host; if s'.numDelegations == s.numDelegations { return; } var ap := Lemma_ActionThatChangesHostIsThatHostsAction(b, c, i-1, host_idx); assert ap.nextActionIndex == 1; assert s'.numDelegations == s.numDelegations + 1; Lemma_ReceivedPacketAlwaysSingleMessageToProperDestination(b, c, i-1, host_idx); if IsShardStepOfHost(b[i-1], b[i], host_idx) { shard_steps := shard_steps + {i-1}; } else { assert IsDelegateStep(b[i-1], b[i], host_idx); delegate_steps := delegate_steps + {i-1}; } } lemma Lemma_DelegationBound( b:Behavior, asp:AssumptionParameters, i:int, host_idx:int ) requires LivenessAssumptions(b, asp); requires 0 <= i; requires 0 <= host_idx < |asp.c.hostIds|; ensures 0 <= host_idx < |b[i].hosts|; ensures b[i].hosts[host_idx].host.numDelegations < asp.c.params.max_delegations - 2; { Lemma_ConstantsAllConsistent(b, asp.c, i); var host := asp.c.hostIds[host_idx]; var delegate_steps, shard_steps_direct := Lemma_GetDelegateAndShardStepsLeadingToNumDelegations(b, asp.c, i, host_idx); var shard_packets_direct := Lemma_GetPacketsFromShardStepsOfHost(b, asp.c, i, host_idx, shard_steps_direct); var delegate_packets := Lemma_GetPacketsFromDelegateSteps(b, asp.c, i, host_idx, delegate_steps); var all_delegate_packets := AllDelegatePacketsToHost(b, i, asp.c.hostIds[host_idx]); SubsetCardinality(delegate_packets, all_delegate_packets); var shard_steps_indirect := Lemma_GetShardStepsLeadingToDelegateMessages(b, asp.c, i, host_idx); assert |shard_steps_indirect| == |all_delegate_packets|; var shard_packets_indirect := Lemma_GetPacketsFromShardStepsOfOtherHost(b, asp.c, i, host_idx, shard_steps_indirect); forall p1, p2 | p1 in shard_packets_direct && p2 in shard_packets_indirect ensures p1 != p2; { assert p1.dst == host; assert p2.dst != host; } var shard_packets := shard_packets_direct + shard_packets_indirect; assert |shard_packets| == |shard_packets_direct| + |shard_packets_indirect|; var all_shard_packets := AllShardPacketsSent(b[i].environment.sentPackets); SubsetCardinality(shard_packets, all_shard_packets); calc { b[i].hosts[host_idx].host.numDelegations; |delegate_steps| + |shard_steps_direct| + 1; |delegate_packets| + |shard_packets_direct| + 1; <= |all_delegate_packets| + |shard_packets_direct| + 1; |shard_steps_indirect| + |shard_packets_direct| + 1; |shard_packets_indirect| + |shard_packets_direct| + 1; |shard_packets| + 1; <= |all_shard_packets| + 1; <= asp.c.params.max_delegations - 4 + 1; } } lemma Lemma_ReceivedPacketSlotEmptyUnlessNextActionIndexOne( b:Behavior, asp:AssumptionParameters, i:int, idx:int ) requires LivenessAssumptions(b, asp); requires 0 <= i; requires 0 <= idx < |asp.c.hostIds|; ensures 0 <= idx < |b[i].hosts|; ensures var s := b[i].hosts[idx]; s.host.receivedPacket.Some? ==> s.nextActionIndex == 1; { if i == 0 { return; } Lemma_AssumptionsMakeValidTransition(b, asp.c, i-1); Lemma_ConstantsAllConsistent(b, asp.c, i-1); Lemma_ReceivedPacketSlotEmptyUnlessNextActionIndexOne(b, asp, i-1, idx); if b[i-1].hosts[idx] == b[i].hosts[idx] { return; } var ap := Lemma_ActionThatChangesHostIsThatHostsAction(b, asp.c, i-1, idx); Lemma_ReceivedPacketAlwaysSingleMessageToProperDestination(b, asp.c, i-1, idx); assert 0 <= idx < |asp.c.hostIds| && 0 <= i-1 && 0 <= idx < |b[i-1].hosts|; Lemma_DelegationBound(b, asp, i-1, idx); assert b[i-1].hosts[idx].host.numDelegations < asp.c.params.max_delegations - 2; } lemma Lemma_PacketInHostQueueStaysThereUnlessActionZeroOccurs( b:Behavior, asp:AssumptionParameters, i:int, host_idx:int, host:NodeIdentity, p:LSHTPacket ) requires LivenessAssumptions(b, asp); requires 0 <= i; requires 0 <= host_idx < |asp.c.hostIds|; requires host == asp.c.hostIds[host_idx]; requires host in b[i].environment.hostInfo; requires |b[i].environment.hostInfo[host].queue| > 0; requires p == b[i].environment.hostInfo[host].queue[0]; requires !( b[i].environment.nextStep.LEnvStepHostIos? && b[i].environment.nextStep.actor == host && 0 <= host_idx < |b[i].hosts| && b[i].hosts[host_idx].nextActionIndex == 0); ensures host in b[i+1].environment.hostInfo; ensures |b[i+1].environment.hostInfo[host].queue| > 0; ensures p == b[i+1].environment.hostInfo[host].queue[0]; { Lemma_AssumptionsMakeValidTransition(b, asp.c, i); Lemma_ConstantsAllConsistent(b, asp.c, i); Lemma_HostQueuesNext(b, asp, i); var hostQueue := if host in b[i].environment.hostInfo then b[i].environment.hostInfo[host].queue else []; var hostQueue' := if host in b[i+1].environment.hostInfo then b[i+1].environment.hostInfo[host].queue else []; if b[i].environment.nextStep.LEnvStepHostIos? && b[i].environment.nextStep.actor in b[i].config.hostIds { var ap := Lemma_GetParametersOfAction(b, asp.c, i); var id := asp.c.hostIds[ap.idx]; if ap.idx != host_idx { assert HostsDistinct(asp.c.hostIds, ap.idx, host_idx); assert hostQueue' == hostQueue; } else { assert HostQueue_PerformIos(hostQueue, hostQueue', ap.ios); assert ap.nextActionIndex != 0; assert |ap.ios| == 0 || (ap.ios[0] in ap.ios /* trigger */ && ap.ios[0].LIoOpSend?); assert hostQueue' == hostQueue; } } } lemma Lemma_PacketInHostQueueEventuallyReceived( b:Behavior, asp:AssumptionParameters, current_step:int, host_idx:int, p:LSHTPacket ) returns (next_step:int, ap:SHTActionParams) requires LivenessAssumptions(b, asp); requires 0 <= current_step; requires 0 <= host_idx < |asp.c.hostIds|; requires asp.c.hostIds[host_idx] in b[current_step].environment.hostInfo; requires p in b[current_step].environment.hostInfo[asp.c.hostIds[host_idx]].queue; ensures current_step <= next_step; ensures SHTActionOccurred(b[next_step], b[next_step+1], ap); ensures ap.idx == host_idx; ensures ap.nextActionIndex == 0; ensures b[next_step].hosts[host_idx].host.receivedPacket.None?; ensures |ap.ios| > 0; ensures ap.ios[0] == LIoOpReceive(p); { var host := asp.c.hostIds[host_idx]; var intermediate_step := Lemma_PacketInHostQueueEventuallyAtFrontOfHostQueue(b, asp, current_step, host_idx, p); var P := stepmap(imap i :: host in b[i].environment.hostInfo && |b[i].environment.hostInfo[host].queue| > 0 && p == b[i].environment.hostInfo[host].queue[0]); var Q := stepmap(imap i :: host in b[i].environment.hostInfo && |b[i].environment.hostInfo[host].queue| > 0 && p == b[i].environment.hostInfo[host].queue[0] && b[i].environment.nextStep.LEnvStepHostIos? && b[i].environment.nextStep.actor == host && 0 <= host_idx < |b[i].hosts| && b[i].hosts[host_idx].nextActionIndex == 0); var action_step := Lemma_HostNextPerformsSubactionEventually(b, asp, host_idx, intermediate_step, 0); forall j | intermediate_step <= j ensures sat(j, TemporalWF1Req1(P, Q)); { if sat(j, P) && !sat(j, Q) { Lemma_PacketInHostQueueStaysThereUnlessActionZeroOccurs(b, asp, j, host_idx, host, p); assert sat(j+1, P); } } forall ensures sat(action_step, imply(P, or(Q, next(Q)))) { if sat(action_step, P) { Lemma_ConstantsAllConsistent(b, asp.c, action_step); var ap_intermediate := Lemma_GetParametersOfAction(b, asp.c, action_step); Lemma_GetHostIndexIsUnique(asp.c, host_idx); assert host_idx == ap_intermediate.idx; assert sat(action_step, Q); } } next_step := TemporalWF1Specific(intermediate_step, action_step, P, Q); Lemma_ConstantsAllConsistent(b, asp.c, next_step); ap := Lemma_GetParametersOfAction(b, asp.c, next_step); Lemma_GetHostIndexIsUnique(asp.c, host_idx); Lemma_ReceivedPacketSlotEmptyUnlessNextActionIndexOne(b, asp, next_step, host_idx); Lemma_HostQueuesNext(b, asp, next_step); } lemma Lemma_DeliveredPacketEventuallyReceived( b:Behavior, asp:AssumptionParameters, deliver_step:int, host_idx:int, p:LSHTPacket ) returns (next_step:int, ap:SHTActionParams) requires LivenessAssumptions(b, asp); requires 0 <= deliver_step; requires 0 <= host_idx < |asp.c.hostIds|; requires p.dst == asp.c.hostIds[host_idx]; requires b[deliver_step].environment.nextStep == LEnvStepDeliverPacket(p); ensures deliver_step + 1 <= next_step; ensures SHTActionOccurred(b[next_step], b[next_step+1], ap); ensures ap.idx == host_idx; ensures ap.nextActionIndex == 0; ensures b[next_step].hosts[host_idx].host.receivedPacket.None?; ensures |ap.ios| > 0; ensures ap.ios[0] == LIoOpReceive(p); { Lemma_AssumptionsMakeValidTransition(b, asp.c, deliver_step); Lemma_HostQueuesNext(b, asp, deliver_step); next_step, ap := Lemma_PacketInHostQueueEventuallyReceived(b, asp, deliver_step + 1, host_idx, p); } lemma Lemma_PacketSentInfinitelyOftenEventuallyReceived( b:Behavior, asp:AssumptionParameters, current_step:int, src_idx:int, dst_idx:int, p:LSHTPacket ) returns (receive_step:int, ap:SHTActionParams) requires LivenessAssumptions(b, asp); requires 0 <= src_idx < |asp.c.hostIds|; requires 0 <= dst_idx < |asp.c.hostIds|; requires sat(current_step, always(eventual(SHTPacketSentTemporal(b, p)))); requires 0 <= current_step; requires p.src == asp.c.hostIds[src_idx]; requires p.dst == asp.c.hostIds[dst_idx]; ensures current_step <= receive_step; ensures SHTActionOccurred(b[receive_step], b[receive_step+1], ap); ensures ap.idx == dst_idx; ensures ap.nextActionIndex == 0; ensures b[receive_step].hosts[dst_idx].host.receivedPacket.None?; ensures |ap.ios| > 0; ensures ap.ios[0] == LIoOpReceive(p); { var eb := RestrictBehaviorToEnvironment(b); var host_set := Collections__Sets_i.SeqToSet(asp.c.hostIds); assert NetworkWeaklyFair(eb, asp.c.hostIds); forall i | current_step <= i ensures sat(i, eventual(PacketSentBetweenHostsTemporal(eb, p, host_set, host_set))); { TemporalDeduceFromAlways(current_step, i, eventual(SHTPacketSentTemporal(b, p))); var j := TemporalDeduceFromEventual(i, SHTPacketSentTemporal(b, p)); Lemma_HostQueuesNext(b, asp, j); Lemma_ConstantsAllConsistent(b, asp.c, j); Lemma_GetHostIndexIsUnique(asp.c, src_idx); Lemma_GetHostIndexIsUnique(asp.c, dst_idx); assert PacketSentBetweenHosts(eb[j], p, host_set, host_set); TemporalEventually(i, j, PacketSentBetweenHostsTemporal(eb, p, host_set, host_set)); } TemporalAlways(current_step, eventual(PacketSentBetweenHostsTemporal(eb, p, host_set, host_set))); TemporalDeduceFromAlways(0, current_step, imply(always(eventual(PacketSentBetweenHostsTemporal(eb, p, host_set, host_set))), eventual(PacketDeliveredTemporal(eb, p)))); var deliver_step := TemporalDeduceFromEventual(current_step, PacketDeliveredTemporal(eb, p)); receive_step, ap := Lemma_DeliveredPacketEventuallyReceived(b, asp, deliver_step, dst_idx, p); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/LiveSHT/LivenessProof/PacketSending.i.dfy ================================================ include "../RefinementProof/SHT.i.dfy" include "RefinementInvariants.i.dfy" module LivenessProof__PacketSending_i { import opened Environment_s import opened LivenessProof__Actions_i import opened LivenessProof__Assumptions_i import opened LivenessProof__Constants_i import opened LivenessProof__RefinementInvariants_i import opened LiveSHT__Environment_i import opened LiveSHT__SHT_i import opened SHT__Configuration_i import opened SHT__Host_i import opened SHT__Network_i import opened SHT__SingleDelivery_i import opened Temporal__Temporal_s lemma Lemma_ActionThatSendsPacketIsActionOfSource( b:Behavior, c:SHTConfiguration, i:int, p:LSHTPacket ) returns (ap:SHTActionParams) requires IsValidBehaviorPrefix(b, c, i+1); requires 0 <= i; requires p.src in c.hostIds; requires p in b[i+1].environment.sentPackets; requires p !in b[i].environment.sentPackets; ensures SHTActionOccurred(b[i], b[i+1], ap); ensures 0 <= ap.idx < |c.hostIds|; ensures p.src == c.hostIds[ap.idx]; ensures LSHT_Next(b[i], b[i+1]); ensures LIoOpSend(p) in ap.ios; { Lemma_AssumptionsMakeValidTransition(b, c, i); Lemma_ConstantsAllConsistent(b, c, i); assert b[i].environment.nextStep.LEnvStepHostIos?; assert LIoOpSend(p) in b[i].environment.nextStep.ios; ap := Lemma_GetParametersOfAction(b, c, i); } lemma Lemma_ActionThatSendsFreshPacketIsNotResend( b:Behavior, c:SHTConfiguration, i:int, ap:SHTActionParams, p:LSHTPacket ) requires IsValidBehaviorPrefix(b, c, i+1); requires 0 < i; requires p in b[i+1].environment.sentPackets; requires p !in b[i].environment.sentPackets; requires SHTActionOccurred(b[i], b[i+1], ap); ensures ap.nextActionIndex != 2; { Lemma_AssumptionsMakeValidTransition(b, c, i); Lemma_ConstantsAllConsistent(b, c, i); assert LIoOpSend(p) in ap.ios; assert LSHTPacketToPacket(p) in ap.out; if ap.nextActionIndex == 2 { Lemma_HostConstantsMeHasAppropriateValue(b, c, i, ap.idx); assert SpontaneouslyRetransmit(ap.host, ap.host', ap.out); assert ap.out == UnAckedMessages(ap.host.sd, ap.host.me); var s := ap.host.sd; var dst, j :| dst in s.sendState && 0 <= j < |s.sendState[dst].unAcked| && s.sendState[dst].unAcked[j].SingleMessage? && LSHTPacketToPacket(p) == Packet(s.sendState[dst].unAcked[j].dst, ap.host.me, s.sendState[dst].unAcked[j]); assert LSHTPacketToPacket(p).msg == s.sendState[dst].unAcked[j]; assert p.msg == s.sendState[dst].unAcked[j]; Lemma_MessageInUnackedListHasParticularDestination(b, c, i, ap.idx, dst, p.msg); Lemma_UnAckedPacketInNetwork(b, c, i, ap.idx, p); } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/LiveSHT/LivenessProof/RefinementInvariants.i.dfy ================================================ include "Constants.i.dfy" include "Actions.i.dfy" include "../../SHT/RefinementProof/RefinementProof.i.dfy" include "../RefinementProof/SHTRefinement.i.dfy" include "../RefinementProof/SHTLemmas.i.dfy" module LivenessProof__RefinementInvariants_i { import opened Concrete_NodeIdentity_i import opened Environment_s import opened LivenessProof__Actions_i import opened LivenessProof__Assumptions_i import opened LivenessProof__Constants_i import opened LiveSHT__Environment_i import opened LiveSHT__EnvironmentRefinement_i import opened LiveSHT__SHT_i import opened LiveSHT__SHTRefinement_i import opened RefinementProof__DistributedSystemLemmas_i import opened SHT__Configuration_i import opened SHT__Delegations_i import opened SHT__Host_i import opened SHT__InvDefs_i import opened SHT__InvProof_i import opened SHT__Message_i import opened SHT__Network_i import opened SHT__RefinementProof_i import opened SHT__SHT_i import opened SHT__SingleDelivery_i import opened SHT__SingleMessage_i import opened Temporal__Temporal_s function PacketToLSHTPacket(p:Packet) : LSHTPacket { LPacket(p.dst, p.src, p.msg) } lemma Lemma_ActionMaintainsMapComplete( ss:LSHT_State, ss':LSHT_State, ap:SHTActionParams ) requires SHTActionOccurred(ss, ss', ap); requires LSHTState_RefinementInvariant(ss); requires MapComplete(LSHTState_Refine(ss)); requires ss'.config == ss.config; requires LSHT_Next(ss, ss'); ensures LSHTState_RefinementInvariant(ss'); ensures MapComplete(LSHTState_Refine(ss')); { var h_s := LSHTState_Refine(ss); forall idx | 0 <= idx < |ss'.config.hostIds| ensures DelegationMapComplete(ss'.hosts[idx].host.delegationMap); { var id := ss.config.hostIds[idx]; Lemma_GetHostIndexIsUnique(ss.config, idx); assert DelegationMapComplete(h_s.hosts[id].delegationMap); assert DelegationMapComplete(ss.hosts[idx].host.delegationMap); } } lemma Lemma_RefinementInvariantHolds( b:Behavior, c:SHTConfiguration, i:int ) requires IsValidBehaviorPrefix(b, c, i); requires 0 <= i; ensures LSHTState_RefinementInvariant(b[i]); ensures Inv(LSHTState_Refine(b[i])); { if i == 0 { InitInv(c, LSHTState_Refine(b[i])); return; } Lemma_RefinementInvariantHolds(b, c, i-1); Lemma_AssumptionsMakeValidTransition(b, c, i-1); Lemma_ConstantsAllConsistent(b, c, i-1); var h_s := LSHTState_Refine(b[i-1]); var h_s' := LSHTState_Refine(b[i]); if b[i-1].environment.nextStep.LEnvStepHostIos? { if b[i-1].environment.nextStep.actor in b[i-1].config.hostIds { var ap := Lemma_GetParametersOfAction(b, c, i-1); Lemma_ActionMaintainsMapComplete(b[i-1], b[i], ap); var id := c.hostIds[ap.idx]; assert ap.out == LSHTIoSeq_RefineAsSends(ap.ios); if ap.nextActionIndex == 0 { if ap.ios[0].LIoOpTimeoutReceive? { assert h_s'.hosts == h_s.hosts; assert h_s'.network == h_s.network; assert h_s == h_s'; } else { assert SHT_NextPred(h_s, h_s', id, ap.recv, ap.out); NextInv(h_s, h_s'); } } else if ap.nextActionIndex == 1 { assert SHT_NextPred(h_s, h_s', id, ap.recv, ap.out); NextInv(h_s, h_s'); } else if ap.nextActionIndex == 2 { if ap.resendCount == 0 { assert SHT_NextPred(h_s, h_s', id, ap.recv, ap.out); NextInv(h_s, h_s'); } else { assert h_s'.hosts == h_s.hosts; assert h_s'.network == h_s.network; assert h_s == h_s'; } } else { assert false; } } else { var s := b[i-1]; var s' := b[i]; assert exists idx, ios :: LSHT_NextExternal(s, s', idx, ios); var idx, ios :| LSHT_NextExternal(s, s', idx, ios); assert SHT_NextExternal(h_s, h_s', idx, {}, LSHTIoSeq_RefineAsSends(ios)); NextInv(h_s, h_s'); } } else { assert LSHT_NextEnvironment(b[i-1], b[i]); assert h_s'.hosts == h_s.hosts; assert h_s'.network == h_s.network; } } lemma Lemma_PacketsHaveSenderUniqueSeqnos( b:Behavior, c:SHTConfiguration, i:int, p1:LSHTPacket, p2:LSHTPacket ) requires IsValidBehaviorPrefix(b, c, i); requires 0 <= i; requires p1 in b[i].environment.sentPackets; requires p2 in b[i].environment.sentPackets; requires p1.msg.SingleMessage?; requires p2.msg.SingleMessage?; requires p1.src == p2.src; requires p1.dst == p2.dst; requires p1.src in b[i].config.hostIds && p1.dst in b[i].config.hostIds; requires p2.src in b[i].config.hostIds && p2.dst in b[i].config.hostIds; requires p1.msg.seqno == p2.msg.seqno; ensures p1 == p2; { Lemma_RefinementInvariantHolds(b, c, i); var s := LSHTState_Refine(b[i]); reveal_PacketsHaveSenderUniqueSeqnos(); assert LSHTPacketToPacket(p1) in s.network; assert LSHTPacketToPacket(p2) in s.network; } lemma Lemma_ReceiverHasCanceledNoUnsentSeqno( b:Behavior, c:SHTConfiguration, i:int, src_idx:int, dst_idx:int ) requires IsValidBehaviorPrefix(b, c, i); requires 0 <= i; requires 0 <= src_idx < |c.hostIds|; requires 0 <= dst_idx < |c.hostIds|; ensures 0 <= src_idx < |b[i].hosts|; ensures 0 <= dst_idx < |b[i].hosts|; ensures HighestSeqnoSent(b[i].hosts[src_idx].host.sd, c.hostIds[dst_idx]) >= TombstoneTableLookup(c.hostIds[src_idx], b[i].hosts[dst_idx].host.sd.receiveState); { Lemma_ConstantsAllConsistent(b, c, i); var s := LSHTState_Refine(b[i]); Lemma_GetHostIndexIsUnique(b[i].config, src_idx); Lemma_GetHostIndexIsUnique(b[i].config, dst_idx); var src := c.hostIds[src_idx]; var dst := c.hostIds[dst_idx]; var seqno := HighestSeqnoSent(b[i].hosts[src_idx].host.sd, c.hostIds[dst_idx]) + 1; Lemma_RefinementInvariantHolds(b, c, i); assert ReceiverHasNotCanceledUnsentSeqno(s, dst, src, seqno); assert seqno > TombstoneTableLookup(src, s.hosts[dst].sd.receiveState); } lemma Lemma_MessageInUnackedListHasParticularSeqno( b:Behavior, c:SHTConfiguration, i:int, src_idx:int, dst:NodeIdentity, m:SingleMessage, pos:int ) requires IsValidBehaviorPrefix(b, c, i); requires 0 <= i; requires 0 <= src_idx < |c.hostIds|; requires 0 <= src_idx < |b[i].hosts|; requires dst in c.hostIds; requires dst in b[i].hosts[src_idx].host.sd.sendState; requires 0 <= pos < |b[i].hosts[src_idx].host.sd.sendState[dst].unAcked|; requires m == b[i].hosts[src_idx].host.sd.sendState[dst].unAcked[pos]; ensures m.SingleMessage?; ensures m.seqno == b[i].hosts[src_idx].host.sd.sendState[dst].numPacketsAcked + pos + 1; decreases pos; { Lemma_ConstantsAllConsistent(b, c, i); var s := LSHTState_Refine(b[i]); Lemma_GetHostIndexIsUnique(b[i].config, src_idx); var src := c.hostIds[src_idx]; var ackState := s.hosts[src].sd; var unAcked := AckStateLookup(dst, ackState.sendState).unAcked; Lemma_RefinementInvariantHolds(b, c, i); assert AckListsInv(s); assert dst in AllHostIdentities(s); assert UnAckedListProperties(ackState); assert NoAcksInUnAckedLists(ackState); assert 0 <= pos < |unAcked|; assert unAcked[pos].SingleMessage?; if pos == 0 { assert UnAckedListExceedsNumPacketsAcked(ackState); } else { Lemma_MessageInUnackedListHasParticularSeqno(b, c, i, src_idx, dst, unAcked[pos-1], pos-1); assert UnAckedListsSequential(ackState); assert unAcked[pos].seqno == unAcked[pos-1].seqno + 1; } } lemma Lemma_GetPositionOfMessageInUnackedList( b:Behavior, c:SHTConfiguration, i:int, src_idx:int, dst:NodeIdentity, m:SingleMessage ) returns (pos:int) requires IsValidBehaviorPrefix(b, c, i); requires 0 <= i; requires 0 <= src_idx < |c.hostIds|; requires 0 <= src_idx < |b[i].hosts|; requires dst in c.hostIds; requires dst in b[i].hosts[src_idx].host.sd.sendState; requires m in b[i].hosts[src_idx].host.sd.sendState[dst].unAcked; ensures 0 <= pos < |b[i].hosts[src_idx].host.sd.sendState[dst].unAcked|; ensures m == b[i].hosts[src_idx].host.sd.sendState[dst].unAcked[pos]; ensures m.SingleMessage?; ensures pos == m.seqno - b[i].hosts[src_idx].host.sd.sendState[dst].numPacketsAcked - 1; { Lemma_ConstantsAllConsistent(b, c, i); pos :| 0 <= pos < |b[i].hosts[src_idx].host.sd.sendState[dst].unAcked| && b[i].hosts[src_idx].host.sd.sendState[dst].unAcked[pos] == m; Lemma_MessageInUnackedListHasParticularSeqno(b, c, i, src_idx, dst, m, pos); } lemma Lemma_MessageInUnackedListHasParticularDestination( b:Behavior, c:SHTConfiguration, i:int, src_idx:int, dst:NodeIdentity, m:SingleMessage ) requires IsValidBehaviorPrefix(b, c, i); requires 0 <= i; requires 0 <= src_idx < |c.hostIds|; requires 0 <= src_idx < |b[i].hosts|; requires dst in b[i].hosts[src_idx].host.sd.sendState; requires m in b[i].hosts[src_idx].host.sd.sendState[dst].unAcked; ensures m.SingleMessage?; ensures m.dst == dst; { Lemma_ConstantsAllConsistent(b, c, i); var s := LSHTState_Refine(b[i]); Lemma_GetHostIndexIsUnique(b[i].config, src_idx); var src := c.hostIds[src_idx]; var ackState := s.hosts[src].sd; var unAcked := AckStateLookup(dst, ackState.sendState).unAcked; Lemma_RefinementInvariantHolds(b, c, i); assert AckListsInv(s); assert UnAckedListProperties(ackState); var pos :| 0 <= pos < |unAcked| && unAcked[pos] == m; assert NoAcksInUnAckedLists(ackState); assert 0 <= pos < |unAcked|; assert unAcked[pos].SingleMessage?; assert UnAckedDstsConsistent(ackState); assert m.dst == dst; } lemma Lemma_HostConstantsMeHasAppropriateValue( b:Behavior, c:SHTConfiguration, i:int, idx:int ) requires IsValidBehaviorPrefix(b, c, i); requires 0 <= i; requires 0 <= idx < |c.hostIds|; ensures 0 <= idx < |b[i].hosts|; ensures b[i].hosts[idx].host.me == c.hostIds[idx]; { Lemma_ConstantsAllConsistent(b, c, i); var s := LSHTState_Refine(b[i]); Lemma_RefinementInvariantHolds(b, c, i); assert InvConstants(s); var id := c.hostIds[idx]; assert id in AllHostIdentities(s); } lemma Lemma_ReceivedPacketWasSent( b:Behavior, c:SHTConfiguration, i:int, idx:int ) requires IsValidBehaviorPrefix(b, c, i); requires 0 <= i; requires 0 <= idx < |b[i].hosts|; requires b[i].hosts[idx].host.receivedPacket.Some?; ensures PacketToLSHTPacket(b[i].hosts[idx].host.receivedPacket.v) in b[i].environment.sentPackets; { Lemma_ConstantsAllConsistent(b, c, i); var s := LSHTState_Refine(b[i]); Lemma_RefinementInvariantHolds(b, c, i); assert BufferedPacketsInv(s); var id := c.hostIds[idx]; Lemma_GetHostIndexIsUnique(c, idx); assert id in AllHostIdentities(s); } lemma Lemma_UnAckedPacketInNetwork( b:Behavior, c:SHTConfiguration, i:int, idx:int, p:LSHTPacket ) requires IsValidBehaviorPrefix(b, c, i); requires 0 <= i; requires 0 <= idx < |b[i].hosts|; requires 0 <= idx < |c.hostIds|; requires p.msg in AckStateLookup(p.dst, b[i].hosts[idx].host.sd.sendState).unAcked; requires p.src == c.hostIds[idx]; ensures p in b[i].environment.sentPackets; { Lemma_ConstantsAllConsistent(b, c, i); var s := LSHTState_Refine(b[i]); Lemma_RefinementInvariantHolds(b, c, i); var id := c.hostIds[idx]; Lemma_GetHostIndexIsUnique(c, idx); assert UnAckedListProperties(s.hosts[id].sd); assert NoAcksInUnAckedLists(s.hosts[id].sd); assert UnAckedListInNetwork(s); reveal_UnAckedListInNetwork(); assert id in AllHostIdentities(s); assert p.msg in AckStateLookup(p.dst, s.hosts[id].sd.sendState).unAcked; assert Packet(p.msg.dst, s.hosts[id].me, p.msg) in s.network; Lemma_HostConstantsMeHasAppropriateValue(b, c, i, idx); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/LiveSHT/LivenessProof/RoundRobin.i.dfy ================================================ include "Assumptions.i.dfy" include "Constants.i.dfy" include "../../../Common/Framework/EnvironmentSynchronyLemmas.i.dfy" include "../../Common/Liveness/RTSchedule.i.dfy" module LivenessProof__RoundRobin_i { import opened Collections__Maps2_s import opened Liveness__EnvironmentSynchronyLemmas_i import opened Liveness__RTSchedule_i import opened LivenessProof__Assumptions_i import opened LivenessProof__Constants_i import opened LiveSHT__Scheduler_i import opened LiveSHT__SHT_i import opened Temporal__Rules_i import opened Temporal__Temporal_s function{:opaque} MakeLSHTAction_ReceivePacket_Temporal( b:Behavior, host_index:int ):temporal requires imaptotal(b); ensures forall i {:trigger sat(i, MakeLSHTAction_ReceivePacket_Temporal(b, host_index))} :: sat(i, MakeLSHTAction_ReceivePacket_Temporal(b, host_index)) <==> b[i].environment.nextStep.LEnvStepHostIos? && 0 <= host_index < |b[i].config.hostIds| && b[i].environment.nextStep.actor == b[i].config.hostIds[host_index] && 0 <= host_index < |b[i].hosts| && b[i].hosts[host_index].nextActionIndex == 0 && var ios := b[i].environment.nextStep.ios; LSHT_NextOneHost(b[i], b[i+1], host_index, ios) && LHost_ReceivePacket_Next(b[i].hosts[host_index].host, b[i+1].hosts[host_index].host, ios); { stepmap(imap i :: b[i].environment.nextStep.LEnvStepHostIos? && 0 <= host_index < |b[i].config.hostIds| && b[i].environment.nextStep.actor == b[i].config.hostIds[host_index] && 0 <= host_index < |b[i].hosts| && b[i].hosts[host_index].nextActionIndex == 0 && var ios := b[i].environment.nextStep.ios; LSHT_NextOneHost(b[i], b[i+1], host_index, ios) && LHost_ReceivePacket_Next(b[i].hosts[host_index].host, b[i+1].hosts[host_index].host, ios)) } function{:opaque} MakeLSHTAction_ProcessReceivedPacket_Temporal( b:Behavior, host_index:int ):temporal requires imaptotal(b); ensures forall i {:trigger sat(i, MakeLSHTAction_ProcessReceivedPacket_Temporal(b, host_index))} :: sat(i, MakeLSHTAction_ProcessReceivedPacket_Temporal(b, host_index)) <==> b[i].environment.nextStep.LEnvStepHostIos? && 0 <= host_index < |b[i].config.hostIds| && b[i].environment.nextStep.actor == b[i].config.hostIds[host_index] && 0 <= host_index < |b[i].hosts| && b[i].hosts[host_index].nextActionIndex == 1 && var ios := b[i].environment.nextStep.ios; LSHT_NextOneHost(b[i], b[i+1], host_index, ios) && LHost_ProcessReceivedPacket_Next(b[i].hosts[host_index].host, b[i+1].hosts[host_index].host, ios); { stepmap(imap i :: b[i].environment.nextStep.LEnvStepHostIos? && 0 <= host_index < |b[i].config.hostIds| && b[i].environment.nextStep.actor == b[i].config.hostIds[host_index] && 0 <= host_index < |b[i].hosts| && b[i].hosts[host_index].nextActionIndex == 1 && var ios := b[i].environment.nextStep.ios; LSHT_NextOneHost(b[i], b[i+1], host_index, ios) && LHost_ProcessReceivedPacket_Next(b[i].hosts[host_index].host, b[i+1].hosts[host_index].host, ios)) } function{:opaque} MakeLSHTAction_NoReceive_Next_Wrapper_Temporal( b:Behavior, host_index:int ):temporal requires imaptotal(b); ensures forall i {:trigger sat(i, MakeLSHTAction_NoReceive_Next_Wrapper_Temporal(b, host_index))} :: sat(i, MakeLSHTAction_NoReceive_Next_Wrapper_Temporal(b, host_index)) <==> b[i].environment.nextStep.LEnvStepHostIos? && 0 <= host_index < |b[i].config.hostIds| && b[i].environment.nextStep.actor == b[i].config.hostIds[host_index] && 0 <= host_index < |b[i].hosts| && b[i].hosts[host_index].nextActionIndex == 2 && var ios := b[i].environment.nextStep.ios; LSHT_NextOneHost(b[i], b[i+1], host_index, ios) && LHost_NoReceive_Next_Wrapper(b[i].hosts[host_index], b[i+1].hosts[host_index], ios); { stepmap(imap i :: b[i].environment.nextStep.LEnvStepHostIos? && 0 <= host_index < |b[i].config.hostIds| && b[i].environment.nextStep.actor == b[i].config.hostIds[host_index] && 0 <= host_index < |b[i].hosts| && b[i].hosts[host_index].nextActionIndex == 2 && var ios := b[i].environment.nextStep.ios; LSHT_NextOneHost(b[i], b[i+1], host_index, ios) && LHost_NoReceive_Next_Wrapper(b[i].hosts[host_index], b[i+1].hosts[host_index], ios)) } function HostSchedule(b:Behavior, host_index:int):seq requires imaptotal(b); { [ MakeLSHTAction_ReceivePacket_Temporal(b, host_index), MakeLSHTAction_ProcessReceivedPacket_Temporal(b, host_index), MakeLSHTAction_NoReceive_Next_Wrapper_Temporal(b, host_index) ] } lemma Lemma_SHTNextTakesSchedulerActionOrLeavesNextActionIndexUnchanged( b:Behavior, asp:AssumptionParameters, host_index:int, next_action_type_fun:imap, scheduler_action:temporal ) requires LivenessAssumptions(b, asp); requires 0 <= host_index < |asp.c.hostIds|; requires imaptotal(next_action_type_fun); requires forall i {:trigger next_action_type_fun[i]} :: next_action_type_fun[i] == if 0 <= host_index < |b[i].hosts| then b[i].hosts[host_index].nextActionIndex else 0; requires forall i :: sat(i, scheduler_action) <==> LSHTHostTakesAction(b[i], b[i+1], host_index); ensures sat(0, always(SchedulerActsOrNextActionTypeUnchangedTemporal(b, next_action_type_fun, scheduler_action))); { var m := SchedulerActsOrNextActionTypeUnchangedTemporal(b, next_action_type_fun, scheduler_action); forall i | 0 <= i ensures sat(i, m); { assert LSHT_Next(b[i], b[i+1]); Lemma_ConstantsAllConsistent(b, asp.c, i); if (exists idx, ios :: LSHT_NextOneHost(b[i], b[i+1], idx, ios)) { var idx, ios :| LSHT_NextOneHost(b[i], b[i+1], idx, ios); if (idx == host_index) { assert sat(i, scheduler_action); } else { assert next_action_type_fun[i] == next_action_type_fun[i+1]; } } else { assert next_action_type_fun[i] == next_action_type_fun[i+1]; } assert sat(i, m); } TemporalAlways(0, m); } lemma Lemma_HostNextPerformsSubactionEventually( b:Behavior, asp:AssumptionParameters, host_index:int, earliest_step:int, action_index:int ) returns (action_step:int) requires LivenessAssumptions(b, asp); requires 0 <= host_index < |asp.c.hostIds|; requires 0 <= action_index < LHost_NumActions(); requires 0 <= earliest_step; ensures earliest_step <= action_step; ensures sat(action_step, HostSchedule(b, host_index)[action_index]); { var next_action_type_fun := imap i :: if 0 <= host_index < |b[i].hosts| then b[i].hosts[host_index].nextActionIndex else 0; var scheduler_action := LSHTHostTakesActionTemporal(b, host_index); var schedule := HostSchedule(b, host_index); Lemma_SHTNextTakesSchedulerActionOrLeavesNextActionIndexUnchanged(b, asp, host_index, next_action_type_fun, scheduler_action); forall i | 0 <= i && sat(i, scheduler_action) ensures var action_type_index := next_action_type_fun[i]; (0 <= action_type_index < |schedule| ==> sat(i, schedule[action_type_index])) && next_action_type_fun[i+1] == (action_type_index + 1) % |schedule|; { } action_step := Lemma_RoundRobinSchedulerEventuallyPerformsSpecificAction(b, next_action_type_fun, scheduler_action, schedule, 0, earliest_step, action_index); } lemma Lemma_HostNextPerformsProcessPacketEventually( b:Behavior, asp:AssumptionParameters, host_index:int, earliest_step:int ) returns (action_step:int) requires LivenessAssumptions(b, asp); requires 0 <= host_index < |asp.c.hostIds|; requires 0 <= earliest_step; ensures earliest_step <= action_step; ensures sat(action_step, ReceiveAttemptedTemporal(RestrictBehaviorToEnvironment(b), asp.c.hostIds[host_index])); { action_step := Lemma_HostNextPerformsSubactionEventually(b, asp, host_index, earliest_step, 0); var host := asp.c.hostIds[host_index]; Lemma_ConstantsAllConsistent(b, asp.c, action_step); var ios := b[action_step].environment.nextStep.ios; assert |ios| >= 1 && (ios[0].LIoOpTimeoutReceive? || ios[0].LIoOpReceive?); assert ReceiveAttemptedInStep(b[action_step].environment, host); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/LiveSHT/LivenessProof/Seqno.i.dfy ================================================ include "InfiniteSends.i.dfy" include "../../../Common/Logic/Temporal/Rules.i.dfy" module LivenessProof__Seqno_i { import opened Environment_s import opened LivenessProof__Actions_i import opened LivenessProof__Acks_i import opened LivenessProof__Assumptions_i import opened LivenessProof__Constants_i import opened LivenessProof__InfiniteSends_i import opened LivenessProof__PacketReceipt_i import opened LivenessProof__RefinementInvariants_i import opened LiveSHT__SHT_i import opened LiveSHT__SHTRefinement_i import opened SHT__Configuration_i import opened SHT__Message_i import opened SHT__SingleDelivery_i import opened SHT__SingleMessage_i import opened Temporal__Rules_i import opened Temporal__Temporal_s lemma Lemma_IfRecipientSequenceNumberNeverBeyondThenPacketReceived( b:Behavior, asp:AssumptionParameters, current_step:int, src_idx:int, dst_idx:int, m:SingleMessage ) returns (receive_step:int, ap:SHTActionParams) requires LivenessAssumptions(b, asp); requires 0 <= src_idx < |asp.c.hostIds|; requires 0 <= dst_idx < |asp.c.hostIds|; requires 0 <= src_idx < |b[current_step].hosts|; requires 0 <= current_step; requires m.SingleMessage?; requires m.dst == asp.c.hostIds[dst_idx]; requires sat(current_step, always(RecipientSequenceNumberBelowTemporal(b, src_idx, dst_idx, m.seqno))); requires m.dst in b[current_step].hosts[src_idx].host.sd.sendState; requires m in b[current_step].hosts[src_idx].host.sd.sendState[m.dst].unAcked; ensures current_step <= receive_step; ensures SHTActionOccurred(b[receive_step], b[receive_step+1], ap); ensures ap.idx == dst_idx; ensures ap.nextActionIndex == 0; ensures b[receive_step].hosts[dst_idx].host.receivedPacket.None?; ensures |ap.ios| > 0; ensures ap.ios[0] == LIoOpReceive(LPacket(m.dst, asp.c.hostIds[src_idx], m)); { var p := LPacket(m.dst, asp.c.hostIds[src_idx], m); Lemma_IfRecipientSequenceNumberNeverBeyondThenPacketSentInfinitelyOften(b, asp, current_step, src_idx, dst_idx, m); receive_step, ap := Lemma_PacketSentInfinitelyOftenEventuallyReceived(b, asp, current_step, src_idx, dst_idx, p); } lemma Lemma_IfTheresAnUnackedPacketThenRecipientSequenceNumberIncreases( b:Behavior, asp:AssumptionParameters, current_step:int, src_idx:int, dst_idx:int, m:SingleMessage ) returns (next_step:int) requires LivenessAssumptions(b, asp); requires 0 <= src_idx < |asp.c.hostIds|; requires 0 <= dst_idx < |asp.c.hostIds|; requires 0 <= src_idx < |b[current_step].hosts|; requires 0 <= dst_idx < |b[current_step].hosts|; requires 0 <= current_step; requires m.SingleMessage?; requires m.dst == asp.c.hostIds[dst_idx]; requires m.dst in b[current_step].hosts[src_idx].host.sd.sendState; requires m in b[current_step].hosts[src_idx].host.sd.sendState[m.dst].unAcked; requires TombstoneTableLookup(asp.c.hostIds[src_idx], b[current_step].hosts[dst_idx].host.sd.receiveState) < m.seqno; ensures current_step <= next_step; ensures 0 <= dst_idx < |b[next_step].hosts|; ensures TombstoneTableLookup(asp.c.hostIds[src_idx], b[next_step].hosts[dst_idx].host.sd.receiveState) > TombstoneTableLookup(asp.c.hostIds[src_idx], b[current_step].hosts[dst_idx].host.sd.receiveState); { var src := asp.c.hostIds[src_idx]; var dst := asp.c.hostIds[dst_idx]; Lemma_GetHostIndexIsUnique(asp.c, src_idx); Lemma_GetHostIndexIsUnique(asp.c, dst_idx); Lemma_ConstantsAllConsistent(b, asp.c, current_step); var receiveState := b[current_step].hosts[dst_idx].host.sd.receiveState; var sendState := b[current_step].hosts[src_idx].host.sd.sendState; var recipientSeqno := TombstoneTableLookup(src, receiveState); var senderNumAcked := AckStateLookup(dst, sendState).numPacketsAcked; Lemma_NumPacketsAckedBeforeRecipientSequenceNumber(b, asp.c, current_step, src_idx, dst_idx); assert senderNumAcked <= recipientSeqno < m.seqno; var pos := Lemma_GetPositionOfMessageInUnackedList(b, asp.c, current_step, src_idx, dst, m); assert pos == m.seqno - senderNumAcked - 1 >= 0; var m_expected := sendState[dst].unAcked[recipientSeqno - senderNumAcked]; Lemma_MessageInUnackedListHasParticularSeqno(b, asp.c, current_step, src_idx, dst, m_expected, recipientSeqno - senderNumAcked); assert m_expected.seqno == recipientSeqno + 1; Lemma_MessageInUnackedListHasParticularDestination(b, asp.c, current_step, src_idx, dst, m_expected); if sat(current_step, always(RecipientSequenceNumberBelowTemporal(b, src_idx, dst_idx, m_expected.seqno))) { var receive_step, ap := Lemma_IfRecipientSequenceNumberNeverBeyondThenPacketReceived(b, asp, current_step, src_idx, dst_idx, m_expected); Lemma_ConstantsAllConsistent(b, asp.c, receive_step); assert ap.pkt.msg == m_expected; var last_seqno := TombstoneTableLookup(ap.pkt.src, ap.host.sd.receiveState); Lemma_RecipientSequenceNumberMonotonic(b, asp.c, current_step, receive_step, src, dst_idx); assert last_seqno >= recipientSeqno; if m_expected.seqno == last_seqno + 1 { assert NewSingleMessage(ap.host.sd, ap.pkt); next_step := receive_step + 1; assert TombstoneTableLookup(src, b[next_step].hosts[dst_idx].host.sd.receiveState) >= m_expected.seqno; } else { next_step := receive_step; assert TombstoneTableLookup(src, b[receive_step].hosts[dst_idx].host.sd.receiveState) >= m_expected.seqno; } return; } TemporalNot(current_step, RecipientSequenceNumberBelowTemporal(b, src_idx, dst_idx, m_expected.seqno)); next_step := TemporalDeduceFromEventual(current_step, not(RecipientSequenceNumberBelowTemporal(b, src_idx, dst_idx, m_expected.seqno))); Lemma_ConstantsAllConsistent(b, asp.c, next_step); } lemma Lemma_IfTheresAnUnackedPacketThenRecipientSequenceNumberReachesItsSequenceNumber( b:Behavior, asp:AssumptionParameters, current_step:int, src_idx:int, dst_idx:int, m:SingleMessage ) returns (next_step:int) requires LivenessAssumptions(b, asp); requires 0 <= src_idx < |asp.c.hostIds|; requires 0 <= dst_idx < |asp.c.hostIds|; requires 0 <= src_idx < |b[current_step].hosts|; requires 0 <= dst_idx < |b[current_step].hosts|; requires 0 <= current_step; requires m.SingleMessage?; requires m.dst == asp.c.hostIds[dst_idx]; requires m.dst in b[current_step].hosts[src_idx].host.sd.sendState; requires m in b[current_step].hosts[src_idx].host.sd.sendState[m.dst].unAcked; ensures current_step <= next_step; ensures 0 <= dst_idx < |b[next_step].hosts|; ensures TombstoneTableLookup(asp.c.hostIds[src_idx], b[next_step].hosts[dst_idx].host.sd.receiveState) >= m.seqno; decreases m.seqno - TombstoneTableLookup(asp.c.hostIds[src_idx], b[current_step].hosts[dst_idx].host.sd.receiveState); { var src := asp.c.hostIds[src_idx]; var dst := asp.c.hostIds[dst_idx]; Lemma_GetHostIndexIsUnique(asp.c, src_idx); Lemma_GetHostIndexIsUnique(asp.c, dst_idx); Lemma_ConstantsAllConsistent(b, asp.c, current_step); var x := RecipientSequenceNumberBelowTemporal(b, src_idx, dst_idx, m.seqno); if !sat(current_step, always(x)) { TemporalNot(current_step, x); next_step := TemporalDeduceFromEventual(current_step, not(x)); Lemma_ConstantsAllConsistent(b, asp.c, next_step); return; } TemporalDeduceFromAlways(current_step, current_step, x); assert TombstoneTableLookup(src, b[current_step].hosts[dst_idx].host.sd.receiveState) < m.seqno; var intermediate_step := Lemma_IfTheresAnUnackedPacketThenRecipientSequenceNumberIncreases(b, asp, current_step, src_idx, dst_idx, m); Lemma_ConstantsAllConsistent(b, asp.c, intermediate_step); TemporalDeduceFromAlways(current_step, intermediate_step, x); assert TombstoneTableLookup(src, b[intermediate_step].hosts[dst_idx].host.sd.receiveState) < m.seqno; Lemma_IfRecipientSequenceNumberNeverBeyondThenPacketStaysInSendState(b, asp, current_step, intermediate_step, src_idx, dst_idx, m); next_step := Lemma_IfTheresAnUnackedPacketThenRecipientSequenceNumberReachesItsSequenceNumber(b, asp, intermediate_step, src_idx, dst_idx, m); Lemma_ConstantsAllConsistent(b, asp.c, next_step); } lemma Lemma_GetReceiveStepForSequenceNumber( b:Behavior, c:SHTConfiguration, i:int, j:int, src_idx:int, dst_idx:int, seqno:int ) returns (receive_step:int, ap:SHTActionParams) requires IsValidBehaviorPrefix(b, c, j); requires 0 <= i <= j; requires |c.hostIds| == |b[i].hosts| == |b[j].hosts|; requires 0 <= src_idx < |c.hostIds|; requires 0 <= dst_idx < |c.hostIds|; requires TombstoneTableLookup(c.hostIds[src_idx], b[i].hosts[dst_idx].host.sd.receiveState) < seqno; requires TombstoneTableLookup(c.hostIds[src_idx], b[j].hosts[dst_idx].host.sd.receiveState) >= seqno; ensures i <= receive_step < j; ensures SHTActionOccurred(b[receive_step], b[receive_step+1], ap); ensures ap.idx == dst_idx; ensures ap.nextActionIndex == 0; ensures b[receive_step].hosts[dst_idx].host.receivedPacket.None?; ensures b[receive_step+1].hosts[dst_idx].host.receivedPacket.Some?; ensures ap.pkt.msg.SingleMessage?; ensures ap.pkt.msg.seqno == seqno; ensures |ap.ios| > 0; ensures ap.ios[0].LIoOpReceive?; ensures ap.ios[0].r.msg == ap.pkt.msg; ensures ap.ios[0].r.src == c.hostIds[src_idx]; { Lemma_ConstantsAllConsistent(b, c, i); Lemma_ConstantsAllConsistent(b, c, j); var x := RecipientSequenceNumberBelowTemporal(b, src_idx, dst_idx, seqno); receive_step := earliestStepBetween(i, j, not(x)) - 1; assert i <= receive_step < j; assert !sat(receive_step, not(x)); assert sat(receive_step, x); assert sat(receive_step + 1, not(x)); Lemma_ConstantsAllConsistent(b, c, receive_step); Lemma_AssumptionsMakeValidTransition(b, c, receive_step); ap := Lemma_ActionThatChangesHostIsThatHostsAction(b, c, receive_step, dst_idx); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/LiveSHT/RefinementProof/Environment.i.dfy ================================================ include "../../SHT/SingleDelivery.i.dfy" include "../../SHT/Message.i.dfy" include "../../../Common/Framework/Environment.s.dfy" module LiveSHT__Environment_i { import opened Concrete_NodeIdentity_i`Spec import opened SHT__Message_i import opened SHT__SingleMessage_i import opened SHT__SingleDelivery_i import opened Environment_s type LSHTEnvironment = LEnvironment> type LSHTPacket = LPacket> type LSHTIo = LIoOp> function ConcatenateSHTIos(s:seq>) : seq { if |s| == 0 then [] else s[0] + ConcatenateSHTIos(s[1..]) } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/LiveSHT/RefinementProof/EnvironmentLemmas.i.dfy ================================================ include "../../../Common/Framework/Environment.s.dfy" include "EnvironmentRefinement.i.dfy" module LiveSHT__EnvironmentLemmas_i { import opened Environment_s import opened LiveSHT__Environment_i import opened LiveSHT__EnvironmentRefinement_i lemma Lemma_EffectOnLSHTEnvironmentRefinementOfAddingPackets(e:LSHTEnvironment, e':LSHTEnvironment, ios:seq) requires e'.sentPackets == e.sentPackets + (set io | io in ios && io.LIoOpSend? :: io.s); ensures LSHTEnvironment_Refine(e') == LSHTEnvironment_Refine(e) + LSHTIoSeq_RefineAsSends(ios); { } lemma Lemma_LSHTIoSeq_RefineAsSendsEmptyHelper(x: T, s1: set, s2: set) requires x in s1 requires x !in s2 ensures s1 != s2 { } lemma Lemma_LSHTIoSeq_RefineAsSendsEmpty(ios:seq) requires (set io | io in ios && io.LIoOpSend? :: io.s) == {}; ensures LSHTIoSeq_RefineAsSends(ios) == {}; { var sends := LSHTIoSeq_RefineAsSends(ios); if (|sends| > 0) { var io' :| io' in ios && io'.LIoOpSend?; assert io'.s in (set io | io in ios && io.LIoOpSend? :: io.s); Lemma_LSHTIoSeq_RefineAsSendsEmptyHelper(io'.s, set io | io in ios && io.LIoOpSend? :: io.s, {}); assert false; } } lemma Lemma_LSHTPacketSetRefineIsCommutative(l_ps1:set, l_ps2:set) ensures LSHTPacketSet_Refine(l_ps1 + l_ps2) == LSHTPacketSet_Refine(l_ps1) + LSHTPacketSet_Refine(l_ps2); { var h_ps1 := LSHTPacketSet_Refine(l_ps1); var h_ps2 := LSHTPacketSet_Refine(l_ps2); var l_ps := l_ps1 + l_ps2; var h_ps := LSHTPacketSet_Refine(l_ps); forall h_p | h_p in h_ps1 ensures h_p in h_ps; { } forall h_p | h_p in h_ps2 ensures h_p in h_ps; { } forall h_p | h_p in h_ps ensures (h_p in h_ps1) || (h_p in h_ps2); { } } lemma Lemma_LSHTPacketSetRefineOfOnePacket(l_ps:LSHTPacket) ensures LSHTPacketSet_Refine({l_ps}) == { LSHTPacket_Refine(l_ps) }; { } lemma Lemma_LSHTPacketSeqRefineIsCommutative(l_ps1:seq, l_ps2:seq) ensures LSHTPacketSeq_Refine(l_ps1 + l_ps2) == LSHTPacketSeq_Refine(l_ps1) + LSHTPacketSeq_Refine(l_ps2); { var h_ps1 := LSHTPacketSeq_Refine(l_ps1); var h_ps2 := LSHTPacketSeq_Refine(l_ps2); var l_ps := l_ps1 + l_ps2; var h_ps := LSHTPacketSeq_Refine(l_ps); forall h_p | h_p in h_ps1 ensures h_p in h_ps; { } forall h_p | h_p in h_ps2 ensures h_p in h_ps; { } forall h_p | h_p in h_ps ensures (h_p in h_ps1) || (h_p in h_ps2); { } } lemma Lemma_LSHTPacketSeqRefineOfOnePacket(l_ps:LSHTPacket) ensures LSHTPacketSeq_Refine([l_ps]) == { LSHTPacket_Refine(l_ps) }; { } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/LiveSHT/RefinementProof/EnvironmentRefinement.i.dfy ================================================ include "Environment.i.dfy" include "../../SHT/Network.i.dfy" module LiveSHT__EnvironmentRefinement_i { import opened LiveSHT__Environment_i import opened SHT__Network_i function LSHTPacket_Refine(p:LSHTPacket) : Packet { Packet(p.dst, p.src, p.msg) } function LSHTPacketSet_Refine(packets:set) : set { set p | p in packets :: LSHTPacket_Refine(p) } function LSHTPacketSeq_Refine(packets:seq) : set { set p | p in packets :: LSHTPacket_Refine(p) } function LSHTIoSeq_RefineAsSends(ios:seq) : set { set io | io in ios && io.LIoOpSend? :: LSHTPacket_Refine(io.s) } function LSHTIoSeq_RefineAsReceives(ios:seq) : set { set io | io in ios && io.LIoOpReceive? :: LSHTPacket_Refine(io.r) } function LSHTEnvironment_Refine(e:LSHTEnvironment) : Network { set p | p in e.sentPackets :: LSHTPacket_Refine(p) } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/LiveSHT/RefinementProof/SHT.i.dfy ================================================ include "../../SHT/Host.i.dfy" include "../../SHT/Configuration.i.dfy" include "../../../Common/Framework/Environment.s.dfy" include "../Scheduler.i.dfy" module LiveSHT__SHT_i { import opened SHT__Host_i import opened SHT__Configuration_i import opened Environment_s import opened Concrete_NodeIdentity_i`Spec import opened LiveSHT__Scheduler_i import opened LiveSHT__Environment_i datatype LSHT_State = LSHT_State( config:SHTConfiguration, environment:LSHTEnvironment, hosts:seq ) predicate LSHT_MapsComplete(s:LSHT_State) { |s.config.hostIds| == |s.hosts| && WFSHTConfiguration(s.config) && (forall i :: 0 <= i < |s.config.hostIds| ==> s.hosts[i].host.me == s.config.hostIds[i]) } predicate LSHT_Init(config:SHTConfiguration, s:LSHT_State) { LSHT_MapsComplete(s) && s.config == config && LEnvironment_Init(s.environment) && (forall i :: 0 <= i < |s.config.hostIds| ==> LScheduler_Init(s.hosts[i], s.config.hostIds[i], s.config.rootIdentity, s.config.hostIds, s.config.params)) } predicate LSHT_NextOneHost(s:LSHT_State, s':LSHT_State, idx:int, ios:seq) { LSHT_MapsComplete(s) && LSHT_MapsComplete(s') && s'.config == s.config && 0 <= idx < |s.config.hostIds| && LScheduler_Next(s.hosts[idx], s'.hosts[idx], ios) && LEnvironment_Next(s.environment, s'.environment) && s.environment.nextStep == LEnvStepHostIos(s.config.hostIds[idx], ios) && s'.hosts == s.hosts[idx := s'.hosts[idx]] } predicate LSHT_NextEnvironment(s:LSHT_State, s':LSHT_State) { !s.environment.nextStep.LEnvStepHostIos? && LEnvironment_Next(s.environment, s'.environment) && s'.config == s.config && s'.hosts == s.hosts } predicate LSHT_NextExternal(s:LSHT_State, s':LSHT_State, eid:NodeIdentity, ios:seq) { LSHT_MapsComplete(s) && LSHT_MapsComplete(s') && eid !in s.config.hostIds && LEnvironment_Next(s.environment, s'.environment) && s.environment.nextStep == LEnvStepHostIos(eid, ios) && s'.config == s.config && s'.hosts == s.hosts } predicate LSHT_Next(s:LSHT_State, s':LSHT_State) { (exists idx, ios :: LSHT_NextOneHost(s, s', idx, ios)) || (exists idx, ios :: LSHT_NextExternal(s, s', idx, ios)) || LSHT_NextEnvironment(s, s') } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/LiveSHT/RefinementProof/SHTLemmas.i.dfy ================================================ include "../../../Common/Collections/Maps2.i.dfy" include "SHTRefinement.i.dfy" include "SchedulerRefinement.i.dfy" include "SchedulerLemmas.i.dfy" include "EnvironmentLemmas.i.dfy" include "SHT.i.dfy" module RefinementProof__DistributedSystemLemmas_i { import opened Native__Io_s import opened Collections__Maps2_s import opened Collections__Maps2_i import opened Concrete_NodeIdentity_i`Spec import opened Environment_s import opened SHT__Host_i import opened SHT__Network_i import opened SHT__SHT_i import opened SHT__Configuration_i import opened LiveSHT__SHTRefinement_i import opened LiveSHT__Scheduler_i import opened LiveSHT__SchedulerRefinement_i import opened LiveSHT__SchedulerLemmas_i import opened LiveSHT__EnvironmentLemmas_i import opened LiveSHT__SHT_i import opened LiveSHT__EnvironmentRefinement_i import opened LiveSHT__Environment_i lemma Lemma_HostNextImpliesHostNextWithBiggerReceiveSet(s:Host, s':Host, recvs1:set, recvs2:set, out:set) requires Host_Next(s, s', recvs1, out); requires recvs1 <= recvs2; ensures Host_Next(s, s', recvs1, out); { } lemma {:timeLimitMultiplier 2} Lemma_HostRefinementAllowsSHTStateRefinement( ps:SHT_State, ps':SHT_State, actor:NodeIdentity, environment:LSHTEnvironment, environment':LSHTEnvironment, ios:seq ) requires environment.nextStep == LEnvStepHostIos(actor, ios); requires LEnvironment_Next(environment, environment'); requires SHT_MapsComplete(ps); requires SHT_MapsComplete(ps'); requires ps'.config == ps.config; requires actor in ps.hosts; requires actor in ps'.hosts; requires forall id :: id in ps.hosts <==> id in ps'.hosts; requires forall id :: id in ps.hosts <==> id in ps.config.hostIds; requires forall oid :: oid in ps.config.hostIds && oid != actor ==> ps'.hosts[oid] == ps.hosts[oid]; requires actor in ps.config.hostIds; requires ps.network == LSHTEnvironment_Refine(environment); requires ps'.network == LSHTEnvironment_Refine(environment'); requires HostNextOrStutter(ps.hosts[actor], ps'.hosts[actor], PacketsTo(LSHTEnvironment_Refine(environment), actor), LSHTIoSeq_RefineAsSends(ios)); ensures SHTNextOrStutter(ps, ps'); { var receives := PacketsTo(LSHTEnvironment_Refine(environment), actor); var sends := LSHTIoSeq_RefineAsSends(ios); var host := ps.hosts[actor]; var host' := ps'.hosts[actor]; Lemma_EffectOnLSHTEnvironmentRefinementOfAddingPackets(environment, environment', ios); if host' == host && sends == {} { assert ps'.network == ps.network; assert ps'.hosts == ps.hosts; assert ps' == ps; return; } assert receives <= PacketsTo(ps.network, actor); assert Host_Next(host, host', receives, sends); Lemma_HostNextImpliesHostNextWithBiggerReceiveSet(host, host', receives, PacketsTo(ps.network, actor), sends); assert Host_Next(host, host', PacketsTo(ps.network, actor), sends); assert SHT_NextPred(ps, ps', actor, PacketsTo(ps.network, actor), sends); assert SHT_Next(ps, ps'); assert SHTNextOrStutter(ps, ps'); } lemma Lemma_LSHTInitImpliesSHTInit(l_config:SHTConfiguration, l_ps:LSHT_State) requires LSHT_Init(l_config, l_ps); ensures SHT_Init(LSHTConfiguration_Refine(l_config), LSHTState_Refine(l_ps)); ensures LSHTState_RefinementInvariant(l_ps); { var h_config := l_config; var h_ps := LSHTState_Refine(l_ps); forall nodeIndex | 0 <= nodeIndex < |h_config.hostIds| ensures Host_Init(h_ps.hosts[h_config.hostIds[nodeIndex]], h_config.hostIds[nodeIndex], h_config.rootIdentity, h_config.hostIds, h_config.params); ensures LScheduler_RefinementInvariant(l_ps.hosts[nodeIndex]); { Lemma_GetHostIndexIsUnique(l_config, nodeIndex); } } lemma Lemma_LSHTNextPreservesLocalInvariant(ps:LSHT_State, ps':LSHT_State) requires LSHTState_RefinementInvariant(ps); requires LSHT_Next(ps, ps'); ensures |ps.hosts| == |ps'.hosts|; ensures |ps'.hosts| == |ps'.config.hostIds|; { } lemma Lemma_SHTStateRefinementLeavesHostDomainUnchanged(l_ps:LSHT_State, h_ps:SHT_State) requires LSHTState_RefinementInvariant(l_ps); requires h_ps == LSHTState_Refine(l_ps); ensures forall id :: id in l_ps.config.hostIds <==> id in mapdomain(h_ps.hosts); { forall id | id in l_ps.config.hostIds ensures id in mapdomain(h_ps.hosts); { assert id in h_ps.hosts; } } lemma Lemma_LSHTNextOneHostMaintainsInvariant(l_s:LSHT_State, l_s':LSHT_State, idx:int, ios:seq) requires l_s.config == l_s'.config; requires LSHT_NextOneHost(l_s, l_s', idx, ios); requires LSHTState_RefinementInvariant(l_s); ensures LSHTState_RefinementInvariant(l_s'); { Lemma_LSHTNextPreservesLocalInvariant(l_s, l_s'); Lemma_LSchedulerNextImpliesHostNextOrStutter(l_s.hosts[idx], l_s'.hosts[idx], l_s.environment, l_s'.environment, ios); } lemma Lemma_LSHTNextOneHostImpliesSHTNext(l_ps:LSHT_State, l_ps':LSHT_State, idx:int, ios:seq) requires LSHT_NextOneHost(l_ps, l_ps', idx, ios); requires LSHTState_RefinementInvariant(l_ps); ensures LSHTState_RefinementInvariant(l_ps'); ensures SHTNextOrStutter(LSHTState_Refine(l_ps), LSHTState_Refine(l_ps')); { var h_ps := LSHTState_Refine(l_ps); Lemma_LSHTNextOneHostMaintainsInvariant(l_ps, l_ps', idx, ios); var h_ps' := LSHTState_Refine(l_ps'); var id := l_ps.config.hostIds[idx]; Lemma_SHTStateRefinementLeavesHostDomainUnchanged(l_ps, h_ps); Lemma_SHTStateRefinementLeavesHostDomainUnchanged(l_ps', h_ps'); assert mapdomain(h_ps'.hosts) == mapdomain(h_ps.hosts); forall oid | oid != id && oid in h_ps.hosts ensures oid in h_ps'.hosts && h_ps'.hosts[oid] == h_ps.hosts[oid]; { assert oid in mapdomain(h_ps.hosts); assert oid in mapdomain(h_ps'.hosts); var idx' := GetHostIndex(oid, l_ps.config); calc { h_ps.hosts[oid]; (l_ps.hosts[idx'].host); (l_ps'.hosts[idx'].host); h_ps'.hosts[oid]; } } Lemma_LSchedulerNextImpliesHostNextOrStutter(l_ps.hosts[idx], l_ps'.hosts[idx], l_ps.environment, l_ps'.environment, ios); Lemma_GetHostIndexIsUnique(l_ps.config, idx); Lemma_HostRefinementAllowsSHTStateRefinement(h_ps, h_ps', id, l_ps.environment, l_ps'.environment, ios); } lemma Lemma_LSHTNextExternalImpliesSHTNext(l_ps:LSHT_State, l_ps':LSHT_State, idx:EndPoint, ios:seq) requires LSHT_NextExternal(l_ps, l_ps', idx, ios); requires LSHTState_RefinementInvariant(l_ps); ensures LSHTState_RefinementInvariant(l_ps'); ensures SHTNextOrStutter(LSHTState_Refine(l_ps), LSHTState_Refine(l_ps')); { var h_ps := LSHTState_Refine(l_ps); //Lemma_LSHTNextOneHostMaintainsInvariant(l_ps, l_ps', idx, ios); var h_ps' := LSHTState_Refine(l_ps'); Lemma_SHTStateRefinementLeavesHostDomainUnchanged(l_ps, h_ps); Lemma_SHTStateRefinementLeavesHostDomainUnchanged(l_ps', h_ps'); assert mapdomain(h_ps'.hosts) == mapdomain(h_ps.hosts); var s := [h_ps, h_ps']; assert SHT_NextExternal(h_ps, h_ps', idx, LSHTIoSeq_RefineAsSends(ios), LSHTIoSeq_RefineAsSends(ios)); // OBSERVE: exists assert SHTNextOrStutter(h_ps, h_ps'); } lemma Lemma_LSHTNextEnvironmentImpliesSHTNext(l_s:LSHT_State, l_s':LSHT_State) requires LSHT_NextEnvironment(l_s, l_s'); requires LSHTState_RefinementInvariant(l_s); requires LSHTState_RefinementInvariant(l_s'); ensures SHTNextOrStutter(LSHTState_Refine(l_s), LSHTState_Refine(l_s')); { var h_s := LSHTState_Refine(l_s); var h_s' := LSHTState_Refine(l_s'); assert h_s'.hosts == h_s.hosts; var s := [h_s]; assert s[0] == LSHTState_Refine(l_s); assert h_s'.network == h_s.network; assert SHTNextOrStutter(LSHTState_Refine(l_s), LSHTState_Refine(l_s')); } lemma Lemma_LSHTNextImpliesSHTNext(l_s:LSHT_State, l_s':LSHT_State) requires LSHT_Next(l_s, l_s'); requires LSHTState_RefinementInvariant(l_s); ensures LSHTState_RefinementInvariant(l_s'); ensures SHTNextOrStutter(LSHTState_Refine(l_s), LSHTState_Refine(l_s')); { if (exists idx, ios :: LSHT_NextOneHost(l_s, l_s', idx, ios)) { var idx, ios :| LSHT_NextOneHost(l_s, l_s', idx, ios); Lemma_LSHTNextOneHostImpliesSHTNext(l_s, l_s', idx, ios); } else if (exists idx, ios :: LSHT_NextExternal(l_s, l_s', idx, ios)) { var idx, ios :| LSHT_NextExternal(l_s, l_s', idx, ios); Lemma_LSHTNextExternalImpliesSHTNext(l_s, l_s', idx, ios); } else if LSHT_NextEnvironment(l_s, l_s') { Lemma_LSHTNextEnvironmentImpliesSHTNext(l_s, l_s'); } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/LiveSHT/RefinementProof/SHTRefinement.i.dfy ================================================ include "../../../Common/Collections/Maps2.i.dfy" include "SHT.i.dfy" include "SchedulerRefinement.i.dfy" include "EnvironmentRefinement.i.dfy" include "../../SHT/RefinementProof/SHT.i.dfy" include "../../../Common/Collections/Seqs.i.dfy" module LiveSHT__SHTRefinement_i { import opened Collections__Maps2_i import opened Concrete_NodeIdentity_i`Spec import opened LiveSHT__SHT_i import opened LiveSHT__SchedulerRefinement_i import opened LiveSHT__EnvironmentRefinement_i import opened SHT__SHT_i import opened SHT__Configuration_i import opened Collections__Seqs_i function LSHTConfiguration_Refine(c:SHTConfiguration) : SHTConfiguration { c } function GetHostIndex(id:NodeIdentity, c:SHTConfiguration):int requires id in c.hostIds; ensures var idx := GetHostIndex(id, c); 0 <= idx < |c.hostIds| && c.hostIds[idx] == id; { FindIndexInSeq(c.hostIds, id) } lemma Lemma_GetHostIndexIsUnique(c:SHTConfiguration, idx:int) requires WFSHTConfiguration(c); requires 0 <= idx < |c.hostIds|; ensures GetHostIndex(c.hostIds[idx], c) == idx; { var j := GetHostIndex(c.hostIds[idx], c); assert HostsDistinct(c.hostIds, idx, j); } function LSHTState_Refine(s:LSHT_State) : SHT_State requires LSHT_MapsComplete(s); ensures SHT_MapsComplete(LSHTState_Refine(s)) { SHT_State(LSHTConfiguration_Refine(s.config), LSHTEnvironment_Refine(s.environment), (map id {:trigger LScheduler_Refine(s.hosts[GetHostIndex(id, s.config)])} | id in s.config.hostIds :: LScheduler_Refine(s.hosts[GetHostIndex(id, s.config)]))) } predicate LSHTState_RefinementInvariant(s:LSHT_State) { |s.hosts| == |s.config.hostIds| && LSHT_MapsComplete(s) && (forall nodeIndex :: 0 <= nodeIndex < |s.config.hostIds| ==> LScheduler_RefinementInvariant(s.hosts[nodeIndex])) } predicate SHTNextOrStutter(ls:SHT_State, ls':SHT_State) { ls == ls' || SHT_Next(ls, ls') } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/LiveSHT/RefinementProof/SchedulerLemmas.i.dfy ================================================ include "SchedulerRefinement.i.dfy" include "EnvironmentRefinement.i.dfy" include "Environment.i.dfy" module LiveSHT__SchedulerLemmas_i { import opened Environment_s import opened SHT__Host_i import opened SHT__Network_i import opened LiveSHT__SchedulerRefinement_i import opened LiveSHT__EnvironmentRefinement_i import opened LiveSHT__Environment_i import opened LiveSHT__Scheduler_i lemma Lemma_LHostNextReceivePacketImpliesHostNextOrStutter( l_host:Host, l_host':Host, l_environment:LSHTEnvironment, l_environment':LSHTEnvironment, ios:seq ) requires l_host.constants == l_host'.constants; requires LEnvironment_Next(l_environment, l_environment'); requires l_environment.nextStep == LEnvStepHostIos(l_host.me, ios); requires LHost_ReceivePacket_Next(l_host, l_host', ios); ensures HostNextOrStutter(l_host, l_host', PacketsTo(LSHTEnvironment_Refine(l_environment), l_host.me), LSHTIoSeq_RefineAsSends(ios)); { if (ios[0].LIoOpTimeoutReceive?) { assert l_host == l_host'; return; } assert ios[0].r in l_environment.sentPackets; assert IsValidLEnvStep(l_environment, l_environment.nextStep); assert IsValidLIoOp(ios[0], l_host.me, l_environment); assert ios[0].r.dst == l_host.me; var sent_packets := ExtractSentPacketsFromIos(ios); Lemma_HostRefinementForPacketsAppliesToIos(l_host, l_host', PacketsTo(LSHTEnvironment_Refine(l_environment), l_host.me), sent_packets, l_environment, l_environment', ios); } lemma Lemma_LHostNextProcessReceivedPacketImpliesHostNextOrStutter( l_host:Host, l_host':Host, l_environment:LSHTEnvironment, l_environment':LSHTEnvironment, ios:seq ) requires l_host.constants == l_host'.constants; requires l_host.me == l_host'.me; requires LHost_ProcessReceivedPacket_Next(l_host, l_host', ios); requires LEnvironment_Next(l_environment, l_environment'); requires l_environment.nextStep == LEnvStepHostIos(l_host.me, ios); ensures HostNextOrStutter(l_host, l_host', PacketsTo(LSHTEnvironment_Refine(l_environment), l_host.me), LSHTIoSeq_RefineAsSends(ios)); { var sent_packets := ExtractSentPacketsFromIos(ios); Lemma_HostRefinementForPacketsAppliesToIos(l_host, l_host', PacketsTo(LSHTEnvironment_Refine(l_environment), l_host.me), sent_packets, l_environment, l_environment', ios); } lemma Lemma_LHostNextSpontaneousImpliesHostNextOrStutter( l_scheduler:LScheduler, l_scheduler':LScheduler, l_environment:LSHTEnvironment, l_environment':LSHTEnvironment, ios:seq ) requires LHost_NoReceive_Next_Wrapper(l_scheduler, l_scheduler', ios); requires LEnvironment_Next(l_environment, l_environment'); requires l_environment.nextStep == LEnvStepHostIos(l_scheduler.host.me, ios); ensures HostNextOrStutter(l_scheduler.host, l_scheduler'.host, PacketsTo(LSHTEnvironment_Refine(l_environment), l_scheduler.host.me), LSHTIoSeq_RefineAsSends(ios)); { if (l_scheduler'.resendCount == 0) { var sent_packets := ExtractSentPacketsFromIos(ios); Lemma_HostRefinementForPacketsAppliesToIos(l_scheduler.host, l_scheduler'.host, PacketsTo(LSHTEnvironment_Refine(l_environment), l_scheduler.host.me), sent_packets, l_environment, l_environment', ios); } else { assert l_scheduler'.host == l_scheduler.host; assert ios == []; } } lemma Lemma_LSchedulerNextImpliesHostNextOrStutter(l_scheduler:LScheduler, l_scheduler':LScheduler, l_environment:LSHTEnvironment, l_environment':LSHTEnvironment, ios:seq) requires l_scheduler.host.constants == l_scheduler'.host.constants; requires l_scheduler.host.me == l_scheduler'.host.me; requires LScheduler_Next(l_scheduler, l_scheduler', ios); requires LEnvironment_Next(l_environment, l_environment'); requires l_environment.nextStep == LEnvStepHostIos(l_scheduler.host.me, ios); requires LScheduler_RefinementInvariant(l_scheduler); ensures LScheduler_RefinementInvariant(l_scheduler'); ensures HostNextOrStutter(l_scheduler.host, l_scheduler'.host, PacketsTo(LSHTEnvironment_Refine(l_environment), l_scheduler.host.me), LSHTIoSeq_RefineAsSends(ios)); { assert 0 <= l_scheduler'.nextActionIndex < LHost_NumActions(); var l_host := l_scheduler.host; var l_host' := l_scheduler'.host; if l_scheduler.nextActionIndex == 0 { Lemma_LHostNextReceivePacketImpliesHostNextOrStutter(l_host, l_host', l_environment, l_environment', ios); } else if l_scheduler.nextActionIndex == 1 { Lemma_LHostNextProcessReceivedPacketImpliesHostNextOrStutter(l_host, l_host', l_environment, l_environment', ios); } else if l_scheduler.nextActionIndex == 2 { Lemma_LHostNextSpontaneousImpliesHostNextOrStutter(l_scheduler, l_scheduler', l_environment, l_environment', ios); } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/LiveSHT/RefinementProof/SchedulerRefinement.i.dfy ================================================ include "../Scheduler.i.dfy" include "../../SHT/Host.i.dfy" include "EnvironmentRefinement.i.dfy" module LiveSHT__SchedulerRefinement_i { import opened LiveSHT__Scheduler_i import opened LiveSHT__EnvironmentRefinement_i import opened Environment_s import opened SHT__Host_i import opened SHT__Network_i import opened LiveSHT__Environment_i function AddPacketSets(ps:seq>) : set ensures forall i :: 0 <= i < |ps| ==> ps[i] <= AddPacketSets(ps); { if |ps| == 0 then {} else ps[0] + AddPacketSets(ps[1..]) } predicate HostNextOrStutter(host:Host, host':Host, receives:set, sends:set) { (host == host' && sends == {}) || ( (forall p :: p in receives ==> p.dst == host.me) && (forall p :: p in sends ==> p.src == host.me) && Host_Next(host, host', receives, sends)) } lemma Lemma_HostRefinementForPacketsAppliesToIos( host:Host, host':Host, receives:set, sent_packets:seq, environment:LSHTEnvironment, environment':LSHTEnvironment, ios:seq ) requires LEnvironment_Next(environment, environment'); requires environment.nextStep == LEnvStepHostIos(host.me, ios); requires receives <= PacketsTo(LSHTEnvironment_Refine(environment), host.me); requires forall p :: p in sent_packets <==> p in (set io | io in ios && io.LIoOpSend? :: io.s); requires Host_Next(host, host', receives, ExtractPacketsFromLSHTPackets(sent_packets)); ensures Host_Next(host, host', PacketsTo(LSHTEnvironment_Refine(environment), host.me), LSHTIoSeq_RefineAsSends(ios)); { assert receives <= PacketsTo(LSHTEnvironment_Refine(environment), host.me); assert ExtractPacketsFromLSHTPackets(sent_packets) == LSHTIoSeq_RefineAsSends(ios); } predicate LScheduler_RefinementInvariant(s:LScheduler) { 0 <= s.nextActionIndex < LHost_NumActions() } function LScheduler_Refine(s:LScheduler) : Host { s.host } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/LiveSHT/Scheduler.i.dfy ================================================ include "../SHT/Host.i.dfy" include "RefinementProof/Environment.i.dfy" include "RefinementProof/EnvironmentRefinement.i.dfy" include "../../Common/Collections/Sets.i.dfy" module LiveSHT__BoundedClock_i { datatype BoundedClock = BoundedClock(min:int, max:int) } module LiveSHT__Scheduler_i { import opened SHT__Host_i import opened LiveSHT__Environment_i import opened LiveSHT__EnvironmentRefinement_i import opened Collections__Sets_i import opened LiveSHT__BoundedClock_i import opened SHT__Network_i import opened Protocol_Parameters_i import opened Concrete_NodeIdentity_i`Spec import opened SHT__Delegations_i import opened Environment_s function {:opaque} ExtractSentPacketsFromIos(ios:seq) : seq ensures forall p :: p in ExtractSentPacketsFromIos(ios) <==> LIoOpSend(p) in ios; { if |ios| == 0 then [] else if ios[0].LIoOpSend? then [ios[0].s] + ExtractSentPacketsFromIos(ios[1..]) else ExtractSentPacketsFromIos(ios[1..]) } predicate ReceivePacket_Wrapper(s:Host, s':Host, pkt:Packet, sent_packets:set) { exists ack :: ReceivePacket(s, s', pkt, sent_packets, ack) } predicate LHost_ReceivePacketWithoutReadingClock(s:Host, s':Host, ios:seq) requires |ios| >= 1; requires ios[0].LIoOpReceive?; requires DelegationMapComplete(s.delegationMap); { var pkt := Packet(ios[0].r.dst, ios[0].r.src, ios[0].r.msg); var sent_packets := ExtractPacketsFromLSHTPackets(ExtractSentPacketsFromIos(ios)); ReceivePacket_Wrapper(s, s', pkt, sent_packets) } predicate LHost_ReceivePacket_Next(s:Host, s':Host, ios:seq) { |ios| >= 1 && if ios[0].LIoOpTimeoutReceive? then s' == s && |ios| == 1 else ( DelegationMapComplete(s.delegationMap) && (ios[0].LIoOpReceive? //&& ios[0].r.msg.SingleMessage? && (forall i{:trigger ios[i].LIoOpSend?} :: 1 <= i < |ios| ==> ios[i].LIoOpSend?) && LHost_ReceivePacketWithoutReadingClock(s, s', ios)) ) } function LHost_NumActions() : int { 3 } datatype LScheduler = LScheduler(host:Host, nextActionIndex:int, resendCount:int) predicate LScheduler_Init(s:LScheduler, me:NodeIdentity, rootIdentity:NodeIdentity, hostIds:seq, params:Parameters) { Host_Init(s.host, me, rootIdentity, hostIds, params) && s.nextActionIndex == 0 && s.resendCount == 0 } predicate LHost_ProcessReceivedPacket_Next(s:Host, s':Host, ios:seq) { DelegationMapComplete(s.delegationMap) && (forall io {:trigger io in ios} :: io in ios ==> io.LIoOpSend?) && ProcessReceivedPacket(s, s', ExtractPacketsFromLSHTPackets(ExtractSentPacketsFromIos(ios))) } predicate LHost_NoReceive_Next(s:Host, s':Host, ios:seq) { DelegationMapComplete(s.delegationMap) && (forall io {:trigger io in ios} :: io in ios ==> io.LIoOpSend?) && SpontaneouslyRetransmit(s, s', ExtractPacketsFromLSHTPackets(ExtractSentPacketsFromIos(ios))) } /* predicate LHost_Next_ReadClock_MaybeReSendUnAckedPackets(s:Host, s':Host, clock:BoundedClock, ios:seq) { if clock.max < s.nextHeartbeatTime then s' == s && sent_packets == [] else s'.nextHeartbeatTime == LCappedAddition(clock.min, s.constants.all.params.heartbeatPeriod, s.constants.all.params) && LBroadcastToEveryone(s.constants.all.config, s.constants.myIndex, LPaxosMessage_Heartbeat(s.proposer.electionState.currentView, s.constants.myIndex in s.proposer.electionState.currentViewSuspectors, s.executor.opsComplete), sent_packets) && s' == s[nextHeartbeatTime := s'.nextHeartbeatTime] }*/ predicate LHost_NoReceive_Next_Wrapper(s:LScheduler, s':LScheduler, ios:seq) { DelegationMapComplete(s.host.delegationMap) && s'.resendCount == (s.resendCount + 1) % 100000000 && if (s'.resendCount == 0) then LHost_NoReceive_Next(s.host, s'.host, ios) else ( ios == [] && s' == s.(resendCount := s'.resendCount, nextActionIndex := s'.nextActionIndex)) } predicate LScheduler_Next(s:LScheduler, s':LScheduler, ios:seq) { s'.nextActionIndex == (s.nextActionIndex + 1) % LHost_NumActions() && s'.host.constants == s.host.constants && s'.host.me == s.host.me && if s.nextActionIndex == 0 then s'.resendCount == s.resendCount && LHost_ReceivePacket_Next(s.host, s'.host, ios) else if s.nextActionIndex == 1 then s'.resendCount == s.resendCount && LHost_ProcessReceivedPacket_Next(s.host, s'.host, ios) else LHost_NoReceive_Next_Wrapper(s, s', ios) } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/Lock/Node.i.dfy ================================================ include "Types.i.dfy" module Protocol_Node_i { import opened Types_i import opened Native__Io_s type Config = seq datatype Node = Node(held:bool, epoch:int, my_index:int, config:Config) predicate NodeInit(s:Node, my_index:int, config:Config) { s.epoch == (if my_index == 0 then 1 else 0) && 0 <= my_index < |config| && s.my_index == my_index // change && s.held == (my_index == 0) && s.config == config } predicate NodeGrant(s:Node, s':Node, ios:seq) { s.my_index == s'.my_index // change && if s.held && s.epoch < 0xFFFF_FFFF_FFFF_FFFF then !s'.held && |ios| == 1 && ios[0].LIoOpSend? && |s.config| > 0 && s'.config == s.config && s'.epoch == s.epoch && var outbound_packet := ios[0].s; outbound_packet.msg.Transfer? && outbound_packet.msg.transfer_epoch == s.epoch + 1 && outbound_packet.dst == s.config[(s.my_index + 1) % |s.config|] else s == s' && ios == [] } predicate NodeAccept(s:Node, s':Node, ios:seq) { s.my_index == s'.my_index // change && |ios| >= 1 && if ios[0].LIoOpTimeoutReceive? then s == s' && |ios| == 1 else ios[0].LIoOpReceive? && if !s.held && ios[0].r.src in s.config && ios[0].r.msg.Transfer? && ios[0].r.msg.transfer_epoch > s.epoch then s'.held && |ios| == 2 && ios[1].LIoOpSend? && ios[1].s.msg.Locked? && s'.epoch == ios[0].r.msg.transfer_epoch == ios[1].s.msg.locked_epoch && s'.config == s.config else s == s' && |ios| == 1 } predicate NodeNext(s:Node, s':Node, ios:seq) { NodeGrant(s, s', ios) || NodeAccept(s, s', ios) } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/Lock/RefinementProof/DistributedSystem.i.dfy ================================================ include "../Node.i.dfy" include "../../../Impl/Common/SeqIsUnique.i.dfy" include "../../../Common/Collections/Seqs.i.dfy" include "../../../Common/Framework/DistributedSystem.s.dfy" include "../../../Impl/Lock/Host.i.dfy" module DistributedSystem_i { import opened Native__Io_s import opened Environment_s import opened Types_i import opened Protocol_Node_i import opened Common__SeqIsUniqueDef_i import opened Common__SeqIsUnique_i import opened Collections__Seqs_i import opened Host_i`Spec ///////////////////////////////////////// // LS_State ///////////////////////////////////////// datatype LS_State = LS_State( environment:LockEnvironment, servers:map ) predicate LS_Init(s:LS_State, config:Config) { LEnvironment_Init(s.environment) && |config| > 0 && SeqIsUnique(config) && (forall e :: e in config <==> e in s.servers) && (forall index :: 0 <= index < |config| ==> NodeInit(s.servers[config[index]], index, config)) } predicate LS_NextOneServer(s:LS_State, s':LS_State, id:EndPoint, ios:seq) requires id in s.servers; { id in s'.servers && NodeNext(s.servers[id], s'.servers[id], ios) && s'.servers == s.servers[id := s'.servers[id]] } predicate NodeAcquiresLock(e:EndPoint, s:LS_State, s':LS_State) { e in s.servers && e in s'.servers && !s.servers[e].held && s'.servers[e].held } predicate LS_Next(s:LS_State, s':LS_State) { LEnvironment_Next(s.environment, s'.environment) && if s.environment.nextStep.LEnvStepHostIos? && s.environment.nextStep.actor in s.servers then LS_NextOneServer(s, s', s.environment.nextStep.actor, s.environment.nextStep.ios) else s'.servers == s.servers } ///////////////////////////////////////////// // GLS_State: an LS_State augmented with // a history field. This history field is // initialized and updated according to // GLS_Init and GLS_Next ///////////////////////////////////////////// datatype GLS_State = GLS_State( ls:LS_State, history:seq ) predicate GLS_Init(s:GLS_State, config:Config) { LS_Init(s.ls, config) && s.history == [config[0]] } ///////////////////////////////////////////////////////// // GLS_Next is defined according to LS_Next. When a node // sends a grant message, the destination of that message // (as computed in NodeGrant), is appended to the history ///////////////////////////////////////////////////////// predicate GLS_Next(s:GLS_State, s':GLS_State) { LS_Next(s.ls, s'.ls) && (if s.ls.environment.nextStep.LEnvStepHostIos? && s.ls.environment.nextStep.actor in s.ls.servers && NodeGrant(s.ls.servers[s.ls.environment.nextStep.actor], s'.ls.servers[s.ls.environment.nextStep.actor], s.ls.environment.nextStep.ios) && s.ls.servers[s.ls.environment.nextStep.actor].held && s.ls.servers[s.ls.environment.nextStep.actor].epoch < 0xFFFF_FFFF_FFFF_FFFF then s'.history == s.history + [s.ls.servers[s.ls.environment.nextStep.actor].config[(s.ls.servers[s.ls.environment.nextStep.actor].my_index + 1) % |s.ls.servers[s.ls.environment.nextStep.actor].config|]] else s'.history == s.history ) } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/Lock/RefinementProof/Refinement.i.dfy ================================================ include "DistributedSystem.i.dfy" include "../../../Services/Lock/AbstractService.s.dfy" include "../../../Common/Collections/Sets.i.dfy" module Refinement_i { import opened DistributedSystem_i import opened AbstractServiceLock_s`All import opened Collections__Maps2_s function AbstractifyGLS_State(gls:GLS_State) : ServiceState { ServiceState'(mapdomain(gls.ls.servers), gls.history) } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/Lock/RefinementProof/RefinementProof.i.dfy ================================================ include "Refinement.i.dfy" include "../../../Common/Collections/Sets.i.dfy" include "../../../Common/Collections/Maps.i.dfy" include "../../../Common/Logic/Option.i.dfy" module RefinementProof_i { import opened Native__Io_s import opened Environment_s import opened Protocol_Node_i import opened DistributedSystem_i import opened Refinement_i import opened Collections__Seqs_s import opened Collections__Maps2_s import opened Collections__Sets_i import opened Collections__Maps_i import opened Logic__Option_i import opened Common__SeqIsUnique_i import opened AbstractServiceLock_s`All lemma lemma_InitRefines(gls:GLS_State, config:Config) requires GLS_Init(gls, config); ensures Service_Init(AbstractifyGLS_State(gls), UniqueSeqToSet(config)); { assert config[0] in config; // OBSERVE: triggers the exists in Service_Init var s := AbstractifyGLS_State(gls); calc { s.hosts; mapdomain(gls.ls.servers); UniqueSeqToSet(config); } assert config[0] in config; // OBSERVE assert config[0] in UniqueSeqToSet(config); } predicate IsValidBehavior(glb:seq, config:Config) { |glb| > 0 && GLS_Init(glb[0], config) && (forall i {:trigger GLS_Next(glb[i], glb[i+1])} :: 0 <= i < |glb| - 1 ==> GLS_Next(glb[i], glb[i+1])) } lemma lemma_LS_Next(glb:seq, config:Config, i:int) requires IsValidBehavior(glb, config); requires 0 <= i < |glb| - 1; ensures GLS_Next(glb[i], glb[i+1]); { } lemma lemma_LSConsistent(glb:seq, config:Config, i:int) requires IsValidBehavior(glb, config); requires 0 <= i < |glb|; ensures |glb[i].ls.servers| == |config|; ensures forall e :: e in config <==> e in glb[i].ls.servers; ensures mapdomain(glb[i].ls.servers) == mapdomain(glb[0].ls.servers); ensures forall id :: id in config ==> glb[0].ls.servers[id].config == glb[i].ls.servers[id].config; { if i == 0 { calc { UniqueSeqToSet(config); mapdomain(glb[0].ls.servers); } lemma_seqs_set_cardinality(config, mapdomain(glb[0].ls.servers)); calc { |mapdomain(glb[0].ls.servers)|; { lemma_MapSizeIsDomainSize(mapdomain(glb[0].ls.servers), glb[0].ls.servers); } |glb[0].ls.servers|; } } else { lemma_LS_Next(glb, config, i - 1); lemma_LSConsistent(glb, config, i - 1); } } lemma lemma_LSNodeConsistent(glb:seq, config:Config, i:int, candidate:EndPoint, e:EndPoint) requires IsValidBehavior(glb, config); requires 0 <= i < |glb|; requires e in glb[i].ls.servers; ensures candidate in glb[i].ls.servers <==> candidate in glb[i].ls.servers[e].config; { if i == 0 { } else { lemma_LS_Next(glb, config, i-1); lemma_LSConsistent(glb, config, i-1); lemma_LSNodeConsistent(glb, config, i-1, candidate, e); } } lemma lemma_HistoryIncrement(glb:seq, config:Config, i:int) requires IsValidBehavior(glb, config); requires 0 <= i < |glb| - 1; ensures |glb[i].history| + 1 == |glb[i].history| || glb[i].history == glb[i].history; { } lemma lemma_HistorySize(glb:seq, config:Config, i:int) requires IsValidBehavior(glb, config); requires 0 <= i < |glb|; ensures 1 <= |glb[i].history| <= i + 1; { if i == 0 { var locked_packets := set p | p in glb[i].ls.environment.sentPackets && p.msg.Locked?; assert |locked_packets| == 0; assert exists host :: host in (glb[i]).ls.servers && (glb[i]).ls.servers[host].held; assert |glb[i].history| == 1; } else { lemma_HistorySize(glb, config, i - 1); lemma_HistoryIncrement(glb, config, i - 1); assert GLS_Next(glb[i-1], glb[i]); } } lemma lemma_HistoryMembership(glb:seq, config:Config, i:int) requires IsValidBehavior(glb, config); requires 0 <= i < |glb|; ensures 1 <= |glb[i].history| <= i + 1; ensures last(glb[i].history) in glb[i].ls.servers; { lemma_HistorySize(glb, config, i); if i == 0 { } else { lemma_LS_Next(glb, config, i - 1); lemma_LSConsistent(glb, config, i - 1); lemma_LSConsistent(glb, config, i); lemma_HistoryMembership(glb, config, i-1); } } lemma lemma_LS_NextAbstract(glb:seq, config:Config, i:int) requires IsValidBehavior(glb, config); requires 0 <= i < |glb| - 1; ensures Service_Next(AbstractifyGLS_State(glb[i]), AbstractifyGLS_State(glb[i+1])) || AbstractifyGLS_State(glb[i]) == AbstractifyGLS_State(glb[i+1]); { lemma_LSConsistent(glb, config, i); lemma_LSConsistent(glb, config, i+1); assert GLS_Next(glb[i], glb[i+1]); if i == 0 { assert glb[i].ls.servers[config[0]].held; } else { lemma_HistorySize(glb, config, i); assert |glb[i].history| > 0; lemma_HistoryMembership(glb, config, i); assert last(glb[i].history) in glb[i].ls.servers; } } /////////////////////////////////////////////////////////////////// /// Everything above here is useful for proving the refinement /// of Init and Next. The lemma below establishes properties /// needed to prove Service_Correspondence. /////////////////////////////////////////////////////////////////// lemma MakeLockHistory(glb:seq, config:Config, i:int) returns (history:seq) requires IsValidBehavior(glb, config); requires 0 <= i < |glb|; ensures |history| > 0; ensures forall p :: p in glb[i].ls.environment.sentPackets && p.msg.Transfer? && p.src in glb[i].ls.servers ==> 2 <= p.msg.transfer_epoch <= |history|; ensures forall p :: p in glb[i].ls.environment.sentPackets && p.msg.Transfer? && p.src in glb[i].ls.servers ==> history[p.msg.transfer_epoch-1] == p.dst; ensures forall h,j :: h in glb[i].ls.servers && 0 <= j < |history|-1 && history[j] == h ==> j+1 <= glb[i].ls.servers[h].epoch; ensures forall h :: h in glb[i].ls.servers && h != last(history) ==> !glb[i].ls.servers[h].held; ensures forall h :: h in glb[i].ls.servers && glb[i].ls.servers[h].held ==> glb[i].ls.servers[h].epoch == |history|; ensures history == glb[i].history; { if i == 0 { history := [config[0]]; } else { var prevHistory := MakeLockHistory(glb, config, i-1); lemma_LS_Next(glb, config, i-1); lemma_LSConsistent(glb, config, i-1); lemma_LSConsistent(glb, config, i); var s := glb[i-1]; var s' := glb[i]; assert LEnvironment_Next(s.ls.environment, s'.ls.environment); if s.ls.environment.nextStep.LEnvStepHostIos? && s.ls.environment.nextStep.actor in s.ls.servers { var id := s.ls.environment.nextStep.actor; var ios := s.ls.environment.nextStep.ios; if NodeGrant(s.ls.servers[id], s'.ls.servers[id], ios) { if s.ls.servers[id].held && s.ls.servers[id].epoch < 0xFFFF_FFFF_FFFF_FFFF { history := prevHistory + [ios[0].s.dst]; } else { history := prevHistory; } } else { history := prevHistory; if !ios[0].LIoOpTimeoutReceive? && !s.ls.servers[id].held && ios[0].r.src in s.ls.servers[id].config && ios[0].r.msg.Transfer? && ios[0].r.msg.transfer_epoch > s.ls.servers[id].epoch { var p := ios[0].r; assert IsValidLIoOp(ios[0], id, s.ls.environment); // trigger assert p.dst == id; } } } else { history := prevHistory; } } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/Lock/Types.i.dfy ================================================ include "../../Common/Framework/Environment.s.dfy" include "../../Common/Native/Io.s.dfy" module Types_i { import opened Environment_s import opened Native__Io_s datatype LockMessage = Transfer(transfer_epoch:int) | Locked(locked_epoch:int) | Invalid type LockEnvironment = LEnvironment type LockPacket = LPacket type LockIo = LIoOp } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/Acceptor.i.dfy ================================================ include "Environment.i.dfy" include "Configuration.i.dfy" include "Constants.i.dfy" include "Broadcast.i.dfy" include "../../Common/Collections/CountMatches.i.dfy" module LiveRSL__Acceptor_i { import opened LiveRSL__Environment_i import opened LiveRSL__Configuration_i import opened LiveRSL__Constants_i import opened LiveRSL__Broadcast_i import opened LiveRSL__Types_i import opened LiveRSL__Message_i import opened Collections__CountMatches_i import opened Environment_s import opened Common__UpperBound_s datatype LAcceptor = LAcceptor( constants:LReplicaConstants, max_bal:Ballot, votes:Votes, last_checkpointed_operation:seq, log_truncation_point:OperationNumber ) predicate IsLogTruncationPointValid(log_truncation_point:OperationNumber, last_checkpointed_operation:seq, config:LConfiguration) { IsNthHighestValueInSequence(log_truncation_point, last_checkpointed_operation, LMinQuorumSize(config)) } predicate RemoveVotesBeforeLogTruncationPoint(votes:Votes, votes':Votes, log_truncation_point:int) { && (forall opn :: opn in votes' ==> opn in votes && votes'[opn] == votes[opn]) && (forall opn :: opn < log_truncation_point ==> opn !in votes') && (forall opn :: opn >= log_truncation_point && opn in votes ==> opn in votes') } predicate LAddVoteAndRemoveOldOnes(votes:Votes, votes':Votes, new_opn:OperationNumber, new_vote:Vote, log_truncation_point:OperationNumber) { && (forall opn :: opn in votes' <==> opn >= log_truncation_point && (opn in votes || opn == new_opn)) && (forall opn :: opn in votes' ==> votes'[opn] == (if opn == new_opn then new_vote else votes[opn])) } predicate LAcceptorInit(a:LAcceptor, c:LReplicaConstants) { && a.constants == c && a.max_bal == Ballot(0,0) && a.votes == map [] && |a.last_checkpointed_operation| == |c.all.config.replica_ids| && (forall idx {:trigger a.last_checkpointed_operation[idx]} :: 0 <= idx < |a.last_checkpointed_operation| ==> a.last_checkpointed_operation[idx] == 0) && a.log_truncation_point == 0 } predicate LAcceptorProcess1a(s:LAcceptor, s':LAcceptor, inp:RslPacket, sent_packets:seq) requires inp.msg.RslMessage_1a? { var m := inp.msg; if inp.src in s.constants.all.config.replica_ids && BalLt(s.max_bal, m.bal_1a) && LReplicaConstantsValid(s.constants) then && sent_packets == [ LPacket(inp.src, s.constants.all.config.replica_ids[s.constants.my_index], RslMessage_1b(m.bal_1a, s.log_truncation_point, s.votes)) ] && s' == s.(max_bal := m.bal_1a) else s' == s && sent_packets == [] } predicate LAcceptorProcess2a(s:LAcceptor, s':LAcceptor, inp:RslPacket, sent_packets:seq) requires inp.msg.RslMessage_2a? requires inp.src in s.constants.all.config.replica_ids requires BalLeq(s.max_bal, inp.msg.bal_2a) requires LeqUpperBound(inp.msg.opn_2a, s.constants.all.params.max_integer_val) { var m := inp.msg; var newLogTruncationPoint := if inp.msg.opn_2a - s.constants.all.params.max_log_length + 1 > s.log_truncation_point then inp.msg.opn_2a - s.constants.all.params.max_log_length + 1 else s.log_truncation_point; && LBroadcastToEveryone(s.constants.all.config, s.constants.my_index, RslMessage_2b(m.bal_2a, m.opn_2a, m.val_2a), sent_packets) && s'.max_bal == m.bal_2a && s'.log_truncation_point == newLogTruncationPoint && (if s.log_truncation_point <= inp.msg.opn_2a then LAddVoteAndRemoveOldOnes(s.votes, s'.votes, m.opn_2a, Vote(m.bal_2a, m.val_2a), newLogTruncationPoint) else s'.votes == s.votes ) // UNCHANGED && s'.constants == s.constants && s'.last_checkpointed_operation == s.last_checkpointed_operation } predicate LAcceptorProcessHeartbeat(s:LAcceptor, s':LAcceptor, inp:RslPacket) requires inp.msg.RslMessage_Heartbeat? { if inp.src in s.constants.all.config.replica_ids then var sender_index := GetReplicaIndex(inp.src, s.constants.all.config); if 0 <= sender_index < |s.last_checkpointed_operation| && inp.msg.opn_ckpt > s.last_checkpointed_operation[sender_index] then //s' == s[last_checkpointed_operation := s.last_checkpointed_operation[inp.src := inp.msg.opn_ckpt]] s'.last_checkpointed_operation == s.last_checkpointed_operation[sender_index := inp.msg.opn_ckpt] // UNCHANGED && s'.constants == s.constants && s'.max_bal == s.max_bal && s'.votes == s.votes && s'.log_truncation_point == s.log_truncation_point else s' == s else s' == s } predicate LAcceptorTruncateLog(s:LAcceptor, s':LAcceptor, opn:OperationNumber) { if opn <= s.log_truncation_point then s' == s else && RemoveVotesBeforeLogTruncationPoint(s.votes, s'.votes, opn) && s' == s.(log_truncation_point := opn, votes := s'.votes) } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/Broadcast.i.dfy ================================================ include "Configuration.i.dfy" include "Environment.i.dfy" module LiveRSL__Broadcast_i { import opened LiveRSL__Configuration_i import opened LiveRSL__Environment_i import opened LiveRSL__Message_i import opened Environment_s predicate LBroadcastToEveryone(c:LConfiguration, myidx:int, m:RslMessage, sent_packets:seq) { && |sent_packets| == |c.replica_ids| && 0 <= myidx < |c.replica_ids| && forall idx {:trigger sent_packets[idx]}{:trigger c.replica_ids[idx]}{:trigger LPacket(c.replica_ids[idx], c.replica_ids[myidx], m)} :: 0 <= idx < |sent_packets| ==> sent_packets[idx] == LPacket(c.replica_ids[idx], c.replica_ids[myidx], m) } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/ClockReading.i.dfy ================================================ module LiveRSL__ClockReading_i { datatype ClockReading = ClockReading(t:int) } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/CommonProof/Actions.i.dfy ================================================ include "../DistributedSystem.i.dfy" include "Assumptions.i.dfy" include "Constants.i.dfy" module CommonProof__Actions_i { import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Constants_i import opened LiveRSL__Message_i import opened LiveRSL__Environment_i import opened LiveRSL__Replica_i import opened CommonProof__Assumptions_i import opened CommonProof__Constants_i import opened Temporal__Temporal_s import opened Environment_s import opened Collections__Maps2_s predicate PacketProcessedViaIos( ps:RslState, ps':RslState, p:RslPacket, idx:int, ios:seq ) { && |ios| > 0 && LIoOpReceive(p) == ios[0] && 0 <= idx < |ps.constants.config.replica_ids| && p.dst == ps.constants.config.replica_ids[idx] && ps.environment.nextStep == LEnvStepHostIos(p.dst, ios) && RslNextOneReplica(ps, ps', idx, ios) && LReplicaNextProcessPacket(ps.replicas[idx].replica, ps'.replicas[idx].replica, ios) } predicate PacketProcessedDuringAction( ps:RslState, p:RslPacket ) { ps.environment.nextStep.LEnvStepHostIos? && LIoOpReceive(p) in ps.environment.nextStep.ios } function{:opaque} PacketProcessedTemporal( b:Behavior, p:RslPacket ):temporal requires imaptotal(b) ensures forall i {:trigger sat(i, PacketProcessedTemporal(b, p))} :: sat(i, PacketProcessedTemporal(b, p)) <==> PacketProcessedDuringAction(b[i], p) { stepmap(imap i :: PacketProcessedDuringAction(b[i], p)) } predicate PacketSentDuringAction( ps:RslState, p:RslPacket ) { ps.environment.nextStep.LEnvStepHostIos? && LIoOpSend(p) in ps.environment.nextStep.ios } function{:opaque} PacketSentTemporal( b:Behavior, p:RslPacket ):temporal requires imaptotal(b) ensures forall i {:trigger sat(i, PacketSentTemporal(b, p))} :: sat(i, PacketSentTemporal(b, p)) <==> PacketSentDuringAction(b[i], p) { stepmap(imap i :: PacketSentDuringAction(b[i], p)) } lemma lemma_ActionThatChangesReplicaIsThatReplicasAction( b:Behavior, c:LConstants, i:int, host_index:int ) returns (ios:seq) requires IsValidBehaviorPrefix(b, c, i+1) requires 0 <= i requires 0 <= host_index < |b[i].replicas| requires 0 <= host_index < |b[i+1].replicas| requires b[i+1].replicas[host_index] != b[i].replicas[host_index] ensures b[i].environment.nextStep.LEnvStepHostIos? ensures 0 <= host_index < |c.config.replica_ids| ensures b[i].environment.nextStep.actor == c.config.replica_ids[host_index] ensures ios == b[i].environment.nextStep.ios ensures RslNext(b[i], b[i+1]) ensures RslNextOneReplica(b[i], b[i+1], host_index, ios) { lemma_AssumptionsMakeValidTransition(b, c, i); lemma_ConstantsAllConsistent(b, c, i); assert RslNext(b[i], b[i+1]); ios :| RslNextOneReplica(b[i], b[i+1], host_index, ios); } lemma lemma_PacketProcessedImpliesPacketSent( ps:RslState, ps':RslState, idx:int, ios:seq, inp:RslPacket ) requires RslNextOneReplica(ps, ps', idx, ios) requires LIoOpReceive(inp) in ios ensures inp in ps.environment.sentPackets { var id := ps.constants.config.replica_ids[idx]; var e := ps.environment; var e' := ps'.environment; assert IsValidLIoOp(LIoOpReceive(inp), id, ps.environment); assert inp in e.sentPackets; } lemma lemma_PacketProcessedImpliesPacketSentAlt( b:Behavior, c:LConstants, i:int, idx:int, inp:RslPacket ) requires IsValidBehaviorPrefix(b, c, i+1) requires 0 <= i requires 0 <= idx < |c.config.replica_ids| requires b[i].environment.nextStep.LEnvStepHostIos? requires b[i].environment.nextStep.actor == c.config.replica_ids[idx] requires LIoOpReceive(inp) in b[i].environment.nextStep.ios ensures inp in b[i].environment.sentPackets { var ps := b[i]; var ps' := b[i+1]; lemma_AssumptionsMakeValidTransition(b, c, i); lemma_ConstantsAllConsistent(b, c, i); var id := ps.constants.config.replica_ids[idx]; var e := ps.environment; var e' := ps'.environment; assert IsValidLIoOp(LIoOpReceive(inp), id, ps.environment); assert inp in e.sentPackets; } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/CommonProof/Assumptions.i.dfy ================================================ include "../DistributedSystem.i.dfy" module CommonProof__Assumptions_i { import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Message_i import opened LiveRSL__Constants_i import opened Temporal__Temporal_s import opened Concrete_NodeIdentity_i import opened Environment_s import opened Collections__Maps2_s function{:opaque} RestrictBehaviorToEnvironment( b:Behavior ):Behavior> requires imaptotal(b) ensures imaptotal(RestrictBehaviorToEnvironment(b)) ensures forall i {:trigger RestrictBehaviorToEnvironment(b)[i]} :: RestrictBehaviorToEnvironment(b)[i] == b[i].environment { imap i :: b[i].environment } predicate IsValidBehaviorPrefix( b:Behavior, c:LConstants, i:int ) { && imaptotal(b) && RslInit(c, b[0]) && (forall j {:trigger RslNext(b[j], b[j+1])} :: 0 <= j < i ==> RslNext(b[j], b[j+1])) } predicate IsValidBehavior( b:Behavior, c:LConstants ) { && imaptotal(b) && RslInit(c, b[0]) && (forall i {:trigger RslNext(b[i], b[i+1])} :: i >= 0 ==> RslNext(b[i], b[i+1])) } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/CommonProof/CanonicalizeBallot.i.dfy ================================================ include "../Types.i.dfy" include "../Configuration.i.dfy" include "../Proposer.i.dfy" include "../../../Common/Collections/Sets.i.dfy" include "../../../../Libraries/Math/mul.i.dfy" include "../../../../Libraries/Math/div.i.dfy" module CommonProof__CanonicalizeBallot_i { import opened LiveRSL__Types_i import opened LiveRSL__Configuration_i import opened LiveRSL__Constants_i import opened LiveRSL__Proposer_i import opened LiveRSL__Election_i import opened Collections__Sets_i import opened Math__mul_i import opened Math__div_nonlinear_i import opened Math__div_i import opened Common__UpperBound_s predicate IsValidBallot(b:Ballot, c:LConstants) { 0 <= b.proposer_id < |c.config.replica_ids| } predicate BallotHasSuccessor(b:Ballot, c:LConstants) { || LtUpperBound(b.seqno, c.params.max_integer_val) || (b.seqno == c.params.max_integer_val.n && 0 <= b.proposer_id + 1 < |c.config.replica_ids|) } ////////////////////////// // CanonicalizeBallot ////////////////////////// function{:opaque} CanonicalizeBallot(b:Ballot, c:LConstants):int { b.seqno * |c.config.replica_ids| + b.proposer_id } lemma lemma_CanonicalizeBallotProperties() ensures forall b1:Ballot, b2:Ballot, c:LConstants :: IsValidBallot(b1, c) && IsValidBallot(b2, c) ==> && (BalLeq(b1, b2) <==> CanonicalizeBallot(b1, c) <= CanonicalizeBallot(b2, c)) && (BalLt(b1, b2) <==> CanonicalizeBallot(b1, c) < CanonicalizeBallot(b2, c)) && (b1 == b2 <==> CanonicalizeBallot(b1, c) == CanonicalizeBallot(b2, c)); { reveal CanonicalizeBallot(); forall b1:Ballot, b2:Ballot, c:LConstants | 0 <= b1.proposer_id < |c.config.replica_ids| && 0 <= b2.proposer_id < |c.config.replica_ids| ensures b1.seqno < b2.seqno ==> CanonicalizeBallot(b1, c) < CanonicalizeBallot(b2, c) { var ids := c.config.replica_ids; if b1.seqno < b2.seqno { calc { CanonicalizeBallot(b1, c); < b1.seqno * |c.config.replica_ids| + 1 * |ids|; == { lemma_mul_is_distributive_add_other_way(|ids|, b1.seqno, 1); } (b1.seqno + 1) * |ids|; <= { lemma_mul_properties(); } b2.seqno * |ids|; <= CanonicalizeBallot(b2, c); } } } forall b1:Ballot, b2:Ballot, c:LConstants | 0 <= b1.proposer_id < |c.config.replica_ids| && 0 <= b2.proposer_id < |c.config.replica_ids| ensures b1 != b2 ==> CanonicalizeBallot(b1, c) != CanonicalizeBallot(b2, c) { } } lemma lemma_CanonicalizeBallotPropertiesSpecific(b1:Ballot, b2:Ballot, c:LConstants) requires IsValidBallot(b1, c) requires IsValidBallot(b2, c) ensures && (BalLeq(b1, b2) <==> CanonicalizeBallot(b1, c) <= CanonicalizeBallot(b2, c)) && (BalLt(b1, b2) <==> CanonicalizeBallot(b1, c) < CanonicalizeBallot(b2, c)) && (b1 == b2 <==> CanonicalizeBallot(b1, c) == CanonicalizeBallot(b2, c)) { lemma_CanonicalizeBallotProperties(); } lemma lemma_CanonicalizeSuccessor(b:Ballot, c:LConstants) requires 0 <= b.proposer_id < |c.config.replica_ids| requires BallotHasSuccessor(b, c) ensures CanonicalizeBallot(ComputeSuccessorView(b, c), c) == CanonicalizeBallot(b, c) + 1 { reveal CanonicalizeBallot(); lemma_CanonicalizeBallotProperties(); var ids := c.config.replica_ids; var params := c.params; if b.proposer_id + 1 >= |c.config.replica_ids| { calc { CanonicalizeBallot(ComputeSuccessorView(b, c), c); CanonicalizeBallot(Ballot(b.seqno + 1, 0), c); (b.seqno + 1) * |ids| + 0; { lemma_mul_is_distributive_add_other_way(|ids|, b.seqno, 1); } b.seqno * |ids| + 1 * |ids|; b.seqno * |ids| + |ids|; b.seqno * |ids| + |ids| - 1 + 1; CanonicalizeBallot(b, c) + 1; } } } lemma lemma_NothingBetweenViewAndSuccessor(b:Ballot, b':Ballot, c:LConstants) requires IsValidBallot(b, c) requires BallotHasSuccessor(b, c) requires IsValidBallot(b', c) ensures !BalLt(b, b') || !BalLt(b', ComputeSuccessorView(b, c)) { lemma_CanonicalizeBallotProperties(); var b'' := ComputeSuccessorView(b, c); if BalLt(b, b') && BalLt(b', b'') { lemma_CanonicalizeSuccessor(b, c); assert CanonicalizeBallot(b, c) < CanonicalizeBallot(b', c) < CanonicalizeBallot(b, c) + 1; assert false; } } function DecanonicalizeBallot(i:int, c:LConstants):Ballot requires WellFormedLConfiguration(c.config) { Ballot(i / |c.config.replica_ids|, i % |c.config.replica_ids|) } lemma lemma_DecanonicalizeBallotProperties(i:int, c:LConstants) requires i >= 0 requires WellFormedLConfiguration(c.config) ensures CanonicalizeBallot(DecanonicalizeBallot(i, c), c) == i { calc { CanonicalizeBallot(DecanonicalizeBallot(i, c), c); CanonicalizeBallot(Ballot(i / |c.config.replica_ids|, i % |c.config.replica_ids|), c); { reveal_CanonicalizeBallot(); } (i / |c.config.replica_ids|) * |c.config.replica_ids| + (i % |c.config.replica_ids|); { lemma_mul_is_commutative(i / |c.config.replica_ids|, |c.config.replica_ids|); } |c.config.replica_ids| * (i / |c.config.replica_ids|) + i % |c.config.replica_ids|; { lemma_fundamental_div_mod(i, |c.config.replica_ids|); } i; } } function ComputePredecessorView(b:Ballot, c:LConstants):Ballot requires CanonicalizeBallot(b, c) > 0 requires WellFormedLConfiguration(c.config) { DecanonicalizeBallot(CanonicalizeBallot(b, c) - 1, c) } lemma lemma_ComputePredecessorViewProperties(b:Ballot, c:LConstants) requires WellFormedLConfiguration(c.config) requires IsValidBallot(b, c) requires CanonicalizeBallot(b, c) > 0 requires LeqUpperBound(b.seqno, c.params.max_integer_val) ensures BallotHasSuccessor(ComputePredecessorView(b, c), c) ensures CanonicalizeBallot(ComputePredecessorView(b, c), c) == CanonicalizeBallot(b, c) - 1 ensures ComputeSuccessorView(ComputePredecessorView(b, c), c) == b { var i := CanonicalizeBallot(b, c); var b' := DecanonicalizeBallot(i-1, c); lemma_DecanonicalizeBallotProperties(i-1, c); lemma_CanonicalizeBallotPropertiesSpecific(ComputePredecessorView(b, c), b, c); lemma_CanonicalizeBallotPropertiesSpecific(b, ComputeSuccessorView(ComputePredecessorView(b, c), c), c); lemma_CanonicalizeSuccessor(b', c); } lemma lemma_ComputeSuccessorViewProducesValidBallot(b:Ballot, c:LConstants) requires WellFormedLConfiguration(c.config) requires IsValidBallot(b, c) ensures IsValidBallot(ComputeSuccessorView(b, c), c) { } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/CommonProof/Chosen.i.dfy ================================================ include "../DistributedSystem.i.dfy" include "Assumptions.i.dfy" include "Constants.i.dfy" include "Actions.i.dfy" include "PacketSending.i.dfy" include "Environment.i.dfy" include "LearnerState.i.dfy" include "Quorum.i.dfy" include "Message1b.i.dfy" module CommonProof__Chosen_i { import opened LiveRSL__Configuration_i import opened LiveRSL__Constants_i import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Environment_i import opened LiveRSL__Executor_i import opened LiveRSL__Message_i import opened LiveRSL__Proposer_i import opened LiveRSL__Types_i import opened CommonProof__Assumptions_i import opened CommonProof__Constants_i import opened CommonProof__Actions_i import opened CommonProof__PacketSending_i import opened CommonProof__Environment_i import opened CommonProof__LearnerState_i import opened CommonProof__Quorum_i import opened CommonProof__Message1b_i import opened CommonProof__Message2a_i import opened CommonProof__Message2b_i import opened Concrete_NodeIdentity_i import opened Temporal__Temporal_s import opened Collections__Sets_i import opened Environment_s datatype QuorumOf2bs = QuorumOf2bs(c:LConstants, indices:set, packets:seq, bal:Ballot, opn:OperationNumber, v:RequestBatch) predicate IsValidQuorumOf2bs( ps:RslState, q:QuorumOf2bs ) { && |q.indices| >= LMinQuorumSize(ps.constants.config) && |q.packets| == |ps.constants.config.replica_ids| && (forall idx :: idx in q.indices ==> && 0 <= idx < |ps.constants.config.replica_ids| && var p := q.packets[idx]; && p.src == ps.constants.config.replica_ids[idx] && p.msg.RslMessage_2b? && p.msg.opn_2b == q.opn && p.msg.val_2b == q.v && p.msg.bal_2b == q.bal && p in ps.environment.sentPackets) } lemma lemma_QuorumOf2bsStaysValid( b:Behavior, c:LConstants, i:int, j:int, q:QuorumOf2bs ) requires IsValidBehaviorPrefix(b, c, j) requires IsValidQuorumOf2bs(b[i], q) requires 0 <= i <= j ensures IsValidQuorumOf2bs(b[j], q) { lemma_ConstantsAllConsistent(b, c, i); lemma_ConstantsAllConsistent(b, c, j); forall idx | idx in q.indices ensures q.packets[idx] in b[j].environment.sentPackets { lemma_PacketStaysInSentPackets(b, c, i, j, q.packets[idx]); } } lemma lemma_ChosenQuorumAnd2aFromLaterBallotMatchValues( b:Behavior, c:LConstants, i:int, quorum_of_2bs:QuorumOf2bs, packet2a:RslPacket ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires IsValidQuorumOf2bs(b[i], quorum_of_2bs) requires packet2a in b[i].environment.sentPackets requires packet2a.src in c.config.replica_ids requires packet2a.msg.RslMessage_2a? requires quorum_of_2bs.opn == packet2a.msg.opn_2a requires BalLt(quorum_of_2bs.bal, packet2a.msg.bal_2a) ensures quorum_of_2bs.v == packet2a.msg.val_2a decreases packet2a.msg.bal_2a.seqno, packet2a.msg.bal_2a.proposer_id { lemma_ConstantsAllConsistent(b, c, i); var opn := quorum_of_2bs.opn; var quorum_of_1bs := lemma_2aMessageHas1bQuorumPermittingIt(b, c, i, packet2a); var quorum_of_1bs_indices := lemma_GetIndicesFromPackets(quorum_of_1bs, c.config); var overlap_idx := lemma_QuorumIndexOverlap(quorum_of_1bs_indices, quorum_of_2bs.indices, |c.config.replica_ids|); var packet1b_overlap :| packet1b_overlap in quorum_of_1bs && packet1b_overlap.src == c.config.replica_ids[overlap_idx]; var packet2b_overlap := quorum_of_2bs.packets[overlap_idx]; if opn !in packet1b_overlap.msg.votes { lemma_1bMessageWithoutOpnImplicationsFor2b(b, c, i, opn, packet1b_overlap, packet2b_overlap); assert false; } var highestballot_in_1b_set :| LValIsHighestNumberedProposalAtBallot(packet2a.msg.val_2a, highestballot_in_1b_set, quorum_of_1bs, opn); assert BalLeq(packet1b_overlap.msg.votes[opn].max_value_bal, highestballot_in_1b_set); var packet1b_highestballot :| && packet1b_highestballot in quorum_of_1bs && opn in packet1b_highestballot.msg.votes && packet1b_highestballot.msg.votes[opn] == Vote(highestballot_in_1b_set, packet2a.msg.val_2a); lemma_Vote1bMessageIsFromEarlierBallot(b, c, i, opn, packet1b_highestballot); lemma_1bMessageWithOpnImplicationsFor2b(b, c, i, opn, packet1b_overlap, packet2b_overlap); var previous_packet2a := lemma_1bMessageWithOpnImplies2aSent(b, c, i, opn, packet1b_highestballot); assert BalLt(previous_packet2a.msg.bal_2a, packet2a.msg.bal_2a); if quorum_of_2bs.bal == previous_packet2a.msg.bal_2a { var packet2a_overlap := lemma_2bMessageHasCorresponding2aMessage(b, c, i, packet2b_overlap); lemma_2aMessagesFromSameBallotAndOperationMatch(b, c, i, packet2a_overlap, previous_packet2a); } else { lemma_2aMessageHasValidBallot(b, c, i, packet2a); // to demonstrate decreases values are >= 0 lemma_ChosenQuorumAnd2aFromLaterBallotMatchValues(b, c, i, quorum_of_2bs, previous_packet2a); } } lemma lemma_ChosenQuorumsMatchValue( b:Behavior, c:LConstants, i:int, q1:QuorumOf2bs, q2:QuorumOf2bs ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires IsValidQuorumOf2bs(b[i], q1) requires IsValidQuorumOf2bs(b[i], q2) requires q1.opn == q2.opn ensures q1.v == q2.v { lemma_ConstantsAllConsistent(b, c, i); var idx1 :| idx1 in q1.indices; var idx2 :| idx2 in q2.indices; var p1_2b := q1.packets[idx1]; var p2_2b := q2.packets[idx2]; var p1_2a := lemma_2bMessageHasCorresponding2aMessage(b, c, i, p1_2b); var p2_2a := lemma_2bMessageHasCorresponding2aMessage(b, c, i, p2_2b); if q1.bal == q2.bal { lemma_2aMessagesFromSameBallotAndOperationMatch(b, c, i, p1_2a, p2_2a); } else if BalLt(q1.bal, q2.bal) { lemma_ChosenQuorumAnd2aFromLaterBallotMatchValues(b, c, i, q1, p2_2a); } else { lemma_ChosenQuorumAnd2aFromLaterBallotMatchValues(b, c, i, q2, p1_2a); } } lemma lemma_DecidedOperationWasChosen( b:Behavior, c:LConstants, i:int, idx:int ) returns ( q:QuorumOf2bs ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires 0 <= idx < |b[i].replicas| requires b[i].replicas[idx].replica.executor.next_op_to_execute.OutstandingOpKnown? ensures IsValidQuorumOf2bs(b[i], q) ensures var s := b[i].replicas[idx].replica.executor; q.bal == s.next_op_to_execute.bal && q.opn == s.ops_complete && q.v == s.next_op_to_execute.v { if i == 0 { return; } lemma_ReplicaConstantsAllConsistent(b, c, i, idx); lemma_ReplicaConstantsAllConsistent(b, c, i-1, idx); lemma_AssumptionsMakeValidTransition(b, c, i-1); var s := b[i-1].replicas[idx].replica; var s' := b[i].replicas[idx].replica; if s'.executor.next_op_to_execute == s.executor.next_op_to_execute { q := lemma_DecidedOperationWasChosen(b, c, i-1, idx); lemma_QuorumOf2bsStaysValid(b, c, i-1, i, q); return; } var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, c, i-1, idx); assert b[i-1].replicas[idx].nextActionIndex == 5; var opn := s.executor.ops_complete; var v := s.learner.unexecuted_learner_state[opn].candidate_learned_value; var bal := s.learner.max_ballot_seen; assert opn in s.learner.unexecuted_learner_state; assert |s.learner.unexecuted_learner_state[opn].received_2b_message_senders| >= LMinQuorumSize(c.config); assert s'.executor.next_op_to_execute == OutstandingOpKnown(v, bal); var senders := s.learner.unexecuted_learner_state[opn].received_2b_message_senders; var indices:set := {}; var packets:seq := []; var sender_idx := 0; var dummy_packet := LPacket(c.config.replica_ids[0], c.config.replica_ids[0], RslMessage_1a(Ballot(0, 0))); while sender_idx < |c.config.replica_ids| invariant 0 <= sender_idx <= |c.config.replica_ids| invariant |packets| == sender_idx invariant forall sidx :: sidx in indices ==> && 0 <= sidx < sender_idx && var p := packets[sidx]; && p.src == b[i].constants.config.replica_ids[sidx] && p.msg.RslMessage_2b? && p.msg.opn_2b == opn && p.msg.val_2b == v && p.msg.bal_2b == bal && p in b[i].environment.sentPackets invariant forall sidx {:trigger c.config.replica_ids[sidx] in senders} :: 0 <= sidx < sender_idx && c.config.replica_ids[sidx] in senders ==> sidx in indices { var sender := c.config.replica_ids[sender_idx]; if sender in senders { var sender_idx_unused, p := lemma_GetSent2bMessageFromLearnerState(b, c, i, idx, opn, sender); assert ReplicasDistinct(c.config.replica_ids, sender_idx, GetReplicaIndex(p.src, c.config)); packets := packets + [p]; indices := indices + {sender_idx}; } else { packets := packets + [dummy_packet]; } sender_idx := sender_idx + 1; } lemma_Received2bMessageSendersAlwaysValidReplicas(b, c, i-1, idx, opn); var alt_indices := lemma_GetIndicesFromNodes(senders, c.config); forall sidx | sidx in alt_indices ensures sidx in indices { assert 0 <= sidx < |c.config.replica_ids|; assert c.config.replica_ids[sidx] in senders; } SubsetCardinality(alt_indices, indices); q := QuorumOf2bs(c, indices, packets, bal, opn, v); } lemma lemma_ExecutedOperationAndAllBeforeItWereChosen( b:Behavior, c:LConstants, i:int, idx:int ) returns ( qs:seq ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires 0 <= idx < |b[i].replicas| ensures |qs| == b[i].replicas[idx].replica.executor.ops_complete ensures forall opn :: 0 <= opn < |qs| ==> && IsValidQuorumOf2bs(b[i], qs[opn]) && qs[opn].opn == opn && BalLeq(qs[opn].bal, b[i].replicas[idx].replica.executor.max_bal_reflected) decreases i { if i == 0 { qs := []; return; } lemma_ReplicaConstantsAllConsistent(b, c, i, idx); lemma_ReplicaConstantsAllConsistent(b, c, i-1, idx); lemma_AssumptionsMakeValidTransition(b, c, i-1); var s := b[i-1].replicas[idx].replica.executor; var s' := b[i].replicas[idx].replica.executor; if s'.ops_complete == s.ops_complete { qs := lemma_ExecutedOperationAndAllBeforeItWereChosen(b, c, i-1, idx); forall opn | 0 <= opn < |qs| ensures IsValidQuorumOf2bs(b[i], qs[opn]) { lemma_QuorumOf2bsStaysValid(b, c, i-1, i, qs[opn]); } if s'.max_bal_reflected != s.max_bal_reflected { var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, c, i-1, idx); assert false; } return; } var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, c, i-1, idx); if b[i-1].replicas[idx].nextActionIndex == 0 { var p := ios[0].r; qs := lemma_TransferredStateBasedOnChosenOperations(b, c, i-1, p); return; } var prev_qs := lemma_ExecutedOperationAndAllBeforeItWereChosen(b, c, i-1, idx); var q := lemma_DecidedOperationWasChosen(b, c, i-1, idx); qs := prev_qs + [q]; } lemma lemma_TransferredStateBasedOnChosenOperations( b:Behavior, c:LConstants, i:int, p:RslPacket ) returns ( qs:seq ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires p in b[i].environment.sentPackets requires p.src in c.config.replica_ids requires p.msg.RslMessage_AppStateSupply? ensures |qs| == p.msg.opn_state_supply ensures forall opn :: 0 <= opn < |qs| ==> && IsValidQuorumOf2bs(b[i], qs[opn]) && qs[opn].opn == opn && BalLeq(qs[opn].bal, p.msg.bal_state_supply) decreases i { if i == 0 { return; } lemma_ConstantsAllConsistent(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i); if p in b[i-1].environment.sentPackets { qs := lemma_TransferredStateBasedOnChosenOperations(b, c, i-1, p); forall opn | 0 <= opn < |qs| ensures IsValidQuorumOf2bs(b[i], qs[opn]) { lemma_QuorumOf2bsStaysValid(b, c, i-1, i, qs[opn]); } return; } lemma_AssumptionsMakeValidTransition(b, c, i-1); var idx, ios := lemma_ActionThatSendsAppStateSupplyIsProcessAppStateRequest(b[i-1], b[i], p); qs := lemma_ExecutedOperationAndAllBeforeItWereChosen(b, c, i-1, idx); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/CommonProof/Constants.i.dfy ================================================ include "../DistributedSystem.i.dfy" include "../../../Common/Logic/Temporal/Rules.i.dfy" include "Assumptions.i.dfy" module CommonProof__Constants_i { import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Constants_i import opened Temporal__Temporal_s import opened Temporal__Rules_i import opened Temporal__Heuristics_i import opened CommonProof__Assumptions_i /////////////////////////////// // INVARIANTS /////////////////////////////// predicate ConstantsAllConsistentInv(ps:RslState) { && |ps.constants.config.replica_ids| == |ps.replicas| && forall idx :: 0 <= idx < |ps.constants.config.replica_ids| ==> var s := ps.replicas[idx].replica; && s.constants.my_index == idx && s.constants.all == ps.constants && s.proposer.constants == s.constants && s.proposer.election_state.constants == s.constants && s.acceptor.constants == s.constants && s.learner.constants == s.constants && s.executor.constants == s.constants } /////////////////////////////// // INVARIANT LEMMAS /////////////////////////////// lemma lemma_AssumptionsMakeValidTransition( b:Behavior, c:LConstants, i:int ) requires IsValidBehaviorPrefix(b, c, i+1) requires 0 <= i ensures RslNext(b[i], b[i+1]) { } lemma lemma_ReplicasSize( b:Behavior, c:LConstants, i:int ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i ensures |c.config.replica_ids| == |b[i].replicas| { if i > 0 { lemma_ConstantsAllConsistent(b, c, i); lemma_AssumptionsMakeValidTransition(b, c, i-1); lemma_ReplicasSize(b, c, i-1); } } lemma lemma_ReplicaInState( b:Behavior, c:LConstants, replica_index:int, i:int ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires 0 <= replica_index < |c.config.replica_ids| ensures 0 <= replica_index < |b[i].replicas| { lemma_ReplicasSize(b, c, i); } lemma lemma_ConstantsAllConsistent( b:Behavior, c:LConstants, i:int ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i ensures b[i].constants == c ensures ConstantsAllConsistentInv(b[i]) { TemporalAssist(); if i > 0 { lemma_ConstantsAllConsistent(b, c, i-1); lemma_AssumptionsMakeValidTransition(b, c, i-1); } } lemma lemma_ReplicaConstantsAllConsistent( b:Behavior, c:LConstants, i:int, idx:int ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires 0 <= idx < |b[i].replicas| || 0 <= idx < |c.config.replica_ids| || 0 <= idx < |b[i].constants.config.replica_ids| ensures b[i].constants == c ensures |b[i].constants.config.replica_ids| == |b[i].replicas| ensures var s := b[i].replicas[idx].replica; && s.constants.my_index == idx && s.constants.all == b[i].constants && s.proposer.constants == s.constants && s.proposer.election_state.constants == s.constants && s.acceptor.constants == s.constants && s.learner.constants == s.constants && s.executor.constants == s.constants { lemma_ConstantsAllConsistent(b, c, i); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/CommonProof/Environment.i.dfy ================================================ include "../DistributedSystem.i.dfy" include "../../../Common/Logic/Temporal/Heuristics.i.dfy" include "Assumptions.i.dfy" include "Constants.i.dfy" module CommonProof__Environment_i { import opened LiveRSL__Constants_i import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Environment_i import opened Temporal__Temporal_s import opened Temporal__Heuristics_i import opened Temporal__Rules_i import opened CommonProof__Assumptions_i import opened CommonProof__Constants_i import opened Environment_s lemma lemma_PacketStaysInSentPackets( b:Behavior, c:LConstants, i:int, j:int, p:RslPacket ) requires IsValidBehaviorPrefix(b, c, j) requires 0 <= i <= j requires p in b[i].environment.sentPackets ensures p in b[j].environment.sentPackets { if j == i { } else { lemma_PacketStaysInSentPackets(b, c, i, j-1, p); lemma_AssumptionsMakeValidTransition(b, c, j-1); } } lemma lemma_PacketSetStaysInSentPackets( b:Behavior, c:LConstants, i:int, j:int, packets:set ) requires IsValidBehaviorPrefix(b, c, j) requires 0 <= i <= j requires packets <= b[i].environment.sentPackets ensures packets <= b[j].environment.sentPackets { forall p | p in packets ensures p in b[j].environment.sentPackets { lemma_PacketStaysInSentPackets(b, c, i, j, p); } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/CommonProof/LearnerState.i.dfy ================================================ include "../DistributedSystem.i.dfy" include "Assumptions.i.dfy" include "Constants.i.dfy" include "Actions.i.dfy" include "PacketSending.i.dfy" include "Environment.i.dfy" include "Message2b.i.dfy" include "Message2a.i.dfy" module CommonProof__LearnerState_i { import opened LiveRSL__Configuration_i import opened LiveRSL__Constants_i import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Environment_i import opened LiveRSL__Types_i import opened CommonProof__Assumptions_i import opened CommonProof__Constants_i import opened CommonProof__Actions_i import opened CommonProof__PacketSending_i import opened CommonProof__Environment_i import opened CommonProof__Message2b_i import opened CommonProof__Message2a_i import opened Temporal__Temporal_s import opened Concrete_NodeIdentity_i lemma lemma_Received2bMessageSendersAlwaysValidReplicas( b:Behavior, c:LConstants, i:int, learner_idx:int, opn:OperationNumber ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires 0 <= learner_idx < |b[i].replicas| requires opn in b[i].replicas[learner_idx].replica.learner.unexecuted_learner_state ensures forall sender :: sender in b[i].replicas[learner_idx].replica.learner.unexecuted_learner_state[opn].received_2b_message_senders ==> sender in c.config.replica_ids decreases i { if i == 0 { return; } lemma_AssumptionsMakeValidTransition(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i); var s := b[i-1].replicas[learner_idx].replica.learner; var s' := b[i].replicas[learner_idx].replica.learner; forall sender | sender in s'.unexecuted_learner_state[opn].received_2b_message_senders ensures sender in c.config.replica_ids { if opn in s.unexecuted_learner_state && sender in s.unexecuted_learner_state[opn].received_2b_message_senders { lemma_Received2bMessageSendersAlwaysValidReplicas(b, c, i-1, learner_idx, opn); } else { var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, c, i-1, learner_idx); } } } lemma lemma_Received2bMessageSendersAlwaysNonempty( b:Behavior, c:LConstants, i:int, learner_idx:int, opn:OperationNumber ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires 0 <= learner_idx < |b[i].replicas| requires opn in b[i].replicas[learner_idx].replica.learner.unexecuted_learner_state ensures |b[i].replicas[learner_idx].replica.learner.unexecuted_learner_state[opn].received_2b_message_senders| > 0 decreases i { if i == 0 { return; } lemma_AssumptionsMakeValidTransition(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i); var s := b[i-1].replicas[learner_idx].replica.learner; var s' := b[i].replicas[learner_idx].replica.learner; if s'.unexecuted_learner_state == s.unexecuted_learner_state { lemma_Received2bMessageSendersAlwaysNonempty(b, c, i-1, learner_idx, opn); return; } var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, c, i-1, learner_idx); if opn in s.unexecuted_learner_state { lemma_Received2bMessageSendersAlwaysNonempty(b, c, i-1, learner_idx, opn); } } lemma lemma_GetSent2bMessageFromLearnerState( b:Behavior, c:LConstants, i:int, learner_idx:int, opn:OperationNumber, sender:NodeIdentity ) returns ( sender_idx:int, p:RslPacket ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires 0 <= learner_idx < |b[i].replicas| requires opn in b[i].replicas[learner_idx].replica.learner.unexecuted_learner_state requires sender in b[i].replicas[learner_idx].replica.learner.unexecuted_learner_state[opn].received_2b_message_senders ensures 0 <= sender_idx < |c.config.replica_ids| ensures p in b[i].environment.sentPackets ensures p.src == sender == c.config.replica_ids[sender_idx] ensures p.msg.RslMessage_2b? ensures p.msg.opn_2b == opn ensures p.msg.bal_2b == b[i].replicas[learner_idx].replica.learner.max_ballot_seen ensures p.msg.val_2b == b[i].replicas[learner_idx].replica.learner.unexecuted_learner_state[opn].candidate_learned_value decreases i { if i == 0 { return; } lemma_ReplicaConstantsAllConsistent(b, c, i, learner_idx); lemma_ReplicaConstantsAllConsistent(b, c, i-1, learner_idx); lemma_AssumptionsMakeValidTransition(b, c, i-1); var s := b[i-1].replicas[learner_idx].replica.learner; var s' := b[i].replicas[learner_idx].replica.learner; if s'.max_ballot_seen == s.max_ballot_seen && s'.unexecuted_learner_state == s.unexecuted_learner_state { sender_idx, p := lemma_GetSent2bMessageFromLearnerState(b, c, i-1, learner_idx, opn, sender); lemma_PacketStaysInSentPackets(b, c, i-1, i, p); return; } if && opn in s.unexecuted_learner_state && sender in s.unexecuted_learner_state[opn].received_2b_message_senders && s'.unexecuted_learner_state[opn].candidate_learned_value == s.unexecuted_learner_state[opn].candidate_learned_value && s'.max_ballot_seen == s.max_ballot_seen { sender_idx, p := lemma_GetSent2bMessageFromLearnerState(b, c, i-1, learner_idx, opn, sender); lemma_PacketStaysInSentPackets(b, c, i-1, i, p); return; } var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, c, i-1, learner_idx); assert ios[0].LIoOpReceive?; p := ios[0].r; sender_idx := GetReplicaIndex(p.src, c.config); if p.msg.val_2b != s'.unexecuted_learner_state[opn].candidate_learned_value { assert p.msg.bal_2b == s.max_ballot_seen; assert opn in s.unexecuted_learner_state; lemma_Received2bMessageSendersAlwaysNonempty(b, c, i-1, learner_idx, opn); var sender2 :| sender2 in s.unexecuted_learner_state[opn].received_2b_message_senders; var sender2_idx, p2 := lemma_GetSent2bMessageFromLearnerState(b, c, i-1, learner_idx, opn, sender2); var p_2a := lemma_2bMessageHasCorresponding2aMessage(b, c, i, p); var p2_2a := lemma_2bMessageHasCorresponding2aMessage(b, c, i, p2); lemma_2aMessagesFromSameBallotAndOperationMatch(b, c, i, p_2a, p2_2a); } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/CommonProof/LogTruncationPoint.i.dfy ================================================ include "Assumptions.i.dfy" include "Actions.i.dfy" include "PacketSending.i.dfy" include "MaxBallotISent1a.i.dfy" include "Quorum.i.dfy" module CommonProof__LogTruncationPoint_i { import opened LiveRSL__Configuration_i import opened LiveRSL__Constants_i import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Types_i import opened LiveRSL__Environment_i import opened CommonProof__Assumptions_i import opened CommonProof__Actions_i import opened CommonProof__Constants_i import opened CommonProof__PacketSending_i import opened CommonProof__MaxBallotISent1a_i import opened CommonProof__Quorum_i import opened Temporal__Temporal_s import opened Collections__CountMatches_i import opened Collections__Sets_i predicate QuorumIsWitnessForLogTruncationPoint( ps:RslState, q:set, log_truncation_point:int ) { && |q| >= LMinQuorumSize(ps.constants.config) && forall idx :: idx in q ==> 0 <= idx < |ps.replicas| && ps.replicas[idx].replica.executor.ops_complete >= log_truncation_point } predicate LogTruncationPointInfoValid( ps:RslState, log_truncation_point:int ) { exists q:set :: QuorumIsWitnessForLogTruncationPoint(ps, q, log_truncation_point) } predicate LogTruncationPointInfoInPacketValid( ps:RslState, p:RslPacket ) { && (p.msg.RslMessage_1b? ==> LogTruncationPointInfoValid(ps, p.msg.log_truncation_point)) && (p.msg.RslMessage_2a? ==> LogTruncationPointInfoValid(ps, p.msg.opn_2a - ps.constants.params.max_log_length + 1)) } predicate LogTruncationPointInvariant( ps:RslState ) { && (forall idx {:trigger LogTruncationPointInfoValid(ps, ps.replicas[idx].replica.acceptor.log_truncation_point)} :: 0 <= idx < |ps.replicas| ==> LogTruncationPointInfoValid(ps, ps.replicas[idx].replica.acceptor.log_truncation_point)) && (forall p {:trigger LogTruncationPointInfoInPacketValid(ps, p)} :: p in ps.environment.sentPackets && p.src in ps.constants.config.replica_ids ==> LogTruncationPointInfoInPacketValid(ps, p)) } lemma lemma_OpsCompleteMonotonicOneStep( b:Behavior, c:LConstants, i:int, idx:int ) requires IsValidBehaviorPrefix(b, c, i+1) requires 0 <= i requires 0 <= idx < |b[i].replicas| ensures 0 <= idx < |b[i+1].replicas| ensures b[i].replicas[idx].replica.executor.ops_complete <= b[i+1].replicas[idx].replica.executor.ops_complete { lemma_ConstantsAllConsistent(b, c, i); lemma_ConstantsAllConsistent(b, c, i+1); if b[i].replicas[idx].replica.executor.ops_complete > b[i+1].replicas[idx].replica.executor.ops_complete { lemma_ConstantsAllConsistent(b, c, i); lemma_ConstantsAllConsistent(b, c, i+1); var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, c, i, idx); assert false; } } lemma lemma_OpsCompleteMonotonic( b:Behavior, c:LConstants, i:int, j:int, idx:int ) requires IsValidBehaviorPrefix(b, c, j) requires 0 <= i <= j requires 0 <= idx < |b[i].replicas| ensures 0 <= idx < |b[j].replicas| ensures b[i].replicas[idx].replica.executor.ops_complete <= b[j].replicas[idx].replica.executor.ops_complete decreases j-i { if j == i { } else if j == i + 1 { lemma_OpsCompleteMonotonicOneStep(b, c, i, idx); } else { lemma_OpsCompleteMonotonic(b, c, i, j-1, idx); lemma_OpsCompleteMonotonicOneStep(b, c, j-1, idx); } } lemma lemma_LogTruncationPointMonotonicOneStep( b:Behavior, c:LConstants, i:int, idx:int ) requires IsValidBehaviorPrefix(b, c, i+1) requires 0 <= i requires 0 <= idx < |b[i].replicas| ensures 0 <= idx < |b[i+1].replicas| ensures b[i].replicas[idx].replica.acceptor.log_truncation_point <= b[i+1].replicas[idx].replica.acceptor.log_truncation_point { lemma_ConstantsAllConsistent(b, c, i); lemma_ConstantsAllConsistent(b, c, i+1); if b[i].replicas[idx].replica.acceptor.log_truncation_point > b[i+1].replicas[idx].replica.acceptor.log_truncation_point { lemma_ConstantsAllConsistent(b, c, i); lemma_ConstantsAllConsistent(b, c, i+1); var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, c, i, idx); assert false; } } lemma lemma_LogTruncationPointMonotonic( b:Behavior, c:LConstants, i:int, j:int, idx:int ) requires IsValidBehaviorPrefix(b, c, j) requires 0 <= i <= j requires 0 <= idx < |b[i].replicas| ensures 0 <= idx < |b[j].replicas| ensures b[i].replicas[idx].replica.acceptor.log_truncation_point <= b[j].replicas[idx].replica.acceptor.log_truncation_point decreases j-i { if j == i { } else if j == i + 1 { lemma_LogTruncationPointMonotonicOneStep(b, c, i, idx); } else { lemma_LogTruncationPointMonotonic(b, c, i, j-1, idx); lemma_LogTruncationPointMonotonicOneStep(b, c, j-1, idx); } } lemma lemma_HeartbeatMessagesReflectOpsComplete( b:Behavior, c:LConstants, i:int, p:RslPacket ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires p in b[i].environment.sentPackets requires p.msg.RslMessage_Heartbeat? requires p.src in c.config.replica_ids ensures var sender_index := GetReplicaIndex(p.src, c.config); && 0 <= sender_index < |b[i].replicas| && p.msg.opn_ckpt <= b[i].replicas[sender_index].replica.executor.ops_complete { if i == 0 { assert false; } lemma_ConstantsAllConsistent(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i); var sender_index := GetReplicaIndex(p.src, c.config); if p in b[i-1].environment.sentPackets { lemma_HeartbeatMessagesReflectOpsComplete(b, c, i-1, p); lemma_OpsCompleteMonotonicOneStep(b, c, i-1, sender_index); } else { lemma_AssumptionsMakeValidTransition(b, c, i-1); var idx, ios := lemma_ActionThatSendsHeartbeatIsMaybeSendHeartbeat(b[i-1], b[i], p); assert ReplicasDistinct(c.config.replica_ids, idx, sender_index); } } lemma lemma_LastCheckpointedOperationSize( b:Behavior, c:LConstants, i:int, idx:int ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires 0 <= idx < |b[i].replicas| ensures |b[i].replicas[idx].replica.acceptor.last_checkpointed_operation| == |b[i].replicas| decreases i { if i > 0 { lemma_ConstantsAllConsistent(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i); lemma_LastCheckpointedOperationSize(b, c, i-1, idx); if |b[i].replicas[idx].replica.acceptor.last_checkpointed_operation| != |b[i].replicas| { var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, c, i-1, idx); assert false; } } } lemma lemma_LastCheckpointedOperationReflectsOpsComplete( b:Behavior, c:LConstants, i:int, acceptor_idx:int, executor_idx:int ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires 0 <= acceptor_idx < |b[i].replicas| requires 0 <= executor_idx < |b[i].replicas| ensures 0 <= executor_idx < |b[i].replicas[acceptor_idx].replica.acceptor.last_checkpointed_operation| ensures b[i].replicas[acceptor_idx].replica.acceptor.last_checkpointed_operation[executor_idx] <= b[i].replicas[executor_idx].replica.executor.ops_complete { lemma_LastCheckpointedOperationSize(b, c, i, acceptor_idx); if i > 0 { lemma_ConstantsAllConsistent(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i); lemma_LastCheckpointedOperationReflectsOpsComplete(b, c, i-1, acceptor_idx, executor_idx); lemma_OpsCompleteMonotonicOneStep(b, c, i-1, executor_idx); if b[i].replicas[acceptor_idx].replica.acceptor.last_checkpointed_operation[executor_idx] > b[i].replicas[executor_idx].replica.executor.ops_complete { var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, c, i-1, acceptor_idx); lemma_PacketProcessedImpliesPacketSent(b[i-1], b[i], acceptor_idx, ios, ios[0].r); lemma_HeartbeatMessagesReflectOpsComplete(b, c, i-1, ios[0].r); assert false; } } } lemma lemma_LogTruncationPointInfoValidImpliesValidNext( b:Behavior, c:LConstants, i:int, log_truncation_point:int ) requires IsValidBehaviorPrefix(b, c, i+1) requires 0 <= i requires LogTruncationPointInfoValid(b[i], log_truncation_point) ensures LogTruncationPointInfoValid(b[i+1], log_truncation_point) { var q :| QuorumIsWitnessForLogTruncationPoint(b[i], q, log_truncation_point); lemma_ConstantsAllConsistent(b, c, i); lemma_ConstantsAllConsistent(b, c, i+1); forall idx | idx in q ensures 0 <= idx < |b[i+1].replicas| ensures b[i+1].replicas[idx].replica.executor.ops_complete >= log_truncation_point { assert 0 <= idx < |b[i].replicas| && b[i].replicas[idx].replica.executor.ops_complete >= log_truncation_point; lemma_OpsCompleteMonotonicOneStep(b, c, i, idx); } assert QuorumIsWitnessForLogTruncationPoint(b[i+1], q, log_truncation_point); } lemma lemma_LogTruncationPointInfoValidImpliesSmallerOneValid( b:Behavior, c:LConstants, i:int, logTruncationPoint1:int, logTruncationPoint2:int ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires LogTruncationPointInfoValid(b[i], logTruncationPoint1) requires logTruncationPoint2 <= logTruncationPoint1 ensures LogTruncationPointInfoValid(b[i], logTruncationPoint2) { var q :| QuorumIsWitnessForLogTruncationPoint(b[i], q, logTruncationPoint1); lemma_ConstantsAllConsistent(b, c, i); forall idx | idx in q ensures b[i].replicas[idx].replica.executor.ops_complete >= logTruncationPoint2 { assert 0 <= idx < |b[i].replicas| && b[i].replicas[idx].replica.executor.ops_complete >= logTruncationPoint1; } assert QuorumIsWitnessForLogTruncationPoint(b[i], q, logTruncationPoint2); } lemma lemma_LogTruncationPointStateInvariantMaintainedByStep( b:Behavior, c:LConstants, i:int, idx:int ) requires IsValidBehaviorPrefix(b, c, i+1) requires 0 <= i requires LogTruncationPointInvariant(b[i]) requires 0 <= idx < |b[i+1].replicas| ensures LogTruncationPointInfoValid(b[i+1], b[i+1].replicas[idx].replica.acceptor.log_truncation_point) { lemma_ConstantsAllConsistent(b, c, i); lemma_ConstantsAllConsistent(b, c, i+1); var s := b[i].replicas[idx].replica; var s' := b[i+1].replicas[idx].replica; if s'.acceptor.log_truncation_point == s.acceptor.log_truncation_point { lemma_LogTruncationPointInfoValidImpliesValidNext(b, c, i, s.acceptor.log_truncation_point); } else { var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, c, i, idx); var nextActionIndex := b[i].replicas[idx].nextActionIndex; if nextActionIndex == 0 { var p := ios[0].r; lemma_PacketProcessedImpliesPacketSent(b[i], b[i+1], idx, ios, p); assert LogTruncationPointInfoInPacketValid(b[i], p); if p.msg.RslMessage_1b? { assert LogTruncationPointInfoValid(b[i], p.msg.log_truncation_point); assert s'.acceptor.log_truncation_point == p.msg.log_truncation_point; lemma_LogTruncationPointInfoValidImpliesValidNext(b, c, i, s'.acceptor.log_truncation_point); } else if p.msg.RslMessage_2a? { assert LogTruncationPointInfoValid(b[i], p.msg.opn_2a - b[i].constants.params.max_log_length + 1); assert s'.acceptor.log_truncation_point == p.msg.opn_2a - b[i].constants.params.max_log_length + 1; lemma_LogTruncationPointInfoValidImpliesValidNext(b, c, i, s'.acceptor.log_truncation_point); } else { assert false; } } else if nextActionIndex == 4 { var log_truncation_point := s'.acceptor.log_truncation_point; assert IsNthHighestValueInSequence(log_truncation_point, s.acceptor.last_checkpointed_operation, LMinQuorumSize(s.constants.all.config)); assert CountMatchesInSeq(s.acceptor.last_checkpointed_operation, x => x >= log_truncation_point) >= LMinQuorumSize(s.constants.all.config); var q := SetOfIndicesOfMatchesInSeq(s.acceptor.last_checkpointed_operation, x => x >= log_truncation_point); assert |q| == CountMatchesInSeq(s.acceptor.last_checkpointed_operation, x => x >= log_truncation_point); assert |q| >= LMinQuorumSize(s.constants.all.config); forall executor_idx | executor_idx in q ensures 0 <= executor_idx < |b[i+1].replicas| ensures b[i+1].replicas[executor_idx].replica.executor.ops_complete >= log_truncation_point { assert s.acceptor.last_checkpointed_operation[executor_idx] >= log_truncation_point; lemma_LastCheckpointedOperationSize(b, c, i+1, idx); lemma_LastCheckpointedOperationReflectsOpsComplete(b, c, i+1, idx, executor_idx); } assert QuorumIsWitnessForLogTruncationPoint(b[i+1], q, log_truncation_point); } else { assert false; } } } lemma lemma_LogTruncationPointInvariantHolds( b:Behavior, c:LConstants, i:int ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i ensures LogTruncationPointInvariant(b[i]) { if i == 0 { var q := SetOfNumbersInRightExclusiveRange(0, |b[i].constants.config.replica_ids|); calc { |q|; |b[i].constants.config.replica_ids|; >= |b[i].constants.config.replica_ids| / 2 + 1; LMinQuorumSize(b[i].constants.config); } assert QuorumIsWitnessForLogTruncationPoint(b[i], q, 0); assert LogTruncationPointInfoValid(b[i], 0); assert LogTruncationPointInvariant(b[i]); } else { lemma_LogTruncationPointInvariantHolds(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i); forall idx | 0 <= idx < |b[i].replicas| ensures LogTruncationPointInfoValid(b[i], b[i].replicas[idx].replica.acceptor.log_truncation_point) { lemma_LogTruncationPointStateInvariantMaintainedByStep(b, c, i-1, idx); } forall p | p in b[i].environment.sentPackets && p.src in b[i].constants.config.replica_ids ensures LogTruncationPointInfoInPacketValid(b[i], p) { if p in b[i-1].environment.sentPackets { assert p.src in b[i-1].constants.config.replica_ids; assert LogTruncationPointInfoInPacketValid(b[i-1], p); if p.msg.RslMessage_1b? { lemma_LogTruncationPointInfoValidImpliesValidNext(b, c, i-1, p.msg.log_truncation_point); } else if p.msg.RslMessage_2a? { lemma_LogTruncationPointInfoValidImpliesValidNext(b, c, i-1, p.msg.opn_2a - b[i].constants.params.max_log_length + 1); } } else { lemma_AssumptionsMakeValidTransition(b, c, i-1); if p.msg.RslMessage_1b? { var idx, ios := lemma_ActionThatSends1bIsProcess1a(b[i-1], b[i], p); assert p.msg.log_truncation_point == b[i-1].replicas[idx].replica.acceptor.log_truncation_point; lemma_LogTruncationPointInfoValidImpliesValidNext(b, c, i-1, p.msg.log_truncation_point); } else if p.msg.RslMessage_2a? { var idx, ios := lemma_ActionThatSends2aIsMaybeNominateValueAndSend2a(b[i-1], b[i], p); var s := b[i-1].replicas[idx].replica; lemma_LogTruncationPointInfoValidImpliesValidNext(b, c, i-1, s.acceptor.log_truncation_point); lemma_LogTruncationPointInfoValidImpliesSmallerOneValid(b, c, i, s.acceptor.log_truncation_point, p.msg.opn_2a - s.proposer.constants.all.params.max_log_length + 1); } } } } } lemma lemma_AlwaysSomeReplicaInQuorumBeyondLogTruncationPoint( b:Behavior, c:LConstants, i:int, acceptor_idx:int, quorum:set ) returns ( king_idx:int ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires 0 <= acceptor_idx < |b[i].replicas| requires forall replica_index :: replica_index in quorum ==> 0 <= replica_index < |c.config.replica_ids| requires |quorum| >= LMinQuorumSize(c.config) ensures king_idx in quorum ensures 0 <= king_idx < |b[i].replicas| ensures b[i].replicas[king_idx].replica.executor.ops_complete >= b[i].replicas[acceptor_idx].replica.acceptor.log_truncation_point { lemma_LogTruncationPointInvariantHolds(b, c, i); var log_truncation_point := b[i].replicas[acceptor_idx].replica.acceptor.log_truncation_point; assert LogTruncationPointInfoValid(b[i], log_truncation_point); var q :| QuorumIsWitnessForLogTruncationPoint(b[i], q, log_truncation_point); lemma_ConstantsAllConsistent(b, c, i); king_idx := lemma_QuorumIndexOverlap(q, quorum, |c.config.replica_ids|); } lemma lemma_ProposerLogTruncationPointAlwaysBeyondThatOfAllReceived1bs( b:Behavior, c:LConstants, i:int, idx:int ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires 0 <= idx < |b[i].replicas| ensures var s := b[i].replicas[idx].replica; forall p{:trigger p in s.proposer.received_1b_packets} :: p in s.proposer.received_1b_packets && p.msg.RslMessage_1b? ==> s.acceptor.log_truncation_point >= p.msg.log_truncation_point decreases i { if i > 0 { lemma_ConstantsAllConsistent(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i); var s := b[i-1].replicas[idx].replica; var s' := b[i].replicas[idx].replica; forall p | p in s'.proposer.received_1b_packets && p.msg.RslMessage_1b? ensures s'.acceptor.log_truncation_point >= p.msg.log_truncation_point { if p in s.proposer.received_1b_packets { lemma_ProposerLogTruncationPointAlwaysBeyondThatOfAllReceived1bs(b, c, i-1, idx); assert s.acceptor.log_truncation_point >= p.msg.log_truncation_point; lemma_LogTruncationPointMonotonicOneStep(b, c, i-1, idx); } else { var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, c, i-1, idx); assert s'.acceptor.log_truncation_point >= p.msg.log_truncation_point; } } } } lemma lemma_VoteAlwaysWithinLogTruncationPointRange( b:Behavior, c:LConstants, i:int, replica_idx:int, opn:OperationNumber ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires 0 <= replica_idx < |b[i].replicas| requires opn in b[i].replicas[replica_idx].replica.acceptor.votes ensures var log_truncation_point := b[i].replicas[replica_idx].replica.acceptor.log_truncation_point; log_truncation_point <= opn < log_truncation_point + c.params.max_log_length { if i == 0 { return; } lemma_ConstantsAllConsistent(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i); var s := b[i-1].replicas[replica_idx].replica; var s' := b[i].replicas[replica_idx].replica; var log_truncation_point := s.acceptor.log_truncation_point; var log_truncation_point' := s'.acceptor.log_truncation_point; if log_truncation_point' <= opn < log_truncation_point' + c.params.max_log_length { return; } if opn in s.acceptor.votes { lemma_VoteAlwaysWithinLogTruncationPointRange(b, c, i-1, replica_idx, opn); if log_truncation_point == log_truncation_point' { assert false; } else { var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, c, i-1, replica_idx); assert false; } } else { var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, c, i-1, replica_idx); assert false; } } lemma lemma_VoteIn1bMessageAlwaysWithinLogTruncationPointRange( b:Behavior, c:LConstants, i:int, opn:OperationNumber, p:RslPacket ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires p in b[i].environment.sentPackets requires p.msg.RslMessage_1b? requires p.src in c.config.replica_ids requires opn in p.msg.votes ensures var log_truncation_point := p.msg.log_truncation_point; log_truncation_point <= opn < log_truncation_point + c.params.max_log_length { if i == 0 { return; } if p in b[i-1].environment.sentPackets { lemma_VoteIn1bMessageAlwaysWithinLogTruncationPointRange(b, c, i-1, opn, p); return; } lemma_AssumptionsMakeValidTransition(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i); var idx, ios := lemma_ActionThatSends1bIsProcess1a(b[i-1], b[i], p); var log_truncation_point := p.msg.log_truncation_point; lemma_VoteAlwaysWithinLogTruncationPointRange(b, c, i-1, idx, opn); assert log_truncation_point <= opn < log_truncation_point + c.params.max_log_length; } lemma lemma_VoteInReceived1bMessageAlwaysWithinLogTruncationPointRange( b:Behavior, c:LConstants, i:int, idx:int, opn:OperationNumber, p:RslPacket ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires 0 <= idx < |b[i].replicas| requires p in b[i].replicas[idx].replica.proposer.received_1b_packets requires p.msg.RslMessage_1b? requires opn in p.msg.votes ensures var log_truncation_point := b[i].replicas[idx].replica.acceptor.log_truncation_point; opn < log_truncation_point + c.params.max_log_length { if i == 0 { return; } lemma_AssumptionsMakeValidTransition(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i); var s := b[i-1].replicas[idx].replica; var s' := b[i].replicas[idx].replica; lemma_LogTruncationPointMonotonicOneStep(b, c, i-1, idx); if p in s.proposer.received_1b_packets { lemma_VoteInReceived1bMessageAlwaysWithinLogTruncationPointRange(b, c, i-1, idx, opn, p); lemma_LogTruncationPointMonotonicOneStep(b, c, i-1, idx); return; } var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, c, i-1, idx); lemma_VoteIn1bMessageAlwaysWithinLogTruncationPointRange(b, c, i, opn, p); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/CommonProof/MaxBallot.i.dfy ================================================ include "../DistributedSystem.i.dfy" include "Assumptions.i.dfy" include "Constants.i.dfy" include "Actions.i.dfy" include "PacketSending.i.dfy" include "MaxBallotISent1a.i.dfy" module CommonProof__MaxBallot_i { import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Constants_i import opened LiveRSL__Types_i import opened CommonProof__Assumptions_i import opened CommonProof__Constants_i import opened CommonProof__Actions_i import opened CommonProof__PacketSending_i import opened CommonProof__MaxBallotISent1a_i import opened Temporal__Temporal_s lemma lemma_MaxBalLeqMaxBallotPrimarySent1a( b:Behavior, c:LConstants, i:int, idx:int ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires 0 <= idx < |b[i].replicas| ensures 0 <= b[i].replicas[idx].replica.acceptor.max_bal.proposer_id < |b[i].replicas| ensures var max_bal := b[i].replicas[idx].replica.acceptor.max_bal; BalLeq(max_bal, b[i].replicas[max_bal.proposer_id].replica.proposer.max_ballot_i_sent_1a) decreases i { if i > 0 { lemma_ConstantsAllConsistent(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i); lemma_AssumptionsMakeValidTransition(b, c, i-1); var s := b[i-1].replicas[idx].replica; var s' := b[i].replicas[idx].replica; var max_bal := s.acceptor.max_bal; var max_bal' := s'.acceptor.max_bal; if max_bal == max_bal' { lemma_MaxBalLeqMaxBallotPrimarySent1a(b, c, i-1, idx); lemma_MaxBallotISent1aMonotonicOneStep(b, c, i-1, max_bal.proposer_id); } else { var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, c, i-1, idx); var nextActionIndex := b[i-1].replicas[idx].nextActionIndex; assert nextActionIndex == 0; var p := ios[0].r; lemma_PacketProcessedImpliesPacketSent(b[i-1], b[i], idx, ios, p); assert p in b[i-1].environment.sentPackets; if p.msg.RslMessage_1a? { lemma_Message1aLeqMaxBallotSenderSent1a(b, c, i-1, p); } else if p.msg.RslMessage_2a? { lemma_Message2aLeqMaxBallotSenderSent1a(b, c, i-1, p); } else { assert false; } } } } lemma lemma_VotePrecedesMaxBal( b:Behavior, c:LConstants, i:int, idx:int, opn:OperationNumber ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires 0 <= idx < |b[i].replicas| requires opn in b[i].replicas[idx].replica.acceptor.votes ensures BalLeq(b[i].replicas[idx].replica.acceptor.votes[opn].max_value_bal, b[i].replicas[idx].replica.acceptor.max_bal) decreases i { if i == 0 { return; } lemma_ReplicaConstantsAllConsistent(b, c, i, idx); lemma_ReplicaConstantsAllConsistent(b, c, i-1, idx); lemma_AssumptionsMakeValidTransition(b, c, i-1); var s := b[i-1].replicas[idx].replica.acceptor; var s' := b[i].replicas[idx].replica.acceptor; if s' == s { lemma_VotePrecedesMaxBal(b, c, i-1, idx, opn); return; } var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, c, i-1, idx); if opn in s.votes { lemma_VotePrecedesMaxBal(b, c, i-1, idx, opn); } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/CommonProof/MaxBallotISent1a.i.dfy ================================================ include "../DistributedSystem.i.dfy" include "Assumptions.i.dfy" include "Constants.i.dfy" include "Actions.i.dfy" include "PacketSending.i.dfy" module CommonProof__MaxBallotISent1a_i { import opened LiveRSL__Constants_i import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Environment_i import opened LiveRSL__Types_i import opened CommonProof__Assumptions_i import opened CommonProof__Constants_i import opened CommonProof__Actions_i import opened CommonProof__PacketSending_i import opened Temporal__Temporal_s predicate PrimaryHasReachedState2OfBallot( ps:RslState, bal:Ballot ) { var proposer_idx := bal.proposer_id; && 0 <= proposer_idx < |ps.replicas| && var s := ps.replicas[proposer_idx].replica.proposer; && BalLeq(bal, s.max_ballot_i_sent_1a) && (bal == s.max_ballot_i_sent_1a ==> s.current_state != 1) } lemma lemma_MaxBallotISent1aMonotonicOneStep( b:Behavior, c:LConstants, i:int, idx:int ) requires IsValidBehaviorPrefix(b, c, i+1) requires 0 <= i requires 0 <= idx < |b[i].replicas| ensures 0 <= idx < |b[i+1].replicas| ensures BalLeq(b[i].replicas[idx].replica.proposer.max_ballot_i_sent_1a, b[i+1].replicas[idx].replica.proposer.max_ballot_i_sent_1a) ensures b[i].replicas[idx].replica.proposer.current_state != 1 ==> || b[i+1].replicas[idx].replica.proposer.current_state != 1 || BalLt(b[i].replicas[idx].replica.proposer.max_ballot_i_sent_1a, b[i+1].replicas[idx].replica.proposer.max_ballot_i_sent_1a) { lemma_AssumptionsMakeValidTransition(b, c, i); lemma_ConstantsAllConsistent(b, c, i+1); } lemma lemma_MaxBallotISent1aMonotonic( b:Behavior, c:LConstants, i:int, j:int, idx:int ) requires IsValidBehaviorPrefix(b, c, j) requires 0 <= i <= j requires 0 <= idx < |b[i].replicas| ensures 0 <= idx < |b[j].replicas| ensures BalLeq(b[i].replicas[idx].replica.proposer.max_ballot_i_sent_1a, b[j].replicas[idx].replica.proposer.max_ballot_i_sent_1a) ensures b[i].replicas[idx].replica.proposer.current_state != 1 ==> || b[j].replicas[idx].replica.proposer.current_state != 1 || BalLt(b[i].replicas[idx].replica.proposer.max_ballot_i_sent_1a, b[j].replicas[idx].replica.proposer.max_ballot_i_sent_1a) { if j > i { lemma_ReplicaConstantsAllConsistent(b, c, i, idx); lemma_ReplicaConstantsAllConsistent(b, c, j-1, idx); lemma_ReplicaConstantsAllConsistent(b, c, j, idx); lemma_MaxBallotISent1aMonotonic(b, c, i, j-1, idx); lemma_MaxBallotISent1aMonotonicOneStep(b, c, j-1, idx); } } lemma lemma_MaxBallotISent1aHasMeAsProposer( b:Behavior, c:LConstants, i:int, idx:int ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires 0 <= idx < |b[i].replicas| ensures b[i].replicas[idx].replica.proposer.max_ballot_i_sent_1a.proposer_id == idx ensures b[i].replicas[idx].replica.proposer.max_ballot_i_sent_1a.seqno >= 0 decreases i { if i > 0 { lemma_ConstantsAllConsistent(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i); lemma_MaxBallotISent1aHasMeAsProposer(b, c, i-1, idx); if b[i].replicas[idx].replica.proposer.max_ballot_i_sent_1a != b[i-1].replicas[idx].replica.proposer.max_ballot_i_sent_1a { var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, c, i-1, idx); } } } lemma lemma_PrimaryHasReachedState2OfBallotMaintainedByOneStep( b:Behavior, c:LConstants, i:int, bal:Ballot ) requires IsValidBehaviorPrefix(b, c, i+1) requires 0 <= i requires PrimaryHasReachedState2OfBallot(b[i], bal) ensures PrimaryHasReachedState2OfBallot(b[i+1], bal) { lemma_MaxBallotISent1aMonotonicOneStep(b, c, i, bal.proposer_id); } lemma lemma_Message1aLeqMaxBallotSenderSent1a( b:Behavior, c:LConstants, i:int, p:RslPacket ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires p in b[i].environment.sentPackets requires p.src in c.config.replica_ids requires p.msg.RslMessage_1a? ensures 0 <= p.msg.bal_1a.proposer_id < |b[i].replicas| == |b[i].constants.config.replica_ids| ensures p.src == b[i].constants.config.replica_ids[p.msg.bal_1a.proposer_id] ensures var proposer_idx := p.msg.bal_1a.proposer_id; BalLeq(p.msg.bal_1a, b[i].replicas[proposer_idx].replica.proposer.max_ballot_i_sent_1a) decreases i { if i > 0 { lemma_ConstantsAllConsistent(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i); lemma_AssumptionsMakeValidTransition(b, c, i-1); if p in b[i-1].environment.sentPackets { lemma_Message1aLeqMaxBallotSenderSent1a(b, c, i-1, p); lemma_MaxBallotISent1aMonotonicOneStep(b, c, i-1, p.msg.bal_1a.proposer_id); } else { var idx, ios := lemma_ActionThatSends1aIsMaybeEnterNewViewAndSend1a(b[i-1], b[i], p); lemma_MaxBallotISent1aHasMeAsProposer(b, c, i-1, idx); } } } lemma lemma_MessageStartingPhase2LeqMaxBallotSenderSent1a( b:Behavior, c:LConstants, i:int, p:RslPacket ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires p in b[i].environment.sentPackets requires p.src in c.config.replica_ids requires p.msg.RslMessage_StartingPhase2? ensures 0 <= p.msg.bal_2.proposer_id < |b[i].replicas| == |b[i].constants.config.replica_ids| ensures p.src == b[i].constants.config.replica_ids[p.msg.bal_2.proposer_id] ensures var proposer_idx := p.msg.bal_2.proposer_id; BalLeq(p.msg.bal_2, b[i].replicas[proposer_idx].replica.proposer.max_ballot_i_sent_1a) decreases i { if i > 0 { lemma_ConstantsAllConsistent(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i); lemma_AssumptionsMakeValidTransition(b, c, i-1); if p in b[i-1].environment.sentPackets { lemma_MessageStartingPhase2LeqMaxBallotSenderSent1a(b, c, i-1, p); lemma_MaxBallotISent1aMonotonicOneStep(b, c, i-1, p.msg.bal_2.proposer_id); } else { var idx, ios := lemma_ActionThatSendsStartingPhase2IsMaybeEnterPhase2(b[i-1], b[i], p); lemma_MaxBallotISent1aHasMeAsProposer(b, c, i-1, idx); } } } lemma lemma_Message2aLeqMaxBallotSenderSent1a( b:Behavior, c:LConstants, i:int, p:RslPacket ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires p in b[i].environment.sentPackets requires p.src in c.config.replica_ids requires p.msg.RslMessage_2a? ensures 0 <= p.msg.bal_2a.proposer_id < |b[i].replicas| == |b[i].constants.config.replica_ids| ensures p.src == b[i].constants.config.replica_ids[p.msg.bal_2a.proposer_id] ensures var proposer_idx := p.msg.bal_2a.proposer_id; BalLeq(p.msg.bal_2a, b[i].replicas[proposer_idx].replica.proposer.max_ballot_i_sent_1a) decreases i { if i > 0 { lemma_ConstantsAllConsistent(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i); lemma_AssumptionsMakeValidTransition(b, c, i-1); if p in b[i-1].environment.sentPackets { lemma_Message2aLeqMaxBallotSenderSent1a(b, c, i-1, p); lemma_MaxBallotISent1aMonotonicOneStep(b, c, i-1, p.msg.bal_2a.proposer_id); } else { var idx, ios := lemma_ActionThatSends2aIsMaybeNominateValueAndSend2a(b[i-1], b[i], p); lemma_MaxBallotISent1aHasMeAsProposer(b, c, i-1, idx); } } } lemma lemma_Message2aShowsPrimaryReachedState2( b:Behavior, c:LConstants, i:int, p:RslPacket ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires p in b[i].environment.sentPackets requires p.src in c.config.replica_ids requires p.msg.RslMessage_2a? ensures PrimaryHasReachedState2OfBallot(b[i], p.msg.bal_2a) decreases i { lemma_Message2aLeqMaxBallotSenderSent1a(b, c, i, p); if i > 0 { lemma_ConstantsAllConsistent(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i); lemma_AssumptionsMakeValidTransition(b, c, i-1); if p in b[i-1].environment.sentPackets { lemma_Message2aShowsPrimaryReachedState2(b, c, i-1, p); lemma_PrimaryHasReachedState2OfBallotMaintainedByOneStep(b, c, i-1, p.msg.bal_2a); } else { var idx, ios := lemma_ActionThatSends2aIsMaybeNominateValueAndSend2a(b[i-1], b[i], p); lemma_MaxBallotISent1aHasMeAsProposer(b, c, i-1, idx); } } } lemma lemma_Message2bShowsPrimaryReachedState2( b:Behavior, c:LConstants, i:int, p:RslPacket ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires p in b[i].environment.sentPackets requires p.src in c.config.replica_ids requires p.msg.RslMessage_2b? ensures PrimaryHasReachedState2OfBallot(b[i], p.msg.bal_2b) decreases i { if i > 0 { lemma_ConstantsAllConsistent(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i); lemma_AssumptionsMakeValidTransition(b, c, i-1); if p in b[i-1].environment.sentPackets { lemma_Message2bShowsPrimaryReachedState2(b, c, i-1, p); lemma_PrimaryHasReachedState2OfBallotMaintainedByOneStep(b, c, i-1, p.msg.bal_2b); } else { var idx, ios := lemma_ActionThatSends2bIsProcess2a(b[i-1], b[i], p); lemma_PacketProcessedImpliesPacketSent(b[i-1], b[i], idx, ios, ios[0].r); lemma_Message2aShowsPrimaryReachedState2(b, c, i-1, ios[0].r); } } } lemma lemma_LearnerMaxBallotSeenShowsPrimaryReachedState2( b:Behavior, c:LConstants, i:int, learner_idx:int ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires 0 <= learner_idx < |b[i].replicas| ensures PrimaryHasReachedState2OfBallot(b[i], b[i].replicas[learner_idx].replica.learner.max_ballot_seen) decreases i { if i > 0 { lemma_ConstantsAllConsistent(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i); lemma_AssumptionsMakeValidTransition(b, c, i-1); var max_ballot_seen := b[i-1].replicas[learner_idx].replica.learner.max_ballot_seen; var max_ballot_seen' := b[i].replicas[learner_idx].replica.learner.max_ballot_seen; if max_ballot_seen' == max_ballot_seen { lemma_LearnerMaxBallotSeenShowsPrimaryReachedState2(b, c, i-1, learner_idx); lemma_PrimaryHasReachedState2OfBallotMaintainedByOneStep(b, c, i-1, max_ballot_seen); } else { var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, c, i-1, learner_idx); lemma_PacketProcessedImpliesPacketSent(b[i-1], b[i], learner_idx, ios, ios[0].r); lemma_Message2bShowsPrimaryReachedState2(b, c, i-1, ios[0].r); } } } lemma lemma_ExecutorNextOpToExecuteBallotShowsPrimaryReachedState2( b:Behavior, c:LConstants, i:int, executor_idx:int ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires 0 <= executor_idx < |b[i].replicas| ensures var nextOp := b[i].replicas[executor_idx].replica.executor.next_op_to_execute; nextOp.OutstandingOpKnown? ==> PrimaryHasReachedState2OfBallot(b[i], nextOp.bal) decreases i { if i > 0 { lemma_ConstantsAllConsistent(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i); lemma_AssumptionsMakeValidTransition(b, c, i-1); var nextOp := b[i-1].replicas[executor_idx].replica.executor.next_op_to_execute; var nextOp' := b[i].replicas[executor_idx].replica.executor.next_op_to_execute; if nextOp' == nextOp { lemma_ExecutorNextOpToExecuteBallotShowsPrimaryReachedState2(b, c, i-1, executor_idx); if nextOp.OutstandingOpKnown? { lemma_PrimaryHasReachedState2OfBallotMaintainedByOneStep(b, c, i-1, nextOp.bal); } } else { var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, c, i-1, executor_idx); lemma_LearnerMaxBallotSeenShowsPrimaryReachedState2(b, c, i-1, executor_idx); } } } lemma lemma_Received1bPacketsAreFromMaxBallotISent1a( b:Behavior, c:LConstants, i:int, idx:int ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires 0 <= idx < |b[i].replicas| ensures var s := b[i].replicas[idx].replica.proposer; forall p :: p in s.received_1b_packets ==> && p.msg.RslMessage_1b? && p.msg.bal_1b == s.max_ballot_i_sent_1a && p.src in c.config.replica_ids && p in b[i].environment.sentPackets ensures var s := b[i].replicas[idx].replica.proposer; forall p1, p2 :: p1 in s.received_1b_packets && p2 in s.received_1b_packets ==> p1 == p2 || p1.src != p2.src { if i > 0 { lemma_ConstantsAllConsistent(b, c, i-1); lemma_AssumptionsMakeValidTransition(b, c, i-1); lemma_Received1bPacketsAreFromMaxBallotISent1a(b, c, i-1, idx); var s := b[i-1].replicas[idx].replica.proposer; var s' := b[i].replicas[idx].replica.proposer; forall p | p in s'.received_1b_packets ensures p.msg.RslMessage_1b? ensures p.msg.bal_1b == s.max_ballot_i_sent_1a ensures p in b[i].environment.sentPackets { if p !in s.received_1b_packets { var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, c, i-1, idx); lemma_PacketProcessedImpliesPacketSent(b[i-1], b[i], idx, ios, p); } } forall p1, p2 | p1 in s'.received_1b_packets && p2 in s'.received_1b_packets ensures p1 == p2 || p1.src != p2.src { if p1 !in s.received_1b_packets || p2 !in s.received_1b_packets { var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, c, i-1, idx); } } } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/CommonProof/Message1b.i.dfy ================================================ include "../DistributedSystem.i.dfy" include "Assumptions.i.dfy" include "Constants.i.dfy" include "Actions.i.dfy" include "PacketSending.i.dfy" include "Environment.i.dfy" include "Message2b.i.dfy" include "MaxBallot.i.dfy" module CommonProof__Message1b_i { import opened LiveRSL__Constants_i import opened LiveRSL__Configuration_i import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Environment_i import opened LiveRSL__Types_i import opened CommonProof__Assumptions_i import opened CommonProof__Constants_i import opened CommonProof__Actions_i import opened CommonProof__PacketSending_i import opened CommonProof__Environment_i import opened CommonProof__Message2b_i import opened CommonProof__MaxBallot_i import opened Environment_s import opened Temporal__Temporal_s lemma lemma_1bMessageImplicationsForAcceptorState( b:Behavior, c:LConstants, i:int, opn:OperationNumber, p:RslPacket ) returns ( acceptor_idx:int ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires p in b[i].environment.sentPackets requires p.src in c.config.replica_ids requires p.msg.RslMessage_1b? ensures 0 <= acceptor_idx < |c.config.replica_ids| ensures 0 <= acceptor_idx < |b[i].replicas| ensures p.src == c.config.replica_ids[acceptor_idx] ensures BalLeq(p.msg.bal_1b, b[i].replicas[acceptor_idx].replica.acceptor.max_bal) ensures var s := b[i].replicas[acceptor_idx].replica.acceptor; opn in p.msg.votes && opn >= s.log_truncation_point ==> && opn in s.votes && (|| BalLeq(p.msg.bal_1b, s.votes[opn].max_value_bal) || s.votes[opn] == Vote(p.msg.votes[opn].max_value_bal, p.msg.votes[opn].max_val)) ensures var s := b[i].replicas[acceptor_idx].replica.acceptor; opn !in p.msg.votes && opn >= s.log_truncation_point ==> || opn !in s.votes || (opn in s.votes && BalLeq(p.msg.bal_1b, s.votes[opn].max_value_bal)); decreases i { if i == 0 { return; } lemma_AssumptionsMakeValidTransition(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i); lemma_ConstantsAllConsistent(b, c, i-1); if p in b[i-1].environment.sentPackets { acceptor_idx := lemma_1bMessageImplicationsForAcceptorState(b, c, i-1, opn, p); var s := b[i-1].replicas[acceptor_idx].replica.acceptor; var s' := b[i].replicas[acceptor_idx].replica.acceptor; if opn < s'.log_truncation_point { return; } if s'.log_truncation_point == s.log_truncation_point && s'.votes == s.votes { return; } var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, c, i-1, acceptor_idx); assert opn >= s'.log_truncation_point >= s.log_truncation_point; if opn in p.msg.votes { lemma_CurrentVoteDoesNotExceedMaxBal(b, c, i-1, opn, acceptor_idx); if s'.votes[opn].max_value_bal == s.votes[opn].max_value_bal { lemma_ActionThatOverwritesVoteWithSameBallotDoesntChangeValue(b, c, i-1, opn, s.votes[opn].max_value_bal, acceptor_idx); } } return; } var ios:seq; acceptor_idx, ios := lemma_ActionThatSends1bIsProcess1a(b[i-1], b[i], p); var s := b[i-1].replicas[acceptor_idx].replica.acceptor; var s' := b[i].replicas[acceptor_idx].replica.acceptor; if opn in s.votes && opn in s'.votes && s'.votes[opn].max_value_bal == s.votes[opn].max_value_bal { lemma_ActionThatOverwritesVoteWithSameBallotDoesntChangeValue(b, c, i-1, opn, s.votes[opn].max_value_bal, acceptor_idx); } } lemma lemma_1bMessageWithoutOpnImplicationsFor2b( b:Behavior, c:LConstants, i:int, opn:OperationNumber, p_1b:RslPacket, p_2b:RslPacket ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires p_1b in b[i].environment.sentPackets requires p_2b in b[i].environment.sentPackets requires p_1b.src in c.config.replica_ids requires p_1b.src == p_2b.src requires p_1b.msg.RslMessage_1b? requires p_2b.msg.RslMessage_2b? requires opn !in p_1b.msg.votes requires opn >= p_1b.msg.log_truncation_point requires p_2b.msg.opn_2b == opn ensures BalLeq(p_1b.msg.bal_1b, p_2b.msg.bal_2b) decreases i { if i == 0 { return; } lemma_AssumptionsMakeValidTransition(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i); lemma_ConstantsAllConsistent(b, c, i-1); if p_1b in b[i-1].environment.sentPackets { if p_2b in b[i-1].environment.sentPackets { lemma_1bMessageWithoutOpnImplicationsFor2b(b, c, i-1, opn, p_1b, p_2b); } else { var acceptor_idx := lemma_1bMessageImplicationsForAcceptorState(b, c, i-1, opn, p_1b); var acceptor_idx_alt, ios := lemma_ActionThatSends2bIsProcess2a(b[i-1], b[i], p_2b); assert ReplicasDistinct(c.config.replica_ids, acceptor_idx, acceptor_idx_alt); } } else { if p_2b in b[i-1].environment.sentPackets { var acceptor_idx := lemma_2bMessageImplicationsForAcceptorState(b, c, i-1, p_2b); var acceptor_idx_alt, ios := lemma_ActionThatSends1bIsProcess1a(b[i-1], b[i], p_1b); assert ReplicasDistinct(c.config.replica_ids, acceptor_idx, acceptor_idx_alt); } else { var acceptor_idx, ios := lemma_ActionThatSends1bIsProcess1a(b[i-1], b[i], p_1b); assert LIoOpSend(p_1b) in ios; assert false; } } } lemma lemma_1bMessageWithOpnImplicationsFor2b( b:Behavior, c:LConstants, i:int, opn:OperationNumber, p_1b:RslPacket, p_2b:RslPacket ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires p_1b in b[i].environment.sentPackets requires p_2b in b[i].environment.sentPackets requires p_1b.src in c.config.replica_ids requires p_1b.src == p_2b.src requires p_1b.msg.RslMessage_1b? requires p_2b.msg.RslMessage_2b? requires opn in p_1b.msg.votes requires opn >= p_1b.msg.log_truncation_point requires p_2b.msg.opn_2b == opn ensures || BalLeq(p_1b.msg.bal_1b, p_2b.msg.bal_2b) || (p_2b.msg.bal_2b == p_1b.msg.votes[opn].max_value_bal && p_2b.msg.val_2b == p_1b.msg.votes[opn].max_val) || BalLt(p_2b.msg.bal_2b, p_1b.msg.votes[opn].max_value_bal) decreases i { if i == 0 { return; } lemma_AssumptionsMakeValidTransition(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i); lemma_ConstantsAllConsistent(b, c, i-1); if p_1b in b[i-1].environment.sentPackets { if p_2b in b[i-1].environment.sentPackets { lemma_1bMessageWithOpnImplicationsFor2b(b, c, i-1, opn, p_1b, p_2b); } else { var acceptor_idx := lemma_1bMessageImplicationsForAcceptorState(b, c, i-1, opn, p_1b); var acceptor_idx_alt, ios := lemma_ActionThatSends2bIsProcess2a(b[i-1], b[i], p_2b); assert ReplicasDistinct(c.config.replica_ids, acceptor_idx, acceptor_idx_alt); } } else { if p_2b in b[i-1].environment.sentPackets { var acceptor_idx := lemma_2bMessageImplicationsForAcceptorState(b, c, i-1, p_2b); var acceptor_idx_alt, ios := lemma_ActionThatSends1bIsProcess1a(b[i-1], b[i], p_1b); assert ReplicasDistinct(c.config.replica_ids, acceptor_idx, acceptor_idx_alt); } else { var acceptor_idx, ios := lemma_ActionThatSends1bIsProcess1a(b[i-1], b[i], p_1b); assert LIoOpSend(p_1b) in ios; assert false; } } } lemma lemma_Vote1bMessageIsFromEarlierBallot( b:Behavior, c:LConstants, i:int, opn:OperationNumber, p:RslPacket ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires p in b[i].environment.sentPackets requires p.src in c.config.replica_ids requires p.msg.RslMessage_1b? requires opn in p.msg.votes ensures BalLt(p.msg.votes[opn].max_value_bal, p.msg.bal_1b) decreases i { if i == 0 { return; } lemma_AssumptionsMakeValidTransition(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i); lemma_ConstantsAllConsistent(b, c, i-1); if p in b[i-1].environment.sentPackets { lemma_Vote1bMessageIsFromEarlierBallot(b, c, i-1, opn, p); return; } var idx, ios := lemma_ActionThatSends1bIsProcess1a(b[i-1], b[i], p); lemma_VotePrecedesMaxBal(b, c, i-1, idx, opn); } lemma lemma_1bMessageWithOpnImplies2aSent( b:Behavior, c:LConstants, i:int, opn:OperationNumber, p_1b:RslPacket ) returns ( p_2a:RslPacket ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires p_1b in b[i].environment.sentPackets requires p_1b.src in c.config.replica_ids requires p_1b.msg.RslMessage_1b? requires opn in p_1b.msg.votes ensures p_2a in b[i].environment.sentPackets ensures p_2a.src in c.config.replica_ids ensures p_2a.msg.RslMessage_2a? ensures p_2a.msg.opn_2a == opn ensures p_2a.msg.bal_2a == p_1b.msg.votes[opn].max_value_bal ensures p_2a.msg.val_2a == p_1b.msg.votes[opn].max_val decreases i { if i == 0 { return; } lemma_AssumptionsMakeValidTransition(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i); lemma_ConstantsAllConsistent(b, c, i-1); if p_1b in b[i-1].environment.sentPackets { p_2a := lemma_1bMessageWithOpnImplies2aSent(b, c, i-1, opn, p_1b); return; } var idx, ios := lemma_ActionThatSends1bIsProcess1a(b[i-1], b[i], p_1b); p_2a := lemma_VoteWithOpnImplies2aSent(b, c, i-1, idx, opn); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/CommonProof/Message2a.i.dfy ================================================ include "../DistributedSystem.i.dfy" include "Assumptions.i.dfy" include "Constants.i.dfy" include "Actions.i.dfy" include "PacketSending.i.dfy" include "Environment.i.dfy" include "MaxBallotISent1a.i.dfy" include "Received1b.i.dfy" module CommonProof__Message2a_i { import opened LiveRSL__Configuration_i import opened LiveRSL__Constants_i import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Environment_i import opened LiveRSL__Proposer_i import opened LiveRSL__Types_i import opened CommonProof__Assumptions_i import opened CommonProof__Constants_i import opened CommonProof__Actions_i import opened CommonProof__PacketSending_i import opened CommonProof__Environment_i import opened CommonProof__MaxBallotISent1a_i import opened CommonProof__Received1b_i import opened Temporal__Temporal_s import opened Environment_s lemma lemma_2aMessageImplicationsForProposerState( b:Behavior, c:LConstants, i:int, p:RslPacket ) returns ( proposer_idx:int ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires p in b[i].environment.sentPackets requires p.src in c.config.replica_ids requires p.msg.RslMessage_2a? ensures 0 <= proposer_idx < |c.config.replica_ids| ensures 0 <= proposer_idx < |b[i].replicas| ensures p.src == c.config.replica_ids[proposer_idx] ensures p.msg.bal_2a.proposer_id == proposer_idx ensures var s := b[i].replicas[proposer_idx].replica.proposer; || BalLt(p.msg.bal_2a, s.max_ballot_i_sent_1a) || (&& s.max_ballot_i_sent_1a == p.msg.bal_2a && s.current_state != 1 && s.next_operation_number_to_propose > p.msg.opn_2a) decreases i { if i == 0 { return; } lemma_AssumptionsMakeValidTransition(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i); lemma_ConstantsAllConsistent(b, c, i-1); if p in b[i-1].environment.sentPackets { proposer_idx := lemma_2aMessageImplicationsForProposerState(b, c, i-1, p); var s := b[i-1].replicas[proposer_idx].replica.proposer; var s' := b[i].replicas[proposer_idx].replica.proposer; if s' != s { var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, c, i-1, proposer_idx); } return; } var ios:seq; proposer_idx, ios := lemma_ActionThatSends2aIsMaybeNominateValueAndSend2a(b[i-1], b[i], p); lemma_MaxBallotISent1aHasMeAsProposer(b, c, i-1, proposer_idx); } lemma lemma_2aMessagesFromSameBallotAndOperationMatchWithoutLossOfGenerality( b:Behavior, c:LConstants, i:int, p1:RslPacket, p2:RslPacket ) requires IsValidBehaviorPrefix(b, c, i) requires 0 < i requires p1 in b[i].environment.sentPackets requires p2 in b[i].environment.sentPackets requires p1.src in c.config.replica_ids requires p2.src in c.config.replica_ids requires p1.msg.RslMessage_2a? requires p2.msg.RslMessage_2a? requires p1.msg.opn_2a == p2.msg.opn_2a requires p1.msg.bal_2a == p2.msg.bal_2a requires p2 in b[i-1].environment.sentPackets ==> p1 in b[i-1].environment.sentPackets ensures p1.msg.val_2a == p2.msg.val_2a decreases 2 * i { lemma_AssumptionsMakeValidTransition(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i); lemma_ConstantsAllConsistent(b, c, i-1); if p2 in b[i-1].environment.sentPackets { // Both packets had already been sent by i-1, so we induction. lemma_2aMessagesFromSameBallotAndOperationMatch(b, c, i-1, p1, p2); return; } var proposer_idx, ios := lemma_ActionThatSends2aIsMaybeNominateValueAndSend2a(b[i-1], b[i], p2); if p1 !in b[i-1].environment.sentPackets { // Both packets were sent in step i-1, so observe that any two packets sent in the same step // have the same value. assert LIoOpSend(p1) in ios; assert LIoOpSend(p2) in ios; return; } // Note the implications on processor state for p1, since once p1 is sent we // won't be able to send p2. var alt_proposer_idx := lemma_2aMessageImplicationsForProposerState(b, c, i-1, p1); // Note the implications on processor state for p2, just to notice that they // use the same replica index. var alt2_proposer_idx := lemma_2aMessageImplicationsForProposerState(b, c, i, p2); assert alt_proposer_idx == alt2_proposer_idx; assert ReplicasDistinct(c.config.replica_ids, proposer_idx, alt_proposer_idx); assert proposer_idx == alt_proposer_idx; assert false; } lemma lemma_2aMessagesFromSameBallotAndOperationMatch( b:Behavior, c:LConstants, i:int, p1:RslPacket, p2:RslPacket ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires p1 in b[i].environment.sentPackets requires p2 in b[i].environment.sentPackets requires p1.src in c.config.replica_ids requires p2.src in c.config.replica_ids requires p1.msg.RslMessage_2a? requires p2.msg.RslMessage_2a? requires p1.msg.opn_2a == p2.msg.opn_2a requires p1.msg.bal_2a == p2.msg.bal_2a ensures p1.msg.val_2a == p2.msg.val_2a decreases 2 * i + 1 { if i == 0 { return; } if p2 in b[i-1].environment.sentPackets && p1 !in b[i-1].environment.sentPackets { lemma_2aMessagesFromSameBallotAndOperationMatchWithoutLossOfGenerality(b, c, i, p2, p1); } else { lemma_2aMessagesFromSameBallotAndOperationMatchWithoutLossOfGenerality(b, c, i, p1, p2); } } lemma lemma_2aMessageHas1bQuorumPermittingIt( b:Behavior, c:LConstants, i:int, p:RslPacket ) returns ( q:set ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires p in b[i].environment.sentPackets requires p.src in c.config.replica_ids requires p.msg.RslMessage_2a? ensures q <= b[i].environment.sentPackets ensures |q| >= LMinQuorumSize(c.config) ensures LIsAfterLogTruncationPoint(p.msg.opn_2a, q) ensures LSetOfMessage1bAboutBallot(q, p.msg.bal_2a) ensures LAllAcceptorsHadNoProposal(q, p.msg.opn_2a) || LValIsHighestNumberedProposal(p.msg.val_2a, q, p.msg.opn_2a) ensures forall p1, p2 :: p1 in q && p2 in q && p1 != p2 ==> p1.src != p2.src ensures forall p1 :: p1 in q ==> p1.src in c.config.replica_ids { if i == 0 { return; } if p in b[i-1].environment.sentPackets { q := lemma_2aMessageHas1bQuorumPermittingIt(b, c, i-1, p); lemma_PacketSetStaysInSentPackets(b, c, i-1, i, q); return; } lemma_ConstantsAllConsistent(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i); lemma_AssumptionsMakeValidTransition(b, c, i-1); var idx, ios := lemma_ActionThatSends2aIsMaybeNominateValueAndSend2a(b[i-1], b[i], p); q := b[i-1].replicas[idx].replica.proposer.received_1b_packets; forall p_1b | p_1b in q ensures p_1b in b[i].environment.sentPackets { lemma_PacketInReceived1bWasSent(b, c, i-1, idx, p_1b); lemma_PacketStaysInSentPackets(b, c, i-1, i, p_1b); } lemma_Received1bPacketsAreFromMaxBallotISent1a(b, c, i-1, idx); } lemma lemma_Find2aThatCausedVote( b:Behavior, c:LConstants, i:int, idx:int, opn:OperationNumber ) returns ( p:RslPacket ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires 0 <= idx < |b[i].replicas| requires opn in b[i].replicas[idx].replica.acceptor.votes ensures p in b[i].environment.sentPackets ensures p.src in c.config.replica_ids ensures p.msg.RslMessage_2a? ensures p.msg.opn_2a == opn ensures p.msg.val_2a == b[i].replicas[idx].replica.acceptor.votes[opn].max_val ensures p.msg.bal_2a == b[i].replicas[idx].replica.acceptor.votes[opn].max_value_bal decreases i { if i == 0 { return; } lemma_ReplicaConstantsAllConsistent(b, c, i, idx); lemma_ReplicaConstantsAllConsistent(b, c, i-1, idx); lemma_AssumptionsMakeValidTransition(b, c, i-1); var s := b[i-1].replicas[idx].replica.acceptor; var s' := b[i].replicas[idx].replica.acceptor; if opn in s.votes && s'.votes[opn] == s.votes[opn] { p := lemma_Find2aThatCausedVote(b, c, i-1, idx, opn); return; } var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, c, i-1, idx); p := ios[0].r; } lemma lemma_2aMessageHasValidBallot( b:Behavior, c:LConstants, i:int, p:RslPacket ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires p in b[i].environment.sentPackets requires p.src in c.config.replica_ids requires p.msg.RslMessage_2a? ensures p.msg.bal_2a.seqno >= 0 ensures 0 <= p.msg.bal_2a.proposer_id < |c.config.replica_ids| { if i == 0 { return; } lemma_ConstantsAllConsistent(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i); lemma_AssumptionsMakeValidTransition(b, c, i-1); if p in b[i-1].environment.sentPackets { lemma_2aMessageHasValidBallot(b, c, i-1, p); return; } var idx, ios := lemma_ActionThatSends2aIsMaybeNominateValueAndSend2a(b[i-1], b[i], p); lemma_MaxBallotISent1aHasMeAsProposer(b, c, i-1, idx); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/CommonProof/Message2b.i.dfy ================================================ include "../DistributedSystem.i.dfy" include "Assumptions.i.dfy" include "Constants.i.dfy" include "Actions.i.dfy" include "PacketSending.i.dfy" include "Environment.i.dfy" include "Message2a.i.dfy" module CommonProof__Message2b_i { import opened LiveRSL__Constants_i import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Environment_i import opened LiveRSL__Types_i import opened CommonProof__Assumptions_i import opened CommonProof__Constants_i import opened CommonProof__Actions_i import opened CommonProof__PacketSending_i import opened CommonProof__Environment_i import opened CommonProof__Message2a_i import opened Temporal__Temporal_s lemma lemma_2bMessageHasCorresponding2aMessage( b:Behavior, c:LConstants, i:int, p_2b:RslPacket ) returns ( p_2a:RslPacket ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires p_2b in b[i].environment.sentPackets requires p_2b.src in c.config.replica_ids requires p_2b.msg.RslMessage_2b? ensures p_2a in b[i].environment.sentPackets ensures p_2a.src in c.config.replica_ids ensures p_2a.msg.RslMessage_2a? ensures p_2a.msg.opn_2a == p_2b.msg.opn_2b ensures p_2a.msg.bal_2a == p_2b.msg.bal_2b ensures p_2a.msg.val_2a == p_2b.msg.val_2b decreases i { if i == 0 { return; } if p_2b in b[i-1].environment.sentPackets { p_2a := lemma_2bMessageHasCorresponding2aMessage(b, c, i-1, p_2b); lemma_PacketStaysInSentPackets(b, c, i-1, i, p_2a); return; } lemma_AssumptionsMakeValidTransition(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i); lemma_ConstantsAllConsistent(b, c, i-1); var proposer_idx, ios := lemma_ActionThatSends2bIsProcess2a(b[i-1], b[i], p_2b); p_2a := ios[0].r; } lemma lemma_CurrentVoteDoesNotExceedMaxBal( b:Behavior, c:LConstants, i:int, opn:OperationNumber, idx:int ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires 0 <= idx < |b[i].replicas| requires opn in b[i].replicas[idx].replica.acceptor.votes ensures BalLeq(b[i].replicas[idx].replica.acceptor.votes[opn].max_value_bal, b[i].replicas[idx].replica.acceptor.max_bal) { if i == 0 { return; } lemma_ReplicaConstantsAllConsistent(b, c, i, idx); lemma_ReplicaConstantsAllConsistent(b, c, i-1, idx); var s := b[i-1].replicas[idx].replica.acceptor; var s' := b[i].replicas[idx].replica.acceptor; if s'.votes == s.votes && s'.max_bal == s.max_bal { lemma_CurrentVoteDoesNotExceedMaxBal(b, c, i-1, opn, idx); return; } var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, c, i-1, idx); if opn in s.votes { lemma_CurrentVoteDoesNotExceedMaxBal(b, c, i-1, opn, idx); } } lemma lemma_ActionThatOverwritesVoteWithSameBallotDoesntChangeValue( b:Behavior, c:LConstants, i:int, opn:OperationNumber, bal:Ballot, idx:int ) requires IsValidBehaviorPrefix(b, c, i+1) requires 0 <= i requires 0 <= idx < |b[i].replicas| requires 0 <= idx < |b[i+1].replicas| requires opn in b[i].replicas[idx].replica.acceptor.votes requires opn in b[i+1].replicas[idx].replica.acceptor.votes requires b[i].replicas[idx].replica.acceptor.votes[opn].max_value_bal == b[i+1].replicas[idx].replica.acceptor.votes[opn].max_value_bal ensures b[i].replicas[idx].replica.acceptor.votes[opn].max_val == b[i+1].replicas[idx].replica.acceptor.votes[opn].max_val { lemma_ReplicaConstantsAllConsistent(b, c, i, idx); lemma_ReplicaConstantsAllConsistent(b, c, i+1, idx); lemma_AssumptionsMakeValidTransition(b, c, i); var s := b[i].replicas[idx].replica.acceptor; var s' := b[i+1].replicas[idx].replica.acceptor; if s'.votes[opn].max_val != s.votes[opn].max_val { var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, c, i, idx); var earlier_2a := lemma_Find2aThatCausedVote(b, c, i, idx, opn); lemma_2aMessagesFromSameBallotAndOperationMatch(b, c, i+1, earlier_2a, ios[0].r); assert false; } } lemma lemma_2bMessageImplicationsForAcceptorState( b:Behavior, c:LConstants, i:int, p:RslPacket ) returns ( acceptor_idx:int ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires p in b[i].environment.sentPackets requires p.src in c.config.replica_ids requires p.msg.RslMessage_2b? ensures 0 <= acceptor_idx < |c.config.replica_ids| ensures 0 <= acceptor_idx < |b[i].replicas| ensures p.src == c.config.replica_ids[acceptor_idx] ensures BalLeq(p.msg.bal_2b, b[i].replicas[acceptor_idx].replica.acceptor.max_bal) ensures var s := b[i].replicas[acceptor_idx].replica.acceptor; p.msg.opn_2b >= s.log_truncation_point ==> && p.msg.opn_2b in s.votes && BalLeq(p.msg.bal_2b, s.votes[p.msg.opn_2b].max_value_bal) && (s.votes[p.msg.opn_2b].max_value_bal == p.msg.bal_2b ==> s.votes[p.msg.opn_2b].max_val == p.msg.val_2b) decreases i { if i == 0 { return; } lemma_AssumptionsMakeValidTransition(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i); lemma_ConstantsAllConsistent(b, c, i-1); var v := p.msg.val_2b; var opn := p.msg.opn_2b; var bal := p.msg.bal_2b; if p in b[i-1].environment.sentPackets { acceptor_idx := lemma_2bMessageImplicationsForAcceptorState(b, c, i-1, p); var s := b[i-1].replicas[acceptor_idx].replica.acceptor; var s' := b[i].replicas[acceptor_idx].replica.acceptor; if s' != s { var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, c, i-1, acceptor_idx); if opn >= s'.log_truncation_point { lemma_CurrentVoteDoesNotExceedMaxBal(b, c, i-1, opn, acceptor_idx); if s'.votes[opn].max_value_bal == s.votes[opn].max_value_bal { lemma_ActionThatOverwritesVoteWithSameBallotDoesntChangeValue(b, c, i-1, opn, bal, acceptor_idx); } } } return; } var ios:seq; acceptor_idx, ios := lemma_ActionThatSends2bIsProcess2a(b[i-1], b[i], p); } lemma lemma_VoteWithOpnImplies2aSent( b:Behavior, c:LConstants, i:int, idx:int, opn:OperationNumber ) returns ( p:RslPacket ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires 0 <= idx < |b[i].replicas| requires opn in b[i].replicas[idx].replica.acceptor.votes ensures p in b[i].environment.sentPackets ensures p.src in c.config.replica_ids ensures p.msg.RslMessage_2a? ensures p.msg.opn_2a == opn ensures p.msg.bal_2a == b[i].replicas[idx].replica.acceptor.votes[opn].max_value_bal ensures p.msg.val_2a == b[i].replicas[idx].replica.acceptor.votes[opn].max_val decreases i { if i == 0 { return; } lemma_AssumptionsMakeValidTransition(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i); lemma_ConstantsAllConsistent(b, c, i-1); var s := b[i-1].replicas[idx].replica.acceptor; var s' := b[i].replicas[idx].replica.acceptor; if s'.votes == s.votes { p := lemma_VoteWithOpnImplies2aSent(b, c, i-1, idx, opn); return; } var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, c, i-1, idx); if opn in s.votes && s'.votes[opn] == s.votes[opn] { p := lemma_VoteWithOpnImplies2aSent(b, c, i-1, idx, opn); return; } p := ios[0].r; } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/CommonProof/PacketSending.i.dfy ================================================ include "../DistributedSystem.i.dfy" module CommonProof__PacketSending_i { import opened LiveRSL__Acceptor_i import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Environment_i import opened LiveRSL__Executor_i import opened LiveRSL__Replica_i import opened Environment_s lemma lemma_ActionThatSendsPacketIsActionOfSource( ps:RslState, ps':RslState, p:RslPacket ) returns ( idx:int, ios:seq ) requires p.src in ps.constants.config.replica_ids requires p in ps'.environment.sentPackets requires p !in ps.environment.sentPackets requires RslNext(ps, ps') ensures 0 <= idx < |ps.constants.config.replica_ids| ensures 0 <= idx < |ps'.constants.config.replica_ids| ensures p.src == ps.constants.config.replica_ids[idx] ensures RslNextOneReplica(ps, ps', idx, ios) ensures LIoOpSend(p) in ios { assert ps.environment.nextStep.LEnvStepHostIos?; assert LIoOpSend(p) in ps.environment.nextStep.ios; idx, ios :| RslNextOneReplica(ps, ps', idx, ios) && LIoOpSend(p) in ios; } lemma lemma_ActionThatSends1aIsMaybeEnterNewViewAndSend1a( ps:RslState, ps':RslState, p:RslPacket ) returns ( idx:int, ios:seq ) requires p.src in ps.constants.config.replica_ids requires p.msg.RslMessage_1a? requires p in ps'.environment.sentPackets requires p !in ps.environment.sentPackets requires RslNext(ps, ps') ensures 0 <= idx < |ps.constants.config.replica_ids| ensures 0 <= idx < |ps'.constants.config.replica_ids| ensures p.src == ps.constants.config.replica_ids[idx] ensures RslNextOneReplica(ps, ps', idx, ios) ensures LIoOpSend(p) in ios ensures LReplicaNextSpontaneousMaybeEnterNewViewAndSend1a(ps.replicas[idx].replica, ps'.replicas[idx].replica, ExtractSentPacketsFromIos(ios)) { assert ps.environment.nextStep.LEnvStepHostIos?; assert LIoOpSend(p) in ps.environment.nextStep.ios; idx, ios :| RslNextOneReplica(ps, ps', idx, ios) && LIoOpSend(p) in ios; var nextActionIndex := ps.replicas[idx].nextActionIndex; if nextActionIndex != 1 { assert false; } } lemma lemma_ActionThatSends1bIsProcess1a( ps:RslState, ps':RslState, p:RslPacket ) returns ( idx:int, ios:seq ) requires p.src in ps.constants.config.replica_ids requires p.msg.RslMessage_1b? requires p in ps'.environment.sentPackets requires p !in ps.environment.sentPackets requires RslNext(ps, ps') ensures 0 <= idx < |ps.constants.config.replica_ids| ensures 0 <= idx < |ps'.constants.config.replica_ids| ensures p.src == ps.constants.config.replica_ids[idx] ensures RslNextOneReplica(ps, ps', idx, ios) ensures |ios| > 0 ensures ios[0].LIoOpReceive? ensures ios[0].r.msg.RslMessage_1a? ensures LIoOpSend(p) in ios ensures LReplicaNextProcessPacketWithoutReadingClock(ps.replicas[idx].replica, ps'.replicas[idx].replica, ios) ensures LAcceptorProcess1a(ps.replicas[idx].replica.acceptor, ps'.replicas[idx].replica.acceptor, ios[0].r, [p]) { assert ps.environment.nextStep.LEnvStepHostIos?; assert LIoOpSend(p) in ps.environment.nextStep.ios; idx, ios :| RslNextOneReplica(ps, ps', idx, ios) && LIoOpSend(p) in ios; } lemma lemma_ActionThatSends2aIsMaybeNominateValueAndSend2a( ps:RslState, ps':RslState, p:RslPacket ) returns ( idx:int, ios:seq ) requires p.src in ps.constants.config.replica_ids requires p.msg.RslMessage_2a? requires p in ps'.environment.sentPackets requires p !in ps.environment.sentPackets requires RslNext(ps, ps') ensures 0 <= idx < |ps.constants.config.replica_ids| ensures 0 <= idx < |ps'.constants.config.replica_ids| ensures p.src == ps.constants.config.replica_ids[idx] ensures RslNextOneReplica(ps, ps', idx, ios) ensures LIoOpSend(p) in ios ensures SpontaneousIos(ios, 1) ensures LReplicaNextReadClockMaybeNominateValueAndSend2a(ps.replicas[idx].replica, ps'.replicas[idx].replica, SpontaneousClock(ios), ExtractSentPacketsFromIos(ios)) { assert ps.environment.nextStep.LEnvStepHostIos?; assert LIoOpSend(p) in ps.environment.nextStep.ios; idx, ios :| RslNextOneReplica(ps, ps', idx, ios) && LIoOpSend(p) in ios; var nextActionIndex := ps.replicas[idx].nextActionIndex; if nextActionIndex != 3 { assert false; } } lemma lemma_ActionThatSends2bIsProcess2a( ps:RslState, ps':RslState, p:RslPacket ) returns ( idx:int, ios:seq ) requires p.src in ps.constants.config.replica_ids requires p.msg.RslMessage_2b? requires p in ps'.environment.sentPackets requires p !in ps.environment.sentPackets requires RslNext(ps, ps') ensures 0 <= idx < |ps.constants.config.replica_ids| ensures 0 <= idx < |ps'.constants.config.replica_ids| ensures p.src == ps.constants.config.replica_ids[idx] ensures RslNextOneReplica(ps, ps', idx, ios) ensures |ios| > 0 ensures ios[0].LIoOpReceive? ensures LIoOpSend(p) in ios ensures LReplicaNextProcess2a(ps.replicas[idx].replica, ps'.replicas[idx].replica, ios[0].r, ExtractSentPacketsFromIos(ios)) { assert ps.environment.nextStep.LEnvStepHostIos?; assert LIoOpSend(p) in ps.environment.nextStep.ios; idx, ios :| RslNextOneReplica(ps, ps', idx, ios) && LIoOpSend(p) in ios; } lemma lemma_ActionThatSendsHeartbeatIsMaybeSendHeartbeat( ps:RslState, ps':RslState, p:RslPacket ) returns ( idx:int, ios:seq ) requires p.src in ps.constants.config.replica_ids requires p.msg.RslMessage_Heartbeat? requires p in ps'.environment.sentPackets requires p !in ps.environment.sentPackets requires RslNext(ps, ps') ensures 0 <= idx < |ps.constants.config.replica_ids| ensures 0 <= idx < |ps'.constants.config.replica_ids| ensures p.src == ps.constants.config.replica_ids[idx] ensures RslNextOneReplica(ps, ps', idx, ios) ensures |ios| > 0 ensures ios[0].LIoOpReadClock? ensures LIoOpSend(p) in ios ensures SpontaneousIos(ios, 1) ensures LReplicaNextReadClockMaybeSendHeartbeat(ps.replicas[idx].replica, ps'.replicas[idx].replica, SpontaneousClock(ios), ExtractSentPacketsFromIos(ios)) { assert ps.environment.nextStep.LEnvStepHostIos?; assert LIoOpSend(p) in ps.environment.nextStep.ios; idx, ios :| RslNextOneReplica(ps, ps', idx, ios) && LIoOpSend(p) in ios; } lemma lemma_ActionThatSendsAppStateRequestIsProcessStartingPhase2( ps:RslState, ps':RslState, p:RslPacket ) returns ( idx:int, ios:seq ) requires p.src in ps.constants.config.replica_ids requires p.msg.RslMessage_AppStateRequest? requires p in ps'.environment.sentPackets requires p !in ps.environment.sentPackets requires RslNext(ps, ps') ensures 0 <= idx < |ps.constants.config.replica_ids| ensures 0 <= idx < |ps'.constants.config.replica_ids| ensures p.src == ps.constants.config.replica_ids[idx] ensures RslNextOneReplica(ps, ps', idx, ios) ensures |ios| > 0 ensures ios[0].LIoOpReceive? ensures ios[0].r.msg.RslMessage_StartingPhase2? ensures LIoOpSend(p) in ios ensures LReplicaNextProcessPacketWithoutReadingClock(ps.replicas[idx].replica, ps'.replicas[idx].replica, ios) ensures LExecutorProcessStartingPhase2(ps.replicas[idx].replica.executor, ps'.replicas[idx].replica.executor, ios[0].r, ExtractSentPacketsFromIos(ios)) { assert ps.environment.nextStep.LEnvStepHostIos?; assert LIoOpSend(p) in ps.environment.nextStep.ios; idx, ios :| RslNextOneReplica(ps, ps', idx, ios) && LIoOpSend(p) in ios; } lemma lemma_ActionThatSendsAppStateSupplyIsProcessAppStateRequest( ps:RslState, ps':RslState, p:RslPacket ) returns ( idx:int, ios:seq ) requires p.src in ps.constants.config.replica_ids requires p.msg.RslMessage_AppStateSupply? requires p in ps'.environment.sentPackets requires p !in ps.environment.sentPackets requires RslNext(ps, ps') ensures 0 <= idx < |ps.constants.config.replica_ids| ensures 0 <= idx < |ps'.constants.config.replica_ids| ensures p.src == ps.constants.config.replica_ids[idx] ensures RslNextOneReplica(ps, ps', idx, ios) ensures |ios| > 0 ensures ios[0].LIoOpReceive? ensures ios[0].r.msg.RslMessage_AppStateRequest? ensures LIoOpSend(p) in ios ensures LReplicaNextProcessPacketWithoutReadingClock(ps.replicas[idx].replica, ps'.replicas[idx].replica, ios) ensures LExecutorProcessAppStateRequest(ps.replicas[idx].replica.executor, ps'.replicas[idx].replica.executor, ios[0].r, [p]) { assert ps.environment.nextStep.LEnvStepHostIos?; assert LIoOpSend(p) in ps.environment.nextStep.ios; idx, ios :| RslNextOneReplica(ps, ps', idx, ios) && LIoOpSend(p) in ios; } lemma lemma_ActionThatSendsStartingPhase2IsMaybeEnterPhase2( ps:RslState, ps':RslState, p:RslPacket ) returns ( idx:int, ios:seq ) requires p.src in ps.constants.config.replica_ids requires p.msg.RslMessage_StartingPhase2? requires p in ps'.environment.sentPackets requires p !in ps.environment.sentPackets requires RslNext(ps, ps') ensures 0 <= idx < |ps.constants.config.replica_ids| ensures 0 <= idx < |ps'.constants.config.replica_ids| ensures p.src == ps.constants.config.replica_ids[idx] ensures RslNextOneReplica(ps, ps', idx, ios) ensures LIoOpSend(p) in ios ensures LReplicaNextSpontaneousMaybeEnterPhase2(ps.replicas[idx].replica, ps'.replicas[idx].replica, ExtractSentPacketsFromIos(ios)) { assert ps.environment.nextStep.LEnvStepHostIos?; assert LIoOpSend(p) in ps.environment.nextStep.ios; idx, ios :| RslNextOneReplica(ps, ps', idx, ios) && LIoOpSend(p) in ios; var nextActionIndex := ps.replicas[idx].nextActionIndex; if nextActionIndex != 2 { assert false; } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/CommonProof/Quorum.i.dfy ================================================ include "../Constants.i.dfy" include "../Environment.i.dfy" module CommonProof__Quorum_i { import opened LiveRSL__Constants_i import opened LiveRSL__Configuration_i import opened LiveRSL__Environment_i import opened Concrete_NodeIdentity_i import opened Collections__Sets_i lemma lemma_SetOfElementsOfRangeNoBiggerThanRange(Q:set, n:int) requires forall idx :: idx in Q ==> 0 <= idx < n requires 0 <= n ensures |Q| <= n decreases n { if n == 0 { forall idx | idx in Q ensures false { } assert Q == {}; } else if n-1 in Q { lemma_SetOfElementsOfRangeNoBiggerThanRange(Q - {n-1}, n-1); } else { lemma_SetOfElementsOfRangeNoBiggerThanRange(Q, n-1); } } lemma lemma_QuorumIndexOverlap(Q1:set, Q2:set, n:int) returns (common:int) requires forall idx :: idx in Q1 ==> 0 <= idx < n requires forall idx :: idx in Q2 ==> 0 <= idx < n requires |Q1| + |Q2| > n >= 0 ensures common in Q1 ensures common in Q2 ensures 0 <= common < n { if Q1 * Q2 == {} { lemma_SetOfElementsOfRangeNoBiggerThanRange(Q1 + Q2, n); assert false; } common :| common in Q1*Q2; } lemma lemma_GetIndicesFromNodes(nodes:set, config:LConfiguration) returns (indices:set) requires WellFormedLConfiguration(config) requires forall node :: node in nodes ==> node in config.replica_ids ensures forall idx :: idx in indices ==> 0 <= idx < |config.replica_ids| && config.replica_ids[idx] in nodes ensures forall node :: node in nodes ==> GetReplicaIndex(node, config) in indices ensures |indices| == |nodes| { indices := set idx | 0 <= idx < |config.replica_ids| && config.replica_ids[idx] in nodes; // var f := (idx requires 0 <= idx < |config.replica_ids| => config.replica_ids[idx]); var f := (idx => if (idx >= 0 && idx < |config.replica_ids|) then config.replica_ids[idx] else var end:NodeIdentity :| (true);end ); forall idx1, idx2 | idx1 in indices && idx2 in indices && f(idx1) in nodes && f(idx2) in nodes && f(idx1) == f(idx2) ensures idx1 == idx2 { assert ReplicasDistinct(config.replica_ids, idx1, idx2); } forall node | node in nodes ensures exists idx :: idx in indices && node == f(idx) { var idx := GetReplicaIndex(node, config); assert idx in indices && node == f(idx); } lemma_MapSetCardinalityOver(indices, nodes, f); } lemma lemma_GetIndicesFromPackets(packets:set, config:LConfiguration) returns (indices:set) requires WellFormedLConfiguration(config) requires forall p :: p in packets ==> p.src in config.replica_ids requires forall p1, p2 :: p1 in packets && p2 in packets && p1 != p2 ==> p1.src != p2.src ensures forall idx :: idx in indices ==> 0 <= idx < |config.replica_ids| && exists p :: (p in packets && config.replica_ids[idx] == p.src) ensures forall p :: p in packets ==> GetReplicaIndex(p.src, config) in indices ensures |indices| == |packets| { var nodes := set p | p in packets :: p.src; indices := lemma_GetIndicesFromNodes(nodes, config); lemma_MapSetCardinalityOver(packets, nodes, ((x:RslPacket)=>x.src)); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/CommonProof/Received1b.i.dfy ================================================ include "Assumptions.i.dfy" include "Actions.i.dfy" include "PacketSending.i.dfy" module CommonProof__Received1b_i { import opened LiveRSL__Constants_i import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Environment_i import opened CommonProof__Assumptions_i import opened CommonProof__Actions_i import opened CommonProof__Constants_i import opened CommonProof__PacketSending_i import opened Temporal__Temporal_s lemma lemma_PacketInReceived1bWasSent( b:Behavior, c:LConstants, i:int, replica_idx:int, p:RslPacket ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires 0 <= replica_idx < |b[i].replicas| requires p in b[i].replicas[replica_idx].replica.proposer.received_1b_packets ensures p in b[i].environment.sentPackets ensures p.src in c.config.replica_ids { if i == 0 { return; } lemma_ConstantsAllConsistent(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i); lemma_AssumptionsMakeValidTransition(b, c, i-1); var s := b[i-1].replicas[replica_idx].replica.proposer; var s' := b[i].replicas[replica_idx].replica.proposer; if p in s.received_1b_packets { lemma_PacketInReceived1bWasSent(b, c, i-1, replica_idx, p); assert p in b[i].environment.sentPackets; return; } var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, c, i-1, replica_idx); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/CommonProof/ReplyCache.i.dfy ================================================ include "../DistributedSystem.i.dfy" include "Assumptions.i.dfy" include "Actions.i.dfy" include "Constants.i.dfy" include "PacketSending.i.dfy" ///////////////////// // INVARIANTS ///////////////////// module CommonProof__ReplyCache_i { import opened LiveRSL__Constants_i import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Environment_i import opened LiveRSL__Message_i import opened LiveRSL__Replica_i import opened LiveRSL__Types_i import opened Concrete_NodeIdentity_i import opened CommonProof__Assumptions_i import opened CommonProof__Actions_i import opened CommonProof__Constants_i import opened CommonProof__PacketSending_i import opened Temporal__Temporal_s import opened Environment_s predicate ReplyCacheObjectInv(cache:ReplyCache, client:NodeIdentity) { client in cache ==> cache[client].Reply? && cache[client].client == client } predicate ReplyCacheStateInv(ps:RslState, client:NodeIdentity) { forall idx :: 0 <= idx < |ps.replicas| ==> ReplyCacheObjectInv(ps.replicas[idx].replica.executor.reply_cache, client) } lemma lemma_ReplyCacheStateInv( b:Behavior, c:LConstants, i:int, client:NodeIdentity ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i ensures ReplyCacheStateInv(b[i], client) { if i > 0 { lemma_ReplyCacheStateInv(b, c, i-1, client); lemma_ConstantsAllConsistent(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i); lemma_AssumptionsMakeValidTransition(b, c, i-1); var ps := b[i-1]; var ps' := b[i]; assert RslNext(ps, ps'); forall idx | 0 <= idx < |ps'.replicas| ensures ReplyCacheObjectInv(ps'.replicas[idx].replica.executor.reply_cache, client) { lemma_ReplicasSize(b, c, i-1); lemma_ReplicasSize(b, c, i); var s := ps.replicas[idx].replica; var s' := ps'.replicas[idx].replica; var cache := s.executor.reply_cache; var cache' := s'.executor.reply_cache; if cache' == cache { assert ReplyCacheObjectInv(cache', client); } else { var ios :| RslNextOneReplica(ps, ps', idx, ios); assert ReplyCacheObjectInv(cache', client); } } } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/CommonProof/Requests.i.dfy ================================================ include "../DistributedSystem.i.dfy" include "../CommonProof/Assumptions.i.dfy" include "../CommonProof/Constants.i.dfy" include "../CommonProof/Actions.i.dfy" include "../CommonProof/Environment.i.dfy" include "../CommonProof/PacketSending.i.dfy" include "../CommonProof/Chosen.i.dfy" module CommonProof__Requests_i { import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Election_i import opened LiveRSL__Types_i import opened CommonProof__Assumptions_i import opened CommonProof__Constants_i import opened CommonProof__Actions_i import opened CommonProof__Environment_i import opened CommonProof__PacketSending_i import opened CommonProof__Chosen_i lemma lemma_RemoveAllSatisfiedRequestsInSequenceProducesSubsequence(s':seq, s:seq, r:Request) requires s' == RemoveAllSatisfiedRequestsInSequence(s, r) ensures forall x :: x in s' ==> x in s decreases s, 1 { if |s| > 0 && !RequestsMatch(s[0], r) { lemma_RemoveAllSatisfiedRequestsInSequenceProducesSubsequence(RemoveAllSatisfiedRequestsInSequence(s[1..], r), s[1..], r); } } lemma lemma_RemoveExecutedRequestBatchProducesSubsequence(s':seq, s:seq, batch:RequestBatch) requires s' == RemoveExecutedRequestBatch(s, batch) ensures forall x :: x in s' ==> x in s decreases |batch| { if |batch| > 0 { var s'' := RemoveAllSatisfiedRequestsInSequence(s, batch[0]); lemma_RemoveAllSatisfiedRequestsInSequenceProducesSubsequence(s'', s, batch[0]); lemma_RemoveExecutedRequestBatchProducesSubsequence(s', s'', batch[1..]); } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/Configuration.i.dfy ================================================ include "Types.i.dfy" include "../../Common/Collections/Sets.i.dfy" include "../../Common/Collections/Seqs.i.dfy" module LiveRSL__Configuration_i { import opened LiveRSL__Types_i import opened Collections__Sets_i import opened Collections__Seqs_i import opened Concrete_NodeIdentity_i datatype LConfiguration = LConfiguration( clientIds:set, replica_ids:seq ) // Jay suggests using a less-general notion of quorum. function LMinQuorumSize(c:LConfiguration) : int { |c.replica_ids|/2+1 } predicate ReplicasDistinct(replica_ids:seq, i:int, j:int) { 0 <= i < |replica_ids| && 0 <= j < |replica_ids| && replica_ids[i] == replica_ids[j] ==> i == j } predicate WellFormedLConfiguration(c:LConfiguration) { && 0 < |c.replica_ids| && (forall i, j :: ReplicasDistinct(c.replica_ids, i, j)) } predicate IsReplicaIndex(idx:int, id:NodeIdentity, c:LConfiguration) { && 0 <= idx < |c.replica_ids| && c.replica_ids[idx] == id } function GetReplicaIndex(id:NodeIdentity, c:LConfiguration):int requires id in c.replica_ids ensures var idx := GetReplicaIndex(id, c); 0 <= idx < |c.replica_ids| && c.replica_ids[idx] == id { FindIndexInSeq(c.replica_ids, id) } lemma lemma_GetReplicaIndexIsUnique(c:LConfiguration, idx:int) requires WellFormedLConfiguration(c) requires 0 <= idx < |c.replica_ids| ensures GetReplicaIndex(c.replica_ids[idx], c) == idx { var j := GetReplicaIndex(c.replica_ids[idx], c); assert ReplicasDistinct(c.replica_ids, idx, j); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/Constants.i.dfy ================================================ include "Configuration.i.dfy" include "Parameters.i.dfy" module LiveRSL__Constants_i { import opened LiveRSL__Configuration_i import opened LiveRSL__Parameters_i datatype LConstants = LConstants( config:LConfiguration, params:LParameters ) datatype LReplicaConstants = LReplicaConstants( my_index:int, all:LConstants ) predicate LReplicaConstantsValid(c:LReplicaConstants) { 0 <= c.my_index < |c.all.config.replica_ids| } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/DistributedSystem.i.dfy ================================================ include "../../Common/Collections/Maps2.i.dfy" include "Constants.i.dfy" include "Environment.i.dfy" include "Replica.i.dfy" module LiveRSL__DistributedSystem_i { import opened Collections__Maps2_i import opened LiveRSL__Constants_i import opened LiveRSL__Environment_i import opened LiveRSL__Replica_i import opened LiveRSL__Message_i import opened LiveRSL__Configuration_i import opened LiveRSL__Parameters_i import opened Concrete_NodeIdentity_i import opened Environment_s datatype RslState = RslState( constants:LConstants, environment:LEnvironment, replicas:seq ) predicate RslMapsComplete(ps:RslState) { |ps.replicas| == |ps.constants.config.replica_ids| } predicate RslConstantsUnchanged(ps:RslState, ps':RslState) { && |ps'.replicas| == |ps.replicas| && ps'.constants == ps.constants } predicate RslInit(con:LConstants, ps:RslState) { && WellFormedLConfiguration(con.config) && WFLParameters(con.params) && ps.constants == con && LEnvironment_Init(ps.environment) && RslMapsComplete(ps) && (forall i :: 0 <= i < |con.config.replica_ids| ==> LSchedulerInit(ps.replicas[i], LReplicaConstants(i, con))) } predicate RslNextCommon(ps:RslState, ps':RslState) { && RslMapsComplete(ps) && RslConstantsUnchanged(ps, ps') && LEnvironment_Next(ps.environment, ps'.environment) } predicate RslNextOneReplica(ps:RslState, ps':RslState, idx:int, ios:seq) { && RslNextCommon(ps, ps') && 0 <= idx < |ps.constants.config.replica_ids| && LSchedulerNext(ps.replicas[idx], ps'.replicas[idx], ios) && ps.environment.nextStep == LEnvStepHostIos(ps.constants.config.replica_ids[idx], ios) && ps'.replicas == ps.replicas[idx := ps'.replicas[idx]] } predicate RslNextEnvironment(ps:RslState, ps':RslState) { && RslNextCommon(ps, ps') && !ps.environment.nextStep.LEnvStepHostIos? && ps'.replicas == ps.replicas } predicate RslNextOneExternal(ps:RslState, ps':RslState, eid:NodeIdentity, ios:seq) { && RslNextCommon(ps, ps') && eid !in ps.constants.config.replica_ids && ps.environment.nextStep == LEnvStepHostIos(eid, ios) && ps'.replicas == ps.replicas } predicate RslNext(ps:RslState, ps':RslState) { || (exists idx, ios :: RslNextOneReplica(ps, ps', idx, ios)) || (exists eid, ios :: RslNextOneExternal(ps, ps', eid, ios)) || RslNextEnvironment(ps, ps') } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/Election.i.dfy ================================================ include "Constants.i.dfy" include "Environment.i.dfy" include "Types.i.dfy" include "../../Common/Collections/Seqs.i.dfy" module LiveRSL__Election_i { import opened LiveRSL__Constants_i import opened LiveRSL__Environment_i import opened LiveRSL__Types_i import opened LiveRSL__Configuration_i import opened Collections__Seqs_i import opened Common__UpperBound_s ////////////////////// // ELECTION STATE ////////////////////// datatype ElectionState = ElectionState( constants:LReplicaConstants, // The replica constants, duplicated here for convenience current_view:Ballot, // The last view I think has won a leader election current_view_suspectors:set, // The set of indices of nodes who suspect current_view. When this constitutes // a quorum, I'll elect the next view. epoch_end_time:int, // When the next view-test epoch will end. epoch_length:int, // How long the current view-test epoch length is. When we enter a new view, // we double this. requests_received_this_epoch:seq, // The set of requests we've received this epoch but haven't executed this epoch yet // and didn't execute in the previous epoch. requests_received_prev_epochs:seq // The set of requests we received in the previous epoch but haven't executed in // the current epoch, the previous epoch, or the epoch before that. ) ////////////////////// // BALLOT MATH ////////////////////// function ComputeSuccessorView(b:Ballot, c:LConstants):Ballot { if b.proposer_id + 1 < |c.config.replica_ids| then Ballot(b.seqno, b.proposer_id + 1) else Ballot(b.seqno + 1, 0) } ////////////////////// // SEQUENCE MATH ////////////////////// function BoundRequestSequence(s:seq, lengthBound:UpperBound):seq { if lengthBound.UpperBoundFinite? && 0 <= lengthBound.n < |s| then s[..lengthBound.n] else s } ////////////////////// // REQUESTS ////////////////////// predicate RequestsMatch(r1:Request, r2:Request) { r1.Request? && r2.Request? && r1.client == r2.client && r1.seqno == r2.seqno } predicate RequestSatisfiedBy(r1:Request, r2:Request) { r1.Request? && r2.Request? && r1.client == r2.client && r1.seqno <= r2.seqno } function RemoveAllSatisfiedRequestsInSequence(s:seq, r:Request):seq { if |s| == 0 then [] else if RequestSatisfiedBy(s[0], r) then RemoveAllSatisfiedRequestsInSequence(s[1..], r) else [s[0]] + RemoveAllSatisfiedRequestsInSequence(s[1..], r) } ////////////////////// // INITIALIZATION ////////////////////// predicate ElectionStateInit( es:ElectionState, c:LReplicaConstants ) requires |c.all.config.replica_ids| > 0 { && es.constants == c && es.current_view == Ballot(1, 0) && es.current_view_suspectors == {} && es.epoch_end_time == 0 && es.epoch_length == c.all.params.baseline_view_timeout_period && es.requests_received_this_epoch == [] && es.requests_received_prev_epochs == [] } ////////////////////// // ACTIONS ////////////////////// predicate ElectionStateProcessHeartbeat( es:ElectionState, es':ElectionState, p:RslPacket, clock:int ) requires p.msg.RslMessage_Heartbeat? { if p.src !in es.constants.all.config.replica_ids then es' == es else var sender_index := GetReplicaIndex(p.src, es.constants.all.config); if p.msg.bal_heartbeat == es.current_view && p.msg.suspicious then es' == es.(current_view_suspectors := es.current_view_suspectors + {sender_index}) else if BalLt(es.current_view, p.msg.bal_heartbeat) then var new_epoch_length := UpperBoundedAddition(es.epoch_length, es.epoch_length, es.constants.all.params.max_integer_val); es' == es.(current_view := p.msg.bal_heartbeat, current_view_suspectors := (if p.msg.suspicious then {sender_index} else {}), epoch_length := new_epoch_length, epoch_end_time := UpperBoundedAddition(clock, new_epoch_length, es.constants.all.params.max_integer_val), requests_received_prev_epochs := BoundRequestSequence(es.requests_received_prev_epochs + es.requests_received_this_epoch, es.constants.all.params.max_integer_val), requests_received_this_epoch := []) else es' == es } predicate ElectionStateCheckForViewTimeout( es:ElectionState, es':ElectionState, clock:int ) { if clock < es.epoch_end_time then es' == es else if |es.requests_received_prev_epochs| == 0 then var new_epoch_length := es.constants.all.params.baseline_view_timeout_period; es' == es.(epoch_length := new_epoch_length, epoch_end_time := UpperBoundedAddition(clock, new_epoch_length, es.constants.all.params.max_integer_val), requests_received_prev_epochs := es.requests_received_this_epoch, requests_received_this_epoch := []) else es' == es.(current_view_suspectors := es.current_view_suspectors + {es.constants.my_index}, epoch_end_time := UpperBoundedAddition(clock, es.epoch_length, es.constants.all.params.max_integer_val), requests_received_prev_epochs := BoundRequestSequence(es.requests_received_prev_epochs + es.requests_received_this_epoch, es.constants.all.params.max_integer_val), requests_received_this_epoch := []) } predicate ElectionStateCheckForQuorumOfViewSuspicions( es:ElectionState, es':ElectionState, clock:int ) { if |es.current_view_suspectors| < LMinQuorumSize(es.constants.all.config) || !LtUpperBound(es.current_view.seqno, es.constants.all.params.max_integer_val) then es' == es else var new_epoch_length := UpperBoundedAddition(es.epoch_length, es.epoch_length, es.constants.all.params.max_integer_val); es' == es.(current_view := ComputeSuccessorView(es.current_view, es.constants.all), current_view_suspectors := {}, epoch_length := new_epoch_length, epoch_end_time := UpperBoundedAddition(clock, new_epoch_length, es.constants.all.params.max_integer_val), requests_received_prev_epochs := BoundRequestSequence(es.requests_received_prev_epochs + es.requests_received_this_epoch, es.constants.all.params.max_integer_val), requests_received_this_epoch := []) } predicate ElectionStateReflectReceivedRequest( es:ElectionState, es':ElectionState, req:Request ) { if exists earlier_req :: && (earlier_req in es.requests_received_prev_epochs || earlier_req in es.requests_received_this_epoch) && RequestsMatch(earlier_req, req) then es' == es else es' == es.(requests_received_this_epoch := BoundRequestSequence(es.requests_received_this_epoch + [req], es.constants.all.params.max_integer_val)) } function RemoveExecutedRequestBatch(reqs:seq, batch:RequestBatch):seq decreases |batch| { if |batch| == 0 then reqs else RemoveExecutedRequestBatch(RemoveAllSatisfiedRequestsInSequence(reqs, batch[0]), batch[1..]) } predicate ElectionStateReflectExecutedRequestBatch( es:ElectionState, es':ElectionState, batch:RequestBatch ) { es' == es.(requests_received_prev_epochs := RemoveExecutedRequestBatch(es.requests_received_prev_epochs, batch), requests_received_this_epoch := RemoveExecutedRequestBatch(es.requests_received_this_epoch, batch)) } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/Environment.i.dfy ================================================ include "Types.i.dfy" include "Message.i.dfy" include "../../Common/Framework/Environment.s.dfy" module LiveRSL__Environment_i { import opened LiveRSL__Types_i import opened LiveRSL__Message_i import opened Environment_s import opened Concrete_NodeIdentity_i type RslEnvironment = LEnvironment type RslPacket = LPacket type RslIo = LIoOp function ConcatenatePaxosIos(s:seq>) : seq { if |s| == 0 then [] else s[0] + ConcatenatePaxosIos(s[1..]) } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/Executor.i.dfy ================================================ include "Configuration.i.dfy" include "Environment.i.dfy" include "Types.i.dfy" include "Constants.i.dfy" include "../../Services/RSL/AppStateMachine.s.dfy" include "StateMachine.i.dfy" include "Broadcast.i.dfy" include "../../Common/Collections/Maps.i.dfy" module LiveRSL__Executor_i { import opened LiveRSL__Configuration_i import opened LiveRSL__Environment_i import opened LiveRSL__Types_i import opened LiveRSL__Constants_i import opened LiveRSL__Message_i import opened LiveRSL__StateMachine_i import opened LiveRSL__Broadcast_i import opened AppStateMachine_s import opened Collections__Maps_i import opened Concrete_NodeIdentity_i import opened Environment_s import opened Common__UpperBound_s datatype OutstandingOperation = OutstandingOpKnown(v:RequestBatch, bal:Ballot) | OutstandingOpUnknown() datatype LExecutor = LExecutor( constants:LReplicaConstants, app:AppState, ops_complete:int, max_bal_reflected:Ballot, next_op_to_execute:OutstandingOperation, reply_cache:ReplyCache ) predicate LExecutorInit(s:LExecutor, c:LReplicaConstants) { && s.constants == c && s.app == AppInitialize() && s.ops_complete == 0 && s.max_bal_reflected == Ballot(0, 0) && s.next_op_to_execute == OutstandingOpUnknown() && s.reply_cache == map[] } predicate LExecutorGetDecision(s:LExecutor, s':LExecutor, bal:Ballot, opn:OperationNumber, v:RequestBatch) requires opn == s.ops_complete requires s.next_op_to_execute.OutstandingOpUnknown? { s' == s.(next_op_to_execute := OutstandingOpKnown(v, bal)) } function GetPacketsFromReplies(me:NodeIdentity, requests:seq, replies:seq) : seq requires |requests| == |replies| requires forall r :: r in replies ==> r.Reply? ensures forall p :: p in GetPacketsFromReplies(me, requests, replies) ==> p.src == me && p.msg.RslMessage_Reply? { if |requests| == 0 then [] else [LPacket(requests[0].client, me, RslMessage_Reply(requests[0].seqno, replies[0].reply))] + GetPacketsFromReplies(me, requests[1..], replies[1..]) } lemma lemma_SizeOfGetPacketsFromReplies(me:NodeIdentity, requests:seq, replies:seq, packets:seq) requires |requests| == |replies| requires forall r :: r in replies ==> r.Reply? requires packets == GetPacketsFromReplies(me, requests, replies) ensures |packets| == |requests| decreases |requests| { if |requests| > 0 { lemma_SizeOfGetPacketsFromReplies(me, requests[1..], replies[1..], packets[1..]); } } lemma lemma_SpecificPacketInGetPacketsFromReplies(me:NodeIdentity, requests:seq, replies:seq, packets:seq, batch_idx:int) requires |requests| == |replies| requires forall r :: r in replies ==> r.Reply? requires 0 <= batch_idx < |requests| requires packets == GetPacketsFromReplies(me, requests, replies) ensures |packets| == |requests| ensures packets[batch_idx] == LPacket(requests[batch_idx].client, me, RslMessage_Reply(requests[batch_idx].seqno, replies[batch_idx].reply)) decreases |requests| { lemma_SizeOfGetPacketsFromReplies(me, requests, replies, packets); if |requests| > 0 { if batch_idx > 0 { lemma_SpecificPacketInGetPacketsFromReplies(me, requests[1..], replies[1..], packets[1..], batch_idx-1); } } } predicate LExecutorExecute(s:LExecutor, s':LExecutor, sent_packets:seq) requires s.next_op_to_execute.OutstandingOpKnown? requires LtUpperBound(s.ops_complete, s.constants.all.params.max_integer_val) requires LReplicaConstantsValid(s.constants) { var batch := s.next_op_to_execute.v; var temp := HandleRequestBatch(s.app, batch); var new_state := temp.0[|temp.0|-1]; var replies := temp.1; && s'.constants == s.constants && s'.app == new_state && s'.ops_complete == s.ops_complete + 1 && s'.max_bal_reflected == (if BalLeq(s.max_bal_reflected, s.next_op_to_execute.bal) then s.next_op_to_execute.bal else s.max_bal_reflected) && s'.next_op_to_execute == OutstandingOpUnknown() && (forall client :: client in s'.reply_cache ==> (|| (client in s.reply_cache && s'.reply_cache[client] == s.reply_cache[client]) || (exists req_idx :: && 0 <= req_idx < |batch| && replies[req_idx].client == client && s'.reply_cache[client] == replies[req_idx]))) && sent_packets == GetPacketsFromReplies(s.constants.all.config.replica_ids[s.constants.my_index], batch, replies) } predicate LExecutorProcessAppStateSupply(s:LExecutor, s':LExecutor, inp:RslPacket) requires inp.msg.RslMessage_AppStateSupply? requires inp.src in s.constants.all.config.replica_ids && inp.msg.opn_state_supply > s.ops_complete { var m := inp.msg; s' == s.(app := m.app_state, ops_complete := m.opn_state_supply, max_bal_reflected := m.bal_state_supply, next_op_to_execute := OutstandingOpUnknown()) } predicate LExecutorProcessAppStateRequest(s:LExecutor, s':LExecutor, inp:RslPacket, sent_packets:seq) requires inp.msg.RslMessage_AppStateRequest? { var m := inp.msg; if && inp.src in s.constants.all.config.replica_ids && BalLeq(s.max_bal_reflected, m.bal_state_req) && s.ops_complete >= m.opn_state_req && LReplicaConstantsValid(s.constants) then && s' == s && sent_packets == [ LPacket(inp.src, s.constants.all.config.replica_ids[s.constants.my_index], RslMessage_AppStateSupply(s.max_bal_reflected, s.ops_complete, s.app)) ] else s' == s && sent_packets == [] } predicate LExecutorProcessStartingPhase2(s:LExecutor, s':LExecutor, inp:RslPacket, sent_packets:seq) requires inp.msg.RslMessage_StartingPhase2? { if inp.src in s.constants.all.config.replica_ids && inp.msg.logTruncationPoint_2 > s.ops_complete then s' == s && LBroadcastToEveryone(s.constants.all.config, s.constants.my_index, RslMessage_AppStateRequest(inp.msg.bal_2, inp.msg.logTruncationPoint_2), sent_packets) else s' == s && sent_packets == [] } predicate LExecutorProcessRequest(s:LExecutor, inp:RslPacket, sent_packets:seq) requires inp.msg.RslMessage_Request? requires inp.src in s.reply_cache requires s.reply_cache[inp.src].Reply? requires inp.msg.seqno_req <= s.reply_cache[inp.src].seqno { if LReplicaConstantsValid(s.constants) then var r := s.reply_cache[inp.src]; sent_packets == [ LPacket(r.client, s.constants.all.config.replica_ids[s.constants.my_index], RslMessage_Reply(r.seqno, r.reply)) ] else sent_packets == [] } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/Learner.i.dfy ================================================ include "Configuration.i.dfy" include "Environment.i.dfy" include "Types.i.dfy" include "Constants.i.dfy" include "Executor.i.dfy" include "../../Common/Collections/Maps.i.dfy" module LiveRSL__Learner_i { import opened LiveRSL__Configuration_i import opened LiveRSL__Environment_i import opened LiveRSL__Types_i import opened LiveRSL__Constants_i import opened LiveRSL__Executor_i import opened Collections__Maps_i datatype LLearner = LLearner( constants:LReplicaConstants, max_ballot_seen:Ballot, unexecuted_learner_state:LearnerState ) predicate LLearnerInit(l:LLearner, c:LReplicaConstants) { && l.constants == c && l.max_ballot_seen == Ballot(0,0) && l.unexecuted_learner_state == map[] } predicate LLearnerProcess2b(s:LLearner, s':LLearner, packet:RslPacket) requires packet.msg.RslMessage_2b? { var m := packet.msg; var opn := m.opn_2b; if packet.src !in s.constants.all.config.replica_ids || BalLt(m.bal_2b, s.max_ballot_seen) then s' == s else if BalLt(s.max_ballot_seen, m.bal_2b) then var tup' := LearnerTuple({packet.src}, m.val_2b); s' == s.(max_ballot_seen := m.bal_2b, unexecuted_learner_state := map[opn := tup']) else if opn !in s.unexecuted_learner_state then var tup' := LearnerTuple({packet.src}, m.val_2b); s' == s.(unexecuted_learner_state := s.unexecuted_learner_state[opn := tup']) else if packet.src in s.unexecuted_learner_state[opn].received_2b_message_senders then s' == s else var tup := s.unexecuted_learner_state[opn]; var tup' := tup.(received_2b_message_senders := tup.received_2b_message_senders + {packet.src}); s' == s.(unexecuted_learner_state := s.unexecuted_learner_state[opn := tup']) } predicate LLearnerForgetDecision(s:LLearner, s':LLearner, opn:OperationNumber) { if opn in s.unexecuted_learner_state then s' == s.(unexecuted_learner_state := RemoveElt(s.unexecuted_learner_state, opn)) else s' == s } predicate LLearnerForgetOperationsBefore(s:LLearner, s':LLearner, ops_complete:OperationNumber) { s' == s.(unexecuted_learner_state := (map op | op in s.unexecuted_learner_state && op >= ops_complete :: s.unexecuted_learner_state[op])) } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/LivenessProof/Assumptions.i.dfy ================================================ include "../DistributedSystem.i.dfy" include "../CommonProof/Assumptions.i.dfy" include "../../../Common/Framework/EnvironmentSynchrony.s.dfy" module LivenessProof__Assumptions_i { import opened LiveRSL__Configuration_i import opened LiveRSL__Constants_i import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Message_i import opened LiveRSL__Parameters_i import opened LiveRSL__Replica_i import opened LiveRSL__Types_i import opened CommonProof__Assumptions_i import opened EnvironmentSynchrony_s import opened Temporal__Temporal_s import opened Temporal__Time_s import opened Concrete_NodeIdentity_i import opened Collections__Maps2_s import opened AppStateMachine_s import opened Environment_s import opened Common__UpperBound_s /////////////////////// // TYPES /////////////////////// datatype AssumptionParameters = AssumptionParameters( c:LConstants, live_quorum:set, synchrony_start:int, latency_bound:int, host_period:int, burst_size:int, persistent_request:Request, persistent_period:int, max_clock_ambiguity:int ) /////////////////////// // HELPERS /////////////////////// function SetOfReplicaIndicesToSetOfHosts(s:set, ids:seq):set { set idx | idx in s && 0 <= idx < |ids| :: ids[idx] } predicate RslSchedulerActionOccursForReplica( ps:RslState, ps':RslState, replica_index:int ) { exists ios {:trigger RslNextOneReplica(ps, ps', replica_index, ios)} {:trigger LSchedulerNext(ps.replicas[replica_index], ps'.replicas[replica_index], ios) } :: && RslNextOneReplica(ps, ps', replica_index, ios) && LSchedulerNext(ps.replicas[replica_index], ps'.replicas[replica_index], ios) } function{:opaque} MakeRslActionTemporalFromSchedulerFunction( b:Behavior, replica_index:int ):temporal requires imaptotal(b) ensures forall i {:trigger sat(i, MakeRslActionTemporalFromSchedulerFunction(b, replica_index))} :: sat(i, MakeRslActionTemporalFromSchedulerFunction(b, replica_index)) <==> RslSchedulerActionOccursForReplica(b[i], b[nextstep(i)], replica_index) { stepmap(imap i :: RslSchedulerActionOccursForReplica(b[i], b[nextstep(i)], replica_index)) } function{:opaque} PaxosTimeMap(b:Behavior):imap requires imaptotal(b) ensures imaptotal(PaxosTimeMap(b)) ensures forall i {:trigger PaxosTimeMap(b)[i]} :: PaxosTimeMap(b)[i] == b[i].environment.time { imap i :: b[i].environment.time } predicate ClientSendsRequestToReplica(ps:RslState, request:Request, replica:NodeIdentity) requires request.Request? { && ps.environment.nextStep.LEnvStepHostIos? && ps.environment.nextStep.actor == request.client && LIoOpSend(LPacket(replica, request.client, RslMessage_Request(request.seqno, request.request))) in ps.environment.nextStep.ios } function{:opaque} ClientSendsRequestToReplicaTemporal( b:Behavior, request:Request, replica:NodeIdentity ):temporal requires imaptotal(b) requires request.Request? ensures forall i {:trigger sat(i, ClientSendsRequestToReplicaTemporal(b, request, replica))} :: sat(i, ClientSendsRequestToReplicaTemporal(b, request, replica)) <==> ClientSendsRequestToReplica(b[i], request, replica) { stepmap(imap i :: ClientSendsRequestToReplica(b[i], request, replica)) } predicate ClientNeverSentHigherSequenceNumberRequest(ps:RslState, request:Request) requires request.Request? { forall p :: p in ps.environment.sentPackets && p.src == request.client && p.msg.RslMessage_Request? ==> p.msg.seqno_req < request.seqno || (p.msg.seqno_req == request.seqno && p.msg.val == request.request) } function{:opaque} ClientNeverSentHigherSequenceNumberRequestTemporal( b:Behavior, asp:AssumptionParameters ):temporal requires imaptotal(b) requires asp.persistent_request.Request? ensures forall i {:trigger sat(i, ClientNeverSentHigherSequenceNumberRequestTemporal(b, asp))} :: sat(i, ClientNeverSentHigherSequenceNumberRequestTemporal(b, asp)) <==> ClientNeverSentHigherSequenceNumberRequest(b[i], asp.persistent_request) { stepmap(imap i :: ClientNeverSentHigherSequenceNumberRequest(b[i], asp.persistent_request)) } /////////////////////// // ASSUMPTIONS /////////////////////// predicate HostExecutesPeriodically( b:Behavior, asp:AssumptionParameters, replica_index:int ) requires imaptotal(b) { var scheduler_action := MakeRslActionTemporalFromSchedulerFunction(b, replica_index); sat(asp.synchrony_start, always(eventuallynextwithin(scheduler_action, asp.host_period, PaxosTimeMap(b)))) } predicate PersistentClientSendsRequestPeriodically( b:Behavior, asp:AssumptionParameters, replica_index:int ) requires imaptotal(b) requires asp.persistent_request.Request? requires 0 <= replica_index < |asp.c.config.replica_ids| { var client_send := ClientSendsRequestToReplicaTemporal(b, asp.persistent_request, asp.c.config.replica_ids[replica_index]); sat(asp.synchrony_start, always(eventuallynextwithin(client_send, asp.persistent_period, PaxosTimeMap(b)))) } predicate ReplyDeliveredDuringStep(ps:RslState, req:Request) { && req.Request? && ps.environment.nextStep.LEnvStepDeliverPacket? && var p := ps.environment.nextStep.p; && p.src in ps.constants.config.replica_ids && p.dst == req.client && p.msg.RslMessage_Reply? && p.msg.seqno_reply == req.seqno } function{:opaque} ReplyDeliveredTemporal(b:Behavior, req:Request):temporal requires imaptotal(b) ensures forall i {:trigger sat(i, ReplyDeliveredTemporal(b, req))} :: sat(i, ReplyDeliveredTemporal(b, req)) <==> ReplyDeliveredDuringStep(b[i], req) { stepmap(imap i :: ReplyDeliveredDuringStep(b[i], req)) } predicate OverflowProtectionNotUsedForReplica(ps:RslState, replica_index:int, params:LParameters, max_clock_ambiguity:int) requires 0 <= replica_index < |ps.replicas| { var s := ps.replicas[replica_index].replica; && LtUpperBound(s.proposer.election_state.current_view.seqno, params.max_integer_val) && LeqUpperBound(ps.environment.time + max_clock_ambiguity + s.proposer.election_state.epoch_length, params.max_integer_val) && LeqUpperBound(s.proposer.election_state.epoch_length + s.proposer.election_state.epoch_length, params.max_integer_val) && LeqUpperBound(s.acceptor.log_truncation_point + params.max_log_length, params.max_integer_val) && LtUpperBound(s.proposer.next_operation_number_to_propose, params.max_integer_val) && LtUpperBound(s.executor.ops_complete, params.max_integer_val) && LeqUpperBound(|s.proposer.election_state.requests_received_prev_epochs + s.proposer.election_state.requests_received_this_epoch|, params.max_integer_val) && LtUpperBound(|s.proposer.election_state.requests_received_this_epoch|, params.max_integer_val) } predicate OverflowProtectionNotUsed(ps:RslState, params:LParameters, max_clock_ambiguity:int) { forall replica_index :: 0 <= replica_index < |ps.replicas| ==> OverflowProtectionNotUsedForReplica(ps, replica_index, params, max_clock_ambiguity) } function{:opaque} OverflowProtectionNotUsedTemporal(b:Behavior, params:LParameters, max_clock_ambiguity:int):temporal requires imaptotal(b) ensures forall i {:trigger sat(i, OverflowProtectionNotUsedTemporal(b, params, max_clock_ambiguity))} :: sat(i, OverflowProtectionNotUsedTemporal(b, params, max_clock_ambiguity)) <==> OverflowProtectionNotUsed(b[i], params, max_clock_ambiguity) { stepmap(imap i :: OverflowProtectionNotUsed(b[i], params, max_clock_ambiguity)) } /////////////////////////// // TOP-LEVEL ASSUMPTIONS /////////////////////////// predicate LivenessAssumptions( b:Behavior, asp:AssumptionParameters ) { && IsValidBehavior(b, asp.c) && var eb := RestrictBehaviorToEnvironment(b); var live_hosts := SetOfReplicaIndicesToSetOfHosts(asp.live_quorum, asp.c.config.replica_ids); && HostQueuesLive(eb) // The synchrony period start time is valid && 0 <= asp.synchrony_start // Time goes forward without Zeno behaviors && NoZenoBehavior(eb) // Live replicas have fairly accurate time sync && 0 <= asp.max_clock_ambiguity && ClockAmbiguityLimitedForHosts(eb, 0, asp.max_clock_ambiguity, live_hosts) // Overflow protection is never used && sat(0, always(OverflowProtectionNotUsedTemporal(b, asp.c.params, asp.max_clock_ambiguity))) // The live quorum is a set of replica indices and is big enough to constitute a quorum && (forall replica_index :: replica_index in asp.live_quorum ==> 0 <= replica_index < |asp.c.config.replica_ids|) && |asp.live_quorum| >= LMinQuorumSize(asp.c.config) // Each host in the live quorum executes periodically, with period asp.host_period && 0 < asp.host_period && (forall replica_index {:trigger HostExecutesPeriodically(b, asp, replica_index)} :: replica_index in asp.live_quorum ==> HostExecutesPeriodically(b, asp, replica_index)) // The request is valid && |asp.persistent_request.request| <= MaxAppRequestSize() // The persistent client sends its request periodically, with period asp.persistent_period && 0 < asp.persistent_period && asp.persistent_request.Request? && (forall replica_index {:trigger PersistentClientSendsRequestPeriodically(b, asp, replica_index)} :: replica_index in asp.live_quorum ==> PersistentClientSendsRequestPeriodically(b, asp, replica_index)) // and the persistent client never sends a request with a higher sequence number && sat(0, always(ClientNeverSentHigherSequenceNumberRequestTemporal(b, asp))) // ..but it never receives a reply. && sat(0, always(not(ReplyDeliveredTemporal(b, asp.persistent_request)))) // The network delivers packets among the client and live quorum within time asp.latency_bound && 0 < asp.latency_bound && NetworkSynchronousForHosts(eb, asp.synchrony_start, asp.latency_bound, live_hosts + {asp.persistent_request.client}, live_hosts + {asp.persistent_request.client}) // The network doesn't deliver packets to any host in the live quorum faster than it can process them && 0 < asp.burst_size && NetworkDeliveryRateBoundedForHosts(eb, asp.synchrony_start, asp.burst_size, asp.burst_size * asp.host_period * LReplicaNumActions() + 1, live_hosts) } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/LivenessProof/Catchup.i.dfy ================================================ include "Assumptions.i.dfy" include "Invariants.i.dfy" include "StablePeriod.i.dfy" include "PacketHandling.i.dfy" include "MaxBalReflected.i.dfy" include "Phase2Invariants.i.dfy" include "../CommonProof/LogTruncationPoint.i.dfy" include "../CommonProof/Actions.i.dfy" include "../../../Common/Logic/Temporal/Sets.i.dfy" module LivenessProof__Catchup_i { import opened LiveRSL__Broadcast_i import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Environment_i import opened LiveRSL__Message_i import opened LiveRSL__Replica_i import opened LiveRSL__Types_i import opened LivenessProof__Assumptions_i import opened LivenessProof__Invariants_i import opened LivenessProof__StablePeriod_i import opened LivenessProof__PacketHandling_i import opened LivenessProof__MaxBalReflected_i import opened LivenessProof__Phase2Invariants_i import opened CommonProof__Actions_i import opened CommonProof__Constants_i import opened CommonProof__LogTruncationPoint_i import opened Temporal__Rules_i import opened Temporal__Temporal_s import opened Temporal__Time_s import opened Temporal__Sets_i import opened Environment_s import opened Collections__Maps2_s lemma{:timeLimitMultiplier 2} lemma_EventuallySpecificLiveReplicaCaughtUp( b:Behavior, asp:AssumptionParameters, idx:int, h:Phase2Params ) returns ( step:int ) requires Phase2StableWithRequest(b, asp, h) requires idx in asp.live_quorum ensures h.start_step + 1 <= step ensures sat(step, beforeabsolutetime(or(ReplicaCaughtUpTemporal(b, idx, h.log_truncation_point), not(NoReplicaBeyondViewTemporal(b, h.view))), b[h.start_step+1].environment.time + h.processing_bound * 3, PaxosTimeMap(b))) { var f := PaxosTimeMap(b); var x := ReplicaCaughtUpTemporal(b, idx, h.log_truncation_point); var z := NoReplicaBeyondViewTemporal(b, h.view); var deadline := b[h.start_step+1].environment.time + h.processing_bound * 3; lemma_ConstantsAllConsistent(b, asp.c, h.start_step); var s1 := b[h.start_step].replicas[h.view.proposer_id].replica.proposer; assert s1.current_state == 1; assert LBroadcastToEveryone(b[h.start_step].constants.config, h.view.proposer_id, RslMessage_StartingPhase2(h.view, h.log_truncation_point), ExtractSentPacketsFromIos(h.ios)); var p := LPacket(asp.c.config.replica_ids[idx], asp.c.config.replica_ids[h.view.proposer_id], RslMessage_StartingPhase2(s1.max_ballot_i_sent_1a, h.log_truncation_point)); assert p in ExtractSentPacketsFromIos(h.ios); var first_step, ios2 := lemma_PacketSentToIndexProcessedByIt(b, asp, h.start_step, h.processing_bound, h.start_step, idx, p); lemma_ConstantsAllConsistent(b, asp.c, first_step); var s2 := b[first_step].replicas[idx].replica.executor; if s2.ops_complete >= h.log_truncation_point { step := first_step; assert sat(step, beforeabsolutetime(x, deadline, f)); return; } assert LBroadcastToEveryone(s2.constants.all.config, s2.constants.my_index, RslMessage_AppStateRequest(p.msg.bal_2, h.log_truncation_point), ExtractSentPacketsFromIos(ios2)); var p2 := LPacket(asp.c.config.replica_ids[h.king_idx], asp.c.config.replica_ids[idx], RslMessage_AppStateRequest(p.msg.bal_2, h.log_truncation_point)); assert p2 in ExtractSentPacketsFromIos(ios2); var second_step, ios3 := lemma_PacketSentToIndexProcessedByIt(b, asp, h.start_step, h.processing_bound, first_step, h.king_idx, p2); lemma_ConstantsAllConsistent(b, asp.c, second_step); var s3 := b[second_step].replicas[h.king_idx].replica.executor; lemma_OpsCompleteMonotonic(b, asp.c, h.start_step+1, second_step, h.king_idx); assert s3.ops_complete >= h.log_truncation_point; assert p.msg.bal_2 == h.view; if sat(second_step, not(NoReplicaBeyondViewTemporal(b, h.view))) { step := second_step; assert sat(step, beforeabsolutetime(not(z), deadline, f)); return; } lemma_MaxBalReflectedLeqCurrentView(b, asp, second_step, h.view, h.king_idx); assert BalLeq(s3.max_bal_reflected, h.view); var p3 := LPacket(asp.c.config.replica_ids[idx], asp.c.config.replica_ids[h.king_idx], RslMessage_AppStateSupply(s3.max_bal_reflected, s3.ops_complete, s3.app)); assert p3 in ExtractSentPacketsFromIos(ios3); var third_step, ios4 := lemma_PacketSentToIndexProcessedByIt(b, asp, h.start_step, h.processing_bound, second_step, idx, p3); lemma_ConstantsAllConsistent(b, asp.c, third_step); var s4' := b[third_step+1].replicas[idx].replica.executor; assert s4'.ops_complete >= h.log_truncation_point; step := third_step+1; } lemma lemma_ReplicaCaughtUpIsStable( b:Behavior, asp:AssumptionParameters, i:int, idx:int, opn:int ) requires LivenessAssumptions(b, asp) requires 0 <= i ensures sat(i, imply(ReplicaCaughtUpTemporal(b, idx, opn), always(ReplicaCaughtUpTemporal(b, idx, opn)))) { if sat(i, ReplicaCaughtUpTemporal(b, idx, opn)) { forall j | i <= j ensures sat(j, ReplicaCaughtUpTemporal(b, idx, opn)) { lemma_OpsCompleteMonotonic(b, asp.c, i, j, idx); } TemporalAlways(i, ReplicaCaughtUpTemporal(b, idx, opn)); } } lemma lemma_EventuallyAllLiveReplicasCaughtUp( b:Behavior, asp:AssumptionParameters, h:Phase2Params ) requires Phase2StableWithRequest(b, asp, h) ensures sat(h.start_step+1, eventuallywithin(or(always(andset(AllReplicasCaughtUpTemporalSet(b, asp.live_quorum, h.log_truncation_point))), not(NoReplicaBeyondViewTemporal(b, h.view))), h.processing_bound * 3, PaxosTimeMap(b))) { var xs := AllReplicasCaughtUpTemporalSet(b, asp.live_quorum, h.log_truncation_point); var y := not(NoReplicaBeyondViewTemporal(b, h.view)); var t := h.processing_bound * 3; var f := PaxosTimeMap(b); forall x | x in xs ensures sat(h.start_step + 1, eventuallywithin(or(always(x), y), t, f)) { var idx :| idx in asp.live_quorum && x == ReplicaCaughtUpTemporal(b, idx, h.log_truncation_point); var step := lemma_EventuallySpecificLiveReplicaCaughtUp(b, asp, idx, h); assert sat(step, or(x, y)); lemma_ReplicaCaughtUpIsStable(b, asp, step, idx, h.log_truncation_point); assert sat(step, or(always(x), y)); TemporalEventually(h.start_step+1, step, beforeabsolutetime(or(always(x), y), f[h.start_step+1] + t, f)); } Lemma_EventuallyAlwaysWithinEachOrAlternativeImpliesEventuallyAlwaysWithinAllOrAlternative(h.start_step + 1, xs, y, t, f); } lemma lemma_EventuallyAllLiveReplicasReadyForFirstOperation( b:Behavior, asp:AssumptionParameters, h:Phase2Params ) returns ( step:int ) requires Phase2StableWithRequest(b, asp, h) ensures h.start_step + 1 <= step ensures b[step].environment.time <= b[h.start_step + 1].environment.time + h.processing_bound * 3 ensures sat(step, or(AllLiveReplicasReadyForNextOperationTemporal(b, asp.live_quorum, h.view, h.log_truncation_point), not(NoReplicaBeyondViewTemporal(b, h.view)))) { var t := h.processing_bound * 3; var f := PaxosTimeMap(b); var xs := AllReplicasCaughtUpTemporalSet(b, asp.live_quorum, h.log_truncation_point); var y := AllLiveReplicasReadyForNextOperationTemporal(b, asp.live_quorum, h.view, h.log_truncation_point); var z := NoReplicaBeyondViewTemporal(b, h.view); lemma_EventuallyAllLiveReplicasCaughtUp(b, asp, h); step := TemporalDeduceFromEventual(h.start_step + 1, beforeabsolutetime(or(always(andset(xs)), not(NoReplicaBeyondViewTemporal(b, h.view))), f[h.start_step + 1] + t, f)); lemma_ConstantsAllConsistent(b, asp.c, step); if sat(step, z) { forall idx | idx in asp.live_quorum ensures ReplicaCaughtUp(b[step], idx, h.log_truncation_point) { var x := ReplicaCaughtUpTemporal(b, idx, h.log_truncation_point); assert x in xs; assert sat(step, or(always(andset(xs)), not(z))); assert sat(step, always(andset(xs))); TemporalDeduceFromAlways(step, step, andset(xs)); assert sat(step, x); } var s := b[step].replicas[h.view.proposer_id].replica; lemma_LogTruncationPointMonotonic(b, asp.c, h.start_step + 1, step, h.view.proposer_id); assert s.acceptor.log_truncation_point >= h.log_truncation_point; lemma_NextOperationNumberToProposeIncreasesInPhase2(b, asp, h, h.start_step + 1, step); assert s.proposer.next_operation_number_to_propose >= h.log_truncation_point; assert sat(step, y); } assert sat(step, or(y, not(z))); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/LivenessProof/Environment.i.dfy ================================================ include "Assumptions.i.dfy" include "Invariants.i.dfy" include "../CommonProof/Constants.i.dfy" include "../CommonProof/Environment.i.dfy" include "../../../Common/Logic/Temporal/Heuristics.i.dfy" include "../../../Common/Logic/Temporal/Induction.i.dfy" include "../../../Common/Logic/Temporal/Rules.i.dfy" include "../../../Common/Logic/Temporal/Time.i.dfy" module LivenessProof__Environment_i { import opened LiveRSL__Constants_i import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Environment_i import opened LivenessProof__Assumptions_i import opened LivenessProof__Invariants_i import opened CommonProof__Assumptions_i import opened CommonProof__Constants_i import opened CommonProof__Environment_i import opened Temporal__Temporal_s import opened Temporal__Heuristics_i import opened Temporal__Induction_i import opened Temporal__Rules_i import opened Temporal__Time_s import opened Temporal__Time_i import opened Environment_s import opened EnvironmentSynchrony_s lemma lemma_AssumptionsMakeValidEnvironmentBehavior( b:Behavior, c:LConstants ) requires IsValidBehavior(b, c) ensures LEnvironment_BehaviorSatisfiesSpec(RestrictBehaviorToEnvironment(b)) { var eb := RestrictBehaviorToEnvironment(b); var x := EnvironmentNextTemporal(eb); forall i | i >= 0 ensures sat(i, x) { assert RslNext(b[i], b[i+1]); assert LEnvironment_Next(eb[i], eb[i+1]); } TemporalAlways(0, x); assert LEnvironment_Init(eb[0]); assert LEnvironment_BehaviorSatisfiesSpec(eb); } lemma lemma_ClockAmbiguityLimitApplies( b:Behavior, asp:AssumptionParameters, i:int, idx:int, io:RslIo ) requires LivenessAssumptions(b, asp) requires 0 <= i requires idx in asp.live_quorum requires 0 <= idx < |asp.c.config.replica_ids| requires b[i].environment.nextStep.LEnvStepHostIos? requires b[i].environment.nextStep.actor == asp.c.config.replica_ids[idx] requires io in b[i].environment.nextStep.ios requires io.LIoOpReadClock? ensures b[i].environment.time - asp.max_clock_ambiguity <= io.t <= b[i].environment.time + asp.max_clock_ambiguity ensures b[i].environment.time == b[i+1].environment.time { var live_hosts := SetOfReplicaIndicesToSetOfHosts(asp.live_quorum, asp.c.config.replica_ids); TemporalDeduceFromAlways(0, i, ClockAmbiguityLimitedForHostsTemporal(RestrictBehaviorToEnvironment(b), asp.max_clock_ambiguity, live_hosts)); lemma_AssumptionsMakeValidTransition(b, asp.c, i); lemma_ConstantsAllConsistent(b, asp.c, i); } lemma lemma_PacketSentAppearsInSentPackets( b:Behavior, c:LConstants, send_step:int, p:RslPacket ) requires IsValidBehavior(b, c) requires b[send_step].environment.nextStep.LEnvStepHostIos? requires LIoOpSend(p) in b[send_step].environment.nextStep.ios requires send_step >= 0 ensures p in b[send_step + 1].environment.sentPackets { assert RslNext(b[send_step], b[send_step + 1]); } lemma lemma_PacketSentAppearsInSentPacketsEnvironment( b:Behavior>, send_step:int, p:LPacket ) requires LEnvironment_BehaviorSatisfiesSpec(b) requires b[send_step].nextStep.LEnvStepHostIos? requires LIoOpSend(p) in b[send_step].nextStep.ios requires send_step >= 0 ensures p in b[send_step + 1].sentPackets { TemporalDeduceFromAlways(0, send_step, EnvironmentNextTemporal(b)); } lemma lemma_PacketSentEventuallyDelivered( b:Behavior, asp:AssumptionParameters, send_step:int, p:RslPacket ) returns ( delivery_step:int ) requires LivenessAssumptions(b, asp) requires asp.synchrony_start <= send_step requires var hosts := SetOfReplicaIndicesToSetOfHosts(asp.live_quorum, asp.c.config.replica_ids) + { asp.persistent_request.client }; PacketSentBetweenHosts(b[send_step].environment, p, hosts, hosts) ensures send_step <= delivery_step ensures b[delivery_step].environment.nextStep == LEnvStepDeliverPacket(p) ensures b[delivery_step+1].environment.time <= b[send_step+1].environment.time + asp.latency_bound { var eb := RestrictBehaviorToEnvironment(b); var hosts := SetOfReplicaIndicesToSetOfHosts(asp.live_quorum, asp.c.config.replica_ids) + { asp.persistent_request.client }; assert NetworkSynchronousForHosts(eb, asp.synchrony_start, asp.latency_bound, hosts, hosts); TemporalDeduceFromAlways(asp.synchrony_start, send_step, PacketsSynchronousForHostsTemporal(eb, asp.latency_bound, hosts, hosts)); assert PacketSentBetweenHosts(eb[send_step], p, hosts, hosts); // TRIGGER lemma_PacketSentAppearsInSentPackets(b, asp.c, send_step, p); assert p in eb[send_step + 1].sentPackets; assert sat(send_step, next(eventuallynextwithin(PacketDeliveredTemporal(eb, p), asp.latency_bound, BehaviorToTimeMap(eb)))); assert sat(send_step+1, eventuallynextwithin(PacketDeliveredTemporal(eb, p), asp.latency_bound, BehaviorToTimeMap(eb))); delivery_step := TemporalDeduceFromEventuallyNextWithin(send_step+1, PacketDeliveredTemporal(eb, p), asp.latency_bound, BehaviorToTimeMap(eb)); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/LivenessProof/EpochLength.i.dfy ================================================ include "../DistributedSystem.i.dfy" include "Assumptions.i.dfy" include "Invariants.i.dfy" include "RequestsReceived.i.dfy" include "ViewSuspicion.i.dfy" include "WF1.i.dfy" include "../CommonProof/Actions.i.dfy" module LivenessProof__EpochLength_i { import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Election_i import opened LiveRSL__Environment_i import opened LiveRSL__Types_i import opened LivenessProof__Assumptions_i import opened LivenessProof__Invariants_i import opened LivenessProof__PacketHandling_i import opened LivenessProof__RequestsReceived_i import opened LivenessProof__StablePeriod_i import opened LivenessProof__ViewAdvance_i import opened LivenessProof__ViewChange_i import opened LivenessProof__ViewPropagation_i import opened LivenessProof__ViewSuspicion_i import opened LivenessProof__WF1_i import opened CommonProof__Actions_i import opened CommonProof__Constants_i import opened Temporal__Temporal_s import opened Temporal__Rules_i import opened Temporal__WF1_i import opened Environment_s import opened Collections__Maps2_s predicate HostReadyToIncreaseEpochLength( ps:RslState, idx:int, epoch_length:int, epoch_end_time:int ) { && 0 <= idx < |ps.replicas| && var es := ps.replicas[idx].replica.proposer.election_state; && es.epoch_length == epoch_length && es.epoch_end_time == epoch_end_time } function{:opaque} HostReadyToIncreaseEpochLengthTemporal( b:Behavior, idx:int, epoch_length:int, epoch_end_time:int ):temporal requires imaptotal(b) ensures forall i {:trigger sat(i, HostReadyToIncreaseEpochLengthTemporal(b, idx, epoch_length, epoch_end_time))} :: sat(i, HostReadyToIncreaseEpochLengthTemporal(b, idx, epoch_length, epoch_end_time)) <==> HostReadyToIncreaseEpochLength(b[i], idx, epoch_length, epoch_end_time); { stepmap(imap i :: HostReadyToIncreaseEpochLength(b[i], idx, epoch_length, epoch_end_time)) } predicate EpochLengthEqualOrGreater(ps:RslState, idx:int, epoch_length:int) { && 0 <= idx < |ps.replicas| && ps.replicas[idx].replica.proposer.election_state.epoch_length >= epoch_length } function{:opaque} EpochLengthEqualOrGreaterTemporal(b:Behavior, idx:int, epoch_length:int):temporal requires imaptotal(b) ensures forall i{:trigger sat(i, EpochLengthEqualOrGreaterTemporal(b, idx, epoch_length))} :: sat(i, EpochLengthEqualOrGreaterTemporal(b, idx, epoch_length)) == EpochLengthEqualOrGreater(b[i], idx, epoch_length) { stepmap(imap i :: EpochLengthEqualOrGreater(b[i], idx, epoch_length)) } lemma lemma_EpochLengthAtLeastInitialValue( b:Behavior, asp:AssumptionParameters, i:int, idx:int ) requires LivenessAssumptions(b, asp) requires 0 <= idx < |asp.c.config.replica_ids| requires 0 <= i ensures EpochLengthEqualOrGreater(b[i], idx, asp.c.params.baseline_view_timeout_period) { lemma_ConstantsAllConsistent(b, asp.c, i); if i == 0 { assert EpochLengthEqualOrGreater(b[i], idx, asp.c.params.baseline_view_timeout_period); } else { lemma_EpochLengthAtLeastInitialValue(b, asp, i-1, idx); lemma_ConstantsAllConsistent(b, asp.c, i-1); lemma_AssumptionsMakeValidTransition(b, asp.c, i-1); assert EpochLengthEqualOrGreater(b[i-1], idx, asp.c.params.baseline_view_timeout_period); if !EpochLengthEqualOrGreater(b[i], idx, asp.c.params.baseline_view_timeout_period) { var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, i-1, idx); lemma_OverflowProtectionNotUsedForReplica(b, asp, i-1, idx); assert false; } } } lemma lemma_EpochLengthNeverDecreases( b:Behavior, asp:AssumptionParameters, idx:int, start_step:int, i:int, j:int ) requires LivenessAssumptions(b, asp) requires idx in asp.live_quorum requires sat(start_step, always(RequestInRequestsReceivedPrevEpochsTemporal(b, asp.persistent_request, idx))) requires 0 <= start_step <= i <= j ensures 0 <= idx < |b[i].replicas| ensures 0 <= idx < |b[j].replicas| ensures b[i].replicas[idx].replica.proposer.election_state.epoch_length <= b[j].replicas[idx].replica.proposer.election_state.epoch_length decreases j - i { lemma_ConstantsAllConsistent(b, asp.c, i); lemma_ConstantsAllConsistent(b, asp.c, j); if j == i + 1 { lemma_AssumptionsMakeValidTransition(b, asp.c, i); TemporalDeduceFromAlways(start_step, i, RequestInRequestsReceivedPrevEpochsTemporal(b, asp.persistent_request, idx)); lemma_OverflowProtectionNotUsedForReplica(b, asp, i, idx); // assert OverflowProtectionNotUsed(b[i], idx, b[i].replicas[idx].replica.proposer.election_state.constants.all.params); lemma_EpochLengthAtLeastInitialValue(b, asp, i, idx); if b[i].replicas[idx].replica.proposer.election_state.epoch_length > b[j].replicas[idx].replica.proposer.election_state.epoch_length { var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, i, idx); assert false; } } else if j > i + 1 { lemma_EpochLengthNeverDecreases(b, asp, idx, start_step, i, i+1); lemma_EpochLengthNeverDecreases(b, asp, idx, start_step, i+1, j); } } lemma lemma_EpochLengthEventuallyIncreasesWF1Req1( b:Behavior, asp:AssumptionParameters, i:int, idx:int, epoch_length:int ) requires LivenessAssumptions(b, asp) requires idx in asp.live_quorum requires sat(i, RequestInRequestsReceivedPrevEpochsTemporal(b, asp.persistent_request, idx)) requires 0 <= i ensures var P := EpochLengthEqualOrGreaterTemporal(b, idx, epoch_length); var Q := EpochLengthEqualOrGreaterTemporal(b, idx, epoch_length + 1); sat(i, TemporalWF1Req1(P, Q)) { var P := EpochLengthEqualOrGreaterTemporal(b, idx, epoch_length); var Q := EpochLengthEqualOrGreaterTemporal(b, idx, epoch_length + 1); if sat(i, P) && !sat(i, Q) && !sat(i+1, P) && !sat(i+1, Q) { lemma_ConstantsAllConsistent(b, asp.c, i); lemma_ConstantsAllConsistent(b, asp.c, i+1); var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, i, idx); lemma_OverflowProtectionNotUsedForReplica(b, asp, i, idx); lemma_EpochLengthAtLeastInitialValue(b, asp, i, idx); assert false; } } lemma lemma_EpochLengthEventuallyIncreases( b:Behavior, asp:AssumptionParameters, processing_sync_start:int, processing_bound:int, idx:int, start_step:int, i:int ) returns ( step:int ) requires LivenessAssumptions(b, asp) requires PacketProcessingSynchronous(b, asp, processing_sync_start, processing_bound) requires processing_sync_start <= start_step <= i requires idx in asp.live_quorum requires sat(start_step, always(RequestInRequestsReceivedPrevEpochsTemporal(b, asp.persistent_request, idx))) ensures i <= step ensures 0 <= idx < |b[i].replicas| ensures 0 <= idx < |b[step].replicas| ensures b[step].replicas[idx].replica.proposer.election_state.epoch_length > b[i].replicas[idx].replica.proposer.election_state.epoch_length { lemma_ConstantsAllConsistent(b, asp.c, i); lemma_OverflowProtectionNotUsedForReplica(b, asp, i, idx); lemma_IsValidBallot(b, asp, i, idx); var epoch_length := b[i].replicas[idx].replica.proposer.election_state.epoch_length; var current_view := b[i].replicas[idx].replica.proposer.election_state.current_view; var nextView := ComputeSuccessorView(current_view, asp.c); lemma_IfPacketProcessingSynchronousThenAlways(b, asp, processing_sync_start, i, processing_bound); var intermediate_step, replica_index := lemma_SomeReplicaInLiveQuorumReachesView(b, asp, i, processing_bound, nextView); var advance_step := lemma_OneLiveReplicaSoonAdvancesAnother(b, asp, processing_sync_start, processing_bound, intermediate_step, replica_index, idx); lemma_ConstantsAllConsistent(b, asp.c, advance_step); var x := not(HostInViewTemporal(b, idx, current_view)); var action_step := earliestStepBetween(i, advance_step, x) - 1; assert i <= action_step; lemma_ConstantsAllConsistent(b, asp.c, action_step); lemma_ConstantsAllConsistent(b, asp.c, action_step+1); assert !sat(action_step, x); var P := EpochLengthEqualOrGreaterTemporal(b, idx, epoch_length); var Q := EpochLengthEqualOrGreaterTemporal(b, idx, epoch_length + 1); forall j | i <= j ensures sat(j, TemporalWF1Req1(P, Q)) { TemporalDeduceFromAlways(start_step, j, RequestInRequestsReceivedPrevEpochsTemporal(b, asp.persistent_request, idx)); lemma_EpochLengthEventuallyIncreasesWF1Req1(b, asp, j, idx, epoch_length); } if !sat(action_step, imply(P, or(Q, next(Q)))) { assert sat(action_step, P) && !sat(action_step, Q) && !sat(action_step+1, Q); var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, action_step, idx); lemma_OverflowProtectionNotUsedForReplica(b, asp, action_step, idx); lemma_EpochLengthAtLeastInitialValue(b, asp, action_step, idx); assert false; } step := TemporalWF1Specific(i, action_step, P, Q); } lemma lemma_EpochLengthEventuallyReaches( b:Behavior, asp:AssumptionParameters, processing_sync_start:int, processing_bound:int, idx:int, start_step:int, epoch_length:int ) returns ( step:int ) requires LivenessAssumptions(b, asp) requires PacketProcessingSynchronous(b, asp, processing_sync_start, processing_bound) requires processing_sync_start <= start_step requires idx in asp.live_quorum requires sat(start_step, always(RequestInRequestsReceivedPrevEpochsTemporal(b, asp.persistent_request, idx))) ensures step >= start_step ensures 0 <= idx < |b[step].replicas| ensures b[step].replicas[idx].replica.proposer.election_state.epoch_length >= epoch_length decreases epoch_length { lemma_ConstantsAllConsistent(b, asp.c, start_step); if epoch_length <= asp.c.params.baseline_view_timeout_period { lemma_EpochLengthAtLeastInitialValue(b, asp, start_step, idx); step := start_step; } else { var almost_step := lemma_EpochLengthEventuallyReaches(b, asp, processing_sync_start, processing_bound, idx, start_step, epoch_length - 1); Lemma_AlwaysImpliesLaterAlways(start_step, almost_step, RequestInRequestsReceivedPrevEpochsTemporal(b, asp.persistent_request, idx)); step := lemma_EpochLengthEventuallyIncreases(b, asp, processing_sync_start, processing_bound, idx, start_step, almost_step); } } lemma lemma_EpochLengthForSomeEventuallyReaches( b:Behavior, asp:AssumptionParameters, processing_sync_start:int, processing_bound:int, start_step:int, replica_indices:set, epoch_length:int ) returns ( step:int ) requires LivenessAssumptions(b, asp) requires PacketProcessingSynchronous(b, asp, processing_sync_start, processing_bound) requires processing_sync_start <= start_step requires replica_indices <= asp.live_quorum requires forall idx :: idx in replica_indices ==> sat(start_step, always(RequestInRequestsReceivedPrevEpochsTemporal(b, asp.persistent_request, idx))) ensures start_step <= step; ensures forall idx :: idx in replica_indices ==> && 0 <= idx < |b[step].replicas| && b[step].replicas[idx].replica.proposer.election_state.epoch_length >= epoch_length { if |replica_indices| == 0 { step := start_step; } else { var some_index :| some_index in replica_indices; var other_indices := replica_indices - {some_index}; var almost_step := lemma_EpochLengthForSomeEventuallyReaches(b, asp, processing_sync_start, processing_bound, start_step, other_indices, epoch_length); Lemma_AlwaysImpliesLaterAlways(start_step, almost_step, RequestInRequestsReceivedPrevEpochsTemporal(b, asp.persistent_request, some_index)); step := lemma_EpochLengthEventuallyReaches(b, asp, processing_sync_start, processing_bound, some_index, almost_step, epoch_length); forall idx | idx in replica_indices ensures 0 <= idx < |b[step].replicas| ensures b[step].replicas[idx].replica.proposer.election_state.epoch_length >= epoch_length { lemma_ConstantsAllConsistent(b, asp.c, almost_step); lemma_ConstantsAllConsistent(b, asp.c, step); if idx != some_index { assert idx in other_indices; lemma_EpochLengthNeverDecreases(b, asp, idx, start_step, almost_step, step); } } } } lemma lemma_EpochLengthForAllEventuallyReaches( b:Behavior, asp:AssumptionParameters, processing_sync_start:int, processing_bound:int, epoch_length:int ) returns ( step:int ) requires LivenessAssumptions(b, asp) requires PacketProcessingSynchronous(b, asp, processing_sync_start, processing_bound) ensures processing_sync_start <= step ensures forall idx :: idx in asp.live_quorum ==> sat(step, always(RequestInRequestsReceivedPrevEpochsTemporal(b, asp.persistent_request, idx))) ensures forall idx :: idx in asp.live_quorum ==> sat(step, always(EpochLengthEqualOrGreaterTemporal(b, idx, epoch_length))) { var start_step := lemma_EventuallyForAllPersistentRequestAlwaysInRequestsReceivedPrevEpochs(b, asp, processing_sync_start, processing_bound); step := lemma_EpochLengthForSomeEventuallyReaches(b, asp, processing_sync_start, processing_bound, start_step, asp.live_quorum, epoch_length); forall idx | idx in asp.live_quorum ensures sat(step, always(RequestInRequestsReceivedPrevEpochsTemporal(b, asp.persistent_request, idx))) ensures sat(step, always(EpochLengthEqualOrGreaterTemporal(b, idx, epoch_length))) { Lemma_AlwaysImpliesLaterAlways(start_step, step, RequestInRequestsReceivedPrevEpochsTemporal(b, asp.persistent_request, idx)); forall i | step <= i ensures sat(i, EpochLengthEqualOrGreaterTemporal(b, idx, epoch_length)) { lemma_EpochLengthNeverDecreases(b, asp, idx, start_step, step, i); } TemporalAlways(step, EpochLengthEqualOrGreaterTemporal(b, idx, epoch_length)); } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/LivenessProof/Execution.i.dfy ================================================ include "../DistributedSystem.i.dfy" include "Assumptions.i.dfy" include "Invariants.i.dfy" include "Environment.i.dfy" include "../CommonProof/Actions.i.dfy" module LivenessProof__Execution_i { import opened LiveRSL__Constants_i import opened LiveRSL__Configuration_i import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Environment_i import opened LiveRSL__Executor_i import opened LiveRSL__Replica_i import opened LiveRSL__StateMachine_i import opened LivenessProof__Assumptions_i import opened LivenessProof__Invariants_i import opened LivenessProof__Environment_i import opened CommonProof__Actions_i import opened CommonProof__Constants_i import opened Concrete_NodeIdentity_i import opened Temporal__Temporal_s import opened Temporal__Rules_i import opened Environment_s import opened EnvironmentSynchrony_s import opened Collections__Maps2_s import opened Common__UpperBound_s predicate ReplySentToClientWithSeqno(ps:RslState, ps':RslState, client:NodeIdentity, seqno:int, idx:int, ios:seq, batch_idx:int) { && 0 <= idx < |ps.replicas| && 0 <= idx < |ps'.replicas| && var s := ps.replicas[idx].replica; var s' := ps'.replicas[idx].replica; && RslNextOneReplica(ps, ps', idx, ios) && LReplicaNextSpontaneousMaybeExecute(s, s', ExtractSentPacketsFromIos(ios)) && s.executor.next_op_to_execute.OutstandingOpKnown? && LtUpperBound(s.executor.ops_complete, s.executor.constants.all.params.max_integer_val) && LReplicaConstantsValid(s.executor.constants) && 0 <= batch_idx < |s.executor.next_op_to_execute.v| && s.executor.next_op_to_execute.v[batch_idx].Request? && s.executor.next_op_to_execute.v[batch_idx].client == client && s.executor.next_op_to_execute.v[batch_idx].seqno == seqno } predicate RequestWithSeqnoExecuted(ps:RslState, ps':RslState, client:NodeIdentity, seqno:int, idx:int) { exists ios, batch_idx :: ReplySentToClientWithSeqno(ps, ps', client, seqno, idx, ios, batch_idx) } function {:opaque} RequestWithSeqnoExecutedTemporal(b:Behavior, client:NodeIdentity, seqno:int, idx:int):temporal requires imaptotal(b) ensures forall i {:trigger sat(i, RequestWithSeqnoExecutedTemporal(b, client, seqno, idx))} :: sat(i, RequestWithSeqnoExecutedTemporal(b, client, seqno, idx)) <==> RequestWithSeqnoExecuted(b[i], b[nextstep(i)], client, seqno, idx) { stepmap(imap i :: RequestWithSeqnoExecuted(b[i], b[nextstep(i)], client, seqno, idx)) } predicate ReplySentToClientAtLeastSeqno(ps:RslState, ps':RslState, client:NodeIdentity, seqno:int, idx:int, ios:seq, batch_idx:int) { && 0 <= idx < |ps.replicas| && 0 <= idx < |ps'.replicas| && var s := ps.replicas[idx].replica; var s' := ps'.replicas[idx].replica; && RslNextOneReplica(ps, ps', idx, ios) && LReplicaNextSpontaneousMaybeExecute(s, s', ExtractSentPacketsFromIos(ios)) && s.executor.next_op_to_execute.OutstandingOpKnown? && LtUpperBound(s.executor.ops_complete, s.executor.constants.all.params.max_integer_val) && LReplicaConstantsValid(s.executor.constants) && 0 <= batch_idx < |s.executor.next_op_to_execute.v| && s.executor.next_op_to_execute.v[batch_idx].Request? && s.executor.next_op_to_execute.v[batch_idx].client == client && s.executor.next_op_to_execute.v[batch_idx].seqno >= seqno } predicate RequestAtLeastSeqnoExecuted(ps:RslState, ps':RslState, client:NodeIdentity, seqno:int, idx:int) { exists ios, batch_idx :: ReplySentToClientAtLeastSeqno(ps, ps', client, seqno, idx, ios, batch_idx) } function {:opaque} RequestAtLeastSeqnoExecutedTemporal(b:Behavior, client:NodeIdentity, seqno:int, idx:int):temporal requires imaptotal(b) ensures forall i {:trigger sat(i, RequestAtLeastSeqnoExecutedTemporal(b, client, seqno, idx))} :: sat(i, RequestAtLeastSeqnoExecutedTemporal(b, client, seqno, idx)) <==> RequestAtLeastSeqnoExecuted(b[i], b[nextstep(i)], client, seqno, idx) { stepmap(imap i :: RequestAtLeastSeqnoExecuted(b[i], b[nextstep(i)], client, seqno, idx)) } lemma lemma_PersistentRequestNeverExecuted( b:Behavior, asp:AssumptionParameters, idx:int ) requires LivenessAssumptions(b, asp) requires idx in asp.live_quorum ensures sat(asp.synchrony_start, always(not(RequestWithSeqnoExecutedTemporal(b, asp.persistent_request.client, asp.persistent_request.seqno, idx)))) { var client := asp.persistent_request.client; var seqno := asp.persistent_request.seqno; var t := RequestWithSeqnoExecutedTemporal(b, client, seqno, idx); forall i | asp.synchrony_start <= i ensures !sat(i, t) { if sat(i, t) { lemma_ConstantsAllConsistent(b, asp.c, i); var ps := b[i]; var ps' := b[i+1]; var s := ps.replicas[idx].replica.executor; var ios, batch_idx :| ReplySentToClientWithSeqno(ps, ps', client, seqno, idx, ios, batch_idx); var sent_packets := ExtractSentPacketsFromIos(ios); assert LExecutorExecute(ps.replicas[idx].replica.executor, ps'.replicas[idx].replica.executor, sent_packets); var batch := s.next_op_to_execute.v; var temp := HandleRequestBatch(s.app, batch); var new_state := temp.0[|temp.0|-1]; var replies := temp.1; var me := s.constants.all.config.replica_ids[s.constants.my_index]; lemma_SpecificPacketInGetPacketsFromReplies(me, batch, replies, sent_packets, batch_idx); var p := sent_packets[batch_idx]; assert LIoOpSend(p) in ios; var delivery_step := lemma_PacketSentEventuallyDelivered(b, asp, i, p); lemma_ConstantsAllConsistent(b, asp.c, delivery_step); assert ReplyDeliveredDuringStep(b[delivery_step], asp.persistent_request); TemporalDeduceFromAlways(0, delivery_step, not(ReplyDeliveredTemporal(b, asp.persistent_request))); assert false; } } TemporalAlways(asp.synchrony_start, not(t)); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/LivenessProof/GenericInvariants.i.dfy ================================================ include "Invariants.i.dfy" include "RealTime.i.dfy" include "../CommonProof/Actions.i.dfy" module LivenessProof__GenericInvariants_i { import opened LiveRSL__Constants_i import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Replica_i import opened LiveRSL__Environment_i import opened LiveRSL__Types_i import opened LivenessProof__Assumptions_i import opened LivenessProof__Environment_i import opened LivenessProof__Invariants_i import opened LivenessProof__RealTime_i import opened CommonProof__Actions_i import opened CommonProof__Assumptions_i import opened CommonProof__Constants_i import opened Temporal__Temporal_s import opened Environment_s import opened Collections__Maps2_s import opened Common__UpperBound_s lemma lemma_ProposerBatchTimerNeverTooFarInFuture( b:Behavior, asp:AssumptionParameters, i:int, idx:int ) requires LivenessAssumptions(b, asp) requires 0 <= i requires idx in asp.live_quorum ensures 0 <= idx < |b[i].replicas| ensures var s := b[i].replicas[idx].replica.proposer; s.incomplete_batch_timer.IncompleteBatchTimerOn? ==> s.incomplete_batch_timer.when <= b[i].environment.time + asp.max_clock_ambiguity + asp.c.params.max_batch_delay decreases i { lemma_ConstantsAllConsistent(b, asp.c, i); if i > 0 { lemma_ConstantsAllConsistent(b, asp.c, i-1); lemma_ConstantsAllConsistent(b, asp.c, i); var s := b[i-1].replicas[idx].replica.proposer; var s' := b[i].replicas[idx].replica.proposer; lemma_ProposerBatchTimerNeverTooFarInFuture(b, asp, i-1, idx); if s'.incomplete_batch_timer.IncompleteBatchTimerOn? { if s'.incomplete_batch_timer == s.incomplete_batch_timer { lemma_TimeAdvancesBetween(b, asp, i-1, i); } else { var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, i-1, idx); assert LReplicaNextReadClockMaybeNominateValueAndSend2a(b[i-1].replicas[idx].replica, b[i].replicas[idx].replica, SpontaneousClock(ios), ExtractSentPacketsFromIos(ios)); assert ios[0].LIoOpReadClock?; lemma_ClockAmbiguityLimitApplies(b, asp, i-1, idx, ios[0]); assert ios[0].t <= b[i].environment.time + asp.max_clock_ambiguity; assert s'.incomplete_batch_timer.when == UpperBoundedAddition(ios[0].t, asp.c.params.max_batch_delay, asp.c.params.max_integer_val); } } } } lemma lemma_HeartbeatTimerNeverTooFarInFuture( b:Behavior, asp:AssumptionParameters, i:int, idx:int ) requires LivenessAssumptions(b, asp) requires 0 <= i requires idx in asp.live_quorum ensures 0 <= idx < |b[i].replicas| ensures var s := b[i].replicas[idx].replica; s.nextHeartbeatTime <= b[i].environment.time + asp.max_clock_ambiguity + asp.c.params.heartbeat_period decreases i { lemma_ConstantsAllConsistent(b, asp.c, i); if i > 0 { lemma_ConstantsAllConsistent(b, asp.c, i-1); lemma_ConstantsAllConsistent(b, asp.c, i); var s := b[i-1].replicas[idx].replica; var s' := b[i].replicas[idx].replica; lemma_HeartbeatTimerNeverTooFarInFuture(b, asp, i-1, idx); if s'.nextHeartbeatTime == s.nextHeartbeatTime { lemma_TimeAdvancesBetween(b, asp, i-1, i); } else { var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, i-1, idx); assert ios[0].LIoOpReadClock?; lemma_ClockAmbiguityLimitApplies(b, asp, i-1, idx, ios[0]); assert ios[0].t <= b[i].environment.time + asp.max_clock_ambiguity; assert s'.nextHeartbeatTime == UpperBoundedAddition(ios[0].t, asp.c.params.heartbeat_period, asp.c.params.max_integer_val); } } } lemma lemma_NextCheckpointedOperationAlwaysSizeOfReplicas( b:Behavior, c:LConstants, i:int, idx:int ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires 0 <= idx < |b[i].replicas| ensures |b[i].replicas[idx].replica.acceptor.last_checkpointed_operation| == |c.config.replica_ids| { if i == 0 { return; } lemma_ConstantsAllConsistent(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i); lemma_NextCheckpointedOperationAlwaysSizeOfReplicas(b, c, i-1, idx); lemma_AssumptionsMakeValidTransition(b, c, i-1); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/LivenessProof/Invariants.i.dfy ================================================ include "../DistributedSystem.i.dfy" include "../../../Common/Framework/HostQueueLemmas.i.dfy" include "../../../Common/Logic/Temporal/Heuristics.i.dfy" include "Assumptions.i.dfy" include "../CommonProof/Constants.i.dfy" module LivenessProof__Invariants_i { import opened LiveRSL__DistributedSystem_i import opened Liveness__HostQueueLemmas_i import opened Temporal__Temporal_s import opened Temporal__Heuristics_i import opened Temporal__Rules_i import opened LivenessProof__Assumptions_i import opened CommonProof__Assumptions_i import opened CommonProof__Constants_i import opened EnvironmentSynchrony_s lemma lemma_HostQueuesNext( b:Behavior, asp:AssumptionParameters, i:int ) requires LivenessAssumptions(b, asp) requires 0 <= i ensures HostQueues_Next(b[i].environment, b[i+1].environment) { TemporalDeduceFromAlways(0, i, HostQueuesNextTemporal(RestrictBehaviorToEnvironment(b))); } lemma lemma_LEnvironmentInvariantHolds( b:Behavior, asp:AssumptionParameters, i:int ) requires LivenessAssumptions(b, asp) requires 0 <= i ensures LEnvironmentInvariant(b[i].environment) { if i == 0 { Lemma_LEnvironmentInitEstablishesInvariant(b[i].environment); } else { lemma_LEnvironmentInvariantHolds(b, asp, i-1); lemma_AssumptionsMakeValidTransition(b, asp.c, i-1); lemma_HostQueuesNext(b, asp, i-1); Lemma_LEnvironmentNextPreservesInvariant(b[i-1].environment, b[i].environment); } } lemma lemma_OverflowProtectionNotUsedForReplica( b:Behavior, asp:AssumptionParameters, i:int, idx:int ) requires LivenessAssumptions(b, asp) requires 0 <= i requires 0 <= idx < |b[i].replicas| ensures OverflowProtectionNotUsedForReplica(b[i], idx, asp.c.params, asp.max_clock_ambiguity) { TemporalDeduceFromAlways(0, i, OverflowProtectionNotUsedTemporal(b, asp.c.params, asp.max_clock_ambiguity)); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/LivenessProof/LivenessProof.i.dfy ================================================ include "Assumptions.i.dfy" include "Invariants.i.dfy" include "StablePeriod.i.dfy" include "Phase2Start.i.dfy" include "Phase2Conclusion.i.dfy" include "StateTransfer.i.dfy" module LivenessProof__LivenessProof_i { import opened AppStateMachine_s import opened LiveRSL__Constants_i import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Environment_i import opened LiveRSL__Executor_i import opened LiveRSL__Message_i import opened LiveRSL__Replica_i import opened LiveRSL__StateMachine_i import opened LiveRSL__Types_i import opened LivenessProof__Assumptions_i import opened LivenessProof__Environment_i import opened LivenessProof__Invariants_i import opened LivenessProof__StablePeriod_i import opened LivenessProof__Phase2Start_i import opened LivenessProof__Phase2Conclusion_i import opened LivenessProof__StateTransfer_i import opened CommonProof__Chosen_i import opened CommonProof__Constants_i import opened CommonProof__Environment_i import opened CommonProof__MaxBallotISent1a_i import opened CommonProof__Message2a_i import opened CommonProof__Message2b_i import opened Temporal__Rules_i import opened Temporal__Temporal_s import opened Environment_s import opened Concrete_NodeIdentity_i import opened Common__UpperBound_s lemma lemma_EventuallyLiveReplicaExecutesClientRequest( b:Behavior, asp:AssumptionParameters ) returns ( execute_step:int, executor_idx:int, ios:seq ) requires LivenessAssumptions(b, asp) ensures asp.synchrony_start <= execute_step ensures executor_idx in asp.live_quorum ensures 0 <= executor_idx < |b[execute_step].replicas| ensures 0 <= executor_idx < |b[execute_step+1].replicas| ensures RslNextOneReplica(b[execute_step], b[execute_step+1], executor_idx, ios) ensures var s := b[execute_step].replicas[executor_idx].replica.executor; && s.next_op_to_execute.OutstandingOpKnown? && asp.persistent_request in s.next_op_to_execute.v && LtUpperBound(s.ops_complete, s.constants.all.params.max_integer_val) && LReplicaConstantsValid(s.constants); ensures LExecutorExecute(b[execute_step].replicas[executor_idx].replica.executor, b[execute_step+1].replicas[executor_idx].replica.executor, ExtractSentPacketsFromIos(ios)); { var h:Phase2Params, step:int, opn_higher:OperationNumber, p:RslPacket; h, step, opn_higher, p, execute_step, ios := lemma_EventuallyKingExecutesOperationCorrespondingTo2aWithClientRequest(b, asp); executor_idx := h.king_idx; var opn := p.msg.opn_2a; var bal := p.msg.bal_2a; lemma_ConstantsAllConsistent(b, asp.c, execute_step); var s := b[execute_step].replicas[executor_idx].replica.executor; var s' := b[execute_step+1].replicas[executor_idx].replica.executor; assert BalLeq(s.next_op_to_execute.bal, h.view); var q := lemma_DecidedOperationWasChosen(b, asp.c, execute_step, executor_idx); lemma_QuorumOf1bsFromPhase2StartPrecludesQuorumOf2bsFromEarlierView(b, asp, h, execute_step, q); assert s.next_op_to_execute.bal == h.view; var quorum_idx :| quorum_idx in q.indices; var packet_2b_from_quorum := q.packets[quorum_idx]; var packet_2a_from_quorum := lemma_2bMessageHasCorresponding2aMessage(b, asp.c, execute_step, packet_2b_from_quorum); var latest_step := if execute_step > step then execute_step else step; lemma_PacketStaysInSentPackets(b, asp.c, execute_step, latest_step, packet_2a_from_quorum); lemma_PacketStaysInSentPackets(b, asp.c, step, latest_step, p); lemma_2aMessagesFromSameBallotAndOperationMatch(b, asp.c, latest_step, packet_2a_from_quorum, p); assert asp.persistent_request in s.next_op_to_execute.v; var x := stepmap(imap j :: packet_2a_from_quorum in b[j].environment.sentPackets); var send_2a_next_step := earliestStepBetween(0, execute_step, x); assert sat(send_2a_next_step, x); if (send_2a_next_step <= h.start_step) { var proposer_idx := lemma_2aMessageImplicationsForProposerState(b, asp.c, send_2a_next_step, packet_2a_from_quorum); assert proposer_idx == h.view.proposer_id; lemma_MaxBallotISent1aMonotonic(b, asp.c, send_2a_next_step, h.start_step, proposer_idx); assert false; } assert asp.synchrony_start <= h.start_step < send_2a_next_step <= execute_step; } lemma lemma_ExecutingRequestBatchWithRequestProducesReply( app:AppState, requestBatch:RequestBatch, req:Request, replies:seq ) returns ( i:int, reply:Reply ) requires replies == HandleRequestBatch(app, requestBatch).1 requires req in requestBatch ensures 0 <= i < |requestBatch| == |replies| ensures req == requestBatch[i] ensures reply == replies[i] ensures reply.client == req.client ensures reply.seqno == req.seqno { var states := HandleRequestBatch(app, requestBatch).0; lemma_HandleRequestBatchTriggerHappy(app, requestBatch, states, replies); i :| 0 <= i < |requestBatch| && req == requestBatch[i]; reply := replies[i]; } lemma lemma_ExecutingRequestBatchWithRequestProducesReplyMessage( requestBatch:RequestBatch, replies:seq, me:NodeIdentity, sent_packets:seq, i:int, req:Request, reply:Reply ) returns ( p:RslPacket ) requires 0 <= i < |requestBatch| == |replies| requires req == requestBatch[i] requires reply == replies[i] requires sent_packets == GetPacketsFromReplies(me, requestBatch, replies) requires reply.client == req.client requires reply.seqno == req.seqno ensures p in sent_packets ensures p.src == me ensures p.dst == req.client ensures p.msg.RslMessage_Reply? ensures p.msg.seqno_reply == req.seqno { if req == requestBatch[0] { p := sent_packets[0]; } else { p := lemma_ExecutingRequestBatchWithRequestProducesReplyMessage(requestBatch[1..], replies[1..], me, sent_packets[1..], i-1, req, reply); } } lemma lemma_EventuallyLiveReplicaSendsReplyToClientDuringSynchronyPeriod( b:Behavior, asp:AssumptionParameters ) returns ( execute_step:int, executor_idx:int, ios:seq, p:RslPacket ) requires LivenessAssumptions(b, asp) ensures asp.synchrony_start <= execute_step ensures executor_idx in asp.live_quorum ensures 0 <= executor_idx < |b[execute_step].replicas| ensures 0 <= executor_idx < |b[execute_step+1].replicas| ensures LIoOpSend(p) in ios ensures p.src == asp.c.config.replica_ids[executor_idx] ensures p.dst == asp.persistent_request.client ensures p.msg.RslMessage_Reply? ensures p.msg.seqno_reply == asp.persistent_request.seqno ensures RslNextOneReplica(b[execute_step], b[execute_step+1], executor_idx, ios) { execute_step, executor_idx, ios := lemma_EventuallyLiveReplicaExecutesClientRequest(b, asp); lemma_ReplicaConstantsAllConsistent(b, asp.c, execute_step, executor_idx); var s := b[execute_step].replicas[executor_idx].replica.executor; var replies := HandleRequestBatch(s.app, s.next_op_to_execute.v).1; var i, reply := lemma_ExecutingRequestBatchWithRequestProducesReply(s.app, s.next_op_to_execute.v, asp.persistent_request, replies); var me := asp.c.config.replica_ids[executor_idx]; var sent_packets := ExtractSentPacketsFromIos(ios); p := lemma_ExecutingRequestBatchWithRequestProducesReplyMessage(s.next_op_to_execute.v, replies, me, sent_packets, i, asp.persistent_request, reply); } lemma lemma_LivenessAssumptionsAssumingClientNeverGetsReplyCannotHold( b:Behavior, asp:AssumptionParameters ) requires LivenessAssumptions(b, asp) ensures false; { var execute_step, executor_idx, ios, p := lemma_EventuallyLiveReplicaSendsReplyToClientDuringSynchronyPeriod(b, asp); var delivery_step := lemma_PacketSentEventuallyDelivered(b, asp, execute_step, p); lemma_ReplicaConstantsAllConsistent(b, asp.c, delivery_step, executor_idx); assert ReplyDeliveredDuringStep(b[delivery_step], asp.persistent_request); TemporalDeduceFromAlways(0, delivery_step, not(ReplyDeliveredTemporal(b, asp.persistent_request))); assert false; } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/LivenessProof/MaxBalReflected.i.dfy ================================================ include "Assumptions.i.dfy" include "Invariants.i.dfy" include "ViewChange.i.dfy" include "MaxBallot.i.dfy" include "../CommonProof/Actions.i.dfy" include "../CommonProof/PacketSending.i.dfy" include "../CommonProof/MaxBallotISent1a.i.dfy" module LivenessProof__MaxBalReflected_i { import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Executor_i import opened LiveRSL__Message_i import opened LiveRSL__Replica_i import opened LiveRSL__Types_i import opened LivenessProof__Assumptions_i import opened LivenessProof__Invariants_i import opened LivenessProof__MaxBallot_i import opened LivenessProof__MaxBallotISent1a_i import opened LivenessProof__StablePeriod_i import opened LivenessProof__ViewChange_i import opened CommonProof__Actions_i import opened CommonProof__Constants_i import opened CommonProof__PacketSending_i import opened CommonProof__MaxBallotISent1a_i import opened Temporal__Temporal_s import opened Collections__Seqs_i import opened Environment_s predicate MaxBalReflectedInvariant( ps:RslState ) { && (forall idx {:trigger PrimaryHasReachedState2OfBallot(ps, ps.replicas[idx].replica.executor.max_bal_reflected)} :: 0 <= idx < |ps.replicas| ==> PrimaryHasReachedState2OfBallot(ps, ps.replicas[idx].replica.executor.max_bal_reflected)) && (forall p {:trigger p.msg.RslMessage_AppStateSupply?} :: p in ps.environment.sentPackets && p.src in ps.constants.config.replica_ids && p.msg.RslMessage_AppStateSupply? ==> PrimaryHasReachedState2OfBallot(ps, p.msg.bal_state_supply)) } lemma lemma_IfMaxBalReflectedChangedThenInvariantStillHolds( b:Behavior, asp:AssumptionParameters, i:int, idx:int ) requires LivenessAssumptions(b, asp) requires 0 <= i requires MaxBalReflectedInvariant(b[i]) requires 0 <= idx < |b[i].replicas| requires 0 <= idx < |b[i+1].replicas| requires b[i+1].replicas[idx].replica.executor.max_bal_reflected != b[i].replicas[idx].replica.executor.max_bal_reflected ensures PrimaryHasReachedState2OfBallot(b[i+1], b[i+1].replicas[idx].replica.executor.max_bal_reflected) { lemma_ConstantsAllConsistent(b, asp.c, i); lemma_ConstantsAllConsistent(b, asp.c, i+1); lemma_AssumptionsMakeValidTransition(b, asp.c, i); var max_bal_reflected := b[i].replicas[idx].replica.executor.max_bal_reflected; var max_bal_reflected' := b[i+1].replicas[idx].replica.executor.max_bal_reflected; assert max_bal_reflected' != max_bal_reflected; var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, i, idx); var nextActionIndex := b[i].replicas[idx].nextActionIndex; if nextActionIndex == 0 { assert LExecutorProcessAppStateSupply(b[i].replicas[idx].replica.executor, b[i+1].replicas[idx].replica.executor, ios[0].r); var p := ios[0].r; lemma_PacketProcessedImpliesPacketSent(b[i], b[i+1], idx, ios, p); assert p in b[i].environment.sentPackets && p.src in b[i].constants.config.replica_ids && p.msg.RslMessage_AppStateSupply?; assert PrimaryHasReachedState2OfBallot(b[i], p.msg.bal_state_supply); lemma_PrimaryHasReachedState2OfBallotMaintainedByOneStep(b, asp.c, i, p.msg.bal_state_supply); assert PrimaryHasReachedState2OfBallot(b[i+1], p.msg.bal_state_supply); assert max_bal_reflected' == p.msg.bal_state_supply; assert PrimaryHasReachedState2OfBallot(b[i+1], max_bal_reflected'); } else if nextActionIndex == 6 { assert LReplicaNextSpontaneousMaybeExecute(b[i].replicas[idx].replica, b[i+1].replicas[idx].replica, ExtractSentPacketsFromIos(ios)); assert b[i].replicas[idx].replica.executor.next_op_to_execute.OutstandingOpKnown?; lemma_ExecutorNextOpToExecuteBallotShowsPrimaryReachedState2(b, asp.c, i, idx); lemma_PrimaryHasReachedState2OfBallotMaintainedByOneStep(b, asp.c, i, b[i].replicas[idx].replica.executor.next_op_to_execute.bal); assert max_bal_reflected' == b[i].replicas[idx].replica.executor.next_op_to_execute.bal; assert PrimaryHasReachedState2OfBallot(b[i+1], max_bal_reflected'); } else { assert false; } } lemma lemma_MaxBalReflectedInvariantHolds( b:Behavior, asp:AssumptionParameters, i:int ) requires LivenessAssumptions(b, asp) requires 0 <= i ensures MaxBalReflectedInvariant(b[i]) { if i > 0 { lemma_ConstantsAllConsistent(b, asp.c, i-1); lemma_ConstantsAllConsistent(b, asp.c, i); lemma_AssumptionsMakeValidTransition(b, asp.c, i-1); lemma_MaxBalReflectedInvariantHolds(b, asp, i-1); forall idx | 0 <= idx < |b[i].replicas| ensures PrimaryHasReachedState2OfBallot(b[i], b[i].replicas[idx].replica.executor.max_bal_reflected) { var max_bal_reflected := b[i-1].replicas[idx].replica.executor.max_bal_reflected; var max_bal_reflected' := b[i].replicas[idx].replica.executor.max_bal_reflected; if max_bal_reflected' == max_bal_reflected { assert 0 <= idx < |b[i-1].replicas|; assert PrimaryHasReachedState2OfBallot(b[i-1], max_bal_reflected); lemma_PrimaryHasReachedState2OfBallotMaintainedByOneStep(b, asp.c, i-1, max_bal_reflected); } else { lemma_IfMaxBalReflectedChangedThenInvariantStillHolds(b, asp, i-1, idx); } } forall p | p in b[i].environment.sentPackets && p.src in b[i].constants.config.replica_ids && p.msg.RslMessage_AppStateSupply? ensures PrimaryHasReachedState2OfBallot(b[i], p.msg.bal_state_supply) { if p in b[i-1].environment.sentPackets { assert PrimaryHasReachedState2OfBallot(b[i-1], p.msg.bal_state_supply); lemma_PrimaryHasReachedState2OfBallotMaintainedByOneStep(b, asp.c, i-1, p.msg.bal_state_supply); } else { var idx, ios := lemma_ActionThatSendsAppStateSupplyIsProcessAppStateRequest(b[i-1], b[i], p); var s := b[i-1].replicas[idx].replica.executor; assert LExecutorProcessAppStateRequest(b[i-1].replicas[idx].replica.executor, b[i].replicas[idx].replica.executor, ios[0].r, [p]); Lemma_IdenticalSingletonSequencesHaveIdenticalElement(p, LPacket(ios[0].r.src, asp.c.config.replica_ids[idx], RslMessage_AppStateSupply(s.max_bal_reflected, s.ops_complete, s.app))); assert 0 <= idx < |b[i-1].replicas|; assert PrimaryHasReachedState2OfBallot(b[i-1], s.max_bal_reflected); assert p.msg.bal_state_supply == s.max_bal_reflected; lemma_PrimaryHasReachedState2OfBallotMaintainedByOneStep(b, asp.c, i-1, p.msg.bal_state_supply); } } } } lemma lemma_MaxBalReflectedLeqCurrentView( b:Behavior, asp:AssumptionParameters, i:int, view:Ballot, idx:int ) requires LivenessAssumptions(b, asp) requires 0 <= i requires sat(i, NoReplicaBeyondViewTemporal(b, view)) requires 0 <= idx < |b[i].replicas| ensures BalLeq(b[i].replicas[idx].replica.executor.max_bal_reflected, view) { lemma_NoReplicaBeyondViewImpliesNoMaxBallotISent1aBeyondView(b, asp, i, view); lemma_MaxBalReflectedInvariantHolds(b, asp, i); var max_bal_reflected := b[i].replicas[idx].replica.executor.max_bal_reflected; assert PrimaryHasReachedState2OfBallot(b[i], max_bal_reflected); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/LivenessProof/MaxBallot.i.dfy ================================================ include "Assumptions.i.dfy" include "Invariants.i.dfy" include "ViewChange.i.dfy" include "MaxBallotISent1a.i.dfy" include "../CommonProof/Actions.i.dfy" include "../CommonProof/MaxBallot.i.dfy" include "../CommonProof/PacketSending.i.dfy" module LivenessProof__MaxBallot_i { import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Types_i import opened LivenessProof__Assumptions_i import opened LivenessProof__Invariants_i import opened LivenessProof__MaxBallotISent1a_i import opened LivenessProof__StablePeriod_i import opened LivenessProof__ViewChange_i import opened CommonProof__Actions_i import opened CommonProof__MaxBallot_i import opened CommonProof__PacketSending_i import opened Temporal__Temporal_s lemma lemma_WhenStablePeriodStartsEveryMaxBalPrecedesView( b:Behavior, asp:AssumptionParameters, i:int, idx:int, ahead_idx:int, view:Ballot ) requires LivenessAssumptions(b, asp) requires 0 <= i requires 0 <= idx < |b[i].replicas| requires StablePeriodStarted(b[i], asp.live_quorum, view, ahead_idx) ensures BalLt(b[i].replicas[idx].replica.acceptor.max_bal, view) { var max_bal := b[i].replicas[idx].replica.acceptor.max_bal; lemma_MaxBalLeqMaxBallotPrimarySent1a(b, asp.c, i, idx); assert BalLt(b[i].replicas[max_bal.proposer_id].replica.proposer.max_ballot_i_sent_1a, view); // TRIGGER } lemma lemma_DuringStablePeriodNoMaxBalBeyondView( b:Behavior, asp:AssumptionParameters, i:int, idx:int, view:Ballot ) requires LivenessAssumptions(b, asp) requires 0 <= i requires 0 <= idx < |b[i].replicas| requires NoMaxBallotISent1aBeyondView(b[i], view) ensures BalLeq(b[i].replicas[idx].replica.acceptor.max_bal, view) { var max_bal := b[i].replicas[idx].replica.acceptor.max_bal; lemma_MaxBalLeqMaxBallotPrimarySent1a(b, asp.c, i, idx); assert BalLeq(b[i].replicas[max_bal.proposer_id].replica.proposer.max_ballot_i_sent_1a, view); // TRIGGER } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/LivenessProof/MaxBallotISent1a.i.dfy ================================================ include "Assumptions.i.dfy" include "Invariants.i.dfy" include "ViewChange.i.dfy" include "../CommonProof/Actions.i.dfy" module LivenessProof__MaxBallotISent1a_i { import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Types_i import opened LivenessProof__Assumptions_i import opened LivenessProof__Environment_i import opened LivenessProof__Invariants_i import opened LivenessProof__StablePeriod_i import opened LivenessProof__ViewChange_i import opened CommonProof__Actions_i import opened CommonProof__Constants_i import opened Temporal__Temporal_s lemma lemma_MaxBallotISent1aLeqView( b:Behavior, asp:AssumptionParameters, i:int, idx:int ) requires LivenessAssumptions(b, asp) requires 0 <= i requires 0 <= idx < |b[i].replicas| ensures BalLeq(b[i].replicas[idx].replica.proposer.max_ballot_i_sent_1a, b[i].replicas[idx].replica.proposer.election_state.current_view) decreases i { if i > 0 { lemma_ConstantsAllConsistent(b, asp.c, i-1); lemma_ConstantsAllConsistent(b, asp.c, i); lemma_MaxBallotISent1aLeqView(b, asp, i-1, idx); lemma_AssumptionsMakeValidTransition(b, asp.c, i-1); lemma_BalLtProperties(); if b[i].replicas[idx].replica.proposer.max_ballot_i_sent_1a != b[i-1].replicas[idx].replica.proposer.max_ballot_i_sent_1a { var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, i-1, idx); } else { lemma_ViewOfHostMonotonic(b, asp, idx, i-1, i); } } } lemma lemma_NoReplicaBeyondViewImpliesNoMaxBallotISent1aBeyondView( b:Behavior, asp:AssumptionParameters, i:int, view:Ballot ) requires LivenessAssumptions(b, asp) requires 0 <= i requires NoReplicaBeyondView(b[i], view) ensures NoMaxBallotISent1aBeyondView(b[i], view) { forall idx | 0 <= idx < |b[i].replicas| ensures BalLeq(b[i].replicas[idx].replica.proposer.max_ballot_i_sent_1a, view) { assert BalLeq(CurrentViewOfHost(b[i], idx), view); lemma_MaxBallotISent1aLeqView(b, asp, i, idx); } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/LivenessProof/NextOp.i.dfy ================================================ include "Assumptions.i.dfy" include "Invariants.i.dfy" include "StablePeriod.i.dfy" include "Catchup.i.dfy" include "WF1.i.dfy" module LivenessProof__NextOp_i { import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Environment_i import opened LiveRSL__Proposer_i import opened LiveRSL__Replica_i import opened LiveRSL__Types_i import opened LivenessProof__Assumptions_i import opened LivenessProof__Catchup_i import opened LivenessProof__Environment_i import opened LivenessProof__GenericInvariants_i import opened LivenessProof__Invariants_i import opened LivenessProof__Phase2Invariants_i import opened LivenessProof__RoundRobin_i import opened LivenessProof__StablePeriod_i import opened LivenessProof__WF1_i import opened CommonProof__Actions_i import opened CommonProof__Constants_i import opened CommonProof__LogTruncationPoint_i import opened Temporal__Rules_i import opened Temporal__Temporal_s import opened Temporal__Time_s import opened Temporal__WF1_i import opened Environment_s import opened Collections__Maps2_s predicate AllLiveReplicasCaughtUpWithEarlierOperationWithRequestQueueEmpty( ps:RslState, live_quorum:set, view:Ballot, opn:OperationNumber ) { && 0 <= view.proposer_id < |ps.replicas| && var s := ps.replicas[view.proposer_id].replica.proposer; && |s.request_queue| == 0 && AllLiveReplicasReadyForNextOperation(ps, live_quorum, view, s.next_operation_number_to_propose) && s.next_operation_number_to_propose <= opn } function{:opaque} AllLiveReplicasCaughtUpWithEarlierOperationWithRequestQueueEmptyTemporal( b:Behavior, live_quorum:set, view:Ballot, opn:OperationNumber ):temporal requires imaptotal(b) ensures forall i{:trigger sat(i, AllLiveReplicasCaughtUpWithEarlierOperationWithRequestQueueEmptyTemporal(b, live_quorum, view, opn))} :: sat(i, AllLiveReplicasCaughtUpWithEarlierOperationWithRequestQueueEmptyTemporal(b, live_quorum, view, opn)) == AllLiveReplicasCaughtUpWithEarlierOperationWithRequestQueueEmpty(b[i], live_quorum, view, opn) { stepmap(imap i :: AllLiveReplicasCaughtUpWithEarlierOperationWithRequestQueueEmpty(b[i], live_quorum, view, opn)) } predicate ProposerStartsBatchTimer( ps:RslState, idx:int ) { && 0 <= idx < |ps.replicas| && ps.replicas[idx].replica.proposer.incomplete_batch_timer.IncompleteBatchTimerOn? } function{:opaque} ProposerStartsBatchTimerTemporal( b:Behavior, idx:int ):temporal requires imaptotal(b) ensures forall i{:trigger sat(i, ProposerStartsBatchTimerTemporal(b, idx))} :: sat(i, ProposerStartsBatchTimerTemporal(b, idx)) == ProposerStartsBatchTimer(b[i], idx) { stepmap(imap i :: ProposerStartsBatchTimer(b[i], idx)) } predicate ProposerExceedsCertainNextOp( ps:RslState, idx:int, opn:int ) { && 0 <= idx < |ps.replicas| && ps.replicas[idx].replica.proposer.next_operation_number_to_propose > opn } function{:opaque} ProposerExceedsCertainNextOpTemporal( b:Behavior, idx:int, opn:int ):temporal requires imaptotal(b) ensures forall i{:trigger sat(i, ProposerExceedsCertainNextOpTemporal(b, idx, opn))} :: sat(i, ProposerExceedsCertainNextOpTemporal(b, idx, opn)) == ProposerExceedsCertainNextOp(b[i], idx, opn) { stepmap(imap i :: ProposerExceedsCertainNextOp(b[i], idx, opn)) } predicate ProposerHasCertainNextOpAndNonemptyRequestQueue( ps:RslState, idx:int, opn:int ) { && 0 <= idx < |ps.replicas| && var s := ps.replicas[idx].replica; && s.proposer.next_operation_number_to_propose == opn && |s.proposer.request_queue| > 0 && s.acceptor.log_truncation_point >= opn } function{:opaque} ProposerHasCertainNextOpAndNonemptyRequestQueueTemporal( b:Behavior, idx:int, opn:int ):temporal requires imaptotal(b) ensures forall i{:trigger sat(i, ProposerHasCertainNextOpAndNonemptyRequestQueueTemporal(b, idx, opn))} :: sat(i, ProposerHasCertainNextOpAndNonemptyRequestQueueTemporal(b, idx, opn)) == ProposerHasCertainNextOpAndNonemptyRequestQueue(b[i], idx, opn) { stepmap(imap i :: ProposerHasCertainNextOpAndNonemptyRequestQueue(b[i], idx, opn)) } predicate ProposerHasCertainNextOpAndNonemptyRequestQueueAndBatchTimer( ps:RslState, idx:int, opn:int, timerExpiration:int ) { && 0 <= idx < |ps.replicas| && var s := ps.replicas[idx].replica; && s.proposer.next_operation_number_to_propose == opn && |s.proposer.request_queue| > 0 && s.acceptor.log_truncation_point >= opn && s.proposer.incomplete_batch_timer == IncompleteBatchTimerOn(timerExpiration) } function{:opaque} ProposerHasCertainNextOpAndNonemptyRequestQueueAndBatchTimerTemporal( b:Behavior, idx:int, opn:int, timerExpiration:int ):temporal requires imaptotal(b) ensures forall i{:trigger sat(i, ProposerHasCertainNextOpAndNonemptyRequestQueueAndBatchTimerTemporal(b, idx, opn, timerExpiration))} :: sat(i, ProposerHasCertainNextOpAndNonemptyRequestQueueAndBatchTimerTemporal(b, idx, opn, timerExpiration)) == ProposerHasCertainNextOpAndNonemptyRequestQueueAndBatchTimer(b[i], idx, opn, timerExpiration) { stepmap(imap i :: ProposerHasCertainNextOpAndNonemptyRequestQueueAndBatchTimer(b[i], idx, opn, timerExpiration)) } lemma lemma_IfProposerHasCertainNextOpAndNonemptyRequestQueueThenProposerEventuallyStartsBatchTimerHelper( b:Behavior, asp:AssumptionParameters, h:Phase2Params, opn:OperationNumber, prev_step:int, i:int ) requires Phase2StableWithRequest(b, asp, h) requires opn >= h.log_truncation_point requires prev_step <= i requires h.start_step + 1 <= prev_step requires AllLiveReplicasReadyForNextOperation(b[prev_step], asp.live_quorum, h.view, opn) requires ProposerHasCertainNextOpAndNonemptyRequestQueue(b[prev_step], h.view.proposer_id, opn) requires && ProposerHasCertainNextOpAndNonemptyRequestQueue(b[i], h.view.proposer_id, opn) && AllLiveReplicasReadyForNextOperation(b[i], asp.live_quorum, h.view, opn) requires !(&& ProposerHasCertainNextOpAndNonemptyRequestQueue(b[i+1], h.view.proposer_id, opn) && AllLiveReplicasReadyForNextOperation(b[i+1], asp.live_quorum, h.view, opn)) requires !(&& ProposerStartsBatchTimer(b[i], h.view.proposer_id) && AllLiveReplicasReadyForNextOperation(b[i], asp.live_quorum, h.view, opn)) requires !(&& ProposerExceedsCertainNextOp(b[i], h.view.proposer_id, opn) && AllLiveReplicasReadyForNextOperation(b[i], asp.live_quorum, h.view, opn)) requires NoReplicaBeyondView(b[i], h.view) requires !(&& ProposerStartsBatchTimer(b[i+1], h.view.proposer_id) && AllLiveReplicasReadyForNextOperation(b[i+1], asp.live_quorum, h.view, opn)) requires !(&& ProposerExceedsCertainNextOp(b[i+1], h.view.proposer_id, opn) && AllLiveReplicasReadyForNextOperation(b[i+1], asp.live_quorum, h.view, opn)) requires NoReplicaBeyondView(b[i+1], h.view) ensures false { var idx := h.view.proposer_id; lemma_ProposerStaysInState2InPhase2(b, asp, h, i); lemma_ProposerStaysInState2InPhase2(b, asp, h, i+1); lemma_AssumptionsMakeValidTransition(b, asp.c, i); lemma_IfAllLiveReplicasReadyForNextOperationThenSoLaterInPhase2(b, asp, h, opn, prev_step, i+1); lemma_LogTruncationPointMonotonicOneStep(b, asp.c, i, idx); lemma_IfAllLiveReplicasReadyForNextOperationThenSoLaterInPhase2(b, asp, h, opn, prev_step, i+1); lemma_LogTruncationPointMonotonicOneStep(b, asp.c, i, idx); var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, i, idx); } lemma lemma_IfProposerHasCertainNextOpAndNonemptyRequestQueueThenProposerEventuallyStartsBatchTimer( b:Behavior, asp:AssumptionParameters, h:Phase2Params, opn:OperationNumber, prev_step:int ) returns ( step:int ) requires Phase2StableWithRequest(b, asp, h) requires opn >= h.log_truncation_point requires h.start_step + 1 <= prev_step requires AllLiveReplicasReadyForNextOperation(b[prev_step], asp.live_quorum, h.view, opn) requires ProposerHasCertainNextOpAndNonemptyRequestQueue(b[prev_step], h.view.proposer_id, opn) ensures h.start_step + 1 <= step ensures var f := PaxosTimeMap(b); var t := TimeToPerformGenericAction(asp); var w := and(ProposerStartsBatchTimerTemporal(b, h.view.proposer_id), AllLiveReplicasReadyForNextOperationTemporal(b, asp.live_quorum, h.view, opn)); var x := and(ProposerExceedsCertainNextOpTemporal(b, h.view.proposer_id, opn), AllLiveReplicasReadyForNextOperationTemporal(b, asp.live_quorum, h.view, opn)); var y := AllLiveReplicasCaughtUpWithEarlierOperationWithRequestQueueEmptyTemporal(b, asp.live_quorum, h.view, opn + 1); var z := NoReplicaBeyondViewTemporal(b, h.view); sat(step, beforeabsolutetime(or(w, or(x, or(y, not(z)))), b[prev_step].environment.time + t, f)) { var f := PaxosTimeMap(b); var t := TimeToPerformGenericAction(asp); var w := and(ProposerStartsBatchTimerTemporal(b, h.view.proposer_id), AllLiveReplicasReadyForNextOperationTemporal(b, asp.live_quorum, h.view, opn)); var x := and(ProposerExceedsCertainNextOpTemporal(b, h.view.proposer_id, opn), AllLiveReplicasReadyForNextOperationTemporal(b, asp.live_quorum, h.view, opn)); var y := AllLiveReplicasCaughtUpWithEarlierOperationWithRequestQueueEmptyTemporal(b, asp.live_quorum, h.view, opn + 1); var z := NoReplicaBeyondViewTemporal(b, h.view); var idx := h.view.proposer_id; var P := and(ProposerHasCertainNextOpAndNonemptyRequestQueueTemporal(b, h.view.proposer_id, opn), AllLiveReplicasReadyForNextOperationTemporal(b, asp.live_quorum, h.view, opn)); var Q := or(w, or(x, not(z))); var Action := MakeRslActionTemporalFromReadClockReplicaFunction(b, LReplicaNextReadClockMaybeNominateValueAndSend2a, idx); forall i | prev_step <= i ensures sat(i, TemporalWF1Req1(P, Q)) ensures sat(i, TemporalWF1Req2(P, Q, Action)) { if sat(i, P) && !sat(i, Q) && !sat(i+1, Q) { lemma_ProposerStaysInState2InPhase2(b, asp, h, i); lemma_ProposerStaysInState2InPhase2(b, asp, h, i+1); lemma_AssumptionsMakeValidTransition(b, asp.c, i); if !sat(i+1, P) { lemma_IfProposerHasCertainNextOpAndNonemptyRequestQueueThenProposerEventuallyStartsBatchTimerHelper(b, asp, h, opn, prev_step, i); } if sat(i, Action) { assert SpecificClockReadingRslActionOccurs(b[i], b[i+1], LReplicaNextReadClockMaybeNominateValueAndSend2a, idx); var ios:seq :| && RslNextOneReplica(b[i], b[i+1], idx, ios) && SpontaneousIos(ios, 1) && LReplicaNextReadClockMaybeNominateValueAndSend2a(b[i].replicas[idx].replica, b[i+1].replicas[idx].replica, SpontaneousClock(ios), ExtractSentPacketsFromIos(ios)); if sat(i, not(z)) { assert sat(i, Q); assert false; } else { lemma_ProposerCanNominateInPhase2(b, asp, h, i); var s := b[i].replicas[idx].replica; assert s.acceptor.log_truncation_point >= s.proposer.next_operation_number_to_propose; assert s.proposer.next_operation_number_to_propose < s.acceptor.log_truncation_point + asp.c.params.max_log_length; assert LProposerCanNominateUsingOperationNumber(s.proposer, s.acceptor.log_truncation_point, s.proposer.next_operation_number_to_propose); lemma_IfAllLiveReplicasReadyForNextOperationThenSoLaterInPhase2(b, asp, h, opn, prev_step, i+1); assert LProposerNominateNewValueAndSend2a(s.proposer, b[i+1].replicas[idx].replica.proposer, ios[0].t, s.acceptor.log_truncation_point, ExtractSentPacketsFromIos(ios)); assert ProposerStartsBatchTimer(b[i+1], h.view.proposer_id); assert sat(i+1, ProposerStartsBatchTimerTemporal(b, h.view.proposer_id)); assert false; } } } } TemporalAlways(prev_step, TemporalWF1Req1(P, Q)); TemporalAlways(prev_step, TemporalWF1Req2(P, Q, Action)); lemma_ReplicaNextPerformsSubactionPeriodically(b, asp, idx, 3); lemma_EstablishRequirementsForWF1RealTime(b, asp, prev_step, Action, t); TemporalWF1RealTime(prev_step, P, Q, Action, t, f); TemporalDeduceFromAlways(prev_step, prev_step, imply(P, eventuallywithin(Q, t, f))); assert sat(prev_step, P); step := TemporalDeduceFromEventual(prev_step, beforeabsolutetime(Q, b[prev_step].environment.time + t, f)); } lemma lemma_IfLiveReplicasReadyForAnOperationThenProposerEventuallyStartsBatchTimer( b:Behavior, asp:AssumptionParameters, h:Phase2Params, opn:OperationNumber, prev_step:int ) returns ( step:int ) requires Phase2StableWithRequest(b, asp, h) requires opn >= h.log_truncation_point requires h.start_step + 1 <= prev_step requires AllLiveReplicasReadyForNextOperation(b[prev_step], asp.live_quorum, h.view, opn) ensures h.start_step + 1 <= step ensures var f := PaxosTimeMap(b); var t := b[prev_step].environment.time + TimeToPerformGenericAction(asp); var w := and(ProposerStartsBatchTimerTemporal(b, h.view.proposer_id), AllLiveReplicasReadyForNextOperationTemporal(b, asp.live_quorum, h.view, opn)); var x := and(ProposerExceedsCertainNextOpTemporal(b, h.view.proposer_id, opn), AllLiveReplicasReadyForNextOperationTemporal(b, asp.live_quorum, h.view, opn)); var y := AllLiveReplicasCaughtUpWithEarlierOperationWithRequestQueueEmptyTemporal(b, asp.live_quorum, h.view, opn + 1); var z := NoReplicaBeyondViewTemporal(b, h.view); sat(step, beforeabsolutetime(or(w, or(x, or(y, not(z)))), t, f)) { var f := PaxosTimeMap(b); var t := b[prev_step].environment.time + TimeToPerformGenericAction(asp); var w := and(ProposerStartsBatchTimerTemporal(b, h.view.proposer_id), AllLiveReplicasReadyForNextOperationTemporal(b, asp.live_quorum, h.view, opn)); var x := and(ProposerExceedsCertainNextOpTemporal(b, h.view.proposer_id, opn), AllLiveReplicasReadyForNextOperationTemporal(b, asp.live_quorum, h.view, opn)); var y := AllLiveReplicasCaughtUpWithEarlierOperationWithRequestQueueEmptyTemporal(b, asp.live_quorum, h.view, opn + 1); var z := NoReplicaBeyondViewTemporal(b, h.view); var idx := h.view.proposer_id; lemma_ConstantsAllConsistent(b, asp.c, prev_step); var s := b[prev_step].replicas[idx].replica.proposer; if !sat(prev_step, z) { step := prev_step; assert sat(step, beforeabsolutetime(not(z), t, f)); return; } if s.next_operation_number_to_propose > opn { step := prev_step; assert sat(step, beforeabsolutetime(x, t, f)); return; } if |s.request_queue| == 0 { step := prev_step; assert sat(step, y); return; } step := lemma_IfProposerHasCertainNextOpAndNonemptyRequestQueueThenProposerEventuallyStartsBatchTimer(b, asp, h, opn, prev_step); } lemma lemma_IfProposerHasCertainNextOpAndNonemptyRequestQueueAndBatchTimerThenProposerEventuallyAdvancesNextOpHelper( b:Behavior, asp:AssumptionParameters, h:Phase2Params, opn:OperationNumber, prev_step:int, timerExpiration:int, i:int ) requires Phase2StableWithRequest(b, asp, h) requires opn >= h.log_truncation_point requires h.start_step + 1 <= prev_step requires AllLiveReplicasReadyForNextOperation(b[prev_step], asp.live_quorum, h.view, opn) requires ProposerHasCertainNextOpAndNonemptyRequestQueueAndBatchTimer(b[prev_step], h.view.proposer_id, opn, timerExpiration) requires prev_step <= i requires ProposerHasCertainNextOpAndNonemptyRequestQueueAndBatchTimer(b[i], h.view.proposer_id, opn, timerExpiration) requires !ProposerHasCertainNextOpAndNonemptyRequestQueueAndBatchTimer(b[i+1], h.view.proposer_id, opn, timerExpiration) requires !(&& ProposerExceedsCertainNextOp(b[i], h.view.proposer_id, opn) && AllLiveReplicasReadyForNextOperation(b[i], asp.live_quorum, h.view, opn)) requires NoReplicaBeyondView(b[i], h.view) requires !(&& ProposerExceedsCertainNextOp(b[i+1], h.view.proposer_id, opn) && AllLiveReplicasReadyForNextOperation(b[i+1], asp.live_quorum, h.view, opn)) requires NoReplicaBeyondView(b[i+1], h.view) ensures false { var idx := h.view.proposer_id; lemma_ProposerBatchTimerNeverTooFarInFuture(b, asp, prev_step, idx); lemma_ConstantsAllConsistent(b, asp.c, prev_step); assert timerExpiration <= b[prev_step].environment.time + asp.c.params.max_batch_delay + asp.max_clock_ambiguity; lemma_ConstantsAllConsistent(b, asp.c, i); lemma_ProposerStaysInState2InPhase2(b, asp, h, i); lemma_ProposerStaysInState2InPhase2(b, asp, h, i+1); lemma_IfAllLiveReplicasReadyForNextOperationThenSoLaterInPhase2(b, asp, h, opn, prev_step, i+1); lemma_LogTruncationPointMonotonicOneStep(b, asp.c, i, idx); var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, i, idx); } lemma lemma_IfProposerHasCertainNextOpAndNonemptyRequestQueueAndBatchTimerThenProposerEventuallyAdvancesNextOp( b:Behavior, asp:AssumptionParameters, h:Phase2Params, opn:OperationNumber, prev_step:int, timerExpiration:int ) returns ( step:int ) requires Phase2StableWithRequest(b, asp, h) requires opn >= h.log_truncation_point requires h.start_step + 1 <= prev_step requires AllLiveReplicasReadyForNextOperation(b[prev_step], asp.live_quorum, h.view, opn) requires ProposerHasCertainNextOpAndNonemptyRequestQueueAndBatchTimer(b[prev_step], h.view.proposer_id, opn, timerExpiration) ensures h.start_step + 1 <= step ensures var f := PaxosTimeMap(b); var t := asp.c.params.max_batch_delay + asp.max_clock_ambiguity * 2 + TimeToPerformGenericAction(asp); var x := and(ProposerExceedsCertainNextOpTemporal(b, h.view.proposer_id, opn), AllLiveReplicasReadyForNextOperationTemporal(b, asp.live_quorum, h.view, opn)); var z := NoReplicaBeyondViewTemporal(b, h.view); sat(step, beforeabsolutetime(or(x, not(z)), b[prev_step].environment.time + t, f)) { var f := PaxosTimeMap(b); var t := asp.c.params.max_batch_delay + TimeToPerformGenericAction(asp); var x := and(ProposerExceedsCertainNextOpTemporal(b, h.view.proposer_id, opn), AllLiveReplicasReadyForNextOperationTemporal(b, asp.live_quorum, h.view, opn)); var z := NoReplicaBeyondViewTemporal(b, h.view); var idx := h.view.proposer_id; lemma_ProposerBatchTimerNeverTooFarInFuture(b, asp, prev_step, idx); lemma_ConstantsAllConsistent(b, asp.c, prev_step); assert timerExpiration <= b[prev_step].environment.time + asp.c.params.max_batch_delay + asp.max_clock_ambiguity; var P := ProposerHasCertainNextOpAndNonemptyRequestQueueAndBatchTimerTemporal(b, h.view.proposer_id, opn, timerExpiration); assert sat(prev_step, P); var Q := or(x, not(z)); var Action := MakeRslActionTemporalFromReadClockReplicaFunction(b, LReplicaNextReadClockMaybeNominateValueAndSend2a, idx); forall i | prev_step <= i ensures sat(i, TemporalWF1Req1(P, Q)) ensures sat(i, TemporalWF1RealTimeDelayedReq2(P, Q, Action, timerExpiration + asp.max_clock_ambiguity, f)) { if sat(i, P) && !sat(i, Q) && !sat(i+1, Q) { lemma_ConstantsAllConsistent(b, asp.c, i); lemma_ProposerStaysInState2InPhase2(b, asp, h, i); lemma_ProposerStaysInState2InPhase2(b, asp, h, i+1); if !sat(i+1, P) { lemma_IfProposerHasCertainNextOpAndNonemptyRequestQueueAndBatchTimerThenProposerEventuallyAdvancesNextOpHelper( b, asp, h, opn, prev_step, timerExpiration, i); } if sat(i, nextafter(Action, timerExpiration + asp.max_clock_ambiguity, f)) { assert SpecificClockReadingRslActionOccurs(b[i], b[i+1], LReplicaNextReadClockMaybeNominateValueAndSend2a, idx); var ios:seq :| && RslNextOneReplica(b[i], b[i+1], idx, ios) && SpontaneousIos(ios, 1) && LReplicaNextReadClockMaybeNominateValueAndSend2a(b[i].replicas[idx].replica, b[i+1].replicas[idx].replica, SpontaneousClock(ios), ExtractSentPacketsFromIos(ios)); if sat(i, not(z)) { assert sat(i, Q); assert false; } else { lemma_ProposerCanNominateInPhase2(b, asp, h, i); var s := b[i].replicas[idx].replica; assert s.acceptor.log_truncation_point >= s.proposer.next_operation_number_to_propose; assert s.proposer.next_operation_number_to_propose < s.acceptor.log_truncation_point + asp.c.params.max_log_length; assert LProposerCanNominateUsingOperationNumber(s.proposer, s.acceptor.log_truncation_point, s.proposer.next_operation_number_to_propose); assert ios[0].LIoOpReadClock?; lemma_ClockAmbiguityLimitApplies(b, asp, i, idx, ios[0]); assert ios[0].t >= b[i+1].environment.time - asp.max_clock_ambiguity; assert ios[0].t >= timerExpiration; assert false; } } } } TemporalAlways(prev_step, TemporalWF1Req1(P, Q)); TemporalAlways(prev_step, TemporalWF1RealTimeDelayedReq2(P, Q, Action, timerExpiration + asp.max_clock_ambiguity, f)); lemma_ReplicaNextPerformsSubactionPeriodically(b, asp, idx, 3); lemma_EstablishRequirementsForWF1RealTimeDelayed(b, asp, prev_step, Action, TimeToPerformGenericAction(asp)); step := TemporalWF1RealTimeDelayed(prev_step, P, Q, Action, TimeToPerformGenericAction(asp), timerExpiration + asp.max_clock_ambiguity, f); } lemma lemma_IfLiveReplicasReadyForAnOperationThenProposerEventuallyAdvancesNextOp( b:Behavior, asp:AssumptionParameters, h:Phase2Params, opn:OperationNumber, prev_step:int ) returns ( step:int ) requires Phase2StableWithRequest(b, asp, h) requires opn >= h.log_truncation_point requires h.start_step + 1 <= prev_step requires AllLiveReplicasReadyForNextOperation(b[prev_step], asp.live_quorum, h.view, opn) ensures h.start_step + 1 <= step ensures var f := PaxosTimeMap(b); var t := b[prev_step].environment.time + asp.c.params.max_batch_delay + asp.max_clock_ambiguity * 2 + TimeToPerformGenericAction(asp) * 2; var x := and(ProposerExceedsCertainNextOpTemporal(b, h.view.proposer_id, opn), AllLiveReplicasReadyForNextOperationTemporal(b, asp.live_quorum, h.view, opn)); var y := AllLiveReplicasCaughtUpWithEarlierOperationWithRequestQueueEmptyTemporal(b, asp.live_quorum, h.view, opn + 1); var z := NoReplicaBeyondViewTemporal(b, h.view); sat(step, beforeabsolutetime(or(x, or(y, not(z))), t, f)) { var f := PaxosTimeMap(b); var t := b[prev_step].environment.time + asp.c.params.max_batch_delay + asp.max_clock_ambiguity * 2 + TimeToPerformGenericAction(asp) * 2; var x := and(ProposerExceedsCertainNextOpTemporal(b, h.view.proposer_id, opn), AllLiveReplicasReadyForNextOperationTemporal(b, asp.live_quorum, h.view, opn)); var y := AllLiveReplicasCaughtUpWithEarlierOperationWithRequestQueueEmptyTemporal(b, asp.live_quorum, h.view, opn + 1); var z := NoReplicaBeyondViewTemporal(b, h.view); var idx := h.view.proposer_id; var first_step := lemma_IfLiveReplicasReadyForAnOperationThenProposerEventuallyStartsBatchTimer(b, asp, h, opn, prev_step); assert sat(first_step, before(t, f)); lemma_ConstantsAllConsistent(b, asp.c, first_step); var s := b[first_step].replicas[idx].replica.proposer; if !sat(first_step, z) { step := first_step; assert sat(step, beforeabsolutetime(not(z), t, f)); return; } if s.next_operation_number_to_propose > opn { step := first_step; assert sat(step, x); return; } if |s.request_queue| == 0 { step := first_step; assert sat(step, y); return; } step := lemma_IfProposerHasCertainNextOpAndNonemptyRequestQueueAndBatchTimerThenProposerEventuallyAdvancesNextOp(b, asp, h, opn, first_step, s.incomplete_batch_timer.when); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/LivenessProof/PacketHandling.i.dfy ================================================ include "RealTime.i.dfy" include "RoundRobin.i.dfy" include "../CommonProof/Environment.i.dfy" include "../CommonProof/Actions.i.dfy" include "../../../Common/Logic/Temporal/Heuristics.i.dfy" include "../../../Common/Logic/Temporal/Rules.i.dfy" include "../../../Common/Logic/Temporal/Time.i.dfy" include "../../../Common/Logic/Temporal/LeadsTo.i.dfy" include "../../../Common/Framework/EnvironmentSynchronyLemmas.i.dfy" include "../../../../Libraries/Math/mul.i.dfy" include "../../../../Libraries/Math/mul_auto.i.dfy" module LivenessProof__PacketHandling_i { import opened LiveRSL__Configuration_i import opened LiveRSL__Constants_i import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Environment_i import opened LiveRSL__Replica_i import opened LivenessProof__Assumptions_i import opened LivenessProof__Environment_i import opened LivenessProof__Invariants_i import opened LivenessProof__RoundRobin_i import opened LivenessProof__RealTime_i import opened CommonProof__Actions_i import opened CommonProof__Assumptions_i import opened CommonProof__Constants_i import opened CommonProof__Environment_i import opened Temporal__Heuristics_i import opened Temporal__Rules_i import opened Temporal__Time_i import opened Temporal__LeadsTo_i import opened Liveness__EnvironmentSynchronyLemmas_i import opened Liveness__HostQueueLemmas_i import opened Math__mul_i import opened Math__mul_auto_i import opened Math__mul_nonlinear_i import opened Temporal__Temporal_s import opened Temporal__Time_s import opened Collections__Maps2_s import opened Collections__Maps2_i import opened Environment_s import opened EnvironmentSynchrony_s import opened Concrete_NodeIdentity_i predicate AllPacketsProcessedWithin( b:Behavior, i:int, processing_period:int, sources:set, destinations:set ) requires imaptotal(b) { forall p {:trigger PacketSentBetweenHosts(b[i].environment, p, sources, destinations)} :: PacketSentBetweenHosts(b[i].environment, p, sources, destinations) ==> sat(i, eventuallynextwithin(PacketProcessedTemporal(b, p), processing_period, PaxosTimeMap(b))) } function{:opaque} AllPacketsProcessedWithinTemporal( b:Behavior, processing_period:int, sources:set, destinations:set ):temporal requires imaptotal(b) ensures forall i {:trigger sat(i, AllPacketsProcessedWithinTemporal(b, processing_period, sources, destinations))} :: sat(i, AllPacketsProcessedWithinTemporal(b, processing_period, sources, destinations)) <==> AllPacketsProcessedWithin(b, i, processing_period, sources, destinations) { stepmap(imap i :: AllPacketsProcessedWithin(b, i, processing_period, sources, destinations)) } lemma lemma_LReplicaNextProcessPacketOnlyReceivesOnePacket( s:LReplica, s':LReplica, p:RslPacket, ios:seq ) requires LReplicaNextProcessPacket(s, s', ios) requires LIoOpReceive(p) in ios ensures ios[0] == LIoOpReceive(p) { Lemma_IfOpSeqIsCompatibleWithReductionAndFirstIsntReceiveThenNoneAreReceives(ios); assert ios[0].LIoOpReceive?; forall i | 0 < i < |ios| ensures !ios[i].LIoOpReceive? { if ios[0].r.msg.RslMessage_Heartbeat? { if i == 1 { assert ios[i].LIoOpReadClock?; } else { assert ios[i] in ios[2..]; assert ios[i].LIoOpSend?; } } else { assert ios[i] in ios[1..]; assert ios[i].LIoOpSend?; } } assert ios[0] == LIoOpReceive(p); } lemma lemma_PacketReceiveCausesPacketProcessing( b:Behavior, asp:AssumptionParameters, p:RslPacket, i:int ) requires LivenessAssumptions(b, asp) requires 0 <= i requires p.dst in asp.c.config.replica_ids requires sat(i, PacketReceivedTemporal(RestrictBehaviorToEnvironment(b), p)) ensures PacketProcessedDuringAction(b[i], p) { var eb := RestrictBehaviorToEnvironment(b); var ps := b[i]; var ps' := b[i+1]; lemma_AssumptionsMakeValidTransition(b, asp.c, i); lemma_HostQueuesNext(b, asp, i); lemma_ConstantsAllConsistent(b, asp.c, i); assert sat(i, PacketReceivedTemporal(eb, p)); assert PacketReceivedDuringAction(ps.environment, p); var ios := ps.environment.nextStep.ios; var io := LIoOpReceive(p); assert io in ios; assert IsValidLIoOp(io, p.dst, ps.environment); Lemma_ReceiveMakesHostQueueSmaller(ps.environment.hostInfo[p.dst].queue, ps'.environment.hostInfo[p.dst].queue, ios, p); assert ps'.environment.hostInfo[p.dst].queue != ps.environment.hostInfo[p.dst].queue; if (exists idx, ios' :: RslNextOneReplica(ps, ps', idx, ios')) { var idx, ios' :| RslNextOneReplica(ps, ps', idx, ios'); Lemma_ReceiveRemovesPacketFromHostQueue(ps.environment.hostInfo[p.dst].queue, ps'.environment.hostInfo[p.dst].queue, ios, p); Lemma_RemovePacketFromHostQueueImpliesReceive(ps.environment.hostInfo[p.dst].queue, ps'.environment.hostInfo[p.dst].queue, ios', p); assert io in ios'; lemma_LReplicaNextProcessPacketOnlyReceivesOnePacket(ps.replicas[idx].replica, ps'.replicas[idx].replica, p, ios'); assert PacketProcessedViaIos(b[i], b[i+1], p, idx, ios'); } else if (exists eid, ios' :: RslNextOneExternal(ps, ps', eid, ios')) { var eid, ios' :| RslNextOneExternal(ps, ps', eid, ios'); assert eid !in ps.constants.config.replica_ids; assert p.dst != eid; assert HostQueue_PerformIos(ps.environment.hostInfo[p.dst].queue, ps'.environment.hostInfo[p.dst].queue, []); assert ps'.environment.hostInfo[p.dst] == ps.environment.hostInfo[p.dst]; assert false; } else { assert false; } } lemma lemma_IfPacketsSynchronousForHostsThenSynchronousForFewerHosts( b:Behavior>, sync_start:int, latency_bound:int, sources:set, destinations:set, sources':set, destinations':set ) requires LEnvironment_BehaviorSatisfiesSpec(b) requires NetworkSynchronousForHosts(b, sync_start, latency_bound, sources, destinations) requires 0 <= sync_start requires sources' <= sources requires destinations' <= destinations ensures NetworkSynchronousForHosts(b, sync_start, latency_bound, sources', destinations') { forall i | sync_start <= i ensures sat(i, PacketsSynchronousForHostsTemporal(b, latency_bound, sources', destinations')) { forall p | PacketSentBetweenHosts(b[i], p, sources', destinations') ensures sat(i, next(eventuallynextwithin(PacketDeliveredTemporal(b, p), latency_bound, BehaviorToTimeMap(b)))) { assert PacketSentBetweenHosts(b[i], p, sources, destinations); TemporalDeduceFromAlways(sync_start, i, PacketsSynchronousForHostsTemporal(b, latency_bound, sources, destinations)); lemma_PacketSentAppearsInSentPacketsEnvironment(b, i, p); } } TemporalAlways(sync_start, PacketsSynchronousForHostsTemporal(b, latency_bound, sources', destinations')); } lemma lemma_AllPacketsReceivedInTime( b:Behavior, asp:AssumptionParameters ) returns ( processing_sync_start:int, processing_bound:int ) requires LivenessAssumptions(b, asp) ensures asp.synchrony_start <= processing_sync_start ensures processing_bound == asp.latency_bound + asp.burst_size * TimeToPerformGenericAction(asp) ensures var eb := RestrictBehaviorToEnvironment(b); var sources := SetOfReplicaIndicesToSetOfHosts(asp.live_quorum, asp.c.config.replica_ids) + {asp.persistent_request.client}; var destinations := SetOfReplicaIndicesToSetOfHosts(asp.live_quorum, asp.c.config.replica_ids); sat(processing_sync_start, always(AllPacketsReceivedWithinTemporal(eb, processing_bound, sources, destinations))) { var eb := RestrictBehaviorToEnvironment(b); var sources := SetOfReplicaIndicesToSetOfHosts(asp.live_quorum, asp.c.config.replica_ids) + {asp.persistent_request.client}; var destinations := SetOfReplicaIndicesToSetOfHosts(asp.live_quorum, asp.c.config.replica_ids); var receive_period := TimeToPerformGenericAction(asp); var burst_period := asp.burst_size * TimeToPerformGenericAction(asp) + 1; var real_time_fun := PaxosTimeMap(b); lemma_mul_is_associative(asp.burst_size, asp.host_period, LReplicaNumActions()); forall i {:trigger real_time_fun[i]} {:trigger BehaviorToTimeMap(eb)[i]} ensures real_time_fun[i] == BehaviorToTimeMap(eb)[i] { } assert real_time_fun == BehaviorToTimeMap(eb); lemma_AssumptionsMakeValidEnvironmentBehavior(b, asp.c); assert LEnvironment_BehaviorSatisfiesSpec(eb); assert NetworkSynchronousForHosts(eb, asp.synchrony_start, asp.latency_bound, sources, sources); lemma_IfPacketsSynchronousForHostsThenSynchronousForFewerHosts(eb, asp.synchrony_start, asp.latency_bound, sources, sources, sources, destinations); assert NetworkSynchronousForHosts(eb, asp.synchrony_start, asp.latency_bound, sources, destinations); assert sat(asp.synchrony_start, always(PacketsSynchronousForHostsTemporal(eb, asp.latency_bound, sources, destinations))); TemporalEventually(0, asp.synchrony_start, always(PacketsSynchronousForHostsTemporal(eb, asp.latency_bound, sources, destinations))); forall host | host in destinations ensures sat(0, eventual(always(NetworkDeliveryRateForHostBoundedTemporal(eb, asp.burst_size, burst_period, host)))) { var replica_index :| replica_index in asp.live_quorum && host == asp.c.config.replica_ids[replica_index]; assert sat(asp.synchrony_start, always(NetworkDeliveryRateForHostBoundedTemporal(eb, asp.burst_size, burst_period, host))); TemporalEventually(0, asp.synchrony_start, always(NetworkDeliveryRateForHostBoundedTemporal(eb, asp.burst_size, burst_period, host))); } lemma_mul_is_associative(asp.burst_size, asp.host_period, LReplicaNumActions()); assert forall host :: host in destinations ==> sat(0, eventual(always(NetworkDeliveryRateForHostBoundedTemporal(eb, asp.burst_size, asp.burst_size * receive_period + 1, host)))); forall host | host in destinations ensures sat(asp.synchrony_start, always(eventuallynextwithin(ReceiveAttemptedTemporal(eb, host), receive_period, real_time_fun))) { var replica_index :| replica_index in asp.live_quorum && host == asp.c.config.replica_ids[replica_index]; lemma_ReplicaNextPerformsProcessPacketPeriodically(b, asp, replica_index); } forall ensures 1 <= receive_period { lemma_mul_inequality_forall(); lemma_mul_auto(); } forall i, j | 0 <= i <= j ensures b[i].environment.time <= b[j].environment.time { lemma_TimeAdvancesBetween(b, asp, i, j); } processing_sync_start, processing_bound := Lemma_EventuallyAllPacketsAlwaysReceivedInTime(asp.synchrony_start, asp.latency_bound, sources, destinations, eb, asp.burst_size, receive_period); } predicate PacketProcessingSynchronousOneStep( b:Behavior, i:int, processing_bound:int, sources:set, destinations:set ) requires imaptotal(b) { forall p {:trigger PacketSentDuringAction(b[i], p)} :: PacketSentDuringAction(b[i], p) && p.src in sources && p.dst in destinations ==> sat(i, next(eventuallynextwithin(PacketProcessedTemporal(b, p), processing_bound, PaxosTimeMap(b)))) } function{:opaque} PacketProcessingSynchronousTemporal( b:Behavior, processing_bound:int, sources:set, destinations:set ):temporal requires imaptotal(b) ensures forall i {:trigger sat(i, PacketProcessingSynchronousTemporal(b, processing_bound, sources, destinations))} :: sat(i, PacketProcessingSynchronousTemporal(b, processing_bound, sources, destinations)) <==> PacketProcessingSynchronousOneStep(b, i, processing_bound, sources, destinations) { stepmap(imap i :: PacketProcessingSynchronousOneStep(b, i, processing_bound, sources, destinations)) } predicate PacketProcessingSynchronous( b:Behavior, asp:AssumptionParameters, start_step:int, processing_bound:int ) requires LivenessAssumptions(b, asp) { var sources := SetOfReplicaIndicesToSetOfHosts(asp.live_quorum, asp.c.config.replica_ids) + {asp.persistent_request.client}; var destinations := SetOfReplicaIndicesToSetOfHosts(asp.live_quorum, asp.c.config.replica_ids); && asp.synchrony_start <= start_step && processing_bound >= 0 && sat(start_step, always(PacketProcessingSynchronousTemporal(b, processing_bound, sources, destinations))) } lemma lemma_EventuallyPacketProcessingSynchronous( b:Behavior, asp:AssumptionParameters ) returns ( processing_sync_start:int, processing_bound:int ) requires LivenessAssumptions(b, asp) ensures PacketProcessingSynchronous(b, asp, processing_sync_start, processing_bound) { TemporalAssist(); var eb := RestrictBehaviorToEnvironment(b); var f := PaxosTimeMap(b); var sources := SetOfReplicaIndicesToSetOfHosts(asp.live_quorum, asp.c.config.replica_ids) + {asp.persistent_request.client}; var destinations := SetOfReplicaIndicesToSetOfHosts(asp.live_quorum, asp.c.config.replica_ids); var receive_period := TimeToPerformGenericAction(asp); processing_sync_start, processing_bound := lemma_AllPacketsReceivedInTime(b, asp); forall i | processing_sync_start <= i ensures sat(i, PacketProcessingSynchronousTemporal(b, processing_bound, sources, destinations)) { forall p{:trigger PacketSentDuringAction(b[i], p)} | PacketSentDuringAction(b[i], p) && p.src in sources && p.dst in destinations ensures sat(i+1, eventuallynextwithin(PacketProcessedTemporal(b, p), processing_bound, f)) { TemporalDeduceFromAlways(processing_sync_start, i, AllPacketsReceivedWithinTemporal(eb, processing_bound, sources, destinations)); assert PacketSentBetweenHosts(eb[i], p, sources, destinations); // TRIGGER assert sat(i, AllPacketsReceivedWithinTemporal(eb, processing_bound, sources, destinations)); assert AllPacketsReceivedWithin(eb, i, processing_bound, sources, destinations); assert sat(i, next(eventuallynextwithin(PacketReceivedTemporal(eb, p), processing_bound, f))); var j := TemporalDeduceFromEventual(i+1, nextbefore(PacketReceivedTemporal(eb, p), f[i+1] + processing_bound, f)); assert sat(j, PacketReceivedTemporal(eb, p)); lemma_PacketReceiveCausesPacketProcessing(b, asp, p, j); assert sat(j, imply(PacketReceivedTemporal(eb, p), PacketProcessedTemporal(b, p))); assert sat(j, PacketProcessedTemporal(b, p)); TemporalEventually(i+1, j, nextbefore(PacketProcessedTemporal(b, p), f[i+1] + processing_bound, f)); } } TemporalAlways(processing_sync_start, PacketProcessingSynchronousTemporal(b, processing_bound, sources, destinations)); lemma_mul_nonnegative(asp.burst_size, receive_period); } lemma lemma_IfPacketProcessingSynchronousThenAlways( b:Behavior, asp:AssumptionParameters, start_step:int, later_step:int, processing_bound:int ) requires LivenessAssumptions(b, asp) requires PacketProcessingSynchronous(b, asp, start_step, processing_bound) requires start_step <= later_step ensures PacketProcessingSynchronous(b, asp, later_step, processing_bound) { var sources := SetOfReplicaIndicesToSetOfHosts(asp.live_quorum, asp.c.config.replica_ids) + {asp.persistent_request.client}; var destinations := SetOfReplicaIndicesToSetOfHosts(asp.live_quorum, asp.c.config.replica_ids); Lemma_AlwaysImpliesLaterAlways(start_step, later_step, PacketProcessingSynchronousTemporal(b, processing_bound, sources, destinations)); } lemma lemma_SchedulerActionThatReceivesReceivesFirst( s:LScheduler, s':LScheduler, p:RslPacket, ios:seq ) requires LIoOpReceive(p) in ios requires LSchedulerNext(s, s', ios) ensures LIoOpReceive(p) == ios[0] { if LReplicaNextProcessPacket(s.replica, s'.replica, ios) { assert ios[0].LIoOpReceive?; if ios[0].r.msg.RslMessage_Heartbeat? { assert ios[1].LIoOpReadClock?; assert forall i :: 1 < i < |ios| ==> ios[i].LIoOpSend?; assert LIoOpReceive(p) == ios[0]; } else { assert LReplicaNextProcessPacketWithoutReadingClock(s.replica, s'.replica, ios); assert ios[0].LIoOpReceive?; assert forall i :: 0 < i < |ios| ==> ios[i].LIoOpSend?; assert LIoOpReceive(p) == ios[0]; } } } lemma lemma_PacketSentToIndexProcessedByIt( b:Behavior, asp:AssumptionParameters, processing_sync_start:int, processing_bound:int, send_step:int, idx:int, p:RslPacket ) returns ( processing_step:int, ios:seq ) requires LivenessAssumptions(b, asp) requires idx in asp.live_quorum requires PacketSentDuringAction(b[send_step], p) requires p.src in SetOfReplicaIndicesToSetOfHosts(asp.live_quorum, asp.c.config.replica_ids) + { asp.persistent_request.client } requires p.dst == asp.c.config.replica_ids[idx] requires PacketProcessingSynchronous(b, asp, processing_sync_start, processing_bound) requires processing_sync_start <= send_step ensures send_step+1 <= processing_step ensures PacketProcessedViaIos(b[processing_step], b[processing_step+1], p, idx, ios) ensures b[processing_step+1].environment.time <= b[send_step+1].environment.time + processing_bound { TemporalAssist(); var timefun := PaxosTimeMap(b); assert TLe(processing_sync_start, send_step); processing_step :| && TLe(send_step+1, processing_step) && sat(processing_step, PacketProcessedTemporal(b, p)) && timefun[processing_step+1] <= timefun[send_step+1] + processing_bound; lemma_ConstantsAllConsistent(b, asp.c, processing_step); lemma_ConstantsAllConsistent(b, asp.c, processing_step+1); lemma_AssumptionsMakeValidTransition(b, asp.c, processing_step); assert b[processing_step].environment.nextStep.LEnvStepHostIos?; ios := b[processing_step].environment.nextStep.ios; var actor := b[processing_step].environment.nextStep.actor; assert p.dst == actor; assert RslNext(b[processing_step], b[processing_step+1]); if exists idx', ios' {:trigger RslNextOneReplica(b[processing_step], b[processing_step+1], idx', ios')} :: RslNextOneReplica(b[processing_step], b[processing_step+1], idx', ios') { var idx', ios' :| RslNextOneReplica(b[processing_step], b[processing_step+1], idx', ios'); assert ReplicasDistinct(asp.c.config.replica_ids, idx, idx'); assert idx' == idx && ios' == ios; assert LSchedulerNext(b[processing_step].replicas[idx], b[processing_step+1].replicas[idx], ios); assert LIoOpReceive(p) in ios; lemma_SchedulerActionThatReceivesReceivesFirst(b[processing_step].replicas[idx], b[processing_step+1].replicas[idx], p, ios); assert PacketProcessedViaIos(b[processing_step], b[processing_step+1], p, idx, ios); } else if exists eid, ios' {:trigger RslNextOneExternal(b[processing_step], b[processing_step+1], eid, ios')} :: RslNextOneExternal(b[processing_step], b[processing_step+1], eid, ios') { var eid, ios' :| RslNextOneExternal(b[processing_step], b[processing_step+1], eid, ios'); assert false; } else { assert false; } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/LivenessProof/Phase1a.i.dfy ================================================ include "Assumptions.i.dfy" include "Invariants.i.dfy" include "StablePeriod.i.dfy" include "ViewAdvance.i.dfy" include "MaxBallotISent1a.i.dfy" include "MaxBallot.i.dfy" include "WF1.i.dfy" include "../CommonProof/MaxBallotISent1a.i.dfy" include "../CommonProof/MaxBallot.i.dfy" include "../CommonProof/Constants.i.dfy" include "../../../Common/Framework/EnvironmentSynchronyLemmas.i.dfy" module LivenessProof__Phase1a_i { import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Environment_i import opened LiveRSL__Proposer_i import opened LiveRSL__Replica_i import opened LiveRSL__Types_i import opened LivenessProof__Assumptions_i import opened LivenessProof__Invariants_i import opened LivenessProof__MaxBallotISent1a_i import opened LivenessProof__MaxBallot_i import opened LivenessProof__PacketHandling_i import opened LivenessProof__RealTime_i import opened LivenessProof__RoundRobin_i import opened LivenessProof__StablePeriod_i import opened LivenessProof__ViewAdvance_i import opened LivenessProof__ViewChange_i import opened LivenessProof__WF1_i import opened CommonProof__Actions_i import opened CommonProof__Constants_i import opened CommonProof__MaxBallotISent1a_i import opened CommonProof__MaxBallot_i import opened Liveness__EnvironmentSynchronyLemmas_i import opened Temporal__LeadsTo_i import opened Temporal__Rules_i import opened Temporal__Temporal_s import opened Temporal__Time_s import opened Temporal__Time_i import opened Temporal__WF1_i import opened Environment_s import opened Collections__Maps2_s predicate PrimaryInView( ps:RslState, view:Ballot ) { && 0 <= view.proposer_id < |ps.replicas| && CurrentViewOfHost(ps, view.proposer_id) == view } function{:opaque} PrimaryInViewTemporal( b:Behavior, view:Ballot ):temporal requires imaptotal(b) ensures forall i{:trigger sat(i, PrimaryInViewTemporal(b, view))} :: sat(i, PrimaryInViewTemporal(b, view)) == PrimaryInView(b[i], view) { stepmap(imap i :: PrimaryInView(b[i], view)) } predicate PrimaryMaxBallotISent1aInView( ps:RslState, view:Ballot ) { && 0 <= view.proposer_id < |ps.replicas| && ps.replicas[view.proposer_id].replica.proposer.max_ballot_i_sent_1a == view } function{:opaque} PrimaryMaxBallotISent1aInViewTemporal( b:Behavior, view:Ballot ):temporal requires imaptotal(b) ensures forall i{:trigger sat(i, PrimaryMaxBallotISent1aInViewTemporal(b, view))} :: sat(i, PrimaryMaxBallotISent1aInViewTemporal(b, view)) == PrimaryMaxBallotISent1aInView(b[i], view) { stepmap(imap i :: PrimaryMaxBallotISent1aInView(b[i], view)) } predicate PrimarySent1aInView( ps:RslState, ps':RslState, view:Ballot ) { exists ios :: && 0 <= view.proposer_id < |ps.replicas| && 0 <= view.proposer_id < |ps'.replicas| && var idx := view.proposer_id; var s := ps.replicas[idx].replica.proposer; var s' := ps'.replicas[idx].replica.proposer; && RslNextOneReplica(ps, ps', view.proposer_id, ios) && LProposerMaybeEnterNewViewAndSend1a(s, s', ExtractSentPacketsFromIos(ios)) && s.election_state.current_view.proposer_id == s.constants.my_index && BalLt(s.max_ballot_i_sent_1a, s.election_state.current_view) && s.election_state.current_view == view } function{:opaque} PrimarySent1aInViewTemporal( b:Behavior, view:Ballot ):temporal requires imaptotal(b) ensures forall i{:trigger sat(i, PrimarySent1aInViewTemporal(b, view))} :: sat(i, PrimarySent1aInViewTemporal(b, view)) == PrimarySent1aInView(b[i], b[nextstep(i)], view) { stepmap(imap i :: PrimarySent1aInView(b[i], b[nextstep(i)], view)) } lemma lemma_StablePeriodStartedLeadsToPrimaryInView( b:Behavior, asp:AssumptionParameters, start_step:int, processing_bound:int, view:Ballot, ahead_idx:int ) requires LivenessAssumptions(b, asp) requires PacketProcessingSynchronous(b, asp, start_step, processing_bound) ensures sat(start_step, leadstowithin(StablePeriodStartedTemporal(b, asp.live_quorum, view, ahead_idx), or(PrimaryInViewTemporal(b, view), not(NoReplicaBeyondViewTemporal(b, view))), TimeForOneReplicaToAdvanceAnother(asp, processing_bound), PaxosTimeMap(b))) { var x := StablePeriodStartedTemporal(b, asp.live_quorum, view, ahead_idx); var y := or(PrimaryInViewTemporal(b, view), not(NoReplicaBeyondViewTemporal(b, view))); var t := TimeForOneReplicaToAdvanceAnother(asp, processing_bound); var timefun := PaxosTimeMap(b); var primary_idx := view.proposer_id; forall i | start_step <= i ensures sat(i, imply(x, eventuallywithin(y, t, timefun))) { if sat(i, x) { lemma_IfPacketProcessingSynchronousThenAlways(b, asp, start_step, i, processing_bound); var j := lemma_OneLiveReplicaSoonAdvancesAnother(b, asp, i, processing_bound, i, ahead_idx, primary_idx); assert timefun[j] <= timefun[i] + t; assert BalLeq(view, CurrentViewOfHost(b[j], primary_idx)); if CurrentViewOfHost(b[j], primary_idx) == view { assert sat(j, PrimaryInViewTemporal(b, view)); } else { assert !BalLeq(CurrentViewOfHost(b[j], primary_idx), view); assert sat(j, not(NoReplicaBeyondViewTemporal(b, view))); } assert sat(j, y); assert sat(j, beforeabsolutetime(y, timefun[i] + t, timefun)); TemporalEventually(i, j, beforeabsolutetime(y, timefun[i] + t, timefun)); } } TemporalAlways(start_step, imply(x, eventuallywithin(y, t, timefun))); } lemma lemma_StablePeriodStartedLeadsToPrimaryInViewAlt( b:Behavior, asp:AssumptionParameters, start_step:int, processing_bound:int, view:Ballot, ahead_idx:int ) returns ( step:int ) requires LivenessAssumptions(b, asp) requires PacketProcessingSynchronous(b, asp, start_step, processing_bound) requires sat(start_step, StablePeriodStartedTemporal(b, asp.live_quorum, view, ahead_idx)) ensures start_step <= step ensures sat(step, or(PrimaryInViewTemporal(b, view), not(NoReplicaBeyondViewTemporal(b, view)))) ensures b[step].environment.time <= b[start_step].environment.time + TimeForOneReplicaToAdvanceAnother(asp, processing_bound) { var primary_idx := view.proposer_id; step := lemma_OneLiveReplicaSoonAdvancesAnother(b, asp, start_step, processing_bound, start_step, ahead_idx, primary_idx); assert BalLeq(view, CurrentViewOfHost(b[step], primary_idx)); if CurrentViewOfHost(b[step], primary_idx) == view { assert sat(step, PrimaryInViewTemporal(b, view)); } else { assert !BalLeq(CurrentViewOfHost(b[step], primary_idx), view); assert sat(step, not(NoReplicaBeyondViewTemporal(b, view))); } } lemma lemma_PrimaryInViewLeadsToPrimaryMaxBallotISent1aInViewWF1Req1( b:Behavior, asp:AssumptionParameters, start_step:int, view:Ballot ) requires LivenessAssumptions(b, asp) requires 0 <= start_step ensures var P := PrimaryInViewTemporal(b, view); var Q := or(PrimaryMaxBallotISent1aInViewTemporal(b, view), not(NoReplicaBeyondViewTemporal(b, view))); sat(start_step, always(TemporalWF1Req1(P, Q))) { var primary_idx := view.proposer_id; var P := PrimaryInViewTemporal(b, view); var Q := or(PrimaryMaxBallotISent1aInViewTemporal(b, view), not(NoReplicaBeyondViewTemporal(b, view))); forall i | start_step <= i ensures sat(i, TemporalWF1Req1(P, Q)) { if sat(i, P) && !sat(i, Q) && !sat(i+1, P) && !sat(i+1, Q) { lemma_ConstantsAllConsistent(b, asp.c, i); lemma_ConstantsAllConsistent(b, asp.c, i+1); assert BalLeq(CurrentViewOfHost(b[i+1], primary_idx), view); lemma_ViewOfHostMonotonic(b, asp, primary_idx, i, i+1); assert !NoReplicaBeyondView(b[i+1], view); } } TemporalAlways(start_step, TemporalWF1Req1(P, Q)); } lemma lemma_PrimaryInViewLeadsToPrimaryMaxBallotISent1aInViewWF1Req2( b:Behavior, asp:AssumptionParameters, start_step:int, view:Ballot ) requires LivenessAssumptions(b, asp) requires 0 <= start_step ensures var P := PrimaryInViewTemporal(b, view); var Q := or(PrimaryMaxBallotISent1aInViewTemporal(b, view), not(NoReplicaBeyondViewTemporal(b, view))); var Action := MakeRslActionTemporalFromSpontaneousReplicaFunction(b, LReplicaNextSpontaneousMaybeEnterNewViewAndSend1a, view.proposer_id); sat(start_step, always(TemporalWF1Req2(P, Q, Action))) { var primary_idx := view.proposer_id; var P := PrimaryInViewTemporal(b, view); var Q := or(PrimaryMaxBallotISent1aInViewTemporal(b, view), not(NoReplicaBeyondViewTemporal(b, view))); var Action := MakeRslActionTemporalFromSpontaneousReplicaFunction(b, LReplicaNextSpontaneousMaybeEnterNewViewAndSend1a, primary_idx); forall i | start_step <= i ensures sat(i, TemporalWF1Req2(P, Q, Action)) { if sat(i, P) && sat(i, Action) && !sat(i, Q) && !sat(i+1, Q) { lemma_ConstantsAllConsistent(b, asp.c, i); lemma_ConstantsAllConsistent(b, asp.c, i+1); assert SpecificSpontaneousRslActionOccurs(b[i], b[i+1], LReplicaNextSpontaneousMaybeEnterNewViewAndSend1a, primary_idx); var ios :| && RslNextOneReplica(b[i], b[i+1], primary_idx, ios) && SpontaneousIos(ios, 0) && LReplicaNextSpontaneousMaybeEnterNewViewAndSend1a(b[i].replicas[primary_idx].replica, b[i+1].replicas[primary_idx].replica, ExtractSentPacketsFromIos(ios)); lemma_NoReplicaBeyondViewImpliesNoMaxBallotISent1aBeyondView(b, asp, i, view); assert BalLeq(b[i].replicas[primary_idx].replica.proposer.max_ballot_i_sent_1a, view); assert false; } } TemporalAlways(start_step, TemporalWF1Req2(P, Q, Action)); } lemma lemma_PrimaryInViewLeadsToPrimaryMaxBallotISent1aInView( b:Behavior, asp:AssumptionParameters, start_step:int, view:Ballot ) requires LivenessAssumptions(b, asp) requires asp.synchrony_start <= start_step requires view.proposer_id in asp.live_quorum ensures sat(start_step, leadstowithin(PrimaryInViewTemporal(b, view), or(PrimaryMaxBallotISent1aInViewTemporal(b, view), not(NoReplicaBeyondViewTemporal(b, view))), TimeToPerformGenericAction(asp), PaxosTimeMap(b))) { var timefun := PaxosTimeMap(b); var primary_idx := view.proposer_id; var P := PrimaryInViewTemporal(b, view); var Q := or(PrimaryMaxBallotISent1aInViewTemporal(b, view), not(NoReplicaBeyondViewTemporal(b, view))); var Action := MakeRslActionTemporalFromSpontaneousReplicaFunction(b, LReplicaNextSpontaneousMaybeEnterNewViewAndSend1a, primary_idx); var t := TimeToPerformGenericAction(asp); lemma_PrimaryInViewLeadsToPrimaryMaxBallotISent1aInViewWF1Req1(b, asp, start_step, view); lemma_PrimaryInViewLeadsToPrimaryMaxBallotISent1aInViewWF1Req2(b, asp, start_step, view); lemma_ReplicaNextPerformsSubactionPeriodically(b, asp, primary_idx, 1); lemma_EstablishRequirementsForWF1RealTime(b, asp, start_step, Action, t); TemporalWF1RealTime(start_step, P, Q, Action, t, timefun); } lemma lemma_StablePeriodStartedLeadsToPrimaryMaxBallotISent1aInView( b:Behavior, asp:AssumptionParameters, start_step:int, processing_bound:int, view:Ballot, ahead_idx:int ) requires LivenessAssumptions(b, asp) requires PacketProcessingSynchronous(b, asp, start_step, processing_bound) requires view.proposer_id in asp.live_quorum ensures sat(start_step, leadstowithin(StablePeriodStartedTemporal(b, asp.live_quorum, view, ahead_idx), or(PrimaryMaxBallotISent1aInViewTemporal(b, view), not(NoReplicaBeyondViewTemporal(b, view))), TimeForOneReplicaToAdvanceAnother(asp, processing_bound) + TimeToPerformGenericAction(asp), PaxosTimeMap(b))) { var w := StablePeriodStartedTemporal(b, asp.live_quorum, view, ahead_idx); var x := PrimaryInViewTemporal(b, view); var y := PrimaryMaxBallotISent1aInViewTemporal(b, view); var z := not(NoReplicaBeyondViewTemporal(b, view)); var t1 := TimeForOneReplicaToAdvanceAnother(asp, processing_bound); var t2 := TimeToPerformGenericAction(asp); lemma_StablePeriodStartedLeadsToPrimaryInView(b, asp, start_step, processing_bound, view, ahead_idx); lemma_PrimaryInViewLeadsToPrimaryMaxBallotISent1aInView(b, asp, start_step, view); Lemma_LeadsToTwoPossibilitiesWithin(start_step, w, x, y, z, t1, t2, PaxosTimeMap(b)); assert sat(start_step, leadstowithin(w, or(y, z), t1 + t2, PaxosTimeMap(b))); } lemma lemma_IfPrimaryTransitionsToMaxBallotISent1aInViewThenPrimarySent1a( b:Behavior, asp:AssumptionParameters, i:int, view:Ballot ) requires LivenessAssumptions(b, asp) requires 0 <= i requires !sat(i, PrimaryMaxBallotISent1aInViewTemporal(b, view)) requires sat(i+1, PrimaryMaxBallotISent1aInViewTemporal(b, view)) ensures sat(i, PrimarySent1aInViewTemporal(b, view)) { lemma_ConstantsAllConsistent(b, asp.c, i); lemma_ConstantsAllConsistent(b, asp.c, i+1); var idx := view.proposer_id; var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, i, idx); assert PrimarySent1aInView(b[i], b[i+1], view); } lemma lemma_StablePeriodStartedLeadsToPrimarySending1a( b:Behavior, asp:AssumptionParameters, start_step:int, processing_bound:int, view:Ballot, ahead_idx:int ) requires LivenessAssumptions(b, asp) requires PacketProcessingSynchronous(b, asp, start_step, processing_bound) requires view.proposer_id in asp.live_quorum ensures var t := TimeForOneReplicaToAdvanceAnother(asp, processing_bound) + TimeToPerformGenericAction(asp); var f := PaxosTimeMap(b); sat(start_step, always(imply(StablePeriodStartedTemporal(b, asp.live_quorum, view, ahead_idx), or(eventuallynextwithin(PrimarySent1aInViewTemporal(b, view), t, f), eventuallywithin(not(NoReplicaBeyondViewTemporal(b, view)), t, f))))) { var t := TimeForOneReplicaToAdvanceAnother(asp, processing_bound) + TimeToPerformGenericAction(asp); var f := PaxosTimeMap(b); var x := StablePeriodStartedTemporal(b, asp.live_quorum, view, ahead_idx); var y := PrimaryMaxBallotISent1aInViewTemporal(b, view); var z := not(NoReplicaBeyondViewTemporal(b, view)); var w := PrimarySent1aInViewTemporal(b, view); lemma_StablePeriodStartedLeadsToPrimaryMaxBallotISent1aInView(b, asp, start_step, processing_bound, view, ahead_idx); lemma_TimeMonotonicFromInvariantHolds(b, asp, start_step); TemporalAlways(start_step, imply(x, not(y))); Lemma_LeadsToWithinOrSomethingLeadsToTransitionOrSomething(start_step, x, y, z, t, f); forall j | start_step <= j ensures sat(j, imply(x, or(eventuallynextwithin(w, t, f), eventuallywithin(z, t, f)))) { TemporalDeduceFromAlways(start_step, j, imply(x, or(eventuallynextwithin(and(not(y), next(y)), t, f), eventuallywithin(z, t, f)))); if sat(j, x) && !sat(j, eventuallywithin(z, t, f)) { assert sat(j, eventuallynextwithin(and(not(y), next(y)), t, f)); var k := TemporalDeduceFromEventual(j, nextbefore(and(not(y), next(y)), f[j] + t, f)); lemma_IfPrimaryTransitionsToMaxBallotISent1aInViewThenPrimarySent1a(b, asp, k, view); TemporalEventually(j, k, nextbefore(w, f[j] + t, f)); } } TemporalAlways(start_step, imply(x, or(eventuallynextwithin(w, t, f), eventuallywithin(z, t, f)))); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/LivenessProof/Phase1b.i.dfy ================================================ include "Assumptions.i.dfy" include "Invariants.i.dfy" include "StablePeriod.i.dfy" include "ViewAdvance.i.dfy" include "MaxBallotISent1a.i.dfy" include "MaxBallot.i.dfy" include "PacketHandling.i.dfy" include "Phase1a.i.dfy" include "../CommonProof/MaxBallotISent1a.i.dfy" include "../CommonProof/MaxBallot.i.dfy" include "../CommonProof/Constants.i.dfy" include "../../../Common/Framework/EnvironmentSynchronyLemmas.i.dfy" module LivenessProof__Phase1b_i { import opened LiveRSL__Broadcast_i import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Environment_i import opened LiveRSL__Message_i import opened LiveRSL__Proposer_i import opened LiveRSL__Replica_i import opened LiveRSL__Types_i import opened LivenessProof__Assumptions_i import opened LivenessProof__Invariants_i import opened LivenessProof__MaxBallotISent1a_i import opened LivenessProof__MaxBallot_i import opened LivenessProof__PacketHandling_i import opened LivenessProof__Phase1a_i import opened LivenessProof__RealTime_i import opened LivenessProof__RoundRobin_i import opened LivenessProof__StablePeriod_i import opened LivenessProof__ViewAdvance_i import opened LivenessProof__ViewChange_i import opened CommonProof__Actions_i import opened CommonProof__Constants_i import opened CommonProof__MaxBallotISent1a_i import opened CommonProof__MaxBallot_i import opened CommonProof__PacketSending_i import opened Liveness__EnvironmentSynchronyLemmas_i import opened Temporal__Induction_i import opened Temporal__LeadsTo_i import opened Temporal__Rules_i import opened Temporal__Temporal_s import opened Temporal__Time_s import opened Environment_s import opened Collections__Maps2_s predicate PrimaryInState1or2( ps:RslState, view:Ballot ) { && 0 <= view.proposer_id < |ps.replicas| && ps.replicas[view.proposer_id].replica.proposer.max_ballot_i_sent_1a == view && (ps.replicas[view.proposer_id].replica.proposer.current_state == 1 || ps.replicas[view.proposer_id].replica.proposer.current_state == 2) } function{:opaque} PrimaryInState1or2Temporal( b:Behavior, view:Ballot ):temporal requires imaptotal(b) ensures forall i{:trigger sat(i, PrimaryInState1or2Temporal(b, view))} :: sat(i, PrimaryInState1or2Temporal(b, view)) == PrimaryInState1or2(b[i], view) { stepmap(imap i :: PrimaryInState1or2(b[i], view)) } predicate PrimaryInState2( ps:RslState, view:Ballot ) { && 0 <= view.proposer_id < |ps.replicas| && ps.replicas[view.proposer_id].replica.proposer.max_ballot_i_sent_1a == view && ps.replicas[view.proposer_id].replica.proposer.current_state == 2 } function{:opaque} PrimaryInState2Temporal( b:Behavior, view:Ballot ):temporal requires imaptotal(b) ensures forall i{:trigger sat(i, PrimaryInState2Temporal(b, view))} :: sat(i, PrimaryInState2Temporal(b, view)) == PrimaryInState2(b[i], view) { stepmap(imap i :: PrimaryInState2(b[i], view)) } predicate AcceptorHasMaxBalInView( ps:RslState, view:Ballot, idx:int ) { && 0 <= idx < |ps.replicas| && ps.replicas[idx].replica.acceptor.max_bal == view } function{:opaque} AcceptorHasMaxBalInViewTemporal( b:Behavior, view:Ballot, idx:int ):temporal requires imaptotal(b) ensures forall i{:trigger sat(i, AcceptorHasMaxBalInViewTemporal(b, view, idx))} :: sat(i, AcceptorHasMaxBalInViewTemporal(b, view, idx)) == AcceptorHasMaxBalInView(b[i], view, idx) { stepmap(imap i :: AcceptorHasMaxBalInView(b[i], view, idx)) } predicate PrimaryHasSpecific1bFromAcceptorInView( ps:RslState, view:Ballot, idx:int, p:RslPacket ) requires 0 <= view.proposer_id < |ps.replicas| requires 0 <= idx < |ps.constants.config.replica_ids| { && p in ps.replicas[view.proposer_id].replica.proposer.received_1b_packets && p.msg.RslMessage_1b? && p.msg.bal_1b == view && p.src == ps.constants.config.replica_ids[idx] && ps.replicas[view.proposer_id].replica.proposer.max_ballot_i_sent_1a == view && ps.replicas[view.proposer_id].replica.proposer.current_state == 1 } predicate PrimaryHas1bFromAcceptorInView( ps:RslState, view:Ballot, idx:int ) { && 0 <= view.proposer_id < |ps.replicas| && 0 <= idx < |ps.constants.config.replica_ids| && exists p :: PrimaryHasSpecific1bFromAcceptorInView(ps, view, idx, p) } function{:opaque} PrimaryHas1bFromAcceptorInViewTemporal( b:Behavior, view:Ballot, idx:int ):temporal requires imaptotal(b) ensures forall i{:trigger sat(i, PrimaryHas1bFromAcceptorInViewTemporal(b, view, idx))} :: sat(i, PrimaryHas1bFromAcceptorInViewTemporal(b, view, idx)) == PrimaryHas1bFromAcceptorInView(b[i], view, idx) { stepmap(imap i :: PrimaryHas1bFromAcceptorInView(b[i], view, idx)) } lemma{:timeLimitMultiplier 3} lemma_PrimarySending1aLeadsToAcceptorSettingMaxBal( b:Behavior, asp:AssumptionParameters, start_step:int, processing_bound:int, view:Ballot, idx:int ) requires LivenessAssumptions(b, asp) requires PacketProcessingSynchronous(b, asp, start_step, processing_bound) requires view.proposer_id in asp.live_quorum requires idx in asp.live_quorum ensures sat(start_step, always(imply(PrimarySent1aInViewTemporal(b, view), next(eventuallywithin(or(AcceptorHasMaxBalInViewTemporal(b, view, idx), not(NoReplicaBeyondViewTemporal(b, view))), processing_bound, PaxosTimeMap(b)))))) { var primary_idx := view.proposer_id; var x := PrimarySent1aInViewTemporal(b, view); var y := AcceptorHasMaxBalInViewTemporal(b, view, idx); var z := not(NoReplicaBeyondViewTemporal(b, view)); var t := processing_bound; var f := PaxosTimeMap(b); forall j | start_step <= j ensures sat(j, imply(x, next(eventuallywithin(or(y, z), t, f)))) { if sat(j, x) { lemma_ConstantsAllConsistent(b, asp.c, j); lemma_ConstantsAllConsistent(b, asp.c, j+1); var ps := b[j]; var ps' := b[j+1]; var s := ps.replicas[primary_idx].replica.proposer; var s' := ps'.replicas[primary_idx].replica.proposer; var ios :| && RslNextOneReplica(ps, ps', view.proposer_id, ios) && LProposerMaybeEnterNewViewAndSend1a(s, s', ExtractSentPacketsFromIos(ios)) && s.election_state.current_view.proposer_id == s.constants.my_index && BalLt(s.max_ballot_i_sent_1a, s.election_state.current_view) && s.election_state.current_view == view; var sent_packets := ExtractSentPacketsFromIos(ios); assert LBroadcastToEveryone(s.constants.all.config, s.constants.my_index, RslMessage_1a(s.election_state.current_view), sent_packets); var p := LPacket(s.constants.all.config.replica_ids[idx], s.constants.all.config.replica_ids[s.constants.my_index], RslMessage_1a(s.election_state.current_view)); assert p in sent_packets; var k, ios' := lemma_PacketSentToIndexProcessedByIt(b, asp, start_step, t, j, idx, p); lemma_ConstantsAllConsistent(b, asp.c, k); lemma_ConstantsAllConsistent(b, asp.c, k+1); assert BalLeq(view, b[k+1].replicas[idx].replica.acceptor.max_bal); if !sat(k+1, or(y, z)) { lemma_NoReplicaBeyondViewImpliesNoMaxBallotISent1aBeyondView(b, asp, k+1, view); lemma_DuringStablePeriodNoMaxBalBeyondView(b, asp, k+1, idx, view); assert BalLeq(b[k+1].replicas[idx].replica.acceptor.max_bal, view); assert false; } TemporalEventually(j+1, k+1, beforeabsolutetime(or(y, z), f[j+1] + t, f)); } } TemporalAlways(start_step, imply(x, next(eventuallywithin(or(y, z), t, f)))); } lemma lemma_StablePeriodStartedLeadsToAcceptorSettingMaxBal( b:Behavior, asp:AssumptionParameters, start_step:int, processing_bound:int, view:Ballot, ahead_idx:int, idx:int ) requires LivenessAssumptions(b, asp) requires PacketProcessingSynchronous(b, asp, start_step, processing_bound) requires view.proposer_id in asp.live_quorum requires idx in asp.live_quorum ensures var t := TimeForOneReplicaToAdvanceAnother(asp, processing_bound) + TimeToPerformGenericAction(asp) + processing_bound; sat(start_step, always(imply(StablePeriodStartedTemporal(b, asp.live_quorum, view, ahead_idx), or(eventuallynextwithin(and(not(AcceptorHasMaxBalInViewTemporal(b, view, idx)), next(AcceptorHasMaxBalInViewTemporal(b, view, idx))), t, PaxosTimeMap(b)), eventuallywithin(not(NoReplicaBeyondViewTemporal(b, view)), t, PaxosTimeMap(b)))))) { var w := StablePeriodStartedTemporal(b, asp.live_quorum, view, ahead_idx); var x := PrimarySent1aInViewTemporal(b, view); var y := AcceptorHasMaxBalInViewTemporal(b, view, idx); var z := not(NoReplicaBeyondViewTemporal(b, view)); var t1 := TimeForOneReplicaToAdvanceAnother(asp, processing_bound) + TimeToPerformGenericAction(asp); var t2 := processing_bound; var t := t1 + t2; var f := PaxosTimeMap(b); lemma_StablePeriodStartedLeadsToPrimarySending1a(b, asp, start_step, processing_bound, view, ahead_idx); assert sat(start_step, always(imply(w, or(eventuallynextwithin(x, t1, f), eventuallywithin(z, t1, f))))); lemma_PrimarySending1aLeadsToAcceptorSettingMaxBal(b, asp, start_step, processing_bound, view, idx); assert sat(start_step, always(imply(x, next(eventuallywithin(or(y, z), t2, f))))); Lemma_LeadsToTwoPossibilitiesWithinWithFirstStepAnAction(start_step, w, x, y, z, t1, t2, f); assert sat(start_step, leadstowithin(w, or(y, z), t1+t2, f)); forall j | start_step <= j ensures sat(j, imply(w, not(y))) { if sat(j, w) && sat(j, y) { assert b[j].replicas[idx].replica.acceptor.max_bal == view; lemma_MaxBalLeqMaxBallotPrimarySent1a(b, asp.c, j, idx); assert BalLt(b[j].replicas[view.proposer_id].replica.proposer.max_ballot_i_sent_1a, view); assert false; } } TemporalAlways(start_step, imply(w, not(y))); lemma_TimeMonotonicFromInvariantHolds(b, asp, start_step); Lemma_LeadsToWithinOrSomethingLeadsToTransitionOrSomething(start_step, w, y, z, t1 + t2, f); } lemma lemma_IfPrimaryInState2ItsAlwaysAtLeastThere( b:Behavior, asp:AssumptionParameters, i:int, view:Ballot ) requires LivenessAssumptions(b, asp) requires 0 <= i requires var t := or(PrimaryInState2Temporal(b, view), not(NoReplicaBeyondViewTemporal(b, view))); sat(i, t) ensures var t := or(PrimaryInState2Temporal(b, view), not(NoReplicaBeyondViewTemporal(b, view))); sat(i, always(t)) { var x := PrimaryInState2Temporal(b, view); var y := not(NoReplicaBeyondViewTemporal(b, view)); var t := or(x, y); forall j | i <= j ensures sat(j, imply(t, next(t))) { lemma_ConstantsAllConsistent(b, asp.c, j); if sat(j, t) { if sat(j, y) { var idx :| 0 <= idx < |b[j].replicas| && !BalLeq(CurrentViewOfHost(b[j], idx), view); lemma_ViewOfHostMonotonic(b, asp, idx, j, j+1); assert sat(j, next(t)); } else { assert sat(j, x); if !sat(j+1, t) { lemma_BalLtProperties(); lemma_ConstantsAllConsistent(b, asp.c, j+1); var primary_idx := view.proposer_id; var s := b[j].replicas[primary_idx].replica; var s' := b[j+1].replicas[primary_idx].replica; lemma_MaxBallotISent1aMonotonicOneStep(b, asp.c, j, primary_idx); assert BalLeq(s.proposer.max_ballot_i_sent_1a, s'.proposer.max_ballot_i_sent_1a); assert BalLeq(view, s'.proposer.max_ballot_i_sent_1a); lemma_MaxBallotISent1aLeqView(b, asp, j+1, primary_idx); assert BalLeq(s'.proposer.max_ballot_i_sent_1a, CurrentViewOfHost(b[j+1], primary_idx)); assert BalLeq(view, CurrentViewOfHost(b[j+1], primary_idx)); lemma_ViewOfHostMonotonic(b, asp, primary_idx, j, j+1); assert BalLeq(CurrentViewOfHost(b[j+1], primary_idx), view); assert CurrentViewOfHost(b[j+1], primary_idx) == view; assert BalLeq(CurrentViewOfHost(b[j], primary_idx), view); lemma_MaxBallotISent1aLeqView(b, asp, j, primary_idx); assert BalLeq(view, CurrentViewOfHost(b[j], primary_idx)); assert s'.proposer.election_state.current_view == s.proposer.election_state.current_view; var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, j, primary_idx); assert s.proposer.current_state == 2; assert s'.proposer.current_state != 2; assert false; } } } reveal imply(); reveal next(); } TemporalInductionNext(i, t); } lemma lemma_If2aMessageSentThenPrimaryInState2( b:Behavior, asp:AssumptionParameters, i:int, p:RslPacket, view:Ballot ) requires LivenessAssumptions(b, asp) requires 0 <= i requires p.msg.RslMessage_2a? requires p.msg.bal_2a == view requires 0 <= view.proposer_id < |asp.c.config.replica_ids| requires p.src in asp.c.config.replica_ids requires p in b[i].environment.sentPackets ensures p.src == asp.c.config.replica_ids[view.proposer_id] ensures var t := or(PrimaryInState2Temporal(b, view), not(NoReplicaBeyondViewTemporal(b, view))); sat(i, always(t)) decreases i { var t := or(PrimaryInState2Temporal(b, view), not(NoReplicaBeyondViewTemporal(b, view))); if i == 0 { assert |b[i].environment.sentPackets| == 0; assert false; } else if p in b[i-1].environment.sentPackets { lemma_If2aMessageSentThenPrimaryInState2(b, asp, i-1, p, view); Lemma_AlwaysImpliesLaterAlways(i-1, i, t); } else { lemma_AssumptionsMakeValidTransition(b, asp.c, i-1); lemma_ConstantsAllConsistent(b, asp.c, i-1); var idx, ios := lemma_ActionThatSends2aIsMaybeNominateValueAndSend2a(b[i-1], b[i], p); assert asp.c.config.replica_ids[idx] == p.src; lemma_MaxBallotISent1aHasMeAsProposer(b, asp.c, i, idx); assert PrimaryInState2(b[i-1], view); assert sat(i-1, PrimaryInState2Temporal(b, view)); lemma_IfPrimaryInState2ItsAlwaysAtLeastThere(b, asp, i-1, view); Lemma_AlwaysImpliesLaterAlways(i-1, i, t); } } lemma lemma_IfPrimaryInState1or2ItsAlwaysAtLeastThere( b:Behavior, asp:AssumptionParameters, i:int, view:Ballot ) requires LivenessAssumptions(b, asp) requires 0 <= i requires var t := or(PrimaryInState1or2Temporal(b, view), not(NoReplicaBeyondViewTemporal(b, view))); sat(i, t) ensures var t := or(PrimaryInState1or2Temporal(b, view), not(NoReplicaBeyondViewTemporal(b, view))); sat(i, always(t)) { var x := PrimaryInState1or2Temporal(b, view); var y := not(NoReplicaBeyondViewTemporal(b, view)); var t := or(x, y); forall j | i <= j ensures sat(j, imply(t, next(t))) { lemma_ConstantsAllConsistent(b, asp.c, j); if sat(j, t) { if sat(j, y) { var idx :| 0 <= idx < |b[j].replicas| && !BalLeq(CurrentViewOfHost(b[j], idx), view); lemma_ViewOfHostMonotonic(b, asp, idx, j, j+1); assert sat(j, next(t)); } else { assert sat(j, x); if !sat(j+1, t) { lemma_BalLtProperties(); lemma_ConstantsAllConsistent(b, asp.c, j+1); var primary_idx := view.proposer_id; var s := b[j].replicas[primary_idx].replica; var s' := b[j+1].replicas[primary_idx].replica; lemma_MaxBallotISent1aMonotonicOneStep(b, asp.c, j, primary_idx); assert BalLeq(s.proposer.max_ballot_i_sent_1a, s'.proposer.max_ballot_i_sent_1a); assert BalLeq(view, s'.proposer.max_ballot_i_sent_1a); lemma_MaxBallotISent1aLeqView(b, asp, j+1, primary_idx); assert BalLeq(s'.proposer.max_ballot_i_sent_1a, CurrentViewOfHost(b[j+1], primary_idx)); assert BalLeq(view, CurrentViewOfHost(b[j+1], primary_idx)); lemma_ViewOfHostMonotonic(b, asp, primary_idx, j, j+1); assert BalLeq(CurrentViewOfHost(b[j+1], primary_idx), view); assert CurrentViewOfHost(b[j+1], primary_idx) == view; assert BalLeq(CurrentViewOfHost(b[j], primary_idx), view); lemma_MaxBallotISent1aLeqView(b, asp, j, primary_idx); assert BalLeq(view, CurrentViewOfHost(b[j], primary_idx)); assert s'.proposer.election_state.current_view == s.proposer.election_state.current_view; var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, j, primary_idx); assert s.proposer.current_state >= 2; assert s'.proposer.current_state == 0; assert false; } } } reveal imply(); reveal next(); } TemporalInductionNext(i, t); } lemma lemma_If1aMessageSentThenPrimaryInState1or2( b:Behavior, asp:AssumptionParameters, i:int, p:RslPacket, view:Ballot ) requires LivenessAssumptions(b, asp) requires 0 <= i requires p.msg.RslMessage_1a? requires p.msg.bal_1a == view requires 0 <= view.proposer_id < |asp.c.config.replica_ids| requires p.src in asp.c.config.replica_ids requires p in b[i].environment.sentPackets ensures p.src == asp.c.config.replica_ids[view.proposer_id] ensures var t := or(PrimaryInState1or2Temporal(b, view), not(NoReplicaBeyondViewTemporal(b, view))); sat(i, always(t)) decreases i { var t := or(PrimaryInState1or2Temporal(b, view), not(NoReplicaBeyondViewTemporal(b, view))); if i == 0 { assert |b[i].environment.sentPackets| == 0; assert false; } else if p in b[i-1].environment.sentPackets { lemma_If1aMessageSentThenPrimaryInState1or2(b, asp, i-1, p, view); Lemma_AlwaysImpliesLaterAlways(i-1, i, t); } else { lemma_AssumptionsMakeValidTransition(b, asp.c, i-1); lemma_ConstantsAllConsistent(b, asp.c, i-1); var idx, ios := lemma_ActionThatSends1aIsMaybeEnterNewViewAndSend1a(b[i-1], b[i], p); assert asp.c.config.replica_ids[idx] == p.src; lemma_MaxBallotISent1aHasMeAsProposer(b, asp.c, i, idx); assert sat(i, PrimaryInState1or2Temporal(b, view)); lemma_IfPrimaryInState1or2ItsAlwaysAtLeastThere(b, asp, i, view); } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/LivenessProof/Phase1bCont.i.dfy ================================================ include "Assumptions.i.dfy" include "Invariants.i.dfy" include "StablePeriod.i.dfy" include "ViewAdvance.i.dfy" include "MaxBallotISent1a.i.dfy" include "MaxBallot.i.dfy" include "PacketHandling.i.dfy" include "Phase1b.i.dfy" include "../CommonProof/MaxBallotISent1a.i.dfy" include "../CommonProof/MaxBallot.i.dfy" include "../CommonProof/Constants.i.dfy" include "../../../Common/Framework/EnvironmentSynchronyLemmas.i.dfy" include "../../../Common/Logic/Temporal/Sets.i.dfy" include "../../../Common/Collections/Sets.i.dfy" module LivenessProof__Phase1bCont_i { import opened LiveRSL__Acceptor_i import opened LiveRSL__Configuration_i import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Environment_i import opened LiveRSL__Message_i import opened LiveRSL__Proposer_i import opened LiveRSL__Replica_i import opened LiveRSL__Types_i import opened LivenessProof__Assumptions_i import opened LivenessProof__Invariants_i import opened LivenessProof__MaxBallotISent1a_i import opened LivenessProof__MaxBallot_i import opened LivenessProof__PacketHandling_i import opened LivenessProof__Phase1a_i import opened LivenessProof__Phase1b_i import opened LivenessProof__RealTime_i import opened LivenessProof__RoundRobin_i import opened LivenessProof__StablePeriod_i import opened LivenessProof__ViewAdvance_i import opened LivenessProof__ViewChange_i import opened LivenessProof__WF1_i import opened CommonProof__Actions_i import opened CommonProof__Constants_i import opened CommonProof__MaxBallotISent1a_i import opened CommonProof__MaxBallot_i import opened Liveness__EnvironmentSynchronyLemmas_i import opened Temporal__Heuristics_i import opened Temporal__Induction_i import opened Temporal__LeadsTo_i import opened Temporal__Rules_i import opened Temporal__Sets_i import opened Temporal__Temporal_s import opened Temporal__Time_s import opened Temporal__Time_i import opened Temporal__WF1_i import opened Collections__Sets_i import opened Collections__Maps2_s import opened Collections__Maps2_i import opened Environment_s predicate AcceptorSent1bInView( ps:RslState, ps':RslState, view:Ballot, idx:int ) { && PrimaryInState1or2(ps, view) && 0 <= idx < |ps.replicas| && 0 <= idx < |ps'.replicas| && ps.environment.nextStep.LEnvStepHostIos? && var ios := ps.environment.nextStep.ios; var s := ps.replicas[idx].replica.acceptor; var s' := ps'.replicas[idx].replica.acceptor; && RslNextOneReplica(ps, ps', idx, ios) && |ios| > 0 && ios[0].LIoOpReceive? && ios[0].r.msg.RslMessage_1a? && ios[0].r.msg.bal_1a == view && BalLt(s.max_bal, view) && s'.max_bal == view && LAcceptorProcess1a(s, s', ios[0].r, ExtractSentPacketsFromIos(ios)) } function{:opaque} AcceptorSent1bInViewTemporal( b:Behavior, view:Ballot, idx:int ):temporal requires imaptotal(b) ensures forall i{:trigger sat(i, AcceptorSent1bInViewTemporal(b, view, idx))} :: sat(i, AcceptorSent1bInViewTemporal(b, view, idx)) == AcceptorSent1bInView(b[i], b[nextstep(i)], view, idx) { stepmap(imap i :: AcceptorSent1bInView(b[i], b[nextstep(i)], view, idx)) } function PrimaryHas1bFromAcceptorOrIsPastPhase1Temporal( b:Behavior, view:Ballot, idx:int ):temporal requires imaptotal(b) { or(PrimaryHas1bFromAcceptorInViewTemporal(b, view, idx), or(PrimaryInState2Temporal(b, view), not(NoReplicaBeyondViewTemporal(b, view)))) } lemma lemma_StablePeriodStartedLeadsToAcceptorSending1b( b:Behavior, asp:AssumptionParameters, start_step:int, processing_bound:int, view:Ballot, ahead_idx:int, idx:int ) requires LivenessAssumptions(b, asp) requires PacketProcessingSynchronous(b, asp, start_step, processing_bound) requires view.proposer_id in asp.live_quorum requires idx in asp.live_quorum ensures var t := TimeForOneReplicaToAdvanceAnother(asp, processing_bound) + TimeToPerformGenericAction(asp) + processing_bound; var f := PaxosTimeMap(b); sat(start_step, always(imply(StablePeriodStartedTemporal(b, asp.live_quorum, view, ahead_idx), or(eventuallynextwithin(AcceptorSent1bInViewTemporal(b, view, idx), t, f), eventuallywithin(or(PrimaryInState2Temporal(b, view), not(NoReplicaBeyondViewTemporal(b, view))), t, f))))) { var t := TimeForOneReplicaToAdvanceAnother(asp, processing_bound) + TimeToPerformGenericAction(asp) + processing_bound; var f := PaxosTimeMap(b); var a := AcceptorHasMaxBalInViewTemporal(b, view, idx); var w := StablePeriodStartedTemporal(b, asp.live_quorum, view, ahead_idx); var x := AcceptorSent1bInViewTemporal(b, view, idx); var y := PrimaryInState2Temporal(b, view); var z := not(NoReplicaBeyondViewTemporal(b, view)); lemma_StablePeriodStartedLeadsToAcceptorSettingMaxBal(b, asp, start_step, processing_bound, view, ahead_idx, idx); assert sat(start_step, always(imply(w, or(eventuallynextwithin(and(not(a), next(a)), t, f), eventuallywithin(z, t, f))))); forall j | start_step <= j ensures sat(j, imply(w, or(eventuallynextwithin(x, t, f), eventuallywithin(or(y, z), t, f)))) { if sat(j, w) { if sat(j, eventuallywithin(z, t, f)) { var k := TemporalDeduceFromEventuallyWithin(j, z, t, f); TemporalEventuallyWithin(j, k, or(y, z), t, f); } else { TemporalDeduceFromAlways(start_step, j, imply(w, or(eventuallynextwithin(and(not(a), next(a)), t, f), eventuallywithin(z, t, f)))); var k := TemporalDeduceFromEventuallyNextWithin(j, and(not(a), next(a)), t, f); lemma_ConstantsAllConsistent(b, asp.c, k); lemma_ConstantsAllConsistent(b, asp.c, k+1); var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, k, idx); var s := b[k].replicas[idx].replica; assert b[k].replicas[idx].nextActionIndex == 0; assert |ios| > 0; assert ios[0].LIoOpReceive?; lemma_PacketProcessedImpliesPacketSent(b[k], b[k+1], idx, ios, ios[0].r); if ios[0].r.msg.RslMessage_1a? { lemma_If1aMessageSentThenPrimaryInState1or2(b, asp, k, ios[0].r, view); TemporalDeduceFromAlways(k, k, or(PrimaryInState1or2Temporal(b, view), not(NoReplicaBeyondViewTemporal(b, view)))); if sat(k, z) { TemporalEventuallyWithin(j, k, or(y, z), t, f); } else { assert AcceptorSent1bInView(b[k], b[k+1], view, idx); assert sat(k, x); TemporalEventuallyNextWithin(j, k, x, t, f); } } else if ios[0].r.msg.RslMessage_2a? { lemma_If2aMessageSentThenPrimaryInState2(b, asp, k, ios[0].r, view); TemporalDeduceFromAlways(k, k, or(PrimaryInState2Temporal(b, view), not(NoReplicaBeyondViewTemporal(b, view)))); assert sat(k, or(y, z)); TemporalEventuallyWithin(j, k, or(y, z), t, f); } else { assert false; } } } } TemporalAlways(start_step, imply(w, or(eventuallynextwithin(x, t, f), eventuallywithin(or(y, z), t, f)))); } lemma lemma_StablePeriodStartedLeadsToPrimaryGetting1bFromAcceptorHelper( b:Behavior, asp:AssumptionParameters, start_step:int, processing_bound:int, view:Ballot, idx:int, i:int ) returns ( step:int ) requires LivenessAssumptions(b, asp) requires PacketProcessingSynchronous(b, asp, start_step, processing_bound) requires view.proposer_id in asp.live_quorum requires idx in asp.live_quorum requires start_step <= i requires sat(i, AcceptorSent1bInViewTemporal(b, view, idx)) ensures TLe(i, step) ensures sat(step, or(PrimaryHas1bFromAcceptorInViewTemporal(b, view, idx), or(PrimaryInState2Temporal(b, view), not(NoReplicaBeyondViewTemporal(b, view))))) ensures b[step].environment.time <= b[i+1].environment.time + processing_bound { var t := processing_bound; var f := PaxosTimeMap(b); assert sat(i, PrimaryInState1or2Temporal(b, view)); assert AcceptorSent1bInView(b[i], b[i+1], view, idx); lemma_ConstantsAllConsistent(b, asp.c, i); lemma_ConstantsAllConsistent(b, asp.c, i+1); var primary_idx := view.proposer_id; var s := b[i].replicas[idx].replica.acceptor; var s' := b[i+1].replicas[idx].replica.acceptor; var ios:seq :| && RslNextOneReplica(b[i], b[i+1], idx, ios) && |ios| > 0 && ios[0].LIoOpReceive? && ios[0].r.msg.RslMessage_1a? && ios[0].r.msg.bal_1a == view && BalLt(s.max_bal, view) && s'.max_bal == view && LAcceptorProcess1a(s, s', ios[0].r, ExtractSentPacketsFromIos(ios)); var sent_packets := ExtractSentPacketsFromIos(ios); var p := LPacket(ios[0].r.src, s.constants.all.config.replica_ids[s.constants.my_index], RslMessage_1b(view, s.log_truncation_point, s.votes)); assert p in sent_packets; lemma_PacketProcessedImpliesPacketSent(b[i], b[i+1], idx, ios, ios[0].r); lemma_If1aMessageSentThenPrimaryInState1or2(b, asp, i, ios[0].r, view); assert p.dst == asp.c.config.replica_ids[primary_idx]; var j, ios2 := lemma_PacketSentToIndexProcessedByIt(b, asp, start_step, t, i, primary_idx, p); lemma_ConstantsAllConsistent(b, asp.c, j); lemma_ConstantsAllConsistent(b, asp.c, j+1); step := j + 1; var s2 := b[j].replicas[primary_idx].replica; var s2' := b[j+1].replicas[primary_idx].replica; assert PacketProcessedViaIos(b[j], b[j+1], p, primary_idx, ios2); assert LReplicaNextProcess1b(s2, s2', p, ExtractSentPacketsFromIos(ios2)); assert p.src in s2.proposer.constants.all.config.replica_ids; lemma_IfPrimaryInState1or2ItsAlwaysAtLeastThere(b, asp, i, view); TemporalDeduceFromAlways(i, j, or(PrimaryInState1or2Temporal(b, view), not(NoReplicaBeyondViewTemporal(b, view)))); var x := PrimaryHas1bFromAcceptorInViewTemporal(b, view, idx); var y := PrimaryInState2Temporal(b, view); var z := not(NoReplicaBeyondViewTemporal(b, view)); if sat(j, or(y, z)) { step := j; lemma_TimeAdvancesBetween(b, asp, j, j+1); } else { assert s2.proposer.max_ballot_i_sent_1a == view; assert s2.proposer.current_state == 1; step := j + 1; if exists other_packet :: other_packet in s2.proposer.received_1b_packets && other_packet.src == p.src { var other_packet :| other_packet in s2.proposer.received_1b_packets && other_packet.src == p.src; lemma_Received1bPacketsAreFromMaxBallotISent1a(b, asp.c, step, primary_idx); assert other_packet.msg.RslMessage_1b? && other_packet.msg.bal_1b == s2.proposer.max_ballot_i_sent_1a; assert PrimaryHasSpecific1bFromAcceptorInView(b[step], view, idx, other_packet); } else { assert PrimaryHasSpecific1bFromAcceptorInView(b[step], view, idx, p); } assert sat(step, x); } } lemma lemma_StablePeriodStartedLeadsToPrimaryGetting1bFromAcceptor( b:Behavior, asp:AssumptionParameters, start_step:int, processing_bound:int, view:Ballot, ahead_idx:int, idx:int ) requires LivenessAssumptions(b, asp) requires PacketProcessingSynchronous(b, asp, start_step, processing_bound) requires view.proposer_id in asp.live_quorum requires idx in asp.live_quorum ensures var t := TimeForOneReplicaToAdvanceAnother(asp, processing_bound) + TimeToPerformGenericAction(asp) + processing_bound * 2; var f := PaxosTimeMap(b); sat(start_step, leadstowithin(StablePeriodStartedTemporal(b, asp.live_quorum, view, ahead_idx), PrimaryHas1bFromAcceptorOrIsPastPhase1Temporal(b, view, idx), t, f)) { var t1 := TimeForOneReplicaToAdvanceAnother(asp, processing_bound) + TimeToPerformGenericAction(asp) + processing_bound; var t2 := processing_bound; var t := TimeForOneReplicaToAdvanceAnother(asp, processing_bound) + TimeToPerformGenericAction(asp) + processing_bound * 2; var f := PaxosTimeMap(b); var a := AcceptorSent1bInViewTemporal(b, view, idx); var w := StablePeriodStartedTemporal(b, asp.live_quorum, view, ahead_idx); var x := PrimaryHas1bFromAcceptorInViewTemporal(b, view, idx); var y := PrimaryInState2Temporal(b, view); var z := not(NoReplicaBeyondViewTemporal(b, view)); assert t == t1 + t2; lemma_StablePeriodStartedLeadsToAcceptorSending1b(b, asp, start_step, processing_bound, view, ahead_idx, idx); assert sat(start_step, always(imply(w, or(eventuallynextwithin(a, t1, f), eventuallywithin(or(y, z), t1, f))))); TemporalAssist(); forall j | start_step <= j ensures sat(j, imply(w, eventuallywithin(or(x, or(y, z)), t, f))) { if sat(j, w) { TemporalDeduceFromAlways(start_step, j, imply(w, or(eventuallynextwithin(a, t1, f), eventuallywithin(or(y, z), t1, f)))); if sat(j, eventuallywithin(or(y, z), t1, f)) { assert sat(j, eventuallywithin(or(x, or(y, z)), t1, f)); assert sat(j, eventuallywithin(or(x, or(y, z)), t, f)); } else { assert sat(j, eventuallynextwithin(a, t1, f)); var k :| TLe(j, k) && sat(k, nextbefore(a, f[j] + t1, f)); var m := lemma_StablePeriodStartedLeadsToPrimaryGetting1bFromAcceptorHelper(b, asp, start_step, processing_bound, view, idx, k); assert sat(m, beforeabsolutetime(or(x, or(y, z)), f[k+1] + t2, f)); assert sat(m, beforeabsolutetime(or(x, or(y, z)), f[j] + t, f)); } } } } lemma lemma_PrimaryHas1bFromAcceptorOrIsPastPhase1Stable( b:Behavior, asp:AssumptionParameters, i:int, view:Ballot, idx:int ) requires LivenessAssumptions(b, asp) requires 0 <= i requires 0 <= view.proposer_id < |asp.c.config.replica_ids| ensures sat(i, always(imply(PrimaryHas1bFromAcceptorOrIsPastPhase1Temporal(b, view, idx), always(PrimaryHas1bFromAcceptorOrIsPastPhase1Temporal(b, view, idx))))) { var x := PrimaryHas1bFromAcceptorInViewTemporal(b, view, idx); var y := PrimaryInState2Temporal(b, view); var z := not(NoReplicaBeyondViewTemporal(b, view)); var t := PrimaryHas1bFromAcceptorOrIsPastPhase1Temporal(b, view, idx); forall j | i <= j && sat(j, t) ensures sat(j, always(t)) { forall k | j <= k && sat(k, t) && !sat(k+1, t) ensures false { if sat(k, or(y, z)) { lemma_IfPrimaryInState2ItsAlwaysAtLeastThere(b, asp, k, view); TemporalDeduceFromAlways(k, k+1, or(y, z)); assert sat(k+1, t); assert false; } else { assert sat(k, x); var p :| PrimaryHasSpecific1bFromAcceptorInView(b[k], view, idx, p); lemma_ConstantsAllConsistent(b, asp.c, k); lemma_ConstantsAllConsistent(b, asp.c, k+1); var primary_idx := view.proposer_id; var s := b[k].replicas[primary_idx].replica; var s' := b[k+1].replicas[primary_idx].replica; lemma_NoReplicaBeyondViewImpliesNoMaxBallotISent1aBeyondView(b, asp, k, view); lemma_MaxBallotISent1aLeqView(b, asp, k, primary_idx); assert BalLeq(s.proposer.max_ballot_i_sent_1a, s.proposer.election_state.current_view); assert BalLeq(CurrentViewOfHost(b[k], primary_idx), view); assert s.proposer.election_state.current_view == view; lemma_ViewOfHostMonotonic(b, asp, primary_idx, k, k+1); assert BalLeq(s.proposer.election_state.current_view, s'.proposer.election_state.current_view); assert BalLeq(CurrentViewOfHost(b[k+1], primary_idx), view); assert s'.proposer.election_state.current_view == view; lemma_MaxBallotISent1aLeqView(b, asp, k+1, primary_idx); lemma_MaxBallotISent1aMonotonicOneStep(b, asp.c, k, primary_idx); assert s'.proposer.max_ballot_i_sent_1a == view; assert !PrimaryHasSpecific1bFromAcceptorInView(b[k+1], view, idx, p); var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, k, primary_idx); assert false; } } TemporalInductionNext(j, t); } TemporalAlways(i, imply(t, always(t))); } lemma lemma_StablePeriodStartedLeadsToPrimaryGetting1bFromAcceptorForever( b:Behavior, asp:AssumptionParameters, start_step:int, processing_bound:int, view:Ballot, ahead_idx:int, idx:int ) requires LivenessAssumptions(b, asp) requires PacketProcessingSynchronous(b, asp, start_step, processing_bound) requires view.proposer_id in asp.live_quorum requires idx in asp.live_quorum ensures var t := TimeForOneReplicaToAdvanceAnother(asp, processing_bound) + TimeToPerformGenericAction(asp) + processing_bound * 2; var f := PaxosTimeMap(b); sat(start_step, leadstowithin(StablePeriodStartedTemporal(b, asp.live_quorum, view, ahead_idx), always(PrimaryHas1bFromAcceptorOrIsPastPhase1Temporal(b, view, idx)), t, f)) { var t := TimeForOneReplicaToAdvanceAnother(asp, processing_bound) + TimeToPerformGenericAction(asp) + processing_bound * 2; var f := PaxosTimeMap(b); lemma_StablePeriodStartedLeadsToPrimaryGetting1bFromAcceptor(b, asp, start_step, processing_bound, view, ahead_idx, idx); lemma_PrimaryHas1bFromAcceptorOrIsPastPhase1Stable(b, asp, start_step, view, idx); Lemma_LeadsToWithinImpliesLeadsToConsequenceWithin(start_step, StablePeriodStartedTemporal(b, asp.live_quorum, view, ahead_idx), PrimaryHas1bFromAcceptorOrIsPastPhase1Temporal(b, view, idx), always(PrimaryHas1bFromAcceptorOrIsPastPhase1Temporal(b, view, idx)), t, f); } function{:opaque} PrimaryHas1bFromAllLiveAcceptorsOrIsPastPhase1TemporalSet( b:Behavior, live_quorum:set, view:Ballot ):set requires imaptotal(b) ensures forall idx :: idx in live_quorum ==> PrimaryHas1bFromAcceptorOrIsPastPhase1Temporal(b, view, idx) in PrimaryHas1bFromAllLiveAcceptorsOrIsPastPhase1TemporalSet(b, live_quorum, view) ensures forall x :: x in PrimaryHas1bFromAllLiveAcceptorsOrIsPastPhase1TemporalSet(b, live_quorum, view) ==> exists idx :: idx in live_quorum && x == PrimaryHas1bFromAcceptorOrIsPastPhase1Temporal(b, view, idx) { set idx | idx in live_quorum :: PrimaryHas1bFromAcceptorOrIsPastPhase1Temporal(b, view, idx) } lemma lemma_StablePeriodStartedLeadsToPrimaryGetting1bFromEveryLiveAcceptorForever( b:Behavior, asp:AssumptionParameters, start_step:int, processing_bound:int, view:Ballot, ahead_idx:int ) requires LivenessAssumptions(b, asp) requires PacketProcessingSynchronous(b, asp, start_step, processing_bound) requires view.proposer_id in asp.live_quorum ensures var t := TimeForOneReplicaToAdvanceAnother(asp, processing_bound) + TimeToPerformGenericAction(asp) + processing_bound * 2; var f := PaxosTimeMap(b); var xs := PrimaryHas1bFromAllLiveAcceptorsOrIsPastPhase1TemporalSet(b, asp.live_quorum, view); sat(start_step, leadstowithin(StablePeriodStartedTemporal(b, asp.live_quorum, view, ahead_idx), always(andset(xs)), t, f)) { var t := TimeForOneReplicaToAdvanceAnother(asp, processing_bound) + TimeToPerformGenericAction(asp) + processing_bound * 2; var f := PaxosTimeMap(b); var w := StablePeriodStartedTemporal(b, asp.live_quorum, view, ahead_idx); var xs := PrimaryHas1bFromAllLiveAcceptorsOrIsPastPhase1TemporalSet(b, asp.live_quorum, view); forall x | x in xs ensures sat(start_step, leadstowithin(w, always(x), t, f)) { var idx :| idx in asp.live_quorum && x == PrimaryHas1bFromAcceptorOrIsPastPhase1Temporal(b, view, idx); lemma_StablePeriodStartedLeadsToPrimaryGetting1bFromAcceptorForever(b, asp, start_step, processing_bound, view, ahead_idx, idx); } Lemma_LeadsToAlwaysEachWithinImpliesLeadsToAlwaysAllWithin(start_step, w, xs, t, f); } lemma lemma_PrimaryHas1bFromAllLiveAcceptorsLeadsToPrimaryEnteringPhase2WF1Req2( b:Behavior, asp:AssumptionParameters, start_step:int, i:int, view:Ballot ) requires LivenessAssumptions(b, asp) requires view.proposer_id in asp.live_quorum requires 0 <= start_step <= i ensures var primary_idx := view.proposer_id; var xs := PrimaryHas1bFromAllLiveAcceptorsOrIsPastPhase1TemporalSet(b, asp.live_quorum, view); var P := always(andset(xs)); var Q := or(PrimaryInState2Temporal(b, view), not(NoReplicaBeyondViewTemporal(b, view))); var Action := MakeRslActionTemporalFromSpontaneousReplicaFunction(b, LReplicaNextSpontaneousMaybeEnterPhase2, primary_idx); sat(i, TemporalWF1Req2(P, Q, Action)) { var primary_idx := view.proposer_id; var xs := PrimaryHas1bFromAllLiveAcceptorsOrIsPastPhase1TemporalSet(b, asp.live_quorum, view); var y := PrimaryInState2Temporal(b, view); var z := not(NoReplicaBeyondViewTemporal(b, view)); var P := always(andset(xs)); var Q := or(y, z); var Action := MakeRslActionTemporalFromSpontaneousReplicaFunction(b, LReplicaNextSpontaneousMaybeEnterPhase2, primary_idx); if sat(i, P) && !sat(i, Q) && sat(i, Action) { lemma_ConstantsAllConsistent(b, asp.c, i); lemma_ConstantsAllConsistent(b, asp.c, i+1); assert BalLeq(CurrentViewOfHost(b[i], primary_idx), view); assert SpecificSpontaneousRslActionOccurs(b[i], b[i+1], LReplicaNextSpontaneousMaybeEnterPhase2, primary_idx); var ios:seq :| && RslNextOneReplica(b[i], b[i+1], primary_idx, ios) && SpontaneousIos(ios, 0) && LReplicaNextSpontaneousMaybeEnterPhase2(b[i].replicas[primary_idx].replica, b[i+1].replicas[primary_idx].replica, ExtractSentPacketsFromIos(ios)); var s := b[i].replicas[primary_idx].replica.proposer; var s' := b[i+1].replicas[primary_idx].replica.proposer; TemporalDeduceFromAlways(i, i, andset(xs)); lemma_Received1bPacketsAreFromMaxBallotISent1a(b, asp.c, i, primary_idx); var mapper := (p:RslPacket) requires p.src in asp.c.config.replica_ids => GetReplicaIndex(p.src, asp.c.config); var sources := MapSetToSetOver(s.received_1b_packets, mapper); forall idx | idx in asp.live_quorum ensures idx in sources { assert sat(i, PrimaryHas1bFromAcceptorInViewTemporal(b, view, idx)); var p :| PrimaryHasSpecific1bFromAcceptorInView(b[i], view, idx, p); assert ReplicasDistinct(asp.c.config.replica_ids, mapper(p), idx); assert mapper(p) == idx; } lemma_SubsetCardinality(sources, asp.live_quorum, x=>true); assert |s.received_1b_packets| >= LMinQuorumSize(s.constants.all.config); assert LSetOfMessage1bAboutBallot(s.received_1b_packets, s.max_ballot_i_sent_1a); assert s.current_state == 1; assert s' == s.(current_state := 2, next_operation_number_to_propose := b[i].replicas[primary_idx].replica.acceptor.log_truncation_point); assert PrimaryInState2(b[i+1], view); assert sat(i+1, y); assert sat(i+1, Q); } } lemma lemma_PrimaryHas1bFromAllLiveAcceptorsLeadsToPrimaryEnteringPhase2( b:Behavior, asp:AssumptionParameters, start_step:int, view:Ballot ) requires LivenessAssumptions(b, asp) requires asp.synchrony_start <= start_step requires view.proposer_id in asp.live_quorum ensures var t := TimeToPerformGenericAction(asp); var f := PaxosTimeMap(b); var xs := PrimaryHas1bFromAllLiveAcceptorsOrIsPastPhase1TemporalSet(b, asp.live_quorum, view); sat(start_step, leadstowithin(always(andset(xs)), or(PrimaryInState2Temporal(b, view), not(NoReplicaBeyondViewTemporal(b, view))), t, f)) { var t := TimeToPerformGenericAction(asp); var f := PaxosTimeMap(b); var primary_idx := view.proposer_id; var xs := PrimaryHas1bFromAllLiveAcceptorsOrIsPastPhase1TemporalSet(b, asp.live_quorum, view); var y := PrimaryInState2Temporal(b, view); var z := not(NoReplicaBeyondViewTemporal(b, view)); var P := always(andset(xs)); var Q := or(y, z); var Action := MakeRslActionTemporalFromSpontaneousReplicaFunction(b, LReplicaNextSpontaneousMaybeEnterPhase2, primary_idx); forall i | start_step <= i ensures sat(i, TemporalWF1Req1(P, Q)) ensures sat(i, TemporalWF1Req2(P, Q, Action)) { if sat(i, P) { Lemma_AlwaysImpliesLaterAlways(i, i+1, andset(xs)); } lemma_PrimaryHas1bFromAllLiveAcceptorsLeadsToPrimaryEnteringPhase2WF1Req2(b, asp, start_step, i, view); } TemporalAlways(start_step, TemporalWF1Req1(P, Q)); TemporalAlways(start_step, TemporalWF1Req2(P, Q, Action)); lemma_ReplicaNextPerformsSubactionPeriodically(b, asp, primary_idx, 2); lemma_EstablishRequirementsForWF1RealTime(b, asp, start_step, Action, t); TemporalWF1RealTime(start_step, P, Q, Action, t, f); } lemma lemma_StablePeriodStartedLeadsToPrimaryInPhase2( b:Behavior, asp:AssumptionParameters, start_step:int, processing_bound:int, view:Ballot, ahead_idx:int ) requires LivenessAssumptions(b, asp) requires PacketProcessingSynchronous(b, asp, start_step, processing_bound) requires view.proposer_id in asp.live_quorum ensures var t := TimeForOneReplicaToAdvanceAnother(asp, processing_bound) + TimeToPerformGenericAction(asp) * 2 + processing_bound * 2; var f := PaxosTimeMap(b); sat(start_step, leadstowithin(StablePeriodStartedTemporal(b, asp.live_quorum, view, ahead_idx), or(PrimaryInState2Temporal(b, view), not(NoReplicaBeyondViewTemporal(b, view))), t, f)) { var t1 := TimeForOneReplicaToAdvanceAnother(asp, processing_bound) + TimeToPerformGenericAction(asp) + processing_bound * 2; var t2 := TimeToPerformGenericAction(asp); var t := TimeForOneReplicaToAdvanceAnother(asp, processing_bound) + TimeToPerformGenericAction(asp) * 2 + processing_bound * 2; var f := PaxosTimeMap(b); var xs := PrimaryHas1bFromAllLiveAcceptorsOrIsPastPhase1TemporalSet(b, asp.live_quorum, view); assert t == t1 + t2; lemma_StablePeriodStartedLeadsToPrimaryGetting1bFromEveryLiveAcceptorForever(b, asp, start_step, processing_bound, view, ahead_idx); lemma_PrimaryHas1bFromAllLiveAcceptorsLeadsToPrimaryEnteringPhase2(b, asp, start_step, view); TransitivityOfLeadsToWithin(start_step, StablePeriodStartedTemporal(b, asp.live_quorum, view, ahead_idx), always(andset(xs)), or(PrimaryInState2Temporal(b, view), not(NoReplicaBeyondViewTemporal(b, view))), t1, t2, f); } lemma lemma_StablePeriodStartedLeadsToPrimaryEnteringPhase2( b:Behavior, asp:AssumptionParameters, start_step:int, processing_bound:int, view:Ballot, ahead_idx:int ) requires LivenessAssumptions(b, asp) requires PacketProcessingSynchronous(b, asp, start_step, processing_bound) requires view.proposer_id in asp.live_quorum ensures var t := TimeForOneReplicaToAdvanceAnother(asp, processing_bound) + TimeToPerformGenericAction(asp) * 2 + processing_bound * 2; var f := PaxosTimeMap(b); var y := PrimaryInState2Temporal(b, view); sat(start_step, always(imply(StablePeriodStartedTemporal(b, asp.live_quorum, view, ahead_idx), or(eventuallynextwithin(and(not(y), next(y)), t, f), eventuallywithin(not(NoReplicaBeyondViewTemporal(b, view)), t, f))))) { var t := TimeForOneReplicaToAdvanceAnother(asp, processing_bound) + TimeToPerformGenericAction(asp) * 2 + processing_bound * 2; var f := PaxosTimeMap(b); var x := StablePeriodStartedTemporal(b, asp.live_quorum, view, ahead_idx); var y := PrimaryInState2Temporal(b, view); var z := not(NoReplicaBeyondViewTemporal(b, view)); lemma_StablePeriodStartedLeadsToPrimaryInPhase2(b, asp, start_step, processing_bound, view, ahead_idx); TemporalAlways(start_step, imply(x, not(y))); lemma_TimeMonotonicFromInvariantHolds(b, asp, start_step); Lemma_LeadsToWithinOrSomethingLeadsToTransitionOrSomething(start_step, x, y, z, t, f); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/LivenessProof/Phase2Conclusion.i.dfy ================================================ include "Assumptions.i.dfy" include "Invariants.i.dfy" include "StablePeriod.i.dfy" include "Phase2Start.i.dfy" include "Phase2c.i.dfy" include "GenericInvariants.i.dfy" include "StateTransfer.i.dfy" module LivenessProof__Phase2Conclusion_i { import opened LiveRSL__Broadcast_i import opened LiveRSL__Constants_i import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Environment_i import opened LiveRSL__Executor_i import opened LiveRSL__Message_i import opened LiveRSL__Proposer_i import opened LiveRSL__Replica_i import opened LiveRSL__Types_i import opened LivenessProof__Assumptions_i import opened LivenessProof__Invariants_i import opened LivenessProof__MaxBalReflected_i import opened LivenessProof__NextOp_i import opened LivenessProof__PacketHandling_i import opened LivenessProof__Phase2Invariants_i import opened LivenessProof__Phase2Start_i import opened LivenessProof__Phase2c_i import opened LivenessProof__StablePeriod_i import opened LivenessProof__StateTransfer_i import opened CommonProof__Actions_i import opened CommonProof__Constants_i import opened CommonProof__Environment_i import opened Temporal__Rules_i import opened Temporal__Temporal_s import opened Temporal__Time_i import opened Environment_s import opened EnvironmentSynchrony_s import opened Collections__Maps2_s import opened Common__UpperBound_s import opened Math__mul_i predicate A2aPacketWithThePersistentClientRequestWasSentInThisViewAndAssignedAnEarlierOperationNumber( p:RslPacket, b:Behavior, asp:AssumptionParameters, h:Phase2Params, i:int, opn:OperationNumber ) requires imaptotal(b) { && h.start_step + 1 <= i && p in b[i].environment.sentPackets && 0 <= h.view.proposer_id < |asp.c.config.replica_ids| && 0 <= h.view.proposer_id < |b[h.start_step + 1].replicas| && p.src == asp.c.config.replica_ids[h.view.proposer_id] && p.dst == asp.c.config.replica_ids[h.view.proposer_id] && p.msg.RslMessage_2a? && p.msg.opn_2a < opn && p.msg.bal_2a == h.view && asp.persistent_request in p.msg.val_2a && 0 <= p.msg.opn_2a && LSetOfMessage1b(b[h.start_step + 1].replicas[h.view.proposer_id].replica.proposer.received_1b_packets) && LIsAfterLogTruncationPoint(p.msg.opn_2a, b[h.start_step + 1].replicas[h.view.proposer_id].replica.proposer.received_1b_packets) && LAllAcceptorsHadNoProposal(b[h.start_step + 1].replicas[h.view.proposer_id].replica.proposer.received_1b_packets, p.msg.opn_2a) } predicate ProposerReachedCertainNextOp( ps:RslState, idx:int, opn:OperationNumber ) { && 0 <= idx < |ps.replicas| && ps.replicas[idx].replica.proposer.next_operation_number_to_propose >= opn } function{:opaque} ProposerReachedCertainNextOpTemporal( b:Behavior, idx:int, opn:OperationNumber ):temporal requires imaptotal(b) ensures forall i{:trigger sat(i, ProposerReachedCertainNextOpTemporal(b, idx, opn))} :: sat(i, ProposerReachedCertainNextOpTemporal(b, idx, opn)) == ProposerReachedCertainNextOp(b[i], idx, opn) { stepmap(imap i :: ProposerReachedCertainNextOp(b[i], idx, opn)) } lemma lemma_Phase2EventuallyReadyForOperationBeyondClientRequest( b:Behavior, asp:AssumptionParameters ) returns ( h:Phase2Params, step:int ) requires LivenessAssumptions(b, asp) ensures Phase2StableWithRequest(b, asp, h) ensures h.start_step + 1 <= step ensures sat(step, NoReplicaBeyondViewTemporal(b, h.view)) ensures var opn := h.log_truncation_point + asp.c.params.max_log_length + h.num_requests; sat(step, or(AllLiveReplicasReadyForNextOperationTemporal(b, asp.live_quorum, h.view, opn), AllLiveReplicasCaughtUpWithEarlierOperationWithRequestQueueEmptyTemporal(b, asp.live_quorum, h.view, opn))) { var processing_sync_start, processing_bound := lemma_EventuallyPacketProcessingSynchronous(b, asp); var primary_idx :| primary_idx in asp.live_quorum; var per_request_duration := TimeToAdvanceOneOperation(asp, processing_bound); var base_duration := TimeToBeginPhase2(asp, processing_bound) + asp.c.params.max_log_length * per_request_duration; lemma_mul_nonnegative(asp.c.params.max_log_length, per_request_duration); h := lemma_EventuallyPhase2StableWithRequest(b, asp, processing_sync_start, processing_bound, primary_idx, base_duration, per_request_duration); var opn := h.log_truncation_point + asp.c.params.max_log_length + h.num_requests; step := lemma_EventuallyAllLiveReplicasReadyForCertainOperation(b, asp, h, opn); assert h.per_request_duration == per_request_duration; assert h.base_duration == base_duration; assert h.duration == h.base_duration + h.num_requests * h.per_request_duration; calc { b[step].environment.time; <= b[h.start_step + 1].environment.time + TimeToBeginPhase2(asp, h.processing_bound) + (asp.c.params.max_log_length + h.num_requests) * per_request_duration; { lemma_mul_is_distributive_add_other_way(per_request_duration, asp.c.params.max_log_length, h.num_requests); } b[h.start_step + 1].environment.time + TimeToBeginPhase2(asp, h.processing_bound) + asp.c.params.max_log_length * per_request_duration + h.num_requests * per_request_duration; b[h.start_step + 1].environment.time + h.duration; } TemporalDeduceFromAlwaysWithin(h.start_step + 1, step, NoReplicaBeyondViewTemporal(b, h.view), h.duration, PaxosTimeMap(b)); } lemma{:timeLimitMultiplier 2} lemma_RequestMovesUpInPrimaryRequestQueueAsNextOpToProposeIncreases( b:Behavior, asp:AssumptionParameters, h:Phase2Params, i:int ) returns ( p:RslPacket ) requires Phase2StableWithRequest(b, asp, h) requires h.start_step + 1 <= i requires NoReplicaBeyondView(b[i], h.view) ensures 0 <= h.view.proposer_id < |b[i].replicas| ensures var s := b[i].replicas[h.view.proposer_id].replica.proposer; var diff := s.next_operation_number_to_propose - (h.log_truncation_point + asp.c.params.max_log_length); var n := if diff >= 0 then h.num_requests - diff else h.num_requests; || ObjectInFirstNOfSequence(asp.persistent_request, s.request_queue, n) || A2aPacketWithThePersistentClientRequestWasSentInThisViewAndAssignedAnEarlierOperationNumber(p, b, asp, h, i, s.next_operation_number_to_propose) decreases i { if i == h.start_step + 1 { return; } lemma_ConstantsAllConsistent(b, asp.c, i-1); lemma_ConstantsAllConsistent(b, asp.c, i); lemma_AssumptionsMakeValidTransition(b, asp.c, i-1); var s := b[i-1].replicas[h.view.proposer_id].replica.proposer; var s' := b[i].replicas[h.view.proposer_id].replica.proposer; lemma_IfNoReplicaBeyondViewNowThenNoReplicaBeyondViewEarlier(b, asp, i-1, i, h.view); lemma_ProposerStaysInState2InPhase2(b, asp, h, i-1); lemma_ProposerStaysInState2InPhase2(b, asp, h, i); p := lemma_RequestMovesUpInPrimaryRequestQueueAsNextOpToProposeIncreases(b, asp, h, i-1); var diff := s.next_operation_number_to_propose - (h.log_truncation_point + asp.c.params.max_log_length); var diff' := s'.next_operation_number_to_propose - (h.log_truncation_point + asp.c.params.max_log_length); var n := if diff >= 0 then h.num_requests - diff else h.num_requests; var n' := if diff' >= 0 then h.num_requests - diff' else h.num_requests; if !ObjectInFirstNOfSequence(asp.persistent_request, s.request_queue, n) { lemma_NextOperationNumberToProposeIncreasesInPhase2OneStep(b, asp, h, i-1); return; } if s.next_operation_number_to_propose == s'.next_operation_number_to_propose { if s.request_queue != s'.request_queue { var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, i-1, h.view.proposer_id); var val :| s'.request_queue == s.request_queue + [val]; assert s.request_queue <= s'.request_queue; assert ObjectInFirstNOfSequence(asp.persistent_request, s'.request_queue, n); } } else { var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, i-1, h.view.proposer_id); assert s'.next_operation_number_to_propose == s.next_operation_number_to_propose + 1; if && LAllAcceptorsHadNoProposal(s.received_1b_packets, s.next_operation_number_to_propose) && LProposerNominateNewValueAndSend2a(s, s', ios[0].t, b[i-1].replicas[h.view.proposer_id].replica.acceptor.log_truncation_point, ExtractSentPacketsFromIos(ios)) { var batchSize := if |s.request_queue| <= asp.c.params.max_batch_size then |s.request_queue| else asp.c.params.max_batch_size; if asp.persistent_request in s.request_queue[..batchSize] { assert LBroadcastToEveryone(asp.c.config, h.view.proposer_id, RslMessage_2a(h.view, s.next_operation_number_to_propose, s.request_queue[..batchSize]), ExtractSentPacketsFromIos(ios)); p := LPacket(asp.c.config.replica_ids[h.view.proposer_id], asp.c.config.replica_ids[h.view.proposer_id], RslMessage_2a(h.view, s.next_operation_number_to_propose, s.request_queue[..batchSize])); assert LIoOpSend(p) in ios; assert p in b[i].environment.sentPackets; assert s'.next_operation_number_to_propose > s.next_operation_number_to_propose; lemma_Received1bPacketInvariantInPhase2(b, asp, h, i-1); assert A2aPacketWithThePersistentClientRequestWasSentInThisViewAndAssignedAnEarlierOperationNumber(p, b, asp, h, i, s'.next_operation_number_to_propose); } else { assert s'.request_queue == s.request_queue[batchSize..]; } } else { if diff >= 0 { lemma_OperationNumberMaxLogLengthAheadHasNoProposal(b, asp, h, i, s.next_operation_number_to_propose); var opn :| opn > s.next_operation_number_to_propose && !LAllAcceptorsHadNoProposal(s.received_1b_packets, opn); lemma_OperationNumberMaxLogLengthAheadHasNoProposal(b, asp, h, i, opn); assert false; } assert n' == n; assert s'.request_queue == s.request_queue; } } } lemma lemma_RequestGetsProposedOnceNextOpIsHighEnough( b:Behavior, asp:AssumptionParameters, h:Phase2Params, i:int, opn:OperationNumber ) returns ( p:RslPacket ) requires Phase2StableWithRequest(b, asp, h) requires h.start_step + 1 <= i requires NoReplicaBeyondView(b[i], h.view) requires 0 <= h.view.proposer_id < |b[i].replicas| requires b[i].replicas[h.view.proposer_id].replica.proposer.next_operation_number_to_propose >= opn >= h.log_truncation_point + asp.c.params.max_log_length + h.num_requests ensures 0 <= h.view.proposer_id < |b[i].replicas| ensures A2aPacketWithThePersistentClientRequestWasSentInThisViewAndAssignedAnEarlierOperationNumber(p, b, asp, h, i, opn) { var x := ProposerReachedCertainNextOpTemporal(b, h.view.proposer_id, opn); assert sat(i, x); assert !sat(h.start_step + 1, x); var earliest_step_reaching_opn := earliestStepBetween(h.start_step + 1, i, x); var prev_step := earliest_step_reaching_opn - 1; assert h.start_step + 1 <= prev_step < earliest_step_reaching_opn <= i; assert !sat(prev_step, x); lemma_ConstantsAllConsistent(b, asp.c, prev_step); lemma_ConstantsAllConsistent(b, asp.c, prev_step + 1); lemma_AssumptionsMakeValidTransition(b, asp.c, prev_step); lemma_IfNoReplicaBeyondViewNowThenNoReplicaBeyondViewEarlier(b, asp, prev_step, i, h.view); lemma_IfNoReplicaBeyondViewNowThenNoReplicaBeyondViewEarlier(b, asp, prev_step + 1, i, h.view); lemma_ProposerStaysInState2InPhase2(b, asp, h, prev_step); lemma_ProposerStaysInState2InPhase2(b, asp, h, prev_step + 1); var s := b[prev_step].replicas[h.view.proposer_id].replica.proposer; var s' := b[prev_step + 1].replicas[h.view.proposer_id].replica.proposer; assert s'.next_operation_number_to_propose >= opn > s.next_operation_number_to_propose; var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, prev_step, h.view.proposer_id); assert s'.next_operation_number_to_propose == opn; p := lemma_RequestMovesUpInPrimaryRequestQueueAsNextOpToProposeIncreases(b, asp, h, prev_step + 1); lemma_PacketStaysInSentPackets(b, asp.c, prev_step + 1, i, p); } lemma lemma_IfPersistentRequestMissingFromRequestQueueDuringPhase2ThenPersistentRequestIsProposed( b:Behavior, asp:AssumptionParameters, h:Phase2Params, i:int, opn:OperationNumber ) returns ( p:RslPacket ) requires Phase2StableWithRequest(b, asp, h) requires h.start_step + 1 <= i requires NoReplicaBeyondView(b[i], h.view) requires 0 <= h.view.proposer_id < |b[i].replicas| requires asp.persistent_request !in b[i].replicas[h.view.proposer_id].replica.proposer.request_queue ensures A2aPacketWithThePersistentClientRequestWasSentInThisViewAndAssignedAnEarlierOperationNumber(p, b, asp, h, i, b[i].replicas[h.view.proposer_id].replica.proposer.next_operation_number_to_propose) { if i == h.start_step + 1 { return; } lemma_ConstantsAllConsistent(b, asp.c, i-1); lemma_ConstantsAllConsistent(b, asp.c, i); lemma_AssumptionsMakeValidTransition(b, asp.c, i-1); lemma_IfNoReplicaBeyondViewNowThenNoReplicaBeyondViewEarlier(b, asp, i-1, i, h.view); lemma_ProposerStaysInState2InPhase2(b, asp, h, i-1); lemma_ProposerStaysInState2InPhase2(b, asp, h, i); var s := b[i-1].replicas[h.view.proposer_id].replica.proposer; var s' := b[i].replicas[h.view.proposer_id].replica.proposer; if asp.persistent_request !in s.request_queue { p := lemma_IfPersistentRequestMissingFromRequestQueueDuringPhase2ThenPersistentRequestIsProposed(b, asp, h, i-1, opn); lemma_NextOperationNumberToProposeIncreasesInPhase2OneStep(b, asp, h, i-1); return; } var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, i-1, h.view.proposer_id); assert s'.next_operation_number_to_propose == s.next_operation_number_to_propose + 1; assert LAllAcceptorsHadNoProposal(s.received_1b_packets, s.next_operation_number_to_propose); assert LProposerNominateNewValueAndSend2a(s, s', ios[0].t, b[i-1].replicas[h.view.proposer_id].replica.acceptor.log_truncation_point, ExtractSentPacketsFromIos(ios)); var batchSize := if |s.request_queue| <= asp.c.params.max_batch_size then |s.request_queue| else asp.c.params.max_batch_size; assert asp.persistent_request in s.request_queue[..batchSize]; p := LPacket(asp.c.config.replica_ids[h.view.proposer_id], asp.c.config.replica_ids[h.view.proposer_id], RslMessage_2a(h.view, s.next_operation_number_to_propose, s.request_queue[..batchSize])); assert LIoOpSend(p) in ios; assert p in b[i].environment.sentPackets; lemma_Received1bPacketInvariantInPhase2(b, asp, h, i-1); assert A2aPacketWithThePersistentClientRequestWasSentInThisViewAndAssignedAnEarlierOperationNumber(p, b, asp, h, i, s'.next_operation_number_to_propose); } lemma lemma_Phase2EventuallyReadyForOperationBeyond2aWithClientRequest( b:Behavior, asp:AssumptionParameters ) returns ( h:Phase2Params, step:int, opn:OperationNumber, p:RslPacket ) requires LivenessAssumptions(b, asp) ensures Phase2StableWithRequest(b, asp, h) ensures sat(step, NoReplicaBeyondViewTemporal(b, h.view)) ensures ReplicaCaughtUp(b[step], h.king_idx, opn) ensures A2aPacketWithThePersistentClientRequestWasSentInThisViewAndAssignedAnEarlierOperationNumber(p, b, asp, h, step, opn) { h, step := lemma_Phase2EventuallyReadyForOperationBeyondClientRequest(b, asp); opn := h.log_truncation_point + asp.c.params.max_log_length + h.num_requests; lemma_ConstantsAllConsistent(b, asp.c, step); assert sat(step, NoReplicaBeyondViewTemporal(b, h.view)); if sat(step, AllLiveReplicasReadyForNextOperationTemporal(b, asp.live_quorum, h.view, opn)) { p := lemma_RequestGetsProposedOnceNextOpIsHighEnough(b, asp, h, step, opn); assert ReplicaCaughtUp(b[step], h.king_idx, opn); assert A2aPacketWithThePersistentClientRequestWasSentInThisViewAndAssignedAnEarlierOperationNumber(p, b, asp, h, step, opn); } else { p := lemma_IfPersistentRequestMissingFromRequestQueueDuringPhase2ThenPersistentRequestIsProposed(b, asp, h, step, opn); opn := b[step].replicas[h.view.proposer_id].replica.proposer.next_operation_number_to_propose; assert ReplicaCaughtUp(b[step], h.king_idx, opn); assert A2aPacketWithThePersistentClientRequestWasSentInThisViewAndAssignedAnEarlierOperationNumber(p, b, asp, h, step, opn); } } lemma lemma_EventuallyKingExecutesOperationCorrespondingTo2aWithClientRequest( b:Behavior, asp:AssumptionParameters ) returns ( h:Phase2Params, step:int, opn:OperationNumber, p:RslPacket, execute_step:int, ios:seq ) requires LivenessAssumptions(b, asp) ensures Phase2StableWithRequest(b, asp, h) ensures A2aPacketWithThePersistentClientRequestWasSentInThisViewAndAssignedAnEarlierOperationNumber(p, b, asp, h, step, opn) ensures 0 <= execute_step ensures 0 <= h.king_idx < |b[execute_step].replicas| ensures 0 <= h.king_idx < |b[execute_step+1].replicas| ensures RslNextOneReplica(b[execute_step], b[execute_step+1], h.king_idx, ios) ensures var s := b[execute_step].replicas[h.king_idx].replica.executor; && s.next_op_to_execute.OutstandingOpKnown? && BalLeq(s.next_op_to_execute.bal, h.view) && s.ops_complete == p.msg.opn_2a && LtUpperBound(s.ops_complete, s.constants.all.params.max_integer_val) && LReplicaConstantsValid(s.constants) ensures LExecutorExecute(b[execute_step].replicas[h.king_idx].replica.executor, b[execute_step+1].replicas[h.king_idx].replica.executor, ExtractSentPacketsFromIos(ios)) { h, step, opn, p := lemma_Phase2EventuallyReadyForOperationBeyond2aWithClientRequest(b, asp); var x := stepmap(imap j :: 0 <= h.king_idx < |b[j].replicas| && b[j].replicas[h.king_idx].replica.executor.ops_complete > p.msg.opn_2a); var execute_next_step := earliestStepBetween(0, step, x); execute_step := execute_next_step - 1; assert !sat(0, x); assert !sat(execute_step, x); lemma_ReplicaConstantsAllConsistent(b, asp.c, execute_step, h.king_idx); lemma_ReplicaConstantsAllConsistent(b, asp.c, execute_next_step, h.king_idx); lemma_IfNoReplicaBeyondViewNowThenNoReplicaBeyondViewEarlier(b, asp, execute_step, step, h.view); ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, execute_step, h.king_idx); var s := b[execute_step].replicas[h.king_idx].replica.executor; var s' := b[execute_next_step].replicas[h.king_idx].replica.executor; if b[execute_step].replicas[h.king_idx].nextActionIndex == 0 { var p_state_supply := ios[0].r; assert IsValidLIoOp(ios[0], asp.c.config.replica_ids[h.king_idx], b[execute_step].environment); lemma_StateSupplyToKingDoesNotIncludeOpn(b, asp, h, execute_step, p.msg.opn_2a, p_state_supply); assert false; } lemma_IfNoReplicaBeyondViewNowThenNoReplicaBeyondViewEarlier(b, asp, execute_next_step, step, h.view); lemma_MaxBalReflectedLeqCurrentView(b, asp, execute_next_step, h.view, h.king_idx); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/LivenessProof/Phase2Invariants.i.dfy ================================================ include "Assumptions.i.dfy" include "Invariants.i.dfy" include "StablePeriod.i.dfy" include "ViewChange.i.dfy" include "MaxBallot.i.dfy" include "MaxBallotISent1a.i.dfy" include "MaxBalReflected.i.dfy" include "GenericInvariants.i.dfy" include "../CommonProof/MaxBallotISent1a.i.dfy" include "../CommonProof/MaxBallot.i.dfy" include "../CommonProof/Constants.i.dfy" include "../CommonProof/Actions.i.dfy" include "../CommonProof/LogTruncationPoint.i.dfy" include "../CommonProof/Environment.i.dfy" module LivenessProof__Phase2Invariants_i { import opened LiveRSL__Configuration_i import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Environment_i import opened LiveRSL__Proposer_i import opened LiveRSL__Types_i import opened LivenessProof__Assumptions_i import opened LivenessProof__Invariants_i import opened LivenessProof__StablePeriod_i import opened LivenessProof__ViewChange_i import opened LivenessProof__MaxBallot_i import opened LivenessProof__MaxBallotISent1a_i import opened LivenessProof__MaxBalReflected_i import opened LivenessProof__GenericInvariants_i import opened CommonProof__Actions_i import opened CommonProof__Constants_i import opened CommonProof__Environment_i import opened CommonProof__LogTruncationPoint_i import opened CommonProof__MaxBallot_i import opened CommonProof__MaxBallotISent1a_i import opened Temporal__Temporal_s import opened Environment_s import opened Collections__Maps2_s import opened Common__UpperBound_s predicate ReplicaCaughtUp( ps:RslState, idx:int, opn:OperationNumber ) { 0 <= idx < |ps.replicas| && ps.replicas[idx].replica.executor.ops_complete >= opn } function{:opaque} ReplicaCaughtUpTemporal( b:Behavior, idx:int, opn:OperationNumber ):temporal requires imaptotal(b) ensures forall i{:trigger sat(i, ReplicaCaughtUpTemporal(b, idx, opn))} :: sat(i, ReplicaCaughtUpTemporal(b, idx, opn)) == ReplicaCaughtUp(b[i], idx, opn) { stepmap(imap i :: ReplicaCaughtUp(b[i], idx, opn)) } function{:opaque} AllReplicasCaughtUpTemporalSet( b:Behavior, live_quorum:set, opn:OperationNumber ):set requires imaptotal(b) ensures forall idx :: idx in live_quorum ==> ReplicaCaughtUpTemporal(b, idx, opn) in AllReplicasCaughtUpTemporalSet(b, live_quorum, opn) ensures forall t :: t in AllReplicasCaughtUpTemporalSet(b, live_quorum, opn) ==> exists idx :: idx in live_quorum && t == ReplicaCaughtUpTemporal(b, idx, opn) { set idx | idx in live_quorum :: ReplicaCaughtUpTemporal(b, idx, opn) } predicate AllLiveReplicasReadyForNextOperation( ps:RslState, live_quorum:set, view:Ballot, opn:OperationNumber ) { && (forall idx :: idx in live_quorum ==> ReplicaCaughtUp(ps, idx, opn)) && var proposer_idx := view.proposer_id; && 0 <= proposer_idx < |ps.replicas| && var s := ps.replicas[proposer_idx].replica; && s.proposer.next_operation_number_to_propose >= opn && s.acceptor.log_truncation_point >= opn } function {:opaque} AllLiveReplicasReadyForNextOperationTemporal( b:Behavior, live_quorum:set, view:Ballot, opn:OperationNumber ):temporal requires imaptotal(b) ensures forall i{:trigger sat(i, AllLiveReplicasReadyForNextOperationTemporal(b, live_quorum, view, opn))} :: sat(i, AllLiveReplicasReadyForNextOperationTemporal(b, live_quorum, view, opn)) == AllLiveReplicasReadyForNextOperation(b[i], live_quorum, view, opn) { stepmap(imap i :: AllLiveReplicasReadyForNextOperation(b[i], live_quorum, view, opn)) } lemma lemma_IfNoReplicaBeyondViewNowThenNoReplicaBeyondViewEarlier( b:Behavior, asp:AssumptionParameters, i:int, j:int, view:Ballot ) requires LivenessAssumptions(b, asp) requires 0 <= i <= j requires NoReplicaBeyondView(b[j], view) ensures NoReplicaBeyondView(b[i], view) { if !sat(i, NoReplicaBeyondViewTemporal(b, view)) { var idx :| 0 <= idx < |b[i].replicas| && BalLt(view, CurrentViewOfHost(b[i], idx)); lemma_ConstantsAllConsistent(b, asp.c, i); lemma_ConstantsAllConsistent(b, asp.c, j); lemma_ViewOfHostMonotonic(b, asp, idx, i, j); assert false; } } lemma lemma_ProposerStaysInState2InPhase2( b:Behavior, asp:AssumptionParameters, h:Phase2Params, i:int ) requires Phase2StableWithRequest(b, asp, h) requires h.start_step + 1 <= i requires NoReplicaBeyondView(b[i], h.view) ensures 0 <= h.view.proposer_id < |b[i].replicas| ensures var s := b[i].replicas[h.view.proposer_id].replica.proposer; && s.max_ballot_i_sent_1a == h.view && s.current_state == 2; decreases i { lemma_ConstantsAllConsistent(b, asp.c, i); if i > h.start_step + 1 { lemma_ConstantsAllConsistent(b, asp.c, i-1); lemma_IfNoReplicaBeyondViewNowThenNoReplicaBeyondViewEarlier(b, asp, i-1, i, h.view); lemma_ProposerStaysInState2InPhase2(b, asp, h, i-1); var s := b[i-1].replicas[h.view.proposer_id].replica.proposer; var s' := b[i].replicas[h.view.proposer_id].replica.proposer; assert s.max_ballot_i_sent_1a == h.view; assert s.current_state == 2; assert BalLeq(CurrentViewOfHost(b[i-1], h.view.proposer_id), h.view); // TRIGGER lemma_MaxBallotISent1aLeqView(b, asp, i-1, h.view.proposer_id); assert s.election_state.current_view == h.view; assert BalLeq(CurrentViewOfHost(b[i], h.view.proposer_id), h.view); // TRIGGER assert BalLeq(s'.election_state.current_view, h.view); lemma_NoReplicaBeyondViewImpliesNoMaxBallotISent1aBeyondView(b, asp, i, h.view); assert BalLeq(s'.max_ballot_i_sent_1a, h.view); if s'.max_ballot_i_sent_1a != h.view || s'.current_state != 2 { var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, i-1, h.view.proposer_id); assert false; } } } lemma lemma_NextOperationNumberToProposeIncreasesInPhase2OneStep( b:Behavior, asp:AssumptionParameters, h:Phase2Params, i:int ) requires Phase2StableWithRequest(b, asp, h) requires h.start_step + 1 <= i requires NoReplicaBeyondView(b[i+1], h.view) ensures 0 <= h.view.proposer_id < |b[i].replicas| ensures 0 <= h.view.proposer_id < |b[i+1].replicas| ensures b[i+1].replicas[h.view.proposer_id].replica.proposer.next_operation_number_to_propose >= b[i].replicas[h.view.proposer_id].replica.proposer.next_operation_number_to_propose { lemma_ConstantsAllConsistent(b, asp.c, i); lemma_ConstantsAllConsistent(b, asp.c, i+1); var s := b[i].replicas[h.view.proposer_id].replica.proposer; var s' := b[i+1].replicas[h.view.proposer_id].replica.proposer; if s'.next_operation_number_to_propose < s.next_operation_number_to_propose { lemma_IfNoReplicaBeyondViewNowThenNoReplicaBeyondViewEarlier(b, asp, i, i+1, h.view); lemma_ProposerStaysInState2InPhase2(b, asp, h, i); assert s.max_ballot_i_sent_1a == h.view; assert s.current_state == 2; var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, i, h.view.proposer_id); assert false; } } lemma lemma_NextOperationNumberToProposeIncreasesInPhase2( b:Behavior, asp:AssumptionParameters, h:Phase2Params, i:int, j:int ) requires Phase2StableWithRequest(b, asp, h) requires h.start_step + 1 <= i <= j requires NoReplicaBeyondView(b[j], h.view) ensures 0 <= h.view.proposer_id < |b[i].replicas| ensures 0 <= h.view.proposer_id < |b[j].replicas| ensures b[j].replicas[h.view.proposer_id].replica.proposer.next_operation_number_to_propose >= b[i].replicas[h.view.proposer_id].replica.proposer.next_operation_number_to_propose decreases j-i { lemma_ConstantsAllConsistent(b, asp.c, i); lemma_ConstantsAllConsistent(b, asp.c, j); if j == i { } else if j == i + 1 { lemma_NextOperationNumberToProposeIncreasesInPhase2OneStep(b, asp, h, i); } else { lemma_IfNoReplicaBeyondViewNowThenNoReplicaBeyondViewEarlier(b, asp, j-1, j, h.view); lemma_ConstantsAllConsistent(b, asp.c, j-1); lemma_NextOperationNumberToProposeIncreasesInPhase2(b, asp, h, i, j-1); lemma_NextOperationNumberToProposeIncreasesInPhase2OneStep(b, asp, h, j-1); } } lemma lemma_Received1bPacketInvariantInPhase2( b:Behavior, asp:AssumptionParameters, h:Phase2Params, i:int ) requires Phase2StableWithRequest(b, asp, h) requires h.start_step + 1 <= i requires NoReplicaBeyondView(b[i], h.view) ensures 0 <= h.view.proposer_id < |b[i].replicas| ensures var s := b[i].replicas[h.view.proposer_id].replica.proposer; && s.received_1b_packets == b[h.start_step + 1].replicas[h.view.proposer_id].replica.proposer.received_1b_packets && |s.received_1b_packets| >= LMinQuorumSize(s.constants.all.config) && LSetOfMessage1bAboutBallot(s.received_1b_packets, s.max_ballot_i_sent_1a) decreases i; { lemma_ConstantsAllConsistent(b, asp.c, i); if i > h.start_step + 1 { lemma_ConstantsAllConsistent(b, asp.c, i-1); lemma_IfNoReplicaBeyondViewNowThenNoReplicaBeyondViewEarlier(b, asp, i-1, i, h.view); lemma_ProposerStaysInState2InPhase2(b, asp, h, i-1); lemma_ProposerStaysInState2InPhase2(b, asp, h, i); var idx := h.view.proposer_id; var s := b[i-1].replicas[idx].replica.proposer; var s' := b[i].replicas[idx].replica.proposer; if s'.received_1b_packets != s.received_1b_packets { var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, i-1, idx); assert false; } lemma_Received1bPacketInvariantInPhase2(b, asp, h, i-1); } } lemma lemma_ProposerCanNominateInPhase2( b:Behavior, asp:AssumptionParameters, h:Phase2Params, i:int ) requires Phase2StableWithRequest(b, asp, h) requires h.start_step + 1 <= i requires NoReplicaBeyondView(b[i], h.view) ensures 0 <= h.view.proposer_id < |b[i].replicas| ensures var s := b[i].replicas[h.view.proposer_id].replica; s.proposer.next_operation_number_to_propose < s.acceptor.log_truncation_point + asp.c.params.max_log_length ==> LProposerCanNominateUsingOperationNumber(s.proposer, s.acceptor.log_truncation_point, s.proposer.next_operation_number_to_propose) decreases i { lemma_ConstantsAllConsistent(b, asp.c, i); var idx := h.view.proposer_id; var s := b[i].replicas[idx].replica; var opn := s.proposer.next_operation_number_to_propose; if opn < s.acceptor.log_truncation_point + asp.c.params.max_log_length { lemma_ProposerStaysInState2InPhase2(b, asp, h, i); assert s.proposer.max_ballot_i_sent_1a == h.view; assert s.proposer.current_state == 2; lemma_MaxBallotISent1aLeqView(b, asp, i, idx); assert BalLeq(CurrentViewOfHost(b[i], idx), h.view); assert s.proposer.election_state.current_view == s.proposer.max_ballot_i_sent_1a; lemma_OverflowProtectionNotUsedForReplica(b, asp, i, idx); assert opn < UpperBoundedAddition(s.acceptor.log_truncation_point, s.proposer.constants.all.params.max_log_length, s.proposer.constants.all.params.max_integer_val); lemma_NextOperationNumberToProposeIncreasesInPhase2(b, asp, h, h.start_step + 1, i); calc { opn; >= b[h.start_step + 1].replicas[idx].replica.proposer.next_operation_number_to_propose; == b[h.start_step + 1].replicas[idx].replica.acceptor.log_truncation_point; >= { lemma_LogTruncationPointMonotonic(b, asp.c, 0, h.start_step + 1, idx); } b[0].replicas[idx].replica.acceptor.log_truncation_point; == 0; } lemma_Received1bPacketInvariantInPhase2(b, asp, h, i); assert s.proposer.next_operation_number_to_propose >= h.log_truncation_point; lemma_ProposerLogTruncationPointAlwaysBeyondThatOfAllReceived1bs(b, asp.c, h.start_step + 1, idx); assert forall p :: p in s.proposer.received_1b_packets && p.msg.RslMessage_1b? ==> p.msg.log_truncation_point <= h.log_truncation_point <= s.proposer.next_operation_number_to_propose; assert LProposerCanNominateUsingOperationNumber(s.proposer, s.acceptor.log_truncation_point, opn); } } lemma lemma_IfAllLiveReplicasReadyForNextOperationThenSoLaterInPhase2( b:Behavior, asp:AssumptionParameters, h:Phase2Params, opn:OperationNumber, i:int, j:int ) requires Phase2StableWithRequest(b, asp, h) requires h.start_step + 1 <= i <= j requires AllLiveReplicasReadyForNextOperation(b[i], asp.live_quorum, h.view, opn) requires NoReplicaBeyondView(b[j], h.view) ensures AllLiveReplicasReadyForNextOperation(b[j], asp.live_quorum, h.view, opn) { lemma_LogTruncationPointMonotonic(b, asp.c, i, j, h.view.proposer_id); lemma_NextOperationNumberToProposeIncreasesInPhase2(b, asp, h, i, j); forall idx | idx in asp.live_quorum ensures ReplicaCaughtUp(b[j], idx, opn) { lemma_OpsCompleteMonotonic(b, asp.c, i, j, idx); } } lemma lemma_MaxBalNeverExceedsViewDuringPhase2( b:Behavior, asp:AssumptionParameters, h:Phase2Params, i:int, idx:int ) requires Phase2StableWithRequest(b, asp, h) requires h.start_step + 1 <= i requires 0 <= idx < |b[i].replicas| requires NoReplicaBeyondView(b[i], h.view) ensures BalLeq(b[i].replicas[idx].replica.acceptor.max_bal, h.view) { if NoReplicaBeyondView(b[i], h.view) { lemma_MaxBalLeqMaxBallotPrimarySent1a(b, asp.c, i, idx); var max_bal := b[i].replicas[idx].replica.acceptor.max_bal; assert BalLeq(max_bal, b[i].replicas[max_bal.proposer_id].replica.proposer.max_ballot_i_sent_1a); lemma_NoReplicaBeyondViewImpliesNoMaxBallotISent1aBeyondView(b, asp, i, h.view); assert BalLeq(b[i].replicas[max_bal.proposer_id].replica.proposer.max_ballot_i_sent_1a, h.view); } } lemma lemma_LearnerMaxBallotSeenNeverExceedsViewDuringPhase2( b:Behavior, asp:AssumptionParameters, h:Phase2Params, i:int, idx:int ) requires Phase2StableWithRequest(b, asp, h) requires h.start_step + 1 <= i requires 0 <= idx < |b[i].replicas| requires NoReplicaBeyondView(b[i], h.view) ensures BalLeq(b[i].replicas[idx].replica.learner.max_ballot_seen, h.view) { var max_ballot_seen := b[i].replicas[idx].replica.learner.max_ballot_seen; lemma_LearnerMaxBallotSeenShowsPrimaryReachedState2(b, asp.c, i, idx); assert BalLeq(max_ballot_seen, b[i].replicas[max_ballot_seen.proposer_id].replica.proposer.max_ballot_i_sent_1a); lemma_NoReplicaBeyondViewImpliesNoMaxBallotISent1aBeyondView(b, asp, i, h.view); assert BalLeq(b[i].replicas[max_ballot_seen.proposer_id].replica.proposer.max_ballot_i_sent_1a, h.view); } lemma lemma_OperationNumberMaxLogLengthAheadHasNoProposal( b:Behavior, asp:AssumptionParameters, h:Phase2Params, i:int, opn:OperationNumber ) requires Phase2StableWithRequest(b, asp, h) requires h.start_step + 1 <= i requires NoReplicaBeyondView(b[i], h.view) requires opn >= h.log_truncation_point + asp.c.params.max_log_length ensures 0 <= h.view.proposer_id < |b[i].replicas| ensures LSetOfMessage1b(b[i].replicas[h.view.proposer_id].replica.proposer.received_1b_packets) ensures LAllAcceptorsHadNoProposal(b[i].replicas[h.view.proposer_id].replica.proposer.received_1b_packets, opn) { lemma_Received1bPacketInvariantInPhase2(b, asp, h, i); lemma_ConstantsAllConsistent(b, asp.c, h.start_step + 1); lemma_ConstantsAllConsistent(b, asp.c, i); var s := b[h.start_step + 1].replicas[h.view.proposer_id].replica; forall p | p in s.proposer.received_1b_packets ensures opn !in p.msg.votes { if opn in p.msg.votes { lemma_VoteInReceived1bMessageAlwaysWithinLogTruncationPointRange(b, asp.c, h.start_step + 1, h.view.proposer_id, opn, p); assert false; } } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/LivenessProof/Phase2Start.i.dfy ================================================ include "Assumptions.i.dfy" include "Invariants.i.dfy" include "ViewPersistence.i.dfy" include "Phase1bCont.i.dfy" include "RequestQueue.i.dfy" include "../CommonProof/Constants.i.dfy" include "../CommonProof/Actions.i.dfy" include "../CommonProof/LogTruncationPoint.i.dfy" include "../../../../Libraries/Math/mul.i.dfy" include "../../../Common/Logic/Temporal/Rules.i.dfy" module LivenessProof__Phase2Start_i { import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Environment_i import opened LiveRSL__Types_i import opened LivenessProof__Assumptions_i import opened LivenessProof__Invariants_i import opened LivenessProof__PacketHandling_i import opened LivenessProof__Phase1b_i import opened LivenessProof__Phase1bCont_i import opened LivenessProof__RealTime_i import opened LivenessProof__RequestQueue_i import opened LivenessProof__RoundRobin_i import opened LivenessProof__StablePeriod_i import opened LivenessProof__ViewAdvance_i import opened LivenessProof__ViewPersistence_i import opened CommonProof__Constants_i import opened CommonProof__Actions_i import opened CommonProof__LogTruncationPoint_i import opened Math__mul_i import opened Temporal__Rules_i import opened Temporal__Temporal_s import opened Temporal__Time_s import opened Temporal__Time_i import opened Environment_s import opened Collections__Maps2_s import opened Common__UpperBound_s lemma lemma_EventuallyPhase2StableWithRequestHelper( b:Behavior, asp:AssumptionParameters, processing_sync_start:int, processing_bound:int, primary_idx:int, base_duration:int, per_request_duration:int ) returns ( start_step:int, ahead_idx:int, step:int, view:Ballot, num_requests:int, duration:int ) requires LivenessAssumptions(b, asp) requires PacketProcessingSynchronous(b, asp, processing_sync_start, processing_bound) requires primary_idx in asp.live_quorum requires base_duration >= 0 requires per_request_duration >= 0 ensures processing_sync_start <= step ensures view.proposer_id == primary_idx ensures LeqUpperBound(view.seqno, asp.c.params.max_integer_val) ensures num_requests > 0 ensures duration == base_duration + num_requests * per_request_duration ensures processing_sync_start <= start_step <= step ensures sat(start_step, StablePeriodStartedTemporal(b, asp.live_quorum, view, ahead_idx)) ensures sat(start_step, always(RequestInFirstNTemporal(b, view.proposer_id, asp.persistent_request, num_requests))) ensures sat(step, always(untilabsolutetime(NoReplicaBeyondViewTemporal(b, view), b[step+1].environment.time + duration, PaxosTimeMap(b)))) ensures !PrimaryInState2(b[step], view) ensures PrimaryInState2(b[step+1], view) { var t := TimeForOneReplicaToAdvanceAnother(asp, processing_bound) + TimeToPerformGenericAction(asp) * 2 + processing_bound * 2; var f := PaxosTimeMap(b); var full_duration:int; view, start_step, ahead_idx, num_requests, full_duration := lemma_EventuallyBallotStableWithRequest(b, asp, processing_sync_start, processing_bound, primary_idx, t + base_duration, per_request_duration); lemma_mul_nonnegative(num_requests, per_request_duration); var x := StablePeriodStartedTemporal(b, asp.live_quorum, view, ahead_idx); var y := PrimaryInState2Temporal(b, view); var z := NoReplicaBeyondViewTemporal(b, view); duration := base_duration + num_requests * per_request_duration; lemma_IfPacketProcessingSynchronousThenAlways(b, asp, processing_sync_start, start_step, processing_bound); lemma_StablePeriodStartedLeadsToPrimaryEnteringPhase2(b, asp, start_step, processing_bound, view, ahead_idx); TemporalDeduceFromAlways(start_step, start_step, imply(x, or(eventuallynextwithin(and(not(y), next(y)), t, f), eventuallywithin(not(z), t, f)))); assert sat(start_step, x); assert sat(start_step, or(eventuallynextwithin(and(not(y), next(y)), t, f), eventuallywithin(not(z), t, f))); if sat(start_step, eventuallywithin(not(z), t, f)) { var i := TemporalDeduceFromEventual(start_step, beforeabsolutetime(not(z), f[start_step] + t, f)); TemporalDeduceFromAlways(start_step, i, untilabsolutetime(z, f[start_step] + full_duration, f)); assert full_duration >= t; assert false; } assert sat(start_step, eventuallynextwithin(and(not(y), next(y)), t, f)); step := TemporalDeduceFromEventual(start_step, nextbefore(and(not(y), next(y)), f[start_step]+t, f)); Lemma_AlwaysImpliesLaterAlways(start_step, step, untilabsolutetime(z, f[start_step] + full_duration, f)); assert f[step+1] + duration <= f[start_step] + full_duration; lemma_TimeMonotonicFromInvariantHolds(b, asp, step); Lemma_AlwaysUntilAbsoluteTimeImpliesAlwaysUntilEarlierTime(step, z, f[start_step] + full_duration, f[step+1] + duration, f); } lemma lemma_EventuallyPhase2StableWithRequest( b:Behavior, asp:AssumptionParameters, processing_sync_start:int, processing_bound:int, primary_idx:int, base_duration:int, per_request_duration:int ) returns ( h:Phase2Params ) requires LivenessAssumptions(b, asp) requires PacketProcessingSynchronous(b, asp, processing_sync_start, processing_bound) requires primary_idx in asp.live_quorum requires base_duration >= 0 requires per_request_duration >= 0 ensures h.view.proposer_id == primary_idx ensures LeqUpperBound(h.view.seqno, asp.c.params.max_integer_val) ensures h.base_duration == base_duration ensures h.per_request_duration == per_request_duration ensures h.processing_bound == processing_bound ensures Phase2StableWithRequest(b, asp, h) { var stable_start_step, ahead_idx, start_step, view, num_requests, duration := lemma_EventuallyPhase2StableWithRequestHelper(b, asp, processing_sync_start, processing_bound, primary_idx, base_duration, per_request_duration); lemma_ConstantsAllConsistent(b, asp.c, start_step); var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, start_step, primary_idx); var log_truncation_point := b[start_step].replicas[primary_idx].replica.acceptor.log_truncation_point; var king_idx := lemma_AlwaysSomeReplicaInQuorumBeyondLogTruncationPoint(b, asp.c, start_step+1, primary_idx, asp.live_quorum); lemma_RequestInFirstNOfRequestQueueDuringPhase1(b, asp, start_step, stable_start_step, view, ahead_idx, asp.persistent_request, num_requests); h := Phase2Params(start_step, duration, base_duration, per_request_duration, processing_bound, view, log_truncation_point, king_idx, num_requests, ios); lemma_IfPacketProcessingSynchronousThenAlways(b, asp, processing_sync_start, start_step, processing_bound); Lemma_AlwaysImpliesLaterAlways(start_step, start_step + 1, untilabsolutetime(NoReplicaBeyondViewTemporal(b, view), b[h.start_step + 1].environment.time + h.duration, PaxosTimeMap(b))); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/LivenessProof/Phase2a.i.dfy ================================================ include "Assumptions.i.dfy" include "Invariants.i.dfy" include "StablePeriod.i.dfy" include "NextOp.i.dfy" module LivenessProof__Phase2a_i { import opened LiveRSL__Broadcast_i import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Environment_i import opened LiveRSL__Learner_i import opened LiveRSL__Message_i import opened LiveRSL__Proposer_i import opened LiveRSL__Replica_i import opened LiveRSL__Types_i import opened LivenessProof__Assumptions_i import opened LivenessProof__Invariants_i import opened LivenessProof__NextOp_i import opened LivenessProof__PacketHandling_i import opened LivenessProof__Phase2Invariants_i import opened LivenessProof__RealTime_i import opened LivenessProof__RoundRobin_i import opened LivenessProof__StablePeriod_i import opened CommonProof__Actions_i import opened CommonProof__Constants_i import opened Temporal__Induction_i import opened Temporal__Rules_i import opened Temporal__Sets_i import opened Temporal__Temporal_s import opened Temporal__Time_s import opened Temporal__Time_i import opened Environment_s import opened Collections__Maps2_s import opened Common__UpperBound_s predicate ProposerSends2asForOperation( ps:RslState, ps':RslState, idx:int, opn:OperationNumber, ios:seq ) { && 0 <= idx < |ps.replicas| && 0 <= idx < |ps'.replicas| && ps.replicas[idx].replica.proposer.next_operation_number_to_propose == opn && ps'.replicas[idx].replica.proposer.next_operation_number_to_propose == opn + 1 && RslNextOneReplica(ps, ps', idx, ios) && SpontaneousIos(ios, 1) && LProposerMaybeNominateValueAndSend2a(ps.replicas[idx].replica.proposer, ps'.replicas[idx].replica.proposer, ios[0].t, ps.replicas[idx].replica.acceptor.log_truncation_point, ExtractSentPacketsFromIos(ios)) } function{:opaque} ProposerSends2asForOperationTemporal( b:Behavior, idx:int, opn:OperationNumber ):temporal requires imaptotal(b) ensures forall i{:trigger sat(i, ProposerSends2asForOperationTemporal(b, idx, opn))} :: sat(i, ProposerSends2asForOperationTemporal(b, idx, opn)) <==> exists ios {:trigger ProposerSends2asForOperation(b[i], b[nextstep(i)], idx, opn, ios)} :: ProposerSends2asForOperation(b[i], b[nextstep(i)], idx, opn, ios) { stepmap(imap i :: exists ios {:trigger ProposerSends2asForOperation(b[i], b[nextstep(i)], idx, opn, ios)} :: ProposerSends2asForOperation(b[i], b[nextstep(i)], idx, opn, ios)) } predicate LearnerHas2bFromAcceptorInView( ps:RslState, acceptor_idx:int, learner_idx:int, view:Ballot, opn:OperationNumber ) { && 0 <= acceptor_idx < |ps.constants.config.replica_ids| && 0 <= learner_idx < |ps.replicas| && var s := ps.replicas[learner_idx].replica.learner; && s.max_ballot_seen == view && opn in s.unexecuted_learner_state && ps.constants.config.replica_ids[acceptor_idx] in s.unexecuted_learner_state[opn].received_2b_message_senders } function{:opaque} LearnerHas2bFromAcceptorInViewTemporal( b:Behavior, acceptor_idx:int, learner_idx:int, view:Ballot, opn:OperationNumber ):temporal requires imaptotal(b) ensures forall i{:trigger sat(i, LearnerHas2bFromAcceptorInViewTemporal(b, acceptor_idx, learner_idx, view, opn))} :: sat(i, LearnerHas2bFromAcceptorInViewTemporal(b, acceptor_idx, learner_idx, view, opn)) == LearnerHas2bFromAcceptorInView(b[i], acceptor_idx, learner_idx, view, opn); { stepmap(imap i :: LearnerHas2bFromAcceptorInView(b[i], acceptor_idx, learner_idx, view, opn)) } predicate ExecutorHasLearnedDecisionAboutOp( ps:RslState, idx:int, opn:OperationNumber ) { && 0 <= idx < |ps.replicas| && var s := ps.replicas[idx].replica.executor; s.ops_complete > opn || (s.ops_complete == opn && s.next_op_to_execute.OutstandingOpKnown?) } function{:opaque} ExecutorHasLearnedDecisionAboutOpTemporal( b:Behavior, idx:int, opn:OperationNumber ):temporal requires imaptotal(b) ensures forall i{:trigger sat(i, ExecutorHasLearnedDecisionAboutOpTemporal(b, idx, opn))} :: sat(i, ExecutorHasLearnedDecisionAboutOpTemporal(b, idx, opn)) == ExecutorHasLearnedDecisionAboutOp(b[i], idx, opn) { stepmap(imap i :: ExecutorHasLearnedDecisionAboutOp(b[i], idx, opn)) } function{:opaque} LearnerHas2bFromEveryAcceptorInViewTemporalSet( b:Behavior, live_quorum:set, learner_idx:int, view:Ballot, opn:OperationNumber ):set requires imaptotal(b) ensures forall acceptor_idx :: acceptor_idx in live_quorum ==> or(LearnerHas2bFromAcceptorInViewTemporal(b, acceptor_idx, learner_idx, view, opn), or(ExecutorHasLearnedDecisionAboutOpTemporal(b, learner_idx, opn), not(NoReplicaBeyondViewTemporal(b, view)))) in LearnerHas2bFromEveryAcceptorInViewTemporalSet(b, live_quorum, learner_idx, view, opn) ensures forall x :: x in LearnerHas2bFromEveryAcceptorInViewTemporalSet(b, live_quorum, learner_idx, view, opn) ==> exists acceptor_idx :: && acceptor_idx in live_quorum && x == or(LearnerHas2bFromAcceptorInViewTemporal(b, acceptor_idx, learner_idx, view, opn), or(ExecutorHasLearnedDecisionAboutOpTemporal(b, learner_idx, opn), not(NoReplicaBeyondViewTemporal(b, view)))) { set acceptor_idx | acceptor_idx in live_quorum :: or(LearnerHas2bFromAcceptorInViewTemporal(b, acceptor_idx, learner_idx, view, opn), or(ExecutorHasLearnedDecisionAboutOpTemporal(b, learner_idx, opn), not(NoReplicaBeyondViewTemporal(b, view)))) } lemma lemma_IfNextOperationBeyondThenProposerSent2as( b:Behavior, asp:AssumptionParameters, h:Phase2Params, opn:OperationNumber, i:int ) returns ( step:int, ios:seq ) requires Phase2StableWithRequest(b, asp, h) requires h.start_step + 1 <= i requires opn >= h.log_truncation_point requires 0 <= h.view.proposer_id < |b[i].replicas| requires b[i].replicas[h.view.proposer_id].replica.proposer.next_operation_number_to_propose > opn requires NoReplicaBeyondView(b[i], h.view) ensures h.start_step + 1 <= step < i ensures ProposerSends2asForOperation(b[step], b[step+1], h.view.proposer_id, opn, ios) { var idx := h.view.proposer_id; var next_step := earliestStepBetween(h.start_step + 1, i, ProposerExceedsCertainNextOpTemporal(b, idx, opn)); step := next_step - 1; assert h.start_step + 1 <= step < next_step <= i; assert !sat(step, ProposerExceedsCertainNextOpTemporal(b, idx, opn)); lemma_IfNoReplicaBeyondViewNowThenNoReplicaBeyondViewEarlier(b, asp, step, i, h.view); lemma_IfNoReplicaBeyondViewNowThenNoReplicaBeyondViewEarlier(b, asp, step+1, i, h.view); lemma_ProposerStaysInState2InPhase2(b, asp, h, step); lemma_ProposerStaysInState2InPhase2(b, asp, h, step+1); ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, step, idx); lemma_ConstantsAllConsistent(b, asp.c, step); lemma_ConstantsAllConsistent(b, asp.c, step+1); } lemma lemma_IfLiveReplicasReadyForAnOperationThenLearnerEventuallyLearnsItLastStep( b:Behavior, asp:AssumptionParameters, h:Phase2Params, opn:OperationNumber, prev_step:int, acceptor_idx:int, learner_idx:int, v:RequestBatch, p:RslPacket, third_step:int, ios:seq ) returns ( step:int ) requires Phase2StableWithRequest(b, asp, h) requires opn >= h.log_truncation_point requires h.start_step + 1 <= prev_step requires AllLiveReplicasReadyForNextOperation(b[prev_step], asp.live_quorum, h.view, opn) requires acceptor_idx in asp.live_quorum requires learner_idx in asp.live_quorum requires p.src == asp.c.config.replica_ids[acceptor_idx] requires p.msg == RslMessage_2b(h.view, opn, v) requires PacketProcessedViaIos(b[third_step], b[third_step+1], p, learner_idx, ios) requires b[third_step+1].environment.time <= b[prev_step].environment.time + asp.c.params.max_batch_delay + asp.max_clock_ambiguity * 2 + TimeToPerformGenericAction(asp) * 2 + h.processing_bound * 2 requires h.start_step + 1 <= third_step ensures h.start_step + 1 <= step ensures var f := PaxosTimeMap(b); var t := b[prev_step].environment.time + asp.c.params.max_batch_delay + asp.max_clock_ambiguity * 2 + TimeToPerformGenericAction(asp) * 2 + h.processing_bound * 2; var w := LearnerHas2bFromAcceptorInViewTemporal(b, acceptor_idx, learner_idx, h.view, opn); var x := ExecutorHasLearnedDecisionAboutOpTemporal(b, learner_idx, opn); var y := AllLiveReplicasCaughtUpWithEarlierOperationWithRequestQueueEmptyTemporal(b, asp.live_quorum, h.view, opn + 1); var z := NoReplicaBeyondViewTemporal(b, h.view); sat(step, beforeabsolutetime(or(w, or(x, or(y, not(z)))), t, f)) { var f := PaxosTimeMap(b); var w := LearnerHas2bFromAcceptorInViewTemporal(b, acceptor_idx, learner_idx, h.view, opn); var x := ExecutorHasLearnedDecisionAboutOpTemporal(b, learner_idx, opn); var y := AllLiveReplicasCaughtUpWithEarlierOperationWithRequestQueueEmptyTemporal(b, asp.live_quorum, h.view, opn + 1); var z := NoReplicaBeyondViewTemporal(b, h.view); if sat(third_step, or(x, not(z))) { step := third_step; lemma_TimeAdvancesBetween(b, asp, third_step, third_step + 1); return; } lemma_ConstantsAllConsistent(b, asp.c, third_step); var s3 := b[third_step].replicas[learner_idx].replica; lemma_ConstantsAllConsistent(b, asp.c, third_step+1); var s3' := b[third_step+1].replicas[learner_idx].replica; assert LReplicaNextProcessPacket(s3, s3', ios); assert LReplicaNextProcess2b(s3, s3', p, ExtractSentPacketsFromIos(ios)); var op_learnable := s3.executor.ops_complete < opn || (s3.executor.ops_complete == opn && s3.executor.next_op_to_execute.OutstandingOpUnknown?); assert op_learnable; assert LLearnerProcess2b(s3.learner, s3'.learner, p); lemma_LearnerMaxBallotSeenNeverExceedsViewDuringPhase2(b, asp, h, third_step, learner_idx); assert p.src in s3.learner.constants.all.config.replica_ids; assert !BalLt(p.msg.bal_2b, s3.learner.max_ballot_seen); assert s3'.learner.max_ballot_seen == h.view; assert opn in s3'.learner.unexecuted_learner_state; assert p.src == asp.c.config.replica_ids[acceptor_idx]; assert p.src in s3'.learner.unexecuted_learner_state[opn].received_2b_message_senders; step := third_step + 1; assert LearnerHas2bFromAcceptorInView(b[step], acceptor_idx, learner_idx, h.view, opn); } lemma lemma_IfLiveReplicasReadyForAnOperationThenLearnerEventuallyLearnsItSecondStep( b:Behavior, asp:AssumptionParameters, h:Phase2Params, opn:OperationNumber, prev_step:int, acceptor_idx:int, learner_idx:int, v:RequestBatch, p:RslPacket, second_step:int, ios:seq ) returns ( step:int ) requires Phase2StableWithRequest(b, asp, h) requires opn >= h.log_truncation_point requires h.start_step + 1 <= prev_step requires AllLiveReplicasReadyForNextOperation(b[prev_step], asp.live_quorum, h.view, opn) requires acceptor_idx in asp.live_quorum requires learner_idx in asp.live_quorum requires p.src == asp.c.config.replica_ids[h.view.proposer_id] requires p.msg == RslMessage_2a(h.view, opn, v) requires PacketProcessedViaIos(b[second_step], b[second_step+1], p, acceptor_idx, ios) requires b[second_step+1].environment.time <= b[prev_step].environment.time + asp.c.params.max_batch_delay + asp.max_clock_ambiguity * 2 + TimeToPerformGenericAction(asp) * 2 + h.processing_bound requires h.start_step + 1 <= second_step requires LeqUpperBound(opn, asp.c.params.max_integer_val) ensures h.start_step + 1 <= step ensures var f := PaxosTimeMap(b); var t := b[prev_step].environment.time + asp.c.params.max_batch_delay + asp.max_clock_ambiguity * 2 + TimeToPerformGenericAction(asp) * 2 + h.processing_bound * 2; var w := LearnerHas2bFromAcceptorInViewTemporal(b, acceptor_idx, learner_idx, h.view, opn); var x := ExecutorHasLearnedDecisionAboutOpTemporal(b, learner_idx, opn); var y := AllLiveReplicasCaughtUpWithEarlierOperationWithRequestQueueEmptyTemporal(b, asp.live_quorum, h.view, opn + 1); var z := NoReplicaBeyondViewTemporal(b, h.view); sat(step, beforeabsolutetime(or(w, or(x, or(y, not(z)))), t, f)) { var f := PaxosTimeMap(b); var w := LearnerHas2bFromAcceptorInViewTemporal(b, acceptor_idx, learner_idx, h.view, opn); var x := ExecutorHasLearnedDecisionAboutOpTemporal(b, learner_idx, opn); var y := AllLiveReplicasCaughtUpWithEarlierOperationWithRequestQueueEmptyTemporal(b, asp.live_quorum, h.view, opn + 1); var z := NoReplicaBeyondViewTemporal(b, h.view); if sat(second_step, not(z)) { step := second_step; lemma_TimeAdvancesBetween(b, asp, second_step, second_step+1); return; } lemma_ConstantsAllConsistent(b, asp.c, second_step); lemma_ConstantsAllConsistent(b, asp.c, second_step+1); var s2 := b[second_step].replicas[acceptor_idx].replica; var s2' := b[second_step+1].replicas[acceptor_idx].replica; lemma_MaxBalNeverExceedsViewDuringPhase2(b, asp, h, second_step, acceptor_idx); assert LBroadcastToEveryone(asp.c.config, acceptor_idx, RslMessage_2b(h.view, opn, v), ExtractSentPacketsFromIos(ios)); var p2 := LPacket(asp.c.config.replica_ids[learner_idx], asp.c.config.replica_ids[acceptor_idx], RslMessage_2b(h.view, opn, v)); assert p2 in ExtractSentPacketsFromIos(ios); var third_step, ios3 := lemma_PacketSentToIndexProcessedByIt(b, asp, h.start_step, h.processing_bound, second_step, learner_idx, p2); assert f[third_step+1] <= f[prev_step] + asp.c.params.max_batch_delay + asp.max_clock_ambiguity * 2 + TimeToPerformGenericAction(asp) * 2 + h.processing_bound * 2; step := lemma_IfLiveReplicasReadyForAnOperationThenLearnerEventuallyLearnsItLastStep(b, asp, h, opn, prev_step, acceptor_idx, learner_idx, v, p2, third_step, ios3); } lemma lemma_IfLiveReplicasReadyForAnOperationThenLearnerEventuallyLearnsIt( b:Behavior, asp:AssumptionParameters, h:Phase2Params, opn:OperationNumber, prev_step:int, acceptor_idx:int, learner_idx:int ) returns ( step:int ) requires Phase2StableWithRequest(b, asp, h) requires opn >= h.log_truncation_point requires h.start_step + 1 <= prev_step requires AllLiveReplicasReadyForNextOperation(b[prev_step], asp.live_quorum, h.view, opn) requires acceptor_idx in asp.live_quorum requires learner_idx in asp.live_quorum ensures h.start_step + 1 <= step ensures var f := PaxosTimeMap(b); var t := b[prev_step].environment.time + asp.c.params.max_batch_delay + asp.max_clock_ambiguity * 2 + TimeToPerformGenericAction(asp) * 2 + h.processing_bound * 2; var w := LearnerHas2bFromAcceptorInViewTemporal(b, acceptor_idx, learner_idx, h.view, opn); var x := ExecutorHasLearnedDecisionAboutOpTemporal(b, learner_idx, opn); var y := AllLiveReplicasCaughtUpWithEarlierOperationWithRequestQueueEmptyTemporal(b, asp.live_quorum, h.view, opn + 1); var z := NoReplicaBeyondViewTemporal(b, h.view); sat(step, beforeabsolutetime(or(w, or(x, or(y, not(z)))), t, f)) { var f := PaxosTimeMap(b); var t := b[prev_step].environment.time + asp.c.params.max_batch_delay + asp.max_clock_ambiguity * 2 + TimeToPerformGenericAction(asp) * 2 + h.processing_bound * 2; var w := LearnerHas2bFromAcceptorInViewTemporal(b, acceptor_idx, learner_idx, h.view, opn); var x := ExecutorHasLearnedDecisionAboutOpTemporal(b, learner_idx, opn); var y := AllLiveReplicasCaughtUpWithEarlierOperationWithRequestQueueEmptyTemporal(b, asp.live_quorum, h.view, opn + 1); var z := NoReplicaBeyondViewTemporal(b, h.view); var later_step := lemma_IfLiveReplicasReadyForAnOperationThenProposerEventuallyAdvancesNextOp(b, asp, h, opn, prev_step); assert f[later_step] <= f[prev_step] + asp.c.params.max_batch_delay + asp.max_clock_ambiguity * 2 + TimeToPerformGenericAction(asp) * 2; lemma_ConstantsAllConsistent(b, asp.c, later_step); if sat(later_step, or(y, not(z))) { step := later_step; return; } var first_step, ios := lemma_IfNextOperationBeyondThenProposerSent2as(b, asp, h, opn, later_step); lemma_TimeAdvancesBetween(b, asp, first_step + 1, later_step); if sat(first_step, not(z)) { step := first_step; lemma_TimeAdvancesBetween(b, asp, step, first_step + 1); return; } assert f[first_step+1] <= f[prev_step] + asp.c.params.max_batch_delay + asp.max_clock_ambiguity * 2 + TimeToPerformGenericAction(asp) * 2; lemma_ConstantsAllConsistent(b, asp.c, first_step); var s1 := b[first_step].replicas[h.view.proposer_id].replica; var v :| LBroadcastToEveryone(asp.c.config, h.view.proposer_id, RslMessage_2a(s1.proposer.max_ballot_i_sent_1a, opn, v), ExtractSentPacketsFromIos(ios)); lemma_ProposerStaysInState2InPhase2(b, asp, h, first_step); assert s1.proposer.max_ballot_i_sent_1a == h.view; var p := LPacket(asp.c.config.replica_ids[acceptor_idx], asp.c.config.replica_ids[h.view.proposer_id], RslMessage_2a(h.view, opn, v)); assert p in ExtractSentPacketsFromIos(ios); var second_step, ios2 := lemma_PacketSentToIndexProcessedByIt(b, asp, h.start_step, h.processing_bound, first_step, acceptor_idx, p); assert f[second_step+1] <= f[prev_step] + asp.c.params.max_batch_delay + asp.max_clock_ambiguity * 2 + TimeToPerformGenericAction(asp) * 2 + h.processing_bound; step := lemma_IfLiveReplicasReadyForAnOperationThenLearnerEventuallyLearnsItSecondStep(b, asp, h, opn, prev_step, acceptor_idx, learner_idx, v, p, second_step, ios2); } lemma lemma_IfLearnerHas2bFromAcceptorItKeepsItHelper( b:Behavior, asp:AssumptionParameters, h:Phase2Params, opn:OperationNumber, acceptor_idx:int, learner_idx:int, j:int ) requires Phase2StableWithRequest(b, asp, h) requires h.start_step + 1 <= j requires 0 <= learner_idx < |asp.c.config.replica_ids| requires ExecutorHasLearnedDecisionAboutOp(b[j], learner_idx, opn) requires !LearnerHas2bFromAcceptorInView(b[j+1], acceptor_idx, learner_idx, h.view, opn) requires !ExecutorHasLearnedDecisionAboutOp(b[j+1], learner_idx, opn) requires NoReplicaBeyondView(b[j+1], h.view) ensures false { lemma_ConstantsAllConsistent(b, asp.c, j); lemma_ConstantsAllConsistent(b, asp.c, j+1); lemma_AssumptionsMakeValidTransition(b, asp.c, j); var s := b[j].replicas[learner_idx].replica; var s' := b[j+1].replicas[learner_idx].replica; assert NoReplicaBeyondView(b[j+1], h.view); lemma_IfNoReplicaBeyondViewNowThenNoReplicaBeyondViewEarlier(b, asp, j, j+1, h.view); assert NoReplicaBeyondView(b[j], h.view); lemma_ProposerStaysInState2InPhase2(b, asp, h, j); lemma_ProposerStaysInState2InPhase2(b, asp, h, j+1); assert s'.executor.ops_complete != s.executor.ops_complete || s'.executor.next_op_to_execute != s.executor.next_op_to_execute; var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, j, learner_idx); } lemma lemma_IfLearnerHas2bFromAcceptorItKeepsItHelper2( b:Behavior, asp:AssumptionParameters, h:Phase2Params, opn:OperationNumber, acceptor_idx:int, learner_idx:int, j:int ) requires Phase2StableWithRequest(b, asp, h) requires h.start_step + 1 <= j requires 0 <= learner_idx < |asp.c.config.replica_ids| requires !ExecutorHasLearnedDecisionAboutOp(b[j], learner_idx, opn) requires LearnerHas2bFromAcceptorInView(b[j], acceptor_idx, learner_idx, h.view, opn) requires !LearnerHas2bFromAcceptorInView(b[j+1], acceptor_idx, learner_idx, h.view, opn) requires !ExecutorHasLearnedDecisionAboutOp(b[j+1], learner_idx, opn) requires NoReplicaBeyondView(b[j+1], h.view) ensures false { lemma_ConstantsAllConsistent(b, asp.c, j); lemma_ConstantsAllConsistent(b, asp.c, j+1); lemma_AssumptionsMakeValidTransition(b, asp.c, j); var s := b[j].replicas[learner_idx].replica; var s' := b[j+1].replicas[learner_idx].replica; assert NoReplicaBeyondView(b[j+1], h.view); lemma_IfNoReplicaBeyondViewNowThenNoReplicaBeyondViewEarlier(b, asp, j, j+1, h.view); assert NoReplicaBeyondView(b[j], h.view); lemma_ProposerStaysInState2InPhase2(b, asp, h, j); lemma_ProposerStaysInState2InPhase2(b, asp, h, j+1); lemma_LearnerMaxBallotSeenNeverExceedsViewDuringPhase2(b, asp, h, j, learner_idx); lemma_LearnerMaxBallotSeenNeverExceedsViewDuringPhase2(b, asp, h, j+1, learner_idx); assert s'.learner.max_ballot_seen != s.learner.max_ballot_seen || s'.learner.unexecuted_learner_state != s.learner.unexecuted_learner_state; var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, j, learner_idx); assert BalLeq(s.learner.max_ballot_seen, s'.learner.max_ballot_seen); assert s'.learner.max_ballot_seen == s.learner.max_ballot_seen; } lemma lemma_IfLearnerHas2bFromAcceptorItKeepsIt( b:Behavior, asp:AssumptionParameters, h:Phase2Params, opn:OperationNumber, acceptor_idx:int, learner_idx:int, i:int ) requires Phase2StableWithRequest(b, asp, h) requires h.start_step + 1 <= i requires 0 <= learner_idx < |asp.c.config.replica_ids| requires sat(i, or(LearnerHas2bFromAcceptorInViewTemporal(b, acceptor_idx, learner_idx, h.view, opn), or(ExecutorHasLearnedDecisionAboutOpTemporal(b, learner_idx, opn), not(NoReplicaBeyondViewTemporal(b, h.view))))) ensures sat(i, always(or(LearnerHas2bFromAcceptorInViewTemporal(b, acceptor_idx, learner_idx, h.view, opn), or(ExecutorHasLearnedDecisionAboutOpTemporal(b, learner_idx, opn), not(NoReplicaBeyondViewTemporal(b, h.view)))))); { var x := or(LearnerHas2bFromAcceptorInViewTemporal(b, acceptor_idx, learner_idx, h.view, opn), or(ExecutorHasLearnedDecisionAboutOpTemporal(b, learner_idx, opn), not(NoReplicaBeyondViewTemporal(b, h.view)))); forall j | i <= j ensures sat(j, imply(x, next(x))) { if sat(j, x) && !sat(j+1, x) { if sat(j, ExecutorHasLearnedDecisionAboutOpTemporal(b, learner_idx, opn)) { lemma_IfLearnerHas2bFromAcceptorItKeepsItHelper(b, asp, h, opn, acceptor_idx, learner_idx, j); } else if sat(j, LearnerHas2bFromAcceptorInViewTemporal(b, acceptor_idx, learner_idx, h.view, opn)) { lemma_IfLearnerHas2bFromAcceptorItKeepsItHelper2(b, asp, h, opn, acceptor_idx, learner_idx, j); } else { assert NoReplicaBeyondView(b[j+1], h.view); lemma_IfNoReplicaBeyondViewNowThenNoReplicaBeyondViewEarlier(b, asp, j, j+1, h.view); assert NoReplicaBeyondView(b[j], h.view); assert false; } } reveal imply(); reveal next(); } TemporalInductionNext(i, x); } lemma lemma_IfLiveReplicasReadyForAnOperationThenLearnerEventuallyLearnsItFromAll( b:Behavior, asp:AssumptionParameters, h:Phase2Params, opn:OperationNumber, prev_step:int, learner_idx:int ) returns ( step:int ) requires Phase2StableWithRequest(b, asp, h) requires opn >= h.log_truncation_point requires h.start_step + 1 <= prev_step requires AllLiveReplicasReadyForNextOperation(b[prev_step], asp.live_quorum, h.view, opn) requires learner_idx in asp.live_quorum ensures h.start_step + 1 <= step ensures var f := PaxosTimeMap(b); var t := b[prev_step].environment.time + asp.c.params.max_batch_delay + asp.max_clock_ambiguity * 2 + TimeToPerformGenericAction(asp) * 2 + h.processing_bound * 2; var x := always(andset(LearnerHas2bFromEveryAcceptorInViewTemporalSet(b, asp.live_quorum, learner_idx, h.view, opn))); var y := AllLiveReplicasCaughtUpWithEarlierOperationWithRequestQueueEmptyTemporal(b, asp.live_quorum, h.view, opn + 1); sat(step, beforeabsolutetime(or(x, y), t, f)) { var t := b[prev_step].environment.time - b[h.start_step + 1].environment.time + asp.c.params.max_batch_delay + asp.max_clock_ambiguity * 2 + TimeToPerformGenericAction(asp) * 2 + h.processing_bound * 2; var f := PaxosTimeMap(b); var y := AllLiveReplicasCaughtUpWithEarlierOperationWithRequestQueueEmptyTemporal(b, asp.live_quorum, h.view, opn + 1); var x2 := ExecutorHasLearnedDecisionAboutOpTemporal(b, learner_idx, opn); var z := NoReplicaBeyondViewTemporal(b, h.view); lemma_TimeAdvancesBetween(b, asp, h.start_step + 1, prev_step); if sat(h.start_step + 1, eventuallywithin(y, t, f)) { step := TemporalDeduceFromEventual(h.start_step + 1, beforeabsolutetime(y, f[h.start_step + 1] + t, f)); return; } forall acceptor_idx | acceptor_idx in asp.live_quorum ensures var a := or(LearnerHas2bFromAcceptorInViewTemporal(b, acceptor_idx, learner_idx, h.view, opn), or(x2, not(z))); sat(h.start_step + 1, eventuallywithin(always(a), t, f)) { var learn_step := lemma_IfLiveReplicasReadyForAnOperationThenLearnerEventuallyLearnsIt(b, asp, h, opn, prev_step, acceptor_idx, learner_idx); assert f[learn_step] <= f[h.start_step+1] + t; var x1 := LearnerHas2bFromAcceptorInViewTemporal(b, acceptor_idx, learner_idx, h.view, opn); var a := or(x1, or(x2, not(z))); assert sat(learn_step, or(x1, or(x2, or(y, not(z))))); if sat(learn_step, y) { TemporalEventually(h.start_step + 1, learn_step, beforeabsolutetime(y, f[h.start_step + 1] + t, f)); assert sat(h.start_step + 1, eventuallywithin(y, t, f)); assert false; } else { lemma_IfLearnerHas2bFromAcceptorItKeepsIt(b, asp, h, opn, acceptor_idx, learner_idx, learn_step); TemporalEventually(h.start_step + 1, learn_step, beforeabsolutetime(always(a), f[h.start_step + 1] + t, f)); assert sat(h.start_step + 1, eventuallywithin(always(a), t, f)); } } var xs := LearnerHas2bFromEveryAcceptorInViewTemporalSet(b, asp.live_quorum, learner_idx, h.view, opn); Lemma_EventuallyAlwaysWithinEachImpliesEventuallyAlwaysWithinAll(h.start_step + 1, xs, t, f); step := TemporalDeduceFromEventuallyWithin(h.start_step + 1, always(andset(xs)), t, f); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/LivenessProof/Phase2b.i.dfy ================================================ include "Assumptions.i.dfy" include "Invariants.i.dfy" include "StablePeriod.i.dfy" include "NextOp.i.dfy" include "Phase2a.i.dfy" include "../CommonProof/Quorum.i.dfy" include "../CommonProof/LearnerState.i.dfy" module LivenessProof__Phase2b_i { import opened LiveRSL__Configuration_i import opened LiveRSL__Constants_i import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Environment_i import opened LiveRSL__Executor_i import opened LiveRSL__Replica_i import opened LiveRSL__Types_i import opened LivenessProof__Assumptions_i import opened LivenessProof__Invariants_i import opened LivenessProof__StablePeriod_i import opened LivenessProof__NextOp_i import opened LivenessProof__Phase2a_i import opened LivenessProof__Phase2Invariants_i import opened LivenessProof__RealTime_i import opened LivenessProof__RoundRobin_i import opened LivenessProof__WF1_i import opened CommonProof__Actions_i import opened CommonProof__Assumptions_i import opened CommonProof__Constants_i import opened CommonProof__LearnerState_i import opened CommonProof__LogTruncationPoint_i import opened CommonProof__Quorum_i import opened Temporal__LeadsTo_i import opened Temporal__Rules_i import opened Temporal__Sets_i import opened Temporal__Temporal_s import opened Temporal__Time_s import opened Temporal__WF1_i import opened Environment_s import opened Collections__Maps2_s import opened Collections__Sets_i lemma lemma_IfLiveReplicasReadyForAnOperationAndLearnerHas2bsFromAllLiveReplicasThenExecutorEventuallyHasDecisionWF1Req2( b:Behavior, asp:AssumptionParameters, h:Phase2Params, opn:OperationNumber, prev_step:int, i:int, learner_idx:int ) requires Phase2StableWithRequest(b, asp, h) requires opn >= h.log_truncation_point requires h.start_step + 1 <= prev_step <= i requires AllLiveReplicasReadyForNextOperation(b[prev_step], asp.live_quorum, h.view, opn) requires learner_idx in asp.live_quorum requires sat(i, always(andset(LearnerHas2bFromEveryAcceptorInViewTemporalSet(b, asp.live_quorum, learner_idx, h.view, opn)))) requires !sat(i, ExecutorHasLearnedDecisionAboutOpTemporal(b, learner_idx, opn)) requires !sat(i+1, ExecutorHasLearnedDecisionAboutOpTemporal(b, learner_idx, opn)) requires !sat(i, AllLiveReplicasCaughtUpWithEarlierOperationWithRequestQueueEmptyTemporal(b, asp.live_quorum, h.view, opn + 1)) requires !sat(i+1, AllLiveReplicasCaughtUpWithEarlierOperationWithRequestQueueEmptyTemporal(b, asp.live_quorum, h.view, opn + 1)) requires sat(i, NoReplicaBeyondViewTemporal(b, h.view)) requires sat(i+1, NoReplicaBeyondViewTemporal(b, h.view)) requires sat(i, ReplicaSchedule(b, learner_idx)[5]) ensures false { var w_once := andset(LearnerHas2bFromEveryAcceptorInViewTemporalSet(b, asp.live_quorum, learner_idx, h.view, opn)); var x := ExecutorHasLearnedDecisionAboutOpTemporal(b, learner_idx, opn); var z := NoReplicaBeyondViewTemporal(b, h.view); lemma_ConstantsAllConsistent(b, asp.c, i); lemma_ConstantsAllConsistent(b, asp.c, i+1); var s := b[i].replicas[learner_idx].replica; var s' := b[i+1].replicas[learner_idx].replica; assert SpecificSpontaneousRslActionOccurs(b[i], b[i+1], LReplicaNextSpontaneousMaybeMakeDecision, learner_idx); var ios:seq :| && RslNextOneReplica(b[i], b[i+1], learner_idx, ios) && LReplicaNextSpontaneousMaybeMakeDecision(s, s', ExtractSentPacketsFromIos(ios)); lemma_ConstantsAllConsistent(b, asp.c, prev_step); lemma_OpsCompleteMonotonic(b, asp.c, prev_step, i, learner_idx); assert s.executor.ops_complete == opn; assert s.executor.next_op_to_execute.OutstandingOpUnknown?; forall acceptor_idx | acceptor_idx in asp.live_quorum ensures opn in s.learner.unexecuted_learner_state ensures asp.c.config.replica_ids[acceptor_idx] in s.learner.unexecuted_learner_state[opn].received_2b_message_senders { var a := or(LearnerHas2bFromAcceptorInViewTemporal(b, acceptor_idx, learner_idx, h.view, opn), or(x, not(z))); assert a in LearnerHas2bFromEveryAcceptorInViewTemporalSet(b, asp.live_quorum, learner_idx, h.view, opn); TemporalDeduceFromAlways(i, i+1, w_once); assert sat(i+1, a); } assert {:split_here} true; assert opn in s.learner.unexecuted_learner_state; lemma_Received2bMessageSendersAlwaysValidReplicas(b, asp.c, i, learner_idx, opn); var acceptor_indices := lemma_GetIndicesFromNodes(s.learner.unexecuted_learner_state[opn].received_2b_message_senders, asp.c.config); forall acceptor_idx | acceptor_idx in asp.live_quorum ensures acceptor_idx in acceptor_indices { assert asp.c.config.replica_ids[acceptor_idx] in s.learner.unexecuted_learner_state[opn].received_2b_message_senders; assert ReplicasDistinct(asp.c.config.replica_ids, acceptor_idx, GetReplicaIndex(asp.c.config.replica_ids[acceptor_idx], asp.c.config)); } assert {:split_here} true; SubsetCardinality(asp.live_quorum, acceptor_indices); assert |asp.live_quorum| <= |s.learner.unexecuted_learner_state[opn].received_2b_message_senders|; assert |s.learner.unexecuted_learner_state[opn].received_2b_message_senders| >= LMinQuorumSize(s.learner.constants.all.config); assert LExecutorGetDecision(s.executor, s'.executor, s.learner.max_ballot_seen, opn, s.learner.unexecuted_learner_state[opn].candidate_learned_value); assert sat(i+1, ExecutorHasLearnedDecisionAboutOpTemporal(b, learner_idx, opn)); assert !sat(i+1, ExecutorHasLearnedDecisionAboutOpTemporal(b, learner_idx, opn)); assert false; } lemma lemma_IfLiveReplicasReadyForAnOperationAndLearnerHas2bsFromAllLiveReplicasThenExecutorEventuallyHasDecision( b:Behavior, asp:AssumptionParameters, h:Phase2Params, opn:OperationNumber, prev_step:int, first_step:int, learner_idx:int ) returns ( step:int ) requires Phase2StableWithRequest(b, asp, h) requires opn >= h.log_truncation_point requires h.start_step + 1 <= prev_step <= first_step requires AllLiveReplicasReadyForNextOperation(b[prev_step], asp.live_quorum, h.view, opn) requires sat(first_step, always(andset(LearnerHas2bFromEveryAcceptorInViewTemporalSet(b, asp.live_quorum, learner_idx, h.view, opn)))) requires learner_idx in asp.live_quorum ensures first_step <= step ensures b[step].environment.time <= b[first_step].environment.time + TimeToPerformGenericAction(asp) ensures var x := ExecutorHasLearnedDecisionAboutOpTemporal(b, learner_idx, opn); var y := AllLiveReplicasCaughtUpWithEarlierOperationWithRequestQueueEmptyTemporal(b, asp.live_quorum, h.view, opn + 1); var z := NoReplicaBeyondViewTemporal(b, h.view); sat(step, or(x, or(y, not(z)))) { var f := PaxosTimeMap(b); var w_once := andset(LearnerHas2bFromEveryAcceptorInViewTemporalSet(b, asp.live_quorum, learner_idx, h.view, opn)); var w := always(w_once); var x := ExecutorHasLearnedDecisionAboutOpTemporal(b, learner_idx, opn); var y := AllLiveReplicasCaughtUpWithEarlierOperationWithRequestQueueEmptyTemporal(b, asp.live_quorum, h.view, opn + 1); var z := NoReplicaBeyondViewTemporal(b, h.view); lemma_TimeAdvancesBetween(b, asp, h.start_step + 1, prev_step); var P := w; var Q := or(x, or(y, not(z))); var Action := ReplicaSchedule(b, learner_idx)[5]; forall i | first_step <= i ensures sat(i, TemporalWF1Req1(P, Q)) ensures sat(i, TemporalWF1Req2(P, Q, Action)) { if sat(i, P) && !sat(i, Q) && !sat(i+1, Q) { Lemma_AlwaysImpliesLaterAlways(i, i+1, w_once); assert sat(i+1, P); if sat(i, Action) { lemma_IfLiveReplicasReadyForAnOperationAndLearnerHas2bsFromAllLiveReplicasThenExecutorEventuallyHasDecisionWF1Req2(b, asp, h, opn, prev_step, i, learner_idx); assert false; } } } TemporalAlways(first_step, TemporalWF1Req1(P, Q)); TemporalAlways(first_step, TemporalWF1Req2(P, Q, Action)); lemma_ReplicaNextPerformsSubactionPeriodically(b, asp, learner_idx, 5); lemma_EstablishRequirementsForWF1RealTime(b, asp, first_step, Action, TimeToPerformGenericAction(asp)); TemporalWF1RealTime(first_step, P, Q, Action, TimeToPerformGenericAction(asp), f); step := TemporalDeduceFromLeadsToWithin(first_step, first_step, P, Q, TimeToPerformGenericAction(asp), f); } lemma lemma_IfLiveReplicasReadyForAnOperationThenExecutorEventuallyHasDecision( b:Behavior, asp:AssumptionParameters, h:Phase2Params, opn:OperationNumber, prev_step:int, learner_idx:int ) returns ( step:int ) requires Phase2StableWithRequest(b, asp, h) requires opn >= h.log_truncation_point requires h.start_step + 1 <= prev_step requires AllLiveReplicasReadyForNextOperation(b[prev_step], asp.live_quorum, h.view, opn) requires learner_idx in asp.live_quorum ensures h.start_step + 1 <= step ensures var f := PaxosTimeMap(b); var t := b[prev_step].environment.time + asp.c.params.max_batch_delay + asp.max_clock_ambiguity * 2 + TimeToPerformGenericAction(asp) * 3 + h.processing_bound * 2; var x := ExecutorHasLearnedDecisionAboutOpTemporal(b, learner_idx, opn); var y := AllLiveReplicasCaughtUpWithEarlierOperationWithRequestQueueEmptyTemporal(b, asp.live_quorum, h.view, opn + 1); var z := NoReplicaBeyondViewTemporal(b, h.view); sat(step, beforeabsolutetime(or(x, or(y, not(z))), t, f)) { var w_once := andset(LearnerHas2bFromEveryAcceptorInViewTemporalSet(b, asp.live_quorum, learner_idx, h.view, opn)); var w := always(w_once); var x := ExecutorHasLearnedDecisionAboutOpTemporal(b, learner_idx, opn); var y := AllLiveReplicasCaughtUpWithEarlierOperationWithRequestQueueEmptyTemporal(b, asp.live_quorum, h.view, opn + 1); var z := NoReplicaBeyondViewTemporal(b, h.view); var first_step := lemma_IfLiveReplicasReadyForAnOperationThenLearnerEventuallyLearnsItFromAll(b, asp, h, opn, prev_step, learner_idx); if sat(first_step, or(x, or(y, not(z)))) { step := first_step; return; } if first_step < prev_step { Lemma_AlwaysImpliesLaterAlways(first_step, prev_step, w_once); first_step := prev_step; } assert sat(first_step, w); step := lemma_IfLiveReplicasReadyForAnOperationAndLearnerHas2bsFromAllLiveReplicasThenExecutorEventuallyHasDecision(b, asp, h, opn, prev_step, first_step, learner_idx); } lemma lemma_ExecutorHasLearnedDecisionAboutOpStable( b:Behavior, c:LConstants, i:int, j:int, idx:int, opn:OperationNumber ) requires IsValidBehaviorPrefix(b, c, j) requires 0 <= i <= j requires 0 <= idx < |b[i].replicas| requires sat(i, ExecutorHasLearnedDecisionAboutOpTemporal(b, idx, opn)) ensures sat(j, ExecutorHasLearnedDecisionAboutOpTemporal(b, idx, opn)) decreases j - i { if j == i { return; } lemma_ExecutorHasLearnedDecisionAboutOpStable(b, c, i, j-1, idx, opn); if !sat(j, ExecutorHasLearnedDecisionAboutOpTemporal(b, idx, opn)) { lemma_ConstantsAllConsistent(b, c, j-1); lemma_ConstantsAllConsistent(b, c, j); var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, c, j-1, idx); assert false; } } lemma lemma_IfLiveReplicasReadyForAnOperationThenExecutorEventuallyExecutesIt( b:Behavior, asp:AssumptionParameters, h:Phase2Params, opn:OperationNumber, prev_step:int, executor_idx:int ) returns ( step:int ) requires Phase2StableWithRequest(b, asp, h) requires opn >= h.log_truncation_point requires h.start_step + 1 <= prev_step requires AllLiveReplicasReadyForNextOperation(b[prev_step], asp.live_quorum, h.view, opn) requires executor_idx in asp.live_quorum ensures h.start_step + 1 <= step ensures var f := PaxosTimeMap(b); var t := b[prev_step].environment.time + asp.c.params.max_batch_delay + asp.max_clock_ambiguity * 2 + TimeToPerformGenericAction(asp) * 4 + h.processing_bound * 2; var x := ReplicaCaughtUpTemporal(b, executor_idx, opn + 1); var y := AllLiveReplicasCaughtUpWithEarlierOperationWithRequestQueueEmptyTemporal(b, asp.live_quorum, h.view, opn + 1); var z := NoReplicaBeyondViewTemporal(b, h.view); sat(step, beforeabsolutetime(or(x, or(y, not(z))), t, f)) { var f := PaxosTimeMap(b); var w := ExecutorHasLearnedDecisionAboutOpTemporal(b, executor_idx, opn); var x := ReplicaCaughtUpTemporal(b, executor_idx, opn + 1); var y := AllLiveReplicasCaughtUpWithEarlierOperationWithRequestQueueEmptyTemporal(b, asp.live_quorum, h.view, opn + 1); var z := NoReplicaBeyondViewTemporal(b, h.view); var first_step := lemma_IfLiveReplicasReadyForAnOperationThenExecutorEventuallyHasDecision(b, asp, h, opn, prev_step, executor_idx); if sat(first_step, or(x, or(y, not(z)))) { step := first_step; return; } if first_step < prev_step { lemma_ExecutorHasLearnedDecisionAboutOpStable(b, asp.c, first_step, prev_step, executor_idx, opn); first_step := prev_step; } assert sat(first_step, w); var P := w; var Q := or(x, or(y, not(z))); var Action := ReplicaSchedule(b, executor_idx)[6]; forall i | first_step <= i ensures sat(i, TemporalWF1Req1(P, Q)) ensures sat(i, TemporalWF1Req2(P, Q, Action)) { if sat(i, P) && !sat(i, Q) && !sat(i+1, Q) { lemma_ExecutorHasLearnedDecisionAboutOpStable(b, asp.c, first_step, i+1, executor_idx, opn); assert sat(i+1, P); if sat(i, Action) { lemma_ConstantsAllConsistent(b, asp.c, i); lemma_ConstantsAllConsistent(b, asp.c, i+1); var s := b[i].replicas[executor_idx].replica; var s' := b[i+1].replicas[executor_idx].replica; assert SpecificSpontaneousRslActionOccurs(b[i], b[i+1], LReplicaNextSpontaneousMaybeExecute, executor_idx); var ios:seq :| && RslNextOneReplica(b[i], b[i+1], executor_idx, ios) && LReplicaNextSpontaneousMaybeExecute(s, s', ExtractSentPacketsFromIos(ios)); lemma_OverflowProtectionNotUsedForReplica(b, asp, i, executor_idx); assert LExecutorExecute(s.executor, s'.executor, ExtractSentPacketsFromIos(ios)); assert false; } } } TemporalAlways(first_step, TemporalWF1Req1(P, Q)); TemporalAlways(first_step, TemporalWF1Req2(P, Q, Action)); lemma_ReplicaNextPerformsSubactionPeriodically(b, asp, executor_idx, 6); lemma_EstablishRequirementsForWF1RealTime(b, asp, first_step, Action, TimeToPerformGenericAction(asp)); TemporalWF1RealTime(first_step, P, Q, Action, TimeToPerformGenericAction(asp), f); step := TemporalDeduceFromLeadsToWithin(first_step, first_step, P, Q, TimeToPerformGenericAction(asp), f); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/LivenessProof/Phase2c.i.dfy ================================================ include "Assumptions.i.dfy" include "Invariants.i.dfy" include "StablePeriod.i.dfy" include "NextOp.i.dfy" include "Phase2b.i.dfy" include "GenericInvariants.i.dfy" include "../CommonProof/Quorum.i.dfy" include "../CommonProof/LearnerState.i.dfy" // Sure, there's no Phase 2c in Paxos. But it's what this file calls the phase // when the executors have finished executing the request and are telling the // primary about it so it can do log truncation. module LivenessProof__Phase2c_i { import opened LiveRSL__Acceptor_i import opened LiveRSL__Broadcast_i import opened LiveRSL__Configuration_i import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Environment_i import opened LiveRSL__Message_i import opened LiveRSL__Replica_i import opened LiveRSL__Types_i import opened LivenessProof__Assumptions_i import opened LivenessProof__Catchup_i import opened LivenessProof__Environment_i import opened LivenessProof__GenericInvariants_i import opened LivenessProof__Invariants_i import opened LivenessProof__NextOp_i import opened LivenessProof__PacketHandling_i import opened LivenessProof__Phase2b_i import opened LivenessProof__Phase2Invariants_i import opened LivenessProof__RealTime_i import opened LivenessProof__RoundRobin_i import opened LivenessProof__StablePeriod_i import opened LivenessProof__WF1_i import opened CommonProof__Actions_i import opened CommonProof__Constants_i import opened CommonProof__LogTruncationPoint_i import opened CommonProof__Quorum_i import opened Temporal__Induction_i import opened Temporal__LeadsTo_i import opened Temporal__Rules_i import opened Temporal__Sets_i import opened Temporal__Temporal_s import opened Temporal__Time_s import opened Temporal__Time_i import opened Temporal__WF1_i import opened Environment_s import opened Collections__CountMatches_i import opened Collections__Maps2_s import opened Collections__Sets_i import opened Math__mul_i predicate ReplicaSentHeartbeatToPrimaryReflectingOpn( ps:RslState, replica_idx:int, primary_idx:int, opn:OperationNumber, p:RslPacket ) { && ps.environment.nextStep.LEnvStepHostIos? && LIoOpSend(p) in ps.environment.nextStep.ios && 0 <= replica_idx < |ps.constants.config.replica_ids| && 0 <= primary_idx < |ps.constants.config.replica_ids| && p.src == ps.constants.config.replica_ids[replica_idx] && p.dst == ps.constants.config.replica_ids[primary_idx] && p.msg.RslMessage_Heartbeat? && p.msg.opn_ckpt >= opn && 0 <= replica_idx < |ps.replicas| && ps.replicas[replica_idx].replica.executor.ops_complete >= opn } function{:opaque} ReplicaSentHeartbeatToPrimaryReflectingOpnTemporal( b:Behavior, replica_idx:int, primary_idx:int, opn:OperationNumber ):temporal requires imaptotal(b) ensures forall i{:trigger sat(i, ReplicaSentHeartbeatToPrimaryReflectingOpnTemporal(b, replica_idx, primary_idx, opn))} :: sat(i, ReplicaSentHeartbeatToPrimaryReflectingOpnTemporal(b, replica_idx, primary_idx, opn)) <==> exists p :: ReplicaSentHeartbeatToPrimaryReflectingOpn(b[i], replica_idx, primary_idx, opn, p) { stepmap(imap i :: exists p :: ReplicaSentHeartbeatToPrimaryReflectingOpn(b[i], replica_idx, primary_idx, opn, p)) } function{:opaque} NextHeartbeatTimeOfReplicaIsParticularValueTemporal( b:Behavior, idx:int, nextHeartbeatTime:int ):temporal requires imaptotal(b) ensures forall i{:trigger sat(i, NextHeartbeatTimeOfReplicaIsParticularValueTemporal(b, idx, nextHeartbeatTime))} :: sat(i, NextHeartbeatTimeOfReplicaIsParticularValueTemporal(b, idx, nextHeartbeatTime)) <==> (0 <= idx < |b[i].replicas| && b[i].replicas[idx].replica.nextHeartbeatTime == nextHeartbeatTime) { stepmap(imap i :: 0 <= idx < |b[i].replicas| && b[i].replicas[idx].replica.nextHeartbeatTime == nextHeartbeatTime) } predicate PrimaryKnowsReplicaHasOpsComplete( ps:RslState, replica_idx:int, primary_idx:int, opn:OperationNumber ) { && 0 <= primary_idx < |ps.replicas| && 0 <= replica_idx < |ps.replicas| && 0 <= replica_idx < |ps.replicas[primary_idx].replica.acceptor.last_checkpointed_operation| && ps.replicas[primary_idx].replica.acceptor.last_checkpointed_operation[replica_idx] >= opn && ps.replicas[replica_idx].replica.executor.ops_complete>= opn } function{:opaque} PrimaryKnowsReplicaHasOpsCompleteTemporal( b:Behavior, replica_idx:int, primary_idx:int, opn:OperationNumber ):temporal requires imaptotal(b) ensures forall i{:trigger sat(i, PrimaryKnowsReplicaHasOpsCompleteTemporal(b, replica_idx, primary_idx, opn))} :: sat(i, PrimaryKnowsReplicaHasOpsCompleteTemporal(b, replica_idx, primary_idx, opn)) <==> PrimaryKnowsReplicaHasOpsComplete(b[i], replica_idx, primary_idx, opn) { stepmap(imap i :: PrimaryKnowsReplicaHasOpsComplete(b[i], replica_idx, primary_idx, opn)) } function{:opaque} PrimaryKnowsEveryReplicaHasOpsCompleteTemporalSet( b:Behavior, replica_indices:set, primary_idx:int, opn:OperationNumber ):set requires imaptotal(b) ensures forall replica_idx :: replica_idx in replica_indices ==> PrimaryKnowsReplicaHasOpsCompleteTemporal(b, replica_idx, primary_idx, opn) in PrimaryKnowsEveryReplicaHasOpsCompleteTemporalSet(b, replica_indices, primary_idx, opn) ensures forall x :: x in PrimaryKnowsEveryReplicaHasOpsCompleteTemporalSet(b, replica_indices, primary_idx, opn) ==> exists replica_idx :: && replica_idx in replica_indices && x == PrimaryKnowsReplicaHasOpsCompleteTemporal(b, replica_idx, primary_idx, opn) { set replica_idx | replica_idx in replica_indices :: PrimaryKnowsReplicaHasOpsCompleteTemporal(b, replica_idx, primary_idx, opn) } predicate PrimaryHasAdvancedLogTruncationPoint( ps:RslState, live_quorum:set, view:Ballot, opn:int ) { && (forall idx :: idx in live_quorum ==> ReplicaCaughtUp(ps, idx, opn)) && 0 <= view.proposer_id < |ps.replicas| && ps.replicas[view.proposer_id].replica.acceptor.log_truncation_point >= opn } function {:opaque} PrimaryHasAdvancedLogTruncationPointTemporal( b:Behavior, live_quorum:set, view:Ballot, opn:int ):temporal requires imaptotal(b) ensures forall i{:trigger sat(i, PrimaryHasAdvancedLogTruncationPointTemporal(b, live_quorum, view, opn))} :: sat(i, PrimaryHasAdvancedLogTruncationPointTemporal(b, live_quorum, view, opn)) == PrimaryHasAdvancedLogTruncationPoint(b[i], live_quorum, view, opn) { stepmap(imap i :: PrimaryHasAdvancedLogTruncationPoint(b[i], live_quorum, view, opn)) } lemma lemma_IfExecutorCaughtUpThenExecutorEventuallyExecutesItAndTellsPrimary( b:Behavior, asp:AssumptionParameters, h:Phase2Params, opn:OperationNumber, prev_step:int, first_step:int, executor_idx:int ) returns ( step:int ) requires Phase2StableWithRequest(b, asp, h) requires opn >= h.log_truncation_point requires h.start_step + 1 <= prev_step <= first_step requires AllLiveReplicasReadyForNextOperation(b[prev_step], asp.live_quorum, h.view, opn) requires executor_idx in asp.live_quorum requires sat(first_step, ReplicaCaughtUpTemporal(b, executor_idx, opn + 1)) ensures h.start_step + 1 <= step ensures b[step].environment.time <= b[first_step].environment.time + asp.c.params.heartbeat_period + asp.max_clock_ambiguity * 2 + TimeToPerformGenericAction(asp) ensures var x := ReplicaSentHeartbeatToPrimaryReflectingOpnTemporal(b, executor_idx, h.view.proposer_id, opn + 1); var y := AllLiveReplicasCaughtUpWithEarlierOperationWithRequestQueueEmptyTemporal(b, asp.live_quorum, h.view, opn + 1); var z := NoReplicaBeyondViewTemporal(b, h.view); sat(step, or(x, or(y, not(z)))) { var f := PaxosTimeMap(b); var w := ReplicaCaughtUpTemporal(b, executor_idx, opn + 1); var x := ReplicaSentHeartbeatToPrimaryReflectingOpnTemporal(b, executor_idx, h.view.proposer_id, opn + 1); var y := AllLiveReplicasCaughtUpWithEarlierOperationWithRequestQueueEmptyTemporal(b, asp.live_quorum, h.view, opn + 1); var z := NoReplicaBeyondViewTemporal(b, h.view); lemma_ConstantsAllConsistent(b, asp.c, first_step); var nextHeartbeatTime := b[first_step].replicas[executor_idx].replica.nextHeartbeatTime; lemma_HeartbeatTimerNeverTooFarInFuture(b, asp, first_step, executor_idx); assert nextHeartbeatTime <= b[first_step].environment.time + asp.c.params.heartbeat_period + asp.max_clock_ambiguity; var P := and(w, NextHeartbeatTimeOfReplicaIsParticularValueTemporal(b, executor_idx, nextHeartbeatTime)); var Q := or(x, or(y, not(z))); var Action := ReplicaSchedule(b, executor_idx)[9]; forall i | first_step <= i ensures sat(i, TemporalWF1Req1(P, Q)) ensures sat(i, TemporalWF1RealTimeDelayedReq2(P, Q, Action, nextHeartbeatTime + asp.max_clock_ambiguity, f)) { if sat(i, P) && !sat(i, Q) && !sat(i+1, Q) { lemma_ConstantsAllConsistent(b, asp.c, i); lemma_ConstantsAllConsistent(b, asp.c, i+1); lemma_AssumptionsMakeValidTransition(b, asp.c, i); var s := b[i].replicas[executor_idx].replica; var s' := b[i+1].replicas[executor_idx].replica; var m := RslMessage_Heartbeat(s.proposer.election_state.current_view, s.constants.my_index in s.proposer.election_state.current_view_suspectors, s.executor.ops_complete); var p := LPacket(asp.c.config.replica_ids[h.view.proposer_id], asp.c.config.replica_ids[executor_idx], m); lemma_OpsCompleteMonotonic(b, asp.c, first_step, i+1, executor_idx); if !sat(i+1, P) { var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, i, executor_idx); assert LBroadcastToEveryone(asp.c.config, executor_idx, m, ExtractSentPacketsFromIos(ios)); assert LIoOpSend(p) in ios; assert ReplicaSentHeartbeatToPrimaryReflectingOpn(b[i], executor_idx, h.view.proposer_id, opn + 1, p); assert sat(i+1, x); assert false; } if sat(i, nextafter(Action, nextHeartbeatTime + asp.max_clock_ambiguity, f)) { assert SpecificClockReadingRslActionOccurs(b[i], b[i+1], LReplicaNextReadClockMaybeSendHeartbeat, executor_idx); var ios:seq :| && RslNextOneReplica(b[i], b[i+1], executor_idx, ios) && SpontaneousIos(ios, 1) && LReplicaNextReadClockMaybeSendHeartbeat(s, s', SpontaneousClock(ios), ExtractSentPacketsFromIos(ios)); lemma_ClockAmbiguityLimitApplies(b, asp, i, executor_idx, ios[0]); assert ios[0].t >= b[i].environment.time - asp.max_clock_ambiguity == b[i+1].environment.time - asp.max_clock_ambiguity >= nextHeartbeatTime == s.nextHeartbeatTime; assert LBroadcastToEveryone(asp.c.config, executor_idx, m, ExtractSentPacketsFromIos(ios)); assert LIoOpSend(p) in ios; assert ReplicaSentHeartbeatToPrimaryReflectingOpn(b[i], executor_idx, h.view.proposer_id, opn + 1, p); assert sat(i+1, x); assert false; } } } TemporalAlways(first_step, TemporalWF1Req1(P, Q)); TemporalAlways(first_step, TemporalWF1RealTimeDelayedReq2(P, Q, Action, nextHeartbeatTime + asp.max_clock_ambiguity, f)); lemma_ReplicaNextPerformsSubactionPeriodically(b, asp, executor_idx, 9); lemma_EstablishRequirementsForWF1RealTimeDelayed(b, asp, first_step, Action, TimeToPerformGenericAction(asp)); step := TemporalWF1RealTimeDelayed(first_step, P, Q, Action, TimeToPerformGenericAction(asp), nextHeartbeatTime + asp.max_clock_ambiguity, f); } lemma lemma_IfLiveReplicasReadyForAnOperationThenExecutorEventuallyExecutesItAndTellsPrimary( b:Behavior, asp:AssumptionParameters, h:Phase2Params, opn:OperationNumber, prev_step:int, executor_idx:int ) returns ( step:int ) requires Phase2StableWithRequest(b, asp, h) requires opn >= h.log_truncation_point requires h.start_step + 1 <= prev_step requires AllLiveReplicasReadyForNextOperation(b[prev_step], asp.live_quorum, h.view, opn) requires executor_idx in asp.live_quorum ensures h.start_step + 1 <= step ensures var f := PaxosTimeMap(b); var t := b[prev_step].environment.time + asp.c.params.max_batch_delay + asp.max_clock_ambiguity * 4 + asp.c.params.heartbeat_period + TimeToPerformGenericAction(asp) * 5 + h.processing_bound * 2; var x := ReplicaSentHeartbeatToPrimaryReflectingOpnTemporal(b, executor_idx, h.view.proposer_id, opn + 1); var y := AllLiveReplicasCaughtUpWithEarlierOperationWithRequestQueueEmptyTemporal(b, asp.live_quorum, h.view, opn + 1); var z := NoReplicaBeyondViewTemporal(b, h.view); sat(step, beforeabsolutetime(or(x, or(y, not(z))), t, f)) { var first_step := lemma_IfLiveReplicasReadyForAnOperationThenExecutorEventuallyExecutesIt(b, asp, h, opn, prev_step, executor_idx); var w := ReplicaCaughtUpTemporal(b, executor_idx, opn + 1); var x := ReplicaSentHeartbeatToPrimaryReflectingOpnTemporal(b, executor_idx, h.view.proposer_id, opn + 1); var y := AllLiveReplicasCaughtUpWithEarlierOperationWithRequestQueueEmptyTemporal(b, asp.live_quorum, h.view, opn + 1); var z := NoReplicaBeyondViewTemporal(b, h.view); if sat(first_step, or(x, or(y, not(z)))) { step := first_step; return; } if first_step < prev_step { lemma_OpsCompleteMonotonic(b, asp.c, first_step, prev_step, executor_idx); first_step := prev_step; } assert sat(first_step, w); step := lemma_IfExecutorCaughtUpThenExecutorEventuallyExecutesItAndTellsPrimary(b, asp, h, opn, prev_step, first_step, executor_idx); } lemma lemma_IfLiveReplicasReadyForAnOperationThenPrimaryFindsOutExecutorExecutedIt( b:Behavior, asp:AssumptionParameters, h:Phase2Params, opn:OperationNumber, prev_step:int, executor_idx:int ) returns ( step:int ) requires Phase2StableWithRequest(b, asp, h) requires opn >= h.log_truncation_point requires h.start_step + 1 <= prev_step requires AllLiveReplicasReadyForNextOperation(b[prev_step], asp.live_quorum, h.view, opn) requires executor_idx in asp.live_quorum ensures h.start_step + 1 <= step ensures var f := PaxosTimeMap(b); var t := b[prev_step].environment.time + asp.c.params.max_batch_delay + asp.max_clock_ambiguity * 4 + asp.c.params.heartbeat_period + TimeToPerformGenericAction(asp) * 5 + h.processing_bound * 3; var x := PrimaryKnowsReplicaHasOpsCompleteTemporal(b, executor_idx, h.view.proposer_id, opn + 1); var y := AllLiveReplicasCaughtUpWithEarlierOperationWithRequestQueueEmptyTemporal(b, asp.live_quorum, h.view, opn + 1); var z := NoReplicaBeyondViewTemporal(b, h.view); sat(step, beforeabsolutetime(or(x, or(y, not(z))), t, f)) { var f := PaxosTimeMap(b); var w := ReplicaSentHeartbeatToPrimaryReflectingOpnTemporal(b, executor_idx, h.view.proposer_id, opn + 1); var x := PrimaryKnowsReplicaHasOpsCompleteTemporal(b, executor_idx, h.view.proposer_id, opn + 1); var y := AllLiveReplicasCaughtUpWithEarlierOperationWithRequestQueueEmptyTemporal(b, asp.live_quorum, h.view, opn + 1); var z := NoReplicaBeyondViewTemporal(b, h.view); var t := b[prev_step].environment.time + asp.c.params.max_batch_delay + asp.max_clock_ambiguity * 4 + asp.c.params.heartbeat_period + TimeToPerformGenericAction(asp) * 5 + h.processing_bound * 3; var first_step := lemma_IfLiveReplicasReadyForAnOperationThenExecutorEventuallyExecutesItAndTellsPrimary(b, asp, h, opn, prev_step, executor_idx); if sat(first_step, or(x, or(y, not(z)))) { step := first_step; return; } assert !PrimaryKnowsReplicaHasOpsComplete(b[first_step], executor_idx, h.view.proposer_id, opn + 1); assert !AllLiveReplicasCaughtUpWithEarlierOperationWithRequestQueueEmpty(b[first_step], asp.live_quorum, h.view, opn + 1); assert NoReplicaBeyondView(b[first_step], h.view); lemma_ConstantsAllConsistent(b, asp.c, first_step); assert sat(first_step, w); var p :| ReplicaSentHeartbeatToPrimaryReflectingOpn(b[first_step], executor_idx, h.view.proposer_id, opn + 1, p); lemma_AssumptionsMakeValidTransition(b, asp.c, first_step); assert b[first_step+1].environment.time == b[first_step].environment.time; var processing_step, ios := lemma_PacketSentToIndexProcessedByIt(b, asp, h.start_step, h.processing_bound, first_step, h.view.proposer_id, p); lemma_ConstantsAllConsistent(b, asp.c, processing_step); lemma_ConstantsAllConsistent(b, asp.c, processing_step+1); lemma_NextCheckpointedOperationAlwaysSizeOfReplicas(b, asp.c, processing_step, h.view.proposer_id); assert ReplicasDistinct(asp.c.config.replica_ids, executor_idx, GetReplicaIndex(p.src, asp.c.config)); lemma_OpsCompleteMonotonic(b, asp.c, first_step, processing_step + 1, executor_idx); assert PrimaryKnowsReplicaHasOpsComplete(b[processing_step+1], executor_idx, h.view.proposer_id, opn + 1); step := processing_step + 1; assert f[step] <= t; assert sat(step, x); } lemma lemma_IfLiveReplicasReadyForAnOperationThenPrimaryAlwaysKnowsExecutorExecutedIt( b:Behavior, asp:AssumptionParameters, h:Phase2Params, opn:OperationNumber, prev_step:int, executor_idx:int ) returns ( step:int ) requires Phase2StableWithRequest(b, asp, h) requires opn >= h.log_truncation_point requires h.start_step + 1 <= prev_step requires AllLiveReplicasReadyForNextOperation(b[prev_step], asp.live_quorum, h.view, opn) requires executor_idx in asp.live_quorum ensures h.start_step + 1 <= step ensures var f := PaxosTimeMap(b); var t := b[prev_step].environment.time + asp.c.params.max_batch_delay + asp.max_clock_ambiguity * 4 + asp.c.params.heartbeat_period + TimeToPerformGenericAction(asp) * 5 + h.processing_bound * 3; var x := PrimaryKnowsReplicaHasOpsCompleteTemporal(b, executor_idx, h.view.proposer_id, opn + 1); var y := AllLiveReplicasCaughtUpWithEarlierOperationWithRequestQueueEmptyTemporal(b, asp.live_quorum, h.view, opn + 1); var z := NoReplicaBeyondViewTemporal(b, h.view); sat(step, beforeabsolutetime(or(always(x), or(y, not(z))), t, f)) { var f := PaxosTimeMap(b); var x := PrimaryKnowsReplicaHasOpsCompleteTemporal(b, executor_idx, h.view.proposer_id, opn + 1); var y := AllLiveReplicasCaughtUpWithEarlierOperationWithRequestQueueEmptyTemporal(b, asp.live_quorum, h.view, opn + 1); var z := NoReplicaBeyondViewTemporal(b, h.view); step := lemma_IfLiveReplicasReadyForAnOperationThenPrimaryFindsOutExecutorExecutedIt(b, asp, h, opn, prev_step, executor_idx); if sat(step, or(y, not(z))) { return; } assert sat(step, x); forall i | step <= i ensures sat(i, imply(x, next(x))) { if sat(i, x) && !sat(i+1, x) { lemma_ConstantsAllConsistent(b, asp.c, i); lemma_ConstantsAllConsistent(b, asp.c, i+1); lemma_AssumptionsMakeValidTransition(b, asp.c, i); lemma_OpsCompleteMonotonicOneStep(b, asp.c, i, executor_idx); lemma_NextCheckpointedOperationAlwaysSizeOfReplicas(b, asp.c, i, h.view.proposer_id); var s := b[i].replicas[h.view.proposer_id].replica.acceptor; var s' := b[i+1].replicas[h.view.proposer_id].replica.acceptor; assert s' != s; var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, i, h.view.proposer_id); var action_index := b[i].replicas[h.view.proposer_id].nextActionIndex; if action_index == 1 || action_index == 2 || action_index == 3 || action_index == 4 || action_index == 5 || action_index == 6 || action_index == 7 || action_index == 8 || action_index == 9 { assert s'.last_checkpointed_operation == s.last_checkpointed_operation; assert false; } else if ios[0].LIoOpTimeoutReceive? { assert s' == s; assert false; } else { assert ios[0].LIoOpReceive?; var msg := ios[0].r.msg; if msg.RslMessage_Invalid? || msg.RslMessage_Request? || msg.RslMessage_1a? || msg.RslMessage_1b? || msg.RslMessage_StartingPhase2? || msg.RslMessage_2a? || msg.RslMessage_2b? || msg.RslMessage_Reply? || msg.RslMessage_AppStateRequest? || msg.RslMessage_AppStateSupply? { assert s'.last_checkpointed_operation == s.last_checkpointed_operation; assert false; } else { assert msg.RslMessage_Heartbeat?; assert false; } } } reveal imply(); reveal next(); } TemporalInductionNext(step, x); } lemma lemma_IfLiveReplicasReadyForAnOperationThenPrimaryAlwaysKnowsEveryExecutorExecutedIt( b:Behavior, asp:AssumptionParameters, h:Phase2Params, opn:OperationNumber, prev_step:int ) returns ( step:int ) requires Phase2StableWithRequest(b, asp, h) requires opn >= h.log_truncation_point requires h.start_step + 1 <= prev_step requires AllLiveReplicasReadyForNextOperation(b[prev_step], asp.live_quorum, h.view, opn) ensures h.start_step + 1 <= step ensures var f := PaxosTimeMap(b); var t := b[prev_step].environment.time + asp.c.params.max_batch_delay + asp.max_clock_ambiguity * 4 + asp.c.params.heartbeat_period + TimeToPerformGenericAction(asp) * 5 + h.processing_bound * 3; var always_xs := always(andset(PrimaryKnowsEveryReplicaHasOpsCompleteTemporalSet(b, asp.live_quorum, h.view.proposer_id, opn + 1))); var y := AllLiveReplicasCaughtUpWithEarlierOperationWithRequestQueueEmptyTemporal(b, asp.live_quorum, h.view, opn + 1); var z := NoReplicaBeyondViewTemporal(b, h.view); sat(step, beforeabsolutetime(or(always_xs, or(y, not(z))), t, f)) { var f := PaxosTimeMap(b); var xs := PrimaryKnowsEveryReplicaHasOpsCompleteTemporalSet(b, asp.live_quorum, h.view.proposer_id, opn + 1); var always_xs := always(andset(xs)); var y := AllLiveReplicasCaughtUpWithEarlierOperationWithRequestQueueEmptyTemporal(b, asp.live_quorum, h.view, opn + 1); var z := NoReplicaBeyondViewTemporal(b, h.view); var start_time := b[h.start_step + 1].environment.time; var t := b[prev_step].environment.time + asp.c.params.max_batch_delay + asp.max_clock_ambiguity * 4 + asp.c.params.heartbeat_period + TimeToPerformGenericAction(asp) * 5 + h.processing_bound * 3; lemma_TimeAdvancesBetween(b, asp, h.start_step + 1, prev_step); forall x | x in xs ensures sat(h.start_step + 1, eventuallywithin(or(always(x), or(y, not(z))), t - start_time, f)) { var executor_idx :| executor_idx in asp.live_quorum && x == PrimaryKnowsReplicaHasOpsCompleteTemporal(b, executor_idx, h.view.proposer_id, opn + 1); var my_step := lemma_IfLiveReplicasReadyForAnOperationThenPrimaryAlwaysKnowsExecutorExecutedIt(b, asp, h, opn, prev_step, executor_idx); TemporalEventuallyWithin(h.start_step + 1, my_step, or(always(x), or(y, not(z))), t - start_time, f); } Lemma_EventuallyAlwaysWithinEachOrAlternativeImpliesEventuallyAlwaysWithinAllOrAlternative(h.start_step + 1, xs, or(y, not(z)), t - start_time, f); step := TemporalDeduceFromEventuallyWithin(h.start_step + 1, or(always_xs, or(y, not(z))), t - start_time, f); } lemma lemma_IfPrimaryTruncatesLogDueToCheckpointsWhileKnowingAllRepliesExecutedOpnThenItAdvancesLogTruncationPoint( b:Behavior, asp:AssumptionParameters, h:Phase2Params, opn:OperationNumber, i:int, ios:seq ) requires Phase2StableWithRequest(b, asp, h) requires opn >= h.log_truncation_point requires h.start_step + 1 <= i requires sat(i, andset(PrimaryKnowsEveryReplicaHasOpsCompleteTemporalSet(b, asp.live_quorum, h.view.proposer_id, opn + 1))) requires RslNextOneReplica(b[i], b[i+1], h.view.proposer_id, ios) requires 0 <= h.view.proposer_id < |b[i].replicas| requires 0 <= h.view.proposer_id < |b[i+1].replicas| requires LReplicaNextSpontaneousTruncateLogBasedOnCheckpoints(b[i].replicas[h.view.proposer_id].replica, b[i+1].replicas[h.view.proposer_id].replica, ExtractSentPacketsFromIos(ios)) ensures PrimaryHasAdvancedLogTruncationPoint(b[i+1], asp.live_quorum, h.view, opn + 1) { var xs := PrimaryKnowsEveryReplicaHasOpsCompleteTemporalSet(b, asp.live_quorum, h.view.proposer_id, opn + 1); var s := b[i].replicas[h.view.proposer_id].replica; forall idx | idx in asp.live_quorum ensures ReplicaCaughtUp(b[i+1], idx, opn + 1) ensures 0 <= idx < |s.acceptor.last_checkpointed_operation| ensures s.acceptor.last_checkpointed_operation[idx] >= opn + 1 { var x := PrimaryKnowsReplicaHasOpsCompleteTemporal(b, idx, h.view.proposer_id, opn + 1); assert x in xs; assert sat(i, x); } lemma_ConstantsAllConsistent(b, asp.c, i); lemma_ConstantsAllConsistent(b, asp.c, i+1); var a := s.acceptor.last_checkpointed_operation; forall opn' | IsLogTruncationPointValid(opn', a, s.constants.all.config) ensures opn' >= opn + 1 { if opn' < opn + 1 { assert IsNthHighestValueInSequence(opn', a, LMinQuorumSize(asp.c.config)); var matchfun := x => x > opn'; var matches := SetOfIndicesOfMatchesInSeq(a, matchfun); forall idx | idx in asp.live_quorum ensures idx in matches { assert 0 <= idx < |a|; // OBSERVE assert matchfun(a[idx]); // OBSERVE } assert asp.live_quorum <= matches; SubsetCardinality(asp.live_quorum, matches); assert |asp.live_quorum| <= |matches| == CountMatchesInSeq(a, matchfun) < LMinQuorumSize(asp.c.config); assert false; } } assert PrimaryHasAdvancedLogTruncationPoint(b[i+1], asp.live_quorum, h.view, opn + 1); } lemma lemma_IfLiveReplicasReadyForAnOperationThenEventuallyPrimaryAdvancesLogTruncationPointHelper( b:Behavior, asp:AssumptionParameters, h:Phase2Params, opn:OperationNumber, prev_step:int, first_step:int, i:int ) requires imaptotal(b) requires Phase2StableWithRequest(b, asp, h) requires opn >= h.log_truncation_point requires h.start_step + 1 <= prev_step requires h.start_step + 1 <= first_step <= i requires AllLiveReplicasReadyForNextOperation(b[prev_step], asp.live_quorum, h.view, opn) requires var ws := PrimaryKnowsEveryReplicaHasOpsCompleteTemporalSet(b, asp.live_quorum, h.view.proposer_id, opn + 1); var always_ws := always(andset(ws)); var P := always_ws; var x := PrimaryHasAdvancedLogTruncationPointTemporal(b, asp.live_quorum, h.view, opn + 1); var y := AllLiveReplicasCaughtUpWithEarlierOperationWithRequestQueueEmptyTemporal(b, asp.live_quorum, h.view, opn + 1); var z := NoReplicaBeyondViewTemporal(b, h.view); var Q := or(x, or(y, not(z))); sat(first_step, P) && sat(i, P) && !sat(i, Q) && !sat(i+1, Q) requires sat(i, ReplicaSchedule(b, h.view.proposer_id)[4]) ensures false { var ws := PrimaryKnowsEveryReplicaHasOpsCompleteTemporalSet(b, asp.live_quorum, h.view.proposer_id, opn + 1); lemma_ConstantsAllConsistent(b, asp.c, i); lemma_ConstantsAllConsistent(b, asp.c, i+1); Lemma_AlwaysImpliesLaterAlways(first_step, i+1, andset(ws)); var s := b[i].replicas[h.view.proposer_id].replica; var s' := b[i+1].replicas[h.view.proposer_id].replica; lemma_ExpandReplicaSchedule(b, h.view.proposer_id, 4); assert sat(i, MakeRslActionTemporalFromSpontaneousReplicaFunction(b, LReplicaNextSpontaneousTruncateLogBasedOnCheckpoints, h.view.proposer_id)); assert SpecificSpontaneousRslActionOccurs(b[i], b[i+1], LReplicaNextSpontaneousTruncateLogBasedOnCheckpoints, h.view.proposer_id); var ios:seq :| && RslNextOneReplica(b[i], b[i+1], h.view.proposer_id, ios) && LReplicaNextSpontaneousTruncateLogBasedOnCheckpoints(s, s', ExtractSentPacketsFromIos(ios)); TemporalDeduceFromAlways(i, i, andset(ws)); lemma_IfPrimaryTruncatesLogDueToCheckpointsWhileKnowingAllRepliesExecutedOpnThenItAdvancesLogTruncationPoint(b, asp, h, opn, i, ios); } lemma lemma_IfLiveReplicasReadyForAnOperationThenEventuallyPrimaryAdvancesLogTruncationPoint( b:Behavior, asp:AssumptionParameters, h:Phase2Params, opn:OperationNumber, prev_step:int ) returns ( step:int ) requires Phase2StableWithRequest(b, asp, h) requires opn >= h.log_truncation_point requires h.start_step + 1 <= prev_step requires AllLiveReplicasReadyForNextOperation(b[prev_step], asp.live_quorum, h.view, opn) ensures h.start_step + 1 <= step ensures var f := PaxosTimeMap(b); var t := b[prev_step].environment.time + asp.c.params.max_batch_delay + asp.max_clock_ambiguity * 4 + asp.c.params.heartbeat_period + TimeToPerformGenericAction(asp) * 6 + h.processing_bound * 3; var x := PrimaryHasAdvancedLogTruncationPointTemporal(b, asp.live_quorum, h.view, opn + 1); var y := AllLiveReplicasCaughtUpWithEarlierOperationWithRequestQueueEmptyTemporal(b, asp.live_quorum, h.view, opn + 1); var z := NoReplicaBeyondViewTemporal(b, h.view); sat(step, beforeabsolutetime(or(x, or(y, not(z))), t, f)) { var f := PaxosTimeMap(b); var ws := PrimaryKnowsEveryReplicaHasOpsCompleteTemporalSet(b, asp.live_quorum, h.view.proposer_id, opn + 1); var always_ws := always(andset(ws)); var x := PrimaryHasAdvancedLogTruncationPointTemporal(b, asp.live_quorum, h.view, opn + 1); var y := AllLiveReplicasCaughtUpWithEarlierOperationWithRequestQueueEmptyTemporal(b, asp.live_quorum, h.view, opn + 1); var z := NoReplicaBeyondViewTemporal(b, h.view); var first_step := lemma_IfLiveReplicasReadyForAnOperationThenPrimaryAlwaysKnowsEveryExecutorExecutedIt(b, asp, h, opn, prev_step); if sat(first_step, or(y, not(z))) { step := first_step; return; } assert sat(first_step, always_ws); var P := always_ws; var Q := or(x, or(y, not(z))); forall i | first_step <= i ensures sat(i, TemporalWF1Req1(P, Q)) { if sat(i, P) { Lemma_AlwaysImpliesLaterAlways(first_step, i+1, andset(ws)); assert sat(i+1, P); } } var Action := ReplicaSchedule(b, h.view.proposer_id)[4]; forall i | first_step <= i ensures sat(i, TemporalWF1Req2(P, Q, Action)) { if sat(i, P) && sat(i, Action) && !sat(i, Q) && !sat(i+1, Q) { lemma_IfLiveReplicasReadyForAnOperationThenEventuallyPrimaryAdvancesLogTruncationPointHelper(b, asp, h, opn, prev_step, first_step, i); } } TemporalAlways(first_step, TemporalWF1Req1(P, Q)); TemporalAlways(first_step, TemporalWF1Req2(P, Q, Action)); lemma_ReplicaNextPerformsSubactionPeriodically(b, asp, h.view.proposer_id, 4); lemma_EstablishRequirementsForWF1RealTime(b, asp, first_step, Action, TimeToPerformGenericAction(asp)); TemporalWF1RealTime(first_step, P, Q, Action, TimeToPerformGenericAction(asp), f); step := TemporalDeduceFromLeadsToWithin(first_step, first_step, P, Q, TimeToPerformGenericAction(asp), f); } lemma lemma_IfLiveReplicasReadyForAnOperationTheyllEventuallyBeReadyForNextOperation( b:Behavior, asp:AssumptionParameters, h:Phase2Params, opn:OperationNumber, prev_step:int ) returns ( step:int ) requires Phase2StableWithRequest(b, asp, h) requires opn >= h.log_truncation_point requires h.start_step + 1 <= prev_step requires AllLiveReplicasReadyForNextOperation(b[prev_step], asp.live_quorum, h.view, opn) ensures h.start_step + 1 <= step ensures var f := PaxosTimeMap(b); var t := b[prev_step].environment.time + asp.c.params.max_batch_delay + asp.max_clock_ambiguity * 4 + asp.c.params.heartbeat_period + TimeToPerformGenericAction(asp) * 6 + h.processing_bound * 3; var x := AllLiveReplicasReadyForNextOperationTemporal(b, asp.live_quorum, h.view, opn + 1); var y := AllLiveReplicasCaughtUpWithEarlierOperationWithRequestQueueEmptyTemporal(b, asp.live_quorum, h.view, opn + 1); var z := NoReplicaBeyondViewTemporal(b, h.view); sat(step, beforeabsolutetime(or(x, or(y, not(z))), t, f)) { var x := AllLiveReplicasReadyForNextOperationTemporal(b, asp.live_quorum, h.view, opn + 1); var y := AllLiveReplicasCaughtUpWithEarlierOperationWithRequestQueueEmptyTemporal(b, asp.live_quorum, h.view, opn + 1); var z := NoReplicaBeyondViewTemporal(b, h.view); var step1 := lemma_IfLiveReplicasReadyForAnOperationThenEventuallyPrimaryAdvancesLogTruncationPoint(b, asp, h, opn, prev_step); if sat(step1, or(y, not(z))) { step := step1; return; } lemma_ConstantsAllConsistent(b, asp.c, step1); assert forall idx :: idx in asp.live_quorum ==> ReplicaCaughtUp(b[step1], idx, opn + 1); assert b[step1].replicas[h.view.proposer_id].replica.acceptor.log_truncation_point >= opn + 1; var step2 := lemma_IfLiveReplicasReadyForAnOperationThenProposerEventuallyAdvancesNextOp(b, asp, h, opn, prev_step); if sat(step2, or(y, not(z))) { step := step2; return; } lemma_ConstantsAllConsistent(b, asp.c, step2); assert b[step2].replicas[h.view.proposer_id].replica.proposer.next_operation_number_to_propose >= opn + 1; if step1 < step2 { step := step2; forall idx | idx in asp.live_quorum ensures ReplicaCaughtUp(b[step], idx, opn + 1) { lemma_OpsCompleteMonotonic(b, asp.c, step1, step2, idx); } lemma_LogTruncationPointMonotonic(b, asp.c, step1, step2, h.view.proposer_id); assert AllLiveReplicasReadyForNextOperation(b[step], asp.live_quorum, h.view, opn + 1); } else { step := step1; lemma_NextOperationNumberToProposeIncreasesInPhase2(b, asp, h, step2, step1); assert AllLiveReplicasReadyForNextOperation(b[step], asp.live_quorum, h.view, opn + 1); } } lemma lemma_EventuallyAllLiveReplicasReadyForCertainOperation( b:Behavior, asp:AssumptionParameters, h:Phase2Params, opn:OperationNumber ) returns ( step:int ) requires Phase2StableWithRequest(b, asp, h) requires opn >= h.log_truncation_point ensures h.start_step + 1 <= step ensures b[step].environment.time <= b[h.start_step + 1].environment.time + TimeToBeginPhase2(asp, h.processing_bound) + (opn - h.log_truncation_point) * TimeToAdvanceOneOperation(asp, h.processing_bound) ensures sat(step, or(AllLiveReplicasReadyForNextOperationTemporal(b, asp.live_quorum, h.view, opn), or(AllLiveReplicasCaughtUpWithEarlierOperationWithRequestQueueEmptyTemporal(b, asp.live_quorum, h.view, opn), not(NoReplicaBeyondViewTemporal(b, h.view))))) decreases opn - h.log_truncation_point { if opn == h.log_truncation_point { step := lemma_EventuallyAllLiveReplicasReadyForFirstOperation(b, asp, h); return; } var prev_step := lemma_EventuallyAllLiveReplicasReadyForCertainOperation(b, asp, h, opn - 1); calc { b[prev_step].environment.time + TimeToAdvanceOneOperation(asp, h.processing_bound); <= b[h.start_step+1].environment.time + TimeToBeginPhase2(asp, h.processing_bound) + (opn - 1 - h.log_truncation_point) * TimeToAdvanceOneOperation(asp, h.processing_bound) + TimeToAdvanceOneOperation(asp, h.processing_bound); == b[h.start_step+1].environment.time + TimeToBeginPhase2(asp, h.processing_bound) + (opn - 1 - h.log_truncation_point) * TimeToAdvanceOneOperation(asp, h.processing_bound) + 1 * TimeToAdvanceOneOperation(asp, h.processing_bound); == { lemma_mul_is_distributive_add_other_way(TimeToAdvanceOneOperation(asp, h.processing_bound), opn - 1 - h.log_truncation_point, 1); } b[h.start_step+1].environment.time + TimeToBeginPhase2(asp, h.processing_bound) + (opn - h.log_truncation_point) * TimeToAdvanceOneOperation(asp, h.processing_bound); } if !sat(prev_step, AllLiveReplicasReadyForNextOperationTemporal(b, asp.live_quorum, h.view, opn - 1)) { step := prev_step; return; } step := lemma_IfLiveReplicasReadyForAnOperationTheyllEventuallyBeReadyForNextOperation(b, asp, h, opn - 1, prev_step); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/LivenessProof/RealTime.i.dfy ================================================ include "../DistributedSystem.i.dfy" include "Environment.i.dfy" include "../CommonProof/Constants.i.dfy" include "../../../Common/Logic/Temporal/Induction.i.dfy" include "../../../Common/Logic/Temporal/Rules.i.dfy" include "../../../Common/Logic/Temporal/WF1.i.dfy" module LivenessProof__RealTime_i { import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Types_i import opened LivenessProof__Assumptions_i import opened LivenessProof__Environment_i import opened CommonProof__Assumptions_i import opened CommonProof__Constants_i import opened Collections__Maps2_s import opened Collections__Maps2_i import opened Temporal__Temporal_s import opened Temporal__Induction_i import opened Temporal__Rules_i import opened Temporal__Time_s import opened Temporal__Time_i import opened Temporal__WF1_i import opened EnvironmentSynchrony_s lemma lemma_TimeAdvancesBetween(b:Behavior, asp:AssumptionParameters, i:int, j:int) requires LivenessAssumptions(b, asp) requires 0 <= i <= j ensures PaxosTimeMap(b)[i] <= PaxosTimeMap(b)[j] decreases j - i { if j > i { lemma_TimeAdvancesBetween(b, asp, i, j-1); lemma_AssumptionsMakeValidTransition(b, asp.c, j-1); } } predicate TimeMonotonicFromInvariant(b:Behavior, asp:AssumptionParameters, i:int) requires imaptotal(b) requires imaptotal(PaxosTimeMap(b)) { monotonic_from(i, PaxosTimeMap(b)) } lemma lemma_TimeMonotonicFromInvariantHolds(b:Behavior, asp:AssumptionParameters, i:int) requires LivenessAssumptions(b, asp) requires 0 <= i ensures TimeMonotonicFromInvariant(b, asp, i) { forall j, k | i <= j <= k { lemma_TimeAdvancesBetween(b, asp, j, k); } } lemma lemma_AfterForm(b:Behavior, asp:AssumptionParameters) requires LivenessAssumptions(b, asp) ensures TimeNotZeno(PaxosTimeMap(b)) { var timefun := PaxosTimeMap(b); var eb := RestrictBehaviorToEnvironment(b); reveal eventual(); reveal after(); forall t ensures sat(0, eventual(after(t, timefun))) { var x := TimeReachesTemporal(eb, t); var i := eventualStep(0, x); TemporalEventually(0, i, after(t, timefun)); } assert forall t :: sat(0, eventual(after(t, timefun))); assert forall t :: sat(0, eventual(after(t, PaxosTimeMap(b)))); } lemma lemma_TimeReachesAfter(b:Behavior, asp:AssumptionParameters, i:int, rt:int) returns (j:int) requires LivenessAssumptions(b, asp) ensures i <= j ensures b[j].environment.time >= rt { var eb := RestrictBehaviorToEnvironment(b); var x := TimeReachesTemporal(eb, rt); assert sat(0, eventual(x)); j := TemporalDeduceFromEventual(0, x); assert b[j].environment.time >= rt; if i > j { lemma_TimeAdvancesBetween(b, asp, j, i); j := i; } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/LivenessProof/RequestQueue.i.dfy ================================================ include "Assumptions.i.dfy" include "Invariants.i.dfy" include "StablePeriod.i.dfy" include "../CommonProof/Actions.i.dfy" module LivenessProof__RequestQueue_i { import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Environment_i import opened LiveRSL__Types_i import opened LivenessProof__Assumptions_i import opened LivenessProof__Environment_i import opened LivenessProof__Invariants_i import opened CommonProof__Actions_i import opened CommonProof__Constants_i import opened LivenessProof__StablePeriod_i import opened Temporal__Temporal_s import opened Temporal__Rules_i import opened Environment_s import opened Collections__Maps2_s lemma lemma_RequestInFirstNOfRequestQueueDuringPhase1( b:Behavior, asp:AssumptionParameters, i:int, start_step:int, view:Ballot, ahead_idx:int, req:Request, n:int ) requires LivenessAssumptions(b, asp) requires sat(start_step, StablePeriodStartedTemporal(b, asp.live_quorum, view, ahead_idx)) requires sat(start_step, always(RequestInFirstNTemporal(b, view.proposer_id, req, n))) requires 0 <= start_step <= i requires 0 <= view.proposer_id < |b[i].replicas| requires b[i].replicas[view.proposer_id].replica.proposer.max_ballot_i_sent_1a == view requires b[i].replicas[view.proposer_id].replica.proposer.current_state == 1 ensures RequestInFirstNOfRequestQueue(b[i], view.proposer_id, req, n) { if i == start_step { assert false; } else { lemma_ConstantsAllConsistent(b, asp.c, i-1); lemma_ConstantsAllConsistent(b, asp.c, i); lemma_AssumptionsMakeValidTransition(b, asp.c, i-1); var idx := view.proposer_id; var s := b[i-1].replicas[idx].replica.proposer; var s' := b[i].replicas[idx].replica.proposer; if s.max_ballot_i_sent_1a == view && s.current_state == 1 { lemma_RequestInFirstNOfRequestQueueDuringPhase1(b, asp, i-1, start_step, view, ahead_idx, req, n); if s'.request_queue == s.request_queue { assert RequestInFirstNOfRequestQueue(b[i], idx, req, n); } else { var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, i-1, idx); var action_index := b[i-1].replicas[idx].nextActionIndex; assert action_index == 0 && ios[0].LIoOpReceive? && ios[0].r.msg.RslMessage_Request?; assert s.request_queue <= s'.request_queue; } } else { var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, i-1, idx); TemporalDeduceFromAlways(start_step, i-1, RequestInFirstNTemporal(b, idx, req, n)); var action_index := b[i-1].replicas[idx].nextActionIndex; assert action_index == 1; assert s.election_state.requests_received_prev_epochs <= s'.request_queue; } } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/LivenessProof/RequestsReceived.i.dfy ================================================ include "../DistributedSystem.i.dfy" include "Assumptions.i.dfy" include "Invariants.i.dfy" include "Seqno.i.dfy" include "Execution.i.dfy" include "RoundRobin.i.dfy" include "StablePeriod.i.dfy" include "WF1.i.dfy" include "../CommonProof/Actions.i.dfy" include "../../../Common/Logic/Temporal/WF1.i.dfy" module LivenessProof__RequestsReceived_i { import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Election_i import opened LiveRSL__Environment_i import opened LiveRSL__Message_i import opened LiveRSL__Proposer_i import opened LiveRSL__Replica_i import opened LiveRSL__Types_i import opened LivenessProof__Assumptions_i import opened LivenessProof__Environment_i import opened LivenessProof__Execution_i import opened LivenessProof__Invariants_i import opened LivenessProof__PacketHandling_i import opened LivenessProof__RoundRobin_i import opened LivenessProof__Seqno_i import opened LivenessProof__StablePeriod_i import opened LivenessProof__WF1_i import opened CommonProof__Actions_i import opened CommonProof__Constants_i import opened Temporal__Induction_i import opened Temporal__Rules_i import opened Temporal__Temporal_s import opened Temporal__Time_s import opened Temporal__Time_i import opened Temporal__WF1_i import opened Environment_s import opened Collections__Maps2_s predicate RequestInRequestsReceivedPrevEpochs(ps:RslState, req:Request, idx:int) { && 0 <= idx < |ps.replicas| && req in ps.replicas[idx].replica.proposer.election_state.requests_received_prev_epochs } function {:opaque} RequestInRequestsReceivedPrevEpochsTemporal(b:Behavior, req:Request, idx:int):temporal requires imaptotal(b) ensures forall i {:trigger sat(i, RequestInRequestsReceivedPrevEpochsTemporal(b, req, idx))} :: sat(i, RequestInRequestsReceivedPrevEpochsTemporal(b, req, idx)) <==> RequestInRequestsReceivedPrevEpochs(b[i], req, idx) { stepmap(imap i :: RequestInRequestsReceivedPrevEpochs(b[i], req, idx)) } predicate RequestInRequestsReceivedThisOrPrevEpochs(ps:RslState, req:Request, idx:int) { && 0 <= idx < |ps.replicas| && (|| req in ps.replicas[idx].replica.proposer.election_state.requests_received_prev_epochs || req in ps.replicas[idx].replica.proposer.election_state.requests_received_this_epoch) } function {:opaque} RequestInRequestsReceivedThisOrPrevEpochsTemporal(b:Behavior, req:Request, idx:int):temporal requires imaptotal(b) ensures forall i {:trigger sat(i, RequestInRequestsReceivedThisOrPrevEpochsTemporal(b, req, idx))} :: sat(i, RequestInRequestsReceivedThisOrPrevEpochsTemporal(b, req, idx)) <==> RequestInRequestsReceivedThisOrPrevEpochs(b[i], req, idx) { stepmap(imap i :: RequestInRequestsReceivedThisOrPrevEpochs(b[i], req, idx)) } lemma lemma_RemoveAllSatisfiedRequestsRemoval(s:seq, r:Request, r':Request) ensures r' in s && r' !in RemoveAllSatisfiedRequestsInSequence(s, r) ==> RequestSatisfiedBy(r', r) { if r' in s && r' !in RemoveAllSatisfiedRequestsInSequence(s, r) { assert |s| > 0; assert r' !in RemoveAllSatisfiedRequestsInSequence(s[1..], r); lemma_RemoveAllSatisfiedRequestsRemoval(s[1..], r, r'); if RequestSatisfiedBy(s[0], r) { assert r' in s; if r' == s[0] { assert RequestSatisfiedBy(r', r); } } else { assert r' != s[0]; assert r' in s[1..]; } } } lemma lemma_RemoveExecutedRequestBatchRemoval(s:seq, batch:RequestBatch, r':Request) returns (req_idx:int) requires r' in s requires r' !in RemoveExecutedRequestBatch(s, batch) ensures 0 <= req_idx < |batch| ensures RequestSatisfiedBy(r', batch[req_idx]) decreases |batch| { if |batch| == 0 { } else if RequestSatisfiedBy(r', batch[0]) { req_idx := 0; } else { lemma_RemoveAllSatisfiedRequestsRemoval(s, batch[0], r'); assert r' in RemoveAllSatisfiedRequestsInSequence(s, batch[0]); var req_idx_minus_1 := lemma_RemoveExecutedRequestBatchRemoval(RemoveAllSatisfiedRequestsInSequence(s, batch[0]), batch[1..], r'); req_idx := req_idx_minus_1 + 1; } } lemma lemma_IfObjectNotInFirstNOfSequenceItsNotTheFirst(r:T, s:seq, n:int) requires |s| > 0 requires n > 0 requires !ObjectInFirstNOfSequence(r, s, n) ensures r != s[0] { } lemma lemma_RemoveAllSatisfiedRequestsRemovalFromFirstN(s:seq, r:Request, r':Request, n:int) ensures ObjectInFirstNOfSequence(r', s, n) && !ObjectInFirstNOfSequence(r', RemoveAllSatisfiedRequestsInSequence(s, r), n) ==> RequestSatisfiedBy(r', r) { if ObjectInFirstNOfSequence(r', s, n) && !ObjectInFirstNOfSequence(r', RemoveAllSatisfiedRequestsInSequence(s, r), n) { assert |s| > 0; assert n > 0; if RequestSatisfiedBy(s[0], r) { if !ObjectInFirstNOfSequence(r', s[1..], n) { if |s[1..]| <= n { assert r' !in s[1..]; assert r' == s[0]; } else { assert r' !in s[1..][..n]; assert r' !in s[1..n]; assert |s| >= n; assert r' in s[..n]; assert r' == s[0]; } assert RequestSatisfiedBy(r', r); } else { lemma_RemoveAllSatisfiedRequestsRemovalFromFirstN(s[1..], r, r', n-1); assert RequestSatisfiedBy(r', r); } } else { var s' := RemoveAllSatisfiedRequestsInSequence(s[1..], r); assert !ObjectInFirstNOfSequence(r', [s[0]] + s', n); lemma_IfObjectNotInFirstNOfSequenceItsNotTheFirst(r', [s[0]] + s', n); assert r' != s[0]; lemma_RemoveAllSatisfiedRequestsRemovalFromFirstN(s[1..], r, r', n-1); forall ensures !ObjectInFirstNOfSequence(r', s', n-1) { if |[s[0]] + s'| > n > 0 { assert ([s[0]] + s')[..n] == [s[0]] + s'[..n - 1]; } } } } } lemma lemma_RemoveExecutedRequestBatchRemovalFromFirstN(s:seq, batch:RequestBatch, r':Request, n:int) returns (req_idx:int) requires ObjectInFirstNOfSequence(r', s, n) requires !ObjectInFirstNOfSequence(r', RemoveExecutedRequestBatch(s, batch), n) ensures 0 <= req_idx < |batch| ensures RequestSatisfiedBy(r', batch[req_idx]) decreases |batch| { if |batch| == 0 { } else if RequestSatisfiedBy(r', batch[0]) { req_idx := 0; } else { lemma_RemoveAllSatisfiedRequestsRemovalFromFirstN(s, batch[0], r', n); var s' := RemoveAllSatisfiedRequestsInSequence(s, batch[0]); assert ObjectInFirstNOfSequence(r', s', n); assert !ObjectInFirstNOfSequence(r', RemoveExecutedRequestBatch(s', batch[1..]), n); var req_idx_minus_1 := lemma_RemoveExecutedRequestBatchRemovalFromFirstN(s', batch[1..], r', n); req_idx := req_idx_minus_1 + 1; } } lemma lemma_NextOpToExecuteNeverExceedsSeqno( b:Behavior, asp:AssumptionParameters, i:int, idx:int, req_idx:int ) requires LivenessAssumptions(b, asp) requires 0 <= i requires 0 <= idx < |b[i].replicas| requires b[i].replicas[idx].replica.executor.next_op_to_execute.OutstandingOpKnown? requires 0 <= req_idx < |b[i].replicas[idx].replica.executor.next_op_to_execute.v| requires b[i].replicas[idx].replica.executor.next_op_to_execute.v[req_idx].client == asp.persistent_request.client ensures b[i].replicas[idx].replica.executor.next_op_to_execute.v[req_idx].seqno <= asp.persistent_request.seqno { var s := b[i].replicas[idx].replica; lemma_SequenceNumberStateInvHolds(b, asp, i); assert SequenceNumberReplicaInv(s, asp.persistent_request); assert SequenceNumberRequestInv(s.executor.next_op_to_execute.v[req_idx], asp.persistent_request); } lemma lemma_EventuallyPersistentRequestInRequestsReceivedThisOrPrevEpochs( b:Behavior, asp:AssumptionParameters, processing_sync_start:int, processing_bound:int, idx:int ) returns ( step:int ) requires LivenessAssumptions(b, asp) requires idx in asp.live_quorum requires PacketProcessingSynchronous(b, asp, processing_sync_start, processing_bound) ensures processing_sync_start <= step ensures sat(step, RequestInRequestsReceivedThisOrPrevEpochsTemporal(b, asp.persistent_request, idx)) { var client_send := ClientSendsRequestToReplicaTemporal(b, asp.persistent_request, asp.c.config.replica_ids[idx]); assert PersistentClientSendsRequestPeriodically(b, asp, idx); assert sat(asp.synchrony_start, always(eventuallynextwithin(client_send, asp.persistent_period, PaxosTimeMap(b)))); TemporalDeduceFromAlways(asp.synchrony_start, processing_sync_start, eventuallynextwithin(client_send, asp.persistent_period, PaxosTimeMap(b))); var send_step := TemporalDeduceFromEventual(processing_sync_start, nextbefore(client_send, b[processing_sync_start].environment.time + asp.persistent_period, PaxosTimeMap(b))); var p := LPacket(asp.c.config.replica_ids[idx], asp.persistent_request.client, RslMessage_Request(asp.persistent_request.seqno, asp.persistent_request.request)); var processing_step, ios := lemma_PacketSentToIndexProcessedByIt(b, asp, processing_sync_start, processing_bound, send_step, idx, p); lemma_RequestNeverHitsInReplyCache(b, asp, processing_sync_start, processing_bound, processing_step, idx, ios, p); var es := b[processing_step].replicas[idx].replica.proposer.election_state; var es' := b[processing_step+1].replicas[idx].replica.proposer.election_state; assert ElectionStateReflectReceivedRequest(es, es', asp.persistent_request); if earlier_req :| && (earlier_req in es.requests_received_prev_epochs || earlier_req in es.requests_received_this_epoch) && RequestsMatch(earlier_req, asp.persistent_request) { lemma_SequenceNumberStateInvHolds(b, asp, processing_step); assert SequenceNumberRequestInv(earlier_req, asp.persistent_request); assert RequestInRequestsReceivedThisOrPrevEpochs(b[processing_step], asp.persistent_request, idx); step := processing_step; } else { lemma_ConstantsAllConsistent(b, asp.c, processing_step); lemma_OverflowProtectionNotUsedForReplica(b, asp, processing_step, idx); assert RequestInRequestsReceivedThisOrPrevEpochs(b[processing_step+1], asp.persistent_request, idx); step := processing_step + 1; } } lemma lemma_IfStepRemovesRequestFromBothThisAndPrevEpochsThenItsMaybeExecute( ps:RslState, ps':RslState, asp:AssumptionParameters, idx:int, req:Request ) returns ( ios:seq ) requires RslNext(ps, ps') requires RequestInRequestsReceivedThisOrPrevEpochs(ps, req, idx) requires !RequestInRequestsReceivedThisOrPrevEpochs(ps', req, idx) requires ps.replicas[idx].replica.proposer.election_state.constants.all.params == asp.c.params requires OverflowProtectionNotUsedForReplica(ps, idx, asp.c.params, asp.max_clock_ambiguity) ensures RslNextOneReplica(ps, ps', idx, ios) ensures LReplicaNextSpontaneousMaybeExecute(ps.replicas[idx].replica, ps'.replicas[idx].replica, ExtractSentPacketsFromIos(ios)) { var s := ps.replicas[idx].replica; var s' := ps.replicas[idx].replica; var es := ps.replicas[idx].replica.proposer.election_state; ios :| RslNextOneReplica(ps, ps', idx, ios); if && |ios| >= 1 && ios[0].LIoOpReceive? && ios[0].r.msg.RslMessage_Request? && LReplicaNextProcessRequest(s, s', ios[0].r, ExtractSentPacketsFromIos(ios)) && LProposerProcessRequest(s.proposer, s'.proposer, ios[0].r) { var p := ios[0].r; var val := Request(p.src, p.msg.seqno_req, p.msg.val); assert req in BoundRequestSequence(es.requests_received_prev_epochs + [val], es.constants.all.params.max_integer_val); assert false; } assert req in BoundRequestSequence(es.requests_received_prev_epochs + es.requests_received_this_epoch, es.constants.all.params.max_integer_val); } lemma lemma_EventuallyPersistentRequestAlwaysInRequestsReceivedThisOrPrevEpochs( b:Behavior, asp:AssumptionParameters, processing_sync_start:int, processing_bound:int, idx:int ) returns ( step:int ) requires LivenessAssumptions(b, asp) requires idx in asp.live_quorum requires PacketProcessingSynchronous(b, asp, processing_sync_start, processing_bound) ensures processing_sync_start <= step ensures sat(step, always(RequestInRequestsReceivedThisOrPrevEpochsTemporal(b, asp.persistent_request, idx))) { var client := asp.persistent_request.client; var seqno := asp.persistent_request.seqno; var t := RequestInRequestsReceivedThisOrPrevEpochsTemporal(b, asp.persistent_request, idx); step := lemma_EventuallyPersistentRequestInRequestsReceivedThisOrPrevEpochs(b, asp, processing_sync_start, processing_bound, idx); forall j {:trigger sat(j, imply(t, next(t)))} | step <= j ensures sat(j, imply(t, next(t))) { lemma_ConstantsAllConsistent(b, asp.c, j); lemma_ConstantsAllConsistent(b, asp.c, j+1); if sat(j, t) && !sat(j+1, t) { lemma_AssumptionsMakeValidTransition(b, asp.c, j); lemma_OverflowProtectionNotUsedForReplica(b, asp, j, idx); var ios := lemma_IfStepRemovesRequestFromBothThisAndPrevEpochsThenItsMaybeExecute(b[j], b[j+1], asp, idx, asp.persistent_request); var s := b[j].replicas[idx].replica; var s' := b[j+1].replicas[idx].replica; var es := s.proposer.election_state; var es' := s'.proposer.election_state; if asp.persistent_request in es.requests_received_prev_epochs { var req_idx := lemma_RemoveExecutedRequestBatchRemoval(es.requests_received_prev_epochs, s.executor.next_op_to_execute.v, asp.persistent_request); lemma_NextOpToExecuteNeverExceedsSeqno(b, asp, j, idx, req_idx); assert ReplySentToClientWithSeqno(b[j], b[j+1], client, seqno, idx, ios, req_idx); } else { var req_idx := lemma_RemoveExecutedRequestBatchRemoval(es.requests_received_this_epoch, s.executor.next_op_to_execute.v, asp.persistent_request); lemma_NextOpToExecuteNeverExceedsSeqno(b, asp, j, idx, req_idx); assert ReplySentToClientWithSeqno(b[j], b[j+1], client, seqno, idx, ios, req_idx); } lemma_PersistentRequestNeverExecuted(b, asp, idx); TemporalDeduceFromAlways(asp.synchrony_start, j, not(RequestWithSeqnoExecutedTemporal(b, client, seqno, idx))); assert false; } reveal next(); reveal imply(); } TemporalInductionNext(step, t); TemporalEventually(processing_sync_start, step, always(t)); } predicate RequestInRequestsReceivedThisOrPrevEpochsWithSpecificEpochEnd( ps:RslState, req:Request, idx:int, epoch_end_time:int ) { && 0 <= idx < |ps.replicas| && var es := ps.replicas[idx].replica.proposer.election_state; && es.epoch_end_time == epoch_end_time && (req in es.requests_received_prev_epochs || req in es.requests_received_this_epoch) } function{:opaque} RequestInRequestsReceivedThisOrPrevEpochsWithSpecificEpochEndTemporal( b:Behavior, req:Request, idx:int, epoch_end_time:int ):temporal requires imaptotal(b) ensures forall i {:trigger sat(i, RequestInRequestsReceivedThisOrPrevEpochsWithSpecificEpochEndTemporal(b, req, idx, epoch_end_time))} :: sat(i, RequestInRequestsReceivedThisOrPrevEpochsWithSpecificEpochEndTemporal(b, req, idx, epoch_end_time)) <==> RequestInRequestsReceivedThisOrPrevEpochsWithSpecificEpochEnd(b[i], req, idx, epoch_end_time) { stepmap(imap i :: RequestInRequestsReceivedThisOrPrevEpochsWithSpecificEpochEnd(b[i], req, idx, epoch_end_time)) } lemma lemma_RequestInRequestsReceivedThisOrPrevEpochsWithSpecificEpochEndLeadsToRequestInRequestsReceivedPrevEpochsWF1Req1( b:Behavior, asp:AssumptionParameters, idx:int, epoch_end_time:int ) requires LivenessAssumptions(b, asp) requires idx in asp.live_quorum ensures sat(asp.synchrony_start, always(TemporalWF1Req1( RequestInRequestsReceivedThisOrPrevEpochsWithSpecificEpochEndTemporal(b, asp.persistent_request, idx, epoch_end_time), RequestInRequestsReceivedPrevEpochsTemporal(b, asp.persistent_request, idx)))) { var P := RequestInRequestsReceivedThisOrPrevEpochsWithSpecificEpochEndTemporal(b, asp.persistent_request, idx, epoch_end_time); var Q := RequestInRequestsReceivedPrevEpochsTemporal(b, asp.persistent_request, idx); forall i | asp.synchrony_start <= i ensures sat(i, TemporalWF1Req1(P, Q)) { if sat(i, P) && !sat(i, Q) && !sat(i+1, P) && !sat(i+1, Q) { lemma_ConstantsAllConsistent(b, asp.c, i); lemma_ConstantsAllConsistent(b, asp.c, i+1); var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, i, idx); var nextActionIndex := b[i].replicas[idx].nextActionIndex; assert nextActionIndex == 0 || nextActionIndex == 1 || nextActionIndex == 2 || nextActionIndex == 3 || nextActionIndex == 4 || nextActionIndex == 5 || nextActionIndex == 6 || nextActionIndex == 7 || nextActionIndex == 8 || nextActionIndex == 9; lemma_OverflowProtectionNotUsedForReplica(b, asp, i, idx); var s := b[i].replicas[idx].replica; var s' := b[i+1].replicas[idx].replica; var es := s.proposer.election_state; var es' := s'.proposer.election_state; assert asp.persistent_request in es.requests_received_this_epoch; assert asp.persistent_request !in es.requests_received_prev_epochs; if LReplicaNextSpontaneousMaybeExecute(s, s', ExtractSentPacketsFromIos(ios)) { var req_idx := lemma_RemoveExecutedRequestBatchRemoval(es.requests_received_this_epoch, s.executor.next_op_to_execute.v, asp.persistent_request); lemma_NextOpToExecuteNeverExceedsSeqno(b, asp, i, idx, req_idx); assert ReplySentToClientWithSeqno(b[i], b[i+1], asp.persistent_request.client, asp.persistent_request.seqno, idx, ios, req_idx); lemma_PersistentRequestNeverExecuted(b, asp, idx); TemporalDeduceFromAlways(asp.synchrony_start, i, not(RequestWithSeqnoExecutedTemporal(b, asp.persistent_request.client, asp.persistent_request.seqno, idx))); assert false; } else { if nextActionIndex == 0 { assert false; } else if nextActionIndex == 1 { assert false; } else if nextActionIndex == 2 { assert false; } else if nextActionIndex == 3 { assert false; } else if nextActionIndex == 4 { assert false; } else if nextActionIndex == 5 { assert false; } else if nextActionIndex == 6 { assert false; } else if nextActionIndex == 7 { assert false; } else if nextActionIndex == 8 { assert false; } else if nextActionIndex == 9 { assert false; } else { assert false; } } } } TemporalAlways(asp.synchrony_start, TemporalWF1Req1(P, Q)); } lemma lemma_RequestInRequestsReceivedThisOrPrevEpochsWithSpecificEpochEndLeadsToRequestInRequestsReceivedPrevEpochsWF1Req2( b:Behavior, asp:AssumptionParameters, idx:int, epoch_end_time:int ) requires LivenessAssumptions(b, asp) requires idx in asp.live_quorum ensures sat(asp.synchrony_start, always(TemporalWF1RealTimeDelayedReq2( RequestInRequestsReceivedThisOrPrevEpochsWithSpecificEpochEndTemporal(b, asp.persistent_request, idx, epoch_end_time), RequestInRequestsReceivedPrevEpochsTemporal(b, asp.persistent_request, idx), ReplicaSchedule(b, idx)[7], epoch_end_time + asp.max_clock_ambiguity, PaxosTimeMap(b)))) { var epochEndTimePlus := epoch_end_time + asp.max_clock_ambiguity; var P := RequestInRequestsReceivedThisOrPrevEpochsWithSpecificEpochEndTemporal(b, asp.persistent_request, idx, epoch_end_time); var Q := RequestInRequestsReceivedPrevEpochsTemporal(b, asp.persistent_request, idx); var Action := ReplicaSchedule(b, idx)[7]; var f := PaxosTimeMap(b); forall i | asp.synchrony_start <= i ensures sat(i, TemporalWF1RealTimeDelayedReq2(P, Q, Action, epochEndTimePlus, f)) { if sat(i, P) && sat(i, nextafter(Action, epochEndTimePlus, f)) && !sat(i, Q) && !sat(i+1, Q) { lemma_ConstantsAllConsistent(b, asp.c, i); lemma_ConstantsAllConsistent(b, asp.c, i+1); assert SpecificClockReadingRslActionOccurs(b[i], b[i+1], LReplicaNextReadClockCheckForViewTimeout, idx); var ios:seq :| && RslNextOneReplica(b[i], b[i+1], idx, ios) && SpontaneousIos(ios, 1) && LReplicaNextReadClockCheckForViewTimeout(b[i].replicas[idx].replica, b[i+1].replicas[idx].replica, SpontaneousClock(ios), ExtractSentPacketsFromIos(ios)); lemma_ClockAmbiguityLimitApplies(b, asp, i, idx, ios[0]); lemma_OverflowProtectionNotUsedForReplica(b, asp, i, idx); var es := b[i].replicas[idx].replica.proposer.election_state; var es' := b[i+1].replicas[idx].replica.proposer.election_state; lemma_ClockAmbiguityLimitApplies(b, asp, i, idx, ios[0]); assert ElectionStateCheckForViewTimeout(es, es', ios[0].t); assert false; } } TemporalAlways(asp.synchrony_start, TemporalWF1RealTimeDelayedReq2(P, Q, Action, epochEndTimePlus, f)); } lemma lemma_EventuallyPersistentRequestInRequestsReceivedPrevEpochs( b:Behavior, asp:AssumptionParameters, processing_sync_start:int, processing_bound:int, idx:int ) returns ( step:int ) requires LivenessAssumptions(b, asp) requires idx in asp.live_quorum requires PacketProcessingSynchronous(b, asp, processing_sync_start, processing_bound) ensures processing_sync_start <= step ensures sat(step, RequestInRequestsReceivedPrevEpochsTemporal(b, asp.persistent_request, idx)) { var i := lemma_EventuallyPersistentRequestInRequestsReceivedThisOrPrevEpochs(b, asp, processing_sync_start, processing_bound, idx); lemma_ConstantsAllConsistent(b, asp.c, i); var epoch_end_time := b[i].replicas[idx].replica.proposer.election_state.epoch_end_time; var P := RequestInRequestsReceivedThisOrPrevEpochsWithSpecificEpochEndTemporal(b, asp.persistent_request, idx, epoch_end_time); var Q := RequestInRequestsReceivedPrevEpochsTemporal(b, asp.persistent_request, idx); var Action := ReplicaSchedule(b, idx)[7]; Lemma_AlwaysImpliesLaterAlways(asp.synchrony_start, i, TemporalWF1Req1(P, Q)); Lemma_AlwaysImpliesLaterAlways(asp.synchrony_start, i, TemporalWF1RealTimeDelayedReq2(P, Q, Action, epoch_end_time + asp.max_clock_ambiguity, PaxosTimeMap(b))); lemma_RequestInRequestsReceivedThisOrPrevEpochsWithSpecificEpochEndLeadsToRequestInRequestsReceivedPrevEpochsWF1Req1(b, asp, idx, epoch_end_time); lemma_RequestInRequestsReceivedThisOrPrevEpochsWithSpecificEpochEndLeadsToRequestInRequestsReceivedPrevEpochsWF1Req2(b, asp, idx, epoch_end_time); lemma_ReplicaNextPerformsSubactionPeriodically(b, asp, idx, 7); lemma_EstablishRequirementsForWF1RealTimeDelayed(b, asp, i, Action, TimeToPerformGenericAction(asp)); step := TemporalWF1RealTimeDelayed(i, P, Q, Action, TimeToPerformGenericAction(asp), epoch_end_time + asp.max_clock_ambiguity, PaxosTimeMap(b)); } lemma lemma_EventuallyPersistentRequestAlwaysInRequestsReceivedPrevEpochs( b:Behavior, asp:AssumptionParameters, processing_sync_start:int, processing_bound:int, idx:int ) returns ( step:int ) requires LivenessAssumptions(b, asp) requires idx in asp.live_quorum requires PacketProcessingSynchronous(b, asp, processing_sync_start, processing_bound) ensures processing_sync_start <= step ensures sat(step, always(RequestInRequestsReceivedPrevEpochsTemporal(b, asp.persistent_request, idx))) { var client := asp.persistent_request.client; var seqno := asp.persistent_request.seqno; var t := RequestInRequestsReceivedPrevEpochsTemporal(b, asp.persistent_request, idx); step := lemma_EventuallyPersistentRequestInRequestsReceivedPrevEpochs(b, asp, processing_sync_start, processing_bound, idx); forall j {:trigger sat(j, imply(t, next(t)))} | step <= j ensures sat(j, imply(t, next(t))) { lemma_ConstantsAllConsistent(b, asp.c, j); lemma_ConstantsAllConsistent(b, asp.c, j+1); if sat(j, t) && !sat(j+1, t) { var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, j, idx); lemma_OverflowProtectionNotUsedForReplica(b, asp, j, idx); var s := b[j].replicas[idx].replica; var s' := b[j+1].replicas[idx].replica; var es := s.proposer.election_state; var es' := s'.proposer.election_state; assert LReplicaNextSpontaneousMaybeExecute(s, s', ExtractSentPacketsFromIos(ios)); var req_idx := lemma_RemoveExecutedRequestBatchRemoval(es.requests_received_prev_epochs, s.executor.next_op_to_execute.v, asp.persistent_request); lemma_NextOpToExecuteNeverExceedsSeqno(b, asp, j, idx, req_idx); assert ReplySentToClientWithSeqno(b[j], b[j+1], client, seqno, idx, ios, req_idx); lemma_PersistentRequestNeverExecuted(b, asp, idx); TemporalDeduceFromAlways(asp.synchrony_start, j, not(RequestWithSeqnoExecutedTemporal(b, client, seqno, idx))); assert false; } reveal imply(); reveal next(); } TemporalInductionNext(step, t); TemporalEventually(processing_sync_start, step, always(t)); } lemma lemma_EventuallyForSomePersistentRequestAlwaysInRequestsReceivedPrevEpochs( b:Behavior, asp:AssumptionParameters, processing_sync_start:int, processing_bound:int, indices:set ) returns ( step:int ) requires LivenessAssumptions(b, asp) requires indices <= asp.live_quorum requires PacketProcessingSynchronous(b, asp, processing_sync_start, processing_bound) ensures processing_sync_start <= step ensures forall idx {:auto_trigger} :: idx in indices ==> sat(step, always(RequestInRequestsReceivedPrevEpochsTemporal(b, asp.persistent_request, idx))) { if |indices| == 0 { step := processing_sync_start; } else { var some_index :| some_index in indices; var other_indices := indices - {some_index}; var others_step := lemma_EventuallyForSomePersistentRequestAlwaysInRequestsReceivedPrevEpochs(b, asp, processing_sync_start, processing_bound, other_indices); var this_step := lemma_EventuallyPersistentRequestAlwaysInRequestsReceivedPrevEpochs(b, asp, processing_sync_start, processing_bound, some_index); step := if others_step > this_step then others_step else this_step; forall idx | idx in indices ensures sat(step, always(RequestInRequestsReceivedPrevEpochsTemporal(b, asp.persistent_request, idx))) { if step > this_step { Lemma_AlwaysImpliesLaterAlways(this_step, step, RequestInRequestsReceivedPrevEpochsTemporal(b, asp.persistent_request, idx)); } else { Lemma_AlwaysImpliesLaterAlways(others_step, step, RequestInRequestsReceivedPrevEpochsTemporal(b, asp.persistent_request, idx)); } } } } lemma lemma_EventuallyForAllPersistentRequestAlwaysInRequestsReceivedPrevEpochs( b:Behavior, asp:AssumptionParameters, processing_sync_start:int, processing_bound:int ) returns ( step:int ) requires LivenessAssumptions(b, asp) requires PacketProcessingSynchronous(b, asp, processing_sync_start, processing_bound) ensures processing_sync_start <= step ensures forall idx :: idx in asp.live_quorum ==> sat(step, always(RequestInRequestsReceivedPrevEpochsTemporal(b, asp.persistent_request, idx))) { step := lemma_EventuallyForSomePersistentRequestAlwaysInRequestsReceivedPrevEpochs(b, asp, processing_sync_start, processing_bound, asp.live_quorum); } lemma lemma_PersistentRequestDoesNotIncreasePositionInRequestsReceivedPrevEpochs( b:Behavior, asp:AssumptionParameters, processing_sync_start:int, processing_bound:int, idx:int, step:int, n:int ) requires LivenessAssumptions(b, asp) requires idx in asp.live_quorum requires PacketProcessingSynchronous(b, asp, processing_sync_start, processing_bound) requires processing_sync_start <= step requires sat(step, RequestInFirstNTemporal(b, idx, asp.persistent_request, n)) ensures sat(step, always(RequestInFirstNTemporal(b, idx, asp.persistent_request, n))) { var client := asp.persistent_request.client; var seqno := asp.persistent_request.seqno; var t := RequestInFirstNTemporal(b, idx, asp.persistent_request, n); forall j {:trigger sat(j, imply(t, next(t)))} | step <= j ensures sat(j, imply(t, next(t))) { lemma_ConstantsAllConsistent(b, asp.c, j); lemma_ConstantsAllConsistent(b, asp.c, j+1); if sat(j, t) && !sat(j+1, t) { var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, j, idx); lemma_OverflowProtectionNotUsedForReplica(b, asp, j, idx); var s := b[j].replicas[idx].replica; var s' := b[j+1].replicas[idx].replica; var es := s.proposer.election_state; var es' := s'.proposer.election_state; assert RequestInFirstN(b[j], idx, asp.persistent_request, n); assert !RequestInFirstN(b[j + 1], idx, asp.persistent_request, n); assert s.proposer.election_state.requests_received_prev_epochs != s'.proposer.election_state.requests_received_prev_epochs; var nextActionIndex := b[j].replicas[idx].nextActionIndex; if (nextActionIndex == 0 || nextActionIndex == 7 || nextActionIndex == 8) { assert s.proposer.election_state.requests_received_prev_epochs <= s'.proposer.election_state.requests_received_prev_epochs; assert false; } assert nextActionIndex == 6; assert LReplicaNextSpontaneousMaybeExecute(s, s', ExtractSentPacketsFromIos(ios)); var req_idx := lemma_RemoveExecutedRequestBatchRemovalFromFirstN(es.requests_received_prev_epochs, s.executor.next_op_to_execute.v, asp.persistent_request, n); lemma_NextOpToExecuteNeverExceedsSeqno(b, asp, j, idx, req_idx); assert ReplySentToClientWithSeqno(b[j], b[j+1], client, seqno, idx, ios, req_idx); lemma_PersistentRequestNeverExecuted(b, asp, idx); TemporalDeduceFromAlways(asp.synchrony_start, j, not(RequestWithSeqnoExecutedTemporal(b, client, seqno, idx))); assert false; } reveal imply(); reveal next(); } TemporalInductionNext(step, t); TemporalEventually(processing_sync_start, step, always(t)); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/LivenessProof/RoundRobin.i.dfy ================================================ include "../Replica.i.dfy" include "../DistributedSystem.i.dfy" include "Assumptions.i.dfy" include "Environment.i.dfy" include "Invariants.i.dfy" include "RealTime.i.dfy" include "../CommonProof/Constants.i.dfy" include "../../../Common/Framework/EnvironmentSynchronyLemmas.i.dfy" include "../../Common/Liveness/RTSchedule.i.dfy" include "../../../../Libraries/Math/mul.i.dfy" module LivenessProof__RoundRobin_i { import opened LiveRSL__ClockReading_i import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Environment_i import opened LiveRSL__Replica_i import opened LivenessProof__Assumptions_i import opened LivenessProof__Environment_i import opened LivenessProof__Invariants_i import opened CommonProof__Assumptions_i import opened CommonProof__Constants_i import opened Liveness__EnvironmentSynchronyLemmas_i import opened Liveness__RTSchedule_i import opened LivenessProof__RealTime_i import opened Math__mul_i import opened Temporal__Monotonicity_i import opened Temporal__Rules_i import opened Temporal__Temporal_s import opened Temporal__Time_s import opened Temporal__Time_i import opened Collections__Maps2_s import opened Collections__Maps2_i predicate SpecificRslActionOccurs( ps:RslState, ps':RslState, action_fun:(LReplica, LReplica, seq)->bool, replica_index:int ) reads action_fun.reads requires forall r, r', ios :: action_fun.requires(r, r', ios) { exists ios {:trigger RslNextOneReplica(ps, ps', replica_index, ios)} {:trigger action_fun(ps.replicas[replica_index].replica, ps'.replicas[replica_index].replica, ios)} :: && RslNextOneReplica(ps, ps', replica_index, ios) && action_fun(ps.replicas[replica_index].replica, ps'.replicas[replica_index].replica, ios) } function{:opaque} MakeRslActionTemporalFromReplicaFunction( b:Behavior, action_fun:(LReplica, LReplica, seq)->bool, replica_index:int ):temporal reads action_fun.reads requires forall r, r', ios :: action_fun.requires(r, r', ios) requires imaptotal(b) ensures forall i {:trigger sat(i, MakeRslActionTemporalFromReplicaFunction(b, action_fun, replica_index))} :: sat(i, MakeRslActionTemporalFromReplicaFunction(b, action_fun, replica_index)) <==> SpecificRslActionOccurs(b[i], b[i+1], action_fun, replica_index) { stepmap(imap i :: SpecificRslActionOccurs(b[i], b[nextstep(i)], action_fun, replica_index)) } predicate SpecificSpontaneousRslActionOccurs( ps:RslState, ps':RslState, action_fun:(LReplica, LReplica, seq)->bool, replica_index:int ) reads action_fun.reads requires forall r, r', sent_packets :: action_fun.requires(r, r', sent_packets) { exists ios {:trigger RslNextOneReplica(ps, ps', replica_index, ios)} {:trigger action_fun(ps.replicas[replica_index].replica, ps'.replicas[replica_index].replica, ExtractSentPacketsFromIos(ios))} :: && RslNextOneReplica(ps, ps', replica_index, ios) && SpontaneousIos(ios, 0) && action_fun(ps.replicas[replica_index].replica, ps'.replicas[replica_index].replica, ExtractSentPacketsFromIos(ios)) } function{:opaque} MakeRslActionTemporalFromSpontaneousReplicaFunction( b:Behavior, action_fun:(LReplica, LReplica, seq)->bool, replica_index:int ):temporal reads action_fun.reads requires forall r, r', sent_packets :: action_fun.requires(r, r', sent_packets) requires imaptotal(b) ensures forall i {:trigger sat(i, MakeRslActionTemporalFromSpontaneousReplicaFunction(b, action_fun, replica_index))} :: sat(i, MakeRslActionTemporalFromSpontaneousReplicaFunction(b, action_fun, replica_index)) <==> SpecificSpontaneousRslActionOccurs(b[i], b[i+1], action_fun, replica_index) { stepmap(imap i :: SpecificSpontaneousRslActionOccurs(b[i], b[nextstep(i)], action_fun, replica_index)) } predicate SpecificClockReadingRslActionOccurs( ps:RslState, ps':RslState, action_fun:(LReplica, LReplica, ClockReading, seq)->bool, replica_index:int ) reads action_fun.reads requires forall r, r', ios :: action_fun.requires(r, r', SpontaneousClock(ios), ExtractSentPacketsFromIos(ios)) { exists ios {:trigger RslNextOneReplica(ps, ps', replica_index, ios)} {:trigger action_fun(ps.replicas[replica_index].replica, ps'.replicas[replica_index].replica, SpontaneousClock(ios), ExtractSentPacketsFromIos(ios))} :: && RslNextOneReplica(ps, ps', replica_index, ios) && SpontaneousIos(ios, 1) && action_fun(ps.replicas[replica_index].replica, ps'.replicas[replica_index].replica, SpontaneousClock(ios), ExtractSentPacketsFromIos(ios)) } function{:opaque} MakeRslActionTemporalFromReadClockReplicaFunction( b:Behavior, action_fun:(LReplica, LReplica, ClockReading, seq)->bool, replica_index:int ):temporal reads action_fun.reads requires forall r, r', ios :: action_fun.requires(r, r', SpontaneousClock(ios), ExtractSentPacketsFromIos(ios)) requires imaptotal(b) ensures forall i {:trigger sat(i, MakeRslActionTemporalFromReadClockReplicaFunction(b, action_fun, replica_index))} :: sat(i, MakeRslActionTemporalFromReadClockReplicaFunction(b, action_fun, replica_index)) <==> SpecificClockReadingRslActionOccurs(b[i], b[nextstep(i)], action_fun, replica_index) { stepmap(imap i :: SpecificClockReadingRslActionOccurs(b[i], b[nextstep(i)], action_fun, replica_index)) } function ReplicaSchedule(b:Behavior, replica_index:int):seq requires imaptotal(b) { [ MakeRslActionTemporalFromReplicaFunction(b, LReplicaNextProcessPacket, replica_index), MakeRslActionTemporalFromSpontaneousReplicaFunction(b, LReplicaNextSpontaneousMaybeEnterNewViewAndSend1a, replica_index), MakeRslActionTemporalFromSpontaneousReplicaFunction(b, LReplicaNextSpontaneousMaybeEnterPhase2, replica_index), MakeRslActionTemporalFromReadClockReplicaFunction(b, LReplicaNextReadClockMaybeNominateValueAndSend2a, replica_index), MakeRslActionTemporalFromSpontaneousReplicaFunction(b, LReplicaNextSpontaneousTruncateLogBasedOnCheckpoints, replica_index), MakeRslActionTemporalFromSpontaneousReplicaFunction(b, LReplicaNextSpontaneousMaybeMakeDecision, replica_index), MakeRslActionTemporalFromSpontaneousReplicaFunction(b, LReplicaNextSpontaneousMaybeExecute, replica_index), MakeRslActionTemporalFromReadClockReplicaFunction(b, LReplicaNextReadClockCheckForViewTimeout, replica_index), MakeRslActionTemporalFromReadClockReplicaFunction(b, LReplicaNextReadClockCheckForQuorumOfViewSuspicions, replica_index), MakeRslActionTemporalFromReadClockReplicaFunction(b, LReplicaNextReadClockMaybeSendHeartbeat, replica_index) ] } function TimeToPerformGenericAction(asp:AssumptionParameters):int requires asp.host_period > 0 ensures TimeToPerformGenericAction(asp) >= 0 { lemma_mul_nonnegative(asp.host_period, LReplicaNumActions()); asp.host_period * LReplicaNumActions() } lemma lemma_ExpandReplicaSchedule( b:Behavior, idx:int, pos:int ) requires imaptotal(b) ensures pos == 0 ==> ReplicaSchedule(b, idx)[pos] == MakeRslActionTemporalFromReplicaFunction(b, LReplicaNextProcessPacket, idx) ensures pos == 1 ==> ReplicaSchedule(b, idx)[pos] == MakeRslActionTemporalFromSpontaneousReplicaFunction(b, LReplicaNextSpontaneousMaybeEnterNewViewAndSend1a, idx) ensures pos == 2 ==> ReplicaSchedule(b, idx)[pos] == MakeRslActionTemporalFromSpontaneousReplicaFunction(b, LReplicaNextSpontaneousMaybeEnterPhase2, idx) ensures pos == 3 ==> ReplicaSchedule(b, idx)[pos] == MakeRslActionTemporalFromReadClockReplicaFunction(b, LReplicaNextReadClockMaybeNominateValueAndSend2a, idx) ensures pos == 4 ==> ReplicaSchedule(b, idx)[pos] == MakeRslActionTemporalFromSpontaneousReplicaFunction(b, LReplicaNextSpontaneousTruncateLogBasedOnCheckpoints, idx) ensures pos == 5 ==> ReplicaSchedule(b, idx)[pos] == MakeRslActionTemporalFromSpontaneousReplicaFunction(b, LReplicaNextSpontaneousMaybeMakeDecision, idx) ensures pos == 6 ==> ReplicaSchedule(b, idx)[pos] == MakeRslActionTemporalFromSpontaneousReplicaFunction(b, LReplicaNextSpontaneousMaybeExecute, idx) ensures pos == 7 ==> ReplicaSchedule(b, idx)[pos] == MakeRslActionTemporalFromReadClockReplicaFunction(b, LReplicaNextReadClockCheckForViewTimeout, idx) ensures pos == 8 ==> ReplicaSchedule(b, idx)[pos] == MakeRslActionTemporalFromReadClockReplicaFunction(b, LReplicaNextReadClockCheckForQuorumOfViewSuspicions, idx) ensures pos == 9 ==> ReplicaSchedule(b, idx)[pos] == MakeRslActionTemporalFromReadClockReplicaFunction(b, LReplicaNextReadClockMaybeSendHeartbeat, idx) { } lemma lemma_PaxosNextTakesSchedulerActionOrLeavesNextActionIndexUnchanged( b:Behavior, asp:AssumptionParameters, replica_index:int, next_action_type_fun:imap, scheduler_action:temporal ) requires LivenessAssumptions(b, asp) requires 0 <= replica_index < |asp.c.config.replica_ids| requires imaptotal(next_action_type_fun) requires forall i {:trigger next_action_type_fun[i]} :: next_action_type_fun[i] == if 0 <= replica_index < |b[i].replicas| then b[i].replicas[replica_index].nextActionIndex else 0 requires forall i :: sat(i, scheduler_action) <==> exists ios {:trigger RslNextOneReplica(b[i], b[i+1], replica_index, ios)} {:trigger LSchedulerNext(b[i].replicas[replica_index], b[i+1].replicas[replica_index], ios)} :: && RslNextOneReplica(b[i], b[i+1], replica_index, ios) && LSchedulerNext(b[i].replicas[replica_index], b[i+1].replicas[replica_index], ios) ensures sat(0, always(SchedulerActsOrNextActionTypeUnchangedTemporal(b, next_action_type_fun, scheduler_action))) { var m := SchedulerActsOrNextActionTypeUnchangedTemporal(b, next_action_type_fun, scheduler_action); forall i | TLe(0, i) ensures sat(i, m) { assert RslNext(b[i], b[i+1]); lemma_ConstantsAllConsistent(b, asp.c, i); if (exists idx, ios {:trigger RslNextOneReplica(b[i], b[i+1], idx, ios)} :: RslNextOneReplica(b[i], b[i+1], idx, ios)) { var idx, ios :| RslNextOneReplica(b[i], b[i+1], idx, ios); if (idx == replica_index) { assert sat(i, scheduler_action); } else { assert next_action_type_fun[i] == next_action_type_fun[i+1]; } } else { assert next_action_type_fun[i] == next_action_type_fun[i+1]; } assert sat(i, m); } TemporalAlways(0, m); } lemma lemma_SchedulerNextImpliesSpecificScheduleAction( b:Behavior, i:int, asp:AssumptionParameters, replica_index:int, action_index:int ) requires imaptotal(b) requires sat(i, MakeRslActionTemporalFromSchedulerFunction(b, replica_index)) requires b[i].replicas[replica_index].nextActionIndex == action_index ensures 0 <= action_index < LReplicaNumActions() ==> sat(i, ReplicaSchedule(b, replica_index)[action_index]) { assert RslSchedulerActionOccursForReplica(b[i], b[i+1], replica_index); var ios :| && RslNextOneReplica(b[i], b[i+1], replica_index, ios) && LSchedulerNext(b[i].replicas[replica_index], b[i+1].replicas[replica_index], ios); if action_index == 0 { assert SpecificRslActionOccurs(b[i], b[i+1], LReplicaNextProcessPacket, replica_index); } else if action_index == 1 { assert SpecificSpontaneousRslActionOccurs(b[i], b[i+1], LReplicaNextSpontaneousMaybeEnterNewViewAndSend1a, replica_index); } else if action_index == 2 { assert SpecificSpontaneousRslActionOccurs(b[i], b[i+1], LReplicaNextSpontaneousMaybeEnterPhase2, replica_index); } else if action_index == 3 { assert SpecificClockReadingRslActionOccurs(b[i], b[i+1], LReplicaNextReadClockMaybeNominateValueAndSend2a, replica_index); } else if action_index == 4 { assert SpecificSpontaneousRslActionOccurs(b[i], b[i+1], LReplicaNextSpontaneousTruncateLogBasedOnCheckpoints, replica_index); } else if action_index == 5 { assert SpecificSpontaneousRslActionOccurs(b[i], b[i+1], LReplicaNextSpontaneousMaybeMakeDecision, replica_index); } else if action_index == 6 { assert SpecificSpontaneousRslActionOccurs(b[i], b[i+1], LReplicaNextSpontaneousMaybeExecute, replica_index); } else if action_index == 7 { assert SpecificClockReadingRslActionOccurs(b[i], b[i+1], LReplicaNextReadClockCheckForViewTimeout, replica_index); } else if action_index == 8 { assert SpecificClockReadingRslActionOccurs(b[i], b[i+1], LReplicaNextReadClockCheckForQuorumOfViewSuspicions, replica_index); } else if action_index == 9 { assert SpecificClockReadingRslActionOccurs(b[i], b[i+1], LReplicaNextReadClockMaybeSendHeartbeat, replica_index); } } lemma lemma_ReplicaNextPerformsSubactionPeriodically( b:Behavior, asp:AssumptionParameters, replica_index:int, action_index:int ) requires LivenessAssumptions(b, asp) requires replica_index in asp.live_quorum requires 0 <= action_index < LReplicaNumActions() ensures var real_time_fun := PaxosTimeMap(b); var longer_interval := TimeToPerformGenericAction(asp); sat(asp.synchrony_start, always(eventuallynextwithin(ReplicaSchedule(b, replica_index)[action_index], longer_interval, real_time_fun))); { var next_action_type_fun := imap i :: if 0 <= replica_index < |b[i].replicas| then b[i].replicas[replica_index].nextActionIndex else 0; var real_time_fun := PaxosTimeMap(b); var scheduler_action := MakeRslActionTemporalFromSchedulerFunction(b, replica_index); var schedule := ReplicaSchedule(b, replica_index); var t := stepmap(imap j :: real_time_fun[j] <= real_time_fun[nextstep(j)]); forall j | 0 <= j ensures sat(j, t) { lemma_AssumptionsMakeValidTransition(b, asp.c, j); } TemporalAlways(0, t); Lemma_MonotonicStepsLeadToMonotonicBehavior(0, real_time_fun); lemma_PaxosNextTakesSchedulerActionOrLeavesNextActionIndexUnchanged(b, asp, replica_index, next_action_type_fun, scheduler_action); assert HostExecutesPeriodically(b, asp, replica_index); forall i {:trigger sat(i, scheduler_action)} | 0 <= i && sat(i, scheduler_action) ensures var action_type_index := next_action_type_fun[i]; && (0 <= action_type_index < |schedule| ==> sat(i, schedule[action_type_index])) && next_action_type_fun[i+1] == (action_type_index + 1) % |schedule| { var action_type_index := next_action_type_fun[i]; lemma_SchedulerNextImpliesSpecificScheduleAction(b, i, asp, replica_index, action_type_index); assert next_action_type_fun[i+1] == (action_type_index + 1) % |schedule|; } Lemma_RoundRobinSchedulerTimelyForAllActionsTemporal(b, next_action_type_fun, real_time_fun, scheduler_action, schedule, asp.synchrony_start, asp.host_period); assert sat(asp.synchrony_start, always(eventuallynextwithin(schedule[action_index], asp.host_period * |schedule|, real_time_fun))); assert sat(asp.synchrony_start, always(eventuallynextwithin(ReplicaSchedule(b, replica_index)[action_index], TimeToPerformGenericAction(asp), real_time_fun))); } lemma lemma_ReplicaNextPerformsSubactionSoon( b:Behavior, asp:AssumptionParameters, start_step:int, replica_index:int, action_index:int ) returns ( action_step:int ) requires LivenessAssumptions(b, asp) requires replica_index in asp.live_quorum requires 0 <= action_index < LReplicaNumActions() requires asp.synchrony_start <= start_step ensures start_step <= action_step ensures b[action_step+1].environment.time <= b[start_step].environment.time + TimeToPerformGenericAction(asp) ensures sat(action_step, ReplicaSchedule(b, replica_index)[action_index]) { var x := ReplicaSchedule(b, replica_index)[action_index]; var t := TimeToPerformGenericAction(asp); var f := PaxosTimeMap(b); lemma_ReplicaNextPerformsSubactionPeriodically(b, asp, replica_index, action_index); TemporalDeduceFromAlways(asp.synchrony_start, start_step, eventuallynextwithin(x, t, f)); action_step := TemporalDeduceFromEventuallyNextWithin(start_step, x, t, f); } lemma lemma_ReplicaNextPerformsSubactionSoonAfter( b:Behavior, asp:AssumptionParameters, start_step:int, replica_index:int, action_index:int, earliest:int ) returns ( action_step:int ) requires LivenessAssumptions(b, asp) requires replica_index in asp.live_quorum requires 0 <= action_index < LReplicaNumActions() requires asp.synchrony_start <= start_step ensures start_step <= action_step ensures b[action_step+1].environment.time >= earliest ensures b[action_step+1].environment.time <= TimeToPerformGenericAction(asp) + (if earliest >= b[start_step].environment.time then earliest else b[start_step].environment.time) ensures sat(action_step, ReplicaSchedule(b, replica_index)[action_index]); { var x := ReplicaSchedule(b, replica_index)[action_index]; var t := TimeToPerformGenericAction(asp); var f := PaxosTimeMap(b); lemma_ReplicaNextPerformsSubactionPeriodically(b, asp, replica_index, action_index); TemporalDeduceFromAlways(asp.synchrony_start, start_step, eventuallynextwithin(x, t, f)); if earliest < b[start_step].environment.time { action_step := TemporalDeduceFromEventuallyNextWithin(start_step, x, t, f); assert b[action_step+1].environment.time <= b[start_step].environment.time + t; lemma_TimeAdvancesBetween(b, asp, start_step, action_step+1); } else { Lemma_AlwaysImpliesLaterAlways(asp.synchrony_start, start_step, eventuallynextwithin(x, t, f)); lemma_TimeMonotonicFromInvariantHolds(b, asp, 0); lemma_AfterForm(b, asp); action_step := Lemma_AlwaysEventuallyWithinMeansAlwaysEventuallyWithinAfter(start_step, x, earliest - b[start_step].environment.time, t, f); assert b[action_step+1].environment.time <= b[start_step].environment.time + (earliest - b[start_step].environment.time) + t; } } lemma lemma_ProcessingPacketCausesReceiveAttempt( b:Behavior, asp:AssumptionParameters, replica_index:int, i:int ) requires LivenessAssumptions(b, asp) requires 0 <= i requires 0 <= replica_index < |asp.c.config.replica_ids| requires sat(i, MakeRslActionTemporalFromReplicaFunction(b, LReplicaNextProcessPacket, replica_index)) ensures sat(i, ReceiveAttemptedTemporal(RestrictBehaviorToEnvironment(b), asp.c.config.replica_ids[replica_index])) { var eb := RestrictBehaviorToEnvironment(b); var host := asp.c.config.replica_ids[replica_index]; lemma_ReplicasSize(b, asp.c, i); var action := MakeRslActionTemporalFromReplicaFunction(b, LReplicaNextProcessPacket, replica_index); assert sat(i, action); assert SpecificRslActionOccurs(b[i], b[i+1], LReplicaNextProcessPacket, replica_index); var ios:seq :| && RslNextOneReplica(b[i], b[i+1], replica_index, ios) && LReplicaNextProcessPacket(b[i].replicas[replica_index].replica, b[i+1].replicas[replica_index].replica, ios); assert |ios| >= 1 && (ios[0].LIoOpTimeoutReceive? || ios[0].LIoOpReceive?); lemma_ConstantsAllConsistent(b, asp.c, i); assert ReceiveAttemptedInStep(b[i].environment, host); assert sat(i, ReceiveAttemptedTemporal(eb, host)); } lemma lemma_ReplicaNextPerformsProcessPacketPeriodically( b:Behavior, asp:AssumptionParameters, replica_index:int ) requires LivenessAssumptions(b, asp) requires replica_index in asp.live_quorum ensures var real_time_fun := PaxosTimeMap(b); var longer_interval := TimeToPerformGenericAction(asp); sat(asp.synchrony_start, always(eventuallynextwithin(MakeRslActionTemporalFromReplicaFunction(b, LReplicaNextProcessPacket, replica_index), longer_interval, real_time_fun))) ensures var real_time_fun := PaxosTimeMap(b); var longer_interval := TimeToPerformGenericAction(asp); var host := asp.c.config.replica_ids[replica_index]; sat(asp.synchrony_start, always(eventuallynextwithin(ReceiveAttemptedTemporal(RestrictBehaviorToEnvironment(b), host), longer_interval, real_time_fun))) { var real_time_fun := PaxosTimeMap(b); var longer_interval := TimeToPerformGenericAction(asp); lemma_ReplicaNextPerformsSubactionPeriodically(b, asp, replica_index, 0); assert sat(asp.synchrony_start, always(eventuallynextwithin(MakeRslActionTemporalFromReplicaFunction(b, LReplicaNextProcessPacket, replica_index), longer_interval, real_time_fun))); var host := asp.c.config.replica_ids[replica_index]; var eb := RestrictBehaviorToEnvironment(b); forall i | TLe(asp.synchrony_start, i) ensures sat(i, eventuallynextwithin(ReceiveAttemptedTemporal(eb, host), longer_interval, real_time_fun)) { lemma_ReplicasSize(b, asp.c, i); TemporalDeduceFromAlways(asp.synchrony_start, i, eventuallynextwithin(MakeRslActionTemporalFromReplicaFunction(b, LReplicaNextProcessPacket, replica_index), longer_interval, real_time_fun)); var j := TemporalDeduceFromEventuallyNextWithin(i, MakeRslActionTemporalFromReplicaFunction(b, LReplicaNextProcessPacket, replica_index), longer_interval, real_time_fun); lemma_ProcessingPacketCausesReceiveAttempt(b, asp, replica_index, j); TemporalEventuallyNextWithin(i, j, ReceiveAttemptedTemporal(eb, host), longer_interval, real_time_fun); } TemporalAlways(asp.synchrony_start, eventuallynextwithin(ReceiveAttemptedTemporal(RestrictBehaviorToEnvironment(b), host), longer_interval, real_time_fun)); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/LivenessProof/Seqno.i.dfy ================================================ include "../DistributedSystem.i.dfy" include "Assumptions.i.dfy" include "Invariants.i.dfy" include "PacketHandling.i.dfy" include "../CommonProof/Constants.i.dfy" include "../CommonProof/Actions.i.dfy" include "../CommonProof/ReplyCache.i.dfy" include "../CommonProof/Requests.i.dfy" module LivenessProof__Seqno_i { import opened LiveRSL__Acceptor_i import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Election_i import opened LiveRSL__Environment_i import opened LiveRSL__Executor_i import opened LiveRSL__Learner_i import opened LiveRSL__Proposer_i import opened LiveRSL__Replica_i import opened LiveRSL__StateMachine_i import opened LiveRSL__Types_i import opened LivenessProof__Assumptions_i import opened LivenessProof__Environment_i import opened LivenessProof__Invariants_i import opened LivenessProof__PacketHandling_i import opened Liveness__HostQueueLemmas_i import opened CommonProof__Actions_i import opened CommonProof__Constants_i import opened CommonProof__PacketSending_i import opened CommonProof__ReplyCache_i import opened CommonProof__Requests_i import opened Temporal__Heuristics_i import opened Temporal__Rules_i import opened Temporal__Temporal_s import opened AppStateMachine_s import opened Environment_s import opened EnvironmentSynchrony_s ///////////////////// // INVARIANTS ///////////////////// predicate SequenceNumberRequestInv(req':Request, req:Request) requires req.Request? { req'.Request? && req'.client == req.client ==> (req'.seqno < req.seqno) || (req'.seqno == req.seqno && req'.request == req.request) } predicate SequenceNumberBatchInv(batch:RequestBatch, req:Request) requires req.Request? { forall req' :: req' in batch ==> SequenceNumberRequestInv(req', req) } predicate SequenceNumberVotesInv(votes:Votes, req:Request) requires req.Request? { forall op :: op in votes ==> SequenceNumberBatchInv(votes[op].max_val, req) } predicate SequenceNumberLearnerStateInv(s:LearnerState, req:Request) requires req.Request? { forall op :: op in s ==> SequenceNumberBatchInv(s[op].candidate_learned_value, req) } predicate SequenceNumberReplyCacheInv(reply_cache:ReplyCache, req:Request) requires req.Request? { req.client in reply_cache && reply_cache[req.client].Reply? ==> reply_cache[req.client].seqno <= req.seqno } predicate SequenceNumberPacketInv(p:RslPacket, req:Request) requires req.Request? { && (p.msg.RslMessage_Request? ==> SequenceNumberRequestInv(Request(p.src, p.msg.seqno_req, p.msg.val), req)) && (p.msg.RslMessage_1b? ==> SequenceNumberVotesInv(p.msg.votes, req)) && (p.msg.RslMessage_2a? ==> SequenceNumberBatchInv(p.msg.val_2a, req)) && (p.msg.RslMessage_2b? ==> SequenceNumberBatchInv(p.msg.val_2b, req)) } predicate SequenceNumberReplicaInv(s:LReplica, req:Request) requires req.Request? { && (forall r :: r in s.proposer.request_queue ==> SequenceNumberRequestInv(r, req)) && (forall p :: p in s.proposer.received_1b_packets ==> SequenceNumberPacketInv(p, req)) && (forall r :: r in s.proposer.election_state.requests_received_this_epoch ==> SequenceNumberRequestInv(r, req)) && (forall r :: r in s.proposer.election_state.requests_received_prev_epochs ==> SequenceNumberRequestInv(r, req)) && SequenceNumberVotesInv(s.acceptor.votes, req) && SequenceNumberLearnerStateInv(s.learner.unexecuted_learner_state, req) && (s.executor.next_op_to_execute.OutstandingOpKnown? ==> SequenceNumberBatchInv(s.executor.next_op_to_execute.v, req)) && SequenceNumberReplyCacheInv(s.executor.reply_cache, req) } predicate SequenceNumberStateInv(ps:RslState, req:Request) requires req.Request? { && (forall p :: p in ps.environment.sentPackets && p.src in ps.constants.config.replica_ids ==> SequenceNumberPacketInv(p, req)) && (forall idx :: 0 <= idx < |ps.replicas| ==> SequenceNumberReplicaInv(ps.replicas[idx].replica, req)) } //////////////////////// // PACKET INVARIANT //////////////////////// lemma lemma_SequenceNumberPacketInvHolds( ps:RslState, ps':RslState, idx:int, ios:seq, p:RslPacket, req:Request ) requires RslNextOneReplica(ps, ps', idx, ios) requires req.Request? requires LIoOpSend(p) in ios requires SequenceNumberStateInv(ps, req) requires LEnvironmentInvariant(ps.environment) requires ConstantsAllConsistentInv(ps) ensures SequenceNumberPacketInv(p, req) { var s := ps.replicas[idx].replica; var s' := ps'.replicas[idx].replica; var id := ps.constants.config.replica_ids[idx]; var e := ps.environment; var e' := ps'.environment; var sent_packets := ExtractSentPacketsFromIos(ios); if p.msg.RslMessage_2b? { var inp:RslPacket :| ios[0] == LIoOpReceive(inp) && inp.msg.RslMessage_2a? && LReplicaNextProcess2a(s, s', inp, sent_packets); lemma_PacketProcessedImpliesPacketSent(ps, ps', idx, ios, inp); if inp.src in ps.constants.config.replica_ids { assert SequenceNumberPacketInv(inp, req); assert SequenceNumberPacketInv(p, req); } } } lemma lemma_ReplicaNextPreservesSequenceNumberRequestQueueInv( ps:RslState, ps':RslState, idx:int, ios:seq, req:Request ) requires RslNext(ps, ps') requires req.Request? requires 0 <= idx < |ps.replicas| requires RslNextOneReplica(ps, ps', idx, ios) requires SequenceNumberStateInv(ps, req) requires LEnvironmentInvariant(ps.environment) requires ConstantsAllConsistentInv(ps) requires |ps.constants.config.replica_ids| == |ps.replicas| == |ps'.constants.config.replica_ids| == |ps'.replicas| requires 0 <= idx < |ps'.replicas| requires ClientNeverSentHigherSequenceNumberRequest(ps, req) ensures forall r :: r in ps'.replicas[idx].replica.proposer.request_queue ==> SequenceNumberRequestInv(r, req) { var s := ps.replicas[idx].replica; var s' := ps'.replicas[idx].replica; var votes := s.acceptor.votes; var votes' := s'.acceptor.votes; var id := ps.constants.config.replica_ids[idx]; var e := ps.environment; var e' := ps'.environment; forall r | r in s'.proposer.request_queue ensures SequenceNumberRequestInv(r, req) { if r !in s.proposer.request_queue { if |ios| > 0 && ios[0].LIoOpReceive? && LProposerProcessRequest(s.proposer, s'.proposer, ios[0].r) { var inp := ios[0].r; lemma_PacketProcessedImpliesPacketSent(ps, ps', idx, ios, inp); assert SequenceNumberPacketInv(inp, req); assert r == Request(inp.src, inp.msg.seqno_req, inp.msg.val); assert SequenceNumberRequestInv(r, req); } else { assert SequenceNumberRequestInv(r, req); } } } } //////////////////////////////////////////////// // STATE INVARIANTS - SPECIFIC PARTS OF STATE //////////////////////////////////////////////// lemma lemma_ReplicaNextPreservesSequenceNumberReceived1bPacketsInv( ps:RslState, ps':RslState, idx:int, ios:seq, req:Request ) requires RslNext(ps, ps') requires req.Request? requires 0 <= idx < |ps.replicas| requires RslNextOneReplica(ps, ps', idx, ios) requires SequenceNumberStateInv(ps, req) requires LEnvironmentInvariant(ps.environment) requires ConstantsAllConsistentInv(ps) requires |ps.constants.config.replica_ids| == |ps.replicas| == |ps'.constants.config.replica_ids| == |ps'.replicas| requires 0 <= idx < |ps'.replicas| ensures forall p :: p in ps'.replicas[idx].replica.proposer.received_1b_packets ==> SequenceNumberPacketInv(p, req) { var s := ps.replicas[idx].replica; var s' := ps'.replicas[idx].replica; var votes := s.acceptor.votes; var votes' := s'.acceptor.votes; var id := ps.constants.config.replica_ids[idx]; var e := ps.environment; var e' := ps'.environment; forall p | p in s'.proposer.received_1b_packets ensures SequenceNumberPacketInv(p, req) { if p !in s.proposer.received_1b_packets { assert |ios| > 0 && ios[0].LIoOpReceive? && LProposerProcess1b(s.proposer, s'.proposer, ios[0].r); var inp := ios[0].r; lemma_PacketProcessedImpliesPacketSent(ps, ps', idx, ios, inp); assert SequenceNumberPacketInv(inp, req); } } } lemma lemma_ReplicaNextPreservesSequenceNumberRequestsReceivedInv( ps:RslState, ps':RslState, idx:int, ios:seq, req:Request ) requires RslNext(ps, ps') requires req.Request? requires 0 <= idx < |ps.replicas| requires RslNextOneReplica(ps, ps', idx, ios) requires SequenceNumberStateInv(ps, req) requires LEnvironmentInvariant(ps.environment) requires ConstantsAllConsistentInv(ps) requires |ps.constants.config.replica_ids| == |ps.replicas| == |ps'.constants.config.replica_ids| == |ps'.replicas| requires 0 <= idx < |ps'.replicas| requires ClientNeverSentHigherSequenceNumberRequest(ps, req) ensures forall r :: r in ps'.replicas[idx].replica.proposer.election_state.requests_received_this_epoch ==> SequenceNumberRequestInv(r, req) ensures forall r :: r in ps'.replicas[idx].replica.proposer.election_state.requests_received_prev_epochs ==> SequenceNumberRequestInv(r, req) { var s := ps.replicas[idx].replica; var s' := ps'.replicas[idx].replica; var votes := s.acceptor.votes; var votes' := s'.acceptor.votes; var id := ps.constants.config.replica_ids[idx]; var e := ps.environment; var e' := ps'.environment; var es := s.proposer.election_state; var es' := s'.proposer.election_state; forall r | r in es'.requests_received_this_epoch ensures SequenceNumberRequestInv(r, req) { if r !in es.requests_received_this_epoch { if |ios| > 0 && ios[0].LIoOpReceive? && LProposerProcessRequest(s.proposer, s'.proposer, ios[0].r) { var inp := ios[0].r; lemma_PacketProcessedImpliesPacketSent(ps, ps', idx, ios, inp); assert SequenceNumberPacketInv(inp, req); assert SequenceNumberRequestInv(r, req); } else if exists batch :: ElectionStateReflectExecutedRequestBatch(es, es', batch) { var batch :| ElectionStateReflectExecutedRequestBatch(es, es', batch); lemma_RemoveExecutedRequestBatchProducesSubsequence(es'.requests_received_this_epoch, es.requests_received_this_epoch, batch); assert SequenceNumberRequestInv(r, req); } else { assert false; } } } forall r | r in es'.requests_received_prev_epochs ensures SequenceNumberRequestInv(r, req) { if r !in es.requests_received_prev_epochs { if exists batch :: ElectionStateReflectExecutedRequestBatch(es, es', batch) { var batch :| ElectionStateReflectExecutedRequestBatch(es, es', batch); lemma_RemoveExecutedRequestBatchProducesSubsequence(es'.requests_received_prev_epochs, es.requests_received_prev_epochs, batch); assert SequenceNumberRequestInv(r, req); } assert r in es.requests_received_this_epoch; } } } lemma lemma_ReplicaNextPreservesSequenceNumberVotesInv( ps:RslState, ps':RslState, idx:int, ios:seq, req:Request ) requires RslNext(ps, ps') requires req.Request? requires 0 <= idx < |ps.replicas| requires RslNextOneReplica(ps, ps', idx, ios) requires SequenceNumberStateInv(ps, req) requires LEnvironmentInvariant(ps.environment) requires ConstantsAllConsistentInv(ps) requires |ps.constants.config.replica_ids| == |ps.replicas| == |ps'.constants.config.replica_ids| == |ps'.replicas| requires 0 <= idx < |ps'.replicas| ensures SequenceNumberVotesInv(ps'.replicas[idx].replica.acceptor.votes, req) { var s := ps.replicas[idx].replica; var s' := ps'.replicas[idx].replica; var votes := s.acceptor.votes; var votes' := s'.acceptor.votes; var id := ps.constants.config.replica_ids[idx]; forall op | op in votes' ensures SequenceNumberBatchInv(votes'[op].max_val, req) { if op in votes && votes'[op] == votes[op] { assert SequenceNumberBatchInv(votes[op].max_val, req); } else { assert |ios| >= 1 && ios[0].LIoOpReceive?; var inp := ios[0].r; assert LAcceptorProcess2a(s.acceptor, s'.acceptor, inp, ExtractSentPacketsFromIos(ios)); lemma_PacketProcessedImpliesPacketSent(ps, ps', idx, ios, inp); assert SequenceNumberPacketInv(inp, req); assert SequenceNumberBatchInv(votes'[op].max_val, req); } } } lemma lemma_ReplicaNextPreservesSequenceNumberLearnerStateInv( ps:RslState, ps':RslState, idx:int, ios:seq, req:Request ) requires RslNext(ps, ps') requires req.Request? requires 0 <= idx < |ps.replicas| requires RslNextOneReplica(ps, ps', idx, ios) requires SequenceNumberStateInv(ps, req) requires LEnvironmentInvariant(ps.environment) requires ConstantsAllConsistentInv(ps) requires |ps.constants.config.replica_ids| == |ps.replicas| == |ps'.constants.config.replica_ids| == |ps'.replicas| requires 0 <= idx < |ps'.replicas| ensures SequenceNumberLearnerStateInv(ps'.replicas[idx].replica.learner.unexecuted_learner_state, req) { var s := ps.replicas[idx].replica; var s' := ps'.replicas[idx].replica; var votes := s.acceptor.votes; var votes' := s'.acceptor.votes; var id := ps.constants.config.replica_ids[idx]; forall op | op in s'.learner.unexecuted_learner_state ensures SequenceNumberBatchInv(s'.learner.unexecuted_learner_state[op].candidate_learned_value, req) { if op in s.learner.unexecuted_learner_state && s'.learner.unexecuted_learner_state[op] == s.learner.unexecuted_learner_state[op] { assert SequenceNumberBatchInv(s.learner.unexecuted_learner_state[op].candidate_learned_value, req); } else { assert |ios| >= 1 && ios[0].LIoOpReceive?; var inp := ios[0].r; assert LLearnerProcess2b(s.learner, s'.learner, inp); lemma_PacketProcessedImpliesPacketSent(ps, ps', idx, ios, inp); assert SequenceNumberPacketInv(inp, req); assert SequenceNumberBatchInv(s'.learner.unexecuted_learner_state[op].candidate_learned_value, req); } } } lemma lemma_ReplicaNextPreservesSequenceNumberReplyCacheInv( ps:RslState, ps':RslState, idx:int, ios:seq, req:Request ) requires RslNext(ps, ps') requires req.Request? requires 0 <= idx < |ps.replicas| requires RslNextOneReplica(ps, ps', idx, ios) requires SequenceNumberStateInv(ps, req) requires LEnvironmentInvariant(ps.environment) requires ConstantsAllConsistentInv(ps) requires |ps.constants.config.replica_ids| == |ps.replicas| == |ps'.constants.config.replica_ids| == |ps'.replicas| requires 0 <= idx < |ps'.replicas| ensures SequenceNumberReplyCacheInv(ps'.replicas[idx].replica.executor.reply_cache, req) { var s := ps.replicas[idx].replica; var s' := ps'.replicas[idx].replica; var votes := s.acceptor.votes; var votes' := s'.acceptor.votes; var id := ps.constants.config.replica_ids[idx]; if req.Request? && req.client in s'.executor.reply_cache && s'.executor.reply_cache[req.client].Reply? && s'.executor.reply_cache[req.client].seqno > req.seqno { if LReplicaNextSpontaneousMaybeExecute(s, s', ExtractSentPacketsFromIos(ios)) { var batch := s.executor.next_op_to_execute.v; var states := HandleRequestBatch(s.executor.app, batch).0; var replies := HandleRequestBatch(s.executor.app, batch).1; lemma_HandleRequestBatchTriggerHappy(s.executor.app, batch, states, replies); assert SequenceNumberReplyCacheInv(s.executor.reply_cache, req); var req_idx :| 0 <= req_idx < |batch| && replies[req_idx].client == req.client && s'.executor.reply_cache[req.client] == replies[req_idx]; assert SequenceNumberBatchInv(batch, req); assert SequenceNumberRequestInv(batch[req_idx], req); assert false; } else if |ios| > 0 && ios[0].LIoOpReceive? && LExecutorProcessAppStateSupply(s.executor, s'.executor, ios[0].r) { assert SequenceNumberReplyCacheInv(s'.executor.reply_cache, req); } else { assert SequenceNumberReplyCacheInv(s'.executor.reply_cache, req); } } } lemma lemma_ReplicaNextPreservesSequenceNumberReplicaInv( ps:RslState, ps':RslState, idx:int, ios:seq, req:Request ) requires RslNext(ps, ps') requires req.Request? requires 0 <= idx < |ps.replicas| requires RslNextOneReplica(ps, ps', idx, ios) requires SequenceNumberStateInv(ps, req) requires LEnvironmentInvariant(ps.environment) requires ConstantsAllConsistentInv(ps) requires |ps.constants.config.replica_ids| == |ps.replicas| == |ps'.constants.config.replica_ids| == |ps'.replicas| requires 0 <= idx < |ps'.replicas| requires ClientNeverSentHigherSequenceNumberRequest(ps, req) ensures SequenceNumberReplicaInv(ps'.replicas[idx].replica, req) { var s := ps.replicas[idx].replica; var s' := ps'.replicas[idx].replica; lemma_ReplicaNextPreservesSequenceNumberRequestQueueInv(ps, ps', idx, ios, req); lemma_ReplicaNextPreservesSequenceNumberReceived1bPacketsInv(ps, ps', idx, ios, req); lemma_ReplicaNextPreservesSequenceNumberRequestsReceivedInv(ps, ps', idx, ios, req); lemma_ReplicaNextPreservesSequenceNumberVotesInv(ps, ps', idx, ios, req); lemma_ReplicaNextPreservesSequenceNumberLearnerStateInv(ps, ps', idx, ios, req); assert s'.executor.next_op_to_execute.OutstandingOpKnown? ==> SequenceNumberBatchInv(s'.executor.next_op_to_execute.v, req); lemma_ReplicaNextPreservesSequenceNumberReplyCacheInv(ps, ps', idx, ios, req); } ///////////////////////////////// // STATE INVARIANT - REPLICA ///////////////////////////////// lemma lemma_PaxosNextPreservesSequenceNumberReplicaInv(ps:RslState, ps':RslState, idx:int, req:Request) requires RslNext(ps, ps') requires req.Request? requires SequenceNumberStateInv(ps, req) requires LEnvironmentInvariant(ps.environment) requires ConstantsAllConsistentInv(ps) requires |ps.constants.config.replica_ids| == |ps.replicas| == |ps'.constants.config.replica_ids| == |ps'.replicas| requires 0 <= idx < |ps'.replicas| requires ClientNeverSentHigherSequenceNumberRequest(ps, req) ensures SequenceNumberReplicaInv(ps'.replicas[idx].replica, req) { var id := ps.constants.config.replica_ids[idx]; if exists other_index, ios :: RslNextOneReplica(ps, ps', other_index, ios) { var other_index, ios :| RslNextOneReplica(ps, ps', other_index, ios); if other_index != idx { assert SequenceNumberReplicaInv(ps.replicas[idx].replica, req); assert ps'.replicas[idx].replica == ps.replicas[idx].replica; assert SequenceNumberReplicaInv(ps'.replicas[idx].replica, req); } else { lemma_ReplicaNextPreservesSequenceNumberReplicaInv(ps, ps', idx, ios, req); } } } ///////////////////////////////// // STATE INVARIANT - OVERALL ///////////////////////////////// lemma lemma_SequenceNumberStateInvHolds(b:Behavior, asp:AssumptionParameters, i:int) requires LivenessAssumptions(b, asp) requires 0 <= i ensures SequenceNumberStateInv(b[i], asp.persistent_request) { lemma_LEnvironmentInvariantHolds(b, asp, i); lemma_ConstantsAllConsistent(b, asp.c, i); if i > 0 { lemma_SequenceNumberStateInvHolds(b, asp, i-1); lemma_ConstantsAllConsistent(b, asp.c, i-1); lemma_LEnvironmentInvariantHolds(b, asp, i-1); lemma_AssumptionsMakeValidTransition(b, asp.c, i-1); var ps := b[i-1]; var ps' := b[i]; assert RslNext(ps, ps'); forall idx | 0 <= idx < |ps'.replicas| ensures SequenceNumberReplicaInv(ps'.replicas[idx].replica, asp.persistent_request) { TemporalDeduceFromAlways(0, i-1, ClientNeverSentHigherSequenceNumberRequestTemporal(b, asp)); assert sat(i-1, ClientNeverSentHigherSequenceNumberRequestTemporal(b, asp)); assert ClientNeverSentHigherSequenceNumberRequest(ps, asp.persistent_request); lemma_PaxosNextPreservesSequenceNumberReplicaInv(ps, ps', idx, asp.persistent_request); } forall p | p in ps'.environment.sentPackets && p.src in ps.constants.config.replica_ids ensures SequenceNumberPacketInv(p, asp.persistent_request) { if p !in ps.environment.sentPackets { var idx, ios := lemma_ActionThatSendsPacketIsActionOfSource(ps, ps', p); lemma_SequenceNumberPacketInvHolds(ps, ps', idx, ios, p, asp.persistent_request); } } } } /////////////////////////// // USEFUL COROLLARIES /////////////////////////// lemma lemma_SequenceNumberReplyCacheInvHolds( b:Behavior, asp:AssumptionParameters, i:int, idx:int ) requires LivenessAssumptions(b, asp) requires 0 <= i requires 0 <= idx < |b[i].replicas| ensures SequenceNumberReplyCacheInv(b[i].replicas[idx].replica.executor.reply_cache, asp.persistent_request) { lemma_SequenceNumberStateInvHolds(b, asp, i); } lemma lemma_RequestNeverHitsInReplyCache( b:Behavior, asp:AssumptionParameters, processing_sync_start:int, processing_bound:int, i:int, idx:int, ios:seq, inp:RslPacket ) requires LivenessAssumptions(b, asp) requires RslNextOneReplica(b[i], b[i+1], idx, ios) requires 0 <= idx < |b[i].replicas| requires 0 <= idx < |b[i+1].replicas| requires idx in asp.live_quorum requires inp.src == asp.persistent_request.client requires inp.msg.RslMessage_Request? requires inp.msg.seqno_req == asp.persistent_request.seqno requires inp.msg.val == asp.persistent_request.request requires processing_sync_start <= i requires PacketProcessingSynchronous(b, asp, processing_sync_start, processing_bound) requires LReplicaNextProcessRequest(b[i].replicas[idx].replica, b[i+1].replicas[idx].replica, inp, ExtractSentPacketsFromIos(ios)) ensures LProposerProcessRequest(b[i].replicas[idx].replica.proposer, b[i+1].replicas[idx].replica.proposer, inp) ensures ExtractSentPacketsFromIos(ios) == [] ensures b[i+1].replicas[idx].replica == b[i].replicas[idx].replica.(proposer := b[i+1].replicas[idx].replica.proposer) { // If we satisfy the postcondition, we're done. if && LProposerProcessRequest(b[i].replicas[idx].replica.proposer, b[i+1].replicas[idx].replica.proposer, inp) && ExtractSentPacketsFromIos(ios) == [] && b[i+1].replicas[idx].replica == b[i].replicas[idx].replica.(proposer := b[i+1].replicas[idx].replica.proposer) { return; } // Since we don't satisfy the postcondition, we know that we sent a reply out of // the reply cache. var executor := b[i].replicas[idx].replica.executor; var reply_cache := executor.reply_cache; var sent_packets := ExtractSentPacketsFromIos(ios); assert |inp.msg.val| <= MaxAppRequestSize(); lemma_SequenceNumberReplyCacheInvHolds(b, asp, i, idx); lemma_ConstantsAllConsistent(b, asp.c, i); // From the reply-cache invariant, we know that there can never be a sequence number // in the reply cache beyond that of the persistent request. Also, the protocol dictates // that we don't send a reply out of the reply cache that precedes the given request. // So it must be that the reply we sent out of the reply cache matches this request's // sequence number. assert inp.msg.seqno_req == reply_cache[inp.src].seqno; lemma_ReplyCacheStateInv(b, asp.c, i, inp.src); assert reply_cache[inp.src].client == inp.src; var p := sent_packets[0]; assert LIoOpSend(p) in ios; // Since we sent a matching reply out of the reply cache, and we're in the synchronous // period, the packet must be eventually received by the client. This contradicts // the assumption that the client never receives a reply. And this contradiction // completes the proof. assert asp.synchrony_start <= i; assert p.src in SetOfReplicaIndicesToSetOfHosts(asp.live_quorum, asp.c.config.replica_ids) + { asp.persistent_request.client }; assert p.dst in SetOfReplicaIndicesToSetOfHosts(asp.live_quorum, asp.c.config.replica_ids) + { asp.persistent_request.client }; var delivery_step := lemma_PacketSentEventuallyDelivered(b, asp, i, p); lemma_ConstantsAllConsistent(b, asp.c, delivery_step); assert ReplyDeliveredDuringStep(b[delivery_step], asp.persistent_request); TemporalDeduceFromAlways(0, delivery_step, not(ReplyDeliveredTemporal(b, asp.persistent_request))); assert false; } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/LivenessProof/StablePeriod.i.dfy ================================================ include "Assumptions.i.dfy" include "PacketHandling.i.dfy" module LivenessProof__StablePeriod_i { import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Environment_i import opened LiveRSL__Proposer_i import opened LiveRSL__Replica_i import opened LiveRSL__Types_i import opened LivenessProof__Assumptions_i import opened LivenessProof__PacketHandling_i import opened LivenessProof__RoundRobin_i import opened Temporal__Temporal_s import opened Temporal__Time_s import opened Collections__Maps2_s function CurrentViewOfHost( ps:RslState, replica_index:int ):Ballot requires 0 <= replica_index < |ps.replicas| { ps.replicas[replica_index].replica.proposer.election_state.current_view } predicate StablePeriodStarted( ps:RslState, live_quorum:set, view:Ballot, ahead_idx:int ) { && ahead_idx in live_quorum && 0 <= ahead_idx < |ps.replicas| && BalLeq(view, CurrentViewOfHost(ps, ahead_idx)) && view.proposer_id in live_quorum && (forall idx :: 0 <= idx < |ps.replicas| ==> BalLt(ps.replicas[idx].replica.proposer.max_ballot_i_sent_1a, view)) } function{:opaque} StablePeriodStartedTemporal( b:Behavior, live_quorum:set, view:Ballot, ahead_idx:int ):temporal requires imaptotal(b) ensures forall i{:trigger sat(i, StablePeriodStartedTemporal(b, live_quorum, view, ahead_idx))} :: sat(i, StablePeriodStartedTemporal(b, live_quorum, view, ahead_idx)) <==> StablePeriodStarted(b[i], live_quorum, view, ahead_idx) { stepmap(imap i :: StablePeriodStarted(b[i], live_quorum, view, ahead_idx)) } predicate NoReplicaBeyondView( ps:RslState, view:Ballot ) { forall idx :: 0 <= idx < |ps.replicas| ==> BalLeq(CurrentViewOfHost(ps, idx), view) } function{:opaque} NoReplicaBeyondViewTemporal( b:Behavior, view:Ballot ):temporal requires imaptotal(b) ensures forall i{:trigger sat(i, NoReplicaBeyondViewTemporal(b, view))} :: sat(i, NoReplicaBeyondViewTemporal(b, view)) <==> NoReplicaBeyondView(b[i], view) { stepmap(imap i :: NoReplicaBeyondView(b[i], view)) } predicate NoMaxBallotISent1aBeyondView( ps:RslState, view:Ballot ) { forall idx :: 0 <= idx < |ps.replicas| ==> BalLeq(ps.replicas[idx].replica.proposer.max_ballot_i_sent_1a, view) } function{:opaque} NoMaxBallotISent1aBeyondViewTemporal( b:Behavior, view:Ballot ):temporal requires imaptotal(b) ensures forall i{:trigger sat(i, NoMaxBallotISent1aBeyondViewTemporal(b, view))} :: sat(i, NoMaxBallotISent1aBeyondViewTemporal(b, view)) <==> NoMaxBallotISent1aBeyondView(b[i], view) { stepmap(imap i :: NoMaxBallotISent1aBeyondView(b[i], view)) } predicate ObjectInFirstNOfSequence(obj:T, s:seq, n:int) { if |s| <= n then (obj in s) else (n > 0 && obj in s[..n]) } predicate RequestInFirstN( ps:RslState, idx:int, req:Request, n:int ) { && 0 <= idx < |ps.replicas| && ObjectInFirstNOfSequence(req, ps.replicas[idx].replica.proposer.election_state.requests_received_prev_epochs, n) } function{:opaque} RequestInFirstNTemporal( b:Behavior, idx:int, req:Request, n:int ):temporal requires imaptotal(b) ensures forall i{:trigger sat(i, RequestInFirstNTemporal(b, idx, req, n))} :: sat(i, RequestInFirstNTemporal(b, idx, req, n)) <==> RequestInFirstN(b[i], idx, req, n) { stepmap(imap i :: RequestInFirstN(b[i], idx, req, n)) } predicate RequestInFirstNOfRequestQueue( ps:RslState, idx:int, req:Request, n:int ) { && 0 <= idx < |ps.replicas| && ObjectInFirstNOfSequence(req, ps.replicas[idx].replica.proposer.request_queue, n) } datatype Phase2Params = Phase2Params( start_step:int, duration:int, base_duration:int, per_request_duration:int, processing_bound:int, view:Ballot, log_truncation_point:int, king_idx:int, num_requests:int, ios:seq ) function TimeToBeginPhase2(asp:AssumptionParameters, processing_bound:int):int { processing_bound * 3 } function TimeToAdvanceOneOperation(asp:AssumptionParameters, processing_bound:int):int requires asp.host_period > 0 { asp.c.params.max_batch_delay + asp.max_clock_ambiguity * 4 + asp.c.params.heartbeat_period + TimeToPerformGenericAction(asp) * 6 + processing_bound * 3 } predicate Phase2Started( ps:RslState, ps':RslState, asp:AssumptionParameters, h:Phase2Params ) { && 0 <= h.king_idx < |ps'.replicas| && 0 <= h.view.proposer_id < |ps.replicas| && 0 <= h.view.proposer_id < |ps'.replicas| && ps'.replicas[h.king_idx].replica.executor.ops_complete >= h.log_truncation_point && var s := ps.replicas[h.view.proposer_id].replica; var s' := ps'.replicas[h.view.proposer_id].replica; && RslNextOneReplica(ps, ps', h.view.proposer_id, h.ios) && LProposerMaybeEnterPhase2(s.proposer, s'.proposer, s.acceptor.log_truncation_point, ExtractSentPacketsFromIos(h.ios)) && s.proposer.current_state == 1 && s'.proposer.current_state == 2 && s'.proposer.max_ballot_i_sent_1a == h.view && s'.proposer.next_operation_number_to_propose == h.log_truncation_point && ObjectInFirstNOfSequence(asp.persistent_request, s'.proposer.request_queue, h.num_requests) && s'.acceptor.log_truncation_point == h.log_truncation_point } function{:opaque} Phase2StartedTemporal( b:Behavior, asp:AssumptionParameters, h:Phase2Params ):temporal requires imaptotal(b) ensures forall i {:trigger sat(i, Phase2StartedTemporal(b, asp, h))} :: sat(i, Phase2StartedTemporal(b, asp, h)) <==> Phase2Started(b[i], b[nextstep(i)], asp, h); { stepmap(imap i :: Phase2Started(b[i], b[nextstep(i)], asp, h)) } predicate Phase2StableWithRequest( b:Behavior, asp:AssumptionParameters, h:Phase2Params ) { && LivenessAssumptions(b, asp) && asp.synchrony_start <= h.start_step && PacketProcessingSynchronous(b, asp, h.start_step, h.processing_bound) && h.base_duration >= 0 && h.per_request_duration >= 0 && h.duration == h.base_duration + h.num_requests * h.per_request_duration && h.view.proposer_id in asp.live_quorum && h.king_idx in asp.live_quorum && h.num_requests > 0 && sat(h.start_step, Phase2StartedTemporal(b, asp, h)) && sat(h.start_step+1, alwayswithin(NoReplicaBeyondViewTemporal(b, h.view), h.duration, PaxosTimeMap(b))) } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/LivenessProof/StateTransfer.i.dfy ================================================ include "Assumptions.i.dfy" include "Invariants.i.dfy" include "Phase2Invariants.i.dfy" include "../CommonProof/Actions.i.dfy" include "../CommonProof/PacketSending.i.dfy" include "../CommonProof/MaxBallotISent1a.i.dfy" include "../CommonProof/Environment.i.dfy" include "../CommonProof/Chosen.i.dfy" include "../CommonProof/Quorum.i.dfy" include "../CommonProof/Received1b.i.dfy" module LivenessProof__StateTransfer_i { import opened LiveRSL__Configuration_i import opened LiveRSL__Constants_i import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Environment_i import opened LiveRSL__Proposer_i import opened LiveRSL__Types_i import opened LivenessProof__Assumptions_i import opened LivenessProof__Invariants_i import opened LivenessProof__MaxBallotISent1a_i import opened LivenessProof__Phase2Invariants_i import opened LivenessProof__StablePeriod_i import opened CommonProof__Actions_i import opened CommonProof__Assumptions_i import opened CommonProof__Chosen_i import opened CommonProof__Constants_i import opened CommonProof__Environment_i import opened CommonProof__LogTruncationPoint_i import opened CommonProof__MaxBallotISent1a_i import opened CommonProof__Message1b_i import opened CommonProof__PacketSending_i import opened CommonProof__Quorum_i import opened CommonProof__Received1b_i import opened Temporal__Temporal_s import opened Temporal__Rules_i import opened Environment_s import opened Collections__Maps2_s lemma lemma_AppStateSupplyImpliesAppStateRequest( b:Behavior, c:LConstants, i:int, p_state_supply:RslPacket ) returns ( p_state_req:RslPacket ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires p_state_supply in b[i].environment.sentPackets requires p_state_supply.src in c.config.replica_ids requires p_state_supply.msg.RslMessage_AppStateSupply? ensures p_state_req in b[i].environment.sentPackets ensures p_state_req.src in c.config.replica_ids ensures p_state_req.src == p_state_supply.dst ensures p_state_req.msg.RslMessage_AppStateRequest? ensures BalLeq(p_state_supply.msg.bal_state_supply, p_state_req.msg.bal_state_req) { if i == 0 { return; } lemma_ConstantsAllConsistent(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i); lemma_AssumptionsMakeValidTransition(b, c, i-1); if p_state_supply in b[i-1].environment.sentPackets { p_state_req := lemma_AppStateSupplyImpliesAppStateRequest(b, c, i-1, p_state_supply); lemma_PacketStaysInSentPackets(b, c, i-1, i, p_state_req); return; } var idx, ios := lemma_ActionThatSendsAppStateSupplyIsProcessAppStateRequest(b[i-1], b[i], p_state_supply); p_state_req := ios[0].r; assert IsValidLIoOp(ios[0], c.config.replica_ids[idx], b[i-1].environment); } lemma{:timeLimitMultiplier 2} lemma_StateRequestFromKingPrecedesBallotDuringStableView( b:Behavior, asp:AssumptionParameters, h:Phase2Params, i:int, p_state_req:RslPacket ) requires Phase2StableWithRequest(b, asp, h) requires 0 <= i requires p_state_req in b[i].environment.sentPackets requires p_state_req.src == asp.c.config.replica_ids[h.king_idx] requires p_state_req.msg.RslMessage_AppStateRequest? requires NoReplicaBeyondView(b[i], h.view) ensures BalLt(p_state_req.msg.bal_state_req, h.view) { if i == 0 { return; } lemma_ConstantsAllConsistent(b, asp.c, i-1); lemma_ConstantsAllConsistent(b, asp.c, i); lemma_AssumptionsMakeValidTransition(b, asp.c, i-1); if p_state_req in b[i-1].environment.sentPackets { lemma_IfNoReplicaBeyondViewNowThenNoReplicaBeyondViewEarlier(b, asp, i-1, i, h.view); lemma_StateRequestFromKingPrecedesBallotDuringStableView(b, asp, h, i-1, p_state_req); return; } var king_idx, king_ios := lemma_ActionThatSendsAppStateRequestIsProcessStartingPhase2(b[i-1], b[i], p_state_req); var p_starting_phase2 := king_ios[0].r; assert ReplicasDistinct(asp.c.config.replica_ids, king_idx, h.king_idx); assert b[i].replicas[king_idx].replica.executor.ops_complete < p_starting_phase2.msg.logTruncationPoint_2; var x := stepmap(imap j :: p_starting_phase2 in b[j].environment.sentPackets); var next_step := earliestStepBetween(0, i, x); var step := next_step - 1; assert !sat(0, x); assert !sat(step, x); lemma_ConstantsAllConsistent(b, asp.c, step); lemma_ConstantsAllConsistent(b, asp.c, next_step); lemma_AssumptionsMakeValidTransition(b, asp.c, step); var primary_idx, primary_ios := lemma_ActionThatSendsStartingPhase2IsMaybeEnterPhase2(b[step], b[next_step], p_starting_phase2); var s := b[step].replicas[primary_idx].replica.proposer; var s' := b[next_step].replicas[primary_idx].replica.proposer; lemma_IfNoReplicaBeyondViewNowThenNoReplicaBeyondViewEarlier(b, asp, step, i, h.view); lemma_NoReplicaBeyondViewImpliesNoMaxBallotISent1aBeyondView(b, asp, step, h.view); assert BalLeq(s.max_ballot_i_sent_1a, h.view); if BalLt(s.max_ballot_i_sent_1a, h.view) { return; } lemma_MaxBallotISent1aHasMeAsProposer(b, asp.c, step, primary_idx); if next_step <= h.start_step { lemma_MaxBallotISent1aMonotonic(b, asp.c, next_step, h.start_step, primary_idx); assert false; } if next_step > h.start_step + 1 { lemma_MaxBallotISent1aMonotonic(b, asp.c, h.start_step + 1, step, primary_idx); assert false; } assert p_starting_phase2.msg.logTruncationPoint_2 == h.log_truncation_point; assert h.start_step + 1 <= i; lemma_OpsCompleteMonotonic(b, asp.c, h.start_step + 1, i, h.king_idx); assert false; } lemma lemma_StateSupplyToKingPrecedesBallotDuringStableView( b:Behavior, asp:AssumptionParameters, h:Phase2Params, i:int, p:RslPacket ) requires Phase2StableWithRequest(b, asp, h) requires 0 <= i requires p in b[i].environment.sentPackets requires p.src in asp.c.config.replica_ids requires p.dst == asp.c.config.replica_ids[h.king_idx] requires p.msg.RslMessage_AppStateSupply? requires NoReplicaBeyondView(b[i], h.view) ensures BalLt(p.msg.bal_state_supply, h.view) { if i == 0 { return; } lemma_ConstantsAllConsistent(b, asp.c, i-1); lemma_ConstantsAllConsistent(b, asp.c, i); lemma_AssumptionsMakeValidTransition(b, asp.c, i-1); lemma_IfNoReplicaBeyondViewNowThenNoReplicaBeyondViewEarlier(b, asp, i-1, i, h.view); if p in b[i-1].environment.sentPackets { lemma_StateSupplyToKingPrecedesBallotDuringStableView(b, asp, h, i-1, p); return; } var idx, ios := lemma_ActionThatSendsAppStateSupplyIsProcessAppStateRequest(b[i-1], b[i], p); var p_state_req := ios[0].r; lemma_StateRequestFromKingPrecedesBallotDuringStableView(b, asp, h, i-1, p_state_req); } lemma lemma_QuorumOf1bsFromPhase2StartPrecludesQuorumOf2bsFromEarlierView( b:Behavior, asp:AssumptionParameters, h:Phase2Params, i:int, q:QuorumOf2bs ) requires Phase2StableWithRequest(b, asp, h) requires 0 <= i requires LAllAcceptorsHadNoProposal(b[h.start_step + 1].replicas[h.view.proposer_id].replica.proposer.received_1b_packets, q.opn) requires LIsAfterLogTruncationPoint(q.opn, b[h.start_step + 1].replicas[h.view.proposer_id].replica.proposer.received_1b_packets) requires IsValidQuorumOf2bs(b[i], q) ensures BalLeq(h.view, q.bal) { lemma_ConstantsAllConsistent(b, asp.c, h.start_step + 1); lemma_ConstantsAllConsistent(b, asp.c, i); lemma_Received1bPacketsAreFromMaxBallotISent1a(b, asp.c, h.start_step + 1, h.view.proposer_id); var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, h.start_step, h.view.proposer_id); var received_1b_packets := b[h.start_step + 1].replicas[h.view.proposer_id].replica.proposer.received_1b_packets; var received1b_indices := lemma_GetIndicesFromPackets(received_1b_packets, asp.c.config); var overlap_idx := lemma_QuorumIndexOverlap(q.indices, received1b_indices, |asp.c.config.replica_ids|); var packet_1b :| packet_1b in received_1b_packets && packet_1b.src == asp.c.config.replica_ids[overlap_idx]; var packet_2b := q.packets[overlap_idx]; var later_step := if h.start_step + 1 <= i then i else h.start_step + 1; lemma_PacketStaysInSentPackets(b, asp.c, h.start_step + 1, later_step, packet_1b); lemma_PacketStaysInSentPackets(b, asp.c, i, later_step, packet_2b); lemma_1bMessageWithoutOpnImplicationsFor2b(b, asp.c, later_step, q.opn, packet_1b, packet_2b); } lemma lemma_StateSupplyToKingDoesNotIncludeOpn( b:Behavior, asp:AssumptionParameters, h:Phase2Params, i:int, opn:OperationNumber, p:RslPacket ) requires Phase2StableWithRequest(b, asp, h) requires 0 <= i requires 0 <= opn requires p in b[i].environment.sentPackets requires p.src in asp.c.config.replica_ids requires p.dst == asp.c.config.replica_ids[h.king_idx] requires p.msg.RslMessage_AppStateSupply? requires LIsAfterLogTruncationPoint(opn, b[h.start_step + 1].replicas[h.view.proposer_id].replica.proposer.received_1b_packets) requires LAllAcceptorsHadNoProposal(b[h.start_step + 1].replicas[h.view.proposer_id].replica.proposer.received_1b_packets, opn) requires NoReplicaBeyondView(b[i], h.view) ensures p.msg.opn_state_supply <= opn { lemma_StateSupplyToKingPrecedesBallotDuringStableView(b, asp, h, i, p); assert BalLt(p.msg.bal_state_supply, h.view); var qs := lemma_TransferredStateBasedOnChosenOperations(b, asp.c, i, p); if p.msg.opn_state_supply > opn { var q := qs[opn]; assert BalLeq(q.bal, p.msg.bal_state_supply); assert BalLt(q.bal, h.view); lemma_QuorumOf1bsFromPhase2StartPrecludesQuorumOf2bsFromEarlierView(b, asp, h, i, q); assert false; } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/LivenessProof/ViewAdvance.i.dfy ================================================ include "../DistributedSystem.i.dfy" include "Assumptions.i.dfy" include "Invariants.i.dfy" include "ViewPropagation.i.dfy" include "ViewPropagation2.i.dfy" include "WF1.i.dfy" include "../CommonProof/Constants.i.dfy" module LivenessProof__ViewAdvance_i { import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Election_i import opened LiveRSL__Environment_i import opened LiveRSL__Message_i import opened LiveRSL__Proposer_i import opened LiveRSL__Replica_i import opened LiveRSL__Types_i import opened LivenessProof__Assumptions_i import opened LivenessProof__Environment_i import opened LivenessProof__Invariants_i import opened LivenessProof__PacketHandling_i import opened LivenessProof__RealTime_i import opened LivenessProof__RoundRobin_i import opened LivenessProof__StablePeriod_i import opened LivenessProof__ViewChange_i import opened LivenessProof__ViewPropagation_i import opened LivenessProof__ViewPropagation2_i import opened LivenessProof__WF1_i import opened CommonProof__Actions_i import opened CommonProof__Constants_i import opened Temporal__Rules_i import opened Temporal__Temporal_s import opened Temporal__Time_s import opened Temporal__Time_i import opened Temporal__WF1_i import opened Environment_s import opened Collections__Maps2_s function TimeForOneReplicaToSendHeartbeat(asp:AssumptionParameters):int requires asp.host_period > 0 requires asp.max_clock_ambiguity >= 0 requires asp.c.params.heartbeat_period >= 0 ensures TimeForOneReplicaToSendHeartbeat(asp) >= 0 { asp.max_clock_ambiguity * 2 + asp.c.params.heartbeat_period + TimeToPerformGenericAction(asp) } function TimeForOneReplicaToAdvanceAnother(asp:AssumptionParameters, processing_bound:int):int requires asp.host_period > 0 requires asp.max_clock_ambiguity >= 0 requires asp.c.params.heartbeat_period >= 0 requires processing_bound >= 0 ensures TimeForOneReplicaToAdvanceAnother(asp, processing_bound) >= 0 { TimeForOneReplicaToSendHeartbeat(asp) + processing_bound } predicate HostReachedView( ps:RslState, replica_index:int, view:Ballot ) { 0 <= replica_index < |ps.replicas| && BalLeq(view, CurrentViewOfHost(ps, replica_index)) } function{:opaque} HostReachedViewTemporal(b:Behavior, replica_index:int, view:Ballot):temporal requires imaptotal(b) ensures forall i {:trigger sat(i, HostReachedViewTemporal(b, replica_index, view))} :: sat(i, HostReachedViewTemporal(b, replica_index, view)) <==> HostReachedView(b[i], replica_index, view) { stepmap(imap i :: HostReachedView(b[i], replica_index, view)) } predicate NextHeartbeatTimeInv(ps:RslState, idx:int, max_clock_ambiguity:int) { && 0 <= idx < |ps.replicas| && ps.replicas[idx].replica.nextHeartbeatTime <= ps.environment.time + max_clock_ambiguity + ps.constants.params.heartbeat_period } predicate ReplicaHasSpecificNextHeartbeatTime( ps:RslState, replica_index:int, nextHeartbeatTime:int ) { && 0 <= replica_index < |ps.replicas| && ps.replicas[replica_index].replica.nextHeartbeatTime == nextHeartbeatTime } function{:opaque} ReplicaHasSpecificNextHeartbeatTimeTemporal( b:Behavior, replica_index:int, nextHeartbeatTime:int ):temporal requires imaptotal(b) ensures forall i {:trigger sat(i, ReplicaHasSpecificNextHeartbeatTimeTemporal(b, replica_index, nextHeartbeatTime))} :: sat(i, ReplicaHasSpecificNextHeartbeatTimeTemporal(b, replica_index, nextHeartbeatTime)) <==> ReplicaHasSpecificNextHeartbeatTime(b[i], replica_index, nextHeartbeatTime) { stepmap(imap i :: ReplicaHasSpecificNextHeartbeatTime(b[i], replica_index, nextHeartbeatTime)) } predicate ReplicaSentHeartbeat( ps:RslState, ps':RslState, sender_idx:int, receiver_idx:int, p:RslPacket ) { && 0 <= receiver_idx < |ps.constants.config.replica_ids| && 0 <= sender_idx < |ps.constants.config.replica_ids| && 0 <= sender_idx < |ps.replicas| && p.dst == ps.constants.config.replica_ids[receiver_idx] && p.src == ps.constants.config.replica_ids[sender_idx] && p.msg.RslMessage_Heartbeat? && p.msg.bal_heartbeat == ps.replicas[sender_idx].replica.proposer.election_state.current_view && ps.environment.nextStep.LEnvStepHostIos? && ps.environment.nextStep.actor == p.src && LIoOpSend(p) in ps.environment.nextStep.ios && RslNext(ps, ps') && RslNextOneReplica(ps, ps', sender_idx, ps.environment.nextStep.ios) } function{:opaque} ReplicaSentHeartbeatTemporal( b:Behavior, sender_idx:int, receiver_idx:int ):temporal requires imaptotal(b) ensures forall i {:trigger sat(i, ReplicaSentHeartbeatTemporal(b, sender_idx, receiver_idx))} :: sat(i, ReplicaSentHeartbeatTemporal(b, sender_idx, receiver_idx)) <==> exists p {:trigger ReplicaSentHeartbeat(b[i], b[nextstep(i)], sender_idx, receiver_idx, p)} :: ReplicaSentHeartbeat(b[i], b[nextstep(i)], sender_idx, receiver_idx, p) { stepmap(imap i :: exists p {:trigger ReplicaSentHeartbeat(b[i], b[nextstep(i)], sender_idx, receiver_idx, p)} :: ReplicaSentHeartbeat(b[i], b[nextstep(i)], sender_idx, receiver_idx, p)) } lemma lemma_NextHeartbeatTimeInv( b:Behavior, asp:AssumptionParameters, i:int, idx:int ) requires LivenessAssumptions(b, asp) requires 0 <= i requires idx in asp.live_quorum ensures NextHeartbeatTimeInv(b[i], idx, asp.max_clock_ambiguity) { lemma_ConstantsAllConsistent(b, asp.c, i); if i > 0 { lemma_ConstantsAllConsistent(b, asp.c, i-1); lemma_AssumptionsMakeValidTransition(b, asp.c, i-1); lemma_TimeAdvancesBetween(b, asp, i-1, i); lemma_NextHeartbeatTimeInv(b, asp, i-1, idx); var ps := b[i-1]; var ps' := b[i]; var s := ps.replicas[idx].replica; var s' := ps'.replicas[idx].replica; if !NextHeartbeatTimeInv(b[i], idx, asp.max_clock_ambiguity) { assert s'.nextHeartbeatTime > s.nextHeartbeatTime; var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, i-1, idx); lemma_ClockAmbiguityLimitApplies(b, asp, i-1, idx, ios[0]); assert false; } } } lemma lemma_ReplicaEventuallySendsHeartbeatForViewWithinWF1Req1( b:Behavior, asp:AssumptionParameters, sender_idx:int, receiver_idx:int, start_step:int, nextHeartbeatTime:int ) requires LivenessAssumptions(b, asp) requires sender_idx in asp.live_quorum requires 0 <= receiver_idx < |asp.c.config.replica_ids| requires 0 <= start_step ensures var P := ReplicaHasSpecificNextHeartbeatTimeTemporal(b, sender_idx, nextHeartbeatTime); var Q := ReplicaSentHeartbeatTemporal(b, sender_idx, receiver_idx); sat(start_step, always(imply(P, or(Q, next(P))))) { var P := ReplicaHasSpecificNextHeartbeatTimeTemporal(b, sender_idx, nextHeartbeatTime); var Q := ReplicaSentHeartbeatTemporal(b, sender_idx, receiver_idx); var t := imply(P, or(Q, next(P))); forall i | start_step <= i ensures sat(i, t) { if sat(i, P) && !sat(i, Q) && !sat(i+1, P) { lemma_ConstantsAllConsistent(b, asp.c, i); lemma_ConstantsAllConsistent(b, asp.c, i+1); lemma_AssumptionsMakeValidTransition(b, asp.c, i); var ps := b[i]; var ps' := b[i+1]; var s := ps.replicas[sender_idx].replica; var s' := ps'.replicas[sender_idx].replica; var es := s.proposer.election_state; assert s'.nextHeartbeatTime != s.nextHeartbeatTime; var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, i, sender_idx); var sent_packets := ExtractSentPacketsFromIos(ios); assert |ios| > 0; assert ios[0].LIoOpReadClock?; assert LReplicaNextReadClockMaybeSendHeartbeat(s, s', SpontaneousClock(ios), sent_packets); assert ios[0].t >= s.nextHeartbeatTime; var p := LPacket(ps.constants.config.replica_ids[receiver_idx], ps.constants.config.replica_ids[sender_idx], RslMessage_Heartbeat(es.current_view, es.constants.my_index in es.current_view_suspectors, s.executor.ops_complete)); assert p in sent_packets; assert p in ps'.environment.sentPackets; assert ReplicaSentHeartbeat(ps, ps', sender_idx, receiver_idx, p); assert false; } } TemporalAlways(start_step, t); } lemma lemma_ReplicaEventuallySendsHeartbeatForViewWithinWF1Req2( b:Behavior, asp:AssumptionParameters, sender_idx:int, receiver_idx:int, start_step:int, nextHeartbeatTime:int ) requires LivenessAssumptions(b, asp) requires sender_idx in asp.live_quorum requires 0 <= receiver_idx < |asp.c.config.replica_ids| requires 0 <= start_step ensures var P := ReplicaHasSpecificNextHeartbeatTimeTemporal(b, sender_idx, nextHeartbeatTime); var Q := ReplicaSentHeartbeatTemporal(b, sender_idx, receiver_idx); var Action := ReplicaSchedule(b, sender_idx)[9]; sat(start_step, always(TemporalWF1RealTimeDelayedImmediateQReq2(P, Q, Action, nextHeartbeatTime + asp.max_clock_ambiguity, PaxosTimeMap(b)))) { var P := ReplicaHasSpecificNextHeartbeatTimeTemporal(b, sender_idx, nextHeartbeatTime); var Q := ReplicaSentHeartbeatTemporal(b, sender_idx, receiver_idx); var Action := ReplicaSchedule(b, sender_idx)[9]; var t := TemporalWF1RealTimeDelayedImmediateQReq2(P, Q, Action, nextHeartbeatTime + asp.max_clock_ambiguity, PaxosTimeMap(b)); forall i | start_step <= i ensures sat(i, t) { if sat(i, P) && sat(i, nextafter(Action, nextHeartbeatTime + asp.max_clock_ambiguity, PaxosTimeMap(b))) && !sat(i, Q) { lemma_ConstantsAllConsistent(b, asp.c, i); lemma_ConstantsAllConsistent(b, asp.c, i+1); assert SpecificClockReadingRslActionOccurs(b[i], b[i+1], LReplicaNextReadClockMaybeSendHeartbeat, sender_idx); var ios:seq :| && RslNextOneReplica(b[i], b[i+1], sender_idx, ios) && SpontaneousIos(ios, 1) && LReplicaNextReadClockMaybeSendHeartbeat(b[i].replicas[sender_idx].replica, b[i+1].replicas[sender_idx].replica, SpontaneousClock(ios), ExtractSentPacketsFromIos(ios)); lemma_ClockAmbiguityLimitApplies(b, asp, i, sender_idx, ios[0]); calc { ios[0].t; >= b[i+1].environment.time - asp.max_clock_ambiguity; >= nextHeartbeatTime; } var ps := b[i]; var ps' := b[i+1]; var s := ps.replicas[sender_idx].replica; var s' := ps'.replicas[sender_idx].replica; var es := s.proposer.election_state; var p := LPacket(ps.constants.config.replica_ids[receiver_idx], ps.constants.config.replica_ids[sender_idx], RslMessage_Heartbeat(es.current_view, es.constants.my_index in es.current_view_suspectors, s.executor.ops_complete)); assert p in ExtractSentPacketsFromIos(ios); assert p in ps'.environment.sentPackets; assert ReplicaSentHeartbeat(ps, ps', sender_idx, receiver_idx, p); assert false; } } TemporalAlways(start_step, t); } lemma lemma_ReplicaEventuallySendsHeartbeatForViewWithin( b:Behavior, asp:AssumptionParameters, processing_sync_start:int, processing_bound:int, sender_idx:int, receiver_idx:int, start_step:int ) returns ( step:int, p:RslPacket ) requires LivenessAssumptions(b, asp) requires PacketProcessingSynchronous(b, asp, processing_sync_start, processing_bound) requires 0 <= processing_sync_start <= start_step requires sender_idx in asp.live_quorum requires receiver_idx in asp.live_quorum ensures start_step <= step ensures ReplicaSentHeartbeat(b[step], b[step+1], sender_idx, receiver_idx, p) ensures b[step+1].environment.time <= b[start_step].environment.time + TimeForOneReplicaToSendHeartbeat(asp) { lemma_ConstantsAllConsistent(b, asp.c, start_step); var nextHeartbeatTime := b[start_step].replicas[sender_idx].replica.nextHeartbeatTime; var P := ReplicaHasSpecificNextHeartbeatTimeTemporal(b, sender_idx, nextHeartbeatTime); var Q := ReplicaSentHeartbeatTemporal(b, sender_idx, receiver_idx); var Action := ReplicaSchedule(b, sender_idx)[9]; var span := TimeToPerformGenericAction(asp); var timefun := PaxosTimeMap(b); lemma_ReplicaEventuallySendsHeartbeatForViewWithinWF1Req1(b, asp, sender_idx, receiver_idx, start_step, nextHeartbeatTime); lemma_ReplicaEventuallySendsHeartbeatForViewWithinWF1Req2(b, asp, sender_idx, receiver_idx, start_step, nextHeartbeatTime); lemma_ReplicaNextPerformsSubactionPeriodically(b, asp, sender_idx, 9); lemma_EstablishRequirementsForWF1RealTimeDelayed(b, asp, start_step, Action, span); assume TimeNotZeno(timefun); step := TemporalWF1RealTimeDelayedImmediateQ(start_step, P, Q, Action, span, nextHeartbeatTime + asp.max_clock_ambiguity, timefun); assert start_step <= step; p :| ReplicaSentHeartbeat(b[step], b[step+1], sender_idx, receiver_idx, p); lemma_NextHeartbeatTimeInv(b, asp, start_step, sender_idx); lemma_ConstantsAllConsistent(b, asp.c, step); lemma_AssumptionsMakeValidTransition(b, asp.c, step); lemma_ClockAmbiguityLimitApplies(b, asp, step, sender_idx, b[step].environment.nextStep.ios[0]); } lemma lemma_ProcessingHeartbeatBringsViewUp( ps:RslState, ps':RslState, p:RslPacket, idx:int, ios:seq ) requires PacketProcessedViaIos(ps, ps', p, idx, ios) requires p.msg.RslMessage_Heartbeat? requires p.src in ps.replicas[idx].replica.proposer.election_state.constants.all.config.replica_ids ensures BalLeq(p.msg.bal_heartbeat, ps'.replicas[idx].replica.proposer.election_state.current_view) { var s := ps.replicas[idx].replica; var s' := ps'.replicas[idx].replica; var es := s.proposer.election_state; var es' := s'.proposer.election_state; assert LProposerProcessHeartbeat(s.proposer, s'.proposer, p, ios[1].t); assert ElectionStateProcessHeartbeat(es, es', p, ios[1].t); lemma_BalLtProperties(); } lemma lemma_OneLiveReplicaSoonAdvancesAnother( b:Behavior, asp:AssumptionParameters, processing_sync_start:int, processing_bound:int, start_step:int, ahead_idx:int, moved_idx:int ) returns ( step:int ) requires LivenessAssumptions(b, asp) requires PacketProcessingSynchronous(b, asp, processing_sync_start, processing_bound) requires 0 <= processing_sync_start <= start_step requires ahead_idx in asp.live_quorum requires moved_idx in asp.live_quorum ensures 0 <= ahead_idx < |b[start_step].replicas| ensures 0 <= moved_idx < |b[step].replicas| ensures start_step <= step ensures BalLeq(CurrentViewOfHost(b[start_step], ahead_idx), CurrentViewOfHost(b[step], moved_idx)) ensures b[step].environment.time <= b[start_step].environment.time + TimeForOneReplicaToAdvanceAnother(asp, processing_bound) { lemma_ConstantsAllConsistent(b, asp.c, start_step); var nextHeartbeatTime := b[start_step].replicas[ahead_idx].replica.nextHeartbeatTime; var send_step, p := lemma_ReplicaEventuallySendsHeartbeatForViewWithin(b, asp, processing_sync_start, processing_bound, ahead_idx, moved_idx, start_step); lemma_ConstantsAllConsistent(b, asp.c, send_step); var view := CurrentViewOfHost(b[send_step], ahead_idx); lemma_ViewOfHostMonotonic(b, asp, ahead_idx, start_step, send_step); var s := b[send_step].replicas[ahead_idx].replica; assert BalLeq(CurrentViewOfHost(b[start_step], ahead_idx), view); assert p.msg.bal_heartbeat == view; var processing_step, ios := lemma_PacketSentToIndexProcessedByIt(b, asp, processing_sync_start, processing_bound, send_step, moved_idx, p); lemma_ConstantsAllConsistent(b, asp.c, processing_step); lemma_ProcessingHeartbeatBringsViewUp(b[processing_step], b[processing_step+1], p, moved_idx, ios); lemma_BalLtProperties(); step := processing_step + 1; } lemma lemma_OneLiveReplicaSoonAdvancesAnotherForever( b:Behavior, asp:AssumptionParameters, processing_sync_start:int, processing_bound:int, start_step:int, ahead_idx:int, moved_idx:int ) returns ( step:int ) requires LivenessAssumptions(b, asp) requires PacketProcessingSynchronous(b, asp, processing_sync_start, processing_bound) requires 0 <= processing_sync_start <= start_step requires ahead_idx in asp.live_quorum requires moved_idx in asp.live_quorum ensures 0 <= ahead_idx < |b[start_step].replicas| ensures 0 <= moved_idx < |b[step].replicas| ensures BalLeq(CurrentViewOfHost(b[start_step], ahead_idx), CurrentViewOfHost(b[step], moved_idx)) ensures start_step <= step ensures b[step].environment.time <= b[start_step].environment.time + TimeForOneReplicaToAdvanceAnother(asp, processing_bound) ensures sat(step, always(HostReachedViewTemporal(b, moved_idx, CurrentViewOfHost(b[start_step], ahead_idx)))) { step := lemma_OneLiveReplicaSoonAdvancesAnother(b, asp, processing_sync_start, processing_bound, start_step, ahead_idx, moved_idx); forall j | step <= j ensures sat(j, HostReachedViewTemporal(b, moved_idx, CurrentViewOfHost(b[start_step], ahead_idx))) { lemma_ConstantsAllConsistent(b, asp.c, j); lemma_ViewOfHostMonotonic(b, asp, moved_idx, step, j); } TemporalAlways(step, HostReachedViewTemporal(b, moved_idx, CurrentViewOfHost(b[start_step], ahead_idx))); } lemma lemma_OneLiveReplicaSoonAdvancesSomeForever( b:Behavior, asp:AssumptionParameters, processing_sync_start:int, processing_bound:int, start_step:int, ahead_idx:int, moved_indices:set ) returns ( step:int ) requires LivenessAssumptions(b, asp) requires PacketProcessingSynchronous(b, asp, processing_sync_start, processing_bound) requires 0 <= processing_sync_start <= start_step requires ahead_idx in asp.live_quorum requires moved_indices <= asp.live_quorum ensures 0 <= ahead_idx < |b[start_step].replicas| ensures start_step <= step ensures forall moved_idx :: moved_idx in moved_indices ==> sat(step, always(HostReachedViewTemporal(b, moved_idx, CurrentViewOfHost(b[start_step], ahead_idx)))) ensures b[step].environment.time <= b[start_step].environment.time + TimeForOneReplicaToAdvanceAnother(asp, processing_bound) decreases |moved_indices| { lemma_ConstantsAllConsistent(b, asp.c, start_step); if |moved_indices| == 0 { step := start_step; } else { var moved_idx :| moved_idx in moved_indices; var other_indices := moved_indices - {moved_idx}; var first_step := lemma_OneLiveReplicaSoonAdvancesSomeForever(b, asp, processing_sync_start, processing_bound, start_step, ahead_idx, other_indices); var second_step := lemma_OneLiveReplicaSoonAdvancesAnotherForever(b, asp, processing_sync_start, processing_bound, start_step, ahead_idx, moved_idx); var view := CurrentViewOfHost(b[start_step], ahead_idx); if second_step >= first_step { step := second_step; forall midx | midx in moved_indices ensures sat(step, always(HostReachedViewTemporal(b, midx, view))) { if midx != moved_idx { Lemma_AlwaysImpliesLaterAlways(first_step, step, HostReachedViewTemporal(b, midx, view)); } } } else { step := first_step; forall midx | midx in moved_indices ensures sat(step, always(HostReachedViewTemporal(b, midx, view))) { if midx == moved_idx { Lemma_AlwaysImpliesLaterAlways(second_step, step, HostReachedViewTemporal(b, midx, view)); } } } } } lemma lemma_OneLiveReplicaSoonAdvancesAllForever( b:Behavior, asp:AssumptionParameters, processing_sync_start:int, processing_bound:int, start_step:int, ahead_idx:int ) returns ( step:int ) requires LivenessAssumptions(b, asp) requires PacketProcessingSynchronous(b, asp, processing_sync_start, processing_bound) requires 0 <= processing_sync_start <= start_step requires ahead_idx in asp.live_quorum ensures 0 <= ahead_idx < |b[start_step].replicas| ensures start_step <= step ensures forall moved_idx :: moved_idx in asp.live_quorum ==> sat(step, always(HostReachedViewTemporal(b, moved_idx, CurrentViewOfHost(b[start_step], ahead_idx)))) ensures b[step].environment.time <= b[start_step].environment.time + TimeForOneReplicaToAdvanceAnother(asp, processing_bound) { step := lemma_OneLiveReplicaSoonAdvancesSomeForever(b, asp, processing_sync_start, processing_bound, start_step, ahead_idx, asp.live_quorum); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/LivenessProof/ViewChange.i.dfy ================================================ include "../DistributedSystem.i.dfy" include "Assumptions.i.dfy" include "Invariants.i.dfy" include "RequestsReceived.i.dfy" include "RoundRobin.i.dfy" include "StablePeriod.i.dfy" include "WF1.i.dfy" include "../CommonProof/Constants.i.dfy" include "../CommonProof/Actions.i.dfy" module LivenessProof__ViewChange_i { import opened LiveRSL__Constants_i import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Election_i import opened LiveRSL__Environment_i import opened LiveRSL__Proposer_i import opened LiveRSL__Replica_i import opened LiveRSL__Types_i import opened LivenessProof__Assumptions_i import opened LivenessProof__Environment_i import opened LivenessProof__Invariants_i import opened LivenessProof__PacketHandling_i import opened LivenessProof__RequestsReceived_i import opened LivenessProof__RoundRobin_i import opened LivenessProof__StablePeriod_i import opened LivenessProof__WF1_i import opened CommonProof__Constants_i import opened CommonProof__Actions_i import opened Temporal__LeadsTo_i import opened Temporal__Rules_i import opened Temporal__Temporal_s import opened Temporal__Time_s import opened Temporal__WF1_i import opened Collections__Maps2_s import opened Common__UpperBound_s datatype ViewPlus = ViewPlus(view:Ballot, suspected:bool) predicate ViewPlusLt(vp1:ViewPlus, vp2:ViewPlus) { BalLt(vp1.view, vp2.view) || (vp1.view == vp2.view && !vp1.suspected && vp2.suspected) } predicate ViewPlusLe(vp1:ViewPlus, vp2:ViewPlus) { BalLt(vp1.view, vp2.view) || (vp1.view == vp2.view && (vp1.suspected ==> vp2.suspected)) } function CurrentViewPlusOfHost( ps:RslState, replica_index:int ):ViewPlus requires 0 <= replica_index < |ps.replicas| { var es := ps.replicas[replica_index].replica.proposer.election_state; ViewPlus(es.current_view, es.constants.my_index in es.current_view_suspectors) } predicate HostInView( ps:RslState, replica_index:int, view:Ballot ) { 0 <= replica_index < |ps.replicas| && CurrentViewOfHost(ps, replica_index) == view } function{:opaque} HostInViewTemporal(b:Behavior, replica_index:int, view:Ballot):temporal requires imaptotal(b) ensures forall i {:trigger sat(i, HostInViewTemporal(b, replica_index, view))} :: sat(i, HostInViewTemporal(b, replica_index, view)) <==> HostInView(b[i], replica_index, view) { stepmap(imap i :: HostInView(b[i], replica_index, view)) } predicate HostSuspectsOrInLaterView( ps:RslState, replica_index:int, view:Ballot ) { && 0 <= replica_index < |ps.replicas| && ViewPlusLe(ViewPlus(view, true), CurrentViewPlusOfHost(ps, replica_index)) } function{:opaque} HostSuspectsOrInLaterViewTemporal(b:Behavior, replica_index:int, view:Ballot):temporal requires imaptotal(b) ensures forall i {:trigger sat(i, HostSuspectsOrInLaterViewTemporal(b, replica_index, view))} :: sat(i, HostSuspectsOrInLaterViewTemporal(b, replica_index, view)) <==> HostSuspectsOrInLaterView(b[i], replica_index, view) { stepmap(imap i :: HostSuspectsOrInLaterView(b[i], replica_index, view)) } predicate HostReadyToSuspectView( ps:RslState, idx:int, view:Ballot, req:Request, epoch_end_time:int ) { && 0 <= idx < |ps.replicas| && var es := ps.replicas[idx].replica.proposer.election_state; && es.current_view == view && !(es.constants.my_index in es.current_view_suspectors) && es.epoch_end_time == epoch_end_time && req in es.requests_received_prev_epochs } function{:opaque} HostReadyToSuspectViewTemporal( b:Behavior, idx:int, view:Ballot, req:Request, epoch_end_time:int ):temporal requires imaptotal(b) ensures forall i {:trigger sat(i, HostReadyToSuspectViewTemporal(b, idx, view, req, epoch_end_time))} :: sat(i, HostReadyToSuspectViewTemporal(b, idx, view, req, epoch_end_time)) <==> HostReadyToSuspectView(b[i], idx, view, req, epoch_end_time) { stepmap(imap i :: HostReadyToSuspectView(b[i], idx, view, req, epoch_end_time)) } lemma lemma_ViewPlusLeTransitive(vp1:ViewPlus, vp2:ViewPlus, vp3:ViewPlus) ensures ViewPlusLe(vp1, vp2) && ViewPlusLe(vp2, vp3) ==> ViewPlusLe(vp1, vp3) { lemma_BalLtProperties(); } lemma lemma_ViewPlusLeTransitiveDefinite(vp1:ViewPlus, vp2:ViewPlus, vp3:ViewPlus) requires ViewPlusLe(vp1, vp2) requires ViewPlusLe(vp2, vp3) ensures ViewPlusLe(vp1, vp3) { lemma_ViewPlusLeTransitive(vp1, vp2, vp3); } lemma lemma_ComputeSuccessorViewStrictlyIncreases(view:Ballot, constants:LConstants) requires LtUpperBound(view.seqno, constants.params.max_integer_val) ensures BalLt(view, ComputeSuccessorView(view, constants)) { lemma_BalLtProperties(); } lemma lemma_ViewPlusOfHostMonotonic( b:Behavior, asp:AssumptionParameters, idx:int, i:int, j:int ) requires LivenessAssumptions(b, asp) requires 0 <= i <= j requires 0 <= idx < |asp.c.config.replica_ids| ensures 0 <= idx < |b[i].replicas| ensures 0 <= idx < |b[j].replicas| ensures ViewPlusLe(CurrentViewPlusOfHost(b[i], idx), CurrentViewPlusOfHost(b[j], idx)) decreases j-i { lemma_ConstantsAllConsistent(b, asp.c, i); lemma_ConstantsAllConsistent(b, asp.c, j); lemma_BalLtProperties(); var vp1 := CurrentViewPlusOfHost(b[i], idx); var vp2 := CurrentViewPlusOfHost(b[j], idx); if j == i + 1 { lemma_AssumptionsMakeValidTransition(b, asp.c, i); if !ViewPlusLe(vp1, vp2) { var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, i, idx); lemma_OverflowProtectionNotUsedForReplica(b, asp, i, idx); assert false; } } else if j > i + 1 { lemma_ViewPlusOfHostMonotonic(b, asp, idx, i, i+1); lemma_ViewPlusOfHostMonotonic(b, asp, idx, i+1, j); lemma_ViewPlusLeTransitive(vp1, CurrentViewPlusOfHost(b[i+1], idx), vp2); } } lemma lemma_ViewOfHostMonotonic( b:Behavior, asp:AssumptionParameters, idx:int, i:int, j:int ) requires LivenessAssumptions(b, asp) requires 0 <= i <= j requires 0 <= idx < |asp.c.config.replica_ids| ensures 0 <= idx < |b[i].replicas| ensures 0 <= idx < |b[j].replicas| ensures BalLeq(CurrentViewOfHost(b[i], idx), CurrentViewOfHost(b[j], idx)) { lemma_ViewPlusOfHostMonotonic(b, asp, idx, i, j); } lemma lemma_HostReadyToSuspectViewEventuallyDoesWF1Req1( b:Behavior, asp:AssumptionParameters, idx:int, view:Ballot, epoch_end_time:int, start_step:int ) requires LivenessAssumptions(b, asp) requires idx in asp.live_quorum requires 0 <= start_step requires sat(start_step, always(RequestInRequestsReceivedPrevEpochsTemporal(b, asp.persistent_request, idx))) ensures var P := HostReadyToSuspectViewTemporal(b, idx, view, asp.persistent_request, epoch_end_time); var Q := HostSuspectsOrInLaterViewTemporal(b, idx, view); sat(start_step, always(TemporalWF1Req1(P, Q))) { var P := HostReadyToSuspectViewTemporal(b, idx, view, asp.persistent_request, epoch_end_time); var Q := HostSuspectsOrInLaterViewTemporal(b, idx, view); forall i | start_step <= i ensures sat(i, TemporalWF1Req1(P, Q)) { if sat(i, P) && !sat(i, Q) && !sat(i+1, P) && !sat(i+1, Q) { lemma_ConstantsAllConsistent(b, asp.c, i); lemma_ConstantsAllConsistent(b, asp.c, i+1); var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, i, idx); lemma_OverflowProtectionNotUsedForReplica(b, asp, i, idx); TemporalDeduceFromAlways(start_step, i+1, RequestInRequestsReceivedPrevEpochsTemporal(b, asp.persistent_request, idx)); assert false; } } TemporalAlways(start_step, TemporalWF1Req1(P, Q)); } lemma lemma_HostReadyToSuspectViewEventuallyDoesWF1Req2( b:Behavior, asp:AssumptionParameters, idx:int, view:Ballot, epoch_end_time:int, start_step:int ) requires LivenessAssumptions(b, asp) requires idx in asp.live_quorum requires asp.synchrony_start <= start_step requires sat(start_step, always(RequestInRequestsReceivedPrevEpochsTemporal(b, asp.persistent_request, idx))) ensures var P := HostReadyToSuspectViewTemporal(b, idx, view, asp.persistent_request, epoch_end_time); var Q := HostSuspectsOrInLaterViewTemporal(b, idx, view); var Action := ReplicaSchedule(b, idx)[7]; sat(start_step, always(TemporalWF1RealTimeDelayedReq2(P, Q, Action, epoch_end_time + asp.max_clock_ambiguity, PaxosTimeMap(b)))) { var epochEndTimePlus := epoch_end_time + asp.max_clock_ambiguity; var P := HostReadyToSuspectViewTemporal(b, idx, view, asp.persistent_request, epoch_end_time); var Q := HostSuspectsOrInLaterViewTemporal(b, idx, view); var Action := ReplicaSchedule(b, idx)[7]; var x := TemporalWF1RealTimeDelayedReq2(P, Q, Action, epochEndTimePlus, PaxosTimeMap(b)); forall i | start_step <= i ensures sat(i, x) { if sat(i, P) && sat(i, nextafter(Action, epochEndTimePlus, PaxosTimeMap(b))) && !sat(i, Q) && !sat(i+1, Q) { lemma_ConstantsAllConsistent(b, asp.c, i); lemma_ConstantsAllConsistent(b, asp.c, i+1); assert SpecificClockReadingRslActionOccurs(b[i], b[i+1], LReplicaNextReadClockCheckForViewTimeout, idx); var ios:seq :| && RslNextOneReplica(b[i], b[i+1], idx, ios) && SpontaneousIos(ios, 1) && LReplicaNextReadClockCheckForViewTimeout(b[i].replicas[idx].replica, b[i+1].replicas[idx].replica, SpontaneousClock(ios), ExtractSentPacketsFromIos(ios)); lemma_ClockAmbiguityLimitApplies(b, asp, i, idx, ios[0]); lemma_OverflowProtectionNotUsedForReplica(b, asp, i, idx); var es := b[i].replicas[idx].replica.proposer.election_state; var es' := b[i+1].replicas[idx].replica.proposer.election_state; assert ElectionStateCheckForViewTimeout(es, es', ios[0].t); assert es' == es.(current_view_suspectors := es.current_view_suspectors + {es.constants.my_index}, epoch_end_time := UpperBoundedAddition(ios[0].t, es.epoch_length, es.constants.all.params.max_integer_val), requests_received_prev_epochs := BoundRequestSequence(es.requests_received_prev_epochs + es.requests_received_this_epoch, es.constants.all.params.max_integer_val), requests_received_this_epoch := []); assert false; } } TemporalAlways(start_step, x); } lemma lemma_HostReadyToSuspectViewEventuallyDoes( b:Behavior, asp:AssumptionParameters, idx:int, view:Ballot, epoch_end_time:int, start_step:int ) requires LivenessAssumptions(b, asp) requires idx in asp.live_quorum requires asp.synchrony_start <= start_step requires sat(start_step, always(RequestInRequestsReceivedPrevEpochsTemporal(b, asp.persistent_request, idx))) ensures var P := HostReadyToSuspectViewTemporal(b, idx, view, asp.persistent_request, epoch_end_time); var Q := HostSuspectsOrInLaterViewTemporal(b, idx, view); sat(start_step, leadsto(P, Q)) { var epochEndTimePlus := epoch_end_time + asp.max_clock_ambiguity; var P := HostReadyToSuspectViewTemporal(b, idx, view, asp.persistent_request, epoch_end_time); var Q := HostSuspectsOrInLaterViewTemporal(b, idx, view); var Action := ReplicaSchedule(b, idx)[7]; forall i | start_step <= i ensures sat(i, imply(P, eventual(Q))) { if sat(i, P) { Lemma_AlwaysImpliesLaterAlways(start_step, i, RequestInRequestsReceivedPrevEpochsTemporal(b, asp.persistent_request, idx)); lemma_HostReadyToSuspectViewEventuallyDoesWF1Req1(b, asp, idx, view, epoch_end_time, i); lemma_HostReadyToSuspectViewEventuallyDoesWF1Req2(b, asp, idx, view, epoch_end_time, i); lemma_ReplicaNextPerformsSubactionPeriodically(b, asp, idx, 7); lemma_EstablishRequirementsForWF1RealTimeDelayed(b, asp, i, Action, TimeToPerformGenericAction(asp)); var step := TemporalWF1RealTimeDelayed(i, P, Q, Action, TimeToPerformGenericAction(asp), epochEndTimePlus, PaxosTimeMap(b)); TemporalEventually(i, step, Q); } } TemporalAlways(start_step, imply(P, eventual(Q))); } lemma lemma_ReplicaEventuallySuspectsViewOrIsInDifferentView( b:Behavior, asp:AssumptionParameters, processing_sync_start:int, processing_bound:int, idx:int, start_step:int ) returns ( step:int ) requires LivenessAssumptions(b, asp) requires PacketProcessingSynchronous(b, asp, processing_sync_start, processing_bound) requires idx in asp.live_quorum requires processing_sync_start <= start_step requires 0 <= idx < |b[start_step].replicas| ensures start_step <= step ensures HostSuspectsOrInLaterView(b[step], idx, CurrentViewOfHost(b[start_step], idx)) ensures sat(step, always(RequestInRequestsReceivedPrevEpochsTemporal(b, asp.persistent_request, idx))) { var initialView := CurrentViewOfHost(b[start_step], idx); var i := lemma_EventuallyPersistentRequestAlwaysInRequestsReceivedPrevEpochs(b, asp, processing_sync_start, processing_bound, idx); if i < start_step { Lemma_AlwaysImpliesLaterAlways(i, start_step, RequestInRequestsReceivedPrevEpochsTemporal(b, asp.persistent_request, idx)); i := start_step; } assert sat(i, always(RequestInRequestsReceivedPrevEpochsTemporal(b, asp.persistent_request, idx))); lemma_ConstantsAllConsistent(b, asp.c, i); lemma_ViewPlusOfHostMonotonic(b, asp, idx, start_step, i); if HostSuspectsOrInLaterView(b[i], idx, initialView) { TemporalEventually(start_step, i, HostSuspectsOrInLaterViewTemporal(b, idx, initialView)); step := i; } else { var epoch_end_time := b[i].replicas[idx].replica.proposer.election_state.epoch_end_time; var P := HostReadyToSuspectViewTemporal(b, idx, initialView, asp.persistent_request, epoch_end_time); var Q := HostSuspectsOrInLaterViewTemporal(b, idx, initialView); lemma_HostReadyToSuspectViewEventuallyDoes(b, asp, idx, initialView, epoch_end_time, i); TemporalDeduceFromAlways(i, i, RequestInRequestsReceivedPrevEpochsTemporal(b, asp.persistent_request, idx)); assert HostReadyToSuspectView(b[i], idx, initialView, asp.persistent_request, epoch_end_time); TemporalDeduceFromAlways(i, i, imply(P, eventual(Q))); step := TemporalDeduceFromEventual(i, Q); Lemma_AlwaysImpliesLaterAlways(i, step, RequestInRequestsReceivedPrevEpochsTemporal(b, asp.persistent_request, idx)); } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/LivenessProof/ViewPersistence.i.dfy ================================================ include "Assumptions.i.dfy" include "Invariants.i.dfy" include "EpochLength.i.dfy" include "ViewChange.i.dfy" include "ViewPropagation.i.dfy" include "ViewPropagation2.i.dfy" include "ViewSuspicion.i.dfy" include "MaxBallotISent1a.i.dfy" include "StablePeriod.i.dfy" include "../CommonProof/CanonicalizeBallot.i.dfy" include "../CommonProof/MaxBallotISent1a.i.dfy" include "../CommonProof/Actions.i.dfy" include "../../../Common/Framework/EnvironmentSynchronyLemmas.i.dfy" include "../../../../Libraries/Math/mul.i.dfy" module LivenessProof__ViewPersistence_i { import opened LiveRSL__Configuration_i import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Election_i import opened LiveRSL__Environment_i import opened LiveRSL__Replica_i import opened LiveRSL__Types_i import opened LivenessProof__Assumptions_i import opened LivenessProof__Environment_i import opened LivenessProof__EpochLength_i import opened LivenessProof__Invariants_i import opened LivenessProof__PacketHandling_i import opened LivenessProof__RealTime_i import opened LivenessProof__ViewChange_i import opened LivenessProof__ViewPropagation_i import opened LivenessProof__ViewPropagation2_i import opened LivenessProof__ViewSuspicion_i import opened LivenessProof__MaxBallotISent1a_i import opened LivenessProof__RequestsReceived_i import opened LivenessProof__StablePeriod_i import opened CommonProof__Actions_i import opened CommonProof__CanonicalizeBallot_i import opened CommonProof__Constants_i import opened CommonProof__MaxBallotISent1a_i import opened CommonProof__Quorum_i import opened Common__UpperBound_s import opened Liveness__EnvironmentSynchronyLemmas_i import opened Math__mul_i import opened Temporal__Induction_i import opened Temporal__Rules_i import opened Temporal__Temporal_s import opened Temporal__Time_s import opened Temporal__Time_i import opened Collections__Maps2_s import opened Collections__Sets_i import opened Environment_s import opened EnvironmentSynchrony_s predicate NoLiveReplicaSuspectsViewBefore( ps:RslState, live_quorum:set, view:Ballot, endTime:int, max_clock_ambiguity:int ) { ps.environment.time < endTime - max_clock_ambiguity ==> forall idx :: idx in live_quorum ==> && 0 <= idx < |ps.replicas| && var es := ps.replicas[idx].replica.proposer.election_state; (|| BalLt(es.current_view, view) || (&& es.current_view == view && es.constants.my_index !in es.current_view_suspectors && es.epoch_end_time >= endTime)) } function{:opaque} NoLiveReplicaSuspectsViewBeforeTemporal( b:Behavior, live_quorum:set, view:Ballot, endTime:int, max_clock_ambiguity:int ):temporal requires imaptotal(b) ensures forall i {:trigger sat(i, NoLiveReplicaSuspectsViewBeforeTemporal(b, live_quorum, view, endTime, max_clock_ambiguity))} :: sat(i, NoLiveReplicaSuspectsViewBeforeTemporal(b, live_quorum, view, endTime, max_clock_ambiguity)) <==> NoLiveReplicaSuspectsViewBefore(b[i], live_quorum, view, endTime, max_clock_ambiguity) { stepmap(imap i :: NoLiveReplicaSuspectsViewBefore(b[i], live_quorum, view, endTime, max_clock_ambiguity)) } lemma {:timeLimitMultiplier 2} lemma_NoLiveReplicaSuspectsViewBeforeStableOneStep( b:Behavior, asp:AssumptionParameters, i:int, view:Ballot, minEpochLength:int, endTime:int ) requires LivenessAssumptions(b, asp) requires 0 <= i requires IsValidBallot(view, asp.c) requires minEpochLength >= 0 requires b[i].environment.time >= endTime - minEpochLength - asp.max_clock_ambiguity requires NoLiveReplicaSuspectsViewBefore(b[i], asp.live_quorum, view, endTime, asp.max_clock_ambiguity) requires forall idx :: idx in asp.live_quorum ==> EpochLengthEqualOrGreater(b[i], idx, minEpochLength + asp.max_clock_ambiguity * 2) ensures NoLiveReplicaSuspectsViewBefore(b[i+1], asp.live_quorum, view, endTime, asp.max_clock_ambiguity) { lemma_AssumptionsMakeValidTransition(b, asp.c, i); lemma_ConstantsAllConsistent(b, asp.c, i); lemma_ConstantsAllConsistent(b, asp.c, i+1); var ps := b[i]; var ps' := b[i+1]; if !NoLiveReplicaSuspectsViewBefore(b[i+1], asp.live_quorum, view, endTime, asp.max_clock_ambiguity) { lemma_NoOneCanExceedViewUntilAQuorumMemberSuspectsIt(b, asp, i, view); assert AllQuorumMembersViewPlusLe(ps, asp.live_quorum, ViewPlus(view, false)); assert AllReplicasViewPlusLe(ps, ViewPlus(view, true)); assert ps.environment.time < endTime - asp.max_clock_ambiguity; forall idx | idx in asp.live_quorum ensures var es' := ps'.replicas[idx].replica.proposer.election_state; || BalLt(es'.current_view, view) || (&& es'.current_view == view && es'.constants.my_index !in es'.current_view_suspectors && es'.epoch_end_time >= endTime) { var s := ps.replicas[idx].replica; var s' := ps'.replicas[idx].replica; var es := s.proposer.election_state; var es' := s'.proposer.election_state; if es' != es && !BalLt(es'.current_view, view) { lemma_ViewOfHostMonotonic(b, asp, idx, i, i+1); lemma_IsValidBallot(b, asp, i, idx); lemma_IsValidBallot(b, asp, i+1, idx); lemma_ViewInfoStateInvHolds(b, asp, i); assert EpochLengthEqualOrGreater(ps, idx, minEpochLength); lemma_OverflowProtectionNotUsedForReplica(b, asp, i, idx); var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, i, idx); var sent_packets := ExtractSentPacketsFromIos(ios); if |ios| > 1 && ios[1].LIoOpReadClock? && LReplicaNextProcessHeartbeat(s, s', ios[0].r, ios[1].t, sent_packets) && ios[0].r.src in asp.c.config.replica_ids { var p := ios[0].r; var oid := p.src; var sender_index := GetReplicaIndex(oid, es.constants.all.config); lemma_PacketProcessedImpliesPacketSent(ps, ps', idx, ios, p); lemma_ClockAmbiguityLimitApplies(b, asp, i, idx, ios[1]); assert p in ps.environment.sentPackets; assert ViewInfoConsistent(ps, sender_index); assert ViewInfoInPacketConsistent(ps, sender_index, p); assert ViewPlusLe(CurrentViewPlusOfHost(ps, sender_index), ViewPlus(view, true)); assert es'.current_view == view; assert es'.constants.my_index !in es'.current_view_suspectors; assert es'.epoch_end_time >= endTime; } else if LReplicaNextReadClockCheckForQuorumOfViewSuspicions(s, s', SpontaneousClock(ios), sent_packets) { assert es'.current_view == ComputeSuccessorView(es.current_view, asp.c); lemma_NothingBetweenViewAndSuccessor(es.current_view, view, asp.c); if es.current_view == view { assert |es.current_view_suspectors| >= LMinQuorumSize(es.constants.all.config); lemma_AllSuspectorsValidStateInvHolds(b, asp, i); var live_suspector_idx := lemma_QuorumIndexOverlap(es.current_view_suspectors, asp.live_quorum, |asp.c.config.replica_ids|); assert 0 <= live_suspector_idx < |ps.replicas|; assert ViewInfoConsistent(ps, live_suspector_idx); assert ViewInfoInObserverConsistent(ps, live_suspector_idx, idx); lemma_ViewPlusLeTransitiveDefinite(ViewPlus(view, true), CurrentViewPlusOfHost(ps, live_suspector_idx), ViewPlus(view, false)); assert false; } lemma_ClockAmbiguityLimitApplies(b, asp, i, idx, ios[0]); } else if SpontaneousIos(ios, 1) { lemma_ClockAmbiguityLimitApplies(b, asp, i, idx, ios[0]); assert es'.current_view == view; assert es'.constants.my_index !in es'.current_view_suspectors; assert es'.epoch_end_time >= endTime; } } } } } lemma lemma_NoLiveReplicaSuspectsViewBeforeStable( b:Behavior, asp:AssumptionParameters, i:int, view:Ballot, minEpochLength:int, endTime:int ) requires LivenessAssumptions(b, asp) requires 0 <= i requires IsValidBallot(view, asp.c) requires minEpochLength >= 0 requires b[i].environment.time >= endTime - minEpochLength - asp.max_clock_ambiguity requires NoLiveReplicaSuspectsViewBefore(b[i], asp.live_quorum, view, endTime, asp.max_clock_ambiguity) requires forall idx :: idx in asp.live_quorum ==> sat(i, always(EpochLengthEqualOrGreaterTemporal(b, idx, minEpochLength + asp.max_clock_ambiguity * 2))) ensures sat(i, always(NoLiveReplicaSuspectsViewBeforeTemporal(b, asp.live_quorum, view, endTime, asp.max_clock_ambiguity))) { var x := NoLiveReplicaSuspectsViewBeforeTemporal(b, asp.live_quorum, view, endTime, asp.max_clock_ambiguity); forall j | i <= j ensures sat(j, imply(x, next(x))) { if sat(j, x) { forall idx | idx in asp.live_quorum ensures EpochLengthEqualOrGreater(b[j], idx, minEpochLength + asp.max_clock_ambiguity * 2) { TemporalDeduceFromAlways(i, j, EpochLengthEqualOrGreaterTemporal(b, idx, minEpochLength + asp.max_clock_ambiguity * 2)); } lemma_TimeAdvancesBetween(b, asp, i, j); lemma_NoLiveReplicaSuspectsViewBeforeStableOneStep(b, asp, j, view, minEpochLength, endTime); } reveal imply(); reveal next(); } TemporalInductionNext(i, x); } lemma lemma_LaterViewWithPrimaryExists( ps:RslState, primary_idx:int, max_integer_val:UpperBound ) returns ( view:Ballot ) requires ConstantsAllConsistentInv(ps) requires 0 <= primary_idx < |ps.replicas| requires forall idx :: 0 <= idx < |ps.replicas| ==> LtUpperBound(CurrentViewOfHost(ps, idx).seqno, max_integer_val) ensures view.proposer_id == primary_idx ensures LeqUpperBound(view.seqno, max_integer_val) ensures forall idx :: 0 <= idx < |ps.replicas| ==> BalLt(CurrentViewOfHost(ps, idx), view) { var ballot_seqnos := set idx | 0 <= idx < |ps.constants.config.replica_ids| :: CurrentViewOfHost(ps, idx).seqno; assert CurrentViewOfHost(ps, primary_idx).seqno in ballot_seqnos; var highest_seqno := intsetmax(ballot_seqnos); var highest_idx :| 0 <= highest_idx < |ps.constants.config.replica_ids| && CurrentViewOfHost(ps, highest_idx).seqno == highest_seqno; assert LtUpperBound(highest_seqno, max_integer_val); var next_seqno := highest_seqno + 1; view := Ballot(next_seqno, primary_idx); assert IsValidBallot(view, ps.constants); forall idx | 0 <= idx < |ps.constants.config.replica_ids| ensures BalLt(CurrentViewOfHost(ps, idx), view) { assert CurrentViewOfHost(ps, idx).seqno in ballot_seqnos; } } predicate SomeReplicaInLiveQuorumReachedView( ps:RslState, live_quorum:set, view:Ballot ) { exists idx :: idx in live_quorum && 0 <= idx < |ps.replicas| && BalLeq(view, CurrentViewOfHost(ps, idx)) } function{:opaque} SomeReplicaInLiveQuorumReachedViewTemporal( b:Behavior, live_quorum:set, view:Ballot ):temporal requires imaptotal(b) ensures forall i{:trigger sat(i, SomeReplicaInLiveQuorumReachedViewTemporal(b, live_quorum, view))} :: sat(i, SomeReplicaInLiveQuorumReachedViewTemporal(b, live_quorum, view)) <==> SomeReplicaInLiveQuorumReachedView(b[i], live_quorum, view) { stepmap(imap i :: SomeReplicaInLiveQuorumReachedView(b[i], live_quorum, view)) } lemma lemma_FirstStepWithLiveReplicaInQuorumHasNoLiveReplicaSuspectingBeforeIfHeartbeat( b:Behavior, asp:AssumptionParameters, view:Ballot, duration:int, step:int, ios:seq, ahead_idx:int ) requires LivenessAssumptions(b, asp) requires duration > 0 requires 1 <= step requires view.proposer_id in asp.live_quorum requires forall idx :: idx in asp.live_quorum ==> sat(step-1, EpochLengthEqualOrGreaterTemporal(b, idx, duration + asp.max_clock_ambiguity * 2)) requires ahead_idx in asp.live_quorum requires 0 <= ahead_idx < |b[step].replicas| requires BalLeq(view, CurrentViewOfHost(b[step], ahead_idx)) requires !SomeReplicaInLiveQuorumReachedView(b[step-1], asp.live_quorum, view) requires |ios| > 1 requires ios[0].LIoOpReceive? requires ios[0].r.msg.RslMessage_Heartbeat? requires ios[1].LIoOpReadClock? requires RslNextOneReplica(b[step-1], b[step], ahead_idx, ios) requires LReplicaNextProcessHeartbeat(b[step-1].replicas[ahead_idx].replica, b[step].replicas[ahead_idx].replica, ios[0].r, ios[1].t, ExtractSentPacketsFromIos(ios)) ensures var es' := b[step].replicas[ahead_idx].replica.proposer.election_state; && es'.current_view == view && es'.constants.my_index !in es'.current_view_suspectors && es'.epoch_end_time >= b[step].environment.time + duration + asp.max_clock_ambiguity { var ps := b[step-1]; var ps' := b[step]; var s := ps.replicas[ahead_idx].replica; var s' := ps'.replicas[ahead_idx].replica; var es := s.proposer.election_state; var es' := s'.proposer.election_state; lemma_ViewOfHostMonotonic(b, asp, ahead_idx, step-1, step); lemma_IsValidBallot(b, asp, step-1, ahead_idx); lemma_IsValidBallot(b, asp, step, ahead_idx); lemma_OverflowProtectionNotUsedForReplica(b, asp, step-1, ahead_idx); lemma_OverflowProtectionNotUsedForReplica(b, asp, step, ahead_idx); assert EpochLengthEqualOrGreater(ps, ahead_idx, duration); lemma_ConstantsAllConsistent(b, asp.c, step-1); lemma_ConstantsAllConsistent(b, asp.c, step); lemma_AssumptionsMakeValidTransition(b, asp.c, step-1); var p := ios[0].r; var oid := p.src; var sender_index := GetReplicaIndex(oid, es.constants.all.config); lemma_PacketProcessedImpliesPacketSent(ps, ps', ahead_idx, ios, p); assert p in ps.environment.sentPackets; lemma_ViewInfoStateInvHolds(b, asp, step-1); assert ViewInfoConsistent(ps, sender_index); assert ViewInfoInPacketConsistent(ps, sender_index, p); assert ViewPlusLe(ViewPlus(p.msg.bal_heartbeat, p.msg.suspicious), CurrentViewPlusOfHost(ps, sender_index)); lemma_NoOneCanExceedViewUntilAQuorumMemberSuspectsIt(b, asp, step-1, view); assert AllQuorumMembersViewPlusLe(ps, asp.live_quorum, ViewPlus(view, false)); assert AllReplicasViewPlusLe(ps, ViewPlus(view, true)); assert ViewPlusLe(CurrentViewPlusOfHost(ps, sender_index), ViewPlus(view, true)); lemma_BalLtProperties(); lemma_ViewPlusLeTransitiveDefinite(ViewPlus(p.msg.bal_heartbeat, p.msg.suspicious), CurrentViewPlusOfHost(ps, sender_index), ViewPlus(view, true)); assert BalLeq(p.msg.bal_heartbeat, view); lemma_ClockAmbiguityLimitApplies(b, asp, step-1, ahead_idx, ios[1]); } lemma{:timeLimitMultiplier 2} lemma_FirstStepWithLiveReplicaInQuorumHasNoLiveReplicaSuspectingBefore( b:Behavior, asp:AssumptionParameters, view:Ballot, duration:int, step:int ) requires LivenessAssumptions(b, asp) requires duration > 0 requires 1 <= step requires view.proposer_id in asp.live_quorum requires forall idx :: idx in asp.live_quorum ==> sat(step-1, EpochLengthEqualOrGreaterTemporal(b, idx, duration + asp.max_clock_ambiguity * 2)) requires !SomeReplicaInLiveQuorumReachedView(b[step-1], asp.live_quorum, view) requires SomeReplicaInLiveQuorumReachedView(b[step], asp.live_quorum, view) ensures NoLiveReplicaSuspectsViewBefore(b[step], asp.live_quorum, view, b[step].environment.time + duration + asp.max_clock_ambiguity, asp.max_clock_ambiguity) { var ps := b[step-1]; var ps' := b[step]; var ahead_idx :| ahead_idx in asp.live_quorum && 0 <= ahead_idx < |ps'.replicas| && BalLeq(view, CurrentViewOfHost(ps', ahead_idx)); lemma_ConstantsAllConsistent(b, asp.c, step-1); lemma_ConstantsAllConsistent(b, asp.c, step); lemma_AssumptionsMakeValidTransition(b, asp.c, step-1); var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, step-1, ahead_idx); forall idx | idx in asp.live_quorum ensures var es' := ps'.replicas[idx].replica.proposer.election_state; || BalLt(es'.current_view, view) || (&& es'.current_view == view && es'.constants.my_index !in es'.current_view_suspectors && es'.epoch_end_time >= ps'.environment.time + duration + asp.max_clock_ambiguity) { var s := ps.replicas[idx].replica; var s' := ps'.replicas[idx].replica; var es := s.proposer.election_state; var es' := s'.proposer.election_state; lemma_ViewOfHostMonotonic(b, asp, idx, step-1, step); if idx != ahead_idx { assert BalLt(es'.current_view, view); } else { lemma_IsValidBallot(b, asp, step-1, idx); lemma_IsValidBallot(b, asp, step, idx); lemma_OverflowProtectionNotUsedForReplica(b, asp, step-1, idx); lemma_OverflowProtectionNotUsedForReplica(b, asp, step, idx); assert EpochLengthEqualOrGreater(ps, idx, duration); var ios2 := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, step-1, idx); var sent_packets := ExtractSentPacketsFromIos(ios2); if |ios2| > 1 && ios2[1].LIoOpReadClock? && LReplicaNextProcessHeartbeat(s, s', ios2[0].r, ios2[1].t, sent_packets) && ios2[0].r.src in asp.c.config.replica_ids { lemma_FirstStepWithLiveReplicaInQuorumHasNoLiveReplicaSuspectingBeforeIfHeartbeat(b, asp, view, duration, step, ios2, ahead_idx); lemma_ClockAmbiguityLimitApplies(b, asp, step-1, idx, ios2[1]); } else if LReplicaNextReadClockCheckForQuorumOfViewSuspicions(s, s', SpontaneousClock(ios2), sent_packets) { assert es'.current_view == ComputeSuccessorView(es.current_view, asp.c); lemma_NothingBetweenViewAndSuccessor(es.current_view, view, asp.c); lemma_ClockAmbiguityLimitApplies(b, asp, step-1, idx, ios2[0]); } } } } lemma lemma_FirstStepWithLiveReplicaInQuorumHasAllMaxBallot1aBeforeView( b:Behavior, asp:AssumptionParameters, view:Ballot, duration:int, step:int ) requires LivenessAssumptions(b, asp) requires duration > 0 requires 1 <= step requires view.proposer_id in asp.live_quorum requires !SomeReplicaInLiveQuorumReachedView(b[step-1], asp.live_quorum, view) requires SomeReplicaInLiveQuorumReachedView(b[step], asp.live_quorum, view) ensures forall idx :: 0 <= idx < |b[step].replicas| ==> BalLt(b[step].replicas[idx].replica.proposer.max_ballot_i_sent_1a, view) { var ps := b[step-1]; var ps' := b[step]; var ahead_idx :| ahead_idx in asp.live_quorum && 0 <= ahead_idx < |ps'.replicas| && BalLeq(view, CurrentViewOfHost(ps', ahead_idx)); lemma_ConstantsAllConsistent(b, asp.c, step-1); lemma_ConstantsAllConsistent(b, asp.c, step); lemma_AssumptionsMakeValidTransition(b, asp.c, step-1); var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, step-1, ahead_idx); forall idx | 0 <= idx < |b[step].replicas| ensures BalLt(b[step].replicas[idx].replica.proposer.max_ballot_i_sent_1a, view) { var s := b[step-1].replicas[idx].replica.proposer; var s' := b[step].replicas[idx].replica.proposer; lemma_BalLtProperties(); lemma_MaxBallotISent1aLeqView(b, asp, step-1, idx); assert BalLeq(s.max_ballot_i_sent_1a, s.election_state.current_view); if idx == ahead_idx || idx in asp.live_quorum { assert BalLt(s.election_state.current_view, view); assert BalLt(s.max_ballot_i_sent_1a, view); assert s'.max_ballot_i_sent_1a == s.max_ballot_i_sent_1a; } else { lemma_NoOneCanExceedViewUntilAQuorumMemberSuspectsIt(b, asp, step-1, view); assert AllQuorumMembersViewPlusLe(b[step-1], asp.live_quorum, ViewPlus(view, false)); assert AllReplicasViewPlusLe(b[step-1], ViewPlus(view, true)); assert ViewPlusLe(CurrentViewPlusOfHost(b[step-1], idx), ViewPlus(view, true)); assert BalLeq(s.election_state.current_view, view); lemma_MaxBallotISent1aHasMeAsProposer(b, asp.c, step-1, idx); assert s.max_ballot_i_sent_1a.proposer_id != view.proposer_id; assert BalLt(s.max_ballot_i_sent_1a, view); } } } lemma lemma_EventuallyViewStable( b:Behavior, asp:AssumptionParameters, processing_sync_start:int, processing_bound:int, primary_idx:int, duration:int ) returns ( view:Ballot, step:int ) requires LivenessAssumptions(b, asp) requires PacketProcessingSynchronous(b, asp, processing_sync_start, processing_bound) requires primary_idx in asp.live_quorum requires duration > 0 ensures processing_sync_start <= step ensures view.proposer_id == primary_idx ensures LeqUpperBound(view.seqno, asp.c.params.max_integer_val) ensures SomeReplicaInLiveQuorumReachedView(b[step], asp.live_quorum, view) ensures forall idx :: 0 <= idx < |b[step].replicas| ==> BalLt(b[step].replicas[idx].replica.proposer.max_ballot_i_sent_1a, view) ensures sat(step, always(NoLiveReplicaSuspectsViewBeforeTemporal(b, asp.live_quorum, view, b[step].environment.time + duration + asp.max_clock_ambiguity, asp.max_clock_ambiguity))) { var first_step := lemma_EpochLengthForAllEventuallyReaches(b, asp, processing_sync_start, processing_bound, duration + asp.max_clock_ambiguity * 2); lemma_ConstantsAllConsistent(b, asp.c, first_step); forall idx | 0 <= idx < |b[first_step].replicas| ensures LtUpperBound(CurrentViewOfHost(b[first_step], idx).seqno, asp.c.params.max_integer_val) { lemma_OverflowProtectionNotUsedForReplica(b, asp, first_step, idx); } view := lemma_LaterViewWithPrimaryExists(b[first_step], primary_idx, asp.c.params.max_integer_val); assert !sat(first_step, SomeReplicaInLiveQuorumReachedViewTemporal(b, asp.live_quorum, view)); lemma_IfPacketProcessingSynchronousThenAlways(b, asp, processing_sync_start, first_step, processing_bound); var second_step, replica_index := lemma_SomeReplicaInLiveQuorumReachesView(b, asp, first_step, processing_bound, view); assert sat(second_step, SomeReplicaInLiveQuorumReachedViewTemporal(b, asp.live_quorum, view)); TemporalEventually(first_step, second_step, SomeReplicaInLiveQuorumReachedViewTemporal(b, asp.live_quorum, view)); step := earliestStep(first_step, SomeReplicaInLiveQuorumReachedViewTemporal(b, asp.live_quorum, view)); assert first_step <= step - 1 < step; assert !sat(step-1, SomeReplicaInLiveQuorumReachedViewTemporal(b, asp.live_quorum, view)); var endTime := b[step].environment.time + duration + asp.max_clock_ambiguity; forall idx | idx in asp.live_quorum ensures sat(step, always(EpochLengthEqualOrGreaterTemporal(b, idx, duration + asp.max_clock_ambiguity * 2))) ensures sat(step-1, EpochLengthEqualOrGreaterTemporal(b, idx, duration + asp.max_clock_ambiguity * 2)) { TemporalDeduceFromAlways(first_step, step-1, EpochLengthEqualOrGreaterTemporal(b, idx, duration + asp.max_clock_ambiguity * 2)); Lemma_AlwaysImpliesLaterAlways(first_step, step, EpochLengthEqualOrGreaterTemporal(b, idx, duration + asp.max_clock_ambiguity * 2)); } lemma_FirstStepWithLiveReplicaInQuorumHasNoLiveReplicaSuspectingBefore(b, asp, view, duration, step); lemma_FirstStepWithLiveReplicaInQuorumHasAllMaxBallot1aBeforeView(b, asp, view, duration, step); lemma_NoLiveReplicaSuspectsViewBeforeStable(b, asp, step, view, duration, endTime); } lemma lemma_EventuallyBallotStable( b:Behavior, asp:AssumptionParameters, processing_sync_start:int, processing_bound:int, primary_idx:int, duration:int ) returns ( view:Ballot, step:int, ahead_idx:int ) requires LivenessAssumptions(b, asp) requires PacketProcessingSynchronous(b, asp, processing_sync_start, processing_bound) requires primary_idx in asp.live_quorum requires duration >= 0 ensures processing_sync_start <= step ensures view.proposer_id == primary_idx ensures LeqUpperBound(view.seqno, asp.c.params.max_integer_val) ensures sat(step, StablePeriodStartedTemporal(b, asp.live_quorum, view, ahead_idx)) ensures sat(step, always(untilabsolutetime(NoReplicaBeyondViewTemporal(b, view), b[step].environment.time + duration, PaxosTimeMap(b)))) { view, step := lemma_EventuallyViewStable(b, asp, processing_sync_start, processing_bound, primary_idx, duration+1); ahead_idx :| ahead_idx in asp.live_quorum && 0 <= ahead_idx < |b[step].replicas| && BalLeq(view, CurrentViewOfHost(b[step], ahead_idx)); assert StablePeriodStarted(b[step], asp.live_quorum, view, ahead_idx); var time_plus_duration := b[step].environment.time + duration; forall i | step <= i ensures sat(i, untilabsolutetime(NoReplicaBeyondViewTemporal(b, view), time_plus_duration, PaxosTimeMap(b))) { TemporalDeduceFromAlways(step, i, NoLiveReplicaSuspectsViewBeforeTemporal(b, asp.live_quorum, view, time_plus_duration + asp.max_clock_ambiguity + 1, asp.max_clock_ambiguity)); if b[i].environment.time <= time_plus_duration { assert b[i].environment.time < time_plus_duration + 1; lemma_ConstantsAllConsistent(b, asp.c, i); forall idx | idx in asp.live_quorum ensures ViewPlusLe(CurrentViewPlusOfHost(b[i], idx), ViewPlus(view, false)) { var es := b[i].replicas[idx].replica.proposer.election_state; assert || BalLt(es.current_view, view) || (&& es.current_view == view && es.constants.my_index !in es.current_view_suspectors && es.epoch_end_time >= time_plus_duration + asp.max_clock_ambiguity + 1); } lemma_NoOneCanExceedViewUntilAQuorumMemberSuspectsIt(b, asp, i, view); assert AllQuorumMembersViewPlusLe(b[i], asp.live_quorum, ViewPlus(view, false)); assert AllReplicasViewPlusLe(b[i], ViewPlus(view, true)); forall idx | 0 <= idx < |b[i].replicas| ensures BalLeq(CurrentViewOfHost(b[i], idx), view) { assert ViewPlusLe(CurrentViewPlusOfHost(b[i], idx), ViewPlus(view, true)); lemma_BalLtProperties(); } assert NoReplicaBeyondView(b[i], view); } } TemporalAlways(step, untilabsolutetime(NoReplicaBeyondViewTemporal(b, view), time_plus_duration, PaxosTimeMap(b))); } lemma lemma_EventuallyBallotStableWithRequest( b:Behavior, asp:AssumptionParameters, processing_sync_start:int, processing_bound:int, primary_idx:int, base_duration:int, per_request_duration:int ) returns ( view:Ballot, step:int, ahead_idx:int, num_requests:int, duration:int ) requires LivenessAssumptions(b, asp) requires PacketProcessingSynchronous(b, asp, processing_sync_start, processing_bound) requires primary_idx in asp.live_quorum requires base_duration >= 0 requires per_request_duration >= 0 ensures processing_sync_start <= step ensures num_requests > 0 ensures view.proposer_id == primary_idx ensures LeqUpperBound(view.seqno, asp.c.params.max_integer_val) ensures duration == base_duration + num_requests * per_request_duration ensures sat(step, StablePeriodStartedTemporal(b, asp.live_quorum, view, ahead_idx)) ensures sat(step, always(untilabsolutetime(NoReplicaBeyondViewTemporal(b, view), b[step].environment.time + duration, PaxosTimeMap(b)))) ensures sat(step, always(RequestInFirstNTemporal(b, primary_idx, asp.persistent_request, num_requests))) { var first_step := lemma_EventuallyPersistentRequestInRequestsReceivedPrevEpochs(b, asp, processing_sync_start, processing_bound, primary_idx); num_requests := |b[first_step].replicas[primary_idx].replica.proposer.election_state.requests_received_prev_epochs|; duration := base_duration + num_requests * per_request_duration; lemma_mul_nonnegative(num_requests, per_request_duration); lemma_PersistentRequestDoesNotIncreasePositionInRequestsReceivedPrevEpochs(b, asp, processing_sync_start, processing_bound, primary_idx, first_step, num_requests); lemma_IfPacketProcessingSynchronousThenAlways(b, asp, processing_sync_start, first_step, processing_bound); lemma_ConstantsAllConsistent(b, asp.c, first_step); view, step, ahead_idx := lemma_EventuallyBallotStable(b, asp, first_step, processing_bound, primary_idx, duration); Lemma_AlwaysImpliesLaterAlways(first_step, step, RequestInFirstNTemporal(b, primary_idx, asp.persistent_request, num_requests)); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/LivenessProof/ViewPropagation.i.dfy ================================================ include "../DistributedSystem.i.dfy" include "Assumptions.i.dfy" include "Invariants.i.dfy" include "ViewChange.i.dfy" include "WF1.i.dfy" include "../CommonProof/Actions.i.dfy" include "../CommonProof/CanonicalizeBallot.i.dfy" include "../CommonProof/PacketSending.i.dfy" include "../CommonProof/Quorum.i.dfy" module LivenessProof__ViewPropagation_i { import opened LiveRSL__Configuration_i import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Election_i import opened LiveRSL__Environment_i import opened LiveRSL__Replica_i import opened LiveRSL__Types_i import opened LivenessProof__Assumptions_i import opened LivenessProof__Invariants_i import opened LivenessProof__StablePeriod_i import opened LivenessProof__ViewChange_i import opened LivenessProof__WF1_i import opened CommonProof__Actions_i import opened CommonProof__CanonicalizeBallot_i import opened CommonProof__Constants_i import opened CommonProof__PacketSending_i import opened CommonProof__Quorum_i import opened Concrete_NodeIdentity_i import opened Temporal__Temporal_s import opened Collections__Maps2_s import opened Environment_s predicate ViewInfoInObserverConsistent(ps:RslState, idx:int, observer_idx:int) requires 0 <= idx < |ps.replicas| requires 0 <= observer_idx < |ps.replicas| { idx in ps.replicas[observer_idx].replica.proposer.election_state.current_view_suspectors ==> ViewPlusLe(ViewPlus(CurrentViewOfHost(ps, observer_idx), true), CurrentViewPlusOfHost(ps, idx)) } predicate ViewInfoInPacketConsistent(ps:RslState, idx:int, p:RslPacket) requires 0 <= idx < |ps.replicas| { 0 <= idx < |ps.constants.config.replica_ids| && p.src == ps.constants.config.replica_ids[idx] && p.msg.RslMessage_Heartbeat? ==> && IsValidBallot(p.msg.bal_heartbeat, ps.constants) && ViewPlusLe(ViewPlus(p.msg.bal_heartbeat, p.msg.suspicious), CurrentViewPlusOfHost(ps, idx)) } predicate ViewInfoConsistent(ps:RslState, idx:int) requires 0 <= idx < |ps.replicas| { && IsValidBallot(CurrentViewOfHost(ps, idx), ps.constants) && (forall observer_idx :: 0 <= observer_idx < |ps.replicas| ==> ViewInfoInObserverConsistent(ps, idx, observer_idx)) && (forall p :: p in ps.environment.sentPackets ==> ViewInfoInPacketConsistent(ps, idx, p)) } predicate ViewInfoStateInv(ps:RslState) { forall idx :: 0 <= idx < |ps.replicas| ==> ViewInfoConsistent(ps, idx) } predicate AllSuspectorsValidStateInv(ps:RslState) { forall idx, suspector_idx :: 0 <= idx < |ps.replicas| && suspector_idx in ps.replicas[idx].replica.proposer.election_state.current_view_suspectors ==> 0 <= suspector_idx < |ps.replicas| } predicate AllQuorumMembersViewPlusLe(ps:RslState, quorum:set, v:ViewPlus) { forall idx :: idx in quorum && 0 <= idx < |ps.replicas| ==> ViewPlusLe(CurrentViewPlusOfHost(ps, idx), v) } predicate AllReplicasViewPlusLe(ps:RslState, v:ViewPlus) { forall idx :: 0 <= idx < |ps.replicas| ==> ViewPlusLe(CurrentViewPlusOfHost(ps, idx), v) } predicate NoMemberBeyondViewUntilAQuorumMemberSuspectsIt(ps:RslState, quorum:set, v:Ballot) { AllQuorumMembersViewPlusLe(ps, quorum, ViewPlus(v, false)) ==> AllReplicasViewPlusLe(ps, ViewPlus(v, true)) } predicate HostSuspectsOrInLaterViewWithSpecificNextHeartbeatTime( ps:RslState, replica_index:int, view:Ballot, nextHeartbeatTime:int ) { && 0 <= replica_index < |ps.replicas| && ViewPlusLe(ViewPlus(view, true), CurrentViewPlusOfHost(ps, replica_index)) && ps.replicas[replica_index].replica.nextHeartbeatTime == nextHeartbeatTime } function{:opaque} HostSuspectsOrInLaterViewWithSpecificNextHeartbeatTimeTemporal( b:Behavior, replica_index:int, view:Ballot, nextHeartbeatTime:int ):temporal requires imaptotal(b) ensures forall i {:trigger sat(i, HostSuspectsOrInLaterViewWithSpecificNextHeartbeatTimeTemporal(b, replica_index, view, nextHeartbeatTime))} :: sat(i, HostSuspectsOrInLaterViewWithSpecificNextHeartbeatTimeTemporal(b, replica_index, view, nextHeartbeatTime)) <==> HostSuspectsOrInLaterViewWithSpecificNextHeartbeatTime(b[i], replica_index, view, nextHeartbeatTime) { stepmap(imap i :: HostSuspectsOrInLaterViewWithSpecificNextHeartbeatTime(b[i], replica_index, view, nextHeartbeatTime)) } predicate HostSentSuspicion( ps:RslState, sid:NodeIdentity, oid:NodeIdentity, view:Ballot, p:RslPacket ) { && p.dst == oid && p.src == sid && p.msg.RslMessage_Heartbeat? && p.msg.bal_heartbeat == view && p.msg.suspicious && ps.environment.nextStep.LEnvStepHostIos? && LIoOpSend(p) in ps.environment.nextStep.ios } predicate HostSentSuspicionOrInLaterView( ps:RslState, suspector_idx:int, observer_idx:int, view:Ballot ) { && |ps.replicas| == |ps.constants.config.replica_ids| && 0 <= suspector_idx < |ps.replicas| && 0 <= observer_idx < |ps.replicas| && (|| BalLt(view, CurrentViewOfHost(ps, suspector_idx)) || exists p :: HostSentSuspicion(ps, ps.constants.config.replica_ids[suspector_idx], ps.constants.config.replica_ids[observer_idx], view, p)) } function{:opaque} HostSentSuspicionOrInLaterViewTemporal( b:Behavior, suspector_idx:int, observer_idx:int, view:Ballot ):temporal requires imaptotal(b) ensures forall i {:trigger sat(i, HostSentSuspicionOrInLaterViewTemporal(b, suspector_idx, observer_idx, view))} :: sat(i, HostSentSuspicionOrInLaterViewTemporal(b, suspector_idx, observer_idx, view)) == HostSentSuspicionOrInLaterView(b[i], suspector_idx, observer_idx, view) { stepmap(imap i :: HostSentSuspicionOrInLaterView(b[i], suspector_idx, observer_idx, view)) } predicate SuspicionPropagatedToObserver( ps:RslState, suspector_idx:int, observer_idx:int, view:Ballot ) { && |ps.replicas| == |ps.constants.config.replica_ids| && 0 <= suspector_idx < |ps.replicas| && 0 <= observer_idx < |ps.replicas| && (|| BalLt(view, CurrentViewOfHost(ps, suspector_idx)) || BalLt(view, CurrentViewOfHost(ps, observer_idx)) || (&& CurrentViewOfHost(ps, observer_idx) == view && suspector_idx in ps.replicas[observer_idx].replica.proposer.election_state.current_view_suspectors)) } function{:opaque} SuspicionPropagatedToObserverTemporal( b:Behavior, suspector_idx:int, observer_idx:int, view:Ballot ):temporal requires imaptotal(b) ensures forall i {:trigger sat(i, SuspicionPropagatedToObserverTemporal(b, suspector_idx, observer_idx, view))} :: sat(i, SuspicionPropagatedToObserverTemporal(b, suspector_idx, observer_idx, view)) == SuspicionPropagatedToObserver(b[i], suspector_idx, observer_idx, view) { stepmap(imap i :: SuspicionPropagatedToObserver(b[i], suspector_idx, observer_idx, view)) } lemma lemma_PaxosNextPreservesViewInfoInObserverConsistent( b:Behavior, asp:AssumptionParameters, i:int, idx:int, observer_idx:int ) requires LivenessAssumptions(b, asp) requires 0 <= i requires ViewInfoStateInv(b[i]) requires 0 <= idx < |b[i+1].replicas| requires 0 <= observer_idx < |b[i+1].replicas| ensures ViewInfoInObserverConsistent(b[i+1], idx, observer_idx) { lemma_AssumptionsMakeValidTransition(b, asp.c, i); lemma_ConstantsAllConsistent(b, asp.c, i); lemma_ConstantsAllConsistent(b, asp.c, i+1); var ps := b[i]; var ps' := b[i+1]; var s := ps.replicas[observer_idx].replica; var s' := ps'.replicas[observer_idx].replica; var es := s.proposer.election_state; var es' := s'.proposer.election_state; assert RslNext(ps, ps'); lemma_ViewPlusOfHostMonotonic(b, asp, idx, i, i+1); assert ViewInfoConsistent(ps, idx); assert ViewInfoInObserverConsistent(ps, idx, observer_idx); // lemma_LEnvironmentInvariantHolds(b, asp, i); if idx in es'.current_view_suspectors { if idx in es.current_view_suspectors { if es.current_view != es'.current_view { var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, i, observer_idx); assert LReplicaNextProcessHeartbeat(s, s', ios[0].r, ios[1].t, ExtractSentPacketsFromIos(ios)); lemma_PacketProcessedImpliesPacketSent(ps, ps', observer_idx, ios, ios[0].r); assert ViewInfoInPacketConsistent(ps, idx, ios[0].r); } } else { var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, i, observer_idx); if |ios| >= 2 && ios[0].LIoOpReceive? && ios[1].LIoOpReadClock? && LReplicaNextProcessHeartbeat(s, s', ios[0].r, ios[1].t, ExtractSentPacketsFromIos(ios)) { lemma_PacketProcessedImpliesPacketSent(ps, ps', observer_idx, ios, ios[0].r); assert ViewInfoInPacketConsistent(ps, idx, ios[0].r); } else if LReplicaNextReadClockCheckForViewTimeout(s, s', SpontaneousClock(ios), ExtractSentPacketsFromIos(ios)) { assert idx == observer_idx; } } } } lemma{:timeLimitMultiplier 2} lemma_PaxosNextPreservesViewInfoInPacketConsistent( b:Behavior, asp:AssumptionParameters, i:int, idx:int, p:RslPacket ) requires LivenessAssumptions(b, asp) requires 0 <= i requires ViewInfoStateInv(b[i]) requires 0 <= idx < |b[i+1].replicas| requires p in b[i+1].environment.sentPackets ensures ViewInfoInPacketConsistent(b[i+1], idx, p) { lemma_AssumptionsMakeValidTransition(b, asp.c, i); lemma_ConstantsAllConsistent(b, asp.c, i); lemma_ConstantsAllConsistent(b, asp.c, i+1); var ps := b[i]; var ps' := b[i+1]; var s := ps.replicas[idx].replica; var s' := ps'.replicas[idx].replica; var es := s.proposer.election_state; var es' := s'.proposer.election_state; assert RslNext(ps, ps'); assert ViewInfoConsistent(ps, idx); if p.src == ps.constants.config.replica_ids[idx] && p.msg.RslMessage_Heartbeat? { if p in ps.environment.sentPackets { assert ViewInfoInPacketConsistent(ps, idx, p); lemma_ViewPlusOfHostMonotonic(b, asp, idx, i, i+1); lemma_ViewPlusLeTransitive(ViewPlus(p.msg.bal_heartbeat, p.msg.suspicious), CurrentViewPlusOfHost(ps, idx), CurrentViewPlusOfHost(ps', idx)); } else { var observer_idx, ios := lemma_ActionThatSendsHeartbeatIsMaybeSendHeartbeat(ps, ps', p); assert ReplicasDistinct(ps.constants.config.replica_ids, idx, observer_idx); assert idx == observer_idx; } } } lemma lemma_PaxosNextPreservesIsValidBallot( b:Behavior, asp:AssumptionParameters, i:int, idx:int ) requires LivenessAssumptions(b, asp) requires 0 <= i requires ViewInfoStateInv(b[i]) requires 0 <= idx < |b[i+1].replicas| ensures IsValidBallot(CurrentViewOfHost(b[i+1], idx), b[i+1].constants) { lemma_AssumptionsMakeValidTransition(b, asp.c, i); lemma_ConstantsAllConsistent(b, asp.c, i); lemma_ConstantsAllConsistent(b, asp.c, i+1); var ps := b[i]; var ps' := b[i+1]; var s := ps.replicas[idx].replica; var s' := ps'.replicas[idx].replica; var es := s.proposer.election_state; var es' := s'.proposer.election_state; assert RslNext(ps, ps'); // lemma_LEnvironmentInvariantHolds(b, asp, i); assert ViewInfoConsistent(b[i], idx); if es'.current_view != es.current_view { var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, i, idx); var sent_packets := ExtractSentPacketsFromIos(ios); if && |ios| > 1 && ios[1].LIoOpReadClock? && LReplicaNextProcessHeartbeat(s, s', ios[0].r, ios[1].t, sent_packets) && ios[0].r.src in asp.c.config.replica_ids { var p := ios[0].r; var sender_idx := GetReplicaIndex(p.src, ps.constants.config); lemma_PacketProcessedImpliesPacketSent(ps, ps', idx, ios, p); assert ViewInfoConsistent(ps, sender_idx); assert ViewInfoInPacketConsistent(ps, sender_idx, p); assert IsValidBallot(p.msg.bal_heartbeat, ps.constants); assert IsValidBallot(es'.current_view, ps'.constants); } else if LReplicaNextReadClockCheckForQuorumOfViewSuspicions(s, s', SpontaneousClock(ios), sent_packets) { assert es'.current_view == ComputeSuccessorView(es.current_view, es.constants.all); lemma_ComputeSuccessorViewProducesValidBallot(es.current_view, es.constants.all); assert IsValidBallot(es'.current_view, ps'.constants); } else { assert false; } } } lemma lemma_ViewInfoStateInvHolds( b:Behavior, asp:AssumptionParameters, i:int ) requires LivenessAssumptions(b, asp) requires 0 <= i ensures ViewInfoStateInv(b[i]) { if i > 0 { lemma_ViewInfoStateInvHolds(b, asp, i-1); forall idx, observer_idx | 0 <= idx < |b[i].replicas| && 0 <= observer_idx < |b[i].replicas| ensures ViewInfoInObserverConsistent(b[i], idx, observer_idx) { lemma_PaxosNextPreservesViewInfoInObserverConsistent(b, asp, i-1, idx, observer_idx); } forall idx, p | 0 <= idx < |b[i].replicas| && p in b[i].environment.sentPackets ensures ViewInfoInPacketConsistent(b[i], idx, p) { lemma_PaxosNextPreservesViewInfoInPacketConsistent(b, asp, i-1, idx, p); } forall idx | 0 <= idx < |b[i].replicas| ensures IsValidBallot(CurrentViewOfHost(b[i], idx), b[i].constants) { lemma_PaxosNextPreservesIsValidBallot(b, asp, i-1, idx); } } } lemma{:timeLimitMultiplier 2} lemma_AllSuspectorsValidStateInvHolds( b:Behavior, asp:AssumptionParameters, i:int ) requires LivenessAssumptions(b, asp) requires 0 <= i ensures AllSuspectorsValidStateInv(b[i]) { if i > 0 { lemma_AssumptionsMakeValidTransition(b, asp.c, i-1); lemma_AllSuspectorsValidStateInvHolds(b, asp, i-1); lemma_ConstantsAllConsistent(b, asp.c, i-1); lemma_ConstantsAllConsistent(b, asp.c, i); var ps := b[i-1]; var ps' := b[i]; if !AllSuspectorsValidStateInv(b[i]) { var idx, suspector_idx :| && 0 <= idx < |ps'.replicas| && suspector_idx in ps'.replicas[idx].replica.proposer.election_state.current_view_suspectors && !(0 <= suspector_idx < |ps'.replicas|); var s := ps.replicas[idx].replica; var s' := ps'.replicas[idx].replica; var es := s.proposer.election_state; var es' := s'.proposer.election_state; assert suspector_idx in es'.current_view_suspectors - es.current_view_suspectors; var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, i-1, idx); var sent_packets := ExtractSentPacketsFromIos(ios); if |ios| > 1 && ios[1].LIoOpReadClock? && LReplicaNextProcessHeartbeat(s, s', ios[0].r, ios[1].t, sent_packets) && ios[0].r.src in asp.c.config.replica_ids { assert suspector_idx == GetReplicaIndex(ios[0].r.src, es.constants.all.config); assert false; } else if LReplicaNextReadClockCheckForViewTimeout(s, s', SpontaneousClock(ios), sent_packets) { assert suspector_idx == es.constants.my_index; assert false; } else { assert false; } } } } lemma lemma_IsValidBallot( b:Behavior, asp:AssumptionParameters, i:int, idx:int ) requires LivenessAssumptions(b, asp) requires 0 <= i requires 0 <= idx < |b[i].replicas| ensures IsValidBallot(CurrentViewOfHost(b[i], idx), asp.c) { lemma_ConstantsAllConsistent(b, asp.c, i); lemma_ViewInfoStateInvHolds(b, asp, i); assert ViewInfoConsistent(b[i], idx); } lemma lemma_CantChangeViewIfNoOneInQuorumSuspects( b:Behavior, asp:AssumptionParameters, i:int, idx:int, view:Ballot ) requires LivenessAssumptions(b, asp) requires 0 <= i requires 0 <= view.proposer_id < |asp.c.config.replica_ids| requires AllQuorumMembersViewPlusLe(b[i], asp.live_quorum, ViewPlus(view, false)) requires 0 <= idx < |b[i].replicas| requires 0 <= idx < |b[i+1].replicas| requires ViewPlusLe(CurrentViewPlusOfHost(b[i], idx), ViewPlus(view, true)) requires ViewPlusLt(ViewPlus(view, true), CurrentViewPlusOfHost(b[i+1], idx)) requires AllReplicasViewPlusLe(b[i], ViewPlus(view, true)) ensures false { lemma_AssumptionsMakeValidTransition(b, asp.c, i); lemma_ConstantsAllConsistent(b, asp.c, i); lemma_ConstantsAllConsistent(b, asp.c, i+1); var ps := b[i]; var ps' := b[i+1]; var s := ps.replicas[idx].replica; var s' := ps'.replicas[idx].replica; var es := s.proposer.election_state; lemma_BalLtProperties(); assert BalLt(CurrentViewOfHost(ps, idx), CurrentViewOfHost(ps', idx)); assert BalLt(view, CurrentViewOfHost(ps', idx)); // lemma_LEnvironmentInvariantHolds(b, asp, i); lemma_ViewInfoStateInvHolds(b, asp, i); var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, i, idx); var sent_packets := ExtractSentPacketsFromIos(ios); if |ios| > 1 && ios[1].LIoOpReadClock? && LReplicaNextProcessHeartbeat(s, s', ios[0].r, ios[1].t, sent_packets) && ios[0].r.src in asp.c.config.replica_ids { var p := ios[0].r; var oid := p.src; var sender_index := GetReplicaIndex(oid, es.constants.all.config); lemma_PacketProcessedImpliesPacketSent(ps, ps', idx, ios, p); assert p in ps.environment.sentPackets; assert ViewInfoConsistent(ps, sender_index); assert ViewInfoInPacketConsistent(ps, sender_index, p); assert ViewPlusLe(CurrentViewPlusOfHost(ps, sender_index), ViewPlus(view, true)); assert false; } else if LReplicaNextReadClockCheckForQuorumOfViewSuspicions(s, s', SpontaneousClock(ios), sent_packets) { assert |es.current_view_suspectors| >= LMinQuorumSize(es.constants.all.config); lemma_AllSuspectorsValidStateInvHolds(b, asp, i); var common_index := lemma_QuorumIndexOverlap(es.current_view_suspectors, asp.live_quorum, |asp.c.config.replica_ids|); assert ViewPlusLe(CurrentViewPlusOfHost(ps, common_index), ViewPlus(view, false)); assert ViewInfoConsistent(ps, common_index); assert ViewInfoInObserverConsistent(ps, common_index, idx); assert ViewPlusLe(ViewPlus(CurrentViewOfHost(ps, idx), true), CurrentViewPlusOfHost(ps, common_index)); lemma_ViewPlusLeTransitiveDefinite(ViewPlus(CurrentViewOfHost(ps, idx), true), CurrentViewPlusOfHost(ps, common_index), ViewPlus(view, false)); assert BalLt(CurrentViewOfHost(ps, idx), view); assert BalLt(view, CurrentViewOfHost(ps', idx)); lemma_OverflowProtectionNotUsedForReplica(b, asp, i, idx); lemma_NothingBetweenViewAndSuccessor(CurrentViewOfHost(ps, idx), view, es.constants.all); assert false; } else { assert false; } } lemma lemma_NoOneCanExceedViewUntilAQuorumMemberSuspectsItOneStep( b:Behavior, asp:AssumptionParameters, i:int, view:Ballot ) requires LivenessAssumptions(b, asp) requires 0 <= i requires 0 <= view.proposer_id < |asp.c.config.replica_ids| requires NoMemberBeyondViewUntilAQuorumMemberSuspectsIt(b[i], asp.live_quorum, view) ensures NoMemberBeyondViewUntilAQuorumMemberSuspectsIt(b[i+1], asp.live_quorum, view) { lemma_AssumptionsMakeValidTransition(b, asp.c, i); lemma_ConstantsAllConsistent(b, asp.c, i); lemma_ConstantsAllConsistent(b, asp.c, i+1); var ps := b[i]; var ps' := b[i+1]; assert RslNext(ps, ps'); if !NoMemberBeyondViewUntilAQuorumMemberSuspectsIt(ps', asp.live_quorum, view) { forall live_idx | live_idx in asp.live_quorum ensures ViewPlusLe(CurrentViewPlusOfHost(ps, live_idx), ViewPlus(view, false)) { lemma_ViewPlusOfHostMonotonic(b, asp, live_idx, i, i+1); lemma_ViewPlusLeTransitiveDefinite(CurrentViewPlusOfHost(ps, live_idx), CurrentViewPlusOfHost(ps', live_idx), ViewPlus(view, false)); } assert AllQuorumMembersViewPlusLe(ps, asp.live_quorum, ViewPlus(view, false)); assert AllReplicasViewPlusLe(ps, ViewPlus(view, true)); var idx :| 0 <= idx < |ps.replicas| && !ViewPlusLe(CurrentViewPlusOfHost(ps', idx), ViewPlus(view, true)); assert ViewPlusLe(CurrentViewPlusOfHost(ps, idx), ViewPlus(view, true)); lemma_CantChangeViewIfNoOneInQuorumSuspects(b, asp, i, idx, view); } } lemma lemma_NoOneCanExceedViewUntilAQuorumMemberSuspectsIt( b:Behavior, asp:AssumptionParameters, i:int, view:Ballot ) requires LivenessAssumptions(b, asp) requires 0 <= i requires 0 <= view.proposer_id < |asp.c.config.replica_ids| ensures NoMemberBeyondViewUntilAQuorumMemberSuspectsIt(b[i], asp.live_quorum, view) { lemma_BalLtProperties(); lemma_ConstantsAllConsistent(b, asp.c, i); if i == 0 { assert forall idx :: 0 <= idx < |b[i].replicas| ==> CurrentViewPlusOfHost(b[i], idx) == ViewPlus(Ballot(1, 0), false); if BalLt(view, Ballot(1, 0)) { var idx :| idx in asp.live_quorum; assert CurrentViewPlusOfHost(b[i], idx) == ViewPlus(Ballot(1, 0), false); assert !ViewPlusLe(CurrentViewPlusOfHost(b[i], idx), ViewPlus(view, false)); assert !AllQuorumMembersViewPlusLe(b[i], asp.live_quorum, ViewPlus(view, false)); } else { forall idx | 0 <= idx < |b[i].replicas| ensures ViewPlusLe(CurrentViewPlusOfHost(b[i], idx), ViewPlus(view, true)) { assert CurrentViewPlusOfHost(b[i], idx) == ViewPlus(Ballot(1, 0), false); } assert AllReplicasViewPlusLe(b[i], ViewPlus(view, true)); } } else { lemma_NoOneCanExceedViewUntilAQuorumMemberSuspectsIt(b, asp, i-1, view); lemma_NoOneCanExceedViewUntilAQuorumMemberSuspectsItOneStep(b, asp, i-1, view); } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/LivenessProof/ViewPropagation2.i.dfy ================================================ include "../DistributedSystem.i.dfy" include "Assumptions.i.dfy" include "Invariants.i.dfy" include "ViewChange.i.dfy" include "ViewPropagation.i.dfy" include "WF1.i.dfy" include "../CommonProof/Actions.i.dfy" include "../CommonProof/CanonicalizeBallot.i.dfy" include "../CommonProof/PacketSending.i.dfy" include "../CommonProof/Quorum.i.dfy" module LivenessProof__ViewPropagation2_i { import opened LiveRSL__Broadcast_i import opened LiveRSL__Configuration_i import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Message_i import opened LiveRSL__Proposer_i import opened LiveRSL__Replica_i import opened LiveRSL__Types_i import opened LivenessProof__Assumptions_i import opened LivenessProof__Environment_i import opened LivenessProof__Invariants_i import opened LivenessProof__PacketHandling_i import opened LivenessProof__RequestsReceived_i import opened LivenessProof__RoundRobin_i import opened LivenessProof__StablePeriod_i import opened LivenessProof__ViewChange_i import opened LivenessProof__ViewPropagation_i import opened LivenessProof__WF1_i import opened CommonProof__Actions_i import opened CommonProof__CanonicalizeBallot_i import opened CommonProof__Constants_i import opened CommonProof__PacketSending_i import opened CommonProof__Quorum_i import opened Temporal__Rules_i import opened Temporal__Temporal_s import opened Temporal__Time_s import opened Temporal__WF1_i import opened Environment_s lemma lemma_ReplicaEventuallySendsSuspicionOrLeavesViewWF1Req1( b:Behavior, asp:AssumptionParameters, suspector_idx:int, observer_idx:int, view:Ballot, nextHeartbeatTime:int, start_step:int ) requires LivenessAssumptions(b, asp) requires suspector_idx in asp.live_quorum requires 0 <= observer_idx < |asp.c.config.replica_ids| requires 0 <= start_step requires sat(start_step, always(RequestInRequestsReceivedPrevEpochsTemporal(b, asp.persistent_request, suspector_idx))) ensures var P := HostSuspectsOrInLaterViewWithSpecificNextHeartbeatTimeTemporal(b, suspector_idx, view, nextHeartbeatTime); var Q := HostSentSuspicionOrInLaterViewTemporal(b, suspector_idx, observer_idx, view); sat(start_step, always(TemporalWF1Req1(P, Q))) { var P := HostSuspectsOrInLaterViewWithSpecificNextHeartbeatTimeTemporal(b, suspector_idx, view, nextHeartbeatTime); var Q := HostSentSuspicionOrInLaterViewTemporal(b, suspector_idx, observer_idx, view); forall i | start_step <= i ensures sat(i, TemporalWF1Req1(P, Q)) { if sat(i, P) && !sat(i, Q) && !sat(i+1, P) && !sat(i+1, Q) { lemma_ConstantsAllConsistent(b, asp.c, i); lemma_ConstantsAllConsistent(b, asp.c, i+1); lemma_ViewPlusOfHostMonotonic(b, asp, suspector_idx, i, i+1); lemma_AssumptionsMakeValidTransition(b, asp.c, i); var ps := b[i]; var ps' := b[i+1]; var s := ps.replicas[suspector_idx].replica; var s' := ps'.replicas[suspector_idx].replica; assert s'.nextHeartbeatTime != s.nextHeartbeatTime; var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, asp.c, i, suspector_idx); var sent_packets := ExtractSentPacketsFromIos(ios); assert |ios| > 0; assert ios[0].LIoOpReadClock?; assert LReplicaNextReadClockMaybeSendHeartbeat(s, s', SpontaneousClock(ios), sent_packets); assert ios[0].t >= s.nextHeartbeatTime; var sid := ps.constants.config.replica_ids[suspector_idx]; var oid := ps.constants.config.replica_ids[observer_idx]; var p := LPacket(oid, sid, RslMessage_Heartbeat(view, true, s.executor.ops_complete)); assert p in sent_packets; assert p in ps'.environment.sentPackets; assert HostSentSuspicion(ps, sid, oid, view, p); assert false; } } TemporalAlways(start_step, TemporalWF1Req1(P, Q)); } lemma {:timeLimitMultiplier 2} lemma_ReplicaEventuallySendsSuspicionOrLeavesViewWF1Req2( b:Behavior, asp:AssumptionParameters, suspector_idx:int, observer_idx:int, view:Ballot, nextHeartbeatTime:int, start_step:int ) requires LivenessAssumptions(b, asp) requires suspector_idx in asp.live_quorum requires 0 <= observer_idx < |asp.c.config.replica_ids| requires asp.synchrony_start <= start_step requires sat(start_step, always(RequestInRequestsReceivedPrevEpochsTemporal(b, asp.persistent_request, suspector_idx))) ensures var P := HostSuspectsOrInLaterViewWithSpecificNextHeartbeatTimeTemporal(b, suspector_idx, view, nextHeartbeatTime); var Q := HostSentSuspicionOrInLaterViewTemporal(b, suspector_idx, observer_idx, view); var Action := ReplicaSchedule(b, suspector_idx)[9]; sat(start_step, always(TemporalWF1RealTimeDelayedReq2(P, Q, Action, nextHeartbeatTime + asp.max_clock_ambiguity, PaxosTimeMap(b)))) { var P := HostSuspectsOrInLaterViewWithSpecificNextHeartbeatTimeTemporal(b, suspector_idx, view, nextHeartbeatTime); var Q := HostSentSuspicionOrInLaterViewTemporal(b, suspector_idx, observer_idx, view); var Action := ReplicaSchedule(b, suspector_idx)[9]; var x := TemporalWF1RealTimeDelayedReq2(P, Q, Action, nextHeartbeatTime + asp.max_clock_ambiguity, PaxosTimeMap(b)); forall i | start_step <= i ensures sat(i, x) { if sat(i, P) && sat(i, nextafter(Action, nextHeartbeatTime + asp.max_clock_ambiguity, PaxosTimeMap(b))) && !sat(i, Q) && !sat(i+1, Q) { lemma_ConstantsAllConsistent(b, asp.c, i); lemma_ConstantsAllConsistent(b, asp.c, i+1); assert SpecificClockReadingRslActionOccurs(b[i], b[i+1], LReplicaNextReadClockMaybeSendHeartbeat, suspector_idx); var ios :| && RslNextOneReplica(b[i], b[i+1], suspector_idx, ios) && SpontaneousIos(ios, 1) && LReplicaNextReadClockMaybeSendHeartbeat(b[i].replicas[suspector_idx].replica, b[i+1].replicas[suspector_idx].replica, SpontaneousClock(ios), ExtractSentPacketsFromIos(ios)); var ps := b[i]; var ps' := b[i+1]; var s := ps.replicas[suspector_idx].replica; var s' := ps'.replicas[suspector_idx].replica; var sid := ps.constants.config.replica_ids[suspector_idx]; var oid := ps.constants.config.replica_ids[observer_idx]; var p := LPacket(oid, sid, RslMessage_Heartbeat(view, true, s.executor.ops_complete)); lemma_ClockAmbiguityLimitApplies(b, asp, i, suspector_idx, ios[0]); assert LBroadcastToEveryone(s.constants.all.config, s.constants.my_index, RslMessage_Heartbeat(s.proposer.election_state.current_view, s.constants.my_index in s.proposer.election_state.current_view_suspectors, s.executor.ops_complete), ExtractSentPacketsFromIos(ios)); assert p in ExtractSentPacketsFromIos(ios); assert p in ps'.environment.sentPackets; assert HostSentSuspicion(ps, sid, oid, view, p); assert false; } } TemporalAlways(start_step, x); } lemma lemma_ReplicaEventuallySendsSuspicionOrLeavesView( b:Behavior, asp:AssumptionParameters, processing_sync_start:int, processing_bound:int, suspector_idx:int, observer_idx:int, start_step:int ) returns ( step:int ) requires LivenessAssumptions(b, asp) requires PacketProcessingSynchronous(b, asp, processing_sync_start, processing_bound) requires suspector_idx in asp.live_quorum requires processing_sync_start <= start_step requires 0 <= suspector_idx < |b[start_step].replicas| requires 0 <= observer_idx < |b[start_step].replicas| ensures start_step <= step ensures HostSentSuspicionOrInLaterView(b[step], suspector_idx, observer_idx, CurrentViewOfHost(b[start_step], suspector_idx)) { lemma_ConstantsAllConsistent(b, asp.c, start_step); var view := CurrentViewOfHost(b[start_step], suspector_idx); var i := lemma_ReplicaEventuallySuspectsViewOrIsInDifferentView(b, asp, processing_sync_start, processing_bound, suspector_idx, start_step); lemma_ConstantsAllConsistent(b, asp.c, i); var nextHeartbeatTime := b[i].replicas[suspector_idx].replica.nextHeartbeatTime; var P := HostSuspectsOrInLaterViewWithSpecificNextHeartbeatTimeTemporal(b, suspector_idx, view, nextHeartbeatTime); var Q := HostSentSuspicionOrInLaterViewTemporal(b, suspector_idx, observer_idx, view); var Action := ReplicaSchedule(b, suspector_idx)[9]; Lemma_AlwaysImpliesLaterAlways(start_step, i, RequestInRequestsReceivedPrevEpochsTemporal(b, asp.persistent_request, suspector_idx)); lemma_ReplicaEventuallySendsSuspicionOrLeavesViewWF1Req1(b, asp, suspector_idx, observer_idx, view, nextHeartbeatTime, i); lemma_ReplicaEventuallySendsSuspicionOrLeavesViewWF1Req2(b, asp, suspector_idx, observer_idx, view, nextHeartbeatTime, i); lemma_ReplicaNextPerformsSubactionPeriodically(b, asp, suspector_idx, 9); lemma_EstablishRequirementsForWF1RealTimeDelayed(b, asp, i, Action, TimeToPerformGenericAction(asp)); step := TemporalWF1RealTimeDelayed(i, P, Q, Action, TimeToPerformGenericAction(asp), nextHeartbeatTime + asp.max_clock_ambiguity, PaxosTimeMap(b)); } lemma lemma_ReplicaEventuallyPropagatesSuspicionOrLeavesView( b:Behavior, asp:AssumptionParameters, processing_sync_start:int, processing_bound:int, suspector_idx:int, observer_idx:int, start_step:int ) returns ( step:int ) requires LivenessAssumptions(b, asp) requires PacketProcessingSynchronous(b, asp, processing_sync_start, processing_bound) requires suspector_idx in asp.live_quorum requires observer_idx in asp.live_quorum requires processing_sync_start <= start_step requires 0 <= suspector_idx < |b[start_step].replicas| ensures start_step <= step ensures 0 <= suspector_idx < |b[step].replicas| ensures 0 <= observer_idx < |b[step].replicas| ensures var view := CurrentViewOfHost(b[start_step], suspector_idx); SuspicionPropagatedToObserver(b[step], suspector_idx, observer_idx, view) { lemma_ConstantsAllConsistent(b, asp.c, start_step); var view := CurrentViewOfHost(b[start_step], suspector_idx); var sid := asp.c.config.replica_ids[suspector_idx]; var oid := asp.c.config.replica_ids[observer_idx]; var i := lemma_ReplicaEventuallySendsSuspicionOrLeavesView(b, asp, processing_sync_start, processing_bound, suspector_idx, observer_idx, start_step); lemma_ConstantsAllConsistent(b, asp.c, i); assert HostSentSuspicionOrInLaterView(b[i], suspector_idx, observer_idx, view); if BalLt(view, CurrentViewOfHost(b[i], suspector_idx)) { step := i; return; } var p :| HostSentSuspicion(b[i], sid, oid, view, p); var processing_step, ios := lemma_PacketSentToIndexProcessedByIt(b, asp, processing_sync_start, processing_bound, i, observer_idx, p); lemma_ConstantsAllConsistent(b, asp.c, processing_step); lemma_ConstantsAllConsistent(b, asp.c, processing_step+1); var s := b[processing_step].replicas[observer_idx].replica; var s' := b[processing_step+1].replicas[observer_idx].replica; var es := s.proposer.election_state; var es' := s'.proposer.election_state; assert LProposerProcessHeartbeat(s.proposer, s'.proposer, p, ios[1].t); step := processing_step + 1; assert ReplicasDistinct(asp.c.config.replica_ids, suspector_idx, GetReplicaIndex(p.src, es.constants.all.config)); if es.current_view == view { assert suspector_idx in es'.current_view_suspectors; } else if BalLt(es.current_view, view) { assert suspector_idx in es'.current_view_suspectors; } else { lemma_BalLtProperties(); assert BalLt(view, es.current_view); } } lemma lemma_SuspicionPropagatedToObserverStableOneStep( b:Behavior, asp:AssumptionParameters, suspector_idx:int, observer_idx:int, view:Ballot, i:int ) requires LivenessAssumptions(b, asp) requires 0 <= observer_idx < |asp.c.config.replica_ids| requires 0 <= suspector_idx < |asp.c.config.replica_ids| requires 0 <= i requires SuspicionPropagatedToObserver(b[i], suspector_idx, observer_idx, view) ensures SuspicionPropagatedToObserver(b[i+1], suspector_idx, observer_idx, view) { lemma_ConstantsAllConsistent(b, asp.c, i); lemma_ConstantsAllConsistent(b, asp.c, i+1); lemma_AssumptionsMakeValidTransition(b, asp.c, i); lemma_ViewPlusOfHostMonotonic(b, asp, suspector_idx, i, i+1); lemma_ViewPlusOfHostMonotonic(b, asp, observer_idx, i, i+1); } lemma lemma_SuspicionPropagatedToObserverStableMultipleSteps( b:Behavior, asp:AssumptionParameters, suspector_idx:int, observer_idx:int, view:Ballot, i:int, j:int ) requires LivenessAssumptions(b, asp) requires 0 <= observer_idx < |asp.c.config.replica_ids| requires 0 <= suspector_idx < |asp.c.config.replica_ids| requires 0 <= i <= j requires SuspicionPropagatedToObserver(b[i], suspector_idx, observer_idx, view) ensures SuspicionPropagatedToObserver(b[j], suspector_idx, observer_idx, view) decreases j-i { if j > i + 1 { lemma_SuspicionPropagatedToObserverStableMultipleSteps(b, asp, suspector_idx, observer_idx, view, i, j-1); lemma_SuspicionPropagatedToObserverStableMultipleSteps(b, asp, suspector_idx, observer_idx, view, j-1, j); } else if j == i + 1 { lemma_ConstantsAllConsistent(b, asp.c, i); lemma_ConstantsAllConsistent(b, asp.c, i+1); lemma_AssumptionsMakeValidTransition(b, asp.c, i); lemma_ViewPlusOfHostMonotonic(b, asp, observer_idx, i, i+1); lemma_ViewPlusOfHostMonotonic(b, asp, suspector_idx, i, i+1); } } lemma lemma_SuspicionPropagatedToObserverStable( b:Behavior, asp:AssumptionParameters, suspector_idx:int, observer_idx:int, view:Ballot, i:int ) requires LivenessAssumptions(b, asp) requires 0 <= observer_idx < |asp.c.config.replica_ids| requires 0 <= suspector_idx < |asp.c.config.replica_ids| requires 0 <= i requires SuspicionPropagatedToObserver(b[i], suspector_idx, observer_idx, view) ensures sat(i, always(SuspicionPropagatedToObserverTemporal(b, suspector_idx, observer_idx, view))) { forall j | i <= j ensures sat(j, SuspicionPropagatedToObserverTemporal(b, suspector_idx, observer_idx, view)) { lemma_SuspicionPropagatedToObserverStableMultipleSteps(b, asp, suspector_idx, observer_idx, view, i, j); } TemporalAlways(i, SuspicionPropagatedToObserverTemporal(b, suspector_idx, observer_idx, view)); } lemma lemma_SuspicionEventuallyPropagatedToObserverForever( b:Behavior, asp:AssumptionParameters, processing_sync_start:int, processing_bound:int, suspector_idx:int, observer_idx:int, start_step:int ) returns ( step:int ) requires LivenessAssumptions(b, asp) requires PacketProcessingSynchronous(b, asp, processing_sync_start, processing_bound) requires suspector_idx in asp.live_quorum requires observer_idx in asp.live_quorum requires processing_sync_start <= start_step requires 0 <= suspector_idx < |b[start_step].replicas| ensures start_step <= step ensures 0 <= suspector_idx < |b[step].replicas| ensures 0 <= observer_idx < |b[step].replicas| ensures var view := CurrentViewOfHost(b[start_step], suspector_idx); sat(step, always(SuspicionPropagatedToObserverTemporal(b, suspector_idx, observer_idx, view))) { lemma_ConstantsAllConsistent(b, asp.c, start_step); var view := CurrentViewOfHost(b[start_step], suspector_idx); step := lemma_ReplicaEventuallyPropagatesSuspicionOrLeavesView(b, asp, processing_sync_start, processing_bound, suspector_idx, observer_idx, start_step); lemma_SuspicionPropagatedToObserverStable(b, asp, suspector_idx, observer_idx, view, step); } lemma lemma_SuspicionOfLiveReplicasEventuallyPropagatedToObserverForever( b:Behavior, asp:AssumptionParameters, processing_sync_start:int, processing_bound:int, observer_idx:int, suspector_indices:set, view:Ballot, start_step:int ) returns ( step:int ) requires LivenessAssumptions(b, asp) requires PacketProcessingSynchronous(b, asp, processing_sync_start, processing_bound) requires suspector_indices <= asp.live_quorum requires observer_idx in asp.live_quorum requires processing_sync_start <= start_step requires forall suspector_idx :: suspector_idx in suspector_indices ==> 0 <= suspector_idx < |b[start_step].replicas| && CurrentViewOfHost(b[start_step], suspector_idx) == view ensures start_step <= step ensures forall suspector_idx :: suspector_idx in suspector_indices ==> sat(step, always(SuspicionPropagatedToObserverTemporal(b, suspector_idx, observer_idx, view))) decreases |suspector_indices| { if |suspector_indices| == 0 { step := start_step; } else { var suspector_idx :| suspector_idx in suspector_indices; var other_indices := suspector_indices - { suspector_idx }; var first_step := lemma_SuspicionOfLiveReplicasEventuallyPropagatedToObserverForever(b, asp, processing_sync_start, processing_bound, observer_idx, other_indices, view, start_step); var second_step := lemma_SuspicionEventuallyPropagatedToObserverForever(b, asp, processing_sync_start, processing_bound, suspector_idx, observer_idx, start_step); if second_step >= first_step { step := second_step; forall sidx | sidx in suspector_indices ensures sat(step, always(SuspicionPropagatedToObserverTemporal(b, sidx, observer_idx, view))) { if sidx != suspector_idx { Lemma_AlwaysImpliesLaterAlways(first_step, step, SuspicionPropagatedToObserverTemporal(b, sidx, observer_idx, view)); } } } else { step := first_step; forall sidx | sidx in suspector_indices ensures sat(step, always(SuspicionPropagatedToObserverTemporal(b, sidx, observer_idx, view))) { if sidx == suspector_idx { Lemma_AlwaysImpliesLaterAlways(second_step, step, SuspicionPropagatedToObserverTemporal(b, sidx, observer_idx, view)); } } } } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/LivenessProof/ViewSuspicion.i.dfy ================================================ include "../DistributedSystem.i.dfy" include "Assumptions.i.dfy" include "Invariants.i.dfy" include "ViewPropagation.i.dfy" include "ViewPropagation2.i.dfy" include "ViewAdvance.i.dfy" include "../CommonProof/Constants.i.dfy" include "../../../Common/Collections/Sets.i.dfy" module LivenessProof__ViewSuspicion_i { import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Election_i import opened LiveRSL__Environment_i import opened LiveRSL__Proposer_i import opened LiveRSL__Replica_i import opened LiveRSL__Types_i import opened LivenessProof__Assumptions_i import opened LivenessProof__Invariants_i import opened LivenessProof__PacketHandling_i import opened LivenessProof__RoundRobin_i import opened LivenessProof__StablePeriod_i import opened LivenessProof__ViewPropagation_i import opened LivenessProof__ViewPropagation2_i import opened LivenessProof__ViewAdvance_i import opened LivenessProof__ViewChange_i import opened CommonProof__CanonicalizeBallot_i import opened CommonProof__Constants_i import opened Collections__Maps2_s import opened Collections__Sets_i import opened Temporal__Temporal_s import opened Temporal__Rules_i import opened Common__UpperBound_s import opened Environment_s predicate ReplicaHasCollectedSuspicionFrom( ps:RslState, collector_idx:int, suspector_idx:int, view:Ballot ) { && 0 <= collector_idx < |ps.replicas| && (|| BalLt(view, CurrentViewOfHost(ps, collector_idx)) || (&& CurrentViewOfHost(ps, collector_idx) == view && suspector_idx in ps.replicas[collector_idx].replica.proposer.election_state.current_view_suspectors)) } function{:opaque} ReplicaHasCollectedSuspicionFromTemporal( b:Behavior, collector_idx:int, suspector_idx:int, view:Ballot ):temporal requires imaptotal(b) ensures forall i {:trigger sat(i, ReplicaHasCollectedSuspicionFromTemporal(b, collector_idx, suspector_idx, view))} :: sat(i, ReplicaHasCollectedSuspicionFromTemporal(b, collector_idx, suspector_idx, view)) == ReplicaHasCollectedSuspicionFrom(b[i], collector_idx, suspector_idx, view) { stepmap(imap i :: ReplicaHasCollectedSuspicionFrom(b[i], collector_idx, suspector_idx, view)) } lemma lemma_ReplicaHasCollectedSuspicionFromStableOneStep( b:Behavior, asp:AssumptionParameters, collector_idx:int, suspector_idx:int, view:Ballot, i:int ) requires LivenessAssumptions(b, asp) requires 0 <= collector_idx < |asp.c.config.replica_ids| requires 0 <= suspector_idx < |asp.c.config.replica_ids| requires 0 <= i requires ReplicaHasCollectedSuspicionFrom(b[i], collector_idx, suspector_idx, view) ensures ReplicaHasCollectedSuspicionFrom(b[i+1], collector_idx, suspector_idx, view) { lemma_ConstantsAllConsistent(b, asp.c, i); lemma_ConstantsAllConsistent(b, asp.c, i+1); lemma_AssumptionsMakeValidTransition(b, asp.c, i); lemma_ViewPlusOfHostMonotonic(b, asp, collector_idx, i, i+1); } lemma lemma_ReplicaHasCollectedSuspicionFromStableMultipleSteps( b:Behavior, asp:AssumptionParameters, collector_idx:int, suspector_idx:int, view:Ballot, i:int, j:int ) requires LivenessAssumptions(b, asp) requires 0 <= collector_idx < |asp.c.config.replica_ids| requires 0 <= suspector_idx < |asp.c.config.replica_ids| requires 0 <= i <= j requires ReplicaHasCollectedSuspicionFrom(b[i], collector_idx, suspector_idx, view) ensures ReplicaHasCollectedSuspicionFrom(b[j], collector_idx, suspector_idx, view) decreases j-i { if j > i + 1 { lemma_ReplicaHasCollectedSuspicionFromStableMultipleSteps(b, asp, collector_idx, suspector_idx, view, i, j-1); lemma_ReplicaHasCollectedSuspicionFromStableMultipleSteps(b, asp, collector_idx, suspector_idx, view, j-1, j); } else if j == i + 1 { lemma_ConstantsAllConsistent(b, asp.c, i); lemma_ConstantsAllConsistent(b, asp.c, i+1); lemma_AssumptionsMakeValidTransition(b, asp.c, i); lemma_ViewPlusOfHostMonotonic(b, asp, collector_idx, i, i+1); } } lemma lemma_ReplicaHasCollectedSuspicionFromStable( b:Behavior, asp:AssumptionParameters, collector_idx:int, suspector_idx:int, view:Ballot, i:int ) requires LivenessAssumptions(b, asp) requires 0 <= collector_idx < |asp.c.config.replica_ids| requires 0 <= suspector_idx < |asp.c.config.replica_ids| requires 0 <= i requires ReplicaHasCollectedSuspicionFrom(b[i], collector_idx, suspector_idx, view) ensures sat(i, always(ReplicaHasCollectedSuspicionFromTemporal(b, collector_idx, suspector_idx, view))) { forall j | i <= j ensures sat(j, ReplicaHasCollectedSuspicionFromTemporal(b, collector_idx, suspector_idx, view)) { lemma_ReplicaHasCollectedSuspicionFromStableMultipleSteps(b, asp, collector_idx, suspector_idx, view, i, j); } TemporalAlways(i, ReplicaHasCollectedSuspicionFromTemporal(b, collector_idx, suspector_idx, view)); } lemma lemma_ReplicaEventuallyCollectsSuspicionOrLeavesView( b:Behavior, asp:AssumptionParameters, processing_sync_start:int, processing_bound:int, suspector_idx:int, collector_idx:int, start_step:int ) returns ( step:int ) requires LivenessAssumptions(b, asp) requires PacketProcessingSynchronous(b, asp, processing_sync_start, processing_bound) requires suspector_idx in asp.live_quorum requires collector_idx in asp.live_quorum requires processing_sync_start <= start_step requires 0 <= suspector_idx < |b[start_step].replicas| ensures start_step <= step ensures 0 <= suspector_idx < |b[step].replicas| ensures 0 <= collector_idx < |b[step].replicas| ensures var view := CurrentViewOfHost(b[start_step], suspector_idx); || BalLt(view, CurrentViewOfHost(b[step], suspector_idx)) || sat(step, always(ReplicaHasCollectedSuspicionFromTemporal(b, collector_idx, suspector_idx, view))) { var view := CurrentViewOfHost(b[start_step], suspector_idx); step := lemma_ReplicaEventuallyPropagatesSuspicionOrLeavesView(b, asp, processing_sync_start, processing_bound, suspector_idx, collector_idx, start_step); lemma_ConstantsAllConsistent(b, asp.c, step); if !BalLt(view, CurrentViewOfHost(b[step], suspector_idx)) { lemma_ReplicaHasCollectedSuspicionFromStable(b, asp, collector_idx, suspector_idx, view, step); } } lemma lemma_IfReplicaHasCollectedSuspicionsFromLiveQuorumItWillAdvanceView( b:Behavior, asp:AssumptionParameters, collector_idx:int, view:Ballot, action_step:int, ios:seq ) requires LivenessAssumptions(b, asp) requires 0 <= action_step requires IsValidBallot(view, asp.c) requires BallotHasSuccessor(view, asp.c) requires collector_idx in asp.live_quorum requires 0 <= collector_idx < |b[action_step].replicas| requires 0 <= collector_idx < |b[action_step+1].replicas| requires RslNextOneReplica(b[action_step], b[action_step+1], collector_idx, ios) requires SpontaneousIos(ios, 1) requires LReplicaNextReadClockCheckForQuorumOfViewSuspicions(b[action_step].replicas[collector_idx].replica, b[action_step+1].replicas[collector_idx].replica, SpontaneousClock(ios), ExtractSentPacketsFromIos(ios)) requires CurrentViewOfHost(b[action_step], collector_idx) == view requires forall suspector_idx :: suspector_idx in asp.live_quorum ==> suspector_idx in b[action_step].replicas[collector_idx].replica.proposer.election_state.current_view_suspectors ensures 0 <= collector_idx < |b[action_step+1].replicas| ensures BalLt(view, CurrentViewOfHost(b[action_step+1], collector_idx)) { lemma_ConstantsAllConsistent(b, asp.c, action_step); var ps := b[action_step]; var ps' := b[action_step+1]; var s := ps.replicas[collector_idx].replica; var s' := ps'.replicas[collector_idx].replica; var es := s.proposer.election_state; var es' := s'.proposer.election_state; assert LReplicaNextReadClockCheckForQuorumOfViewSuspicions(s, s', SpontaneousClock(ios), ExtractSentPacketsFromIos(ios)); assert LProposerCheckForQuorumOfViewSuspicions(s.proposer, s'.proposer, ios[0].t); assert ElectionStateCheckForQuorumOfViewSuspicions(es, es', ios[0].t); SubsetCardinality(asp.live_quorum, es.current_view_suspectors); lemma_OverflowProtectionNotUsedForReplica(b, asp, action_step, collector_idx); assert es'.current_view == ComputeSuccessorView(es.current_view, es.constants.all); } lemma lemma_IfAllLiveReplicasInViewOneWillReachSuccessor( b:Behavior, asp:AssumptionParameters, processing_sync_start:int, processing_bound:int, view:Ballot, start_step:int ) returns ( step:int, replica_index:int ) requires LivenessAssumptions(b, asp) requires PacketProcessingSynchronous(b, asp, processing_sync_start, processing_bound) requires 0 <= processing_sync_start <= start_step requires IsValidBallot(view, asp.c) requires BallotHasSuccessor(view, asp.c) requires forall idx :: idx in asp.live_quorum ==> 0 <= idx < |b[start_step].replicas| && CurrentViewOfHost(b[start_step], idx) == view ensures processing_sync_start <= step ensures replica_index in asp.live_quorum ensures 0 <= replica_index < |b[step].replicas| ensures BalLt(view, CurrentViewOfHost(b[step], replica_index)) { lemma_ConstantsAllConsistent(b, asp.c, start_step); var collector_idx :| collector_idx in asp.live_quorum; var first_step := lemma_SuspicionOfLiveReplicasEventuallyPropagatedToObserverForever(b, asp, processing_sync_start, processing_bound, collector_idx, asp.live_quorum, view, start_step); var action_step := lemma_ReplicaNextPerformsSubactionSoon(b, asp, first_step, collector_idx, 8); assert SpecificClockReadingRslActionOccurs(b[action_step], b[action_step+1], LReplicaNextReadClockCheckForQuorumOfViewSuspicions, collector_idx); var ios :| && RslNextOneReplica(b[action_step], b[action_step+1], collector_idx, ios) && SpontaneousIos(ios, 1) && LReplicaNextReadClockCheckForQuorumOfViewSuspicions(b[action_step].replicas[collector_idx].replica, b[action_step+1].replicas[collector_idx].replica, SpontaneousClock(ios), ExtractSentPacketsFromIos(ios)); lemma_ConstantsAllConsistent(b, asp.c, action_step); if exists ridx :: ridx in asp.live_quorum && BalLt(view, CurrentViewOfHost(b[action_step], ridx)) { step := action_step; replica_index :| replica_index in asp.live_quorum && BalLt(view, CurrentViewOfHost(b[action_step], replica_index)); return; } assert !BalLt(view, CurrentViewOfHost(b[action_step], collector_idx)); lemma_BalLtProperties(); forall suspector_idx | suspector_idx in asp.live_quorum ensures suspector_idx in b[action_step].replicas[collector_idx].replica.proposer.election_state.current_view_suspectors { TemporalDeduceFromAlways(first_step, action_step, SuspicionPropagatedToObserverTemporal(b, suspector_idx, collector_idx, view)); lemma_ViewPlusOfHostMonotonic(b, asp, suspector_idx, start_step, action_step); assert !BalLt(view, CurrentViewOfHost(b[action_step], suspector_idx)); } lemma_ViewPlusOfHostMonotonic(b, asp, collector_idx, start_step, action_step); step := action_step + 1; replica_index := collector_idx; lemma_IfReplicaHasCollectedSuspicionsFromLiveQuorumItWillAdvanceView(b, asp, collector_idx, view, action_step, ios); } lemma lemma_IfOneLiveReplicaReachesViewOneWillReachSuccessor( b:Behavior, asp:AssumptionParameters, processing_sync_start:int, processing_bound:int, view:Ballot, start_step:int, cur_index:int ) returns ( step:int, replica_index:int ) requires LivenessAssumptions(b, asp) requires PacketProcessingSynchronous(b, asp, processing_sync_start, processing_bound) requires 0 <= processing_sync_start <= start_step requires cur_index in asp.live_quorum requires IsValidBallot(view, asp.c) requires BallotHasSuccessor(view, asp.c) requires 0 <= cur_index < |b[start_step].replicas| requires BalLeq(view, CurrentViewOfHost(b[start_step], cur_index)) ensures processing_sync_start <= step ensures replica_index in asp.live_quorum ensures 0 <= replica_index < |b[step].replicas| ensures BalLt(view, CurrentViewOfHost(b[step], replica_index)) { if CurrentViewOfHost(b[start_step], cur_index) != view { step := start_step; replica_index := cur_index; lemma_BalLtProperties(); return; } assert CurrentViewOfHost(b[start_step], cur_index) == view; var first_step := lemma_OneLiveReplicaSoonAdvancesAllForever(b, asp, processing_sync_start, processing_bound, start_step, cur_index); lemma_ConstantsAllConsistent(b, asp.c, first_step); if exists ridx :: ridx in asp.live_quorum && BalLt(view, CurrentViewOfHost(b[first_step], ridx)) { step := first_step; replica_index :| replica_index in asp.live_quorum && BalLt(view, CurrentViewOfHost(b[first_step], replica_index)); return; } forall ridx | ridx in asp.live_quorum ensures CurrentViewOfHost(b[first_step], ridx) == view { TemporalDeduceFromAlways(first_step, first_step, HostReachedViewTemporal(b, ridx, view)); assert !BalLt(view, CurrentViewOfHost(b[first_step], ridx)); } step, replica_index := lemma_IfAllLiveReplicasInViewOneWillReachSuccessor(b, asp, processing_sync_start, processing_bound, view, first_step); } lemma lemma_SomeReplicaInLiveQuorumReachesView( b:Behavior, asp:AssumptionParameters, processing_sync_start:int, processing_bound:int, view:Ballot ) returns ( step:int, replica_index:int ) requires LivenessAssumptions(b, asp) requires PacketProcessingSynchronous(b, asp, processing_sync_start, processing_bound) requires 0 <= processing_sync_start requires IsValidBallot(view, asp.c) requires LeqUpperBound(view.seqno, asp.c.params.max_integer_val) ensures processing_sync_start <= step ensures replica_index in asp.live_quorum ensures 0 <= replica_index < |b[step].replicas| ensures BalLeq(view, CurrentViewOfHost(b[step], replica_index)) decreases CanonicalizeBallot(view, asp.c) { lemma_CanonicalizeBallotProperties(); var cview := CanonicalizeBallot(view, asp.c); if cview <= 1 { replica_index :| replica_index in asp.live_quorum; lemma_ConstantsAllConsistent(b, asp.c, 0); calc { CanonicalizeBallot(CurrentViewOfHost(b[0], replica_index), asp.c); CanonicalizeBallot(Ballot(1, 0), asp.c); { reveal_CanonicalizeBallot(); } |asp.c.config.replica_ids|; >= 1; >= cview; } lemma_IsValidBallot(b, asp, 0, replica_index); assert BalLeq(view, CurrentViewOfHost(b[0], replica_index)); step := processing_sync_start; lemma_ConstantsAllConsistent(b, asp.c, step); lemma_ViewPlusOfHostMonotonic(b, asp, replica_index, 0, step); } else { var previousView := ComputePredecessorView(view, asp.c); lemma_ComputePredecessorViewProperties(view, asp.c); var first_step, cur_index := lemma_SomeReplicaInLiveQuorumReachesView(b, asp, processing_sync_start, processing_bound, previousView); lemma_ConstantsAllConsistent(b, asp.c, first_step); step, replica_index := lemma_IfOneLiveReplicaReachesViewOneWillReachSuccessor(b, asp, processing_sync_start, processing_bound, previousView, first_step, cur_index); lemma_ConstantsAllConsistent(b, asp.c, step); lemma_IsValidBallot(b, asp, step, replica_index); lemma_NothingBetweenViewAndSuccessor(previousView, CurrentViewOfHost(b[step], replica_index), asp.c); lemma_BalLtProperties(); } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/LivenessProof/WF1.i.dfy ================================================ include "Invariants.i.dfy" include "RealTime.i.dfy" include "../../../Common/Logic/Temporal/WF1.i.dfy" include "../CommonProof/Actions.i.dfy" module LivenessProof__WF1_i { import opened LiveRSL__DistributedSystem_i import opened LivenessProof__Assumptions_i import opened LivenessProof__Invariants_i import opened LivenessProof__RealTime_i import opened CommonProof__Actions_i import opened Temporal__Rules_i import opened Temporal__Temporal_s import opened Temporal__Time_s import opened Temporal__Time_i import opened Temporal__WF1_i import opened Collections__Maps2_i lemma lemma_EstablishRequirementsForWF1RealTimeDelayed( b:Behavior, asp:AssumptionParameters, i:int, action:temporal, span:int ) requires LivenessAssumptions(b, asp) requires asp.synchrony_start <= i requires sat(asp.synchrony_start, always(eventuallynextwithin(action, span, PaxosTimeMap(b)))) ensures sat(i, always(eventuallynextwithin(action, span, PaxosTimeMap(b)))) ensures monotonic_from(0, PaxosTimeMap(b)) ensures TimeNotZeno(PaxosTimeMap(b)) { lemma_TimeMonotonicFromInvariantHolds(b, asp, 0); lemma_AfterForm(b, asp); Lemma_AlwaysImpliesLaterAlways(asp.synchrony_start, i, eventuallynextwithin(action, span, PaxosTimeMap(b))); reveal eventual(); reveal after(); } lemma lemma_EstablishRequirementsForWF1RealTime( b:Behavior, asp:AssumptionParameters, i:int, action:temporal, span:int ) requires LivenessAssumptions(b, asp) requires asp.synchrony_start <= i requires sat(asp.synchrony_start, always(eventuallynextwithin(action, span, PaxosTimeMap(b)))) ensures sat(i, always(eventuallynextwithin(action, span, PaxosTimeMap(b)))) ensures monotonic_from(i, PaxosTimeMap(b)) { lemma_TimeMonotonicFromInvariantHolds(b, asp, i); Lemma_AlwaysImpliesLaterAlways(asp.synchrony_start, i, eventuallynextwithin(action, span, PaxosTimeMap(b))); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/Message.i.dfy ================================================ include "Types.i.dfy" module LiveRSL__Message_i { import opened LiveRSL__Types_i import opened AppStateMachine_s // TODO put to/from header in every message datatype RslMessage = RslMessage_Invalid() | RslMessage_Request(seqno_req:int, val:AppRequest) | RslMessage_1a(bal_1a:Ballot) | RslMessage_1b(bal_1b:Ballot, log_truncation_point:OperationNumber, votes:Votes) | RslMessage_2a(bal_2a:Ballot, opn_2a:OperationNumber, val_2a:RequestBatch) | RslMessage_2b(bal_2b:Ballot, opn_2b:OperationNumber, val_2b:RequestBatch) | RslMessage_Heartbeat(bal_heartbeat:Ballot, suspicious:bool, opn_ckpt:OperationNumber) | RslMessage_Reply(seqno_reply:int, reply:AppReply) | RslMessage_AppStateRequest(bal_state_req:Ballot, opn_state_req:OperationNumber) | RslMessage_AppStateSupply(bal_state_supply:Ballot, opn_state_supply:OperationNumber, app_state:AppState) | RslMessage_StartingPhase2(bal_2:Ballot, logTruncationPoint_2:OperationNumber) } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/Parameters.i.dfy ================================================ include "../Common/UpperBound.s.dfy" module LiveRSL__Parameters_i { import opened Common__UpperBound_s datatype LParameters = LParameters( max_log_length:int, baseline_view_timeout_period:int, heartbeat_period:int, max_integer_val:UpperBound, max_batch_size:int, max_batch_delay:int ) predicate WFLParameters(p:LParameters) { && p.max_log_length > 0 && p.baseline_view_timeout_period > 0 && p.heartbeat_period > 0 && (p.max_integer_val.UpperBoundFinite? ==> p.max_integer_val.n > p.max_log_length) && p.max_batch_size > 0 && p.max_batch_delay >= 0 } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/Proposer.i.dfy ================================================ include "Configuration.i.dfy" include "Environment.i.dfy" include "Constants.i.dfy" include "Broadcast.i.dfy" include "Election.i.dfy" include "Acceptor.i.dfy" module LiveRSL__Proposer_i { import opened LiveRSL__Configuration_i import opened LiveRSL__Environment_i import opened LiveRSL__Constants_i import opened LiveRSL__Broadcast_i import opened LiveRSL__Acceptor_i import opened LiveRSL__Election_i import opened LiveRSL__Types_i import opened LiveRSL__Message_i import opened Concrete_NodeIdentity_i import opened Common__UpperBound_s /////////////////////////////////// // DATATYPE DEFINITION /////////////////////////////////// datatype IncompleteBatchTimer = IncompleteBatchTimerOn(when:int) | IncompleteBatchTimerOff() datatype LProposer = LProposer( constants:LReplicaConstants, // The replica constants, duplicated here for convenience current_state:int, // What state the proposer is in: // 0 = not leader // 1 = leader in phase 1 // 2 = leader in phase 2 request_queue:seq, // Values that clients have requested that I need to eventually // propose, in the order I should propose them max_ballot_i_sent_1a:Ballot, // The maximum ballot I've sent a 1a message for next_operation_number_to_propose:int, // The next operation number I should propose received_1b_packets:set, // The set of 1b messages I've received concerning max_ballot_i_sent_1a highest_seqno_requested_by_client_this_view:map, // For each client, the highest sequence number for a request // I proposed in max_ballot_i_sent_1a incomplete_batch_timer:IncompleteBatchTimer, // If the incomplete batch timer is set, it indicates when I should // give up on trying to amass a full-size batch and just propose // whatever I have. If it's not set, I shouldn't propose an // incomplete batch. election_state:ElectionState // State for view change election management ) /////////////////////////////////// // HELPER FUNCTIONS /////////////////////////////////// predicate LIsAfterLogTruncationPoint(opn:OperationNumber, received_1b_packets:set) { (forall p :: p in received_1b_packets && p.msg.RslMessage_1b? ==> p.msg.log_truncation_point <= opn) } predicate LSetOfMessage1b(S:set) { forall p :: p in S ==> p.msg.RslMessage_1b? } predicate LSetOfMessage1bAboutBallot(S:set, b:Ballot) { && LSetOfMessage1b(S) && (forall p :: p in S ==> p.msg.bal_1b == b) } predicate LAllAcceptorsHadNoProposal(S:set, opn:OperationNumber) requires LSetOfMessage1b(S) { forall p :: p in S ==> !(opn in p.msg.votes) } predicate LMaxBallotInS(c:Ballot, S:set, opn:OperationNumber) requires LSetOfMessage1b(S) { forall p :: p in S && opn in p.msg.votes ==> BalLeq(p.msg.votes[opn].max_value_bal, c) } predicate LExistsBallotInS(v:RequestBatch, c:Ballot, S:set, opn:OperationNumber) requires LSetOfMessage1b(S) { exists p :: && p in S && opn in p.msg.votes && p.msg.votes[opn].max_value_bal==c && p.msg.votes[opn].max_val==v } predicate LValIsHighestNumberedProposalAtBallot(v:RequestBatch, c:Ballot, S:set, opn:OperationNumber) requires LSetOfMessage1b(S) { && LMaxBallotInS(c, S, opn) && LExistsBallotInS(v, c, S, opn) } predicate LValIsHighestNumberedProposal(v:RequestBatch, S:set, opn:OperationNumber) requires LSetOfMessage1b(S) { exists c :: LValIsHighestNumberedProposalAtBallot(v, c, S, opn) } predicate LProposerCanNominateUsingOperationNumber(s:LProposer, log_truncation_point:OperationNumber, opn:OperationNumber) { && s.election_state.current_view == s.max_ballot_i_sent_1a && s.current_state == 2 && |s.received_1b_packets| >= LMinQuorumSize(s.constants.all.config) && LSetOfMessage1bAboutBallot(s.received_1b_packets, s.max_ballot_i_sent_1a) // Don't try to nominate for an operation that's already been truncated into history: && LIsAfterLogTruncationPoint(opn, s.received_1b_packets) // Don't try to nominate in an operation that's too far in the future; that would grow the log too much. && opn < UpperBoundedAddition(log_truncation_point, s.constants.all.params.max_log_length, s.constants.all.params.max_integer_val) // Disallow negative operations && opn >= 0 // It must be possible to add one and still be representable, so we can compute next_operation_number_to_propose && LtUpperBound(opn, s.constants.all.params.max_integer_val) } /////////////////////////////////// // INITIALIZATION /////////////////////////////////// predicate LProposerInit(s:LProposer, c:LReplicaConstants) requires WellFormedLConfiguration(c.all.config) { && s.constants == c && s.current_state == 0 && s.request_queue == [] && s.max_ballot_i_sent_1a == Ballot(0, c.my_index) && s.next_operation_number_to_propose == 0 && s.received_1b_packets == {} && s.highest_seqno_requested_by_client_this_view == map[] && ElectionStateInit(s.election_state, c) && s.incomplete_batch_timer.IncompleteBatchTimerOff? } /////////////////////////////////// // ACTIONS /////////////////////////////////// predicate LProposerProcessRequest(s:LProposer, s':LProposer, packet:RslPacket) requires packet.msg.RslMessage_Request? { var val := Request(packet.src, packet.msg.seqno_req, packet.msg.val); && ElectionStateReflectReceivedRequest(s.election_state, s'.election_state, val) && if && s.current_state != 0 && (|| val.client !in s.highest_seqno_requested_by_client_this_view || val.seqno > s.highest_seqno_requested_by_client_this_view[val.client]) then s' == s.(election_state := s'.election_state, request_queue := s.request_queue + [val], highest_seqno_requested_by_client_this_view := s.highest_seqno_requested_by_client_this_view[val.client := val.seqno]) else s' == s.(election_state := s'.election_state) } predicate LProposerMaybeEnterNewViewAndSend1a(s:LProposer, s':LProposer, sent_packets:seq) { if && s.election_state.current_view.proposer_id == s.constants.my_index && BalLt(s.max_ballot_i_sent_1a, s.election_state.current_view) then && s' == s.(current_state := 1, max_ballot_i_sent_1a := s.election_state.current_view, received_1b_packets := {}, highest_seqno_requested_by_client_this_view := map[], request_queue := s.election_state.requests_received_prev_epochs + s.election_state.requests_received_this_epoch) && LBroadcastToEveryone(s.constants.all.config, s.constants.my_index, RslMessage_1a(s.election_state.current_view), sent_packets) else s' == s && sent_packets == [] } predicate LProposerProcess1b(s:LProposer, s':LProposer, p:RslPacket) requires p.msg.RslMessage_1b? requires p.src in s.constants.all.config.replica_ids requires p.msg.bal_1b == s.max_ballot_i_sent_1a requires s.current_state == 1 requires forall other_packet :: other_packet in s.received_1b_packets ==> other_packet.src != p.src { s' == s.(received_1b_packets := s.received_1b_packets + { p }) } predicate LProposerMaybeEnterPhase2(s:LProposer, s':LProposer, log_truncation_point:OperationNumber, sent_packets:seq) { if && |s.received_1b_packets| >= LMinQuorumSize(s.constants.all.config) && LSetOfMessage1bAboutBallot(s.received_1b_packets, s.max_ballot_i_sent_1a) && s.current_state == 1 then && s' == s.(current_state := 2, next_operation_number_to_propose := log_truncation_point) && LBroadcastToEveryone(s.constants.all.config, s.constants.my_index, RslMessage_StartingPhase2(s.max_ballot_i_sent_1a, log_truncation_point), sent_packets) else s' == s && sent_packets == [] } predicate LProposerNominateNewValueAndSend2a(s:LProposer, s':LProposer, clock:int, log_truncation_point:OperationNumber, sent_packets:seq) requires LProposerCanNominateUsingOperationNumber(s, log_truncation_point, s.next_operation_number_to_propose) requires LAllAcceptorsHadNoProposal(s.received_1b_packets, s.next_operation_number_to_propose) { var batchSize := if |s.request_queue| <= s.constants.all.params.max_batch_size || s.constants.all.params.max_batch_size < 0 then |s.request_queue| else s.constants.all.params.max_batch_size; var v := s.request_queue[..batchSize]; var opn := s.next_operation_number_to_propose; && s' == s.(request_queue := s.request_queue[batchSize..], next_operation_number_to_propose := s.next_operation_number_to_propose + 1, incomplete_batch_timer := if |s.request_queue| > batchSize then IncompleteBatchTimerOn(UpperBoundedAddition(clock, s.constants.all.params.max_batch_delay, s.constants.all.params.max_integer_val)) else IncompleteBatchTimerOff()) && LBroadcastToEveryone(s.constants.all.config, s.constants.my_index, RslMessage_2a(s.max_ballot_i_sent_1a, opn, v), sent_packets) } predicate LProposerNominateOldValueAndSend2a(s:LProposer, s':LProposer, log_truncation_point:OperationNumber, sent_packets:seq) requires LProposerCanNominateUsingOperationNumber(s, log_truncation_point, s.next_operation_number_to_propose) requires !LAllAcceptorsHadNoProposal(s.received_1b_packets, s.next_operation_number_to_propose) { var opn := s.next_operation_number_to_propose; exists v :: && LValIsHighestNumberedProposal(v, s.received_1b_packets, opn) && s' == s.(next_operation_number_to_propose := s.next_operation_number_to_propose + 1) && LBroadcastToEveryone(s.constants.all.config, s.constants.my_index, RslMessage_2a(s.max_ballot_i_sent_1a, opn, v), sent_packets) } predicate LProposerMaybeNominateValueAndSend2a(s:LProposer, s':LProposer, clock:int, log_truncation_point:int, sent_packets:seq) { if !LProposerCanNominateUsingOperationNumber(s, log_truncation_point, s.next_operation_number_to_propose) then s' == s && sent_packets == [] else if !LAllAcceptorsHadNoProposal(s.received_1b_packets, s.next_operation_number_to_propose) then LProposerNominateOldValueAndSend2a(s, s', log_truncation_point, sent_packets) else if || (exists opn :: opn > s.next_operation_number_to_propose && !LAllAcceptorsHadNoProposal(s.received_1b_packets, opn)) || |s.request_queue| >= s.constants.all.params.max_batch_size || (|s.request_queue| > 0 && s.incomplete_batch_timer.IncompleteBatchTimerOn? && clock >= s.incomplete_batch_timer.when) then LProposerNominateNewValueAndSend2a(s, s', clock, log_truncation_point, sent_packets) else if |s.request_queue| > 0 && s.incomplete_batch_timer.IncompleteBatchTimerOff? then && s' == s.(incomplete_batch_timer := IncompleteBatchTimerOn(UpperBoundedAddition(clock, s.constants.all.params.max_batch_delay, s.constants.all.params.max_integer_val))) && sent_packets == [] else s' == s && sent_packets == [] } predicate LProposerProcessHeartbeat(s:LProposer, s':LProposer, p:RslPacket, clock:int) requires p.msg.RslMessage_Heartbeat? { && ElectionStateProcessHeartbeat(s.election_state, s'.election_state, p, clock) && (if BalLt(s.election_state.current_view, s'.election_state.current_view) then s'.current_state == 0 && s'.request_queue == [] else s'.current_state == s.current_state && s'.request_queue == s.request_queue ) && s' == s.(election_state := s'.election_state, current_state := s'.current_state, request_queue := s'.request_queue) } predicate LProposerCheckForViewTimeout(s:LProposer, s':LProposer, clock:int) { && ElectionStateCheckForViewTimeout(s.election_state, s'.election_state, clock) && s' == s.(election_state := s'.election_state) } predicate LProposerCheckForQuorumOfViewSuspicions(s:LProposer, s':LProposer, clock:int) { && ElectionStateCheckForQuorumOfViewSuspicions(s.election_state, s'.election_state, clock) && (if BalLt(s.election_state.current_view, s'.election_state.current_view) then s'.current_state == 0 && s'.request_queue == [] else s'.current_state == s.current_state && s'.request_queue == s.request_queue ) && s' == s.(election_state := s'.election_state, current_state := s'.current_state, request_queue := s'.request_queue) } predicate LProposerResetViewTimerDueToExecution(s:LProposer, s':LProposer, val:RequestBatch) { && ElectionStateReflectExecutedRequestBatch(s.election_state, s'.election_state, val) && s' == s.(election_state := s'.election_state) } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/RefinementProof/Chosen.i.dfy ================================================ include "../DistributedSystem.i.dfy" include "../CommonProof/Constants.i.dfy" include "../CommonProof/Actions.i.dfy" include "../CommonProof/PacketSending.i.dfy" include "../CommonProof/Chosen.i.dfy" include "../../../Common/Collections/Seqs.s.dfy" include "../../../Common/Collections/Sets.i.dfy" include "HandleRequestBatch.i.dfy" module DirectRefinement__Chosen_i { import opened LiveRSL__Constants_i import opened LiveRSL__DistributedSystem_i import opened LiveRSL__StateMachine_i import opened LiveRSL__Types_i import opened CommonProof__Actions_i import opened CommonProof__Assumptions_i import opened CommonProof__Chosen_i import opened CommonProof__Constants_i import opened CommonProof__Environment_i import opened CommonProof__PacketSending_i import opened Collections__Seqs_s import opened Collections__Sets_i import opened DirectRefinement__HandleRequestBatch_i import opened Temporal__Temporal_s predicate IsValidQuorumOf2bsSequence(ps:RslState, qs:seq) { forall opn :: 0 <= opn < |qs| ==> qs[opn].opn == opn && IsValidQuorumOf2bs(ps, qs[opn]) } predicate IsMaximalQuorumOf2bsSequence(ps:RslState, qs:seq) { && IsValidQuorumOf2bsSequence(ps, qs) && !exists q :: IsValidQuorumOf2bs(ps, q) && q.opn == |qs| } function GetSequenceOfRequestBatches(qs:seq):seq ensures |GetSequenceOfRequestBatches(qs)| == |qs| { if |qs| == 0 then [] else GetSequenceOfRequestBatches(all_but_last(qs)) + [last(qs).v] } lemma lemma_SequenceOfRequestBatchesNthElement(qs:seq, n:int) requires 0 <= n < |qs| ensures GetSequenceOfRequestBatches(qs)[n] == qs[n].v { if n < |qs| - 1 { lemma_SequenceOfRequestBatchesNthElement(all_but_last(qs), n); } } lemma lemma_GetUpperBoundOnQuorumOf2bsOperationNumber( b:Behavior, c:LConstants, i:int ) returns ( bound:OperationNumber ) requires IsValidBehaviorPrefix(b, c, i) ensures bound >= 0 ensures !exists q :: IsValidQuorumOf2bs(b[i], q) && q.opn == bound { var opns := set p | p in b[i].environment.sentPackets && p.msg.RslMessage_2b? :: p.msg.opn_2b; bound := if |opns| > 0 && intsetmax(opns) >= 0 then intsetmax(opns) + 1 else 1; if exists q :: IsValidQuorumOf2bs(b[i], q) && q.opn == bound { var q :| IsValidQuorumOf2bs(b[i], q) && q.opn == bound; var idx :| idx in q.indices; var p := q.packets[idx]; assert p.msg.opn_2b in opns; assert p.msg.opn_2b > intsetmax(opns); assert p.msg.opn_2b in opns; assert false; } } lemma lemma_GetMaximalQuorumOf2bsSequenceWithinBound( b:Behavior, c:LConstants, i:int, bound:OperationNumber ) returns ( qs:seq ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= bound ensures IsValidQuorumOf2bsSequence(b[i], qs) ensures |qs| == bound || !exists q :: IsValidQuorumOf2bs(b[i], q) && q.opn == |qs| { if bound == 0 { qs := []; return; } qs := lemma_GetMaximalQuorumOf2bsSequenceWithinBound(b, c, i, bound-1); if !exists q :: IsValidQuorumOf2bs(b[i], q) && q.opn == |qs| { return; } assert |qs| == bound - 1; var q :| IsValidQuorumOf2bs(b[i], q) && q.opn == bound - 1; qs := qs + [q]; } lemma lemma_GetMaximalQuorumOf2bsSequence( b:Behavior, c:LConstants, i:int ) returns ( qs:seq ) requires IsValidBehaviorPrefix(b, c, i) ensures IsMaximalQuorumOf2bsSequence(b[i], qs) { var bound := lemma_GetUpperBoundOnQuorumOf2bsOperationNumber(b, c, i); qs := lemma_GetMaximalQuorumOf2bsSequenceWithinBound(b, c, i, bound); } lemma lemma_IfValidQuorumOf2bsSequenceNowThenNext( b:Behavior, c:LConstants, i:int, qs:seq ) requires IsValidBehaviorPrefix(b, c, i+1) requires 0 <= i requires IsValidQuorumOf2bsSequence(b[i], qs) ensures IsValidQuorumOf2bsSequence(b[i+1], qs) { lemma_ConstantsAllConsistent(b, c, i); lemma_ConstantsAllConsistent(b, c, i+1); forall opn | 0 <= opn < |qs| ensures qs[opn].opn == opn ensures IsValidQuorumOf2bs(b[i+1], qs[opn]) { assert qs[opn].opn == opn && IsValidQuorumOf2bs(b[i], qs[opn]); forall idx | idx in qs[opn].indices ensures qs[opn].packets[idx] in b[i+1].environment.sentPackets { lemma_PacketStaysInSentPackets(b, c, i, i+1, qs[opn].packets[idx]); } } } lemma lemma_TwoMaximalQuorumsOf2bsMatch( b:Behavior, c:LConstants, i:int, qs1:seq, qs2:seq ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires IsMaximalQuorumOf2bsSequence(b[i], qs1) requires IsMaximalQuorumOf2bsSequence(b[i], qs2) ensures GetSequenceOfRequestBatches(qs1) == GetSequenceOfRequestBatches(qs2) { var batches1 := GetSequenceOfRequestBatches(qs1); var batches2 := GetSequenceOfRequestBatches(qs2); if |qs1| > |qs2| { assert IsValidQuorumOf2bs(b[i], qs1[|qs2|]) && qs1[|qs2|].opn == |qs2|; assert false; } if |qs2| > |qs1| { assert IsValidQuorumOf2bs(b[i], qs2[|qs1|]) && qs2[|qs1|].opn == |qs1|; assert false; } forall opn | 0 <= opn < |qs1| ensures batches1[opn] == batches2[opn] { lemma_ChosenQuorumsMatchValue(b, c, i, qs1[opn], qs2[opn]); lemma_SequenceOfRequestBatchesNthElement(qs1, opn); lemma_SequenceOfRequestBatchesNthElement(qs2, opn); } } lemma lemma_RegularQuorumOf2bSequenceIsPrefixOfMaximalQuorumOf2bSequence( b:Behavior, c:LConstants, i:int, qs_regular:seq, qs_maximal:seq ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires IsValidQuorumOf2bsSequence(b[i], qs_regular) requires IsMaximalQuorumOf2bsSequence(b[i], qs_maximal) ensures |GetSequenceOfRequestBatches(qs_regular)| <= |GetSequenceOfRequestBatches(qs_maximal)| ensures GetSequenceOfRequestBatches(qs_regular) == GetSequenceOfRequestBatches(qs_maximal)[..|GetSequenceOfRequestBatches(qs_regular)|] { var batches1 := GetSequenceOfRequestBatches(qs_regular); var batches2 := GetSequenceOfRequestBatches(qs_maximal); if |qs_regular| > |qs_maximal| { assert IsValidQuorumOf2bs(b[i], qs_regular[|qs_maximal|]) && qs_regular[|qs_maximal|].opn == |qs_maximal|; assert false; } forall opn | 0 <= opn < |qs_regular| ensures batches1[opn] == batches2[opn] { lemma_ChosenQuorumsMatchValue(b, c, i, qs_regular[opn], qs_maximal[opn]); lemma_SequenceOfRequestBatchesNthElement(qs_regular, opn); lemma_SequenceOfRequestBatchesNthElement(qs_maximal, opn); } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/RefinementProof/Execution.i.dfy ================================================ include "../DistributedSystem.i.dfy" include "../CommonProof/Assumptions.i.dfy" include "../CommonProof/Constants.i.dfy" include "../CommonProof/Actions.i.dfy" include "../CommonProof/Environment.i.dfy" include "../CommonProof/PacketSending.i.dfy" include "../CommonProof/Chosen.i.dfy" include "Chosen.i.dfy" module DirectRefinement__Execution_i { import opened LiveRSL__Configuration_i import opened LiveRSL__Constants_i import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Environment_i import opened LiveRSL__Message_i import opened LiveRSL__Executor_i import opened LiveRSL__Replica_i import opened LiveRSL__StateMachine_i import opened LiveRSL__Types_i import opened Concrete_NodeIdentity_i import opened CommonProof__Assumptions_i import opened CommonProof__Actions_i import opened CommonProof__Chosen_i import opened CommonProof__Constants_i import opened CommonProof__Environment_i import opened CommonProof__PacketSending_i import opened DirectRefinement__Chosen_i import opened DirectRefinement__HandleRequestBatch_i import opened Environment_s import opened Temporal__Temporal_s import opened Common__UpperBound_s import opened Collections__Seqs_s ////////////////////////////// // APP STATE ////////////////////////////// lemma lemma_AppStateAlwaysValid( b:Behavior, c:LConstants, i:int, idx:int ) returns ( qs:seq ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires 0 <= idx < |b[i].replicas| ensures IsValidQuorumOf2bsSequence(b[i], qs) ensures |qs| == b[i].replicas[idx].replica.executor.ops_complete ensures b[i].replicas[idx].replica.executor.app == GetAppStateFromRequestBatches(GetSequenceOfRequestBatches(qs)) decreases i { if i == 0 { qs := []; return; } lemma_ReplicaConstantsAllConsistent(b, c, i, idx); lemma_ReplicaConstantsAllConsistent(b, c, i-1, idx); lemma_AssumptionsMakeValidTransition(b, c, i-1); var s := b[i-1].replicas[idx].replica.executor; var s' := b[i].replicas[idx].replica.executor; if s'.ops_complete == s.ops_complete { qs := lemma_AppStateAlwaysValid(b, c, i-1, idx); lemma_IfValidQuorumOf2bsSequenceNowThenNext(b, c, i-1, qs); return; } var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, c, i-1, idx); if b[i-1].replicas[idx].nextActionIndex == 0 { var p := ios[0].r; qs := lemma_TransferredStateAlwaysValid(b, c, i-1, p); return; } var prev_qs := lemma_AppStateAlwaysValid(b, c, i-1, idx); var q := lemma_DecidedOperationWasChosen(b, c, i-1, idx); qs := prev_qs + [q]; assert GetSequenceOfRequestBatches(qs) == GetSequenceOfRequestBatches(prev_qs) + [q.v]; } lemma lemma_TransferredStateAlwaysValid( b:Behavior, c:LConstants, i:int, p:RslPacket ) returns ( qs:seq ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires p in b[i].environment.sentPackets requires p.src in c.config.replica_ids requires p.msg.RslMessage_AppStateSupply? ensures IsValidQuorumOf2bsSequence(b[i], qs) ensures |qs| == p.msg.opn_state_supply ensures p.msg.app_state == GetAppStateFromRequestBatches(GetSequenceOfRequestBatches(qs)) decreases i { if i == 0 { return; } lemma_ConstantsAllConsistent(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i); if p in b[i-1].environment.sentPackets { qs := lemma_TransferredStateAlwaysValid(b, c, i-1, p); lemma_IfValidQuorumOf2bsSequenceNowThenNext(b, c, i-1, qs); return; } lemma_AssumptionsMakeValidTransition(b, c, i-1); var idx, ios := lemma_ActionThatSendsAppStateSupplyIsProcessAppStateRequest(b[i-1], b[i], p); qs := lemma_AppStateAlwaysValid(b, c, i-1, idx); } ////////////////////////////// // REPLY CACHE ////////////////////////////// lemma lemma_ReplyInReplyCacheIsAllowed( b:Behavior, c:LConstants, i:int, client:NodeIdentity, idx:int ) returns ( qs:seq, batches:seq, batch_num:int, req_num:int ) requires IsValidBehaviorPrefix(b, c, i+1) requires 0 <= i requires 0 <= idx < |c.config.replica_ids| requires 0 <= idx < |b[i].replicas| requires client in b[i].replicas[idx].replica.executor.reply_cache ensures IsValidQuorumOf2bsSequence(b[i], qs) ensures batches == GetSequenceOfRequestBatches(qs) ensures 0 <= batch_num < |batches| ensures 0 <= req_num < |batches[batch_num]| ensures b[i].replicas[idx].replica.executor.reply_cache[client] == GetReplyFromRequestBatches(batches, batch_num, req_num) decreases i { if i == 0 { return; } lemma_ConstantsAllConsistent(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i); lemma_AssumptionsMakeValidTransition(b, c, i-1); var s := b[i-1].replicas[idx].replica.executor; var s' := b[i].replicas[idx].replica.executor; if client in s.reply_cache && s'.reply_cache[client] == s.reply_cache[client] { qs, batches, batch_num, req_num := lemma_ReplyInReplyCacheIsAllowed(b, c, i-1, client, idx); return; } var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, c, i-1, idx); var nextActionIndex := b[i-1].replicas[idx].nextActionIndex; if nextActionIndex == 0 { var p := ios[0].r; return; } assert nextActionIndex == 6; var qs_prev := lemma_AppStateAlwaysValid(b, c, i-1, idx); var q := lemma_DecidedOperationWasChosen(b, c, i-1, idx); qs := qs_prev + [q]; batches := GetSequenceOfRequestBatches(qs); batch_num := |qs_prev|; assert GetSequenceOfRequestBatches(qs_prev) == batches[..batch_num]; assert s.app == GetAppStateFromRequestBatches(GetSequenceOfRequestBatches(qs_prev)); var batch := s.next_op_to_execute.v; var replies := HandleRequestBatch(s.app, batch).1; req_num :| 0 <= req_num < |batch| && replies[req_num].client == client && s'.reply_cache[client] == replies[req_num]; } ////////////////////////////// // REPLIES ////////////////////////////// lemma lemma_GetRequestIndexCorrespondingToPacketInGetPacketsFromReplies( p:RslPacket, me:NodeIdentity, requests:seq, replies:seq ) returns ( i:int ) requires |requests| == |replies| requires forall r :: r in replies ==> r.Reply? requires p in GetPacketsFromReplies(me, requests, replies) ensures 0 <= i < |requests| ensures p.src == me ensures p.dst == requests[i].client ensures p.msg.RslMessage_Reply? ensures p.msg.seqno_reply == requests[i].seqno ensures p.msg.reply == replies[i].reply { if |requests| == 0 { assert false; } if p == LPacket(requests[0].client, me, RslMessage_Reply(requests[0].seqno, replies[0].reply)) { i := 0; } else { var i_minus_1 := lemma_GetRequestIndexCorrespondingToPacketInGetPacketsFromReplies(p, me, requests[1..], replies[1..]); i := i_minus_1 + 1; } } lemma lemma_ReplySentViaExecutionIsAllowed( b:Behavior, c:LConstants, i:int, p:RslPacket, idx:int, ios:seq ) returns ( qs:seq, batches:seq, batch_num:int, req_num:int ) requires IsValidBehaviorPrefix(b, c, i+1) requires 0 <= i requires 0 <= idx < |c.config.replica_ids| requires 0 <= idx < |b[i].replicas| requires LIoOpSend(p) in ios requires RslNext(b[i], b[i+1]) requires b[i].environment.nextStep == LEnvStepHostIos(c.config.replica_ids[idx], ios) requires b[i].replicas[idx].replica.executor.next_op_to_execute.OutstandingOpKnown? requires LtUpperBound(b[i].replicas[idx].replica.executor.ops_complete, b[i].replicas[idx].replica.executor.constants.all.params.max_integer_val) requires LReplicaConstantsValid(b[i].replicas[idx].replica.executor.constants) requires LExecutorExecute(b[i].replicas[idx].replica.executor, b[i+1].replicas[idx].replica.executor, ExtractSentPacketsFromIos(ios)) ensures IsValidQuorumOf2bsSequence(b[i], qs) ensures batches == GetSequenceOfRequestBatches(qs) ensures 0 <= batch_num < |batches| ensures 0 <= req_num < |batches[batch_num]| ensures Reply(p.dst, p.msg.seqno_reply, p.msg.reply) == GetReplyFromRequestBatches(batches, batch_num, req_num) { lemma_ReplicaConstantsAllConsistent(b, c, i, idx); lemma_ReplicaConstantsAllConsistent(b, c, i+1, idx); var qs_prev := lemma_AppStateAlwaysValid(b, c, i, idx); var q := lemma_DecidedOperationWasChosen(b, c, i, idx); qs := qs_prev + [q]; batches := GetSequenceOfRequestBatches(qs); batch_num := |qs_prev|; assert GetSequenceOfRequestBatches(qs_prev) == batches[..batch_num]; var s := b[i].replicas[idx].replica.executor; assert s.app == GetAppStateFromRequestBatches(GetSequenceOfRequestBatches(qs_prev)); var batch := s.next_op_to_execute.v; var temp := HandleRequestBatch(s.app, batch); lemma_HandleRequestBatchTriggerHappy(s.app, batch, temp.0, temp.1); var new_state := last(temp.0); var replies := temp.1; var me := c.config.replica_ids[idx]; assert p in GetPacketsFromReplies(me, batch, replies); assert p.src == c.config.replica_ids[idx]; req_num := lemma_GetRequestIndexCorrespondingToPacketInGetPacketsFromReplies(p, me, batch, replies); var reply := Reply(p.dst, p.msg.seqno_reply, p.msg.reply); assert reply == replies[req_num]; } lemma lemma_ReplySentIsAllowed( b:Behavior, c:LConstants, i:int, p:RslPacket ) returns ( qs:seq, batches:seq, batch_num:int, req_num:int ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires p in b[i].environment.sentPackets requires p.src in c.config.replica_ids requires p.msg.RslMessage_Reply? ensures IsValidQuorumOf2bsSequence(b[i], qs) ensures batches == GetSequenceOfRequestBatches(qs) ensures 0 <= batch_num < |batches| ensures 0 <= req_num < |batches[batch_num]| ensures Reply(p.dst, p.msg.seqno_reply, p.msg.reply) == GetReplyFromRequestBatches(batches, batch_num, req_num) decreases i { if i == 0 { return; } lemma_ConstantsAllConsistent(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i); lemma_AssumptionsMakeValidTransition(b, c, i-1); if p in b[i-1].environment.sentPackets { qs, batches, batch_num, req_num := lemma_ReplySentIsAllowed(b, c, i-1, p); lemma_IfValidQuorumOf2bsSequenceNowThenNext(b, c, i-1, qs); return; } assert b[i-1].environment.nextStep.LEnvStepHostIos?; assert LIoOpSend(p) in b[i-1].environment.nextStep.ios; var idx := GetReplicaIndex(b[i-1].environment.nextStep.actor, c.config); var ios := b[i-1].environment.nextStep.ios; var idx_alt :| RslNextOneReplica(b[i-1], b[i], idx_alt, ios); assert ReplicasDistinct(c.config.replica_ids, idx, idx_alt); var nextActionIndex := b[i-1].replicas[idx].nextActionIndex; if nextActionIndex == 0 { qs, batches, batch_num, req_num := lemma_ReplyInReplyCacheIsAllowed(b, c, i-1, ios[0].r.src, idx); lemma_IfValidQuorumOf2bsSequenceNowThenNext(b, c, i-1, qs); } else if nextActionIndex == 6 { qs, batches, batch_num, req_num := lemma_ReplySentViaExecutionIsAllowed(b, c, i-1, p, idx, ios); lemma_IfValidQuorumOf2bsSequenceNowThenNext(b, c, i-1, qs); } else { assert false; } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/RefinementProof/HandleRequestBatch.i.dfy ================================================ include "../DistributedSystem.i.dfy" include "../../../Common/Collections/Seqs.s.dfy" module DirectRefinement__HandleRequestBatch_i { import opened LiveRSL__DistributedSystem_i import opened LiveRSL__StateMachine_i import opened LiveRSL__Types_i import opened Collections__Seqs_s import opened AppStateMachine_s function GetAppStateFromRequestBatches(batches:seq):AppState { if |batches| == 0 then AppInitialize() else last(HandleRequestBatch(GetAppStateFromRequestBatches(all_but_last(batches)), last(batches)).0) } function GetReplyFromRequestBatches(batches:seq, batch_num:int, req_num:int):Reply requires 0 <= batch_num < |batches| requires 0 <= req_num < |batches[batch_num]| { var prev_state := GetAppStateFromRequestBatches(batches[..batch_num]); var result := HandleRequestBatch(prev_state, batches[batch_num]); result.1[req_num] } lemma lemma_GetReplyFromRequestBatchesMatchesInSubsequence(batches1:seq, batches2:seq, batch_num:int, req_num:int) requires 0 <= batch_num < |batches1| <= |batches2| requires batches1 == batches2[..|batches1|] requires 0 <= req_num < |batches1[batch_num]| ensures GetReplyFromRequestBatches(batches1, batch_num, req_num) == GetReplyFromRequestBatches(batches2, batch_num, req_num) { assert batches1[..batch_num] == batches2[..batch_num]; assert batches1[batch_num] == batches2[batch_num]; } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/RefinementProof/Refinement.i.dfy ================================================ include "StateMachine.i.dfy" include "HandleRequestBatch.i.dfy" include "Chosen.i.dfy" include "Execution.i.dfy" include "Requests.i.dfy" include "../DistributedSystem.i.dfy" include "../CommonProof/Chosen.i.dfy" include "../../../Common/Collections/Seqs.s.dfy" module DirectRefinement__Refinement_i { import opened DirectRefinement__StateMachine_i import opened DirectRefinement__HandleRequestBatch_i import opened DirectRefinement__Chosen_i import opened DirectRefinement__Execution_i import opened DirectRefinement__Requests_i import opened LiveRSL__Constants_i import opened LiveRSL__DistributedSystem_i import opened LiveRSL__StateMachine_i import opened LiveRSL__Types_i import opened Concrete_NodeIdentity_i import opened CommonProof__Assumptions_i import opened CommonProof__Chosen_i import opened CommonProof__Constants_i import opened Collections__Seqs_s import opened Collections__Sets_i import opened Collections__Maps2_s import opened Temporal__Temporal_s import opened AppStateMachine_s function GetServerAddresses(ps:RslState):set { MapSeqToSet(ps.constants.config.replica_ids, x=>x) } function ProduceIntermediateAbstractState(server_addresses:set, batches:seq, reqs_in_last_batch:int) :RSLSystemState requires |batches| > 0 requires 0 <= reqs_in_last_batch <= |last(batches)| { var requests := set batch_num, req_num | 0 <= batch_num < |batches| && 0 <= req_num < (if batch_num == |batches|-1 then reqs_in_last_batch else |batches[batch_num]|) :: batches[batch_num][req_num]; var replies := set batch_num, req_num | 0 <= batch_num < |batches| && 0 <= req_num < (if batch_num == |batches|-1 then reqs_in_last_batch else |batches[batch_num]|) :: GetReplyFromRequestBatches(batches, batch_num, req_num); var stateBeforePrevBatch := GetAppStateFromRequestBatches(all_but_last(batches)); var appStatesDuringBatch := HandleRequestBatch(stateBeforePrevBatch, last(batches)).0; RSLSystemState(server_addresses, appStatesDuringBatch[reqs_in_last_batch], requests, replies) } function ProduceAbstractState(server_addresses:set, batches:seq):RSLSystemState { var requests := set batch_num, req_num | 0 <= batch_num < |batches| && 0 <= req_num < |batches[batch_num]| :: batches[batch_num][req_num]; var replies := set batch_num, req_num | 0 <= batch_num < |batches| && 0 <= req_num < |batches[batch_num]| :: GetReplyFromRequestBatches(batches, batch_num, req_num); RSLSystemState(server_addresses, GetAppStateFromRequestBatches(batches), requests, replies) } predicate SystemRefinementRelation(ps:RslState, rs:RSLSystemState) { exists qs :: IsMaximalQuorumOf2bsSequence(ps, qs) && rs == ProduceAbstractState(GetServerAddresses(ps), GetSequenceOfRequestBatches(qs)) } lemma lemma_ProduceAbstractStateSatisfiesRefinementRelation( b:Behavior, c:LConstants, i:int, qs:seq, rs:RSLSystemState ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires IsMaximalQuorumOf2bsSequence(b[i], qs) requires rs == ProduceAbstractState(GetServerAddresses(b[i]), GetSequenceOfRequestBatches(qs)) ensures RslSystemRefinement(b[i], rs) { var ps := b[i]; var batches := GetSequenceOfRequestBatches(qs); lemma_ConstantsAllConsistent(b, c, i); forall p | p in ps.environment.sentPackets && p.src in rs.server_addresses && p.msg.RslMessage_Reply? ensures Reply(p.dst, p.msg.seqno_reply, p.msg.reply) in rs.replies { assert p.src in GetServerAddresses(ps); var qs', batches', batch_num, req_num := lemma_ReplySentIsAllowed(b, c, i, p); lemma_RegularQuorumOf2bSequenceIsPrefixOfMaximalQuorumOf2bSequence(b, c, i, qs', qs); lemma_GetReplyFromRequestBatchesMatchesInSubsequence(batches', batches, batch_num, req_num); } forall req | req in rs.requests ensures exists p :: && p in ps.environment.sentPackets && p.dst in rs.server_addresses && p.msg.RslMessage_Request? && req == Request(p.src, p.msg.seqno_req, p.msg.val); { var batch_num, req_num :| 0 <= batch_num < |batches| && 0 <= req_num < |batches[batch_num]| && req == batches[batch_num][req_num]; var p := lemma_DecidedRequestWasSentByClient(b, c, i, qs, batches, batch_num, req_num); } } lemma lemma_ProduceIntermediateAbstractStatesSatisfiesNext( server_addresses:set, batches:seq, reqs_in_last_batch:int ) returns ( request:Request ) requires |batches| > 0 requires 0 <= reqs_in_last_batch < |last(batches)| requires |last(batches)[reqs_in_last_batch].request| <= MaxAppRequestSize() ensures request == last(batches)[reqs_in_last_batch] ensures RslSystemNextServerExecutesRequest(ProduceIntermediateAbstractState(server_addresses, batches, reqs_in_last_batch), ProduceIntermediateAbstractState(server_addresses, batches, reqs_in_last_batch+1), request) { var rs := ProduceIntermediateAbstractState(server_addresses, batches, reqs_in_last_batch); var rs' := ProduceIntermediateAbstractState(server_addresses, batches, reqs_in_last_batch+1); request := last(batches)[reqs_in_last_batch]; var reply := GetReplyFromRequestBatches(batches, |batches|-1, reqs_in_last_batch); assert rs'.requests == rs.requests + { request }; assert rs'.replies == rs.replies + { reply }; var stateBeforePrevBatch := GetAppStateFromRequestBatches(all_but_last(batches)); var appStatesDuringBatch := HandleRequestBatch(stateBeforePrevBatch, last(batches)).0; var g_replies := HandleRequestBatch(stateBeforePrevBatch, last(batches)).1; lemma_HandleRequestBatchTriggerHappy(stateBeforePrevBatch, last(batches), appStatesDuringBatch, g_replies); var result := AppHandleRequest(rs.app, last(batches)[reqs_in_last_batch].request); assert rs'.app == result.0; assert reply.reply == result.1; assert RslSystemNextServerExecutesRequest(rs, rs', request); } lemma lemma_FirstProduceIntermediateAbstractStateProducesAbstractState( server_addresses:set, batches:seq ) requires |batches| > 0 ensures ProduceAbstractState(server_addresses, all_but_last(batches)) == ProduceIntermediateAbstractState(server_addresses, batches, 0) { var rs := ProduceAbstractState(server_addresses, all_but_last(batches)); var rs' := ProduceIntermediateAbstractState(server_addresses, batches, 0); var requests := set batch_num, req_num | 0 <= batch_num < |batches| && 0 <= req_num < (if batch_num == |batches|-1 then 0 else |batches[batch_num]|) :: batches[batch_num][req_num]; var replies := set batch_num, req_num | 0 <= batch_num < |batches| && 0 <= req_num < (if batch_num == |batches|-1 then 0 else |batches[batch_num]|) :: GetReplyFromRequestBatches(batches, batch_num, req_num); var stateBeforePrevBatch := GetAppStateFromRequestBatches(all_but_last(batches)); var appStatesDuringBatch := HandleRequestBatch(stateBeforePrevBatch, last(batches)).0; var replies' := HandleRequestBatch(stateBeforePrevBatch, last(batches)).1; lemma_HandleRequestBatchTriggerHappy(stateBeforePrevBatch, last(batches), appStatesDuringBatch, replies'); forall req | req in rs'.requests ensures req in rs.requests { var batch_num, req_num :| && 0 <= batch_num < |batches| && 0 <= req_num < (if batch_num == |batches|-1 then 0 else |batches[batch_num]|) && req == batches[batch_num][req_num]; assert 0 <= batch_num < |all_but_last(batches)|; assert 0 <= req_num < |batches[batch_num]|; assert 0 <= req_num < |all_but_last(batches)[batch_num]|; } assert rs'.requests == rs.requests; forall reply | reply in rs'.replies ensures reply in rs.replies { var batch_num, req_num :| && 0 <= batch_num < |batches| && 0 <= req_num < (if batch_num == |batches|-1 then 0 else |batches[batch_num]|) && reply == GetReplyFromRequestBatches(batches, batch_num, req_num); assert 0 <= batch_num < |all_but_last(batches)|; assert 0 <= req_num < |batches[batch_num]|; assert 0 <= req_num < |all_but_last(batches)[batch_num]|; lemma_GetReplyFromRequestBatchesMatchesInSubsequence(all_but_last(batches), batches, batch_num, req_num); } forall reply | reply in rs.replies ensures reply in rs'.replies { var batch_num, req_num :| && 0 <= batch_num < |all_but_last(batches)| && 0 <= req_num < |batches[batch_num]| && reply == GetReplyFromRequestBatches(all_but_last(batches), batch_num, req_num); lemma_GetReplyFromRequestBatchesMatchesInSubsequence(all_but_last(batches), batches, batch_num, req_num); } assert rs'.replies == rs.replies; } lemma lemma_LastProduceIntermediateAbstractStateProducesAbstractState( server_addresses:set, batches:seq ) requires |batches| > 0 ensures ProduceAbstractState(server_addresses, batches) == ProduceIntermediateAbstractState(server_addresses, batches, |last(batches)|) { var rs := ProduceAbstractState(server_addresses, batches); var rs' := ProduceIntermediateAbstractState(server_addresses, batches, |last(batches)|); assert rs'.requests == rs.requests; forall reply | reply in rs'.replies ensures reply in rs.replies { var batch_num, req_num :| && 0 <= batch_num < |batches| && 0 <= req_num < (if batch_num == |batches|-1 then |last(batches)| else |batches[batch_num]|) && reply == GetReplyFromRequestBatches(batches, batch_num, req_num); assert 0 <= req_num < |batches[batch_num]|; } assert rs'.replies == rs.replies; } function {:opaque} ConvertBehaviorSeqToImap(s:seq):imap requires |s| > 0 ensures imaptotal(ConvertBehaviorSeqToImap(s)) ensures forall i :: 0 <= i < |s| ==> ConvertBehaviorSeqToImap(s)[i] == s[i] { imap i {:trigger s[i]} :: if i < 0 then s[0] else if 0 <= i < |s| then s[i] else last(s) } predicate RslSystemBehaviorRefinementCorrectImap( b:Behavior, prefix_len:int, high_level_behavior:seq ) { && imaptotal(b) && |high_level_behavior| == prefix_len && (forall i :: 0 <= i < prefix_len ==> RslSystemRefinement(b[i], high_level_behavior[i])) && |high_level_behavior| > 0 && RslSystemInit(high_level_behavior[0], MapSeqToSet(b[0].constants.config.replica_ids, x=>x)) && (forall i {:trigger RslSystemNext(high_level_behavior[i], high_level_behavior[i+1])} :: 0 <= i < |high_level_behavior| - 1 ==> RslSystemNext(high_level_behavior[i], high_level_behavior[i+1])) } lemma lemma_GetBehaviorRefinementForBehaviorOfOneStep( b:Behavior, c:LConstants ) returns ( high_level_behavior:seq ) requires imaptotal(b) requires RslInit(c, b[0]) ensures RslSystemBehaviorRefinementCorrectImap(b, 1, high_level_behavior) ensures |high_level_behavior| == 1 ensures SystemRefinementRelation(b[0], high_level_behavior[0]) { var qs := []; var rs := ProduceAbstractState(GetServerAddresses(b[0]), GetSequenceOfRequestBatches(qs)); if exists q :: IsValidQuorumOf2bs(b[0], q) && q.opn == 0 { var q :| IsValidQuorumOf2bs(b[0], q) && q.opn == 0; var idx :| idx in q.indices; var packet := q.packets[idx]; assert false; } assert IsMaximalQuorumOf2bsSequence(b[0], qs); assert SystemRefinementRelation(b[0], rs); high_level_behavior := [ rs ]; } lemma lemma_DemonstrateRslSystemNextWhenBatchExtended( server_addresses:set, s:RSLSystemState, s':RSLSystemState, batches:seq, count:int ) returns ( intermediate_states:seq, batch:seq ) requires |batches| > 0 requires 0 <= count <= |last(batches)| requires forall req, batch :: batch in batches && req in batch ==> |req.request| <= MaxAppRequestSize() requires s == ProduceIntermediateAbstractState(server_addresses, batches, 0) requires s' == ProduceIntermediateAbstractState(server_addresses, batches, count) ensures RslStateSequenceReflectsBatchExecution(s, s', intermediate_states, batch) ensures RslSystemNext(s, s') decreases count { if count == 0 { assert s' == s; intermediate_states := [s]; batch := []; assert RslStateSequenceReflectsBatchExecution(s, s', intermediate_states, batch); return; } var s_middle := ProduceIntermediateAbstractState(server_addresses, batches, count - 1); var intermediate_states_middle, batch_middle := lemma_DemonstrateRslSystemNextWhenBatchExtended(server_addresses, s, s_middle, batches, count - 1); intermediate_states := intermediate_states_middle + [s']; assert last(batches) in batches && last(batches)[count-1] in last(batches); assert |last(batches)[count-1].request| <= MaxAppRequestSize(); var next_request := lemma_ProduceIntermediateAbstractStatesSatisfiesNext(server_addresses, batches, count-1); batch := batch_middle + [next_request]; assert RslSystemNextServerExecutesRequest(s_middle, s', next_request); assert RslStateSequenceReflectsBatchExecution(s, s', intermediate_states, batch); } lemma lemma_DemonstrateRslSystemNextWhenBatchesAdded( server_addresses:set, s:RSLSystemState, s':RSLSystemState, batches:seq, batches':seq ) returns ( intermediate_states:seq, batch:seq ) requires s == ProduceAbstractState(server_addresses, batches) requires s' == ProduceAbstractState(server_addresses, batches') requires |batches| <= |batches'| requires batches'[..|batches|] == batches requires forall req, batch :: batch in batches' && req in batch ==> |req.request| <= MaxAppRequestSize() ensures RslStateSequenceReflectsBatchExecution(s, s', intermediate_states, batch) ensures RslSystemNext(s, s') decreases |batches'| { if |batches| == |batches'| { assert batches' == batches; assert s == s'; intermediate_states := [s]; batch := []; assert RslStateSequenceReflectsBatchExecution(s, s', intermediate_states, batch); return; } var s_middle := ProduceAbstractState(server_addresses, all_but_last(batches')); var intermediate_states_middle, batch_middle := lemma_DemonstrateRslSystemNextWhenBatchesAdded(server_addresses, s, s_middle, batches, all_but_last(batches')); lemma_FirstProduceIntermediateAbstractStateProducesAbstractState(server_addresses, batches'); lemma_LastProduceIntermediateAbstractStateProducesAbstractState(server_addresses, batches'); var intermediate_states_next, batch_next := lemma_DemonstrateRslSystemNextWhenBatchExtended(server_addresses, s_middle, s', batches', |last(batches')|); intermediate_states := all_but_last(intermediate_states_middle) + intermediate_states_next; batch := batch_middle + batch_next; assert RslStateSequenceReflectsBatchExecution(s, s', intermediate_states, batch); } lemma lemma_GetBehaviorRefinementForPrefix( b:Behavior, c:LConstants, i:int ) returns ( high_level_behavior:seq ) requires 0 <= i requires IsValidBehaviorPrefix(b, c, i) ensures RslSystemBehaviorRefinementCorrectImap(b, i+1, high_level_behavior) ensures SystemRefinementRelation(b[i], last(high_level_behavior)) { if i == 0 { high_level_behavior := lemma_GetBehaviorRefinementForBehaviorOfOneStep(b, c); return; } lemma_ConstantsAllConsistent(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i); assert GetServerAddresses(b[i-1]) == GetServerAddresses(b[i]); var server_addresses := GetServerAddresses(b[i-1]); var prev_high_level_behavior := lemma_GetBehaviorRefinementForPrefix(b, c, i-1); var prev_rs := last(prev_high_level_behavior); var prev_qs :| && IsMaximalQuorumOf2bsSequence(b[i-1], prev_qs) && prev_rs == ProduceAbstractState(server_addresses, GetSequenceOfRequestBatches(prev_qs)); var prev_batches := GetSequenceOfRequestBatches(prev_qs); var qs := lemma_GetMaximalQuorumOf2bsSequence(b, c, i); var batches := GetSequenceOfRequestBatches(qs); lemma_IfValidQuorumOf2bsSequenceNowThenNext(b, c, i-1, prev_qs); lemma_RegularQuorumOf2bSequenceIsPrefixOfMaximalQuorumOf2bSequence(b, c, i, prev_qs, qs); forall req, batch | batch in batches && req in batch ensures |req.request| <= MaxAppRequestSize() { var batch_num :| 0 <= batch_num < |batches| && batches[batch_num] == batch; var req_num :| 0 <= req_num < |batch| && batch[req_num] == req; var p := lemma_DecidedRequestWasSentByClient(b, c, i, qs, batches, batch_num, req_num); } var s' := ProduceAbstractState(server_addresses, batches); var intermediate_states, batch := lemma_DemonstrateRslSystemNextWhenBatchesAdded(server_addresses, last(prev_high_level_behavior), s', prev_batches, batches); high_level_behavior := prev_high_level_behavior + [s']; lemma_ProduceAbstractStateSatisfiesRefinementRelation(b, c, i, qs, last(high_level_behavior)); assert RslSystemRefinement(b[i], last(high_level_behavior)); } lemma lemma_GetBehaviorRefinement( low_level_behavior:seq, c:LConstants ) returns ( high_level_behavior:seq ) requires |low_level_behavior| > 0 requires RslInit(c, low_level_behavior[0]) requires forall i {:trigger RslNext(low_level_behavior[i], low_level_behavior[i+1])} :: 0 <= i < |low_level_behavior| - 1 ==> RslNext(low_level_behavior[i], low_level_behavior[i+1]) ensures RslSystemBehaviorRefinementCorrect(MapSeqToSet(c.config.replica_ids, x=>x), low_level_behavior, high_level_behavior) { var b := ConvertBehaviorSeqToImap(low_level_behavior); high_level_behavior := lemma_GetBehaviorRefinementForPrefix(b, c, |low_level_behavior|-1); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/RefinementProof/Requests.i.dfy ================================================ include "../DistributedSystem.i.dfy" include "../CommonProof/Requests.i.dfy" include "Chosen.i.dfy" module DirectRefinement__Requests_i { import opened LiveRSL__Constants_i import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Election_i import opened LiveRSL__Environment_i import opened LiveRSL__Proposer_i import opened LiveRSL__Replica_i import opened LiveRSL__Types_i import opened CommonProof__Actions_i import opened CommonProof__Assumptions_i import opened CommonProof__Chosen_i import opened CommonProof__Constants_i import opened CommonProof__Environment_i import opened CommonProof__Message1b_i import opened CommonProof__Message2b_i import opened CommonProof__PacketSending_i import opened CommonProof__Received1b_i import opened CommonProof__Requests_i import opened AppStateMachine_s import opened DirectRefinement__Chosen_i import opened Temporal__Temporal_s import opened Environment_s lemma lemma_RequestInRequestsReceivedThisEpochHasCorrespondingRequestMessage( b:Behavior, c:LConstants, i:int, idx:int, req:Request ) returns ( p:RslPacket ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires 0 <= idx < |b[i].replicas| requires req in b[i].replicas[idx].replica.proposer.election_state.requests_received_this_epoch ensures p in b[i].environment.sentPackets ensures p.dst in c.config.replica_ids ensures p.msg.RslMessage_Request? ensures req == Request(p.src, p.msg.seqno_req, p.msg.val) ensures |p.msg.val| <= MaxAppRequestSize() decreases i { if i == 0 { return; } lemma_ConstantsAllConsistent(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i); lemma_AssumptionsMakeValidTransition(b, c, i-1); var es := b[i-1].replicas[idx].replica.proposer.election_state; var es' := b[i].replicas[idx].replica.proposer.election_state; if req in es.requests_received_this_epoch { p := lemma_RequestInRequestsReceivedThisEpochHasCorrespondingRequestMessage(b, c, i-1, idx, req); lemma_PacketStaysInSentPackets(b, c, i-1, i, p); return; } var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, c, i-1, idx); var nextActionIndex := b[i-1].replicas[idx].nextActionIndex; if nextActionIndex == 0 { p := ios[0].r; assert IsValidLIoOp(ios[0], c.config.replica_ids[idx], b[i-1].environment); return; } var batch := b[i-1].replicas[idx].replica.executor.next_op_to_execute.v; assert ElectionStateReflectExecutedRequestBatch(es, es', batch); lemma_RemoveExecutedRequestBatchProducesSubsequence(es'.requests_received_this_epoch, es.requests_received_this_epoch, batch); assert false; } lemma lemma_RequestInRequestsReceivedPrevEpochsHasCorrespondingRequestMessage( b:Behavior, c:LConstants, i:int, idx:int, req:Request ) returns ( p:RslPacket ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires 0 <= idx < |b[i].replicas| requires req in b[i].replicas[idx].replica.proposer.election_state.requests_received_prev_epochs ensures p in b[i].environment.sentPackets ensures p.dst in c.config.replica_ids ensures p.msg.RslMessage_Request? ensures req == Request(p.src, p.msg.seqno_req, p.msg.val) ensures |p.msg.val| <= MaxAppRequestSize() decreases i { if i == 0 { return; } lemma_ConstantsAllConsistent(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i); lemma_AssumptionsMakeValidTransition(b, c, i-1); var es := b[i-1].replicas[idx].replica.proposer.election_state; var es' := b[i].replicas[idx].replica.proposer.election_state; if req in es.requests_received_prev_epochs { p := lemma_RequestInRequestsReceivedPrevEpochsHasCorrespondingRequestMessage(b, c, i-1, idx, req); lemma_PacketStaysInSentPackets(b, c, i-1, i, p); return; } if req in es.requests_received_this_epoch { p := lemma_RequestInRequestsReceivedThisEpochHasCorrespondingRequestMessage(b, c, i-1, idx, req); lemma_PacketStaysInSentPackets(b, c, i-1, i, p); return; } var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, c, i-1, idx); var batch := b[i-1].replicas[idx].replica.executor.next_op_to_execute.v; assert ElectionStateReflectExecutedRequestBatch(es, es', batch); lemma_RemoveExecutedRequestBatchProducesSubsequence(es'.requests_received_prev_epochs, es.requests_received_prev_epochs, batch); assert false; } lemma lemma_RequestInRequestQueueHasCorrespondingRequestMessage( b:Behavior, c:LConstants, i:int, idx:int, req:Request ) returns ( p:RslPacket ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires 0 <= idx < |b[i].replicas| requires req in b[i].replicas[idx].replica.proposer.request_queue ensures p in b[i].environment.sentPackets ensures p.dst in c.config.replica_ids ensures p.msg.RslMessage_Request? ensures req == Request(p.src, p.msg.seqno_req, p.msg.val) ensures |p.msg.val| <= MaxAppRequestSize() decreases i { if i == 0 { return; } lemma_ConstantsAllConsistent(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i); lemma_AssumptionsMakeValidTransition(b, c, i-1); var s := b[i-1].replicas[idx].replica.proposer; var s' := b[i].replicas[idx].replica.proposer; if req in s.request_queue { p := lemma_RequestInRequestQueueHasCorrespondingRequestMessage(b, c, i-1, idx, req); lemma_PacketStaysInSentPackets(b, c, i-1, i, p); return; } if req in s.election_state.requests_received_prev_epochs { p := lemma_RequestInRequestsReceivedPrevEpochsHasCorrespondingRequestMessage(b, c, i-1, idx, req); lemma_PacketStaysInSentPackets(b, c, i-1, i, p); return; } if req in s.election_state.requests_received_this_epoch { p := lemma_RequestInRequestsReceivedThisEpochHasCorrespondingRequestMessage(b, c, i-1, idx, req); lemma_PacketStaysInSentPackets(b, c, i-1, i, p); return; } var ios := lemma_ActionThatChangesReplicaIsThatReplicasAction(b, c, i-1, idx); p := ios[0].r; assert IsValidLIoOp(ios[0], c.config.replica_ids[idx], b[i-1].environment); } lemma lemma_RequestIn1bMessageHasCorrespondingRequestMessage( b:Behavior, c:LConstants, i:int, p_1b:RslPacket, opn:OperationNumber, req_num:int ) returns ( p_req:RslPacket ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires p_1b in b[i].environment.sentPackets requires p_1b.src in c.config.replica_ids requires p_1b.msg.RslMessage_1b? requires opn in p_1b.msg.votes requires 0 <= req_num < |p_1b.msg.votes[opn].max_val| ensures p_req in b[i].environment.sentPackets ensures p_req.dst in c.config.replica_ids ensures p_req.msg.RslMessage_Request? ensures p_1b.msg.votes[opn].max_val[req_num] == Request(p_req.src, p_req.msg.seqno_req, p_req.msg.val) ensures |p_req.msg.val| <= MaxAppRequestSize() decreases i, 1 { var p_2a := lemma_1bMessageWithOpnImplies2aSent(b, c, i, opn, p_1b); p_req := lemma_RequestIn2aMessageHasCorrespondingRequestMessage(b, c, i, p_2a, req_num); } lemma lemma_RequestIn2aMessageHasCorrespondingRequestMessage( b:Behavior, c:LConstants, i:int, p_2a:RslPacket, req_num:int ) returns ( p_req:RslPacket ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires p_2a in b[i].environment.sentPackets requires p_2a.src in c.config.replica_ids requires p_2a.msg.RslMessage_2a? requires 0 <= req_num < |p_2a.msg.val_2a| ensures p_req in b[i].environment.sentPackets ensures p_req.dst in c.config.replica_ids ensures p_req.msg.RslMessage_Request? ensures p_2a.msg.val_2a[req_num] == Request(p_req.src, p_req.msg.seqno_req, p_req.msg.val) ensures |p_req.msg.val| <= MaxAppRequestSize() decreases i, 0 { if i == 0 { return; } if p_2a in b[i-1].environment.sentPackets { p_req := lemma_RequestIn2aMessageHasCorrespondingRequestMessage(b, c, i-1, p_2a, req_num); lemma_PacketStaysInSentPackets(b, c, i-1, i, p_req); return; } lemma_ConstantsAllConsistent(b, c, i-1); lemma_ConstantsAllConsistent(b, c, i); lemma_AssumptionsMakeValidTransition(b, c, i-1); var idx, ios := lemma_ActionThatSends2aIsMaybeNominateValueAndSend2a(b[i-1], b[i], p_2a); var s := b[i-1].replicas[idx].replica.proposer; var s' := b[i].replicas[idx].replica.proposer; var log_truncation_point := b[i-1].replicas[idx].replica.acceptor.log_truncation_point; var sent_packets := ExtractSentPacketsFromIos(ios); if LAllAcceptorsHadNoProposal(s.received_1b_packets, s.next_operation_number_to_propose) { assert LProposerNominateNewValueAndSend2a(s, s', ios[0].t, log_truncation_point, sent_packets); assert s.request_queue[req_num] == p_2a.msg.val_2a[req_num]; p_req := lemma_RequestInRequestQueueHasCorrespondingRequestMessage(b, c, i-1, idx, s.request_queue[req_num]); } else { assert LProposerNominateOldValueAndSend2a(s, s', log_truncation_point, sent_packets); var opn := s.next_operation_number_to_propose; var v := p_2a.msg.val_2a; // var earlier_ballot :| LValIsHighestNumberedProposalAtBallot(v, earlier_ballot, s.received_1b_packets, opn); var p_1b :| p_1b in s.received_1b_packets && opn in p_1b.msg.votes && p_1b.msg.votes[opn].max_val == v; lemma_PacketInReceived1bWasSent(b, c, i-1, idx, p_1b); p_req := lemma_RequestIn1bMessageHasCorrespondingRequestMessage(b, c, i-1, p_1b, opn, req_num); } } lemma lemma_DecidedRequestWasSentByClient( b:Behavior, c:LConstants, i:int, qs:seq, batches:seq, batch_num:int, req_num:int ) returns ( p:RslPacket ) requires IsValidBehaviorPrefix(b, c, i) requires 0 <= i requires IsValidQuorumOf2bsSequence(b[i], qs) requires batches == GetSequenceOfRequestBatches(qs) requires 0 <= batch_num < |batches| requires 0 <= req_num < |batches[batch_num]| ensures p in b[i].environment.sentPackets ensures p.dst in c.config.replica_ids ensures p.msg.RslMessage_Request? ensures batches[batch_num][req_num] == Request(p.src, p.msg.seqno_req, p.msg.val) ensures |p.msg.val| <= MaxAppRequestSize() decreases i { lemma_ConstantsAllConsistent(b, c, i); lemma_SequenceOfRequestBatchesNthElement(qs, batch_num); var batch := batches[batch_num]; var request := batch[req_num]; var q := qs[batch_num]; var idx :| idx in q.indices; var packet_2b := q.packets[idx]; assert packet_2b.msg.RslMessage_2b?; assert packet_2b.msg.val_2b == batch; var packet_2a := lemma_2bMessageHasCorresponding2aMessage(b, c, i, packet_2b); p := lemma_RequestIn2aMessageHasCorrespondingRequestMessage(b, c, i, packet_2a, req_num); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/RefinementProof/StateMachine.i.dfy ================================================ include "../DistributedSystem.i.dfy" module DirectRefinement__StateMachine_i { import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Types_i import opened Concrete_NodeIdentity_i import opened AppStateMachine_s import opened Collections__Seqs_s datatype RSLSystemState = RSLSystemState( server_addresses:set, app:AppState, requests:set, replies:set ) predicate RslSystemInit(s:RSLSystemState, server_addresses:set) { && s.server_addresses == server_addresses && s.app == AppInitialize() && s.requests == {} && s.replies == {} } predicate RslSystemNextServerExecutesRequest(s:RSLSystemState, s':RSLSystemState, req:Request) { && |req.request| <= MaxAppRequestSize() && s'.server_addresses == s.server_addresses && s'.requests == s.requests + { req } && s'.app == AppHandleRequest(s.app, req.request).0 && s'.replies == s.replies + { Reply(req.client, req.seqno, AppHandleRequest(s.app, req.request).1) } } predicate RslStateSequenceReflectsBatchExecution(s:RSLSystemState, s':RSLSystemState, intermediate_states:seq, batch:seq) { && |intermediate_states| == |batch| + 1 && intermediate_states[0] == s && last(intermediate_states) == s' && forall i :: 0 <= i < |batch| ==> RslSystemNextServerExecutesRequest(intermediate_states[i], intermediate_states[i+1], batch[i]) } predicate RslSystemNext(s:RSLSystemState, s':RSLSystemState) { exists intermediate_states, batch :: RslStateSequenceReflectsBatchExecution(s, s', intermediate_states, batch) } predicate RslSystemRefinement(ps:RslState, rs:RSLSystemState) { && (forall p :: p in ps.environment.sentPackets && p.src in rs.server_addresses && p.msg.RslMessage_Reply? ==> Reply(p.dst, p.msg.seqno_reply, p.msg.reply) in rs.replies) && (forall req :: req in rs.requests ==> exists p :: p in ps.environment.sentPackets && p.dst in rs.server_addresses && p.msg.RslMessage_Request? && req == Request(p.src, p.msg.seqno_req, p.msg.val)) } predicate RslSystemBehaviorRefinementCorrect(server_addresses:set, low_level_behavior:seq, high_level_behavior:seq) { && |high_level_behavior| == |low_level_behavior| && (forall i :: 0 <= i < |low_level_behavior| ==> RslSystemRefinement(low_level_behavior[i], high_level_behavior[i])) && |high_level_behavior| > 0 && RslSystemInit(high_level_behavior[0], server_addresses) && (forall i {:trigger high_level_behavior[i], high_level_behavior[i+1]} :: 0 <= i < |high_level_behavior| - 1 ==> RslSystemNext(high_level_behavior[i], high_level_behavior[i+1])) } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/Replica.i.dfy ================================================ include "Configuration.i.dfy" include "Environment.i.dfy" include "Types.i.dfy" include "ClockReading.i.dfy" include "Constants.i.dfy" include "Proposer.i.dfy" include "Acceptor.i.dfy" include "Learner.i.dfy" include "Executor.i.dfy" module LiveRSL__Replica_i { import opened LiveRSL__Configuration_i import opened LiveRSL__Environment_i import opened LiveRSL__Types_i import opened LiveRSL__ClockReading_i import opened LiveRSL__Constants_i import opened LiveRSL__Proposer_i import opened LiveRSL__Acceptor_i import opened LiveRSL__Learner_i import opened LiveRSL__Executor_i import opened LiveRSL__Broadcast_i import opened LiveRSL__Message_i import opened AppStateMachine_s import opened Common__UpperBound_s import opened Environment_s datatype LReplica = LReplica( constants:LReplicaConstants, nextHeartbeatTime:int, proposer:LProposer, acceptor:LAcceptor, learner:LLearner, executor:LExecutor) predicate LReplicaInit(r:LReplica, c:LReplicaConstants) requires WellFormedLConfiguration(c.all.config) { && r.constants == c && r.nextHeartbeatTime == 0 && LProposerInit(r.proposer, c) && LAcceptorInit(r.acceptor, c) && LLearnerInit(r.learner, c) && LExecutorInit(r.executor, c) } predicate LReplicaNextProcessInvalid(s:LReplica, s':LReplica, received_packet:RslPacket, sent_packets:seq) requires received_packet.msg.RslMessage_Invalid? { && s' == s && sent_packets == [] } predicate LReplicaNextProcessRequest(s:LReplica, s':LReplica, received_packet:RslPacket, sent_packets:seq) requires received_packet.msg.RslMessage_Request? { if |received_packet.msg.val| > MaxAppRequestSize() then && sent_packets == [] && s' == s else // We may always propose the request, no matter what the reply-cache state. // If there's a matching or later request in the reply cache, we may instead reply out of the reply cache. || (&& LProposerProcessRequest(s.proposer, s'.proposer, received_packet) && sent_packets == [] && s' == s.(proposer := s'.proposer)) || (&& received_packet.src in s.executor.reply_cache && s.executor.reply_cache[received_packet.src].Reply? && received_packet.msg.seqno_req <= s.executor.reply_cache[received_packet.src].seqno && LExecutorProcessRequest(s.executor, received_packet, sent_packets) && s' == s) } predicate LReplicaNextProcess1a(s:LReplica, s':LReplica, received_packet:RslPacket, sent_packets:seq) requires received_packet.msg.RslMessage_1a? { && LAcceptorProcess1a(s.acceptor, s'.acceptor, received_packet, sent_packets) // UNCHANGED && s' == s.(acceptor := s'.acceptor) } predicate LReplicaNextProcess1b(s:LReplica, s':LReplica, received_packet:RslPacket, sent_packets:seq) requires received_packet.msg.RslMessage_1b? { if && received_packet.src in s.proposer.constants.all.config.replica_ids && received_packet.msg.bal_1b == s.proposer.max_ballot_i_sent_1a && s.proposer.current_state == 1 && (forall other_packet :: other_packet in s.proposer.received_1b_packets ==> other_packet.src != received_packet.src) then && LProposerProcess1b(s.proposer, s'.proposer, received_packet) && LAcceptorTruncateLog(s.acceptor, s'.acceptor, received_packet.msg.log_truncation_point) && sent_packets == [] && s' == s.(proposer := s'.proposer, acceptor := s'.acceptor) else s' == s && sent_packets == [] } predicate LReplicaNextProcessStartingPhase2(s:LReplica, s':LReplica, received_packet:RslPacket, sent_packets:seq) requires received_packet.msg.RslMessage_StartingPhase2? { && LExecutorProcessStartingPhase2(s.executor, s'.executor, received_packet, sent_packets) && s' == s.(executor := s'.executor) } predicate LReplicaNextProcess2a(s:LReplica, s':LReplica, received_packet:RslPacket, sent_packets:seq) requires received_packet.msg.RslMessage_2a? { var m := received_packet.msg; if && received_packet.src in s.acceptor.constants.all.config.replica_ids && BalLeq(s.acceptor.max_bal, m.bal_2a) && LeqUpperBound(m.opn_2a, s.acceptor.constants.all.params.max_integer_val) then && LAcceptorProcess2a(s.acceptor, s'.acceptor, received_packet, sent_packets) && s' == s.(acceptor := s'.acceptor) else s' == s && sent_packets == [] } predicate LReplicaNextProcess2b(s:LReplica, s':LReplica, received_packet:RslPacket, sent_packets:seq) requires received_packet.msg.RslMessage_2b? { var opn := received_packet.msg.opn_2b; var op_learnable := s.executor.ops_complete < opn || (s.executor.ops_complete == opn && s.executor.next_op_to_execute.OutstandingOpUnknown?); if op_learnable then && LLearnerProcess2b(s.learner, s'.learner, received_packet) && sent_packets == [] && s' == s.(learner := s'.learner) else && s' == s && sent_packets == [] } predicate LReplicaNextProcessReply(s:LReplica, s':LReplica, received_packet:RslPacket, sent_packets:seq) requires received_packet.msg.RslMessage_Reply? { && sent_packets == [] && s' == s } predicate LReplicaNextProcessAppStateSupply(s:LReplica, s':LReplica, received_packet:RslPacket, sent_packets:seq) requires received_packet.msg.RslMessage_AppStateSupply? { if received_packet.src in s.executor.constants.all.config.replica_ids && received_packet.msg.opn_state_supply > s.executor.ops_complete then && LLearnerForgetOperationsBefore(s.learner, s'.learner, received_packet.msg.opn_state_supply) && LExecutorProcessAppStateSupply(s.executor, s'.executor, received_packet) && sent_packets == [] && s' == s.(learner := s'.learner, executor := s'.executor) else s' == s && sent_packets == [] } predicate LReplicaNextProcessAppStateRequest(s:LReplica, s':LReplica, received_packet:RslPacket, sent_packets:seq) requires received_packet.msg.RslMessage_AppStateRequest? { && LExecutorProcessAppStateRequest(s.executor, s'.executor, received_packet, sent_packets) && s' == s.(executor := s'.executor) } predicate LReplicaNextProcessHeartbeat(s:LReplica, s':LReplica, received_packet:RslPacket, clock:int, sent_packets:seq) requires received_packet.msg.RslMessage_Heartbeat? { && LProposerProcessHeartbeat(s.proposer, s'.proposer, received_packet, clock) && LAcceptorProcessHeartbeat(s.acceptor, s'.acceptor, received_packet) && sent_packets == [] && s' == s.(proposer := s'.proposer, acceptor := s'.acceptor) } predicate LReplicaNextSpontaneousMaybeEnterNewViewAndSend1a(s:LReplica, s':LReplica, sent_packets:seq) { && LProposerMaybeEnterNewViewAndSend1a(s.proposer, s'.proposer, sent_packets) && s' == s.(proposer := s'.proposer) } predicate LReplicaNextSpontaneousMaybeEnterPhase2(s:LReplica, s':LReplica, sent_packets:seq) { && LProposerMaybeEnterPhase2(s.proposer, s'.proposer, s.acceptor.log_truncation_point, sent_packets) && s' == s.(proposer := s'.proposer) } predicate LReplicaNextReadClockMaybeNominateValueAndSend2a(s:LReplica, s':LReplica, clock:ClockReading, sent_packets:seq) { && LProposerMaybeNominateValueAndSend2a(s.proposer, s'.proposer, clock.t, s.acceptor.log_truncation_point, sent_packets) && s' == s.(proposer := s'.proposer) } predicate LReplicaNextSpontaneousTruncateLogBasedOnCheckpoints(s:LReplica, s':LReplica, sent_packets:seq) { (exists opn :: && IsLogTruncationPointValid(opn, s.acceptor.last_checkpointed_operation, s.constants.all.config) && opn > s.acceptor.log_truncation_point && LAcceptorTruncateLog(s.acceptor, s'.acceptor, opn) && s' == s.(acceptor := s'.acceptor) && sent_packets == [] ) || (exists opn :: && IsLogTruncationPointValid(opn, s.acceptor.last_checkpointed_operation, s.constants.all.config) && opn <= s.acceptor.log_truncation_point && s' == s && sent_packets == [] ) } predicate LReplicaNextSpontaneousMaybeMakeDecision(s:LReplica, s':LReplica, sent_packets:seq) { var opn := s.executor.ops_complete; if && s.executor.next_op_to_execute.OutstandingOpUnknown? && opn in s.learner.unexecuted_learner_state && |s.learner.unexecuted_learner_state[opn].received_2b_message_senders| >= LMinQuorumSize(s.learner.constants.all.config) then && LExecutorGetDecision(s.executor, s'.executor, s.learner.max_ballot_seen, opn, s.learner.unexecuted_learner_state[opn].candidate_learned_value) && s' == s.(executor := s'.executor) && sent_packets == [] else s' == s && sent_packets == [] } predicate LReplicaNextSpontaneousMaybeExecute(s:LReplica, s':LReplica, sent_packets:seq) { if && s.executor.next_op_to_execute.OutstandingOpKnown? && LtUpperBound(s.executor.ops_complete, s.executor.constants.all.params.max_integer_val) && LReplicaConstantsValid(s.executor.constants) then var v := s.executor.next_op_to_execute.v; && LProposerResetViewTimerDueToExecution(s.proposer, s'.proposer, v) && LLearnerForgetDecision(s.learner, s'.learner, s.executor.ops_complete) && LExecutorExecute(s.executor, s'.executor, sent_packets) && s' == s.(proposer := s'.proposer, learner := s'.learner, executor := s'.executor) else s' == s && sent_packets == [] } predicate LReplicaNextReadClockMaybeSendHeartbeat(s:LReplica, s':LReplica, clock:ClockReading, sent_packets:seq) { if clock.t < s.nextHeartbeatTime then s' == s && sent_packets == [] else && s'.nextHeartbeatTime == UpperBoundedAddition(clock.t, s.constants.all.params.heartbeat_period, s.constants.all.params.max_integer_val) && LBroadcastToEveryone(s.constants.all.config, s.constants.my_index, RslMessage_Heartbeat(s.proposer.election_state.current_view, s.constants.my_index in s.proposer.election_state.current_view_suspectors, s.executor.ops_complete), sent_packets) && s' == s.(nextHeartbeatTime := s'.nextHeartbeatTime) } predicate LReplicaNextReadClockCheckForViewTimeout(s:LReplica, s':LReplica, clock:ClockReading, sent_packets:seq) { && LProposerCheckForViewTimeout(s.proposer, s'.proposer, clock.t) && sent_packets == [] && s' == s.(proposer := s'.proposer) } predicate LReplicaNextReadClockCheckForQuorumOfViewSuspicions(s:LReplica, s':LReplica, clock:ClockReading, sent_packets:seq) { && LProposerCheckForQuorumOfViewSuspicions(s.proposer, s'.proposer, clock.t) && sent_packets == [] && s' == s.(proposer := s'.proposer) } function {:opaque} ExtractSentPacketsFromIos(ios:seq) : seq ensures forall p :: p in ExtractSentPacketsFromIos(ios) <==> LIoOpSend(p) in ios { if |ios| == 0 then [] else if ios[0].LIoOpSend? then [ios[0].s] + ExtractSentPacketsFromIos(ios[1..]) else ExtractSentPacketsFromIos(ios[1..]) } predicate LReplicaNextReadClockAndProcessPacket(s:LReplica, s':LReplica, ios:seq) requires |ios| >= 1 requires ios[0].LIoOpReceive? requires ios[0].r.msg.RslMessage_Heartbeat? { && |ios| > 1 && ios[1].LIoOpReadClock? && (forall io :: io in ios[2..] ==> io.LIoOpSend?) && LReplicaNextProcessHeartbeat(s, s', ios[0].r, ios[1].t, ExtractSentPacketsFromIos(ios)) } predicate LReplicaNextProcessPacketWithoutReadingClock(s:LReplica, s':LReplica, ios:seq) requires |ios| >= 1 requires ios[0].LIoOpReceive? requires !ios[0].r.msg.RslMessage_Heartbeat? { && (forall io :: io in ios[1..] ==> io.LIoOpSend?) && var sent_packets := ExtractSentPacketsFromIos(ios); match ios[0].r.msg case RslMessage_Invalid => LReplicaNextProcessInvalid(s, s', ios[0].r, sent_packets) case RslMessage_Request(_, _) => LReplicaNextProcessRequest(s, s', ios[0].r, sent_packets) case RslMessage_1a(_) => LReplicaNextProcess1a(s, s', ios[0].r, sent_packets) case RslMessage_1b(_, _, _) => LReplicaNextProcess1b(s, s', ios[0].r, sent_packets) case RslMessage_StartingPhase2(_, _) => LReplicaNextProcessStartingPhase2(s, s', ios[0].r, sent_packets) case RslMessage_2a(_, _, _) => LReplicaNextProcess2a(s, s', ios[0].r, sent_packets) case RslMessage_2b(_, _, _) => LReplicaNextProcess2b(s, s', ios[0].r, sent_packets) case RslMessage_Reply(_, _) => LReplicaNextProcessReply(s, s', ios[0].r, sent_packets) case RslMessage_AppStateRequest(_, _) => LReplicaNextProcessAppStateRequest(s, s', ios[0].r, sent_packets) case RslMessage_AppStateSupply(_, _, _) => LReplicaNextProcessAppStateSupply(s, s', ios[0].r, sent_packets) } predicate LReplicaNextProcessPacket(s:LReplica, s':LReplica, ios:seq) { && |ios| >= 1 && if ios[0].LIoOpTimeoutReceive? then s' == s && |ios| == 1 else (&& ios[0].LIoOpReceive? && if ios[0].r.msg.RslMessage_Heartbeat? then LReplicaNextReadClockAndProcessPacket(s, s', ios) else LReplicaNextProcessPacketWithoutReadingClock(s, s', ios) ) } function LReplicaNumActions() : int { 10 } predicate SpontaneousIos(ios:seq, clocks:int) requires 0<=clocks<=1 { && clocks <= |ios| && (forall i :: 0<=i ios[i].LIoOpReadClock?) && (forall i :: clocks<=i<|ios| ==> ios[i].LIoOpSend?) } function SpontaneousClock(ios:seq) : ClockReading { if SpontaneousIos(ios, 1) then ClockReading(ios[0].t) else ClockReading(0) // nonsense to avoid putting a precondition on this function } predicate LReplicaNoReceiveNext(s:LReplica, nextActionIndex:int, s':LReplica, ios:seq) { var sent_packets := ExtractSentPacketsFromIos(ios); if nextActionIndex == 1 then && SpontaneousIos(ios, 0) && LReplicaNextSpontaneousMaybeEnterNewViewAndSend1a(s, s', sent_packets) else if nextActionIndex == 2 then && SpontaneousIos(ios, 0) && LReplicaNextSpontaneousMaybeEnterPhase2(s, s', sent_packets) else if nextActionIndex == 3 then && SpontaneousIos(ios, 1) && LReplicaNextReadClockMaybeNominateValueAndSend2a(s, s', SpontaneousClock(ios), sent_packets) else if nextActionIndex == 4 then && SpontaneousIos(ios, 0) && LReplicaNextSpontaneousTruncateLogBasedOnCheckpoints(s, s', sent_packets) else if nextActionIndex == 5 then && SpontaneousIos(ios, 0) && LReplicaNextSpontaneousMaybeMakeDecision(s, s', sent_packets) else if nextActionIndex == 6 then && SpontaneousIos(ios, 0) && LReplicaNextSpontaneousMaybeExecute(s, s', sent_packets) else if nextActionIndex == 7 then && SpontaneousIos(ios, 1) && LReplicaNextReadClockCheckForViewTimeout(s, s', SpontaneousClock(ios), sent_packets) else if nextActionIndex == 8 then && SpontaneousIos(ios, 1) && LReplicaNextReadClockCheckForQuorumOfViewSuspicions(s, s', SpontaneousClock(ios), sent_packets) else && nextActionIndex == 9 && SpontaneousIos(ios, 1) && LReplicaNextReadClockMaybeSendHeartbeat(s, s', SpontaneousClock(ios), sent_packets) } datatype LScheduler = LScheduler(replica:LReplica, nextActionIndex:int) predicate LSchedulerInit(s:LScheduler, c:LReplicaConstants) requires WellFormedLConfiguration(c.all.config) { && LReplicaInit(s.replica, c) && s.nextActionIndex == 0 } predicate LSchedulerNext(s:LScheduler, s':LScheduler, ios:seq) { && s'.nextActionIndex == (s.nextActionIndex + 1) % LReplicaNumActions() && if s.nextActionIndex == 0 then LReplicaNextProcessPacket(s.replica, s'.replica, ios) else LReplicaNoReceiveNext(s.replica, s.nextActionIndex, s'.replica, ios) } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/StateMachine.i.dfy ================================================ include "../../Services/RSL/AppStateMachine.s.dfy" include "Types.i.dfy" module LiveRSL__StateMachine_i { import opened AppStateMachine_s import opened LiveRSL__Types_i function HandleRequest(state:AppState, request:Request) : (AppState, Reply) { var (new_state, reply) := AppHandleRequest(state, request.request); (new_state, Reply(request.client, request.seqno, reply)) } function {:opaque} HandleRequestBatchHidden(state:AppState, batch:RequestBatch) : (seq, seq) ensures var (states, replies) := HandleRequestBatchHidden(state, batch); && |states| == |batch|+1 && |replies| == |batch| && forall i :: 0 <= i < |batch| ==> replies[i].Reply? decreases |batch| { //lemma_HandleRequestBatch(state, batch, HandleRequestBatch(state, batch).0, HandleRequestBatch(state, batch).1); if |batch| == 0 then ([state], []) else var (restStates, restReplies) := HandleRequestBatchHidden(state, batch[..|batch|-1]); var (new_state, reply) := AppHandleRequest(restStates[|restStates|-1], batch[|batch|-1].request); (restStates+[new_state], restReplies+[Reply(batch[|batch|-1].client, batch[|batch|-1].seqno, reply)]) } lemma{:timeLimitMultiplier 2} lemma_HandleRequestBatchHidden(state:AppState, batch:RequestBatch, states:seq, replies:seq) requires (states, replies) == HandleRequestBatchHidden(state, batch); ensures && states[0] == state && |states| == |batch|+1 && |replies| == |batch| && forall i :: 0 <= i < |batch| ==> && replies[i].Reply? && ((states[i+1], replies[i].reply) == AppHandleRequest(states[i], batch[i].request)) && replies[i].client == batch[i].client && replies[i].seqno == batch[i].seqno decreases |batch| { reveal HandleRequestBatchHidden(); if |batch| == 0 { assert && |states| == |batch|+1 && |replies| == |batch| && (forall i :: 0 <= i < |batch| ==> ((states[i+1], replies[i].reply) == AppHandleRequest(states[i], batch[i].request))); } else { var restBatch := HandleRequestBatchHidden(state, batch[..|batch|-1]); var restStates := restBatch.0; var AHR_result := AppHandleRequest(restStates[|restStates|-1], batch[|batch|-1].request); lemma_HandleRequestBatchHidden(state, batch[..|batch|-1], restStates, restBatch.1); assert replies[|batch|-1].reply == AHR_result.1; } } lemma lemma_HandleBatchRequestSizes(state:AppState, batch:RequestBatch, states:seq, replies:seq) requires (states, replies) == HandleRequestBatch(state, batch) ensures states[0] == state ensures |states| == |batch| + 1 ensures |replies| == |batch| { assert states == HandleRequestBatchHidden(state, batch).0; // OBSERVE assert replies == HandleRequestBatchHidden(state, batch).1; // OBSERVE assert (states, replies) == HandleRequestBatchHidden(state, batch); lemma_HandleRequestBatchHidden(state, batch, states,replies); } lemma lemma_HandleBatchRequestProperties(state:AppState, batch:RequestBatch, states:seq, replies:seq, i:int) requires (states, replies) == HandleRequestBatch(state, batch) requires 0 <= i < |batch| ensures states[0] == state ensures |states| == |batch| + 1 ensures |replies| == |batch| ensures replies[i].Reply? ensures var (s, r) := AppHandleRequest(states[i], batch[i].request); s == states[i+1] && r == replies[i].reply //ensures (states[i+1], replies[i]) == AppHandleRequest(states[i], batch[i].request) ensures replies[i].client == batch[i].client ensures replies[i].seqno == batch[i].seqno { assert states == HandleRequestBatchHidden(state, batch).0; // OBSERVE assert replies == HandleRequestBatchHidden(state, batch).1; // OBSERVE assert (states, replies) == HandleRequestBatchHidden(state, batch); lemma_HandleRequestBatchHidden(state, batch, states,replies); } // TODO: The forall in the ensures should have an explicit trigger, // but the proof appears to be depending on the overly generous triggers in several places lemma lemma_HandleRequestBatchTriggerHappy(state:AppState, batch:RequestBatch, states:seq, replies:seq) requires (states, replies) == HandleRequestBatch(state, batch); ensures && states[0] == state && |states| == |batch|+1 && |replies| == |batch| && forall i :: 0 <= i < |batch| ==> && replies[i].Reply? && ((states[i+1], replies[i].reply) == AppHandleRequest(states[i], batch[i].request)) && replies[i].client == batch[i].client && replies[i].seqno == batch[i].seqno { assert states == HandleRequestBatchHidden(state, batch).0; // OBSERVE assert replies == HandleRequestBatchHidden(state, batch).1; // OBSERVE assert (states, replies) == HandleRequestBatchHidden(state, batch); lemma_HandleRequestBatchHidden(state, batch, states, replies); } function HandleRequestBatch(state:AppState, batch:RequestBatch) : (seq, seq) // ensures var (states, replies) := HandleRequestBatch(state, batch); // && states[0] == state // && |states| == |batch|+1 // && |replies| == |batch| // && (forall i :: 0 <= i < |batch| ==> // && replies[i].Reply? // && ((states[i+1], replies[i].reply) == AppHandleRequest(states[i], batch[i].request)) // && replies[i].client == batch[i].client // && replies[i].seqno == batch[i].seqno) { var (states, replies) := HandleRequestBatchHidden(state, batch); lemma_HandleRequestBatchHidden(state, batch, states, replies); (states, replies) } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/RSL/Types.i.dfy ================================================ include "../../Services/RSL/AppStateMachine.s.dfy" include "../Common/NodeIdentity.i.dfy" module LiveRSL__Types_i { import opened AppStateMachine_s import opened Concrete_NodeIdentity_i type OperationNumber = int datatype Ballot = Ballot(seqno:int, proposer_id:int) datatype Request = Request(client:NodeIdentity, seqno:int, request:AppRequest) datatype Reply = Reply(client:NodeIdentity, seqno:int, reply:AppReply) type RequestBatch = seq type ReplyCache = map datatype Vote = Vote(max_value_bal:Ballot, ghost max_val:RequestBatch) type Votes = map datatype LearnerTuple = LearnerTuple(received_2b_message_senders:set, candidate_learned_value:RequestBatch) type LearnerState = map predicate BalLt(ba:Ballot, bb:Ballot) { || ba.seqno < bb.seqno || (ba.seqno==bb.seqno && ba.proposer_id < bb.proposer_id) } predicate BalLeq(ba:Ballot, bb:Ballot) { || ba.seqno < bb.seqno || (ba.seqno==bb.seqno && ba.proposer_id <= bb.proposer_id) } lemma lemma_BalLtMiddle(ba:Ballot, bb:Ballot) requires !BalLt(ba,bb) requires ba!=bb ensures BalLt(bb, ba) { } lemma lemma_BalLtProperties() ensures forall ba,bb :: !BalLt(ba,bb) && ba!=bb ==> BalLt(bb,ba) ensures forall ba,bb :: BalLeq(ba,bb) ==> BalLt(ba,bb) || ba==bb // Transitivity ensures forall ba,bb,bc :: BalLt(ba, bb) && BalLt(bb, bc) ==> BalLt(ba,bc) ensures forall ba,bb,bc :: BalLt(ba, bb) && BalLeq(bb, bc) ==> BalLt(ba,bc) ensures forall ba,bb,bc :: BalLeq(ba, bb) && BalLt(bb, bc) ==> BalLt(ba,bc) { forall (ba,bb | !BalLt(ba,bb) && ba!=bb) ensures BalLt(bb,ba) { lemma_BalLtMiddle(ba,bb); } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/SHT/Configuration.i.dfy ================================================ include "Host.i.dfy" include "Parameters.i.dfy" module SHT__Configuration_i { import opened SHT__Host_i import opened Protocol_Parameters_i import opened Concrete_NodeIdentity_i`Spec datatype SHTConfiguration = SHTConfiguration( clientIds:seq, hostIds:seq, rootIdentity:NodeIdentity, params:Parameters) predicate HostsDistinct(hostIds:seq, i:int, j:int) { 0 <= i < |hostIds| && 0 <= j < |hostIds| && hostIds[i] == hostIds[j] ==> i == j } predicate WFSHTConfiguration(c:SHTConfiguration) { 0 < |c.hostIds| && c.rootIdentity in c.hostIds && (forall i, j :: HostsDistinct(c.hostIds, i, j)) } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/SHT/Delegations.i.dfy ================================================ include "../../Common/Collections/Maps2.s.dfy" include "Message.i.dfy" include "Keys.i.dfy" module SHT__Delegations_i { import opened Collections__Maps2_s import opened AppInterface_i`Spec import opened Concrete_NodeIdentity_i`Spec import opened SHT__HT_s import opened SHT__Message_i import opened SHT__Keys_i type DelegationMap = imap predicate DelegationMapComplete(dm:DelegationMap) { forall k :: k in dm } function {:opaque} UpdateDelegationMap(dm:DelegationMap, newkr:KeyRange, host:NodeIdentity) : DelegationMap requires DelegationMapComplete(dm); ensures DelegationMapComplete(UpdateDelegationMap(dm, newkr, host)); ensures forall k :: UpdateDelegationMap(dm, newkr, host)[k] == if KeyRangeContains(newkr, KeyPlus(k)) then host else dm[k]; { imap k :: if KeyRangeContains(newkr, KeyPlus(k)) then host else dm[k] } predicate DelegateForKeyRangeIsHost(dm:DelegationMap, kr:KeyRange, id:NodeIdentity) requires DelegationMapComplete(dm); { forall k :: KeyRangeContains(kr, KeyPlus(k)) ==> dm[k] == id } // Used in proofs of refinement of implementable data structures to DelegationMap predicate DelegationMapsAreEqualUpToKey(adm:DelegationMap, bdm:DelegationMap, khi:KeyPlus) requires DelegationMapComplete(adm); requires DelegationMapComplete(bdm); { forall k :: KeyPlusLt(KeyPlus(k), khi) ==> adm[k] == bdm[k] } // legacy definition function DelegateForKey(dm:DelegationMap, k:Key) : NodeIdentity requires DelegationMapComplete(dm); { dm[k] } ////////////////////////////////////////////////////////////////////////////// // Functions to update a node's hash table on receipt and transmission of // delegation messages: ////////////////////////////////////////////////////////////////////////////// function BulkUpdateDomain(h:Hashtable, kr:KeyRange, u:Hashtable) : set { // Clumsy heuristically-obviously-finite set construction set k | k in mapdomain(h)+mapdomain(u) && (KeyRangeContains(kr, KeyPlus(k)) ==> k in u) } function BulkUpdateHashtable(h:Hashtable, kr:KeyRange, u:Hashtable) : Hashtable { map k {:auto_trigger} | k in BulkUpdateDomain(h, kr, u) :: if (k in u) then u[k] else h[k] } function BulkRemoveHashtable(h:Hashtable, kr:KeyRange) : Hashtable { map k | (k in h && !KeyRangeContains(kr, KeyPlus(k))) :: h[k] } function ExtractRange(h:Hashtable, kr:KeyRange) : Hashtable { map k | (k in h && KeyRangeContains(kr, KeyPlus(k))) :: h[k] } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/SHT/Host.i.dfy ================================================ include "SingleDelivery.i.dfy" include "Delegations.i.dfy" include "Parameters.i.dfy" include "../LiveSHT/RefinementProof/Environment.i.dfy" include "../../Common/Collections/Sets.i.dfy" include "../../Common/Logic/Option.i.dfy" include "../../Services/SHT/AbstractService.s.dfy" include "../Common/NodeIdentity.i.dfy" module SHT__Host_i { import opened Native__Io_s import opened Collections__Maps2_s import opened SHT__SingleDelivery_i import opened SHT__Delegations_i import opened Protocol_Parameters_i import opened LiveSHT__Environment_i import opened Collections__Sets_i import opened Logic__Option_i import opened AbstractServiceSHT_s`All import opened Concrete_NodeIdentity_i import opened SHT__HT_s import opened SHT__Message_i import opened SHT__SingleMessage_i import opened SHT__Network_i import opened AppInterface_i`Spec import opened SHT__Keys_i datatype Constants = Constants( rootIdentity:NodeIdentity, hostIds:seq, params:Parameters) datatype Host = Host( constants:Constants, me:NodeIdentity, ghost delegationMap:DelegationMap, h:Hashtable, sd:SingleDeliveryAcct, receivedPacket:Option, numDelegations:int, ghost receivedRequests:seq ) function LSHTPacketToPacket(lp:LSHTPacket) : Packet { Packet(lp.dst, lp.src, lp.msg) } predicate ValidKeyPlus(key:KeyPlus) { key.KeyZero? || key.KeyInf? || ValidKey(key.k) } predicate ValidOptionalValue(opt:OptionalValue) { opt.ValueAbsent? || ValidValue(opt.v) } predicate ValidKeyRange(kr:KeyRange) { ValidKeyPlus(kr.klo) && ValidKeyPlus(kr.khi) } function ExtractPacketsFromLSHTPackets(seqPackets:seq) : set ensures forall p :: p in seqPackets <==> Packet(p.dst, p.src, p.msg) in ExtractPacketsFromLSHTPackets(seqPackets) { MapSeqToSet(seqPackets, LSHTPacketToPacket) } predicate DelegationMap_InitTrigger(k:Key) { true } function DelegationMap_Init(rootIdentity:NodeIdentity) : DelegationMap { imap k {:trigger DelegationMap_InitTrigger(k)} :: rootIdentity } function method HashtableLookup(h:Hashtable, k:Key) : OptionalValue { if k in h then ValuePresent(h[k]) else ValueAbsent() } // Initially, everybody thinks the root is in charge of every key. predicate Host_Init(s:Host, id:NodeIdentity, rootIdentity:NodeIdentity, hostIds:seq, params:Parameters) { s==Host( Constants(rootIdentity, hostIds, params), id, DelegationMap_Init(rootIdentity), map [], SingleDelivery_Init(), None, 1, []) } predicate NextGetRequest_Reply(s:Host, s':Host, src:NodeIdentity, seqno:int, k:Key, sm:SingleMessage, m:Message, out:set, shouldSend:bool) requires DelegationMapComplete(s.delegationMap); { var owner := DelegateForKey(s.delegationMap, k); if shouldSend && ValidKey(k) then (if owner == s.me then m == Reply(k, HashtableLookup(s.h, k)) && s'.receivedRequests == s.receivedRequests + [AppGetRequest(seqno, k)] else m == Redirect(k, owner) && s'.receivedRequests == s.receivedRequests ) && SendSingleMessage(s.sd, s'.sd, m, sm, s.constants.params, shouldSend) && sm.dst == src && out == {Packet(src, s.me, sm)} else s' == s.(receivedPacket := s'.receivedPacket) && out == {} } predicate NextGetRequest(s:Host, s':Host, pkt:Packet, out:set) requires pkt.msg.SingleMessage?; requires DelegationMapComplete(s.delegationMap); { pkt.msg.m.GetRequest? && s'.delegationMap == s.delegationMap && s'.h == s.h && s'.numDelegations == s.numDelegations // UNCHANGED && (exists sm,m,b :: NextGetRequest_Reply(s, s', pkt.src, pkt.msg.seqno, pkt.msg.m.k_getrequest, sm, m, out, b)) } predicate NextSetRequest_Complete(s:Host, s':Host, src:NodeIdentity, seqno:int, reqm:Message, sm:SingleMessage, replym:Message, out:set, shouldSend:bool) requires DelegationMapComplete(s.delegationMap); requires reqm.SetRequest?; { var k := reqm.k_setrequest; var ov := reqm.v_setrequest; var owner := DelegateForKey(s.delegationMap, k); if shouldSend && ValidKey(k) && ValidOptionalValue(ov) then (if owner == s.me then s'.h == (if ov.ValueAbsent? then mapremove(s.h, k) else s.h[k:=ov.v]) && replym == Reply(k, ov) && s'.receivedRequests == s.receivedRequests + [AppSetRequest(seqno, k, ov)] else s'.h == s.h && replym == Redirect(k, owner) && s'.receivedRequests == s.receivedRequests ) && SendSingleMessage(s.sd, s'.sd, replym, sm, s.constants.params, shouldSend) && sm.dst == src && out == {Packet(src, s.me, sm)} else s' == s.(receivedPacket := s'.receivedPacket) && out == {} } predicate NextSetRequest(s:Host, s':Host, pkt:Packet, out:set) requires pkt.msg.SingleMessage?; requires DelegationMapComplete(s.delegationMap); { pkt.msg.m.SetRequest? && (exists sm,m,b :: NextSetRequest_Complete(s, s', pkt.src, pkt.msg.seqno, pkt.msg.m, sm, m, out, b)) && s'.delegationMap == s.delegationMap // UNCHANGED && s'.numDelegations == s.numDelegations // UNCHANGED } predicate NextDelegate(s:Host, s':Host, pkt:Packet, out:set) requires pkt.msg.SingleMessage?; requires DelegationMapComplete(s.delegationMap); { pkt.msg.m.Delegate? && (if pkt.src in s.constants.hostIds then s'.delegationMap == UpdateDelegationMap(s.delegationMap, pkt.msg.m.range, s.me) && s'.h == BulkUpdateHashtable(s.h, pkt.msg.m.range, pkt.msg.m.h) && s'.numDelegations == s.numDelegations + 1 else s'.delegationMap == s.delegationMap && s'.h == s.h && s'.numDelegations == s.numDelegations ) && SendNoMessage(s.sd, s'.sd) && ReceiveNoMessage(s.sd, s'.sd) && out == {} && s'.receivedRequests == s.receivedRequests } predicate NextShard(s:Host, s':Host, out:set, kr:KeyRange, recipient:NodeIdentity, sm:SingleMessage, shouldSend:bool) requires DelegationMapComplete(s.delegationMap); { recipient != s.me // HISTORY: proof caught this missing conjunct && recipient in s.constants.hostIds // HISTORY: proof caught this missing conjunct && DelegateForKeyRangeIsHost(s.delegationMap, kr, s.me) // HISTORY: proof caught this missing conjunct! && SendSingleMessage(s.sd, s'.sd, Delegate(kr, ExtractRange(s.h, kr)), sm, s.constants.params, shouldSend) && recipient == sm.dst && s.constants == s'.constants && s'.numDelegations == s.numDelegations + 1 && s'.receivedRequests == s.receivedRequests && if shouldSend then out == { Packet(recipient, s.me, sm) } && s'.delegationMap == UpdateDelegationMap(s.delegationMap, kr, recipient) && s'.h == BulkRemoveHashtable(s.h, kr) else out == {} && s'.delegationMap == s.delegationMap && s'.h == s.h } function max_hashtable_size():int { 62 } predicate NextShard_Wrapper(s:Host, s':Host, pkt:Packet, out:set) requires pkt.msg.SingleMessage?; requires DelegationMapComplete(s.delegationMap); { pkt.msg.m.Shard? && if ( pkt.msg.m.recipient == s.me || !ValidKeyRange(pkt.msg.m.kr) || !ValidPhysicalAddress(pkt.msg.m.recipient) || EmptyKeyRange(pkt.msg.m.kr) || pkt.msg.m.recipient !in s.constants.hostIds || !DelegateForKeyRangeIsHost(s.delegationMap, pkt.msg.m.kr, s.me) || |ExtractRange(s.h, pkt.msg.m.kr)| >= max_hashtable_size()) then s' == s.(receivedPacket := s'.receivedPacket) && out == {} else exists sm,b :: NextShard(s, s', out, pkt.msg.m.kr, pkt.msg.m.recipient, sm, b) } predicate NextReply(s:Host, s':Host, pkt:Packet, out:set) requires pkt.msg.SingleMessage?; requires DelegationMapComplete(s.delegationMap); { pkt.msg.m.Reply? && out == {} && s' == s.(receivedPacket := s'.receivedPacket) } predicate NextRedirect(s:Host, s':Host, pkt:Packet, out:set) requires pkt.msg.SingleMessage?; requires DelegationMapComplete(s.delegationMap); { pkt.msg.m.Redirect? && out == {} && s' == s.(receivedPacket := s'.receivedPacket) } predicate ShouldProcessReceivedMessage(s:Host) { s.receivedPacket.Some? && s.receivedPacket.v.msg.SingleMessage? && ((s.receivedPacket.v.msg.m.Delegate? || s.receivedPacket.v.msg.m.Shard?) ==> s.numDelegations < s.constants.params.max_delegations - 2) } predicate Process_Message(s:Host, s':Host, out:set) requires DelegationMapComplete(s.delegationMap); { if ShouldProcessReceivedMessage(s) then (NextGetRequest(s, s', s.receivedPacket.v, out) || NextSetRequest(s, s', s.receivedPacket.v, out) || NextDelegate(s, s', s.receivedPacket.v, out) || NextShard_Wrapper(s, s', s.receivedPacket.v, out) || NextReply(s, s', s.receivedPacket.v, out) || NextRedirect(s, s', s.receivedPacket.v, out)) && s'.receivedPacket.None? else s' == s && out == {} } predicate ReceivePacket(s:Host, s':Host, pkt:Packet, out:set, ack:Packet) { if s.receivedPacket.None? then // No packet currently waiting to be processed ReceiveSingleMessage(s.sd, s'.sd, pkt, ack, out) // Record and possibly ack it && (if NewSingleMessage(s.sd, pkt) then s'.receivedPacket == Some(pkt) // Enqueue this packet for processing else s'.receivedPacket.None?) && s' == s.(sd := s'.sd, receivedPacket := s'.receivedPacket) // Nothing else changes else s' == s && out == {} } predicate ProcessReceivedPacket(s:Host, s':Host, out:set) requires DelegationMapComplete(s.delegationMap); { if s.receivedPacket.Some? then Process_Message(s, s', out) else s' == s && out == {} } // REVIEW: For safety, we don't need to retransmit at all. // We could also just retransmit some, but not all, leaving it to the impl to decide. // For liveness, we have to retransmit some, and at the very least, retransmit in some order. // I suspect retransmitting them all will simplify things, however. predicate SpontaneouslyRetransmit(s:Host, s':Host, out:set) { (out == UnAckedMessages(s.sd, s.me) && s == s') } predicate Host_Next(s:Host, s':Host, recv:set, out:set) { s'.constants == s.constants && s'.me == s.me && DelegationMapComplete(s.delegationMap) && ( (exists pkt, ack :: pkt in recv && ReceivePacket(s, s', pkt, out, ack)) || ProcessReceivedPacket(s, s', out) || SpontaneouslyRetransmit(s, s', out) ) } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/SHT/Keys.i.dfy ================================================ include "../../Services/SHT/AppInterface.i.dfy" module SHT__Keys_i { import opened AppInterface_i`All predicate method KeyLe(ka:Key, kb:Key) { ka == kb || KeyLt(ka, kb) } lemma KeyAntisymmetry(ka:Key, kb:Key) ensures KeyLt(ka,kb) ==> !KeyLe(kb,ka); ensures !KeyLt(ka,kb) ==> KeyLe(kb,ka); ensures KeyLe(ka,kb) ==> !KeyLt(kb,ka); ensures !KeyLe(ka,kb) ==> KeyLt(kb,ka); { lemma_KeyOrdering(); } lemma KeyEq(ka:Key, kb:Key) requires ka==kb; ensures KeyLe(ka, kb); ensures KeyLe(kb, ka); { } lemma KeyReflexivity(ka:Key, kb:Key) requires KeyLe(ka, kb); requires KeyLe(kb, ka); ensures ka==kb; { lemma_KeyOrdering(); } lemma KeyTransitivityLe(ka:Key, kb:Key, kc:Key) requires KeyLe(ka,kb) && KeyLe(kb,kc); ensures KeyLe(ka,kc); { lemma_KeyOrdering(); } lemma KeyTransitivity(ka:Key, kb:Key, kc:Key) ensures KeyLt(ka,kb) && KeyLe(kb,kc) ==> KeyLt(ka,kc); ensures KeyLe(ka,kb) && KeyLt(kb,kc) ==> KeyLt(ka,kc); ensures KeyLt(ka,kb) && KeyLt(kb,kc) ==> KeyLt(ka,kc); ensures KeyLe(ka,kb) && KeyLe(kb,kc) ==> KeyLe(ka,kc); { lemma_KeyOrdering(); } ////////////////////////////////////////////////////////////////////////////// // KeyPlus creates lower and upper bounds for keys datatype KeyPlus = KeyZero() | KeyPlus(k:Key) | KeyInf() predicate method KeyPlusLt(kp:KeyPlus, kp':KeyPlus) { kp != kp' && match kp { case KeyZero => true case KeyInf => false case KeyPlus(k) => match kp' { case KeyZero => false case KeyInf => true case KeyPlus(k') => KeyLt(k, k') } } } predicate method KeyPlusLe(kp:KeyPlus, kp':KeyPlus) { kp == kp' || KeyPlusLt(kp, kp') } lemma KeyPlusAntisymmetry(ka:KeyPlus, kb:KeyPlus) ensures KeyPlusLt(ka,kb) ==> !KeyPlusLe(kb,ka); ensures !KeyPlusLt(ka,kb) ==> KeyPlusLe(kb,ka); ensures KeyPlusLe(ka,kb) ==> !KeyPlusLt(kb,ka); ensures !KeyPlusLe(ka,kb) ==> KeyPlusLt(kb,ka); { if ka.KeyPlus? && kb.KeyPlus? { KeyAntisymmetry(ka.k, kb.k); } } lemma KeyPlusTransitivity(ka:KeyPlus, kb:KeyPlus, kc:KeyPlus) ensures KeyPlusLt(ka,kb) && KeyPlusLe(kb,kc) ==> KeyPlusLt(ka,kc); ensures KeyPlusLe(ka,kb) && KeyPlusLt(kb,kc) ==> KeyPlusLt(ka,kc); ensures KeyPlusLt(ka,kb) && KeyPlusLt(kb,kc) ==> KeyPlusLt(ka,kc); ensures KeyPlusLe(ka,kb) && KeyPlusLe(kb,kc) ==> KeyPlusLe(ka,kc); { lemma_KeyOrdering(); } ////////////////////////////////////////////////////////////////////////////// // KeyRanges datatype KeyRange = KeyRange(klo:KeyPlus, khi:KeyPlus) // range includes all keys klo <= k < khi predicate method KeyRangeContains(range:KeyRange, kp:KeyPlus) { KeyPlusLe(range.klo, kp) && KeyPlusLt(kp, range.khi) } predicate RangesOverlap(kra:KeyRange, krb:KeyRange) { KeyRangeContains(kra, krb.klo) || KeyRangeContains(kra, krb.khi) || KeyRangeContains(krb, kra.klo) || KeyRangeContains(krb, kra.khi) // Redundant, but adds symmetry } function CompleteRange() : KeyRange { KeyRange(KeyZero(), KeyInf()) } predicate method EmptyKeyRange(kr:KeyRange) { KeyPlusLe(kr.khi, kr.klo) } lemma lemma_EmptyKeyRange(kr:KeyRange) ensures EmptyKeyRange(kr) <==> !KeyPlusLt(kr.klo, kr.khi); { KeyPlusAntisymmetry(kr.klo, kr.khi); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/SHT/Message.i.dfy ================================================ include "../Common/NodeIdentity.i.dfy" include "Keys.i.dfy" include "../../Services/SHT/HT.s.dfy" module SHT__Message_i { import opened AppInterface_i`Spec import opened Concrete_NodeIdentity_i`Spec import opened SHT__Keys_i import opened SHT__HT_s datatype Message = GetRequest(k_getrequest:Key) | SetRequest(k_setrequest:Key, v_setrequest:OptionalValue) | Reply(k_reply:Key, v:OptionalValue) | Redirect(k_redirect:Key, id:NodeIdentity) | Shard(kr:KeyRange, recipient:NodeIdentity) | Delegate(range:KeyRange, h:Hashtable) } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/SHT/Network.i.dfy ================================================ include "Message.i.dfy" include "SingleMessage.i.dfy" module SHT__Network_i { import opened Concrete_NodeIdentity_i`Spec import opened SHT__Message_i import opened SHT__SingleMessage_i // Ugly failure to parameterize type PMsg = SingleMessage datatype Packet = Packet(dst:NodeIdentity, src:NodeIdentity, msg:PMsg) type Network = set predicate Network_Init(n:Network) { n == {} } function PacketsTo(ps:set, dst:NodeIdentity) : set { set p | p in ps && p.dst ==dst } predicate Network_Receive(n:Network, dst:NodeIdentity, recv:set) { recv == PacketsTo(n, dst) } predicate Network_Send(n:Network, n':Network, src:NodeIdentity, out:set) { (forall p :: p in out ==> p.src == src) // Jay rewired this to have OutboundPackets && n' == n + out } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/SHT/Parameters.i.dfy ================================================ module Protocol_Parameters_i { datatype Parameters = Parameters(max_seqno:nat, max_delegations:nat) } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/SHT/RefinementProof/InvDefs.i.dfy ================================================ include "SHT.i.dfy" module SHT__InvDefs_i { import opened SHT__SHT_i import opened Concrete_NodeIdentity_i`Spec import opened SHT__Network_i import opened AppInterface_i`Spec import opened SHT__HT_s import opened SHT__SingleDelivery_i import opened SHT__Host_i import opened Logic__Option_i import opened SHT__Keys_i import opened SHT__Delegations_i // The Refinement definition (Lamport's Bar()) is trusted. // Ugh. That makes the entire Host.i definition ... trusted! Aaagh! // What a mess. Instead, can't we exists something? ////////////////////////////////////////////////////////////////////////////// // These welformedness conditions are needed to define the refinement // mapping, so they get floated up here function AllHostIdentities(s:SHT_State) : seq requires SHT_MapsComplete(s); ensures forall id :: id in AllHostIdentities(s) ==> id in s.hosts; { s.config.hostIds } predicate MapComplete(s:SHT_State) { SHT_MapsComplete(s) && (forall id :: id in AllHostIdentities(s) ==> DelegationMapComplete(s.hosts[id].delegationMap)) } predicate AllDelegationsToKnownHosts(s:SHT_State) requires MapComplete(s); { forall id,k :: id in AllHostIdentities(s) ==> DelegateForKey(s.hosts[id].delegationMap, k) in AllHostIdentities(s) } ////////////////////////////////////////////////////////////////////////////// // Unacked list predicate NoAcksInUnAckedLists(acct:SingleDeliveryAcct) { forall id, i :: var unAcked := AckStateLookup(id, acct.sendState).unAcked; 0 <= i < |unAcked| ==> unAcked[i].SingleMessage? } predicate UnAckedListsSequential(acct:SingleDeliveryAcct) requires NoAcksInUnAckedLists(acct); { forall id, i, j :: var unAcked := AckStateLookup(id, acct.sendState).unAcked; 0 <= i && j == i + 1 && j < |unAcked| ==> unAcked[i].seqno + 1 == unAcked[j].seqno } predicate UnAckedDstsConsistent(acct:SingleDeliveryAcct) requires NoAcksInUnAckedLists(acct); { forall id, i :: var unAcked := AckStateLookup(id, acct.sendState).unAcked; 0 <= i < |unAcked| ==> unAcked[i].dst == id } predicate UnAckedListExceedsNumPacketsAcked(acct:SingleDeliveryAcct) requires NoAcksInUnAckedLists(acct); { forall id :: var ackState := AckStateLookup(id, acct.sendState); |ackState.unAcked| > 0 ==> ackState.unAcked[0].seqno == ackState.numPacketsAcked + 1 } predicate {:opaque} UnAckedListInNetwork(s:SHT_State) requires MapComplete(s); { forall id,msg,dst {:trigger msg in AckStateLookup(dst, s.hosts[id].sd.sendState).unAcked } :: id in AllHostIdentities(s) && msg in AckStateLookup(dst, s.hosts[id].sd.sendState).unAcked && NoAcksInUnAckedLists(s.hosts[id].sd) && dst == msg.dst ==> Packet(msg.dst, s.hosts[id].me, msg) in s.network } predicate UnAckedListProperties(acct:SingleDeliveryAcct) { NoAcksInUnAckedLists(acct) && UnAckedListsSequential(acct) && UnAckedListExceedsNumPacketsAcked(acct) && UnAckedDstsConsistent(acct) } predicate AckListsInv(s:SHT_State) requires MapComplete(s); { UnAckedListInNetwork(s) && (forall id :: id in AllHostIdentities(s) ==> UnAckedListProperties(s.hosts[id].sd)) } /* predicate NoAcksInUnAckedLists(s:SHT_State) requires MapComplete(s); { forall id, id' :: id in AllHostIdentities() && id' in AllHostIdentities() ==> (var unAcked := AckStateLookup(id', s.hosts[id].sd.sendState).unAcked; forall i :: 0 <= i < |unAcked| ==> unAcked[i].SingleMessage?) } predicate UnAckedListsSequential(s:SHT_State) requires MapComplete(s); requires NoAcksInUnAckedLists(s); { forall id, id' :: id in AllHostIdentities() && id' in AllHostIdentities() ==> (var unAcked := AckStateLookup(id', s.hosts[id].sd.sendState).unAcked; forall i, j :: 0 <= i && j == i + 1 && j < |unAcked| ==> unAcked[i].seqno + 1 == unAcked[j].seqno) } predicate UnAckedListExceedsNumPacketsAcked(s:SHT_State) requires MapComplete(s); requires NoAcksInUnAckedLists(s); { forall id, id' :: id in AllHostIdentities() && id' in AllHostIdentities() ==> (var ackState := AckStateLookup(id', s.hosts[id].sd.sendState); |ackState.unAcked| > 0 ==> ackState.unAcked[0].seqno == ackState.numPacketsAcked + 1) } */ ////////////////////////////////////////////////////////////////////////////// // Hosts claim keys predicate DelegationPacket(p:Option) { p.Some? && p.v.msg.SingleMessage? && p.v.msg.m.Delegate? } predicate BufferedPacketClaimsKey(s:Host, k:Key) { DelegationPacket(s.receivedPacket) && KeyRangeContains(s.receivedPacket.v.msg.m.range, KeyPlus(k)) && s.receivedPacket.v.src in s.constants.hostIds && s.receivedPacket.v.dst in s.constants.hostIds } predicate HostClaimsKey(s:Host, k:Key) requires DelegationMapComplete(s.delegationMap); { // My map tells me I own the key DelegateForKey(s.delegationMap, k)==s.me || // or I have a buffered delegation message that gives me ownership of the key BufferedPacketClaimsKey(s, k) } ////////////////////////////////////////////////////////////////////////////// // Packets claim keys predicate PacketsHaveSaneHeaders(s:SHT_State) requires MapComplete(s); { true // Can't establish this once we start letting clients send packets // forall pkt :: pkt in s.network // ==> pkt.src in AllHostIdentities(s) && pkt.dst in AllHostIdentities(s) } predicate PacketInFlight(s:SHT_State, pkt:Packet) requires MapComplete(s); { pkt in s.network && pkt.src in AllHostIdentities(s) && pkt.dst in AllHostIdentities(s) && MessageNotReceived(s.hosts[pkt.dst].sd, pkt.src, pkt.msg) } predicate InFlightPacketClaimsKey(s:SHT_State, pkt:Packet, k:Key) requires MapComplete(s); { pkt.msg.SingleMessage? && pkt.msg.m.Delegate? && PacketInFlight(s, pkt) && KeyRangeContains(pkt.msg.m.range, KeyPlus(k)) } // TODO Explicitly name these CHOOSE invocations to work around Dafny bug function ThePacketThatClaimsKey(s:SHT_State, k:Key) : Packet requires MapComplete(s); requires PacketsHaveSaneHeaders(s); requires exists pkt :: InFlightPacketClaimsKey(s,pkt,k); ensures var p := ThePacketThatClaimsKey(s,k); p.msg.SingleMessage? && p.msg.m.Delegate?; { var pkt :| InFlightPacketClaimsKey(s,pkt,k); pkt } function TheHostThatClaimsKey(s:SHT_State, k:Key) : NodeIdentity requires MapComplete(s); requires AllDelegationsToKnownHosts(s); requires exists id {:trigger HostClaimsKey(s.hosts[id], k)} :: id in AllHostIdentities(s) && HostClaimsKey(s.hosts[id], k); { var id :| id in AllHostIdentities(s) && HostClaimsKey(s.hosts[id], k); id } function FindHostHashTable(s:SHT_State, k:Key) : Hashtable requires MapComplete(s); requires PacketsHaveSaneHeaders(s); requires AllDelegationsToKnownHosts(s); requires exists id {:trigger HostClaimsKey(s.hosts[id], k)} :: id in AllHostIdentities(s) && HostClaimsKey(s.hosts[id], k); { var id := TheHostThatClaimsKey(s, k); if BufferedPacketClaimsKey(s.hosts[id], k) then // && NewSingleMessage(s.hosts[id].sd, s.hosts[id].receivedPacket.v) then s.hosts[id].receivedPacket.v.msg.m.h else // assert DelegateForKey(s.hosts[id].delegationMap, k)==s.hosts[id]..me s.hosts[id].h } function FindHashTable(s:SHT_State, k:Key) : Hashtable requires MapComplete(s); requires PacketsHaveSaneHeaders(s); requires AllDelegationsToKnownHosts(s); { if exists pkt :: InFlightPacketClaimsKey(s,pkt,k) then ThePacketThatClaimsKey(s,k).msg.m.h else if exists id {:trigger HostClaimsKey(s.hosts[id], k)} :: id in AllHostIdentities(s) && HostClaimsKey(s.hosts[id], k) then FindHostHashTable(s, k) else // Inv ==> this case is false map [] } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/SHT/RefinementProof/InvProof.i.dfy ================================================ include "InvDefs.i.dfy" module SHT__InvProof_i { import opened Native__Io_s import opened SHT__SHT_i import opened Concrete_NodeIdentity_i`Spec import opened SHT__Network_i import opened AppInterface_i`Spec import opened SHT__HT_s import opened SHT__SingleDelivery_i import opened SHT__Host_i import opened Logic__Option_i import opened SHT__Keys_i import opened SHT__Delegations_i import opened SHT__InvDefs_i import opened SHT__Message_i import opened SHT__SingleMessage_i import opened Protocol_Parameters_i import opened SHT__Configuration_i lemma lemma_AllDelegationsToKnownHosts(s:SHT_State, k:Key, id:NodeIdentity, nextId:NodeIdentity) requires MapComplete(s); requires AllDelegationsToKnownHosts(s); requires id in AllHostIdentities(s); requires nextId == DelegateForKey(s.hosts[id].delegationMap, k); ensures nextId in AllHostIdentities(s); { var dm := s.hosts[id].delegationMap; } predicate NoHostsStoreEmptyValues(s:SHT_State) requires MapComplete(s); { forall id,k :: id in AllHostIdentities(s) && HostClaimsKey(s.hosts[id], k) && k in s.hosts[id].h ==> HashtableLookup(s.hosts[id].h, k) != ValueAbsent() } predicate BufferedDelegationPacketPresent(pkt:Option) requires DelegationPacket(pkt); { forall k {:trigger HashtableLookup(pkt.v.msg.m.h, k) }:: k in pkt.v.msg.m.h ==> HashtableLookup(pkt.v.msg.m.h, k) != ValueAbsent() } predicate BufferedPacketsInv(s:SHT_State) requires MapComplete(s); { forall id :: id in AllHostIdentities(s) ==> (s.hosts[id].receivedPacket.Some? ==> s.hosts[id].receivedPacket.v in s.network) && (s.hosts[id].receivedPacket.Some? ==> s.hosts[id].receivedPacket.v.dst == id) && (DelegationPacket(s.hosts[id].receivedPacket) ==> BufferedDelegationPacketPresent(s.hosts[id].receivedPacket)) } predicate DestinationsConsistent(s:SHT_State) requires MapComplete(s); { forall pkt :: pkt in s.network && pkt.msg.SingleMessage? && pkt.src in AllHostIdentities(s) ==> pkt.msg.dst == pkt.dst } predicate DelegationMessagesCarryNoEmptyValues(s:SHT_State) { forall pkt, k :: pkt in s.network && pkt.msg.SingleMessage? && pkt.msg.m.Delegate? && k in pkt.msg.m.h ==> HashtableLookup(pkt.msg.m.h, k) != ValueAbsent() } predicate DelegationMessagesCarryOnlyClaimedKeys(s:SHT_State) requires MapComplete(s); { forall pkt, k :: pkt in s.network && pkt.src in AllHostIdentities(s) && pkt.msg.SingleMessage? && pkt.msg.m.Delegate? && k in pkt.msg.m.h ==> KeyRangeContains(pkt.msg.m.range, KeyPlus(k)) } ////////////////////////////////////////////////////////////////////////////// // EachKeyClaimedInExactlyOnePlace (one Host or one Packet) predicate SomeHostClaimsKey(s:SHT_State, k:Key) requires MapComplete(s); { exists id {:trigger HostClaimsKey(s.hosts[id], k)} :: id in AllHostIdentities(s) && HostClaimsKey(s.hosts[id], k) } predicate OnlyOneHostClaimsKey(s:SHT_State, k:Key) requires MapComplete(s); { forall i1,i2 {:trigger HostClaimsKey(s.hosts[i1], k), HostClaimsKey(s.hosts[i2], k)} :: i1 in AllHostIdentities(s) && HostClaimsKey(s.hosts[i1], k) && i2 in AllHostIdentities(s) && HostClaimsKey(s.hosts[i2], k) ==> i1==i2 } predicate UniqueHostClaimsKey(s:SHT_State, k:Key) requires MapComplete(s); { SomeHostClaimsKey(s,k) && OnlyOneHostClaimsKey(s,k) } predicate NoHostClaimsKey(s:SHT_State, k:Key) requires MapComplete(s); { forall id {:trigger HostClaimsKey(s.hosts[id], k)} :: id in AllHostIdentities(s) ==> !HostClaimsKey(s.hosts[id], k) } predicate SomePacketClaimsKey(s:SHT_State, k:Key) requires MapComplete(s); requires PacketsHaveSaneHeaders(s); { exists pkt {:trigger InFlightPacketClaimsKey(s, pkt, k)} :: InFlightPacketClaimsKey(s, pkt, k) } predicate OnlyOnePacketClaimsKey(s:SHT_State, k:Key) requires MapComplete(s); requires PacketsHaveSaneHeaders(s); { forall p1,p2 // {:trigger InFlightPacketClaimsKey(s, p1, k), InFlightPacketClaimsKey(s, p2, k)} {:auto_trigger} :: InFlightPacketClaimsKey(s, p1, k) && InFlightPacketClaimsKey(s, p2, k) ==> p1==p2 } predicate UniqueInFlightPacketClaimsKey(s:SHT_State, k:Key) requires MapComplete(s); requires PacketsHaveSaneHeaders(s); { SomePacketClaimsKey(s, k) && OnlyOnePacketClaimsKey(s, k) } predicate NoInFlightPacketClaimsKey(s:SHT_State, k:Key) requires MapComplete(s); requires PacketsHaveSaneHeaders(s); { forall pkt {:trigger InFlightPacketClaimsKey(s, pkt, k)} :: !InFlightPacketClaimsKey(s, pkt, k) } // Lots of exists in here seem to make this a brittle invariant to expose. predicate {:opaque} EachKeyClaimedInExactlyOnePlace(s:SHT_State) requires MapComplete(s); requires PacketsHaveSaneHeaders(s); { forall k :: (UniqueInFlightPacketClaimsKey(s, k) && NoHostClaimsKey(s, k)) || (NoInFlightPacketClaimsKey(s, k) && UniqueHostClaimsKey(s, k)) } ////////////////////////////////////////////////////////////////////////////// predicate InvConstants(s:SHT_State) requires MapComplete(s); { forall id {:auto_trigger} :: id in AllHostIdentities(s) ==> s.hosts[id].me == id && s.hosts[id].constants.hostIds == s.config.hostIds } predicate HostsStoreOnlyOwnedKeys(s:SHT_State) requires MapComplete(s); { forall id,k :: id in AllHostIdentities(s) && k in s.hosts[id].h ==> HostClaimsKey(s.hosts[id], k) } predicate {:opaque} PacketsHaveSenderUniqueSeqnos(s:SHT_State) requires MapComplete(s); { forall p1,p2 :: p1 in s.network && p2 in s.network && p1.msg.SingleMessage? && p2.msg.SingleMessage? && p1.src == p2.src && p1.dst == p2.dst && p1.src in AllHostIdentities(s) && p1.dst in AllHostIdentities(s) && p2.src in AllHostIdentities(s) && p2.dst in AllHostIdentities(s) && p1.msg.seqno == p2.msg.seqno ==> p1 == p2 } // Need this invariant to prove ReceiverHasCanceledNoUnsentSeqnos predicate NoPacketContainsUnsentSeqno(s:SHT_State) requires MapComplete(s); requires PacketsHaveSaneHeaders(s); { forall pkt :: pkt in s.network && pkt.msg.SingleMessage? && pkt.src in AllHostIdentities(s) && pkt.dst in AllHostIdentities(s) ==> pkt.msg.seqno <= HighestSeqnoSent(s.hosts[pkt.src].sd, pkt.dst) } // Need this invariant to ensure that, at the moment we send a packet, // it isn't DOA because the recipient had inflated his receive seqno predicate ReceiverHasNotCanceledUnsentSeqno(s:SHT_State, dst:NodeIdentity, src:NodeIdentity, seqno:int) requires MapComplete(s); { dst in AllHostIdentities(s) && src in AllHostIdentities(s) && HighestSeqnoSent(s.hosts[src].sd, dst) < seqno ==> seqno > TombstoneTableLookup(src, s.hosts[dst].sd.receiveState) } predicate ReceiverHasCanceledNoUnsentSeqnos(s:SHT_State) requires MapComplete(s); { forall dst, src, seqno :: ReceiverHasNotCanceledUnsentSeqno(s, dst, src, seqno) } /////////////////////////////////////////////////////// // The ultimate invariant ////////////////////////////////////////////////////// predicate Inv(s:SHT_State) { MapComplete(s) && InvConstants(s) && AckListsInv(s) && AllDelegationsToKnownHosts(s) && HostsStoreOnlyOwnedKeys(s) && BufferedPacketsInv(s) && DestinationsConsistent(s) && NoHostsStoreEmptyValues(s) && DelegationMessagesCarryNoEmptyValues(s) && DelegationMessagesCarryOnlyClaimedKeys(s) && PacketsHaveSaneHeaders(s) && PacketsHaveSenderUniqueSeqnos(s) // && NoHostClaimsInFlightKeys(s) && NoPacketContainsUnsentSeqno(s) && ReceiverHasCanceledNoUnsentSeqnos(s) && EachKeyClaimedInExactlyOnePlace(s) } predicate {:opaque} HiddenInv(s:SHT_State) { Inv(s) } /////////////////////////////////////////////////////// // AckList ////////////////////////////////////////////////////// lemma TruncateAckPreservesUnAckListProperties(unAcked:seq>, old_seqno:nat, new_seqno:nat, id:NodeIdentity) requires forall i :: 0 <= i < |unAcked| ==> unAcked[i].SingleMessage? requires forall i, j :: 0 <= i && j == i + 1 && j < |unAcked| ==> unAcked[i].seqno + 1 == unAcked[j].seqno; requires |unAcked| > 0 ==> unAcked[0].seqno == old_seqno + 1; requires new_seqno >= old_seqno; requires forall i :: 0 <= i < |unAcked| ==> unAcked[i].dst == id; ensures var truncated := TruncateUnAckList(unAcked, new_seqno); forall i :: 0 <= i < |truncated| ==> truncated[i].SingleMessage?; ensures var truncated := TruncateUnAckList(unAcked, new_seqno); forall i, j :: 0 <= i && j == i + 1 && j < |truncated| ==> truncated[i].seqno + 1 == truncated[j].seqno; ensures var truncated := TruncateUnAckList(unAcked, new_seqno); |truncated| > 0 ==> truncated[0].seqno == new_seqno + 1; ensures var truncated := TruncateUnAckList(unAcked, new_seqno); |unAcked| - |truncated| <= new_seqno - old_seqno; ensures var truncated := TruncateUnAckList(unAcked, new_seqno); forall i :: 0 <= i < |truncated| ==> truncated[i].dst == id; { assert |unAcked| > 0 ==> unAcked[0].SingleMessage?; if |unAcked| > 0 && unAcked[0].SingleMessage? && unAcked[0].seqno <= new_seqno { TruncateAckPreservesUnAckListProperties(unAcked[1..], old_seqno + 1, new_seqno, id); } else { if |unAcked| == 0 { } else { assert unAcked[0].seqno > new_seqno; } } } lemma TruncateAckPreservesSubset(unAcked:seq>) ensures forall m, seqno:nat :: var truncated := TruncateUnAckList(unAcked, seqno); m in truncated ==> m in unAcked; { forall m, seqno:nat | var truncated := TruncateUnAckList(unAcked, seqno); m in truncated ensures m in unAcked; { } } lemma UnAckedListFinalEntry(unAcked:seq>, old_seqno:nat) requires forall i :: 0 <= i < |unAcked| ==> unAcked[i].SingleMessage? requires forall i, j :: 0 <= i && j == i + 1 && j < |unAcked| ==> unAcked[i].seqno + 1 == unAcked[j].seqno requires |unAcked| > 0 ==> unAcked[0].seqno == old_seqno + 1; ensures |unAcked| > 0 ==> unAcked[|unAcked|-1].seqno == old_seqno + |unAcked|; { if |unAcked| == 0 { } else { UnAckedListFinalEntry(unAcked[1..], old_seqno+1); } } lemma SendSingleMessagePreservesUnAckListProperties(s:SingleDeliveryAcct, s':SingleDeliveryAcct, m:MT, sm:SingleMessage, params:Parameters, shouldSend:bool) requires UnAckedListProperties(s); requires ReceiveNoMessage(s, s'); requires SendSingleMessage(s, s', m, sm, params, shouldSend); ensures UnAckedListProperties(s'); { // Prove NoAcksInUnAckedLists assert forall id :: var unAcked := AckStateLookup(id, s.sendState).unAcked; forall i :: 0 <= i < |unAcked| ==> unAcked[i].SingleMessage?; forall id ensures var unAcked := AckStateLookup(id, s'.sendState).unAcked; forall i :: 0 <= i < |unAcked| ==> unAcked[i].SingleMessage?; { var unAcked := AckStateLookup(id, s'.sendState).unAcked; if sm.dst == id { assert shouldSend ==> unAcked == AckStateLookup(id, s.sendState).unAcked + [ sm ]; // OBSERVE: Key fact, I think } else { assert unAcked == AckStateLookup(id, s.sendState).unAcked; } } // Prove UnAckedListsSequential forall id ensures var unAcked := AckStateLookup(id, s'.sendState).unAcked; forall i, j :: 0 <= i && j == i + 1 && j < |unAcked| ==> unAcked[i].seqno + 1 == unAcked[j].seqno { var numPacketsAcked := AckStateLookup(id, s.sendState).numPacketsAcked; var unAcked := AckStateLookup(id, s.sendState).unAcked; var unAcked' := AckStateLookup(id, s'.sendState).unAcked; if sm.dst == id { assert shouldSend ==> unAcked' == unAcked + [ sm ]; if unAcked == [] { } else { assert unAcked[0].seqno == numPacketsAcked+1; UnAckedListFinalEntry(unAcked, numPacketsAcked); assert unAcked[|unAcked|-1].seqno == numPacketsAcked+1+|unAcked|-1; } assert shouldSend ==> sm.seqno == numPacketsAcked + |unAcked| + 1; } else { assert unAcked' == unAcked; } } // Prove UnAckedListExceedsNumPacketsAcked forall id ensures var ackState := AckStateLookup(id, s'.sendState); |ackState.unAcked| > 0 ==> ackState.unAcked[0].seqno == ackState.numPacketsAcked + 1; ensures var ackState := AckStateLookup(id, s'.sendState); forall i :: 0 <= i < |ackState.unAcked| ==> ackState.unAcked[i].dst == id; { var unAcked := AckStateLookup(id, s.sendState).unAcked; var unAcked' := AckStateLookup(id, s'.sendState).unAcked; if sm.dst == id { assert shouldSend ==> unAcked' == unAcked + [ sm ]; // OBSERVE: Key fact, I think } else { assert unAcked' == unAcked; } } } lemma ReceiveAckPreservesUnAckListProperties(s:SingleDeliveryAcct, s':SingleDeliveryAcct, pkt:Packet, acks:set) requires UnAckedListProperties(s); requires pkt.msg.Ack?; requires ReceiveAck(s, s', pkt, acks); ensures UnAckedListProperties(s'); { var oldAckState := AckStateLookup(pkt.src, s.sendState); var newAckState := AckStateLookup(pkt.src, s'.sendState); if pkt.msg.ack_seqno > oldAckState.numPacketsAcked { TruncateAckPreservesUnAckListProperties(oldAckState.unAcked, oldAckState.numPacketsAcked, pkt.msg.ack_seqno, pkt.src); assert forall id :: id != pkt.src ==> // OBSERVE var unAcked := AckStateLookup(id, s.sendState ).unAcked; var unAcked' := AckStateLookup(id, s'.sendState).unAcked; unAcked == unAcked'; } else { } } lemma HighestSeqnoSent_Monotonic(s:SingleDeliveryAcct, s':SingleDeliveryAcct, pkt:Packet, acks:set) requires UnAckedListProperties(s); requires pkt.msg.Ack?; requires ReceiveAck(s, s', pkt, acks); ensures forall dst :: HighestSeqnoSent(s', dst) >= HighestSeqnoSent(s, dst); { ReceiveAckPreservesUnAckListProperties(s, s', pkt, acks); forall dst ensures HighestSeqnoSent(s', dst) >= HighestSeqnoSent(s, dst); { if dst != pkt.src { assert HighestSeqnoSent(s', dst) == HighestSeqnoSent(s, dst); } else { var oldAckState := AckStateLookup(dst, s.sendState); if pkt.msg.ack_seqno > oldAckState.numPacketsAcked { var newAckState := oldAckState.(numPacketsAcked := pkt.msg.ack_seqno, unAcked := TruncateUnAckList(oldAckState.unAcked, pkt.msg.ack_seqno)); assert s'.sendState[dst] == newAckState; TruncateAckPreservesUnAckListProperties(oldAckState.unAcked, oldAckState.numPacketsAcked, pkt.msg.ack_seqno, dst); calc { HighestSeqnoSent(s, dst); oldAckState.numPacketsAcked + |oldAckState.unAcked|; <= newAckState.numPacketsAcked + |newAckState.unAcked|; HighestSeqnoSent(s', dst); } } else { } } } var oldAckState := AckStateLookup(pkt.src, s.sendState); } lemma ReceivePacket_UnsentSeqnos(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, rpkt:Packet, out:set, ack:Packet) requires Inv(s); requires MapComplete(s'); requires SHT_Next(s, s'); requires SHT_NextPred(s, s', id, recv, out); requires ReceivePacket(s.hosts[id], s'.hosts[id], rpkt, out, ack); requires s.hosts[id].receivedPacket.None?; requires rpkt in recv; ensures ReceiverHasCanceledNoUnsentSeqnos(s'); { var h := s.hosts[id]; var h' := s'.hosts[id]; assert ReceiveSingleMessage(h.sd, h'.sd, rpkt, ack, out); assert forall pkt :: pkt in s'.network && pkt.msg.SingleMessage? ==> pkt in s.network; assert NoPacketContainsUnsentSeqno(s); assert forall other_id :: other_id in AllHostIdentities(s) && other_id != id ==> s.hosts[other_id] == s'.hosts[other_id]; reveal_PacketsHaveSenderUniqueSeqnos(); // Prove ReceiverHasCanceledNoUnsentSeqnos(s') forall dst, src, seqno {:trigger ReceiverHasNotCanceledUnsentSeqno(s', dst, src, seqno)} | dst in AllHostIdentities(s') && src in AllHostIdentities(s') && HighestSeqnoSent(s'.hosts[src].sd, dst) < seqno ensures seqno > TombstoneTableLookup(src, s'.hosts[dst].sd.receiveState); { assert ReceiverHasNotCanceledUnsentSeqno(s, dst, src, seqno); // OBSERVE: Need to trigger to expand the definition var seqno_sent := HighestSeqnoSent(s.hosts[src].sd, dst); var seqno_sent' := HighestSeqnoSent(s'.hosts[src].sd, dst); var seqno_recv := TombstoneTableLookup(src, s.hosts[dst].sd.receiveState); var seqno_recv' := TombstoneTableLookup(src, s'.hosts[dst].sd.receiveState); assert forall i :: i in AllHostIdentities(s') && i != id ==> s'.hosts[i] == s.hosts[i]; //assert rpkt.src != rpkt.dst; if src != id { assert seqno_sent == seqno_sent'; } else { assert src == id == rpkt.dst; var oldAckState := AckStateLookup(dst, h.sd.sendState); var ackState' := AckStateLookup(dst, h'.sd.sendState); assert seqno_sent' == ackState'.numPacketsAcked + |ackState'.unAcked|; if rpkt.msg.Ack? && ReceiveAck(h.sd, h'.sd, rpkt, out) { if dst != rpkt.src { assert seqno_sent' == seqno_sent; } else { HighestSeqnoSent_Monotonic(h.sd, h'.sd, rpkt, out); if rpkt.msg.ack_seqno > oldAckState.numPacketsAcked { assert seqno_sent' >= seqno_sent; } else { assert seqno_sent' == seqno_sent; } assert seqno_sent' >= seqno_sent; } } else { assert h'.sd.sendState == h.sd.sendState; assert seqno_sent' == seqno_sent; } } if NewSingleMessage(h.sd, rpkt) { if rpkt.src == src && dst == id { assert seqno_recv' == seqno_recv + 1; } else { assert seqno_recv' == seqno_recv; } } else { assert seqno_recv == seqno_recv'; } assert seqno > seqno_recv'; } } lemma ReceivePacket_EachKeyClaimed(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, rpkt:Packet, out:set, ack:Packet) requires Inv(s); requires MapComplete(s'); requires SHT_Next(s, s'); requires SHT_NextPred(s, s', id, recv, out); requires ReceivePacket(s.hosts[id], s'.hosts[id], rpkt, out, ack); requires s.hosts[id].receivedPacket.None?; requires rpkt in recv; ensures EachKeyClaimedInExactlyOnePlace(s'); { var h := s.hosts[id]; var h' := s'.hosts[id]; assert ReceiveSingleMessage(h.sd, h'.sd, rpkt, ack, out); if NewSingleMessage(h.sd, rpkt) { assert h' == h.(sd := h'.sd, receivedPacket := Some(rpkt)); } else { assert h' == h.(sd := h'.sd, receivedPacket := None); } // Prove EachKeyClaimedInExactlyOnePlace(s'); forall () ensures EachKeyClaimedInExactlyOnePlace(s'); { reveal_EachKeyClaimedInExactlyOnePlace(); assert forall k :: (UniqueInFlightPacketClaimsKey(s, k) && NoHostClaimsKey(s, k)) || (NoInFlightPacketClaimsKey(s, k) && UniqueHostClaimsKey(s, k)); forall k ensures (UniqueInFlightPacketClaimsKey(s', k) && NoHostClaimsKey(s', k)) || (NoInFlightPacketClaimsKey(s', k) && UniqueHostClaimsKey(s', k)) { if UniqueInFlightPacketClaimsKey(s, k) { assert exists pkt :: InFlightPacketClaimsKey(s, pkt, k); // OBSERVE var pkt :| InFlightPacketClaimsKey(s, pkt, k); var last_seqno := TombstoneTableLookup(pkt.src, s.hosts[pkt.dst].sd.receiveState); var last_seqno' := TombstoneTableLookup(pkt.src, s'.hosts[pkt.dst].sd.receiveState); assert pkt.msg.seqno > last_seqno; if pkt != rpkt { assert pkt in s'.network; if pkt.dst != id { assert pkt.msg.SingleMessage? && pkt.msg.seqno > last_seqno'; } else { if NewSingleMessage(h.sd, rpkt) { assert h' == h.(sd := h'.sd, receivedPacket := Some(rpkt)); if rpkt.src == pkt.src { forall () ensures pkt.msg.seqno != rpkt.msg.seqno; { reveal_PacketsHaveSenderUniqueSeqnos(); } assert pkt.msg.SingleMessage? && pkt.msg.seqno > last_seqno'; } else { assert pkt.msg.SingleMessage? && pkt.msg.seqno > last_seqno'; } } else { assert h' == h.(sd := h'.sd, receivedPacket := None); assert pkt.msg.SingleMessage? && pkt.msg.seqno > last_seqno'; } } assert PacketInFlight(s', pkt); assert InFlightPacketClaimsKey(s', pkt, k); // OBSERVE, exists trigger for SomePacketClaimsKey(s, k) assert forall p1,p2 {:auto_trigger} :: // OBSERVE for OnlyOnePacketClaimsKey(s', k) InFlightPacketClaimsKey(s, p1, k) && InFlightPacketClaimsKey(s, p2, k) ==> p1==p2; forall p1,p2 {:auto_trigger} | InFlightPacketClaimsKey(s', p1, k) // OBSERVE for OnlyOnePacketClaimsKey(s', k) && InFlightPacketClaimsKey(s', p2, k) ensures p1==p2; { assert InFlightPacketClaimsKey(s, p1, k) && InFlightPacketClaimsKey(s, p2, k); } assert OnlyOnePacketClaimsKey(s', k); assert UniqueInFlightPacketClaimsKey(s', k); forall i {:trigger HostClaimsKey(s'.hosts[i], k)} | i in AllHostIdentities(s') ensures !HostClaimsKey(s'.hosts[i], k); // OBSERVE for NoHostClaimsKey(s', k); { assert !HostClaimsKey(s.hosts[i], k); assert !(DelegateForKey(s'.hosts[i].delegationMap, k)==s'.hosts[i].me); if i != id { assert !BufferedPacketClaimsKey(s'.hosts[i], k); } else { if s'.hosts[i].receivedPacket.None? { assert !BufferedPacketClaimsKey(s'.hosts[i], k); } else { assert s'.hosts[i].receivedPacket == Some(rpkt); if BufferedPacketClaimsKey(s'.hosts[i], k) { assert InFlightPacketClaimsKey(s, rpkt, k); assert false; } assert !BufferedPacketClaimsKey(s'.hosts[i], k); } } } assert NoHostClaimsKey(s', k); assert UniqueInFlightPacketClaimsKey(s', k) && NoHostClaimsKey(s', k); } else { // pkt == rpkt assert !pkt.msg.Ack?; if NewSingleMessage(s.hosts[id].sd, pkt) { assert s'.hosts[id].receivedPacket.v == pkt; var last_seqno := TombstoneTableLookup(pkt.src, h.sd.receiveState); assert pkt.msg.seqno == last_seqno + 1; assert h'.sd == h.sd.(receiveState := h.sd.receiveState[pkt.src := (last_seqno + 1) as nat_t]); assert !NewSingleMessage(s'.hosts[id].sd, pkt); assert BufferedPacketClaimsKey(s'.hosts[id], k); assert HostClaimsKey(s'.hosts[id], k); assert UniqueHostClaimsKey(s', k); forall p ensures !InFlightPacketClaimsKey(s', p, k) { if p != pkt { assert !InFlightPacketClaimsKey(s, p, k); assert !InFlightPacketClaimsKey(s', p, k); } else { assert !PacketInFlight(s', p); assert !InFlightPacketClaimsKey(s', p, k); } } assert NoInFlightPacketClaimsKey(s', k) && UniqueHostClaimsKey(s', k); } else { assert PacketInFlight(s', pkt); assert InFlightPacketClaimsKey(s', pkt, k); assert NoHostClaimsKey(s', k); forall p1,p2 {:auto_trigger} | InFlightPacketClaimsKey(s', p1, k) && InFlightPacketClaimsKey(s', p2, k) ensures p1==p2; { assert InFlightPacketClaimsKey(s, p1, k); assert InFlightPacketClaimsKey(s, p2, k); } assert SomePacketClaimsKey(s', k) && OnlyOnePacketClaimsKey(s', k); assert UniqueInFlightPacketClaimsKey(s', k) && NoHostClaimsKey(s', k); } } } else if NoInFlightPacketClaimsKey(s, k) { forall pkt ensures !InFlightPacketClaimsKey(s', pkt, k); { assert !InFlightPacketClaimsKey(s, pkt, k); } assert NoInFlightPacketClaimsKey(s', k); assert SomeHostClaimsKey(s, k); assert exists id :: id in AllHostIdentities(s) && HostClaimsKey(s.hosts[id], k); var i :| i in AllHostIdentities(s) && HostClaimsKey(s.hosts[i], k); assert HostClaimsKey(s'.hosts[i], k); forall i1,i2 | i1 in AllHostIdentities(s') && HostClaimsKey(s'.hosts[i1], k) && i2 in AllHostIdentities(s') && HostClaimsKey(s'.hosts[i2], k) ensures i1==i2; { if i1 == id { if BufferedPacketClaimsKey(s'.hosts[i1], k) { assert InFlightPacketClaimsKey(s, rpkt, k); assert false; } else { assert HostClaimsKey(s.hosts[id], k); } assert HostClaimsKey(s.hosts[id], k); } else { assert HostClaimsKey(s.hosts[i1], k); } if i2 == id { if BufferedPacketClaimsKey(s'.hosts[i2], k) { assert InFlightPacketClaimsKey(s, rpkt, k); assert false; } else { assert HostClaimsKey(s.hosts[id], k); } assert HostClaimsKey(s.hosts[id], k); } else { assert HostClaimsKey(s.hosts[i2], k); } } assert SomeHostClaimsKey(s',k) && OnlyOneHostClaimsKey(s',k); assert UniqueHostClaimsKey(s', k); } else { assert false; // Not a viable option } } } } lemma ReceivePacket_Properties(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, rpkt:Packet, out:set, ack:Packet) requires Inv(s); requires MapComplete(s'); requires SHT_Next(s, s'); requires SHT_NextPred(s, s', id, recv, out); requires ReceivePacket(s.hosts[id], s'.hosts[id], rpkt, out, ack); requires s.hosts[id].receivedPacket.None?; requires rpkt in recv; ensures AckListsInv(s'); ensures PacketsHaveSenderUniqueSeqnos(s'); ensures NoPacketContainsUnsentSeqno(s'); ensures ReceiverHasCanceledNoUnsentSeqnos(s'); ensures EachKeyClaimedInExactlyOnePlace(s'); { var h := s.hosts[id]; var h' := s'.hosts[id]; assert ReceiveSingleMessage(h.sd, h'.sd, rpkt, ack, out); assert forall pkt :: pkt in s'.network && pkt.msg.SingleMessage? ==> pkt in s.network; assert NoPacketContainsUnsentSeqno(s); assert forall other_id :: other_id in AllHostIdentities(s) && other_id != id ==> s.hosts[other_id] == s'.hosts[other_id]; ReceivePacket_UnsentSeqnos(s, s', id, recv, rpkt, out, ack); ReceivePacket_EachKeyClaimed(s, s', id, recv, rpkt, out, ack); reveal_UnAckedListInNetwork(); if rpkt.msg.Ack? { assert out == {}; ReceiveAckPreservesUnAckListProperties(h.sd, h'.sd, rpkt, out); var oldAckState := AckStateLookup(rpkt.src, h.sd.sendState); var newAckState := AckStateLookup(rpkt.src, h'.sd.sendState); assert newAckState.unAcked == TruncateUnAckList(oldAckState.unAcked, rpkt.msg.ack_seqno); TruncateAckPreservesSubset(oldAckState.unAcked); forall id',msg,dst | id' in AllHostIdentities(s) && msg in AckStateLookup(dst, s'.hosts[id'].sd.sendState).unAcked && NoAcksInUnAckedLists(s'.hosts[id'].sd) && dst == msg.dst ensures Packet(msg.dst, s'.hosts[id'].me, msg) in s'.network { var p := Packet(msg.dst, s'.hosts[id'].me, msg); if id' == id { assert msg in AckStateLookup(dst, s.hosts[id'].sd.sendState).unAcked; assert p in s'.network; } else { assert p in s'.network; } } HighestSeqnoSent_Monotonic(h.sd, h'.sd, rpkt, out); assert AckListsInv(s'); } else { } reveal_PacketsHaveSenderUniqueSeqnos(); // ==> assert PacketsHaveSenderUniqueSeqnos(s'); } /* lemma ReceiveSingleMessageNew_Properties(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, rpkt:Packet, out:set, ack:Packet) requires Inv(s); requires MapComplete(s'); requires SHT_Next(s, s'); requires SHT_NextPred(s, s', id, recv, out); requires rpkt in recv; requires ReceivePacket(s.hosts[id], s'.hosts[id], rpkt, out, ack); requires NewSingleMessage(s.hosts[id].sd, rpkt); ensures ReceiverHasCanceledNoUnsentSeqnos(s'); { var h := s.hosts[id]; var h' := s'.hosts[id]; assert ReceiveSingleMessage(h.sd, h'.sd, rpkt, ack, out); assert forall other_id :: other_id in AllHostIdentities(s) && other_id != id ==> s.hosts[other_id] == s'.hosts[other_id]; // Remind Dafny what ReceiverHasCanceledNoUnsentSeqnos(s) means for s forall dst, src, seqno ensures dst in AllHostIdentities(s) && src in AllHostIdentities(s) && HighestSeqnoSent(s.hosts[src].sd, dst) < seqno ==> seqno > TombstoneTableLookup(src, s.hosts[dst].sd.receiveState); { assert ReceiverHasNotCanceledUnsentSeqno(s, dst, src, seqno); // OBSERVE: Need to trigger to expand the definition } forall dst, src, seqno | dst in AllHostIdentities(s) && src in AllHostIdentities(s) && HighestSeqnoSent(s'.hosts[src].sd, dst) < seqno ensures seqno > TombstoneTableLookup(src, s'.hosts[dst].sd.receiveState); { if rpkt.src == src { } else { if dst == id { assert HighestSeqnoSent(s'.hosts[src].sd, dst) == HighestSeqnoSent(s.hosts[src].sd, dst); // OBSERVE assert seqno > TombstoneTableLookup(src, s'.hosts[dst].sd.receiveState); } else { } } } } */ predicate DelegationPacketStable(s:SHT_State, s':SHT_State, id:NodeIdentity) requires id in s.hosts && id in s'.hosts; requires DelegationPacket(s.hosts[id].receivedPacket); { s'.hosts[id].receivedPacket == s.hosts[id].receivedPacket } lemma DelegateStability(s:SHT_State, s':SHT_State) requires MapComplete(s) && InvConstants(s); requires MapComplete(s') && InvConstants(s'); requires s.config == s'.config; requires forall id :: id in AllHostIdentities(s) && DelegationPacket(s.hosts[id].receivedPacket) ==> DelegationPacketStable(s, s', id); // ==> s'.hosts[id].receivedPacket == s.hosts[id].receivedPacket // && NewSingleMessage(s.hosts[id].sd, s.hosts[id].receivedPacket.v) == // NewSingleMessage(s'.hosts[id].sd, s'.hosts[id].receivedPacket.v); requires forall id :: id in AllHostIdentities(s) && !DelegationPacket(s.hosts[id].receivedPacket) ==> !DelegationPacket(s'.hosts[id].receivedPacket); requires forall id :: id in AllHostIdentities(s) ==> s'.hosts[id].delegationMap == s.hosts[id].delegationMap; ensures forall id, k :: id in AllHostIdentities(s) ==> (HostClaimsKey(s.hosts[id], k) <==> HostClaimsKey(s'.hosts[id],k)); { forall id, k | id in AllHostIdentities(s) ensures HostClaimsKey(s.hosts[id], k) <==> HostClaimsKey(s'.hosts[id],k); { var h := s.hosts[id]; var h' := s'.hosts[id]; if BufferedPacketClaimsKey(h, k) { assert BufferedPacketClaimsKey(h', k); } if BufferedPacketClaimsKey(h', k) { assert DelegationPacket(h.receivedPacket); assert KeyRangeContains(h.receivedPacket.v.msg.m.range, KeyPlus(k)); assert BufferedPacketClaimsKey(h, k); } calc { HostClaimsKey(h, k); DelegateForKey(h.delegationMap, k) == h.me || BufferedPacketClaimsKey(h, k); DelegateForKey(h.delegationMap, k) == id || BufferedPacketClaimsKey(h, k); DelegateForKey(h'.delegationMap, k) == id || BufferedPacketClaimsKey(h', k); DelegateForKey(h'.delegationMap, k) == h'.me || BufferedPacketClaimsKey(h', k); HostClaimsKey(h', k); } } } /////////////////////////////////////////////////////// // Delegation ////////////////////////////////////////////////////// lemma DelegateStabilitySpecific(s:SHT_State, s':SHT_State, k:Key, id:NodeIdentity) requires MapComplete(s) && InvConstants(s); requires MapComplete(s') && InvConstants(s'); requires NoConfigChanged(s, s'); requires forall id :: id in AllHostIdentities(s) && DelegationPacket(s.hosts[id].receivedPacket) ==> s'.hosts[id].receivedPacket == s.hosts[id].receivedPacket && NewSingleMessage(s.hosts[id].sd, s.hosts[id].receivedPacket.v) == NewSingleMessage(s'.hosts[id].sd, s'.hosts[id].receivedPacket.v); requires forall id :: id in AllHostIdentities(s) && !DelegationPacket(s.hosts[id].receivedPacket) ==> s'.hosts[id].receivedPacket.None?; requires forall id :: id in AllHostIdentities(s) ==> s'.hosts[id].delegationMap == s.hosts[id].delegationMap; requires id in AllHostIdentities(s); ensures HostClaimsKey(s.hosts[id], k) <==> HostClaimsKey(s'.hosts[id],k); { DelegateStability(s, s'); } // Trigger loop!? lemma NoHostClaimsKeySpecific(s:SHT_State, k:Key, id:NodeIdentity) requires MapComplete(s); requires NoHostClaimsKey(s, k); requires id in AllHostIdentities(s); ensures !HostClaimsKey(s.hosts[id], k); { } predicate NoDelegationPacketsChangedAboutKey(s:SHT_State, s':SHT_State, k:Key) requires MapComplete(s) && InvConstants(s) && PacketsHaveSaneHeaders(s); requires MapComplete(s') && InvConstants(s') && PacketsHaveSaneHeaders(s'); { forall pkt:Packet :: pkt.msg.SingleMessage? && pkt.msg.m.Delegate? && KeyRangeContains(pkt.msg.m.range, KeyPlus(k)) ==> (PacketInFlight(s, pkt) <==> PacketInFlight(s', pkt)) } predicate NoConfigChanged(s:SHT_State, s':SHT_State) requires MapComplete(s); requires MapComplete(s'); { s'.config == s.config } // TODO I think I can just dispense with this disjunct. predicate NoDelegationMapsChanged(s:SHT_State, s':SHT_State) requires MapComplete(s); requires MapComplete(s'); requires NoConfigChanged(s, s'); { forall id {:auto_trigger} :: id in AllHostIdentities(s) ==> s'.hosts[id].delegationMap == s.hosts[id].delegationMap } predicate NoDelegationMapsChangedAboutKey(s:SHT_State, s':SHT_State, k:Key) requires MapComplete(s); requires MapComplete(s'); requires NoConfigChanged(s, s'); { forall id {:trigger DelegateForKey(s.hosts[id].delegationMap, k)} {:trigger DelegateForKey(s'.hosts[id].delegationMap, k)} :: id in AllHostIdentities(s) ==> DelegateForKey(s'.hosts[id].delegationMap, k) == DelegateForKey(s.hosts[id].delegationMap, k) } lemma NonDelegationsEachKeyClaimedInExactlyOnePlace_case1(s:SHT_State, s':SHT_State, k:Key) requires MapComplete(s) && InvConstants(s) && PacketsHaveSaneHeaders(s); requires MapComplete(s') && InvConstants(s') && PacketsHaveSaneHeaders(s'); requires NoDelegationPacketsChangedAboutKey(s, s', k); requires NoConfigChanged(s, s'); requires NoDelegationMapsChanged(s, s') || NoDelegationMapsChangedAboutKey(s, s', k); requires forall id :: id in AllHostIdentities(s) && DelegationPacket(s.hosts[id].receivedPacket) ==> DelegationPacketStable(s, s', id) || s'.hosts[id].receivedPacket.None?; requires forall id :: id in AllHostIdentities(s) && !DelegationPacket(s.hosts[id].receivedPacket) ==> !DelegationPacket(s'.hosts[id].receivedPacket); requires UniqueInFlightPacketClaimsKey(s, k) && NoHostClaimsKey(s, k); ensures UniqueInFlightPacketClaimsKey(s', k) && NoHostClaimsKey(s', k); { // Some unfortunate triggering required by new conservative triggers. // I'm not certain why. // assert exists pkt :: InFlightPacketClaimsKey(s, pkt, k); var pkt :| InFlightPacketClaimsKey(s, pkt, k); assert InFlightPacketClaimsKey(s', pkt, k); assert exists pkt :: InFlightPacketClaimsKey(s', pkt, k); // assert SomePacketClaimsKey(s', k); forall p1,p2 | InFlightPacketClaimsKey(s', p1, k) && InFlightPacketClaimsKey(s', p2, k) ensures p1==p2; { assert InFlightPacketClaimsKey(s, p1, k); assert InFlightPacketClaimsKey(s, p2, k); } // assert OnlyOnePacketClaimsKey(s', k); assert forall id :: id in AllHostIdentities(s) ==> !HostClaimsKey(s.hosts[id], k); } // This was easy to prove until I tightened the precondition. lemma NonDelegationsEachKeyClaimedInExactlyOnePlace_case2(s:SHT_State, s':SHT_State, k:Key) requires HiddenInv(s); requires MapComplete(s) && InvConstants(s) && PacketsHaveSaneHeaders(s); requires MapComplete(s') && InvConstants(s') && PacketsHaveSaneHeaders(s'); requires NoDelegationPacketsChangedAboutKey(s, s', k); requires NoConfigChanged(s, s') requires forall id :: id in AllHostIdentities(s) && DelegationPacket(s.hosts[id].receivedPacket) ==> DelegationPacketStable(s, s', id); requires forall id :: id in AllHostIdentities(s) && !DelegationPacket(s.hosts[id].receivedPacket) ==> !DelegationPacket(s'.hosts[id].receivedPacket); requires NoDelegationMapsChanged(s, s') || NoDelegationMapsChangedAboutKey(s, s', k); requires NoInFlightPacketClaimsKey(s, k) && UniqueHostClaimsKey(s, k); ensures NoInFlightPacketClaimsKey(s', k) && UniqueHostClaimsKey(s', k); { if (NoDelegationMapsChanged(s, s')) { DelegateStability(s, s'); } // assert NoInFlightPacketClaimsKey(s, k); assert forall pkt :: !InFlightPacketClaimsKey(s, pkt, k); // assert NoInFlightPacketClaimsKey(s', k); assert UniqueHostClaimsKey(s, k); var id :| id in AllHostIdentities(s) && HostClaimsKey(s.hosts[id], k); assert id in AllHostIdentities(s) && HostClaimsKey(s'.hosts[id], k); forall i1,i2 | i1 in AllHostIdentities(s) && HostClaimsKey(s'.hosts[i1], k) && i2 in AllHostIdentities(s) && HostClaimsKey(s'.hosts[i2], k) ensures i1==i2; { assert HostClaimsKey(s.hosts[i1], k); assert HostClaimsKey(s.hosts[i2], k); assert i1==i2; } assert UniqueHostClaimsKey(s', k); forall pkt ensures !InFlightPacketClaimsKey(s', pkt, k) { assert !InFlightPacketClaimsKey(s, pkt, k); } assert NoInFlightPacketClaimsKey(s', k); } lemma NonDelegationsEachKeyClaimedInExactlyOnePlace_case2'(s:SHT_State, s':SHT_State, k:Key) requires HiddenInv(s); requires MapComplete(s) && InvConstants(s) && PacketsHaveSaneHeaders(s); requires MapComplete(s') && InvConstants(s') && PacketsHaveSaneHeaders(s'); requires NoDelegationPacketsChangedAboutKey(s, s', k); requires NoConfigChanged(s, s') requires forall id :: id in AllHostIdentities(s) && DelegationPacket(s.hosts[id].receivedPacket) ==> s'.hosts[id].receivedPacket == s.hosts[id].receivedPacket || s'.hosts[id].receivedPacket.None?; requires forall id :: id in AllHostIdentities(s) && DelegationPacket(s.hosts[id].receivedPacket) && s'.hosts[id].receivedPacket.None? ==> !BufferedPacketClaimsKey(s.hosts[id], k); requires forall id :: id in AllHostIdentities(s') ==> s'.hosts[id].sd == s.hosts[id].sd; requires forall id :: id in AllHostIdentities(s) && !DelegationPacket(s.hosts[id].receivedPacket) ==> !DelegationPacket(s'.hosts[id].receivedPacket); requires NoDelegationMapsChanged(s, s') || NoDelegationMapsChangedAboutKey(s, s', k); requires NoInFlightPacketClaimsKey(s, k) && UniqueHostClaimsKey(s, k); ensures NoInFlightPacketClaimsKey(s', k) && UniqueHostClaimsKey(s', k); { assert forall pkt :: !InFlightPacketClaimsKey(s, pkt, k); assert UniqueHostClaimsKey(s, k); var id :| id in AllHostIdentities(s) && HostClaimsKey(s.hosts[id], k); assert id in AllHostIdentities(s) && HostClaimsKey(s'.hosts[id], k); forall i1,i2 | i1 in AllHostIdentities(s) && HostClaimsKey(s'.hosts[i1], k) && i2 in AllHostIdentities(s) && HostClaimsKey(s'.hosts[i2], k) ensures i1==i2; { assert HostClaimsKey(s.hosts[i1], k); assert HostClaimsKey(s.hosts[i2], k); assert i1==i2; } assert UniqueHostClaimsKey(s', k); forall pkt ensures !InFlightPacketClaimsKey(s', pkt, k) { assert !InFlightPacketClaimsKey(s, pkt, k); } assert NoInFlightPacketClaimsKey(s', k); } predicate NotADelegateStep(s:SHT_State, s':SHT_State) requires MapComplete(s); requires MapComplete(s'); requires PacketsHaveSaneHeaders(s); requires PacketsHaveSaneHeaders(s'); { forall pkt:Packet :: pkt.msg.SingleMessage? && pkt.msg.m.Delegate? ==> (PacketInFlight(s, pkt) <==> PacketInFlight(s', pkt)) } lemma NonDelegationsEachKeyClaimedInExactlyOnePlace(s:SHT_State, s':SHT_State) requires Inv(s); requires MapComplete(s) && InvConstants(s) && PacketsHaveSaneHeaders(s); requires MapComplete(s') && InvConstants(s') && PacketsHaveSaneHeaders(s'); requires NoConfigChanged(s, s'); requires NotADelegateStep(s, s'); requires forall id :: id in AllHostIdentities(s) ==> s'.hosts[id].delegationMap == s.hosts[id].delegationMap; requires forall id :: id in AllHostIdentities(s) && DelegationPacket(s.hosts[id].receivedPacket) ==> DelegationPacketStable(s, s', id); requires forall id :: id in AllHostIdentities(s) && !DelegationPacket(s.hosts[id].receivedPacket) ==> !DelegationPacket(s'.hosts[id].receivedPacket); ensures EachKeyClaimedInExactlyOnePlace(s'); { forall k ensures (UniqueInFlightPacketClaimsKey(s', k) && NoHostClaimsKey(s', k)) || (NoInFlightPacketClaimsKey(s', k) && UniqueHostClaimsKey(s', k)); { if (UniqueInFlightPacketClaimsKey(s, k) && NoHostClaimsKey(s, k)) { reveal_EachKeyClaimedInExactlyOnePlace(); NonDelegationsEachKeyClaimedInExactlyOnePlace_case1(s, s', k); } else { reveal_EachKeyClaimedInExactlyOnePlace(); reveal_HiddenInv(); NonDelegationsEachKeyClaimedInExactlyOnePlace_case2(s, s', k); } } reveal_EachKeyClaimedInExactlyOnePlace(); assert EachKeyClaimedInExactlyOnePlace(s'); } lemma NextInv_Get_NotADelegateStep(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, out:set, rpkt:Packet) requires Inv(s); requires MapComplete(s'); requires SHT_Next(s, s'); requires SHT_NextPred(s, s', id, recv, out); requires rpkt in s.network && rpkt.msg.SingleMessage? && rpkt.msg.m.GetRequest? && NextGetRequest(s.hosts[id], s'.hosts[id], rpkt, out); requires !SpontaneouslyRetransmit(s.hosts[id], s'.hosts[id], out); ensures NotADelegateStep(s, s'); { } lemma {:timeLimitMultiplier 3} NextInv_Get(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, out:set, rpkt:Packet) requires Inv(s); requires MapComplete(s'); requires SHT_Next(s, s'); requires SHT_NextPred(s, s', id, recv, out); requires s'.hosts[id].receivedPacket.None?; requires Some(rpkt) == s.hosts[id].receivedPacket; requires rpkt in s.network && rpkt.msg.SingleMessage? && rpkt.msg.m.GetRequest? && NextGetRequest(s.hosts[id], s'.hosts[id], rpkt, out); requires NotADelegateStep(s, s'); requires !SpontaneouslyRetransmit(s.hosts[id], s'.hosts[id], out); ensures Inv(s'); { var k := rpkt.msg.m.k_getrequest; var sm,m,b :| NextGetRequest_Reply(s.hosts[id], s'.hosts[id], rpkt.src, rpkt.msg.seqno, k, sm, m, out, b); if b { assert forall id' :: id' in AllHostIdentities(s) && id' != id ==> s'.hosts[id'] == s.hosts[id']; NonDelegationsEachKeyClaimedInExactlyOnePlace(s, s'); assert SendSingleMessage(s.hosts[id].sd, s'.hosts[id].sd, m, sm, s.hosts[id].constants.params, b); assert NoHostsStoreEmptyValues(s'); reveal_PacketsHaveSenderUniqueSeqnos(); reveal_UnAckedListInNetwork(); forall dst, src, seqno ensures ReceiverHasNotCanceledUnsentSeqno(s', dst, src, seqno); { assert ReceiverHasNotCanceledUnsentSeqno(s, dst, src, seqno); // OBSERVE trigger } // assert ReceiverHasCanceledNoUnsentSeqnos(s'); SendSingleMessagePreservesUnAckListProperties(s.hosts[id].sd, s'.hosts[id].sd, m, sm, s.hosts[id].constants.params, b); // Prove UnAckedListInNetwork reveal_UnAckedListInNetwork(); forall id,msg,dst | id in AllHostIdentities(s) && msg in AckStateLookup(dst, s'.hosts[id].sd.sendState).unAcked && NoAcksInUnAckedLists(s'.hosts[id].sd) && dst == msg.dst ensures Packet(msg.dst, s'.hosts[id].me, msg) in s'.network; { var unAcked := AckStateLookup(dst, s.hosts[id].sd.sendState).unAcked; var unAcked' := AckStateLookup(dst, s'.hosts[id].sd.sendState).unAcked; var i :| 0 <= i < |unAcked'| && unAcked'[i] == msg; if i < |unAcked| { assert msg in AckStateLookup(dst, s.hosts[id].sd.sendState).unAcked; } else { var oldAckState := AckStateLookup(dst, s.hosts[id].sd.sendState); var new_seqno := oldAckState.numPacketsAcked + |oldAckState.unAcked| + 1; if new_seqno > s.hosts[id].constants.params.max_seqno { assert out == {}; } else { assert out == {Packet(msg.dst, s'.hosts[id].me, msg)}; } } } } else { forall dst, src, seqno ensures ReceiverHasNotCanceledUnsentSeqno(s', dst, src, seqno); { assert ReceiverHasNotCanceledUnsentSeqno(s, dst, src, seqno); // OBSERVE trigger } reveal_UnAckedListInNetwork(); reveal_PacketsHaveSenderUniqueSeqnos(); NonDelegationsEachKeyClaimedInExactlyOnePlace(s, s'); } } lemma NextInv_Set_NotADelegateStep(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, out:set, rpkt:Packet) requires Inv(s); requires MapComplete(s'); requires SHT_Next(s, s'); requires SHT_NextPred(s, s', id, recv, out); requires rpkt in s.network && rpkt.msg.SingleMessage? && rpkt.msg.m.SetRequest? && NextSetRequest(s.hosts[id], s'.hosts[id], rpkt, out); requires !SpontaneouslyRetransmit(s.hosts[id], s'.hosts[id], out); ensures NotADelegateStep(s, s'); { } lemma NextInv_Set(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, out:set, rpkt:Packet) requires Inv(s); requires MapComplete(s'); requires SHT_Next(s, s'); requires SHT_NextPred(s, s', id, recv, out); requires Some(rpkt) == s.hosts[id].receivedPacket; requires s'.hosts[id].receivedPacket.None?; requires rpkt in s.network && rpkt.msg.SingleMessage? && rpkt.msg.m.SetRequest? && NextSetRequest(s.hosts[id], s'.hosts[id], rpkt, out); requires NotADelegateStep(s, s'); //requires ReceivePacket(s.hosts[id], s'.hosts[id], rpkt, out, ack); requires !SpontaneouslyRetransmit(s.hosts[id], s'.hosts[id], out); ensures Inv(s'); { var sm,m,b :| NextSetRequest_Complete(s.hosts[id], s'.hosts[id], rpkt.src, rpkt.msg.seqno, rpkt.msg.m, sm, m, out, b); NonDelegationsEachKeyClaimedInExactlyOnePlace(s, s'); if b && ValidKey(rpkt.msg.m.k_setrequest) && ValidOptionalValue(rpkt.msg.m.v_setrequest) { assert SendSingleMessage(s.hosts[id].sd, s'.hosts[id].sd, m, sm, s.hosts[id].constants.params, b); assert NoHostsStoreEmptyValues(s'); //ReceiveSingleMessageNew_Properties(s, s', id, recv, rpkt, out, ack); reveal_PacketsHaveSenderUniqueSeqnos(); reveal_UnAckedListInNetwork(); forall dst, src, seqno ensures ReceiverHasNotCanceledUnsentSeqno(s', dst, src, seqno); { assert ReceiverHasNotCanceledUnsentSeqno(s, dst, src, seqno); // OBSERVE trigger } // assert ReceiverHasCanceledNoUnsentSeqnos(s'); SendSingleMessagePreservesUnAckListProperties(s.hosts[id].sd, s'.hosts[id].sd, m, sm, s.hosts[id].constants.params, b); // Prove UnAckedListInNetwork reveal_UnAckedListInNetwork(); forall id,msg,dst | id in AllHostIdentities(s) && msg in AckStateLookup(dst, s'.hosts[id].sd.sendState).unAcked && NoAcksInUnAckedLists(s'.hosts[id].sd) && dst == msg.dst ensures Packet(msg.dst, s'.hosts[id].me, msg) in s'.network; { var unAcked := AckStateLookup(dst, s.hosts[id].sd.sendState).unAcked; var unAcked' := AckStateLookup(dst, s'.hosts[id].sd.sendState).unAcked; var i :| 0 <= i < |unAcked'| && unAcked'[i] == msg; if i < |unAcked| { assert msg in AckStateLookup(dst, s.hosts[id].sd.sendState).unAcked; } else { var oldAckState := AckStateLookup(dst, s.hosts[id].sd.sendState); var new_seqno := oldAckState.numPacketsAcked + |oldAckState.unAcked| + 1; if new_seqno > s.hosts[id].constants.params.max_seqno { assert out == {}; } else { assert out == {Packet(msg.dst, s'.hosts[id].me, msg)}; } } } } else { forall dst, src, seqno ensures ReceiverHasNotCanceledUnsentSeqno(s', dst, src, seqno); { assert ReceiverHasNotCanceledUnsentSeqno(s, dst, src, seqno); // OBSERVE trigger } reveal_UnAckedListInNetwork(); reveal_PacketsHaveSenderUniqueSeqnos(); } } lemma PacketStillInFlightForward_ReceiveSingle(s:SHT_State, s':SHT_State, id:NodeIdentity, out:set, rpkt:Packet, p:Packet, ack:Packet) requires HiddenInv(s); requires MapComplete(s); requires MapComplete(s'); requires PacketsHaveSaneHeaders(s'); requires NoConfigChanged(s, s'); requires id in AllHostIdentities(s); requires rpkt in s.network; requires rpkt.dst == id; requires ReceiveSingleMessage(s.hosts[id].sd, s'.hosts[id].sd, rpkt, ack, out); requires NewSingleMessage(s.hosts[id].sd, rpkt); requires p!=rpkt; requires Network_Send(s.network, s'.network, id, out); requires !(p in out); requires forall oid :: oid in AllHostIdentities(s) && oid!=id ==> s'.hosts[oid]==s.hosts[oid]; requires PacketInFlight(s, p); ensures PacketInFlight(s', p); { reveal_HiddenInv(); reveal_PacketsHaveSenderUniqueSeqnos(); } lemma PacketStillInFlightReverse(s:SHT_State, s':SHT_State, id:NodeIdentity, rpkt:Packet, out:set, p:Packet, ack:Packet) requires Inv(s); requires MapComplete(s'); requires NoConfigChanged(s, s'); requires PacketsHaveSaneHeaders(s'); requires PacketsHaveSenderUniqueSeqnos(s'); requires Network_Send(s.network, s'.network, id, out); requires rpkt in s.network; requires id in AllHostIdentities(s); requires ReceiveSingleMessage(s.hosts[id].sd, s'.hosts[id].sd, rpkt, ack, out); requires forall oid :: oid in AllHostIdentities(s) && oid!=id ==> s'.hosts[oid]==s.hosts[oid]; requires rpkt.dst == id; requires PacketInFlight(s', p); requires forall po :: po in out ==> p!=po; requires rpkt != p; ensures PacketInFlight(s, p); { assert MessageNotReceived(s'.hosts[p.dst].sd, p.src, p.msg); } lemma NextInv_Delegate_EachKeyClaimedInExactlyOnePlace_NoInFlightPacketClaimsKey(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, out:set, pkt:Packet, k:Key) requires HiddenInv(s); requires MapComplete(s); requires MapComplete(s'); requires PacketsHaveSaneHeaders(s'); requires PacketsHaveSenderUniqueSeqnos(s'); requires SHT_Next(s, s'); requires SHT_NextPred(s, s', id, recv, out); requires Some(pkt) == s.hosts[id].receivedPacket; requires s'.hosts[id].receivedPacket.None?; requires pkt in s.network && pkt.msg.SingleMessage? && pkt.msg.m.Delegate? && NextDelegate(s.hosts[id], s'.hosts[id], pkt, out); requires KeyRangeContains(pkt.msg.m.range, KeyPlus(k)); requires NoInFlightPacketClaimsKey(s, k); requires UniqueHostClaimsKey(s, k); ensures NoInFlightPacketClaimsKey(s', k); ensures UniqueHostClaimsKey(s', k); { reveal_HiddenInv(); // OBSERVE Unfortunate conservative triggers forall ipkt ensures !InFlightPacketClaimsKey(s', ipkt, k); { if ipkt.msg.Ack? || ipkt.msg.InvalidMessage? { // Can't claim a key } else if (!ipkt.msg.m.Delegate?) { // fine } else if (!KeyRangeContains(ipkt.msg.m.range, KeyPlus(k))) { // fine } else if (!PacketInFlight(s', ipkt)) { // fine } else { assert ipkt.msg.SingleMessage?; assert ipkt.msg.m.Delegate?; assert PacketInFlight(s', ipkt); assert KeyRangeContains(ipkt.msg.m.range, KeyPlus(k)); assert InFlightPacketClaimsKey(s', ipkt, k); if PacketInFlight(s, ipkt) { assert InFlightPacketClaimsKey(s, ipkt, k); assert false; } else { assert false; } } } assert forall pkt :: !InFlightPacketClaimsKey(s', pkt, k); // OBSERVE unfortunate trigger assert exists id :: id in AllHostIdentities(s) && HostClaimsKey(s'.hosts[id], k); // OBSERVE unfortunate trigger assert forall i1,i2 :: i1 in AllHostIdentities(s) && HostClaimsKey(s.hosts[i1], k) && i2 in AllHostIdentities(s) && HostClaimsKey(s.hosts[i2], k) ==> i1==i2; // OBSERVE unfortunate trigger } // This shouldn't take a lemma; Dafny's set reasoning managed // to stumble herewith: // // assert rpkt in recv; // assert recv == PacketsTo(s.network, id); // assert rpkt in PacketsTo(s.network, id); // on *This* line!! // assert rpkt in s.network; // Thus, I present: lemma NetworkReceive_ImpliesMembership(s:SHT_State, id:NodeIdentity, recv:set, rpkt:Packet) requires Network_Receive(s.network, id, recv); requires rpkt in recv; ensures rpkt in s.network; { } // And then it lost: // assert out=={}; // assert !(pkt in out); // !!! lemma NextInv_Delegate_EachKeyClaimedInExactlyOnePlace(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, out:set, rpkt:Packet) requires HiddenInv(s); requires MapComplete(s); // requires PacketsHaveSenderUniqueSeqnos(s'); requires MapComplete(s'); requires PacketsHaveSaneHeaders(s'); requires InvConstants(s'); requires PacketsHaveSenderUniqueSeqnos(s'); requires SHT_Next(s, s'); requires SHT_NextPred(s, s', id, recv, out); requires Network_Receive(s.network, id, recv); requires Some(rpkt) == s.hosts[id].receivedPacket; requires s'.hosts[id].receivedPacket.None?; requires rpkt in s.network && rpkt.msg.SingleMessage? && rpkt.msg.m.Delegate? && NextDelegate(s.hosts[id], s'.hosts[id], rpkt, out); ensures EachKeyClaimedInExactlyOnePlace(s'); { forall k ensures (UniqueInFlightPacketClaimsKey(s', k) && NoHostClaimsKey(s', k)) || (NoInFlightPacketClaimsKey(s', k) && UniqueHostClaimsKey(s', k)); { //if (KeyRangeContains(rpkt.msg.m.range, KeyPlus(k))) { if BufferedPacketClaimsKey(s.hosts[id], k) { reveal_HiddenInv(); assert HostClaimsKey(s.hosts[id], k); reveal_EachKeyClaimedInExactlyOnePlace(); NextInv_Delegate_EachKeyClaimedInExactlyOnePlace_NoInFlightPacketClaimsKey(s, s', id, recv, out, rpkt, k); } else { if (UniqueInFlightPacketClaimsKey(s, k) && NoHostClaimsKey(s, k)) { forall pkt | pkt!=rpkt ensures (PacketInFlight(s, pkt) <==> PacketInFlight(s', pkt)); { reveal_PacketsHaveSenderUniqueSeqnos(); } forall xid | xid in AllHostIdentities(s) ensures DelegateForKey(s'.hosts[xid].delegationMap, k) == DelegateForKey(s.hosts[xid].delegationMap, k); { var dm := s.hosts[xid].delegationMap; // OBSERVE trigger var dm' := s'.hosts[xid].delegationMap; // OBSERVE trigger if rpkt.src !in s.hosts[xid].constants.hostIds { assert dm == dm'; } else { calc ==> { true; { reveal_HiddenInv(); } rpkt.dst in s.hosts[xid].constants.hostIds; } assert rpkt.src in s.hosts[xid].constants.hostIds; assert DelegationPacket(Some(rpkt)); assert !KeyRangeContains(rpkt.msg.m.range, KeyPlus(k)); } } assert NoDelegationMapsChangedAboutKey(s, s', k); NonDelegationsEachKeyClaimedInExactlyOnePlace_case1(s, s', k); } else { reveal_HiddenInv(); reveal_EachKeyClaimedInExactlyOnePlace(); forall pkt:Packet | pkt.msg.SingleMessage? && pkt.msg.m.Delegate? && KeyRangeContains(pkt.msg.m.range, KeyPlus(k)) ensures (PacketInFlight(s, pkt) <==> PacketInFlight(s', pkt)); { reveal_PacketsHaveSenderUniqueSeqnos(); } assert NoDelegationPacketsChangedAboutKey(s, s', k); NonDelegationsEachKeyClaimedInExactlyOnePlace_case2'(s, s', k); } } } reveal_EachKeyClaimedInExactlyOnePlace(); assert EachKeyClaimedInExactlyOnePlace(s'); } lemma NextInv_Delegate(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, out:set, rpkt:Packet) requires Inv(s); requires MapComplete(s'); requires SHT_Next(s, s'); requires SHT_NextPred(s, s', id, recv, out); requires Some(rpkt) == s.hosts[id].receivedPacket; requires s'.hosts[id].receivedPacket.None?; requires rpkt in s.network && rpkt.msg.SingleMessage? && rpkt.msg.m.Delegate? && NextDelegate(s.hosts[id], s'.hosts[id], rpkt, out); requires !SpontaneouslyRetransmit(s.hosts[id], s'.hosts[id], out); ensures Inv(s'); { reveal_PacketsHaveSenderUniqueSeqnos(); forall () ensures EachKeyClaimedInExactlyOnePlace(s'); { reveal_HiddenInv(); NextInv_Delegate_EachKeyClaimedInExactlyOnePlace(s, s', id, recv, out, rpkt); reveal_EachKeyClaimedInExactlyOnePlace(); } // NoHostsStoreEmptyValues: forall (i,k | i in AllHostIdentities(s) && HostClaimsKey(s'.hosts[i], k) && k in s'.hosts[i].h) ensures HashtableLookup(s'.hosts[i].h, k) != ValueAbsent() { if (i==id && KeyRangeContains(rpkt.msg.m.range, KeyPlus(k))) { reveal_EachKeyClaimedInExactlyOnePlace(); } else { assert HashtableLookup(s.hosts[i].h, k) != ValueAbsent(); // OBSERVE trigger } } forall id,k:Key | id in AllHostIdentities(s) ensures DelegateForKey(s'.hosts[id].delegationMap, k) in AllHostIdentities(s); { assert DelegateForKey(s.hosts[id].delegationMap, k) in AllHostIdentities(s); // OBSERVE trigger } forall i,k | i in AllHostIdentities(s) && k in s'.hosts[i].h ensures HostClaimsKey(s'.hosts[i], k) { if !(i==id && KeyRangeContains(rpkt.msg.m.range, KeyPlus(k))) { assert DelegateForKey(s.hosts[i].delegationMap, k)==s.hosts[i].me || BufferedPacketClaimsKey(s.hosts[i], k); // OBSERVE trigger } } assert HostsStoreOnlyOwnedKeys(s'); forall dst, src, seqno ensures ReceiverHasNotCanceledUnsentSeqno(s', dst, src, seqno); { assert ReceiverHasNotCanceledUnsentSeqno(s, dst, src, seqno); // OBSERVE trigger } // assert ReceiverHasCanceledNoUnsentSeqnos(s'); reveal_UnAckedListInNetwork(); } lemma NextInv_NextShard_EachKeyClaimedInExactlyOnePlace(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, out:set, kr:KeyRange, recipient:NodeIdentity, sm:SingleMessage, shouldSend:bool) requires Inv(s); // requires PacketsHaveSenderUniqueSeqnos(s'); requires MapComplete(s'); requires PacketsHaveSaneHeaders(s'); requires PacketsHaveSenderUniqueSeqnos(s'); requires SHT_Next(s, s'); requires SHT_NextPred(s, s', id, recv, out); requires recipient in AllHostIdentities(s); requires NextShard(s.hosts[id], s'.hosts[id], out, kr, recipient, sm, shouldSend); requires s'.hosts[id].receivedPacket.None?; requires var pkt := s.hosts[id].receivedPacket; pkt.Some? && pkt.v.msg.SingleMessage? && pkt.v.msg.m.Shard?; requires s.hosts[id].constants.hostIds == s.config.hostIds; ensures EachKeyClaimedInExactlyOnePlace(s'); { var spkt := Packet(recipient, s.hosts[id].me, sm); forall k ensures (UniqueInFlightPacketClaimsKey(s', k) && NoHostClaimsKey(s', k)) || (NoInFlightPacketClaimsKey(s', k) && UniqueHostClaimsKey(s', k)); { if shouldSend { if (KeyRangeContains(kr, KeyPlus(k))) { assert ReceiverHasNotCanceledUnsentSeqno(s, spkt.dst, spkt.src, spkt.msg.seqno); // OBSERVE trigger //PacketInFlight(s', spkt); forall () ensures NoInFlightPacketClaimsKey(s, k); { reveal_EachKeyClaimedInExactlyOnePlace(); assert HostClaimsKey(s.hosts[id], k); assert SomeHostClaimsKey(s, k); } if InFlightPacketClaimsKey(s', spkt, k) { // OBSERVE unfortunate trigger forall p1,p2 | InFlightPacketClaimsKey(s', p1, k) && InFlightPacketClaimsKey(s', p2, k) ensures p1==p2; { // OBSERVE unfortunate triggers: tickle NoInFlightPacketClaimsKey if (PacketInFlight(s, p1)) { assert InFlightPacketClaimsKey(s, p1, k); } if (PacketInFlight(s, p2)) { assert InFlightPacketClaimsKey(s, p2, k); } } assert SomePacketClaimsKey(s', k) && OnlyOnePacketClaimsKey(s', k); assert UniqueInFlightPacketClaimsKey(s', k); forall i | i in AllHostIdentities(s) ensures !HostClaimsKey(s'.hosts[i], k); { reveal_EachKeyClaimedInExactlyOnePlace(); if (i!=id) { // OBSERVE unfortunate trigger assert HostClaimsKey(s.hosts[id], k); } else { assert !(DelegateForKey(s'.hosts[id].delegationMap, k)==s'.hosts[id].me); assert !BufferedPacketClaimsKey(s'.hosts[id], k); assert !HostClaimsKey(s'.hosts[id], k); } } assert NoHostClaimsKey(s', k); } } else { if (UniqueInFlightPacketClaimsKey(s, k) && NoHostClaimsKey(s, k)) { reveal_EachKeyClaimedInExactlyOnePlace(); NonDelegationsEachKeyClaimedInExactlyOnePlace_case1(s, s', k); } else { reveal_EachKeyClaimedInExactlyOnePlace(); reveal_HiddenInv(); NonDelegationsEachKeyClaimedInExactlyOnePlace_case2(s, s', k); } } } else { NonDelegationsEachKeyClaimedInExactlyOnePlace(s, s'); reveal_EachKeyClaimedInExactlyOnePlace(); } } reveal_EachKeyClaimedInExactlyOnePlace(); assert EachKeyClaimedInExactlyOnePlace(s'); } lemma NextInv_Shard(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, out:set, kr:KeyRange, recipient:NodeIdentity, sm:SingleMessage, shouldSend:bool) requires Inv(s); requires MapComplete(s'); requires SHT_Next(s, s'); requires SHT_NextPred(s, s', id, recv, out); requires NextShard(s.hosts[id], s'.hosts[id], out, kr, recipient, sm, shouldSend); requires s'.hosts[id].receivedPacket.None?; requires var pkt := s.hosts[id].receivedPacket; pkt.Some? && pkt.v.msg.SingleMessage? && pkt.v.msg.m.Shard?; requires s.hosts[id].constants.hostIds == s.config.hostIds; ensures Inv(s'); { assert NoHostsStoreEmptyValues(s'); assert DelegationMessagesCarryNoEmptyValues(s'); var m := Delegate(kr, ExtractRange(s.hosts[id].h, kr)); reveal_PacketsHaveSenderUniqueSeqnos(); assert PacketsHaveSenderUniqueSeqnos(s'); forall () ensures EachKeyClaimedInExactlyOnePlace(s'); { NextInv_NextShard_EachKeyClaimedInExactlyOnePlace(s, s', id, recv, out, kr, recipient, sm, shouldSend); reveal_EachKeyClaimedInExactlyOnePlace(); } forall id,k:Key | id in AllHostIdentities(s) ensures DelegateForKey(s'.hosts[id].delegationMap, k) in AllHostIdentities(s); { assert AllDelegationsToKnownHosts(s); assert DelegateForKey(s.hosts[id].delegationMap, k) in AllHostIdentities(s); // OBSERVE trigger } //assert AllDelegationsToKnownHosts(s'); forall dst, src, seqno ensures ReceiverHasNotCanceledUnsentSeqno(s', dst, src, seqno); { assert ReceiverHasNotCanceledUnsentSeqno(s, dst, src, seqno); // OBSERVE trigger } // assert ReceiverHasCanceledNoUnsentSeqnos(s'); SendSingleMessagePreservesUnAckListProperties(s.hosts[id].sd, s'.hosts[id].sd, m, sm, s.hosts[id].constants.params, shouldSend); // Prove UnAckedListInNetwork reveal_UnAckedListInNetwork(); forall id,msg,dst | id in AllHostIdentities(s) && msg in AckStateLookup(dst, s'.hosts[id].sd.sendState).unAcked && NoAcksInUnAckedLists(s'.hosts[id].sd) && dst == msg.dst ensures Packet(msg.dst, s'.hosts[id].me, msg) in s'.network; { var unAcked := AckStateLookup(dst, s.hosts[id].sd.sendState).unAcked; var unAcked' := AckStateLookup(dst, s'.hosts[id].sd.sendState).unAcked; var i :| 0 <= i < |unAcked'| && unAcked'[i] == msg; if i < |unAcked| { assert msg in AckStateLookup(dst, s.hosts[id].sd.sendState).unAcked; } else { var oldAckState := AckStateLookup(dst, s.hosts[id].sd.sendState); var new_seqno := oldAckState.numPacketsAcked + |oldAckState.unAcked| + 1; if new_seqno > s.hosts[id].constants.params.max_seqno { assert out == {}; } else { assert out == {Packet(msg.dst, s'.hosts[id].me, msg)}; } } } } lemma NextInv_Process_Boring_Message(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, out:set) requires Inv(s); requires MapComplete(s'); requires SHT_Next(s, s'); requires SHT_NextPred(s, s', id, recv, out); requires s.hosts[id].receivedPacket.Some? && s.hosts[id].receivedPacket.v.msg.SingleMessage? ==> !s.hosts[id].receivedPacket.v.msg.m.Delegate?; //requires s'.hosts[id].receivedPacket.None?; requires s'.hosts[id] == s.hosts[id].(receivedPacket := None); requires out == {}; requires !SpontaneouslyRetransmit(s.hosts[id], s'.hosts[id], out); ensures Inv(s'); { var h := s.hosts[id]; var h' := s'.hosts[id]; assert out == {}; assert h' == h.(receivedPacket := None); reveal_UnAckedListInNetwork(); // ==> assert AckListsInv(s'); reveal_PacketsHaveSenderUniqueSeqnos(); // ==> assert PacketsHaveSenderUniqueSeqnos(s'); // Prove ReceiverHasCanceledNoUnsentSeqnos(s') forall dst, src, seqno {:trigger ReceiverHasNotCanceledUnsentSeqno(s', dst, src, seqno)} ensures dst in AllHostIdentities(s) && src in AllHostIdentities(s) && HighestSeqnoSent(s.hosts[src].sd, dst) < seqno ==> seqno > TombstoneTableLookup(src, s.hosts[dst].sd.receiveState); { assert ReceiverHasNotCanceledUnsentSeqno(s, dst, src, seqno); // OBSERVE: Need to trigger to expand the definition } assert ReceiverHasCanceledNoUnsentSeqnos(s'); reveal_EachKeyClaimedInExactlyOnePlace(); // ==> assert NotADelegateStep(s, s'); NonDelegationsEachKeyClaimedInExactlyOnePlace(s, s'); // Prove EachKeyClaimedInExactlyOnePlace assert EachKeyClaimedInExactlyOnePlace(s'); } lemma NextInv_Process_Message(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, out:set) requires Inv(s); requires MapComplete(s'); requires SHT_Next(s, s'); requires SHT_NextPred(s, s', id, recv, out); requires s'.hosts[id].receivedPacket.None?; requires ShouldProcessReceivedMessage(s.hosts[id]); requires s.hosts[id].receivedPacket.v in s.network; requires Process_Message(s.hosts[id], s'.hosts[id], out); requires !SpontaneouslyRetransmit(s.hosts[id], s'.hosts[id], out); ensures Inv(s'); { var h := s.hosts[id]; var h' := s'.hosts[id]; var rpkt := s.hosts[id].receivedPacket.v; if (NextGetRequest(h, h', rpkt, out)) { NextInv_Get_NotADelegateStep(s, s', id, recv, out, rpkt); NextInv_Get(s, s', id, recv, out, rpkt); assert Inv(s'); } else if (NextSetRequest(h, h', rpkt, out)) { NextInv_Set_NotADelegateStep(s, s', id, recv, out, rpkt); NextInv_Set(s, s', id, recv, out, rpkt); } else if (NextDelegate(h, h', rpkt, out)) { NextInv_Delegate(s, s', id, recv, out, rpkt); } else if (NextShard_Wrapper(h, h', rpkt, out)) { if ( rpkt.msg.m.recipient == h.me || !ValidKeyRange(rpkt.msg.m.kr) || !ValidPhysicalAddress(rpkt.msg.m.recipient) || EmptyKeyRange(rpkt.msg.m.kr) || rpkt.msg.m.recipient !in h.constants.hostIds || !DelegateForKeyRangeIsHost(h.delegationMap, rpkt.msg.m.kr, h.me) || |ExtractRange(h.h, rpkt.msg.m.kr)| >= max_hashtable_size()) { //s' == s.(receivedPacket := s'.receivedPacket) && out == {} NextInv_Process_Boring_Message(s, s', id, recv, out); } else { var sm,b :| NextShard(h, h', out, rpkt.msg.m.kr, rpkt.msg.m.recipient, sm, b); NextInv_Shard(s, s', id, recv, out, rpkt.msg.m.kr, rpkt.msg.m.recipient, sm, b); } } else if NextReply(h, h', rpkt, out) { NextInv_Process_Boring_Message(s, s', id, recv, out); assert Inv(s'); } else if NextRedirect(h, h', rpkt, out) { NextInv_Process_Boring_Message(s, s', id, recv, out); assert Inv(s'); } else { assert false; } } lemma NextInv_ReceivePacket(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, rpkt:Packet, out:set, ack:Packet) requires Inv(s); requires MapComplete(s'); requires SHT_Next(s, s'); requires SHT_NextPred(s, s', id, recv, out); requires rpkt in recv; requires ReceivePacket(s.hosts[id], s'.hosts[id], rpkt, out, ack); ensures Inv(s'); { var h := s.hosts[id]; var h' := s'.hosts[id]; if h.receivedPacket.None? { assert ReceiveSingleMessage(h.sd, h'.sd, rpkt, ack, out); ReceivePacket_Properties(s, s', id, recv, rpkt, out, ack); } else { assert s.hosts == s'.hosts; // OBSERVE (extensionality) assert s.network == s'.network; // OBSERVE (extensionality?) assert s == s'; } } /* lemma NextInv_ProcessReceivedPacket_BoringPacket(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, out:set) requires Inv(s); requires MapComplete(s'); requires SHT_Next(s, s'); requires SHT_NextPred(s, s', id, recv, out); requires ProcessReceivedPacket(s.hosts[id], s'.hosts[id], out); requires !SpontaneouslyRetransmit(s.hosts[id], s'.hosts[id], out); requires var h := s.hosts[id]; h.receivedPacket.Some? && !NewSingleMessage(h.sd, h.receivedPacket.v); ensures Inv(s'); { var h := s.hosts[id]; var h' := s'.hosts[id]; assert out == {}; assert h' == h.(receivedPacket := None); reveal_UnAckedListInNetwork(); // ==> assert AckListsInv(s'); reveal_PacketsHaveSenderUniqueSeqnos(); // ==> assert PacketsHaveSenderUniqueSeqnos(s'); // Prove ReceiverHasCanceledNoUnsentSeqnos(s') forall dst, src, seqno ensures dst in AllHostIdentities(s) && src in AllHostIdentities(s) && HighestSeqnoSent(s.hosts[src].sd, dst) < seqno ==> seqno > TombstoneTableLookup(src, s.hosts[dst].sd.receiveState); { assert ReceiverHasNotCanceledUnsentSeqno(s, dst, src, seqno); // OBSERVE: Need to trigger to expand the definition } assert ReceiverHasCanceledNoUnsentSeqnos(s'); reveal_EachKeyClaimedInExactlyOnePlace(); // ==> assert NotADelegateStep(s, s'); NonDelegationsEachKeyClaimedInExactlyOnePlace(s, s'); // Prove EachKeyClaimedInExactlyOnePlace assert EachKeyClaimedInExactlyOnePlace(s'); } */ lemma NextInv_ProcessReceivedPacket(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, out:set) requires Inv(s); requires MapComplete(s'); requires SHT_Next(s, s'); requires SHT_NextPred(s, s', id, recv, out); requires ProcessReceivedPacket(s.hosts[id], s'.hosts[id], out); requires !SpontaneouslyRetransmit(s.hosts[id], s'.hosts[id], out); ensures Inv(s'); { var h := s.hosts[id]; var h' := s'.hosts[id]; //assert ReceiveSingleMessage(h.sd, h'.sd, rpkt, ack, ack_packets); if ShouldProcessReceivedMessage(h) { NextInv_Process_Message(s, s', id, recv, out); } else { assert s.hosts == s'.hosts; // OBSERVE (extensionality) assert s.network == s'.network; // OBSERVE (extensionality?) assert s == s'; } } lemma NextInv_SpontaneouslyRetransmit(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, out:set) requires Inv(s); requires MapComplete(s'); requires SHT_Next(s, s'); requires SHT_NextPred(s, s', id, recv, out); requires SpontaneouslyRetransmit(s.hosts[id], s'.hosts[id], out) ensures Inv(s'); { var h := s.hosts[id]; var h' := s'.hosts[id]; reveal_UnAckedListInNetwork(); assert h == h'; forall p | p in out ensures p in s.network; { var dst, i :| dst in h.sd.sendState && 0 <= i < |h.sd.sendState[dst].unAcked| && h.sd.sendState[dst].unAcked[i].SingleMessage? && (var sm := h.sd.sendState[dst].unAcked[i]; p.dst == sm.dst && p.src == s.hosts[id].me && p.msg == sm); // Needed for the OBSERVE on the next line assert AckStateLookup(dst, h.sd.sendState) == h.sd.sendState[dst]; // OBSERVE assert UnAckedMsgForDst(h.sd, p.msg, p.dst); // OBSERVE } reveal_PacketsHaveSenderUniqueSeqnos(); // Prove ReceiverHasCanceledNoUnsentSeqnos(s') forall dst, src, seqno {:trigger ReceiverHasNotCanceledUnsentSeqno(s', dst, src, seqno)} ensures dst in AllHostIdentities(s) && src in AllHostIdentities(s) && HighestSeqnoSent(s.hosts[src].sd, dst) < seqno ==> seqno > TombstoneTableLookup(src, s.hosts[dst].sd.receiveState); { assert ReceiverHasNotCanceledUnsentSeqno(s, dst, src, seqno); // OBSERVE: Need to trigger to expand the definition } NonDelegationsEachKeyClaimedInExactlyOnePlace(s, s'); } lemma NextInv_NextPred(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, out:set) requires Inv(s); requires MapComplete(s'); requires SHT_NextPred(s, s', id, recv, out); ensures Inv(s'); { var h := s.hosts[id]; var h' := s'.hosts[id]; if (exists pkt, ack :: pkt in recv && ReceivePacket(h, h', pkt, out, ack)) { var pkt, ack :| pkt in recv && ReceivePacket(h, h', pkt, out, ack); NextInv_ReceivePacket(s, s', id, recv, pkt, out, ack); } else if SpontaneouslyRetransmit(h, h', out) { NextInv_SpontaneouslyRetransmit(s, s', id, recv, out); } else if ProcessReceivedPacket(h, h', out) { NextInv_ProcessReceivedPacket(s, s', id, recv, out); } } lemma NextInv_NextExternal(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, out:set) requires Inv(s); requires MapComplete(s'); requires SHT_NextExternal(s, s', id, recv, out); ensures Inv(s'); { reveal_UnAckedListInNetwork(); // ==> assert AckListsInv(s'); reveal_PacketsHaveSenderUniqueSeqnos(); // ==> assert PacketsHaveSenderUniqueSeqnos(s'); forall dst, src, seqno ensures ReceiverHasNotCanceledUnsentSeqno(s', dst, src, seqno); // <== Prove this subinvariant { assert ReceiverHasNotCanceledUnsentSeqno(s, dst, src, seqno); } NonDelegationsEachKeyClaimedInExactlyOnePlace(s, s'); // ==> assert EachKeyClaimedInExactlyOnePlace(s'); } lemma NextInv(s:SHT_State, s':SHT_State) requires Inv(s); requires MapComplete(s'); requires SHT_Next(s, s'); ensures Inv(s'); { if (exists id, recv, out :: SHT_NextPred(s, s', id, recv, out)) { var id, recv, out :| SHT_NextPred(s, s', id, recv, out); NextInv_NextPred(s, s', id, recv, out); } else if (exists id, recv, out :: SHT_NextExternal(s, s', id, recv, out)) { var id, recv, out :| SHT_NextExternal(s, s', id, recv, out); NextInv_NextExternal(s, s', id, recv, out); } else { assert false; // There should be no other cases } } lemma InitInv(c:SHTConfiguration, s:SHT_State) requires WFSHTConfiguration(c); requires SHT_Init(c, s); ensures Inv(s); { reveal_UnAckedListInNetwork(); reveal_EachKeyClaimedInExactlyOnePlace(); forall k ensures NoInFlightPacketClaimsKey(s, k); ensures UniqueHostClaimsKey(s, k); { var id := s.config.rootIdentity; assert HostClaimsKey(s.hosts[id], k); } reveal_PacketsHaveSenderUniqueSeqnos(); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/SHT/RefinementProof/Refinement.i.dfy ================================================ include "../../../Services/SHT/HT.s.dfy" include "InvDefs.i.dfy" include "../../../Services/SHT/AbstractService.s.dfy" include "../Message.i.dfy" include "../../Common/NodeIdentity.i.dfy" include "../../../Common/Collections/Maps2.i.dfy" module SHT__Refinement_i { import opened SHT__HT_s import opened SHT__InvDefs_i import opened AbstractServiceSHT_s`All import opened AppInterface_i`Spec import opened SHT__Message_i import opened SHT__SHT_i import opened Concrete_NodeIdentity_i import opened Collections__Maps2_i import opened Collections__Sets_i // Frustrating: // a set comprehension must produce a finite set, but Dafny's heuristics can't figure out how to produce a bounded set of values for 'h' //function RefinedDomain(s:SHT_State) : set // requires MapComplete(s); //{ // set h,k | FindHashTable(s,k)==h && k in h :: k //} // Workaround: Add a finite bound for 'h'. This set doesn't // restrict RefinedDomain at all, but convinces Dafny it's finite. function AllHashTables(s:SHT_State) : set requires MapComplete(s); { (set pkt | pkt in s.network && pkt.src in AllHostIdentities(s) && pkt.msg.SingleMessage? && pkt.msg.m.Delegate? :: pkt.msg.m.h) + (set id {:auto_trigger} | id in AllHostIdentities(s) :: s.hosts[id].h) } // This definition is opaque because it is trigger-happy (alternating quantifiers) function {:opaque} RefinedDomain(s:SHT_State) : set requires MapComplete(s); requires PacketsHaveSaneHeaders(s); requires AllDelegationsToKnownHosts(s); ensures forall k :: k in RefinedDomain(s) ==> k in FindHashTable(s,k); // Exposed to eliminate 'key may not be in domain' error in Refinement() below. { set h,k | (h in AllHashTables(s)) && FindHashTable(s,k)==h && (k in h) :: k } /*function Refinement(s:SHT_State) : Hashtable requires MapComplete(s); requires PacketsHaveSaneHeaders(s); requires AllDelegationsToKnownHosts(s); { // TODO this will be a little tricky around empty values -- we must // be sure the domains match, which probably means ensuring that // we don't store empty values explicitly in either system (and then // making sure that's an invariant). map k | k in RefinedDomain(s) :: FindHashTable(s,k)[k] }*/ function Refinement(s:SHT_State) : ServiceState requires MapComplete(s); requires PacketsHaveSaneHeaders(s); requires AllDelegationsToKnownHosts(s); { // TODO this will be a little tricky around empty values -- we must // be sure the domains match, which probably means ensuring that // we don't store empty values explicitly in either system (and then // making sure that's an invariant). var reqs := set h,i {:trigger h.receivedRequests[i]} | h in maprange(s.hosts) && 0 <= i < |h.receivedRequests| :: h.receivedRequests[i]; var ss := ServiceState'( MapSeqToSet(s.config.hostIds, x => x), map k | k in RefinedDomain(s) :: FindHashTable(s,k)[k], (reqs), //+ (set p | p in s.network && p.msg.SingleMessage? && p.msg.m.SetRequest? :: AppSetRequest(p.src, p.msg.seqno, p.msg.m.k_setrequest, p.msg.m.v_setrequest)), set p | p in s.network && p.msg.SingleMessage? && p.msg.m.Reply? && p.src in s.hosts :: AppReply(p.msg.seqno, p.msg.m.k_reply, p.msg.m.v) ); ss } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/SHT/RefinementProof/RefinementProof.i.dfy ================================================ include "../../../Common/Collections/Maps2.i.dfy" include "../../../Common/Collections/Sets.i.dfy" include "Refinement.i.dfy" include "InvProof.i.dfy" module SHT__RefinementProof_i { import opened Native__Io_s import opened Logic__Option_i import opened Collections__Maps2_s import opened Collections__Maps2_i import opened Collections__Sets_i import opened AbstractServiceSHT_s`All import opened AppInterface_i`Spec import opened Concrete_NodeIdentity_i import opened SHT__Refinement_i import opened SHT__InvProof_i import opened SHT__HT_s import opened SHT__InvDefs_i import opened SHT__Message_i import opened SHT__SHT_i import opened SHT__Network_i import opened SHT__SingleMessage_i import opened SHT__Keys_i import opened SHT__Host_i import opened SHT__Delegations_i import opened SHT__SingleDelivery_i predicate HashtableNext(h:Hashtable, h':Hashtable) { (exists k, ov :: Set(h, h', k, ov)) || (exists k, ov :: Get(h, h', k, ov)) } predicate HashtableStutter(h:Hashtable, h':Hashtable) { h'==h } predicate ServiceStutter(s:ServiceState', s':ServiceState') { s' == s } lemma PacketClaimsKey_forces_FindHashTable(s:SHT_State, pkt:Packet, k:Key) requires MapComplete(s); requires PacketsHaveSaneHeaders(s); requires AllDelegationsToKnownHosts(s); requires InFlightPacketClaimsKey(s,pkt,k); requires UniqueInFlightPacketClaimsKey(s, k); ensures ThePacketThatClaimsKey(s,k) == pkt; ensures FindHashTable(s,k) == pkt.msg.m.h; { assert forall p1,p2 :: InFlightPacketClaimsKey(s,p1,k) && InFlightPacketClaimsKey(s,p2,k) ==> p1==p2; assert ThePacketThatClaimsKey(s,k) == pkt; // assert FindHashTable(s,k) == ThePacketThatClaimsKey(s,k).msg.m.h; } lemma HostClaimsKey_forces_FindHashTable(s:SHT_State, id:NodeIdentity, k:Key) requires Inv(s); requires id in AllHostIdentities(s); requires HostClaimsKey(s.hosts[id], k); ensures FindHashTable(s,k) == FindHostHashTable(s, k); //== s.hosts[id].h; { reveal_EachKeyClaimedInExactlyOnePlace(); assert NoInFlightPacketClaimsKey(s,k); // OBSERVE trigger } lemma UniquePacketClaimsKey_forces_FindHashTable(s:SHT_State, k:Key) returns (pkt:Packet) requires MapComplete(s); requires PacketsHaveSaneHeaders(s); requires AllDelegationsToKnownHosts(s); requires UniqueInFlightPacketClaimsKey(s, k); ensures InFlightPacketClaimsKey(s,pkt,k); ensures ThePacketThatClaimsKey(s,k) == pkt; ensures FindHashTable(s,k) == pkt.msg.m.h; { assert forall p1,p2 :: InFlightPacketClaimsKey(s,p1,k) && InFlightPacketClaimsKey(s,p2,k) ==> p1==p2; pkt :| InFlightPacketClaimsKey(s, pkt, k); assert ThePacketThatClaimsKey(s,k) == pkt; // assert FindHashTable(s,k) == ThePacketThatClaimsKey(s,k).msg.m.h; } lemma HostClaimsKey_forces_FindHostHashTable(s:SHT_State, k:Key) returns (id:NodeIdentity) requires Inv(s); requires UniqueHostClaimsKey(s, k); ensures id in AllHostIdentities(s); ensures HostClaimsKey(s.hosts[id], k); ensures FindHashTable(s,k) == FindHostHashTable(s, k); ensures id == TheHostThatClaimsKey(s, k); { reveal_EachKeyClaimedInExactlyOnePlace(); assert NoInFlightPacketClaimsKey(s,k); // OBSERVE trigger id :| id in AllHostIdentities(s) && HostClaimsKey(s.hosts[id], k); } predicate HashtableIsNormalized(h:Hashtable) { forall k {:trigger k in h} {:trigger h[k]} :: k in h ==> HashtableLookup(h, k) != ValueAbsent() } predicate HashTablesAgreeUpToNormalization(h1:Hashtable, h2:Hashtable) { forall k /* Magical triggers from Chris */ {:trigger HashtableLookup(h1,k)}{:trigger HashtableLookup(h2,k)} :: HashtableLookup(h1,k) == HashtableLookup(h2,k) } lemma HashtableAgreement(h1:Hashtable, h2:Hashtable) requires HashtableIsNormalized(h1); requires HashtableIsNormalized(h2); requires HashTablesAgreeUpToNormalization(h1, h2); ensures h1 == h2; { forall k ensures (k in h1) == (k in h2); { assert HashtableLookup(h1,k) == HashtableLookup(h2,k); // OBSERVE trigger } forall k | (k in h1) ensures h1[k]==h2[k]; { assert HashtableLookup(h1,k) == HashtableLookup(h2,k); // OBSERVE trigger } } predicate InvRefinementNormalized(s:SHT_State) requires MapComplete(s); requires PacketsHaveSaneHeaders(s); requires AllDelegationsToKnownHosts(s); { HashtableIsNormalized(Refinement(s).ht) } predicate {:opaque} HiddenInvRefinementNormalized(s:SHT_State) requires MapComplete(s); requires PacketsHaveSaneHeaders(s); requires AllDelegationsToKnownHosts(s); { InvRefinementNormalized(s) } function NormalizedReplace(h:Hashtable, k:Key, ov:OptionalValue) : Hashtable { if ov.ValuePresent? then h[k := ov.v] else mapremove(h, k) } lemma NormalizedReplace_PreservesNormalization(h:Hashtable, k:Key, v:OptionalValue) requires HashtableIsNormalized(h); ensures HashtableIsNormalized(NormalizedReplace(h,k,v)); { } lemma LookupInRefinement(s:SHT_State, k:Key) requires MapComplete(s); requires PacketsHaveSaneHeaders(s); requires AllDelegationsToKnownHosts(s); requires EachKeyClaimedInExactlyOnePlace(s); requires BufferedPacketsInv(s); requires InvConstants(s); ensures HashtableLookup(Refinement(s).ht, k) == HashtableLookup(FindHashTable(s,k), k); { reveal_RefinedDomain(); if exists pkt :: InFlightPacketClaimsKey(s,pkt,k) { // if k in Refinement(s) { //// calc { //// HashtableLookup(Refinement(s).ht, k); //// if k in Refinement(s) then ValuePresent(Refinement(s)[k]) else ValueAbsent(); //// ValuePresent(Refinement(s)[k]); //// //FindHashTable(s,k)[k]; //// HashtableLookup(FindHashTable(s,k), k); //// } // } assert HashtableLookup(Refinement(s).ht, k) == HashtableLookup(FindHashTable(s,k), k); } else if exists id :: id in AllHostIdentities(s) && HostClaimsKey(s.hosts[id], k) { var id :| id in AllHostIdentities(s) && HostClaimsKey(s.hosts[id], k); var h := s.hosts[id]; assert DelegateForKey(h.delegationMap, k)==h.me || BufferedPacketClaimsKey(h, k); reveal_EachKeyClaimedInExactlyOnePlace(); assert UniqueHostClaimsKey(s, k); // OBSERVE assert OnlyOneHostClaimsKey(s, k); // OBSERVE if id != TheHostThatClaimsKey(s, k) { assert HostClaimsKey(s.hosts[id], k); assert HostClaimsKey(s.hosts[TheHostThatClaimsKey(s, k)], k); assert false; } assert id == TheHostThatClaimsKey(s, k); //assert s.hosts[id] == s.hosts[TheHostThatClaimsKey(s, k)]; assert FindHashTable(s,k) == if BufferedPacketClaimsKey(s.hosts[id], k) then s.hosts[id].receivedPacket.v.msg.m.h else // assert DelegateForKey(s.hosts[id].delegationMap, k)==s.hosts[id].me s.hosts[id].h; if BufferedPacketClaimsKey(s.hosts[id], k) && NewSingleMessage(s.hosts[id].sd, s.hosts[id].receivedPacket.v) { //assert h.receivedPacket.Some? ==> h.receivedPacket.v in s.network; assert h.receivedPacket.v in s.network; assert FindHashTable(s,k) == s.hosts[id].receivedPacket.v.msg.m.h; assert s.hosts[id].receivedPacket.v.src in s.hosts[id].constants.hostIds; assert s.hosts[id].receivedPacket.v.src in AllHostIdentities(s); assert FindHashTable(s,k) in AllHashTables(s); } else { assert FindHashTable(s,k) in AllHashTables(s); } assert FindHashTable(s,k) in AllHashTables(s); //assert k in FindHashTable(s,k); if k in FindHashTable(s, k) { assert HashtableLookup(Refinement(s).ht, k) == HashtableLookup(FindHashTable(s,k), k); } else { assert HashtableLookup(Refinement(s).ht, k) == HashtableLookup(FindHashTable(s,k), k); } } else { assert HashtableLookup(Refinement(s).ht, k) == HashtableLookup(FindHashTable(s,k), k); } } lemma SetPreservesRefinement_koNotk(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, out:set, rpkt:Packet, k:Key, ko:Key, pkt:Packet) // requires Inv(s); // Boy, does Inv cause trouble. requires MapComplete(s); requires PacketsHaveSaneHeaders(s); requires EachKeyClaimedInExactlyOnePlace(s); requires Inv(s'); requires SHT_Next(s, s'); requires SHT_NextPred(s, s', id, recv, out); requires rpkt in s.network && rpkt.msg.SingleMessage? && rpkt.msg.m.SetRequest? && NextSetRequest(s.hosts[id], s'.hosts[id], rpkt, out); requires k==rpkt.msg.m.k_setrequest; requires HostClaimsKey(s.hosts[id], k); requires exists pkt :: InFlightPacketClaimsKey(s,pkt,ko); requires pkt == ThePacketThatClaimsKey(s,ko); requires !SpontaneouslyRetransmit(s.hosts[id], s'.hosts[id], out); ensures ko!=k; { forall () ensures NoHostClaimsKey(s, ko); { reveal_EachKeyClaimedInExactlyOnePlace(); } } predicate NoNewDelegationMessages(s:SHT_State, s':SHT_State) requires MapComplete(s); requires MapComplete(s'); requires PacketsHaveSaneHeaders(s); requires PacketsHaveSaneHeaders(s'); { forall pkt:Packet :: pkt.msg.SingleMessage? && pkt.msg.m.Delegate? ==> (pkt in s.network <==> pkt in s'.network) } predicate InvBasics(s:SHT_State) { MapComplete(s) && PacketsHaveSaneHeaders(s) && AllDelegationsToKnownHosts(s) } lemma ThereCanBeOnlyOneInFlightPacket(s:SHT_State, s':SHT_State, k:Key, pkt:Packet) requires HiddenInv(s) && InvBasics(s); requires HiddenInv(s') && InvBasics(s'); requires SHT_Next(s, s'); requires InFlightPacketClaimsKey(s,pkt,k); requires InFlightPacketClaimsKey(s',pkt,k); ensures ThePacketThatClaimsKey(s,k)==pkt; ensures ThePacketThatClaimsKey(s',k)==pkt; { forall () ensures UniqueInFlightPacketClaimsKey(s, k); ensures UniqueInFlightPacketClaimsKey(s', k); { reveal_HiddenInv(); reveal_EachKeyClaimedInExactlyOnePlace(); } PacketClaimsKey_forces_FindHashTable(s, pkt, k); PacketClaimsKey_forces_FindHashTable(s', pkt, k); } lemma {:timeLimitMultiplier 2} NondelegatingReadonlyStepPreservesRefinement_guts(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, out:set) requires HiddenInv(s) && InvBasics(s); requires HiddenInv(s') && InvBasics(s'); requires SHT_Next(s, s'); requires NotADelegateStep(s, s'); requires forall id :: id in AllHostIdentities(s) ==> s'.hosts[id].h==s.hosts[id].h && s'.hosts[id].delegationMap==s.hosts[id].delegationMap; requires forall id :: id in AllHostIdentities(s) && DelegationPacket(s.hosts[id].receivedPacket) ==> DelegationPacketStable(s, s', id); ensures forall k :: FindHashTable(s,k)==FindHashTable(s',k); { reveal_HiddenInv(); forall k ensures FindHashTable(s,k)==FindHashTable(s',k); { if exists pkt :: InFlightPacketClaimsKey(s,pkt,k) { var pkt :| InFlightPacketClaimsKey(s,pkt,k); ThereCanBeOnlyOneInFlightPacket(s, s', k, pkt); } else { reveal_EachKeyClaimedInExactlyOnePlace(); assert UniqueHostClaimsKey(s, k); // OBSERVE trigger var kid :| kid in AllHostIdentities(s) && HostClaimsKey(s.hosts[kid], k); forall () ensures TheHostThatClaimsKey(s, k)==kid; ensures TheHostThatClaimsKey(s', k)==kid; { assert HostClaimsKey(s'.hosts[kid],k); // most heinous of OBSERVE triggers: assert forall i1,i2 :: i1 in AllHostIdentities(s) && HostClaimsKey(s.hosts[i1], k) && i2 in AllHostIdentities(s) && HostClaimsKey(s.hosts[i2], k) ==> i1==i2; reveal_EachKeyClaimedInExactlyOnePlace(); } } if (exists pkt :: InFlightPacketClaimsKey(s,pkt,k)) { var pkt :| InFlightPacketClaimsKey(s,pkt,k); assert InFlightPacketClaimsKey(s',pkt,k); assert FindHashTable(s,k)==FindHashTable(s',k); } else { forall pkt ensures !InFlightPacketClaimsKey(s', pkt, k) { assert !InFlightPacketClaimsKey(s, pkt, k); // OBSERVE trigger } assert NoInFlightPacketClaimsKey(s', k); // OBSERVE trigger assert UniqueHostClaimsKey(s, k); // OBSERVE assert OnlyOneHostClaimsKey(s, k); // OBSERVE assert FindHashTable(s,k)==FindHashTable(s',k); } } } lemma NondelegatingReadonlyStepPreservesRefinement(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, out:set) requires HiddenInv(s) && InvBasics(s); requires HiddenInv(s') && InvBasics(s'); requires SHT_Next(s, s'); requires NotADelegateStep(s, s'); requires NoNewDelegationMessages(s, s'); requires forall id :: id in AllHostIdentities(s) ==> s'.hosts[id].h==s.hosts[id].h && s'.hosts[id].delegationMap==s.hosts[id].delegationMap; requires forall id :: id in AllHostIdentities(s) && DelegationPacket(s.hosts[id].receivedPacket) ==> DelegationPacketStable(s, s', id); ensures Refinement(s).ht == Refinement(s').ht; { forall () ensures RefinedDomain(s) == RefinedDomain(s'); { NondelegatingReadonlyStepPreservesRefinement_guts(s, s', id, recv, out); reveal_RefinedDomain(); assert forall k :: FindHashTable(s,k)==FindHashTable(s',k); } forall k | k in RefinedDomain(s) ensures FindHashTable(s,k)[k] == FindHashTable(s',k)[k]; { NondelegatingReadonlyStepPreservesRefinement_guts(s, s', id, recv, out); } /*assert Refinement(s).ht == Refinement(s').ht; var R := Refinement(s); var R' := Refinement(s'); var h := s.hosts[id]; var h' := s'.hosts[id]; var rpkt := s.hosts[id].receivedPacket.v; if NextGetRequest(h, h', rpkt, out) { assert Refinement(s).requests == Refinement(s').requests; assert Refinement(s).replies == Refinement(s').replies; }*/ } predicate {:opaque} HiddenSHT_Next_and_SHT_NextPred(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, out:set) requires MapComplete(s); requires MapComplete(s'); { SHT_Next(s, s') && SHT_NextPred(s, s', id, recv, out) } function {:opaque} HiddenRefinement(s:SHT_State) : Hashtable requires InvBasics(s); { Refinement(s).ht } lemma SetPreservesRefinement_InFlight(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, out:set, rpkt:Packet, ko:Key) requires HiddenInv(s) && InvBasics(s); requires HiddenInv(s') && InvBasics(s'); requires SHT_Next(s, s'); requires SHT_NextPred(s, s', id, recv, out); requires id in AllHostIdentities(s); requires HiddenSHT_Next_and_SHT_NextPred(s, s', id, recv, out); requires !SpontaneouslyRetransmit(s.hosts[id], s'.hosts[id], out); requires rpkt in s.network && rpkt.msg.SingleMessage? && rpkt.msg.m.SetRequest? && NextSetRequest(s.hosts[id], s'.hosts[id], rpkt, out); requires InvRefinementNormalized(s); requires DelegateForKey(s.hosts[id].delegationMap, rpkt.msg.m.k_setrequest)==id; requires (exists pkt :: InFlightPacketClaimsKey(s,pkt,ko)); requires !SpontaneouslyRetransmit(s.hosts[id], s'.hosts[id], out); ensures HashtableLookup(HiddenRefinement(s'),ko) == HashtableLookup(NormalizedReplace(HiddenRefinement(s),rpkt.msg.m.k_setrequest,rpkt.msg.m.v_setrequest), ko); { var k := rpkt.msg.m.k_setrequest; var v := rpkt.msg.m.v_setrequest; var R := HiddenRefinement(s); var R' := HiddenRefinement(s'); var NRR := NormalizedReplace(R,k,v); var pkt := ThePacketThatClaimsKey(s,ko); assert InFlightPacketClaimsKey(s,pkt,ko); // OBSERVE trigger ... Whoah, why would I need a trigger here? The :| is an exists that is unhelpful? assert pkt!=rpkt; forall () ensures PacketInFlight(s', pkt); { reveal_HiddenInv(); } forall() ensures ko!=k; { reveal_HiddenInv(); reveal_EachKeyClaimedInExactlyOnePlace(); assert HostClaimsKey(s.hosts[id],k); // OBSERVE trigger assert NoInFlightPacketClaimsKey(s, k); // assert !InFlightPacketClaimsKey(s,pkt,k); } assert InFlightPacketClaimsKey(s',pkt,ko); // OBSERVE trigger forall () ensures EachKeyClaimedInExactlyOnePlace(s) && BufferedPacketsInv(s) && EachKeyClaimedInExactlyOnePlace(s') && BufferedPacketsInv(s'); { reveal_HiddenInv(); } forall () ensures InvConstants(s) && InvConstants(s') { reveal_HiddenInv(); } calc { HashtableLookup(HiddenRefinement(s'),ko); { reveal_HiddenRefinement(); } HashtableLookup(Refinement(s').ht,ko); { LookupInRefinement(s',ko); } HashtableLookup(FindHashTable(s',ko), ko); HashtableLookup(ThePacketThatClaimsKey(s',ko).msg.m.h,ko); { ThereCanBeOnlyOneInFlightPacket(s, s', ko, pkt); } HashtableLookup(ThePacketThatClaimsKey(s,ko).msg.m.h,ko); HashtableLookup(FindHashTable(s,ko), ko); { LookupInRefinement(s,ko); } HashtableLookup(Refinement(s).ht,ko); { reveal_HiddenRefinement(); } HashtableLookup(HiddenRefinement(s),ko); HashtableLookup(NormalizedReplace(HiddenRefinement(s),k,v), ko); } calc { HashtableLookup(R,ko); HashtableLookup(HiddenRefinement(s),ko); { reveal_HiddenRefinement(); } HashtableLookup(Refinement(s).ht,ko); { LookupInRefinement(s,ko); } HashtableLookup(FindHashTable(s,ko), ko); HashtableLookup(ThePacketThatClaimsKey(s,ko).msg.m.h,ko); { assert ThePacketThatClaimsKey(s,ko) == pkt; } HashtableLookup(pkt.msg.m.h,ko); } assert HashtableLookup(R,ko) == HashtableLookup(pkt.msg.m.h,ko); assert InFlightPacketClaimsKey(s',pkt,ko); forall () ensures UniqueInFlightPacketClaimsKey(s, ko); ensures UniqueInFlightPacketClaimsKey(s', ko); { reveal_HiddenInv(); reveal_EachKeyClaimedInExactlyOnePlace(); } PacketClaimsKey_forces_FindHashTable(s', pkt, ko); assert ThePacketThatClaimsKey(s',ko) == pkt; LookupInRefinement(s',ko); assert HashtableLookup(R',ko) == HashtableLookup(ThePacketThatClaimsKey(s',ko).msg.m.h,ko); forall () ensures ko!=k; { reveal_HiddenInv(); SetPreservesRefinement_koNotk(s, s', id, recv, out, rpkt, k, ko, pkt); } // NormalizedReplace_Properties(R,k,v); assert HashtableLookup(NormalizedReplace(R,k,v), ko) == HashtableLookup(R,ko); } predicate FooFHT1(s:SHT_State, k:Key) requires MapComplete(s); requires PacketsHaveSaneHeaders(s); requires AllDelegationsToKnownHosts(s); { exists pkt :: InFlightPacketClaimsKey(s,pkt,k) } predicate FooFHT2(s:SHT_State, k:Key) requires MapComplete(s); requires PacketsHaveSaneHeaders(s); requires AllDelegationsToKnownHosts(s); { exists id {:trigger HostClaimsKey(s.hosts[id], k)} :: id in AllHostIdentities(s) && HostClaimsKey(s.hosts[id], k) } function FooFHT3(s:SHT_State, k:Key) : Hashtable requires MapComplete(s); requires PacketsHaveSaneHeaders(s); requires AllDelegationsToKnownHosts(s); //requires exists id :: id in AllHostIdentities(s) && HostClaimsKey(s.hosts[id], k); requires FooFHT2(s,k); { var id := TheHostThatClaimsKey(s, k); if BufferedPacketClaimsKey(s.hosts[id], k) then s.hosts[id].receivedPacket.v.msg.m.h else // assert DelegateForKey(s.hosts[id].delegationMap, k)==s.hosts[id].me s.hosts[id].h } function FooFindHashTable(s:SHT_State, k:Key) : Hashtable requires MapComplete(s); requires PacketsHaveSaneHeaders(s); requires AllDelegationsToKnownHosts(s); { if FooFHT1(s,k) then ThePacketThatClaimsKey(s,k).msg.m.h else if FooFHT2(s,k) then FooFHT3(s,k) else // Inv ==> this case is false map [] } lemma SetPreservesRefinement_ExpandFindHashTable(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, out:set, rpkt:Packet, ko:Key, kid:NodeIdentity) requires HiddenInv(s) && InvBasics(s); requires HiddenInv(s') && InvBasics(s'); //requires SHT_Next(s, s'); //requires SHT_NextPred(s, s', id, recv, out); requires NoConfigChanged(s, s'); requires id in AllHostIdentities(s); requires HiddenSHT_Next_and_SHT_NextPred(s, s', id, recv, out); requires rpkt in s.network && rpkt.msg.SingleMessage? && rpkt.msg.m.SetRequest? && NextSetRequest(s.hosts[id], s'.hosts[id], rpkt, out); requires InvRefinementNormalized(s); requires DelegateForKey(s.hosts[id].delegationMap, rpkt.msg.m.k_setrequest)==id; requires !(exists pkt :: InFlightPacketClaimsKey(s,pkt,ko)); requires kid in AllHostIdentities(s) && HostClaimsKey(s.hosts[kid], ko); requires !SpontaneouslyRetransmit(s.hosts[id], s'.hosts[id], out); requires s'.hosts[id].receivedPacket.None?; ensures exists id :: id in AllHostIdentities(s) && HostClaimsKey(s'.hosts[id], ko); ensures FindHashTable(s',ko) == FindHostHashTable(s', ko); //s'.hosts[TheHostThatClaimsKey(s', ko)].h; { reveal_HiddenInv(); reveal_EachKeyClaimedInExactlyOnePlace(); assert NoInFlightPacketClaimsKey(s,ko); assert !(exists pkt :: InFlightPacketClaimsKey(s,pkt,ko)); assert kid in AllHostIdentities(s) && HostClaimsKey(s.hosts[kid], ko); forall () ensures kid in AllHostIdentities(s) && HostClaimsKey(s'.hosts[kid], ko); { reveal_HiddenSHT_Next_and_SHT_NextPred(); assert SHT_Next(s, s'); assert SHT_NextPred(s, s', id, recv, out); } assert NoInFlightPacketClaimsKey(s', ko); // OBSERVE trigger assert !(exists pkt :: InFlightPacketClaimsKey(s',pkt,ko)); assert (exists id :: id in AllHostIdentities(s) && HostClaimsKey(s'.hosts[id], ko)); assert !FooFHT1(s',ko); assert FooFHT2(s',ko); assert !BufferedPacketClaimsKey(s'.hosts[id], ko); if kid == id { assert !BufferedPacketClaimsKey(s'.hosts[TheHostThatClaimsKey(s',ko)], ko); } else { calc { s'.hosts[kid]; { reveal_HiddenSHT_Next_and_SHT_NextPred(); assert SHT_Next(s, s'); } s.hosts[kid]; } } calc { FindHashTable(s',ko); FooFindHashTable(s',ko); FooFHT3(s',ko); FindHostHashTable(s', ko); // var id' := TheHostThatClaimsKey(s', ko); // if BufferedPacketClaimsKey(s'.hosts[id'], ko) && NewSingleMessage(s'.hosts[id'].sd, s'.hosts[id'].receivedPacket.v) then // s'.hosts[id'].receivedPacket.v.msg.m.h // else // s'.hosts[id'].h; // s'.hosts[TheHostThatClaimsKey(s', ko)].h; } // assert FindHashTable(s',ko) == s'.hosts[TheHostThatClaimsKey(s', ko)].h; } lemma {:timeLimitMultiplier 2} SetPreservesRefinement_HostClaims(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, out:set, rpkt:Packet, ko:Key, sm:SingleMessage, m:Message) requires HiddenInv(s) && InvBasics(s); requires HiddenInv(s') && InvBasics(s'); requires SHT_Next(s, s'); requires SHT_NextPred(s, s', id, recv, out); requires id in AllHostIdentities(s); requires HiddenSHT_Next_and_SHT_NextPred(s, s', id, recv, out); requires rpkt in s.network && rpkt.msg.SingleMessage? && rpkt.msg.m.SetRequest? && NextSetRequest(s.hosts[id], s'.hosts[id], rpkt, out); requires ValidKey(rpkt.msg.m.k_setrequest) && ValidOptionalValue(rpkt.msg.m.v_setrequest); requires NextSetRequest_Complete(s.hosts[id], s'.hosts[id], rpkt.src, rpkt.msg.seqno, rpkt.msg.m, sm, m, out, true); requires InvRefinementNormalized(s); requires s'.hosts[id].receivedPacket.None?; requires DelegateForKey(s.hosts[id].delegationMap, rpkt.msg.m.k_setrequest)==id; requires !(exists pkt :: InFlightPacketClaimsKey(s,pkt,ko)); requires !SpontaneouslyRetransmit(s.hosts[id], s'.hosts[id], out); requires !DelegationPacket(s.hosts[id].receivedPacket); ensures HashtableLookup(HiddenRefinement(s'),ko) == HashtableLookup(NormalizedReplace(HiddenRefinement(s),rpkt.msg.m.k_setrequest,rpkt.msg.m.v_setrequest), ko); { var k := rpkt.msg.m.k_setrequest; var v := rpkt.msg.m.v_setrequest; var R := HiddenRefinement(s); var R' := HiddenRefinement(s'); var NRR := NormalizedReplace(R,k,v); assert NextSetRequest_Complete(s.hosts[id], s'.hosts[id], rpkt.src, rpkt.msg.seqno, rpkt.msg.m, sm, m, out, true); //assert b; forall () ensures exists kid :: kid in AllHostIdentities(s) && HostClaimsKey(s'.hosts[kid], ko); { reveal_HiddenInv(); reveal_EachKeyClaimedInExactlyOnePlace(); assert !(exists pkt :: InFlightPacketClaimsKey(s,pkt,ko)); if (exists pkt :: InFlightPacketClaimsKey(s',pkt,ko)) { var pkt :| InFlightPacketClaimsKey(s',pkt,ko); assert !InFlightPacketClaimsKey(s,pkt,ko); assert rpkt in recv; assert Network_Receive(s.network, id, recv); assert rpkt.dst == id; assert pkt.msg.m.Delegate?; forall opkt | opkt in out ensures !opkt.msg.m.Delegate?; { var sm,m,b :| NextSetRequest_Complete(s.hosts[id], s'.hosts[id], rpkt.src, rpkt.msg.seqno, rpkt.msg.m, sm, m, out, b); // OBSERVE skolemize var tpkt := Packet(rpkt.src, s.hosts[id].me, sm); ItIsASingletonSet(out, tpkt); ThingsIKnowAboutASingletonSet(out, tpkt, opkt); } assert false; } assert !(exists pkt :: InFlightPacketClaimsKey(s',pkt,ko)); assert UniqueHostClaimsKey(s', ko); } var kid :| kid in AllHostIdentities(s) && HostClaimsKey(s'.hosts[kid], ko); forall () ensures TheHostThatClaimsKey(s', ko)==kid; { reveal_HiddenInv(); reveal_EachKeyClaimedInExactlyOnePlace(); assert NoInFlightPacketClaimsKey(s', ko); // OBSERVE trigger } forall () ensures TheHostThatClaimsKey(s, ko)==kid; { reveal_HiddenInv(); reveal_EachKeyClaimedInExactlyOnePlace(); assert UniqueHostClaimsKey(s, ko); // OBSERVE trigger assert HostClaimsKey(s.hosts[kid], ko); // OBSERVE trigger } forall () ensures kid!=id ==> k!=ko; { reveal_HiddenInv(); reveal_EachKeyClaimedInExactlyOnePlace(); assert HostClaimsKey(s.hosts[id], k); // OBSERVE trigger assert UniqueHostClaimsKey(s, k); // OBSERVE trigger } forall () ensures EachKeyClaimedInExactlyOnePlace(s) && BufferedPacketsInv(s) && EachKeyClaimedInExactlyOnePlace(s') && BufferedPacketsInv(s'); { reveal_HiddenInv(); } forall () ensures InvConstants(s) && InvConstants(s') { reveal_HiddenInv(); } if (k==ko) { assert kid in AllHostIdentities(s) && HostClaimsKey(s'.hosts[kid], k); // OBSERVE trigger to satisfy preconditions of expr on next line. assert TheHostThatClaimsKey(s', k) == TheHostThatClaimsKey(s', ko); forall () ensures NoInFlightPacketClaimsKey(s',k); { reveal_HiddenInv(); reveal_EachKeyClaimedInExactlyOnePlace(); } calc { HashtableLookup(HiddenRefinement(s'),ko); { reveal_HiddenRefinement(); } HashtableLookup(Refinement(s').ht,ko); { LookupInRefinement(s',ko); } HashtableLookup(FindHashTable(s',ko), ko); { assert !(exists pkt :: InFlightPacketClaimsKey(s,pkt,k)); assert id in AllHostIdentities(s) && HostClaimsKey(s'.hosts[id], k); } HashtableLookup(s'.hosts[TheHostThatClaimsKey(s', k)].h, ko); HashtableLookup(s'.hosts[id].h, ko); //if v.ValuePresent? then OptionValue_Present(v) else OptionValue_Absent(); HashtableLookup(NRR, ko); } } else { assert kid in AllHostIdentities(s) && HostClaimsKey(s.hosts[kid], ko); // OBSERVE trigger calc { HashtableLookup(HiddenRefinement(s'),ko); { reveal_HiddenRefinement(); } HashtableLookup(Refinement(s').ht,ko); { LookupInRefinement(s',ko); } HashtableLookup(FindHashTable(s',ko), ko); { SetPreservesRefinement_ExpandFindHashTable(s, s', id, recv, out, rpkt, ko, kid); } HashtableLookup(FindHostHashTable(s',ko), ko); //HashtableLookup(s'.hosts[TheHostThatClaimsKey(s', ko)].h, ko); { if (kid==id) { assert HashtableLookup(s.hosts[id].h, ko) == HashtableLookup(s'.hosts[id].h, ko); } else { assert s'.hosts[kid].h == s.hosts[kid].h; } } HashtableLookup(FindHostHashTable(s, ko), ko); { LookupInRefinement(s,ko); } HashtableLookup(Refinement(s).ht, ko); { reveal_HiddenRefinement(); } HashtableLookup(R, ko); // { HashtableLookup_NormalizedReplace(R, k, v, ko); } HashtableLookup(NormalizedReplace(R,k,v), ko); HashtableLookup(NRR, ko); } calc { HashtableLookup(HiddenRefinement(s'),ko); HashtableLookup(NRR, ko); HashtableLookup(NormalizedReplace(R,k,v), ko); HashtableLookup(NormalizedReplace(HiddenRefinement(s),rpkt.msg.m.k_setrequest,rpkt.msg.m.v_setrequest), ko); } } } //lemma HashtableLookup_NormalizedReplace(R:Hashtable, k:Key, v:Value, ko:Key) // requires k != ko; // ensures HashtableLookup(R, ko) == HashtableLookup(NormalizedReplace(R,k,v), ko); //{ //} lemma SetPreservesRefinement_ko(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, out:set, rpkt:Packet, ko:Key, sm:SingleMessage, m:Message) requires HiddenInv(s) && InvBasics(s); requires HiddenInv(s') && InvBasics(s'); requires SHT_Next(s, s'); requires SHT_NextPred(s, s', id, recv, out); requires id in AllHostIdentities(s); requires HiddenSHT_Next_and_SHT_NextPred(s, s', id, recv, out); requires rpkt in s.network && rpkt.msg.SingleMessage? && rpkt.msg.m.SetRequest? && NextSetRequest(s.hosts[id], s'.hosts[id], rpkt, out); requires ValidKey(rpkt.msg.m.k_setrequest) && ValidOptionalValue(rpkt.msg.m.v_setrequest); requires NextSetRequest_Complete(s.hosts[id], s'.hosts[id], rpkt.src, rpkt.msg.seqno, rpkt.msg.m, sm, m, out, true); requires s'.hosts[id].receivedPacket.None?; requires InvRefinementNormalized(s); requires !SpontaneouslyRetransmit(s.hosts[id], s'.hosts[id], out); requires !DelegationPacket(s.hosts[id].receivedPacket); requires DelegateForKey(s.hosts[id].delegationMap, rpkt.msg.m.k_setrequest)==id; ensures HashtableLookup(HiddenRefinement(s'),ko) == HashtableLookup(NormalizedReplace(HiddenRefinement(s),rpkt.msg.m.k_setrequest,rpkt.msg.m.v_setrequest), ko); { if (exists pkt :: InFlightPacketClaimsKey(s,pkt,ko)) { SetPreservesRefinement_InFlight(s, s', id, recv, out, rpkt, ko); } else { SetPreservesRefinement_HostClaims(s, s', id, recv, out, rpkt, ko, sm, m); } } lemma HashtableLookup_implies_HashtableLookup_one_key(ha:Hashtable, hb:Hashtable, k:Key) requires HashtableLookup(ha,k) == HashtableLookup(hb, k); ensures HashtableLookup(ha,k) == HashtableLookup(hb, k); { if (k in ha) { //assert HashtableLookup(ha,k)==ha[k]; //assert HashtableLookup(ha,k) == OptionValue_Present(ha[k]); assert k in hb; //assert HashtableLookup(hb,k) == OptionValue_Present(hb[k]); assert ha[k] == hb[k]; //assert HashtableLookup(hb,k)==hb[k]; } else { //assert HashtableLookup(ha,k)==[]; assert !(k in hb); //assert HashtableLookup(hb,k)==[]; } } lemma HashtableLookup_implies_HashtableLookup(ha:Hashtable, hb:Hashtable) requires forall k :: HashtableLookup(ha,k) == HashtableLookup(hb, k); ensures forall k :: HashtableLookup(ha,k) == HashtableLookup(hb, k); { forall k ensures HashtableLookup(ha,k) == HashtableLookup(hb, k); { HashtableLookup_implies_HashtableLookup_one_key(ha, hb, k); } } lemma SetPreservesRefinement_main(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, out:set, rpkt:Packet, sm:SingleMessage, m:Message) requires HiddenInv(s) && InvBasics(s); requires HiddenInv(s') && InvBasics(s'); requires SHT_Next(s, s'); requires SHT_NextPred(s, s', id, recv, out); requires id in AllHostIdentities(s); requires HiddenSHT_Next_and_SHT_NextPred(s, s', id, recv, out); requires rpkt in s.network && rpkt.msg.SingleMessage? && rpkt.msg.m.SetRequest? && NextSetRequest(s.hosts[id], s'.hosts[id], rpkt, out); requires ValidKey(rpkt.msg.m.k_setrequest) && ValidOptionalValue(rpkt.msg.m.v_setrequest); requires NextSetRequest_Complete(s.hosts[id], s'.hosts[id], rpkt.src, rpkt.msg.seqno, rpkt.msg.m, sm, m, out, true); requires s'.hosts[id].receivedPacket.None?; requires InvRefinementNormalized(s); requires !SpontaneouslyRetransmit(s.hosts[id], s'.hosts[id], out); requires !DelegationPacket(s.hosts[id].receivedPacket); ensures if DelegateForKey(s.hosts[id].delegationMap, rpkt.msg.m.k_setrequest)==id then Set(HiddenRefinement(s), HiddenRefinement(s'), rpkt.msg.m.k_setrequest, rpkt.msg.m.v_setrequest) else HiddenRefinement(s)==HiddenRefinement(s'); ensures InvRefinementNormalized(s'); { var k := rpkt.msg.m.k_setrequest; var v := rpkt.msg.m.v_setrequest; var R := HiddenRefinement(s); var R' := HiddenRefinement(s'); var sm,m,b :| NextSetRequest_Complete(s.hosts[id], s'.hosts[id], rpkt.src, rpkt.msg.seqno, rpkt.msg.m, sm, m, out, b); if(b) { if (DelegateForKey(s.hosts[id].delegationMap, k)==id) { reveal_HiddenRefinement(); NormalizedReplace_PreservesNormalization(R,k,v); var NRR := NormalizedReplace(R,k,v); // This structure is carefully guarded due to trigger trouble. // The inner forall creates trigger trouble, but the lemma call // satisfies it before the triggers run away. The outer forall // hides the crazily-triggered forall, exposing only the nice // symbolic predicate term. forall () ensures HashTablesAgreeUpToNormalization(R', NRR); ensures HashtableIsNormalized(R'); { forall ko ensures HashtableLookup(R',ko) == HashtableLookup(NRR, ko); { SetPreservesRefinement_ko(s, s', id, recv, out, rpkt, ko, sm, m); } forall ko ensures HashtableLookup(R',ko) == HashtableLookup(NRR, ko); { HashtableLookup_implies_HashtableLookup(R', NRR); } /*forall ko | ko in R' ensures R'[ko]!=[]; { assert HashtableIsNormalized(NRR); assert HashtableLookup(R',ko) == HashtableLookup(NRR, ko); assert ko in NRR; }*/ } reveal_HiddenInv(); HashtableAgreement(R', NRR); } else { reveal_HiddenInv(); NextInv_Set_NotADelegateStep(s, s', id, recv, out, rpkt); NondelegatingReadonlyStepPreservesRefinement(s, s', id, recv, out); reveal_HiddenRefinement(); } } else { reveal_HiddenRefinement(); reveal_HiddenInv(); assert HiddenRefinement(s)==HiddenRefinement(s'); } } lemma GetPreservesRefinement(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, out:set, rpkt:Packet) requires HiddenInv(s) && InvBasics(s); requires HiddenInv(s') && InvBasics(s'); requires SHT_Next(s, s'); requires SHT_NextPred(s, s', id, recv, out); requires id in AllHostIdentities(s); requires HiddenSHT_Next_and_SHT_NextPred(s, s', id, recv, out); requires rpkt in s.network && rpkt.msg.SingleMessage? && rpkt.msg.m.GetRequest? && NextGetRequest(s.hosts[id], s'.hosts[id], rpkt, out); requires InvRefinementNormalized(s); requires !SpontaneouslyRetransmit(s.hosts[id], s'.hosts[id], out); requires !DelegationPacket(s.hosts[id].receivedPacket); ensures if DelegateForKey(s.hosts[id].delegationMap, rpkt.msg.m.k_getrequest)==id then Get(HiddenRefinement(s), HiddenRefinement(s'), rpkt.msg.m.k_getrequest, HashtableLookup(s.hosts[id].h, rpkt.msg.m.k_getrequest)) else HiddenRefinement(s)==HiddenRefinement(s'); ensures InvRefinementNormalized(s'); { reveal_HiddenInv(); NextInv_Get_NotADelegateStep(s, s', id, recv, out, rpkt); NondelegatingReadonlyStepPreservesRefinement(s, s', id, recv, out); var k := rpkt.msg.m.k_getrequest; var v := HashtableLookup(s.hosts[id].h, rpkt.msg.m.k_getrequest); reveal_HiddenRefinement(); assert HiddenRefinement(s)==HiddenRefinement(s'); if (DelegateForKey(s.hosts[id].delegationMap, rpkt.msg.m.k_getrequest)==id) { LookupInRefinement(s, k); forall () ensures FindHashTable(s,k) == s.hosts[id].h; { reveal_EachKeyClaimedInExactlyOnePlace(); assert HostClaimsKey(s.hosts[id], k); // OBSERVE trigger assert NoInFlightPacketClaimsKey(s, k); // OBSERVE trigger } } } lemma NextDelegatePreservesRefinement_rpkt(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, out:set, rpkt:Packet, k:Key) requires HiddenInv(s) && InvBasics(s); requires HiddenInv(s') && InvBasics(s'); requires SHT_Next(s, s'); requires SHT_NextPred(s, s', id, recv, out); requires id in AllHostIdentities(s); requires HiddenSHT_Next_and_SHT_NextPred(s, s', id, recv, out); requires Some(rpkt) == s.hosts[id].receivedPacket; requires s'.hosts[id].receivedPacket.None?; requires rpkt in s.network && rpkt.msg.SingleMessage? && rpkt.msg.m.Delegate? && NextDelegate(s.hosts[id], s'.hosts[id], rpkt, out); requires InvRefinementNormalized(s); requires InFlightPacketClaimsKey(s,rpkt,k); ensures HashtableLookup(HiddenRefinement(s),k) == HashtableLookup(HiddenRefinement(s'),k); ensures k in HiddenRefinement(s') ==> HashtableLookup(HiddenRefinement(s'), k) != ValueAbsent(); { forall () ensures InvConstants(s) && InvConstants(s') { reveal_HiddenInv(); } // Now s.hosts[id] claims key. assert HostClaimsKey(s'.hosts[id], k); forall () ensures EachKeyClaimedInExactlyOnePlace(s) && BufferedPacketsInv(s) && EachKeyClaimedInExactlyOnePlace(s') && BufferedPacketsInv(s'); { reveal_HiddenInv(); } calc { HashtableLookup(HiddenRefinement(s), k); { reveal_HiddenRefinement(); } HashtableLookup(Refinement(s).ht, k); { LookupInRefinement(s,k); } HashtableLookup(FindHashTable(s,k), k); { reveal_HiddenInv(); reveal_EachKeyClaimedInExactlyOnePlace(); PacketClaimsKey_forces_FindHashTable(s, rpkt, k); } HashtableLookup(rpkt.msg.m.h, k); } calc { HashtableLookup(rpkt.msg.m.h, k); { forall () ensures !HostClaimsKey(s.hosts[id], k); { reveal_HiddenInv(); reveal_EachKeyClaimedInExactlyOnePlace(); assert NoHostClaimsKey(s, k); // OBSERVE trigger } forall () ensures HostsStoreOnlyOwnedKeys(s); { reveal_HiddenInv(); } // if (k in BulkUpdateHashtable(s.hosts[id].h, rpkt.msg.m.h)) { // assert HostsStoreOnlyOwnedKeys(s); // assert !(k in s.hosts[id].h); // assert k in rpkt.msg.m.h; // assert rpkt.msg.m.h[k] == BulkUpdateHashtable(s.hosts[id].h, rpkt.msg.m.h)[k]; // } else { // assert !(k in s.hosts[id].h); // } } HashtableLookup(BulkUpdateHashtable(s.hosts[id].h, rpkt.msg.m.range, rpkt.msg.m.h), k); HashtableLookup(s'.hosts[id].h, k); } assert !BufferedPacketClaimsKey(s'.hosts[id], k); calc { id; { reveal_HiddenInv(); reveal_EachKeyClaimedInExactlyOnePlace(); assert UniqueHostClaimsKey(s', k); assert OnlyOneHostClaimsKey(s',k); } TheHostThatClaimsKey(s', k); } calc { HashtableLookup(s'.hosts[id].h, k); HashtableLookup(FindHostHashTable(s',k), k); { reveal_HiddenInv(); HostClaimsKey_forces_FindHashTable(s', id, k); } HashtableLookup(FindHashTable(s',k), k); { LookupInRefinement(s',k); } HashtableLookup(Refinement(s').ht, k); { reveal_HiddenRefinement(); } HashtableLookup(HiddenRefinement(s'), k); } forall () ensures DelegationMessagesCarryNoEmptyValues(s); { reveal_HiddenInv(); } assert k in rpkt.msg.m.h ==> HashtableLookup(rpkt.msg.m.h, k) != ValueAbsent(); // OBSERVE trigger } lemma NextDelegatePreservesRefinement_upkt(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, out:set, rpkt:Packet, k:Key, upkt:Packet) requires HiddenInv(s) && InvBasics(s); requires HiddenInv(s') && InvBasics(s'); requires SHT_Next(s, s'); requires SHT_NextPred(s, s', id, recv, out); requires id in AllHostIdentities(s); requires HiddenSHT_Next_and_SHT_NextPred(s, s', id, recv, out); requires rpkt in s.network && rpkt.msg.SingleMessage? && rpkt.msg.m.Delegate? && NextDelegate(s.hosts[id], s'.hosts[id], rpkt, out); requires Some(rpkt) == s.hosts[id].receivedPacket; requires s'.hosts[id].receivedPacket.None?; requires InvRefinementNormalized(s); requires !InFlightPacketClaimsKey(s, rpkt, k); requires InFlightPacketClaimsKey(s, upkt, k); ensures HashtableLookup(HiddenRefinement(s),k) == HashtableLookup(HiddenRefinement(s'),k); ensures k in HiddenRefinement(s') ==> HashtableLookup(HiddenRefinement(s'), k) != ValueAbsent(); { assert rpkt!=upkt; assert InFlightPacketClaimsKey(s', upkt, k); forall () ensures EachKeyClaimedInExactlyOnePlace(s) && BufferedPacketsInv(s) && EachKeyClaimedInExactlyOnePlace(s') && BufferedPacketsInv(s'); { reveal_HiddenInv(); } forall () ensures InvConstants(s) && InvConstants(s') { reveal_HiddenInv(); } calc { HashtableLookup(HiddenRefinement(s), k); { reveal_HiddenRefinement(); } HashtableLookup(Refinement(s).ht, k); { LookupInRefinement(s,k); } HashtableLookup(FindHashTable(s,k), k); { reveal_HiddenInv(); reveal_EachKeyClaimedInExactlyOnePlace(); PacketClaimsKey_forces_FindHashTable(s, upkt, k); } HashtableLookup(upkt.msg.m.h, k); } calc { HashtableLookup(upkt.msg.m.h, k); { reveal_HiddenInv(); reveal_EachKeyClaimedInExactlyOnePlace(); PacketClaimsKey_forces_FindHashTable(s', upkt, k); } HashtableLookup(FindHashTable(s',k), k); { LookupInRefinement(s',k); } HashtableLookup(Refinement(s').ht, k); { reveal_HiddenRefinement(); } HashtableLookup(HiddenRefinement(s'), k); } forall () ensures DelegationMessagesCarryNoEmptyValues(s); { reveal_HiddenInv(); } assert k in upkt.msg.m.h ==> HashtableLookup(upkt.msg.m.h, k) != ValueAbsent(); } lemma NextDelegatePreservesRefinement_host(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, out:set, rpkt:Packet, k:Key) requires HiddenInv(s) && InvBasics(s); requires HiddenInv(s') && InvBasics(s'); requires SHT_Next(s, s'); requires SHT_NextPred(s, s', id, recv, out); requires id in AllHostIdentities(s); requires HiddenSHT_Next_and_SHT_NextPred(s, s', id, recv, out); requires Some(rpkt) == s.hosts[id].receivedPacket; requires rpkt in s.network && rpkt.msg.SingleMessage? && rpkt.msg.m.Delegate? && NextDelegate(s.hosts[id], s'.hosts[id], rpkt, out); requires Some(rpkt) == s.hosts[id].receivedPacket; requires s'.hosts[id].receivedPacket.None?; requires InvRefinementNormalized(s); requires !InFlightPacketClaimsKey(s, rpkt, k); requires !(UniqueInFlightPacketClaimsKey(s, k) && NoHostClaimsKey(s, k)); ensures HashtableLookup(HiddenRefinement(s),k) == HashtableLookup(HiddenRefinement(s'),k); ensures k in HiddenRefinement(s') ==> HashtableLookup(HiddenRefinement(s'), k) != ValueAbsent(); { forall () ensures NoInFlightPacketClaimsKey(s, k) && UniqueHostClaimsKey(s, k); { reveal_HiddenInv(); reveal_EachKeyClaimedInExactlyOnePlace(); } forall () ensures EachKeyClaimedInExactlyOnePlace(s) && BufferedPacketsInv(s) && EachKeyClaimedInExactlyOnePlace(s') && BufferedPacketsInv(s'); { reveal_HiddenInv(); } forall () ensures InvConstants(s) && InvConstants(s') { reveal_HiddenInv(); } var kid :| kid in AllHostIdentities(s) && HostClaimsKey(s.hosts[kid], k); assert HostClaimsKey(s'.hosts[kid], k); calc { HashtableLookup(HiddenRefinement(s), k); { reveal_HiddenRefinement(); } HashtableLookup(Refinement(s).ht, k); { LookupInRefinement(s,k); } HashtableLookup(FindHashTable(s,k), k); { reveal_HiddenInv(); HostClaimsKey_forces_FindHashTable(s, kid, k); } HashtableLookup(FindHostHashTable(s,k), k); } forall () ensures DelegationMessagesCarryOnlyClaimedKeys(s); { reveal_HiddenInv(); } if (kid==id && rpkt.src in AllHostIdentities(s)) { assert BulkUpdateHashtable(s.hosts[kid].h, rpkt.msg.m.range, rpkt.msg.m.h) == s'.hosts[kid].h; // OBSERVE trigger } // assert HashtableLookup(s.hosts[kid].h, k) == HashtableLookup(s'.hosts[kid].h, k); calc { HashtableLookup(FindHostHashTable(s',k), k); { reveal_HiddenInv(); HostClaimsKey_forces_FindHashTable(s', kid, k); } HashtableLookup(FindHashTable(s',k), k); { LookupInRefinement(s',k); } HashtableLookup(Refinement(s').ht, k); { reveal_HiddenRefinement(); } HashtableLookup(HiddenRefinement(s'), k); } forall () ensures NoHostsStoreEmptyValues(s) { reveal_HiddenInv(); } assert k in s.hosts[kid].h ==> HashtableLookup(s.hosts[kid].h, k) != ValueAbsent(); // OBSERVE trigger if kid == id { if BufferedPacketClaimsKey(s.hosts[kid], k) { calc { HashtableLookup(HiddenRefinement(s),k); HashtableLookup(FindHostHashTable(s,k), k); HashtableLookup(s.hosts[kid].receivedPacket.v.msg.m.h, k); HashtableLookup(s'.hosts[kid].h, k); HashtableLookup(HiddenRefinement(s'), k); } } else { calc { HashtableLookup(HiddenRefinement(s),k); HashtableLookup(s.hosts[kid].h, k); HashtableLookup(s'.hosts[kid].h, k); HashtableLookup(HiddenRefinement(s'), k); } } } else { calc { kid; { reveal_HiddenInv(); reveal_EachKeyClaimedInExactlyOnePlace(); assert UniqueHostClaimsKey(s', k); assert OnlyOneHostClaimsKey(s',k); } TheHostThatClaimsKey(s', k); } calc { HashtableLookup(HiddenRefinement(s),k); HashtableLookup(FindHostHashTable(s,k), k); HashtableLookup(FindHostHashTable(s',k), k); HashtableLookup(HiddenRefinement(s'), k); } } HashtableLookup_implies_HashtableLookup_one_key(HiddenRefinement(s), HiddenRefinement(s'), k); } lemma NextDelegatePreservesRefinement_k(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, out:set, rpkt:Packet, k:Key) requires HiddenInv(s) && InvBasics(s); requires HiddenInv(s') && InvBasics(s'); requires SHT_Next(s, s'); requires SHT_NextPred(s, s', id, recv, out); requires id in AllHostIdentities(s); requires HiddenSHT_Next_and_SHT_NextPred(s, s', id, recv, out); requires Some(rpkt) == s.hosts[id].receivedPacket; requires s'.hosts[id].receivedPacket.None?; requires rpkt in s.network && rpkt.msg.SingleMessage? && rpkt.msg.m.Delegate? && NextDelegate(s.hosts[id], s'.hosts[id], rpkt, out); requires InvRefinementNormalized(s); ensures HashtableLookup(HiddenRefinement(s),k) == HashtableLookup(HiddenRefinement(s'),k); ensures k in HiddenRefinement(s') ==> HashtableLookup(HiddenRefinement(s'), k) != ValueAbsent(); { if (InFlightPacketClaimsKey(s,rpkt,k)) { NextDelegatePreservesRefinement_rpkt(s, s', id, recv, out, rpkt, k); } else if (UniqueInFlightPacketClaimsKey(s, k) && NoHostClaimsKey(s, k)) { var upkt :| InFlightPacketClaimsKey(s, upkt, k); NextDelegatePreservesRefinement_upkt(s, s', id, recv, out, rpkt, k, upkt); } else { NextDelegatePreservesRefinement_host(s, s', id, recv, out, rpkt, k); } } lemma NextDelegatePreservesRefinement_main(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, out:set, rpkt:Packet) requires HiddenInv(s) && InvBasics(s); requires HiddenInv(s') && InvBasics(s'); requires SHT_Next(s, s'); requires SHT_NextPred(s, s', id, recv, out); requires id in AllHostIdentities(s); requires HiddenSHT_Next_and_SHT_NextPred(s, s', id, recv, out); requires Some(rpkt) == s.hosts[id].receivedPacket; requires s'.hosts[id].receivedPacket.None?; requires rpkt in s.network && rpkt.msg.SingleMessage? && rpkt.msg.m.Delegate? && NextDelegate(s.hosts[id], s'.hosts[id], rpkt, out); requires InvRefinementNormalized(s); ensures HiddenRefinement(s)==HiddenRefinement(s'); ensures InvRefinementNormalized(s'); { var HR := HiddenRefinement(s); var HR' := HiddenRefinement(s'); forall k ensures HashtableLookup(HR, k) == HashtableLookup(HR', k); ensures k in HR ==> HashtableLookup(HR, k) != ValueAbsent(); ensures k in HR' ==> HashtableLookup(HR', k) != ValueAbsent(); { NextDelegatePreservesRefinement_k(s, s', id, recv, out, rpkt, k); reveal_HiddenRefinement(); } HashtableAgreement(HiddenRefinement(s), HiddenRefinement(s')); assert HashtableIsNormalized(HiddenRefinement(s')); // OBSERVE trigger reveal_HiddenRefinement(); assert InvRefinementNormalized(s'); } lemma NextShardPreservesRefinement_k(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, out:set, kr:KeyRange, recipient:NodeIdentity, sm:SingleMessage, k:Key, shouldSend:bool) requires HiddenInv(s) && InvBasics(s); requires HiddenInv(s') && InvBasics(s'); requires SHT_Next(s, s'); requires SHT_NextPred(s, s', id, recv, out); requires id in AllHostIdentities(s); requires HiddenSHT_Next_and_SHT_NextPred(s, s', id, recv, out); requires NextShard(s.hosts[id], s'.hosts[id], out, kr, recipient, sm, shouldSend); requires !DelegationPacket(s.hosts[id].receivedPacket); requires !DelegationPacket(s'.hosts[id].receivedPacket); requires InvRefinementNormalized(s); ensures HashtableLookup(HiddenRefinement(s),k) == HashtableLookup(HiddenRefinement(s'),k); ensures k in HiddenRefinement(s') ==> HashtableLookup(HiddenRefinement(s'), k) != ValueAbsent(); { forall () ensures NoHostsStoreEmptyValues(s); { reveal_HiddenInv(); } forall () ensures EachKeyClaimedInExactlyOnePlace(s) && BufferedPacketsInv(s) && EachKeyClaimedInExactlyOnePlace(s') && BufferedPacketsInv(s'); { reveal_HiddenInv(); } forall () ensures InvConstants(s) && InvConstants(s') { reveal_HiddenInv(); } if (HostClaimsKey(s.hosts[id], k)) { calc { id; { reveal_HiddenInv(); reveal_EachKeyClaimedInExactlyOnePlace(); assert UniqueHostClaimsKey(s, k); assert OnlyOneHostClaimsKey(s,k); } TheHostThatClaimsKey(s, k); } calc { HashtableLookup(HiddenRefinement(s),k); { reveal_HiddenRefinement(); } HashtableLookup(Refinement(s).ht, k); { LookupInRefinement(s,k); } HashtableLookup(FindHashTable(s,k), k); { reveal_HiddenInv(); HostClaimsKey_forces_FindHashTable(s, id, k); } HashtableLookup(FindHostHashTable(s,k), k); HashtableLookup(s.hosts[id].h, k); } if DelegateForKey(s.hosts[id].delegationMap, k)==s.hosts[id].me { if (KeyRangeContains(kr, KeyPlus(k))) { var spkt := Packet(recipient, s.hosts[id].me, sm); assert k in s.hosts[id].h ==> HashtableLookup(s.hosts[id].h, k) != ValueAbsent(); if shouldSend { calc { HashtableLookup(spkt.msg.m.h, k); { reveal_HiddenInv(); reveal_EachKeyClaimedInExactlyOnePlace(); assert ReceiverHasNotCanceledUnsentSeqno(s, spkt.dst, spkt.src, spkt.msg.seqno); // OBSERVE trigger assert InFlightPacketClaimsKey(s',spkt,k); // OBSERVE trigger PacketClaimsKey_forces_FindHashTable(s', spkt, k); } HashtableLookup(FindHashTable(s',k), k); { LookupInRefinement(s',k); } HashtableLookup(Refinement(s').ht, k); { reveal_HiddenRefinement(); } HashtableLookup(HiddenRefinement(s'), k); } } else { calc { HashtableLookup(HiddenRefinement(s), k); { reveal_HiddenRefinement(); LookupInRefinement(s,k); } HashtableLookup(FindHashTable(s, k), k); calc { FindHashTable(s, k); { reveal_HiddenInv(); reveal_EachKeyClaimedInExactlyOnePlace(); assert HostClaimsKey(s.hosts[id], k); assert HostClaimsKey(s'.hosts[id], k); assert NoInFlightPacketClaimsKey(s, k); // OBSERVE assert NoInFlightPacketClaimsKey(s', k); // OBSERVE (needed for the next two lines) assert !(exists pkt :: InFlightPacketClaimsKey(s,pkt,k)); assert !(exists pkt :: InFlightPacketClaimsKey(s',pkt,k)); } FindHashTable(s',k); } HashtableLookup(FindHashTable(s',k), k); { LookupInRefinement(s',k); } HashtableLookup(Refinement(s').ht, k); { reveal_HiddenRefinement(); } HashtableLookup(HiddenRefinement(s'), k); } } assert HashtableLookup(HiddenRefinement(s),k) == HashtableLookup(HiddenRefinement(s'),k); } else { assert HostClaimsKey(s'.hosts[id], k); forall pkt ensures !InFlightPacketClaimsKey(s',pkt,k); { reveal_EachKeyClaimedInExactlyOnePlace(); assert UniqueHostClaimsKey(s', k); assert NoInFlightPacketClaimsKey(s', k); assert !InFlightPacketClaimsKey(s', pkt, k); } assert !BufferedPacketClaimsKey(s'.hosts[id], k); calc { id; { reveal_HiddenInv(); reveal_EachKeyClaimedInExactlyOnePlace(); assert UniqueHostClaimsKey(s', k); assert OnlyOneHostClaimsKey(s',k); } TheHostThatClaimsKey(s', k); } calc { HashtableLookup(s'.hosts[id].h, k); HashtableLookup(FindHostHashTable(s',k), k); { reveal_HiddenInv(); HostClaimsKey_forces_FindHashTable(s', id, k); } HashtableLookup(FindHashTable(s',k), k); { LookupInRefinement(s',k); } HashtableLookup(Refinement(s').ht, k); { reveal_HiddenRefinement(); } HashtableLookup(HiddenRefinement(s'), k); } assert HashtableLookup(s.hosts[id].h, k) == HashtableLookup(s'.hosts[id].h, k); // OBSERVE witness assert HashtableLookup(HiddenRefinement(s),k) == HashtableLookup(HiddenRefinement(s'),k); } assert HashtableLookup(HiddenRefinement(s),k) == HashtableLookup(HiddenRefinement(s'),k); } else { assert BufferedPacketClaimsKey(s.hosts[id], k); assert false; } } else if (UniqueInFlightPacketClaimsKey(s, k) && NoHostClaimsKey(s, k)) { var upkt :| InFlightPacketClaimsKey(s, upkt, k); calc { HashtableLookup(HiddenRefinement(s), k); { reveal_HiddenRefinement(); } HashtableLookup(Refinement(s).ht, k); { LookupInRefinement(s,k); } HashtableLookup(FindHashTable(s,k), k); { reveal_HiddenInv(); reveal_EachKeyClaimedInExactlyOnePlace(); PacketClaimsKey_forces_FindHashTable(s, upkt, k); } HashtableLookup(upkt.msg.m.h, k); } calc { HashtableLookup(upkt.msg.m.h, k); { reveal_HiddenInv(); reveal_EachKeyClaimedInExactlyOnePlace(); PacketClaimsKey_forces_FindHashTable(s', upkt, k); } HashtableLookup(FindHashTable(s',k), k); { LookupInRefinement(s',k); } HashtableLookup(Refinement(s').ht, k); { reveal_HiddenRefinement(); } HashtableLookup(HiddenRefinement(s'), k); } forall () ensures DelegationMessagesCarryNoEmptyValues(s); { reveal_HiddenInv(); } assert HashtableLookup(HiddenRefinement(s),k) == HashtableLookup(HiddenRefinement(s'),k); } else { forall () ensures UniqueHostClaimsKey(s, k); { reveal_HiddenInv(); reveal_EachKeyClaimedInExactlyOnePlace(); } var kid :| kid in AllHostIdentities(s) && HostClaimsKey(s.hosts[kid], k); assert kid != id; calc { HashtableLookup(HiddenRefinement(s),k); { reveal_HiddenRefinement(); } HashtableLookup(Refinement(s).ht, k); { LookupInRefinement(s,k); } HashtableLookup(FindHashTable(s,k), k); { reveal_HiddenInv(); HostClaimsKey_forces_FindHashTable(s, kid, k); } HashtableLookup(FindHostHashTable(s,k), k); //HashtableLookup(s.hosts[kid].h, k); } calc { //HashtableLookup(s'.hosts[kid].h, k); HashtableLookup(FindHostHashTable(s',k), k); { reveal_HiddenInv(); HostClaimsKey_forces_FindHashTable(s', kid, k); } HashtableLookup(FindHashTable(s',k), k); { LookupInRefinement(s',k); } HashtableLookup(Refinement(s').ht, k); { reveal_HiddenRefinement(); } HashtableLookup(HiddenRefinement(s'), k); } assert HashtableLookup(HiddenRefinement(s),k) == HashtableLookup(HiddenRefinement(s'),k); } reveal_HiddenRefinement(); } // I had to pull this forall out into a lonely method to avoid the // triggerstorm around the forall block, which doesn't admit explicit // triggers. lemma NextShardPreservesRefinement_JustAgreement(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, out:set, kr:KeyRange, recipient:NodeIdentity, sm:SingleMessage, shouldSend:bool) requires HiddenInv(s) && InvBasics(s); requires HiddenInv(s') && InvBasics(s'); requires NoConfigChanged(s, s'); requires id in AllHostIdentities(s); requires HiddenSHT_Next_and_SHT_NextPred(s, s', id, recv, out); requires NextShard(s.hosts[id], s'.hosts[id], out, kr, recipient, sm, shouldSend); requires !DelegationPacket(s.hosts[id].receivedPacket); requires s'.hosts[id].receivedPacket.None?; requires HiddenInvRefinementNormalized(s); ensures HashTablesAgreeUpToNormalization(HiddenRefinement(s), HiddenRefinement(s')); { forall k ensures HashtableLookup(HiddenRefinement(s), k) == HashtableLookup(HiddenRefinement(s'), k); { reveal_HiddenInvRefinementNormalized(); reveal_HiddenSHT_Next_and_SHT_NextPred(); NextShardPreservesRefinement_k(s, s', id, recv, out, kr, recipient, sm, k, shouldSend); } } lemma NextShardPreservesRefinement_main(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, out:set, kr:KeyRange, recipient:NodeIdentity, sm:SingleMessage, shouldSend:bool) requires HiddenInv(s) && InvBasics(s); requires HiddenInv(s') && InvBasics(s'); requires id in AllHostIdentities(s); requires HiddenSHT_Next_and_SHT_NextPred(s, s', id, recv, out); requires NoConfigChanged(s, s'); requires NextShard(s.hosts[id], s'.hosts[id], out, kr, recipient, sm, shouldSend); requires !DelegationPacket(s.hosts[id].receivedPacket); requires s'.hosts[id].receivedPacket.None?; requires HiddenInvRefinementNormalized(s); ensures HiddenRefinement(s)==HiddenRefinement(s'); ensures InvRefinementNormalized(s'); { var HR := HiddenRefinement(s); var HR' := HiddenRefinement(s'); NextShardPreservesRefinement_JustAgreement(s, s', id, recv, out, kr, recipient, sm, shouldSend); forall ensures HashtableIsNormalized(HR); { reveal_HiddenInvRefinementNormalized(); reveal_HiddenRefinement(); } forall k ensures k in HR' ==> HashtableLookup(HR', k) != ValueAbsent(); { reveal_HiddenInvRefinementNormalized(); reveal_HiddenSHT_Next_and_SHT_NextPred(); NextShardPreservesRefinement_k(s, s', id, recv, out, kr, recipient, sm, k, shouldSend); reveal_HiddenRefinement(); } assert HashtableIsNormalized(HiddenRefinement(s')); // OBSERVE trigger HashtableAgreement(HiddenRefinement(s), HiddenRefinement(s')); reveal_HiddenRefinement(); assert InvRefinementNormalized(s'); } lemma {:timeLimitMultiplier 12} Next_Process_Message_Refines(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, out:set) requires Inv(s); requires MapComplete(s'); requires SHT_Next(s, s'); requires SHT_NextPred(s, s', id, recv, out); requires InvRefinementNormalized(s); requires ShouldProcessReceivedMessage(s.hosts[id]); requires s.hosts[id].receivedPacket.v in s.network; requires s'.hosts[id].receivedPacket.None?; requires Process_Message(s.hosts[id], s'.hosts[id], out); requires !SpontaneouslyRetransmit(s.hosts[id], s'.hosts[id], out); ensures Inv(s'); ensures InvRefinementNormalized(s'); ensures Service_Next(Refinement(s), Refinement(s')) || ServiceStutter(Refinement(s), Refinement(s')); { NextInv(s, s'); var R := Refinement(s); var R' := Refinement(s'); var h := s.hosts[id]; var h' := s'.hosts[id]; var rpkt := s.hosts[id].receivedPacket.v; reveal_HiddenInv(); reveal_HiddenSHT_Next_and_SHT_NextPred(); if NextGetRequest(h, h', rpkt, out) { var k := rpkt.msg.m.k_getrequest; GetPreservesRefinement(s, s', id, recv, out, rpkt); var v := HashtableLookup(h.h, k); var req := AppGetRequest(rpkt.msg.seqno, k); reveal_HiddenRefinement(); var owner := DelegateForKey(h.delegationMap, k); //assume false; var sm:SingleMessage,m,b :| NextGetRequest_Reply(h, h', rpkt.src, rpkt.msg.seqno, k, sm, m, out, b); if(owner == h.me && b) { //assert Get(R.ht, R'.ht, k, v); //var reply := AppReply(rpkt.src, rpkt.msg.seqno, k, v); var p :| p in out; assert p in s'.network && p.msg.SingleMessage? && p.msg.m.Reply?; var reply := AppReply(p.msg.seqno, p.msg.m.k_reply, p.msg.m.v); assert reply in R'.replies; assert h'.receivedRequests[|h'.receivedRequests|-1] == req; assert h'.receivedRequests[.. |h'.receivedRequests|-1] == h.receivedRequests; assert R'.requests == R.requests + { req }; assert R'.replies == R.replies + { reply }; assert Service_Next_ServerExecutesRequest(Refinement(s), Refinement(s'), req, reply); assert Service_Next(Refinement(s), Refinement(s')); } else { //assert HashtableStutter(R.ht, R'.ht); assert Refinement(s).ht == Refinement(s').ht; assert Refinement(s).requests == Refinement(s').requests; assert Refinement(s).replies == Refinement(s').replies; assert ServiceStutter(Refinement(s), Refinement(s')); } //assert Refinement(s').requests == Refinement(s).requests + { req }; } else if NextSetRequest(h, h', rpkt, out) { var sm:SingleMessage,m,b :| NextSetRequest_Complete(h, h', rpkt.src, rpkt.msg.seqno, rpkt.msg.m, sm, m, out, b); reveal_HiddenRefinement(); var k := rpkt.msg.m.k_setrequest; var ov := rpkt.msg.m.v_setrequest; var v := HashtableLookup(h.h, k); var req := AppSetRequest(rpkt.msg.seqno, k, ov); var owner := DelegateForKey(h.delegationMap, k); if(owner == h.me && ValidKey(rpkt.msg.m.k_setrequest) && ValidOptionalValue(rpkt.msg.m.v_setrequest) && b) { SetPreservesRefinement_main(s, s', id, recv, out, rpkt, sm, m); var p :| p in out; assert p in s'.network && p.msg.SingleMessage? && p.msg.m.Reply?; var reply := AppReply(p.msg.seqno, p.msg.m.k_reply, p.msg.m.v); assert reply in R'.replies; forall r | r in R'.requests ensures r in R.requests + { req }; { } forall r | r in R.requests + { req } ensures r in R'.requests; { assert h'.receivedRequests[|h'.receivedRequests|-1] == req; assert h'.receivedRequests[.. |h'.receivedRequests|-1] == h.receivedRequests; assert req in R'.requests; } assert R'.requests == R.requests + { req }; assert Service_Next_ServerExecutesRequest(R, R', req, reply); assert Service_Next(Refinement(s), Refinement(s')); } else { assert NotADelegateStep(s, s'); NondelegatingReadonlyStepPreservesRefinement(s, s', id, recv, out); assert Refinement(s).ht == Refinement(s').ht; assert Refinement(s).requests == Refinement(s').requests; assert Refinement(s).replies == Refinement(s').replies; assert ServiceStutter(Refinement(s), Refinement(s')); } } else if NextDelegate(h, h', rpkt, out) { //assume false; NextDelegatePreservesRefinement_main(s, s', id, recv, out, rpkt); reveal_HiddenRefinement(); assert Refinement(s).ht == Refinement(s').ht; assert Refinement(s).requests == Refinement(s').requests; assert Refinement(s).replies == Refinement(s').replies; assert ServiceStutter(Refinement(s), Refinement(s')); assert ServiceStutter(R, R'); } else if NextShard_Wrapper(h, h', rpkt, out) { reveal_HiddenInvRefinementNormalized(); assert HiddenInvRefinementNormalized(s); reveal_HiddenRefinement(); if ( rpkt.msg.m.recipient == h.me || !ValidKeyRange(rpkt.msg.m.kr) || !ValidPhysicalAddress(rpkt.msg.m.recipient) || EmptyKeyRange(rpkt.msg.m.kr) || rpkt.msg.m.recipient !in h.constants.hostIds || !DelegateForKeyRangeIsHost(h.delegationMap, rpkt.msg.m.kr, h.me) || |ExtractRange(h.h, rpkt.msg.m.kr)| >= max_hashtable_size()) { //assume false; NextInv_Process_Boring_Message(s, s', id, recv, out); NondelegatingReadonlyStepPreservesRefinement(s, s', id, recv, out); assert s.network == s'.network; // OBSERVE (extensionality?) assert HashtableStutter(R.ht, R'.ht); assert Refinement(s).requests == Refinement(s').requests; assert Refinement(s).replies == Refinement(s').replies; } else { var sm,b :| NextShard(h, h', out, rpkt.msg.m.kr, rpkt.msg.m.recipient, sm, b); NextShardPreservesRefinement_main(s, s', id, recv, out, rpkt.msg.m.kr, rpkt.msg.m.recipient, sm, b); assert HashtableStutter(R.ht, R'.ht); assert Refinement(s).requests == Refinement(s').requests; assert Refinement(s).replies == Refinement(s').replies; assert ServiceStutter(R, R'); } } else if NextReply(h, h', rpkt, out) { NextInv_Process_Boring_Message(s, s', id, recv, out); NondelegatingReadonlyStepPreservesRefinement(s, s', id, recv, out); assert Inv(s'); assert Refinement(s).requests == Refinement(s').requests; assert Refinement(s).replies == Refinement(s').replies; assert ServiceStutter(R, R'); } else if NextRedirect(h, h', rpkt, out) { NextInv_Process_Boring_Message(s, s', id, recv, out); assert NotADelegateStep(s, s'); NondelegatingReadonlyStepPreservesRefinement(s, s', id, recv, out); assert Inv(s'); assert Refinement(s).requests == Refinement(s').requests; assert Refinement(s).replies == Refinement(s').replies; assert ServiceStutter(R, R'); } else { assert false; } } /* lemma ReceiveBoringPacketRefines(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, out:set) requires Inv(s); requires MapComplete(s'); requires SHT_Next(s, s'); requires SHT_NextPred(s, s', id, recv, out); requires InvRefinementNormalized(s); requires ProcessReceivedPacket(s.hosts[id], s'.hosts[id], out); requires s.hosts[id].receivedPacket.Some?; requires !NewSingleMessage(s.hosts[id].sd, s.hosts[id].receivedPacket.v); ensures Inv(s'); ensures InvRefinementNormalized(s'); ensures HashtableNext(Refinement(s).ht, Refinement(s')) || HashtableStutter(Refinement(s).ht, Refinement(s')); { NextInv_ProcessReceivedPacket_BoringPacket(s, s', id, recv, out); var h := s.hosts[id]; var h' := s'.hosts[id]; assert out == {}; assert h' == h.(receivedPacket := None); reveal_HiddenInv(); NondelegatingReadonlyStepPreservesRefinement(s, s', id, recv, out); } */ lemma {:timeLimitMultiplier 24} ReceivePacketRefines(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, rpkt:Packet, out:set, ack:Packet) requires Inv(s); requires MapComplete(s'); requires SHT_Next(s, s'); requires SHT_NextPred(s, s', id, recv, out); requires InvRefinementNormalized(s); requires rpkt in recv; requires ReceivePacket(s.hosts[id], s'.hosts[id], rpkt, out, ack); ensures Inv(s'); ensures InvRefinementNormalized(s'); ensures Service_Next(Refinement(s), Refinement(s')) || ServiceStutter(Refinement(s), Refinement(s')); { NextInv_ReceivePacket(s, s', id, recv, rpkt, out, ack); var h := s.hosts[id]; var h' := s'.hosts[id]; if h.receivedPacket.None? { assert ReceiveSingleMessage(h.sd, h'.sd, rpkt, ack, out); reveal_HiddenInv(); if NewSingleMessage(h.sd, rpkt) { if NotADelegateStep(s, s') { NondelegatingReadonlyStepPreservesRefinement(s, s', id, recv, out); assert Refinement(s).requests == Refinement(s').requests; assert Refinement(s).replies == Refinement(s').replies; assert ServiceStutter(Refinement(s), Refinement(s')); } else { reveal_RefinedDomain(); forall k ensures k in RefinedDomain(s') <==> k in RefinedDomain(s); ensures FindHashTable(s,k)[k] == FindHashTable(s',k)[k]; { reveal_EachKeyClaimedInExactlyOnePlace(); if UniqueInFlightPacketClaimsKey(s, k) { assert FindHashTable(s,k) == ThePacketThatClaimsKey(s,k).msg.m.h; assert UniqueInFlightPacketClaimsKey(s', k) || UniqueHostClaimsKey(s', k); if UniqueInFlightPacketClaimsKey(s', k) { var pkt := UniquePacketClaimsKey_forces_FindHashTable(s, k); var pkt' := UniquePacketClaimsKey_forces_FindHashTable(s', k); assert PacketInFlight(s, pkt'); assert InFlightPacketClaimsKey(s, pkt', k); assert pkt == pkt'; calc { FindHashTable(s,k); pkt.msg.m.h; pkt'.msg.m.h; FindHashTable(s',k); } assert k in RefinedDomain(s') <==> k in RefinedDomain(s); } else { var pkt := UniquePacketClaimsKey_forces_FindHashTable(s, k); assert UniqueHostClaimsKey(s', k); var i := HostClaimsKey_forces_FindHostHashTable(s', k); assert i == TheHostThatClaimsKey(s', k); if DelegateForKey(h.delegationMap, k) == h.me { assert HostClaimsKey(h, k); assert SomeHostClaimsKey(s, k); assert NoHostClaimsKey(s, k); assert false; } assert DelegateForKey(h'.delegationMap, k) != h'.me; assert BufferedPacketClaimsKey(s'.hosts[i], k); assert PacketInFlight(s, rpkt); assert InFlightPacketClaimsKey(s, rpkt, k); assert pkt == rpkt; calc { FindHashTable(s',k); FindHostHashTable(s', k); s'.hosts[i].receivedPacket.v.msg.m.h; rpkt.msg.m.h; pkt.msg.m.h; FindHashTable(s,k); } assert k in RefinedDomain(s') <==> k in RefinedDomain(s); } assert k in RefinedDomain(s') <==> k in RefinedDomain(s); } else { assert NoInFlightPacketClaimsKey(s, k) && UniqueHostClaimsKey(s, k); if SomePacketClaimsKey(s', k) { var p :| InFlightPacketClaimsKey(s', p, k); assert InFlightPacketClaimsKey(s, p, k); assert false; } assert NoInFlightPacketClaimsKey(s', k) && UniqueHostClaimsKey(s', k); var i := HostClaimsKey_forces_FindHostHashTable(s , k); var i' := HostClaimsKey_forces_FindHostHashTable(s', k); if i == id { assert !BufferedPacketClaimsKey(s.hosts[i], k); if BufferedPacketClaimsKey(s'.hosts[i], k) { assert InFlightPacketClaimsKey(s, s'.hosts[i].receivedPacket.v, k); assert false; } } calc { FindHashTable(s',k); FindHostHashTable(s', k); { assert i == i'; } FindHostHashTable(s, k); FindHashTable(s,k); } assert k in RefinedDomain(s') <==> k in RefinedDomain(s); } } assert Refinement(s).ht == Refinement(s').ht; assert Refinement(s).requests == Refinement(s').requests; assert Refinement(s).replies == Refinement(s').replies; } } else { NondelegatingReadonlyStepPreservesRefinement(s, s', id, recv, out); assert Refinement(s).requests == Refinement(s').requests; assert Refinement(s).replies == Refinement(s').replies; assert ServiceStutter(Refinement(s), Refinement(s')); } } else { assert s.hosts == s'.hosts; // OBSERVE (extensionality) assert s.network == s'.network; // OBSERVE (extensionality?) assert s == s'; } } lemma ProcessReceivedPacketRefines(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, out:set) requires Inv(s); requires MapComplete(s'); requires SHT_Next(s, s'); requires SHT_NextPred(s, s', id, recv, out); requires InvRefinementNormalized(s); requires ProcessReceivedPacket(s.hosts[id], s'.hosts[id], out); requires !SpontaneouslyRetransmit(s.hosts[id], s'.hosts[id], out); ensures Inv(s'); ensures InvRefinementNormalized(s'); ensures Service_Next(Refinement(s), Refinement(s')) || ServiceStutter(Refinement(s), Refinement(s')); { NextInv_ProcessReceivedPacket(s, s', id, recv, out); var h := s.hosts[id]; var h' := s'.hosts[id]; if ShouldProcessReceivedMessage(h) { Next_Process_Message_Refines(s, s', id, recv, out); } else { assert s.hosts == s'.hosts; // OBSERVE (extensionality) assert s.network == s'.network; // OBSERVE (extensionality?) assert s == s'; } } lemma RetransmitRefines(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, out:set) requires Inv(s); requires SHT_MapsComplete(s); requires MapComplete(s'); requires NoConfigChanged(s, s'); requires SHT_Next(s, s'); requires SHT_NextPred(s, s', id, recv, out); requires InvRefinementNormalized(s); requires SpontaneouslyRetransmit(s.hosts[id], s'.hosts[id], out); ensures Inv(s'); ensures InvRefinementNormalized(s'); ensures Service_Next(Refinement(s), Refinement(s')) || ServiceStutter(Refinement(s), Refinement(s')); { reveal_UnAckedListInNetwork(); NextInv_SpontaneouslyRetransmit(s, s', id, recv, out); var R := Refinement(s); var R' := Refinement(s'); var h := s.hosts[id]; var h' := s'.hosts[id]; forall id',msg,dst | id' in AllHostIdentities(s) && msg in AckStateLookup(dst, s'.hosts[id'].sd.sendState).unAcked && NoAcksInUnAckedLists(s'.hosts[id'].sd) && dst == msg.dst ensures Packet(msg.dst, s'.hosts[id'].me, msg) in s'.network { var p := Packet(msg.dst, s'.hosts[id'].me, msg); if id' == id { assert msg in AckStateLookup(dst, s.hosts[id'].sd.sendState).unAcked; assert p in s'.network; } else { assert p in s'.network; } } assert forall id' :: id' in AllHostIdentities(s) ==> s.hosts[id'] == s'.hosts[id']; Lemma_EqualityConditionForMapsWithSameDomain(s.hosts, s'.hosts); // Proves the next line assert s.hosts == s'.hosts; forall p | p in out ensures p in s.network; { var dst, i :| dst in h.sd.sendState && 0 <= i < |h.sd.sendState[dst].unAcked| && h.sd.sendState[dst].unAcked[i].SingleMessage? && (var sm := h.sd.sendState[dst].unAcked[i]; p.dst == sm.dst && p.src == s.hosts[id].me && p.msg == sm); // Needed for the OBSERVE on the next line assert AckStateLookup(dst, h.sd.sendState) == h.sd.sendState[dst]; // OBSERVE assert UnAckedMsgForDst(h.sd, p.msg, p.dst); // OBSERVE } assert s.network == s'.network; assert s == s'; assert HashtableStutter(R.ht, R'.ht); } lemma {:timeLimitMultiplier 2} NextPredRefines(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, out:set) requires Inv(s); requires MapComplete(s'); requires SHT_Next(s, s'); requires SHT_NextPred(s, s', id, recv, out); requires InvRefinementNormalized(s); ensures Inv(s'); ensures InvRefinementNormalized(s'); ensures Service_Next(Refinement(s), Refinement(s')) || ServiceStutter(Refinement(s), Refinement(s')); { NextInv(s, s'); var R := Refinement(s); var R' := Refinement(s'); var h := s.hosts[id]; var h' := s'.hosts[id]; if (exists pkt, ack :: pkt in recv && ReceivePacket(h, h', pkt, out, ack)) { var pkt, ack :| pkt in recv && ReceivePacket(h, h', pkt, out, ack); ReceivePacketRefines(s, s', id, recv, pkt, out, ack); } else if SpontaneouslyRetransmit(h, h', out) { RetransmitRefines(s, s', id, recv, out); assert InvRefinementNormalized(s'); // OBSERVE trigger } else if ProcessReceivedPacket(h, h', out) { ProcessReceivedPacketRefines(s, s', id, recv, out); } } lemma {:timeLimitMultiplier 8} NextExternalRefines(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, out:set) requires Inv(s); requires MapComplete(s'); requires SHT_Next(s, s'); requires SHT_NextExternal(s, s', id, recv, out); requires InvRefinementNormalized(s); ensures Inv(s'); ensures InvRefinementNormalized(s'); ensures ServiceStutter(Refinement(s), Refinement(s')); { NextInv(s, s'); assert s.hosts == s'.hosts; // OBSERVE (extensionality) reveal_RefinedDomain(); assert AllHashTables(s) == AllHashTables(s'); forall h, k | h in AllHashTables(s) ensures FindHashTable(s,k) == FindHashTable(s',k); { reveal_EachKeyClaimedInExactlyOnePlace(); if exists pkt :: InFlightPacketClaimsKey(s,pkt,k) { var pkt := UniquePacketClaimsKey_forces_FindHashTable(s, k); assert InFlightPacketClaimsKey(s',pkt,k); assert !NoInFlightPacketClaimsKey(s', k); var pkt' := UniquePacketClaimsKey_forces_FindHashTable(s', k); assert pkt == pkt'; calc { FindHashTable(s,k); ThePacketThatClaimsKey(s,k).msg.m.h; ThePacketThatClaimsKey(s',k).msg.m.h; FindHashTable(s',k); } } else if exists id' :: id' in AllHostIdentities(s) && HostClaimsKey(s.hosts[id'], k) { var id' :| id' in AllHostIdentities(s) && HostClaimsKey(s.hosts[id'], k); assert id' in AllHostIdentities(s') && HostClaimsKey(s'.hosts[id'], k); var id_old := HostClaimsKey_forces_FindHostHashTable(s, k); var id_new := HostClaimsKey_forces_FindHostHashTable(s', k); assert UniqueHostClaimsKey(s', k); assert OnlyOneHostClaimsKey(s,k); assert OnlyOneHostClaimsKey(s',k); assert id_old == id_new; calc { FindHashTable(s,k); FindHostHashTable(s, k); FindHostHashTable(s', k); FindHashTable(s',k); } } else { assert UniqueInFlightPacketClaimsKey(s, k) || UniqueHostClaimsKey(s, k); assert SomePacketClaimsKey(s, k) || SomeHostClaimsKey(s, k); assert false; } } assert RefinedDomain(s) == RefinedDomain(s'); assert forall k :: k in RefinedDomain(s') ==> FindHashTable(s,k) == FindHashTable(s',k); assert Refinement(s).ht == Refinement(s').ht; assert Refinement(s).requests == Refinement(s').requests; assert Refinement(s).replies == Refinement(s').replies; assert Inv(s'); assert InvRefinementNormalized(s'); assert ServiceStutter(Refinement(s), Refinement(s')); } lemma NextRefinesService(s:SHT_State, s':SHT_State) requires Inv(s); requires MapComplete(s'); requires SHT_Next(s, s'); requires InvRefinementNormalized(s); ensures Inv(s'); ensures InvRefinementNormalized(s'); ensures Service_Next(Refinement(s), Refinement(s')) || ServiceStutter(Refinement(s), Refinement(s')); { NextInv(s, s'); if (exists id, recv, out :: SHT_NextPred(s, s', id, recv, out)) { var id, recv, out :| SHT_NextPred(s, s', id, recv, out); NextPredRefines(s, s', id, recv, out); } else if (exists id, recv, out :: SHT_NextExternal(s, s', id, recv, out)) { var id, recv, out :| SHT_NextExternal(s, s', id, recv, out); NextExternalRefines(s, s', id, recv, out); } else { assert false; // There should be no other cases } } /* predicate RequestImpliesPacket(s:SHT_State) { forall id :: id in AllHostIdentities(s) ==> } lemma NextRefinesService(s:SHT_State, s':SHT_State) requires Inv(s); requires MapComplete(s'); requires SHT_Next(s, s'); */ } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/SHT/RefinementProof/SHT.i.dfy ================================================ include "../Host.i.dfy" include "../Configuration.i.dfy" module SHT__SHT_i { import opened Collections__Maps2_s import opened SHT__Host_i import opened SHT__Configuration_i import opened Concrete_NodeIdentity_i`Spec import opened SHT__Network_i datatype SHT_State = SHT_State( config:SHTConfiguration, network:Network, hosts:map) predicate SHT_MapsComplete(s:SHT_State) { (forall id {:auto_trigger} :: id in s.config.hostIds <==> id in s.hosts) } predicate SHT_Init(c:SHTConfiguration, s:SHT_State) { SHT_MapsComplete(s) && WFSHTConfiguration(c) && s.config == c && Network_Init(s.network) && (forall nodeIndex :: 0 <= nodeIndex < |s.config.hostIds| ==> var id := s.config.hostIds[nodeIndex]; Host_Init(s.hosts[id], id, s.config.rootIdentity, s.config.hostIds, s.config.params)) } predicate SHT_NextPred(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, out:set) requires SHT_MapsComplete(s); requires SHT_MapsComplete(s'); { id in s.config.hostIds && s'.config == s.config && Network_Receive(s.network, id, recv) && Host_Next(s.hosts[id], s'.hosts[id], recv, out) && Network_Send(s.network, s'.network, id, out) // All other hosts are unchanged && (forall oid {:auto_trigger} :: oid in s.config.hostIds && oid!=id ==> s'.hosts[oid]==s.hosts[oid]) } predicate SHT_NextExternal(s:SHT_State, s':SHT_State, id:NodeIdentity, recv:set, out:set) requires SHT_MapsComplete(s); requires SHT_MapsComplete(s'); { id !in s.config.hostIds && s'.config == s.config && Network_Send(s.network, s'.network, id, out) // Hosts are unchanged && s'.hosts == s.hosts } predicate SHT_Next(s:SHT_State, s':SHT_State) { SHT_MapsComplete(s) && SHT_MapsComplete(s') && s'.config == s.config && mapdomain(s'.hosts) == mapdomain(s.hosts) && ((exists id, recv, out :: SHT_NextPred(s, s', id, recv, out)) ||(exists id, recv, out :: SHT_NextExternal(s, s', id, recv, out))) } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/SHT/SingleDelivery.i.dfy ================================================ include "SingleMessage.i.dfy" include "Network.i.dfy" include "Parameters.i.dfy" module SHT__SingleDelivery_i { import opened Concrete_NodeIdentity_i import opened SHT__Message_i import opened SHT__SingleMessage_i import opened SHT__Network_i import opened Protocol_Parameters_i // A module to ensure each message is delivered exactly once, // built by including sequence numbers in messages and recording // the highest received sequence number and the list of outstanding packets // Workaround for the fact that Dafny won't let us put nat into collection types, like TombstoneTable below newtype nat_t = i:int | 0 <= i // Highest sequence number we have received from each node type TombstoneTable = map // State about packets we've sent to each node datatype AckState = AckState(numPacketsAcked:nat, unAcked:seq>) type SendState = map> datatype SingleDeliveryAcct = SingleDeliveryAcct(receiveState:TombstoneTable, sendState:SendState) function TombstoneTableLookup(src:NodeIdentity, t:TombstoneTable) : nat { if src in t then t[src] as int else 0 } function AckStateLookup(src:NodeIdentity, sendState:SendState):AckState { if src in sendState then sendState[src] else AckState(0, []) } // Written as a function to avoid an exists in the client function SingleDelivery_Init() : SingleDeliveryAcct { SingleDeliveryAcct(map[], map[]) } predicate MessageNotReceived(s:SingleDeliveryAcct, src:NodeIdentity, sm:SingleMessage) { sm.SingleMessage? && sm.seqno > TombstoneTableLookup(src, s.receiveState) } predicate NewSingleMessage(s:SingleDeliveryAcct, pkt:Packet) { pkt.msg.SingleMessage? && var last_seqno := TombstoneTableLookup(pkt.src, s.receiveState); pkt.msg.seqno == last_seqno + 1 } // Remove all packets implicitly ack'ed by seqnoAcked from the list of unacknowledged packets function TruncateUnAckList(unAcked:seq>, seqnoAcked:nat) : seq> ensures forall m :: m in TruncateUnAckList(unAcked, seqnoAcked) ==> m in unAcked; { if |unAcked| > 0 && unAcked[0].SingleMessage? && unAcked[0].seqno <= seqnoAcked then TruncateUnAckList(unAcked[1..], seqnoAcked) else unAcked } predicate ReceiveAck(s:SingleDeliveryAcct, s':SingleDeliveryAcct, pkt:Packet, acks:set) requires pkt.msg.Ack?; { acks == {} && // We don't ack acks var oldAckState := AckStateLookup(pkt.src, s.sendState); if pkt.msg.ack_seqno > oldAckState.numPacketsAcked then var newAckState := oldAckState.(numPacketsAcked := pkt.msg.ack_seqno, unAcked := TruncateUnAckList(oldAckState.unAcked, pkt.msg.ack_seqno)); s' == s.(sendState := s.sendState[pkt.src := newAckState]) else s' == s } predicate ShouldAckSingleMessage(s:SingleDeliveryAcct, pkt:Packet) { pkt.msg.SingleMessage? && // Don't want to ack acks var last_seqno := TombstoneTableLookup(pkt.src, s.receiveState); pkt.msg.seqno <= last_seqno } predicate SendAck(s:SingleDeliveryAcct, pkt:Packet, ack:Packet, acks:set) requires ShouldAckSingleMessage(s, pkt); { ack.msg.Ack? && ack.msg.ack_seqno == pkt.msg.seqno && ack.src == pkt.dst && ack.dst == pkt.src && acks == { ack } } predicate MaybeAckPacket(s:SingleDeliveryAcct, pkt:Packet, ack:Packet, acks:set) { if ShouldAckSingleMessage(s, pkt) then SendAck(s, pkt, ack, acks) else acks == {} } predicate ReceiveRealPacket(s:SingleDeliveryAcct, s':SingleDeliveryAcct, pkt:Packet) requires pkt.msg.SingleMessage?; { if NewSingleMessage(s, pkt) then var last_seqno := TombstoneTableLookup(pkt.src, s.receiveState); // Mark it received s' == s.(receiveState := s.receiveState[pkt.src := (last_seqno + 1) as nat_t]) else s == s' } predicate UnAckedMsgForDst(s:SingleDeliveryAcct, msg:SingleMessage, dst:NodeIdentity) { dst in s.sendState && msg in s.sendState[dst].unAcked } function UnAckedMessages(s:SingleDeliveryAcct, src:NodeIdentity):set { set dst, i | dst in s.sendState && 0 <= i < |s.sendState[dst].unAcked| && s.sendState[dst].unAcked[i].SingleMessage? :: var sm := s.sendState[dst].unAcked[i]; Packet(sm.dst, src, sm) } // Partial actions // Client should ReceiveSingleMessage or ReceiveNoMessage predicate ReceiveSingleMessage(s:SingleDeliveryAcct, s':SingleDeliveryAcct, pkt:Packet, ack:Packet, acks:set) { match pkt.msg { case Ack(_) => ReceiveAck(s, s', pkt, acks) case SingleMessage(seqno, _, m) => ReceiveRealPacket(s, s', pkt) && MaybeAckPacket(s', pkt, ack, acks) case InvalidMessage => (s' == s && acks == {}) } } predicate ReceiveNoMessage(s:SingleDeliveryAcct, s':SingleDeliveryAcct) { s'.receiveState == s.receiveState } // Highest sequence number we've sent to dst function HighestSeqnoSent(s:SingleDeliveryAcct, dst:NodeIdentity) : nat { var ackState := AckStateLookup(dst, s.sendState); ackState.numPacketsAcked + |ackState.unAcked| } // Client should SendSingleMessage or SendNoMessage predicate SendSingleMessage(s:SingleDeliveryAcct, s':SingleDeliveryAcct, m:MT, sm:SingleMessage, params:Parameters, shouldSend:bool) { sm.SingleMessage? && sm.m == m && var oldAckState := AckStateLookup(sm.dst, s.sendState); var new_seqno := oldAckState.numPacketsAcked + |oldAckState.unAcked| + 1; if new_seqno > params.max_seqno then s' == s && !shouldSend // Packet shouldn't be sent if we exceed the maximum sequence number else (s' == s.(sendState := s.sendState[sm.dst := oldAckState.(unAcked := oldAckState.unAcked + [sm])]) && sm.seqno == new_seqno && shouldSend) } predicate SendNoMessage(s:SingleDeliveryAcct, s':SingleDeliveryAcct) { s'.sendState == s.sendState // UNCHANGED } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Protocol/SHT/SingleMessage.i.dfy ================================================ include "../Common/NodeIdentity.i.dfy" module SHT__SingleMessage_i { import opened Concrete_NodeIdentity_i`Spec // A type to ensure each message is delivered exactly once // Note that we send sequence numbers starting at 1 datatype SingleMessage = SingleMessage(seqno:nat, dst:NodeIdentity, m:MT) | Ack(ack_seqno:nat) // I got everything up to and including seqno | InvalidMessage() } ================================================ FILE: ironfleet/src/Dafny/Distributed/Services/Lock/.gitignore ================================================ Main.i.cs build/ ================================================ FILE: ironfleet/src/Dafny/Distributed/Services/Lock/AbstractService.s.dfy ================================================ include "../../Common/Framework/AbstractService.s.dfy" module AbstractServiceLock_s refines AbstractService_s { export Spec provides Native__Io_s, Environment_s, Native__NativeTypes_s provides ServiceState provides Service_Init, Service_Next, Service_Correspondence export All reveals * datatype ServiceState' = ServiceState'( hosts:set, history:seq ) type ServiceState = ServiceState' predicate Service_Init(s:ServiceState, serverAddresses:set) { s.hosts == serverAddresses && (exists e :: e in serverAddresses && s.history == [e]) } predicate Service_Next(s:ServiceState, s':ServiceState) { s'.hosts == s.hosts && (exists new_lock_holder :: new_lock_holder in s.hosts && s'.history == s.history + [new_lock_holder]) } function Uint64ToBytes(u:uint64) : seq { [( u/0x1000000_00000000) as byte, ((u/ 0x10000_00000000)%0x100) as byte, ((u/ 0x100_00000000)%0x100) as byte, ((u/ 0x1_00000000)%0x100) as byte, ((u/ 0x1000000)%0x100) as byte, ((u/ 0x10000)%0x100) as byte, ((u/ 0x100)%0x100) as byte, ( u %0x100) as byte] } function MarshallLockMsg(epoch:int) : seq { if 0 <= epoch < 0x1_0000_0000_0000_0000 then [ 0, 0, 0, 0, 0, 0, 0, 1] // MarshallMesssage_Request magic number + Uint64ToBytes(epoch as uint64) else [ 1 ] } predicate Service_Correspondence(concretePkts:set>>, serviceState:ServiceState) { forall p, epoch :: p in concretePkts && p.src in serviceState.hosts && p.dst in serviceState.hosts && p.msg == MarshallLockMsg(epoch) ==> 1 <= epoch <= |serviceState.history| && p.src == serviceState.history[epoch-1] } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Services/Lock/LockDistributedSystem.i.dfy ================================================ include "../../Impl/Lock/Host.i.dfy" include "../../Common/Framework/DistributedSystem.s.dfy" module Lock_DistributedSystem_i refines DistributedSystem_s { import H_s = Host_i`All } ================================================ FILE: ironfleet/src/Dafny/Distributed/Services/Lock/Main.i.dfy ================================================ include "../../Common/Framework/Main.s.dfy" include "../../Common/Native/Io.s.dfy" include "LockDistributedSystem.i.dfy" include "../../Common/Framework/Environment.s.dfy" include "../../Protocol/Common/NodeIdentity.i.dfy" include "../../Impl/Lock/PacketParsing.i.dfy" include "../../Impl/Lock/NetLock.i.dfy" include "../../Impl/Lock/Host.i.dfy" include "AbstractService.s.dfy" include "../../Protocol/Lock/RefinementProof/Refinement.i.dfy" include "../../Protocol/Lock/RefinementProof/RefinementProof.i.dfy" include "Marshall.i.dfy" module Main_i refines Main_s { import opened DS_s = Lock_DistributedSystem_i import opened Environment_s import opened Types_i import opened Concrete_NodeIdentity_i import opened PacketParsing_i import opened NetLock_i import opened AS_s = AbstractServiceLock_s`All import opened Protocol_Node_i import opened Refinement_i import opened RefinementProof_i import opened MarshallProof_i import opened DistributedSystem_i import opened DS_s.H_s import opened Common__Util_i import opened Common__GenericMarshalling_i import opened Message_i import opened Collections__Sets_i import opened Common__SeqIsUnique_i import opened Common__SeqIsUniqueDef_i import opened Impl_Node_i export provides DS_s, Native__Io_s, Native__NativeTypes_s provides IronfleetMain predicate IsValidBehavior(config:ConcreteConfiguration, db:seq) reads *; { |db| > 0 && DS_Init(db[0], config) && forall i {:trigger DS_Next(db[i], db[i+1])} :: 0 <= i < |db| - 1 ==> DS_Next(db[i], db[i+1]) } predicate IsValidBehaviorLs(config:ConcreteConfiguration, db:seq) reads *; { |db| > 0 && LS_Init(db[0], config) && forall i {:trigger LS_Next(db[i], db[i+1])} :: 0 <= i < |db| - 1 ==> LS_Next(db[i], db[i+1]) } function AbstractifyConcretePacket(p:LPacket>) : LPacket { LPacket(p.dst, p.src, AbstractifyCMessage(DemarshallData(p.msg))) } predicate LEnvStepIsAbstractable(step:LEnvStep>) { match step { case LEnvStepHostIos(actor, ios) => true case LEnvStepDeliverPacket(p) => true case LEnvStepAdvanceTime => true case LEnvStepStutter => true } } function AbstractifyConcreteEnvStep(step:LEnvStep>) : LEnvStep requires LEnvStepIsAbstractable(step); { match step { case LEnvStepHostIos(actor, ios) => LEnvStepHostIos(actor, AbstractifyRawLogToIos(ios)) case LEnvStepDeliverPacket(p) => LEnvStepDeliverPacket(AbstractifyConcretePacket(p)) case LEnvStepAdvanceTime => LEnvStepAdvanceTime() case LEnvStepStutter => LEnvStepStutter() } } predicate ConcreteEnvironmentIsAbstractable(ds_env:LEnvironment>) { LEnvStepIsAbstractable(ds_env.nextStep) } function AbstractifyConcreteSentPackets(sent:set>>) : set> { set p | p in sent :: AbstractifyConcretePacket(p) } function AbstractifyConcreteEnvironment(ds_env:LEnvironment>) : LEnvironment requires ConcreteEnvironmentIsAbstractable(ds_env); { LEnvironment(ds_env.time, AbstractifyConcreteSentPackets(ds_env.sentPackets), map [], AbstractifyConcreteEnvStep(ds_env.nextStep)) } function {:opaque} AbstractifyConcreteReplicas(replicas:map, replica_order:seq) : map requires forall i :: 0 <= i < |replica_order| ==> replica_order[i] in replicas; requires SeqIsUnique(replica_order); ensures |AbstractifyConcreteReplicas(replicas, replica_order)| == |replica_order|; ensures forall i :: 0 <= i < |replica_order| ==> replica_order[i] in AbstractifyConcreteReplicas(replicas, replica_order); ensures forall i :: 0 <= i < |replica_order| ==> AbstractifyConcreteReplicas(replicas, replica_order)[replica_order[i]] == replicas[replica_order[i]].node; ensures forall e :: e in AbstractifyConcreteReplicas(replicas, replica_order) <==> e in replica_order; { if |replica_order| == 0 then map[] else lemma_UniqueSeq_SubSeqsUnique(replica_order, [replica_order[0]], replica_order[1..]); reveal_SeqIsUnique(); assert SeqIsUnique(replica_order[1..]); assert replica_order[0] !in replica_order[1..]; assert replica_order[0] !in AbstractifyConcreteReplicas(replicas, replica_order[1..]); var rest := AbstractifyConcreteReplicas(replicas, replica_order[1..]); rest[replica_order[0] := replicas[replica_order[0]].node] } predicate DsStateIsAbstractable(ds:DS_State) { ValidConfig(ds.config) && (forall r :: r in ds.config ==> r in ds.servers) } function AbstractifyDsState(ds:DS_State) : LS_State requires DsStateIsAbstractable(ds); { LS_State(AbstractifyConcreteEnvironment(ds.environment), AbstractifyConcreteReplicas(ds.servers, ds.config)) } lemma lemma_DeduceTransitionFromDsBehavior( config:ConcreteConfiguration, db:seq, i:int ) requires IsValidBehavior(config, db); requires 0 <= i < |db| - 1; ensures DS_Next(db[i], db[i+1]); { } lemma lemma_DsNextOffset(db:seq, index:int) requires |db| > 0; requires 0 < index < |db|; requires forall i {:trigger DS_Next(db[i], db[i+1])} :: 0 <= i < |db| - 1 ==> DS_Next(db[i], db[i+1]); ensures DS_Next(db[index-1], db[index]); { var i := index - 1; assert DS_Next(db[i], db[i+1]); // OBSERVE trigger for the forall } lemma lemma_DsConsistency(config:ConcreteConfiguration, db:seq, i:int) requires IsValidBehavior(config, db); requires 0 <= i < |db|; ensures db[i].config == config; ensures Collections__Maps2_s.mapdomain(db[i].servers) == Collections__Maps2_s.mapdomain(db[0].servers); { if i == 0 { } else { lemma_DsConsistency(config, db, i-1); lemma_DeduceTransitionFromDsBehavior(config, db, i-1); assert forall server :: server in db[i-1].servers ==> server in db[i].servers; assert forall server :: server in db[i].servers ==> server in db[i-1].servers; forall server | server in Collections__Maps2_s.mapdomain(db[i-1].servers) ensures server in Collections__Maps2_s.mapdomain(db[i].servers) { assert server in db[i-1].servers; assert server in db[i].servers; } forall server | server in Collections__Maps2_s.mapdomain(db[i].servers) ensures server in Collections__Maps2_s.mapdomain(db[i-1].servers) { assert server in db[i].servers; assert server in db[i-1].servers; } } } lemma lemma_IsValidEnvStep(de:LEnvironment>, le:LEnvironment) requires IsValidLEnvStep(de, de.nextStep); requires de.nextStep.LEnvStepHostIos?; requires ConcreteEnvironmentIsAbstractable(de); requires AbstractifyConcreteEnvironment(de) == le; ensures IsValidLEnvStep(le, le.nextStep); { var id := de.nextStep.actor; var ios := de.nextStep.ios; var r_ios := le.nextStep.ios; assert LIoOpSeqCompatibleWithReduction(r_ios); forall io | io in r_ios ensures IsValidLIoOp(io, id, le); { var j :| 0 <= j < |r_ios| && r_ios[j] == io; assert r_ios[j] == AstractifyNetEventToLockIo(ios[j]); assert IsValidLIoOp(ios[j], id, de); } } lemma lemma_IosRelations(ios:seq>>, r_ios:seq>) returns (sends:set>>, r_sends:set>) requires r_ios == AbstractifyRawLogToIos(ios); ensures sends == (set io | io in ios && io.LIoOpSend? :: io.s); ensures r_sends == (set io | io in r_ios && io.LIoOpSend? :: io.s); ensures r_sends == AbstractifyConcreteSentPackets(sends); { sends := (set io | io in ios && io.LIoOpSend? :: io.s); r_sends := (set io | io in r_ios && io.LIoOpSend? :: io.s); var refined_sends := AbstractifyConcreteSentPackets(sends); forall r | r in refined_sends ensures r in r_sends; { var send :| send in sends && AbstractifyConcretePacket(send) == r; var io :| io in ios && io.LIoOpSend? && io.s == send; assert AstractifyNetEventToLockIo(io) in r_ios; } forall r | r in r_sends ensures r in refined_sends; { var r_io :| r_io in r_ios && r_io.LIoOpSend? && r_io.s == r; var j :| 0 <= j < |r_ios| && r_ios[j] == r_io; assert AstractifyNetEventToLockIo(ios[j]) == r_io; assert ios[j] in ios; assert ios[j].s in sends; } } lemma lemma_LEnvironmentNextHost(de :LEnvironment>, le :LEnvironment, de':LEnvironment>, le':LEnvironment) requires ConcreteEnvironmentIsAbstractable(de); requires ConcreteEnvironmentIsAbstractable(de'); requires AbstractifyConcreteEnvironment(de) == le; requires AbstractifyConcreteEnvironment(de') == le'; requires de.nextStep.LEnvStepHostIos?; requires LEnvironment_Next(de, de'); ensures LEnvironment_Next(le, le'); { lemma_IsValidEnvStep(de, le); var id := de.nextStep.actor; var ios := de.nextStep.ios; var r_ios := le.nextStep.ios; assert LEnvironment_PerformIos(de, de', id, ios); var sends, r_sends := lemma_IosRelations(ios, r_ios); assert de.sentPackets + sends == de'.sentPackets; assert le.sentPackets + r_sends == le'.sentPackets; assert forall r_io :: r_io in r_ios && r_io.LIoOpReceive? ==> r_io.r in le.sentPackets; assert LEnvironment_PerformIos(le, le', id, r_ios); } lemma RefinementToLSStateHelper(ds:DS_State, ds':DS_State, ss:LS_State, ss':LS_State) requires DsStateIsAbstractable(ds) requires DsStateIsAbstractable(ds') requires ss == AbstractifyDsState(ds) requires ss' == AbstractifyDsState(ds') requires DS_Next(ds, ds') ensures LS_Next(ss, ss') { reveal_HostNext(); if !ds.environment.nextStep.LEnvStepHostIos? { assert LS_Next(ss, ss'); } else { lemma_LEnvironmentNextHost(ds.environment, ss.environment, ds'.environment, ss'.environment); assert LS_Next(ss, ss'); } } lemma RefinementToLSState(config:ConcreteConfiguration, db:seq) returns (sb:seq) requires |db| > 0; requires DS_Init(db[0], config); requires forall i {:trigger DS_Next(db[i], db[i+1])} :: 0 <= i < |db| - 1 ==> DS_Next(db[i], db[i+1]); ensures |sb| == |db|; ensures LS_Init(sb[0], db[0].config); ensures forall i {:trigger LS_Next(sb[i], sb[i+1])} :: 0 <= i < |sb| - 1 ==> LS_Next(sb[i], sb[i+1]); ensures forall i :: 0 <= i < |db| ==> DsStateIsAbstractable(db[i]) && sb[i] == AbstractifyDsState(db[i]); { if |db| == 1 { var ls := AbstractifyDsState(db[0]); sb := [ ls ]; assert (forall id :: id in db[0].servers ==> HostInit(db[0].servers[id], config, id)); reveal_SeqIsUnique(); } else { lemma_DeduceTransitionFromDsBehavior(config, db, |db|-2); lemma_DsConsistency(config, db, |db|-2); var ls := AbstractifyDsState(db[|db|-2]); var ls' := AbstractifyDsState(last(db)); var rest := RefinementToLSState(config, all_but_last(db)); sb := rest + [ls']; forall i | 0 <= i < |sb| - 1 ensures LS_Next(sb[i], sb[i+1]); { if (0 <= i < |sb|-2) { assert LS_Next(sb[i], sb[i+1]); } else { RefinementToLSStateHelper(db[i], db[i+1], sb[i], sb[i+1]); } } } } lemma lemma_DeduceTransitionFromLsBehavior( config:ConcreteConfiguration, db:seq, i:int ) requires IsValidBehaviorLs(config, db); requires 0 <= i < |db| - 1; ensures LS_Next(db[i], db[i+1]); { } lemma lemma_LsConsistency(config:ConcreteConfiguration, lb:seq, i:int) requires IsValidBehaviorLs(config, lb); requires 0 <= i < |lb|; ensures Collections__Maps2_s.mapdomain(lb[i].servers) == Collections__Maps2_s.mapdomain(lb[0].servers); ensures forall e :: e in lb[i].servers ==> e in lb[0].servers && lb[i].servers[e].config == lb[0].servers[e].config; { if i == 0 { } else { lemma_LsConsistency(config, lb, i-1); lemma_DeduceTransitionFromLsBehavior(config, lb, i-1); assert forall server :: server in lb[i-1].servers ==> server in lb[i].servers; assert forall server :: server in lb[i].servers ==> server in lb[i-1].servers; forall server | server in Collections__Maps2_s.mapdomain(lb[i-1].servers) ensures server in Collections__Maps2_s.mapdomain(lb[i].servers) { assert server in lb[i-1].servers; assert server in lb[i].servers; } forall server | server in Collections__Maps2_s.mapdomain(lb[i].servers) ensures server in Collections__Maps2_s.mapdomain(lb[i-1].servers) { assert server in lb[i].servers; assert server in lb[i-1].servers; } } } lemma {:timeLimitMultiplier 2} MakeGLSBehaviorFromLS(config:ConcreteConfiguration, db:seq) returns (sb:seq) requires |db| > 0; requires LS_Init(db[0], config); requires forall i {:trigger LS_Next(db[i], db[i+1])} :: 0 <= i < |db| - 1 ==> LS_Next(db[i], db[i+1]); ensures |sb| == |db|; ensures GLS_Init(sb[0], config); ensures forall i {:trigger GLS_Next(sb[i], sb[i+1])} :: 0 <= i < |sb| - 1 ==> GLS_Next(sb[i], sb[i+1]); ensures forall i :: 0 <= i < |db| ==> sb[i].ls == db[i]; { if (|db| == 1) { sb := [GLS_State(db[0], [config[0]])]; } else { var rest := MakeGLSBehaviorFromLS(config, all_but_last(db)); var last_history := last(rest).history; var ls := db[|db|-2]; var ls' := db[|db|-1]; if ls.environment.nextStep.LEnvStepHostIos? && ls.environment.nextStep.actor in ls.servers { var id := ls.environment.nextStep.actor; var ios := ls.environment.nextStep.ios; lemma_DeduceTransitionFromLsBehavior(config, db, |db|-2); assert LS_Next(ls, ls'); assert LS_NextOneServer(ls, ls', id, ios); var node := ls.servers[id]; var node' := ls'.servers[id]; assert NodeNext(node, node', ios); var new_history:seq; if NodeGrant(node, node', ios) && node.held && node.epoch < 0xFFFF_FFFF_FFFF_FFFF{ new_history := last_history + [node.config[(node.my_index+1) % |node.config|]]; } else { new_history := last_history; } sb := rest + [GLS_State(db[|db|-1], new_history)]; assert GLS_Next(sb[|sb|-2], sb[|sb|-1]); } else { sb := rest + [GLS_State(db[|db|-1], last_history)]; } } } lemma {:timeLimitMultiplier 2} RefinementToServiceState(config:ConcreteConfiguration, glb:seq) returns (sb:seq) requires |glb| > 0; requires GLS_Init(glb[0], config); requires forall i {:trigger GLS_Next(glb[i], glb[i+1])} :: 0 <= i < |glb| - 1 ==> GLS_Next(glb[i], glb[i+1]); ensures |sb| == |glb|; ensures Service_Init(sb[0], MapSeqToSet(config, x=>x)); ensures forall i {:trigger Service_Next(sb[i], sb[i+1])} :: 0 <= i < |sb| - 1 ==> sb[i] == sb[i+1] || Service_Next(sb[i], sb[i+1]); ensures forall i :: 0 <= i < |glb| ==> sb[i] == AbstractifyGLS_State(glb[i]); ensures forall i :: 0 <= i < |sb| ==> sb[i].hosts == sb[0].hosts; ensures sb[|sb|-1] == AbstractifyGLS_State(glb[|glb|-1]); { if |glb| == 1 { sb := [AbstractifyGLS_State(glb[0])]; lemma_InitRefines(glb[0], config); assert Service_Init(AbstractifyGLS_State(glb[0]), MapSeqToSet(config, x=>x)); } else { var rest := RefinementToServiceState(config, all_but_last(glb)); var gls := last(all_but_last(glb)); var gls' := last(glb); lemma_LS_NextAbstract(glb, config, |glb|-2); sb := rest + [AbstractifyGLS_State(gls')]; if (AbstractifyGLS_State(gls) == AbstractifyGLS_State(gls')) { assert sb[|sb|-2] == sb[|sb|-1]; } else { assert Service_Next(sb[|sb|-2], sb[|sb|-1]); } } } lemma lemma_LockedPacketImpliesTransferPacket( config:ConcreteConfiguration, lb:seq, i:int, p:LockPacket ) requires IsValidBehaviorLs(config, lb); requires 0 <= i < |lb|; requires p in lb[i].environment.sentPackets; requires p.src in lb[i].servers; requires p.msg.Locked?; ensures exists q :: q in lb[i].environment.sentPackets && q.msg.Transfer? && q.src in lb[i].servers && q.msg.transfer_epoch == p.msg.locked_epoch && q.dst == p.src; { if i == 0 { return; } lemma_DeduceTransitionFromLsBehavior(config, lb, i-1); lemma_LsConsistency(config, lb, i); assert Collections__Maps2_s.mapdomain(lb[i].servers) == Collections__Maps2_s.mapdomain(lb[0].servers); assert LS_Init(lb[0], config); if p in lb[i-1].environment.sentPackets { lemma_LockedPacketImpliesTransferPacket(config, lb, i-1, p); } else { var s := lb[i-1]; var s' := lb[i]; assert LS_Next(lb[i-1], lb[i]); if s.environment.nextStep.LEnvStepHostIos? && s.environment.nextStep.actor in s.servers { assert LS_NextOneServer(s, s', s.environment.nextStep.actor, s.environment.nextStep.ios); var id := s.environment.nextStep.actor; var node := s.servers[id]; var node' := s'.servers[id]; var ios := s.environment.nextStep.ios; if NodeAccept(node, node', ios) { var packet := ios[0].r; assert IsValidLIoOp(ios[0], id, s.environment); assert packet in lb[i].environment.sentPackets && packet.msg.Transfer? && packet.msg.transfer_epoch == p.msg.locked_epoch && packet.dst == p.src && packet.src in node.config; assert node.config == lb[0].servers[id].config == lb[i].servers[id].config; assert forall e :: e in lb[i].servers[id].config <==> e in Collections__Maps2_s.mapdomain(lb[i].servers); assert packet.src in lb[i].servers; } } } } lemma lemma_PacketSentByServerIsDemarshallable( config:ConcreteConfiguration, db:seq, i:int, p:LPacket> ) requires IsValidBehavior(config, db); requires 0 <= i < |db|; requires p.src in config; requires p in db[i].environment.sentPackets; ensures Demarshallable(p.msg, CMessageGrammar()); { if i == 0 { return; } if p in db[i-1].environment.sentPackets { lemma_PacketSentByServerIsDemarshallable(config, db, i-1, p); return; } lemma_DeduceTransitionFromDsBehavior(config, db, i-1); lemma_DsConsistency(config, db, i-1); reveal_HostNext(); } lemma RefinementProof(config:DS_s.H_s.ConcreteConfiguration, db:seq) returns (sb:seq) /* requires |db| > 0; requires DS_Init(db[0], config); requires forall i {:trigger DS_Next(db[i], db[i+1])} :: 0 <= i < |db| - 1 ==> DS_Next(db[i], db[i+1]); ensures |db| == |sb|; ensures Service_Init(sb[0], Collections__Maps2_s.mapdomain(db[0].servers)); ensures forall i {:trigger Service_Next(sb[i], sb[i+1])} :: 0 <= i < |sb| - 1 ==> sb[i] == sb[i+1] || Service_Next(sb[i], sb[i+1]); ensures forall i :: 0 <= i < |db| ==> Service_Correspondence(db[i].environment.sentPackets, sb[i]); */ { var lsb := RefinementToLSState(config, db); var glsb := MakeGLSBehaviorFromLS(config, lsb); sb := RefinementToServiceState(config, glsb); //assert forall i :: 0 <= i < |sb| - 1 ==> Service_Next(sb[i], sb[i+1]); forall i | 0 <= i < |db| ensures Service_Correspondence(db[i].environment.sentPackets, sb[i]); { var ls := lsb[i]; var gls := glsb[i]; var ss := sb[i]; var history := MakeLockHistory(glsb, config, i); assert history == gls.history; forall p, epoch | p in db[i].environment.sentPackets && p.src in ss.hosts && p.dst in ss.hosts && p.msg == MarshallLockMsg(epoch) ensures 2 <= epoch <= |ss.history| && p.src == ss.history[epoch-1]; { var ap := AbstractifyConcretePacket(p); assert p.src in sb[0].hosts; lemma_PacketSentByServerIsDemarshallable(config, db, i, p); assert Demarshallable(p.msg, CMessageGrammar()); lemma_ParseMarshallLockedAbstract(p.msg, epoch, ap.msg); lemma_LockedPacketImpliesTransferPacket(config, lsb, i, ap); var q :| q in ls.environment.sentPackets && q.msg.Transfer? && q.msg.transfer_epoch == ap.msg.locked_epoch && q.dst == p.src; assert q in gls.ls.environment.sentPackets; } } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Services/Lock/Marshall.i.dfy ================================================ include "AbstractService.s.dfy" include "../../Protocol/Lock/Types.i.dfy" include "../../Impl/Lock/PacketParsing.i.dfy" module MarshallProof_i { import opened Native__NativeTypes_s import opened AbstractServiceLock_s`All import opened Types_i import opened Math__power2_i import opened Common__Util_i import opened Common__GenericMarshalling_i import opened Message_i import opened PacketParsing_i lemma lemma_ParseValCorrectVCase(data:seq, v:V, g:G) returns (caseId:uint64, val:V, rest:seq) requires ValInGrammar(v, g); requires |data| < 0x1_0000_0000_0000_0000; requires ValidGrammar(g); requires parse_Val(data, g).0.Some?; requires parse_Val(data, g).0.v == v; requires g.GTaggedUnion?; ensures parse_Uint64(data).0.Some?; ensures caseId == parse_Uint64(data).0.v.u; ensures 0 <= caseId as int < |g.cases|; ensures rest == parse_Uint64(data).1; ensures parse_Val(rest, g.cases[caseId]).0.Some?; ensures val == parse_Val(rest, g.cases[caseId]).0.v ensures v == VCase(caseId, val); ensures ValInGrammar(val, g.cases[caseId]); { reveal_parse_Val(); caseId := parse_Uint64(data).0.v.u; var tuple := parse_Val(parse_Uint64(data).1, g.cases[caseId]); val := tuple.0.v; rest := parse_Uint64(data).1; } lemma lemma_ParseValCorrectVUint64(data:seq, v:V, g:G) returns (u:uint64, rest:seq) requires ValInGrammar(v, g); requires |data| < 0x1_0000_0000_0000_0000; requires ValidGrammar(g); requires parse_Val(data, g).0.Some?; requires parse_Val(data, g).0.v == v; requires g.GUint64?; ensures parse_Uint64(data).0.Some?; ensures u == parse_Uint64(data).0.v.u; ensures v == VUint64(u); ensures rest == parse_Val(data, g).1; { reveal_parse_Val(); u := parse_Uint64(data).0.v.u; rest := parse_Uint64(data).1; } lemma lemma_SizeOfCMessageLocked(v:V) requires ValInGrammar(v, CMessageGrammar()); requires ValInGrammar(v.val, CMessageLockedGrammar()); ensures SizeOfV(v) == 16; { } lemma lemma_ParseMarshallLockedAbstract(bytes:seq, epoch:int, msg:LockMessage) requires AbstractifyCMessage(DemarshallData(bytes)) == msg; requires bytes == MarshallLockMsg(epoch); requires Demarshallable(bytes, CMessageGrammar()); ensures msg.Locked?; ensures msg.locked_epoch == epoch; { var marshalled_bytes := MarshallLockMsg(epoch); var g := CMessageGrammar(); if 0 <= epoch < 0x1_0000_0000_0000_0000 { var cmsg := DemarshallData(bytes); var data := bytes; var v := DemarshallFunc(data, g); // Walk through the generic parsing process var msgCaseId, msgCaseVal, rest0 := lemma_ParseValCorrectVCase(data, v, g); // Prove that the first 8 bytes are correct assert msgCaseId == 1; assert 1 == SeqByteToUint64(bytes[..8]); assert bytes[..8] == [ 0, 0, 0, 0, 0, 0, 0, 1]; // Prove that the next 8 bytes of seqno are correct var u, rest := lemma_ParseValCorrectVUint64(rest0, msgCaseVal, GUint64); lemma_2toX(); calc { u; parse_Uint64(rest0).0.v.u; SeqByteToUint64(rest0[..8]); SeqByteToUint64(Uint64ToBytes(epoch as uint64)); SeqByteToUint64(Uint64ToSeqByte(epoch as uint64)); SeqByteToUint64(BEUintToSeqByte(epoch as uint64 as int, 8)); { lemma_BEByteSeqToInt_BEUintToSeqByte_invertability(); } epoch as uint64; } assert msg.locked_epoch == u as int; assert epoch == msg.locked_epoch; } else { reveal_parse_Val(); assert false; } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Services/RSL/.gitignore ================================================ Main.i.cs build/ ================================================ FILE: ironfleet/src/Dafny/Distributed/Services/RSL/AbstractService.s.dfy ================================================ ///////////////////////////////////////////////////////////////////////////// // // This is the specification for an abstract service that implements an // application-defined state machine. It provides linearizability of // state-machine operations requested by clients. That is, each operation // the service executes appears to occur atomically, at a point after it // was submitted by the client and before the service sent its response. // // Note that the specification does not require exactly-once semantics. // If one needs exactly-once semantics, one should enforce that in the // application state machine. For instance, the state machine could keep // track of the highest request sequence number seen from each client, and // treat requests with older sequence numbers as no-ops. // ///////////////////////////////////////////////////////////////////////////// include "../../Common/Framework/AbstractService.s.dfy" include "../../Common/Collections/Seqs.s.dfy" include "AppStateMachine.s.dfy" module AbstractServiceRSL_s refines AbstractService_s { import opened AppStateMachine_s import opened Collections__Seqs_s datatype AppRequestMessage = AppRequestMessage(client:EndPoint, seqno:int, request:AppRequest) datatype AppReplyMessage = AppReplyMessage(client:EndPoint, seqno:int, reply:AppReply) datatype ServiceState' = ServiceState'( serverAddresses:set, app:AppState, requests:set, replies:set ) type ServiceState = ServiceState' predicate Service_Init(s:ServiceState, serverAddresses:set) { && s.serverAddresses == serverAddresses && s.app == AppInitialize() && s.requests == {} && s.replies == {} } predicate ServiceExecutesAppRequest(s:ServiceState, s':ServiceState, req:AppRequestMessage) { && |req.request| <= MaxAppRequestSize() && s'.serverAddresses == s.serverAddresses && s'.requests == s.requests + { req } && s'.app == AppHandleRequest(s.app, req.request).0 && s'.replies == s.replies + { AppReplyMessage(req.client, req.seqno, AppHandleRequest(s.app, req.request).1) } } predicate StateSequenceReflectsBatchExecution(s:ServiceState, s':ServiceState, intermediate_states:seq, batch:seq) { && |intermediate_states| == |batch| + 1 && intermediate_states[0] == s && last(intermediate_states) == s' && forall i :: 0 <= i < |batch| ==> ServiceExecutesAppRequest(intermediate_states[i], intermediate_states[i+1], batch[i]) } predicate Service_Next(s:ServiceState, s':ServiceState) { exists intermediate_states, batch :: StateSequenceReflectsBatchExecution(s, s', intermediate_states, batch) } function Uint64ToBytes(u:uint64) : seq { [( u/0x1000000_00000000) as byte, ((u/ 0x10000_00000000)%0x100) as byte, ((u/ 0x100_00000000)%0x100) as byte, ((u/ 0x1_00000000)%0x100) as byte, ((u/ 0x1000000)%0x100) as byte, ((u/ 0x10000)%0x100) as byte, ((u/ 0x100)%0x100) as byte, ( u %0x100) as byte] } function MarshallServiceRequest(seqno:int, request:AppRequest) : seq { if 0 <= seqno < 0x1_0000_0000_0000_0000 && |request| <= MaxAppRequestSize() then [ 0, 0, 0, 0, 0, 0, 0, 0] // MarshallMesssage_Request magic number + Uint64ToBytes(seqno as uint64) + Uint64ToBytes(|request| as uint64) + request else [ 1 ] } function MarshallServiceReply(seqno:int, reply:AppReply) : seq { if 0 <= seqno < 0x1_0000_0000_0000_0000 && |reply| <= MaxAppReplySize() then [ 0, 0, 0, 0, 0, 0, 0, 6] // MarshallMesssage_Reply magic number + Uint64ToBytes(seqno as uint64) + Uint64ToBytes(|reply| as uint64) + reply else [ 1 ] } predicate Service_Correspondence(concretePkts:set>>, serviceState:ServiceState) { && (forall p, seqno, reply :: p in concretePkts && p.src in serviceState.serverAddresses && p.msg == MarshallServiceReply(seqno, reply) ==> AppReplyMessage(p.dst, seqno, reply) in serviceState.replies) && (forall req :: req in serviceState.requests ==> exists p :: p in concretePkts && p.dst in serviceState.serverAddresses && p.msg == MarshallServiceRequest(req.seqno, req.request) && p.src == req.client) } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Services/RSL/AppStateMachine.s.dfy ================================================ include "../../Common/Native/Io.s.dfy" module AppStateMachine_s { import opened Native__NativeTypes_s import opened Native__Io_s type Bytes = seq type AppState = Bytes type AppRequest = Bytes type AppReply = Bytes function {:axiom} AppInitialize() : AppState function {:axiom} AppHandleRequest(m:AppState, request:AppRequest) : (AppState, AppReply) function method MaxAppRequestSize() : int { 0x800_0000 } // 128 MB function method MaxAppReplySize() : int { 0x800_0000 } // 128 MB function method MaxAppStateSize() : int { 0x1000_0000_0000_0000 } // 2^60 B class AppStateMachine { constructor{:axiom} () requires false function {:axiom} Abstractify() : AppState static method {:axiom} Initialize() returns (m:AppStateMachine) ensures fresh(m) ensures m.Abstractify() == AppInitialize() static method {:axiom} Deserialize(state:AppState) returns (m:AppStateMachine) ensures fresh(m) ensures m.Abstractify() == state method {:axiom} Serialize() returns (state:AppState) ensures state == Abstractify() ensures |state| <= MaxAppStateSize() method {:axiom} HandleRequest(request:AppRequest) returns (reply:AppReply) requires |request| <= MaxAppRequestSize() ensures (Abstractify(), reply) == AppHandleRequest(old(Abstractify()), request) ensures |reply| <= MaxAppReplySize() } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Services/RSL/Main.i.dfy ================================================ include "../../Common/Framework/Main.s.dfy" include "../../Impl/RSL/Host.i.dfy" include "../../Protocol/RSL/RefinementProof/Refinement.i.dfy" include "../../Protocol/Common/NodeIdentity.i.dfy" include "RSLDistributedSystem.i.dfy" include "AbstractService.s.dfy" include "Marshall.i.dfy" module Main_i refines Main_s { import opened Host = Host_i import opened DS_s = RSL_DistributedSystem_i import opened DirectRefinement__Refinement_i import opened Concrete_NodeIdentity_i import opened AS_s = AbstractServiceRSL_s import opened AppStateMachine_s import opened MarshallProof_i import opened LiveRSL__AppInterface_i import opened LiveRSL__CMessageRefinements_i import opened LiveRSL__Configuration_i import opened LiveRSL__Constants_i import opened LiveRSL__ConstantsState_i import opened LiveRSL__CTypes_i import opened LiveRSL__DistributedSystem_i import opened LiveRSL__Environment_i import opened LiveRSL__Message_i import opened LiveRSL__PacketParsing_i import opened LiveRSL__Replica_i import opened LiveRSL__Types_i import opened LiveRSL__NetRSL_i import opened LiveRSL__Unsendable_i import opened Collections__Maps2_s import opened Collections__Sets_i import opened Common__GenericMarshalling_i import opened Common__NodeIdentity_i import opened Common__SeqIsUniqueDef_i import opened AbstractServiceRSL_s import opened DirectRefinement__StateMachine_i import opened Environment_s import opened Math__mod_auto_i predicate IsValidBehavior(config:ConcreteConfiguration, db:seq) reads * { && |db| > 0 && DS_Init(db[0], config) && forall i {:trigger DS_Next(db[i], db[i+1])} :: 0 <= i < |db| - 1 ==> DS_Next(db[i], db[i+1]) } predicate LPacketIsAbstractable(cp:LPacket>) { CMessageIsAbstractable(PaxosDemarshallData(cp.msg)) } function AbstractifyConcretePacket(p:LPacket>) : LPacket requires LPacketIsAbstractable(p) { LPacket(p.dst, p.src, AbstractifyCMessageToRslMessage(PaxosDemarshallData(p.msg))) } predicate LEnvStepIsAbstractable(step:LEnvStep>) { match step { case LEnvStepHostIos(actor, ios) => NetEventLogIsAbstractable(ios) case LEnvStepDeliverPacket(p) => LPacketIsAbstractable(p) case LEnvStepAdvanceTime => true case LEnvStepStutter => true } } function AbstractifyConcreteEnvStep(step:LEnvStep>) : LEnvStep requires LEnvStepIsAbstractable(step) { match step { case LEnvStepHostIos(actor, ios) => LEnvStepHostIos(actor, AbstractifyRawLogToIos(ios)) case LEnvStepDeliverPacket(p) => LEnvStepDeliverPacket(AbstractifyConcretePacket(p)) case LEnvStepAdvanceTime => LEnvStepAdvanceTime() case LEnvStepStutter => LEnvStepStutter() } } predicate ConcreteEnvironmentIsAbstractable(ds_env:LEnvironment>) { && (forall p :: p in ds_env.sentPackets ==> LPacketIsAbstractable(p)) && LEnvStepIsAbstractable(ds_env.nextStep) } function AbstractifyConcreteSentPackets(sent:set>>) : set> requires forall p :: p in sent ==> LPacketIsAbstractable(p) { set p | p in sent :: AbstractifyConcretePacket(p) } function AbstractifyConcreteEnvironment(ds_env:LEnvironment>) : LEnvironment requires ConcreteEnvironmentIsAbstractable(ds_env) { LEnvironment(ds_env.time, AbstractifyConcreteSentPackets(ds_env.sentPackets), map [], AbstractifyConcreteEnvStep(ds_env.nextStep)) } function AbstractifyConcreteReplicas(replicas:map, replica_order:seq) : seq requires forall r :: r in replica_order ==> r in replicas ensures |AbstractifyConcreteReplicas(replicas, replica_order)| == |replica_order| ensures forall i :: 0 <= i < |replica_order| ==> AbstractifyConcreteReplicas(replicas, replica_order)[i] == replicas[replica_order[i]].sched { if replica_order == [] then [] else [replicas[replica_order[0]].sched] + AbstractifyConcreteReplicas(replicas, replica_order[1..]) } predicate DsStateIsAbstractable(ds:DS_State) { && ConstantsStateIsAbstractable(ds.config) && ConcreteEnvironmentIsAbstractable(ds.environment) && (forall r :: r in ds.config.config.replica_ids ==> r in ds.servers) } function AbstractifyDsState(ds:DS_State) : RslState requires DsStateIsAbstractable(ds) { RslState(AbstractifyConstantsStateToLConstants(ds.config), AbstractifyConcreteEnvironment(ds.environment), AbstractifyConcreteReplicas(ds.servers, ds.config.config.replica_ids)) } lemma lemma_DeduceTransitionFromDsBehavior( config:ConcreteConfiguration, db:seq, i:int ) requires IsValidBehavior(config, db) requires 0 <= i < |db| - 1 ensures DS_Next(db[i], db[i+1]) { } lemma lemma_DsNextOffset(db:seq, index:int) requires |db| > 0 requires 0 < index < |db| requires forall i {:trigger DS_Next(db[i], db[i+1])} :: 0 <= i < |db| - 1 ==> DS_Next(db[i], db[i+1]) ensures DS_Next(db[index-1], db[index]) { var i := index - 1; assert DS_Next(db[i], db[i+1]); // OBSERVE trigger for the forall } lemma lemma_DsConsistency(config:ConcreteConfiguration, db:seq, i:int) requires IsValidBehavior(config, db) requires 0 <= i < |db| ensures db[i].config == config ensures mapdomain(db[i].servers) == mapdomain(db[0].servers) { if i == 0 { } else { lemma_DsConsistency(config, db, i-1); lemma_DeduceTransitionFromDsBehavior(config, db, i-1); assert forall server :: server in db[i-1].servers ==> server in db[i].servers; assert forall server :: server in db[i].servers ==> server in db[i-1].servers; forall server | server in mapdomain(db[i-1].servers) ensures server in mapdomain(db[i].servers) { assert server in db[i-1].servers; assert server in db[i].servers; } forall server | server in mapdomain(db[i].servers) ensures server in mapdomain(db[i-1].servers) { assert server in db[i].servers; assert server in db[i-1].servers; } } } lemma lemma_LSchedulerNextPreservesConstants( s:LScheduler, s':LScheduler, ios:seq ) requires LSchedulerNext(s, s', ios) ensures s.replica.constants == s.replica.constants ensures s.replica.proposer.constants == s.replica.proposer.constants ensures s.replica.acceptor.constants == s.replica.acceptor.constants ensures s.replica.learner.constants == s.replica.learner.constants ensures s.replica.executor.constants == s.replica.executor.constants { } lemma {:timeLimitMultiplier 2} lemma_DsConstantsAllConsistent(config:ConcreteConfiguration, db:seq, i:int, id:EndPoint) requires IsValidBehavior(config, db) requires 0 <= i < |db| requires id in db[i].servers ensures db[i].config == config ensures db[i].servers[id].sched.replica.constants.all == AbstractifyConstantsStateToLConstants(config) ensures db[i].servers[id].sched.replica.proposer.constants.all == AbstractifyConstantsStateToLConstants(config) ensures db[i].servers[id].sched.replica.acceptor.constants.all == AbstractifyConstantsStateToLConstants(config) ensures db[i].servers[id].sched.replica.learner.constants.all == AbstractifyConstantsStateToLConstants(config) ensures db[i].servers[id].sched.replica.executor.constants.all == AbstractifyConstantsStateToLConstants(config) { if i == 0 { assert DS_Init(db[0], config); return; } lemma_DsConsistency(config, db, i-1); lemma_DsConsistency(config, db, i); lemma_DeduceTransitionFromDsBehavior(config, db, i-1); assert mapdomain(db[i].servers) == mapdomain(db[0].servers) == mapdomain(db[i-1].servers); lemma_DsConstantsAllConsistent(config, db, i-1, id); var s := db[i-1].servers[id].sched; var s' := db[i].servers[id].sched; if s' == s { return; } var ios :| DS_NextOneServer(db[i-1], db[i], id, ios); var rios := AbstractifyRawLogToIos(ios); assert LSchedulerNext(s, s', rios) || HostNextIgnoreUnsendable(s, s', ios); if LSchedulerNext(s, s', rios) { lemma_LSchedulerNextPreservesConstants(s, s', rios); } else { assert s'.replica == s.replica; } } lemma{:timeLimitMultiplier 4} lemma_PacketSentByServerIsMarshallable( config:ConcreteConfiguration, db:seq, i:int, p:LPacket> ) requires IsValidBehavior(config, db) requires 0 <= i < |db| requires p.src in config.config.replica_ids requires p in db[i].environment.sentPackets ensures NetPacketBound(p.msg) ensures Marshallable(PaxosDemarshallData(p.msg)) { if i == 0 { return; } if p in db[i-1].environment.sentPackets { lemma_PacketSentByServerIsMarshallable(config, db, i-1, p); return; } lemma_DeduceTransitionFromDsBehavior(config, db, i-1); lemma_DsConsistency(config, db, i-1); assert LEnvironment_Next(db[i-1].environment, db[i].environment); assert db[i-1].environment.nextStep.LEnvStepHostIos?; var io := LIoOpSend(p); var ios := db[i-1].environment.nextStep.ios; assert io in ios; assert IsValidLIoOp(io, db[i-1].environment.nextStep.actor, db[i-1].environment); assert db[i-1].environment.nextStep.actor == p.src; assert DS_NextOneServer(db[i-1], db[i], p.src, ios); assert OnlySentMarshallableData(ios); assert NetPacketBound(io.s.msg); assert Marshallable(PaxosDemarshallData(io.s.msg)); } lemma lemma_SentPacketIsValidPhysicalPacket( config:ConcreteConfiguration, db:seq, i:int, p:LPacket> ) requires IsValidBehavior(config, db) requires 0 <= i < |db| requires p in db[i].environment.sentPackets ensures ValidPhysicalPacket(p) { if i == 0 { return; } if p in db[i-1].environment.sentPackets { lemma_SentPacketIsValidPhysicalPacket(config, db, i-1, p); return; } lemma_DeduceTransitionFromDsBehavior(config, db, i-1); assert LEnvironment_Next(db[i-1].environment, db[i].environment); assert db[i-1].environment.nextStep.LEnvStepHostIos?; var io := LIoOpSend(p); assert io in db[i-1].environment.nextStep.ios; assert ValidPhysicalEnvironmentStep(db[i-1].environment.nextStep); } lemma lemma_NetEventIsAbstractable( config:ConcreteConfiguration, db:seq, i:int, net_event:NetEvent ) requires IsValidBehavior(config, db) requires 0 <= i < |db| - 1 requires db[i].environment.nextStep.LEnvStepHostIos? requires net_event in db[i].environment.nextStep.ios ensures NetEventIsAbstractable(net_event) { if net_event.LIoOpTimeoutReceive? || net_event.LIoOpReadClock? { return; } lemma_DeduceTransitionFromDsBehavior(config, db, i); assert ValidPhysicalEnvironmentStep(db[i].environment.nextStep); assert ValidPhysicalIo(net_event); } lemma lemma_DsIsAbstractable(config:ConcreteConfiguration, db:seq, i:int) requires IsValidBehavior(config, db) requires 0 <= i < |db| requires LEnvStepIsAbstractable(last(db).environment.nextStep) ensures DsStateIsAbstractable(db[i]) { lemma_DsConsistency(config, db, i); forall p | p in db[i].environment.sentPackets ensures LPacketIsAbstractable(p) { lemma_SentPacketIsValidPhysicalPacket(config, db, i, p); } if i == |db|-1 { return; } var step := db[i].environment.nextStep; if step.LEnvStepHostIos? { forall io | io in step.ios ensures NetEventIsAbstractable(io) { lemma_NetEventIsAbstractable(config, db, i, io); } assert NetEventLogIsAbstractable(step.ios); } else if step.LEnvStepDeliverPacket? { lemma_DeduceTransitionFromDsBehavior(config, db, i); assert IsValidLEnvStep(db[i].environment, step); assert step.p in db[i].environment.sentPackets; lemma_SentPacketIsValidPhysicalPacket(config, db, i, step.p); } } lemma lemma_IosRelations(ios:seq>>, r_ios:seq>) returns (sends:set>>, r_sends:set>) requires NetEventLogIsAbstractable(ios) requires forall io :: io in ios && io.LIoOpSend? ==> LPacketIsAbstractable(io.s) requires r_ios == AbstractifyRawLogToIos(ios) ensures sends == (set io | io in ios && io.LIoOpSend? :: io.s) ensures r_sends == (set io | io in r_ios && io.LIoOpSend? :: io.s) ensures forall send :: send in sends ==> LPacketIsAbstractable(send) ensures r_sends == AbstractifyConcreteSentPackets(sends) { sends := (set io | io in ios && io.LIoOpSend? :: io.s); r_sends := (set io | io in r_ios && io.LIoOpSend? :: io.s); var refined_sends := AbstractifyConcreteSentPackets(sends); forall r | r in refined_sends ensures r in r_sends { var send :| send in sends && AbstractifyConcretePacket(send) == r; var io :| io in ios && io.LIoOpSend? && io.s == send; assert AbstractifyNetEventToRslIo(io) in r_ios; } forall r | r in r_sends ensures r in refined_sends { var r_io :| r_io in r_ios && r_io.LIoOpSend? && r_io.s == r; var j :| 0 <= j < |r_ios| && r_ios[j] == r_io; assert AbstractifyNetEventToRslIo(ios[j]) == r_io; assert ios[j] in ios; assert ios[j].s in sends; } } lemma lemma_IsValidEnvStep(de:LEnvironment>, le:LEnvironment) requires IsValidLEnvStep(de, de.nextStep) requires de.nextStep.LEnvStepHostIos? requires ConcreteEnvironmentIsAbstractable(de) requires AbstractifyConcreteEnvironment(de) == le ensures IsValidLEnvStep(le, le.nextStep) { var id := de.nextStep.actor; var ios := de.nextStep.ios; var r_ios := le.nextStep.ios; assert LIoOpSeqCompatibleWithReduction(r_ios); forall io | io in r_ios ensures IsValidLIoOp(io, id, le) { var j :| 0 <= j < |r_ios| && r_ios[j] == io; assert r_ios[j] == AbstractifyNetEventToRslIo(ios[j]); assert IsValidLIoOp(ios[j], id, de); } } lemma lemma_LEnvironmentNextHost(de :LEnvironment>, le :LEnvironment, de':LEnvironment>, le':LEnvironment) requires ConcreteEnvironmentIsAbstractable(de) requires ConcreteEnvironmentIsAbstractable(de') requires AbstractifyConcreteEnvironment(de) == le requires AbstractifyConcreteEnvironment(de') == le' requires de.nextStep.LEnvStepHostIos? requires LEnvironment_Next(de, de') ensures LEnvironment_Next(le, le') { lemma_IsValidEnvStep(de, le); var id := de.nextStep.actor; var ios := de.nextStep.ios; var r_ios := le.nextStep.ios; assert LEnvironment_PerformIos(de, de', id, ios); var sends, r_sends := lemma_IosRelations(ios, r_ios); assert de.sentPackets + sends == de'.sentPackets; assert le.sentPackets + r_sends == le'.sentPackets; assert forall r_io :: r_io in r_ios && r_io.LIoOpReceive? ==> r_io.r in le.sentPackets; assert LEnvironment_PerformIos(le, le', id, r_ios); } lemma lemma_RefinementOfUnsendablePacketHasLimitedPossibilities( p:LPacket>, g:G, rp:RslPacket ) requires g == CMessage_grammar() requires ValidGrammar(g) requires !Demarshallable(p.msg, g) || !Marshallable(parse_Message(DemarshallFunc(p.msg, g))) requires NetPacketIsAbstractable(p) requires rp == AbstractifyNetPacketToRslPacket(p) ensures || rp.msg.RslMessage_Invalid? || rp.msg.RslMessage_Request? || rp.msg.RslMessage_1b? || rp.msg.RslMessage_2a? || rp.msg.RslMessage_2b? || rp.msg.RslMessage_Reply? || rp.msg.RslMessage_AppStateSupply? { } lemma lemma_IgnoringUnsendableGivesEmptySentPackets(ios:seq) requires |ios| == 1 requires ios[0].LIoOpReceive? ensures ExtractSentPacketsFromIos(ios) == [] { reveal ExtractSentPacketsFromIos(); } lemma lemma_IgnoringInvalidMessageIsLSchedulerNext( s:LScheduler, s':LScheduler, ios:seq ) requires s.nextActionIndex == 0 requires s' == s.(nextActionIndex := (s.nextActionIndex + 1) % LReplicaNumActions()) requires |ios| == 1 requires ios[0].LIoOpReceive? requires ios[0].r.msg.RslMessage_Invalid? ensures LSchedulerNext(s, s', ios) { var sent_packets := ExtractSentPacketsFromIos(ios); lemma_IgnoringUnsendableGivesEmptySentPackets(ios); assert LReplicaNextProcessInvalid(s.replica, s'.replica, ios[0].r, sent_packets); assert LReplicaNextProcessPacketWithoutReadingClock(s.replica, s'.replica, ios); assert LReplicaNextProcessPacket(s.replica, s'.replica, ios); } lemma lemma_IgnoringInvalidRequestIsLSchedulerNext( s:LScheduler, s':LScheduler, ios:seq ) requires s.nextActionIndex == 0 requires s' == s.(nextActionIndex := (s.nextActionIndex + 1) % LReplicaNumActions()) requires |ios| == 1 requires ios[0].LIoOpReceive? requires ios[0].r.msg.RslMessage_Request? requires !CAppRequestMarshallable(ios[0].r.msg.val) ensures LSchedulerNext(s, s', ios) { var sent_packets := ExtractSentPacketsFromIos(ios); lemma_IgnoringUnsendableGivesEmptySentPackets(ios); assert LReplicaNextProcessRequest(s.replica, s'.replica, ios[0].r, sent_packets); assert LReplicaNextProcessPacketWithoutReadingClock(s.replica, s'.replica, ios); assert LReplicaNextProcessPacket(s.replica, s'.replica, ios); } lemma lemma_IgnoringReplyIsLSchedulerNext( s:LScheduler, s':LScheduler, ios:seq ) requires s.nextActionIndex == 0 requires s' == s.(nextActionIndex := (s.nextActionIndex + 1) % LReplicaNumActions()) requires |ios| == 1 requires ios[0].LIoOpReceive? requires ios[0].r.msg.RslMessage_Reply? ensures LSchedulerNext(s, s', ios) { var sent_packets := ExtractSentPacketsFromIos(ios); lemma_IgnoringUnsendableGivesEmptySentPackets(ios); assert LReplicaNextProcessReply(s.replica, s'.replica, ios[0].r, sent_packets); assert LReplicaNextProcessPacketWithoutReadingClock(s.replica, s'.replica, ios); assert LReplicaNextProcessPacket(s.replica, s'.replica, ios); } lemma lemma_IgnoringCertainMessageTypesFromNonServerIsLSchedulerNext( config:ConcreteConfiguration, db:seq, i:int, id:EndPoint, s:LScheduler, s':LScheduler, ios:seq ) requires IsValidBehavior(config, db) requires 0 <= i < |db| - 1 requires id in db[i].servers requires id in db[i+1].servers requires s == db[i].servers[id].sched requires s' == db[i+1].servers[id].sched requires s.nextActionIndex == 0 requires s' == s.(nextActionIndex := (s.nextActionIndex + 1) % LReplicaNumActions()) requires |ios| == 1 requires ios[0].LIoOpReceive? requires || ios[0].r.msg.RslMessage_1b? || ios[0].r.msg.RslMessage_2a? || ios[0].r.msg.RslMessage_2b? || ios[0].r.msg.RslMessage_AppStateSupply? requires ios[0].r.src !in config.config.replica_ids ensures LSchedulerNext(s, s', ios) { lemma_DsConstantsAllConsistent(config, db, i, id); var sent_packets := ExtractSentPacketsFromIos(ios); lemma_IgnoringUnsendableGivesEmptySentPackets(ios); assert LReplicaNextProcessPacketWithoutReadingClock(s.replica, s'.replica, ios); assert LReplicaNextProcessPacket(s.replica, s'.replica, ios); } lemma lemma_HostNextIgnoreUnsendableIsLSchedulerNext( config:ConcreteConfiguration, db:seq, i:int, id:EndPoint, ios:seq>> ) requires IsValidBehavior(config, db) requires 0 <= i < |db| - 1 requires db[i].environment.nextStep == LEnvStepHostIos(id, ios) requires id in db[i].servers requires id in db[i+1].servers requires LEnvironment_Next(db[i].environment, db[i+1].environment) requires ValidPhysicalEnvironmentStep(db[i].environment.nextStep) requires HostNextIgnoreUnsendable(db[i].servers[id].sched, db[i+1].servers[id].sched, ios) requires NetEventLogIsAbstractable(ios) ensures LSchedulerNext(db[i].servers[id].sched, db[i+1].servers[id].sched, AbstractifyRawLogToIos(ios)) { var p := ios[0].r; var rp := AbstractifyNetPacketToRslPacket(p); var g := CMessage_grammar(); assert !Demarshallable(p.msg, g) || !Marshallable(parse_Message(DemarshallFunc(p.msg, g))); assert IsValidLIoOp(ios[0], id, db[i].environment); if p.src in config.config.replica_ids { lemma_PacketSentByServerIsMarshallable(config, db, i, p); assert false; } lemma_NetEventIsAbstractable(config, db, i, ios[0]); lemma_CMessageGrammarValid(); assert ValidPhysicalIo(ios[0]); assert |p.msg| < 0x1_0000_0000_0000_0000; assert ValidGrammar(g); var rios := AbstractifyRawLogToIos(ios); assert |rios| == 1; assert rios[0].r == rp; var s := db[i].servers[id].sched; var s' := db[i+1].servers[id].sched; assert s.nextActionIndex == 0; calc { s'.nextActionIndex; 1; { lemma_mod_auto(LReplicaNumActions()); } (s.nextActionIndex + 1) % LReplicaNumActions(); } lemma_RefinementOfUnsendablePacketHasLimitedPossibilities(p, g, rp); if rp.msg.RslMessage_Invalid? { lemma_IgnoringInvalidMessageIsLSchedulerNext(s, s', rios); } else if rp.msg.RslMessage_Request? { lemma_IgnoringInvalidRequestIsLSchedulerNext(s, s', rios); } else if rp.msg.RslMessage_Reply? { lemma_IgnoringReplyIsLSchedulerNext(s, s', rios); } else { lemma_DsConsistency(config, db, i); lemma_IgnoringCertainMessageTypesFromNonServerIsLSchedulerNext(config, db, i, id, s, s', rios); } } lemma {:timeLimitMultiplier 2} lemma_RslNext( config:ConcreteConfiguration, db:seq, i:int, ls:RslState, ls':RslState ) requires IsValidBehavior(config, db) requires 0 <= i < |db| - 1 requires DsStateIsAbstractable(db[i]) requires DsStateIsAbstractable(db[i+1]) requires ls == AbstractifyDsState(db[i]) requires ls' == AbstractifyDsState(db[i+1]) requires forall id :: id in db[i].servers ==> id in db[i].config.config.replica_ids ensures RslNext(ls, ls') { var ds := db[i]; var ds' := db[i+1]; lemma_DeduceTransitionFromDsBehavior(config, db, i); if !ds.environment.nextStep.LEnvStepHostIos? { return; } lemma_LEnvironmentNextHost(db[i].environment, ls.environment, db[i+1].environment, ls'.environment); var id := ds.environment.nextStep.actor; var ios := ds.environment.nextStep.ios; var r_ios := AbstractifyRawLogToIos(ios); var replicas := ds.config.config.replica_ids; assert id in ds.servers <==> id in replicas; if id !in ds.servers { assert RslNextOneExternal(ls, ls', id, r_ios); assert RslNext(ls, ls'); return; } var index :| 0 <= index < |replicas| && replicas[index] == id; assert ls.environment.nextStep == LEnvStepHostIos(id, r_ios); assert || LSchedulerNext(ds.servers[id].sched, ds'.servers[id].sched, r_ios) || HostNextIgnoreUnsendable(ds.servers[id].sched, ds'.servers[id].sched, ios); if HostNextIgnoreUnsendable(ds.servers[id].sched, ds'.servers[id].sched, ios) { lemma_HostNextIgnoreUnsendableIsLSchedulerNext(config, db, i, id, ios); } assert LSchedulerNext(ds.servers[id].sched, ds'.servers[id].sched, r_ios); assert LEnvironment_Next(ds.environment, ds'.environment); lemma_LEnvironmentNextHost(ds.environment, ls.environment, ds'.environment, ls'.environment); assert LEnvironment_Next(ls.environment, ls'.environment); reveal SeqIsUnique(); forall other_idx | other_idx != index && 0 <= other_idx < |replicas| ensures replicas[other_idx] != replicas[index] { assert ReplicasDistinct(ls.constants.config.replica_ids, index, other_idx); } assert RslNextOneReplica(ls, ls', index, r_ios); assert RslNext(ls, ls'); } lemma lemma_GetImplBehaviorRefinement(config:ConcreteConfiguration, db:seq) returns (protocol_behavior:seq, c:LConstants) requires IsValidBehavior(config, db) requires LEnvStepIsAbstractable(last(db).environment.nextStep) ensures |protocol_behavior| == |db| ensures protocol_behavior[0].constants == AbstractifyConstantsStateToLConstants(config) ensures RslInit(c, protocol_behavior[0]) ensures forall i :: 0 <= i < |db| ==> DsStateIsAbstractable(db[i]) && protocol_behavior[i] == AbstractifyDsState(db[i]); ensures forall i {:trigger RslNext(protocol_behavior[i], protocol_behavior[i+1])} :: 0 <= i < |protocol_behavior| - 1 ==> RslNext(protocol_behavior[i], protocol_behavior[i+1]) { c := AbstractifyConstantsStateToLConstants(config); if |db| == 1 { lemma_DsIsAbstractable(config, db, 0); var ls := AbstractifyDsState(db[0]); protocol_behavior := [ ls ]; // Prove RslMapsComplete calc { |ls.replicas|; |AbstractifyConcreteReplicas(db[0].servers, db[0].config.config.replica_ids)|; |db[0].config.config.replica_ids|; |AbstractifyEndPointsToNodeIdentities(db[0].config.config.replica_ids)|; |AbstractifyConstantsStateToLConstants(db[0].config).config.replica_ids|; |ls.constants.config.replica_ids|; } calc { ls.constants; AbstractifyConstantsStateToLConstants(db[0].config); AbstractifyConstantsStateToLConstants(config); c; } forall i | 0 <= i < |c.config.replica_ids| ensures LSchedulerInit(ls.replicas[i], LReplicaConstants(i, c)) { reveal SeqIsUnique(); } forall i | 0 <= i < |db| ensures DsStateIsAbstractable(db[i]) && protocol_behavior[i] == AbstractifyDsState(db[i]) { assert i == 0; } } else { lemma_DsConsistency(config, db, |db|-1); lemma_DeduceTransitionFromDsBehavior(config, db, |db|-2); lemma_DsIsAbstractable(config, db, |db|-1); lemma_DsIsAbstractable(config, db, |db|-2); var ls' := AbstractifyDsState(last(db)); var rest, c' := lemma_GetImplBehaviorRefinement(config, all_but_last(db)); protocol_behavior := rest + [ls']; // Help with sequence indexing forall i | 0 <= i < |db| ensures DsStateIsAbstractable(db[i]) ensures protocol_behavior[i] == AbstractifyDsState(db[i]) { lemma_DsIsAbstractable(config, db, i); if i < |db| - 1 { assert db[i] == all_but_last(db)[i]; assert protocol_behavior[i] == AbstractifyDsState(all_but_last(db)[i]); assert protocol_behavior[i] == AbstractifyDsState(db[i]); } else { assert protocol_behavior[i] == ls'; assert i == |db| - 1; assert db[i] == last(db); assert protocol_behavior[i] == AbstractifyDsState(db[i]); } } // Prove the crucial ensures forall i | 0 <= i < |protocol_behavior| - 1 ensures RslNext(protocol_behavior[i], protocol_behavior[i+1]) { if i < |protocol_behavior| - 2 { // Induction hypothesis assert RslNext(protocol_behavior[i], protocol_behavior[i+1]); } else { forall id | id in db[i].servers ensures id in db[i].config.config.replica_ids { calc ==> { id in db[i].servers; id in mapdomain(db[i].servers); { lemma_DsConsistency(config, db, i); } id in mapdomain(db[0].servers); id in db[0].config.config.replica_ids; { lemma_DsConsistency(config, db, i); } id in db[i].config.config.replica_ids; } } lemma_RslNext(config, db, i, protocol_behavior[i], protocol_behavior[i+1]); assert RslNext(protocol_behavior[i], protocol_behavior[i+1]); } } } } function RenameToAppRequestMessage(request:Request) : AppRequestMessage { AppRequestMessage(request.client, request.seqno, request.request) } function RenameToAppReplyMessage(reply:Reply) : AppReplyMessage { AppReplyMessage(reply.client, reply.seqno, reply.reply) } function RenameToAppRequestMessages(requests:set) : set { set r | r in requests :: RenameToAppRequestMessage(r) } function RenameToAppReplies(replies:set) : set { set r | r in replies :: RenameToAppReplyMessage(r) } function RenameToAppBatch(batch:seq) : seq ensures |RenameToAppBatch(batch)| == |batch| ensures forall i :: 0 <= i < |batch| ==> RenameToAppBatch(batch)[i] == RenameToAppRequestMessage(batch[i]) { if |batch| == 0 then [] else RenameToAppBatch(all_but_last(batch)) + [RenameToAppRequestMessage(last(batch))] } function RenameToServiceState(rs:RSLSystemState) : ServiceState { ServiceState'(rs.server_addresses, rs.app, RenameToAppRequestMessages(rs.requests), RenameToAppReplies(rs.replies)) } function RenameToServiceStates(rs:seq) : seq ensures |rs| == |RenameToServiceStates(rs)| ensures forall i :: 0 <= i < |rs| ==> RenameToServiceState(rs[i]) == RenameToServiceStates(rs)[i] { if rs == [] then [] else [RenameToServiceState(rs[0])] + RenameToServiceStates(rs[1..]) } lemma lemma_ServiceNextDoesntChangeServerAddresses(s:ServiceState, s':ServiceState) requires s == s' || Service_Next(s, s') ensures s'.serverAddresses == s.serverAddresses { if s == s' { return; } var intermediate_states:seq, batch :| StateSequenceReflectsBatchExecution(s, s', intermediate_states, batch); var i := 0; while i < |batch| invariant 0 <= i <= |batch| invariant intermediate_states[i].serverAddresses == s.serverAddresses { assert ServiceExecutesAppRequest(intermediate_states[i], intermediate_states[i+1], batch[i]); assert intermediate_states[i+1].serverAddresses == intermediate_states[i].serverAddresses == s.serverAddresses; i := i + 1; } assert intermediate_states[i] == last(intermediate_states) == s'; } lemma lemma_ServiceStateServerAddressesNeverChange(sb:seq, server_addresses:set, i:int) requires |sb| > 0 requires Service_Init(sb[0], server_addresses) requires forall j {:trigger Service_Next(sb[j], sb[j+1])} :: 0 <= j < |sb| - 1 ==> sb[j] == sb[j+1] || Service_Next(sb[j], sb[j+1]) requires 0 <= i < |sb| ensures sb[i].serverAddresses == server_addresses { if i == 0 { return; } var j := i-1; assert sb[j] == sb[j+1] || Service_Next(sb[j], sb[j+1]); assert i == j+1; assert sb[i-1] == sb[i] || Service_Next(sb[i-1], sb[i]); lemma_ServiceNextDoesntChangeServerAddresses(sb[i-1], sb[i]); assert sb[i].serverAddresses == sb[i-1].serverAddresses; lemma_ServiceStateServerAddressesNeverChange(sb, server_addresses, i-1); } lemma lemma_RslSystemNextImpliesServiceNext( rs:RSLSystemState, rs':RSLSystemState, s:ServiceState, s':ServiceState' ) requires s == RenameToServiceState(rs) requires s' == RenameToServiceState(rs') requires RslSystemNext(rs, rs') ensures Service_Next(s, s') { var intermediate_states, batch :| RslStateSequenceReflectsBatchExecution(rs, rs', intermediate_states, batch); var intermediate_states_renamed := RenameToServiceStates(intermediate_states); var batch_renamed := RenameToAppBatch(batch); assert StateSequenceReflectsBatchExecution(s, s', intermediate_states_renamed, batch_renamed); } lemma lemma_RequestSizeBounded(server_addresses:set, rb:seq, pos:int) requires |rb| > 0 requires RslSystemInit(rb[0], server_addresses) requires forall i {:trigger RslSystemNext(rb[i], rb[i+1])} :: 0 <= i < |rb| - 1 ==> rb[i] == rb[i+1] || RslSystemNext(rb[i], rb[i+1]) requires 0 <= pos < |rb| ensures forall req :: req in rb[pos].requests ==> |req.request| <= MaxAppRequestSize() { if pos == 0 { return; } var prev := pos - 1; assert rb[pos] == rb[prev] || RslSystemNext(rb[prev], rb[prev+1]); lemma_RequestSizeBounded(server_addresses, rb, prev); if (rb[pos] == rb[prev]) { return; } var s := rb[prev]; var s' := rb[prev+1]; var intermediate_states:seq, batch:seq :| RslStateSequenceReflectsBatchExecution(s, s', intermediate_states, batch); var which_req := 0; while which_req < |batch| invariant 0 <= which_req <= |batch| invariant forall req :: req in intermediate_states[which_req].requests ==> |req.request| <= MaxAppRequestSize() { assert RslSystemNextServerExecutesRequest(intermediate_states[which_req], intermediate_states[which_req+1], batch[which_req]); which_req := which_req + 1; } } lemma{:timeLimitMultiplier 4} lemma_RefinementProofForFixedBehavior(config:ConcreteConfiguration, db:seq) returns (sb:seq) requires IsValidBehavior(config, db) requires last(db).environment.nextStep.LEnvStepStutter? ensures |db| == |sb| ensures Service_Init(sb[0], mapdomain(db[0].servers)) ensures forall i {:trigger Service_Next(sb[i], sb[i+1])} :: 0 <= i < |sb| - 1 ==> sb[i] == sb[i+1] || Service_Next(sb[i], sb[i+1]) ensures forall i :: 0 <= i < |db| ==> Service_Correspondence(db[i].environment.sentPackets, sb[i]) { var protocol_behavior, lconstants := lemma_GetImplBehaviorRefinement(config, db); var rs := lemma_GetBehaviorRefinement(protocol_behavior, lconstants); sb := RenameToServiceStates(rs); var server_addresses := MapSeqToSet(config.config.replica_ids, x=>x); assert Service_Init(sb[0], server_addresses); forall i {:trigger Service_Next(sb[i], sb[i+1])} | 0 <= i < |sb| - 1 ensures sb[i] == sb[i+1] || Service_Next(sb[i], sb[i+1]) { lemma_RslSystemNextImpliesServiceNext(rs[i], rs[i+1], sb[i], sb[i+1]); } forall i | 0 <= i < |db| ensures Service_Correspondence(db[i].environment.sentPackets, sb[i]) { var concretePkts := db[i].environment.sentPackets; var serviceState := sb[i]; var rsl := rs[i]; var ps := protocol_behavior[i]; assert RslSystemRefinement(ps, rsl); assert RenameToServiceState(rsl) == serviceState; forall p, seqno, reply | p in concretePkts && p.src in serviceState.serverAddresses && p.msg == MarshallServiceReply(seqno, reply) ensures AppReplyMessage(p.dst, seqno, reply) in serviceState.replies; { var abstract_p := AbstractifyConcretePacket(p); lemma_ServiceStateServerAddressesNeverChange(sb, server_addresses, i); assert serviceState.serverAddresses == server_addresses; assert p.src in config.config.replica_ids; lemma_PacketSentByServerIsMarshallable(config, db, i, p); lemma_ParseMarshallReply(p.msg, seqno, reply, abstract_p.msg); assert abstract_p in ps.environment.sentPackets && abstract_p.src in rsl.server_addresses && abstract_p.msg.RslMessage_Reply?; var r := Reply(abstract_p.dst, abstract_p.msg.seqno_reply, abstract_p.msg.reply); assert r in rsl.replies; var service_reply := RenameToAppReplyMessage(r); assert service_reply == AppReplyMessage(p.dst, seqno, reply); assert service_reply in serviceState.replies; } forall req | req in serviceState.requests ensures exists p :: p in concretePkts && p.dst in serviceState.serverAddresses && p.msg == MarshallServiceRequest(req.seqno, req.request) && p.src == req.client { var r_req :| r_req in rsl.requests && RenameToAppRequestMessage(r_req) == req; var abstract_p :| && abstract_p in ps.environment.sentPackets && abstract_p.dst in rsl.server_addresses && abstract_p.msg.RslMessage_Request? && r_req == Request(abstract_p.src, abstract_p.msg.seqno_req, abstract_p.msg.val); lemma_RequestSizeBounded(server_addresses, rs, i); assert |r_req.request| <= MaxAppRequestSize(); assert ps.environment.sentPackets == AbstractifyConcreteSentPackets(concretePkts); var concrete_p :| concrete_p in concretePkts && AbstractifyConcretePacket(concrete_p) == abstract_p; assert concrete_p.dst in serviceState.serverAddresses; assert concrete_p.src == req.client; lemma_ParseMarshallRequest(concrete_p.msg, abstract_p.msg); assert concrete_p.msg == MarshallServiceRequest(req.seqno, req.request); } } } lemma lemma_FixFinalEnvStep(config:ConcreteConfiguration, db:seq) returns (db':seq) requires IsValidBehavior(config, db) ensures |db'| == |db| ensures DS_Init(db'[0], config) ensures forall i {:trigger DS_Next(db'[i], db'[i+1])} :: 0 <= i < |db'| - 1 ==> DS_Next(db'[i], db'[i+1]) ensures last(db').environment.nextStep.LEnvStepStutter? ensures forall i :: 0 <= i < |db'| - 1 ==> db'[i] == db[i] ensures last(db') == last(db).(environment := last(db').environment) ensures last(db').environment == last(db).environment.(nextStep := LEnvStepStutter()) { var sz := |db|; db' := all_but_last(db) + [last(db).(environment := last(db).environment.(nextStep := LEnvStepStutter()))]; assert |db'| == |db|; forall i | 0 <= i < |db'| - 1 ensures DS_Next(db'[i], db'[i+1]) { lemma_DeduceTransitionFromDsBehavior(config, db, i); if i == sz - 2 { assert DS_Next(db'[i], db'[i+1]); } } } lemma RefinementProof(config:DS_s.H_s.ConcreteConfiguration, db:seq) returns (sb:seq) { var db' := lemma_FixFinalEnvStep(config, db); sb := lemma_RefinementProofForFixedBehavior(config, db'); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Services/RSL/Marshall.i.dfy ================================================ include "AbstractService.s.dfy" include "../../Protocol/RSL/Message.i.dfy" include "../../Impl/RSL/PacketParsing.i.dfy" module MarshallProof_i { import opened Native__NativeTypes_s import opened AppStateMachine_s import opened AbstractServiceRSL_s import opened LiveRSL__AppInterface_i import opened LiveRSL__CMessage_i import opened LiveRSL__CMessageRefinements_i import opened LiveRSL__Message_i import opened LiveRSL__PacketParsing_i import opened Common__GenericMarshalling_i import opened Common__Util_i import opened Math__power2_i lemma lemma_ParseValCorrectVCase(data:seq, v:V, g:G) returns (caseId:uint64, val:V, rest:seq) requires ValInGrammar(v, g) requires |data| < 0x1_0000_0000_0000_0000 requires ValidGrammar(g) requires parse_Val(data, g).0.Some? requires parse_Val(data, g).0.v == v requires g.GTaggedUnion? ensures parse_Uint64(data).0.Some? ensures caseId == parse_Uint64(data).0.v.u ensures 0 <= caseId as int < |g.cases| ensures rest == parse_Uint64(data).1 ensures parse_Val(rest, g.cases[caseId]).0.Some? ensures val == parse_Val(rest, g.cases[caseId]).0.v ensures v == VCase(caseId, val) ensures ValInGrammar(val, g.cases[caseId]) { reveal parse_Val(); caseId := parse_Uint64(data).0.v.u; var tuple := parse_Val(parse_Uint64(data).1, g.cases[caseId]); val := tuple.0.v; rest := parse_Uint64(data).1; } lemma {:fuel ValInGrammar,3} lemma_ParseValCorrectTuple2(data:seq, v:V, g:G) returns (val0:V, val1:V, rest:seq) requires ValInGrammar(v, g) requires |data| < 0x1_0000_0000_0000_0000 requires ValidGrammar(g) requires parse_Val(data, g).0.Some? requires parse_Val(data, g).0.v == v requires g.GTuple? requires |g.t| == 2 ensures parse_Val(data, g.t[0]).0.Some? ensures val0 == parse_Val(data, g.t[0]).0.v ensures ValInGrammar(val0, g.t[0]) ensures rest == parse_Val(data, g.t[0]).1 ensures parse_Val(rest, g.t[1]).0.Some? ensures val1 == parse_Val(rest, g.t[1]).0.v ensures ValInGrammar(val1, g.t[1]) ensures v == VTuple([val0, val1]) { reveal parse_Val(); reveal parse_Tuple_contents(); // Prove that v == VTuple([val0, val1]); assert parse_Val(data, g).0.v == parse_Tuple(data, g.t).0.v == VTuple(parse_Tuple_contents(data, g.t).0.v); assert parse_Tuple_contents(data, g.t).0.v == [parse_Val(data, g.t[0]).0.v] + parse_Tuple_contents(parse_Val(data, g.t[0]).1, g.t[1..]).0.v; assert [parse_Val(data, g.t[0]).0.v] + parse_Tuple_contents(parse_Val(data, g.t[0]).1, g.t[1..]).0.v == [parse_Val(data, g.t[0]).0.v] + [parse_Val(parse_Val(data, g.t[0]).1, g.t[1]).0.v]; assert [parse_Val(data, g.t[0]).0.v] + [parse_Val(parse_Val(data, g.t[0]).1, g.t[1]).0.v] == [parse_Val(data, g.t[0]).0.v, parse_Val(parse_Val(data, g.t[0]).1, g.t[1]).0.v]; assert |v.t| == 2; var tuple0 := parse_Val(data, g.t[0]); assert tuple0.0.Some?; val0,rest := tuple0.0.v, tuple0.1; var tuple1 := parse_Val(rest, g.t[1]); var foo; val1,foo := tuple1.0.v, tuple1.1; // Prove that rest is set correctly assert parse_Val(data, g).1 == parse_Tuple(data, g.t).1 == parse_Tuple_contents(data, g.t).1; assert parse_Tuple_contents(data, g.t).1 == parse_Tuple_contents(parse_Val(data, g.t[0]).1, g.t[1..]).1; //assert parse_Tuple_contents(parse_Val(data, g.t[0]).1, g.t[1..]).1 == rest; } lemma lemma_ParseValCorrectVUint64(data:seq, v:V, g:G) returns (u:uint64, rest:seq) requires ValInGrammar(v, g) requires |data| < 0x1_0000_0000_0000_0000 requires ValidGrammar(g) requires parse_Val(data, g).0.Some? requires parse_Val(data, g).0.v == v requires g.GUint64? ensures parse_Uint64(data).0.Some? ensures u == parse_Uint64(data).0.v.u ensures v == VUint64(u) ensures rest == parse_Val(data, g).1 { reveal parse_Val(); u := parse_Uint64(data).0.v.u; rest := parse_Uint64(data).1; } lemma ByteArrayOf8(bytes:seq, b:byte) requires |bytes| == 8 requires SeqByteToUint64(bytes) == b as uint64 ensures bytes == [ 0, 0, 0, 0, 0, 0, 0, b] { } lemma ByteConcat24(bytes:seq) requires |bytes| >= 24 ensures bytes[0..24] == bytes[0..8] + bytes[8..16] + bytes[16..24] { } lemma ByteConcat32(bytes:seq) requires |bytes| >= 32 ensures bytes[0..32] == bytes[0..8] + bytes[8..16] + bytes[16..24] + bytes[24..32] { } lemma {:fuel ValInGrammar,3} lemma_ParseMarshallRequest(bytes:seq, msg:RslMessage) requires msg.RslMessage_Request? requires CMessageIsAbstractable(PaxosDemarshallData(bytes)) requires AbstractifyCMessageToRslMessage(PaxosDemarshallData(bytes)) == msg requires |msg.val| <= MaxAppRequestSize(); ensures bytes == MarshallServiceRequest(msg.seqno_req, msg.val) { var cmsg := PaxosDemarshallData(bytes); assert cmsg.CMessage_Request?; assert cmsg.seqno as int == msg.seqno_req; assert AbstractifyCAppRequestToAppRequest(cmsg.val) == msg.val; var data := bytes; var g := CMessage_grammar(); var v := DemarshallFunc(data, g); // Walk through the generic parsing process var msgCaseId, msgCaseVal, rest0 := lemma_ParseValCorrectVCase(data, v, g); var seqnoVal, appVal, rest1 := lemma_ParseValCorrectTuple2(rest0, msgCaseVal, g.cases[msgCaseId]); // Prove that the first 8 bytes are correct assert msgCaseId == 0; assert 0 == SeqByteToUint64(bytes[0..8]); ByteArrayOf8(bytes[0..8], 0); // Prove that the next 8 bytes are correct var u, rest := lemma_ParseValCorrectVUint64(rest0, seqnoVal, GUint64); assert msg.seqno_req == u as int; assert SeqByteToUint64(rest0[0..8]) == u; assert Uint64ToSeqByte(u) == AbstractServiceRSL_s.Uint64ToBytes(u); lemma_BEByteSeqToInt_BEUintToSeqByte_invertability(); assert rest0[0..8] == Uint64ToSeqByte(msg.seqno_req as uint64); assert data[8..16] == rest0[0..8]; reveal parse_Val(); var request_len, rest2 := lemma_ParseValCorrectVUint64(rest1, VUint64(|msg.val| as uint64), GUint64); assert |msg.val| == request_len as int; assert Uint64ToSeqByte(request_len) == AbstractServiceRSL_s.Uint64ToBytes(request_len); assert rest1[0..8] == Uint64ToSeqByte(|msg.val| as uint64); assert rest1[8..] == rest2 == msg.val; calc { bytes; bytes[0..8] + rest0; [ 0, 0, 0, 0, 0, 0, 0, 0] + rest0; [ 0, 0, 0, 0, 0, 0, 0, 0] + (rest0[0..8] + rest1); [ 0, 0, 0, 0, 0, 0, 0, 0] + (Uint64ToBytes(msg.seqno_req as uint64) + rest1); [ 0, 0, 0, 0, 0, 0, 0, 0] + Uint64ToBytes(msg.seqno_req as uint64) + rest1; [ 0, 0, 0, 0, 0, 0, 0, 0] + Uint64ToBytes(msg.seqno_req as uint64) + (rest1[0..8] + rest1[8..]); [ 0, 0, 0, 0, 0, 0, 0, 0] + Uint64ToBytes(msg.seqno_req as uint64) + (Uint64ToBytes(|msg.val| as uint64) + rest1[8..]); [ 0, 0, 0, 0, 0, 0, 0, 0] + Uint64ToBytes(msg.seqno_req as uint64) + Uint64ToBytes(|msg.val| as uint64) + rest1[8..]; [ 0, 0, 0, 0, 0, 0, 0, 0] + Uint64ToBytes(msg.seqno_req as uint64) + Uint64ToBytes(|msg.val| as uint64) + msg.val; MarshallServiceRequest(msg.seqno_req, msg.val); } } lemma {:timeLimitMultiplier 5} {:fuel ValInGrammar,3} lemma_ParseMarshallReply(bytes:seq, seqno:int, reply:AppReply, msg:RslMessage) requires CMessageIsAbstractable(PaxosDemarshallData(bytes)) requires AbstractifyCMessageToRslMessage(PaxosDemarshallData(bytes)) == msg requires Marshallable(PaxosDemarshallData(bytes)) requires bytes == MarshallServiceReply(seqno, reply) ensures msg.RslMessage_Reply? ensures msg.seqno_reply == seqno ensures msg.reply == reply { var marshalled_bytes := MarshallServiceReply(seqno, reply); var g := CMessage_grammar(); if 0 <= seqno < 0x1_0000_0000_0000_0000 && |reply| <= MaxAppReplySize() { assert marshalled_bytes == [ 0, 0, 0, 0, 0, 0, 0, 6] + AbstractServiceRSL_s.Uint64ToBytes(seqno as uint64) + AbstractServiceRSL_s.Uint64ToBytes(|reply| as uint64) + reply; var cmsg := PaxosDemarshallData(bytes); var data := bytes; var v := DemarshallFunc(data, g); // Walk through the generic parsing process var msgCaseId, msgCaseVal, rest0 := lemma_ParseValCorrectVCase(data, v, g); assert msgCaseId == 6; var seqnoVal, appVal, rest1 := lemma_ParseValCorrectTuple2(rest0, msgCaseVal, g.cases[msgCaseId]); // Prove that the first 8 bytes are correct assert msgCaseId == SeqByteToUint64(bytes[..8]) == 6; assert cmsg.CMessage_Reply?; // Prove the seqno is parsed correctly assert rest0 == AbstractServiceRSL_s.Uint64ToBytes(seqno as uint64) + AbstractServiceRSL_s.Uint64ToBytes(|reply| as uint64) + reply; var u, rest := lemma_ParseValCorrectVUint64(rest0, seqnoVal, GUint64); lemma_2toX(); calc { u; parse_Uint64(rest0).0.v.u; SeqByteToUint64(rest0[..8]); SeqByteToUint64(AbstractServiceRSL_s.Uint64ToBytes(seqno as uint64)); SeqByteToUint64(Uint64ToSeqByte(seqno as uint64)); SeqByteToUint64(BEUintToSeqByte(seqno as uint64 as int, 8)); { lemma_BEByteSeqToInt_BEUintToSeqByte_invertability(); } seqno as uint64; } assert cmsg.seqno_reply as int == msg.seqno_reply; // Prove the app bytes are parsed correctly reveal parse_Val(); var reply_len, rest2 := lemma_ParseValCorrectVUint64(rest1, VUint64(|msg.reply| as uint64), GUint64); assert |msg.reply| == reply_len as int; assert Uint64ToSeqByte(reply_len) == AbstractServiceRSL_s.Uint64ToBytes(reply_len); assert rest1[0..8] == Uint64ToSeqByte(|msg.reply| as uint64); assert rest1[8..] == rest2 == msg.reply; } else { assert bytes == [1]; reveal parse_Val(); assert parse_Val(bytes, g).0.None?; assert false; } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Services/RSL/Program.cs ================================================ using IronfleetCommon; using IronfleetIoFramework; using IronRSL; using MathNet.Numerics.Distributions; using System; using System.IO; using System.Linq; using System.Numerics; using System.Threading; namespace IronRSLServer { public class Params { private string serviceFileName; private string privateKeyFileName; private string localHostNameOrAddress; private int localPort; private bool profile; private bool progress; private bool verbose; private bool safeguard; public Params() { serviceFileName = ""; privateKeyFileName = ""; localHostNameOrAddress = ""; localPort = 0; profile = false; progress = false; verbose = false; safeguard = true; } public string ServiceFileName { get { return serviceFileName; } } public string PrivateKeyFileName { get { return privateKeyFileName; } } public string LocalHostNameOrAddress { get { return localHostNameOrAddress; } } public int LocalPort { get { return localPort; } } public bool Profile { get { return profile; } } public bool Progress { get { return progress; } } public bool Verbose { get { return verbose; } } public bool Safeguard { get { return safeguard; } } public bool Validate() { if (serviceFileName.Length == 0) { Console.WriteLine("ERROR - Missing service parameter"); return false; } if (privateKeyFileName.Length == 0) { Console.WriteLine("ERROR - Missing private parameter"); return false; } return true; } public bool ProcessCommandLineArgument(string arg) { var pos = arg.IndexOf("="); if (pos < 0) { if (serviceFileName.Length == 0) { serviceFileName = arg; return true; } else if (privateKeyFileName.Length == 0) { privateKeyFileName = arg; return true; } else { Console.WriteLine("ERROR - Invalid argument {0}", arg); return false; } } var key = arg.Substring(0, pos).ToLower(); var value = arg.Substring(pos + 1); return SetValue(key, value); } private bool SetBoolValue(string key, string value, ref bool p) { if (value == "false") { p = false; return true; } else if (value == "true") { p = true; return true; } else { Console.WriteLine("ERROR - Invalid {0} value {1} - should be false or true", key, value); return false; } } private bool SetValue(string key, string value) { if (key == "addr") { localHostNameOrAddress = value; return true; } if (key == "port") { try { localPort = Convert.ToInt32(value); return true; } catch (Exception e) { Console.WriteLine("ERROR - Could not convert port {0} to a number. Exception:\n{1}", value, e); return false; } } if (key == "profile") { return SetBoolValue(key, value, ref profile); } if (key == "progress") { return SetBoolValue(key, value, ref progress); } if (key == "verbose") { return SetBoolValue(key, value, ref verbose); } if (key == "safeguard") { return SetBoolValue(key, value, ref safeguard); } Console.WriteLine("ERROR - Invalid argument key {0}", key); return false; } } class Program { static void usage() { Console.Write(@" Usage: dotnet IronRSL{0}Server.dll [key=value]... - file path of the service description - file path of the private key Allowed keys: addr - local host name or address to listen to (default: whatever's specified in the private key file) port - port to listen to (default: whatever's specified in the private key file) profile - print profiling info (false or true, default: false) progress - print progress (false or true, default: false) verbose - use verbose output (false or true, default: false) safeguard - delete the private key file after reading it to prevent running the same instance twice (false or true, default: true [see below]) You should only run an instance of this server once, since we haven't implemented crash recovery. To prevent you from accidentally running it multiple times, this program deletes its private key file right after reading it. You can override this behavior with safeguard=false, but this is a VERY UNSAFE thing to do. Fortunately, IronRSL can deal with the failure of fewer than half its servers. But, if half of them or more fail, you'll have to create a new service. That is, you'll have to start over by running CreateIronServiceCerts, and that new service will be in its initial state. ", Service.Name); } static void Main(string[] args) { Console.WriteLine("IronRSL{0}Server program started", Service.Name); Console.WriteLine("Processing command-line arguments"); Params ps = new Params(); foreach (var arg in args) { if (!ps.ProcessCommandLineArgument(arg)) { usage(); return; } } if (!ps.Validate()) { usage(); return; } ServiceIdentity serviceIdentity = ServiceIdentity.ReadFromFile(ps.ServiceFileName); if (serviceIdentity == null) { return; } if (serviceIdentity.ServiceType != "IronRSL" + Service.Name) { Console.Error.WriteLine("Provided service identity has type {0}, not IronRSL{1}.", serviceIdentity.ServiceType, Service.Name); return; } PrivateIdentity privateIdentity = PrivateIdentity.ReadFromFile(ps.PrivateKeyFileName); if (privateIdentity == null) { return; } Native____Io__s_Compile.PrintParams.SetParameters(ps.Profile, ps.Progress); if (ps.Safeguard) { File.Delete(ps.PrivateKeyFileName); Console.WriteLine("Deleted private key file after reading it since RSL servers should never run twice."); } else { Console.WriteLine(@" *** DANGER: Because you specified safeguard=false, we didn't delete the *** *** private key file to prevent you from running the RSL server twice. *** *** Hopefully, you're just testing things. *** "); } var nc = Native____Io__s_Compile.NetClient.Create(privateIdentity, ps.LocalHostNameOrAddress, ps.LocalPort, serviceIdentity.Servers, ps.Verbose, serviceIdentity.UseSsl); Dafny.ISequence[] serverPublicKeys = serviceIdentity.Servers.Select(server => Dafny.Sequence.FromArray(nc.HashPublicKey(server.PublicKey))).ToArray(); var ironArgs = Dafny.Sequence>.FromArray(serverPublicKeys); Profiler.Initialize(); Native____Io__s_Compile.Time.Initialize(); Console.WriteLine("[[READY]]"); Main__i_Compile.__default.IronfleetMain(nc, ironArgs); Console.WriteLine("[[EXIT]]"); } } } namespace AppStateMachine__s_Compile { public partial class AppStateMachine { Service service; internal AppStateMachine(Service i_service) { service = i_service; } public static AppStateMachine Initialize() { return new AppStateMachine(Service.Initialize()); } public static AppStateMachine Deserialize(Dafny.ISequence state) { return new AppStateMachine(Service.Deserialize(state.Elements)); } public Dafny.ISequence Serialize() { return Dafny.Sequence.FromArray(service.Serialize()); } public Dafny.ISequence HandleRequest(Dafny.ISequence request) { return Dafny.Sequence.FromArray(service.HandleRequest(request.Elements)); } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Services/RSL/RSLDistributedSystem.i.dfy ================================================ include "../../Impl/RSL/Host.i.dfy" include "../../Common/Framework/DistributedSystem.s.dfy" module RSL_DistributedSystem_i refines DistributedSystem_s { import H_s = Host_i } ================================================ FILE: ironfleet/src/Dafny/Distributed/Services/SHT/.gitignore ================================================ Main.i.cs build/ ================================================ FILE: ironfleet/src/Dafny/Distributed/Services/SHT/AbstractService.s.dfy ================================================ include "../../Common/Framework/AbstractService.s.dfy" include "AppInterface.s.dfy" include "HT.s.dfy" module AbstractServiceSHT_s refines AbstractService_s { import opened Bytes_s import opened AppInterface_i`Spec import opened SHT__HT_s export Spec provides Native__Io_s, Environment_s, Native__NativeTypes_s provides ServiceState provides Service_Init, Service_Next, Service_Correspondence reveals AppRequest, AppReply provides AppInterface_i, SHT__HT_s provides MarshallServiceGetRequest, MarshallServiceSetRequest, MarshallServiceReply export All reveals * datatype AppRequest = AppGetRequest(g_seqno:int, g_k:Key) | AppSetRequest(s_seqno:int, s_k:Key, ov:OptionalValue) datatype AppReply = AppReply(seqno:int, k:Key, ov:OptionalValue) datatype ServiceState' = ServiceState'( serverAddresses:set, ht:Hashtable, requests:set, replies:set ) type ServiceState = ServiceState' predicate Service_Init(s:ServiceState, serverAddresses:set) { s.serverAddresses == serverAddresses && SpecInit(s.ht) && s.requests == {} && s.replies == {} } /*predicate Service_Next_ServerReceivesRequest(s:ServiceState, s':ServiceState, req:AppRequest) { s'.requests == s.requests + { req } }*/ predicate Service_Next_ServerExecutesRequest(s:ServiceState, s':ServiceState, req:AppRequest, rep:AppReply) { s'.serverAddresses == s.serverAddresses && s'.requests == s.requests + { req } && (req.AppGetRequest? ==> Get(s.ht, s'.ht, req.g_k, rep.ov) && s'.replies == s.replies + { rep } && req.g_k == rep.k) && (req.AppSetRequest? ==> Set(s.ht, s'.ht, req.s_k, req.ov) && s'.replies == s.replies + { rep } && req.s_k == rep.k && req.ov == rep.ov) } predicate Service_Next(s:ServiceState, s':ServiceState) { exists request, reply :: Service_Next_ServerExecutesRequest(s, s', request, reply) //|| exists request :: Service_Next_ServerReceivesRequest(s, s', request) } function MarshallServiceGetRequest(app:AppRequest, reserved:seq) : seq requires app.AppGetRequest? { if 0 <= app.g_seqno < 0x1_0000_0000_0000_0000 && |reserved| < 0x10_0000 then [ 0, 0, 0, 0, 0, 0, 0, 0] // CSingleMessage_grammar magic number + Uint64ToBytes(app.g_seqno as uint64) + Uint64ToBytes(|reserved| as uint64) + reserved + [ 0, 0, 0, 0, 0, 0, 0, 0] // CMessage_GetRequest_grammar magic number + MarshallSHTKey(app.g_k) else [ 1 ] } function MarshallServiceSetRequest(app:AppRequest, reserved:seq) : seq requires app.AppSetRequest? { if 0 <= app.s_seqno < 0x1_0000_0000_0000_0000 && |reserved| < 0x10_0000 then [ 0, 0, 0, 0, 0, 0, 0, 0] // CSingleMessage_grammar magic number + Uint64ToBytes(app.s_seqno as uint64) + Uint64ToBytes(|reserved| as uint64) + reserved + [ 0, 0, 0, 0, 0, 0, 0, 1] // CMessage_SetRequest_grammar magic number + MarshallSHTKey(app.s_k) + if app.ov.ValuePresent? then [ 0, 0, 0, 0, 0, 0, 0, 0] // ValuePresent magic number + MarshallSHTValue(app.ov.v) else [ 0, 0, 0, 0, 0, 0, 0, 1] // ValueAbsent magic number else [ 1 ] } function MarshallServiceReply(app:AppReply, reserved:seq) : seq { if 0 <= app.seqno < 0x1_0000_0000_0000_0000 && |reserved| < 0x10_0000 then [ 0, 0, 0, 0, 0, 0, 0, 0] // CSingleMessage_grammar magic number + Uint64ToBytes(app.seqno as uint64) + Uint64ToBytes(|reserved| as uint64) + reserved + [ 0, 0, 0, 0, 0, 0, 0, 2] // CMessage_Reply_grammar magic number + MarshallSHTKey(app.k) + if app.ov.ValuePresent? then [ 0, 0, 0, 0, 0, 0, 0, 0] // ValuePresent magic number + MarshallSHTValue(app.ov.v) else [ 0, 0, 0, 0, 0, 0, 0, 1] // ValueAbsent magic number else [ 1 ] } predicate Service_Correspondence(concretePkts:set>>, serviceState:ServiceState) { (forall p, reply, reserved_bytes :: p in concretePkts && p.src in serviceState.serverAddresses && p.msg == MarshallServiceReply(reply, reserved_bytes) && |reserved_bytes| < 0x10_0000 ==> reply in serviceState.replies) && (forall req :: req in serviceState.requests && req.AppGetRequest? ==> exists p, reserved_bytes :: p in concretePkts && p.dst in serviceState.serverAddresses && p.msg == MarshallServiceGetRequest(req, reserved_bytes) && |reserved_bytes| < 0x10_0000) && (forall req :: req in serviceState.requests && req.AppSetRequest? ==> exists p, reserved_bytes :: p in concretePkts && p.dst in serviceState.serverAddresses && p.msg == MarshallServiceSetRequest(req, reserved_bytes) && |reserved_bytes| < 0x10_0000) } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Services/SHT/AppInterface.i.dfy ================================================ include "AppInterface.s.dfy" include "Bytes.s.dfy" module AppInterface_i refines AppInterface_s { import opened Bytes_s export Spec provides Native__NativeTypes_s reveals Key // provides Key REVIEW: triggers a Dafny bug provides Value provides KeyLt provides lemma_KeyOrdering provides KeyMin, ValidKey, ValidValue, MarshallSHTKey, MarshallSHTValue export All reveals * type Key(==, !new) = uint64 type Value = seq predicate method KeyLt(ka:Key, kb:Key) { ka < kb } lemma lemma_KeyOrdering() { } function max_key_len() : int { 16 } function max_val_len() : int { 1024 } predicate ValidKey(key:Key) { true } predicate ValidValue(v:Value) { |v| < max_val_len() } function method KeyMin() : Key { 0 } function MarshallSHTKey(k:Key) : seq { Uint64ToBytes(k) } function MarshallSHTValue(v:Value) : seq { if |v| < 0x1_0000_0000_0000_0000 then Uint64ToBytes(|v| as uint64) + v else [] // We only handle reasonably sized values } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Services/SHT/AppInterface.s.dfy ================================================ include "../../Common/Native/NativeTypes.s.dfy" abstract module AppInterface_s { import opened Native__NativeTypes_s type Key(==, !new) type Value predicate method KeyLt(ka:Key, kb:Key) lemma lemma_KeyOrdering() ensures forall k,k' :: KeyLt(k,k') ==> !KeyLt(k',k); // Antisymmetry ensures forall k,k' :: !KeyLt(k,k') ==> KeyLt(k',k) || k' == k; ensures forall k,k',k'' :: KeyLt(k,k') && KeyLt(k',k'') ==> KeyLt(k, k''); // Transitivity function method KeyMin() : Key ensures forall k :: k == KeyMin() || KeyLt(KeyMin(), k); predicate ValidKey(key:Key) predicate ValidValue(v:Value) function MarshallSHTKey(k:Key) : seq function MarshallSHTValue(v:Value) : seq } ================================================ FILE: ironfleet/src/Dafny/Distributed/Services/SHT/Bytes.s.dfy ================================================ include "../../Common/Native/NativeTypes.s.dfy" module Bytes_s { import opened Native__NativeTypes_s function Uint64ToBytes(u:uint64) : seq { [( u/0x1000000_00000000 ) as byte, ((u/ 0x10000_00000000)%0x100) as byte, ((u/ 0x100_00000000)%0x100) as byte, ((u/ 0x1_00000000)%0x100) as byte, ((u/ 0x1000000)%0x100) as byte, ((u/ 0x10000)%0x100) as byte, ((u/ 0x100)%0x100) as byte, ( u %0x100) as byte] } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Services/SHT/HT.s.dfy ================================================ include "AppInterface.i.dfy" include "../../Common/Collections/Maps2.s.dfy" //////////////////////////////////////////////////////// // High-level spec for SHT is simply a hash table //////////////////////////////////////////////////////// module SHT__HT_s { import opened Collections__Maps2_s import opened AppInterface_i`Spec datatype OptionalValue = ValuePresent(v:Value) | ValueAbsent() type Hashtable = map predicate SpecInit(h:Hashtable) { h == map [] } predicate Set(h:Hashtable, h':Hashtable, k:Key, ov:OptionalValue) { h' == if ov.ValuePresent? then h[k := ov.v] else mapremove(h, k) } predicate Get(h:Hashtable, h':Hashtable, k:Key, ov:OptionalValue) { h' == h && ov == if k in h then ValuePresent(h[k]) else ValueAbsent() } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Services/SHT/Main.i.dfy ================================================ include "../../Common/Framework/Main.s.dfy" include "SHTDistributedSystem.i.dfy" include "../../Impl/LiveSHT/Host.i.dfy" include "../../Common/Collections/Maps2.s.dfy" include "../../Protocol/SHT/RefinementProof/RefinementProof.i.dfy" include "../../Protocol/Common/NodeIdentity.i.dfy" include "../../Protocol/LiveSHT/RefinementProof/SHTLemmas.i.dfy" include "Marshall.i.dfy" include "../../Protocol/SHT/Network.i.dfy" module Main_i refines Main_s { import opened AS_s = AbstractServiceSHT_s`Spec import opened DS_s = SHT_DistributedSystem_i import opened DS_s.H_s import opened Math__mod_auto_i import opened Collections__Sets_i import opened Collections__Maps2_s import opened Collections__Maps2_i import opened Environment_s import opened Common__SeqIsUniqueDef_i import opened SHT__RefinementProof_i import opened Concrete_NodeIdentity_i import opened RefinementProof__DistributedSystemLemmas_i import opened MarshallProof_i import opened SHT__SHT_i import opened SHT__Network_i import opened SHT__Message_i import opened SHT__SingleMessage_i import opened SHT__Configuration_i import opened SHT__CMessage_i import opened SHT__PacketParsing_i import opened SHT__ConstantsState_i import opened SHT__SHTConcreteConfiguration_i import opened SHT__Host_i import opened SHT__Delegations_i import opened SHT__InvDefs_i import opened SHT__InvProof_i import opened SHT__Refinement_i import opened LiveSHT__NetSHT_i import opened LiveSHT__SHT_i import opened LiveSHT__Environment_i import opened LiveSHT__Scheduler_i import opened LiveSHT__Unsendable_i import opened LiveSHT__SHTRefinement_i import opened Common__GenericMarshalling_i import opened Common__NetClient_i import opened Common__NodeIdentity_i export provides DS_s, Native__Io_s, Native__NativeTypes_s provides IronfleetMain predicate IsValidBehavior(config:ConcreteConfiguration, db:seq) reads *; { |db| > 0 && DS_Init(db[0], config) && (forall i {:trigger DS_Next(db[i], db[i+1])} :: 0 <= i < |db| - 1 ==> DS_Next(db[i], db[i+1])) } predicate LPacketIsAbstractable(cp:LPacket>) { CSingleMessageIsAbstractable(SHTDemarshallData(cp.msg)) } function AbstractifyConcretePacket(p:LPacket>) : LPacket> requires LPacketIsAbstractable(p); { LPacket(p.dst, p.src, AbstractifyCSingleMessageToSingleMessage(SHTDemarshallData(p.msg))) } predicate LEnvStepIsAbstractable(step:LEnvStep>) { match step { case LEnvStepHostIos(actor, ios) => NetEventLogIsAbstractable(ios) case LEnvStepDeliverPacket(p) => LPacketIsAbstractable(p) case LEnvStepAdvanceTime => true case LEnvStepStutter => true } } function AbstractifyConcreteEnvStep(step:LEnvStep>) : LEnvStep> requires LEnvStepIsAbstractable(step); { match step { case LEnvStepHostIos(actor, ios) => LEnvStepHostIos(actor, AbstractifyRawLogToIos(ios)) case LEnvStepDeliverPacket(p) => LEnvStepDeliverPacket(AbstractifyConcretePacket(p)) case LEnvStepAdvanceTime => LEnvStepAdvanceTime() case LEnvStepStutter => LEnvStepStutter() } } predicate ConcreteEnvironmentIsAbstractable(ds_env:LEnvironment>) { (forall p :: p in ds_env.sentPackets ==> LPacketIsAbstractable(p)) && LEnvStepIsAbstractable(ds_env.nextStep) } function AbstractifyConcreteSentPackets(sent:set>>) : set>> requires forall p :: p in sent ==> LPacketIsAbstractable(p); { set p | p in sent :: AbstractifyConcretePacket(p) } function AbstractifyConcreteEnvironment(ds_env:LEnvironment>) : LEnvironment> requires ConcreteEnvironmentIsAbstractable(ds_env); { LEnvironment(ds_env.time, AbstractifyConcreteSentPackets(ds_env.sentPackets), map [], AbstractifyConcreteEnvStep(ds_env.nextStep)) } function AbstractifyConcreteConfiguration(ds_config:ConcreteConfiguration) : SHTConfiguration requires ConstantsStateIsAbstractable(ds_config); { AbstractifyToConfiguration( SHTConcreteConfiguration( ds_config.hostIds, ds_config.rootIdentity, ds_config.params ) ) } function{:opaque} AbstractifyConcreteReplicas(replicas:map, replica_order:seq) : seq requires forall r :: r in replica_order ==> r in replicas; ensures |AbstractifyConcreteReplicas(replicas, replica_order)| == |replica_order|; ensures forall i {:trigger AbstractifyConcreteReplicas(replicas, replica_order)[i]} :: 0 <= i < |replica_order| ==> AbstractifyConcreteReplicas(replicas, replica_order)[i] == replicas[replica_order[i]].sched; { if replica_order == [] then [] else [replicas[replica_order[0]].sched] + AbstractifyConcreteReplicas(replicas, replica_order[1..]) } predicate DsStateIsAbstractable(ds:DS_State) { ConstantsStateIsValid(ds.config) && ConcreteEnvironmentIsAbstractable(ds.environment) && (forall r :: r in ds.config.hostIds ==> r in ds.servers) } function AbstractifyDsState(ds:DS_State) : LSHT_State requires DsStateIsAbstractable(ds); { LSHT_State(AbstractifyConcreteConfiguration(ds.config), AbstractifyConcreteEnvironment(ds.environment), AbstractifyConcreteReplicas(ds.servers, ds.config.hostIds)) } lemma lemma_DeduceTransitionFromDsBehavior( config:ConcreteConfiguration, db:seq, i:int ) requires IsValidBehavior(config, db); requires 0 <= i < |db| - 1; ensures DS_Next(db[i], db[i+1]); { } lemma lemma_DsNextOffset(db:seq, index:int) requires |db| > 0; requires 0 < index < |db|; requires forall i {:trigger DS_Next(db[i], db[i+1])} :: 0 <= i < |db| - 1 ==> DS_Next(db[i], db[i+1]); ensures DS_Next(db[index-1], db[index]); { var i := index - 1; assert DS_Next(db[i], db[i+1]); // OBSERVE trigger for the forall } lemma lemma_DsConsistency(config:ConcreteConfiguration, db:seq, i:int) requires IsValidBehavior(config, db); requires 0 <= i < |db|; ensures db[i].config == config; ensures Collections__Maps2_s.mapdomain(db[i].servers) == Collections__Maps2_s.mapdomain(db[0].servers); { if i == 0 { } else { lemma_DsConsistency(config, db, i-1); lemma_DeduceTransitionFromDsBehavior(config, db, i-1); assert forall server :: server in db[i-1].servers ==> server in db[i].servers; assert forall server :: server in db[i].servers ==> server in db[i-1].servers; forall server | server in Collections__Maps2_s.mapdomain(db[i-1].servers) ensures server in Collections__Maps2_s.mapdomain(db[i].servers) { assert server in db[i-1].servers; assert server in db[i].servers; } forall server | server in Collections__Maps2_s.mapdomain(db[i].servers) ensures server in Collections__Maps2_s.mapdomain(db[i-1].servers) { assert server in db[i].servers; assert server in db[i-1].servers; } } } lemma lemma_HostIdsConsistent(config:ConcreteConfiguration, db:seq, i:int, id:EndPoint, query:EndPoint) requires IsValidBehavior(config, db); requires 0 <= i < |db|; requires id in db[i].servers; ensures query in db[i].servers[id].sched.host.constants.hostIds <==> query in config.hostIds; { lemma_DsConsistency(config, db, i); // ==> db[i].config == config if i == 0 { assert query in db[i].servers[id].sched.host.constants.hostIds <==> query in config.hostIds; } else { assert id in db[i].servers <==> id in Collections__Maps2_s.mapdomain(db[i].servers); // OBSERVE assert id in db[i-1].servers <==> id in Collections__Maps2_s.mapdomain(db[i-1].servers); // OBSERVE calc { Collections__Maps2_s.mapdomain(db[i].servers); Collections__Maps2_s.mapdomain(db[0].servers); { lemma_DsConsistency(config, db, i-1); } Collections__Maps2_s.mapdomain(db[i-1].servers); } lemma_HostIdsConsistent(config, db, i-1, id, query); lemma_DeduceTransitionFromDsBehavior(config, db, i-1); } } lemma lemma_PacketSentByServerIsMarshallable( config:ConcreteConfiguration, db:seq, i:int, p:LPacket> ) requires IsValidBehavior(config, db); requires 0 <= i < |db|; requires p.src in config.hostIds; requires p in db[i].environment.sentPackets; ensures NetPacketBound(p.msg); ensures CSingleMessageMarshallable(SHTDemarshallData(p.msg)); { if i == 0 { return; } if p in db[i-1].environment.sentPackets { lemma_PacketSentByServerIsMarshallable(config, db, i-1, p); return; } lemma_DeduceTransitionFromDsBehavior(config, db, i-1); lemma_DsConsistency(config, db, i-1); assert LEnvironment_Next(db[i-1].environment, db[i].environment); assert db[i-1].environment.nextStep.LEnvStepHostIos?; var io := LIoOpSend(p); var ios := db[i-1].environment.nextStep.ios; assert io in ios; assert IsValidLIoOp(io, db[i-1].environment.nextStep.actor, db[i-1].environment); assert db[i-1].environment.nextStep.actor == p.src; assert DS_NextOneServer(db[i-1], db[i], p.src, ios); assert OnlySentMarshallableData(ios); assert NetPacketBound(io.s.msg); assert CSingleMessageMarshallable(SHTDemarshallData(io.s.msg)); } lemma lemma_BufferedPacketFindRawPacket( config:ConcreteConfiguration, db:seq, i:int, id:EndPoint ) returns(p:LPacket>) requires IsValidBehavior(config, db); requires 0 <= i < |db|; requires id in db[i].servers; requires db[i].servers[id].sched.host.receivedPacket.Some?; ensures NetPacketIsAbstractable(p); ensures AbstractifyNetPacketToShtPacket(p) == db[i].servers[id].sched.host.receivedPacket.v; ensures p in db[i].environment.sentPackets; ensures p.dst == id; { if i == 0 { return; } lemma_DeduceTransitionFromDsBehavior(config, db, i-1); lemma_DsConsistency(config, db, i-1); if db[i].servers[id].sched.host.receivedPacket == db[i-1].servers[id].sched.host.receivedPacket { p := lemma_BufferedPacketFindRawPacket(config, db, i-1, id); return; } assert db[i-1].environment.nextStep.actor == id; p := db[i-1].environment.nextStep.ios[0].r; assert IsValidLIoOp(db[i-1].environment.nextStep.ios[0], id, db[i-1].environment); assert p.dst == id; } lemma lemma_FindReceivedRequestStepHelper( config:ConcreteConfiguration, db:seq, i:int, id:EndPoint, req_index:int ) returns (step_before:int, step_after:int) requires IsValidBehavior(config, db); requires 0 <= i < |db|; requires id in db[i].servers; requires 0 <= req_index < |db[i].servers[id].sched.host.receivedRequests|; ensures 0 <= step_before < step_after <= i; ensures step_after == step_before + 1; ensures id in db[step_before].servers; ensures id in db[step_after].servers; ensures |db[step_before].servers[id].sched.host.receivedRequests| == req_index; ensures |db[step_after].servers[id].sched.host.receivedRequests| == req_index + 1; { if i == 0 { assert false; } lemma_DeduceTransitionFromDsBehavior(config, db, i-1); lemma_DsConsistency(config, db, i-1); if db[i].servers[id].sched.host.receivedRequests == db[i-1].servers[id].sched.host.receivedRequests { step_before, step_after := lemma_FindReceivedRequestStepHelper(config, db, i-1, id, req_index); return; } assert |db[i].servers[id].sched.host.receivedRequests| == |db[i-1].servers[id].sched.host.receivedRequests| + 1; if |db[i-1].servers[id].sched.host.receivedRequests| > req_index { step_before, step_after := lemma_FindReceivedRequestStepHelper(config, db, i-1, id, req_index); return; } assert db[i-1].environment.nextStep.actor == id; step_before := i - 1; step_after := i; } lemma lemma_RecevedRequestsConsistent( config:ConcreteConfiguration, db:seq, i:int, j:int, id:EndPoint, req:AppRequest, req_index:int ) requires IsValidBehavior(config, db); requires 0 <= i <= j < |db|; requires id in db[i].servers; requires 0 <= req_index < |db[i].servers[id].sched.host.receivedRequests|; requires db[i].servers[id].sched.host.receivedRequests[req_index] == req; ensures id in db[j].servers; ensures 0 <= req_index < |db[j].servers[id].sched.host.receivedRequests|; ensures db[j].servers[id].sched.host.receivedRequests[req_index] == req; { lemma_DsConsistency(config, db, i); lemma_DsConsistency(config, db, j); if j == i { return; } else { lemma_DsNextOffset(db, j); lemma_DeduceTransitionFromDsBehavior(config, db, j-1); lemma_RecevedRequestsConsistent(config, db, i, j - 1, id, req, req_index); } } lemma lemma_FindReceivedRequestStep( config:ConcreteConfiguration, db:seq, i:int, id:EndPoint, req:AppRequest, req_index:int ) returns (step_before:int, step_after:int) requires IsValidBehavior(config, db); requires 0 <= i < |db|; requires id in db[i].servers; requires 0 <= req_index < |db[i].servers[id].sched.host.receivedRequests|; requires db[i].servers[id].sched.host.receivedRequests[req_index] == req; ensures 0 <= step_before < step_after <= i; ensures step_after == step_before + 1; ensures id in db[step_before].servers; ensures id in db[step_after].servers; ensures |db[step_before].servers[id].sched.host.receivedRequests| == req_index; ensures |db[step_after].servers[id].sched.host.receivedRequests| == req_index + 1; ensures db[step_after].servers[id].sched.host.receivedRequests[req_index] == req; { step_before, step_after := lemma_FindReceivedRequestStepHelper(config, db, i, id, req_index); if db[step_after].servers[id].sched.host.receivedRequests[req_index] != req { var req' := db[step_after].servers[id].sched.host.receivedRequests[req_index]; lemma_RecevedRequestsConsistent(config, db, step_after, i, id, req', req_index); } } lemma lemma_FindRawAppGetRequest( config:ConcreteConfiguration, db:seq, i:int, id:EndPoint, req:AppRequest, req_index:int ) returns (step:int) requires IsValidBehavior(config, db); requires 0 <= i < |db|; requires id in db[i].servers; requires 0 <= req_index < |db[i].servers[id].sched.host.receivedRequests|; requires db[i].servers[id].sched.host.receivedRequests[req_index] == req; requires req.AppGetRequest?; ensures 0 <= step <= i; ensures id in db[step].servers; ensures var h := db[step].servers[id].sched.host; h.receivedPacket.Some? && h.receivedPacket.v.msg.SingleMessage? && h.receivedPacket.v.msg.m.GetRequest? && req == AppGetRequest(h.receivedPacket.v.msg.seqno, h.receivedPacket.v.msg.m.k_getrequest); { var step_before, step_after := lemma_FindReceivedRequestStep(config, db, i, id, req, req_index); step := step_before; assert DS_Next(db[step], db[step+1]); } lemma lemma_FindRawAppSetRequest( config:ConcreteConfiguration, db:seq, i:int, id:EndPoint, req:AppRequest, req_index:int ) returns (step:int) requires IsValidBehavior(config, db); requires 0 <= i < |db|; requires id in db[i].servers; requires 0 <= req_index < |db[i].servers[id].sched.host.receivedRequests|; requires db[i].servers[id].sched.host.receivedRequests[req_index] == req; requires req.AppSetRequest?; ensures 0 <= step <= i; ensures id in db[step].servers; ensures var h := db[step].servers[id].sched.host; h.receivedPacket.Some? && h.receivedPacket.v.msg.SingleMessage? && h.receivedPacket.v.msg.m.SetRequest? && req == AppSetRequest(h.receivedPacket.v.msg.seqno, h.receivedPacket.v.msg.m.k_setrequest, h.receivedPacket.v.msg.m.v_setrequest); { var step_before, step_after := lemma_FindReceivedRequestStep(config, db, i, id, req, req_index); step := step_before; var h := db[step].servers[id].sched.host; assert DS_Next(db[step], db[step+1]); } lemma lemma_SentPacketIsValidPhysicalPacket( config:ConcreteConfiguration, db:seq, i:int, p:LPacket> ) requires IsValidBehavior(config, db); requires 0 <= i < |db|; requires p in db[i].environment.sentPackets; ensures ValidPhysicalPacket(p); { if i == 0 { return; } if p in db[i-1].environment.sentPackets { lemma_SentPacketIsValidPhysicalPacket(config, db, i-1, p); return; } lemma_DeduceTransitionFromDsBehavior(config, db, i-1); assert LEnvironment_Next(db[i-1].environment, db[i].environment); assert db[i-1].environment.nextStep.LEnvStepHostIos?; var io := LIoOpSend(p); assert io in db[i-1].environment.nextStep.ios; assert ValidPhysicalEnvironmentStep(db[i-1].environment.nextStep); } lemma lemma_NetEventIsAbstractable( config:ConcreteConfiguration, db:seq, i:int, net_event:NetEvent ) requires IsValidBehavior(config, db); requires 0 <= i < |db| - 1; requires db[i].environment.nextStep.LEnvStepHostIos?; requires net_event in db[i].environment.nextStep.ios; ensures NetEventIsAbstractable(net_event); { if net_event.LIoOpTimeoutReceive? || net_event.LIoOpReadClock? { return; } lemma_DeduceTransitionFromDsBehavior(config, db, i); assert ValidPhysicalEnvironmentStep(db[i].environment.nextStep); assert ValidPhysicalIo(net_event); } lemma lemma_DsIsAbstractable(config:ConcreteConfiguration, db:seq, i:int) requires IsValidBehavior(config, db); requires 0 <= i < |db|; requires LEnvStepIsAbstractable(last(db).environment.nextStep); ensures DsStateIsAbstractable(db[i]); { lemma_DsConsistency(config, db, i); forall p | p in db[i].environment.sentPackets ensures LPacketIsAbstractable(p); { lemma_SentPacketIsValidPhysicalPacket(config, db, i, p); } if i == |db|-1 { return; } var step := db[i].environment.nextStep; if step.LEnvStepHostIos? { forall io | io in step.ios ensures NetEventIsAbstractable(io); { lemma_NetEventIsAbstractable(config, db, i, io); } assert NetEventLogIsAbstractable(step.ios); } else if step.LEnvStepDeliverPacket? { lemma_DeduceTransitionFromDsBehavior(config, db, i); assert IsValidLEnvStep(db[i].environment, step); assert step.p in db[i].environment.sentPackets; lemma_SentPacketIsValidPhysicalPacket(config, db, i, step.p); } } lemma lemma_IosRelations(ios:seq>>, r_ios:seq>>) returns (sends:set>>, r_sends:set>>) requires NetEventLogIsAbstractable(ios); requires forall io :: io in ios && io.LIoOpSend? ==> LPacketIsAbstractable(io.s); requires r_ios == AbstractifyRawLogToIos(ios); ensures sends == (set io | io in ios && io.LIoOpSend? :: io.s); ensures r_sends == (set io | io in r_ios && io.LIoOpSend? :: io.s); ensures forall send :: send in sends ==> LPacketIsAbstractable(send); ensures r_sends == AbstractifyConcreteSentPackets(sends); { sends := (set io | io in ios && io.LIoOpSend? :: io.s); r_sends := (set io | io in r_ios && io.LIoOpSend? :: io.s); var refined_sends := AbstractifyConcreteSentPackets(sends); forall r | r in refined_sends ensures r in r_sends; { var send :| send in sends && AbstractifyConcretePacket(send) == r; var io :| io in ios && io.LIoOpSend? && io.s == send; assert AbstractifyNetEventToLSHTIo(io) in r_ios; } forall r | r in r_sends ensures r in refined_sends; { var r_io :| r_io in r_ios && r_io.LIoOpSend? && r_io.s == r; var j :| 0 <= j < |r_ios| && r_ios[j] == r_io; assert AbstractifyNetEventToLSHTIo(ios[j]) == r_io; assert ios[j] in ios; assert ios[j].s in sends; } } lemma lemma_IsValidEnvStep(de:LEnvironment>, le:LEnvironment>) requires IsValidLEnvStep(de, de.nextStep); requires de.nextStep.LEnvStepHostIos?; requires ConcreteEnvironmentIsAbstractable(de); requires AbstractifyConcreteEnvironment(de) == le; ensures IsValidLEnvStep(le, le.nextStep); { var id := de.nextStep.actor; var ios := de.nextStep.ios; var r_ios := le.nextStep.ios; assert LIoOpSeqCompatibleWithReduction(r_ios); forall io | io in r_ios ensures IsValidLIoOp(io, id, le); { var j :| 0 <= j < |r_ios| && r_ios[j] == io; assert r_ios[j] == AbstractifyNetEventToLSHTIo(ios[j]); assert IsValidLIoOp(ios[j], id, de); } } lemma lemma_LEnvironmentNextHost(de :LEnvironment>, le :LEnvironment>, de':LEnvironment>, le':LEnvironment>) requires ConcreteEnvironmentIsAbstractable(de); requires ConcreteEnvironmentIsAbstractable(de'); requires AbstractifyConcreteEnvironment(de) == le; requires AbstractifyConcreteEnvironment(de') == le'; requires de.nextStep.LEnvStepHostIos?; requires LEnvironment_Next(de, de'); ensures LEnvironment_Next(le, le'); { lemma_IsValidEnvStep(de, le); var id := de.nextStep.actor; var ios := de.nextStep.ios; var r_ios := le.nextStep.ios; assert LEnvironment_PerformIos(de, de', id, ios); var sends, r_sends := lemma_IosRelations(ios, r_ios); assert de.sentPackets + sends == de'.sentPackets; assert le.sentPackets + r_sends == le'.sentPackets; assert forall r_io :: r_io in r_ios && r_io.LIoOpReceive? ==> r_io.r in le.sentPackets; assert LEnvironment_PerformIos(le, le', id, r_ios); } predicate ReplicasDistinct(replica_ids:seq, i:int, j:int) { 0 <= i < |replica_ids| && 0 <= j < |replica_ids| && replica_ids[i] == replica_ids[j] ==> i == j } lemma lemma_LSchedulerNextPreservesConstants( s:LScheduler, s':LScheduler, ios:seq ) requires LScheduler_Next(s, s', ios); ensures s.host.constants == s.host.constants; { } lemma {:timeLimitMultiplier 2} lemma_AllConfigConsistent(config:ConcreteConfiguration, db:seq, i:int, s:LSHT_State) requires IsValidBehavior(config, db); requires 0 <= i < |db|; requires DsStateIsAbstractable(db[i]); requires s == AbstractifyDsState(db[i]); requires LEnvStepIsAbstractable(last(db).environment.nextStep); ensures db[i].config == config; ensures WFSHTConfiguration(s.config); ensures forall k :: 0 <= k < |s.config.hostIds| ==> s.hosts[k].host.me == s.config.hostIds[k]; { if i == 0 { assert DS_Init(db[0], config); lemma_DsIsAbstractable(config, db, 0); var ls := AbstractifyDsState(db[0]); //sb := [ ls ]; // Prove LSHT_MapsComplete calc { |ls.hosts|; |AbstractifyConcreteReplicas(db[0].servers, db[0].config.hostIds)|; |db[0].config.hostIds|; |AbstractifyEndPointsToNodeIdentities(db[0].config.hostIds)|; |AbstractifyToConstants(db[0].config).hostIds|; |ls.config.hostIds|; } var shtconcreteconfig := SHTConcreteConfiguration( config.hostIds, config.rootIdentity, config.params ); assert SHTConcreteConfigurationIsAbstractable(shtconcreteconfig) && shtconcreteconfig.rootIdentity in shtconcreteconfig.hostIds && 0 < |shtconcreteconfig.hostIds|; lemma_WFSHTConcreteConfiguration(shtconcreteconfig); forall i | 0 <= i < |ls.config.hostIds| ensures ls.hosts[i].host.me == ls.config.hostIds[i]; { reveal_SeqIsUnique(); } return; } lemma_DsConsistency(config, db, i-1); lemma_DsConsistency(config, db, i); lemma_DeduceTransitionFromDsBehavior(config, db, i-1); forall k | 0 <= k < |s.config.hostIds| ensures s.hosts[k].host.me == s.config.hostIds[k]; { lemma_ConfigConsistent(config, db, i, k, s); } lemma_DsIsAbstractable(config, db, i-1); lemma_AllConfigConsistent(config, db, i-1, AbstractifyDsState(db[i-1])); } lemma {:timeLimitMultiplier 2} lemma_ConfigConsistent(config:ConcreteConfiguration, db:seq, i:int, k:int, s:LSHT_State) requires IsValidBehavior(config, db); requires 0 <= i < |db|; requires DsStateIsAbstractable(db[i]); requires s == AbstractifyDsState(db[i]); requires LEnvStepIsAbstractable(last(db).environment.nextStep); requires 0 <= k < |s.config.hostIds|; ensures s.hosts[k].host.me == s.config.hostIds[k]; { var id := s.config.hostIds[k]; assert id in db[i].servers; if i == 0 { assert DS_Init(db[0], config); lemma_DsIsAbstractable(config, db, 0); var ls := AbstractifyDsState(db[0]); //sb := [ ls ]; // Prove LSHT_MapsComplete calc { |ls.hosts|; |AbstractifyConcreteReplicas(db[0].servers, db[0].config.hostIds)|; |db[0].config.hostIds|; |AbstractifyEndPointsToNodeIdentities(db[0].config.hostIds)|; |AbstractifyToConstants(db[0].config).hostIds|; |ls.config.hostIds|; } var shtconcreteconfig := SHTConcreteConfiguration( config.hostIds, config.rootIdentity, config.params ); assert SHTConcreteConfigurationIsAbstractable(shtconcreteconfig) && shtconcreteconfig.rootIdentity in shtconcreteconfig.hostIds && 0 < |shtconcreteconfig.hostIds|; lemma_WFSHTConcreteConfiguration(shtconcreteconfig); forall i | 0 <= i < |ls.config.hostIds| ensures ls.hosts[i].host.me == ls.config.hostIds[i]; { reveal_SeqIsUnique(); } return; } lemma_DsConsistency(config, db, i-1); lemma_DsConsistency(config, db, i); lemma_DeduceTransitionFromDsBehavior(config, db, i-1); assert Collections__Maps2_s.mapdomain(db[i].servers) == Collections__Maps2_s.mapdomain(db[0].servers) == Collections__Maps2_s.mapdomain(db[i-1].servers); lemma_DsIsAbstractable(config, db, i-1); //lemma_ConfigConsistent(config, db, i-1, db[i-1].environment.nextStep.actor); if db[i-1].servers == db[i].servers// && db[i-1].config.hostIds == db[i].config.hostIds { var acr := AbstractifyConcreteReplicas(db[i-1].servers, db[i-1].config.hostIds); var acr' := AbstractifyConcreteReplicas(db[i].servers, db[i].config.hostIds); var ls := AbstractifyDsState(db[i-1]); var ls' := AbstractifyDsState(db[i]); assert ls.hosts == acr; assert ls'.hosts == acr'; assert acr == acr'; assert ls.hosts == ls'.hosts; lemma_ConfigConsistent(config, db, i-1, k, AbstractifyDsState(db[i-1])); /*var lsPrior := AbstractifyDsState(db[i-1]); assert forall i :: 0 <= i < |lsPrior.config.hostIds| ==> lsPrior.hosts[i].host.me == lsPrior.config.hostIds[i]; assert lsPrior == ls;*/ return; } assert db[i-1].environment.nextStep.LEnvStepHostIos? && db[i-1].environment.nextStep.actor in db[i-1].servers; var sc := db[i-1].servers[db[i-1].environment.nextStep.actor].sched; var sc' := db[i].servers[db[i-1].environment.nextStep.actor].sched; assert DS_NextOneServer(db[i-1], db[i], db[i-1].environment.nextStep.actor, db[i-1].environment.nextStep.ios); assert db[i].servers == db[i-1].servers[db[i-1].environment.nextStep.actor := db[i].servers[db[i-1].environment.nextStep.actor]]; var ios :| DS_NextOneServer(db[i-1], db[i], db[i-1].environment.nextStep.actor, ios); var rios := AbstractifyRawLogToIos(ios); //assert HostNext(s.servers[id], s'.servers[id], ios) assert LScheduler_Next(sc, sc', rios) || HostNextIgnoreUnsendable(sc, sc', ios); lemma_ConfigConsistent(config, db, i-1, k, AbstractifyDsState(db[i-1])); if LScheduler_Next(sc, sc', rios) { var ls := AbstractifyDsState(db[i-1]); var ls' := AbstractifyDsState(db[i]); assert ls'.hosts[k].host.me == ls.hosts[k].host.me; assert ls'.hosts == AbstractifyConcreteReplicas(db[i].servers, db[i].config.hostIds); assert AbstractifyConcreteReplicas(db[i].servers, db[i].config.hostIds)[k] == db[i].servers[db[i].config.hostIds[k]].sched; assert ls'.hosts[k] == db[i].servers[db[i].config.hostIds[k]].sched; assert ls.hosts[k] == db[i-1].servers[db[i-1].config.hostIds[k]].sched; assert ls'.config.hostIds[k] == ls.config.hostIds[k]; if (ls.config.hostIds[k] != db[i-1].environment.nextStep.actor) { assert ls'.hosts[k] == ls.hosts[k]; } else { assert ls'.hosts[k].host.me == ls'.config.hostIds[k]; } //lemma_LSchedulerNextPreservesConstants(s, s', rios); } else { //assert s'.host == s.host; } } lemma lemma_RefinementOfUnsendablePacketHasLimitedPossibilities( p:LPacket>, g:G, rp:LSHTPacket ) requires g == CSingleMessage_grammar(); requires ValidGrammar(g); requires !Demarshallable(p.msg, g) || !CSingleMessageMarshallable(parse_CSingleMessage(DemarshallFunc(p.msg, g))); requires NetPacketIsAbstractable(p); requires rp == AbstractifyNetPacketToLSHTPacket(p); ensures rp.msg.InvalidMessage? || rp.msg.SingleMessage? //&& !rp.msg.m.GetRequest?) { assert !rp.msg.Ack?; if Demarshallable(p.msg, g) { var cmsg := parse_CSingleMessage(DemarshallFunc(p.msg, g)); if cmsg.CSingleMessage? { assert !EndPointIsValidPublicKey(cmsg.dst) || !MessageMarshallable(cmsg.m); } } } lemma lemma_IgnoringUnsendableGivesEmptySentPackets(ios:seq) requires |ios| == 1; requires ios[0].LIoOpReceive?; ensures ExtractPacketsFromLSHTPackets(ExtractSentPacketsFromIos(ios)) == {}; { reveal_ExtractSentPacketsFromIos(); } lemma lemma_IgnoringInvalidMessageIsLSchedulerNext( s:LScheduler, s':LScheduler, ios:seq ) requires s.nextActionIndex == 0; requires s' == s.(nextActionIndex := (s.nextActionIndex + 1) % LHost_NumActions()); requires |ios| == 1; requires ios[0].LIoOpReceive?; requires ios[0].r.msg.InvalidMessage?; requires DelegationMapComplete(s.host.delegationMap); ensures LScheduler_Next(s, s', ios); { var sent_packets := ExtractPacketsFromLSHTPackets(ExtractSentPacketsFromIos(ios)); lemma_IgnoringUnsendableGivesEmptySentPackets(ios); assert sent_packets == {}; var packet := Packet(ios[0].r.dst, ios[0].r.src, ios[0].r.msg); var ack; assert ReceivePacket(s.host, s'.host, packet, sent_packets, ack); assert ReceivePacket_Wrapper(s.host, s'.host, packet, sent_packets); assert LHost_ReceivePacketWithoutReadingClock(s.host, s'.host, ios); assert LHost_ReceivePacket_Next(s.host, s'.host, ios); } lemma lemma_IgnoringCertainMessageTypesFromNonServerIsLSchedulerNext( config:ConcreteConfiguration, db:seq, i:int, id:EndPoint, s:LScheduler, s':LScheduler, ios:seq>> ) requires IsValidBehavior(config, db); requires 0 <= i < |db| - 1; requires id in db[i].servers; requires id in db[i+1].servers; requires DelegationMapComplete(s.host.delegationMap); requires DsStateIsAbstractable(db[i]); requires s == db[i].servers[id].sched; requires s' == db[i+1].servers[id].sched; requires s.nextActionIndex == 1; requires IgnoreSchedulerUpdate(s, s'); requires IosReflectIgnoringUnParseable(s, ios); ensures NetEventLogIsAbstractable(ios); ensures LScheduler_Next(s, s', AbstractifyRawLogToIos(ios)); { assert |ios| == 0; assert NetEventLogIsAbstractable([]); assert AbstractifyRawLogToIos([]) == []; if s.host.receivedPacket.v.src in s.host.constants.hostIds { // No real host would have sent such a mangled packet var p := lemma_BufferedPacketFindRawPacket(config, db, i, id); //lemma_AllConfigConsistent(config, db, i, AbstractifyDsState(db[i])); lemma_HostIdsConsistent(config, db, i, id, s.host.receivedPacket.v.src); lemma_PacketSentByServerIsMarshallable(config, db, i, p); assert false; } else { // We ignore delegate messages from non-hosts assert NextDelegate(s.host, s'.host, s.host.receivedPacket.v, {}); assert Process_Message(s.host, s'.host, {}); assert ProcessReceivedPacket(s.host, s'.host, {}); assert Host_Next(s.host, s'.host, {}, {}); } } lemma lemma_HostNextIgnoreUnsendableIsLSchedulerNext( config:ConcreteConfiguration, db:seq, i:int, id:EndPoint, ios:seq>> ) requires IsValidBehavior(config, db); requires 0 <= i < |db| - 1; requires db[i].environment.nextStep == LEnvStepHostIos(id, ios); requires id in db[i].servers; requires id in db[i+1].servers; requires DsStateIsAbstractable(db[i]); requires DelegationMapComplete(db[i].servers[id].sched.host.delegationMap); requires HostNextIgnoreUnsendable(db[i].servers[id].sched, db[i+1].servers[id].sched, ios); ensures LScheduler_Next(db[i].servers[id].sched, db[i+1].servers[id].sched, AbstractifyRawLogToIos(ios)); { var s := db[i].servers[id].sched; var s' := db[i+1].servers[id].sched; assert DS_Next(db[i], db[i+1]); if HostNextIgnoreUnsendableReceive(s, s', ios) { var p := ios[0].r; var rp := AbstractifyNetPacketToLSHTPacket(p); var g := CSingleMessage_grammar(); assert !Demarshallable(p.msg, g) || !CSingleMessageMarshallable(parse_CSingleMessage(DemarshallFunc(p.msg, g))); if p.src in config.hostIds { lemma_PacketSentByServerIsMarshallable(config, db, i, p); assert false; } lemma_NetEventIsAbstractable(config, db, i, ios[0]); lemma_CMessageGrammarValid(); assert |p.msg| < 0x1_0000_0000_0000_0000; assert |g.cases| < 0x1_0000_0000; //assert {:fuel ValidGrammar,5} ValidGrammar(g); var rios := AbstractifyRawLogToIos(ios); assert |rios| == 1; assert rios[0].r == rp; assert s.nextActionIndex == 0; calc { s'.nextActionIndex; 1; { lemma_mod_auto(LHost_NumActions()); } (s.nextActionIndex + 1) % LHost_NumActions(); } lemma_RefinementOfUnsendablePacketHasLimitedPossibilities(p, g, rp); if rp.msg.InvalidMessage? { lemma_IgnoringInvalidMessageIsLSchedulerNext(s, s', rios); assert LScheduler_Next(db[i].servers[id].sched, db[i+1].servers[id].sched, AbstractifyRawLogToIos(ios)); } else if rp.msg.Ack? { assert false; } else { lemma_DsConsistency(config, db, i); assert false; } } else { assert HostNextIgnoreUnsendableProcess(s, s', ios); lemma_IgnoringCertainMessageTypesFromNonServerIsLSchedulerNext(config, db, i, id, s, s', ios); } } lemma lemma_PacketsMonotonicStep( config:ConcreteConfiguration, db:seq, i:int ) requires IsValidBehavior(config, db); requires 0 < i < |db|; ensures db[i-1].environment.sentPackets <= db[i].environment.sentPackets; { lemma_DsConsistency(config, db, i); lemma_DeduceTransitionFromDsBehavior(config, db, i-1); } lemma lemma_PacketsMonotonic( config:ConcreteConfiguration, db:seq, i:int, j:int ) requires IsValidBehavior(config, db); requires 0 < i <= j < |db|; ensures db[i].environment.sentPackets <= db[j].environment.sentPackets; decreases j-i; { if i < j-1 { assert DS_Next(db[i], db[i+1]); lemma_PacketsMonotonic(config, db, i+1, j); } else if i == j-1 { lemma_PacketsMonotonicStep(config, db, j); assert DS_Next(db[i], db[i+1]); } } lemma {:timeLimitMultiplier 2} lemma_DelegationMapComplete( config:ConcreteConfiguration, db:seq, i:int, id:EndPoint ) requires IsValidBehavior(config, db); requires 0 <= i < |db| - 1; requires forall j :: 0 <= j < |db| ==> LEnvStepIsAbstractable(db[j].environment.nextStep); ensures id in db[i].servers ==> DelegationMapComplete(db[i].servers[id].sched.host.delegationMap); { if id in db[i].servers { if i == 0 { assert DelegationMapComplete(db[i].servers[id].sched.host.delegationMap); } else { lemma_DelegationMapComplete(config, db, i - 1, id); var i_minus_1 := i - 1; assert DS_Next(db[i_minus_1], db[i_minus_1+1]); // OBSERVE: trigger based on +1 assert DS_Next(db[i-1], db[i]); if !(db[i-1].environment.nextStep.LEnvStepHostIos? && db[i-1].environment.nextStep.actor in db[i-1].servers) { assert db[i].servers == db[i-1].servers; assert DelegationMapComplete(db[i-1].servers[id].sched.host.delegationMap); } else { var sched := db[i-1].servers[id].sched; var sched' := db[i].servers[id].sched; var ios := db[i-1].environment.nextStep.ios; if id != db[i-1].environment.nextStep.actor { assert db[i].servers[id] == db[i-1].servers[id]; } else { assert LScheduler_Next(sched, sched', AbstractifyRawLogToIos(ios)) || HostNextIgnoreUnsendable(sched, sched', ios); if HostNextIgnoreUnsendable(sched, sched', ios) { assert DelegationMapComplete(db[i].servers[id].sched.host.delegationMap); } else { if sched.nextActionIndex == 0 { assert DelegationMapComplete(db[i].servers[id].sched.host.delegationMap); } else if sched.nextActionIndex == 1 { assert DelegationMapComplete(db[i].servers[id].sched.host.delegationMap); } else { assert DelegationMapComplete(db[i].servers[id].sched.host.delegationMap); } } } } } } } lemma {:timeLimitMultiplier 2} lemma_LSHTNext( config:ConcreteConfiguration, db:seq, i:int, ls:LSHT_State, ls':LSHT_State ) requires IsValidBehavior(config, db); requires 0 <= i < |db| - 1; requires LEnvStepIsAbstractable(last(db).environment.nextStep); requires DsStateIsAbstractable(db[i]); requires DsStateIsAbstractable(db[i+1]); requires ls == AbstractifyDsState(db[i]); requires ls' == AbstractifyDsState(db[i+1]); requires db[i].environment.nextStep.LEnvStepHostIos? ==> var id := db[i].environment.nextStep.actor; id in db[i].servers ==> DelegationMapComplete(db[i].servers[id].sched.host.delegationMap); requires forall id :: id in db[i].servers ==> id in db[i].config.hostIds; ensures LSHT_Next(ls, ls'); { var ds := db[i]; var ds' := db[i+1]; lemma_DeduceTransitionFromDsBehavior(config, db, i); if !ds.environment.nextStep.LEnvStepHostIos? { return; } lemma_LEnvironmentNextHost(db[i].environment, ls.environment, db[i+1].environment, ls'.environment); var id := ds.environment.nextStep.actor; var ios := ds.environment.nextStep.ios; var r_ios := AbstractifyRawLogToIos(ios); var replicas := ds.config.hostIds; assert id in ds.servers <==> id in replicas; lemma_AllConfigConsistent(config, db, i, ls); lemma_AllConfigConsistent(config, db, i+1, ls'); if id !in ds.servers { //assert !exists idx :: 0 <= idx < |replicas| && replicas[idx] == id; assert LSHT_NextExternal(ls, ls', id, r_ios); assert LSHT_Next(ls, ls'); return; } var index :| 0 <= index < |replicas| && replicas[index] == id; assert ls.environment.nextStep == LEnvStepHostIos(id, r_ios); assert LScheduler_Next(ds.servers[id].sched, ds'.servers[id].sched, r_ios) || HostNextIgnoreUnsendable(ds.servers[id].sched, ds'.servers[id].sched, ios); if HostNextIgnoreUnsendable(ds.servers[id].sched, ds'.servers[id].sched, ios) { lemma_HostNextIgnoreUnsendableIsLSchedulerNext(config, db, i, id, ios); } assert LScheduler_Next(ds.servers[id].sched, ds'.servers[id].sched, r_ios); assert LEnvironment_Next(ds.environment, ds'.environment); lemma_LEnvironmentNextHost(ds.environment, ls.environment, ds'.environment, ls'.environment); assert LEnvironment_Next(ls.environment, ls'.environment); reveal_SeqIsUnique(); forall other_idx | other_idx != index && 0 <= other_idx < |replicas| ensures replicas[other_idx] != replicas[index]; { assert ReplicasDistinct(ls.config.hostIds, index, other_idx); } //assert RslNextOneReplica(ls, ls', index, r_ios); assert LSHT_NextOneHost(ls, ls', index, r_ios); assert LSHT_Next(ls, ls'); } lemma {:timeLimitMultiplier 2} RefinementToLiveSHTProof(config:ConcreteConfiguration, db:seq) returns (sb:seq) requires |db| > 0; requires DS_Init(db[0], config); requires LEnvStepIsAbstractable(last(db).environment.nextStep); requires forall i {:trigger DS_Next(db[i], db[i+1])} :: 0 <= i < |db| - 1 ==> DS_Next(db[i], db[i+1]); ensures |sb| == |db|; ensures LSHT_Init(AbstractifyConcreteConfiguration(db[0].config), sb[0]); ensures forall i {:trigger LSHT_Next(sb[i], sb[i+1])} :: 0 <= i < |sb| - 1 ==> LSHT_Next(sb[i], sb[i+1]); ensures forall i :: 0 <= i < |db| ==> DsStateIsAbstractable(db[i]) && sb[i] == AbstractifyDsState(db[i]); //ensures forall i :: 0 <= i < |db| ==> Service_Correspondence(db[i].environment.sentPackets, sb[i]); { var c := AbstractifyConcreteConfiguration(config); if |db| == 1 { lemma_DsIsAbstractable(config, db, 0); var ls := AbstractifyDsState(db[0]); sb := [ ls ]; // Prove LSHT_MapsComplete calc { |ls.hosts|; |AbstractifyConcreteReplicas(db[0].servers, db[0].config.hostIds)|; |db[0].config.hostIds|; |AbstractifyEndPointsToNodeIdentities(db[0].config.hostIds)|; |AbstractifyToConstants(db[0].config).hostIds|; |ls.config.hostIds|; } var shtconcreteconfig := SHTConcreteConfiguration( config.hostIds, config.rootIdentity, config.params ); assert SHTConcreteConfigurationIsAbstractable(shtconcreteconfig) && shtconcreteconfig.rootIdentity in shtconcreteconfig.hostIds && 0 < |shtconcreteconfig.hostIds|; lemma_WFSHTConcreteConfiguration(shtconcreteconfig); forall i | 0 <= i < |c.hostIds| ensures ls.hosts[i].host.me == ls.config.hostIds[i]; { reveal_SeqIsUnique(); } } else { lemma_DsConsistency(config, db, |db|-1); lemma_DeduceTransitionFromDsBehavior(config, db, |db|-2); lemma_DsIsAbstractable(config, db, |db|-1); lemma_DsIsAbstractable(config, db, |db|-2); var ls' := AbstractifyDsState(last(db)); var rest := RefinementToLiveSHTProof(config, all_but_last(db)); assert forall i {:trigger LSHT_Next(rest[i], rest[i+1])} :: 0 <= i < |rest| - 1 ==> LSHT_Next(rest[i], rest[i+1]); sb := rest + [ls']; // Help with sequence indexing forall i | 0 <= i < |db| ensures DsStateIsAbstractable(db[i]); ensures sb[i] == AbstractifyDsState(db[i]); { lemma_DsIsAbstractable(config, db, i); if i < |db| - 1 { assert db[i] == all_but_last(db)[i]; assert sb[i] == AbstractifyDsState(all_but_last(db)[i]); assert sb[i] == AbstractifyDsState(db[i]); } else { assert sb[i] == ls'; assert i == |db| - 1; assert db[i] == last(db); assert sb[i] == AbstractifyDsState(db[i]); } } // Prove the crucial ensures forall i | 0 <= i < |sb| - 1 ensures LSHT_Next(sb[i], sb[i+1]); { if i < |sb| - 2 { // Induction hypothesis assert LSHT_Next(sb[i], sb[i+1]); } else { forall id | id in db[i].servers ensures id in db[i].config.hostIds; { calc ==> { id in db[i].servers; id in Collections__Maps2_s.mapdomain(db[i].servers); { lemma_DsConsistency(config, db, i); } id in Collections__Maps2_s.mapdomain(db[0].servers); id in db[0].config.hostIds; { lemma_DsConsistency(config, db, i); } id in db[i].config.hostIds; } } // var sht_states,_ := RefinementToSHTSequence(c, all_but_last(sb)); // InvHolds(c, sht_states); if db[i].environment.nextStep.LEnvStepHostIos? { lemma_DelegationMapComplete(config, db, i, db[i].environment.nextStep.actor); } lemma_LSHTNext(config, db, i, sb[i], sb[i+1]); assert LSHT_Next(sb[i], sb[i+1]); } } //assume false; } } lemma InvHolds(config:SHTConfiguration, db:seq) requires |db| > 0; requires SHT_Init(config, db[0]); requires forall i {:trigger SHT_Next(db[i], db[i+1])} :: 0 <= i < |db| - 1 ==> db[i] == db[i+1] || SHT_Next(db[i], db[i+1]); ensures forall i {:trigger Inv(db[i])} :: 0 <= i < |db| ==> Inv(db[i]); ensures forall i {:trigger MapComplete(db[i])} :: 0 <= i < |db| ==> MapComplete(db[i]); ensures forall i {:trigger AllDelegationsToKnownHosts(db[i])} :: 0 <= i < |db| ==> AllDelegationsToKnownHosts(db[i]); { if |db| == 1 { InitInv(config, db[0]); } else { InvHolds(config, all_but_last(db)); assert forall i :: 0 <= i < |all_but_last(db)| ==> Inv(all_but_last(db)[i]); var d := last(all_but_last(db)); var d' := last(db); var penultimate_index := |db| - 2; if db[penultimate_index] != db[penultimate_index + 1] { calc { SHT_Next(db[penultimate_index], db[penultimate_index + 1]); // OBSERVE: +1 needed for trigger SHT_Next(d, d'); } NextInv(d, d'); } assert Inv(d'); assert forall i :: 0 <= i < |db| ==> Inv(db[i]); } } lemma {:timeLimitMultiplier 20} RefinementToServiceStateSequence(config:SHTConfiguration, db:seq) returns (sb:seq) requires |db| > 0; requires SHT_Init(config, db[0]); requires forall i {:trigger SHT_Next(db[i], db[i+1])} :: 0 <= i < |db| - 1 ==> db[i] == db[i+1] || SHT_Next(db[i], db[i+1]); ensures |sb| == |db|; ensures forall i {:trigger MapComplete(db[i])} :: 0 <= i < |db| ==> MapComplete(db[i]); ensures forall i {:trigger PacketsHaveSaneHeaders(db[i])} :: 0 <= i < |db| ==> PacketsHaveSaneHeaders(db[i]); ensures forall i {:trigger AllDelegationsToKnownHosts(db[i])} :: 0 <= i < |db| ==> AllDelegationsToKnownHosts(db[i]); ensures forall i {:trigger Refinement(db[i])} :: 0 <= i < |db| ==> Refinement(db[i]) == sb[i]; ensures Service_Init(sb[0], MapSeqToSet(config.hostIds, x => x)); ensures forall i {:trigger Service_Next(sb[i], sb[i+1])} :: 0 <= i < |sb| - 1 ==> sb[i] == sb[i+1] || Service_Next(sb[i], sb[i+1]); //ensures forall i :: 0 <= i < |db| ==> Service_Correspondence(db[i].environment.sentPackets, sb[i]); { if |db| == 1 { sb := [Refinement(db[0])]; } else { InvHolds(config, db); var sb_others := RefinementToServiceStateSequence(config, all_but_last(db)); assert forall i :: 0 <= i < |all_but_last(db)| ==> Refinement(all_but_last(db)[i]) == sb_others[i]; var d := last(all_but_last(db)); var d' := last(db); var s := Refinement(d); var penultimate_index := |db| - 2; if db[penultimate_index] != db[penultimate_index + 1] { calc { SHT_Next(db[penultimate_index], db[penultimate_index + 1]); // OBSERVE: +1 needed for trigger SHT_Next(d, d'); } NextRefinesService(d, d'); } var s' := Refinement(d'); sb := sb_others + [s']; if Service_Next(s, s') { assert last(sb_others) == s; assert forall i {:trigger Service_Next(sb[i], sb[i+1])} :: 0 <= i < |sb| - 1 ==> sb[i] == sb[i+1] || Service_Next(sb[i], sb[i+1]); } else { assert ServiceStutter(s, s'); } } } lemma lemma_SHTRefinementInvariantAppend(db:seq) requires |db| > 0; requires forall i :: 0 <= i < |db|-1 ==> LSHTState_RefinementInvariant(db[i]); requires LSHTState_RefinementInvariant(db[|db|-1]); ensures forall i :: 0 <= i < |db| ==> LSHTState_RefinementInvariant(db[i]); { } lemma {:timeLimitMultiplier 3} RefinementToSHTSequence(config:SHTConfiguration, db:seq) returns (sb:seq) requires |db| > 0; requires LSHT_Init(config, db[0]); requires forall i {:trigger LSHT_Next(db[i], db[i+1])} :: 0 <= i < |db| - 1 ==> LSHT_Next(db[i], db[i+1]); ensures forall i {:trigger LSHTState_RefinementInvariant(db[i])} :: 0 <= i < |db| ==> LSHTState_RefinementInvariant(db[i]); ensures forall i {:trigger LSHT_MapsComplete(db[i])} :: 0 <= i < |db| ==> LSHT_MapsComplete(db[i]); ensures |sb| == |db|; ensures forall i {:trigger LSHTState_Refine(db[i])} :: 0 <= i < |db| ==> LSHTState_Refine(db[i]) == sb[i]; ensures SHT_Init(config, sb[0]); ensures forall i {:trigger SHT_Next(sb[i], sb[i+1])} :: 0 <= i < |sb| - 1 ==> sb[i] == sb[i+1] || SHT_Next(sb[i], sb[i+1]); //ensures forall i :: 0 <= i < |db| ==> Service_Correspondence(db[i].environment.sentPackets, sb[i]); { if |db| == 1 { sb := [LSHTState_Refine(db[0])]; } else { var sb_others := RefinementToSHTSequence(config, all_but_last(db)); var d := last(all_but_last(db)); var d' := last(db); var penultimate_index := |db| - 2; assert forall i :: 0 <= i < |all_but_last(db)| ==> LSHTState_RefinementInvariant(all_but_last(db)[i]); calc { LSHT_Next(db[penultimate_index], db[penultimate_index + 1]); // OBSERVE: +1 needed for trigger LSHT_Next(d, d'); } Lemma_LSHTNextImpliesSHTNext(d, d'); sb := sb_others + [LSHTState_Refine(last(db))]; assert LSHTState_RefinementInvariant(last(db)); lemma_SHTRefinementInvariantAppend(db); assert forall i :: 0 <= i < |db| ==> LSHTState_RefinementInvariant(db[i]); assert forall i :: 0 <= i < |all_but_last(db)| ==> LSHTState_Refine(all_but_last(db)[i]) == sb_others[i]; assert forall i :: 0 <= i < |db|-1 ==> LSHTState_Refine(db[i]) == sb[i]; assert LSHTState_Refine(last(db)) == last(sb); } } ghost method FixFinalEnvStep(config:ConcreteConfiguration, db:seq) returns (db':seq) requires IsValidBehavior(config, db); ensures |db'| == |db|; ensures DS_Init(db'[0], config); ensures forall i {:trigger DS_Next(db'[i], db'[i+1])} :: 0 <= i < |db'| - 1 ==> DS_Next(db'[i], db'[i+1]); ensures last(db').environment.nextStep.LEnvStepStutter?; ensures forall i :: 0 <= i < |db'| - 1 ==> db'[i] == db[i]; ensures last(db') == last(db).(environment := last(db').environment); ensures last(db').environment == last(db).environment.(nextStep := LEnvStepStutter()); ensures LEnvStepIsAbstractable(last(db').environment.nextStep); { var sz := |db|; db' := all_but_last(db) + [last(db).(environment := last(db).environment.(nextStep := LEnvStepStutter()))]; assert |db'| == |db|; forall i | 0 <= i < |db'| - 1 ensures DS_Next(db'[i], db'[i+1]); { lemma_DeduceTransitionFromDsBehavior(config, db, i); if i == sz - 2 { assert DS_Next(db'[i], db'[i+1]); } } assert last(db').environment.nextStep.LEnvStepStutter?; } lemma SequenceSortedProperty(s:seq, i:int, j:int) requires |s| > 0; requires forall i,j :: (0 <= i < |s| - 1) && (j == i+1) ==> s[i] <= s[j]; requires 0 <= i <= j < |s| ensures s[i] <= s[j]; decreases j-i; { if (i == j) { assert s[i] <= s[j]; } else { SequenceSortedProperty(s, i+1, j); } } lemma lemma_ServiceStateServerAddressesNeverChange(sb:seq, server_addresses:set, i:int) requires |sb| > 0; requires Service_Init(sb[0], server_addresses); requires forall j {:trigger Service_Next(sb[j], sb[j+1])} :: 0 <= j < |sb| - 1 ==> sb[j] == sb[j+1] || Service_Next(sb[j], sb[j+1]); requires 0 <= i < |sb|; ensures sb[i].serverAddresses == server_addresses; { if i == 0 { return; } var j := i-1; assert sb[j] == sb[j+1] || Service_Next(sb[j], sb[j+1]); assert i == j+1; assert sb[i-1] == sb[i] || Service_Next(sb[i-1], sb[i]); assert sb[i].serverAddresses == sb[i-1].serverAddresses; lemma_ServiceStateServerAddressesNeverChange(sb, server_addresses, i-1); } predicate HostStateReq(sht_state:SHT_State, req:AppRequest) { exists h,req_index :: h in maprange(sht_state.hosts) && 0 <= req_index < |h.receivedRequests| && req == h.receivedRequests[req_index] } lemma {:timeLimitMultiplier 4} RefinementProofForFixedBehavior(config:ConcreteConfiguration, db:seq) returns (sb:seq) requires |db| > 0; requires DS_Init(db[0], config); requires forall i {:trigger DS_Next(db[i], db[i+1])} :: 0 <= i < |db| - 1 ==> DS_Next(db[i], db[i+1]); requires last(db).environment.nextStep.LEnvStepStutter?; ensures |db| == |sb|; ensures Service_Init(sb[0], Collections__Maps2_s.mapdomain(db[0].servers)); ensures forall i {:trigger Service_Next(sb[i], sb[i+1])} :: 0 <= i < |sb| - 1 ==> sb[i] == sb[i+1] || Service_Next(sb[i], sb[i+1]); ensures forall i {:trigger Service_Correspondence(db[i].environment.sentPackets, sb[i])} :: 0 <= i < |db| ==> Service_Correspondence(db[i].environment.sentPackets, sb[i]); { var sht_config := AbstractifyConcreteConfiguration(config); //var db' := FixFinalEnvStep(config, db); var lsht_states := RefinementToLiveSHTProof(config, db); var sht_states := RefinementToSHTSequence(sht_config, lsht_states); var service_states := RefinementToServiceStateSequence(sht_config, sht_states); sb := service_states; var server_addresses := MapSeqToSet(config.hostIds, x=>x); assert Service_Init(sb[0], server_addresses); forall i {:trigger Service_Next(sb[i], sb[i+1])} | 0 <= i < |sb| - 1 ensures sb[i] == sb[i+1] || Service_Next(sb[i], sb[i+1]); { } forall i | 0 <= i < |db| ensures Service_Correspondence(db[i].environment.sentPackets, sb[i]); { var concretePkts := db[i].environment.sentPackets; var serviceState := sb[i]; var lsht_state := lsht_states[i]; var sht_state := sht_states[i]; forall p, reply, reserved_bytes | p in concretePkts && p.src in serviceState.serverAddresses && p.msg == MarshallServiceReply(reply, reserved_bytes) && |reserved_bytes| < 0x10_0000 ensures reply in serviceState.replies; { var lsht_packet := AbstractifyConcretePacket(p); lemma_ServiceStateServerAddressesNeverChange(sb, server_addresses, i); assert serviceState.serverAddresses == server_addresses; assert p.src in config.hostIds; lemma_PacketSentByServerIsMarshallable(config, db, i, p); lemma_ParseMarshallReply(p.msg, reply, lsht_packet.msg, reserved_bytes); assert lsht_packet.src in serviceState.serverAddresses && lsht_packet.msg.m.Reply?; lemma_DsIsAbstractable(config, db, i); assert lsht_state == AbstractifyDsState(db[i]); assert sht_state == LSHTState_Refine(lsht_state); assert serviceState == Refinement(sht_state); assert lsht_packet in lsht_state.environment.sentPackets; var sht_packet := LSHTPacketToPacket(lsht_packet); assert sht_packet in sht_state.network && sht_packet.msg.SingleMessage? && sht_packet.msg.m.Reply? && sht_packet.src in sht_state.hosts; //assume reply.client == sht_packet.dst; assert reply.seqno == sht_packet.msg.seqno; assert reply.k == sht_packet.msg.m.k_reply; assert reply.ov == sht_packet.msg.m.v; assert reply == AppReply(sht_packet.msg.seqno, sht_packet.msg.m.k_reply, sht_packet.msg.m.v); //assert serviceState.replies == set p | p in sht_state.network && p.msg.SingleMessage? && p.msg.m.Reply? && p.src in sht_state.hosts :: AppReply(p.src, p.msg.seqno, p.msg.m.k_reply, p.msg.m.v); //assert service_reply in set p | p in sht_state.network && p.msg.SingleMessage? && p.msg.m.Reply? && p.src in sht_state.hosts :: AppReply(p.src, p.msg.seqno, p.msg.m.k_reply, p.msg.m.v); assert reply in serviceState.replies; //assert reply in serviceState.replies //assert r in rsl.replies; //var service_reply := RenameToAppReply(r); //assert service_reply == AppReply(p.dst, seqno, reply); //assert service_reply in serviceState.replies; } assert |db| > 0; assert DS_Init(db[0], config); assert last(db).environment.nextStep.LEnvStepStutter?; forall req | req in serviceState.requests && req.AppGetRequest? ensures exists p, reserved_bytes :: p in concretePkts && p.dst in serviceState.serverAddresses && p.msg == MarshallServiceGetRequest(req, reserved_bytes) && |reserved_bytes| < 0x10_0000; { assert serviceState == Refinement(sht_state); var h,req_index :| h in maprange(sht_state.hosts) && 0 <= req_index < |h.receivedRequests| && req == h.receivedRequests[req_index]; var id := h.me; assert h in maprange(sht_state.hosts); assert sht_state == LSHTState_Refine(AbstractifyDsState(db[i])); assert sht_state == LSHTState_Refine(LSHT_State(AbstractifyConcreteConfiguration(db[i].config), AbstractifyConcreteEnvironment(db[i].environment), AbstractifyConcreteReplicas(db[i].servers, db[i].config.hostIds))); InvHolds(sht_config, sht_states); assert Inv(sht_state); var step := lemma_FindRawAppGetRequest(config, db, i, id, req, req_index); var concrete_p := lemma_BufferedPacketFindRawPacket(config, db, step, id); assert concrete_p in db[step].environment.sentPackets; lemma_PacketsMonotonic(config,db, step, i); assert concrete_p in db[i].environment.sentPackets; assert concrete_p.dst in db[step].servers; lemma_DsConsistency(config, db, i); lemma_DsConsistency(config, db, step); assert concrete_p.dst in db[i].servers; assert concrete_p.dst in serviceState.serverAddresses; var sht_p := LSHTPacketToPacket(AbstractifyConcretePacket(concrete_p)); var reserved_bytes := lemma_ParseMarshallGetRequest(concrete_p.msg, sht_p.msg); assert concrete_p.msg == MarshallServiceGetRequest(req, reserved_bytes); } forall req | req in serviceState.requests && req.AppSetRequest? ensures exists p, reserved_bytes :: p in concretePkts && p.dst in serviceState.serverAddresses && p.msg == MarshallServiceSetRequest(req, reserved_bytes) && |reserved_bytes| < 0x10_0000; { assert serviceState == Refinement(sht_state); var h,req_index :| h in maprange(sht_state.hosts) && 0 <= req_index < |h.receivedRequests| && req == h.receivedRequests[req_index]; var id := h.me; assert h in maprange(sht_state.hosts); assert sht_state == LSHTState_Refine(AbstractifyDsState(db[i])); assert sht_state == LSHTState_Refine(LSHT_State(AbstractifyConcreteConfiguration(db[i].config), AbstractifyConcreteEnvironment(db[i].environment), AbstractifyConcreteReplicas(db[i].servers, db[i].config.hostIds))); InvHolds(sht_config, sht_states); assert Inv(sht_state); var step := lemma_FindRawAppSetRequest(config, db, i, id, req, req_index); var concrete_p := lemma_BufferedPacketFindRawPacket(config, db, step, id); assert concrete_p in db[step].environment.sentPackets; lemma_PacketsMonotonic(config,db, step, i); assert concrete_p in db[i].environment.sentPackets; assert concrete_p.dst in db[step].servers; lemma_DsConsistency(config, db, i); lemma_DsConsistency(config, db, step); assert concrete_p.dst in db[i].servers; assert concrete_p.dst in serviceState.serverAddresses; var sht_p := LSHTPacketToPacket(AbstractifyConcretePacket(concrete_p)); var reserved_bytes := lemma_ParseMarshallSetRequest(concrete_p.msg, sht_p.msg); assert concrete_p.msg == MarshallServiceSetRequest(req, reserved_bytes); } } } lemma lemma_FixFinalEnvStep(config:ConcreteConfiguration, db:seq) returns (db':seq) requires IsValidBehavior(config, db); ensures |db'| == |db|; ensures DS_Init(db'[0], config); ensures forall i {:trigger DS_Next(db'[i], db'[i+1])} :: 0 <= i < |db'| - 1 ==> DS_Next(db'[i], db'[i+1]); ensures last(db').environment.nextStep.LEnvStepStutter?; ensures forall i :: 0 <= i < |db'| - 1 ==> db'[i] == db[i]; ensures last(db') == last(db).(environment := last(db').environment); ensures last(db').environment == last(db).environment.(nextStep := LEnvStepStutter()); { var sz := |db|; db' := all_but_last(db) + [last(db).(environment := last(db).environment.(nextStep := LEnvStepStutter()))]; assert |db'| == |db|; forall i | 0 <= i < |db'| - 1 ensures DS_Next(db'[i], db'[i+1]); { lemma_DeduceTransitionFromDsBehavior(config, db, i); if i == sz - 2 { assert DS_Next(db'[i], db'[i+1]); } } } lemma RefinementProof(config:DS_s.H_s.ConcreteConfiguration, db:seq) returns (sb:seq) { var db' := lemma_FixFinalEnvStep(config, db); sb := RefinementProofForFixedBehavior(config, db'); } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Services/SHT/Marshall.i.dfy ================================================ include "AbstractService.s.dfy" include "../../Protocol/SHT/Message.i.dfy" include "../../Impl/SHT/PacketParsing.i.dfy" include "../../Impl/SHT/AppInterfaceConcrete.i.dfy" include "AppInterface.i.dfy" module MarshallProof_i { import opened Native__NativeTypes_s import opened Native__Io_s import opened Bytes_s import opened Math__power2_i import opened AbstractServiceSHT_s`All import opened SHT__Message_i import opened SHT__PacketParsing_i import opened SHT__SingleMessage_i import opened SHT__CMessage_i import opened Impl__AppInterfaceConcrete_i`All import opened AppInterface_i`All import opened Common__Util_i import opened Common__GenericMarshalling_i lemma lemma_ParseValCorrectVByteArray(data:seq, v:V, g:G) returns (len:uint64, val:V, rest:seq) requires ValInGrammar(v, g); requires |data| < 0x1_0000_0000_0000_0000; requires ValidGrammar(g); requires parse_Val(data, g).0.Some?; requires parse_Val(data, g).0.v == v; requires g.GByteArray?; ensures parse_Uint64(data).0.Some?; ensures len == parse_Uint64(data).0.v.u; ensures rest == parse_Uint64(data).1; ensures |rest| >= len as int; ensures val == VByteArray(rest[0..len]); ensures parse_Val(data, g) == parse_ByteArray(data) ensures parse_ByteArray(data).1 == rest[len..] { reveal_parse_Val(); len := parse_Uint64(data).0.v.u; rest := parse_Uint64(data).1; val := VByteArray(rest[0..len]); } lemma lemma_ParseValCorrectVCase(data:seq, v:V, g:G) returns (caseId:uint64, val:V, rest:seq) requires ValInGrammar(v, g); requires |data| < 0x1_0000_0000_0000_0000; requires ValidGrammar(g); requires parse_Val(data, g).0.Some?; requires parse_Val(data, g).0.v == v; requires g.GTaggedUnion?; ensures parse_Uint64(data).0.Some?; ensures caseId == parse_Uint64(data).0.v.u; ensures 0 <= caseId as int < |g.cases|; ensures rest == parse_Uint64(data).1; ensures parse_Val(rest, g.cases[caseId]).0.Some?; ensures val == parse_Val(rest, g.cases[caseId]).0.v; ensures v == VCase(caseId, val); ensures ValInGrammar(val, g.cases[caseId]); ensures parse_Val(data, g) == parse_Case(data, g.cases) { reveal_parse_Val(); caseId := parse_Uint64(data).0.v.u; var tuple := parse_Val(parse_Uint64(data).1, g.cases[caseId]); val := tuple.0.v; rest := parse_Uint64(data).1; } lemma {:fuel ValInGrammar,3} lemma_ParseValCorrectTuple2(data:seq, v:V, g:G) returns (val0:V, val1:V, rest:seq) requires ValInGrammar(v, g); requires |data| < 0x1_0000_0000_0000_0000; requires ValidGrammar(g); requires parse_Val(data, g).0.Some?; requires parse_Val(data, g).0.v == v; requires g.GTuple?; requires |g.t| == 2; ensures parse_Val(data, g.t[0]).0.Some?; ensures val0 == parse_Val(data, g.t[0]).0.v; ensures ValInGrammar(val0, g.t[0]); ensures rest == parse_Val(data, g.t[0]).1; ensures parse_Val(rest, g.t[1]).0.Some?; ensures val1 == parse_Val(rest, g.t[1]).0.v; ensures ValInGrammar(val1, g.t[1]); ensures v == VTuple([val0, val1]); { reveal_parse_Val(); reveal_parse_Tuple_contents(); // Prove that v == VTuple([val0, val1]); assert parse_Val(data, g).0.v == parse_Tuple(data, g.t).0.v == VTuple(parse_Tuple_contents(data, g.t).0.v); assert parse_Tuple_contents(data, g.t).0.v == [parse_Val(data, g.t[0]).0.v] + parse_Tuple_contents(parse_Val(data, g.t[0]).1, g.t[1..]).0.v; assert [parse_Val(data, g.t[0]).0.v] + parse_Tuple_contents(parse_Val(data, g.t[0]).1, g.t[1..]).0.v == [parse_Val(data, g.t[0]).0.v] + [parse_Val(parse_Val(data, g.t[0]).1, g.t[1]).0.v]; assert [parse_Val(data, g.t[0]).0.v] + [parse_Val(parse_Val(data, g.t[0]).1, g.t[1]).0.v] == [parse_Val(data, g.t[0]).0.v, parse_Val(parse_Val(data, g.t[0]).1, g.t[1]).0.v]; assert |v.t| == 2; var tuple0 := parse_Val(data, g.t[0]); assert tuple0.0.Some?; val0,rest := tuple0.0.v, tuple0.1; var tuple1 := parse_Val(rest, g.t[1]); var foo; val1,foo := tuple1.0.v, tuple1.1; // Prove that rest is set correctly assert parse_Val(data, g).1 == parse_Tuple(data, g.t).1 == parse_Tuple_contents(data, g.t).1; assert parse_Tuple_contents(data, g.t).1 == parse_Tuple_contents(parse_Val(data, g.t[0]).1, g.t[1..]).1; //assert parse_Tuple_contents(parse_Val(data, g.t[0]).1, g.t[1..]).1 == rest; } lemma {:fuel ValInGrammar,3} lemma_ParseValCorrectTuple3(data:seq, v:V, g:G) returns (val0:V, val1:V, val2:V, rest1:seq, rest2:seq) requires ValInGrammar(v, g); requires |data| < 0x1_0000_0000_0000_0000; requires ValidGrammar(g); requires parse_Val(data, g).0.Some?; requires parse_Val(data, g).0.v == v; requires g.GTuple?; requires |g.t| == 3; ensures parse_Val(data, g.t[0]).0.Some?; ensures val0 == parse_Val(data, g.t[0]).0.v; ensures ValInGrammar(val0, g.t[0]); ensures rest1 == parse_Val(data, g.t[0]).1; ensures parse_Val(rest1, g.t[1]).0.Some? ensures val1 == parse_Val(rest1, g.t[1]).0.v; ensures ValInGrammar(val1, g.t[1]); ensures rest2 == parse_Val(rest1, g.t[1]).1; ensures parse_Val(rest2, g.t[2]).0.Some?; ensures val2 == parse_Val(rest2, g.t[2]).0.v; ensures ValInGrammar(val2, g.t[2]); ensures v == VTuple([val0, val1, val2]); { reveal_parse_Val(); reveal_parse_Tuple_contents(); // Prove that v == VTuple([val0, val1, val2]); assert parse_Val(data, g).0.v == parse_Tuple(data, g.t).0.v == VTuple(parse_Tuple_contents(data, g.t).0.v); assert parse_Tuple_contents(data, g.t).0.v == [parse_Val(data, g.t[0]).0.v] + parse_Tuple_contents(parse_Val(data, g.t[0]).1, g.t[1..]).0.v; var interm_rest := parse_Val(data, g.t[0]).1; assert [parse_Val(data, g.t[0]).0.v] + parse_Tuple_contents(interm_rest, g.t[1..]).0.v == [parse_Val(data, g.t[0]).0.v] + [parse_Val(interm_rest, g.t[1]).0.v] + parse_Tuple_contents(parse_Val(interm_rest, g.t[1]).1, g.t[2..]).0.v == [parse_Val(data, g.t[0]).0.v] + [parse_Val(interm_rest, g.t[1]).0.v] + [parse_Val(parse_Val(interm_rest, g.t[1]).1, g.t[2]).0.v]; assert [parse_Val(data, g.t[0]).0.v] + [parse_Val(interm_rest, g.t[1]).0.v] + [parse_Val(parse_Val(interm_rest, g.t[1]).1, g.t[2]).0.v] == [parse_Val(data, g.t[0]).0.v, parse_Val(interm_rest, g.t[1]).0.v, parse_Val(parse_Val(interm_rest, g.t[1]).1, g.t[2]).0.v]; assert |v.t| == 3; var foo; var tuple0 := parse_Val(data, g.t[0]); assert tuple0.0.Some?; val0,rest1 := tuple0.0.v, tuple0.1; var tuple1 := parse_Val(interm_rest, g.t[1]); val1,rest2 := tuple1.0.v, tuple1.1; var tuple2 := parse_Val(rest2, g.t[2]); val2,foo := tuple2.0.v, tuple2.1; // Prove that rest is set correctly assert parse_Val(data, g).1 == parse_Tuple(data, g.t).1 == parse_Tuple_contents(data, g.t).1; assert parse_Tuple_contents(data, g.t).1 == parse_Tuple_contents(parse_Val(data, g.t[0]).1, g.t[1..]).1; //assert parse_Tuple_contents(parse_Val(data, g.t[0]).1, g.t[1..]).1 == rest; } lemma lemma_ParseValCorrectVUint64(data:seq, v:V, g:G) returns (u:uint64, rest:seq) requires ValInGrammar(v, g); requires |data| < 0x1_0000_0000_0000_0000; requires ValidGrammar(g); requires parse_Val(data, g).0.Some?; requires parse_Val(data, g).0.v == v; requires g.GUint64?; ensures parse_Uint64(data).0.Some?; ensures u == parse_Uint64(data).0.v.u; ensures v == VUint64(u); ensures rest == parse_Val(data, g).1; ensures rest == parse_Uint64(data).1; { reveal_parse_Val(); u := parse_Uint64(data).0.v.u; rest := parse_Uint64(data).1; } lemma lemma_SeqOffset(s1:seq, s2:seq, offset:int, i:int, j:int) requires 0 <= offset <= |s1| requires s2 == s1[offset..] requires 0 <= i <= j <= |s2| ensures s2[i..j] == s1[i+offset..j+offset] { } lemma {:fuel ValInGrammar,3} lemma_ParseMarshallGetRequest(bytes:seq, msg:SingleMessage) returns (reserved_bytes:seq) requires msg.SingleMessage? && msg.m.GetRequest?; requires CSingleMessageIsAbstractable(SHTDemarshallData(bytes)); requires AbstractifyCSingleMessageToSingleMessage(SHTDemarshallData(bytes)) == msg; ensures |reserved_bytes| < 0x10_0000; ensures bytes == MarshallServiceGetRequest(AppGetRequest(msg.seqno, msg.m.k_getrequest), reserved_bytes); { var cmsg := SHTDemarshallData(bytes); assert cmsg.CSingleMessage?; assert ValidPhysicalAddress(cmsg.dst); var data := bytes; var g := CSingleMessage_grammar(); var v := DemarshallFunc(data, g); assert cmsg.dst == msg.dst; assert SHTDemarshallData(bytes) == parse_CSingleMessage(v); var cs := parse_CSingleMessage(v); assert v.c == 0; assert cs == CSingleMessage(v.val.t[0].u, parse_EndPoint(v.val.t[1]), parse_Message(v.val.t[2])); assert AbstractifyCSingleMessageToSingleMessage(cs) == msg; assert cs.dst == parse_EndPoint(v.val.t[1]); assert cs.dst == EndPoint(v.val.t[1].b); assert cs.dst == msg.dst; assert |v.val.t[1].b| < 0x10_0000; reserved_bytes := v.val.t[1].b; // Walk through the generic parsing process var msgCaseId, msgCaseVal, rest0 := lemma_ParseValCorrectVCase(data, v, g); var seqnoVal, dstVal, msgVal, rest1, rest2 := lemma_ParseValCorrectTuple3(rest0, msgCaseVal, g.cases[msgCaseId]); var mCaseId, mCaseVal, rest3 := lemma_ParseValCorrectVCase(rest2, msgVal, g.cases[msgCaseId].t[2]); assert v.val.t[0] == seqnoVal; assert v.val.t[1] == dstVal; assert v.val.t[2] == msgVal; // Prove that the first 8 bytes are correct assert msgCaseId == 0; assert 0 == SeqByteToUint64(bytes[..8]); assert bytes[..8] == [ 0, 0, 0, 0, 0, 0, 0, 0]; // Prove that the next 8 bytes of seqno are correct var u, rest := lemma_ParseValCorrectVUint64(rest0, seqnoVal, GUint64); assert msg.seqno == u as int; assert SeqByteToUint64(rest0[..8]) == u; assert Uint64ToSeqByte(u) == Uint64ToBytes(u); lemma_BEByteSeqToInt_BEUintToSeqByte_invertability(); assert rest0[..8] == Uint64ToSeqByte(msg.seqno as uint64); assert data[8..16] == rest0[..8]; assert rest == rest0[8..]; assert rest1 == rest0[8..]; // Prove that the bytes of dst are correct var len_dst, val_dst, rest_dst := lemma_ParseValCorrectVByteArray(rest1, dstVal, EndPoint_grammar()); assert val_dst == VByteArray(dstVal.b); assert rest1[..8] == Uint64ToSeqByte(len_dst); assert rest1[..8] == rest0[8..16]; assert data[16..24] == rest1[..8]; assert data[24..24+len_dst] == val_dst.b; assert len_dst as int == |cmsg.dst.public_key|; assert mCaseId == 0; assert rest2 == rest1[8 + len_dst..] == data[24 + len_dst ..]; assert rest2[..8] == data[24 + len_dst .. 32 + len_dst]; assert mCaseId == SeqByteToUint64(rest2[..8]) == SeqByteToUint64(data[24 + len_dst .. 32 + len_dst]); assert data[24 + len_dst .. 32 + len_dst] == Uint64ToSeqByte(mCaseId); var key, rest_key := lemma_ParseValCorrectVUint64(rest3, mCaseVal, GUint64); assert Uint64ToSeqByte(msg.m.k_getrequest) == MarshallSHTKey(msg.m.k_getrequest); assert data[32 + len_dst .. 40 + len_dst] == Uint64ToSeqByte(msg.m.k_getrequest); assert |data| == 40 + len_dst as int; } lemma {:fuel ValInGrammar,5} {:timeLimitMultiplier 2} lemma_ParseMarshallSetRequest(bytes:seq, msg:SingleMessage) returns (reserved_bytes:seq) requires msg.SingleMessage? && msg.m.SetRequest?; requires CSingleMessageIsAbstractable(SHTDemarshallData(bytes)); requires AbstractifyCSingleMessageToSingleMessage(SHTDemarshallData(bytes)) == msg; ensures |reserved_bytes| < 0x10_0000 ensures bytes == MarshallServiceSetRequest(AppSetRequest(msg.seqno, msg.m.k_setrequest, msg.m.v_setrequest), reserved_bytes); { var cmsg := SHTDemarshallData(bytes); assert cmsg.CSingleMessage?; var data := bytes; var g := CSingleMessage_grammar(); var v := DemarshallFunc(data, g); assert cmsg.dst == msg.dst; assert SHTDemarshallData(bytes) == parse_CSingleMessage(v); var cs := parse_CSingleMessage(v); assert v.c == 0; assert cs == CSingleMessage(v.val.t[0].u, parse_EndPoint(v.val.t[1]), parse_Message(v.val.t[2])); assert AbstractifyCSingleMessageToSingleMessage(cs) == msg; assert cs.dst == parse_EndPoint(v.val.t[1]); assert cs.dst == EndPoint(v.val.t[1].b); assert cs.dst == msg.dst; assert |v.val.t[1].b| < 0x10_0000; reserved_bytes := v.val.t[1].b; // Walk through the generic parsing process var msgCaseId, msgCaseVal, rest0 := lemma_ParseValCorrectVCase(data, v, g); var seqnoVal, dstVal, msgVal, rest1, rest2 := lemma_ParseValCorrectTuple3(rest0, msgCaseVal, g.cases[msgCaseId]); var mCaseId, mCaseVal, rest3 := lemma_ParseValCorrectVCase(rest2, msgVal, g.cases[msgCaseId].t[2]); var keyVal, optValueVal, rest4 := lemma_ParseValCorrectTuple2(rest3, mCaseVal, g.cases[msgCaseId].t[2].cases[mCaseId]); var valCaseId, valCaseVal, rest5 := lemma_ParseValCorrectVCase(rest4, optValueVal, OptionalValue_grammar()); // Prove that the first 8 bytes are correct assert msgCaseId == 0; assert 0 == SeqByteToUint64(bytes[..8]); assert bytes[..8] == [ 0, 0, 0, 0, 0, 0, 0, 0]; // Prove that the next 8 bytes of seqno are correct var u, rest := lemma_ParseValCorrectVUint64(rest0, seqnoVal, GUint64); assert msg.seqno == u as int; assert SeqByteToUint64(rest0[..8]) == u; assert Uint64ToSeqByte(u) == Uint64ToBytes(u); lemma_BEByteSeqToInt_BEUintToSeqByte_invertability(); assert rest0[..8] == Uint64ToSeqByte(msg.seqno as uint64); assert data[8..16] == rest0[..8]; assert rest == rest0[8..]; assert rest1 == rest0[8..]; // Prove that the bytes of dst are correct var len_dst, val_dst, rest_dst := lemma_ParseValCorrectVByteArray(rest1, dstVal, EndPoint_grammar()); assert val_dst == VByteArray(dstVal.b); assert rest1[..8] == Uint64ToSeqByte(len_dst); assert rest1[..8] == rest0[8..16]; assert data[16..24] == rest1[..8]; assert data[24..24+len_dst] == val_dst.b; assert len_dst as int == |cmsg.dst.public_key|; assert mCaseId == 1; assert rest2 == rest1[8 + len_dst..] == data[24 + len_dst ..]; assert rest2[..8] == data[24 + len_dst .. 32 + len_dst]; assert mCaseId == SeqByteToUint64(rest2[..8]) == SeqByteToUint64(data[24 + len_dst .. 32 + len_dst]); assert data[24 + len_dst .. 32 + len_dst] == Uint64ToSeqByte(mCaseId); assert Uint64ToSeqByte(msg.m.k_setrequest) == MarshallSHTKey(msg.m.k_setrequest); // Handle the two subcases of OptionalValue if cmsg.m.v_setrequest.ValuePresent? { assert valCaseId == 0; assert 0 == SeqByteToUint64(rest4[..8]); assert rest4[..8] == [ 0, 0, 0, 0, 0, 0, 0, 0]; calc { rest4[..8]; { lemma_SeqOffset(rest3, rest4, 8, 0, 8); } rest3[8..16]; { lemma_SeqOffset(rest2, rest3, 8, 8, 16); } rest2[16..24]; { lemma_SeqOffset(rest1, rest2, 8 + len_dst as int, 16, 24); } rest1[24+len_dst as int..32+len_dst as int]; { lemma_SeqOffset(rest0, rest1, 8, 24 + len_dst as int, 32 + len_dst as int); } rest0[32+len_dst as int..40+len_dst as int]; { lemma_SeqOffset(data, rest0, 8, 32 + len_dst as int, 40 + len_dst as int); } data[40+len_dst as int..48+len_dst as int]; } var byteLen, bytesVal, rest6 := lemma_ParseValCorrectVByteArray(rest5, valCaseVal, GByteArray); assert data[..56+(len_dst as int)+(byteLen as int)] == [ 0, 0, 0, 0, 0, 0, 0, 0] + Uint64ToSeqByte(msg.seqno as uint64) + Uint64ToSeqByte(|reserved_bytes| as uint64) + reserved_bytes + [ 0, 0, 0, 0, 0, 0, 0, 1] + Uint64ToSeqByte(msg.m.k_setrequest) + [ 0, 0, 0, 0, 0, 0, 0, 0] + Uint64ToSeqByte(byteLen) + bytesVal.b; if |data| > 56 + (len_dst as int) + (byteLen as int) { assert data[0..|data|] == data[..]; lemma_parse_Val_view_specific_size(data, v, CSingleMessage_grammar(), 0, |data|); lemma_parse_Val_view_specific(data, v, CSingleMessage_grammar(), 0, |data|); assert false; } assert |data| == 56 + (len_dst as int) + (byteLen as int); assert bytes == MarshallServiceSetRequest(AppSetRequest(msg.seqno, msg.m.k_setrequest, msg.m.v_setrequest), reserved_bytes); } else { assert cmsg.m.v_setrequest.ValueAbsent?; assert valCaseId == 1; assert 1 == SeqByteToUint64(rest4[..8]); assert rest4[..8] == [ 0, 0, 0, 0, 0, 0, 0, 1]; assert data[..48+len_dst as int] == data[..8] + data[8..16] + data[16..24] + data[24..24+len_dst as int] + data[24+len_dst as int..32+len_dst as int] + data[32+len_dst as int..40+len_dst as int] + data[40+len_dst as int..48+len_dst as int]; assert data[..48+len_dst as int] == [ 0, 0, 0, 0, 0, 0, 0, 0] + Uint64ToSeqByte(msg.seqno as uint64) + Uint64ToSeqByte(|reserved_bytes| as uint64) + reserved_bytes + [ 0, 0, 0, 0, 0, 0, 0, 1] + Uint64ToSeqByte(msg.m.k_setrequest) + [ 0, 0, 0, 0, 0, 0, 0, 1]; if |data| > 48 + len_dst as int { assert data[0..|data|] == data[..]; lemma_parse_Val_view_specific_size(data, v, CSingleMessage_grammar(), 0, |data|); lemma_parse_Val_view_specific(data, v, CSingleMessage_grammar(), 0, |data|); assert false; } assert |data| == 48 + len_dst as int; assert bytes == MarshallServiceSetRequest(AppSetRequest(msg.seqno, msg.m.k_setrequest, msg.m.v_setrequest), reserved_bytes); } } lemma lemma_ParseMarshallReplyHelper(bytes:seq, reply:AppReply, reserved_bytes:seq) requires bytes == MarshallServiceReply(reply, reserved_bytes) requires 0 <= reply.seqno < 0x1_0000_0000_0000_0000 requires |reserved_bytes| < 0x10_0000 ensures |bytes| >= 24 + |reserved_bytes| ensures bytes[24..24 + |reserved_bytes|] == reserved_bytes { } lemma {:fuel ValInGrammar,5} {:timeLimitMultiplier 2} lemma_ParseMarshallReply( bytes:seq, reply:AppReply, msg:SingleMessage, reserved_bytes:seq) requires CSingleMessageIsAbstractable(SHTDemarshallData(bytes)); requires AbstractifyCSingleMessageToSingleMessage(SHTDemarshallData(bytes)) == msg; requires CSingleMessageMarshallable(SHTDemarshallData(bytes)); requires bytes == MarshallServiceReply(reply, reserved_bytes); requires |reserved_bytes| < 0x10_0000; ensures msg.SingleMessage?; ensures msg.seqno == reply.seqno; ensures msg.m.Reply?; ensures msg.m.k_reply == reply.k; ensures msg.m.v == reply.ov; { var marshalled_bytes := MarshallServiceReply(reply, reserved_bytes); var g := CSingleMessage_grammar(); if 0 <= reply.seqno < 0x1_0000_0000_0000_0000 { var cmsg := SHTDemarshallData(bytes); var data := bytes; var v := DemarshallFunc(data, g); // Walk through the generic parsing process var msgCaseId, msgCaseVal, rest0 := lemma_ParseValCorrectVCase(data, v, g); var seqnoVal, dstVal, msgVal, rest1, rest2 := lemma_ParseValCorrectTuple3(rest0, msgCaseVal, g.cases[msgCaseId]); var mCaseId, mCaseVal, rest3 := lemma_ParseValCorrectVCase(rest2, msgVal, g.cases[msgCaseId].t[2]); // Prove that the first 8 bytes are correct assert msgCaseId == 0; assert 0 == SeqByteToUint64(bytes[..8]); assert bytes[..8] == [ 0, 0, 0, 0, 0, 0, 0, 0]; // Prove that the next 8 bytes of seqno are correct var u, rest := lemma_ParseValCorrectVUint64(rest0, seqnoVal, GUint64); lemma_2toX(); calc { u; parse_Uint64(rest0).0.v.u; SeqByteToUint64(rest0[..8]); SeqByteToUint64(Uint64ToBytes(reply.seqno as uint64)); SeqByteToUint64(Uint64ToSeqByte(reply.seqno as uint64)); SeqByteToUint64(BEUintToSeqByte(reply.seqno as uint64 as int, 8)); { lemma_BEByteSeqToInt_BEUintToSeqByte_invertability(); } reply.seqno as uint64; } assert msg.seqno == u as int; assert reply.seqno == msg.seqno; var len_dst_uint64, val_dst, rest_dst := lemma_ParseValCorrectVByteArray(rest1, dstVal, EndPoint_grammar()); var len_dst := len_dst_uint64 as int; // Prove some length relationships to show that our indices are within bounds calc ==> { true; rest0 == parse_Uint64(data).1; |rest0| == |data| - 8; } calc ==> { true; rest1 == parse_Uint64(rest0).1; |rest1| == |rest0| - 8; } calc ==> { true; |rest2| == |rest1| - 8 - len_dst; } calc ==> { true; rest3 == parse_Uint64(rest2).1; |rest3| == |rest2| - 8; } assert rest0 == data[8..]; assert rest1 == rest0[8..] == data[16..]; assert rest2 == rest1[8 + len_dst..] == data[24 + len_dst..]; assert rest3 == rest2[8..] == data[32 + len_dst..]; assert data[16..24] == Uint64ToSeqByte(|reserved_bytes| as uint64); assert SeqByteToUint64(data[16..24]) == |reserved_bytes| as uint64 by { lemma_BEByteSeqToInt_BEUintToSeqByte_invertability(); } assert len_dst_uint64 == SeqByteToUint64(rest1[..8]) == SeqByteToUint64(data[16..24]) == |reserved_bytes| as uint64; assert len_dst == |reserved_bytes|; calc { val_dst.b; rest_dst[0..len_dst_uint64]; rest_dst[0..len_dst]; rest1[8..][0..len_dst]; { lemma_SeqOffset(rest1, rest1[8..], 8, 0, len_dst); } rest1[8 .. 8 + len_dst]; data[16..][8 .. 8 + len_dst]; { lemma_SeqOffset(data, data[16..], 16, 8, 8 + len_dst); } data[24 .. 24 + len_dst]; { lemma_ParseMarshallReplyHelper(bytes, reply, reserved_bytes); } reserved_bytes; } assert rest2[..8] == data[24 + len_dst .. 32 + len_dst] == [0, 0, 0, 0, 0, 0, 0, 2]; assert mCaseId == 2; var keyVal, optValueVal, rest4 := lemma_ParseValCorrectTuple2(rest3, mCaseVal, g.cases[msgCaseId].t[2].cases[mCaseId]); var valCaseId, valCaseVal, rest5 := lemma_ParseValCorrectVCase(rest4, optValueVal, OptionalValue_grammar()); assert rest4 == rest3[8..] == data[40 + len_dst..]; // Prove that the key is handled correctly var key, rest_key := lemma_ParseValCorrectVUint64(rest3, keyVal, GUint64); calc { msg.m.k_reply; key; parse_Uint64(rest3).0.v.u; parse_Uint64(MarshallSHTKey(reply.k)).0.v.u; SeqByteToUint64(MarshallSHTKey(reply.k)); SeqByteToUint64(Uint64ToBytes(reply.k)); SeqByteToUint64(Uint64ToSeqByte(reply.k)); SeqByteToUint64(BEUintToSeqByte(reply.k as int, 8)); { lemma_BEByteSeqToInt_BEUintToSeqByte_invertability(); } reply.k; } calc { rest4[..8]; rest4[0..8]; { lemma_SeqOffset(rest3, rest4, 8, 0, 8); } rest3[8..16]; { lemma_SeqOffset(rest2, rest3, 8, 8, 16); } rest2[16..24]; { lemma_SeqOffset(rest1, rest2, 8 + len_dst, 16, 24); } rest1[24+len_dst..32+len_dst]; { lemma_SeqOffset(rest0, rest1, 8, 24 + len_dst, 32 + len_dst); } rest0[32+len_dst..40+len_dst]; { lemma_SeqOffset(data, rest0, 8, 32 + len_dst, 40 + len_dst); } data[40+len_dst..48+len_dst]; } // Handle the two subcases of OptionalValue if reply.ov.ValuePresent? { assert rest4[..8] == [ 0, 0, 0, 0, 0, 0, 0, 0]; assert rest5 == parse_Uint64(rest4).1; assert |rest5| == |rest4| - 8; assert |rest5| < 0x1_0000_0000_0000_0000; var byteLen, bytesVal, rest6 := lemma_ParseValCorrectVByteArray(rest5, valCaseVal, GByteArray); calc { byteLen; parse_Uint64(rest5).0.v.u; SeqByteToUint64(rest5[..8]); SeqByteToUint64(Uint64ToBytes(|reply.ov.v| as uint64)); SeqByteToUint64(Uint64ToSeqByte(|reply.ov.v| as uint64)); SeqByteToUint64(BEUintToSeqByte(|reply.ov.v| as uint64 as int, 8)); { lemma_BEByteSeqToInt_BEUintToSeqByte_invertability(); } |reply.ov.v| as uint64; } assert |bytesVal.b| == |msg.m.v.v|; assert bytesVal.b == msg.m.v.v; assert |bytesVal.b| == |reply.ov.v|; assert bytesVal.b == reply.ov.v; assert msg.m.v == reply.ov; } else { assert rest4[..8] == [ 0, 0, 0, 0, 0, 0, 0, 1]; } } else { assert bytes == [1]; reveal_parse_Val(); assert parse_Val(bytes, g).0.None?; assert false; } } } ================================================ FILE: ironfleet/src/Dafny/Distributed/Services/SHT/SHTDistributedSystem.i.dfy ================================================ include "../../Impl/LiveSHT/Host.i.dfy" include "../../Common/Framework/DistributedSystem.s.dfy" module SHT_DistributedSystem_i refines DistributedSystem_s { import H_s = Host_i`All } ================================================ FILE: ironfleet/src/Dafny/Distributed/apps.dfy.batch ================================================ # # SHT # src/Dafny/Distributed/Services/SHT/Main.i.dfy src/Dafny/Distributed/Protocol/LiveSHT/LivenessProof/LivenessProof.i.dfy # # RSL # src/Dafny/Distributed/Protocol/RSL/LivenessProof/LivenessProof.i.dfy src/Dafny/Distributed/Services/RSL/Main.i.dfy # # Lock # src/Dafny/Distributed/Services/Lock/Main.i.dfy ================================================ FILE: ironfleet/src/Dafny/Libraries/.gitignore ================================================ *.bpl *.log ================================================ FILE: ironfleet/src/Dafny/Libraries/Math/.gitignore ================================================ *.bpl *.log ================================================ FILE: ironfleet/src/Dafny/Libraries/Math/div.i.dfy ================================================ include "power.i.dfy" include "mul.i.dfy" include "div_def.i.dfy" include "div_nonlinear.i.dfy" include "div_auto.i.dfy" module Math__div_i { import opened Math__power_s import opened Math__power_i import opened Math__mod_auto_i import opened Math__mul_auto_i import opened Math__mul_nonlinear_i import opened Math__mul_i import opened Math__div_def_i import opened Math__div_nonlinear_i import opened Math__div_auto_i //-//////////////////////////////////////////////////////////////////////////// //- //- Core div lemmas, with named arguments. //- //-//////////////////////////////////////////////////////////////////////////// lemma lemma_div_by_one_is_identity(x:int) {} lemma lemma_div_basics(x:int) ensures x != 0 ==> 0 / x == 0 ensures x / 1 == x ensures x!=0 ==> x / x == 1 { if (x != 0) { lemma_div_by_self(x); lemma_div_of_0(x); } } lemma lemma_small_div_converse() ensures forall x, d {:trigger x/d} :: 0<=x && 0 x < d { forall x, d | 0<=x && 0 0<=u && 0 u < d); } } lemma lemma_div_is_ordered_by_denominator(x:int, y:int, z:int) requires x >= 0 requires 1 <= y <= z ensures x / y >= x / z decreases x { lemma_div_is_div_recursive_forall(); assert forall u:int, d:int {:trigger u / d}{:trigger my_div_recursive(u, d)} :: d > 0 ==> my_div_recursive(u, d) == u / d; if (x < z) { lemma_div_is_ordered(0, x, y); } else { lemma_div_is_ordered(x-z, x-y, y); lemma_div_is_ordered_by_denominator(x-z, y, z); } } lemma lemma_div_is_strictly_ordered_by_denominator(x:int, d:int) requires 0 < x requires 1 < d ensures x/d < x decreases x { lemma_div_auto_induction(d, x, u => 0 < u ==> u / d < u); } lemma lemma_dividing_sums(a:int, b:int, d:int, R:int) requires 0 { a%d + b%d == R + (a+b)%d; (a+b)-(a+b)%d - R == a-(a%d) + b - (b%d); { lemma_fundamental_div_mod(a+b,d); lemma_fundamental_div_mod(a,d); lemma_fundamental_div_mod(b,d); } d*((a+b)/d) - R == d*(a/d) + d*(b/d); } } //-static lemma lemma_negative_divisor(x:int, d:int) //- requires d < 0 //- ensures x / (-1*d) == -1*(x / d) //-{ //- var q := x / (-1*d); //- var r := x % (-1*d); //- //- calc { //- x; //- { lemma_fundamental_div_mod(x, -1*d); } //- q * (-1*d) + r; //- { lemma_mul_is_associative(q, -1, d); } //- (q*-1)*d + r; //- { lemma_mul_is_commutative(q, -1); } //- (-q) * d + r; //- } //- lemma_mod_range(x, -1*d); //- lemma_fundamental_div_mod_converse(x, d, -q, r); //- assert x / d == -q; //- assert -1*(x/d) == q; //-} lemma lemma_div_pos_is_pos(x:int, divisor:int) requires 0 <= x requires 0 < divisor ensures x / divisor >= 0 { lemma_div_auto_induction(divisor, x, u => 0 <= u ==> u / divisor >= 0); } //-//////////////////////////////////////////////////////////////////////////// //- //- Forall lemmas: these restate the core lemmas with foralls, //- so callers needn't name the specific expressions to manipulate. //- //- These are all boilerplate transformations of args/requires/ensures //- into forall args :: requires ==> ensures, with a correpsonding //- mechanically generated forall proof that invokes the core lemma. // So don't bother reading them. //- //-//////////////////////////////////////////////////////////////////////////// lemma lemma_div_basics_forall() ensures forall x {:trigger 0 / x} :: x != 0 ==> 0 / x == 0 ensures forall x {:trigger x / 1} :: x / 1 == x ensures forall x, y {:trigger x/y} :: x >= 0 && y > 0 ==> x/y >= 0 ensures forall x, y {:trigger x/y} :: x >= 0 && y > 0 ==> x/y <= x { forall x:int ensures x != 0 ==> 0 / x == 0 ensures x / 1 == x { lemma_div_basics(x); } forall x:int, y:int | x >= 0 && y > 0 ensures x / y >= 0 ensures x / y <= x { lemma_div_pos_is_pos(x, y); lemma_div_is_ordered_by_denominator(x, 1, y); } } ////////////////////////////////////////////////////////////////////////////// // // I'm not sure how useful this is. I wrote it to try to bring // negative numerators to the positive side for trying to prove // the negative half of lemma_fundamental_div_mod. That turned out // to be the wrong idea, so maybe these are just useless. lemma lemma_div_neg_neg(x:int, d:int) requires d > 0 ensures x/d == -((-x+d-1)/d) { lemma_div_auto(d); } //- //-//////////////////////////////////////////////////////////////////////////// /******************************* * Useful lemmas about mod * *******************************/ //////////////////////////////////////////////// // No longer needed. Here for legacy reasons //////////////////////////////////////////////// lemma lemma_mod_2(x:int) {} lemma lemma_mod2_plus(x:int) {} lemma lemma_mod2_plus2(x:int) {} lemma lemma_mod32(x:int) {} lemma lemma_mod_remainder_neg_specific(x:int, m:int) {} lemma lemma_mod_remainder_neg() {} lemma lemma_mod_remainder_pos_specific(x:int, m:int) {} lemma lemma_mod_remainder_pos() {} lemma lemma_mod_remainder_specific(x:int, m:int) {} lemma lemma_mod_remainder() {} //////////////////////////////////////////////// // Actual useful lemmas //////////////////////////////////////////////// lemma lemma_mod_basics() ensures forall m:int {:trigger m % m} :: m > 0 ==> m % m == 0 ensures forall x:int, m:int {:trigger (x%m) % m} :: m > 0 ==> (x%m) % m == x%m { forall m:int | m > 0 ensures m % m == 0 { lemma_mod_auto(m); } forall x:int, m:int | m > 0 ensures (x % m) % m == x % m { lemma_mod_auto(m); } } lemma lemma_mod_properties() ensures forall m:int {:trigger m % m} :: m > 0 ==> m % m == 0 ensures forall x:int, m:int {:trigger (x%m) % m} :: m > 0 ==> (x%m) % m == x%m ensures forall x:int, m:int {:trigger x%m} :: m > 0 ==> 0 <= x%m < m { lemma_mod_basics(); forall x:int, m:int | m > 0 ensures m > 0 ==> 0 <= x%m < m { lemma_mod_auto(m); } } lemma lemma_mod_decreases(x:nat, d:nat) requires 00 then a else -a requires 0 < m ensures (m*a + b) % m == b % m { lemma_mod_auto(m); lemma_mul_auto_induction(a, u => (m*u + b) % m == b % m); } lemma lemma_add_mod_noop(x:int, y:int, m:int) requires 0 < m ensures ((x % m) + (y % m)) % m == (x+y) % m { lemma_mod_auto(m); } lemma lemma_add_mod_noop_right(x:int, y:int, m:int) requires 0 < m ensures (x + (y % m)) % m == (x+y) % m { lemma_mod_auto(m); } lemma lemma_mod_equivalence(x:int, y:int, m:int) requires 0 < m ensures x % m == y % m <==> (x - y) % m == 0 { lemma_mod_auto(m); } lemma lemma_sub_mod_noop(x:int, y:int, m:int) requires 0 < m ensures ((x % m) - (y % m)) % m == (x-y) % m { lemma_mod_auto(m); } lemma lemma_sub_mod_noop_right(x:int, y:int, m:int) requires 0 < m ensures (x - (y % m)) % m == (x-y) % m { lemma_mod_auto(m); } lemma lemma_mod_adds(a:int, b:int, d:int) requires 0 a%d + b%d == (a+b)%d { lemma_mul_auto(); lemma_div_auto(d); } lemma {:timeLimitMultiplier 2} lemma_mod_neg_neg(x:int, d:int) requires d > 0 ensures x%d == (x*(1-d))%d { forall ensures (x - x * d) % d == x % d { lemma_mod_auto(d); var f := i => (x - i * d) % d == x % d; assert MulAuto() ==> && f(0) && (forall i {:trigger TMulAutoLe(0, i)} :: TMulAutoLe(0, i) && f(i) ==> f(i + 1)) && (forall i {:trigger TMulAutoLe(i, 0)} :: TMulAutoLe(i, 0) && f(i) ==> f(i - 1)); lemma_mul_auto_induction(x, f); } lemma_mul_auto(); } lemma {:timeLimitMultiplier 2} lemma_fundamental_div_mod_converse(x:int, d:int, q:int, r:int) requires d != 0 requires 0 <= r < d requires x == q * d + r ensures q == x/d ensures r == x%d { lemma_div_auto(d); var f := u => u == (u * d + r) / d; forall i {:trigger TMulAutoLe(0, i)} | TMulAutoLe(0, i) && f(i) ensures f(i + 1) { calc { ((i + 1) * d + r) / d; { lemma_mul_is_distributive_add_other_way(d, i, 1); } (i * d + 1 * d + r) / d; (i * d + d + r) / d; (i * d + r) / d + 1; i + 1; } } lemma_mul_auto_induction(q, f); lemma_mul_auto_induction(q, u => r == (u * d + r) % d); // REVIEW: this is a plausible alternative, but it times out: // lemma_mul_auto(); // lemma_div_auto_induction(d, x, x => x == q * d + r ==> q == x/d && r == x%d); } lemma lemma_mod_pos_bound(x:int, m:int) decreases x requires 0 <= x requires 0 < m ensures 0 <= x%m < m { lemma_mod_auto(m); } lemma lemma_mul_mod_noop_left(x:int, y:int, m:int) requires 0 < m ensures (x % m)*y % m == x*y % m { lemma_mod_auto(m); lemma_mul_auto_induction(y, u => (x % m)*u % m == x*u % m); } lemma lemma_mul_mod_noop_right(x:int, y:int, m:int) requires 0 < m ensures x*(y % m) % m == (x*y) % m { lemma_mod_auto(m); lemma_mul_auto_induction(x, u => u*(y % m) % m == (u*y) % m); } lemma lemma_mul_mod_noop_general(x:int, y:int, m:int) requires 0 < m ensures ((x % m) * y ) % m == (x * y) % m ensures ( x * (y % m)) % m == (x * y) % m ensures ((x % m) * (y % m)) % m == (x * y) % m { lemma_mod_properties(); lemma_mul_mod_noop_left(x, y, m); lemma_mul_mod_noop_right(x, y, m); lemma_mul_mod_noop_right(x % m, y, m); } lemma lemma_mul_mod_noop(x:int, y:int, m:int) requires 0 < m ensures (x % m) * (y % m) % m == (x*y) % m { lemma_mul_mod_noop_general(x, y, m); } lemma lemma_power_mod_noop(b:int, e:nat, m:int) decreases e requires 0 < m ensures power(b % m, e) % m == power(b, e) % m { reveal power(); lemma_mod_properties(); if (e > 0) { calc { power(b % m, e) % m; ((b % m) * power(b % m, e - 1)) % m; { lemma_mul_mod_noop_general(b, power(b % m, e - 1), m); } ((b % m) * (power(b % m, e - 1) % m) % m) % m; { lemma_power_mod_noop(b, e - 1, m); } ((b % m) * (power(b, e - 1) % m) % m) % m; { lemma_mul_mod_noop_general(b, power(b, e - 1), m); } (b * (power(b, e - 1)) % m) % m; (b * (power(b, e - 1))) % m; power(b, e) % m; } } } lemma lemma_mod_subtraction(x:nat, s:nat, d:nat) requires 0 0 ensures (x * m) % m == 0 { lemma_mod_auto(m); lemma_mul_auto_induction(x, u => (u * m) % m == 0); } //- //-//////////////////////////////////////////////////////////////////////////// /************************************************************ * Lemmas that depend on properties of both div and mod * ************************************************************/ //-///////////////////////////////////////////////////// //- Proof that div is recursive div //-///////////////////////////////////////////////////// lemma lemma_div_plus_one(x:int, d:int) requires d > 0 //-requires x >= 0 ensures 1 + x / d == (d + x) / d { lemma_div_auto(d); } lemma lemma_div_minus_one(x:int, d:int) requires d > 0 ensures -1 + x / d == (-d + x) / d { lemma_div_auto(d); } lemma lemma_mod_mod(x:int, a:int, b:int) requires 0 0 ensures my_div_recursive(x, d) == x / d { lemma_div_auto_induction(d, x, u => my_div_recursive(u, d) == u / d); // Omitted rather than prove lemma_negative_divisor // //- if d > 0 { //- lemma_div_is_div_pos(x, d); //- } else { //- calc { //- my_div_recursive(x, d); //- -1 * my_div_pos(x, -1*d); //- { lemma_div_is_div_pos(x, -1*d); } //- -1 * (x / (-1*d)); //- { lemma_negative_divisor(x, d); } //- x / d; //- } //- } } lemma lemma_div_is_div_recursive_forall() ensures forall x:int, d:int :: d > 0 ==> my_div_recursive(x, d) == x / d { forall x:int, d:int | d > 0 ensures my_div_recursive(x, d) == x / d { lemma_div_is_div_recursive(x, d); } } //-///////////////////////////////////////////////////// //-///////////////////////////////////////////////////// //- Proof that mod is recursive mod //-///////////////////////////////////////////////////// lemma lemma_mod_is_mod_recursive(x:int, m:int) requires m > 0 ensures my_mod_recursive(x, m) == x % m decreases if x < 0 then -x + m else x { if x < 0 { calc { my_mod_recursive(x, m); my_mod_recursive(x + m, m); { lemma_mod_is_mod_recursive(x + m, m); } (x + m) % m; { lemma_add_mod_noop(x, m, m); } ((x % m) + (m % m)) % m; { lemma_mod_basics(); } (x % m) % m; { lemma_mod_basics(); } x % m; } } else if x < m { lemma_small_mod(x, m); } else { calc { my_mod_recursive(x, m); my_mod_recursive(x - m, m); { lemma_mod_is_mod_recursive(x - m, m); } (x - m) % m; { lemma_sub_mod_noop(x, m, m); } ((x % m) - (m % m)) % m; { lemma_mod_basics(); } (x % m) % m; { lemma_mod_basics(); } x % m; } } } lemma lemma_mod_is_mod_recursive_forall() ensures forall x:int, d:int :: d > 0 ==> my_mod_recursive(x, d) == x % d { forall x:int, d:int | d > 0 ensures my_mod_recursive(x, d) == x % d { lemma_mod_is_mod_recursive(x, d); } } //-///////////////////////////////////////////////////// lemma lemma_basic_div(d:int) requires d > 0 ensures forall x {:trigger x / d} :: 0 <= x < d ==> x / d == 0 { lemma_div_auto(d); } lemma lemma_div_is_ordered(x:int, y:int, z:int) requires x <= y requires z > 0 ensures x / z <= y / z { lemma_div_auto_induction(z, x - y, xy => xy <= 0 ==> (xy + y) / z <= y / z); } lemma lemma_div_decreases(x:int, d:int) requires 0 0 u/d < u); } lemma lemma_div_nonincreasing(x:int, d:int) requires 0<=x requires 0 0<=u ==> u/d <= u); } lemma lemma_breakdown(a:int, b:int, c:int) requires 0<=a requires 0 0 <= u ==> u - divisor < u / divisor * divisor); } lemma lemma_remainder_lower(x:int, divisor:int) requires 0 <= x requires 0 < divisor ensures x >= x / divisor * divisor { lemma_mul_auto(); lemma_div_auto_induction(divisor, x, u => 0 <= u ==> u >= u / divisor * divisor); } lemma lemma_remainder(x:int, divisor:int) requires 0 <= x requires 0 < divisor ensures 0 <= x - x / divisor * divisor < divisor { lemma_mul_auto(); lemma_div_auto_induction(divisor, x, u => 0 <= u - u / divisor * divisor < divisor); } lemma lemma_div_denominator(x:int,c:nat,d:nat) requires 0 <= x requires 0= d) { lemma_fundamental_div_mod(R, c); //- assert R >= c*(R/c); lemma_mul_inequality(d, R/c, c); lemma_mul_is_commutative_forall(); //- assert c*(R/c) >= c*d; //- assert R >= c*d; assert false; } assert R/c < d; lemma_mul_basics_forall(); lemma_fundamental_div_mod_converse(R/c, d, 0, R/c); assert (R/c) % d == R/c; lemma_fundamental_div_mod(R, c); assert c*(R/c) + R%c == R; assert c*((R/c) % d) + R%c == R; var k := x/(c*d); lemma_fundamental_div_mod(x, c*d); assert x == (c*d)*(x/(c*d)) + x % (c*d); assert R == x - (c*d)*(x/(c*d)); assert R == x - (c*d)*k; calc { c*((x/c)%d) + x%c; { lemma_mod_multiples_vanish(-k, x/c, d); lemma_mul_is_commutative_forall(); } c*((x/c+(-k)*d) % d) + x%c; { lemma_hoist_over_denominator(x, (-k)*d, c); } c*(((x+(((-k)*d)*c))/c) % d) + x%c; { lemma_mul_is_associative(-k,d,c); } c*(((x+((-k)*(d*c)))/c) % d) + x%c; { lemma_mul_unary_negation(k,d*c); } c*(((x+(-(k*(d*c))))/c) % d) + x%c; { lemma_mul_is_associative(k,d,c); } c*(((x+(-(k*d*c)))/c) % d) + x%c; c*(((x-k*d*c)/c) % d) + x%c; { lemma_mul_is_associative_forall(); lemma_mul_is_commutative_forall(); } c*((R/c) % d) + x%c; c*(R/c) + x%c; { lemma_fundamental_div_mod(R,c); assert R == c*(R/c) + R % c; lemma_mod_mod(x,c,d); assert R%c == x%c; } R; { lemma_mod_is_mod_recursive_forall(); } R%(c*d); (x-(c*d)*k) % (c*d); { lemma_mul_unary_negation(c*d,k); } (x+(c*d)*(-k)) % (c*d); { lemma_mod_multiples_vanish(-k, x, c*d); } x % (c*d); } calc ==> { c*(x/c) + x%c - R == c*(x/c) - c*((x/c)%d); { lemma_fundamental_div_mod(x,c); } x - R == c*(x/c) - c*((x/c)%d); } calc ==> { true; { lemma_fundamental_div_mod(x/c,d); } d*((x/c)/d) == x/c - ((x/c)%d); c*(d*((x/c)/d)) == c*(x/c - ((x/c)%d)); { lemma_mul_is_associative_forall(); } (c*d)*((x/c)/d) == c*(x/c - ((x/c)%d)); { lemma_mul_is_distributive_forall(); } (c*d)*((x/c)/d) == c*(x/c) - c*((x/c)%d); (c*d)*((x/c)/d) == x - R; { lemma_fundamental_div_mod(x, c*d); } (c*d)*((x/c)/d) == (c*d)*(x/(c*d)) + x%(c*d) - R; (c*d)*((x/c)/d) == (c*d)*(x/(c*d)); { lemma_mul_one_to_one(c*d, (x/c)/d, x/(c*d)); } (x/c)/d == x/(c*d); } } lemma lemma_mul_hoist_inequality(x:int, y:int, z:int) requires 0 <= x requires 0 < z ensures x*(y/z) <= (x*y)/z { calc { (x*y)/z; { lemma_fundamental_div_mod(y, z); } (x*(z*(y/z)+y%z))/z; { lemma_mul_is_distributive_forall(); } (x*(z*(y/z))+x*(y%z))/z; >= { lemma_mod_properties(); lemma_mul_nonnegative(x, y%z); lemma_div_is_ordered(x*(z*(y/z)), x*(z*(y/z))+x*(y%z), z); } (x*(z*(y/z)))/z; { lemma_mul_is_associative_forall(); lemma_mul_is_commutative_forall(); } (z*(x*(y/z)))/z; { lemma_div_multiples_vanish(x*(y/z), z); } x*(y/z); } } lemma lemma_indistinguishable_quotients(a:int, b:int, d:int) requires 0 var u := ab + b; 0 <= u - u%d <= b < u + d - u%d ==> u/d == b/d); } lemma lemma_truncate_middle(x:int, b:int, c:int) requires 0<=x requires 0 { true; { lemma_fundamental_div_mod(x,c); } x == c*(x/c) + x%c; b*x == b*(c*(x/c) + x%c); { lemma_mul_is_distributive_forall(); } b*x == b*(c*(x/c)) + b*(x%c); { lemma_mul_is_associative_forall(); } b*x == (b*c)*(x/c) + b*(x%c); } } lemma lemma_div_multiples_vanish_quotient(x:int, a:int, d:int) requires 0 u%d == 0 ==> u==d*((u+r)/d)); } lemma lemma_div_multiples_vanish_fancy(x:int, b:int, d:int) requires 0 (d*u + b)/d == u; lemma_mul_auto_induction(x, f); assert f(x); } lemma lemma_div_multiples_vanish(x:int, d:int) requires 0 0 ensures x / z < y / z { lemma_mod_multiples_basic(m, z); lemma_div_auto_induction(z, y - x, yx => var u := yx + x; x < u && u % z == 0 ==> x / z < u / z); } lemma lemma_multiply_divide_le(a:int, b:int, c:int) requires 0 < b requires a <= b * c ensures a / b <= c { lemma_mod_multiples_basic(c, b); lemma_div_auto_induction(b, b * c - a, i => 0 <= i && (i + a) % b == 0 ==> a / b <= (i + a) / b); lemma_div_multiples_vanish(c, b); } lemma lemma_multiply_divide_lt(a:int, b:int, c:int) requires 0 < b requires a < b * c ensures a / b < c { lemma_mod_multiples_basic(c, b); lemma_div_auto_induction(b, b * c - a, i => 0 < i && (i + a) % b == 0 ==> a / b < (i + a) / b); lemma_div_multiples_vanish(c, b); } lemma lemma_hoist_over_denominator(x:int, j:int, d:nat) requires 0 x/d + u == (x+u*d) / d); } lemma lemma_part_bound1(a:int, b:int, c:int) requires 0<=a requires 0 { true; { lemma_mod_properties(); } b*(a/b) % (b*c) < b*c; b*((a/b) - (c*((b*(a/b))/(b*c)))) < b*c; { lemma_mul_is_commutative_forall(); lemma_mul_strict_inequality_converse_forall(); } ((a/b) - (c*((b*(a/b))/(b*c)))) < c; ((a/b) - (c*((b*(a/b))/(b*c)))) <= c-1; { lemma_mul_is_commutative_forall(); lemma_mul_inequality_forall(); } b*((a/b) - (c*((b*(a/b))/(b*c)))) <= b*(c-1); b*(a/b) % (b*c) <= b*(c-1); } } lemma lemma_part_bound2(a:int, b:int, c:int) requires 0<=a requires 0 c * d != 0 ensures forall x:int,c:nat,d:nat {:trigger (x/c)/d} :: 0 <= x && 0 < c && 0 < d ==> (x/c)/d == x/(c*d) { lemma_mul_nonzero_forall(); forall x:int,c:nat,d:nat | 0 <= x && 0 < c && 0 < d ensures (x/c)/d == x/(c*d) { lemma_div_denominator(x,c,d); } } } ================================================ FILE: ironfleet/src/Dafny/Libraries/Math/div_auto.i.dfy ================================================ include "mod_auto.i.dfy" include "div_auto_proofs.i.dfy" module Math__div_auto_i { import opened Math__mod_auto_i import opened Math__mod_auto_proofs_i import opened Math__div_auto_proofs_i predicate DivAuto(n:int) requires n > 0 // TODO: allow n < 0 { && ModAuto(n) && (n / n == -((-n) / n) == 1) && (forall x:int {:trigger x / n} :: 0 <= x < n <==> x / n == 0) && (forall x:int, y:int {:trigger (x + y) / n} :: (var z := (x % n) + (y % n); ( (0 <= z < n && (x + y) / n == x / n + y / n) || (n <= z < n + n && (x + y) / n == x / n + y / n + 1)))) && (forall x:int, y:int {:trigger (x - y) / n} :: (var z := (x % n) - (y % n); ( (0 <= z < n && (x - y) / n == x / n - y / n) || (-n <= z < 0 && (x - y) / n == x / n - y / n - 1)))) } lemma lemma_div_auto(n:int) requires n > 0 ensures DivAuto(n) { lemma_mod_auto(n); lemma_div_auto_basics(n); assert (0 + n) / n == 1; assert (0 - n) / n == -1; forall x:int, y:int {:trigger (x + y) / n} ensures var z := (x % n) + (y % n); (|| (0 <= z < n && (x + y) / n == x / n + y / n) || (n <= z < 2 * n && (x + y) / n == x / n + y / n + 1)) { var f := (xx:int, yy:int) => (var z := (xx % n) + (yy % n); ( (0 <= z < n && (xx + yy) / n == xx / n + yy / n) || (n <= z < 2 * n && (xx + yy) / n == xx / n + yy / n + 1))); forall i, j ensures j >= 0 && f(i, j) ==> f(i, j + n) ensures i < n && f(i, j) ==> f(i - n, j) ensures j < n && f(i, j) ==> f(i, j - n) ensures i >= 0 && f(i, j) ==> f(i + n, j) { assert ((i + n) + j) / n == ((i + j) + n) / n; assert (i + (j + n)) / n == ((i + j) + n) / n; assert ((i - n) + j) / n == ((i + j) - n) / n; assert (i + (j - n)) / n == ((i + j) - n) / n; } forall i, j ensures 0 <= i < n && 0 <= j < n ==> f(i, j) { assert ((i + n) + j) / n == ((i + j) + n) / n; assert (i + (j + n)) / n == ((i + j) + n) / n; assert ((i - n) + j) / n == ((i + j) - n) / n; assert (i + (j - n)) / n == ((i + j) - n) / n; } lemma_mod_induction_forall2(n, f); assert f(x, y); } forall x:int, y:int {:trigger (x - y) / n} ensures var z := (x % n) - (y % n); (|| (0 <= z < n && (x - y) / n == x / n - y / n) || (-n <= z < 0 && (x - y) / n == x / n - y / n - 1)) { var f := (xx:int, yy:int) => (var z := (xx % n) - (yy % n); ( (0 <= z < n && (xx - yy) / n == xx / n - yy / n) || (-n <= z < 0 && (xx - yy) / n == xx / n - yy / n - 1))); forall i, j ensures j >= 0 && f(i, j) ==> f(i, j + n) ensures i < n && f(i, j) ==> f(i - n, j) ensures j < n && f(i, j) ==> f(i, j - n) ensures i >= 0 && f(i, j) ==> f(i + n, j) { assert ((i + n) - j) / n == ((i - j) + n) / n; assert (i - (j - n)) / n == ((i - j) + n) / n; assert ((i - n) - j) / n == ((i - j) - n) / n; assert (i - (j + n)) / n == ((i - j) - n) / n; } forall i, j ensures 0 <= i < n && 0 <= j < n ==> f(i, j) { assert ((i + n) - j) / n == ((i - j) + n) / n; assert (i - (j - n)) / n == ((i - j) + n) / n; assert ((i - n) - j) / n == ((i - j) - n) / n; assert (i - (j + n)) / n == ((i - j) - n) / n; } lemma_mod_induction_forall2(n, f); assert f(x, y); } } predicate TDivAutoLe(x:int, y:int) { x <= y } lemma lemma_div_auto_induction(n:int, x:int, f:int->bool) requires n > 0 requires DivAuto(n) ==> && (forall i {:trigger TDivAutoLe(0, i)} :: TDivAutoLe(0, i) && i < n ==> f(i)) && (forall i {:trigger TDivAutoLe(0, i)} :: TDivAutoLe(0, i) && f(i) ==> f(i + n)) && (forall i {:trigger TDivAutoLe(i + 1, n)} :: TDivAutoLe(i + 1, n) && f(i) ==> f(i - n)) ensures DivAuto(n) ensures f(x) { lemma_div_auto(n); assert forall i :: TDivAutoLe(0, i) && i < n ==> f(i); assert forall i {:trigger f(i), f(i + n)} :: TDivAutoLe(0, i) && f(i) ==> f(i + n); assert forall i {:trigger f(i), f(i - n)} :: TDivAutoLe(i + 1, n) && f(i) ==> f(i - n); lemma_mod_induction_forall(n, f); assert f(x); } lemma lemma_div_auto_induction_forall(n:int, f:int->bool) requires n > 0 requires DivAuto(n) ==> && (forall i {:trigger TDivAutoLe(0, i)} :: TDivAutoLe(0, i) && i < n ==> f(i)) && (forall i {:trigger TDivAutoLe(0, i)} :: TDivAutoLe(0, i) && f(i) ==> f(i + n)) && (forall i {:trigger TDivAutoLe(i + 1, n)} :: TDivAutoLe(i + 1, n) && f(i) ==> f(i - n)) ensures DivAuto(n) ensures forall i {:trigger f(i)} :: f(i) { lemma_div_auto(n); assert forall i :: TDivAutoLe(0, i) && i < n ==> f(i); assert forall i {:trigger f(i), f(i + n)} :: TDivAutoLe(0, i) && f(i) ==> f(i + n); assert forall i {:trigger f(i), f(i - n)} :: TDivAutoLe(i + 1, n) && f(i) ==> f(i - n); lemma_mod_induction_forall(n, f); } } ================================================ FILE: ironfleet/src/Dafny/Libraries/Math/div_auto_proofs.i.dfy ================================================ include "mod_auto.i.dfy" module Math__div_auto_proofs_i { import opened Math__mod_auto_i import opened Math__mod_auto_proofs_i import opened Math__div_nonlinear_i lemma lemma_div_auto_basics(n:int) requires n > 0 ensures n / n == -((-n) / n) == 1 ensures forall x:int {:trigger x / n} :: 0 <= x < n <==> x / n == 0 ensures forall x:int {:trigger (x + n) / n} :: (x + n) / n == x / n + 1 ensures forall x:int {:trigger (x - n) / n} :: (x - n) / n == x / n - 1 { lemma_mod_auto(n); lemma_mod_auto_basics(n); lemma_small_div(); lemma_div_by_self(n); forall x:int | x / n == 0 ensures 0 <= x < n { lemma_fundamental_div_mod(x, n); } } } ================================================ FILE: ironfleet/src/Dafny/Libraries/Math/div_def.i.dfy ================================================ //- Specs/implements mathematical div and mod, not the C version. //- This may produce "surprising" results for negative values //- For example, -3 div 5 is -1 and -3 mod 5 is 2. //- Note this is consistent: -3 * -1 + 2 == 5 module Math__div_def_i { /* function mod(x:int, m:int) : int requires m > 0 decreases if x < 0 then (m - x) else x { if x < 0 then mod(m + x, m) else if x < m then x else mod(x - m, m) } */ function div(x:int, d:int) : int requires d != 0 { x/d } function mod(x:int, d:int) : int requires d != 0 { x%d } function div_recursive(x:int, d:int) : int requires d != 0 { INTERNAL_div_recursive(x,d) } function mod_recursive(x:int, d:int) : int requires d > 0 { INTERNAL_mod_recursive(x,d) } function mod_boogie(x:int, y:int) : int requires y != 0 { x % y } //- INTERNAL_mod_boogie(x,y) } function div_boogie(x:int, y:int) : int requires y != 0 { x / y } //-{ INTERNAL_div_boogie(x,y) } function my_div_recursive(x:int, d:int) : int requires d != 0 { if d > 0 then my_div_pos(x, d) else -1 * my_div_pos(x, -1*d) } function my_div_pos(x:int, d:int) : int requires d > 0 decreases if x < 0 then (d - x) else x { if x < 0 then -1 + my_div_pos(x+d, d) else if x < d then 0 else 1 + my_div_pos(x-d, d) } function my_mod_recursive(x:int, m:int) : int requires m > 0 decreases if x < 0 then (m - x) else x { if x < 0 then my_mod_recursive(m + x, m) else if x < m then x else my_mod_recursive(x - m, m) } //- Kept for legacy reasons: //-static function INTERNAL_mod_boogie(x:int, m:int) : int { x % y } function INTERNAL_mod_recursive(x:int, m:int) : int requires m > 0 { my_mod_recursive(x, m) } //-static function INTERNAL_div_boogie(x:int, m:int) : int { x / m } function INTERNAL_div_recursive(x:int, d:int) : int requires d != 0 { my_div_recursive(x, d) } /* ghost method mod_test() { assert -3 % 5 == 2; assert 10 % -5 == 0; assert 1 % -5 == 1; assert -3 / 5 == -1; } */ } ================================================ FILE: ironfleet/src/Dafny/Libraries/Math/div_nonlinear.i.dfy ================================================ //- //- WARNING: In general, you shouldn't need to call these directly. Try //- to use the ones in div.i.dfy instead. They're more full-featured anyway. module Math__div_nonlinear_i { // WARNING: Think three times before adding anything to this file! // Nonlinear verification is highly unstable, so even if it appears to work, // it may cause problems down the road. Thus, we want to keep this file as // small and simple as possible. Instead of adding code here, try proving // it in div.i.dfy using the connection to the recursive definition lemma lemma_div_of_0(d:int) requires d != 0 ensures 0/d == 0 { } lemma lemma_div_by_self(d:int) requires d != 0 ensures d/d == 1 { } lemma lemma_small_div() ensures forall x, d {:trigger x / d} :: 0 <= x < d && d > 0 ==> x / d == 0 { } lemma lemma_mod_of_zero_is_zero(m:int) requires 0 < m ensures 0 % m == 0 { } lemma lemma_fundamental_div_mod(x:int, d:int) requires d != 0 ensures x == d * (x/d) + (x%d) { } lemma lemma_0_mod_anything() ensures forall m:int {:trigger 0 % m} :: m > 0 ==> 0 % m == 0 { } // lemma lemma_mod_yourself(m:int) // ensures m > 0 ==> m % m == 0 // { } lemma lemma_small_mod(x:nat, m:nat) requires x 0 ensures 0 <= x % m < m { } lemma lemma_real_div_gt(x:real, y:real) requires x > y requires x >= 0.0 requires y > 0.0 ensures x / y > 1 as real { } } ================================================ FILE: ironfleet/src/Dafny/Libraries/Math/mod_auto.i.dfy ================================================ include "mod_auto_proofs.i.dfy" module Math__mod_auto_i { import opened Math__mod_auto_proofs_i import opened Math__div_nonlinear_i import opened Math__mul_nonlinear_i import opened Math__mul_i predicate eq_mod(x:int, y:int, n:int) requires n > 0 { (x - y) % n == 0 // same as x % n == y % n, but easier to do induction on x - y than x and y separately } predicate ModAuto(n:int) requires n > 0; { && (n % n == (-n) % n == 0) && (forall x:int {:trigger (x % n) % n} :: (x % n) % n == x % n) && (forall x:int {:trigger x % n} :: 0 <= x < n <==> x % n == x) && (forall x:int, y:int {:trigger (x + y) % n} :: (var z := (x % n) + (y % n); ( (0 <= z < n && (x + y) % n == z) || (n <= z < n + n && (x + y) % n == z - n)))) && (forall x:int, y:int {:trigger (x - y) % n} :: (var z := (x % n) - (y % n); ( (0 <= z < n && (x - y) % n == z) || (-n <= z < 0 && (x - y) % n == z + n)))) } lemma lemma_QuotientAndRemainderUnique(x:int, q:int, r:int, n:int) requires n > 0 requires 0 <= r < n requires x == q * n + r ensures q == x / n ensures r == x % n decreases if q > 0 then q else -q { lemma_mod_auto_basics(n); lemma_mul_is_commutative_forall(); lemma_mul_is_distributive_add_forall(); lemma_mul_is_distributive_sub_forall(); if q > 0 { assert q * n + r == (q - 1) * n + n + r; lemma_QuotientAndRemainderUnique(x - n, q - 1, r, n); } else if q < 0 { assert q * n + r == (q + 1) * n - n + r; lemma_QuotientAndRemainderUnique(x + n, q + 1, r, n); } else { lemma_small_div(); assert r / n == 0; } } lemma lemma_mod_auto(n:int) requires n > 0 ensures ModAuto(n) { lemma_mod_auto_basics(n); lemma_mul_is_commutative_forall(); lemma_mul_is_distributive_add_forall(); lemma_mul_is_distributive_sub_forall(); forall x:int, y:int {:trigger (x + y) % n} ensures var z := (x % n) + (y % n); || (0 <= z < n && (x + y) % n == z) || (n <= z < 2 * n && (x + y) % n == z - n) { var xq, xr := x / n, x % n; lemma_fundamental_div_mod(x, n); assert x == xq * n + xr; var yq, yr := y / n, y % n; lemma_fundamental_div_mod(y, n); assert y == yq * n + yr; if xr + yr < n { lemma_QuotientAndRemainderUnique(x + y, xq + yq, xr + yr, n); } else { lemma_QuotientAndRemainderUnique(x + y, xq + yq + 1, xr + yr - n, n); } } forall x:int, y:int {:trigger (x - y) % n} ensures var z := (x % n) - (y % n); || (0 <= z < n && (x - y) % n == z) || (-n <= z < 0 && (x - y) % n == z + n) { var xq, xr := x / n, x % n; lemma_fundamental_div_mod(x, n); assert x == xq * n + xr; var yq, yr := y / n, y % n; lemma_fundamental_div_mod(y, n); assert y == yq * n + yr; if xr - yr >= 0 { lemma_QuotientAndRemainderUnique(x - y, xq - yq, xr - yr, n); } else { lemma_QuotientAndRemainderUnique(x - y, xq - yq - 1, xr - yr + n, n); } } } predicate TModAutoLe(x:int, y:int) { x <= y } lemma lemma_mod_auto_induction(n:int, x:int, f:int->bool) requires n > 0 requires ModAuto(n) ==> && (forall i {:trigger TModAutoLe(0, i)} :: TModAutoLe(0, i) && i < n ==> f(i)) && (forall i {:trigger TModAutoLe(0, i)} :: TModAutoLe(0, i) && f(i) ==> f(i + n)) && (forall i {:trigger TModAutoLe(i + 1, n)} :: TModAutoLe(i + 1, n) && f(i) ==> f(i - n)) ensures ModAuto(n) ensures f(x) { lemma_mod_auto(n); assert forall i :: TModAutoLe(0, i) && i < n ==> f(i); assert forall i {:trigger f(i), f(i + n)} :: TModAutoLe(0, i) && f(i) ==> f(i + n); assert forall i {:trigger f(i), f(i - n)} :: TModAutoLe(i + 1, n) && f(i) ==> f(i - n); lemma_mod_induction_forall(n, f); assert f(x); } lemma lemma_mod_auto_induction_forall(n:int, f:int->bool) requires n > 0 requires ModAuto(n) ==> && (forall i {:trigger TModAutoLe(0, i)} :: TModAutoLe(0, i) && i < n ==> f(i)) && (forall i {:trigger TModAutoLe(0, i)} :: TModAutoLe(0, i) && f(i) ==> f(i + n)) && (forall i {:trigger TModAutoLe(i + 1, n)} :: TModAutoLe(i + 1, n) && f(i) ==> f(i - n)) ensures ModAuto(n) ensures forall i {:trigger f(i)} :: f(i) { lemma_mod_auto(n); assert forall i :: TModAutoLe(0, i) && i < n ==> f(i); assert forall i {:trigger f(i), f(i + n)} :: TModAutoLe(0, i) && f(i) ==> f(i + n); assert forall i {:trigger f(i), f(i - n)} :: TModAutoLe(i + 1, n) && f(i) ==> f(i - n); lemma_mod_induction_forall(n, f); } /* TODO: if we need these at all, they should have better triggers to protect call sites lemma lemma_mod_auto_induction2(x:int, y:int, n:int, f:imap<(int,int),bool>) requires n > 0 requires forall i, j :: (i, j) in f requires ModAuto(n) ==> (forall i, j {:trigger f[(i, j)]} :: 0 <= i < n && 0 <= j < n ==> f[(i, j)]) requires ModAuto(n) ==> (forall i, j {:trigger f[(i, j)]} :: i >= 0 && f[(i, j)] ==> f[(i + n, j)]) requires ModAuto(n) ==> (forall i, j {:trigger f[(i, j)]} :: j >= 0 && f[(i, j)] ==> f[(i, j + n)]) requires ModAuto(n) ==> (forall i, j {:trigger f[(i, j)]} :: i < n && f[(i, j)] ==> f[(i - n, j)]) requires ModAuto(n) ==> (forall i, j {:trigger f[(i, j)]} :: j < n && f[(i, j)] ==> f[(i, j - n)]) ensures ModAuto(n) ensures f[(x, y)] { lemma_mod_auto(n); lemma_mod_induction_forall2(n, f); assert f[(x, y)]; } lemma lemma_mod_auto_induction_forall2(n:int, f:imap<(int,int),bool>) requires n > 0 requires forall i, j :: (i, j) in f requires ModAuto(n) ==> (forall i, j {:trigger f[(i, j)]} :: 0 <= i < n && 0 <= j < n ==> f[(i, j)]) requires ModAuto(n) ==> (forall i, j {:trigger f[(i, j)]} :: i >= 0 && f[(i, j)] ==> f[(i + n, j)]) requires ModAuto(n) ==> (forall i, j {:trigger f[(i, j)]} :: j >= 0 && f[(i, j)] ==> f[(i, j + n)]) requires ModAuto(n) ==> (forall i, j {:trigger f[(i, j)]} :: i < n && f[(i, j)] ==> f[(i - n, j)]) requires ModAuto(n) ==> (forall i, j {:trigger f[(i, j)]} :: j < n && f[(i, j)] ==> f[(i, j - n)]) ensures ModAuto(n) ensures forall i, j {:trigger f[(i, j)]} :: f[(i, j)] { lemma_mod_auto(n); lemma_mod_induction_forall2(n, f); } */ } ================================================ FILE: ironfleet/src/Dafny/Libraries/Math/mod_auto_proofs.i.dfy ================================================ include "mul_auto.i.dfy" include "mul.i.dfy" include "div_nonlinear.i.dfy" module Math__mod_auto_proofs_i { import opened Math__mul_auto_i import opened Math__mul_nonlinear_i import opened Math__mul_i import opened Math__div_nonlinear_i lemma lemma_mod_induction_helper(n:int, f:int->bool, x:int) requires n > 0 requires forall i :: 0 <= i < n ==> f(i) requires forall i {:trigger f(i), f(i + n)} :: i >= 0 && f(i) ==> f(i + n) requires forall i {:trigger f(i), f(i - n)} :: i < n && f(i) ==> f(i - n) ensures f(x) decreases if x >= n then x else -x { if (x >= n) { lemma_mod_induction_helper(n, f, x - n); assert f((x - n) + n); } else if (x < 0) { lemma_mod_induction_helper(n, f, x + n); assert f((x + n) - n); } } lemma lemma_mod_induction_forall(n:int, f:int->bool) requires n > 0 requires forall i :: 0 <= i < n ==> f(i) requires forall i {:trigger f(i), f(i + n)} :: i >= 0 && f(i) ==> f(i + n) requires forall i {:trigger f(i), f(i - n)} :: i < n && f(i) ==> f(i - n) ensures forall i :: f(i) { forall i ensures f(i) { lemma_mod_induction_helper(n, f, i); } } lemma lemma_mod_induction_forall2(n:int, f:(int,int)->bool) requires n > 0 requires forall i, j :: 0 <= i < n && 0 <= j < n ==> f(i, j) requires forall i, j {:trigger f(i, j), f(i + n, j)} :: i >= 0 && f(i, j) ==> f(i + n, j) requires forall i, j {:trigger f(i, j), f(i, j + n)} :: j >= 0 && f(i, j) ==> f(i, j + n) requires forall i, j {:trigger f(i, j), f(i - n, j)} :: i < n && f(i, j) ==> f(i - n, j) requires forall i, j {:trigger f(i, j), f(i, j - n)} :: j < n && f(i, j) ==> f(i, j - n) ensures forall i, j :: f(i, j) { forall x, y ensures f(x, y) { forall i | 0 <= i < n ensures f(i, y) { var fj := j => f(i, j); lemma_mod_induction_forall(n, fj); assert fj(y); } var fi := i => f(i, y); lemma_mod_induction_forall(n, fi); assert fi(x); } } lemma lemma_mod_auto_basics(n:int) requires n > 0 ensures forall x:int {:trigger (x + n) % n} :: (x + n) % n == x % n ensures forall x:int {:trigger (x - n) % n} :: (x - n) % n == x % n ensures forall x:int {:trigger (x + n) / n} :: (x + n) / n == x / n + 1 ensures forall x:int {:trigger (x - n) / n} :: (x - n) / n == x / n - 1 ensures forall x:int {:trigger x % n} :: 0 <= x < n <==> x % n == x { forall x:int ensures 0 <= x < n <==> x % n == x { if (0 <= x < n) { lemma_small_mod(x, n); } lemma_mod_range(x, n); } forall x:int ensures (x + n) % n == x % n ensures (x - n) % n == x % n ensures (x + n) / n == x / n + 1 ensures (x - n) / n == x / n - 1 { lemma_fundamental_div_mod(x, n); lemma_fundamental_div_mod(x + n, n); lemma_fundamental_div_mod(x - n, n); lemma_mod_range(x, n); lemma_mod_range(x + n, n); lemma_mod_range(x - n, n); var zp := (x + n) / n - x / n - 1; var zm := (x - n) / n - x / n + 1; forall ensures 0 == n * zp + ((x + n) % n) - (x % n) { lemma_mul_auto(); } forall ensures 0 == n * zm + ((x - n) % n) - (x % n) { lemma_mul_auto(); } if (zp > 0) { lemma_mul_inequality(1, zp, n); } if (zp < 0) { lemma_mul_inequality(zp, -1, n); } if (zp == 0) { lemma_mul_by_zero_is_zero(n); } if (zm > 0) { lemma_mul_inequality(1, zm, n); } if (zm < 0) { lemma_mul_inequality(zm, -1, n); } } } } ================================================ FILE: ironfleet/src/Dafny/Libraries/Math/mul.i.dfy ================================================ include "mul_nonlinear.i.dfy" include "mul_auto.i.dfy" module Math__mul_i { import opened Math__mul_nonlinear_i import opened Math__mul_auto_i // TODO_MODULE: module Math__mul_i { // TODO_MODULE: import opened Math__mul_nonlinear_i function mul(x:int, y:int) : int { x*y } //-//////////////////////////////////////////////////////////// //- Recursive definitions that can be handy for proving //- properties we can't or don't want to rely on nonlinear for //-//////////////////////////////////////////////////////////// function mul_recursive(x:int, y:int) : int { if x >= 0 then mul_pos(x, y) else -1*mul_pos(-1*x, y) } function{:opaque} mul_pos(x:int, y:int) : int requires x >= 0 { if x == 0 then 0 else y + mul_pos(x - 1, y) } lemma lemma_mul_is_mul_recursive(x:int, y:int) ensures x * y == mul_recursive(x, y) { if (x >= 0) { lemma_mul_is_mul_pos(x, y); } if (x <= 0) { lemma_mul_is_mul_pos(-x, y); } lemma_mul_auto(); } lemma lemma_mul_is_mul_pos(x:int, y:int) requires x >= 0 ensures x * y == mul_pos(x, y) { reveal_mul_pos(); lemma_mul_auto_induction(x, u => u >= 0 ==> u * y == mul_pos(u, y)); } //-//////////////////////////////////////////////////////////////////////////// //- //- Core lemmas, with named arguments. //- //-//////////////////////////////////////////////////////////////////////////// lemma lemma_mul_basics(x:int) ensures 0*x == 0 ensures x*0 == 0 ensures 1*x == x ensures x*1 == x { } lemma lemma_mul_is_commutative(x:int, y:int) ensures x*y == y*x { } lemma lemma_mul_ordering_general() ensures forall x:int, y:int {:trigger x*y} :: (0 < x && 0 < y && 0 <= x*y) ==> x <= x*y && y <= x*y { forall x:int, y:int | 0 < x && 0 < y && 0 <= x*y ensures x <= x*y && y <= x*y { lemma_mul_ordering(x, y); } } lemma lemma_mul_is_mul_boogie(x:int, y:int) { } lemma lemma_mul_inequality(x:int, y:int, z:int) requires x <= y requires z >= 0 ensures x*z <= y*z { lemma_mul_auto_induction(z, u => u >= 0 ==> x * u <= y * u); } lemma lemma_mul_upper_bound(x:int, x_bound:int, y:int, y_bound:int) requires x <= x_bound requires y <= y_bound requires 0<=x requires 0<=y ensures x*y <= x_bound * y_bound { lemma_mul_inequality(x, x_bound, y); lemma_mul_inequality(y, y_bound, x_bound); } //- This lemma is less precise than the non-strict version, since //- it uses two < facts to achieve only one < result. Thus, use it with //- caution -- it may be throwing away precision you'll require later. lemma lemma_mul_strict_upper_bound(x:int, x_bound:int, y:int, y_bound:int) requires x < x_bound requires y < y_bound requires 0<=x requires 0<=y ensures x*y < x_bound * y_bound { lemma_mul_auto_induction(x, u => 0 <= u ==> u * y <= u * y_bound); lemma_mul_auto_induction(y_bound, u => 1 <= u ==> x * u < x_bound * u); } lemma lemma_mul_left_inequality(x:int, y:int, z:int) requires x > 0 ensures y <= z ==> x*y <= x*z ensures y < z ==> x*y < x*z { lemma_mul_auto_induction(x, u => u > 0 ==> y <= z ==> u*y <= u*z); lemma_mul_auto_induction(x, u => u > 0 ==> y < z ==> u*y < u*z); } lemma lemma_mul_strict_inequality_converse(x:int, y:int, z:int) requires x*z < y*z requires z >= 0 ensures x < y { lemma_mul_auto_induction(z, u => x * u < y * u && u >= 0 ==> x < y); } lemma lemma_mul_inequality_converse(x:int, y:int, z:int) requires x*z <= y*z requires z > 0 ensures x <= y { lemma_mul_auto_induction(z, u => x * u <= y * u && u > 0 ==> x <= y); } lemma lemma_mul_equality_converse(x:int, y:int, z:int) requires x*z == y*z requires 0 x > y && 0 < u ==> x * u > y * u); lemma_mul_auto_induction(z, u => x < y && 0 < u ==> x * u < y * u); } lemma lemma_mul_is_distributive_add_other_way(x:int, y:int, z:int) ensures (y + z)*x == y*x + z*x { lemma_mul_auto(); } lemma lemma_mul_is_distributive_sub(x:int, y:int, z:int) ensures x*(y - z) == x*y - x*z { lemma_mul_auto(); } lemma lemma_mul_is_distributive(x:int, y:int, z:int) ensures x*(y + z) == x*y + x*z ensures x*(y - z) == x*y - x*z ensures (y + z)*x == y*x + z*x ensures (y - z)*x == y*x - z*x ensures x*(y + z) == (y + z)*x ensures x*(y - z) == (y - z)*x ensures x*y == y*x ensures x*z == z*x { lemma_mul_auto(); } lemma lemma_mul_strictly_increases(x:int, y:int) requires 1 < x requires 0 < y ensures y < x*y { lemma_mul_auto_induction(x, u => 1 < u ==> y < u * y); } lemma lemma_mul_increases(x:int, y:int) requires 0 0 < u ==> y <= u * y); } lemma lemma_mul_nonnegative(x:int, y:int) requires 0 <= x requires 0 <= y ensures 0 <= x*y { lemma_mul_auto_induction(x, u => 0 <= u ==> 0 <= u * y); } lemma lemma_mul_unary_negation(x:int, y:int) ensures (-x)*y == -(x*y) == x*(-y) { lemma_mul_auto_induction(x, u => (-u)*y == -(u*y) == u*(-y)); } // TODO: delete lemma_mul_one_to_one_pos; use lemma_mul_one_to_one instead lemma lemma_mul_one_to_one_pos(m:int, x:int, y:int) requires 0 x > y && 0 < u ==> x * u > y * u); lemma_mul_auto_induction(m, u => x < y && 0 < u ==> x * u < y * u); } lemma lemma_mul_one_to_one(m:int, x:int, y:int) requires m!=0 requires m*x == m*y ensures x == y { lemma_mul_auto_induction(m, u => x > y && 0 < u ==> x * u > y * u); lemma_mul_auto_induction(m, u => x > y && 0 > u ==> x * u < y * u); lemma_mul_auto_induction(m, u => x < y && 0 < u ==> x * u < y * u); lemma_mul_auto_induction(m, u => x < y && 0 > u ==> x * u > y * u); } //-//////////////////////////////////////////////////////////////////////////// //- //- Forall lemmas: these restate the core lemmas with foralls, //- so callers needn't name the specific expressions to manipulate. //- //- These are all boilerplate transformations of args/requires/ensures //- into forall args :: requires ==> ensures, with a correpsonding //- mechanically generated forall proof that invokes the core lemma. // So don't bother reading them. //- //-//////////////////////////////////////////////////////////////////////////// lemma lemma_mul_is_mul_recursive_forall() ensures forall x:int, y:int :: x * y == mul_recursive(x, y) { forall x:int, y:int ensures x * y == mul_recursive(x, y) { lemma_mul_is_mul_recursive(x, y); } } lemma lemma_mul_basics_forall() ensures forall x:int {:trigger 0*x} :: 0*x == 0 ensures forall x:int {:trigger x*0} :: x*0 == 0 ensures forall x:int {:trigger 1*x} :: 1*x == x ensures forall x:int {:trigger x*1} :: x*1 == x { } lemma lemma_mul_is_commutative_forall() ensures forall x:int, y:int {:trigger x*y} :: x*y == y*x { } lemma lemma_mul_ordering_forall() ensures forall x:int, y:int {:trigger x*y} :: 0 < x && 0 < y && 0 <= x*y ==> x <= x*y && y <= x*y { forall x:int, y:int | 0 < x && 0 < y && 0 <= x*y ensures x <= x*y && y <= x*y { lemma_mul_ordering(x,y); } } lemma lemma_mul_strict_inequality_forall() ensures forall x:int, y:int, z:int {:trigger x*z, y*z} :: x < y && z>0 ==> x*z < y*z { forall (x:int, y:int, z:int | x < y && z>0) ensures x*z < y*z { lemma_mul_strict_inequality(x, y, z); } } lemma lemma_mul_inequality_forall() ensures forall x:int, y:int, z:int {:trigger x*z, y*z} :: x <= y && z>=0 ==> x*z <= y*z { forall (x:int, y:int, z:int | x <= y && z>=0) ensures x*z <= y*z { lemma_mul_inequality(x, y, z); } } lemma lemma_mul_strict_inequality_converse_forall() ensures forall x:int, y:int, z:int {:trigger x*z, y*z} :: x*z < y*z && z>=0 ==> x < y { forall (x:int, y:int, z:int | x*z < y*z && z>=0) ensures x < y; { lemma_mul_strict_inequality_converse(x,y,z); } } lemma lemma_mul_inequality_converse_forall() ensures forall x:int, y:int, z:int {:trigger x*z, y*z} :: x*z <= y*z && z>0 ==> x <= y { forall (x:int, y:int, z:int | x*z <= y*z && z>0) ensures x <= y { lemma_mul_inequality_converse(x,y,z); } } lemma lemma_mul_is_distributive_add_forall() ensures forall x:int, y:int, z:int {:trigger x*(y + z)} :: x*(y + z) == x*y + x*z { forall (x:int, y:int, z:int) ensures x*(y + z) == x*y + x*z { lemma_mul_is_distributive_add(x,y,z); } } lemma lemma_mul_is_distributive_sub_forall() ensures forall x:int, y:int, z:int {:trigger x*(y - z)} :: x*(y - z) == x*y - x*z { forall (x:int, y:int, z:int) ensures x*(y - z) == x*y - x*z; { lemma_mul_is_distributive_sub(x,y,z); } } lemma lemma_mul_is_distributive_forall() ensures forall x:int, y:int, z:int {:trigger x*(y + z)} :: x*(y + z) == x*y + x*z ensures forall x:int, y:int, z:int {:trigger x*(y - z)} :: x*(y - z) == x*y - x*z ensures forall x:int, y:int, z:int {:trigger (y + z)*x} :: (y + z)*x == y*x + z*x ensures forall x:int, y:int, z:int {:trigger (y - z)*x} :: (y - z)*x == y*x - z*x { lemma_mul_is_distributive_add_forall(); lemma_mul_is_distributive_sub_forall(); lemma_mul_is_commutative_forall(); } lemma lemma_mul_is_associative_forall() ensures forall x:int, y:int, z:int {:trigger x * (y * z)}{:trigger (x * y) * z} :: x * (y * z) == (x * y) * z { forall (x:int, y:int, z:int) ensures x * (y * z) == (x * y) * z { lemma_mul_is_associative(x,y,z); } } lemma lemma_mul_nonzero_forall() ensures forall x:int, y:int {:trigger x*y} :: x*y != 0 <==> x != 0 && y != 0 { forall (x:int, y:int) ensures x*y != 0 <==> x != 0 && y != 0; { lemma_mul_nonzero(x,y); } } lemma lemma_mul_nonnegative_forall() ensures forall x:int, y:int {:trigger x*y} :: 0 <= x && 0 <= y ==> 0 <= x*y { forall (x:int, y:int | 0 <= x && 0 <= y) ensures 0 <= x*y { lemma_mul_nonnegative(x,y); } } lemma lemma_mul_unary_negation_forall() ensures forall x:int, y:int {:trigger (-x)*y}{:trigger x*(-y)} :: (-x)*y == -(x*y) == x*(-y) { forall (x:int, y:int) ensures (-x)*y == -(x*y) == x*(-y) { lemma_mul_unary_negation(x,y); } } lemma lemma_mul_strictly_increases_forall() ensures forall x:int, y:int {:trigger x*y} :: (1 < x && 0 < y) ==> (y < x*y) { forall (x:int, y:int | 1 < x && 0 < y) ensures y < x*y { lemma_mul_strictly_increases(x,y); } } lemma lemma_mul_increases_forall() ensures forall x:int, y:int {:trigger x*y} :: (0 < x && 0 < y) ==> (y <= x*y) { forall (x:int, y:int | 0 < x && 0 < y) ensures y <= x*y { lemma_mul_increases(x,y); } } lemma lemma_mul_strictly_positive_forall() ensures forall x:int, y:int {:trigger x*y} :: (0 < x && 0 < y) ==> (0 < x*y) { forall (x:int, y:int | 0 < x && 0 < y) ensures 0 < x*y { lemma_mul_strictly_positive(x,y); } } lemma lemma_mul_one_to_one_forall() ensures forall m:int, x:int, y:int {:trigger m*x, m*y} :: (m!=0 && m*x == m*y) ==> x==y { forall (m:int, x:int, y:int | m!=0 && m*x == m*y) ensures x==y { lemma_mul_one_to_one(m, x, y); } } lemma lemma_mul_by_zero_is_zero_forall() ensures forall x: int {:trigger 0*x} {:trigger x*0} :: x*0 == 0*x == 0 { forall x:int {:trigger 0*x} {:trigger x*0} ensures x*0 == 0*x == 0 { lemma_mul_by_zero_is_zero(x); } } ////////////////////////////////////////////////////////////////////////////// // // The big properties bundle. This can be a little dangerous, because // it may produce a trigger storm. Whether it does seems to depend on // how complex the expressions being mul'ed are. If that happens, // fall back on specifying an individiual _forall lemma or use // lemma_mul_auto/lemma_mul_auto_induction. // ////////////////////////////////////////////////////////////////////////////// lemma lemma_mul_properties() ensures forall x:int, y:int {:trigger x*y} :: x*y == y*x // ensures forall x:int {:trigger x*0}{:trigger 0*x} :: x*0 == 0*x == 0 ensures forall x:int {:trigger x*1}{:trigger 1*x} :: x*1 == 1*x == x ensures forall x:int, y:int, z:int {:trigger x*z, y*z} :: x < y && z > 0 ==> x*z < y*z ensures forall x:int, y:int, z:int {:trigger x*z, y*z} :: x <= y && z >= 0 ==> x*z <= y*z ensures forall x:int, y:int, z:int {:trigger x*(y + z)} :: x*(y + z) == x*y + x*z ensures forall x:int, y:int, z:int {:trigger x*(y - z)} :: x*(y - z) == x*y - x*z ensures forall x:int, y:int, z:int {:trigger (y + z)*x} :: (y + z)*x == y*x + z*x ensures forall x:int, y:int, z:int {:trigger (y - z)*x} :: (y - z)*x == y*x - z*x ensures forall x:int, y:int, z:int {:trigger x*(y*z)}{:trigger (x*y)*z} :: x*(y*z) == (x*y)*z ensures forall x:int, y:int {:trigger x*y} :: x*y != 0 <==> x != 0 && y != 0 ensures forall x:int, y:int {:trigger x*y} :: 0 <= x && 0 <= y ==> 0 <= x*y ensures forall x:int, y:int {:trigger x*y} :: 0 < x && 0 < y && 0 <= x*y ==> x <= x*y && y <= x*y ensures forall x:int, y:int {:trigger x*y} :: (1 < x && 0 < y) ==> (y < x*y) ensures forall x:int, y:int {:trigger x*y} :: (0 < x && 0 < y) ==> (y <= x*y) ensures forall x:int, y:int {:trigger x*y} :: (0 < x && 0 < y) ==> (0 < x*y) { lemma_mul_strict_inequality_forall(); lemma_mul_inequality_forall(); lemma_mul_is_distributive_forall(); lemma_mul_is_associative_forall(); lemma_mul_ordering_forall(); lemma_mul_nonzero_forall(); lemma_mul_nonnegative_forall(); lemma_mul_strictly_increases_forall(); lemma_mul_increases_forall(); } //- Kept for legacy reasons: function INTERNAL_mul_recursive(x:int, y:int) : int { mul_recursive(x, y) } // TODO_MODULE: } import opened Math__mul_i_ = Math__mul_i } ================================================ FILE: ironfleet/src/Dafny/Libraries/Math/mul_auto.i.dfy ================================================ include "mul_auto_proofs.i.dfy" module Math__mul_auto_i { import opened Math__mul_auto_proofs_i predicate MulAuto() { && (forall x:int, y:int {:trigger x * y} :: x * y == y * x) && (forall x:int, y:int, z:int {:trigger (x + y) * z} :: (x + y) * z == x * z + y * z) && (forall x:int, y:int, z:int {:trigger (x - y) * z} :: (x - y) * z == x * z - y * z) } lemma lemma_mul_auto() ensures MulAuto() { lemma_mul_auto_commutes(); lemma_mul_auto_distributes(); } predicate TMulAutoLe(x:int, y:int) { x <= y } lemma lemma_mul_auto_induction(x:int, f:int->bool) requires MulAuto() ==> f(0) && (forall i {:trigger TMulAutoLe(0, i)} :: TMulAutoLe(0, i) && f(i) ==> f(i + 1)) && (forall i {:trigger TMulAutoLe(i, 0)} :: TMulAutoLe(i, 0) && f(i) ==> f(i - 1)) ensures MulAuto() ensures f(x) { lemma_mul_auto_commutes(); lemma_mul_auto_distributes(); assert forall i {:trigger f(i)} :: TMulAutoLe(0, i) && f(i) ==> f(i + 1); assert forall i {:trigger f(i)} :: TMulAutoLe(i, 0) && f(i) ==> f(i - 1); lemma_mul_induction_forall(f); assert f(x); } lemma lemma_mul_auto_induction_forall(f:int->bool) requires MulAuto() ==> f(0) && (forall i {:trigger TMulAutoLe(0, i)} :: TMulAutoLe(0, i) && f(i) ==> f(i + 1)) && (forall i {:trigger TMulAutoLe(i, 0)} :: TMulAutoLe(i, 0) && f(i) ==> f(i - 1)) ensures MulAuto() ensures forall i {:trigger f(i)} :: f(i) { lemma_mul_auto_commutes(); lemma_mul_auto_distributes(); assert forall i {:trigger f(i)} :: TMulAutoLe(0, i) && f(i) ==> f(i + 1); assert forall i {:trigger f(i)} :: TMulAutoLe(i, 0) && f(i) ==> f(i - 1); lemma_mul_induction_forall(f); } } ================================================ FILE: ironfleet/src/Dafny/Libraries/Math/mul_auto_proofs.i.dfy ================================================ include "mul_nonlinear.i.dfy" module Math__mul_auto_proofs_i { import opened Math__mul_nonlinear_i lemma lemma_mul_induction_helper(f:int->bool, x:int) requires f(0) requires forall i {:trigger f(i), f(i + 1)} :: i >= 0 && f(i) ==> f(i + 1) requires forall i {:trigger f(i), f(i - 1)} :: i <= 0 && f(i) ==> f(i - 1) ensures f(x) decreases if x >= 0 then x else -x { if (x > 0) { lemma_mul_induction_helper(f, x - 1); assert f((x - 1) + 1); } else if (x < 0) { lemma_mul_induction_helper(f, x + 1); assert f((x + 1) - 1); } } lemma lemma_mul_induction_forall(f:int->bool) requires f(0) requires forall i {:trigger f(i), f(i + 1)} :: i >= 0 && f(i) ==> f(i + 1) requires forall i {:trigger f(i), f(i - 1)} :: i <= 0 && f(i) ==> f(i - 1) ensures forall i :: f(i) { forall i ensures f(i) { lemma_mul_induction_helper(f, i); } } lemma lemma_mul_auto_commutes() ensures forall x:int, y:int {:trigger x * y} :: x * y == y * x { forall x:int, y:int ensures x * y == y * x { lemma_mul_induction_forall(i => x * i == i * x); } } lemma lemma_mul_auto_succ() ensures forall x:int, y:int {:trigger (x + 1) * y} :: (x + 1) * y == x * y + y ensures forall x:int, y:int {:trigger (x - 1) * y} :: (x - 1) * y == x * y - y { lemma_mul_auto_commutes(); forall x:int, y:int ensures (x + 1) * y == x * y + y ensures (x - 1) * y == x * y - y { lemma_mul_is_distributive_add(y, x, 1); lemma_mul_is_distributive_add(y, x, -1); } } lemma lemma_mul_auto_distributes() ensures forall x:int, y:int, z:int {:trigger (x + y) * z} :: (x + y) * z == x * z + y * z ensures forall x:int, y:int, z:int {:trigger (x - y) * z} :: (x - y) * z == x * z - y * z { lemma_mul_auto_succ(); forall x:int, y:int, z:int ensures (x + y) * z == x * z + y * z ensures (x - y) * z == x * z - y * z { var f1 := i => (x + i) * z == x * z + i * z; var f2 := i => (x - i) * z == x * z - i * z; assert forall i {:trigger (x + (i + 1)) * z} :: (x + (i + 1)) * z == ((x + i) + 1) * z == (x + i) * z + z; assert forall i {:trigger (x + (i - 1)) * z} :: (x + (i - 1)) * z == ((x + i) - 1) * z == (x + i) * z - z; assert forall i {:trigger (x - (i + 1)) * z} :: (x - (i + 1)) * z == ((x - i) - 1) * z == (x - i) * z - z; assert forall i {:trigger (x - (i - 1)) * z} :: (x - (i - 1)) * z == ((x - i) + 1) * z == (x - i) * z + z; lemma_mul_induction_forall(f1); lemma_mul_induction_forall(f2); assert f1(y); assert f2(y); } } } ================================================ FILE: ironfleet/src/Dafny/Libraries/Math/mul_nonlinear.i.dfy ================================================ //- //- WARNING: In general, you shouldn't need to call these directly. Try //- to use the ones in mul.i.dfy instead. They're more full-featured anyway. module Math__mul_nonlinear_i { // TODO_MODULE: module Math__mul_nonlinear_i { // WARNING: Think three times before adding anything to this file! // Nonlinear verification is highly unstable, so even if it appears to work, // it may cause problems down the road. Thus, we want to keep this file as // small and simple as possible. Instead of adding code here, try proving // it in div.i.dfy using the connection to the recursive definition lemma lemma_mul_strictly_positive(x:int, y:int) ensures (0 < x && 0 < y) ==> (0 < x*y) {} lemma lemma_mul_nonzero(x:int, y:int) ensures x*y != 0 <==> x != 0 && y != 0 {} lemma lemma_mul_is_associative(x:int, y:int, z:int) ensures x * (y * z) == (x * y) * z {} lemma lemma_mul_is_distributive_add(x:int, y:int, z:int) ensures x*(y + z) == x*y + x*z {} lemma lemma_mul_ordering(x:int, y:int) requires 0 < x requires 0 < y requires 0 <= x*y ensures x <= x*y && y <= x*y { } lemma lemma_mul_strict_inequality(x:int, y:int, z:int) requires x < y requires z > 0 ensures x*z < y*z {} lemma lemma_mul_by_zero_is_zero(x:int) ensures 0*x == 0 ensures x*0 == 0 { } // TODO_MODULE: } import opened Math__mul_nonlinear_i_ = Math__mul_nonlinear_i } ================================================ FILE: ironfleet/src/Dafny/Libraries/Math/power.i.dfy ================================================ include "powers.i.dfy" include "mul.i.dfy" module Math__power_i { import opened Math__power_s import opened Math__mul_i import opened Math__mul_auto_i //-lemma lemma_mul_passes_harmlessly_through_mod( //- ensures mul(x,y) % m == mul(x lemma lemma_power_0(b:int) ensures power(b,0) == 1 { reveal power(); } lemma lemma_power_1(b:int) ensures power(b,1) == b { calc { power(b,1); { reveal power(); } b*power(b,0); { lemma_power_0(b); } b*1; { lemma_mul_basics_forall(); } b; } } lemma lemma_0_power(e:nat) requires e > 0 ensures power(0,e) == 0 { reveal power(); lemma_mul_basics_forall(); if (e != 1) { lemma_0_power(e - 1); } } lemma lemma_1_power(e:nat) ensures power(1,e) == 1 { reveal power(); lemma_mul_basics_forall(); if (e != 0) { lemma_1_power(e - 1); } } lemma lemma_power_adds(b:int, e1:nat, e2:nat) decreases e1 ensures power(b,e1)*power(b,e2) == power(b,e1+e2) { if (e1==0) { calc { power(b,e1)*power(b,e2); { lemma_power_0(b); } 1*power(b,e2); { lemma_mul_basics_forall(); } power(b,0+e2); } } else { calc { power(b,e1)*power(b,e2); { reveal power(); } (b*power(b,e1-1))*power(b,e2); { lemma_mul_is_associative_forall(); } b*(power(b,e1-1)*power(b,e2)); { lemma_power_adds(b, e1-1, e2); } b*power(b,e1-1+e2); { reveal power(); } power(b,e1+e2); } } } lemma lemma_power_multiplies(a:int,b:nat,c:nat) decreases c ensures 0<=b*c ensures power(a,b*c) == power(power(a,b),c) { lemma_mul_nonnegative(b,c); if (0==c) { lemma_mul_basics_forall(); calc { power(a,b*c); { lemma_power_0(a); } 1; { lemma_power_0(power(a,b)); } power(power(a,b),c); } } else { calc { b*c - b; { lemma_mul_basics_forall(); } b*c - mul(b,1); { lemma_mul_is_distributive_forall(); } b*(c-1); } lemma_mul_nonnegative(b,c-1); assert 0 <= b*c-b; calc { power(a,b*c); power(a,b+b*c-b); { lemma_power_adds(a,b,b*c-b); } power(a,b)*power(a,b*c-b); power(a,b)*power(a,b*(c-1)); { lemma_power_multiplies(a,b,c-1); } power(a,b)*power(power(a,b),c-1); { reveal power(); } power(power(a,b),c); } } } lemma lemma_power_distributes(a:int, b:int, e:nat) decreases e ensures power(a*b, e) == power(a, e) * power(b, e) { reveal power(); lemma_mul_basics_forall(); if (e > 0) { calc { power(a*b, e); (a*b) * power(a*b, e - 1); { lemma_power_distributes(a, b, e - 1); } (a*b) * (power(a, e - 1) * power(b, e - 1)); { lemma_mul_is_associative_forall(); lemma_mul_is_commutative_forall(); } (a*power(a, e - 1)) * (b*power(b, e - 1)); power(a,e) * power(b,e); } lemma_mul_is_distributive_forall(); } } lemma lemma_power_auto() ensures forall x:int {:trigger power(x, 0)} :: power(x, 0) == 1 ensures forall x:int {:trigger power(x, 1)} :: power(x, 1) == x ensures forall x:int, y:int {:trigger power(x, y)} :: y == 0 ==> power(x, y) == 1 // REVIEW: because of Dafny's LitInt special treatment, these are not the same as the two ensures above ensures forall x:int, y:int {:trigger power(x, y)} :: y == 1 ==> power(x, y) == x // ... ensures forall x:int, y:int {:trigger x * y} :: 0 < x && 0 < y ==> x <= x * y ensures forall x:int, y:int {:trigger x * y} :: 0 < x && 1 < y ==> x < x * y ensures forall x:int, y:nat, z:nat {:trigger power(x, y + z)} :: power(x, y + z) == power(x, y) * power(x, z) ensures forall x:int, y:nat, z:nat {:trigger power(x, y - z)} :: y >= z ==> power(x, y - z) * power(x, z) == power(x, y) ensures forall x:int, y:int, z:nat {:trigger power(x * y, z)} :: power(x * y, z) == power(x, z) * power(y, z) { reveal power(); // This has to be revealed to allow power to be used in triggers forall x:int ensures power(x, 0) == 1 ensures power(x, 1) == x { lemma_power_0(x); lemma_power_1(x); } forall x:int, y:int, z:nat {:trigger power(x * y, z)} ensures power(x * y, z) == power(x, z) * power(y, z) { lemma_power_distributes(x, y, z); } forall x:int, y:nat, z:nat {:trigger power(x, y + z)} ensures power(x, y + z) == power(x, y) * power(x, z) { lemma_power_adds(x, y, z); } forall x:int, y:nat, z:nat {:trigger power(x, y - z)} | y >= z ensures power(x, y - z) * power(x, z) == power(x, y) { lemma_power_adds(x, y - z, z); } forall x:int, y:int {:trigger x * y} | 0 < x && 0 < y ensures x <= x * y { lemma_mul_auto(); lemma_mul_increases_forall(); lemma_mul_strictly_increases_forall(); } forall x:int, y:int {:trigger x * y} | 0 < x && 1 < y ensures x < x * y { lemma_mul_auto(); lemma_mul_increases_forall(); lemma_mul_strictly_increases_forall(); } } lemma lemma_power_positive(b:int, e:nat) requires 0 0 <= u ==> 0 < power(b, u)); } lemma lemma_power_increases(b:nat,e1:nat,e2:nat) requires 0 0 <= e ==> power(b, e1) <= power(b, e1 + e); forall i {:trigger TMulAutoLe(0, i)} | TMulAutoLe(0, i) && f(i) ensures f(i + 1) { calc { power(b, e1 + i); <= { lemma_power_positive(b, e1 + i); lemma_mul_left_inequality(power(b, e1 + i), 1, b); } power(b, e1 + i) * b; == { lemma_power_1(b); } power(b, e1 + i) * power(b, 1); == { lemma_power_adds(b, e1 + i, 1); } power(b, e1 + i + 1); } } lemma_mul_auto_induction(e2 - e1, f); } lemma lemma_power_strictly_increases(b:nat,e1:nat,e2:nat) requires 1 0 < e ==> power(b, e1) < power(b, e1 + e); forall i {:trigger TMulAutoLe(0, i)} | TMulAutoLe(0, i) && f(i) ensures f(i + 1) { calc { power(b, e1 + i); <= { lemma_power_positive(b, e1 + i); lemma_mul_left_inequality(power(b, e1 + i), 1, b); } power(b, e1 + i) * b; == { lemma_power_1(b); } power(b, e1 + i) * power(b, 1); == { lemma_power_adds(b, e1 + i, 1); } power(b, e1 + i + 1); } } lemma_mul_auto_induction(e2 - e1, f); } lemma lemma_square_is_power_2(x:nat) ensures power(x,2) == x*x { reveal power(); } } ================================================ FILE: ironfleet/src/Dafny/Libraries/Math/power2.i.dfy ================================================ include "power2s.i.dfy" include "powers.i.dfy" include "power.i.dfy" include "div.i.dfy" module Math__power2_i { import opened Math__power2_s import opened Math__power_s import opened Math__power_i import opened Math__div_nonlinear_i import opened Math__div_i import opened Math__mul_auto_i import opened Math__mul_i /* * Real definition in spec directory (included above); * but here's a commented copy for your edification. function {:opaque} power2(exp: nat) : nat ensures power2(exp) > 0 { if (exp==0) then 1 else 2*power2(exp-1) } */ lemma lemma_power2_is_power_2_general() ensures forall x:nat :: power2(x) == power(2,x) { reveal power2(); reveal power(); forall x:nat ensures power2(x) == power(2,x) { lemma_power2_is_power_2(x); } } lemma lemma_power2_is_power_2(x:nat) ensures power2(x) == power(2, x) { reveal power(); reveal power2(); if (x != 0) { lemma_power2_is_power_2(x - 1); } } lemma lemma_power2_auto() ensures power2(0) == 1 ensures power2(1) == 2 ensures forall x:nat, y:nat {:trigger power2(x + y)} :: power2(x + y) == power2(x) * power2(y) ensures forall x:nat, y:nat {:trigger power2(x - y)} :: x >= y ==> power2(x - y) * power2(y) == power2(x) ensures forall x:nat, y:nat {:trigger x * y} :: y == 2 ==> x * y == x + x { reveal power2(); lemma_power2_is_power_2_general(); lemma_power_auto(); } ////////////////////////////////////////////////////////////////////////////// lemma lemma_power2_strictly_increases(e1: int, e2: int) requires 0 <= e1 < e2 ensures power2(e1) < power2(e2) { lemma_power2_auto(); lemma_mul_auto_induction(e2 - e1, e => 0 < e ==> power2(e1) < power2(e1 + e)); } lemma lemma_power2_increases(e1: int, e2: int) requires 0 <= e1 <= e2 ensures power2(e1) <= power2(e2) { lemma_power2_auto(); lemma_mul_auto_induction(e2 - e1, e => 0 <= e ==> power2(e1) <= power2(e1 + e)); } // lemma lemma_power2_positive() // ensures forall e:nat :: 0 < power2(e) // { // lemma_power2_auto(); // lemma_mul_auto_induction_forall(e => 0 <= e ==> 0 < power2(e)); // } // lemma lemma_power2_nonzero_bigger_than_one() // ensures forall e:nat :: 0 1 < power2(e) // { // lemma_power2_auto(); // var f := e => (0 < e ==> 1 < power2(e)); // lemma_mul_auto_induction_forall(f); // assert forall e :: f[e] <==> (0 < e ==> 1 < power2(e)); // REVIEW: why isn't this obvious to Dafny? // } lemma lemma_power2_strictly_increases_converse(e1: int, e2: int) requires 0 <= e1 requires 0 < e2 requires power2(e1) < power2(e2) ensures e1 < e2 { if (e1 >= e2) { lemma_power2_increases(e2, e1); assert false; } } lemma lemma_power2_increases_converse(e1: int, e2: int) requires 0 < e1 requires 0 < e2 requires power2(e1) <= power2(e2) ensures e1 <= e2 { if (e1 > e2) { lemma_power2_strictly_increases(e2, e1); assert false; } } lemma lemma_power2_adds(e1:nat, e2:nat) decreases e2 ensures power2(e1 + e2) == power2(e1) * power2(e2) { reveal power2(); lemma_power2_auto(); } lemma lemma_power2_div_is_sub(x:int, y:int) requires 0 <= x <= y ensures power2(y - x) == power2(y) / power2(x) >= 0 { calc { power2(y) / power2(x); { lemma_power2_adds(y-x, x); } (power2(y-x)*power2(x)) / power2(x); { lemma_div_by_multiple(power2(y-x), power2(x)); } power2(y-x); } } lemma lemma_2toX32() ensures power2(0) == 0x1 ensures power2(1) == 0x2 ensures power2(2) == 0x4 ensures power2(3) == 0x8 ensures power2(4) == 0x10 ensures power2(5) == 0x20 ensures power2(6) == 0x40 ensures power2(7) == 0x80 ensures power2(8) == 0x100 ensures power2(9) == 0x200 ensures power2(10) == 0x400 ensures power2(11) == 0x800 ensures power2(12) == 0x1000 ensures power2(13) == 0x2000 ensures power2(14) == 0x4000 ensures power2(15) == 0x8000 ensures power2(16) == 0x10000 ensures power2(17) == 0x20000 ensures power2(18) == 0x40000 ensures power2(19) == 0x80000 ensures power2(20) == 0x100000 ensures power2(21) == 0x200000 ensures power2(22) == 0x400000 ensures power2(23) == 0x800000 ensures power2(24) == 0x1000000 ensures power2(25) == 0x2000000 ensures power2(26) == 0x4000000 ensures power2(27) == 0x8000000 ensures power2(28) == 0x10000000 ensures power2(29) == 0x20000000 ensures power2(30) == 0x40000000 ensures power2(31) == 0x80000000 ensures power2(32) == 0x100000000 { reveal power2(); } lemma lemma_2toX() ensures power2(64) == 18446744073709551616 ensures power2(60) == 1152921504606846976 ensures power2(32) == 4294967296 ensures power2(24) == 16777216 ensures power2(19) == 524288 ensures power2(16) == 65536 ensures power2(8) == 256 { lemma_2to32(); lemma_2to64(); } lemma lemma_power2_add8(n:int) requires n >= 0 ensures power2(n + 1) == 2 * power2(n) ensures power2(n + 2) == 4 * power2(n) ensures power2(n + 3) == 8 * power2(n) ensures power2(n + 4) == 16 * power2(n) ensures power2(n + 5) == 32 * power2(n) ensures power2(n + 6) == 64 * power2(n) ensures power2(n + 7) == 128 * power2(n) ensures power2(n + 8) == 256 * power2(n) { reveal power2(); } lemma lemma_2to32() ensures power2(32) == 4294967296 ensures power2(24) == 16777216 ensures power2(19) == 524288 ensures power2(16) == 65536 ensures power2(8) == 256 ensures power2(0) == 1 { lemma_2toX32(); } lemma lemma_2to64() ensures power2(64) == 18446744073709551616 ensures power2(60) == 1152921504606846976 { lemma_2to32(); lemma_power2_add8(32); lemma_power2_add8(40); lemma_power2_add8(48); lemma_power2_add8(56); } lemma lemma_power2_0_is_1() ensures power2(0) == 1 { reveal power2(); } lemma lemma_power2_1_is_2() ensures power2(1) == 2 { reveal power2(); } lemma lemma_bit_count_is_unique(x:int, a:int, b:int) requires 0= 0 ==> x / power2(24) == x / 16777216; ensures forall x :: x >= 0 ==> x / power2(16) == x / 65536; ensures forall x :: x >= 0 ==> x / power2(8) == x / 256; { lemma_2toX(); reveal power2(); lemma_div_is_div_recursive_forall(); forall x | x >= 0 ensures x / power2(24) == x / 16777216 && x / power2(16) == x / 65536 && x / power2(8) == x / 256; { lemma_div_2_to_8(x); lemma_div_2_to_16(x); lemma_div_2_to_24(x); } } lemma lemma_div_2_to_8(x:int) requires x >= 0; ensures x / power2(8) == x / 256; { lemma_2toX(); lemma_div_is_div_recursive_forall(); if (x < 256) { } else { lemma_div_2_to_8(x - 256); } } lemma lemma_div_2_to_16(x:int) requires x >= 0; ensures x / power2(16) == x / 65536; { lemma_2toX(); lemma_div_is_div_recursive_forall(); if (x < 65536) { } else { lemma_div_2_to_16(x - 65536); } } lemma lemma_div_2_to_24(x:int) requires x >= 0; ensures x / power2(24) == x / 16777216; { lemma_2toX(); lemma_div_is_div_recursive_forall(); if (x < 16777216) { } else { lemma_div_2_to_24(x - 16777216); } } */ //- //-//////////////////////////////////////////////////////////////////////////// /* lemma lemma_word_to_bytes_unique_specific_power2_helper1(a:int, b:int) requires a % 256 == b % 256; requires (a / power2(8)) % 256 == (b / power2(8)) % 256; requires 0 <= a; requires 0 <= b; ensures a % 65536 == b % 65536; { var d := 256; var c := 256; assert d*c == 65536; lemma_2toX(); calc { a % 65536; a % (d*c); { lemma_mod_breakdown(a,d,c); } d * ((a/d)%c) + a%d; d * ((b/d)%c) + b%d; { lemma_mod_breakdown(b,d,c); } b % (d*c); b % 65536; } } lemma lemma_word_to_bytes_unique_specific_power2_helper2(a:int, b:int) requires (a / power2(16)) % 256 == (b / power2(16)) % 256; requires a / power2(24) == b / power2(24); requires 0 <= a; requires 0 <= b; ensures a / power2(16) == b / power2(16); { var ap := a/power2(16); var bp := b/power2(16); var d := power2(8); lemma_2toX(); lemma_mul_strictly_positive_forall(); calc { ap/d; { lemma_div_denominator(a,power2(16),power2(8)); } a/(power2(16)*power2(8)); { lemma_power2_adds(16,8); } a/power2(24); b/power2(24); { lemma_power2_adds(16,8); } b/(power2(16)*power2(8)); { lemma_div_denominator(b,power2(16),power2(8)); } bp/d; } calc { a/power2(16); ap; { lemma_fundamental_div_mod(ap,d); } d*(ap/d)+ap%d; d*(bp/d)+bp%d; { lemma_fundamental_div_mod(bp,d); } bp; b/power2(16); } } lemma lemma_word_to_bytes_unique_specific_power2_helper3(a:int, b:int) requires a % 65536 == b % 65536; requires a / power2(16) == b / power2(16); requires 0 <= a; requires 0 <= b; ensures a == b; { lemma_2toX(); lemma_fundamental_div_mod(a,65536); lemma_fundamental_div_mod(b,65536); } lemma lemma_word_to_bytes_unique_specific_power2(a:int, b:int) requires a % 256 == b % 256; requires (a / power2(8)) % 256 == (b / power2(8)) % 256; requires (a / power2(16)) % 256 == (b / power2(16)) % 256; requires a / power2(24) == b / power2(24); requires 0 <= a; requires 0 <= b; ensures a == b; { lemma_word_to_bytes_unique_specific_power2_helper1(a, b); lemma_word_to_bytes_unique_specific_power2_helper2(a, b); lemma_word_to_bytes_unique_specific_power2_helper3(a, b); } */ lemma lemma_pull_out_powers_of_2(x:nat, y:nat, z:nat) ensures 0<=x*y ensures 0<=y*z ensures power(power2(x*y), z) == power(power2(x), y*z) { lemma_mul_nonnegative(x,y); lemma_mul_nonnegative(y,z); lemma_power_positive(2,x); calc { power(power2(x*y), z); { lemma_power2_is_power_2(x*y); } power(power(2,x*y), z); { lemma_power_multiplies(2, x, y); } power(power(power(2,x),y), z); { lemma_power_multiplies(power(2,x), y, z); } power(power(2,x), y*z); { lemma_power2_is_power_2(x); } power(power2(x), y*z); } } lemma lemma_rebase_powers_of_2() ensures forall n:nat, e:nat {:trigger power(power2(n), e)} :: 0 <= n * e && power(power2(n), e) == power2(n * e) { reveal power(); reveal power2(); forall n:nat, e:nat ensures 0 <= n * e && power(power2(n), e) == power2(n * e) { lemma_pull_out_powers_of_2(1, n, e); lemma_power2_auto(); lemma_power2_is_power_2_general(); } } lemma lemma_mask_div_2(c:nat) requires 0 0 < u ==> (power2(u)-1)/2 == power2(u-1)-1; assert forall i {:trigger TMulAutoLe(0, i)} :: TMulAutoLe(0, i) && f(i) ==> f(i + 1); assert forall i {:trigger TMulAutoLe(i, 0)} :: TMulAutoLe(i, 0) && f(i) ==> f(i - 1); lemma_mul_auto_induction(c, f); } lemma lemma_power2_division_inequality(x:nat, p:nat, s:nat) requires s<=p requires x { x/power2(s) >= power2(p-s); { lemma_mul_inequality(power2(p-s), x/power2(s), power2(s)); } (x/power2(s))*power2(s) >= power2(p-s)*power2(s); { lemma_fundamental_div_mod(x, power2(s)); lemma_mul_is_commutative_forall(); } x - x%power2(s) >= power2(p-s)*power2(s); { lemma_power2_adds(p-s, s); } x - x%power2(s) >= power2(p); { lemma_mod_properties(); } x >= power2(p); false; } } lemma lemma_power2_unfolding(a:nat, b:nat) ensures 0<=a*b ensures power(power2(a), b) == power2(a*b) { lemma_mul_nonnegative(a,b); lemma_power2_is_power_2(a); lemma_power_multiplies(2,a,b); lemma_power2_is_power_2(a*b); } function{:opaque} NatNumBits(n:nat):nat ensures NatNumBits(n) >= 0 { if n == 0 then 0 else 1 + NatNumBits(n / 2) } lemma lemma_Power2BoundIsNatNumBits(c:nat, n:nat) ensures (((c>0) ==> (power2(c-1) <= n)) && (n < power2(c))) <==> c == NatNumBits(n) { reveal NatNumBits(); reveal power2(); if (c > 0) { lemma_Power2BoundIsNatNumBits(c - 1, n / 2); } assert NatNumBits(n / 2) >= 0; //- dafnycc } } ================================================ FILE: ironfleet/src/Dafny/Libraries/Math/power2s.i.dfy ================================================ module Math__power2_s { // TODO_MODULE: module Math__power2_s { // TODO_MODULE: import opened Libraries__base_s function {:opaque} power2(exp: nat) : nat ensures power2(exp) > 0 { if (exp==0) then 1 else 2*power2(exp-1) } // TODO Yay! A proof in the spec! lemma lemma_power2_32() ensures power2(8) == 0x100 ensures power2(16) == 0x10000 ensures power2(24) == 0x1000000 ensures power2(32) == 0x100000000 { reveal power2(); assert power2(0) == 0x1; assert power2(2) == 0x4; assert power2(4) == 0x10; assert power2(6) == 0x40; assert power2(8) == 0x100; assert power2(10) == 0x400; assert power2(12) == 0x1000; assert power2(14) == 0x4000; assert power2(16) == 0x10000; assert power2(18) == 0x40000; assert power2(20) == 0x100000; assert power2(22) == 0x400000; assert power2(24) == 0x1000000; assert power2(26) == 0x4000000; assert power2(28) == 0x10000000; assert power2(30) == 0x40000000; } // TODO_MODULE: } import opened Math__power2_s_ = Math__power2_s } ================================================ FILE: ironfleet/src/Dafny/Libraries/Math/powers.i.dfy ================================================ module Math__power_s { // TODO_MODULE: module Math__power_s { function {:opaque} power(b:int, e:nat) : int decreases e // ensures b > 0 ==> 0 Exe net6.0 1701;1702;162;164;168;183;219;436;1717;1718 IronLockServer.Program ================================================ FILE: ironfleet/src/IronLockServer/IronLockServer.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.31005.135 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IronLockServer", "IronLockServer.csproj", "{80249939-7D35-43CA-891A-F4C73EC6D959}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {80249939-7D35-43CA-891A-F4C73EC6D959}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {80249939-7D35-43CA-891A-F4C73EC6D959}.Debug|Any CPU.Build.0 = Debug|Any CPU {80249939-7D35-43CA-891A-F4C73EC6D959}.Release|Any CPU.ActiveCfg = Release|Any CPU {80249939-7D35-43CA-891A-F4C73EC6D959}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {3EDDD386-2BE8-48A4-8188-FFDA2034F16D} EndGlobalSection EndGlobal ================================================ FILE: ironfleet/src/IronLockServer/Params.cs ================================================ using System; using System.Collections.Generic; using System.IO; using System.Net; using System.Text.RegularExpressions; namespace IronLockServer { public class Params { private string serviceFileName; private string privateKeyFileName; private string localHostNameOrAddress; private int localPort; private bool verbose; public Params() { serviceFileName = ""; privateKeyFileName = ""; localHostNameOrAddress = ""; localPort = 0; } public string ServiceFileName { get { return serviceFileName; } } public string PrivateKeyFileName { get { return privateKeyFileName; } } public string LocalHostNameOrAddress { get { return localHostNameOrAddress; } } public int LocalPort { get { return localPort; } } public bool Verbose { get { return verbose; } } public bool Validate() { if (serviceFileName.Length == 0) { Console.WriteLine("ERROR - Missing service parameter"); return false; } if (privateKeyFileName.Length == 0) { Console.WriteLine("ERROR - Missing private parameter"); return false; } return true; } public bool ProcessCommandLineArgument(string arg) { var pos = arg.IndexOf("="); if (pos < 0) { if (serviceFileName.Length == 0) { serviceFileName = arg; return true; } else if (privateKeyFileName.Length == 0) { privateKeyFileName = arg; return true; } else { Console.WriteLine("ERROR - Invalid argument {0}", arg); return false; } } var key = arg.Substring(0, pos).ToLower(); var value = arg.Substring(pos + 1); return SetValue(key, value); } private bool SetValue(string key, string value) { if (key == "addr") { localHostNameOrAddress = value; return true; } if (key == "port") { try { localPort = Convert.ToInt32(value); return true; } catch (Exception e) { Console.WriteLine("ERROR - Could not convert port {0} to a number. Exception:\n{1}", value, e); return false; } } if (key == "verbose") { if (value == "false") { verbose = false; return true; } if (value == "true") { verbose = true; return true; } Console.WriteLine("ERROR - Invalid verbose value {0} - should be false or true", value); return false; } Console.WriteLine("ERROR - Invalid argument key {0}", key); return false; } } } ================================================ FILE: ironfleet/src/IronLockServer/Program.cs ================================================ using IronfleetCommon; using IronfleetIoFramework; using MathNet.Numerics.Distributions; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Numerics; using System.Text.Json; using System.Threading; namespace IronLockServer { class Program { static void usage() { Console.Write(@" Usage: dotnet IronLockServer.dll [key=value]... - file path of the service description - file path of the private key Allowed keys: addr - local host name or address to listen to (default: whatever's specified in the private key file) port - port to listen to (default: whatever's specified in the private key file) verbose - use verbose output (false or true, default: false) "); } static void Main(string[] args) { Console.WriteLine("IronLockServer program started"); Console.WriteLine("Processing command-line arguments"); Params ps = new Params(); foreach (var arg in args) { if (!ps.ProcessCommandLineArgument(arg)) { usage(); return; } } if (!ps.Validate()) { usage(); return; } ServiceIdentity serviceIdentity = ServiceIdentity.ReadFromFile(ps.ServiceFileName); if (serviceIdentity == null) { return; } if (serviceIdentity.ServiceType != "IronLock") { Console.Error.WriteLine("ERROR - Service described by {0} is of type {1}, not IronLock", ps.ServiceFileName, serviceIdentity.ServiceType); return; } PrivateIdentity privateIdentity = PrivateIdentity.ReadFromFile(ps.PrivateKeyFileName); if (privateIdentity == null) { return; } var nc = Native____Io__s_Compile.NetClient.Create(privateIdentity, ps.LocalHostNameOrAddress, ps.LocalPort, serviceIdentity.Servers, ps.Verbose, serviceIdentity.UseSsl); Dafny.ISequence[] serverPublicKeys = serviceIdentity.Servers.Select(server => Dafny.Sequence.FromArray(nc.HashPublicKey(server.PublicKey))).ToArray(); var ironArgs = Dafny.Sequence>.FromArray(serverPublicKeys); Profiler.Initialize(); Native____Io__s_Compile.Time.Initialize(); Console.WriteLine("[[READY]]"); Main__i_Compile.__default.IronfleetMain(nc, ironArgs); Console.WriteLine("[[EXIT]]"); } } } ================================================ FILE: ironfleet/src/IronRSLClient/.gitignore ================================================ .vs Properties ================================================ FILE: ironfleet/src/IronRSLClient/IronRSLClient.csproj ================================================ net6.0 IronRSLClient 1.0.4 Jay Lorch and Chris Hawblitzel Microsoft Corporation true MIT ================================================ FILE: ironfleet/src/IronRSLClient/IronRSLClient.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.31321.278 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IronRSLClient", "IronRSLClient.csproj", "{0AC4042E-CFAF-41AD-86DD-C91B39D06CB5}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {0AC4042E-CFAF-41AD-86DD-C91B39D06CB5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0AC4042E-CFAF-41AD-86DD-C91B39D06CB5}.Debug|Any CPU.Build.0 = Debug|Any CPU {0AC4042E-CFAF-41AD-86DD-C91B39D06CB5}.Release|Any CPU.ActiveCfg = Release|Any CPU {0AC4042E-CFAF-41AD-86DD-C91B39D06CB5}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {AFC77FFD-EE03-4482-A506-7F4B3A3B4431} EndGlobalSection EndGlobal ================================================ FILE: ironfleet/src/IronRSLClient/RSLClient.cs ================================================ using IronfleetIoFramework; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; namespace IronRSLClient { public class RSLClient { ServiceIdentity serviceIdentity; byte[][] serverPublicKeys; bool verbose; UInt64 nextSeqNum; int primaryServerIndex; IoScheduler scheduler; public RSLClient(ServiceIdentity i_serviceIdentity, string serviceName, bool i_verbose) { serviceIdentity = i_serviceIdentity; if (serviceIdentity.ServiceType != "IronRSL" + serviceName) { Console.Error.WriteLine("Provided service identity has type {0}, not IronRSL{1}.", serviceIdentity.ServiceType, serviceName); throw new Exception("Wrong service type"); } verbose = i_verbose; nextSeqNum = 0; primaryServerIndex = 0; scheduler = IoScheduler.CreateClient(serviceIdentity.Servers, verbose, serviceIdentity.UseSsl); serverPublicKeys = serviceIdentity.Servers.Select(server => scheduler.HashPublicKey(server.PublicKey)).ToArray(); } public byte[] SubmitRequest (byte[] request, int timeBeforeServerSwitchMs = 1000) { UInt64 seqNum = nextSeqNum++; byte[] requestMessage; using (var memStream = new MemoryStream()) { IoEncoder.WriteUInt64(memStream, 0); // 0 means "this is a CMessage_Request" IoEncoder.WriteUInt64(memStream, seqNum); // sequence number IoEncoder.WriteUInt64(memStream, (UInt64)request.Length); // size of CAppRequest IoEncoder.WriteBytes(memStream, request, 0, (UInt64)request.Length); // CAppRequest requestMessage = memStream.ToArray(); } scheduler.SendPacket(serverPublicKeys[primaryServerIndex], requestMessage); if (verbose) { Console.WriteLine("Sending a request with sequence number {0} to {1}", seqNum, serviceIdentity.Servers[primaryServerIndex]); } while (true) { bool ok, timedOut; byte[] remote; byte[] replyBytes; scheduler.ReceivePacket(timeBeforeServerSwitchMs, out ok, out timedOut, out remote, out replyBytes); if (!ok) { throw new Exception("Unrecoverable networking failure"); } if (timedOut) { primaryServerIndex = (primaryServerIndex + 1) % serviceIdentity.Servers.Count(); if (verbose) { Console.WriteLine("#timeout; rotating to server {0}", primaryServerIndex); } scheduler.SendPacket(serverPublicKeys[primaryServerIndex], requestMessage); continue; } if (replyBytes.Length < 24) { throw new Exception(String.Format("Got RSL reply with invalid length {0}", replyBytes.Length)); } UInt64 messageType = IoEncoder.ExtractUInt64(replyBytes, 0); if (messageType != 6) { throw new Exception("Got RSL message that wasn't a reply"); } UInt64 replySeqNum = IoEncoder.ExtractUInt64(replyBytes, 8); if (replySeqNum != seqNum) { // This is a retransmission of a reply for an old sequence // number. Ignore it. continue; } UInt64 replyLength = IoEncoder.ExtractUInt64(replyBytes, 16); if (replyLength + 24 != (UInt64)replyBytes.Length) { throw new Exception(String.Format("Got RSL reply with invalid encoded length ({0} instead of {1})", replyLength, replyBytes.Length - 24)); } return replyBytes.Skip(24).ToArray(); } } } } ================================================ FILE: ironfleet/src/IronRSLCounterClient/.gitignore ================================================ .vs Properties/ ================================================ FILE: ironfleet/src/IronRSLCounterClient/Client.cs ================================================ using IronfleetCommon; using IronfleetIoFramework; using IronRSLClient; using System; using System.Collections.Generic; using System.IO; using System.Net; using System.Threading; using System.Linq; namespace IronRSLCounterClient { public class IncrementRequest { public IncrementRequest() { } public byte[] Encode() { MemoryStream memStream = new MemoryStream(); IoEncoder.WriteUInt64(memStream, 0); // request type (0 = increment) return memStream.ToArray(); } } public class IncrementReply { public UInt64 counterValue; private IncrementReply(UInt64 i_counterValue) { counterValue = i_counterValue; } public static IncrementReply Decode(byte[] bytes) { if (bytes.Length != 8) { Console.Error.WriteLine("Got invalid-length reply"); return null; } UInt64 counterValue = IoEncoder.ExtractUInt64(bytes, 0); return new IncrementReply(counterValue); } } public class Client { public int id; public Params ps; public ServiceIdentity serviceIdentity; private Client(int i_id, Params i_ps, ServiceIdentity i_serviceIdentity) { id = i_id; ps = i_ps; serviceIdentity = i_serviceIdentity; } static public IEnumerable StartThreads(Params ps, ServiceIdentity serviceIdentity) { for (int i = 0; i < ps.NumThreads; ++i) { Client c = new Client(i, ps, serviceIdentity); Thread t = new Thread(c.Run); t.Start(); yield return t; } } private void Run() { RSLClient rslClient = new RSLClient(serviceIdentity, "Counter", ps.Verbose); Thread.Sleep(3000); for (int requestNum = 1; true; ++requestNum) { var request = new IncrementRequest(); byte[] requestBytes = request.Encode(); var startTime = HiResTimer.Ticks; byte[] replyBytes = rslClient.SubmitRequest(requestBytes); var endTime = HiResTimer.Ticks; var reply = IncrementReply.Decode(replyBytes); if (ps.PrintReplies) { Console.WriteLine("Received increment reply with counter {0}", reply.counterValue); } Console.WriteLine("#req {0} {1} {2}", id, requestNum, HiResTimer.TicksToMilliseconds(endTime - startTime)); } } } } ================================================ FILE: ironfleet/src/IronRSLCounterClient/IronRSLCounterClient.csproj ================================================ Exe net6.0 ================================================ FILE: ironfleet/src/IronRSLCounterClient/IronRSLCounterClient.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.31019.35 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IronRSLCounterClient", "IronRSLCounterClient.csproj", "{A154E4D2-1C7D-47EF-BAE7-B802C50DB10E}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {A154E4D2-1C7D-47EF-BAE7-B802C50DB10E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A154E4D2-1C7D-47EF-BAE7-B802C50DB10E}.Debug|Any CPU.Build.0 = Debug|Any CPU {A154E4D2-1C7D-47EF-BAE7-B802C50DB10E}.Release|Any CPU.ActiveCfg = Release|Any CPU {A154E4D2-1C7D-47EF-BAE7-B802C50DB10E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {1CE7BF3F-5BCC-4D62-8CD7-273A890D9E66} EndGlobalSection EndGlobal ================================================ FILE: ironfleet/src/IronRSLCounterClient/Params.cs ================================================ using System; using System.Net; namespace IronRSLCounterClient { public class Params { private string serviceFileName; private int numThreads; private ulong experimentDuration; private bool verbose; private bool printReplies; public Params() { serviceFileName = ""; numThreads = 1; experimentDuration = 60; verbose = false; printReplies = false; } public string ServiceFileName { get { return serviceFileName; } } public int NumThreads { get { return numThreads; } } public ulong ExperimentDuration { get { return experimentDuration; } } public bool PrintReplies { get { return printReplies; } } public bool Verbose { get { return verbose; } } public bool Validate() { if (serviceFileName.Length == 0) { Console.WriteLine("ERROR - Missing service parameter"); return false; } return true; } public bool ProcessCommandLineArgument(string arg) { var pos = arg.IndexOf("="); if (pos < 0) { if (serviceFileName.Length == 0) { serviceFileName = arg; return true; } else { Console.WriteLine("Invalid argument {0}", arg); return false; } } var key = arg.Substring(0, pos).ToLower(); var value = arg.Substring(pos + 1); return SetValue(key, value); } private bool SetBoolValue(string key, string value, ref bool p) { if (value == "false") { p = false; return true; } else if (value == "true") { p = true; return true; } else { Console.WriteLine("ERROR - Invalid {0} value {1} - should be false or true", key, value); return false; } } private bool SetValue(string key, string value) { if (key == "verbose") { return SetBoolValue(key, value, ref verbose); } if (key == "print") { return SetBoolValue(key, value, ref printReplies); } if (key == "nthreads") { try { numThreads = Convert.ToInt32(value); if (numThreads < 1) { Console.WriteLine("Number of threads must be at least 1, so can't be {0}", numThreads); return false; } } catch (Exception e) { Console.WriteLine("Could not parse number of threads {0} as a number. Exception:\n{1}", value, e); return false; } return true; } if (key == "duration") { experimentDuration = Convert.ToUInt64(value); return true; } Console.WriteLine("Invalid argument key {0}", key); return false; } } } ================================================ FILE: ironfleet/src/IronRSLCounterClient/Program.cs ================================================ using IronfleetCommon; using IronfleetIoFramework; using System; using System.Linq; using System.Numerics; using System.Threading; using System.IO; using System.Net; using System.Collections.Generic; namespace IronRSLCounterClient { class Program { static void usage() { Console.Write(@" Usage: dotnet IronRSLCounterClient.dll [key=value]... - file path of the service description Allowed keys: nthreads - number of client threads to run (default 1) duration - duration of experiment in seconds (default 60) print - print replies (false or true, default false) verbose - print verbose output (false or true, default false) "); } static void Main(string[] args) { Params ps = new Params(); foreach (var arg in args) { if (!ps.ProcessCommandLineArgument(arg)) { usage(); return; } } if (!ps.Validate()) { usage(); return; } var serviceIdentity = ServiceIdentity.ReadFromFile(ps.ServiceFileName); if (serviceIdentity == null) { return; } HiResTimer.Initialize(); if (ps.Verbose) { Console.WriteLine("Client process starting {0} threads running for {1} s...", ps.NumThreads, ps.ExperimentDuration); } Console.WriteLine("[[READY]]"); // Start the experiment var threads = Client.StartThreads(ps, serviceIdentity).ToArray(); if (ps.ExperimentDuration == 0) { threads[0].Join(); } else { Thread.Sleep((int)ps.ExperimentDuration * 1000); Console.Out.WriteLine("[[DONE]]"); Console.Out.Flush(); Environment.Exit(0); } } } } ================================================ FILE: ironfleet/src/IronRSLCounterServer/.gitignore ================================================ .vs Properties/ ================================================ FILE: ironfleet/src/IronRSLCounterServer/IronRSLCounterServer.csproj ================================================  Exe net6.0 1701;1702;162;164;168;183;219;436;1717;1718 IronRSLServer.Program ================================================ FILE: ironfleet/src/IronRSLCounterServer/IronRSLCounterServer.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.31005.135 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IronRSLCounterServer", "IronRSLCounterServer.csproj", "{80249939-7D35-43CA-891A-F4C73EC6D959}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {80249939-7D35-43CA-891A-F4C73EC6D959}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {80249939-7D35-43CA-891A-F4C73EC6D959}.Debug|Any CPU.Build.0 = Debug|Any CPU {80249939-7D35-43CA-891A-F4C73EC6D959}.Release|Any CPU.ActiveCfg = Release|Any CPU {80249939-7D35-43CA-891A-F4C73EC6D959}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {3EDDD386-2BE8-48A4-8188-FFDA2034F16D} EndGlobalSection EndGlobal ================================================ FILE: ironfleet/src/IronRSLCounterServer/Service.cs ================================================ using IronfleetIoFramework; using System; using System.IO; namespace IronRSL { public class Service { UInt64 counter; private Service(UInt64 i_counter) { counter = i_counter; } public static string Name { get { return "Counter"; } } public static Service Initialize() { return new Service(0); } public static Service Deserialize(byte[] buf) { if (buf.Length != 8) { Console.Error.WriteLine("Received Deserialize with wrong number of bytes: {0} instead of 8", buf.Length); return new Service(0); } UInt64 counter = IoEncoder.ExtractUInt64(buf, 0); return new Service(counter); } public byte[] Serialize() { MemoryStream stream = new MemoryStream(); IoEncoder.WriteUInt64(stream, counter); return stream.ToArray(); } public byte[] HandleRequest(byte[] request) { if (request.Length != 8) { Console.Error.WriteLine("Received invalid request with wrong number of bytes: {0} instead of 8", request.Length); } else { UInt64 command = IoEncoder.ExtractUInt64(request, 0); if (command != 0) { Console.Error.WriteLine("Received request with invalid command: {0}", command); } else { counter++; } } MemoryStream stream = new MemoryStream(); IoEncoder.WriteUInt64(stream, counter); return stream.ToArray(); } } } ================================================ FILE: ironfleet/src/IronRSLKVClient/.gitignore ================================================ .vs Properties/ ================================================ FILE: ironfleet/src/IronRSLKVClient/Client.cs ================================================ using IronfleetCommon; using IronRSLClient; using IronfleetIoFramework; using KVMessages; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Text; using System.Threading; namespace IronRSLKVClient { public class Client { public int id; public Params ps; public ServiceIdentity serviceIdentity; private Client(int i_id, Params i_ps, ServiceIdentity i_serviceIdentity) { id = i_id; ps = i_ps; serviceIdentity = i_serviceIdentity; } static public IEnumerable StartThreads(Params ps, ServiceIdentity serviceIdentity) { for (int i = 0; i < ps.NumThreads; ++i) { Client c = new Client(i, ps, serviceIdentity); Thread t = new Thread(c.Run); t.Start(); yield return t; } } private static KVRequest GetRandomRequest(Random rng, Params ps) { int keySelector = rng.Next(26); char k = (char)('a' + keySelector); StringBuilder keyBuilder = new StringBuilder(); keyBuilder.Append(k); keyBuilder.Append(k); keyBuilder.Append(k); string key = keyBuilder.ToString(); int reqTypeSelector = rng.Next(); if (reqTypeSelector < ps.SetFraction * Int32.MaxValue) { char v = (char)('A' + keySelector); StringBuilder valBuilder = new StringBuilder(); valBuilder.Append(v); valBuilder.Append(v); valBuilder.Append(v); valBuilder.Append(v); valBuilder.Append(rng.Next(100000)); string val = valBuilder.ToString(); if (ps.PrintRequestsAndReplies) { Console.WriteLine("Submitting set request for {0} => {1}", key, val); } return new KVSetRequest(key, val); } else if (reqTypeSelector < (ps.SetFraction + ps.DeleteFraction) * Int32.MaxValue) { if (ps.PrintRequestsAndReplies) { Console.WriteLine("Submitting delete request for {0}", key); } return new KVDeleteRequest(key); } else { if (ps.PrintRequestsAndReplies) { Console.WriteLine("Submitting get request for {0}", key); } return new KVGetRequest(key); } } private void Run() { RSLClient rslClient = new RSLClient(serviceIdentity, "KV", ps.Verbose); Thread.Sleep(3000); Random rng = new Random(); for (int requestNum = 1; true; ++requestNum) { KVRequest request = GetRandomRequest(rng, ps); byte[] requestBytes = request.Encode(); var startTime = HiResTimer.Ticks; byte[] replyBytes = rslClient.SubmitRequest(requestBytes); var endTime = HiResTimer.Ticks; KVReply reply = KVReply.Decode(replyBytes, 0); if (ps.PrintRequestsAndReplies) { Console.WriteLine("Received reply of type {0}", reply.ReplyType); if (reply is KVGetFoundReply gfr) { Console.WriteLine("Value obtained for get was {0}", gfr.Val); } } Console.WriteLine("#req {0} {1} {2}", id, requestNum, HiResTimer.TicksToMilliseconds(endTime - startTime)); } } } } ================================================ FILE: ironfleet/src/IronRSLKVClient/IronRSLKVClient.csproj ================================================ Exe net6.0 ================================================ FILE: ironfleet/src/IronRSLKVClient/IronRSLKVClient.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.31019.35 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IronRSLKVClient", "IronRSLKVClient.csproj", "{A154E4D2-1C7D-47EF-BAE7-B802C50DB10E}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {A154E4D2-1C7D-47EF-BAE7-B802C50DB10E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A154E4D2-1C7D-47EF-BAE7-B802C50DB10E}.Debug|Any CPU.Build.0 = Debug|Any CPU {A154E4D2-1C7D-47EF-BAE7-B802C50DB10E}.Release|Any CPU.ActiveCfg = Release|Any CPU {A154E4D2-1C7D-47EF-BAE7-B802C50DB10E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {1CE7BF3F-5BCC-4D62-8CD7-273A890D9E66} EndGlobalSection EndGlobal ================================================ FILE: ironfleet/src/IronRSLKVClient/Params.cs ================================================ using System; using System.Net; namespace IronRSLKVClient { public class Params { private string serviceFileName; private int numThreads; private ulong experimentDuration; private double setFraction; private double deleteFraction; private bool verbose; private bool printRequestsAndReplies; public Params() { serviceFileName = ""; numThreads = 1; experimentDuration = 60; setFraction = 0.05; deleteFraction = 0.25; verbose = false; printRequestsAndReplies = false; } public string ServiceFileName { get { return serviceFileName; } } public int NumThreads { get { return numThreads; } } public ulong ExperimentDuration { get { return experimentDuration; } } public double SetFraction { get { return setFraction; } } public double DeleteFraction { get { return deleteFraction; } } public bool PrintRequestsAndReplies { get { return printRequestsAndReplies; } } public bool Verbose { get { return verbose; } } public bool Validate() { if (serviceFileName.Length == 0) { Console.WriteLine("ERROR - Missing service parameter"); return false; } return true; } public bool ProcessCommandLineArgument(string arg) { var pos = arg.IndexOf("="); if (pos < 0) { if (serviceFileName.Length == 0) { serviceFileName = arg; return true; } else { Console.WriteLine("Invalid argument {0}", arg); return false; } } var key = arg.Substring(0, pos).ToLower(); var value = arg.Substring(pos + 1); return SetValue(key, value); } private bool SetBoolValue(string key, string value, ref bool p) { if (value == "false") { p = false; return true; } else if (value == "true") { p = true; return true; } else { Console.WriteLine("ERROR - Invalid {0} value {1} - should be false or true", key, value); return false; } } private bool SetValue(string key, string value) { if (key == "verbose") { return SetBoolValue(key, value, ref verbose); } if (key == "print") { return SetBoolValue(key, value, ref printRequestsAndReplies); } if (key == "nthreads") { try { numThreads = Convert.ToInt32(value); if (numThreads < 1) { Console.WriteLine("Number of threads must be at least 1, so can't be {0}", numThreads); return false; } return true; } catch (Exception e) { Console.WriteLine("Could not parse number of threads {0} as a number. Exception:\n{1}", value, e); return false; } } if (key == "duration") { experimentDuration = Convert.ToUInt64(value); return true; } if (key == "setfraction") { try { setFraction = Convert.ToDouble(value); return true; } catch (Exception e) { Console.WriteLine("Could not parse set fraction {0} as a number. Exception:\n{1}", value, e); return false; } } if (key == "deletefraction") { try { deleteFraction = Convert.ToDouble(value); return true; } catch (Exception e) { Console.WriteLine("Could not parse delete fraction {0} as a number. Exception:\n{1}", value, e); return false; } } Console.WriteLine("Invalid argument key {0}", key); return false; } } } ================================================ FILE: ironfleet/src/IronRSLKVClient/Program.cs ================================================ using IronfleetCommon; using IronfleetIoFramework; using System; using System.Linq; using System.Numerics; using System.Threading; using System.IO; using System.Net; using System.Collections.Generic; namespace IronRSLKVClient { class Program { static void usage() { Console.Write(@" Usage: dotnet IronRSLKVClient.dll [key=value]... - file path of the service description Allowed keys: nthreads - number of client threads to run (default 1) duration - duration of experiment in seconds (default 60) setfraction - fraction of requests that are sets (default 0.25) deletefraction - fraction of requests that are deletes (default 0.05) print - print requests and replies (false or true, default false) verbose - print verbose output (false or true, default false) "); } static void Main(string[] args) { Params ps = new Params(); foreach (var arg in args) { if (!ps.ProcessCommandLineArgument(arg)) { usage(); return; } } if (!ps.Validate()) { usage(); return; } var serviceIdentity = ServiceIdentity.ReadFromFile(ps.ServiceFileName); if (serviceIdentity == null) { return; } HiResTimer.Initialize(); if (ps.Verbose) { Console.WriteLine("Client process starting {0} threads running for {1} s...", ps.NumThreads, ps.ExperimentDuration); } Console.WriteLine("[[READY]]"); // Start the experiment var threads = Client.StartThreads(ps, serviceIdentity).ToArray(); if (ps.ExperimentDuration == 0) { threads[0].Join(); } else { Thread.Sleep((int)ps.ExperimentDuration * 1000); Console.Out.WriteLine("[[DONE]]"); Console.Out.Flush(); Environment.Exit(0); } } } } ================================================ FILE: ironfleet/src/IronRSLKVServer/.gitignore ================================================ .vs Properties/ ================================================ FILE: ironfleet/src/IronRSLKVServer/IronRSLKVServer.csproj ================================================  Exe net6.0 1701;1702;162;164;168;183;219;436;1717;1718 IronRSLServer.Program ================================================ FILE: ironfleet/src/IronRSLKVServer/IronRSLKVServer.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.31005.135 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IronRSLKVServer", "IronRSLKVServer.csproj", "{80249939-7D35-43CA-891A-F4C73EC6D959}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {80249939-7D35-43CA-891A-F4C73EC6D959}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {80249939-7D35-43CA-891A-F4C73EC6D959}.Debug|Any CPU.Build.0 = Debug|Any CPU {80249939-7D35-43CA-891A-F4C73EC6D959}.Release|Any CPU.ActiveCfg = Release|Any CPU {80249939-7D35-43CA-891A-F4C73EC6D959}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {3EDDD386-2BE8-48A4-8188-FFDA2034F16D} EndGlobalSection EndGlobal ================================================ FILE: ironfleet/src/IronRSLKVServer/KVMessages.cs ================================================ using IronfleetIoFramework; using System; using System.IO; using System.Linq; using System.Text; namespace KVMessages { /////////////////////////////////// // KVRequest /////////////////////////////////// public enum KVRequestType { Invalid = 0, Get = 1, Set = 2, Delete = 3 } public abstract class KVRequest { public KVRequest() { } public virtual KVRequestType RequestType { get { return KVRequestType.Invalid; } } public void Write(Stream stream) { IoEncoder.WriteInt32(stream, (Int32)RequestType); WriteTypeSpecificFields(stream); } public byte[] Encode() { MemoryStream memStream = new MemoryStream(); Write(memStream); return memStream.ToArray(); } public virtual void WriteTypeSpecificFields(Stream stream) { } public static KVRequest Decode(byte[] bytes, int offset) { if (bytes.Length < offset + 4) { Console.Error.WriteLine("Received request of invalid length {0}", bytes.Length - offset); return null; } Int32 whichType = IoEncoder.ExtractInt32(bytes, offset); switch (whichType) { case (Int32)KVRequestType.Get : return KVGetRequest.ExtractFields(bytes, offset + 4); case (Int32)KVRequestType.Set : return KVSetRequest.ExtractFields(bytes, offset + 4); case (Int32)KVRequestType.Delete : return KVDeleteRequest.ExtractFields(bytes, offset + 4); default : Console.Error.WriteLine("Received request with invalid case {0}", whichType); return new KVInvalidRequest(); } } } public class KVInvalidRequest : KVRequest { } public class KVGetRequest : KVRequest { private string key; public KVGetRequest(string i_key) { key = i_key; } public override KVRequestType RequestType { get { return KVRequestType.Get; } } public string Key { get { return key; } } public static KVRequest ExtractFields(byte[] bytes, int offset) { Int32 keySize = IoEncoder.ExtractInt32(bytes, offset); if (keySize < 0 || keySize != bytes.Length - offset - 4) { Console.Error.WriteLine("Received get request with invalid key length ({0} instead of {1})", keySize, bytes.Length - offset - 4); return new KVInvalidRequest(); } byte[] keyBytes = bytes.Skip(offset + 4).ToArray(); string key; try { key = Encoding.UTF8.GetString(keyBytes); } catch (Exception) { Console.Error.WriteLine("Could not decode key in get request using UTF-8"); return new KVInvalidRequest(); } return new KVGetRequest(key); } public override void WriteTypeSpecificFields(Stream stream) { byte[] keyBytes = Encoding.UTF8.GetBytes(key); IoEncoder.WriteInt32(stream, keyBytes.Length); IoEncoder.WriteBytes(stream, keyBytes, 0, (UInt64)keyBytes.Length); } } public class KVSetRequest : KVRequest { private string key; private string val; public KVSetRequest(string i_key, string i_val) { key = i_key; val = i_val; } public override KVRequestType RequestType { get { return KVRequestType.Set; } } public string Key { get { return key; } } public string Val { get { return val; } } public static KVRequest ExtractFields(byte[] bytes, int offset) { Int32 keySize = IoEncoder.ExtractInt32(bytes, offset); if (keySize < 0 || keySize > bytes.Length - offset - 8) { Console.Error.WriteLine("Received set request with invalid key length ({0} > {1})", keySize, bytes.Length - offset - 8); return new KVInvalidRequest(); } byte[] keyBytes = bytes.Skip(offset + 4).Take(keySize).ToArray(); string key; try { key = Encoding.UTF8.GetString(keyBytes); } catch (Exception) { Console.Error.WriteLine("Could not decode key in set request using UTF-8"); return new KVInvalidRequest(); } Int32 valSize = IoEncoder.ExtractInt32(bytes, offset + 4 + keySize); if (valSize < 0 || valSize != bytes.Length - offset - 8 - keySize) { Console.Error.WriteLine("Received set request with invalid value length ({0} instead of {1})", keySize, bytes.Length - offset - 8 - keySize); return new KVInvalidRequest(); } byte[] valBytes = bytes.Skip(offset + 8 + keySize).ToArray(); string val; try { val = Encoding.UTF8.GetString(valBytes); } catch (Exception) { Console.Error.WriteLine("Could not decode value in set request using UTF-8"); return new KVInvalidRequest(); } return new KVSetRequest(key, val); } public override void WriteTypeSpecificFields(Stream stream) { byte[] keyBytes = Encoding.UTF8.GetBytes(key); byte[] valBytes = Encoding.UTF8.GetBytes(val); IoEncoder.WriteInt32(stream, keyBytes.Length); IoEncoder.WriteBytes(stream, keyBytes, 0, (UInt64)keyBytes.Length); IoEncoder.WriteInt32(stream, valBytes.Length); IoEncoder.WriteBytes(stream, valBytes, 0, (UInt64)valBytes.Length); } } public class KVDeleteRequest : KVRequest { private string key; public KVDeleteRequest(string i_key) { key = i_key; } public override KVRequestType RequestType { get { return KVRequestType.Delete; } } public string Key { get { return key; } } public static KVRequest ExtractFields(byte[] bytes, int offset) { Int32 keySize = IoEncoder.ExtractInt32(bytes, offset); if (keySize < 0 || keySize != bytes.Length - offset - 4) { Console.Error.WriteLine("Received delete request with invalid key length ({0} instead of {1})", keySize, bytes.Length - offset - 4); return new KVInvalidRequest(); } byte[] keyBytes = bytes.Skip(offset + 4).ToArray(); string key; try { key = Encoding.UTF8.GetString(keyBytes); } catch (Exception) { Console.Error.WriteLine("Could not decode key in delete request using UTF-8"); return new KVInvalidRequest(); } return new KVDeleteRequest(key); } public override void WriteTypeSpecificFields(Stream stream) { byte[] keyBytes = Encoding.UTF8.GetBytes(key); IoEncoder.WriteInt32(stream, keyBytes.Length); IoEncoder.WriteBytes(stream, keyBytes, 0, (UInt64)keyBytes.Length); } } /////////////////////////////////// // KVReply /////////////////////////////////// public enum KVReplyType { Invalid = 0, GetFound = 1, GetUnfound = 2, SetSuccess = 3, SetFailure = 4, DeleteFound = 5, DeleteUnfound = 6, InvalidRequest = 7 } public abstract class KVReply { public KVReply() { } public virtual KVReplyType ReplyType { get { return KVReplyType.Invalid; } } public void Write(Stream stream) { IoEncoder.WriteInt32(stream, (Int32)ReplyType); WriteTypeSpecificFields(stream); } public virtual void WriteTypeSpecificFields(Stream stream) { } public static KVReply Decode(byte[] bytes, int offset) { if (bytes.Length < offset + 4) { Console.Error.WriteLine("Received reply of invalid length {0}", bytes.Length - offset); return null; } Int32 whichCase = IoEncoder.ExtractInt32(bytes, offset); switch (whichCase) { case (Int32)KVReplyType.GetFound : return KVGetFoundReply.ExtractFields(bytes, offset + 4); case (Int32)KVReplyType.GetUnfound : return KVGetUnfoundReply.ExtractFields(bytes, offset + 4); case (Int32)KVReplyType.SetSuccess : return KVSetSuccessReply.ExtractFields(bytes, offset + 4); case (Int32)KVReplyType.SetFailure : return KVSetFailureReply.ExtractFields(bytes, offset + 4); case (Int32)KVReplyType.DeleteFound : return KVDeleteFoundReply.ExtractFields(bytes, offset + 4); case (Int32)KVReplyType.DeleteUnfound : return KVDeleteUnfoundReply.ExtractFields(bytes, offset + 4); case (Int32)KVReplyType.InvalidRequest : return KVInvalidRequestReply.ExtractFields(bytes, offset + 4); default : Console.Error.WriteLine("Received reply with invalid case {0}", whichCase); return new KVInvalidReply(); } } } public class KVInvalidReply : KVReply { } public class KVGetFoundReply : KVReply { private string val; public KVGetFoundReply(string i_val) { val = i_val; } public override KVReplyType ReplyType { get { return KVReplyType.GetFound; } } public string Val { get { return val; } } public static KVReply ExtractFields(byte[] bytes, int offset) { Int32 valSize = IoEncoder.ExtractInt32(bytes, offset); if (valSize < 0 || valSize != bytes.Length - offset - 4) { Console.Error.WriteLine("Received get-found reply with invalid value length ({0} instead of {1})", valSize, bytes.Length - offset - 4); return new KVInvalidReply(); } byte[] valBytes = bytes.Skip(offset + 4).ToArray(); string val; try { val = Encoding.UTF8.GetString(valBytes); } catch (Exception) { Console.Error.WriteLine("Could not decode value in get-found reply using UTF-8"); return new KVInvalidReply(); } return new KVGetFoundReply(val); } public override void WriteTypeSpecificFields(Stream stream) { byte[] valBytes = Encoding.UTF8.GetBytes(val); IoEncoder.WriteInt32(stream, valBytes.Length); IoEncoder.WriteBytes(stream, valBytes, 0, (UInt64)valBytes.Length); } } public class KVGetUnfoundReply : KVReply { public KVGetUnfoundReply() { } public override KVReplyType ReplyType { get { return KVReplyType.GetUnfound; } } public static KVReply ExtractFields(byte[] bytes, int offset) { if (bytes.Length != offset) { Console.Error.WriteLine("Received get-unfound reply with {0} extraneous bytes", bytes.Length - offset); return new KVInvalidReply(); } return new KVGetUnfoundReply(); } } public class KVSetSuccessReply : KVReply { public KVSetSuccessReply() { } public override KVReplyType ReplyType { get { return KVReplyType.SetSuccess; } } public static KVReply ExtractFields(byte[] bytes, int offset) { if (bytes.Length != offset) { Console.Error.WriteLine("Received set-success reply with {0} extraneous bytes", bytes.Length - offset); return new KVInvalidReply(); } return new KVSetSuccessReply(); } } public class KVSetFailureReply : KVReply { public KVSetFailureReply() { } public override KVReplyType ReplyType { get { return KVReplyType.SetFailure; } } public static KVReply ExtractFields(byte[] bytes, int offset) { if (bytes.Length != offset) { Console.Error.WriteLine("Received set-success reply with {0} extraneous bytes", bytes.Length - offset); return new KVInvalidReply(); } return new KVSetFailureReply(); } } public class KVDeleteFoundReply : KVReply { public KVDeleteFoundReply() { } public override KVReplyType ReplyType { get { return KVReplyType.DeleteFound; } } public static KVReply ExtractFields(byte[] bytes, int offset) { if (bytes.Length != offset) { Console.Error.WriteLine("Received delete-found reply with {0} extraneous bytes", bytes.Length - offset); return new KVInvalidReply(); } return new KVDeleteFoundReply(); } } public class KVDeleteUnfoundReply : KVReply { public KVDeleteUnfoundReply() { } public override KVReplyType ReplyType { get { return KVReplyType.DeleteUnfound; } } public static KVReply ExtractFields(byte[] bytes, int offset) { if (bytes.Length != offset) { Console.Error.WriteLine("Received delete-unfound reply with {0} extraneous bytes", bytes.Length - offset); return new KVInvalidReply(); } return new KVDeleteUnfoundReply(); } } public class KVInvalidRequestReply : KVReply { public KVInvalidRequestReply() { } public override KVReplyType ReplyType { get { return KVReplyType.InvalidRequest; } } public static KVReply ExtractFields(byte[] bytes, int offset) { if (bytes.Length != offset) { Console.Error.WriteLine("Received invalid-request reply with {0} extraneous bytes", bytes.Length - offset); return new KVInvalidReply(); } return new KVInvalidRequestReply(); } } } ================================================ FILE: ironfleet/src/IronRSLKVServer/Service.cs ================================================ using IronfleetIoFramework; using KVMessages; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; namespace IronRSL { public class Service { Dictionary kvStore; public static string Name { get { return "KV"; } } private Service() { kvStore = new Dictionary(); } public static int MaxKeySize { get { return 0x10_0000; /* 1 MB */ } } public static int MaxValueSize { get { return 0x800_0000; /* 128 MB */ } } public static int MaxNumKeys { get { return 100_000_000; /* 100 million */} } public static Service Initialize() { return new Service(); } private void AddInitialKey(string key, string val) { kvStore[key] = val; } public static Service Deserialize(byte[] buf) { Service service = new Service(); int offset = 0; while (offset < buf.Length) { if (offset + 4 > buf.Length) { Console.Error.WriteLine("WARNING - Got partial key size in state machine state"); break; } Int32 keySize = IoEncoder.ExtractInt32(buf, offset); if (keySize < 0 || keySize > MaxKeySize || keySize > buf.Length - offset - 8) { Console.Error.WriteLine("WARNING - Got invalid key size ({0}) in state machine state", keySize); break; } if (keySize > buf.Length - offset - 8) { Console.Error.WriteLine("WARNING - Got key size {0} that exceeds the {1} bytes remaining in state machine state", keySize, buf.Length - offset - 8); break; } byte[] keyBytes = buf.Skip(offset + 4).Take(keySize).ToArray(); Int32 valueSize = IoEncoder.ExtractInt32(buf, offset + 4 + keySize); if (valueSize < 0 || valueSize > MaxValueSize) { Console.Error.WriteLine("WARNING - Got invalid value size {0} in state machine state", valueSize); break; } if (valueSize > buf.Length - offset - 8 - keySize) { Console.Error.WriteLine("WARNING - Got value size {0} that exceeds the {1} bytes remaining in state machine state", valueSize, buf.Length - offset - 8 - keySize); break; } byte[] valueBytes = buf.Skip(offset + 8 + keySize).Take(valueSize).ToArray(); offset += (keySize + valueSize + 8); string key; try { key = Encoding.UTF8.GetString(keyBytes); } catch (Exception e) { Console.Error.WriteLine("WARNING - Got non-UTF-8-encoded key in state machine state"); break; } string value; try { value = Encoding.UTF8.GetString(valueBytes); } catch (Exception e) { Console.Error.WriteLine("WARNING - Got non-UTF-8-encoded value in state machine state"); break; } service.AddInitialKey(key, value); } return service; } public byte[] Serialize() { MemoryStream stream = new MemoryStream(); foreach (var kv in kvStore) { byte[] keyBytes = Encoding.UTF8.GetBytes(kv.Key); byte[] valueBytes = Encoding.UTF8.GetBytes(kv.Value); IoEncoder.WriteInt32(stream, keyBytes.Length); IoEncoder.WriteBytes(stream, keyBytes, 0, (UInt64)keyBytes.Length); IoEncoder.WriteInt32(stream, valueBytes.Length); IoEncoder.WriteBytes(stream, valueBytes, 0, (UInt64)valueBytes.Length); } return stream.ToArray(); } private KVReply HandleRequestInternal(KVRequest req) { if (req is KVGetRequest greq) { if (greq.Key.Length > MaxKeySize) { Console.Error.WriteLine("Received get request with too-large key size {0}", greq.Key.Length); return new KVInvalidRequestReply(); } string val; if (kvStore.TryGetValue(greq.Key, out val)) { return new KVGetFoundReply(val); } else { return new KVGetUnfoundReply(); } } if (req is KVSetRequest sreq) { if (sreq.Key.Length > MaxKeySize) { Console.Error.WriteLine("Received set request with too-large key size {0}", sreq.Key.Length); return new KVInvalidRequestReply(); } if (sreq.Val.Length > MaxValueSize) { Console.Error.WriteLine("Received set request with too-large value size {0}", sreq.Val.Length); return new KVInvalidRequestReply(); } if (kvStore.Count == MaxNumKeys && !kvStore.ContainsKey(sreq.Key)) { Console.Error.WriteLine("Received set request with new key when KV store size was at its maximum"); return new KVSetFailureReply(); } kvStore[sreq.Key] = sreq.Val; return new KVSetSuccessReply(); } if (req is KVDeleteRequest dreq) { if (dreq.Key.Length > MaxKeySize) { Console.Error.WriteLine("Received delete request with too-large key size {0}", dreq.Key.Length); return new KVInvalidRequestReply(); } if (kvStore.ContainsKey(dreq.Key)) { kvStore.Remove(dreq.Key); return new KVDeleteFoundReply(); } return new KVDeleteUnfoundReply(); } return new KVInvalidRequestReply(); } public byte[] HandleRequest(byte[] requestBytes) { KVRequest request = KVRequest.Decode(requestBytes, 0); KVReply reply = HandleRequestInternal(request); MemoryStream stream = new MemoryStream(); reply.Write(stream); return stream.ToArray(); } } } ================================================ FILE: ironfleet/src/IronSHTClient/.gitignore ================================================ *.v12.suo .vs/ Properties/ ================================================ FILE: ironfleet/src/IronSHTClient/Client.cs ================================================ using IronfleetCommon; using IronfleetIoFramework; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Threading; namespace IronSHTClient { public abstract class MessageBase { public ulong CaseId { get; private set; } protected MessageBase(ulong caseId) { this.CaseId = caseId; } public abstract byte[] ToBigEndianByteArray(); public byte[] ToByteArray() { return this.ToBigEndianByteArray(); } protected void EncodeUlong(MemoryStream memStream, ulong value) { if (null == memStream) { throw new ArgumentNullException("memStream"); } var bytes = BitConverter.GetBytes(value); if (BitConverter.IsLittleEndian) { Array.Reverse(bytes); } memStream.Write(bytes, 0, bytes.Length); } protected void EncodeBool(MemoryStream memStream, bool value) { this.EncodeUlong(memStream, value ? 1UL : 0); } protected void EncodeBytes(MemoryStream memStream, byte[] value) { if (null == value) { throw new ArgumentNullException("value"); } this.EncodeUlong(memStream, (ulong)value.Length); memStream.Write(value, 0, value.Length); } protected void EncodeHeader(MemoryStream memStream) { this.EncodeUlong(memStream, CaseId); } } public class GetRequestMessage : MessageBase { public byte[] Value { get; set; } public ulong seqNum; public byte[] myPublicKey; public ulong key; public GetRequestMessage(ulong seqNum, byte[] myPublicKey, ulong key) : base(0) { this.seqNum = seqNum; this.myPublicKey = myPublicKey; this.key = key; } public override byte[] ToBigEndianByteArray() { return this.Encode(); } public ulong GetSeqNum() { return seqNum; } private byte[] Encode(bool retrans = false) { using (var memStream = new MemoryStream()) { this.EncodeUlong(memStream, (ulong)0); // case for CSingleMessage this.EncodeUlong(memStream, (ulong)seqNum); // field one in CSingleMessage this.EncodeBytes(memStream, myPublicKey); // field two in CSingleMessage this.EncodeUlong(memStream, (ulong)0); // case for GetRequest this.EncodeUlong(memStream, key); // field one in GetRequest return memStream.ToArray(); } } } public class SetRequestMessage : MessageBase { public ulong seqNum; public byte[] myPublicKey; public ulong key; public ulong sizeValue; public Random rnd; public SetRequestMessage(ulong seqNum, byte[] myPublicKey, ulong key, ulong sizeValue) : base(0) { this.seqNum = seqNum; this.myPublicKey = myPublicKey; this.key = key; this.sizeValue = sizeValue; rnd = new Random(); } public override byte[] ToBigEndianByteArray() { return this.Encode(); } public ulong GetSeqNum() { return seqNum; } private byte[] Encode(bool retrans = false) { using (var memStream = new MemoryStream()) { byte[] value = new byte[sizeValue]; rnd.NextBytes(value); this.EncodeUlong(memStream, (ulong)0); // case for CSingleMessage this.EncodeUlong(memStream, (ulong)seqNum); // field one in CSingleMessage this.EncodeBytes(memStream, this.myPublicKey); // field two in CSingleMessage this.EncodeUlong(memStream, (ulong)1); // case for SetRequest this.EncodeUlong(memStream, key); // field one in SetRequest this.EncodeUlong(memStream, (ulong)0); // case for OptionalValue this.EncodeBytes(memStream, value); // field two in SetRequest return memStream.ToArray(); } } } public class ShardRequestMessage : MessageBase { public ulong seqNum; public byte[] myPublicKey; public ulong k_lo, k_hi; public byte[] recipient; public ShardRequestMessage(ulong seqNum, byte[] myPublicKey, ulong k_lo, ulong k_hi, byte[] recipient) : base(0) { this.seqNum = seqNum; this.myPublicKey = myPublicKey; this.k_lo = k_lo; this.k_hi = k_hi; this.recipient = recipient; } public override byte[] ToBigEndianByteArray() { return this.Encode(); } public ulong GetSeqNum() { return seqNum; } private byte[] Encode(bool retrans = false) { using (var memStream = new MemoryStream()) { this.EncodeUlong(memStream, (ulong)0); // case for CSingleMessage this.EncodeUlong(memStream, (ulong)seqNum); // field one in CSingleMessage this.EncodeBytes(memStream, this.myPublicKey); // field two in CSingleMessage this.EncodeUlong(memStream, (ulong)4); // case for ShardRequest // encode a KeyRange this.EncodeUlong(memStream, (ulong)0); // case for KeyPlus(k:Key) this.EncodeUlong(memStream, (ulong)k_lo); // klo this.EncodeUlong(memStream, (ulong)0); // case for KeyPlus(k:Key) this.EncodeUlong(memStream, (ulong)k_hi); // khi // encode the recipient this.EncodeBytes(memStream, this.recipient); return memStream.ToArray(); } } } public class AckMessage : MessageBase { public byte[] Value { get; set; } public ulong seqNum; public AckMessage(ulong seqNum) : base(0) { this.seqNum = seqNum; } public override byte[] ToBigEndianByteArray() { return this.Encode(); } public ulong GetSeqNum() { return seqNum; } private byte[] Encode(bool retrans = false) { using (var memStream = new MemoryStream()) { this.EncodeUlong(memStream, (ulong)1); // case for CAck this.EncodeUlong(memStream, (ulong)seqNum); // field one in CSingleMessage return memStream.ToArray(); } } } public class ThreadParams { public Params ps; public ulong id; public ThreadParams(ulong i_id, Params i_ps) { id = i_id; ps = i_ps; } } public class Client { public int id; public Params ps; public IoScheduler scheduler; public ServiceIdentity serviceIdentity; private Client(int i_id, Params i_ps, ServiceIdentity i_serviceIdentity) { id = i_id; ps = i_ps; serviceIdentity = i_serviceIdentity; } static public IEnumerable StartSetupThreads(Params ps, ServiceIdentity serviceIdentity) { if (ps.NumThreads < 0) { throw new ArgumentException("count is less than 1", "count"); } for (int i = 0; i < ps.NumSetupThreads; ++i) { var c = new Client(i, ps, serviceIdentity); Thread t = new Thread(c.Setup); t.Start(); yield return t; } } static public IEnumerable StartExperimentThreads(Params ps, ServiceIdentity serviceIdentity) { if (ps.NumThreads < 0) { throw new ArgumentException("count is less than 1", "count"); } for (int i = 0; i < ps.NumThreads; ++i) { var c = new Client(i, ps, serviceIdentity); Thread t = new Thread(c.Experiment); t.Start(); yield return t; } } public string ByteArrayToString(byte[] ba) { string hex = BitConverter.ToString(ba); return hex.Replace("-", ""); } public void Setup() { scheduler = IoScheduler.CreateClient(serviceIdentity.Servers, ps.Verbose, serviceIdentity.UseSsl); byte[] myPublicKey = IoScheduler.GetCertificatePublicKey(scheduler.MyCert); int serverIdx = 0; ulong seqNum = 0; ulong requestKey; for (requestKey = 0; requestKey < (ulong)ps.NumKeys; ++requestKey) { seqNum++; var msg = new SetRequestMessage(seqNum, myPublicKey, requestKey, (ulong)ps.ValueSize); if (ps.Verbose) { Console.WriteLine("Sending set request message with seq {0}, key {1} to server {2}", seqNum, requestKey, serverIdx); } this.Send(msg, serviceIdentity.Servers[serverIdx].PublicKey); // Wait for the reply var receivedReply = false; while (!receivedReply) { byte[] bytes = Receive(); var endTime = HiResTimer.Ticks; if (bytes == null) { //serverIdx = (serverIdx + 1) % serviceIdentity.Servers.Count(); Console.WriteLine("#timeout; retrying {0}", serverIdx); this.Send(msg, serviceIdentity.Servers[serverIdx].PublicKey); continue; } //Trace("Got the following reply:" + ByteArrayToString(bytes)); //Console.Out.WriteLine("Got packet length: " + bytes.Length); if (bytes.Length == 16) { //Ignore acks if (ps.Verbose) { Console.WriteLine("Received ack"); } } else if (bytes.Length >= 48) { var replySeqNum = ExtractBE64(bytes, offset: 8); if (ps.Verbose) { Console.WriteLine("Reply sequence number : {0}", replySeqNum); } var ack_msg = new AckMessage(replySeqNum); if (ps.Verbose) { Console.Out.WriteLine("Client {0}: Sending an ack with sequence number {1} to {2}", id, replySeqNum, serviceIdentity.Servers[serverIdx]); } this.Send(ack_msg, serviceIdentity.Servers[serverIdx].PublicKey); int publicKeyLength = Convert.ToInt32(ExtractBE64(bytes, offset: 16)); if (bytes.Length < publicKeyLength + 40) { Console.WriteLine("ERROR - Received too-short message (size {0} not long enough for public key of length {1})", bytes.Length, publicKeyLength); } else { var replyKey = ExtractBE64(bytes, offset: 32 + publicKeyLength); // Need to send an ack if (ps.Verbose) { Console.WriteLine("Request key : {0}", requestKey); Console.WriteLine("Reply key : {0}", replyKey); Console.WriteLine("Got packet length: {0}", bytes.Length); } if (replyKey == requestKey) { receivedReply = true; } } } } } } private void ReceiveReply(int serverIdx, byte[] myPublicKey, ulong requestKey, bool receiveOnlyAcks, bool expectRedirect = false) { var receivedReply = false; while (!receivedReply) { byte[] bytes = Receive(); if (bytes == null) { Console.WriteLine("#timeout; retrying {0}", serverIdx); continue; } if (bytes.Length == 16) { var replySeqNum = ExtractBE64(bytes, offset: 8); if (ps.Verbose) { Console.WriteLine("Received an ack for sequence number {0}", replySeqNum); } if (receiveOnlyAcks) { receivedReply = true; } } else if (bytes.Length >= 48) { var replySeqNum = ExtractBE64(bytes, offset: 8); var ack_msg = new AckMessage(replySeqNum); this.Send(ack_msg, serviceIdentity.Servers[serverIdx].PublicKey); int publicKeyLength = Convert.ToInt32(ExtractBE64(bytes, offset: 16)); if (bytes.Length < publicKeyLength + 40) { Console.WriteLine("ERROR - Received too-short message (size {0} not long enough for public key of length {1})", bytes.Length, publicKeyLength); } else { var cmessage_case = ExtractBE64(bytes, offset: 24 + publicKeyLength); if (ps.Verbose) { Console.WriteLine("Received Message Case {0}", cmessage_case); } var replyKey = ExtractBE64(bytes, offset: 32 + publicKeyLength); if (ps.Verbose) { if (cmessage_case == 2) { Console.WriteLine("Received a reply with key {0}", replyKey); } else if (cmessage_case == 3) { Console.WriteLine("Received a redirect for key {0}", replyKey); } } if (replyKey == requestKey && (expectRedirect ? cmessage_case == 3 : cmessage_case == 2)) { receivedReply = true; } } } } } public void Experiment() { ulong requestKey; int serverIdx = 0; scheduler = IoScheduler.CreateClient(serviceIdentity.Servers, ps.Verbose, serviceIdentity.UseSsl); byte[] myPublicKey = IoScheduler.GetCertificatePublicKey(scheduler.MyCert); ulong seqNum = 0; // Test the functionality of the Sharding if (ps.Workload == 'f') { // A delegation can delegate at most 61 keys, so make sure // there can't be that many keys in the range by having the // range be smaller than 61. ulong k_lo = 125; ulong k_hi = 175; requestKey = 150; var recipient = serviceIdentity.Servers[(serverIdx + 1) % serviceIdentity.Servers.Count()]; seqNum++; var msg = new GetRequestMessage(seqNum, myPublicKey, requestKey); this.Send(msg, serviceIdentity.Servers[serverIdx].PublicKey); ReceiveReply(serverIdx, myPublicKey, requestKey, false); seqNum++; Console.WriteLine("Sending a Shard request with a sequence number {0}", seqNum); var shardMessage = new ShardRequestMessage(seqNum, myPublicKey, k_lo, k_hi, recipient.PublicKey); this.Send(shardMessage, serviceIdentity.Servers[serverIdx].PublicKey); ReceiveReply(serverIdx, myPublicKey, requestKey, true); Thread.Sleep(5000); Console.WriteLine("Sending a GetRequest after a Shard, expect a redirect"); seqNum++; msg = new GetRequestMessage(seqNum, myPublicKey, requestKey); this.Send(msg, serviceIdentity.Servers[(serverIdx + 0) % serviceIdentity.Servers.Count()].PublicKey); ReceiveReply(serverIdx, myPublicKey, requestKey, false, expectRedirect: true); Thread.Sleep(5000); Console.WriteLine("Sending a GetRequest after a Shard to the second host, expect a reply"); // Must use sequence number 1 since this is the first message // to this server. msg = new GetRequestMessage(1, myPublicKey, requestKey); this.Send(msg, serviceIdentity.Servers[(serverIdx + 1) % serviceIdentity.Servers.Count()].PublicKey); ReceiveReply((serverIdx + 1) % serviceIdentity.Servers.Count(), myPublicKey, requestKey, false); Console.WriteLine("Successfully received reply"); return; } // Run an actual workload while (true) { seqNum++; var receivedReply = false; requestKey = seqNum % (ulong)ps.NumKeys; MessageBase msg; if (ps.Workload == 'g') { msg = new GetRequestMessage(seqNum, myPublicKey, requestKey); } else { msg = new SetRequestMessage(seqNum, myPublicKey, requestKey, (ulong)ps.ValueSize); } var startTime = HiResTimer.Ticks; this.Send(msg, serviceIdentity.Servers[serverIdx].PublicKey); // Wait for the reply while (!receivedReply) { byte[] bytes = Receive(); if (bytes == null) { //serverIdx = (serverIdx + 1) % serviceIdentity.Servers.Count(); //Console.WriteLine("#timeout; rotating to server {0}", serverIdx); Console.WriteLine("#timeout; retrying {0}", serverIdx); this.Send(msg, serviceIdentity.Servers[serverIdx].PublicKey); continue; } var endTime = HiResTimer.Ticks; if (bytes.Length == 16) { //Ignore acks } else if (bytes.Length >= 56) { var replySeqNum = ExtractBE64(bytes, offset: 8); if (ps.Verbose) { Console.WriteLine("Reply sequence number : {0}", replySeqNum); Console.WriteLine("Client {0}: Sending an ack with sequence number {1} to {2}", id, replySeqNum, serviceIdentity.Servers[serverIdx]); } if (seqNum % 100 == 0) { var ack_msg = new AckMessage(replySeqNum); this.Send(ack_msg, serviceIdentity.Servers[serverIdx].PublicKey); } int publicKeyLength = Convert.ToInt32(ExtractBE64(bytes, offset: 16)); if (bytes.Length < publicKeyLength + 40) { Console.WriteLine("ERROR - Received too-short message (size {0} not long enough for public key of length {1})", bytes.Length, publicKeyLength); } else { var replyKey = ExtractBE64(bytes, offset: 32 + publicKeyLength); // Need to send an ack if (ps.Verbose) { Console.WriteLine("Request key : {0}", requestKey); Console.WriteLine("Reply key : {0}", replyKey); Console.WriteLine("Got packet length: {0}", bytes.Length); } // key is the same as the sequence number if (replyKey == requestKey) { receivedReply = true; Console.WriteLine("#req {0} {1} {2}", id, seqNum, HiResTimer.TicksToMilliseconds(endTime - startTime)); } } } else { Console.WriteLine("Received packet of unexpected length {0}", bytes.Length); } } } } private void Send(MessageBase msg, byte[] remote) { var a = msg.ToBigEndianByteArray(); remote = scheduler.HashPublicKey(remote); if (!scheduler.SendPacket(remote, a)) { throw new InvalidOperationException("failed to send complete message."); } } private byte[] Receive() { bool ok; bool timedOut; byte[] remote; byte[] buffer; scheduler.ReceivePacket(1000, out ok, out timedOut, out remote, out buffer); return buffer; } public ulong EncodeIpPort(IPEndPoint ep) { ushort port = (ushort)ep.Port; byte[] addrBytes = ep.Address.GetAddressBytes(); uint addr = ExtractBE32(addrBytes, 0); MemoryStream str = new MemoryStream(); ushort preamble = 0; var bytes = BitConverter.GetBytes(preamble); str.Write(bytes, 0, bytes.Length); bytes = BitConverter.GetBytes(addr); if (BitConverter.IsLittleEndian) { Array.Reverse(bytes); } str.Write(bytes, 0, bytes.Length); bytes = BitConverter.GetBytes(port); if (BitConverter.IsLittleEndian) { Array.Reverse(bytes); } str.Write(bytes, 0, bytes.Length); byte[] s = str.ToArray(); Array.Reverse(s); return BitConverter.ToUInt64(s, 0); } public static UInt64 ExtractBE64(byte[] byteArray, int offset) { byte[] extractedBytes = byteArray.Skip(offset).Take(8).ToArray(); Array.Reverse(extractedBytes); return BitConverter.ToUInt64(extractedBytes, 0); } public static UInt32 ExtractBE32(byte[] byteArray, int offset) { byte[] extractedBytes = byteArray.Skip(offset).Take(4).ToArray(); Array.Reverse(extractedBytes); return BitConverter.ToUInt32(extractedBytes, 0); } } } ================================================ FILE: ironfleet/src/IronSHTClient/IronSHTClient.csproj ================================================ Exe net6.0 ================================================ FILE: ironfleet/src/IronSHTClient/IronSHTClient.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.31112.23 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IronSHTClient", "IronSHTClient.csproj", "{5CC355BD-00A8-4B66-9E61-13CB850C13E5}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {5CC355BD-00A8-4B66-9E61-13CB850C13E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5CC355BD-00A8-4B66-9E61-13CB850C13E5}.Debug|Any CPU.Build.0 = Debug|Any CPU {5CC355BD-00A8-4B66-9E61-13CB850C13E5}.Release|Any CPU.ActiveCfg = Release|Any CPU {5CC355BD-00A8-4B66-9E61-13CB850C13E5}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {AD1A62DC-08C5-41B5-9C5C-5C0682ED36ED} EndGlobalSection EndGlobal ================================================ FILE: ironfleet/src/IronSHTClient/Params.cs ================================================ using System; using System.Net; namespace IronSHTClient { public class Params { private string serviceFileName; private int numSetupThreads; private int numThreads; private ulong experimentDuration; private char workload; private int numKeys; private int valueSize; private bool verbose; public Params() { serviceFileName = ""; numSetupThreads = 1; numThreads = 1; experimentDuration = 60; workload = 's'; numKeys = 1000; valueSize = 1000; verbose = false; } public string ServiceFileName { get { return serviceFileName; } } public int NumSetupThreads { get { return numSetupThreads; } } public int NumThreads { get { return numThreads; } } public ulong ExperimentDuration { get { return experimentDuration; } } public char Workload { get { return workload; } } public int NumKeys { get { return numKeys; } } public int ValueSize { get { return valueSize; } } public bool Verbose { get { return verbose; } } public bool Validate() { if (serviceFileName.Length == 0) { Console.WriteLine("ERROR - Missing service parameter"); return false; } return true; } public bool ProcessCommandLineArgument(string arg) { var pos = arg.IndexOf("="); if (pos < 0) { if (serviceFileName.Length == 0) { serviceFileName = arg; return true; } else { Console.WriteLine("Invalid argument {0}", arg); return false; } } var key = arg.Substring(0, pos).ToLower(); var value = arg.Substring(pos + 1); return SetValue(key, value); } private bool SetValue(string key, string value) { if (key == "verbose") { if (value == "false") { verbose = false; return true; } if (value == "true") { verbose = true; return true; } Console.WriteLine("ERROR - Invalid verbose value {0} - should be false or true", value); return false; } if (key == "nthreads") { try { numThreads = Convert.ToInt32(value); if (numThreads < 1) { Console.WriteLine("Number of threads must be at least 1, so can't be {0}", numThreads); return false; } } catch (Exception e) { Console.WriteLine("Could not parse number of threads {0} as a number. Exception:\n{1}", value, e); return false; } return true; } if (key == "duration") { experimentDuration = Convert.ToUInt64(value); return true; } if (key == "workload") { if (value != "g" && value != "s" && value != "f") { Console.WriteLine("Workload must be 'g', 's', or 'f', but you specified {0}", value); return false; } workload = value[0]; return true; } if (key == "numkeys") { numKeys = Convert.ToInt32(value); if (numKeys < 1) { Console.WriteLine("Number of keys must be greater than zero, not {0}", value); return false; } return true; } if (key == "valuesize") { valueSize = Convert.ToInt32(value); if (valueSize < 0 || valueSize >= 1024) { Console.WriteLine("Value size must be non-negative and less than 1024, but you specified {0}", valueSize); return false; } return true; } Console.WriteLine("Invalid argument key {0}", key); return false; } } } ================================================ FILE: ironfleet/src/IronSHTClient/Program.cs ================================================ using IronfleetCommon; using IronfleetIoFramework; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Numerics; using System.Threading; namespace IronSHTClient { class Program { static void usage() { Console.Write(@" Usage: dotnet IronSHTClient.dll [key=value]... - file path of the service description Allowed keys: nthreads - number of experiment client threads to run, not counting the setup thread (default 1) duration - duration of experiment in seconds (default 60) workload - g for Gets, s for Sets, f for Sharding (default s) numkeys - number of keys (default 1000) valsize - number of bytes in each value (default 1024) verbose - print verbose output (false or true, default false) "); } static void Main(string[] args) { Params ps = new Params(); foreach (var arg in args) { if (!ps.ProcessCommandLineArgument(arg)) { usage(); return; } } var serviceIdentity = ServiceIdentity.ReadFromFile(ps.ServiceFileName); if (serviceIdentity == null) { return; } if (serviceIdentity.ServiceType != "IronSHT") { Console.Error.WriteLine("ERROR - Service described by {0} is of type {1}, not IronSHT", ps.ServiceFileName, serviceIdentity.ServiceType); return; } HiResTimer.Initialize(); if (ps.Verbose) { Console.WriteLine("Client process starting {0} threads running for {1} s...", ps.NumThreads, ps.ExperimentDuration); } Console.WriteLine("[[READY]]"); // Setup the system var setupThreads = Client.StartSetupThreads(ps, serviceIdentity).ToArray(); setupThreads[0].Join(); Console.WriteLine("[[SETUP COMPLETE]]"); // Start the experiment var threads = Client.StartExperimentThreads(ps, serviceIdentity).ToArray(); if (ps.ExperimentDuration == 0) { threads[0].Join(); } else { Thread.Sleep((int)ps.ExperimentDuration * 1000); Console.Out.WriteLine("[[DONE]]"); Console.Out.Flush(); Environment.Exit(0); } } } } ================================================ FILE: ironfleet/src/IronSHTServer/.gitignore ================================================ .vs Properties/ ================================================ FILE: ironfleet/src/IronSHTServer/IronSHTServer.csproj ================================================  Exe net6.0 1701;1702;162;164;168;183;219;436;1717;1718 IronSHTServer.Program ================================================ FILE: ironfleet/src/IronSHTServer/IronSHTServer.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.31005.135 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IronSHTServer", "IronSHTServer.csproj", "{80249939-7D35-43CA-891A-F4C73EC6D959}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {80249939-7D35-43CA-891A-F4C73EC6D959}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {80249939-7D35-43CA-891A-F4C73EC6D959}.Debug|Any CPU.Build.0 = Debug|Any CPU {80249939-7D35-43CA-891A-F4C73EC6D959}.Release|Any CPU.ActiveCfg = Release|Any CPU {80249939-7D35-43CA-891A-F4C73EC6D959}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {3EDDD386-2BE8-48A4-8188-FFDA2034F16D} EndGlobalSection EndGlobal ================================================ FILE: ironfleet/src/IronSHTServer/Params.cs ================================================ using System; using System.Collections.Generic; using System.IO; using System.Net; using System.Text.RegularExpressions; namespace IronSHTServer { public class Params { private string serviceFileName; private string privateKeyFileName; private string localHostNameOrAddress; private int localPort; private bool profile; private bool verbose; public Params() { serviceFileName = ""; privateKeyFileName = ""; localHostNameOrAddress = ""; localPort = 0; profile = false; verbose = false; } public string ServiceFileName { get { return serviceFileName; } } public string PrivateKeyFileName { get { return privateKeyFileName; } } public string LocalHostNameOrAddress { get { return localHostNameOrAddress; } } public int LocalPort { get { return localPort; } } public bool Profile { get { return profile; } } public bool Verbose { get { return verbose; } } public bool Validate() { if (serviceFileName.Length == 0) { Console.WriteLine("ERROR - Missing service parameter"); return false; } if (privateKeyFileName.Length == 0) { Console.WriteLine("ERROR - Missing private parameter"); return false; } return true; } public bool ProcessCommandLineArgument(string arg) { var pos = arg.IndexOf("="); if (pos < 0) { if (serviceFileName.Length == 0) { serviceFileName = arg; return true; } else if (privateKeyFileName.Length == 0) { privateKeyFileName = arg; return true; } else { Console.WriteLine("ERROR - Invalid argument {0}", arg); return false; } } var key = arg.Substring(0, pos).ToLower(); var value = arg.Substring(pos + 1); return SetValue(key, value); } private bool SetBoolValue(string key, string value, ref bool p) { if (value == "false") { p = false; return true; } else if (value == "true") { p = true; return true; } else { Console.WriteLine("ERROR - Invalid {0} value {1} - should be false or true", key, value); return false; } } private bool SetValue(string key, string value) { if (key == "addr") { localHostNameOrAddress = value; return true; } if (key == "port") { try { localPort = Convert.ToInt32(value); return true; } catch (Exception e) { Console.WriteLine("ERROR - Could not convert port {0} to a number. Exception:\n{1}", value, e); return false; } } if (key == "profile") { return SetBoolValue(key, value, ref profile); } if (key == "verbose") { return SetBoolValue(key, value, ref verbose); } Console.WriteLine("ERROR - Invalid argument key {0}", key); return false; } } } ================================================ FILE: ironfleet/src/IronSHTServer/Program.cs ================================================ using IronfleetCommon; using IronfleetIoFramework; using MathNet.Numerics.Distributions; using System; using System.Linq; using System.Numerics; using System.Threading; namespace IronSHTServer { class Program { static void usage() { Console.Write(@" Usage: dotnet IronSHTServer.dll [key=value]... - file path of the service description - file path of the private key Allowed keys: addr - local host name or address to listen to (default: whatever's specified in the private key file) port - port to listen to (default: whatever's specified in the private key file) profile - print profiling info (false or true, default: false) verbose - use verbose output (false or true, default: false) "); } static void Main(string[] args) { Console.WriteLine("IronSHTServer program started"); Console.WriteLine("Processing command-line arguments"); Params ps = new Params(); foreach (var arg in args) { if (!ps.ProcessCommandLineArgument(arg)) { usage(); return; } } if (!ps.Validate()) { usage(); return; } ServiceIdentity serviceIdentity = ServiceIdentity.ReadFromFile(ps.ServiceFileName); if (serviceIdentity == null) { return; } if (serviceIdentity.ServiceType != "IronSHT") { Console.Error.WriteLine("ERROR - Service described by {0} is of type {1}, not IronSHT", ps.ServiceFileName, serviceIdentity.ServiceType); return; } PrivateIdentity privateIdentity = PrivateIdentity.ReadFromFile(ps.PrivateKeyFileName); if (privateIdentity == null) { return; } Native____Io__s_Compile.PrintParams.SetParameters(ps.Profile, i_shouldPrintProgress: false); var nc = Native____Io__s_Compile.NetClient.Create(privateIdentity, ps.LocalHostNameOrAddress, ps.LocalPort, serviceIdentity.Servers, ps.Verbose, serviceIdentity.UseSsl); Dafny.ISequence[] serverPublicKeys = serviceIdentity.Servers.Select(server => Dafny.Sequence.FromArray(nc.HashPublicKey(server.PublicKey))).ToArray(); var ironArgs = Dafny.Sequence>.FromArray(serverPublicKeys); Profiler.Initialize(); Native____Io__s_Compile.Time.Initialize(); Console.WriteLine("IronFleet program started."); Console.WriteLine("[[READY]]"); Main__i_Compile.__default.IronfleetMain(nc, ironArgs); Console.WriteLine("[[EXIT]]"); } } } ================================================ FILE: ironfleet/src/IronfleetCommon/Networking.cs ================================================ using System; using System.IO; using System.Net; namespace IronfleetCommon { public class Networking { public static IPEndPoint ResolveIPEndpoint(string s) { try { return System.Net.IPEndPoint.Parse(s); } catch (FormatException) { } var pos = s.IndexOf(":"); if (pos < 0) { Console.WriteLine("Invalid endpoint descriptor {0} (no colon found)", s); return null; } string host = s.Substring(0, pos); int port = Convert.ToInt32(s.Substring(pos + 1)); IPAddress[] addresses; try { addresses = Dns.GetHostEntry(host).AddressList; } catch (Exception e) { Console.WriteLine("Could not resolve host name {0} in server endpoint descriptor {1}, leading to exception:\n{2}", host, s, e); return null; } foreach (var addr in addresses) { if (addr.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) { return new IPEndPoint(addr, port); } } Console.WriteLine("Could not resolve host name {0} in server endpoint descriptor {1}", host, s); return null; } } } ================================================ FILE: ironfleet/src/IronfleetCommon/Profiler.cs ================================================ using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; using MathNet.Numerics.Distributions; namespace IronfleetCommon { public class Aggregator { private string name; private bool times; private long total; private int count; private double sumsq; public static void Initialize() { } public Aggregator(string i_name, bool i_times) { name = i_name; times = i_times; total = 0; count = 0; sumsq = 0; } public void AddValue(long value) { //if (CommonParams.printValues) //{ // Console.WriteLine("{0}\t{1}", name, value * 1.0 / Stopwatch.Frequency); //} total += value; count++; sumsq += (value * 1.0 * value); } public void AddTime(Stopwatch s) { AddValue(s.ElapsedTicks); } public override string ToString() { if (count < 1) { return name + ": "; } if (times) { double total_sec = total * 1.0 / Stopwatch.Frequency; if (count == 1) { return name + ": " + total_sec.ToString(); } double average_sec = total_sec / count; double sumsq_sec = sumsq / Stopwatch.Frequency / Stopwatch.Frequency; double variance = (sumsq_sec - total_sec * total_sec / count) / (count - 1); double stdev = Math.Sqrt(variance); double conf95 = StudentT.InvCDF(0, stdev, count-1, 0.975) / Math.Sqrt(count); return string.Format("Aggregate {0}: avg_usec {1} conf95plusorminus {2} stdev {3} count {4} sum {5}", name, average_sec * Math.Pow(10, 6), conf95 * Math.Pow(10, 6), stdev * Math.Pow(10, 6), count, total_sec * Math.Pow(10, 6)); } else { if (count == 1) { return total.ToString(); } double average = total * 1.0 / count; double variance = (sumsq - (total * 1.0 * total) / count) / (count - 1); double stdev = Math.Sqrt(variance); double conf95 = StudentT.InvCDF(0, stdev, count - 1, 0.975) / Math.Sqrt(count); return string.Format("Aggregate {0}: avg_usec {1} conf95plusorminus {2} stdev {3} count {4} sum {5}", name, average * Math.Pow(10, 6), conf95 * Math.Pow(10, 6), stdev * Math.Pow(10, 6), count, total * Math.Pow(10, 6)); } } } public class Profiler { static Dictionary aggregators; static int count; static int ignore_count = 10000; // Ignore the first ignore_count events to try to stabilize measurements static int print_period = 1000000; static bool record; public static void Initialize() { aggregators = new Dictionary(); Aggregator.Initialize(); count = 0; record = false; } public static void Record(string name, long value) { if (record) { if (!aggregators.ContainsKey(name)) { aggregators[name] = new Aggregator(name, true); } aggregators[name].AddValue(value); } count++; if (count > ignore_count) { record = true; } if (count % print_period == 0) { Print(); } } public static void Print() { Console.WriteLine("Profiler statistics"); foreach (KeyValuePair entry in aggregators) { Console.WriteLine(entry.Value.ToString()); } } } } ================================================ FILE: ironfleet/src/IronfleetCommon/Timer.cs ================================================ using System; using System.Diagnostics; namespace IronfleetCommon { public class HiResTimer { private static Stopwatch _stopWatch = null; public static long Ticks { get { return _stopWatch.ElapsedTicks; } } public static void Initialize() { _stopWatch = Stopwatch.StartNew(); } public static double TicksToMilliseconds(long ticks) { return ticks * 1000.0 / Stopwatch.Frequency; } } } ================================================ FILE: ironfleet/src/RedisClient/.gitignore ================================================ /packages/ *.suo ================================================ FILE: ironfleet/src/RedisClient/IronfleetShtClient/App.config ================================================  ================================================ FILE: ironfleet/src/RedisClient/IronfleetShtClient/Experiment.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace IronfleetShtClient { using System.Diagnostics; using System.IO; using System.Security.Cryptography; using System.Threading; public abstract class Experiment { private readonly long durationMs; private readonly long durationTicks; private TextWriter textWriter; private readonly Thread[] threads; private KeyValueStoreClient[] clients; private readonly Barrier startBarrier; private Func connect; protected Experiment(Func connect, int clientCount, long durationMs, TextWriter textWriter) { if (null == connect) { throw new ArgumentNullException("connect"); } if (clientCount < 1) { throw new ArgumentOutOfRangeException("clientCount is less than 1."); } if (durationMs < 1) { throw new ArgumentOutOfRangeException("duration is less than 1 millisecond."); } this.connect = connect; this.durationMs = durationMs; this.durationTicks = TimeSpan.FromMilliseconds(durationMs).Ticks; this.textWriter = textWriter ?? Console.Out; this.startBarrier = new Barrier(clientCount + 1); this.threads = new Thread[clientCount]; this.clients = new KeyValueStoreClient[clientCount]; } public void Perform(Random rng) { Debug.Assert(this.textWriter != null, "the text writer reference cannot be null."); Console.Out.WriteLine("Starting {0} threads...", this.threads.Length); for (var i = 0; i < this.threads.Length; ++i) { var thread = new Thread(ThreadMain); this.threads[i] = thread; this.clients[i] = this.connect(); thread.Start(Tuple.Create(i, rng.Next())); } Console.Out.WriteLine("Waiting for connections to complete..."); this.startBarrier.SignalAndWait(); Console.Out.WriteLine("Test started. Waiting for completion..."); foreach (var t in this.threads) { t.Join(); } Console.Out.WriteLine("Test completed."); } protected abstract void OnRequest(ulong reqNum, KeyValueStoreClient client, Random random); static protected ulong TicksToMilliseconds(long ticks) { return (ulong)(ticks * 1.0 / Stopwatch.Frequency * 1000); } private void ThreadMain(object obj) { var args = (Tuple)obj; int clientId = args.Item1; var random = new Random(args.Item2); var client = this.clients[clientId]; var stopwatch = new Stopwatch(); this.startBarrier.SignalAndWait(); stopwatch.Start(); ulong reqNum = 0; while (stopwatch.ElapsedTicks < this.durationTicks) { var t0 = stopwatch.ElapsedTicks; this.OnRequest(reqNum, client, random); var t1 = stopwatch.ElapsedTicks; var tMs0 = TicksToMilliseconds(t0); var tMs1 = TicksToMilliseconds(t1); lock (this.textWriter) { this.textWriter.WriteLine("#req{0} {1} {2} {3}", reqNum, tMs0, tMs1, clientId); } ++reqNum; } } } } ================================================ FILE: ironfleet/src/RedisClient/IronfleetShtClient/IVocabularyModule.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace IronfleetShtClient { using System.Diagnostics; using System.Threading; public interface IVocabularyModule { byte[] Pick(Random rng); } public static class VocabularyModuleExtensions { public static IEnumerable Series(this IVocabularyModule self, Random rng) { Debug.Assert(self != null, "self is expected to be non-null"); while (true) { yield return self.Pick(rng); } } } } ================================================ FILE: ironfleet/src/RedisClient/IronfleetShtClient/IronfleetShtClient.csproj ================================================  Debug AnyCPU {6257F848-DAFB-443B-90CA-234691ED86DD} Exe Properties IronfleetShtClient IronfleetShtClient v4.5.1 512 true 0 AnyCPU true full false bin\Debug\ DEBUG;TRACE prompt 4 False False True False False False True True True True True True True True False True False True False False False False True False True True True False False True False False True Full %28none%29 0 AnyCPU pdbonly true bin\Release\ TRACE prompt 4 ..\packages\StackExchange.Redis.1.0.481\lib\net45\StackExchange.Redis.dll True ================================================ FILE: ironfleet/src/RedisClient/IronfleetShtClient/KeyValueStoreClient.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace IronfleetShtClient { using System.Net; using System.Runtime.Remoting.Messaging; public abstract class KeyValueStoreClient { public IPEndPoint ServerEndPoint { get; private set; } public KeyValueStoreClient(IPEndPoint endPoint) { this.ServerEndPoint = endPoint; } public abstract byte[] GetValue(byte[] key); public abstract void SetValue(byte[] key, byte[] value); } } ================================================ FILE: ironfleet/src/RedisClient/IronfleetShtClient/Program.cs ================================================  namespace IronfleetShtClient { using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Net; using System.Text; using System.Threading.Tasks; using StackExchange.Redis; public class Program { private static int Usage(int errorCode) { var console = 0 == errorCode ? Console.Out : Console.Error; console.WriteLine("usage: [SERVICE_TYPE] [SERVICE_IP] [SERVICE_PORT] [THREAD_COUNT] [DURATION_SECS]"); return errorCode; } public static int Main(string[] args) { IPEndPoint serviceEndpoint; int threadCount; long experimentDuration; int valueBytes; if (args.Length != 6) { Console.Error.WriteLine("incorrect number of arguments ({0})", args.Length); return Usage(-1); } if (args[0].Trim().ToLowerInvariant() != "redis") { Console.Error.WriteLine("only 'redis' type is currently supported ('{0}' requested)", args[0].Trim()); return Usage(-1); } try { serviceEndpoint = new IPEndPoint(IPAddress.Parse(args[1]), Convert.ToInt32(args[2])); threadCount = Convert.ToInt32(args[3]); experimentDuration = Convert.ToInt64(args[4]) * 1000; valueBytes = Convert.ToInt32(args[5]); } catch (Exception e) { Console.Error.WriteLine("Command line exception: " + e); return Usage(-2); } Console.Out.WriteLine("serviceEndpoint: {0}", serviceEndpoint); Console.Out.WriteLine("threadCount: {0}", threadCount); Console.Out.WriteLine("experimentDuration: {0} ms", experimentDuration); Console.Out.WriteLine("valueBytes: {0}", valueBytes); // Create a directory for logging all of our output string guid = Guid.NewGuid().ToString(); string outputDirectory = String.Format("{0}\\IronfleetOutput\\Job-{1}", Environment.GetEnvironmentVariable("TMP"), guid); Directory.CreateDirectory(outputDirectory); // Create the log file itself var log = new FileStream(outputDirectory + "\\client.txt", FileMode.Create); var logStream = new StreamWriter(log); var rng = new Random(); Func connect = () => RedisClient.Connect(serviceEndpoint); var dog = new StrawDog(connect, threadCount, experimentDuration, valueBytes, rng, logStream); Console.Out.WriteLine("[[READY]]"); Console.Out.WriteLine("ClientGUID {0}", guid); dog.Perform(rng); Console.Out.WriteLine("[[DONE]]"); Console.Out.Flush(); logStream.Flush(); return 0; } } } ================================================ FILE: ironfleet/src/RedisClient/IronfleetShtClient/Properties/AssemblyInfo.cs ================================================ using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("IronfleetShtClient")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("IronfleetShtClient")] [assembly: AssemblyCopyright("Copyright © 2015")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] // Setting ComVisible to false makes the types in this assembly not visible // to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("63f06234-d726-4dbc-805e-b5271c8e1218")] // Version information for an assembly consists of the following four values: // // Major Version // Minor Version // Build Number // Revision // // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] ================================================ FILE: ironfleet/src/RedisClient/IronfleetShtClient/RedisClient.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace IronfleetShtClient { using System.Diagnostics; using System.Net; using StackExchange.Redis; class RedisClient : KeyValueStoreClient { private ConnectionMultiplexer redis; private IDatabase db; private RedisClient(IPEndPoint endPoint, ConnectionMultiplexer redis) : base(endPoint) { if (null == redis) { throw new ArgumentNullException("redis"); } this.redis = redis; this.db = redis.GetDatabase(); } static public RedisClient Connect(IPEndPoint endPoint) { var config = new ConfigurationOptions { EndPoints = { endPoint }, WriteBuffer = 0, Ssl = false, ResolveDns = false }; var redis = ConnectionMultiplexer.Connect(config/*, Console.Error*/); return new RedisClient(endPoint, redis); } public override byte[] GetValue(byte[] key) { Debug.Assert(this.db != null, "the database reference cannot be null."); return this.db.StringGet(key); } public override void SetValue(byte[] key, byte[] value) { Debug.Assert(this.db != null, "the database reference cannot be null."); this.db.StringSet(key, value); } } } ================================================ FILE: ironfleet/src/RedisClient/IronfleetShtClient/StrawDog.cs ================================================ namespace IronfleetShtClient { using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; public class StrawDog : Experiment { private readonly Vocabulary keys; private readonly Vocabulary values; public StrawDog(Func connect, int clientCount, long durationMs, int valueBytes, Random rng, TextWriter textWriter) : base(connect, clientCount, durationMs, textWriter) { if (0 >= valueBytes) { throw new ArgumentOutOfRangeException("valueBytes"); } Console.Out.WriteLine("Generating test data..."); // set up pools of random byte strings for experiment. this.keys = new Vocabulary(rng, new Dictionary { { 8 /*bytes*/, 1000/*entries*/ } }); this.values = new Vocabulary(rng, new Dictionary { { valueBytes, 1000 } }); } protected override void OnRequest(ulong reqNum, KeyValueStoreClient client, Random rng) { Debug.Assert(client != null, "client is expected to be non-null"); Debug.Assert(rng != null, "random is expected to be non-null"); Debug.Assert(this.keys != null, "key vocabulary is expected to be non-null"); Debug.Assert(this.values != null, "value vocabulary is expected to be non-null"); var key = this.keys.Pick(rng); /*if ((reqNum & 1) == 0) { var value = this.values.Pick(rng); client.SetValue(key, value); } else*/ { client.GetValue(key); } } } } ================================================ FILE: ironfleet/src/RedisClient/IronfleetShtClient/Vocabulary.cs ================================================  namespace IronfleetShtClient { using System; using System.CodeDom.Compiler; using System.Collections.Generic; using System.Linq; using System.Diagnostics; public class Vocabulary : IVocabularyModule { private readonly Dictionary specs; private readonly ModuleMux mux; private class ModuleMux : IVocabularyModule { private readonly IVocabularyModule[] sources; public ModuleMux(IEnumerable sources) { if (null == sources) { throw new ArgumentNullException("sources"); } this.sources = sources.ToArray(); if (this.sources.Length == 0) { throw new ArgumentOutOfRangeException("sources", "sources is empty."); } if (this.sources.Contains(null)) { throw new ArgumentException("source list contains a null", "sources"); } } public byte[] Pick(Random rng) { Debug.Assert(rng != null, "expect constructed object"); Debug.Assert(this.sources != null, "expect constructed object"); var i = rng.Next(this.sources.Length); Debug.Assert(this.sources[i] != null, "expect non-null object"); return this.sources[i].Pick(rng); } } private class Page : IVocabularyModule { private readonly int entryLength = 0; private readonly int entryCount = 0; private readonly List entries; public Page(Random rng, int entryLength, int entryCount) { this.entryLength = entryLength; this.entryCount = entryCount; this.entries = Generate(rng, entryLength, entryCount); } private static List Generate(Random rng, int entryLength, int entryCount) { if (rng == null) { throw new ArgumentNullException("rng"); } if (entryLength < 1) { throw new ArgumentOutOfRangeException("entryLength", "is smaller than 1"); } if (entryCount < 1) { throw new ArgumentOutOfRangeException("entryCount", "is smaller than 1"); } var entries = new List(entryCount); for (var i = 0; i < entryCount; ++i) { byte[] entry = null; do { entry = new byte[entryLength]; rng.NextBytes(entry); } while (entries.Contains(entry)); entries.Add(entry); } return entries; } public byte[] Pick(Random rng) { Debug.Assert(rng != null, "expect constructed object"); Debug.Assert(this.entries != null, "expect constructed object"); var i = rng.Next(this.entries.Count); return this.entries[i]; } } public Vocabulary(Random rng, Dictionary specs) { this.specs = specs; this.mux = Generate(rng, specs); } private static ModuleMux Generate(Random rng, Dictionary specs) { if (rng == null) { throw new ArgumentNullException("rng"); } if (null == specs) { throw new ArgumentNullException("specs"); } if (specs.Count == 0) { throw new ArgumentException("vocabulary specification is empty", "specs"); } var pages = new List(); foreach (var i in specs) { pages.Add(new Page(rng, i.Key, i.Value)); } return new ModuleMux(pages); } public byte[] Pick(Random rng) { Debug.Assert(this.mux != null, "expect constructed and initialized object"); return this.mux.Pick(rng); } } } ================================================ FILE: ironfleet/src/RedisClient/IronfleetShtClient/packages.config ================================================  ================================================ FILE: ironfleet/src/RedisClient/IronfleetShtClient.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0.40629.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IronfleetShtClient", "IronfleetShtClient\IronfleetShtClient.csproj", "{6257F848-DAFB-443B-90CA-234691ED86DD}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {6257F848-DAFB-443B-90CA-234691ED86DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6257F848-DAFB-443B-90CA-234691ED86DD}.Debug|Any CPU.Build.0 = Debug|Any CPU {6257F848-DAFB-443B-90CA-234691ED86DD}.Release|Any CPU.ActiveCfg = Release|Any CPU {6257F848-DAFB-443B-90CA-234691ED86DD}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: ironfleet/src/TestIoFramework/.gitignore ================================================ .vs Properties/ ================================================ FILE: ironfleet/src/TestIoFramework/Params.cs ================================================ using System; using System.Collections.Generic; using System.IO; using System.Net; using System.Text.RegularExpressions; namespace TestIoFramework { public class Params { private string serviceFileName; private string privateKeyFileName; private string localHostNameOrAddress; private int localPort; private bool verbose; public Params() { serviceFileName = ""; privateKeyFileName = ""; localHostNameOrAddress = ""; localPort = 0; } public string ServiceFileName { get { return serviceFileName; } } public string PrivateKeyFileName { get { return privateKeyFileName; } } public string LocalHostNameOrAddress { get { return localHostNameOrAddress; } } public int LocalPort { get { return localPort; } } public bool Verbose { get { return verbose; } } public bool Validate() { if (serviceFileName.Length == 0) { Console.WriteLine("ERROR - Missing service parameter"); return false; } if (privateKeyFileName.Length == 0) { Console.WriteLine("ERROR - Missing private parameter"); return false; } return true; } public bool ProcessCommandLineArgument(string arg) { var pos = arg.IndexOf("="); if (pos < 0) { if (serviceFileName.Length == 0) { serviceFileName = arg; return true; } else if (privateKeyFileName.Length == 0) { privateKeyFileName = arg; return true; } else { Console.WriteLine("ERROR - Invalid argument {0}", arg); return false; } } var key = arg.Substring(0, pos).ToLower(); var value = arg.Substring(pos + 1); return SetValue(key, value); } private bool SetValue(string key, string value) { if (key == "addr") { localHostNameOrAddress = value; return true; } if (key == "port") { try { localPort = Convert.ToInt32(value); return true; } catch (Exception e) { Console.WriteLine("ERROR - Could not convert port {0} to a number. Exception:\n{1}", value, e); return false; } } if (key == "verbose") { if (value == "false") { verbose = false; return true; } if (value == "true") { verbose = true; return true; } Console.WriteLine("ERROR - Invalid verbose value {0} - should be false or true", value); return false; } Console.WriteLine("ERROR - Invalid argument key {0}", key); return false; } } } ================================================ FILE: ironfleet/src/TestIoFramework/Program.cs ================================================ using IronfleetIoFramework; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Numerics; using System.Text; using System.Text.Json; using System.Threading; namespace TestIoFramework { class Runner { private ServiceIdentity serviceIdentity; private PrivateIdentity privateIdentity; private IoScheduler scheduler; public Runner(ServiceIdentity i_serviceIdentity, PrivateIdentity i_privateIdentity, Params ps) { serviceIdentity = i_serviceIdentity; privateIdentity = i_privateIdentity; scheduler = IoScheduler.CreateServer(privateIdentity, ps.LocalHostNameOrAddress, ps.LocalPort, serviceIdentity.Servers, ps.Verbose, serviceIdentity.UseSsl); } public void Run() { Console.WriteLine("Starting on {0}", IoScheduler.PublicKeyToString(IoScheduler.GetCertificatePublicKey(scheduler.MyCert))); Thread t = new Thread(this.SenderThread); t.Start(); this.ReceiverThread(); } private void SenderThread() { Random rng = new Random(); while (true) { int serverIndex = rng.Next(serviceIdentity.Servers.Count); PublicIdentity serverIdentity = serviceIdentity.Servers[serverIndex]; byte[] serverPublicKey = serverIdentity.PublicKey; byte[] serverPublicKeyHash = scheduler.HashPublicKey(serverPublicKey); int randomNumber = rng.Next(10000); string message = string.Format("Hello {0}", randomNumber); byte[] messageBytes = Encoding.UTF8.GetBytes(message); Console.WriteLine("Sending message {0} to {1}", message, scheduler.LookupPublicKeyHashAsString(serverPublicKeyHash)); scheduler.SendPacket(serverPublicKeyHash, messageBytes); Thread.Sleep(1000); } } private void ReceiverThread() { while (true) { bool ok; bool timedOut; byte[] remotePublicKeyHash; byte[] messageBytes; scheduler.ReceivePacket(0, out ok, out timedOut, out remotePublicKeyHash, out messageBytes); if (!ok) { Console.WriteLine("Not OK, so terminating receiver thread"); return; } if (timedOut) { Thread.Sleep(100); continue; } string message = Encoding.UTF8.GetString(messageBytes); Console.WriteLine("Received message {0} from {1}", message, scheduler.LookupPublicKeyHashAsString(remotePublicKeyHash)); } } } class Program { static void usage() { Console.Write(@" Usage: dotnet TestIoFramework.dll [key=value]... - file path of the service description - file path of the private key Allowed keys: addr - local host name or address to listen to (default: whatever's specified in the private key file) port - port to listen to (default: whatever's specified in the private key file) verbose - use verbose output (default: false) "); } static void Main(string[] args) { Params ps = new Params(); foreach (var arg in args) { if (!ps.ProcessCommandLineArgument(arg)) { usage(); return; } } if (!ps.Validate()) { return; } ServiceIdentity serviceIdentity = ServiceIdentity.ReadFromFile(ps.ServiceFileName); if (serviceIdentity == null) { return; } PrivateIdentity privateIdentity = PrivateIdentity.ReadFromFile(ps.PrivateKeyFileName); if (privateIdentity == null) { return; } var runner = new Runner(serviceIdentity, privateIdentity, ps); runner.Run(); } } } ================================================ FILE: ironfleet/src/TestIoFramework/TestIoFramework.csproj ================================================  Exe net6.0 1701;1702;162;164;168;183;219;436;1717;1718 TestIoFramework.Program ================================================ FILE: ironfleet/src/TestIoFramework/TestIoFramework.sln ================================================  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.31005.135 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestIoFramework", "TestIoFramework.csproj", "{80249939-7D35-43CA-891A-F4C73EC6D959}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {80249939-7D35-43CA-891A-F4C73EC6D959}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {80249939-7D35-43CA-891A-F4C73EC6D959}.Debug|Any CPU.Build.0 = Debug|Any CPU {80249939-7D35-43CA-891A-F4C73EC6D959}.Release|Any CPU.ActiveCfg = Release|Any CPU {80249939-7D35-43CA-891A-F4C73EC6D959}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {3EDDD386-2BE8-48A4-8188-FFDA2034F16D} EndGlobalSection EndGlobal ================================================ FILE: ironfleet/tools/DepGraph/parse.py ================================================ #!/usr/bin/python import re, sys, os.path, getopt from subprocess import call def main(argv): maxDepth = 1 parsed_files = [] arg_len = len(sys.argv) if arg_len < 2: print "usage: parse.py []" sys.exit(2) arg1 = sys.argv[1] if arg_len >= 3: maxDepth = int(sys.argv[2]) else: maxDepth = 10000 thisfile = sys.argv[0] actualArg1 = os.path.realpath(arg1) currentPath = os.path.dirname(os.path.realpath(thisfile)) srcPath = os.path.realpath(currentPath + "/../../src") #print "maxDepth = ", maxDepth with open(currentPath + "/out.dot", "w") as fw: fw.write("digraph G {\n") parseFile(actualArg1, srcPath, fw, parsed_files, 1, maxDepth) fw.write("}\n") wincurrentpath = currentPath.replace("/cygdrive/c","C:\\") call(["dot", "-Tpdf", wincurrentpath + "/out.dot", "-o", wincurrentpath + "/output.pdf"]) call(["cygstart.exe", currentPath + "/output.pdf"]) def parseFile(filename, srcPath, fw, parsed_files, depth, maxDepth): if filename in parsed_files: return if depth > maxDepth: return parsed_files.append(filename) #print "Parsing file %s at depth %d, with maxDepth %d" % (filename, depth, maxDepth) f = open(filename, "r") for line in f: newfile = parseline(filename,line, srcPath, fw) if newfile: #print "found included file: " + newfile parseFile(newfile, srcPath, fw, parsed_files,depth+1,maxDepth) f.close() def parseline(filename,line, srcPath, fw): # print "Parsing line %s" % line matchObj = re.match("^include ", line) if matchObj: index = line.index("\"") # print "index =", index, secondindex = line.index("\"", index+1) # print "secondindex =", secondindex, substr = line[index+1:secondindex] newPath = os.path.dirname(os.path.realpath(os.path.dirname(filename) + "/" + substr)) newFilename = os.path.basename(substr) actualFile = newPath + "/" +newFilename if not re.match("^"+srcPath,actualFile): print "invalid file prefix" sys.exit(2) if re.search("\.s\.dfy$",newFilename): nodeshape = "\"" + normalizeFilename(actualFile,srcPath) + "\" [shape=box, style=filled, fillcolor=lightblue]\n" fw.write(nodeshape) if re.search("\.s\.dfy$",filename): nodeshape = "\"" + normalizeFilename(filename,srcPath) + "\" [shape=box, style=filled, fillcolor=lightblue]\n" fw.write(nodeshape) outline = "\"" + normalizeFilename(filename,srcPath) + "\" -> \"" + normalizeFilename(actualFile,srcPath) + "\"\n" fw.write(outline) return actualFile def normalizeFilename(filename,srcPath): return filename[len(srcPath)+1:] if __name__ == "__main__": main(sys.argv) ================================================ FILE: ironfleet/tools/scripts/.gitignore ================================================ *.pyc *.obj ================================================ FILE: ironfleet/tools/scripts/build-summary.py ================================================ #!/usr/bin/python import tarfile import re import sys import subprocess from OutputFormatting import * time_re = re.compile("real (\d*)m([\d.]*)s user") disposition_parse_error_re = re.compile("Error opening file") disposition_parse_error2_re = re.compile("(\d*) parse errors detected in") disposition_timeouts_re = re.compile("Dafny program verifier finished with (\d*) verified, (\d*) errors*, (\d) time outs*") disposition_notimeouts_re = re.compile("Dafny program verifier finished with (\d*) verified, (\d*) errors*") disposition_proverdied_re = re.compile("Prover error: Prover died") def extract_time(s): mo = time_re.search(s) if (mo==None): return None else: (min,sec) = mo.groups(0) return int(min)*60+float(sec) class Disposition: def __init__(self, s): self.parse_failures = 0 self.verification_errors = 0 self.timeouts = 0 self.succeeding_methods = 0 mo = disposition_timeouts_re.search(s) if (mo!=None): (succeeding_methods_s,verification_errors_s,timeouts_s) = mo.groups(0) self.succeeding_methods = int(succeeding_methods_s) self.verification_errors = int(verification_errors_s) self.timeouts = int(timeouts_s) return mo = disposition_notimeouts_re.search(s) if (mo!=None): (succeeding_methods_s,verification_errors_s) = mo.groups(0) self.succeeding_methods = int(succeeding_methods_s) self.verification_errors = int(verification_errors_s) return mo = disposition_parse_error_re.search(s) if (mo!=None): self.parse_failures = 1 # not really a count, just a flag. return mo = disposition_parse_error2_re.search(s) if (mo!=None): self.parse_failures = int(mo.groups(0)[0]) return mo = disposition_proverdied_re.search(s) if (mo!=None): self.verification_errors = 1 return print s raise Exception("unparsed log") self.parse_failures = 1 # TODO need regex for timeouts def __repr__(self): if (self.parse_failures>0): return "parse_failure" elif (self.verification_errors>0): return "verification_error" elif (self.timeouts>0): return "timeout" else: return "success" def succeeds(self): return self.parse_failures==0 and self.verification_errors==0 and self.timeouts==0 COMMON_PREFIX="obj/dafny/" class DfyRecord: def __init__(self, filename, time, disposition, log): self.filename = filename self.time = time self.disposition = disposition self.log = log def brief_name(self): if (self.filename.startswith(COMMON_PREFIX)): fn = self.filename[len(COMMON_PREFIX):] fn = fn.replace(".res", ".dfy") return fn else: return self.filename class Summarize: def __init__(self, fmt, tar_fn): self.records = [] self.fmt = fmt self.parse(tar_fn) self.report() def parse(self, tar_fn): self.tf = tarfile.open(tar_fn, "r:gz") self.total_time_sec = 0 res_tis = filter( lambda ti: ti.name.endswith(".res"), self.tf.getmembers()) for ti in res_tis: self.process(ti) def process(self, ti): res = self.tf.extractfile(ti).read() elapsed_time = extract_time(res) logname = ti.name+".log" log = self.tf.extractfile(logname).read() disposition = Disposition(log) record = DfyRecord(ti.name, elapsed_time, disposition, log) self.records.append(record) self.total_time_sec += record.time def collect_git_info_short(self): return subprocess.check_output(["git", "show", "-s"]) def collect_git_info_long(self): return subprocess.check_output(["git", "show"]) def report(self): fmt = self.fmt fp = sys.stdout failure_records = filter(lambda r: not r.disposition.succeeds(), self.records) failure_count = len(failure_records) parse_failure_count = len(filter(lambda r: r.disposition.parse_failures > 0, self.records)) verification_error_count = len(filter(lambda r: r.disposition.verification_errors > 0, self.records)) timeout_count = len(filter(lambda r: r.disposition.timeouts > 0, self.records)) if (failure_count == 0): overall_status = "Success" overall_color = fmt.Green else: overall_status = "Fail" overall_color = fmt.Red git_info = self.collect_git_info_short() fp.write(fmt.prelude()) fp.write(fmt.pre(git_info)) fp.write(fmt.spacer()) fp.write(fmt.color(overall_color, "Overall status: %s" % overall_status)) fp.write(fmt.line("Count of files with failures: %d" % failure_count)) fp.write(fmt.error_count_color(parse_failure_count, fmt.bullet(" Files with parse failures: %d" % parse_failure_count))) fp.write(fmt.error_count_color(verification_error_count, fmt.bullet(" Files with verification failures: %d" % verification_error_count))) fp.write(fmt.error_count_color(timeout_count, fmt.bullet(" Files with timeouts: %d" % timeout_count))) top_n = 10 records_by_time = list(self.records) def bytime(a,b): return cmp(a.time, b.time) records_by_time.sort(bytime) records_by_time = records_by_time[::-1] fp.write(fmt.spacer()) tt_h = int(self.total_time_sec/3600) tt_m = int((self.total_time_sec-tt_h*3600)/60) tt_s = int((self.total_time_sec-tt_h*3600-tt_m*60)) fp.write(fmt.header("Total processing time: %.0fs (%dh%02dm%02ds)" % ( self.total_time_sec, tt_h, tt_m, tt_s))) fp.write(fmt.line("Slowest %d verifications:" % top_n)) for r in records_by_time[:top_n]: fp.write(fmt.error_count_color(1-r.disposition.succeeds(), " %3.0fs %s" % (r.time, r.brief_name()))) def byname(a,b): return cmp(a.filename, b.filename) failure_records.sort(byname) for r in failure_records: fp.write(fmt.spacer()) fp.write(fmt.header("Failure with %s, %s:" % (r.brief_name(), r.disposition))) fp.write(fmt.pre(r.log)) fp.write(fmt.spacer()) fp.write(fmt.header("Commit details")) git_info = self.collect_git_info_long() fp.write(fmt.pre(git_info)) fp.write(fmt.spacer()) fp.write(fmt.epilogue()) progname = sys.argv[0] def Usage(): sys.stderr.write("Usage: %s [--ascii|--html] test.tgz\n" % progname) sys.exit(-1) def main(): argv = sys.argv[1:] fmt = FormatHTML() while (argv[0].startswith("--")): if (argv[0]=="--html"): fmt = FormatHTML() argv = argv[1:] continue if (argv[0]=="--ascii"): fmt = FormatASCII() argv = argv[1:] continue Usage() if (len(argv)!=1): Usage() Summarize(fmt, argv[0]) main() ================================================ FILE: ironfleet/tools/scripts/check-lf.ps1 ================================================ ls -r -fi *.dfy | ?{$b = [System.IO.File]::ReadAllBytes($_.FullName); ($b | ?{$_ -eq 10}).Count -ne ($b | ?{$_ -eq 13}).Count} | %{$b = [System.IO.File]::ReadAllBytes($_.FullName); "$(($b | ?{$_ -eq 10}).Count) $(($b | ?{$_ -eq 13}).Count) $($_.FullName)"} ls -r -fi *.beat | ?{$b = [System.IO.File]::ReadAllBytes($_.FullName); ($b | ?{$_ -eq 10}).Count -ne ($b | ?{$_ -eq 13}).Count} | %{$b = [System.IO.File]::ReadAllBytes($_.FullName); "$(($b | ?{$_ -eq 10}).Count) $(($b | ?{$_ -eq 13}).Count) $($_.FullName)"} ls -r -fi *.basm | ?{$b = [System.IO.File]::ReadAllBytes($_.FullName); ($b | ?{$_ -eq 10}).Count -ne ($b | ?{$_ -eq 13}).Count} | %{$b = [System.IO.File]::ReadAllBytes($_.FullName); "$(($b | ?{$_ -eq 10}).Count) $(($b | ?{$_ -eq 13}).Count) $($_.FullName)"} ls -r -fi *.cs | ?{$b = [System.IO.File]::ReadAllBytes($_.FullName); ($b | ?{$_ -eq 10}).Count -ne ($b | ?{$_ -eq 13}).Count} | %{$b = [System.IO.File]::ReadAllBytes($_.FullName); "$(($b | ?{$_ -eq 10}).Count) $(($b | ?{$_ -eq 13}).Count) $($_.FullName)"} ================================================ FILE: ironfleet/tools/scripts/dafny-line-count.py ================================================ #!/usr/bin/python import sys import os import time import fileinput import re import argparse import subprocess import pickle from prettytable import PrettyTable # Install via: easy_install PrettyTable class DafnyFile: def __init__(self, filename, verify_time): self.filename = filename.replace('\\', '/') self.verify_time = verify_time self.spec = 0 self.impl = 0 self.proof = 0 def __repr__(self): return "%s %s secs %s spec %s impl %s proof" % (self.filename, self.verify_time, self.spec, self.impl, self.proof) def is_spec(self): return self.filename.endswith(".s.dfy") def parse_nubuild(nubuild_output_file): dafny_files = [] nubuild_output = open(nubuild_output_file, "r") for line in nubuild_output.readlines(): result = re.search("DafnyVerifyOneVerb\(#\d+,(.*),\) Success\s+([.0-9]+)s", line) if result: filename = result.group(1) time = result.group(2) dfile = DafnyFile(filename, time) dafny_files += [dfile] nubuild_output.close() return dafny_files def run_dafny(iron_base, show_ghost, dafny_filename, tmp_filename): executable = iron_base + "/tools/Dafny/Dafny.exe" args = [] args += ["/rprint:-"] args += ["/noAutoReq"] args += ["/noVerify"] args += ["/nologo"] args += ["/env:0"] if show_ghost: args += ["/printMode:NoIncludes"] else: args += ["/printMode:NoGhost"] args += [dafny_filename] tmp_file = open(tmp_filename, "w") #print [executable] + args subprocess.call([executable] + args, shell=False, stdout=tmp_file) tmp_file.close() # Remove detritus from running Dafny def clean_dafny_output(filename): file = open(filename, "r") clean = "" for line in file.readlines(): if line.startswith("Dafny program verifier finished"): pass else: clean += line + "\n" file.close() file = open(filename, "w") file.write(clean) file.close() def run_sloccount(iron_base, tmp_dir): executable = "sloccount" args = [] args += ["--details"] args += [tmp_dir] sloc = -1 #print [executable] + args output = subprocess.check_output([executable] + args) #, shell=True) output = output.decode("utf-8") for line in output.split('\n'): result = re.search("(\d+)\s+dafny", line) if result: sloc = result.group(1) if sloc == -1: raise Exception("Failed to find sloccount result!") return sloc def compute_sloc(iron_base, show_ghost, dafny_file, tmp_dir): tmp_file = tmp_dir + "/tmp.dfy" run_dafny(iron_base, show_ghost, dafny_file, tmp_file) clean_dafny_output(tmp_file) sloc = run_sloccount(iron_base, tmp_dir) os.remove(tmp_file) return int(sloc) def collect_line_counts(iron_base, dafny_files): tmp_dir = iron_base + "/tmp/linecounts/" if not os.path.exists(tmp_dir): os.makedirs(tmp_dir) for f in dafny_files: print "Processing %s" % f.filename ghost_sloc = compute_sloc(iron_base, True, f.filename, tmp_dir) if f.is_spec(): f.spec = ghost_sloc f.verify_time = 0 else: impl_sloc = compute_sloc(iron_base, False, f.filename, tmp_dir) f.impl = impl_sloc f.proof = ghost_sloc - impl_sloc def define_categories(): dir_categories = {\ 'src/Dafny/Distributed/Impl/LiveSHT': 'kv_impl',\ 'src/Dafny/Distributed/Impl/SHT': 'kv_impl',\ \ 'src/Dafny/Distributed/Impl/Paxos': 'rsl_impl',\ \ 'src/Dafny/Distributed/Common': 'Common Libraries',\ 'src/Dafny/Distributed/Impl/Common': 'Common Libraries',\ 'src/Dafny/Distributed/Protocol/Common': 'Common Libraries',\ 'src/Dafny/Libraries': 'Common Libraries',\ 'src/Dafny/Drivers': 'Common Libraries',\ \ 'src/Dafny/Distributed/Common/Logic/Temporal': 'TLA Library',\ \ 'src/Dafny/Distributed/Common/Logic/Temporal/Temporal.s.dfy': 'Temporal Logic',\ 'src/Dafny/Distributed/Common/Logic/Temporal/Time.s.dfy': 'Temporal Logic',\ \ 'src/Dafny/Distributed/Protocol/Paxos/Common': 'rsl_proto',\ 'src/Dafny/Distributed/Protocol/Paxos/LiveRSL': 'rsl_proto',\ \ 'src/Dafny/Distributed/Protocol/SHT': 'kv_proto',\ 'src/Dafny/Distributed/Protocol/LiveSHT/Scheduler.i.dfy': 'kv_proto',\ \ 'src/Dafny/Distributed/Protocol/Paxos/LiveRSL/DirectRefinement': 'rsl_refine',\ 'src/Dafny/Distributed/Protocol/Paxos/LiveRSL/CommonProof': 'rsl_refine',\ #'src/Dafny/Distributed/Protocol/Paxos/RSL/': 'rsl_refine',\ #'src/Dafny/Distributed/Protocol/Paxos/LiveRSL/RefinementProof': 'rsl_refine',\ \ 'src/Dafny/Distributed/Protocol/Paxos/LiveRSL/LivenessProof': 'rsl_live',\ \ 'src/Dafny/Distributed/Protocol/SHT/InvProof.i.dfy': 'kv_refine',\ 'src/Dafny/Distributed/Protocol/SHT/InvDefs.i.dfy': 'kv_refine',\ 'src/Dafny/Distributed/Protocol/SHT/Refinement.i.dfy': 'kv_refine',\ 'src/Dafny/Distributed/Protocol/SHT/RefinementProof.i.dfy': 'kv_refine',\ 'src/Dafny/Distributed/Protocol/LiveSHT/': 'kv_refine',\ \ 'src/Dafny/Distributed/Protocol/LiveSHT/CommonProof': 'kv_live',\ 'src/Dafny/Distributed/Protocol/LiveSHT/LivenessProof': 'kv_live',\ \ 'src/Dafny/Distributed/Protocol/Paxos/LiveRSL/StateMachine.s.dfy': 'rsl_spec',\ 'src/Dafny/Distributed/Protocol/Paxos/LiveRSL/DirectRefinement/StateMachine.i.dfy': 'rsl_spec',\ 'src/Dafny/Distributed/Protocol/SHT/HT.s.dfy': 'kv_spec',\ \ 'src/Dafny/Distributed/Common/Native/Io.s.dfy' : 'IO/Native Interface',\ 'src/Dafny/Distributed/Common/Native/NativeTypes.s.dfy' : 'IO/Native Interface',\ 'src/Dafny/Distributed/Protocol/Common/Liveness/Environment.s.dfy' : 'IO/Native Interface',\ 'src/Dafny/Distributed/Protocol/Common/Liveness/EnvironmentSynchrony.s.dfy': 'IO/Native Interface',\ 'src/Dafny/Distributed/Protocol/Common/NodeIdentity.s.dfy' : 'IO/Native Interface',\ } return dir_categories def categorize_files(dafny_files): categorized_files = {} dir_categories = define_categories() for dfile in dafny_files: best_match_prefix = "" best_match_cat = "Unknown" for prefix in dir_categories.keys(): if dfile.filename.startswith(prefix) and len(prefix) > len(best_match_prefix): best_match_prefix = prefix best_match_cat = dir_categories[prefix] if not(best_match_cat in categorized_files): categorized_files[best_match_cat] = [dfile] else: categorized_files[best_match_cat] += [dfile] for cat in sorted(categorized_files.keys()): print print cat print "-----------------------------" for f in categorized_files[cat]: print f return categorized_files class SubTable: def __init__(self, name, row_names, allow_impl): self.name = name self.rows = row_names self.allow_impl = allow_impl def amt(string, pos='c'): if int(string) == 0: return "--" #return "\\multicolumn{1}{r}{--}" # if pos == 'l': # return "\\multicolumn{1}{c}{--}" # elif pos == 'r': # return "\\multicolumn{1}{c|}{--}" # else: # return "\\multicolumn{1}{c}{--}" else: return string def define_labels(): labels = {\ 'rsl_spec': "IronRSL",\ 'kv_spec': "IronKV",\ 'rsl_proto': "IronRSL Protocol",\ 'rsl_refine': "\hspace{11mm}Refinement",\ 'rsl_live': "\hspace{11mm}Liveness",\ 'kv_proto': "IronKV Protocol",\ 'kv_refine': "\hspace{10mm}Refinement",\ 'kv_live': "\hspace{10mm}Liveness",\ 'rsl_impl': "IronRSL",\ 'kv_impl': "IronKV"\ } return labels def table_label(key): labels = define_labels() if key in labels: return labels[key] else: return key def build_table(categorized_files, latex_file): spec = SubTable("High-Level Spec", ['rsl_spec', 'kv_spec', 'Temporal Logic'], allow_impl=False) protocol = SubTable("Distributed Protocol", \ ['rsl_proto', \ 'rsl_refine', \ 'rsl_live', \ 'kv_proto', \ 'kv_refine', \ 'kv_live',\ 'TLA Library', \ ], allow_impl=False) impl = SubTable("Implementation", \ ['IO/Native Interface', 'Common Libraries', 'rsl_impl', 'kv_impl'], \ allow_impl=True) tables = [spec, protocol, impl] latex = "" # latex += r"\begin{tabular}{" + "\n" # latex += r"@{}" + "\n" # latex += r"*{1}{>{\raggedright\arraybackslash}b{.16\textwidth}} @{ } % " + "\n" # latex += r"*{1}{>{\raggedleft\arraybackslash}b{.05\textwidth}} @{ } % Spec" + "\n" # latex += r"*{1}{>{\raggedleft\arraybackslash}b{.05\textwidth}} @{ } % Impl" + "\n" # latex += r"*{1}{>{\raggedleft\arraybackslash}b{.05\textwidth}} @{ } % Proof" + "\n" # latex += r"*{1}{>{\raggedleft\arraybackslash}b{.001\textwidth}} @{ } % dummy" + "\n" # latex += r"*{1}{>{\raggedleft\arraybackslash}b{.09\textwidth}} @{ } % time to verify " + "\n" # latex += r"@{}" + "\n" # latex += r"}" + "\n" # latex += r"& \multicolumn{1}{c}{\textbf{Spec}} & \multicolumn{1}{c}{\textbf{Impl}} & \multicolumn{1}{c}{\textbf{Proof}} & & \multicolumn{1}{c}{\textbf{Time to Verify}}\\" + "\n" # latex += r"& \multicolumn{3}{c}{(source lines of code)} & & \multicolumn{1}{c}{(minutes)}\\" + "\n" # latex += "\n" # latex += r"\midrule" + "\n\n" total_spec_sloc = 0 total_impl_sloc = 0 total_proof_sloc = 0 total_verify = 0 for subtable in tables: print print subtable.name latex += "\\textbf{%s:} &&&& \\\\\n" % (subtable.name) tab = PrettyTable(["Category", "Spec", "Impl", "Proof", "Time To Verify"]) for row in subtable.rows: spec_sloc = 0 impl_sloc = 0 proof_sloc = 0 verify = 0 for file in categorized_files[row]: if file.filename.startswith('src/Dafny/Libraries/') or file.filename.startswith('src/Dafny/Drivers/'): # Temporary hack, since we have a bunch of legacy .s files that really should be .i proof_sloc += file.spec + file.proof impl_sloc += file.impl elif file.filename.endswith("DirectRefinement/StateMachine.i.dfy")\ or file.filename.endswith("Assumptions.i.dfy")\ or file.filename.endswith("Protocol/SHT/Refinement.i.dfy"): # Temporary hack for files that should be a .s spec_sloc += file.spec + file.proof + file.impl verify -= float(file.verify_time) else: spec_sloc += file.spec proof_sloc += file.proof impl_sloc += file.impl verify += float(file.verify_time) if not(subtable.allow_impl): proof_sloc += impl_sloc impl_sloc = 0 # Temporary hack due to failure of spec discovery if subtable.name == "High-Level Spec": verify = 0 row_label = table_label(row) verify_min = verify / 60 tab.add_row([row_label, spec_sloc, impl_sloc, proof_sloc, verify_min]) latex += "%s & %s & %s & %s && %s \\\\\n" % (row_label, amt(spec_sloc,'l'), amt(impl_sloc,'c'), amt(proof_sloc,'r'), amt(int(verify_min))) total_spec_sloc += spec_sloc total_impl_sloc += impl_sloc total_proof_sloc += proof_sloc total_verify += verify print tab print latex += "\\midrule\n" latex += "Total & %s & %s & %s && %s \\\\\n" % (total_spec_sloc, total_impl_sloc, total_proof_sloc, int(total_verify/60)) # latex += "\\bottomrule\n" # latex += "\\end{tabular}\n" print print latex latex_out = open(latex_file, "w") latex_out.write(latex) latex_out.close() def main(): parser = argparse.ArgumentParser(description='Compute Dafny line counts') parser.add_argument('-r', '--root', help="Iron root directory", required=True) parser.add_argument('-n', '--nubuild', help="Output from running ./bin_tools/NuBuild/NuBuild.exe BatchDafny src/Dafny/Distributed/apps.dfy.batch", required=True) parser.add_argument('-c', '--cache', help="Use the specified file for caching per-file line counts", required=False) parser.add_argument('-l', '--latex', help="File for the LaTeX table", required=True) args = parser.parse_args() # roots = [ \ # "src/Dafny/Distributed/Protocol/SHT/RefinementProof.i.dfy",\ # "src/Dafny/Distributed/Protocol/LiveSHT/SHTLemmas.i.dfy",\ # "src/Dafny/Distributed/Impl/LiveSHT/Main.i.dfy",\ # "src/Dafny/Distributed/Protocol/Paxos/LiveRSL/RefinementProof/DistributedSystemLemmas.i.dfy",\ # "src/Dafny/Distributed/Protocol/Paxos/LiveRSL/LivenessProof/LivenessProof.i.dfy",\ # "src/Dafny/Distributed/Impl/Paxos/LiveRSL/Main.i.dfy",\ # ] files = None if args.cache == None or not os.path.exists(args.cache): files = parse_nubuild(args.nubuild) collect_line_counts(args.root, files) pickler = open(args.cache, "w") pickle.dump(files, pickler) pickler.close() else: pickler = open(args.cache, "r") files = pickle.load(pickler) pickler.close() cats = categorize_files(files) build_table(cats, args.latex) main() ================================================ FILE: ironfleet/tools/scripts/dafny-oneproc.py ================================================ #!/usr/bin/python import sys import os import subprocess import re def docmd(*cmd): print "cmd:", " ".join(cmd) subprocess.call(cmd) def main(): (thisprog,dfyfile,procname) = sys.argv boogieFile = dfyfile.replace(".dfy", ".bpl") escapedProcName = procname.replace("_", "__") docmd("dafny", "/timeLimit:1", "/noVerify", "/compile:0", "/arith:5", "/print:%s" % boogieFile, dfyfile) boogieFileHandle = open(boogieFile, 'r') mangledProcName = '' for line in boogieFileHandle: m = re.search(r'^procedure\s*({:[^}]+}\s*)*(Impl[^\(]+)', line) if m: procedureName = m.group(2) if procedureName.find(escapedProcName) > -1: mangledProcName = procedureName break boogieFileHandle.close() if len(mangledProcName) == 0: print 'Could not find procedure with substring %s in %s' % (escapedProcName, boogieFile) sys.exit(-1) docmd("dafny", "/timeLimit:30", "/proverOpt:O:nlsat.randomize=false", "/proverOpt:O:pi.warnings=true", "/proverWarnings:1", "/compile:0", "/noCheating:1", "/arith:5", "/proc:%s" % mangledProcName, dfyfile) docmd("rm", boogieFile) main() ================================================ FILE: ironfleet/tools/scripts/dafnyBuildVsix.ps1 ================================================ # Run this file from the ironfleet directory # (not from ironfleet\tools or ironfleet\tools\scripts or ironfleet\tools\Dafny) # This script assumes existence of: # .\tools\Dafny\DafnyLanguageService.vsix # .\tools\Dafny\DafnyOptions.txt # .\tools\Dafny\z3.exe # It copies .\tools\Dafny\DafnyLanguageService.vsix into: # .\tools\Dafny\DafnyIroncladVsPlugin.vsix # It then adds DafnyOptions.txt and z3.exe to .\tools\Dafny\DafnyIroncladVsPlugin.vsix # It also fixes up the Boogie stack size "running in $pwd" $null = [System.Reflection.Assembly]::LoadWithPartialName("System.IO.Compression") $null = [System.Reflection.Assembly]::LoadWithPartialName("System.IO.Compression.FileSystem") cp .\tools\Dafny\DafnyLanguageService.vsix .\tools\Dafny\DafnyIroncladVsPlugin.vsix $zipArchive = [System.IO.Compression.ZipFile]::Open("$pwd\tools\Dafny\DafnyIroncladVsPlugin.vsix", [System.IO.Compression.ZipArchiveMode]::Update) $zipArchive.GetEntry("DafnyOptions.txt").Delete() $null = [System.IO.Compression.ZipFileExtensions]::CreateEntryFromFile($zipArchive, "$pwd\tools\Dafny\DafnyOptions.txt", "DafnyOptions.txt") #$null = [System.IO.Compression.ZipFileExtensions]::CreateEntryFromFile($zipArchive, "$pwd\tools\Dafny\z3.exe", "z3.exe") $zipArchive.Dispose(); "done" $vis = (ls "C:\Program Files (x86)\Microsoft Visual Studio *")[0].FullName $p = $env:PATH $env:PATH = $p + ";$vis\VC\bin\;$vis\Common7\IDE" & editbin.exe /stack:268435456 .\tools\Dafny\Boogie.exe & editbin.exe /stack:268435456 .\tools\Dafny\Dafny.exe $env:PATH = $p ================================================ FILE: ironfleet/tools/scripts/expand-tabs-in-place ================================================ #!/bin/sh expand -4 < $1 > $1.tmp cat < $1.tmp > $1 rm $1.tmp ================================================ FILE: ironfleet/tools/scripts/function_call_graph.py ================================================ #!/usr/local/bin/python # Some useful pydot examples at: # http://pythonhaven.wordpress.com/tag/pydot/ # GraphVis docs: http://www.graphviz.org/pdf/dotguide.pdf # DOT language spec: http://www.graphviz.org/content/dot-language import argparse import re import pydot import fileinput class Module(): def __init__(self, name): self.name = name self.cluster = None class Function(): def __init__(self, name): self.name = name self.callees = [] self.module = None self.node = None def __str__(self): # if (self.module == None) : # return "%s has no module!!! Why?" % self.name return "%s,%s" % (self.name, self.module.name) class CallGraph(): def __init__(self): self.modules = {} self.functions = {} def get_module(self, name): if not (name in self.modules): self.modules[name] = Module(name) return self.modules[name] def get_function(self, name): if not (name in self.functions): self.functions[name] = Function(name) return self.functions[name] def __str__(self): ret = "" for func in self.functions.values(): ret += "%s\n" % func return ret class Parser(): def __init__(self, filename): self.filename = filename def parse(self): graph = CallGraph() file_in = fileinput.input([self.filename]) for line in file_in: result = re.search("(.*),(.*)=(.*)", line) if result: func_name = result.group(1) module_name = result.group(2) callee_names = result.group(3).strip().split(" ") unique_callee_names = sorted(set(callee_names)) func = graph.get_function(func_name) module = graph.get_module(module_name) callees = [] for name in unique_callee_names: if not name == "": callees += [graph.get_function(name)] func.module = module func.callees = callees file_in.close() return graph class Visualizer(): def __init__(self): pass def draw(self, graph, output_filename, labels): dot = pydot.Dot(graph_type='digraph') # Digraph = Directed graph # graphviz_path = 'C:\Program Files (x86)\Graphviz2.38\\bin' # execs = ['dot', 'twopi', 'neato', 'circo', 'fdp'] # paths = {} # for exe in execs: # paths[exe] = '%s\%s.exe' % (graphviz_path, exe) # dot.set_graphviz_executables(paths) # Create subgraphs for module in graph.modules.values(): module.cluster = pydot.Cluster(module.name, color="blue") dot.add_subgraph(module.cluster) # Create a node for every function for function in graph.functions.values(): if labels: # Labeled with function name function.node = pydot.Node(function.name, shape="circle", style="filled", fillcolor="green") else: # Smaller, unlabeled dots function.node = pydot.Node(function.name, label=" ", shape="circle", style="filled", fillcolor="green") function.module.cluster.add_node(function.node) # Fill in the edges once all of the nodes exist for function in graph.functions.values(): for callee in function.callees: dot.add_edge(pydot.Edge(function.node, callee.node)) dot.write(output_filename) def main(): parser = argparse.ArgumentParser(description='Draw a circuit') parser.add_argument('--func', required=True, help='function call graph output from Dafny') parser.add_argument('--out', required=True, help='file name for resulting graph') parser.add_argument('--labels', type=bool, default=False, help='label each function') args = parser.parse_args() parser = Parser(args.func) graph = parser.parse() #print graph visualizer = Visualizer() visualizer.draw(graph, args.out, args.labels) print "Now run:" print " /cygdrive/c/Program\ Files\ \(x86\)/Graphviz2.38/bin/dot.exe -Tpdf -O %s.dot" % args.out print "to produce a PDF containing the graph" if (__name__=="__main__"): main() ================================================ FILE: ironfleet/tools/scripts/integration-project/build.py ================================================ print('Hello World') ================================================ FILE: ironfleet/tools/scripts/integration-project/build.pyproj ================================================ Debug 2.0 d6efcd20-7f1d-4c5f-816d-766035969e82 . build.py . . build build true false true false ================================================ FILE: ironfleet/tools/scripts/integration-project/build.sln ================================================ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0.21005.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{888888A0-9F3D-457C-B088-3A5042F75D52}") = "build", "build.pyproj", "{D6EFCD20-7F1D-4C5F-816D-766035969E82}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {D6EFCD20-7F1D-4C5F-816D-766035969E82}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D6EFCD20-7F1D-4C5F-816D-766035969E82}.Debug|Any CPU.Build.0 = Debug|Any CPU {D6EFCD20-7F1D-4C5F-816D-766035969E82}.Release|Any CPU.ActiveCfg = Release|Any CPU {D6EFCD20-7F1D-4C5F-816D-766035969E82}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: ironfleet/tools/scripts/integration-project/make-project.sln ================================================ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 VisualStudioVersion = 12.0.21005.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "make-project", "make-project.vcxproj", "{445A671E-C5FE-4732-82FA-360A9A2F50C8}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 Release|Win32 = Release|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {445A671E-C5FE-4732-82FA-360A9A2F50C8}.Debug|Win32.ActiveCfg = Debug|Win32 {445A671E-C5FE-4732-82FA-360A9A2F50C8}.Debug|Win32.Build.0 = Debug|Win32 {445A671E-C5FE-4732-82FA-360A9A2F50C8}.Release|Win32.ActiveCfg = Release|Win32 {445A671E-C5FE-4732-82FA-360A9A2F50C8}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal ================================================ FILE: ironfleet/tools/scripts/integration-project/make-project.vcxproj ================================================ Debug Win32 Release Win32 {445A671E-C5FE-4732-82FA-360A9A2F50C8} MakeFileProj Makefile true v120 Makefile false v120 powershell ../integration-testing.ps1 ./ironfleet/tools/scripts/integration-testing.ps1 WIN32;_DEBUG;$(NMakePreprocessorDefinitions) ./ironfleet/tools/scripts/integration-testing.ps1 make-project.exe ./ironfleet/tools/scripts/integration-testing.ps1 WIN32;NDEBUG;$(NMakePreprocessorDefinitions) ================================================ FILE: ironfleet/tools/scripts/integration-testing.ps1 ================================================ #param ( # [string]$path #) #C:\cygwin\bin\bash.exe --login -c "cd '$path' ; make " #C:\cygwin\bin\bash.exe --login -c "cd research/ironclad/code/iron/src/Dafny; make flib" # If this script is not running on a build server, remind user to # set environment variables so that this script can be debugged if(-not $Env:TF_BUILD -and -not ($Env:TF_BUILD_SOURCESDIRECTORY -and ($Env:TF_BUILD_BUILDNUMBER -and ($Env:TF_BUILD_SOURCEGETVERSION -and $Env:TF_BUILD_BINARIESDIRECTORY)))) { Write-Error "You must set the following environment variables" Write-Error "to test this script interactively." Write-Host '$Env:TF_BUILD_SOURCESDIRECTORY - For example, enter something like:' Write-Host ' $Env:TF_BUILD_SOURCESDIRECTORY = "C:\Builds\1\IroncladApps\DistributedVerify\src\"' Write-Host '$Env:TF_BUILD_BINARIESDIRECTORY - For example, enter something like:' Write-Host ' $Env:TF_BUILD_BINARIESDIRECTORY = "C:\Builds\1\IroncladApps\DistributedVerify\bin\"' Write-Host '$Env:TF_BUILD_BUILDNUMBER - For example, enter something like:' Write-Host ' $Env:TF_BUILD_BUILDNUMBER = "build123"' Write-Host '$Env:TF_BUILD_SOURCEGETVERSION - Expects three colon-delimited fields. For example, enter something like:' Write-Host ' $Env:TF_BUILD_SOURCEGETVERSION = "git:master:4abcd7adf9098012355"' exit 1 } $sha = $Env:TF_BUILD_SOURCEGETVERSION.split(":")[2] #cd $Env:TF_BUILD_SOURCESDIRECTORY\iron #. .\build-tools.ps1 # Run the cygwin make file to run Dafny on all the files C:\cygwin\bin\bash.exe --login -c "cd '$Env:TF_BUILD_SOURCESDIRECTORY'; cd ironfleet/; ./bin_tools/NuBuild/NuBuild.exe -j 4 BatchDafny src/Dafny/Distributed/apps.dfy.batch --html summary.html; git log -1 > gitlog.txt; sed -i -b -e '/_VERIFICATION_RESULT_PLACEHOLDER/r gitlog.txt' -e 's/_VERIFICATION_RESULT_PLACEHOLDER//' summary.html" $cygwin_make_exit_code = $LASTEXITCODE # Save the error code, so we can report it appropriately # Run the email generator C:\cygwin\bin\bash.exe --login -c "cd '$Env:TF_BUILD_SOURCESDIRECTORY'; cd ironfleet/; email -html -f ironclad@microsoft.com -n Ironclad -subject 'Ironclad build summary $Env:TF_BUILD_BUILDNUMBER-$sha' ironclad@microsoft.com < summary.html " ## Attempt to collect any output that may have been produced #$target_dir_name = "C:\BuildLogs\$Env:TF_BUILD_BUILDNUMBER-$sha" ##echo "$target_dir_name" >> C:\BuildLogs\dir_name.txt #mkdir $target_dir_name # #$src_dir_name = "$Env:TF_BUILD_SOURCESDIRECTORY\iron\nuobj\" ##copy "$src_dir_name\summary.xml" $target_dir_name #copy "$src_dir_name\test.tgz" $target_dir_name ##copy "$src_dir_name\iso.sha1" $target_dir_name ##copy "$src_dir_name\build-out.txt" $target_dir_name ##copy "$src_dir_name\summary.html" $target_dir_name # ## Place a copy of all the files above in the bin directory, so TFS will also bundle them up for us #$target_dir_name = $Env:TF_BUILD_BINARIESDIRECTORY ##copy "$src_dir_name\summary.xml" $target_dir_name #copy "$src_dir_name\test.tgz" $target_dir_name ##copy "$src_dir_name\iso.sha1" $target_dir_name ##copy "$src_dir_name\build-out.txt" $target_dir_name ##copy "$src_dir_name\summary.html" $target_dir_name if ($cygwin_make_exit_code -gt 0) { # Cause the build to fail echo make failed exit 5 } ================================================ FILE: ironfleet/tools/scripts/purge.py ================================================ #!/usr/bin/python import sys import os import time import fileinput import re import argparse import subprocess class DafnyFile: def __init__(self, filename, verify_time): self.filename = filename.replace('\\', '/') def __repr__(self): return "%s" % (self.filename) def is_spec(self): return self.filename.endswith(".s.dfy") def parse_nubuild(nubuild_output_file): dafny_files = [] nubuild_output = open(nubuild_output_file, "r") for line in nubuild_output.readlines(): result = re.search("DafnyVerifyOneVerb\(#\d+,(.*),\) Success\s+([.0-9]+)s", line) if result: filename = result.group(1) time = result.group(2) dfile = DafnyFile(filename, time) dafny_files += [dfile] nubuild_output.close() return dafny_files def make_nubuild_set(nubuild_output_file): files = parse_nubuild(nubuild_output_file) filenames = map(lambda x : os.path.normpath(x.filename), files) return set(filenames) def visit_dir(accumulator, dirname, files): for f in files: if f.endswith(".dfy"): accumulator.add(os.path.normpath(os.path.join(dirname,f))) def find_all_files(root): files = set([]) os.path.walk(root + "/src/Dafny/", visit_dir, files) return files def find_unused_files(files_present, files_in_use): return files_present - files_in_use def delete_files(files): print "Deleting:" for f in sorted(files): print f os.remove(f) def delete_empty_dirs(path): if not os.path.isdir(path): return files = os.listdir(path) for f in files: filename = os.path.join(path, f) if os.path.isdir(filename): delete_empty_dirs(filename) files = os.listdir(path) if len(files) == 0: print "Removing empty folder: %s " % (path) os.rmdir(path) def main(): parser = argparse.ArgumentParser(description='Purge unused files') parser.add_argument('-r', '--root', help="Iron root directory", required=True) parser.add_argument('-n', '--nubuild', help="Output from running ./bin_tools/NuBuild/NuBuild.exe BatchDafny src/Dafny/Distributed/apps.dfy.batch", required=True) args = parser.parse_args() #if args.cache == None or not os.path.exists(args.cache): inuse_files = make_nubuild_set(args.nubuild) current_files = find_all_files(args.root) unused_files = find_unused_files(current_files, inuse_files) delete_files(unused_files) delete_empty_dirs("src/Dafny") main()